Match the 3 Nov color ramps and size-based strokes, and replace leftover palette hex with tokens.
Drop Cookies Settings from the footer, link the Home features that already have pages, and give leftover routes their own descriptions.
This commit is contained in:
1 parent
8d07e00667
commit
ca928e306b
32 files changed
+276
-213
No files matched your search
@@ -5,6 +5,7 @@ import MonitorPageContent from "./MonitorPageContent";
|
|||||||
|
|
||||||
export const metadata: Metadata = routeMetadata("/monitor", {
|
export const metadata: Metadata = routeMetadata("/monitor", {
|
||||||
title: messages.metadata.monitor.title,
|
title: messages.metadata.monitor.title,
|
||||||
|
description: messages.metadata.monitor.description,
|
||||||
});
|
});
|
||||||
|
|
||||||
export default function MonitorPage() {
|
export default function MonitorPage() {
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import { NO_INDEX_ROBOTS, routeMetadata } from "../../../lib/siteMetadata";
|
|||||||
|
|
||||||
export const metadata: Metadata = routeMetadata("/login", {
|
export const metadata: Metadata = routeMetadata("/login", {
|
||||||
title: messages.metadata.login.title,
|
title: messages.metadata.login.title,
|
||||||
|
description: messages.metadata.login.description,
|
||||||
robots: NO_INDEX_ROBOTS,
|
robots: NO_INDEX_ROBOTS,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import ProfilePageClient from "./ProfilePageClient";
|
|||||||
|
|
||||||
export const metadata: Metadata = routeMetadata("/profile", {
|
export const metadata: Metadata = routeMetadata("/profile", {
|
||||||
title: messages.metadata.profile.title,
|
title: messages.metadata.profile.title,
|
||||||
|
description: messages.metadata.profile.description,
|
||||||
robots: NO_INDEX_ROBOTS,
|
robots: NO_INDEX_ROBOTS,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -112,6 +112,14 @@ const Button = memo<ButtonProps>(
|
|||||||
xlarge: "p-[var(--space-400)] gap-[var(--space-200)]",
|
xlarge: "p-[var(--space-400)] gap-[var(--space-200)]",
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const strokeStyles: Record<string, string> = {
|
||||||
|
xsmall: "border-[1px] active:border-[1.25px]",
|
||||||
|
small: "border-[1.25px] active:border-[1.5px]",
|
||||||
|
medium: "border-[1.5px] active:border-[1.75px]",
|
||||||
|
large: "border-[1.75px]",
|
||||||
|
xlarge: "border-[2px]",
|
||||||
|
};
|
||||||
|
|
||||||
const fontStyles: Record<string, string> = {
|
const fontStyles: Record<string, string> = {
|
||||||
xsmall: "text-xx-small-label",
|
xsmall: "text-xx-small-label",
|
||||||
small: "text-x-small-label",
|
small: "text-x-small-label",
|
||||||
@@ -122,21 +130,21 @@ const Button = memo<ButtonProps>(
|
|||||||
|
|
||||||
const variantStyles: Record<string, string> = {
|
const variantStyles: Record<string, string> = {
|
||||||
filled:
|
filled:
|
||||||
"bg-[var(--color-surface-invert-primary)] text-[var(--color-content-invert-primary)] border-[1.5px] border-transparent hover:bg-[var(--color-surface-invert-primary)] hover:text-[var(--color-content-invert-brand-primary)] hover:border-[var(--color-border-invert-brand-primary)] focus-visible:bg-[var(--color-surface-invert-primary)] focus-visible:text-[var(--color-content-invert-brand-primary)] focus-visible:outline-none focus-visible:border-transparent focus-visible:shadow-[var(--shadow-focus-default)] active:bg-[var(--color-surface-invert-brand-primary)] active:text-[var(--color-content-invert-primary)] active:border-[var(--color-border-invert-brand-primary)] active:shadow-none active:scale-[0.98] disabled:bg-[var(--color-surface-default-secondary)] disabled:text-[var(--color-content-invert-tertiary)] disabled:border-transparent disabled:cursor-not-allowed disabled:opacity-50 disabled:active:scale-100",
|
"bg-[var(--color-surface-invert-primary)] text-[var(--color-content-invert-primary)] border-transparent hover:bg-[var(--color-surface-invert-primary)] hover:text-[var(--color-content-invert-brand-primary)] hover:border-[var(--color-border-invert-brand-primary)] focus-visible:bg-[var(--color-surface-invert-primary)] focus-visible:text-[var(--color-content-invert-brand-primary)] focus-visible:outline-none focus-visible:border-transparent focus-visible:shadow-[var(--shadow-focus-default)] active:bg-[var(--color-surface-invert-brand-primary)] active:text-[var(--color-content-invert-primary)] active:border-[var(--color-border-invert-brand-primary)] active:shadow-none active:scale-[0.98] disabled:bg-[var(--color-surface-default-secondary)] disabled:text-[var(--color-content-invert-tertiary)] disabled:border-transparent disabled:cursor-not-allowed disabled:opacity-50 disabled:active:scale-100",
|
||||||
"filled-inverse":
|
"filled-inverse":
|
||||||
"bg-[var(--color-surface-default-primary)] text-[var(--color-content-default-primary)] border-[1.5px] border-transparent hover:bg-[var(--color-surface-default-primary)] hover:text-[var(--color-content-default-brand-primary)] hover:border-[var(--color-border-default-brand-primary)] focus-visible:bg-[var(--color-surface-default-primary)] focus-visible:text-[var(--color-content-default-brand-primary)] focus-visible:outline-none focus-visible:border-transparent focus-visible:shadow-[var(--shadow-focus-invert)] active:bg-[var(--color-surface-default-brand-primary)] active:text-[var(--color-content-default-primary)] active:border-[var(--color-border-default-brand-primary)] active:shadow-none active:scale-[0.98] disabled:bg-[var(--color-surface-invert-secondary)] disabled:text-[var(--color-content-default-tertiary)] disabled:border-transparent disabled:cursor-not-allowed disabled:opacity-50 disabled:active:scale-100",
|
"bg-[var(--color-surface-default-primary)] text-[var(--color-content-default-primary)] border-transparent hover:bg-[var(--color-surface-default-primary)] hover:text-[var(--color-content-default-brand-primary)] hover:border-[var(--color-border-default-brand-primary)] focus-visible:bg-[var(--color-surface-default-primary)] focus-visible:text-[var(--color-content-default-brand-primary)] focus-visible:outline-none focus-visible:border-transparent focus-visible:shadow-[var(--shadow-focus-invert)] active:bg-[var(--color-surface-default-brand-primary)] active:text-[var(--color-content-default-primary)] active:border-[var(--color-border-default-brand-primary)] active:shadow-none active:scale-[0.98] disabled:bg-[var(--color-surface-invert-secondary)] disabled:text-[var(--color-content-default-tertiary)] disabled:border-transparent disabled:cursor-not-allowed disabled:opacity-50 disabled:active:scale-100",
|
||||||
outline:
|
outline:
|
||||||
"bg-transparent text-[var(--color-content-default-primary)] border-[1.5px] border-[var(--color-border-invert-primary)] hover:bg-transparent hover:text-[var(--color-content-default-brand-primary)] hover:border-[1.5px] hover:border-[var(--color-border-default-brand-primary)] focus-visible:bg-transparent focus-visible:text-[var(--color-content-default-primary)] focus-visible:outline-none focus-visible:border-[1.5px] focus-visible:border-[var(--color-border-invert-primary)] focus-visible:shadow-[var(--shadow-focus-default)] active:bg-transparent active:text-[var(--color-content-default-primary)] active:border-[1.5px] active:border-[var(--color-border-default-brand-primary)] active:shadow-none active:scale-[0.98] disabled:bg-[var(--color-surface-default-secondary)] disabled:text-[var(--color-content-invert-tertiary)] disabled:border-[1.5px] disabled:border-transparent disabled:cursor-not-allowed disabled:opacity-50 disabled:active:scale-100",
|
"bg-transparent text-[var(--color-content-default-primary)] border-[var(--color-border-invert-primary)] hover:bg-transparent hover:text-[var(--color-content-default-brand-primary)] hover:border-[var(--color-border-default-brand-primary)] focus-visible:bg-transparent focus-visible:text-[var(--color-content-default-primary)] focus-visible:outline-none focus-visible:border-[var(--color-border-invert-primary)] focus-visible:shadow-[var(--shadow-focus-default)] active:bg-transparent active:text-[var(--color-content-default-primary)] active:border-[var(--color-border-default-brand-primary)] active:shadow-none active:scale-[0.98] disabled:bg-[var(--color-surface-default-secondary)] disabled:text-[var(--color-content-invert-tertiary)] disabled:border-transparent disabled:cursor-not-allowed disabled:opacity-50 disabled:active:scale-100",
|
||||||
"outline-inverse":
|
"outline-inverse":
|
||||||
"bg-transparent text-[var(--color-content-invert-primary)] border-[1.5px] border-[var(--color-border-default-primary)] hover:bg-transparent hover:text-[var(--color-content-invert-brand-primary)] hover:border-[1.5px] hover:border-[var(--color-border-invert-brand-primary)] focus-visible:bg-transparent focus-visible:text-[var(--color-content-invert-primary)] focus-visible:outline-none focus-visible:border-[1.5px] focus-visible:border-[var(--color-border-default-primary)] focus-visible:shadow-[var(--shadow-focus-invert)] active:bg-transparent active:text-[var(--color-content-invert-primary)] active:border-[1.5px] active:border-[var(--color-border-invert-brand-primary)] active:shadow-none active:scale-[0.98] disabled:bg-[var(--color-surface-invert-secondary)] disabled:text-[var(--color-content-default-tertiary)] disabled:border-[1.5px] disabled:border-transparent disabled:cursor-not-allowed disabled:opacity-50 disabled:active:scale-100",
|
"bg-transparent text-[var(--color-content-invert-primary)] border-[var(--color-border-default-primary)] hover:bg-transparent hover:text-[var(--color-content-invert-brand-primary)] hover:border-[var(--color-border-invert-brand-primary)] focus-visible:bg-transparent focus-visible:text-[var(--color-content-invert-primary)] focus-visible:outline-none focus-visible:border-[var(--color-border-default-primary)] focus-visible:shadow-[var(--shadow-focus-invert)] active:bg-transparent active:text-[var(--color-content-invert-primary)] active:border-[var(--color-border-invert-brand-primary)] active:shadow-none active:scale-[0.98] disabled:bg-[var(--color-surface-invert-secondary)] disabled:text-[var(--color-content-default-tertiary)] disabled:border-transparent disabled:cursor-not-allowed disabled:opacity-50 disabled:active:scale-100",
|
||||||
ghost:
|
ghost:
|
||||||
"bg-transparent text-[var(--color-content-default-brand-primary)] border-[1.5px] border-transparent hover:bg-transparent hover:text-[var(--color-content-default-primary)] hover:border-transparent focus-visible:bg-transparent focus-visible:text-[var(--color-content-default-brand-primary)] focus-visible:outline-none focus-visible:border-transparent focus-visible:shadow-[var(--shadow-focus-default)] active:bg-transparent active:text-[var(--color-content-default-primary)] active:border-[var(--color-border-default-brand-primary)] active:shadow-none active:scale-[0.98] disabled:bg-[var(--color-surface-default-secondary)] disabled:text-[var(--color-content-invert-tertiary)] disabled:border-transparent disabled:cursor-not-allowed disabled:opacity-50 disabled:active:scale-100",
|
"bg-transparent text-[var(--color-content-default-brand-primary)] border-transparent hover:bg-transparent hover:text-[var(--color-content-default-primary)] hover:border-transparent focus-visible:bg-transparent focus-visible:text-[var(--color-content-default-brand-primary)] focus-visible:outline-none focus-visible:border-transparent focus-visible:shadow-[var(--shadow-focus-default)] active:bg-transparent active:text-[var(--color-content-default-primary)] active:border-[var(--color-border-default-brand-primary)] active:shadow-none active:scale-[0.98] disabled:bg-[var(--color-surface-default-secondary)] disabled:text-[var(--color-content-invert-tertiary)] disabled:border-transparent disabled:cursor-not-allowed disabled:opacity-50 disabled:active:scale-100",
|
||||||
"ghost-inverse":
|
"ghost-inverse":
|
||||||
"bg-transparent text-[var(--color-content-invert-primary)] border-[1.5px] border-transparent hover:bg-transparent hover:text-[var(--color-content-invert-primary)] hover:border-transparent focus-visible:bg-transparent focus-visible:text-[var(--color-content-invert-brand-primary)] focus-visible:outline-none focus-visible:border-transparent focus-visible:shadow-[var(--shadow-focus-invert)] active:bg-[var(--color-surface-invert-brand-primary)] active:text-[var(--color-content-invert-primary)] active:border-[var(--color-border-invert-brand-primary)] active:shadow-none active:scale-[0.98] disabled:bg-[var(--color-surface-invert-secondary)] disabled:text-[var(--color-content-default-tertiary)] disabled:border-transparent disabled:cursor-not-allowed disabled:opacity-50 disabled:active:scale-100",
|
"bg-transparent text-[var(--color-content-invert-primary)] border-transparent hover:bg-transparent hover:text-[var(--color-content-invert-primary)] hover:border-transparent focus-visible:bg-transparent focus-visible:text-[var(--color-content-invert-brand-primary)] focus-visible:outline-none focus-visible:border-transparent focus-visible:shadow-[var(--shadow-focus-invert)] active:bg-[var(--color-surface-invert-brand-primary)] active:text-[var(--color-content-invert-primary)] active:border-[var(--color-border-invert-brand-primary)] active:shadow-none active:scale-[0.98] disabled:bg-[var(--color-surface-invert-secondary)] disabled:text-[var(--color-content-default-tertiary)] disabled:border-transparent disabled:cursor-not-allowed disabled:opacity-50 disabled:active:scale-100",
|
||||||
danger:
|
danger:
|
||||||
"bg-transparent text-[var(--color-content-default-negative-primary)] border border-[var(--color-border-default-negative-primary)] hover:bg-[var(--color-surface-invert-negative-secondary)] hover:text-[var(--color-content-invert-negative-primary)] hover:border-[var(--color-border-default-negative-primary)] focus-visible:bg-transparent focus-visible:text-[var(--color-content-default-negative-primary)] focus-visible:outline-none focus-visible:border-[var(--color-border-default-negative-primary)] focus-visible:shadow-[var(--shadow-focus-default)] active:bg-[var(--color-surface-invert-negative-primary)] active:text-[var(--color-content-invert-primary)] active:border-[1.5px] active:border-[var(--color-border-default-negative-primary)] active:shadow-none active:scale-[0.98] disabled:bg-[var(--color-surface-default-secondary)] disabled:text-[var(--color-content-invert-tertiary)] disabled:border-transparent disabled:cursor-not-allowed disabled:opacity-50 disabled:active:scale-100",
|
"bg-transparent text-[var(--color-content-default-negative-primary)] border-[var(--color-border-default-negative-primary)] hover:bg-[var(--color-surface-invert-negative-secondary)] hover:text-[var(--color-content-invert-negative-primary)] hover:border-[var(--color-border-default-negative-primary)] focus-visible:bg-transparent focus-visible:text-[var(--color-content-default-negative-primary)] focus-visible:outline-none focus-visible:border-[var(--color-border-default-negative-primary)] focus-visible:shadow-[var(--shadow-focus-default)] active:bg-[var(--color-surface-invert-negative-primary)] active:text-[var(--color-content-invert-primary)] active:border-[var(--color-border-default-negative-primary)] active:shadow-none active:scale-[0.98] disabled:bg-[var(--color-surface-default-secondary)] disabled:text-[var(--color-content-invert-tertiary)] disabled:border-transparent disabled:cursor-not-allowed disabled:opacity-50 disabled:active:scale-100",
|
||||||
"danger-inverse":
|
"danger-inverse":
|
||||||
"bg-transparent text-[var(--color-content-invert-negative-primary)] border border-[var(--color-border-invert-negative-primary)] hover:bg-transparent hover:text-[var(--color-content-invert-negative-primary)] hover:border-[var(--color-border-invert-negative-primary)] focus-visible:bg-transparent focus-visible:text-[var(--color-content-invert-negative-primary)] focus-visible:outline-none focus-visible:border-[var(--color-border-invert-negative-primary)] focus-visible:shadow-[var(--shadow-focus-invert)] active:bg-[var(--color-surface-default-negative-primary)] active:text-[var(--color-content-default-primary)] active:border-[1.5px] active:border-[var(--color-border-default-negative-primary)] active:shadow-none active:scale-[0.98] disabled:bg-[var(--color-surface-invert-secondary)] disabled:text-[var(--color-content-default-tertiary)] disabled:border-transparent disabled:cursor-not-allowed disabled:opacity-50 disabled:active:scale-100",
|
"bg-transparent text-[var(--color-content-invert-negative-primary)] border-[var(--color-border-invert-negative-primary)] hover:bg-transparent hover:text-[var(--color-content-invert-negative-primary)] hover:border-[var(--color-border-invert-negative-primary)] focus-visible:bg-transparent focus-visible:text-[var(--color-content-invert-negative-primary)] focus-visible:outline-none focus-visible:border-[var(--color-border-invert-negative-primary)] focus-visible:shadow-[var(--shadow-focus-invert)] active:bg-[var(--color-surface-default-negative-primary)] active:text-[var(--color-content-default-primary)] active:border-[var(--color-border-default-negative-primary)] active:shadow-none active:scale-[0.98] disabled:bg-[var(--color-surface-invert-secondary)] disabled:text-[var(--color-content-default-tertiary)] disabled:border-transparent disabled:cursor-not-allowed disabled:opacity-50 disabled:active:scale-100",
|
||||||
};
|
};
|
||||||
|
|
||||||
// Hover/focus: color + border only — no scale and no extra outline (those
|
// Hover/focus: color + border only — no scale and no extra outline (those
|
||||||
@@ -144,7 +152,7 @@ const Button = memo<ButtonProps>(
|
|||||||
// and cards: color, opacity, or shadow on hover; scale only on press.
|
// and cards: color, opacity, or shadow on hover; scale only on press.
|
||||||
// State prop is informational for Figma alignment; CSS pseudo-classes own
|
// State prop is informational for Figma alignment; CSS pseudo-classes own
|
||||||
// the actual interaction states.
|
// the actual interaction states.
|
||||||
const baseStyles = `inline-flex items-center justify-start box-border whitespace-nowrap shrink-0 touch-manipulation [-webkit-tap-highlight-color:transparent] ${sizeStyles[size]} rounded-[var(--radius-full)] ${fontStyles[size]} transition-[transform,color,background-color,border-color,box-shadow] duration-150 ease-out cursor-pointer ${variantStyles[variant]}`;
|
const baseStyles = `inline-flex items-center justify-start box-border whitespace-nowrap shrink-0 touch-manipulation [-webkit-tap-highlight-color:transparent] ${sizeStyles[size]} rounded-[var(--radius-full)] ${fontStyles[size]} transition-[transform,color,background-color,border-color,box-shadow] duration-150 ease-out cursor-pointer ${variantStyles[variant]} ${strokeStyles[size]}`;
|
||||||
const combinedStyles = `${baseStyles} ${className}`;
|
const combinedStyles = `${baseStyles} ${className}`;
|
||||||
|
|
||||||
const sharedA11y = {
|
const sharedA11y = {
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ function StatView({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<article
|
<article
|
||||||
className={`relative flex h-auto min-h-[182px] w-full flex-col items-start justify-between rounded-[var(--radius-500)] bg-[var(--color-surface-invert-primary,white)] px-[var(--space-600)] py-[var(--space-800)] sm:h-[170px] sm:min-h-0 sm:p-[var(--space-600)] ${className}`.trim()}
|
className={`relative flex h-auto min-h-[182px] w-full flex-col items-start justify-between rounded-[var(--radius-500)] bg-[var(--color-surface-invert-primary)] px-[var(--space-600)] py-[var(--space-800)] sm:h-[170px] sm:min-h-0 sm:p-[var(--space-600)] ${className}`.trim()}
|
||||||
>
|
>
|
||||||
<div className="relative flex w-full flex-col items-start">
|
<div className="relative flex w-full flex-col items-start">
|
||||||
<div className="relative flex items-center">
|
<div className="relative flex items-center">
|
||||||
@@ -29,16 +29,16 @@ function StatView({
|
|||||||
variant={shapeVariant}
|
variant={shapeVariant}
|
||||||
className="absolute -left-[11px] -top-[21px] size-[80px] rotate-[15deg] opacity-90"
|
className="absolute -left-[11px] -top-[21px] size-[80px] rotate-[15deg] opacity-90"
|
||||||
/>
|
/>
|
||||||
<p className="relative font-bricolage-grotesque text-xx-large-heading text-[var(--color-content-invert-primary,black)]">
|
<p className="relative font-bricolage-grotesque text-xx-large-heading text-[var(--color-content-invert-primary)]">
|
||||||
{value}
|
{value}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<p className="text-small-paragraph text-[var(--color-content-invert-primary,black)]">
|
<p className="text-small-paragraph text-[var(--color-content-invert-primary)]">
|
||||||
{label}
|
{label}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
{asOf ? (
|
{asOf ? (
|
||||||
<p className="w-full text-xx-small-paragraph text-[var(--color-content-invert-tertiary,#2d2d2d)]">
|
<p className="w-full text-xx-small-paragraph text-[var(--color-content-invert-tertiary)]">
|
||||||
{sourcedYear ? (
|
{sourcedYear ? (
|
||||||
<>
|
<>
|
||||||
{asOfPrefix ? <span>{`${asOfPrefix} `}</span> : null}
|
{asOfPrefix ? <span>{`${asOfPrefix} `}</span> : null}
|
||||||
|
|||||||
@@ -33,10 +33,10 @@ const ContentContainerContainer = memo<ContentContainerProps>(
|
|||||||
const onLight = tone === "onLight";
|
const onLight = tone === "onLight";
|
||||||
const titleColor = onLight
|
const titleColor = onLight
|
||||||
? "text-[var(--color-content-default-primary)] group-hover:text-[var(--color-content-default-brand-primary)]"
|
? "text-[var(--color-content-default-primary)] group-hover:text-[var(--color-content-default-brand-primary)]"
|
||||||
: "text-[var(--color-content-invert-brand-royal)] group-hover:text-blue-200";
|
: "text-[var(--color-content-invert-brand-navy)] group-hover:text-[var(--color-content-invert-brand-royal)]";
|
||||||
const bodyColor = onLight
|
const bodyColor = onLight
|
||||||
? "text-[var(--color-content-default-secondary)]"
|
? "text-[var(--color-content-default-secondary)]"
|
||||||
: "text-[var(--color-content-invert-brand-royal)]";
|
: "text-[var(--color-content-invert-brand-navy)]";
|
||||||
|
|
||||||
const getIconImage = (slug: string): string => {
|
const getIconImage = (slug: string): string => {
|
||||||
const resolvedSlug =
|
const resolvedSlug =
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ const CheckboxContainer = memo<CheckboxProps>(
|
|||||||
// Default state: tertiary border, with hover and focus states via CSS
|
// Default state: tertiary border, with hover and focus states via CSS
|
||||||
// Hover changes border to brand primary color
|
// Hover changes border to brand primary color
|
||||||
// Focus removes border and shows shadow (double ring: 2px white inner, 4px dark outer)
|
// Focus removes border and shows shadow (double ring: 2px white inner, 4px dark outer)
|
||||||
return `${baseBox} bg-[var(--color-surface-default-primary)] border border-solid border-[var(--color-border-default-control)] hover:border-[var(--color-border-default-brand-primary,#fdfaa8)] focus:border-transparent focus:shadow-[var(--shadow-focus-invert)] focus:outline-none`;
|
return `${baseBox} bg-[var(--color-surface-default-primary)] border border-solid border-[var(--color-border-default-control)] hover:border-[var(--color-border-default-brand-primary)] focus:border-transparent focus:shadow-[var(--shadow-focus-invert)] focus:outline-none`;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Inverse mode styles per Figma
|
// Inverse mode styles per Figma
|
||||||
@@ -64,7 +64,7 @@ const CheckboxContainer = memo<CheckboxProps>(
|
|||||||
// Inverse: transparent background, white border
|
// Inverse: transparent background, white border
|
||||||
// Hover changes border to brand primary color
|
// Hover changes border to brand primary color
|
||||||
// Focus shows shadow (2px dark inner, 4px white outer) - note: reversed from standard
|
// Focus shows shadow (2px dark inner, 4px white outer) - note: reversed from standard
|
||||||
return `${baseBox} bg-transparent border border-solid border-[var(--color-border-invert-primary,white)] hover:border-[var(--color-border-default-brand-primary,#fdfaa8)] focus:shadow-[var(--shadow-focus-default)] focus:outline-none`;
|
return `${baseBox} bg-transparent border border-solid border-[var(--color-border-invert-primary)] hover:border-[var(--color-border-default-brand-primary)] focus:shadow-[var(--shadow-focus-default)] focus:outline-none`;
|
||||||
}
|
}
|
||||||
|
|
||||||
return baseBox;
|
return baseBox;
|
||||||
@@ -75,8 +75,8 @@ const CheckboxContainer = memo<CheckboxProps>(
|
|||||||
// Checkmark color per Figma
|
// Checkmark color per Figma
|
||||||
const checkGlyphColor = checked
|
const checkGlyphColor = checked
|
||||||
? isStandard
|
? isStandard
|
||||||
? "var(--color-content-default-brand-primary, #fefcc9)" // Light yellow/cream for standard mode
|
? "var(--color-content-default-brand-primary)"
|
||||||
: "var(--color-content-invert-primary, #000000)" // Black for inverse mode
|
: "var(--color-content-invert-primary)"
|
||||||
: "transparent";
|
: "transparent";
|
||||||
|
|
||||||
// Label color
|
// Label color
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ function chipSurfaceStyle(
|
|||||||
palette: ChipViewProps["palette"],
|
palette: ChipViewProps["palette"],
|
||||||
size: ChipViewProps["size"],
|
size: ChipViewProps["size"],
|
||||||
): CSSProperties {
|
): CSSProperties {
|
||||||
const borderWidth = size === "s" ? "1.25px" : "2px";
|
const borderWidth = size === "s" ? "1.25px" : "1.5px";
|
||||||
const reset: CSSProperties = {
|
const reset: CSSProperties = {
|
||||||
appearance: "none",
|
appearance: "none",
|
||||||
WebkitAppearance: "none",
|
WebkitAppearance: "none",
|
||||||
@@ -64,14 +64,14 @@ function chipSurfaceStyle(
|
|||||||
}
|
}
|
||||||
if (state === "selected") {
|
if (state === "selected") {
|
||||||
return paint(
|
return paint(
|
||||||
"var(--color-surface-invert-brand-primary, #fefcc9)",
|
"var(--color-surface-invert-brand-primary)",
|
||||||
"var(--color-content-invert-primary, #000)",
|
"var(--color-content-invert-primary)",
|
||||||
"var(--color-border-default-brand-primary, #fdfaa8)",
|
"var(--color-border-default-brand-primary)",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return paint(
|
return paint(
|
||||||
"transparent",
|
"transparent",
|
||||||
"var(--color-content-default-brand-primary, #fefcc9)",
|
"var(--color-content-default-brand-primary)",
|
||||||
"var(--color-border-default-control)",
|
"var(--color-border-default-control)",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -185,7 +185,7 @@ function ChipView({
|
|||||||
{onCheck && (
|
{onCheck && (
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
className="flex items-center justify-center p-[var(--space-150)] rounded-full hover:bg-[var(--color-surface-default-semi-opaque,rgba(0,0,0,0.1))] transition-colors disabled:opacity-50 disabled:cursor-not-allowed"
|
className="flex items-center justify-center p-[var(--space-150)] rounded-full hover:bg-[var(--color-surface-default-semi-opaque)] transition-colors disabled:opacity-50 disabled:cursor-not-allowed"
|
||||||
aria-label={confirmAriaLabel}
|
aria-label={confirmAriaLabel}
|
||||||
disabled={!inputValue || !inputValue.trim()}
|
disabled={!inputValue || !inputValue.trim()}
|
||||||
onClick={(event) => {
|
onClick={(event) => {
|
||||||
@@ -202,7 +202,7 @@ function ChipView({
|
|||||||
viewBox="0 0 12 12"
|
viewBox="0 0 12 12"
|
||||||
fill="none"
|
fill="none"
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
className="text-[var(--color-content-default-brand-primary,#fefcc9)]"
|
className="text-[var(--color-content-default-brand-primary)]"
|
||||||
>
|
>
|
||||||
<path
|
<path
|
||||||
d="M10 3L4.5 8.5L2 6"
|
d="M10 3L4.5 8.5L2 6"
|
||||||
@@ -224,7 +224,7 @@ function ChipView({
|
|||||||
onChange={(e) => onInputChange?.(e.target.value)}
|
onChange={(e) => onInputChange?.(e.target.value)}
|
||||||
onKeyDown={onInputKeyDown}
|
onKeyDown={onInputKeyDown}
|
||||||
placeholder={typeToAddPlaceholder}
|
placeholder={typeToAddPlaceholder}
|
||||||
className="bg-transparent border-none outline-none flex-1 min-w-0 font-normal text-[color:var(--color-content-default-tertiary,#b4b4b4)] placeholder:text-[color:var(--color-content-default-tertiary,#b4b4b4)]"
|
className="bg-transparent border-none outline-none flex-1 min-w-0 font-normal text-[color:var(--color-content-default-tertiary)] placeholder:text-[color:var(--color-content-default-tertiary)]"
|
||||||
style={{
|
style={{
|
||||||
fontSize: isSmall
|
fontSize: isSmall
|
||||||
? "var(--sizing-300)"
|
? "var(--sizing-300)"
|
||||||
@@ -240,7 +240,7 @@ function ChipView({
|
|||||||
{onClose && (
|
{onClose && (
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
className="flex items-center justify-center p-[var(--space-150)] rounded-full hover:bg-[var(--color-surface-default-semi-opaque,rgba(0,0,0,0.1))] transition-colors"
|
className="flex items-center justify-center p-[var(--space-150)] rounded-full hover:bg-[var(--color-surface-default-semi-opaque)] transition-colors"
|
||||||
aria-label={closeAriaLabel}
|
aria-label={closeAriaLabel}
|
||||||
onClick={(event) => {
|
onClick={(event) => {
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
@@ -253,7 +253,7 @@ function ChipView({
|
|||||||
viewBox="0 0 12 12"
|
viewBox="0 0 12 12"
|
||||||
fill="none"
|
fill="none"
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
className="text-[var(--color-content-default-brand-primary,#fefcc9)]"
|
className="text-[var(--color-content-default-brand-primary)]"
|
||||||
>
|
>
|
||||||
<path
|
<path
|
||||||
d="M9 3L3 9M3 3L9 9"
|
d="M9 3L3 9M3 3L9 9"
|
||||||
@@ -309,7 +309,7 @@ function ChipView({
|
|||||||
{onRemove && !isDisabled && (
|
{onRemove && !isDisabled && (
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
className="ml-[var(--space-050)] p-[var(--space-050)] rounded-full hover:bg-[var(--color-surface-default-semi-opaque,rgba(0,0,0,0.05))]"
|
className="ml-[var(--space-050)] p-[var(--space-050)] rounded-full hover:bg-[var(--color-surface-default-semi-opaque)]"
|
||||||
aria-label={`Remove ${label}`}
|
aria-label={`Remove ${label}`}
|
||||||
onClick={(event) => {
|
onClick={(event) => {
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ function MultiSelectView({
|
|||||||
|
|
||||||
{!formHeader || !label ? (
|
{!formHeader || !label ? (
|
||||||
countCaption.length > 0 ? (
|
countCaption.length > 0 ? (
|
||||||
<p className="w-full text-x-small-paragraph text-[color:var(--color-content-default-tertiary,#b4b4b4)]">
|
<p className="w-full text-x-small-paragraph text-[color:var(--color-content-default-tertiary)]">
|
||||||
{countCaption}
|
{countCaption}
|
||||||
</p>
|
</p>
|
||||||
) : null
|
) : null
|
||||||
@@ -133,7 +133,7 @@ function MultiSelectView({
|
|||||||
className={
|
className={
|
||||||
!addButtonText
|
!addButtonText
|
||||||
? // Circular button with border (Rule style)
|
? // Circular button with border (Rule style)
|
||||||
`${atLimit ? "cursor-not-allowed opacity-60" : "cursor-pointer hover:opacity-80"} bg-[var(--color-surface-default-transparent,rgba(0,0,0,0))] border-[1.25px] ${isInverse ? "border-[var(--color-border-default-primary,#141414)]" : "border-[var(--color-border-default-control)]"} border-solid flex items-center justify-center ${isSmall ? "size-[30px]" : "size-[40px]"} rounded-[var(--radius-full)] shrink-0 transition-opacity`
|
`${atLimit ? "cursor-not-allowed opacity-60" : "cursor-pointer hover:opacity-80"} bg-[var(--color-surface-default-transparent)] border-[1.25px] ${isInverse ? "border-[var(--color-border-default-primary)]" : "border-[var(--color-border-default-control)]"} border-solid flex items-center justify-center ${isSmall ? "size-[30px]" : "size-[40px]"} rounded-[var(--radius-full)] shrink-0 transition-opacity`
|
||||||
: // Text add control (default palette: white label + brand “+”; inverse: inverse primary for both)
|
: // Text add control (default palette: white label + brand “+”; inverse: inverse primary for both)
|
||||||
`${atLimit ? "cursor-not-allowed opacity-60" : "cursor-pointer hover:opacity-80"} flex items-center justify-center overflow-hidden rounded-[var(--radius-full)] shrink-0 transition-opacity ${
|
`${atLimit ? "cursor-not-allowed opacity-60" : "cursor-pointer hover:opacity-80"} flex items-center justify-center overflow-hidden rounded-[var(--radius-full)] shrink-0 transition-opacity ${
|
||||||
isSmall
|
isSmall
|
||||||
@@ -151,8 +151,8 @@ function MultiSelectView({
|
|||||||
xmlns="http://www.w3.org/2000/svg"
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
className={`shrink-0 ${
|
className={`shrink-0 ${
|
||||||
!addButtonText && isInverse
|
!addButtonText && isInverse
|
||||||
? "text-[var(--color-content-invert-primary,black)]"
|
? "text-[var(--color-content-invert-primary)]"
|
||||||
: "text-[var(--color-content-default-brand-primary,#fefcc9)]"
|
: "text-[var(--color-content-default-brand-primary)]"
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
<path
|
<path
|
||||||
@@ -167,8 +167,8 @@ function MultiSelectView({
|
|||||||
<span
|
<span
|
||||||
className={`font-medium ${isSmall ? "text-[length:var(--sizing-300)] leading-[14px]" : "text-medium-label"} ${
|
className={`font-medium ${isSmall ? "text-[length:var(--sizing-300)] leading-[14px]" : "text-medium-label"} ${
|
||||||
isInverse
|
isInverse
|
||||||
? "text-[color:var(--color-content-invert-primary,black)]"
|
? "text-[color:var(--color-content-invert-primary)]"
|
||||||
: "text-[color:var(--color-content-default-primary,white)]"
|
: "text-[color:var(--color-content-default-primary)]"
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
{addButtonText}
|
{addButtonText}
|
||||||
|
|||||||
@@ -53,15 +53,15 @@ const RadioButtonContainer = ({
|
|||||||
// Focus shows shadow (double ring: 2px white inner, 4px dark outer)
|
// Focus shows shadow (double ring: 2px white inner, 4px dark outer)
|
||||||
// When checked, border is brand primary (but changes to invert tertiary on focus)
|
// When checked, border is brand primary (but changes to invert tertiary on focus)
|
||||||
const defaultBorder = checked
|
const defaultBorder = checked
|
||||||
? "border-[var(--color-border-default-brand-primary,#fdfaa8)]"
|
? "border-[var(--color-border-default-brand-primary)]"
|
||||||
: "border-[var(--color-border-default-control)]";
|
: "border-[var(--color-border-default-control)]";
|
||||||
|
|
||||||
// When focused and checked, border should be invert tertiary (#2d2d2d) per Figma
|
// When focused and checked, border should be invert tertiary (#2d2d2d) per Figma
|
||||||
const focusBorder = checked
|
const focusBorder = checked
|
||||||
? "focus:border-[var(--color-content-invert-tertiary,#2d2d2d)]"
|
? "focus:border-[var(--color-content-invert-tertiary)]"
|
||||||
: "focus:border-[var(--color-border-default-control)]";
|
: "focus:border-[var(--color-border-default-control)]";
|
||||||
|
|
||||||
return `${baseBox} bg-[var(--color-surface-default-primary)] border border-solid ${defaultBorder} hover:border-[var(--color-border-default-brand-primary,#fdfaa8)] ${focusBorder} focus:shadow-[var(--shadow-focus-invert)] focus:outline-none`;
|
return `${baseBox} bg-[var(--color-surface-default-primary)] border border-solid ${defaultBorder} hover:border-[var(--color-border-default-brand-primary)] ${focusBorder} focus:shadow-[var(--shadow-focus-invert)] focus:outline-none`;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Inverse mode styles
|
// Inverse mode styles
|
||||||
@@ -71,17 +71,17 @@ const RadioButtonContainer = ({
|
|||||||
// Focus shows shadow (double ring: 2px dark inner, 4px white outer)
|
// Focus shows shadow (double ring: 2px dark inner, 4px white outer)
|
||||||
// When checked, border is brand primary (but changes to white on focus)
|
// When checked, border is brand primary (but changes to white on focus)
|
||||||
const defaultBorder = checked
|
const defaultBorder = checked
|
||||||
? "border-[var(--color-border-default-brand-primary,#fdfaa8)]"
|
? "border-[var(--color-border-default-brand-primary)]"
|
||||||
: "border-[var(--color-border-invert-primary,white)]";
|
: "border-[var(--color-border-invert-primary)]";
|
||||||
|
|
||||||
// Hover border: inverse brand primary for both selected and unselected per Figma
|
// Hover border: inverse brand primary for both selected and unselected per Figma
|
||||||
const hoverBorder =
|
const hoverBorder =
|
||||||
"hover:border-[var(--color-border-invert-brand-primary,#6c6701)]";
|
"hover:border-[var(--color-border-invert-brand-primary)]";
|
||||||
|
|
||||||
// Focus border: when focused and checked, border should be white per Figma
|
// Focus border: when focused and checked, border should be white per Figma
|
||||||
const focusBorder = checked
|
const focusBorder = checked
|
||||||
? "focus:border-[var(--color-border-invert-primary,white)]"
|
? "focus:border-[var(--color-border-invert-primary)]"
|
||||||
: "focus:border-[var(--color-border-invert-primary,white)]";
|
: "focus:border-[var(--color-border-invert-primary)]";
|
||||||
|
|
||||||
return `${baseBox} bg-transparent border border-solid ${defaultBorder} ${hoverBorder} ${focusBorder} focus:shadow-[var(--shadow-focus-default)] focus:outline-none`;
|
return `${baseBox} bg-transparent border border-solid ${defaultBorder} ${hoverBorder} ${focusBorder} focus:shadow-[var(--shadow-focus-default)] focus:outline-none`;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,9 +39,9 @@ export function RadioButtonView({
|
|||||||
<div
|
<div
|
||||||
className={`w-[16px] h-[16px] rounded-full transition-all duration-200 ${
|
className={`w-[16px] h-[16px] rounded-full transition-all duration-200 ${
|
||||||
checked && mode === "standard"
|
checked && mode === "standard"
|
||||||
? "bg-[var(--color-content-default-brand-primary,#fefcc9)] group-hover:!bg-[var(--color-surface-default-brand-primary)]"
|
? "bg-[var(--color-content-default-brand-primary)] group-hover:!bg-[var(--color-surface-default-brand-primary)]"
|
||||||
: checked && mode === "inverse"
|
: checked && mode === "inverse"
|
||||||
? "bg-[var(--color-content-default-primary,#000000)]"
|
? "bg-[var(--color-content-default-primary)]"
|
||||||
: "bg-transparent"
|
: "bg-transparent"
|
||||||
}`}
|
}`}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -52,8 +52,8 @@ export function RadioGroupView({
|
|||||||
<span
|
<span
|
||||||
className={`text-small-paragraph ${
|
className={`text-small-paragraph ${
|
||||||
mode === "inverse"
|
mode === "inverse"
|
||||||
? "text-[var(--color-content-invert-secondary,#1f1f1f)]"
|
? "text-[var(--color-content-invert-secondary)]"
|
||||||
: "text-[var(--color-content-default-secondary,#b4b4b4)]"
|
: "text-[var(--color-content-default-secondary)]"
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
{option.subtext}
|
{option.subtext}
|
||||||
|
|||||||
@@ -109,7 +109,7 @@ export function SelectInputView({
|
|||||||
.replace(/\s+/g, " ");
|
.replace(/\s+/g, " ");
|
||||||
|
|
||||||
if (disabled) {
|
if (disabled) {
|
||||||
return `${baseClasses} bg-[var(--color-surface-default-secondary)] text-[var(--color-content-invert-tertiary,#2d2d2d)] border-[var(--color-border-default-primary)] cursor-not-allowed opacity-40`;
|
return `${baseClasses} bg-[var(--color-surface-default-secondary)] text-[var(--color-content-invert-tertiary)] border-[var(--color-border-default-primary)] cursor-not-allowed opacity-40`;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (error) {
|
if (error) {
|
||||||
@@ -135,7 +135,7 @@ export function SelectInputView({
|
|||||||
// Text color based on filled state
|
// Text color based on filled state
|
||||||
const textColorClass = isFilled
|
const textColorClass = isFilled
|
||||||
? "text-[var(--color-content-default-primary)]"
|
? "text-[var(--color-content-default-primary)]"
|
||||||
: "text-[var(--color-content-default-tertiary,#b4b4b4)]";
|
: "text-[var(--color-content-default-tertiary)]";
|
||||||
|
|
||||||
// Chevron icon
|
// Chevron icon
|
||||||
const chevronClasses = `w-5 h-5 text-[var(--color-content-default-primary)] transition-transform duration-200 ${
|
const chevronClasses = `w-5 h-5 text-[var(--color-content-default-primary)] transition-transform duration-200 ${
|
||||||
@@ -151,7 +151,7 @@ export function SelectInputView({
|
|||||||
{label}
|
{label}
|
||||||
</label>
|
</label>
|
||||||
{asterisk && (
|
{asterisk && (
|
||||||
<span className="text-[var(--color-content-default-negative-primary,#ea4845)] text-xx-small-label">
|
<span className="text-[var(--color-content-default-negative-primary)] text-xx-small-label">
|
||||||
*
|
*
|
||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
@@ -167,7 +167,7 @@ export function SelectInputView({
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
{textOptional && (
|
{textOptional && (
|
||||||
<span className="text-[var(--color-content-default-tertiary,#b4b4b4)] text-xx-small-paragraph">
|
<span className="text-[var(--color-content-default-tertiary)] text-xx-small-paragraph">
|
||||||
Optional text
|
Optional text
|
||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -102,7 +102,7 @@ const TextInputContainer = forwardRef<HTMLInputElement, TextInputProps>(
|
|||||||
if (disabled) {
|
if (disabled) {
|
||||||
return {
|
return {
|
||||||
input:
|
input:
|
||||||
"bg-[var(--color-surface-default-secondary)] text-[var(--color-content-invert-tertiary,#2d2d2d)] border border-solid border-[var(--color-border-default-primary)] cursor-not-allowed",
|
"bg-[var(--color-surface-default-secondary)] text-[var(--color-content-invert-tertiary)] border border-solid border-[var(--color-border-default-primary)] cursor-not-allowed",
|
||||||
label: "text-[var(--color-content-default-secondary)]",
|
label: "text-[var(--color-content-default-secondary)]",
|
||||||
inputWrapper: "relative",
|
inputWrapper: "relative",
|
||||||
focusRing: "",
|
focusRing: "",
|
||||||
@@ -171,7 +171,7 @@ const TextInputContainer = forwardRef<HTMLInputElement, TextInputProps>(
|
|||||||
const inputClasses = `
|
const inputClasses = `
|
||||||
w-full transition-all duration-200 ease-in-out
|
w-full transition-all duration-200 ease-in-out
|
||||||
focus:outline-none focus:ring-0
|
focus:outline-none focus:ring-0
|
||||||
placeholder:text-[var(--color-content-default-tertiary,#b4b4b4)]
|
placeholder:text-[var(--color-content-default-tertiary)]
|
||||||
${sizeStyles.input}
|
${sizeStyles.input}
|
||||||
${stateStyles.input}
|
${stateStyles.input}
|
||||||
${className}
|
${className}
|
||||||
@@ -180,7 +180,7 @@ const TextInputContainer = forwardRef<HTMLInputElement, TextInputProps>(
|
|||||||
// Text color for filled text (placeholder color is handled above)
|
// Text color for filled text (placeholder color is handled above)
|
||||||
const textColorClass = isFilled
|
const textColorClass = isFilled
|
||||||
? "text-[var(--color-content-default-primary)]"
|
? "text-[var(--color-content-default-primary)]"
|
||||||
: "text-[var(--color-content-default-tertiary,#b4b4b4)]";
|
: "text-[var(--color-content-default-tertiary)]";
|
||||||
|
|
||||||
// Form field handlers with disabled state handling
|
// Form field handlers with disabled state handling
|
||||||
const { handleChange, handleBlur } = useFormField<HTMLInputElement>(
|
const { handleChange, handleBlur } = useFormField<HTMLInputElement>(
|
||||||
|
|||||||
@@ -20,22 +20,22 @@ function UploadView({
|
|||||||
|
|
||||||
// Button styles based on active state
|
// Button styles based on active state
|
||||||
const buttonBgClass = isActive
|
const buttonBgClass = isActive
|
||||||
? "bg-[var(--color-surface-invert-primary,white)]"
|
? "bg-[var(--color-surface-invert-primary)]"
|
||||||
: "bg-[var(--color-surface-default-secondary,#141414)]";
|
: "bg-[var(--color-surface-default-secondary)]";
|
||||||
|
|
||||||
const buttonTextColor = isActive
|
const buttonTextColor = isActive
|
||||||
? "text-[color:var(--color-content-invert-primary,black)]"
|
? "text-[color:var(--color-content-invert-primary)]"
|
||||||
: "text-[color:var(--color-content-invert-tertiary,#2d2d2d)]";
|
: "text-[color:var(--color-content-invert-tertiary)]";
|
||||||
|
|
||||||
// Description text color based on active state
|
// Description text color based on active state
|
||||||
const descriptionTextColor = isActive
|
const descriptionTextColor = isActive
|
||||||
? "text-[color:var(--color-content-default-primary,white)]"
|
? "text-[color:var(--color-content-default-primary)]"
|
||||||
: "text-[color:var(--color-content-default-tertiary,#b4b4b4)]";
|
: "text-[color:var(--color-content-default-tertiary)]";
|
||||||
|
|
||||||
// Icon color based on active state
|
// Icon color based on active state
|
||||||
const iconColor = isActive
|
const iconColor = isActive
|
||||||
? "text-[color:var(--color-content-invert-primary,black)]"
|
? "text-[color:var(--color-content-invert-primary)]"
|
||||||
: "text-[color:var(--color-content-invert-tertiary,#2d2d2d)]";
|
: "text-[color:var(--color-content-invert-tertiary)]";
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
@@ -55,7 +55,7 @@ function UploadView({
|
|||||||
|
|
||||||
{/* Upload container — max width per create-flow spec */}
|
{/* Upload container — max width per create-flow spec */}
|
||||||
<div
|
<div
|
||||||
className={`bg-[var(--color-surface-default-secondary,#141414)] mx-auto flex w-full max-w-[474px] shrink-0 items-center justify-center gap-[24px] rounded-[var(--radius-200)] px-[var(--space-600)] py-[var(--space-1200)] ${
|
className={`bg-[var(--color-surface-default-secondary)] mx-auto flex w-full max-w-[474px] shrink-0 items-center justify-center gap-[24px] rounded-[var(--radius-200)] px-[var(--space-600)] py-[var(--space-1200)] ${
|
||||||
state === "error"
|
state === "error"
|
||||||
? "border border-[var(--color-border-default-utility-negative)]"
|
? "border border-[var(--color-border-default-utility-negative)]"
|
||||||
: ""
|
: ""
|
||||||
|
|||||||
@@ -216,9 +216,6 @@ const Footer = memo(({ siteOrigin = PRODUCTION_SITE_ORIGIN }: { siteOrigin?: str
|
|||||||
<Link href={t("legal.termsOfServiceHref")} className={legalLinkClass}>
|
<Link href={t("legal.termsOfServiceHref")} className={legalLinkClass}>
|
||||||
{t("legal.termsOfService")}
|
{t("legal.termsOfService")}
|
||||||
</Link>
|
</Link>
|
||||||
<Link href={t("legal.cookiesSettingsHref")} className={legalLinkClass}>
|
|
||||||
{t("legal.cookiesSettings")}
|
|
||||||
</Link>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -63,22 +63,22 @@ const MenuItemContainer = memo<MenuItemProps>(
|
|||||||
const defaultModeStyles: Record<"default" | "hover" | "selected", string> =
|
const defaultModeStyles: Record<"default" | "hover" | "selected", string> =
|
||||||
{
|
{
|
||||||
default:
|
default:
|
||||||
"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)]",
|
"bg-transparent text-[var(--color-content-default-brand-primary)] hover:bg-[var(--color-gray-800)] hover:text-[var(--color-content-default-brand-primary)]",
|
||||||
hover:
|
hover:
|
||||||
"bg-[var(--color-gray-800)] text-[var(--color-content-default-brand-primary,#fefcc9)]",
|
"bg-[var(--color-gray-800)] text-[var(--color-content-default-brand-primary)]",
|
||||||
selected:
|
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)]",
|
"border border-[var(--color-border-default-brand-primary)] text-[var(--color-content-default-brand-primary)] bg-transparent hover:bg-[var(--color-gray-800)]",
|
||||||
};
|
};
|
||||||
|
|
||||||
// State styles for Inverse mode (black text on yellow HeaderTab / inverse surfaces)
|
// State styles for Inverse mode (black text on yellow HeaderTab / inverse surfaces)
|
||||||
const inverseModeStyles: Record<"default" | "hover" | "selected", string> =
|
const inverseModeStyles: Record<"default" | "hover" | "selected", string> =
|
||||||
{
|
{
|
||||||
default:
|
default:
|
||||||
"bg-transparent text-[var(--color-content-invert-primary,black)] hover:bg-[var(--color-surface-invert-brand-secondary)] hover:text-[var(--color-content-invert-primary,black)]",
|
"bg-transparent text-[var(--color-content-invert-primary)] hover:bg-[var(--color-surface-invert-brand-secondary)] hover:text-[var(--color-content-invert-primary)]",
|
||||||
hover:
|
hover:
|
||||||
"bg-[var(--color-surface-invert-brand-secondary)] text-[var(--color-content-invert-primary,black)]",
|
"bg-[var(--color-surface-invert-brand-secondary)] text-[var(--color-content-invert-primary)]",
|
||||||
selected:
|
selected:
|
||||||
"border border-[var(--color-border-default-primary,#141414)] text-[var(--color-content-invert-primary,black)] bg-transparent hover:bg-[var(--color-surface-invert-brand-secondary)]",
|
"border border-[var(--color-border-default-primary)] text-[var(--color-content-invert-primary)] bg-transparent hover:bg-[var(--color-surface-invert-brand-secondary)]",
|
||||||
};
|
};
|
||||||
|
|
||||||
// Get state styles based on mode
|
// Get state styles based on mode
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ const FeatureGridContainer = memo<FeatureGridProps>(
|
|||||||
),
|
),
|
||||||
descriptionClassName: "text-[var(--color-content-invert-brand-lime)]",
|
descriptionClassName: "text-[var(--color-content-invert-brand-lime)]",
|
||||||
iconSrc: getAssetPath(featureIconPath("arrow-left-right")),
|
iconSrc: getAssetPath(featureIconPath("arrow-left-right")),
|
||||||
|
href: "/how-it-works",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
backgroundColor: "bg-[var(--color-surface-invert-brand-rust)]",
|
backgroundColor: "bg-[var(--color-surface-invert-brand-rust)]",
|
||||||
@@ -42,6 +43,7 @@ const FeatureGridContainer = memo<FeatureGridProps>(
|
|||||||
),
|
),
|
||||||
descriptionClassName: "text-[var(--color-content-invert-brand-rust)]",
|
descriptionClassName: "text-[var(--color-content-invert-brand-rust)]",
|
||||||
iconSrc: getAssetPath(featureIconPath("door-open")),
|
iconSrc: getAssetPath(featureIconPath("door-open")),
|
||||||
|
href: "/blog/integrating-new-members-without-dilution",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
backgroundColor: "bg-[var(--color-surface-invert-brand-teal)]",
|
backgroundColor: "bg-[var(--color-surface-invert-brand-teal)]",
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ export interface Feature {
|
|||||||
description: string;
|
description: string;
|
||||||
descriptionClassName: string;
|
descriptionClassName: string;
|
||||||
iconSrc: string;
|
iconSrc: string;
|
||||||
|
href?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface FeatureGridViewProps extends FeatureGridProps {
|
export interface FeatureGridViewProps extends FeatureGridProps {
|
||||||
|
|||||||
@@ -1,8 +1,35 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
|
import Link from "next/link";
|
||||||
import { useTranslation } from "../../../contexts/MessagesContext";
|
import { useTranslation } from "../../../contexts/MessagesContext";
|
||||||
import ContentLockup from "../../type/ContentLockup";
|
import ContentLockup from "../../type/ContentLockup";
|
||||||
import type { FeatureGridViewProps } from "./FeatureGrid.types";
|
import type { Feature, FeatureGridViewProps } from "./FeatureGrid.types";
|
||||||
|
|
||||||
|
function FeatureTileBody({ feature }: { feature: Feature }) {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div className="size-[40px] shrink-0 overflow-clip">
|
||||||
|
{/* eslint-disable-next-line @next/next/no-img-element -- decorative Figma glyph */}
|
||||||
|
<img
|
||||||
|
src={feature.iconSrc}
|
||||||
|
alt=""
|
||||||
|
width={40}
|
||||||
|
height={40}
|
||||||
|
className="size-full object-contain"
|
||||||
|
role="presentation"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="flex w-full flex-col gap-[var(--space-200)]">
|
||||||
|
<p className="font-semibold text-[17px] leading-[22px] text-[var(--color-content-invert-primary)]">
|
||||||
|
{feature.title}
|
||||||
|
</p>
|
||||||
|
<p className={`text-small-paragraph ${feature.descriptionClassName}`}>
|
||||||
|
{feature.description}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/** Figma **Section / Feature-Grid** [18632:10668](https://www.figma.com/design/agv0VBLiBlcnSAaiAORgPR/Community-Rule-System?node-id=18632-10668&m=dev). */
|
/** Figma **Section / Feature-Grid** [18632:10668](https://www.figma.com/design/agv0VBLiBlcnSAaiAORgPR/Community-Rule-System?node-id=18632-10668&m=dev). */
|
||||||
function FeatureGridView({
|
function FeatureGridView({
|
||||||
@@ -41,34 +68,25 @@ function FeatureGridView({
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="grid w-full grid-cols-1 gap-[var(--space-200)] md:grid-cols-2 md:gap-[var(--space-400)] lg:flex-1">
|
<div className="grid w-full grid-cols-1 gap-[var(--space-200)] md:grid-cols-2 md:gap-[var(--space-400)] lg:flex-1">
|
||||||
{features.map((feature) => (
|
{features.map((feature) => {
|
||||||
<div
|
const tileClassName = `flex flex-col gap-[var(--space-400)] p-[var(--space-600)] ${feature.backgroundColor} rounded-[var(--radius-200)] md:rounded-[var(--radius-400)] lg:rounded-[var(--radius-500)]`;
|
||||||
key={feature.title}
|
if (feature.href) {
|
||||||
className={`flex flex-col gap-[var(--space-400)] p-[var(--space-600)] ${feature.backgroundColor} rounded-[var(--radius-200)] md:rounded-[var(--radius-400)] lg:rounded-[var(--radius-500)]`}
|
return (
|
||||||
>
|
<Link
|
||||||
<div className="size-[40px] shrink-0 overflow-clip">
|
key={feature.title}
|
||||||
{/* eslint-disable-next-line @next/next/no-img-element -- decorative Figma glyph */}
|
href={feature.href}
|
||||||
<img
|
className={`${tileClassName} no-underline touch-manipulation [-webkit-tap-highlight-color:transparent] hover:opacity-90 focus-visible:outline-none focus-visible:shadow-[var(--shadow-focus-invert)]`}
|
||||||
src={feature.iconSrc}
|
|
||||||
alt=""
|
|
||||||
width={40}
|
|
||||||
height={40}
|
|
||||||
className="size-full object-contain"
|
|
||||||
role="presentation"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div className="flex w-full flex-col gap-[var(--space-200)]">
|
|
||||||
<p className="font-semibold text-[17px] leading-[22px] text-[var(--color-content-invert-primary)]">
|
|
||||||
{feature.title}
|
|
||||||
</p>
|
|
||||||
<p
|
|
||||||
className={`text-small-paragraph ${feature.descriptionClassName}`}
|
|
||||||
>
|
>
|
||||||
{feature.description}
|
<FeatureTileBody feature={feature} />
|
||||||
</p>
|
</Link>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<div key={feature.title} className={tileClassName}>
|
||||||
|
<FeatureTileBody feature={feature} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
);
|
||||||
))}
|
})}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -75,7 +75,7 @@ function QuoteBlockView({
|
|||||||
role="region"
|
role="region"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
className="relative box-border flex w-full max-w-[1440px] shrink-0 flex-col items-center justify-center gap-[var(--space-800)] overflow-hidden rounded-[var(--space-500)] bg-[var(--color-surface-invert-brand-primary,#fefcc9)] px-[var(--space-800)] py-[var(--space-1200)] md:px-[var(--space-1800)] md:py-[var(--space-2400)]"
|
className="relative box-border flex w-full max-w-[1440px] shrink-0 flex-col items-center justify-center gap-[var(--space-800)] overflow-hidden rounded-[var(--space-500)] bg-[var(--color-surface-invert-brand-primary)] px-[var(--space-800)] py-[var(--space-1200)] md:px-[var(--space-1800)] md:py-[var(--space-2400)]"
|
||||||
>
|
>
|
||||||
<QuoteStatementDecor />
|
<QuoteStatementDecor />
|
||||||
<div className="relative z-10 flex w-full min-w-0 shrink-0 flex-col items-center text-center">
|
<div className="relative z-10 flex w-full min-w-0 shrink-0 flex-col items-center text-center">
|
||||||
|
|||||||
+4
-3
@@ -2,16 +2,17 @@ import type { Metadata } from "next";
|
|||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import messages from "../messages/en/index";
|
import messages from "../messages/en/index";
|
||||||
import { getTranslation } from "../lib/i18n/getTranslation";
|
import { getTranslation } from "../lib/i18n/getTranslation";
|
||||||
import { NO_INDEX_ROBOTS } from "../lib/siteMetadata";
|
import { NO_INDEX_ROBOTS, routeMetadata } from "../lib/siteMetadata";
|
||||||
import { getGovernanceTemplateCatalogEntry } from "../lib/templates/governanceTemplateCatalog";
|
import { getGovernanceTemplateCatalogEntry } from "../lib/templates/governanceTemplateCatalog";
|
||||||
import Icon from "./components/asset/icon";
|
import Icon from "./components/asset/icon";
|
||||||
import Button from "./components/buttons/Button";
|
import Button from "./components/buttons/Button";
|
||||||
import HeroDecor from "./components/sections/HeroBanner/HeroDecor";
|
import HeroDecor from "./components/sections/HeroBanner/HeroDecor";
|
||||||
|
|
||||||
export const metadata: Metadata = {
|
export const metadata: Metadata = routeMetadata("/404", {
|
||||||
title: messages.metadata.notFound.title,
|
title: messages.metadata.notFound.title,
|
||||||
|
description: messages.metadata.notFound.description,
|
||||||
robots: NO_INDEX_ROBOTS,
|
robots: NO_INDEX_ROBOTS,
|
||||||
};
|
});
|
||||||
|
|
||||||
const NOT_FOUND_TEMPLATE_SLUGS = [
|
const NOT_FOUND_TEMPLATE_SLUGS = [
|
||||||
"consensus",
|
"consensus",
|
||||||
|
|||||||
+83
-80
@@ -202,14 +202,15 @@
|
|||||||
/* Grays & alpha */
|
/* Grays & alpha */
|
||||||
--color-gray-000: #ffffff;
|
--color-gray-000: #ffffff;
|
||||||
--color-gray-050: #f6f6f6;
|
--color-gray-050: #f6f6f6;
|
||||||
--color-gray-100: #e5e5e5;
|
--color-gray-100: #e4e4e4;
|
||||||
--color-gray-200: #d2d2d2;
|
--color-gray-150: #d2d2d2;
|
||||||
--color-gray-300: #b4b4b4;
|
--color-gray-200: #c2c2c2;
|
||||||
--color-gray-400: #8f8f8f;
|
--color-gray-300: #a4a4a4;
|
||||||
--color-gray-500: #666666;
|
--color-gray-400: #8a8a8a;
|
||||||
--color-gray-600: #464646;
|
--color-gray-500: #717171;
|
||||||
--color-gray-700: #2d2d2d;
|
--color-gray-600: #5b5b5b;
|
||||||
--color-gray-800: #1f1f1f;
|
--color-gray-700: #464646;
|
||||||
|
--color-gray-800: #303030;
|
||||||
--color-gray-900: #141414;
|
--color-gray-900: #141414;
|
||||||
--color-gray-1000: #000000;
|
--color-gray-1000: #000000;
|
||||||
|
|
||||||
@@ -244,16 +245,16 @@
|
|||||||
/* Lavender */
|
/* Lavender */
|
||||||
--color-lavender-lavender0: #f0ebff;
|
--color-lavender-lavender0: #f0ebff;
|
||||||
--color-lavender-lavender50: #e8defe;
|
--color-lavender-lavender50: #e8defe;
|
||||||
--color-lavender-lavender100: #e0d1fd;
|
--color-lavender-lavender100: #dccdf9;
|
||||||
--color-lavender-lavender150: #d7c3f9;
|
--color-lavender-lavender150: #d1bdf3;
|
||||||
--color-lavender-lavender200: #ceb5f6;
|
--color-lavender-lavender200: #c6adee;
|
||||||
--color-lavender-lavender300: #bb97ea;
|
--color-lavender-lavender300: #b490e2;
|
||||||
--color-lavender-lavender400: #a578d9;
|
--color-lavender-lavender400: #a275d5;
|
||||||
--color-lavender-lavender500: #8d5ac4;
|
--color-lavender-lavender500: #8f5cc6;
|
||||||
--color-lavender-lavender600: #743ea9;
|
--color-lavender-lavender600: #7c47b2;
|
||||||
--color-lavender-lavender700: #5a278c;
|
--color-lavender-lavender700: #67359b;
|
||||||
--color-lavender-lavender800: #41146c;
|
--color-lavender-lavender800: #50277e;
|
||||||
--color-lavender-lavender900: #2b074d;
|
--color-lavender-lavender900: #38185c;
|
||||||
--color-lavender-lavender1000: #1a0033;
|
--color-lavender-lavender1000: #1a0033;
|
||||||
|
|
||||||
/* Lime */
|
/* Lime */
|
||||||
@@ -274,61 +275,61 @@
|
|||||||
/* Magenta */
|
/* Magenta */
|
||||||
--color-magenta-magenta0: #ffebf0;
|
--color-magenta-magenta0: #ffebf0;
|
||||||
--color-magenta-magenta50: #fedee7;
|
--color-magenta-magenta50: #fedee7;
|
||||||
--color-magenta-magenta100: #fdd1dd;
|
--color-magenta-magenta100: #f8ccd8;
|
||||||
--color-magenta-magenta150: #f9c3d2;
|
--color-magenta-magenta150: #f0bbca;
|
||||||
--color-magenta-magenta200: #f6b5c7;
|
--color-magenta-magenta200: #eaaabc;
|
||||||
--color-magenta-magenta300: #ea97ad;
|
--color-magenta-magenta300: #dd8ba1;
|
||||||
--color-magenta-magenta400: #d97892;
|
--color-magenta-magenta400: #ce6f89;
|
||||||
--color-magenta-magenta500: #c45a76;
|
--color-magenta-magenta500: #be5571;
|
||||||
--color-magenta-magenta600: #a93e5b;
|
--color-magenta-magenta600: #aa3f5b;
|
||||||
--color-magenta-magenta700: #8c2742;
|
--color-magenta-magenta700: #922d47;
|
||||||
--color-magenta-magenta800: #6c142b;
|
--color-magenta-magenta800: #761f33;
|
||||||
--color-magenta-magenta900: #4d071a;
|
--color-magenta-magenta900: #571222;
|
||||||
--color-magenta-magenta1000: #33000e;
|
--color-magenta-magenta1000: #33000e;
|
||||||
|
|
||||||
/* Red */
|
/* Red */
|
||||||
--color-red-red0: #ffebf1;
|
--color-red-red0: #ffebf1;
|
||||||
--color-red-red50: #fec9d6;
|
--color-red-red50: #fec9d6;
|
||||||
--color-red-red100: #fda8b7;
|
--color-red-red100: #ffb6c2;
|
||||||
--color-red-red150: #f98c98;
|
--color-red-red150: #ffa4ac;
|
||||||
--color-red-red200: #f66f78;
|
--color-red-red200: #ff9296;
|
||||||
--color-red-red300: #ea4845;
|
--color-red-red300: #ff6a62;
|
||||||
--color-red-red400: #d93529;
|
--color-red-red400: #ef4c3d;
|
||||||
--color-red-red500: #c42916;
|
--color-red-red500: #d33a26;
|
||||||
--color-red-red600: #a9200b;
|
--color-red-red600: #b62e1a;
|
||||||
--color-red-red700: #8c1905;
|
--color-red-red700: #972613;
|
||||||
--color-red-red800: #6c1301;
|
--color-red-red800: #771f0d;
|
||||||
--color-red-red900: #4d0d00;
|
--color-red-red900: #571707;
|
||||||
--color-red-red1000: #330800;
|
--color-red-red1000: #330800;
|
||||||
|
|
||||||
/* Royal Blue */
|
/* Royal Blue */
|
||||||
--color-royal-blue-royal-blue0: #ebecff;
|
--color-royal-blue-royal-blue0: #ebecff;
|
||||||
--color-royal-blue-royal-blue50: #c9cdfe;
|
--color-royal-blue-royal-blue50: #c9cdfe;
|
||||||
--color-royal-blue-royal-blue100: #a8adfd;
|
--color-royal-blue-royal-blue100: #b9bfff;
|
||||||
--color-royal-blue-royal-blue150: #8c91f9;
|
--color-royal-blue-royal-blue150: #aab1ff;
|
||||||
--color-royal-blue-royal-blue200: #6f74f6;
|
--color-royal-blue-royal-blue200: #99a4ff;
|
||||||
--color-royal-blue-royal-blue300: #4548ea;
|
--color-royal-blue-royal-blue300: #778cff;
|
||||||
--color-royal-blue-royal-blue400: #2b29d9;
|
--color-royal-blue-royal-blue400: #5674ff;
|
||||||
--color-royal-blue-royal-blue500: #1c16c4;
|
--color-royal-blue-royal-blue500: #3a5afe;
|
||||||
--color-royal-blue-royal-blue600: #140ba9;
|
--color-royal-blue-royal-blue600: #2d4adb;
|
||||||
--color-royal-blue-royal-blue700: #0f058c;
|
--color-royal-blue-royal-blue700: #233bb6;
|
||||||
--color-royal-blue-royal-blue800: #0c016c;
|
--color-royal-blue-royal-blue800: #1d2c8f;
|
||||||
--color-royal-blue-royal-blue900: #0a004d;
|
--color-royal-blue-royal-blue900: #171b65;
|
||||||
--color-royal-blue-royal-blue1000: #080033;
|
--color-royal-blue-royal-blue1000: #080033;
|
||||||
|
|
||||||
/* Rust */
|
/* Rust */
|
||||||
--color-rust-rust0: #ffedeb;
|
--color-rust-rust0: #ffedeb;
|
||||||
--color-rust-rust50: #fed8d4;
|
--color-rust-rust50: #fed8d4;
|
||||||
--color-rust-rust100: #fdc4bd;
|
--color-rust-rust100: #ffc6bf;
|
||||||
--color-rust-rust150: #f9b0a6;
|
--color-rust-rust150: #feb4aa;
|
||||||
--color-rust-rust200: #f69c8f;
|
--color-rust-rust200: #fda395;
|
||||||
--color-rust-rust300: #ea7a65;
|
--color-rust-rust300: #f4836e;
|
||||||
--color-rust-rust400: #d96043;
|
--color-rust-rust400: #e46a4c;
|
||||||
--color-rust-rust500: #c44e29;
|
--color-rust-rust500: #cd5632;
|
||||||
--color-rust-rust600: #a94417;
|
--color-rust-rust600: #b04a1f;
|
||||||
--color-rust-rust700: #8c3d0b;
|
--color-rust-rust700: #904111;
|
||||||
--color-rust-rust800: #6c3604;
|
--color-rust-rust800: #703909;
|
||||||
--color-rust-rust900: #4d2c01;
|
--color-rust-rust900: #512f05;
|
||||||
--color-rust-rust1000: #332100;
|
--color-rust-rust1000: #332100;
|
||||||
|
|
||||||
/* Teal */
|
/* Teal */
|
||||||
@@ -392,25 +393,25 @@
|
|||||||
--color-border-invert-warning-primary: var(--color-yellow-yellow600);
|
--color-border-invert-warning-primary: var(--color-yellow-yellow600);
|
||||||
--color-border-invert-negative-primary: var(--color-red-red300);
|
--color-border-invert-negative-primary: var(--color-red-red300);
|
||||||
|
|
||||||
/* Link — nearest palette step for each off-ramp hex */
|
/* Link — Navigation / Link binds content tokens */
|
||||||
--color-link-primary: var(--color-gray-1000);
|
--color-link-primary: var(--color-content-invert-primary);
|
||||||
--color-link-primary-hover: var(--color-gray-500);
|
--color-link-primary-hover: var(--color-content-invert-quaternary);
|
||||||
--color-link-primary-focus: var(--color-gray-500);
|
--color-link-primary-focus: var(--color-content-invert-quaternary);
|
||||||
--color-link-primary-active: var(--color-gray-500);
|
--color-link-primary-active: var(--color-content-invert-quaternary);
|
||||||
--color-link-secondary: var(--color-gray-500);
|
--color-link-secondary: var(--color-content-invert-quaternary);
|
||||||
--color-link-secondary-hover: var(--color-gray-700);
|
--color-link-secondary-hover: var(--color-content-invert-tertiary);
|
||||||
--color-link-secondary-focus: var(--color-gray-700);
|
--color-link-secondary-focus: var(--color-content-invert-tertiary);
|
||||||
--color-link-secondary-active: var(--color-gray-700);
|
--color-link-secondary-active: var(--color-content-invert-tertiary);
|
||||||
--color-link-invert-primary: var(--color-gray-000);
|
--color-link-invert-primary: var(--color-content-default-primary);
|
||||||
--color-link-invert-primary-hover: var(--color-gray-300);
|
--color-link-invert-primary-hover: var(--color-content-default-tertiary);
|
||||||
--color-link-invert-primary-focus: var(--color-gray-300);
|
--color-link-invert-primary-focus: var(--color-content-default-tertiary);
|
||||||
--color-link-invert-primary-active: var(--color-gray-300);
|
--color-link-invert-primary-active: var(--color-content-default-tertiary);
|
||||||
--color-link-invert-secondary: var(--color-gray-300);
|
--color-link-invert-secondary: var(--color-content-default-tertiary);
|
||||||
--color-link-invert-secondary-hover: var(--color-gray-050);
|
--color-link-invert-secondary-hover: var(--color-content-default-primary);
|
||||||
--color-link-invert-secondary-focus: var(--color-gray-050);
|
--color-link-invert-secondary-focus: var(--color-content-default-primary);
|
||||||
--color-link-invert-secondary-active: var(--color-gray-050);
|
--color-link-invert-secondary-active: var(--color-content-default-primary);
|
||||||
--color-border-link-focus: var(--color-gray-1000);
|
--color-border-link-focus: var(--color-border-default-primary);
|
||||||
--color-border-link-invert-focus: var(--color-gray-000);
|
--color-border-link-invert-focus: var(--color-border-invert-primary);
|
||||||
|
|
||||||
/* Content */
|
/* Content */
|
||||||
--color-content-default-brand-accent: var(--color-opacity-700);
|
--color-content-default-brand-accent: var(--color-opacity-700);
|
||||||
@@ -443,10 +444,12 @@
|
|||||||
--color-content-invert-primary: var(--color-gray-1000);
|
--color-content-invert-primary: var(--color-gray-1000);
|
||||||
--color-content-invert-secondary: var(--color-gray-800);
|
--color-content-invert-secondary: var(--color-gray-800);
|
||||||
--color-content-invert-tertiary: var(--color-gray-700);
|
--color-content-invert-tertiary: var(--color-gray-700);
|
||||||
|
--color-content-invert-quaternary: var(--color-gray-500);
|
||||||
--color-content-invert-brand-primary: var(--color-yellow-yellow900);
|
--color-content-invert-brand-primary: var(--color-yellow-yellow900);
|
||||||
--color-content-invert-brand-secondary: var(--color-yellow-yellow800);
|
--color-content-invert-brand-secondary: var(--color-yellow-yellow800);
|
||||||
--color-content-invert-brand-lime: var(--color-lime-lime800);
|
--color-content-invert-brand-lime: var(--color-lime-lime800);
|
||||||
--color-content-invert-brand-royal: var(--color-royal-blue-royal-blue400);
|
--color-content-invert-brand-royal: var(--color-royal-blue-royal-blue700);
|
||||||
|
--color-content-invert-brand-navy: var(--color-royal-blue-royal-blue1000);
|
||||||
--color-content-invert-brand-teal: var(--color-teal-teal700);
|
--color-content-invert-brand-teal: var(--color-teal-teal700);
|
||||||
--color-content-invert-brand-rust: var(--color-rust-rust700);
|
--color-content-invert-brand-rust: var(--color-rust-rust700);
|
||||||
--color-content-invert-brand-lavender: var(--color-lavender-lavender700);
|
--color-content-invert-brand-lavender: var(--color-lavender-lavender700);
|
||||||
@@ -454,7 +457,7 @@
|
|||||||
--color-content-invert-brand-red: var(--color-red-red700);
|
--color-content-invert-brand-red: var(--color-red-red700);
|
||||||
--color-content-invert-positive-primary: var(--color-kiwi-kiwi800);
|
--color-content-invert-positive-primary: var(--color-kiwi-kiwi800);
|
||||||
--color-content-invert-warning-primary: var(--color-yellow-yellow800);
|
--color-content-invert-warning-primary: var(--color-yellow-yellow800);
|
||||||
--color-content-invert-negative-primary: var(--color-red-red500);
|
--color-content-invert-negative-primary: var(--color-red-red600);
|
||||||
|
|
||||||
/* Surface */
|
/* Surface */
|
||||||
--color-surface-default-brand-red: var(--color-red-red700);
|
--color-surface-default-brand-red: var(--color-red-red700);
|
||||||
@@ -463,7 +466,7 @@
|
|||||||
--color-surface-default-brand-lime: var(--color-lime-lime800);
|
--color-surface-default-brand-lime: var(--color-lime-lime800);
|
||||||
--color-surface-default-brand-primary: var(--color-yellow-yellow1000);
|
--color-surface-default-brand-primary: var(--color-yellow-yellow1000);
|
||||||
--color-surface-default-brand-secondary: var(--color-yellow-yellow800);
|
--color-surface-default-brand-secondary: var(--color-yellow-yellow800);
|
||||||
--color-surface-default-brand-royal: var(--color-royal-blue-royal-blue600);
|
--color-surface-default-brand-royal: var(--color-royal-blue-royal-blue700);
|
||||||
--color-surface-default-brand-rust: var(--color-rust-rust700);
|
--color-surface-default-brand-rust: var(--color-rust-rust700);
|
||||||
--color-surface-default-brand-teal: var(--color-teal-teal700);
|
--color-surface-default-brand-teal: var(--color-teal-teal700);
|
||||||
--color-surface-default-positive-secondary: var(--color-kiwi-kiwi1000);
|
--color-surface-default-positive-secondary: var(--color-kiwi-kiwi1000);
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"_comment": "FeatureGrid component defaults (shared across pages). Explore the patterns goes to /learn; feature cards stay non-interactive until destinations are decided.",
|
"_comment": "FeatureGrid component defaults (shared across pages). Explore the patterns goes to /templates. Feature cards link only when a matching page exists.",
|
||||||
"linkText": "Explore the patterns",
|
"linkText": "Explore the patterns",
|
||||||
"linkHref": "/learn",
|
"linkHref": "/templates",
|
||||||
"ariaLabel": "Feature tools and services",
|
"ariaLabel": "Feature tools and services",
|
||||||
"features": {
|
"features": {
|
||||||
"decisionMaking": {
|
"decisionMaking": {
|
||||||
|
|||||||
@@ -31,9 +31,7 @@
|
|||||||
"privacyPolicy": "Privacy Policy",
|
"privacyPolicy": "Privacy Policy",
|
||||||
"privacyPolicyHref": "/privacy",
|
"privacyPolicyHref": "/privacy",
|
||||||
"termsOfService": "Terms of Service",
|
"termsOfService": "Terms of Service",
|
||||||
"termsOfServiceHref": "/terms",
|
"termsOfServiceHref": "/terms"
|
||||||
"cookiesSettings": "Cookies Settings",
|
|
||||||
"cookiesSettingsHref": "/cookies"
|
|
||||||
},
|
},
|
||||||
"license": {
|
"license": {
|
||||||
"_comment": "Replaces Figma's '© All right reserved'. Covers user-facing content (guides, template copy, marketing) per README — not GPL-3.0 application source. Published user-authored rules are a separate grant.",
|
"_comment": "Replaces Figma's '© All right reserved'. Covers user-facing content (guides, template copy, marketing) per README — not GPL-3.0 application source. Published user-authored rules are a separate grant.",
|
||||||
|
|||||||
@@ -7,8 +7,8 @@
|
|||||||
"templatesAlt": "CommunityRule governance templates"
|
"templatesAlt": "CommunityRule governance templates"
|
||||||
},
|
},
|
||||||
"home": {
|
"home": {
|
||||||
"title": "Build structure before you need it — CommunityRule",
|
"title": "CommunityRule | Write down how your community works",
|
||||||
"description": "Strong communities agree on four things early. They settle how they talk, who belongs, how they decide and what happens when they disagree. Write yours down together.",
|
"description": "Write down how your community talks, who belongs, how it decides and what happens when it disagrees. Free for every community.",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"community",
|
"community",
|
||||||
"governance",
|
"governance",
|
||||||
@@ -47,16 +47,20 @@
|
|||||||
"fallbackDescription": "A blog post from our community."
|
"fallbackDescription": "A blog post from our community."
|
||||||
},
|
},
|
||||||
"login": {
|
"login": {
|
||||||
"title": "Log in"
|
"title": "Log in",
|
||||||
|
"description": "Enter your email and we'll send you a magic link to sign in. No password needed!"
|
||||||
},
|
},
|
||||||
"profile": {
|
"profile": {
|
||||||
"title": "Profile"
|
"title": "Profile",
|
||||||
|
"description": "Manage your CommunityRules, saved progress, and account."
|
||||||
},
|
},
|
||||||
"monitor": {
|
"monitor": {
|
||||||
"title": "Monitor"
|
"title": "Monitor",
|
||||||
|
"description": "Real-time monitoring of Core Web Vitals and performance metrics for Community Rule 3.0"
|
||||||
},
|
},
|
||||||
"notFound": {
|
"notFound": {
|
||||||
"title": "Page not found"
|
"title": "Page not found",
|
||||||
|
"description": "Looks like this page didn't make it to a consensus. It may have moved, been removed, or never existed."
|
||||||
},
|
},
|
||||||
"useCases": {
|
"useCases": {
|
||||||
"title": "Use cases",
|
"title": "Use cases",
|
||||||
|
|||||||
@@ -47,22 +47,32 @@ describe("FeatureGrid (behavioral tests)", () => {
|
|||||||
).not.toBeInTheDocument();
|
).not.toBeInTheDocument();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("renders all four feature cards as static tiles", () => {
|
it("links the two features that have pages and leaves the others as tiles", () => {
|
||||||
render(<FeatureGrid title="Test" subtitle="Test" />);
|
render(<FeatureGrid title="Test" subtitle="Test" />);
|
||||||
expect(screen.getByText("Choose how you decide")).toBeInTheDocument();
|
expect(screen.getByText("Choose how you decide")).toBeInTheDocument();
|
||||||
expect(screen.getByText("Name your values")).toBeInTheDocument();
|
|
||||||
expect(screen.getByText("Define membership")).toBeInTheDocument();
|
|
||||||
expect(screen.getByText("Plan for conflict")).toBeInTheDocument();
|
expect(screen.getByText("Plan for conflict")).toBeInTheDocument();
|
||||||
expect(
|
expect(
|
||||||
screen.queryByRole("link", { name: "Choose how you decide" }),
|
screen.queryByRole("link", { name: /Choose how you decide/ }),
|
||||||
).not.toBeInTheDocument();
|
).not.toBeInTheDocument();
|
||||||
|
expect(
|
||||||
|
screen.queryByRole("link", { name: /Plan for conflict/ }),
|
||||||
|
).not.toBeInTheDocument();
|
||||||
|
expect(
|
||||||
|
screen.getByRole("link", { name: /Name your values/ }),
|
||||||
|
).toHaveAttribute("href", "/how-it-works");
|
||||||
|
expect(
|
||||||
|
screen.getByRole("link", { name: /Define membership/ }),
|
||||||
|
).toHaveAttribute(
|
||||||
|
"href",
|
||||||
|
"/blog/integrating-new-members-without-dilution",
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("sends Explore the patterns to the Learn page", () => {
|
it("sends Explore the patterns to the templates page", () => {
|
||||||
render(<FeatureGrid title="Test" subtitle="Test" />);
|
render(<FeatureGrid title="Test" subtitle="Test" />);
|
||||||
expect(
|
expect(
|
||||||
screen.getByRole("link", { name: "Explore the patterns" }),
|
screen.getByRole("link", { name: "Explore the patterns" }),
|
||||||
).toHaveAttribute("href", "/learn");
|
).toHaveAttribute("href", "/templates");
|
||||||
});
|
});
|
||||||
|
|
||||||
it("does not apply a focus ring to the entire grid shell", () => {
|
it("does not apply a focus ring to the entire grid shell", () => {
|
||||||
|
|||||||
@@ -110,7 +110,7 @@ describe("Footer (behavioral tests)", () => {
|
|||||||
expect(screen.queryByText(/all right reserved/i)).not.toBeInTheDocument();
|
expect(screen.queryByText(/all right reserved/i)).not.toBeInTheDocument();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("renders legal links to privacy, terms, and cookies pages", () => {
|
it("renders legal links to privacy and terms pages", () => {
|
||||||
render(<Footer />);
|
render(<Footer />);
|
||||||
expect(
|
expect(
|
||||||
screen.getAllByRole("link", { name: "Privacy Policy" })[0],
|
screen.getAllByRole("link", { name: "Privacy Policy" })[0],
|
||||||
@@ -119,7 +119,7 @@ describe("Footer (behavioral tests)", () => {
|
|||||||
screen.getAllByRole("link", { name: "Terms of Service" })[0],
|
screen.getAllByRole("link", { name: "Terms of Service" })[0],
|
||||||
).toHaveAttribute("href", "/terms");
|
).toHaveAttribute("href", "/terms");
|
||||||
expect(
|
expect(
|
||||||
screen.getAllByRole("link", { name: "Cookies Settings" })[0],
|
screen.queryByRole("link", { name: "Cookies Settings" }),
|
||||||
).toHaveAttribute("href", "/cookies");
|
).not.toBeInTheDocument();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -37,7 +37,7 @@ describe("Upload (behavioral tests)", () => {
|
|||||||
render(<Upload label="Upload" />);
|
render(<Upload label="Upload" />);
|
||||||
const button = screen.getByRole("button", { name: /upload/i });
|
const button = screen.getByRole("button", { name: /upload/i });
|
||||||
expect(button).toHaveClass(
|
expect(button).toHaveClass(
|
||||||
"bg-[var(--color-surface-invert-primary,white)]",
|
"bg-[var(--color-surface-invert-primary)]",
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -45,7 +45,7 @@ describe("Upload (behavioral tests)", () => {
|
|||||||
render(<Upload label="Upload" active={false} />);
|
render(<Upload label="Upload" active={false} />);
|
||||||
const button = screen.getByRole("button", { name: /upload/i });
|
const button = screen.getByRole("button", { name: /upload/i });
|
||||||
expect(button).toHaveClass(
|
expect(button).toHaveClass(
|
||||||
"bg-[var(--color-surface-default-secondary,#141414)]",
|
"bg-[var(--color-surface-default-secondary)]",
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -95,7 +95,7 @@ describe("Upload (behavioral tests)", () => {
|
|||||||
);
|
);
|
||||||
const descriptionContainer = descriptionText.parentElement;
|
const descriptionContainer = descriptionText.parentElement;
|
||||||
expect(descriptionContainer).toHaveClass(
|
expect(descriptionContainer).toHaveClass(
|
||||||
"text-[color:var(--color-content-default-primary,white)]",
|
"text-[color:var(--color-content-default-primary)]",
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -106,7 +106,7 @@ describe("Upload (behavioral tests)", () => {
|
|||||||
);
|
);
|
||||||
const descriptionContainer = descriptionText.parentElement;
|
const descriptionContainer = descriptionText.parentElement;
|
||||||
expect(descriptionContainer).toHaveClass(
|
expect(descriptionContainer).toHaveClass(
|
||||||
"text-[color:var(--color-content-default-tertiary,#b4b4b4)]",
|
"text-[color:var(--color-content-default-tertiary)]",
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -129,13 +129,24 @@ test.describe("Critical User Journeys", () => {
|
|||||||
featureSection.locator("text=Plan for conflict"),
|
featureSection.locator("text=Plan for conflict"),
|
||||||
).toBeVisible();
|
).toBeVisible();
|
||||||
|
|
||||||
// Feature tiles are presentational — only the lockup "Explore the patterns" is a link
|
|
||||||
await expect(
|
await expect(
|
||||||
featureSection.locator('a[href="#decision-making"]'),
|
featureSection.locator('a[href="#decision-making"]'),
|
||||||
).toHaveCount(0);
|
).toHaveCount(0);
|
||||||
|
await expect(
|
||||||
|
featureSection.getByRole("link", { name: "Choose how you decide" }),
|
||||||
|
).toHaveCount(0);
|
||||||
|
await expect(
|
||||||
|
featureSection.getByRole("link", { name: "Plan for conflict" }),
|
||||||
|
).toHaveCount(0);
|
||||||
|
await expect(
|
||||||
|
featureSection.getByRole("link", { name: "Name your values" }),
|
||||||
|
).toHaveAttribute("href", "/how-it-works");
|
||||||
|
await expect(
|
||||||
|
featureSection.getByRole("link", { name: "Define membership" }),
|
||||||
|
).toHaveAttribute("href", "/blog/integrating-new-members-without-dilution");
|
||||||
await expect(
|
await expect(
|
||||||
featureSection.getByRole("link", { name: "Explore the patterns" }),
|
featureSection.getByRole("link", { name: "Explore the patterns" }),
|
||||||
).toHaveAttribute("href", "/learn");
|
).toHaveAttribute("href", "/templates");
|
||||||
});
|
});
|
||||||
|
|
||||||
test("header navigation functionality", async ({ page }) => {
|
test("header navigation functionality", async ({ page }) => {
|
||||||
|
|||||||
@@ -123,7 +123,7 @@ describe("Page", () => {
|
|||||||
const learnMore = screen.getAllByRole("link", {
|
const learnMore = screen.getAllByRole("link", {
|
||||||
name: "Explore the patterns",
|
name: "Explore the patterns",
|
||||||
});
|
});
|
||||||
expect(learnMore[0]).toHaveAttribute("href", "/learn");
|
expect(learnMore[0]).toHaveAttribute("href", "/templates");
|
||||||
});
|
});
|
||||||
|
|
||||||
test("renders ask organizer section with correct data", () => {
|
test("renders ask organizer section with correct data", () => {
|
||||||
|
|||||||
@@ -12,11 +12,18 @@ function decl(name: string): string {
|
|||||||
describe("Figma tokens", () => {
|
describe("Figma tokens", () => {
|
||||||
it("points theme colors, radius, and focus at Figma", () => {
|
it("points theme colors, radius, and focus at Figma", () => {
|
||||||
expect(decl("--radius-500")).toBe("24px");
|
expect(decl("--radius-500")).toBe("24px");
|
||||||
expect(decl("--color-surface-default-brand-royal")).toContain("royal-blue600");
|
expect(decl("--color-surface-default-brand-royal")).toContain("royal-blue700");
|
||||||
expect(decl("--color-surface-default-brand-kiwi")).toContain("kiwi800");
|
expect(decl("--color-surface-default-brand-kiwi")).toContain("kiwi800");
|
||||||
expect(decl("--color-content-default-brand-secondary")).toContain("yellow200");
|
expect(decl("--color-content-default-brand-secondary")).toContain("yellow200");
|
||||||
expect(decl("--color-content-invert-brand-secondary")).toContain("yellow800");
|
expect(decl("--color-content-invert-brand-secondary")).toContain("yellow800");
|
||||||
expect(decl("--color-content-invert-brand-royal")).toContain("royal-blue400");
|
expect(decl("--color-content-invert-brand-royal")).toContain("royal-blue700");
|
||||||
|
expect(decl("--color-content-invert-brand-navy")).toContain("royal-blue1000");
|
||||||
|
expect(decl("--color-content-invert-quaternary")).toContain("gray-500");
|
||||||
|
expect(decl("--color-content-invert-negative-primary")).toContain("red600");
|
||||||
|
expect(decl("--color-gray-150")).toBe("#d2d2d2");
|
||||||
|
expect(decl("--color-gray-500")).toBe("#717171");
|
||||||
|
expect(decl("--color-royal-blue-royal-blue700")).toBe("#233bb6");
|
||||||
|
expect(decl("--color-red-red600")).toBe("#b62e1a");
|
||||||
expect(decl("--color-content-default-utility-negative")).toContain("red300");
|
expect(decl("--color-content-default-utility-negative")).toContain("red300");
|
||||||
expect(decl("--color-content-default-negative-primary")).toContain(
|
expect(decl("--color-content-default-negative-primary")).toContain(
|
||||||
"utility-negative",
|
"utility-negative",
|
||||||
|
|||||||
Reference in new issue
Block a user