feat(layout): move the note actions into the breadcrumb area

This commit is contained in:
Elian Doran 2025-12-09 20:04:28 +02:00
parent e58d6bf2a3
commit fe7ca210dd
No known key found for this signature in database
4 changed files with 134 additions and 133 deletions

View File

@ -47,6 +47,7 @@ import LauncherContainer from "../widgets/launch_bar/LauncherContainer.jsx";
import Breadcrumb from "../widgets/Breadcrumb.jsx";
import TabHistoryNavigationButtons from "../widgets/TabHistoryNavigationButtons.jsx";
import { experimentalFeatures, isExperimentalFeatureEnabled } from "../services/experimental_features.js";
import NoteActions from "../widgets/ribbon/NoteActions.jsx";
export default class DesktopLayout {
@ -139,13 +140,14 @@ export default class DesktopLayout {
.child(<MovePaneButton direction="right" />)
.child(<ClosePaneButton />)
.child(<CreatePaneButton />)
.optChild(isNewLayout, <NoteActions />)
)
.child(new FlexContainer("row")
.class("title-row")
.child(<NoteIconWidget />)
.child(<NoteTitleWidget />)
)
.optChild(!isNewLayout, <Ribbon />)
.optChild(!isNewLayout, <Ribbon><NoteActions /></Ribbon>)
.child(new WatchedFileUpdateStatusWidget())
.child(<FloatingButtons items={DESKTOP_FLOATING_BUTTONS} />)
.child(

View File

@ -1,33 +1,29 @@
import { ConvertToAttachmentResponse } from "@triliumnext/commons";
import { FormDropdownDivider, FormListHeader, FormListItem } from "../react/FormList";
import { isElectron as getIsElectron, isMac as getIsMac } from "../../services/utils";
import { ParentComponent } from "../react/react_utils";
import { t } from "../../services/i18n"
import { useContext } from "preact/hooks";
import { useIsNoteReadOnly, useNoteLabel, useNoteProperty } from "../react/hooks";
import { useTriliumOption } from "../react/hooks";
import ActionButton from "../react/ActionButton"
import appContext, { CommandNames } from "../../components/app_context";
import NoteContext from "../../components/note_context";
import FNote from "../../entities/fnote";
import branches from "../../services/branches";
import dialog from "../../services/dialog";
import Dropdown from "../react/Dropdown";
import FNote from "../../entities/fnote"
import NoteContext from "../../components/note_context";
import { t } from "../../services/i18n";
import server from "../../services/server";
import toast from "../../services/toast";
import { isElectron as getIsElectron, isMac as getIsMac } from "../../services/utils";
import ws from "../../services/ws";
import ActionButton from "../react/ActionButton";
import Dropdown from "../react/Dropdown";
import { FormDropdownDivider, FormListHeader, FormListItem } from "../react/FormList";
import { useIsNoteReadOnly, useNoteContext, useNoteLabel, useNoteProperty, useTriliumOption } from "../react/hooks";
import { ParentComponent } from "../react/react_utils";
interface NoteActionsProps {
note?: FNote;
noteContext?: NoteContext;
}
export default function NoteActions({ note, noteContext }: NoteActionsProps) {
export default function NoteActions() {
const { note, noteContext } = useNoteContext();
return (
<>
<div className="ribbon-button-container" style={{ contain: "none" }}>
{note && <RevisionsButton note={note} />}
{note && note.type !== "launcher" && <NoteContextMenu note={note as FNote} noteContext={noteContext}/>}
</>
{note && note.type !== "launcher" && <NoteContextMenu note={note as FNote} noteContext={noteContext} />}
</div>
);
}
@ -47,7 +43,7 @@ function RevisionsButton({ note }: { note: FNote }) {
function NoteContextMenu({ note, noteContext }: { note: FNote, noteContext?: NoteContext }) {
const parentComponent = useContext(ParentComponent);
const noteType = useNoteProperty(note, "type") ?? "";
const [ viewType ] = useNoteLabel(note, "viewType");
const [viewType] = useNoteLabel(note, "viewType");
const canBeConvertedToAttachment = note?.isEligibleForConversionToAttachment();
const isSearchable = ["text", "code", "book", "mindMap", "doc"].includes(noteType);
const isInOptionsOrHelp = note?.noteId.startsWith("_options") || note?.noteId.startsWith("_help");
@ -56,8 +52,8 @@ function NoteContextMenu({ note, noteContext }: { note: FNote, noteContext?: Not
const isMac = getIsMac();
const hasSource = ["text", "code", "relationMap", "mermaid", "canvas", "mindMap", "aiChat"].includes(noteType);
const isSearchOrBook = ["search", "book"].includes(noteType);
const [ syncServerHost ] = useTriliumOption("syncServerHost");
const {isReadOnly, enableEditing} = useIsNoteReadOnly(note, noteContext);
const [syncServerHost] = useTriliumOption("syncServerHost");
const { isReadOnly, enableEditing } = useIsNoteReadOnly(note, noteContext);
return (
<Dropdown
@ -73,7 +69,7 @@ function NoteContextMenu({ note, noteContext }: { note: FNote, noteContext?: Not
<FormDropdownDivider />
</>}
{canBeConvertedToAttachment && <ConvertToAttachment note={note} /> }
{canBeConvertedToAttachment && <ConvertToAttachment note={note} />}
{note.type === "render" && <CommandItem command="renderActiveNote" icon="bx bx-extension" text={t("note_actions.re_render_note")} />}
<CommandItem command="findInText" icon="bx bx-search" disabled={!isSearchable} text={t("note_actions.search_in_note")} />
<CommandItem command="printActiveNote" icon="bx bx-printer" disabled={!isPrintable} text={t("note_actions.print_note")} />
@ -131,7 +127,7 @@ function DevelopmentActions({ note, noteContext }: { note: FNote, noteContext?:
});
}}>Crash editor</FormListItem>)}
</>
)
);
}
function CommandItem({ icon, text, title, command, disabled }: { icon: string, text: string, title?: string, command: CommandNames | (() => void), disabled?: boolean, destructive?: boolean }) {
@ -141,7 +137,7 @@ function CommandItem({ icon, text, title, command, disabled }: { icon: string, t
triggerCommand={typeof command === "string" ? command : undefined}
onClick={typeof command === "function" ? command : undefined}
disabled={disabled}
>{text}</FormListItem>
>{text}</FormListItem>;
}
function ConvertToAttachment({ note }: { note: FNote }) {
@ -170,5 +166,5 @@ function ConvertToAttachment({ note }: { note: FNote }) {
});
}}
>{t("note_actions.convert_into_attachment")}</FormListItem>
)
);
}

