Restore asset/Logo import casing so Turbopack can resolve the module, and align the site lockup gaps with the Figma Asset/Logo instances. Co-authored-by: Cursor <cursoragent@cursor.com>
140 lines
5.0 KiB
TypeScript
140 lines
5.0 KiB
TypeScript
"use client";
|
||
|
||
import { memo } from "react";
|
||
import Link from "next/link";
|
||
import { useTranslation } from "../../../contexts/MessagesContext";
|
||
import { getAssetPath, ASSETS } from "../../../../lib/assetUtils";
|
||
|
||
interface LogoProps {
|
||
size?:
|
||
| "default"
|
||
| "footer"
|
||
| "createFlow"
|
||
| "topNavFolderTop"
|
||
| "topNavHeader";
|
||
/**
|
||
* Visual style: default (dark on light) or inverse (e.g. black/white on teal).
|
||
* @default "default"
|
||
*/
|
||
palette?: "default" | "inverse";
|
||
/**
|
||
* Whether to show the "CommunityRule" wordmark.
|
||
* @default true
|
||
*/
|
||
wordmark?: boolean;
|
||
}
|
||
|
||
interface SizeConfig {
|
||
containerHeight: string;
|
||
gap: string;
|
||
textSize: string;
|
||
lineHeight: string;
|
||
iconSize: string;
|
||
}
|
||
|
||
const Logo = memo<LogoProps>(
|
||
({ size = "default", palette = "default", wordmark = true }) => {
|
||
const t = useTranslation("controlsChrome");
|
||
|
||
// Figma: "Asset / Logo" (4002:6735) — 40×6×27 at 1x; nav/footer/create-flow
|
||
// instances scale that lockup.
|
||
const sizes: Record<string, SizeConfig> = {
|
||
default: {
|
||
containerHeight: "h-[var(--spacing-scale-040)]",
|
||
gap: "gap-[var(--spacing-scale-006)]",
|
||
textSize: "text-[21.97px]",
|
||
lineHeight: "leading-[27.05px]",
|
||
iconSize: "w-[27px] h-[27px]",
|
||
},
|
||
footer: {
|
||
containerHeight: "h-[41px] md:h-[56px] lg:h-[82px]",
|
||
gap: "gap-[6.21px] md:gap-[8.49px] lg:gap-[12.43px]",
|
||
textSize:
|
||
"text-[22.75px] md:text-[31.08px] lg:text-[45.51px]",
|
||
lineHeight:
|
||
"leading-[28px] md:leading-[38.25px] lg:leading-[56.01px]",
|
||
iconSize:
|
||
"w-[27.96px] h-[27.96px] md:w-[38.18px] md:h-[38.18px] lg:w-[55.91px] lg:h-[55.91px]",
|
||
},
|
||
createFlow: {
|
||
containerHeight: "h-[30px] md:h-[var(--spacing-scale-040)]",
|
||
gap: "gap-[4.5px] md:gap-[var(--spacing-scale-006)]",
|
||
textSize: "text-[16.48px] md:text-[21.97px]",
|
||
lineHeight: "leading-[20.28px] md:leading-[27.05px]",
|
||
iconSize: "w-[20.25px] h-[20.25px] md:w-[27px] md:h-[27px]",
|
||
},
|
||
topNavFolderTop: {
|
||
containerHeight:
|
||
"h-[14.1px] sm:h-[21.35px] md:h-[var(--spacing-scale-032)] lg:h-[var(--spacing-scale-040)] xl:h-[50.35px]",
|
||
gap: "gap-0 sm:gap-[3.2px] md:gap-[4.8px] lg:gap-[var(--spacing-scale-006)] xl:gap-[7.5px]",
|
||
textSize:
|
||
"text-[11.57px] sm:text-[11.72px] md:text-[17.58px] lg:text-[21.97px] xl:text-[27.47px]",
|
||
lineHeight:
|
||
"leading-[14.24px] sm:leading-[14.42px] md:leading-[21.64px] lg:leading-[27.05px] xl:leading-[33.81px]",
|
||
iconSize:
|
||
"w-[14.1px] h-[14.1px] sm:w-[14.4px] sm:h-[14.4px] md:w-[21.6px] md:h-[21.6px] lg:w-[27px] lg:h-[27px] xl:w-[33.75px] xl:h-[33.75px]",
|
||
},
|
||
topNavHeader: {
|
||
containerHeight:
|
||
"h-[14.2px] sm:h-[21.22px] md:h-[var(--spacing-scale-032)] lg:h-[40.69px] xl:h-[50.35px]",
|
||
gap: "gap-0 sm:gap-[3.18px] md:gap-[4.85px] lg:gap-[6.06px] xl:gap-[7.5px]",
|
||
textSize:
|
||
"text-[11.57px] sm:text-[11.66px] md:text-[17.76px] lg:text-[22.2px] xl:text-[27.47px]",
|
||
lineHeight:
|
||
"leading-[14.24px] sm:leading-[14.35px] md:leading-[21.86px] lg:leading-[27.32px] xl:leading-[33.81px]",
|
||
iconSize:
|
||
"w-[14.2px] h-[14.2px] sm:w-[14.33px] sm:h-[14.33px] md:w-[21.82px] md:h-[21.82px] lg:w-[27.27px] lg:h-[27.27px] xl:w-[33.75px] xl:h-[33.75px]",
|
||
},
|
||
};
|
||
|
||
const config = sizes[size || "default"] || sizes.default;
|
||
const isInverse = palette === "inverse";
|
||
const textColorClass = isInverse
|
||
? "text-[var(--color-content-invert-primary)]"
|
||
: "text-[var(--color-content-default-primary)]";
|
||
const wordmarkVisibilityClass =
|
||
size === "topNavFolderTop" || size === "topNavHeader"
|
||
? wordmark
|
||
? "hidden sm:block"
|
||
: "hidden"
|
||
: wordmark
|
||
? ""
|
||
: "hidden";
|
||
|
||
return (
|
||
<Link href="/" className="group block" aria-label={t("logoAlt")}>
|
||
<div
|
||
className={`flex items-center ${config.containerHeight} ${
|
||
wordmark ? config.gap : ""
|
||
} cursor-pointer`}
|
||
>
|
||
{/* Logo Text - responsive visibility for topNav sizes */}
|
||
<div
|
||
className={`font-bricolage-grotesque ${textColorClass} ${config.textSize} ${config.lineHeight} font-normal tracking-[0px] transition-opacity duration-200 ease-out group-hover:opacity-80 ${wordmarkVisibilityClass}`}
|
||
aria-label={t("logoText")}
|
||
>
|
||
{t("logoText")}
|
||
</div>
|
||
|
||
{/* Vector Icon */}
|
||
{/* eslint-disable-next-line @next/next/no-img-element */}
|
||
<img
|
||
src={getAssetPath(ASSETS.LOGO)}
|
||
alt={t("logoAlt")}
|
||
width={27}
|
||
height={27}
|
||
className={`flex-shrink-0 ${config.iconSize} origin-center transition-transform duration-200 ease-out group-hover:scale-110 ${
|
||
isInverse ? "brightness-0" : ""
|
||
}`}
|
||
aria-hidden="true"
|
||
/>
|
||
</div>
|
||
</Link>
|
||
);
|
||
},
|
||
);
|
||
|
||
Logo.displayName = "Logo";
|
||
|
||
export default Logo;
|