Coding
PromptBeginner5 minmarkdown
Nano Banana Pro
Agent skill for nano-banana-pro
6
A spaced repetition flashcard app for learning German vocabulary, built with Tauri 2, Vue 3, and TypeScript.
Sign in to like and favorite skills
A spaced repetition flashcard app for learning German vocabulary, built with Tauri 2, Vue 3, and TypeScript.
verteilte/ āāā src/ # Frontend (Vue 3 + TypeScript) ā āāā App.vue # Main app (1077 lines) - all UI logic ā āāā lib/ ā ā āāā database.ts # User vocabulary database (SQLite) ā ā āāā dictionary.ts # German-English dictionary (200k+ words) ā ā āāā utils.ts # Utility functions ā āāā components/ui/ # Shadcn-vue UI components ā āāā main.ts # App entry point āāā src-tauri/ # Backend (Rust) ā āāā src/ ā ā āāā lib.rs # Dictionary decompression + migrations ā ā āāā main.rs # App entry ā āāā Cargo.toml # Rust dependencies ā āāā tauri.conf.json # Tauri configuration āāā public/ ā āāā dictionary.db.gz # Compressed dictionary (52MB ā 150MB) āāā scripts/ ā āāā build-dictionary-db.cjs # Dictionary builder script āāā package.json # npm dependencies
<script setup>words.db - User's vocabulary cardsdictionary.db - German-English dictionary (200k+ entries){ "@tauri-apps/plugin-sql": "SQLite plugin", "@tauri-apps/plugin-clipboard-manager": "Clipboard access", "pako": "gzip compression (dictionary)", "flate2": "Rust gzip decompression" }
Bad: -2 score, 10 min intervalGood: +1 score, exponential growthGreat: +2 score, 2x exponential growthnextReviewAt timestampwords.db)ā ļø IMPORTANT: Database uses camelCase column names (createdAt, lastReviewedAt, nextReviewAt)!
CREATE TABLE words ( id INTEGER PRIMARY KEY AUTOINCREMENT, original TEXT NOT NULL, -- German word translation TEXT NOT NULL, -- English translation article TEXT NOT NULL DEFAULT '', -- der/die/das created_at DATETIME DEFAULT CURRENT_TIMESTAMP, -- Legacy column (unused) score INTEGER NOT NULL DEFAULT 0, -- Spaced repetition score createdAt INTEGER NOT NULL, -- Timestamp (ms) - ACTUAL COLUMN USED lastReviewedAt INTEGER NOT NULL, -- Timestamp (ms) - ACTUAL COLUMN USED nextReviewAt INTEGER NOT NULL -- Timestamp (ms) - ACTUAL COLUMN USED );
Migrations:
created_atdictionary.db)CREATE TABLE dictionary ( word TEXT PRIMARY KEY, -- German word pronunciation TEXT, -- IPA pronunciation gender TEXT, -- der/die/das meanings TEXT, -- JSON array of English meanings notes TEXT, -- JSON array of usage notes synonyms TEXT, -- JSON array of German synonyms seeAlso TEXT -- JSON array of related words );
function calculateNextReview(score: number, adjustment: number): number { const newScore = Math.max(0, score + adjustment); // Exponential intervals based on SM-2 const intervals = [ 10 * 60 * 1000, // 0: 10 minutes 1 * 60 * 60 * 1000, // 1: 1 hour 4 * 60 * 60 * 1000, // 2: 4 hours 1 * 24 * 60 * 60 * 1000, // 3: 1 day 3 * 24 * 60 * 60 * 1000, // 4: 3 days 7 * 24 * 60 * 60 * 1000, // 5: 1 week 14 * 24 * 60 * 60 * 1000, // 6: 2 weeks 30 * 24 * 60 * 60 * 1000, // 7: 1 month 90 * 24 * 60 * 60 * 1000, // 8: 3 months 180 * 24 * 60 * 60 * 1000 // 9+: 6 months ]; const interval = intervals[Math.min(newScore, intervals.length - 1)]; return Date.now() + interval; }
Rating Actions:
score - 2, 10 minutesscore + 1, exponentialscore + 2, exponential (2x jump)SELECT * FROM dictionary WHERE LOWER(word) LIKE 'haus%' ORDER BY LENGTH(word), word LIMIT 10
// 1. Query 200 entries containing search term SELECT * FROM dictionary WHERE LOWER(meanings) LIKE '%house%' LIMIT 200 // 2. Fuzzy match in TypeScript meanings.split(',').forEach(phrase => { const distance = levenshteinDistance(searchTerm, phrase.trim()); const score = distance + (phraseIndex * 0.5); // Position penalty }); // 3. Sort by score (lower = better) // 4. Return top 10 matches
Levenshtein Distance: Measures edit distance between strings
# Install Rust curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh # Install Node.js (v18+) # Install dependencies npm install
# Start dev server (Vite + Tauri hot reload) npm run tauri dev # Build dictionary database (if changed) npm run build-dictionary
# Build optimized binary npm run tauri build # Output: src-tauri/target/release/bundle/
Date.now() + 60000 (60 seconds)nextReviewAt = now)nextReviewAt timestampsetTimeout with Vue's nextTick() for better reactivityinputmode="text", enterkeyhint="next")bg-purple-500)rotateY(180deg)tauri.conf.json{ "identifier": "com.sheaksadi.verteilte", "productName": "Verteilte", "bundle": { "resources": ["../public/dictionary.db.gz"] // Embedded dictionary } }
package.json Scripts{ "dev": "vite", "build": "vue-tsc --noEmit && vite build", "tauri": "tauri", "build-dictionary": "node scripts/build-dictionary-db.cjs" }
ref() and computed() for reactivitycalculateNextReview(), handleKeydown()MIT License - Feel free to use and modify
Built with ā¤ļø for German language learners