generated from tpl/obsidian-sample-plugin
142 lines
3.2 KiB
Svelte
142 lines
3.2 KiB
Svelte
<script lang="ts">
|
|
import type BookTrackerPlugin from "@src/main";
|
|
import type { ReadingLogEntry } from "@utils/ReadingLog";
|
|
import FileSuggest from "@ui/components/suggesters/FileSuggest.svelte";
|
|
import { v4 as uuidv4 } from "uuid";
|
|
|
|
const INPUT_DATETIME_FORMAT = "YYYY-MM-DDTHH:mm";
|
|
|
|
interface Props {
|
|
plugin: BookTrackerPlugin;
|
|
entry?: ReadingLogEntry;
|
|
onSubmit?: (entry: ReadingLogEntry) => void;
|
|
}
|
|
|
|
let { plugin, entry, onSubmit }: Props = $props();
|
|
|
|
let editMode = $derived(entry !== undefined);
|
|
let book = $state(entry?.book ?? "");
|
|
let pagesRead = $state(entry?.pagesRead ?? 0);
|
|
let pagesReadTotal = $state(entry?.pagesReadTotal ?? 0);
|
|
let pagesRemaining = $state(entry?.pagesRemaining ?? 0);
|
|
let createdAt = $state(
|
|
entry?.createdAt?.format(INPUT_DATETIME_FORMAT) ??
|
|
// @ts-expect-error Moment is provided by Obsidian
|
|
moment().format(INPUT_DATETIME_FORMAT),
|
|
);
|
|
|
|
// Source: https://github.com/sveltejs/svelte/discussions/14220#discussioncomment-11188219
|
|
function watch<T>(
|
|
getter: () => T,
|
|
effectCallback: (t: T | undefined) => void,
|
|
) {
|
|
let previous: T | undefined = undefined;
|
|
|
|
$effect(() => {
|
|
const current = getter(); // add $state.snapshot for deep reactivity
|
|
const cleanup = effectCallback(previous);
|
|
previous = current;
|
|
|
|
return cleanup;
|
|
});
|
|
}
|
|
|
|
watch(
|
|
() => pagesRead,
|
|
(prev) => {
|
|
if (prev !== pagesRead && prev !== undefined) {
|
|
const diff = pagesRead - prev;
|
|
pagesReadTotal = pagesReadTotal + diff;
|
|
pagesRemaining = pagesRemaining - diff;
|
|
}
|
|
},
|
|
);
|
|
|
|
function onsubmit(ev: SubmitEvent) {
|
|
ev.preventDefault();
|
|
onSubmit?.({
|
|
id: entry?.id ?? uuidv4(),
|
|
book,
|
|
pagesRead,
|
|
pagesReadTotal,
|
|
pagesRemaining,
|
|
// @ts-expect-error Moment is provided by Obsidian
|
|
createdAt: moment(createdAt),
|
|
});
|
|
}
|
|
</script>
|
|
|
|
<div class="obt-reading-log-entry-editor">
|
|
<h2>{editMode ? "Edit" : "Create"} Reading Log Entry</h2>
|
|
<form {onsubmit}>
|
|
<div class="fields">
|
|
<label for="book">Book</label>
|
|
<FileSuggest
|
|
id="book"
|
|
app={plugin.app}
|
|
asString
|
|
property="basename"
|
|
inFolder={plugin.settings.bookFolder}
|
|
bind:value={book}
|
|
/>
|
|
<label for="pagesRead">Pages Read</label>
|
|
<input
|
|
type="number"
|
|
name="pagesRead"
|
|
id="pagesRead"
|
|
bind:value={pagesRead}
|
|
/>
|
|
<label for="pagesReadTotal">Pages Read Total</label>
|
|
<input
|
|
type="number"
|
|
name="pagesReadTotal"
|
|
id="pagesReadTotal"
|
|
bind:value={pagesReadTotal}
|
|
/>
|
|
<label for="pagesRemaining">Pages Remaining</label>
|
|
<input
|
|
type="number"
|
|
name="pagesRemaining"
|
|
id="pagesRemaining"
|
|
bind:value={pagesRemaining}
|
|
/>
|
|
<label for="createdAt">Created At</label>
|
|
<input
|
|
type="datetime-local"
|
|
name="createdAt"
|
|
id="createdAt"
|
|
bind:value={createdAt}
|
|
/>
|
|
</div>
|
|
<button type="submit">Submit</button>
|
|
</form>
|
|
</div>
|
|
|
|
<style lang="scss">
|
|
.obt-reading-log-entry-editor {
|
|
margin-bottom: var(--size-4-4);
|
|
|
|
h2 {
|
|
margin-bottom: var(--size-4-6);
|
|
}
|
|
|
|
form {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: var(--size-4-4);
|
|
|
|
.fields {
|
|
display: grid;
|
|
grid-template-columns: max-content 1fr;
|
|
gap: var(--size-4-4);
|
|
align-items: center;
|
|
|
|
input:disabled {
|
|
color: var(--text-muted);
|
|
cursor: not-allowed;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
</style>
|