diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json deleted file mode 100644 index deffab7..0000000 --- a/.devcontainer/devcontainer.json +++ /dev/null @@ -1,65 +0,0 @@ -{ - "name": "Laconic Core Development", - "image": "mcr.microsoft.com/devcontainers/javascript-node:0-18", - - // Add environment variables - "containerEnv": { - "NODE_ENV": "development" - }, - - // Mount your SSH keys for git authentication - "mounts": [ - "source=${localEnv:HOME}/.ssh,target=/home/node/.ssh,type=bind,readonly" - ], - - "customizations": { - "vscode": { - "extensions": [ - "biomejs.biome", - "ms-vscode.vscode-typescript-next", - "ms-azuretools.vscode-docker", - "dbaeumer.vscode-eslint", - "christian-kohler.path-intellisense", - "github.vscode-pull-request-github", - "streetsidesoftware.code-spell-checker", - "eamodio.gitlens" - ], - "settings": { - "editor.defaultFormatter": "biomejs.biome", - "editor.formatOnSave": true, - "editor.codeActionsOnSave": { - "source.organizeImports": "explicit", - "source.fixAll": "explicit", - "source.addMissingImports.ts": "explicit", - "source.fixAll.ts": "explicit", - "source.removeUnusedImports": "explicit" - }, - // Additional helpful settings - "editor.bracketPairColorization.enabled": true, - "editor.guides.bracketPairs": true, - "terminal.integrated.defaultProfile.linux": "bash", - "javascript.updateImportsOnFileMove.enabled": "always", - "typescript.updateImportsOnFileMove.enabled": "always", - "files.exclude": { - "**/.git": true, - "**/node_modules": true, - "**/dist": true - } - } - } - }, - - // Forward common development ports - "forwardPorts": [3000, 4000, 5000, 8000], - - // Set up git configuration - "postCreateCommand": "pnpm install && git config --global pull.rebase true", - - "remoteUser": "node", - - // Features to install in the container - "features": { - "ghcr.io/devcontainers/features/github-cli:1": {}, - "ghcr.io/devcontainers/features/git:1": {} - } -} diff --git a/.eslintrc.js b/.eslintrc.js deleted file mode 100644 index d600723..0000000 --- a/.eslintrc.js +++ /dev/null @@ -1,13 +0,0 @@ -module.exports = { - root: true, - parser: '@typescript-eslint/parser', - plugins: ['@typescript-eslint'], - extends: ['eslint:recommended', 'plugin:@typescript-eslint/recommended'], - rules: { - // Add rules that can be auto-fixed - '@typescript-eslint/no-unused-vars': 'error', - '@typescript-eslint/explicit-module-boundary-types': 'off', - '@typescript-eslint/no-explicit-any': 'warn', - '@typescript-eslint/no-non-null-assertion': 'warn' - } -} diff --git a/.vscode/settings.json b/.vscode/settings.json index e7f470a..6f210cb 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -4,12 +4,12 @@ "typescript.enablePromptUseWorkspaceTsdk": true, "editor.formatOnSave": true, "editor.codeActionsOnSave": { - "source.fixAll": true, - "source.organizeImports": true + "source.fixAll": "explicit", + "source.organizeImports": "explicit" }, "editor.defaultFormatter": "biomejs.biome", "[typescript]": { - "editor.defaultFormatter": "biomejs.biome" + "editor.defaultFormatter": "vscode.typescript-language-features" }, "[typescriptreact]": { "editor.defaultFormatter": "biomejs.biome" diff --git a/apps/deploy-fe/.gitignore b/apps/deploy-fe/.gitignore new file mode 100644 index 0000000..c878ccb --- /dev/null +++ b/apps/deploy-fe/.gitignore @@ -0,0 +1,7 @@ +node_modules +.next/ +.turbo/ +.env +.env.local +.env.development.local +.env.test.local diff --git a/apps/deploy-fe/components.json b/apps/deploy-fe/components.json new file mode 100644 index 0000000..c6e73e6 --- /dev/null +++ b/apps/deploy-fe/components.json @@ -0,0 +1,20 @@ +{ + "$schema": "https://ui.shadcn.com/schema.json", + "style": "new-york", + "rsc": true, + "tsx": true, + "tailwind": { + "config": "tailwind.config.ts", + "css": "../../../services/ui/src/styles/globals.css", + "baseColor": "zinc", + "cssVariables": true + }, + "iconLibrary": "lucide", + "aliases": { + "components": "@/components", + "hooks": "@/hooks", + "lib": "@/lib", + "utils": "@workspace/ui/lib/utils", + "ui": "@workspace/ui/components" + } +} diff --git a/apps/deploy-fe/next.config.mjs b/apps/deploy-fe/next.config.mjs new file mode 100644 index 0000000..05584cb --- /dev/null +++ b/apps/deploy-fe/next.config.mjs @@ -0,0 +1,6 @@ +/** @type {import('next').NextConfig} */ +const nextConfig = { + transpilePackages: ['@workspace/ui'] +} + +export default nextConfig diff --git a/apps/deploy-fe/package.json b/apps/deploy-fe/package.json new file mode 100644 index 0000000..739631a --- /dev/null +++ b/apps/deploy-fe/package.json @@ -0,0 +1,75 @@ +{ + "name": "deploy-fe", + "version": "0.0.1", + "type": "module", + "private": true, + "scripts": { + "dev": "next dev --turbopack", + "build": "next build", + "start": "next start", + "lint": "biome check .", + "lint:fix": "biome check --write .", + "format": "biome format .", + "format:fix": "biome format --write .", + "check-types": "tsc --noEmit", + "fix-types": "tsc --noEmit --pretty --incremental" + }, + "dependencies": { + "@biomejs/biome": "^1.9.4", + "@biomejs/monorepo": "github:biomejs/biome", + "@hookform/resolvers": "^4.1.2", + "@radix-ui/react-accordion": "^1.2.3", + "@radix-ui/react-alert-dialog": "^1.1.6", + "@radix-ui/react-aspect-ratio": "^1.1.2", + "@radix-ui/react-avatar": "^1.1.3", + "@radix-ui/react-checkbox": "^1.1.4", + "@radix-ui/react-collapsible": "^1.1.3", + "@radix-ui/react-context-menu": "^2.2.6", + "@radix-ui/react-dialog": "^1.1.6", + "@radix-ui/react-dropdown-menu": "^2.1.6", + "@radix-ui/react-hover-card": "^1.1.6", + "@radix-ui/react-label": "^2.1.2", + "@radix-ui/react-menubar": "^1.1.6", + "@radix-ui/react-navigation-menu": "^1.2.5", + "@radix-ui/react-popover": "^1.1.6", + "@radix-ui/react-progress": "^1.1.2", + "@radix-ui/react-radio-group": "^1.2.3", + "@radix-ui/react-scroll-area": "^1.2.3", + "@radix-ui/react-select": "^2.1.6", + "@radix-ui/react-separator": "^1.1.2", + "@radix-ui/react-slider": "^1.2.3", + "@radix-ui/react-slot": "^1.1.1", + "@radix-ui/react-switch": "^1.1.3", + "@radix-ui/react-tabs": "^1.1.3", + "@radix-ui/react-toggle": "^1.1.2", + "@radix-ui/react-toggle-group": "^1.1.2", + "@radix-ui/react-tooltip": "^1.1.8", + "@workspace/ui": "workspace:*", + "class-variance-authority": "^0.7.0", + "cmdk": "1.0.0", + "date-fns": "^4.1.0", + "embla-carousel-react": "^8.5.2", + "input-otp": "^1.4.2", + "lucide-react": "0.456.0", + "next": "^15.1.0", + "next-themes": "^0.4.4", + "react": "^19.0.0", + "react-day-picker": "8.10.1", + "react-dom": "^19.0.0", + "react-hook-form": "^7.54.2", + "react-resizable-panels": "^2.1.7", + "recharts": "^2.15.1", + "sonner": "^2.0.1", + "vaul": "^1.1.2", + "zod": "^3.23.8" + }, + "devDependencies": { + "@types/node": "^20", + "@types/react": "18.3.0", + "@types/react-dom": "18.3.1", + "@workspace/typescript-config": "workspace:*", + "postcss": "^8", + "tailwindcss": "^4.0.9", + "typescript": "^5" + } +} diff --git a/apps/deploy-fe/postcss.config.mjs b/apps/deploy-fe/postcss.config.mjs new file mode 100644 index 0000000..d923411 --- /dev/null +++ b/apps/deploy-fe/postcss.config.mjs @@ -0,0 +1,6 @@ +export default { + plugins: { + '@tailwindcss/postcss': {}, + autoprefixer: {} + } +} diff --git a/apps/deploy-fe/src/app/(web3-authenticated)/(dashboard)/(buy-prepaid-service)/bp/page.tsx b/apps/deploy-fe/src/app/(web3-authenticated)/(dashboard)/(buy-prepaid-service)/bp/page.tsx new file mode 100644 index 0000000..7c4a8ac --- /dev/null +++ b/apps/deploy-fe/src/app/(web3-authenticated)/(dashboard)/(buy-prepaid-service)/bp/page.tsx @@ -0,0 +1,18 @@ +import type { Metadata } from 'next' + +export const metadata: Metadata = { + title: 'Buy Prepaid Service', + description: 'Buy prepaid service page description' +} + +const Page = () => { + return ( +
+

+ Hello from (web3-authenticated)/(dashboard)/(buy-prepaid-service)/bp +

+
+ ) +} + +export default Page diff --git a/apps/deploy-fe/src/app/(web3-authenticated)/(dashboard)/(projects)/pr/[provider]/[orgSlug]/(projects)/ps/(create)/cr/(configure)/cf/page.tsx b/apps/deploy-fe/src/app/(web3-authenticated)/(dashboard)/(projects)/pr/[provider]/[orgSlug]/(projects)/ps/(create)/cr/(configure)/cf/page.tsx new file mode 100644 index 0000000..d1469af --- /dev/null +++ b/apps/deploy-fe/src/app/(web3-authenticated)/(dashboard)/(projects)/pr/[provider]/[orgSlug]/(projects)/ps/(create)/cr/(configure)/cf/page.tsx @@ -0,0 +1,12 @@ +const Page = () => { + return ( +
+

+ Hello from + (web3-authenticated)/(dashboard)/(projects)/pr/[provider]/[orgSlug]/(projects)/ps/(create)/cr/(configure)/cf +

+
+ ) +} + +export default Page diff --git a/apps/deploy-fe/src/app/(web3-authenticated)/(dashboard)/(projects)/pr/[provider]/[orgSlug]/(projects)/ps/(create)/cr/(deploy)/dp/page.tsx b/apps/deploy-fe/src/app/(web3-authenticated)/(dashboard)/(projects)/pr/[provider]/[orgSlug]/(projects)/ps/(create)/cr/(deploy)/dp/page.tsx new file mode 100644 index 0000000..7c25d1e --- /dev/null +++ b/apps/deploy-fe/src/app/(web3-authenticated)/(dashboard)/(projects)/pr/[provider]/[orgSlug]/(projects)/ps/(create)/cr/(deploy)/dp/page.tsx @@ -0,0 +1,12 @@ +const Page = () => { + return ( +
+

+ Hello from + (web3-authenticated)/(dashboard)/(projects)/pr/[provider]/[orgSlug]/(projects)/ps/(create)/cr/(deploy)/dp +

+
+ ) +} + +export default Page diff --git a/apps/deploy-fe/src/app/(web3-authenticated)/(dashboard)/(projects)/pr/[provider]/[orgSlug]/(projects)/ps/(create)/cr/(success)/sc/[id]/page.tsx b/apps/deploy-fe/src/app/(web3-authenticated)/(dashboard)/(projects)/pr/[provider]/[orgSlug]/(projects)/ps/(create)/cr/(success)/sc/[id]/page.tsx new file mode 100644 index 0000000..4e1cd5e --- /dev/null +++ b/apps/deploy-fe/src/app/(web3-authenticated)/(dashboard)/(projects)/pr/[provider]/[orgSlug]/(projects)/ps/(create)/cr/(success)/sc/[id]/page.tsx @@ -0,0 +1,12 @@ +const Page = () => { + return ( +
+

+ Hello from + (web3-authenticated)/(dashboard)/(projects)/pr/[provider]/[orgSlug]/(projects)/ps/(create)/cr/(success)/sc/[id] +

+
+ ) +} + +export default Page diff --git a/apps/deploy-fe/src/app/(web3-authenticated)/(dashboard)/(projects)/pr/[provider]/[orgSlug]/(projects)/ps/(create)/cr/(template)/tm/(configure)/cf/page.tsx b/apps/deploy-fe/src/app/(web3-authenticated)/(dashboard)/(projects)/pr/[provider]/[orgSlug]/(projects)/ps/(create)/cr/(template)/tm/(configure)/cf/page.tsx new file mode 100644 index 0000000..85cd9ce --- /dev/null +++ b/apps/deploy-fe/src/app/(web3-authenticated)/(dashboard)/(projects)/pr/[provider]/[orgSlug]/(projects)/ps/(create)/cr/(template)/tm/(configure)/cf/page.tsx @@ -0,0 +1,12 @@ +const Page = () => { + return ( +
+

+ Hello from + (web3-authenticated)/(dashboard)/(projects)/pr/[provider]/[orgSlug]/(projects)/ps/(create)/cr/(template)/tm/(configure)/cf +

+
+ ) +} + +export default Page diff --git a/apps/deploy-fe/src/app/(web3-authenticated)/(dashboard)/(projects)/pr/[provider]/[orgSlug]/(projects)/ps/(create)/cr/(template)/tm/(deploy)/dp/page.tsx b/apps/deploy-fe/src/app/(web3-authenticated)/(dashboard)/(projects)/pr/[provider]/[orgSlug]/(projects)/ps/(create)/cr/(template)/tm/(deploy)/dp/page.tsx new file mode 100644 index 0000000..d55be54 --- /dev/null +++ b/apps/deploy-fe/src/app/(web3-authenticated)/(dashboard)/(projects)/pr/[provider]/[orgSlug]/(projects)/ps/(create)/cr/(template)/tm/(deploy)/dp/page.tsx @@ -0,0 +1,12 @@ +const Page = () => { + return ( +
+

+ Hello from + (web3-authenticated)/(dashboard)/(projects)/pr/[provider]/[orgSlug]/(projects)/ps/(create)/cr/(template)/tm/(deploy)/dp +

+
+ ) +} + +export default Page diff --git a/apps/deploy-fe/src/app/(web3-authenticated)/(dashboard)/(projects)/pr/[provider]/[orgSlug]/(projects)/ps/[id]/(deployments)/dep/page.tsx b/apps/deploy-fe/src/app/(web3-authenticated)/(dashboard)/(projects)/pr/[provider]/[orgSlug]/(projects)/ps/[id]/(deployments)/dep/page.tsx new file mode 100644 index 0000000..e31979b --- /dev/null +++ b/apps/deploy-fe/src/app/(web3-authenticated)/(dashboard)/(projects)/pr/[provider]/[orgSlug]/(projects)/ps/[id]/(deployments)/dep/page.tsx @@ -0,0 +1,12 @@ +const Page = () => { + return ( +
+

+ Hello from + (web3-authenticated)/(dashboard)/(projects)/pr/[provider]/[orgSlug]/(projects)/ps/[id]/(deployments)/dep +

+
+ ) +} + +export default Page diff --git a/apps/deploy-fe/src/app/(web3-authenticated)/(dashboard)/(projects)/pr/[provider]/[orgSlug]/(projects)/ps/[id]/(integrations)/int/page.tsx b/apps/deploy-fe/src/app/(web3-authenticated)/(dashboard)/(projects)/pr/[provider]/[orgSlug]/(projects)/ps/[id]/(integrations)/int/page.tsx new file mode 100644 index 0000000..d66d91d --- /dev/null +++ b/apps/deploy-fe/src/app/(web3-authenticated)/(dashboard)/(projects)/pr/[provider]/[orgSlug]/(projects)/ps/[id]/(integrations)/int/page.tsx @@ -0,0 +1,12 @@ +const Page = () => { + return ( +
+

+ Hello from + (web3-authenticated)/(dashboard)/(projects)/pr/[provider]/[orgSlug]/(projects)/ps/[id]/(integrations)/int +

+
+ ) +} + +export default Page diff --git a/apps/deploy-fe/src/app/(web3-authenticated)/(dashboard)/(projects)/pr/[provider]/[orgSlug]/(projects)/ps/[id]/(settings)/set/(collaborators)/col/page.tsx b/apps/deploy-fe/src/app/(web3-authenticated)/(dashboard)/(projects)/pr/[provider]/[orgSlug]/(projects)/ps/[id]/(settings)/set/(collaborators)/col/page.tsx new file mode 100644 index 0000000..5d99b5d --- /dev/null +++ b/apps/deploy-fe/src/app/(web3-authenticated)/(dashboard)/(projects)/pr/[provider]/[orgSlug]/(projects)/ps/[id]/(settings)/set/(collaborators)/col/page.tsx @@ -0,0 +1,12 @@ +const Page = () => { + return ( +
+

+ Hello from + (web3-authenticated)/(dashboard)/(projects)/pr/[provider]/[orgSlug]/(projects)/ps/[id]/(settings)/set/(collaborators)/col +

+
+ ) +} + +export default Page diff --git a/apps/deploy-fe/src/app/(web3-authenticated)/(dashboard)/(projects)/pr/[provider]/[orgSlug]/(projects)/ps/[id]/(settings)/set/(domains)/dom/(add)/cf/page.tsx b/apps/deploy-fe/src/app/(web3-authenticated)/(dashboard)/(projects)/pr/[provider]/[orgSlug]/(projects)/ps/[id]/(settings)/set/(domains)/dom/(add)/cf/page.tsx new file mode 100644 index 0000000..62369b0 --- /dev/null +++ b/apps/deploy-fe/src/app/(web3-authenticated)/(dashboard)/(projects)/pr/[provider]/[orgSlug]/(projects)/ps/[id]/(settings)/set/(domains)/dom/(add)/cf/page.tsx @@ -0,0 +1,12 @@ +const Page = () => { + return ( +
+

+ Hello from + (web3-authenticated)/(dashboard)/(projects)/pr/[provider]/[orgSlug]/(projects)/ps/[id]/(settings)/set/(domains)/dom/(add)/cf +

+
+ ) +} + +export default Page diff --git a/apps/deploy-fe/src/app/(web3-authenticated)/(dashboard)/(projects)/pr/[provider]/[orgSlug]/(projects)/ps/[id]/(settings)/set/(domains)/dom/(add)/config/cf/page.tsx b/apps/deploy-fe/src/app/(web3-authenticated)/(dashboard)/(projects)/pr/[provider]/[orgSlug]/(projects)/ps/[id]/(settings)/set/(domains)/dom/(add)/config/cf/page.tsx new file mode 100644 index 0000000..6246ab7 --- /dev/null +++ b/apps/deploy-fe/src/app/(web3-authenticated)/(dashboard)/(projects)/pr/[provider]/[orgSlug]/(projects)/ps/[id]/(settings)/set/(domains)/dom/(add)/config/cf/page.tsx @@ -0,0 +1,12 @@ +const Page = () => { + return ( +
+

+ Hello from + (web3-authenticated)/(dashboard)/(projects)/pr/[provider]/[orgSlug]/(projects)/ps/[id]/(settings)/set/(domains)/dom/(add)/config/cf +

+
+ ) +} + +export default Page diff --git a/apps/deploy-fe/src/app/(web3-authenticated)/(dashboard)/(projects)/pr/[provider]/[orgSlug]/(projects)/ps/[id]/(settings)/set/(environment-variables)/env/page.tsx b/apps/deploy-fe/src/app/(web3-authenticated)/(dashboard)/(projects)/pr/[provider]/[orgSlug]/(projects)/ps/[id]/(settings)/set/(environment-variables)/env/page.tsx new file mode 100644 index 0000000..79e56f6 --- /dev/null +++ b/apps/deploy-fe/src/app/(web3-authenticated)/(dashboard)/(projects)/pr/[provider]/[orgSlug]/(projects)/ps/[id]/(settings)/set/(environment-variables)/env/page.tsx @@ -0,0 +1,12 @@ +const Page = () => { + return ( +
+

+ Hello from + (web3-authenticated)/(dashboard)/(projects)/pr/[provider]/[orgSlug]/(projects)/ps/[id]/(settings)/set/(environment-variables)/env +

+
+ ) +} + +export default Page diff --git a/apps/deploy-fe/src/app/(web3-authenticated)/(dashboard)/(projects)/pr/[provider]/[orgSlug]/(projects)/ps/[id]/(settings)/set/(git)/page.tsx b/apps/deploy-fe/src/app/(web3-authenticated)/(dashboard)/(projects)/pr/[provider]/[orgSlug]/(projects)/ps/[id]/(settings)/set/(git)/page.tsx new file mode 100644 index 0000000..dbede3f --- /dev/null +++ b/apps/deploy-fe/src/app/(web3-authenticated)/(dashboard)/(projects)/pr/[provider]/[orgSlug]/(projects)/ps/[id]/(settings)/set/(git)/page.tsx @@ -0,0 +1,12 @@ +const Page = () => { + return ( +
+

+ Hello from + (web3-authenticated)/(dashboard)/(projects)/pr/[provider]/[orgSlug]/(projects)/ps/[id]/(settings)/set/(git) +

+
+ ) +} + +export default Page diff --git a/apps/deploy-fe/src/app/(web3-authenticated)/(dashboard)/(projects)/pr/[provider]/[orgSlug]/(projects)/ps/[id]/page.tsx b/apps/deploy-fe/src/app/(web3-authenticated)/(dashboard)/(projects)/pr/[provider]/[orgSlug]/(projects)/ps/[id]/page.tsx new file mode 100644 index 0000000..a85a657 --- /dev/null +++ b/apps/deploy-fe/src/app/(web3-authenticated)/(dashboard)/(projects)/pr/[provider]/[orgSlug]/(projects)/ps/[id]/page.tsx @@ -0,0 +1,39 @@ +// // Define your own params interface to avoid using Next.js internals +// interface PageParams { +// id: string +// provider: string +// orgSlug: string +// } + +// // Generate dynamic metadata based on project ID +// export async function generateMetadata({ +// params +// }: { +// params: PageParams +// }): Promise { +// const { id } = params + +// try { +// const project = { name: 'Project Name' } +// // const project = await getProject(id) +// return { +// title: `Project: ${project.name}`, +// description: `Details for project ${project.name}` +// } +// } catch (error) { +// return { +// title: 'Project Details', +// description: 'Project information page' +// } +// } +// } + +export default async function ProjectPage() { + const id = 'A fake project ID' + return ( +
+

