Components
Client Only
Installation
pnpm dlx @docyrus/cli add @docyrus/ui-awesome-statsUI Primitives(3 components)
npx shadcn@latest add card popover sortableUsage
import { AwesomeStats } from '@docyrus/ui/components/awesome-stats';
const items = [
{
id: 'revenue',
eyebrow: 'Growth',
title: 'Monthly revenue',
value: 2840000,
format: {
style: 'currency',
currency: 'USD',
notation: 'compact',
maximumFractionDigits: 1
},
comparison: {
previousValue: 2470000,
period: 'last-month'
},
miniChart: {
type: 'area',
data: [1.72, 1.98, 2.14, 2.08, 2.31, 2.54, 2.84],
position: 'right'
}
},
{
id: 'returns',
title: 'Return rate',
value: 3.4,
format: { style: 'percent', maximumFractionDigits: 1 },
comparison: {
previousValue: 4.2,
period: 'last-month',
positiveDirection: 'down'
},
miniChart: {
type: 'bar',
data: [5.1, 4.7, 4.4, 4.2, 4.1, 3.8, 3.4],
position: 'bottom'
}
}
];
<AwesomeStats
items={items}
layout={{
type: 'grid',
columns: 2,
maxCardWidth: 420,
gap: '1rem'
}}
/>Layouts
| Layout | Config | Use when |
|---|---|---|
grid | columns, optional maxCardWidth, optional gap | You want a responsive dashboard-style stat grid. |
flex | cardWidth, behavior, optional gap | You need fixed-width cards that either wrap or scroll horizontally. |
tabs | optional defaultTabId | You want multiple stats to share a single card surface with animated tab switching. |
Card Features
| Prop | Purpose |
|---|---|
eyebrow | Small light label above the title. |
icon | Supports either a React node or a Docyrus icon string such as "fal chart-line". |
color | Tailwind-style color token or raw CSS color used for icon and chart accents. |
comparison | Computes the delta against a previous period and styles it as positive or negative. |
miniChart | Renders sparkline, bar, or area charts at the right edge or docked to the bottom. |
unitLabel | Appends a small unit label next to the formatted value. |
sortable | Enables drag-and-drop reordering for cards and tab items. |
onClick | Per-item click handler. Takes precedence over the top-level onItemClick. |
Awesome Card Mode
Set cardVariant="awesome" to render every stat with AwesomeCard. Use awesomeCardProps for the safe shared subset:
<AwesomeStats
items={items}
cardVariant="awesome"
sortable
awesomeCardProps={{
pattern: true,
patternStyle: 'dots',
collapsible: false
}}
layout={{
type: 'flex',
behavior: 'scroll',
cardWidth: 320
}}
/>Clickable Cards
Pass onItemClick to make every card actionable, or set a per-item onClick for individual handlers (per-item wins when both are present). Use clickTarget to choose what the user clicks:
clickTarget | Behavior |
|---|---|
card (default) | The entire card is clickable — cursor-pointer over the whole surface, keyboard-focusable (Enter / Space activate it). |
title | Only the title is clickable and underlines on hover. |
<AwesomeStats
items={items}
clickTarget="card"
onItemClick={(item) => router.push(`/metrics/${item.id}`)}
layout={{ type: 'grid', columns: 2 }}
/>
// Or per-item handlers with a title-only target:
const items = [
{
id: 'revenue',
title: 'Monthly revenue',
value: 2840000,
onClick: (item) => openDrawer(item.id)
}
];
<AwesomeStats items={items} clickTarget="title" layout={{ type: 'grid', columns: 2 }} />The card menu button and drag handle stop propagation, so they never trigger the card/title click handler.