Compare commits

..

5 Commits

Author SHA1 Message Date
1c6627bdfb feat: added pages, forms, and functionality.
All checks were successful
Smart Deploy / build-deploy (push) Successful in 2m34s
2026-02-08 21:11:57 +05:30
3fb4c5bbe0 chore: Sync lockfile with dependencies
All checks were successful
Smart Deploy / build-deploy (push) Successful in 2m2s
2026-02-08 18:34:49 +05:30
687563b5c5 modified deploy file
Some checks failed
Smart Deploy / build-deploy (push) Failing after 42s
2026-02-08 18:31:41 +05:30
0fea70273f modified deploy file
Some checks failed
Smart Deploy / build-deploy (push) Failing after 58s
2026-02-08 18:28:10 +05:30
7c54332b09 fodler change 2026-02-08 18:22:05 +05:30
42 changed files with 6714 additions and 37 deletions

View File

@@ -5,10 +5,14 @@ on: [push]
jobs: jobs:
build-deploy: build-deploy:
runs-on: ubuntu-latest runs-on: ubuntu-latest
# 👇 ADD THIS LINE! It gives the runner a brain (Node.js + Git)
container: node:20-bookworm
steps: steps:
- name: Check out repository code - name: Check out repository code
uses: actions/checkout@v3 uses: actions/checkout@v3
# You can keep this, but the container already has Node 20!
- name: Install Node.js - name: Install Node.js
uses: actions/setup-node@v3 uses: actions/setup-node@v3
with: with:
@@ -19,27 +23,13 @@ jobs:
- name: Build Astro Site - name: Build Astro Site
run: npm run build run: npm run build
# env:
# PUBLIC_API_URL: ${{ secrets.PUBLIC_API_URL }}
# ---------------------------------------------------------
# CASE 1: PRODUCTION (Main Branch)
# ---------------------------------------------------------
- name: Deploy to Production - name: Deploy to Production
if: gitea.ref == 'refs/heads/main' if: gitea.ref == 'refs/heads/main'
run: npx netlify-cli deploy --prod --dir=dist --site=${{ secrets.NETLIFY_SITE_ID }} --auth=${{ secrets.NETLIFY_AUTH_TOKEN }} --message "Prod: ${{ gitea.sha }}" run: npx netlify-cli deploy --prod --dir=dist --site=${{ secrets.NETLIFY_SITE_ID }} --auth=${{ secrets.NETLIFY_AUTH_TOKEN }} --message "Prod ${{ gitea.sha }}"
# --------------------------------------------------------- - name: Deploy Preview
# CASE 2: PREVIEW (Any other branch)
# ---------------------------------------------------------
- name: Deploy Preview with Subdomain
if: gitea.ref != 'refs/heads/main' if: gitea.ref != 'refs/heads/main'
run: | run: |
# 1. Get the branch name (e.g., 'feature/login')
# 2. Replace slashes with dashes (e.g., 'feature-login') because URLs can't have slashes
ALIAS=$(echo "${{ gitea.ref_name }}" | tr / -) ALIAS=$(echo "${{ gitea.ref_name }}" | tr / -)
npx netlify-cli deploy --dir=dist --alias "$ALIAS" --site=${{ secrets.NETLIFY_SITE_ID }} --auth=${{ secrets.NETLIFY_AUTH_TOKEN }} --message "Preview $ALIAS"
echo "Deploying to alias: $ALIAS"
# 3. Deploy with the --alias flag
npx netlify-cli deploy --dir=dist --alias "$ALIAS" --site=${{ secrets.NETLIFY_SITE_ID }} --auth=${{ secrets.NETLIFY_AUTH_TOKEN }} --message "Preview: $ALIAS"

View File

@@ -1,5 +1,6 @@
// @ts-check // @ts-check
import { defineConfig } from 'astro/config'; import { defineConfig } from 'astro/config';
import react from '@astrojs/react';
import tailwindcss from '@tailwindcss/vite'; import tailwindcss from '@tailwindcss/vite';
import netlify from '@astrojs/netlify'; import netlify from '@astrojs/netlify';
@@ -10,5 +11,6 @@ export default defineConfig({
plugins: [tailwindcss()] plugins: [tailwindcss()]
}, },
integrations: [react()],
adapter: netlify() adapter: netlify()
}); });

627
package-lock.json generated
View File

