diff --git a/components.json b/components.json new file mode 100644 index 0000000..ffe928f --- /dev/null +++ b/components.json @@ -0,0 +1,21 @@ +{ + "$schema": "https://ui.shadcn.com/schema.json", + "style": "new-york", + "rsc": true, + "tsx": true, + "tailwind": { + "config": "", + "css": "src/app/globals.css", + "baseColor": "neutral", + "cssVariables": true, + "prefix": "" + }, + "aliases": { + "components": "@/components", + "utils": "@/lib/utils", + "ui": "@/components/ui", + "lib": "@/lib", + "hooks": "@/hooks" + }, + "iconLibrary": "lucide" +} \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 87c8584..7b1fefa 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,9 +8,23 @@ "name": "codenuk-frontend", "version": "0.1.0", "dependencies": { + "@next/font": "^14.2.15", + "@radix-ui/react-avatar": "^1.1.10", + "@radix-ui/react-checkbox": "^1.3.2", + "@radix-ui/react-dropdown-menu": "^2.1.15", + "@radix-ui/react-label": "^2.1.7", + "@radix-ui/react-progress": "^1.1.7", + "@radix-ui/react-radio-group": "^1.3.7", + "@radix-ui/react-select": "^2.2.5", + "@radix-ui/react-slot": "^1.2.3", + "@radix-ui/react-tabs": "^1.1.12", + "class-variance-authority": "^0.7.1", + "clsx": "^2.1.1", + "lucide-react": "^0.539.0", "next": "15.4.6", "react": "19.1.0", - "react-dom": "19.1.0" + "react-dom": "19.1.0", + "tailwind-merge": "^3.3.1" }, "devDependencies": { "@eslint/eslintrc": "^3", @@ -21,6 +35,7 @@ "eslint": "^9", "eslint-config-next": "15.4.6", "tailwindcss": "^4", + "tw-animate-css": "^1.3.6", "typescript": "^5" } }, @@ -225,6 +240,44 @@ "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, + "node_modules/@floating-ui/core": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.7.3.tgz", + "integrity": "sha512-sGnvb5dmrJaKEZ+LDIpguvdX3bDlEllmv4/ClQ9awcmCZrlx5jQyyMWFM5kBI+EyNOCDDiKk8il0zeuX3Zlg/w==", + "license": "MIT", + "dependencies": { + "@floating-ui/utils": "^0.2.10" + } + }, + "node_modules/@floating-ui/dom": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.7.3.tgz", + "integrity": "sha512-uZA413QEpNuhtb3/iIKoYMSK07keHPYeXF02Zhd6e213j+d1NamLix/mCLxBUDW/Gx52sPH2m+chlUsyaBs/Ag==", + "license": "MIT", + "dependencies": { + "@floating-ui/core": "^1.7.3", + "@floating-ui/utils": "^0.2.10" + } + }, + "node_modules/@floating-ui/react-dom": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.1.5.tgz", + "integrity": "sha512-HDO/1/1oH9fjj4eLgegrlH3dklZpHtUYYFiVwMUwfGvk9jWDRWqkklA2/NFScknrcNSspbV868WjXORvreDX+Q==", + "license": "MIT", + "dependencies": { + "@floating-ui/dom": "^1.7.3" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, + "node_modules/@floating-ui/utils": { + "version": "0.2.10", + "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.10.tgz", + "integrity": "sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ==", + "license": "MIT" + }, "node_modules/@humanfs/core": { "version": "0.19.1", "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", @@ -790,6 +843,15 @@ "fast-glob": "3.3.1" } }, + "node_modules/@next/font": { + "version": "14.2.15", + "resolved": "https://registry.npmjs.org/@next/font/-/font-14.2.15.tgz", + "integrity": "sha512-QopYhBmCDDrNDynbi+ZD1hDZXmQXVFo7TmAFp4DQgO/kogz1OLbQ92hPigJbj572eZ3GaaVxNIyYVn3/eAsehg==", + "license": "MIT", + "peerDependencies": { + "next": "*" + } + }, "node_modules/@next/swc-darwin-arm64": { "version": "15.4.6", "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-15.4.6.tgz", @@ -966,6 +1028,810 @@ "node": ">=12.4.0" } }, + "node_modules/@radix-ui/number": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/number/-/number-1.1.1.tgz", + "integrity": "sha512-MkKCwxlXTgz6CFoJx3pCwn07GKp36+aZyu/u2Ln2VrA5DcdyCZkASEDBTd8x5whTQQL5CiYf4prXKLcgQdv29g==", + "license": "MIT" + }, + "node_modules/@radix-ui/primitive": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.2.tgz", + "integrity": "sha512-XnbHrrprsNqZKQhStrSwgRUQzoCI1glLzdw79xiZPoofhGICeZRSQ3dIxAKH1gb3OHfNf4d6f+vAv3kil2eggA==", + "license": "MIT" + }, + "node_modules/@radix-ui/react-arrow": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/@radix-ui/react-arrow/-/react-arrow-1.1.7.tgz", + "integrity": "sha512-F+M1tLhO+mlQaOWspE8Wstg+z6PwxwRd8oQ8IXceWz92kfAmalTRf0EjrouQeo7QssEPfCn05B4Ihs1K9WQ/7w==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-primitive": "2.1.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-avatar": { + "version": "1.1.10", + "resolved": "https://registry.npmjs.org/@radix-ui/react-avatar/-/react-avatar-1.1.10.tgz", + "integrity": "sha512-V8piFfWapM5OmNCXTzVQY+E1rDa53zY+MQ4Y7356v4fFz6vqCyUtIz2rUD44ZEdwg78/jKmMJHj07+C/Z/rcog==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-callback-ref": "1.1.1", + "@radix-ui/react-use-is-hydrated": "0.1.0", + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-checkbox": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-checkbox/-/react-checkbox-1.3.2.tgz", + "integrity": "sha512-yd+dI56KZqawxKZrJ31eENUwqc1QSqg4OZ15rybGjF2ZNwMO+wCyHzAVLRp9qoYJf7kYy0YpZ2b0JCzJ42HZpA==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.2", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-presence": "1.1.4", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-controllable-state": "1.2.2", + "@radix-ui/react-use-previous": "1.1.1", + "@radix-ui/react-use-size": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-collection": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/@radix-ui/react-collection/-/react-collection-1.1.7.tgz", + "integrity": "sha512-Fh9rGN0MoI4ZFUNyfFVNU4y9LUz93u9/0K+yLgA2bwRojxM8JU1DyvvMBabnZPBgMWREAJvU2jjVzq+LrFUglw==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-slot": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-compose-refs": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.2.tgz", + "integrity": "sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-context": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.2.tgz", + "integrity": "sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-direction": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-direction/-/react-direction-1.1.1.tgz", + "integrity": "sha512-1UEWRX6jnOA2y4H5WczZ44gOOjTEmlqv1uNW4GAJEO5+bauCBhv8snY65Iw5/VOS/ghKN9gr2KjnLKxrsvoMVw==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-dismissable-layer": { + "version": "1.1.10", + "resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.10.tgz", + "integrity": "sha512-IM1zzRV4W3HtVgftdQiiOmA0AdJlCtMLe00FXaHwgt3rAnNsIyDqshvkIW3hj/iu5hu8ERP7KIYki6NkqDxAwQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.2", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-callback-ref": "1.1.1", + "@radix-ui/react-use-escape-keydown": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-dropdown-menu": { + "version": "2.1.15", + "resolved": "https://registry.npmjs.org/@radix-ui/react-dropdown-menu/-/react-dropdown-menu-2.1.15.tgz", + "integrity": "sha512-mIBnOjgwo9AH3FyKaSWoSu/dYj6VdhJ7frEPiGTeXCdUFHjl9h3mFh2wwhEtINOmYXWhdpf1rY2minFsmaNgVQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.2", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-menu": "2.1.15", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-controllable-state": "1.2.2" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-focus-guards": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-guards/-/react-focus-guards-1.1.2.tgz", + "integrity": "sha512-fyjAACV62oPV925xFCrH8DR5xWhg9KYtJT4s3u54jxp+L/hbpTY2kIeEFFbFe+a/HCE94zGQMZLIpVTPVZDhaA==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-focus-scope": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-scope/-/react-focus-scope-1.1.7.tgz", + "integrity": "sha512-t2ODlkXBQyn7jkl6TNaw/MtVEVvIGelJDCG41Okq/KwUsJBwQ4XVZsHAVUkK4mBv3ewiAS3PGuUWuY2BoK4ZUw==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-callback-ref": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-id": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-id/-/react-id-1.1.1.tgz", + "integrity": "sha512-kGkGegYIdQsOb4XjsfM97rXsiHaBwco+hFI66oO4s9LU+PLAC5oJ7khdOVFxkhsmlbpUqDAvXw11CluXP+jkHg==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-label": { + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/@radix-ui/react-label/-/react-label-2.1.7.tgz", + "integrity": "sha512-YT1GqPSL8kJn20djelMX7/cTRp/Y9w5IZHvfxQTVHrOqa2yMl7i/UfMqKRU5V7mEyKTrUVgJXhNQPVCG8PBLoQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-primitive": "2.1.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-menu": { + "version": "2.1.15", + "resolved": "https://registry.npmjs.org/@radix-ui/react-menu/-/react-menu-2.1.15.tgz", + "integrity": "sha512-tVlmA3Vb9n8SZSd+YSbuFR66l87Wiy4du+YE+0hzKQEANA+7cWKH1WgqcEX4pXqxUFQKrWQGHdvEfw00TjFiew==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.2", + "@radix-ui/react-collection": "1.1.7", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-dismissable-layer": "1.1.10", + "@radix-ui/react-focus-guards": "1.1.2", + "@radix-ui/react-focus-scope": "1.1.7", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-popper": "1.2.7", + "@radix-ui/react-portal": "1.1.9", + "@radix-ui/react-presence": "1.1.4", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-roving-focus": "1.1.10", + "@radix-ui/react-slot": "1.2.3", + "@radix-ui/react-use-callback-ref": "1.1.1", + "aria-hidden": "^1.2.4", + "react-remove-scroll": "^2.6.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-popper": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-1.2.7.tgz", + "integrity": "sha512-IUFAccz1JyKcf/RjB552PlWwxjeCJB8/4KxT7EhBHOJM+mN7LdW+B3kacJXILm32xawcMMjb2i0cIZpo+f9kiQ==", + "license": "MIT", + "dependencies": { + "@floating-ui/react-dom": "^2.0.0", + "@radix-ui/react-arrow": "1.1.7", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-callback-ref": "1.1.1", + "@radix-ui/react-use-layout-effect": "1.1.1", + "@radix-ui/react-use-rect": "1.1.1", + "@radix-ui/react-use-size": "1.1.1", + "@radix-ui/rect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-portal": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/@radix-ui/react-portal/-/react-portal-1.1.9.tgz", + "integrity": "sha512-bpIxvq03if6UNwXZ+HTK71JLh4APvnXntDc6XOX8UVq4XQOVl7lwok0AvIl+b8zgCw3fSaVTZMpAPPagXbKmHQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-presence": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.1.4.tgz", + "integrity": "sha512-ueDqRbdc4/bkaQT3GIpLQssRlFgWaL/U2z/S31qRwwLWoxHLgry3SIfCwhxeQNbirEUXFa+lq3RL3oBYXtcmIA==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-primitive": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.3.tgz", + "integrity": "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-slot": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-progress": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/@radix-ui/react-progress/-/react-progress-1.1.7.tgz", + "integrity": "sha512-vPdg/tF6YC/ynuBIJlk1mm7Le0VgW6ub6J2UWnTQ7/D23KXcPI1qy+0vBkgKgd38RCMJavBXpB83HPNFMTb0Fg==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-primitive": "2.1.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-radio-group": { + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/@radix-ui/react-radio-group/-/react-radio-group-1.3.7.tgz", + "integrity": "sha512-9w5XhD0KPOrm92OTTE0SysH3sYzHsSTHNvZgUBo/VZ80VdYyB5RneDbc0dKpURS24IxkoFRu/hI0i4XyfFwY6g==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.2", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-presence": "1.1.4", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-roving-focus": "1.1.10", + "@radix-ui/react-use-controllable-state": "1.2.2", + "@radix-ui/react-use-previous": "1.1.1", + "@radix-ui/react-use-size": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-roving-focus": { + "version": "1.1.10", + "resolved": "https://registry.npmjs.org/@radix-ui/react-roving-focus/-/react-roving-focus-1.1.10.tgz", + "integrity": "sha512-dT9aOXUen9JSsxnMPv/0VqySQf5eDQ6LCk5Sw28kamz8wSOW2bJdlX2Bg5VUIIcV+6XlHpWTIuTPCf/UNIyq8Q==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.2", + "@radix-ui/react-collection": "1.1.7", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-callback-ref": "1.1.1", + "@radix-ui/react-use-controllable-state": "1.2.2" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-select": { + "version": "2.2.5", + "resolved": "https://registry.npmjs.org/@radix-ui/react-select/-/react-select-2.2.5.tgz", + "integrity": "sha512-HnMTdXEVuuyzx63ME0ut4+sEMYW6oouHWNGUZc7ddvUWIcfCva/AMoqEW/3wnEllriMWBa0RHspCYnfCWJQYmA==", + "license": "MIT", + "dependencies": { + "@radix-ui/number": "1.1.1", + "@radix-ui/primitive": "1.1.2", + "@radix-ui/react-collection": "1.1.7", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-dismissable-layer": "1.1.10", + "@radix-ui/react-focus-guards": "1.1.2", + "@radix-ui/react-focus-scope": "1.1.7", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-popper": "1.2.7", + "@radix-ui/react-portal": "1.1.9", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-slot": "1.2.3", + "@radix-ui/react-use-callback-ref": "1.1.1", + "@radix-ui/react-use-controllable-state": "1.2.2", + "@radix-ui/react-use-layout-effect": "1.1.1", + "@radix-ui/react-use-previous": "1.1.1", + "@radix-ui/react-visually-hidden": "1.2.3", + "aria-hidden": "^1.2.4", + "react-remove-scroll": "^2.6.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-slot": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz", + "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-tabs": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/@radix-ui/react-tabs/-/react-tabs-1.1.12.tgz", + "integrity": "sha512-GTVAlRVrQrSw3cEARM0nAx73ixrWDPNZAruETn3oHCNP6SbZ/hNxdxp+u7VkIEv3/sFoLq1PfcHrl7Pnp0CDpw==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-presence": "1.1.4", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-roving-focus": "1.1.10", + "@radix-ui/react-use-controllable-state": "1.2.2" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-callback-ref": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.1.1.tgz", + "integrity": "sha512-FkBMwD+qbGQeMu1cOHnuGB6x4yzPjho8ap5WtbEJ26umhgqVXbhekKUQO+hZEL1vU92a3wHwdp0HAcqAUF5iDg==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-controllable-state": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.2.2.tgz", + "integrity": "sha512-BjasUjixPFdS+NKkypcyyN5Pmg83Olst0+c6vGov0diwTEo6mgdqVR6hxcEgFuh4QrAs7Rc+9KuGJ9TVCj0Zzg==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-effect-event": "0.0.2", + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-effect-event": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-effect-event/-/react-use-effect-event-0.0.2.tgz", + "integrity": "sha512-Qp8WbZOBe+blgpuUT+lw2xheLP8q0oatc9UpmiemEICxGvFLYmHm9QowVZGHtJlGbS6A6yJ3iViad/2cVjnOiA==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-escape-keydown": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-escape-keydown/-/react-use-escape-keydown-1.1.1.tgz", + "integrity": "sha512-Il0+boE7w/XebUHyBjroE+DbByORGR9KKmITzbR7MyQ4akpORYP/ZmbhAr0DG7RmmBqoOnZdy2QlvajJ2QA59g==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-callback-ref": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-is-hydrated": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-is-hydrated/-/react-use-is-hydrated-0.1.0.tgz", + "integrity": "sha512-U+UORVEq+cTnRIaostJv9AGdV3G6Y+zbVd+12e18jQ5A3c0xL03IhnHuiU4UV69wolOQp5GfR58NW/EgdQhwOA==", + "license": "MIT", + "dependencies": { + "use-sync-external-store": "^1.5.0" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-layout-effect": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.1.1.tgz", + "integrity": "sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-previous": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-previous/-/react-use-previous-1.1.1.tgz", + "integrity": "sha512-2dHfToCj/pzca2Ck724OZ5L0EVrr3eHRNsG/b3xQJLA2hZpVCS99bLAX+hm1IHXDEnzU6by5z/5MIY794/a8NQ==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-rect": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-rect/-/react-use-rect-1.1.1.tgz", + "integrity": "sha512-QTYuDesS0VtuHNNvMh+CjlKJ4LJickCMUAqjlE3+j8w+RlRpwyX3apEQKGFzbZGdo7XNG1tXa+bQqIE7HIXT2w==", + "license": "MIT", + "dependencies": { + "@radix-ui/rect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-size": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-size/-/react-use-size-1.1.1.tgz", + "integrity": "sha512-ewrXRDTAqAXlkl6t/fkXWNAhFX9I+CkKlw6zjEwk86RSPKwZr3xpBRso655aqYafwtnbpHLj6toFzmd6xdVptQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-visually-hidden": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-visually-hidden/-/react-visually-hidden-1.2.3.tgz", + "integrity": "sha512-pzJq12tEaaIhqjbzpCuv/OypJY/BPavOofm+dbab+MHLajy277+1lLm6JFcGgF5eskJ6mquGirhXY2GD/8u8Ug==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-primitive": "2.1.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/rect": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/rect/-/rect-1.1.1.tgz", + "integrity": "sha512-HPwpGIzkl28mWyZqG52jiqDJ12waP11Pa1lGoiyUkIEuMLBP0oeK/C89esbXrxsky5we7dfd8U58nm0SgAWpVw==", + "license": "MIT" + }, "node_modules/@rtsao/scc": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@rtsao/scc/-/scc-1.1.0.tgz", @@ -1311,7 +2177,7 @@ "version": "19.1.10", "resolved": "https://registry.npmjs.org/@types/react/-/react-19.1.10.tgz", "integrity": "sha512-EhBeSYX0Y6ye8pNebpKrwFJq7BoQ8J5SO6NlvNwwHjSj6adXJViPQrKlsyPw7hLBLvckEMO1yxeGdR82YBBlDg==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "csstype": "^3.0.2" @@ -1321,7 +2187,7 @@ "version": "19.1.7", "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.1.7.tgz", "integrity": "sha512-i5ZzwYpqjmrKenzkoLM2Ibzt6mAsM7pxB6BCIouEVVmgiqaMj1TjaK7hnA36hbW5aZv20kx7Lw6hWzPWg0Rurw==", - "dev": true, + "devOptional": true, "license": "MIT", "peerDependencies": { "@types/react": "^19.0.0" @@ -1947,6 +2813,18 @@ "dev": true, "license": "Python-2.0" }, + "node_modules/aria-hidden": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/aria-hidden/-/aria-hidden-1.2.6.tgz", + "integrity": "sha512-ik3ZgC9dY/lYVVM++OISsaYDeg1tb0VtP5uL3ouh1koGOaUMDPpbFIei4JkFimWUFPn90sbMNMXQAIVOlnYKJA==", + "license": "MIT", + "dependencies": { + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/aria-query": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.2.tgz", @@ -2308,12 +3186,33 @@ "node": ">=18" } }, + "node_modules/class-variance-authority": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/class-variance-authority/-/class-variance-authority-0.7.1.tgz", + "integrity": "sha512-Ka+9Trutv7G8M6WT6SeiRWz792K5qEqIGEGzXKhAE6xOWAY6pPH8U+9IY3oCMv6kqTmLsv7Xh/2w2RigkePMsg==", + "license": "Apache-2.0", + "dependencies": { + "clsx": "^2.1.1" + }, + "funding": { + "url": "https://polar.sh/cva" + } + }, "node_modules/client-only": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz", "integrity": "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==", "license": "MIT" }, + "node_modules/clsx": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", + "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/color": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/color/-/color-4.2.3.tgz", @@ -2385,7 +3284,7 @@ "version": "3.1.3", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/damerau-levenshtein": { @@ -2520,6 +3419,12 @@ "node": ">=8" } }, + "node_modules/detect-node-es": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/detect-node-es/-/detect-node-es-1.1.0.tgz", + "integrity": "sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==", + "license": "MIT" + }, "node_modules/doctrine": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", @@ -3392,6 +4297,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/get-nonce": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-nonce/-/get-nonce-1.0.1.tgz", + "integrity": "sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/get-proto": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", @@ -4492,6 +5406,15 @@ "loose-envify": "cli.js" } }, + "node_modules/lucide-react": { + "version": "0.539.0", + "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-0.539.0.tgz", + "integrity": "sha512-VVISr+VF2krO91FeuCrm1rSOLACQUYVy7NQkzrOty52Y8TlTPcXcMdQFj9bYzBgXbWCiywlwSZ3Z8u6a+6bMlg==", + "license": "ISC", + "peerDependencies": { + "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, "node_modules/magic-string": { "version": "0.30.17", "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.17.tgz", @@ -5096,6 +6019,75 @@ "dev": true, "license": "MIT" }, + "node_modules/react-remove-scroll": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/react-remove-scroll/-/react-remove-scroll-2.7.1.tgz", + "integrity": "sha512-HpMh8+oahmIdOuS5aFKKY6Pyog+FNaZV/XyJOq7b4YFwsFHe5yYfdbIalI4k3vU2nSDql7YskmUseHsRrJqIPA==", + "license": "MIT", + "dependencies": { + "react-remove-scroll-bar": "^2.3.7", + "react-style-singleton": "^2.2.3", + "tslib": "^2.1.0", + "use-callback-ref": "^1.3.3", + "use-sidecar": "^1.1.3" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/react-remove-scroll-bar": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/react-remove-scroll-bar/-/react-remove-scroll-bar-2.3.8.tgz", + "integrity": "sha512-9r+yi9+mgU33AKcj6IbT9oRCO78WriSj6t/cF8DWBZJ9aOGPOTEDvdUDz1FwKim7QXWwmHqtdHnRJfhAxEG46Q==", + "license": "MIT", + "dependencies": { + "react-style-singleton": "^2.2.2", + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/react-style-singleton": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/react-style-singleton/-/react-style-singleton-2.2.3.tgz", + "integrity": "sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ==", + "license": "MIT", + "dependencies": { + "get-nonce": "^1.0.0", + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, "node_modules/reflect.getprototypeof": { "version": "1.0.10", "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.10.tgz", @@ -5706,6 +6698,16 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/tailwind-merge": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-3.3.1.tgz", + "integrity": "sha512-gBXpgUm/3rp1lMZZrM/w7D8GKqshif0zAymAhbCyIt8KMe+0v9DQ7cdYLR4FHH/cKpdTXb+A/tKKU3eolfsI+g==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/dcastil" + } + }, "node_modules/tailwindcss": { "version": "4.1.11", "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.1.11.tgz", @@ -5831,6 +6833,16 @@ "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", "license": "0BSD" }, + "node_modules/tw-animate-css": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/tw-animate-css/-/tw-animate-css-1.3.6.tgz", + "integrity": "sha512-9dy0R9UsYEGmgf26L8UcHiLmSFTHa9+D7+dAt/G/sF5dCnPePZbfgDYinc7/UzAM7g/baVrmS6m9yEpU46d+LA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/Wombosvideo" + } + }, "node_modules/type-check": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", @@ -6007,6 +7019,58 @@ "punycode": "^2.1.0" } }, + "node_modules/use-callback-ref": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/use-callback-ref/-/use-callback-ref-1.3.3.tgz", + "integrity": "sha512-jQL3lRnocaFtu3V00JToYz/4QkNWswxijDaCVNZRiRTO3HQDLsdu1ZtmIUvV4yPp+rvWm5j0y0TG/S61cuijTg==", + "license": "MIT", + "dependencies": { + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/use-sidecar": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/use-sidecar/-/use-sidecar-1.1.3.tgz", + "integrity": "sha512-Fedw0aZvkhynoPYlA5WXrMCAMm+nSWdZt6lzJQ7Ok8S6Q+VsHmHpRWndVRJ8Be0ZbkfPc5LRYH+5XrzXcEeLRQ==", + "license": "MIT", + "dependencies": { + "detect-node-es": "^1.1.0", + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/use-sync-external-store": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.5.0.tgz", + "integrity": "sha512-Rb46I4cGGVBmjamjphe8L/UnvJD+uPPtTkNvX5mZgqdbavhI4EbgIWJiIHXJ8bc/i9EQGPRh4DwEURJ552Do0A==", + "license": "MIT", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", diff --git a/package.json b/package.json index a6eaa4c..365a91b 100644 --- a/package.json +++ b/package.json @@ -9,19 +9,34 @@ "lint": "next lint" }, "dependencies": { + "@next/font": "^14.2.15", + "@radix-ui/react-avatar": "^1.1.10", + "@radix-ui/react-checkbox": "^1.3.2", + "@radix-ui/react-dropdown-menu": "^2.1.15", + "@radix-ui/react-label": "^2.1.7", + "@radix-ui/react-progress": "^1.1.7", + "@radix-ui/react-radio-group": "^1.3.7", + "@radix-ui/react-select": "^2.2.5", + "@radix-ui/react-slot": "^1.2.3", + "@radix-ui/react-tabs": "^1.1.12", + "class-variance-authority": "^0.7.1", + "clsx": "^2.1.1", + "lucide-react": "^0.539.0", + "next": "15.4.6", "react": "19.1.0", "react-dom": "19.1.0", - "next": "15.4.6" + "tailwind-merge": "^3.3.1" }, "devDependencies": { - "typescript": "^5", + "@eslint/eslintrc": "^3", + "@tailwindcss/postcss": "^4", "@types/node": "^20", "@types/react": "^19", "@types/react-dom": "^19", - "@tailwindcss/postcss": "^4", - "tailwindcss": "^4", "eslint": "^9", "eslint-config-next": "15.4.6", - "@eslint/eslintrc": "^3" + "tailwindcss": "^4", + "tw-animate-css": "^1.3.6", + "typescript": "^5" } } diff --git a/public/analytics-dashboard-preview.png b/public/analytics-dashboard-preview.png new file mode 100644 index 0000000..2849a39 Binary files /dev/null and b/public/analytics-dashboard-preview.png differ diff --git a/public/blog-platform-preview.png b/public/blog-platform-preview.png new file mode 100644 index 0000000..bff95e5 Binary files /dev/null and b/public/blog-platform-preview.png differ diff --git a/public/landing-page-preview.png b/public/landing-page-preview.png new file mode 100644 index 0000000..42819a0 Binary files /dev/null and b/public/landing-page-preview.png differ diff --git a/public/marketing-website-preview.png b/public/marketing-website-preview.png new file mode 100644 index 0000000..6a1e9fd Binary files /dev/null and b/public/marketing-website-preview.png differ diff --git a/public/saas-platform-preview.png b/public/saas-platform-preview.png new file mode 100644 index 0000000..9024388 Binary files /dev/null and b/public/saas-platform-preview.png differ diff --git a/public/seo-blog-preview.png b/public/seo-blog-preview.png new file mode 100644 index 0000000..201b123 Binary files /dev/null and b/public/seo-blog-preview.png differ diff --git a/src/app/architecture/page.tsx b/src/app/architecture/page.tsx new file mode 100644 index 0000000..a52d257 --- /dev/null +++ b/src/app/architecture/page.tsx @@ -0,0 +1,5 @@ +import ArchitectureGenerator from "@/components/architecture/architecture-generator" + +export default function ArchitecturePage() { + return +} \ No newline at end of file diff --git a/src/app/auth/page.tsx b/src/app/auth/page.tsx new file mode 100644 index 0000000..a1d510f --- /dev/null +++ b/src/app/auth/page.tsx @@ -0,0 +1,5 @@ +import { AuthPage } from "@/components/auth/auth-page" + +export default function AuthPageRoute() { + return +} diff --git a/src/app/business-context/page.tsx b/src/app/business-context/page.tsx new file mode 100644 index 0000000..7119ad6 --- /dev/null +++ b/src/app/business-context/page.tsx @@ -0,0 +1,5 @@ +import BusinessContextGenerator from "@/components/business-context/business-context-generator" + +export default function BusinessContextPage() { + return +} diff --git a/src/app/features/page.tsx b/src/app/features/page.tsx new file mode 100644 index 0000000..7ea41e0 --- /dev/null +++ b/src/app/features/page.tsx @@ -0,0 +1,5 @@ +import { FeaturesPage } from "@/components/features/features-page" + +export default function FeaturesPageRoute() { + return +} diff --git a/src/app/globals.css b/src/app/globals.css index a2dc41e..dc98be7 100644 --- a/src/app/globals.css +++ b/src/app/globals.css @@ -1,26 +1,122 @@ @import "tailwindcss"; +@import "tw-animate-css"; -:root { - --background: #ffffff; - --foreground: #171717; -} +@custom-variant dark (&:is(.dark *)); @theme inline { --color-background: var(--background); --color-foreground: var(--foreground); --font-sans: var(--font-geist-sans); --font-mono: var(--font-geist-mono); + --color-sidebar-ring: var(--sidebar-ring); + --color-sidebar-border: var(--sidebar-border); + --color-sidebar-accent-foreground: var(--sidebar-accent-foreground); + --color-sidebar-accent: var(--sidebar-accent); + --color-sidebar-primary-foreground: var(--sidebar-primary-foreground); + --color-sidebar-primary: var(--sidebar-primary); + --color-sidebar-foreground: var(--sidebar-foreground); + --color-sidebar: var(--sidebar); + --color-chart-5: var(--chart-5); + --color-chart-4: var(--chart-4); + --color-chart-3: var(--chart-3); + --color-chart-2: var(--chart-2); + --color-chart-1: var(--chart-1); + --color-ring: var(--ring); + --color-input: var(--input); + --color-border: var(--border); + --color-destructive: var(--destructive); + --color-accent-foreground: var(--accent-foreground); + --color-accent: var(--accent); + --color-muted-foreground: var(--muted-foreground); + --color-muted: var(--muted); + --color-secondary-foreground: var(--secondary-foreground); + --color-secondary: var(--secondary); + --color-primary-foreground: var(--primary-foreground); + --color-primary: var(--primary); + --color-popover-foreground: var(--popover-foreground); + --color-popover: var(--popover); + --color-card-foreground: var(--card-foreground); + --color-card: var(--card); + --radius-sm: calc(var(--radius) - 4px); + --radius-md: calc(var(--radius) - 2px); + --radius-lg: var(--radius); + --radius-xl: calc(var(--radius) + 4px); } -@media (prefers-color-scheme: dark) { - :root { - --background: #0a0a0a; - --foreground: #ededed; +:root { + --radius: 0.625rem; + --background: oklch(1 0 0); + --foreground: oklch(0.145 0 0); + --card: oklch(1 0 0); + --card-foreground: oklch(0.145 0 0); + --popover: oklch(1 0 0); + --popover-foreground: oklch(0.145 0 0); + --primary: oklch(0.205 0 0); + --primary-foreground: oklch(0.985 0 0); + --secondary: oklch(0.97 0 0); + --secondary-foreground: oklch(0.205 0 0); + --muted: oklch(0.97 0 0); + --muted-foreground: oklch(0.556 0 0); + --accent: oklch(0.97 0 0); + --accent-foreground: oklch(0.205 0 0); + --destructive: oklch(0.577 0.245 27.325); + --border: oklch(0.922 0 0); + --input: oklch(0.922 0 0); + --ring: oklch(0.708 0 0); + --chart-1: oklch(0.646 0.222 41.116); + --chart-2: oklch(0.6 0.118 184.704); + --chart-3: oklch(0.398 0.07 227.392); + --chart-4: oklch(0.828 0.189 84.429); + --chart-5: oklch(0.769 0.188 70.08); + --sidebar: oklch(0.985 0 0); + --sidebar-foreground: oklch(0.145 0 0); + --sidebar-primary: oklch(0.205 0 0); + --sidebar-primary-foreground: oklch(0.985 0 0); + --sidebar-accent: oklch(0.97 0 0); + --sidebar-accent-foreground: oklch(0.205 0 0); + --sidebar-border: oklch(0.922 0 0); + --sidebar-ring: oklch(0.708 0 0); +} + +.dark { + --background: oklch(0.145 0 0); + --foreground: oklch(0.985 0 0); + --card: oklch(0.205 0 0); + --card-foreground: oklch(0.985 0 0); + --popover: oklch(0.205 0 0); + --popover-foreground: oklch(0.985 0 0); + --primary: oklch(0.922 0 0); + --primary-foreground: oklch(0.205 0 0); + --secondary: oklch(0.269 0 0); + --secondary-foreground: oklch(0.985 0 0); + --muted: oklch(0.269 0 0); + --muted-foreground: oklch(0.708 0 0); + --accent: oklch(0.269 0 0); + --accent-foreground: oklch(0.985 0 0); + --destructive: oklch(0.704 0.191 22.216); + --border: oklch(1 0 0 / 10%); + --input: oklch(1 0 0 / 15%); + --ring: oklch(0.556 0 0); + --chart-1: oklch(0.488 0.243 264.376); + --chart-2: oklch(0.696 0.17 162.48); + --chart-3: oklch(0.769 0.188 70.08); + --chart-4: oklch(0.627 0.265 303.9); + --chart-5: oklch(0.645 0.246 16.439); + --sidebar: oklch(0.205 0 0); + --sidebar-foreground: oklch(0.985 0 0); + --sidebar-primary: oklch(0.488 0.243 264.376); + --sidebar-primary-foreground: oklch(0.985 0 0); + --sidebar-accent: oklch(0.269 0 0); + --sidebar-accent-foreground: oklch(0.985 0 0); + --sidebar-border: oklch(1 0 0 / 10%); + --sidebar-ring: oklch(0.556 0 0); +} + +@layer base { + * { + @apply border-border outline-ring/50; + } + body { + @apply bg-background text-foreground; } } - -body { - background: var(--background); - color: var(--foreground); - font-family: Arial, Helvetica, sans-serif; -} diff --git a/src/app/layout.tsx b/src/app/layout.tsx index f7fa87e..49d20d1 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -1,34 +1,44 @@ -import type { Metadata } from "next"; -import { Geist, Geist_Mono } from "next/font/google"; -import "./globals.css"; +import type React from "react" +import type { Metadata } from "next" +import { Poppins } from "next/font/google" +import { AuthProvider } from "@/contexts/auth-context" +import { AppLayout } from "@/components/layout/app-layout" +import "./globals.css" -const geistSans = Geist({ - variable: "--font-geist-sans", +const poppins = Poppins({ subsets: ["latin"], -}); - -const geistMono = Geist_Mono({ - variable: "--font-geist-mono", - subsets: ["latin"], -}); + weight: ["300", "400", "500", "600", "700"], + variable: "--font-poppins", +}) export const metadata: Metadata = { - title: "Create Next App", - description: "Generated by create next app", -}; + title: "Codenuk - AI-Powered Project Builder", + description: "Build scalable applications with AI-generated architecture and code", + generator: "v0.dev", +} export default function RootLayout({ children, }: Readonly<{ - children: React.ReactNode; + children: React.ReactNode }>) { return ( - - {children} + + + + + + +
{children}
+
+
- ); + ) } diff --git a/src/app/page.tsx b/src/app/page.tsx index a932894..ba374ff 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -1,103 +1,5 @@ -import Image from "next/image"; +import { redirect } from "next/navigation" -export default function Home() { - return ( -
-
- Next.js logo -
    -
  1. - Get started by editing{" "} - - src/app/page.tsx - - . -
  2. -
  3. - Save and see your changes instantly. -
  4. -
- - -
- -
- ); +export default function HomePage() { + redirect("/project-builder") } diff --git a/src/app/project-builder/page.tsx b/src/app/project-builder/page.tsx new file mode 100644 index 0000000..46beb18 --- /dev/null +++ b/src/app/project-builder/page.tsx @@ -0,0 +1,10 @@ +import { Suspense } from "react" +import { MainDashboard } from "@/components/main-dashboard" + +export default function ProjectBuilderPage() { + return ( + Loading...}> + + + ) +} diff --git a/src/app/templates/page.tsx b/src/app/templates/page.tsx new file mode 100644 index 0000000..48910c9 --- /dev/null +++ b/src/app/templates/page.tsx @@ -0,0 +1,5 @@ +import { TemplatesPage } from "@/components/templates/template-page" + +export default function TemplatesPageRoute() { + return +} diff --git a/src/components/architecture/architecture-generator.tsx b/src/components/architecture/architecture-generator.tsx new file mode 100644 index 0000000..fbb15f1 --- /dev/null +++ b/src/components/architecture/architecture-generator.tsx @@ -0,0 +1,191 @@ +"use client" + +import { useState } from "react" +import { Button } from "@/components/ui/button" +import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card" +import { Badge } from "@/components/ui/badge" +import { Input } from "@/components/ui/input" +import { Code, Database, Server, Shield, Zap, Layers, GitBranch } from "lucide-react" + +export default function ArchitectureGenerator() { + const [selectedArchitecture, setSelectedArchitecture] = useState("") + const [projectName, setProjectName] = useState("") + + const architecturePatterns = [ + { + id: "monolithic", + name: "Monolithic Architecture", + description: "Single application with all components tightly coupled", + icon: Layers, + complexity: "Low", + bestFor: "Small to medium projects", + pros: ["Simple to develop", "Easy to deploy", "Lower initial cost"], + cons: ["Harder to scale", "Technology lock-in", "Difficult to maintain"], + }, + { + id: "microservices", + name: "Microservices Architecture", + description: "Loosely coupled services that can be developed and deployed independently", + icon: GitBranch, + complexity: "High", + bestFor: "Large, complex applications", + pros: ["Independent scaling", "Technology diversity", "Easier maintenance"], + cons: ["Distributed complexity", "Network overhead", "Data consistency challenges"], + }, + { + id: "serverless", + name: "Serverless Architecture", + description: "Event-driven, auto-scaling functions without server management", + icon: Zap, + complexity: "Medium", + bestFor: "Event-driven applications", + pros: ["Auto-scaling", "Pay-per-use", "No server management"], + cons: ["Cold start latency", "Vendor lock-in", "Limited execution time"], + }, + { + id: "layered", + name: "Layered Architecture", + description: "Separation of concerns with distinct layers for different responsibilities", + icon: Database, + complexity: "Medium", + bestFor: "Business applications", + pros: ["Clear separation", "Easy to test", "Maintainable"], + cons: ["Performance overhead", "Tight coupling between layers"], + }, + ] + + const generateArchitecture = () => { + if (!selectedArchitecture || !projectName) return + + // Here you would typically call an API to generate the architecture + console.log(`Generating ${selectedArchitecture} architecture for ${projectName}`) + } + + return ( +
+
+ {/* Header */} +
+

