From 0eed72b88843b3a7aad1c64d69cd52ebb56ffb50 Mon Sep 17 00:00:00 2001 From: Elian Doran Date: Thu, 11 Dec 2025 18:53:48 +0200 Subject: [PATCH] feat(note_bars): view type switcher --- apps/client/src/widgets/NoteTitleDetails.tsx | 45 ++------------- .../note_bars/CollectionProperties.tsx | 29 ++++++++++ apps/client/src/widgets/note_title.css | 3 +- .../ribbon/CollectionPropertiesTab.tsx | 55 +++++++++++-------- 4 files changed, 67 insertions(+), 65 deletions(-) create mode 100644 apps/client/src/widgets/note_bars/CollectionProperties.tsx diff --git a/apps/client/src/widgets/NoteTitleDetails.tsx b/apps/client/src/widgets/NoteTitleDetails.tsx index c9992578f..60618ecb5 100644 --- a/apps/client/src/widgets/NoteTitleDetails.tsx +++ b/apps/client/src/widgets/NoteTitleDetails.tsx @@ -1,46 +1,13 @@ -import { type ComponentChild } from "preact"; - -import { formatDateTime } from "../utils/formatters"; -import { useNoteContext, useStaticTooltip } from "./react/hooks"; -import { joinElements } from "./react/react_utils"; -import { useNoteMetadata } from "./ribbon/NoteInfoTab"; -import { Trans } from "react-i18next"; -import { useRef } from "preact/hooks"; +import CollectionProperties from "./note_bars/CollectionProperties"; +import { useNoteContext, useNoteProperty } from "./react/hooks"; export default function NoteTitleDetails() { - const { note, noteContext } = useNoteContext(); - const isHiddenNote = note?.noteId.startsWith("_"); - const isDefaultView = noteContext?.viewScope?.viewMode === "default"; + const { note } = useNoteContext(); + const noteType = useNoteProperty(note, "type"); - const items: ComponentChild[] = [].filter(item => !!item); - - return items.length && ( + return (
- {joinElements(items, " • ")} + {note && noteType === "book" && }
); } - -function TextWithValue({ i18nKey, value, valueTooltip }: { - i18nKey: string; - value: string; - valueTooltip: string; -}) { - const listItemRef = useRef(null); - useStaticTooltip(listItemRef, { - selector: "span.value", - title: valueTooltip, - popperConfig: { placement: "bottom" } - }); - - return ( -
  • - {value} as React.ReactElement - }} - /> -
  • - ); -} diff --git a/apps/client/src/widgets/note_bars/CollectionProperties.tsx b/apps/client/src/widgets/note_bars/CollectionProperties.tsx new file mode 100644 index 000000000..8436f3af6 --- /dev/null +++ b/apps/client/src/widgets/note_bars/CollectionProperties.tsx @@ -0,0 +1,29 @@ +import FNote from "../../entities/fnote"; +import { ViewTypeOptions } from "../collections/interface"; +import Dropdown from "../react/Dropdown"; +import { FormListItem } from "../react/FormList"; +import { useViewType, VIEW_TYPE_MAPPINGS } from "../ribbon/CollectionPropertiesTab"; + +export default function CollectionProperties({ note }: { note: FNote }) { + return ( + + ); +} + +function ViewTypeSwitcher({ note }: { note: FNote }) { + const [ viewType, setViewType ] = useViewType(note); + + return ( + + {Object.entries(VIEW_TYPE_MAPPINGS).map(([ key, label ]) => ( + setViewType(key)} + checked={viewType === key} + >{label} + ))} + + ); +} diff --git a/apps/client/src/widgets/note_title.css b/apps/client/src/widgets/note_title.css index 174c7d786..668695cd9 100644 --- a/apps/client/src/widgets/note_title.css +++ b/apps/client/src/widgets/note_title.css @@ -89,8 +89,7 @@ body.experimental-feature-new-layout { } .title-details { - margin-bottom: 0.2em; - opacity: 0.65; + padding-bottom: 0.2em; font-size: 0.8em; } } diff --git a/apps/client/src/widgets/ribbon/CollectionPropertiesTab.tsx b/apps/client/src/widgets/ribbon/CollectionPropertiesTab.tsx index 374633c49..7df070879 100644 --- a/apps/client/src/widgets/ribbon/CollectionPropertiesTab.tsx +++ b/apps/client/src/widgets/ribbon/CollectionPropertiesTab.tsx @@ -12,34 +12,41 @@ import FormCheckbox from "../react/FormCheckbox"; import FormTextBox from "../react/FormTextBox"; import { ComponentChildren } from "preact"; import { ViewTypeOptions } from "../collections/interface"; -import { FormDropdownDivider, FormListItem } from "../react/FormList"; +import { isExperimentalFeatureEnabled } from "../../services/experimental_features"; -const VIEW_TYPE_MAPPINGS: Record = { - grid: t("book_properties.grid"), - list: t("book_properties.list"), - calendar: t("book_properties.calendar"), - table: t("book_properties.table"), - geoMap: t("book_properties.geo-map"), - board: t("book_properties.board"), - presentation: t("book_properties.presentation") +export const VIEW_TYPE_MAPPINGS: Record = { + grid: t("book_properties.grid"), + list: t("book_properties.list"), + calendar: t("book_properties.calendar"), + table: t("book_properties.table"), + geoMap: t("book_properties.geo-map"), + board: t("book_properties.board"), + presentation: t("book_properties.presentation") }; -export default function CollectionPropertiesTab({ note }: TabContext) { - const [ viewType, setViewType ] = useNoteLabel(note, "viewType"); - const defaultViewType = (note?.type === "search" ? "list" : "grid"); - const viewTypeWithDefault = (viewType ?? defaultViewType) as ViewTypeOptions; - const properties = bookPropertiesConfig[viewTypeWithDefault].properties; +const isNewLayout = isExperimentalFeatureEnabled("new-layout"); - return ( -
    - {note && ( - <> - - - - )} -
    - ); +export default function CollectionPropertiesTab({ note }: TabContext) { + const [viewType, setViewType] = useViewType(note); + const properties = bookPropertiesConfig[viewType].properties; + + return ( +
    + {note && ( + <> + {!isNewLayout && } + + + )} +
    + ); +} + +export function useViewType(note: FNote | null | undefined) { + const [ viewType, setViewType ] = useNoteLabel(note, "viewType"); + const defaultViewType = (note?.type === "search" ? "list" : "grid"); + const viewTypeWithDefault = (viewType ?? defaultViewType) as ViewTypeOptions; + return [ viewTypeWithDefault, setViewType ] as const; } function CollectionTypeSwitcher({ viewType, setViewType }: { viewType: string, setViewType: (newValue: string) => void }) {