Resolve errors with migrated components

This commit is contained in:
adilallo
2026-01-29 19:07:59 -07:00
parent 539f6c62e3
commit f7e0b5f517
13 changed files with 675 additions and 305 deletions
@@ -1,71 +1,180 @@
"use client";
import { memo, useMemo } from "react";
import { memo } from "react";
import { usePathname } from "next/navigation";
import { useSchemaData } from "../../hooks";
import MenuBarItem from "../MenuBarItem";
import Button from "../Button";
import AvatarContainer from "../AvatarContainer";
import Avatar from "../Avatar";
import Logo from "../Logo";
import { getAssetPath, ASSETS } from "../../../lib/assetUtils";
import HomeHeaderView from "./HomeHeader.view";
import type { HomeHeaderProps } from "./HomeHeader.types";
import type { HomeHeaderProps, NavSize } from "./HomeHeader.types";
// Configuration data for testing
export const navigationItems = [
{ href: "#", text: "Use cases", extraPadding: true },
{ href: "/learn", text: "Learn" },
{ href: "#", text: "About" },
];
export const avatarImages = [
{ src: getAssetPath(ASSETS.AVATAR_1), alt: "Avatar 1" },
{ src: getAssetPath(ASSETS.AVATAR_2), alt: "Avatar 2" },
{ src: getAssetPath(ASSETS.AVATAR_3), alt: "Avatar 3" },
];
export const logoConfig = [
{
breakpoint: "block sm:hidden",
size: "homeHeaderXsmall" as const,
showText: false,
},
{
breakpoint: "hidden sm:block md:hidden",
size: "homeHeaderSm" as const,
showText: true,
},
{
breakpoint: "hidden md:block lg:hidden",
size: "homeHeaderMd" as const,
showText: true,
},
{
breakpoint: "hidden lg:block xl:hidden",
size: "homeHeaderLg" as const,
showText: true,
},
{
breakpoint: "hidden xl:block",
size: "homeHeaderXl" as const,
showText: true,
},
];
const HomeHeaderContainer = memo<HomeHeaderProps>(() => {
const pathname = usePathname();
const { schemaData } = useSchemaData();
// Navigation items configuration
const navigationItems = useMemo(
() => [
{
label: "Home",
href: "/",
isActive: pathname === "/",
},
{
label: "Learn",
href: "/learn",
isActive: pathname === "/learn",
},
{
label: "Monitor",
href: "/monitor",
isActive: pathname === "/monitor",
},
{
label: "Blog",
href: "/blog",
isActive: pathname?.startsWith("/blog") ?? false,
},
],
[pathname],
);
// Schema markup for site navigation (home page specific)
const schemaData = {
"@context": "https://schema.org",
"@type": "WebSite",
name: "CommunityRule",
url: "https://communityrule.com",
description: "Build operating manuals for successful communities",
potentialAction: {
"@type": "SearchAction",
target: "https://communityrule.com/search?q={search_term_string}",
"query-input": "required name=search_term_string",
},
};
// Avatar images configuration
const avatarImages = useMemo(
() => [
{
src: "/assets/avatar-1.svg",
alt: "User avatar 1",
},
{
src: "/assets/avatar-2.svg",
alt: "User avatar 2",
},
{
src: "/assets/avatar-3.svg",
alt: "User avatar 3",
},
],
[],
);
const renderNavigationItems = (size: NavSize) => {
return navigationItems.map((item, index) => (
<MenuBarItem
key={index}
href={item.href}
size={
item.extraPadding &&
(size === "xsmall" ||
size === "default" ||
size === "home" ||
size === "homeMd" ||
size === "large" ||
size === "homeXlarge")
? size === "home" || size === "homeMd"
? "homeMd"
: size === "large"
? "large"
: size === "homeXlarge"
? "homeXlarge"
: "xsmallUseCases"
: size
}
variant={
size === "xsmall" ||
size === "default" ||
size === "home" ||
size === "homeMd" ||
size === "large" ||
size === "homeXlarge"
? "home"
: "default"
}
isActive={pathname === item.href}
ariaLabel={`Navigate to ${item.text} page`}
>
{item.text}
</MenuBarItem>
));
};
// Logo configuration
const logoConfig = useMemo(
() => ({
src: "/assets/logo.svg",
alt: "Community Rule Logo",
width: 120,
height: 32,
}),
[],
);
const renderAvatarGroup = (
containerSize: "small" | "medium" | "large" | "xlarge",
avatarSize: "small" | "medium" | "large" | "xlarge",
) => {
return (
<AvatarContainer size={containerSize}>
{avatarImages.map((avatar, index) => (
<Avatar
key={index}
src={avatar.src}
alt={avatar.alt}
size={avatarSize}
/>
))}
</AvatarContainer>
);
};
const renderLoginButton = (size: NavSize) => {
return (
<MenuBarItem
href="#"
size={size}
variant={size === "xsmall" || size === "default" ? "home" : "default"}
ariaLabel="Log in to your account"
>
Log in
</MenuBarItem>
);
};
const renderCreateRuleButton = (
buttonSize: "xsmall" | "small" | "medium" | "large" | "xlarge",
containerSize: "small" | "medium" | "large" | "xlarge",
avatarSize: "small" | "medium" | "large" | "xlarge",
) => {
return (
<Button
size={buttonSize}
variant="secondary"
ariaLabel="Create a new rule with avatar decoration"
>
{renderAvatarGroup(containerSize, avatarSize)}
<span>Create rule</span>
</Button>
);
};
const renderLogo = (
size:
| "default"
| "homeHeaderXsmall"
| "homeHeaderSm"
| "homeHeaderMd"
| "homeHeaderLg"
| "homeHeaderXl"
| "header"
| "headerMd"
| "headerLg"
| "headerXl"
| "footer"
| "footerLg",
showText: boolean,
) => {
return <Logo size={size} showText={showText} />;
};
return (
<HomeHeaderView
@@ -74,6 +183,11 @@ const HomeHeaderContainer = memo<HomeHeaderProps>(() => {
navigationItems={navigationItems}
avatarImages={avatarImages}
logoConfig={logoConfig}
renderNavigationItems={renderNavigationItems}
renderAvatarGroup={renderAvatarGroup}
renderLoginButton={renderLoginButton}
renderCreateRuleButton={renderCreateRuleButton}
renderLogo={renderLogo}
/>
);
});
+60 -8
View File
@@ -1,23 +1,75 @@
import type React from "react";
export interface HomeHeaderProps {
// Currently no props, but keeping interface for future extensibility
}
export type NavSize =
| "default"
| "xsmall"
| "xsmallUseCases"
| "home"
| "homeMd"
| "homeUseCases"
| "large"
| "largeUseCases"
| "homeXlarge"
| "xlarge";
export interface HomeHeaderViewProps {
pathname: string;
schemaData: object;
navigationItems: Array<{
label: string;
href: string;
isActive: boolean;
text: string;
extraPadding?: boolean;
}>;
avatarImages: Array<{
src: string;
alt: string;
}>;
logoConfig: {
src: string;
alt: string;
width: number;
height: number;
};
logoConfig: Array<{
breakpoint: string;
size:
| "default"
| "homeHeaderXsmall"
| "homeHeaderSm"
| "homeHeaderMd"
| "homeHeaderLg"
| "homeHeaderXl"
| "header"
| "headerMd"
| "headerLg"
| "headerXl"
| "footer"
| "footerLg";
showText: boolean;
}>;
renderNavigationItems: (size: NavSize) => React.ReactNode;
renderAvatarGroup: (
containerSize: "small" | "medium" | "large" | "xlarge",
avatarSize: "small" | "medium" | "large" | "xlarge",
) => React.ReactNode;
renderLoginButton: (size: NavSize) => React.ReactNode;
renderCreateRuleButton: (
buttonSize: "xsmall" | "small" | "medium" | "large" | "xlarge",
containerSize: "small" | "medium" | "large" | "xlarge",
avatarSize: "small" | "medium" | "large" | "xlarge",
) => React.ReactNode;
renderLogo: (
size:
| "default"
| "homeHeaderXsmall"
| "homeHeaderSm"
| "homeHeaderMd"
| "homeHeaderLg"
| "homeHeaderXl"
| "header"
| "headerMd"
| "headerLg"
| "headerXl"
| "footer"
| "footerLg",
showText: boolean,
) => React.ReactNode;
}
+92 -34
View File
@@ -3,9 +3,12 @@
import { memo } from "react";
import Script from "next/script";
import Logo from "../Logo";
import NavigationItem from "../NavigationItem";
import AvatarContainer from "../AvatarContainer";
import HeaderTab from "../HeaderTab";
import MenuBar from "../MenuBar";
import MenuBarItem from "../MenuBarItem";
import Button from "../Button";
import AvatarContainer from "../AvatarContainer";
import Avatar from "../Avatar";
import type { HomeHeaderViewProps } from "./HomeHeader.types";
function HomeHeaderView({
@@ -14,6 +17,11 @@ function HomeHeaderView({
navigationItems,
avatarImages,
logoConfig,
renderNavigationItems,
renderAvatarGroup,
renderLoginButton,
renderCreateRuleButton,
renderLogo,
}: HomeHeaderViewProps) {
return (
<>
@@ -22,41 +30,91 @@ function HomeHeaderView({
type="application/ld+json"
dangerouslySetInnerHTML={{ __html: JSON.stringify(schemaData) }}
/>
<header className="sticky top-0 z-50 bg-[var(--color-surface-default-primary)] border-b border-[var(--color-border-default-tertiary)]">
<div className="max-w-[1440px] mx-auto px-[var(--spacing-scale-016)] md:px-[var(--spacing-scale-032)] lg:px-[var(--spacing-scale-064)]">
<div className="flex items-center justify-between h-[var(--measures-sizing-064)] md:h-[var(--measures-sizing-080)]">
<div className="flex items-center gap-[var(--spacing-scale-040)]">
<Logo
src={logoConfig.src}
alt={logoConfig.alt}
width={logoConfig.width}
height={logoConfig.height}
/>
<nav className="hidden md:flex items-center gap-[var(--spacing-scale-016)]">
{navigationItems.map((item) => (
<NavigationItem
key={item.href}
href={item.href}
isActive={item.isActive}
>
{item.label}
</NavigationItem>
))}
</nav>
<header
className="w-full bg-transparent overflow-hidden"
role="banner"
aria-label="Home page navigation header"
>
<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)]"
role="navigation"
aria-label="Main navigation"
>
<HeaderTab className="flex items-center self-end" stretch={true}>
{/* Logo - Consistent left positioning within HeaderTab */}
<div>
{logoConfig.map((config, index) => (
<div key={index} className={config.breakpoint}>
{renderLogo(config.size, config.showText)}
</div>
))}
</div>
<div className="flex items-center gap-[var(--spacing-scale-016)]">
<AvatarContainer avatars={avatarImages} />
<Button
href="/learn"
variant="primary"
size="medium"
className="hidden md:inline-flex"
>
Get Started
</Button>
{/* XSmall menu bar - positioned next to logo */}
<div className="block sm:hidden -me-[2px]">
<MenuBar size="default">
{renderNavigationItems("xsmall")}
{renderLoginButton("xsmall")}
</MenuBar>
</div>
</HeaderTab>
{/* Navigation Links - Centered in header for SM and up */}
<div className="absolute left-1/2 transform -translate-x-1/2 hidden sm:block">
<div className="hidden sm:block md:hidden">
<MenuBar size="default">
{renderNavigationItems("xsmall")}
{renderLoginButton("xsmall")}
</MenuBar>
</div>
<div className="hidden md:block lg:hidden">
<MenuBar size="medium">{renderNavigationItems("homeMd")}</MenuBar>
</div>
<div className="hidden lg:block xl:hidden">
<MenuBar size="large">{renderNavigationItems("large")}</MenuBar>
</div>
<div className="hidden xl:block">
<MenuBar size="large">
{renderNavigationItems("homeXlarge")}
</MenuBar>
</div>
</div>
</div>
{/* Authentication Elements - Consistent right alignment outside HeaderTab */}
<div className="flex items-center">
{/* XSmall and Small breakpoints - create rule button outside HeaderTab */}
<div className="block md:hidden">
{renderCreateRuleButton("xsmall", "small", "small")}
</div>
{/* Medium breakpoint - login outside HeaderTab, create rule outside */}
<div className="hidden md:block lg:hidden absolute right-[var(--spacing-measures-spacing-016)]">
<div className="flex items-center gap-[var(--spacing-scale-010)]">
{renderLoginButton("homeMd")}
{renderCreateRuleButton("small", "medium", "medium")}
</div>
</div>
{/* Large breakpoint */}
<div className="hidden lg:flex xl:hidden items-center">
<div className="flex items-center gap-[var(--spacing-scale-004)]">
{renderLoginButton("large")}
{renderCreateRuleButton("large", "large", "large")}
</div>
</div>
{/* XLarge breakpoint */}
<div className="hidden xl:flex items-center">
<div className="flex items-center gap-[var(--spacing-scale-004)]">
{renderLoginButton("homeXlarge")}
{renderCreateRuleButton("xlarge", "xlarge", "xlarge")}
</div>
</div>
</div>
</nav>
</header>
</>
);