@@ -9,9 +9,17 @@
"version": "0.0.1", "version": "0.0.1",
"dependencies": { "dependencies": {
"@astrojs/netlify": "^6.6.4", "@astrojs/netlify": "^6.6.4",
"@astrojs/react": "^4.4.2",
"@tailwindcss/vite": "^4.1.18", "@tailwindcss/vite": "^4.1.18",
"astro": "^5.17.1", "astro": "^5.17.1",
"tailwindcss": "^4.1.18" "clsx": "^2.1.1",
"framer-motion": "^12.33.0",
"lucide-react": "^0.563.0",
"react": "^19.2.4",
"react-dom": "^19.2.4",
"tailwind-merge": "^3.4.0",
"tailwindcss": "^4.1.18",
"tailwindcss-animate": "^1.0.7"
} }
}, },
"node_modules/@astrojs/compiler": { "node_modules/@astrojs/compiler": {
@@ -87,6 +95,26 @@
"node": "18.20.8 || ^20.3.0 || >=22.0.0" "node": "18.20.8 || ^20.3.0 || >=22.0.0"
} }
}, },
"node_modules/@astrojs/react": {
"version": "4.4.2",
"resolved": "https://registry.npmjs.org/@astrojs/react/-/react-4.4.2.tgz",
"integrity": "sha512-1tl95bpGfuaDMDn8O3x/5Dxii1HPvzjvpL2YTuqOOrQehs60I2DKiDgh1jrKc7G8lv+LQT5H15V6QONQ+9waeQ==",
"license": "MIT",
"dependencies": {
"@vitejs/plugin-react": "^4.7.0",
"ultrahtml": "^1.6.0",
"vite": "^6.4.1"
},
"engines": {
"node": "18.20.8 || ^20.3.0 || >=22.0.0"
},
"peerDependencies": {
"@types/react": "^17.0.50 || ^18.0.21 || ^19.0.0",
"@types/react-dom": "^17.0.17 || ^18.0.6 || ^19.0.0",
"react": "^17.0.2 || ^18.0.0 || ^19.0.0",
"react-dom": "^17.0.2 || ^18.0.0 || ^19.0.0"
}
},
"node_modules/@astrojs/telemetry": { "node_modules/@astrojs/telemetry": {
"version": "3.3.0", "version": "3.3.0",
"resolved": "https://registry.npmjs.org/@astrojs/telemetry/-/telemetry-3.3.0.tgz", "resolved": "https://registry.npmjs.org/@astrojs/telemetry/-/telemetry-3.3.0.tgz",
@@ -125,6 +153,159 @@
"node": ">=6.9.0" "node": ">=6.9.0"
} }
}, },
"node_modules/@babel/compat-data": {
"version": "7.29.0",
"resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.0.tgz",
"integrity": "sha512-T1NCJqT/j9+cn8fvkt7jtwbLBfLC/1y1c7NtCeXFRgzGTsafi68MRv8yzkYSapBnFA6L3U2VSc02ciDzoAJhJg==",
"license": "MIT",
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/core": {
"version": "7.29.0",
"resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.0.tgz",
"integrity": "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==",
"license": "MIT",
"peer": true,
"dependencies": {
"@babel/code-frame": "^7.29.0",
"@babel/generator": "^7.29.0",
"@babel/helper-compilation-targets": "^7.28.6",
"@babel/helper-module-transforms": "^7.28.6",
"@babel/helpers": "^7.28.6",
"@babel/parser": "^7.29.0",
"@babel/template": "^7.28.6",
"@babel/traverse": "^7.29.0",
"@babel/types": "^7.29.0",
"@jridgewell/remapping": "^2.3.5",
"convert-source-map": "^2.0.0",
"debug": "^4.1.0",
"gensync": "^1.0.0-beta.2",
"json5": "^2.2.3",
"semver": "^6.3.1"
},
"engines": {
"node": ">=6.9.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/babel"
}
},
"node_modules/@babel/core/node_modules/semver": {
"version": "6.3.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
"license": "ISC",
"bin": {
"semver": "bin/semver.js"
}
},
"node_modules/@babel/generator": {
"version": "7.29.1",
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.1.tgz",
"integrity": "sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==",
"license": "MIT",
"dependencies": {
"@babel/parser": "^7.29.0",
"@babel/types": "^7.29.0",
"@jridgewell/gen-mapping": "^0.3.12",
"@jridgewell/trace-mapping": "^0.3.28",
"jsesc": "^3.0.2"
},
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/helper-compilation-targets": {
"version": "7.28.6",
"resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.28.6.tgz",
"integrity": "sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA==",
"license": "MIT",
"dependencies": {
"@babel/compat-data": "^7.28.6",
"@babel/helper-validator-option": "^7.27.1",
"browserslist": "^4.24.0",
"lru-cache": "^5.1.1",
"semver": "^6.3.1"
},
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/helper-compilation-targets/node_modules/lru-cache": {
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz",
"integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==",
"license": "ISC",
"dependencies": {
"yallist": "^3.0.2"
}
},
"node_modules/@babel/helper-compilation-targets/node_modules/semver": {
"version": "6.3.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
"license": "ISC",
"bin": {
"semver": "bin/semver.js"
}
},
"node_modules/@babel/helper-compilation-targets/node_modules/yallist": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz",
"integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==",
"license": "ISC"
},
"node_modules/@babel/helper-globals": {
"version": "7.28.0",
"resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz",
"integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==",
"license": "MIT",
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/helper-module-imports": {
"version": "7.28.6",
"resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.28.6.tgz",
"integrity": "sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==",
"license": "MIT",
"dependencies": {
"@babel/traverse": "^7.28.6",
"@babel/types": "^7.28.6"
},
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/helper-module-transforms": {
"version": "7.28.6",
"resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.6.tgz",
"integrity": "sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==",
"license": "MIT",
"dependencies": {
"@babel/helper-module-imports": "^7.28.6",
"@babel/helper-validator-identifier": "^7.28.5",
"@babel/traverse": "^7.28.6"
},
"engines": {
"node": ">=6.9.0"
},
"peerDependencies": {
"@babel/core": "^7.0.0"
}
},
"node_modules/@babel/helper-plugin-utils": {
"version": "7.28.6",
"resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.28.6.tgz",
"integrity": "sha512-S9gzZ/bz83GRysI7gAD4wPT/AI3uCnY+9xn+Mx/KPs2JwHJIz1W8PZkg2cqyt3RNOBM8ejcXhV6y8Og7ly/Dug==",
"license": "MIT",
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/helper-string-parser": { "node_modules/@babel/helper-string-parser": {
"version": "7.27.1", "version": "7.27.1",
"resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz",
@@ -143,6 +324,28 @@
"node": ">=6.9.0" "node": ">=6.9.0"
} }
}, },
"node_modules/@babel/helper-validator-option": {
"version": "7.27.1",
"resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz",
"integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==",
"license": "MIT",
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/helpers": {
"version": "7.28.6",
"resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.6.tgz",
"integrity": "sha512-xOBvwq86HHdB7WUDTfKfT/Vuxh7gElQ+Sfti2Cy6yIWNW05P8iUslOVcZ4/sKbE+/jQaukQAdz/gf3724kYdqw==",
"license": "MIT",
"dependencies": {
"@babel/template": "^7.28.6",
"@babel/types": "^7.28.6"
},
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/parser": { "node_modules/@babel/parser": {
"version": "7.29.0", "version": "7.29.0",
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.0.tgz", "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.0.tgz",
@@ -158,6 +361,68 @@
"node": ">=6.0.0" "node": ">=6.0.0"
} }
}, },
"node_modules/@babel/plugin-transform-react-jsx-self": {
"version": "7.27.1",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.27.1.tgz",
"integrity": "sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw==",
"license": "MIT",
"dependencies": {
"@babel/helper-plugin-utils": "^7.27.1"
},
"engines": {
"node": ">=6.9.0"
},
"peerDependencies": {
"@babel/core": "^7.0.0-0"
}
},
"node_modules/@babel/plugin-transform-react-jsx-source": {
"version": "7.27.1",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.27.1.tgz",
"integrity": "sha512-zbwoTsBruTeKB9hSq73ha66iFeJHuaFkUbwvqElnygoNbj/jHRsSeokowZFN3CZ64IvEqcmmkVe89OPXc7ldAw==",
"license": "MIT",
"dependencies": {
"@babel/helper-plugin-utils": "^7.27.1"
},
"engines": {
"node": ">=6.9.0"
},
"peerDependencies": {
"@babel/core": "^7.0.0-0"
}
},
"node_modules/@babel/template": {
"version": "7.28.6",
"resolved": "https://registry.npmjs.org/@babel/template/-/template-7.28.6.tgz",
"integrity": "sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==",
"license": "MIT",
"dependencies": {
"@babel/code-frame": "^7.28.6",
"@babel/parser": "^7.28.6",
"@babel/types": "^7.28.6"
},
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/traverse": {
"version": "7.29.0",
"resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.0.tgz",
"integrity": "sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==",
"license": "MIT",
"dependencies": {
"@babel/code-frame": "^7.29.0",
"@babel/generator": "^7.29.0",
"@babel/helper-globals": "^7.28.0",
"@babel/parser": "^7.29.0",
"@babel/template": "^7.28.6",
"@babel/types": "^7.29.0",
"debug": "^4.3.1"
},
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/types": { "node_modules/@babel/types": {
"version": "7.29.0", "version": "7.29.0",
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.0.tgz", "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.0.tgz",
@@ -3309,6 +3574,12 @@
"node": ">=14" "node": ">=14"
} }
}, },
"node_modules/@rolldown/pluginutils": {
"version": "1.0.0-beta.27",
"resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.27.tgz",
"integrity": "sha512-+d0F4MKMCbeVUJwG96uQ4SgAznZNSq93I3V+9NHA4OpvqG8mRCpGdKmK8l/dl02h2CCDHwW2FqilnTyDcAnqjA==",
"license": "MIT"
},
"node_modules/@rollup/pluginutils": { "node_modules/@rollup/pluginutils": {
"version": "5.3.0", "version": "5.3.0",
"resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.3.0.tgz", "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.3.0.tgz",
@@ -3996,6 +4267,47 @@
"vite": "^5.2.0 || ^6 || ^7" "vite": "^5.2.0 || ^6 || ^7"
} }
}, },
"node_modules/@types/babel__core": {
"version": "7.20.5",
"resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz",
"integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==",
"license": "MIT",
"dependencies": {
"@babel/parser": "^7.20.7",
"@babel/types": "^7.20.7",
"@types/babel__generator": "*",
"@types/babel__template": "*",
"@types/babel__traverse": "*"
}
},
"node_modules/@types/babel__generator": {
"version": "7.27.0",
"resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.27.0.tgz",
"integrity": "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==",
"license": "MIT",
"dependencies": {
"@babel/types": "^7.0.0"
}
},
"node_modules/@types/babel__template": {
"version": "7.4.4",
"resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz",
"integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==",
"license": "MIT",
"dependencies": {
"@babel/parser": "^7.1.0",
"@babel/types": "^7.0.0"
}
},
"node_modules/@types/babel__traverse": {
"version": "7.28.0",
"resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.28.0.tgz",
"integrity": "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==",
"license": "MIT",
"dependencies": {
"@babel/types": "^7.28.2"
}
},
"node_modules/@types/debug": { "node_modules/@types/debug": {
"version": "4.1.12", "version": "4.1.12",
"resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.12.tgz", "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.12.tgz",
@@ -4044,12 +4356,42 @@
"@types/unist": "*" "@types/unist": "*"
} }
}, },
"node_modules/@types/node": {
"version": "25.2.2",
"resolved": "https://registry.npmjs.org/@types/node/-/node-25.2.2.tgz",
"integrity": "sha512-BkmoP5/FhRYek5izySdkOneRyXYN35I860MFAGupTdebyE66uZaR+bXLHq8k4DirE5DwQi3NuhvRU1jqTVwUrQ==",
"license": "MIT",
"optional": true,
"dependencies": {
"undici-types": "~7.16.0"
}
},
"node_modules/@types/normalize-package-data": { "node_modules/@types/normalize-package-data": {
"version": "2.4.4", "version": "2.4.4",
"resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.4.tgz", "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.4.tgz",
"integrity": "sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==", "integrity": "sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==",
"license": "MIT" "license": "MIT"
}, },
"node_modules/@types/react": {
"version": "19.2.13",
"resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.13.tgz",
"integrity": "sha512-KkiJeU6VbYbUOp5ITMIc7kBfqlYkKA5KhEHVrGMmUUMt7NeaZg65ojdPk+FtNrBAOXNVM5QM72jnADjM+XVRAQ==",
"license": "MIT",
"peer": true,
"dependencies": {
"csstype": "^3.2.2"
}
},
"node_modules/@types/react-dom": {
"version": "19.2.3",
"resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.2.3.tgz",
"integrity": "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==",
"license": "MIT",
"peer": true,
"peerDependencies": {
"@types/react": "^19.2.0"
}
},
"node_modules/@types/retry": { "node_modules/@types/retry": {
"version": "0.12.2", "version": "0.12.2",
"resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.2.tgz", "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.2.tgz",
@@ -4210,6 +4552,26 @@
"integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==",
"license": "MIT" "license": "MIT"
}, },
"node_modules/@vitejs/plugin-react": {
"version": "4.7.0",
"resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.7.0.tgz",
"integrity": "sha512-gUu9hwfWvvEDBBmgtAowQCojwZmJ5mcLn3aufeCsitijs3+f2NsrPtlAWIR6OPiqljl96GVCUbLe0HyqIpVaoA==",
"license": "MIT",
"dependencies": {
"@babel/core": "^7.28.0",
"@babel/plugin-transform-react-jsx-self": "^7.27.1",
"@babel/plugin-transform-react-jsx-source": "^7.27.1",
"@rolldown/pluginutils": "1.0.0-beta.27",
"@types/babel__core": "^7.20.5",
"react-refresh": "^0.17.0"
},
"engines": {
"node": "^14.18.0 || >=16.0.0"
},
"peerDependencies": {
"vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0"
}
},
"node_modules/@vue/compiler-core": { "node_modules/@vue/compiler-core": {
"version": "3.5.27", "version": "3.5.27",
"resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.27.tgz", "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.27.tgz",
@@ -4811,6 +5173,15 @@
], ],
"license": "MIT" "license": "MIT"
}, },
"node_modules/baseline-browser-mapping": {
"version": "2.9.19",
"resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.9.19.tgz",
"integrity": "sha512-ipDqC8FrAl/76p2SSWKSI+H9tFwm7vYqXQrItCuiVPt26Km0jS+NzSsBWAaBusvSbQcfJG+JitdMm+wZAgTYqg==",
"license": "Apache-2.0",
"bin": {
"baseline-browser-mapping": "dist/cli.js"
}
},
"node_modules/better-ajv-errors": { "node_modules/better-ajv-errors": {
"version": "1.2.0", "version": "1.2.0",
"resolved": "https://registry.npmjs.org/better-ajv-errors/-/better-ajv-errors-1.2.0.tgz", "resolved": "https://registry.npmjs.org/better-ajv-errors/-/better-ajv-errors-1.2.0.tgz",
@@ -4931,6 +5302,40 @@
"node": ">=8" "node": ">=8"
} }
}, },
"node_modules/browserslist": {
"version": "4.28.1",
"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.1.tgz",
"integrity": "sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==",
"funding": [
{
"type": "opencollective",
"url": "https://opencollective.com/browserslist"
},
{
"type": "tidelift",
"url": "https://tidelift.com/funding/github/npm/browserslist"
},
{
"type": "github",
"url": "https://github.com/sponsors/ai"
}
],
"license": "MIT",
"peer": true,
"dependencies": {
"baseline-browser-mapping": "^2.9.0",
"caniuse-lite": "^1.0.30001759",
"electron-to-chromium": "^1.5.263",
"node-releases": "^2.0.27",
"update-browserslist-db": "^1.2.0"
},
"bin": {
"browserslist": "cli.js"
},
"engines": {
"node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7"
}
},
"node_modules/buffer": { "node_modules/buffer": {
"version": "6.0.3", "version": "6.0.3",
"resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz",
@@ -4996,6 +5401,26 @@
"url": "https://github.com/sponsors/sindresorhus" "url": "https://github.com/sponsors/sindresorhus"
} }
}, },
"node_modules/caniuse-lite": {
"version": "1.0.30001769",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001769.tgz",
"integrity": "sha512-BCfFL1sHijQlBGWBMuJyhZUhzo7wer5sVj9hqekB/7xn0Ypy+pER/edCYQm4exbXj4WiySGp40P8UuTh6w1srg==",
"funding": [
{
"type": "opencollective",
"url": "https://opencollective.com/browserslist"
},
{
"type": "tidelift",
"url": "https://tidelift.com/funding/github/npm/caniuse-lite"
},
{
"type": "github",
"url": "https://github.com/sponsors/ai"
}
],
"license": "CC-BY-4.0"
},
"node_modules/ccount": { "node_modules/ccount": {
"version": "2.0.1", "version": "2.0.1",
"resolved": "https://registry.npmjs.org/ccount/-/ccount-2.0.1.tgz", "resolved": "https://registry.npmjs.org/ccount/-/ccount-2.0.1.tgz",
@@ -5374,6 +5799,12 @@
"node": "^14.18.0 || >=16.10.0" "node": "^14.18.0 || >=16.10.0"
} }
}, },
"node_modules/convert-source-map": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz",
"integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==",
"license": "MIT"
},
"node_modules/cookie": { "node_modules/cookie": {
"version": "1.1.1", "version": "1.1.1",
"resolved": "https://registry.npmjs.org/cookie/-/cookie-1.1.1.tgz", "resolved": "https://registry.npmjs.org/cookie/-/cookie-1.1.1.tgz",
@@ -5576,6 +6007,12 @@
"integrity": "sha512-aylIc7Z9y4yzHYAJNuESG3hfhC+0Ibp/MAMiaOZgNv4pmEdFyfZhhhny4MNiAfWdBQ1RQ2mfDWmM1x8SvGyp8g==", "integrity": "sha512-aylIc7Z9y4yzHYAJNuESG3hfhC+0Ibp/MAMiaOZgNv4pmEdFyfZhhhny4MNiAfWdBQ1RQ2mfDWmM1x8SvGyp8g==",
"license": "CC0-1.0" "license": "CC0-1.0"
}, },
"node_modules/csstype": {
"version": "3.2.3",
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz",
"integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==",
"license": "MIT"
},
"node_modules/data-uri-to-buffer": { "node_modules/data-uri-to-buffer": {
"version": "4.0.1", "version": "4.0.1",
"resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz", "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz",
@@ -5979,6 +6416,12 @@
"safe-buffer": "^5.0.1" "safe-buffer": "^5.0.1"
} }
}, },
"node_modules/electron-to-chromium": {
"version": "1.5.286",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.286.tgz",
"integrity": "sha512-9tfDXhJ4RKFNerfjdCcZfufu49vg620741MNs26a9+bhLThdB+plgMeou98CAaHu/WATj2iHOOHTp1hWtABj2A==",
"license": "ISC"
},
"node_modules/emoji-regex": { "node_modules/emoji-regex": {
"version": "10.6.0", "version": "10.6.0",
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.6.0.tgz", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.6.0.tgz",
@@ -6557,6 +7000,33 @@
"node": ">=12.20.0" "node": ">=12.20.0"
} }
}, },
"node_modules/framer-motion": {
"version": "12.33.0",
"resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-12.33.0.tgz",
"integrity": "sha512-ca8d+rRPcDP5iIF+MoT3WNc0KHJMjIyFAbtVLvM9eA7joGSpeqDfiNH/kCs1t4CHi04njYvWyj0jS4QlEK/rJQ==",
"license": "MIT",
"dependencies": {
"motion-dom": "^12.33.0",
"motion-utils": "^12.29.2",
"tslib": "^2.4.0"
},
"peerDependencies": {
"@emotion/is-prop-valid": "*",
"react": "^18.0.0 || ^19.0.0",
"react-dom": "^18.0.0 || ^19.0.0"
},
"peerDependenciesMeta": {
"@emotion/is-prop-valid": {
"optional": true
},
"react": {
"optional": true
},
"react-dom": {
"optional": true
}
}
},
"node_modules/fsevents": { "node_modules/fsevents": {
"version": "2.3.3", "version": "2.3.3",
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
@@ -6580,6 +7050,15 @@
"url": "https://github.com/sponsors/ljharb" "url": "https://github.com/sponsors/ljharb"
} }
}, },
"node_modules/gensync": {
"version": "1.0.0-beta.2",
"resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz",
"integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==",
"license": "MIT",
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/get-amd-module-type": { "node_modules/get-amd-module-type": {
"version": "6.0.1", "version": "6.0.1",
"resolved": "https://registry.npmjs.org/get-amd-module-type/-/get-amd-module-type-6.0.1.tgz", "resolved": "https://registry.npmjs.org/get-amd-module-type/-/get-amd-module-type-6.0.1.tgz",
@@ -7390,12 +7869,36 @@
"js-yaml": "bin/js-yaml.js" "js-yaml": "bin/js-yaml.js"
} }
}, },
"node_modules/jsesc": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz",
"integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==",
"license": "MIT",
"bin": {
"jsesc": "bin/jsesc"
},
"engines": {
"node": ">=6"
}
},
"node_modules/json-schema-traverse": { "node_modules/json-schema-traverse": {
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
"integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==",
"license": "MIT" "license": "MIT"
}, },
"node_modules/json5": {
"version": "2.2.3",
"resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
"integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==",
"license": "MIT",
"bin": {
"json5": "lib/cli.js"
},
"engines": {
"node": ">=6"
}
},
"node_modules/jsonpointer": { "node_modules/jsonpointer": {
"version": "5.0.1", "version": "5.0.1",
"resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-5.0.1.tgz", "resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-5.0.1.tgz",
@@ -7945,6 +8448,15 @@
"node": "20 || >=22" "node": "20 || >=22"
} }
}, },
"node_modules/lucide-react": {
"version": "0.563.0",
"resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-0.563.0.tgz",
"integrity": "sha512-8dXPB2GI4dI8jV4MgUDGBeLdGk8ekfqVZ0BdLcrRzocGgG75ltNEmWS+gE7uokKF/0oSUuczNDT+g9hFJ23FkA==",
"license": "ISC",
"peerDependencies": {
"react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0"
}
},
"node_modules/luxon": { "node_modules/luxon": {
"version": "3.7.2", "version": "3.7.2",
"resolved": "https://registry.npmjs.org/luxon/-/luxon-3.7.2.tgz", "resolved": "https://registry.npmjs.org/luxon/-/luxon-3.7.2.tgz",
@@ -8967,6 +9479,21 @@
"integrity": "sha512-EGWKgxALGMgzvxYF1UyGTy0HXX/2vHLkw6+NvDKW2jypWbHpjQuj4UMcqQWXHERJhVGKikolT06G3bcKe4fi7w==", "integrity": "sha512-EGWKgxALGMgzvxYF1UyGTy0HXX/2vHLkw6+NvDKW2jypWbHpjQuj4UMcqQWXHERJhVGKikolT06G3bcKe4fi7w==",
"license": "MIT" "license": "MIT"
}, },
"node_modules/motion-dom": {
"version": "12.33.0",
"resolved": "https://registry.npmjs.org/motion-dom/-/motion-dom-12.33.0.tgz",
"integrity": "sha512-XRPebVypsl0UM+7v0Hr8o9UAj0S2djsQWRdHBd5iVouVpMrQqAI0C/rDAT3QaYnXnHuC5hMcwDHCboNeyYjPoQ==",
"license": "MIT",
"dependencies": {
"motion-utils": "^12.29.2"
}
},
"node_modules/motion-utils": {
"version": "12.29.2",
"resolved": "https://registry.npmjs.org/motion-utils/-/motion-utils-12.29.2.tgz",
"integrity": "sha512-G3kc34H2cX2gI63RqU+cZq+zWRRPSsNIOjpdl9TN4AQwC4sgwYPl/Q/Obf/d53nOm569T0fYK+tcoSV50BWx8A==",
"license": "MIT"
},
"node_modules/mrmime": { "node_modules/mrmime": {
"version": "2.0.1", "version": "2.0.1",
"resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.1.tgz", "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.1.tgz",
@@ -9104,6 +9631,12 @@
"integrity": "sha512-8DY+kFsDkNXy1sJglUfuODx1/opAGJGyrTuFqEoN90oRc2Vk0ZbD4K2qmKXBBEhZQzdKHIVfEJpDU8Ak2NJEvQ==", "integrity": "sha512-8DY+kFsDkNXy1sJglUfuODx1/opAGJGyrTuFqEoN90oRc2Vk0ZbD4K2qmKXBBEhZQzdKHIVfEJpDU8Ak2NJEvQ==",
"license": "MIT" "license": "MIT"
}, },
"node_modules/node-releases": {
"version": "2.0.27",
"resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.27.tgz",
"integrity": "sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==",
"license": "MIT"
},
"node_modules/node-source-walk": { "node_modules/node-source-walk": {
"version": "7.0.1", "version": "7.0.1",
"resolved": "https://registry.npmjs.org/node-source-walk/-/node-source-walk-7.0.1.tgz", "resolved": "https://registry.npmjs.org/node-source-walk/-/node-source-walk-7.0.1.tgz",
@@ -9767,6 +10300,38 @@
"integrity": "sha512-b484I/7b8rDEdSDKckSSBA8knMpcdsXudlE/LNL639wFoHKwLbEkQFZHWEYwDC0wa0FKUcCY+GAF73Z7wxNVFA==", "integrity": "sha512-b484I/7b8rDEdSDKckSSBA8knMpcdsXudlE/LNL639wFoHKwLbEkQFZHWEYwDC0wa0FKUcCY+GAF73Z7wxNVFA==",
"license": "MIT" "license": "MIT"
}, },
"node_modules/react": {
"version": "19.2.4",
"resolved": "https://registry.npmjs.org/react/-/react-19.2.4.tgz",
"integrity": "sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ==",
"license": "MIT",
"peer": true,
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/react-dom": {
"version": "19.2.4",
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.4.tgz",
"integrity": "sha512-AXJdLo8kgMbimY95O2aKQqsz2iWi9jMgKJhRBAxECE4IFxfcazB2LmzloIoibJI3C12IlY20+KFaLv+71bUJeQ==",
"license": "MIT",
"peer": true,
"dependencies": {
"scheduler": "^0.27.0"
},
"peerDependencies": {
"react": "^19.2.4"
}
},
"node_modules/react-refresh": {
"version": "0.17.0",
"resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.17.0.tgz",
"integrity": "sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ==",
"license": "MIT",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/read-package-up": { "node_modules/read-package-up": {
"version": "11.0.0", "version": "11.0.0",
"resolved": "https://registry.npmjs.org/read-package-up/-/read-package-up-11.0.0.tgz", "resolved": "https://registry.npmjs.org/read-package-up/-/read-package-up-11.0.0.tgz",
@@ -10194,6 +10759,7 @@
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.57.1.tgz", "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.57.1.tgz",
"integrity": "sha512-oQL6lgK3e2QZeQ7gcgIkS2YZPg5slw37hYufJ3edKlfQSGGm8ICoxswK15ntSzF/a8+h7ekRy7k7oWc3BQ7y8A==", "integrity": "sha512-oQL6lgK3e2QZeQ7gcgIkS2YZPg5slw37hYufJ3edKlfQSGGm8ICoxswK15ntSzF/a8+h7ekRy7k7oWc3BQ7y8A==",
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"@types/estree": "1.0.8" "@types/estree": "1.0.8"
}, },
@@ -10294,6 +10860,12 @@
"node": ">=11.0.0" "node": ">=11.0.0"
} }
}, },
"node_modules/scheduler": {
"version": "0.27.0",
"resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz",
"integrity": "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==",
"license": "MIT"
},
"node_modules/semver": { "node_modules/semver": {
"version": "7.7.4", "version": "7.7.4",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz",
@@ -10711,11 +11283,31 @@
"url": "https://github.com/sponsors/sindresorhus" "url": "https://github.com/sponsors/sindresorhus"
} }
}, },
"node_modules/tailwind-merge": {
"version": "3.4.0",
"resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-3.4.0.tgz",
"integrity": "sha512-uSaO4gnW+b3Y2aWoWfFpX62vn2sR3skfhbjsEnaBI81WD1wBLlHZe5sWf0AqjksNdYTbGBEd0UasQMT3SNV15g==",
"license": "MIT",
"funding": {
"type": "github",
"url": "https://github.com/sponsors/dcastil"
}
},
"node_modules/tailwindcss": { "node_modules/tailwindcss": {
"version": "4.1.18", "version": "4.1.18",
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.1.18.tgz", "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.1.18.tgz",
"integrity": "sha512-4+Z+0yiYyEtUVCScyfHCxOYP06L5Ne+JiHhY2IjR2KWMIWhJOYZKLSGZaP5HkZ8+bY0cxfzwDE5uOmzFXyIwxw==", "integrity": "sha512-4+Z+0yiYyEtUVCScyfHCxOYP06L5Ne+JiHhY2IjR2KWMIWhJOYZKLSGZaP5HkZ8+bY0cxfzwDE5uOmzFXyIwxw==",
"license": "MIT" "license": "MIT",
"peer": true
},
"node_modules/tailwindcss-animate": {
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/tailwindcss-animate/-/tailwindcss-animate-1.0.7.tgz",
"integrity": "sha512-bl6mpH3T7I3UFxuvDEXLxy/VuFxBk5bbzplh7tXI68mwMokNYd1t9qPBHlnyTwfa4JGC4zP516I1hYYtQ/vspA==",
"license": "MIT",
"peerDependencies": {
"tailwindcss": ">=3.0.0 || insiders"
}
}, },
"node_modules/tapable": { "node_modules/tapable": {
"version": "2.3.0", "version": "2.3.0",
@@ -11283,6 +11875,36 @@
"integrity": "sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==", "integrity": "sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==",
"license": "MIT" "license": "MIT"
}, },
"node_modules/update-browserslist-db": {
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz",
"integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==",
"funding": [
{
"type": "opencollective",
"url": "https://opencollective.com/browserslist"
},
{
"type": "tidelift",
"url": "https://tidelift.com/funding/github/npm/browserslist"
},
{
"type": "github",
"url": "https://github.com/sponsors/ai"
}
],
"license": "MIT",
"dependencies": {
"escalade": "^3.2.0",
"picocolors": "^1.1.1"
},
"bin": {
"update-browserslist-db": "cli.js"
},
"peerDependencies": {
"browserslist": ">= 4.21.0"
}
},
"node_modules/uqr": { "node_modules/uqr": {
"version": "0.1.2", "version": "0.1.2",
"resolved": "https://registry.npmjs.org/uqr/-/uqr-0.1.2.tgz", "resolved": "https://registry.npmjs.org/uqr/-/uqr-0.1.2.tgz",
@@ -11792,7 +12414,6 @@
"resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.2.tgz", "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.2.tgz",
"integrity": "sha512-mplynKqc1C2hTVYxd0PU2xQAc22TI1vShAYGksCCfxbn/dFwnHTNi1bvYsBTkhdUNtGIf5xNOg938rrSSYvS9A==", "integrity": "sha512-mplynKqc1C2hTVYxd0PU2xQAc22TI1vShAYGksCCfxbn/dFwnHTNi1bvYsBTkhdUNtGIf5xNOg938rrSSYvS9A==",
"license": "ISC", "license": "ISC",
"peer": true,
"bin": { "bin": {
"yaml": "bin.mjs" "yaml": "bin.mjs"
}, },

View File

@@ -10,8 +10,16 @@
}, },
"dependencies": { "dependencies": {
"@astrojs/netlify": "^6.6.4", "@astrojs/netlify": "^6.6.4",
"@astrojs/react": "^4.4.2",
"@tailwindcss/vite": "^4.1.18", "@tailwindcss/vite": "^4.1.18",
"astro": "^5.17.1", "astro": "^5.17.1",
"tailwindcss": "^4.1.18" "clsx": "^2.1.1",
"framer-motion": "^12.33.0",
"lucide-react": "^0.563.0",
"react": "^19.2.4",
"react-dom": "^19.2.4",
"tailwind-merge": "^3.4.0",
"tailwindcss": "^4.1.18",
"tailwindcss-animate": "^1.0.7"
} }
} }

186
src/components/Footer.astro Normal file
View File

@@ -0,0 +1,186 @@
---
import { Code2, Github, Twitter, Linkedin } from "lucide-react";
---
<footer class="py-20 border-t border-white/5 bg-slate-950">
<div class="container mx-auto px-6">
<div class="grid md:grid-cols-4 gap-12 mb-16">
<div class="col-span-1 md:col-span-2">
<div class="flex items-center gap-2 mb-6">
<div
class="w-8 h-8 bg-amber-500 rounded-lg flex items-center justify-center transform rotate-12"
>
<Code2 size={18} className="text-slate-900" />
</div>
<span
class="text-xl font-bold font-heading tracking-tight text-white"
>
Move. <span class="text-indigo-400">Compete.</span> Play.
</span>
</div>
<p class="text-slate-500 max-w-sm mb-6 leading-relaxed">
The premier hub for tech professionals to transition from
AI-anxiety to AI-mastery through building and community.
</p>
<div class="flex gap-4">
<a
href="#"
class="w-10 h-10 rounded-lg bg-slate-900 border border-slate-800 flex items-center justify-center text-slate-400 hover:text-amber-500 hover:border-amber-500/50 transition-all"
>
<span class="sr-only">Discord</span>
<svg
xmlns="http://www.w3.org/2000/svg"
width="18"
height="18"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<path
d="M9.5 7.5c-.828 0-1.5.671-1.5 1.5 0 .828.672 1.5 1.5 1.5s1.5-.672 1.5-1.5c0-.829-.672-1.5-1.5-1.5zm5 0c-.828 0-1.5.671-1.5 1.5 0 .828.672 1.5 1.5 1.5s1.5-.672 1.5-1.5c0-.829-.672-1.5-1.5-1.5z"
></path>
<path
d="M18.7 4.1c-1.26-.42-2.61-.73-4-.91-.18.31-.35.63-.49.97-1.5-.23-3-.23-4.5 0-.14-.34-.31-.66-.49-.97-1.39.18-2.74.49-4 .91-2.59 3.89-3.29 7.69-2.94 11.44 1.69 1.25 3.33 2.01 4.95 2.51.4-.54.75-1.12 1.05-1.72-.58-.22-1.13-.48-1.66-.78.14-.1.27-.21.4-.32 3.21 1.49 6.76 1.49 9.96 0 .13.11.26.22.4.32-.53.3-1.08.56-1.66.78.3.6.65 1.18 1.05 1.72 1.62-.5 3.26-1.26 4.95-2.51.39-4.2-.65-7.84-2.94-11.44z"
></path>
</svg>
</a>
<a
id="footer-gitea-trigger"
href="#"
class="w-10 h-10 rounded-lg bg-slate-900 border border-slate-800 flex items-center justify-center text-slate-400 hover:text-amber-500 hover:border-amber-500/50 transition-all"
>
<span class="sr-only">Gitea</span>
<svg
xmlns="http://www.w3.org/2000/svg"
width="18"
height="18"
viewBox="0 0 640 640"
fill="currentColor"
>
<path
d="M395.9,484.2l-126.9-61c-12.5-6-17.9-21.2-11.8-33.8l61-126.9c6-12.5,21.2-17.9,33.8-11.8 c17.2,8.3,27.1,13,27.1,13l-0.1-109.2l16.7-0.1l0.1,117.1c0,0,57.4,24.2,83.1,40.1c3.7,2.3,10.2,6.8,12.9,14.4 c2.1,6.1,2,13.1-1,19.3l-61,126.9C423.6,484.9,408.4,490.3,395.9,484.2z"
></path>
<path
d="M622.7,149.8c-4.1-4.1-9.6-4-9.6-4s-117.2,6.6-177.9,8c-13.3,0.3-26.5,0.6-39.6,0.7c0,39.1,0,78.2,0,117.2 c-5.5-2.6-11.1-5.3-16.6-7.9c0-36.4-0.1-109.2-0.1-109.2c-29,0.4-89.2-2.2-89.2-2.2s-141.4-7.1-156.8-8.5 c-9.8-0.6-22.5-2.1-39,1.5c-8.7,1.8-33.5,7.4-53.8,26.9C-4.9,212.4,6.6,276.2,8,285.8c1.7,11.7,6.9,44.2,31.7,72.5 c45.8,56.1,144.4,54.8,144.4,54.8s12.1,28.9,30.6,55.5c25,33.1,50.7,58.9,75.7,62c63,0,188.9-0.1,188.9-0.1s12,0.1,28.3-10.3 c14-8.5,26.5-23.4,26.5-23.4s12.9-13.8,30.9-45.3c5.5-9.7,10.1-19.1,14.1-28c0,0,55.2-117.1,55.2-231.1 C633.2,157.9,624.7,151.8,622.7,149.8z M125.6,353.9c-25.9-8.5-36.9-18.7-36.9-18.7S69.6,321.8,60,295.4 c-16.5-44.2-1.4-71.2-1.4-71.2s8.4-22.5,38.5-30c13.8-3.7,31-3.1,31-3.1s7.1,59.4,15.7,94.2c7.2,29.2,24.8,77.7,24.8,77.7 S142.5,359.9,125.6,353.9z M425.9,461.5c0,0-6.1,14.5-19.6,15.4c-5.8,0.4-10.3-1.2-10.3-1.2s-0.3-0.1-5.3-2.1l-112.9-55 c0,0-10.9-5.7-12.8-15.6c-2.2-8.1,2.7-18.1,2.7-18.1L322,273c0,0,4.8-9.7,12.2-13c0.6-0.3,2.3-1,4.5-1.5c8.1-2.1,18,2.8,18,2.8 l110.7,53.7c0,0,12.6,5.7,15.3,16.2c1.9,7.4-0.5,14-1.8,17.2C474.6,363.8,425.9,461.5,425.9,461.5z"
></path>
<path
d="M326.8,380.1c-8.2,0.1-15.4,5.8-17.3,13.8c-1.9,8,2,16.3,9.1,20c7.7,4,17.5,1.8,22.7-5.4 c5.1-7.1,4.3-16.9-1.8-23.1l24-49.1c1.5,0.1,3.7,0.2,6.2-0.5c4.1-0.9,7.1-3.6,7.1-3.6c4.2,1.8,8.6,3.8,13.2,6.1 c4.8,2.4,9.3,4.9,13.4,7.3c0.9,0.5,1.8,1.1,2.8,1.9c1.6,1.3,3.4,3.1,4.7,5.5c1.9,5.5-1.9,14.9-1.9,14.9 c-2.3,7.6-18.4,40.6-18.4,40.6c-8.1-0.2-15.3,5-17.7,12.5c-2.6,8.1,1.1,17.3,8.9,21.3c7.8,4,17.4,1.7,22.5-5.3 c5-6.8,4.6-16.3-1.1-22.6c1.9-3.7,3.7-7.4,5.6-11.3c5-10.4,13.5-30.4,13.5-30.4c0.9-1.7,5.7-10.3,2.7-21.3 c-2.5-11.4-12.6-16.7-12.6-16.7c-12.2-7.9-29.2-15.2-29.2-15.2s0-4.1-1.1-7.1c-1.1-3.1-2.8-5.1-3.9-6.3c4.7-9.7,9.4-19.3,14.1-29 c-4.1-2-8.1-4-12.2-6.1c-4.8,9.8-9.7,19.7-14.5,29.5c-6.7-0.1-12.9,3.5-16.1,9.4c-3.4,6.3-2.7,14.1,1.9,19.8 C343.2,346.5,335,363.3,326.8,380.1z"
></path>
</svg>
</a>
<a
href="#"
class="w-10 h-10 rounded-lg bg-slate-900 border border-slate-800 flex items-center justify-center text-slate-400 hover:text-amber-500 hover:border-amber-500/50 transition-all"
>
<span class="sr-only">Twitter</span>
<Twitter size={18} />
</a>
<a
href="#"
class="w-10 h-10 rounded-lg bg-slate-900 border border-slate-800 flex items-center justify-center text-slate-400 hover:text-amber-500 hover:border-amber-500/50 transition-all"
>
<span class="sr-only">LinkedIn</span>
<Linkedin size={18} />
</a>
</div>
</div>
<div>
<h5 class="text-white font-bold mb-6 font-heading">Resource</h5>
<ul class="space-y-4 text-sm text-slate-500">
<li>
<a
href="#"
class="hover:text-amber-400 transition-colors"
>The Manifesto</a
>
</li>
<li>
<a
href="#"
class="hover:text-amber-400 transition-colors"
>Build Kits</a
>
</li>
<li>
<a
href="#"
class="hover:text-amber-400 transition-colors"
>Squad Directory</a
>
</li>
<li>
<a
href="#"
class="hover:text-amber-400 transition-colors"
>Alumni Network</a
>
</li>
</ul>
</div>
<div>
<h5 class="text-white font-bold mb-6 font-heading">
Protocols
</h5>
<ul class="space-y-4 text-sm text-slate-500 font-mono">
<li>
<a
href="#"
class="hover:text-indigo-400 transition-colors"
>MCP Spec</a
>
</li>
<li>
<a
href="#"
class="hover:text-indigo-400 transition-colors"
>UCP Handshake</a
>
</li>
<li>
<a
href="#"
class="hover:text-indigo-400 transition-colors"
>Agent SDK</a
>
</li>
<li>
<a
href="#"
class="hover:text-indigo-400 transition-colors"
>A2A Messaging</a
>
</li>
</ul>
</div>
</div>
<div
class="flex flex-col md:flex-row justify-between items-center gap-6 pt-10 border-t border-white/5"
>
<p class="text-sm text-slate-600 font-heading font-bold">
© {new Date().getFullYear()} Move. Compete. Play. — The future belongs
to the builders. ⚡ Built with AI
</p>
<div class="flex gap-8 text-xs text-slate-600">
<a href="#" class="hover:text-slate-400">Privacy Policy</a>
<a href="#" class="hover:text-slate-400">Terms of Service</a>
<a href="#" class="hover:text-slate-400">Code of Conduct</a>
</div>
</div>
</div>
</footer>
<script>
const footerTrigger = document.getElementById("footer-gitea-trigger");
if (footerTrigger) {
footerTrigger.addEventListener("click", (e) => {
e.preventDefault();
window.dispatchEvent(new CustomEvent("open-join-modal"));
});
}
</script>

View File

