@fragments-sdk/ui 0.8.0 → 0.8.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +1 -1
- package/README.md +2 -0
- package/fragments.json +1 -1
- package/package.json +21 -2
- package/src/assets/fragments-logo.tsx +37 -0
- package/src/assets/fragments_logo.svg +1 -0
- package/src/assets/fragments_logo_text.svg +1 -0
- package/src/blocks/AccountSettings.block.ts +1 -1
- package/src/blocks/ActivityFeed.block.ts +7 -7
- package/src/blocks/ChatInterface.block.ts +36 -80
- package/src/blocks/DashboardLayout.block.ts +85 -66
- package/src/blocks/DashboardPage.block.ts +297 -0
- package/src/blocks/EmptyState.block.ts +5 -3
- package/src/blocks/FeatureGrid.block.ts +1 -1
- package/src/blocks/LoginForm.block.ts +21 -26
- package/src/blocks/PricingComparison.block.ts +1 -1
- package/src/blocks/ShoppingCart.block.ts +2 -2
- package/src/components/Accordion/Accordion.fragment.tsx +2 -2
- package/src/components/Alert/Alert.fragment.tsx +2 -2
- package/src/components/AppShell/AppShell.fragment.tsx +2 -2
- package/src/components/Avatar/Avatar.fragment.tsx +2 -2
- package/src/components/Badge/Badge.fragment.tsx +2 -2
- package/src/components/Box/Box.fragment.tsx +2 -2
- package/src/components/Breadcrumbs/Breadcrumbs.fragment.tsx +2 -2
- package/src/components/Button/Button.fragment.tsx +2 -2
- package/src/components/ButtonGroup/ButtonGroup.fragment.tsx +2 -2
- package/src/components/Card/Card.fragment.tsx +2 -2
- package/src/components/Chart/Chart.fragment.tsx +2 -2
- package/src/components/Checkbox/Checkbox.fragment.tsx +2 -2
- package/src/components/Chip/Chip.fragment.tsx +2 -2
- package/src/components/CodeBlock/CodeBlock.fragment.tsx +2 -2
- package/src/components/CodeBlock/CodeBlock.module.scss +10 -52
- package/src/components/CodeBlock/index.tsx +13 -24
- package/src/components/Collapsible/Collapsible.fragment.tsx +2 -2
- package/src/components/ColorPicker/ColorPicker.fragment.tsx +2 -2
- package/src/components/Combobox/Combobox.fragment.tsx +2 -2
- package/src/components/ConversationList/ConversationList.fragment.tsx +2 -2
- package/src/components/DatePicker/DatePicker.fragment.tsx +2 -2
- package/src/components/Dialog/Dialog.fragment.tsx +2 -2
- package/src/components/EmptyState/EmptyState.fragment.tsx +2 -2
- package/src/components/Field/Field.fragment.tsx +2 -2
- package/src/components/Fieldset/Fieldset.fragment.tsx +2 -2
- package/src/components/Form/Form.fragment.tsx +2 -2
- package/src/components/Grid/Grid.fragment.tsx +2 -2
- package/src/components/Header/Header.fragment.tsx +2 -2
- package/src/components/Icon/Icon.fragment.tsx +2 -2
- package/src/components/Image/Image.fragment.tsx +2 -2
- package/src/components/Input/Input.fragment.tsx +2 -2
- package/src/components/Input/Input.test.tsx +35 -0
- package/src/components/Input/index.tsx +47 -2
- package/src/components/Link/Link.fragment.tsx +2 -2
- package/src/components/List/List.fragment.tsx +2 -2
- package/src/components/Listbox/Listbox.fragment.tsx +2 -2
- package/src/components/Loading/Loading.fragment.tsx +2 -2
- package/src/components/Markdown/Markdown.fragment.tsx +2 -2
- package/src/components/Markdown/Markdown.module.scss +5 -0
- package/src/components/Menu/Menu.fragment.tsx +2 -2
- package/src/components/Menu/Menu.module.scss +2 -0
- package/src/components/Message/Message.fragment.tsx +2 -2
- package/src/components/Popover/Popover.fragment.tsx +2 -2
- package/src/components/Progress/Progress.fragment.tsx +2 -2
- package/src/components/Prompt/Prompt.fragment.tsx +2 -2
- package/src/components/RadioGroup/RadioGroup.fragment.tsx +2 -2
- package/src/components/ScrollArea/ScrollArea.fragment.tsx +2 -2
- package/src/components/Select/Select.fragment.tsx +2 -2
- package/src/components/Separator/Separator.fragment.tsx +2 -2
- package/src/components/Sidebar/Sidebar.fragment.tsx +2 -2
- package/src/components/Sidebar/Sidebar.module.scss +1 -5
- package/src/components/Skeleton/Skeleton.fragment.tsx +2 -2
- package/src/components/Slider/Slider.fragment.tsx +2 -2
- package/src/components/Stack/Stack.fragment.tsx +2 -2
- package/src/components/Table/Table.fragment.tsx +3 -3
- package/src/components/Table/index.tsx +43 -5
- package/src/components/TableOfContents/TableOfContents.fragment.tsx +2 -2
- package/src/components/TableOfContents/TableOfContents.module.scss +0 -5
- package/src/components/TableOfContents/index.tsx +6 -1
- package/src/components/Tabs/Tabs.fragment.tsx +2 -2
- package/src/components/Text/Text.fragment.tsx +2 -2
- package/src/components/Text/Text.module.scss +6 -0
- package/src/components/Text/Text.test.tsx +5 -0
- package/src/components/Text/index.tsx +3 -0
- package/src/components/Textarea/Textarea.fragment.tsx +2 -2
- package/src/components/Theme/Theme.fragment.tsx +2 -2
- package/src/components/Theme/ThemeToggle.module.scss +1 -1
- package/src/components/Theme/index.tsx +1 -1
- package/src/components/ThinkingIndicator/ThinkingIndicator.fragment.tsx +2 -2
- package/src/components/Toast/Toast.fragment.tsx +2 -2
- package/src/components/Toggle/Toggle.fragment.tsx +2 -2
- package/src/components/ToggleGroup/ToggleGroup.fragment.tsx +37 -5
- package/src/components/Tooltip/Tooltip.fragment.tsx +2 -2
- package/src/components/VisuallyHidden/VisuallyHidden.fragment.tsx +2 -2
- package/src/index.ts +3 -0
- package/src/tokens/_derive.scss +32 -8
- package/src/tokens/_mixins.scss +9 -0
- package/src/tokens/_variables.scss +4 -4
- package/src/blocks/AIChat.block.ts +0 -266
- package/src/blocks/AppShell.block.ts +0 -175
- package/src/blocks/CTABanner.block.ts +0 -24
- package/src/blocks/CardGrid.block.ts +0 -22
- package/src/blocks/CodeExamples.block.ts +0 -66
- package/src/blocks/ConfirmDialog.block.ts +0 -19
- package/src/blocks/ConversationWithHistory.block.ts +0 -45
- package/src/blocks/DashboardNav.block.ts +0 -183
- package/src/blocks/ForgotPassword.block.ts +0 -26
- package/src/blocks/FormLayout.block.ts +0 -31
- package/src/blocks/InsetDashboardLayout.block.ts +0 -79
- package/src/blocks/MetricDashboard.block.ts +0 -38
- package/src/blocks/NewsletterSignup.block.ts +0 -26
- package/src/blocks/NotificationList.block.ts +0 -39
- package/src/blocks/NotificationPreferences.block.ts +0 -40
- package/src/blocks/OrderSummary.block.ts +0 -52
- package/src/blocks/ProfileEditForm.block.ts +0 -51
- package/src/blocks/SearchResults.block.ts +0 -39
- package/src/blocks/SettingsPage.block.ts +0 -58
- package/src/blocks/StreamingMessage.block.ts +0 -24
- package/src/blocks/TestimonialCard.block.ts +0 -27
- package/src/blocks/UserProfileCard.block.ts +0 -29
- package/src/recipes/AIChat.recipe.ts +0 -266
- package/src/recipes/AppShell.recipe.ts +0 -175
- package/src/recipes/CardGrid.recipe.ts +0 -22
- package/src/recipes/ChatInterface.recipe.ts +0 -87
- package/src/recipes/CodeExamples.recipe.ts +0 -66
- package/src/recipes/ConfirmDialog.recipe.ts +0 -19
- package/src/recipes/DashboardLayout.recipe.ts +0 -73
- package/src/recipes/DashboardNav.recipe.ts +0 -183
- package/src/recipes/FormLayout.recipe.ts +0 -31
- package/src/recipes/LoginForm.recipe.ts +0 -33
- package/src/recipes/SettingsPage.recipe.ts +0 -58
|
@@ -2,72 +2,91 @@ import { defineBlock } from '@fragments/core';
|
|
|
2
2
|
|
|
3
3
|
export default defineBlock({
|
|
4
4
|
name: 'Dashboard Layout',
|
|
5
|
-
description:
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
5
|
+
description:
|
|
6
|
+
'Full application shell with sidebar navigation, header, and metrics grid',
|
|
7
|
+
category: 'dashboard',
|
|
8
|
+
components: [
|
|
9
|
+
'AppShell',
|
|
10
|
+
'Header',
|
|
11
|
+
'Sidebar',
|
|
12
|
+
'Stack',
|
|
13
|
+
'Grid',
|
|
14
|
+
'Card',
|
|
15
|
+
'Text',
|
|
16
|
+
'Badge',
|
|
17
|
+
'Input',
|
|
18
|
+
'ThemeToggle',
|
|
19
|
+
'Avatar',
|
|
20
|
+
],
|
|
21
|
+
tags: ['dashboard', 'layout', 'sidebar', 'app-shell', 'navigation'],
|
|
9
22
|
code: `
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
<
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
<
|
|
59
|
-
</
|
|
60
|
-
<
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
</
|
|
23
|
+
const navItems = [
|
|
24
|
+
{ label: 'Dashboard', active: true },
|
|
25
|
+
{ label: 'Analytics', active: false },
|
|
26
|
+
{ label: 'Projects', active: false },
|
|
27
|
+
{ label: 'Settings', active: false },
|
|
28
|
+
];
|
|
29
|
+
|
|
30
|
+
const metrics = [
|
|
31
|
+
{ label: 'Total Users', value: '12,847', change: '+12%' },
|
|
32
|
+
{ label: 'Revenue', value: '$48,352', change: '+8%' },
|
|
33
|
+
{ label: 'Active Projects', value: '23', change: '+3' },
|
|
34
|
+
];
|
|
35
|
+
|
|
36
|
+
<AppShell layout="inset">
|
|
37
|
+
<AppShell.Header>
|
|
38
|
+
<Header>
|
|
39
|
+
<Header.Trigger />
|
|
40
|
+
<Header.Search>
|
|
41
|
+
<Input placeholder="Search..." style={{ width: '240px' }} />
|
|
42
|
+
</Header.Search>
|
|
43
|
+
<Header.Spacer />
|
|
44
|
+
<Header.Actions>
|
|
45
|
+
<ThemeToggle size="sm" />
|
|
46
|
+
<Avatar size="sm" initials="JD" />
|
|
47
|
+
</Header.Actions>
|
|
48
|
+
</Header>
|
|
49
|
+
</AppShell.Header>
|
|
50
|
+
<AppShell.Sidebar width="220px" collapsible="offcanvas">
|
|
51
|
+
<Sidebar.Header>
|
|
52
|
+
<Text weight="semibold" size="lg">Acme Inc</Text>
|
|
53
|
+
</Sidebar.Header>
|
|
54
|
+
<Sidebar.Nav>
|
|
55
|
+
<Sidebar.Section label="Main">
|
|
56
|
+
{navItems.map((item) => (
|
|
57
|
+
<Sidebar.Item key={item.label} active={item.active}>
|
|
58
|
+
{item.label}
|
|
59
|
+
</Sidebar.Item>
|
|
60
|
+
))}
|
|
61
|
+
</Sidebar.Section>
|
|
62
|
+
</Sidebar.Nav>
|
|
63
|
+
<Sidebar.Footer>
|
|
64
|
+
<Text size="sm" color="tertiary">v2.0.0</Text>
|
|
65
|
+
</Sidebar.Footer>
|
|
66
|
+
</AppShell.Sidebar>
|
|
67
|
+
<AppShell.Main padding="lg">
|
|
68
|
+
<Stack gap="lg">
|
|
69
|
+
<Stack gap="xs">
|
|
70
|
+
<Text size="xl" weight="semibold">Dashboard</Text>
|
|
71
|
+
<Text color="tertiary">Welcome back! Here's an overview of your metrics.</Text>
|
|
72
|
+
</Stack>
|
|
73
|
+
<Grid columns={{ base: 1, md: 3 }} gap="md">
|
|
74
|
+
{metrics.map((metric) => (
|
|
75
|
+
<Card key={metric.label}>
|
|
76
|
+
<Card.Body>
|
|
77
|
+
<Stack gap="sm">
|
|
78
|
+
<Text size="sm" color="tertiary">{metric.label}</Text>
|
|
79
|
+
<Stack direction="row" justify="between" align="baseline">
|
|
80
|
+
<Text size="2xl" weight="semibold">{metric.value}</Text>
|
|
81
|
+
<Badge variant="success">{metric.change}</Badge>
|
|
82
|
+
</Stack>
|
|
83
|
+
</Stack>
|
|
84
|
+
</Card.Body>
|
|
85
|
+
</Card>
|
|
86
|
+
))}
|
|
87
|
+
</Grid>
|
|
88
|
+
</Stack>
|
|
89
|
+
</AppShell.Main>
|
|
90
|
+
</AppShell>
|
|
72
91
|
`.trim(),
|
|
73
92
|
});
|
|
@@ -0,0 +1,297 @@
|
|
|
1
|
+
import { defineBlock } from '@fragments/core';
|
|
2
|
+
|
|
3
|
+
export default defineBlock({
|
|
4
|
+
name: 'Dashboard Page',
|
|
5
|
+
description:
|
|
6
|
+
'Full dashboard page with sidebar navigation, stats cards, revenue chart, transactions table, and activity feed',
|
|
7
|
+
category: 'kitchen-sink',
|
|
8
|
+
components: [
|
|
9
|
+
'AppShell',
|
|
10
|
+
'Header',
|
|
11
|
+
'Sidebar',
|
|
12
|
+
'Grid',
|
|
13
|
+
'Card',
|
|
14
|
+
'Stack',
|
|
15
|
+
'Text',
|
|
16
|
+
'Badge',
|
|
17
|
+
'Icon',
|
|
18
|
+
'Avatar',
|
|
19
|
+
'Input',
|
|
20
|
+
'Button',
|
|
21
|
+
'Separator',
|
|
22
|
+
'Table',
|
|
23
|
+
'ChartContainer',
|
|
24
|
+
'ChartTooltip',
|
|
25
|
+
'Breadcrumbs',
|
|
26
|
+
'ThemeToggle',
|
|
27
|
+
'Progress',
|
|
28
|
+
'Tabs',
|
|
29
|
+
],
|
|
30
|
+
tags: [
|
|
31
|
+
'dashboard',
|
|
32
|
+
'full-page',
|
|
33
|
+
'kitchen-sink',
|
|
34
|
+
'chart',
|
|
35
|
+
'table',
|
|
36
|
+
'sidebar',
|
|
37
|
+
'stats',
|
|
38
|
+
'metrics',
|
|
39
|
+
'analytics',
|
|
40
|
+
],
|
|
41
|
+
code: `
|
|
42
|
+
import { AreaChart, Area, XAxis } from 'recharts';
|
|
43
|
+
import {
|
|
44
|
+
TrendUp, TrendDown, Bell, SquaresFour, ChartBar,
|
|
45
|
+
FileText, GearSix, Users, UserCircle, CreditCard,
|
|
46
|
+
Bank, Lightning, Wallet, CheckCircle, Clock, XCircle,
|
|
47
|
+
ArrowClockwise, DownloadSimple,
|
|
48
|
+
} from '@phosphor-icons/react';
|
|
49
|
+
|
|
50
|
+
// ── Stats data ──────────────────────────────────────────────
|
|
51
|
+
const stats = [
|
|
52
|
+
{ label: 'Total Revenue', value: '$45,231', change: '+20.1%', up: true },
|
|
53
|
+
{ label: 'Active Users', value: '2,350', change: '+12.5%', up: true },
|
|
54
|
+
{ label: 'Sessions', value: '12,543', change: '-3.2%', up: false },
|
|
55
|
+
{ label: 'Growth Rate', value: '4.5%', change: '+0.8%', up: true },
|
|
56
|
+
];
|
|
57
|
+
|
|
58
|
+
// ── Chart data ──────────────────────────────────────────────
|
|
59
|
+
const revenueData = [
|
|
60
|
+
{ month: 'Sep', revenue: 3200 },
|
|
61
|
+
{ month: 'Oct', revenue: 4100 },
|
|
62
|
+
{ month: 'Nov', revenue: 3800 },
|
|
63
|
+
{ month: 'Dec', revenue: 5200 },
|
|
64
|
+
{ month: 'Jan', revenue: 4800 },
|
|
65
|
+
{ month: 'Feb', revenue: 6100 },
|
|
66
|
+
];
|
|
67
|
+
|
|
68
|
+
const chartConfig = {
|
|
69
|
+
revenue: { label: 'Revenue', color: 'var(--fui-color-accent)' },
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
// ── Table data ──────────────────────────────────────────────
|
|
73
|
+
const methodIcons = { card: CreditCard, bank: Bank, crypto: Lightning, wallet: Wallet };
|
|
74
|
+
const methodLabels = { card: 'Card', bank: 'Bank', crypto: 'Crypto', wallet: 'Wallet' };
|
|
75
|
+
const statusConfig = {
|
|
76
|
+
completed: { variant: 'success', icon: CheckCircle, label: 'Completed' },
|
|
77
|
+
pending: { variant: 'warning', icon: Clock, label: 'Pending' },
|
|
78
|
+
failed: { variant: 'error', icon: XCircle, label: 'Failed' },
|
|
79
|
+
refunded: { variant: 'info', icon: ArrowClockwise, label: 'Refunded' },
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
const transactions = [
|
|
83
|
+
{ id: '1', customer: 'Alice Chen', method: 'card', amount: '$1,250.00', status: 'completed', date: 'Feb 3' },
|
|
84
|
+
{ id: '2', customer: 'Bob Park', method: 'bank', amount: '$890.00', status: 'pending', date: 'Feb 2' },
|
|
85
|
+
{ id: '3', customer: 'Clara Liu', method: 'crypto', amount: '$2,100.00', status: 'completed', date: 'Feb 1' },
|
|
86
|
+
{ id: '4', customer: 'David Kim', method: 'wallet', amount: '$450.00', status: 'failed', date: 'Jan 31' },
|
|
87
|
+
{ id: '5', customer: 'Eva Santos', method: 'card', amount: '$3,200.00', status: 'completed', date: 'Jan 30' },
|
|
88
|
+
];
|
|
89
|
+
|
|
90
|
+
const columns = createColumns([
|
|
91
|
+
{
|
|
92
|
+
key: 'customer',
|
|
93
|
+
header: 'Customer',
|
|
94
|
+
cell: (row) => (
|
|
95
|
+
<Stack direction="row" gap="sm" align="center">
|
|
96
|
+
<Icon icon={UserCircle} size="sm" />
|
|
97
|
+
<Text size="sm" weight="medium">{row.customer}</Text>
|
|
98
|
+
</Stack>
|
|
99
|
+
),
|
|
100
|
+
},
|
|
101
|
+
{
|
|
102
|
+
key: 'method',
|
|
103
|
+
header: 'Method',
|
|
104
|
+
cell: (row) => (
|
|
105
|
+
<Stack direction="row" gap="xs" align="center">
|
|
106
|
+
<Icon icon={methodIcons[row.method]} size="xs" />
|
|
107
|
+
<Text size="sm" color="secondary">{methodLabels[row.method]}</Text>
|
|
108
|
+
</Stack>
|
|
109
|
+
),
|
|
110
|
+
},
|
|
111
|
+
{
|
|
112
|
+
key: 'amount',
|
|
113
|
+
header: 'Amount',
|
|
114
|
+
cell: (row) => <Text size="sm" weight="medium" font="mono">{row.amount}</Text>,
|
|
115
|
+
},
|
|
116
|
+
{
|
|
117
|
+
key: 'status',
|
|
118
|
+
header: 'Status',
|
|
119
|
+
cell: (row) => {
|
|
120
|
+
const cfg = statusConfig[row.status];
|
|
121
|
+
return (
|
|
122
|
+
<Badge variant={cfg.variant} size="sm" icon={<Icon icon={cfg.icon} size="xs" />}>
|
|
123
|
+
{cfg.label}
|
|
124
|
+
</Badge>
|
|
125
|
+
);
|
|
126
|
+
},
|
|
127
|
+
},
|
|
128
|
+
{ key: 'date', header: 'Date' },
|
|
129
|
+
]);
|
|
130
|
+
|
|
131
|
+
// ── Activity data ───────────────────────────────────────────
|
|
132
|
+
const activities = [
|
|
133
|
+
{ id: 1, user: 'Alice Chen', action: 'completed a purchase', time: '2 min ago', initials: 'AC' },
|
|
134
|
+
{ id: 2, user: 'Bob Park', action: 'submitted a support ticket', time: '15 min ago', initials: 'BP' },
|
|
135
|
+
{ id: 3, user: 'Clara Liu', action: 'upgraded to Pro plan', time: '1 hour ago', initials: 'CL' },
|
|
136
|
+
{ id: 4, user: 'David Kim', action: 'left a review', time: '3 hours ago', initials: 'DK' },
|
|
137
|
+
];
|
|
138
|
+
|
|
139
|
+
// ── Layout ──────────────────────────────────────────────────
|
|
140
|
+
|
|
141
|
+
<AppShell layout="sidebar-inset">
|
|
142
|
+
<AppShell.Header>
|
|
143
|
+
<Header>
|
|
144
|
+
<Header.Trigger />
|
|
145
|
+
<Header.Nav>
|
|
146
|
+
<Breadcrumbs>
|
|
147
|
+
<Breadcrumbs.Item>Dashboard</Breadcrumbs.Item>
|
|
148
|
+
<Breadcrumbs.Item>Overview</Breadcrumbs.Item>
|
|
149
|
+
</Breadcrumbs>
|
|
150
|
+
</Header.Nav>
|
|
151
|
+
<Header.Spacer />
|
|
152
|
+
<Header.Search>
|
|
153
|
+
<Input placeholder="Search..." size="sm" style={{ width: 200 }} />
|
|
154
|
+
</Header.Search>
|
|
155
|
+
<Header.Actions>
|
|
156
|
+
<Button variant="ghost" size="sm" icon aria-label="Notifications">
|
|
157
|
+
<Icon icon={Bell} />
|
|
158
|
+
</Button>
|
|
159
|
+
<ThemeToggle size="sm" />
|
|
160
|
+
<Avatar size="sm" initials="JD" />
|
|
161
|
+
</Header.Actions>
|
|
162
|
+
</Header>
|
|
163
|
+
</AppShell.Header>
|
|
164
|
+
|
|
165
|
+
<AppShell.Sidebar width="220px" collapsible="icon">
|
|
166
|
+
<Sidebar.Header>
|
|
167
|
+
<Text weight="semibold" size="lg">Acme Inc</Text>
|
|
168
|
+
</Sidebar.Header>
|
|
169
|
+
<Sidebar.Nav>
|
|
170
|
+
<Sidebar.Section label="Main">
|
|
171
|
+
<Sidebar.Item icon={<Icon icon={SquaresFour} />} active>Dashboard</Sidebar.Item>
|
|
172
|
+
<Sidebar.Item icon={<Icon icon={ChartBar} />}>Analytics</Sidebar.Item>
|
|
173
|
+
<Sidebar.Item icon={<Icon icon={Users} />}>Customers</Sidebar.Item>
|
|
174
|
+
<Sidebar.Item icon={<Icon icon={FileText} />}>Reports</Sidebar.Item>
|
|
175
|
+
</Sidebar.Section>
|
|
176
|
+
<Sidebar.Section label="System">
|
|
177
|
+
<Sidebar.Item icon={<Icon icon={GearSix} />}>Settings</Sidebar.Item>
|
|
178
|
+
</Sidebar.Section>
|
|
179
|
+
</Sidebar.Nav>
|
|
180
|
+
<Sidebar.Footer>
|
|
181
|
+
<Sidebar.CollapseToggle />
|
|
182
|
+
</Sidebar.Footer>
|
|
183
|
+
</AppShell.Sidebar>
|
|
184
|
+
|
|
185
|
+
<AppShell.Main padding="lg">
|
|
186
|
+
<Stack gap="lg">
|
|
187
|
+
{/* Page header */}
|
|
188
|
+
<Stack direction="row" justify="between" align="end">
|
|
189
|
+
<Stack gap="xs">
|
|
190
|
+
<Text size="xl" weight="semibold">Dashboard</Text>
|
|
191
|
+
<Text color="secondary">Welcome back! Here's an overview of your metrics.</Text>
|
|
192
|
+
</Stack>
|
|
193
|
+
<Button variant="primary" size="sm">
|
|
194
|
+
<Icon icon={DownloadSimple} size="sm" /> Export
|
|
195
|
+
</Button>
|
|
196
|
+
</Stack>
|
|
197
|
+
|
|
198
|
+
{/* Stats cards */}
|
|
199
|
+
<Grid columns={{ base: 1, sm: 2, lg: 4 }} gap="md">
|
|
200
|
+
{stats.map((stat) => (
|
|
201
|
+
<Card key={stat.label}>
|
|
202
|
+
<Card.Body>
|
|
203
|
+
<Stack gap="xs">
|
|
204
|
+
<Text size="sm" color="secondary">{stat.label}</Text>
|
|
205
|
+
<Text size="2xl" weight="semibold">{stat.value}</Text>
|
|
206
|
+
<Badge
|
|
207
|
+
variant={stat.up ? 'success' : 'warning'}
|
|
208
|
+
size="sm"
|
|
209
|
+
icon={<Icon icon={stat.up ? TrendUp : TrendDown} size="xs" />}
|
|
210
|
+
>
|
|
211
|
+
{stat.change}
|
|
212
|
+
</Badge>
|
|
213
|
+
</Stack>
|
|
214
|
+
</Card.Body>
|
|
215
|
+
</Card>
|
|
216
|
+
))}
|
|
217
|
+
</Grid>
|
|
218
|
+
|
|
219
|
+
{/* Chart + Activity feed row */}
|
|
220
|
+
<Grid columns={{ base: 1, lg: 3 }} gap="md">
|
|
221
|
+
<Grid.Item colSpan={2}>
|
|
222
|
+
<Card style={{ height: '100%' }}>
|
|
223
|
+
<Card.Header>
|
|
224
|
+
<Stack direction="row" justify="between" align="center">
|
|
225
|
+
<Card.Title>Revenue</Card.Title>
|
|
226
|
+
<Text size="sm" color="secondary">Last 6 months</Text>
|
|
227
|
+
</Stack>
|
|
228
|
+
</Card.Header>
|
|
229
|
+
<Card.Body>
|
|
230
|
+
<div style={{ height: 220 }}>
|
|
231
|
+
<ChartContainer config={chartConfig}>
|
|
232
|
+
<AreaChart data={revenueData} margin={{ top: 5, right: 5, bottom: 0, left: -20 }}>
|
|
233
|
+
<XAxis dataKey="month" tickLine={false} axisLine={false} />
|
|
234
|
+
<Area
|
|
235
|
+
type="monotone"
|
|
236
|
+
dataKey="revenue"
|
|
237
|
+
stroke="var(--fui-color-accent)"
|
|
238
|
+
fill="var(--fui-color-accent)"
|
|
239
|
+
fillOpacity={0.15}
|
|
240
|
+
strokeWidth={2}
|
|
241
|
+
/>
|
|
242
|
+
<ChartTooltip />
|
|
243
|
+
</AreaChart>
|
|
244
|
+
</ChartContainer>
|
|
245
|
+
</div>
|
|
246
|
+
</Card.Body>
|
|
247
|
+
</Card>
|
|
248
|
+
</Grid.Item>
|
|
249
|
+
|
|
250
|
+
<Card>
|
|
251
|
+
<Card.Header>
|
|
252
|
+
<Card.Title>Recent Activity</Card.Title>
|
|
253
|
+
</Card.Header>
|
|
254
|
+
<Card.Body>
|
|
255
|
+
<Stack gap="md">
|
|
256
|
+
{activities.map((a) => (
|
|
257
|
+
<Stack key={a.id} direction="row" gap="sm" align="center">
|
|
258
|
+
<Avatar size="sm" initials={a.initials} />
|
|
259
|
+
<Stack gap="xs" style={{ flex: 1 }}>
|
|
260
|
+
<Text size="sm">
|
|
261
|
+
<Text size="sm" weight="semibold">{a.user}</Text> {a.action}
|
|
262
|
+
</Text>
|
|
263
|
+
<Text size="xs" color="tertiary">{a.time}</Text>
|
|
264
|
+
</Stack>
|
|
265
|
+
</Stack>
|
|
266
|
+
))}
|
|
267
|
+
</Stack>
|
|
268
|
+
</Card.Body>
|
|
269
|
+
</Card>
|
|
270
|
+
</Grid>
|
|
271
|
+
|
|
272
|
+
{/* Transactions table */}
|
|
273
|
+
<Card>
|
|
274
|
+
<Card.Header>
|
|
275
|
+
<Stack direction="row" justify="between" align="center">
|
|
276
|
+
<Stack direction="row" gap="sm" align="center">
|
|
277
|
+
<Card.Title>Recent Transactions</Card.Title>
|
|
278
|
+
<Badge variant="outline" size="sm">5 total</Badge>
|
|
279
|
+
</Stack>
|
|
280
|
+
<Button variant="ghost" size="sm" icon aria-label="Download">
|
|
281
|
+
<Icon icon={DownloadSimple} size="sm" />
|
|
282
|
+
</Button>
|
|
283
|
+
</Stack>
|
|
284
|
+
</Card.Header>
|
|
285
|
+
<Table
|
|
286
|
+
columns={columns}
|
|
287
|
+
data={transactions}
|
|
288
|
+
size="sm"
|
|
289
|
+
caption="Recent transactions"
|
|
290
|
+
captionHidden
|
|
291
|
+
/>
|
|
292
|
+
</Card>
|
|
293
|
+
</Stack>
|
|
294
|
+
</AppShell.Main>
|
|
295
|
+
</AppShell>
|
|
296
|
+
`.trim(),
|
|
297
|
+
});
|
|
@@ -2,14 +2,16 @@ import { defineBlock } from '@fragments/core';
|
|
|
2
2
|
|
|
3
3
|
export default defineBlock({
|
|
4
4
|
name: 'Empty State',
|
|
5
|
-
description: 'Placeholder when no content
|
|
5
|
+
description: 'Placeholder with icon, message, and action when no content exists',
|
|
6
6
|
category: 'dashboard',
|
|
7
7
|
components: ['EmptyState', 'Button'],
|
|
8
|
-
tags: ['empty', 'placeholder', 'zero-state', '
|
|
8
|
+
tags: ['empty', 'placeholder', 'zero-state', 'no-data'],
|
|
9
9
|
code: `
|
|
10
10
|
<EmptyState>
|
|
11
11
|
<EmptyState.Icon>
|
|
12
|
-
<
|
|
12
|
+
<svg width="48" height="48" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5">
|
|
13
|
+
<path d="M21 8v13H3V8M1 3h22v5H1zM10 12h4" />
|
|
14
|
+
</svg>
|
|
13
15
|
</EmptyState.Icon>
|
|
14
16
|
<EmptyState.Title>No items yet</EmptyState.Title>
|
|
15
17
|
<EmptyState.Description>Get started by creating your first item.</EmptyState.Description>
|
|
@@ -19,7 +19,7 @@ const features = [
|
|
|
19
19
|
<Card key={feature.title}>
|
|
20
20
|
<Card.Body>
|
|
21
21
|
<Stack gap="md">
|
|
22
|
-
<Icon icon={feature.icon} size="lg"
|
|
22
|
+
<Icon icon={feature.icon} size="lg" variant="accent" />
|
|
23
23
|
<Stack gap="xs">
|
|
24
24
|
<Text weight="semibold">{feature.title}</Text>
|
|
25
25
|
<Text size="sm" color="tertiary">{feature.description}</Text>
|
|
@@ -2,32 +2,27 @@ import { defineBlock } from '@fragments/core';
|
|
|
2
2
|
|
|
3
3
|
export default defineBlock({
|
|
4
4
|
name: 'Login Form',
|
|
5
|
-
description: 'Email/password authentication form with
|
|
6
|
-
category: '
|
|
7
|
-
components: ['Input', 'Button', '
|
|
8
|
-
tags: ['auth', 'login', 'form'],
|
|
5
|
+
description: 'Email/password authentication form with card layout and footer links',
|
|
6
|
+
category: 'authentication',
|
|
7
|
+
components: ['Card', 'Stack', 'Input', 'Button', 'Text', 'Link'],
|
|
8
|
+
tags: ['auth', 'login', 'signin', 'form'],
|
|
9
9
|
code: `
|
|
10
|
-
<
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
<Input
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
<
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
<Alert.Body>
|
|
28
|
-
<Alert.Content>{error}</Alert.Content>
|
|
29
|
-
</Alert.Body>
|
|
30
|
-
</Alert>
|
|
31
|
-
)}
|
|
10
|
+
<Card variant="elevated">
|
|
11
|
+
<Card.Header>
|
|
12
|
+
<Card.Title>Sign In</Card.Title>
|
|
13
|
+
<Card.Description>Welcome back! Please enter your details.</Card.Description>
|
|
14
|
+
</Card.Header>
|
|
15
|
+
<Card.Body>
|
|
16
|
+
<Stack gap="md">
|
|
17
|
+
<Input label="Email" type="email" placeholder="Enter your email" />
|
|
18
|
+
<Input label="Password" type="password" placeholder="Enter your password" />
|
|
19
|
+
<Link href="#" variant="subtle"><Text size="sm">Forgot password?</Text></Link>
|
|
20
|
+
<Button variant="primary" fullWidth>Sign In</Button>
|
|
21
|
+
</Stack>
|
|
22
|
+
</Card.Body>
|
|
23
|
+
<Card.Footer>
|
|
24
|
+
<Text size="sm" color="tertiary">Don't have an account? <Link href="#">Sign up</Link></Text>
|
|
25
|
+
</Card.Footer>
|
|
26
|
+
</Card>
|
|
32
27
|
`.trim(),
|
|
33
28
|
});
|
|
@@ -13,7 +13,7 @@ const tiers = [
|
|
|
13
13
|
{ name: 'Enterprise', price: '$99', period: '/month', description: 'For large organizations', features: ['Everything in Pro', 'Custom integrations', 'Dedicated support', 'SLA guarantee'], ctaText: 'Contact Sales' },
|
|
14
14
|
];
|
|
15
15
|
|
|
16
|
-
<Grid columns={3} gap="lg">
|
|
16
|
+
<Grid columns={{ base: 1, lg: 3 }} gap="lg">
|
|
17
17
|
{tiers.map((tier) => (
|
|
18
18
|
<Card key={tier.name}>
|
|
19
19
|
<Card.Header>
|
|
@@ -21,8 +21,8 @@ const items = [
|
|
|
21
21
|
</Card.Header>
|
|
22
22
|
<Card.Body>
|
|
23
23
|
<Stack gap="md">
|
|
24
|
-
{items.map((item
|
|
25
|
-
<Stack key={
|
|
24
|
+
{items.map((item) => (
|
|
25
|
+
<Stack key={item.name} direction="row" gap="md" align="center">
|
|
26
26
|
<Image src={item.image} alt={item.name} width={64} height={64} rounded="md" />
|
|
27
27
|
<Stack gap="xs" style={{ flex: 1 }}>
|
|
28
28
|
<Text weight="semibold">{item.name}</Text>
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import {
|
|
2
|
+
import { defineFragment } from '@fragments/core';
|
|
3
3
|
import { Accordion } from '.';
|
|
4
4
|
|
|
5
|
-
export default
|
|
5
|
+
export default defineFragment({
|
|
6
6
|
component: Accordion,
|
|
7
7
|
|
|
8
8
|
meta: {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import {
|
|
2
|
+
import { defineFragment } from '@fragments/core';
|
|
3
3
|
import { AppShell } from '.';
|
|
4
4
|
import { Header } from '../Header';
|
|
5
5
|
import { Sidebar } from '../Sidebar';
|
|
@@ -38,7 +38,7 @@ function SearchIcon() {
|
|
|
38
38
|
);
|
|
39
39
|
}
|
|
40
40
|
|
|
41
|
-
export default
|
|
41
|
+
export default defineFragment({
|
|
42
42
|
component: AppShell,
|
|
43
43
|
|
|
44
44
|
meta: {
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import {
|
|
2
|
+
import { defineFragment } from '@fragments/core';
|
|
3
3
|
import { Breadcrumbs } from '.';
|
|
4
4
|
|
|
5
|
-
export default
|
|
5
|
+
export default defineFragment({
|
|
6
6
|
component: Breadcrumbs,
|
|
7
7
|
|
|
8
8
|
meta: {
|