v3: follows, notifications, invite-only registration, unread markers

This commit is contained in:
khannurien
2026-03-21 18:42:47 +00:00
parent 7c098e7c4c
commit 608c6bc6a8
55 changed files with 4743 additions and 884 deletions

View File

@@ -10,11 +10,9 @@ import type {
RawDump,
RawPlaylistMembership,
} from "../model.ts";
import {
deserializeDump,
deserializePlaylistMembership,
} from "../model.ts";
import { deserializeDump, deserializePlaylistMembership } from "../model.ts";
import { useAuth } from "../hooks/useAuth.ts";
import { useWS } from "../hooks/useWS.ts";
import { formatBytes } from "../utils/format.ts";
import RichContentCard from "./RichContentCard.tsx";
import { MediaPlayer } from "./MediaPlayer.tsx";
@@ -74,6 +72,7 @@ interface DumpCreateModalProps {
export function DumpCreateModal({ onClose }: DumpCreateModalProps) {
const { authFetch } = useAuth();
const { injectDump } = useWS();
const backdropRef = useRef<HTMLDivElement>(null);
const [phase, setPhase] = useState<Phase>("create");
@@ -225,6 +224,7 @@ export function DumpCreateModal({ onClose }: DumpCreateModalProps) {
const apiResponse = await res.json();
if (apiResponse.success) {
const dump = deserializeDump(apiResponse.data as RawDump);
injectDump(dump);
setCreatedDump(dump);
setPhase("playlist");
setPlaylistsLoading(true);
@@ -281,7 +281,6 @@ export function DumpCreateModal({ onClose }: DumpCreateModalProps) {
}
};
const submitting = submitState.status === "submitting";
return createPortal(
@@ -376,7 +375,9 @@ export function DumpCreateModal({ onClose }: DumpCreateModalProps) {
)}
{urlPreview.status === "done" &&
urlPreview.richContent && (
<RichContentCard richContent={urlPreview.richContent} />
<RichContentCard
richContent={urlPreview.richContent}
/>
)}
</>
)
@@ -411,21 +412,24 @@ export function DumpCreateModal({ onClose }: DumpCreateModalProps) {
/>
</div>
<label className="toggle-row">
<span className="toggle-label">Public</span>
<span className="toggle-switch">
<input
type="checkbox"
checked={!isPrivate}
onChange={(e) => setIsPrivate(!e.target.checked)}
disabled={submitting}
/>
<span className="toggle-thumb" />
</span>
{isPrivate && (
<span className="toggle-hint">Only visible to you</span>
)}
</label>
<div className="dump-mode-toggle">
<button
type="button"
className={!isPrivate ? "active" : ""}
disabled={submitting}
onClick={() => setIsPrivate(false)}
>
Public
</button>
<button
type="button"
className={isPrivate ? "active" : ""}
disabled={submitting}
onClick={() => setIsPrivate(true)}
>
Private
</button>
</div>
<div className="form-actions">
<div className="form-actions-right">