@@ -0,0 +1,97 @@
---
import { Code2 } from "lucide-react";
---
<nav
id="navbar"
class="fixed top-0 w-full z-50 transition-all duration-300 py-6 bg-transparent"
>
<div class="container mx-auto px-6 flex items-center justify-between">
<div class="flex items-center gap-2">
<div
class="w-8 h-8 bg-amber-500 rounded-lg flex items-center justify-center transform rotate-12"
>
<Code2 size={18} className="text-slate-900" />
</div>
<span
class="text-xl font-bold font-heading tracking-tight text-white"
>
Move. <span class="text-indigo-400">Compete.</span> Play.
</span>
</div>
<div class="hidden md:flex items-center gap-10">
{
[
{ name: "The Mission", href: "#the-mission" },
{ name: "Build Projects", href: "/#build-season" },
{ name: "Squads", href: "#squads" },
{ name: "Manifesto", href: "#manifesto" },
].map((link) => (
<a
href={link.href}
class="text-sm font-medium text-slate-300 hover:text-amber-400 transition-colors"
>
{link.name}
</a>
))
}
</div>
<button
id="join-trigger"
class="bg-amber-500 hover:bg-amber-400 text-slate-900 font-bold px-4 py-2 text-sm md:px-6 md:py-2.5 md:text-base rounded-full transition-all hover:scale-105 active:scale-95 shadow-lg shadow-amber-500/20 cursor-pointer flex items-center gap-2"
>
<svg
xmlns="http://www.w3.org/2000/svg"
width="20"
height="20"
viewBox="0 0 640 640"
fill="currentColor"
>
<path
d="M395.9,484.2l-126.9-61c-12.5-6-17.9-21.2-11.8-33.8l61-126.9c6-12.5,21.2-17.9,33.8-11.8 c17.2,8.3,27.1,13,27.1,13l-0.1-109.2l16.7-0.1l0.1,117.1c0,0,57.4,24.2,83.1,40.1c3.7,2.3,10.2,6.8,12.9,14.4 c2.1,6.1,2,13.1-1,19.3l-61,126.9C423.6,484.9,408.4,490.3,395.9,484.2z"
></path>
<path
d="M622.7,149.8c-4.1-4.1-9.6-4-9.6-4s-117.2,6.6-177.9,8c-13.3,0.3-26.5,0.6-39.6,0.7c0,39.1,0,78.2,0,117.2 c-5.5-2.6-11.1-5.3-16.6-7.9c0-36.4-0.1-109.2-0.1-109.2c-29,0.4-89.2-2.2-89.2-2.2s-141.4-7.1-156.8-8.5 c-9.8-0.6-22.5-2.1-39,1.5c-8.7,1.8-33.5,7.4-53.8,26.9C-4.9,212.4,6.6,276.2,8,285.8c1.7,11.7,6.9,44.2,31.7,72.5 c45.8,56.1,144.4,54.8,144.4,54.8s12.1,28.9,30.6,55.5c25,33.1,50.7,58.9,75.7,62c63,0,188.9-0.1,188.9-0.1s12,0.1,28.3-10.3 c14-8.5,26.5-23.4,26.5-23.4s12.9-13.8,30.9-45.3c5.5-9.7,10.1-19.1,14.1-28c0,0,55.2-117.1,55.2-231.1 C633.2,157.9,624.7,151.8,622.7,149.8z M125.6,353.9c-25.9-8.5-36.9-18.7-36.9-18.7S69.6,321.8,60,295.4 c-16.5-44.2-1.4-71.2-1.4-71.2s8.4-22.5,38.5-30c13.8-3.7,31-3.1,31-3.1s7.1,59.4,15.7,94.2c7.2,29.2,24.8,77.7,24.8,77.7 S142.5,359.9,125.6,353.9z M425.9,461.5c0,0-6.1,14.5-19.6,15.4c-5.8,0.4-10.3-1.2-10.3-1.2s-0.3-0.1-5.3-2.1l-112.9-55 c0,0-10.9-5.7-12.8-15.6c-2.2-8.1,2.7-18.1,2.7-18.1L322,273c0,0,4.8-9.7,12.2-13c0.6-0.3,2.3-1,4.5-1.5c8.1-2.1,18,2.8,18,2.8 l110.7,53.7c0,0,12.6,5.7,15.3,16.2c1.9,7.4-0.5,14-1.8,17.2C474.6,363.8,425.9,461.5,425.9,461.5z"
></path>
<path
d="M326.8,380.1c-8.2,0.1-15.4,5.8-17.3,13.8c-1.9,8,2,16.3,9.1,20c7.7,4,17.5,1.8,22.7-5.4 c5.1-7.1,4.3-16.9-1.8-23.1l24-49.1c1.5,0.1,3.7,0.2,6.2-0.5c4.1-0.9,7.1-3.6,7.1-3.6c4.2,1.8,8.6,3.8,13.2,6.1 c4.8,2.4,9.3,4.9,13.4,7.3c0.9,0.5,1.8,1.1,2.8,1.9c1.6,1.3,3.4,3.1,4.7,5.5c1.9,5.5-1.9,14.9-1.9,14.9 c-2.3,7.6-18.4,40.6-18.4,40.6c-8.1-0.2-15.3,5-17.7,12.5c-2.6,8.1,1.1,17.3,8.9,21.3c7.8,4,17.4,1.7,22.5-5.3 c5-6.8,4.6-16.3-1.1-22.6c1.9-3.7,3.7-7.4,5.6-11.3c5-10.4,13.5-30.4,13.5-30.4c0.9-1.7,5.7-10.3,2.7-21.3 c-2.5-11.4-12.6-16.7-12.6-16.7c-12.2-7.9-29.2-15.2-29.2-15.2s0-4.1-1.1-7.1c-1.1-3.1-2.8-5.1-3.9-6.3c4.7-9.7,9.4-19.3,14.1-29 c-4.1-2-8.1-4-12.2-6.1c-4.8,9.8-9.7,19.7-14.5,29.5c-6.7-0.1-12.9,3.5-16.1,9.4c-3.4,6.3-2.7,14.1,1.9,19.8 C343.2,346.5,335,363.3,326.8,380.1z"
></path>
</svg>
Contribute
</button>
</div>
</nav>
<script>
const nav = document.getElementById("navbar");
if (nav) {
const joinTrigger = document.getElementById("join-trigger");
if (joinTrigger) {
joinTrigger.addEventListener("click", () => {
window.dispatchEvent(new CustomEvent("open-join-modal"));
});
}
window.addEventListener("scroll", () => {
if (window.scrollY > 50) {
nav.classList.add(
"bg-slate-900/80",
"backdrop-blur-md",
"py-4",
"shadow-xl",
);
nav.classList.remove("bg-transparent", "py-6");
} else {
nav.classList.add("bg-transparent", "py-6");
nav.classList.remove(
"bg-slate-900/80",
"backdrop-blur-md",
"py-4",
"shadow-xl",
);
}
});
}
</script>

View File

@@ -0,0 +1,46 @@
---
const TECH_STACK = [
"MCP",
"Supabase",
"Gemini",
"Claude",
"UCP",
"Agent-to-Agent",
"OpenAI",
"LangChain",
"VectorDB",
"LlamaIndex",
"Pinecone",
];
---
<section class="py-12 border-y border-white/5 bg-slate-800">
<div class="flex overflow-hidden group">
<div
class="flex animate-scroll hover:[animation-play-state:paused] whitespace-nowrap"
>
{
[...TECH_STACK, ...TECH_STACK].map((tech) => (
<div class="mx-8 px-6 py-2 rounded-full border border-slate-800 bg-slate-800/30 text-slate-400 font-mono text-sm flex items-center gap-2 hover:border-indigo-500/50 hover:text-indigo-400 transition-all cursor-default">
<div class="w-1.5 h-1.5 rounded-full bg-indigo-500/50" />
{tech}
</div>
))
}
</div>
</div>
</section>
<style>
@keyframes scroll {
0% {
transform: translateX(0);
}
100% {
transform: translateX(-50%);
}
}
.animate-scroll {
animation: scroll 30s linear infinite;
}
</style>

View File

@@ -0,0 +1,70 @@
import { useState } from 'react';
import { motion } from 'framer-motion';
export const CodeWindow = () => {
const [lines] = useState([
{ text: "const agent = new BuilderAgent({", color: "text-indigo-400" },
{ text: " protocol: 'MCP',", color: "text-amber-400" },
{ text: " squad: 'Alpha-Team',", color: "text-amber-400" },
{ text: " mission: 'Future-Proof',", color: "text-amber-400" },
{ text: "});", color: "text-indigo-400" },
{ text: "", color: "" },
{ text: "await agent.startBuilding();", color: "text-emerald-400" }
]);
return (
<div className="bg-[#0f172a] rounded-xl border border-slate-700 overflow-hidden shadow-2xl h-full flex flex-col font-mono text-sm">
<div className="flex items-center gap-2 px-4 py-3 bg-slate-800/50 border-b border-slate-700">
<div className="flex gap-1.5">
<div className="w-3 h-3 rounded-full bg-red-500/50" />
<div className="w-3 h-3 rounded-full bg-amber-500/50" />
<div className="w-3 h-3 rounded-full bg-emerald-500/50" />
</div>
<div className="ml-4 text-slate-500 text-xs tracking-wider">BUILDER_SQUAD_01.ts</div>
</div>
<div className="p-6 flex-1 relative">
<div className="space-y-2">
{lines.map((line, i) => (
<motion.div
key={i}
initial={{ opacity: 0, x: -10 }}
animate={{ opacity: 1, x: 0 }}
transition={{ delay: i * 0.1 }}
className="flex gap-4"
>
<span className="text-slate-600 w-4 text-right select-none">{i + 1}</span>
<span className={line.color}>{line.text}</span>
</motion.div>
))}
</div>
{/* Animated Cursors */}
<motion.div
animate={{ x: [0, 40, -20, 0], y: [0, 60, 20, 0] }}
transition={{ duration: 8, repeat: Infinity, ease: "easeInOut" }}
className="absolute top-20 left-40"
>
<div className="relative group">
<div className="w-1 h-5 bg-amber-400" />
<div className="absolute left-1 top-0 bg-amber-400 text-[#1E293B] text-[10px] px-1.5 py-0.5 rounded-sm whitespace-nowrap font-bold">
Priya_Dev
</div>
</div>
</motion.div>
<motion.div
animate={{ x: [0, -30, 40, 0], y: [0, -20, 80, 0] }}
transition={{ duration: 12, repeat: Infinity, ease: "easeInOut", delay: 1 }}
className="absolute top-10 left-60"
>
<div className="relative group">
<div className="w-1 h-5 bg-indigo-400" />
<div className="absolute left-1 top-0 bg-indigo-400 text-white text-[10px] px-1.5 py-0.5 rounded-sm whitespace-nowrap font-bold">
Arjun_AI
</div>
</div>
</motion.div>
</div>
</div>
);
};

View File

@@ -0,0 +1,117 @@
import { ArrowRight } from 'lucide-react';
import { ProfileCard, type Profile } from './ProfileCard';
const PROFILES: Profile[] = [
{
name: "The Student",
role: "Future-Proofing the Degree",
story: "Universities teach theory; the market demands shipping. Stop worrying about your GPA and start building an Agent portfolio that makes recruiters ignore your grades.",
badge: "Portfolio Builder",
image: "https://images.unsplash.com/photo-1539571696357-5a69c17a67c6?w=400&h=400&fit=crop",
},
{
name: "The IT Professional",
role: "Surviving the Shift",
story: "Afraid of AI automating your services job? Don't compete with it—manage it. Pivot from 'Legacy Maintenance' to 'AI Infrastructure Lead' by mastering MCP.",
badge: "AI Architect",
image: "https://images.unsplash.com/photo-1494790108377-be9c29b29330?w=400&h=400&fit=crop",
},
{
name: "The Founder",
role: "Building an AI Workforce",
story: "Overwhelmed by the speed of tech? Stop hiring expensive agencies. Use our Squads to build your own custom AI tools and ship your MVP in weeks, not months.",
badge: "Solo Shipper",
image: "https://images.unsplash.com/photo-1472099645785-5658abf4ff4e?w=400&h=400&fit=crop",
},
];
export const Community = () => {
return (
<section className="py-24">
<div className="container mx-auto px-6">
<div className="flex flex-col md:flex-row justify-between items-end mb-16 gap-6">
<div className="max-w-xl">
<h2 className="text-4xl font-bold font-heading mb-4 text-white">
From Anxiety to Action
</h2>
<p className="text-slate-400 font-sans">
The Gym is open for everyone. Whether you are starting out or leveling up, you have a
squad waiting for you.
</p>
</div>
<button className="text-amber-500 font-bold flex items-center gap-2 hover:text-amber-400 transition-colors cursor-pointer">
See all alumni <ArrowRight size={18} />
</button>
</div>
<div className="grid md:grid-cols-3 gap-8">
{PROFILES.map((profile, i) => (
<ProfileCard key={i} profile={profile} />
))}
</div>
<div
id="build-season"
className="mt-20 p-12 rounded-[2rem] bg-gradient-to-br from-indigo-600/20 to-amber-600/10 border border-white/10 relative overflow-hidden scroll-mt-32"
>
<div className="relative z-10 flex flex-col md:flex-row items-center gap-10">
<div className="flex-1">
<h3 className="text-3xl font-bold font-heading mb-4 text-white">
Build Season #01 is approaching. 📣
</h3>
<p className="text-slate-300 text-lg mb-8 max-w-lg font-sans">
Don't build alone. Join a Squad of 4-5 builders to ship your first MCP Agent in 6
weeks. Whether you are a student looking for a portfolio piece or a pro updating
your skillsyour Squad keeps you shipping.
</p>
<div className="flex flex-wrap gap-4">
<a
href="/apply-season"
className="bg-white text-slate-900 font-bold px-8 py-4 rounded-xl hover:bg-slate-200 transition-all cursor-pointer inline-block"
>
Apply for Season #01
</a>
<div className="flex items-center gap-4 px-6 text-sm text-slate-400 border-l border-white/10">
<div className="flex flex-col">
<span className="font-bold text-white uppercase tracking-widest text-[10px]">
START DATE
</span>
<span>TBD</span>
</div>
</div>
</div>
</div>
<div className="hidden lg:grid grid-cols-2 gap-4 flex-shrink-0">
<div className="p-4 bg-slate-900/60 rounded-xl border border-white/5 text-center">
<div className="text-2xl font-bold text-amber-500">Build an MCP Server</div>
<div className="text-[10px] text-slate-500 uppercase font-bold tracking-widest">
CURRENT MISSION
</div>
</div>
<div className="p-4 bg-slate-900/60 rounded-xl border border-white/5 text-center">
<div className="text-2xl font-bold text-indigo-400">4-6 Builders</div>
<div className="text-[10px] text-slate-500 uppercase font-bold tracking-widest">
SQUAD SIZE
</div>
</div>
<div className="p-4 bg-slate-900/60 rounded-xl border border-white/5 text-center">
<div className="text-2xl font-bold text-emerald-400">6 Weeks</div>
<div className="text-[10px] text-slate-500 uppercase font-bold tracking-widest">
DURATION
</div>
</div>
<div className="p-4 bg-slate-900/60 rounded-xl border border-white/5 text-center">
<div className="text-2xl font-bold text-purple-400">Free</div>
<div className="text-[10px] text-slate-500 uppercase font-bold tracking-widest">
COST
</div>
</div>
</div>
</div>
{/* Background elements for this section */}
<div className="absolute top-0 right-0 w-full h-full bg-[radial-gradient(circle_at_top_right,rgba(99,102,241,0.1),transparent)] pointer-events-none" />
</div>
</div>
</section>
);
};

View File

@@ -0,0 +1,40 @@
import { Tv, Network, Handshake } from 'lucide-react';
import { GlassCard } from './GlassCard';
export const Features = () => {
return (
<section className="py-24 bg-slate-900/50">
<div className="container mx-auto px-6">
<div className="text-center mb-16">
<h2 className="text-3xl md:text-4xl font-bold font-heading mb-4 text-white">
A Gym for Builders, Not a Classroom
</h2>
<p className="text-slate-400 max-w-2xl mx-auto font-sans">
Skip the generic videos. Join a community where the curriculum is "Building things that
matter."
</p>
</div>
<div className="grid md:grid-cols-3 gap-8">
<GlassCard
icon={Tv}
title="No More Tutorials"
text="Stop gathering 'knowledge' and start building skill. Tutorials make you feel smart while your skills stagnate. We ship from Day 1."
delay={0.1}
/>
<GlassCard
icon={Network}
title="Protocol First"
text="Master the plumbing of the future. Deep dive into Model Context Protocol (MCP), Universal Commerce Protocol (UCP), and Agentic frameworks."
delay={0.2}
/>
<GlassCard
icon={Handshake}
title="Squad Mode"
text="Never build alone. Match with creators who share your stack. Weekly sprints, peer reviews, and collaborative repos."
delay={0.3}
/>
</div>
</div>
</section>
);
};

View File

