From 030582b2d5bc9f5db94810c3da79d0ad53e5d59c Mon Sep 17 00:00:00 2001 From: Elian Doran Date: Sun, 30 Nov 2025 19:14:21 +0200 Subject: [PATCH 1/5] feat(i18n): add English (United Kingdom) --- apps/client/src/widgets/collections/calendar/index.tsx | 1 + apps/client/src/widgets/type_widgets/MindMap.tsx | 1 + apps/client/src/widgets/type_widgets/canvas/i18n.spec.ts | 1 + apps/client/src/widgets/type_widgets/canvas/i18n.ts | 4 +++- apps/server/src/services/i18n.ts | 2 ++ packages/ckeditor5/src/i18n.ts | 5 +++++ packages/commons/src/lib/i18n.ts | 1 + 7 files changed, 14 insertions(+), 1 deletion(-) diff --git a/apps/client/src/widgets/collections/calendar/index.tsx b/apps/client/src/widgets/collections/calendar/index.tsx index bac6862b2..8bf5ce7f9 100644 --- a/apps/client/src/widgets/collections/calendar/index.tsx +++ b/apps/client/src/widgets/collections/calendar/index.tsx @@ -77,6 +77,7 @@ export const LOCALE_MAPPINGS: Record Promise<{ de "pt_br": () => import("@fullcalendar/core/locales/pt-br"), uk: () => import("@fullcalendar/core/locales/uk"), en: null, + "en-GB": () => import("@fullcalendar/core/locales/en-gb"), "en_rtl": null, ar: () => import("@fullcalendar/core/locales/ar") }; diff --git a/apps/client/src/widgets/type_widgets/MindMap.tsx b/apps/client/src/widgets/type_widgets/MindMap.tsx index eb54170c3..f8409c75c 100644 --- a/apps/client/src/widgets/type_widgets/MindMap.tsx +++ b/apps/client/src/widgets/type_widgets/MindMap.tsx @@ -28,6 +28,7 @@ const LOCALE_MAPPINGS: Record de: null, en: "en", en_rtl: "en", + "en-GB": "en", es: "es", fr: "fr", it: "it", diff --git a/apps/client/src/widgets/type_widgets/canvas/i18n.spec.ts b/apps/client/src/widgets/type_widgets/canvas/i18n.spec.ts index 71eb3d18c..c77e4979d 100644 --- a/apps/client/src/widgets/type_widgets/canvas/i18n.spec.ts +++ b/apps/client/src/widgets/type_widgets/canvas/i18n.spec.ts @@ -22,6 +22,7 @@ describe("Canvas i18n", () => { if (locale.contentOnly || locale.devOnly) continue; const languageCode = LANGUAGE_MAPPINGS[locale.id]; if (!supportedLanguageCodes.has(languageCode)) { + console.log("Supported locales:", Array.from(supportedLanguageCodes.values()).join(", ")); expect.fail(`Unable to find locale for ${locale.id} -> ${languageCode}.`) } } diff --git a/apps/client/src/widgets/type_widgets/canvas/i18n.ts b/apps/client/src/widgets/type_widgets/canvas/i18n.ts index 43ee724cf..47324abfc 100644 --- a/apps/client/src/widgets/type_widgets/canvas/i18n.ts +++ b/apps/client/src/widgets/type_widgets/canvas/i18n.ts @@ -1,10 +1,12 @@ +import { Language } from "@excalidraw/excalidraw/i18n"; import type { DISPLAYABLE_LOCALE_IDS } from "@triliumnext/commons"; -export const LANGUAGE_MAPPINGS: Record = { +export const LANGUAGE_MAPPINGS: Record = { ar: "ar-SA", cn: "zh-CN", de: "de-DE", en: "en", + "en-GB": "en", en_rtl: "en", es: "es-ES", fr: "fr-FR", diff --git a/apps/server/src/services/i18n.ts b/apps/server/src/services/i18n.ts index be7ebdeb5..82eb6f408 100644 --- a/apps/server/src/services/i18n.ts +++ b/apps/server/src/services/i18n.ts @@ -7,11 +7,13 @@ import hidden_subtree from "./hidden_subtree.js"; import { LOCALES, type Locale, type LOCALE_IDS } from "@triliumnext/commons"; import dayjs, { Dayjs } from "dayjs"; +// When adding a new locale, prefer the version with hyphen instead of underscore. export const DAYJS_LOADER: Record Promise> = { "ar": () => import("dayjs/locale/ar.js"), "cn": () => import("dayjs/locale/zh-cn.js"), "de": () => import("dayjs/locale/de.js"), "en": () => import("dayjs/locale/en.js"), + "en-GB": () => import("dayjs/locale/en-gb.js"), "en_rtl": () => import("dayjs/locale/en.js"), "es": () => import("dayjs/locale/es.js"), "fa": () => import("dayjs/locale/fa.js"), diff --git a/packages/ckeditor5/src/i18n.ts b/packages/ckeditor5/src/i18n.ts index 3053f4b7d..a409fa437 100644 --- a/packages/ckeditor5/src/i18n.ts +++ b/packages/ckeditor5/src/i18n.ts @@ -10,6 +10,11 @@ interface LocaleMapping { const LOCALE_MAPPINGS: Record = { en: null, en_rtl: null, + "en-GB": { + languageCode: "en-GB", + coreTranslation: () => import("ckeditor5/translations/en-gb.js"), + premiumFeaturesTranslation: () => import("ckeditor5-premium-features/translations/en-gb.js"), + }, ar: { languageCode: "ar", coreTranslation: () => import("ckeditor5/translations/ar.js"), diff --git a/packages/commons/src/lib/i18n.ts b/packages/commons/src/lib/i18n.ts index 65ff196d2..8d2bc0232 100644 --- a/packages/commons/src/lib/i18n.ts +++ b/packages/commons/src/lib/i18n.ts @@ -15,6 +15,7 @@ const UNSORTED_LOCALES = [ { id: "cn", name: "简体中文", electronLocale: "zh_CN" }, { id: "de", name: "Deutsch", electronLocale: "de" }, { id: "en", name: "English", electronLocale: "en" }, + { id: "en-GB", name: "English (United Kingdom)", electronLocale: "en_GB" }, { id: "es", name: "Español", electronLocale: "es" }, { id: "fr", name: "Français", electronLocale: "fr" }, { id: "it", name: "Italiano", electronLocale: "it" }, From aacd92eee38b68128fa82c44d96258096bf3412a Mon Sep 17 00:00:00 2001 From: Elian Doran Date: Sun, 30 Nov 2025 19:47:17 +0200 Subject: [PATCH 2/5] chore(popup-editor): implement switch to full editor button --- apps/client/src/translations/en/translation.json | 3 +++ apps/client/src/widgets/dialogs/PopupEditor.tsx | 11 +++++++++-- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/apps/client/src/translations/en/translation.json b/apps/client/src/translations/en/translation.json index 514301594..c1a509944 100644 --- a/apps/client/src/translations/en/translation.json +++ b/apps/client/src/translations/en/translation.json @@ -2107,5 +2107,8 @@ "clear-color": "Clear note color", "set-color": "Set note color", "set-custom-color": "Set custom note color" + }, + "popup-editor": { + "maximize": "Switch to full editor" } } diff --git a/apps/client/src/widgets/dialogs/PopupEditor.tsx b/apps/client/src/widgets/dialogs/PopupEditor.tsx index 0d158f828..c85dcd3b3 100644 --- a/apps/client/src/widgets/dialogs/PopupEditor.tsx +++ b/apps/client/src/widgets/dialogs/PopupEditor.tsx @@ -19,6 +19,8 @@ import tree from "../../services/tree"; import froca from "../../services/froca"; import ReadOnlyNoteInfoBar from "../ReadOnlyNoteInfoBar"; import MobileEditorToolbar from "../type_widgets/text/mobile_editor_toolbar"; +import { t } from "../../services/i18n"; +import appContext from "../../components/app_context"; export default function PopupEditor() { const [ shown, setShown ] = useState(false); @@ -62,8 +64,13 @@ export default function PopupEditor() { title={} customTitleBarButtons={[{ iconClassName: "bx-expand-alt", - title: "Switch to full editor", - onClick: () => {/* TO DO */} + title: t("popup-editor.maximize"), + onClick: async () => { + if (!noteContext.noteId) return; + const { noteId, hoistedNoteId } = noteContext; + await appContext.tabManager.openInNewTab(noteId, hoistedNoteId, true); + setShown(false); + } }]} className="popup-editor-dialog" size="lg" From 7779acc7bcde4aebade6db670d306a1bc1c77711 Mon Sep 17 00:00:00 2001 From: Elian Doran Date: Sun, 30 Nov 2025 19:55:40 +0200 Subject: [PATCH 3/5] refactor(client): split revisions CSS into file --- apps/client/src/stylesheets/style.css | 40 ------------------ apps/client/src/widgets/dialogs/revisions.css | 41 +++++++++++++++++++ apps/client/src/widgets/dialogs/revisions.tsx | 1 + 3 files changed, 42 insertions(+), 40 deletions(-) create mode 100644 apps/client/src/widgets/dialogs/revisions.css diff --git a/apps/client/src/stylesheets/style.css b/apps/client/src/stylesheets/style.css index ea55db041..5db4b1582 100644 --- a/apps/client/src/stylesheets/style.css +++ b/apps/client/src/stylesheets/style.css @@ -1686,46 +1686,6 @@ body:not(.mobile) #launcher-pane.horizontal .dropdown-submenu > .dropdown-menu { body.mobile .modal-dialog.modal-dialog-scrollable { height: unset; } - - body.mobile .revisions-dialog .modal-dialog { - height: 95vh; - } - - body.mobile .revisions-dialog .modal-body { - height: 100% !important; - flex-direction: column; - padding: 0; - } - - body.mobile .revisions-dialog .revision-list { - height: unset; - max-height: 20vh; - border-bottom: 1px solid var(--main-border-color) !important; - padding: 0 1em; - } - - body.mobile .revisions-dialog .modal-body > .revision-content-wrapper { - flex-grow: 1; - height: 100%; - overflow: auto; - margin: 0; - } - - body.mobile .revisions-dialog .modal-body > .revision-content-wrapper > div:first-of-type { - flex-direction: column; - } - - body.mobile .revisions-dialog .revision-title { - font-size: 1rem; - } - - body.mobile .revisions-dialog .revision-title-buttons { - text-align: center; - } - - body.mobile .revisions-dialog .revision-content { - padding: 0.5em; - } } /* Mobile, tablet mode */ diff --git a/apps/client/src/widgets/dialogs/revisions.css b/apps/client/src/widgets/dialogs/revisions.css new file mode 100644 index 000000000..91c3af11c --- /dev/null +++ b/apps/client/src/widgets/dialogs/revisions.css @@ -0,0 +1,41 @@ +body.mobile .revisions-dialog { + .modal-dialog { + height: 95vh; + } + + .modal-body { + height: 100% !important; + flex-direction: column; + padding: 0; + } + + .revision-list { + height: unset; + max-height: 20vh; + border-bottom: 1px solid var(--main-border-color) !important; + padding: 0 1em; + } + + .modal-body > .revision-content-wrapper { + flex-grow: 1; + height: 100%; + overflow: auto; + margin: 0; + } + + .modal-body > .revision-content-wrapper > div:first-of-type { + flex-direction: column; + } + + .revision-title { + font-size: 1rem; + } + + .revision-title-buttons { + text-align: center; + } + + .revision-content { + padding: 0.5em; + } +} \ No newline at end of file diff --git a/apps/client/src/widgets/dialogs/revisions.tsx b/apps/client/src/widgets/dialogs/revisions.tsx index e20c4c978..fd2dd9a16 100644 --- a/apps/client/src/widgets/dialogs/revisions.tsx +++ b/apps/client/src/widgets/dialogs/revisions.tsx @@ -20,6 +20,7 @@ import ActionButton from "../react/ActionButton"; import options from "../../services/options"; import { useTriliumEvent } from "../react/hooks"; import { diffWords } from "diff"; +import "./revisions.css"; export default function RevisionsDialog() { const [ note, setNote ] = useState(); From 5ff77c16abca59a5a65fd8d38ba366c8240ac4a4 Mon Sep 17 00:00:00 2001 From: Elian Doran Date: Sun, 30 Nov 2025 21:13:07 +0200 Subject: [PATCH 4/5] feat(revisions): improve layout on mobile --- apps/client/src/widgets/dialogs/revisions.css | 22 ++++++++++++++++++- apps/client/src/widgets/dialogs/revisions.tsx | 2 +- apps/client/src/widgets/react/FormList.tsx | 6 +++-- 3 files changed, 26 insertions(+), 4 deletions(-) diff --git a/apps/client/src/widgets/dialogs/revisions.css b/apps/client/src/widgets/dialogs/revisions.css index 91c3af11c..5528ac368 100644 --- a/apps/client/src/widgets/dialogs/revisions.css +++ b/apps/client/src/widgets/dialogs/revisions.css @@ -2,15 +2,31 @@ body.mobile .revisions-dialog { .modal-dialog { height: 95vh; } + + .modal-header { + display: flex; + flex-wrap: wrap; + gap: 0.25em; + font-size: 0.9em; + } + + .modal-title { + flex-grow: 1; + width: 100%; + } .modal-body { height: 100% !important; flex-direction: column; padding: 0; } + + .modal-footer { + font-size: 0.9em; + } .revision-list { - height: unset; + height: fit-content !important; max-height: 20vh; border-bottom: 1px solid var(--main-border-color) !important; padding: 0 1em; @@ -18,6 +34,7 @@ body.mobile .revisions-dialog { .modal-body > .revision-content-wrapper { flex-grow: 1; + max-width: unset !important; height: 100%; overflow: auto; margin: 0; @@ -33,6 +50,9 @@ body.mobile .revisions-dialog { .revision-title-buttons { text-align: center; + display: flex; + gap: 0.25em; + flex-wrap: wrap; } .revision-content { diff --git a/apps/client/src/widgets/dialogs/revisions.tsx b/apps/client/src/widgets/dialogs/revisions.tsx index fd2dd9a16..322abdd3b 100644 --- a/apps/client/src/widgets/dialogs/revisions.tsx +++ b/apps/client/src/widgets/dialogs/revisions.tsx @@ -138,7 +138,7 @@ export default function RevisionsDialog() { function RevisionsList({ revisions, onSelect, currentRevision }: { revisions: RevisionItem[], onSelect: (val: string) => void, currentRevision?: RevisionItem }) { return ( - + {revisions.map((item) => void; style?: CSSProperties; + wrapperClassName?: string; fullHeight?: boolean; } -export default function FormList({ children, onSelect, style, fullHeight }: FormListOpts) { +export default function FormList({ children, onSelect, style, fullHeight, wrapperClassName }: FormListOpts) { const wrapperRef = useRef(null); const triggerRef = useRef(null); @@ -43,7 +45,7 @@ export default function FormList({ children, onSelect, style, fullHeight }: Form }, [ fullHeight ]); return ( -
+