feat(web): shared design primitives (IconChip, SectionHeader, EmptyState)
This commit is contained in:
parent
66d82b8b68
commit
e0c07be232
4 changed files with 130 additions and 0 deletions
48
src/ds/EmptyState.tsx
Normal file
48
src/ds/EmptyState.tsx
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
import { Icon, type IconName } from "./icons";
|
||||
|
||||
/** A designed empty / low-data state: a soft icon medallion, a title, and a
|
||||
* one-line hint. Replaces the bare "Гүйлгээ алга" text so a quiet screen still
|
||||
* feels intentional. */
|
||||
export function EmptyState({
|
||||
icon,
|
||||
title,
|
||||
hint,
|
||||
compact = false,
|
||||
}: {
|
||||
icon: IconName;
|
||||
title: string;
|
||||
hint?: string;
|
||||
compact?: boolean;
|
||||
}) {
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
alignItems: "center",
|
||||
textAlign: "center",
|
||||
gap: 10,
|
||||
padding: compact ? "20px 16px" : "36px 20px",
|
||||
}}
|
||||
>
|
||||
<span
|
||||
aria-hidden
|
||||
style={{
|
||||
width: 52,
|
||||
height: 52,
|
||||
borderRadius: 18,
|
||||
display: "grid",
|
||||
placeItems: "center",
|
||||
color: "var(--seed-color-fg-neutral-muted, #8b8b8b)",
|
||||
background: "var(--seed-color-bg-neutral-subtle, #eef0f2)",
|
||||
}}
|
||||
>
|
||||
<Icon name={icon} size={26} />
|
||||
</span>
|
||||
<span style={{ fontSize: 15, fontWeight: 700, color: "var(--seed-color-fg-neutral)" }}>{title}</span>
|
||||
{hint ? (
|
||||
<span style={{ fontSize: 13, maxWidth: 280, color: "var(--seed-color-fg-neutral-muted, #8b8b8b)" }}>{hint}</span>
|
||||
) : null}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
35
src/ds/IconChip.tsx
Normal file
35
src/ds/IconChip.tsx
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
import { Icon, type IconName } from "./icons";
|
||||
|
||||
/** The rounded, tinted icon square used on every list row (transactions,
|
||||
* accounts, assets, planner categories, profile menu). One source of truth for
|
||||
* the chip so all rows share the exact same shape/size. */
|
||||
export function IconChip({
|
||||
icon,
|
||||
tint,
|
||||
fg,
|
||||
size = 40,
|
||||
}: {
|
||||
icon: IconName;
|
||||
tint: string;
|
||||
fg: string;
|
||||
size?: number;
|
||||
}) {
|
||||
const radius = Math.round(size * 0.32);
|
||||
return (
|
||||
<span
|
||||
aria-hidden
|
||||
style={{
|
||||
width: size,
|
||||
height: size,
|
||||
flexShrink: 0,
|
||||
borderRadius: radius,
|
||||
display: "grid",
|
||||
placeItems: "center",
|
||||
color: fg,
|
||||
background: tint,
|
||||
}}
|
||||
>
|
||||
<Icon name={icon} size={Math.round(size * 0.5)} />
|
||||
</span>
|
||||
);
|
||||
}
|
||||
44
src/ds/SectionHeader.tsx
Normal file
44
src/ds/SectionHeader.tsx
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
import type { ReactNode } from "react";
|
||||
import { Icon } from "./icons";
|
||||
|
||||
/** A section title with an optional trailing action (e.g. a `+` add button).
|
||||
* Used to head every list block so spacing + type are consistent. */
|
||||
export function SectionHeader({
|
||||
title,
|
||||
action,
|
||||
onAction,
|
||||
actionLabel,
|
||||
}: {
|
||||
title: string;
|
||||
action?: ReactNode;
|
||||
onAction?: () => void;
|
||||
actionLabel?: string;
|
||||
}) {
|
||||
return (
|
||||
<div style={{ display: "flex", alignItems: "center", justifyContent: "space-between", gap: 12 }}>
|
||||
<h2 style={{ margin: 0, fontSize: 17, fontWeight: 700, color: "var(--seed-color-fg-neutral)" }}>{title}</h2>
|
||||
{onAction ? (
|
||||
<button
|
||||
type="button"
|
||||
onClick={onAction}
|
||||
aria-label={actionLabel}
|
||||
style={{
|
||||
all: "unset",
|
||||
cursor: "pointer",
|
||||
width: 32,
|
||||
height: 32,
|
||||
borderRadius: 10,
|
||||
display: "grid",
|
||||
placeItems: "center",
|
||||
color: "var(--seed-color-fg-neutral)",
|
||||
background: "var(--seed-color-bg-neutral-subtle, #eef0f2)",
|
||||
}}
|
||||
>
|
||||
<Icon name="plus" size={18} />
|
||||
</button>
|
||||
) : (
|
||||
action ?? null
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
@ -17,3 +17,6 @@ export { Card } from "./Card";
|
|||
export type { CardProps } from "./Card";
|
||||
export * from "./categoryStyle";
|
||||
export * from "./icons";
|
||||
export * from "./IconChip";
|
||||
export * from "./SectionHeader";
|
||||
export * from "./EmptyState";
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue