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.
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
<script lang="ts">
|
||||
import { resolve } from '$app/paths';
|
||||
import BookCover from './book-cover.svelte';
|
||||
import BookActionsMenu from './book-actions-menu.svelte';
|
||||
import * as Tooltip from '$lib/components/ui/tooltip/index';
|
||||
@@ -120,7 +121,7 @@
|
||||
? 'cursor-pointer'
|
||||
: ''}"
|
||||
>
|
||||
<a href="/book/{book.id}" class="shrink-0">
|
||||
<a href={resolve('/(root)/(library)/book/[bookId]', { bookId: String(book.id) })} class="shrink-0">
|
||||
<BookCover {book} height={110} />
|
||||
</a>
|
||||
|
||||
@@ -128,7 +129,7 @@
|
||||
<div class="flex items-start gap-2">
|
||||
<div class="min-w-0 flex-1">
|
||||
<a
|
||||
href="/book/{book.id}"
|
||||
href={resolve('/(root)/(library)/book/[bookId]', { bookId: String(book.id) })}
|
||||
class="line-clamp-2 font-serif text-sm leading-snug hover:underline"
|
||||
>
|
||||
{book.title}
|
||||
@@ -166,7 +167,9 @@
|
||||
{#each book.tags.slice(0, TAG_LIMIT) as tag (tag.id)}
|
||||
<a
|
||||
data-row-control
|
||||
href="/library/{libraryState.activeLibrary?.id}/view?tags={tag.id}"
|
||||
href="{resolve('/(root)/(library)/library/[libraryId]/view', {
|
||||
libraryId: String(libraryState.activeLibrary?.id ?? '')
|
||||
})}?tags={tag.id}"
|
||||
class={badgeVariants({ variant: 'secondary' })}>{tag.name}</a
|
||||
>
|
||||
{/each}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<script lang="ts">
|
||||
import { resolve } from '$app/paths';
|
||||
import * as Table from '$lib/components/ui/table/index';
|
||||
import * as DropdownMenu from '$lib/components/ui/dropdown-menu/index';
|
||||
import * as Tooltip from '$lib/components/ui/tooltip/index';
|
||||
@@ -52,7 +53,9 @@
|
||||
|
||||
const visible = $derived(columns.filter((c) => c.on));
|
||||
|
||||
const allSelected = $derived(books.length > 0 && books.every((b) => selectionState.isSelected(b.id)));
|
||||
const allSelected = $derived(
|
||||
books.length > 0 && books.every((b) => selectionState.isSelected(b.id))
|
||||
);
|
||||
|
||||
/** What a record is lacking — the reason this view exists. */
|
||||
function missing(book: Book) {
|
||||
@@ -208,19 +211,26 @@
|
||||
/>
|
||||
</Table.Cell>
|
||||
<Table.Cell>
|
||||
<a href="/book/{book.id}"><BookCover {book} height={36} /></a>
|
||||
<a href={resolve('/(root)/(library)/book/[bookId]', { bookId: String(book.id) })}
|
||||
><BookCover {book} height={36} /></a
|
||||
>
|
||||
</Table.Cell>
|
||||
|
||||
{#each visible as column (column.key)}
|
||||
{#if column.key === 'title'}
|
||||
<Table.Cell class="max-w-[280px] truncate font-serif">
|
||||
<a href="/book/{book.id}" class="hover:underline">{book.title}</a>
|
||||
<a
|
||||
href={resolve('/(root)/(library)/book/[bookId]', { bookId: String(book.id) })}
|
||||
class="hover:underline">{book.title}</a
|
||||
>
|
||||
</Table.Cell>
|
||||
{:else if column.key === 'authors'}
|
||||
<Table.Cell class="max-w-[180px] truncate">
|
||||
{#each book.authors as author (author.id)}
|
||||
<a
|
||||
href="/library/{libraryState.activeLibrary?.id}/view?authors={author.id}"
|
||||
href="{resolve('/(root)/(library)/library/[libraryId]/view', {
|
||||
libraryId: String(libraryState.activeLibrary?.id ?? '')
|
||||
})}?authors={author.id}"
|
||||
class="cs-list hover:underline">{author.name}</a
|
||||
>  
|
||||
{/each}
|
||||
@@ -248,7 +258,7 @@
|
||||
{formatFileSize(totalSize(book))}
|
||||
</Table.Cell>
|
||||
{:else if column.key === 'added'}
|
||||
<Table.Cell class="font-mono text-xs tabular-nums text-muted-foreground">
|
||||
<Table.Cell class="font-mono text-xs text-muted-foreground tabular-nums">
|
||||
{addedOn(book)}
|
||||
</Table.Cell>
|
||||
{:else if column.key === 'progress'}
|
||||
@@ -263,7 +273,7 @@
|
||||
style="width: {Math.round(book.progress.percentage * 100)}%;"
|
||||
></span>
|
||||
</span>
|
||||
<span class="font-mono text-xs tabular-nums text-muted-foreground">
|
||||
<span class="font-mono text-xs text-muted-foreground tabular-nums">
|
||||
{Math.round(book.progress.percentage * 100)}%
|
||||
</span>
|
||||
</span>
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
<script lang="ts">
|
||||
import { resolve } from '$app/paths';
|
||||
import BookImage from './book-image.svelte';
|
||||
import { Progress } from '$lib/components/ui/progress/index';
|
||||
import { getLibraryState } from '$lib/state/library.svelte';
|
||||
import { getBookSelectionState } from '$lib/state/bookSelection.svelte';
|
||||
import type { Book } from '$lib/schema';
|
||||
|
||||
let { book, class: className = '', ...rest }: { book: Book, class?: string} = $props();
|
||||
let { book, class: className = '', ...rest }: { book: Book; class?: string } = $props();
|
||||
|
||||
const selectionState = getBookSelectionState();
|
||||
const libraryState = getLibraryState();
|
||||
@@ -24,7 +25,7 @@
|
||||
<div class="flex w-full flex-shrink-0 flex-col gap-1 {className}">
|
||||
<!-- Book Cover -->
|
||||
<a
|
||||
href="/book/{book.id}"
|
||||
href={resolve('/(root)/(library)/book/[bookId]', { bookId: String(book.id) })}
|
||||
class="group relative aspect-9/12 w-full overflow-hidden rounded-sm shadow-lg drop-shadow-lg transition-all duration-200 {selected
|
||||
? 'ring-2 ring-star'
|
||||
: ''}"
|
||||
@@ -51,7 +52,9 @@
|
||||
</a>
|
||||
|
||||
<!-- Book Title -->
|
||||
<a href="/book/{book.id}" class="text-base-content mt-1 line-clamp-2 w-full font-serif text-sm hover:underline"
|
||||
<a
|
||||
href={resolve('/(root)/(library)/book/[bookId]', { bookId: String(book.id) })}
|
||||
class="text-base-content mt-1 line-clamp-2 w-full font-serif text-sm hover:underline"
|
||||
>{book.title}</a
|
||||
>
|
||||
|
||||
@@ -59,7 +62,9 @@
|
||||
<p class="line-clamp-1 w-full text-xs text-muted-foreground">
|
||||
{#each book.authors as author}
|
||||
<a
|
||||
href="/library/{libraryState.activeLibrary?.id}/view?authors={author.id}"
|
||||
href="{resolve('/(root)/(library)/library/[libraryId]/view', {
|
||||
libraryId: String(libraryState.activeLibrary?.id ?? '')
|
||||
})}?authors={author.id}"
|
||||
class="cs-list hover:underline">{author.name}</a
|
||||
>  
|
||||
{/each}
|
||||
|
||||
Reference in New Issue
Block a user