From 0d8453f6a76009251476df79d2e5d8f7744b1b5a Mon Sep 17 00:00:00 2001 From: Elian Doran Date: Tue, 3 Feb 2026 18:58:04 +0200 Subject: [PATCH] feat(mobile/note_actions): integrate code language switcher --- apps/client/src/stylesheets/style.css | 1 + .../mobile_widgets/mobile_detail_menu.css | 3 ++ .../mobile_widgets/mobile_detail_menu.tsx | 38 ++++++++++++++++- .../src/widgets/ribbon/BasicPropertiesTab.tsx | 42 +++++++++---------- 4 files changed, 61 insertions(+), 23 deletions(-) create mode 100644 apps/client/src/widgets/mobile_widgets/mobile_detail_menu.css diff --git a/apps/client/src/stylesheets/style.css b/apps/client/src/stylesheets/style.css index e3d3f5279f..cac9bc2989 100644 --- a/apps/client/src/stylesheets/style.css +++ b/apps/client/src/stylesheets/style.css @@ -409,6 +409,7 @@ body.desktop .tabulator-popup-container, .dropdown-menu.static { box-shadow: unset; + backdrop-filter: unset !important; } .dropend .dropdown-toggle::after { diff --git a/apps/client/src/widgets/mobile_widgets/mobile_detail_menu.css b/apps/client/src/widgets/mobile_widgets/mobile_detail_menu.css new file mode 100644 index 0000000000..f3e1503471 --- /dev/null +++ b/apps/client/src/widgets/mobile_widgets/mobile_detail_menu.css @@ -0,0 +1,3 @@ +.code-note-switcher-modal .dropdown-menu { + background: none !important; +} 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 3a89bdec85..53bb58c50e 100644 --- a/apps/client/src/widgets/mobile_widgets/mobile_detail_menu.tsx +++ b/apps/client/src/widgets/mobile_widgets/mobile_detail_menu.tsx @@ -1,14 +1,18 @@ +import "./mobile_detail_menu.css"; + import { createPortal, useState } from "preact/compat"; import FNote, { NotePathRecord } from "../../entities/fnote"; import { t } from "../../services/i18n"; import note_create from "../../services/note_create"; +import server from "../../services/server"; import { BacklinksList, useBacklinkCount } from "../FloatingButtonsDefinitions"; import { NoteInfoContent } from "../layout/StatusBar"; import ActionButton from "../react/ActionButton"; import { FormDropdownDivider, FormListItem } from "../react/FormList"; -import { useNoteContext } from "../react/hooks"; +import { useNoteContext, useNoteProperty } from "../react/hooks"; import Modal from "../react/Modal"; +import { NoteTypeCodeNoteList, useMimeTypes } from "../ribbon/BasicPropertiesTab"; import { NoteContextMenu } from "../ribbon/NoteActions"; import NoteActionsCustom from "../ribbon/NoteActionsCustom"; import { NotePathsWidget, useSortedNotePaths } from "../ribbon/NotePathsTab"; @@ -22,6 +26,7 @@ export default function MobileDetailMenu() { const [ notePathsModalShown, setNotePathsModalShown ] = useState(false); const [ noteInfoModalShown, setNoteInfoModalShown ] = useState(false); const [ similarNotesModalShown, setSimilarNotesModalShown ] = useState(false); + const [ codeNoteSwitcherModalShown, setCodeNoteSwitcherModalShown ] = useState(false); const sortedNotePaths = useSortedNotePaths(note, hoistedNoteId); const backlinksCount = useBacklinkCount(note, viewScope?.viewMode === "default"); @@ -76,7 +81,8 @@ export default function MobileDetailMenu() { >{t("close_pane_button.close_this_pane")} } - setNoteInfoModalShown(true)} >{t("note_info_widget.title")} + {note.type === "code" && setCodeNoteSwitcherModalShown(true)}>{t("status_bar.code_note_switcher")}} + setNoteInfoModalShown(true)}>{t("note_info_widget.title")} setSimilarNotesModalShown(true)}>{t("similar_notes.title")} } @@ -95,6 +101,7 @@ export default function MobileDetailMenu() { + ), document.body)} @@ -168,3 +175,30 @@ function SimilarNotesModal({ note, modalShown, setModalShown }: { note: FNote | ); } + +function CodeNoteSwitcherModal({ note, modalShown, setModalShown }: { note: FNote | null | undefined } & WithModal) { + const currentNoteMime = useNoteProperty(note, "mime"); + const mimeTypes = useMimeTypes(); + + return ( + setModalShown(false)} + > +
+ {note && { + server.put(`notes/${note.noteId}/type`, { type, mime }); + setModalShown(false); + }} + // setModalShown={() => setModalShown(true)} + />} +
+
+ ); +} diff --git a/apps/client/src/widgets/ribbon/BasicPropertiesTab.tsx b/apps/client/src/widgets/ribbon/BasicPropertiesTab.tsx index 9b800bebb9..5dbd0d29cb 100644 --- a/apps/client/src/widgets/ribbon/BasicPropertiesTab.tsx +++ b/apps/client/src/widgets/ribbon/BasicPropertiesTab.tsx @@ -1,5 +1,4 @@ import { MimeType, NoteType, ToggleInParentResponse } from "@triliumnext/commons"; -import { ComponentChildren } from "preact"; import { createPortal } from "preact/compat"; import { Dispatch, StateUpdater, useCallback, useEffect, useMemo, useState } from "preact/hooks"; @@ -117,19 +116,18 @@ export function NoteTypeDropdownContent({ currentNoteType, currentNoteMime, note onClick={() => changeNoteType(type, mime)} >{title} ); - } else { - return ( - <> - - - {title} - - - ); } + return ( + <> + + + {title} + + + ); })} {!noCodeNotes && } @@ -141,7 +139,7 @@ export function NoteTypeCodeNoteList({ currentMimeType, mimeTypes, changeNoteTyp currentMimeType?: string; mimeTypes: MimeType[]; changeNoteType(type: NoteType, mime: string): void; - setModalShown(shown: boolean): void; + setModalShown?(shown: boolean): void; }) { return ( <> @@ -155,8 +153,10 @@ export function NoteTypeCodeNoteList({ currentMimeType, mimeTypes, changeNoteTyp ))} - - setModalShown(true)}>{t("basic_properties.configure_code_notes")} + {setModalShown && <> + + setModalShown(true)}>{t("basic_properties.configure_code_notes")} + } ); } @@ -195,7 +195,7 @@ function ProtectedNoteSwitch({ note }: { note?: FNote | null }) { onChange={(shouldProtect) => note && protected_session.protectNote(note.noteId, shouldProtect, false)} /> - ) + ); } function EditabilitySelect({ note }: { note?: FNote | null }) { @@ -417,9 +417,9 @@ function findTypeTitle(type?: NoteType, mime?: string | null) { const found = mimeTypes.find((mt) => mt.mime === mime); return found ? found.title : mime; - } else { - const noteType = NOTE_TYPES.find((nt) => nt.type === type); - - return noteType ? noteType.title : type; } + const noteType = NOTE_TYPES.find((nt) => nt.type === type); + + return noteType ? noteType.title : type; + }