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:
John O'Keefe committed 2026-10-21 13:18:24 -04:00
1 parent 8aeecaa0ef
commit 77cd268f4e
37 files changed
+1151 -1853

No files matched your search

+46 -115
View File
@@ -7,9 +7,7 @@ const SCROLL_AMOUNT = 300;
let scanListenerRegistered = false;
function scrollCarousel(collectionId: string, direction: number): void {
const track = document.getElementById(
`carousel-track-${collectionId}`,
) as HTMLElement;
const track = document.getElementById(`carousel-track-${collectionId}`) as HTMLElement;
if (!track) return;
const scrollAmount = direction * SCROLL_AMOUNT;
@@ -17,20 +15,15 @@ function scrollCarousel(collectionId: string, direction: number): void {
}
async function openDashboardSettings(): Promise<void> {
const librarySelect = document.getElementById(
"library-select",
) as HTMLSelectElement;
const librarySelect = document.getElementById("library-select") as HTMLSelectElement;
const libraryId = librarySelect?.value || "";
// Empty select = the All Libraries view: its preferences are the GLOBAL
// scope — the server returns that row when library_id is absent.
const query = libraryId ? `?library_id=${encodeURIComponent(libraryId)}` : "";
const response = await fetch(
`/api/dashboard/preferences${query}`,
{
headers: { Authorization: `Bearer ${localStorage.getItem("token")}` },
},
);
const response = await fetch(`/api/dashboard/preferences${query}`, {
headers: { Authorization: `Bearer ${localStorage.getItem("token")}` },
});
if (response.ok) {
const prefs = await response.json();
@@ -38,11 +31,8 @@ async function openDashboardSettings(): Promise<void> {
// Scope indicator: make it unmistakable what a save will customize.
const scopeEl = document.getElementById("dashboard-scope-label");
if (scopeEl) {
const optionText =
librarySelect?.selectedOptions[0]?.textContent || libraryId;
scopeEl.textContent = (
libraryId ? optionText : optionText || "All Libraries"
)
const optionText = librarySelect?.selectedOptions[0]?.textContent || libraryId;
scopeEl.textContent = (libraryId ? optionText : optionText || "All Libraries")
.replace(/\s*\(\d+\)$/, "")
.trim();
}
@@ -52,16 +42,12 @@ async function openDashboardSettings(): Promise<void> {
return;
}
const modal = document.getElementById(
"dashboard-settings-modal",
) as HTMLElement;
const modal = document.getElementById("dashboard-settings-modal") as HTMLElement;
modal?.classList.remove("hidden");
}
function applyPreferencesToModal(prefs: any): void {
const collectionList = document.getElementById(
"collection-list",
) as HTMLElement;
const collectionList = document.getElementById("collection-list") as HTMLElement;
if (!collectionList) return;
const slider = document.querySelector(
@@ -73,16 +59,12 @@ function applyPreferencesToModal(prefs: any): void {
display.textContent = String(prefs.items_per_section);
}
const items = collectionList.querySelectorAll(
"[data-collection-id]",
) as NodeListOf<HTMLElement>;
const items = collectionList.querySelectorAll("[data-collection-id]") as NodeListOf<HTMLElement>;
const orderedItems: HTMLElement[] = [];
items.forEach((item) => {
const collectionId = item.dataset.collectionId;
const checkbox = item.querySelector(
'input[type="checkbox"]',
) as HTMLInputElement;
const checkbox = item.querySelector('input[type="checkbox"]') as HTMLInputElement;
const isHidden = prefs.hidden_collections.includes(collectionId);
if (checkbox) checkbox.checked = !isHidden;
@@ -99,32 +81,25 @@ function applyPreferencesToModal(prefs: any): void {
}
function closeDashboardSettings(): void {
const modal = document.getElementById(
"dashboard-settings-modal",
) as HTMLElement;
const modal = document.getElementById("dashboard-settings-modal") as HTMLElement;
modal?.classList.add("hidden");
}
async function fetchAndRenderSections(libraryId: string): Promise<void> {
const param = libraryId ? `library_id=${libraryId}` : "";
const response = await fetch(
`/api/dashboard/sections?${param}`,
{
headers: {
Authorization: `Bearer ${localStorage.getItem("token")}`,
"Content-Type": "application/json",
},
const response = await fetch(`/api/dashboard/sections?${param}`, {
headers: {
Authorization: `Bearer ${localStorage.getItem("token")}`,
"Content-Type": "application/json",
},
);
});
if (!response.ok) throw new Error("Failed to load sections");
const data = await response.json();
renderDashboardCollections(data.sections);
}
async function saveDashboardSettings(): Promise<void> {
const collectionList = document.getElementById(
"collection-list",
) as HTMLElement;
const collectionList = document.getElementById("collection-list") as HTMLElement;
if (!collectionList) return;
const collectionItems = collectionList.querySelectorAll(
"[data-collection-id]",
@@ -133,9 +108,7 @@ async function saveDashboardSettings(): Promise<void> {
const collectionOrder: string[] = [];
collectionItems.forEach((item) => {
const collectionId = item.dataset.collectionId;
const checkbox = item.querySelector(
'input[type="checkbox"]',
) as HTMLInputElement;
const checkbox = item.querySelector('input[type="checkbox"]') as HTMLInputElement;
if (collectionId) {
collectionOrder.push(collectionId);
if (checkbox && !checkbox.checked) {
@@ -144,12 +117,9 @@ async function saveDashboardSettings(): Promise<void> {
}
});
const itemsPerCollection =
(document.querySelector("#items-count-display") as HTMLElement)
?.textContent || "20";
(document.querySelector("#items-count-display") as HTMLElement)?.textContent || "20";
try {
const librarySelect = document.getElementById(
"library-select",
) as HTMLSelectElement;
const librarySelect = document.getElementById("library-select") as HTMLSelectElement;
const libraryId = librarySelect?.value || "";
const response = await apiPut("/dashboard/preferences", {
// Empty select = the All Libraries view: an explicit JSON null is
@@ -255,9 +225,7 @@ function renderSectionHTML(section: SectionData): string {
style="scrollbar-width: none; -ms-overflow-style: none;">
${
section.items.length > 0
? section.items
.map((item) => renderBookCard(item))
.join("")
? section.items.map((item) => renderBookCard(item)).join("")
: '<div class="text-center py-8 w-full" style="color: var(--text-secondary);"><p>No items in this collection</p></div>'
}
</div>
@@ -279,9 +247,7 @@ function renderSectionHTML(section: SectionData): string {
}
function renderDashboardCollections(sections: SectionData[]): void {
const container = document.getElementById(
"collections-container",
) as HTMLElement;
const container = document.getElementById("collections-container") as HTMLElement;
if (!container) return;
const currentWood = container.getAttribute("data-wood");
@@ -342,7 +308,6 @@ function badgeTitleFor(badge: string): string {
return "";
}
function renderBookCard(book: BookInfo): string {
const coverUrl = book.cover_image_path || "/static/placeholder-book.svg";
const actionHref = book.has_conflict
@@ -354,11 +319,7 @@ function renderBookCard(book: BookInfo): string {
: isAudio
? `Listen to ${book.title}`
: `Read ${book.title}`;
const actionTitle = book.has_conflict
? "Resolve progress conflict"
: isAudio
? "Listen"
: "Read";
const actionTitle = book.has_conflict ? "Resolve progress conflict" : isAudio ? "Listen" : "Read";
const actionIcon = isAudio ? HEADPHONES_ICON : BOOK_OPEN_ICON;
const badgeIcon = badgeIconFor(book.badge || "");
@@ -393,20 +354,13 @@ function renderBookCard(book: BookInfo): string {
}
async function reloadPage(): Promise<void> {
const librarySelect = document.getElementById(
"library-select",
) as HTMLSelectElement;
const librarySelect = document.getElementById("library-select") as HTMLSelectElement;
const libraryId = librarySelect?.value || "";
await switchWithTransition("collections-container", () =>
fetchAndRenderSections(libraryId),
);
await switchWithTransition("collections-container", () => fetchAndRenderSections(libraryId));
}
function updateItemsCount(
input: HTMLInputElement,
displayTarget: string,
): void {
function updateItemsCount(input: HTMLInputElement, displayTarget: string): void {
const displayElement = document.getElementById(displayTarget) as HTMLElement;
if (displayElement) {
displayElement.textContent = input.value;
@@ -414,9 +368,7 @@ function updateItemsCount(
}
function initDragAndDrop(): void {
const collectionList = document.getElementById(
"collection-list",
) as HTMLElement;
const collectionList = document.getElementById("collection-list") as HTMLElement;
if (!collectionList) return;
let draggedItem: HTMLElement | null = null;
@@ -440,11 +392,7 @@ function initDragAndDrop(): void {
collectionList.addEventListener("dragover", (e: Event) => {
e.preventDefault();
const target = e.target as HTMLElement;
if (
target.classList.contains("collection-item") &&
target !== draggedItem &&
draggedItem
) {
if (target.classList.contains("collection-item") && target !== draggedItem && draggedItem) {
const rect = target.getBoundingClientRect();
const midY = rect.top + rect.height / 2;
if ((e as DragEvent).clientY < midY) {
@@ -509,8 +457,7 @@ function initDashboard() {
switch (action) {
case "scroll-carousel": {
const collectionId =
target.dataset.collectionId || actionElem?.dataset.collectionId;
const collectionId = target.dataset.collectionId || actionElem?.dataset.collectionId;
const direction = parseInt(
target.dataset.direction || actionElem?.dataset.direction || "0",
);
@@ -531,8 +478,7 @@ function initDashboard() {
break;
case "restore-system-collection": {
const colName =
actionElem?.dataset.collectionName || target.dataset.collectionName;
const colName = actionElem?.dataset.collectionName || target.dataset.collectionName;
const colTitle =
actionElem?.dataset.collectionTitle ||
target.dataset.collectionTitle ||
@@ -565,55 +511,40 @@ function initDashboard() {
if (!scanListenerRegistered) {
scanListenerRegistered = true;
window.addEventListener("bookhoard:scan-complete", async () => {
const librarySelect = document.getElementById(
"library-select",
) as HTMLSelectElement;
const librarySelect = document.getElementById("library-select") as HTMLSelectElement;
const libraryId = librarySelect?.value || "";
try {
const param = libraryId ? `library_id=${libraryId}` : "";
const response = await fetch(
`/api/dashboard/sections?${param}`,
{
headers: {
Authorization: `Bearer ${localStorage.getItem("token")}`,
"Content-Type": "application/json",
},
const response = await fetch(`/api/dashboard/sections?${param}`, {
headers: {
Authorization: `Bearer ${localStorage.getItem("token")}`,
"Content-Type": "application/json",
},
);
});
if (!response.ok) return;
const data = await response.json();
const container = document.getElementById(
"collections-container",
) as HTMLElement;
const container = document.getElementById("collections-container") as HTMLElement;
if (!container) return;
const freshSectionIds = new Set(
(data.sections as SectionData[]).map((s) => s.id),
);
const freshSectionIds = new Set((data.sections as SectionData[]).map((s) => s.id));
for (const section of data.sections as SectionData[]) {
const track = document.getElementById(
`carousel-track-${section.id}`,
);
const track = document.getElementById(`carousel-track-${section.id}`);
if (!track) {
container.insertAdjacentHTML(
"beforeend",
renderSectionHTML(section),
);
container.insertAdjacentHTML("beforeend", renderSectionHTML(section));
continue;
}
track.innerHTML = section.items.length > 0
? section.items.map((item) => renderBookCard(item)).join("")
: '<div class="text-center py-8 w-full" style="color: var(--text-secondary);"><p>No items in this collection</p></div>';
track.innerHTML =
section.items.length > 0
? section.items.map((item) => renderBookCard(item)).join("")
: '<div class="text-center py-8 w-full" style="color: var(--text-secondary);"><p>No items in this collection</p></div>';
}
const existingSections = container.querySelectorAll<HTMLElement>(
".dashboard-collection",
);
const existingSections = container.querySelectorAll<HTMLElement>(".dashboard-collection");
existingSections.forEach((sec) => {
const secId = sec.getAttribute("data-collection-id");
if (secId && !freshSectionIds.has(secId)) {