Merge pull request #84 from gamosoft/features/new-features

Features/new features
This commit is contained in:
Guillermo Villar 2025-12-12 16:46:17 +01:00 committed by GitHub
commit 64cc6432a2
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 165 additions and 9 deletions

27
docs/logo-512.svg Normal file
View File

@ -0,0 +1,27 @@
<svg xmlns="http://www.w3.org/2000/svg" width="439" height="512" viewBox="40 30 120 140">
<defs>
<linearGradient id="logoGradient" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" style="stop-color: #667eea;"/>
<stop offset="100%" style="stop-color: #764ba2;"/>
</linearGradient>
</defs>
<!-- Main document shape -->
<rect x="40" y="30" width="120" height="140" rx="8" fill="url(#logoGradient)"/>
<!-- Paper fold effect at top right -->
<path d="M 140 30 L 140 50 L 160 50 Z" fill="#5568d3"/>
<!-- Lines representing text on the document -->
<line x1="60" y1="70" x2="140" y2="70" stroke="white" stroke-width="4" stroke-linecap="round" opacity="0.9"/>
<line x1="60" y1="90" x2="140" y2="90" stroke="white" stroke-width="4" stroke-linecap="round" opacity="0.9"/>
<line x1="60" y1="110" x2="120" y2="110" stroke="white" stroke-width="4" stroke-linecap="round" opacity="0.9"/>
<!-- Discovery symbol - a magnifying glass -->
<g transform="translate(100, 135)">
<circle cx="0" cy="0" r="18" fill="none" stroke="white" stroke-width="4"/>
<line x1="13" y1="13" x2="25" y2="25" stroke="white" stroke-width="4" stroke-linecap="round"/>
<circle cx="0" cy="0" r="10" fill="white" opacity="0.3"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

26
docs/logo-cropped.svg Normal file
View File

