@fragments-sdk/ui 0.8.1 → 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/Input/Input.test.tsx +35 -0
- package/src/components/Input/index.tsx +47 -2
- package/src/components/Menu/Menu.module.scss +2 -0
- package/src/components/Table/Table.fragment.tsx +1 -1
- package/src/components/ToggleGroup/ToggleGroup.fragment.tsx +32 -0
- package/src/index.ts +3 -0
- package/src/tokens/_derive.scss +32 -8
- 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
|
@@ -1,175 +0,0 @@
|
|
|
1
|
-
import { defineRecipe } from '@fragments/core';
|
|
2
|
-
|
|
3
|
-
export default defineRecipe({
|
|
4
|
-
name: 'App Shell',
|
|
5
|
-
description: 'Full application layout with sidebar, header, and main content. Supports two layout modes: stacked (header full-width) and sidebar-inset (sidebar full-height).',
|
|
6
|
-
category: 'layout',
|
|
7
|
-
components: ['AppShell', 'Header', 'Sidebar', 'Theme'],
|
|
8
|
-
tags: ['layout', 'app-shell', 'sidebar', 'navigation', 'dashboard'],
|
|
9
|
-
code: `
|
|
10
|
-
// App Shell - Stacked Layout (header spans full width)
|
|
11
|
-
// Best for apps where the brand should be prominent in the header
|
|
12
|
-
|
|
13
|
-
import { AppShell, Header, Input, Sidebar, ThemeToggle } from '@fragments-sdk/ui';
|
|
14
|
-
|
|
15
|
-
function StackedLayout({ children }) {
|
|
16
|
-
return (
|
|
17
|
-
<AppShell layout="stacked">
|
|
18
|
-
<AppShell.Header>
|
|
19
|
-
<Header>
|
|
20
|
-
<Header.SkipLink />
|
|
21
|
-
<Header.Trigger />
|
|
22
|
-
<Header.Brand href="/">MyApp</Header.Brand>
|
|
23
|
-
<Header.Nav>
|
|
24
|
-
<Header.NavItem href="/" active>Dashboard</Header.NavItem>
|
|
25
|
-
<Header.NavItem href="/settings">Settings</Header.NavItem>
|
|
26
|
-
</Header.Nav>
|
|
27
|
-
<Header.Spacer />
|
|
28
|
-
<Header.Actions>
|
|
29
|
-
<ThemeToggle />
|
|
30
|
-
</Header.Actions>
|
|
31
|
-
</Header>
|
|
32
|
-
</AppShell.Header>
|
|
33
|
-
|
|
34
|
-
<AppShell.Sidebar width="240px" collapsible="offcanvas">
|
|
35
|
-
<Sidebar.Nav>
|
|
36
|
-
<Sidebar.Section label="Menu">
|
|
37
|
-
<Sidebar.Item icon={<HomeIcon />} href="/" active>
|
|
38
|
-
Home
|
|
39
|
-
</Sidebar.Item>
|
|
40
|
-
<Sidebar.Item icon={<ChartIcon />} href="/analytics">
|
|
41
|
-
Analytics
|
|
42
|
-
</Sidebar.Item>
|
|
43
|
-
<Sidebar.Item icon={<GearIcon />} href="/settings">
|
|
44
|
-
Settings
|
|
45
|
-
</Sidebar.Item>
|
|
46
|
-
</Sidebar.Section>
|
|
47
|
-
</Sidebar.Nav>
|
|
48
|
-
</AppShell.Sidebar>
|
|
49
|
-
|
|
50
|
-
<AppShell.Main padding="lg">
|
|
51
|
-
{children}
|
|
52
|
-
</AppShell.Main>
|
|
53
|
-
</AppShell>
|
|
54
|
-
);
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
// App Shell - Sidebar Inset Layout (sidebar is full height)
|
|
58
|
-
// Best for documentation sites or when sidebar branding is preferred
|
|
59
|
-
|
|
60
|
-
function SidebarInsetLayout({ children }) {
|
|
61
|
-
return (
|
|
62
|
-
<AppShell layout="sidebar-inset">
|
|
63
|
-
<AppShell.Header>
|
|
64
|
-
<Header>
|
|
65
|
-
<Header.SkipLink />
|
|
66
|
-
<Header.Trigger />
|
|
67
|
-
<Header.Search>
|
|
68
|
-
<Input placeholder="Search..." />
|
|
69
|
-
</Header.Search>
|
|
70
|
-
<Header.Spacer />
|
|
71
|
-
<Header.Actions>
|
|
72
|
-
<ThemeToggle />
|
|
73
|
-
</Header.Actions>
|
|
74
|
-
</Header>
|
|
75
|
-
</AppShell.Header>
|
|
76
|
-
|
|
77
|
-
<AppShell.Sidebar width="260px" collapsible="offcanvas">
|
|
78
|
-
<Sidebar.Header>
|
|
79
|
-
<a href="/">MyApp</a>
|
|
80
|
-
</Sidebar.Header>
|
|
81
|
-
<Sidebar.Nav>
|
|
82
|
-
<Sidebar.Section label="Getting Started">
|
|
83
|
-
<Sidebar.Item href="/docs" active>Introduction</Sidebar.Item>
|
|
84
|
-
<Sidebar.Item href="/docs/install">Installation</Sidebar.Item>
|
|
85
|
-
</Sidebar.Section>
|
|
86
|
-
<Sidebar.Section label="Components">
|
|
87
|
-
<Sidebar.Item href="/components">Overview</Sidebar.Item>
|
|
88
|
-
<Sidebar.Item href="/components/button">Button</Sidebar.Item>
|
|
89
|
-
</Sidebar.Section>
|
|
90
|
-
</Sidebar.Nav>
|
|
91
|
-
<Sidebar.Footer>v1.0.0</Sidebar.Footer>
|
|
92
|
-
</AppShell.Sidebar>
|
|
93
|
-
|
|
94
|
-
<AppShell.Main padding="lg">
|
|
95
|
-
{children}
|
|
96
|
-
</AppShell.Main>
|
|
97
|
-
</AppShell>
|
|
98
|
-
);
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
// App Shell with Collapsible Icon Sidebar
|
|
102
|
-
// Sidebar collapses to icons only - great for dashboards
|
|
103
|
-
|
|
104
|
-
function CollapsibleLayout({ children }) {
|
|
105
|
-
return (
|
|
106
|
-
<AppShell layout="sidebar-inset">
|
|
107
|
-
<AppShell.Header>
|
|
108
|
-
<Header>
|
|
109
|
-
<Header.Trigger />
|
|
110
|
-
<Header.Spacer />
|
|
111
|
-
<Header.Actions>
|
|
112
|
-
<ThemeToggle />
|
|
113
|
-
</Header.Actions>
|
|
114
|
-
</Header>
|
|
115
|
-
</AppShell.Header>
|
|
116
|
-
|
|
117
|
-
<AppShell.Sidebar collapsible="icon" width="240px" collapsedWidth="64px">
|
|
118
|
-
<Sidebar.Header collapsedContent={<Logo />}>
|
|
119
|
-
<Logo /> <span>MyApp</span>
|
|
120
|
-
</Sidebar.Header>
|
|
121
|
-
<Sidebar.Nav>
|
|
122
|
-
<Sidebar.Section>
|
|
123
|
-
<Sidebar.Item icon={<HomeIcon />} active>Dashboard</Sidebar.Item>
|
|
124
|
-
<Sidebar.Item icon={<ChartIcon />}>Analytics</Sidebar.Item>
|
|
125
|
-
<Sidebar.Item icon={<GearIcon />}>Settings</Sidebar.Item>
|
|
126
|
-
</Sidebar.Section>
|
|
127
|
-
</Sidebar.Nav>
|
|
128
|
-
<Sidebar.Footer>
|
|
129
|
-
<Sidebar.CollapseToggle />
|
|
130
|
-
</Sidebar.Footer>
|
|
131
|
-
</AppShell.Sidebar>
|
|
132
|
-
|
|
133
|
-
<AppShell.Main padding="lg">
|
|
134
|
-
{children}
|
|
135
|
-
</AppShell.Main>
|
|
136
|
-
</AppShell>
|
|
137
|
-
);
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
// App Shell with Aside Panel
|
|
141
|
-
// Optional right panel for additional context
|
|
142
|
-
|
|
143
|
-
function LayoutWithAside({ children, aside }) {
|
|
144
|
-
return (
|
|
145
|
-
<AppShell layout="stacked">
|
|
146
|
-
<AppShell.Header>
|
|
147
|
-
<Header>
|
|
148
|
-
<Header.Brand>MyApp</Header.Brand>
|
|
149
|
-
<Header.Spacer />
|
|
150
|
-
<Header.Actions>
|
|
151
|
-
<ThemeToggle />
|
|
152
|
-
</Header.Actions>
|
|
153
|
-
</Header>
|
|
154
|
-
</AppShell.Header>
|
|
155
|
-
|
|
156
|
-
<AppShell.Sidebar width="200px" collapsible="offcanvas">
|
|
157
|
-
<Sidebar.Nav>
|
|
158
|
-
<Sidebar.Section>
|
|
159
|
-
<Sidebar.Item icon={<HomeIcon />} active>Home</Sidebar.Item>
|
|
160
|
-
</Sidebar.Section>
|
|
161
|
-
</Sidebar.Nav>
|
|
162
|
-
</AppShell.Sidebar>
|
|
163
|
-
|
|
164
|
-
<AppShell.Main padding="lg">
|
|
165
|
-
{children}
|
|
166
|
-
</AppShell.Main>
|
|
167
|
-
|
|
168
|
-
<AppShell.Aside width="280px">
|
|
169
|
-
{aside}
|
|
170
|
-
</AppShell.Aside>
|
|
171
|
-
</AppShell>
|
|
172
|
-
);
|
|
173
|
-
}
|
|
174
|
-
`.trim(),
|
|
175
|
-
});
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
import { defineRecipe } from '@fragments/core';
|
|
2
|
-
|
|
3
|
-
export default defineRecipe({
|
|
4
|
-
name: 'Card Grid',
|
|
5
|
-
description: 'Responsive grid of cards that reflows based on available space',
|
|
6
|
-
category: 'layout',
|
|
7
|
-
components: ['Grid', 'Card'],
|
|
8
|
-
tags: ['grid', 'cards', 'responsive', 'dashboard', 'tiles'],
|
|
9
|
-
code: `
|
|
10
|
-
<Grid columns="auto" minChildWidth="16rem" gap="md">
|
|
11
|
-
{items.map(item => (
|
|
12
|
-
<Card key={item.id}>
|
|
13
|
-
<Card.Header>
|
|
14
|
-
<Card.Title>{item.title}</Card.Title>
|
|
15
|
-
<Card.Description>{item.description}</Card.Description>
|
|
16
|
-
</Card.Header>
|
|
17
|
-
<Card.Body>{item.content}</Card.Body>
|
|
18
|
-
</Card>
|
|
19
|
-
))}
|
|
20
|
-
</Grid>
|
|
21
|
-
`.trim(),
|
|
22
|
-
});
|
|
@@ -1,87 +0,0 @@
|
|
|
1
|
-
import { defineRecipe } from '@fragments/core';
|
|
2
|
-
|
|
3
|
-
export default defineRecipe({
|
|
4
|
-
name: 'Chat Interface',
|
|
5
|
-
description: 'AI chat interface with message history and prompt input',
|
|
6
|
-
category: 'layout',
|
|
7
|
-
components: ['Prompt', 'Card', 'Avatar', 'Stack'],
|
|
8
|
-
tags: ['chat', 'ai', 'assistant', 'conversation'],
|
|
9
|
-
code: `
|
|
10
|
-
import { useState } from 'react';
|
|
11
|
-
import { Prompt, Card, Avatar, Stack } from '@fragments-sdk/ui';
|
|
12
|
-
|
|
13
|
-
interface Message {
|
|
14
|
-
id: string;
|
|
15
|
-
role: 'user' | 'assistant';
|
|
16
|
-
content: string;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
function ChatInterface() {
|
|
20
|
-
const [messages, setMessages] = useState<Message[]>([]);
|
|
21
|
-
const [isLoading, setIsLoading] = useState(false);
|
|
22
|
-
|
|
23
|
-
const handleSubmit = async (value: string) => {
|
|
24
|
-
// Add user message
|
|
25
|
-
const userMessage: Message = {
|
|
26
|
-
id: crypto.randomUUID(),
|
|
27
|
-
role: 'user',
|
|
28
|
-
content: value,
|
|
29
|
-
};
|
|
30
|
-
setMessages((prev) => [...prev, userMessage]);
|
|
31
|
-
setIsLoading(true);
|
|
32
|
-
|
|
33
|
-
try {
|
|
34
|
-
// Simulate API call
|
|
35
|
-
await new Promise((resolve) => setTimeout(resolve, 1000));
|
|
36
|
-
|
|
37
|
-
// Add assistant response
|
|
38
|
-
const assistantMessage: Message = {
|
|
39
|
-
id: crypto.randomUUID(),
|
|
40
|
-
role: 'assistant',
|
|
41
|
-
content: 'This is a simulated response. Replace with your AI API call.',
|
|
42
|
-
};
|
|
43
|
-
setMessages((prev) => [...prev, assistantMessage]);
|
|
44
|
-
} finally {
|
|
45
|
-
setIsLoading(false);
|
|
46
|
-
}
|
|
47
|
-
};
|
|
48
|
-
|
|
49
|
-
return (
|
|
50
|
-
<Stack gap="4" style={{ height: '100vh', padding: '1rem' }}>
|
|
51
|
-
{/* Messages */}
|
|
52
|
-
<Stack gap="3" style={{ flex: 1, overflow: 'auto' }}>
|
|
53
|
-
{messages.map((msg) => (
|
|
54
|
-
<Card key={msg.id} padding="md">
|
|
55
|
-
<Card.Body>
|
|
56
|
-
<Stack direction="row" gap="3" align="start">
|
|
57
|
-
<Avatar size="sm">
|
|
58
|
-
{msg.role === 'user' ? 'U' : 'AI'}
|
|
59
|
-
</Avatar>
|
|
60
|
-
<div style={{ flex: 1 }}>{msg.content}</div>
|
|
61
|
-
</Stack>
|
|
62
|
-
</Card.Body>
|
|
63
|
-
</Card>
|
|
64
|
-
))}
|
|
65
|
-
</Stack>
|
|
66
|
-
|
|
67
|
-
{/* Prompt */}
|
|
68
|
-
<Prompt onSubmit={handleSubmit} loading={isLoading}>
|
|
69
|
-
<Prompt.Textarea placeholder="Ask anything..." />
|
|
70
|
-
<Prompt.Toolbar>
|
|
71
|
-
<Prompt.Actions>
|
|
72
|
-
<Prompt.ActionButton aria-label="Attach file">
|
|
73
|
-
+
|
|
74
|
-
</Prompt.ActionButton>
|
|
75
|
-
<Prompt.ModeButton>Auto</Prompt.ModeButton>
|
|
76
|
-
</Prompt.Actions>
|
|
77
|
-
<Prompt.Info>
|
|
78
|
-
<Prompt.Usage>52% used</Prompt.Usage>
|
|
79
|
-
<Prompt.Submit />
|
|
80
|
-
</Prompt.Info>
|
|
81
|
-
</Prompt.Toolbar>
|
|
82
|
-
</Prompt>
|
|
83
|
-
</Stack>
|
|
84
|
-
);
|
|
85
|
-
}
|
|
86
|
-
`.trim(),
|
|
87
|
-
});
|
|
@@ -1,66 +0,0 @@
|
|
|
1
|
-
import { defineRecipe } from '@fragments/core';
|
|
2
|
-
|
|
3
|
-
export default defineRecipe({
|
|
4
|
-
name: 'Code Examples',
|
|
5
|
-
description: 'Patterns for displaying code in documentation with syntax highlighting',
|
|
6
|
-
category: 'documentation',
|
|
7
|
-
components: ['CodeBlock', 'Tabs', 'Card'],
|
|
8
|
-
tags: ['code', 'documentation', 'syntax', 'examples'],
|
|
9
|
-
code: `
|
|
10
|
-
// Installation commands with package manager tabs
|
|
11
|
-
<Tabs defaultValue="npm">
|
|
12
|
-
<Tabs.List>
|
|
13
|
-
<Tabs.Tab value="npm">npm</Tabs.Tab>
|
|
14
|
-
<Tabs.Tab value="pnpm">pnpm</Tabs.Tab>
|
|
15
|
-
<Tabs.Tab value="yarn">yarn</Tabs.Tab>
|
|
16
|
-
</Tabs.List>
|
|
17
|
-
<Tabs.Panel value="npm">
|
|
18
|
-
<CodeBlock code="npm install @fragments-sdk/ui" language="bash" />
|
|
19
|
-
</Tabs.Panel>
|
|
20
|
-
<Tabs.Panel value="pnpm">
|
|
21
|
-
<CodeBlock code="pnpm add @fragments-sdk/ui" language="bash" />
|
|
22
|
-
</Tabs.Panel>
|
|
23
|
-
<Tabs.Panel value="yarn">
|
|
24
|
-
<CodeBlock code="yarn add @fragments-sdk/ui" language="bash" />
|
|
25
|
-
</Tabs.Panel>
|
|
26
|
-
</Tabs>
|
|
27
|
-
|
|
28
|
-
// Usage example with preview
|
|
29
|
-
<Card>
|
|
30
|
-
<Card.Header>
|
|
31
|
-
<Card.Title>Button Example</Card.Title>
|
|
32
|
-
</Card.Header>
|
|
33
|
-
<Card.Body>
|
|
34
|
-
<div className="preview">
|
|
35
|
-
<Button variant="primary">Click me</Button>
|
|
36
|
-
</div>
|
|
37
|
-
<CodeBlock
|
|
38
|
-
code={\`<Button variant="primary">Click me</Button>\`}
|
|
39
|
-
language="tsx"
|
|
40
|
-
/>
|
|
41
|
-
</Card.Body>
|
|
42
|
-
</Card>
|
|
43
|
-
|
|
44
|
-
// Multi-file example with titles
|
|
45
|
-
<CodeBlock
|
|
46
|
-
title="Button.tsx"
|
|
47
|
-
code={buttonCode}
|
|
48
|
-
language="tsx"
|
|
49
|
-
showLineNumbers
|
|
50
|
-
/>
|
|
51
|
-
<CodeBlock
|
|
52
|
-
title="Button.module.scss"
|
|
53
|
-
code={stylesCode}
|
|
54
|
-
language="scss"
|
|
55
|
-
showLineNumbers
|
|
56
|
-
/>
|
|
57
|
-
|
|
58
|
-
// Highlighted important lines
|
|
59
|
-
<CodeBlock
|
|
60
|
-
code={exampleCode}
|
|
61
|
-
language="tsx"
|
|
62
|
-
showLineNumbers
|
|
63
|
-
highlightLines={[3, "7-10"]}
|
|
64
|
-
/>
|
|
65
|
-
`.trim(),
|
|
66
|
-
});
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
import { defineRecipe } from '@fragments/core';
|
|
2
|
-
|
|
3
|
-
export default defineRecipe({
|
|
4
|
-
name: 'Confirm Dialog',
|
|
5
|
-
description: 'Confirmation dialog with destructive action warning',
|
|
6
|
-
category: 'overlays',
|
|
7
|
-
components: ['Dialog', 'Button'],
|
|
8
|
-
tags: ['confirm', 'dialog', 'modal', 'destructive'],
|
|
9
|
-
code: `
|
|
10
|
-
<Dialog open={isOpen} onClose={onClose}>
|
|
11
|
-
<Dialog.Title>{title}</Dialog.Title>
|
|
12
|
-
<Dialog.Description>{description}</Dialog.Description>
|
|
13
|
-
<Dialog.Actions>
|
|
14
|
-
<Button variant="secondary" onClick={onClose}>Cancel</Button>
|
|
15
|
-
<Button variant="danger" onClick={onConfirm}>Confirm</Button>
|
|
16
|
-
</Dialog.Actions>
|
|
17
|
-
</Dialog>
|
|
18
|
-
`.trim(),
|
|
19
|
-
});
|
|
@@ -1,73 +0,0 @@
|
|
|
1
|
-
import { defineRecipe } from '@fragments/core';
|
|
2
|
-
|
|
3
|
-
export default defineRecipe({
|
|
4
|
-
name: 'Dashboard Layout',
|
|
5
|
-
description: 'Dashboard grid with a featured full-width card and smaller metric cards below',
|
|
6
|
-
category: 'layout',
|
|
7
|
-
components: ['Grid', 'Card', 'Badge', 'Separator'],
|
|
8
|
-
tags: ['dashboard', 'layout', 'metrics', 'widgets', 'overview'],
|
|
9
|
-
code: `
|
|
10
|
-
<Grid columns={4} gap="lg">
|
|
11
|
-
<Grid.Item colSpan="full">
|
|
12
|
-
<Card>
|
|
13
|
-
<Card.Header>
|
|
14
|
-
<Card.Title>Overview</Card.Title>
|
|
15
|
-
<Card.Description>Key metrics for this period</Card.Description>
|
|
16
|
-
</Card.Header>
|
|
17
|
-
<Card.Body>{summaryContent}</Card.Body>
|
|
18
|
-
</Card>
|
|
19
|
-
</Grid.Item>
|
|
20
|
-
<Card variant="outlined">
|
|
21
|
-
<Card.Header>
|
|
22
|
-
<Card.Title>Users</Card.Title>
|
|
23
|
-
</Card.Header>
|
|
24
|
-
<Card.Body>
|
|
25
|
-
<Badge variant="success">{stats.users}</Badge>
|
|
26
|
-
</Card.Body>
|
|
27
|
-
</Card>
|
|
28
|
-
<Card variant="outlined">
|
|
29
|
-
<Card.Header>
|
|
30
|
-
<Card.Title>Revenue</Card.Title>
|
|
31
|
-
</Card.Header>
|
|
32
|
-
<Card.Body>
|
|
33
|
-
<Badge variant="info">{stats.revenue}</Badge>
|
|
34
|
-
</Card.Body>
|
|
35
|
-
</Card>
|
|
36
|
-
<Card variant="outlined">
|
|
37
|
-
<Card.Header>
|
|
38
|
-
<Card.Title>Orders</Card.Title>
|
|
39
|
-
</Card.Header>
|
|
40
|
-
<Card.Body>
|
|
41
|
-
<Badge variant="warning">{stats.orders}</Badge>
|
|
42
|
-
</Card.Body>
|
|
43
|
-
</Card>
|
|
44
|
-
<Card variant="outlined">
|
|
45
|
-
<Card.Header>
|
|
46
|
-
<Card.Title>Errors</Card.Title>
|
|
47
|
-
</Card.Header>
|
|
48
|
-
<Card.Body>
|
|
49
|
-
<Badge variant="danger">{stats.errors}</Badge>
|
|
50
|
-
</Card.Body>
|
|
51
|
-
</Card>
|
|
52
|
-
<Grid.Item colSpan="full">
|
|
53
|
-
<Separator spacing="md" />
|
|
54
|
-
</Grid.Item>
|
|
55
|
-
<Grid.Item colSpan={2}>
|
|
56
|
-
<Card>
|
|
57
|
-
<Card.Header>
|
|
58
|
-
<Card.Title>Recent Activity</Card.Title>
|
|
59
|
-
</Card.Header>
|
|
60
|
-
<Card.Body>{activityList}</Card.Body>
|
|
61
|
-
</Card>
|
|
62
|
-
</Grid.Item>
|
|
63
|
-
<Grid.Item colSpan={2}>
|
|
64
|
-
<Card>
|
|
65
|
-
<Card.Header>
|
|
66
|
-
<Card.Title>Notifications</Card.Title>
|
|
67
|
-
</Card.Header>
|
|
68
|
-
<Card.Body>{notificationList}</Card.Body>
|
|
69
|
-
</Card>
|
|
70
|
-
</Grid.Item>
|
|
71
|
-
</Grid>
|
|
72
|
-
`.trim(),
|
|
73
|
-
});
|
|
@@ -1,183 +0,0 @@
|
|
|
1
|
-
import { defineRecipe } from '@fragments/core';
|
|
2
|
-
|
|
3
|
-
export default defineRecipe({
|
|
4
|
-
name: 'Dashboard Navigation',
|
|
5
|
-
description: 'Sidebar navigation pattern for dashboard applications with user profile, sections, and nested menus',
|
|
6
|
-
category: 'navigation',
|
|
7
|
-
components: ['Sidebar', 'Avatar'],
|
|
8
|
-
tags: ['navigation', 'sidebar', 'dashboard', 'admin', 'menu'],
|
|
9
|
-
code: `
|
|
10
|
-
// Dashboard Navigation with User Profile
|
|
11
|
-
// A complete sidebar navigation for admin/dashboard interfaces
|
|
12
|
-
|
|
13
|
-
function DashboardNav({ user, currentPath }) {
|
|
14
|
-
const [collapsed, setCollapsed] = React.useState(false);
|
|
15
|
-
const [projectsExpanded, setProjectsExpanded] = React.useState(false);
|
|
16
|
-
|
|
17
|
-
return (
|
|
18
|
-
<Sidebar
|
|
19
|
-
collapsed={collapsed}
|
|
20
|
-
onCollapsedChange={setCollapsed}
|
|
21
|
-
>
|
|
22
|
-
{/* Brand header */}
|
|
23
|
-
<Sidebar.Header>
|
|
24
|
-
<svg width="32" height="32" viewBox="0 0 256 256" fill="var(--fui-color-accent)">
|
|
25
|
-
<path d="M208,32H48A16,16,0,0,0,32,48V208a16,16,0,0,0,16,16H208a16,16,0,0,0,16-16V48A16,16,0,0,0,208,32Zm0,176H48V48H208V208Z" />
|
|
26
|
-
</svg>
|
|
27
|
-
{!collapsed && (
|
|
28
|
-
<span style={{ fontWeight: 600, fontSize: '16px' }}>Dashboard</span>
|
|
29
|
-
)}
|
|
30
|
-
<Sidebar.CollapseToggle />
|
|
31
|
-
</Sidebar.Header>
|
|
32
|
-
|
|
33
|
-
{/* Main navigation */}
|
|
34
|
-
<Sidebar.Nav aria-label="Dashboard navigation">
|
|
35
|
-
{/* Primary section */}
|
|
36
|
-
<Sidebar.Section>
|
|
37
|
-
<Sidebar.Item
|
|
38
|
-
icon={<HomeIcon />}
|
|
39
|
-
href="/dashboard"
|
|
40
|
-
active={currentPath === '/dashboard'}
|
|
41
|
-
>
|
|
42
|
-
Overview
|
|
43
|
-
</Sidebar.Item>
|
|
44
|
-
<Sidebar.Item
|
|
45
|
-
icon={<ChartIcon />}
|
|
46
|
-
href="/analytics"
|
|
47
|
-
active={currentPath === '/analytics'}
|
|
48
|
-
badge="New"
|
|
49
|
-
>
|
|
50
|
-
Analytics
|
|
51
|
-
</Sidebar.Item>
|
|
52
|
-
<Sidebar.Item
|
|
53
|
-
icon={<InboxIcon />}
|
|
54
|
-
href="/inbox"
|
|
55
|
-
active={currentPath === '/inbox'}
|
|
56
|
-
badge="5"
|
|
57
|
-
>
|
|
58
|
-
Inbox
|
|
59
|
-
</Sidebar.Item>
|
|
60
|
-
</Sidebar.Section>
|
|
61
|
-
|
|
62
|
-
{/* Projects section with nested items */}
|
|
63
|
-
<Sidebar.Section label="Workspace">
|
|
64
|
-
<Sidebar.Item
|
|
65
|
-
icon={<FolderIcon />}
|
|
66
|
-
hasSubmenu
|
|
67
|
-
expanded={projectsExpanded}
|
|
68
|
-
onExpandedChange={setProjectsExpanded}
|
|
69
|
-
>
|
|
70
|
-
Projects
|
|
71
|
-
</Sidebar.Item>
|
|
72
|
-
<Sidebar.Submenu>
|
|
73
|
-
<Sidebar.SubItem
|
|
74
|
-
href="/projects/website"
|
|
75
|
-
active={currentPath === '/projects/website'}
|
|
76
|
-
>
|
|
77
|
-
Website Redesign
|
|
78
|
-
</Sidebar.SubItem>
|
|
79
|
-
<Sidebar.SubItem
|
|
80
|
-
href="/projects/mobile"
|
|
81
|
-
active={currentPath === '/projects/mobile'}
|
|
82
|
-
>
|
|
83
|
-
Mobile App
|
|
84
|
-
</Sidebar.SubItem>
|
|
85
|
-
<Sidebar.SubItem
|
|
86
|
-
href="/projects/api"
|
|
87
|
-
active={currentPath === '/projects/api'}
|
|
88
|
-
>
|
|
89
|
-
API Integration
|
|
90
|
-
</Sidebar.SubItem>
|
|
91
|
-
</Sidebar.Submenu>
|
|
92
|
-
<Sidebar.Item
|
|
93
|
-
icon={<UsersIcon />}
|
|
94
|
-
href="/team"
|
|
95
|
-
active={currentPath === '/team'}
|
|
96
|
-
>
|
|
97
|
-
Team Members
|
|
98
|
-
</Sidebar.Item>
|
|
99
|
-
<Sidebar.Item
|
|
100
|
-
icon={<CalendarIcon />}
|
|
101
|
-
href="/calendar"
|
|
102
|
-
active={currentPath === '/calendar'}
|
|
103
|
-
>
|
|
104
|
-
Calendar
|
|
105
|
-
</Sidebar.Item>
|
|
106
|
-
</Sidebar.Section>
|
|
107
|
-
|
|
108
|
-
{/* Settings section */}
|
|
109
|
-
<Sidebar.Section label="Account">
|
|
110
|
-
<Sidebar.Item
|
|
111
|
-
icon={<GearIcon />}
|
|
112
|
-
href="/settings"
|
|
113
|
-
active={currentPath === '/settings'}
|
|
114
|
-
>
|
|
115
|
-
Settings
|
|
116
|
-
</Sidebar.Item>
|
|
117
|
-
<Sidebar.Item
|
|
118
|
-
icon={<HelpIcon />}
|
|
119
|
-
href="/help"
|
|
120
|
-
active={currentPath === '/help'}
|
|
121
|
-
>
|
|
122
|
-
Help & Support
|
|
123
|
-
</Sidebar.Item>
|
|
124
|
-
</Sidebar.Section>
|
|
125
|
-
</Sidebar.Nav>
|
|
126
|
-
|
|
127
|
-
{/* Footer with user profile */}
|
|
128
|
-
<Sidebar.Footer>
|
|
129
|
-
<div style={{
|
|
130
|
-
display: 'flex',
|
|
131
|
-
alignItems: 'center',
|
|
132
|
-
gap: '12px',
|
|
133
|
-
padding: collapsed ? '0' : '8px',
|
|
134
|
-
borderRadius: '8px',
|
|
135
|
-
cursor: 'pointer',
|
|
136
|
-
}}>
|
|
137
|
-
<Avatar
|
|
138
|
-
src={user.avatar}
|
|
139
|
-
name={user.name}
|
|
140
|
-
size="sm"
|
|
141
|
-
/>
|
|
142
|
-
{!collapsed && (
|
|
143
|
-
<div style={{ flex: 1, minWidth: 0 }}>
|
|
144
|
-
<div style={{
|
|
145
|
-
fontWeight: 500,
|
|
146
|
-
fontSize: '14px',
|
|
147
|
-
whiteSpace: 'nowrap',
|
|
148
|
-
overflow: 'hidden',
|
|
149
|
-
textOverflow: 'ellipsis',
|
|
150
|
-
}}>
|
|
151
|
-
{user.name}
|
|
152
|
-
</div>
|
|
153
|
-
<div style={{
|
|
154
|
-
fontSize: '12px',
|
|
155
|
-
color: 'var(--fui-text-secondary)',
|
|
156
|
-
whiteSpace: 'nowrap',
|
|
157
|
-
overflow: 'hidden',
|
|
158
|
-
textOverflow: 'ellipsis',
|
|
159
|
-
}}>
|
|
160
|
-
{user.email}
|
|
161
|
-
</div>
|
|
162
|
-
</div>
|
|
163
|
-
)}
|
|
164
|
-
</div>
|
|
165
|
-
</Sidebar.Footer>
|
|
166
|
-
</Sidebar>
|
|
167
|
-
);
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
// Usage example:
|
|
171
|
-
// <DashboardNav
|
|
172
|
-
// user={{ name: 'Jane Doe', email: 'jane@example.com', avatar: '/avatar.jpg' }}
|
|
173
|
-
// currentPath="/dashboard"
|
|
174
|
-
// />
|
|
175
|
-
|
|
176
|
-
// Icon components (use your preferred icon library)
|
|
177
|
-
const HomeIcon = () => (
|
|
178
|
-
<svg width="20" height="20" viewBox="0 0 256 256" fill="currentColor">
|
|
179
|
-
<path d="M219.31,108.68l-80-80a16,16,0,0,0-22.62,0l-80,80A15.87,15.87,0,0,0,32,120v96a8,8,0,0,0,8,8H96a8,8,0,0,0,8-8V160h48v56a8,8,0,0,0,8,8h56a8,8,0,0,0,8-8V120A15.87,15.87,0,0,0,219.31,108.68Z" />
|
|
180
|
-
</svg>
|
|
181
|
-
);
|
|
182
|
-
`.trim(),
|
|
183
|
-
});
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
import { defineRecipe } from '@fragments/core';
|
|
2
|
-
|
|
3
|
-
export default defineRecipe({
|
|
4
|
-
name: 'Form Layout',
|
|
5
|
-
description: 'Two-column form with full-width fields where needed, using Grid for alignment',
|
|
6
|
-
category: 'forms',
|
|
7
|
-
components: ['Grid', 'Input', 'Textarea', 'Select', 'Button'],
|
|
8
|
-
tags: ['form', 'layout', 'grid', 'inputs', 'settings'],
|
|
9
|
-
code: `
|
|
10
|
-
<Grid columns={2} gap="md">
|
|
11
|
-
<Input label="First Name" placeholder="Jane" />
|
|
12
|
-
<Input label="Last Name" placeholder="Doe" />
|
|
13
|
-
<Grid.Item colSpan="full">
|
|
14
|
-
<Input label="Email" type="email" placeholder="jane@example.com" />
|
|
15
|
-
</Grid.Item>
|
|
16
|
-
<Grid.Item colSpan="full">
|
|
17
|
-
<Select label="Role">
|
|
18
|
-
<Select.Item value="admin">Admin</Select.Item>
|
|
19
|
-
<Select.Item value="editor">Editor</Select.Item>
|
|
20
|
-
<Select.Item value="viewer">Viewer</Select.Item>
|
|
21
|
-
</Select>
|
|
22
|
-
</Grid.Item>
|
|
23
|
-
<Grid.Item colSpan="full">
|
|
24
|
-
<Textarea label="Bio" placeholder="Tell us about yourself" />
|
|
25
|
-
</Grid.Item>
|
|
26
|
-
<Grid.Item colSpan="full">
|
|
27
|
-
<Button type="submit" variant="primary">Save</Button>
|
|
28
|
-
</Grid.Item>
|
|
29
|
-
</Grid>
|
|
30
|
-
`.trim(),
|
|
31
|
-
});
|