style: format web/src with oxfmt defaults (via vp fmt)
One-time mechanical sweep, isolated from any functional change. - oxfmt defaults: double quotes, semicolons, 2-space indent, LF, printWidth 100, trailing commas, bracket spacing, arrow parens. - vite.config.ts gains an fmt.ignorePatterns block for web/static: vendored/minified assets (htmx.min.js, compiled css) must never be reformatted. - Verified: rebuild after the sweep produces byte-identical JS/CSS bundles; only sourcemaps changed (they embed sourcesContent).
This commit is contained in:
1 parent
8aeecaa0ef
commit
77cd268f4e
37 files changed
+1151
-1853
No files matched your search
+47
-90
@@ -169,9 +169,7 @@ Alpine.data("bookDetail", () => {
|
||||
const coverImg = document.querySelector(
|
||||
"#metadata-editor-modal img#metadata-cover-preview",
|
||||
) as HTMLImageElement | null;
|
||||
const hasCover =
|
||||
coverImg?.src &&
|
||||
!coverImg.src.includes("placeholder-book.svg");
|
||||
const hasCover = coverImg?.src && !coverImg.src.includes("placeholder-book.svg");
|
||||
|
||||
const initialTags: string[] = [];
|
||||
const tagBadges = document.querySelectorAll("#metadata-editor-modal [data-editor-tag]");
|
||||
@@ -293,7 +291,7 @@ Alpine.data("bookDetail", () => {
|
||||
// HTML — no \n\n separators in it) and came up empty every time.
|
||||
this.bannerEditRow = row;
|
||||
this.bannerEditText = String(
|
||||
this.bannerSources.find(s => s.row.key === row.key)?.source ?? "",
|
||||
this.bannerSources.find((s) => s.row.key === row.key)?.source ?? "",
|
||||
);
|
||||
this.bannerEditOpen = true;
|
||||
},
|
||||
@@ -308,7 +306,7 @@ Alpine.data("bookDetail", () => {
|
||||
// Full-replace PUT: title + position ride along from the row's
|
||||
// stored values; the note is the editable part.
|
||||
const bmId = row.key.slice("bookmark-".length);
|
||||
const src = this.bannerSources.find(s => s.row.key === row.key);
|
||||
const src = this.bannerSources.find((s) => s.row.key === row.key);
|
||||
const resp = await fetch(`/api/media-items/${mediaId}/bookmarks/${bmId}`, {
|
||||
method: "PUT",
|
||||
headers: { Authorization: getAuthHeader(), "Content-Type": "application/json" },
|
||||
@@ -323,8 +321,10 @@ Alpine.data("bookDetail", () => {
|
||||
const noteId = row.key.slice("note-".length);
|
||||
// The stored position rides along: the server's PUT hard-sets the
|
||||
// position column.
|
||||
const position = (row.loc || "").startsWith("cfi:") || (row.loc || "").startsWith("page:")
|
||||
? row.loc : undefined;
|
||||
const position =
|
||||
(row.loc || "").startsWith("cfi:") || (row.loc || "").startsWith("page:")
|
||||
? row.loc
|
||||
: undefined;
|
||||
const resp = await fetch(`/api/media-items/${mediaId}/notes/${noteId}`, {
|
||||
method: "PUT",
|
||||
headers: { Authorization: getAuthHeader(), "Content-Type": "application/json" },
|
||||
@@ -335,7 +335,7 @@ Alpine.data("bookDetail", () => {
|
||||
// Highlight-attached note: the full-replace highlight PUT; empty
|
||||
// content clears the note (allowed by the validator).
|
||||
const hlId = row.key.slice("hl-".length);
|
||||
const src = this.bannerSources.find(s => s.row.key === row.key);
|
||||
const src = this.bannerSources.find((s) => s.row.key === row.key);
|
||||
if (content === String(src?.source ?? "")) return;
|
||||
// The banner only ever changes note_text: read the highlight list,
|
||||
// then full-replace the row with the new note text.
|
||||
@@ -352,7 +352,8 @@ Alpine.data("bookDetail", () => {
|
||||
headers: { Authorization: getAuthHeader(), "Content-Type": "application/json" },
|
||||
body: JSON.stringify({
|
||||
selection_text: typeof hl.selection_text === "string" ? hl.selection_text : "",
|
||||
start_position: typeof (hl.start_position ?? "") === "string" ? hl.start_position : "",
|
||||
start_position:
|
||||
typeof (hl.start_position ?? "") === "string" ? hl.start_position : "",
|
||||
end_position: typeof (hl.end_position ?? "") === "string" ? hl.end_position : "",
|
||||
epubcfi_start: hl.epubcfi_start ?? "",
|
||||
epubcfi_end: hl.epubcfi_end ?? "",
|
||||
@@ -479,10 +480,7 @@ Alpine.data("bookDetail", () => {
|
||||
showToast("Conflict resolved successfully", "success");
|
||||
setTimeout(() => window.location.reload(), 500);
|
||||
} catch (e) {
|
||||
showToast(
|
||||
e instanceof Error ? e.message : "Failed to resolve conflict",
|
||||
"error",
|
||||
);
|
||||
showToast(e instanceof Error ? e.message : "Failed to resolve conflict", "error");
|
||||
}
|
||||
},
|
||||
|
||||
@@ -507,10 +505,7 @@ Alpine.data("bookDetail", () => {
|
||||
showToast("Annotation restored", "success");
|
||||
setTimeout(() => window.location.reload(), 500);
|
||||
} catch (e) {
|
||||
showToast(
|
||||
e instanceof Error ? e.message : "Failed to restore annotation",
|
||||
"error",
|
||||
);
|
||||
showToast(e instanceof Error ? e.message : "Failed to restore annotation", "error");
|
||||
}
|
||||
},
|
||||
|
||||
@@ -538,10 +533,7 @@ Alpine.data("bookDetail", () => {
|
||||
showToast("Annotation permanently deleted", "success");
|
||||
setTimeout(() => window.location.reload(), 500);
|
||||
} catch (e) {
|
||||
showToast(
|
||||
e instanceof Error ? e.message : "Failed to delete annotation",
|
||||
"error",
|
||||
);
|
||||
showToast(e instanceof Error ? e.message : "Failed to delete annotation", "error");
|
||||
}
|
||||
},
|
||||
|
||||
@@ -560,8 +552,7 @@ Alpine.data("bookDetail", () => {
|
||||
const conflictId = document.body.getAttribute("data-conflict-id");
|
||||
const conflictWinner = document.body.getAttribute("data-conflict-winner");
|
||||
this.conflictId = conflictId && conflictId !== "null" ? conflictId : "";
|
||||
this.conflictWinner =
|
||||
conflictWinner && conflictWinner !== "null" ? conflictWinner : "";
|
||||
this.conflictWinner = conflictWinner && conflictWinner !== "null" ? conflictWinner : "";
|
||||
|
||||
const link = document.getElementById("back-link");
|
||||
if (!link) return;
|
||||
@@ -628,10 +619,7 @@ Alpine.data("bookDetail", () => {
|
||||
this.ratingHover = 0;
|
||||
showToast("Rating saved", "success");
|
||||
} catch (e) {
|
||||
showToast(
|
||||
e instanceof Error ? e.message : "Failed to save rating",
|
||||
"error",
|
||||
);
|
||||
showToast(e instanceof Error ? e.message : "Failed to save rating", "error");
|
||||
} finally {
|
||||
this.ratingSaving = false;
|
||||
}
|
||||
@@ -654,10 +642,7 @@ Alpine.data("bookDetail", () => {
|
||||
this.ratingHover = 0;
|
||||
showToast("Rating cleared", "success");
|
||||
} catch (e) {
|
||||
showToast(
|
||||
e instanceof Error ? e.message : "Failed to clear rating",
|
||||
"error",
|
||||
);
|
||||
showToast(e instanceof Error ? e.message : "Failed to clear rating", "error");
|
||||
} finally {
|
||||
this.ratingSaving = false;
|
||||
}
|
||||
@@ -691,10 +676,7 @@ Alpine.data("bookDetail", () => {
|
||||
// Reload so the server-rendered card (or its absence) matches.
|
||||
window.location.reload();
|
||||
} catch (e) {
|
||||
showToast(
|
||||
e instanceof Error ? e.message : "Failed to save review",
|
||||
"error",
|
||||
);
|
||||
showToast(e instanceof Error ? e.message : "Failed to save review", "error");
|
||||
this.reviewSaving = false;
|
||||
}
|
||||
},
|
||||
@@ -714,10 +696,7 @@ Alpine.data("bookDetail", () => {
|
||||
}
|
||||
window.location.reload();
|
||||
} catch (e) {
|
||||
showToast(
|
||||
e instanceof Error ? e.message : "Failed to delete review",
|
||||
"error",
|
||||
);
|
||||
showToast(e instanceof Error ? e.message : "Failed to delete review", "error");
|
||||
this.reviewSaving = false;
|
||||
}
|
||||
},
|
||||
@@ -732,23 +711,18 @@ Alpine.data("bookDetail", () => {
|
||||
// conflict. The winner only needs to be a valid source key; the final
|
||||
// read/unread state is set by the progress write that follows.
|
||||
if (this.conflictId && this.conflictWinner) {
|
||||
const cr = await fetch(
|
||||
`/api/conflicts/${this.conflictId}/resolve`,
|
||||
{
|
||||
method: "POST",
|
||||
headers: {
|
||||
Authorization: getAuthHeader(),
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({ winner: this.conflictWinner }),
|
||||
const cr = await fetch(`/api/conflicts/${this.conflictId}/resolve`, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
Authorization: getAuthHeader(),
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
);
|
||||
body: JSON.stringify({ winner: this.conflictWinner }),
|
||||
});
|
||||
// 400 means it was already resolved - treat as no conflict.
|
||||
if (!cr.ok && cr.status !== 400) {
|
||||
const err = await cr.json().catch(() => ({}));
|
||||
throw new Error(
|
||||
err.error || err.message || "Failed to clear sync conflict",
|
||||
);
|
||||
throw new Error(err.error || err.message || "Failed to clear sync conflict");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -780,16 +754,10 @@ Alpine.data("bookDetail", () => {
|
||||
}
|
||||
}
|
||||
|
||||
showToast(
|
||||
read ? "Marked as read" : "Marked as unread",
|
||||
"success",
|
||||
);
|
||||
showToast(read ? "Marked as read" : "Marked as unread", "success");
|
||||
setTimeout(() => window.location.reload(), 500);
|
||||
} catch (e) {
|
||||
showToast(
|
||||
e instanceof Error ? e.message : "Failed to update read state",
|
||||
"error",
|
||||
);
|
||||
showToast(e instanceof Error ? e.message : "Failed to update read state", "error");
|
||||
} finally {
|
||||
this.readSaving = false;
|
||||
}
|
||||
@@ -805,9 +773,7 @@ Alpine.data("bookDetail", () => {
|
||||
|
||||
const reader = new FileReader();
|
||||
reader.onload = (e) => {
|
||||
const preview = document.getElementById(
|
||||
"metadata-cover-preview",
|
||||
) as HTMLImageElement;
|
||||
const preview = document.getElementById("metadata-cover-preview") as HTMLImageElement;
|
||||
if (preview && e.target?.result) {
|
||||
preview.src = e.target.result as string;
|
||||
}
|
||||
@@ -820,9 +786,7 @@ Alpine.data("bookDetail", () => {
|
||||
this.coverAction = "remove";
|
||||
this.coverFile = null;
|
||||
this.newCoverPreview = "";
|
||||
const preview = document.getElementById(
|
||||
"metadata-cover-preview",
|
||||
) as HTMLImageElement;
|
||||
const preview = document.getElementById("metadata-cover-preview") as HTMLImageElement;
|
||||
if (preview) {
|
||||
preview.src = "/static/placeholder-book.svg";
|
||||
}
|
||||
@@ -880,10 +844,7 @@ Alpine.data("bookDetail", () => {
|
||||
showToast("Metadata saved successfully", "success");
|
||||
setTimeout(() => window.location.reload(), 500);
|
||||
} catch (e) {
|
||||
showToast(
|
||||
e instanceof Error ? e.message : "Failed to save metadata",
|
||||
"error",
|
||||
);
|
||||
showToast(e instanceof Error ? e.message : "Failed to save metadata", "error");
|
||||
} finally {
|
||||
this.saving = false;
|
||||
}
|
||||
@@ -905,10 +866,7 @@ Alpine.data("bookDetail", () => {
|
||||
showToast("Book rescanned successfully", "success");
|
||||
setTimeout(() => window.location.reload(), 500);
|
||||
} catch (e) {
|
||||
showToast(
|
||||
e instanceof Error ? e.message : "Failed to rescan book",
|
||||
"error",
|
||||
);
|
||||
showToast(e instanceof Error ? e.message : "Failed to rescan book", "error");
|
||||
} finally {
|
||||
this.rescanning = false;
|
||||
}
|
||||
@@ -926,13 +884,10 @@ Alpine.data("bookDetail", () => {
|
||||
this.resetting = true;
|
||||
const mediaId = getMediaId();
|
||||
try {
|
||||
const resp = await fetch(
|
||||
`/api/media-items/${mediaId}/rescan?reset_overrides=true`,
|
||||
{
|
||||
method: "POST",
|
||||
headers: { Authorization: getAuthHeader() },
|
||||
},
|
||||
);
|
||||
const resp = await fetch(`/api/media-items/${mediaId}/rescan?reset_overrides=true`, {
|
||||
method: "POST",
|
||||
headers: { Authorization: getAuthHeader() },
|
||||
});
|
||||
if (!resp.ok) {
|
||||
const err = await resp.json().catch(() => ({}));
|
||||
throw new Error(err.error || "Failed to reset metadata");
|
||||
@@ -940,10 +895,7 @@ Alpine.data("bookDetail", () => {
|
||||
showToast("Metadata reset to scanned defaults", "success");
|
||||
setTimeout(() => window.location.reload(), 500);
|
||||
} catch (e) {
|
||||
showToast(
|
||||
e instanceof Error ? e.message : "Failed to reset metadata",
|
||||
"error",
|
||||
);
|
||||
showToast(e instanceof Error ? e.message : "Failed to reset metadata", "error");
|
||||
} finally {
|
||||
this.resetting = false;
|
||||
}
|
||||
@@ -958,7 +910,9 @@ Alpine.data("bookDetail", () => {
|
||||
}
|
||||
const results = await searchTagSuggestions(this.tagSearch, libraryId);
|
||||
const current = this.editorTags.map((t: string) => t.toLowerCase());
|
||||
this.tagSuggestions = results.filter((r: TagSuggestion) => !current.includes(r.value.toLowerCase()));
|
||||
this.tagSuggestions = results.filter(
|
||||
(r: TagSuggestion) => !current.includes(r.value.toLowerCase()),
|
||||
);
|
||||
this.showTagDropdown = this.tagSuggestions.length > 0;
|
||||
this.highlightedTagIndex = -1;
|
||||
},
|
||||
@@ -984,7 +938,9 @@ Alpine.data("bookDetail", () => {
|
||||
},
|
||||
|
||||
hideEditorTagDropdown() {
|
||||
setTimeout(() => { this.showTagDropdown = false; }, 200);
|
||||
setTimeout(() => {
|
||||
this.showTagDropdown = false;
|
||||
}, 200);
|
||||
},
|
||||
|
||||
onTagKeydown(event: KeyboardEvent) {
|
||||
@@ -996,9 +952,10 @@ Alpine.data("bookDetail", () => {
|
||||
} else if (event.key === "ArrowUp") {
|
||||
event.preventDefault();
|
||||
if (this.showTagDropdown && this.tagSuggestions.length > 0) {
|
||||
this.highlightedTagIndex = this.highlightedTagIndex <= 0
|
||||
? this.tagSuggestions.length - 1
|
||||
: this.highlightedTagIndex - 1;
|
||||
this.highlightedTagIndex =
|
||||
this.highlightedTagIndex <= 0
|
||||
? this.tagSuggestions.length - 1
|
||||
: this.highlightedTagIndex - 1;
|
||||
}
|
||||
} else if (event.key === "Enter") {
|
||||
event.preventDefault();
|
||||
|
||||
Reference in new issue
Block a user