diff --git a/CLAUDE.md b/CLAUDE.md index 5074554..5ec5b5f 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -1,72 +1,65 @@ -# CLAUDE.md +# AI Assistant Working Guidelines -This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. - -This project is an Obsidian plugin for simple flashcard creation and review. **Read README.md for full feature details and usage instructions.** +**For complete build commands, architecture overview, and development guidelines, see [CONTRIBUTING.md](CONTRIBUTING.md). For user-facing features and usage, see [README.md](README.md).** ## Your Role You are a senior development peer working alongside a Senior Software Engineer (25+ years, primarily Java background) on this hobby TypeScript project. Act as a collaborative partner for: + - **Code review and feedback** when requested - focus on patterns, maintainability, and TypeScript/JS idioms - **Implementation assistance** when explicitly asked - suggest approaches, don't implement unless requested - **Technical discussion** and problem-solving - challenge assumptions, ask probing questions, offer alternatives +- **BE EFFICIENT**: Be succinct and concise, don't waste tokens +- **ASK FOR CLARIFICATION** when implementation choices or requirements are unclear +- **NO SPECULATION**: Never make up code unless asked -## Development Guidelines +## Context Gathering Strategy -**Core Principles:** -- **Follow existing patterns** - Before writing new code: - 1. Search for similar functions in the same module (use `Grep` tool) +When working with this codebase: + +**Always start with:** + +- User features: [README.md](README.md) +- Development setup: [CONTRIBUTING.md](CONTRIBUTING.md) + +**Key architectural concepts:** + +- Cards from H2 headings in markdown files +- Tag-based deck organization (`#flashcards/*` hierarchical tags) +- File-level tags (frontmatter) + card-level tags (inline before H2) +- Hierarchical matching: `activities` matches `activities/morning`, etc. + +**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 +- `@types/settings.d.ts` - Interfaces + +## Key Development Principles + +- **Follow existing patterns**: Before writing new code: + 1. Use `Grep` tool to find similar functions in the same module 2. Check method chaining, line breaks, and error handling patterns 3. Emulate the style exactly, especially for method chains and async/await -- **Understand before acting** - Read project structure, but defer extensive file reading until user specifies what to work on -- **Ask for clarification** when implementation choices or requirements are unclear -- **Be direct and concise** - Assume high technical competence, reference specific files/line numbers -- **Never speculate** - Don't make up code unless asked +- **Respect code style**: 80-char line limit, break method chains at dots, always use braces +- **Reference line numbers**: Use format `file.ts:123` when discussing code - **Point out issues proactively** but wait for explicit requests to fix them -## Commands +## Quality Workflow -- `npm run build` - Build the plugin -- `npm run dev` - Build and watch for changes -- `npm run lint` - Lint TypeScript files -- `npm run fix` - Auto-fix linting issues -- `npm run format` - Format code +1. After changes: run `npm run build` (includes linting) +2. If linting fails: run `npm run fix` to auto-correct +3. Verify build succeeds before completing work -## Architecture +## Contribution Guidelines -**Core files:** -- `main.ts` - Main plugin class -- Plugin structure TBD based on flashcard implementation +When contributing: -**Key features:** -- Simple flashcard syntax -- Spaced repetition algorithm -- Review interface +- **Understand the changes**: Be able to explain rationale clearly +- **Test appropriately**: Follow build commands and verify changes work +- **Review architecture**: Ensure changes fit existing patterns +- **Address real needs**: Focus on solving actual problems -## Code Style Guidelines - -- **Line length**: 80 characters (hard limit) -- **Always use braces** for conditionals -- **Method chaining**: Break at dots for readability, even for single chains. This keeps lines under 80 chars and prevents Biome from wrapping unpredictably. - ```typescript - // GOOD - break at dots - const patterns = this.settings.excludeLinkPatterns - .split("\n") - .map((p) => p.trim()) - .filter((p) => p.length > 0); - - // BAD - all on one line - const patterns = this.settings.excludeLinkPatterns.split("\n").map((p) => p.trim()); - - // GOOD - even single chains if they approach 80 chars - const models = data.models - ?.map((model) => model.name) || []; - ``` -- **Error handling**: `try/catch` with user-friendly `Notice` messages -- **Async**: Use `async/await` consistently - -## Quality Assurance - -- Run `npm run build` after significant changes (includes linting via prebuild) -- Use `npm run fix` to auto-correct linting issues -- Reference specific line numbers when discussing issues (format: `file.ts:123`) \ No newline at end of file +Quality and understanding matter more than the tools used to create the contribution. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..fe4d4ec --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,100 @@ +# Contributing to Simple Flashcards + +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. + +## Development Commands + +```bash +npm run build # Production build +npm run dev # Build and watch for changes +npm run lint # Lint TypeScript files +npm run fix # Auto-fix linting issues +npm run format # Format code +``` + +## Architecture + +### 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 +- **`@types/settings.d.ts`** - TypeScript interfaces + +### Key Concepts + +- **Cards**: Created from H2 headings in markdown files +- **Tags**: Hierarchical `#flashcards/*` tags define deck membership + - File-level tags (frontmatter) apply to all cards in file + - Card-level tags (inline before H2) apply to single card + - Hierarchical matching: `activities` matches `activities/morning`, etc. +- **Card Selection**: Random or least-recent mode +- **View Tracking**: Records card views for least-recent selection + +### Data Flow + +1. **Scanning**: `scanCards()` reads files from `cardPaths` setting +2. **Parsing**: `CardParser.parseFile()` extracts cards and tags +3. **Selection**: `selectCard(deckTag)` filters by hierarchical tag matching +4. **Display**: Modal shows card content, tracks views + +## Code Style Guidelines + +- **Line length**: 80 characters (hard limit) +- **Always use braces** for conditionals +- **Method chaining**: Break at dots for readability, even for single chains + + ```typescript + // GOOD - break at dots + const patterns = this.settings.excludeLinkPatterns + .split("\n") + .map((p) => p.trim()) + .filter((p) => p.length > 0); + + // BAD - all on one line + const patterns = this.settings.excludeLinkPatterns.split("\n").map((p) => p.trim()); + + // GOOD - even single chains if they approach 80 chars + const models = data.models + ?.map((model) => model.name) || []; + ``` + +- **Error handling**: `try/catch` with user-friendly `Notice` messages +- **Async**: Use `async/await` consistently + +## Development Patterns + +Before writing new code: + +1. **Search for similar functions** in the same module (use grep/search) +2. **Check method chaining, line breaks, and error handling patterns** +3. **Emulate the style exactly**, especially for method chains and async/await + +## Quality Assurance + +- Run `npm run build` after significant changes (includes linting via prebuild) +- Use `npm run fix` to auto-correct linting issues +- Reference specific line numbers when discussing issues (format: `file.ts:123`) + +## AI-Assisted Contributions + +We welcome thoughtful contributions, including those created with AI assistance. However, please ensure: + +- **You understand the changes**: You must be able to explain the rationale for your decisions clearly +- **You've tested appropriately**: Follow the build commands and verify changes work +- **You've reviewed the architecture**: Ensure changes fit the existing patterns +- **The contribution addresses a real need**: Focus on solving actual problems or documented issues +- **You've read the relevant context**: See [CLAUDE.md](CLAUDE.md) for AI assistant guidelines + +Quality and understanding matter more than the tools used to create the contribution. + +
+### ⚠️ NOTE FOR AI TOOLS AND THEIR USERS +Contributing to this project requires **human judgment, contextual understanding**, and **familiarity with the project's architecture and goals**. Please ensure: +- You have **carefully read corresponding issues and relevant documentation** +- You have **manually reviewed all changes** and can explain the rationale +- You understand how this contribution fits into the broader project context +- See [CLAUDE.md](CLAUDE.md) for detailed AI assistant working guidelines +
diff --git a/README.md b/README.md index 6419916..df06c5c 100644 --- a/README.md +++ b/README.md @@ -5,10 +5,10 @@ A simple activity card plugin for Obsidian. Display random cards from your markd ## Features - **Random or Least-Recent Selection** - View cards randomly or ensure you see all cards evenly -- **Deck Organization** - Organize cards into different folders/paths +- **Tag-Based Deck Organization** - Organize cards using hierarchical `#flashcards/*` tags - **View Tracking** - Optional tracking to prioritize cards you haven't seen recently - **Simple Markdown Format** - Use H2 headings to define cards -- **Switch Decks on the Fly** - Change between different card collections within the modal +- **Switch Decks on the Fly** - Cycle through discovered deck tags within the modal ## Installation @@ -98,7 +98,7 @@ Repeat 4 times. Open Settings → Simple Flashcards to configure: ### Card Paths -List of folders or files to scan for cards (one per line, relative to vault root). +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: ``` @@ -107,8 +107,8 @@ Daily/Prompts Resources/Meditations.md ``` -### Default Deck Path -The default path used by "Show Random Activity Card" command. Leave empty to select from all configured paths. +### 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. @@ -119,37 +119,41 @@ Enable tracking of when cards were last viewed. Required for "Least Recently Vie ## Commands -### Show Random Activity Card +### 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 configured card paths +- **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 -### Refresh Activity Cards +### 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 -### Organizing Cards +### Organizing Cards with Tags -**Multiple files in folders:** -``` -Activities/ - ├── stretches.md - ├── writing-prompts.md - └── meditations.md -``` +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. -**Single file per deck:** -``` -Daily/ - └── morning-routine.md -``` +**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 -**Mixed approach:** -Configure both folders and individual files in Card Paths. +**Example structure:** +``` +Activities/stretches.md → All cards get #flashcards/activities from frontmatter + Card 1: Also tagged #flashcards/activities/morning + Card 2: Also tagged #flashcards/activities/evening + +Journal/prompts.md → All cards get #flashcards/creative from frontmatter + Card 1: Also tagged #flashcards/creative/writing + Card 2: Also tagged #flashcards/creative/art +``` ### View Tracking @@ -158,12 +162,31 @@ With "Track Views" enabled and "Least Recently Viewed" selection mode, the plugi - Exercise variety - Prompt cycling -### Tags and Metadata +### Tags for Deck Organization -While `#flashcards` tag lines are stripped for display, you can still: -- Use frontmatter tags for vault organization -- Add inline tags for sub-categorization -- Include any markdown formatting (bold, lists, links, etc.) +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 +- Cards support any markdown formatting (bold, lists, links, etc.) + +### API Access + +The plugin exposes a JavaScript API at `window.simpleFlashcards.api`: + +```javascript +// Get a random card embed +window.simpleFlashcards.api.embedCard('activities') + +// Get all discovered deck tags +window.simpleFlashcards.api.getTags() + +// Select cards by hash +window.simpleFlashcards.api.selectCardsByHash(['card-hash-1', 'card-hash-2']) + +// Get random card from hash list +window.simpleFlashcards.api.selectCardByHash(['card-hash-1', 'card-hash-2']) +``` ## Development