@@ -0,0 +1,26 @@
import { motion } from 'framer-motion';
import type { LucideIcon } from 'lucide-react';
interface GlassCardProps {
icon: LucideIcon;
title: string;
text: string;
delay?: number;
}
export const GlassCard = ({ icon: Icon, title, text, delay = 0 }: GlassCardProps) => (
<motion.div
initial={{ opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
transition={{ duration: 0.6, delay }}
className="relative group p-8 rounded-2xl border border-white/10 bg-white/5 backdrop-blur-xl hover:bg-white/10 transition-all duration-300"
>
<div className="mb-6 w-12 h-12 flex items-center justify-center rounded-lg bg-indigo-500/20 text-indigo-400 group-hover:scale-110 transition-transform duration-300">
<Icon size={24} />
</div>
<h3 className="text-xl font-bold mb-3 text-white font-heading">{title}</h3>
<p className="text-slate-400 leading-relaxed font-sans">{text}</p>
<div className="absolute inset-0 border-2 border-transparent group-hover:border-indigo-500/30 rounded-2xl transition-all duration-300 pointer-events-none" />
</motion.div>
);

View File

@@ -0,0 +1,137 @@
import { motion } from 'framer-motion';
import { Zap, ChevronRight, Terminal } from 'lucide-react';
import { CodeWindow } from './CodeWindow';
export const Hero = () => {
return (
<section className="relative pt-32 pb-20 overflow-hidden">
{/* Background Grid Pattern */}
<div
className="absolute inset-0 z-0 opacity-10 pointer-events-none"
style={{
backgroundImage: 'radial-gradient(#6366F1 0.5px, transparent 0.5px)',
backgroundSize: '24px 24px',
}}
/>
<div className="absolute top-0 right-0 w-[500px] h-[500px] bg-indigo-500/10 blur-[120px] rounded-full -z-10" />
<div className="absolute bottom-0 left-0 w-[500px] h-[500px] bg-amber-500/5 blur-[120px] rounded-full -z-10" />
<div className="container mx-auto px-6 relative z-10">
<div className="grid grid-cols-1 lg:grid-cols-2 gap-16 items-center">
<motion.div
initial={{ opacity: 0, x: -50 }}
animate={{ opacity: 1, x: 0 }}
transition={{ duration: 0.8 }}
>
<div className="inline-flex items-center gap-2 bg-indigo-500/10 border border-indigo-500/20 px-3 py-1 rounded-full text-indigo-400 text-xs font-bold mb-6 tracking-wide uppercase">
<Zap size={14} /> Future-Proof Your Career
</div>
<h1 className="text-4xl md:text-6xl lg:text-7xl font-bold font-heading leading-[1.1] mb-8 text-white">
Don't Fear the AI. <br />
<span className="text-transparent bg-clip-text bg-gradient-to-r from-amber-400 to-amber-600">
Build with AI.
</span>
</h1>
<p className="text-xl text-slate-400 mb-10 leading-relaxed max-w-xl font-sans">
The safe harbor for developers, students, and founders to stop watching tutorials and
start shipping. Master MCP, UCP, and Agents by building real products together.
</p>
<div className="flex flex-col sm:flex-row gap-4">
<button
onClick={() => {
window.dispatchEvent(
new CustomEvent('open-join-modal', {
detail: { mode: 'opensource' },
})
);
}}
className="w-full sm:w-auto bg-amber-500 hover:bg-amber-400 text-slate-900 font-bold px-8 py-4 rounded-xl transition-all flex items-center justify-center gap-2 group cursor-pointer"
>
Join the Community
</button>
<button className="w-full sm:w-auto border border-slate-700 hover:border-slate-500 bg-white/5 px-8 py-4 rounded-xl font-bold transition-all text-white flex items-center justify-center gap-2 cursor-pointer">
Read Manifesto
</button>
</div>
<div className="mt-12 flex flex-col sm:flex-row items-start sm:items-center gap-6">
<div className="flex -space-x-3">
{[1, 2, 3, 4].map((i) => (
<div
key={i}
className="w-10 h-10 rounded-full border-2 border-slate-900 bg-slate-700 flex items-center justify-center overflow-hidden"
>
<img
src={`https://api.dicebear.com/7.x/avataaars/svg?seed=${i + 123}`}
alt="avatar"
className="w-full h-full object-cover"
/>
</div>
))}
<div className="w-10 h-10 rounded-full border-2 border-slate-900 bg-indigo-600 flex items-center justify-center text-[10px] font-bold text-white">
+
</div>
</div>
<div className="flex flex-col sm:flex-row sm:items-center gap-2 sm:gap-0">
<p
className="text-sm text-slate-500 flex items-center gap-2"
style={{
fontWeight: '400',
fontStyle: 'normal',
color: '#90a1b9',
}}
>
Join the Founding Class of 2026
</p>
<button
onClick={() => {
const buildSection = document.getElementById('build-season');
buildSection?.scrollIntoView({
behavior: 'smooth',
block: 'center',
});
}}
className="inline-flex items-center gap-1 px-3 py-1 rounded-full bg-amber-500/10 border border-amber-500/20 text-amber-500 text-xs font-bold hover:bg-amber-500/20 transition-all cursor-pointer sm:ml-2"
>
Learn More <ChevronRight size={14} />
</button>
</div>
</div>
</motion.div>
<motion.div
initial={{ opacity: 0, scale: 0.9 }}
animate={{ opacity: 1, scale: 1 }}
transition={{ duration: 0.8, delay: 0.2 }}
className="relative mt-12 lg:mt-0"
>
<div className="relative z-10">
<CodeWindow />
</div>
{/* Decorative elements */}
<div className="absolute -top-12 -right-8 w-64 h-64 bg-indigo-500/20 rounded-full blur-[80px] -z-10" />
<div className="absolute -bottom-8 -left-12 w-48 h-48 bg-amber-500/10 rounded-full blur-[60px] -z-10" />
{/* Floating Badge */}
<motion.div
animate={{ y: [0, -10, 0] }}
transition={{ duration: 4, repeat: Infinity, ease: 'easeInOut' }}
className="absolute -bottom-6 right-10 z-20 bg-slate-800 border border-slate-700 p-4 rounded-xl shadow-2xl flex items-center gap-3"
>
<div className="p-2 bg-amber-500/10 text-amber-500 rounded-lg">
<Terminal size={20} />
</div>
<div>
<div className="text-[10px] text-slate-500 uppercase font-bold tracking-widest">
Active Stack
</div>
<div className="text-sm font-bold text-white">Gemini 3 Pro + MCP</div>
</div>
</motion.div>
</motion.div>
</div>
</div>
</section>
);
};

View File

@@ -0,0 +1,179 @@
import { useState, useEffect } from "react";
import { motion, AnimatePresence } from "framer-motion";
import { X, Check } from "lucide-react";
export const JoinModal = () => {
const [isOpen, setIsOpen] = useState(false);
const [isSubmitted, setIsSubmitted] = useState(false);
const [contentMode, setContentMode] = useState<'default' | 'opensource'>('default');
const [source, setSource] = useState('gitea_contribute');
useEffect(() => {
const handleOpen = (event: CustomEvent) => {
const mode = event.detail?.mode || 'default';
setContentMode(mode);
setSource(mode === 'opensource' ? 'community_join' : 'gitea_contribute');
setIsOpen(true);
};
window.addEventListener("open-join-modal", handleOpen as EventListener);
return () => window.removeEventListener("open-join-modal", handleOpen as EventListener);
}, []);
const handleSubmit = (e: React.FormEvent) => {
// Allow default form submission for Netlify to handle redirect
setIsSubmitted(true);
};
return (
<AnimatePresence>
{isOpen && (
<div className="fixed inset-0 z-[100] flex items-center justify-center px-4">
<motion.div
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
exit={{ opacity: 0 }}
onClick={() => setIsOpen(false)}
className="absolute inset-0 bg-slate-950/80 backdrop-blur-sm"
/>
<motion.div
initial={{ opacity: 0, scale: 0.95, y: 20 }}
animate={{ opacity: 1, scale: 1, y: 0 }}
exit={{ opacity: 0, scale: 0.95, y: 20 }}
className="relative z-10 w-full max-w-2xl bg-slate-900 border border-white/10 rounded-2xl shadow-2xl overflow-hidden"
>
<div className="absolute top-4 right-4 z-20">
<button
onClick={() => setIsOpen(false)}
className="p-2 text-slate-400 hover:text-white hover:bg-white/10 rounded-full transition-colors cursor-pointer"
>
<X size={20} />
</button>
</div>
<div className="flex flex-col md:flex-row h-full">
{/* Content Side */}
<div className="p-8 md:p-10 flex-1">
<h2 className="text-3xl font-bold font-heading text-white mb-6">
{contentMode === 'opensource' ? "Build on Open Ground." : "Claim Your Locker."}
</h2>
<div className="space-y-4 text-slate-300 text-sm leading-relaxed mb-8">
<p>
{contentMode === 'opensource'
? "We believe in tools that grant freedom, not locked gardens. Join a network of builders who value ownership over convenience."
: "We don't build on rented land. While the rest of the world relies on centralized platforms, we host our own infrastructure."}
</p>
<div>
<h4 className="font-bold text-white mb-1">
{contentMode === 'opensource' ? "Why Open Source?" : "Why Gitea?"}
</h4>
<ul className="space-y-2 list-disc pl-4 marker:text-amber-500">
{contentMode === 'opensource' ? (
<>
<li>
<b className="text-slate-200">Transparency:</b> Code that can be audited, trusted, and improved by everyone. No black boxes.
</li>
<li>
<b className="text-slate-200">Collaboration:</b> A global community of builders pushing the boundaries together.
</li>
<li>
<b className="text-slate-200">Longevity:</b> Software that survives its creators. We build for the long game.
</li>
</>
) : (
<>
<li>
<b className="text-slate-200">Sovereignty:</b> We own our data, our code, and our community. No corporate shutdowns or VC pivots.
</li>
<li>
<b className="text-slate-200">Focus:</b> A noise-free environment designed purely for shipping products. No vanity metrics, just commits.
</li>
<li>
<b className="text-slate-200">The Badge:</b> Access is earned. having an <code className="bg-slate-800 px-1 py-0.5 rounded text-indigo-400">movecompeteplay gitea access</code> is a mark of a serious builder.
</li>
</>
)}
</ul>
</div>
<blockquote className="hidden md:block border-l-2 border-amber-500 pl-4 italic text-slate-400 my-4">
{contentMode === 'opensource'
? "\"Open source is not just a license; it's a statement of independence.\""
: "\"The code won't write itself. The servers won't maintain themselves. We do it the hard way because it's the right way.\""}
</blockquote>
</div>
<form
name="join-community"
method="POST"
action="/success"
data-netlify="true"
netlify-honeypot="bot-field"
className="space-y-4"
>
<input type="hidden" name="form-name" value="join-community" />
<input type="hidden" name="source" value={source} />
<p className="hidden">
<label>
Dont fill this out if youre human: <input name="bot-field" />
</label>
</p>
<div className="flex flex-col md:flex-row gap-4">
<div className="flex-1">
<label htmlFor="email" className="block text-xs font-bold text-slate-500 uppercase tracking-widest mb-2">
Email Address
</label>
<input
name="email"
type="email"
id="email"
required
placeholder="builder@example.com"
className="w-full bg-slate-950 border border-slate-700 rounded-xl px-4 py-3 text-white placeholder:text-slate-600 focus:outline-none focus:border-amber-500 transition-colors"
/>
</div>
<div className="flex-1">
<label htmlFor="social" className="block text-xs font-bold text-slate-500 uppercase tracking-widest mb-2">
LinkedIn / Twitter URL
</label>
<input
name="social"
type="url"
id="social"
placeholder="twitter.com/builder"
className="w-full bg-slate-950 border border-slate-700 rounded-xl px-4 py-3 text-white placeholder:text-slate-600 focus:outline-none focus:border-amber-500 transition-colors"
/>
</div>
</div>
<div>
<label htmlFor="project" className="block text-xs font-bold text-slate-500 uppercase tracking-widest mb-2">
What will you build?
</label>
<input
name="project"
type="text"
id="project"
required
placeholder="A new agent framework..."
className="w-full bg-slate-950 border border-slate-700 rounded-xl px-4 py-3 text-white placeholder:text-slate-600 focus:outline-none focus:border-amber-500 transition-colors"
/>
</div>
<button
type="submit"
className="w-full bg-amber-500 hover:bg-amber-400 text-slate-900 font-bold py-4 rounded-xl transition-all hover:scale-[1.02] active:scale-[0.98] shadow-lg shadow-amber-500/20 cursor-pointer"
>
Request Access
</button>
</form>
</div>
</div>
</motion.div>
</div>
)}
</AnimatePresence>
);
};

View File

@@ -0,0 +1,31 @@
import { motion } from 'framer-motion';
export interface Profile {
name: string;
role: string;
story: string;
badge: string;
image: string;
}
export const ProfileCard = ({ profile }: { profile: Profile }) => (
<motion.div
whileHover={{ y: -5 }}
className="bg-slate-800/40 border border-slate-700/50 p-6 rounded-2xl flex flex-col items-center text-center group"
>
<div className="relative mb-6">
<div className="w-24 h-24 rounded-full overflow-hidden border-2 border-indigo-500/30 group-hover:border-indigo-400 transition-colors">
<img src={profile.image} alt={profile.name} className="w-full h-full object-cover" />
</div>
<div
className="absolute -bottom-2 -right-2 bg-amber-500 text-[#1E293B] text-[10px] font-bold px-2 py-1 rounded-full uppercase tracking-tighter shadow-lg"
style={{ fontSize: "9px" }}
>
{profile.badge}
</div>
</div>
<h4 className="text-white font-bold text-lg mb-1">{profile.name}</h4>
<p className="text-indigo-400 text-sm font-mono mb-4">{profile.role}</p>
<p className="text-slate-400 text-sm italic">"{profile.story}"</p>
</motion.div>
);

29
src/layouts/Layout.astro Normal file
View File

@@ -0,0 +1,29 @@
---
import "../styles/global.css";
interface Props {
title: string;
}
const { title } = Astro.props;
---
<!doctype html>
<html lang="en" class="dark">
<head>
<meta charset="UTF-8" />
<meta
name="description"
content="Move. Compete. Play. — The future belongs to the builders."
/>
<meta name="viewport" content="width=device-width" />
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
<meta name="generator" content={Astro.generator} />
<title>{title}</title>
</head>
<body
class="bg-background text-foreground font-sans min-h-screen selection:bg-amber-500/30 selection:text-amber-200"
>
<slot />
</body>
</html>

6
src/lib/utils.ts Normal file
View File

@@ -0,0 +1,6 @@
import { type ClassValue, clsx } from 'clsx';
import { twMerge } from 'tailwind-merge';
export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs));
}

View File

@@ -0,0 +1,233 @@
---
import Layout from "../layouts/Layout.astro";
---
<Layout title="Draft Day: Season #01 - Move. Compete. Play.">
<div class="min-h-screen bg-slate-950 py-20 px-4 md:px-0">
<div class="container mx-auto max-w-2xl">
{/* Header */}
<div class="mb-12">
<div
class="inline-flex items-center gap-2 bg-amber-500/10 border border-amber-500/20 px-3 py-1 rounded-full text-amber-500 text-xs font-bold mb-6 tracking-wide uppercase"
>
Cohort #01 Applications Open
</div>
<h1
class="text-4xl md:text-5xl font-bold font-heading text-white mb-6"
>
Draft Day: Season #01
</h1>
<p class="text-xl text-slate-400 font-sans mb-8">
6 Weeks. 1 Squad. 1 Shipped Product.
</p>
<blockquote
class="border-l-4 border-indigo-500 pl-6 py-2 italic text-slate-300 bg-indigo-500/5 rounded-r-xl"
>
"We curate teams based on skill, timezone, and ambition. You
are not just joining a server; you are joining a roster."
</blockquote>
</div>
{/* Form */}
<form
name="draft-application"
method="POST"
action="/success"
data-netlify="true"
netlify-honeypot="bot-field"
class="space-y-12 bg-slate-900/50 p-8 md:p-12 rounded-3xl border border-white/5"
>
<input
type="hidden"
name="form-name"
value="draft-application"
/>
<p class="hidden">
<label>
Dont fill this out if youre human: <input
name="bot-field"
/>
</label>
</p>
{/* 1. Identity */}
<div class="space-y-6">
<h2
class="text-2xl font-bold text-white border-b border-white/10 pb-4"
>
1. Identity
</h2>
<div class="grid md:grid-cols-2 gap-6">
<div class="space-y-2">
<label
for="pilot-name"
class="block text-xs font-bold text-slate-400 uppercase tracking-widest"
>
Pilot Name
</label>
<input
type="text"
id="pilot-name"
name="pilot-name"
required
class="w-full bg-slate-950 border border-slate-700 rounded-xl px-4 py-3 text-white placeholder:text-slate-600 focus:outline-none focus:border-amber-500 transition-colors"
placeholder="Callsign"
/>
</div>
<div class="space-y-2">
<label
for="email"
class="block text-xs font-bold text-slate-400 uppercase tracking-widest"
>
Comms (Email)
</label>
<input
type="email"
id="email"
name="email"
required
class="w-full bg-slate-950 border border-slate-700 rounded-xl px-4 py-3 text-white placeholder:text-slate-600 focus:outline-none focus:border-amber-500 transition-colors"
placeholder="hacker@example.com"
/>
</div>
</div>
</div>
{/* 2. Squad Fit */}
<div class="space-y-6">
<h2
class="text-2xl font-bold text-white border-b border-white/10 pb-4"
>
2. Squad Fit
</h2>
<div class="space-y-4">
<label
class="block text-xs font-bold text-slate-400 uppercase tracking-widest"
>
What is your Primary Role?
</label>
<div class="space-y-3">
<label
class="flex items-start gap-3 p-4 bg-slate-950 rounded-xl border border-slate-800 cursor-pointer hover:border-amber-500/50 transition-colors group"
>
<input
type="radio"
name="role"
value="engineer"
required
class="mt-1 text-amber-500 focus:ring-amber-500 bg-slate-900 border-slate-700"
/>
<div>
<div
class="font-bold text-white group-hover:text-amber-500 transition-colors"
>
Engineer
</div>
<div class="text-sm text-slate-400">
Full Stack, Backend, AI
</div>
</div>
</label>
<label
class="flex items-start gap-3 p-4 bg-slate-950 rounded-xl border border-slate-800 cursor-pointer hover:border-amber-500/50 transition-colors group"
>
<input
type="radio"
name="role"
value="designer"
required
class="mt-1 text-amber-500 focus:ring-amber-500 bg-slate-900 border-slate-700"
/>
<div>
<div
class="font-bold text-white group-hover:text-amber-500 transition-colors"
>
Designer
</div>
<div class="text-sm text-slate-400">
UI/UX, Frontend Polish
</div>
</div>
</label>
<label
class="flex items-start gap-3 p-4 bg-slate-950 rounded-xl border border-slate-800 cursor-pointer hover:border-amber-500/50 transition-colors group"
>
<input
type="radio"
name="role"
value="operator"
required
class="mt-1 text-amber-500 focus:ring-amber-500 bg-slate-900 border-slate-700"
/>
<div>
<div
class="font-bold text-white group-hover:text-amber-500 transition-colors"
>
Operator
</div>
<div class="text-sm text-slate-400">
PM, Growth, Documentation
</div>
</div>
</label>
</div>
</div>
<div class="space-y-2">
<label
for="tech-stack"
class="block text-xs font-bold text-slate-400 uppercase tracking-widest"
>
Your Tech Stack
</label>
<input
type="text"
id="tech-stack"
name="tech-stack"
required
class="w-full bg-slate-950 border border-slate-700 rounded-xl px-4 py-3 text-white placeholder:text-slate-600 focus:outline-none focus:border-amber-500 transition-colors"
placeholder="e.g., Next.js, Python/FastAPI, Flutter"
/>
<p class="text-xs text-slate-500">
Be specific so we can match you with compatible
builders.
</p>
</div>
</div>
{/* 3. The Pledge */}
<div class="space-y-6">
<h2
class="text-2xl font-bold text-white border-b border-white/10 pb-4"
>
3. The Pledge
</h2>
<label
class="flex items-start gap-4 p-4 bg-amber-500/5 border border-amber-500/20 rounded-xl cursor-pointer"
>
<input
type="checkbox"
name="pledge"
required
class="mt-1 w-5 h-5 text-amber-500 rounded focus:ring-amber-500 bg-slate-900 border-slate-700"
/>
<span class="text-slate-300 text-sm leading-relaxed">
I commit to the 6-week sprint. I understand that if
I ghost my squad, I will be banned from future
seasons. This is a team sport.
</span>
</label>
</div>
{/* 4. CTA */}
<button
type="submit"
class="w-full bg-amber-500 hover:bg-amber-400 text-slate-900 font-bold py-5 text-lg rounded-xl transition-all hover:scale-[1.01] active:scale-[0.99] shadow-lg shadow-amber-500/20 cursor-pointer flex items-center justify-center gap-2"
>
Submit Application <span class="text-xl">-></span>
</button>
</form>
</div>
</div>
</Layout>