Architecture Generator

+

+ Generate optimal architecture patterns for your project based on requirements and scale +

+
+ + {/* Project Name Input */} +
+ + setProjectName(e.target.value)} + className="text-center" + /> +
+ + {/* Architecture Patterns */} +
+ {architecturePatterns.map((pattern) => { + const Icon = pattern.icon + return ( + setSelectedArchitecture(pattern.id)} + > + +
+ +
+ {pattern.name} + + {pattern.complexity} Complexity + +
+ +

{pattern.description}

+
+

Best for:

+

{pattern.bestFor}

+
+
+
+ ) + })} +
+ + {/* Generate Button */} +
+ +
+ + {/* Selected Architecture Details */} + {selectedArchitecture && ( +
+ + + + + Architecture Details + + + + {(() => { + const pattern = architecturePatterns.find(p => p.id === selectedArchitecture) + if (!pattern) return null + + return ( +
+
+

+ + Advantages +

+
    + {pattern.pros.map((pro, index) => ( +
  • +
    + {pro} +
  • + ))} +
+
+
+

+ + Considerations +

+
    + {pattern.cons.map((con, index) => ( +
  • +
    + {con} +
  • + ))} +
+
+
+ ) + })()} +
+
+
+ )} +
+
+ ) +} diff --git a/src/components/auth/auth-page.tsx b/src/components/auth/auth-page.tsx new file mode 100644 index 0000000..5b23341 --- /dev/null +++ b/src/components/auth/auth-page.tsx @@ -0,0 +1,25 @@ +"use client" + +import { useState } from "react" +import { SignInForm } from "./signin-form" +import { SignUpForm } from "./signup-form" + +export function AuthPage() { + const [isSignIn, setIsSignIn] = useState(true) + + return ( +
+
+
+

Codenuk

+

AI-Powered Project Builder

+
+ {isSignIn ? ( + setIsSignIn(false)} /> + ) : ( + setIsSignIn(true)} /> + )} +
+
+ ) +} diff --git a/src/components/auth/signin-form.tsx b/src/components/auth/signin-form.tsx new file mode 100644 index 0000000..27314bd --- /dev/null +++ b/src/components/auth/signin-form.tsx @@ -0,0 +1,117 @@ +"use client" + +import type React from "react" + +import { useState } from "react" +import { useRouter } from "next/navigation" +import { Button } from "@/components/ui/button" +import { Input } from "@/components/ui/input" +import { Label } from "@/components/ui/label" +import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card" +import { Eye, EyeOff, Loader2 } from "lucide-react" +import { useAuth } from "@/contexts/auth-context" + +interface SignInFormProps { + onToggleMode: () => void +} + +export function SignInForm({ onToggleMode }: SignInFormProps) { + const [showPassword, setShowPassword] = useState(false) + const [isLoading, setIsLoading] = useState(false) + const [error, setError] = useState("") + const [formData, setFormData] = useState({ + email: "", + password: "", + }) + + const { login } = useAuth() + const router = useRouter() + + const handleSubmit = async (e: React.FormEvent) => { + e.preventDefault() + setError("") + setIsLoading(true) + + try { + const success = await login(formData.email, formData.password) + if (success) { + router.push("/") + } else { + setError("Invalid email or password") + } + } catch (err) { + setError("An error occurred. Please try again.") + } finally { + setIsLoading(false) + } + } + + return ( + + + Sign In + Enter your credentials to access your account + + +
+
+ + setFormData({ ...formData, email: e.target.value })} + required + /> +
+
+ +
+ setFormData({ ...formData, password: e.target.value })} + required + /> + +
+
+ + {/* Error Message */} + {error && ( +
+ {error} +
+ )} + + +
+ +
+
+
+
+ ) +} diff --git a/src/components/auth/signup-form.tsx b/src/components/auth/signup-form.tsx new file mode 100644 index 0000000..5f052fe --- /dev/null +++ b/src/components/auth/signup-form.tsx @@ -0,0 +1,159 @@ +"use client" + +import type React from "react" + +import { useState } from "react" +import { useRouter } from "next/navigation" +import { Button } from "@/components/ui/button" +import { Input } from "@/components/ui/input" +import { Label } from "@/components/ui/label" +import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card" +import { Eye, EyeOff, Loader2 } from "lucide-react" +import { useAuth } from "@/contexts/auth-context" + +interface SignUpFormProps { + onToggleMode: () => void +} + +export function SignUpForm({ onToggleMode }: SignUpFormProps) { + const [showPassword, setShowPassword] = useState(false) + const [showConfirmPassword, setShowConfirmPassword] = useState(false) + const [isLoading, setIsLoading] = useState(false) + const [error, setError] = useState("") + const [formData, setFormData] = useState({ + name: "", + email: "", + password: "", + confirmPassword: "", + }) + + const { signup } = useAuth() + const router = useRouter() + + const handleSubmit = async (e: React.FormEvent) => { + e.preventDefault() + setError("") + + if (formData.password !== formData.confirmPassword) { + setError("Passwords don't match") + return + } + + setIsLoading(true) + + try { + const success = await signup(formData.name, formData.email, formData.password) + if (success) { + router.push("/") + } else { + setError("Failed to create account. Please try again.") + } + } catch (err) { + setError("An error occurred. Please try again.") + } finally { + setIsLoading(false) + } + } + + return ( + + + Sign Up + Create your account to get started + + +
+
+ + setFormData({ ...formData, name: e.target.value })} + required + /> +
+
+ + setFormData({ ...formData, email: e.target.value })} + required + /> +
+
+ +
+ setFormData({ ...formData, password: e.target.value })} + required + /> + +
+
+
+ +
+ setFormData({ ...formData, confirmPassword: e.target.value })} + required + /> + +
+
+ + {/* Error Message */} + {error && ( +
+ {error} +
+ )} + + +
+ +
+
+
+
+ ) +} diff --git a/src/components/business-context/business-context-generator.tsx b/src/components/business-context/business-context-generator.tsx new file mode 100644 index 0000000..7c616b6 --- /dev/null +++ b/src/components/business-context/business-context-generator.tsx @@ -0,0 +1,546 @@ +"use client" + +import React from "react" + +import { useState } from "react" +import { Button } from "@/components/ui/button" +import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card" +import { Label } from "@/components/ui/label" +import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select" +import { Checkbox } from "@/components/ui/checkbox" +import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group" +import { Progress } from "@/components/ui/progress" +import { Badge } from "@/components/ui/badge" +import { Users, Server, DollarSign, Shield } from "lucide-react" + +interface BusinessContext { + userScale: { + expectedUsers: string + growthRate: string + peakTraffic: string + globalReach: boolean + } + technical: { + performance: string + availability: string + security: string[] + integrations: string[] + } + business: { + model: string + revenue: string + budget: string + timeline: string + } + operational: { + team: string + maintenance: string + monitoring: string[] + compliance: string[] + } +} + +export default function BusinessContextGenerator() { + const [currentSection, setCurrentSection] = useState(0) + const [context, setContext] = useState({ + userScale: { + expectedUsers: "", + growthRate: "", + peakTraffic: "", + globalReach: false, + }, + technical: { + performance: "", + availability: "", + security: [], + integrations: [], + }, + business: { + model: "", + revenue: "", + budget: "", + timeline: "", + }, + operational: { + team: "", + maintenance: "", + monitoring: [], + compliance: [], + }, + }) + + const sections = [ + { title: "User Scale & Growth", icon: Users, color: "bg-blue-500" }, + { title: "Technical Requirements", icon: Server, color: "bg-green-500" }, + { title: "Business Model", icon: DollarSign, color: "bg-purple-500" }, + { title: "Operational Context", icon: Shield, color: "bg-orange-500" }, + ] + + const progress = ((currentSection + 1) / sections.length) * 100 + + const updateContext = (section: keyof BusinessContext, field: string, value: any) => { + setContext((prev) => ({ + ...prev, + [section]: { + ...prev[section], + [field]: value, + }, + })) + } + + const toggleArrayValue = (section: keyof BusinessContext, field: string, value: string) => { + setContext((prev) => { + const currentArray = (prev[section] as any)[field] || [] + const newArray = currentArray.includes(value) + ? currentArray.filter((item: string) => item !== value) + : [...currentArray, value] + + return { + ...prev, + [section]: { + ...prev[section], + [field]: newArray, + }, + } + }) + } + + const renderUserScaleSection = () => ( +
+
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ updateContext("userScale", "globalReach", checked)} + /> + +
+
+ ) + + const renderTechnicalSection = () => ( +
+
+ + updateContext("technical", "performance", value)} + > +
+ + +
+
+ + +
+
+ + +
+
+
+ +
+ + updateContext("technical", "availability", value)} + > +
+ + +
+
+ + +
+
+ + +
+
+
+ +
+ +
+ {[ + "Authentication", + "Authorization", + "Data Encryption", + "GDPR Compliance", + "SOC2 Compliance", + "PCI Compliance", + ].map((security) => ( +
+ toggleArrayValue("technical", "security", security)} + /> + +
+ ))} +
+
+ +
+ +
+ {[ + "Payment Processing", + "Email Service", + "SMS Service", + "Analytics", + "CRM", + "Social Media", + "File Storage", + "CDN", + ].map((integration) => ( +
+ toggleArrayValue("technical", "integrations", integration)} + /> + +
+ ))} +
+
+
+ ) + + const renderBusinessSection = () => ( +
+
+ + updateContext("business", "model", value)}> +
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+
+ +
+ + +
+ +
+ + +
+ +
+ + +
+
+ ) + + const renderOperationalSection = () => ( +
+
+ + updateContext("operational", "team", value)} + > +
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+
+ +
+ + updateContext("operational", "maintenance", value)} + > +
+ + +
+
+ + +
+
+ + +
+
+
+ +
+ +
+ {[ + "Error Tracking", + "Performance Monitoring", + "User Analytics", + "Security Monitoring", + "Uptime Monitoring", + "Log Management", + ].map((monitoring) => ( +
+ toggleArrayValue("operational", "monitoring", monitoring)} + /> + +
+ ))} +
+
+ +
+ +
+ {["GDPR", "CCPA", "HIPAA", "SOX", "PCI DSS", "ISO 27001"].map((compliance) => ( +
+ toggleArrayValue("operational", "compliance", compliance)} + /> + +
+ ))} +
+
+
+ ) + + const renderSection = () => { + switch (currentSection) { + case 0: + return renderUserScaleSection() + case 1: + return renderTechnicalSection() + case 2: + return renderBusinessSection() + case 3: + return renderOperationalSection() + default: + return null + } + } + + return ( +
+
+
+

Business Context Generator

+

+ Help us understand your business requirements to generate the perfect architecture +

+
+ +
+
+ Progress + + {currentSection + 1} of {sections.length} + +
+ +
+ +
+ {sections.map((section, index) => { + const Icon = section.icon + return ( + setCurrentSection(index)} + > + +
+ +
+

{section.title}

+ {index < currentSection && ( + + Completed + + )} + {index === currentSection && Current} +
+
+ ) + })} +
+ + + + + {React.createElement(sections[currentSection].icon, { className: "w-5 h-5" })} + {sections[currentSection].title} + + + {currentSection === 0 && "Define your expected user base and growth patterns"} + {currentSection === 1 && "Specify technical performance and security requirements"} + {currentSection === 2 && "Outline your business model and financial expectations"} + {currentSection === 3 && "Configure operational and compliance requirements"} + + + {renderSection()} + + +
+ + +
+
+
+ ) +} diff --git a/src/components/features/features-page.tsx b/src/components/features/features-page.tsx new file mode 100644 index 0000000..039f5f5 --- /dev/null +++ b/src/components/features/features-page.tsx @@ -0,0 +1,684 @@ +"use client" + +import type React from "react" + +import { useState, useRef } from "react" +import Link from "next/link" +import { Button } from "@/components/ui/button" +import { Input } from "@/components/ui/input" +import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card" +import { Badge } from "@/components/ui/badge" +import { + Search, + Plus, + Trash2, + GripVertical, + Database, + Shield, + CreditCard, + BarChart3, + Bell, + Mail, + Globe, + Smartphone, + Zap, + Settings, + FileText, + ImageIcon, + Video, + MessageSquare, + Star, + Code, + Palette, + Layers, + Save, + Download, +} from "lucide-react" +import { ArrowRight } from "lucide-react" // Added import for ArrowRight + +interface Feature { + id: string + name: string + description: string + category: string + icon: any + complexity: number + timeImpact: string + dependencies: string[] + conflicts: string[] + techStack: string[] + businessQuestions: string[] + isCore?: boolean + isPopular?: boolean +} + +interface SelectedFeature extends Feature { + order: number + customConfig?: any +} + +export function FeaturesPage() { + const [activeTab, setActiveTab] = useState("browse") + const [selectedCategory, setSelectedCategory] = useState("all") + const [searchQuery, setSearchQuery] = useState("") + const [selectedFeatures, setSelectedFeatures] = useState([]) + const [draggedFeature, setDraggedFeature] = useState(null) + const [dragOverIndex, setDragOverIndex] = useState(null) + const dropZoneRef = useRef(null) + + const features: Feature[] = [ + // Core Features + { + id: "user-auth", + name: "User Authentication", + description: "Secure user registration, login, and session management", + category: "core", + icon: Shield, + complexity: 3, + timeImpact: "2-3 days", + dependencies: [], + conflicts: [], + techStack: ["NextAuth.js", "JWT", "OAuth"], + businessQuestions: [ + "How many users do you expect in the first year?", + "Do you need social login (Google, Facebook)?", + "Will you have different user roles?", + ], + isCore: true, + isPopular: true, + }, + { + id: "database", + name: "Database Integration", + description: "Data storage and management system", + category: "core", + icon: Database, + complexity: 4, + timeImpact: "3-5 days", + dependencies: [], + conflicts: [], + techStack: ["PostgreSQL", "Prisma", "Redis"], + businessQuestions: [ + "What's your expected data volume?", + "Do you need real-time data updates?", + "What's your data backup strategy?", + ], + isCore: true, + isPopular: true, + }, + { + id: "api-management", + name: "API Management", + description: "RESTful API with rate limiting and documentation", + category: "core", + icon: Code, + complexity: 3, + timeImpact: "2-4 days", + dependencies: ["database"], + conflicts: [], + techStack: ["Next.js API Routes", "Swagger", "Rate Limiting"], + businessQuestions: [ + "Will you have external API integrations?", + "Do you need API versioning?", + "What's your expected API call volume?", + ], + isCore: true, + }, + + // Business Features + { + id: "payment-processing", + name: "Payment Processing", + description: "Secure payment handling with multiple providers", + category: "business", + icon: CreditCard, + complexity: 5, + timeImpact: "1-2 weeks", + dependencies: ["user-auth", "database"], + conflicts: [], + techStack: ["Stripe", "PayPal", "Webhook Handling"], + businessQuestions: [ + "What payment methods do you need?", + "What's your expected transaction volume?", + "Do you need subscription billing?", + ], + isPopular: true, + }, + { + id: "analytics", + name: "Analytics & Tracking", + description: "User behavior tracking and business metrics", + category: "business", + icon: BarChart3, + complexity: 3, + timeImpact: "2-3 days", + dependencies: [], + conflicts: [], + techStack: ["Google Analytics", "Mixpanel", "Custom Events"], + businessQuestions: [ + "What metrics are most important to track?", + "Do you need real-time analytics?", + "What's your privacy policy regarding data?", + ], + isPopular: true, + }, + { + id: "notifications", + name: "Notification System", + description: "Email, SMS, and push notifications", + category: "business", + icon: Bell, + complexity: 4, + timeImpact: "3-5 days", + dependencies: ["user-auth"], + conflicts: [], + techStack: ["SendGrid", "Twilio", "Push API"], + businessQuestions: [ + "What types of notifications do you need?", + "How frequently will you send notifications?", + "Do you need notification preferences?", + ], + }, + + // UI/UX Features + { + id: "responsive-design", + name: "Responsive Design", + description: "Mobile-first responsive layout", + category: "ui", + icon: Smartphone, + complexity: 2, + timeImpact: "1-2 days", + dependencies: [], + conflicts: [], + techStack: ["Tailwind CSS", "CSS Grid", "Flexbox"], + businessQuestions: ["What devices will your users primarily use?", "Do you need a mobile app later?"], + isCore: true, + }, + { + id: "dark-mode", + name: "Dark Mode", + description: "Toggle between light and dark themes", + category: "ui", + icon: Palette, + complexity: 2, + timeImpact: "1 day", + dependencies: ["responsive-design"], + conflicts: [], + techStack: ["CSS Variables", "Theme Provider"], + businessQuestions: ["Is this important for your user base?"], + }, + { + id: "animations", + name: "Animations & Transitions", + description: "Smooth animations and micro-interactions", + category: "ui", + icon: Zap, + complexity: 3, + timeImpact: "2-3 days", + dependencies: ["responsive-design"], + conflicts: [], + techStack: ["Framer Motion", "CSS Animations"], + businessQuestions: ["What's your performance priority?"], + }, + + // Content Features + { + id: "content-management", + name: "Content Management", + description: "CMS for managing dynamic content", + category: "content", + icon: FileText, + complexity: 4, + timeImpact: "1 week", + dependencies: ["database"], + conflicts: [], + techStack: ["Sanity", "Strapi", "MDX"], + businessQuestions: ["Who will manage content?", "How often will content change?"], + }, + { + id: "media-upload", + name: "Media Upload", + description: "File and image upload with optimization", + category: "content", + icon: ImageIcon, // Updated from Image to ImageIcon + complexity: 3, + timeImpact: "2-3 days", + dependencies: ["database"], + conflicts: [], + techStack: ["Cloudinary", "AWS S3", "Image Optimization"], + businessQuestions: ["What file types do you need?", "What's your storage budget?"], + }, + { + id: "video-streaming", + name: "Video Streaming", + description: "Video upload and streaming capabilities", + category: "content", + icon: Video, + complexity: 5, + timeImpact: "1-2 weeks", + dependencies: ["media-upload"], + conflicts: [], + techStack: ["Vimeo API", "YouTube API", "Video.js"], + businessQuestions: ["What video quality do you need?", "Expected video volume?"], + }, + + // Communication Features + { + id: "chat-system", + name: "Real-time Chat", + description: "Live messaging and communication", + category: "communication", + icon: MessageSquare, + complexity: 4, + timeImpact: "1 week", + dependencies: ["user-auth", "database"], + conflicts: [], + techStack: ["WebSockets", "Socket.io", "Real-time DB"], + businessQuestions: ["How many concurrent users?", "Do you need group chats?"], + }, + { + id: "email-integration", + name: "Email Integration", + description: "Email sending and template management", + category: "communication", + icon: Mail, + complexity: 3, + timeImpact: "2-3 days", + dependencies: [], + conflicts: [], + techStack: ["SendGrid", "Mailgun", "Email Templates"], + businessQuestions: ["What types of emails will you send?", "Expected email volume?"], + }, + + // Advanced Features + { + id: "ai-integration", + name: "AI Integration", + description: "Machine learning and AI-powered features", + category: "advanced", + icon: Layers, + complexity: 5, + timeImpact: "1-3 weeks", + dependencies: ["api-management"], + conflicts: [], + techStack: ["OpenAI API", "TensorFlow", "Custom Models"], + businessQuestions: ["What AI capabilities do you need?", "What's your AI budget?", "Do you have training data?"], + }, + { + id: "real-time", + name: "Real-time Features", + description: "Live updates and collaboration", + category: "advanced", + icon: Zap, + complexity: 4, + timeImpact: "1 week", + dependencies: ["database"], + conflicts: [], + techStack: ["WebSockets", "Socket.io", "Redis Pub/Sub"], + businessQuestions: ["How many concurrent users?", "What needs to be real-time?"], + }, + ] + + const categories = [ + { id: "all", name: "All Features", icon: Globe, count: features.length }, + { id: "core", name: "Core", icon: Settings, count: features.filter((f) => f.category === "core").length }, + { + id: "business", + name: "Business", + icon: BarChart3, + count: features.filter((f) => f.category === "business").length, + }, + { id: "ui", name: "UI/UX", icon: Palette, count: features.filter((f) => f.category === "ui").length }, + { id: "content", name: "Content", icon: FileText, count: features.filter((f) => f.category === "content").length }, + { + id: "communication", + name: "Communication", + icon: MessageSquare, + count: features.filter((f) => f.category === "communication").length, + }, + { + id: "advanced", + name: "Advanced", + icon: Layers, + count: features.filter((f) => f.category === "advanced").length, + }, + ] + + const filteredFeatures = features.filter((feature) => { + const matchesCategory = selectedCategory === "all" || feature.category === selectedCategory + const matchesSearch = + feature.name.toLowerCase().includes(searchQuery.toLowerCase()) || + feature.description.toLowerCase().includes(searchQuery.toLowerCase()) + const notAlreadySelected = !selectedFeatures.some((sf) => sf.id === feature.id) + return matchesCategory && matchesSearch && notAlreadySelected + }) + + const getComplexityColor = (complexity: number) => { + if (complexity <= 2) return "bg-green-100 text-green-800" + if (complexity <= 3) return "bg-yellow-100 text-yellow-800" + return "bg-red-100 text-red-800" + } + + const getComplexityLabel = (complexity: number) => { + if (complexity <= 2) return "Simple" + if (complexity <= 3) return "Moderate" + return "Complex" + } + + const handleDragStart = (feature: Feature) => { + setDraggedFeature(feature) + } + + const handleDragOver = (e: React.DragEvent, index?: number) => { + e.preventDefault() + if (typeof index === "number") { + setDragOverIndex(index) + } + } + + const handleDrop = (e: React.DragEvent, index?: number) => { + e.preventDefault() + if (!draggedFeature) return + + const newFeature: SelectedFeature = { + ...draggedFeature, + order: typeof index === "number" ? index : selectedFeatures.length, + } + + if (typeof index === "number") { + const newFeatures = [...selectedFeatures] + newFeatures.splice(index, 0, newFeature) + // Update order for all features + newFeatures.forEach((f, i) => (f.order = i)) + setSelectedFeatures(newFeatures) + } else { + setSelectedFeatures([...selectedFeatures, newFeature]) + } + + setDraggedFeature(null) + setDragOverIndex(null) + } + + const removeFeature = (featureId: string) => { + setSelectedFeatures(selectedFeatures.filter((f) => f.id !== featureId)) + } + + const reorderFeatures = (fromIndex: number, toIndex: number) => { + const newFeatures = [...selectedFeatures] + const [movedFeature] = newFeatures.splice(fromIndex, 1) + newFeatures.splice(toIndex, 0, movedFeature) + // Update order for all features + newFeatures.forEach((f, i) => (f.order = i)) + setSelectedFeatures(newFeatures) + } + + const calculateTotalComplexity = () => { + return selectedFeatures.reduce((total, feature) => total + feature.complexity, 0) + } + + const calculateEstimatedTime = () => { + const totalDays = selectedFeatures.reduce((total, feature) => { + const days = feature.timeImpact.match(/(\d+)/g)?.map(Number) || [1] + return total + Math.max(...days) + }, 0) + + if (totalDays < 7) return `${totalDays} days` + if (totalDays < 30) return `${Math.ceil(totalDays / 7)} weeks` + return `${Math.ceil(totalDays / 30)} months` + } + + const FeatureCard = ({ feature, isDraggable = true }: { feature: Feature; isDraggable?: boolean }) => { + const Icon = feature.icon + return ( + isDraggable && handleDragStart(feature)} + > + +
+
+
+ +
+
+ {feature.name} +
+ + {getComplexityLabel(feature.complexity)} + + {feature.isCore && Core} + {feature.isPopular && ( + + + Popular + + )} +
+
+
+ {isDraggable && } +
+

