From 42a082f11b8a3fb5f021c579262682198d612b36 Mon Sep 17 00:00:00 2001 From: Adorian Doran Date: Fri, 19 Sep 2025 21:10:26 +0300 Subject: [PATCH 01/15] style: fix the spacing of the keyboard shortcuts in menu items --- apps/client/src/stylesheets/style.css | 6 +++--- apps/client/src/stylesheets/theme-next/base.css | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/client/src/stylesheets/style.css b/apps/client/src/stylesheets/style.css index f6f07684f..6ce636e01 100644 --- a/apps/client/src/stylesheets/style.css +++ b/apps/client/src/stylesheets/style.css @@ -444,9 +444,11 @@ body #context-menu-container .dropdown-item > span { align-items: center; } -.dropdown-item span.keyboard-shortcut { +.dropdown-item span.keyboard-shortcut, +.dropdown-item *:not(.keyboard-shortcut) > kbd { flex-grow: 1; text-align: right; + padding-inline-start: 12px; } .dropdown-menu kbd { @@ -456,8 +458,6 @@ body #context-menu-container .dropdown-item > span { box-shadow: none; padding-bottom: 0; padding: 0; - flex-grow: 1; - text-align: right; } .dropdown-item, diff --git a/apps/client/src/stylesheets/theme-next/base.css b/apps/client/src/stylesheets/theme-next/base.css index 0e6f7f127..50bc058a0 100644 --- a/apps/client/src/stylesheets/theme-next/base.css +++ b/apps/client/src/stylesheets/theme-next/base.css @@ -154,7 +154,7 @@ body.desktop .dropdown-submenu .dropdown-menu { .dropdown-item, body.mobile .dropdown-submenu .dropdown-toggle { padding: 2px 2px 2px 8px !important; - padding-inline-end: 16px !important; + padding-inline-end: 22px !important; /* Note: the right padding should also accommodate the submenu arrow. */ border-radius: 6px; cursor: default !important; From c0c1c8a9c288c3ba32b37799d882d925be3c7adf Mon Sep 17 00:00:00 2001 From: Adorian Doran Date: Fri, 19 Sep 2025 21:41:44 +0300 Subject: [PATCH 02/15] style(next)/launcher/calendar: restyle the week number column --- apps/client/src/stylesheets/theme-next/shell.css | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/apps/client/src/stylesheets/theme-next/shell.css b/apps/client/src/stylesheets/theme-next/shell.css index 0ffe0ec40..9dbb04c9f 100644 --- a/apps/client/src/stylesheets/theme-next/shell.css +++ b/apps/client/src/stylesheets/theme-next/shell.css @@ -348,6 +348,21 @@ body.layout-horizontal > .horizontal { --select-arrow-svg: initial; /* Disable the dropdown arrow */ } +/* Week number column */ +.calendar-dropdown-widget .calendar-week-number { + transform: rotate(270deg); + justify-content: center; + padding: 0; + opacity: 0.5; + font-size: 1em; + font-weight: 700; + letter-spacing: .5pt; +} + +.calendar-dropdown-widget .calendar-week-number::after { + display: none; +} + @media (max-width: 992px) { .calendar-dropdown-widget .calendar-header button { margin: 0 !important; From 90337016e76122c07356cb225db43053cfa42428 Mon Sep 17 00:00:00 2001 From: Adorian Doran Date: Fri, 19 Sep 2025 21:49:01 +0300 Subject: [PATCH 03/15] style(next)/launcher/calendar: fix the rounded corners of the arrow buttons --- apps/client/src/stylesheets/theme-next/forms.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/client/src/stylesheets/theme-next/forms.css b/apps/client/src/stylesheets/theme-next/forms.css index 530a5c999..44a11cbbb 100644 --- a/apps/client/src/stylesheets/theme-next/forms.css +++ b/apps/client/src/stylesheets/theme-next/forms.css @@ -84,7 +84,7 @@ button.btn.btn-success kbd { */ :root .icon-action:not(.global-menu-button), -:root .btn.tn-tool-button, +:root .tn-tool-button, :root .btn-group .tn-tool-button:not(:last-child), :root .btn-group .tn-tool-button:last-child { width: var(--icon-button-size); From 79718c7e6e0331755bda6a3429baaa4caf20e7d0 Mon Sep 17 00:00:00 2001 From: Adorian Doran Date: Fri, 19 Sep 2025 23:46:14 +0300 Subject: [PATCH 04/15] style(next)/bulk actions dialog: fix the alignment of the help and close buttons for actions --- apps/client/src/widgets/dialogs/bulk_actions.css | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/apps/client/src/widgets/dialogs/bulk_actions.css b/apps/client/src/widgets/dialogs/bulk_actions.css index fe64a02b3..5f103feea 100644 --- a/apps/client/src/widgets/dialogs/bulk_actions.css +++ b/apps/client/src/widgets/dialogs/bulk_actions.css @@ -17,8 +17,15 @@ } .bulk-actions-dialog .bulk-existing-action-list .button-column { - /* minimal width so that table remains static sized and most space remains for middle column with settings */ width: 50px; white-space: nowrap; text-align: right; +} + +.bulk-actions-dialog .bulk-existing-action-list .button-column > * { + vertical-align: middle; +} + +.bulk-actions-dialog .bulk-existing-action-list .button-column .help-dropdown { + display: inline-block !important; } \ No newline at end of file From 17e87278ebdcec05821d482626d0b56c5e1db43a Mon Sep 17 00:00:00 2001 From: Adorian Doran Date: Sat, 20 Sep 2025 00:18:56 +0300 Subject: [PATCH 05/15] client/menus: add support for menu headers --- apps/client/src/menus/context_menu.ts | 9 ++++++++- apps/client/src/services/note_types.ts | 5 ++--- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/apps/client/src/menus/context_menu.ts b/apps/client/src/menus/context_menu.ts index 983c0a48c..09b51694d 100644 --- a/apps/client/src/menus/context_menu.ts +++ b/apps/client/src/menus/context_menu.ts @@ -18,6 +18,11 @@ interface MenuSeparatorItem { title: "----"; } +interface MenuHeader { + title: string; + kind: "header"; +} + export interface MenuItemBadge { title: string; className?: string; @@ -45,7 +50,7 @@ export interface MenuCommandItem { columns?: number; } -export type MenuItem = MenuCommandItem | MenuSeparatorItem; +export type MenuItem = MenuCommandItem | MenuSeparatorItem | MenuHeader; export type MenuHandler = (item: MenuCommandItem, e: JQuery.MouseDownEvent) => void; export type ContextMenuEvent = PointerEvent | MouseEvent | JQuery.ContextMenuEvent; @@ -158,6 +163,8 @@ class ContextMenu { if (item.title === "----") { $parent.append($("
").addClass("dropdown-divider")); + } else if ("kind" in item && item.kind === "header") { + $parent.append($("
").addClass("dropdown-header").text(item.title)); } else { const $icon = $(""); diff --git a/apps/client/src/services/note_types.ts b/apps/client/src/services/note_types.ts index 64d31ad39..0dba6a0c0 100644 --- a/apps/client/src/services/note_types.ts +++ b/apps/client/src/services/note_types.ts @@ -157,9 +157,8 @@ async function getBuiltInTemplates(title: string | null, command: TreeCommandNam const items: MenuItem[] = []; if (title) { items.push({ - title: title, - enabled: false, - uiIcon: "bx bx-empty" + title: "title", + kind: "header" }); } else { items.push(SEPARATOR); From b26803b627c79650eda63eb4854ec1b02538ae49 Mon Sep 17 00:00:00 2001 From: Adorian Doran Date: Sat, 20 Sep 2025 00:34:25 +0300 Subject: [PATCH 06/15] client/menus: refactor --- apps/client/src/menus/context_menu.ts | 4 ++-- apps/client/src/menus/electron_context_menu.ts | 2 +- apps/client/src/menus/launcher_context_menu.ts | 6 +++--- apps/client/src/menus/tree_context_menu.ts | 18 +++++++++--------- apps/client/src/services/note_types.ts | 4 ++-- .../widgets/collections/board/context_menu.ts | 6 +++--- .../widgets/collections/geomap/context_menu.ts | 6 +++--- .../widgets/collections/table/context_menu.ts | 12 ++++++------ .../src/widgets/dialogs/note_type_chooser.tsx | 4 ++-- .../mobile_widgets/mobile_detail_menu.tsx | 2 +- .../ribbon/components/AttributeEditor.tsx | 2 +- apps/client/src/widgets/tab_row.ts | 4 ++-- 12 files changed, 35 insertions(+), 35 deletions(-) diff --git a/apps/client/src/menus/context_menu.ts b/apps/client/src/menus/context_menu.ts index 09b51694d..786c53e4e 100644 --- a/apps/client/src/menus/context_menu.ts +++ b/apps/client/src/menus/context_menu.ts @@ -15,7 +15,7 @@ export interface ContextMenuOptions { } interface MenuSeparatorItem { - title: "----"; + kind: "separator"; } interface MenuHeader { @@ -161,7 +161,7 @@ class ContextMenu { continue; } - if (item.title === "----") { + if ("kind" in item && item.kind === "separator") { $parent.append($("
").addClass("dropdown-divider")); } else if ("kind" in item && item.kind === "header") { $parent.append($("
").addClass("dropdown-header").text(item.title)); diff --git a/apps/client/src/menus/electron_context_menu.ts b/apps/client/src/menus/electron_context_menu.ts index 51415c655..cbd35dcb8 100644 --- a/apps/client/src/menus/electron_context_menu.ts +++ b/apps/client/src/menus/electron_context_menu.ts @@ -112,7 +112,7 @@ function setupContextMenu() { // Replace the placeholder with the real search keyword. let searchUrl = searchEngineUrl.replace("{keyword}", encodeURIComponent(params.selectionText)); - items.push({ title: "----" }); + items.push({ kind: "separator" }); items.push({ title: t("electron_context_menu.search_online", { term: shortenedSelection, searchEngine: searchEngineName }), diff --git a/apps/client/src/menus/launcher_context_menu.ts b/apps/client/src/menus/launcher_context_menu.ts index 2ac7decee..717180690 100644 --- a/apps/client/src/menus/launcher_context_menu.ts +++ b/apps/client/src/menus/launcher_context_menu.ts @@ -45,16 +45,16 @@ export default class LauncherContextMenu implements SelectMenuItemEventListener< isVisibleRoot || isAvailableRoot ? { title: t("launcher_context_menu.add-script-launcher"), command: "addScriptLauncher", uiIcon: "bx bx-code-curly" } : null, isVisibleRoot || isAvailableRoot ? { title: t("launcher_context_menu.add-custom-widget"), command: "addWidgetLauncher", uiIcon: "bx bx-customize" } : null, isVisibleRoot || isAvailableRoot ? { title: t("launcher_context_menu.add-spacer"), command: "addSpacerLauncher", uiIcon: "bx bx-dots-horizontal" } : null, - isVisibleRoot || isAvailableRoot ? { title: "----" } : null, + isVisibleRoot || isAvailableRoot ? { kind: "separator" } : null, isAvailableItem ? { title: t("launcher_context_menu.move-to-visible-launchers"), command: "moveLauncherToVisible", uiIcon: "bx bx-show", enabled: true } : null, isVisibleItem ? { title: t("launcher_context_menu.move-to-available-launchers"), command: "moveLauncherToAvailable", uiIcon: "bx bx-hide", enabled: true } : null, - isVisibleItem || isAvailableItem ? { title: "----" } : null, + isVisibleItem || isAvailableItem ? { kind: "separator" } : null, { title: `${t("launcher_context_menu.duplicate-launcher")}`, command: "duplicateSubtree", uiIcon: "bx bx-outline", enabled: isItem }, { title: `${t("launcher_context_menu.delete")}`, command: "deleteNotes", uiIcon: "bx bx-trash destructive-action-icon", enabled: canBeDeleted }, - { title: "----" }, + { kind: "separator" }, { title: t("launcher_context_menu.reset"), command: "resetLauncher", uiIcon: "bx bx-reset destructive-action-icon", enabled: canBeReset } ]; diff --git a/apps/client/src/menus/tree_context_menu.ts b/apps/client/src/menus/tree_context_menu.ts index 4ef517912..6504b49eb 100644 --- a/apps/client/src/menus/tree_context_menu.ts +++ b/apps/client/src/menus/tree_context_menu.ts @@ -93,7 +93,7 @@ export default class TreeContextMenu implements SelectMenuItemEventListener(); let rootCreationDate: Date | undefined; @@ -157,7 +157,7 @@ async function getBuiltInTemplates(title: string | null, command: TreeCommandNam const items: MenuItem[] = []; if (title) { items.push({ - title: "title", + title: title, kind: "header" }); } else { diff --git a/apps/client/src/widgets/collections/board/context_menu.ts b/apps/client/src/widgets/collections/board/context_menu.ts index d3f74fde4..0c818a111 100644 --- a/apps/client/src/widgets/collections/board/context_menu.ts +++ b/apps/client/src/widgets/collections/board/context_menu.ts @@ -41,7 +41,7 @@ export function openNoteContextMenu(api: Api, event: ContextMenuEvent, note: FNo y: event.pageY, items: [ ...link_context_menu.getItems(), - { title: "----" }, + { kind: "separator" }, { title: t("board_view.move-to"), uiIcon: "bx bx-transfer", @@ -52,7 +52,7 @@ export function openNoteContextMenu(api: Api, event: ContextMenuEvent, note: FNo })), }, getArchiveMenuItem(note), - { title: "----" }, + { kind: "separator" }, { title: t("board_view.insert-above"), uiIcon: "bx bx-list-plus", @@ -63,7 +63,7 @@ export function openNoteContextMenu(api: Api, event: ContextMenuEvent, note: FNo uiIcon: "bx bx-empty", handler: () => api.insertRowAtPosition(column, branchId, "after") }, - { title: "----" }, + { kind: "separator" }, { title: t("board_view.remove-from-board"), uiIcon: "bx bx-task-x", diff --git a/apps/client/src/widgets/collections/geomap/context_menu.ts b/apps/client/src/widgets/collections/geomap/context_menu.ts index 617c4637f..dd583e266 100644 --- a/apps/client/src/widgets/collections/geomap/context_menu.ts +++ b/apps/client/src/widgets/collections/geomap/context_menu.ts @@ -10,14 +10,14 @@ import link from "../../../services/link.js"; export default function openContextMenu(noteId: string, e: LeafletMouseEvent, isEditable: boolean) { let items: MenuItem[] = [ ...buildGeoLocationItem(e), - { title: "----" }, + { kind: "separator" }, ...linkContextMenu.getItems(), ]; if (isEditable) { items = [ ...items, - { title: "----" }, + { kind: "separator" }, { title: t("geo-map-context.remove-from-map"), command: "deleteFromMap", uiIcon: "bx bx-trash" } ]; } @@ -46,7 +46,7 @@ export function openMapContextMenu(noteId: string, e: LeafletMouseEvent, isEdita if (isEditable) { items = [ ...items, - { title: "----" }, + { kind: "separator" }, { title: t("geo-map-context.add-note"), handler: () => createNewNote(noteId, e), diff --git a/apps/client/src/widgets/collections/table/context_menu.ts b/apps/client/src/widgets/collections/table/context_menu.ts index 16cbd39ff..eb0a303ae 100644 --- a/apps/client/src/widgets/collections/table/context_menu.ts +++ b/apps/client/src/widgets/collections/table/context_menu.ts @@ -74,7 +74,7 @@ function showColumnContextMenu(parentComponent: Component, e: MouseEvent, column handler: () => tabulator.clearSort() }, { - title: "----" + kind: "separator" }, { title: t("table_view.hide-column", { title }), @@ -86,7 +86,7 @@ function showColumnContextMenu(parentComponent: Component, e: MouseEvent, column uiIcon: "bx bx-columns", items: buildColumnItems(tabulator) }, - { title: "----" }, + { kind: "separator" }, { title: t("table_view.add-column-to-the-left"), uiIcon: "bx bx-horizontal-left", @@ -105,7 +105,7 @@ function showColumnContextMenu(parentComponent: Component, e: MouseEvent, column direction: "after" }) }, - { title: "----" }, + { kind: "separator" }, { title: t("table_view.edit-column"), uiIcon: "bx bxs-edit-alt", @@ -143,7 +143,7 @@ function showHeaderContextMenu(parentComponent: Component, e: MouseEvent, tabula uiIcon: "bx bx-columns", items: buildColumnItems(tabulator) }, - { title: "----" }, + { kind: "separator" }, { title: t("table_view.new-column"), uiIcon: "bx bx-empty", @@ -174,7 +174,7 @@ export function showRowContextMenu(parentComponent: Component, e: MouseEvent, ro contextMenu.show({ items: [ ...link_context_menu.getItems(), - { title: "----" }, + { kind: "separator" }, { title: t("table_view.row-insert-above"), uiIcon: "bx bx-horizontal-left bx-rotate-90", @@ -214,7 +214,7 @@ export function showRowContextMenu(parentComponent: Component, e: MouseEvent, ro } }) }, - { title: "----" }, + { kind: "separator" }, { title: t("table_context_menu.delete_row"), uiIcon: "bx bx-trash", diff --git a/apps/client/src/widgets/dialogs/note_type_chooser.tsx b/apps/client/src/widgets/dialogs/note_type_chooser.tsx index bc6e8abc9..fba12acca 100644 --- a/apps/client/src/widgets/dialogs/note_type_chooser.tsx +++ b/apps/client/src/widgets/dialogs/note_type_chooser.tsx @@ -41,7 +41,7 @@ export default function NoteTypeChooserDialogComponent() { let index = -1; setNoteTypes((noteTypes ?? []).map((item) => { - if (item.title === "----") { + if ("kind" in item && item.kind === "separator") { index++; return { title: SEPARATOR_TITLE_REPLACEMENTS[index], @@ -95,7 +95,7 @@ export default function NoteTypeChooserDialogComponent() { {noteTypes.map((_item) => { - if (_item.title === "----") { + if ("kind" in _item && _item.kind === "separator") { return; } diff --git a/apps/client/src/widgets/mobile_widgets/mobile_detail_menu.tsx b/apps/client/src/widgets/mobile_widgets/mobile_detail_menu.tsx index 596a70300..a9e88246e 100644 --- a/apps/client/src/widgets/mobile_widgets/mobile_detail_menu.tsx +++ b/apps/client/src/widgets/mobile_widgets/mobile_detail_menu.tsx @@ -24,7 +24,7 @@ export default function MobileDetailMenu() { items: [ { title: t("mobile_detail_menu.insert_child_note"), command: "insertChildNote", uiIcon: "bx bx-plus", enabled: note?.type !== "search" }, { title: t("mobile_detail_menu.delete_this_note"), command: "delete", uiIcon: "bx bx-trash", enabled: note?.noteId !== "root" }, - { title: "----" }, + { kind: "separator" }, { title: "Note revisions", command: "showRevisions", uiIcon: "bx bx-history" } ], selectMenuItemHandler: async ({ command }) => { diff --git a/apps/client/src/widgets/ribbon/components/AttributeEditor.tsx b/apps/client/src/widgets/ribbon/components/AttributeEditor.tsx index 32cae708b..337636265 100644 --- a/apps/client/src/widgets/ribbon/components/AttributeEditor.tsx +++ b/apps/client/src/widgets/ribbon/components/AttributeEditor.tsx @@ -387,7 +387,7 @@ export default function AttributeEditor({ api, note, componentId, notePath, ntxI items: [ { title: t("attribute_editor.add_new_label"), command: "addNewLabel", uiIcon: "bx bx-hash" }, { title: t("attribute_editor.add_new_relation"), command: "addNewRelation", uiIcon: "bx bx-transfer" }, - { title: "----" }, + { kind: "separator" }, { title: t("attribute_editor.add_new_label_definition"), command: "addNewLabelDefinition", uiIcon: "bx bx-empty" }, { title: t("attribute_editor.add_new_relation_definition"), command: "addNewRelationDefinition", uiIcon: "bx bx-empty" } ], diff --git a/apps/client/src/widgets/tab_row.ts b/apps/client/src/widgets/tab_row.ts index cf1367878..1f48de516 100644 --- a/apps/client/src/widgets/tab_row.ts +++ b/apps/client/src/widgets/tab_row.ts @@ -356,11 +356,11 @@ export default class TabRowWidget extends BasicWidget { { title: t("tab_row.close_right_tabs"), command: "closeRightTabs", uiIcon: "bx bx-empty", enabled: appContext.tabManager.noteContexts?.at(-1)?.ntxId !== ntxId }, { title: t("tab_row.close_all_tabs"), command: "closeAllTabs", uiIcon: "bx bx-empty" }, - { title: "----" }, + { kind: "separator" }, { title: t("tab_row.reopen_last_tab"), command: "reopenLastTab", uiIcon: "bx bx-undo", enabled: appContext.tabManager.recentlyClosedTabs.length !== 0 }, - { title: "----" }, + { kind: "separator" }, { title: t("tab_row.move_tab_to_new_window"), command: "moveTabToNewWindow", uiIcon: "bx bx-window-open" }, { title: t("tab_row.copy_tab_to_new_window"), command: "copyTabToNewWindow", uiIcon: "bx bx-empty" } From 0b05f597dc1d46e6d010af9ab9b228e5b01accf4 Mon Sep 17 00:00:00 2001 From: Adorian Doran Date: Sat, 20 Sep 2025 01:08:36 +0300 Subject: [PATCH 07/15] client/menus: refactor --- apps/client/src/menus/context_menu.ts | 4 ++-- apps/client/src/services/note_types.ts | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/client/src/menus/context_menu.ts b/apps/client/src/menus/context_menu.ts index 786c53e4e..a0e6d5cb5 100644 --- a/apps/client/src/menus/context_menu.ts +++ b/apps/client/src/menus/context_menu.ts @@ -14,11 +14,11 @@ export interface ContextMenuOptions { onHide?: () => void; } -interface MenuSeparatorItem { +export interface MenuSeparatorItem { kind: "separator"; } -interface MenuHeader { +export interface MenuHeader { title: string; kind: "header"; } diff --git a/apps/client/src/services/note_types.ts b/apps/client/src/services/note_types.ts index daa9bf000..b8eeb90e1 100644 --- a/apps/client/src/services/note_types.ts +++ b/apps/client/src/services/note_types.ts @@ -1,7 +1,7 @@ import { t } from "./i18n.js"; import froca from "./froca.js"; import server from "./server.js"; -import type { MenuCommandItem, MenuItem, MenuItemBadge } from "../menus/context_menu.js"; +import type { MenuCommandItem, MenuItem, MenuItemBadge, MenuSeparatorItem } from "../menus/context_menu.js"; import type { NoteType } from "../entities/fnote.js"; import type { TreeCommandNames } from "../menus/tree_context_menu.js"; @@ -73,7 +73,7 @@ const BETA_BADGE = { title: t("note_types.beta-feature") }; -const SEPARATOR = { kind: "separator" }; +const SEPARATOR: MenuSeparatorItem = { kind: "separator" }; const creationDateCache = new Map(); let rootCreationDate: Date | undefined; From 8877eded9b57ad34b69b520f48aabb554ed27714 Mon Sep 17 00:00:00 2001 From: Adorian Doran Date: Sat, 20 Sep 2025 01:11:24 +0300 Subject: [PATCH 08/15] style/menus: tweak header layout and add multi-column menu divider line --- apps/client/src/stylesheets/style.css | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/apps/client/src/stylesheets/style.css b/apps/client/src/stylesheets/style.css index 6ce636e01..fe5d8e980 100644 --- a/apps/client/src/stylesheets/style.css +++ b/apps/client/src/stylesheets/style.css @@ -378,6 +378,7 @@ button kbd { body.desktop .dropdown-menu, body.desktop .tabulator-popup-container { border: 1px solid var(--dropdown-border-color); + column-rule: 1px solid var(--dropdown-border-color); box-shadow: 0px 10px 20px rgba(0, 0, 0, var(--dropdown-shadow-opacity)); animation: dropdown-menu-opening 100ms ease-in; } @@ -466,6 +467,11 @@ body #context-menu-container .dropdown-item > span { border: 1px solid transparent !important; } +.dropdown-header { + break-after: avoid; + break-inside: avoid; +} + .dropdown-item.disabled, .dropdown-item.disabled kbd { color: #aaa !important; From daba190e743a08a30ec273c224d7e0c178a9b94d Mon Sep 17 00:00:00 2001 From: Adorian Doran Date: Sat, 20 Sep 2025 01:57:58 +0300 Subject: [PATCH 09/15] client/menus: rearrange "Insert note" submenu items --- apps/client/src/services/note_types.ts | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/apps/client/src/services/note_types.ts b/apps/client/src/services/note_types.ts index b8eeb90e1..a42631f9f 100644 --- a/apps/client/src/services/note_types.ts +++ b/apps/client/src/services/note_types.ts @@ -81,8 +81,8 @@ let rootCreationDate: Date | undefined; async function getNoteTypeItems(command?: TreeCommandNames) { const items: MenuItem[] = [ ...getBlankNoteTypes(command), - ...await getBuiltInTemplates(t("note_types.collections"), command, true), ...await getBuiltInTemplates(null, command, false), + ...await getBuiltInTemplates(t("note_types.collections"), command, true), ...await getUserTemplates(command) ]; @@ -121,7 +121,10 @@ async function getUserTemplates(command?: TreeCommandNames) { } const items: MenuItem[] = [ - SEPARATOR + { + title: t("note_type_chooser.templates"), + kind: "header" + } ]; for (const templateNote of templateNotes) { From 9a9edf16c478f67a8a68570ed63ecc76590cabf0 Mon Sep 17 00:00:00 2001 From: Adorian Doran Date: Sat, 20 Sep 2025 02:59:41 +0300 Subject: [PATCH 10/15] client/menus: manage proper column breaking on Firefox --- apps/client/src/menus/context_menu.ts | 32 +++++++++++++++++++++++---- apps/client/src/stylesheets/style.css | 4 ++++ 2 files changed, 32 insertions(+), 4 deletions(-) diff --git a/apps/client/src/menus/context_menu.ts b/apps/client/src/menus/context_menu.ts index a0e6d5cb5..c9ab89e3f 100644 --- a/apps/client/src/menus/context_menu.ts +++ b/apps/client/src/menus/context_menu.ts @@ -156,15 +156,32 @@ class ContextMenu { } addItems($parent: JQuery, items: MenuItem[]) { - for (const item of items) { + let $group = $parent; + let shouldResetGroup = false; // If true, the next item will be the last one from the group + + for (let index = 0; index < items.length; index++) { + const item = items[index]; if (!item) { continue; } + // If the next item is a separator or header, create a new group to avoid column breaks + // before and after the seaparator/header. + // This is a workaround for Firefox not supporting break-after: avoid on columns. + const nextItem = (index < items.length - 1) ? items[index + 1] : null; + if (!shouldResetGroup && nextItem && "kind" in nextItem) { + if (nextItem.kind === "separator" || nextItem.kind === "header") { + $group = $("