obsidian-book-tracker/src/ui/components/DetailsView.svelte

216 lines
5.4 KiB
Svelte

<script lang="ts">
import { STATUS_IN_PROGRESS, STATUS_READ } from "@src/const";
import type BookTrackerPlugin from "@src/main";
import { getMetadataContext } from "@ui/stores/metadata.svelte";
import { getSettingsContext } from "@ui/stores/settings.svelte";
import { getLinkpath } from "obsidian";
import type { ShelfSettings } from "@ui/code-blocks/ShelfCodeBlock";
import { Dot, Flame, Star, StarHalf } from "lucide-svelte";
import RatingInput from "./RatingInput.svelte";
import OpenFileLink from "./OpenFileLink.svelte";
interface Props {
plugin: BookTrackerPlugin;
settings: ShelfSettings;
}
const { plugin, settings }: Props = $props();
const settingsStore = getSettingsContext();
const metadataStore = getMetadataContext();
</script>
<div class="book-details-list">
{#each metadataStore.metadata as book}
{@const coverPath = book.frontmatter[settings.coverProperty]}
{@const title = book.frontmatter[settings.titleProperty]}
{@const subtitle = settings.subtitleProperty
? book.frontmatter[settings.subtitleProperty]
: undefined}
{@const authors = book.frontmatter[settings.authorsProperty]}
{@const description = settings.descriptionProperty
? book.frontmatter[settings.descriptionProperty]
: undefined}
{@const seriesTitle = settings.seriesTitleProperty
? book.frontmatter[settings.seriesTitleProperty]
: undefined}
{@const seriesNumber = settings.seriesNumberProperty
? book.frontmatter[settings.seriesNumberProperty]
: undefined}
{@const startDate =
book.frontmatter[settingsStore.settings.startDateProperty]}
{@const endDate =
book.frontmatter[settingsStore.settings.endDateProperty]}
{@const rating =
book.frontmatter[settingsStore.settings.ratingProperty] ?? 0}
{@const spice =
book.frontmatter[settingsStore.settings.spiceProperty] ?? 0}
<div class="book-details">
<img
src={plugin.app.vault.getResourcePath(
plugin.app.vault.getFileByPath(coverPath)!,
)}
alt={title}
/>
<div class="book-info">
<OpenFileLink file={book.file}>
<h2 class="book-title">
{title}
</h2>
</OpenFileLink>
{#if subtitle}
<p class="subtitle">{subtitle}</p>
{/if}
<p class="authors">By: {authors.join(", ")}</p>
{#if seriesTitle}
<p class="series">
<span class="series-title">{seriesTitle}</span>
{#if seriesNumber}
<span class="series-number">#{seriesNumber}</span>
{/if}
</p>
{/if}
{#if description}
<hr />
<p class="description">{@html description}</p>
<hr />
{/if}
<div class="footer">
{#if settings.statusFilter === STATUS_IN_PROGRESS || settings.statusFilter === STATUS_READ}
<p class="start-date">
Started:
<datetime datetime={startDate}>{startDate}</datetime
>
</p>
{/if}
{#if settings.statusFilter === STATUS_IN_PROGRESS}
<Dot color="var(--text-muted)" />
<p class="current-page">
Current Page: {plugin.readingLog.getLastEntryForBook(
book.file.basename,
)?.pagesReadTotal ?? 0}
</p>
{/if}
{#if settings.statusFilter === STATUS_READ}
{@const iconSize = 18}
<Dot color="var(--text-muted)" />
<p class="end-date">
Finished:
<datetime datetime={endDate}>{endDate}</datetime>
</p>
<Dot color="var(--text-muted)" />
<RatingInput value={rating} disabled {iconSize}>
{#snippet inactive()}
<Star
color="var(--background-modifier-border)"
/>
{/snippet}
{#snippet active()}
<Star
color="var(--color-yellow)"
fill="rgba(var(--color-yellow-rgb), 0.2)"
/>
{/snippet}
{#snippet partial()}
<Star
color="var(--background-modifier-border)"
/>
<StarHalf
color="var(--color-yellow)"
fill="rgba(var(--color-yellow-rgb), 0.2)"
/>
{/snippet}
</RatingInput>
<RatingInput value={spice} disabled {iconSize}>
{#snippet inactive()}
<Flame
color="var(--background-modifier-border)"
/>
{/snippet}
{#snippet active()}
<Flame
color="var(--color-red)"
fill="rgba(var(--color-red-rgb), 0.2)"
/>
{/snippet}
</RatingInput>
{/if}
</div>
</div>
</div>
{/each}
</div>
<style lang="scss">
@use "../styles/breakpoints";
.book-details-list {
display: flex;
flex-direction: column;
gap: var(--size-4-6);
.book-details {
display: flex;
align-items: start;
gap: 1rem;
background-color: var(--background-secondary);
border-radius: var(--radius-l);
img {
border-radius: var(--radius-l);
max-width: 30%;
}
.book-info {
display: flex;
flex-direction: column;
gap: var(--size-4-2);
padding: var(--size-4-4);
h2,
p {
margin: 0;
}
hr {
margin: var(--size-4-2) 0;
}
.authors,
.series {
font-size: var(--font-small);
color: var(--text-muted);
}
.description {
max-height: 30rem;
overflow-y: auto;
}
.footer {
font-size: var(--font-smaller);
color: var(--text-muted);
display: flex;
gap: var(--size-2-2);
align-items: center;
flex-wrap: wrap;
}
}
}
container: book-details-list / inline-size;
@container book-details-list (width < 600px) {
.book-details {
flex-direction: column;
align-items: center;
img {
max-height: 30rem;
max-width: 100%;
}
}
}
}
</style>