Project ID: {id}

+ {/* Project content */} +
+ ) +} diff --git a/apps/deploy-fe/src/app/(web3-authenticated)/(dashboard)/(projects)/pr/[provider]/[orgSlug]/(settings)/set/page.tsx b/apps/deploy-fe/src/app/(web3-authenticated)/(dashboard)/(projects)/pr/[provider]/[orgSlug]/(settings)/set/page.tsx new file mode 100644 index 0000000..a2962aa --- /dev/null +++ b/apps/deploy-fe/src/app/(web3-authenticated)/(dashboard)/(projects)/pr/[provider]/[orgSlug]/(settings)/set/page.tsx @@ -0,0 +1,12 @@ +const Page = () => { + return ( +
+

+ Hello from + (web3-authenticated)/(dashboard)/(projects)/pr/[provider]/[orgSlug]/(settings)/set +

+
+ ) +} + +export default Page diff --git a/apps/deploy-fe/src/app/(web3-authenticated)/(dashboard)/(projects)/pr/error.tsx b/apps/deploy-fe/src/app/(web3-authenticated)/(dashboard)/(projects)/pr/error.tsx new file mode 100644 index 0000000..79eb833 --- /dev/null +++ b/apps/deploy-fe/src/app/(web3-authenticated)/(dashboard)/(projects)/pr/error.tsx @@ -0,0 +1,30 @@ +'use client' + +import { Button } from '@workspace/ui/components/button' +import { useEffect } from 'react' + +export default function ClientError({ + error, + reset +}: { + error: Error & { digest?: string } + reset: () => void +}) { + useEffect(() => { + // Log the error to an error reporting service + console.error(error) + }, [error]) + + return ( +
+

Something went wrong!

+

{error.message}

+ +
+ ) +} diff --git a/apps/deploy-fe/src/app/(web3-authenticated)/(dashboard)/(projects)/pr/loading.tsx b/apps/deploy-fe/src/app/(web3-authenticated)/(dashboard)/(projects)/pr/loading.tsx new file mode 100644 index 0000000..1c7a06d --- /dev/null +++ b/apps/deploy-fe/src/app/(web3-authenticated)/(dashboard)/(projects)/pr/loading.tsx @@ -0,0 +1,10 @@ +export default function Loading() { + return ( +
+
+
+
+
+
+ ) +} diff --git a/apps/deploy-fe/src/app/(web3-authenticated)/(dashboard)/layout.tsx b/apps/deploy-fe/src/app/(web3-authenticated)/(dashboard)/layout.tsx new file mode 100644 index 0000000..535feaf --- /dev/null +++ b/apps/deploy-fe/src/app/(web3-authenticated)/(dashboard)/layout.tsx @@ -0,0 +1,16 @@ +import type React from 'react' + +interface LayoutProps { + children: React.ReactNode +} + +const Layout: React.FC = ({ children }) => { + return ( +
+

Layout for (web3-authenticated)/(dashboard)

+ {children} +
+ ) +} + +export default Layout diff --git a/apps/deploy-fe/src/app/(web3-authenticated)/layout.tsx b/apps/deploy-fe/src/app/(web3-authenticated)/layout.tsx new file mode 100644 index 0000000..50a6419 --- /dev/null +++ b/apps/deploy-fe/src/app/(web3-authenticated)/layout.tsx @@ -0,0 +1,16 @@ +import type React from 'react' + +interface LayoutProps { + children: React.ReactNode +} + +const Layout: React.FC = ({ children }) => { + return ( +
+

Layout for (web3-authenticated)

+ {children} +
+ ) +} + +export default Layout diff --git a/apps/web/app/favicon.ico b/apps/deploy-fe/src/app/favicon.ico similarity index 100% rename from apps/web/app/favicon.ico rename to apps/deploy-fe/src/app/favicon.ico diff --git a/apps/deploy-fe/src/app/layout.tsx b/apps/deploy-fe/src/app/layout.tsx new file mode 100644 index 0000000..34c343d --- /dev/null +++ b/apps/deploy-fe/src/app/layout.tsx @@ -0,0 +1,43 @@ +import { Providers } from '@/components/providers' +import '@workspace/ui/globals.css' +import type { Metadata } from 'next' +import { Geist, Geist_Mono } from 'next/font/google' + +const fontSans = Geist({ + subsets: ['latin'], + variable: '--font-sans' +}) + +const fontMono = Geist_Mono({ + subsets: ['latin'], + variable: '--font-mono' +}) + +// Add root metadata with template pattern +export const metadata: Metadata = { + title: { + template: '%s | Qwrk Deploy', + default: 'Qwrk Deploy - Cloud Deployment Platform' + }, + description: 'Deploy your applications with Qwrk', + metadataBase: new URL('https://deploy.qwrk.app'), + icons: { + icon: '/favicon.ico' + } +} + +export default function RootLayout({ + children +}: Readonly<{ + children: React.ReactNode +}>) { + return ( + + + {children} + + + ) +} diff --git a/apps/deploy-fe/src/app/login/page.tsx b/apps/deploy-fe/src/app/login/page.tsx new file mode 100644 index 0000000..e64e5b8 --- /dev/null +++ b/apps/deploy-fe/src/app/login/page.tsx @@ -0,0 +1,16 @@ +import type { Metadata } from 'next' + +export const metadata: Metadata = { + title: 'Login Page', + description: 'Login page description' +} + +const Page = () => { + return ( +
+

Hello from login

+
+ ) +} + +export default Page diff --git a/apps/deploy-fe/src/app/not-found.tsx b/apps/deploy-fe/src/app/not-found.tsx new file mode 100644 index 0000000..965cc12 --- /dev/null +++ b/apps/deploy-fe/src/app/not-found.tsx @@ -0,0 +1,22 @@ +import type { Metadata } from 'next' +import Link from 'next/link' + +export const metadata: Metadata = { + title: 'Page Not Found', + description: 'The requested page could not be found' +} + +export default function NotFound() { + return ( +
+

404 - Page Not Found

+

The page you are looking for does not exist.

+ + Return Home + +
+ ) +} diff --git a/apps/deploy-fe/src/app/page.tsx b/apps/deploy-fe/src/app/page.tsx new file mode 100644 index 0000000..11377c3 --- /dev/null +++ b/apps/deploy-fe/src/app/page.tsx @@ -0,0 +1,18 @@ +import { Button } from '@workspace/ui/components/button' +import type { Metadata } from 'next' + +export const metadata: Metadata = { + title: 'Home Page', + description: 'Home page description' +} + +export default function Page() { + return ( +
+
+

Hello World

+ +
+
+ ) +} diff --git a/apps/deploy-fe/src/app/store/layout.tsx b/apps/deploy-fe/src/app/store/layout.tsx new file mode 100644 index 0000000..c697393 --- /dev/null +++ b/apps/deploy-fe/src/app/store/layout.tsx @@ -0,0 +1,16 @@ +import type React from 'react' + +interface LayoutProps { + children: React.ReactNode +} + +const Layout: React.FC = ({ children }) => { + return ( +
+

Layout for store

+ {children} +
+ ) +} + +export default Layout diff --git a/apps/deploy-fe/src/app/store/page.tsx b/apps/deploy-fe/src/app/store/page.tsx new file mode 100644 index 0000000..58229c2 --- /dev/null +++ b/apps/deploy-fe/src/app/store/page.tsx @@ -0,0 +1,16 @@ +import type { Metadata } from 'next' + +export const metadata: Metadata = { + title: 'Store Page', + description: 'Store page description' +} + +const Page = () => { + return ( +
+

Hello from store

+
+ ) +} + +export default Page diff --git a/apps/deploy-fe/src/app/wallet/layout.tsx b/apps/deploy-fe/src/app/wallet/layout.tsx new file mode 100644 index 0000000..f54215a --- /dev/null +++ b/apps/deploy-fe/src/app/wallet/layout.tsx @@ -0,0 +1,16 @@ +import type React from 'react' + +interface LayoutProps { + children: React.ReactNode +} + +const Layout: React.FC = ({ children }) => { + return ( +
+

Layout for wallet

+ {children} +
+ ) +} + +export default Layout diff --git a/apps/deploy-fe/src/app/wallet/page.tsx b/apps/deploy-fe/src/app/wallet/page.tsx new file mode 100644 index 0000000..1df576a --- /dev/null +++ b/apps/deploy-fe/src/app/wallet/page.tsx @@ -0,0 +1,16 @@ +import type { Metadata } from 'next' + +export const metadata: Metadata = { + title: 'Wallet Page', + description: 'Wallet page description' +} + +const Page = () => { + return ( +
+

Hello from wallet

+
+ ) +} + +export default Page diff --git a/apps/web/components/.gitkeep b/apps/deploy-fe/src/components/.gitkeep similarity index 100% rename from apps/web/components/.gitkeep rename to apps/deploy-fe/src/components/.gitkeep diff --git a/apps/web/components/providers.tsx b/apps/deploy-fe/src/components/providers.tsx similarity index 100% rename from apps/web/components/providers.tsx rename to apps/deploy-fe/src/components/providers.tsx diff --git a/apps/web/hooks/.gitkeep b/apps/deploy-fe/src/hooks/.gitkeep similarity index 100% rename from apps/web/hooks/.gitkeep rename to apps/deploy-fe/src/hooks/.gitkeep diff --git a/apps/web/hooks/use-mobile.tsx b/apps/deploy-fe/src/hooks/use-mobile.tsx similarity index 100% rename from apps/web/hooks/use-mobile.tsx rename to apps/deploy-fe/src/hooks/use-mobile.tsx diff --git a/apps/web/lib/.gitkeep b/apps/deploy-fe/src/lib/.gitkeep similarity index 100% rename from apps/web/lib/.gitkeep rename to apps/deploy-fe/src/lib/.gitkeep diff --git a/apps/deploy-fe/tailwind.config.ts b/apps/deploy-fe/tailwind.config.ts new file mode 100644 index 0000000..7dc697b --- /dev/null +++ b/apps/deploy-fe/tailwind.config.ts @@ -0,0 +1 @@ +export * from '@workspace/ui/tailwind.config' diff --git a/apps/deploy-fe/tsconfig.json b/apps/deploy-fe/tsconfig.json new file mode 100644 index 0000000..c0240cf --- /dev/null +++ b/apps/deploy-fe/tsconfig.json @@ -0,0 +1,23 @@ +{ + "extends": "@workspace/typescript-config/nextjs.json", + "compilerOptions": { + "baseUrl": ".", + "paths": { + "@/*": ["./src/*"], + "@workspace/ui/*": ["../../packages/ui/src/*"] + }, + "plugins": [ + { + "name": "next" + } + ] + }, + "include": [ + "next-env.d.ts", + "next.config.mjs", + "./src/**/*.ts", + "./src/**/*.tsx", + ".next/types/**/*.ts" + ], + "exclude": ["node_modules"] +} diff --git a/apps/web/package.json b/apps/web/package.json index 9f29a4b..0bdfc2d 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -8,7 +8,7 @@ "build": "next build", "start": "next start", "lint": "biome check .", - "lint:fix": "biome check --apply .", + "lint:fix": "biome check --write .", "format": "biome format .", "format:fix": "biome format --write .", "check-types": "tsc --noEmit", @@ -44,6 +44,7 @@ "@radix-ui/react-toggle": "^1.1.2", "@radix-ui/react-toggle-group": "^1.1.2", "@radix-ui/react-tooltip": "^1.1.8", + "@tailwindcss/upgrade": "^4.0.6", "@workspace/ui": "workspace:*", "class-variance-authority": "^0.7.0", "cmdk": "1.0.0", diff --git a/apps/web/postcss.config.mjs b/apps/web/postcss.config.mjs index 5f90e69..d923411 100644 --- a/apps/web/postcss.config.mjs +++ b/apps/web/postcss.config.mjs @@ -1 +1,6 @@ -export { default } from '@workspace/ui/postcss.config' +export default { + plugins: { + '@tailwindcss/postcss': {}, + autoprefixer: {} + } +} diff --git a/apps/web/src/app/favicon.ico b/apps/web/src/app/favicon.ico new file mode 100644 index 0000000..718d6fe Binary files /dev/null and b/apps/web/src/app/favicon.ico differ diff --git a/apps/web/app/layout.tsx b/apps/web/src/app/layout.tsx similarity index 100% rename from apps/web/app/layout.tsx rename to apps/web/src/app/layout.tsx index 83476dc..f30f61b 100644 --- a/apps/web/app/layout.tsx +++ b/apps/web/src/app/layout.tsx @@ -1,6 +1,6 @@ +import { Providers } from '@/components/providers' import '@workspace/ui/globals.css' -import { Providers } from '@/components/providers' import { Geist, Geist_Mono } from 'next/font/google' const fontSans = Geist({ diff --git a/apps/web/app/page.tsx b/apps/web/src/app/page.tsx similarity index 100% rename from apps/web/app/page.tsx rename to apps/web/src/app/page.tsx diff --git a/apps/web/src/components/.gitkeep b/apps/web/src/components/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/apps/web/src/components/providers.tsx b/apps/web/src/components/providers.tsx new file mode 100644 index 0000000..a78ecb5 --- /dev/null +++ b/apps/web/src/components/providers.tsx @@ -0,0 +1,18 @@ +'use client' + +import { ThemeProvider as NextThemesProvider } from 'next-themes' +import type * as React from 'react' + +export function Providers({ children }: { children: React.ReactNode }) { + return ( + + {children} + + ) +} diff --git a/apps/web/src/hooks/.gitkeep b/apps/web/src/hooks/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/apps/web/src/hooks/use-mobile.tsx b/apps/web/src/hooks/use-mobile.tsx new file mode 100644 index 0000000..4331d5c --- /dev/null +++ b/apps/web/src/hooks/use-mobile.tsx @@ -0,0 +1,19 @@ +import * as React from 'react' + +const MOBILE_BREAKPOINT = 768 + +export function useIsMobile() { + const [isMobile, setIsMobile] = React.useState(undefined) + + React.useEffect(() => { + const mql = window.matchMedia(`(max-width: ${MOBILE_BREAKPOINT - 1}px)`) + const onChange = () => { + setIsMobile(window.innerWidth < MOBILE_BREAKPOINT) + } + mql.addEventListener('change', onChange) + setIsMobile(window.innerWidth < MOBILE_BREAKPOINT) + return () => mql.removeEventListener('change', onChange) + }, []) + + return !!isMobile +} diff --git a/apps/web/src/lib/.gitkeep b/apps/web/src/lib/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/apps/web/tsconfig.json b/apps/web/tsconfig.json index 7e80576..305dcfa 100644 --- a/apps/web/tsconfig.json +++ b/apps/web/tsconfig.json @@ -3,7 +3,7 @@ "compilerOptions": { "baseUrl": ".", "paths": { - "@/*": ["./*"], + "@/*": ["./src/*"], "@workspace/ui/*": ["../../packages/ui/src/*"] }, "plugins": [ diff --git a/biome.json b/biome.json index e6cba48..6bf7431 100644 --- a/biome.json +++ b/biome.json @@ -7,7 +7,7 @@ }, "files": { "ignoreUnknown": false, - "ignore": ["node_modules", "dist", "build"] + "ignore": ["node_modules", "dist", "build", ".next"] }, "formatter": { "enabled": true, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index cab8d74..092481a 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -27,14 +27,14 @@ importers: specifier: ^5.7.3 version: 5.7.3 - apps/web: + apps/deploy-fe: dependencies: '@biomejs/biome': specifier: ^1.9.4 version: 1.9.4 '@biomejs/monorepo': specifier: github:biomejs/biome - version: https://codeload.github.com/biomejs/biome/tar.gz/d95df40a86c8debb369fdc9070c91642325bfe1f + version: https://codeload.github.com/biomejs/biome/tar.gz/21dd358be5dade01d672916a0ab76bc825ef85cb '@hookform/resolvers': specifier: ^4.1.2 version: 4.1.2(react-hook-form@7.54.2(react@19.0.0)) @@ -193,6 +193,175 @@ importers: specifier: ^5 version: 5.7.3 + apps/web: + dependencies: + '@biomejs/biome': + specifier: ^1.9.4 + version: 1.9.4 + '@biomejs/monorepo': + specifier: github:biomejs/biome + version: https://codeload.github.com/biomejs/biome/tar.gz/21dd358be5dade01d672916a0ab76bc825ef85cb + '@hookform/resolvers': + specifier: ^4.1.2 + version: 4.1.2(react-hook-form@7.54.2(react@19.0.0)) + '@radix-ui/react-accordion': + specifier: ^1.2.3 + version: 1.2.3(@types/react-dom@18.3.1)(@types/react@18.3.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@radix-ui/react-alert-dialog': + specifier: ^1.1.6 + version: 1.1.6(@types/react-dom@18.3.1)(@types/react@18.3.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@radix-ui/react-aspect-ratio': + specifier: ^1.1.2 + version: 1.1.2(@types/react-dom@18.3.1)(@types/react@18.3.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@radix-ui/react-avatar': + specifier: ^1.1.3 + version: 1.1.3(@types/react-dom@18.3.1)(@types/react@18.3.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@radix-ui/react-checkbox': + specifier: ^1.1.4 + version: 1.1.4(@types/react-dom@18.3.1)(@types/react@18.3.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@radix-ui/react-collapsible': + specifier: ^1.1.3 + version: 1.1.3(@types/react-dom@18.3.1)(@types/react@18.3.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@radix-ui/react-context-menu': + specifier: ^2.2.6 + version: 2.2.6(@types/react-dom@18.3.1)(@types/react@18.3.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@radix-ui/react-dialog': + specifier: ^1.1.6 + version: 1.1.6(@types/react-dom@18.3.1)(@types/react@18.3.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@radix-ui/react-dropdown-menu': + specifier: ^2.1.6 + version: 2.1.6(@types/react-dom@18.3.1)(@types/react@18.3.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@radix-ui/react-hover-card': + specifier: ^1.1.6 + version: 1.1.6(@types/react-dom@18.3.1)(@types/react@18.3.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@radix-ui/react-label': + specifier: ^2.1.2 + version: 2.1.2(@types/react-dom@18.3.1)(@types/react@18.3.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@radix-ui/react-menubar': + specifier: ^1.1.6 + version: 1.1.6(@types/react-dom@18.3.1)(@types/react@18.3.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@radix-ui/react-navigation-menu': + specifier: ^1.2.5 + version: 1.2.5(@types/react-dom@18.3.1)(@types/react@18.3.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@radix-ui/react-popover': + specifier: ^1.1.6 + version: 1.1.6(@types/react-dom@18.3.1)(@types/react@18.3.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@radix-ui/react-progress': + specifier: ^1.1.2 + version: 1.1.2(@types/react-dom@18.3.1)(@types/react@18.3.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@radix-ui/react-radio-group': + specifier: ^1.2.3 + version: 1.2.3(@types/react-dom@18.3.1)(@types/react@18.3.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@radix-ui/react-scroll-area': + specifier: ^1.2.3 + version: 1.2.3(@types/react-dom@18.3.1)(@types/react@18.3.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@radix-ui/react-select': + specifier: ^2.1.6 + version: 2.1.6(@types/react-dom@18.3.1)(@types/react@18.3.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@radix-ui/react-separator': + specifier: ^1.1.2 + version: 1.1.2(@types/react-dom@18.3.1)(@types/react@18.3.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@radix-ui/react-slider': + specifier: ^1.2.3 + version: 1.2.3(@types/react-dom@18.3.1)(@types/react@18.3.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@radix-ui/react-slot': + specifier: ^1.1.1 + version: 1.1.2(@types/react@18.3.0)(react@19.0.0) + '@radix-ui/react-switch': + specifier: ^1.1.3 + version: 1.1.3(@types/react-dom@18.3.1)(@types/react@18.3.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@radix-ui/react-tabs': + specifier: ^1.1.3 + version: 1.1.3(@types/react-dom@18.3.1)(@types/react@18.3.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@radix-ui/react-toggle': + specifier: ^1.1.2 + version: 1.1.2(@types/react-dom@18.3.1)(@types/react@18.3.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@radix-ui/react-toggle-group': + specifier: ^1.1.2 + version: 1.1.2(@types/react-dom@18.3.1)(@types/react@18.3.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@radix-ui/react-tooltip': + specifier: ^1.1.8 + version: 1.1.8(@types/react-dom@18.3.1)(@types/react@18.3.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@tailwindcss/upgrade': + specifier: ^4.0.6 + version: 4.0.6 + '@workspace/ui': + specifier: workspace:* + version: link:../../services/ui + class-variance-authority: + specifier: ^0.7.0 + version: 0.7.1 + cmdk: + specifier: 1.0.0 + version: 1.0.0(@types/react-dom@18.3.1)(@types/react@18.3.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + date-fns: + specifier: ^4.1.0 + version: 4.1.0 + embla-carousel-react: + specifier: ^8.5.2 + version: 8.5.2(react@19.0.0) + input-otp: + specifier: ^1.4.2 + version: 1.4.2(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + lucide-react: + specifier: 0.456.0 + version: 0.456.0(react@19.0.0) + next: + specifier: ^15.1.0 + version: 15.2.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + next-themes: + specifier: ^0.4.4 + version: 0.4.4(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + react: + specifier: ^19.0.0 + version: 19.0.0 + react-day-picker: + specifier: 8.10.1 + version: 8.10.1(date-fns@4.1.0)(react@19.0.0) + react-dom: + specifier: ^19.0.0 + version: 19.0.0(react@19.0.0) + react-hook-form: + specifier: ^7.54.2 + version: 7.54.2(react@19.0.0) + react-resizable-panels: + specifier: ^2.1.7 + version: 2.1.7(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + recharts: + specifier: ^2.15.1 + version: 2.15.1(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + sonner: + specifier: ^2.0.1 + version: 2.0.1(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + vaul: + specifier: ^1.1.2 + version: 1.1.2(@types/react-dom@18.3.1)(@types/react@18.3.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + zod: + specifier: ^3.23.8 + version: 3.24.2 + devDependencies: + '@types/node': + specifier: ^20 + version: 20.17.19 + '@types/react': + specifier: 18.3.0 + version: 18.3.0 + '@types/react-dom': + specifier: 18.3.1 + version: 18.3.1 + '@workspace/typescript-config': + specifier: workspace:* + version: link:../../services/typescript-config + postcss: + specifier: ^8 + version: 8.5.3 + tailwindcss: + specifier: ^4.0.9 + version: 4.0.9 + typescript: + specifier: ^5 + version: 5.7.3 + services/typescript-config: {} services/ui: @@ -202,7 +371,7 @@ importers: version: 1.9.4 '@biomejs/monorepo': specifier: github:biomejs/biome - version: https://codeload.github.com/biomejs/biome/tar.gz/d95df40a86c8debb369fdc9070c91642325bfe1f + version: https://codeload.github.com/biomejs/biome/tar.gz/21dd358be5dade01d672916a0ab76bc825ef85cb '@radix-ui/react-slot': specifier: ^1.1.1 version: 1.1.2(@types/react@18.3.0)(react@19.0.0) @@ -234,6 +403,9 @@ importers: specifier: ^3.23.8 version: 3.24.2 devDependencies: + '@tailwindcss/postcss': + specifier: ^4.0.9 + version: 4.0.9 '@turbo/gen': specifier: ^2.2.3 version: 2.4.4(@types/node@22.13.5)(typescript@5.7.3) @@ -253,7 +425,7 @@ importers: specifier: ^10.4.20 version: 10.4.20(postcss@8.5.3) postcss: - specifier: ^8.4.47 + specifier: ^8.5.3 version: 8.5.3 tailwindcss: specifier: ^4.0.9 @@ -264,6 +436,10 @@ importers: packages: + '@alloc/quick-lru@5.2.0': + resolution: {integrity: sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==} + engines: {node: '>=10'} + '@babel/runtime-corejs3@7.26.9': resolution: {integrity: sha512-5EVjbTegqN7RSJle6hMWYxO4voo4rI+9krITk+DWR+diJgGrjZjrIBnJhjrHYYQsFgI7j1w1QnrvV7YSKBfYGg==} engines: {node: '>=6.9.0'} @@ -325,8 +501,8 @@ packages: cpu: [x64] os: [win32] - '@biomejs/monorepo@https://codeload.github.com/biomejs/biome/tar.gz/d95df40a86c8debb369fdc9070c91642325bfe1f': - resolution: {tarball: https://codeload.github.com/biomejs/biome/tar.gz/d95df40a86c8debb369fdc9070c91642325bfe1f} + '@biomejs/monorepo@https://codeload.github.com/biomejs/biome/tar.gz/21dd358be5dade01d672916a0ab76bc825ef85cb': + resolution: {tarball: https://codeload.github.com/biomejs/biome/tar.gz/21dd358be5dade01d672916a0ab76bc825ef85cb} version: 0.0.0 '@cspotcode/source-map-support@0.8.1': @@ -1290,6 +1466,10 @@ packages: '@radix-ui/rect@1.1.0': resolution: {integrity: sha512-A9+lCBZoaMJlVKcRBz2YByCG+Cp2t6nAnMnNba+XiWxnj6r4JUFqfsgwocMBZU9LPtdxC6wB56ySYpc7LQIoJg==} + '@sindresorhus/merge-streams@2.3.0': + resolution: {integrity: sha512-LtoMMhxAlorcGhmFYI+LhPgbPZCkgP6ra1YL604EeF6U98pLlQ3iWIGMdWSC+vWmPBWBNgmDBAhnAobLROJmwg==} + engines: {node: '>=18'} + '@standard-schema/utils@0.3.0': resolution: {integrity: sha512-e7Mew686owMaPJVNNLs55PUvgz371nKgwsc4vxE49zsODpJEnxgxRo2y/OKrqueavXgZNMDVj3DdHFlaSAeU8g==} @@ -1299,6 +1479,86 @@ packages: '@swc/helpers@0.5.15': resolution: {integrity: sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g==} + '@tailwindcss/node@4.0.9': + resolution: {integrity: sha512-tOJvdI7XfJbARYhxX+0RArAhmuDcczTC46DGCEziqxzzbIaPnfYaIyRT31n4u8lROrsO7Q6u/K9bmQHL2uL1bQ==} + + '@tailwindcss/oxide-android-arm64@4.0.9': + resolution: {integrity: sha512-YBgy6+2flE/8dbtrdotVInhMVIxnHJPbAwa7U1gX4l2ThUIaPUp18LjB9wEH8wAGMBZUb//SzLtdXXNBHPUl6Q==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [android] + + '@tailwindcss/oxide-darwin-arm64@4.0.9': + resolution: {integrity: sha512-pWdl4J2dIHXALgy2jVkwKBmtEb73kqIfMpYmcgESr7oPQ+lbcQ4+tlPeVXaSAmang+vglAfFpXQCOvs/aGSqlw==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [darwin] + + '@tailwindcss/oxide-darwin-x64@4.0.9': + resolution: {integrity: sha512-4Dq3lKp0/C7vrRSkNPtBGVebEyWt9QPPlQctxJ0H3MDyiQYvzVYf8jKow7h5QkWNe8hbatEqljMj/Y0M+ERYJg==} + engines: {node: '>= 10'} + cpu: [x64] + os: [darwin] + + '@tailwindcss/oxide-freebsd-x64@4.0.9': + resolution: {integrity: sha512-k7U1RwRODta8x0uealtVt3RoWAWqA+D5FAOsvVGpYoI6ObgmnzqWW6pnVwz70tL8UZ/QXjeMyiICXyjzB6OGtQ==} + engines: {node: '>= 10'} + cpu: [x64] + os: [freebsd] + + '@tailwindcss/oxide-linux-arm-gnueabihf@4.0.9': + resolution: {integrity: sha512-NDDjVweHz2zo4j+oS8y3KwKL5wGCZoXGA9ruJM982uVJLdsF8/1AeKvUwKRlMBpxHt1EdWJSAh8a0Mfhl28GlQ==} + engines: {node: '>= 10'} + cpu: [arm] + os: [linux] + + '@tailwindcss/oxide-linux-arm64-gnu@4.0.9': + resolution: {integrity: sha512-jk90UZ0jzJl3Dy1BhuFfRZ2KP9wVKMXPjmCtY4U6fF2LvrjP5gWFJj5VHzfzHonJexjrGe1lMzgtjriuZkxagg==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + + '@tailwindcss/oxide-linux-arm64-musl@4.0.9': + resolution: {integrity: sha512-3eMjyTC6HBxh9nRgOHzrc96PYh1/jWOwHZ3Kk0JN0Kl25BJ80Lj9HEvvwVDNTgPg154LdICwuFLuhfgH9DULmg==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + + '@tailwindcss/oxide-linux-x64-gnu@4.0.9': + resolution: {integrity: sha512-v0D8WqI/c3WpWH1kq/HP0J899ATLdGZmENa2/emmNjubT0sWtEke9W9+wXeEoACuGAhF9i3PO5MeyditpDCiWQ==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + + '@tailwindcss/oxide-linux-x64-musl@4.0.9': + resolution: {integrity: sha512-Kvp0TCkfeXyeehqLJr7otsc4hd/BUPfcIGrQiwsTVCfaMfjQZCG7DjI+9/QqPZha8YapLA9UoIcUILRYO7NE1Q==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + + '@tailwindcss/oxide-win32-arm64-msvc@4.0.9': + resolution: {integrity: sha512-m3+60T/7YvWekajNq/eexjhV8z10rswcz4BC9bioJ7YaN+7K8W2AmLmG0B79H14m6UHE571qB0XsPus4n0QVgQ==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [win32] + + '@tailwindcss/oxide-win32-x64-msvc@4.0.9': + resolution: {integrity: sha512-dpc05mSlqkwVNOUjGu/ZXd5U1XNch1kHFJ4/cHkZFvaW1RzbHmRt24gvM8/HC6IirMxNarzVw4IXVtvrOoZtxA==} + engines: {node: '>= 10'} + cpu: [x64] + os: [win32] + + '@tailwindcss/oxide@4.0.9': + resolution: {integrity: sha512-eLizHmXFqHswJONwfqi/WZjtmWZpIalpvMlNhTM99/bkHtUs6IqgI1XQ0/W5eO2HiRQcIlXUogI2ycvKhVLNcA==} + engines: {node: '>= 10'} + + '@tailwindcss/postcss@4.0.9': + resolution: {integrity: sha512-BT/E+pdMqulavEAVM5NCpxmGEwHiLDPpkmg/c/X25ZBW+izTe+aZ+v1gf/HXTrihRoCxrUp5U4YyHsBTzspQKQ==} + + '@tailwindcss/upgrade@4.0.6': + resolution: {integrity: sha512-vq6wVJ+jdHuiHfIPO7/1EQFZbTW7OhFmTc40OJdnI0mvC0J/7QC1hOtIIV+JCySxp+ozOerYTu6cZxhDdl4xCQ==} + hasBin: true + '@tootallnate/quickjs-emscripten@0.23.0': resolution: {integrity: sha512-C5Mc6rdnsaJDjO3UpGW/CQTHtCKaYlScZTly4JIu97Jxo/odCiH0ITnDXSJPTOrEKk/ycSZ0AOgTmkDtkOsvIA==} @@ -1576,6 +1836,11 @@ packages: resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} engines: {node: '>= 8'} + cssesc@3.0.0: + resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==} + engines: {node: '>=4'} + hasBin: true + csstype@3.1.3: resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==} @@ -1642,6 +1907,14 @@ packages: decimal.js-light@2.5.1: resolution: {integrity: sha512-qIMFpTMZmny+MMIitAB6D7iVPEorVw6YQRWkvarTkT4tBeSLLiHzcwj6q0MmYSFCiVpiqPJTJEYIrpcPzVEIvg==} + dedent@1.5.3: + resolution: {integrity: sha512-NHQtfOOW68WD8lgypbLA5oT+Bt0xXJhiYvoR6SmmNXZfpzOGXwdKWmcwG8N7PwVVWV3eF/68nmD9BaJSsTBhyQ==} + peerDependencies: + babel-plugin-macros: ^3.1.0 + peerDependenciesMeta: + babel-plugin-macros: + optional: true + deep-extend@0.6.0: resolution: {integrity: sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==} engines: {node: '>=4.0.0'} @@ -1657,6 +1930,11 @@ packages: resolution: {integrity: sha512-wH9xOVHnczo9jN2IW68BabcecVPxacIA3g/7z6vhSU/4stOKQzeCRK0yD0A24WiAAUJmmVpWqrERcTxnLo3AnA==} engines: {node: '>=8'} + detect-libc@1.0.3: + resolution: {integrity: sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==} + engines: {node: '>=0.10'} + hasBin: true + detect-libc@2.0.3: resolution: {integrity: sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==} engines: {node: '>=8'} @@ -1697,6 +1975,10 @@ packages: emoji-regex@8.0.0: resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} + enhanced-resolve@5.18.1: + resolution: {integrity: sha512-ZSW3ma5GkcQBIpwZTSRAI8N71Uuwgs93IezB7mf7R60tC8ZbJideoDNKjHn2O9KIlx6rkGTTEk1xUCK2E1Y2Yg==} + engines: {node: '>=10.13.0'} + escalade@3.2.0: resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} engines: {node: '>=6'} @@ -1790,6 +2072,10 @@ packages: resolution: {integrity: sha512-7dUi7RvCoT/xast/o/dLN53oqND4yk0nsHkhRgn9w65C4PofCLOoJ39iSOg+qVDdWQPIEj+eszMHQ+aLVwwQSg==} engines: {node: '>=8'} + globby@14.1.0: + resolution: {integrity: sha512-0Ia46fDOaT7k4og1PDW4YbodWWr3scS2vAr2lTbsplOt2WkKp0vQbkI9wKis/T5LV/dqPjO3bpS/z6GTJB82LA==} + engines: {node: '>=18'} + graceful-fs@4.2.11: resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} @@ -1840,6 +2126,10 @@ packages: resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} engines: {node: '>= 4'} + ignore@7.0.3: + resolution: {integrity: sha512-bAH5jbK/F3T3Jls4I0SO1hmPR0dKU0a7+SY6n1yzRtG54FLO8d6w/nxLFX2Nb7dBu6cCWXPaAME6cYqFUMmuCA==} + engines: {node: '>= 4'} + indent-string@4.0.0: resolution: {integrity: sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==} engines: {node: '>=8'} @@ -1932,6 +2222,10 @@ packages: isexe@2.0.0: resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + jiti@2.4.2: + resolution: {integrity: sha512-rg9zJN+G4n2nfJl5MW3BMygZX56zKPNVEYYqq7adpmMh4Jn2QNEwhvQlFy6jPVdcod7txZtKHWnyZiA3a0zP7A==} + hasBin: true + js-tokens@4.0.0: resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} @@ -1999,6 +2293,70 @@ packages: resolution: {integrity: sha512-/5royc/WbL2KTfFJ54wEdvxUZOBXwc54v/fW2Bz4LMOkAA3LWIxnoUiybSiauu+nhdTG98qERxH1YHwF2wZlAA==} hasBin: true + lightningcss-darwin-arm64@1.29.1: + resolution: {integrity: sha512-HtR5XJ5A0lvCqYAoSv2QdZZyoHNttBpa5EP9aNuzBQeKGfbyH5+UipLWvVzpP4Uml5ej4BYs5I9Lco9u1fECqw==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [darwin] + + lightningcss-darwin-x64@1.29.1: + resolution: {integrity: sha512-k33G9IzKUpHy/J/3+9MCO4e+PzaFblsgBjSGlpAaFikeBFm8B/CkO3cKU9oI4g+fjS2KlkLM/Bza9K/aw8wsNA==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [darwin] + + lightningcss-freebsd-x64@1.29.1: + resolution: {integrity: sha512-0SUW22fv/8kln2LnIdOCmSuXnxgxVC276W5KLTwoehiO0hxkacBxjHOL5EtHD8BAXg2BvuhsJPmVMasvby3LiQ==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [freebsd] + + lightningcss-linux-arm-gnueabihf@1.29.1: + resolution: {integrity: sha512-sD32pFvlR0kDlqsOZmYqH/68SqUMPNj+0pucGxToXZi4XZgZmqeX/NkxNKCPsswAXU3UeYgDSpGhu05eAufjDg==} + engines: {node: '>= 12.0.0'} + cpu: [arm] + os: [linux] + + lightningcss-linux-arm64-gnu@1.29.1: + resolution: {integrity: sha512-0+vClRIZ6mmJl/dxGuRsE197o1HDEeeRk6nzycSy2GofC2JsY4ifCRnvUWf/CUBQmlrvMzt6SMQNMSEu22csWQ==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + + lightningcss-linux-arm64-musl@1.29.1: + resolution: {integrity: sha512-UKMFrG4rL/uHNgelBsDwJcBqVpzNJbzsKkbI3Ja5fg00sgQnHw/VrzUTEc4jhZ+AN2BvQYz/tkHu4vt1kLuJyw==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + + lightningcss-linux-x64-gnu@1.29.1: + resolution: {integrity: sha512-u1S+xdODy/eEtjADqirA774y3jLcm8RPtYztwReEXoZKdzgsHYPl0s5V52Tst+GKzqjebkULT86XMSxejzfISw==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + + lightningcss-linux-x64-musl@1.29.1: + resolution: {integrity: sha512-L0Tx0DtaNUTzXv0lbGCLB/c/qEADanHbu4QdcNOXLIe1i8i22rZRpbT3gpWYsCh9aSL9zFujY/WmEXIatWvXbw==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + + lightningcss-win32-arm64-msvc@1.29.1: + resolution: {integrity: sha512-QoOVnkIEFfbW4xPi+dpdft/zAKmgLgsRHfJalEPYuJDOWf7cLQzYg0DEh8/sn737FaeMJxHZRc1oBreiwZCjog==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [win32] + + lightningcss-win32-x64-msvc@1.29.1: + resolution: {integrity: sha512-NygcbThNBe4JElP+olyTI/doBNGJvLs3bFCRPdvuCcxZCcCZ71B858IHpdm7L1btZex0FvCmM17FK98Y9MRy1Q==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [win32] + + lightningcss@1.29.1: + resolution: {integrity: sha512-FmGoeD4S05ewj+AkhTY+D+myDvXI6eL27FjHIjoyUkO/uw7WZD1fBVs0QxeYWa7E17CUHJaYX/RUGISCtcrG4Q==} + engines: {node: '>= 12.0.0'} + lodash.get@4.4.2: resolution: {integrity: sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==} deprecated: This package is deprecated. Use the optional chaining (?.) operator instead. @@ -2065,6 +2423,10 @@ packages: resolution: {integrity: sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==} hasBin: true + mri@1.2.0: + resolution: {integrity: sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==} + engines: {node: '>=4'} + ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} @@ -2113,6 +2475,14 @@ packages: no-case@2.3.2: resolution: {integrity: sha512-rmTZ9kz+f3rCvK2TD1Ue/oZlns7OGoIWP4fc3llxxRXlOkHKoWPPWJOfFYpITabSow43QJbRIoHQXtt10VldyQ==} + node-addon-api@8.3.1: + resolution: {integrity: sha512-lytcDEdxKjGJPTLEfW4mYMigRezMlyJY8W4wxJK8zE533Jlb8L8dRuObJFWg2P+AuOIxoCgKF+2Oq4d4Zd0OUA==} + engines: {node: ^18 || ^20 || >= 21} + + node-gyp-build@4.8.4: + resolution: {integrity: sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ==} + hasBin: true + node-plop@0.26.3: resolution: {integrity: sha512-Cov028YhBZ5aB7MdMWJEmwyBig43aGL5WT4vdoB28Oitau1zZAcHUn8Sgfk9HM33TqhtLJ9PlM/O0Mv+QpV/4Q==} engines: {node: '>=8.9.4'} @@ -2187,6 +2557,10 @@ packages: resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} engines: {node: '>=8'} + path-type@6.0.0: + resolution: {integrity: sha512-Vj7sf++t5pBD637NSfkxpHSMfWaeig5+DKWLhcqIYx6mWQz5hdJTGDVMQiJcw1ZYkhs7AazKDGpRVji1LJCZUQ==} + engines: {node: '>=18'} + picocolors@1.0.1: resolution: {integrity: sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==} @@ -2197,6 +2571,20 @@ packages: resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} engines: {node: '>=8.6'} + pify@2.3.0: + resolution: {integrity: sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==} + engines: {node: '>=0.10.0'} + + postcss-import@16.1.0: + resolution: {integrity: sha512-7hsAZ4xGXl4MW+OKEWCnF6T5jqBw80/EE9aXg1r2yyn1RsVEU8EtKXbijEODa+rg7iih4bKf7vlvTGYR4CnPNg==} + engines: {node: '>=18.0.0'} + peerDependencies: + postcss: ^8.0.0 + + postcss-selector-parser@7.1.0: + resolution: {integrity: sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA==} + engines: {node: '>=4'} + postcss-value-parser@4.2.0: resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==} @@ -2208,6 +2596,11 @@ packages: resolution: {integrity: sha512-dle9A3yYxlBSrt8Fu+IpjGT8SY8hN0mlaA6GY8t0P5PjIOZemULz/E2Bnm/2dcUOena75OTNkHI76uZBNUUq3A==} engines: {node: ^10 || ^12 || >=14} + prettier@3.5.0: + resolution: {integrity: sha512-quyMrVt6svPS7CjQ9gKb3GLEX/rl3BCL2oa/QkNcXv4YNVBC9olt3s+H7ukto06q7B1Qz46PbrKLO34PR6vXcA==} + engines: {node: '>=14'} + hasBin: true + prop-types@15.8.1: resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==} @@ -2310,6 +2703,9 @@ packages: resolution: {integrity: sha512-V8AVnmPIICiWpGfm6GLzCR/W5FXLchHop40W4nXBmdlEceh16rCN8O8LNWm5bh5XUX91fh7KpA+W0TgMKmgTpQ==} engines: {node: '>=0.10.0'} + read-cache@1.0.0: + resolution: {integrity: sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==} + readable-stream@3.6.2: resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==} engines: {node: '>= 6'} @@ -2410,6 +2806,10 @@ packages: resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} engines: {node: '>=8'} + slash@5.1.0: + resolution: {integrity: sha512-ZA6oR3T/pEyuqwMgAKT0/hAv8oAXckzbkmR0UkUosQ+Mc4RxGoJkRmwHgHufaenlyAgE1Mxgpdcrf75y6XcnDg==} + engines: {node: '>=14.16'} + smart-buffer@4.2.0: resolution: {integrity: sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==} engines: {node: '>= 6.0.0', npm: '>= 3.0.0'} @@ -2501,9 +2901,16 @@ packages: peerDependencies: tailwindcss: '>=3.0.0 || insiders' + tailwindcss@4.0.6: + resolution: {integrity: sha512-mysewHYJKaXgNOW6pp5xon/emCsfAMnO8WMaGKZZ35fomnR/T5gYnRg2/yRTTrtXiEl1tiVkeRt0eMO6HxEZqw==} + tailwindcss@4.0.9: resolution: {integrity: sha512-12laZu+fv1ONDRoNR9ipTOpUD7RN9essRVkX36sjxuRUInpN7hIiHN4lBd/SIFjbISvnXzp8h/hXzmU8SQQYhw==} + tapable@2.2.1: + resolution: {integrity: sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==} + engines: {node: '>=6'} + through@2.3.8: resolution: {integrity: sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==} @@ -2527,6 +2934,25 @@ packages: resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} engines: {node: '>=8.0'} + tree-sitter-javascript@0.23.1: + resolution: {integrity: sha512-/bnhbrTD9frUYHQTiYnPcxyHORIw157ERBa6dqzaKxvR/x3PC4Yzd+D1pZIMS6zNg2v3a8BZ0oK7jHqsQo9fWA==} + peerDependencies: + tree-sitter: ^0.21.1 + peerDependenciesMeta: + tree-sitter: + optional: true + + tree-sitter-typescript@0.23.2: + resolution: {integrity: sha512-e04JUUKxTT53/x3Uq1zIL45DoYKVfHH4CZqwgZhPg5qYROl5nQjV+85ruFzFGZxu+QeFVbRTPDRnqL9UbU4VeA==} + peerDependencies: + tree-sitter: ^0.21.0 + peerDependenciesMeta: + tree-sitter: + optional: true + + tree-sitter@0.22.4: + resolution: {integrity: sha512-usbHZP9/oxNsUY65MQUsduGRqDHQOou1cagUSwjhoSYAmSahjQDAVsh9s+SlZkn8X8+O1FULRGwHu7AFP3kjzg==} + ts-node@10.9.2: resolution: {integrity: sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==} hasBin: true @@ -2601,6 +3027,10 @@ packages: undici-types@6.20.0: resolution: {integrity: sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==} + unicorn-magic@0.3.0: + resolution: {integrity: sha512-+QBBXBCvifc56fsbuxZQ6Sic3wqqc3WWaqxs58gvJrcOuN83HGTCwz3oS5phzU9LthRNE9VrJCFCLUgHeeFnfA==} + engines: {node: '>=18'} + universalify@2.0.1: resolution: {integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==} engines: {node: '>= 10.0.0'} @@ -2686,6 +3116,8 @@ packages: snapshots: + '@alloc/quick-lru@5.2.0': {} + '@babel/runtime-corejs3@7.26.9': dependencies: core-js-pure: 3.40.0 @@ -2730,7 +3162,7 @@ snapshots: '@biomejs/cli-win32-x64@1.9.4': optional: true - '@biomejs/monorepo@https://codeload.github.com/biomejs/biome/tar.gz/d95df40a86c8debb369fdc9070c91642325bfe1f': {} + '@biomejs/monorepo@https://codeload.github.com/biomejs/biome/tar.gz/21dd358be5dade01d672916a0ab76bc825ef85cb': {} '@cspotcode/source-map-support@0.8.1': dependencies: @@ -3673,6 +4105,8 @@ snapshots: '@radix-ui/rect@1.1.0': {} + '@sindresorhus/merge-streams@2.3.0': {} + '@standard-schema/utils@0.3.0': {} '@swc/counter@0.1.3': {} @@ -3681,6 +4115,89 @@ snapshots: dependencies: tslib: 2.8.1 + '@tailwindcss/node@4.0.9': + dependencies: + enhanced-resolve: 5.18.1 + jiti: 2.4.2 + tailwindcss: 4.0.9 + + '@tailwindcss/oxide-android-arm64@4.0.9': + optional: true + + '@tailwindcss/oxide-darwin-arm64@4.0.9': + optional: true + + '@tailwindcss/oxide-darwin-x64@4.0.9': + optional: true + + '@tailwindcss/oxide-freebsd-x64@4.0.9': + optional: true + + '@tailwindcss/oxide-linux-arm-gnueabihf@4.0.9': + optional: true + + '@tailwindcss/oxide-linux-arm64-gnu@4.0.9': + optional: true + + '@tailwindcss/oxide-linux-arm64-musl@4.0.9': + optional: true + + '@tailwindcss/oxide-linux-x64-gnu@4.0.9': + optional: true + + '@tailwindcss/oxide-linux-x64-musl@4.0.9': + optional: true + + '@tailwindcss/oxide-win32-arm64-msvc@4.0.9': + optional: true + + '@tailwindcss/oxide-win32-x64-msvc@4.0.9': + optional: true + + '@tailwindcss/oxide@4.0.9': + optionalDependencies: + '@tailwindcss/oxide-android-arm64': 4.0.9 + '@tailwindcss/oxide-darwin-arm64': 4.0.9 + '@tailwindcss/oxide-darwin-x64': 4.0.9 + '@tailwindcss/oxide-freebsd-x64': 4.0.9 + '@tailwindcss/oxide-linux-arm-gnueabihf': 4.0.9 + '@tailwindcss/oxide-linux-arm64-gnu': 4.0.9 + '@tailwindcss/oxide-linux-arm64-musl': 4.0.9 + '@tailwindcss/oxide-linux-x64-gnu': 4.0.9 + '@tailwindcss/oxide-linux-x64-musl': 4.0.9 + '@tailwindcss/oxide-win32-arm64-msvc': 4.0.9 + '@tailwindcss/oxide-win32-x64-msvc': 4.0.9 + + '@tailwindcss/postcss@4.0.9': + dependencies: + '@alloc/quick-lru': 5.2.0 + '@tailwindcss/node': 4.0.9 + '@tailwindcss/oxide': 4.0.9 + lightningcss: 1.29.1 + postcss: 8.5.3 + tailwindcss: 4.0.9 + + '@tailwindcss/upgrade@4.0.6': + dependencies: + '@tailwindcss/node': 4.0.9 + '@tailwindcss/oxide': 4.0.9 + braces: 3.0.3 + dedent: 1.5.3 + enhanced-resolve: 5.18.1 + globby: 14.1.0 + jiti: 2.4.2 + mri: 1.2.0 + picocolors: 1.1.1 + postcss: 8.5.3 + postcss-import: 16.1.0(postcss@8.5.3) + postcss-selector-parser: 7.1.0 + prettier: 3.5.0 + tailwindcss: 4.0.6 + tree-sitter: 0.22.4 + tree-sitter-typescript: 0.23.2(tree-sitter@0.22.4) + transitivePeerDependencies: + - babel-plugin-macros + '@tootallnate/quickjs-emscripten@0.23.0': {} '@tsconfig/node10@1.0.11': {} @@ -3999,6 +4516,8 @@ snapshots: shebang-command: 2.0.0 which: 2.0.2 + cssesc@3.0.0: {} + csstype@3.1.3: {} d3-array@3.2.4: @@ -4049,6 +4568,8 @@ snapshots: decimal.js-light@2.5.1: {} + dedent@1.5.3: {} + deep-extend@0.6.0: {} defaults@1.0.4: @@ -4072,6 +4593,8 @@ snapshots: rimraf: 3.0.2 slash: 3.0.0 + detect-libc@1.0.3: {} + detect-libc@2.0.3: optional: true @@ -4108,6 +4631,11 @@ snapshots: emoji-regex@8.0.0: {} + enhanced-resolve@5.18.1: + dependencies: + graceful-fs: 4.2.11 + tapable: 2.2.1 + escalade@3.2.0: {} escape-string-regexp@1.0.5: {} @@ -4216,6 +4744,15 @@ snapshots: merge2: 1.4.1 slash: 3.0.0 + globby@14.1.0: + dependencies: + '@sindresorhus/merge-streams': 2.3.0 + fast-glob: 3.3.3 + ignore: 7.0.3 + path-type: 6.0.0 + slash: 5.1.0 + unicorn-magic: 0.3.0 + graceful-fs@4.2.11: {} gradient-string@2.0.2: @@ -4269,6 +4806,8 @@ snapshots: ignore@5.3.2: {} + ignore@7.0.3: {} + indent-string@4.0.0: {} inflight@1.0.6: @@ -4365,6 +4904,8 @@ snapshots: isexe@2.0.0: {} + jiti@2.4.2: {} + js-tokens@4.0.0: {} js-yaml@4.1.0: @@ -4422,6 +4963,51 @@ snapshots: lefthook-windows-arm64: 1.11.2 lefthook-windows-x64: 1.11.2 + lightningcss-darwin-arm64@1.29.1: + optional: true + + lightningcss-darwin-x64@1.29.1: + optional: true + + lightningcss-freebsd-x64@1.29.1: + optional: true + + lightningcss-linux-arm-gnueabihf@1.29.1: + optional: true + + lightningcss-linux-arm64-gnu@1.29.1: + optional: true + + lightningcss-linux-arm64-musl@1.29.1: + optional: true + + lightningcss-linux-x64-gnu@1.29.1: + optional: true + + lightningcss-linux-x64-musl@1.29.1: + optional: true + + lightningcss-win32-arm64-msvc@1.29.1: + optional: true + + lightningcss-win32-x64-msvc@1.29.1: + optional: true + + lightningcss@1.29.1: + dependencies: + detect-libc: 1.0.3 + optionalDependencies: + lightningcss-darwin-arm64: 1.29.1 + lightningcss-darwin-x64: 1.29.1 + lightningcss-freebsd-x64: 1.29.1 + lightningcss-linux-arm-gnueabihf: 1.29.1 + lightningcss-linux-arm64-gnu: 1.29.1 + lightningcss-linux-arm64-musl: 1.29.1 + lightningcss-linux-x64-gnu: 1.29.1 + lightningcss-linux-x64-musl: 1.29.1 + lightningcss-win32-arm64-msvc: 1.29.1 + lightningcss-win32-x64-msvc: 1.29.1 + lodash.get@4.4.2: {} lodash@4.17.21: {} @@ -4478,6 +5064,8 @@ snapshots: dependencies: minimist: 1.2.8 + mri@1.2.0: {} + ms@2.1.3: {} mute-stream@0.0.8: {} @@ -4522,6 +5110,10 @@ snapshots: dependencies: lower-case: 1.1.4 + node-addon-api@8.3.1: {} + + node-gyp-build@4.8.4: {} + node-plop@0.26.3: dependencies: '@babel/runtime-corejs3': 7.26.9 @@ -4622,12 +5214,28 @@ snapshots: path-type@4.0.0: {} + path-type@6.0.0: {} + picocolors@1.0.1: {} picocolors@1.1.1: {} picomatch@2.3.1: {} + pify@2.3.0: {} + + postcss-import@16.1.0(postcss@8.5.3): + dependencies: + postcss: 8.5.3 + postcss-value-parser: 4.2.0 + read-cache: 1.0.0 + resolve: 1.22.10 + + postcss-selector-parser@7.1.0: + dependencies: + cssesc: 3.0.0 + util-deprecate: 1.0.2 + postcss-value-parser@4.2.0: {} postcss@8.4.31: @@ -4642,6 +5250,8 @@ snapshots: picocolors: 1.1.1 source-map-js: 1.2.1 + prettier@3.5.0: {} + prop-types@15.8.1: dependencies: loose-envify: 1.4.0 @@ -4752,6 +5362,10 @@ snapshots: react@19.0.0: {} + read-cache@1.0.0: + dependencies: + pify: 2.3.0 + readable-stream@3.6.2: dependencies: inherits: 2.0.4 @@ -4875,6 +5489,8 @@ snapshots: slash@3.0.0: {} + slash@5.1.0: {} + smart-buffer@4.2.0: {} snake-case@2.1.0: @@ -4951,8 +5567,12 @@ snapshots: dependencies: tailwindcss: 4.0.9 + tailwindcss@4.0.6: {} + tailwindcss@4.0.9: {} + tapable@2.2.1: {} + through@2.3.8: {} tiny-invariant@1.3.3: {} @@ -4977,6 +5597,26 @@ snapshots: dependencies: is-number: 7.0.0 + tree-sitter-javascript@0.23.1(tree-sitter@0.22.4): + dependencies: + node-addon-api: 8.3.1 + node-gyp-build: 4.8.4 + optionalDependencies: + tree-sitter: 0.22.4 + + tree-sitter-typescript@0.23.2(tree-sitter@0.22.4): + dependencies: + node-addon-api: 8.3.1 + node-gyp-build: 4.8.4 + tree-sitter-javascript: 0.23.1(tree-sitter@0.22.4) + optionalDependencies: + tree-sitter: 0.22.4 + + tree-sitter@0.22.4: + dependencies: + node-addon-api: 8.3.1 + node-gyp-build: 4.8.4 + ts-node@10.9.2(@types/node@22.13.5)(typescript@5.7.3): dependencies: '@cspotcode/source-map-support': 0.8.1 @@ -5037,6 +5677,8 @@ snapshots: undici-types@6.20.0: {} + unicorn-magic@0.3.0: {} + universalify@2.0.1: {} update-browserslist-db@1.1.3(browserslist@4.24.4): diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index da7fe60..50db9dc 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -1,9 +1,15 @@ packages: - apps/* - services/* -ignoredBuiltDependencies: - - '@biomejs/biome' - - core-js-pure - - sharp onlyBuiltDependencies: - '@biomejs/biome' + - '@biomejs/cli-darwin-arm64' + - chalk + - lefthook + - lefthook-darwin-arm64 + - tree-sitter + - tree-sitter-javascript + - tree-sitter-typescript + - turbo + - turbo-darwin-arm64 + - typescript diff --git a/services/ui/package.json b/services/ui/package.json index ec9a066..4e9235e 100644 --- a/services/ui/package.json +++ b/services/ui/package.json @@ -21,13 +21,14 @@ "zod": "^3.23.8" }, "devDependencies": { + "@tailwindcss/postcss": "^4.0.9", "@turbo/gen": "^2.2.3", "@types/node": "^22.9.0", "@types/react": "18.3.0", "@types/react-dom": "18.3.1", "@workspace/typescript-config": "workspace:*", "autoprefixer": "^10.4.20", - "postcss": "^8.4.47", + "postcss": "^8.5.3", "react": "^18.3.1", "tailwindcss": "^4.0.9", "typescript": "^5.6.3" diff --git a/services/ui/postcss.config.mjs b/services/ui/postcss.config.mjs index 764f5bd..4d8610d 100644 --- a/services/ui/postcss.config.mjs +++ b/services/ui/postcss.config.mjs @@ -1,9 +1,5 @@ -/** @type {import('postcss-load-config').Config} */ -const config = { +module.exports = { plugins: { - tailwindcss: {}, - autoprefixer: {} + '@tailwindcss/postcss': {} } } - -export default config diff --git a/services/ui/src/styles/globals.css b/services/ui/src/styles/globals.css index 05a646b..a8d2d5c 100644 --- a/services/ui/src/styles/globals.css +++ b/services/ui/src/styles/globals.css @@ -1,6 +1,4 @@ -@tailwind base; -@tailwind components; -@tailwind utilities; +@import "tailwindcss"; @layer base { :root { @@ -72,22 +70,13 @@ --sidebar-border: 240 3.7% 15.9%; --sidebar-ring: 217.2 91.2% 59.8%; } -} + /* } */ -@layer base { + /* @theme base { * { @apply border-border; } body { @apply bg-background text-foreground; - } -} - -@layer base { - * { - @apply border-border outline-ring/50; - } - body { - @apply bg-background text-foreground; - } + } */ } diff --git a/services/ui/tailwind.config.ts b/services/ui/tailwind.config.ts index 8f0ab24..980f37e 100644 --- a/services/ui/tailwind.config.ts +++ b/services/ui/tailwind.config.ts @@ -1,6 +1,6 @@ import type { Config } from 'tailwindcss' -import defaultTheme from 'tailwindcss' import tailwindcssAnimate from 'tailwindcss-animate' +import defaultTheme from 'tailwindcss/defaultTheme' const config = { // darkMode: ["class"], content: [ diff --git a/standards/blueprints/next-app-router-structure.md b/standards/blueprints/next-app-router-structure.md new file mode 100644 index 0000000..926e031 --- /dev/null +++ b/standards/blueprints/next-app-router-structure.md @@ -0,0 +1,171 @@ +# Next.js App Router Structure with Abbreviated URLs + +``` +app/ + page.tsx # URL: / + layout.tsx + not-found.tsx + global-error.tsx + + login/ + page.tsx # URL: /login + + wallet/ + page.tsx # URL: /wallet + layout.tsx + + store/ + page.tsx # URL: /store + layout.tsx + + (web3-authenticated)/ # Auth wrapper (not in URL) + layout.tsx + + (dashboard)/ # Dashboard wrapper (not in URL) + layout.tsx + + page.tsx # URL: / + + (buy-prepaid-service)/ + bp/ # Abbreviated + page.tsx # URL: /bp + + (projects)/ + pr/ # Abbreviated + page.tsx # URL: /pr + + [provider]/ + page.tsx # URL: /pr/[provider] + + [orgSlug]/ + page.tsx # URL: /pr/[provider]/[orgSlug] + layout.tsx + error.tsx + not-found.tsx + loading.tsx + + (settings)/ + set/ # Abbreviated + page.tsx # URL: /pr/[provider]/[orgSlug]/set + + (projects)/ + ps/ # Abbreviated + page.tsx # URL: /pr/[provider]/[orgSlug]/ps + layout.tsx + loading.tsx + error.tsx + + (create)/ + cr/ # Abbreviated + page.tsx # URL: /pr/[provider]/[orgSlug]/ps/cr + layout.tsx + + (configure)/ + cf/ # Abbreviated + page.tsx # URL: /pr/[provider]/[orgSlug]/ps/cr/cf + + (deploy)/ + dp/ # Abbreviated + page.tsx # URL: /pr/[provider]/[orgSlug]/ps/cr/dp + loading.tsx + + (success)/ + sc/ # Abbreviated + [id]/ + page.tsx # URL: /pr/[provider]/[orgSlug]/ps/cr/sc/[id] + + (template)/ + tm/ # Abbreviated + page.tsx # URL: /pr/[provider]/[orgSlug]/ps/cr/tm + + (configure)/ + cf/ # Abbreviated + page.tsx # URL: /pr/[provider]/[orgSlug]/ps/cr/tm/cf + + (deploy)/ + dp/ # Abbreviated + page.tsx # URL: /pr/[provider]/[orgSlug]/ps/cr/tm/dp + loading.tsx + + [id]/ + page.tsx # URL: /pr/[provider]/[orgSlug]/ps/[id] + layout.tsx + loading.tsx + error.tsx + not-found.tsx + + (deployments)/ + dep/ # Abbreviated + page.tsx # URL: /pr/[provider]/[orgSlug]/ps/[id]/dep + loading.tsx + + (integrations)/ + int/ # Abbreviated + page.tsx # URL: /pr/[provider]/[orgSlug]/ps/[id]/int + + (settings)/ + set/ # Abbreviated + page.tsx # URL: /pr/[provider]/[orgSlug]/ps/[id]/set + layout.tsx + + (domains)/ + dom/ # Abbreviated + page.tsx # URL: /pr/[provider]/[orgSlug]/ps/[id]/set/dom + + (add)/ + add/ # Kept as-is (short enough) + page.tsx # URL: /pr/[provider]/[orgSlug]/ps/[id]/set/dom/add + + (config)/ + cf/ # Abbreviated + page.tsx # URL: /pr/[provider]/[orgSlug]/ps/[id]/set/dom/add/cf + + (git)/ + git/ # Kept as-is (short enough) + page.tsx # URL: /pr/[provider]/[orgSlug]/ps/[id]/set/git + + (environment-variables)/ + env/ # Abbreviated + page.tsx # URL: /pr/[provider]/[orgSlug]/ps/[id]/set/env + + (collaborators)/ + col/ # Abbreviated + page.tsx # URL: /pr/[provider]/[orgSlug]/ps/[id]/set/col +``` + +## Abbreviation Legend + +- bp = buy-prepaid-service +- pr = projects +- ps = projects (within organization) +- cr = create +- cf = configure +- dp = deploy +- sc = success +- tm = template +- dep = deployments +- int = integrations +- set = settings +- dom = domains +- env = environment-variables +- col = collaborators + +## API Routes + +``` +app/ + api/ + route.ts + + organizations/ + [slug]/ + route.ts + + projects/ + route.ts + + [id]/ + route.ts + deployments/ + route.ts +``` diff --git a/standards/blueprints/nextjs-templates.md b/standards/blueprints/nextjs-templates.md new file mode 100644 index 0000000..b7db49b --- /dev/null +++ b/standards/blueprints/nextjs-templates.md @@ -0,0 +1,441 @@ +# Next.js App Router File Templates + +This document provides basic templates for the common file types used in a Next.js application with the App Router. These templates follow the current best practices for Next.js 15. + +## Page Templates + +### Basic Page (`page.tsx`) + +```tsx +import { Metadata } from 'next' + +export const metadata: Metadata = { + title: 'Page Title', + description: 'Page description', +} + +export default function Page() { + return ( +
+

Page Content

+ {/* Page content goes here */} +
+ ) +} +``` + +### Dynamic Route Page (`[slug]/page.tsx`) + +```tsx +export async function generateMetadata({ params }) { + return { + title: `Page for ${params.slug}`, + description: `Description for ${params.slug}`, + } +} + +export default function DynamicPage({ params }) { + const { slug } = params + + return ( +
+

Dynamic Page: {slug}

+ {/* Dynamic page content goes here */} +
+ ) +} +``` + +## Layout Templates + +### Root Layout (`layout.tsx`) + +```tsx +import { Metadata } from 'next' +import './globals.css' + +export const metadata: Metadata = { + title: { + template: '%s | Site Name', + default: 'Site Name', + }, + description: 'Site description', +} + +export default function RootLayout({ children }) { + return ( + + +
+ {/* Header content */} +
+
{children}
+
+ {/* Footer content */} +
+ + + ) +} +``` + +### Nested Layout (`(dashboard)/layout.tsx`) + +```tsx +export default function DashboardLayout({ children }) { + return ( +
+ +
+ {children} +
+
+ ) +} +``` + +### Auth Layout with Session Check (`(authenticated)/layout.tsx`) + +```tsx +import { redirect } from 'next/navigation' + +// This is a Server Component +export default async function AuthLayout({ children }) { + const session = await getSession() // Replace with your auth solution + + if (!session) { + redirect('/login') + } + + return <>{children} +} +``` + +## Error Handling Templates + +### Not Found (`not-found.tsx`) + +```tsx +import Link from 'next/link' + +export const metadata = { + title: 'Not Found', + description: 'Page not found', +} + +export default function NotFound() { + return ( +
+

404 - Page Not Found

+

The page you are looking for does not exist.

+ + Return to Home + +
+ ) +} +``` + +### Error Page (`error.tsx`) + +```tsx +'use client' // Error components must be Client Components + +import { useEffect } from 'react' + +export default function Error({ error, reset }) { + useEffect(() => { + // Log the error to an error reporting service + console.error(error) + }, [error]) + + return ( +
+

