generated from tpl/obsidian-sample-plugin
Reorganize ui code into ui directory
This commit is contained in:
parent
976fe482b4
commit
259b939bbb
23
src/main.ts
23
src/main.ts
|
@ -5,9 +5,13 @@ import {
|
||||||
DEFAULT_SETTINGS,
|
DEFAULT_SETTINGS,
|
||||||
} from "./settings/settings";
|
} from "./settings/settings";
|
||||||
import { getBookByLegacyId, type SearchResult } from "@data-sources/goodreads";
|
import { getBookByLegacyId, type SearchResult } from "@data-sources/goodreads";
|
||||||
import { Templater } from "./utils/templater";
|
import { Templater } from "@utils/templater";
|
||||||
import { GoodreadsSearchModal } from "@views/goodreads-search-modal";
|
import {
|
||||||
import { GoodreadsSearchSuggestModal } from "@views/goodreads-search-suggest-modal";
|
GoodreadsSearchModal,
|
||||||
|
GoodreadsSearchSuggestModal,
|
||||||
|
ReadingProgressModal,
|
||||||
|
RatingModal,
|
||||||
|
} from "@ui/modals";
|
||||||
import {
|
import {
|
||||||
CONTENT_TYPE_EXTENSIONS,
|
CONTENT_TYPE_EXTENSIONS,
|
||||||
IN_PROGRESS_STATE,
|
IN_PROGRESS_STATE,
|
||||||
|
@ -15,10 +19,7 @@ import {
|
||||||
TO_BE_READ_STATE,
|
TO_BE_READ_STATE,
|
||||||
} from "./const";
|
} from "./const";
|
||||||
import { ReadingLog, Storage } from "@utils/storage";
|
import { ReadingLog, Storage } from "@utils/storage";
|
||||||
import { ReadingProgressModal } from "@views/reading-progress-modal";
|
import { registerReadingLogCodeBlockProcessor } from "@ui/code-blocks";
|
||||||
import { RatingModal } from "@views/rating-modal";
|
|
||||||
import { renderCodeBlockProcessor } from "@utils/svelte";
|
|
||||||
import ReadingLogViewer from "@components/ReadingLogViewer.svelte";
|
|
||||||
|
|
||||||
export default class BookTrackerPlugin extends Plugin {
|
export default class BookTrackerPlugin extends Plugin {
|
||||||
settings: BookTrackerPluginSettings;
|
settings: BookTrackerPluginSettings;
|
||||||
|
@ -65,13 +66,7 @@ export default class BookTrackerPlugin extends Plugin {
|
||||||
|
|
||||||
this.addSettingTab(new BookTrackerSettingTab(this.app, this));
|
this.addSettingTab(new BookTrackerSettingTab(this.app, this));
|
||||||
|
|
||||||
this.registerMarkdownCodeBlockProcessor(
|
registerReadingLogCodeBlockProcessor(this);
|
||||||
"readinglog",
|
|
||||||
renderCodeBlockProcessor(ReadingLogViewer, {
|
|
||||||
app: this.app,
|
|
||||||
readingLog: this.readingLog,
|
|
||||||
})
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onunload() {}
|
onunload() {}
|
||||||
|
|
|
@ -0,0 +1,29 @@
|
||||||
|
import { registerCodeBlockRenderer } from ".";
|
||||||
|
import { SvelteCodeBlockRenderer } from "./SvelteCodeBlockRenderer";
|
||||||
|
import ReadingLogCodeBlockView from "./ReadingLogCodeBlockView.svelte";
|
||||||
|
import type BookTrackerPlugin from "@src/main";
|
||||||
|
|
||||||
|
export function registerReadingLogCodeBlockProcessor(
|
||||||
|
plugin: BookTrackerPlugin
|
||||||
|
): void {
|
||||||
|
registerCodeBlockRenderer(
|
||||||
|
plugin,
|
||||||
|
"readinglog",
|
||||||
|
(_source, el) => new ReadingLogCodeBlockRenderer(el, plugin)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export class ReadingLogCodeBlockRenderer extends SvelteCodeBlockRenderer<
|
||||||
|
typeof ReadingLogCodeBlockView
|
||||||
|
> {
|
||||||
|
constructor(contentEl: HTMLElement, plugin: BookTrackerPlugin) {
|
||||||
|
super(contentEl, ReadingLogCodeBlockView, {
|
||||||
|
props: {
|
||||||
|
app: plugin.app,
|
||||||
|
readingLog: plugin.readingLog,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
onunload() {}
|
||||||
|
}
|
|
@ -3,8 +3,7 @@
|
||||||
import type { ReadingLogEntry } from "@src/types";
|
import type { ReadingLogEntry } from "@src/types";
|
||||||
import type { App } from "obsidian";
|
import type { App } from "obsidian";
|
||||||
import { Edit, Trash, Plus } from "lucide-svelte";
|
import { Edit, Trash, Plus } from "lucide-svelte";
|
||||||
import { ReadingLogEntryEditModal } from "@views/reading-log-entry-edit-modal";
|
import { ReadingLogEntryEditModal } from "@ui/modals";
|
||||||
import { ReadingLogNewEntryModal } from "@views/reading-log-new-entry-modal";
|
|
||||||
|
|
||||||
const ALL_TIME = "ALL_TIME";
|
const ALL_TIME = "ALL_TIME";
|
||||||
|
|
||||||
|
@ -70,23 +69,24 @@
|
||||||
);
|
);
|
||||||
|
|
||||||
function createEntry() {
|
function createEntry() {
|
||||||
const modal = new ReadingLogNewEntryModal(app);
|
const modal = new ReadingLogEntryEditModal(app, async (entry) => {
|
||||||
modal.once("submit", async (event) => {
|
|
||||||
modal.close();
|
modal.close();
|
||||||
await readingLog.addRawEntry(event.entry);
|
await readingLog.addRawEntry(entry);
|
||||||
reload();
|
reload();
|
||||||
});
|
});
|
||||||
modal.open();
|
modal.open();
|
||||||
}
|
}
|
||||||
|
|
||||||
function editEntry(i: number, entry: ReadingLogEntry) {
|
function editEntry(i: number, entry: ReadingLogEntry) {
|
||||||
const modal = new ReadingLogEntryEditModal(app, entry);
|
const modal = new ReadingLogEntryEditModal(
|
||||||
modal.once("submit", async (event) => {
|
app,
|
||||||
console.log(i, event);
|
async (entry) => {
|
||||||
modal.close();
|
modal.close();
|
||||||
await readingLog.updateEntry(i, event.entry);
|
await readingLog.updateEntry(i, entry);
|
||||||
reload();
|
reload();
|
||||||
});
|
},
|
||||||
|
entry,
|
||||||
|
);
|
||||||
modal.open();
|
modal.open();
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,33 @@
|
||||||
|
import { mount, unmount, type Component, type MountOptions } from "svelte";
|
||||||
|
import { MarkdownRenderChild } from "obsidian";
|
||||||
|
|
||||||
|
export class SvelteCodeBlockRenderer<
|
||||||
|
TComponent extends Component<TProps, TExports, TBindings>,
|
||||||
|
TProps extends Record<string, any> = {},
|
||||||
|
TExports extends Record<string, any> = {},
|
||||||
|
TBindings extends keyof TProps | "" = string
|
||||||
|
> extends MarkdownRenderChild {
|
||||||
|
protected component: TExports | undefined;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private readonly contentEl: HTMLElement,
|
||||||
|
private readonly componentCtor: TComponent,
|
||||||
|
private readonly mountOpts: Omit<MountOptions<TProps>, "target">
|
||||||
|
) {
|
||||||
|
super(contentEl);
|
||||||
|
}
|
||||||
|
|
||||||
|
onload(): void {
|
||||||
|
this.component = mount(this.componentCtor, {
|
||||||
|
...this.mountOpts,
|
||||||
|
target: this.contentEl,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
onunload(): void {
|
||||||
|
if (this.component) {
|
||||||
|
unmount(this.component);
|
||||||
|
this.component = undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,46 @@
|
||||||
|
import type { Plugin } from "obsidian";
|
||||||
|
import { mount, unmount, type Component, type MountOptions } from "svelte";
|
||||||
|
import { MarkdownRenderChild } from "obsidian";
|
||||||
|
|
||||||
|
export function registerCodeBlockRenderer(
|
||||||
|
plugin: Plugin,
|
||||||
|
name: string,
|
||||||
|
renderer: (source: string, el: HTMLElement) => MarkdownRenderChild
|
||||||
|
): void {
|
||||||
|
plugin.registerMarkdownCodeBlockProcessor(name, (source, el, ctx) => {
|
||||||
|
ctx.addChild(renderer(source, el));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export class SvelteCodeBlockRenderer<
|
||||||
|
TComponent extends Component<TProps, TExports, TBindings>,
|
||||||
|
TProps extends Record<string, any> = {},
|
||||||
|
TExports extends Record<string, any> = {},
|
||||||
|
TBindings extends keyof TProps | "" = string
|
||||||
|
> extends MarkdownRenderChild {
|
||||||
|
protected component: TExports | undefined;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private readonly contentEl: HTMLElement,
|
||||||
|
private readonly componentCtor: TComponent,
|
||||||
|
private readonly mountOpts: Omit<MountOptions<TProps>, "target">
|
||||||
|
) {
|
||||||
|
super(contentEl);
|
||||||
|
}
|
||||||
|
|
||||||
|
onload(): void {
|
||||||
|
this.component = mount(this.componentCtor, {
|
||||||
|
...this.mountOpts,
|
||||||
|
target: this.contentEl,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
onunload(): void {
|
||||||
|
if (this.component) {
|
||||||
|
unmount(this.component);
|
||||||
|
this.component = undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export { registerReadingLogCodeBlockProcessor } from "./ReadingLogCodeBlock";
|
|
@ -0,0 +1,31 @@
|
||||||
|
import GoodreadsSearchModalView from "./GoodreadsSearchModalView.svelte";
|
||||||
|
import { type SearchResult } from "@data-sources/goodreads";
|
||||||
|
import { App } from "obsidian";
|
||||||
|
import { SvelteModal } from "./SvelteModal";
|
||||||
|
|
||||||
|
export class GoodreadsSearchModal extends SvelteModal<
|
||||||
|
typeof GoodreadsSearchModalView
|
||||||
|
> {
|
||||||
|
constructor(
|
||||||
|
app: App,
|
||||||
|
onSearch: (error: any, results: SearchResult[]) => void = () => {}
|
||||||
|
) {
|
||||||
|
super(app, GoodreadsSearchModalView, { props: { onSearch } });
|
||||||
|
}
|
||||||
|
|
||||||
|
static createAndOpen(app: App): Promise<SearchResult[]> {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const modal = new GoodreadsSearchModal(app, (error, results) => {
|
||||||
|
modal.close();
|
||||||
|
|
||||||
|
if (error) {
|
||||||
|
reject(error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
resolve(results);
|
||||||
|
});
|
||||||
|
modal.open();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,11 +2,10 @@
|
||||||
import { searchBooks, type SearchResult } from "@data-sources/goodreads";
|
import { searchBooks, type SearchResult } from "@data-sources/goodreads";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
onSearch: (query: string, results: SearchResult[]) => void;
|
onSearch: (error: any, results?: SearchResult[]) => void;
|
||||||
onError: (error: Error) => void;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let { onSearch, onError }: Props = $props();
|
let { onSearch }: Props = $props();
|
||||||
|
|
||||||
let query = $state("");
|
let query = $state("");
|
||||||
|
|
||||||
|
@ -16,12 +15,12 @@
|
||||||
try {
|
try {
|
||||||
const results = await searchBooks(query);
|
const results = await searchBooks(query);
|
||||||
if (results.length === 0) {
|
if (results.length === 0) {
|
||||||
onError(new Error("No results found."));
|
onSearch(new Error("No results found."));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
onSearch(query, results);
|
onSearch(null, results);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
onError(error as Error);
|
onSearch(error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
import GoodreadsSearchSuggestion from "@components/GoodreadsSearchSuggestion.svelte";
|
import GoodreadsSearchSuggestion from "./GoodreadsSearchSuggestion.svelte";
|
||||||
import { type SearchResult } from "@data-sources/goodreads";
|
import { type SearchResult } from "@data-sources/goodreads";
|
||||||
import { App, Notice, SuggestModal } from "obsidian";
|
import { App, Notice, SuggestModal } from "obsidian";
|
||||||
import { mount } from "svelte";
|
import { mount } from "svelte";
|
||||||
|
@ -12,7 +12,7 @@ export class GoodreadsSearchSuggestModal extends SuggestModal<SearchResult> {
|
||||||
super(app);
|
super(app);
|
||||||
}
|
}
|
||||||
|
|
||||||
getSuggestions(query: string): SearchResult[] | Promise<SearchResult[]> {
|
getSuggestions(_query: string): SearchResult[] | Promise<SearchResult[]> {
|
||||||
return this.results;
|
return this.results;
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,19 @@
|
||||||
|
import RatingModalView from "./RatingModalView.svelte";
|
||||||
|
import { App } from "obsidian";
|
||||||
|
import { SvelteModal } from "./SvelteModal";
|
||||||
|
|
||||||
|
export class RatingModal extends SvelteModal<typeof RatingModalView> {
|
||||||
|
constructor(app: App, onSubmit: (rating: number) => void = () => {}) {
|
||||||
|
super(app, RatingModalView, { props: { onSubmit } });
|
||||||
|
}
|
||||||
|
|
||||||
|
static createAndOpen(app: App): Promise<number> {
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
const modal = new RatingModal(app, (rating) => {
|
||||||
|
modal.close();
|
||||||
|
resolve(rating);
|
||||||
|
});
|
||||||
|
modal.open();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,5 +1,5 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import RatingInput from "./RatingInput.svelte";
|
import RatingInput from "@ui/components/RatingInput.svelte";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
onSubmit: (value: number) => void;
|
onSubmit: (value: number) => void;
|
|
@ -0,0 +1,18 @@
|
||||||
|
import ReadingLogEntryEditModalView from "./ReadingLogEntryEditModalView.svelte";
|
||||||
|
import type { ReadingLogEntry } from "@src/types";
|
||||||
|
import { App } from "obsidian";
|
||||||
|
import { SvelteModal } from "./SvelteModal";
|
||||||
|
|
||||||
|
export class ReadingLogEntryEditModal extends SvelteModal<
|
||||||
|
typeof ReadingLogEntryEditModalView
|
||||||
|
> {
|
||||||
|
constructor(
|
||||||
|
app: App,
|
||||||
|
onSubmit?: (entry: ReadingLogEntry) => void,
|
||||||
|
entry?: ReadingLogEntry
|
||||||
|
) {
|
||||||
|
super(app, ReadingLogEntryEditModalView, {
|
||||||
|
props: { app, entry, onSubmit },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,31 @@
|
||||||
|
import ReadingProgressModalView from "./ReadingProgressModalView.svelte";
|
||||||
|
import { App } from "obsidian";
|
||||||
|
import { SvelteModal } from "./SvelteModal";
|
||||||
|
|
||||||
|
export class ReadingProgressModal extends SvelteModal<
|
||||||
|
typeof ReadingProgressModalView
|
||||||
|
> {
|
||||||
|
constructor(
|
||||||
|
app: App,
|
||||||
|
pageLength: number,
|
||||||
|
onSubmit: (pageNumber: number) => void = () => {}
|
||||||
|
) {
|
||||||
|
super(app, ReadingProgressModalView, {
|
||||||
|
props: { pageLength, onSubmit },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
static createAndOpen(app: App, pageLength: number): Promise<number> {
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
const modal = new ReadingProgressModal(
|
||||||
|
app,
|
||||||
|
pageLength,
|
||||||
|
(pageNumber: number) => {
|
||||||
|
modal.close();
|
||||||
|
resolve(pageNumber);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
modal.open();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,5 @@
|
||||||
|
export { GoodreadsSearchModal } from "./GoodreadsSearchModal";
|
||||||
|
export { GoodreadsSearchSuggestModal } from "./GoodreadsSearchSuggestModal";
|
||||||
|
export { RatingModal } from "./RatingModal";
|
||||||
|
export { ReadingLogEntryEditModal } from "./ReadingLogEntryEditModal";
|
||||||
|
export { ReadingProgressModal } from "./ReadingProgressModal";
|
|
@ -1,59 +0,0 @@
|
||||||
export abstract class Event {}
|
|
||||||
|
|
||||||
export type EventHandler<T> = (event: T) => void;
|
|
||||||
|
|
||||||
export type EventHandlerMap<TEventMap, T extends keyof TEventMap> = Record<
|
|
||||||
T,
|
|
||||||
EventHandler<TEventMap[T]>[]
|
|
||||||
>;
|
|
||||||
|
|
||||||
type Constructor = new (...args: any[]) => {};
|
|
||||||
|
|
||||||
export function EventEmitter<TEventMap, TBase extends Constructor>(
|
|
||||||
Base: TBase
|
|
||||||
) {
|
|
||||||
return class extends Base {
|
|
||||||
private readonly listeners: EventHandlerMap<
|
|
||||||
TEventMap,
|
|
||||||
keyof TEventMap
|
|
||||||
> = {} as EventHandlerMap<TEventMap, keyof TEventMap>;
|
|
||||||
|
|
||||||
public on<T extends keyof TEventMap>(
|
|
||||||
type: T,
|
|
||||||
handler: EventHandler<TEventMap[T]>
|
|
||||||
) {
|
|
||||||
if (!this.listeners[type]) {
|
|
||||||
this.listeners[type] = [];
|
|
||||||
}
|
|
||||||
this.listeners[type].push(handler);
|
|
||||||
}
|
|
||||||
|
|
||||||
public off<T extends keyof TEventMap>(
|
|
||||||
type: T,
|
|
||||||
handler: EventHandler<TEventMap[T]>
|
|
||||||
) {
|
|
||||||
if (this.listeners[type]) {
|
|
||||||
this.listeners[type] = this.listeners[type].filter(
|
|
||||||
(h) => h !== handler
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public once<T extends keyof TEventMap>(
|
|
||||||
type: T,
|
|
||||||
handler: EventHandler<TEventMap[T]>
|
|
||||||
) {
|
|
||||||
const wrappedHandler = (event: TEventMap[T]) => {
|
|
||||||
handler(event);
|
|
||||||
this.off(type, wrappedHandler);
|
|
||||||
};
|
|
||||||
this.on(type, wrappedHandler);
|
|
||||||
}
|
|
||||||
|
|
||||||
public emit<T extends keyof TEventMap>(type: T, event: TEventMap[T]) {
|
|
||||||
if (this.listeners[type]) {
|
|
||||||
this.listeners[type].forEach((handler) => handler(event));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
|
@ -1,33 +0,0 @@
|
||||||
import type { MarkdownPostProcessorContext } from "obsidian";
|
|
||||||
import { mount, unmount, type Component, type ComponentProps } from "svelte";
|
|
||||||
import { MarkdownRenderChild } from "obsidian";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Renders a svelte component as a code block processor.
|
|
||||||
* @param component the svelte component to render.
|
|
||||||
* @param props properties forwarded to the component.
|
|
||||||
* @param stateProvider an optional provider that handles state & state updates of the code block processor.
|
|
||||||
*/
|
|
||||||
export function renderCodeBlockProcessor<C extends Component>(
|
|
||||||
component: C,
|
|
||||||
props: ComponentProps<C>
|
|
||||||
) {
|
|
||||||
return (
|
|
||||||
source: string,
|
|
||||||
containerEl: HTMLElement,
|
|
||||||
ctx: MarkdownPostProcessorContext
|
|
||||||
) => {
|
|
||||||
const svelteComponent = mount(component, {
|
|
||||||
target: containerEl,
|
|
||||||
props,
|
|
||||||
});
|
|
||||||
|
|
||||||
class UnloadSvelteComponent extends MarkdownRenderChild {
|
|
||||||
onunload() {
|
|
||||||
unmount(svelteComponent);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx.addChild(new UnloadSvelteComponent(containerEl));
|
|
||||||
};
|
|
||||||
}
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { App, TFile } from "obsidian";
|
import { App } from "obsidian";
|
||||||
import * as Handlebars from "handlebars";
|
import * as Handlebars from "handlebars";
|
||||||
|
|
||||||
Handlebars.registerHelper("formatDate", (date: Date, format: string) => {
|
Handlebars.registerHelper("formatDate", (date: Date, format: string) => {
|
||||||
|
|
|
@ -1,58 +0,0 @@
|
||||||
import GoodreadsSearch from "@components/GoodreadsSearch.svelte";
|
|
||||||
import { type SearchResult } from "@data-sources/goodreads";
|
|
||||||
import { Event, EventEmitter } from "@utils/event";
|
|
||||||
import { App } from "obsidian";
|
|
||||||
import { SvelteModal } from "./svelte-modal";
|
|
||||||
|
|
||||||
export class SearchEvent extends Event {
|
|
||||||
constructor(
|
|
||||||
public readonly query: string,
|
|
||||||
public readonly results: SearchResult[]
|
|
||||||
) {
|
|
||||||
super();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class ErrorEvent extends Event {
|
|
||||||
constructor(public readonly error: Error) {
|
|
||||||
super();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
interface GoodreadsSearchModalEventMap {
|
|
||||||
search: SearchEvent;
|
|
||||||
error: ErrorEvent;
|
|
||||||
}
|
|
||||||
|
|
||||||
export class GoodreadsSearchModal extends EventEmitter<
|
|
||||||
GoodreadsSearchModalEventMap,
|
|
||||||
typeof SvelteModal<typeof GoodreadsSearch>
|
|
||||||
>(SvelteModal) {
|
|
||||||
constructor(app: App) {
|
|
||||||
super(app, GoodreadsSearch, {
|
|
||||||
props: {
|
|
||||||
onError: (error: Error) => {
|
|
||||||
this.emit("error", new ErrorEvent(error));
|
|
||||||
},
|
|
||||||
onSearch: (query: string, results: SearchResult[]) => {
|
|
||||||
this.emit("search", new SearchEvent(query, results));
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
static createAndOpen(app: App): Promise<SearchResult[]> {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
const modal = new GoodreadsSearchModal(app);
|
|
||||||
modal.once("search", (event: SearchEvent) => {
|
|
||||||
modal.close();
|
|
||||||
resolve(event.results);
|
|
||||||
});
|
|
||||||
modal.once("error", (event: ErrorEvent) => {
|
|
||||||
modal.close();
|
|
||||||
reject(event.error);
|
|
||||||
});
|
|
||||||
modal.open();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,39 +0,0 @@
|
||||||
import Rating from "@components/Rating.svelte";
|
|
||||||
import { Event, EventEmitter } from "@utils/event";
|
|
||||||
import { App } from "obsidian";
|
|
||||||
import { SvelteModal } from "./svelte-modal";
|
|
||||||
|
|
||||||
class SubmitEvent extends Event {
|
|
||||||
constructor(public readonly rating: number) {
|
|
||||||
super();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
interface RatingModalEventMap {
|
|
||||||
submit: SubmitEvent;
|
|
||||||
}
|
|
||||||
|
|
||||||
export class RatingModal extends EventEmitter<
|
|
||||||
RatingModalEventMap,
|
|
||||||
typeof SvelteModal<typeof Rating>
|
|
||||||
>(SvelteModal) {
|
|
||||||
constructor(app: App) {
|
|
||||||
super(app, Rating, {
|
|
||||||
props: {
|
|
||||||
onSubmit: (rating: number) =>
|
|
||||||
this.emit("submit", new SubmitEvent(rating)),
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
static createAndOpen(app: App): Promise<number> {
|
|
||||||
return new Promise((resolve) => {
|
|
||||||
const modal = new RatingModal(app);
|
|
||||||
modal.once("submit", (event: SubmitEvent) => {
|
|
||||||
modal.close();
|
|
||||||
resolve(event.rating);
|
|
||||||
});
|
|
||||||
modal.open();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,31 +0,0 @@
|
||||||
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 ReadingLogEntryEditModalEventMap {
|
|
||||||
submit: SubmitEvent;
|
|
||||||
}
|
|
||||||
|
|
||||||
export class ReadingLogEntryEditModal extends EventEmitter<
|
|
||||||
ReadingLogEntryEditModalEventMap,
|
|
||||||
typeof SvelteModal<typeof ReadingLogEntryEditor>
|
|
||||||
>(SvelteModal) {
|
|
||||||
constructor(app: App, entry: ReadingLogEntry) {
|
|
||||||
super(app, ReadingLogEntryEditor, {
|
|
||||||
props: {
|
|
||||||
app,
|
|
||||||
entry,
|
|
||||||
onSubmit: (entry: ReadingLogEntry) =>
|
|
||||||
this.emit("submit", new SubmitEvent(entry)),
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,30 +0,0 @@
|
||||||
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<typeof ReadingLogEntryEditor>
|
|
||||||
>(SvelteModal) {
|
|
||||||
constructor(app: App) {
|
|
||||||
super(app, ReadingLogEntryEditor, {
|
|
||||||
props: {
|
|
||||||
app,
|
|
||||||
onSubmit: (entry: ReadingLogEntry) =>
|
|
||||||
this.emit("submit", new SubmitEvent(entry)),
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,41 +0,0 @@
|
||||||
import ReadingProgress from "@components/ReadingProgress.svelte";
|
|
||||||
import { Event, EventEmitter } from "@utils/event";
|
|
||||||
import { App } from "obsidian";
|
|
||||||
import { SvelteModal } from "./svelte-modal";
|
|
||||||
|
|
||||||
export class SubmitEvent extends Event {
|
|
||||||
constructor(public readonly pageNumber: number) {
|
|
||||||
super();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
interface ReadingProgressModalEventMap {
|
|
||||||
submit: SubmitEvent;
|
|
||||||
}
|
|
||||||
|
|
||||||
export class ReadingProgressModal extends EventEmitter<
|
|
||||||
ReadingProgressModalEventMap,
|
|
||||||
typeof SvelteModal<typeof ReadingProgress>
|
|
||||||
>(SvelteModal) {
|
|
||||||
constructor(app: App, pageLength: number) {
|
|
||||||
super(app, ReadingProgress, {
|
|
||||||
props: {
|
|
||||||
pageLength,
|
|
||||||
onSubmit: (pageNumber: number) => {
|
|
||||||
this.emit("submit", new SubmitEvent(pageNumber));
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
static createAndOpen(app: App, pageLength: number): Promise<number> {
|
|
||||||
return new Promise((resolve) => {
|
|
||||||
const modal = new ReadingProgressModal(app, pageLength);
|
|
||||||
modal.once("submit", (event: SubmitEvent) => {
|
|
||||||
modal.close();
|
|
||||||
resolve(event.pageNumber);
|
|
||||||
});
|
|
||||||
modal.open();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -20,9 +20,9 @@
|
||||||
"ES7"
|
"ES7"
|
||||||
],
|
],
|
||||||
"paths": {
|
"paths": {
|
||||||
"@components/*": ["src/components/*"],
|
|
||||||
"@data-sources/*": ["src/data-sources/*"],
|
"@data-sources/*": ["src/data-sources/*"],
|
||||||
"@settings/*": ["src/settings/*"],
|
"@settings/*": ["src/settings/*"],
|
||||||
|
"@ui/*": ["src/ui/*"],
|
||||||
"@utils/*": ["src/utils/*"],
|
"@utils/*": ["src/utils/*"],
|
||||||
"@views/*": ["src/views/*"],
|
"@views/*": ["src/views/*"],
|
||||||
"@src/*": ["src/*"]
|
"@src/*": ["src/*"]
|
||||||
|
|
Loading…
Reference in New Issue