diff --git a/public/pages/notes.js b/public/pages/notes.js
index 68a97d3..c9f032c 100644
--- a/public/pages/notes.js
+++ b/public/pages/notes.js
@@ -149,6 +149,53 @@ function renderNoteCard(note) {
`;
}
+// --------------------------------------------------------
+// Formatierungs-Helfer
+// --------------------------------------------------------
+
+function applyFormat(textarea, format) {
+ const start = textarea.selectionStart;
+ const end = textarea.selectionEnd;
+ const text = textarea.value;
+ const sel = text.slice(start, end);
+
+ let before, after, insert;
+ switch (format) {
+ case 'bold':
+ before = '**'; after = '**';
+ insert = sel || 'Text';
+ break;
+ case 'italic':
+ before = '*'; after = '*';
+ insert = sel || 'Text';
+ break;
+ case 'list': {
+ // Jede Zeile mit "- " prefixen oder neuen Listenpunkt einfügen
+ if (sel) {
+ const lines = sel.split('\n').map((l) => l.startsWith('- ') ? l : `- ${l}`);
+ textarea.setRangeText(lines.join('\n'), start, end, 'end');
+ return;
+ }
+ before = ''; after = '';
+ const lineStart = text.lastIndexOf('\n', start - 1) + 1;
+ const currentLine = text.slice(lineStart, start);
+ if (currentLine.trim() === '') {
+ textarea.setRangeText('- ', start, start, 'end');
+ } else {
+ textarea.setRangeText('\n- ', start, start, 'end');
+ }
+ return;
+ }
+ default: return;
+ }
+
+ const replacement = `${before}${insert}${after}`;
+ textarea.setRangeText(replacement, start, end, 'select');
+ // Selektion auf den eingefügten Text setzen (ohne Marker)
+ textarea.selectionStart = start + before.length;
+ textarea.selectionEnd = start + before.length + insert.length;
+}
+
// --------------------------------------------------------
// Modal
// --------------------------------------------------------
@@ -165,8 +212,20 @@ function openNoteModal({ mode, note = null }) {
@@ -205,6 +264,22 @@ function openNoteModal({ mode, note = null }) {
});
});
+ // Formatierungs-Toolbar
+ const textarea = panel.querySelector('#note-content');
+ panel.querySelectorAll('.note-format-btn[data-format]').forEach((btn) => {
+ btn.addEventListener('click', () => {
+ applyFormat(textarea, btn.dataset.format);
+ textarea.focus();
+ });
+ });
+
+ textarea.addEventListener('keydown', (e) => {
+ if (e.ctrlKey || e.metaKey) {
+ if (e.key === 'b') { e.preventDefault(); applyFormat(textarea, 'bold'); }
+ if (e.key === 'i') { e.preventDefault(); applyFormat(textarea, 'italic'); }
+ }
+ });
+
panel.querySelector('#note-modal-cancel').addEventListener('click', closeModal);
panel.querySelector('#note-modal-save').addEventListener('click', async () => {
diff --git a/public/styles/notes.css b/public/styles/notes.css
index b944cec..baf8e44 100644
--- a/public/styles/notes.css
+++ b/public/styles/notes.css
@@ -101,7 +101,7 @@
position: relative;
opacity: 0;
transition: opacity var(--transition-fast), background-color var(--transition-fast);
- color: var(--color-text-primary);
+ color: inherit;
}
.note-card__pin::before {
@@ -127,14 +127,15 @@
font-size: var(--text-sm);
font-weight: var(--font-weight-semibold);
margin-bottom: var(--space-1);
- color: var(--color-text-primary);
+ color: inherit;
padding-right: var(--space-6);
}
.note-card__content {
font-size: var(--text-sm);
line-height: var(--line-height-relaxed);
- color: var(--color-text-secondary);
+ color: inherit;
+ opacity: 0.78;
word-break: break-word;
white-space: pre-wrap;
}
@@ -149,7 +150,8 @@
justify-content: space-between;
margin-top: var(--space-2);
padding-top: var(--space-2);
- border-top: 1px solid var(--color-border-subtle);
+ border-top: 1px solid currentColor;
+ opacity: 0.55;
}
.note-card__creator {
@@ -157,7 +159,7 @@
align-items: center;
gap: var(--space-1);
font-size: var(--text-xs);
- color: var(--color-text-tertiary);
+ color: inherit;
}
.note-card__avatar {
@@ -184,7 +186,7 @@
align-items: center;
justify-content: center;
position: relative;
- color: var(--color-text-tertiary);
+ color: inherit;
opacity: 0;
transition: opacity var(--transition-fast), background-color var(--transition-fast);
}
@@ -256,3 +258,54 @@
.note-color-swatch:hover { transform: scale(1.15); }
.note-color-swatch--active { border-color: var(--color-text-primary); transform: scale(1.1); }
+/* --------------------------------------------------------
+ * Formatierungs-Toolbar im Notiz-Editor
+ * -------------------------------------------------------- */
+.note-format-toolbar {
+ display: flex;
+ gap: var(--space-1);
+ padding: var(--space-1) var(--space-2);
+ border: 1.5px solid var(--color-border);
+ border-bottom: none;
+ border-radius: var(--radius-sm) var(--radius-sm) 0 0;
+ background-color: var(--color-surface-2);
+}
+
+.note-format-toolbar + .form-input {
+ border-top-left-radius: 0;
+ border-top-right-radius: 0;
+}
+
+.note-format-btn {
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ width: 32px;
+ height: 32px;
+ border: none;
+ border-radius: var(--radius-xs);
+ background: transparent;
+ color: var(--color-text-secondary);
+ cursor: pointer;
+ transition: background-color var(--transition-fast), color var(--transition-fast);
+ font-size: var(--text-sm);
+ padding: 0;
+}
+
+.note-format-btn:hover {
+ background-color: var(--color-accent-light);
+ color: var(--color-accent);
+}
+
+.note-format-btn--sep {
+ width: 1px;
+ background-color: var(--color-border);
+ margin: var(--space-1) var(--space-1);
+ cursor: default;
+}
+
+.note-format-btn--sep:hover {
+ background-color: var(--color-border);
+ color: var(--color-text-secondary);
+}
+
diff --git a/public/sw.js b/public/sw.js
index 61d33b1..68b36d6 100644
--- a/public/sw.js
+++ b/public/sw.js
@@ -12,9 +12,9 @@
* API: Immer Netzwerk (kein Caching von Nutzerdaten)
*/
-const SHELL_CACHE = 'oikos-shell-v17';
-const PAGES_CACHE = 'oikos-pages-v17';
-const ASSETS_CACHE = 'oikos-assets-v17';
+const SHELL_CACHE = 'oikos-shell-v18';
+const PAGES_CACHE = 'oikos-pages-v18';
+const ASSETS_CACHE = 'oikos-assets-v18';
const ALL_CACHES = [SHELL_CACHE, PAGES_CACHE, ASSETS_CACHE];
// App-Shell: sofort benötigt für ersten Render