From fac41dadec2d252fced4da5bc1af213c42600009 Mon Sep 17 00:00:00 2001 From: Jimmy Svensson Date: Thu, 11 Apr 2024 09:54:40 +0200 Subject: [PATCH] feat: add main-menu styles and examples (#255) --- .../src/components/main-menu/main-menu.tsx | 76 +++++++++ .../src/components/story/story-status.tsx | 8 +- examples/src/main-page.tsx | 23 ++- examples/src/routing/route-map.tsx | 8 +- examples/src/routing/routes.ts | 2 +- .../examples/main-menu.tsx | 112 ------------- .../main-menu/examples/main-menu-vertical.tsx | 147 ++++++++++++++++++ .../stories/main-menu/examples/main-menu.tsx | 145 +++++++++++++++++ .../main-menu-page.tsx} | 33 ++-- styles/src/index.ts | 1 + styles/src/main-menu/main-menu.styles.ts | 93 +++++++++++ 11 files changed, 506 insertions(+), 142 deletions(-) create mode 100644 examples/src/components/main-menu/main-menu.tsx delete mode 100644 examples/src/stories/fluent-implementations/examples/main-menu.tsx create mode 100644 examples/src/stories/main-menu/examples/main-menu-vertical.tsx create mode 100644 examples/src/stories/main-menu/examples/main-menu.tsx rename examples/src/stories/{fluent-implementations/fluent-implementation-page.tsx => main-menu/main-menu-page.tsx} (56%) create mode 100644 styles/src/main-menu/main-menu.styles.ts diff --git a/examples/src/components/main-menu/main-menu.tsx b/examples/src/components/main-menu/main-menu.tsx new file mode 100644 index 00000000..86aa2840 --- /dev/null +++ b/examples/src/components/main-menu/main-menu.tsx @@ -0,0 +1,76 @@ +import { + useMainMenuContainerStyles, + useMainMenuTabListStyles, + useMainMenuTabStyles, +} from "@axiscommunications/fluent-styles"; +import { + Tab, + TabList, + TabProps, + useTabListContext_unstable, +} from "@fluentui/react-components"; +import { + bundleIcon, + CardUiFilled, + CardUiRegular, + HomeFilled, + HomeRegular, + SettingsFilled, + SettingsRegular, +} from "@fluentui/react-icons"; +import React, { useEffect, useState } from "react"; +import { useLocation, useNavigate } from "react-router-dom"; +import { routes } from "../../routing/routes"; + +const HomeIcon = bundleIcon(HomeFilled, HomeRegular); +const RandomIcon = bundleIcon(CardUiFilled, CardUiRegular); +const SettingsIcon = bundleIcon(SettingsFilled, SettingsRegular); + +const HOME_VALUE = "1"; + +export function MainMenu() { + const [selectedTab, setSelectedTab] = useState(HOME_VALUE); + const navigate = useNavigate(); + const { pathname } = useLocation(); + + useEffect(() => { + if (pathname === routes.Home) { + setSelectedTab(HOME_VALUE); + } + }, [pathname]); + + const { rootStyle: containerRootStyle } = useMainMenuContainerStyles(); + const { rootStyle, spacerStyle } = useMainMenuTabListStyles(); + + return ( +
+ { + setSelectedTab(value as unknown as string); + }} + > + navigate(routes.Home)} + icon={} + value={HOME_VALUE} + /> + } value="2" /> +
+ } value="3" /> + +
+ ); +} + +type TMainMenuTab = TabProps; + +function MainMenuTab({ children, ...props }: TMainMenuTab) { + const selected = useTabListContext_unstable((c) => c.selectedValue); + const { rootStyle } = useMainMenuTabStyles(selected === props.value); + return {children}; +} diff --git a/examples/src/components/story/story-status.tsx b/examples/src/components/story/story-status.tsx index f811ade7..fc55f778 100644 --- a/examples/src/components/story/story-status.tsx +++ b/examples/src/components/story/story-status.tsx @@ -24,7 +24,7 @@ const STATUS_BADGES: Record = { [EStoryStatus.WIP]: ( @@ -34,7 +34,7 @@ const STATUS_BADGES: Record = { [EStoryStatus.NEW]: ( @@ -44,7 +44,7 @@ const STATUS_BADGES: Record = { [EStoryStatus.STABLE]: ( @@ -54,7 +54,7 @@ const STATUS_BADGES: Record = { [EStoryStatus.UNSTABLE]: ( diff --git a/examples/src/main-page.tsx b/examples/src/main-page.tsx index 170b7b86..07c8b74c 100644 --- a/examples/src/main-page.tsx +++ b/examples/src/main-page.tsx @@ -1,15 +1,17 @@ -import { makeStyles, tokens } from "@fluentui/react-components"; +import { makeStyles } from "@fluentui/react-components"; import React from "react"; import { Outlet } from "react-router-dom"; +import { MainMenu } from "./components/main-menu/main-menu"; +import { NavigationMenu } from "./components/navigation-menu/navigation-menu"; import { Navbar } from "./components/top-bar"; import { Layout } from "./layout"; -import { useStaticStyles } from "./styles/static"; -import { NavigationMenu } from "./components/navigation-menu/navigation-menu"; import { useScrollToAnchor } from "./routing/use-scroll-to-anchor"; +import { useStaticStyles } from "./styles/static"; -export const useStyles = makeStyles({ - navigation: { - paddingRight: tokens.spacingHorizontalL, +const useStyles = makeStyles({ + navigationContainer: { + display: "flex", + height: "100%", }, }); @@ -17,10 +19,17 @@ export const MainPage = () => { useStaticStyles(); useScrollToAnchor(); + const styles = useStyles(); + return ( } - navigation={} + navigation={ +
+ + +
+ } content={} /> ); diff --git a/examples/src/routing/route-map.tsx b/examples/src/routing/route-map.tsx index ece38050..5af6a35e 100644 --- a/examples/src/routing/route-map.tsx +++ b/examples/src/routing/route-map.tsx @@ -9,7 +9,7 @@ import { ThemePage } from "../stories/theme-page"; import { routes, TRoute } from "./routes"; import { TableUtilitiesPage } from "../stories/table-utilities/table-utlities-page"; import { IllustrationPage } from "../stories/illustrations/illustration-page"; -import { FluentImplementationPage } from "../stories/fluent-implementations/fluent-implementation-page"; +import { MainMenuPage } from "../stories/main-menu/main-menu-page"; export enum RouteGroup { MISC, @@ -35,10 +35,10 @@ type TRouteData = { export const routeMap: Map = new Map([ [ - routes.fluentImplementations, + routes.mainMenu, { - label: "Fluent implementations", - element: , + label: "Main menu", + element: , group: RouteGroup.STORY, category: RouteCategory.STYLE, ghInfo: { diff --git a/examples/src/routing/routes.ts b/examples/src/routing/routes.ts index da9fcb1f..f4744ea2 100644 --- a/examples/src/routing/routes.ts +++ b/examples/src/routing/routes.ts @@ -8,7 +8,7 @@ export const routes = { PasswordInput: "/password-input", TabListUtilities: "/tab-list-utilities", Illustrations: "/illustrations-catalog", - fluentImplementations: "/fluent-implementations", + mainMenu: "/main-menu", } as const; export type TRoute = (typeof routes)[keyof typeof routes]; diff --git a/examples/src/stories/fluent-implementations/examples/main-menu.tsx b/examples/src/stories/fluent-implementations/examples/main-menu.tsx deleted file mode 100644 index a1d85c46..00000000 --- a/examples/src/stories/fluent-implementations/examples/main-menu.tsx +++ /dev/null @@ -1,112 +0,0 @@ -import { - useNavigationStyles, - useTabStyles, -} from "@axiscommunications/fluent-styles"; -import { - makeStyles, - Tab, - TabList, - TabProps, - useTabListContext_unstable, -} from "@fluentui/react-components"; -import { - CardUi20Regular, - Home20Regular, - Settings20Regular, -} from "@fluentui/react-icons"; -import React, { useState } from "react"; - -const useStyles = makeStyles({ - root: { - display: "flex", - width: "min-content", - height: "250px", - }, -}); - -export function MainMenu() { - const [selectedTab, setSelectedTab] = useState("1"); - const { container, spacer, tabList } = useNavigationStyles(); - const styles = useStyles(); - - return ( -
-
- { - setSelectedTab(value as unknown as string); - }} - > - } value="1" /> - } value="2" /> -
- } value="3" /> - -
-
- ); -} - -type TMainMenuTab = TabProps; - -function MainMenuTab({ children, ...props }: TMainMenuTab) { - const selected = useTabListContext_unstable((c) => c.selectedValue); - const { rootStyle } = useTabStyles({ selected: selected === props.value }); - return {children}; -} - -export const MainMenuExampleString = ` -import { useNavigationStyles, useTabStyles } from '@axiscommunications/fluent-styles' -import { Tab, TabList, TabProps, makeStyles, useTabListContext_unstable } from '@fluentui/react-components' -import { CardUi20Filled, Home20Filled, Settings20Filled } from '@fluentui/react-icons' -import React, { useState } from 'react' - -const useStyles = makeStyles({ - root: { - display: "flex", - width: "min-content", - height: "250px" - } -}) - -export function MainMenu() { - const [selectedTab, setSelectedTab] = useState("1"); - const { container, spacer, tabList } = useNavigationStyles() - const styles = useStyles(); - - return ( -
-
- { - setSelectedTab(value as unknown as string); - }} - > - } value="1" /> - } value="2" /> -
- } value="3" /> - -
-
- ) -} - -type TMainMenuTab = TabProps - -function MainMenuTab({ children, ...props }: TMainMenuTab) { - const selected = useTabListContext_unstable((c) => c.selectedValue) - const { rootStyle } = useTabStyles({ selected: selected === props.value }); - return {children}; -} -`; diff --git a/examples/src/stories/main-menu/examples/main-menu-vertical.tsx b/examples/src/stories/main-menu/examples/main-menu-vertical.tsx new file mode 100644 index 00000000..2404bc29 --- /dev/null +++ b/examples/src/stories/main-menu/examples/main-menu-vertical.tsx @@ -0,0 +1,147 @@ +import { + useMainMenuContainerStyles, + useMainMenuTabListStyles, + useMainMenuTabStyles, +} from "@axiscommunications/fluent-styles"; +import { + makeStyles, + Tab, + TabList, + TabProps, + useTabListContext_unstable, +} from "@fluentui/react-components"; +import { + bundleIcon, + CardUiFilled, + CardUiRegular, + HomeFilled, + HomeRegular, + SettingsFilled, + SettingsRegular, +} from "@fluentui/react-icons"; +import React, { useState } from "react"; + +const HomeIcon = bundleIcon(HomeFilled, HomeRegular); +const RandomIcon = bundleIcon(CardUiFilled, CardUiRegular); +const SettingsIcon = bundleIcon(SettingsFilled, SettingsRegular); + +const useStyles = makeStyles({ + root: { + width: "min-content", + display: "flex", + height: "300px", + }, +}); + +export function MainMenuVertical() { + const [selectedTab, setSelectedTab] = useState("1"); + const styles = useStyles(); + + const { rootStyle: containerRootStyle } = useMainMenuContainerStyles(); + const { rootStyle, spacerStyle } = useMainMenuTabListStyles(); + + return ( +
+
+ { + setSelectedTab(value as unknown as string); + }} + > + } value="1" /> + } value="2" /> +
+ } value="3" /> + +
+
+ ); +} + +type TMainMenuTab = TabProps; + +function MainMenuTab({ children, ...props }: TMainMenuTab) { + const selected = useTabListContext_unstable((c) => c.selectedValue); + const { rootStyle } = useMainMenuTabStyles(selected === props.value); + return {children}; +} + +export const MainMenuExampleStringVertical = ` +import { + useMainMenuContainerStyles, + useMainMenuTabListStyles, + useMainMenuTabStyles, +} from "@axiscommunications/fluent-styles"; +import { + makeStyles, + Tab, + TabList, + TabProps, + useTabListContext_unstable, +} from "@fluentui/react-components"; +import { + bundleIcon, + CardUiFilled, + CardUiRegular, + HomeFilled, + HomeRegular, + SettingsFilled, + SettingsRegular, +} from "@fluentui/react-icons"; +import React, { useState } from "react"; + +const HomeIcon = bundleIcon(HomeFilled, HomeRegular); +const RandomIcon = bundleIcon(CardUiFilled, CardUiRegular); +const SettingsIcon = bundleIcon(SettingsFilled, SettingsRegular); + +const useStyles = makeStyles({ + root: { + width: "min-content", + display: "flex", + height: "300px", + }, +}); + +export function MainMenuVertical() { + const [selectedTab, setSelectedTab] = useState("1"); + const styles = useStyles(); + + const { rootStyle: containerRootStyle } = useMainMenuContainerStyles(); + const { rootStyle, spacerStyle } = useMainMenuTabListStyles(); + + return ( +
+
+ { + setSelectedTab(value as unknown as string); + }} + > + } value="1" /> + } value="2" /> +
+ } value="3" /> + +
+
+ ); +} + +type TMainMenuTab = TabProps; + +function MainMenuTab({ children, ...props }: TMainMenuTab) { + const selected = useTabListContext_unstable((c) => c.selectedValue); + const { rootStyle } = useMainMenuTabStyles(selected === props.value); + return {children}; +} +`; diff --git a/examples/src/stories/main-menu/examples/main-menu.tsx b/examples/src/stories/main-menu/examples/main-menu.tsx new file mode 100644 index 00000000..e0b55938 --- /dev/null +++ b/examples/src/stories/main-menu/examples/main-menu.tsx @@ -0,0 +1,145 @@ +import { + useMainMenuContainerStyles, + useMainMenuTabListStyles, + useMainMenuTabStyles, +} from "@axiscommunications/fluent-styles"; +import { + makeStyles, + Tab, + TabList, + TabProps, + useTabListContext_unstable, +} from "@fluentui/react-components"; +import { + bundleIcon, + CardUiFilled, + CardUiRegular, + HomeFilled, + HomeRegular, + SettingsFilled, + SettingsRegular, +} from "@fluentui/react-icons"; +import React, { useState } from "react"; + +const HomeIcon = bundleIcon(HomeFilled, HomeRegular); +const RandomIcon = bundleIcon(CardUiFilled, CardUiRegular); +const SettingsIcon = bundleIcon(SettingsFilled, SettingsRegular); + +const useStyles = makeStyles({ + root: { + display: "flex", + }, +}); + +export function MainMenu() { + const [selectedTab, setSelectedTab] = useState("1"); + const styles = useStyles(); + + const { rootStyle: containerRootStyle } = useMainMenuContainerStyles( + "horizontal" + ); + const { rootStyle, spacerStyle } = useMainMenuTabListStyles("horizontal"); + + return ( +
+
+ { + setSelectedTab(value as unknown as string); + }} + > + } value="1" /> + } value="2" /> +
+ } value="3" /> + +
+
+ ); +} + +type TMainMenuTab = TabProps; + +function MainMenuTab({ children, ...props }: TMainMenuTab) { + const selected = useTabListContext_unstable((c) => c.selectedValue); + const { rootStyle } = useMainMenuTabStyles(selected === props.value); + return {children}; +} + +export const MainMenuExampleString = ` +import { + useMainMenuContainerStyles, + useMainMenuTabListStyles, + useMainMenuTabStyles, +} from "@axiscommunications/fluent-styles"; +import { + makeStyles, + Tab, + TabList, + TabProps, + useTabListContext_unstable, +} from "@fluentui/react-components"; +import { + bundleIcon, + CardUiFilled, + CardUiRegular, + HomeFilled, + HomeRegular, + SettingsFilled, + SettingsRegular, +} from "@fluentui/react-icons"; +import React, { useState } from "react"; + +const HomeIcon = bundleIcon(HomeFilled, HomeRegular); +const RandomIcon = bundleIcon(CardUiFilled, CardUiRegular); +const SettingsIcon = bundleIcon(SettingsFilled, SettingsRegular); + +const useStyles = makeStyles({ + root: { + display: "flex", + }, +}); + +export function MainMenu() { + const [selectedTab, setSelectedTab] = useState("1"); + const styles = useStyles(); + + const { rootStyle: containerRootStyle } = useMainMenuContainerStyles( + "horizontal" + ); + const { rootStyle, spacerStyle } = useMainMenuTabListStyles("horizontal"); + + return ( +
+
+ { + setSelectedTab(value as unknown as string); + }} + > + } value="1" /> + } value="2" /> +
+ } value="3" /> + +
+
+ ); +} + +type TMainMenuTab = TabProps; + +function MainMenuTab({ children, ...props }: TMainMenuTab) { + const selected = useTabListContext_unstable((c) => c.selectedValue); + const { rootStyle } = useMainMenuTabStyles(selected === props.value); + return {children}; +} +`; diff --git a/examples/src/stories/fluent-implementations/fluent-implementation-page.tsx b/examples/src/stories/main-menu/main-menu-page.tsx similarity index 56% rename from examples/src/stories/fluent-implementations/fluent-implementation-page.tsx rename to examples/src/stories/main-menu/main-menu-page.tsx index 63553aa8..7b6a6560 100644 --- a/examples/src/stories/fluent-implementations/fluent-implementation-page.tsx +++ b/examples/src/stories/main-menu/main-menu-page.tsx @@ -5,34 +5,39 @@ import { useExampleWithNavigation } from "../../components/story/story.utils"; import { getGhInfoByKey } from "../../routing/route-map"; import { routes } from "../../routing/routes"; import { MainMenu, MainMenuExampleString } from "./examples/main-menu"; +import { + MainMenuExampleStringVertical, + MainMenuVertical, +} from "./examples/main-menu-vertical"; +import { EStoryStatus } from "../../components/story/story-status"; const examples: pageData[] = [ { - title: "MainMenu", - anchor: "MainMenu", + title: "Vertical", + anchor: "Vertical", + example: , + codeString: MainMenuExampleStringVertical, + }, + { + title: "Horizontal", + anchor: "Horizontal", example: , codeString: MainMenuExampleString, }, ]; -export const FluentImplementationPage = () => { - const gh = getGhInfoByKey(routes.fluentImplementations); +export const MainMenuPage = () => { + const gh = getGhInfoByKey(routes.mainMenu); const { renderSections, renderNavigation } = useExampleWithNavigation( - examples.map(d => { - return { - ...d, - example: ( - d.example - ), - }; - }) + examples ); return ( { + const styles = useContainerStyle(); + const rootStyle = mergeClasses(styles.root, styles[orientation]); + return { styles, rootStyle }; +}; + +const useTabListStyles = makeStyles({ + root: { + ...shorthands.gap(tokens.spacingVerticalXS), + }, + vertical: { + height: "100%", + }, + horizontal: { + width: "100%", + }, + spacer: { + flexGrow: 1, + }, +}); + +export const useMainMenuTabListStyles = ( + orientation: "vertical" | "horizontal" = "vertical" +) => { + const styles = useTabListStyles(); + const rootStyle = mergeClasses(styles.root, styles[orientation]); + const spacerStyle = mergeClasses(styles.spacer); + return { styles, rootStyle, spacerStyle }; +}; + +const useTabStyles = makeStyles({ + root: { + [`& .${tabClassNames.icon} `]: { + color: tokens.colorNeutralForeground1, + }, + "&:hover": { + backgroundColor: tokens.colorNeutralBackground3Hover, + [`& .${tabClassNames.icon}`]: { + color: tokens.colorNeutralForeground1, + }, + }, + "&:active": { + backgroundColor: tokens.colorNeutralBackground3Hover, + [`& .${tabClassNames.icon}`]: { + color: tokens.colorNeutralForeground1, + }, + }, + }, + selected: { + backgroundColor: tokens.colorNeutralBackground3Selected, + "&:hover": { + backgroundColor: tokens.colorNeutralBackground3Hover, + }, + }, +}); + +export const useMainMenuTabStyles = (selected?: boolean) => { + const styles = useTabStyles(); + const rootStyle = mergeClasses(styles.root, selected && styles.selected); + return { styles, rootStyle }; +};