Skip to content

Commit d0980c0

Browse files
authored
Shadcn UI (#51)
* initial shadcn * example dashboard * example dashboard * feat(shadcn-ui): basic form from lib * feat(shadcn-ui): basic wizard from lib * feat(shadcn-ui): app example * feat(shadcn-ui): app example * feat(shadcn-ui): use shadcn components
1 parent 3bbe216 commit d0980c0

File tree

230 files changed

+20100
-103
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

230 files changed

+20100
-103
lines changed

packages/example/package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@
1414
},
1515
"dependencies": {
1616
"react": "^18.2.0",
17-
"react-dom": "^18.2.0"
17+
"react-dom": "^18.2.0",
18+
"react-router-dom": "^6.13.0"
1819
},
1920
"devDependencies": {
2021
"@types/react": "^18.0.26",

packages/example/src/ShadcnApp.tsx

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
import React from 'react';
2+
import { BrowserRouter } from 'react-router-dom';
3+
import { SelectField } from '@tutim/fields';
4+
import { TutimProvider } from '@tutim/headless';
5+
import '@tutim/shadcn-ui/dist/output.css';
6+
import formConfig from './basic.json';
7+
import { HeadlessWizard } from './Wizards/HeadlessWizard';
8+
import { TutimWizardExample } from './Wizards/TutimWizardExample';
9+
import { defaultFields } from '@tutim/shadcn-ui';
10+
11+
const contextOptions = {
12+
clientId: '2',
13+
forms: { ['form-config-1337']: formConfig },
14+
};
15+
16+
const examples: Record<string, () => JSX.Element> = {
17+
HeadlessWizard,
18+
TutimWizardExample,
19+
};
20+
21+
const options = Object.keys(examples).map((key, ix) => ({ value: key, label: `${ix}) => ${key}` }));
22+
23+
function App(): React.ReactNode {
24+
const [exampleKey, setExample] = React.useState(options[options.length - 1].value);
25+
const Example = examples[exampleKey];
26+
27+
return (
28+
<BrowserRouter>
29+
<div>
30+
<div style={{ padding: '10px', borderBottom: '4px solid green', marginBottom: '30px' }}>
31+
<h3>Pick any wizard example</h3>
32+
<SelectField
33+
fieldConfig={{ key: 'select', label: 'Example', type: 'select', options }}
34+
inputProps={{
35+
value: exampleKey,
36+
onChange: (e: any) => setExample(e.target.value),
37+
}}
38+
/>
39+
</div>
40+
<TutimProvider fieldComponents={defaultFields} options={contextOptions}>
41+
{<Example />}
42+
</TutimProvider>
43+
</div>
44+
</BrowserRouter>
45+
);
46+
}
47+
48+
export default App;

packages/example/src/Wizards/HeadlessWizard.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ const config: FormConfig = {
2020
type: 'text',
2121
},
2222
{ key: 'email', isRequired: true, label: 'Email', type: 'text' },
23-
{ key: 'phone', label: 'Phone', type: 'number' },
23+
{ key: 'phone', label: 'Phone', type: 'text' },
2424
{ key: 'additional', label: 'additional', type: 'text', isRequired: true },
2525
],
2626
wizard: {

packages/example/src/Wizards/TutimWizardExample.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ const config: FormConfig = {
2424
type: 'text',
2525
},
2626
{ key: 'email', isRequired: true, label: 'Email', type: 'text' },
27-
{ key: 'phone', label: 'Phone', type: 'number' },
27+
{ key: 'phone', label: 'Phone', type: 'text' },
2828
{ key: 'additional', label: 'additional', type: 'text', isRequired: true },
2929
],
3030
wizard: {
Lines changed: 272 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,272 @@
1+
{
2+
"type": "page",
3+
"name": "AnalyticsDashboardPage",
4+
"layout": "hidden flex-col md:flex",
5+
"description": "SaaS Subscription Analytics Dashboard",
6+
"components": [
7+
{
8+
"type": "organism",
9+
"name": "Header",
10+
"layout": "flex h-16 items-center px-4 border-b",
11+
"description": "",
12+
"components": [
13+
{
14+
"type": "molecule",
15+
"name": "TeamSwitcher",
16+
"layout": "",
17+
"description": "",
18+
"components": [
19+
{
20+
"type": "atom",
21+
"name": "Button",
22+
"layout": "h-8 w-40",
23+
"description": "",
24+
"components": []
25+
}
26+
]
27+
},
28+
{
29+
"type": "molecule",
30+
"name": "DashboardNav",
31+
"layout": "flex items-center space-x-4 lg:space-x-6 mx-6",
32+
"description": "",
33+
"components": [
34+
{
35+
"type": "atom",
36+
"name": "NavItems",
37+
"layout": "h-8 w-60",
38+
"description": "",
39+
"components": []
40+
}
41+
]
42+
},
43+
{
44+
"type": "atom",
45+
"name": "HeaderActions",
46+
"layout": "ml-auto flex items-center space-x-4",
47+
"description": "",
48+
"components": [
49+
{
50+
"type": "atom",
51+
"name": "SearchInput",
52+
"layout": "h-9 md:w-[100px] lg:w-[300px]",
53+
"description": "",
54+
"components": []
55+
},
56+
{
57+
"type": "molecule",
58+
"name": "UserNav",
59+
"layout": "",
60+
"description": "",
61+
"components": [
62+
{
63+
"type": "atom",
64+
"name": "Button",
65+
"layout": "relative h-8 w-8 rounded-full",
66+
"description": "",
67+
"components": []
68+
}
69+
]
70+
}
71+
]
72+
}
73+
]
74+
},
75+
{
76+
"type": "atom",
77+
"name": "DashboardContent",
78+
"layout": "flex-1 space-y-4 p-8 pt-6",
79+
"description": "",
80+
"components": [
81+
{
82+
"type": "organism",
83+
"name": "SubHeader",
84+
"layout": "flex items-center justify-between space-y-2",
85+
"description": "",
86+
"components": [
87+
{
88+
"type": "atom",
89+
"name": "SubHeaderTypography",
90+
"layout": "w-32 h-8",
91+
"description": "",
92+
"components": []
93+
},
94+
{
95+
"type": "atom",
96+
"name": "SubHeaderActions",
97+
"layout": "flex items-center space-x-2",
98+
"description": "",
99+
"components": [
100+
{
101+
"type": "atom",
102+
"name": "CalendarContainer",
103+
"layout": "grid gap-2",
104+
"description": "",
105+
"components": [
106+
{
107+
"type": "atom",
108+
"name": "CalendarPopover",
109+
"layout": "w-48 h-8",
110+
"description": "",
111+
"components": []
112+
}
113+
]
114+
},
115+
{
116+
"type": "atom",
117+
"name": "DownloadButton",
118+
"layout": "w-24 h-8",
119+
"description": "",
120+
"components": []
121+
}
122+
]
123+
}
124+
]
125+
},
126+
{
127+
"type": "atom",
128+
"name": "Tabs",
129+
"layout": "space-y-4",
130+
"description": "",
131+
"components": [
132+
{
133+
"type": "organism",
134+
"name": "TabNav",
135+
"layout": "w-80 inline-flex h-10 items-center justify-center rounded-md bg-muted p-1 text-muted-foreground",
136+
"description": "",
137+
"components": []
138+
},
139+
{
140+
"type": "atom",
141+
"name": "TabsContent",
142+
"layout": "mt-2 ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 space-y-4",
143+
"description": "",
144+
"components": [
145+
{
146+
"type": "organism",
147+
"name": "SmallCardsContainer",
148+
"layout": "grid gap-4 md:grid-cols-2 lg:grid-cols-4",
149+
"description": "",
150+
"components": [
151+
{
152+
"type": "molecule",
153+
"name": "TotalRevenueCard",
154+
"layout": "p-4 rounded-lg border bg-card text-card-foreground shadow-sm",
155+
"description": "",
156+
"components": [
157+
{
158+
"type": "atom",
159+
"name": "TotalRevenueCardContent",
160+
"layout": "h-24",
161+
"description": "",
162+
"components": []
163+
}
164+
]
165+
},
166+
{
167+
"type": "molecule",
168+
"name": "SubscriptionsCard",
169+
"layout": "p-4 rounded-lg border bg-card text-card-foreground shadow-sm",
170+
"description": "",
171+
"components": [
172+
{
173+
"type": "atom",
174+
"name": "SubscriptionsCardContent",
175+
"layout": "h-24",
176+
"description": "",
177+
"components": []
178+
}
179+
]
180+
},
181+
{
182+
"type": "molecule",
183+
"name": "SalesCard",
184+
"layout": "p-4 rounded-lg border bg-card text-card-foreground shadow-sm",
185+
"description": "",
186+
"components": [
187+
{
188+
"type": "atom",
189+
"name": "SalesCardContent",
190+
"layout": "h-24",
191+
"description": "",
192+
"components": []
193+
}
194+
]
195+
},
196+
{
197+
"type": "molecule",
198+
"name": "ActiveNowCard",
199+
"layout": "p-4 rounded-lg border bg-card text-card-foreground shadow-sm",
200+
"description": "",
201+
"components": [
202+
{
203+
"type": "atom",
204+
"name": "ActiveNowCardContent",
205+
"layout": "h-24",
206+
"description": "",
207+
"components": []
208+
}
209+
]
210+
}
211+
]
212+
},
213+
{
214+
"type": "organism",
215+
"name": "BigCardsContainer",
216+
"layout": "grid gap-4 md:grid-cols-2 lg:grid-cols-7",
217+
"description": "",
218+
"components": [
219+
{
220+
"type": "molecule",
221+
"name": "OverviewCard",
222+
"layout": "col-span-4 p-4 rounded-lg border bg-card text-card-foreground shadow-sm",
223+
"description": "",
224+
"components": [
225+
{
226+
"type": "atom",
227+
"name": "CardHeader",
228+
"layout": "w-40 h-8 mb-4",
229+
"description": "",
230+
"components": []
231+
},
232+
{
233+
"type": "atom",
234+
"name": "OverviewCardContent",
235+
"layout": "w-full h-80",
236+
"description": "",
237+
"components": []
238+
}
239+
]
240+
},
241+
{
242+
"type": "molecule",
243+
"name": "RecentSalesCard",
244+
"layout": "col-span-3 p-4 rounded-lg border bg-card text-card-foreground shadow-sm",
245+
"description": "",
246+
"components": [
247+
{
248+
"type": "atom",
249+
"name": "CardHeader",
250+
"layout": "w-40 h-8 mb-4",
251+
"description": "",
252+
"components": []
253+
},
254+
{
255+
"type": "atom",
256+
"name": "RecentSalesCardContent",
257+
"layout": "w-full h-80",
258+
"description": "",
259+
"components": []
260+
}
261+
]
262+
}
263+
]
264+
}
265+
]
266+
}
267+
]
268+
}
269+
]
270+
}
271+
]
272+
}

packages/example/src/main.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import React from 'react';
22
import ReactDOM from 'react-dom/client';
3-
import App from './App';
3+
// import App from './App';
4+
import App from './ShadcnApp';
45

56
ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render(<App />);

packages/shadcn-ui/.eslintrc.cjs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
module.exports = {
2+
"env": {
3+
"browser": true,
4+
"es2021": true
5+
},
6+
"extends": ["eslint:recommended", "plugin:react/recommended", "plugin:@typescript-eslint/recommended", "plugin:storybook/recommended"],
7+
"parser": "@typescript-eslint/parser",
8+
"parserOptions": {
9+
"ecmaFeatures": {
10+
"jsx": true
11+
},
12+
"ecmaVersion": 12,
13+
"sourceType": "module"
14+
},
15+
"plugins": ["react", "@typescript-eslint"],
16+
"rules": {
17+
"react/prop-types": "off",
18+
"react/react-in-jsx-scope": "off"
19+
}
20+
};

0 commit comments

Comments
 (0)