{feature.description}

+
+ + +
+ Time Impact: {feature.timeImpact} + Complexity: {feature.complexity}/5 +
+ +
+

Tech Stack:

+
+ {feature.techStack.slice(0, 3).map((tech, index) => ( + + {tech} + + ))} + {feature.techStack.length > 3 && ( + + +{feature.techStack.length - 3} + + )} +
+
+ + {feature.dependencies.length > 0 && ( +
+ Dependencies: + + {feature.dependencies + .map((depId) => { + const dep = features.find((f) => f.id === depId) + return dep?.name + }) + .join(", ")} + +
+ )} +
+
+ ) + } + + const SelectedFeatureCard = ({ feature, index }: { feature: SelectedFeature; index: number }) => { + const Icon = feature.icon + return ( + handleDragStart(feature)} + onDragOver={(e) => handleDragOver(e, index)} + onDrop={(e) => handleDrop(e, index)} + > + +
+
+ +
+ +
+
+

{feature.name}

+

{feature.timeImpact}

+
+
+
+ {feature.complexity} + +
+
+
+
+ ) + } + + return ( +
+ +
+
+ {/* Features Library */} +
+
+

Features Library

+
+
+ + setSearchQuery(e.target.value)} + className="pl-10 w-80" + /> +
+
+
+ + {/* Category Filters */} +
+ {categories.map((category) => { + const Icon = category.icon + return ( + + ) + })} +
+ + {/* Features Grid */} +
+ {filteredFeatures.map((feature) => ( + + ))} +
+
+ + {/* Selected Features Panel */} +
+ + + + Selected Features + {selectedFeatures.length} + +

