mirror of
https://github.com/zadam/trilium.git
synced 2025-12-15 12:49:53 +01:00
feat(status_bar): code mime switcher
This commit is contained in:
@@ -2163,6 +2163,7 @@
|
|||||||
"attributes_one": "{{count}} attribute",
|
"attributes_one": "{{count}} attribute",
|
||||||
"attributes_other": "{{count}} attributes",
|
"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.",
|
"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"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,10 +17,10 @@ import { formatDateTime } from "../../utils/formatters";
|
|||||||
import { BacklinksList, useBacklinkCount } from "../FloatingButtonsDefinitions";
|
import { BacklinksList, useBacklinkCount } from "../FloatingButtonsDefinitions";
|
||||||
import Dropdown, { DropdownProps } from "../react/Dropdown";
|
import Dropdown, { DropdownProps } from "../react/Dropdown";
|
||||||
import { FormDropdownDivider, FormListItem } from "../react/FormList";
|
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 Icon from "../react/Icon";
|
||||||
import { ParentComponent } from "../react/react_utils";
|
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 AttributeEditor, { AttributeEditorImperativeHandlers } from "../ribbon/components/AttributeEditor";
|
||||||
import InheritedAttributesTab from "../ribbon/InheritedAttributesTab";
|
import InheritedAttributesTab from "../ribbon/InheritedAttributesTab";
|
||||||
import { NoteSizeWidget, useNoteMetadata } from "../ribbon/NoteInfoTab";
|
import { NoteSizeWidget, useNoteMetadata } from "../ribbon/NoteInfoTab";
|
||||||
@@ -28,6 +28,7 @@ import { NotePathsWidget, useSortedNotePaths } from "../ribbon/NotePathsTab";
|
|||||||
import { useAttachments } from "../type_widgets/Attachment";
|
import { useAttachments } from "../type_widgets/Attachment";
|
||||||
import { useProcessedLocales } from "../type_widgets/options/components/LocaleSelector";
|
import { useProcessedLocales } from "../type_widgets/options/components/LocaleSelector";
|
||||||
import Breadcrumb from "./Breadcrumb";
|
import Breadcrumb from "./Breadcrumb";
|
||||||
|
import server from "../../services/server";
|
||||||
|
|
||||||
interface StatusBarContext {
|
interface StatusBarContext {
|
||||||
note: FNote;
|
note: FNote;
|
||||||
@@ -53,6 +54,7 @@ export default function StatusBar() {
|
|||||||
<Breadcrumb {...context} />
|
<Breadcrumb {...context} />
|
||||||
|
|
||||||
<div className="actions-row">
|
<div className="actions-row">
|
||||||
|
<CodeNoteSwitcher {...context} />
|
||||||
<LanguageSwitcher {...context} />
|
<LanguageSwitcher {...context} />
|
||||||
{!isHiddenNote && <NotePaths {...context} />}
|
{!isHiddenNote && <NotePaths {...context} />}
|
||||||
<AttributesButton {...attributesContext} />
|
<AttributesButton {...attributesContext} />
|
||||||
@@ -75,15 +77,19 @@ function StatusBarDropdown({ children, icon, text, buttonClassName, titleOptions
|
|||||||
buttonClassName={clsx("status-bar-dropdown-button", buttonClassName)}
|
buttonClassName={clsx("status-bar-dropdown-button", buttonClassName)}
|
||||||
titlePosition="top"
|
titlePosition="top"
|
||||||
titleOptions={{
|
titleOptions={{
|
||||||
...titleOptions,
|
|
||||||
popperConfig: {
|
popperConfig: {
|
||||||
...titleOptions?.popperConfig,
|
...titleOptions?.popperConfig,
|
||||||
strategy: "fixed"
|
strategy: "fixed"
|
||||||
}
|
},
|
||||||
|
...titleOptions
|
||||||
}}
|
}}
|
||||||
dropdownOptions={{
|
dropdownOptions={{
|
||||||
...dropdownOptions,
|
autoClose: "outside",
|
||||||
autoClose: "outside"
|
popperConfig: {
|
||||||
|
strategy: "fixed",
|
||||||
|
placement: "top"
|
||||||
|
},
|
||||||
|
...dropdownOptions
|
||||||
}}
|
}}
|
||||||
text={<>
|
text={<>
|
||||||
{icon && (<><Icon icon={icon} /> </>)}
|
{icon && (<><Icon icon={icon} /> </>)}
|
||||||
@@ -340,3 +346,28 @@ function NotePaths({ note, hoistedNoteId, notePath }: StatusBarContext) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
//#endregion
|
//#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 (
|
||||||
|
<StatusBarDropdown
|
||||||
|
icon="bx bx-code-curly"
|
||||||
|
text={correspondingMimeType?.title}
|
||||||
|
title={t("status_bar.code_note_switcher")}
|
||||||
|
dropdownOptions={{ autoClose: true }}
|
||||||
|
>
|
||||||
|
<NoteTypeCodeNoteList
|
||||||
|
mimeTypes={mimeTypes}
|
||||||
|
changeNoteType={(type, mime) => server.put(`notes/${note.noteId}/type`, { type, mime })}
|
||||||
|
setModalShown={() => {}}
|
||||||
|
/>
|
||||||
|
</StatusBarDropdown>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
//#endregion
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { NoteType, ToggleInParentResponse } from "@triliumnext/commons";
|
import { MimeType, NoteType, ToggleInParentResponse } from "@triliumnext/commons";
|
||||||
import { ComponentChildren } from "preact";
|
import { ComponentChildren } from "preact";
|
||||||
import { createPortal } from "preact/compat";
|
import { createPortal } from "preact/compat";
|
||||||
import { Dispatch, StateUpdater, useCallback, useEffect, useMemo, useState } from "preact/hooks";
|
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<StateUpdater<boolean>> }) {
|
export function NoteTypeDropdownContent({ currentNoteType, currentNoteMime, note, setModalShown }: { currentNoteType?: NoteType, currentNoteMime?: string | null, note?: FNote | null, setModalShown: Dispatch<StateUpdater<boolean>> }) {
|
||||||
const [ codeNotesMimeTypes ] = useTriliumOption("codeNotesMimeTypes");
|
const mimeTypes = useMimeTypes();
|
||||||
const noteTypes = useMemo(() => NOTE_TYPES.filter((nt) => !nt.reserved && !nt.static), []);
|
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) => {
|
const changeNoteType = useCallback(async (type: NoteType, mime?: string) => {
|
||||||
if (!note || (type === currentNoteType && mime === currentNoteMime)) {
|
if (!note || (type === currentNoteType && mime === currentNoteMime)) {
|
||||||
return;
|
return;
|
||||||
@@ -130,8 +126,23 @@ export function NoteTypeDropdownContent({ currentNoteType, currentNoteMime, note
|
|||||||
}
|
}
|
||||||
})}
|
})}
|
||||||
|
|
||||||
|
<NoteTypeCodeNoteList mimeTypes={mimeTypes} changeNoteType={changeNoteType} setModalShown={setModalShown} />
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function NoteTypeCodeNoteList({ mimeTypes, changeNoteType, setModalShown }: {
|
||||||
|
mimeTypes: MimeType[];
|
||||||
|
changeNoteType(type: NoteType, mime: string): void;
|
||||||
|
setModalShown(shown: boolean): void;
|
||||||
|
}) {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
{mimeTypes.map(({ title, mime }) => (
|
{mimeTypes.map(({ title, mime }) => (
|
||||||
<FormListItem onClick={() => changeNoteType("code", mime)}>
|
<FormListItem
|
||||||
|
key={mime}
|
||||||
|
onClick={() => changeNoteType("code", mime)}
|
||||||
|
>
|
||||||
{title}
|
{title}
|
||||||
</FormListItem>
|
</FormListItem>
|
||||||
))}
|
))}
|
||||||
@@ -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 }) {
|
function NoteTypeOptionsModal({ modalShown, setModalShown }: { modalShown: boolean, setModalShown: (shown: boolean) => void }) {
|
||||||
return (
|
return (
|
||||||
<Modal
|
<Modal
|
||||||
|
|||||||
Reference in New Issue
Block a user