nexstruct 1.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.
Files changed (229) hide show
  1. package/AGENTS.md +122 -0
  2. package/LICENSE +21 -0
  3. package/README.md +103 -0
  4. package/package.json +99 -0
  5. package/scaffold/generator.js +409 -0
  6. package/scaffold/index.js +20 -0
  7. package/scaffold/prompts.js +108 -0
  8. package/templates/api/axios/src/api/axios/client.api.ts +30 -0
  9. package/templates/api/axios/src/api/axios/users.api.ts +15 -0
  10. package/templates/api/fetch/src/api/fetch/client.api.ts +68 -0
  11. package/templates/api/fetch/src/api/fetch/users.api.ts +15 -0
  12. package/templates/api/trpc/src/api/trpc/client.api.ts +4 -0
  13. package/templates/api/trpc/src/api/trpc/router.api.ts +15 -0
  14. package/templates/api/trpc/src/api/trpc/server.client.api.ts +4 -0
  15. package/templates/api/trpc/src/providers/trpc.provider.tsx +24 -0
  16. package/templates/auth/clerk/src/auth/clerk/auth.service.ts +4 -0
  17. package/templates/auth/clerk/src/hooks/use-auth.hook.ts +13 -0
  18. package/templates/auth/clerk/src/middleware.ts +7 -0
  19. package/templates/auth/clerk/src/providers/auth.provider.tsx +6 -0
  20. package/templates/auth/next-auth/src/app/api/auth/[...nextauth]/route.ts +5 -0
  21. package/templates/auth/next-auth/src/auth/next-auth/auth.service.ts +45 -0
  22. package/templates/auth/next-auth/src/hooks/use-session.hook.ts +13 -0
  23. package/templates/auth/next-auth/src/providers/session.provider.tsx +6 -0
  24. package/templates/forms/formik/src/components/forms/login-form.component.tsx +30 -0
  25. package/templates/forms/formik/src/forms/formik/hooks/use-form-config.hook.ts +7 -0
  26. package/templates/forms/formik/src/forms/formik/schemas/example.schema.ts +8 -0
  27. package/templates/forms/react-hook-form/src/components/forms/login-form.component.tsx +27 -0
  28. package/templates/forms/react-hook-form/src/forms/react-hook-form/hooks/use-form.hook.ts +13 -0
  29. package/templates/forms/react-hook-form/src/forms/react-hook-form/schemas/example.schema.ts +15 -0
  30. package/templates/nextjs-base/next.config.ts +5 -0
  31. package/templates/nextjs-base/postcss.config.mjs +9 -0
  32. package/templates/nextjs-base/src/app/_components/navbar.tsx +88 -0
  33. package/templates/nextjs-base/src/app/_components/sidebar.tsx +223 -0
  34. package/templates/nextjs-base/src/app/error.tsx +39 -0
  35. package/templates/nextjs-base/src/app/globals.css +71 -0
  36. package/templates/nextjs-base/src/app/layout.tsx +21 -0
  37. package/templates/nextjs-base/src/app/loading.tsx +13 -0
  38. package/templates/nextjs-base/src/app/not-found.tsx +22 -0
  39. package/templates/nextjs-base/src/app/page.tsx +10 -0
  40. package/templates/nextjs-base/tailwind.config.ts +69 -0
  41. package/templates/shared/src/components/common/theme-toggle.component.tsx +31 -0
  42. package/templates/shared/src/components/common/toast/custom-message.component.tsx +18 -0
  43. package/templates/shared/src/components/common/toast/index.ts +8 -0
  44. package/templates/shared/src/components/common/toast/toast-message.component.tsx +112 -0
  45. package/templates/shared/src/hooks/use-debounce.hook.ts +12 -0
  46. package/templates/shared/src/hooks/use-fetch.hook.ts +42 -0
  47. package/templates/shared/src/hooks/use-intersection-observer.hook.ts +39 -0
  48. package/templates/shared/src/hooks/use-local-storage.hook.ts +30 -0
  49. package/templates/shared/src/hooks/use-media-query.hook.ts +26 -0
  50. package/templates/shared/src/hooks/use-toggle.hook.ts +12 -0
  51. package/templates/shared/src/lib/utils.util.ts +361 -0
  52. package/templates/shared/src/providers/theme.provider.tsx +17 -0
  53. package/templates/shared/src/providers/toast.provider.tsx +32 -0
  54. package/templates/shared/src/types/common.type.ts +34 -0
  55. package/templates/state/context/src/store/context/auth.context.tsx +47 -0
  56. package/templates/state/context/src/store/context/counter.context.tsx +41 -0
  57. package/templates/state/context/src/store/context/index.ts +2 -0
  58. package/templates/state/redux/src/providers/redux.provider.tsx +7 -0
  59. package/templates/state/redux/src/store/redux/hooks.store.ts +5 -0
  60. package/templates/state/redux/src/store/redux/index.ts +4 -0
  61. package/templates/state/redux/src/store/redux/slices/api.slice.ts +8 -0
  62. package/templates/state/redux/src/store/redux/slices/counter.slice.ts +24 -0
  63. package/templates/state/redux/src/store/redux/store.store.ts +13 -0
  64. package/templates/state/zustand/src/store/zustand/counter.store.ts +15 -0
  65. package/templates/state/zustand/src/store/zustand/index.ts +2 -0
  66. package/templates/state/zustand/src/store/zustand/user.store.ts +32 -0
  67. package/templates/ui/antd/COMPONENT_GUIDE.md +326 -0
  68. package/templates/ui/antd/src/app/examples/dialog/page.tsx +205 -0
  69. package/templates/ui/antd/src/app/examples/form/page.tsx +160 -0
  70. package/templates/ui/antd/src/app/examples/layout.tsx +125 -0
  71. package/templates/ui/antd/src/app/examples/page.tsx +64 -0
  72. package/templates/ui/antd/src/app/examples/table/page.tsx +118 -0
  73. package/templates/ui/antd/src/app/page.tsx +283 -0
  74. package/templates/ui/antd/src/components/common/DynamicTable/dynamic-table.component.tsx +79 -0
  75. package/templates/ui/antd/src/components/common/button/action-button.component.tsx +63 -0
  76. package/templates/ui/antd/src/components/common/dialog/dialog-wrapper.component.tsx +63 -0
  77. package/templates/ui/antd/src/components/common/fields/assets/components/check-field.component.tsx +55 -0
  78. package/templates/ui/antd/src/components/common/fields/assets/components/date-picker-field.component.tsx +80 -0
  79. package/templates/ui/antd/src/components/common/fields/assets/components/limit-field.component.tsx +26 -0
  80. package/templates/ui/antd/src/components/common/fields/assets/components/multi-check-field.component.tsx +56 -0
  81. package/templates/ui/antd/src/components/common/fields/assets/components/number-field.component.tsx +100 -0
  82. package/templates/ui/antd/src/components/common/fields/assets/components/otp-field.component.tsx +63 -0
  83. package/templates/ui/antd/src/components/common/fields/assets/components/password-field.component.tsx +106 -0
  84. package/templates/ui/antd/src/components/common/fields/assets/components/phone-number-field.component.tsx +78 -0
  85. package/templates/ui/antd/src/components/common/fields/assets/components/radio-field.component.tsx +55 -0
  86. package/templates/ui/antd/src/components/common/fields/assets/components/range-date-picker.component.tsx +66 -0
  87. package/templates/ui/antd/src/components/common/fields/assets/components/search-field.component.tsx +24 -0
  88. package/templates/ui/antd/src/components/common/fields/assets/components/select-field.component.tsx +82 -0
  89. package/templates/ui/antd/src/components/common/fields/assets/components/single-check-field.component.tsx +50 -0
  90. package/templates/ui/antd/src/components/common/fields/assets/components/single-select-field.component.tsx +86 -0
  91. package/templates/ui/antd/src/components/common/fields/assets/components/string-number-field.component.tsx +80 -0
  92. package/templates/ui/antd/src/components/common/fields/assets/components/switch-field.component.tsx +62 -0
  93. package/templates/ui/antd/src/components/common/fields/assets/components/text-area-field.component.tsx +85 -0
  94. package/templates/ui/antd/src/components/common/fields/assets/components/text-field.component.tsx +88 -0
  95. package/templates/ui/antd/src/components/common/fields/assets/interface/input-props.type.ts +233 -0
  96. package/templates/ui/antd/src/components/common/fields/cusInputField.component.tsx +40 -0
  97. package/templates/ui/antd/src/components/common/pagination/pagination.component.tsx +27 -0
  98. package/templates/ui/antd/src/components/ui/avatar.component.tsx +8 -0
  99. package/templates/ui/antd/src/components/ui/badge.component.tsx +8 -0
  100. package/templates/ui/antd/src/components/ui/button.component.tsx +8 -0
  101. package/templates/ui/antd/src/components/ui/card.component.tsx +8 -0
  102. package/templates/ui/antd/src/components/ui/checkbox.component.tsx +8 -0
  103. package/templates/ui/antd/src/components/ui/dialog.component.tsx +9 -0
  104. package/templates/ui/antd/src/components/ui/dropdown-menu.component.tsx +10 -0
  105. package/templates/ui/antd/src/components/ui/form.component.tsx +12 -0
  106. package/templates/ui/antd/src/components/ui/input.component.tsx +13 -0
  107. package/templates/ui/antd/src/components/ui/label.component.tsx +18 -0
  108. package/templates/ui/antd/src/components/ui/popover.component.tsx +8 -0
  109. package/templates/ui/antd/src/components/ui/progress.component.tsx +8 -0
  110. package/templates/ui/antd/src/components/ui/radio-group.component.tsx +10 -0
  111. package/templates/ui/antd/src/components/ui/scroll-area.component.tsx +25 -0
  112. package/templates/ui/antd/src/components/ui/select.component.tsx +8 -0
  113. package/templates/ui/antd/src/components/ui/separator.component.tsx +8 -0
  114. package/templates/ui/antd/src/components/ui/sheet.component.tsx +8 -0
  115. package/templates/ui/antd/src/components/ui/switch.component.tsx +8 -0
  116. package/templates/ui/antd/src/components/ui/table.component.tsx +8 -0
  117. package/templates/ui/antd/src/components/ui/tabs.component.tsx +8 -0
  118. package/templates/ui/antd/src/components/ui/textarea.component.tsx +9 -0
  119. package/templates/ui/antd/src/components/ui/tooltip.component.tsx +8 -0
  120. package/templates/ui/antd/src/lib/theme.util.ts +40 -0
  121. package/templates/ui/antd/src/providers/antd.provider.tsx +13 -0
  122. package/templates/ui/mui/src/app/examples/layout.tsx +113 -0
  123. package/templates/ui/mui/src/app/examples/page.tsx +716 -0
  124. package/templates/ui/mui/src/app/page.tsx +298 -0
  125. package/templates/ui/mui/src/components/common/DynamicTable/dynamic-table.component.tsx +131 -0
  126. package/templates/ui/mui/src/components/common/button/action-button.component.tsx +57 -0
  127. package/templates/ui/mui/src/components/common/dialog/dialog-wrapper.component.tsx +55 -0
  128. package/templates/ui/mui/src/components/common/fields/assets/components/check-field.component.tsx +51 -0
  129. package/templates/ui/mui/src/components/common/fields/assets/components/date-picker-field.component.tsx +50 -0
  130. package/templates/ui/mui/src/components/common/fields/assets/components/multi-check-field.component.tsx +14 -0
  131. package/templates/ui/mui/src/components/common/fields/assets/components/number-field.component.tsx +59 -0
  132. package/templates/ui/mui/src/components/common/fields/assets/components/password-field.component.tsx +87 -0
  133. package/templates/ui/mui/src/components/common/fields/assets/components/phone-number-field.component.tsx +48 -0
  134. package/templates/ui/mui/src/components/common/fields/assets/components/radio-field.component.tsx +37 -0
  135. package/templates/ui/mui/src/components/common/fields/assets/components/search-field.component.tsx +41 -0
  136. package/templates/ui/mui/src/components/common/fields/assets/components/select-field.component.tsx +77 -0
  137. package/templates/ui/mui/src/components/common/fields/assets/components/single-check-field.component.tsx +39 -0
  138. package/templates/ui/mui/src/components/common/fields/assets/components/single-select-field.component.tsx +56 -0
  139. package/templates/ui/mui/src/components/common/fields/assets/components/string-number-field.component.tsx +52 -0
  140. package/templates/ui/mui/src/components/common/fields/assets/components/switch-field.component.tsx +35 -0
  141. package/templates/ui/mui/src/components/common/fields/assets/components/text-area-field.component.tsx +46 -0
  142. package/templates/ui/mui/src/components/common/fields/assets/components/text-field.component.tsx +51 -0
  143. package/templates/ui/mui/src/components/common/fields/assets/interface/input-props.type.ts +193 -0
  144. package/templates/ui/mui/src/components/common/fields/cusInputField.component.tsx +34 -0
  145. package/templates/ui/mui/src/components/common/pagination/pagination.component.tsx +59 -0
  146. package/templates/ui/mui/src/components/ui/avatar.component.tsx +19 -0
  147. package/templates/ui/mui/src/components/ui/badge.component.tsx +18 -0
  148. package/templates/ui/mui/src/components/ui/button.component.tsx +22 -0
  149. package/templates/ui/mui/src/components/ui/card.component.tsx +39 -0
  150. package/templates/ui/mui/src/components/ui/checkbox.component.tsx +21 -0
  151. package/templates/ui/mui/src/components/ui/dialog.component.tsx +38 -0
  152. package/templates/ui/mui/src/components/ui/dropdown-menu.component.tsx +43 -0
  153. package/templates/ui/mui/src/components/ui/form.component.tsx +98 -0
  154. package/templates/ui/mui/src/components/ui/input.component.tsx +15 -0
  155. package/templates/ui/mui/src/components/ui/label.component.tsx +15 -0
  156. package/templates/ui/mui/src/components/ui/popover.component.tsx +20 -0
  157. package/templates/ui/mui/src/components/ui/progress.component.tsx +19 -0
  158. package/templates/ui/mui/src/components/ui/radio-group.component.tsx +25 -0
  159. package/templates/ui/mui/src/components/ui/scroll-area.component.tsx +27 -0
  160. package/templates/ui/mui/src/components/ui/select.component.tsx +26 -0
  161. package/templates/ui/mui/src/components/ui/separator.component.tsx +11 -0
  162. package/templates/ui/mui/src/components/ui/sheet.component.tsx +44 -0
  163. package/templates/ui/mui/src/components/ui/switch.component.tsx +23 -0
  164. package/templates/ui/mui/src/components/ui/table.component.tsx +34 -0
  165. package/templates/ui/mui/src/components/ui/tabs.component.tsx +38 -0
  166. package/templates/ui/mui/src/components/ui/textarea.component.tsx +18 -0
  167. package/templates/ui/mui/src/components/ui/tooltip.component.tsx +24 -0
  168. package/templates/ui/mui/src/lib/theme.util.ts +73 -0
  169. package/templates/ui/mui/src/providers/mui.provider.tsx +13 -0
  170. package/templates/ui/shadcn/COMPONENT_GUIDE.md +306 -0
  171. package/templates/ui/shadcn/src/app/examples/dialog/page.tsx +122 -0
  172. package/templates/ui/shadcn/src/app/examples/form/page.tsx +107 -0
  173. package/templates/ui/shadcn/src/app/examples/layout.tsx +24 -0
  174. package/templates/ui/shadcn/src/app/examples/page.tsx +30 -0
  175. package/templates/ui/shadcn/src/app/examples/table/page.tsx +77 -0
  176. package/templates/ui/shadcn/src/app/page.tsx +20 -0
  177. package/templates/ui/shadcn/src/components/common/DynamicTable/dynamic-table.component.tsx +136 -0
  178. package/templates/ui/shadcn/src/components/common/button/action-button.component.tsx +68 -0
  179. package/templates/ui/shadcn/src/components/common/dialog/dialog-wrapper.component.tsx +58 -0
  180. package/templates/ui/shadcn/src/components/common/fields/assets/components/check-field.component.tsx +52 -0
  181. package/templates/ui/shadcn/src/components/common/fields/assets/components/date-picker-field.component.tsx +62 -0
  182. package/templates/ui/shadcn/src/components/common/fields/assets/components/dynamic-file-upload-field.component.tsx +152 -0
  183. package/templates/ui/shadcn/src/components/common/fields/assets/components/limit-field.component.tsx +73 -0
  184. package/templates/ui/shadcn/src/components/common/fields/assets/components/multi-check-field.component.tsx +46 -0
  185. package/templates/ui/shadcn/src/components/common/fields/assets/components/number-field.component.tsx +124 -0
  186. package/templates/ui/shadcn/src/components/common/fields/assets/components/otp-field.component.tsx +61 -0
  187. package/templates/ui/shadcn/src/components/common/fields/assets/components/password-field.component.tsx +110 -0
  188. package/templates/ui/shadcn/src/components/common/fields/assets/components/phone-number-field.component.tsx +90 -0
  189. package/templates/ui/shadcn/src/components/common/fields/assets/components/radio-field.component.tsx +41 -0
  190. package/templates/ui/shadcn/src/components/common/fields/assets/components/range-date-picker.component.tsx +71 -0
  191. package/templates/ui/shadcn/src/components/common/fields/assets/components/rich-text-editor.component.tsx +91 -0
  192. package/templates/ui/shadcn/src/components/common/fields/assets/components/search-field.component.tsx +34 -0
  193. package/templates/ui/shadcn/src/components/common/fields/assets/components/select-field.component.tsx +231 -0
  194. package/templates/ui/shadcn/src/components/common/fields/assets/components/single-check-field.component.tsx +42 -0
  195. package/templates/ui/shadcn/src/components/common/fields/assets/components/single-select-field.component.tsx +82 -0
  196. package/templates/ui/shadcn/src/components/common/fields/assets/components/string-number-field.component.tsx +68 -0
  197. package/templates/ui/shadcn/src/components/common/fields/assets/components/switch-field.component.tsx +61 -0
  198. package/templates/ui/shadcn/src/components/common/fields/assets/components/text-area-field.component.tsx +62 -0
  199. package/templates/ui/shadcn/src/components/common/fields/assets/components/text-area-with-file.component.tsx +142 -0
  200. package/templates/ui/shadcn/src/components/common/fields/assets/components/text-field.component.tsx +80 -0
  201. package/templates/ui/shadcn/src/components/common/fields/assets/components/tiny-editor.component.tsx +51 -0
  202. package/templates/ui/shadcn/src/components/common/fields/assets/components/upload-profile-picture.component.tsx +103 -0
  203. package/templates/ui/shadcn/src/components/common/fields/assets/components/upload-video-file.component.tsx +86 -0
  204. package/templates/ui/shadcn/src/components/common/fields/assets/interface/input-props.type.ts +198 -0
  205. package/templates/ui/shadcn/src/components/common/fields/cusInputField.component.tsx +52 -0
  206. package/templates/ui/shadcn/src/components/common/pagination/pagination.component.tsx +68 -0
  207. package/templates/ui/shadcn/src/components/ui/avatar.component.tsx +37 -0
  208. package/templates/ui/shadcn/src/components/ui/badge.component.tsx +28 -0
  209. package/templates/ui/shadcn/src/components/ui/button.component.tsx +52 -0
  210. package/templates/ui/shadcn/src/components/ui/card.component.tsx +46 -0
  211. package/templates/ui/shadcn/src/components/ui/checkbox.component.tsx +25 -0
  212. package/templates/ui/shadcn/src/components/ui/dialog.component.tsx +98 -0
  213. package/templates/ui/shadcn/src/components/ui/dropdown-menu.component.tsx +163 -0
  214. package/templates/ui/shadcn/src/components/ui/form.component.tsx +110 -0
  215. package/templates/ui/shadcn/src/components/ui/input-otp.component.tsx +64 -0
  216. package/templates/ui/shadcn/src/components/ui/input.component.tsx +23 -0
  217. package/templates/ui/shadcn/src/components/ui/label.component.tsx +23 -0
  218. package/templates/ui/shadcn/src/components/ui/popover.component.tsx +27 -0
  219. package/templates/ui/shadcn/src/components/ui/progress.component.tsx +22 -0
  220. package/templates/ui/shadcn/src/components/ui/radio-group.component.tsx +33 -0
  221. package/templates/ui/shadcn/src/components/ui/scroll-area.component.tsx +37 -0
  222. package/templates/ui/shadcn/src/components/ui/select.component.tsx +139 -0
  223. package/templates/ui/shadcn/src/components/ui/separator.component.tsx +23 -0
  224. package/templates/ui/shadcn/src/components/ui/sheet.component.tsx +89 -0
  225. package/templates/ui/shadcn/src/components/ui/switch.component.tsx +26 -0
  226. package/templates/ui/shadcn/src/components/ui/table.component.tsx +71 -0
  227. package/templates/ui/shadcn/src/components/ui/tabs.component.tsx +52 -0
  228. package/templates/ui/shadcn/src/components/ui/textarea.component.tsx +20 -0
  229. package/templates/ui/shadcn/src/components/ui/tooltip.component.tsx +25 -0
