diff --git a/frontend/app.js b/frontend/app.js
index a70d0a9..c5a3713 100644
--- a/frontend/app.js
+++ b/frontend/app.js
@@ -19,6 +19,9 @@ const CONFIG = {
TOAST_DURATION_SUCCESS_MS: 3500,
};
+/** Heroicons outline "share" (same d= as shared-note icon in the file tree) */
+const SHARE_ICON_PATH = 'M8.684 13.342C8.886 12.938 9 12.482 9 12c0-.482-.114-.938-.316-1.342m0 2.684a3 3 0 110-2.684m0 2.684l6.632 3.316m-6.632-6l6.632-3.316m0 0a3 3 0 105.367-2.684 3 3 0 00-5.367 2.684zm0 9.316a3 3 0 105.368 2.684 3 3 0 00-5.368-2.684z';
+
// localStorage settings configuration - centralized definition of all persisted settings
const LOCAL_SETTINGS = {
// Boolean settings
@@ -231,7 +234,7 @@ function noteApp() {
sortMode: localStorage.getItem('sortMode') || 'a-z',
// Icon rail / panel state
- activePanel: 'files', // 'files', 'search', 'tags', 'settings'
+ activePanel: 'files', // 'files', 'search', 'tags', 'outline', 'backlinks', 'shared', 'settings'
// Folder state
folderTree: [],
@@ -329,6 +332,7 @@ function noteApp() {
showShareQR: false,
shareLinkCopied: false,
_sharedNotePaths: new Set(), // O(1) lookup for shared note indicators
+ _sharedNotePathsList: [], // sorted paths, mirrors Set for reactive sidebar panel
// Quick Switcher state (Ctrl+Alt+P)
showQuickSwitcher: false,
@@ -2237,7 +2241,7 @@ function noteApp() {
// Share icon for shared notes
const isShared = !isMediaFile && this.isNoteShared(note.path);
- const shareIcon = isShared ? '' : '';
+ const shareIcon = isShared ? `` : '';
const icon = this.getMediaIcon(note.type);
const deleteTitle = !isMediaFile
? this.t('toolbar.delete_note')
@@ -6111,19 +6115,38 @@ function noteApp() {
// Share Functions
// ============================================================================
- // Load list of shared note paths (for visual indicators)
+ // Load list of shared note paths (for visual indicators and Shared sidebar panel)
async loadSharedNotePaths() {
try {
const response = await fetch('/api/shared-notes');
if (response.ok) {
const data = await response.json();
this._sharedNotePaths = new Set(data.paths || []);
+ this._syncSharedNotePathsList();
}
} catch (error) {
console.error('Failed to load shared note paths:', error);
this._sharedNotePaths = new Set();
+ this._sharedNotePathsList = [];
}
},
+
+ _syncSharedNotePathsList() {
+ this._sharedNotePathsList = [...this._sharedNotePaths].sort((a, b) =>
+ a.localeCompare(b, undefined, { sensitivity: 'base' })
+ );
+ },
+
+ /** Display rows for Shared notes panel: name + folder line (search-style) */
+ getSharedPanelItems() {
+ return this._sharedNotePathsList.map((path) => {
+ const noMd = path.replace(/\.md$/i, '');
+ const last = Math.max(noMd.lastIndexOf('/'), noMd.lastIndexOf('\\'));
+ const name = last < 0 ? noMd : noMd.slice(last + 1);
+ const folder = last < 0 ? '' : noMd.slice(0, last).replace(/\\/g, '/');
+ return { path, name, folder: folder || 'Root' };
+ });
+ },
// Check if a note is currently shared (O(1) lookup)
isNoteShared(notePath) {
@@ -6284,6 +6307,7 @@ function noteApp() {
this.shareInfo.shared = true;
// Update the shared paths set
this._sharedNotePaths.add(this.currentNote);
+ this._syncSharedNotePathsList();
} else {
const error = await response.json();
this.toast(this.t('share.error_creating', { error: error.detail || 'Unknown error' }), { type: 'error' });
@@ -6342,6 +6366,7 @@ function noteApp() {
this.shareInfo = { shared: false };
// Update the shared paths set
this._sharedNotePaths.delete(this.currentNote);
+ this._syncSharedNotePathsList();
} else {
const error = await response.json();
this.toast(this.t('share.error_revoking', { error: error.detail || 'Unknown error' }), { type: 'error' });
diff --git a/frontend/index.html b/frontend/index.html
index ee2a0eb..91c3107 100644
--- a/frontend/index.html
+++ b/frontend/index.html
@@ -1521,6 +1521,26 @@
x-text="backlinks.length > 9 ? '9+' : backlinks.length"
>
+
+
+
@@ -1992,6 +2012,48 @@
+
+
+
+
diff --git a/locales/de-DE.json b/locales/de-DE.json
index cbf3532..aa1ef95 100644
--- a/locales/de-DE.json
+++ b/locales/de-DE.json
@@ -142,7 +142,9 @@
"error_creating": "Fehler beim Erstellen des Freigabelinks: {{error}}",
"error_revoking": "Fehler beim Widerrufen des Freigabelinks: {{error}}",
"show_qr": "QR-Code anzeigen",
- "hide_qr": "QR-Code ausblenden"
+ "hide_qr": "QR-Code ausblenden",
+ "panel_title": "Geteilt",
+ "no_shared": "Keine geteilten Notizen"
},
"quick_switcher": {
"placeholder": "Notizen suchen...",
diff --git a/locales/en-GB.json b/locales/en-GB.json
index 7b28b53..e8560e7 100644
--- a/locales/en-GB.json
+++ b/locales/en-GB.json
@@ -141,7 +141,9 @@
"error_creating": "Failed to create share link: {{error}}",
"error_revoking": "Failed to revoke share link: {{error}}",
"show_qr": "Show QR Code",
- "hide_qr": "Hide QR Code"
+ "hide_qr": "Hide QR Code",
+ "panel_title": "Shared",
+ "no_shared": "No shared notes"
},
"quick_switcher": {
"placeholder": "Type to search notes...",
diff --git a/locales/en-US.json b/locales/en-US.json
index 1c96289..8332fc7 100644
--- a/locales/en-US.json
+++ b/locales/en-US.json
@@ -142,7 +142,9 @@
"error_creating": "Failed to create share link: {{error}}",
"error_revoking": "Failed to revoke share link: {{error}}",
"show_qr": "Show QR Code",
- "hide_qr": "Hide QR Code"
+ "hide_qr": "Hide QR Code",
+ "panel_title": "Shared",
+ "no_shared": "No shared notes"
},
"quick_switcher": {
"placeholder": "Type to search notes...",
diff --git a/locales/es-ES.json b/locales/es-ES.json
index 75c4633..d61bb56 100644
--- a/locales/es-ES.json
+++ b/locales/es-ES.json
@@ -142,7 +142,9 @@
"error_creating": "Error al crear el enlace: {{error}}",
"error_revoking": "Error al revocar el enlace: {{error}}",
"show_qr": "Mostrar código QR",
- "hide_qr": "Ocultar código QR"
+ "hide_qr": "Ocultar código QR",
+ "panel_title": "Compartidas",
+ "no_shared": "No hay notas compartidas"
},
"quick_switcher": {
"placeholder": "Escribe para buscar notas...",
diff --git a/locales/fr-FR.json b/locales/fr-FR.json
index a7773a0..cdc9493 100644
--- a/locales/fr-FR.json
+++ b/locales/fr-FR.json
@@ -142,7 +142,9 @@
"error_creating": "Échec de la création du lien : {{error}}",
"error_revoking": "Échec de la révocation du lien : {{error}}",
"show_qr": "Afficher le code QR",
- "hide_qr": "Masquer le code QR"
+ "hide_qr": "Masquer le code QR",
+ "panel_title": "Partagées",
+ "no_shared": "Aucune note partagée"
},
"quick_switcher": {
"placeholder": "Rechercher des notes...",
diff --git a/locales/hu-HU.json b/locales/hu-HU.json
index 225b462..ebe18ae 100644
--- a/locales/hu-HU.json
+++ b/locales/hu-HU.json
@@ -142,7 +142,9 @@
"error_creating": "Hiba történt a megosztási link létrehozásánál: {{error}}",
"error_revoking": "Nemsikerült visszavonni a megosztási linket: {{error}}",
"show_qr": "QR-Kód Megjelenítése",
- "hide_qr": "QR-Kód Elrejtése"
+ "hide_qr": "QR-Kód Elrejtése",
+ "panel_title": "Megosztott",
+ "no_shared": "Nincs megosztott jegyzet"
},
"quick_switcher": {
"placeholder": "Írj a jegyzetek kereséséhez...",
diff --git a/locales/it-IT.json b/locales/it-IT.json
index d908e52..04152e7 100644
--- a/locales/it-IT.json
+++ b/locales/it-IT.json
@@ -141,7 +141,9 @@
"error_creating": "Impossibile creare il link: {{error}}",
"error_revoking": "Impossibile revocare il link: {{error}}",
"show_qr": "Mostra codice QR",
- "hide_qr": "Nascondi codice QR"
+ "hide_qr": "Nascondi codice QR",
+ "panel_title": "Condivise",
+ "no_shared": "Nessuna nota condivisa"
},
"quick_switcher": {
"placeholder": "Cerca note...",
diff --git a/locales/ja-JP.json b/locales/ja-JP.json
index 69dce4f..4868469 100644
--- a/locales/ja-JP.json
+++ b/locales/ja-JP.json
@@ -141,7 +141,9 @@
"error_creating": "共有リンクの作成に失敗しました: {{error}}",
"error_revoking": "共有リンクの取り消しに失敗しました: {{error}}",
"show_qr": "QRコードを表示",
- "hide_qr": "QRコードを非表示"
+ "hide_qr": "QRコードを非表示",
+ "panel_title": "共有",
+ "no_shared": "共有中のノートはありません"
},
"quick_switcher": {
"placeholder": "ノートを検索...",
diff --git a/locales/ru-RU.json b/locales/ru-RU.json
index ee73cee..affab82 100644
--- a/locales/ru-RU.json
+++ b/locales/ru-RU.json
@@ -141,7 +141,9 @@
"error_creating": "Не удалось создать ссылку: {{error}}",
"error_revoking": "Не удалось отозвать ссылку: {{error}}",
"show_qr": "Показать QR-код",
- "hide_qr": "Скрыть QR-код"
+ "hide_qr": "Скрыть QR-код",
+ "panel_title": "Опубликовано",
+ "no_shared": "Нет опубликованных заметок"
},
"quick_switcher": {
"placeholder": "Поиск заметок...",
diff --git a/locales/sl-SI.json b/locales/sl-SI.json
index 24668b6..2c2ae1a 100644
--- a/locales/sl-SI.json
+++ b/locales/sl-SI.json
@@ -141,7 +141,9 @@
"error_creating": "Napaka pri ustvarjanju povezave: {{error}}",
"error_revoking": "Napaka pri preklicu povezave: {{error}}",
"show_qr": "Prikaži QR kodo",
- "hide_qr": "Skrij QR kodo"
+ "hide_qr": "Skrij QR kodo",
+ "panel_title": "V skupni rabi",
+ "no_shared": "Ni deljenih zapisov"
},
"quick_switcher": {
"placeholder": "Išči beležke...",
diff --git a/locales/zh-CN.json b/locales/zh-CN.json
index 03f667f..ac7f7cf 100644
--- a/locales/zh-CN.json
+++ b/locales/zh-CN.json
@@ -141,7 +141,9 @@
"error_creating": "创建分享链接失败:{{error}}",
"error_revoking": "撤销分享链接失败:{{error}}",
"show_qr": "显示二维码",
- "hide_qr": "隐藏二维码"
+ "hide_qr": "隐藏二维码",
+ "panel_title": "已分享",
+ "no_shared": "暂无已分享的笔记"
},
"quick_switcher": {
"placeholder": "搜索笔记...",