♻️ rename to Deck Notes

This commit is contained in:
Erin Schnabel 2025-11-17 21:33:15 -05:00
parent 63c230a198
commit d46be3cce5
No known key found for this signature in database
16 changed files with 110 additions and 93 deletions

View file

@ -31,10 +31,10 @@ When working with this codebase:
**Core modules to understand:**
- `flashcards-Plugin.ts` - Main plugin, scanning, filtering
- `flashcards-CardParser.ts` - Parsing and tag extraction
- `flashcards-Modal.ts` - Display modal
- `flashcards-Api.ts` - External API
- `dn-Plugin.ts` - Main plugin, scanning, filtering
- `dn-CardParser.ts` - Parsing and tag extraction
- `dn-Modal.ts` - Display modal
- `dn-Api.ts` - External API
- `@types/settings.d.ts` - Interfaces
## Key Development Principles

View file

@ -1,6 +1,6 @@
# Contributing to Simple Flashcards
# Contributing to Deck Notes
This is an Obsidian plugin for simple flashcard creation and review using tag-based deck organization. See [README.md](README.md) for user-facing features and usage.
This is an Obsidian plugin for tag-based card decks. Define cards for activities, strategies, or any content you want to rotate through. See [README.md](README.md) for user-facing features and usage.
## Development Commands
@ -16,11 +16,11 @@ npm run format # Format code
### Core Files
- **`flashcards-Plugin.ts`** - Main plugin class, card scanning, deck filtering
- **`flashcards-CardParser.ts`** - Parses markdown files into cards, extracts tags
- **`flashcards-Modal.ts`** - Card display modal with deck switching
- **`flashcards-Api.ts`** - JavaScript API for external access
- **`flashcards-SettingsTab.ts`** - Settings UI
- **`dn-Plugin.ts`** - Main plugin class, card scanning, deck filtering
- **`dn-CardParser.ts`** - Parses markdown files into cards, extracts tags
- **`dn-Modal.ts`** - Card display modal with deck switching
- **`dn-Api.ts`** - JavaScript API for external access
- **`dn-SettingsTab.ts`** - Settings UI
- **`@types/settings.d.ts`** - TypeScript interfaces
### Key Concepts

View file

