Update TopNav component

This commit is contained in:
adilallo
2026-02-06 14:25:27 -07:00
parent d5c7262794
commit 162fdf94db
13 changed files with 383 additions and 433 deletions
+2 -2
View File
@@ -46,7 +46,7 @@ const Button = memo<ButtonProps>(
const size = normalizeSize(sizeProp);
const sizeStyles: Record<string, string> = {
xsmall:
"p-[var(--spacing-scale-006)] gap-[var(--spacing-scale-002)]",
"p-[var(--spacing-scale-004)] gap-[var(--spacing-scale-002)]",
small:
"p-[var(--spacing-scale-008)] gap-[var(--spacing-scale-002)]",
medium: "p-[var(--spacing-scale-010)] gap-[var(--spacing-scale-004)]",
@@ -102,7 +102,7 @@ const Button = memo<ButtonProps>(
? ""
: hoverOutlineStyles[size];
const baseStyles = `inline-flex items-center justify-start box-border ${sizeStyles[size]} rounded-[var(--radius-measures-radius-full)] ${fontStyles[size]} transition-all duration-500 ease-in-out cursor-pointer ${variantStyles[variant]} ${outlineStyles}`;
const baseStyles = `inline-flex items-center justify-start box-border whitespace-nowrap shrink-0 ${sizeStyles[size]} rounded-[var(--radius-measures-radius-full)] ${fontStyles[size]} transition-all duration-500 ease-in-out cursor-pointer ${variantStyles[variant]} ${outlineStyles}`;
const combinedStyles = `${baseStyles} ${className}`;
const sharedA11y = {
+3 -3
View File
@@ -19,13 +19,13 @@ const Avatar = memo<AvatarProps>(
// Normalize props to handle both PascalCase (Figma) and lowercase (codebase)
const size = normalizeSize(sizeProp, "small");
const sizeStyles: Record<string, string> = {
small: "w-[var(--spacing-scale-016)] h-[var(--spacing-scale-016)]",
medium: "w-[18px] h-[18px]",
small: "w-[var(--spacing-scale-016)] h-[var(--spacing-scale-016)] border-[1.5px] border-[#FFFFFF4D] border-solid",
medium: "w-[var(--spacing-scale-018)] h-[var(--spacing-scale-018)]",
large: "w-[var(--spacing-scale-024)] h-[var(--spacing-scale-024)]",
xlarge: "w-[var(--spacing-scale-032)] h-[var(--spacing-scale-032)]",
};
const baseStyles = `rounded-[var(--radius-measures-radius-full)] object-cover ${sizeStyles[size]} ${className}`;
const baseStyles = `rounded-[var(--radius-measures-radius-full)] object-cover box-border ${sizeStyles[size]} ${className}`;
return <img src={src} alt={alt} className={baseStyles} {...props} />;
},
-47
View File
@@ -1,47 +0,0 @@
import { memo } from "react";
import { getAssetPath } from "../../../lib/assetUtils";
interface HeaderTabProps extends React.HTMLAttributes<HTMLDivElement> {
children?: React.ReactNode;
className?: string;
stretch?: boolean;
}
const HeaderTab = memo<HeaderTabProps>(
({ children, className = "", stretch = false, ...props }) => {
const stretchClasses = stretch
? "flex-1 sm:mr-[var(--spacing-scale-008)] md:mr-[185px] lg:mr-[var(--spacing-scale-024)] xl:mr-[var(--spacing-scale-032)]"
: "";
return (
<div
className={`HeaderTab header-breakpoint-transition relative bg-[var(--color-surface-inverse-brand-primary)] rounded-t-[32px] sm:rounded-t-[32px] md:rounded-t-[32px] lg:rounded-t-[32px] xl:rounded-t-[32px] pl-[var(--spacing-scale-012)] h-[40px] sm:h-[52px] md:h-[52px] lg:h-[52px] xl:h-[64px] sm:pr-[var(--spacing-scale-006)] md:pl-[var(--spacing-scale-024)] lg:pl-[var(--spacing-scale-024)] xl:pl-[var(--spacing-scale-032)] md:pr-[var(--spacing-scale-012)] lg:pr-[var(--spacing-scale-048)] xl:pr-[var(--spacing-scale-120)] md:gap-[var(--spacing-scale-032)] ${stretchClasses} ${className}`}
{...props}
>
{children}
<img
src={getAssetPath("assets/Union_xsm.svg")}
alt=""
role="presentation"
className="absolute -bottom-[3px] -right-[52px] w-[61px] h-[24px] sm:w-[61px] sm:h-[31.5px] sm:hidden -z-10"
/>
<img
src={getAssetPath("assets/Union_sm_md_lg.svg")}
alt=""
role="presentation"
className="absolute -bottom-[3.7px] -right-[53px] w-[61px] h-[24px] sm:w-[61px] sm:h-[31.5px] hidden sm:block xl:hidden -z-10"
/>
<img
src={getAssetPath("assets/Union_xlg.svg")}
alt=""
role="presentation"
className="absolute -bottom-[6px] -right-[94px] w-[105px] h-[53px] hidden xl:block -z-10"
/>
</div>
);
},
);
HeaderTab.displayName = "HeaderTab";
export default HeaderTab;
+23 -20
View File
@@ -5,39 +5,42 @@ import { useTranslation } from "../../contexts/MessagesContext";
import { normalizeMenuBarSize } from "../../../lib/propNormalization";
export type MenuBarSizeValue =
| "xsmall"
| "default"
| "medium"
| "large"
| "XSmall"
| "Default"
| "X Small"
| "Small"
| "Medium"
| "Large";
| "Large"
| "X Large";
interface MenuBarProps extends React.HTMLAttributes<HTMLElement> {
children?: React.ReactNode;
className?: string;
/**
* Menu bar size. Accepts both lowercase and PascalCase (case-insensitive).
* Figma uses PascalCase, codebase uses lowercase - both are supported.
* Menu bar size. Uses Figma format: "X Small", "Small", "Medium", "Large", "X Large".
* @default "X Small"
*/
size?: MenuBarSizeValue;
}
const MenuBar = memo<MenuBarProps>(
({ children, className = "", size: sizeProp = "default", ...props }) => {
// Normalize props to handle both PascalCase (Figma) and lowercase (codebase)
({ children, className = "", size: sizeProp = "X Small", ...props }) => {
const size = normalizeMenuBarSize(sizeProp);
const t = useTranslation("menuBar");
const sizeStyles: Record<string, string> = {
xsmall:
"px-[var(--spacing-scale-004)] py-[var(--spacing-scale-004)] gap-[var(--spacing-scale-001)] rounded-[4px]",
default:
"px-[var(--spacing-scale-004)] py-[var(--spacing-scale-004)] gap-[var(--spacing-scale-001)]",
medium:
"px-[var(--spacing-scale-004)] py-[var(--spacing-scale-004)] gap-[var(--spacing-scale-004)]",
large:
"px-[var(--spacing-scale-004)] py-[var(--spacing-scale-004)] gap-[var(--spacing-scale-012)]",
// Size styles based on Figma specifications
const sizeStyles: Record<
"X Small" | "Small" | "Medium" | "Large" | "X Large",
string
> = {
"X Small":
"px-[var(--spacing-scale-004)] py-[var(--spacing-scale-004)] gap-[var(--spacing-scale-001)] rounded-[var(--spacing-scale-004)]",
Small:
"px-[var(--spacing-scale-004)] py-[var(--spacing-scale-004)] gap-[var(--spacing-scale-004)] rounded-[var(--spacing-scale-004)]",
Medium:
"px-[var(--spacing-scale-004)] py-[var(--spacing-scale-004)] gap-[var(--spacing-scale-004)] rounded-[var(--spacing-scale-004)]",
Large:
"px-[var(--spacing-scale-004)] py-[var(--spacing-scale-004)] gap-[var(--spacing-scale-012)] rounded-[var(--spacing-scale-004)]",
"X Large":
"px-[var(--spacing-scale-004)] py-[var(--spacing-scale-004)] gap-[var(--spacing-scale-012)] rounded-[var(--spacing-scale-004)]",
};
const baseStyles = `flex items-center ${sizeStyles[size]} ${className}`;
@@ -3,152 +3,108 @@
import { memo } from "react";
import MenuBarItemView from "./MenuBarItem.view";
import type { MenuBarItemProps } from "./MenuBarItem.types";
import { normalizeMenuBarItemVariant } from "../../../../lib/propNormalization";
import {
normalizeMenuBarItemState,
normalizeMenuBarItemMode,
normalizeMenuBarItemSize,
} from "../../../../lib/propNormalization";
const MenuBarItemContainer = memo<MenuBarItemProps>(
({
href = "#",
children,
variant: variantProp = "default",
size: sizeProp = "default",
state: stateProp,
mode: modeProp,
icon: _icon = false,
size: sizeProp = "X Small",
className = "",
disabled = false,
isActive = false,
reducedPadding = false,
ariaLabel,
...props
}) => {
// Normalize props to handle both PascalCase (Figma) and lowercase (codebase)
const variant = normalizeMenuBarItemVariant(variantProp);
// Size has many values, normalize by lowercasing
const size = (sizeProp?.toLowerCase() || "default") as typeof sizeProp;
const variantStyles: Record<string, string> = {
const state = normalizeMenuBarItemState(stateProp, "default");
const mode = normalizeMenuBarItemMode(modeProp, "default");
const size = normalizeMenuBarItemSize(sizeProp, "X Small");
// Size styles based on Figma specifications
const sizeStyles: Record<
"X Small" | "Small" | "Medium" | "Large" | "X Large",
string
> = {
"X Small": reducedPadding ? "px-[var(--spacing-scale-004)] py-[var(--spacing-scale-002)]" : "px-[var(--spacing-scale-004)] py-[var(--spacing-scale-002)]",
Small: "px-[var(--spacing-scale-004)] py-[var(--spacing-scale-002)]",
Medium: reducedPadding ? "px-[var(--spacing-scale-002)] py-[var(--spacing-scale-008)] h-[32px]" : "px-[var(--spacing-scale-008)] py-[var(--spacing-scale-008)] h-[32px]",
Large: "px-[var(--spacing-scale-016)] py-[var(--spacing-scale-016)] h-[44px]",
"X Large": "px-[var(--spacing-scale-016)] py-[var(--spacing-scale-016)] h-[44px]",
};
// Text styles based on Figma specifications
const textStyles: Record<
"X Small" | "Small" | "Medium" | "Large" | "X Large",
string
> = {
"X Small":
"font-inter text-[10px] leading-[12px] font-medium tracking-[0%]",
Small:
"font-inter text-[12px] leading-[14px] font-medium tracking-[0%]",
Medium:
"font-inter text-[12px] leading-[14px] font-medium tracking-[0%]",
Large:
"font-inter text-[16px] leading-[20px] font-medium tracking-[0%]",
"X Large":
"font-inter text-[24px] leading-[28px] font-normal tracking-[0%]",
};
// State styles for Default mode (yellow text on dark background)
const defaultModeStyles: Record<
"default" | "hover" | "selected",
string
> = {
default:
"bg-transparent text-[var(--color-content-default-brand-primary)] hover:bg-[var(--color-surface-default-tertiary)] hover:text-[var(--color-content-default-brand-primary)] hover:scale-[1.02] active:bg-transparent active:text-[var(--color-content-default-brand-primary)] active:scale-[0.98] disabled:bg-[var(--color-surface-default-tertiary)] disabled:text-[var(--color-content-default-tertiary)] disabled:opacity-50 disabled:cursor-not-allowed disabled:hover:scale-100 disabled:active:scale-100",
home: "bg-transparent text-[var(--color-content-inverse-primary)] hover:bg-[var(--color-content-default-brand-accent)] hover:text-[var(--color-content-inverse-primary)] hover:scale-[1.02] active:bg-transparent active:text-[var(--color-content-inverse-primary)] active:scale-[0.98] disabled:bg-[var(--color-surface-default-tertiary)] disabled:text-[var(--color-content-default-tertiary)] disabled:opacity-50 disabled:cursor-not-allowed disabled:hover:scale-100 disabled:active:scale-100",
"bg-transparent text-[var(--color-content-default-brand-primary,#fefcc9)] hover:bg-[var(--color-gray-800)] hover:text-[var(--color-content-default-brand-primary,#fefcc9)]",
hover:
"bg-[var(--color-gray-800)] text-[var(--color-content-default-brand-primary,#fefcc9)]",
selected:
"border border-[var(--color-border-default-brand-primary,#fdfaa8)] text-[var(--color-content-default-brand-primary,#fefcc9)] bg-transparent hover:bg-[var(--color-gray-800)]",
};
const activeOutlineStyles: Record<string, string> = {
xsmall:
"active:outline-1 active:outline-[var(--color-content-default-primary)] focus:outline-1 focus:outline-[var(--color-content-default-primary)]",
xsmallUseCases:
"active:outline-1 active:outline-[var(--color-content-default-primary)] focus:outline-1 focus:outline-[var(--color-content-default-primary)]",
// State styles for Inverse mode (black text on yellow background)
const inverseModeStyles: Record<
"default" | "hover" | "selected",
string
> = {
default:
"active:outline-[1.5px] active:outline-[var(--color-content-default-brand-primary)] focus:outline-[1.5px] focus:outline-[var(--color-content-default-brand-primary)]",
homeMd:
"active:outline-[1.5px] active:outline-[var(--color-content-default-brand-primary)] focus:outline-[1.5px] focus:outline-[var(--color-content-default-brand-primary)]",
homeUseCases:
"active:outline-[1.5px] active:outline-[var(--color-content-default-brand-primary)] focus:outline-[1.5px] focus:outline-[var(--color-content-default-brand-primary)]",
large:
"active:outline-[1.75px] active:outline-[var(--color-content-default-brand-primary)] focus:outline-[1.75px] focus:outline-[var(--color-content-default-brand-primary)]",
largeUseCases:
"active:outline-[1.75px] active:outline-[var(--color-content-default-brand-primary)] focus:outline-[1.75px] focus:outline-[var(--color-content-default-brand-primary)]",
homeXlarge:
"active:outline-[2px] active:outline-[var(--color-content-default-brand-primary)] focus:outline-[2px] focus:outline-[var(--color-content-default-brand-primary)]",
xlarge:
"active:outline-2 active:outline-[var(--color-content-default-brand-primary)] focus:outline-2 focus:outline-[var(--color-content-default-brand-primary)]",
"bg-transparent text-[var(--color-content-inverse-primary,black)] hover:bg-[var(--color-surface-brand-accent,#4d4a00)] hover:text-[var(--color-content-inverse-primary,black)]",
hover:
"bg-[var(--color-surface-brand-accent,#4d4a00)] text-[var(--color-content-inverse-primary,black)]",
selected:
"border border-[var(--color-border-default-primary,#141414)] text-[var(--color-content-inverse-primary,black)] bg-transparent hover:bg-[var(--color-surface-brand-accent,#4d4a00)]",
};
const homeOutlineStyles: Record<string, string> = {
xsmall:
"active:outline-1 active:outline-[var(--color-content-default-primary)] focus:outline-1 focus:outline-[var(--color-content-default-primary)]",
xsmallUseCases:
"active:outline-1 active:outline-[var(--color-content-default-primary)] focus:outline-1 focus:outline-[var(--color-content-default-primary)]",
default:
"active:outline-[1.5px] active:outline-[var(--color-content-default-primary)] focus:outline-[1.5px] focus:outline-[var(--color-content-default-primary)]",
homeMd:
"active:outline-[1.5px] active:outline-[var(--color-content-default-primary)] focus:outline-[1.5px] focus:outline-[var(--color-content-default-primary)]",
homeUseCases:
"active:outline-[1.5px] active:outline-[var(--color-content-default-primary)] focus:outline-[1.5px] focus:outline-[var(--color-content-default-primary)]",
largeUseCases:
"active:outline-[1.75px] active:outline-[var(--color-content-default-primary)] focus:outline-[1.75px] focus:outline-[var(--color-content-default-primary)]",
large:
"active:outline-[1.75px] active:outline-[var(--color-content-default-primary)] focus:outline-[1.75px] focus:outline-[var(--color-content-default-primary)]",
homeXlarge:
"active:outline-[2px] active:outline-[var(--color-content-default-primary)] focus:outline-[2px] focus:outline-[var(--color-content-default-primary)]",
xlarge:
"active:outline-2 active:outline-[var(--color-content-default-primary)] focus:outline-2 focus:outline-[var(--color-content-default-primary)]",
};
// Get state styles based on mode
const stateStyles =
mode === "inverse" ? inverseModeStyles : defaultModeStyles;
const activeStateStyles: Record<string, string> = {
xsmall:
"!outline-1 !outline-[var(--color-content-default-brand-primary)] !text-[var(--color-content-default-brand-primary)] focus:!outline-1 focus:!outline-[var(--color-content-default-brand-primary)]",
xsmallUseCases:
"!outline-1 !outline-[var(--color-content-default-brand-primary)] !text-[var(--color-content-default-brand-primary)] focus:!outline-1 focus:!outline-[var(--color-content-default-brand-primary)]",
default:
"!outline-[1.5px] !outline-[var(--color-content-default-brand-primary)] !text-[var(--color-content-default-brand-primary)] focus:!outline-[1.5px] focus:!outline-[var(--color-content-default-brand-primary)]",
homeMd:
"!outline-[1.5px] !outline-[var(--color-content-default-brand-primary)] !text-[var(--color-content-default-brand-primary)] focus:!outline-[1.5px] focus:!outline-[var(--color-content-default-brand-primary)]",
homeUseCases:
"!outline-[1.5px] !outline-[var(--color-content-default-brand-primary)] !text-[var(--color-content-default-brand-primary)] focus:!outline-[1.5px] focus:!outline-[var(--color-content-default-brand-primary)]",
large:
"!outline-[1.75px] !outline-[var(--color-content-default-brand-primary)] !text-[var(--color-content-default-brand-primary)] focus:!outline-[1.75px] focus:!outline-[var(--color-content-default-brand-primary)]",
largeUseCases:
"!outline-[1.75px] !outline-[var(--color-content-default-brand-primary)] !text-[var(--color-content-default-brand-primary)] focus:!outline-[1.75px] focus:!outline-[var(--color-content-default-brand-primary)]",
homeXlarge:
"!outline-[2px] !outline-[var(--color-content-default-brand-primary)] !text-[var(--color-content-default-brand-primary)] focus:!outline-[2px] focus:!outline-[var(--color-content-default-brand-primary)]",
xlarge:
"!outline-2 !outline-[var(--color-content-default-brand-primary)] !text-[var(--color-content-default-brand-primary)] focus:!outline-2 focus:!outline-[var(--color-content-default-brand-primary)]",
};
// Base styles
const baseStyles = `inline-flex items-center whitespace-nowrap ${sizeStyles[size]} ${textStyles[size]} rounded-[var(--radius-measures-radius-full)] transition-all duration-200 ease-in-out cursor-pointer`;
const sizeStyles: Record<string, string> = {
default:
"px-[var(--spacing-measures-spacing-016)] py-[var(--spacing-measures-spacing-016)] gap-[var(--spacing-scale-004)]",
xsmall:
"px-[var(--spacing-scale-004)] py-[var(--spacing-scale-002)] gap-[var(--spacing-scale-004)]",
xsmallUseCases:
"px-[var(--spacing-scale-002)] py-[var(--spacing-scale-002)] gap-[var(--spacing-scale-004)]",
homeMd:
"px-[var(--spacing-scale-008)] py-[var(--spacing-scale-008)] gap-[var(--spacing-scale-004)]",
homeUseCases:
"px-[var(--spacing-scale-002)] py-[var(--spacing-scale-008)] gap-[var(--spacing-scale-004)]",
large:
"px-[var(--spacing-scale-012)] py-[var(--spacing-scale-012)] gap-[var(--spacing-scale-004)] h-[44px]",
largeUseCases:
"px-[var(--spacing-scale-012)] py-[var(--spacing-scale-012)] gap-[var(--spacing-scale-004)] h-[44px]",
homeXlarge:
"px-[var(--spacing-scale-016)] py-[var(--spacing-scale-016)] gap-[var(--spacing-scale-004)] h-[44px]",
xlarge:
"px-[var(--spacing-scale-016)] py-[var(--spacing-scale-008)] gap-[var(--spacing-scale-004)] h-[44px]",
};
// Interactive styles
const interactiveStyles =
"hover:scale-[1.02] active:scale-[0.98] focus:scale-[1.02] disabled:opacity-50 disabled:cursor-not-allowed disabled:hover:scale-100 disabled:active:scale-100";
const smallTextStyle =
"font-inter text-[10px] leading-[12px] font-medium tracking-[0%]";
const mediumTextStyle =
"font-inter text-[12px] leading-[14px] font-medium tracking-[0%]";
const largeTextStyle =
"font-inter text-[16px] leading-[20px] font-medium tracking-[0%]";
const xlargeTextStyle =
"font-inter text-[24px] leading-[28px] font-normal tracking-[0%]";
// Disabled styles
const disabledStyles = disabled
? "bg-[var(--color-surface-default-tertiary)] text-[var(--color-content-default-tertiary)]"
: "";
const textStyles: Record<string, string> = {
default: smallTextStyle,
xsmall: smallTextStyle,
xsmallUseCases: smallTextStyle,
home: smallTextStyle,
homeMd: mediumTextStyle,
homeUseCases: mediumTextStyle,
large: largeTextStyle,
largeUseCases: largeTextStyle,
homeXlarge: xlargeTextStyle,
xlarge: xlargeTextStyle,
};
const baseStyles = `inline-flex items-center ${sizeStyles[size]} rounded-[var(--radius-measures-radius-full)] ${textStyles[size]} transition-all duration-200 ease-in-out cursor-pointer focus:scale-[1.02]`;
let finalVariant = variant;
if (disabled) {
finalVariant = "default";
}
const combinedStyles = `${baseStyles} ${variantStyles[finalVariant]} ${
finalVariant === "home"
? homeOutlineStyles[size]
: activeOutlineStyles[size]
} ${isActive ? activeStateStyles[size] : ""} ${className}`;
// Combine all styles
const combinedStyles = `${baseStyles} ${stateStyles[state]} ${interactiveStyles} ${disabledStyles} ${className}`;
const accessibilityProps = {
...(ariaLabel && { "aria-label": ariaLabel }),
...(disabled && { "aria-disabled": true }),
...(state === "selected" && { "aria-current": "page" as const }),
role: "menuitem" as const,
tabIndex: disabled ? -1 : 0,
...props,
@@ -1,43 +1,50 @@
export type MenuBarItemSizeValue =
| "default"
| "xsmall"
| "xsmallUseCases"
| "home"
| "homeMd"
| "homeUseCases"
| "large"
| "largeUseCases"
| "homeXlarge"
| "xlarge"
| "Default"
| "XSmall"
| "XSmallUseCases"
| "Home"
| "HomeMd"
| "HomeUseCases"
| "X Small"
| "Small"
| "Medium"
| "Large"
| "LargeUseCases"
| "HomeXlarge"
| "XLarge";
| "X Large";
export type MenuBarItemVariantValue = "default" | "home" | "Default" | "Home";
export type MenuBarItemStateValue =
| "default"
| "hover"
| "selected";
export type MenuBarItemModeValue =
| "default"
| "inverse";
export interface MenuBarItemProps extends React.AnchorHTMLAttributes<HTMLAnchorElement> {
href?: string;
children?: React.ReactNode;
/**
* Menu bar item variant. Accepts both lowercase and PascalCase (case-insensitive).
* Figma uses PascalCase, codebase uses lowercase - both are supported.
* Menu bar item state: "default", "hover", or "selected".
* @default "default"
*/
variant?: MenuBarItemVariantValue;
state?: MenuBarItemStateValue;
/**
* Menu bar item size. Accepts both lowercase and PascalCase (case-insensitive).
* Figma uses PascalCase, codebase uses lowercase - both are supported.
* Menu bar item mode. Default mode has yellow text on dark background.
* Inverse mode has black text on yellow background (for folderTop variant).
* @default "default"
*/
mode?: MenuBarItemModeValue;
/**
* Whether to show an icon (for future icon support).
* @default false
*/
icon?: boolean;
/**
* Menu bar item size. Uses Figma format: "X Small", "Small", "Medium", "Large", "X Large".
* @default "X Small"
*/
size?: MenuBarItemSizeValue;
className?: string;
disabled?: boolean;
isActive?: boolean;
/**
* Whether to use reduced padding (for "use cases" button).
* @default false
*/
reducedPadding?: boolean;
ariaLabel?: string;
}
@@ -99,54 +99,38 @@ const TopNavContainer = memo<TopNavProps>(
];
const renderNavigationItems = (size: NavSize) => {
return navigationItems.map((item, index) => {
// Determine size based on folderTop and item properties
let itemSize: NavSize = size;
if (item.extraPadding) {
if (folderTop) {
if (
size === "xsmall" ||
size === "default" ||
size === "home" ||
size === "homeMd" ||
size === "large" ||
size === "homeXlarge"
) {
itemSize =
size === "home" || size === "homeMd"
? "homeMd"
: size === "large"
? "large"
: size === "homeXlarge"
? "homeXlarge"
: "xsmallUseCases";
}
} else {
if (size === "xsmall") {
itemSize = "xsmallUseCases";
}
}
}
// Map NavSize to Figma MenuBarItem sizes
const sizeMap: Record<NavSize, "X Small" | "Small" | "Medium" | "Large" | "X Large"> = {
default: "Small",
xsmall: "X Small",
xsmallUseCases: "X Small",
home: "X Small",
homeMd: "Medium",
homeUseCases: "Small",
large: "Large",
largeUseCases: "Large",
homeXlarge: "X Large",
xlarge: "X Large",
};
// Determine variant based on folderTop
const variant = folderTop
? size === "xsmall" ||
size === "default" ||
size === "home" ||
size === "homeMd" ||
size === "large" ||
size === "homeXlarge"
? "home"
: "default"
: "default";
// Determine mode based on folderTop
const mode = folderTop ? "inverse" : "default";
return navigationItems.map((item, index) => {
// Map size to Figma size
let itemSize = sizeMap[size] || "Small";
// Pass reducedPadding for "use cases" button (item with extraPadding: true)
const isUseCases = item.extraPadding === true;
return (
<MenuBarItem
key={index}
href={item.href}
size={itemSize}
variant={variant}
isActive={pathname === item.href}
mode={mode}
state={pathname === item.href ? "selected" : "default"}
reducedPadding={isUseCases}
ariaLabel={t("ariaLabels.navigateToPage").replace("{text}", item.text)}
>
{item.text}
@@ -174,18 +158,32 @@ const TopNavContainer = memo<TopNavProps>(
};
const renderLoginButton = (size: NavSize) => {
// Determine variant based on folderTop
const variant = folderTop
? size === "xsmall" || size === "default"
? "home"
: "default"
: "default";
// Map NavSize to Figma MenuBarItem sizes
const sizeMap: Record<NavSize, "X Small" | "Small" | "Medium" | "Large" | "X Large"> = {
default: "Small",
xsmall: "X Small",
xsmallUseCases: "X Small",
home: "X Small",
homeMd: "Medium",
homeUseCases: "Small",
large: "Large",
largeUseCases: "Large",
homeXlarge: "X Large",
xlarge: "X Large",
};
// Determine mode based on folderTop and breakpoint size
// folderTop: inverse mode (black text) for smallest breakpoints (xsmall/home)
// folderTop: default mode (yellow text) for 640px+ breakpoints (homeMd/large/homeXlarge/xlarge)
// false folderTop: always default mode (yellow text on dark background)
const isSmallBreakpoint = size === "xsmall" || size === "home";
const mode = folderTop && isSmallBreakpoint ? "inverse" : "default";
return (
<MenuBarItem
href="#"
size={size}
variant={variant}
size={sizeMap[size] || "Small"}
mode={mode}
ariaLabel={t("ariaLabels.logInToAccount")}
>
{t("buttons.logIn")}
@@ -3,7 +3,7 @@
import { memo } from "react";
import Script from "next/script";
import { useTranslation } from "../../../contexts/MessagesContext";
import HeaderTab from "../HeaderTab";
import { getAssetPath } from "../../../../lib/assetUtils";
import MenuBar from "../MenuBar";
import type { TopNavViewProps } from "./TopNav.types";
@@ -36,11 +36,12 @@ function TopNavView({
aria-label={t("ariaLabels.homePageNavigationHeader")}
>
<nav
className="relative flex items-center justify-between mx-auto h-[50px] sm:h-[62px] md:h-[68px] lg:h-[68px] xl:h-[88px] px-[var(--spacing-scale-008)] pr-[var(--spacing-scale-016)] pt-[var(--spacing-scale-010)] sm:px-[var(--spacing-scale-010)] sm:pr-[var(--spacing-scale-020)] sm:pt-[var(--spacing-scale-010)] md:px-[var(--spacing-scale-016)] md:pr-[var(--spacing-scale-032)] md:pt-[var(--spacing-scale-016)] lg:pl-[var(--spacing-scale-024)] lg:pt-[var(--spacing-scale-016)] lg:pr-[var(--spacing-scale-056)] xl:pl-[var(--spacing-scale-048)] xl:pt-[var(--spacing-scale-024)] xl:pr-[var(--spacing-scale-056)]"
className="relative flex items-center justify-between mx-auto h-[50px] sm:h-[62px] md:h-[68px] lg:h-[68px] xl:h-[88px] pl-[var(--spacing-scale-008)] pr-[var(--spacing-scale-016)] pt-[var(--spacing-scale-010)] sm:px-[var(--spacing-scale-010)] sm:pr-[var(--spacing-scale-020)] sm:pt-[var(--spacing-scale-010)] md:px-[var(--spacing-scale-016)] md:pr-[var(--spacing-scale-032)] md:pt-[var(--spacing-scale-016)] lg:pl-[var(--spacing-scale-024)] lg:pt-[var(--spacing-scale-016)] lg:pr-[var(--spacing-scale-056)] xl:pl-[var(--spacing-scale-048)] xl:pt-[var(--spacing-scale-024)] xl:pr-[var(--spacing-scale-056)]"
role="navigation"
aria-label={t("ariaLabels.mainNavigation")}
>
<HeaderTab className="flex items-center self-end" stretch={true}>
{/* Header Tab - Yellow tab container with decorative Union images */}
<div className="HeaderTab header-breakpoint-transition relative bg-[var(--color-surface-inverse-brand-primary)] rounded-tl-[var(--radius-measures-radius-medium)] rounded-tr-[var(--radius-measures-radius-medium)] sm:rounded-t-[var(--radius-measures-radius-xlarge)] md:rounded-t-[var(--radius-measures-radius-xlarge)] lg:rounded-t-[var(--radius-measures-radius-xlarge)] xl:rounded-t-[var(--radius-measures-radius-xlarge)] pl-[var(--spacing-scale-012)] pr-[var(--spacing-scale-048)] h-[var(--spacing-scale-040)] sm:pl-[var(--spacing-scale-012)] sm:h-[52px] sm:pr-[var(--spacing-scale-006)] md:h-[52px] md:pl-[var(--spacing-scale-024)] md:pr-[var(--spacing-scale-012)] lg:h-[52px] lg:pl-[var(--spacing-scale-024)] lg:pr-[var(--spacing-scale-048)] xl:h-[64px] xl:pl-[var(--spacing-scale-032)] xl:pr-[var(--spacing-scale-120)] md:gap-[var(--spacing-scale-032)] flex-1 min-w-0 min-w-[197px] sm:min-w-0 sm:mr-[var(--spacing-scale-008)] md:mr-[185px] lg:mr-[var(--spacing-scale-024)] xl:mr-[var(--spacing-scale-032)] flex items-center self-end">
{/* Logo - Consistent left positioning within HeaderTab */}
<div>
{logoConfig.map((config, index) => (
@@ -52,32 +53,56 @@ function TopNavView({
{/* XSmall menu bar - positioned next to logo */}
<div className="block sm:hidden -me-[2px]">
<MenuBar size="default">
<MenuBar size="X Small">
{renderNavigationItems("xsmall")}
{logIn && renderLoginButton("xsmall")}
</MenuBar>
</div>
</HeaderTab>
{/* Decorative Union images for tab appearance */}
<img
src={getAssetPath("assets/Union_xsm.svg")}
alt=""
role="presentation"
className="absolute -bottom-[3px] -right-[52px] w-[61px] h-[24px] sm:w-[61px] sm:h-[31.5px] sm:hidden -z-10"
/>
<img
src={getAssetPath("assets/Union_sm_md_lg.svg")}
alt=""
role="presentation"
className="absolute -bottom-[3.7px] -right-[53px] w-[61px] h-[24px] sm:w-[61px] sm:h-[31.5px] hidden sm:block xl:hidden -z-10"
/>
<img
src={getAssetPath("assets/Union_xlg.svg")}
alt=""
role="presentation"
className="absolute -bottom-[6px] -right-[94px] w-[105px] h-[53px] hidden xl:block -z-10"
/>
</div>
{/* Navigation Links - Centered in header for SM and up */}
<div className="absolute left-1/2 transform -translate-x-1/2 hidden sm:block">
{/* 430-639px (sm: breakpoint): MenuBar X Small */}
<div className="hidden sm:block md:hidden">
<MenuBar size="default">
<MenuBar size="X Small">
{renderNavigationItems("xsmall")}
{logIn && renderLoginButton("xsmall")}
</MenuBar>
</div>
{/* 640-1023px (md: breakpoint): MenuBar Small */}
<div className="hidden md:block lg:hidden">
<MenuBar size="medium">{renderNavigationItems("homeMd")}</MenuBar>
<MenuBar size="Small">{renderNavigationItems("homeMd")}</MenuBar>
</div>
{/* 1024-1440px (lg: breakpoint): MenuBar Large */}
<div className="hidden lg:block xl:hidden">
<MenuBar size="large">{renderNavigationItems("large")}</MenuBar>
<MenuBar size="Large">{renderNavigationItems("large")}</MenuBar>
</div>
{/* 1440px+ (xl: breakpoint): MenuBar X Large */}
<div className="hidden xl:block">
<MenuBar size="large">
<MenuBar size="X Large">
{renderNavigationItems("homeXlarge")}
</MenuBar>
</div>
@@ -133,7 +158,7 @@ function TopNavView({
aria-label={t("ariaLabels.mainNavigationHeader")}
>
<nav
className="flex items-center justify-between mx-auto h-[40px] lg:h-[84px] xl:h-[88px] px-[var(--spacing-measures-spacing-016)] py-[var(--spacing-measures-spacing-008)] lg:px-[var(--spacing-measures-spacing-64,64px)] lg:py-[var(--spacing-measures-spacing-016,16px)]"
className="flex items-center gap-[var(--spacing-scale-002)] sm:justify-between mx-auto h-[var(--spacing-scale-040)] lg:h-[84px] xl:h-[88px] px-[var(--spacing-scale-016)] py-[var(--spacing-scale-008)] sm:px-[var(--spacing-measures-spacing-016)] sm:py-[var(--spacing-measures-spacing-008)] lg:px-[var(--spacing-measures-spacing-64,64px)] lg:py-[var(--spacing-measures-spacing-016,16px)] sm:gap-0"
role="navigation"
aria-label={t("ariaLabels.mainNavigation")}
>
@@ -151,46 +176,44 @@ function TopNavView({
</div>
{/* Navigation Links - Consistent center positioning */}
<div className="flex items-center">
{/* XSmall breakpoint - Navigation items moved to right section */}
<div className="flex items-center flex-1 justify-end sm:flex-none sm:justify-center">
{/* XSmall breakpoint - Navigation items in Actions section (flex-1, justify-end) */}
<div className="block sm:hidden" data-testid="nav-xs">
{/* Empty for XSmall - navigation moved to right */}
</div>
{/* Small breakpoint - All items grouped together, centered */}
<div className="hidden sm:block md:hidden" data-testid="nav-sm">
<MenuBar size="default">
<MenuBar size="X Small">
{renderNavigationItems("xsmall")}
{logIn && renderLoginButton("xsmall")}
</MenuBar>
</div>
{/* 430-639px (sm: breakpoint): MenuBar X Small */}
<div className="hidden sm:block md:hidden" data-testid="nav-sm">
<MenuBar size="X Small">
{renderNavigationItems("xsmall")}
{logIn && renderLoginButton("xsmall")}
</MenuBar>
</div>
{/* 640-1023px (md: breakpoint): MenuBar X Small (different from folderTop=true) */}
<div className="hidden md:block lg:hidden" data-testid="nav-md">
<MenuBar size="default">
<MenuBar size="X Small">
{renderNavigationItems("xsmall")}
</MenuBar>
</div>
<div className="hidden lg:block xl:hidden" data-testid="nav-lg">
<MenuBar size="large">{renderNavigationItems("large")}</MenuBar>
<MenuBar size="Large">{renderNavigationItems("large")}</MenuBar>
</div>
<div className="hidden xl:block" data-testid="nav-xl">
<MenuBar size="large">{renderNavigationItems("xlarge")}</MenuBar>
<MenuBar size="X Large">{renderNavigationItems("xlarge")}</MenuBar>
</div>
</div>
{/* Authentication Elements - Consistent right alignment across all breakpoints */}
<div className="flex items-center">
{/* XSmall breakpoint - All navigation items + Create Rule button */}
<div className="block sm:hidden" data-testid="auth-xs">
<div className="flex items-center gap-[var(--spacing-scale-001)]">
<MenuBar size="default">
{renderNavigationItems("xsmall")}
{logIn && renderLoginButton("xsmall")}
</MenuBar>
{renderCreateRuleButton("xsmall", "small", "small")}
</div>
<div className="flex items-center shrink-0">
{/* XSmall breakpoint - Only Create Rule button */}
<div className="block sm:hidden shrink-0" data-testid="auth-xs">
{renderCreateRuleButton("xsmall", "small", "small")}
</div>
{/* Small breakpoint - Only Create Rule button */}
@@ -203,7 +226,7 @@ function TopNavView({
{/* Medium breakpoint */}
<div className="hidden md:block lg:hidden" data-testid="auth-md">
<div className="flex items-center gap-[var(--spacing-measures-spacing-010)]">
<MenuBar size="default">
<MenuBar size="Small">
{logIn && renderLoginButton("xsmall")}
</MenuBar>
{renderCreateRuleButton("xsmall", "medium", "medium")}
@@ -213,7 +236,7 @@ function TopNavView({
{/* Large breakpoint */}
<div className="hidden lg:block xl:hidden" data-testid="auth-lg">
<div className="flex items-center gap-[var(--spacing-measures-spacing-004)]">
<MenuBar size="large">
<MenuBar size="Large">
{logIn && renderLoginButton("large")}
</MenuBar>
{renderCreateRuleButton("large", "xlarge", "xlarge")}
@@ -223,7 +246,7 @@ function TopNavView({
{/* XLarge breakpoint */}
<div className="hidden xl:block" data-testid="auth-xl">
<div className="flex items-center gap-[var(--spacing-measures-spacing-004)]">
<MenuBar size="large">
<MenuBar size="X Large">
{logIn && renderLoginButton("xlarge")}
</MenuBar>
{renderCreateRuleButton("xlarge", "xlarge", "xlarge")}
+65 -23
View File
@@ -238,33 +238,23 @@ export type SizeValue =
| "XLarge";
/**
* Normalize menu bar size prop values
* Normalize MenuBar size prop values to Figma specifications
* Maps to: "X Small" | "Small" | "Medium" | "Large" | "X Large"
* Also supports legacy format for backward compatibility
*/
export function normalizeMenuBarSize(
value: string | undefined,
defaultValue: "default" = "default"
): "xsmall" | "default" | "medium" | "large" {
defaultValue: "X Small" | "Small" | "Medium" | "Large" | "X Large" = "X Small"
): "X Small" | "Small" | "Medium" | "Large" | "X Large" {
if (!value) return defaultValue;
const normalized = value.toLowerCase();
const sizes = ["xsmall", "default", "medium", "large"];
if (sizes.includes(normalized)) {
return normalized as typeof defaultValue;
}
return defaultValue;
}
/**
* Normalize menu bar item variant prop values
*/
export function normalizeMenuBarItemVariant(
value: string | undefined,
defaultValue: "default" = "default"
): "default" | "home" {
if (!value) return defaultValue;
const normalized = value.toLowerCase();
const variants = ["default", "home"];
if (variants.includes(normalized)) {
return normalized as typeof defaultValue;
if (
value === "X Small" ||
value === "Small" ||
value === "Medium" ||
value === "Large" ||
value === "X Large"
) {
return value;
}
return defaultValue;
}
@@ -650,3 +640,55 @@ export function normalizeInputLabelPalette(
}
return defaultValue;
}
/**
* Normalize MenuBarItem state prop values (Default/Hover/Selected -> default/hover/selected)
*/
export function normalizeMenuBarItemState(
value: string | undefined,
defaultValue: "default" | "hover" | "selected" = "default"
): "default" | "hover" | "selected" {
if (!value) return defaultValue;
if (value === "default" || value === "hover" || value === "selected") {
return value;
}
return defaultValue;
}
/**
* Normalize MenuBarItem mode prop values.
* Default mode: yellow text on dark background (standard header)
* Inverse mode: black text on yellow background (folderTop variant)
*/
export function normalizeMenuBarItemMode(
value: string | undefined,
defaultValue: "default" | "inverse" = "default"
): "default" | "inverse" {
if (!value) return defaultValue;
if (value === "default" || value === "inverse") {
return value;
}
return defaultValue;
}
/**
* Normalize MenuBarItem size prop values.
* Accepts: "X Small", "Small", "Medium", "Large", "X Large"
*/
export function normalizeMenuBarItemSize(
value: string | undefined,
defaultValue: "X Small" | "Small" | "Medium" | "Large" | "X Large" = "X Small"
): "X Small" | "Small" | "Medium" | "Large" | "X Large" {
if (!value) return defaultValue;
if (
value === "X Small" ||
value === "Small" ||
value === "Medium" ||
value === "Large" ||
value === "X Large"
) {
return value;
}
return defaultValue;
}
-38
View File
@@ -1,38 +0,0 @@
import HeaderTab from "../../app/components/navigation/HeaderTab";
import Logo from "../../app/components/icons/Logo";
export default {
title: "Components/Navigation/HeaderTab",
component: HeaderTab,
parameters: {
layout: "centered",
docs: {
description: {
component:
"A header tab container with decorative Union images and responsive behavior. Used to wrap content in the header with consistent styling and responsive breakpoint transitions.",
},
},
},
argTypes: {
stretch: {
control: { type: "boolean" },
description: "Whether the tab should stretch to fill available space",
},
className: {
control: { type: "text" },
description: "Additional CSS classes",
},
},
tags: ["autodocs"],
};
export const Default = {
args: {
stretch: false,
},
render: (args) => (
<HeaderTab {...args}>
<Logo size="homeHeaderMd" />
</HeaderTab>
),
};
+32 -23
View File
@@ -16,7 +16,7 @@ export default {
argTypes: {
size: {
control: { type: "select" },
options: ["xsmall", "default", "medium", "large"],
options: ["X Small", "Small", "Medium", "Large", "X Large"],
description: "The size of the menu bar and its children",
},
className: {
@@ -29,13 +29,13 @@ export default {
export const Default = {
args: {
size: "default",
size: "Small",
},
render: (args) => (
<MenuBar {...args}>
<MenuBarItem size="large">Home</MenuBarItem>
<MenuBarItem size="large">About</MenuBarItem>
<MenuBarItem size="large">Contact</MenuBarItem>
<MenuBarItem size="Large">Home</MenuBarItem>
<MenuBarItem size="Large">About</MenuBarItem>
<MenuBarItem size="Large">Contact</MenuBarItem>
</MenuBar>
),
};
@@ -45,38 +45,47 @@ export const Sizes = {
render: () => (
<div className="space-y-6">
<div>
<h3 className="text-white font-semibold mb-3">XSmall Size</h3>
<MenuBar size="xsmall">
<MenuBarItem size="xsmall">Home</MenuBarItem>
<MenuBarItem size="xsmall">About</MenuBarItem>
<MenuBarItem size="xsmall">Contact</MenuBarItem>
<h3 className="text-white font-semibold mb-3">X Small Size</h3>
<MenuBar size="X Small">
<MenuBarItem size="X Small">Home</MenuBarItem>
<MenuBarItem size="X Small">About</MenuBarItem>
<MenuBarItem size="X Small">Contact</MenuBarItem>
</MenuBar>
</div>
<div>
<h3 className="text-white font-semibold mb-3">Default Size</h3>
<MenuBar size="default">
<MenuBarItem size="large">Home</MenuBarItem>
<MenuBarItem size="large">About</MenuBarItem>
<MenuBarItem size="large">Contact</MenuBarItem>
<h3 className="text-white font-semibold mb-3">Small Size</h3>
<MenuBar size="Small">
<MenuBarItem size="Large">Home</MenuBarItem>
<MenuBarItem size="Large">About</MenuBarItem>
<MenuBarItem size="Large">Contact</MenuBarItem>
</MenuBar>
</div>
<div>
<h3 className="text-white font-semibold mb-3">Medium Size</h3>
<MenuBar size="medium">
<MenuBarItem size="large">Home</MenuBarItem>
<MenuBarItem size="large">About</MenuBarItem>
<MenuBarItem size="large">Contact</MenuBarItem>
<MenuBar size="Medium">
<MenuBarItem size="Large">Home</MenuBarItem>
<MenuBarItem size="Large">About</MenuBarItem>
<MenuBarItem size="Large">Contact</MenuBarItem>
</MenuBar>
</div>
<div>
<h3 className="text-white font-semibold mb-3">Large Size</h3>
<MenuBar size="large">
<MenuBarItem size="large">Home</MenuBarItem>
<MenuBarItem size="large">About</MenuBarItem>
<MenuBarItem size="large">Contact</MenuBarItem>
<MenuBar size="Large">
<MenuBarItem size="Large">Home</MenuBarItem>
<MenuBarItem size="Large">About</MenuBarItem>
<MenuBarItem size="Large">Contact</MenuBarItem>
</MenuBar>
</div>
<div>
<h3 className="text-white font-semibold mb-3">X Large Size</h3>
<MenuBar size="X Large">
<MenuBarItem size="X Large">Home</MenuBarItem>
<MenuBarItem size="X Large">About</MenuBarItem>
<MenuBarItem size="X Large">Contact</MenuBarItem>
</MenuBar>
</div>
</div>
+40 -43
View File
@@ -13,23 +13,14 @@ export default {
},
},
argTypes: {
variant: {
mode: {
control: { type: "select" },
options: ["default", "home"],
description: "The visual style variant of the menu item",
options: ["default", "inverse"],
description: "The visual style mode of the menu item",
},
size: {
control: { type: "select" },
options: [
"xsmall",
"xsmallUseCases",
"homeMd",
"homeUseCases",
"large",
"largeUseCases",
"homeXlarge",
"xlarge",
],
options: ["X Small", "Small", "Medium", "Large", "X Large"],
description: "The size of the menu item",
},
disabled: {
@@ -48,23 +39,23 @@ export default {
export const Default = {
args: {
children: "Menu Item",
size: "large",
size: "Large",
},
};
export const Variants = {
export const Modes = {
args: {
children: "Menu Item",
size: "large",
size: "Large",
},
render: (args) => (
<div className="space-y-4">
<div className="space-x-4">
<MenuBarItem {...args} variant="default">
<MenuBarItem {...args} mode="default">
Default
</MenuBarItem>
<MenuBarItem {...args} variant="home">
Home
<MenuBarItem {...args} mode="inverse">
Inverse
</MenuBarItem>
</div>
</div>
@@ -72,7 +63,7 @@ export const Variants = {
parameters: {
docs: {
description: {
story: "Different visual variants of the menu item component.",
story: "Different visual modes of the menu item component.",
},
},
},
@@ -81,19 +72,25 @@ export const Variants = {
export const Sizes = {
args: {
children: "Menu Item",
variant: "default",
mode: "default",
},
render: (args) => (
<div className="space-y-4">
<div className="space-x-4">
<MenuBarItem {...args} size="xsmall">
XSmall
<MenuBarItem {...args} size="X Small">
X Small
</MenuBarItem>
<MenuBarItem {...args} size="large">
<MenuBarItem {...args} size="Small">
Small
</MenuBarItem>
<MenuBarItem {...args} size="Medium">
Medium
</MenuBarItem>
<MenuBarItem {...args} size="Large">
Large
</MenuBarItem>
<MenuBarItem {...args} size="xlarge">
XLarge
<MenuBarItem {...args} size="X Large">
X Large
</MenuBarItem>
</div>
</div>
@@ -110,8 +107,8 @@ export const Sizes = {
export const States = {
args: {
children: "Menu Item",
size: "large",
variant: "default",
size: "Large",
mode: "default",
},
render: (args) => (
<div className="space-y-4">
@@ -132,30 +129,30 @@ export const States = {
},
};
export const AllVariants = {
export const AllModes = {
args: {},
render: () => (
<div className="space-y-6">
<div>
<h3 className="text-white font-semibold mb-3">Default Variant</h3>
<h3 className="text-white font-semibold mb-3">Default Mode</h3>
<div className="space-x-4">
<MenuBarItem size="xsmall">XSmall</MenuBarItem>
<MenuBarItem size="large">Large</MenuBarItem>
<MenuBarItem size="xlarge">XLarge</MenuBarItem>
<MenuBarItem size="X Small" mode="default">X Small</MenuBarItem>
<MenuBarItem size="Large" mode="default">Large</MenuBarItem>
<MenuBarItem size="X Large" mode="default">X Large</MenuBarItem>
</div>
</div>
<div>
<h3 className="text-white font-semibold mb-3">Home Variant</h3>
<h3 className="text-white font-semibold mb-3">Inverse Mode</h3>
<div className="space-x-4">
<MenuBarItem variant="home" size="xsmall">
XSmall
<MenuBarItem mode="inverse" size="X Small">
X Small
</MenuBarItem>
<MenuBarItem variant="home" size="large">
<MenuBarItem mode="inverse" size="Large">
Large
</MenuBarItem>
<MenuBarItem variant="home" size="xlarge">
XLarge
<MenuBarItem mode="inverse" size="X Large">
X Large
</MenuBarItem>
</div>
</div>
@@ -163,11 +160,11 @@ export const AllVariants = {
<div>
<h3 className="text-white font-semibold mb-3">Disabled States</h3>
<div className="space-x-4">
<MenuBarItem size="large" disabled>
<MenuBarItem size="Large" mode="default" disabled>
Default Disabled
</MenuBarItem>
<MenuBarItem variant="home" size="large" disabled>
Home Disabled
<MenuBarItem mode="inverse" size="Large" disabled>
Inverse Disabled
</MenuBarItem>
</div>
</div>
@@ -177,7 +174,7 @@ export const AllVariants = {
docs: {
description: {
story:
"Complete overview of all menu item variants, sizes, and states.",
"Complete overview of all menu item modes, sizes, and states.",
},
},
},
+3 -3
View File
@@ -8,14 +8,14 @@ export default {
docs: {
description: {
component:
"Unified navigation component that supports two variants: folderTop (home page style with yellow HeaderTab) and standard (dark sticky header). Supports all props from Figma design: size, loggedIn, folderTop, profile, and logIn.",
"Unified navigation component that supports two variants: folderTop (home page style with yellow tab container) and standard (dark sticky header). Supports all props from Figma design: size, loggedIn, folderTop, profile, and logIn.",
},
},
},
argTypes: {
folderTop: {
control: "boolean",
description: "When true, renders the home page variant with HeaderTab wrapper. When false, renders the standard header variant.",
description: "When true, renders the home page variant with yellow tab container. When false, renders the standard header variant.",
},
loggedIn: {
control: "boolean",
@@ -63,7 +63,7 @@ export const HomePage = {
docs: {
description: {
story:
"Home page variant (folderTop=true) with transparent background and yellow HeaderTab wrapper. Use the Viewport toolbar to see responsive behavior.",
"Home page variant (folderTop=true) with transparent background and yellow tab container. Use the Viewport toolbar to see responsive behavior.",
},
},
},