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.
- package/LICENSE +1 -1
- package/README.md +94 -18
- package/bin/virastack.js +7 -0
- package/package.json +43 -9
- package/src/commands/add.js +64 -0
- package/src/commands/init.js +286 -0
- package/src/i18n.js +231 -0
- package/src/index.js +64 -0
- package/src/utils/args.js +60 -0
- package/src/utils/copy-template.js +81 -0
- package/src/utils/exec.js +29 -0
- package/src/utils/git.js +38 -0
- package/src/utils/is-online.js +14 -0
- package/src/utils/package-info.js +12 -0
- package/src/utils/package-manager.js +33 -0
- package/src/utils/setup-env.js +25 -0
- package/src/utils/telemetry.js +86 -0
- package/src/utils/tools.js +48 -0
- package/src/utils/update-package-json.js +44 -0
- package/src/utils/update-readme.js +25 -0
- package/src/utils/validate-project-name.js +26 -0
- package/templates/nextjs/.changeset/README.md +8 -0
- package/templates/nextjs/.changeset/config.json +11 -0
- package/templates/nextjs/.env.example +6 -0
- package/templates/nextjs/.env.local +6 -0
- package/templates/nextjs/.eslintcache +1 -0
- package/templates/nextjs/.github/workflows/ci.yml +41 -0
- package/templates/nextjs/.husky/commit-msg +1 -0
- package/templates/nextjs/.husky/pre-commit +1 -0
- package/templates/nextjs/.husky/pre-push +1 -0
- package/templates/nextjs/.prettierignore +6 -0
- package/templates/nextjs/.prettierrc +42 -0
- package/templates/nextjs/.vscode/extensions.json +7 -0
- package/templates/nextjs/.vscode/settings.json +20 -0
- package/templates/nextjs/LICENSE +21 -0
- package/templates/nextjs/README.md +202 -0
- package/templates/nextjs/_gitignore +45 -0
- package/templates/nextjs/commitlint.config.js +6 -0
- package/templates/nextjs/eslint.config.mjs +27 -0
- package/templates/nextjs/knip.config.js +25 -0
- package/templates/nextjs/next-env.d.ts +6 -0
- package/templates/nextjs/next.config.ts +39 -0
- package/templates/nextjs/package.json +115 -0
- package/templates/nextjs/pnpm-lock.yaml +6467 -0
- package/templates/nextjs/pnpm-workspace.yaml +3 -0
- package/templates/nextjs/postcss.config.mjs +7 -0
- package/templates/nextjs/public/favicon.ico +0 -0
- package/templates/nextjs/public/llms.txt +96 -0
- package/templates/nextjs/public/logo.png +0 -0
- package/templates/nextjs/public/logo.webp +0 -0
- package/templates/nextjs/public/og.png +0 -0
- package/templates/nextjs/src/app/error.tsx +34 -0
- package/templates/nextjs/src/app/favicon.ico +0 -0
- package/templates/nextjs/src/app/global-error.tsx +32 -0
- package/templates/nextjs/src/app/layout.tsx +37 -0
- package/templates/nextjs/src/app/loading.tsx +12 -0
- package/templates/nextjs/src/app/manifest.ts +22 -0
- package/templates/nextjs/src/app/not-found.tsx +18 -0
- package/templates/nextjs/src/app/page.tsx +5 -0
- package/templates/nextjs/src/app/robots.ts +13 -0
- package/templates/nextjs/src/app/sitemap.ts +14 -0
- package/templates/nextjs/src/components/shared/ThemeToggle.tsx +30 -0
- package/templates/nextjs/src/components/ui/avatar.tsx +54 -0
- package/templates/nextjs/src/components/ui/button.tsx +46 -0
- package/templates/nextjs/src/components/ui/dialog.tsx +107 -0
- package/templates/nextjs/src/components/ui/field.tsx +24 -0
- package/templates/nextjs/src/components/ui/index.ts +27 -0
- package/templates/nextjs/src/components/ui/input.tsx +23 -0
- package/templates/nextjs/src/components/ui/label.tsx +17 -0
- package/templates/nextjs/src/components/ui/skeleton.tsx +13 -0
- package/templates/nextjs/src/components/ui/table.tsx +94 -0
- package/templates/nextjs/src/components/ui/tabs.tsx +46 -0
- package/templates/nextjs/src/config/seo.config.ts +37 -0
- package/templates/nextjs/src/config/site.config.ts +15 -0
- package/templates/nextjs/src/constants/index.ts +5 -0
- package/templates/nextjs/src/env.ts +41 -0
- package/templates/nextjs/src/features/landing/api/get-users.api.ts +7 -0
- package/templates/nextjs/src/features/landing/api/index.ts +2 -0
- package/templates/nextjs/src/features/landing/api/query-keys.ts +7 -0
- package/templates/nextjs/src/features/landing/components/CartDemo.tsx +66 -0
- package/templates/nextjs/src/features/landing/components/Features.tsx +39 -0
- package/templates/nextjs/src/features/landing/components/Hero.tsx +65 -0
- package/templates/nextjs/src/features/landing/components/LandingPage.tsx +17 -0
- package/templates/nextjs/src/features/landing/components/ProjectFormDemo.tsx +62 -0
- package/templates/nextjs/src/features/landing/components/Reveal.tsx +83 -0
- package/templates/nextjs/src/features/landing/components/Showcase.tsx +66 -0
- package/templates/nextjs/src/features/landing/components/UsersDemo.tsx +188 -0
- package/templates/nextjs/src/features/landing/data/features.data.tsx +47 -0
- package/templates/nextjs/src/features/landing/data/index.ts +1 -0
- package/templates/nextjs/src/features/landing/helpers/get-initials.ts +15 -0
- package/templates/nextjs/src/features/landing/helpers/index.ts +7 -0
- package/templates/nextjs/src/features/landing/helpers/motion.ts +21 -0
- package/templates/nextjs/src/features/landing/hooks/index.ts +1 -0
- package/templates/nextjs/src/features/landing/hooks/use-users.ts +16 -0
- package/templates/nextjs/src/features/landing/icons/index.ts +6 -0
- package/templates/nextjs/src/features/landing/icons/nextjs.tsx +68 -0
- package/templates/nextjs/src/features/landing/icons/react-hook-form.tsx +18 -0
- package/templates/nextjs/src/features/landing/icons/react.tsx +20 -0
- package/templates/nextjs/src/features/landing/icons/tailwind.tsx +14 -0
- package/templates/nextjs/src/features/landing/icons/tanstack.tsx +321 -0
- package/templates/nextjs/src/features/landing/icons/typescript.tsx +16 -0
- package/templates/nextjs/src/features/landing/index.ts +1 -0
- package/templates/nextjs/src/features/landing/schemas/index.ts +1 -0
- package/templates/nextjs/src/features/landing/schemas/project.schema.ts +7 -0
- package/templates/nextjs/src/features/landing/stores/counter.store.ts +18 -0
- package/templates/nextjs/src/features/landing/stores/index.ts +1 -0
- package/templates/nextjs/src/features/landing/types/index.ts +1 -0
- package/templates/nextjs/src/features/landing/types/user.types.ts +9 -0
- package/templates/nextjs/src/helpers/format-date.ts +13 -0
- package/templates/nextjs/src/helpers/index.ts +1 -0
- package/templates/nextjs/src/hooks/index.ts +5 -0
- package/templates/nextjs/src/lib/api.ts +97 -0
- package/templates/nextjs/src/lib/query-client.ts +18 -0
- package/templates/nextjs/src/lib/utils.ts +12 -0
- package/templates/nextjs/src/providers/Providers.tsx +15 -0
- package/templates/nextjs/src/providers/QueryProvider.tsx +19 -0
- package/templates/nextjs/src/providers/ThemeProvider.tsx +9 -0
- package/templates/nextjs/src/providers/index.ts +1 -0
- package/templates/nextjs/src/proxy.ts +6 -0
- package/templates/nextjs/src/schemas/index.ts +5 -0
- package/templates/nextjs/src/stores/index.ts +5 -0
- package/templates/nextjs/src/styles/tailwind.css +122 -0
- package/templates/nextjs/src/types/site-config.types.ts +10 -0
- package/templates/nextjs/tsconfig.json +45 -0
- package/templates/nextjs/tsconfig.tsbuildinfo +1 -0
- package/templates/tanstack/.changeset/README.md +8 -0
- package/templates/tanstack/.changeset/config.json +11 -0
- package/templates/tanstack/.env.example +6 -0
- package/templates/tanstack/.env.local +6 -0
- package/templates/tanstack/.eslintcache +1 -0
- package/templates/tanstack/.github/workflows/ci.yml +41 -0
- package/templates/tanstack/.husky/commit-msg +1 -0
- package/templates/tanstack/.husky/pre-commit +1 -0
- package/templates/tanstack/.husky/pre-push +1 -0
- package/templates/tanstack/.prettierignore +7 -0
- package/templates/tanstack/.prettierrc +41 -0
- package/templates/tanstack/.vscode/extensions.json +7 -0
- package/templates/tanstack/.vscode/settings.json +22 -0
- package/templates/tanstack/LICENSE +21 -0
- package/templates/tanstack/README.md +204 -0
- package/templates/tanstack/_gitignore +52 -0
- package/templates/tanstack/commitlint.config.js +6 -0
- package/templates/tanstack/eslint.config.js +28 -0
- package/templates/tanstack/knip.config.js +22 -0
- package/templates/tanstack/package.json +130 -0
- package/templates/tanstack/pnpm-lock.yaml +5835 -0
- package/templates/tanstack/pnpm-workspace.yaml +3 -0
- package/templates/tanstack/public/favicon.ico +0 -0
- package/templates/tanstack/public/llms.txt +86 -0
- package/templates/tanstack/public/logo.png +0 -0
- package/templates/tanstack/public/logo.webp +0 -0
- package/templates/tanstack/public/og.png +0 -0
- package/templates/tanstack/src/components/shared/DefaultCatchBoundary.tsx +36 -0
- package/templates/tanstack/src/components/shared/NotFound.tsx +18 -0
- package/templates/tanstack/src/components/shared/Pending.tsx +13 -0
- package/templates/tanstack/src/components/shared/ThemeToggle.tsx +31 -0
- package/templates/tanstack/src/components/ui/avatar.tsx +52 -0
- package/templates/tanstack/src/components/ui/button.tsx +47 -0
- package/templates/tanstack/src/components/ui/dialog.tsx +107 -0
- package/templates/tanstack/src/components/ui/field.tsx +24 -0
- package/templates/tanstack/src/components/ui/index.ts +27 -0
- package/templates/tanstack/src/components/ui/input.tsx +23 -0
- package/templates/tanstack/src/components/ui/label.tsx +17 -0
- package/templates/tanstack/src/components/ui/skeleton.tsx +13 -0
- package/templates/tanstack/src/components/ui/table.tsx +94 -0
- package/templates/tanstack/src/components/ui/tabs.tsx +46 -0
- package/templates/tanstack/src/config/seo.config.ts +52 -0
- package/templates/tanstack/src/config/site.config.ts +15 -0
- package/templates/tanstack/src/constants/index.ts +5 -0
- package/templates/tanstack/src/env.ts +47 -0
- package/templates/tanstack/src/features/landing/api/get-users.api.ts +7 -0
- package/templates/tanstack/src/features/landing/api/index.ts +2 -0
- package/templates/tanstack/src/features/landing/api/query-keys.ts +7 -0
- package/templates/tanstack/src/features/landing/components/CartDemo.tsx +66 -0
- package/templates/tanstack/src/features/landing/components/Features.tsx +39 -0
- package/templates/tanstack/src/features/landing/components/Hero.tsx +63 -0
- package/templates/tanstack/src/features/landing/components/LandingPage.tsx +17 -0
- package/templates/tanstack/src/features/landing/components/ProjectFormDemo.tsx +63 -0
- package/templates/tanstack/src/features/landing/components/Reveal.tsx +83 -0
- package/templates/tanstack/src/features/landing/components/Showcase.tsx +66 -0
- package/templates/tanstack/src/features/landing/components/UsersDemo.tsx +191 -0
- package/templates/tanstack/src/features/landing/data/features.data.tsx +45 -0
- package/templates/tanstack/src/features/landing/data/index.ts +1 -0
- package/templates/tanstack/src/features/landing/helpers/get-initials.ts +15 -0
- package/templates/tanstack/src/features/landing/helpers/index.ts +7 -0
- package/templates/tanstack/src/features/landing/helpers/motion.ts +21 -0
- package/templates/tanstack/src/features/landing/hooks/index.ts +1 -0
- package/templates/tanstack/src/features/landing/hooks/use-users.ts +19 -0
- package/templates/tanstack/src/features/landing/icons/index.ts +5 -0
- package/templates/tanstack/src/features/landing/icons/react-hook-form.tsx +18 -0
- package/templates/tanstack/src/features/landing/icons/react.tsx +20 -0
- package/templates/tanstack/src/features/landing/icons/tailwind.tsx +14 -0
- package/templates/tanstack/src/features/landing/icons/tanstack.tsx +321 -0
- package/templates/tanstack/src/features/landing/icons/typescript.tsx +16 -0
- package/templates/tanstack/src/features/landing/index.ts +1 -0
- package/templates/tanstack/src/features/landing/schemas/index.ts +1 -0
- package/templates/tanstack/src/features/landing/schemas/project.schema.ts +7 -0
- package/templates/tanstack/src/features/landing/stores/counter.store.ts +18 -0
- package/templates/tanstack/src/features/landing/stores/index.ts +1 -0
- package/templates/tanstack/src/features/landing/types/index.ts +1 -0
- package/templates/tanstack/src/features/landing/types/user.types.ts +9 -0
- package/templates/tanstack/src/helpers/format-date.ts +13 -0
- package/templates/tanstack/src/helpers/index.ts +1 -0
- package/templates/tanstack/src/hooks/index.ts +5 -0
- package/templates/tanstack/src/lib/api.ts +97 -0
- package/templates/tanstack/src/lib/query-client.ts +18 -0
- package/templates/tanstack/src/lib/utils.ts +13 -0
- package/templates/tanstack/src/providers/Providers.tsx +12 -0
- package/templates/tanstack/src/providers/ThemeProvider.tsx +98 -0
- package/templates/tanstack/src/providers/devtools.tsx +6 -0
- package/templates/tanstack/src/providers/index.ts +1 -0
- package/templates/tanstack/src/providers/root-provider.ts +9 -0
- package/templates/tanstack/src/routeTree.gen.ts +123 -0
- package/templates/tanstack/src/router.tsx +27 -0
- package/templates/tanstack/src/routes/__root.tsx +78 -0
- package/templates/tanstack/src/routes/index.tsx +13 -0
- package/templates/tanstack/src/routes/robots[.]txt.ts +21 -0
- package/templates/tanstack/src/routes/site[.]webmanifest.ts +32 -0
- package/templates/tanstack/src/routes/sitemap[.]xml.ts +27 -0
- package/templates/tanstack/src/schemas/index.ts +5 -0
- package/templates/tanstack/src/start.ts +20 -0
- package/templates/tanstack/src/stores/index.ts +5 -0
- package/templates/tanstack/src/styles/tailwind.css +123 -0
- package/templates/tanstack/src/types/site-config.types.ts +10 -0
- package/templates/tanstack/tsconfig.json +25 -0
- package/templates/tanstack/tsr.config.json +3 -0
- package/templates/tanstack/vite.config.ts +12 -0
- package/templates-i18n/nextjs/.changeset/README.md +8 -0
- package/templates-i18n/nextjs/.changeset/config.json +11 -0
- package/templates-i18n/nextjs/.env.example +6 -0
- package/templates-i18n/nextjs/.eslintcache +1 -0
- package/templates-i18n/nextjs/.github/workflows/ci.yml +41 -0
- package/templates-i18n/nextjs/.husky/commit-msg +1 -0
- package/templates-i18n/nextjs/.husky/pre-commit +1 -0
- package/templates-i18n/nextjs/.husky/pre-push +1 -0
- package/templates-i18n/nextjs/.prettierignore +6 -0
- package/templates-i18n/nextjs/.prettierrc +42 -0
- package/templates-i18n/nextjs/.vscode/extensions.json +7 -0
- package/templates-i18n/nextjs/.vscode/settings.json +20 -0
- package/templates-i18n/nextjs/LICENSE +21 -0
- package/templates-i18n/nextjs/README.md +202 -0
- package/templates-i18n/nextjs/_gitignore +45 -0
- package/templates-i18n/nextjs/commitlint.config.js +6 -0
- package/templates-i18n/nextjs/eslint.config.mjs +27 -0
- package/templates-i18n/nextjs/knip.config.js +29 -0
- package/templates-i18n/nextjs/next-env.d.ts +6 -0
- package/templates-i18n/nextjs/next.config.ts +42 -0
- package/templates-i18n/nextjs/package.json +117 -0
- package/templates-i18n/nextjs/pnpm-lock.yaml +6854 -0
- package/templates-i18n/nextjs/pnpm-workspace.yaml +3 -0
- package/templates-i18n/nextjs/postcss.config.mjs +7 -0
- package/templates-i18n/nextjs/public/favicon.ico +0 -0
- package/templates-i18n/nextjs/public/llms.txt +96 -0
- package/templates-i18n/nextjs/public/logo.png +0 -0
- package/templates-i18n/nextjs/public/logo.webp +0 -0
- package/templates-i18n/nextjs/public/og.png +0 -0
- package/templates-i18n/nextjs/src/app/[locale]/error.tsx +34 -0
- package/templates-i18n/nextjs/src/app/[locale]/layout.tsx +60 -0
- package/templates-i18n/nextjs/src/app/[locale]/loading.tsx +12 -0
- package/templates-i18n/nextjs/src/app/[locale]/not-found.tsx +18 -0
- package/templates-i18n/nextjs/src/app/[locale]/page.tsx +10 -0
- package/templates-i18n/nextjs/src/app/favicon.ico +0 -0
- package/templates-i18n/nextjs/src/app/global-error.tsx +32 -0
- package/templates-i18n/nextjs/src/app/manifest.ts +22 -0
- package/templates-i18n/nextjs/src/app/robots.ts +13 -0
- package/templates-i18n/nextjs/src/app/sitemap.ts +14 -0
- package/templates-i18n/nextjs/src/components/shared/LanguageSwitcher.tsx +48 -0
- package/templates-i18n/nextjs/src/components/shared/ThemeToggle.tsx +30 -0
- package/templates-i18n/nextjs/src/components/ui/avatar.tsx +54 -0
- package/templates-i18n/nextjs/src/components/ui/button.tsx +46 -0
- package/templates-i18n/nextjs/src/components/ui/dialog.tsx +107 -0
- package/templates-i18n/nextjs/src/components/ui/field.tsx +24 -0
- package/templates-i18n/nextjs/src/components/ui/index.ts +27 -0
- package/templates-i18n/nextjs/src/components/ui/input.tsx +23 -0
- package/templates-i18n/nextjs/src/components/ui/label.tsx +17 -0
- package/templates-i18n/nextjs/src/components/ui/skeleton.tsx +13 -0
- package/templates-i18n/nextjs/src/components/ui/table.tsx +94 -0
- package/templates-i18n/nextjs/src/components/ui/tabs.tsx +46 -0
- package/templates-i18n/nextjs/src/config/seo.config.ts +37 -0
- package/templates-i18n/nextjs/src/config/site.config.ts +15 -0
- package/templates-i18n/nextjs/src/constants/index.ts +5 -0
- package/templates-i18n/nextjs/src/env.ts +41 -0
- package/templates-i18n/nextjs/src/features/landing/api/get-users.api.ts +7 -0
- package/templates-i18n/nextjs/src/features/landing/api/index.ts +2 -0
- package/templates-i18n/nextjs/src/features/landing/api/query-keys.ts +7 -0
- package/templates-i18n/nextjs/src/features/landing/components/CartDemo.tsx +68 -0
- package/templates-i18n/nextjs/src/features/landing/components/Features.tsx +84 -0
- package/templates-i18n/nextjs/src/features/landing/components/Hero.tsx +76 -0
- package/templates-i18n/nextjs/src/features/landing/components/LandingPage.tsx +17 -0
- package/templates-i18n/nextjs/src/features/landing/components/ProjectFormDemo.tsx +64 -0
- package/templates-i18n/nextjs/src/features/landing/components/Reveal.tsx +83 -0
- package/templates-i18n/nextjs/src/features/landing/components/Showcase.tsx +83 -0
- package/templates-i18n/nextjs/src/features/landing/components/UsersDemo.tsx +191 -0
- package/templates-i18n/nextjs/src/features/landing/data/features.data.tsx +47 -0
- package/templates-i18n/nextjs/src/features/landing/data/index.ts +1 -0
- package/templates-i18n/nextjs/src/features/landing/helpers/get-initials.ts +15 -0
- package/templates-i18n/nextjs/src/features/landing/helpers/index.ts +7 -0
- package/templates-i18n/nextjs/src/features/landing/helpers/motion.ts +21 -0
- package/templates-i18n/nextjs/src/features/landing/hooks/index.ts +1 -0
- package/templates-i18n/nextjs/src/features/landing/hooks/use-users.ts +16 -0
- package/templates-i18n/nextjs/src/features/landing/icons/index.ts +6 -0
- package/templates-i18n/nextjs/src/features/landing/icons/nextjs.tsx +68 -0
- package/templates-i18n/nextjs/src/features/landing/icons/react-hook-form.tsx +18 -0
- package/templates-i18n/nextjs/src/features/landing/icons/react.tsx +20 -0
- package/templates-i18n/nextjs/src/features/landing/icons/tailwind.tsx +14 -0
- package/templates-i18n/nextjs/src/features/landing/icons/tanstack.tsx +321 -0
- package/templates-i18n/nextjs/src/features/landing/icons/typescript.tsx +16 -0
- package/templates-i18n/nextjs/src/features/landing/index.ts +1 -0
- package/templates-i18n/nextjs/src/features/landing/schemas/index.ts +1 -0
- package/templates-i18n/nextjs/src/features/landing/schemas/project.schema.ts +9 -0
- package/templates-i18n/nextjs/src/features/landing/stores/counter.store.ts +18 -0
- package/templates-i18n/nextjs/src/features/landing/stores/index.ts +1 -0
- package/templates-i18n/nextjs/src/features/landing/types/index.ts +1 -0
- package/templates-i18n/nextjs/src/features/landing/types/user.types.ts +9 -0
- package/templates-i18n/nextjs/src/helpers/format-date.ts +13 -0
- package/templates-i18n/nextjs/src/helpers/index.ts +1 -0
- package/templates-i18n/nextjs/src/hooks/index.ts +5 -0
- package/templates-i18n/nextjs/src/i18n/request.ts +16 -0
- package/templates-i18n/nextjs/src/i18n/routing.ts +11 -0
- package/templates-i18n/nextjs/src/lib/api.ts +97 -0
- package/templates-i18n/nextjs/src/lib/query-client.ts +18 -0
- package/templates-i18n/nextjs/src/lib/utils.ts +12 -0
- package/templates-i18n/nextjs/src/messages/en.json +55 -0
- package/templates-i18n/nextjs/src/messages/tr.json +55 -0
- package/templates-i18n/nextjs/src/providers/Providers.tsx +15 -0
- package/templates-i18n/nextjs/src/providers/QueryProvider.tsx +19 -0
- package/templates-i18n/nextjs/src/providers/ThemeProvider.tsx +9 -0
- package/templates-i18n/nextjs/src/providers/index.ts +1 -0
- package/templates-i18n/nextjs/src/proxy.ts +16 -0
- package/templates-i18n/nextjs/src/schemas/index.ts +5 -0
- package/templates-i18n/nextjs/src/stores/index.ts +5 -0
- package/templates-i18n/nextjs/src/styles/tailwind.css +122 -0
- package/templates-i18n/nextjs/src/types/site-config.types.ts +10 -0
- package/templates-i18n/nextjs/tsconfig.json +45 -0
- package/templates-i18n/nextjs/tsconfig.tsbuildinfo +1 -0
- package/templates-i18n/tanstack/.changeset/README.md +8 -0
- package/templates-i18n/tanstack/.changeset/config.json +11 -0
- package/templates-i18n/tanstack/.env.example +6 -0
- package/templates-i18n/tanstack/.eslintcache +1 -0
- package/templates-i18n/tanstack/.github/workflows/ci.yml +41 -0
- package/templates-i18n/tanstack/.husky/commit-msg +1 -0
- package/templates-i18n/tanstack/.husky/pre-commit +1 -0
- package/templates-i18n/tanstack/.husky/pre-push +1 -0
- package/templates-i18n/tanstack/.prettierignore +7 -0
- package/templates-i18n/tanstack/.prettierrc +41 -0
- package/templates-i18n/tanstack/.vscode/extensions.json +7 -0
- package/templates-i18n/tanstack/.vscode/settings.json +22 -0
- package/templates-i18n/tanstack/LICENSE +21 -0
- package/templates-i18n/tanstack/README.md +204 -0
- package/templates-i18n/tanstack/_gitignore +52 -0
- package/templates-i18n/tanstack/commitlint.config.js +6 -0
- package/templates-i18n/tanstack/eslint.config.js +29 -0
- package/templates-i18n/tanstack/knip.config.js +26 -0
- package/templates-i18n/tanstack/messages/en.json +65 -0
- package/templates-i18n/tanstack/messages/tr.json +65 -0
- package/templates-i18n/tanstack/package.json +132 -0
- package/templates-i18n/tanstack/pnpm-lock.yaml +5998 -0
- package/templates-i18n/tanstack/pnpm-workspace.yaml +3 -0
- package/templates-i18n/tanstack/project.inlang/README.md +157 -0
- package/templates-i18n/tanstack/project.inlang/settings.json +9 -0
- package/templates-i18n/tanstack/public/favicon.ico +0 -0
- package/templates-i18n/tanstack/public/llms.txt +86 -0
- package/templates-i18n/tanstack/public/logo.png +0 -0
- package/templates-i18n/tanstack/public/logo.webp +0 -0
- package/templates-i18n/tanstack/public/og.png +0 -0
- package/templates-i18n/tanstack/src/components/shared/DefaultCatchBoundary.tsx +36 -0
- package/templates-i18n/tanstack/src/components/shared/LanguageSwitcher.tsx +57 -0
- package/templates-i18n/tanstack/src/components/shared/NotFound.tsx +18 -0
- package/templates-i18n/tanstack/src/components/shared/Pending.tsx +13 -0
- package/templates-i18n/tanstack/src/components/shared/ThemeToggle.tsx +31 -0
- package/templates-i18n/tanstack/src/components/ui/avatar.tsx +52 -0
- package/templates-i18n/tanstack/src/components/ui/button.tsx +47 -0
- package/templates-i18n/tanstack/src/components/ui/dialog.tsx +107 -0
- package/templates-i18n/tanstack/src/components/ui/field.tsx +24 -0
- package/templates-i18n/tanstack/src/components/ui/index.ts +27 -0
- package/templates-i18n/tanstack/src/components/ui/input.tsx +23 -0
- package/templates-i18n/tanstack/src/components/ui/label.tsx +17 -0
- package/templates-i18n/tanstack/src/components/ui/skeleton.tsx +13 -0
- package/templates-i18n/tanstack/src/components/ui/table.tsx +94 -0
- package/templates-i18n/tanstack/src/components/ui/tabs.tsx +46 -0
- package/templates-i18n/tanstack/src/config/seo.config.ts +52 -0
- package/templates-i18n/tanstack/src/config/site.config.ts +15 -0
- package/templates-i18n/tanstack/src/constants/index.ts +5 -0
- package/templates-i18n/tanstack/src/env.ts +47 -0
- package/templates-i18n/tanstack/src/features/landing/api/get-users.api.ts +7 -0
- package/templates-i18n/tanstack/src/features/landing/api/index.ts +2 -0
- package/templates-i18n/tanstack/src/features/landing/api/query-keys.ts +7 -0
- package/templates-i18n/tanstack/src/features/landing/components/CartDemo.tsx +67 -0
- package/templates-i18n/tanstack/src/features/landing/components/Features.tsx +79 -0
- package/templates-i18n/tanstack/src/features/landing/components/Hero.tsx +68 -0
- package/templates-i18n/tanstack/src/features/landing/components/LandingPage.tsx +17 -0
- package/templates-i18n/tanstack/src/features/landing/components/ProjectFormDemo.tsx +64 -0
- package/templates-i18n/tanstack/src/features/landing/components/Reveal.tsx +83 -0
- package/templates-i18n/tanstack/src/features/landing/components/Showcase.tsx +81 -0
- package/templates-i18n/tanstack/src/features/landing/components/UsersDemo.tsx +191 -0
- package/templates-i18n/tanstack/src/features/landing/data/features.data.tsx +45 -0
- package/templates-i18n/tanstack/src/features/landing/data/index.ts +1 -0
- package/templates-i18n/tanstack/src/features/landing/helpers/get-initials.ts +15 -0
- package/templates-i18n/tanstack/src/features/landing/helpers/index.ts +7 -0
- package/templates-i18n/tanstack/src/features/landing/helpers/motion.ts +21 -0
- package/templates-i18n/tanstack/src/features/landing/hooks/index.ts +1 -0
- package/templates-i18n/tanstack/src/features/landing/hooks/use-users.ts +19 -0
- package/templates-i18n/tanstack/src/features/landing/icons/index.ts +5 -0
- package/templates-i18n/tanstack/src/features/landing/icons/react-hook-form.tsx +18 -0
- package/templates-i18n/tanstack/src/features/landing/icons/react.tsx +20 -0
- package/templates-i18n/tanstack/src/features/landing/icons/tailwind.tsx +14 -0
- package/templates-i18n/tanstack/src/features/landing/icons/tanstack.tsx +321 -0
- package/templates-i18n/tanstack/src/features/landing/icons/typescript.tsx +16 -0
- package/templates-i18n/tanstack/src/features/landing/index.ts +1 -0
- package/templates-i18n/tanstack/src/features/landing/schemas/index.ts +1 -0
- package/templates-i18n/tanstack/src/features/landing/schemas/project.schema.ts +10 -0
- package/templates-i18n/tanstack/src/features/landing/stores/counter.store.ts +18 -0
- package/templates-i18n/tanstack/src/features/landing/stores/index.ts +1 -0
- package/templates-i18n/tanstack/src/features/landing/types/index.ts +1 -0
- package/templates-i18n/tanstack/src/features/landing/types/user.types.ts +9 -0
- package/templates-i18n/tanstack/src/helpers/format-date.ts +13 -0
- package/templates-i18n/tanstack/src/helpers/index.ts +1 -0
- package/templates-i18n/tanstack/src/hooks/index.ts +5 -0
- package/templates-i18n/tanstack/src/lib/api.ts +97 -0
- package/templates-i18n/tanstack/src/lib/query-client.ts +18 -0
- package/templates-i18n/tanstack/src/lib/utils.ts +13 -0
- package/templates-i18n/tanstack/src/paraglide/README.md +162 -0
- package/templates-i18n/tanstack/src/providers/Providers.tsx +12 -0
- package/templates-i18n/tanstack/src/providers/ThemeProvider.tsx +98 -0
- package/templates-i18n/tanstack/src/providers/devtools.tsx +6 -0
- package/templates-i18n/tanstack/src/providers/index.ts +1 -0
- package/templates-i18n/tanstack/src/providers/root-provider.ts +9 -0
- package/templates-i18n/tanstack/src/routeTree.gen.ts +179 -0
- package/templates-i18n/tanstack/src/router.tsx +27 -0
- package/templates-i18n/tanstack/src/routes/$lang/index.tsx +13 -0
- package/templates-i18n/tanstack/src/routes/$lang.tsx +22 -0
- package/templates-i18n/tanstack/src/routes/__root.tsx +80 -0
- package/templates-i18n/tanstack/src/routes/index.tsx +13 -0
- package/templates-i18n/tanstack/src/routes/robots[.]txt.ts +21 -0
- package/templates-i18n/tanstack/src/routes/site[.]webmanifest.ts +32 -0
- package/templates-i18n/tanstack/src/routes/sitemap[.]xml.ts +27 -0
- package/templates-i18n/tanstack/src/schemas/index.ts +5 -0
- package/templates-i18n/tanstack/src/server.ts +10 -0
- package/templates-i18n/tanstack/src/start.ts +20 -0
- package/templates-i18n/tanstack/src/stores/index.ts +5 -0
- package/templates-i18n/tanstack/src/styles/tailwind.css +123 -0
- package/templates-i18n/tanstack/src/types/site-config.types.ts +10 -0
- package/templates-i18n/tanstack/tsconfig.json +26 -0
- package/templates-i18n/tanstack/tsr.config.json +3 -0
- package/templates-i18n/tanstack/vite.config.ts +31 -0
- package/index.js +0 -3
- package/public/start.jpg +0 -0
|
Binary file
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
# ViraStack Start — Next.js Edition
|
|
2
|
+
|
|
3
|
+
> Premium Next.js 16 + React 19 + Tailwind CSS 4 boilerplate focused on clean architecture, UI/UX, and agent-ready developer experience. Auth, database/ORM, i18n, and testing are intentionally omitted — bring the solution that fits your project.
|
|
4
|
+
|
|
5
|
+
Built on the App Router with Server/Client Components, streaming, and the Metadata API. UI primitives use **Base UI** (unstyled, accessible) styled with Tailwind CSS 4 design tokens. State is split by job: TanStack Query for server state, Zustand for client state, `nuqs` for URL state. Forms use React Hook Form + Zod. The home route renders a deletable `features/landing` demo that follows the canonical ViraStack feature tree. **ViraStack AI** (`@virastack/ai`) adds agent rules on scaffold; design skills come from [emilkowalski/skills](https://github.com/emilkowalski/skills) and [make-interfaces-feel-better](https://github.com/jakubkrehel/make-interfaces-feel-better).
|
|
6
|
+
|
|
7
|
+
- Tech stack: Next.js 16, React 19, Tailwind CSS 4, TypeScript 5 (strict + `noUncheckedIndexedAccess`), Node.js `>=20.9`
|
|
8
|
+
- UI: Base UI, Framer Motion, Sonner, Lucide React, `next-themes`, `class-variance-authority`
|
|
9
|
+
- Data & state: TanStack Query 5, Zustand, `nuqs`
|
|
10
|
+
- Forms: React Hook Form + Zod (+ `@hookform/resolvers`)
|
|
11
|
+
- API: Native `fetch` wrapper in `src/lib/api.ts` (`ApiError` with `message`, `status`, `data`); Axios is optional, not installed
|
|
12
|
+
- Env: Hand-rolled Zod schema in `src/env.ts` (no `@t3-oss/env-nextjs`)
|
|
13
|
+
- Tooling: ESLint 9, Prettier 3, Husky, Knip, Commitlint, Changesets, `@next/bundle-analyzer`
|
|
14
|
+
- Quality scripts: `pnpm typecheck`, `pnpm lint` / `lint:ci`, `pnpm knip`, `pnpm build`
|
|
15
|
+
- ViraStack AI (via `npx @virastack/ai init`): `AGENTS.md`, `CLAUDE.md`, `.cursor/rules/*.mdc`, `docs/*`
|
|
16
|
+
- Not included by default: Auth, DB/ORM, i18n (`next-intl` not installed), test runner, CSP
|
|
17
|
+
|
|
18
|
+
## Docs
|
|
19
|
+
- [Repository (GitHub)](https://github.com/virastack/start): CLI and templates
|
|
20
|
+
- [README](https://github.com/virastack/start/tree/main/templates/nextjs): Features, structure, and conventions
|
|
21
|
+
- [Architecture guide](https://github.com/virastack/ai/blob/main/templates/core/docs/architecture-guide.md): Placement rules and import conventions
|
|
22
|
+
- [Product docs](https://www.virastack.com/nextjs-boilerplate/): ViraStack Next.js boilerplate
|
|
23
|
+
|
|
24
|
+
## Key Files & Entry Points
|
|
25
|
+
- [`src/app/layout.tsx`](https://github.com/virastack/start/blob/main/templates/nextjs/src/app/layout.tsx): Root layout, fonts, providers
|
|
26
|
+
- [`src/app/page.tsx`](https://github.com/virastack/start/blob/main/templates/nextjs/src/app/page.tsx): Home route → `<LandingPage />`
|
|
27
|
+
- [`src/app/loading.tsx`](https://github.com/virastack/start/blob/main/templates/nextjs/src/app/loading.tsx): Route-level skeleton
|
|
28
|
+
- [`src/app/error.tsx`](https://github.com/virastack/start/blob/main/templates/nextjs/src/app/error.tsx): Route-level error boundary
|
|
29
|
+
- [`src/app/not-found.tsx`](https://github.com/virastack/start/blob/main/templates/nextjs/src/app/not-found.tsx): 404 boundary
|
|
30
|
+
- [`src/app/global-error.tsx`](https://github.com/virastack/start/blob/main/templates/nextjs/src/app/global-error.tsx): Root error boundary
|
|
31
|
+
- [`src/app/robots.ts`](https://github.com/virastack/start/blob/main/templates/nextjs/src/app/robots.ts): Robots configuration
|
|
32
|
+
- [`src/app/sitemap.ts`](https://github.com/virastack/start/blob/main/templates/nextjs/src/app/sitemap.ts): Sitemap generation
|
|
33
|
+
- [`src/app/manifest.ts`](https://github.com/virastack/start/blob/main/templates/nextjs/src/app/manifest.ts): Web app manifest (titles from `siteConfig`)
|
|
34
|
+
- [`src/proxy.ts`](https://github.com/virastack/start/blob/main/templates/nextjs/src/proxy.ts): Next.js 16 network boundary scaffold (passthrough)
|
|
35
|
+
- [`src/env.ts`](https://github.com/virastack/start/blob/main/templates/nextjs/src/env.ts): Zod-validated environment schema
|
|
36
|
+
- [`src/config/site.config.ts`](https://github.com/virastack/start/blob/main/templates/nextjs/src/config/site.config.ts): Site config (name, URL, links)
|
|
37
|
+
- [`src/config/seo.config.ts`](https://github.com/virastack/start/blob/main/templates/nextjs/src/config/seo.config.ts): Default Metadata object (OG/icons via `/og.png`, `/logo.webp`)
|
|
38
|
+
- [`src/lib/api.ts`](https://github.com/virastack/start/blob/main/templates/nextjs/src/lib/api.ts): Native `fetch` wrapper with retry & typed `ApiError`
|
|
39
|
+
- [`src/lib/query-client.ts`](https://github.com/virastack/start/blob/main/templates/nextjs/src/lib/query-client.ts): QueryClient factory & defaults
|
|
40
|
+
- [`src/providers/Providers.tsx`](https://github.com/virastack/start/blob/main/templates/nextjs/src/providers/Providers.tsx): App-wide providers (Theme, Query, Nuqs, Toaster)
|
|
41
|
+
- [`next.config.ts`](https://github.com/virastack/start/blob/main/templates/nextjs/next.config.ts): Next config + baseline security headers (no CSP by default)
|
|
42
|
+
|
|
43
|
+
## Landing Feature (demo — delete when building)
|
|
44
|
+
Canonical tree under `src/features/landing/`. Home page composes `LandingPage`.
|
|
45
|
+
|
|
46
|
+
- [`src/features/landing/index.ts`](https://github.com/virastack/start/blob/main/templates/nextjs/src/features/landing/index.ts): Public export (`LandingPage`)
|
|
47
|
+
- [`src/features/landing/components/LandingPage.tsx`](https://github.com/virastack/start/blob/main/templates/nextjs/src/features/landing/components/LandingPage.tsx): Page composition (Header + sections + Footer)
|
|
48
|
+
- [`src/features/landing/components/Hero.tsx`](https://github.com/virastack/start/blob/main/templates/nextjs/src/features/landing/components/Hero.tsx): Hero section
|
|
49
|
+
- [`src/features/landing/components/Features.tsx`](https://github.com/virastack/start/blob/main/templates/nextjs/src/features/landing/components/Features.tsx): Feature grid
|
|
50
|
+
- [`src/features/landing/components/Showcase.tsx`](https://github.com/virastack/start/blob/main/templates/nextjs/src/features/landing/components/Showcase.tsx): Stack demos host (Query, Zustand, forms, nuqs)
|
|
51
|
+
- [`src/features/landing/components/UsersDemo.tsx`](https://github.com/virastack/start/blob/main/templates/nextjs/src/features/landing/components/UsersDemo.tsx): TanStack Query + `nuqs` demo
|
|
52
|
+
- [`src/features/landing/components/CartDemo.tsx`](https://github.com/virastack/start/blob/main/templates/nextjs/src/features/landing/components/CartDemo.tsx): Zustand demo
|
|
53
|
+
- [`src/features/landing/components/ProjectFormDemo.tsx`](https://github.com/virastack/start/blob/main/templates/nextjs/src/features/landing/components/ProjectFormDemo.tsx): RHF + Zod demo
|
|
54
|
+
- [`src/features/landing/api/get-users.api.ts`](https://github.com/virastack/start/blob/main/templates/nextjs/src/features/landing/api/get-users.api.ts): Feature API function
|
|
55
|
+
- [`src/features/landing/hooks/use-users.ts`](https://github.com/virastack/start/blob/main/templates/nextjs/src/features/landing/hooks/use-users.ts): Feature TanStack Query hook
|
|
56
|
+
- [`src/features/landing/stores/counter.store.ts`](https://github.com/virastack/start/blob/main/templates/nextjs/src/features/landing/stores/counter.store.ts): Feature Zustand store
|
|
57
|
+
- [`src/features/landing/schemas/project.schema.ts`](https://github.com/virastack/start/blob/main/templates/nextjs/src/features/landing/schemas/project.schema.ts): Feature Zod schema
|
|
58
|
+
- [`src/features/landing/data/features.data.tsx`](https://github.com/virastack/start/blob/main/templates/nextjs/src/features/landing/data/features.data.tsx): Feature static data
|
|
59
|
+
- [`src/features/landing/helpers/`](https://github.com/virastack/start/tree/main/templates/nextjs/src/features/landing/helpers): Feature helpers (motion tokens, initials)
|
|
60
|
+
- [`src/features/landing/icons/`](https://github.com/virastack/start/tree/main/templates/nextjs/src/features/landing/icons): Brand SVGs used only by the landing demo
|
|
61
|
+
- [`src/features/landing/types/user.types.ts`](https://github.com/virastack/start/blob/main/templates/nextjs/src/features/landing/types/user.types.ts): Feature types
|
|
62
|
+
|
|
63
|
+
Quick start: delete `src/features/landing`, replace `src/app/page.tsx`, keep `components/layout` if you still want chrome.
|
|
64
|
+
|
|
65
|
+
## UI & Shared Layers
|
|
66
|
+
- [`src/components/ui`](https://github.com/virastack/start/tree/main/templates/nextjs/src/components/ui): Base UI primitives (Button, Input, Field, Dialog, Tabs, Skeleton, Label, Avatar, Table)
|
|
67
|
+
- [`src/components/layout`](https://github.com/virastack/start/tree/main/templates/nextjs/src/components/layout): Header / Footer (reusable; Header accepts optional `links`)
|
|
68
|
+
- [`src/components/shared`](https://github.com/virastack/start/tree/main/templates/nextjs/src/components/shared): Cross-feature components (ThemeToggle)
|
|
69
|
+
- [`src/hooks`](https://github.com/virastack/start/tree/main/templates/nextjs/src/hooks), [`src/stores`](https://github.com/virastack/start/tree/main/templates/nextjs/src/stores), [`src/schemas`](https://github.com/virastack/start/tree/main/templates/nextjs/src/schemas): Shared barrels (promote via Rule of Three)
|
|
70
|
+
- [`src/helpers`](https://github.com/virastack/start/tree/main/templates/nextjs/src/helpers): Shared helpers
|
|
71
|
+
- [`src/styles/tailwind.css`](https://github.com/virastack/start/blob/main/templates/nextjs/src/styles/tailwind.css): Tailwind v4 entry + design tokens
|
|
72
|
+
- Assets: [`public/logo.webp`](https://github.com/virastack/start/blob/main/templates/nextjs/public/logo.webp), [`public/og.png`](https://github.com/virastack/start/blob/main/templates/nextjs/public/og.png), [`public/favicon.ico`](https://github.com/virastack/start/blob/main/templates/nextjs/public/favicon.ico)
|
|
73
|
+
|
|
74
|
+
## Customization & Imports
|
|
75
|
+
- Search the project for `FIXME:` (site config, remote images, auth attachment on the API client).
|
|
76
|
+
- Prefer short path aliases: `@/ui`, `@/hooks`, `@/schemas`, `@/layout` over long forms. Prefer feature-local imports under `@/features/[feature]/…` for demo-scoped code.
|
|
77
|
+
- Default scope is `features/[feature]/` — promote to global `src/` only when a second feature needs it. No cross-feature imports.
|
|
78
|
+
|
|
79
|
+
## ViraStack AI
|
|
80
|
+
- Install or refresh: `npx @virastack/ai init --force`
|
|
81
|
+
- `AGENTS.md`: Agent operating guide (all agents)
|
|
82
|
+
- `CLAUDE.md`: Claude Code entry point (`@AGENTS.md`)
|
|
83
|
+
- `.cursor/rules/*.mdc`: Scoped coding rules (Cursor auto-loads)
|
|
84
|
+
- `docs/architecture-guide.md`, `docs/MEMORIES.md`: Architecture and project memory
|
|
85
|
+
- Skills: [emilkowalski/skills](https://github.com/emilkowalski/skills) (7 design-engineering skills) + [make-interfaces-feel-better](https://github.com/jakubkrehel/make-interfaces-feel-better)
|
|
86
|
+
- Package: [`@virastack/ai`](https://github.com/virastack/ai)
|
|
87
|
+
|
|
88
|
+
## External References
|
|
89
|
+
- [Next.js Docs](https://nextjs.org/docs): App Router, Server/Client Components, routing, metadata, images, fonts
|
|
90
|
+
- [React](https://react.dev/): Modern React APIs and RSC foundations
|
|
91
|
+
- [Tailwind CSS v4](https://tailwindcss.com/): Design tokens & utility-first styling
|
|
92
|
+
- [Base UI](https://base-ui.com/): Unstyled, accessible React components
|
|
93
|
+
- [TanStack Query](https://tanstack.com/query/latest): Server-state syncing & caching
|
|
94
|
+
- [nuqs](https://nuqs.dev/): Type-safe URL search param state
|
|
95
|
+
- [Zod](https://zod.dev/): Runtime validation and parsing
|
|
96
|
+
- [ViraStack AI](https://github.com/virastack/ai): Shared agent rules package (`@virastack/ai`)
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { useEffect } from "react";
|
|
4
|
+
import Link from "next/link";
|
|
5
|
+
|
|
6
|
+
import { Button } from "@/components/ui/button";
|
|
7
|
+
|
|
8
|
+
export default function Error({
|
|
9
|
+
error,
|
|
10
|
+
reset,
|
|
11
|
+
}: {
|
|
12
|
+
error: Error & { digest?: string };
|
|
13
|
+
reset: () => void;
|
|
14
|
+
}) {
|
|
15
|
+
useEffect(() => {
|
|
16
|
+
console.error(error);
|
|
17
|
+
}, [error]);
|
|
18
|
+
|
|
19
|
+
return (
|
|
20
|
+
<div className="mx-auto flex flex-1 flex-col items-center justify-center gap-4 px-6 py-24 text-center">
|
|
21
|
+
<h1 className="text-2xl font-semibold tracking-tight">Something went wrong</h1>
|
|
22
|
+
<p className="max-w-md text-sm text-muted-foreground">
|
|
23
|
+
An unexpected error occurred while rendering this page. You can try again, or head back to
|
|
24
|
+
the homepage.
|
|
25
|
+
</p>
|
|
26
|
+
<div className="flex gap-3">
|
|
27
|
+
<Button onClick={reset}>Try again</Button>
|
|
28
|
+
<Button variant="outline" nativeButton={false} render={<Link href="/" />}>
|
|
29
|
+
Go home
|
|
30
|
+
</Button>
|
|
31
|
+
</div>
|
|
32
|
+
</div>
|
|
33
|
+
);
|
|
34
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import type { Metadata } from "next";
|
|
2
|
+
import { Inter } from "next/font/google";
|
|
3
|
+
import { notFound } from "next/navigation";
|
|
4
|
+
|
|
5
|
+
import { NextIntlClientProvider } from "next-intl";
|
|
6
|
+
import { getMessages, setRequestLocale } from "next-intl/server";
|
|
7
|
+
import { NuqsAdapter } from "nuqs/adapters/next/app";
|
|
8
|
+
|
|
9
|
+
import { defaultMetadata } from "@/config/seo.config";
|
|
10
|
+
|
|
11
|
+
import { Providers } from "@/providers";
|
|
12
|
+
|
|
13
|
+
import { routing } from "@/i18n/routing";
|
|
14
|
+
|
|
15
|
+
import "@/styles/tailwind.css";
|
|
16
|
+
|
|
17
|
+
const inter = Inter({
|
|
18
|
+
variable: "--font-inter",
|
|
19
|
+
subsets: ["latin"],
|
|
20
|
+
display: "swap",
|
|
21
|
+
preload: true,
|
|
22
|
+
adjustFontFallback: true,
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
export const metadata: Metadata = defaultMetadata;
|
|
26
|
+
|
|
27
|
+
export default async function RootLayout({
|
|
28
|
+
children,
|
|
29
|
+
params,
|
|
30
|
+
}: Readonly<{
|
|
31
|
+
children: React.ReactNode;
|
|
32
|
+
params: Promise<{ locale: string }>;
|
|
33
|
+
}>) {
|
|
34
|
+
const { locale } = await params;
|
|
35
|
+
|
|
36
|
+
if (!routing.locales.includes(locale as "en" | "tr")) {
|
|
37
|
+
notFound();
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
setRequestLocale(locale);
|
|
41
|
+
|
|
42
|
+
const messages = await getMessages();
|
|
43
|
+
|
|
44
|
+
return (
|
|
45
|
+
<html
|
|
46
|
+
lang={locale}
|
|
47
|
+
className={`${inter.variable} h-full`}
|
|
48
|
+
suppressHydrationWarning
|
|
49
|
+
data-scroll-behavior="smooth"
|
|
50
|
+
>
|
|
51
|
+
<body className="flex min-h-full flex-col antialiased" suppressHydrationWarning>
|
|
52
|
+
<NextIntlClientProvider messages={messages}>
|
|
53
|
+
<NuqsAdapter>
|
|
54
|
+
<Providers>{children}</Providers>
|
|
55
|
+
</NuqsAdapter>
|
|
56
|
+
</NextIntlClientProvider>
|
|
57
|
+
</body>
|
|
58
|
+
</html>
|
|
59
|
+
);
|
|
60
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { Skeleton } from "@/components/ui/skeleton";
|
|
2
|
+
|
|
3
|
+
export default function Loading() {
|
|
4
|
+
return (
|
|
5
|
+
<div className="mx-auto flex w-full max-w-3xl flex-1 flex-col items-center gap-4 px-6 py-24">
|
|
6
|
+
<Skeleton className="h-10 w-2/3" />
|
|
7
|
+
<Skeleton className="h-4 w-full" />
|
|
8
|
+
<Skeleton className="h-4 w-5/6" />
|
|
9
|
+
<Skeleton className="mt-6 h-40 w-full" />
|
|
10
|
+
</div>
|
|
11
|
+
);
|
|
12
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import Link from "next/link";
|
|
2
|
+
|
|
3
|
+
import { Button } from "@/components/ui/button";
|
|
4
|
+
|
|
5
|
+
export default function NotFound() {
|
|
6
|
+
return (
|
|
7
|
+
<div className="mx-auto flex flex-1 flex-col items-center justify-center gap-4 px-6 py-24 text-center">
|
|
8
|
+
<p className="text-sm font-medium text-muted-foreground">404</p>
|
|
9
|
+
<h1 className="text-2xl font-semibold tracking-tight">Page not found</h1>
|
|
10
|
+
<p className="max-w-md text-sm text-muted-foreground">
|
|
11
|
+
The page you're looking for doesn't exist or has been moved.
|
|
12
|
+
</p>
|
|
13
|
+
<Button nativeButton={false} render={<Link href="/" />}>
|
|
14
|
+
Go home
|
|
15
|
+
</Button>
|
|
16
|
+
</div>
|
|
17
|
+
);
|
|
18
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { setRequestLocale } from "next-intl/server";
|
|
2
|
+
|
|
3
|
+
import { LandingPage } from "@/features/landing";
|
|
4
|
+
|
|
5
|
+
export default async function HomePage({ params }: { params: Promise<{ locale: string }> }) {
|
|
6
|
+
const { locale } = await params;
|
|
7
|
+
setRequestLocale(locale);
|
|
8
|
+
|
|
9
|
+
return <LandingPage />;
|
|
10
|
+
}
|
|
Binary file
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { useEffect } from "react";
|
|
4
|
+
|
|
5
|
+
export default function GlobalError({
|
|
6
|
+
error,
|
|
7
|
+
reset,
|
|
8
|
+
}: {
|
|
9
|
+
error: Error & { digest?: string };
|
|
10
|
+
reset: () => void;
|
|
11
|
+
}) {
|
|
12
|
+
useEffect(() => {
|
|
13
|
+
console.error(error);
|
|
14
|
+
}, [error]);
|
|
15
|
+
|
|
16
|
+
return (
|
|
17
|
+
<html lang="en" data-scroll-behavior="smooth">
|
|
18
|
+
<body className="flex min-h-screen flex-col items-center justify-center gap-4 px-6 text-center">
|
|
19
|
+
<h1 className="text-2xl font-semibold tracking-tight">A critical error occurred</h1>
|
|
20
|
+
<p className="max-w-md text-sm text-neutral-500">
|
|
21
|
+
The application failed to render. Please try again.
|
|
22
|
+
</p>
|
|
23
|
+
<button
|
|
24
|
+
onClick={reset}
|
|
25
|
+
className="rounded-md bg-neutral-900 px-4 py-2 text-sm font-medium text-white"
|
|
26
|
+
>
|
|
27
|
+
Try again
|
|
28
|
+
</button>
|
|
29
|
+
</body>
|
|
30
|
+
</html>
|
|
31
|
+
);
|
|
32
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { MetadataRoute } from "next";
|
|
2
|
+
|
|
3
|
+
import { siteConfig } from "@/config/site.config";
|
|
4
|
+
|
|
5
|
+
export default function manifest(): MetadataRoute.Manifest {
|
|
6
|
+
return {
|
|
7
|
+
name: siteConfig.name,
|
|
8
|
+
short_name: siteConfig.name,
|
|
9
|
+
description: siteConfig.description,
|
|
10
|
+
start_url: "/",
|
|
11
|
+
display: "standalone",
|
|
12
|
+
background_color: "#ffffff",
|
|
13
|
+
theme_color: "#ffffff",
|
|
14
|
+
icons: [
|
|
15
|
+
{
|
|
16
|
+
src: "/logo.webp",
|
|
17
|
+
sizes: "96x96",
|
|
18
|
+
type: "image/webp",
|
|
19
|
+
},
|
|
20
|
+
],
|
|
21
|
+
};
|
|
22
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { MetadataRoute } from "next";
|
|
2
|
+
|
|
3
|
+
import { siteConfig } from "@/config/site.config";
|
|
4
|
+
|
|
5
|
+
export default function robots(): MetadataRoute.Robots {
|
|
6
|
+
return {
|
|
7
|
+
rules: {
|
|
8
|
+
userAgent: "*",
|
|
9
|
+
allow: "/",
|
|
10
|
+
},
|
|
11
|
+
sitemap: `${siteConfig.url}/sitemap.xml`,
|
|
12
|
+
};
|
|
13
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { MetadataRoute } from "next";
|
|
2
|
+
|
|
3
|
+
import { siteConfig } from "@/config/site.config";
|
|
4
|
+
|
|
5
|
+
export default function sitemap(): MetadataRoute.Sitemap {
|
|
6
|
+
return [
|
|
7
|
+
{
|
|
8
|
+
url: siteConfig.url,
|
|
9
|
+
lastModified: new Date(),
|
|
10
|
+
changeFrequency: "monthly",
|
|
11
|
+
priority: 1,
|
|
12
|
+
},
|
|
13
|
+
];
|
|
14
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { useTransition } from "react";
|
|
4
|
+
|
|
5
|
+
import { useLocale } from "next-intl";
|
|
6
|
+
|
|
7
|
+
import { usePathname, useRouter } from "@/i18n/routing";
|
|
8
|
+
|
|
9
|
+
export function LanguageSwitcher() {
|
|
10
|
+
const locale = useLocale();
|
|
11
|
+
const router = useRouter();
|
|
12
|
+
const pathname = usePathname();
|
|
13
|
+
const [isPending, startTransition] = useTransition();
|
|
14
|
+
|
|
15
|
+
const onChange = (e: React.ChangeEvent<HTMLSelectElement>) => {
|
|
16
|
+
const nextLocale = e.target.value;
|
|
17
|
+
startTransition(() => {
|
|
18
|
+
router.replace(pathname, { locale: nextLocale });
|
|
19
|
+
});
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
return (
|
|
23
|
+
<div className="relative">
|
|
24
|
+
<select
|
|
25
|
+
value={locale}
|
|
26
|
+
onChange={onChange}
|
|
27
|
+
disabled={isPending}
|
|
28
|
+
className="h-10 cursor-pointer appearance-none rounded-md border border-input bg-background pr-8 pl-3 text-sm text-foreground focus:border-primary focus:ring-1 focus:ring-primary focus:outline-none disabled:opacity-50"
|
|
29
|
+
>
|
|
30
|
+
<option value="en">EN</option>
|
|
31
|
+
<option value="tr">TR</option>
|
|
32
|
+
</select>
|
|
33
|
+
<div className="pointer-events-none absolute top-[11px] right-2.5 h-4 w-4 text-muted-foreground">
|
|
34
|
+
<svg
|
|
35
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
36
|
+
viewBox="0 0 24 24"
|
|
37
|
+
fill="none"
|
|
38
|
+
stroke="currentColor"
|
|
39
|
+
strokeWidth="2"
|
|
40
|
+
strokeLinecap="round"
|
|
41
|
+
strokeLinejoin="round"
|
|
42
|
+
>
|
|
43
|
+
<path d="m6 9 6 6 6-6" />
|
|
44
|
+
</svg>
|
|
45
|
+
</div>
|
|
46
|
+
</div>
|
|
47
|
+
);
|
|
48
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { MoonIcon, SunIcon } from "lucide-react";
|
|
4
|
+
import { useTheme } from "next-themes";
|
|
5
|
+
import { useIsClient } from "usehooks-ts";
|
|
6
|
+
|
|
7
|
+
import { Button } from "@/components/ui/button";
|
|
8
|
+
|
|
9
|
+
export function ThemeToggle() {
|
|
10
|
+
const { resolvedTheme, setTheme } = useTheme();
|
|
11
|
+
const isClient = useIsClient();
|
|
12
|
+
|
|
13
|
+
if (!isClient) {
|
|
14
|
+
return <Button variant="outline" size="icon" aria-hidden className="size-8 opacity-0" />;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const isDark = resolvedTheme === "dark";
|
|
18
|
+
|
|
19
|
+
return (
|
|
20
|
+
<Button
|
|
21
|
+
variant="outline"
|
|
22
|
+
size="icon"
|
|
23
|
+
className="size-8"
|
|
24
|
+
aria-label={isDark ? "Switch to light theme" : "Switch to dark theme"}
|
|
25
|
+
onClick={() => setTheme(isDark ? "light" : "dark")}
|
|
26
|
+
>
|
|
27
|
+
{isDark ? <SunIcon className="size-3.5" /> : <MoonIcon className="size-3.5" />}
|
|
28
|
+
</Button>
|
|
29
|
+
);
|
|
30
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
|
|
3
|
+
import { cn } from "@/lib/utils";
|
|
4
|
+
|
|
5
|
+
const Avatar = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(
|
|
6
|
+
({ className, ...props }, ref) => (
|
|
7
|
+
<div
|
|
8
|
+
ref={ref}
|
|
9
|
+
className={cn("relative flex h-10 w-10 shrink-0 overflow-hidden rounded-full", className)}
|
|
10
|
+
{...props}
|
|
11
|
+
/>
|
|
12
|
+
),
|
|
13
|
+
);
|
|
14
|
+
Avatar.displayName = "Avatar";
|
|
15
|
+
|
|
16
|
+
const AvatarImage = React.forwardRef<
|
|
17
|
+
HTMLImageElement,
|
|
18
|
+
React.ImgHTMLAttributes<HTMLImageElement> & {
|
|
19
|
+
onLoadingStatusChange?: (status: "loading" | "loaded" | "error") => void;
|
|
20
|
+
}
|
|
21
|
+
>(({ className, src, alt = "", ...props }, ref) => {
|
|
22
|
+
const [status, setStatus] = React.useState<"loading" | "loaded" | "error">("loading");
|
|
23
|
+
|
|
24
|
+
return (
|
|
25
|
+
// Avatar primitives accept arbitrary remote URLs; next/image needs a configured domain list.
|
|
26
|
+
// eslint-disable-next-line @next/next/no-img-element -- intentional for flexible avatar sources
|
|
27
|
+
<img
|
|
28
|
+
ref={ref}
|
|
29
|
+
src={src}
|
|
30
|
+
alt={alt}
|
|
31
|
+
className={cn("aspect-square h-full w-full", status !== "loaded" && "hidden", className)}
|
|
32
|
+
onLoad={() => setStatus("loaded")}
|
|
33
|
+
onError={() => setStatus("error")}
|
|
34
|
+
{...props}
|
|
35
|
+
/>
|
|
36
|
+
);
|
|
37
|
+
});
|
|
38
|
+
AvatarImage.displayName = "AvatarImage";
|
|
39
|
+
|
|
40
|
+
const AvatarFallback = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(
|
|
41
|
+
({ className, ...props }, ref) => (
|
|
42
|
+
<div
|
|
43
|
+
ref={ref}
|
|
44
|
+
className={cn(
|
|
45
|
+
"flex h-full w-full items-center justify-center rounded-full bg-muted text-xs",
|
|
46
|
+
className,
|
|
47
|
+
)}
|
|
48
|
+
{...props}
|
|
49
|
+
/>
|
|
50
|
+
),
|
|
51
|
+
);
|
|
52
|
+
AvatarFallback.displayName = "AvatarFallback";
|
|
53
|
+
|
|
54
|
+
export { Avatar, AvatarImage, AvatarFallback };
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import type { ComponentProps } from "react";
|
|
2
|
+
|
|
3
|
+
import { Button as BaseButton } from "@base-ui/react/button";
|
|
4
|
+
import { cva, type VariantProps } from "class-variance-authority";
|
|
5
|
+
|
|
6
|
+
import { cn } from "@/lib/utils";
|
|
7
|
+
|
|
8
|
+
export const buttonVariants = cva(
|
|
9
|
+
"inline-flex shrink-0 items-center justify-center gap-2 rounded-md text-sm font-medium whitespace-nowrap transition-all outline-none focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
|
|
10
|
+
{
|
|
11
|
+
variants: {
|
|
12
|
+
variant: {
|
|
13
|
+
default: "bg-primary text-primary-foreground shadow-xs hover:bg-primary/90",
|
|
14
|
+
destructive:
|
|
15
|
+
"bg-destructive text-white shadow-xs hover:bg-destructive/90 focus-visible:ring-destructive/20",
|
|
16
|
+
outline:
|
|
17
|
+
"border border-input bg-background shadow-xs hover:bg-accent hover:text-accent-foreground",
|
|
18
|
+
secondary: "bg-secondary text-secondary-foreground shadow-xs hover:bg-secondary/80",
|
|
19
|
+
ghost: "hover:bg-accent hover:text-accent-foreground",
|
|
20
|
+
link: "text-primary underline-offset-4 hover:underline",
|
|
21
|
+
},
|
|
22
|
+
size: {
|
|
23
|
+
default: "h-9 px-4 py-2 has-[>svg]:px-3",
|
|
24
|
+
sm: "h-8 gap-1.5 rounded-md px-3 has-[>svg]:px-2.5",
|
|
25
|
+
lg: "h-10 rounded-md px-6 has-[>svg]:px-4",
|
|
26
|
+
icon: "size-9",
|
|
27
|
+
},
|
|
28
|
+
},
|
|
29
|
+
defaultVariants: {
|
|
30
|
+
variant: "default",
|
|
31
|
+
size: "default",
|
|
32
|
+
},
|
|
33
|
+
},
|
|
34
|
+
);
|
|
35
|
+
|
|
36
|
+
export type ButtonProps = ComponentProps<typeof BaseButton> & VariantProps<typeof buttonVariants>;
|
|
37
|
+
|
|
38
|
+
export function Button({ className, variant, size, ...props }: ButtonProps) {
|
|
39
|
+
return (
|
|
40
|
+
<BaseButton
|
|
41
|
+
data-slot="button"
|
|
42
|
+
className={cn(buttonVariants({ variant, size, className }))}
|
|
43
|
+
{...props}
|
|
44
|
+
/>
|
|
45
|
+
);
|
|
46
|
+
}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import type { ComponentProps } from "react";
|
|
2
|
+
|
|
3
|
+
import { XIcon } from "lucide-react";
|
|
4
|
+
import { Dialog as BaseDialog } from "@base-ui/react/dialog";
|
|
5
|
+
|
|
6
|
+
import { cn } from "@/lib/utils";
|
|
7
|
+
|
|
8
|
+
export function Dialog(props: ComponentProps<typeof BaseDialog.Root>) {
|
|
9
|
+
return <BaseDialog.Root data-slot="dialog" {...props} />;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export function DialogTrigger(props: ComponentProps<typeof BaseDialog.Trigger>) {
|
|
13
|
+
return <BaseDialog.Trigger data-slot="dialog-trigger" {...props} />;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export function DialogClose(props: ComponentProps<typeof BaseDialog.Close>) {
|
|
17
|
+
return <BaseDialog.Close data-slot="dialog-close" {...props} />;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export function DialogContent({
|
|
21
|
+
className,
|
|
22
|
+
children,
|
|
23
|
+
showCloseButton = true,
|
|
24
|
+
...props
|
|
25
|
+
}: ComponentProps<typeof BaseDialog.Popup> & { showCloseButton?: boolean }) {
|
|
26
|
+
return (
|
|
27
|
+
<BaseDialog.Portal>
|
|
28
|
+
<BaseDialog.Backdrop
|
|
29
|
+
data-slot="dialog-backdrop"
|
|
30
|
+
className={cn(
|
|
31
|
+
"fixed inset-0 z-50 bg-black/50",
|
|
32
|
+
"data-[ending-style]:opacity-0 data-[starting-style]:opacity-0",
|
|
33
|
+
"transition-opacity duration-150",
|
|
34
|
+
)}
|
|
35
|
+
/>
|
|
36
|
+
<BaseDialog.Popup
|
|
37
|
+
data-slot="dialog-content"
|
|
38
|
+
className={cn(
|
|
39
|
+
"fixed top-1/2 left-1/2 z-50 grid w-full max-w-lg -translate-x-1/2 -translate-y-1/2 gap-4",
|
|
40
|
+
"rounded-lg border border-border bg-background p-6 shadow-lg",
|
|
41
|
+
"data-[starting-style]:scale-95 data-[starting-style]:opacity-0",
|
|
42
|
+
"data-[ending-style]:scale-95 data-[ending-style]:opacity-0",
|
|
43
|
+
"transition-all duration-150",
|
|
44
|
+
className,
|
|
45
|
+
)}
|
|
46
|
+
{...props}
|
|
47
|
+
>
|
|
48
|
+
{children}
|
|
49
|
+
{showCloseButton && (
|
|
50
|
+
<BaseDialog.Close
|
|
51
|
+
data-slot="dialog-close"
|
|
52
|
+
className={cn(
|
|
53
|
+
"absolute top-4 right-4 rounded-xs opacity-70 transition-opacity outline-none",
|
|
54
|
+
"hover:opacity-100 focus-visible:ring-[3px] focus-visible:ring-ring/50",
|
|
55
|
+
)}
|
|
56
|
+
>
|
|
57
|
+
<XIcon className="size-4" />
|
|
58
|
+
<span className="sr-only">Close</span>
|
|
59
|
+
</BaseDialog.Close>
|
|
60
|
+
)}
|
|
61
|
+
</BaseDialog.Popup>
|
|
62
|
+
</BaseDialog.Portal>
|
|
63
|
+
);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export function DialogHeader({ className, ...props }: ComponentProps<"div">) {
|
|
67
|
+
return (
|
|
68
|
+
<div
|
|
69
|
+
data-slot="dialog-header"
|
|
70
|
+
className={cn("flex flex-col gap-2 text-center sm:text-left", className)}
|
|
71
|
+
{...props}
|
|
72
|
+
/>
|
|
73
|
+
);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export function DialogFooter({ className, ...props }: ComponentProps<"div">) {
|
|
77
|
+
return (
|
|
78
|
+
<div
|
|
79
|
+
data-slot="dialog-footer"
|
|
80
|
+
className={cn("flex flex-col-reverse gap-2 sm:flex-row sm:justify-end", className)}
|
|
81
|
+
{...props}
|
|
82
|
+
/>
|
|
83
|
+
);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export function DialogTitle({ className, ...props }: ComponentProps<typeof BaseDialog.Title>) {
|
|
87
|
+
return (
|
|
88
|
+
<BaseDialog.Title
|
|
89
|
+
data-slot="dialog-title"
|
|
90
|
+
className={cn("text-lg leading-none font-semibold", className)}
|
|
91
|
+
{...props}
|
|
92
|
+
/>
|
|
93
|
+
);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export function DialogDescription({
|
|
97
|
+
className,
|
|
98
|
+
...props
|
|
99
|
+
}: ComponentProps<typeof BaseDialog.Description>) {
|
|
100
|
+
return (
|
|
101
|
+
<BaseDialog.Description
|
|
102
|
+
data-slot="dialog-description"
|
|
103
|
+
className={cn("text-sm text-muted-foreground", className)}
|
|
104
|
+
{...props}
|
|
105
|
+
/>
|
|
106
|
+
);
|
|
107
|
+
}
|