Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,6 @@ src/styled
*.log
.DS_Store
*.tgz

# Figma fidelity audit scratch (playwright + screenshots)
.audit/
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@aymurai/ui",
"version": "0.2.1",
"version": "0.3.0",
"description": "AymurAI shared React component library, extracted from the Figma UI Library and authored with Panda CSS.",
"license": "MIT",
"type": "module",
Expand Down
33 changes: 31 additions & 2 deletions src/components/archives/ArchiveProgress.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,17 @@ function ProgressBar({

const pct = Math.min(100, Math.max(0, progress));

// Figma renders the active/completed fill with a 45° diagonal hatch texture
// (a "barber-pole" loading pattern): periwinkle stripes over the light-blue
// in-progress fill, white stripes over the navy completed fill. Applied as an
// inline backgroundImage (gradients are not tokenizable).
const stripe =
status === "completed"
? "repeating-linear-gradient(135deg, rgba(255,255,255,0.5) 0px, rgba(255,255,255,0.5) 2px, transparent 2px, transparent 7px)"
: status === "default"
? "repeating-linear-gradient(135deg, rgba(63,71,157,0.35) 0px, rgba(63,71,157,0.35) 2px, transparent 2px, transparent 7px)"
: undefined;

return (
<div
className={css({
Expand Down Expand Up @@ -116,7 +127,7 @@ function ProgressBar({
transitionDuration: "normal",
transitionTimingFunction: "default",
})}
style={{ width: `${pct}%` }}
style={{ width: `${pct}%`, backgroundImage: stripe }}
/>
</div>
);
Expand Down Expand Up @@ -161,6 +172,7 @@ function ProgressLabel({
<span
className={css({
textStyle: "label.md.default",
fontWeight: "[300]",
color: "system.error",
fontStyle: "italic",
whiteSpace: "nowrap",
Expand All @@ -171,6 +183,23 @@ function ProgressLabel({
);
}

// Figma: "Replace archive" shows a light-italic caption (text.lighter), not a %.
if (status === "replace") {
return (
<span
className={css({
textStyle: "label.md.default",
fontWeight: "[300]",
color: "text.lighter",
fontStyle: "italic",
whiteSpace: "nowrap",
})}
>
Detuviste el procesamiento de este archivo
</span>
);
}

return (
<span
className={css({
Expand Down Expand Up @@ -200,7 +229,7 @@ export function ArchiveProgress({
const nameColor =
status === "error"
? "system.error"
: status === "stopped"
: status === "stopped" || status === "replace"
? "text.onbutton-disabled"
: "text.default";

Expand Down
25 changes: 19 additions & 6 deletions src/components/archives/ArchiveView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -242,21 +242,34 @@ export function ArchiveView({
{fileName}
</p>

{/* Error message */}
{/* Error message — Figma: 14px italic, two lines, constrained to card width. */}
{isError && (
<p
className={css({
// Figma error message is 14px italic (subtitle.sm), not 12px.
textStyle: "subtitle.sm.default",
color: "system.error",
fontStyle: "italic",
textAlign: "center",
minW: "full",
w: "[157px]",
})}
>
{type === "preview-error"
? "Error de carga.\nVolvelo a intentar."
: "Error de guardado.\nVolver a cargar archivo."}
{type === "preview-error" ? (
<>
<span className={css({ display: "block" })}>Error de carga.</span>
<span className={css({ display: "block" })}>
Volvelo a intentar.
</span>
</>
) : (
<>
<span className={css({ display: "block" })}>
Error de guardado.
</span>
<span className={css({ display: "block" })}>
Volver a cargar archivo.
</span>
</>
)}
</p>
)}
</div>
Expand Down
48 changes: 40 additions & 8 deletions src/components/avatar/Avatar.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,19 @@ const meta = {
size: { control: "inline-radio", options: ["sm", "md"] },
color: {
control: "inline-radio",
options: ["primary", "secondary", "warning", "success"],
options: [
"primary",
"secondary",
"warning",
"success",
"violet",
"green",
"red",
"yellow",
"pink",
"orange",
"green-light",
],
},
},
} satisfies Meta<typeof Avatar>;
Expand All @@ -23,17 +35,37 @@ export default meta;
type Story = StoryObj<typeof meta>;

export const Default: Story = {
args: { initials: "AD", size: "sm", color: "primary" },
args: { initials: "AD", size: "sm", color: "violet" },
};

/** Figma bg/category/* speaker-palette — one avatar per colour, both sizes. */
export const Matrix: Story = {
render: () => (
<div style={{ display: "flex", gap: "12px", alignItems: "center" }}>
<Avatar initials="AD" color="primary" />
<Avatar initials="AB" color="secondary" />
<Avatar initials="MC" color="warning" />
<Avatar initials="JL" color="success" />
<Avatar initials="AD" color="primary" size="md" />
<div style={{ display: "flex", flexDirection: "column", gap: "16px" }}>
<div style={{ display: "flex", gap: "12px", alignItems: "center" }}>
<Avatar initials="AB" color="violet" size="sm" />
<Avatar initials="CD" color="green" size="sm" />
<Avatar initials="EF" color="red" size="sm" />
<Avatar initials="GH" color="yellow" size="sm" />
<Avatar initials="IJ" color="pink" size="sm" />
<Avatar initials="KL" color="orange" size="sm" />
<Avatar initials="MN" color="green-light" size="sm" />
</div>
<div style={{ display: "flex", gap: "12px", alignItems: "center" }}>
<Avatar initials="AB" color="violet" size="md" />
<Avatar initials="CD" color="green" size="md" />
<Avatar initials="EF" color="red" size="md" />
<Avatar initials="GH" color="yellow" size="md" />
<Avatar initials="IJ" color="pink" size="md" />
<Avatar initials="KL" color="orange" size="md" />
<Avatar initials="MN" color="green-light" size="md" />
</div>
<div style={{ display: "flex", gap: "12px", alignItems: "center" }}>
<Avatar initials="AD" color="primary" size="sm" />
<Avatar initials="AB" color="secondary" size="sm" />
<Avatar initials="MC" color="warning" size="sm" />
<Avatar initials="JL" color="success" size="sm" />
</div>
</div>
),
};
13 changes: 9 additions & 4 deletions src/components/big-icon-button/BigIconButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -60,29 +60,34 @@ const bigIconButton = cva({
bg: "action.pressed",
color: "text.onbutton-alternative",
},
"&:disabled": { bg: "action.disabled", color: "text.onbutton-default" },
// TOKEN GAP: Figma action-disabled for this component = #E2EBF3 (blue-tinted),
// not the warm-grey #E0DDE2 stored in action.disabled. Escape until token updated.
"&:disabled": { bg: "[#E2EBF3]", color: "text.onbutton-default" },
},
secondary: {
bg: "bg.secondary",
color: "text.onbutton-default",
borderWidth: "[2px]",
borderStyle: "solid",
borderColor: "action.alt-default",
"&:hover:enabled": { borderColor: "action.hover" },
// TOKEN GAP: Figma secondary-hover border = #728197 (muted blue-grey);
// action.hover = #110041 is wrong here. Escape until token promoted.
"&:hover:enabled": { borderColor: "[#728197]" },
"&:active:enabled": {
bg: "action.pressed",
color: "text.onbutton-alternative",
borderColor: "action.pressed",
},
// TOKEN GAP: Figma disabled border uses same #E2EBF3 as primary disabled bg.
"&:disabled": {
borderColor: "action.disabled",
borderColor: "[#E2EBF3]",
color: "text.onbutton-disabled",
},
},
tertiary: {
bg: "[transparent]",
color: "text.onbutton-default",
"&:hover:enabled": { bg: "bg.primary-alternative" },
// Figma tertiary hover: no bg fill — stays transparent.
"&:active:enabled": {
bg: "action.pressed",
color: "text.onbutton-alternative",
Expand Down
13 changes: 4 additions & 9 deletions src/components/button-link/ButtonLink.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -45,24 +45,24 @@ export const SizeMAlternative: Story = {
};

// Figma: Size=S, Type=Default (21:5355)
// Note: Size=S always renders a built-in CaretDown — do not pass iconRight.
export const SizeSDefault: Story = {
args: {
size: "S",
type: "Default",
children: "call to action",
iconLeft: <ArrowLeft size={16} />,
iconRight: <CaretDown size={16} />,
},
};

// Figma: Size=S, Type=Alternative (21:5359)
// Note: Size=S always renders a built-in CaretDown — do not pass iconRight.
export const SizeSAlternative: Story = {
args: {
size: "S",
type: "Alternative",
children: "call to action",
iconLeft: <ArrowLeft size={16} />,
iconRight: <CaretDown size={16} />,
},
parameters: { backgrounds: { default: "dark" } },
};
Expand Down Expand Up @@ -99,12 +99,8 @@ export const Matrix: Story = {
Size M / Alternative
</ButtonLink>
</div>
<ButtonLink
size="S"
type="Default"
iconLeft={<ArrowLeft size={16} />}
iconRight={<CaretDown size={16} />}
>
{/* Size=S: built-in CaretDown replaces iconRight */}
<ButtonLink size="S" type="Default" iconLeft={<ArrowLeft size={16} />}>
Size S / Default
</ButtonLink>
<div
Expand All @@ -114,7 +110,6 @@ export const Matrix: Story = {
size="S"
type="Alternative"
iconLeft={<ArrowLeft size={16} />}
iconRight={<CaretDown size={16} />}
>
Size S / Alternative
</ButtonLink>
Expand Down
8 changes: 5 additions & 3 deletions src/components/button-link/ButtonLink.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -96,12 +96,14 @@ export function ButtonLink({
>
{iconLeft && <span aria-hidden="true">{iconLeft}</span>}
{children}
{iconRight && <span aria-hidden="true">{iconRight}</span>}
{/* Figma Size=S carries a trailing caret-down (angle-down-small). */}
{size === "S" && (
{/* Figma Size=S always carries a trailing caret-down (angle-down-small)
as the exclusive right slot. For Size=M the caller controls iconRight. */}
{size === "S" ? (
<span aria-hidden="true">
<CaretDown size={16} />
</span>
) : (
iconRight && <span aria-hidden="true">{iconRight}</span>
)}
</a>
);
Expand Down
Loading
Loading