@donotdev/cli 0.0.3

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 (281) hide show
  1. package/LICENSE.md +48 -0
  2. package/README.md +291 -0
  3. package/dependencies-matrix.json +694 -0
  4. package/dist/bin/commands/build.d.ts +11 -0
  5. package/dist/bin/commands/build.d.ts.map +1 -0
  6. package/dist/bin/commands/build.js +8162 -0
  7. package/dist/bin/commands/build.js.map +1 -0
  8. package/dist/bin/commands/bump.d.ts +11 -0
  9. package/dist/bin/commands/bump.d.ts.map +1 -0
  10. package/dist/bin/commands/bump.js +8004 -0
  11. package/dist/bin/commands/bump.js.map +1 -0
  12. package/dist/bin/commands/cacheout.d.ts +11 -0
  13. package/dist/bin/commands/cacheout.d.ts.map +1 -0
  14. package/dist/bin/commands/cacheout.js +7630 -0
  15. package/dist/bin/commands/cacheout.js.map +1 -0
  16. package/dist/bin/commands/create-app.d.ts +11 -0
  17. package/dist/bin/commands/create-app.d.ts.map +1 -0
  18. package/dist/bin/commands/create-app.js +9032 -0
  19. package/dist/bin/commands/create-app.js.map +1 -0
  20. package/dist/bin/commands/create-project.d.ts +11 -0
  21. package/dist/bin/commands/create-project.d.ts.map +1 -0
  22. package/dist/bin/commands/create-project.js +9643 -0
  23. package/dist/bin/commands/create-project.js.map +1 -0
  24. package/dist/bin/commands/deploy.d.ts +11 -0
  25. package/dist/bin/commands/deploy.d.ts.map +1 -0
  26. package/dist/bin/commands/deploy.js +9007 -0
  27. package/dist/bin/commands/deploy.js.map +1 -0
  28. package/dist/bin/commands/dev.d.ts +11 -0
  29. package/dist/bin/commands/dev.d.ts.map +1 -0
  30. package/dist/bin/commands/dev.js +7892 -0
  31. package/dist/bin/commands/dev.js.map +1 -0
  32. package/dist/bin/commands/emu.d.ts +11 -0
  33. package/dist/bin/commands/emu.d.ts.map +1 -0
  34. package/dist/bin/commands/emu.js +8302 -0
  35. package/dist/bin/commands/emu.js.map +1 -0
  36. package/dist/bin/commands/format.d.ts +11 -0
  37. package/dist/bin/commands/format.d.ts.map +1 -0
  38. package/dist/bin/commands/format.js +8009 -0
  39. package/dist/bin/commands/format.js.map +1 -0
  40. package/dist/bin/commands/lint.d.ts +11 -0
  41. package/dist/bin/commands/lint.d.ts.map +1 -0
  42. package/dist/bin/commands/lint.js +7481 -0
  43. package/dist/bin/commands/lint.js.map +1 -0
  44. package/dist/bin/commands/preview.d.ts +11 -0
  45. package/dist/bin/commands/preview.d.ts.map +1 -0
  46. package/dist/bin/commands/preview.js +7909 -0
  47. package/dist/bin/commands/preview.js.map +1 -0
  48. package/dist/bin/commands/sync-secrets.d.ts +11 -0
  49. package/dist/bin/commands/sync-secrets.d.ts.map +1 -0
  50. package/dist/bin/commands/sync-secrets.js +8227 -0
  51. package/dist/bin/commands/sync-secrets.js.map +1 -0
  52. package/dist/bin/dndev.js +222 -0
  53. package/dist/bin/donotdev.js +222 -0
  54. package/dist/index.d.ts +8 -0
  55. package/dist/index.d.ts.map +1 -0
  56. package/dist/index.js +12820 -0
  57. package/dist/index.js.map +1 -0
  58. package/package.json +71 -0
  59. package/templates/app-demo/index.html.example +20 -0
  60. package/templates/app-demo/public/favicon.ico.example +0 -0
  61. package/templates/app-demo/public/fonts/Roboto-400-cyrillic-ext.woff2.example +0 -0
  62. package/templates/app-demo/public/fonts/Roboto-400-cyrillic.woff2.example +0 -0
  63. package/templates/app-demo/public/fonts/Roboto-400-greek-ext.woff2.example +0 -0
  64. package/templates/app-demo/public/fonts/Roboto-400-greek.woff2.example +0 -0
  65. package/templates/app-demo/public/fonts/Roboto-400-latin-ext.woff2.example +0 -0
  66. package/templates/app-demo/public/fonts/Roboto-400-latin.woff2.example +0 -0
  67. package/templates/app-demo/public/fonts/Roboto-400-vietnamese.woff2.example +0 -0
  68. package/templates/app-demo/public/fonts/Roboto-700-cyrillic-ext.woff2.example +0 -0
  69. package/templates/app-demo/public/fonts/Roboto-700-cyrillic.woff2.example +0 -0
  70. package/templates/app-demo/public/fonts/Roboto-700-greek-ext.woff2.example +0 -0
  71. package/templates/app-demo/public/fonts/Roboto-700-greek.woff2.example +0 -0
  72. package/templates/app-demo/public/fonts/Roboto-700-latin-ext.woff2.example +0 -0
  73. package/templates/app-demo/public/fonts/Roboto-700-latin.woff2.example +0 -0
  74. package/templates/app-demo/public/fonts/Roboto-700-vietnamese.woff2.example +0 -0
  75. package/templates/app-demo/public/fonts/fonts.css.example +144 -0
  76. package/templates/app-demo/public/logo.png.example +0 -0
  77. package/templates/app-demo/public/logo.svg.example +1 -0
  78. package/templates/app-demo/public/manifest.json.example +10 -0
  79. package/templates/app-demo/src/App.tsx.example +17 -0
  80. package/templates/app-demo/src/Routes.tsx.example +20 -0
  81. package/templates/app-demo/src/components/ThemeToggle.tsx.example +48 -0
  82. package/templates/app-demo/src/globals.css.example +4 -0
  83. package/templates/app-demo/src/main.tsx.example +27 -0
  84. package/templates/app-demo/src/pages/DetailPage.tsx.example +103 -0
  85. package/templates/app-demo/src/pages/FullPage.tsx.example +142 -0
  86. package/templates/app-demo/src/pages/HomePage.tsx.example +79 -0
  87. package/templates/app-demo/src/pages/components/ComponentRenderer.tsx.example +511 -0
  88. package/templates/app-demo/src/pages/components/ComponentsData.tsx.example +152 -0
  89. package/templates/app-demo/src/pages/components/DemoLayout.tsx.example +266 -0
  90. package/templates/app-demo/src/pages/components/LayoutRoute.tsx.example +20 -0
  91. package/templates/app-demo/src/pages/components/componentConfig.ts.example +921 -0
  92. package/templates/app-demo/src/themes.css.example +179 -0
  93. package/templates/app-demo/tsconfig.json.example +9 -0
  94. package/templates/app-demo/vite.config.ts.example +53 -0
  95. package/templates/app-next/.env.example +92 -0
  96. package/templates/app-next/next.config.ts.example +8 -0
  97. package/templates/app-next/postcss.config.js.example +58 -0
  98. package/templates/app-next/service-account-key.json.example +2 -0
  99. package/templates/app-next/src/app/ClientLayout.tsx.example +39 -0
  100. package/templates/app-next/src/app/layout.tsx.example +52 -0
  101. package/templates/app-next/src/app/not-found.tsx.example +21 -0
  102. package/templates/app-next/src/config/app.ts.example +75 -0
  103. package/templates/app-next/src/config/legal.ts.example +170 -0
  104. package/templates/app-next/src/globals.css.example +15 -0
  105. package/templates/app-next/src/locales/dndev_en.json.example +516 -0
  106. package/templates/app-next/src/pages/HomePage.tsx.example +20 -0
  107. package/templates/app-next/src/pages/legal/LegalNoticePage.tsx.example +75 -0
  108. package/templates/app-next/src/pages/legal/PrivacyPage.tsx.example +69 -0
  109. package/templates/app-next/src/pages/legal/TermsPage.tsx.example +71 -0
  110. package/templates/app-next/src/themes.css.example +179 -0
  111. package/templates/app-next/tsconfig.json.example +11 -0
  112. package/templates/app-payload/.env.example +28 -0
  113. package/templates/app-payload/README.md.example +233 -0
  114. package/templates/app-payload/collections/Company.ts.example +125 -0
  115. package/templates/app-payload/collections/Hero.ts.example +62 -0
  116. package/templates/app-payload/collections/Media.ts.example +41 -0
  117. package/templates/app-payload/collections/Products.ts.example +115 -0
  118. package/templates/app-payload/collections/Services.ts.example +104 -0
  119. package/templates/app-payload/collections/Testimonials.ts.example +92 -0
  120. package/templates/app-payload/collections/Users.ts.example +35 -0
  121. package/templates/app-payload/src/server.ts.example +79 -0
  122. package/templates/app-payload/tsconfig.json.example +24 -0
  123. package/templates/app-vite/.env.example +77 -0
  124. package/templates/app-vite/index.html.example +127 -0
  125. package/templates/app-vite/service-account-key.json.example +2 -0
  126. package/templates/app-vite/src/App.tsx.example +39 -0
  127. package/templates/app-vite/src/Routes.tsx.example +16 -0
  128. package/templates/app-vite/src/config/app.ts.example +75 -0
  129. package/templates/app-vite/src/config/legal.ts.example +170 -0
  130. package/templates/app-vite/src/globals.css.example +11 -0
  131. package/templates/app-vite/src/locales/dndev_en.json.example +516 -0
  132. package/templates/app-vite/src/main.tsx.example +21 -0
  133. package/templates/app-vite/src/pages/HomePage.tsx.example +22 -0
  134. package/templates/app-vite/src/pages/NotFoundPage.tsx.example +33 -0
  135. package/templates/app-vite/src/pages/legal/LegalNoticePage.tsx.example +75 -0
  136. package/templates/app-vite/src/pages/legal/PrivacyPage.tsx.example +69 -0
  137. package/templates/app-vite/src/pages/legal/TermsPage.tsx.example +71 -0
  138. package/templates/app-vite/src/pages/locales/README.md.example +1 -0
  139. package/templates/app-vite/src/pages/locales/example_en.json.example +5 -0
  140. package/templates/app-vite/src/themes.css.example +179 -0
  141. package/templates/app-vite/tsconfig.json.example +9 -0
  142. package/templates/app-vite/vite.config.ts.example +9 -0
  143. package/templates/functions-firebase/README.md.example +129 -0
  144. package/templates/functions-firebase/build.mjs.example +52 -0
  145. package/templates/functions-firebase/functions-firebase/.env.example.example +45 -0
  146. package/templates/functions-firebase/functions-firebase/README.md.example +123 -0
  147. package/templates/functions-firebase/functions-firebase/build.mjs.example +52 -0
  148. package/templates/functions-firebase/functions-firebase/src/auth/getCustomClaims.ts.example +19 -0
  149. package/templates/functions-firebase/functions-firebase/src/auth/getUserAuthStatus.ts.example +21 -0
  150. package/templates/functions-firebase/functions-firebase/src/auth/index.ts.example +11 -0
  151. package/templates/functions-firebase/functions-firebase/src/auth/removeCustomClaims.ts.example +21 -0
  152. package/templates/functions-firebase/functions-firebase/src/auth/setCustomClaims.ts.example +21 -0
  153. package/templates/functions-firebase/functions-firebase/src/billing/handleStripeWebhook.ts.example +24 -0
  154. package/templates/functions-firebase/functions-firebase/src/billing/index.ts.example +10 -0
  155. package/templates/functions-firebase/functions-firebase/src/billing/processPaymentSuccess.ts.example +14 -0
  156. package/templates/functions-firebase/functions-firebase/src/billing/refreshSubscriptionStatus.ts.example +14 -0
  157. package/templates/functions-firebase/functions-firebase/src/crud/createEntity.ts.example +19 -0
  158. package/templates/functions-firebase/functions-firebase/src/crud/deleteEntity.ts.example +14 -0
  159. package/templates/functions-firebase/functions-firebase/src/crud/getEntity.ts.example +14 -0
  160. package/templates/functions-firebase/functions-firebase/src/crud/index.ts.example +12 -0
  161. package/templates/functions-firebase/functions-firebase/src/crud/listEntities.ts.example +14 -0
  162. package/templates/functions-firebase/functions-firebase/src/crud/updateEntity.ts.example +14 -0
  163. package/templates/functions-firebase/functions-firebase/src/index.ts.example +45 -0
  164. package/templates/functions-firebase/functions-firebase/src/oauth/checkGitHubAccess.ts.example +14 -0
  165. package/templates/functions-firebase/functions-firebase/src/oauth/disconnect.ts.example +14 -0
  166. package/templates/functions-firebase/functions-firebase/src/oauth/exchangeToken.ts.example +14 -0
  167. package/templates/functions-firebase/functions-firebase/src/oauth/getConnections.ts.example +14 -0
  168. package/templates/functions-firebase/functions-firebase/src/oauth/grantGitHubAccess.ts.example +14 -0
  169. package/templates/functions-firebase/functions-firebase/src/oauth/index.ts.example +17 -0
  170. package/templates/functions-firebase/functions-firebase/src/oauth/refreshToken.ts.example +14 -0
  171. package/templates/functions-firebase/functions-firebase/src/oauth/revokeGitHubAccess.ts.example +14 -0
  172. package/templates/functions-firebase/functions-firebase/tsconfig.json.example +21 -0
  173. package/templates/functions-firebase/functions.yaml.example +14 -0
  174. package/templates/functions-firebase/src/auth/getCustomClaims.ts.example +19 -0
  175. package/templates/functions-firebase/src/auth/getUserAuthStatus.ts.example +21 -0
  176. package/templates/functions-firebase/src/auth/index.ts.example +11 -0
  177. package/templates/functions-firebase/src/auth/removeCustomClaims.ts.example +21 -0
  178. package/templates/functions-firebase/src/auth/setCustomClaims.ts.example +21 -0
  179. package/templates/functions-firebase/src/billing/handleStripeWebhook.ts.example +24 -0
  180. package/templates/functions-firebase/src/billing/index.ts.example +10 -0
  181. package/templates/functions-firebase/src/billing/processPaymentSuccess.ts.example +14 -0
  182. package/templates/functions-firebase/src/billing/refreshSubscriptionStatus.ts.example +14 -0
  183. package/templates/functions-firebase/src/crud/createEntity.ts.example +19 -0
  184. package/templates/functions-firebase/src/crud/deleteEntity.ts.example +14 -0
  185. package/templates/functions-firebase/src/crud/getEntity.ts.example +14 -0
  186. package/templates/functions-firebase/src/crud/index.ts.example +12 -0
  187. package/templates/functions-firebase/src/crud/listEntities.ts.example +14 -0
  188. package/templates/functions-firebase/src/crud/updateEntity.ts.example +14 -0
  189. package/templates/functions-firebase/src/index.ts.example +45 -0
  190. package/templates/functions-firebase/src/oauth/checkGitHubAccess.ts.example +14 -0
  191. package/templates/functions-firebase/src/oauth/disconnect.ts.example +14 -0
  192. package/templates/functions-firebase/src/oauth/exchangeToken.ts.example +14 -0
  193. package/templates/functions-firebase/src/oauth/getConnections.ts.example +14 -0
  194. package/templates/functions-firebase/src/oauth/grantGitHubAccess.ts.example +14 -0
  195. package/templates/functions-firebase/src/oauth/index.ts.example +17 -0
  196. package/templates/functions-firebase/src/oauth/refreshToken.ts.example +14 -0
  197. package/templates/functions-firebase/src/oauth/revokeGitHubAccess.ts.example +14 -0
  198. package/templates/functions-firebase/tsconfig.json.example +24 -0
  199. package/templates/functions-vercel/README.md.example +116 -0
  200. package/templates/functions-vercel/build.mjs.example +52 -0
  201. package/templates/functions-vercel/functions-vercel/.env.example.example +37 -0
  202. package/templates/functions-vercel/functions-vercel/README.md.example +116 -0
  203. package/templates/functions-vercel/functions-vercel/build.mjs.example +52 -0
  204. package/templates/functions-vercel/functions-vercel/src/api/auth/getCustomClaims.ts.example +20 -0
  205. package/templates/functions-vercel/functions-vercel/src/api/auth/getUserAuthStatus.ts.example +20 -0
  206. package/templates/functions-vercel/functions-vercel/src/api/auth/removeCustomClaims.ts.example +20 -0
  207. package/templates/functions-vercel/functions-vercel/src/api/auth/setCustomClaims.ts.example +20 -0
  208. package/templates/functions-vercel/functions-vercel/src/api/billing/handleStripeWebhook.ts.example +20 -0
  209. package/templates/functions-vercel/functions-vercel/src/api/billing/processPaymentSuccess.ts.example +20 -0
  210. package/templates/functions-vercel/functions-vercel/src/api/billing/refreshSubscriptionStatus.ts.example +20 -0
  211. package/templates/functions-vercel/functions-vercel/src/api/crud/createEntity.ts.example +20 -0
  212. package/templates/functions-vercel/functions-vercel/src/api/crud/deleteEntity.ts.example +20 -0
  213. package/templates/functions-vercel/functions-vercel/src/api/crud/getEntity.ts.example +20 -0
  214. package/templates/functions-vercel/functions-vercel/src/api/crud/listEntities.ts.example +20 -0
  215. package/templates/functions-vercel/functions-vercel/src/api/crud/updateEntity.ts.example +20 -0
  216. package/templates/functions-vercel/functions-vercel/src/api/oauth/checkGitHubAccess.ts.example +20 -0
  217. package/templates/functions-vercel/functions-vercel/src/api/oauth/disconnect.ts.example +20 -0
  218. package/templates/functions-vercel/functions-vercel/src/api/oauth/exchangeToken.ts.example +20 -0
  219. package/templates/functions-vercel/functions-vercel/src/api/oauth/getConnections.ts.example +20 -0
  220. package/templates/functions-vercel/functions-vercel/src/api/oauth/grantGitHubAccess.ts.example +20 -0
  221. package/templates/functions-vercel/functions-vercel/src/api/oauth/refreshToken.ts.example +20 -0
  222. package/templates/functions-vercel/functions-vercel/src/api/oauth/revokeGitHubAccess.ts.example +20 -0
  223. package/templates/functions-vercel/functions-vercel/tsconfig.json.example +21 -0
  224. package/templates/functions-vercel/functions-vercel/vercel.json.example +14 -0
  225. package/templates/functions-vercel/src/api/auth/getCustomClaims.ts.example +20 -0
  226. package/templates/functions-vercel/src/api/auth/getUserAuthStatus.ts.example +20 -0
  227. package/templates/functions-vercel/src/api/auth/removeCustomClaims.ts.example +20 -0
  228. package/templates/functions-vercel/src/api/auth/setCustomClaims.ts.example +20 -0
  229. package/templates/functions-vercel/src/api/billing/handleStripeWebhook.ts.example +20 -0
  230. package/templates/functions-vercel/src/api/billing/processPaymentSuccess.ts.example +20 -0
  231. package/templates/functions-vercel/src/api/billing/refreshSubscriptionStatus.ts.example +20 -0
  232. package/templates/functions-vercel/src/api/crud/createEntity.ts.example +20 -0
  233. package/templates/functions-vercel/src/api/crud/deleteEntity.ts.example +20 -0
  234. package/templates/functions-vercel/src/api/crud/getEntity.ts.example +20 -0
  235. package/templates/functions-vercel/src/api/crud/listEntities.ts.example +20 -0
  236. package/templates/functions-vercel/src/api/crud/updateEntity.ts.example +20 -0
  237. package/templates/functions-vercel/src/api/oauth/checkGitHubAccess.ts.example +20 -0
  238. package/templates/functions-vercel/src/api/oauth/disconnect.ts.example +20 -0
  239. package/templates/functions-vercel/src/api/oauth/exchangeToken.ts.example +20 -0
  240. package/templates/functions-vercel/src/api/oauth/getConnections.ts.example +20 -0
  241. package/templates/functions-vercel/src/api/oauth/grantGitHubAccess.ts.example +20 -0
  242. package/templates/functions-vercel/src/api/oauth/refreshToken.ts.example +20 -0
  243. package/templates/functions-vercel/src/api/oauth/revokeGitHubAccess.ts.example +20 -0
  244. package/templates/functions-vercel/tsconfig.json.example +24 -0
  245. package/templates/functions-vercel/vercel.json.example +14 -0
  246. package/templates/github/github/workflows/firebase-deploy.yml.example +79 -0
  247. package/templates/github/workflows/firebase-deploy.yml.example +79 -0
  248. package/templates/root-consumer/.env.example +19 -0
  249. package/templates/root-consumer/.gitignore.example +82 -0
  250. package/templates/root-consumer/.prettierrc.cjs.example +12 -0
  251. package/templates/root-consumer/CLAUDE.md.example +73 -0
  252. package/templates/root-consumer/README.md.example +295 -0
  253. package/templates/root-consumer/bunfig.toml.example +68 -0
  254. package/templates/root-consumer/eslint.config.js.example +336 -0
  255. package/templates/root-consumer/firebase.json.example +348 -0
  256. package/templates/root-consumer/guides/AGENT_START_HERE.md.example +98 -0
  257. package/templates/root-consumer/guides/APP_CHECK_SETUP.md.example +111 -0
  258. package/templates/root-consumer/guides/AUTH_SETUP.md.example +92 -0
  259. package/templates/root-consumer/guides/BILLING_SETUP.md.example +120 -0
  260. package/templates/root-consumer/guides/CLI.md.example +293 -0
  261. package/templates/root-consumer/guides/COMPONENTS.md.example +875 -0
  262. package/templates/root-consumer/guides/CONFIG_SETUP.md.example +132 -0
  263. package/templates/root-consumer/guides/EMULATOR_SETUP.md.example +48 -0
  264. package/templates/root-consumer/guides/FEATURES.md.example +286 -0
  265. package/templates/root-consumer/guides/FRAMEWORK_OVERVIEW.md.example +97 -0
  266. package/templates/root-consumer/guides/FUNCTIONS.md.example +177 -0
  267. package/templates/root-consumer/guides/GETTING_STARTED.md.example +451 -0
  268. package/templates/root-consumer/guides/HOW_TO_USE.md.example +296 -0
  269. package/templates/root-consumer/guides/I18N_SETUP.md.example +204 -0
  270. package/templates/root-consumer/guides/IMPORT_PATTERNS.md.example +79 -0
  271. package/templates/root-consumer/guides/INDEX.md.example +50 -0
  272. package/templates/root-consumer/guides/INSTALLATION.md.example +296 -0
  273. package/templates/root-consumer/guides/LAYOUTS.md.example +310 -0
  274. package/templates/root-consumer/guides/PAGES_SETUP.md.example +123 -0
  275. package/templates/root-consumer/guides/STYLING.md.example +273 -0
  276. package/templates/root-consumer/guides/THEMING_SETUP.md.example +119 -0
  277. package/templates/root-consumer/guides/VERSION_CONTROL.md.example +181 -0
  278. package/templates/root-consumer/tsconfig.functions.json.example +15 -0
  279. package/templates/root-consumer/tsconfig.json.example +18 -0
  280. package/templates/root-consumer/turbo.json.example +46 -0
  281. package/templates/root-consumer/vercel.json.example +124 -0
@@ -0,0 +1,79 @@
1
+ // apps/demo/src/pages/HomePage.tsx
2
+
3
+ import { useMemo } from 'react';
4
+ import { useNavigate, useOutletContext } from 'react-router-dom';
5
+
6
+ import {
7
+ Badge,
8
+ Card,
9
+ Grid,
10
+ Section,
11
+ Stack,
12
+ } from '@donotdev/components';
13
+
14
+ import {
15
+ COMPONENT_CONFIGS,
16
+ getCSSFamilies,
17
+ } from './components/componentConfig';
18
+ import type { CSSFamily } from './components/ComponentsData';
19
+
20
+ type LayoutContext = {
21
+ selectedTab: CSSFamily | 'all';
22
+ searchQuery: string;
23
+ };
24
+
25
+ export default function HomePage() {
26
+ const navigate = useNavigate();
27
+ const {
28
+ selectedTab,
29
+ searchQuery,
30
+ } = useOutletContext<LayoutContext>();
31
+
32
+ const componentsInTab = useMemo(() => {
33
+ return COMPONENT_CONFIGS.filter((config) => {
34
+ if (selectedTab !== 'all' && config.cssFamily !== selectedTab)
35
+ return false;
36
+
37
+ const matchesSearch =
38
+ searchQuery === '' ||
39
+ config.name.toLowerCase().includes(searchQuery.toLowerCase());
40
+
41
+ return matchesSearch;
42
+ }).sort((a, b) => a.name.localeCompare(b.name));
43
+ }, [selectedTab, searchQuery]);
44
+
45
+ const cssFamilies = getCSSFamilies();
46
+
47
+ return (
48
+ <Section
49
+ title={
50
+ cssFamilies.find((f) => f.id === selectedTab)?.label ||
51
+ 'Components'
52
+ }
53
+ subtitle={`${componentsInTab.length} components`}
54
+ >
55
+ <Grid cols="auto-fit" minColWidth="240px" gap="medium">
56
+ {componentsInTab.map((config) => {
57
+ const isFullPageComponent = config.cssFamily === 'layout';
58
+ return (
59
+ <Card
60
+ key={config.id}
61
+ title={config.name}
62
+ onClick={() =>
63
+ isFullPageComponent
64
+ ? navigate('/full')
65
+ : navigate(`/component/${config.id}`)
66
+ }
67
+ >
68
+ <Stack direction="row" justify="end">
69
+ <Badge variant="secondary">
70
+ {cssFamilies.find((f) => f.id === config.cssFamily)?.label || config.cssFamily}
71
+ </Badge>
72
+ </Stack>
73
+ </Card>
74
+ );
75
+ })}
76
+ </Grid>
77
+ </Section>
78
+ );
79
+ }
@@ -0,0 +1,511 @@
1
+ // apps/demo/src/pages/components/ComponentRenderer.tsx
2
+ // Data-driven component renderer - no special cases
3
+
4
+ import { useState } from 'react';
5
+ import type { ReactNode } from 'react';
6
+ import {
7
+ Button,
8
+ Card,
9
+ Combobox,
10
+ Command,
11
+ Stack,
12
+ Text,
13
+ Select,
14
+ Input,
15
+ Spinner,
16
+ useToast,
17
+ TOAST_DURATIONS,
18
+ type CommandGroup,
19
+ } from '@donotdev/components';
20
+
21
+ import { PROP_VALUES } from './ComponentsData';
22
+ import type { ComponentConfig } from './componentConfig';
23
+
24
+ interface ComponentRendererProps {
25
+ config: ComponentConfig;
26
+ variantProps?: Record<string, any>;
27
+ }
28
+
29
+ const PROP_TYPE_TO_PROP_NAME: Record<string, string> = {
30
+ accordionItems: 'items',
31
+ tabsItems: 'items',
32
+ listItems: 'items',
33
+ navigationItems: 'items',
34
+ commandGroups: 'groups',
35
+ descriptionListItems: 'items',
36
+ demoItems: 'items',
37
+ avatarSrc: 'src',
38
+ avatarFallback: 'fallback',
39
+ selectOptions: 'options',
40
+ comboboxOptions: 'options',
41
+ radioGroupItems: 'items',
42
+ toggleGroupItems: 'items',
43
+ };
44
+
45
+ /**
46
+ * Generic state wrapper for controlled components
47
+ * Returns [value, onChange, additionalProps]
48
+ */
49
+ function useComponentState(config: ComponentConfig, variantProps: Record<string, any>): [any, ((val: any) => void) | undefined, Record<string, any>] {
50
+ const { stateType, defaultStateValue } = config;
51
+
52
+ if (!stateType || stateType === 'custom') {
53
+ return [undefined, undefined, {}];
54
+ }
55
+
56
+ switch (stateType) {
57
+ case 'controlled-value': {
58
+ const [value, setValue] = useState<string | string[]>(defaultStateValue ?? '');
59
+ return [value, setValue, {}];
60
+ }
61
+ case 'controlled-checked': {
62
+ const [checked, setChecked] = useState<boolean>(defaultStateValue ?? false);
63
+ return [checked, setChecked, {}];
64
+ }
65
+ case 'controlled-pressed': {
66
+ const [pressed, setPressed] = useState<boolean>(defaultStateValue ?? false);
67
+ return [pressed, setPressed, {}];
68
+ }
69
+ case 'controlled-range': {
70
+ const [value, setValue] = useState<number[]>(defaultStateValue ?? [2]);
71
+ return [value, setValue, {}];
72
+ }
73
+ case 'controlled-date': {
74
+ const [selected, setSelected] = useState<Date | undefined>(defaultStateValue ?? new Date());
75
+ return [selected, setSelected, { mode: 'single' }];
76
+ }
77
+ case 'controlled-dates': {
78
+ const [selected, setSelected] = useState<Date[]>(defaultStateValue ?? []);
79
+ return [selected, setSelected, { mode: 'multiple' }];
80
+ }
81
+ case 'controlled-date-range': {
82
+ const [selected, setSelected] = useState<{ from?: Date; to?: Date }>(defaultStateValue ?? {});
83
+ return [selected, setSelected, { mode: 'range' }];
84
+ }
85
+ default:
86
+ return [undefined, undefined, {}];
87
+ }
88
+ }
89
+
90
+ export function ComponentRenderer({
91
+ config,
92
+ variantProps = {},
93
+ }: ComponentRendererProps) {
94
+ const Component = config.component;
95
+ const [selectedDate, setSelectedDate] = useState<Date | undefined>(
96
+ config.id === 'calendar' && variantProps.mode === 'single' ? new Date() : undefined
97
+ );
98
+ const [selectedDates, setSelectedDates] = useState<Date[]>(
99
+ config.id === 'calendar' && variantProps.mode === 'multiple' ? [] : []
100
+ );
101
+ const [selectedRange, setSelectedRange] = useState<{ from?: Date; to?: Date }>(
102
+ config.id === 'calendar' && variantProps.mode === 'range' ? {} : {}
103
+ );
104
+ const [sheetOpen, setSheetOpen] = useState<boolean>(false);
105
+ const [dialogOpen, setDialogOpen] = useState<boolean>(false);
106
+ const [alertDialogOpen, setAlertDialogOpen] = useState<boolean>(false);
107
+ const [commandDialogOpen, setCommandDialogOpen] = useState<boolean>(false);
108
+ const [tabCount, setTabCount] = useState<number>(2);
109
+ const [generatedTabsItems, setGeneratedTabsItems] = useState<Array<{ value: string; label: string; content: string }> | null>(null);
110
+ const [activeOverlayVariant, setActiveOverlayVariant] = useState<string | null>(null);
111
+
112
+ if (config.layoutDescription) {
113
+ return (
114
+ <Card
115
+ title={config.name}
116
+ variant="muted"
117
+ subtitle={config.layoutDescription || `Layout component: ${config.name}`}
118
+ >
119
+ <Text variant="muted">
120
+ {config.notes || 'This is a layout component. Use it to structure your page content.'}
121
+ </Text>
122
+ </Card>
123
+ );
124
+ }
125
+
126
+ const componentProps: Record<string, any> = {
127
+ ...variantProps,
128
+ ...config.customProps,
129
+ };
130
+
131
+ if (config.propTypes) {
132
+ for (const propType of config.propTypes) {
133
+ const value = PROP_VALUES[propType as keyof typeof PROP_VALUES];
134
+ if (value !== undefined) {
135
+ const propName = PROP_TYPE_TO_PROP_NAME[propType] || propType;
136
+
137
+ if (propType === 'accordionItems' && Array.isArray(value)) {
138
+ componentProps[propName] = value.map((item) => {
139
+ if (typeof item === 'object' && item !== null && 'trigger' in item && typeof item.trigger === 'string') {
140
+ const triggerContent = config.supportsCommonProps.icon ? (
141
+ <Stack direction="row" gap="tight" align="center">
142
+ <PROP_VALUES.icon className="dndev-size-md" />
143
+ <Text>{item.trigger}</Text>
144
+ </Stack>
145
+ ) : (
146
+ <Text>{item.trigger}</Text>
147
+ );
148
+ return {
149
+ ...item,
150
+ trigger: triggerContent,
151
+ };
152
+ }
153
+ return item;
154
+ });
155
+ } else if (propType === 'collapsibleContent') {
156
+ componentProps.children = value;
157
+ } else if (propType === 'commandGroups' && config.id === 'command-dialog') {
158
+ // CommandDialog needs Command component as children
159
+ // Type assertion: commandGroups propType always returns CommandGroup[]
160
+ componentProps.children = <Command groups={value as CommandGroup[]} />;
161
+ } else if (propType === 'tabsItems' && Array.isArray(value)) {
162
+ // Use generated tabs if available, otherwise use default
163
+ const tabsToUse = generatedTabsItems || (value as Array<{ value: string; label: string; content: string | ReactNode }>);
164
+ // Tabs needs items with content as ReactNode
165
+ if (tabsToUse && tabsToUse.length > 0) {
166
+ componentProps.items = tabsToUse.map((item) => ({
167
+ ...item,
168
+ content: typeof item.content === 'string' ? <Text>{item.content}</Text> : item.content,
169
+ }));
170
+ // Set default value to first tab if not provided
171
+ if (!componentProps.defaultValue && !componentProps.value && tabsToUse[0]) {
172
+ componentProps.defaultValue = tabsToUse[0].value;
173
+ }
174
+ }
175
+ } else {
176
+ componentProps[propName] = value;
177
+ }
178
+ }
179
+ }
180
+ }
181
+
182
+ if (config.supportsCommonProps.content) {
183
+ const usesChildren = ['button', 'badge', 'toggle', 'label', 'text', 'collapsible', 'dialog', 'sheet', 'popover', 'hover-card'].includes(config.id);
184
+ const shortLabelComponents = ['badge', 'button'];
185
+ const contentValue = shortLabelComponents.includes(config.id) ? PROP_VALUES.shortLabel : PROP_VALUES.content;
186
+ if (usesChildren) {
187
+ componentProps.children = contentValue;
188
+ } else if (config.id !== 'tooltip') {
189
+ componentProps.content = contentValue;
190
+ }
191
+ }
192
+
193
+ if (config.id === 'button' && config.supportsCommonProps.icon) {
194
+ componentProps.icon = PROP_VALUES.icon;
195
+ }
196
+
197
+ if (config.needsTrigger) {
198
+ const triggerText = config.triggerText || PROP_VALUES.trigger;
199
+ const buttonVariant = variantProps.variant && config.variants?.variant?.includes(variantProps.variant)
200
+ ? variantProps.variant
201
+ : undefined;
202
+ const triggerButton = <Button icon={PROP_VALUES.icon} variant={buttonVariant}>{triggerText}</Button>;
203
+
204
+ if (config.id === 'tooltip') {
205
+ componentProps.children = triggerButton;
206
+ if (config.supportsCommonProps.content) {
207
+ componentProps.content = PROP_VALUES.content;
208
+ }
209
+ } else {
210
+ componentProps.trigger = triggerButton;
211
+ }
212
+ }
213
+
214
+ // Generic state management for controlled components
215
+ const [stateValue, setStateValue, stateProps] = useComponentState(config, variantProps);
216
+
217
+ // Wire up state to component props based on stateType
218
+ if (config.stateType && config.stateType !== 'custom') {
219
+ if (config.stateType === 'controlled-value') {
220
+ componentProps.value = stateValue;
221
+ componentProps.onValueChange = setStateValue;
222
+ } else if (config.stateType === 'controlled-checked') {
223
+ componentProps.checked = stateValue;
224
+ componentProps.onCheckedChange = setStateValue;
225
+ } else if (config.stateType === 'controlled-pressed') {
226
+ componentProps.pressed = stateValue;
227
+ componentProps.onPressedChange = setStateValue;
228
+ } else if (config.stateType === 'controlled-range') {
229
+ componentProps.value = stateValue;
230
+ componentProps.onValueChange = setStateValue;
231
+ } else if (config.stateType.startsWith('controlled-date')) {
232
+ componentProps.selected = stateValue;
233
+ componentProps.onSelect = setStateValue;
234
+ Object.assign(componentProps, stateProps);
235
+ }
236
+ }
237
+
238
+ // Custom rendering modes for special components
239
+ if (config.id === 'calendar') {
240
+ const mode = variantProps.mode || 'single';
241
+ componentProps.mode = mode;
242
+
243
+ if (mode === 'single') {
244
+ componentProps.selected = selectedDate;
245
+ componentProps.onSelect = setSelectedDate;
246
+ } else if (mode === 'multiple') {
247
+ componentProps.selected = selectedDates;
248
+ componentProps.onSelect = setSelectedDates;
249
+ } else if (mode === 'range') {
250
+ componentProps.selected = selectedRange;
251
+ componentProps.onSelect = setSelectedRange;
252
+ }
253
+ }
254
+
255
+ // Special handling for Pagination (needs state for currentPage)
256
+ if (config.id === 'pagination') {
257
+ const [currentPage, setCurrentPage] = useState<number>(1);
258
+ return (
259
+ <Stack align="center" justify="center">
260
+ <Component
261
+ {...componentProps}
262
+ currentPage={currentPage}
263
+ totalPages={10}
264
+ onPageChange={setCurrentPage}
265
+ />
266
+ </Stack>
267
+ );
268
+ }
269
+
270
+ // Special handling for InfiniteScroll (truly infinite - loops through items)
271
+ if (config.id === 'infinite-scroll') {
272
+ const baseItems = componentProps.items || [];
273
+ const [displayedItems, setDisplayedItems] = useState<string[]>(baseItems);
274
+
275
+ const loadMore = () => {
276
+ // Instantly add more items by looping through base items
277
+ const currentIndex = displayedItems.length % baseItems.length;
278
+ const itemsToAdd = baseItems.slice(currentIndex, currentIndex + 5);
279
+ // If we need more items than available, loop back to start
280
+ const remainingNeeded = 5 - itemsToAdd.length;
281
+ const loopedItems = remainingNeeded > 0 ? baseItems.slice(0, remainingNeeded) : [];
282
+ setDisplayedItems(prev => [...prev, ...itemsToAdd, ...loopedItems]);
283
+ };
284
+
285
+ const renderItem = (item: string, index: number) => (
286
+ <Card title={item} variant="muted">
287
+ <Text variant="muted">Item #{index + 1}: {item}</Text>
288
+ </Card>
289
+ );
290
+
291
+ const { items: _, renderItem: __, ...restProps } = componentProps;
292
+
293
+ return (
294
+ <Component
295
+ items={displayedItems}
296
+ renderItem={renderItem}
297
+ loadMore={loadMore}
298
+ hasMore={true}
299
+ loading={false}
300
+ {...restProps}
301
+ />
302
+ );
303
+ }
304
+
305
+ // Render demo content if provided in config
306
+ if (config.demoContent && config.stateType === 'controlled-value') {
307
+ const demoValue = stateValue ?? config.defaultStateValue ?? '';
308
+ return (
309
+ <Stack gap="large" align="center">
310
+ <Component
311
+ {...componentProps}
312
+ value={demoValue}
313
+ onValueChange={(value: string | string[] | undefined) => {
314
+ if (value !== undefined && setStateValue) {
315
+ setStateValue(value);
316
+ }
317
+ }}
318
+ />
319
+ {config.demoContent(demoValue, setStateValue || (() => {}))}
320
+ </Stack>
321
+ );
322
+ }
323
+
324
+ // Special handling for Toaster (useToast hook demo)
325
+ if (config.id === 'toaster') {
326
+ const { toast } = useToast();
327
+ const [message, setMessage] = useState<string>('');
328
+ const [duration, setDuration] = useState<string>('5000');
329
+
330
+ const toastTypes: Array<{ type: 'default' | 'success' | 'error' | 'warning' | 'info'; label: string }> = [
331
+ { type: 'default', label: 'Default' },
332
+ { type: 'success', label: 'Success' },
333
+ { type: 'error', label: 'Error' },
334
+ { type: 'warning', label: 'Warning' },
335
+ { type: 'info', label: 'Info' },
336
+ ];
337
+
338
+ const durationOptions = [
339
+ { value: '0', label: 'Forever (0ms)' },
340
+ { value: '3000', label: '3 seconds' },
341
+ { value: '4000', label: '4 seconds' },
342
+ { value: '5000', label: '5 seconds' },
343
+ { value: '6000', label: '6 seconds' },
344
+ { value: '7000', label: '7 seconds' },
345
+ ];
346
+
347
+ const durationValue = parseInt(duration, 10);
348
+
349
+ return (
350
+ <Stack gap="large" align="center" justify="center">
351
+ <Stack gap="medium" className="dndev-w-full dndev-max-w-md">
352
+ <Stack direction="row" gap="tight" align="end">
353
+ <Input
354
+ placeholder="Enter toast message..."
355
+ value={message}
356
+ onChange={(e) => setMessage(e.target.value)}
357
+ onKeyDown={(e) => {
358
+ if (e.key === 'Enter' && message.trim()) {
359
+ toast({ ...(message.trim() ? { title: message } : {}), duration: durationValue });
360
+ setMessage('');
361
+ }
362
+ }}
363
+ />
364
+ <Button
365
+ onClick={() => {
366
+ if (message.trim()) {
367
+ toast({ ...(message.trim() ? { title: message } : {}), duration: durationValue });
368
+ setMessage('');
369
+ }
370
+ }}
371
+ >
372
+ Show Toast
373
+ </Button>
374
+ </Stack>
375
+ <Select
376
+ value={duration}
377
+ onValueChange={setDuration}
378
+ placeholder="Select duration..."
379
+ options={durationOptions}
380
+ />
381
+ <Text variant="muted" className="dndev-text-center">
382
+ Or try different toast types:
383
+ </Text>
384
+ <Stack direction="column" gap="tight" wrap="wrap">
385
+ {toastTypes.map(({ type, label }) => (
386
+ <Button
387
+ key={type}
388
+ variant={type === 'error' ? 'destructive' : type === 'success' ? 'primary' : 'outline'}
389
+ onClick={() => {
390
+ toast({
391
+ title: `${label} Toast`,
392
+ description: message.trim() || `This is a ${type} notification`,
393
+ toastType: type,
394
+ duration: durationValue,
395
+ });
396
+ }}
397
+ >
398
+ {label}
399
+ </Button>
400
+ ))}
401
+ </Stack>
402
+ </Stack>
403
+ </Stack>
404
+ );
405
+ }
406
+
407
+ // Special handling for Sheet/Dialog/AlertDialog/CommandDialog (controlled state)
408
+ if (config.id === 'sheet') {
409
+ componentProps.open = sheetOpen;
410
+ componentProps.onOpenChange = setSheetOpen;
411
+ } else if (config.id === 'dialog') {
412
+ componentProps.open = dialogOpen;
413
+ componentProps.onOpenChange = setDialogOpen;
414
+ } else if (config.id === 'alert-dialog') {
415
+ componentProps.open = alertDialogOpen;
416
+ componentProps.onOpenChange = setAlertDialogOpen;
417
+ } else if (config.id === 'command-dialog') {
418
+ componentProps.open = commandDialogOpen;
419
+ componentProps.onOpenChange = setCommandDialogOpen;
420
+ }
421
+
422
+ const handleGenerateTabs = () => {
423
+ const count = Math.max(1, Math.min(50, tabCount));
424
+ const newTabs = Array.from({ length: count }, (_, i) => ({
425
+ value: `tab${i + 1}`,
426
+ label: `Tab ${i + 1}`,
427
+ content: `Content for Tab ${i + 1}. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.`,
428
+ }));
429
+ setGeneratedTabsItems(newTabs);
430
+ };
431
+
432
+ try {
433
+ if (config.id === 'tabs') {
434
+ return (
435
+ <Stack gap="medium" align="stretch">
436
+ <Stack direction="row" gap="medium" align="center">
437
+ <Input
438
+ type="number"
439
+ min={1}
440
+ max={50}
441
+ value={tabCount}
442
+ onChange={(e) => setTabCount(Number(e.target.value) || 2)}
443
+ style={{ width: '120px' }}
444
+ />
445
+ <Button onClick={handleGenerateTabs}>Generate Tabs</Button>
446
+ </Stack>
447
+ <Component {...componentProps} />
448
+ </Stack>
449
+ );
450
+ }
451
+ if (config.id === 'spinner') {
452
+ const currentVariant = variantProps.variant || componentProps.variant || 'primary';
453
+ const isActive = activeOverlayVariant === currentVariant;
454
+ return (
455
+ <>
456
+ <Stack gap="medium" align="center" justify="center" style={{ minHeight: '200px', position: 'relative', zIndex: 10000 }}>
457
+ <Button
458
+ variant="ghost"
459
+ onClick={() => {
460
+ if (isActive) {
461
+ setActiveOverlayVariant(null);
462
+ } else {
463
+ setActiveOverlayVariant(currentVariant);
464
+ }
465
+ }}
466
+ icon={<Spinner variant={currentVariant as any} />}
467
+ >
468
+ {isActive ? 'Stop Overlay' : 'Start Overlay'}
469
+ </Button>
470
+ </Stack>
471
+ {isActive && (
472
+ <Component {...componentProps} overlay variant={currentVariant as any} />
473
+ )}
474
+ </>
475
+ );
476
+ }
477
+ if (config.id === 'hero-section') {
478
+ return <Component {...componentProps} />;
479
+ }
480
+
481
+ if (config.showStateLabel && config.stateType) {
482
+ let stateLabel = '';
483
+ if (config.stateType === 'controlled-pressed') {
484
+ stateLabel = stateValue ? 'On' : 'Off';
485
+ } else if (config.stateType === 'controlled-checked') {
486
+ stateLabel = stateValue ? 'On' : 'Off';
487
+ } else if (config.stateType === 'controlled-value') {
488
+ stateLabel = String(stateValue || '');
489
+ }
490
+
491
+ return (
492
+ <Stack direction="row" align="center" gap="medium">
493
+ <Component {...componentProps} />
494
+ <Text variant="muted">State: {stateLabel}</Text>
495
+ </Stack>
496
+ );
497
+ }
498
+
499
+ return (
500
+ <Stack align="center" justify="center">
501
+ <Component {...componentProps} />
502
+ </Stack>
503
+ );
504
+ } catch (error) {
505
+ return (
506
+ <Text variant="destructive">
507
+ Error: {String(error)}
508
+ </Text>
509
+ );
510
+ }
511
+ }