v3: allow users to edit dump thumbnail, fixed some linter errors in the frontend
All checks were successful
Build and Publish Docker Image / build-and-push (push) Successful in 41s
All checks were successful
Build and Publish Docker Image / build-and-push (push) Successful in 41s
This commit is contained in:
@@ -96,7 +96,9 @@ export function DumpCreateModal(
|
||||
const [submitState, setSubmitState] = useState<SubmitState>({
|
||||
status: "idle",
|
||||
});
|
||||
const [urlPreview, setUrlPreview] = useState<UrlPreview>({ status: "idle" });
|
||||
const [urlFetchState, setUrlFetchState] = useState<UrlPreview>({
|
||||
status: "idle",
|
||||
});
|
||||
const debounceRef = useRef<ReturnType<typeof setTimeout> | null>(null);
|
||||
|
||||
// Playlist phase state
|
||||
@@ -109,40 +111,54 @@ export function DumpCreateModal(
|
||||
setTitleEditing(false);
|
||||
};
|
||||
|
||||
// Canonical form of `url`, used (rather than the raw input text) to decide
|
||||
// whether the preview actually needs to re-fetch — e.g. "example.com" and
|
||||
// "https://example.com" (set later by onBlur's normalizeUrl) canonicalize
|
||||
// to the same value, so they shouldn't trigger two separate fetches.
|
||||
let canonicalUrl: string | null;
|
||||
try {
|
||||
const u = new URL(normalizeUrl(url));
|
||||
canonicalUrl = (u.protocol === "http:" || u.protocol === "https:")
|
||||
? u.toString()
|
||||
: null;
|
||||
} catch {
|
||||
canonicalUrl = null;
|
||||
}
|
||||
|
||||
// Idle state is derived below from canonicalUrl rather than set here, so
|
||||
// this effect only ever needs to set loading/done (inside the timeout).
|
||||
const urlPreview: UrlPreview = canonicalUrl
|
||||
? urlFetchState
|
||||
: { status: "idle" };
|
||||
|
||||
// Debounced URL preview
|
||||
useEffect(() => {
|
||||
if (debounceRef.current) clearTimeout(debounceRef.current);
|
||||
if (!canonicalUrl) return;
|
||||
|
||||
let trimmed: string;
|
||||
try {
|
||||
const u = new URL(normalizeUrl(url));
|
||||
if (u.protocol !== "http:" && u.protocol !== "https:") throw new Error();
|
||||
trimmed = u.toString();
|
||||
} catch {
|
||||
setUrlPreview({ status: "idle" });
|
||||
return;
|
||||
}
|
||||
// Deferred to a microtask (rather than called directly) so the immediate
|
||||
// "loading" feedback doesn't fire synchronously within the effect body —
|
||||
// same timing for the user, just not in the same tick.
|
||||
queueMicrotask(() => setUrlFetchState({ status: "loading" }));
|
||||
|
||||
setUrlPreview({ status: "loading" });
|
||||
debounceRef.current = setTimeout(async () => {
|
||||
try {
|
||||
const res = await fetch(
|
||||
`${API_URL}/api/preview?url=${encodeURIComponent(trimmed)}`,
|
||||
);
|
||||
const body = await res.json();
|
||||
setUrlPreview({
|
||||
status: "done",
|
||||
richContent: body.success ? body.data : null,
|
||||
debounceRef.current = setTimeout(() => {
|
||||
fetch(`${API_URL}/api/preview?url=${encodeURIComponent(canonicalUrl)}`)
|
||||
.then((res) => res.json())
|
||||
.then((body) => {
|
||||
setUrlFetchState({
|
||||
status: "done",
|
||||
richContent: body.success ? body.data : null,
|
||||
});
|
||||
})
|
||||
.catch(() => {
|
||||
setUrlFetchState({ status: "done", richContent: null });
|
||||
});
|
||||
} catch {
|
||||
setUrlPreview({ status: "done", richContent: null });
|
||||
}
|
||||
}, 600);
|
||||
|
||||
return () => {
|
||||
if (debounceRef.current) clearTimeout(debounceRef.current);
|
||||
};
|
||||
}, [url]);
|
||||
}, [canonicalUrl]);
|
||||
|
||||
// Paste handler
|
||||
useEffect(() => {
|
||||
@@ -151,7 +167,6 @@ export function DumpCreateModal(
|
||||
if (pastedFile) {
|
||||
setMode("file");
|
||||
setUrl("");
|
||||
setUrlPreview({ status: "idle" });
|
||||
selectFile(pastedFile);
|
||||
setSubmitState({ status: "idle" });
|
||||
return;
|
||||
@@ -310,7 +325,6 @@ export function DumpCreateModal(
|
||||
onClick={() => {
|
||||
setMode("file");
|
||||
setUrl("");
|
||||
setUrlPreview({ status: "idle" });
|
||||
setSubmitState({ status: "idle" });
|
||||
}}
|
||||
disabled={submitting}
|
||||
@@ -346,7 +360,6 @@ export function DumpCreateModal(
|
||||
e.preventDefault();
|
||||
setMode("file");
|
||||
setUrl("");
|
||||
setUrlPreview({ status: "idle" });
|
||||
selectFile(pastedFile);
|
||||
setSubmitState({ status: "idle" });
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user