diff --git a/src/@types/settings.d.ts b/src/@types/settings.d.ts index 3b579e4..456cefb 100644 --- a/src/@types/settings.d.ts +++ b/src/@types/settings.d.ts @@ -10,6 +10,7 @@ export interface SimpleFlashcardsSettings { defaultDeckPath: string; // Default path for quick command trackViews: boolean; // Enable view tracking selectionMode: "random" | "least-recent"; + calloutType: string; // Callout type for embedded cards (e.g., "readaloud") } export interface SimpleFlashcardsData { diff --git a/src/@types/window-type.d.ts b/src/@types/window-type.d.ts new file mode 100644 index 0000000..fba9d16 --- /dev/null +++ b/src/@types/window-type.d.ts @@ -0,0 +1,9 @@ +import type { SimpleFlashcardsApi } from "../flashcards-Api"; + +declare global { + interface Window { + simpleFlashcards?: { + api?: SimpleFlashcardsApi; + }; + } +} diff --git a/src/flashcards-Api.ts b/src/flashcards-Api.ts new file mode 100644 index 0000000..ab4907e --- /dev/null +++ b/src/flashcards-Api.ts @@ -0,0 +1,17 @@ +import type SimpleFlashcardsPlugin from "./flashcards-Plugin"; + +export class SimpleFlashcardsApi { + plugin: SimpleFlashcardsPlugin; + + constructor(plugin: SimpleFlashcardsPlugin) { + this.plugin = plugin; + } + + /** + * Get a random card embed as formatted text + * @returns The card embed text, or null if no cards available + */ + embedCard(): string | null { + return this.plugin.getCardEmbedText(); + } +} diff --git a/src/flashcards-Constants.ts b/src/flashcards-Constants.ts index 81edd67..0106dda 100644 --- a/src/flashcards-Constants.ts +++ b/src/flashcards-Constants.ts @@ -5,4 +5,5 @@ export const DEFAULT_SETTINGS: SimpleFlashcardsSettings = { defaultDeckPath: "", trackViews: true, selectionMode: "least-recent", + calloutType: "tip", }; diff --git a/src/flashcards-Plugin.ts b/src/flashcards-Plugin.ts index 74bcfe9..a4c1766 100644 --- a/src/flashcards-Plugin.ts +++ b/src/flashcards-Plugin.ts @@ -1,9 +1,10 @@ -import { Notice, Plugin, TFile, TFolder } from "obsidian"; +import { type Editor, Notice, Plugin, TFile, TFolder } from "obsidian"; import type { Card, SimpleFlashcardsData, SimpleFlashcardsSettings, } from "./@types/settings"; +import { SimpleFlashcardsApi } from "./flashcards-Api"; import { CardParser } from "./flashcards-CardParser"; import { DEFAULT_SETTINGS } from "./flashcards-Constants"; import { FlashcardModal } from "./flashcards-Modal"; @@ -14,6 +15,7 @@ export default class SimpleFlashcardsPlugin extends Plugin { data!: SimpleFlashcardsData; cachedCards: Card[] = []; cardParser!: CardParser; + api!: SimpleFlashcardsApi; async onload() { console.log("Loading Simple Flashcards plugin"); @@ -23,33 +25,54 @@ export default class SimpleFlashcardsPlugin extends Plugin { this.addSettingTab(new SimpleFlashcardsSettingsTab(this.app, this)); - // Command: Show Random Activity Card - this.addCommand({ - id: "show-random-card", - name: "Show Random Activity Card", - callback: () => { - this.showRandomCard(); - }, - }); - - // Command: Refresh Activity Cards - this.addCommand({ - id: "refresh-cards", - name: "Refresh Activity Cards", - callback: async () => { - await this.scanCards(); - new Notice("Activity cards refreshed"); - }, - }); - - // Defer initial card scan to avoid blocking startup + // Defer initial card scan, API, and command registration to avoid blocking startup this.app.workspace.onLayoutReady(async () => { await this.scanCards(); + + // Initialize API + this.api = new SimpleFlashcardsApi(this); + if (!window.simpleFlashcards) { + window.simpleFlashcards = {}; + } + window.simpleFlashcards.api = this.api; + + // Command: Show Random Activity Card + this.addCommand({ + id: "show-random-card", + name: "Show Activity Card", + callback: () => { + this.showRandomCard(); + }, + }); + + // Command: Embed Random Card + this.addCommand({ + id: "embed-card", + name: "Embed Activity Card", + editorCallback: (editor) => { + this.insertCardEmbed(editor); + }, + }); + + // Command: Refresh Activity Cards + this.addCommand({ + id: "refresh-cards", + name: "Refresh Activity Cards", + callback: async () => { + await this.scanCards(); + new Notice("Activity cards refreshed"); + }, + }); }); } onunload() { console.log("Unloading Simple Flashcards plugin"); + + // Clear API reference + if (window.simpleFlashcards) { + window.simpleFlashcards.api = undefined; + } } async loadSettings() { @@ -129,12 +152,7 @@ export default class SimpleFlashcardsPlugin extends Plugin { }); } - async showRandomCard() { - // Lazy load cards if not yet scanned - if (this.cachedCards.length === 0) { - await this.scanCards(); - } - + showRandomCard() { const deckPath = this.settings.defaultDeckPath || undefined; const card = this.selectCard(deckPath); @@ -145,4 +163,41 @@ export default class SimpleFlashcardsPlugin extends Plugin { new FlashcardModal(this.app, this, card, deckPath).open(); } + + getCardEmbedText(): string | null { + const deckPath = this.settings.defaultDeckPath || undefined; + const card = this.selectCard(deckPath); + + if (!card) { + return null; + } + + // Create collapsible callout with card content + const contentLines = card.content + .split("\n") + .map((line) => `> ${line}`); + + const embedText = [ + `> [!${this.settings.calloutType}]+ ${card.heading}`, + ...contentLines, + ].join("\n"); + + // Record as viewed + if (this.settings.trackViews) { + this.recordView(card.key); + } + + return embedText; + } + + insertCardEmbed(editor: Editor) { + const embedText = this.getCardEmbedText(); + + if (!embedText) { + new Notice("No cards available. Check your settings."); + return; + } + + editor.replaceSelection(embedText); + } } diff --git a/src/flashcards-SettingsTab.ts b/src/flashcards-SettingsTab.ts index fcbaec3..746cb61 100644 --- a/src/flashcards-SettingsTab.ts +++ b/src/flashcards-SettingsTab.ts @@ -124,6 +124,20 @@ export class SimpleFlashcardsSettingsTab extends PluginSettingTab { }), ); + new Setting(containerEl) + .setName("Callout Type") + .setDesc( + "Callout type for embedded cards (e.g., note, tip, warning)", + ) + .addText((text) => + text + .setPlaceholder("readaloud") + .setValue(this.newSettings.calloutType) + .onChange((value) => { + this.newSettings.calloutType = value.trim(); + }), + ); + containerEl.createEl("h3", { text: "Usage" }); const usage = containerEl.createEl("div"); usage.createEl("p", { diff --git a/tsconfig.json b/tsconfig.json deleted file mode 100644 index fb0c4a1..0000000 --- a/tsconfig.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "compilerOptions": { - "baseUrl": ".", - "inlineSourceMap": true, - "inlineSources": true, - "module": "ESNext", - "target": "ES2020", - "allowJs": true, - "noImplicitAny": true, - "moduleResolution": "node", - "importHelpers": true, - "isolatedModules": true, - "strictNullChecks": true, - "lib": [ - "DOM", - "ES2020" - ] - }, - "include": [ - "**/*.ts" - ] -}