Something went wrong!

+ +
+ ) +} +``` + +### Global Error (`global-error.tsx`) + +```tsx +'use client' + +export default function GlobalError({ error, reset }) { + return ( + + +
+

Something went wrong!

+ +
+ + + ) +} +``` + +## Loading States + +### Loading Component (`loading.tsx`) + +```tsx +export default function Loading() { + return ( +
+
+

Loading...

+
+ ) +} +``` + +## Route Handlers + +### API Route (`api/route.ts`) + +```ts +import { NextResponse } from 'next/server' + +export async function GET(request) { + // Handle GET request + return NextResponse.json({ message: 'Hello World' }) +} + +export async function POST(request) { + // Handle POST request + const body = await request.json() + return NextResponse.json({ received: body }) +} +``` + +### Dynamic API Route (`api/[slug]/route.ts`) + +```ts +import { NextResponse } from 'next/server' + +export async function GET(request, { params }) { + const { slug } = params + return NextResponse.json({ slug }) +} +``` + +## Middleware + +### Middleware (`middleware.ts`) + +Place this file in the root of your project: + +```ts +import { NextResponse } from 'next/server' +import type { NextRequest } from 'next/server' + +// This function runs before requests are completed +export function middleware(request: NextRequest) { + const currentUrl = request.nextUrl.clone() + + // Example: check if user is authenticated + const isAuthenticated = checkAuth(request) + + if (!isAuthenticated && currentUrl.pathname.startsWith('/protected')) { + return NextResponse.redirect(new URL('/login', request.url)) + } + + return NextResponse.next() +} + +// Configure matcher for paths that should trigger middleware +export const config = { + matcher: ['/protected/:path*', '/api/:path*'], +} + +// Example auth check function +function checkAuth(request) { + // Implement your auth check logic here + return !!request.cookies.get('auth-token') +} +``` + +## Utilities - Server Actions + +### Form Actions (`actions.ts`) + +```ts +'use server' + +export async function submitForm(formData: FormData) { + // Validate data + const name = formData.get('name') + const email = formData.get('email') + + // Process data + try { + // Save to database or send to API + await saveToDatabase({ name, email }) + return { success: true } + } catch (error) { + return { success: false, error: error.message } + } +} + +async function saveToDatabase(data) { + // Implementation for database interaction +} +``` + +## Server Component with Data Fetching + +### Data Fetching in Server Component (`dashboard/page.tsx`) + +```tsx +// This is a Server Component +export default async function DashboardPage() { + // This data fetching happens on the server + const data = await fetchDashboardData() + + return ( +
+

Dashboard

+
+ {data.map(item => ( +
+

{item.title}

+

{item.value}

+
+ ))} +
+
+ ) +} + +async function fetchDashboardData() { + // API or database call + const res = await fetch('https://api.example.com/dashboard-data', { + cache: 'no-store' // Don't cache this data + }) + + if (!res.ok) { + throw new Error('Failed to fetch dashboard data') + } + + return res.json() +} +``` + +## Client Component with Hooks + +### Interactive Client Component (`components/Counter.tsx`) + +```tsx +'use client' // Mark as Client Component + +import { useState } from 'react' + +export default function Counter() { + const [count, setCount] = useState(0) + + return ( +
+

Count: {count}

+ +
+ ) +} +``` + +## Parallel Routes + +### Parallel Route Layout (`@dashboard/page.tsx` and `@profile/page.tsx`) + +In your directory structure: +``` +app/ + layout.tsx + [user]/ + layout.tsx + page.tsx + @dashboard/ + page.tsx + @profile/ + page.tsx +``` + +In `[user]/layout.tsx`: +```tsx +export default function UserLayout({ children, dashboard, profile }) { + return ( +
+
+ {/* Sidebar navigation */} +
+
+ {children} +
+
+ {dashboard} +
+
+ {profile} +
+
+ ) +} +``` + +## Route Interception + +### Photo Modal Example (`./(.)photos/[id]/page.tsx`) + +The directory structure might look like: +``` +app/ + photos/ + page.tsx + [id]/ + page.tsx + (.)photos/ + [id]/ + page.tsx // This intercepts /photos/[id] +``` + +In `./(.)photos/[id]/page.tsx`: +```tsx +export default function PhotoModal({ params }) { + const { id } = params + + // Fetch photo data based on id + + return ( +
+
+

Photo {id}

+ {`Photo +
+
+ ) +} +``` + +## References + +- [Official Next.js Documentation](https://nextjs.org/docs/app) +- [Pages and Layouts](https://nextjs.org/docs/app/building-your-application/routing/pages-and-layouts) +- [Route Handlers](https://nextjs.org/docs/app/building-your-application/routing/route-handlers) +- [Error Handling](https://nextjs.org/docs/app/building-your-application/routing/error-handling) +- [Loading UI and Streaming](https://nextjs.org/docs/app/building-your-application/routing/loading-ui-and-streaming) +- [Metadata API](https://nextjs.org/docs/app/building-your-application/optimizing/metadata) +- [Server Actions](https://nextjs.org/docs/app/building-your-application/data-fetching/server-actions) +- [Middleware](https://nextjs.org/docs/app/building-your-application/routing/middleware)