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 ( -
+