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}
+
+
+
+ )
+}
+```
+
+### 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 (
+
+ )
+}
+```
+
+## 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}
+

+
+
+ )
+}
+```
+
+## 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)