diff --git a/apps/client/src/widgets/NoteDetail.tsx b/apps/client/src/widgets/NoteDetail.tsx index a5bc62916..894bb4ac5 100644 --- a/apps/client/src/widgets/NoteDetail.tsx +++ b/apps/client/src/widgets/NoteDetail.tsx @@ -1,16 +1,18 @@ -import { useNoteContext, useTriliumEvent } from "./react/hooks" -import FNote from "../entities/fnote"; -import protected_session_holder from "../services/protected_session_holder"; -import { useEffect, useRef, useState } from "preact/hooks"; -import NoteContext from "../components/note_context"; -import { isValidElement, VNode } from "preact"; -import { TypeWidgetProps } from "./type_widgets/type_widget"; import "./NoteDetail.css"; + +import { isValidElement, VNode } from "preact"; +import { useEffect, useRef, useState } from "preact/hooks"; + +import NoteContext from "../components/note_context"; +import FNote from "../entities/fnote"; import attributes from "../services/attributes"; -import { ExtendedNoteType, TYPE_MAPPINGS, TypeWidget } from "./note_types"; -import { dynamicRequire, isElectron, isMobile } from "../services/utils"; -import toast from "../services/toast.js"; import { t } from "../services/i18n"; +import protected_session_holder from "../services/protected_session_holder"; +import toast from "../services/toast.js"; +import { dynamicRequire, isElectron, isMobile } from "../services/utils"; +import { ExtendedNoteType, TYPE_MAPPINGS, TypeWidget } from "./note_types"; +import { useNoteContext, useTriliumEvent } from "./react/hooks"; +import { TypeWidgetProps } from "./type_widgets/type_widget"; /** * The note detail is in charge of rendering the content of a note, by determining its type (e.g. text, code) and using the appropriate view widget. @@ -80,7 +82,7 @@ export default function NoteDetail() { parentComponent.handleEvent("noteTypeMimeChanged", { noteId: note.noteId }); } else if (note.noteId && loadResults.isNoteReloaded(note.noteId, parentComponent.componentId) - && (type !== (await getWidgetType(note, noteContext)) || mime !== note?.mime)) { + && (type !== (await getExtendedWidgetType(note, noteContext)) || mime !== note?.mime)) { // this needs to have a triggerEvent so that e.g., note type (not in the component subtree) is updated parentComponent.triggerEvent("noteTypeMimeChanged", { noteId: note.noteId }); } else { @@ -212,7 +214,7 @@ export default function NoteDetail() { isVisible={type === itemType} isFullHeight={isFullHeight} props={props} - /> + />; })} ); @@ -254,7 +256,7 @@ function useNoteInfo() { const [ mime, setMime ] = useState(); function refresh() { - getWidgetType(actualNote, noteContext).then(type => { + getExtendedWidgetType(actualNote, noteContext).then(type => { setNote(actualNote); setType(type); setMime(actualNote?.mime); @@ -282,12 +284,12 @@ async function getCorrespondingWidget(type: ExtendedNoteType): Promise { +export async function getExtendedWidgetType(note: FNote | null | undefined, noteContext: NoteContext | undefined): Promise { if (!noteContext) return undefined; if (!note) { // If the note is null, then it's a new tab. If it's undefined, then it's not loaded yet. @@ -324,7 +326,7 @@ async function getWidgetType(note: FNote | null | undefined, noteContext: NoteCo return resultingType; } -function checkFullHeight(noteContext: NoteContext | undefined, type: ExtendedNoteType | undefined) { +export function checkFullHeight(noteContext: NoteContext | undefined, type: ExtendedNoteType | undefined) { if (!noteContext) return false; // https://github.com/zadam/trilium/issues/2522 diff --git a/apps/client/src/widgets/layout/NoteTitleActions.tsx b/apps/client/src/widgets/layout/NoteTitleActions.tsx index 9678084f6..a04bfc242 100644 --- a/apps/client/src/widgets/layout/NoteTitleActions.tsx +++ b/apps/client/src/widgets/layout/NoteTitleActions.tsx @@ -1,22 +1,25 @@ import "./NoteTitleActions.css"; import clsx from "clsx"; +import { useEffect, useState } from "preact/hooks"; +import NoteContext from "../../components/note_context"; import FNote from "../../entities/fnote"; import { t } from "../../services/i18n"; import CollectionProperties from "../note_bars/CollectionProperties"; +import { checkFullHeight, getExtendedWidgetType } from "../NoteDetail"; import { PromotedAttributesContent, usePromotedAttributeData } from "../PromotedAttributes"; -import Collapsible from "../react/Collapsible"; +import Collapsible, { ExternallyControlledCollapsible } from "../react/Collapsible"; import { useNoteContext, useNoteProperty } from "../react/hooks"; import SearchDefinitionTab from "../ribbon/SearchDefinitionTab"; export default function NoteTitleActions() { - const { note, ntxId, componentId } = useNoteContext(); + const { note, ntxId, componentId, noteContext } = useNoteContext(); const isHiddenNote = note && note.noteId !== "_search" && note.noteId.startsWith("_"); const noteType = useNoteProperty(note, "type"); const items = [ - note && , + note && , note && noteType === "search" && , note && !isHiddenNote && noteType === "book" && ].filter(Boolean); @@ -39,15 +42,29 @@ function SearchProperties({ note, ntxId }: { note: FNote, ntxId: string | null | ); } -function PromotedAttributes({ note, componentId }: { note: FNote | null | undefined, componentId: string }) { +function PromotedAttributes({ note, componentId, noteContext }: { + note: FNote | null | undefined, + componentId: string, + noteContext: NoteContext | undefined +}) { const [ cells, setCells ] = usePromotedAttributeData(note, componentId); - if (!cells?.length) return false; + const [ expanded, setExpanded ] = useState(false); + useEffect(() => { + getExtendedWidgetType(note, noteContext).then(extendedNoteType => { + const fullHeight = checkFullHeight(noteContext, extendedNoteType); + setExpanded(!fullHeight); + }); + }, [ note, noteContext ]); + + if (!cells?.length) return false; return (note && ( - - + )); } diff --git a/apps/client/src/widgets/react/Collapsible.tsx b/apps/client/src/widgets/react/Collapsible.tsx index 2bf5be43d..e98e3782f 100644 --- a/apps/client/src/widgets/react/Collapsible.tsx +++ b/apps/client/src/widgets/react/Collapsible.tsx @@ -13,10 +13,17 @@ interface CollapsibleProps extends Pick, "classNa initiallyExpanded?: boolean; } -export default function Collapsible({ title, children, className, initiallyExpanded }: CollapsibleProps) { +export default function Collapsible({ initiallyExpanded, ...restProps }: CollapsibleProps) { + const [ expanded, setExpanded ] = useState(initiallyExpanded); + return ; +} + +export function ExternallyControlledCollapsible({ title, children, className, expanded, setExpanded }: Omit & { + expanded: boolean | undefined; + setExpanded: (expanded: boolean) => void +}) { const bodyRef = useRef(null); const innerRef = useRef(null); - const [ expanded, setExpanded ] = useState(initiallyExpanded); const { height } = useElementSize(innerRef) ?? {}; const contentId = useUniqueName(); @@ -48,5 +55,4 @@ export default function Collapsible({ title, children, className, initiallyExpan ); - }