Drag features here to build your project

+
+ + {/* Project Summary */} +
+
+ Total Complexity: + 20 + ? "destructive" + : calculateTotalComplexity() > 15 + ? "default" + : "secondary" + } + > + {calculateTotalComplexity()}/50 + +
+
+ Estimated Time: + {calculateEstimatedTime()} +
+
+ + {/* Drop Zone */} +
+ {selectedFeatures.length === 0 ? ( +
+ +

+ Drag features from the library to start building your project +

+
+ ) : ( +
+ {selectedFeatures + .sort((a, b) => a.order - b.order) + .map((feature, index) => ( + + ))} +
+ )} +
+ + {/* Actions */} + {selectedFeatures.length > 0 && ( +
+ + +
+ )} +
+
+
+
+
+
+ ) +} diff --git a/src/components/layout/app-layout.tsx b/src/components/layout/app-layout.tsx new file mode 100644 index 0000000..511211d --- /dev/null +++ b/src/components/layout/app-layout.tsx @@ -0,0 +1,49 @@ +"use client" + +import { useAuth } from "@/contexts/auth-context" +import Header from "@/components/navigation/header" +import { usePathname } from "next/navigation" + +interface AppLayoutProps { + children: React.ReactNode +} + +export function AppLayout({ children }: AppLayoutProps) { + const { isAuthenticated, isLoading } = useAuth() + const pathname = usePathname() + + // Don't show header on auth pages + const isAuthPage = pathname === "/auth" + + // Show loading state while checking auth + if (isLoading) { + return ( +
+
+
+ ) + } + + // For auth pages, don't show header + if (isAuthPage) { + return <>{children} + } + + // For authenticated users on other pages, show header + if (isAuthenticated) { + return ( + <> +
+ {children} + + ) + } + + // For unauthenticated users on non-auth pages, redirect to auth + return ( + <> +
+ {children} + + ) +} diff --git a/src/components/main-dashboard.tsx b/src/components/main-dashboard.tsx new file mode 100644 index 0000000..472a05f --- /dev/null +++ b/src/components/main-dashboard.tsx @@ -0,0 +1,806 @@ +"use client" + +import { useState } from "react" +import Link from "next/link" +import { Button } from "@/components/ui/button" +import { Input } from "@/components/ui/input" +import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card" +import { Badge } from "@/components/ui/badge" +import { ArrowRight, Plus, Globe, BarChart3, Zap, Code, Search, Star, Clock, Users, Layers } from "lucide-react" + +interface Template { + id: string + title: string + description: string + category: string + features: string[] + complexity: number + timeEstimate: string + techStack: string[] + popularity?: number + lastUpdated?: string +} + +function TemplateSelectionStep({ onNext }: { onNext: (template: Template) => void }) { + const [selectedCategory, setSelectedCategory] = useState("all") + const [searchQuery, setSearchQuery] = useState("") + + const templates: Template[] = [ + // Marketing Templates (10) + { + id: "marketing-website", + title: "Marketing Website", + description: "Professional marketing site with CMS and lead generation", + category: "marketing", + features: ["Content Management", "Contact Forms", "SEO Optimization", "Analytics Integration"], + complexity: 2, + timeEstimate: "1-2 weeks", + techStack: ["Next.js", "Sanity CMS", "Tailwind CSS", "Vercel"], + popularity: 95, + lastUpdated: "2024-01-15", + }, + { + id: "landing-page", + title: "Landing Page", + description: "High-converting landing page with A/B testing capabilities", + category: "marketing", + features: ["A/B Testing", "Conversion Tracking", "Lead Capture", "Mobile Optimization"], + complexity: 2, + timeEstimate: "3-5 days", + techStack: ["Next.js", "Tailwind CSS", "Google Analytics", "Mailchimp"], + popularity: 88, + lastUpdated: "2024-01-10", + }, + { + id: "blog-platform", + title: "Blog Platform", + description: "Content-rich blog with SEO optimization and social sharing", + category: "marketing", + features: ["Content Management", "SEO Tools", "Social Sharing", "Comment System"], + complexity: 3, + timeEstimate: "1-2 weeks", + techStack: ["Next.js", "MDX", "Tailwind CSS", "Disqus"], + popularity: 82, + lastUpdated: "2024-01-12", + }, + { + id: "portfolio-site", + title: "Portfolio Website", + description: "Personal or agency portfolio with project showcase", + category: "marketing", + features: ["Project Gallery", "Contact Forms", "Blog", "Responsive Design"], + complexity: 2, + timeEstimate: "1-2 weeks", + techStack: ["Next.js", "MDX", "Tailwind CSS", "Framer Motion"], + popularity: 79, + lastUpdated: "2024-01-08", + }, + { + id: "agency-website", + title: "Agency Website", + description: "Full-service agency site with team profiles and case studies", + category: "marketing", + features: ["Team Profiles", "Case Studies", "Service Pages", "Client Testimonials"], + complexity: 3, + timeEstimate: "2-3 weeks", + techStack: ["Next.js", "Strapi", "Tailwind CSS", "Framer Motion"], + popularity: 76, + lastUpdated: "2024-01-14", + }, + { + id: "event-website", + title: "Event Website", + description: "Event promotion site with registration and ticketing", + category: "marketing", + features: ["Event Registration", "Ticketing", "Speaker Profiles", "Schedule Management"], + complexity: 4, + timeEstimate: "2-3 weeks", + techStack: ["Next.js", "Stripe", "Calendar API", "Email Integration"], + popularity: 73, + lastUpdated: "2024-01-11", + }, + { + id: "restaurant-website", + title: "Restaurant Website", + description: "Restaurant site with menu, reservations, and online ordering", + category: "marketing", + features: ["Menu Display", "Online Reservations", "Order System", "Location Info"], + complexity: 3, + timeEstimate: "1-2 weeks", + techStack: ["Next.js", "Reservation API", "Payment Processing", "Google Maps"], + popularity: 70, + lastUpdated: "2024-01-09", + }, + { + id: "nonprofit-website", + title: "Nonprofit Website", + description: "Nonprofit organization site with donation and volunteer management", + category: "marketing", + features: ["Donation Processing", "Volunteer Registration", "Event Management", "Impact Tracking"], + complexity: 3, + timeEstimate: "2-3 weeks", + techStack: ["Next.js", "Stripe", "Volunteer API", "Analytics"], + popularity: 67, + lastUpdated: "2024-01-13", + }, + { + id: "real-estate-website", + title: "Real Estate Website", + description: "Property listing site with search and contact features", + category: "marketing", + features: ["Property Listings", "Search Filters", "Contact Forms", "Virtual Tours"], + complexity: 4, + timeEstimate: "2-4 weeks", + techStack: ["Next.js", "Property API", "Map Integration", "Image Gallery"], + popularity: 64, + lastUpdated: "2024-01-07", + }, + { + id: "personal-brand", + title: "Personal Brand Site", + description: "Personal branding site for professionals and creators", + category: "marketing", + features: ["About Page", "Services", "Testimonials", "Contact Integration"], + complexity: 2, + timeEstimate: "1 week", + techStack: ["Next.js", "Tailwind CSS", "Contact Forms", "Social Links"], + popularity: 61, + lastUpdated: "2024-01-06", + }, + + // Software Templates (10) + { + id: "saas-platform", + title: "SaaS Platform", + description: "Complete SaaS application with user management, billing, and analytics", + category: "software", + features: ["User Authentication", "Payment Processing", "Analytics Integration", "API Management"], + complexity: 5, + timeEstimate: "4-6 weeks", + techStack: ["Next.js", "PostgreSQL", "Stripe", "NextAuth.js"], + popularity: 92, + lastUpdated: "2024-01-15", + }, + { + id: "dashboard-app", + title: "Analytics Dashboard", + description: "Data visualization dashboard with real-time updates", + category: "software", + features: ["Data Visualization", "Real-time Updates", "User Authentication", "Export Features"], + complexity: 4, + timeEstimate: "3-4 weeks", + techStack: ["Next.js", "Chart.js", "WebSockets", "PostgreSQL"], + popularity: 89, + lastUpdated: "2024-01-14", + }, + { + id: "mobile-app", + title: "Mobile App (PWA)", + description: "Progressive web app with mobile-first design", + category: "software", + features: ["Offline Support", "Push Notifications", "Mobile Optimization", "App Install"], + complexity: 4, + timeEstimate: "2-3 weeks", + techStack: ["Next.js", "PWA", "Service Workers", "Push API"], + popularity: 86, + lastUpdated: "2024-01-13", + }, + { + id: "project-management", + title: "Project Management Tool", + description: "Team collaboration and project tracking application", + category: "software", + features: ["Task Management", "Team Collaboration", "Time Tracking", "Reporting"], + complexity: 5, + timeEstimate: "4-5 weeks", + techStack: ["Next.js", "PostgreSQL", "Real-time Updates", "File Upload"], + popularity: 83, + lastUpdated: "2024-01-12", + }, + { + id: "crm-system", + title: "CRM System", + description: "Customer relationship management with sales pipeline", + category: "software", + features: ["Contact Management", "Sales Pipeline", "Email Integration", "Reporting"], + complexity: 5, + timeEstimate: "3-5 weeks", + techStack: ["Next.js", "PostgreSQL", "Email API", "Calendar Integration"], + popularity: 80, + lastUpdated: "2024-01-11", + }, + { + id: "inventory-management", + title: "Inventory Management", + description: "Stock tracking and warehouse management system", + category: "software", + features: ["Stock Tracking", "Barcode Scanning", "Supplier Management", "Reports"], + complexity: 4, + timeEstimate: "3-4 weeks", + techStack: ["Next.js", "PostgreSQL", "Barcode API", "PDF Generation"], + popularity: 77, + lastUpdated: "2024-01-10", + }, + { + id: "learning-platform", + title: "Learning Management System", + description: "Online education platform with courses and assessments", + category: "software", + features: ["Course Management", "Video Streaming", "Assessments", "Progress Tracking"], + complexity: 5, + timeEstimate: "4-6 weeks", + techStack: ["Next.js", "Video API", "PostgreSQL", "Payment Processing"], + popularity: 74, + lastUpdated: "2024-01-09", + }, + { + id: "booking-system", + title: "Booking System", + description: "Appointment and reservation management platform", + category: "software", + features: ["Calendar Integration", "Payment Processing", "Notifications", "Customer Management"], + complexity: 4, + timeEstimate: "2-4 weeks", + techStack: ["Next.js", "Calendar API", "Stripe", "Email Integration"], + popularity: 71, + lastUpdated: "2024-01-08", + }, + { + id: "chat-application", + title: "Chat Application", + description: "Real-time messaging platform with file sharing", + category: "software", + features: ["Real-time Messaging", "File Sharing", "Group Chats", "User Presence"], + complexity: 4, + timeEstimate: "2-3 weeks", + techStack: ["Next.js", "WebSockets", "File Storage", "Real-time DB"], + popularity: 68, + lastUpdated: "2024-01-07", + }, + { + id: "api-platform", + title: "API Platform", + description: "RESTful API with documentation and rate limiting", + category: "software", + features: ["API Documentation", "Rate Limiting", "Authentication", "Monitoring"], + complexity: 4, + timeEstimate: "2-3 weeks", + techStack: ["Next.js", "Swagger", "Redis", "Monitoring Tools"], + popularity: 65, + lastUpdated: "2024-01-06", + }, + + // SEO Templates (10) + { + id: "seo-optimized-blog", + title: "SEO-Optimized Blog", + description: "Blog platform with advanced SEO features and schema markup", + category: "seo", + features: ["Schema Markup", "Meta Optimization", "Sitemap Generation", "Performance Optimization"], + complexity: 3, + timeEstimate: "2-3 weeks", + techStack: ["Next.js", "SEO Tools", "Schema.org", "Google Search Console"], + popularity: 90, + lastUpdated: "2024-01-15", + }, + { + id: "local-business-site", + title: "Local Business Website", + description: "Local SEO optimized site with Google My Business integration", + category: "seo", + features: ["Local SEO", "Google My Business", "Review Management", "Location Pages"], + complexity: 3, + timeEstimate: "1-2 weeks", + techStack: ["Next.js", "Google APIs", "Review APIs", "Local Schema"], + popularity: 87, + lastUpdated: "2024-01-14", + }, + { + id: "ecommerce-seo", + title: "E-commerce SEO Site", + description: "Product-focused e-commerce with advanced SEO optimization", + category: "seo", + features: ["Product Schema", "Category Optimization", "Review Rich Snippets", "Performance"], + complexity: 4, + timeEstimate: "3-4 weeks", + techStack: ["Next.js", "Product APIs", "Review Systems", "CDN"], + popularity: 84, + lastUpdated: "2024-01-13", + }, + { + id: "news-website", + title: "News Website", + description: "News platform with article SEO and AMP support", + category: "seo", + features: ["Article Schema", "AMP Support", "Breaking News", "Social Sharing"], + complexity: 4, + timeEstimate: "2-4 weeks", + techStack: ["Next.js", "AMP", "News APIs", "Social APIs"], + popularity: 81, + lastUpdated: "2024-01-12", + }, + { + id: "directory-website", + title: "Business Directory", + description: "Local business directory with search and listings", + category: "seo", + features: ["Business Listings", "Search Optimization", "Category Pages", "Review System"], + complexity: 4, + timeEstimate: "3-4 weeks", + techStack: ["Next.js", "Search APIs", "Location Services", "Review APIs"], + popularity: 78, + lastUpdated: "2024-01-11", + }, + { + id: "recipe-website", + title: "Recipe Website", + description: "Recipe platform with rich snippets and cooking schema", + category: "seo", + features: ["Recipe Schema", "Nutrition Info", "Cooking Times", "User Ratings"], + complexity: 3, + timeEstimate: "2-3 weeks", + techStack: ["Next.js", "Recipe APIs", "Nutrition APIs", "Rating System"], + popularity: 75, + lastUpdated: "2024-01-10", + }, + { + id: "job-board", + title: "Job Board", + description: "Job listing platform with structured data for search engines", + category: "seo", + features: ["Job Schema", "Search Filters", "Application Tracking", "Company Profiles"], + complexity: 4, + timeEstimate: "3-4 weeks", + techStack: ["Next.js", "Job APIs", "Application System", "Company APIs"], + popularity: 72, + lastUpdated: "2024-01-09", + }, + { + id: "review-website", + title: "Review Website", + description: "Product/service review platform with rich snippets", + category: "seo", + features: ["Review Schema", "Rating System", "Comparison Tools", "User Profiles"], + complexity: 4, + timeEstimate: "2-4 weeks", + techStack: ["Next.js", "Review APIs", "Rating System", "Comparison Tools"], + popularity: 69, + lastUpdated: "2024-01-08", + }, + { + id: "travel-website", + title: "Travel Website", + description: "Travel guide with location-based SEO and booking integration", + category: "seo", + features: ["Location Schema", "Travel Guides", "Booking Integration", "Photo Galleries"], + complexity: 4, + timeEstimate: "3-4 weeks", + techStack: ["Next.js", "Travel APIs", "Booking APIs", "Map Integration"], + popularity: 66, + lastUpdated: "2024-01-07", + }, + { + id: "healthcare-website", + title: "Healthcare Website", + description: "Medical practice website with health-focused SEO", + category: "seo", + features: ["Medical Schema", "Appointment Booking", "Health Articles", "Doctor Profiles"], + complexity: 3, + timeEstimate: "2-3 weeks", + techStack: ["Next.js", "Medical APIs", "Booking System", "Content Management"], + popularity: 63, + lastUpdated: "2024-01-06", + }, + ] + + const categories = [ + { id: "all", name: "All Templates", icon: Globe, count: templates.length }, + { + id: "marketing", + name: "Marketing & Branding", + icon: Zap, + count: templates.filter((t) => t.category === "marketing").length, + }, + { + id: "software", + name: "Software & Tools", + icon: Code, + count: templates.filter((t) => t.category === "software").length, + }, + { id: "seo", name: "SEO & Content", icon: BarChart3, count: templates.filter((t) => t.category === "seo").length }, + ] + + const filteredTemplates = templates.filter((template) => { + const matchesCategory = selectedCategory === "all" || template.category === selectedCategory + const matchesSearch = + template.title.toLowerCase().includes(searchQuery.toLowerCase()) || + template.description.toLowerCase().includes(searchQuery.toLowerCase()) || + template.features.some((feature) => feature.toLowerCase().includes(searchQuery.toLowerCase())) + return matchesCategory && matchesSearch + }) + + const getComplexityColor = (complexity: number) => { + if (complexity <= 2) return "bg-green-100 text-green-800" + if (complexity <= 3) return "bg-yellow-100 text-yellow-800" + return "bg-red-100 text-red-800" + } + + const getComplexityLabel = (complexity: number) => { + if (complexity <= 2) return "Simple" + if (complexity <= 3) return "Moderate" + return "Complex" + } + + return ( +
+ {/* Header */} +
+

