diff --git a/apps/client/package.json b/apps/client/package.json
index b2abba919..0864031a0 100644
--- a/apps/client/package.json
+++ b/apps/client/package.json
@@ -40,7 +40,7 @@
"debounce": "2.2.0",
"draggabilly": "3.0.0",
"force-graph": "1.51.0",
- "globals": "16.3.0",
+ "globals": "16.4.0",
"i18next": "25.5.2",
"i18next-http-backend": "3.0.2",
"jquery": "3.7.1",
@@ -71,7 +71,7 @@
"@types/leaflet": "1.9.20",
"@types/leaflet-gpx": "1.3.8",
"@types/mark.js": "8.11.12",
- "@types/tabulator-tables": "6.2.10",
+ "@types/tabulator-tables": "6.2.11",
"copy-webpack-plugin": "13.0.1",
"happy-dom": "18.0.1",
"script-loader": "0.7.2",
diff --git a/apps/client/src/stylesheets/style.css b/apps/client/src/stylesheets/style.css
index dae60802b..deca1440d 100644
--- a/apps/client/src/stylesheets/style.css
+++ b/apps/client/src/stylesheets/style.css
@@ -161,7 +161,8 @@ textarea,
color: var(--muted-text-color);
}
-.form-group.disabled {
+.form-group.disabled,
+.form-checkbox.disabled {
opacity: 0.5;
pointer-events: none;
}
diff --git a/apps/client/src/translations/cn/translation.json b/apps/client/src/translations/cn/translation.json
index 0045d43b2..caf3f1bfa 100644
--- a/apps/client/src/translations/cn/translation.json
+++ b/apps/client/src/translations/cn/translation.json
@@ -276,7 +276,12 @@
"mime": "MIME 类型: ",
"file_size": "文件大小:",
"preview": "预览:",
- "preview_not_available": "无法预览此类型的笔记。"
+ "preview_not_available": "无法预览此类型的笔记。",
+ "diff_on": "显示差异",
+ "diff_off": "显示内容",
+ "diff_on_hint": "点击以显示笔记源代码差异",
+ "diff_off_hint": "点击以显示笔记内容",
+ "diff_not_available": "差异不可用。"
},
"sort_child_notes": {
"sort_children_by": "按...排序子笔记",
@@ -2021,6 +2026,8 @@
"title": "性能",
"enable-motion": "启用过渡和动画",
"enable-shadows": "启用阴影",
- "enable-backdrop-effects": "启用菜单、弹窗和面板的背景效果"
+ "enable-backdrop-effects": "启用菜单、弹窗和面板的背景效果",
+ "enable-smooth-scroll": "启用平滑滚动",
+ "app-restart-required": "(需重启程序以应用更改)"
}
}
diff --git a/apps/client/src/translations/cs/translation.json b/apps/client/src/translations/cs/translation.json
new file mode 100644
index 000000000..0967ef424
--- /dev/null
+++ b/apps/client/src/translations/cs/translation.json
@@ -0,0 +1 @@
+{}
diff --git a/apps/client/src/translations/de/translation.json b/apps/client/src/translations/de/translation.json
index 57b4dc1a6..f8b097b55 100644
--- a/apps/client/src/translations/de/translation.json
+++ b/apps/client/src/translations/de/translation.json
@@ -276,7 +276,12 @@
"preview": "Vorschau:",
"preview_not_available": "Für diesen Notiztyp ist keine Vorschau verfügbar.",
"restore_button": "Wiederherstellen",
- "delete_button": "Löschen"
+ "delete_button": "Löschen",
+ "diff_on": "Zeige Differenz",
+ "diff_off": "Zeige Inhalt",
+ "diff_on_hint": "Klicke, um die Differenz des Notiz-Quellcodes zu zeigen",
+ "diff_off_hint": "Klicke, um den Notizinhalt zu zeigen",
+ "diff_not_available": "Differenz-Abgleich ist nicht verfügbar."
},
"sort_child_notes": {
"sort_children_by": "Unternotizen sortieren nach...",
@@ -1839,7 +1844,9 @@
"title": "Leistung",
"enable-motion": "Aktiviere Übergänge und Animationen",
"enable-shadows": "Aktiviere Schatten",
- "enable-backdrop-effects": "Aktiviere Hintergrundeffekte für Menüs, Pop-up Fenster und Panele"
+ "enable-backdrop-effects": "Aktiviere Hintergrundeffekte für Menüs, Pop-up Fenster und Panele",
+ "enable-smooth-scroll": "Aktiviere sanftes Scrollen",
+ "app-restart-required": "(Ein Neustart der Anwendung ist erforderlich, damit die Änderungen wirksam werden)"
},
"code-editor-options": {
"title": "Editor"
diff --git a/apps/client/src/translations/it/translation.json b/apps/client/src/translations/it/translation.json
index f83602521..08f00c755 100644
--- a/apps/client/src/translations/it/translation.json
+++ b/apps/client/src/translations/it/translation.json
@@ -63,7 +63,7 @@
"search_for_note_by_its_name": "cerca una nota per nome",
"cloned_note_prefix_title": "Le note clonate saranno mostrate nell'albero delle note con il dato prefisso",
"prefix_optional": "Prefisso (opzionale)",
- "clone_to_selected_note": "Clona sotto la nota selezionata invio",
+ "clone_to_selected_note": "Clona verso la nota selezionata invio",
"no_path_to_clone_to": "Nessun percorso per clonare dentro.",
"note_cloned": "La nota \"{{clonedTitle}}\" è stata clonata in \"{{targetTitle}}\""
},
@@ -79,7 +79,7 @@
"ok": "OK",
"close": "Chiudi",
"delete_notes_preview": "Anteprima di eliminazione delle note",
- "delete_all_clones_description": "Elimina anche tutti i cloni (può essere disfatto tramite i cambiamenti recenti)",
+ "delete_all_clones_description": "Elimina anche tutti i cloni (può essere ripristinato nella sezione cambiamenti recenti)",
"erase_notes_description": "L'eliminazione normale (soft) marca le note come eliminate e potranno essere recuperate entro un certo lasso di tempo (dalla finestra dei cambiamenti recenti). Selezionando questa opzione le note si elimineranno immediatamente e non sarà possibile recuperarle.",
"erase_notes_warning": "Elimina le note in modo permanente (non potrà essere disfatto), compresi tutti i cloni. Ciò forzerà un nuovo caricamento dell'applicazione.",
"cancel": "Annulla",
@@ -105,7 +105,10 @@
"format_html": "HTML - raccomandato in quanto mantiene tutti i formati",
"format_html_zip": "HTML in archivio ZIP - questo è raccomandato in quanto conserva tutta la formattazione.",
"format_markdown": "MArkdown - questo conserva la maggior parte della formattazione.",
- "export_type_single": "Solo questa nota, senza le sottostanti"
+ "export_type_single": "Solo questa nota, senza le sottostanti",
+ "format_opml": "OPML - formato per scambio informazioni outline. Formattazione, immagini e files non sono inclusi.",
+ "opml_version_1": "OPML v.1.0 - solo testo semplice",
+ "opml_version_2": "OPML v2.0 - supporta anche HTML"
},
"password_not_set": {
"body1": "Le note protette sono crittografate utilizzando una password utente, ma la password non è stata ancora impostata.",
diff --git a/apps/client/src/translations/nl/translation.json b/apps/client/src/translations/nl/translation.json
index 14e853dd6..9b84d90e9 100644
--- a/apps/client/src/translations/nl/translation.json
+++ b/apps/client/src/translations/nl/translation.json
@@ -4,6 +4,64 @@
"homepage": "Homepagina:",
"app_version": "App versie:",
"db_version": "DB Versie:",
- "sync_version": "Sync Versie:"
+ "sync_version": "Sync Versie:",
+ "build_date": "Build datum:",
+ "build_revision": "Build revisie:",
+ "data_directory": "Gegevensmap:"
+ },
+ "toast": {
+ "critical-error": {
+ "title": "Kritische Error"
+ }
+ },
+ "add_link": {
+ "add_link": "Voeg link toe",
+ "help_on_links": "Hulp bij links",
+ "note": "notitie",
+ "search_note": "zoek voor notitie op naam",
+ "link_title_mirrors": "De link titel is hetzelfde als de notitie's huidige titel",
+ "link_title": "Link titel",
+ "button_add_link": "Link toevoegen"
+ },
+ "branch_prefix": {
+ "edit_branch_prefix": "Bewerk branch prefix",
+ "save": "Opslaan",
+ "branch_prefix_saved": "Branch prefix is opgeslagen."
+ },
+ "bulk_actions": {
+ "bulk_actions": "Bulk acties",
+ "affected_notes": "Getroffen notities",
+ "available_actions": "Beschikbare acties",
+ "chosen_actions": "Kies acties",
+ "execute_bulk_actions": "Bulk acties uitvoeren",
+ "bulk_actions_executed": "Bulk acties zijn succesvol uitgevoerd.",
+ "none_yet": "Nog niks... voeg een actie toe door een van de beschikbare bovenstaande opties te klikken.",
+ "labels": "Labels",
+ "relations": "Relaties",
+ "notes": "Notities",
+ "other": "Andere"
+ },
+ "calendar": {
+ "april": "April",
+ "may": "Mei",
+ "june": "Juni",
+ "july": "Juli",
+ "august": "Augustus",
+ "september": "September",
+ "october": "Oktober",
+ "november": "November",
+ "december": "December"
+ },
+ "close_pane_button": {
+ "close_this_pane": "Sluit dit paneel"
+ },
+ "create_pane_button": {
+ "create_new_split": "Maak nieuwe split"
+ },
+ "edit_button": {
+ "edit_this_note": "Notitie bewerken"
+ },
+ "show_toc_widget_button": {
+ "show_toc": "Laat Inhoudsopgave zien"
}
}
diff --git a/apps/client/src/translations/ro/translation.json b/apps/client/src/translations/ro/translation.json
index 69dc904b9..9d9b824b9 100644
--- a/apps/client/src/translations/ro/translation.json
+++ b/apps/client/src/translations/ro/translation.json
@@ -267,7 +267,8 @@
"basic_properties": "Proprietăți de bază",
"editable": "Editabil",
"note_type": "Tipul notiței",
- "language": "Limbă"
+ "language": "Limbă",
+ "configure_code_notes": "Configurează notițele de tip cod..."
},
"book": {
"no_children_help": "Această notiță de tip Carte nu are nicio subnotiță așadar nu este nimic de afișat. Vedeți wiki pentru detalii."
@@ -1070,7 +1071,12 @@
"revisions_deleted": "Notița reviziei a fost ștearsă.",
"maximum_revisions": "Numărul maxim de revizii pentru notița curentă: {{number}}.",
"settings": "Setări revizii ale notițelor",
- "snapshot_interval": "Intervalul de creare a reviziilor pentru notițe: {{seconds}}s."
+ "snapshot_interval": "Intervalul de creare a reviziilor pentru notițe: {{seconds}}s.",
+ "diff_on": "Evidențiază diferențele",
+ "diff_off": "Afișează conținutul",
+ "diff_on_hint": "Clic pentru a afișa diferențele față de revizia anterioară, la nivel de cod sursă",
+ "diff_off_hint": "Clic pentru a afișa întregul conținut al reviziei",
+ "diff_not_available": "Diferențele nu pot fi evidențiate."
},
"revisions_button": {
"note_revisions": "Revizii ale notiței"
@@ -1373,8 +1379,8 @@
},
"shared_info": {
"help_link": "Pentru informații vizitați wiki-ul.",
- "shared_locally": "Această notiță este partajată local la {{- link}}",
- "shared_publicly": "Această notiță este partajată public la {{- link}}"
+ "shared_locally": "Această notiță este partajată local la {{- link}}.",
+ "shared_publicly": "Această notiță este partajată public la {{- link}}."
},
"note_types": {
"book": "Colecție",
@@ -1472,7 +1478,8 @@
"create-child-note": "Crează subnotiță",
"hoist-this-note-workspace": "Focalizează spațiul de lucru",
"refresh-saved-search-results": "Reîmprospătează căutarea salvată",
- "unhoist": "Defocalizează notița"
+ "unhoist": "Defocalizează notița",
+ "toggle-sidebar": "Comută bara laterală"
},
"title_bar_buttons": {
"window-on-top": "Menține fereastra mereu vizibilă"
diff --git a/apps/client/src/translations/ru/translation.json b/apps/client/src/translations/ru/translation.json
index 23ea17730..1c5dd7cba 100644
--- a/apps/client/src/translations/ru/translation.json
+++ b/apps/client/src/translations/ru/translation.json
@@ -379,7 +379,12 @@
"settings": "Настройка версионирования заметок",
"no_revisions": "У этой заметки еще нет версий...",
"snapshot_interval": "Интервал создания версии заметки: {{seconds}} с.",
- "maximum_revisions": "Максимальное количество версий заметки: {{number}}."
+ "maximum_revisions": "Максимальное количество версий заметки: {{number}}.",
+ "diff_on": "Сравнить",
+ "diff_off": "Показать содержимое",
+ "diff_on_hint": "Отобразить сравнение исходного кода заметки",
+ "diff_off_hint": "Отобразить контент заметки",
+ "diff_not_available": "Сравнение недоступно."
},
"sort_child_notes": {
"sort_children_by": "Сортировать дочерние заметки по...",
@@ -2025,6 +2030,8 @@
"title": "Производительность",
"enable-motion": "Включить визуальные эффекты и анимации",
"enable-shadows": "Включить тени",
- "enable-backdrop-effects": "Включить эффекты размытия фона меню, всплывающих окон и панелей"
+ "enable-backdrop-effects": "Включить эффекты размытия фона меню, всплывающих окон и панелей",
+ "enable-smooth-scroll": "Включить плавную прокрутку",
+ "app-restart-required": "(для вступления изменений в силу требуется перезапуск приложения)"
}
}
diff --git a/apps/client/src/translations/tw/translation.json b/apps/client/src/translations/tw/translation.json
index 4f29a48b5..3c19ae4ae 100644
--- a/apps/client/src/translations/tw/translation.json
+++ b/apps/client/src/translations/tw/translation.json
@@ -276,7 +276,12 @@
"preview": "預覽:",
"preview_not_available": "無法預覽此類型的筆記。",
"restore_button": "還原",
- "delete_button": "刪除"
+ "delete_button": "刪除",
+ "diff_on": "顯示差異",
+ "diff_off": "顯示內容",
+ "diff_on_hint": "點擊以顯示筆記原始碼差異",
+ "diff_off_hint": "點擊以顯示筆記內容",
+ "diff_not_available": "差異不可用。"
},
"sort_child_notes": {
"sort_children_by": "依…排序子筆記",
@@ -2021,6 +2026,8 @@
"title": "效能",
"enable-motion": "啟用轉場與動畫",
"enable-shadows": "啟用陰影",
- "enable-backdrop-effects": "啟用選單、彈出視窗和面板的背景特效"
+ "enable-backdrop-effects": "啟用選單、彈出視窗和面板的背景特效",
+ "enable-smooth-scroll": "啟用平滑滾動",
+ "app-restart-required": "(需要重啟程式以套用更改)"
}
}
diff --git a/apps/client/src/translations/uk/translation.json b/apps/client/src/translations/uk/translation.json
index 65c3dcea0..c7fe5c2fc 100644
--- a/apps/client/src/translations/uk/translation.json
+++ b/apps/client/src/translations/uk/translation.json
@@ -326,7 +326,12 @@
"mime": "МІМЕ: ",
"file_size": "Розмір файлу:",
"preview": "Попередній перегляд:",
- "preview_not_available": "Попередній перегляд недоступний для цього типу нотатки."
+ "preview_not_available": "Попередній перегляд недоступний для цього типу нотатки.",
+ "diff_on": "Показати різницю",
+ "diff_off": "Показати вміст",
+ "diff_on_hint": "Натисніть, щоб показати різницю в джерелі нотатки",
+ "diff_off_hint": "Натисніть, щоб показати вміст нотатки",
+ "diff_not_available": "Різниця недоступна."
},
"include_note": {
"dialog_title": "Включити нотатку",
@@ -2025,6 +2030,8 @@
"title": "Продуктивність",
"enable-motion": "Увімкнути переходи та анімацію",
"enable-shadows": "Увімкнути тіні",
- "enable-backdrop-effects": "Увімкнути фонові ефекти для меню, спливаючих вікон та панелей"
+ "enable-backdrop-effects": "Увімкнути фонові ефекти для меню, спливаючих вікон та панелей",
+ "enable-smooth-scroll": "Увімкнути плавне прокручування",
+ "app-restart-required": "(щоб зміни набули чинності, потрібен перезапуск програми)"
}
}
diff --git a/apps/client/src/widgets/dialogs/import.tsx b/apps/client/src/widgets/dialogs/import.tsx
index 58f28dd54..a54a01573 100644
--- a/apps/client/src/widgets/dialogs/import.tsx
+++ b/apps/client/src/widgets/dialogs/import.tsx
@@ -8,15 +8,16 @@ import FormGroup, { FormMultiGroup } from "../react/FormGroup";
import Modal from "../react/Modal";
import RawHtml from "../react/RawHtml";
import importService, { UploadFilesOptions } from "../../services/import";
-import { useTriliumEvent } from "../react/hooks";
+import { useTriliumEvent, useTriliumOptionBool } from "../react/hooks";
export default function ImportDialog() {
+ const [ compressImages ] = useTriliumOptionBool("compressImages");
const [ parentNoteId, setParentNoteId ] = useState();
const [ noteTitle, setNoteTitle ] = useState();
const [ files, setFiles ] = useState(null);
const [ safeImport, setSafeImport ] = useState(true);
const [ explodeArchives, setExplodeArchives ] = useState(true);
- const [ shrinkImages, setShrinkImages ] = useState(true);
+ const [ shrinkImages, setShrinkImages ] = useState(compressImages);
const [ textImportedAsText, setTextImportedAsText ] = useState(true);
const [ codeImportedAsCode, setCodeImportedAsCode ] = useState(true);
const [ replaceUnderscoresWithSpaces, setReplaceUnderscoresWithSpaces ] = useState(true);
@@ -69,7 +70,8 @@ export default function ImportDialog() {
/>
}
show={shown}
@@ -69,13 +69,12 @@ export default function IncludeNoteDialog() {
)
}
-async function includeNote(notePath: string, textTypeWidget: EditableTextTypeWidget) {
+async function includeNote(notePath: string, textTypeWidget: EditableTextTypeWidget, boxSize: BoxSize) {
const noteId = tree.getNoteIdFromUrl(notePath);
if (!noteId) {
return;
}
const note = await froca.getNote(noteId);
- const boxSize = $("input[name='include-note-box-size']:checked").val() as string;
if (["image", "canvas", "mermaid"].includes(note?.type ?? "")) {
// there's no benefit to use insert note functionlity for images,
diff --git a/apps/client/src/widgets/note_tree.ts b/apps/client/src/widgets/note_tree.ts
index 248bf0a3a..2bbee7b36 100644
--- a/apps/client/src/widgets/note_tree.ts
+++ b/apps/client/src/widgets/note_tree.ts
@@ -219,21 +219,22 @@ export default class NoteTreeWidget extends NoteContextAwareWidget {
this.$tree = this.$widget.find(".tree");
this.$treeActions = this.$widget.find(".tree-actions");
- this.$tree.on("mousedown", ".unhoist-button", () => hoistedNoteService.unhoist());
- this.$tree.on("mousedown", ".refresh-search-button", (e) => this.refreshSearch(e));
- this.$tree.on("mousedown", ".add-note-button", (e) => {
- const node = $.ui.fancytree.getNode(e as unknown as Event);
- const parentNotePath = treeService.getNotePath(node);
+ this.$tree.on("mousedown", (e: JQuery.MouseDownEvent) => {
+ const target = e.target as HTMLElement;
+ if (e.button !== 0) return;
- noteCreateService.createNote(parentNotePath, {
- isProtected: node.data.isProtected
- });
- });
-
- this.$tree.on("mousedown", ".enter-workspace-button", (e) => {
- const node = $.ui.fancytree.getNode(e as unknown as Event);
-
- this.triggerCommand("hoistNote", { noteId: node.data.noteId });
+ if (target.classList.contains("unhoist-button")) {
+ hoistedNoteService.unhoist();
+ } else if (target.classList.contains("refresh-search-button")) {
+ this.refreshSearch(e);
+ } else if (target.classList.contains("add-note-button")) {
+ const node = $.ui.fancytree.getNode(e as unknown as Event);
+ const parentNotePath = treeService.getNotePath(node);
+ noteCreateService.createNote(parentNotePath, { isProtected: node.data.isProtected });
+ } else if (target.classList.contains("enter-workspace-button")) {
+ const node = $.ui.fancytree.getNode(e as unknown as Event);
+ this.triggerCommand("hoistNote", { noteId: node.data.noteId });
+ }
});
// fancytree doesn't support middle click, so this is a way to support it
diff --git a/apps/client/src/widgets/react/FormCheckbox.tsx b/apps/client/src/widgets/react/FormCheckbox.tsx
index 55e0797b3..13a62f631 100644
--- a/apps/client/src/widgets/react/FormCheckbox.tsx
+++ b/apps/client/src/widgets/react/FormCheckbox.tsx
@@ -22,7 +22,6 @@ const FormCheckbox = memo(({ name, disabled, label, currentValue, onChange, hint
const labelRef = useRef(null);
const id = useUniqueName(name);
- // Fix: Move useEffect outside conditional
useEffect(() => {
if (!hint || !labelRef.current) return;
@@ -34,22 +33,19 @@ const FormCheckbox = memo(({ name, disabled, label, currentValue, onChange, hint
return () => tooltipInstance?.dispose();
}, [hint]); // Proper dependency
- // Memoize style object
const labelStyle = useMemo(() =>
hint ? { textDecoration: "underline dotted var(--main-text-color)" } : undefined,
[hint]
);
- // Memoize onChange handler
const handleChange = useCallback((e: Event) => {
onChange((e.target as HTMLInputElement).checked);
}, [onChange]);
- // Memoize title attribute
const titleText = useMemo(() => hint ? escapeQuotes(hint) : undefined, [hint]);
return (
-