View File

@@ -1,17 +1,22 @@
--- ---
import Layout from "../layouts/Layout.astro";
import Navbar from "../components/Navbar.astro";
import Footer from "../components/Footer.astro";
import TechMarquee from "../components/TechMarquee.astro";
import { Hero } from "../components/react/Hero";
import { Features } from "../components/react/Features";
import { Community } from "../components/react/Community";
import { JoinModal } from "../components/react/JoinModal";
---
--- <Layout title="Move. Compete. Play. — The future belongs to the builders.">
<Navbar />
<html lang="en"> <JoinModal client:load />
<head> <main>
<meta charset="utf-8" /> <Hero client:load />
<link rel="icon" type="image/svg+xml" href="/favicon.svg" /> <Features client:visible />
<link rel="icon" href="/favicon.ico" /> <TechMarquee />
<meta name="viewport" content="width=device-width" /> <Community client:visible />
<meta name="generator" content={Astro.generator} /> </main>
<title>Astro</title> <Footer />
</head> </Layout>
<body>
<h1>Astro</h1>
</body>
</html>

51
src/pages/success.astro Normal file
View File

@@ -0,0 +1,51 @@
---
import Layout from "../layouts/Layout.astro";
import { Check } from "lucide-react";
---
<Layout title="Request Received - Move. Compete. Play.">
<div class="min-h-screen bg-slate-950 flex items-center justify-center p-4">
<div
class="max-w-md w-full bg-slate-900 border border-white/10 rounded-2xl p-8 md:p-12 text-center shadow-2xl relative overflow-hidden"
>
{/* Background decoration */}
<div
class="absolute top-0 right-0 w-64 h-64 bg-indigo-500/10 rounded-full blur-[80px] -z-10"
>
</div>
<div
class="absolute bottom-0 left-0 w-48 h-48 bg-amber-500/5 rounded-full blur-[60px] -z-10"
>
</div>
<div
class="w-16 h-16 bg-emerald-500/10 rounded-full flex items-center justify-center mx-auto mb-6 border border-emerald-500/20"
>
<Check class="text-emerald-500" size={32} />
</div>
<h1 class="text-3xl font-bold font-heading text-white mb-4">
You're in the Queue.
</h1>
<div class="space-y-4 text-slate-400 text-sm leading-relaxed mb-8">
<p>
We've received your request for a locker. Our team reviews
every application manually to ensure the quality of the
community.
</p>
<p>
Keep an eye on your inbox. If you have the code, you'll get
the keys.
</p>
</div>
<a
href="/"
class="inline-block w-full bg-amber-500 hover:bg-amber-400 text-slate-900 font-bold py-4 rounded-xl transition-all hover:scale-[1.02] active:scale-[0.98] shadow-lg shadow-amber-500/20 cursor-pointer"
>
Return to Base
</a>
</div>
</div>
</Layout>

View File

@@ -1 +1,142 @@
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=Space+Grotesk:wght@400;500;600;700&display=swap');
@import "tailwindcss"; @import "tailwindcss";
@plugin "tailwindcss-animate";
@custom-variant dark (&:is(.dark *));
@theme inline {
--color-background: var(--background);
--color-foreground: var(--foreground);
--font-sans: "Inter", sans-serif;
--font-heading: "Space Grotesk", sans-serif;
--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: var(--radius-sm);
--radius-md: var(--radius-md);
--radius-lg: var(--radius-lg);
--radius-xl: var(--radius-xl);
}
:root {
--card: #F8FAFC;
--ring: #FE9A00;
--input: #E2E8F0;
--muted: #CBD5E1;
--accent: #FE9A00;
--border: #E2E8F0;
--chart-1: #293445;
--chart-2: #FE9A00;
--chart-3: #10B981;
--chart-4: #F59E0B;
--chart-5: #3B82F6;
--popover: #FFFFFF;
--primary: #293445;
--sidebar: #F8FAFC;
--secondary: #E2E8F0;
--background: #FFFFFF;
--foreground: #1E293B;
--destructive: #EF4444;
--sidebar-ring: #FE9A00;
--sidebar-accent: #FE9A00;
--sidebar-border: #E2E8F0;
--card-foreground: #1E293B;
--sidebar-primary: #293445;
--muted-foreground: #64748B;
--accent-foreground: #1E293B;
--popover-foreground: #1E293B;
--primary-foreground: #FFFFFF;
--sidebar-foreground: #1E293B;
--secondary-foreground: #1E293B;
--destructive-foreground: #FFFFFF;
--sidebar-accent-foreground: #1E293B;
--sidebar-primary-foreground: #FFFFFF;
--radius: 0rem;
--shadow: 0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1);
--font-body: Inter;
--radius-lg: 0.875rem;
--radius-md: 0.5rem;
--radius-sm: 0.25rem;
--radius-xl: 1rem;
--shadow-lg: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1);
--shadow-md: 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1);
--shadow-sm: 0 1px 2px 0 rgb(0 0 0 / 0.05);
--shadow-xl: 0 20px 25px -5px rgb(0 0 0 / 0.1), 0 8px 10px -6px rgb(0 0 0 / 0.1);
--shadow-2xl: 0 25px 50px -12px rgb(0 0 0 / 0.25);
--font-heading: Space Grotesk;
}
.dark {
--card: #293445;
--ring: #FE9A00;
--input: #334155;
--muted: #475569;
--accent: #FE9A00;
--border: #334155;
--chart-1: #293445;
--chart-2: #FE9A00;
--chart-3: #34D399;
--chart-4: #FBBF24;
--chart-5: #60A5FA;
--popover: #293445;
--primary: #293445;
--sidebar: #1E293B;
--secondary: #334155;
--background: #1E293B;
--foreground: #F1F5F9;
--destructive: #DC2626;
--sidebar-ring: #FE9A00;
--sidebar-accent: #FE9A00;
--sidebar-border: #334155;
--card-foreground: #F1F5F9;
--sidebar-primary: #293445;
--muted-foreground: #CBD5E1;
--accent-foreground: #1E293B;
--popover-foreground: #F1F5F9;
--primary-foreground: #FFFFFF;
--sidebar-foreground: #F1F5F9;
--secondary-foreground: #F1F5F9;
--destructive-foreground: #FFFFFF;
--sidebar-accent-foreground: #1E293B;
--sidebar-primary-foreground: #FFFFFF;
}
@layer base {
* {
@apply border-border outline-ring/50;
}
body {
@apply bg-background text-foreground;
font-family: var(--font-body);
}
h1, h2, h3, h4, h5, h6 {
font-family: var(--font-heading);
}
}

74
syleguide.md Normal file
View File

@@ -0,0 +1,74 @@
# Move. Compete. Play. — Design System
**Version:** 1.0 (MVP)
**Theme:** Warm Futurism / The Developer Gym
**Vibe:** Dark, focused, high-performance, but welcoming. Think "Nike Pro meets VS Code."
---
## 1. Color Palette
### **Primary (The Gym Floor)**
* **Slate 950 (`#020617`):** The main background. Deep, infinite, focused.
* **Slate 900 (`#0f172a`):** Surface / Cards. Slightly elevated to create depth.
* **Slate 50 (`#f8fafc`):** Primary Text. High contrast but not harsh white.
### **Accent (The Energy)**
* **Amber 500 (`#f59e0b`):** "The Spark." Used for primary buttons, active states, and key highlights.
* **Amber 400 (`#fbbf24`):** Hover states and glowing text effects.
* **Emerald 500 (`#10b981`):** "Success." Used for passing tests, deployed status, and growth metrics.
### **Gradients (The Atmosphere)**
* **The Warm Glow:** `bg-gradient-to-r from-amber-500/20 to-transparent` (Used for background blobs).
* **The Glass Surface:** `bg-slate-900/50 backdrop-blur-md border border-slate-800` (Used for HUDs and floating navs).
---
## 2. Typography
**Font Family:** `Inter` (Sans-serif) for UI / `Calistoga` (Serif) for Headlines (Optional).
* **H1 (Hero):** Text-5xl / Bold / Tight Tracking.
* *Usage:* Landing page main statement.
* **H2 (Section):** Text-3xl / Semibold.
* *Usage:* "Build Seasons," "Leaderboard."
* **Body:** Text-base / Text-slate-400.
* *Usage:* Paragraphs. Easy to read, low eye strain.
* **Mono:** `JetBrains Mono` or `Fira Code`.
* *Usage:* Code snippets, terminal outputs, and data values.
---
## 3. Core Components
### **Buttons**
* **Primary (Action):**
* `bg-amber-500 text-slate-950 font-bold px-6 py-3 rounded-lg hover:bg-amber-400 transition-all`
* *Effect:* Subtle shadow glow on hover.
* **Secondary (Ghost):**
* `border border-slate-700 text-slate-300 px-6 py-3 rounded-lg hover:border-slate-500 hover:text-white transition-all`
### **Cards (Bento Grid Style)**
* **Container:** `bg-slate-900 border border-slate-800 rounded-xl p-6`
* **Hover Effect:** Border color shifts to `slate-600` or subtle `amber-500/20` glow.
* **Content:** Icon top-left, heavy bold title, muted description.
### **Badges / Tags**
* **Status (Live):** `bg-green-500/10 text-green-400 border border-green-500/20 rounded-full px-3 py-1 text-xs uppercase tracking-wider`
* **Tag (Tech):** `bg-slate-800 text-slate-400 border border-slate-700 rounded-md px-2 py-1 text-xs font-mono`
---
## 4. Imagery & Effects
* **Noise Texture:** A subtle grain overlay (5% opacity) to prevent the dark background from looking "flat."
* **Glow Orbs:** Blurred circles of Amber or Indigo positioned behind text to separate it from the background.
* **Grid Lines:** Very faint (`slate-800/50`) background grid patterns to reinforce the "engineering" aesthetic.
---
## 5. Tone of Voice
* **Direct & Action-Oriented:** "Ship Code," "Deploy Now," "Join the League."
* **No Fluff:** Avoid corporate jargon like "synergy" or "innovative solutions."
* **Encouraging but Tough:** "The code won't write itself." / "Respect the grind."

24
ui_mockup/.gitignore vendored Normal file
View File

@@ -0,0 +1,24 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*
node_modules
dist
dist-ssr
*.local
# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?

30
ui_mockup/.prettierignore Normal file
View File

@@ -0,0 +1,30 @@
# Build outputs
dist/
build/
out/
# Dependencies
node_modules/
# Logs
*.log
# Cache
.eslintcache
.cache/
# Coverage
coverage/
# Misc
.DS_Store
.env*
!.env.example
# Debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# TypeScript
*.tsbuildinfo

10
ui_mockup/.prettierrc Normal file
View File

@@ -0,0 +1,10 @@
{
"semi": true,
"singleQuote": true,
"tabWidth": 2,
"trailingComma": "es5",
"printWidth": 100,
"bracketSpacing": true,
"arrowParens": "avoid",
"endOfLine": "lf"
}

21
ui_mockup/components.json Normal file
View File

@@ -0,0 +1,21 @@
{
"$schema": "https://ui.shadcn.com/schema.json",
"style": "new-york",
"rsc": false,
"tsx": true,
"tailwind": {
"config": "",
"css": "src/index.css",
"baseColor": "neutral",
"cssVariables": true,
"prefix": ""
},
"aliases": {
"components": "@/components",
"utils": "@/lib/utils",
"ui": "@/components/ui",
"lib": "@/lib",
"hooks": "@/hooks"
},
"iconLibrary": "lucide"
}

View File

@@ -0,0 +1,26 @@
import js from '@eslint/js';
import globals from 'globals';
import reactHooks from 'eslint-plugin-react-hooks';
import reactRefresh from 'eslint-plugin-react-refresh';
import tseslint from 'typescript-eslint';
export default tseslint.config(
{ ignores: ['dist'] },
{
extends: [js.configs.recommended, ...tseslint.configs.recommended],
files: ['**/*.{ts,tsx}'],
languageOptions: {
ecmaVersion: 2020,
globals: globals.browser,
},
plugins: {
'react-hooks': reactHooks,
'react-refresh': reactRefresh,
},
rules: {
...reactHooks.configs.recommended.rules,
'react-refresh/only-export-components': ['warn', { allowConstantExport: true }],
'@typescript-eslint/no-unused-vars': 'off',
},
}
);

12
ui_mockup/index.html Normal file
View File

@@ -0,0 +1,12 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Move Compete Play Landing</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.tsx"></script>
</body>
</html>

65
ui_mockup/package.json Normal file
View File

