diff --git a/src/commands/CreateReadingLogBackupCommand.ts b/src/commands/CreateReadingLogBackupCommand.ts new file mode 100644 index 0000000..82776be --- /dev/null +++ b/src/commands/CreateReadingLogBackupCommand.ts @@ -0,0 +1,15 @@ +import type { ReadingLog } from "@utils/ReadingLog"; +import { Command } from "./Command"; + +export class BackupReadingLogCommand extends Command { + constructor(private readonly readingLog: ReadingLog) { + super("create-reading-log-backup", "Create Reading Log Backup"); + } + + async callback() { + // @ts-expect-error Moment is provided by Obsidian + const timestamp = moment().format("YYYY-MM-DD_HH-mm-ss"); + const backupFilename = `reading-log-backup_${timestamp}.json`; + await this.readingLog.save(backupFilename); + } +} diff --git a/src/commands/RestoreReadingLogBackupCommand.ts b/src/commands/RestoreReadingLogBackupCommand.ts new file mode 100644 index 0000000..b1332b1 --- /dev/null +++ b/src/commands/RestoreReadingLogBackupCommand.ts @@ -0,0 +1,41 @@ +import type { ReadingLog } from "@utils/ReadingLog"; +import { Command } from "./Command"; +import type { Storage } from "@utils/Storage"; +import { Notice, type App } from "obsidian"; +import { TextSuggestModal } from "@ui/modals/TextSuggestModal"; + +function basename(path: string) { + return path.split("/").pop()!; +} + +export class RestoreReadingLogBackupCommand extends Command { + constructor( + private readonly app: App, + private readonly storage: Storage, + private readonly readingLog: ReadingLog + ) { + super("restore-reading-log-backup", "Restore Reading Log Backup"); + } + + async callback() { + let items = await this.storage.listFiles(); + + items = items + .map((f) => basename(f)) + .filter( + (f) => + f.startsWith("reading-log-backup_") && f.endsWith(".json") + ); + + const backupPath = await TextSuggestModal.createAndOpen( + this.app, + items + ); + if (backupPath) { + await this.readingLog.load(backupPath); + await this.readingLog.save(); + } else { + new Notice("No backup file selected."); + } + } +} diff --git a/src/main.ts b/src/main.ts index 02c5086..9f5febb 100644 --- a/src/main.ts +++ b/src/main.ts @@ -15,6 +15,8 @@ import { LogReadingStartedCommand } from "@commands/LogReadingStartedCommand"; import { LogReadingProgressCommand } from "@commands/LogReadingProgressCommand"; import { LogReadingFinishedCommand } from "@commands/LogReadingFinishedCommand"; import { ResetReadingStatusCommand } from "@commands/ResetReadingStatusCommand"; +import { BackupReadingLogCommand } from "@commands/CreateReadingLogBackupCommand"; +import { RestoreReadingLogBackupCommand } from "@commands/RestoreReadingLogBackupCommand"; export default class BookTrackerPlugin extends Plugin { settings: BookTrackerPluginSettings; @@ -54,6 +56,14 @@ export default class BookTrackerPlugin extends Plugin { this.settings ) ); + this.addCommand(new BackupReadingLogCommand(this.readingLog)); + this.addCommand( + new RestoreReadingLogBackupCommand( + this.app, + this.storage, + this.readingLog + ) + ); this.addSettingTab(new BookTrackerSettingTab(this)); diff --git a/src/ui/components/suggesters/TextInputSuggest.svelte b/src/ui/components/suggesters/TextInputSuggest.svelte index 430d96f..236770b 100644 --- a/src/ui/components/suggesters/TextInputSuggest.svelte +++ b/src/ui/components/suggesters/TextInputSuggest.svelte @@ -122,61 +122,45 @@ await onChange?.(query); } - onMount(() => { - const scope = new Scope(); + function onkeydown(event: KeyboardEvent) { + if (!expanded) return; - const arrowUpHandler = scope.register( - [], - "ArrowUp", - (event: KeyboardEvent) => { - if (!event.isComposing) { - setSelectedItem(selectedIndex - 1, true); - return false; - } - }, - ); - - const arrowDownHandler = scope.register( - [], - "ArrowDown", - (event: KeyboardEvent) => { - if (!event.isComposing) { - setSelectedItem(selectedIndex + 1, true); - return false; - } - }, - ); - - const enterHandler = scope.register([], "Enter", (ev) => { - if (!ev.isComposing) { - selectItem(selectedIndex); - return false; - } - }); - - const escapeHandler = scope.register([], "Escape", (ev) => { - if (!ev.isComposing) { + switch (event.key) { + case "Esc": + case "Escape": + case "Cancel": expanded = false; - return false; - } - }); + break; + case "Accept": + case "Enter": + selectItem(selectedIndex); + break; + case "ArrowUp": + setSelectedItem(selectedIndex - 1, true); + break; + case "ArrowDown": + setSelectedItem(selectedIndex + 1, true); + break; + case "Tab": + setSelectedItem( + selectedIndex + (event.shiftKey ? -1 : 1), + false, + ); + break; + default: + return; + } - app.keymap.pushScope(scope); - - return () => { - scope.unregister(arrowUpHandler); - scope.unregister(arrowDownHandler); - scope.unregister(enterHandler); - scope.unregister(escapeHandler); - app.keymap.popScope(scope); - }; - }); + event.preventDefault(); + event.stopPropagation(); + }
(expanded = false)} + onfocusout={() => (expanded = false)} >
{#if expanded} -
-