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
+275
-212
No files matched your search
@@ -5,6 +5,7 @@ import MonitorPageContent from "./MonitorPageContent";
|
||||
|
||||
export const metadata: Metadata = routeMetadata("/monitor", {
|
||||
title: messages.metadata.monitor.title,
|
||||
description: messages.metadata.monitor.description,
|
||||
});
|
||||
|
||||
export default function MonitorPage() {
|
||||
|
||||
@@ -4,6 +4,7 @@ import { NO_INDEX_ROBOTS, routeMetadata } from "../../../lib/siteMetadata";
|
||||
|
||||
export const metadata: Metadata = routeMetadata("/login", {
|
||||
title: messages.metadata.login.title,
|
||||
description: messages.metadata.login.description,
|
||||
robots: NO_INDEX_ROBOTS,
|
||||
});
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ import ProfilePageClient from "./ProfilePageClient";
|
||||
|
||||
export const metadata: Metadata = routeMetadata("/profile", {
|
||||
title: messages.metadata.profile.title,
|
||||
description: messages.metadata.profile.description,
|
||||
robots: NO_INDEX_ROBOTS,
|
||||
});
|
||||
|
||||
|
||||
@@ -112,6 +112,14 @@ const Button = memo<ButtonProps>(
|
||||
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> = {
|
||||
xsmall: "text-xx-small-label",
|
||||
small: "text-x-small-label",
|
||||
@@ -122,21 +130,21 @@ const Button = memo<ButtonProps>(
|
||||
|
||||
const variantStyles: Record<string, string> = {
|
||||
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":
|
||||
"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:
|
||||
"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":
|
||||
"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:
|
||||
"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":
|
||||
"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:
|
||||
"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":
|
||||
"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
|
||||
@@ -144,7 +152,7 @@ const Button = memo<ButtonProps>(
|
||||
// and cards: color, opacity, or shadow on hover; scale only on press.
|
||||
// State prop is informational for Figma alignment; CSS pseudo-classes own
|
||||
// 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 sharedA11y = {
|
||||
|
||||
@@ -21,7 +21,7 @@ function StatView({
|
||||
|
||||
return (
|
||||
<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 items-center">
|
||||
@@ -29,16 +29,16 @@ function StatView({
|
||||
variant={shapeVariant}
|
||||
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}
|
||||
</p>
|
||||
</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}
|
||||
</p>
|
||||
</div>
|
||||
{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 ? (
|
||||
<>
|
||||
{asOfPrefix ? <span>{`${asOfPrefix} `}</span> : null}
|
||||
|
||||
@@ -33,10 +33,10 @@ const ContentContainerContainer = memo<ContentContainerProps>(
|
||||
const onLight = tone === "onLight";
|
||||
const titleColor = onLight
|
||||
? "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
|
||||
? "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 resolvedSlug =
|
||||
|
||||
@@ -56,7 +56,7 @@ const CheckboxContainer = memo<CheckboxProps>(
|
||||
// Default state: tertiary border, with hover and focus states via CSS
|
||||
// Hover changes border to brand primary color
|
||||
// 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
|
||||
@@ -64,7 +64,7 @@ const CheckboxContainer = memo<CheckboxProps>(
|
||||
// Inverse: transparent background, white border
|
||||
// Hover changes border to brand primary color
|
||||
// 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;
|
||||
@@ -75,8 +75,8 @@ const CheckboxContainer = memo<CheckboxProps>(
|
||||
// Checkmark color per Figma
|
||||
const checkGlyphColor = checked
|
||||
? isStandard
|
||||
? "var(--color-content-default-brand-primary, #fefcc9)" // Light yellow/cream for standard mode
|
||||
: "var(--color-content-invert-primary, #000000)" // Black for inverse mode
|
||||
? "var(--color-content-default-brand-primary)"
|
||||
: "var(--color-content-invert-primary)"
|
||||
: "transparent";
|
||||
|
||||
// Label color
|
||||
|
||||
@@ -8,7 +8,7 @@ function chipSurfaceStyle(
|
||||
palette: ChipViewProps["palette"],
|
||||
size: ChipViewProps["size"],
|
||||
): CSSProperties {
|
||||
const borderWidth = size === "s" ? "1.25px" : "2px";
|
||||
const borderWidth = size === "s" ? "1.25px" : "1.5px";
|
||||
const reset: CSSProperties = {
|
||||
appearance: "none",
|
||||
WebkitAppearance: "none",
|
||||
@@ -64,14 +64,14 @@ function chipSurfaceStyle(
|
||||
}
|
||||
if (state === "selected") {
|
||||
return paint(
|
||||
"var(--color-surface-invert-brand-primary, #fefcc9)",
|
||||
"var(--color-content-invert-primary, #000)",
|
||||
"var(--color-border-default-brand-primary, #fdfaa8)",
|
||||
"var(--color-surface-invert-brand-primary)",
|
||||
"var(--color-content-invert-primary)",
|
||||
"var(--color-border-default-brand-primary)",
|
||||
);
|
||||
}
|
||||
return paint(
|
||||
"transparent",
|
||||
"var(--color-content-default-brand-primary, #fefcc9)",
|
||||
"var(--color-content-default-brand-primary)",
|
||||
"var(--color-border-default-control)",
|
||||
);
|
||||
}
|
||||
@@ -185,7 +185,7 @@ function ChipView({
|
||||
{onCheck && (
|
||||
<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}
|
||||
disabled={!inputValue || !inputValue.trim()}
|
||||
onClick={(event) => {
|
||||
@@ -202,7 +202,7 @@ function ChipView({
|
||||
viewBox="0 0 12 12"
|
||||
fill="none"
|
||||
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
|
||||
d="M10 3L4.5 8.5L2 6"
|
||||
@@ -224,7 +224,7 @@ function ChipView({
|
||||
onChange={(e) => onInputChange?.(e.target.value)}
|
||||
onKeyDown={onInputKeyDown}
|
||||
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={{
|
||||
fontSize: isSmall
|
||||
? "var(--sizing-300)"
|
||||
@@ -240,7 +240,7 @@ function ChipView({
|
||||
{onClose && (
|
||||
<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}
|
||||
onClick={(event) => {
|
||||
event.stopPropagation();
|
||||
@@ -253,7 +253,7 @@ function ChipView({
|
||||
viewBox="0 0 12 12"
|
||||
fill="none"
|
||||
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
|
||||
d="M9 3L3 9M3 3L9 9"
|
||||
@@ -309,7 +309,7 @@ function ChipView({
|
||||
{onRemove && !isDisabled && (
|
||||
<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}`}
|
||||
onClick={(event) => {
|
||||
event.stopPropagation();
|
||||
|
||||
@@ -59,7 +59,7 @@ function MultiSelectView({
|
||||
|
||||
{!formHeader || !label ? (
|
||||
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}
|
||||
</p>
|
||||
) : null
|
||||
@@ -133,7 +133,7 @@ function MultiSelectView({
|
||||
className={
|
||||
!addButtonText
|
||||
? // 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)
|
||||
`${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
|
||||
@@ -151,8 +151,8 @@ function MultiSelectView({
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
className={`shrink-0 ${
|
||||
!addButtonText && isInverse
|
||||
? "text-[var(--color-content-invert-primary,black)]"
|
||||
: "text-[var(--color-content-default-brand-primary,#fefcc9)]"
|
||||
? "text-[var(--color-content-invert-primary)]"
|
||||
: "text-[var(--color-content-default-brand-primary)]"
|
||||
}`}
|
||||
>
|
||||
<path
|
||||
@@ -167,8 +167,8 @@ function MultiSelectView({
|
||||
<span
|
||||
className={`font-medium ${isSmall ? "text-[length:var(--sizing-300)] leading-[14px]" : "text-medium-label"} ${
|
||||
isInverse
|
||||
? "text-[color:var(--color-content-invert-primary,black)]"
|
||||
: "text-[color:var(--color-content-default-primary,white)]"
|
||||
? "text-[color:var(--color-content-invert-primary)]"
|
||||
: "text-[color:var(--color-content-default-primary)]"
|
||||
}`}
|
||||
>
|
||||
{addButtonText}
|
||||
|
||||
@@ -53,15 +53,15 @@ const RadioButtonContainer = ({
|
||||
// Focus shows shadow (double ring: 2px white inner, 4px dark outer)
|
||||
// When checked, border is brand primary (but changes to invert tertiary on focus)
|
||||
const defaultBorder = checked
|
||||
? "border-[var(--color-border-default-brand-primary,#fdfaa8)]"
|
||||
? "border-[var(--color-border-default-brand-primary)]"
|
||||
: "border-[var(--color-border-default-control)]";
|
||||
|
||||
// When focused and checked, border should be invert tertiary (#2d2d2d) per Figma
|
||||
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)]";
|
||||
|
||||
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
|
||||
@@ -71,17 +71,17 @@ const RadioButtonContainer = ({
|
||||
// Focus shows shadow (double ring: 2px dark inner, 4px white outer)
|
||||
// When checked, border is brand primary (but changes to white on focus)
|
||||
const defaultBorder = checked
|
||||
? "border-[var(--color-border-default-brand-primary,#fdfaa8)]"
|
||||
: "border-[var(--color-border-invert-primary,white)]";
|
||||
? "border-[var(--color-border-default-brand-primary)]"
|
||||
: "border-[var(--color-border-invert-primary)]";
|
||||
|
||||
// Hover border: inverse brand primary for both selected and unselected per Figma
|
||||
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
|
||||
const focusBorder = checked
|
||||
? "focus:border-[var(--color-border-invert-primary,white)]"
|
||||
: "focus:border-[var(--color-border-invert-primary,white)]";
|
||||
? "focus:border-[var(--color-border-invert-primary)]"
|
||||
: "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`;
|
||||
}
|
||||
|
||||
@@ -39,9 +39,9 @@ export function RadioButtonView({
|
||||
<div
|
||||
className={`w-[16px] h-[16px] rounded-full transition-all duration-200 ${
|
||||
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"
|
||||
? "bg-[var(--color-content-default-primary,#000000)]"
|
||||
? "bg-[var(--color-content-default-primary)]"
|
||||
: "bg-transparent"
|
||||
}`}
|
||||
/>
|
||||
|
||||
@@ -52,8 +52,8 @@ export function RadioGroupView({
|
||||
<span
|
||||
className={`text-small-paragraph ${
|
||||
mode === "inverse"
|
||||
? "text-[var(--color-content-invert-secondary,#1f1f1f)]"
|
||||
: "text-[var(--color-content-default-secondary,#b4b4b4)]"
|
||||
? "text-[var(--color-content-invert-secondary)]"
|
||||
: "text-[var(--color-content-default-secondary)]"
|
||||
}`}
|
||||
>
|
||||
{option.subtext}
|
||||
|
||||
@@ -109,7 +109,7 @@ export function SelectInputView({
|
||||
.replace(/\s+/g, " ");
|
||||
|
||||
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) {
|
||||
@@ -135,7 +135,7 @@ export function SelectInputView({
|
||||
// Text color based on filled state
|
||||
const textColorClass = isFilled
|
||||
? "text-[var(--color-content-default-primary)]"
|
||||
: "text-[var(--color-content-default-tertiary,#b4b4b4)]";
|
||||
: "text-[var(--color-content-default-tertiary)]";
|
||||
|
||||
// Chevron icon
|
||||
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>
|
||||
{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>
|
||||
)}
|
||||
@@ -167,7 +167,7 @@ export function SelectInputView({
|
||||
)}
|
||||
</div>
|
||||
{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
|
||||
</span>
|
||||
)}
|
||||
|
||||
@@ -102,7 +102,7 @@ const TextInputContainer = forwardRef<HTMLInputElement, TextInputProps>(
|
||||
if (disabled) {
|
||||
return {
|
||||
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)]",
|
||||
inputWrapper: "relative",
|
||||
focusRing: "",
|
||||
@@ -171,7 +171,7 @@ const TextInputContainer = forwardRef<HTMLInputElement, TextInputProps>(
|
||||
const inputClasses = `
|
||||
w-full transition-all duration-200 ease-in-out
|
||||
focus:outline-none focus:ring-0
|
||||
placeholder:text-[var(--color-content-default-tertiary,#b4b4b4)]
|
||||
placeholder:text-[var(--color-content-default-tertiary)]
|
||||
${sizeStyles.input}
|
||||
${stateStyles.input}
|
||||
${className}
|
||||
@@ -180,7 +180,7 @@ const TextInputContainer = forwardRef<HTMLInputElement, TextInputProps>(
|
||||
// Text color for filled text (placeholder color is handled above)
|
||||
const textColorClass = isFilled
|
||||
? "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
|
||||
const { handleChange, handleBlur } = useFormField<HTMLInputElement>(
|
||||
|
||||
@@ -20,22 +20,22 @@ function UploadView({
|
||||
|
||||
// Button styles based on active state
|
||||
const buttonBgClass = isActive
|
||||
? "bg-[var(--color-surface-invert-primary,white)]"
|
||||
: "bg-[var(--color-surface-default-secondary,#141414)]";
|
||||
? "bg-[var(--color-surface-invert-primary)]"
|
||||
: "bg-[var(--color-surface-default-secondary)]";
|
||||
|
||||
const buttonTextColor = isActive
|
||||
? "text-[color:var(--color-content-invert-primary,black)]"
|
||||
: "text-[color:var(--color-content-invert-tertiary,#2d2d2d)]";
|
||||
? "text-[color:var(--color-content-invert-primary)]"
|
||||
: "text-[color:var(--color-content-invert-tertiary)]";
|
||||
|
||||
// Description text color based on active state
|
||||
const descriptionTextColor = isActive
|
||||
? "text-[color:var(--color-content-default-primary,white)]"
|
||||
: "text-[color:var(--color-content-default-tertiary,#b4b4b4)]";
|
||||
? "text-[color:var(--color-content-default-primary)]"
|
||||
: "text-[color:var(--color-content-default-tertiary)]";
|
||||
|
||||
// Icon color based on active state
|
||||
const iconColor = isActive
|
||||
? "text-[color:var(--color-content-invert-primary,black)]"
|
||||
: "text-[color:var(--color-content-invert-tertiary,#2d2d2d)]";
|
||||
? "text-[color:var(--color-content-invert-primary)]"
|
||||
: "text-[color:var(--color-content-invert-tertiary)]";
|
||||
|
||||
return (
|
||||
<div
|
||||
@@ -55,7 +55,7 @@ function UploadView({
|
||||
|
||||
{/* Upload container — max width per create-flow spec */}
|
||||
<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"
|
||||
? "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}>
|
||||
{t("legal.termsOfService")}
|
||||
</Link>
|
||||
<Link href={t("legal.cookiesSettingsHref")} className={legalLinkClass}>
|
||||
{t("legal.cookiesSettings")}
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -63,22 +63,22 @@ const MenuItemContainer = memo<MenuItemProps>(
|
||||
const defaultModeStyles: Record<"default" | "hover" | "selected", string> =
|
||||
{
|
||||
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:
|
||||
"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:
|
||||
"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)
|
||||
const inverseModeStyles: Record<"default" | "hover" | "selected", string> =
|
||||
{
|
||||
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:
|
||||
"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:
|
||||
"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
|
||||
|
||||
@@ -33,6 +33,7 @@ const FeatureGridContainer = memo<FeatureGridProps>(
|
||||
),
|
||||
descriptionClassName: "text-[var(--color-content-invert-brand-lime)]",
|
||||
iconSrc: getAssetPath(featureIconPath("arrow-left-right")),
|
||||
href: "/how-it-works",
|
||||
},
|
||||
{
|
||||
backgroundColor: "bg-[var(--color-surface-invert-brand-rust)]",
|
||||
@@ -42,6 +43,7 @@ const FeatureGridContainer = memo<FeatureGridProps>(
|
||||
),
|
||||
descriptionClassName: "text-[var(--color-content-invert-brand-rust)]",
|
||||
iconSrc: getAssetPath(featureIconPath("door-open")),
|
||||
href: "/blog/integrating-new-members-without-dilution",
|
||||
},
|
||||
{
|
||||
backgroundColor: "bg-[var(--color-surface-invert-brand-teal)]",
|
||||
|
||||
@@ -10,6 +10,7 @@ export interface Feature {
|
||||
description: string;
|
||||
descriptionClassName: string;
|
||||
iconSrc: string;
|
||||
href?: string;
|
||||
}
|
||||
|
||||
export interface FeatureGridViewProps extends FeatureGridProps {
|
||||
|
||||
@@ -1,8 +1,35 @@
|
||||
"use client";
|
||||
|
||||
import Link from "next/link";
|
||||
import { useTranslation } from "../../../contexts/MessagesContext";
|
||||
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). */
|
||||
function FeatureGridView({
|
||||
@@ -41,34 +68,25 @@ function FeatureGridView({
|
||||
</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">
|
||||
{features.map((feature) => (
|
||||
<div
|
||||
{features.map((feature) => {
|
||||
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)]`;
|
||||
if (feature.href) {
|
||||
return (
|
||||
<Link
|
||||
key={feature.title}
|
||||
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)]`}
|
||||
href={feature.href}
|
||||
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)]`}
|
||||
>
|
||||
<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"
|
||||
/>
|
||||
<FeatureTileBody feature={feature} />
|
||||
</Link>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<div key={feature.title} className={tileClassName}>
|
||||
<FeatureTileBody feature={feature} />
|
||||
</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>
|
||||
</div>
|
||||
))}
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -75,7 +75,7 @@ function QuoteBlockView({
|
||||
role="region"
|
||||
>
|
||||
<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 />
|
||||
<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 messages from "../messages/en/index";
|
||||
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 Icon from "./components/asset/icon";
|
||||
import Button from "./components/buttons/Button";
|
||||
import HeroDecor from "./components/sections/HeroBanner/HeroDecor";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
export const metadata: Metadata = routeMetadata("/404", {
|
||||
title: messages.metadata.notFound.title,
|
||||
description: messages.metadata.notFound.description,
|
||||
robots: NO_INDEX_ROBOTS,
|
||||
};
|
||||
});
|
||||
|
||||
const NOT_FOUND_TEMPLATE_SLUGS = [
|
||||
"consensus",
|
||||
|
||||
+83
-80
@@ -202,14 +202,15 @@
|
||||
/* Grays & alpha */
|
||||
--color-gray-000: #ffffff;
|
||||
--color-gray-050: #f6f6f6;
|
||||
--color-gray-100: #e5e5e5;
|
||||
--color-gray-200: #d2d2d2;
|
||||
--color-gray-300: #b4b4b4;
|
||||
--color-gray-400: #8f8f8f;
|
||||
--color-gray-500: #666666;
|
||||
--color-gray-600: #464646;
|
||||
--color-gray-700: #2d2d2d;
|
||||
--color-gray-800: #1f1f1f;
|
||||
--color-gray-100: #e4e4e4;
|
||||
--color-gray-150: #d2d2d2;
|
||||
--color-gray-200: #c2c2c2;
|
||||
--color-gray-300: #a4a4a4;
|
||||
--color-gray-400: #8a8a8a;
|
||||
--color-gray-500: #717171;
|
||||
--color-gray-600: #5b5b5b;
|
||||
--color-gray-700: #464646;
|
||||
--color-gray-800: #303030;
|
||||
--color-gray-900: #141414;
|
||||
--color-gray-1000: #000000;
|
||||
|
||||
@@ -244,16 +245,16 @@
|
||||
/* Lavender */
|
||||
--color-lavender-lavender0: #f0ebff;
|
||||
--color-lavender-lavender50: #e8defe;
|
||||
--color-lavender-lavender100: #e0d1fd;
|
||||
--color-lavender-lavender150: #d7c3f9;
|
||||
--color-lavender-lavender200: #ceb5f6;
|
||||
--color-lavender-lavender300: #bb97ea;
|
||||
--color-lavender-lavender400: #a578d9;
|
||||
--color-lavender-lavender500: #8d5ac4;
|
||||
--color-lavender-lavender600: #743ea9;
|
||||
--color-lavender-lavender700: #5a278c;
|
||||
--color-lavender-lavender800: #41146c;
|
||||
--color-lavender-lavender900: #2b074d;
|
||||
--color-lavender-lavender100: #dccdf9;
|
||||
--color-lavender-lavender150: #d1bdf3;
|
||||
--color-lavender-lavender200: #c6adee;
|
||||
--color-lavender-lavender300: #b490e2;
|
||||
--color-lavender-lavender400: #a275d5;
|
||||
--color-lavender-lavender500: #8f5cc6;
|
||||
--color-lavender-lavender600: #7c47b2;
|
||||
--color-lavender-lavender700: #67359b;
|
||||
--color-lavender-lavender800: #50277e;
|
||||
--color-lavender-lavender900: #38185c;
|
||||
--color-lavender-lavender1000: #1a0033;
|
||||
|
||||
/* Lime */
|
||||
@@ -274,61 +275,61 @@
|
||||
/* Magenta */
|
||||
--color-magenta-magenta0: #ffebf0;
|
||||
--color-magenta-magenta50: #fedee7;
|
||||
--color-magenta-magenta100: #fdd1dd;
|
||||
--color-magenta-magenta150: #f9c3d2;
|
||||
--color-magenta-magenta200: #f6b5c7;
|
||||
--color-magenta-magenta300: #ea97ad;
|
||||
--color-magenta-magenta400: #d97892;
|
||||
--color-magenta-magenta500: #c45a76;
|
||||
--color-magenta-magenta600: #a93e5b;
|
||||
--color-magenta-magenta700: #8c2742;
|
||||
--color-magenta-magenta800: #6c142b;
|
||||
--color-magenta-magenta900: #4d071a;
|
||||
--color-magenta-magenta100: #f8ccd8;
|
||||
--color-magenta-magenta150: #f0bbca;
|
||||
--color-magenta-magenta200: #eaaabc;
|
||||
--color-magenta-magenta300: #dd8ba1;
|
||||
--color-magenta-magenta400: #ce6f89;
|
||||
--color-magenta-magenta500: #be5571;
|
||||
--color-magenta-magenta600: #aa3f5b;
|
||||
--color-magenta-magenta700: #922d47;
|
||||
--color-magenta-magenta800: #761f33;
|
||||
--color-magenta-magenta900: #571222;
|
||||
--color-magenta-magenta1000: #33000e;
|
||||
|
||||
/* Red */
|
||||
--color-red-red0: #ffebf1;
|
||||
--color-red-red50: #fec9d6;
|
||||
--color-red-red100: #fda8b7;
|
||||
--color-red-red150: #f98c98;
|
||||
--color-red-red200: #f66f78;
|
||||
--color-red-red300: #ea4845;
|
||||
--color-red-red400: #d93529;
|
||||
--color-red-red500: #c42916;
|
||||
--color-red-red600: #a9200b;
|
||||
--color-red-red700: #8c1905;
|
||||
--color-red-red800: #6c1301;
|
||||
--color-red-red900: #4d0d00;
|
||||
--color-red-red100: #ffb6c2;
|
||||
--color-red-red150: #ffa4ac;
|
||||
--color-red-red200: #ff9296;
|
||||
--color-red-red300: #ff6a62;
|
||||
--color-red-red400: #ef4c3d;
|
||||
--color-red-red500: #d33a26;
|
||||
--color-red-red600: #b62e1a;
|
||||
--color-red-red700: #972613;
|
||||
--color-red-red800: #771f0d;
|
||||
--color-red-red900: #571707;
|
||||
--color-red-red1000: #330800;
|
||||
|
||||
/* Royal Blue */
|
||||
--color-royal-blue-royal-blue0: #ebecff;
|
||||
--color-royal-blue-royal-blue50: #c9cdfe;
|
||||
--color-royal-blue-royal-blue100: #a8adfd;
|
||||
--color-royal-blue-royal-blue150: #8c91f9;
|
||||
--color-royal-blue-royal-blue200: #6f74f6;
|
||||
--color-royal-blue-royal-blue300: #4548ea;
|
||||
--color-royal-blue-royal-blue400: #2b29d9;
|
||||
--color-royal-blue-royal-blue500: #1c16c4;
|
||||
--color-royal-blue-royal-blue600: #140ba9;
|
||||
--color-royal-blue-royal-blue700: #0f058c;
|
||||
--color-royal-blue-royal-blue800: #0c016c;
|
||||
--color-royal-blue-royal-blue900: #0a004d;
|
||||
--color-royal-blue-royal-blue100: #b9bfff;
|
||||
--color-royal-blue-royal-blue150: #aab1ff;
|
||||
--color-royal-blue-royal-blue200: #99a4ff;
|
||||
--color-royal-blue-royal-blue300: #778cff;
|
||||
--color-royal-blue-royal-blue400: #5674ff;
|
||||
--color-royal-blue-royal-blue500: #3a5afe;
|
||||
--color-royal-blue-royal-blue600: #2d4adb;
|
||||
--color-royal-blue-royal-blue700: #233bb6;
|
||||
--color-royal-blue-royal-blue800: #1d2c8f;
|
||||
--color-royal-blue-royal-blue900: #171b65;
|
||||
--color-royal-blue-royal-blue1000: #080033;
|
||||
|
||||
/* Rust */
|
||||
--color-rust-rust0: #ffedeb;
|
||||
--color-rust-rust50: #fed8d4;
|
||||
--color-rust-rust100: #fdc4bd;
|
||||
--color-rust-rust150: #f9b0a6;
|
||||
--color-rust-rust200: #f69c8f;
|
||||
--color-rust-rust300: #ea7a65;
|
||||
--color-rust-rust400: #d96043;
|
||||
--color-rust-rust500: #c44e29;
|
||||
--color-rust-rust600: #a94417;
|
||||
--color-rust-rust700: #8c3d0b;
|
||||
--color-rust-rust800: #6c3604;
|
||||
--color-rust-rust900: #4d2c01;
|
||||
--color-rust-rust100: #ffc6bf;
|
||||
--color-rust-rust150: #feb4aa;
|
||||
--color-rust-rust200: #fda395;
|
||||
--color-rust-rust300: #f4836e;
|
||||
--color-rust-rust400: #e46a4c;
|
||||
--color-rust-rust500: #cd5632;
|
||||
--color-rust-rust600: #b04a1f;
|
||||
--color-rust-rust700: #904111;
|
||||
--color-rust-rust800: #703909;
|
||||
--color-rust-rust900: #512f05;
|
||||
--color-rust-rust1000: #332100;
|
||||
|
||||
/* Teal */
|
||||
@@ -392,25 +393,25 @@
|
||||
--color-border-invert-warning-primary: var(--color-yellow-yellow600);
|
||||
--color-border-invert-negative-primary: var(--color-red-red300);
|
||||
|
||||
/* Link — nearest palette step for each off-ramp hex */
|
||||
--color-link-primary: var(--color-gray-1000);
|
||||
--color-link-primary-hover: var(--color-gray-500);
|
||||
--color-link-primary-focus: var(--color-gray-500);
|
||||
--color-link-primary-active: var(--color-gray-500);
|
||||
--color-link-secondary: var(--color-gray-500);
|
||||
--color-link-secondary-hover: var(--color-gray-700);
|
||||
--color-link-secondary-focus: var(--color-gray-700);
|
||||
--color-link-secondary-active: var(--color-gray-700);
|
||||
--color-link-invert-primary: var(--color-gray-000);
|
||||
--color-link-invert-primary-hover: var(--color-gray-300);
|
||||
--color-link-invert-primary-focus: var(--color-gray-300);
|
||||
--color-link-invert-primary-active: var(--color-gray-300);
|
||||
--color-link-invert-secondary: var(--color-gray-300);
|
||||
--color-link-invert-secondary-hover: var(--color-gray-050);
|
||||
--color-link-invert-secondary-focus: var(--color-gray-050);
|
||||
--color-link-invert-secondary-active: var(--color-gray-050);
|
||||
--color-border-link-focus: var(--color-gray-1000);
|
||||
--color-border-link-invert-focus: var(--color-gray-000);
|
||||
/* Link — Navigation / Link binds content tokens */
|
||||
--color-link-primary: var(--color-content-invert-primary);
|
||||
--color-link-primary-hover: var(--color-content-invert-quaternary);
|
||||
--color-link-primary-focus: var(--color-content-invert-quaternary);
|
||||
--color-link-primary-active: var(--color-content-invert-quaternary);
|
||||
--color-link-secondary: var(--color-content-invert-quaternary);
|
||||
--color-link-secondary-hover: var(--color-content-invert-tertiary);
|
||||
--color-link-secondary-focus: var(--color-content-invert-tertiary);
|
||||
--color-link-secondary-active: var(--color-content-invert-tertiary);
|
||||
--color-link-invert-primary: var(--color-content-default-primary);
|
||||
--color-link-invert-primary-hover: var(--color-content-default-tertiary);
|
||||
--color-link-invert-primary-focus: var(--color-content-default-tertiary);
|
||||
--color-link-invert-primary-active: var(--color-content-default-tertiary);
|
||||
--color-link-invert-secondary: var(--color-content-default-tertiary);
|
||||
--color-link-invert-secondary-hover: var(--color-content-default-primary);
|
||||
--color-link-invert-secondary-focus: var(--color-content-default-primary);
|
||||
--color-link-invert-secondary-active: var(--color-content-default-primary);
|
||||
--color-border-link-focus: var(--color-border-default-primary);
|
||||
--color-border-link-invert-focus: var(--color-border-invert-primary);
|
||||
|
||||
/* Content */
|
||||
--color-content-default-brand-accent: var(--color-opacity-700);
|
||||
@@ -443,10 +444,12 @@
|
||||
--color-content-invert-primary: var(--color-gray-1000);
|
||||
--color-content-invert-secondary: var(--color-gray-800);
|
||||
--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-secondary: var(--color-yellow-yellow800);
|
||||
--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-rust: var(--color-rust-rust700);
|
||||
--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-positive-primary: var(--color-kiwi-kiwi800);
|
||||
--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 */
|
||||
--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-primary: var(--color-yellow-yellow1000);
|
||||
--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-teal: var(--color-teal-teal700);
|
||||
--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",
|
||||
"linkHref": "/learn",
|
||||
"linkHref": "/templates",
|
||||
"ariaLabel": "Feature tools and services",
|
||||
"features": {
|
||||
"decisionMaking": {
|
||||
|
||||
@@ -31,9 +31,7 @@
|
||||
"privacyPolicy": "Privacy Policy",
|
||||
"privacyPolicyHref": "/privacy",
|
||||
"termsOfService": "Terms of Service",
|
||||
"termsOfServiceHref": "/terms",
|
||||
"cookiesSettings": "Cookies Settings",
|
||||
"cookiesSettingsHref": "/cookies"
|
||||
"termsOfServiceHref": "/terms"
|
||||
},
|
||||
"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.",
|
||||
|
||||
@@ -7,8 +7,8 @@
|
||||
"templatesAlt": "CommunityRule governance templates"
|
||||
},
|
||||
"home": {
|
||||
"title": "Build structure before you need it — CommunityRule",
|
||||
"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.",
|
||||
"title": "CommunityRule | Write down how your community works",
|
||||
"description": "Write down how your community talks, who belongs, how it decides and what happens when it disagrees. Free for every community.",
|
||||
"keywords": [
|
||||
"community",
|
||||
"governance",
|
||||
@@ -47,16 +47,20 @@
|
||||
"fallbackDescription": "A blog post from our community."
|
||||
},
|
||||
"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": {
|
||||
"title": "Profile"
|
||||
"title": "Profile",
|
||||
"description": "Manage your CommunityRules, saved progress, and account."
|
||||
},
|
||||
"monitor": {
|
||||
"title": "Monitor"
|
||||
"title": "Monitor",
|
||||
"description": "Real-time monitoring of Core Web Vitals and performance metrics for Community Rule 3.0"
|
||||
},
|
||||
"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": {
|
||||
"title": "Use cases",
|
||||
|
||||
@@ -47,22 +47,32 @@ describe("FeatureGrid (behavioral tests)", () => {
|
||||
).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" />);
|
||||
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.queryByRole("link", { name: "Choose how you decide" }),
|
||||
screen.queryByRole("link", { name: /Choose how you decide/ }),
|
||||
).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" />);
|
||||
expect(
|
||||
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", () => {
|
||||
|
||||
@@ -110,7 +110,7 @@ describe("Footer (behavioral tests)", () => {
|
||||
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 />);
|
||||
expect(
|
||||
screen.getAllByRole("link", { name: "Privacy Policy" })[0],
|
||||
@@ -119,7 +119,7 @@ describe("Footer (behavioral tests)", () => {
|
||||
screen.getAllByRole("link", { name: "Terms of Service" })[0],
|
||||
).toHaveAttribute("href", "/terms");
|
||||
expect(
|
||||
screen.getAllByRole("link", { name: "Cookies Settings" })[0],
|
||||
).toHaveAttribute("href", "/cookies");
|
||||
screen.queryByRole("link", { name: "Cookies Settings" }),
|
||||
).not.toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
@@ -37,7 +37,7 @@ describe("Upload (behavioral tests)", () => {
|
||||
render(<Upload label="Upload" />);
|
||||
const button = screen.getByRole("button", { name: /upload/i });
|
||||
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} />);
|
||||
const button = screen.getByRole("button", { name: /upload/i });
|
||||
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;
|
||||
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;
|
||||
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"),
|
||||
).toBeVisible();
|
||||
|
||||
// Feature tiles are presentational — only the lockup "Explore the patterns" is a link
|
||||
await expect(
|
||||
featureSection.locator('a[href="#decision-making"]'),
|
||||
).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(
|
||||
featureSection.getByRole("link", { name: "Explore the patterns" }),
|
||||
).toHaveAttribute("href", "/learn");
|
||||
).toHaveAttribute("href", "/templates");
|
||||
});
|
||||
|
||||
test("header navigation functionality", async ({ page }) => {
|
||||
|
||||
@@ -123,7 +123,7 @@ describe("Page", () => {
|
||||
const learnMore = screen.getAllByRole("link", {
|
||||
name: "Explore the patterns",
|
||||
});
|
||||
expect(learnMore[0]).toHaveAttribute("href", "/learn");
|
||||
expect(learnMore[0]).toHaveAttribute("href", "/templates");
|
||||
});
|
||||
|
||||
test("renders ask organizer section with correct data", () => {
|
||||
|
||||
@@ -12,11 +12,18 @@ function decl(name: string): string {
|
||||
describe("Figma tokens", () => {
|
||||
it("points theme colors, radius, and focus at Figma", () => {
|
||||
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-content-default-brand-secondary")).toContain("yellow200");
|
||||
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-negative-primary")).toContain(
|
||||
"utility-negative",
|
||||
|
||||
Reference in new issue
Block a user