@@ -0,0 +1,65 @@
{
"name": "component-forge",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "tsc -b && vite build",
"lint": "eslint .",
"preview": "vite preview",
"format": "prettier --write .",
"format:check": "prettier --check ."
},
"dependencies": {
"@dnd-kit/core": "^6.3.1",
"@dnd-kit/modifiers": "^9.0.0",
"@dnd-kit/sortable": "^10.0.0",
"@headless-tree/core": "^1.4.0",
"@headless-tree/react": "^1.4.0",
"@hookform/resolvers": "^5.2.1",
"@react-three/drei": "^10.0.6",
"@react-three/fiber": "^9.1.2",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
"cmdk": "^1.1.1",
"date-fns": "^4.1.0",
"embla-carousel-react": "^8.6.0",
"framer-motion": "^12.4.10",
"input-otp": "^1.4.2",
"lucide-react": "^0.542.0",
"next-themes": "^0.4.6",
"radix-ui": "^1.4.3",
"react": "^19.0.0",
"react-day-picker": "^9.9.0",
"react-dom": "^19.0.0",
"react-hook-form": "^7.62.0",
"react-resizable-panels": "^3.0.5",
"recharts": "2.15.4",
"sonner": "^2.0.7",
"tailwind-merge": "^3.3.1",
"tailwindcss-animate": "^1.0.7",
"three": "^0.175.0",
"uuid": "^11.1.0",
"vaul": "^1.1.2",
"zod": "^4.1.5"
},
"devDependencies": {
"@eslint/js": "^9.21.0",
"@tailwindcss/vite": "^4.0.9",
"@types/node": "^22.13.9",
"@types/react": "^19.0.10",
"@types/react-dom": "^19.0.4",
"@vitejs/plugin-react": "^4.3.4",
"eslint": "^9.21.0",
"eslint-plugin-react-hooks": "^5.1.0",
"eslint-plugin-react-refresh": "^0.4.19",
"globals": "^15.15.0",
"prettier": "3.5.3",
"tailwindcss": "^4.0.9",
"tw-animate-css": "^1.3.7",
"typescript": "~5.7.2",
"typescript-eslint": "^8.24.1",
"vite": "^6.2.0"
}
}

36
ui_mockup/src/App.tsx Normal file
View File

@@ -0,0 +1,36 @@
import { useMemo } from 'react';
import { Container, Theme } from './settings/types';
import { LandingPage } from './components/generated/LandingPage';
let theme: Theme = 'dark';
// only use 'centered' container for standalone components, never for full page apps or websites.
let container: Container = 'none';
function App() {
function setTheme(theme: Theme) {
if (theme === 'dark') {
document.documentElement.classList.add('dark');
} else {
document.documentElement.classList.remove('dark');
}
}
setTheme(theme);
const generatedComponent = useMemo(() => {
// THIS IS WHERE THE TOP LEVEL GENRATED COMPONENT WILL BE RETURNED!
return <LandingPage />; // %EXPORT_STATEMENT%
}, []);
if (container === 'centered') {
return (
<div className="h-full w-full flex flex-col items-center justify-center">
{generatedComponent}
</div>
);
} else {
return generatedComponent;
}
}
export default App;

View File

@@ -0,0 +1,463 @@
import React, { useState, useEffect } from 'react';
import { motion, AnimatePresence } from 'framer-motion';
import { ChevronRight, Tv, Network, Handshake, Users, Code2, Zap, ArrowRight, Terminal, Cpu, Layers, Globe, Rocket, Twitter, Github, Linkedin } from 'lucide-react';
// --- Constants & Types ---
const TECH_STACK = ["MCP", "Supabase", "Gemini", "Claude", "UCP", "Agent-to-Agent", "OpenAI", "LangChain", "VectorDB", "LlamaIndex", "Pinecone"];
const PROFILES = [{
name: "Alex Chen",
role: "Computer Science Student",
story: "From anxious undergrad to shipping an MCP-based task automation agent.",
badge: "Automation Pro",
image: "https://images.unsplash.com/photo-1539571696357-5a69c17a67c6?w=400&h=400&fit=crop"
}, {
name: "Sarah Jenkins",
role: "IT Specialist",
story: "Future-proofed my career by building a private UCP gateway for my company.",
badge: "Infrastructure Lead",
image: "https://images.unsplash.com/photo-1494790108377-be9c29b29330?w=400&h=400&fit=crop"
}, {
name: "Marcus Vane",
role: "SaaS Founder",
story: "Pivoted from legacy software to an AI-first startup using A2A protocols.",
badge: "Serial Founder",
image: "https://images.unsplash.com/photo-1472099645785-5658abf4ff4e?w=400&h=400&fit=crop"
}] as any[];
// --- Sub-components (Internal) ---
const GlassCard = ({
icon: Icon,
title,
text,
delay = 0
}: {
icon: any;
title: string;
text: string;
delay?: number;
}) => <motion.div initial={{
opacity: 0,
y: 20
}} whileInView={{
opacity: 1,
y: 0
}} viewport={{
once: true
}} transition={{
duration: 0.6,
delay
}} className="relative group p-8 rounded-2xl border border-white/10 bg-white/5 backdrop-blur-xl hover:bg-white/10 transition-all duration-300">
<div className="mb-6 w-12 h-12 flex items-center justify-center rounded-lg bg-indigo-500/20 text-indigo-400 group-hover:scale-110 transition-transform duration-300">
<Icon size={24} />
</div>
<h3 className="text-xl font-bold mb-3 text-white font-['Space_Grotesk']">{title}</h3>
<p className="text-slate-400 leading-relaxed font-['Inter']">{text}</p>
<div className="absolute inset-0 border-2 border-transparent group-hover:border-indigo-500/30 rounded-2xl transition-all duration-300 pointer-events-none" />
</motion.div>;
const CodeWindow = () => {
const [lines, setLines] = useState([{
text: "const agent = new BuilderAgent({",
color: "text-indigo-400"
}, {
text: " protocol: 'MCP',",
color: "text-amber-400"
}, {
text: " squad: 'Alpha-Team',",
color: "text-amber-400"
}, {
text: " mission: 'Future-Proof',",
color: "text-amber-400"
}, {
text: "});",
color: "text-indigo-400"
}, {
text: "",
color: ""
}, {
text: "await agent.startBuilding();",
color: "text-emerald-400"
}]);
return <div className="bg-[#0f172a] rounded-xl border border-slate-700 overflow-hidden shadow-2xl h-full flex flex-col font-mono text-sm">
<div className="flex items-center gap-2 px-4 py-3 bg-slate-800/50 border-b border-slate-700">
<div className="flex gap-1.5">
<div className="w-3 h-3 rounded-full bg-red-500/50" />
<div className="w-3 h-3 rounded-full bg-amber-500/50" />
<div className="w-3 h-3 rounded-full bg-emerald-500/50" />
</div>
<div className="ml-4 text-slate-500 text-xs tracking-wider">BUILDER_SQUAD_01.ts</div>
</div>
<div className="p-6 flex-1 relative">
<div className="space-y-2">
{lines.map((line, i) => <motion.div key={i} initial={{
opacity: 0,
x: -10
}} animate={{
opacity: 1,
x: 0
}} transition={{
delay: i * 0.1
}} className="flex gap-4">
<span className="text-slate-600 w-4 text-right select-none">{i + 1}</span>
<span className={line.color}>{line.text}</span>
</motion.div>)}
</div>
{/* Animated Cursors */}
<motion.div animate={{
x: [0, 40, -20, 0],
y: [0, 60, 20, 0]
}} transition={{
duration: 8,
repeat: Infinity,
ease: "easeInOut"
}} className="absolute top-20 left-40">
<div className="relative group">
<div className="w-1 h-5 bg-amber-400" />
<div className="absolute left-1 top-0 bg-amber-400 text-[#1E293B] text-[10px] px-1.5 py-0.5 rounded-sm whitespace-nowrap font-bold">Priya_Dev</div>
</div>
</motion.div>
<motion.div animate={{
x: [0, -30, 40, 0],
y: [0, -20, 80, 0]
}} transition={{
duration: 12,
repeat: Infinity,
ease: "easeInOut",
delay: 1
}} className="absolute top-10 left-60">
<div className="relative group">
<div className="w-1 h-5 bg-indigo-400" />
<div className="absolute left-1 top-0 bg-indigo-400 text-white text-[10px] px-1.5 py-0.5 rounded-sm whitespace-nowrap font-bold">Arjun_AI</div>
</div>
</motion.div>
</div>
</div>;
};
const ProfileCard = ({
profile
}: {
profile: typeof PROFILES[0];
}) => <motion.div whileHover={{
y: -5
}} className="bg-slate-800/40 border border-slate-700/50 p-6 rounded-2xl flex flex-col items-center text-center group">
<div className="relative mb-6">
<div className="w-24 h-24 rounded-full overflow-hidden border-2 border-indigo-500/30 group-hover:border-indigo-400 transition-colors">
<img src={profile.image} alt={profile.name} className="w-full h-full object-cover" />
</div>
<div className="absolute -bottom-2 -right-2 bg-amber-500 text-[#1E293B] text-[10px] font-bold px-2 py-1 rounded-full uppercase tracking-tighter shadow-lg" style={{
fontSize: "9px"
}}>Portfolio Builder</div>
</div>
<h4 className="text-white font-bold text-lg mb-1">The Student</h4>
<p className="text-indigo-400 text-sm font-mono mb-4">Future-Proofing the Degree</p>
<p className="text-slate-400 text-sm italic">"Universities teach theory; the market demands shipping. Stop worrying about your GPA and start building an Agent portfolio that makes recruiters ignore your grades."</p>
</motion.div>;
// @component: LandingPage
export const LandingPage = () => {
const [isScrolled, setIsScrolled] = useState(false);
useEffect(() => {
const handleScroll = () => setIsScrolled(window.scrollY > 50);
window.addEventListener('scroll', handleScroll);
return () => window.removeEventListener('scroll', handleScroll);
}, []);
// @return
return <div className="min-h-screen bg-[#1E293B] text-slate-100 selection:bg-amber-500/30 font-['Inter'] selection:text-amber-200">
{/* Navbar */}
<nav className={`fixed top-0 w-full z-50 transition-all duration-300 ${isScrolled ? 'bg-[#1E293B]/80 backdrop-blur-md py-4 shadow-xl' : 'bg-transparent py-6'}`}>
<div className="container mx-auto px-6 flex items-center justify-between">
<div className="flex items-center gap-2">
<div className="w-8 h-8 bg-amber-500 rounded-lg flex items-center justify-center transform rotate-12">
<Code2 size={18} className="text-[#1E293B]" />
</div>
<span className="text-xl font-bold font-['Space_Grotesk'] tracking-tight">
Move. <span className="text-indigo-400">Compete.</span> Play.
</span>
</div>
<div className="hidden md:flex items-center gap-10">
{['The Mission', 'Build Projects', 'Squads', 'Manifesto'].map(link => <a key={link} href={`#${link.toLowerCase().replace(' ', '-')}`} className="text-sm font-medium text-slate-300 hover:text-amber-400 transition-colors">
{link}
</a>)}
</div>
<button className="bg-amber-500 hover:bg-amber-400 text-[#1E293B] font-bold px-6 py-2.5 rounded-full transition-all hover:scale-105 active:scale-95 shadow-lg shadow-amber-500/20">
Join the Builders
</button>
</div>
</nav>
{/* Hero Section */}
<section className="relative pt-32 pb-20 overflow-hidden">
{/* Background Grid Pattern */}
<div className="absolute inset-0 z-0 opacity-10 pointer-events-none" style={{
backgroundImage: 'radial-gradient(#6366F1 0.5px, transparent 0.5px)',
backgroundSize: '24px 24px'
}} />
<div className="absolute top-0 right-0 w-[500px] h-[500px] bg-indigo-500/10 blur-[120px] rounded-full -z-10" />
<div className="absolute bottom-0 left-0 w-[500px] h-[500px] bg-amber-500/5 blur-[120px] rounded-full -z-10" />
<div className="container mx-auto px-6 relative z-10">
<div className="grid grid-cols-1 lg:grid-cols-2 gap-16 items-center">
<motion.div initial={{
opacity: 0,
x: -50
}} animate={{
opacity: 1,
x: 0
}} transition={{
duration: 0.8
}}>
<div className="inline-flex items-center gap-2 bg-indigo-500/10 border border-indigo-500/20 px-3 py-1 rounded-full text-indigo-400 text-xs font-bold mb-6 tracking-wide uppercase">
<Zap size={14} /> Future-Proof Your Career
</div>
<h1 className="text-4xl md:text-6xl lg:text-7xl font-bold font-['Space_Grotesk'] leading-[1.1] mb-8">
Don't Fear the AI. <br />
<span className="text-transparent bg-clip-text bg-gradient-to-r from-amber-400 to-amber-600">Build with AI.</span>
</h1>
<p className="text-xl text-slate-400 mb-10 leading-relaxed max-w-xl">
The safe harbor for developers, students, and founders to stop watching tutorials and start shipping. Master MCP, UCP, and Agents by building real products together.
</p>
<div className="flex flex-col sm:flex-row gap-4">
<button className="w-full sm:w-auto bg-amber-500 hover:bg-amber-400 text-[#1E293B] font-bold px-8 py-4 rounded-xl transition-all flex items-center justify-center gap-2 group">Join the Community</button>
<button className="w-full sm:w-auto border border-slate-700 hover:border-slate-500 bg-white/5 px-8 py-4 rounded-xl font-bold transition-all text-white flex items-center justify-center gap-2">
Read Manifesto
</button>
</div>
<div className="mt-12 flex items-center gap-6">
<div className="flex -space-x-3">
{[1, 2, 3, 4].map(i => <div key={i} className="w-10 h-10 rounded-full border-2 border-[#1E293B] bg-slate-700 flex items-center justify-center overflow-hidden">
<img src={`https://api.dicebear.com/7.x/avataaars/svg?seed=${i + 123}`} alt="avatar" />
</div>)}
<div className="w-10 h-10 rounded-full border-2 border-[#1E293B] bg-indigo-600 flex items-center justify-center text-[10px] font-bold">+</div>
</div>
<p className="text-sm text-slate-500" style={{
fontWeight: "400",
fontStyle: "normal",
color: "#90a1b9"
}}>
Join the Founding Class of 2026
<button onClick={() => {
const buildSection = document.getElementById('build-season');
buildSection?.scrollIntoView({
behavior: 'smooth',
block: 'center'
});
}} className="ml-2 inline-flex items-center gap-1 px-3 py-1 rounded-full bg-amber-500/10 border border-amber-500/20 text-amber-500 text-xs font-bold hover:bg-amber-500/20 transition-all">
Learn More <ChevronRight size={14} />
</button>
</p>
</div>
</motion.div>
<motion.div initial={{
opacity: 0,
scale: 0.9
}} animate={{
opacity: 1,
scale: 1
}} transition={{
duration: 0.8,
delay: 0.2
}} className="relative mt-12 lg:mt-0">
<div className="relative z-10">
<CodeWindow />
</div>
{/* Decorative elements */}
<div className="absolute -top-12 -right-8 w-64 h-64 bg-indigo-500/20 rounded-full blur-[80px] -z-10" />
<div className="absolute -bottom-8 -left-12 w-48 h-48 bg-amber-500/10 rounded-full blur-[60px] -z-10" />
{/* Floating Badge */}
<motion.div animate={{
y: [0, -10, 0]
}} transition={{
duration: 4,
repeat: Infinity,
ease: "easeInOut"
}} className="absolute -bottom-6 right-10 z-20 bg-slate-800 border border-slate-700 p-4 rounded-xl shadow-2xl flex items-center gap-3">
<div className="p-2 bg-amber-500/10 text-amber-500 rounded-lg">
<Terminal size={20} />
</div>
<div>
<div className="text-[10px] text-slate-500 uppercase font-bold tracking-widest">Active Stack</div>
<div className="text-sm font-bold text-white">Gemini 3 Pro + MCP</div>
</div>
</motion.div>
</motion.div>
</div>
</div>
</section>
{/* Feature Grid */}
<section className="py-24 bg-slate-900/50">
<div className="container mx-auto px-6">
<div className="text-center mb-16">
<h2 className="text-3xl md:text-4xl font-bold font-['Space_Grotesk'] mb-4">A Gym for Builders, Not a Classroom</h2>
<p className="text-slate-400 max-w-2xl mx-auto">Skip the generic videos. Join a community where the curriculum is "Building things that matter."</p>
</div>
<div className="grid md:grid-cols-3 gap-8">
<GlassCard icon={Tv} title="No More Tutorials" text="Stop gathering 'knowledge' and start building skill. Tutorials make you feel smart while your skills stagnate. We ship from Day 1." delay={0.1} />
<GlassCard icon={Network} title="Protocol First" text="Master the plumbing of the future. Deep dive into Model Context Protocol (MCP), Universal Commerce Protocol (UCP), and Agentic frameworks." delay={0.2} />
<GlassCard icon={Handshake} title="Squad Mode" text="Never build alone. Match with creators who share your stack. Weekly sprints, peer reviews, and collaborative repos." delay={0.3} />
</div>
</div>
</section>
{/* Tech Marquee */}
<section className="py-12 border-y border-white/5 bg-[#1E293B]">
<div className="flex overflow-hidden group">
<div className="flex animate-scroll hover:[animation-play-state:paused] whitespace-nowrap">
{[...TECH_STACK, ...TECH_STACK].map((tech, i) => <div key={i} className="mx-8 px-6 py-2 rounded-full border border-slate-800 bg-slate-800/30 text-slate-400 font-mono text-sm flex items-center gap-2 hover:border-indigo-500/50 hover:text-indigo-400 transition-all cursor-default">
<div className="w-1.5 h-1.5 rounded-full bg-indigo-500/50" />
{tech}
</div>)}
</div>
</div>
</section>
{/* Community Spotlight */}
<section className="py-24">
<div className="container mx-auto px-6">
<div className="flex flex-col md:flex-row justify-between items-end mb-16 gap-6">
<div className="max-w-xl">
<h2 className="text-4xl font-bold font-['Space_Grotesk'] mb-4">From Anxiety to Action</h2>
<p className="text-slate-400">The Gym is open for everyone. Whether you are starting out or leveling up, you have a squad waiting for you.</p>
</div>
<button className="text-amber-500 font-bold flex items-center gap-2 hover:text-amber-400 transition-colors">
See all alumni <ArrowRight size={18} />
</button>
</div>
<div className="grid md:grid-cols-3 gap-8">
{PROFILES.map((profile, i) => <ProfileCard key={i} profile={profile} />)}
</div>
<div id="build-season" className="mt-20 p-12 rounded-[2rem] bg-gradient-to-br from-indigo-600/20 to-amber-600/10 border border-white/10 relative overflow-hidden">
<div className="relative z-10 flex flex-col md:flex-row items-center gap-10">
<div className="flex-1">
<h3 className="text-3xl font-bold font-['Space_Grotesk'] mb-4">Build Season #01 is approaching. 📣</h3>
<p className="text-slate-300 text-lg mb-8 max-w-lg">Don't build alone. Join a Squad of 4-5 builders to ship your first MCP Agent in 6 weeks. Whether you are a student looking for a portfolio piece or a pro updating your skillsyour Squad keeps you shipping.</p>
<div className="flex flex-wrap gap-4">
<button className="bg-white text-[#1E293B] font-bold px-8 py-4 rounded-xl hover:bg-slate-200 transition-all">Apply for Season #01</button>
<div className="flex items-center gap-4 px-6 text-sm text-slate-400 border-l border-white/10">
<div className="flex flex-col">
<span className="font-bold text-white uppercase tracking-widest text-[10px]">START DATE</span>
<span>TBD</span>
</div>
</div>
</div>
</div>
<div className="hidden lg:grid grid-cols-2 gap-4 flex-shrink-0">
<div className="p-4 bg-slate-900/60 rounded-xl border border-white/5 text-center">
<div className="text-2xl font-bold text-amber-500">Build an MCP Server</div>
<div className="text-[10px] text-slate-500 uppercase font-bold tracking-widest">CURRENT MISSION</div>
</div>
<div className="p-4 bg-slate-900/60 rounded-xl border border-white/5 text-center">
<div className="text-2xl font-bold text-indigo-400">4-6 Builders</div>
<div className="text-[10px] text-slate-500 uppercase font-bold tracking-widest">SQUAD SIZE</div>
</div>
<div className="p-4 bg-slate-900/60 rounded-xl border border-white/5 text-center">
<div className="text-2xl font-bold text-emerald-400">6 Weeks</div>
<div className="text-[10px] text-slate-500 uppercase font-bold tracking-widest">DURATION</div>
</div>
<div className="p-4 bg-slate-900/60 rounded-xl border border-white/5 text-center">
<div className="text-2xl font-bold text-purple-400">Free</div>
<div className="text-[10px] text-slate-500 uppercase font-bold tracking-widest">COST</div>
</div>
</div>
</div>
{/* Background elements for this section */}
<div className="absolute top-0 right-0 w-full h-full bg-[radial-gradient(circle_at_top_right,rgba(99,102,241,0.1),transparent)] pointer-events-none" />
</div>
</div>
</section>
{/* Footer */}
<footer className="py-20 border-t border-white/5 bg-slate-950">
<div className="container mx-auto px-6">
<div className="grid md:grid-cols-4 gap-12 mb-16">
<div className="col-span-1 md:col-span-2">
<div className="flex items-center gap-2 mb-6">
<div className="w-8 h-8 bg-amber-500 rounded-lg flex items-center justify-center transform rotate-12">
<Code2 size={18} className="text-[#1E293B]" />
</div>
<span className="text-xl font-bold font-['Space_Grotesk'] tracking-tight">
Move. <span className="text-indigo-400">Compete.</span> Play.
</span>
</div>
<p className="text-slate-500 max-w-sm mb-6 leading-relaxed">
The premier hub for tech professionals to transition from AI-anxiety to AI-mastery through building and community.
</p>
<div className="flex gap-4">
<a href="#" className="w-10 h-10 rounded-lg bg-slate-900 border border-slate-800 flex items-center justify-center text-slate-400 hover:text-amber-500 hover:border-amber-500/50 transition-all">
<span className="sr-only">Discord</span>
<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
<path d="M9.5 7.5c-.828 0-1.5.671-1.5 1.5 0 .828.672 1.5 1.5 1.5s1.5-.672 1.5-1.5c0-.829-.672-1.5-1.5-1.5zm5 0c-.828 0-1.5.671-1.5 1.5 0 .828.672 1.5 1.5 1.5s1.5-.672 1.5-1.5c0-.829-.672-1.5-1.5-1.5z" />
<path d="M18.7 4.1c-1.26-.42-2.61-.73-4-.91-.18.31-.35.63-.49.97-1.5-.23-3-.23-4.5 0-.14-.34-.31-.66-.49-.97-1.39.18-2.74.49-4 .91-2.59 3.89-3.29 7.69-2.94 11.44 1.69 1.25 3.33 2.01 4.95 2.51.4-.54.75-1.12 1.05-1.72-.58-.22-1.13-.48-1.66-.78.14-.1.27-.21.4-.32 3.21 1.49 6.76 1.49 9.96 0 .13.11.26.22.4.32-.53.3-1.08.56-1.66.78.3.6.65 1.18 1.05 1.72 1.62-.5 3.26-1.26 4.95-2.51.39-4.2-.65-7.84-2.94-11.44z" />
</svg>
</a>
<a href="#" className="w-10 h-10 rounded-lg bg-slate-900 border border-slate-800 flex items-center justify-center text-slate-400 hover:text-amber-500 hover:border-amber-500/50 transition-all">
<span className="sr-only">GitHub</span>
<Github size={18} />
</a>
<a href="#" className="w-10 h-10 rounded-lg bg-slate-900 border border-slate-800 flex items-center justify-center text-slate-400 hover:text-amber-500 hover:border-amber-500/50 transition-all">
<span className="sr-only">Twitter</span>
<Twitter size={18} />
</a>
<a href="#" className="w-10 h-10 rounded-lg bg-slate-900 border border-slate-800 flex items-center justify-center text-slate-400 hover:text-amber-500 hover:border-amber-500/50 transition-all">
<span className="sr-only">LinkedIn</span>
<Linkedin size={18} />
</a>
</div>
</div>
<div>
<h5 className="text-white font-bold mb-6 font-['Space_Grotesk']">Resource</h5>
<ul className="space-y-4 text-sm text-slate-500">
<li><a href="#" className="hover:text-amber-400 transition-colors">The Manifesto</a></li>
<li><a href="#" className="hover:text-amber-400 transition-colors">Build Kits</a></li>
<li><a href="#" className="hover:text-amber-400 transition-colors">Squad Directory</a></li>
<li><a href="#" className="hover:text-amber-400 transition-colors">Alumni Network</a></li>
</ul>
</div>
<div>
<h5 className="text-white font-bold mb-6 font-['Space_Grotesk']">Protocols</h5>
<ul className="space-y-4 text-sm text-slate-500 font-mono">
<li><a href="#" className="hover:text-indigo-400 transition-colors">MCP Spec</a></li>
<li><a href="#" className="hover:text-indigo-400 transition-colors">UCP Handshake</a></li>
<li><a href="#" className="hover:text-indigo-400 transition-colors">Agent SDK</a></li>
<li><a href="#" className="hover:text-indigo-400 transition-colors">A2A Messaging</a></li>
</ul>
</div>
</div>
<div className="flex flex-col md:flex-row justify-between items-center gap-6 pt-10 border-t border-white/5">
<p className="text-sm text-slate-600 font-['Space_Grotesk'] font-bold">© 2023 Move. Compete. Play. The future belongs to the builders. Built with AI</p>
<div className="flex gap-8 text-xs text-slate-600">
<a href="#" className="hover:text-slate-400">Privacy Policy</a>
<a href="#" className="hover:text-slate-400">Terms of Service</a>
<a href="#" className="hover:text-slate-400">Code of Conduct</a>
</div>
</div>
</div>
</footer>
{/* Global Styles for the marquee animation */}
<style>{`
@keyframes scroll {
0% { transform: translateX(0); }
100% { transform: translateX(-50%); }
}
.animate-scroll {
animation: scroll 30s linear infinite;
}
`}</style>
</div>;
};

