diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..96f1d1d --- /dev/null +++ b/.gitignore @@ -0,0 +1,6 @@ +node_modules/ +dist/ +.env +.env.local +.DS_Store +*.log diff --git a/README.md b/README.md index b1900a9..e8ac2ca 100644 --- a/README.md +++ b/README.md @@ -1 +1,66 @@ -# gxchatindia \ No newline at end of file +# Gothwad Tech — Official Website + +Official website for **Gothwad Tech** — India's sovereign software collective. + +**Live:** https://gothwadtech.com + +## ✨ What this site is + +- **Official portal:** Everything Gothwad in one place. One Gothwad Account unlocks Mail, Drive, Meet, Store, Tube, GrixChat, Indogram, Browser, Education, AI Studio, Docs and CEO. +- **Ecosystem directory:** All 25+ products with direct subdomain links (`{host}.gothwadtech.com`), category filters and GitHub source links. +- **Product access hub:** Every card has a live “Open” button and a “Source” link — just like the Docs portal. +- **Same design language:** Matches `gothwadtech` (corporate) and `docs` (developer portal) repos — zinc + `#0494f4` brand, light/dark theme, responsive. + +## 🗺️ Routes + +| Path | Description | +|------|-------------| +| `/` | Home — hero + quick access + app shortcuts (search + category filter) | +| `/ecosystem` | Full product directory — all Gothwad apps with direct links | +| `/products` | Sovereign flagships: Browser, GrixChat, Indogram + full catalog | +| `/solutions` | School ERP, restaurant POS, shop billing, custom enterprise & deep-tech | +| `/docs` | Developer documentation index (mirrors docs.gothwadtech.com structure) | +| `/company` | About + leadership (Pawan Gothwad, Yuvkesh Meena, Vishnu) | +| `/contact` | Official inboxes + direct founder/leadership + WhatsApp/Phone | + +Deep links and refreshes work via `_redirects` SPA fallback on Cloudflare Pages. + +## 🎨 Assets + +Moved from `GothwadTech/gothwadtech` repo per request: + +- `public/assets/` root: `apple-touch-icon.png`, `favicon.ico`, `icon-192*.png`, `icon-512*.png`, `logo.png` (all PNG/icon images outside the two subfolders) +- `public/assets/brand/` + `public/assets/icons/` — kept as-is (two existing subfolders) +- `public/manifest.json`, `favicon.ico`, `logo.svg`, `robots.txt`, `sitemap.xml`, `_redirects`, `_headers` + +## 🛠 Stack + +- Vite 6 + React 19 + TypeScript 5 +- Tailwind CSS 4 via `@tailwindcss/vite` (same as `gothwadtech` + `docs`) +- `lucide-react` icons, `motion` for micro-interactions + +## 🚀 Run + +```bash +npm install +npm run dev # http://localhost:3000 +npm run build # → dist/ +npm run preview # serve built site +npm run typecheck +``` + +## 🔗 Ecosystem quick links + +- Accounts: https://accounts.gothwadtech.com +- Mail: https://mail.gothwadtech.com +- Drive: https://drive.gothwadtech.com +- Meet: https://meet.gothwadtech.com +- Tube: https://tube.gothwadtech.com +- GrixChat: https://grixchat.gothwadtech.com +- Indogram: https://indogram.gothwadtech.com +- Browser: https://browser.gothwadtech.com +- Docs: https://docs.gothwadtech.com +- CEO: https://ceo.gothwadtech.com +- GitHub: https://github.com/GothwadTech + +© 2026 Gothwad Tech Private Limited. Aatmanirbhar Bharat. diff --git a/index.html b/index.html new file mode 100644 index 0000000..76b3432 --- /dev/null +++ b/index.html @@ -0,0 +1,284 @@ + + + + + + + + + + + + + + + + + Gothwad Tech — Official Website | Sovereign Software, Browser & AI from India + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..2ba13fa --- /dev/null +++ b/package-lock.json @@ -0,0 +1,2551 @@ +{ + "name": "gothwadtech-website", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "gothwadtech-website", + "version": "1.0.0", + "dependencies": { + "lucide-react": "^0.546.0", + "motion": "^12.23.24", + "react": "^19.0.1", + "react-dom": "^19.0.1" + }, + "devDependencies": { + "@tailwindcss/vite": "^4.1.14", + "@types/node": "^22.14.0", + "@types/react": "^19.0.0", + "@types/react-dom": "^19.0.0", + "@vitejs/plugin-react": "^5.0.4", + "tailwindcss": "^4.1.14", + "typescript": "~5.8.2", + "vite": "^6.2.3" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.7.tgz", + "integrity": "sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.29.7", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.7.tgz", + "integrity": "sha512-locTkQyKvwIEgBzVrn8693ebc97F2U8ZHjbXwDXJ5Fn2TCpNwTlKcaKLkdHop5c/icOFE7qt7Q9JC5hnKNa6Gg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.7.tgz", + "integrity": "sha512-RgHBCvtjbOK2gXSNBNIkNoEc9qoVEtau3hj8gEqKQuL3HZAibKarWFEI3Lfm6EYKkLalOh8eSrj9b+ch9H/VBA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.7", + "@babel/generator": "^7.29.7", + "@babel/helper-compilation-targets": "^7.29.7", + "@babel/helper-module-transforms": "^7.29.7", + "@babel/helpers": "^7.29.7", + "@babel/parser": "^7.29.7", + "@babel/template": "^7.29.7", + "@babel/traverse": "^7.29.7", + "@babel/types": "^7.29.7", + "@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/generator": { + "version": "7.29.8", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.8.tgz", + "integrity": "sha512-gZbepsdh3WDtgZKWL+vTPh71LSBrm/Y4/QDZBVCcYfmeTEEuoOYwlSy+G1StfJg+/Zy550u/3TATbm7qDbbMtg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.29.8", + "@babel/types": "^7.29.8", + "@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.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.29.7.tgz", + "integrity": "sha512-wem6WaBj4NaVYVdNhLPPVacES6ZJ+KBBfSkTMD3YZxbP3rm3Di85tJU5ljaUNhaOynt+Aj0xruhYuzQBt8n71g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.29.7", + "@babel/helper-validator-option": "^7.29.7", + "browserslist": "^4.24.0", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-globals": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.29.7.tgz", + "integrity": "sha512-3nQVUAtvkKH9zahfWgw96Jc/uFOmjACE1kQz82E2lqWmHBgjzbNlsC22nuQTfahmWeQtTq5nQ/4Nnd2A1wj4zA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.29.7.tgz", + "integrity": "sha512-ejHwrQQYcm9xnTivShn2IDOlIzInN34AXskvq9QicvCtEzq1Vzclu/tKF8Jq1Cg8JG2GL6/EmjgsCT7lXepE3g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.29.7", + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.29.7.tgz", + "integrity": "sha512-UPUVSyXbOh627KiCIGQSgwWzGeBKLkaJ9PJEdrngIwMSzxLR4jS4+f1f1jb7VzBbg8nFLaYotvVPFCTqdrmTAg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.29.7", + "@babel/helper-validator-identifier": "^7.29.7", + "@babel/traverse": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.29.7.tgz", + "integrity": "sha512-G7sHYigPY17oO5SYWnfD/0MTBwVR781S/JI643e/JhUYgVgWE/61SoW3NH9KWUKyKq5LVh3npif99Wkt6j86Jw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.29.11", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.29.11.tgz", + "integrity": "sha512-snZbO7MEDOof+hvNa97EjEY7qD7h2kwvQr5AJC3ZhQudKW5dnej6k3kP9NQV88hJwaS8vDqRLFo9rivLEhle2g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.29.7.tgz", + "integrity": "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.29.7.tgz", + "integrity": "sha512-N9ZErrD+yW5geCDtBqnOoxmR8+tNKiGuxKlDpuJxfsqpa2dFcexaziGAE/qoHLiDDreVNMupxGmSoNlyvsA3gw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.29.10", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.29.10.tgz", + "integrity": "sha512-EMCx3AGZ3WfAl6ht7AyQoPm2Lh+BGYEMdc4Q6Hf7uSCDOZFuLq44qNwL+iaim8VlyYhRAo4X43+weadK8ZB4Yg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/template": "^7.29.7", + "@babel/types": "^7.29.8" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.29.11", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.11.tgz", + "integrity": "sha512-OZ6+oaK7GMyg3IfCpj8JOmn8n+w2rJbDT0LLfVDTLb1ZFeKDh3AiNELgCMUw175IJHSkLl74hG0M0VLsvx+gag==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.29.11" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-self": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.29.7.tgz", + "integrity": "sha512-TL0hMc9xzy86VD31nUiwzd5otRAcyEPcsegCxolO0PvcXuH1v0kECe/UIznYFihpkvU5wg/jk4v0TTEFfm53fw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-source": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.29.7.tgz", + "integrity": "sha512-06IyK09H3wi4cGbhDBwp5gUGo0IKtnYa8tyTiephirPCK6fbobVGiXMMI5zLQ4aKEYP3wZ3ArU44o+8KMrSG/Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/template": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.29.7.tgz", + "integrity": "sha512-puq+Gf35oI24FeN11LkoUQFqv9uwNeWpxXZi/Ji3rRIoKAzKnxRaZ+Gkj0vKS9ZCiTESfng1N9LyOyXvo+m+Gg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.7", + "@babel/parser": "^7.29.7", + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.29.10", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.10.tgz", + "integrity": "sha512-B3lYAs2nkKskbgQ1nfy8Ma9ao9Q1rntTAQHrzzyDuj+TSO+X3le6PfWwqDvodsb+OumE10eMFfuMCTQSQ5iuIQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.7", + "@babel/generator": "^7.29.8", + "@babel/helper-globals": "^7.29.7", + "@babel/parser": "^7.29.9", + "@babel/template": "^7.29.7", + "@babel/types": "^7.29.8", + "debug": "^4.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.29.11", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.11.tgz", + "integrity": "sha512-WCsemW40Cpc6gouC1SrY6PBaZ+oLRlEVY9XBvZBI7il/HyUrb2nJ505wE1MHEFyDZNnrWDEuy4jL50WVHfTTSQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.29.11", + "@babel/helper-validator-identifier": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.12.tgz", + "integrity": "sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.12.tgz", + "integrity": "sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.12.tgz", + "integrity": "sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.12.tgz", + "integrity": "sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.12.tgz", + "integrity": "sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.12.tgz", + "integrity": "sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.12.tgz", + "integrity": "sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.12.tgz", + "integrity": "sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.12.tgz", + "integrity": "sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.12.tgz", + "integrity": "sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.12.tgz", + "integrity": "sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.12.tgz", + "integrity": "sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.12.tgz", + "integrity": "sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.12.tgz", + "integrity": "sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.12.tgz", + "integrity": "sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.12.tgz", + "integrity": "sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.12.tgz", + "integrity": "sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.12.tgz", + "integrity": "sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.12.tgz", + "integrity": "sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.12.tgz", + "integrity": "sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.12.tgz", + "integrity": "sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.12.tgz", + "integrity": "sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.12.tgz", + "integrity": "sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.12.tgz", + "integrity": "sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.12.tgz", + "integrity": "sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.12.tgz", + "integrity": "sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/remapping": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", + "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.6.0.tgz", + "integrity": "sha512-T7jf+5zgsZHwNJ4lvQ7/aezbyk0nNX+zJVWpmHA7VYsEx7a7qr5Rg5IbtJFqkgze5Y2sruq1RUY8Q837Od7iFw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@napi-rs/lzma-linux-x64-gnu": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/@napi-rs/lzma-linux-x64-gnu/-/lzma-linux-x64-gnu-1.5.1.tgz", + "integrity": "sha512-oTXEIha4SsuXdTA4Iyskj0kpdx2yVXdhd75c2v3xGrHFfVMsbhTPZU/nMPL4sWKo4pBHm3aucLaqGlF696dTyQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^22.20 || ^24.12 || >=25" + } + }, + "node_modules/@rolldown/pluginutils": { + "version": "1.0.0-rc.3", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-rc.3.tgz", + "integrity": "sha512-eybk3TjzzzV97Dlj5c+XrBFW57eTNhzod66y9HrBlzJ6NsCrWCp/2kaPS3K9wJmurBC0Tdw4yPjXKZqlznim3Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.65.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.65.0.tgz", + "integrity": "sha512-t2AnVba25baFdq7gczzS13JyVcdubLVbFX1X04mxrggDrTQPUXNv3XM0k9H1hr5tqvg7AVvtQ720QHAj0iYqhg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.65.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.65.0.tgz", + "integrity": "sha512-dNONUaEwPGhl/nuO2KV8VABWlcjYyU6KtZGN8dQv5OS5JU7JSCxPijVNKXbRJd0iuTzTiJ4TjPt/4bbvDRNiMQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.65.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.65.0.tgz", + "integrity": "sha512-zWQqUH+9zavr2Bxuzfpuv2SIF3X31cr58TvSQC9o1GhpOvkqRwr60GkZdQcudyT/BEgdpdSafjgd2I13MbTL7g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.65.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.65.0.tgz", + "integrity": "sha512-RQYreBFWtO4//hIuOaZkYUnF/lPU4lz35dveDimDshWCJvVisVtJ/shmT9bkXK8wFJY+FJF89X6F3Cq1qI3LCw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.65.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.65.0.tgz", + "integrity": "sha512-A0NfMj6Cuh/9BE5k3awJKv6HoxFVXIcLAb6SZqAMoxUHPA1ZNNK4RsGuUPD/vL7nEAm9LG+ZzXWWTrnC0XtkpA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.65.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.65.0.tgz", + "integrity": "sha512-BI6/H7q3aP0I7S7GOrjyxTjgEJlSnovXE38+bdxBpuKN6z+d//uF+T+VQ3Q7ltJL/71p17ufartARX9Ja5gOGQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.65.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.65.0.tgz", + "integrity": "sha512-W1vUprf09RWaVWnsFP1vlUkEWJzTZlpObOEAYZXt9Fq0UVAOYEkeGr7wBX7McKqqIQskXdBnpiOMgwPujordgA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.65.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.65.0.tgz", + "integrity": "sha512-s8QTcZWgrl9haFzEGIqyE5BWyo89pFDGLMBFZ752WYxk8DJwNU/O1X6pZgPw829d9/sm6CCHyrMP3aurt76p1Q==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.65.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.65.0.tgz", + "integrity": "sha512-ke1f6dLRzkqveyjjF2fkEwQYZvxHtNNwjegY8nJrwcO0Bdqr8CzFO/pKE0Bns13cx0qz2Ba2Y0Hs3dSwMdnHxA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.65.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.65.0.tgz", + "integrity": "sha512-926SMeUcy4y18Rz/w2aJiUKOnyAnm6czg72bXkQEaeemsll+Wr0hnsjb2BGRpHvWgwAMYy5ACJCotbvfLCfj0A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-gnu": { + "version": "4.65.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.65.0.tgz", + "integrity": "sha512-6T7JNRP1hc4hqF2dUsEoVLOt9K8tmODoCLldtQRYnrddGGQY8Gqe2pM/qMMUo7EMowpP7oa2N95k0/8sYK/ipw==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-musl": { + "version": "4.65.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.65.0.tgz", + "integrity": "sha512-SImGFl1Je5kpyAgOCPONVT7h6ASV8mAUwGRjY7eZvVjPg//PfHOXgI+P241RF/+HqsA4PP3qD527ysWFKNQyhQ==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-gnu": { + "version": "4.65.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.65.0.tgz", + "integrity": "sha512-XeDTbmPF1Yu5asfXGPrMkWoxTDhgryQbmw5Q1+R582O51VNCk23J6f2pDrsAp5YkneBVBwtExx6ZGOb9D2aQ6A==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-musl": { + "version": "4.65.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.65.0.tgz", + "integrity": "sha512-VS55JUI/1nsljmV/jfqNkLZXFw8uMO8nNlfoHmSevNf6fO3neuhyDvx9dv3c/Ytt8r/431SL8Qax1dpYvOMZTg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.65.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.65.0.tgz", + "integrity": "sha512-Vblw84TbX7RS4la1Y4+yQ7aore/oSyaNtFbppuBr5Vs/4LfBeXKq9dIfoExw6zOvRERqd2rRAjnZRaMhH/0x5w==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.65.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.65.0.tgz", + "integrity": "sha512-7+gHjtONvKgwR9InTKFaLq53f6YzBJkgeMRBENdWTsQr+spahGqQm8HF5aXpq8i4JaRrOqYyv6Zn1WltDTxaZQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.65.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.65.0.tgz", + "integrity": "sha512-KvNDC0J6s4vVHhtJ6KrDXU0Er0au/hmRIBq/+1maCV8TseGupeKizq0bWcrbp2HE1T8xoknvN0Q/KZ/YF0qX3w==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.65.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.65.0.tgz", + "integrity": "sha512-GExdD15WPvu/x/drELjVam7vX8EsPgvTMOa/iJL/p/4m/oOqzbb7JXZg8fXR4hlXtg/sF2zyTZ3bR0AEtEMlhQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.65.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.65.0.tgz", + "integrity": "sha512-8sT9PemIZfIMED4Vd4KGoOXVDj5CMSWNcGdbheRUx9TYS03yOWdT2Q0lXPyEyNBB9YTilwewIQKNIBk6Nxi0Kg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-openbsd-x64": { + "version": "4.65.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.65.0.tgz", + "integrity": "sha512-pO6Ehi0jo5yE0R6PltKhJhv9mlIiyzBJk5N5NUF2OF6xtVKI+1bdXxj/rb0jGXy3hck1ELVT0QPY3tzkAm360w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ] + }, + "node_modules/@rollup/rollup-openharmony-arm64": { + "version": "4.65.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.65.0.tgz", + "integrity": "sha512-vo7N3/+cjjPDYr8vtxC+qSNgWa9sDvJ7g8N8R5SWqFY4WiNH1ULcAU70SKVyHeiIZOYYwNP9pTipmhN5sl1NPw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.65.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.65.0.tgz", + "integrity": "sha512-ArwvgFAbjKcDM7qqotZ4OVYf+UMT9xH2YzkCzK4+AuZSDihMlz1Ekoe4INwBVXzn2mnJzuIYOcSx07iTBijGRQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.65.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.65.0.tgz", + "integrity": "sha512-QGMmK4/cxKE/36FoLMSHQBCyymv/eFTnsCvvsBF0rgmOvVbvX78VWZRerL3dHa77f4pM6Xcc2iGDhJ10w/svKQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-gnu": { + "version": "4.65.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.65.0.tgz", + "integrity": "sha512-XfKYFWHIPs4HPODIMsGF1IKlS3H1e3WokUZIgpmn4+uNnZBlnRDDHEylNyazbQXwhMKZre68OjtRYbKqb5+j8w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.65.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.65.0.tgz", + "integrity": "sha512-wPWi++K4Bs1VR4XihOhfGi4IGX6Cub7FlerTf8X2v+2BtDHddgSqWCXwGD+h2yAe4/niIhNDwAltioOC+wEogQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@tailwindcss/node": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.3.3.tgz", + "integrity": "sha512-/T8IKEsf9VTU6tLjgC7+sv2mOPtQxzE2jMw7u4Tt40Tx+QSZxpzh95/H6cMKoja9XuW7iMdLJYBB0o9G1CaAgg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/remapping": "^2.3.5", + "enhanced-resolve": "^5.24.1", + "jiti": "^2.7.0", + "lightningcss": "1.32.0", + "magic-string": "^0.30.21", + "source-map-js": "^1.2.1", + "tailwindcss": "4.3.3" + } + }, + "node_modules/@tailwindcss/oxide": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.3.3.tgz", + "integrity": "sha512-krXjAikiaFSPaK/FkAQT5UTx3VormQaiZ5hBFlJZ9UFQGB/rwg1MZIhHAG9smMQRTdyJxP6Qt5MwMtdyU5FWrA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 20" + }, + "optionalDependencies": { + "@tailwindcss/oxide-android-arm64": "4.3.3", + "@tailwindcss/oxide-darwin-arm64": "4.3.3", + "@tailwindcss/oxide-darwin-x64": "4.3.3", + "@tailwindcss/oxide-freebsd-x64": "4.3.3", + "@tailwindcss/oxide-linux-arm-gnueabihf": "4.3.3", + "@tailwindcss/oxide-linux-arm64-gnu": "4.3.3", + "@tailwindcss/oxide-linux-arm64-musl": "4.3.3", + "@tailwindcss/oxide-linux-x64-gnu": "4.3.3", + "@tailwindcss/oxide-linux-x64-musl": "4.3.3", + "@tailwindcss/oxide-wasm32-wasi": "4.3.3", + "@tailwindcss/oxide-win32-arm64-msvc": "4.3.3", + "@tailwindcss/oxide-win32-x64-msvc": "4.3.3" + } + }, + "node_modules/@tailwindcss/oxide-android-arm64": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.3.3.tgz", + "integrity": "sha512-Y85A2gmPSkl5Ve5qR86GL4HT509cFqQh1aes9p3sSkyTPwt0Pppf3GkwGe4JPACcRYjgJIEhQgM6dBClnr0NYw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-darwin-arm64": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.3.3.tgz", + "integrity": "sha512-BiaWatpBcERQFDlOjRDpIVXuFK5PJez5SA4JMg6VYZdBYU+qKfV/vqjcIs+IYmtitf1xYQZTwXvU/8y4lfZUGw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-darwin-x64": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.3.3.tgz", + "integrity": "sha512-fAeUqfV5ndhxRwai8cXGzdLvul9utWOmeTkv69unv4ZXixjn61Z+p9lCWdwOwA3TYboG3BwdVuN/RDjhBRl0mw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-freebsd-x64": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.3.3.tgz", + "integrity": "sha512-iyf5bV6+wnAlflVeEy7R25dupxTNECZN5QMI0qNT6eT+EgaGdZcKhGkr5SdoaWiLJ3spLqIY9VCeSGrwmtg4kw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm-gnueabihf": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.3.3.tgz", + "integrity": "sha512-aAYUprJAJQWWbRrPvtjdroZ56Md+JM8pMiopS6xGEwDfLhqj+2ver2p4nU4Mb3CRqcMmNBjo8KkUgcxhkzVQGQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm64-gnu": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.3.3.tgz", + "integrity": "sha512-nDxldcEENOxZRzC2uu9jrutZdAAQtb+8WWDCSnWL1zvBk1+FN+x6MtDViPB5AJMfttVCUhehGWus3XBPgatM/w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm64-musl": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.3.3.tgz", + "integrity": "sha512-Md44bD6veX/PC5iyF8cDVnw4HBIANZepRZZ7a8DQOvkfo5WUBwcp6iAuCUz23u+4SUkhJlD3eL7hNdW8ezd/kA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-linux-x64-gnu": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.3.3.tgz", + "integrity": "sha512-tx7us1muwOKAKWao2v/GaafFeQboE6aj88vC6ziN2NCGcRm8gWUhwjzg+YdVB1e4boAtdtma4L43onunI6NS4w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-linux-x64-musl": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.3.3.tgz", + "integrity": "sha512-SJxX60smvHgasZoBy11dX6YRjXJFovwWBoedhbQPOBzgFWBHGB+TVPWB9BxzR7TTxU8FQZAI2AyiNCMzFm8Img==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-wasm32-wasi": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-wasm32-wasi/-/oxide-wasm32-wasi-4.3.3.tgz", + "integrity": "sha512-jx1+rPhY/5Ympkktd656HBWEBLxP7dH06losBLjjf5vgCODXvi9KhtftWcMIwTFIDqBr7cRnQkdLnAG+IOlGvQ==", + "bundleDependencies": [ + "@napi-rs/wasm-runtime", + "@emnapi/core", + "@emnapi/runtime", + "@tybys/wasm-util", + "@emnapi/wasi-threads", + "tslib" + ], + "cpu": [ + "wasm32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/core": "^1.11.1", + "@emnapi/runtime": "^1.11.1", + "@emnapi/wasi-threads": "^1.2.2", + "@napi-rs/wasm-runtime": "^1.1.4", + "@tybys/wasm-util": "^0.10.2", + "tslib": "^2.8.1" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@tailwindcss/oxide-win32-arm64-msvc": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.3.3.tgz", + "integrity": "sha512-3rc292Ca2ceK6Ulcc/bAVnTs/3nDtoPhyEKlgPv+yQJQi/JS/AMJlqzxvlDacL1nekbrcf6bTqp/jV4qgnPxNQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-win32-x64-msvc": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.3.3.tgz", + "integrity": "sha512-yJ0pwIVc/nYeGoV02WtsN8KYyLQv7kyI2wDnkezyJlGGjkd4QLwDGAwl47YpPJeuI0M0ObaXGSPjvWDPeTPggw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/vite": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/vite/-/vite-4.3.3.tgz", + "integrity": "sha512-yYU8cogLeSh/ms2jh8Fj7jaba/EWa7Ja6GoUqYZaraEuCI5YS6ms6ObZgjjedm+jm6XZjdNRWBpPP6Z86oOxcw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@tailwindcss/node": "4.3.3", + "@tailwindcss/oxide": "4.3.3", + "tailwindcss": "4.3.3" + }, + "peerDependencies": { + "vite": "^5.2.0 || ^6 || ^7 || ^8" + } + }, + "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==", + "dev": true, + "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==", + "dev": true, + "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==", + "dev": true, + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.28.2" + } + }, + "node_modules/@types/estree": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.9.tgz", + "integrity": "sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "22.20.5", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.20.5.tgz", + "integrity": "sha512-U2+DNr+wSjpsTS/wZGYHq7GcwfuSmKiKvoPvK22zwTlRhU91yOniN4qRR5KhIjvif7ysw/dz/hKmfDH0Ris4aA==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~6.21.0" + } + }, + "node_modules/@types/react": { + "version": "19.3.0", + "resolved": "https://registry.npmjs.org/@types/react/-/react-19.3.0.tgz", + "integrity": "sha512-N0rFCuH9YoxG9/m61l9MfpJKfmLOVU0em7ipIz6TRgSSkvReLB9vL85GB+yr8Bs5leqpvg96JSwF4ZS1s4viQg==", + "dev": true, + "license": "MIT", + "dependencies": { + "csstype": "^3.2.2" + } + }, + "node_modules/@types/react-dom": { + "version": "19.3.0", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.3.0.tgz", + "integrity": "sha512-ZI7bU42mZXXKHn/qNLEw2IrbiINU7X5+vfgdixBHkCNpYWXjKgfQ/P+uyGb5CjOLB9UcnTeg3rylQtV2hym44Q==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@types/react": "^19.3.0" + } + }, + "node_modules/@vitejs/plugin-react": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-5.2.0.tgz", + "integrity": "sha512-YmKkfhOAi3wsB1PhJq5Scj3GXMn3WvtQ/JC0xoopuHoXSdmtdStOpFrYaT1kie2YgFBcIe64ROzMYRjCrYOdYw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.29.0", + "@babel/plugin-transform-react-jsx-self": "^7.27.1", + "@babel/plugin-transform-react-jsx-source": "^7.27.1", + "@rolldown/pluginutils": "1.0.0-rc.3", + "@types/babel__core": "^7.20.5", + "react-refresh": "^0.18.0" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "peerDependencies": { + "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/baseline-browser-mapping": { + "version": "2.11.32", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.11.32.tgz", + "integrity": "sha512-UvuxFU9P3hM29LrQdwu0cD6w6/+SFr+UlB9s/knI7+O2rK9xFxKUwSDWxGdbbqQ9/V7BJ5s0NI5nQAE4uJp3gQ==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "baseline-browser-mapping": "dist/cli.cjs" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/browserslist": { + "version": "4.29.4", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.29.4.tgz", + "integrity": "sha512-2TcbbiwXEq+N0kD36tykpCfyyQigUXmuwNQbnPp4Xk4PX9JOqVIKjJlIDjpH7uY6tmRGoAd+apeT1p60T8wsdA==", + "dev": true, + "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": { + "baseline-browser-mapping": "^2.11.29", + "caniuse-lite": "^1.0.30001816", + "electron-to-chromium": "^1.5.459", + "node-releases": "^2.0.59", + "update-browserslist-db": "^1.3.4" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001819", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001819.tgz", + "integrity": "sha512-LFUqIIAwpzsIuevnKnsR9qnStBcgzPShTX61lBwN9uFkkf8o8zLiebEjbW8AYtZiF+1YKDWfdt/pWDtMuG8Xwg==", + "dev": true, + "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/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==", + "dev": true, + "license": "MIT" + }, + "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==", + "dev": true, + "license": "MIT" + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/detect-libc": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", + "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=8" + } + }, + "node_modules/electron-to-chromium": { + "version": "1.5.464", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.464.tgz", + "integrity": "sha512-nRa65aFge40viPAKxMKULIY8tcXKwKboJWNn4RoKwyWXJ6SP7BnrDGKUTzc64818jIciH0PK7LSF8QzZes19GA==", + "dev": true, + "license": "ISC" + }, + "node_modules/enhanced-resolve": { + "version": "5.26.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.26.0.tgz", + "integrity": "sha512-9vhedylFonb2YGogzUKX6+Ja72gOJbN1QHAqdrvqLwhdl/QWbKopzoUC9EbQNVsAns/bx/4uyqalrQAoy1IByw==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.4", + "tapable": "^2.3.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/esbuild": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.12.tgz", + "integrity": "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.25.12", + "@esbuild/android-arm": "0.25.12", + "@esbuild/android-arm64": "0.25.12", + "@esbuild/android-x64": "0.25.12", + "@esbuild/darwin-arm64": "0.25.12", + "@esbuild/darwin-x64": "0.25.12", + "@esbuild/freebsd-arm64": "0.25.12", + "@esbuild/freebsd-x64": "0.25.12", + "@esbuild/linux-arm": "0.25.12", + "@esbuild/linux-arm64": "0.25.12", + "@esbuild/linux-ia32": "0.25.12", + "@esbuild/linux-loong64": "0.25.12", + "@esbuild/linux-mips64el": "0.25.12", + "@esbuild/linux-ppc64": "0.25.12", + "@esbuild/linux-riscv64": "0.25.12", + "@esbuild/linux-s390x": "0.25.12", + "@esbuild/linux-x64": "0.25.12", + "@esbuild/netbsd-arm64": "0.25.12", + "@esbuild/netbsd-x64": "0.25.12", + "@esbuild/openbsd-arm64": "0.25.12", + "@esbuild/openbsd-x64": "0.25.12", + "@esbuild/openharmony-arm64": "0.25.12", + "@esbuild/sunos-x64": "0.25.12", + "@esbuild/win32-arm64": "0.25.12", + "@esbuild/win32-ia32": "0.25.12", + "@esbuild/win32-x64": "0.25.12" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/framer-motion": { + "version": "12.43.0", + "resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-12.43.0.tgz", + "integrity": "sha512-1eaL3RvR/kAlbG7UYcpMptEyzPoENO0c6w7ZnB3/hh2vSAz/6uGAFn6fdoqTBguNstf3MsFhJHsD/0DHiclG+g==", + "license": "MIT", + "dependencies": { + "motion-dom": "^12.43.0", + "motion-utils": "^12.39.0", + "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": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "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==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/jiti": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.7.0.tgz", + "integrity": "sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ==", + "dev": true, + "license": "MIT", + "bin": { + "jiti": "lib/jiti-cli.mjs" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/jsesc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "dev": true, + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "license": "MIT", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/lightningcss": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.32.0.tgz", + "integrity": "sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==", + "dev": true, + "license": "MPL-2.0", + "dependencies": { + "detect-libc": "^2.0.3" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "lightningcss-android-arm64": "1.32.0", + "lightningcss-darwin-arm64": "1.32.0", + "lightningcss-darwin-x64": "1.32.0", + "lightningcss-freebsd-x64": "1.32.0", + "lightningcss-linux-arm-gnueabihf": "1.32.0", + "lightningcss-linux-arm64-gnu": "1.32.0", + "lightningcss-linux-arm64-musl": "1.32.0", + "lightningcss-linux-x64-gnu": "1.32.0", + "lightningcss-linux-x64-musl": "1.32.0", + "lightningcss-win32-arm64-msvc": "1.32.0", + "lightningcss-win32-x64-msvc": "1.32.0" + } + }, + "node_modules/lightningcss-android-arm64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.32.0.tgz", + "integrity": "sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-arm64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.32.0.tgz", + "integrity": "sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-x64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.32.0.tgz", + "integrity": "sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-freebsd-x64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.32.0.tgz", + "integrity": "sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm-gnueabihf": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.32.0.tgz", + "integrity": "sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-gnu": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.32.0.tgz", + "integrity": "sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-musl": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.32.0.tgz", + "integrity": "sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-gnu": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.32.0.tgz", + "integrity": "sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-musl": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.32.0.tgz", + "integrity": "sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-arm64-msvc": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.32.0.tgz", + "integrity": "sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-x64-msvc": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.32.0.tgz", + "integrity": "sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "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==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/lucide-react": { + "version": "0.546.0", + "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-0.546.0.tgz", + "integrity": "sha512-Z94u6fKT43lKeYHiVyvyR8fT7pwCzDu7RyMPpTvh054+xahSgj4HFQ+NmflvzdXsoAjYGdCguGaFKYuvq0ThCQ==", + "license": "ISC", + "peerDependencies": { + "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/magic-string": { + "version": "0.30.21", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", + "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.5" + } + }, + "node_modules/motion": { + "version": "12.43.0", + "resolved": "https://registry.npmjs.org/motion/-/motion-12.43.0.tgz", + "integrity": "sha512-BQgQbSa9Hn3/mtbib0MK53y6JSANa+YKUKlaYnWzAVDH424RYQ5LVpV3pNiWH00BA2z4ojsSdMzqT7g2FQwjuQ==", + "license": "MIT", + "dependencies": { + "framer-motion": "^12.43.0", + "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/motion-dom": { + "version": "12.43.0", + "resolved": "https://registry.npmjs.org/motion-dom/-/motion-dom-12.43.0.tgz", + "integrity": "sha512-azKON4d9S65PEoFUiQTMTgPheEmzf2QngdRc50AKfJp9Q9mmcBVw22c8eMq9k8kxOFHdL7+WZY7N/5F/lwiDag==", + "license": "MIT", + "dependencies": { + "motion-utils": "^12.39.0" + } + }, + "node_modules/motion-utils": { + "version": "12.39.0", + "resolved": "https://registry.npmjs.org/motion-utils/-/motion-utils-12.39.0.tgz", + "integrity": "sha512-8nadJAJjTtqRkmRF36FoJTrywK9nnFmnPwnSMyxaOCU7GDjN9RTMJIxx9De8ErM+vpPhMccr/6fo5WciyQLnMQ==", + "license": "MIT" + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/nanoid": { + "version": "3.3.20", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.20.tgz", + "integrity": "sha512-uKdg2G3GNCKQn9byYOpxbGqrT2fGO5KRt5J/8b3pok8rT6qxGWF6hxMyJiEYtAf+FVyYuD9hRaDqX5uPFYJ4ZQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/node-releases": { + "version": "2.0.60", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.60.tgz", + "integrity": "sha512-OmO8+GM1JUZqXET720VrJCwkjUCXmCMQm0Z3UDDRbfNLHS4NEAvY60j5jiFv0tkKw2PNNlqOLhahVmwJIOLDIQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.7.tgz", + "integrity": "sha512-qcJu88Q2IWqJsDD529JKMdwGm/dvInW4HvQnRwiH9JtihJvzGOscDtHE3x1pBKeUOTysQ8kVmLnJ2kJu7yhcGA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/postcss": { + "version": "8.5.31", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.31.tgz", + "integrity": "sha512-YUbWYCgErwnMAVkjUnYa+KlMBzGpHwiIt/DE7f0G33AuX2LH9UcTk6KgWxd3zRU+pN3u/C+Xl3EnMLM4Hea7Sg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.20", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.2" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/react": { + "version": "19.3.1", + "resolved": "https://registry.npmjs.org/react/-/react-19.3.1.tgz", + "integrity": "sha512-QNhWdt7nrgVWWQG58QuGsAR3jv3Hbe4mb4vz7w2csnHavciZJgda1CPNaldF6eVxv90ud3jUXpKlHL69gO38yw==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-dom": { + "version": "19.3.1", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.3.1.tgz", + "integrity": "sha512-Y0bARz53lhEC1NMCASs0/j+faB/zqt3R8hpvg1e8+61ZVJ4UL0UdC4cBbXfZMcIuhrfgeILTLe+ZeBCavQPtKQ==", + "license": "MIT", + "dependencies": { + "scheduler": "^0.28.0" + }, + "peerDependencies": { + "react": "^19.3.1" + } + }, + "node_modules/react-refresh": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.18.0.tgz", + "integrity": "sha512-QgT5//D3jfjJb6Gsjxv0Slpj23ip+HtOpnNgnb2S5zU3CB26G/IDPGoy4RJB42wzFE46DRsstbW6tKHoKbhAxw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/rollup": { + "version": "4.65.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.65.0.tgz", + "integrity": "sha512-QVCvQUTGDN6JRwi3jVGCY3H4aTHvi9rX0LyoBMkGUvdh/Z6O51CzcLz85BWZaTCDGhl6ySGqYZs+xI1jmPqGcw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "1.0.9" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@napi-rs/lzma-linux-x64-gnu": "1.5.1", + "@rollup/rollup-android-arm-eabi": "4.65.0", + "@rollup/rollup-android-arm64": "4.65.0", + "@rollup/rollup-darwin-arm64": "4.65.0", + "@rollup/rollup-darwin-x64": "4.65.0", + "@rollup/rollup-freebsd-arm64": "4.65.0", + "@rollup/rollup-freebsd-x64": "4.65.0", + "@rollup/rollup-linux-arm-gnueabihf": "4.65.0", + "@rollup/rollup-linux-arm-musleabihf": "4.65.0", + "@rollup/rollup-linux-arm64-gnu": "4.65.0", + "@rollup/rollup-linux-arm64-musl": "4.65.0", + "@rollup/rollup-linux-loong64-gnu": "4.65.0", + "@rollup/rollup-linux-loong64-musl": "4.65.0", + "@rollup/rollup-linux-ppc64-gnu": "4.65.0", + "@rollup/rollup-linux-ppc64-musl": "4.65.0", + "@rollup/rollup-linux-riscv64-gnu": "4.65.0", + "@rollup/rollup-linux-riscv64-musl": "4.65.0", + "@rollup/rollup-linux-s390x-gnu": "4.65.0", + "@rollup/rollup-linux-x64-gnu": "4.65.0", + "@rollup/rollup-linux-x64-musl": "4.65.0", + "@rollup/rollup-openbsd-x64": "4.65.0", + "@rollup/rollup-openharmony-arm64": "4.65.0", + "@rollup/rollup-win32-arm64-msvc": "4.65.0", + "@rollup/rollup-win32-ia32-msvc": "4.65.0", + "@rollup/rollup-win32-x64-gnu": "4.65.0", + "@rollup/rollup-win32-x64-msvc": "4.65.0", + "fsevents": "~2.3.2" + } + }, + "node_modules/scheduler": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.28.0.tgz", + "integrity": "sha512-juorfCmIkIw8tT+p5BXSm6PJjQF/ycEYmKyzURCIt/RaZIhL+PulbQ9Yu2z1HdOJDdqDTlxA1+xKBmHXJsczAw==", + "license": "MIT" + }, + "node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/source-map-js": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.2.tgz", + "integrity": "sha512-KGj/8Y43x35aZVDtt+J4mK1hoLGHULMYfSkODJNQjNDC3oW1PqPoxMwo0pLUsWM/UEGzON/NxeHywEfNXNP3Vw==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/tailwindcss": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.3.3.tgz", + "integrity": "sha512-gOhV3P7ufE62QDGg1zVaTgCR+EtPv92k2nIhVcVKcLmxT1sUBsQGhnZj175j+MqRt4zLF7ic+sCYjfhxMxj7YQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/tapable": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.3.tgz", + "integrity": "sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/tinyglobby": { + "version": "0.2.17", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.17.tgz", + "integrity": "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.4" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD" + }, + "node_modules/typescript": { + "version": "5.8.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz", + "integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/undici-types": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", + "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/update-browserslist-db": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.3.4.tgz", + "integrity": "sha512-t8wonIOdQyOjtPd2VktlBu6QjTVTks6v8bSi7kd0r2Vll8TK1JYDZtRRdbmCHOAMphkZgrzK+L+vXK4pyZ8t4A==", + "dev": true, + "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/vite": { + "version": "6.4.5", + "resolved": "https://registry.npmjs.org/vite/-/vite-6.4.5.tgz", + "integrity": "sha512-4enwjFfi4IwtEh0w+jPzpLVOFQiPHmmzPxcHXQOyEur47o6u0jE573DmGpjA+7irXoMLYRZD5ZaFUEneS3abPg==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "^0.25.0", + "fdir": "^6.4.4", + "picomatch": "^4.0.2", + "postcss": "^8.5.3", + "rollup": "^4.34.9", + "tinyglobby": "^0.2.13" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^18.0.0 || ^20.0.0 || >=22.0.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", + "jiti": ">=1.21.0", + "less": "*", + "lightningcss": "^1.21.0", + "sass": "*", + "sass-embedded": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "jiti": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true, + "license": "ISC" + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..a5fb702 --- /dev/null +++ b/package.json @@ -0,0 +1,30 @@ +{ + "name": "gothwadtech-website", + "private": true, + "version": "1.0.0", + "type": "module", + "scripts": { + "dev": "vite --port=3000 --host=0.0.0.0", + "build": "vite build", + "preview": "vite preview --host 0.0.0.0 --port 3000", + "typecheck": "tsc --noEmit", + "lint": "eslint .", + "verify": "npm run typecheck && npm run build" + }, + "dependencies": { + "lucide-react": "^0.546.0", + "motion": "^12.23.24", + "react": "^19.0.1", + "react-dom": "^19.0.1" + }, + "devDependencies": { + "@tailwindcss/vite": "^4.1.14", + "@types/node": "^22.14.0", + "@types/react": "^19.0.0", + "@types/react-dom": "^19.0.0", + "@vitejs/plugin-react": "^5.0.4", + "tailwindcss": "^4.1.14", + "typescript": "~5.8.2", + "vite": "^6.2.3" + } +} diff --git a/public/.well-known/robots.txt b/public/.well-known/robots.txt new file mode 100644 index 0000000..e659d57 --- /dev/null +++ b/public/.well-known/robots.txt @@ -0,0 +1,35 @@ +# Gothwad Tech — https://gothwadtech.com +# Primary domain is gothwadtech.com (non-www). www → apex 301. + +User-agent: * +Allow: / +# Allow all important SEO assets explicitly (prevents accidental noindex on icons/manifest) +Allow: /favicon.ico +Allow: /favicon-*.png +Allow: /apple-touch-icon.png +Allow: /icon-*.png +Allow: /logo.svg +Allow: /manifest.json +Allow: /assets/ +Allow: /sitemap.xml +# Block private/internal areas +Disallow: /api/ +Disallow: /admin/ +Disallow: /*?*utm_* +Disallow: /*?*fbclid* +Disallow: /*?*gclid* + +# Crawlers: obey crawl-friendly sitemap +Sitemap: https://gothwadtech.com/sitemap.xml + +# Host directive (legacy Bing support — canonical is via link rel=canonical + 301 in _redirects) +Host: https://gothwadtech.com + +User-agent: GPTBot +Allow: / +User-agent: Claude-Web +Allow: / +User-agent: PerplexityBot +Allow: / +User-agent: Google-Extended +Allow: / diff --git a/public/.well-known/security.txt b/public/.well-known/security.txt new file mode 100644 index 0000000..ccada0a --- /dev/null +++ b/public/.well-known/security.txt @@ -0,0 +1,5 @@ +Contact: mailto:security@gothwadtech.com +Contact: mailto:contact@gothwadtech.com +Expires: 2027-10-24T00:00:00+05:30 +Preferred-Languages: en, hi +Canonical: https://gothwadtech.com/.well-known/security.txt diff --git a/public/_headers b/public/_headers new file mode 100644 index 0000000..21207d8 --- /dev/null +++ b/public/_headers @@ -0,0 +1,88 @@ +/* + # Security & SEO headers for gothwadtech.com (apex canonical) + X-Robots-Tag: all + X-Content-Type-Options: nosniff + X-Frame-Options: DENY + Referrer-Policy: strict-origin-when-cross-origin + Permissions-Policy: camera=(), microphone=(), geolocation=(), interest-cohort=(), payment=() + Strict-Transport-Security: max-age=31536000; includeSubDomains; preload + Cross-Origin-Opener-Policy: same-origin + Cross-Origin-Resource-Policy: same-origin + Link: ; rel="canonical" + Cache-Control: no-cache + +/assets/brand/* + Cache-Control: public, max-age=31536000, immutable + Content-Type: image/png + +/assets/icons/* + Cache-Control: public, max-age=31536000, immutable + Content-Type: image/png + +/assets/* + Cache-Control: public, max-age=31536000, immutable + +/favicon.ico + Cache-Control: public, max-age=86400 + Content-Type: image/x-icon + +/favicon-*.png + Cache-Control: public, max-age=86400 + Content-Type: image/png + +/icon-*.png + Cache-Control: public, max-age=86400 + Content-Type: image/png + +/apple-touch-icon* + Cache-Control: public, max-age=86400 + Content-Type: image/png + +/logo.svg + Cache-Control: public, max-age=31536000, immutable + Content-Type: image/svg+xml + +/manifest.json + Cache-Control: public, max-age=3600 + Content-Type: application/manifest+json + +/sitemap.xml + Cache-Control: public, max-age=3600 + Content-Type: application/xml + X-Robots-Tag: all + +/robots.txt + Cache-Control: public, max-age=3600 + Content-Type: text/plain + +/opensearch.xml + Cache-Control: public, max-age=86400 + Content-Type: application/opensearchdescription+xml + +/llms.txt + Cache-Control: public, max-age=3600 + Content-Type: text/plain + +/humans.txt + Cache-Control: public, max-age=86400 + Content-Type: text/plain + +/browserconfig.xml + Cache-Control: public, max-age=86400 + Content-Type: application/xml + +/security.txt + Cache-Control: public, max-age=86400 + Content-Type: text/plain + +/.well-known/* + Cache-Control: public, max-age=86400 + +/*.js + Cache-Control: public, max-age=31536000, immutable + +/*.css + Cache-Control: public, max-age=31536000, immutable + +/*.html + Cache-Control: no-cache diff --git a/public/_redirects b/public/_redirects new file mode 100644 index 0000000..b5e25e1 --- /dev/null +++ b/public/_redirects @@ -0,0 +1,29 @@ +# ============================================================ +# Gothwad Tech — Cloudflare Pages redirects & SEO canonical +# Primary domain is https://gothwadtech.com (non-www). +# We 301 redirect www → apex for canonical consistency (fixes Google +# showing www.gothwadtech.com instead of gothwadtech.com). +# Order matters: specific redirects first, SPA fallback last. +# ============================================================ + +# 1) Enforce HTTPS + non-www canonical (SEO: stops www duplicate index) +https://www.gothwadtech.com/* https://gothwadtech.com/:splat 301! +http://www.gothwadtech.com/* https://gothwadtech.com/:splat 301! +http://gothwadtech.com/* https://gothwadtech.com/:splat 301! + +# 2) Legacy path aliases (keep old links alive, pass link equity) +# These used to be hash links — now they are real paths. +/about /company 301! +/portfolio /ecosystem 301! +/browser /products 301! +/leadership /company 301! +/legacy /ecosystem 301! + +# 3) www subdomain direct (fallback if protocol not matched above) +www.gothwadtech.com/* https://gothwadtech.com/:splat 301! + +# 4) SPA fallback — every unmatched path serves index.html so deep links +# and hard-refresh on /ecosystem, /products etc. never 404. +# Cloudflare Pages serves real assets first, so /favicon.ico, +# /assets/*, /manifest.json etc. bypass this rule. +/* /index.html 200 diff --git a/public/apple-touch-icon-180x180.png b/public/apple-touch-icon-180x180.png new file mode 100644 index 0000000..f53aefb Binary files /dev/null and b/public/apple-touch-icon-180x180.png differ diff --git a/public/apple-touch-icon.png b/public/apple-touch-icon.png new file mode 100644 index 0000000..f53aefb Binary files /dev/null and b/public/apple-touch-icon.png differ diff --git a/public/assets/README.txt b/public/assets/README.txt new file mode 100644 index 0000000..3bdd02f --- /dev/null +++ b/public/assets/README.txt @@ -0,0 +1,18 @@ +Add this to your HTML : + + + + +Add this to your app's manifest.json: + + ... + { + "icons": [ + { "src": "/favicon.ico", "type": "image/x-icon", "sizes": "16x16 32x32" }, + { "src": "/icon-192.png", "type": "image/png", "sizes": "192x192" }, + { "src": "/icon-512.png", "type": "image/png", "sizes": "512x512" }, + { "src": "/icon-192-maskable.png", "type": "image/png", "sizes": "192x192", "purpose": "maskable" }, + { "src": "/icon-512-maskable.png", "type": "image/png", "sizes": "512x512", "purpose": "maskable" } + ] + } + ... diff --git a/public/assets/apple-touch-icon.png b/public/assets/apple-touch-icon.png new file mode 100644 index 0000000..b369885 Binary files /dev/null and b/public/assets/apple-touch-icon.png differ diff --git a/public/assets/brand/logo.png b/public/assets/brand/logo.png new file mode 100644 index 0000000..6b16e59 Binary files /dev/null and b/public/assets/brand/logo.png differ diff --git a/public/assets/brand/og-image.png b/public/assets/brand/og-image.png new file mode 100644 index 0000000..6b16e59 Binary files /dev/null and b/public/assets/brand/og-image.png differ diff --git a/public/assets/favicon.ico b/public/assets/favicon.ico new file mode 100644 index 0000000..8f685be Binary files /dev/null and b/public/assets/favicon.ico differ diff --git a/public/assets/icon-192-maskable.png b/public/assets/icon-192-maskable.png new file mode 100644 index 0000000..2c715f7 Binary files /dev/null and b/public/assets/icon-192-maskable.png differ diff --git a/public/assets/icon-192.png b/public/assets/icon-192.png new file mode 100644 index 0000000..b07496d Binary files /dev/null and b/public/assets/icon-192.png differ diff --git a/public/assets/icon-512-maskable.png b/public/assets/icon-512-maskable.png new file mode 100644 index 0000000..329e1a1 Binary files /dev/null and b/public/assets/icon-512-maskable.png differ diff --git a/public/assets/icon-512.png b/public/assets/icon-512.png new file mode 100644 index 0000000..271e7b0 Binary files /dev/null and b/public/assets/icon-512.png differ diff --git a/public/assets/icons/icon-144-maskable.png b/public/assets/icons/icon-144-maskable.png new file mode 100644 index 0000000..e2cfd49 Binary files /dev/null and b/public/assets/icons/icon-144-maskable.png differ diff --git a/public/assets/icons/icon-144.png b/public/assets/icons/icon-144.png new file mode 100644 index 0000000..e2cfd49 Binary files /dev/null and b/public/assets/icons/icon-144.png differ diff --git a/public/assets/icons/icon-192-maskable.png b/public/assets/icons/icon-192-maskable.png new file mode 100644 index 0000000..03ef7f2 Binary files /dev/null and b/public/assets/icons/icon-192-maskable.png differ diff --git a/public/assets/icons/icon-192.png b/public/assets/icons/icon-192.png new file mode 100644 index 0000000..03ef7f2 Binary files /dev/null and b/public/assets/icons/icon-192.png differ diff --git a/public/assets/icons/icon-384-maskable.png b/public/assets/icons/icon-384-maskable.png new file mode 100644 index 0000000..4478072 Binary files /dev/null and b/public/assets/icons/icon-384-maskable.png differ diff --git a/public/assets/icons/icon-384.png b/public/assets/icons/icon-384.png new file mode 100644 index 0000000..4478072 Binary files /dev/null and b/public/assets/icons/icon-384.png differ diff --git a/public/assets/icons/icon-48-maskable.png b/public/assets/icons/icon-48-maskable.png new file mode 100644 index 0000000..72c3f58 Binary files /dev/null and b/public/assets/icons/icon-48-maskable.png differ diff --git a/public/assets/icons/icon-48.png b/public/assets/icons/icon-48.png new file mode 100644 index 0000000..72c3f58 Binary files /dev/null and b/public/assets/icons/icon-48.png differ diff --git a/public/assets/icons/icon-512-maskable.png b/public/assets/icons/icon-512-maskable.png new file mode 100644 index 0000000..02f3265 Binary files /dev/null and b/public/assets/icons/icon-512-maskable.png differ diff --git a/public/assets/icons/icon-512.png b/public/assets/icons/icon-512.png new file mode 100644 index 0000000..02f3265 Binary files /dev/null and b/public/assets/icons/icon-512.png differ diff --git a/public/assets/icons/icon-72-maskable.png b/public/assets/icons/icon-72-maskable.png new file mode 100644 index 0000000..6877e90 Binary files /dev/null and b/public/assets/icons/icon-72-maskable.png differ diff --git a/public/assets/icons/icon-72.png b/public/assets/icons/icon-72.png new file mode 100644 index 0000000..6877e90 Binary files /dev/null and b/public/assets/icons/icon-72.png differ diff --git a/public/assets/icons/icon-96-maskable.png b/public/assets/icons/icon-96-maskable.png new file mode 100644 index 0000000..f9e2535 Binary files /dev/null and b/public/assets/icons/icon-96-maskable.png differ diff --git a/public/assets/icons/icon-96.png b/public/assets/icons/icon-96.png new file mode 100644 index 0000000..f9e2535 Binary files /dev/null and b/public/assets/icons/icon-96.png differ diff --git a/public/assets/logo.png b/public/assets/logo.png new file mode 100644 index 0000000..6b16e59 Binary files /dev/null and b/public/assets/logo.png differ diff --git a/public/browserconfig.xml b/public/browserconfig.xml new file mode 100644 index 0000000..813fbc8 --- /dev/null +++ b/public/browserconfig.xml @@ -0,0 +1,17 @@ + + + + + + + + + #0494f4 + + + + 30 + 1 + + + diff --git a/public/favicon-16x16.png b/public/favicon-16x16.png new file mode 100644 index 0000000..f3850c5 Binary files /dev/null and b/public/favicon-16x16.png differ diff --git a/public/favicon-32x32.png b/public/favicon-32x32.png new file mode 100644 index 0000000..ba96b0b Binary files /dev/null and b/public/favicon-32x32.png differ diff --git a/public/favicon-48x48.png b/public/favicon-48x48.png new file mode 100644 index 0000000..72c3f58 Binary files /dev/null and b/public/favicon-48x48.png differ diff --git a/public/favicon.ico b/public/favicon.ico new file mode 100644 index 0000000..5f112cc Binary files /dev/null and b/public/favicon.ico differ diff --git a/public/humans.txt b/public/humans.txt new file mode 100644 index 0000000..ddad460 --- /dev/null +++ b/public/humans.txt @@ -0,0 +1,28 @@ +/* the humans behind Gothwad Tech */ +Site: https://gothwadtech.com — Official website of Gothwad Tech +Location: Jaipur, Rajasthan, India + +/* team */ +Founder & Product Architect: Pawan Gothwad — pawan@gothwadtech.com — https://github.com/GothwadTech +CEO: Yuvkesh Meena — ceo.gothwadtech.com — Dausa, Rajasthan, India +Co-Founder & CTO: Vishnu Meena — vishnu@gothwadtech.com +CEO: Nishant — nishant@gothwadtech.com + +/* contact */ +Contact: contact@gothwadtech.com +Support: support@gothwadtech.com +Help: help@gothwadtech.com +Phone: +91 73399 04665 +WhatsApp: https://wa.me/917339904665 + +/* technology */ +Stack: Vite, React 19, TypeScript, Tailwind CSS, Cloudflare Pages +Design: Gothwad Design System — #0494f4 brand, zinc, light/dark + +/* thanks */ +Thanks to Aatmanirbhar Bharat — sovereign tech for India. + +/* site */ +Docs: https://docs.gothwadtech.com +GitHub: https://github.com/GothwadTech +CEO: https://ceo.gothwadtech.com diff --git a/public/icon-192x192.png b/public/icon-192x192.png new file mode 100644 index 0000000..03ef7f2 Binary files /dev/null and b/public/icon-192x192.png differ diff --git a/public/icon-512x512.png b/public/icon-512x512.png new file mode 100644 index 0000000..02f3265 Binary files /dev/null and b/public/icon-512x512.png differ diff --git a/public/llms.txt b/public/llms.txt new file mode 100644 index 0000000..ed43637 --- /dev/null +++ b/public/llms.txt @@ -0,0 +1,61 @@ +# Gothwad Tech — llms.txt +# https://gothwadtech.com/llms.txt +# Machine-readable overview for LLM & AI crawlers. + +> Gothwad Tech is India's sovereign software collective from Jaipur, Rajasthan (founded 2023, founder Pawan Gothwad, CEO Yuvkesh Meena). +> One Gothwad Account powers a unified ecosystem: Mail, Drive, Meet, Store, Tube, GrixChat, Indogram, Browser, Education, AI Studio, Remote Desktop, Docs and more. +> All products are documented and mostly open-source at https://github.com/GothwadTech. + +## Official domains (canonical is https://gothwadtech.com — non-www) +- Main: https://gothwadtech.com +- Accounts (auth): https://accounts.gothwadtech.com +- Mail: https://mail.gothwadtech.com +- Drive: https://drive.gothwadtech.com +- Meet: https://meet.gothwadtech.com +- Calendar: https://calender.gothwadtech.com (note spelling in DNS) +- Contacts: https://contacts.gothwadtech.com +- Notes: https://notes.gothwadtech.com +- Store: https://store.gothwadtech.com +- Tube: https://tube.gothwadtech.com +- GrixChat: https://grixchat.gothwadtech.com +- Indogram: https://indogram.gothwadtech.com +- Browser: https://browser.gothwadtech.com +- Education: https://education.gothwadtech.com +- AI Studio: https://ai.gothwadtech.com +- Remote Desktop: https://remotedesk.gothwadtech.com +- Docs: https://docs.gothwadtech.com +- CEO: https://ceo.gothwadtech.com + +## Site sections +- / : Home — hero, quick-access tiles, search + filter shortcuts +- /ecosystem : Directory of all 25+ products with direct subdomain links + GitHub source +- /products : Sovereign flagships (Browser 11.8MB, GrixChat <15ms, Indogram 200k members) +- /solutions : School ERP, restaurant POS, kirana billing/Khata, enterprise ERP, sovereign engines +- /docs : Developer docs index (Accounts OAuth PKCE, Mail setup & REST, Tube, Meet, etc.) +- /company : About, mission Aatmanirbhar Bharat, leadership +- /contact : Business, support, help, info inboxes + founder contacts + WhatsApp + +## Structured data +- Organization JSON-LD at https://gothwadtech.com/#organization +- WebSite with SearchAction (query: /ecosystem?q={search_term_string}) +- BreadcrumbList per route +- ItemList for ecosystem products + +## Docs & source +- Docs site: https://docs.gothwadtech.com +- Docs repo: https://github.com/GothwadTech/docs (source-cited, SOURCES.md) +- Main org: https://github.com/GothwadTech +- This website repo: https://github.com/GothwadTech/website + +## Brand & contact +- Logo: https://gothwadtech.com/assets/brand/logo.png +- OG image: https://gothwadtech.com/assets/brand/og-image.png +- Contact: contact@gothwadtech.com, pawan@gothwadtech.com, +91 73399 04665 +- Address: Jaipur, Rajasthan, India + +## Markdown for AI +See also: +- https://gothwadtech.com/sitemap.xml +- https://gothwadtech.com/robots.txt +- https://gothwadtech.com/humans.txt +- https://gothwadtech.com/manifest.json diff --git a/public/logo.svg b/public/logo.svg new file mode 100644 index 0000000..000bc7f --- /dev/null +++ b/public/logo.svg @@ -0,0 +1,51 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/manifest.json b/public/manifest.json new file mode 100644 index 0000000..b4fc48b --- /dev/null +++ b/public/manifest.json @@ -0,0 +1,48 @@ +{ + "id": "https://gothwadtech.com/", + "name": "Gothwad Tech — Official Website", + "short_name": "Gothwad Tech", + "description": "Official portal of Gothwad Tech — one account for Mail, Drive, Meet, Store, Tube, GrixChat, Indogram, Browser, Education, AI and Docs. Sovereign tech from India.", + "start_url": "/", + "scope": "/", + "display": "standalone", + "display_override": ["window-controls-overlay", "standalone", "browser"], + "orientation": "any", + "background_color": "#ffffff", + "theme_color": "#0494f4", + "lang": "en-IN", + "dir": "ltr", + "categories": ["business", "productivity", "utilities", "developer-tools", "education", "social"], + "handle_links": "preferred", + "launch_handler": { "client_mode": ["auto", "navigate-new", "focus-existing"] }, + "icons": [ + { "src": "/favicon.ico", "type": "image/x-icon", "sizes": "16x16 32x32 48x48" }, + { "src": "/favicon-16x16.png", "type": "image/png", "sizes": "16x16" }, + { "src": "/favicon-32x32.png", "type": "image/png", "sizes": "32x32" }, + { "src": "/favicon-48x48.png", "type": "image/png", "sizes": "48x48" }, + { "src": "/assets/icons/icon-48.png", "type": "image/png", "sizes": "48x48" }, + { "src": "/assets/icons/icon-72.png", "type": "image/png", "sizes": "72x72" }, + { "src": "/assets/icons/icon-96.png", "type": "image/png", "sizes": "96x96" }, + { "src": "/assets/icons/icon-144.png", "type": "image/png", "sizes": "144x144" }, + { "src": "/assets/icons/icon-192.png", "type": "image/png", "sizes": "192x192", "purpose": "any" }, + { "src": "/assets/icons/icon-384.png", "type": "image/png", "sizes": "384x384", "purpose": "any" }, + { "src": "/assets/icons/icon-512.png", "type": "image/png", "sizes": "512x512", "purpose": "any" }, + { "src": "/assets/icons/icon-192-maskable.png", "type": "image/png", "sizes": "192x192", "purpose": "maskable" }, + { "src": "/assets/icons/icon-512-maskable.png", "type": "image/png", "sizes": "512x512", "purpose": "maskable" }, + { "src": "/apple-touch-icon.png", "type": "image/png", "sizes": "180x180" } + ], + "screenshots": [ + { "src": "/assets/brand/og-image.png", "type": "image/png", "sizes": "512x512", "form_factor": "wide", "label": "Gothwad Tech — everything Gothwad, in one place" } + ], + "shortcuts": [ + { "name": "Ecosystem — All Products", "short_name": "Ecosystem", "description": "Browse all Gothwad products with direct links", "url": "/ecosystem", "icons": [{ "src": "/assets/icons/icon-192.png", "sizes": "192x192" }] }, + { "name": "Gothwad Mail", "short_name": "Mail", "description": "Open your Gothwad inbox", "url": "https://mail.gothwadtech.com", "icons": [{ "src": "/assets/icons/icon-192.png", "sizes": "192x192" }] }, + { "name": "Gothwad Docs", "short_name": "Docs", "description": "Developer documentation", "url": "https://docs.gothwadtech.com", "icons": [{ "src": "/assets/icons/icon-192.png", "sizes": "192x192" }] }, + { "name": "Gothwad Tube", "short_name": "Tube", "description": "A better way to watch", "url": "https://tube.gothwadtech.com", "icons": [{ "src": "/assets/icons/icon-192.png", "sizes": "192x192" }] } + ], + "related_applications": [], + "prefer_related_applications": false, + "edge_side_panel": { "preferred_width": 400 }, + "file_handlers": [], + "protocol_handlers": [] +} diff --git a/public/opensearch.xml b/public/opensearch.xml new file mode 100644 index 0000000..3ada913 --- /dev/null +++ b/public/opensearch.xml @@ -0,0 +1,13 @@ + + + Gothwad Tech + Search all Gothwad products — Mail, Drive, Meet, Tube, Browser, GrixChat and more. + UTF-8 + https://gothwadtech.com/favicon.ico + + + Gothwad Tech Private Limited + © 2026 Gothwad Tech — gothwadtech.com + en-IN + diff --git a/public/robots.txt b/public/robots.txt new file mode 100644 index 0000000..e659d57 --- /dev/null +++ b/public/robots.txt @@ -0,0 +1,35 @@ +# Gothwad Tech — https://gothwadtech.com +# Primary domain is gothwadtech.com (non-www). www → apex 301. + +User-agent: * +Allow: / +# Allow all important SEO assets explicitly (prevents accidental noindex on icons/manifest) +Allow: /favicon.ico +Allow: /favicon-*.png +Allow: /apple-touch-icon.png +Allow: /icon-*.png +Allow: /logo.svg +Allow: /manifest.json +Allow: /assets/ +Allow: /sitemap.xml +# Block private/internal areas +Disallow: /api/ +Disallow: /admin/ +Disallow: /*?*utm_* +Disallow: /*?*fbclid* +Disallow: /*?*gclid* + +# Crawlers: obey crawl-friendly sitemap +Sitemap: https://gothwadtech.com/sitemap.xml + +# Host directive (legacy Bing support — canonical is via link rel=canonical + 301 in _redirects) +Host: https://gothwadtech.com + +User-agent: GPTBot +Allow: / +User-agent: Claude-Web +Allow: / +User-agent: PerplexityBot +Allow: / +User-agent: Google-Extended +Allow: / diff --git a/public/security.txt b/public/security.txt new file mode 100644 index 0000000..ccada0a --- /dev/null +++ b/public/security.txt @@ -0,0 +1,5 @@ +Contact: mailto:security@gothwadtech.com +Contact: mailto:contact@gothwadtech.com +Expires: 2027-10-24T00:00:00+05:30 +Preferred-Languages: en, hi +Canonical: https://gothwadtech.com/.well-known/security.txt diff --git a/public/sitemap.xml b/public/sitemap.xml new file mode 100644 index 0000000..01e480f --- /dev/null +++ b/public/sitemap.xml @@ -0,0 +1,80 @@ + + + + + https://gothwadtech.com/ + 2026-10-24 + daily + 1.0 + + https://gothwadtech.com/assets/brand/logo.png + Gothwad Tech — sovereign software collective logo + Gothwad Tech + + + https://gothwadtech.com/assets/brand/og-image.png + Gothwad Tech — everything Gothwad, in one place + Gothwad Tech official website + + + + + + + + https://gothwadtech.com/ecosystem + 2026-10-24 + daily + 0.95 + + https://gothwadtech.com/assets/brand/og-image.png + Gothwad Ecosystem — all products + + + + + + + https://gothwadtech.com/products + 2026-10-24 + weekly + 0.90 + + https://gothwadtech.com/assets/brand/logo.png + Gothwad Browser, GrixChat, Indogram — sovereign apps + + + + + https://gothwadtech.com/solutions + 2026-10-24 + weekly + 0.85 + + + + https://gothwadtech.com/docs + 2026-10-24 + weekly + 0.90 + + + + https://gothwadtech.com/company + 2026-10-24 + monthly + 0.80 + + + + https://gothwadtech.com/contact + 2026-10-24 + monthly + 0.80 + + diff --git a/src/App.tsx b/src/App.tsx new file mode 100644 index 0000000..fbdbbdd --- /dev/null +++ b/src/App.tsx @@ -0,0 +1,395 @@ +import React, { useEffect, useState, Suspense, lazy } from 'react'; +import { ThemeProvider } from './context/ThemeContext'; +import { Navbar } from './components/Navbar'; +import { Footer } from './components/Footer'; + +const HomePage = lazy(() => import('./pages/HomePage').then((m) => ({ default: m.HomePage }))); +const EcosystemPage = lazy(() => import('./pages/EcosystemPage').then((m) => ({ default: m.EcosystemPage }))); +const ProductsPage = lazy(() => import('./pages/ProductsPage').then((m) => ({ default: m.ProductsPage }))); +const SolutionsPage = lazy(() => import('./pages/SolutionsPage').then((m) => ({ default: m.SolutionsPage }))); +const DocsPage = lazy(() => import('./pages/DocsPage').then((m) => ({ default: m.DocsPage }))); +const CompanyPage = lazy(() => import('./pages/CompanyPage').then((m) => ({ default: m.CompanyPage }))); +const ContactPage = lazy(() => import('./pages/ContactPage').then((m) => ({ default: m.ContactPage }))); + +const ROUTES = ['home', 'ecosystem', 'products', 'solutions', 'docs', 'company', 'contact']; + +const ROUTE_ALIASES: Record = { + '': 'home', + '/': 'home', + about: 'company', + portfolio: 'ecosystem', + browser: 'products', + leadership: 'company', +}; + +import { parseAuthuserFromUrl, stripAuthuserPath, buildAccountSlotPath } from './config/brand'; + +function pageFromPathname(pathname: string): string { + const clean = stripAuthuserPath(pathname); + const seg = clean.split('/').filter(Boolean)[0]?.toLowerCase() ?? ''; + if (!seg) return 'home'; + const target = ROUTE_ALIASES[seg] ?? seg; + return ROUTES.includes(target) ? target : 'home'; +} + +function pageFromHash(hash: string): string | null { + const raw = hash.replace(/^#/, '').toLowerCase().trim(); + if (!raw) return null; + const target = ROUTE_ALIASES[raw] ?? raw; + return ROUTES.includes(target) ? target : null; +} + +const pathForPage = (page: string) => { + const base = page === 'home' ? '/' : `/${page}`; + // Preserve /u// slot like Gmail so authuser stays in URL (and for SSO header) + try { + const { authuser, hasExplicitSlot } = parseAuthuserFromUrl(window.location.pathname, window.location.search); + if (hasExplicitSlot) return `${buildAccountSlotPath(authuser)}${base === '/' ? '' : base.slice(1)}`.replace(/\/\//g, '/') || '/'; + } catch {} + return base; +}; + +type PageMeta = { + title: string; + description: string; + ogType?: string; + keywords?: string; + breadcrumbs: { name: string; path: string }[]; + jsonLdExtra?: Record | null; +}; + +// Exhaustive per-route meta — 55-60 char titles, 150-160 char descriptions, brand included +const PAGE_META: Record = { + home: { + title: 'Gothwad Tech — Official Website | Sovereign Software from India', + description: + 'Official site of Gothwad Tech — Jaipur-based sovereign collective. One account for Mail, Drive, Meet, Store, Tube, GrixChat, Indogram, Browser, Education, AI & Docs.', + keywords: + 'Gothwad Tech, gothwadtech.com, gothwadtech official, Pawan Gothwad, sovereign software India, Gothwad Browser, Gothwad Accounts', + breadcrumbs: [{ name: 'Home', path: '/' }], + }, + ecosystem: { + title: 'Gothwad Ecosystem — All Products & Direct Links | Gothwad Tech', + description: + 'Browse the full Gothwad ecosystem — Accounts, Mail, Drive, Meet, Tube, Browser, GrixChat, Indogram, Launcher, Education, AI & more with live links.', + keywords: + 'Gothwad ecosystem, Gothwad products, gothwadtech.com products, Gothwad Mail, Gothwad Drive, Gothwad Tube, GrixChat, Indogram', + breadcrumbs: [ + { name: 'Home', path: '/' }, + { name: 'Ecosystem', path: '/ecosystem' }, + ], + jsonLdExtra: { + '@type': 'CollectionPage', + name: 'Gothwad Ecosystem Directory', + }, + }, + products: { + title: 'Products — Browser, GrixChat, Indogram | Gothwad Tech', + description: + 'Sovereign apps by Gothwad Tech: Browser (11.8 MB, 75% less RAM), GrixChat (<15ms), Indogram (200k members) plus Mail, Drive, Meet & Tube.', + keywords: + 'Gothwad Browser, GrixChat, Indogram, sovereign browser India, Gothwad products, Aatmanirbhar Bharat apps', + breadcrumbs: [ + { name: 'Home', path: '/' }, + { name: 'Products', path: '/products' }, + ], + }, + solutions: { + title: 'Solutions — School ERP, Restaurant POS & Enterprise | Gothwad Tech', + description: + 'Solutions for Bharat: School ERP, Restaurant POS & ordering, Kirana billing & Khata, Business CRM & custom sovereign browser engines.', + keywords: + 'Gothwad solutions, school ERP India, restaurant POS, shop billing, business ERP, sovereign systems, Gothwad Tech solutions', + breadcrumbs: [ + { name: 'Home', path: '/' }, + { name: 'Solutions', path: '/solutions' }, + ], + }, + docs: { + title: 'Docs — Developer Documentation | Gothwad Tech', + description: + 'Gothwad Tech developer docs: Accounts OAuth PKCE, Mail REST, Tube web, GrixChat, Meet, Cloudflare deploy — source-cited guides.', + keywords: + 'Gothwad docs, Gothwad documentation, docs.gothwadtech.com, Gothwad Accounts OAuth, Gothwad Mail API', + breadcrumbs: [ + { name: 'Home', path: '/' }, + { name: 'Docs', path: '/docs' }, + ], + }, + company: { + title: 'Company — Leadership & Aatmanirbhar Mission | Gothwad Tech', + description: + 'About Gothwad Tech: mission to build sovereign tech for India. Leadership by Pawan Gothwad & CEO Yuvkesh Meena from Jaipur, Rajasthan.', + keywords: + 'Gothwad Tech company, Pawan Gothwad, Yuvkesh Meena, about Gothwad Tech, Aatmanirbhar Bharat, Jaipur tech company', + breadcrumbs: [ + { name: 'Home', path: '/' }, + { name: 'Company', path: '/company' }, + ], + }, + contact: { + title: 'Contact — Talk to Gothwad Tech | Support & Business', + description: + 'Contact Gothwad Tech: contact@gothwadtech.com, +91 73399 04665 WhatsApp/Call. Business, support, help & media desks — reply in 2-4 hours.', + keywords: + 'contact Gothwad Tech, Gothwad Tech phone, Gothwad support, Gothwad help, pawan@gothwadtech.com, contact@gothwadtech.com', + breadcrumbs: [ + { name: 'Home', path: '/' }, + { name: 'Contact', path: '/contact' }, + ], + }, +}; + +function setMeta(selector: string, attr: 'content' | 'href', value: string) { + let el = document.querySelector(selector) as HTMLElement | null; + if (!el) { + const isLink = selector.startsWith('link'); + el = document.createElement(isLink ? 'link' : 'meta'); + if (isLink) { + // infer rel from selector + const relMatch = selector.match(/rel="([^"]+)"/); + el.setAttribute('rel', relMatch?.[1] ?? 'canonical'); + } else { + const name = selector.includes('property=') ? 'property' : 'name'; + const m = selector.match(/\[(?:name|property)="([^"]+)"\]/); + const raw = m?.[1]; + if (raw) el.setAttribute(name, raw); + } + document.head.appendChild(el); + } + el.setAttribute(attr, value); +} + +function upsertJsonLd(id: string, data: unknown) { + let el = document.getElementById(id) as HTMLScriptElement | null; + if (!el) { + el = document.createElement('script'); + el.id = id; + el.type = 'application/ld+json'; + document.head.appendChild(el); + } + el.textContent = JSON.stringify(data); +} + +function removeJsonLd(id: string) { + document.getElementById(id)?.remove(); +} + +function buildBreadcrumbJsonLd(breadcrumbs: { name: string; path: string }[]) { + return { + '@context': 'https://schema.org', + '@type': 'BreadcrumbList', + '@id': 'https://gothwadtech.com/#breadcrumb', + itemListElement: breadcrumbs.map((b, i) => ({ + '@type': 'ListItem', + position: i + 1, + name: b.name, + item: `https://gothwadtech.com${b.path}`, + })), + }; +} + +function buildWebPageJsonLd(page: string, meta: PageMeta, canonical: string) { + const base: Record = { + '@context': 'https://schema.org', + '@type': meta.jsonLdExtra?.['@type'] ?? 'WebPage', + '@id': `${canonical}#webpage`, + url: canonical, + name: meta.title, + description: meta.description, + isPartOf: { '@id': 'https://gothwadtech.com/#website' }, + about: { '@id': 'https://gothwadtech.com/#organization' }, + inLanguage: 'en-IN', + datePublished: '2023-01-01T00:00:00+05:30', + dateModified: '2026-10-24T00:00:00+05:30', + primaryImageOfPage: { '@id': 'https://gothwadtech.com/#logo' }, + breadcrumb: { '@id': 'https://gothwadtech.com/#breadcrumb' }, + ...(meta.jsonLdExtra ?? {}), + }; + // attach canonical breadcrumb id + return base; +} + +function RouteFallback() { + return ( +
+ Loading page… +
+
+ ); +} + +function AppContent() { + const [activePage, setActivePage] = useState(() => { + if (typeof window !== 'undefined') { + const legacy = pageFromHash(window.location.hash); + if (legacy) return legacy; + return pageFromPathname(window.location.pathname); + } + return 'home'; + }); + + const handleNavigate = (page: string) => { + const norm = ROUTES.includes(page) ? page : 'home'; + setActivePage(norm); + const path = pathForPage(norm); + if (window.location.pathname !== path) { + window.history.pushState({}, '', path); + } + window.scrollTo({ top: 0, behavior: 'smooth' }); + }; + + useEffect(() => { + const legacy = pageFromHash(window.location.hash); + if (legacy) { + window.history.replaceState({}, '', pathForPage(legacy)); + setActivePage(legacy); + } else { + setActivePage(pageFromPathname(window.location.pathname)); + } + const sync = () => setActivePage(pageFromPathname(window.location.pathname)); + window.addEventListener('popstate', sync); + return () => window.removeEventListener('popstate', sync); + }, []); + + useEffect(() => { + const meta = PAGE_META[activePage] ?? PAGE_META.home; + const canonical = `https://gothwadtech.com${pathForPage(activePage)}`; + const ogImage = 'https://gothwadtech.com/assets/brand/og-image.png'; + + // Core title & description + document.title = meta.title; + setMeta('meta[name="description"]', 'content', meta.description); + if (meta.keywords) setMeta('meta[name="keywords"]', 'content', meta.keywords); + setMeta('meta[name="title"]', 'content', meta.title); + + // Canonical + hreflang + setMeta('link[rel="canonical"]', 'href', canonical); + setMeta('link[rel="alternate"][hreflang="x-default"]', 'href', canonical); + setMeta('link[rel="alternate"][hreflang="en-IN"]', 'href', canonical); + + // Open Graph + setMeta('meta[property="og:title"]', 'content', meta.title); + setMeta('meta[property="og:description"]', 'content', meta.description); + setMeta('meta[property="og:url"]', 'content', canonical); + setMeta('meta[property="og:image"]', 'content', ogImage); + setMeta('meta[property="og:image:secure_url"]', 'content', ogImage); + setMeta('meta[property="og:updated_time"]', 'content', new Date().toISOString()); + + // Twitter + setMeta('meta[name="twitter:title"]', 'content', meta.title); + setMeta('meta[name="twitter:description"]', 'content', meta.description); + setMeta('meta[name="twitter:url"]', 'content', canonical); + setMeta('meta[name="twitter:image"]', 'content', ogImage); + + // Robots hints per route (all indexable; no noindex anywhere) + setMeta('meta[name="robots"]', 'content', 'index, follow, max-image-preview:large, max-snippet:-1, max-video-preview:-1'); + setMeta('meta[name="googlebot"]', 'content', 'index, follow, max-image-preview:large, max-snippet:-1, max-video-preview:-1'); + + // JSON-LD — WebPage + Breadcrumb for every route + upsertJsonLd('ld-webpage-dynamic', buildWebPageJsonLd(activePage, meta, canonical)); + upsertJsonLd('ld-breadcrumb-dynamic', buildBreadcrumbJsonLd(meta.breadcrumbs)); + + // Route-specific extra ItemList for ecosystem/products/docs to boost rich results + if (activePage === 'ecosystem') { + upsertJsonLd('ld-itemlist-ecosystem', { + '@context': 'https://schema.org', + '@type': 'ItemList', + '@id': `${canonical}#products`, + name: 'Gothwad Ecosystem — All Products', + description: 'Complete list of Gothwad Tech products: Accounts, Mail, Drive, Meet, Tube, Browser, GrixChat, Indogram, Launcher, Manager, Education, AI and more.', + numberOfItems: 25, + itemListElement: [ + 'Accounts', + 'Mail', + 'Drive', + 'Meet', + 'Calendar', + 'Contacts', + 'Notes', + 'Store', + 'Tube', + 'GrixChat', + 'Indogram', + 'Browser', + 'Launcher', + 'Manager', + 'Remote Desktop', + 'Internet', + 'Computer', + 'Education', + 'ClashDrive', + 'AI Studio', + 'Docs', + 'CEO', + ].map((name, i) => ({ + '@type': 'ListItem', + position: i + 1, + name, + url: `https://gothwadtech.com/ecosystem#${name.toLowerCase().replace(/\s/g, '-')}`, + })), + }); + } else { + removeJsonLd('ld-itemlist-ecosystem'); + } + + if (activePage === 'contact') { + upsertJsonLd('ld-contact', { + '@context': 'https://schema.org', + '@type': 'ContactPage', + '@id': `${canonical}#contactpage`, + url: canonical, + name: meta.title, + description: meta.description, + isPartOf: { '@id': 'https://gothwadtech.com/#website' }, + about: { '@id': 'https://gothwadtech.com/#organization' }, + }); + } else { + removeJsonLd('ld-contact'); + } + + if (activePage === 'company') { + upsertJsonLd('ld-about', { + '@context': 'https://schema.org', + '@type': 'AboutPage', + '@id': `${canonical}#aboutpage`, + url: canonical, + name: meta.title, + description: meta.description, + isPartOf: { '@id': 'https://gothwadtech.com/#website' }, + about: { '@id': 'https://gothwadtech.com/#organization' }, + mainEntity: { '@id': 'https://gothwadtech.com/#organization' }, + }); + } else { + removeJsonLd('ld-about'); + } + }, [activePage]); + + return ( +
+ + +
+ }> + {activePage === 'home' && } + {activePage === 'ecosystem' && } + {activePage === 'products' && } + {activePage === 'solutions' && } + {activePage === 'docs' && } + {activePage === 'company' && } + {activePage === 'contact' && } + +
+ +
+
+ ); +} + +export default function App() { + return ( + + + + ); +} diff --git a/src/components/AppShortcuts.tsx b/src/components/AppShortcuts.tsx new file mode 100644 index 0000000..5ca8b46 --- /dev/null +++ b/src/components/AppShortcuts.tsx @@ -0,0 +1,112 @@ +import React, { useMemo, useState } from 'react'; +import { ArrowUpRight, Search } from 'lucide-react'; +import { ECOSYSTEM_APPS, CATEGORIES } from '../data/ecosystem'; +import type { CategoryId } from '../data/ecosystem'; + +function filterApps(category: CategoryId, query: string) { + const q = query.trim().toLowerCase(); + return ECOSYSTEM_APPS.filter((app) => { + const byCat = category === 'all' ? true : app.category === category; + if (!byCat) return false; + if (!q) return true; + return ( + app.name.toLowerCase().includes(q) || + app.tagline.toLowerCase().includes(q) || + app.description.toLowerCase().includes(q) || + app.host.toLowerCase().includes(q) + ); + }); +} + +export const AppShortcuts: React.FC<{ compact?: boolean }> = ({ compact }) => { + const [category, setCategory] = useState('all'); + const [query, setQuery] = useState(''); + + const apps = useMemo(() => filterApps(category, query), [category, query]); + + return ( +
+ {/* Controls: category pills + search — matches docs/portal aesthetic */} +
+
+ {CATEGORIES.map((c) => ( + + ))} +
+ +
+ + setQuery(e.target.value)} + placeholder="Search products, e.g. Mail, Tube…" + className="w-full pl-9 pr-3 py-2 rounded-xl bg-white dark:bg-zinc-900 border border-zinc-200 dark:border-zinc-800 text-xs text-zinc-900 dark:text-white placeholder-zinc-400 focus:outline-none focus:border-[#0494f4] focus:ring-2 focus:ring-[#0494f4]/20" + /> +
+
+ + {/* Grid — 2→3→4 cols, card design like gothwadtech/portal */} + + + {apps.length === 0 && ( +
+
No products found
+
Try a different keyword or category.
+ +
+ )} +
+ ); +}; diff --git a/src/components/Breadcrumbs.tsx b/src/components/Breadcrumbs.tsx new file mode 100644 index 0000000..2c3dc6f --- /dev/null +++ b/src/components/Breadcrumbs.tsx @@ -0,0 +1,38 @@ +import React from 'react'; +import { ChevronRight, Home } from 'lucide-react'; + +type Crumb = { name: string; path?: string }; + +export const Breadcrumbs: React.FC<{ items: Crumb[]; onNavigate?: (path: string) => void }> = ({ items, onNavigate }) => { + // Always prepend Home unless already present + const full = items[0]?.name === 'Home' ? items : [{ name: 'Home', path: '/' }, ...items]; + return ( + + ); +}; diff --git a/src/components/Footer.tsx b/src/components/Footer.tsx new file mode 100644 index 0000000..acc9957 --- /dev/null +++ b/src/components/Footer.tsx @@ -0,0 +1,24 @@ +import React from 'react'; +import { Github, BookOpen } from 'lucide-react'; +import { COMPANY_INFO } from '../data/companyData'; + +export const Footer: React.FC<{ onNavigate: (page: string) => void }> = ({ onNavigate }) => { + return ( +
+
+
+ © {new Date().getFullYear()} {COMPANY_INFO.legalName} + • + Jaipur, Rajasthan, India +
+
+ Docs + GitHub + + + www.gothwadtech.com +
+
+
+ ); +}; diff --git a/src/components/Logo.tsx b/src/components/Logo.tsx new file mode 100644 index 0000000..c173398 --- /dev/null +++ b/src/components/Logo.tsx @@ -0,0 +1,82 @@ +import React, { useState } from 'react'; +import { COMPANY_INFO } from '../data/companyData'; + +interface LogoProps { + className?: string; + showText?: boolean; + size?: 'sm' | 'md' | 'lg' | 'xl'; + imageSrc?: string; +} + +export const Logo: React.FC = ({ + className = '', + showText = true, + size = 'md', + imageSrc = '/assets/icons/icon-512.png', +}) => { + const [imageError, setImageError] = useState(false); + + const containerSizes = { + sm: 'w-9 h-9 sm:w-10 sm:h-10 rounded-[10px]', + md: 'w-11 h-11 sm:w-12 sm:h-12 rounded-[12px]', + lg: 'w-14 h-14 sm:w-16 sm:h-16 rounded-[16px]', + xl: 'w-20 h-20 rounded-[18px]', + }; + + const textSizes = { + sm: 'text-lg sm:text-xl tracking-tight', + md: 'text-xl sm:text-2xl tracking-tight', + lg: 'text-2xl sm:text-3xl tracking-tight', + xl: 'text-3xl sm:text-4xl tracking-tight', + }; + + return ( +
+
+ {!imageError && imageSrc ? ( + {COMPANY_INFO.name} { + if (imageSrc !== '/assets/icons/icon-512.png') { + const img = new Image(); + img.src = '/assets/icons/icon-512.png'; + img.onload = () => setImageError(false); + img.onerror = () => setImageError(true); + } else { + setImageError(true); + } + }} + className="w-full h-full object-cover block" + /> + ) : ( + + + + + + + )} +
+ + {showText && ( +
+
+ + GOTHWAD + + TECH +
+ {size === 'lg' || size === 'xl' ? ( + + Official • Sovereign Tech + + ) : null} +
+ )} +
+ ); +}; diff --git a/src/components/Navbar.tsx b/src/components/Navbar.tsx new file mode 100644 index 0000000..ef628e3 --- /dev/null +++ b/src/components/Navbar.tsx @@ -0,0 +1,124 @@ +import React, { useRef } from 'react'; +import { Logo } from './Logo'; +import { useGothwadSession } from '../hooks/useGothwadSession'; +import { openGothwadAccountMenu, avatarColorFor, initialsFromAccount } from '../lib/accountMenuWidget'; +import { ACCOUNTS_WEB_ORIGIN, ACCOUNTS_API_ORIGIN, buildSignInUrl, buildAccountSlotPath } from '../config/brand'; +import { signOutGothwadSlot, switchGothwadAccountSlot } from '../lib/gothwadSso'; +import { useTheme as useThemeCtx } from '../context/ThemeContext'; + +interface NavbarProps { + activePage: string; + onNavigate: (page: string) => void; +} + +export const Navbar: React.FC = ({ activePage, onNavigate }) => { + const isHome = activePage === 'home'; + const { data, loading, authuser, authenticated } = useGothwadSession(); + const { isDark } = useThemeCtx(); + const avatarBtnRef = useRef(null); + + const handleAvatarClick = () => { + if (!avatarBtnRef.current || !data?.user) return; + const effectiveUser = data.user; + const effectiveAccounts = data.accounts.length ? data.accounts : [{ + id: data.activeId || 'a', + authuser, + username: effectiveUser.username || '', + name: effectiveUser.name || effectiveUser.username || 'Account', + firstName: effectiveUser.firstName, + lastName: effectiveUser.lastName, + email: effectiveUser.email, + avatarUrl: effectiveUser.avatarUrl, + avatar_url: effectiveUser.avatar_url, + } as any]; + + openGothwadAccountMenu( + { user: effectiveUser as any, accounts: effectiveAccounts as any, activeId: data.activeId || effectiveAccounts[0]?.id || 'a', authuser }, + { + theme: (isDark ? 'dark' : 'light') as any, + anchorEl: avatarBtnRef.current, + nextUrl: window.location.href, + manageAccountHref: `${ACCOUNTS_WEB_ORIGIN}/u/${authuser}/me`, + accountsWebOrigin: ACCOUNTS_WEB_ORIGIN, + accountsApiOrigin: `${ACCOUNTS_API_ORIGIN}/api`, + appDomain: 'gothwadtech.com', + accountHref: (acct: any) => buildAccountSlotPath(acct.authuser ?? 0), + onSwitchAccount: async (target: any) => { + const res = await switchGothwadAccountSlot(target.id, target.authuser ?? 0); + if (res.ok) { + const path = buildAccountSlotPath(target.authuser ?? 0); + // preserve SPA route after the slot prefix + const current = window.location.pathname.replace(/^\/u\/[0-5]/, '') || '/'; + window.location.href = `${path}${current.replace(/^\//, '') ? current.slice(1) ? `/${current.replace(/^\//,'')}` : '/' : '/'}`.replace('//','/'); + // fallback reload + setTimeout(() => window.location.reload(), 300); + } else { + window.location.href = buildAccountSlotPath(target.authuser ?? 0); + } + }, + onSignOutAccount: async (slotId: string) => { + await signOutGothwadSlot(slotId, authuser); + window.location.reload(); + }, + onSignOutAll: async () => { + await signOutGothwadSlot(undefined, authuser); + window.location.reload(); + }, + } + ); + }; + + const signInHref = buildSignInUrl(typeof window !== 'undefined' ? window.location.href : 'https://gothwadtech.com'); + + return ( +
+
+
+ {!isHome && ( + + )} + +
+ + +
+
+ ); +}; diff --git a/src/components/PortalBar.tsx b/src/components/PortalBar.tsx new file mode 100644 index 0000000..57f323f --- /dev/null +++ b/src/components/PortalBar.tsx @@ -0,0 +1,31 @@ +import React from 'react'; +import { ArrowUpRight, Github, BookOpen, Mail } from 'lucide-react'; + +export const PortalBar: React.FC = () => { + return ( +
+
+
+ + Official Portal + + One Account for Mail, Drive, Meet, Tube, GrixChat, Browser & more +
+ +
+
+ ); +}; diff --git a/src/config/brand.ts b/src/config/brand.ts new file mode 100644 index 0000000..5da3cc5 --- /dev/null +++ b/src/config/brand.ts @@ -0,0 +1,77 @@ +export const DEFAULT_APP_DOMAIN = "gothwadtech.com"; + +function readViteEnv(key: string): string { + try { + if (typeof import.meta !== "undefined" && (import.meta as any).env) { + const val = (import.meta as any).env[key]; + if (typeof val === "string" && val.trim()) return val.trim(); + } + } catch {} + return ""; +} + +export const APP_DOMAIN = (readViteEnv("VITE_APP_DOMAIN") || DEFAULT_APP_DOMAIN) + .toLowerCase() + .replace(/^https?:\/\//, "") + .replace(/\/+$/, ""); + +export const ACCOUNTS_WEB_ORIGIN = ( + readViteEnv("VITE_ACCOUNTS_WEB_URL") || `https://accounts.${APP_DOMAIN}` +).replace(/\/+$/, ""); + +export const ACCOUNTS_API_ORIGIN = ( + readViteEnv("VITE_ACCOUNTS_API_URL") || `https://api.${APP_DOMAIN}` +).replace(/\/+$/, ""); + +export const ECOSYSTEM_NAME = "Gothwad"; +export const ACCOUNT_WIDGET_URL = `${ACCOUNTS_WEB_ORIGIN}/widget/account-menu.js`; + +export function formatGothwadEmail(username: string, domain = APP_DOMAIN): string { + const clean = String(username || "").trim().toLowerCase(); + if (!clean) return ""; + return clean.includes("@") ? clean : `${clean}@${domain}`; +} + +export function buildAccountSlotPath(authuser: number): string { + const slot = Number.isInteger(authuser) && authuser >= 0 && authuser <= 5 ? authuser : 0; + return `/u/${slot}/`; +} + +export function parseAuthuserFromUrl( + pathname = typeof window !== "undefined" ? window.location.pathname : "/", + search = typeof window !== "undefined" ? window.location.search : "" +): { authuser: number; hasExplicitSlot: boolean } { + const pathMatch = pathname.match(/^\/u\/([0-5])(?:\/|$)/); + if (pathMatch) return { authuser: Number.parseInt(pathMatch[1], 10), hasExplicitSlot: true }; + try { + const params = new URLSearchParams(search); + const q = params.get("authuser")?.trim() || params.get("u")?.trim(); + if (q && /^[0-5]$/.test(q)) return { authuser: Number.parseInt(q, 10), hasExplicitSlot: true }; + } catch {} + return { authuser: 0, hasExplicitSlot: false }; +} + +export function buildSignInUrl( + nextUrl = typeof window !== "undefined" ? window.location.href : `https://${APP_DOMAIN}`, + opts: { choose?: boolean; add?: boolean } = {} +): string { + const params = new URLSearchParams(); + if (opts.choose) params.set("choose", "1"); + if (opts.add) params.set("add", "1"); + params.set("next", nextUrl); + return `${ACCOUNTS_WEB_ORIGIN}/signin?${params.toString()}`; +} + +export function buildManageAccountUrl(authuser = 0): string { + const slot = Number.isInteger(authuser) && authuser >= 0 && authuser <= 5 ? authuser : 0; + return `${ACCOUNTS_WEB_ORIGIN}/u/${slot}/me`; +} + +// strip /u// prefix for SPA routing +export function stripAuthuserPath(pathname: string): string { + if (/^\/u\/[0-5](?:\/|$)/.test(pathname)) { + const rest = pathname.replace(/^\/u\/[0-5]/, "") || "/"; + return rest.startsWith("/") ? rest : `/${rest}`; + } + return pathname; +} diff --git a/src/context/ThemeContext.tsx b/src/context/ThemeContext.tsx new file mode 100644 index 0000000..1e25ebe --- /dev/null +++ b/src/context/ThemeContext.tsx @@ -0,0 +1,89 @@ +import React, { createContext, useContext, useEffect, useState } from 'react'; + +type ThemeMode = 'light' | 'dark' | 'system'; + +interface ThemeContextType { + themeMode: ThemeMode; + isDark: boolean; + setThemeMode: (mode: ThemeMode) => void; + toggleTheme: () => void; +} + +const ThemeContext = createContext(undefined); + +function getSystemIsDark(): boolean { + if (typeof window === 'undefined') return false; + return window.matchMedia('(prefers-color-scheme: dark)').matches; +} + +function applyTheme(isDark: boolean) { + const root = document.documentElement; + root.classList.remove('light', 'dark'); + root.classList.add(isDark ? 'dark' : 'light'); + root.style.colorScheme = isDark ? 'dark' : 'light'; + try { + localStorage.setItem('gothwad-theme', isDark ? 'dark' : 'light'); + } catch {} +} + +export const ThemeProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => { + const [themeMode, setThemeModeState] = useState(() => { + try { + const stored = localStorage.getItem('gothwad-theme') as 'light' | 'dark' | null; + if (stored === 'dark' || stored === 'light') return stored; + } catch {} + return 'system'; + }); + + const [isDark, setIsDark] = useState(false); + + useEffect(() => { + const compute = () => { + if (themeMode === 'system') return getSystemIsDark(); + return themeMode === 'dark'; + }; + setIsDark(compute()); + + if (themeMode === 'system') { + const mql = window.matchMedia('(prefers-color-scheme: dark)'); + const handler = () => setIsDark(getSystemIsDark()); + mql.addEventListener('change', handler); + return () => mql.removeEventListener('change', handler); + } + }, [themeMode]); + + useEffect(() => { + applyTheme(isDark); + }, [isDark]); + + const setThemeMode = (mode: ThemeMode) => { + setThemeModeState(mode); + if (mode === 'system') { + try { + localStorage.removeItem('gothwad-theme'); + } catch {} + } else { + try { + localStorage.setItem('gothwad-theme', mode); + } catch {} + } + }; + + const toggleTheme = () => { + // Toggle between light/dark directly for one-click UX, like gothwadtech site + const next = isDark ? 'light' : 'dark'; + setThemeMode(next as ThemeMode); + }; + + return ( + + {children} + + ); +}; + +export const useTheme = () => { + const ctx = useContext(ThemeContext); + if (!ctx) throw new Error('useTheme must be used within ThemeProvider'); + return ctx; +}; diff --git a/src/data/companyData.ts b/src/data/companyData.ts new file mode 100644 index 0000000..1fcd88b --- /dev/null +++ b/src/data/companyData.ts @@ -0,0 +1,36 @@ +export const COMPANY_INFO = { + name: 'Gothwad Tech', + domain: 'gothwadtech.com', + legalName: 'Gothwad Tech Private Limited', + tagline: 'Digital Solutions for Indian Businesses & Sovereign Tech Platforms', + slogan: 'Empowering Indian Businesses & Building Sovereign Tech — Aatmanirbhar Bharat', + shortDescription: + 'One Gothwad Account for everything. Access Mail, Drive, Meet, Store, Tube, GrixChat, Indogram, Browser, Education, AI Studio and the full Gothwad ecosystem — with docs, guides and direct product links.', + foundedYear: '2023', + headquarters: 'Jaipur, Rajasthan, India', + phone: '+91 73399 04665', + phoneRaw: '07339904665', + whatsappNumberOnly: '917339904665', + email: 'contact@gothwadtech.com', + supportEmail: 'support@gothwadtech.com', + helpEmail: 'help@gothwadtech.com', + infoEmail: 'info@gothwadtech.com', + docsEmail: 'docs@gothwadtech.com', + founderEmail: 'pawan@gothwadtech.com', + ceoEmail: 'nishant@gothwadtech.com', + coFounderEmail: 'vishnu@gothwadtech.com', + stats: [ + { label: 'Ecosystem Apps', value: '13+ Products', helper: 'Mail, Drive, Meet, Tube +' }, + { label: 'Open Repos', value: '30+ Repos', helper: 'Public on GitHub' }, + { label: 'Engineering Team', value: '12 Specialists', helper: 'Web, Mobile, AI, Cloud' }, + { label: 'Satisfaction', value: '4.95 / 5', helper: 'Verified client reviews' }, + ], + socials: [ + { label: 'GitHub', href: 'https://github.com/GothwadTech' }, + { label: 'X (Twitter)', href: 'https://x.com/gothwadtech' }, + { label: 'LinkedIn', href: 'https://linkedin.com/company/gothwadtech' }, + { label: 'Dribbble', href: 'https://github.com/GothwadTech' }, + ], +}; + +export const ROOT_DOMAIN = 'gothwadtech.com'; diff --git a/src/data/ecosystem.ts b/src/data/ecosystem.ts new file mode 100644 index 0000000..b43ac63 --- /dev/null +++ b/src/data/ecosystem.ts @@ -0,0 +1,569 @@ +import { + Fingerprint, + Mail, + HardDrive, + Video, + ShoppingBag, + CalendarDays, + Users, + NotebookText, + Play, + MessageCircle, + Send, + Globe, + GraduationCap, + Sparkles, + HardDriveIcon, + MonitorSmartphone, + FileText, + Bot, + Computer, + Wifi, + LayoutGrid, + BookOpen, + ShieldCheck, + Terminal, + Building2, + Github, + ExternalLink, + Smartphone, +} from 'lucide-react'; +import type { LucideIcon } from 'lucide-react'; + +export interface EcosystemApp { + id: string; + name: string; + tagline: string; + description: string; + host: string; // subdomain + href: string; // full https url + githubRepo?: string; + githubUrl?: string; + icon: LucideIcon; + accent: string; // tailwind bg for tile + iconBg: string; + iconText: string; + category: 'identity' | 'productivity' | 'communication' | 'media' | 'devices' | 'education' | 'devtools' | 'company'; + core?: boolean; // can't be disconnected (account-connected) + badge?: string; + platforms: string[]; + available: boolean; // true if subdomain exists +} + +export const ROOT_DOMAIN = 'gothwadtech.com'; + +function url(host: string) { + return `https://${host}.${ROOT_DOMAIN}`; +} + +function repoUrl(repo: string) { + return `https://github.com/GothwadTech/${repo}`; +} + +export const ECOSYSTEM_APPS: EcosystemApp[] = [ + // —————————————————————————————————— + // Identity & Core (account-connected) + // —————————————————————————————————— + { + id: 'accounts', + name: 'Gothwad Accounts', + tagline: 'One identity for everything', + description: 'Sign in once. OAuth 2.0 + PKCE, session management and connected apps directory.', + host: 'accounts', + href: url('accounts'), + githubRepo: 'accounts', + githubUrl: repoUrl('accounts'), + icon: Fingerprint, + accent: 'bg-orange-500', + iconBg: 'bg-orange-500/10 border-orange-500/20', + iconText: 'text-orange-600 dark:text-orange-400', + category: 'identity', + core: true, + badge: 'Identity', + platforms: ['Web', 'OAuth 2.0'], + available: true, + }, + { + id: 'mail', + name: 'Gothwad Mail', + tagline: 'Your Gothwad inbox', + description: 'Edge-powered inbox. Send, receive and manage @gothwadtech.com email on Cloudflare.', + host: 'mail', + href: url('mail'), + githubRepo: 'mail', + githubUrl: repoUrl('mail'), + icon: Mail, + accent: 'bg-[#0494f4]', + iconBg: 'bg-[#0494f4]/10 border-[#0494f4]/20', + iconText: 'text-[#0494f4]', + category: 'productivity', + core: true, + badge: 'Core', + platforms: ['Web', 'Cloudflare Workers'], + available: true, + }, + { + id: 'drive', + name: 'Gothwad Drive', + tagline: 'Files and folders', + description: 'Cloud file storage with sharing, previews and Telegram-backed ClashDrive extension.', + host: 'drive', + href: url('drive'), + githubRepo: 'drive', + githubUrl: repoUrl('drive'), + icon: HardDrive, + accent: 'bg-emerald-500', + iconBg: 'bg-emerald-500/10 border-emerald-500/20', + iconText: 'text-emerald-600 dark:text-emerald-400', + category: 'productivity', + core: true, + badge: 'Core', + platforms: ['Web', 'Cloud'], + available: true, + }, + { + id: 'meet', + name: 'Gothwad Meet', + tagline: 'Video meetings', + description: 'WebRTC peer-to-peer meetings. No installs. Share links and meet face to face.', + host: 'meet', + href: url('meet'), + githubRepo: 'meet', + githubUrl: repoUrl('meet'), + icon: Video, + accent: 'bg-amber-500', + iconBg: 'bg-amber-500/10 border-amber-500/20', + iconText: 'text-amber-600 dark:text-amber-400', + category: 'communication', + core: true, + badge: 'Core', + platforms: ['Web', 'WebRTC'], + available: true, + }, + { + id: 'calendar', + name: 'Gothwad Calendar', + tagline: 'Events and reminders', + description: 'Schedule events, invites and reminders — synced with your Gothwad Account.', + host: 'calender', // DNS record is actually spelled calender (kept compatible) + href: url('calender'), + githubRepo: 'calendar', + githubUrl: repoUrl('calender'), + icon: CalendarDays, + accent: 'bg-violet-500', + iconBg: 'bg-violet-500/10 border-violet-500/20', + iconText: 'text-violet-600 dark:text-violet-400', + category: 'productivity', + core: true, + badge: 'Core', + platforms: ['Web'], + available: true, + }, + { + id: 'contacts', + name: 'Gothwad Contacts', + tagline: 'People and addresses', + description: 'Manage contacts and address book, synced across Gothwad apps.', + host: 'contacts', + href: url('contacts'), + githubRepo: 'contacts', + githubUrl: repoUrl('contacts'), + icon: Users, + accent: 'bg-cyan-500', + iconBg: 'bg-cyan-500/10 border-cyan-500/20', + iconText: 'text-cyan-600 dark:text-cyan-400', + category: 'productivity', + core: true, + badge: 'Core', + platforms: ['Web'], + available: true, + }, + { + id: 'notes', + name: 'Gothwad Notes', + tagline: 'Notes and lists, synced', + description: 'Markdown notes with lists and quick capture, synced via Gothwad account.', + host: 'notes', + href: url('notes'), + githubRepo: 'notes', + githubUrl: repoUrl('notes'), + icon: NotebookText, + accent: 'bg-rose-500', + iconBg: 'bg-rose-500/10 border-rose-500/20', + iconText: 'text-rose-600 dark:text-rose-400', + category: 'productivity', + core: true, + badge: 'Core', + platforms: ['Web'], + available: true, + }, + { + id: 'store', + name: 'Gothwad Store', + tagline: 'Apps and add-ons', + description: 'Kiwi Store — India’s open-source app HUB. Discover and install Gothwad add-ons.', + host: 'store', + href: url('store'), + githubRepo: 'store', + githubUrl: repoUrl('store'), + icon: ShoppingBag, + accent: 'bg-orange-600', + iconBg: 'bg-orange-500/10 border-orange-500/20', + iconText: 'text-orange-700 dark:text-orange-400', + category: 'media', + core: true, + badge: 'Store', + platforms: ['Web'], + available: true, + }, + // —————————————————————————————————— + // Consumer / Communication / Media + // —————————————————————————————————— + { + id: 'tube', + name: 'Gothwad Tube', + tagline: 'A better way to watch', + description: 'Video discovery — PlusTube web platform + PlusTube app with Gothwad Account login.', + host: 'tube', + href: url('tube'), + githubRepo: 'tubeweb', + githubUrl: repoUrl('tubeweb'), + icon: Play, + accent: 'bg-red-600', + iconBg: 'bg-red-500/10 border-red-500/20', + iconText: 'text-red-600 dark:text-red-400', + category: 'media', + badge: 'Video', + platforms: ['Web', 'Android'], + available: true, + }, + { + id: 'grixchat', + name: 'GrixChat', + tagline: 'Messaging, together', + description: 'Real-time messenger & calling. Instagram + WhatsApp-like, mobile-first. <15ms dispatch.', + host: 'grixchat', + href: url('grixchat'), + githubRepo: 'grixchat', + githubUrl: repoUrl('grixchat'), + icon: MessageCircle, + accent: 'bg-teal-500', + iconBg: 'bg-teal-500/10 border-teal-500/20', + iconText: 'text-teal-600 dark:text-teal-400', + category: 'communication', + badge: 'Messenger', + platforms: ['Web', 'Android'], + available: true, + }, + { + id: 'indogram', + name: 'Indogram', + tagline: 'Sovereign cloud communities', + description: 'Telegram-style sovereign cloud: 200k groups, unlimited storage, bots & multi-device.', + host: 'indogram', + href: url('indogram'), + githubRepo: 'indogramapp', + githubUrl: repoUrl('indogramapp'), + icon: Send, + accent: 'bg-sky-500', + iconBg: 'bg-sky-500/10 border-sky-500/20', + iconText: 'text-sky-600 dark:text-sky-400', + category: 'communication', + badge: 'Cloud Messenger', + platforms: ['Web', 'Android'], + available: true, + }, + { + id: 'browser', + name: 'Gothwad Browser', + tagline: 'Built for the bigger screen', + description: 'Ultra-light Rust/C++ sovereign browser — 11.8 MB, 75% less RAM, TurboShield ad-block.', + host: 'browser', + href: url('browser'), + githubRepo: 'browser', + githubUrl: repoUrl('browser'), + icon: Globe, + accent: 'bg-[#0494f4]', + iconBg: 'bg-[#0494f4]/10 border-[#0494f4]/20', + iconText: 'text-[#0494f4]', + category: 'devices', + badge: 'Flagship', + platforms: ['Android', 'Android TV', 'Web'], + available: true, + }, + { + id: 'launcher', + name: 'Gothwad Launcher', + tagline: 'Android TV home', + description: 'TV Launcher for Android TVs & tablets — simple, remote-friendly, ad-free recent apps.', + host: 'launcher', + href: repoUrl('launcher'), + githubRepo: 'launcher', + githubUrl: repoUrl('launcher'), + icon: MonitorSmartphone, + accent: 'bg-blue-600', + iconBg: 'bg-blue-500/10 border-blue-500/20', + iconText: 'text-blue-600 dark:text-blue-400', + category: 'devices', + badge: 'Android TV', + platforms: ['Android TV'], + available: true, + }, + { + id: 'manager', + name: 'Gothwad Manager', + tagline: 'File manager for Android', + description: 'All-in-one file manager — RTL, folder sizes, fast and efficient explorer.', + host: 'manager', + href: repoUrl('manager'), + githubRepo: 'manager', + githubUrl: repoUrl('manager'), + icon: FileText, + accent: 'bg-orange-500', + iconBg: 'bg-orange-500/10 border-orange-500/20', + iconText: 'text-orange-600 dark:text-orange-400', + category: 'devices', + badge: 'File Manager', + platforms: ['Android', 'TV'], + available: true, + }, + { + id: 'remotedesk', + name: 'Gothwad Remote Desktop', + tagline: 'Windows remote, zero-database', + description: '100% Zero-Database Cloudflare Pages portal — Win11 OS + Hyper-V isolated VM, WebRTC P2P.', + host: 'remotedesk', + href: url('remotedesk'), + githubRepo: 'remotedesk', + githubUrl: repoUrl('remotedesk'), + icon: Computer, + accent: 'bg-zinc-800', + iconBg: 'bg-zinc-800/10 border-zinc-800/20', + iconText: 'text-zinc-700 dark:text-zinc-300', + category: 'devtools', + badge: 'Windows', + platforms: ['Web', 'Windows'], + available: true, + }, + { + id: 'internet', + name: 'Gothwad Internet', + tagline: 'Lightweight phone browser', + description: 'Lightweight browser for Android phones — fastest, lightest multitasking with file manager.', + host: 'internet', + href: repoUrl('internet'), + githubRepo: 'internet', + githubUrl: repoUrl('internet'), + icon: Wifi, + accent: 'bg-sky-600', + iconBg: 'bg-sky-500/10 border-sky-500/20', + iconText: 'text-sky-700 dark:text-sky-400', + category: 'devices', + badge: 'Phone Browser', + platforms: ['Android'], + available: true, + }, + { + id: 'computer', + name: 'Gothwad Computer', + tagline: 'Desktop mode for Android', + description: 'Android app that gives phones a desktop-like TV experience with external input support.', + host: 'computer', + href: repoUrl('computer'), + githubRepo: 'computer', + githubUrl: repoUrl('computer'), + icon: Computer, + accent: 'bg-zinc-700', + iconBg: 'bg-zinc-700/10 border-zinc-700/20', + iconText: 'text-zinc-700 dark:text-zinc-300', + category: 'devices', + badge: 'Desktop', + platforms: ['Android', 'TV'], + available: true, + }, + // —————————————————————————————————— + // Education + Dev + AI + // —————————————————————————————————— + { + id: 'education', + name: 'Gothwad Education', + tagline: 'School & learning platform', + description: 'Admin + Teacher + Student + Parent experiences. PWParent apps, fees, attendance, ERP.', + host: 'education', + href: url('education'), + githubRepo: 'education', + githubUrl: 'https://github.com/GothwadTech/education', + icon: GraduationCap, + accent: 'bg-indigo-500', + iconBg: 'bg-indigo-500/10 border-indigo-500/20', + iconText: 'text-indigo-600 dark:text-indigo-400', + category: 'education', + badge: 'ERP', + platforms: ['Web', 'Android'], + available: true, + }, + { + id: 'clashdrive', + name: 'ClashDrive', + tagline: 'Telegram-backed storage', + description: 'Browser storage workspace built over Telegram supergroup forum topics.', + host: 'clashdrive', + href: url('clashdrive'), + githubRepo: 'Clashdrive', + githubUrl: repoUrl('Clashdrive'), + icon: HardDriveIcon, + accent: 'bg-lime-600', + iconBg: 'bg-lime-600/10 border-lime-600/20', + iconText: 'text-lime-700 dark:text-lime-400', + category: 'productivity', + badge: 'Storage', + platforms: ['Web'], + available: true, + }, + { + id: 'ai', + name: 'Gothwad AI Studio', + tagline: 'Developer workspace', + description: 'Mobile-first dev workspace: browse GH repos, manage files and edit code on the go.', + host: 'ai', + href: url('ai'), + githubRepo: 'ai', + githubUrl: repoUrl('ai'), + icon: Sparkles, + accent: 'bg-fuchsia-500', + iconBg: 'bg-fuchsia-500/10 border-fuchsia-500/20', + iconText: 'text-fuchsia-600 dark:text-fuchsia-400', + category: 'devtools', + badge: 'AI', + platforms: ['Web', 'Mobile'], + available: true, + }, + { + id: 'plusgit', + name: 'PlusGit', + tagline: 'Git for mobile', + description: 'Gothwad Git client — manage repositories from your phone with ease.', + host: 'plusgit', + href: repoUrl('plusgit'), + githubRepo: 'plusgit', + githubUrl: repoUrl('plusgit'), + icon: Terminal, + accent: 'bg-zinc-900', + iconBg: 'bg-zinc-900/10 border-zinc-900/20', + iconText: 'text-zinc-900 dark:text-zinc-400', + category: 'devtools', + badge: 'Git', + platforms: ['Android', 'Web'], + available: true, + }, + // —————————————————————————————————— + // Company hubs + // —————————————————————————————————— + { + id: 'docs', + name: 'Gothwad Docs', + tagline: 'Developer documentation', + description: 'Central source-based docs — Accounts OAuth/PKCE, Mail REST, Tube web, GrixChat, Meet & more.', + host: 'docs', + href: url('docs'), + githubRepo: 'docs', + githubUrl: repoUrl('docs'), + icon: BookOpen, + accent: 'bg-amber-600', + iconBg: 'bg-amber-600/10 border-amber-600/20', + iconText: 'text-amber-700 dark:text-amber-400', + category: 'company', + badge: 'Docs', + platforms: ['Web'], + available: true, + }, + { + id: 'ceo', + name: 'CEO — Yuvkesh Meena', + tagline: 'Leadership profile', + description: 'Meet Yuvkesh Meena, CEO of Gothwad Tech. Born in Dausa, Rajasthan.', + host: 'ceo', + href: url('ceo'), + githubRepo: 'ceo', + githubUrl: repoUrl('ceo'), + icon: Building2, + accent: 'bg-zinc-700', + iconBg: 'bg-zinc-800/10 border-zinc-800/20', + iconText: 'text-zinc-700 dark:text-zinc-300', + category: 'company', + badge: 'Leadership', + platforms: ['Web'], + available: true, + }, + { + id: 'about', + name: 'About Gothwad Tech', + tagline: 'Corporate & company site', + description: 'Learn about mission: Aatmanirbhar Bharat, sovereign consumer apps & enterprise solutions.', + host: 'www', + href: 'https://www.gothwadtech.com', + githubRepo: 'gothwadtech', + githubUrl: repoUrl('gothwadtech'), + icon: Building2, + accent: 'bg-[#0494f4]', + iconBg: 'bg-[#0494f4]/10 border-[#0494f4]/20', + iconText: 'text-[#0494f4]', + category: 'company', + badge: 'About', + platforms: ['Web'], + available: true, + }, + { + id: 'accountsapp', + name: 'Gothwad Accounts App', + tagline: 'Native account manager', + description: 'Android accounts companion: manage Gothwad identity on device.', + host: 'accountsapp', + href: repoUrl('accountsapp'), + githubRepo: 'accountsapp', + githubUrl: repoUrl('accountsapp'), + icon: Smartphone, + accent: 'bg-orange-500', + iconBg: 'bg-orange-500/10 border-orange-500/20', + iconText: 'text-orange-600 dark:text-orange-400', + category: 'identity', + badge: 'Android', + platforms: ['Android'], + available: true, + }, + { + id: 'domains', + name: 'Gothwad Domains', + tagline: 'Ecosystem domains', + description: 'Public domain registry and routing map for Gothwad Tech.', + host: 'domains', + href: repoUrl('domains'), + githubRepo: 'domains', + githubUrl: repoUrl('domains'), + icon: LayoutGrid, + accent: 'bg-zinc-600', + iconBg: 'bg-zinc-600/10 border-zinc-600/20', + iconText: 'text-zinc-600 dark:text-zinc-400', + category: 'company', + badge: 'Registry', + platforms: ['Git'], + available: true, + }, +]; + +export const CATEGORIES = [ + { id: 'all', label: 'All products', count: ECOSYSTEM_APPS.length }, + { id: 'identity', label: 'Identity & security' }, + { id: 'productivity', label: 'Productivity' }, + { id: 'communication', label: 'Communication' }, + { id: 'media', label: 'Media & apps' }, + { id: 'devices', label: 'Devices & TV' }, + { id: 'education', label: 'Education' }, + { id: 'devtools', label: 'Developer tools' }, + { id: 'company', label: 'Company & docs' }, +] as const; + +export type CategoryId = (typeof CATEGORIES)[number]['id']; + +// Legacy alias for home portal quick shortcuts (mirrors GOTHWAD_APPS) +export const PORTAL_FAVORITES = ['mail', 'drive', 'meet', 'tube', 'grixchat', 'browser', 'docs', 'accounts', 'education', 'store', 'ai', 'ceo']; diff --git a/src/hooks/useGothwadSession.ts b/src/hooks/useGothwadSession.ts new file mode 100644 index 0000000..230e6ca --- /dev/null +++ b/src/hooks/useGothwadSession.ts @@ -0,0 +1,25 @@ +import { useEffect, useState, useCallback } from "react"; +import { fetchGothwadSession, getCurrentAuthuser, type FetchMeResult } from "../lib/gothwadSso"; +import { preloadGothwadAccountMenu } from "../lib/accountMenuWidget"; + +export function useGothwadSession() { + const [data, setData] = useState(null); + const [loading, setLoading] = useState(true); + + const refresh = useCallback(async () => { + const authuser = getCurrentAuthuser(); + setLoading(true); + const res = await fetchGothwadSession(authuser); + setData(res); + setLoading(false); + if (res.authenticated) preloadGothwadAccountMenu(); + }, []); + + useEffect(() => { + void refresh(); + // preload widget even before auth resolves, so first click is 0ms + preloadGothwadAccountMenu(); + }, [refresh]); + + return { data, loading, refresh, authuser: data?.authuser ?? getCurrentAuthuser(), authenticated: data?.authenticated ?? false }; +} diff --git a/src/index.css b/src/index.css new file mode 100644 index 0000000..2cf418f --- /dev/null +++ b/src/index.css @@ -0,0 +1,73 @@ +@import "tailwindcss"; + +@custom-variant dark (&:where(.dark, .dark *)); + +@theme { + --color-brand-50: #eef8ff; + --color-brand-100: #d8efff; + --color-brand-200: #bae3ff; + --color-brand-300: #8bd3ff; + --color-brand-400: #54baff; + --color-brand-500: #0494f4; + --color-brand-600: #0077cd; + --color-brand-700: #005fa7; + --color-brand-800: #045089; + --color-brand-900: #0a4372; + --color-brand-950: #062b4c; + --color-brand: #0494f4; + + --color-zinc-950: #202124; + --color-zinc-900: #292a2d; + --color-zinc-850: #2e2f33; + --color-zinc-800: #303134; + --color-zinc-700: #3c4043; + --color-zinc-600: #5f6368; + --color-zinc-500: #80868b; + --color-zinc-400: #9aa0a6; + --color-zinc-300: #bdc1c6; + --color-zinc-200: #dadce0; + --color-zinc-100: #f1f3f4; + --color-zinc-50: #f8f9fa; +} + +:root { + --primary-brand: #0494f4; +} + +html.dark, +html.dark body { + background-color: #202124 !important; + color: #e8eaed !important; +} + +html.light, +html.light body { + background-color: #ffffff !important; + color: #202124 !important; +} + +* { + -webkit-tap-highlight-color: transparent; +} + +body { + will-change: auto; + font-family: 'Plus Jakarta Sans', ui-sans-serif, system-ui, -apple-system, sans-serif; +} + +h1,h2,h3 { + font-family: 'Space Grotesk', sans-serif; +} + +/* scrollbar */ +::-webkit-scrollbar { + width: 8px; + height: 8px; +} +::-webkit-scrollbar-thumb { + background: #dadce0; + border-radius: 999px; +} +.dark ::-webkit-scrollbar-thumb { + background: #3c4043; +} diff --git a/src/lib/accountMenuWidget.ts b/src/lib/accountMenuWidget.ts new file mode 100644 index 0000000..00d90fc --- /dev/null +++ b/src/lib/accountMenuWidget.ts @@ -0,0 +1,242 @@ +/** + * Gothwad Website — Account switcher (port of drive's accountMenuWidget) + * Same Google-style sheet that Mail/Drive use, hosted at accounts.gothwadtech.com/widget/account-menu.js + * Falls back to inline shadow-DOM sheet when widget unreachable/offline. + */ +import { + ACCOUNT_WIDGET_URL, + ACCOUNTS_API_ORIGIN, + ACCOUNTS_WEB_ORIGIN, + APP_DOMAIN, + ECOSYSTEM_NAME, +} from "../config/brand"; +import type { GothwadAccountItem, GothwadSsoUser } from "./gothwadSso"; + +export interface GothwadAccountMenuOptions { + appDomain?: string; + accountsWebOrigin?: string; + accountsApiOrigin?: string; + ecosystemName?: string; + theme?: "light" | "dark" | "system"; + anchorEl?: HTMLElement | null; + nextUrl?: string; + manageAccountHref?: string; + accountHref?: (acct: GothwadAccountItem) => string; + onSwitchAccount?: (acct: GothwadAccountItem) => void | Promise; + onSignOutAccount?: (slotId: string) => void | Promise; + onSignOutAll?: () => void | Promise; + onClose?: () => void; + onError?: (msg: string) => void; + extraActions?: { label: string; onClick: () => void }[]; +} + +export interface GothwadAccountMenuState { + user: GothwadSsoUser | null; + accounts: GothwadAccountItem[]; + activeId: string | null; + authuser: number; +} + +export interface GothwadAccountMenuController { + isOpen(): boolean; + open(state: GothwadAccountMenuState, opts?: GothwadAccountMenuOptions): void; + update(patchState: Partial, patchOpts?: Partial): void; + close(): void; +} + +declare global { + interface Window { + GothwadAccountMenu?: GothwadAccountMenuController; + } +} + +const AVATAR_PALETTE = ["#9334a6", "#0b57d0", "#0d652d", "#c5221f", "#00639b", "#b06000", "#7627bb", "#185abc"]; + +function esc(value: unknown): string { + return String(value ?? "").replace(/[&<>"']/g, (ch) => ({ "&": "&", "<": "<", ">": ">", '"': """, "'": "'" }[ch] || ch)); +} + +export function avatarColorFor(seed: string): string { + const s = String(seed || "u").toLowerCase(); + let hash = 0; + for (let i = 0; i < s.length; i += 1) hash = ((hash << 5) - hash + s.charCodeAt(i)) | 0; + return AVATAR_PALETTE[Math.abs(hash) % AVATAR_PALETTE.length]; +} + +export function initialsFrom(name?: string, fallback?: string): string { + const full = String(name || fallback || "?").trim(); + const parts = full.split(/[\s._@-]+/).filter(Boolean); + if (parts.length >= 2) return (parts[0][0] + parts[1][0]).toUpperCase(); + return full.slice(0, 1).toUpperCase() || "?"; +} + +export function initialsFromAccount(item?: Partial | null): string { + const full = `${item?.firstName || ""} ${item?.lastName || ""}`.trim() || String(item?.name || (item as any)?.username || "?").trim(); + return initialsFrom(full); +} + +const FALLBACK_CSS = ` +.gw-layer{--gw-surface:#eef3f8;--gw-card:#ffffff;--gw-card-hover:#f5f8fc;--gw-text:#1f1f1f;--gw-subtext:#444746;--gw-accent:#0b57d0;--gw-danger:#b3261e;--gw-danger-bg:#fceeee;--gw-border:rgba(0,0,0,0.08);position:fixed;inset:0;z-index:2147483000;font-family:system-ui,-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,sans-serif;color:var(--gw-text)} +.gw-layer[data-theme="dark"]{--gw-surface:#1b1f26;--gw-card:#282c34;--gw-card-hover:#323741;--gw-text:#e3e3e3;--gw-subtext:#c4c7c5;--gw-accent:#8ab4f8;--gw-danger:#f28b82;--gw-danger-bg:#3c2525;--gw-border:rgba(255,255,255,0.1)} +.gw-backdrop{position:fixed;inset:0;background:rgba(0,0,0,0.28)} +.gw-sheet{position:fixed;inset:0;display:flex;flex-direction:column;background:var(--gw-surface);overflow-y:auto;padding:14px 16px 20px} +@media(min-width:640px){.gw-backdrop{background:transparent}.gw-sheet{inset:auto;top:var(--gw-top,58px);right:var(--gw-right,16px);width:388px;max-width:calc(100vw - 24px);border-radius:28px;border:1px solid var(--gw-border);box-shadow:0 16px 42px rgba(0,0,0,0.24),0 2px 8px rgba(0,0,0,0.12)}} +.gw-topbar{display:flex;justify-content:flex-end;margin-bottom:4px} +.gw-close{width:36px;height:36px;border:none;border-radius:999px;background:transparent;color:var(--gw-subtext);cursor:pointer;font-size:18px} +.gw-stack{display:flex;flex-direction:column;gap:2px} +.gw-hero{display:flex;align-items:center;gap:14px;background:var(--gw-card);padding:16px 18px;border-radius:24px 24px 4px 4px} +.gw-avatar{display:inline-grid;place-items:center;border-radius:999px;overflow:hidden;color:#fff;font-weight:600;flex-shrink:0} +.gw-avatar img{width:100%;height:100%;object-fit:cover;display:block} +.gw-hero-name{font-size:18px;font-weight:600;color:var(--gw-text)} +.gw-hero-email{font-size:13px;color:var(--gw-subtext);margin-top:2px} +.gw-row{display:flex;align-items:center;gap:14px;width:100%;min-height:56px;padding:10px 18px;border:none;border-radius:4px;background:var(--gw-card);color:var(--gw-text);text-align:left;text-decoration:none;font-size:14px;font-weight:500;cursor:pointer;box-sizing:border-box} +.gw-row:hover{background:var(--gw-card-hover)} +.gw-row.is-last{border-radius:4px 4px 24px 24px} +.gw-acct-meta{flex:1;min-width:0} +.gw-acct-name{display:block;font-size:14px;font-weight:500;color:var(--gw-text);overflow:hidden;text-overflow:ellipsis;white-space:nowrap} +.gw-acct-email{display:block;font-size:12px;color:var(--gw-subtext);overflow:hidden;text-overflow:ellipsis;white-space:nowrap} +.gw-manage-pill{display:flex;align-items:center;justify-content:center;gap:10px;width:100%;min-height:50px;margin-top:12px;padding:0 20px;border-radius:999px;background:var(--gw-card);color:var(--gw-text);text-decoration:none;font-size:14px;font-weight:500;box-sizing:border-box} +.gw-manage-pill:hover{background:var(--gw-card-hover)} +.gw-extra-group{display:flex;flex-direction:column;gap:2px;margin-top:10px} +.gw-extra-group .gw-row{border-radius:20px} +`; + +function renderAvatarHtml(acct: Partial, sizePx: number): string { + const bg = avatarColorFor((acct as any).username || (acct as any).email || (acct as any).name || "u"); + const label = esc(initialsFromAccount(acct)); + const fontSize = Math.max(13, Math.round(sizePx * 0.42)); + if ((acct as any).avatarUrl || (acct as any).avatar_url) { + const url = esc((acct as any).avatarUrl || (acct as any).avatar_url); + return ``; + } + return `${label}`; +} + +class FallbackAccountMenu implements GothwadAccountMenuController { + private hostEl: HTMLDivElement | null = null; + private layerEl: HTMLDivElement | null = null; + private state: GothwadAccountMenuState = { user: null, accounts: [], activeId: null, authuser: 0 }; + private opts: GothwadAccountMenuOptions = {}; + private onKey = (e: KeyboardEvent) => { if (e.key === "Escape") this.close(); }; + isOpen() { return Boolean(this.hostEl); } + open(state: GothwadAccountMenuState, opts: GothwadAccountMenuOptions = {}) { + this.state = { ...this.state, ...state }; + this.opts = { ...opts }; + if (!this.hostEl && typeof document !== "undefined") { + this.hostEl = document.createElement("div"); + const shadow = (this.hostEl as any).attachShadow ? this.hostEl.attachShadow({ mode: "open" }) : this.hostEl; + const style = document.createElement("style"); + style.textContent = FALLBACK_CSS; + this.layerEl = document.createElement("div"); + this.layerEl.className = "gw-layer"; + shadow.appendChild(style); + shadow.appendChild(this.layerEl); + document.body.appendChild(this.hostEl); + window.addEventListener("keydown", this.onKey); + } + this.render(); + } + update(patchState: Partial, patchOpts?: Partial) { + this.state = { ...this.state, ...patchState }; + if (patchOpts) this.opts = { ...this.opts, ...patchOpts }; + if (this.isOpen()) this.render(); + } + close() { + if (!this.hostEl) return; + this.hostEl.remove(); + this.hostEl = null; + this.layerEl = null; + window.removeEventListener("keydown", this.onKey); + this.opts.onClose?.(); + } + private render() { + if (!this.layerEl) return; + const isDark = this.opts.theme === "dark" || (this.opts.theme !== "light" && document.documentElement.classList.contains("dark")); + this.layerEl.setAttribute("data-theme", isDark ? "dark" : "light"); + const rect = this.opts.anchorEl?.getBoundingClientRect?.(); + if (rect) { + this.layerEl.style.setProperty("--gw-top", `${Math.max(12, Math.round(rect.bottom + 10))}px`); + this.layerEl.style.setProperty("--gw-right", `${Math.max(12, Math.round(window.innerWidth - rect.right))}px`); + } + const active = this.state.user || (this.state.accounts[0] as any); + const others = (this.state.accounts || []).filter((a) => (a.username || (a as any).email || "").toLowerCase() !== (active?.username || (active as any)?.email || "").toLowerCase()); + const webOrigin = this.opts.accountsWebOrigin || ACCOUNTS_WEB_ORIGIN; + const nextUrl = this.opts.nextUrl || (typeof window !== "undefined" ? window.location.href : ""); + const addHref = `${webOrigin}/signin?choose=1&add=1&next=${encodeURIComponent(nextUrl)}`; + const manageHref = this.opts.manageAccountHref || `${webOrigin}/u/${this.state.authuser}/me`; + const extraActions = this.opts.extraActions || []; + this.layerEl.innerHTML = ` +
+ + `; + this.layerEl.querySelectorAll('[data-action="close"]').forEach((el) => el.addEventListener("click", () => this.close())); + this.layerEl.querySelectorAll("[data-switch]").forEach((el) => { + el.addEventListener("click", (e) => { + if ((e as MouseEvent).metaKey || (e as MouseEvent).ctrlKey) return; + e.preventDefault(); + const id = el.getAttribute("data-switch"); + const target = this.state.accounts.find((a) => a.id === id); + this.close(); + if (target) void this.opts.onSwitchAccount?.(target); + }); + }); + this.layerEl.querySelector('[data-action="signout-active"]')?.addEventListener("click", () => { + const slotId = this.state.activeId || this.state.accounts[0]?.id || "a"; + this.close(); + if (this.opts.onSignOutAccount) void this.opts.onSignOutAccount(slotId); + else void this.opts.onSignOutAll?.(); + }); + this.layerEl.querySelectorAll("[data-extra]").forEach((el) => { + el.addEventListener("click", () => { + const idx = Number(el.getAttribute("data-extra")); + this.close(); + extraActions[idx]?.onClick?.(); + }); + }); + } +} + +let preloadStarted = false; + +export function preloadGothwadAccountMenu(): void { + if (typeof window === "undefined") return; + if (!window.GothwadAccountMenu) window.GothwadAccountMenu = new FallbackAccountMenu(); + if (preloadStarted) return; + preloadStarted = true; + try { + if (!document.querySelector(`script[src="${ACCOUNT_WIDGET_URL}"]`)) { + const script = document.createElement("script"); + script.type = "module"; + script.async = true; + script.src = ACCOUNT_WIDGET_URL; + document.head.appendChild(script); + } + } catch {} +} + +export function openGothwadAccountMenu(state: GothwadAccountMenuState, opts: GothwadAccountMenuOptions): void { + preloadGothwadAccountMenu(); + window.GothwadAccountMenu?.open(state, { + appDomain: APP_DOMAIN, + accountsWebOrigin: ACCOUNTS_WEB_ORIGIN, + accountsApiOrigin: `${ACCOUNTS_API_ORIGIN}/api`, + ecosystemName: ECOSYSTEM_NAME, + ...opts, + }); +} + +export const preloadAccountMenuWidget = preloadGothwadAccountMenu; +export const openAccountMenu = openGothwadAccountMenu; diff --git a/src/lib/gothwadSso.ts b/src/lib/gothwadSso.ts new file mode 100644 index 0000000..1e89c76 --- /dev/null +++ b/src/lib/gothwadSso.ts @@ -0,0 +1,167 @@ +import { + ACCOUNTS_API_ORIGIN, + ACCOUNTS_WEB_ORIGIN, + buildAccountSlotPath, + buildSignInUrl, + formatGothwadEmail, + parseAuthuserFromUrl, +} from "../config/brand"; + +export const DEFAULT_API_TIMEOUT_MS = 8000; + +export interface GothwadSsoUser { + id: string; + username?: string; + email: string; + firstName?: string; + lastName?: string; + name: string; + avatarUrl?: string | null; + avatar_url?: string | null; +} + +export interface GothwadAccountItem { + id: string; + authuser: number; + username?: string; + name: string; + firstName?: string; + lastName?: string; + email: string; + avatarUrl?: string | null; + avatar_url?: string | null; + accountUrl?: string | null; +} + +export type ServiceErrorKind = "none" | "routing_html" | "http_5xx" | "rate_limited" | "network" | "timeout" | "redirect"; + +export interface FetchMeResult { + status: "authenticated" | "anonymous" | "error"; + authenticated: boolean; + activeId: string | null; + authuser: number; + user: GothwadSsoUser | null; + accounts: GothwadAccountItem[]; + errorKind: ServiceErrorKind; + errorMessage: string | null; +} + +function normalizeClientUser(raw: any): GothwadSsoUser | null { + if (!raw || typeof raw !== "object") return null; + const id = String(raw.id || raw.userId || "").trim(); + const rawEmail = String(raw.email || "").trim().toLowerCase(); + const username = String(raw.username || (rawEmail ? rawEmail.split("@")[0] : "")).trim().toLowerCase(); + if (!id || !username) return null; + const firstName = String(raw.firstName ?? raw.first_name ?? "").trim(); + const lastName = String(raw.lastName ?? raw.last_name ?? "").trim(); + const name = String(raw.name || `${firstName} ${lastName}`.trim() || username).trim(); + const avatarUrl = raw.avatarUrl ?? raw.avatar_url ?? null; + return { id, username, email: formatGothwadEmail(raw.email || username), firstName, lastName, name, avatarUrl: avatarUrl ? String(avatarUrl) : null, avatar_url: avatarUrl ? String(avatarUrl) : null }; +} + +function normalizeClientAccount(raw: any, idx: number): GothwadAccountItem { + const username = String(raw?.username || "").trim().toLowerCase(); + const firstName = String(raw?.firstName ?? raw?.first_name ?? "").trim(); + const lastName = String(raw?.lastName ?? raw?.last_name ?? "").trim(); + const name = String(raw?.name || `${firstName} ${lastName}`.trim() || username || "Account").trim(); + const authuser = Number.isInteger(raw?.authuser) ? Number(raw.authuser) : idx; + const avatarUrl = raw?.avatarUrl ?? raw?.avatar_url ?? null; + return { + id: String(raw?.id || raw?.slot || "a"), + authuser, + username, + name, + firstName, + lastName, + email: formatGothwadEmail(raw?.email || username), + avatarUrl: avatarUrl ? String(avatarUrl) : null, + avatar_url: avatarUrl ? String(avatarUrl) : null, + accountUrl: raw?.accountUrl || `${ACCOUNTS_WEB_ORIGIN}/u/${authuser}/me`, + }; +} + +export function getCurrentAuthuser(): number { + return parseAuthuserFromUrl().authuser; +} +export const slotUrl = buildAccountSlotPath; +export const buildSsoSignInUrl = buildSignInUrl; + +function buildAuthuserHeaders(authuser?: number): Record { + const h: Record = { Accept: "application/json" }; + if (Number.isInteger(authuser) && authuser! >= 0 && authuser! <= 5) h["X-Gothwad-Authuser"] = String(authuser); + return h; +} + +async function fetchBounded(url: string, init: RequestInit, timeoutMs = DEFAULT_API_TIMEOUT_MS): Promise { + const controller = new AbortController(); + const timer = setTimeout(() => controller.abort(new Error("RequestTimeout")), timeoutMs); + try { + return await fetch(url, { ...init, cache: "no-store", redirect: "manual", signal: controller.signal }); + } finally { + clearTimeout(timer); + } +} + +export async function fetchGothwadSession(authuser = 0): Promise { + const headers = buildAuthuserHeaders(authuser); + const endpoint = `${ACCOUNTS_API_ORIGIN}/api/me`; + try { + const res = await fetchBounded(endpoint, { method: "GET", credentials: "include", headers }); + if (res.type === "opaqueredirect" || (res as any).redirected || (res.status >= 300 && res.status < 400)) { + return { status: "error", authenticated: false, activeId: null, authuser, user: null, accounts: [], errorKind: "redirect", errorMessage: "Identity redirect" }; + } + const ct = (res.headers.get("content-type") || "").toLowerCase(); + if (ct.includes("text/html")) { + return { status: "error", authenticated: false, activeId: null, authuser, user: null, accounts: [], errorKind: "routing_html", errorMessage: "HTML response" }; + } + if (res.status === 429) return { status: "error", authenticated: false, activeId: null, authuser, user: null, accounts: [], errorKind: "rate_limited", errorMessage: "Rate limited" }; + const data: any = await res.json().catch(() => null); + if (res.ok && data?.authenticated && data?.user) { + const user = normalizeClientUser(data.user); + if (!user) return { status: "error", authenticated: false, activeId: null, authuser, user: null, accounts: [], errorKind: "http_5xx", errorMessage: "Bad payload" }; + const accounts: GothwadAccountItem[] = Array.isArray(data.accounts) && data.accounts.length > 0 + ? data.accounts.map((a: any, i: number) => normalizeClientAccount(a, i)) + : [normalizeClientAccount({ ...user, id: data.activeId || "a", authuser: data.authuser ?? authuser }, 0)]; + return { status: "authenticated", authenticated: true, activeId: String(data.activeId || accounts[0]?.id || "a"), authuser: Number.isInteger(data.authuser) ? Number(data.authuser) : authuser, user, accounts, errorKind: "none", errorMessage: null }; + } + if (res.status === 200 || res.status === 401) { + return { status: "anonymous", authenticated: false, activeId: null, authuser, user: null, accounts: [], errorKind: "none", errorMessage: null }; + } + if (res.status >= 500) return { status: "error", authenticated: false, activeId: null, authuser, user: null, accounts: [], errorKind: "http_5xx", errorMessage: data?.message || `HTTP ${res.status}` }; + return { status: "anonymous", authenticated: false, activeId: null, authuser, user: null, accounts: [], errorKind: "none", errorMessage: null }; + } catch (err: any) { + const msg = err?.message || String(err); + if (msg.includes("RequestTimeout") || err?.name === "AbortError") { + return { status: "error", authenticated: false, activeId: null, authuser, user: null, accounts: [], errorKind: "timeout", errorMessage: "Timeout" }; + } + return { status: "error", authenticated: false, activeId: null, authuser, user: null, accounts: [], errorKind: "network", errorMessage: "Network error" }; + } +} + +export const fetchSsoMe = fetchGothwadSession; + +// Helpers for switch / signout — mirrored from drive +export async function switchGothwadAccountSlot(slotId: string, authuser: number): Promise<{ ok: boolean; error?: string }> { + const headers: Record = { ...buildAuthuserHeaders(authuser), "Content-Type": "application/json" }; + try { + const res = await fetchBounded(`${ACCOUNTS_API_ORIGIN}/api/auth/switch`, { method: "POST", credentials: "include", headers, body: JSON.stringify({ id: slotId, authuser }) }); + const ct = (res.headers.get("content-type") || "").toLowerCase(); + if (ct.includes("application/json")) { + const data: any = await res.json().catch(() => null); + if (res.ok && data?.ok !== false) return { ok: true }; + return { ok: false, error: data?.message || `Switch failed (${res.status})` }; + } + return { ok: res.ok }; + } catch { return { ok: false, error: "Network error" }; } +} + +export async function signOutGothwadSlot(slotId?: string, authuser = 0): Promise<{ ok: boolean }> { + const path = slotId ? `/api/auth/accounts/${encodeURIComponent(slotId)}/signout` : "/api/auth/signout"; + const headers: Record = { ...buildAuthuserHeaders(authuser), "Content-Type": "application/json" }; + try { + const res = await fetchBounded(`${ACCOUNTS_API_ORIGIN}${path}`, { method: "POST", credentials: "include", headers, body: "{}" }); + return { ok: res.ok }; + } catch { return { ok: false }; } +} +export const signOutSsoSlot = (slotId: string, authuser = 0) => signOutGothwadSlot(slotId, authuser); +export const signOutAllSso = (authuser = 0) => signOutGothwadSlot(undefined, authuser); diff --git a/src/main.tsx b/src/main.tsx new file mode 100644 index 0000000..2339d59 --- /dev/null +++ b/src/main.tsx @@ -0,0 +1,10 @@ +import React from 'react'; +import ReactDOM from 'react-dom/client'; +import App from './App'; +import './index.css'; + +ReactDOM.createRoot(document.getElementById('root')!).render( + + + +); diff --git a/src/pages/CompanyPage.tsx b/src/pages/CompanyPage.tsx new file mode 100644 index 0000000..52c24bb --- /dev/null +++ b/src/pages/CompanyPage.tsx @@ -0,0 +1,33 @@ +import React from 'react'; +import { Breadcrumbs } from '../components/Breadcrumbs'; + +export const CompanyPage: React.FC<{ onNavigate: (p: string) => void }> = ({ onNavigate }) => { + return ( +
+ +

Gothwad Tech

+

+ Sovereign software from Jaipur, Rajasthan — founder Pawan Gothwad, CEO Yuvkesh Meena. We build browsers, messaging and business tools for Bharat. Open-source on GitHub. +

+ +
+ {[ + { name: 'Pawan Gothwad', role: 'Founder', email: 'pawan@gothwadtech.com' }, + { name: 'Yuvkesh Meena', role: 'CEO', email: 'ceo@gothwadtech.com', highlight: true }, + { name: 'Vishnu Meena', role: 'CTO', email: 'vishnu@gothwadtech.com' }, + ].map((p) => ( + +
{p.name.split(' ').map(n=>n[0]).join('')}
+
{p.name}
+
{p.role}
+
{p.email}
+
+ ))} +
+ +
+ 12 specialists • founded 2023 • Aatmanirbhar Bharat • GitHub +
+
+ ); +}; diff --git a/src/pages/ContactPage.tsx b/src/pages/ContactPage.tsx new file mode 100644 index 0000000..73cfd95 --- /dev/null +++ b/src/pages/ContactPage.tsx @@ -0,0 +1,38 @@ +import React from 'react'; +import { Mail, Phone, MessageSquare } from 'lucide-react'; +import { Breadcrumbs } from '../components/Breadcrumbs'; +import { COMPANY_INFO } from '../data/companyData'; + +export const ContactPage: React.FC = () => { + return ( +
+ +

Contact

+

We reply in 2–4 hours.

+ +
+ {[ + { label: 'Business', email: COMPANY_INFO.email }, + { label: 'Support', email: COMPANY_INFO.supportEmail }, + { label: 'Help', email: COMPANY_INFO.helpEmail }, + ].map((it) => ( + + + + {it.label} + + {it.email} + + ))} + +
+
+ ); +}; diff --git a/src/pages/DocsPage.tsx b/src/pages/DocsPage.tsx new file mode 100644 index 0000000..74ed165 --- /dev/null +++ b/src/pages/DocsPage.tsx @@ -0,0 +1,40 @@ +import React from 'react'; +import { BookOpen, ArrowRight } from 'lucide-react'; +import { Breadcrumbs } from '../components/Breadcrumbs'; + +const DOCS = [ + { title: 'Quickstart', desc: 'Run your first Gothwad app', href: 'https://docs.gothwadtech.com/docs/quickstart' }, + { title: 'Accounts OAuth', desc: 'PKCE flow + user info', href: 'https://docs.gothwadtech.com/docs/oauth' }, + { title: 'Mail setup', desc: 'Deploy inbox on Cloudflare', href: 'https://docs.gothwadtech.com/docs/mail-setup' }, + { title: 'API reference', desc: 'Accounts + Mail REST', href: 'https://docs.gothwadtech.com/docs/api' }, + { title: 'Ecosystem', desc: 'How apps connect', href: 'https://docs.gothwadtech.com/docs/architecture' }, + { title: 'Browser', desc: 'Android TV & mobile', href: 'https://docs.gothwadtech.com/docs/browser' }, +]; + +export const DocsPage: React.FC = () => { + return ( +
+ +

Docs

+

Source-based docs for Gothwad ecosystem.

+ +
+ {DOCS.map((d) => ( + +
+
{d.title}
+
{d.desc}
+
+ +
+ ))} +
+ + +
+ ); +}; diff --git a/src/pages/EcosystemPage.tsx b/src/pages/EcosystemPage.tsx new file mode 100644 index 0000000..21a06e9 --- /dev/null +++ b/src/pages/EcosystemPage.tsx @@ -0,0 +1,136 @@ +import React, { useMemo, useState } from 'react'; +import { ArrowUpRight, Github, Search, ExternalLink, Fingerprint, Mail, HardDrive, Video } from 'lucide-react'; +import { ECOSYSTEM_APPS, CATEGORIES } from '../data/ecosystem'; +import type { CategoryId } from '../data/ecosystem'; +import { Breadcrumbs } from '../components/Breadcrumbs'; +import { COMPANY_INFO } from '../data/companyData'; + +export const EcosystemPage: React.FC<{ onNavigate?: (p: string) => void }> = () => { + const [category, setCategory] = useState('all'); + const [query, setQuery] = useState(''); + + const apps = useMemo(() => { + const q = query.trim().toLowerCase(); + return ECOSYSTEM_APPS.filter((app) => { + const catOk = category === 'all' ? true : app.category === category; + if (!catOk) return false; + if (!q) return true; + return ( + app.name.toLowerCase().includes(q) || + app.tagline.toLowerCase().includes(q) || + app.description.toLowerCase().includes(q) || + app.host.toLowerCase().includes(q) || + (app.githubRepo ?? '').toLowerCase().includes(q) + ); + }); + }, [category, query]); + + return ( +
+ +
+
+ Ecosystem Directory +
+

+ All Gothwad products — direct links +

+

+ Every Gothwad product in one place. Each card shows the live subdomain ({'{host}.gothwadtech.com'}), a short description, GitHub repo and one-click access. Connected apps use your Gothwad Account; standalone apps use “Sign in with Gothwad”. +

+
+ +
+
+ {CATEGORIES.map((c) => ( + + ))} +
+
+ + setQuery(e.target.value)} + placeholder="Search: Mail, Drive, Tube, Browser…" + className="w-full pl-9 pr-3 py-2 rounded-xl bg-white dark:bg-zinc-950 border border-zinc-200 dark:border-zinc-800 text-xs text-zinc-900 dark:text-white placeholder-zinc-400 focus:outline-none focus:border-[#0494f4] focus:ring-2 focus:ring-[#0494f4]/20" + /> +
+
+ +
+ Showing {apps.length} {apps.length === 1 ? 'product' : 'products'} • Core = Gothwad Account connected (cannot be revoked) • Others = “Sign in with Gothwad” (revocable) +
+ +
+ {apps.map((app) => { + const Icon = app.icon; + return ( +
+
+
+ +
+
+ + {app.badge} + + {app.core && Core} +
+
+ +

{app.name}

+
{app.tagline}
+

{app.description}

+ +
+ {app.platforms.map((p) => ( + + {p} + + ))} +
+ +
+ + Open + + {app.githubUrl && ( + + Source + + )} +
+
{app.host}.gothwadtech.com
+
+ ); + })} +
+ + {/* Bottom helper — mirrors docs “leadership themes” but as product CTA */} +
+
+

A connected ecosystem

+

Accounts, Mail, Drive, Meet and Store live alongside standalone products in the same Gothwad Account directory — same as our docs portal.

+
+
+

Web & mobile, side by side

+

From Cloudflare Pages web apps to native Android apps for phones, tablets & Android TVs — one portfolio, many platforms.

+
+
+

Public record of the work

+

Every card links to its GitHub repo and documentation boundary. Read the source, not just the marketing copy.

+
+
+ +
+ Need OAuth integration? Read Sign in with Gothwad (PKCE) • Deploy your own to Cloudflare Pages +
+
+ ); +}; diff --git a/src/pages/HomePage.tsx b/src/pages/HomePage.tsx new file mode 100644 index 0000000..20b1a14 --- /dev/null +++ b/src/pages/HomePage.tsx @@ -0,0 +1,142 @@ +import React, { useState } from 'react'; +import { Search, ArrowUpRight, Grid2X2, Github, BookOpen } from 'lucide-react'; +import { Logo } from '../components/Logo'; +import { ECOSYSTEM_APPS } from '../data/ecosystem'; + +export const HomePage: React.FC<{ onNavigate: (p: string) => void }> = ({ onNavigate }) => { + const [q, setQ] = useState(''); + + const filtered = ECOSYSTEM_APPS.filter((app) => { + if (!q.trim()) return true; + const s = q.toLowerCase(); + return ( + app.name.toLowerCase().includes(s) || + app.tagline.toLowerCase().includes(s) || + app.host.toLowerCase().includes(s) || + app.description.toLowerCase().includes(s) + ); + }); + + return ( +
+ {/* Google-like centered hero */} +
+ {/* Big logo — like Google doodle */} +
+ +

Gothwad Tech — Official Website

+

+ Everything Gothwad, in one place. +

+
+ + {/* Search bar — Google rounded-full */} +
+
+ + setQ(e.target.value)} + placeholder="Search products — try Mail, Drive, Browser..." + className="flex-1 h-full bg-transparent outline-none text-sm text-zinc-900 dark:text-white placeholder:text-zinc-400" + autoFocus + /> + {q && ( + + )} +
+
+ + +
+
+ + {/* Product grid — like Google apps / Chrome shortcuts */} +
+
+ QUICK ACCESS + + +
+ +
+ {filtered.map((app) => { + const Icon = app.icon; + return ( + +
+ +
+ + {app.name} + + + {app.host}.gothwadtech.com + +
+ ); + })} +
+ + {filtered.length === 0 && ( +
+

No products found for “{q}”

+ +
+ )} +
+ + {/* Minimal language + India */} +
+ Offered by Gothwad Tech in: English • हिन्दी +
+
+ + {/* Google-like footer */} +
+
+
India • Jaipur, Rajasthan • Aatmanirbhar Bharat
+
+ + Docs + + + GitHub + + + CEO + + + +
+
+
+
+ ); +}; diff --git a/src/pages/ProductsPage.tsx b/src/pages/ProductsPage.tsx new file mode 100644 index 0000000..ff602b3 --- /dev/null +++ b/src/pages/ProductsPage.tsx @@ -0,0 +1,45 @@ +import React from 'react'; +import { Compass, MessageSquare, Send, ArrowRight, ExternalLink } from 'lucide-react'; +import { Breadcrumbs } from '../components/Breadcrumbs'; + +const PRODUCTS = [ + { id: 'browser', name: 'Gothwad Browser', desc: '11.8 MB • 75% less RAM • TurboShield', icon: Compass, color: 'text-[#0494f4]', href: 'https://browser.gothwadtech.com', play: 'https://play.google.com/store/apps/details?id=com.gothwad.browser' }, + { id: 'grixchat', name: 'GrixChat', desc: '<15ms • 2GB files • HD calling', icon: MessageSquare, color: 'text-emerald-600', href: 'https://grixchat.gothwadtech.com', play: 'https://play.google.com/store/apps/details?id=com.gothwad.grixchat' }, + { id: 'indogram', name: 'Indogram', desc: '200k members • unlimited cloud', icon: Send, color: 'text-sky-600', href: 'https://indogram.gothwadtech.com', play: 'https://play.google.com/store/apps/details?id=com.gothwad.indogram' }, +]; + +export const ProductsPage: React.FC = () => { + return ( +
+ +

Sovereign apps

+

Three flagships — open on any device.

+ +
+ {PRODUCTS.map((p) => { + const Icon = p.icon; + return ( +
+
+ +
+

{p.name}

+

{p.desc}

+ +
+ ); + })} +
+ +
+ Want all products? Try the ecosystem hub. + Ecosystem +
+
+ ); +}; diff --git a/src/pages/SolutionsPage.tsx b/src/pages/SolutionsPage.tsx new file mode 100644 index 0000000..7255c3d --- /dev/null +++ b/src/pages/SolutionsPage.tsx @@ -0,0 +1,44 @@ +import React from 'react'; +import { GraduationCap, Utensils, Store, Building2, ArrowRight } from 'lucide-react'; +import { Breadcrumbs } from '../components/Breadcrumbs'; + +const ITEMS = [ + { icon: GraduationCap, title: 'School ERP', desc: 'Fees, attendance, parent app', price: '₹24,999' }, + { icon: Utensils, title: 'Restaurant POS', desc: 'Ordering + QR + billing', price: '₹19,999' }, + { icon: Store, title: 'Shop billing', desc: 'Barcode + Khata + storefront', price: '₹14,999' }, + { icon: Building2, title: 'Business CRM', desc: 'Leads, invoices, payroll', price: '₹29,999' }, +]; + +export const SolutionsPage: React.FC<{ onNavigate: (p: string) => void }> = ({ onNavigate }) => { + return ( +
+ +

Solutions

+

Simple tools for shops, schools and startups.

+ +
+ {ITEMS.map((it) => { + const Icon = it.icon; + return ( +
+
+ +
+
+
{it.title}
+
{it.desc}
+
+ {it.price} +
+ ); + })} +
+ +
+ +
+
+ ); +}; diff --git a/src/vite-env.d.ts b/src/vite-env.d.ts new file mode 100644 index 0000000..11f02fe --- /dev/null +++ b/src/vite-env.d.ts @@ -0,0 +1 @@ +/// diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..a63109e --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,27 @@ +{ + "compilerOptions": { + "target": "ES2020", + "useDefineForClassFields": true, + "lib": ["ES2020", "DOM", "DOM.Iterable"], + "module": "ESNext", + "skipLibCheck": true, + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "isolatedModules": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "react-jsx", + "strict": true, + "noUnusedLocals": false, + "noUnusedParameters": false, + "noFallthroughCasesInSwitch": true, + "forceConsistentCasingInFileNames": true, + "allowSyntheticDefaultImports": true, + "baseUrl": ".", + "paths": { + "@/*": ["./src/*"] + } + }, + "include": ["src"], + "references": [{ "path": "./tsconfig.node.json" }] +} diff --git a/tsconfig.node.json b/tsconfig.node.json new file mode 100644 index 0000000..482b7fd --- /dev/null +++ b/tsconfig.node.json @@ -0,0 +1,19 @@ +{ + "compilerOptions": { + "composite": true, + "target": "ES2022", + "lib": ["ES2022"], + "module": "ESNext", + "skipLibCheck": true, + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "isolatedModules": true, + "moduleDetection": "force", + "noEmit": false, + "strict": true, + "noUnusedLocals": false, + "noUnusedParameters": false, + "noFallthroughCasesInSwitch": true + }, + "include": ["vite.config.ts"] +} diff --git a/vite.config.ts b/vite.config.ts new file mode 100644 index 0000000..1c5bdca --- /dev/null +++ b/vite.config.ts @@ -0,0 +1,18 @@ +import tailwindcss from '@tailwindcss/vite'; +import react from '@vitejs/plugin-react'; +import path from 'path'; +import { defineConfig } from 'vite'; + +export default defineConfig({ + plugins: [react(), tailwindcss()], + resolve: { + alias: { + '@': path.resolve(__dirname, '.'), + }, + }, + server: { + allowedHosts: true as const, + hmr: process.env.DISABLE_HMR !== 'true', + watch: process.env.DISABLE_HMR === 'true' ? null : {}, + }, +});