virastack 0.0.1 → 1.0.1

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 (447) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +94 -18
  3. package/bin/virastack.js +7 -0
  4. package/package.json +43 -9
  5. package/src/commands/add.js +64 -0
  6. package/src/commands/init.js +286 -0
  7. package/src/i18n.js +231 -0
  8. package/src/index.js +64 -0
  9. package/src/utils/args.js +60 -0
  10. package/src/utils/copy-template.js +81 -0
  11. package/src/utils/exec.js +29 -0
  12. package/src/utils/git.js +38 -0
  13. package/src/utils/is-online.js +14 -0
  14. package/src/utils/package-info.js +12 -0
  15. package/src/utils/package-manager.js +33 -0
  16. package/src/utils/setup-env.js +25 -0
  17. package/src/utils/telemetry.js +86 -0
  18. package/src/utils/tools.js +48 -0
  19. package/src/utils/update-package-json.js +44 -0
  20. package/src/utils/update-readme.js +25 -0
  21. package/src/utils/validate-project-name.js +26 -0
  22. package/templates/nextjs/.changeset/README.md +8 -0
  23. package/templates/nextjs/.changeset/config.json +11 -0
  24. package/templates/nextjs/.env.example +6 -0
  25. package/templates/nextjs/.env.local +6 -0
  26. package/templates/nextjs/.eslintcache +1 -0
  27. package/templates/nextjs/.github/workflows/ci.yml +41 -0
  28. package/templates/nextjs/.husky/commit-msg +1 -0
  29. package/templates/nextjs/.husky/pre-commit +1 -0
  30. package/templates/nextjs/.husky/pre-push +1 -0
  31. package/templates/nextjs/.prettierignore +6 -0
  32. package/templates/nextjs/.prettierrc +42 -0
  33. package/templates/nextjs/.vscode/extensions.json +7 -0
  34. package/templates/nextjs/.vscode/settings.json +20 -0
  35. package/templates/nextjs/LICENSE +21 -0
  36. package/templates/nextjs/README.md +202 -0
  37. package/templates/nextjs/_gitignore +45 -0
  38. package/templates/nextjs/commitlint.config.js +6 -0
  39. package/templates/nextjs/eslint.config.mjs +27 -0
  40. package/templates/nextjs/knip.config.js +25 -0
  41. package/templates/nextjs/next-env.d.ts +6 -0
  42. package/templates/nextjs/next.config.ts +39 -0
  43. package/templates/nextjs/package.json +115 -0
  44. package/templates/nextjs/pnpm-lock.yaml +6467 -0
  45. package/templates/nextjs/pnpm-workspace.yaml +3 -0
  46. package/templates/nextjs/postcss.config.mjs +7 -0
  47. package/templates/nextjs/public/favicon.ico +0 -0
  48. package/templates/nextjs/public/llms.txt +96 -0
  49. package/templates/nextjs/public/logo.png +0 -0
  50. package/templates/nextjs/public/logo.webp +0 -0
  51. package/templates/nextjs/public/og.png +0 -0
  52. package/templates/nextjs/src/app/error.tsx +34 -0
  53. package/templates/nextjs/src/app/favicon.ico +0 -0
  54. package/templates/nextjs/src/app/global-error.tsx +32 -0
  55. package/templates/nextjs/src/app/layout.tsx +37 -0
  56. package/templates/nextjs/src/app/loading.tsx +12 -0
  57. package/templates/nextjs/src/app/manifest.ts +22 -0
  58. package/templates/nextjs/src/app/not-found.tsx +18 -0
  59. package/templates/nextjs/src/app/page.tsx +5 -0
  60. package/templates/nextjs/src/app/robots.ts +13 -0
  61. package/templates/nextjs/src/app/sitemap.ts +14 -0
  62. package/templates/nextjs/src/components/shared/ThemeToggle.tsx +30 -0
  63. package/templates/nextjs/src/components/ui/avatar.tsx +54 -0
  64. package/templates/nextjs/src/components/ui/button.tsx +46 -0
  65. package/templates/nextjs/src/components/ui/dialog.tsx +107 -0
  66. package/templates/nextjs/src/components/ui/field.tsx +24 -0
  67. package/templates/nextjs/src/components/ui/index.ts +27 -0
  68. package/templates/nextjs/src/components/ui/input.tsx +23 -0
  69. package/templates/nextjs/src/components/ui/label.tsx +17 -0
  70. package/templates/nextjs/src/components/ui/skeleton.tsx +13 -0
  71. package/templates/nextjs/src/components/ui/table.tsx +94 -0
  72. package/templates/nextjs/src/components/ui/tabs.tsx +46 -0
  73. package/templates/nextjs/src/config/seo.config.ts +37 -0
  74. package/templates/nextjs/src/config/site.config.ts +15 -0
  75. package/templates/nextjs/src/constants/index.ts +5 -0
  76. package/templates/nextjs/src/env.ts +41 -0
  77. package/templates/nextjs/src/features/landing/api/get-users.api.ts +7 -0
  78. package/templates/nextjs/src/features/landing/api/index.ts +2 -0
  79. package/templates/nextjs/src/features/landing/api/query-keys.ts +7 -0
  80. package/templates/nextjs/src/features/landing/components/CartDemo.tsx +66 -0
  81. package/templates/nextjs/src/features/landing/components/Features.tsx +39 -0
  82. package/templates/nextjs/src/features/landing/components/Hero.tsx +65 -0
  83. package/templates/nextjs/src/features/landing/components/LandingPage.tsx +17 -0
  84. package/templates/nextjs/src/features/landing/components/ProjectFormDemo.tsx +62 -0
  85. package/templates/nextjs/src/features/landing/components/Reveal.tsx +83 -0
  86. package/templates/nextjs/src/features/landing/components/Showcase.tsx +66 -0
  87. package/templates/nextjs/src/features/landing/components/UsersDemo.tsx +188 -0
  88. package/templates/nextjs/src/features/landing/data/features.data.tsx +47 -0
  89. package/templates/nextjs/src/features/landing/data/index.ts +1 -0
  90. package/templates/nextjs/src/features/landing/helpers/get-initials.ts +15 -0
  91. package/templates/nextjs/src/features/landing/helpers/index.ts +7 -0
  92. package/templates/nextjs/src/features/landing/helpers/motion.ts +21 -0
  93. package/templates/nextjs/src/features/landing/hooks/index.ts +1 -0
  94. package/templates/nextjs/src/features/landing/hooks/use-users.ts +16 -0
  95. package/templates/nextjs/src/features/landing/icons/index.ts +6 -0
  96. package/templates/nextjs/src/features/landing/icons/nextjs.tsx +68 -0
  97. package/templates/nextjs/src/features/landing/icons/react-hook-form.tsx +18 -0
  98. package/templates/nextjs/src/features/landing/icons/react.tsx +20 -0
  99. package/templates/nextjs/src/features/landing/icons/tailwind.tsx +14 -0
  100. package/templates/nextjs/src/features/landing/icons/tanstack.tsx +321 -0
  101. package/templates/nextjs/src/features/landing/icons/typescript.tsx +16 -0
  102. package/templates/nextjs/src/features/landing/index.ts +1 -0
  103. package/templates/nextjs/src/features/landing/schemas/index.ts +1 -0
  104. package/templates/nextjs/src/features/landing/schemas/project.schema.ts +7 -0
  105. package/templates/nextjs/src/features/landing/stores/counter.store.ts +18 -0
  106. package/templates/nextjs/src/features/landing/stores/index.ts +1 -0
  107. package/templates/nextjs/src/features/landing/types/index.ts +1 -0
  108. package/templates/nextjs/src/features/landing/types/user.types.ts +9 -0
  109. package/templates/nextjs/src/helpers/format-date.ts +13 -0
  110. package/templates/nextjs/src/helpers/index.ts +1 -0
  111. package/templates/nextjs/src/hooks/index.ts +5 -0
  112. package/templates/nextjs/src/lib/api.ts +97 -0
  113. package/templates/nextjs/src/lib/query-client.ts +18 -0
  114. package/templates/nextjs/src/lib/utils.ts +12 -0
  115. package/templates/nextjs/src/providers/Providers.tsx +15 -0
  116. package/templates/nextjs/src/providers/QueryProvider.tsx +19 -0
  117. package/templates/nextjs/src/providers/ThemeProvider.tsx +9 -0
  118. package/templates/nextjs/src/providers/index.ts +1 -0
  119. package/templates/nextjs/src/proxy.ts +6 -0
  120. package/templates/nextjs/src/schemas/index.ts +5 -0
  121. package/templates/nextjs/src/stores/index.ts +5 -0
  122. package/templates/nextjs/src/styles/tailwind.css +122 -0
  123. package/templates/nextjs/src/types/site-config.types.ts +10 -0
  124. package/templates/nextjs/tsconfig.json +45 -0
  125. package/templates/nextjs/tsconfig.tsbuildinfo +1 -0
  126. package/templates/tanstack/.changeset/README.md +8 -0
  127. package/templates/tanstack/.changeset/config.json +11 -0
  128. package/templates/tanstack/.env.example +6 -0
  129. package/templates/tanstack/.env.local +6 -0
  130. package/templates/tanstack/.eslintcache +1 -0
  131. package/templates/tanstack/.github/workflows/ci.yml +41 -0
  132. package/templates/tanstack/.husky/commit-msg +1 -0
  133. package/templates/tanstack/.husky/pre-commit +1 -0
  134. package/templates/tanstack/.husky/pre-push +1 -0
  135. package/templates/tanstack/.prettierignore +7 -0
  136. package/templates/tanstack/.prettierrc +41 -0
  137. package/templates/tanstack/.vscode/extensions.json +7 -0
  138. package/templates/tanstack/.vscode/settings.json +22 -0
  139. package/templates/tanstack/LICENSE +21 -0
  140. package/templates/tanstack/README.md +204 -0
  141. package/templates/tanstack/_gitignore +52 -0
  142. package/templates/tanstack/commitlint.config.js +6 -0
  143. package/templates/tanstack/eslint.config.js +28 -0
  144. package/templates/tanstack/knip.config.js +22 -0
  145. package/templates/tanstack/package.json +130 -0
  146. package/templates/tanstack/pnpm-lock.yaml +5835 -0
  147. package/templates/tanstack/pnpm-workspace.yaml +3 -0
  148. package/templates/tanstack/public/favicon.ico +0 -0
  149. package/templates/tanstack/public/llms.txt +86 -0
  150. package/templates/tanstack/public/logo.png +0 -0
  151. package/templates/tanstack/public/logo.webp +0 -0
  152. package/templates/tanstack/public/og.png +0 -0
  153. package/templates/tanstack/src/components/shared/DefaultCatchBoundary.tsx +36 -0
  154. package/templates/tanstack/src/components/shared/NotFound.tsx +18 -0
  155. package/templates/tanstack/src/components/shared/Pending.tsx +13 -0
  156. package/templates/tanstack/src/components/shared/ThemeToggle.tsx +31 -0
  157. package/templates/tanstack/src/components/ui/avatar.tsx +52 -0
  158. package/templates/tanstack/src/components/ui/button.tsx +47 -0
  159. package/templates/tanstack/src/components/ui/dialog.tsx +107 -0
  160. package/templates/tanstack/src/components/ui/field.tsx +24 -0
  161. package/templates/tanstack/src/components/ui/index.ts +27 -0
  162. package/templates/tanstack/src/components/ui/input.tsx +23 -0
  163. package/templates/tanstack/src/components/ui/label.tsx +17 -0
  164. package/templates/tanstack/src/components/ui/skeleton.tsx +13 -0
  165. package/templates/tanstack/src/components/ui/table.tsx +94 -0
  166. package/templates/tanstack/src/components/ui/tabs.tsx +46 -0
  167. package/templates/tanstack/src/config/seo.config.ts +52 -0
  168. package/templates/tanstack/src/config/site.config.ts +15 -0
  169. package/templates/tanstack/src/constants/index.ts +5 -0
  170. package/templates/tanstack/src/env.ts +47 -0
  171. package/templates/tanstack/src/features/landing/api/get-users.api.ts +7 -0
  172. package/templates/tanstack/src/features/landing/api/index.ts +2 -0
  173. package/templates/tanstack/src/features/landing/api/query-keys.ts +7 -0
  174. package/templates/tanstack/src/features/landing/components/CartDemo.tsx +66 -0
  175. package/templates/tanstack/src/features/landing/components/Features.tsx +39 -0
  176. package/templates/tanstack/src/features/landing/components/Hero.tsx +63 -0
  177. package/templates/tanstack/src/features/landing/components/LandingPage.tsx +17 -0
  178. package/templates/tanstack/src/features/landing/components/ProjectFormDemo.tsx +63 -0
  179. package/templates/tanstack/src/features/landing/components/Reveal.tsx +83 -0
  180. package/templates/tanstack/src/features/landing/components/Showcase.tsx +66 -0
  181. package/templates/tanstack/src/features/landing/components/UsersDemo.tsx +191 -0
  182. package/templates/tanstack/src/features/landing/data/features.data.tsx +45 -0
  183. package/templates/tanstack/src/features/landing/data/index.ts +1 -0
  184. package/templates/tanstack/src/features/landing/helpers/get-initials.ts +15 -0
  185. package/templates/tanstack/src/features/landing/helpers/index.ts +7 -0
  186. package/templates/tanstack/src/features/landing/helpers/motion.ts +21 -0
  187. package/templates/tanstack/src/features/landing/hooks/index.ts +1 -0
  188. package/templates/tanstack/src/features/landing/hooks/use-users.ts +19 -0
  189. package/templates/tanstack/src/features/landing/icons/index.ts +5 -0
  190. package/templates/tanstack/src/features/landing/icons/react-hook-form.tsx +18 -0
  191. package/templates/tanstack/src/features/landing/icons/react.tsx +20 -0
  192. package/templates/tanstack/src/features/landing/icons/tailwind.tsx +14 -0
  193. package/templates/tanstack/src/features/landing/icons/tanstack.tsx +321 -0
  194. package/templates/tanstack/src/features/landing/icons/typescript.tsx +16 -0
  195. package/templates/tanstack/src/features/landing/index.ts +1 -0
  196. package/templates/tanstack/src/features/landing/schemas/index.ts +1 -0
  197. package/templates/tanstack/src/features/landing/schemas/project.schema.ts +7 -0
  198. package/templates/tanstack/src/features/landing/stores/counter.store.ts +18 -0
  199. package/templates/tanstack/src/features/landing/stores/index.ts +1 -0
  200. package/templates/tanstack/src/features/landing/types/index.ts +1 -0
  201. package/templates/tanstack/src/features/landing/types/user.types.ts +9 -0
  202. package/templates/tanstack/src/helpers/format-date.ts +13 -0
  203. package/templates/tanstack/src/helpers/index.ts +1 -0
  204. package/templates/tanstack/src/hooks/index.ts +5 -0
  205. package/templates/tanstack/src/lib/api.ts +97 -0
  206. package/templates/tanstack/src/lib/query-client.ts +18 -0
  207. package/templates/tanstack/src/lib/utils.ts +13 -0
  208. package/templates/tanstack/src/providers/Providers.tsx +12 -0
  209. package/templates/tanstack/src/providers/ThemeProvider.tsx +98 -0
  210. package/templates/tanstack/src/providers/devtools.tsx +6 -0
  211. package/templates/tanstack/src/providers/index.ts +1 -0
  212. package/templates/tanstack/src/providers/root-provider.ts +9 -0
  213. package/templates/tanstack/src/routeTree.gen.ts +123 -0
  214. package/templates/tanstack/src/router.tsx +27 -0
  215. package/templates/tanstack/src/routes/__root.tsx +78 -0
  216. package/templates/tanstack/src/routes/index.tsx +13 -0
  217. package/templates/tanstack/src/routes/robots[.]txt.ts +21 -0
  218. package/templates/tanstack/src/routes/site[.]webmanifest.ts +32 -0
  219. package/templates/tanstack/src/routes/sitemap[.]xml.ts +27 -0
  220. package/templates/tanstack/src/schemas/index.ts +5 -0
  221. package/templates/tanstack/src/start.ts +20 -0
  222. package/templates/tanstack/src/stores/index.ts +5 -0
  223. package/templates/tanstack/src/styles/tailwind.css +123 -0
  224. package/templates/tanstack/src/types/site-config.types.ts +10 -0
  225. package/templates/tanstack/tsconfig.json +25 -0
  226. package/templates/tanstack/tsr.config.json +3 -0
  227. package/templates/tanstack/vite.config.ts +12 -0
  228. package/templates-i18n/nextjs/.changeset/README.md +8 -0
  229. package/templates-i18n/nextjs/.changeset/config.json +11 -0
  230. package/templates-i18n/nextjs/.env.example +6 -0
  231. package/templates-i18n/nextjs/.eslintcache +1 -0
  232. package/templates-i18n/nextjs/.github/workflows/ci.yml +41 -0
  233. package/templates-i18n/nextjs/.husky/commit-msg +1 -0
  234. package/templates-i18n/nextjs/.husky/pre-commit +1 -0
  235. package/templates-i18n/nextjs/.husky/pre-push +1 -0
  236. package/templates-i18n/nextjs/.prettierignore +6 -0
  237. package/templates-i18n/nextjs/.prettierrc +42 -0
  238. package/templates-i18n/nextjs/.vscode/extensions.json +7 -0
  239. package/templates-i18n/nextjs/.vscode/settings.json +20 -0
  240. package/templates-i18n/nextjs/LICENSE +21 -0
  241. package/templates-i18n/nextjs/README.md +202 -0
  242. package/templates-i18n/nextjs/_gitignore +45 -0
  243. package/templates-i18n/nextjs/commitlint.config.js +6 -0
  244. package/templates-i18n/nextjs/eslint.config.mjs +27 -0
  245. package/templates-i18n/nextjs/knip.config.js +29 -0
  246. package/templates-i18n/nextjs/next-env.d.ts +6 -0
  247. package/templates-i18n/nextjs/next.config.ts +42 -0
  248. package/templates-i18n/nextjs/package.json +117 -0
  249. package/templates-i18n/nextjs/pnpm-lock.yaml +6854 -0
  250. package/templates-i18n/nextjs/pnpm-workspace.yaml +3 -0
  251. package/templates-i18n/nextjs/postcss.config.mjs +7 -0
  252. package/templates-i18n/nextjs/public/favicon.ico +0 -0
  253. package/templates-i18n/nextjs/public/llms.txt +96 -0
  254. package/templates-i18n/nextjs/public/logo.png +0 -0
  255. package/templates-i18n/nextjs/public/logo.webp +0 -0
  256. package/templates-i18n/nextjs/public/og.png +0 -0
  257. package/templates-i18n/nextjs/src/app/[locale]/error.tsx +34 -0
  258. package/templates-i18n/nextjs/src/app/[locale]/layout.tsx +60 -0
  259. package/templates-i18n/nextjs/src/app/[locale]/loading.tsx +12 -0
  260. package/templates-i18n/nextjs/src/app/[locale]/not-found.tsx +18 -0
  261. package/templates-i18n/nextjs/src/app/[locale]/page.tsx +10 -0
  262. package/templates-i18n/nextjs/src/app/favicon.ico +0 -0
  263. package/templates-i18n/nextjs/src/app/global-error.tsx +32 -0
  264. package/templates-i18n/nextjs/src/app/manifest.ts +22 -0
  265. package/templates-i18n/nextjs/src/app/robots.ts +13 -0
  266. package/templates-i18n/nextjs/src/app/sitemap.ts +14 -0
  267. package/templates-i18n/nextjs/src/components/shared/LanguageSwitcher.tsx +48 -0
  268. package/templates-i18n/nextjs/src/components/shared/ThemeToggle.tsx +30 -0
  269. package/templates-i18n/nextjs/src/components/ui/avatar.tsx +54 -0
  270. package/templates-i18n/nextjs/src/components/ui/button.tsx +46 -0
  271. package/templates-i18n/nextjs/src/components/ui/dialog.tsx +107 -0
  272. package/templates-i18n/nextjs/src/components/ui/field.tsx +24 -0
  273. package/templates-i18n/nextjs/src/components/ui/index.ts +27 -0
  274. package/templates-i18n/nextjs/src/components/ui/input.tsx +23 -0
  275. package/templates-i18n/nextjs/src/components/ui/label.tsx +17 -0
  276. package/templates-i18n/nextjs/src/components/ui/skeleton.tsx +13 -0
  277. package/templates-i18n/nextjs/src/components/ui/table.tsx +94 -0
  278. package/templates-i18n/nextjs/src/components/ui/tabs.tsx +46 -0
  279. package/templates-i18n/nextjs/src/config/seo.config.ts +37 -0
  280. package/templates-i18n/nextjs/src/config/site.config.ts +15 -0
  281. package/templates-i18n/nextjs/src/constants/index.ts +5 -0
  282. package/templates-i18n/nextjs/src/env.ts +41 -0
  283. package/templates-i18n/nextjs/src/features/landing/api/get-users.api.ts +7 -0
  284. package/templates-i18n/nextjs/src/features/landing/api/index.ts +2 -0
  285. package/templates-i18n/nextjs/src/features/landing/api/query-keys.ts +7 -0
  286. package/templates-i18n/nextjs/src/features/landing/components/CartDemo.tsx +68 -0
  287. package/templates-i18n/nextjs/src/features/landing/components/Features.tsx +84 -0
  288. package/templates-i18n/nextjs/src/features/landing/components/Hero.tsx +76 -0
  289. package/templates-i18n/nextjs/src/features/landing/components/LandingPage.tsx +17 -0
  290. package/templates-i18n/nextjs/src/features/landing/components/ProjectFormDemo.tsx +64 -0
  291. package/templates-i18n/nextjs/src/features/landing/components/Reveal.tsx +83 -0
  292. package/templates-i18n/nextjs/src/features/landing/components/Showcase.tsx +83 -0
  293. package/templates-i18n/nextjs/src/features/landing/components/UsersDemo.tsx +191 -0
  294. package/templates-i18n/nextjs/src/features/landing/data/features.data.tsx +47 -0
  295. package/templates-i18n/nextjs/src/features/landing/data/index.ts +1 -0
  296. package/templates-i18n/nextjs/src/features/landing/helpers/get-initials.ts +15 -0
  297. package/templates-i18n/nextjs/src/features/landing/helpers/index.ts +7 -0
  298. package/templates-i18n/nextjs/src/features/landing/helpers/motion.ts +21 -0
  299. package/templates-i18n/nextjs/src/features/landing/hooks/index.ts +1 -0
  300. package/templates-i18n/nextjs/src/features/landing/hooks/use-users.ts +16 -0
  301. package/templates-i18n/nextjs/src/features/landing/icons/index.ts +6 -0
  302. package/templates-i18n/nextjs/src/features/landing/icons/nextjs.tsx +68 -0
  303. package/templates-i18n/nextjs/src/features/landing/icons/react-hook-form.tsx +18 -0
  304. package/templates-i18n/nextjs/src/features/landing/icons/react.tsx +20 -0
  305. package/templates-i18n/nextjs/src/features/landing/icons/tailwind.tsx +14 -0
  306. package/templates-i18n/nextjs/src/features/landing/icons/tanstack.tsx +321 -0
  307. package/templates-i18n/nextjs/src/features/landing/icons/typescript.tsx +16 -0
  308. package/templates-i18n/nextjs/src/features/landing/index.ts +1 -0
  309. package/templates-i18n/nextjs/src/features/landing/schemas/index.ts +1 -0
  310. package/templates-i18n/nextjs/src/features/landing/schemas/project.schema.ts +9 -0
  311. package/templates-i18n/nextjs/src/features/landing/stores/counter.store.ts +18 -0
  312. package/templates-i18n/nextjs/src/features/landing/stores/index.ts +1 -0
  313. package/templates-i18n/nextjs/src/features/landing/types/index.ts +1 -0
  314. package/templates-i18n/nextjs/src/features/landing/types/user.types.ts +9 -0
  315. package/templates-i18n/nextjs/src/helpers/format-date.ts +13 -0
  316. package/templates-i18n/nextjs/src/helpers/index.ts +1 -0
  317. package/templates-i18n/nextjs/src/hooks/index.ts +5 -0
  318. package/templates-i18n/nextjs/src/i18n/request.ts +16 -0
  319. package/templates-i18n/nextjs/src/i18n/routing.ts +11 -0
  320. package/templates-i18n/nextjs/src/lib/api.ts +97 -0
  321. package/templates-i18n/nextjs/src/lib/query-client.ts +18 -0
  322. package/templates-i18n/nextjs/src/lib/utils.ts +12 -0
  323. package/templates-i18n/nextjs/src/messages/en.json +55 -0
  324. package/templates-i18n/nextjs/src/messages/tr.json +55 -0
  325. package/templates-i18n/nextjs/src/providers/Providers.tsx +15 -0
  326. package/templates-i18n/nextjs/src/providers/QueryProvider.tsx +19 -0
  327. package/templates-i18n/nextjs/src/providers/ThemeProvider.tsx +9 -0
  328. package/templates-i18n/nextjs/src/providers/index.ts +1 -0
  329. package/templates-i18n/nextjs/src/proxy.ts +16 -0
  330. package/templates-i18n/nextjs/src/schemas/index.ts +5 -0
  331. package/templates-i18n/nextjs/src/stores/index.ts +5 -0
  332. package/templates-i18n/nextjs/src/styles/tailwind.css +122 -0
  333. package/templates-i18n/nextjs/src/types/site-config.types.ts +10 -0
  334. package/templates-i18n/nextjs/tsconfig.json +45 -0
  335. package/templates-i18n/nextjs/tsconfig.tsbuildinfo +1 -0
  336. package/templates-i18n/tanstack/.changeset/README.md +8 -0
  337. package/templates-i18n/tanstack/.changeset/config.json +11 -0
  338. package/templates-i18n/tanstack/.env.example +6 -0
  339. package/templates-i18n/tanstack/.eslintcache +1 -0
  340. package/templates-i18n/tanstack/.github/workflows/ci.yml +41 -0
  341. package/templates-i18n/tanstack/.husky/commit-msg +1 -0
  342. package/templates-i18n/tanstack/.husky/pre-commit +1 -0
  343. package/templates-i18n/tanstack/.husky/pre-push +1 -0
  344. package/templates-i18n/tanstack/.prettierignore +7 -0
  345. package/templates-i18n/tanstack/.prettierrc +41 -0
  346. package/templates-i18n/tanstack/.vscode/extensions.json +7 -0
  347. package/templates-i18n/tanstack/.vscode/settings.json +22 -0
  348. package/templates-i18n/tanstack/LICENSE +21 -0
  349. package/templates-i18n/tanstack/README.md +204 -0
  350. package/templates-i18n/tanstack/_gitignore +52 -0
  351. package/templates-i18n/tanstack/commitlint.config.js +6 -0
  352. package/templates-i18n/tanstack/eslint.config.js +29 -0
  353. package/templates-i18n/tanstack/knip.config.js +26 -0
  354. package/templates-i18n/tanstack/messages/en.json +65 -0
  355. package/templates-i18n/tanstack/messages/tr.json +65 -0
  356. package/templates-i18n/tanstack/package.json +132 -0
  357. package/templates-i18n/tanstack/pnpm-lock.yaml +5998 -0
  358. package/templates-i18n/tanstack/pnpm-workspace.yaml +3 -0
  359. package/templates-i18n/tanstack/project.inlang/README.md +157 -0
  360. package/templates-i18n/tanstack/project.inlang/settings.json +9 -0
  361. package/templates-i18n/tanstack/public/favicon.ico +0 -0
  362. package/templates-i18n/tanstack/public/llms.txt +86 -0
  363. package/templates-i18n/tanstack/public/logo.png +0 -0
  364. package/templates-i18n/tanstack/public/logo.webp +0 -0
  365. package/templates-i18n/tanstack/public/og.png +0 -0
  366. package/templates-i18n/tanstack/src/components/shared/DefaultCatchBoundary.tsx +36 -0
  367. package/templates-i18n/tanstack/src/components/shared/LanguageSwitcher.tsx +57 -0
  368. package/templates-i18n/tanstack/src/components/shared/NotFound.tsx +18 -0
  369. package/templates-i18n/tanstack/src/components/shared/Pending.tsx +13 -0
  370. package/templates-i18n/tanstack/src/components/shared/ThemeToggle.tsx +31 -0
  371. package/templates-i18n/tanstack/src/components/ui/avatar.tsx +52 -0
  372. package/templates-i18n/tanstack/src/components/ui/button.tsx +47 -0
  373. package/templates-i18n/tanstack/src/components/ui/dialog.tsx +107 -0
  374. package/templates-i18n/tanstack/src/components/ui/field.tsx +24 -0
  375. package/templates-i18n/tanstack/src/components/ui/index.ts +27 -0
  376. package/templates-i18n/tanstack/src/components/ui/input.tsx +23 -0
  377. package/templates-i18n/tanstack/src/components/ui/label.tsx +17 -0
  378. package/templates-i18n/tanstack/src/components/ui/skeleton.tsx +13 -0
  379. package/templates-i18n/tanstack/src/components/ui/table.tsx +94 -0
  380. package/templates-i18n/tanstack/src/components/ui/tabs.tsx +46 -0
  381. package/templates-i18n/tanstack/src/config/seo.config.ts +52 -0
  382. package/templates-i18n/tanstack/src/config/site.config.ts +15 -0
  383. package/templates-i18n/tanstack/src/constants/index.ts +5 -0
  384. package/templates-i18n/tanstack/src/env.ts +47 -0
  385. package/templates-i18n/tanstack/src/features/landing/api/get-users.api.ts +7 -0
  386. package/templates-i18n/tanstack/src/features/landing/api/index.ts +2 -0
  387. package/templates-i18n/tanstack/src/features/landing/api/query-keys.ts +7 -0
  388. package/templates-i18n/tanstack/src/features/landing/components/CartDemo.tsx +67 -0
  389. package/templates-i18n/tanstack/src/features/landing/components/Features.tsx +79 -0
  390. package/templates-i18n/tanstack/src/features/landing/components/Hero.tsx +68 -0
  391. package/templates-i18n/tanstack/src/features/landing/components/LandingPage.tsx +17 -0
  392. package/templates-i18n/tanstack/src/features/landing/components/ProjectFormDemo.tsx +64 -0
  393. package/templates-i18n/tanstack/src/features/landing/components/Reveal.tsx +83 -0
  394. package/templates-i18n/tanstack/src/features/landing/components/Showcase.tsx +81 -0
  395. package/templates-i18n/tanstack/src/features/landing/components/UsersDemo.tsx +191 -0
  396. package/templates-i18n/tanstack/src/features/landing/data/features.data.tsx +45 -0
  397. package/templates-i18n/tanstack/src/features/landing/data/index.ts +1 -0
  398. package/templates-i18n/tanstack/src/features/landing/helpers/get-initials.ts +15 -0
  399. package/templates-i18n/tanstack/src/features/landing/helpers/index.ts +7 -0
  400. package/templates-i18n/tanstack/src/features/landing/helpers/motion.ts +21 -0
  401. package/templates-i18n/tanstack/src/features/landing/hooks/index.ts +1 -0
  402. package/templates-i18n/tanstack/src/features/landing/hooks/use-users.ts +19 -0
  403. package/templates-i18n/tanstack/src/features/landing/icons/index.ts +5 -0
  404. package/templates-i18n/tanstack/src/features/landing/icons/react-hook-form.tsx +18 -0
  405. package/templates-i18n/tanstack/src/features/landing/icons/react.tsx +20 -0
  406. package/templates-i18n/tanstack/src/features/landing/icons/tailwind.tsx +14 -0
  407. package/templates-i18n/tanstack/src/features/landing/icons/tanstack.tsx +321 -0
  408. package/templates-i18n/tanstack/src/features/landing/icons/typescript.tsx +16 -0
  409. package/templates-i18n/tanstack/src/features/landing/index.ts +1 -0
  410. package/templates-i18n/tanstack/src/features/landing/schemas/index.ts +1 -0
  411. package/templates-i18n/tanstack/src/features/landing/schemas/project.schema.ts +10 -0
  412. package/templates-i18n/tanstack/src/features/landing/stores/counter.store.ts +18 -0
  413. package/templates-i18n/tanstack/src/features/landing/stores/index.ts +1 -0
  414. package/templates-i18n/tanstack/src/features/landing/types/index.ts +1 -0
  415. package/templates-i18n/tanstack/src/features/landing/types/user.types.ts +9 -0
  416. package/templates-i18n/tanstack/src/helpers/format-date.ts +13 -0
  417. package/templates-i18n/tanstack/src/helpers/index.ts +1 -0
  418. package/templates-i18n/tanstack/src/hooks/index.ts +5 -0
  419. package/templates-i18n/tanstack/src/lib/api.ts +97 -0
  420. package/templates-i18n/tanstack/src/lib/query-client.ts +18 -0
  421. package/templates-i18n/tanstack/src/lib/utils.ts +13 -0
  422. package/templates-i18n/tanstack/src/paraglide/README.md +162 -0
  423. package/templates-i18n/tanstack/src/providers/Providers.tsx +12 -0
  424. package/templates-i18n/tanstack/src/providers/ThemeProvider.tsx +98 -0
  425. package/templates-i18n/tanstack/src/providers/devtools.tsx +6 -0
  426. package/templates-i18n/tanstack/src/providers/index.ts +1 -0
  427. package/templates-i18n/tanstack/src/providers/root-provider.ts +9 -0
  428. package/templates-i18n/tanstack/src/routeTree.gen.ts +179 -0
  429. package/templates-i18n/tanstack/src/router.tsx +27 -0
  430. package/templates-i18n/tanstack/src/routes/$lang/index.tsx +13 -0
  431. package/templates-i18n/tanstack/src/routes/$lang.tsx +22 -0
  432. package/templates-i18n/tanstack/src/routes/__root.tsx +80 -0
  433. package/templates-i18n/tanstack/src/routes/index.tsx +13 -0
  434. package/templates-i18n/tanstack/src/routes/robots[.]txt.ts +21 -0
  435. package/templates-i18n/tanstack/src/routes/site[.]webmanifest.ts +32 -0
  436. package/templates-i18n/tanstack/src/routes/sitemap[.]xml.ts +27 -0
  437. package/templates-i18n/tanstack/src/schemas/index.ts +5 -0
  438. package/templates-i18n/tanstack/src/server.ts +10 -0
  439. package/templates-i18n/tanstack/src/start.ts +20 -0
  440. package/templates-i18n/tanstack/src/stores/index.ts +5 -0
  441. package/templates-i18n/tanstack/src/styles/tailwind.css +123 -0
  442. package/templates-i18n/tanstack/src/types/site-config.types.ts +10 -0
  443. package/templates-i18n/tanstack/tsconfig.json +26 -0
  444. package/templates-i18n/tanstack/tsr.config.json +3 -0
  445. package/templates-i18n/tanstack/vite.config.ts +31 -0
  446. package/index.js +0 -3
  447. package/public/start.jpg +0 -0