@ -0,0 +1,26 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="40 30 120 140">
<defs>
<linearGradient id="logoGradient" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" style="stop-color: rgb(102, 126, 234); stop-opacity: 1; --darkreader-inline-stopcolor: var(--darkreader-text-667eea, #67a0ea);" data-darkreader-inline-stopcolor=""/>
<stop offset="100%" style="stop-color: rgb(118, 75, 162); stop-opacity: 1; --darkreader-inline-stopcolor: var(--darkreader-text-764ba2, #926bba);" data-darkreader-inline-stopcolor=""/>
</linearGradient>
</defs>
<!-- Main document shape -->
<rect x="40" y="30" width="120" height="140" rx="8" fill="url(#logoGradient)"/>
<!-- Paper fold effect at top right -->
<path d="M 140 30 L 140 50 L 160 50 Z" fill="#5568d3" data-darkreader-inline-fill="" style="--darkreader-inline-fill: var(--darkreader-text-5568d3, #5f91d6);"/>
<!-- Lines representing text on the document -->
<line x1="60" y1="70" x2="140" y2="70" stroke="white" stroke-width="4" stroke-linecap="round" opacity="0.9" data-darkreader-inline-stroke="" style="--darkreader-inline-stroke: var(--darkreader-border-ffffff, #303436);"/>
<line x1="60" y1="90" x2="140" y2="90" stroke="white" stroke-width="4" stroke-linecap="round" opacity="0.9" data-darkreader-inline-stroke="" style="--darkreader-inline-stroke: var(--darkreader-border-ffffff, #303436);"/>
<line x1="60" y1="110" x2="120" y2="110" stroke="white" stroke-width="4" stroke-linecap="round" opacity="0.9" data-darkreader-inline-stroke="" style="--darkreader-inline-stroke: var(--darkreader-border-ffffff, #303436);"/>
<!-- Discovery symbol - a magnifying glass -->
<g transform="translate(100, 135)">
<circle cx="0" cy="0" r="18" fill="none" stroke="white" stroke-width="4" data-darkreader-inline-stroke="" style="--darkreader-inline-stroke: var(--darkreader-text-ffffff, #e8e6e3);"/>
<line x1="13" y1="13" x2="25" y2="25" stroke="white" stroke-width="4" stroke-linecap="round" data-darkreader-inline-stroke="" style="--darkreader-inline-stroke: var(--darkreader-border-ffffff, #303436);"/>
<circle cx="0" cy="0" r="10" fill="white" opacity="0.3" data-darkreader-inline-fill="" style="--darkreader-inline-fill: var(--darkreader-text-ffffff, #e8e6e3);"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.2 KiB

View File

@ -49,6 +49,7 @@
- **Browser history** - Back/forward buttons navigate between notes - **Browser history** - Back/forward buttons navigate between notes
- **Shareable links** - Bookmark or share direct links to notes with highlighted terms - **Shareable links** - Bookmark or share direct links to notes with highlighted terms
- **Refresh safe** - Page reload keeps you on the same note with search context - **Refresh safe** - Page reload keeps you on the same note with search context
- **Copy link button** - One-click copy of note URL to clipboard
## 🎨 Customization ## 🎨 Customization
@ -275,6 +276,7 @@ date: {{date}}
| `Ctrl+B` | `Cmd+B` | Bold | `**text**` | | `Ctrl+B` | `Cmd+B` | Bold | `**text**` |
| `Ctrl+I` | `Cmd+I` | Italic | `*text*` | | `Ctrl+I` | `Cmd+I` | Italic | `*text*` |
| `Ctrl+K` | `Cmd+K` | Insert link | `[text](url)` | | `Ctrl+K` | `Cmd+K` | Insert link | `[text](url)` |
| `Ctrl+Alt+T` | `Cmd+Option+T` | Insert table | 3x3 table placeholder |
## 🚀 Performance ## 🚀 Performance

View File

@ -55,6 +55,7 @@ function noteApp() {
totalMatches: 0, // Total number of matches in the note totalMatches: 0, // Total number of matches in the note
isSaving: false, isSaving: false,
lastSaved: false, lastSaved: false,
linkCopied: false,
saveTimeout: null, saveTimeout: null,
// Theme state // Theme state
@ -461,6 +462,12 @@ function noteApp() {
e.preventDefault(); e.preventDefault();
this.insertLink(); this.insertLink();
} }
// Ctrl/Cmd + Alt + T for table
if ((e.ctrlKey || e.metaKey) && e.altKey && e.key === 't') {
e.preventDefault();
this.insertTable();
}
} }
}); });
} }
@ -2548,6 +2555,39 @@ function noteApp() {
this.autoSave(); this.autoSave();
}, },
// Insert a markdown table placeholder
insertTable() {
const editor = document.getElementById('note-editor');
if (!editor) return;
const cursorPos = editor.selectionStart;
// Basic 3x3 table placeholder
const table = `| Header 1 | Header 2 | Header 3 |
|----------|----------|----------|
| Cell 1 | Cell 2 | Cell 3 |
| Cell 4 | Cell 5 | Cell 6 |
`;
// Add newline before if not at start of line
const textBefore = this.noteContent.substring(0, cursorPos);
const needsNewlineBefore = textBefore.length > 0 && !textBefore.endsWith('\n');
const prefix = needsNewlineBefore ? '\n\n' : '';
// Insert the table
this.noteContent = textBefore + prefix + table + this.noteContent.substring(cursorPos);
// Position cursor at first header for easy editing
this.$nextTick(() => {
const newPos = cursorPos + prefix.length + 2; // After "| "
editor.setSelectionRange(newPos, newPos + 8); // Select "Header 1"
editor.focus();
});
// Trigger autosave
this.autoSave();
},
// Save current note // Save current note
async saveNote() { async saveNote() {
if (!this.currentNote) return; if (!this.currentNote) return;
@ -3975,6 +4015,34 @@ function noteApp() {
} }
}, },
// Copy current note link to clipboard
async copyNoteLink() {
if (!this.currentNote) return;
// Build the full URL
const pathWithoutExtension = this.currentNote.replace('.md', '');
const encodedPath = pathWithoutExtension.split('/').map(segment => encodeURIComponent(segment)).join('/');
const url = `${window.location.origin}/${encodedPath}`;
try {
await navigator.clipboard.writeText(url);
} catch (error) {
// Fallback for older browsers
const textArea = document.createElement('textarea');
textArea.value = url;
document.body.appendChild(textArea);
textArea.select();
document.execCommand('copy');
document.body.removeChild(textArea);
}
// Show brief "Copied!" feedback
this.linkCopied = true;
setTimeout(() => {
this.linkCopied = false;
}, 1500);
},
// Homepage folder navigation methods // Homepage folder navigation methods
goToHomepageFolder(folderPath) { goToHomepageFolder(folderPath) {
this.showGraph = false; // Close graph when navigating this.showGraph = false; // Close graph when navigating

View File

@ -1829,6 +1829,8 @@
@click="viewMode = 'edit'" @click="viewMode = 'edit'"
class="px-2 md:px-3 py-1 text-xs md:text-sm rounded transition" class="px-2 md:px-3 py-1 text-xs md:text-sm rounded transition"
:style="viewMode === 'edit' ? 'background-color: var(--accent-primary); color: white;' : 'color: var(--text-secondary);'" :style="viewMode === 'edit' ? 'background-color: var(--accent-primary); color: white;' : 'color: var(--text-secondary);'"
@mouseenter="if (viewMode !== 'edit') $el.style.backgroundColor = 'var(--bg-secondary)'"
@mouseleave="if (viewMode !== 'edit') $el.style.backgroundColor = 'transparent'"
> >
Edit Edit
</button> </button>
@ -1836,6 +1838,8 @@
@click="viewMode = 'split'" @click="viewMode = 'split'"
class="mobile-hide-split px-2 md:px-3 py-1 text-xs md:text-sm rounded transition" class="mobile-hide-split px-2 md:px-3 py-1 text-xs md:text-sm rounded transition"
:style="viewMode === 'split' ? 'background-color: var(--accent-primary); color: white;' : 'color: var(--text-secondary);'" :style="viewMode === 'split' ? 'background-color: var(--accent-primary); color: white;' : 'color: var(--text-secondary);'"
@mouseenter="if (viewMode !== 'split') $el.style.backgroundColor = 'var(--bg-secondary)'"
@mouseleave="if (viewMode !== 'split') $el.style.backgroundColor = 'transparent'"
> >
Split Split
</button> </button>
@ -1843,21 +1847,50 @@
@click="viewMode = 'preview'" @click="viewMode = 'preview'"
class="px-2 md:px-3 py-1 text-xs md:text-sm rounded transition" class="px-2 md:px-3 py-1 text-xs md:text-sm rounded transition"
:style="viewMode === 'preview' ? 'background-color: var(--accent-primary); color: white;' : 'color: var(--text-secondary);'" :style="viewMode === 'preview' ? 'background-color: var(--accent-primary); color: white;' : 'color: var(--text-secondary);'"
@mouseenter="if (viewMode !== 'preview') $el.style.backgroundColor = 'var(--bg-secondary)'"
@mouseleave="if (viewMode !== 'preview') $el.style.backgroundColor = 'transparent'"
> >
Preview Preview
</button> </button>
</div> </div>
<!-- Export HTML Button --> <!-- Note Actions Toolbar -->
<button <div
@click="exportToHTML()" x-show="currentNote"
class="px-2 md:px-3 py-1 md:py-1.5 text-xs md:text-sm rounded transition hover:opacity-80" class="flex items-center rounded overflow-hidden"
style="background-color: var(--accent-secondary); color: var(--text-primary);" style="background-color: var(--bg-tertiary); border: 1px solid var(--border-primary);"
title="Export as HTML"
> >
<span class="hidden md:inline">📄 Export HTML</span> <button
<span class="md:hidden">📄</span> @click="exportToHTML()"
</button> class="p-2 transition"
style="color: var(--text-secondary);"
title="Export as HTML"
@mouseenter="$el.style.backgroundColor = 'var(--bg-secondary)'"
@mouseleave="$el.style.backgroundColor = 'transparent'"
>
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 10v6m0 0l-3-3m3 3l3-3m2 8H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"></path>
</svg>
</button>
<div style="width: 1px; height: 20px; background-color: var(--border-primary);"></div>
<button
@click="copyNoteLink()"
class="p-2 transition hover:bg-opacity-80"
:title="linkCopied ? 'Copied!' : 'Copy link to clipboard'"
:style="'color: ' + (linkCopied ? 'var(--success, #22c55e)' : 'var(--text-secondary)') + ';'"
@mouseenter="$el.style.backgroundColor = 'var(--bg-secondary)'"
@mouseleave="$el.style.backgroundColor = 'transparent'"
>
<!-- Link icon (default) -->
<svg x-show="!linkCopied" class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13.828 10.172a4 4 0 00-5.656 0l-4 4a4 4 0 105.656 5.656l1.102-1.101m-.758-4.899a4 4 0 005.656 0l4-4a4 4 0 00-5.656-5.656l-1.1 1.1"></path>
</svg>
<!-- Checkmark icon (after copy) -->
<svg x-show="linkCopied" x-cloak class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"></path>
</svg>
</button>
</div>
</div> </div>
</div> </div>