generated from tpl/obsidian-sample-plugin
Compare commits
2 Commits
Author | SHA1 | Date |
---|---|---|
|
8b19f1ea03 | |
|
0ef651d661 |
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"id": "obsidian-book-tracker",
|
"id": "obsidian-book-tracker",
|
||||||
"name": "Book Tracker",
|
"name": "Book Tracker",
|
||||||
"version": "1.6.1",
|
"version": "1.7.1",
|
||||||
"minAppVersion": "0.15.0",
|
"minAppVersion": "0.15.0",
|
||||||
"description": "Simplifies tracking your reading progress and managing your book collection in Obsidian.",
|
"description": "Simplifies tracking your reading progress and managing your book collection in Obsidian.",
|
||||||
"author": "FiFiTiDo",
|
"author": "FiFiTiDo",
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "obsidian-book-tracker",
|
"name": "obsidian-book-tracker",
|
||||||
"version": "1.6.1",
|
"version": "1.7.1",
|
||||||
"description": "Simplifies tracking your reading progress and managing your book collection in Obsidian.",
|
"description": "Simplifies tracking your reading progress and managing your book collection in Obsidian.",
|
||||||
"main": "main.js",
|
"main": "main.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
<script lang="ts">
|
||||||
|
interface Props {
|
||||||
|
id?: string;
|
||||||
|
name?: string;
|
||||||
|
value?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
let { id, name, value = $bindable() }: Props = $props();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<input {id} {name} type="text" bind:value />
|
|
@ -0,0 +1,21 @@
|
||||||
|
<script lang="ts">
|
||||||
|
interface Props {
|
||||||
|
id?: string;
|
||||||
|
name?: string;
|
||||||
|
checked?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
let { id, name, checked = $bindable() }: Props = $props();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div
|
||||||
|
class="checkbox-container"
|
||||||
|
class:is-enabled={checked}
|
||||||
|
onclick={() => (checked = !checked)}
|
||||||
|
onkeypress={(e) => e.key === "Space" && (checked = !checked)}
|
||||||
|
role="switch"
|
||||||
|
aria-checked={checked}
|
||||||
|
tabindex="0"
|
||||||
|
>
|
||||||
|
<input {id} {name} type="checkbox" bind:checked tabindex="0" />
|
||||||
|
</div>
|
|
@ -3,42 +3,39 @@
|
||||||
import TextInputSuggest, { type Item } from "./TextInputSuggest.svelte";
|
import TextInputSuggest, { type Item } from "./TextInputSuggest.svelte";
|
||||||
import type { StringKeys } from "@utils/types";
|
import type { StringKeys } from "@utils/types";
|
||||||
import { getAppContext } from "@ui/stores/app";
|
import { getAppContext } from "@ui/stores/app";
|
||||||
|
import { isInAnyFolder } from "@utils/fs";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
id: string;
|
id: string;
|
||||||
asString?: boolean;
|
|
||||||
property?: StringKeys<TFile>;
|
property?: StringKeys<TFile>;
|
||||||
inFolder?: string;
|
folderFilter?: string[];
|
||||||
value?: TFile | string;
|
value?: string;
|
||||||
disabled?: boolean;
|
disabled?: boolean;
|
||||||
onSelected?: (fileOrPath: TFile | string) => void;
|
onSelected?: (propertyValue: string) => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
let {
|
let {
|
||||||
id,
|
id,
|
||||||
asString,
|
|
||||||
property = "path",
|
property = "path",
|
||||||
inFolder,
|
folderFilter,
|
||||||
value = $bindable(),
|
value = $bindable(),
|
||||||
disabled,
|
disabled,
|
||||||
onSelected,
|
onSelected,
|
||||||
}: Props = $props();
|
}: Props = $props();
|
||||||
const app = getAppContext();
|
const app = getAppContext();
|
||||||
|
|
||||||
let items: Item<TFile | string>[] = $state([]);
|
let items: Item<string>[] = $state([]);
|
||||||
|
|
||||||
function handleChange(query: string) {
|
function handleChange(query: string) {
|
||||||
items = app.vault
|
items = app.vault
|
||||||
.getMarkdownFiles()
|
.getMarkdownFiles()
|
||||||
.filter(
|
.filter(
|
||||||
(f) =>
|
(f) =>
|
||||||
(inFolder === undefined || f.path.startsWith(inFolder)) &&
|
(folderFilter === undefined ||
|
||||||
|
isInAnyFolder(f, folderFilter)) &&
|
||||||
f[property].toLowerCase().includes(query.toLowerCase()),
|
f[property].toLowerCase().includes(query.toLowerCase()),
|
||||||
)
|
)
|
||||||
.map((f) => ({
|
.map((f) => f[property]);
|
||||||
text: f[property],
|
|
||||||
value: asString ? f[property] : f,
|
|
||||||
}));
|
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -3,22 +3,21 @@
|
||||||
import TextInputSuggest, { type Item } from "./TextInputSuggest.svelte";
|
import TextInputSuggest, { type Item } from "./TextInputSuggest.svelte";
|
||||||
import type { StringKeys } from "@utils/types";
|
import type { StringKeys } from "@utils/types";
|
||||||
import { getAppContext } from "@ui/stores/app";
|
import { getAppContext } from "@ui/stores/app";
|
||||||
|
import { isInAnyFolder } from "@utils/fs";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
id: string;
|
id: string;
|
||||||
asString?: boolean;
|
|
||||||
property?: StringKeys<TFolder>;
|
property?: StringKeys<TFolder>;
|
||||||
inFolder?: string;
|
folderFilter?: string[];
|
||||||
value?: TFolder | string;
|
value?: string;
|
||||||
disabled?: boolean;
|
disabled?: boolean;
|
||||||
onSelected?: (folderOrPath: TFolder | string) => void;
|
onSelected?: (propertyValue: string) => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
let {
|
let {
|
||||||
id,
|
id,
|
||||||
asString,
|
|
||||||
property = "path",
|
property = "path",
|
||||||
inFolder,
|
folderFilter,
|
||||||
value = $bindable(),
|
value = $bindable(),
|
||||||
disabled,
|
disabled,
|
||||||
onSelected,
|
onSelected,
|
||||||
|
@ -32,13 +31,11 @@
|
||||||
.getAllFolders()
|
.getAllFolders()
|
||||||
.filter(
|
.filter(
|
||||||
(f) =>
|
(f) =>
|
||||||
(inFolder === undefined || f.path.startsWith(inFolder)) &&
|
(folderFilter === undefined ||
|
||||||
|
isInAnyFolder(f, folderFilter)) &&
|
||||||
f[property].toLowerCase().includes(query.toLowerCase()),
|
f[property].toLowerCase().includes(query.toLowerCase()),
|
||||||
)
|
)
|
||||||
.map((f) => ({
|
.map((f) => f[property]);
|
||||||
text: f[property],
|
|
||||||
value: asString ? f[property] : f,
|
|
||||||
}));
|
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -12,16 +12,14 @@
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
id: string;
|
id: string;
|
||||||
asString?: boolean;
|
value?: string;
|
||||||
value?: Property | string;
|
|
||||||
accepts?: string[];
|
accepts?: string[];
|
||||||
disabled?: boolean;
|
disabled?: boolean;
|
||||||
onSelected?: (propertyOrName: Property | string) => void;
|
onSelected?: (propertyName: string) => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
let {
|
let {
|
||||||
id,
|
id,
|
||||||
asString,
|
|
||||||
value = $bindable(),
|
value = $bindable(),
|
||||||
accepts,
|
accepts,
|
||||||
disabled,
|
disabled,
|
||||||
|
@ -29,7 +27,7 @@
|
||||||
}: Props = $props();
|
}: Props = $props();
|
||||||
const app = getAppContext();
|
const app = getAppContext();
|
||||||
|
|
||||||
let items: Item<Property | string>[] = $state([]);
|
let items: Item<string>[] = $state([]);
|
||||||
|
|
||||||
async function handleChange(query: string) {
|
async function handleChange(query: string) {
|
||||||
const typesContent = await app.vault.adapter.read(
|
const typesContent = await app.vault.adapter.read(
|
||||||
|
@ -45,10 +43,7 @@
|
||||||
|
|
||||||
return name.toLowerCase().includes(query.toLowerCase());
|
return name.toLowerCase().includes(query.toLowerCase());
|
||||||
})
|
})
|
||||||
.map(([name, type]) => ({
|
.map(([name, _]) => name);
|
||||||
text: name,
|
|
||||||
value: asString ? name : { name, type },
|
|
||||||
}));
|
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
<script lang="ts" module>
|
<script lang="ts" module>
|
||||||
export type Item<T> = {
|
export type Item<T> =
|
||||||
text: string;
|
| {
|
||||||
value: T;
|
label: string;
|
||||||
};
|
value: T;
|
||||||
|
}
|
||||||
|
| (T extends string ? T : never);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
|
@ -26,7 +28,7 @@
|
||||||
|
|
||||||
let {
|
let {
|
||||||
id,
|
id,
|
||||||
items,
|
items: itemsProp,
|
||||||
value = $bindable(),
|
value = $bindable(),
|
||||||
loading = false,
|
loading = false,
|
||||||
suggestion,
|
suggestion,
|
||||||
|
@ -35,6 +37,12 @@
|
||||||
onSelected,
|
onSelected,
|
||||||
}: Props = $props();
|
}: Props = $props();
|
||||||
|
|
||||||
|
const items = $derived(
|
||||||
|
itemsProp.map((item) =>
|
||||||
|
typeof item === "string" ? { label: item, value: item } : item,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
let query = $state("");
|
let query = $state("");
|
||||||
let expanded = $state(false);
|
let expanded = $state(false);
|
||||||
let selectedIndex = $state(0);
|
let selectedIndex = $state(0);
|
||||||
|
@ -53,7 +61,7 @@
|
||||||
const idx = findIndex(value);
|
const idx = findIndex(value);
|
||||||
if (idx !== -1) {
|
if (idx !== -1) {
|
||||||
const item = items[idx];
|
const item = items[idx];
|
||||||
query = item.text;
|
query = item.label;
|
||||||
selectedIndex = idx;
|
selectedIndex = idx;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -99,7 +107,7 @@
|
||||||
async function selectItem(index: number) {
|
async function selectItem(index: number) {
|
||||||
const item = items[index];
|
const item = items[index];
|
||||||
if (!item) return;
|
if (!item) return;
|
||||||
const { text: newQuery, value: newValue } = item;
|
const { label: newQuery, value: newValue } = item;
|
||||||
selectedIndex = index;
|
selectedIndex = index;
|
||||||
expanded = false;
|
expanded = false;
|
||||||
query = newQuery;
|
query = newQuery;
|
||||||
|
@ -195,7 +203,7 @@
|
||||||
{#if suggestion}
|
{#if suggestion}
|
||||||
{@render suggestion(item)}
|
{@render suggestion(item)}
|
||||||
{:else}
|
{:else}
|
||||||
{item.text}
|
{item.label}
|
||||||
{/if}
|
{/if}
|
||||||
</li>
|
</li>
|
||||||
{/each}
|
{/each}
|
|
@ -1,7 +1,7 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import type { ComponentProps } from "svelte";
|
import type { ComponentProps } from "svelte";
|
||||||
import Item from "./Item.svelte";
|
import Item from "./Item.svelte";
|
||||||
import FileSuggest from "../suggesters/FileSuggest.svelte";
|
import FileSuggest from "../form/suggesters/FileSuggest.svelte";
|
||||||
|
|
||||||
type Props = Omit<ComponentProps<typeof Item>, "control"> & {
|
type Props = Omit<ComponentProps<typeof Item>, "control"> & {
|
||||||
id: string;
|
id: string;
|
||||||
|
@ -13,6 +13,6 @@
|
||||||
|
|
||||||
<Item {name} {description}>
|
<Item {name} {description}>
|
||||||
{#snippet control()}
|
{#snippet control()}
|
||||||
<FileSuggest {id} asString bind:value />
|
<FileSuggest {id} bind:value />
|
||||||
{/snippet}
|
{/snippet}
|
||||||
</Item>
|
</Item>
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import type { ComponentProps } from "svelte";
|
import type { ComponentProps } from "svelte";
|
||||||
import Item from "./Item.svelte";
|
import Item from "./Item.svelte";
|
||||||
import FolderSuggest from "../suggesters/FolderSuggest.svelte";
|
import FolderSuggest from "../form/suggesters/FolderSuggest.svelte";
|
||||||
|
|
||||||
type Props = Omit<ComponentProps<typeof Item>, "control"> & {
|
type Props = Omit<ComponentProps<typeof Item>, "control"> & {
|
||||||
id: string;
|
id: string;
|
||||||
|
@ -13,6 +13,6 @@
|
||||||
|
|
||||||
<Item {name} {description}>
|
<Item {name} {description}>
|
||||||
{#snippet control()}
|
{#snippet control()}
|
||||||
<FolderSuggest {id} asString bind:value />
|
<FolderSuggest {id} bind:value />
|
||||||
{/snippet}
|
{/snippet}
|
||||||
</Item>
|
</Item>
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import type { ComponentProps } from "svelte";
|
import type { ComponentProps } from "svelte";
|
||||||
import Item from "./Item.svelte";
|
import Item from "./Item.svelte";
|
||||||
import PropertySuggest from "../suggesters/PropertySuggest.svelte";
|
import PropertySuggest from "../form/suggesters/PropertySuggest.svelte";
|
||||||
|
|
||||||
type Props = Omit<ComponentProps<typeof Item>, "control"> & {
|
type Props = Omit<ComponentProps<typeof Item>, "control"> & {
|
||||||
id: string;
|
id: string;
|
||||||
|
@ -20,6 +20,6 @@
|
||||||
|
|
||||||
<Item {name} {description}>
|
<Item {name} {description}>
|
||||||
{#snippet control()}
|
{#snippet control()}
|
||||||
<PropertySuggest {id} asString bind:value {accepts} />
|
<PropertySuggest {id} bind:value {accepts} />
|
||||||
{/snippet}
|
{/snippet}
|
||||||
</Item>
|
</Item>
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import type { ComponentProps } from "svelte";
|
import type { ComponentProps } from "svelte";
|
||||||
import Item from "./Item.svelte";
|
import Item from "./Item.svelte";
|
||||||
|
import TextControl from "../form/TextControl.svelte";
|
||||||
|
|
||||||
type Props = Omit<ComponentProps<typeof Item>, "control"> & {
|
type Props = Omit<ComponentProps<typeof Item>, "control"> & {
|
||||||
id?: string;
|
id?: string;
|
||||||
|
@ -12,6 +13,6 @@
|
||||||
|
|
||||||
<Item {name} {description}>
|
<Item {name} {description}>
|
||||||
{#snippet control()}
|
{#snippet control()}
|
||||||
<input {id} type="text" bind:value />
|
<TextControl {id} bind:value />
|
||||||
{/snippet}
|
{/snippet}
|
||||||
</Item>
|
</Item>
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import type { ComponentProps } from "svelte";
|
import type { ComponentProps } from "svelte";
|
||||||
import Item from "./Item.svelte";
|
import Item from "./Item.svelte";
|
||||||
|
import ToggleControl from "../form/ToggleControl.svelte";
|
||||||
|
|
||||||
type Props = Omit<ComponentProps<typeof Item>, "control"> & {
|
type Props = Omit<ComponentProps<typeof Item>, "control"> & {
|
||||||
id?: string;
|
id?: string;
|
||||||
|
@ -12,15 +13,6 @@
|
||||||
|
|
||||||
<Item {name} {description}>
|
<Item {name} {description}>
|
||||||
{#snippet control()}
|
{#snippet control()}
|
||||||
<!-- svelte-ignore a11y_no_static_element_interactions -->
|
<ToggleControl {id} bind:checked />
|
||||||
<!-- svelte-ignore a11y_click_events_have_key_events -->
|
|
||||||
<!-- input only covers part of the toggle element. onclick here covers the rest -->
|
|
||||||
<div
|
|
||||||
class="checkbox-container"
|
|
||||||
class:is-enabled={checked}
|
|
||||||
onclick={() => (checked = !checked)}
|
|
||||||
>
|
|
||||||
<input {id} type="checkbox" bind:checked tabindex="0" />
|
|
||||||
</div>
|
|
||||||
{/snippet}
|
{/snippet}
|
||||||
</Item>
|
</Item>
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import type BookTrackerPlugin from "@src/main";
|
import type BookTrackerPlugin from "@src/main";
|
||||||
import type { ReadingLogEntry } from "@utils/ReadingLog";
|
import type { ReadingLogEntry } from "@utils/ReadingLog";
|
||||||
import FileSuggest from "@ui/components/suggesters/FileSuggest.svelte";
|
import FileSuggest from "@ui/components/form/suggesters/FileSuggest.svelte";
|
||||||
import { v4 as uuidv4 } from "uuid";
|
import { v4 as uuidv4 } from "uuid";
|
||||||
import { createPrevious } from "@ui/stores/previous.svelte";
|
import { createPrevious } from "@ui/stores/previous.svelte";
|
||||||
import { createMetadata } from "@ui/stores/metadata.svelte";
|
import { createMetadata } from "@ui/stores/metadata.svelte";
|
||||||
|
@ -16,6 +16,7 @@
|
||||||
setReadingLogContext,
|
setReadingLogContext,
|
||||||
} from "@ui/stores/reading-log.svelte";
|
} from "@ui/stores/reading-log.svelte";
|
||||||
import { onDestroy } from "svelte";
|
import { onDestroy } from "svelte";
|
||||||
|
import ToggleControl from "@ui/components/form/ToggleControl.svelte";
|
||||||
|
|
||||||
const INPUT_DATETIME_FORMAT = "YYYY-MM-DDTHH:mm";
|
const INPUT_DATETIME_FORMAT = "YYYY-MM-DDTHH:mm";
|
||||||
|
|
||||||
|
@ -43,13 +44,24 @@
|
||||||
const bookMetadata = $derived(
|
const bookMetadata = $derived(
|
||||||
metadataStore.metadata.find((m) => m.file.basename === book),
|
metadataStore.metadata.find((m) => m.file.basename === book),
|
||||||
);
|
);
|
||||||
const lastEntryIndex = $derived(
|
const previousEntry = $derived.by(() => {
|
||||||
readingLogStore.entries.findLastIndex((e) => e.book === book),
|
const index = readingLogStore.entries.findIndex(
|
||||||
);
|
(e) => e.id === entry?.id,
|
||||||
const lastEntry = $derived(
|
);
|
||||||
lastEntryIndex !== -1 ? readingLogStore.entries[lastEntryIndex] : null,
|
|
||||||
);
|
|
||||||
|
|
||||||
|
let data = readingLogStore.entries;
|
||||||
|
if (index !== -1) {
|
||||||
|
data = data.slice(0, index);
|
||||||
|
}
|
||||||
|
|
||||||
|
const previousEntryIndex = data.findLastIndex((e) => e.book === book);
|
||||||
|
|
||||||
|
return previousEntryIndex !== -1
|
||||||
|
? readingLogStore.entries[previousEntryIndex]
|
||||||
|
: null;
|
||||||
|
});
|
||||||
|
|
||||||
|
let syncPageCounts = $state(true);
|
||||||
const pageCount = $derived(bookMetadata?.book.pageCount ?? 0);
|
const pageCount = $derived(bookMetadata?.book.pageCount ?? 0);
|
||||||
let pagesRead = $state(entry?.pagesRead ?? 0);
|
let pagesRead = $state(entry?.pagesRead ?? 0);
|
||||||
const pagesReadPrev = createPrevious(() => pagesRead);
|
const pagesReadPrev = createPrevious(() => pagesRead);
|
||||||
|
@ -61,20 +73,24 @@
|
||||||
);
|
);
|
||||||
|
|
||||||
$effect(() => {
|
$effect(() => {
|
||||||
pagesReadTotal = (lastEntry?.pagesReadTotal ?? 0) + pagesRead;
|
if (!syncPageCounts) return;
|
||||||
|
pagesReadTotal = (previousEntry?.pagesReadTotal ?? 0) + pagesRead;
|
||||||
});
|
});
|
||||||
|
|
||||||
$effect(() => {
|
$effect(() => {
|
||||||
|
if (!syncPageCounts) return;
|
||||||
const diff = pagesRead - (pagesReadPrev.value ?? 0);
|
const diff = pagesRead - (pagesReadPrev.value ?? 0);
|
||||||
pagesRead = pagesRead;
|
pagesRead = pagesRead;
|
||||||
pagesReadTotal = pagesReadTotal + diff;
|
pagesReadTotal = pagesReadTotal + diff;
|
||||||
});
|
});
|
||||||
|
|
||||||
$effect(() => {
|
$effect(() => {
|
||||||
|
if (!syncPageCounts) return;
|
||||||
pagesRemaining = pageCount - pagesReadTotal;
|
pagesRemaining = pageCount - pagesReadTotal;
|
||||||
});
|
});
|
||||||
|
|
||||||
$effect(() => {
|
$effect(() => {
|
||||||
|
if (!syncPageCounts) return;
|
||||||
pagesReadTotal = Math.max(pagesReadTotal, pagesRead);
|
pagesReadTotal = Math.max(pagesReadTotal, pagesRead);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -108,9 +124,11 @@
|
||||||
<label for="book">Book</label>
|
<label for="book">Book</label>
|
||||||
<FileSuggest
|
<FileSuggest
|
||||||
id="book"
|
id="book"
|
||||||
asString
|
|
||||||
property="basename"
|
property="basename"
|
||||||
inFolder={plugin.settings.bookFolder}
|
folderFilter={[
|
||||||
|
plugin.settings.tbrFolder,
|
||||||
|
plugin.settings.readBooksFolder,
|
||||||
|
]}
|
||||||
bind:value={book}
|
bind:value={book}
|
||||||
/>
|
/>
|
||||||
<label for="pagesRead">Pages Read</label>
|
<label for="pagesRead">Pages Read</label>
|
||||||
|
@ -136,6 +154,12 @@
|
||||||
id="pagesRemaining"
|
id="pagesRemaining"
|
||||||
bind:value={pagesRemaining}
|
bind:value={pagesRemaining}
|
||||||
/>
|
/>
|
||||||
|
<label for="syncPageCounts">Sync Page Counts</label>
|
||||||
|
<ToggleControl
|
||||||
|
name="syncPageCounts"
|
||||||
|
id="syncPageCounts"
|
||||||
|
bind:checked={syncPageCounts}
|
||||||
|
/>
|
||||||
<label for="createdAt">Created At</label>
|
<label for="createdAt">Created At</label>
|
||||||
<input
|
<input
|
||||||
type="datetime-local"
|
type="datetime-local"
|
||||||
|
|
|
@ -170,35 +170,29 @@
|
||||||
|
|
||||||
<div class="obt-settings">
|
<div class="obt-settings">
|
||||||
<Header title="Folders" />
|
<Header title="Folders" />
|
||||||
<FolderSuggestItem
|
|
||||||
id="book-folder"
|
|
||||||
name="Book Folder"
|
|
||||||
description="Select the folder where book entries are stored."
|
|
||||||
bind:value={settingsStore.settings.bookFolder}
|
|
||||||
/>
|
|
||||||
<FolderSuggestItem
|
<FolderSuggestItem
|
||||||
id="tbr-folder"
|
id="tbr-folder"
|
||||||
name="To Be Read Folder"
|
name="To Be Read Folder"
|
||||||
description="Select the folder to use for To Be Read entries"
|
description="The folder to use for To Be Read or Currently Reading book entries."
|
||||||
bind:value={settingsStore.settings.tbrFolder}
|
bind:value={settingsStore.settings.tbrFolder}
|
||||||
/>
|
/>
|
||||||
<FolderSuggestItem
|
<FolderSuggestItem
|
||||||
id="read-folder"
|
id="read-folder"
|
||||||
name="Read Books Folder"
|
name="Read Books Folder"
|
||||||
description="Select the folder to use for Read entries."
|
description="The folder to use for Read book entries."
|
||||||
bind:value={settingsStore.settings.readBooksFolder}
|
bind:value={settingsStore.settings.readBooksFolder}
|
||||||
/>
|
/>
|
||||||
<ToggleItem
|
<ToggleItem
|
||||||
id="organize-read-books"
|
id="organize-read-books"
|
||||||
name="Organize Read Books"
|
name="Organize Read Books"
|
||||||
description="Organize read books into folders based on the date read."
|
description="Whether to automatically organize read books into folders, based on the date read, when finishing a book."
|
||||||
bind:checked={settingsStore.settings.organizeReadBooks}
|
bind:checked={settingsStore.settings.organizeReadBooks}
|
||||||
/>
|
/>
|
||||||
<Header title="Book Creation" />
|
<Header title="Book Creation" />
|
||||||
<FileSuggestItem
|
<FileSuggestItem
|
||||||
id="template-file"
|
id="template-file"
|
||||||
name="Template File"
|
name="Template File"
|
||||||
description="Select the template file to use for new book entries."
|
description="The template file to use when creating new book entries."
|
||||||
bind:value={settingsStore.settings.templateFile}
|
bind:value={settingsStore.settings.templateFile}
|
||||||
/>
|
/>
|
||||||
<TextInputItem
|
<TextInputItem
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
export interface BookTrackerSettings {
|
export interface BookTrackerSettings {
|
||||||
bookFolder: string;
|
|
||||||
tbrFolder: string;
|
tbrFolder: string;
|
||||||
readBooksFolder: string;
|
readBooksFolder: string;
|
||||||
organizeReadBooks: boolean;
|
organizeReadBooks: boolean;
|
||||||
|
@ -34,7 +33,6 @@ export interface BookTrackerSettings {
|
||||||
}
|
}
|
||||||
|
|
||||||
export const DEFAULT_SETTINGS: BookTrackerSettings = {
|
export const DEFAULT_SETTINGS: BookTrackerSettings = {
|
||||||
bookFolder: "books",
|
|
||||||
tbrFolder: "books/tbr",
|
tbrFolder: "books/tbr",
|
||||||
readBooksFolder: "books/read",
|
readBooksFolder: "books/read",
|
||||||
organizeReadBooks: true,
|
organizeReadBooks: true,
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { normalizePath, type Vault } from "obsidian";
|
import { normalizePath, TAbstractFile, type Vault } from "obsidian";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A simple analog of Node.js's `path.join(...)`.
|
* A simple analog of Node.js's `path.join(...)`.
|
||||||
|
@ -52,3 +52,7 @@ export async function mkdirRecursive(
|
||||||
await vault.adapter.mkdir(stack.pop()!);
|
await vault.adapter.mkdir(stack.pop()!);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function isInAnyFolder(file: TAbstractFile, folders: string[]): boolean {
|
||||||
|
return folders.some((folder) => file.path.startsWith(folder));
|
||||||
|
}
|
||||||
|
|
|
@ -10,5 +10,7 @@
|
||||||
"1.4.2": "0.15.0",
|
"1.4.2": "0.15.0",
|
||||||
"1.5.0": "0.15.0",
|
"1.5.0": "0.15.0",
|
||||||
"1.6.0": "0.15.0",
|
"1.6.0": "0.15.0",
|
||||||
"1.6.1": "0.15.0"
|
"1.6.1": "0.15.0",
|
||||||
|
"1.7.0": "0.15.0",
|
||||||
|
"1.7.1": "0.15.0"
|
||||||
}
|
}
|
Loading…
Reference in New Issue