mirror of
https://github.com/zadam/trilium.git
synced 2025-11-10 16:39:02 +01:00
fix(ribbon): formatting toolbar displayed in read-only notes
This commit is contained in:
parent
8589f7f164
commit
532df6559a
@ -841,7 +841,7 @@ export function arrayEqual<T>(a: T[], b: T[]) {
|
||||
return true;
|
||||
}
|
||||
|
||||
type Indexed<T extends object> = T & { index: number };
|
||||
export type Indexed<T extends object> = T & { index: number };
|
||||
|
||||
/**
|
||||
* Given an object array, alters every object in the array to have an index field assigned to it.
|
||||
|
||||
@ -2,7 +2,7 @@ import { useCallback, useEffect, useMemo, useRef, useState } from "preact/hooks"
|
||||
import { useNoteContext, useNoteProperty, useStaticTooltipWithKeyboardShortcut, useTriliumEvents } from "../react/hooks";
|
||||
import "./style.css";
|
||||
|
||||
import { numberObjectsInPlace } from "../../services/utils";
|
||||
import { Indexed, numberObjectsInPlace } from "../../services/utils";
|
||||
import { EventNames } from "../../components/app_context";
|
||||
import NoteActions from "./NoteActions";
|
||||
import { KeyboardActionNames } from "@triliumnext/commons";
|
||||
@ -11,23 +11,39 @@ import { TabConfiguration, TitleContext } from "./ribbon-interface";
|
||||
|
||||
const TAB_CONFIGURATION = numberObjectsInPlace<TabConfiguration>(RIBBON_TAB_DEFINITIONS);
|
||||
|
||||
interface ComputedTab extends Indexed<TabConfiguration> {
|
||||
shouldShow: boolean;
|
||||
}
|
||||
|
||||
export default function Ribbon() {
|
||||
const { note, ntxId, hoistedNoteId, notePath, noteContext, componentId } = useNoteContext();
|
||||
const noteType = useNoteProperty(note, "type");
|
||||
const titleContext: TitleContext = { note };
|
||||
const [ activeTabIndex, setActiveTabIndex ] = useState<number | undefined>();
|
||||
const computedTabs = useMemo(
|
||||
() => TAB_CONFIGURATION.map(tab => {
|
||||
const shouldShow = typeof tab.show === "boolean" ? tab.show : tab.show?.(titleContext);
|
||||
return {
|
||||
const [ computedTabs, setComputedTabs ] = useState<ComputedTab[]>();
|
||||
const titleContext: TitleContext = useMemo(() => ({
|
||||
note,
|
||||
noteContext
|
||||
}), [ note, noteContext ]);
|
||||
|
||||
async function refresh() {
|
||||
const computedTabs: ComputedTab[] = [];
|
||||
for (const tab of TAB_CONFIGURATION) {
|
||||
const shouldShow = await shouldShowTab(tab.show, titleContext);
|
||||
computedTabs.push({
|
||||
...tab,
|
||||
shouldShow
|
||||
shouldShow: !!shouldShow
|
||||
});
|
||||
}
|
||||
}),
|
||||
[ titleContext, note, noteType ]);
|
||||
setComputedTabs(computedTabs);
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
refresh();
|
||||
}, [ note, noteType ]);
|
||||
|
||||
// Automatically activate the first ribbon tab that needs to be activated whenever a note changes.
|
||||
useEffect(() => {
|
||||
if (!computedTabs) return;
|
||||
const tabToActivate = computedTabs.find(tab => tab.shouldShow && (typeof tab.activate === "boolean" ? tab.activate : tab.activate?.(titleContext)));
|
||||
setActiveTabIndex(tabToActivate?.index);
|
||||
}, [ note?.noteId ]);
|
||||
@ -35,6 +51,7 @@ export default function Ribbon() {
|
||||
// Register keyboard shortcuts.
|
||||
const eventsToListenTo = useMemo(() => TAB_CONFIGURATION.filter(config => config.toggleCommand).map(config => config.toggleCommand) as EventNames[], []);
|
||||
useTriliumEvents(eventsToListenTo, useCallback((e, toggleCommand) => {
|
||||
if (!computedTabs) return;
|
||||
const correspondingTab = computedTabs.find(tab => tab.toggleCommand === toggleCommand);
|
||||
if (correspondingTab) {
|
||||
if (activeTabIndex !== correspondingTab.index) {
|
||||
@ -51,7 +68,7 @@ export default function Ribbon() {
|
||||
<>
|
||||
<div className="ribbon-top-row">
|
||||
<div className="ribbon-tab-container">
|
||||
{computedTabs.map(({ title, icon, index, toggleCommand, shouldShow }) => (
|
||||
{computedTabs && computedTabs.map(({ title, icon, index, toggleCommand, shouldShow }) => (
|
||||
shouldShow && <RibbonTab
|
||||
icon={icon}
|
||||
title={typeof title === "string" ? title : title(titleContext)}
|
||||
@ -74,7 +91,7 @@ export default function Ribbon() {
|
||||
</div>
|
||||
|
||||
<div className="ribbon-body-container">
|
||||
{computedTabs.map(tab => {
|
||||
{computedTabs && computedTabs.map(tab => {
|
||||
const isActive = tab.index === activeTabIndex;
|
||||
if (!isActive && !tab.stayInDom) {
|
||||
return;
|
||||
@ -129,3 +146,9 @@ function RibbonTab({ icon, title, active, onClick, toggleCommand }: { icon: stri
|
||||
)
|
||||
}
|
||||
|
||||
async function shouldShowTab(showConfig: boolean | ((context: TitleContext) => Promise<boolean | null | undefined> | boolean | null | undefined), context: TitleContext) {
|
||||
if (showConfig === null || showConfig === undefined) return true;
|
||||
if (typeof showConfig === "boolean") return showConfig;
|
||||
if ("then" in showConfig) return await showConfig(context);
|
||||
return showConfig(context);
|
||||
}
|
||||
|
||||
@ -21,7 +21,9 @@ export const RIBBON_TAB_DEFINITIONS: TabConfiguration[] = [
|
||||
{
|
||||
title: t("classic_editor_toolbar.title"),
|
||||
icon: "bx bx-text",
|
||||
show: ({ note }) => note?.type === "text" && options.get("textNoteEditorType") === "ckeditor-classic",
|
||||
show: async ({ note, noteContext }) => note?.type === "text"
|
||||
&& options.get("textNoteEditorType") === "ckeditor-classic"
|
||||
&& !(await noteContext?.isReadOnly()),
|
||||
toggleCommand: "toggleRibbonTabClassicEditor",
|
||||
content: FormattingToolbar,
|
||||
activate: true,
|
||||
|
||||
@ -16,13 +16,14 @@ export interface TabContext {
|
||||
|
||||
export interface TitleContext {
|
||||
note: FNote | null | undefined;
|
||||
noteContext: NoteContext | undefined;
|
||||
}
|
||||
|
||||
export interface TabConfiguration {
|
||||
title: string | ((context: TitleContext) => string);
|
||||
icon: string;
|
||||
content: (context: TabContext) => VNode | false;
|
||||
show: boolean | ((context: TitleContext) => boolean | null | undefined);
|
||||
show: boolean | ((context: TitleContext) => Promise<boolean | null | undefined> | boolean | null | undefined);
|
||||
toggleCommand?: KeyboardActionNames;
|
||||
activate?: boolean | ((context: TitleContext) => boolean);
|
||||
/**
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user