From d6207b57436dfea67266ff54aa944de0c676af70 Mon Sep 17 00:00:00 2001 From: patrick Date: Wed, 12 Aug 2026 11:08:09 -0400 Subject: [PATCH] refactor: resolve() internal links instead of plain hrefs Type-checks every link against the real route tree. Caught a dead one: the book page linked tags to /tag/{id}, a route that has never existed. --- frontend/eslint.config.js | 6 + .../lib/components/forms/books-upload.svelte | 18 +- .../lib/components/layout/app-sidebar.svelte | 5 +- .../src/lib/components/layout/nav-main.svelte | 227 +++--- .../src/lib/components/layout/nav-user.svelte | 21 +- .../lib/components/layout/search-form.svelte | 7 +- .../lib/components/reader/epub-reader.svelte | 14 +- .../src/lib/components/view/book-rows.svelte | 9 +- .../src/lib/components/view/book-table.svelte | 22 +- .../lib/components/view/book-thumbnail.svelte | 13 +- .../src/lib/state/bookCollection.svelte.ts | 10 +- frontend/src/lib/state/library.svelte.ts | 5 +- .../(library)/book/[bookId]/+page.svelte | 660 +++++++++--------- .../[bookId]/read/epub/[fileId]/+page.svelte | 4 +- .../[bookId]/read/pdf/[fileId]/+page.svelte | 8 +- .../src/routes/(root)/settings/+layout.svelte | 33 +- .../(root)/settings/account/+page.svelte | 3 +- .../(root)/settings/libraries/+page.svelte | 6 +- frontend/src/routes/login/+layout@.svelte | 4 +- 19 files changed, 588 insertions(+), 487 deletions(-) diff --git a/frontend/eslint.config.js b/frontend/eslint.config.js index da76ca7..30448e4 100644 --- a/frontend/eslint.config.js +++ b/frontend/eslint.config.js @@ -29,6 +29,12 @@ export default defineConfig( 'no-undef': 'off' } }, + { + // Generated shadcn components take href as a prop and cannot resolve it — + // that is the caller's job. Editing them here would be lost on regeneration. + files: ['src/lib/components/ui/**'], + rules: { 'svelte/no-navigation-without-resolve': 'off' } + }, { files: ['**/*.svelte', '**/*.svelte.ts', '**/*.svelte.js'], languageOptions: { diff --git a/frontend/src/lib/components/forms/books-upload.svelte b/frontend/src/lib/components/forms/books-upload.svelte index a27375e..b68f935 100644 --- a/frontend/src/lib/components/forms/books-upload.svelte +++ b/frontend/src/lib/components/forms/books-upload.svelte @@ -1,4 +1,5 @@ @@ -88,8 +92,10 @@ } // Update library book count - const count = uploadBooks.result.total - libraryState.libraries.find(lib => uploadBooks.fields.library_id.value() == lib.id.toString())!.total += count + const count = uploadBooks.result.total; + libraryState.libraries.find( + (lib) => uploadBooks.fields.library_id.value() == lib.id.toString() + )!.total += count; // Reset the files field uploadBooks.fields.files.set([]); diff --git a/frontend/src/lib/components/layout/app-sidebar.svelte b/frontend/src/lib/components/layout/app-sidebar.svelte index 096e989..4c16f19 100644 --- a/frontend/src/lib/components/layout/app-sidebar.svelte +++ b/frontend/src/lib/components/layout/app-sidebar.svelte @@ -1,4 +1,5 @@ @@ -40,6 +41,8 @@ --> {#snippet child({ props })} + + {header.title} diff --git a/frontend/src/lib/components/layout/nav-main.svelte b/frontend/src/lib/components/layout/nav-main.svelte index 71e101e..cd6098a 100644 --- a/frontend/src/lib/components/layout/nav-main.svelte +++ b/frontend/src/lib/components/layout/nav-main.svelte @@ -1,118 +1,137 @@ {#snippet shelvesTrigger(item: { title: string; icon: typeof House })} - - {item.title} - + + {item.title} + {/snippet} - - {#each items as item (item.title)} - {@const url = item.path(libraryState.activeLibrary?.id)} - {@const isActive = page.url.pathname === url} - {#if 'shelves' in item} - - {#snippet child({ props })} - - {#if sidebar.state === 'collapsed'} - - { - sidebar.setOpen(true); - shelvesOpen = true; - }} - > - {@render shelvesTrigger(item)} - - {:else} - - {#snippet child({ props })} - - {@render shelvesTrigger(item)} - - {/snippet} - - {/if} - - - {#each bookshelfState.getBookshelves(libraryState.activeLibrary!.id) ?? [] as shelf (shelf.id)} - - - {#snippet child({ props })} - - - {shelf.total} - - {shelf.title} - - - - {/snippet} - - - {/each} - - - - {/snippet} - - {:else} - - - {#snippet child({ props })} - - {#if item.icon} - - {/if} - {item.title} - - {/snippet} - - - {/if} - {/each} - - \ No newline at end of file + { + sidebar.setOpen(true); + shelvesOpen = true; + }} + > + {@render shelvesTrigger(item)} + + {:else} + + {#snippet child({ props })} + + {@render shelvesTrigger(item)} + + {/snippet} + + {/if} + + + {#each bookshelfState.getBookshelves(libraryState.activeLibrary!.id) ?? [] as shelf (shelf.id)} + + + {#snippet child({ props })} + + + {shelf.total} + + {shelf.title} + + {/snippet} + + + {/each} + + + + {/snippet} + + {:else} + + + {#snippet child({ props })} + + + + {#if item.icon} + + {/if} + {item.title} + + {/snippet} + + + {/if} + {/each} + + diff --git a/frontend/src/lib/components/layout/nav-user.svelte b/frontend/src/lib/components/layout/nav-user.svelte index c1ec24f..4a35a5f 100644 --- a/frontend/src/lib/components/layout/nav-user.svelte +++ b/frontend/src/lib/components/layout/nav-user.svelte @@ -1,4 +1,5 @@ + import { resolve } from '$app/paths'; import { page } from '$app/state'; import { Button, buttonVariants } from '$lib/components/ui/button/index.js'; import { Spinner } from '$lib/components/ui/spinner/index'; @@ -55,7 +56,7 @@
@@ -76,7 +77,10 @@ Try again - + Back to book diff --git a/frontend/src/routes/(root)/settings/+layout.svelte b/frontend/src/routes/(root)/settings/+layout.svelte index 1845d51..a87b0db 100644 --- a/frontend/src/routes/(root)/settings/+layout.svelte +++ b/frontend/src/routes/(root)/settings/+layout.svelte @@ -1,25 +1,19 @@
@@ -28,8 +22,9 @@