@@ -0,0 +1,716 @@
1
+ 'use client';
2
+
3
+ import { useState, useEffect } from 'react';
4
+ import { useForm } from 'react-hook-form';
5
+ import { zodResolver } from '@hookform/resolvers/zod';
6
+ import { z } from 'zod';
7
+
8
+ import Box from '@mui/material/Box';
9
+ import Typography from '@mui/material/Typography';
10
+ import Container from '@mui/material/Container';
11
+ import Grid from '@mui/material/Grid';
12
+ import Chip from '@mui/material/Chip';
13
+ import TextField from '@mui/material/TextField';
14
+ import Select from '@mui/material/Select';
15
+ import MenuItem from '@mui/material/MenuItem';
16
+ import FormControl from '@mui/material/FormControl';
17
+ import InputLabel from '@mui/material/InputLabel';
18
+ import Slider from '@mui/material/Slider';
19
+ import LinearProgress from '@mui/material/LinearProgress';
20
+ import Badge from '@mui/material/Badge';
21
+ import IconButton from '@mui/material/IconButton';
22
+ import Avatar from '@mui/material/Avatar';
23
+ import AvatarGroup from '@mui/material/AvatarGroup';
24
+ import Tooltip from '@mui/material/Tooltip';
25
+ import Paper from '@mui/material/Paper';
26
+ import Divider from '@mui/material/Divider';
27
+ import Table from '@mui/material/Table';
28
+ import TableBody from '@mui/material/TableBody';
29
+ import TableCell from '@mui/material/TableCell';
30
+ import TableContainer from '@mui/material/TableContainer';
31
+ import TableHead from '@mui/material/TableHead';
32
+ import TableRow from '@mui/material/TableRow';
33
+ import Checkbox from '@mui/material/Checkbox';
34
+ import Switch from '@mui/material/Switch';
35
+ import FormControlLabel from '@mui/material/FormControlLabel';
36
+ import Radio from '@mui/material/Radio';
37
+ import RadioGroup from '@mui/material/RadioGroup';
38
+ import FormLabel from '@mui/material/FormLabel';
39
+ import CircularProgress from '@mui/material/CircularProgress';
40
+ import Button from '@mui/material/Button';
41
+ import ButtonGroup from '@mui/material/ButtonGroup';
42
+ import Card from '@mui/material/Card';
43
+ import CardContent from '@mui/material/CardContent';
44
+ import CardActions from '@mui/material/CardActions';
45
+ import Dialog from '@mui/material/Dialog';
46
+ import DialogTitle from '@mui/material/DialogTitle';
47
+ import DialogContent from '@mui/material/DialogContent';
48
+ import DialogActions from '@mui/material/DialogActions';
49
+ import DialogContentText from '@mui/material/DialogContentText';
50
+ import Tabs from '@mui/material/Tabs';
51
+ import Tab from '@mui/material/Tab';
52
+ import Alert from '@mui/material/Alert';
53
+ import AlertTitle from '@mui/material/AlertTitle';
54
+ import Snackbar from '@mui/material/Snackbar';
55
+ import Skeleton from '@mui/material/Skeleton';
56
+ import Rating from '@mui/material/Rating';
57
+ import Stack from '@mui/material/Stack';
58
+ import Fab from '@mui/material/Fab';
59
+ import SpeedDial from '@mui/material/SpeedDial';
60
+ import SpeedDialIcon from '@mui/material/SpeedDialIcon';
61
+ import SpeedDialAction from '@mui/material/SpeedDialAction';
62
+ import Breadcrumbs from '@mui/material/Breadcrumbs';
63
+ import Link from '@mui/material/Link';
64
+
65
+ import AddIcon from '@mui/icons-material/Add';
66
+ import EditIcon from '@mui/icons-material/Edit';
67
+ import DeleteIcon from '@mui/icons-material/Delete';
68
+ import InfoIcon from '@mui/icons-material/Info';
69
+ import SettingsIcon from '@mui/icons-material/Settings';
70
+ import FavoriteIcon from '@mui/icons-material/Favorite';
71
+ import ShareIcon from '@mui/icons-material/Share';
72
+ import SendIcon from '@mui/icons-material/Send';
73
+ import SaveIcon from '@mui/icons-material/Save';
74
+ import CloudUploadIcon from '@mui/icons-material/CloudUpload';
75
+ import NotificationsIcon from '@mui/icons-material/Notifications';
76
+ import HomeIcon from '@mui/icons-material/Home';
77
+ import ArrowForwardIcon from '@mui/icons-material/ArrowForward';
78
+
79
+ const sections = [
80
+ { id: 'overview', label: 'Overview' },
81
+ { id: 'buttons', label: 'Buttons' },
82
+ { id: 'inputs', label: 'Inputs' },
83
+ { id: 'displays', label: 'Display' },
84
+ { id: 'feedback', label: 'Feedback' },
85
+ { id: 'table', label: 'Table' },
86
+ { id: 'form', label: 'Form' },
87
+ { id: 'common', label: 'Common' },
88
+ ];
89
+
90
+ const sampleData = Array.from({ length: 40 }, (_, i) => ({
91
+ id: String(i + 1), name: `User ${i + 1}`,
92
+ email: `user${i + 1}@example.com`,
93
+ role: ['Admin', 'Editor', 'Viewer'][i % 3],
94
+ status: ['Active', 'Inactive'][i % 2],
95
+ }));
96
+
97
+ const formSchema = z.object({
98
+ fullName: z.string().min(2, 'Name must be at least 2 characters'),
99
+ email: z.string().email('Invalid email'),
100
+ age: z.coerce.number().min(18, 'Must be 18+').max(120),
101
+ bio: z.string().optional(),
102
+ });
103
+
104
+ export default function ShowcasePage() {
105
+ const [activeTab, setActiveTab] = useState(0);
106
+ const [activeSection, setActiveSection] = useState('overview');
107
+ const [dialogOpen, setDialogOpen] = useState(false);
108
+ const [snackOpen, setSnackOpen] = useState(false);
109
+ const [progress, setProgress] = useState(30);
110
+ const [sliderVal, setSliderVal] = useState(50);
111
+ const [switchOn, setSwitchOn] = useState(false);
112
+ const [tableLoading, setTableLoading] = useState(false);
113
+ const [tablePage, setTablePage] = useState(1);
114
+ const [selectedIds, setSelectedIds] = useState<string[]>([]);
115
+ const [speedDialOpen, setSpeedDialOpen] = useState(false);
116
+ const perPage = 6;
117
+ const totalPages = Math.ceil(sampleData.length / perPage);
118
+ const paginatedData = sampleData.slice((tablePage - 1) * perPage, tablePage * perPage);
119
+
120
+ useEffect(() => {
121
+ const timer = setInterval(() => setProgress((old) => old >= 100 ? 0 : old + 10), 800);
122
+ return () => clearInterval(timer);
123
+ }, []);
124
+
125
+ const tableConfig = {
126
+ columns: [
127
+ { key: 'name', header: 'Name' },
128
+ { key: 'email', header: 'Email' },
129
+ {
130
+ key: 'role', header: 'Role',
131
+ render: (item: any) => (
132
+ <Chip label={item.role} size="small" color={item.role === 'Admin' ? 'primary' : item.role === 'Editor' ? 'warning' : 'default'} />
133
+ ),
134
+ },
135
+ {
136
+ key: 'status', header: 'Status',
137
+ render: (item: any) => (
138
+ <Chip label={item.status} size="small" color={item.status === 'Active' ? 'success' : 'default'} variant="outlined" />
139
+ ),
140
+ },
141
+ ],
142
+ emptyMessage: 'No users found',
143
+ };
144
+
145
+ const form = useForm({ resolver: zodResolver(formSchema), defaultValues: { fullName: '', email: '', age: 18, bio: '' } });
146
+
147
+ const isRowSelected = (id: string) => selectedIds.includes(id);
148
+ const toggleRow = (id: string) => setSelectedIds((prev) => prev.includes(id) ? prev.filter((x) => x !== id) : [...prev, id]);
149
+ const toggleAll = () => setSelectedIds((prev) => prev.length === paginatedData.length ? [] : paginatedData.map((x) => x.id));
150
+
151
+ const scrollTo = (id: string) => {
152
+ setActiveSection(id);
153
+ document.getElementById(id)?.scrollIntoView({ behavior: 'smooth' });
154
+ };
155
+
156
+ const sectionHeader = (title: string, subtitle?: string) => (
157
+ <Box sx={{ mb: 4, textAlign: 'center' }}>
158
+ <Typography variant="h4" fontWeight={800} gutterBottom sx={{ background: 'linear-gradient(135deg, primary.main, secondary.main)', WebkitBackgroundClip: 'text', WebkitTextFillColor: 'transparent' }}>
159
+ {title}
160
+ </Typography>
161
+ {subtitle && <Typography variant="body1" color="text.secondary" sx={{ maxWidth: 600, mx: 'auto' }}>{subtitle}</Typography>}
162
+ <Divider sx={{ mt: 2, maxWidth: 80, mx: 'auto', borderWidth: 2, borderColor: 'primary.main', borderRadius: 2 }} />
163
+ </Box>
164
+ );
165
+
166
+ const demoCard = (children: React.ReactNode, label?: string) => (
167
+ <Card variant="outlined" sx={{ height: '100%', transition: 'all 0.2s', '&:hover': { boxShadow: 4, borderColor: 'primary.light' } }}>
168
+ {label && <Box sx={{ px: 2, pt: 1.5, pb: 0.5 }}><Chip label={label} size="small" color="primary" variant="outlined" /></Box>}
169
+ <CardContent sx={{ display: 'flex', flexWrap: 'wrap', gap: 1.5, alignItems: 'center' }}>
170
+ {children}
171
+ </CardContent>
172
+ </Card>
173
+ );
174
+
175
+ return (
176
+ <Box sx={{ minHeight: '100vh', bgcolor: 'background.default' }}>
177
+ {/* Sticky Nav */}
178
+ <Box sx={{ position: 'sticky', top: 0, zIndex: 100, bgcolor: 'background.paper', borderBottom: 1, borderColor: 'divider', backdropFilter: 'blur(12px)', transition: 'all 0.3s' }}>
179
+ <Container maxWidth="xl" sx={{ display: 'flex', alignItems: 'center', height: 64, gap: 0.5, overflow: 'auto', '&::-webkit-scrollbar': { display: 'none' } }}>
180
+ <Typography variant="subtitle2" fontWeight={700} sx={{ mr: 2, whiteSpace: 'nowrap', background: 'linear-gradient(135deg, #2563eb, #7c3aed)', WebkitBackgroundClip: 'text', WebkitTextFillColor: 'transparent' }}>
181
+ MUI Showcase
182
+ </Typography>
183
+ <Chip label="Material UI" size="small" color="primary" sx={{ mr: 2, fontWeight: 600 }} />
184
+ <Box sx={{ display: 'flex', gap: 0.5 }}>
185
+ {sections.map((s) => (
186
+ <Button key={s.id} size="small" variant={activeSection === s.id ? 'contained' : 'text'} onClick={() => scrollTo(s.id)} sx={{ minWidth: 'auto', px: 1.5, fontSize: '0.75rem', whiteSpace: 'nowrap' }}>
187
+ {s.label}
188
+ </Button>
189
+ ))}
190
+ </Box>
191
+ </Container>
192
+ </Box>
193
+
194
+ {/* Hero */}
195
+ <Box sx={{ background: 'linear-gradient(135deg, #1e3a5f 0%, #2563eb 50%, #7c3aed 100%)', color: 'white', py: { xs: 8, md: 12 } }}>
196
+ <Container maxWidth="md" sx={{ textAlign: 'center' }}>
197
+ <Chip label="Material UI Component System" size="small" sx={{ color: 'white', borderColor: 'rgba(255,255,255,0.4)', mb: 3, fontWeight: 600, backdropFilter: 'blur(8px)', bgcolor: 'rgba(255,255,255,0.1)' }} />
198
+ <Typography variant="h2" fontWeight={800} sx={{ fontSize: { xs: '2rem', md: '3.5rem' }, lineHeight: 1.2 }}>Beautiful MUI Components</Typography>
199
+ <Typography variant="h6" sx={{ mt: 2, opacity: 0.9, fontWeight: 400, maxWidth: 600, mx: 'auto' }}>
200
+ A complete, production-ready component library built on Material UI with react-hook-form integration, dynamic tables, dialogs, and more.
201
+ </Typography>
202
+ <Stack direction="row" spacing={2} justifyContent="center" sx={{ mt: 4 }}>
203
+ <Button variant="contained" size="large" endIcon={<ArrowForwardIcon />} sx={{ bgcolor: 'white', color: '#2563eb', '&:hover': { bgcolor: 'rgba(255,255,255,0.9)' } }} onClick={() => scrollTo('buttons')}>Explore Components</Button>
204
+ <Button variant="outlined" size="large" sx={{ color: 'white', borderColor: 'rgba(255,255,255,0.4)', '&:hover': { borderColor: 'white', bgcolor: 'rgba(255,255,255,0.1)' } }} onClick={() => setSnackOpen(true)}>Quick Demo</Button>
205
+ </Stack>
206
+ </Container>
207
+ </Box>
208
+
209
+ <Container maxWidth="xl" sx={{ py: 6 }}>
210
+ {/* === BUTTONS === */}
211
+ <Box id="buttons" sx={{ scrollMarginTop: 80, mb: 8 }}>
212
+ {sectionHeader('Buttons', 'All variants, sizes, colors and states available in the Button component')}
213
+
214
+ <Grid container spacing={3}>
215
+ <Grid size={{ xs: 12, md: 6 }}>
216
+ {demoCard(
217
+ <><Button variant="contained">Contained</Button><Button variant="outlined">Outlined</Button><Button variant="text">Text</Button></>,
218
+ 'Variants'
219
+ )}
220
+ </Grid>
221
+ <Grid size={{ xs: 12, md: 6 }}>
222
+ {demoCard(
223
+ <><Button size="small">Small</Button><Button size="medium">Medium</Button><Button size="large">Large</Button></>,
224
+ 'Sizes'
225
+ )}
226
+ </Grid>
227
+ <Grid size={{ xs: 12, md: 6 }}>
228
+ {demoCard(
229
+ <><Button color="primary">Primary</Button><Button color="secondary">Secondary</Button><Button color="error">Error</Button><Button color="warning">Warning</Button><Button color="success">Success</Button><Button color="info">Info</Button></>,
230
+ 'Colors'
231
+ )}
232
+ </Grid>
233
+ <Grid size={{ xs: 12, md: 6 }}>
234
+ {demoCard(
235
+ <><Button variant="contained" startIcon={<AddIcon />}>Add</Button><Button variant="contained" endIcon={<SendIcon />}>Send</Button><Button variant="outlined" startIcon={<SaveIcon />}>Save</Button><Button variant="contained" startIcon={<CloudUploadIcon />}>Upload</Button></>,
236
+ 'With Icons'
237
+ )}
238
+ </Grid>
239
+ <Grid size={{ xs: 12, md: 6 }}>
240
+ {demoCard(
241
+ <><Button variant="contained" disabled>Disabled</Button><Button variant="outlined" disabled>Disabled</Button><Button variant="text" disabled>Disabled</Button></>,
242
+ 'Disabled'
243
+ )}
244
+ </Grid>
245
+ <Grid size={{ xs: 12, md: 6 }}>
246
+ {demoCard(
247
+ <><Button variant="contained" loading>Loading</Button><Button variant="outlined" loading>Loading</Button><Button variant="contained" loading loadingPosition="start" startIcon={<SaveIcon />}>Saving</Button></>,
248
+ 'Loading'
249
+ )}
250
+ </Grid>
251
+ </Grid>
252
+ </Box>
253
+
254
+ {/* === INPUTS === */}
255
+ <Box id="inputs" sx={{ scrollMarginTop: 80, mb: 8 }}>
256
+ {sectionHeader('Inputs & Controls', 'Text fields, selects, toggles, and form controls')}
257
+
258
+ <Grid container spacing={3}>
259
+ <Grid size={{ xs: 12, md: 6 }}>
260
+ <Card variant="outlined" sx={{ '&:hover': { boxShadow: 4 } }}>
261
+ <CardContent sx={{ display: 'flex', flexDirection: 'column', gap: 2 }}>
262
+ <Chip label="Text Fields" size="small" color="primary" variant="outlined" sx={{ alignSelf: 'flex-start' }} />
263
+ <TextField label="Standard" variant="outlined" fullWidth size="small" />
264
+ <TextField label="With Helper" variant="outlined" fullWidth size="small" helperText="This is a helpful message" />
265
+ <TextField label="Error" variant="outlined" fullWidth size="small" error helperText="This field is required" />
266
+ <TextField label="Disabled" variant="outlined" fullWidth size="small" disabled value="Disabled content" />
267
+ <TextField label="Multiline" variant="outlined" fullWidth multiline rows={2} size="small" />
268
+ </CardContent>
269
+ </Card>
270
+ </Grid>
271
+
272
+ <Grid size={{ xs: 12, md: 6 }}>
273
+ <Card variant="outlined" sx={{ '&:hover': { boxShadow: 4 } }}>
274
+ <CardContent sx={{ display: 'flex', flexDirection: 'column', gap: 2 }}>
275
+ <Chip label="Select & Autocomplete" size="small" color="primary" variant="outlined" sx={{ alignSelf: 'flex-start' }} />
276
+ <FormControl fullWidth size="small">
277
+ <InputLabel>Role</InputLabel>
278
+ <Select label="Role" defaultValue="">
279
+ <MenuItem value=""><em>None</em></MenuItem>
280
+ <MenuItem value="admin">Admin</MenuItem>
281
+ <MenuItem value="editor">Editor</MenuItem>
282
+ <MenuItem value="viewer">Viewer</MenuItem>
283
+ </Select>
284
+ </FormControl>
285
+ <FormControl fullWidth size="small">
286
+ <InputLabel>Country</InputLabel>
287
+ <Select label="Country" defaultValue="">
288
+ <MenuItem value="us">United States</MenuItem>
289
+ <MenuItem value="uk">United Kingdom</MenuItem>
290
+ <MenuItem value="ca">Canada</MenuItem>
291
+ <MenuItem value="au">Australia</MenuItem>
292
+ </Select>
293
+ </FormControl>
294
+ </CardContent>
295
+ </Card>
296
+ </Grid>
297
+
298
+ <Grid size={{ xs: 12, md: 4 }}>
299
+ <Card variant="outlined" sx={{ '&:hover': { boxShadow: 4 } }}>
300
+ <CardContent>
301
+ <Chip label="Switches" size="small" color="primary" variant="outlined" sx={{ mb: 2 }} />
302
+ <FormControlLabel control={<Switch checked={switchOn} onChange={(_, v) => setSwitchOn(v)} />} label={switchOn ? 'Enabled' : 'Disabled'} />
303
+ <FormControlLabel control={<Switch defaultChecked />} label="Notifications" />
304
+ <FormControlLabel control={<Switch />} label="Dark Mode" disabled />
305
+ </CardContent>
306
+ </Card>
307
+ </Grid>
308
+
309
+ <Grid size={{ xs: 12, md: 4 }}>
310
+ <Card variant="outlined" sx={{ '&:hover': { boxShadow: 4 } }}>
311
+ <CardContent>
312
+ <Chip label="Checkboxes" size="small" color="primary" variant="outlined" sx={{ mb: 2 }} />
313
+ <FormControlLabel control={<Checkbox />} label="Option A" />
314
+ <FormControlLabel control={<Checkbox defaultChecked />} label="Option B" />
315
+ <FormControlLabel control={<Checkbox />} label="Option C" disabled />
316
+ <FormControlLabel control={<Checkbox defaultChecked indeterminate />} label="Indeterminate" />
317
+ </CardContent>
318
+ </Card>
319
+ </Grid>
320
+
321
+ <Grid size={{ xs: 12, md: 4 }}>
322
+ <Card variant="outlined" sx={{ '&:hover': { boxShadow: 4 } }}>
323
+ <CardContent>
324
+ <Chip label="Radio Buttons" size="small" color="primary" variant="outlined" sx={{ mb: 2 }} />
325
+ <RadioGroup defaultValue="first">
326
+ <FormControlLabel value="first" control={<Radio />} label="First Choice" />
327
+ <FormControlLabel value="second" control={<Radio />} label="Second Choice" />
328
+ <FormControlLabel value="third" control={<Radio />} label="Third Choice" disabled />
329
+ </RadioGroup>
330
+ </CardContent>
331
+ </Card>
332
+ </Grid>
333
+ </Grid>
334
+ </Box>
335
+
336
+ {/* === DISPLAY === */}
337
+ <Box id="displays" sx={{ scrollMarginTop: 80, mb: 8 }}>
338
+ {sectionHeader('Display Components', 'Cards, avatars, badges, progress, and more')}
339
+
340
+ <Grid container spacing={3}>
341
+ <Grid size={{ xs: 12, md: 6 }}>
342
+ <Card variant="outlined" sx={{ '&:hover': { boxShadow: 4 } }}>
343
+ <CardContent>
344
+ <Chip label="Avatars" size="small" color="primary" variant="outlined" sx={{ mb: 2 }} />
345
+ <Stack direction="row" spacing={1} alignItems="center">
346
+ <Avatar sx={{ bgcolor: 'primary.main' }}>A</Avatar>
347
+ <Avatar sx={{ bgcolor: 'secondary.main' }}>B</Avatar>
348
+ <Avatar sx={{ bgcolor: 'success.main' }}>C</Avatar>
349
+ <Avatar sx={{ bgcolor: 'warning.main' }}>D</Avatar>
350
+ <Avatar sx={{ bgcolor: 'error.main' }}>E</Avatar>
351
+ <AvatarGroup total={12}>
352
+ <Avatar sx={{ bgcolor: 'primary.main' }}>U</Avatar>
353
+ <Avatar sx={{ bgcolor: 'secondary.main' }}>S</Avatar>
354
+ <Avatar sx={{ bgcolor: 'success.main' }}>E</Avatar>
355
+ <Avatar sx={{ bgcolor: 'warning.main' }}>R</Avatar>
356
+ </AvatarGroup>
357
+ </Stack>
358
+ </CardContent>
359
+ </Card>
360
+ </Grid>
361
+
362
+ <Grid size={{ xs: 12, md: 6 }}>
363
+ <Card variant="outlined" sx={{ '&:hover': { boxShadow: 4 } }}>
364
+ <CardContent>
365
+ <Chip label="Badges" size="small" color="primary" variant="outlined" sx={{ mb: 2 }} />
366
+ <Stack direction="row" spacing={2} alignItems="center" flexWrap="wrap">
367
+ <Badge badgeContent={4} color="primary"><NotificationsIcon color="action" /></Badge>
368
+ <Badge badgeContent={99} color="error"><NotificationsIcon color="action" /></Badge>
369
+ <Badge badgeContent="!" color="warning"><NotificationsIcon color="action" /></Badge>
370
+ <Badge variant="dot" color="success"><NotificationsIcon color="action" /></Badge>
371
+ <Chip label="Default" color="default" size="small" />
372
+ <Chip label="Primary" color="primary" size="small" />
373
+ <Chip label="Success" color="success" size="small" />
374
+ <Chip label="Warning" color="warning" size="small" />
375
+ <Chip label="Error" color="error" size="small" />
376
+ <Chip label="Info" color="info" size="small" />
377
+ <Chip label="Outlined" variant="outlined" size="small" />
378
+ <Chip label="Deleted" onDelete={() => {}} size="small" />
379
+ </Stack>
380
+ </CardContent>
381
+ </Card>
382
+ </Grid>
383
+
384
+ <Grid size={{ xs: 12, md: 6 }}>
385
+ <Card variant="outlined" sx={{ '&:hover': { boxShadow: 4 } }}>
386
+ <CardContent>
387
+ <Chip label="Progress" size="small" color="primary" variant="outlined" sx={{ mb: 2 }} />
388
+ <Stack spacing={3}>
389
+ <Box><Typography variant="caption" color="text.secondary" gutterBottom display="block">Indeterminate</Typography><LinearProgress /></Box>
390
+ <Box><Typography variant="caption" color="text.secondary" gutterBottom display="block">Determinate — {progress}%</Typography><LinearProgress variant="determinate" value={progress} /></Box>
391
+ <Box><Typography variant="caption" color="text.secondary" gutterBottom display="block">Circular</Typography><CircularProgress size={24} /></Box>
392
+ <Box><Typography variant="caption" color="text.secondary" gutterBottom display="block">Slider — {sliderVal}</Typography><Slider value={sliderVal} onChange={(_, v) => setSliderVal(v as number)} /></Box>
393
+ <Box><Typography variant="caption" color="text.secondary" gutterBottom display="block">Rating</Typography><Rating defaultValue={4} precision={0.5} /></Box>
394
+ </Stack>
395
+ </CardContent>
396
+ </Card>
397
+ </Grid>
398
+
399
+ <Grid size={{ xs: 12, md: 6 }}>
400
+ <Card variant="outlined" sx={{ '&:hover': { boxShadow: 4 } }}>
401
+ <CardContent>
402
+ <Chip label="Tooltips" size="small" color="primary" variant="outlined" sx={{ mb: 2 }} />
403
+ <Stack direction="row" spacing={1} alignItems="center" flexWrap="wrap">
404
+ <Tooltip title="Top tooltip" placement="top"><Button variant="outlined" size="small">Top</Button></Tooltip>
405
+ <Tooltip title="Bottom tooltip" placement="bottom"><Button variant="outlined" size="small">Bottom</Button></Tooltip>
406
+ <Tooltip title="Left tooltip" placement="left"><Button variant="outlined" size="small">Left</Button></Tooltip>
407
+ <Tooltip title="Right tooltip" placement="right"><Button variant="outlined" size="small">Right</Button></Tooltip>
408
+ <Tooltip title={<><Typography variant="caption" fontWeight={700}>Rich Content</Typography><Typography variant="caption" display="block">With multiple lines</Typography></>}><Button variant="outlined" size="small">Rich</Button></Tooltip>
409
+ </Stack>
410
+ </CardContent>
411
+ </Card>
412
+ </Grid>
413
+ </Grid>
414
+ </Box>
415
+
416
+ {/* === FEEDBACK === */}
417
+ <Box id="feedback" sx={{ scrollMarginTop: 80, mb: 8 }}>
418
+ {sectionHeader('Feedback & Dialogs', 'Dialogs, alerts, snackbars, and skeleton loaders')}
419
+
420
+ <Grid container spacing={3}>
421
+ <Grid size={{ xs: 12, md: 6 }}>
422
+ <Card variant="outlined" sx={{ '&:hover': { boxShadow: 4 } }}>
423
+ <CardContent>
424
+ <Chip label="Alerts" size="small" color="primary" variant="outlined" sx={{ mb: 2 }} />
425
+ <Stack spacing={1}>
426
+ <Alert severity="success" onClose={() => {}}><AlertTitle>Success</AlertTitle>Operation completed successfully</Alert>
427
+ <Alert severity="info"><AlertTitle>Info</AlertTitle>This is an informational message</Alert>
428
+ <Alert severity="warning"><AlertTitle>Warning</AlertTitle>Please check your input</Alert>
429
+ <Alert severity="error"><AlertTitle>Error</AlertTitle>Something went wrong</Alert>
430
+ </Stack>
431
+ </CardContent>
432
+ </Card>
433
+ </Grid>
434
+
435
+ <Grid size={{ xs: 12, md: 6 }}>
436
+ <Card variant="outlined" sx={{ '&:hover': { boxShadow: 4 } }}>
437
+ <CardContent>
438
+ <Chip label="Dialogs & Snackbars" size="small" color="primary" variant="outlined" sx={{ mb: 2 }} />
439
+ <Stack spacing={1.5}>
440
+ <Button variant="contained" onClick={() => setDialogOpen(true)} startIcon={<InfoIcon />}>Open Dialog</Button>
441
+ <Button variant="outlined" onClick={() => setSnackOpen(true)} startIcon={<NotificationsIcon />}>Show Snackbar</Button>
442
+ </Stack>
443
+ <Dialog open={dialogOpen} onClose={() => setDialogOpen(false)} maxWidth="sm" fullWidth>
444
+ <DialogTitle>Confirm Action</DialogTitle>
445
+ <DialogContent><DialogContentText>This is a sample dialog with content. It demonstrates the Dialog component with title, content, and actions.</DialogContentText></DialogContent>
446
+ <DialogActions><Button onClick={() => setDialogOpen(false)}>Cancel</Button><Button variant="contained" onClick={() => { setDialogOpen(false); setSnackOpen(true); }}>Confirm</Button></DialogActions>
447
+ </Dialog>
448
+ <Snackbar open={snackOpen} autoHideDuration={3000} onClose={() => setSnackOpen(false)} message="Action completed successfully!" action={<Button color="inherit" size="small" onClick={() => setSnackOpen(false)}>Close</Button>} />
449
+ </CardContent>
450
+ </Card>
451
+ </Grid>
452
+
453
+ <Grid size={{ xs: 12, md: 6 }}>
454
+ <Card variant="outlined" sx={{ '&:hover': { boxShadow: 4 } }}>
455
+ <CardContent>
456
+ <Chip label="Skeleton" size="small" color="primary" variant="outlined" sx={{ mb: 2 }} />
457
+ <Stack spacing={1}>
458
+ <Skeleton variant="circular" width={40} height={40} />
459
+ <Skeleton variant="rectangular" height={60} sx={{ borderRadius: 1 }} />
460
+ <Skeleton variant="rounded" height={40} sx={{ borderRadius: 1 }} />
461
+ <Skeleton width="60%" />
462
+ <Skeleton width="80%" />
463
+ </Stack>
464
+ </CardContent>
465
+ </Card>
466
+ </Grid>
467
+
468
+ <Grid size={{ xs: 12, md: 6 }}>
469
+ <Card variant="outlined" sx={{ '&:hover': { boxShadow: 4 } }}>
470
+ <CardContent>
471
+ <Chip label="Cards" size="small" color="primary" variant="outlined" sx={{ mb: 2 }} />
472
+ <Card variant="outlined">
473
+ <CardContent>
474
+ <Typography variant="h6" fontWeight={600}>Card Title</Typography>
475
+ <Typography variant="body2" color="text.secondary" sx={{ mt: 1 }}>
476
+ This is a card component showing how content can be structured with MUI Card, CardContent, and CardActions.
477
+ </Typography>
478
+ </CardContent>
479
+ <CardActions sx={{ px: 2, pb: 2 }}>
480
+ <Button size="small" variant="contained">Action</Button>
481
+ <Button size="small">Cancel</Button>
482
+ </CardActions>
483
+ </Card>
484
+ </CardContent>
485
+ </Card>
486
+ </Grid>
487
+ </Grid>
488
+ </Box>
489
+
490
+ {/* === TABLE === */}
491
+ <Box id="table" sx={{ scrollMarginTop: 80, mb: 8 }}>
492
+ {sectionHeader('Dynamic Table', 'Config-driven table with loading, empty, checkbox selection, and pagination')}
493
+
494
+ <Card variant="outlined" sx={{ '&:hover': { boxShadow: 4 } }}>
495
+ <CardContent>
496
+ <Stack direction="row" spacing={1.5} sx={{ mb: 2 }} alignItems="center">
497
+ <Button variant={tableLoading ? 'outlined' : 'contained'} size="small" onClick={() => setTableLoading(!tableLoading)}>
498
+ {tableLoading ? 'Stop Loading' : 'Simulate Loading'}
499
+ </Button>
500
+ <Button variant="outlined" size="small" onClick={() => setSelectedIds([])}>Clear Selection</Button>
501
+ <Typography variant="caption" color="text.secondary">{selectedIds.length > 0 ? `${selectedIds.length} selected` : 'No rows selected'}</Typography>
502
+ </Stack>
503
+ <TableContainer component={Paper} variant="outlined" sx={{ borderRadius: 2 }}>
504
+ <Table>
505
+ <TableHead>
506
+ <TableRow>
507
+ <TableCell padding="checkbox"><Checkbox checked={paginatedData.length > 0 && paginatedData.every((x) => isRowSelected(x.id))} indeterminate={paginatedData.some((x) => isRowSelected(x.id)) && !paginatedData.every((x) => isRowSelected(x.id))} onChange={toggleAll} /></TableCell>
508
+ <TableCell sx={{ fontWeight: 600 }}>Name</TableCell>
509
+ <TableCell sx={{ fontWeight: 600 }}>Email</TableCell>
510
+ <TableCell sx={{ fontWeight: 600 }}>Role</TableCell>
511
+ <TableCell sx={{ fontWeight: 600 }}>Status</TableCell>
512
+ </TableRow>
513
+ </TableHead>
514
+ <TableBody>
515
+ {tableLoading ? (
516
+ <TableRow>
517
+ <TableCell colSpan={5} align="center" sx={{ py: 8 }}>
518
+ <CircularProgress />
519
+ </TableCell>
520
+ </TableRow>
521
+ ) : paginatedData.length === 0 ? (
522
+ <TableRow>
523
+ <TableCell colSpan={5} align="center" sx={{ py: 8 }}>
524
+ <Typography color="text.secondary">No data available</Typography>
525
+ </TableCell>
526
+ </TableRow>
527
+ ) : (
528
+ paginatedData.map((row) => (
529
+ <TableRow key={row.id} hover selected={isRowSelected(row.id)}>
530
+ <TableCell padding="checkbox"><Checkbox checked={isRowSelected(row.id)} onChange={() => toggleRow(row.id)} /></TableCell>
531
+ <TableCell>{row.name}</TableCell>
532
+ <TableCell>{row.email}</TableCell>
533
+ <TableCell><Chip label={row.role} size="small" color={row.role === 'Admin' ? 'primary' : row.role === 'Editor' ? 'warning' : 'default'} /></TableCell>
534
+ <TableCell><Chip label={row.status} size="small" color={row.status === 'Active' ? 'success' : 'default'} variant="outlined" /></TableCell>
535
+ </TableRow>
536
+ ))
537
+ )}
538
+ </TableBody>
539
+ </Table>
540
+ </TableContainer>
541
+
542
+ {/* Pagination */}
543
+ {totalPages > 1 && !tableLoading && (
544
+ <Box sx={{ display: 'flex', justifyContent: 'center', alignItems: 'center', gap: 0.5, mt: 2 }}>
545
+ <IconButton size="small" disabled={tablePage <= 1} onClick={() => setTablePage((p) => Math.max(1, p - 1))}>
546
+ <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2"><path d="M15 18l-6-6 6-6" /></svg>
547
+ </IconButton>
548
+ {(() => {
549
+ const pages: (number | 'ellipsis')[] = [1];
550
+ const left = Math.max(2, tablePage - 1);
551
+ const right = Math.min(totalPages - 1, tablePage + 1);
552
+ if (left > 2) pages.push('ellipsis');
553
+ for (let i = left; i <= right; i++) pages.push(i);
554
+ if (right < totalPages - 1) pages.push('ellipsis');
555
+ if (totalPages > 1) pages.push(totalPages);
556
+ return pages.map((p, i) => p === 'ellipsis' ? <Typography key={`e-${i}`} variant="body2" color="text.secondary" sx={{ px: 0.5 }}>...</Typography> : <Button key={p} size="small" variant={tablePage === p ? 'contained' : 'outlined'} onClick={() => setTablePage(p)} sx={{ minWidth: 36, height: 36, p: 0 }}>{p}</Button>);
557
+ })()}
558
+ <IconButton size="small" disabled={tablePage >= totalPages} onClick={() => setTablePage((p) => Math.min(totalPages, p + 1))}>
559
+ <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2"><path d="M9 18l6-6-6-6" /></svg>
560
+ </IconButton>
561
+ </Box>
562
+ )}
563
+ </CardContent>
564
+ </Card>
565
+ </Box>
566
+
567
+ {/* === FORM === */}
568
+ <Box id="form" sx={{ scrollMarginTop: 80, mb: 8 }}>
569
+ {sectionHeader('Form with Validation', 'React Hook Form + Zod validation with CustomField components')}
570
+
571
+ <Card variant="outlined" sx={{ '&:hover': { boxShadow: 4 } }}>
572
+ <CardContent>
573
+ <Grid container spacing={3}>
574
+ <Grid size={{ xs: 12, md: 6 }}>
575
+ <form onSubmit={form.handleSubmit((data) => { alert(JSON.stringify(data, null, 2)); })}>
576
+ <Stack spacing={2}>
577
+ <TextField label="Full Name" variant="outlined" fullWidth size="small" error={!!form.formState.errors.fullName} helperText={form.formState.errors.fullName?.message as string} {...form.register('fullName')} />
578
+ <TextField label="Email" variant="outlined" fullWidth size="small" error={!!form.formState.errors.email} helperText={form.formState.errors.email?.message as string} {...form.register('email')} />
579
+ <TextField label="Age" variant="outlined" fullWidth size="small" type="number" error={!!form.formState.errors.age} helperText={form.formState.errors.age?.message as string} {...form.register('age', { valueAsNumber: true })} />
580
+ <TextField label="Bio" variant="outlined" fullWidth size="small" multiline rows={2} {...form.register('bio')} />
581
+ <FormControl fullWidth size="small">
582
+ <InputLabel>Role</InputLabel>
583
+ <Select label="Role" defaultValue="">
584
+ <MenuItem value="admin">Admin</MenuItem>
585
+ <MenuItem value="editor">Editor</MenuItem>
586
+ <MenuItem value="viewer">Viewer</MenuItem>
587
+ </Select>
588
+ </FormControl>
589
+ <FormControlLabel control={<Switch defaultChecked />} label="Email Notifications" />
590
+ <FormControlLabel control={<Checkbox />} label="I accept the terms" />
591
+ <Button type="submit" variant="contained" size="large" startIcon={<SendIcon />} fullWidth>Submit</Button>
592
+ </Stack>
593
+ </form>
594
+ </Grid>
595
+ <Grid size={{ xs: 12, md: 6 }}>
596
+ <Paper variant="outlined" sx={{ p: 2, bgcolor: 'grey.50', height: '100%' }}>
597
+ <Typography variant="subtitle2" fontWeight={600} gutterBottom>Form State</Typography>
598
+ <Typography variant="caption" component="pre" sx={{ fontFamily: 'monospace', whiteSpace: 'pre-wrap', fontSize: '0.7rem', color: 'text.secondary' }}>
599
+ {JSON.stringify({ values: form.watch(), errors: form.formState.errors, isValid: form.formState.isValid, isDirty: form.formState.isDirty }, null, 2)}
600
+ </Typography>
601
+ </Paper>
602
+ </Grid>
603
+ </Grid>
604
+ </CardContent>
605
+ </Card>
606
+ </Box>
607
+
608
+ {/* === COMMON === */}
609
+ <Box id="common" sx={{ scrollMarginTop: 80, mb: 8 }}>
610
+ {sectionHeader('Common Compositions', 'Button groups, breadcrumbs, speed dial, and more')}
611
+
612
+ <Grid container spacing={3}>
613
+ <Grid size={{ xs: 12, md: 6 }}>
614
+ <Card variant="outlined" sx={{ '&:hover': { boxShadow: 4 } }}>
615
+ <CardContent>
616
+ <Chip label="Button Groups" size="small" color="primary" variant="outlined" sx={{ mb: 2 }} />
617
+ <Stack spacing={2}>
618
+ <ButtonGroup variant="contained" size="small">
619
+ <Button>Left</Button>
620
+ <Button>Center</Button>
621
+ <Button>Right</Button>
622
+ </ButtonGroup>
623
+ <ButtonGroup variant="outlined" size="small">
624
+ <Button>One</Button>
625
+ <Button>Two</Button>
626
+ <Button>Three</Button>
627
+ </ButtonGroup>
628
+ </Stack>
629
+ </CardContent>
630
+ </Card>
631
+ </Grid>
632
+
633
+ <Grid size={{ xs: 12, md: 6 }}>
634
+ <Card variant="outlined" sx={{ '&:hover': { boxShadow: 4 } }}>
635
+ <CardContent>
636
+ <Chip label="Breadcrumbs" size="small" color="primary" variant="outlined" sx={{ mb: 2 }} />
637
+ <Breadcrumbs>
638
+ <Link underline="hover" color="inherit" href="#"><HomeIcon sx={{ mr: 0.5, fontSize: 16 }} />Home</Link>
639
+ <Link underline="hover" color="inherit" href="#">Components</Link>
640
+ <Typography color="text.primary">MUI Showcase</Typography>
641
+ </Breadcrumbs>
642
+ </CardContent>
643
+ </Card>
644
+ </Grid>
645
+
646
+ <Grid size={{ xs: 12, md: 6 }}>
647
+ <Card variant="outlined" sx={{ '&:hover': { boxShadow: 4 } }}>
648
+ <CardContent>
649
+ <Chip label="FAB & Speed Dial" size="small" color="primary" variant="outlined" sx={{ mb: 2 }} />
650
+ <Stack direction="row" spacing={2} alignItems="center">
651
+ <Fab color="primary" size="small"><AddIcon /></Fab>
652
+ <Fab color="secondary" size="small"><EditIcon /></Fab>
653
+ <SpeedDial
654
+ ariaLabel="SpeedDial"
655
+ icon={<SpeedDialIcon />}
656
+ direction="right"
657
+ open={speedDialOpen}
658
+ onOpen={() => setSpeedDialOpen(true)}
659
+ onClose={() => setSpeedDialOpen(false)}
660
+ FabProps={{ size: 'small' }}
661
+ sx={{ '& .MuiSpeedDial-actions': { gap: 0.5 } }}
662
+ >
663
+ <SpeedDialAction icon={<SaveIcon />} tooltipTitle="Save" onClick={() => setSpeedDialOpen(false)} />
664
+ <SpeedDialAction icon={<ShareIcon />} tooltipTitle="Share" onClick={() => setSpeedDialOpen(false)} />
665
+ <SpeedDialAction icon={<FavoriteIcon />} tooltipTitle="Favorite" onClick={() => setSpeedDialOpen(false)} />
666
+ </SpeedDial>
667
+ </Stack>
668
+ </CardContent>
669
+ </Card>
670
+ </Grid>
671
+
672
+ <Grid size={{ xs: 12, md: 6 }}>
673
+ <Card variant="outlined" sx={{ '&:hover': { boxShadow: 4 } }}>
674
+ <CardContent>
675
+ <Chip label="Tabs" size="small" color="primary" variant="outlined" sx={{ mb: 2 }} />
676
+ <Box>
677
+ <Tabs value={activeTab} onChange={(_, v) => setActiveTab(v)}>
678
+ <Tab label="Details" />
679
+ <Tab label="Settings" />
680
+ <Tab label="Activity" />
681
+ </Tabs>
682
+ <Box sx={{ p: 2, border: 1, borderColor: 'divider', borderTop: 0, borderRadius: '0 0 8px 8px' }}>
683
+ {activeTab === 0 && <Typography variant="body2" color="text.secondary">Details panel content goes here.</Typography>}
684
+ {activeTab === 1 && <Typography variant="body2" color="text.secondary">Settings panel content goes here.</Typography>}
685
+ {activeTab === 2 && <Typography variant="body2" color="text.secondary">Activity panel content goes here.</Typography>}
686
+ </Box>
687
+ </Box>
688
+ </CardContent>
689
+ </Card>
690
+ </Grid>
691
+ </Grid>
692
+ </Box>
693
+ </Container>
694
+
695
+ {/* Footer */}
696
+ <Box sx={{ bgcolor: 'grey.900', color: 'white', py: 6 }}>
697
+ <Container maxWidth="md" sx={{ textAlign: 'center' }}>
698
+ <Typography variant="h5" fontWeight={700} gutterBottom>MUI Component System</Typography>
699
+ <Typography variant="body2" sx={{ opacity: 0.7, mb: 3 }}>
700
+ Built with Material UI — a complete component library for production-ready Next.js applications.
701
+ </Typography>
702
+ <Stack direction="row" spacing={1} justifyContent="center" flexWrap="wrap">
703
+ <Chip label="Material UI" size="small" sx={{ color: 'white', borderColor: 'rgba(255,255,255,0.3)' }} variant="outlined" />
704
+ <Chip label="React Hook Form" size="small" sx={{ color: 'white', borderColor: 'rgba(255,255,255,0.3)' }} variant="outlined" />
705
+ <Chip label="Zod" size="small" sx={{ color: 'white', borderColor: 'rgba(255,255,255,0.3)' }} variant="outlined" />
706
+ <Chip label="Next.js 15" size="small" sx={{ color: 'white', borderColor: 'rgba(255,255,255,0.3)' }} variant="outlined" />
707
+ <Chip label="TypeScript" size="small" sx={{ color: 'white', borderColor: 'rgba(255,255,255,0.3)' }} variant="outlined" />
708
+ </Stack>
709
+ <Typography variant="caption" sx={{ mt: 3, opacity: 0.5, display: 'block' }}>
710
+ Scaffolded with Nexstruct
711
+ </Typography>
712
+ </Container>
713
+ </Box>
714
+ </Box>
715
+ );
716
+ }