diff --git a/backend/themes.py b/backend/themes.py index cdcf150..982fcd0 100644 --- a/backend/themes.py +++ b/backend/themes.py @@ -7,6 +7,32 @@ from typing import List, Dict import re +def parse_theme_metadata(theme_path: Path) -> Dict[str, str]: + """Parse theme metadata from CSS file comments""" + metadata = { + "type": "dark" # Default to dark for backward compatibility + } + + try: + with open(theme_path, 'r', encoding='utf-8') as f: + # Read first few lines to find metadata + for i, line in enumerate(f): + if i > 10: # Only check first 10 lines + break + + # Look for @theme-type metadata + if '@theme-type:' in line: + # Extract the value (light or dark) + match = re.search(r'@theme-type:\s*(light|dark)', line) + if match: + metadata["type"] = match.group(1) + break + except Exception as e: + print(f"Error parsing theme metadata from {theme_path}: {e}") + + return metadata + + def get_available_themes(themes_dir: str) -> List[Dict[str, str]]: """Get all available themes from the themes directory""" themes_path = Path(themes_dir) @@ -30,9 +56,13 @@ def get_available_themes(themes_dir: str) -> List[Dict[str, str]]: theme_name = theme_file.stem.replace("-", " ").replace("_", " ").title() icon = theme_icons.get(theme_file.stem, "🎨") + # Parse theme metadata + metadata = parse_theme_metadata(theme_file) + themes.append({ "id": theme_file.stem, "name": f"{icon} {theme_name}", + "type": metadata["type"], # Add theme type (light/dark) "builtin": False }) diff --git a/documentation/FEATURES.md b/documentation/FEATURES.md index 392b25b..d0a6022 100644 --- a/documentation/FEATURES.md +++ b/documentation/FEATURES.md @@ -9,7 +9,8 @@ - **Undo/Redo** - Ctrl+Z / Ctrl+Y support - **Syntax highlighting** for code blocks (50+ languages) - **Copy code blocks** - One-click copy button on hover -- **LaTeX/Math rendering** - Beautiful mathematical equations with MathJax +- **LaTeX/Math rendering** - Beautiful mathematical equations with MathJax (see [MATHJAX.md](MATHJAX.md)) +- **Mermaid diagrams** - Create flowcharts, sequence diagrams, and more (see [MERMAID.md](MERMAID.md)) - **HTML Export** - Export notes as standalone HTML files ### Organization @@ -106,6 +107,31 @@ $$ 📄 **See the [MATHJAX](MATHJAX.md) note for more examples and syntax reference.** +## 📊 Mermaid Diagrams + +### Visual Diagrams +- **Flowcharts** - Process flows and decision trees +- **Sequence diagrams** - System interactions over time +- **Class diagrams** - UML class relationships +- **State diagrams** - State machines and transitions +- **Gantt charts** - Project timelines +- **Pie charts** - Data visualization +- **Git graphs** - Branch and commit history +- **Theme support** - Adapts to your theme + +### Example +````markdown +```mermaid +graph TD + A[Start] --> B{Is it working?} + B -->|Yes| C[Great!] + B -->|No| D[Debug] + D --> B +``` +```` + +📄 **See the [MERMAID](MERMAID.md) note for diagram examples and syntax reference.** + ## ⚡ Keyboard Shortcuts | Windows/Linux | Mac | Action | diff --git a/documentation/MERMAID.md b/documentation/MERMAID.md new file mode 100644 index 0000000..158d134 --- /dev/null +++ b/documentation/MERMAID.md @@ -0,0 +1,376 @@ +# Mermaid Diagrams + +NoteDiscovery supports **Mermaid** diagrams directly in your markdown notes! Mermaid lets you create diagrams and visualizations using text-based definitions, making it easy to version control and collaborate. + +## How to Use + +Simply create a code block with the language set to `mermaid`: + +````markdown +```mermaid +graph TD + A[Start] --> B{Is it working?} + B -->|Yes| C[Great!] + B -->|No| D[Debug] + D --> B +``` +```` + +## Basic Examples + +### Flowchart + +````markdown +```mermaid +graph LR + A[Square Rect] --> B((Circle)) + A --> C(Round Rect) + B --> D{Rhombus} + C --> D +``` +```` + +**Preview:** + +```mermaid +graph LR + A[Square Rect] --> B((Circle)) + A --> C(Round Rect) + B --> D{Rhombus} + C --> D +``` + +--- + +### Sequence Diagram + +````markdown +```mermaid +sequenceDiagram + Alice->>John: Hello John, how are you? + John-->>Alice: Great! + Alice-)John: See you later! +``` +```` + +**Preview:** + +```mermaid +sequenceDiagram + Alice->>John: Hello John, how are you? + John-->>Alice: Great! + Alice-)John: See you later! +``` + +--- + +### Class Diagram + +````markdown +```mermaid +classDiagram + Animal <|-- Duck + Animal <|-- Fish + Animal : +int age + Animal : +String gender + Animal: +isMammal() + class Duck{ + +String beakColor + +swim() + +quack() + } + class Fish{ + -int sizeInFeet + -canEat() + } +``` +```` + +**Preview:** + +```mermaid +classDiagram + Animal <|-- Duck + Animal <|-- Fish + Animal : +int age + Animal : +String gender + Animal: +isMammal() + class Duck{ + +String beakColor + +swim() + +quack() + } + class Fish{ + -int sizeInFeet + -canEat() + } +``` + +--- + +### State Diagram + +````markdown +```mermaid +stateDiagram-v2 + [*] --> Still + Still --> [*] + Still --> Moving + Moving --> Still + Moving --> Crash + Crash --> [*] +``` +```` + +**Preview:** + +```mermaid +stateDiagram-v2 + [*] --> Still + Still --> [*] + Still --> Moving + Moving --> Still + Moving --> Crash + Crash --> [*] +``` + +--- + +### Gantt Chart + +````markdown +```mermaid +gantt + title Project Timeline + dateFormat YYYY-MM-DD + section Planning + Research :a1, 2024-01-01, 30d + Design :after a1, 20d + section Development + Backend :2024-02-01, 40d + Frontend :2024-02-15, 35d + section Testing + Integration Tests :2024-03-20, 15d +``` +```` + +**Preview:** + +```mermaid +gantt + title Project Timeline + dateFormat YYYY-MM-DD + section Planning + Research :a1, 2024-01-01, 30d + Design :after a1, 20d + section Development + Backend :2024-02-01, 40d + Frontend :2024-02-15, 35d + section Testing + Integration Tests :2024-03-20, 15d +``` + +--- + +### Entity Relationship Diagram + +````markdown +```mermaid +erDiagram + CUSTOMER ||--o{ ORDER : places + ORDER ||--|{ LINE-ITEM : contains + CUSTOMER }|..|{ DELIVERY-ADDRESS : uses + + CUSTOMER { + string name + string email + string phone + } + ORDER { + int orderNumber + date orderDate + string status + } +``` +```` + +**Preview:** + +```mermaid +erDiagram + CUSTOMER ||--o{ ORDER : places + ORDER ||--|{ LINE-ITEM : contains + CUSTOMER }|..|{ DELIVERY-ADDRESS : uses + + CUSTOMER { + string name + string email + string phone + } + ORDER { + int orderNumber + date orderDate + string status + } +``` + +--- + +### Pie Chart + +````markdown +```mermaid +pie title Pet Preferences + "Dogs" : 45 + "Cats" : 30 + "Birds" : 15 + "Fish" : 10 +``` +```` + +**Preview:** + +```mermaid +pie title Pet Preferences + "Dogs" : 45 + "Cats" : 30 + "Birds" : 15 + "Fish" : 10 +``` + +--- + +### Git Graph + +````markdown +```mermaid +gitGraph + commit + commit + branch develop + checkout develop + commit + commit + checkout main + merge develop + commit +``` +```` + +**Preview:** + +```mermaid +gitGraph + commit + commit + branch develop + checkout develop + commit + commit + checkout main + merge develop + commit +``` + +--- + +### User Journey + +````markdown +```mermaid +journey + title My Working Day + section Go to work + Make tea: 5: Me + Go upstairs: 3: Me + Do work: 1: Me, Cat + section Go home + Go downstairs: 5: Me + Sit down: 5: Me +``` +```` + +**Preview:** + +```mermaid +journey + title My Working Day + section Go to work + Make tea: 5: Me + Go upstairs: 3: Me + Do work: 1: Me, Cat + section Go home + Go downstairs: 5: Me + Sit down: 5: Me +``` + +--- + +### Mindmap + +````markdown +```mermaid +mindmap + root((NoteDiscovery)) + Features + Markdown + Themes + Search + Folders + Integrations + MathJax + Mermaid + Syntax Highlighting + Benefits + Fast + Simple + Offline-first +``` +```` + +**Preview:** + +```mermaid +mindmap + root((NoteDiscovery)) + Features + Markdown + Themes + Search + Folders + Integrations + MathJax + Mermaid + Syntax Highlighting + Benefits + Fast + Simple + Offline-first +``` + +--- + +## Theme Support + +Mermaid diagrams automatically adapt to your current NoteDiscovery theme: +- **Light themes** use the default Mermaid color scheme +- **Dark themes** use dark-optimized colors with proper contrast +- Theme changes automatically re-render all diagrams + +## Tips + +1. **Keep it simple**: Start with basic diagrams and add complexity as needed +2. **Use comments**: Add `%%` for comments in your Mermaid code +3. **Test syntax**: If a diagram doesn't render, check the Mermaid [documentation](https://mermaid.js.org/) +4. **Export**: Diagrams are included when you export notes to HTML + +## More Information + +For the complete Mermaid syntax and more diagram types, visit the official documentation: +- [Mermaid Documentation](https://mermaid.js.org/) +- [Live Editor](https://mermaid.live/) - Test your diagrams online + +--- + +**Pro Tip**: Combine Mermaid diagrams with LaTeX math expressions and code blocks for comprehensive technical documentation! 📊 + diff --git a/documentation/THEMES.md b/documentation/THEMES.md index e7a7c3c..9fc6dd8 100644 --- a/documentation/THEMES.md +++ b/documentation/THEMES.md @@ -72,7 +72,32 @@ If your file is named `my-awesome-theme.css`, use `data-theme="my-awesome-theme" } ``` -#### 3. (Optional) Add a custom emoji icon +#### 3. Add theme type metadata (Recommended) + +Add a comment at the **top of your CSS file** to indicate if your theme is light or dark: + +```css +/* @theme-type: light */ +/* OR */ +/* @theme-type: dark */ +``` + +**Example:** +```css +/* @theme-type: dark */ +/* My Awesome Theme - A beautiful custom theme */ + +:root[data-theme="my-awesome-theme"] { + /* ... your CSS variables ... */ +} +``` + +**Why is this needed?** +Some features (like Mermaid diagrams, Chart.js) need to know if the background is light or dark to adjust their rendering colors accordingly. This metadata is automatically parsed by the application. + +**Default behavior:** If you don't add this metadata, your theme will default to `dark` for backward compatibility. + +#### 4. (Optional) Add a custom emoji icon Edit `backend/themes.py` and add your theme to the `theme_icons` dictionary: @@ -85,7 +110,7 @@ theme_icons = { If you skip this step, your theme will use 🎨 as the default icon. -#### 4. Restart the application +#### 5. Restart the application ```bash # If using Docker: diff --git a/frontend/app.js b/frontend/app.js index c767e6e..0e6bb7a 100644 --- a/frontend/app.js +++ b/frontend/app.js @@ -59,6 +59,7 @@ function noteApp() { expandedFolders: new Set(), draggedNote: null, draggedFolder: null, + dragOverFolder: null, // Track which folder is being hovered during drag // Scroll sync state isScrolling: false, @@ -91,6 +92,9 @@ function noteApp() { // Dropdown state showNewDropdown: false, + // Mermaid state cache + lastMermaidTheme: null, + // DOM element cache (to avoid repeated querySelector calls) _domCache: { editor: null, @@ -294,6 +298,32 @@ function noteApp() { highlightTheme.href = 'https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/github-dark.min.css'; } } + + // Re-render Mermaid diagrams with new theme if there's a current note + if (this.currentNote) { + // Small delay to allow theme CSS to load + setTimeout(() => { + // Clear existing Mermaid renders + const previewContent = document.querySelector('.markdown-preview'); + if (previewContent) { + const mermaidContainers = previewContent.querySelectorAll('.mermaid-rendered'); + mermaidContainers.forEach(container => { + // Replace with the original code block for re-rendering + const parent = container.parentElement; + if (parent && container.dataset.originalCode) { + const pre = document.createElement('pre'); + const code = document.createElement('code'); + code.className = 'language-mermaid'; + code.textContent = container.dataset.originalCode; + pre.appendChild(code); + parent.replaceChild(pre, container); + } + }); + } + // Re-render with new theme + this.renderMermaid(); + }, 100); + } } catch (error) { console.error('Failed to load theme:', error); } @@ -412,15 +442,25 @@ function noteApp() {
Nothing to preview yet...
'; @@ -1690,12 +1844,17 @@ function noteApp() { // Trigger MathJax rendering after DOM updates this.typesetMath(); + // Render Mermaid diagrams + this.renderMermaid(); + // Apply syntax highlighting and add copy buttons to code blocks setTimeout(() => { // Use cached reference if available, otherwise query const previewEl = this._domCache.previewContent || document.querySelector('.markdown-preview'); if (previewEl) { - previewEl.querySelectorAll('pre code').forEach((block) => { + // Exclude code blocks that are rendered by other tools (e.g., Mermaid diagrams) + // Note: MathJax uses $$...$$ delimiters (not code blocks) so no exclusion needed + previewEl.querySelectorAll('pre code:not(.language-mermaid)').forEach((block) => { // Apply syntax highlighting if (!block.classList.contains('hljs')) { hljs.highlightElement(block); @@ -2228,19 +2387,32 @@ function noteApp() { for (const sheet of styleSheets) { try { + // Skip external stylesheets (CDN resources) to avoid CORS errors + // We link them directly in the exported HTML anyway + if (sheet.href && (sheet.href.startsWith('http://') || sheet.href.startsWith('https://'))) { + const currentOrigin = window.location.origin; + const sheetURL = new URL(sheet.href); + if (sheetURL.origin !== currentOrigin) { + // Skip cross-origin stylesheets (they're linked directly in export) + continue; + } + } + const rules = Array.from(sheet.cssRules || []); for (const rule of rules) { const cssText = rule.cssText; - // Include rules that target markdown-preview or mjx-container + // Include rules that target markdown-preview, mjx-container, or mermaid-rendered if (cssText.includes('.markdown-preview') || cssText.includes('mjx-container') || - cssText.includes('.MathJax')) { + cssText.includes('.MathJax') || + cssText.includes('.mermaid-rendered')) { markdownStyles += cssText + '\n'; } } } catch (e) { - // Skip stylesheets that can't be accessed (CORS) - console.warn('Could not access stylesheet:', sheet.href, e); + // Gracefully skip stylesheets that can't be accessed + // (This should rarely happen now that we skip external stylesheets) + console.debug('Skipping stylesheet:', sheet.href); } } @@ -2271,8 +2443,8 @@ function noteApp() { startup: { pageReady: () => { return MathJax.startup.defaultPageReady().then(() => { - // Highlight code blocks after MathJax is done - document.querySelectorAll('pre code').forEach((block) => { + // Highlight code blocks after MathJax is done (exclude diagram renderers) + document.querySelectorAll('pre code:not(.language-mermaid)').forEach((block) => { hljs.highlightElement(block); }); }); @@ -2282,6 +2454,39 @@ function noteApp() { + + +