@turk.net/mui 3.0.6 → 3.0.8
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/.opencode/rules/design-compliance.md +119 -0
- package/.opencode/skills/onehub-design-verification/SKILL.md +315 -0
- package/.opencode/skills/turknet-onehub-component-usage/SKILL.md +16 -16
- package/COMPONENT_GLOSSARY.md +500 -0
- package/COMPONENT_MAP.md +567 -0
- package/DESIGN_RULES.md +399 -0
- package/DESIGN_SOURCES.md +198 -0
- package/DESIGN_TOKENS_MAP.md +271 -0
- package/ESLINT_DESIGN_RULES.md +392 -0
- package/LLM_EXAMPLES.md +183 -169
- package/LLM_GUIDELINES.md +192 -192
- package/PAGE_PATTERNS.md +509 -0
- package/README.md +18 -19
- package/SKILL_SETUP.md +237 -200
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1 -0
- package/dist/index.mjs.map +1 -1
- package/dist/theme/index.js +1 -0
- package/dist/theme/index.js.map +1 -1
- package/dist/theme/index.mjs +1 -0
- package/dist/theme/index.mjs.map +1 -1
- package/package.json +20 -3
- package/scripts/verify-design.js +351 -0
package/PAGE_PATTERNS.md
ADDED
|
@@ -0,0 +1,509 @@
|
|
|
1
|
+
# OneHub Page Patterns
|
|
2
|
+
|
|
3
|
+
> **Purpose:** Standardized page patterns for OneHub modules. When creating a new page, match it to the closest pattern below and follow the exact structure, layout, component set, and spacing grid.
|
|
4
|
+
>
|
|
5
|
+
> **All patterns MUST use OneHub theme rules:** typography variants, spacing via `theme.spacing()`, colors via CSS custom properties.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Pattern 1: List Page (Table + Filters)
|
|
10
|
+
|
|
11
|
+
**Use case:** Task lists, customer lists, ticket lists, lead lists, any tabular data with search/filter.
|
|
12
|
+
|
|
13
|
+
### Layout
|
|
14
|
+
|
|
15
|
+
```
|
|
16
|
+
TabBasedLayout (app level)
|
|
17
|
+
└── DashboardLayout / WithSidebarLayout (page level)
|
|
18
|
+
└── PageContentContainer
|
|
19
|
+
├── PageContentHeader (title + actions)
|
|
20
|
+
└── Content Area
|
|
21
|
+
├── Search & Filter Bar
|
|
22
|
+
├── Active Filter Tags (Chips)
|
|
23
|
+
├── Table Header Row
|
|
24
|
+
├── Table Data Rows
|
|
25
|
+
└── Pagination
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
### Component Breakdown
|
|
29
|
+
|
|
30
|
+
| Element | Component | Props |
|
|
31
|
+
|---------|-----------|-------|
|
|
32
|
+
| Page title | `Typography` | `variant="display.xs.bold"` |
|
|
33
|
+
| Search input | `TextField` | `color="neutral" size="medium" placeholder="Ara"` |
|
|
34
|
+
| Search icon | `SearchIcon` from icons | `size: 20px` |
|
|
35
|
+
| Filter button | `Button` | `variant="text" size="medium" color="secondary"` |
|
|
36
|
+
| Active filter tags | `Chip` | `variant="tint" color="primary" size="small" onDelete={...}` |
|
|
37
|
+
| Clear filters button | `Button` | `variant="text" size="medium" color="primary"` |
|
|
38
|
+
| Table header | Custom `Box` | `bg: neutral.background[2].rest`, `height: 40px` |
|
|
39
|
+
| Table header text | `Typography` | `variant="text.xs.medium"` |
|
|
40
|
+
| Table row | Custom `Box` | `bg: neutral.background[1].rest`, `height: 56px` |
|
|
41
|
+
| Table primary text | `Typography` | `variant="text.sm.medium" color="neutral.foreground[1].rest"` |
|
|
42
|
+
| Table secondary text | `Typography` | `variant="text.sm.regular" color="neutral.foreground[4].rest"` |
|
|
43
|
+
| Status indicator | `Badge` or `Chip` | Depends on status type |
|
|
44
|
+
| Pagination | `Pagination` | `size="medium" color="primary"` |
|
|
45
|
+
|
|
46
|
+
### Spacing Grid
|
|
47
|
+
|
|
48
|
+
```
|
|
49
|
+
Table cell: paddingLeft/Right: theme.spacing(8) (32px)
|
|
50
|
+
Table header: height: theme.spacing(10) (40px)
|
|
51
|
+
Table row: height: theme.spacing(14) (56px)
|
|
52
|
+
Row gap: gap: theme.spacing(2) (8px)
|
|
53
|
+
Section gap: marginBottom: theme.spacing(4) (16px)
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
### Figma Reference
|
|
57
|
+
|
|
58
|
+
- `My task table` (`364:28717`)
|
|
59
|
+
- `Team task table` (`694:41994`)
|
|
60
|
+
- `Customer table` (`2291:40548`)
|
|
61
|
+
- `Ticket List table` (`9148:52401`)
|
|
62
|
+
|
|
63
|
+
### Example Structure
|
|
64
|
+
|
|
65
|
+
```tsx
|
|
66
|
+
function TaskListPage() {
|
|
67
|
+
return (
|
|
68
|
+
<PageContentContainer>
|
|
69
|
+
<PageContentHeader>
|
|
70
|
+
<Typography variant="display.xs.bold">My Tasks</Typography>
|
|
71
|
+
<Button variant="contained" color="primary" size="medium">
|
|
72
|
+
New Task
|
|
73
|
+
</Button>
|
|
74
|
+
</PageContentHeader>
|
|
75
|
+
|
|
76
|
+
{/* Search & Filter Bar */}
|
|
77
|
+
<Box sx={{ display: 'flex', gap: 2, mb: 2 }}>
|
|
78
|
+
<TextField
|
|
79
|
+
color="neutral"
|
|
80
|
+
size="medium"
|
|
81
|
+
placeholder="Ara"
|
|
82
|
+
InputProps={{ startAdornment: <SearchIcon /> }}
|
|
83
|
+
sx={{ flex: 1 }}
|
|
84
|
+
/>
|
|
85
|
+
<Button variant="text" size="medium" color="secondary" startIcon={<FilterIcon />}>
|
|
86
|
+
Filters
|
|
87
|
+
</Button>
|
|
88
|
+
</Box>
|
|
89
|
+
|
|
90
|
+
{/* Active Filter Tags */}
|
|
91
|
+
<Box sx={{ display: 'flex', gap: 1, mb: 2 }}>
|
|
92
|
+
<Chip variant="tint" color="primary" size="small" label="Today" onDelete={handleRemove} />
|
|
93
|
+
</Box>
|
|
94
|
+
|
|
95
|
+
{/* Table */}
|
|
96
|
+
<Box sx={{ border: 1, borderColor: 'var(--neutral-stroke-3-rest)', borderRadius: 1 }}>
|
|
97
|
+
{/* Header */}
|
|
98
|
+
<Box sx={{
|
|
99
|
+
display: 'flex',
|
|
100
|
+
px: 8,
|
|
101
|
+
height: 40,
|
|
102
|
+
alignItems: 'center',
|
|
103
|
+
bgcolor: 'var(--neutral-background-2-rest)',
|
|
104
|
+
borderBottom: 1,
|
|
105
|
+
borderColor: 'var(--neutral-stroke-3-rest)'
|
|
106
|
+
}}>
|
|
107
|
+
<Typography variant="text.xs.medium" sx={{ minWidth: 140 }}>Date</Typography>
|
|
108
|
+
<Typography variant="text.xs.medium" sx={{ minWidth: 90 }}>Customer</Typography>
|
|
109
|
+
<Typography variant="text.xs.medium" sx={{ flex: 1 }}>Description</Typography>
|
|
110
|
+
<Typography variant="text.xs.medium">Rating</Typography>
|
|
111
|
+
</Box>
|
|
112
|
+
|
|
113
|
+
{/* Rows */}
|
|
114
|
+
{tasks.map(task => (
|
|
115
|
+
<Box key={task.id} sx={{
|
|
116
|
+
display: 'flex',
|
|
117
|
+
px: 8,
|
|
118
|
+
height: 56,
|
|
119
|
+
alignItems: 'center',
|
|
120
|
+
borderBottom: 1,
|
|
121
|
+
borderColor: 'var(--neutral-stroke-3-rest)',
|
|
122
|
+
bgcolor: 'var(--neutral-background-1-rest)'
|
|
123
|
+
}}>
|
|
124
|
+
<Box sx={{ minWidth: 140 }}>
|
|
125
|
+
<Typography variant="text.lg.medium" color="var(--neutral-foreground-2-rest)">06</Typography>
|
|
126
|
+
<Typography variant="text.sm.regular" color="var(--neutral-foreground-4-rest)">WED, THU</Typography>
|
|
127
|
+
</Box>
|
|
128
|
+
<Typography variant="text.sm.regular" color="var(--neutral-foreground-4-rest)" sx={{ minWidth: 90 }}>
|
|
129
|
+
Gizem K.
|
|
130
|
+
</Typography>
|
|
131
|
+
<Typography variant="text.sm.medium" sx={{ flex: 1 }}>{task.description}</Typography>
|
|
132
|
+
<Box sx={{ display: 'flex', gap: 1 }}>
|
|
133
|
+
<FaceHappyIcon />
|
|
134
|
+
<MessageIcon />
|
|
135
|
+
</Box>
|
|
136
|
+
</Box>
|
|
137
|
+
))}
|
|
138
|
+
</Box>
|
|
139
|
+
|
|
140
|
+
{/* Pagination */}
|
|
141
|
+
<Box sx={{ display: 'flex', justifyContent: 'center', mt: 4 }}>
|
|
142
|
+
<Pagination count={totalPages} size="medium" color="primary" />
|
|
143
|
+
</Box>
|
|
144
|
+
</PageContentContainer>
|
|
145
|
+
);
|
|
146
|
+
}
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
---
|
|
150
|
+
|
|
151
|
+
## Pattern 2: Detail Page
|
|
152
|
+
|
|
153
|
+
**Use case:** Task detail, customer detail, ticket detail — viewing a single record with multiple sections.
|
|
154
|
+
|
|
155
|
+
### Layout
|
|
156
|
+
|
|
157
|
+
```
|
|
158
|
+
TabBasedLayout
|
|
159
|
+
└── WithSidebarLayout
|
|
160
|
+
└── PageContentContainer
|
|
161
|
+
├── PageContentHeader (back button + title)
|
|
162
|
+
├── Tab Navigation (optional)
|
|
163
|
+
└── Content Sections
|
|
164
|
+
├── Section Card 1
|
|
165
|
+
├── Section Card 2
|
|
166
|
+
└── ...
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
### Component Breakdown
|
|
170
|
+
|
|
171
|
+
| Element | Component | Props |
|
|
172
|
+
|---------|-----------|-------|
|
|
173
|
+
| Back button | `Button` | `variant="text" size="medium" color="primary"` |
|
|
174
|
+
| Page title | `Typography` | `variant="display.xs.bold"` |
|
|
175
|
+
| Section tabs | `Tabs` + `Tab` | Active: `text.sm.semibold`, Inactive: `text.sm.regular` |
|
|
176
|
+
| Section card | `Paper` | `elevation={0}` |
|
|
177
|
+
| Section title | `Typography` | `variant="text.lg.medium"` |
|
|
178
|
+
| Field label | `Typography` | `variant="text.xs.regular" color="neutral.foreground[2].rest"` |
|
|
179
|
+
| Field value | `Typography` | `variant="text.sm.regular" color="neutral.foreground[1].rest"` |
|
|
180
|
+
| Status badge | `Chip` | `variant="tint" size="small"` |
|
|
181
|
+
| Action buttons | `Button` | `variant="contained" color="primary"` |
|
|
182
|
+
|
|
183
|
+
### Spacing Grid
|
|
184
|
+
|
|
185
|
+
```
|
|
186
|
+
Section gap: marginBottom: theme.spacing(4) (16px)
|
|
187
|
+
Card padding: padding: theme.spacing(4) (16px)
|
|
188
|
+
Field row gap: gap: theme.spacing(2) (8px)
|
|
189
|
+
Field label-value: marginBottom: theme.spacing(1) (4px)
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
### Example Structure
|
|
193
|
+
|
|
194
|
+
```tsx
|
|
195
|
+
function DetailPage() {
|
|
196
|
+
return (
|
|
197
|
+
<PageContentContainer>
|
|
198
|
+
<PageContentHeader>
|
|
199
|
+
<Box sx={{ display: 'flex', alignItems: 'center', gap: 2 }}>
|
|
200
|
+
<Button variant="text" size="medium" color="primary" startIcon={<ArrowLeftIcon />}>
|
|
201
|
+
Back
|
|
202
|
+
</Button>
|
|
203
|
+
<Typography variant="display.xs.bold">Task Detail</Typography>
|
|
204
|
+
</Box>
|
|
205
|
+
<Box sx={{ display: 'flex', gap: 2 }}>
|
|
206
|
+
<Button variant="outlined" size="medium" color="secondary">Transfer</Button>
|
|
207
|
+
<Button variant="contained" size="medium" color="primary">Complete</Button>
|
|
208
|
+
</Box>
|
|
209
|
+
</PageContentHeader>
|
|
210
|
+
|
|
211
|
+
{/* Tabs */}
|
|
212
|
+
<Tabs value={tab} onChange={handleTabChange} sx={{ mb: 4 }}>
|
|
213
|
+
<Tab label="Overview" />
|
|
214
|
+
<Tab label="History" />
|
|
215
|
+
</Tabs>
|
|
216
|
+
|
|
217
|
+
{/* Content */}
|
|
218
|
+
<Paper elevation={0} sx={{ p: 4, mb: 4 }}>
|
|
219
|
+
<Typography variant="text.lg.medium" sx={{ mb: 4 }}>Customer Info</Typography>
|
|
220
|
+
<Box sx={{ display: 'grid', gridTemplateColumns: 'repeat(3, 1fr)', gap: 4 }}>
|
|
221
|
+
<Box>
|
|
222
|
+
<Typography variant="text.xs.regular" color="var(--neutral-foreground-2-rest)">Name</Typography>
|
|
223
|
+
<Typography variant="text.sm.regular">Gizem K.</Typography>
|
|
224
|
+
</Box>
|
|
225
|
+
<Box>
|
|
226
|
+
<Typography variant="text.xs.regular" color="var(--neutral-foreground-2-rest)">Status</Typography>
|
|
227
|
+
<Chip variant="tint" color="success" size="small" label="Active" />
|
|
228
|
+
</Box>
|
|
229
|
+
</Box>
|
|
230
|
+
</Paper>
|
|
231
|
+
</PageContentContainer>
|
|
232
|
+
);
|
|
233
|
+
}
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
---
|
|
237
|
+
|
|
238
|
+
## Pattern 3: Form Page
|
|
239
|
+
|
|
240
|
+
**Use case:** New task, edit task, settings forms, any data entry page.
|
|
241
|
+
|
|
242
|
+
### Layout
|
|
243
|
+
|
|
244
|
+
```
|
|
245
|
+
TabBasedLayout
|
|
246
|
+
└── WithSidebarLayout
|
|
247
|
+
└── PageContentContainer
|
|
248
|
+
├── PageContentHeader (title)
|
|
249
|
+
├── Form (Formik)
|
|
250
|
+
│ ├── Form Section 1
|
|
251
|
+
│ │ ├── Field Row
|
|
252
|
+
│ │ └── ...
|
|
253
|
+
│ └── Form Section 2
|
|
254
|
+
└── Form Actions (Submit + Cancel)
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
### Component Breakdown
|
|
258
|
+
|
|
259
|
+
| Element | Component | Props |
|
|
260
|
+
|---------|-----------|-------|
|
|
261
|
+
| Page title | `Typography` | `variant="display.xs.bold"` |
|
|
262
|
+
| Form wrapper | `form` + `Formik` | Formik `onSubmit` handler |
|
|
263
|
+
| Section title | `Typography` | `variant="text.lg.medium"` |
|
|
264
|
+
| Text input | `TextField` | `color="neutral" size="medium" fullWidth` |
|
|
265
|
+
| Dropdown | `Select` | `color="neutral" size="medium"` |
|
|
266
|
+
| Autocomplete | `Autocomplete` | `size="medium" color="neutral"` |
|
|
267
|
+
| Radio group | `RadioGroup` + `Radio` | `color="primary"` |
|
|
268
|
+
| Checkbox | `Checkbox` + `FormControlLabel` | `color="primary"` |
|
|
269
|
+
| Switch toggle | `Switch` + `FormControlLabel` | `color="primary"` |
|
|
270
|
+
| Date picker | `DatePicker` | `dayjs` adapter |
|
|
271
|
+
| Error message | `FormHelperText` | `error` |
|
|
272
|
+
| Submit button | `Button` | `variant="contained" color="primary" size="medium"` |
|
|
273
|
+
| Cancel button | `Button` | `variant="outlined" color="secondary" size="medium"` |
|
|
274
|
+
|
|
275
|
+
### Spacing Grid
|
|
276
|
+
|
|
277
|
+
```
|
|
278
|
+
Section gap: marginBottom: theme.spacing(4) (16px)
|
|
279
|
+
Field row gap: gap: theme.spacing(2) (8px)
|
|
280
|
+
Label margin: marginBottom: theme.spacing(1) (4px)
|
|
281
|
+
Field fullWidth: fullWidth
|
|
282
|
+
Form actions: gap: theme.spacing(2), justifyContent: flex-end
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
### Example Structure
|
|
286
|
+
|
|
287
|
+
```tsx
|
|
288
|
+
function CreateTaskForm() {
|
|
289
|
+
const formik = useFormik({
|
|
290
|
+
initialValues: { title: '', customer: null, priority: 'medium', notify: false },
|
|
291
|
+
validationSchema: yup.object({
|
|
292
|
+
title: yup.string().required('Title is required'),
|
|
293
|
+
customer: yup.object().required('Customer is required'),
|
|
294
|
+
}),
|
|
295
|
+
onSubmit: (values) => createTask(values),
|
|
296
|
+
});
|
|
297
|
+
|
|
298
|
+
return (
|
|
299
|
+
<PageContentContainer>
|
|
300
|
+
<PageContentHeader>
|
|
301
|
+
<Typography variant="display.xs.bold">New Task</Typography>
|
|
302
|
+
</PageContentHeader>
|
|
303
|
+
|
|
304
|
+
<form onSubmit={formik.handleSubmit}>
|
|
305
|
+
<Paper elevation={0} sx={{ p: 4, mb: 4 }}>
|
|
306
|
+
<Typography variant="text.lg.medium" sx={{ mb: 4 }}>Task Details</Typography>
|
|
307
|
+
|
|
308
|
+
<Box sx={{ display: 'flex', flexDirection: 'column', gap: 2 }}>
|
|
309
|
+
<TextField
|
|
310
|
+
name="title"
|
|
311
|
+
label="Title"
|
|
312
|
+
color="neutral"
|
|
313
|
+
size="medium"
|
|
314
|
+
fullWidth
|
|
315
|
+
value={formik.values.title}
|
|
316
|
+
onChange={formik.handleChange}
|
|
317
|
+
error={formik.touched.title && Boolean(formik.errors.title)}
|
|
318
|
+
helperText={formik.touched.title && formik.errors.title}
|
|
319
|
+
/>
|
|
320
|
+
|
|
321
|
+
<Autocomplete
|
|
322
|
+
options={customers}
|
|
323
|
+
size="medium"
|
|
324
|
+
renderInput={(params) => (
|
|
325
|
+
<TextField {...params} label="Customer" color="neutral" />
|
|
326
|
+
)}
|
|
327
|
+
value={formik.values.customer}
|
|
328
|
+
onChange={(_, value) => formik.setFieldValue('customer', value)}
|
|
329
|
+
/>
|
|
330
|
+
|
|
331
|
+
<FormControlLabel
|
|
332
|
+
control={<Switch color="primary" checked={formik.values.notify} />}
|
|
333
|
+
label="Notify team"
|
|
334
|
+
/>
|
|
335
|
+
</Box>
|
|
336
|
+
</Paper>
|
|
337
|
+
|
|
338
|
+
<Box sx={{ display: 'flex', justifyContent: 'flex-end', gap: 2 }}>
|
|
339
|
+
<Button variant="outlined" size="medium" color="secondary">Cancel</Button>
|
|
340
|
+
<Button variant="contained" size="medium" color="primary" type="submit">
|
|
341
|
+
Create
|
|
342
|
+
</Button>
|
|
343
|
+
</Box>
|
|
344
|
+
</form>
|
|
345
|
+
</PageContentContainer>
|
|
346
|
+
);
|
|
347
|
+
}
|
|
348
|
+
```
|
|
349
|
+
|
|
350
|
+
---
|
|
351
|
+
|
|
352
|
+
## Pattern 4: Dashboard
|
|
353
|
+
|
|
354
|
+
**Use case:** Overview screens with metrics, charts, quick actions.
|
|
355
|
+
|
|
356
|
+
### Layout
|
|
357
|
+
|
|
358
|
+
```
|
|
359
|
+
TabBasedLayout
|
|
360
|
+
└── WithSidebarLayout
|
|
361
|
+
└── PageContentContainer
|
|
362
|
+
├── PageContentHeader (title + date filter)
|
|
363
|
+
├── Metrics Row (Cards)
|
|
364
|
+
├── Charts/Graphs Section
|
|
365
|
+
└── Quick Actions
|
|
366
|
+
```
|
|
367
|
+
|
|
368
|
+
### Component Breakdown
|
|
369
|
+
|
|
370
|
+
| Element | Component | Props |
|
|
371
|
+
|---------|-----------|-------|
|
|
372
|
+
| Page title | `Typography` | `variant="display.xs.bold"` |
|
|
373
|
+
| Date filter | `Chip` or `Select` | Filter chips shown in Figma |
|
|
374
|
+
| Metric card | `Paper` | `elevation={0}` |
|
|
375
|
+
| Metric value | `Typography` | `variant="display.md.semibold"` |
|
|
376
|
+
| Metric label | `Typography` | `variant="text.xs.regular" color="neutral.foreground[2].rest"` |
|
|
377
|
+
| Chart area | Custom component | Uses ApexCharts or similar |
|
|
378
|
+
|
|
379
|
+
### Spacing Grid
|
|
380
|
+
|
|
381
|
+
```
|
|
382
|
+
Card gap: gap: theme.spacing(2) (8px)
|
|
383
|
+
Card padding: padding: theme.spacing(4) (16px)
|
|
384
|
+
Section gap: marginBottom: theme.spacing(4) (16px)
|
|
385
|
+
```
|
|
386
|
+
|
|
387
|
+
---
|
|
388
|
+
|
|
389
|
+
## Pattern 5: Dialog/Modal
|
|
390
|
+
|
|
391
|
+
**Use case:** Confirmation dialogs, quick edit forms, transfer/ticket close.
|
|
392
|
+
|
|
393
|
+
### Component Breakdown
|
|
394
|
+
|
|
395
|
+
| Element | Component | Props |
|
|
396
|
+
|---------|-----------|-------|
|
|
397
|
+
| Dialog | `Dialog` | `maxWidth`, `fullWidth` options |
|
|
398
|
+
| Title | `DialogTitle` | Typography: `text.lg.medium` |
|
|
399
|
+
| Content | `DialogContent` | Typography: `text.md.regular` |
|
|
400
|
+
| Content text | `DialogContentText` | — |
|
|
401
|
+
| Primary action | `Button` | `variant="contained" color="primary"` |
|
|
402
|
+
| Secondary action | `Button` | `variant="outlined" color="secondary"` |
|
|
403
|
+
| Destructive action | `Button` | `variant="contained" color="error"` |
|
|
404
|
+
|
|
405
|
+
### Example Structure
|
|
406
|
+
|
|
407
|
+
```tsx
|
|
408
|
+
<Dialog open={open} onClose={handleClose} maxWidth="sm" fullWidth>
|
|
409
|
+
<DialogTitle>Confirm Action</DialogTitle>
|
|
410
|
+
<DialogContent>
|
|
411
|
+
<DialogContentText>
|
|
412
|
+
Are you sure you want to close this ticket?
|
|
413
|
+
</DialogContentText>
|
|
414
|
+
</DialogContent>
|
|
415
|
+
<DialogActions>
|
|
416
|
+
<Button variant="outlined" size="medium" color="secondary" onClick={handleClose}>
|
|
417
|
+
Cancel
|
|
418
|
+
</Button>
|
|
419
|
+
<Button variant="contained" size="medium" color="error" onClick={handleConfirm}>
|
|
420
|
+
Close Ticket
|
|
421
|
+
</Button>
|
|
422
|
+
</DialogActions>
|
|
423
|
+
</Dialog>
|
|
424
|
+
```
|
|
425
|
+
|
|
426
|
+
---
|
|
427
|
+
|
|
428
|
+
## Pattern 6: Notifications
|
|
429
|
+
|
|
430
|
+
**Use case:** Success/error/warning feedback to users.
|
|
431
|
+
|
|
432
|
+
### Component
|
|
433
|
+
|
|
434
|
+
```typescript
|
|
435
|
+
// Use notistack's useSnackbar hook (preferred)
|
|
436
|
+
const { enqueueSnackbar } = useSnackbar();
|
|
437
|
+
|
|
438
|
+
enqueueSnackbar('Operation successful', { variant: 'success' });
|
|
439
|
+
enqueueSnackbar('Something went wrong', { variant: 'error' });
|
|
440
|
+
|
|
441
|
+
// OR: MUI Snackbar + Alert
|
|
442
|
+
<Snackbar open={open} autoHideDuration={6000} onClose={handleClose}>
|
|
443
|
+
<Alert severity="success" onClose={handleClose}>Message</Alert>
|
|
444
|
+
</Snackbar>
|
|
445
|
+
```
|
|
446
|
+
|
|
447
|
+
---
|
|
448
|
+
|
|
449
|
+
## Pattern 7: Empty State
|
|
450
|
+
|
|
451
|
+
**Use case:** When a list or search returns no results.
|
|
452
|
+
|
|
453
|
+
### Example
|
|
454
|
+
|
|
455
|
+
```tsx
|
|
456
|
+
<Box sx={{
|
|
457
|
+
display: 'flex',
|
|
458
|
+
flexDirection: 'column',
|
|
459
|
+
alignItems: 'center',
|
|
460
|
+
justifyContent: 'center',
|
|
461
|
+
py: 16
|
|
462
|
+
}}>
|
|
463
|
+
<EmptyIcon style={{ width: 64, height: 64 }} />
|
|
464
|
+
<Typography variant="text.lg.medium" sx={{ mt: 4 }}>
|
|
465
|
+
No results found
|
|
466
|
+
</Typography>
|
|
467
|
+
<Typography variant="text.sm.regular" color="var(--neutral-foreground-4-rest)" sx={{ mt: 1 }}>
|
|
468
|
+
Try adjusting your search or filter criteria
|
|
469
|
+
</Typography>
|
|
470
|
+
</Box>
|
|
471
|
+
```
|
|
472
|
+
|
|
473
|
+
---
|
|
474
|
+
|
|
475
|
+
## Pattern 8: Loading State
|
|
476
|
+
|
|
477
|
+
**Use case:** While data is being fetched.
|
|
478
|
+
|
|
479
|
+
### Example
|
|
480
|
+
|
|
481
|
+
```tsx
|
|
482
|
+
// Skeleton loader (preferred)
|
|
483
|
+
<Box sx={{ display: 'flex', flexDirection: 'column', gap: 2 }}>
|
|
484
|
+
<Skeleton variant="rectangular" height={40} />
|
|
485
|
+
<Skeleton variant="rectangular" height={56} />
|
|
486
|
+
<Skeleton variant="rectangular" height={56} />
|
|
487
|
+
<Skeleton variant="rectangular" height={56} />
|
|
488
|
+
</Box>
|
|
489
|
+
|
|
490
|
+
// Or: CircularProgress
|
|
491
|
+
<Box sx={{ display: 'flex', justifyContent: 'center', py: 16 }}>
|
|
492
|
+
<CircularProgress />
|
|
493
|
+
</Box>
|
|
494
|
+
```
|
|
495
|
+
|
|
496
|
+
---
|
|
497
|
+
|
|
498
|
+
## Quick Decision Guide
|
|
499
|
+
|
|
500
|
+
| If you need to... | Use Pattern |
|
|
501
|
+
|-------------------|-------------|
|
|
502
|
+
| Show a list of records | Pattern 1: List Page |
|
|
503
|
+
| View single record details | Pattern 2: Detail Page |
|
|
504
|
+
| Collect user input | Pattern 3: Form Page |
|
|
505
|
+
| Show metrics/overview | Pattern 4: Dashboard |
|
|
506
|
+
| Confirm destructive action | Pattern 5: Dialog/Modal |
|
|
507
|
+
| Show feedback message | Pattern 6: Notifications |
|
|
508
|
+
| Handle no-data state | Pattern 7: Empty State |
|
|
509
|
+
| Handle loading state | Pattern 8: Loading State |
|
package/README.md
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
|
-
# @
|
|
1
|
+
# @turk.net/mui - Material UI Theme Package
|
|
2
2
|
|
|
3
|
-
A Material UI theme package for
|
|
3
|
+
A Material UI theme package for NextJs projects, providing customized theme configuration, and icon components.
|
|
4
4
|
|
|
5
5
|
> **Note:** This is a theme package, not a component library. It provides styling and theming for Material UI components. For component usage, refer to the [Material UI documentation](https://mui.com/material-ui/getting-started/).
|
|
6
6
|
|
|
7
7
|
## Installation
|
|
8
8
|
|
|
9
9
|
```bash
|
|
10
|
-
npm install @
|
|
10
|
+
npm install @turk.net/mui
|
|
11
11
|
# or
|
|
12
|
-
yarn add @
|
|
12
|
+
yarn add @turk.net/mui
|
|
13
13
|
```
|
|
14
14
|
|
|
15
15
|
## Usage
|
|
@@ -19,15 +19,11 @@ yarn add @turknet/onehub
|
|
|
19
19
|
Wrap your application with the theme provider:
|
|
20
20
|
|
|
21
21
|
```tsx
|
|
22
|
-
import { ThemeProvider } from
|
|
23
|
-
import theme from
|
|
22
|
+
import { ThemeProvider } from "@mui/material/styles";
|
|
23
|
+
import theme from "@turk.net/mui/theme";
|
|
24
24
|
|
|
25
25
|
function App() {
|
|
26
|
-
return
|
|
27
|
-
<ThemeProvider theme={theme}>
|
|
28
|
-
{/* Your app content */}
|
|
29
|
-
</ThemeProvider>
|
|
30
|
-
);
|
|
26
|
+
return <ThemeProvider theme={theme}>{/* Your app content */}</ThemeProvider>;
|
|
31
27
|
}
|
|
32
28
|
```
|
|
33
29
|
|
|
@@ -36,7 +32,7 @@ function App() {
|
|
|
36
32
|
Once the theme is applied, use Material UI components as documented in the [Material UI documentation](https://mui.com/material-ui/getting-started/):
|
|
37
33
|
|
|
38
34
|
```tsx
|
|
39
|
-
import { Button, Typography, Box } from
|
|
35
|
+
import { Button, Typography, Box } from "@mui/material";
|
|
40
36
|
|
|
41
37
|
function MyComponent() {
|
|
42
38
|
return (
|
|
@@ -57,7 +53,7 @@ The theme will automatically style all Material UI components according to the O
|
|
|
57
53
|
This theme includes custom typography variants following the Untitled UI design system:
|
|
58
54
|
|
|
59
55
|
```tsx
|
|
60
|
-
import { Typography } from
|
|
56
|
+
import { Typography } from "@mui/material";
|
|
61
57
|
|
|
62
58
|
function TypographyExamples() {
|
|
63
59
|
return (
|
|
@@ -67,7 +63,7 @@ function TypographyExamples() {
|
|
|
67
63
|
<Typography variant="display.xl.semibold">Large Display</Typography>
|
|
68
64
|
<Typography variant="display.lg.medium">Medium Display</Typography>
|
|
69
65
|
<Typography variant="display.md.regular">Regular Display</Typography>
|
|
70
|
-
|
|
66
|
+
|
|
71
67
|
{/* Text variants - for body text and UI elements */}
|
|
72
68
|
<Typography variant="text.xl.bold">Extra Large Text</Typography>
|
|
73
69
|
<Typography variant="text.lg.semibold">Large Text</Typography>
|
|
@@ -87,31 +83,32 @@ function TypographyExamples() {
|
|
|
87
83
|
The package includes custom icon components:
|
|
88
84
|
|
|
89
85
|
```tsx
|
|
90
|
-
import HomeIcon from
|
|
91
|
-
import
|
|
86
|
+
import HomeIcon from "@turk.net/mui/icons/Home";
|
|
87
|
+
import Settings01Icon from "@turk.net/mui/icons/Settings01Icon";
|
|
92
88
|
|
|
93
89
|
function MyComponent() {
|
|
94
90
|
return (
|
|
95
91
|
<div>
|
|
96
92
|
<HomeIcon />
|
|
97
|
-
<
|
|
93
|
+
<Settings01Icon />
|
|
98
94
|
</div>
|
|
99
95
|
);
|
|
100
96
|
}
|
|
101
97
|
```
|
|
102
98
|
|
|
103
|
-
> **Note:** Fonts are automatically loaded when you import the theme. No additional setup required!
|
|
104
|
-
|
|
105
99
|
## What's Included
|
|
100
|
+
|
|
106
101
|
- Custom color schemes (light/dark mode support)
|
|
107
102
|
- Typography variants following Untitled UI design system
|
|
108
103
|
- Custom shadows and spacing
|
|
109
104
|
- Component style overrides
|
|
110
105
|
|
|
111
106
|
### Icons
|
|
107
|
+
|
|
112
108
|
Custom SVG icons as React components, compatible with Material UI's icon system.
|
|
113
109
|
|
|
114
110
|
### Fonts
|
|
111
|
+
|
|
115
112
|
Inter font family (Regular, Medium, SemiBold, Bold with italic variants) in WOFF2 format.
|
|
116
113
|
|
|
117
114
|
## Development
|
|
@@ -123,6 +120,7 @@ yarn build
|
|
|
123
120
|
```
|
|
124
121
|
|
|
125
122
|
This will:
|
|
123
|
+
|
|
126
124
|
1. Generate icon components from SVG files
|
|
127
125
|
2. Bundle the library with tsup (ESM + CJS)
|
|
128
126
|
3. Convert TTF fonts to WOFF2 and generate fonts.css
|
|
@@ -158,6 +156,7 @@ For projects that want LLM models to automatically follow Material UI best pract
|
|
|
158
156
|
- **Skill File**: `.opencode/skills/turknet-onehub-component-usage/SKILL.md` - The actual skill that enforces component usage rules
|
|
159
157
|
|
|
160
158
|
The OpenCode skill automatically guides LLM models to:
|
|
159
|
+
|
|
161
160
|
- Use Material UI components exclusively
|
|
162
161
|
- Follow variant/size/color rules from the theme
|
|
163
162
|
- Avoid custom components
|