View File

@@ -0,0 +1,19 @@
import * as React from 'react';
const MOBILE_BREAKPOINT = 768;
export function useIsMobile() {
const [isMobile, setIsMobile] = React.useState<boolean | undefined>(undefined);
React.useEffect(() => {
const mql = window.matchMedia(`(max-width: ${MOBILE_BREAKPOINT - 1}px)`);
const onChange = () => {
setIsMobile(window.innerWidth < MOBILE_BREAKPOINT);
};
mql.addEventListener('change', onChange);
setIsMobile(window.innerWidth < MOBILE_BREAKPOINT);
return () => mql.removeEventListener('change', onChange);
}, []);
return !!isMobile;
}

181
ui_mockup/src/index.css Normal file
View File

@@ -0,0 +1,181 @@
@import url('https://fonts.googleapis.com/css2?family=Inter&family=Arial&family=Helvetica&family=Times+New+Roman&family=Georgia&family=Roboto&display=swap');
@import 'tailwindcss';
@plugin "tailwindcss-animate";
@custom-variant dark (&:is(.dark *));
body {
margin: 0;
padding: 0;
display: flex;
width: 100%;
height: 100%;
min-height: 100vh;
box-sizing: border-box;
overflow: auto;
overscroll-behavior-x: none;
}
@theme inline {
--color-background: var(--background);
--color-foreground: var(--foreground);
--font-sans: var(--font-geist-sans);
--font-body: var(--font-body);
--font-heading: var(--font-heading);
--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);
}
:root {
--radius: 0.625rem;
--background: oklch(0.2795 0.0368 260.0299);
--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;
font-family: var(--font-body);
}
h1,
h2,
h3,
h4,
h5,
h6 {
font-family: var(--font-heading);
}
html,
body,
#root {
height: 100%;
width: 100%;
margin: 0;
padding: 0;
overscroll-behavior-x: none;
}
}
/* Broken Image Fallback Styles */
img.broken-image-fallback {
position: relative;
display: inline-block;
background: #f9fafb;
border: 1px solid #e5e7eb;
object-fit: none;
object-position: center;
animation: fadeIn 0.3s ease-in-out;
}
.dark img.broken-image-fallback {
background: #1f2937;
border-color: #374151;
}
@keyframes fadeIn {
from {
opacity: 0;
}
to {
opacity: 1;
}
}

View File

@@ -0,0 +1,29 @@
import { clsx, type ClassValue } from 'clsx';
import { twMerge } from 'tailwind-merge';
export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs));
}
/**
* Ensures light mode is always used by removing the dark class from the document element.
* This can be called from any component that needs to ensure light mode.
*/
export function ensureLightMode() {
if (typeof document !== 'undefined') {
// Always set dark mode to false
document.documentElement.classList.toggle('dark', false);
}
}
/**
* Removes any dark mode classes from a className string
* @param className The class string to process
* @returns The class string with dark mode classes removed
*/
export function removeDarkClasses(className: string): string {
return className
.split(' ')
.filter(cls => !cls.startsWith('dark:'))
.join(' ');
}

45
ui_mockup/src/main.tsx Normal file
View File

@@ -0,0 +1,45 @@
import { StrictMode } from 'react';
// Force light mode by removing dark class and preventing it from being added
document.documentElement.classList.remove('dark');
// Override the system preference detection
const forceLightMode = () => {
// Always set dark mode to false regardless of localStorage or system preference
document.documentElement.classList.toggle('dark', false // Force to false instead of checking localStorage or system preference
);
};
const addBrokenImageHandler = () => {
document.addEventListener('error', function (e) {
if (e.target instanceof HTMLImageElement) {
const img = e.target;
if (!img.dataset.fallbackApplied) {
img.dataset.fallbackApplied = 'true';
// Create a simple fallback SVG icon as data URL
const fallbackSvg = `data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%239ca3af' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect width='18' height='18' x='3' y='3' rx='2' ry='2'/%3E%3Ccircle cx='9' cy='9' r='2'/%3E%3Cpath d='m21 15-3.086-3.086a2 2 0 0 0-2.828 0L6 21'/%3E%3C/svg%3E`;
img.src = fallbackSvg;
img.classList.add('broken-image-fallback');
if (!img.alt || img.alt.trim() === '') {
img.alt = 'Image not available';
}
}
}
}, true);
};
// Run immediately
forceLightMode();
addBrokenImageHandler();
// Also run when the DOM is loaded to ensure it applies
document.addEventListener('DOMContentLoaded', forceLightMode);
// Override system preference changes
const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)');
mediaQuery.addEventListener('change', forceLightMode);
import { createRoot } from 'react-dom/client';
import './index.css';
import App from './App.tsx';
createRoot(document.getElementById('root')!).render(<StrictMode>
<App />
</StrictMode>);

View File

@@ -0,0 +1,19 @@
import { Theme, Container } from './types';
const injectedTheme: string = '%INJECTED_THEME%';
const injectedContainer: string = '%INJECTED_CONTAINER%';
let theme: Theme = 'light';
let container: Container = 'none';
if (injectedTheme === 'light' || injectedTheme === 'dark') {
theme = injectedTheme;
}
if (injectedContainer === 'centered' || injectedContainer === 'none') {
container = injectedContainer;
}
export default {
theme,
container,
};

2
ui_mockup/src/settings/types.d.ts vendored Normal file
View File

@@ -0,0 +1,2 @@
export type Theme = 'light' | 'dark';
export type Container = 'centered' | 'none';

1
ui_mockup/src/vite-env.d.ts vendored Normal file
View File

@@ -0,0 +1 @@
/// <reference types="vite/client" />

View File

@@ -0,0 +1,31 @@
{
"compilerOptions": {
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
"target": "ES2020",
"useDefineForClassFields": true,
"lib": ["ES2020", "DOM", "DOM.Iterable"],
"module": "ESNext",
"skipLibCheck": true,
/* Bundler mode */
"moduleResolution": "bundler",
"allowImportingTsExtensions": true,
"isolatedModules": true,
"moduleDetection": "force",
"noEmit": true,
"jsx": "react-jsx",
/* Linting */
"strict": true,
"noUnusedLocals": false,
"noUnusedParameters": false,
"noFallthroughCasesInSwitch": true,
"noUncheckedSideEffectImports": true,
"noImplicitAny": false,
"baseUrl": ".",
"paths": {
"@/*": ["./src/*"]
}
},
"include": ["src"]
}

10
ui_mockup/tsconfig.json Normal file
View File

@@ -0,0 +1,10 @@
{
"files": [],
"references": [{ "path": "./tsconfig.app.json" }, { "path": "./tsconfig.node.json" }],
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@/*": ["./src/*"]
}
}
}

View File

@@ -0,0 +1,24 @@
{
"compilerOptions": {
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
"target": "ES2022",
"lib": ["ES2023"],
"module": "ESNext",
"skipLibCheck": true,
/* Bundler mode */
"moduleResolution": "bundler",
"allowImportingTsExtensions": true,
"isolatedModules": true,
"moduleDetection": "force",
"noEmit": true,
/* Linting */
"strict": true,
"noUnusedLocals": false,
"noUnusedParameters": false,
"noFallthroughCasesInSwitch": true,
"noUncheckedSideEffectImports": true
},
"include": ["vite.config.ts"]
}

14
ui_mockup/vite.config.ts Normal file
View File

@@ -0,0 +1,14 @@
import path from 'path';
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import tailwindcss from '@tailwindcss/vite';
// https://vite.dev/config/
export default defineConfig({
plugins: [react(), tailwindcss()],
resolve: {
alias: {
'@': path.resolve(__dirname, './src'),
},
},
});

3526
ui_mockup/yarn.lock Normal file

File diff suppressed because it is too large Load Diff