diff --git a/package.json b/package.json
index cc3bed0..3a7e3c4 100644
--- a/package.json
+++ b/package.json
@@ -30,6 +30,7 @@
"sass": "^1.89.2",
"svelte": "^5.34.8",
"svelte-check": "^4.2.2",
+ "svelte-popperjs": "^1.3.2",
"svelte-preprocess": "^6.0.3",
"tslib": "2.4.0",
"typescript": "5.0.4"
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 4e8decd..f9544d6 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -59,6 +59,9 @@ importers:
svelte-check:
specifier: ^4.2.2
version: 4.2.2(picomatch@4.0.2)(svelte@5.34.8)(typescript@5.0.4)
+ svelte-popperjs:
+ specifier: ^1.3.2
+ version: 1.3.2(@popperjs/core@2.11.8)(svelte@5.34.8)
svelte-preprocess:
specifier: ^6.0.3
version: 6.0.3(postcss@8.5.6)(sass@1.89.2)(svelte@5.34.8)(typescript@5.0.4)
@@ -1444,6 +1447,12 @@ packages:
svelte: ^4.0.0 || ^5.0.0-next.0
typescript: '>=5.0.0'
+ svelte-popperjs@1.3.2:
+ resolution: {integrity: sha512-fwrErlkvngL876WXRnL3OLlfk/n9YkZwwLxuKRpZOYCJLt1zrwhoKTXS+/sRgDveD/zd6GQ35hV89EOip+NBGA==}
+ peerDependencies:
+ '@popperjs/core': '>=2'
+ svelte: '>=3'
+
svelte-preprocess@6.0.3:
resolution: {integrity: sha512-PLG2k05qHdhmRG7zR/dyo5qKvakhm8IJ+hD2eFRQmMLHp7X3eJnjeupUtvuRpbNiF31RjVw45W+abDwHEmP5OA==}
engines: {node: '>= 18.0.0'}
@@ -3050,6 +3059,11 @@ snapshots:
transitivePeerDependencies:
- picomatch
+ svelte-popperjs@1.3.2(@popperjs/core@2.11.8)(svelte@5.34.8):
+ dependencies:
+ '@popperjs/core': 2.11.8
+ svelte: 5.34.8
+
svelte-preprocess@6.0.3(postcss@8.5.6)(sass@1.89.2)(svelte@5.34.8)(typescript@5.0.4):
dependencies:
svelte: 5.34.8
diff --git a/src/components/ReadingLogEntryEditor.svelte b/src/components/ReadingLogEntryEditor.svelte
index 922bf2d..e960b70 100644
--- a/src/components/ReadingLogEntryEditor.svelte
+++ b/src/components/ReadingLogEntryEditor.svelte
@@ -1,15 +1,21 @@
-
Edit Reading Log Entry
+
{editMode ? "Edit" : "Create"} Reading Log Entry
@@ -95,7 +123,13 @@
.fields {
display: grid;
grid-template-columns: max-content 1fr;
- gap: var(--size-4-2);
+ gap: var(--size-4-4);
+ align-items: center;
+
+ input:disabled {
+ color: var(--text-muted);
+ cursor: not-allowed;
+ }
}
}
}
diff --git a/src/components/ReadingLogViewer.svelte b/src/components/ReadingLogViewer.svelte
index 289efb0..e6a1ec1 100644
--- a/src/components/ReadingLogViewer.svelte
+++ b/src/components/ReadingLogViewer.svelte
@@ -2,8 +2,9 @@
import type { ReadingLog } from "@utils/storage";
import type { ReadingLogEntry } from "@src/types";
import type { App } from "obsidian";
- import { Edit, Trash } from "lucide-svelte";
+ import { Edit, Trash, Plus } from "lucide-svelte";
import { ReadingLogEntryEditModal } from "@views/reading-log-entry-edit-modal";
+ import { ReadingLogNewEntryModal } from "@views/reading-log-new-entry-modal";
const ALL_TIME = "ALL_TIME";
@@ -68,6 +69,16 @@
),
);
+ function createEntry() {
+ const modal = new ReadingLogNewEntryModal(app);
+ modal.once("submit", async (event) => {
+ modal.close();
+ await readingLog.addRawEntry(event.entry);
+ reload();
+ });
+ modal.open();
+ }
+
function editEntry(i: number, entry: ReadingLogEntry) {
const modal = new ReadingLogEntryEditModal(app, entry);
modal.once("submit", async (event) => {
@@ -86,28 +97,36 @@
-
-
-
+
+
+
+
+
+
@@ -155,6 +174,27 @@
@use "../styles/utils";
.obt-reading-log-viewer {
+ .controls {
+ display: grid;
+ grid-template-columns: 1fr 1fr;
+ align-items: center;
+
+ .right {
+ text-align: right;
+
+ button.create-entry {
+ display: inline-flex;
+ gap: var(--size-2-2);
+ align-items: center;
+
+ :global(svg) {
+ width: var(--icon-s);
+ height: var(--icon-s);
+ }
+ }
+ }
+ }
+
.year-filter:has(> option.all-time:checked) + .month-filter {
display: none;
}
diff --git a/src/settings/suggesters/book.ts b/src/settings/suggesters/book.ts
new file mode 100644
index 0000000..6e2d8c3
--- /dev/null
+++ b/src/settings/suggesters/book.ts
@@ -0,0 +1,34 @@
+// Credits go to Liam's Periodic Notes Plugin: https://github.com/liamcain/obsidian-periodic-notes
+
+import { TAbstractFile, TFile } from "obsidian";
+import { TextInputSuggest } from "./core";
+
+export class BookSuggest extends TextInputSuggest {
+ getSuggestions(inputStr: string): TFile[] {
+ const abstractFiles = this.app.vault.getAllLoadedFiles();
+ const files: TFile[] = [];
+ const lowerCaseInputStr = inputStr.toLowerCase();
+
+ abstractFiles.forEach((file: TAbstractFile) => {
+ if (
+ file instanceof TFile &&
+ file.extension === "md" &&
+ file.basename.toLowerCase().contains(lowerCaseInputStr)
+ ) {
+ files.push(file);
+ }
+ });
+
+ return files;
+ }
+
+ renderSuggestion(file: TFile, el: HTMLElement): void {
+ el.setText(file.basename);
+ }
+
+ selectSuggestion(file: TFile): void {
+ this.inputEl.value = file.basename;
+ this.inputEl.trigger("input");
+ this.close();
+ }
+}
diff --git a/src/utils/storage.ts b/src/utils/storage.ts
index 1a813e7..0908e50 100644
--- a/src/utils/storage.ts
+++ b/src/utils/storage.ts
@@ -93,7 +93,11 @@ export class ReadingLog {
createdAt: new Date(),
};
- this.entries.push(newEntry);
+ await this.addRawEntry(newEntry);
+ }
+
+ public async addRawEntry(entry: ReadingLogEntry) {
+ this.entries.push(entry);
await this.storeEntries();
}
diff --git a/src/views/reading-log-entry-edit-modal.ts b/src/views/reading-log-entry-edit-modal.ts
index 932b846..beb9533 100644
--- a/src/views/reading-log-entry-edit-modal.ts
+++ b/src/views/reading-log-entry-edit-modal.ts
@@ -21,6 +21,7 @@ export class ReadingLogEntryEditModal extends EventEmitter<
constructor(app: App, entry: ReadingLogEntry) {
super(app, ReadingLogEntryEditor, {
props: {
+ app,
entry,
onSubmit: (entry: ReadingLogEntry) =>
this.emit("submit", new SubmitEvent(entry)),
diff --git a/src/views/reading-log-new-entry-modal.ts b/src/views/reading-log-new-entry-modal.ts
new file mode 100644
index 0000000..2971fbd
--- /dev/null
+++ b/src/views/reading-log-new-entry-modal.ts
@@ -0,0 +1,30 @@
+import ReadingLogEntryEditor from "@components/ReadingLogEntryEditor.svelte";
+import type { ReadingLogEntry } from "@src/types";
+import { Event, EventEmitter } from "@utils/event";
+import { App } from "obsidian";
+import { SvelteModal } from "./svelte-modal";
+
+export class SubmitEvent extends Event {
+ constructor(public readonly entry: ReadingLogEntry) {
+ super();
+ }
+}
+
+interface ReadingLogNewEntryModalEventMap {
+ submit: SubmitEvent;
+}
+
+export class ReadingLogNewEntryModal extends EventEmitter<
+ ReadingLogNewEntryModalEventMap,
+ typeof SvelteModal
+>(SvelteModal) {
+ constructor(app: App) {
+ super(app, ReadingLogEntryEditor, {
+ props: {
+ app,
+ onSubmit: (entry: ReadingLogEntry) =>
+ this.emit("submit", new SubmitEvent(entry)),
+ },
+ });
+ }
+}