View File

@ -16,7 +16,7 @@ interface ComputedTab extends Indexed<TabConfiguration> {
shouldShow: boolean;
}
export default function Ribbon() {
export default function Ribbon({ children }: { children?: preact.ComponentChildren }) {
const { note, ntxId, hoistedNoteId, notePath, noteContext, componentId, isReadOnlyTemporarilyDisabled } = useNoteContext();
const noteType = useNoteProperty(note, "type");
const [ activeTabIndex, setActiveTabIndex ] = useState<number | undefined>();
@ -99,9 +99,7 @@ export default function Ribbon() {
/>
))}
</div>
<div className="ribbon-button-container">
{ note && <NoteActions note={note} noteContext={noteContext} /> }
</div>
{children}
</div>
<div className="ribbon-body-container">

View File

@ -417,15 +417,20 @@ body[dir=rtl] .attribute-list-editor {
/* #endregion */
/* #region Experimental layout */
body.experimental-feature-new-layout .ribbon-container {
body.experimental-feature-new-layout {
.ribbon-container {
display: flex;
flex-direction: column-reverse;
border-top: 1px solid var(--main-border-color);
.ribbon-tab-spacer,
.ribbon-button-container,
.ribbon-body {
border-bottom: 0 !important;
}
}
.ribbon-button-container {
border-bottom: 0 !important;
}
}
/* #endregion */