|
|
|
|
@@ -247,13 +247,16 @@
|
|
|
|
|
<!-- ── Streak widget ───────────────────────────────────────────────────────────── -->
|
|
|
|
|
{#if streak > 0}
|
|
|
|
|
<div class="mb-6 flex items-center gap-3 flex-wrap text-sm">
|
|
|
|
|
<span class="inline-flex items-center gap-1.5 px-3 py-1.5 rounded-lg bg-(--color-surface-2) border border-(--color-border)">
|
|
|
|
|
<span class="font-semibold text-(--color-text)">{streak}</span>
|
|
|
|
|
<span class="text-(--color-muted)">day{streak !== 1 ? 's' : ''} reading</span>
|
|
|
|
|
<span class="inline-flex items-center gap-1.5 px-3 py-1.5 rounded-lg bg-(--color-brand)/10 border border-(--color-brand)/30 text-(--color-brand) font-semibold">
|
|
|
|
|
<svg class="w-4 h-4 shrink-0" viewBox="0 0 24 24" fill="currentColor">
|
|
|
|
|
<path d="M13.5 0.67s.74 2.65.74 4.8c0 2.06-1.35 3.73-3.41 3.73-2.07 0-3.63-1.67-3.63-3.73l.03-.36C5.21 7.51 4 10.62 4 14c0 4.42 3.58 8 8 8s8-3.58 8-8C20 8.61 17.41 3.8 13.5.67zM11.71 19c-1.78 0-3.22-1.4-3.22-3.14 0-1.62 1.05-2.76 2.81-3.12 1.77-.36 3.6-1.21 4.62-2.58.39 1.29.59 2.65.59 4.04 0 2.65-2.15 4.8-4.8 4.8z"/>
|
|
|
|
|
</svg>
|
|
|
|
|
{streak} day{streak !== 1 ? 's' : ''}
|
|
|
|
|
</span>
|
|
|
|
|
{#if data.stats.booksInProgress > 0}
|
|
|
|
|
<span class="text-(--color-muted)">
|
|
|
|
|
<span class="font-semibold text-(--color-text)">{data.stats.booksInProgress}</span> {data.stats.booksInProgress === 1 ? 'book' : 'books'} in progress
|
|
|
|
|
<span class="inline-flex items-center gap-1.5 px-3 py-1.5 rounded-lg bg-(--color-surface-2) border border-(--color-border) text-(--color-muted)">
|
|
|
|
|
<span class="font-semibold text-(--color-text)">{data.stats.booksInProgress}</span>
|
|
|
|
|
{data.stats.booksInProgress === 1 ? 'book' : 'books'} in progress
|
|
|
|
|
</span>
|
|
|
|
|
{/if}
|
|
|
|
|
</div>
|
|
|
|
|
@@ -263,32 +266,39 @@
|
|
|
|
|
{#if shelfBooks.length > 0}
|
|
|
|
|
<section class="mb-10">
|
|
|
|
|
<div class="flex items-baseline justify-between mb-3">
|
|
|
|
|
<h2 class="text-base font-bold text-(--color-text)">{m.home_continue_reading()}</h2>
|
|
|
|
|
<h2 class="text-lg font-bold text-(--color-text)">{m.home_continue_reading()}</h2>
|
|
|
|
|
<a href="/books" class="text-xs text-(--color-brand) hover:text-(--color-brand-dim)">{m.home_view_all()}</a>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="flex gap-3 overflow-x-auto pb-2 scrollbar-none -mx-4 px-4">
|
|
|
|
|
{#each shelfBooks as { book, chapter }}
|
|
|
|
|
<div class="group relative flex flex-col rounded-lg overflow-hidden bg-(--color-surface-2) hover:bg-(--color-surface-3) border border-(--color-border) hover:border-(--color-brand)/40 transition-all shrink-0 w-32 sm:w-36">
|
|
|
|
|
<div class="group relative flex flex-col rounded-lg overflow-hidden bg-(--color-surface-2) hover:bg-(--color-surface-3) border border-(--color-border) hover:border-(--color-brand)/40 transition-all shrink-0 w-36 sm:w-40">
|
|
|
|
|
<a href="/books/{book.slug}/chapters/{chapter}" class="block">
|
|
|
|
|
<div class="aspect-[2/3] overflow-hidden relative">
|
|
|
|
|
{#if book.cover}
|
|
|
|
|
<img src={book.cover} alt={book.title} class="w-full h-full object-cover group-hover:scale-105 transition-transform duration-300" loading="lazy" />
|
|
|
|
|
{:else}
|
|
|
|
|
<div class="w-full h-full bg-(--color-surface-3) flex items-center justify-center">
|
|
|
|
|
<svg class="w-8 h-8 text-(--color-muted)" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M12 6.253v13m0-13C10.832 5.477 9.246 5 7.5 5S4.168 5.477 3 6.253v13C4.168 18.477 5.754 18 7.5 18s3.332.477 4.5 1.253m0-13C13.168 5.477 14.754 5 16.5 5c1.747 0 3.332.477 4.5 1.253v13C19.832 18.477 18.247 18 16.5 18c-1.746 0-3.332.477-4.5 1.253"/></svg>
|
|
|
|
|
<span class="text-4xl font-bold text-(--color-muted) select-none opacity-50">{(book.title ?? '?').charAt(0).toUpperCase()}</span>
|
|
|
|
|
</div>
|
|
|
|
|
{/if}
|
|
|
|
|
<!-- Chapter badge -->
|
|
|
|
|
<span class="absolute bottom-1.5 right-1.5 text-xs bg-(--color-brand) text-(--color-surface) font-bold px-1.5 py-0.5 rounded">
|
|
|
|
|
{m.home_chapter_badge({ n: String(chapter) })}
|
|
|
|
|
</span>
|
|
|
|
|
<!-- Reading progress bar -->
|
|
|
|
|
{#if book.total_chapters > 0}
|
|
|
|
|
{@const pct = Math.min(100, Math.round((chapter / book.total_chapters) * 100))}
|
|
|
|
|
<div class="absolute bottom-0 left-0 right-0 h-1 bg-black/40">
|
|
|
|
|
<div class="h-full bg-(--color-brand) transition-all" style="width: {pct}%"></div>
|
|
|
|
|
</div>
|
|
|
|
|
{/if}
|
|
|
|
|
</div>
|
|
|
|
|
</a>
|
|
|
|
|
<!-- Listen button (hover overlay) -->
|
|
|
|
|
<button
|
|
|
|
|
type="button"
|
|
|
|
|
onclick={() => playChapter(book.slug, chapter)}
|
|
|
|
|
class="absolute bottom-8 left-1.5 w-7 h-7 rounded-full bg-black/60 text-white flex items-center justify-center opacity-0 group-hover:opacity-100 transition-opacity"
|
|
|
|
|
class="absolute bottom-9 left-1.5 w-7 h-7 rounded-full bg-black/60 text-white flex items-center justify-center opacity-100 sm:opacity-0 sm:group-hover:opacity-100 transition-opacity"
|
|
|
|
|
title="Listen"
|
|
|
|
|
aria-label="Listen to chapter {chapter}"
|
|
|
|
|
>
|
|
|
|
|
@@ -296,6 +306,9 @@
|
|
|
|
|
</button>
|
|
|
|
|
<a href="/books/{book.slug}/chapters/{chapter}" class="p-2 block">
|
|
|
|
|
<h3 class="text-xs font-semibold text-(--color-text) line-clamp-2 leading-snug">{book.title ?? ''}</h3>
|
|
|
|
|
{#if book.author}
|
|
|
|
|
<p class="text-xs text-(--color-muted) truncate mt-0.5">{book.author}</p>
|
|
|
|
|
{/if}
|
|
|
|
|
</a>
|
|
|
|
|
</div>
|
|
|
|
|
{/each}
|
|
|
|
|
@@ -307,7 +320,7 @@
|
|
|
|
|
{#if data.continueCompleted.length > 0}
|
|
|
|
|
<section class="mb-10">
|
|
|
|
|
<div class="flex items-baseline justify-between mb-3">
|
|
|
|
|
<h2 class="text-base font-bold text-(--color-text)">Completed</h2>
|
|
|
|
|
<h2 class="text-lg font-bold text-(--color-text)">Completed</h2>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="flex gap-3 overflow-x-auto pb-2 scrollbar-none -mx-4 px-4">
|
|
|
|
|
{#each data.continueCompleted as { book, chapter }}
|
|
|
|
|
@@ -318,7 +331,7 @@
|
|
|
|
|
<img src={book.cover} alt={book.title} class="w-full h-full object-cover group-hover:scale-105 transition-transform duration-300" loading="lazy" />
|
|
|
|
|
{:else}
|
|
|
|
|
<div class="w-full h-full bg-(--color-surface-3) flex items-center justify-center">
|
|
|
|
|
<svg class="w-8 h-8 text-(--color-muted)" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M12 6.253v13m0-13C10.832 5.477 9.246 5 7.5 5S4.168 5.477 3 6.253v13C4.168 18.477 5.754 18 7.5 18s3.332.477 4.5 1.253m0-13C13.168 5.477 14.754 5 16.5 5c1.747 0 3.332.477 4.5 1.253v13C19.832 18.477 18.247 18 16.5 18c-1.746 0-3.332.477-4.5 1.253"/></svg>
|
|
|
|
|
<span class="text-4xl font-bold text-(--color-muted) select-none opacity-50">{(book.title ?? '?').charAt(0).toUpperCase()}</span>
|
|
|
|
|
</div>
|
|
|
|
|
{/if}
|
|
|
|
|
<span class="absolute top-1.5 right-1.5 text-xs bg-green-600/90 text-white font-bold px-1.5 py-0.5 rounded">Done</span>
|
|
|
|
|
@@ -339,7 +352,7 @@
|
|
|
|
|
{#if data.readyToListen.length > 0 && !hidden.has('ready-to-listen')}
|
|
|
|
|
<section class="mb-10">
|
|
|
|
|
<div class="flex items-baseline justify-between mb-3">
|
|
|
|
|
<h2 class="text-base font-bold text-(--color-text)">Ready to Listen</h2>
|
|
|
|
|
<h2 class="text-lg font-bold text-(--color-text)">Ready to Listen</h2>
|
|
|
|
|
<div class="flex items-center gap-3">
|
|
|
|
|
<a href="/listen" class="text-xs text-(--color-brand) hover:text-(--color-brand-dim)">View all</a>
|
|
|
|
|
<button type="button" onclick={() => hide('ready-to-listen')} title="Hide section"
|
|
|
|
|
@@ -360,7 +373,7 @@
|
|
|
|
|
<img src={book.cover} alt={book.title} class="w-full h-full object-cover group-hover:scale-105 transition-transform duration-300" loading="lazy" />
|
|
|
|
|
{:else}
|
|
|
|
|
<div class="w-full h-full bg-(--color-surface-3) flex items-center justify-center">
|
|
|
|
|
<svg class="w-8 h-8 text-(--color-muted)" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M12 6.253v13m0-13C10.832 5.477 9.246 5 7.5 5S4.168 5.477 3 6.253v13C4.168 18.477 5.754 18 7.5 18s3.332.477 4.5 1.253m0-13C13.168 5.477 14.754 5 16.5 5c1.747 0 3.332.477 4.5 1.253v13C19.832 18.477 18.247 18 16.5 18c-1.746 0-3.332.477-4.5 1.253"/></svg>
|
|
|
|
|
<span class="text-4xl font-bold text-(--color-muted) select-none opacity-50">{(book.title ?? '?').charAt(0).toUpperCase()}</span>
|
|
|
|
|
</div>
|
|
|
|
|
{/if}
|
|
|
|
|
<!-- Headphones badge -->
|
|
|
|
|
@@ -402,7 +415,7 @@
|
|
|
|
|
{#if !hidden.has('browse-genre')}
|
|
|
|
|
<section class="mb-10">
|
|
|
|
|
<div class="flex items-baseline justify-between mb-3">
|
|
|
|
|
<h2 class="text-base font-bold text-(--color-text)">Browse by genre</h2>
|
|
|
|
|
<h2 class="text-lg font-bold text-(--color-text)">Browse by genre</h2>
|
|
|
|
|
<div class="flex items-center gap-3">
|
|
|
|
|
<a href="/catalogue" class="text-xs text-(--color-brand) hover:text-(--color-brand-dim)">{m.home_view_all()}</a>
|
|
|
|
|
<button type="button" onclick={() => hide('browse-genre')} title="Hide section"
|
|
|
|
|
@@ -415,8 +428,11 @@
|
|
|
|
|
</div>
|
|
|
|
|
<div class="flex gap-2 overflow-x-auto pb-1 scrollbar-none -mx-4 px-4">
|
|
|
|
|
{#each GENRES as genre}
|
|
|
|
|
{@const isTop = data.topGenre && genre.toLowerCase() === data.topGenre.toLowerCase()}
|
|
|
|
|
<a href="/catalogue?genre={encodeURIComponent(genre)}"
|
|
|
|
|
class="shrink-0 px-3.5 py-1.5 rounded-full border border-(--color-border) bg-(--color-surface-2) text-sm text-(--color-muted) hover:border-(--color-brand)/50 hover:text-(--color-text) hover:bg-(--color-surface-3) transition-colors whitespace-nowrap">
|
|
|
|
|
class="shrink-0 px-3.5 py-1.5 rounded-full border text-sm transition-colors whitespace-nowrap {isTop
|
|
|
|
|
? 'border-(--color-brand) bg-(--color-brand)/10 text-(--color-brand) font-semibold'
|
|
|
|
|
: 'border-(--color-border) bg-(--color-surface-2) text-(--color-muted) hover:border-(--color-brand)/50 hover:text-(--color-text) hover:bg-(--color-surface-3)'}">
|
|
|
|
|
{genre}
|
|
|
|
|
</a>
|
|
|
|
|
{/each}
|
|
|
|
|
@@ -428,7 +444,7 @@
|
|
|
|
|
{#if data.trendingBooks.length > 0 && !hidden.has('trending')}
|
|
|
|
|
<section class="mb-10">
|
|
|
|
|
<div class="flex items-baseline justify-between mb-3">
|
|
|
|
|
<h2 class="text-base font-bold text-(--color-text)">Trending Now</h2>
|
|
|
|
|
<h2 class="text-lg font-bold text-(--color-text)">Trending Now</h2>
|
|
|
|
|
<div class="flex items-center gap-3">
|
|
|
|
|
<a href="/catalogue" class="text-xs text-(--color-brand) hover:text-(--color-brand-dim)">{m.home_view_all()}</a>
|
|
|
|
|
<button type="button" onclick={() => hide('trending')} title="Hide section"
|
|
|
|
|
@@ -449,7 +465,7 @@
|
|
|
|
|
<img src={book.cover} alt={book.title} class="w-full h-full object-cover group-hover:scale-105 transition-transform duration-300" loading="lazy" />
|
|
|
|
|
{:else}
|
|
|
|
|
<div class="w-full h-full bg-(--color-surface-3) flex items-center justify-center">
|
|
|
|
|
<svg class="w-8 h-8 text-(--color-muted)" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M12 6.253v13m0-13C10.832 5.477 9.246 5 7.5 5S4.168 5.477 3 6.253v13C4.168 18.477 5.754 18 7.5 18s3.332.477 4.5 1.253m0-13C13.168 5.477 14.754 5 16.5 5c1.747 0 3.332.477 4.5 1.253v13C19.832 18.477 18.247 18 16.5 18c-1.746 0-3.332.477-4.5 1.253"/></svg>
|
|
|
|
|
<span class="text-4xl font-bold text-(--color-muted) select-none opacity-50">{(book.title ?? '?').charAt(0).toUpperCase()}</span>
|
|
|
|
|
</div>
|
|
|
|
|
{/if}
|
|
|
|
|
<span class="absolute top-1.5 left-1.5 text-xs bg-(--color-brand)/80 text-(--color-surface) font-bold px-1.5 py-0.5 rounded">#{book.ranking}</span>
|
|
|
|
|
@@ -477,15 +493,18 @@
|
|
|
|
|
{#if data.recommendedBooks.length > 0 && data.topGenre && !hidden.has('because-you-read')}
|
|
|
|
|
<section class="mb-10">
|
|
|
|
|
<div class="flex items-baseline justify-between mb-3">
|
|
|
|
|
<h2 class="text-base font-bold text-(--color-text)">
|
|
|
|
|
Because you read <span class="text-(--color-brand)">{data.topGenre}</span>
|
|
|
|
|
<h2 class="text-lg font-bold text-(--color-text)">
|
|
|
|
|
Because you read <span class="text-(--color-brand)">{data.topGenre ? data.topGenre.charAt(0).toUpperCase() + data.topGenre.slice(1) : ''}</span>
|
|
|
|
|
</h2>
|
|
|
|
|
<button type="button" onclick={() => hide('because-you-read')} title="Hide section"
|
|
|
|
|
class="text-(--color-muted) hover:text-(--color-text) transition-colors">
|
|
|
|
|
<svg class="w-3.5 h-3.5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
|
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13.875 18.825A10.05 10.05 0 0112 19c-4.478 0-8.268-2.943-9.543-7a9.97 9.97 0 011.563-3.029m5.858.908a3 3 0 114.243 4.243M9.878 9.878l4.242 4.242M9.88 9.88l-3.29-3.29m7.532 7.532l3.29 3.29M3 3l3.59 3.59m0 0A9.953 9.953 0 0112 5c4.478 0 8.268 2.943 9.543 7a10.025 10.025 0 01-4.132 5.411m0 0L21 21"/>
|
|
|
|
|
</svg>
|
|
|
|
|
</button>
|
|
|
|
|
<div class="flex items-center gap-3">
|
|
|
|
|
<a href="/catalogue?genre={encodeURIComponent(data.topGenre ?? '')}" class="text-xs text-(--color-brand) hover:text-(--color-brand-dim)">View all</a>
|
|
|
|
|
<button type="button" onclick={() => hide('because-you-read')} title="Hide section"
|
|
|
|
|
class="text-(--color-muted) hover:text-(--color-text) transition-colors">
|
|
|
|
|
<svg class="w-3.5 h-3.5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
|
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13.875 18.825A10.05 10.05 0 0112 19c-4.478 0-8.268-2.943-9.543-7a9.97 9.97 0 011.563-3.029m5.858.908a3 3 0 114.243 4.243M9.878 9.878l4.242 4.242M9.88 9.88l-3.29-3.29m7.532 7.532l3.29 3.29M3 3l3.59 3.59m0 0A9.953 9.953 0 0112 5c4.478 0 8.268 2.943 9.543 7a10.025 10.025 0 01-4.132 5.411m0 0L21 21"/>
|
|
|
|
|
</svg>
|
|
|
|
|
</button>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="flex gap-3 overflow-x-auto pb-2 scrollbar-none -mx-4 px-4">
|
|
|
|
|
{#each data.recommendedBooks as book}
|
|
|
|
|
@@ -497,7 +516,7 @@
|
|
|
|
|
<img src={book.cover} alt={book.title} class="w-full h-full object-cover group-hover:scale-105 transition-transform duration-300" loading="lazy" />
|
|
|
|
|
{:else}
|
|
|
|
|
<div class="w-full h-full bg-(--color-surface-3) flex items-center justify-center">
|
|
|
|
|
<svg class="w-8 h-8 text-(--color-muted)" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M12 6.253v13m0-13C10.832 5.477 9.246 5 7.5 5S4.168 5.477 3 6.253v13C4.168 18.477 5.754 18 7.5 18s3.332.477 4.5 1.253m0-13C13.168 5.477 14.754 5 16.5 5c1.747 0 3.332.477 4.5 1.253v13C19.832 18.477 18.247 18 16.5 18c-1.746 0-3.332.477-4.5 1.253"/></svg>
|
|
|
|
|
<span class="text-4xl font-bold text-(--color-muted) select-none opacity-50">{(book.title ?? '?').charAt(0).toUpperCase()}</span>
|
|
|
|
|
</div>
|
|
|
|
|
{/if}
|
|
|
|
|
</div>
|
|
|
|
|
@@ -524,7 +543,7 @@
|
|
|
|
|
{#if dedupedRecent.length > 0 && !hidden.has('recently-updated')}
|
|
|
|
|
<section class="mb-10">
|
|
|
|
|
<div class="flex items-baseline justify-between mb-3">
|
|
|
|
|
<h2 class="text-base font-bold text-(--color-text)">{m.home_recently_updated()}</h2>
|
|
|
|
|
<h2 class="text-lg font-bold text-(--color-text)">{m.home_recently_updated()}</h2>
|
|
|
|
|
<div class="flex items-center gap-3">
|
|
|
|
|
<a href="/catalogue" class="text-xs text-(--color-brand) hover:text-(--color-brand-dim)">{m.home_view_all()}</a>
|
|
|
|
|
<button type="button" onclick={() => hide('recently-updated')} title="Hide section"
|
|
|
|
|
@@ -545,7 +564,7 @@
|
|
|
|
|
<img src={book.cover} alt={book.title} class="w-full h-full object-cover group-hover:scale-105 transition-transform duration-300" loading="lazy" />
|
|
|
|
|
{:else}
|
|
|
|
|
<div class="w-full h-full bg-(--color-surface-3) flex items-center justify-center">
|
|
|
|
|
<svg class="w-8 h-8 text-(--color-muted)" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M12 6.253v13m0-13C10.832 5.477 9.246 5 7.5 5S4.168 5.477 3 6.253v13C4.168 18.477 5.754 18 7.5 18s3.332.477 4.5 1.253m0-13C13.168 5.477 14.754 5 16.5 5c1.747 0 3.332.477 4.5 1.253v13C19.832 18.477 18.247 18 16.5 18c-1.746 0-3.332.477-4.5 1.253"/></svg>
|
|
|
|
|
<span class="text-4xl font-bold text-(--color-muted) select-none opacity-50">{(book.title ?? '?').charAt(0).toUpperCase()}</span>
|
|
|
|
|
</div>
|
|
|
|
|
{/if}
|
|
|
|
|
{#if count > 1}
|
|
|
|
|
@@ -577,7 +596,7 @@
|
|
|
|
|
{#if data.subscriptionFeed.length > 0 && !hidden.has('from-following')}
|
|
|
|
|
<section class="mb-10">
|
|
|
|
|
<div class="flex items-baseline justify-between mb-3">
|
|
|
|
|
<h2 class="text-base font-bold text-(--color-text)">{m.home_from_following()}</h2>
|
|
|
|
|
<h2 class="text-lg font-bold text-(--color-text)">{m.home_from_following()}</h2>
|
|
|
|
|
<button type="button" onclick={() => hide('from-following')} title="Hide section"
|
|
|
|
|
class="text-(--color-muted) hover:text-(--color-text) transition-colors">
|
|
|
|
|
<svg class="w-3.5 h-3.5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
|
|
|
@@ -594,7 +613,7 @@
|
|
|
|
|
<img src={book.cover} alt={book.title} class="w-full h-full object-cover group-hover:scale-105 transition-transform duration-300" loading="lazy" />
|
|
|
|
|
{:else}
|
|
|
|
|
<div class="w-full h-full bg-(--color-surface-3) flex items-center justify-center">
|
|
|
|
|
<svg class="w-8 h-8 text-(--color-muted)" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M12 6.253v13m0-13C10.832 5.477 9.246 5 7.5 5S4.168 5.477 3 6.253v13C4.168 18.477 5.754 18 7.5 18s3.332.477 4.5 1.253m0-13C13.168 5.477 14.754 5 16.5 5c1.747 0 3.332.477 4.5 1.253v13C19.832 18.477 18.247 18 16.5 18c-1.746 0-3.332.477-4.5 1.253"/></svg>
|
|
|
|
|
<span class="text-4xl font-bold text-(--color-muted) select-none opacity-50">{(book.title ?? '?').charAt(0).toUpperCase()}</span>
|
|
|
|
|
</div>
|
|
|
|
|
{/if}
|
|
|
|
|
</div>
|
|
|
|
|
|