R0: design foundations — reference tokens, motion set, lucide primitives
- globals.css @theme merged with the measured reference system (docs/tokens.css): hover/divider/subtle-fg colors, cream + bubble tokens, squircle/toggle radii, spec-verbatim shadow set (bubble, card, dialog, dock-tile, CTA glow, launcher glow, screen-card ambient, dock capsule), marketing light palette, default 0.25s ease-app transition tokens. Legacy aliases (--color-accent, --spacing-rail/panel-*) retained so existing classes keep working - motion.css: full app-shell choreography (zoom-in/out from tile origin w/ --app-origin-scale, push/pop slides, cross-fade) + messageSlideIn, create-claw step/swatch, device-* set — keyframes verbatim from docs/motion.md - lucide-react installed (ISC). New tested primitives: Button (cream/ coral/ghost/icon/launcher variants per measured states), GradientGlyph (per-instance coral linearGradient stroke, the reference glyph technique), SegmentedTabs, Card + SectionLabel + GroupedRows, SearchPill; Avatar extended (squircle r17, rail/chat/welcome sizes, online-dot overlay) 82 unit tests; functional e2e suite green (visual baselines regenerate in R7). Co-Authored-By: Claude Fable 5 <[email protected]>
This commit is contained in:
co-authored by
Claude Fable 5
parent
447f7039d8
commit
3ec1d3b829
@@ -2,26 +2,54 @@ interface AvatarProps {
|
||||
name: string;
|
||||
/** Per-agent accent hex; defaults to the brand coral. */
|
||||
accent?: string;
|
||||
size?: "sm" | "md" | "lg";
|
||||
size?: "sm" | "md" | "lg" | "rail" | "chat" | "welcome";
|
||||
/** Circle (people) or 17px-radius squircle (claws, measured). */
|
||||
shape?: "circle" | "squircle";
|
||||
/** Green presence dot overlay (rail + chat headers). */
|
||||
online?: boolean;
|
||||
}
|
||||
|
||||
const SIZES = { sm: "size-6 text-xxs", md: "size-8 text-xs", lg: "size-16 text-xl" };
|
||||
const SIZES = {
|
||||
sm: "size-6 text-xxs",
|
||||
md: "size-8 text-xs",
|
||||
lg: "size-16 text-xl",
|
||||
rail: "size-12 text-base" /* 48px claw rail tile */,
|
||||
chat: "size-[50px] text-base" /* assistant message avatar */,
|
||||
welcome: "size-[126px] text-4xl" /* empty-state hero */,
|
||||
};
|
||||
|
||||
/** Initials avatar used until generated art assets land (excluded by spec). */
|
||||
export function Avatar({ name, accent, size = "md" }: AvatarProps) {
|
||||
export function Avatar({
|
||||
name,
|
||||
accent,
|
||||
size = "md",
|
||||
shape = "circle",
|
||||
online = false,
|
||||
}: AvatarProps) {
|
||||
const initials = name
|
||||
.split(/\s+/)
|
||||
.filter(Boolean)
|
||||
.slice(0, 2)
|
||||
.map((part) => part[0]!.toUpperCase())
|
||||
.join("");
|
||||
const radius =
|
||||
shape === "squircle" ? "rounded-radius-squircle" : "rounded-full";
|
||||
return (
|
||||
<span
|
||||
aria-hidden
|
||||
className={`inline-flex items-center justify-center rounded-full font-medium text-background ${SIZES[size]}`}
|
||||
style={{ backgroundColor: accent || "var(--color-accent)" }}
|
||||
>
|
||||
{initials}
|
||||
<span className="relative inline-flex">
|
||||
<span
|
||||
aria-hidden
|
||||
className={`inline-flex items-center justify-center font-medium text-background ${radius} ${SIZES[size]}`}
|
||||
style={{ backgroundColor: accent || "var(--color-accent)" }}
|
||||
>
|
||||
{initials}
|
||||
</span>
|
||||
{online && (
|
||||
<span
|
||||
data-online-dot
|
||||
aria-hidden
|
||||
className="absolute -right-0.5 -bottom-0.5 size-2.5 rounded-full border-2 border-background bg-green-500"
|
||||
/>
|
||||
)}
|
||||
</span>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user