Match Home, top nav, hero, and logo wall to the current marketing frames.
Puts Workshops in the header, pairs the hero with a static rule card and breakpoint CTAs, and shows the three pilot marks with no wall label. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
1 parent
e12e06f7ce
commit
33cdaf135c
47 files changed
+728
-527
No files matched your search
@@ -1,8 +1,8 @@
|
||||
"use client";
|
||||
|
||||
/**
|
||||
* Figma: "Navigation / Top" (22078-808559); Folder-top 430–639 (18582:22056),
|
||||
* 640–1023 (18580:17113).
|
||||
* Figma: "Navigation / Top" (5944:17779); Folder-top 320–429 (18583:22098),
|
||||
* 430–639 (18582:22056); standard 320–429 (18411:57843).
|
||||
*/
|
||||
|
||||
import { memo, useCallback } from "react";
|
||||
@@ -82,7 +82,7 @@ const TopContainer = memo<TopProps>(
|
||||
const logoSize = folderTop ? "topNavFolderTop" : "topNavHeader";
|
||||
|
||||
const navigationItems = [
|
||||
{ href: "/use-cases", text: t("navigation.useCases"), extraPadding: true },
|
||||
{ href: "/workshops", text: t("navigation.workshops") },
|
||||
{ href: "/learn", text: t("navigation.learn") },
|
||||
{ href: "/about", text: t("navigation.about") },
|
||||
];
|
||||
@@ -93,30 +93,25 @@ const TopContainer = memo<TopProps>(
|
||||
? FOLDER_NAV_ITEM_RESPONSIVE_CLASS
|
||||
: NAV_ITEM_RESPONSIVE_CLASS;
|
||||
|
||||
return navigationItems.map((item) => {
|
||||
const isUseCases = item.extraPadding === true;
|
||||
|
||||
return (
|
||||
<MenuItem
|
||||
key={item.href}
|
||||
href={item.href}
|
||||
size="X Small"
|
||||
mode={mode}
|
||||
state={pathname === item.href ? "selected" : "default"}
|
||||
reducedPadding={isUseCases}
|
||||
className={sizeClass}
|
||||
ariaLabel={t("ariaLabels.navigateToPage").replace(
|
||||
"{text}",
|
||||
item.text,
|
||||
)}
|
||||
>
|
||||
{item.text}
|
||||
</MenuItem>
|
||||
);
|
||||
});
|
||||
return navigationItems.map((item) => (
|
||||
<MenuItem
|
||||
key={item.href}
|
||||
href={item.href}
|
||||
size="X Small"
|
||||
mode={mode}
|
||||
state={pathname === item.href ? "selected" : "default"}
|
||||
className={sizeClass}
|
||||
ariaLabel={t("ariaLabels.navigateToPage").replace(
|
||||
"{text}",
|
||||
item.text,
|
||||
)}
|
||||
>
|
||||
{item.text}
|
||||
</MenuItem>
|
||||
));
|
||||
};
|
||||
|
||||
const renderLoginButton = () => {
|
||||
const renderLoginButton = (className = "") => {
|
||||
const label = loggedIn ? t("buttons.profile") : t("buttons.logIn");
|
||||
const ariaLabel = loggedIn
|
||||
? t("ariaLabels.goToProfile")
|
||||
@@ -124,16 +119,23 @@ const TopContainer = memo<TopProps>(
|
||||
const navSelected =
|
||||
(loggedIn && pathname === "/profile") ||
|
||||
(!loggedIn && pathname === "/login");
|
||||
const loginClassName = folderTop
|
||||
? FOLDER_NAV_ITEM_RESPONSIVE_CLASS
|
||||
: NAV_ITEM_RESPONSIVE_CLASS;
|
||||
const loginClassName = [
|
||||
folderTop
|
||||
? FOLDER_NAV_ITEM_RESPONSIVE_CLASS
|
||||
: NAV_ITEM_RESPONSIVE_CLASS,
|
||||
className,
|
||||
]
|
||||
.filter(Boolean)
|
||||
.join(" ");
|
||||
const inFolderTab = folderTop && className.includes("md:hidden");
|
||||
const mode = inFolderTab ? "inverse" : "default";
|
||||
|
||||
if (loggedIn) {
|
||||
return (
|
||||
<MenuItem
|
||||
href="/profile"
|
||||
size="X Small"
|
||||
mode="default"
|
||||
mode={mode}
|
||||
state={navSelected ? "selected" : "default"}
|
||||
className={loginClassName}
|
||||
ariaLabel={ariaLabel}
|
||||
@@ -154,7 +156,7 @@ const TopContainer = memo<TopProps>(
|
||||
}
|
||||
href="/login"
|
||||
size="X Small"
|
||||
mode="default"
|
||||
mode={mode}
|
||||
state={navSelected ? "selected" : "default"}
|
||||
className={loginClassName}
|
||||
ariaLabel={ariaLabel}
|
||||
@@ -182,8 +184,8 @@ const TopContainer = memo<TopProps>(
|
||||
size="small"
|
||||
className={
|
||||
folderTop
|
||||
? "md:-space-x-[9px] lg:-space-x-[var(--space-250)] xl:-space-x-[13px]"
|
||||
: "lg:-space-x-[var(--space-250)] xl:-space-x-[13px]"
|
||||
? "max-sm:hidden md:-space-x-[9px] lg:-space-x-[var(--space-250)] xl:-space-x-[13px]"
|
||||
: "max-sm:hidden lg:-space-x-[var(--space-250)] xl:-space-x-[13px]"
|
||||
}
|
||||
>
|
||||
{avatarImageSources.map((src, index) => (
|
||||
|
||||
@@ -28,6 +28,6 @@ export interface TopViewProps {
|
||||
};
|
||||
logoSize: "topNavFolderTop" | "topNavHeader";
|
||||
renderNavigationItems: () => React.ReactNode;
|
||||
renderLoginButton: () => React.ReactNode;
|
||||
renderLoginButton: (_className?: string) => React.ReactNode;
|
||||
renderCreateRuleButton: () => React.ReactNode;
|
||||
}
|
||||
@@ -22,8 +22,9 @@ function TopView({
|
||||
}: TopViewProps) {
|
||||
const t = useTranslation(folderTop ? "homeHeader" : "header");
|
||||
|
||||
const loginControl = logIn ? (
|
||||
<Menu size="X Small" className="lg:gap-[var(--space-300)]">
|
||||
const phoneAuthItem = logIn ? renderLoginButton("md:hidden") : null;
|
||||
const desktopAuthItem = logIn ? (
|
||||
<Menu size="X Small" className="hidden md:flex lg:gap-[var(--space-300)]">
|
||||
{renderLoginButton()}
|
||||
</Menu>
|
||||
) : null;
|
||||
@@ -40,13 +41,14 @@ function TopView({
|
||||
className="w-full overflow-visible bg-transparent"
|
||||
role="banner"
|
||||
aria-label={t("ariaLabels.homePageNavigationHeader")}
|
||||
data-figma-node="5944-17779"
|
||||
>
|
||||
<nav
|
||||
className="relative mx-auto flex h-[50px] items-end justify-between pl-[var(--space-200)] pr-[var(--space-400)] pt-[var(--space-250)] sm:h-[62px] sm:px-[var(--space-250)] sm:pr-[var(--space-500)] sm:pt-[var(--space-250)] md:h-[68px] md:px-[var(--space-400)] md:pr-[var(--space-800)] md:pt-[var(--space-400)] lg:h-[68px] lg:pl-[var(--space-600)] lg:pr-[var(--space-1400)] lg:pt-[var(--space-400)] xl:h-[88px] xl:pl-[var(--space-1200)] xl:pr-[var(--space-1400)] xl:pt-[var(--space-600)]"
|
||||
role="navigation"
|
||||
aria-label={t("ariaLabels.mainNavigation")}
|
||||
>
|
||||
<div className="HeaderTab header-breakpoint-transition relative flex h-[var(--space-1000)] w-fit min-w-0 items-center self-end overflow-visible rounded-tl-[var(--radius-400)] rounded-tr-[var(--radius-400)] bg-[var(--color-surface-invert-brand-primary)] pl-[var(--space-300)] pr-[var(--space-300)] sm:mr-[var(--space-200)] sm:h-[52px] sm:w-auto sm:flex-1 sm:rounded-t-[var(--radius-500)] sm:pr-[var(--space-150)] md:h-[52px] md:min-w-0 md:rounded-t-[var(--radius-500)] md:pl-[var(--space-600)] md:pr-[var(--space-300)] lg:mr-[var(--space-600)] lg:h-[52px] lg:rounded-t-[var(--radius-500)] lg:pl-[var(--space-600)] lg:pr-[var(--space-1200)] xl:mr-[var(--space-800)] xl:h-[64px] xl:rounded-t-[var(--radius-500)] xl:pl-[var(--space-800)] xl:pr-[var(--space-3000)]">
|
||||
<div className="HeaderTab header-breakpoint-transition relative flex h-[var(--space-1000)] min-w-0 flex-1 items-center justify-between self-end overflow-visible rounded-tl-[var(--radius-400)] rounded-tr-[var(--radius-400)] bg-[var(--color-surface-invert-brand-primary)] pl-[var(--space-300)] pr-[var(--space-300)] sm:mr-[var(--space-200)] sm:h-[52px] sm:rounded-t-[var(--radius-500)] sm:pr-[var(--space-150)] md:h-[52px] md:rounded-t-[var(--radius-500)] md:pl-[var(--space-600)] md:pr-[var(--space-300)] lg:mr-[var(--space-600)] lg:h-[52px] lg:rounded-t-[var(--radius-500)] lg:pl-[var(--space-600)] lg:pr-[var(--space-1200)] xl:mr-[var(--space-800)] xl:h-[64px] xl:rounded-t-[var(--radius-500)] xl:pl-[var(--space-800)] xl:pr-[var(--space-3000)]">
|
||||
<div className="relative z-[1] shrink-0">
|
||||
<Logo
|
||||
size={logoSize}
|
||||
@@ -56,7 +58,7 @@ function TopView({
|
||||
</div>
|
||||
|
||||
<div
|
||||
className="relative z-[1] shrink-0 md:absolute md:top-1/2 md:left-[calc(50vw-var(--space-400))] md:-translate-x-1/2 md:-translate-y-1/2 lg:left-[calc(50vw-var(--space-600))] xl:left-[calc(50vw-var(--space-1200))]"
|
||||
className="relative z-[1] min-w-0 md:absolute md:top-1/2 md:left-[calc(50vw-var(--space-400))] md:-translate-x-1/2 md:-translate-y-1/2 lg:left-[calc(50vw-var(--space-600))] xl:left-[calc(50vw-var(--space-1200))]"
|
||||
data-top="nav"
|
||||
>
|
||||
<Menu
|
||||
@@ -64,6 +66,7 @@ function TopView({
|
||||
className="md:gap-[var(--space-100)] lg:gap-[var(--space-300)]"
|
||||
>
|
||||
{renderNavigationItems()}
|
||||
{phoneAuthItem}
|
||||
</Menu>
|
||||
</div>
|
||||
|
||||
@@ -94,7 +97,7 @@ function TopView({
|
||||
className="flex shrink-0 items-center gap-[var(--space-100)] self-center md:gap-[var(--space-250)]"
|
||||
data-top="auth"
|
||||
>
|
||||
{loginControl}
|
||||
{desktopAuthItem}
|
||||
{renderCreateRuleButton()}
|
||||
</div>
|
||||
</nav>
|
||||
@@ -105,11 +108,10 @@ function TopView({
|
||||
|
||||
/**
|
||||
* Standard marketing / app top nav.
|
||||
* Figma: "Navigation / Top" (Community-Rule-System, node 22078-808559).
|
||||
* Below md: auto | 1fr | auto so the logo cannot paint over the cluster.
|
||||
* From md: 1fr | auto | 1fr so the cluster sits on the same page midline
|
||||
* as Folder-top (Create rule is wider than the logo, so a leftover-column
|
||||
* center sits off-center).
|
||||
* Figma: "Navigation / Top" (Community-Rule-System, node 5944:17779).
|
||||
* Below md: logo | links (with Log in / Profile) | Create rule, so the mark
|
||||
* cannot paint over the cluster. From md: 1fr | auto | 1fr so the cluster
|
||||
* sits on the page midline.
|
||||
*/
|
||||
return (
|
||||
<>
|
||||
@@ -121,13 +123,17 @@ function TopView({
|
||||
className="relative z-50 w-full border-b border-[var(--border-color-default-tertiary)] bg-[var(--color-surface-default-primary)]"
|
||||
role="banner"
|
||||
aria-label={t("ariaLabels.mainNavigationHeader")}
|
||||
data-figma-node="5944-17779"
|
||||
>
|
||||
<nav
|
||||
className="grid w-full grid-cols-[auto_minmax(0,1fr)_auto] items-center px-[var(--space-400)] py-[var(--space-200)] sm:px-[var(--space-400)] md:grid-cols-[minmax(0,1fr)_auto_minmax(0,1fr)] lg:px-[var(--space-1800)] lg:py-[var(--space-400)]"
|
||||
className="flex w-full items-center gap-[var(--space-200)] px-[var(--space-400)] py-[var(--space-200)] sm:px-[var(--space-400)] md:grid md:grid-cols-[minmax(0,1fr)_auto_minmax(0,1fr)] md:gap-0 lg:px-[var(--space-1800)] lg:py-[var(--space-400)]"
|
||||
role="navigation"
|
||||
aria-label={t("ariaLabels.mainNavigation")}
|
||||
>
|
||||
<div className="min-w-0 shrink-0 justify-self-start lg:w-[200px] lg:max-w-[200px]" data-top="logo">
|
||||
<div
|
||||
className="min-w-0 shrink-0 justify-self-start lg:w-[200px] lg:max-w-[200px]"
|
||||
data-top="logo"
|
||||
>
|
||||
<Logo
|
||||
size={logoSize}
|
||||
wordmark
|
||||
@@ -136,7 +142,7 @@ function TopView({
|
||||
</div>
|
||||
|
||||
<div
|
||||
className="flex min-w-0 items-center justify-end md:justify-center"
|
||||
className="flex min-w-0 flex-1 items-center justify-end md:flex-none md:justify-center"
|
||||
data-top="nav"
|
||||
>
|
||||
<Menu
|
||||
@@ -144,6 +150,7 @@ function TopView({
|
||||
className="min-w-0 lg:gap-[var(--space-300)]"
|
||||
>
|
||||
{renderNavigationItems()}
|
||||
{phoneAuthItem}
|
||||
</Menu>
|
||||
</div>
|
||||
|
||||
@@ -151,7 +158,7 @@ function TopView({
|
||||
className="flex shrink-0 items-center justify-self-end gap-[var(--space-100)] md:gap-[var(--space-250)] lg:gap-[var(--space-100)]"
|
||||
data-top="auth"
|
||||
>
|
||||
{loginControl}
|
||||
{desktopAuthItem}
|
||||
{renderCreateRuleButton()}
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
Reference in new issue
Block a user