113 lines
3.8 KiB
TypeScript
113 lines
3.8 KiB
TypeScript
import { getDirection, type Locale } from "../LanguageSwitcher";
|
|||
|
|
|
||
|
|
/* Exported from Figma assets/eu-en (224:11275) and assets/eu-en - darkBg
|
||
|
|
(238:2325). The source files are downscaled copies of the Figma exports. */
|
||
|
|
const EMBLEM_SRC = {
|
||
|
|
light: "/assets/eu-flag.png",
|
||
|
|
dark: "/assets/eu-flag-dark.png",
|
||
|
|
} as const;
|
||
|
|
|
||
|
|
const EMBLEM_INTRINSIC_WIDTH = 192;
|
||
|
|
const EMBLEM_INTRINSIC_HEIGHT = 128;
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Drawn emblem box per size. "md" is the 48x32 the navigation and the drawer
|
||
|
|
* use; "sm" is the 36x24 the home hero draws above the wordmark (478:15951).
|
||
|
|
* Only the emblem changes - see the note on the statement below.
|
||
|
|
*/
|
||
|
|
const EMBLEM_BOX = {
|
||
|
|
md: "h-[32px] w-[48px]",
|
||
|
|
sm: "h-[24px] w-[36px]",
|
||
|
|
} as const;
|
||
|
|
|
||
|
|
export type EuBadgeSize = keyof typeof EMBLEM_BOX;
|
||
|
|
|
||
|
|
/** Which tier-2 surface the badge is sitting on. `:root` is the dark one. */
|
||
|
|
export type EuBadgeSurface = keyof typeof EMBLEM_SRC;
|
||
|
|
|
||
|
|
export interface EuBadgeProps {
|
||
|
|
/** "Funded by the European Union", already in the reader's language. */
|
||
|
|
statement: string;
|
||
|
|
/** Alt text for the emblem. Empty when the statement is rendered beside it. */
|
||
|
|
emblemAlt?: string;
|
||
|
|
/** Language of `statement` - drives the font switch and the text direction. */
|
||
|
|
locale: Locale;
|
||
|
|
surface: EuBadgeSurface;
|
||
|
|
/** "md" (48x32) by default; "sm" (36x24) for the hero lockup. */
|
||
|
|
size?: EuBadgeSize;
|
||
|
|
className?: string;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* The mandatory EU visibility lockup: emblem + funding statement.
|
||
|
|
*
|
||
|
|
* The lockup itself is pinned to `dir="ltr"` so the emblem always leads, which
|
||
|
|
* is how the Arabic navigation frame (334:526) draws it; only the statement
|
||
|
|
* carries the reader's own direction. A mirroring ancestor still moves the
|
||
|
|
* whole badge from the inline start to the inline end in Arabic.
|
||
|
|
*
|
||
|
|
* DEVIATION FROM FIGMA (colour): the design sets the statement in EU reflex
|
||
|
|
* blue (hex 0f2a8e). A raw hex is not permitted in a component here, and there
|
||
|
|
* is no semantic token for a third-party brand colour, so the statement uses
|
||
|
|
* --text-primary. It stays legible on both surfaces and the emblem still
|
||
|
|
* carries the EU colours. Add a tier-2 token if the blue has to come back.
|
||
|
|
*
|
||
|
|
* DEVIATION FROM FIGMA (type): the hero badge sets the statement at 10px. The
|
||
|
|
* type scale has no 10px role and a raw font-size is not permitted, so both
|
||
|
|
* sizes render the statement at `label-md` (12px). The lockup is then a little
|
||
|
|
* taller than the 24px emblem at "sm"; it is also more legible, which EU
|
||
|
|
* visibility guidance asks for. Add a tier-2 role if 10px is required.
|
||
|
|
*/
|
||
|
|
export function EuBadge({
|
||
|
|
statement,
|
||
|
|
emblemAlt = "",
|
||
|
|
locale,
|
||
|
|
surface,
|
||
|
|
size = "md",
|
||
|
|
className,
|
||
|
|
}: EuBadgeProps) {
|
||
|
|
return (
|
||
|
|
<div
|
||
|
|
dir="ltr"
|
||
|
|
className={["flex shrink-0 items-center gap-2xs", className]
|
||
|
|
.filter(Boolean)
|
||
|
|
.join(" ")}
|
||
|
|
>
|
||
|
|
<img
|
||
|
|
src={EMBLEM_SRC[surface]}
|
||
|
|
alt={emblemAlt}
|
||
|
|
width={EMBLEM_INTRINSIC_WIDTH}
|
||
|
|
height={EMBLEM_INTRINSIC_HEIGHT}
|
||
|
|
loading="eager"
|
||
|
|
decoding="async"
|
||
|
|
draggable={false}
|
||
|
|
className={`block shrink-0 ${EMBLEM_BOX[size]}`}
|
||
|
|
/>
|
||
|
|
<span
|
||
|
|
lang={locale}
|
||
|
|
dir={getDirection(locale)}
|
||
|
|
className="label-md block w-[96px] text-[var(--text-primary)]"
|
||
|
|
>
|
||
|
|
{statement}
|
||
|
|
</span>
|
||
|
|
</div>
|
||
|
|
);
|
||
|
|
}
|
||
|
|
|
||
|
|
export default EuBadge;
|
||
|
|
|
||
|
|
/* ---------------------------------------------------------------------------
|
||
|
|
USAGE
|
||
|
|
---------------------------------------------------------------------------
|
||
|
|
// In the mobile drawer, on the dark surface:
|
||
|
|
<EuBadge statement={t("site.euStatement")} locale="en" surface="dark" />
|
||
|
|
|
||
|
|
// Above the home hero wordmark, at the smaller emblem size:
|
||
|
|
<EuBadge
|
||
|
|
size="sm"
|
||
|
|
statement={t("site.euStatement")}
|
||
|
|
locale={locale}
|
||
|
|
surface="dark"
|
||
|
|
/>
|
||
|
|
------------------------------------------------------------------------ */
|