diff --git a/src/main.ts b/src/main.ts
index 8a79dbb..f91c3fb 100644
--- a/src/main.ts
+++ b/src/main.ts
@@ -22,7 +22,7 @@ import { BackupReadingLogCommand } from "@commands/CreateReadingLogBackupCommand
import { RestoreReadingLogBackupCommand } from "@commands/RestoreReadingLogBackupCommand";
import { Goodreads } from "@data-sources/Goodreads";
import { CreateBookFromGoodreadsUrlCommand } from "@commands/CreateBookFromGoodreadsUrlCommand";
-import { registerBookshelfCodeBlockProcessor } from "@ui/code-blocks/BookshelfCodeBlock";
+import { registerShelfCodeBlockProcessor } from "@ui/code-blocks/ShelfCodeBlock";
export default class BookTrackerPlugin extends Plugin {
public settings: BookTrackerPluginSettings;
@@ -86,7 +86,7 @@ export default class BookTrackerPlugin extends Plugin {
registerReadingLogCodeBlockProcessor(this);
registerReadingStatsCodeBlockProcessor(this);
- registerBookshelfCodeBlockProcessor(this);
+ registerShelfCodeBlockProcessor(this);
}
onunload() {}
diff --git a/src/ui/code-blocks/BookshelfCodeBlock.ts b/src/ui/code-blocks/BookshelfCodeBlock.ts
deleted file mode 100644
index 35cc4fd..0000000
--- a/src/ui/code-blocks/BookshelfCodeBlock.ts
+++ /dev/null
@@ -1,35 +0,0 @@
-import { registerCodeBlockRenderer } from ".";
-import { SvelteCodeBlockRenderer } from "./SvelteCodeBlockRenderer";
-import BookshelfCodeBlockView from "./BookshelfCodeBlockView.svelte";
-import type BookTrackerPlugin from "@src/main";
-import z from "zod/v4";
-
-export function registerBookshelfCodeBlockProcessor(
- plugin: BookTrackerPlugin
-): void {
- registerCodeBlockRenderer(
- plugin,
- "bookshelf",
- (source, el) => new BookshelfCodeBlockRenderer(plugin, source, el)
- );
-}
-
-export const BookshelfSettingsSchema = z.object({
- titleProperty: z.string(),
- subtitleProperty: z.optional(z.string()),
- authorsProperty: z.string(),
-});
-
-export class BookshelfCodeBlockRenderer extends SvelteCodeBlockRenderer<
- typeof BookshelfCodeBlockView
-> {
- constructor(
- plugin: BookTrackerPlugin,
- source: string,
- contentEl: HTMLElement
- ) {
- super(contentEl, BookshelfCodeBlockView, { props: { plugin, source } });
- }
-
- onunload() {}
-}
diff --git a/src/ui/code-blocks/BookshelfCodeBlockView.svelte b/src/ui/code-blocks/BookshelfCodeBlockView.svelte
deleted file mode 100644
index 5e0fd9a..0000000
--- a/src/ui/code-blocks/BookshelfCodeBlockView.svelte
+++ /dev/null
@@ -1,166 +0,0 @@
-
-
-
- {#each books as book}
- {#if Array.isArray(book)}
-
- {#each book as bookData}
-
- plugin.app.workspace.openLinkText(
- bookData.file.path,
- "",
- true,
- )}
- />
- {/each}
-
- {:else}
-
- plugin.app.workspace.openLinkText(book.file.path, "", true)}
- />
- {/if}
- {/each}
-
diff --git a/src/ui/code-blocks/ShelfCodeBlock.ts b/src/ui/code-blocks/ShelfCodeBlock.ts
new file mode 100644
index 0000000..89ffaf7
--- /dev/null
+++ b/src/ui/code-blocks/ShelfCodeBlock.ts
@@ -0,0 +1,46 @@
+import { registerCodeBlockRenderer } from ".";
+import { SvelteCodeBlockRenderer } from "./SvelteCodeBlockRenderer";
+import ShelfCodeBockView from "./ShelfCodeBlockView.svelte";
+import type BookTrackerPlugin from "@src/main";
+import z from "zod/v4";
+import { STATUS_IN_PROGRESS, STATUS_READ, STATUS_TO_BE_READ } from "@src/const";
+
+export function registerShelfCodeBlockProcessor(
+ plugin: BookTrackerPlugin
+): void {
+ registerCodeBlockRenderer(
+ plugin,
+ "shelf",
+ (source, el) => new ShelfCodeBlockRenderer(plugin, source, el)
+ );
+}
+
+export const SHELF_VIEWS = ["table", "bookshelf"] as const;
+export type ShelfView = (typeof SHELF_VIEWS)[number];
+
+export const ShelfSettingsSchema = z.object({
+ statusFilter: z
+ .enum([STATUS_TO_BE_READ, STATUS_IN_PROGRESS, STATUS_READ])
+ .default(STATUS_TO_BE_READ),
+ defaultView: z.enum(SHELF_VIEWS).default("table"),
+ coverProperty: z.string(),
+ titleProperty: z.string(),
+ subtitleProperty: z.optional(z.string()),
+ authorsProperty: z.string(),
+ seriesTitleProperty: z.optional(z.string()),
+ seriesNumberProperty: z.optional(z.string()),
+});
+
+export class ShelfCodeBlockRenderer extends SvelteCodeBlockRenderer<
+ typeof ShelfCodeBockView
+> {
+ constructor(
+ plugin: BookTrackerPlugin,
+ source: string,
+ contentEl: HTMLElement
+ ) {
+ super(contentEl, ShelfCodeBockView, { props: { plugin, source } });
+ }
+
+ onunload() {}
+}
diff --git a/src/ui/code-blocks/ShelfCodeBlockView.svelte b/src/ui/code-blocks/ShelfCodeBlockView.svelte
new file mode 100644
index 0000000..02a9971
--- /dev/null
+++ b/src/ui/code-blocks/ShelfCodeBlockView.svelte
@@ -0,0 +1,289 @@
+
+
+
+
+
+ {#if settings.statusFilter === STATUS_READ}
+
+ {/if}
+
+ {#if view === "bookshelf"}
+
+ {#each books as book}
+ {#if Array.isArray(book)}
+
+ {#each book as bookData}
+
+ plugin.app.workspace.openLinkText(
+ bookData.file.path,
+ "",
+ true,
+ )}
+ />
+ {/each}
+
+ {:else}
+
+ plugin.app.workspace.openLinkText(
+ book.file.path,
+ "",
+ true,
+ )}
+ />
+ {/if}
+ {/each}
+
+ {:else if view === "table"}
+
+
+
+ Cover |
+ Title |
+ Authors |
+ {#if settings.seriesTitleProperty}
+ Series |
+ {/if}
+ {#if settings.seriesNumberProperty}
+ # |
+ {/if}
+ {#if settings.statusFilter === STATUS_IN_PROGRESS || settings.statusFilter === STATUS_READ}
+ Start Date |
+ {/if}
+ {#if settings.statusFilter === STATUS_READ}
+ End Date |
+ Rating |
+ {/if}
+
+
+
+ {#each metadataStore.metadata as book}
+
+
+
+ |
+ {book.frontmatter[settings.titleProperty]} |
+
+ {book.frontmatter[settings.authorsProperty].join(
+ ", ",
+ )}
+ |
+ {#if settings.seriesTitleProperty}
+
+ {book.frontmatter[settings.seriesTitleProperty]}
+ |
+ {/if}
+ {#if settings.seriesNumberProperty}
+
+ {book.frontmatter[
+ settings.seriesNumberProperty
+ ]}
+ |
+ {/if}
+ {#if settings.statusFilter === STATUS_IN_PROGRESS || settings.statusFilter === STATUS_READ}
+
+ {book.frontmatter[
+ settingsStore.settings.startDateProperty
+ ]}
+ |
+ {/if}
+ {#if settings.statusFilter === STATUS_READ}
+
+ {book.frontmatter[
+ settingsStore.settings.endDateProperty
+ ]}
+ |
+
+
+ |
+ {/if}
+
+ {/each}
+
+
+ {/if}
+
+
+
diff --git a/src/ui/components/DateFilter.svelte b/src/ui/components/DateFilter.svelte
new file mode 100644
index 0000000..b3b9842
--- /dev/null
+++ b/src/ui/components/DateFilter.svelte
@@ -0,0 +1,46 @@
+
+
+
+{#if store.filterYear !== ALL_TIME}
+
+{/if}
diff --git a/src/ui/components/Rating.svelte b/src/ui/components/Rating.svelte
new file mode 100644
index 0000000..902ca38
--- /dev/null
+++ b/src/ui/components/Rating.svelte
@@ -0,0 +1,186 @@
+
+
+{rating}
+
+
diff --git a/src/ui/stores/date-filter.svelte.ts b/src/ui/stores/date-filter.svelte.ts
index 66824c5..cfaa74e 100644
--- a/src/ui/stores/date-filter.svelte.ts
+++ b/src/ui/stores/date-filter.svelte.ts
@@ -22,21 +22,23 @@ export function createDateFilter(
initialMonth ? today.getMonth() + 1 : ALL_TIME
);
const filteredData = $derived.by(() => {
- return data().filter((item) => {
- const date = selector(item);
- if (filterYear !== ALL_TIME) {
- if (date.year() !== filterYear) {
- return false;
+ return data()
+ .filter((item) => {
+ const date = selector(item);
+ if (filterYear !== ALL_TIME) {
+ if (date.year() !== filterYear) {
+ return false;
+ }
}
- }
- if (filterMonth !== ALL_TIME) {
- if (date.month() !== filterMonth - 1) {
- return false;
+ if (filterMonth !== ALL_TIME) {
+ if (date.month() !== filterMonth - 1) {
+ return false;
+ }
}
- }
- return true;
- });
+ return true;
+ })
+ .sort((a, b) => selector(a).diff(selector(b)));
});
const filterYears = $derived.by(() => {