diff --git a/apps/website/pages/_app.tsx b/apps/website/pages/_app.tsx index 7fa01ce30..fdffe9c9a 100644 --- a/apps/website/pages/_app.tsx +++ b/apps/website/pages/_app.tsx @@ -43,6 +43,7 @@ export default function App({ Component, pageProps, emotionCache = clientSideEmo href: link.path, selected: matchPaths(link.path), badge: link.status && link.status !== "stable" ? : undefined, + icon: link.icon, renderItem: ({ children }: { children: ReactNode }) => ( {children} @@ -55,6 +56,7 @@ export default function App({ Component, pageProps, emotionCache = clientSideEmo if ("links" in link) { return { label: link.label, + icon: link.icon, items: normalizeNavTabs(link.links), } as GroupItem; } @@ -68,11 +70,11 @@ export default function App({ Component, pageProps, emotionCache = clientSideEmo for (const item of items) { if (isGroupItem(item)) { - const filteredChildren = filterNavTree(item.items, q); const matches = item.label.toLowerCase().includes(q); + const filteredChildren = matches ? item.items : filterNavTree(item.items, q); if (matches || filteredChildren.length > 0) { - result.push({ ...item, items: filteredChildren }); + result.push({ ...item, items: filteredChildren, defaultOpen: true }); } } else { if (item.label.toLowerCase().includes(q)) { @@ -85,12 +87,17 @@ export default function App({ Component, pageProps, emotionCache = clientSideEmo }; const navItems: Section[] = useMemo(() => { + const q = filter.trim().toLowerCase(); + return LinksSections.map((section) => { const baseItems = normalizeNavTabs(section.links); - const items = filter ? filterNavTree(baseItems, filter.trim().toLowerCase()) : baseItems; + const sectionMatches = section.label.toLowerCase().includes(q); + + const items = filter ? (sectionMatches ? baseItems : filterNavTree(baseItems, q)) : baseItems; + return { title: section.label, - items, + items: section.label === "Components" ? items.map((item) => ({ ...item, defaultOpen: true })) : items, }; }).filter((section) => section.items.length > 0); }, [currentPath, filter]); diff --git a/apps/website/screens/common/componentsList.json b/apps/website/screens/common/componentsList.json index 2d33c15f3..7a736d581 100644 --- a/apps/website/screens/common/componentsList.json +++ b/apps/website/screens/common/componentsList.json @@ -1,143 +1,368 @@ [ - { "label": "Accordion", "path": "/components/accordion", "status": "stable" }, - { "label": "Alert", "path": "/components/alert", "status": "stable" }, { - "label": "Application layout", + "label": "Content", + "icon": "folder_open", "links": [ { - "label": "Application layout", - "path": "/components/application-layout", - "status": "stable" + "label": "Accordion", + "path": "/components/accordion", + "status": "stable", + "icon": "menu_open" }, - { "label": "Footer", "path": "/components/footer", "status": "stable" }, - { "label": "Header", "path": "/components/header", "status": "stable" }, - { "label": "Sidenav", "path": "/components/sidenav", "status": "stable" } + { + "label": "Avatar", + "path": "/components/avatar", + "status": "experimental", + "icon": "filled_account_circle" + }, + { + "label": "Card", + "path": "/components/card", + "status": "stable", + "icon": "credit_card" + }, + { + "label": "Dialog", + "path": "/components/dialog", + "status": "stable", + "icon": "open_in_new" + }, + { + "label": "Divider", + "path": "/components/divider", + "status": "stable", + "icon": "border_left" + }, + { + "label": "Image", + "path": "/components/image", + "status": "stable", + "icon": "image" + }, + { + "label": "Wizard", + "path": "/components/wizard", + "status": "stable", + "icon": "auto_fix_high" + } ] }, { - "label": "Avatar", - "path": "/components/avatar", - "status": "experimental" - }, - { - "label": "Badge", - "path": "/components/badge", - "status": "stable" - }, - { "label": "Bleed", "path": "/components/bleed", "status": "stable" }, - { - "label": "Breadcrumbs", - "path": "/components/breadcrumbs", - "status": "stable" - }, - { - "label": "Bulleted list", - "path": "/components/bulleted-list", - "status": "stable" - }, - { "label": "Button", "path": "/components/button", "status": "stable" }, - { "label": "Card", "path": "/components/card", "status": "stable" }, - { "label": "Checkbox", "path": "/components/checkbox", "status": "stable" }, - { "label": "Chip", "path": "/components/chip", "status": "stable" }, - { - "label": "Container", - "path": "/components/container", - "status": "stable" - }, - { - "label": "Contextual menu", - "path": "/components/contextual-menu", - "status": "stable" - }, - { - "label": "Data grid", - "path": "/components/data-grid", - "status": "new" - }, - { - "label": "Date input", - "path": "/components/date-input", - "status": "stable" - }, - { "label": "Dialog", "path": "/components/dialog", "status": "stable" }, - { - "label": "Divider", - "path": "/components/divider", - "status": "stable" - }, - { "label": "Dropdown", "path": "/components/dropdown", "status": "stable" }, - { - "label": "File input", - "path": "/components/file-input", - "status": "stable" - }, - { "label": "Flex", "path": "/components/flex", "status": "stable" }, - { "label": "Grid", "path": "/components/grid", "status": "stable" }, - { "label": "Heading", "path": "/components/heading", "status": "stable" }, - { "label": "Image", "path": "/components/image", "status": "stable" }, - { "label": "Inset", "path": "/components/inset", "status": "stable" }, - { "label": "Link", "path": "/components/link", "status": "stable" }, - { "label": "Nav tabs", "path": "/components/nav-tabs", "status": "stable" }, - { - "label": "Number input", - "path": "/components/number-input", - "status": "stable" - }, - { "label": "Paginator", "path": "/components/paginator", "status": "stable" }, - { "label": "Paragraph", "path": "/components/paragraph", "status": "stable" }, - { - "label": "Password input", - "path": "/components/password-input", - "status": "stable" - }, - { - "label": "Progress bar", - "path": "/components/progress-bar", - "status": "stable" - }, - { "label": "Quick nav", "path": "/components/quick-nav", "status": "stable" }, - { - "label": "Radio group", - "path": "/components/radio-group", - "status": "stable" + "label": "Data visualization", + "icon": "insert_chart", + "links": [ + { + "label": "Data grid", + "path": "/components/data-grid", + "status": "new", + "icon": "table_rows" + }, + { + "label": "Paginator", + "path": "/components/paginator", + "status": "stable", + "icon": "last_page" + }, + { + "label": "Resultset table", + "path": "/components/resultset-table", + "status": "stable", + "icon": "table_chart" + }, + { + "label": "Table", + "path": "/components/table", + "status": "stable", + "icon": "table_chart" + } + ] }, { - "label": "Resultset table", - "path": "/components/resultset-table", - "status": "stable" + "label": "Feedback", + "icon": "feedback", + "links": [ + { + "label": "Alert", + "path": "/components/alert", + "status": "stable", + "icon": "filled_error" + }, + { + "label": "Progress bar", + "path": "/components/progress-bar", + "status": "stable", + "icon": "linear_scale" + }, + { + "label": "Spinner", + "path": "/components/spinner", + "status": "stable", + "icon": "autorenew" + }, + { + "label": "Toast", + "path": "/components/toast", + "status": "stable", + "icon": "chat_bubble" + }, + { + "label": "Tooltip", + "path": "/components/tooltip", + "status": "stable", + "icon": "question_answer" + } + ] }, - { "label": "Select", "path": "/components/select", "status": "stable" }, - { "label": "Slider", "path": "/components/slider", "status": "stable" }, - { "label": "Spinner", "path": "/components/spinner", "status": "stable" }, { - "label": "Status light", - "path": "/components/status-light", - "status": "stable" + "label": "Forms", + "icon": "assignment", + "links": [ + { + "label": "Button", + "path": "/components/button", + "status": "stable", + "icon": "smart_button" + }, + { + "label": "Checkbox", + "path": "/components/checkbox", + "status": "stable", + "icon": "filled_check_box" + }, + { + "label": "Date input", + "path": "/components/date-input", + "status": "stable", + "icon": "date_range" + }, + { + "label": "File input", + "path": "/components/file-input", + "status": "stable", + "icon": "filled_file_upload" + }, + { + "label": "Number input", + "path": "/components/number-input", + "status": "stable", + "icon": "pin" + }, + { + "label": "Password input", + "path": "/components/password-input", + "status": "stable", + "icon": "password" + }, + { + "label": "Radio group", + "path": "/components/radio-group", + "status": "stable", + "icon": "radio_button_checked" + }, + { + "label": "Select", + "path": "/components/select", + "status": "stable", + "icon": "expand_circle_down" + }, + { + "label": "Slider", + "path": "/components/slider", + "status": "stable", + "icon": "sliders" + }, + { + "label": "Switch", + "path": "/components/switch", + "status": "stable", + "icon": "toggle_on" + }, + { + "label": "Text input", + "path": "/components/text-input", + "status": "stable", + "icon": "input" + }, + { + "label": "Textarea", + "path": "/components/textarea", + "status": "stable", + "icon": "subject" + }, + { + "label": "Toggle group", + "path": "/components/toggle-group", + "status": "stable", + "icon": "toggle_off" + } + ] }, - { "label": "Switch", "path": "/components/switch", "status": "stable" }, - { "label": "Table", "path": "/components/table", "status": "stable" }, - { "label": "Tabs", "path": "/components/tabs", "status": "stable" }, { - "label": "Text input", - "path": "/components/text-input", - "status": "stable" + "label": "Layout", + "icon": "dashboard_customize", + "links": [ + { + "label": "Application level", + "icon": "view_quilt", + "links": [ + { + "label": "Application layout", + "path": "/components/application-layout", + "status": "stable", + "icon": "dashboard" + }, + { + "label": "Footer", + "path": "/components/footer", + "status": "stable", + "icon": "view_agenda" + }, + { + "label": "Header", + "path": "/components/header", + "status": "stable", + "icon": "view_day" + }, + { + "label": "Sidenav", + "path": "/components/sidenav", + "status": "stable", + "icon": "view_sidebar" + } + ] + }, + { + "label": "Bleed", + "path": "/components/bleed", + "status": "stable", + "icon": "vertical_align_center" + }, + { + "label": "Container", + "path": "/components/container", + "status": "stable", + "icon": "crop_square" + }, + { + "label": "Flex", + "path": "/components/flex", + "status": "stable", + "icon": "view_stream" + }, + { + "label": "Grid", + "path": "/components/grid", + "status": "stable", + "icon": "grid_on" + }, + { + "label": "Inset", + "path": "/components/inset", + "status": "stable", + "icon": "padding" + } + ] }, - { "label": "Textarea", "path": "/components/textarea", "status": "stable" }, - { "label": "Toast", "path": "/components/toast", "status": "stable" }, { - "label": "Toggle group", - "path": "/components/toggle-group", - "status": "stable" + "label": "Navigation", + "icon": "navigation", + "links": [ + { + "label": "Breadcrumbs", + "path": "/components/breadcrumbs", + "status": "stable", + "icon": "arrow_back" + }, + { + "label": "Contextual menu", + "path": "/components/contextual-menu", + "status": "stable", + "icon": "notes" + }, + { + "label": "Dropdown", + "path": "/components/dropdown", + "status": "stable", + "icon": "south" + }, + { + "label": "Link", + "path": "/components/link", + "status": "stable", + "icon": "link" + }, + { + "label": "Nav tabs", + "path": "/components/nav-tabs", + "status": "stable", + "icon": "tab" + }, + { + "label": "Quick nav", + "path": "/components/quick-nav", + "status": "stable", + "icon": "menu" + }, + { + "label": "Tabs", + "path": "/components/tabs", + "status": "stable", + "icon": "tabs" + } + ] }, { - "label": "Tooltip", - "path": "/components/tooltip", - "status": "stable" + "label": "Status", + "icon": "flag", + "links": [ + { + "label": "Badge", + "path": "/components/badge", + "status": "stable", + "icon": "filled_label" + }, + { + "label": "Chip", + "path": "/components/chip", + "status": "stable", + "icon": "toggle_off" + }, + { + "label": "Status light", + "path": "/components/status-light", + "status": "stable", + "icon": "filled_circle" + } + ] }, { - "label": "Typography", - "path": "/components/typography", - "status": "stable" - }, - { "label": "Wizard", "path": "/components/wizard", "status": "stable" } + "label": "Text", + "icon": "text_snippet", + "links": [ + { + "label": "Bulleted list", + "path": "/components/bulleted-list", + "status": "stable", + "icon": "format_list_bulleted" + }, + { + "label": "Heading", + "path": "/components/heading", + "status": "stable", + "icon": "title" + }, + { + "label": "Paragraph", + "path": "/components/paragraph", + "status": "stable", + "icon": "notes" + }, + { + "label": "Typography", + "path": "/components/typography", + "status": "stable", + "icon": "text_fields" + } + ] + } ] diff --git a/apps/website/screens/common/pagesList.tsx b/apps/website/screens/common/pagesList.tsx index ce2f32205..32f1f9f99 100644 --- a/apps/website/screens/common/pagesList.tsx +++ b/apps/website/screens/common/pagesList.tsx @@ -1,3 +1,4 @@ +import { SVG } from "../../../../packages/lib/src/common/utils"; import componentsList from "./componentsList.json"; export type ComponentStatus = "experimental" | "new" | "stable" | "legacy" | "deprecated"; @@ -6,11 +7,13 @@ export type LinkDetails = { label: string; path: string; status?: ComponentStatus; + icon?: string | SVG; }; export type LinksSectionDetails = { label: string; links: (LinkDetails | LinksSectionDetails)[]; + icon?: string | SVG; }; type NavigationLinks = { @@ -19,22 +22,23 @@ type NavigationLinks = { }; const overviewLinks: LinkDetails[] = [ - { label: "Introduction", path: "/overview/introduction" }, - { label: "Installation", path: "/overview/installation" }, - { label: "Component lifecycle", path: "/overview/component-lifecycle" }, - { label: "Releases", path: "/overview/releases" }, + { label: "Introduction", path: "/overview/introduction", icon: "info" }, + { label: "Installation", path: "/overview/installation", icon: "download" }, + { label: "Component lifecycle", path: "/overview/component-lifecycle", icon: "cycle" }, + { label: "Releases", path: "/overview/releases", icon: "deployed_code" }, ]; const utilitiesLinks: LinkDetails[] = [ { label: "Halstack provider", path: "/utilities/halstack-provider", + icon: "integration_instructions", }, ]; const principlesLinks: LinkDetails[] = [ - { label: "Data visualization", path: "/principles/data-visualization" }, - { label: "Localization", path: "/principles/localization" }, + { label: "Data visualization", path: "/principles/data-visualization", icon: "insert_chart" }, + { label: "Localization", path: "/principles/localization", icon: "language" }, ]; const tokensLinks: LinkDetails[] = [ @@ -44,14 +48,14 @@ const tokensLinks: LinkDetails[] = [ ]; const foundationsLinks: (LinkDetails | LinksSectionDetails)[] = [ - { label: "Color", path: "/foundations/color" }, - { label: "Elevation", path: "/foundations/elevation" }, - { label: "Height", path: "/foundations/height" }, - { label: "Iconography", path: "/foundations/iconography" }, - { label: "Layout", path: "/foundations/layout" }, - { label: "Spacing", path: "/foundations/spacing" }, - { label: "Tokens", links: tokensLinks }, - { label: "Typography", path: "/foundations/typography" }, + { label: "Color", path: "/foundations/color", icon: "palette" }, + { label: "Elevation", path: "/foundations/elevation", icon: "layers" }, + { label: "Height", path: "/foundations/height", icon: "height" }, + { label: "Iconography", path: "/foundations/iconography", icon: "emoji_symbols" }, + { label: "Layout", path: "/foundations/layout", icon: "grid_on" }, + { label: "Spacing", path: "/foundations/spacing", icon: "space_bar" }, + { label: "Tokens", links: tokensLinks, icon: "token" }, + { label: "Typography", path: "/foundations/typography", icon: "font_download" }, ]; const v16Links: LinkDetails[] = [ @@ -60,7 +64,7 @@ const v16Links: LinkDetails[] = [ { label: "Migrating tokens", path: "/migration/16/migrating-tokens" }, ]; -const migrationLinks: LinksSectionDetails[] = [{ label: "v16", links: v16Links }]; +const migrationLinks: LinksSectionDetails[] = [{ label: "v16", links: v16Links, icon: "deployed_code_update" }]; const componentsLinks = componentsList as (LinkDetails | LinksSectionDetails)[]; diff --git a/apps/website/screens/components/sidenav/code/SidenavCodePage.tsx b/apps/website/screens/components/sidenav/code/SidenavCodePage.tsx index 8aea4f519..1b67dfc4d 100644 --- a/apps/website/screens/components/sidenav/code/SidenavCodePage.tsx +++ b/apps/website/screens/components/sidenav/code/SidenavCodePage.tsx @@ -16,6 +16,7 @@ const itemTypeString = `{ const groupItemTypeString = `{ ${commonItemTypeString} + defaultOpen?: boolean; items: (Item | GroupItem)[]; }`; diff --git a/packages/lib/src/base-menu/GroupItem.tsx b/packages/lib/src/base-menu/GroupItem.tsx index 44af31428..17158c26c 100644 --- a/packages/lib/src/base-menu/GroupItem.tsx +++ b/packages/lib/src/base-menu/GroupItem.tsx @@ -13,7 +13,11 @@ const GroupItem = ({ items, ...props }: GroupItemProps) => { const NavigationTreeId = `sidenav-${useId()}`; const contextValue = useContext(BaseMenuContext) ?? {}; - const { groupSelected, isOpen, toggleOpen, hasPopOver, isHorizontal } = useGroupItem(items, contextValue); + const { groupSelected, isOpen, toggleOpen, hasPopOver, isHorizontal } = useGroupItem( + items, + contextValue, + props.defaultOpen + ); return hasPopOver ? ( <> diff --git a/packages/lib/src/base-menu/types.ts b/packages/lib/src/base-menu/types.ts index 86d70c0f9..adf2ea4fe 100644 --- a/packages/lib/src/base-menu/types.ts +++ b/packages/lib/src/base-menu/types.ts @@ -16,6 +16,7 @@ type Item = CommonItemProps & { type GroupItem = CommonItemProps & { items: (Item | GroupItem)[]; + defaultOpen?: boolean; }; type Section = { items: (Item | GroupItem)[]; title?: string }; type Props = { @@ -47,12 +48,11 @@ type Props = { }; type ItemWithId = Item & { id: number }; -type GroupItemWithId = { - badge?: ReactElement; - icon: string | SVG; + +type GroupItemWithId = Omit & { items: (ItemWithId | GroupItemWithId)[]; - label: string; }; + type SectionWithId = { items: (ItemWithId | GroupItemWithId)[]; title?: string }; type SingleItemProps = ItemWithId & { diff --git a/packages/lib/src/base-menu/useGroupItem.ts b/packages/lib/src/base-menu/useGroupItem.ts index 1bb2096f3..c24123ee1 100644 --- a/packages/lib/src/base-menu/useGroupItem.ts +++ b/packages/lib/src/base-menu/useGroupItem.ts @@ -8,11 +8,11 @@ const isGroupSelected = (items: GroupItemProps["items"], selectedItemId?: number else return !!item.selected; }); -export const useGroupItem = (items: GroupItemProps["items"], context: BaseMenuContextProps) => { +export const useGroupItem = (items: GroupItemProps["items"], context: BaseMenuContextProps, defaultOpen?: boolean) => { const groupMenuId = `group-menu-${useId()}`; const { selectedItemId, hasPopOver } = context ?? {}; const groupSelected = useMemo(() => isGroupSelected(items, selectedItemId), [items, selectedItemId]); - const [isOpen, setIsOpen] = useState(hasPopOver ? false : groupSelected && selectedItemId === -1); + const [isOpen, setIsOpen] = useState(hasPopOver ? false : (defaultOpen ?? (groupSelected && selectedItemId === -1))); const toggleOpen = () => setIsOpen((prev) => !prev); diff --git a/packages/lib/src/sidenav/types.ts b/packages/lib/src/sidenav/types.ts index 34e511b4e..f1a9fc5e0 100644 --- a/packages/lib/src/sidenav/types.ts +++ b/packages/lib/src/sidenav/types.ts @@ -57,6 +57,7 @@ type Item = CommonItemProps & { selected?: boolean; }; type GroupItem = CommonItemProps & { + defaultOpen?: boolean; items: (Item | GroupItem)[]; };