Choose Your Project Template

+

+ Select from our comprehensive library of professionally designed templates +

+
+ + {/* Search and Filter */} +
+
+ + setSearchQuery(e.target.value)} + className="pl-10 h-12 text-lg border-2 border-gray-200 hover:border-blue-300 focus:border-blue-500 focus:ring-2 focus:ring-blue-200 rounded-xl shadow-sm transition-all duration-300" + /> +
+ + {/* Category Filters */} +
+ {categories.map((category) => { + const Icon = category.icon + return ( + + ) + })} +
+
+ + {/* Templates Grid */} +
+ {filteredTemplates.map((template) => ( + + {/* Card Header with gradient background */} +
+
+
+ + {template.title} + +
+ + {getComplexityLabel(template.complexity)} + + {template.popularity && ( +
+ + {template.popularity}% +
+ )} +
+
+
+

{template.description}

+
+ + +
+ {/* Stats Row */} +
+
+ + {template.timeEstimate} +
+
+ + {template.features.length} features +
+
+ + {/* Features Section */} +
+
+

+ + Key Features +

+
+ {template.features.slice(0, 3).map((feature, index) => ( + + {feature} + + ))} + {template.features.length > 3 && ( + + +{template.features.length - 3} more + + )} +
+
+ + {/* Tech Stack Section */} +
+

+ + Tech Stack +

+
+ {template.techStack.slice(0, 3).map((tech, index) => ( + + {tech} + + ))} + {template.techStack.length > 3 && ( + + +{template.techStack.length - 3} + + )} +
+
+
+
+ + {/* Action Button - Always at bottom */} +
+ +
+
+
+ ))} +
+ + {/* Custom Template Option */} + + +
+ +
+

Create Custom Template

+

+ Don't see what you need? Create a custom project type with your specific requirements and tech stack. +

+ +
+
+ + {/* Results Summary */} + {searchQuery && ( +
+

+ Showing {filteredTemplates.length} template{filteredTemplates.length !== 1 ? "s" : ""} + {searchQuery && ` matching "${searchQuery}"`} +

+
+ )} +
+ ) +} + +// Feature Selection Step Component +function FeatureSelectionStep({ + template, + onNext, + onBack, +}: { template: Template; onNext: () => void; onBack: () => void }) { + return ( +
+ {/* Header */} +
+

Select Features for {template.title}

+

+ Choose the features that best fit your project requirements. +

+
+ + {/* Features List */} +
+ {template.features.map((feature, index) => ( + + + + {feature} + + + + +

+ This feature enhances your project with {feature} capabilities. +

+
+
+ ))} +
+ + {/* Navigation Buttons */} +
+
+ + +
+
+
+ ) +} + +// Main Dashboard Component +export function MainDashboard() { + const [currentStep, setCurrentStep] = useState(1) + const [selectedTemplate, setSelectedTemplate] = useState