nurosys-agents 2.0.0
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/.agent/INSTRUCTIONS.md +82 -0
- package/.agent/README.md +483 -0
- package/.agent/backend/skills/architect/SKILL.md +436 -0
- package/.agent/backend/skills/auth-and-permissions/SKILL.md +168 -0
- package/.agent/backend/skills/brainstorm/SKILL.md +127 -0
- package/.agent/backend/skills/code-reviewer/SKILL.md +324 -0
- package/.agent/backend/skills/create-blueprint/SKILL.md +650 -0
- package/.agent/backend/skills/debug-issue/SKILL.md +53 -0
- package/.agent/backend/skills/explore-codebase/SKILL.md +45 -0
- package/.agent/backend/skills/quick-execute/SKILL.md +99 -0
- package/.agent/backend/skills/refactor-safely/SKILL.md +46 -0
- package/.agent/backend/skills/security-assessment/SKILL.md +174 -0
- package/.agent/backend/workflows/module-runner.claude.md +226 -0
- package/.agent/backend/workflows/module-runner.codex.md +155 -0
- package/.agent/backend/workflows/module-runner.cursor.md +212 -0
- package/.agent/frontend/skills/architect/SKILL.md +644 -0
- package/.agent/frontend/skills/auth-and-permissions/SKILL.md +43 -0
- package/.agent/frontend/skills/create-blueprint/SKILL.md +635 -0
- package/.agent/frontend/skills/debug-issue/SKILL.md +28 -0
- package/.agent/frontend/skills/explore-codebase/SKILL.md +29 -0
- package/.agent/frontend/skills/feature-workflow/SKILL.md +61 -0
- package/.agent/frontend/skills/react-quality-review/SKILL.md +126 -0
- package/.agent/frontend/skills/react-quality-review/examples.md +24 -0
- package/.agent/frontend/skills/react-quality-review/rules/_sections.md +26 -0
- package/.agent/frontend/skills/react-quality-review/rules/_template.md +28 -0
- package/.agent/frontend/skills/react-quality-review/rules/advanced-event-handler-refs.md +55 -0
- package/.agent/frontend/skills/react-quality-review/rules/advanced-init-once.md +42 -0
- package/.agent/frontend/skills/react-quality-review/rules/react-rules-calling.md +66 -0
- package/.agent/frontend/skills/react-quality-review/rules/react-rules-hooks.md +91 -0
- package/.agent/frontend/skills/react-quality-review/rules/react-rules-purity.md +121 -0
- package/.agent/frontend/skills/react-quality-review/rules/rendering-activity.md +26 -0
- package/.agent/frontend/skills/react-quality-review/rules/rendering-conditional-render.md +40 -0
- package/.agent/frontend/skills/react-quality-review/rules/rendering-content-visibility.md +38 -0
- package/.agent/frontend/skills/react-quality-review/rules/rendering-hoist-jsx.md +46 -0
- package/.agent/frontend/skills/react-quality-review/rules/rendering-usetransition-loading.md +75 -0
- package/.agent/frontend/skills/react-quality-review/rules/rerender-defer-reads.md +39 -0
- package/.agent/frontend/skills/react-quality-review/rules/rerender-dependencies.md +45 -0
- package/.agent/frontend/skills/react-quality-review/rules/rerender-derived-state-no-effect.md +40 -0
- package/.agent/frontend/skills/react-quality-review/rules/rerender-derived-state.md +29 -0
- package/.agent/frontend/skills/react-quality-review/rules/rerender-functional-setstate.md +74 -0
- package/.agent/frontend/skills/react-quality-review/rules/rerender-lazy-state-init.md +58 -0
- package/.agent/frontend/skills/react-quality-review/rules/rerender-memo-with-default-value.md +38 -0
- package/.agent/frontend/skills/react-quality-review/rules/rerender-memo.md +44 -0
- package/.agent/frontend/skills/react-quality-review/rules/rerender-move-effect-to-event.md +45 -0
- package/.agent/frontend/skills/react-quality-review/rules/rerender-no-inline-components.md +82 -0
- package/.agent/frontend/skills/react-quality-review/rules/rerender-simple-expression-in-memo.md +35 -0
- package/.agent/frontend/skills/react-quality-review/rules/rerender-transitions.md +40 -0
- package/.agent/frontend/skills/react-quality-review/rules/rerender-use-ref-transient-values.md +73 -0
- package/.agent/frontend/skills/refactor-safely/SKILL.md +29 -0
- package/.agent/frontend/skills/vuexy-component-guide/SKILL.md +369 -0
- package/.agent/frontend/skills/vuexy-component-guide/examples.md +662 -0
- package/.agent/frontend/skills/vuexy-component-guide/reference.md +1036 -0
- package/.agent/frontend/workflows/build-feature-react.workflow.md +82 -0
- package/.agent/frontend/workflows/feature-module-runner.md +101 -0
- package/.agent/monolith/skills/architect/SKILL.md +648 -0
- package/.agent/monolith/skills/auth-and-permissions/SKILL.md +43 -0
- package/.agent/monolith/skills/code-reviewer/SKILL.md +281 -0
- package/.agent/monolith/skills/create-blueprint/SKILL.md +635 -0
- package/.agent/monolith/skills/debug-issue/SKILL.md +28 -0
- package/.agent/monolith/skills/explore-codebase/SKILL.md +29 -0
- package/.agent/monolith/skills/feature-workflow/SKILL.md +61 -0
- package/.agent/monolith/skills/react-quality-review/SKILL.md +126 -0
- package/.agent/monolith/skills/react-quality-review/examples.md +24 -0
- package/.agent/monolith/skills/react-quality-review/rules/_sections.md +26 -0
- package/.agent/monolith/skills/react-quality-review/rules/_template.md +28 -0
- package/.agent/monolith/skills/react-quality-review/rules/advanced-event-handler-refs.md +55 -0
- package/.agent/monolith/skills/react-quality-review/rules/advanced-init-once.md +42 -0
- package/.agent/monolith/skills/react-quality-review/rules/react-rules-calling.md +66 -0
- package/.agent/monolith/skills/react-quality-review/rules/react-rules-hooks.md +91 -0
- package/.agent/monolith/skills/react-quality-review/rules/react-rules-purity.md +121 -0
- package/.agent/monolith/skills/react-quality-review/rules/rendering-activity.md +26 -0
- package/.agent/monolith/skills/react-quality-review/rules/rendering-conditional-render.md +40 -0
- package/.agent/monolith/skills/react-quality-review/rules/rendering-content-visibility.md +38 -0
- package/.agent/monolith/skills/react-quality-review/rules/rendering-hoist-jsx.md +46 -0
- package/.agent/monolith/skills/react-quality-review/rules/rendering-usetransition-loading.md +75 -0
- package/.agent/monolith/skills/react-quality-review/rules/rerender-defer-reads.md +39 -0
- package/.agent/monolith/skills/react-quality-review/rules/rerender-dependencies.md +45 -0
- package/.agent/monolith/skills/react-quality-review/rules/rerender-derived-state-no-effect.md +40 -0
- package/.agent/monolith/skills/react-quality-review/rules/rerender-derived-state.md +29 -0
- package/.agent/monolith/skills/react-quality-review/rules/rerender-functional-setstate.md +74 -0
- package/.agent/monolith/skills/react-quality-review/rules/rerender-lazy-state-init.md +58 -0
- package/.agent/monolith/skills/react-quality-review/rules/rerender-memo-with-default-value.md +38 -0
- package/.agent/monolith/skills/react-quality-review/rules/rerender-memo.md +44 -0
- package/.agent/monolith/skills/react-quality-review/rules/rerender-move-effect-to-event.md +45 -0
- package/.agent/monolith/skills/react-quality-review/rules/rerender-no-inline-components.md +82 -0
- package/.agent/monolith/skills/react-quality-review/rules/rerender-simple-expression-in-memo.md +35 -0
- package/.agent/monolith/skills/react-quality-review/rules/rerender-transitions.md +40 -0
- package/.agent/monolith/skills/react-quality-review/rules/rerender-use-ref-transient-values.md +73 -0
- package/.agent/monolith/skills/refactor-safely/SKILL.md +29 -0
- package/.agent/monolith/skills/vuexy-component-guide/SKILL.md +369 -0
- package/.agent/monolith/skills/vuexy-component-guide/examples.md +662 -0
- package/.agent/monolith/skills/vuexy-component-guide/reference.md +1036 -0
- package/.agent/monolith/workflows/add-new-api-feature-module.md +63 -0
- package/.agent/monolith/workflows/backend-quality-review.md +27 -0
- package/.agent/monolith/workflows/build-feature-backend.workflow.md +91 -0
- package/.agent/monolith/workflows/build-feature-react.workflow.md +82 -0
- package/.agent/monolith/workflows/feature-module-runner.md +97 -0
- package/.agent/templates/FEATURE_PLAN.md +42 -0
- package/.agent/templates/MODULE.md +45 -0
- package/.agent/templates/REVIEW_REPORT.md +44 -0
- package/.agent/templates/SECURITY_REPORT.md +70 -0
- package/.agent/templates/TEST_PLAN.md +49 -0
- package/README.md +131 -0
- package/package.json +42 -0
- package/scripts/setup-rules.js +224 -0
- package/scripts/setup.js +518 -0
|
@@ -0,0 +1,662 @@
|
|
|
1
|
+
# Vuexy Component Examples
|
|
2
|
+
|
|
3
|
+
Ready-to-use interface patterns from the codebase.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Example 1: Multi-Step Form (Stepper + Validation)
|
|
8
|
+
|
|
9
|
+
See `src/views/forms/form-wizard/StepperLinearWithValidation.tsx` for the full source.
|
|
10
|
+
|
|
11
|
+
### Pattern Overview
|
|
12
|
+
|
|
13
|
+
Each step has its own `useForm` instance with independent `valibotResolver`. Use `StepperCustomDot` from `@components/stepper-dot` as the step icon, wrapped in `StepperWrapper` from `@core/styles/stepper`.
|
|
14
|
+
|
|
15
|
+
### Components Used
|
|
16
|
+
|
|
17
|
+
- Stepper (styled), Step, StepLabel, MuiStepper (`@mui/material`)
|
|
18
|
+
- StepperCustomDot (`@components/stepper-dot`)
|
|
19
|
+
- StepperWrapper (`@core/styles/stepper`)
|
|
20
|
+
- CustomTextField (`@core/components/mui/TextField`)
|
|
21
|
+
- Grid, Card, CardContent, Button, Divider, Typography
|
|
22
|
+
|
|
23
|
+
### Key Pattern
|
|
24
|
+
|
|
25
|
+
```tsx
|
|
26
|
+
import { useState } from 'react'
|
|
27
|
+
import { Controller, useForm } from 'react-hook-form'
|
|
28
|
+
import { valibotResolver } from '@hookform/resolvers/valibot'
|
|
29
|
+
import { object, string, nonEmpty, minLength, pipe } from 'valibot'
|
|
30
|
+
import { styled } from '@mui/material/styles'
|
|
31
|
+
import MuiStepper from '@mui/material/Stepper'
|
|
32
|
+
import Step from '@mui/material/Step'
|
|
33
|
+
import StepLabel from '@mui/material/StepLabel'
|
|
34
|
+
import Grid from '@mui/material/Grid'
|
|
35
|
+
import Button from '@mui/material/Button'
|
|
36
|
+
import Card from '@mui/material/Card'
|
|
37
|
+
import CardContent from '@mui/material/CardContent'
|
|
38
|
+
import Divider from '@mui/material/Divider'
|
|
39
|
+
import CustomTextField from '@core/components/mui/TextField'
|
|
40
|
+
import StepperWrapper from '@core/styles/stepper'
|
|
41
|
+
import StepperCustomDot from '@components/stepper-dot'
|
|
42
|
+
import DirectionalIcon from '@components/DirectionalIcon'
|
|
43
|
+
|
|
44
|
+
const Stepper = styled(MuiStepper)(({ theme }) => ({
|
|
45
|
+
justifyContent: 'center',
|
|
46
|
+
'& .MuiStep-root': {
|
|
47
|
+
'&:first-of-type': { paddingInlineStart: 0 },
|
|
48
|
+
'&:last-of-type': { paddingInlineEnd: 0 }
|
|
49
|
+
}
|
|
50
|
+
}))
|
|
51
|
+
|
|
52
|
+
const steps = [
|
|
53
|
+
{ title: 'Account Details', subtitle: 'Enter your account details' },
|
|
54
|
+
{ title: 'Personal Info', subtitle: 'Setup Information' }
|
|
55
|
+
]
|
|
56
|
+
|
|
57
|
+
const schema = object({
|
|
58
|
+
email: pipe(string(), nonEmpty('This field is required'), minLength(1))
|
|
59
|
+
})
|
|
60
|
+
|
|
61
|
+
// Separate useForm per step
|
|
62
|
+
const { control, handleSubmit, formState: { errors } } = useForm({
|
|
63
|
+
resolver: valibotResolver(schema),
|
|
64
|
+
defaultValues: { email: '' }
|
|
65
|
+
})
|
|
66
|
+
|
|
67
|
+
// Form body
|
|
68
|
+
return (
|
|
69
|
+
<Card>
|
|
70
|
+
<CardContent>
|
|
71
|
+
<StepperWrapper>
|
|
72
|
+
<Stepper activeStep={activeStep}>
|
|
73
|
+
{steps.map((step, i) => (
|
|
74
|
+
<Step key={i}>
|
|
75
|
+
<StepLabel slots={{ stepIcon: StepperCustomDot }}>
|
|
76
|
+
<Typography className='step-number'>{`0${i + 1}`}</Typography>
|
|
77
|
+
<Typography className='step-title'>{step.title}</Typography>
|
|
78
|
+
<Typography>{step.subtitle}</Typography>
|
|
79
|
+
</StepLabel>
|
|
80
|
+
</Step>
|
|
81
|
+
))}
|
|
82
|
+
</Stepper>
|
|
83
|
+
</StepperWrapper>
|
|
84
|
+
</CardContent>
|
|
85
|
+
<Divider />
|
|
86
|
+
<CardContent>
|
|
87
|
+
{/* Render step content */}
|
|
88
|
+
</CardContent>
|
|
89
|
+
</Card>
|
|
90
|
+
)
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
---
|
|
94
|
+
|
|
95
|
+
## Example 2: Add/Edit User Dialog (Form in Dialog)
|
|
96
|
+
|
|
97
|
+
Used in `src/components/dialogs/add-edit-address/`, `src/components/dialogs/role-dialog/`, `src/views/apps/user/list/AddUserDrawer.tsx`.
|
|
98
|
+
|
|
99
|
+
### Components Used
|
|
100
|
+
|
|
101
|
+
- Dialog, DialogTitle, DialogContent, DialogActions
|
|
102
|
+
- CustomTextField, Grid, Button, Switch, FormControlLabel, Typography
|
|
103
|
+
- DialogCloseButton (`@/components/dialogs/DialogCloseButton`)
|
|
104
|
+
|
|
105
|
+
### Pattern
|
|
106
|
+
|
|
107
|
+
```tsx
|
|
108
|
+
'use client'
|
|
109
|
+
|
|
110
|
+
import { useState } from 'react'
|
|
111
|
+
import { Controller, useForm } from 'react-hook-form'
|
|
112
|
+
import { toast } from 'react-toastify'
|
|
113
|
+
import Dialog from '@mui/material/Dialog'
|
|
114
|
+
import DialogTitle from '@mui/material/DialogTitle'
|
|
115
|
+
import DialogContent from '@mui/material/DialogContent'
|
|
116
|
+
import DialogActions from '@mui/material/DialogActions'
|
|
117
|
+
import Button from '@mui/material/Button'
|
|
118
|
+
import Typography from '@mui/material/Typography'
|
|
119
|
+
import Grid from '@mui/material/Grid'
|
|
120
|
+
import CustomTextField from '@core/components/mui/TextField'
|
|
121
|
+
import Switch from '@mui/material/Switch'
|
|
122
|
+
import FormControlLabel from '@mui/material/FormControlLabel'
|
|
123
|
+
import MenuItem from '@mui/material/MenuItem'
|
|
124
|
+
import DialogCloseButton from '@/components/dialogs/DialogCloseButton'
|
|
125
|
+
|
|
126
|
+
export default function AddEditAddressDialog() {
|
|
127
|
+
const [open, setOpen] = useState(false)
|
|
128
|
+
|
|
129
|
+
const {
|
|
130
|
+
control,
|
|
131
|
+
handleSubmit,
|
|
132
|
+
formState: { errors },
|
|
133
|
+
reset
|
|
134
|
+
} = useForm({
|
|
135
|
+
defaultValues: { address: '', city: '', state: '', zip: '', checked: false }
|
|
136
|
+
})
|
|
137
|
+
|
|
138
|
+
const onSubmit = (data: any) => {
|
|
139
|
+
toast.success('Address saved')
|
|
140
|
+
setOpen(false)
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
return (
|
|
144
|
+
<>
|
|
145
|
+
<Button variant='contained' onClick={() => setOpen(true)}>Open Dialog</Button>
|
|
146
|
+
<Dialog open={open} onClose={() => setOpen(false)} fullWidth maxWidth='sm'>
|
|
147
|
+
<DialogTitle className='flex justify-between items-center'>
|
|
148
|
+
Add Address
|
|
149
|
+
<DialogCloseButton onClick={() => setOpen(false)} />
|
|
150
|
+
</DialogTitle>
|
|
151
|
+
<DialogContent className='overflow-visible pbs-0'>
|
|
152
|
+
<form onSubmit={handleSubmit(onSubmit)}>
|
|
153
|
+
<Grid container spacing={6}>
|
|
154
|
+
<Grid size={{ xs: 12 }}>
|
|
155
|
+
<Controller
|
|
156
|
+
name='address'
|
|
157
|
+
control={control}
|
|
158
|
+
rules={{ required: true }}
|
|
159
|
+
render={({ field }) => (
|
|
160
|
+
<CustomTextField
|
|
161
|
+
{...field}
|
|
162
|
+
fullWidth
|
|
163
|
+
label='Address Line'
|
|
164
|
+
{...(errors.address && { error: true, helperText: 'This field is required.' })}
|
|
165
|
+
/>
|
|
166
|
+
)}
|
|
167
|
+
/>
|
|
168
|
+
</Grid>
|
|
169
|
+
<Grid size={{ xs: 12, sm: 6 }}>
|
|
170
|
+
<Controller
|
|
171
|
+
name='city'
|
|
172
|
+
control={control}
|
|
173
|
+
rules={{ required: true }}
|
|
174
|
+
render={({ field }) => (
|
|
175
|
+
<CustomTextField {...field} fullWidth label='City' />
|
|
176
|
+
)}
|
|
177
|
+
/>
|
|
178
|
+
</Grid>
|
|
179
|
+
<Grid size={{ xs: 12, sm: 6 }}>
|
|
180
|
+
<Controller
|
|
181
|
+
name='state'
|
|
182
|
+
control={control}
|
|
183
|
+
rules={{ required: true }}
|
|
184
|
+
render={({ field }) => (
|
|
185
|
+
<CustomTextField
|
|
186
|
+
select
|
|
187
|
+
fullWidth
|
|
188
|
+
label='State'
|
|
189
|
+
{...field}
|
|
190
|
+
>
|
|
191
|
+
<MenuItem value='California'>California</MenuItem>
|
|
192
|
+
<MenuItem value='New York'>New York</MenuItem>
|
|
193
|
+
<MenuItem value='Texas'>Texas</MenuItem>
|
|
194
|
+
</CustomTextField>
|
|
195
|
+
)}
|
|
196
|
+
/>
|
|
197
|
+
</Grid>
|
|
198
|
+
<Grid size={{ xs: 12 }}>
|
|
199
|
+
<FormControlLabel control={<Switch />} label='Use as a billing address' />
|
|
200
|
+
</Grid>
|
|
201
|
+
</Grid>
|
|
202
|
+
</form>
|
|
203
|
+
</DialogContent>
|
|
204
|
+
<DialogActions className='dialog-actions-dense'>
|
|
205
|
+
<Button variant='tonal' color='secondary' onClick={() => { setOpen(false); reset() }}>Cancel</Button>
|
|
206
|
+
<Button variant='contained' onClick={handleSubmit(onSubmit)}>Submit</Button>
|
|
207
|
+
</DialogActions>
|
|
208
|
+
</Dialog>
|
|
209
|
+
</>
|
|
210
|
+
)
|
|
211
|
+
}
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
---
|
|
215
|
+
|
|
216
|
+
## Example 3: Role/Permission Dialog (Checkbox Groups)
|
|
217
|
+
|
|
218
|
+
Used in `src/components/dialogs/role-dialog/`, `src/components/dialogs/permission-dialog/`.
|
|
219
|
+
|
|
220
|
+
### Components Used
|
|
221
|
+
|
|
222
|
+
- Dialog, DialogTitle, DialogContent, DialogActions
|
|
223
|
+
- Checkbox, FormGroup, FormControlLabel
|
|
224
|
+
- Alert, AlertTitle
|
|
225
|
+
- Typography
|
|
226
|
+
|
|
227
|
+
### Pattern
|
|
228
|
+
|
|
229
|
+
```tsx
|
|
230
|
+
import Dialog from '@mui/material/Dialog'
|
|
231
|
+
import DialogTitle from '@mui/material/DialogTitle'
|
|
232
|
+
import DialogContent from '@mui/material/DialogContent'
|
|
233
|
+
import DialogActions from '@mui/material/DialogActions'
|
|
234
|
+
import Checkbox from '@mui/material/Checkbox'
|
|
235
|
+
import FormGroup from '@mui/material/FormGroup'
|
|
236
|
+
import FormControlLabel from '@mui/material/FormControlLabel'
|
|
237
|
+
import Alert from '@mui/material/Alert'
|
|
238
|
+
import AlertTitle from '@mui/material/AlertTitle'
|
|
239
|
+
import Button from '@mui/material/Button'
|
|
240
|
+
import Typography from '@mui/material/Typography'
|
|
241
|
+
|
|
242
|
+
const modulePermissions = {
|
|
243
|
+
'User Management': ['View', 'Add', 'Edit', 'Delete'],
|
|
244
|
+
'Content Management': ['View', 'Add', 'Edit', 'Publish'],
|
|
245
|
+
'Settings': ['View', 'Edit']
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
Object.entries(modulePermissions).map(([module, permissions]) => (
|
|
249
|
+
<div key={module} className='mbe-4'>
|
|
250
|
+
<Typography className='font-medium'>{module}</Typography>
|
|
251
|
+
<FormGroup>
|
|
252
|
+
{permissions.map(perm => (
|
|
253
|
+
<FormControlLabel
|
|
254
|
+
key={perm}
|
|
255
|
+
control={<Checkbox defaultChecked />}
|
|
256
|
+
label={perm}
|
|
257
|
+
/>
|
|
258
|
+
))}
|
|
259
|
+
</FormGroup>
|
|
260
|
+
</div>
|
|
261
|
+
))
|
|
262
|
+
|
|
263
|
+
<Alert severity='warning' className='mbs-6'>
|
|
264
|
+
<AlertTitle>Warning!</AlertTitle>
|
|
265
|
+
You cannot uncheck the "Read" permission, it is required for security.
|
|
266
|
+
</Alert>
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
---
|
|
270
|
+
|
|
271
|
+
## Example 4: Pricing Card with Switch
|
|
272
|
+
|
|
273
|
+
Used in `src/components/pricing/index.tsx`, `src/views/front-pages/pricing/`.
|
|
274
|
+
|
|
275
|
+
### Components Used
|
|
276
|
+
|
|
277
|
+
- Card, CardContent
|
|
278
|
+
- Chip (CustomChip)
|
|
279
|
+
- Button
|
|
280
|
+
- Typography
|
|
281
|
+
- Switch, FormControlLabel
|
|
282
|
+
- InputLabel, Grid
|
|
283
|
+
|
|
284
|
+
### Pattern
|
|
285
|
+
|
|
286
|
+
```tsx
|
|
287
|
+
'use client'
|
|
288
|
+
|
|
289
|
+
import { useState } from 'react'
|
|
290
|
+
import Grid from '@mui/material/Grid'
|
|
291
|
+
import Typography from '@mui/material/Typography'
|
|
292
|
+
import Switch from '@mui/material/Switch'
|
|
293
|
+
import InputLabel from '@mui/material/InputLabel'
|
|
294
|
+
import FormControlLabel from '@mui/material/FormControlLabel'
|
|
295
|
+
import Button from '@mui/material/Button'
|
|
296
|
+
import Chip from '@mui/material/Chip'
|
|
297
|
+
import CardContent from '@mui/material/CardContent'
|
|
298
|
+
|
|
299
|
+
const [isAnnual, setIsAnnual] = useState(true)
|
|
300
|
+
|
|
301
|
+
// Toggle switch
|
|
302
|
+
<Grid container spacing={4} className='mbe-12 items-center justify-center'>
|
|
303
|
+
<Grid size='auto'>
|
|
304
|
+
<InputLabel htmlFor='pricing'>Monthly</InputLabel>
|
|
305
|
+
</Grid>
|
|
306
|
+
<Grid size='auto'>
|
|
307
|
+
<Switch id='pricing' checked={isAnnual} onChange={() => setIsAnnual(!isAnnual)} />
|
|
308
|
+
</Grid>
|
|
309
|
+
<Grid size='auto'>
|
|
310
|
+
<InputLabel htmlFor='pricing'>Annually</InputLabel>
|
|
311
|
+
</Grid>
|
|
312
|
+
</Grid>
|
|
313
|
+
|
|
314
|
+
// Plan card
|
|
315
|
+
<CardContent>
|
|
316
|
+
<Typography variant='h5'>$29{isAnnual ? '/mo' : '/mo'}</Typography>
|
|
317
|
+
<Typography variant='body2' color='text.secondary'>
|
|
318
|
+
per user
|
|
319
|
+
</Typography>
|
|
320
|
+
<div className='mbs-4 mbe-6'>
|
|
321
|
+
<Chip label='Popular' color='primary' size='small' />
|
|
322
|
+
</div>
|
|
323
|
+
<Button fullWidth variant='contained'>
|
|
324
|
+
Get Started
|
|
325
|
+
</Button>
|
|
326
|
+
</CardContent>
|
|
327
|
+
```
|
|
328
|
+
|
|
329
|
+
---
|
|
330
|
+
|
|
331
|
+
## Example 5: Data Table with Selection
|
|
332
|
+
|
|
333
|
+
Used in `src/views/apps/invoice/list/InvoiceListTable.tsx`, `src/views/apps/ecommerce/customers/list/`.
|
|
334
|
+
|
|
335
|
+
### Components Used
|
|
336
|
+
|
|
337
|
+
- Card, CardContent
|
|
338
|
+
- Table, TableHead, TableBody, TableRow, TableCell
|
|
339
|
+
- Checkbox
|
|
340
|
+
- IconButton
|
|
341
|
+
- Tooltip
|
|
342
|
+
- Chip (CustomChip)
|
|
343
|
+
- Typography
|
|
344
|
+
- Button
|
|
345
|
+
- TablePagination
|
|
346
|
+
|
|
347
|
+
### Pattern
|
|
348
|
+
|
|
349
|
+
```tsx
|
|
350
|
+
const [selected, setSelected] = useState(new Set<number>())
|
|
351
|
+
const [selectAll, setSelectAll] = useState(false)
|
|
352
|
+
|
|
353
|
+
<Card>
|
|
354
|
+
<CardContent>
|
|
355
|
+
<Table>
|
|
356
|
+
<TableHead>
|
|
357
|
+
<TableRow>
|
|
358
|
+
<TableCell padding='checkbox'>
|
|
359
|
+
<Checkbox
|
|
360
|
+
checked={selectAll}
|
|
361
|
+
onChange={e => {
|
|
362
|
+
setSelectAll(e.target.checked)
|
|
363
|
+
if (e.target.checked) {
|
|
364
|
+
setSelected(new Set(invoices.map(i => i.id)))
|
|
365
|
+
} else {
|
|
366
|
+
setSelected(new Set())
|
|
367
|
+
}
|
|
368
|
+
}}
|
|
369
|
+
/>
|
|
370
|
+
</TableCell>
|
|
371
|
+
<TableCell>Invoice ID</TableCell>
|
|
372
|
+
<TableCell>Client</TableCell>
|
|
373
|
+
<TableCell>Status</TableCell>
|
|
374
|
+
<TableCell align='right'>Balance</TableCell>
|
|
375
|
+
<TableCell align='right'>Actions</TableCell>
|
|
376
|
+
</TableRow>
|
|
377
|
+
</TableHead>
|
|
378
|
+
<TableBody>
|
|
379
|
+
{invoices.map(invoice => (
|
|
380
|
+
<TableRow key={invoice.id} className={selected.has(invoice.id) ? 'selected' : ''}>
|
|
381
|
+
<TableCell padding='checkbox'>
|
|
382
|
+
<Checkbox
|
|
383
|
+
checked={selected.has(invoice.id)}
|
|
384
|
+
onChange={() => {
|
|
385
|
+
const newSelected = new Set(selected)
|
|
386
|
+
selected.has(invoice.id) ? newSelected.delete(invoice.id) : newSelected.add(invoice.id)
|
|
387
|
+
setSelected(newSelected)
|
|
388
|
+
}}
|
|
389
|
+
/>
|
|
390
|
+
</TableCell>
|
|
391
|
+
<TableCell>
|
|
392
|
+
<Typography color='text.primary'>
|
|
393
|
+
<Link href={`/apps/invoice/preview/${invoice.id}`}>#{invoice.id}</Link>
|
|
394
|
+
</Typography>
|
|
395
|
+
</TableCell>
|
|
396
|
+
<TableCell>{invoice.clientName}</TableCell>
|
|
397
|
+
<TableCell>
|
|
398
|
+
<CustomChip
|
|
399
|
+
round='true'
|
|
400
|
+
size='small'
|
|
401
|
+
skin='light'
|
|
402
|
+
color={invoice.status === 'Paid' ? 'success' : 'warning'}
|
|
403
|
+
label={invoice.status}
|
|
404
|
+
/>
|
|
405
|
+
</TableCell>
|
|
406
|
+
<TableCell align='right'>{invoice.balance}</TableCell>
|
|
407
|
+
<TableCell align='right'>
|
|
408
|
+
<Tooltip title='Send Mail'>
|
|
409
|
+
<IconButton onClick={() => handleSend(invoice.id)}>
|
|
410
|
+
<i className='tabler-mail' />
|
|
411
|
+
</IconButton>
|
|
412
|
+
</Tooltip>
|
|
413
|
+
<Tooltip title='Preview'>
|
|
414
|
+
<IconButton onClick={() => handlePreview(invoice.id)}>
|
|
415
|
+
<i className='tabler-eye' />
|
|
416
|
+
</IconButton>
|
|
417
|
+
</Tooltip>
|
|
418
|
+
<Tooltip title='Delete'>
|
|
419
|
+
<IconButton onClick={() => handleDelete(invoice.id)}>
|
|
420
|
+
<i className='tabler-trash' />
|
|
421
|
+
</IconButton>
|
|
422
|
+
</Tooltip>
|
|
423
|
+
</TableCell>
|
|
424
|
+
</TableRow>
|
|
425
|
+
))}
|
|
426
|
+
</TableBody>
|
|
427
|
+
</Table>
|
|
428
|
+
</CardContent>
|
|
429
|
+
<TablePagination
|
|
430
|
+
component='div'
|
|
431
|
+
count={totalItems}
|
|
432
|
+
page={page}
|
|
433
|
+
rowsPerPage={rowsPerPage}
|
|
434
|
+
onPageChange={(_, newPage) => setPage(newPage)}
|
|
435
|
+
onRowsPerPageChange={e => { setRowsPerPage(+e.target.value); setPage(0) }}
|
|
436
|
+
/>
|
|
437
|
+
</Card>
|
|
438
|
+
```
|
|
439
|
+
|
|
440
|
+
---
|
|
441
|
+
|
|
442
|
+
## Example 6: Stats Cards
|
|
443
|
+
|
|
444
|
+
Used across all dashboards.
|
|
445
|
+
|
|
446
|
+
```tsx
|
|
447
|
+
import CardStatsVertical from '@components/card-statistics/Vertical'
|
|
448
|
+
|
|
449
|
+
<Grid container spacing={6}>
|
|
450
|
+
<Grid size={{ xs: 12, sm: 6, md: 3 }}>
|
|
451
|
+
<CardStatsVertical
|
|
452
|
+
title='Total Revenue'
|
|
453
|
+
stats='$45.2K'
|
|
454
|
+
chipText='+18%'
|
|
455
|
+
chipType='success'
|
|
456
|
+
avatarIcon='tabler-currency-dollar'
|
|
457
|
+
avatarColor='primary'
|
|
458
|
+
/>
|
|
459
|
+
</Grid>
|
|
460
|
+
<Grid size={{ xs: 12, sm: 6, md: 3 }}>
|
|
461
|
+
<CardStatsVertical
|
|
462
|
+
title='Total Orders'
|
|
463
|
+
stats='1,234'
|
|
464
|
+
chipText='+6.2%'
|
|
465
|
+
chipType='success'
|
|
466
|
+
avatarIcon='tabler-shopping-cart'
|
|
467
|
+
avatarColor='info'
|
|
468
|
+
/>
|
|
469
|
+
</Grid>
|
|
470
|
+
</Grid>
|
|
471
|
+
```
|
|
472
|
+
|
|
473
|
+
---
|
|
474
|
+
|
|
475
|
+
## Example 7: Profile/Account Settings (Tabs + Forms)
|
|
476
|
+
|
|
477
|
+
```tsx
|
|
478
|
+
'use client'
|
|
479
|
+
|
|
480
|
+
import { useState } from 'react'
|
|
481
|
+
import TabContext from '@mui/lab/TabContext'
|
|
482
|
+
import TabPanel from '@mui/lab/TabPanel'
|
|
483
|
+
import Tab from '@mui/material/Tab'
|
|
484
|
+
import Grid from '@mui/material/Grid'
|
|
485
|
+
import Card from '@mui/material/Card'
|
|
486
|
+
import CardContent from '@mui/material/CardContent'
|
|
487
|
+
import CustomTabList from '@core/components/mui/TabList'
|
|
488
|
+
import CustomTextField from '@core/components/mui/TextField'
|
|
489
|
+
import CustomAvatar from '@core/components/mui/Avatar'
|
|
490
|
+
import Button from '@mui/material/Button'
|
|
491
|
+
import AvatarGroup from '@mui/material/AvatarGroup'
|
|
492
|
+
import Typography from '@mui/material/Typography'
|
|
493
|
+
import Chip from '@mui/material/Chip'
|
|
494
|
+
import Divider from '@mui/material/Divider'
|
|
495
|
+
|
|
496
|
+
export default function AccountSettings() {
|
|
497
|
+
const [tabValue, setTabValue] = useState('account')
|
|
498
|
+
|
|
499
|
+
return (
|
|
500
|
+
<TabContext value={tabValue}>
|
|
501
|
+
<Grid container spacing={6}>
|
|
502
|
+
<Grid size={12}>
|
|
503
|
+
<Card>
|
|
504
|
+
<CardContent>
|
|
505
|
+
<CustomTabList
|
|
506
|
+
onChange={(_, v) => setTabValue(v)}
|
|
507
|
+
variant='scrollable'
|
|
508
|
+
pill='true'
|
|
509
|
+
color='primary'
|
|
510
|
+
>
|
|
511
|
+
<Tab label='Account' value='account' />
|
|
512
|
+
<Tab label='Security' value='security' />
|
|
513
|
+
<Tab label='Billing' value='billing' />
|
|
514
|
+
</CustomTabList>
|
|
515
|
+
</CardContent>
|
|
516
|
+
</Card>
|
|
517
|
+
</Grid>
|
|
518
|
+
<Grid size={12}>
|
|
519
|
+
<TabPanel value='account'>
|
|
520
|
+
<Card>
|
|
521
|
+
<CardContent>
|
|
522
|
+
<form>
|
|
523
|
+
<Grid container spacing={6}>
|
|
524
|
+
<Grid size={{ xs: 12, sm: 6 }}>
|
|
525
|
+
<CustomTextField fullWidth label='First Name' placeholder='John' />
|
|
526
|
+
</Grid>
|
|
527
|
+
<Grid size={{ xs: 12, sm: 6 }}>
|
|
528
|
+
<CustomTextField fullWidth label='Last Name' placeholder='Doe' />
|
|
529
|
+
</Grid>
|
|
530
|
+
<Grid size={{ xs: 12 }}>
|
|
531
|
+
<Button variant='contained' type='submit'>Save Changes</Button>
|
|
532
|
+
</Grid>
|
|
533
|
+
</Grid>
|
|
534
|
+
</form>
|
|
535
|
+
</CardContent>
|
|
536
|
+
</Card>
|
|
537
|
+
</TabPanel>
|
|
538
|
+
</Grid>
|
|
539
|
+
</Grid>
|
|
540
|
+
</TabContext>
|
|
541
|
+
)
|
|
542
|
+
}
|
|
543
|
+
```
|
|
544
|
+
|
|
545
|
+
---
|
|
546
|
+
|
|
547
|
+
## Example 8: Timeline (@mui/lab)
|
|
548
|
+
|
|
549
|
+
```tsx
|
|
550
|
+
import Timeline from '@mui/lab/Timeline'
|
|
551
|
+
import TimelineItem from '@mui/lab/TimelineItem'
|
|
552
|
+
import TimelineSeparator from '@mui/lab/TimelineSeparator'
|
|
553
|
+
import TimelineConnector from '@mui/lab/TimelineConnector'
|
|
554
|
+
import TimelineContent from '@mui/lab/TimelineContent'
|
|
555
|
+
import TimelineDot from '@mui/lab/TimelineDot'
|
|
556
|
+
import Typography from '@mui/material/Typography'
|
|
557
|
+
|
|
558
|
+
<Timeline position='alternate'>
|
|
559
|
+
<TimelineItem>
|
|
560
|
+
<TimelineSeparator>
|
|
561
|
+
<TimelineDot color='primary' />
|
|
562
|
+
<TimelineConnector />
|
|
563
|
+
</TimelineSeparator>
|
|
564
|
+
<TimelineContent>
|
|
565
|
+
<Typography color='text.primary'>12 Invoices have been sent</Typography>
|
|
566
|
+
<Typography variant='body2' color='text.secondary'>01 Jan 2025</Typography>
|
|
567
|
+
</TimelineContent>
|
|
568
|
+
</TimelineItem>
|
|
569
|
+
</Timeline>
|
|
570
|
+
```
|
|
571
|
+
|
|
572
|
+
---
|
|
573
|
+
|
|
574
|
+
## Example 9: Two-Factor Auth Dialog
|
|
575
|
+
|
|
576
|
+
Used in `src/components/dialogs/two-factor-auth/`.
|
|
577
|
+
|
|
578
|
+
```tsx
|
|
579
|
+
import Alert from '@mui/material/Alert'
|
|
580
|
+
import AlertTitle from '@mui/material/AlertTitle'
|
|
581
|
+
import Grid from '@mui/material/Grid'
|
|
582
|
+
import Dialog from '@mui/material/Dialog'
|
|
583
|
+
import DialogTitle from '@mui/material/DialogTitle'
|
|
584
|
+
import DialogContent from '@mui/material/DialogContent'
|
|
585
|
+
import DialogActions from '@mui/material/DialogActions'
|
|
586
|
+
import Button from '@mui/material/Button'
|
|
587
|
+
import Typography from '@mui/material/Typography'
|
|
588
|
+
|
|
589
|
+
<Alert severity='info'>
|
|
590
|
+
<AlertTitle>Two-Factor Authentication</AlertTitle>
|
|
591
|
+
Add a secondary phone to get login notifications
|
|
592
|
+
</Alert>
|
|
593
|
+
|
|
594
|
+
<Dialog open={open} onClose={handleClose}>
|
|
595
|
+
<DialogTitle>Enable Two-Factor Authentication</DialogTitle>
|
|
596
|
+
<DialogContent>
|
|
597
|
+
<Alert severity='warning'>
|
|
598
|
+
After this process is complete, you will be required to enter a code each time you log in.
|
|
599
|
+
</Alert>
|
|
600
|
+
</DialogContent>
|
|
601
|
+
<DialogActions className='dialog-actions-dense'>
|
|
602
|
+
<Button variant='tonal' color='secondary' onClick={handleClose}>Cancel</Button>
|
|
603
|
+
<Button variant='contained'>Enable</Button>
|
|
604
|
+
</DialogActions>
|
|
605
|
+
</Dialog>
|
|
606
|
+
```
|
|
607
|
+
|
|
608
|
+
---
|
|
609
|
+
|
|
610
|
+
## Example 10: Responsive Design with useMediaQuery
|
|
611
|
+
|
|
612
|
+
```tsx
|
|
613
|
+
'use client'
|
|
614
|
+
|
|
615
|
+
import useMediaQuery from '@mui/material/useMediaQuery'
|
|
616
|
+
import { useTheme } from '@mui/material/styles'
|
|
617
|
+
|
|
618
|
+
const isSmallScreen = useMediaQuery(theme => theme.breakpoints.down('sm'))
|
|
619
|
+
const isMediumScreen = useMediaQuery(theme => theme.breakpoints.down('md'))
|
|
620
|
+
|
|
621
|
+
{isSmallScreen ? (
|
|
622
|
+
<VerticalLayout>
|
|
623
|
+
mobile-only content
|
|
624
|
+
</VerticalLayout>
|
|
625
|
+
) : (
|
|
626
|
+
<HorizontalLayout>
|
|
627
|
+
desktop content
|
|
628
|
+
</HorizontalLayout>
|
|
629
|
+
)}
|
|
630
|
+
```
|
|
631
|
+
|
|
632
|
+
---
|
|
633
|
+
|
|
634
|
+
## Quick Reference: Which Component for What?
|
|
635
|
+
|
|
636
|
+
| I need... | Use this | Import from |
|
|
637
|
+
|-----------|----------|-------------|
|
|
638
|
+
| Text input | `CustomTextField` | `@core/components/mui/TextField` |
|
|
639
|
+
| Dropdown select | `CustomTextField` with `select` + `MenuItem` | `@core/components/mui/TextField` + `@mui/material/MenuItem` |
|
|
640
|
+
| Number/Email/Password | `CustomTextField` with `type` prop | `@core/components/mui/TextField` |
|
|
641
|
+
| Date picker | `AppReactDatepicker` with `CustomTextField` as `customInput` | `@/libs/styles/AppReactDatepicker` |
|
|
642
|
+
| Avatar with color | `CustomAvatar` with `color` + `skin` | `@core/components/mui/Avatar` |
|
|
643
|
+
| Badge with light bg | `CustomBadge` with `tonal='true'` | `@core/components/mui/Badge` |
|
|
644
|
+
| Status label | `CustomChip` | `@core/components/mui/Chip` |
|
|
645
|
+
| Card container | `Card` + `CardHeader` + `CardContent` | `@mui/material/` |
|
|
646
|
+
| Dialog overlay | `Dialog` + `DialogTitle/Content/Actions` | `@mui/material/` |
|
|
647
|
+
| Slide-in panel | `Drawer` with `variant='temporary'` | `@mui/material/Drawer` |
|
|
648
|
+
| Tabs navigation | `TabContext` + `CustomTabList` + `TabPanel` | `@mui/lab` + `@core/components/mui/TabList` |
|
|
649
|
+
| Multi-step form | `Stepper` + `Step` + `StepLabel` | `@mui/material/` |
|
|
650
|
+
| Timeline | `Timeline` + `TimelineItem/Dot/Connector` | `@mui/lab/` |
|
|
651
|
+
| Alert message | `Alert` + `AlertTitle` | `@mui/material/` |
|
|
652
|
+
| Loading spinner | `CircularProgress` | `@mui/material/CircularProgress` |
|
|
653
|
+
| Toast notification | `toast.success()/error()/warning()` | `react-toastify` |
|
|
654
|
+
| Table rows | `Table` + `TableHead` + `TableBody` + `TableRow` + `TableCell` | `@mui/material/` |
|
|
655
|
+
| Pagination | `TablePagination` or `Pagination` | `@mui/material/` |
|
|
656
|
+
| Button (primary action) | `Button` with `variant='contained'` | `@mui/material/Button` |
|
|
657
|
+
| Button (secondary action) | `Button` with `variant='tonal'` | `@mui/material/Button` |
|
|
658
|
+
| Icon button | `IconButton` | `@mui/material/IconButton` |
|
|
659
|
+
| Tooltip | `Tooltip` with `title` + `arrow` | `@mui/material/Tooltip` |
|
|
660
|
+
| Grid layout | `Grid` with `size={{ xs: 12, sm: 6 }}` | `@mui/material/Grid` |
|
|
661
|
+
| Responsive check | `useMediaQuery(theme.breakpoints.down('sm'))` | `@mui/material/useMediaQuery` |
|
|
662
|
+
| Form with validation | `useForm` + `Controller` + `CustomTextField` | `react-hook-form` + valibot resolver + custom textfield |
|