From 23062470f5b095c2955f2db9685542fce503d3b1 Mon Sep 17 00:00:00 2001 From: Elian Doran Date: Sat, 13 Dec 2025 01:03:57 +0200 Subject: [PATCH] feat(status_bar): code mime switcher --- .../src/translations/en/translation.json | 3 +- apps/client/src/widgets/layout/StatusBar.tsx | 43 ++++++++++++++++--- .../src/widgets/ribbon/BasicPropertiesTab.tsx | 34 ++++++++++++--- 3 files changed, 66 insertions(+), 14 deletions(-) diff --git a/apps/client/src/translations/en/translation.json b/apps/client/src/translations/en/translation.json index ebd0f2662..17b1b90ae 100644 --- a/apps/client/src/translations/en/translation.json +++ b/apps/client/src/translations/en/translation.json @@ -2163,6 +2163,7 @@ "attributes_one": "{{count}} attribute", "attributes_other": "{{count}} attributes", "attributes_title": "Click to open a dedicated pane to edit this note's owned attributes, as well as to see the list of inherited attributes.", - "note_paths_title": "Click to see the paths where this note is placed into the tree." + "note_paths_title": "Click to see the paths where this note is placed into the tree.", + "code_note_switcher": "Change language mode" } } diff --git a/apps/client/src/widgets/layout/StatusBar.tsx b/apps/client/src/widgets/layout/StatusBar.tsx index 5d08bb5f6..50db10908 100644 --- a/apps/client/src/widgets/layout/StatusBar.tsx +++ b/apps/client/src/widgets/layout/StatusBar.tsx @@ -17,10 +17,10 @@ import { formatDateTime } from "../../utils/formatters"; import { BacklinksList, useBacklinkCount } from "../FloatingButtonsDefinitions"; import Dropdown, { DropdownProps } from "../react/Dropdown"; import { FormDropdownDivider, FormListItem } from "../react/FormList"; -import { useActiveNoteContext, useLegacyImperativeHandlers, useStaticTooltip, useTriliumEvent, useTriliumEvents } from "../react/hooks"; +import { useActiveNoteContext, useLegacyImperativeHandlers, useNoteProperty, useStaticTooltip, useTriliumEvent, useTriliumEvents } from "../react/hooks"; import Icon from "../react/Icon"; import { ParentComponent } from "../react/react_utils"; -import { ContentLanguagesModal, useLanguageSwitcher } from "../ribbon/BasicPropertiesTab"; +import { ContentLanguagesModal, NoteTypeCodeNoteList, useLanguageSwitcher, useMimeTypes } from "../ribbon/BasicPropertiesTab"; import AttributeEditor, { AttributeEditorImperativeHandlers } from "../ribbon/components/AttributeEditor"; import InheritedAttributesTab from "../ribbon/InheritedAttributesTab"; import { NoteSizeWidget, useNoteMetadata } from "../ribbon/NoteInfoTab"; @@ -28,6 +28,7 @@ import { NotePathsWidget, useSortedNotePaths } from "../ribbon/NotePathsTab"; import { useAttachments } from "../type_widgets/Attachment"; import { useProcessedLocales } from "../type_widgets/options/components/LocaleSelector"; import Breadcrumb from "./Breadcrumb"; +import server from "../../services/server"; interface StatusBarContext { note: FNote; @@ -53,6 +54,7 @@ export default function StatusBar() {
+ {!isHiddenNote && } @@ -75,15 +77,19 @@ function StatusBarDropdown({ children, icon, text, buttonClassName, titleOptions buttonClassName={clsx("status-bar-dropdown-button", buttonClassName)} titlePosition="top" titleOptions={{ - ...titleOptions, popperConfig: { ...titleOptions?.popperConfig, strategy: "fixed" - } + }, + ...titleOptions }} dropdownOptions={{ - ...dropdownOptions, - autoClose: "outside" + autoClose: "outside", + popperConfig: { + strategy: "fixed", + placement: "top" + }, + ...dropdownOptions }} text={<> {icon && (<> )} @@ -340,3 +346,28 @@ function NotePaths({ note, hoistedNoteId, notePath }: StatusBarContext) { ); } //#endregion + +//#region Code note switcher +function CodeNoteSwitcher({ note }: StatusBarContext) { + const currentNoteMime = useNoteProperty(note, "mime"); + const mimeTypes = useMimeTypes(); + const correspondingMimeType = useMemo(() => ( + mimeTypes.find(m => m.mime === currentNoteMime) + ), [ mimeTypes, currentNoteMime ]); + + return ( + + server.put(`notes/${note.noteId}/type`, { type, mime })} + setModalShown={() => {}} + /> + + ); +} +//#endregion diff --git a/apps/client/src/widgets/ribbon/BasicPropertiesTab.tsx b/apps/client/src/widgets/ribbon/BasicPropertiesTab.tsx index 761577949..75887c0b4 100644 --- a/apps/client/src/widgets/ribbon/BasicPropertiesTab.tsx +++ b/apps/client/src/widgets/ribbon/BasicPropertiesTab.tsx @@ -1,4 +1,4 @@ -import { NoteType, ToggleInParentResponse } from "@triliumnext/commons"; +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"; @@ -66,12 +66,8 @@ function NoteTypeWidget({ note }: { note?: FNote | null }) { } export function NoteTypeDropdownContent({ currentNoteType, currentNoteMime, note, setModalShown }: { currentNoteType?: NoteType, currentNoteMime?: string | null, note?: FNote | null, setModalShown: Dispatch> }) { - const [ codeNotesMimeTypes ] = useTriliumOption("codeNotesMimeTypes"); + const mimeTypes = useMimeTypes(); const noteTypes = useMemo(() => NOTE_TYPES.filter((nt) => !nt.reserved && !nt.static), []); - const mimeTypes = useMemo(() => { - mime_types.loadMimeTypes(); - return mime_types.getMimeTypes().filter(mimeType => mimeType.enabled); - }, [ codeNotesMimeTypes ]); const changeNoteType = useCallback(async (type: NoteType, mime?: string) => { if (!note || (type === currentNoteType && mime === currentNoteMime)) { return; @@ -130,8 +126,23 @@ export function NoteTypeDropdownContent({ currentNoteType, currentNoteMime, note } })} + + + ); +} + +export function NoteTypeCodeNoteList({ mimeTypes, changeNoteType, setModalShown }: { + mimeTypes: MimeType[]; + changeNoteType(type: NoteType, mime: string): void; + setModalShown(shown: boolean): void; +}) { + return ( + <> {mimeTypes.map(({ title, mime }) => ( - changeNoteType("code", mime)}> + changeNoteType("code", mime)} + > {title} ))} @@ -142,6 +153,15 @@ export function NoteTypeDropdownContent({ currentNoteType, currentNoteMime, note ); } +export function useMimeTypes() { + const [ codeNotesMimeTypes ] = useTriliumOption("codeNotesMimeTypes"); + const mimeTypes = useMemo(() => { + mime_types.loadMimeTypes(); + return mime_types.getMimeTypes().filter(mimeType => mimeType.enabled); + }, [ codeNotesMimeTypes ]); // eslint-disable-line react-hooks/exhaustive-deps + return mimeTypes; +} + function NoteTypeOptionsModal({ modalShown, setModalShown }: { modalShown: boolean, setModalShown: (shown: boolean) => void }) { return (