@@ -0,0 +1,46 @@
1
+ import type { ComponentProps } from "react";
2
+
3
+ import { Tabs as BaseTabs } from "@base-ui/react/tabs";
4
+
5
+ import { cn } from "@/lib/utils";
6
+
7
+ export function Tabs({ className, ...props }: ComponentProps<typeof BaseTabs.Root>) {
8
+ return (
9
+ <BaseTabs.Root data-slot="tabs" className={cn("flex flex-col gap-3", className)} {...props} />
10
+ );
11
+ }
12
+
13
+ export function TabsList({ className, ...props }: ComponentProps<typeof BaseTabs.List>) {
14
+ return (
15
+ <BaseTabs.List
16
+ data-slot="tabs-list"
17
+ className={cn(
18
+ "relative inline-flex h-9 w-fit items-center rounded-lg bg-muted p-[3px] text-muted-foreground",
19
+ className,
20
+ )}
21
+ {...props}
22
+ />
23
+ );
24
+ }
25
+
26
+ export function TabsTrigger({ className, ...props }: ComponentProps<typeof BaseTabs.Tab>) {
27
+ return (
28
+ <BaseTabs.Tab
29
+ data-slot="tabs-trigger"
30
+ className={cn(
31
+ "inline-flex h-[calc(100%-1px)] flex-1 items-center justify-center gap-1.5 rounded-md px-2 py-1 text-sm font-medium whitespace-nowrap transition-[color,box-shadow] outline-none",
32
+ "text-foreground data-[selected]:bg-background data-[selected]:shadow-sm",
33
+ "focus-visible:ring-[3px] focus-visible:ring-ring/50",
34
+ "disabled:pointer-events-none disabled:opacity-50",
35
+ className,
36
+ )}
37
+ {...props}
38
+ />
39
+ );
40
+ }
41
+
42
+ export function TabsContent({ className, ...props }: ComponentProps<typeof BaseTabs.Panel>) {
43
+ return (
44
+ <BaseTabs.Panel data-slot="tabs-content" className={cn("outline-none", className)} {...props} />
45
+ );
46
+ }
@@ -0,0 +1,52 @@
1
+ import { siteConfig } from "@/config/site.config";
2
+
3
+ /** Shared SEO fields used by the root route `head()` and social meta tags. */
4
+ const defaultSeo = {
5
+ title: siteConfig.name,
6
+ titleTemplate: `%s · ${siteConfig.name}`,
7
+ description: siteConfig.description,
8
+ keywords: ["TanStack Start", "React", "TypeScript", "Tailwind CSS", "ViraStack", "Boilerplate"],
9
+ authors: [{ name: "ViraStack", url: siteConfig.url }],
10
+ creator: "ViraStack",
11
+ openGraph: {
12
+ type: "website",
13
+ locale: "en_US",
14
+ url: siteConfig.url,
15
+ title: siteConfig.name,
16
+ description: siteConfig.description,
17
+ siteName: siteConfig.name,
18
+ images: [{ url: siteConfig.ogImage, width: 1200, height: 630, alt: siteConfig.name }],
19
+ },
20
+ twitter: {
21
+ card: "summary_large_image",
22
+ title: siteConfig.name,
23
+ description: siteConfig.description,
24
+ images: [siteConfig.ogImage],
25
+ },
26
+ } as const;
27
+
28
+ /** Flatten `defaultSeo` into TanStack Router `head().meta` entries. */
29
+ export function seoHeadMeta() {
30
+ const og = defaultSeo.openGraph;
31
+ const twitter = defaultSeo.twitter;
32
+
33
+ return [
34
+ { title: defaultSeo.title },
35
+ { name: "description", content: defaultSeo.description },
36
+ { name: "keywords", content: defaultSeo.keywords.join(", ") },
37
+ { name: "author", content: defaultSeo.creator },
38
+ { name: "creator", content: defaultSeo.creator },
39
+ { name: "robots", content: "index, follow" },
40
+ { property: "og:type", content: og.type },
41
+ { property: "og:locale", content: og.locale },
42
+ { property: "og:url", content: og.url },
43
+ { property: "og:title", content: og.title },
44
+ { property: "og:description", content: og.description },
45
+ { property: "og:site_name", content: og.siteName },
46
+ { property: "og:image", content: og.images[0].url },
47
+ { name: "twitter:card", content: twitter.card },
48
+ { name: "twitter:title", content: twitter.title },
49
+ { name: "twitter:description", content: twitter.description },
50
+ { name: "twitter:image", content: twitter.images[0] },
51
+ ];
52
+ }
@@ -0,0 +1,15 @@
1
+ import type { SiteConfig } from "@/types/site-config.types";
2
+ import { env } from "@/env";
3
+
4
+ // FIXME: replace with your own site metadata.
5
+ export const siteConfig: SiteConfig = {
6
+ name: env.VITE_APP_NAME,
7
+ description:
8
+ "Premium TanStack Start boilerplate built for scalable UI/UX, clean architecture, and agent-ready developer experience.",
9
+ url: env.VITE_APP_URL,
10
+ ogImage: `${env.VITE_APP_URL}/og.png`,
11
+ links: {
12
+ github: "https://github.com/virastack/start",
13
+ twitter: "https://x.com/virastack",
14
+ },
15
+ };
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Shared constants promoted out of features (Rule of Three).
3
+ * Feature-scoped constants live under `src/features/[feature]/constants`.
4
+ */
5
+ export {};
@@ -0,0 +1,47 @@
1
+ import { z } from "zod";
2
+
3
+ /**
4
+ * Type-safe environment variable schema.
5
+ *
6
+ * Client-exposed variables MUST be prefixed with `VITE_` (Vite inlines these
7
+ * at build time). Server-only variables have no prefix and must never be
8
+ * read via `import.meta.env` on the client.
9
+ */
10
+ const serverSchema = z.object({
11
+ NODE_ENV: z.enum(["development", "production", "test"]).default("development"),
12
+ });
13
+
14
+ const clientSchema = z.object({
15
+ VITE_APP_URL: z.string().url().default("http://localhost:3000"),
16
+ VITE_APP_NAME: z.string().min(1).default("ViraStack Start - TanStack Edition"),
17
+ });
18
+
19
+ function readEnv(key: string): string | undefined {
20
+ if (typeof process !== "undefined" && process.env[key] != null) {
21
+ return process.env[key];
22
+ }
23
+ return (import.meta.env as Record<string, string | undefined>)[key];
24
+ }
25
+
26
+ const serverParsed = serverSchema.safeParse({
27
+ NODE_ENV: readEnv("NODE_ENV"),
28
+ });
29
+
30
+ const clientParsed = clientSchema.safeParse({
31
+ VITE_APP_URL: readEnv("VITE_APP_URL"),
32
+ VITE_APP_NAME: readEnv("VITE_APP_NAME"),
33
+ });
34
+
35
+ if (!serverParsed.success || !clientParsed.success) {
36
+ console.error(
37
+ "❌ Invalid environment variables:",
38
+ serverParsed.error?.flatten().fieldErrors,
39
+ clientParsed.error?.flatten().fieldErrors,
40
+ );
41
+ throw new Error("Invalid environment variables. Check src/env.ts");
42
+ }
43
+
44
+ export const env = {
45
+ ...serverParsed.data,
46
+ ...clientParsed.data,
47
+ };
@@ -0,0 +1,7 @@
1
+ import { api } from "@/lib/api";
2
+
3
+ import type { User } from "@/features/landing/types";
4
+
5
+ export function getUsers(signal?: AbortSignal) {
6
+ return api.get<User[]>("https://jsonplaceholder.typicode.com/users?_limit=5", { signal });
7
+ }
@@ -0,0 +1,2 @@
1
+ export { getUsers } from "@/features/landing/api/get-users.api";
2
+ export { userKeys } from "@/features/landing/api/query-keys";
@@ -0,0 +1,7 @@
1
+ export const userKeys = {
2
+ all: ["users"] as const,
3
+ lists: () => [...userKeys.all, "list"] as const,
4
+ list: (filters?: object) => [...userKeys.lists(), { filters }] as const,
5
+ details: () => [...userKeys.all, "detail"] as const,
6
+ detail: (id: string) => [...userKeys.details(), id] as const,
7
+ };
@@ -0,0 +1,66 @@
1
+ "use client";
2
+
3
+ import { MinusIcon, PlusIcon, ShirtIcon, Trash2Icon } from "lucide-react";
4
+
5
+ import { Button } from "@/components/ui/button";
6
+ import { useCounterStore } from "@/features/landing/stores";
7
+
8
+ /**
9
+ * Demonstrates global client state with Zustand via a mini cart UI.
10
+ */
11
+ export function CartDemo() {
12
+ const { count, increment, decrement, reset } = useCounterStore();
13
+
14
+ return (
15
+ <div className="flex flex-col gap-4">
16
+ <div className="flex items-center gap-4 rounded-xl border border-border/50 bg-background/50 p-3">
17
+ <div className="flex h-12 w-12 shrink-0 items-center justify-center rounded-lg bg-primary/10 text-primary">
18
+ <ShirtIcon className="size-6" />
19
+ </div>
20
+ <div className="flex flex-1 flex-col">
21
+ <h5 className="font-medium text-foreground">Cotton T-Shirt</h5>
22
+ <p className="text-sm text-muted-foreground">White / XL</p>
23
+ </div>
24
+ <div className="flex flex-col items-end gap-1">
25
+ <span className="font-semibold text-foreground">{count * 350}</span>
26
+ <span className="text-xs text-muted-foreground">Total</span>
27
+ </div>
28
+ </div>
29
+
30
+ <div className="flex items-center justify-between">
31
+ <div className="flex items-center gap-2">
32
+ <Button
33
+ variant="outline"
34
+ size="icon"
35
+ className="h-8 w-8 rounded-full"
36
+ aria-label="Decrement"
37
+ onClick={decrement}
38
+ disabled={count === 0}
39
+ >
40
+ <MinusIcon className="size-4" />
41
+ </Button>
42
+ <span className="w-6 text-center font-medium tabular-nums">{count}</span>
43
+ <Button
44
+ variant="outline"
45
+ size="icon"
46
+ className="h-8 w-8 rounded-full"
47
+ aria-label="Increment"
48
+ onClick={increment}
49
+ >
50
+ <PlusIcon className="size-4" />
51
+ </Button>
52
+ </div>
53
+ <Button
54
+ variant="ghost"
55
+ size="sm"
56
+ className="h-8 gap-1.5 px-2 text-muted-foreground hover:text-destructive"
57
+ onClick={reset}
58
+ disabled={count === 0}
59
+ >
60
+ <Trash2Icon className="size-3.5" />
61
+ <span className="text-xs">Clear</span>
62
+ </Button>
63
+ </div>
64
+ </div>
65
+ );
66
+ }
@@ -0,0 +1,39 @@
1
+ import { RevealGroup, RevealItem } from "@/features/landing/components/Reveal";
2
+ import { FEATURES } from "@/features/landing/data";
3
+ import { featureCardClassName } from "@/features/landing/helpers";
4
+
5
+ export function Features() {
6
+ return (
7
+ <section id="features" className="mx-auto max-w-5xl px-6 py-16">
8
+ <RevealGroup className="mb-16 text-center">
9
+ <RevealItem>
10
+ <h2 className="text-3xl font-semibold tracking-tight text-balance">Features</h2>
11
+ </RevealItem>
12
+ <RevealItem>
13
+ <p className="mx-auto mt-3 max-w-xl text-base text-balance text-muted-foreground">
14
+ Everything you need to build a modern web application, already configured with the best
15
+ practices.
16
+ </p>
17
+ </RevealItem>
18
+ </RevealGroup>
19
+
20
+ <RevealGroup className="grid grid-cols-1 gap-6 sm:grid-cols-2 lg:grid-cols-3">
21
+ {FEATURES.map((feature) => (
22
+ <RevealItem key={feature.title} className={featureCardClassName}>
23
+ <div className="mb-2 flex h-12 w-12 items-center justify-center rounded-xl bg-primary/10 transition-transform duration-200 ease-out group-hover:scale-105">
24
+ {feature.icon}
25
+ </div>
26
+ <div className="flex flex-col gap-1.5">
27
+ <h3 className="text-base font-semibold text-balance text-foreground md:text-lg">
28
+ {feature.title}
29
+ </h3>
30
+ <p className="text-sm leading-relaxed text-pretty text-muted-foreground">
31
+ {feature.description}
32
+ </p>
33
+ </div>
34
+ </RevealItem>
35
+ ))}
36
+ </RevealGroup>
37
+ </section>
38
+ );
39
+ }
@@ -0,0 +1,63 @@
1
+ import { siteConfig } from "@/config/site.config";
2
+
3
+ import { ThemeToggle } from "@/components/shared/ThemeToggle";
4
+ import { Button } from "@/components/ui/button";
5
+ import { Reveal } from "@/features/landing/components/Reveal";
6
+ import { ReactIcon, TailwindIcon, TanstackIcon } from "@/features/landing/icons";
7
+
8
+ export function Hero() {
9
+ return (
10
+ <section className="mx-auto flex max-w-3xl flex-col items-center gap-6 px-6 pt-24 pb-16 text-center">
11
+ <Reveal mode="mount" delay={0} y={-8}>
12
+ <span className="rounded-full border border-border px-3 py-1 text-xs font-medium text-muted-foreground">
13
+ Premium UI/UX · Agent-ready · Zero bloat
14
+ </span>
15
+ </Reveal>
16
+
17
+ <h1 className="mb-2 text-center text-4xl lg:text-6xl">
18
+ <span className="font-black text-primary">ViraStack</span>{" "}
19
+ <span className="font-medium text-teal-500 italic">Start</span>
20
+ <span className="mt-2 block text-lg font-normal text-muted-foreground lg:text-xl">
21
+ TanStack Edition
22
+ </span>
23
+ </h1>
24
+
25
+ <p className="max-w-2xl text-base leading-relaxed text-balance text-muted-foreground sm:text-lg">
26
+ Built with{" "}
27
+ <span className="inline-flex items-center gap-1 font-semibold text-foreground">
28
+ <TanstackIcon className="h-4 w-4" />
29
+ TanStack Start
30
+ </span>
31
+ ,{" "}
32
+ <span className="inline-flex items-center gap-1 font-semibold text-foreground">
33
+ <ReactIcon className="h-4 w-4" />
34
+ React 19
35
+ </span>
36
+ , and{" "}
37
+ <span className="inline-flex items-center gap-1 font-semibold text-foreground">
38
+ <TailwindIcon className="h-4 w-4" />
39
+ Tailwind CSS 4
40
+ </span>{" "}
41
+ - wired together with <span className="font-medium text-foreground italic">
42
+ Zustand
43
+ </span>, <span className="font-medium text-foreground italic">TanStack Query</span>, and{" "}
44
+ <span className="font-medium text-foreground italic">React Hook Form</span> so you can ship
45
+ a polished product from day one.
46
+ </p>
47
+
48
+ <Reveal mode="mount" delay={0.1} className="mt-2 flex items-center gap-2">
49
+ <Button
50
+ className="h-10 px-4 py-2"
51
+ nativeButton={false}
52
+ render={<a href={siteConfig.links.github} target="_blank" rel="noreferrer" />}
53
+ >
54
+ <span>⭐</span>
55
+ <span>Star on GitHub</span>
56
+ </Button>
57
+ <div className="h-10 w-10 [&>button]:h-full [&>button]:w-full">
58
+ <ThemeToggle />
59
+ </div>
60
+ </Reveal>
61
+ </section>
62
+ );
63
+ }
@@ -0,0 +1,17 @@
1
+ import { Features } from "@/features/landing/components/Features";
2
+ import { Hero } from "@/features/landing/components/Hero";
3
+ import { Showcase } from "@/features/landing/components/Showcase";
4
+
5
+ /**
6
+ * Demo landing surface. Delete `src/features/landing` and replace
7
+ * `src/routes/index.tsx` when you start your own product UI.
8
+ */
9
+ export function LandingPage() {
10
+ return (
11
+ <main className="flex-1">
12
+ <Hero />
13
+ <Features />
14
+ <Showcase />
15
+ </main>
16
+ );
17
+ }
@@ -0,0 +1,63 @@
1
+ "use client";
2
+
3
+ import { zodResolver } from "@hookform/resolvers/zod";
4
+ import { Controller, useForm } from "react-hook-form";
5
+ import { toast } from "sonner";
6
+
7
+ import { Button } from "@/components/ui/button";
8
+ import { FieldDescription, FieldError } from "@/components/ui/field";
9
+ import { Input } from "@/components/ui/input";
10
+ import { Label } from "@/components/ui/label";
11
+ import { projectSchema } from "@/features/landing/schemas";
12
+ import type { ProjectInput } from "@/features/landing/schemas";
13
+
14
+ export function ProjectFormDemo() {
15
+ const {
16
+ control,
17
+ handleSubmit,
18
+ reset,
19
+ formState: { errors, isSubmitting },
20
+ } = useForm<ProjectInput>({
21
+ resolver: zodResolver(projectSchema),
22
+ defaultValues: { name: "" },
23
+ });
24
+
25
+ async function onSubmit(values: ProjectInput) {
26
+ await new Promise((resolve) => setTimeout(resolve, 600));
27
+ toast.success(`Created project: ${values.name}`);
28
+ reset();
29
+ }
30
+
31
+ return (
32
+ <form onSubmit={handleSubmit(onSubmit)} noValidate className="flex flex-col gap-4">
33
+ <div className="flex flex-col gap-2.5 text-left">
34
+ <Label htmlFor="name">Project Name</Label>
35
+ <Controller
36
+ control={control}
37
+ name="name"
38
+ render={({ field }) => (
39
+ <Input
40
+ id="name"
41
+ type="text"
42
+ placeholder="virastack-app"
43
+ aria-invalid={!!errors.name}
44
+ value={field.value}
45
+ onChange={(event) => field.onChange(event.target.value)}
46
+ onBlur={field.onBlur}
47
+ ref={field.ref}
48
+ />
49
+ )}
50
+ />
51
+ {errors.name ? (
52
+ <FieldError>{errors.name.message}</FieldError>
53
+ ) : (
54
+ <FieldDescription>Use 3–50 characters for the project name.</FieldDescription>
55
+ )}
56
+ </div>
57
+
58
+ <Button type="submit" disabled={isSubmitting}>
59
+ {isSubmitting ? "Creating…" : "Create Project"}
60
+ </Button>
61
+ </form>
62
+ );
63
+ }
@@ -0,0 +1,83 @@
1
+ "use client";
2
+
3
+ import type { ReactNode } from "react";
4
+
5
+ import { motion } from "framer-motion";
6
+
7
+ import { fadeInUp, staggerContainer, viewport } from "@/features/landing/helpers";
8
+
9
+ type RevealProps = {
10
+ children: ReactNode;
11
+ className?: string;
12
+ /** Mount animation delay in seconds (hero-style). Ignored when `mode="view"`. */
13
+ delay?: number;
14
+ /** `mount` = animate on load; `view` = animate when scrolled into view. */
15
+ mode?: "mount" | "view";
16
+ /** Initial Y offset for mount animations. */
17
+ y?: number;
18
+ /**
19
+ * When false (mount mode), only translate — keep opacity at 1 so LCP text
20
+ * is painted on first frame. Default true.
21
+ */
22
+ fadeOpacity?: boolean;
23
+ };
24
+
25
+ /**
26
+ * Client-only motion shell. Keep copy/markup in Server Components and wrap
27
+ * animated regions with this so the page stays SSR-first.
28
+ */
29
+ export function Reveal({
30
+ children,
31
+ className,
32
+ delay = 0,
33
+ mode = "view",
34
+ y = 12,
35
+ fadeOpacity = true,
36
+ }: RevealProps) {
37
+ if (mode === "mount") {
38
+ return (
39
+ <motion.div
40
+ className={className}
41
+ initial={fadeOpacity ? { opacity: 0, y } : { y }}
42
+ animate={fadeOpacity ? { opacity: 1, y: 0 } : { y: 0 }}
43
+ transition={{ duration: 0.45, delay, ease: "easeOut" }}
44
+ >
45
+ {children}
46
+ </motion.div>
47
+ );
48
+ }
49
+
50
+ return (
51
+ <motion.div
52
+ className={className}
53
+ initial="hidden"
54
+ whileInView="visible"
55
+ viewport={viewport}
56
+ variants={fadeInUp}
57
+ >
58
+ {children}
59
+ </motion.div>
60
+ );
61
+ }
62
+
63
+ export function RevealGroup({ children, className }: { children: ReactNode; className?: string }) {
64
+ return (
65
+ <motion.div
66
+ className={className}
67
+ initial="hidden"
68
+ whileInView="visible"
69
+ viewport={viewport}
70
+ variants={staggerContainer}
71
+ >
72
+ {children}
73
+ </motion.div>
74
+ );
75
+ }
76
+
77
+ export function RevealItem({ children, className }: { children: ReactNode; className?: string }) {
78
+ return (
79
+ <motion.div className={className} variants={fadeInUp}>
80
+ {children}
81
+ </motion.div>
82
+ );
83
+ }
@@ -0,0 +1,66 @@
1
+ import { siteConfig } from "@/config/site.config";
2
+
3
+ import { formatDate } from "@/helpers";
4
+
5
+ import { CartDemo } from "@/features/landing/components/CartDemo";
6
+ import { ProjectFormDemo } from "@/features/landing/components/ProjectFormDemo";
7
+ import { RevealGroup, RevealItem } from "@/features/landing/components/Reveal";
8
+ import { UsersDemo } from "@/features/landing/components/UsersDemo";
9
+ import { featureCardClassName } from "@/features/landing/helpers";
10
+
11
+ export function Showcase() {
12
+ return (
13
+ <section id="showcase" className="mx-auto max-w-5xl px-6 pb-16">
14
+ <RevealGroup className="mb-10 text-center">
15
+ <RevealItem>
16
+ <h2 className="text-3xl font-semibold tracking-tight text-balance">Showcase</h2>
17
+ </RevealItem>
18
+ <RevealItem>
19
+ <p className="mx-auto mt-3 max-w-2xl text-base text-balance text-muted-foreground">
20
+ Experience the seamless integration of UI components and state management.
21
+ </p>
22
+ </RevealItem>
23
+ </RevealGroup>
24
+
25
+ <RevealGroup className="grid grid-cols-1 gap-6 lg:grid-cols-2 lg:items-stretch">
26
+ <RevealItem className={`${featureCardClassName} h-full min-h-0 [&>*]:min-h-0 [&>*]:flex-1`}>
27
+ <UsersDemo />
28
+ </RevealItem>
29
+
30
+ <div className="flex flex-col gap-6">
31
+ <RevealItem className={featureCardClassName}>
32
+ <div className="mb-4">
33
+ <h4 className="text-base font-semibold text-foreground md:text-lg">New Project</h4>
34
+ <p className="mt-1 text-sm text-pretty text-muted-foreground">
35
+ Validated forms with{" "}
36
+ <span className="font-semibold text-foreground">React Hook Form</span> and{" "}
37
+ <span className="font-semibold text-foreground">Zod</span>.
38
+ </p>
39
+ </div>
40
+ <ProjectFormDemo />
41
+ </RevealItem>
42
+
43
+ <RevealItem className={`${featureCardClassName} flex flex-col`}>
44
+ <div>
45
+ <h4 className="text-base font-semibold text-foreground md:text-lg">Global State</h4>
46
+ <p className="mt-1 text-sm text-pretty text-muted-foreground">
47
+ Shared client state managed with{" "}
48
+ <span className="font-semibold text-foreground">Zustand</span>.
49
+ </p>
50
+ </div>
51
+ <CartDemo />
52
+ </RevealItem>
53
+ </div>
54
+ </RevealGroup>
55
+
56
+ <div className="mt-20 flex flex-col items-center justify-center gap-2 text-sm text-muted-foreground">
57
+ <p suppressHydrationWarning>
58
+ © {new Date().getFullYear()} {siteConfig.name}. MIT Licensed.
59
+ </p>
60
+ <p className="italic" suppressHydrationWarning>
61
+ Last built on {formatDate(new Date())}.
62
+ </p>
63
+ </div>
64
+ </section>
65
+ );
66
+ }