@ -1,6 +1,6 @@
# Simple Flashcards
# Deck Notes
A simple activity card plugin for Obsidian. Display random cards from your markdown files for meditations, prompts, exercises, or any repeatable activities.
Define card decks for activities, strategies, or any content you want to rotate through. Embed cards in your notes or browse them in a modal. Filter by tag hierarchies to narrow your selection.
## Features
@ -15,20 +15,22 @@ A simple activity card plugin for Obsidian. Display random cards from your markd
### Manual Installation
1. Download the latest release from the [Releases page](https://github.com/ebullient/obsidian-flashcards/releases)
2. Extract the files into your vault's plugins folder: `<vault>/.obsidian/plugins/simple-flashcards/`
2. Extract the files into your vault's plugins folder: `<vault>/.obsidian/plugins/deck-notes/`
3. Reload Obsidian
4. Enable the plugin in Settings → Community Plugins
### Development Installation
1. Clone this repository into your vault's plugins folder:
```bash
cd <vault>/.obsidian/plugins
git clone https://github.com/ebullient/obsidian-flashcards.git simple-flashcards
cd simple-flashcards
git clone https://github.com/ebullient/obsidian-flashcards.git deck-notes
cd deck-notes
```
2. Install dependencies and build:
```bash
npm install
npm run build
@ -95,42 +97,51 @@ Repeat 4 times.
## Configuration
Open Settings → Simple Flashcards to configure:
Open Settings → Deck Notes to configure:
### Card Paths
List of folders or files to scan for cards (one per line, relative to vault root). This defines which files are scanned, not which cards are displayed.
Example:
```
```txt
Activities/Exercises
Daily/Prompts
Resources/Meditations.md
```
### Default Deck Tag
The default tag used by "Show Random Activity Card" command (e.g., `activities` or `activities/morning`). Leave empty to select from all cards with any `#flashcards/*` tag.
### Track Views
Enable tracking of when cards were last viewed. Required for "Least Recently Viewed" selection mode.
### Selection Mode
- **Random** - Pure random selection
- **Least Recently Viewed** - Prioritizes cards you haven't seen recently
## Commands
### Show Card
Opens a modal displaying a card from your default deck (or all cards if no default is set).
**Modal Controls:**
- **Switch Deck** - Cycle through discovered deck tags (e.g., `activities`, `activities/morning`)
- **Next Card** - View another card (records the current card as viewed)
- **Done** - Close the modal
### Embed Card
Inserts a card as a collapsible callout at the cursor position.
### Refresh Cards
Rescans all configured paths to pick up new or modified cards.
## Usage Tips
@ -140,12 +151,14 @@ Rescans all configured paths to pick up new or modified cards.
Cards are organized into decks using hierarchical `#flashcards/*` tags. Tags support hierarchy, so selecting `activities` will show cards tagged with `activities`, `activities/morning`, `activities/creative`, etc.
**Tag inheritance:**
- Tags in frontmatter apply to all cards in the file
- Tags before each H2 heading apply only to that card
- Cards can have multiple tags for multiple deck membership
**Example structure:**
```
```txt
Activities/stretches.md → All cards get #flashcards/activities from frontmatter
Card 1: Also tagged #flashcards/activities/morning
Card 2: Also tagged #flashcards/activities/evening
@ -158,6 +171,7 @@ Journal/prompts.md → All cards get #flashcards/creative from frontmatter
### View Tracking
With "Track Views" enabled and "Least Recently Viewed" selection mode, the plugin ensures you see all cards before repeating. Perfect for:
- Daily meditation rotations
- Exercise variety
- Prompt cycling
@ -165,6 +179,7 @@ With "Track Views" enabled and "Least Recently Viewed" selection mode, the plugi
### Tags for Deck Organization
Use hierarchical `#flashcards/*` tags to organize cards:
- Add tags in frontmatter: `tags: [flashcards/activities]` (applies to all cards in file)
- Add inline tags before H2 headings: `#flashcards/activities/morning` (applies to single card)
- Lines starting with `#flashcards` are automatically stripped from card display
@ -172,20 +187,20 @@ Use hierarchical `#flashcards/*` tags to organize cards:
### API Access
The plugin exposes a JavaScript API at `window.simpleFlashcards.api`:
The plugin exposes a JavaScript API at `window.deckNotes.api`:
```javascript
// Get a random card embed
window.simpleFlashcards.api.embedCard('activities')
window.deckNotes.api.embedCard('activities')
// Get all discovered deck tags
window.simpleFlashcards.api.getTags()
window.deckNotes.api.getTags()
// Select cards by hash
window.simpleFlashcards.api.selectCardsByHash(['card-hash-1', 'card-hash-2'])
window.deckNotes.api.selectCardsByHash(['card-hash-1', 'card-hash-2'])
// Get random card from hash list
window.simpleFlashcards.api.selectCardByHash(['card-hash-1', 'card-hash-2'])
window.deckNotes.api.selectCardByHash(['card-hash-1', 'card-hash-2'])
```
## Development
@ -202,15 +217,15 @@ npm run format # Format code
### Project Structure
```
```txt
src/
├── @types/
│ └── settings.d.ts # TypeScript interfaces
├── flashcards-Plugin.ts # Main plugin class
├── flashcards-CardParser.ts # Parse files into cards
├── flashcards-Modal.ts # Card display modal
├── flashcards-SettingsTab.ts # Settings UI
├── flashcards-Constants.ts # Default settings
├── dn-Plugin.ts # Main plugin class
├── dn-CardParser.ts # Parse files into cards
├── dn-Modal.ts # Card display modal
├── dn-SettingsTab.ts # Settings UI
├── dn-Constants.ts # Default settings
└── main.ts # Entry point
```

10
manifest-beta.json Normal file
View file

@ -0,0 +1,10 @@
{
"id": "deck-notes",
"name": "Deck Notes",
"version": "0.1.0",
"minAppVersion": "1.9.0",
"description": "Define card decks for activities, strategies, or any content you want to rotate through. Embed cards in your notes or browse them in a modal. Filter by tag hierarchies to narrow your selection.",
"author": "ebullient",
"authorUrl": "https://github.com/ebullient",
"isDesktopOnly": false
}

View file

@ -1,9 +1,9 @@
{
"id": "simple-flashcards",
"name": "Simple Flashcards",
"id": "deck-notes",
"name": "Deck Notes",
"version": "0.1.0",
"minAppVersion": "1.9.0",
"description": "A simple flashcard plugin for Obsidian",
"description": "Define card decks for activities, strategies, or any content you want to rotate through. Embed cards in your notes or browse them in a modal. Filter by tag hierarchies to narrow your selection.",
"author": "ebullient",
"authorUrl": "https://github.com/ebullient",
"isDesktopOnly": false

16
package-lock.json generated
View file

@ -1,11 +1,11 @@
{
"name": "simple-flashcards",
"name": "deck-notes",
"version": "0.1.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "simple-flashcards",
"name": "deck-notes",
"version": "0.1.0",
"license": "MIT",
"devDependencies": {
@ -654,8 +654,7 @@
"resolved": "https://registry.npmjs.org/@marijn/find-cluster-break/-/find-cluster-break-1.0.2.tgz",
"integrity": "sha512-l0h88YhZFyKdXIFNfSWpyjStDjGHwZ/U7iobcK1cQQD8sejsONdQtTVU+1wVN1PBw40PiiHB1vA5S7VTfQiP9g==",
"dev": true,
"license": "MIT",
"peer": true
"license": "MIT"
},
"node_modules/@types/codemirror": {
"version": "5.60.8",
@ -743,8 +742,7 @@
"resolved": "https://registry.npmjs.org/crelt/-/crelt-1.0.6.tgz",
"integrity": "sha512-VQ2MBenTq1fWZUH9DJNGti7kKv6EeAuYr3cLwxUWhIu1baTaXh4Ib5W2CqHVqib4/MqbYGJqiL3Zb8GJZr3l4g==",
"dev": true,
"license": "MIT",
"peer": true
"license": "MIT"
},
"node_modules/esbuild": {
"version": "0.25.10",
@ -950,8 +948,7 @@
"resolved": "https://registry.npmjs.org/style-mod/-/style-mod-4.1.2.tgz",
"integrity": "sha512-wnD1HyVqpJUI2+eKZ+eo1UwghftP6yuFheBqqe+bWCotBjC2K1YnteJILRMs3SM4V/0dLEW1SC27MWP5y+mwmw==",
"dev": true,
"license": "MIT",
"peer": true
"license": "MIT"
},
"node_modules/tr46": {
"version": "0.0.3",
@ -1007,8 +1004,7 @@
"resolved": "https://registry.npmjs.org/w3c-keyname/-/w3c-keyname-2.2.8.tgz",
"integrity": "sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ==",
"dev": true,
"license": "MIT",
"peer": true
"license": "MIT"
},
"node_modules/webidl-conversions": {
"version": "3.0.1",

View file

@ -1,8 +1,8 @@
{
"name": "simple-flashcards",
"name": "deck-notes",
"version": "0.1.0",
"private": true,
"description": "Simple flashcard plugin for Obsidian (https://obsidian.md)",
"description": "Define card decks for activities, strategies, or any content you want to rotate through. Embed cards in your notes or browse them in a modal. Filter by tag hierarchies to narrow your selection.",
"main": "main.js",
"scripts": {
"dev": "node esbuild.config.mjs",

View file

@ -7,7 +7,7 @@ export interface Card {
tags: string[]; // Normalized deck tags (without #flashcards/ prefix)
}
export interface SimpleFlashcardsSettings {
export interface DeckNotesSettings {
cardPaths: string[]; // ["Journal/Coping", "Activities"]
defaultDeckTag: string; // Default tag for deck selection (e.g., "activities")
trackViews: boolean; // Enable view tracking
@ -15,6 +15,6 @@ export interface SimpleFlashcardsSettings {
calloutType: string; // Callout type for embedded cards (e.g., "readaloud")
}
export interface SimpleFlashcardsData {
export interface DeckNotesData {
cardViews: Record<string, number>; // "file.md#heading" → timestamp
}

View file

@ -1,9 +1,9 @@
import type { SimpleFlashcardsApi } from "../flashcards-Api";
import type { DeckNotesApi } from "../dn-Api";
declare global {
interface Window {
simpleFlashcards?: {
api?: SimpleFlashcardsApi;
deckNotes?: {
api?: DeckNotesApi;
};
}
}

View file

@ -1,10 +1,10 @@
import type { Card } from "./@types/settings";
import type SimpleFlashcardsPlugin from "./flashcards-Plugin";
import type DeckNotesPlugin from "./dn-Plugin";
export class SimpleFlashcardsApi {
plugin: SimpleFlashcardsPlugin;
export class DeckNotesApi {
plugin: DeckNotesPlugin;
constructor(plugin: SimpleFlashcardsPlugin) {
constructor(plugin: DeckNotesPlugin) {
this.plugin = plugin;
}

View file

@ -1,6 +1,6 @@
import type { SimpleFlashcardsSettings } from "./@types/settings";
import type { DeckNotesSettings } from "./@types/settings";
export const DEFAULT_SETTINGS: SimpleFlashcardsSettings = {
export const DEFAULT_SETTINGS: DeckNotesSettings = {
cardPaths: [],
defaultDeckTag: "",
trackViews: true,

View file

@ -1,15 +1,15 @@
import { type App, ButtonComponent, MarkdownRenderer, Modal } from "obsidian";
import type { Card } from "./@types/settings";
import type SimpleFlashcardsPlugin from "./flashcards-Plugin";
import type DeckNotesPlugin from "./dn-Plugin";
export class FlashcardModal extends Modal {
plugin: SimpleFlashcardsPlugin;
plugin: DeckNotesPlugin;
card: Card | null;
deckTag: string | undefined;
constructor(
app: App,
plugin: SimpleFlashcardsPlugin,
plugin: DeckNotesPlugin,
card: Card | null,
deckTag?: string,
) {

View file

@ -1,40 +1,36 @@
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";
import { SimpleFlashcardsSettingsTab } from "./flashcards-SettingsTab";
import type { Card, DeckNotesData, DeckNotesSettings } from "./@types/settings";
import { DeckNotesApi } from "./dn-Api";
import { CardParser } from "./dn-CardParser";
import { DEFAULT_SETTINGS } from "./dn-Constants";
import { FlashcardModal } from "./dn-Modal";
import { DeckNotesSettingsTab } from "./dn-SettingsTab";
export default class SimpleFlashcardsPlugin extends Plugin {
settings!: SimpleFlashcardsSettings;
data!: SimpleFlashcardsData;
export default class DeckNotesPlugin extends Plugin {
settings!: DeckNotesSettings;
data!: DeckNotesData;
cachedCards: Card[] = [];
cardParser!: CardParser;
api!: SimpleFlashcardsApi;
api!: DeckNotesApi;
async onload() {
console.log("Loading Simple Flashcards plugin");
console.log("Loading Deck Notes plugin");
await this.loadSettings();
this.cardParser = new CardParser(this.app);
this.addSettingTab(new SimpleFlashcardsSettingsTab(this.app, this));
this.addSettingTab(new DeckNotesSettingsTab(this.app, this));
// 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 = {};
this.api = new DeckNotesApi(this);
if (!window.deckNotes) {
window.deckNotes = {};
}
window.simpleFlashcards.api = this.api;
window.deckNotes.api = this.api;
// Command: Show Random Card
this.addCommand({
@ -67,11 +63,11 @@ export default class SimpleFlashcardsPlugin extends Plugin {
}
onunload() {
console.log("Unloading Simple Flashcards plugin");
console.log("Unloading Deck Notes plugin");
// Clear API reference
if (window.simpleFlashcards) {
window.simpleFlashcards.api = undefined;
if (window.deckNotes) {
window.deckNotes.api = undefined;
}
}

View file

@ -1,12 +1,12 @@
import { type App, PluginSettingTab, Setting } from "obsidian";
import type { SimpleFlashcardsSettings } from "./@types/settings";
import type SimpleFlashcardsPlugin from "./flashcards-Plugin";
import type { DeckNotesSettings } from "./@types/settings";
import type DeckNotesPlugin from "./dn-Plugin";
export class SimpleFlashcardsSettingsTab extends PluginSettingTab {
plugin: SimpleFlashcardsPlugin;
newSettings!: SimpleFlashcardsSettings;
export class DeckNotesSettingsTab extends PluginSettingTab {
plugin: DeckNotesPlugin;
newSettings!: DeckNotesSettings;
constructor(app: App, plugin: SimpleFlashcardsPlugin) {
constructor(app: App, plugin: DeckNotesPlugin) {
super(app, plugin);
this.plugin = plugin;
}
@ -16,7 +16,7 @@ export class SimpleFlashcardsSettingsTab extends PluginSettingTab {
await this.plugin.saveSettings();
}
private cloneSettings(): SimpleFlashcardsSettings {
private cloneSettings(): DeckNotesSettings {
return JSON.parse(JSON.stringify(this.plugin.settings));
}
@ -33,11 +33,11 @@ export class SimpleFlashcardsSettingsTab extends PluginSettingTab {
const { containerEl } = this;
containerEl.empty();
new Setting(containerEl).setHeading().setName("Simple Flashcards");
new Setting(containerEl).setHeading().setName("Deck Notes");
new Setting(containerEl)
.setName("Save Settings")
.setClass("flashcards-save-reset")
.setClass("decknotes-save-reset")
.addButton((button) =>
button
.setButtonText("Reset")

View file

@ -1,3 +1,3 @@
import SimpleFlashcardsPlugin from "./flashcards-Plugin";
import DeckNotesPlugin from "./dn-Plugin";
export default SimpleFlashcardsPlugin;
export default DeckNotesPlugin;