modified: astro-site/src/components/mockup/ChatArea.jsx
This commit is contained in:
parent
e6ab906dc0
commit
313b7d2518
14 changed files with 608 additions and 269 deletions
50
PROGRESS-README.md
Normal file
50
PROGRESS-README.md
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
# AeThex Connect – Progress & Next Steps
|
||||
|
||||
## Current Progress
|
||||
|
||||
### 1. UI & Frontend
|
||||
- Modern, branded landing and login pages (Astro + React + Tailwind)
|
||||
- Glassy, Discord-style chat/voice UI with channel, member, and chat areas
|
||||
- Demo login and account linking UI (AeThex + Matrix, now being phased out)
|
||||
- WebRTC integration for voice (UI and hooks scaffolded)
|
||||
|
||||
### 2. Matrix Integration (Deprecated)
|
||||
- MatrixProvider and context for chat/voice (now being removed due to auth/friction)
|
||||
- Demo login attempted with Matrix test accounts (blocked by Matrix.org restrictions)
|
||||
- Error handling and feedback for Matrix login failures
|
||||
|
||||
### 3. Architecture Decisions
|
||||
- Decided to move away from Matrix for chat/auth due to complexity and lack of control
|
||||
- Plan to use AeThex-native authentication and backend for chat/voice
|
||||
- WebRTC will be used for voice, with custom signaling
|
||||
|
||||
## Next Steps
|
||||
|
||||
### 1. Backend
|
||||
- Scaffold a Node.js (or similar) backend for:
|
||||
- AeThex account authentication (JWT/session)
|
||||
- Real-time chat (Socket.io or websockets)
|
||||
- WebRTC signaling for voice
|
||||
- Add basic chat channels, DMs, and presence
|
||||
|
||||
### 2. Frontend
|
||||
- Remove Matrix login and context from UI
|
||||
- Connect chat/voice UI to new backend (Socket.io/websockets for chat, WebRTC for voice)
|
||||
- Use AeThex login for all authentication
|
||||
- Add error handling, loading states, and user feedback
|
||||
|
||||
### 3. Features & Polish
|
||||
- Add moderation tools, premium features, and integrations as needed
|
||||
- Polish UI/UX for onboarding, chat, and voice
|
||||
- Prepare for MVP launch and user testing
|
||||
|
||||
---
|
||||
|
||||
**Summary:**
|
||||
- UI and core experience are in place
|
||||
- Matrix is being replaced with a custom AeThex-native backend
|
||||
- Next: Build backend, connect frontend, and iterate on features
|
||||
|
||||
---
|
||||
|
||||
*This README reflects the current state and roadmap for AeThex Connect as of January 2026.*
|
||||
194
astro-site/package-lock.json
generated
194
astro-site/package-lock.json
generated
|
|
@ -12,6 +12,7 @@
|
|||
"@types/react": "^19.2.8",
|
||||
"@types/react-dom": "^19.2.3",
|
||||
"astro": "^4.0.0",
|
||||
"matrix-js-sdk": "^40.0.0",
|
||||
"mumble-client": "^1.3.0",
|
||||
"react": "^19.2.3",
|
||||
"react-dom": "^19.2.3",
|
||||
|
|
@ -905,6 +906,15 @@
|
|||
"@babel/core": "^7.0.0-0"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/runtime": {
|
||||
"version": "7.28.6",
|
||||
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.28.6.tgz",
|
||||
"integrity": "sha512-05WQkdpL9COIMz4LjTxGpPNCdlpyimKppYNoJ5Di5EUObifl8t4tuLuUBBZEpoLYOmfvIWrsp9fCl0HoPRVTdA==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/template": {
|
||||
"version": "7.27.2",
|
||||
"resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.2.tgz",
|
||||
|
|
@ -1782,6 +1792,15 @@
|
|||
"@jridgewell/sourcemap-codec": "^1.4.14"
|
||||
}
|
||||
},
|
||||
"node_modules/@matrix-org/matrix-sdk-crypto-wasm": {
|
||||
"version": "16.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@matrix-org/matrix-sdk-crypto-wasm/-/matrix-sdk-crypto-wasm-16.0.0.tgz",
|
||||
"integrity": "sha512-c+0eu/ckG+ik62CaOFvHAulJlspw2CBKcLrWbiEQsXv4J3PC4xaaDI5VHFAl7FDU+U9Ww2DDNTieszCh4Lk0/Q==",
|
||||
"license": "Apache-2.0",
|
||||
"engines": {
|
||||
"node": ">= 18"
|
||||
}
|
||||
},
|
||||
"node_modules/@nodelib/fs.scandir": {
|
||||
"version": "2.1.5",
|
||||
"resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
|
||||
|
|
@ -2313,6 +2332,12 @@
|
|||
"integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/events": {
|
||||
"version": "3.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@types/events/-/events-3.0.3.tgz",
|
||||
"integrity": "sha512-trOc4AAUThEz9hapPtSd7wf5tiQKvTtu5b371UxXdTuqzIh0ArcRspRP0i0Viu+LXstIQ1z96t1nsPxT9ol01g==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/hast": {
|
||||
"version": "3.0.4",
|
||||
"resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.4.tgz",
|
||||
|
|
@ -2410,6 +2435,12 @@
|
|||
"node": ">=0.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/another-json": {
|
||||
"version": "0.2.0",
|
||||
"resolved": "https://registry.npmjs.org/another-json/-/another-json-0.2.0.tgz",
|
||||
"integrity": "sha512-/Ndrl68UQLhnCdsAzEXLMFuOR546o2qbYRqCglaNHbjXrwG1ayTcdwr3zkSGOGtGXDyR5X9nCFfnyG2AFJIsqg==",
|
||||
"license": "Apache-2.0"
|
||||
},
|
||||
"node_modules/ansi-align": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.1.tgz",
|
||||
|
|
@ -2716,6 +2747,12 @@
|
|||
"integrity": "sha512-kwDPIFCGx0NZHog36dj+tHiwP4QMzsZ3AgMViUBKI0+V5n4U0ufTCUMhnQ04diaRI8EX/QcPfql7zlhZ7j4zgg==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/base-x": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/base-x/-/base-x-5.0.1.tgz",
|
||||
"integrity": "sha512-M7uio8Zt++eg3jPj+rHMfCC+IuygQHHCOU+IYsVtik6FWjuYpVt/+MRKcgsAMHh8mMFAwnB+Bs+mTrFiXjMzKg==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/base64-js": {
|
||||
"version": "1.5.1",
|
||||
"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
|
||||
|
|
@ -2836,6 +2873,15 @@
|
|||
"node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7"
|
||||
}
|
||||
},
|
||||
"node_modules/bs58": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/bs58/-/bs58-6.0.0.tgz",
|
||||
"integrity": "sha512-PD0wEnEYg6ijszw/u8s+iI3H17cTymlrwkKhDhPZq+Sokl3AU4htyBFTjAeNAlCCmg0f53g6ih3jATyCKftTfw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"base-x": "^5.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/buffer": {
|
||||
"version": "6.0.3",
|
||||
"resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz",
|
||||
|
|
@ -3220,6 +3266,15 @@
|
|||
"integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/content-type": {
|
||||
"version": "1.0.5",
|
||||
"resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz",
|
||||
"integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/convert-source-map": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz",
|
||||
|
|
@ -3520,6 +3575,15 @@
|
|||
"integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/events": {
|
||||
"version": "3.3.0",
|
||||
"resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz",
|
||||
"integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=0.8.x"
|
||||
}
|
||||
},
|
||||
"node_modules/extend": {
|
||||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz",
|
||||
|
|
@ -4177,6 +4241,18 @@
|
|||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/is-network-error": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/is-network-error/-/is-network-error-1.3.0.tgz",
|
||||
"integrity": "sha512-6oIwpsgRfnDiyEDLMay/GqCl3HoAtH5+RUKW29gYkL0QA+ipzpDLA16yQs7/RHCSu+BwgbJaOUqa4A99qNVQVw==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=16"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/is-number": {
|
||||
"version": "7.0.0",
|
||||
"resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
|
||||
|
|
@ -4290,6 +4366,15 @@
|
|||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/jwt-decode": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/jwt-decode/-/jwt-decode-4.0.0.tgz",
|
||||
"integrity": "sha512-+KJGIyHgkGuIq3IEBNftfhW/LfWhXUIY6OmyVWjliu5KH1y0fw7VQ8YndE2O4qZdMSd9SqbnC8GOcZEy0Om7sA==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/kind-of": {
|
||||
"version": "6.0.3",
|
||||
"resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz",
|
||||
|
|
@ -4426,6 +4511,19 @@
|
|||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/loglevel": {
|
||||
"version": "1.9.2",
|
||||
"resolved": "https://registry.npmjs.org/loglevel/-/loglevel-1.9.2.tgz",
|
||||
"integrity": "sha512-HgMmCqIJSAKqo68l0rS2AanEWfkxaZ5wNiEFb5ggm08lDs9Xl2KxBlX3PTcaD2chBM1gXAYf491/M2Rv8Jwayg==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.6.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "tidelift",
|
||||
"url": "https://tidelift.com/funding/github/npm/loglevel"
|
||||
}
|
||||
},
|
||||
"node_modules/long": {
|
||||
"version": "3.2.0",
|
||||
"resolved": "https://registry.npmjs.org/long/-/long-3.2.0.tgz",
|
||||
|
|
@ -4484,6 +4582,47 @@
|
|||
"url": "https://github.com/sponsors/wooorm"
|
||||
}
|
||||
},
|
||||
"node_modules/matrix-events-sdk": {
|
||||
"version": "0.0.1",
|
||||
"resolved": "https://registry.npmjs.org/matrix-events-sdk/-/matrix-events-sdk-0.0.1.tgz",
|
||||
"integrity": "sha512-1QEOsXO+bhyCroIe2/A5OwaxHvBm7EsSQ46DEDn8RBIfQwN5HWBpFvyWWR4QY0KHPPnnJdI99wgRiAl7Ad5qaA==",
|
||||
"license": "Apache-2.0"
|
||||
},
|
||||
"node_modules/matrix-js-sdk": {
|
||||
"version": "40.0.0",
|
||||
"resolved": "https://registry.npmjs.org/matrix-js-sdk/-/matrix-js-sdk-40.0.0.tgz",
|
||||
"integrity": "sha512-KQzMJQ7ZzQlgCIYgUOOVT0+dhlyKZS6bq0Gdf1WCt/tIGc4m56aD2h+EqZKv9aNZ3AtPbPUMDMEpHDva0ggYQg==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.12.5",
|
||||
"@matrix-org/matrix-sdk-crypto-wasm": "^16.0.0",
|
||||
"another-json": "^0.2.0",
|
||||
"bs58": "^6.0.0",
|
||||
"content-type": "^1.0.4",
|
||||
"jwt-decode": "^4.0.0",
|
||||
"loglevel": "^1.9.2",
|
||||
"matrix-events-sdk": "0.0.1",
|
||||
"matrix-widget-api": "^1.14.0",
|
||||
"oidc-client-ts": "^3.0.1",
|
||||
"p-retry": "7",
|
||||
"sdp-transform": "^3.0.0",
|
||||
"unhomoglyph": "^1.0.6",
|
||||
"uuid": "13"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=22.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/matrix-widget-api": {
|
||||
"version": "1.16.0",
|
||||
"resolved": "https://registry.npmjs.org/matrix-widget-api/-/matrix-widget-api-1.16.0.tgz",
|
||||
"integrity": "sha512-OCsCzEN54jWamvWkBa7PqcKdlOhLA+nJbUyqsATHvzb4/NMcjdUZWSDurZxyNE5eYlNwxClA6Hw20mzJEKJbvg==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@types/events": "^3.0.0",
|
||||
"events": "^3.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/mdast-util-definitions": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/mdast-util-definitions/-/mdast-util-definitions-6.0.0.tgz",
|
||||
|
|
@ -5467,6 +5606,18 @@
|
|||
"node": ">= 6"
|
||||
}
|
||||
},
|
||||
"node_modules/oidc-client-ts": {
|
||||
"version": "3.4.1",
|
||||
"resolved": "https://registry.npmjs.org/oidc-client-ts/-/oidc-client-ts-3.4.1.tgz",
|
||||
"integrity": "sha512-jNdst/U28Iasukx/L5MP6b274Vr7ftQs6qAhPBCvz6Wt5rPCA+Q/tUmCzfCHHWweWw5szeMy2Gfrm1rITwUKrw==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"jwt-decode": "^4.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/once": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
|
||||
|
|
@ -5601,6 +5752,21 @@
|
|||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/p-retry": {
|
||||
"version": "7.1.1",
|
||||
"resolved": "https://registry.npmjs.org/p-retry/-/p-retry-7.1.1.tgz",
|
||||
"integrity": "sha512-J5ApzjyRkkf601HpEeykoiCvzHQjWxPAHhyjFcEUP2SWq0+35NKh8TLhpLw+Dkq5TZBFvUM6UigdE9hIVYTl5w==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"is-network-error": "^1.1.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=20"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/p-timeout": {
|
||||
"version": "6.1.4",
|
||||
"resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-6.1.4.tgz",
|
||||
|
|
@ -6467,6 +6633,15 @@
|
|||
"integrity": "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/sdp-transform": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/sdp-transform/-/sdp-transform-3.0.0.tgz",
|
||||
"integrity": "sha512-gfYVRGxjHkGF2NPeUWHw5u6T/KGFtS5/drPms73gaSuMaVHKCY3lpLnGDfswVQO0kddeePoti09AwhYP4zA8dQ==",
|
||||
"license": "MIT",
|
||||
"bin": {
|
||||
"sdp-verify": "checker.js"
|
||||
}
|
||||
},
|
||||
"node_modules/section-matter": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/section-matter/-/section-matter-1.0.0.tgz",
|
||||
|
|
@ -7047,6 +7222,12 @@
|
|||
"integrity": "sha512-R9fBn90VTJrqqLDwyMph+HGne8eqY1iPfYhPzZrvKpIfwkWZbcYlfpsb8B9dTvBfpy1/hqAD7Wi8EKfP9e8zdw==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/unhomoglyph": {
|
||||
"version": "1.0.6",
|
||||
"resolved": "https://registry.npmjs.org/unhomoglyph/-/unhomoglyph-1.0.6.tgz",
|
||||
"integrity": "sha512-7uvcWI3hWshSADBu4JpnyYbTVc7YlhF5GDW/oPD5AxIxl34k4wXR3WDkPnzLxkN32LiTCTKMQLtKVZiwki3zGg==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/unified": {
|
||||
"version": "11.0.5",
|
||||
"resolved": "https://registry.npmjs.org/unified/-/unified-11.0.5.tgz",
|
||||
|
|
@ -7225,6 +7406,19 @@
|
|||
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/uuid": {
|
||||
"version": "13.0.0",
|
||||
"resolved": "https://registry.npmjs.org/uuid/-/uuid-13.0.0.tgz",
|
||||
"integrity": "sha512-XQegIaBTVUjSHliKqcnFqYypAd4S+WCYt5NIeRs6w/UAry7z8Y9j5ZwRRL4kzq9U3sD6v+85er9FvkEaBpji2w==",
|
||||
"funding": [
|
||||
"https://github.com/sponsors/broofa",
|
||||
"https://github.com/sponsors/ctavan"
|
||||
],
|
||||
"license": "MIT",
|
||||
"bin": {
|
||||
"uuid": "dist-node/bin/uuid"
|
||||
}
|
||||
},
|
||||
"node_modules/vfile": {
|
||||
"version": "6.0.3",
|
||||
"resolved": "https://registry.npmjs.org/vfile/-/vfile-6.0.3.tgz",
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
"version": "1.0.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "astro dev",
|
||||
"dev": "astro dev --port 4321",
|
||||
"build": "astro build",
|
||||
"preview": "astro preview"
|
||||
},
|
||||
|
|
@ -12,6 +12,7 @@
|
|||
"@types/react": "^19.2.8",
|
||||
"@types/react-dom": "^19.2.3",
|
||||
"astro": "^4.0.0",
|
||||
"matrix-js-sdk": "^40.0.0",
|
||||
"mumble-client": "^1.3.0",
|
||||
"react": "^19.2.3",
|
||||
"react-dom": "^19.2.3",
|
||||
|
|
|
|||
|
|
@ -1,4 +1,8 @@
|
|||
|
||||
|
||||
import React, { useState } from "react";
|
||||
import { useMatrix } from "../matrix/MatrixProvider.jsx";
|
||||
|
||||
|
||||
/**
|
||||
* UI for linking AeThex and Matrix accounts.
|
||||
|
|
@ -7,6 +11,38 @@ import React, { useState } from "react";
|
|||
* 3. Store mapping in localStorage (or call backend in real app)
|
||||
*/
|
||||
export default function AccountLinker({ onLinked }) {
|
||||
const matrixCtx = useMatrix();
|
||||
if (!matrixCtx) {
|
||||
return (
|
||||
<div className="flex items-center justify-center min-h-screen bg-gradient-to-br from-[#1a1a2e] via-[#23234a] to-[#0f3460]">
|
||||
<div className="relative flex flex-col items-center">
|
||||
<div className="w-16 h-16 mb-6">
|
||||
<svg className="animate-spin-slow" viewBox="0 0 50 50">
|
||||
<circle className="opacity-20" cx="25" cy="25" r="20" stroke="#fff" strokeWidth="5" fill="none" />
|
||||
<circle className="animate-spinner" cx="25" cy="25" r="20" stroke="#ff6bcb" strokeWidth="5" fill="none" strokeDasharray="100" strokeDashoffset="60" />
|
||||
</svg>
|
||||
</div>
|
||||
<div className="toast bg-[#23234a] text-white px-6 py-4 rounded-xl shadow-lg border border-pink-400 animate-fade-in">
|
||||
<span className="font-bold text-pink-400">Hang tight!</span> <br />
|
||||
<span className="text-sm text-blue-200">We’re prepping your login experience…</span>
|
||||
</div>
|
||||
</div>
|
||||
<style>{`
|
||||
.animate-spin-slow { animation: spin 1.8s linear infinite; }
|
||||
@keyframes spin { 100% { transform: rotate(360deg); } }
|
||||
.animate-spinner { animation: dash 1.5s ease-in-out infinite; }
|
||||
@keyframes dash {
|
||||
0% { stroke-dashoffset: 100; }
|
||||
50% { stroke-dashoffset: 20; }
|
||||
100% { stroke-dashoffset: 100; }
|
||||
}
|
||||
.animate-fade-in { animation: fadeIn 0.8s cubic-bezier(.4,0,.2,1) both; }
|
||||
@keyframes fadeIn { from { opacity: 0; transform: translateY(30px); } to { opacity: 1; transform: none; } }
|
||||
`}</style>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
const { login } = matrixCtx;
|
||||
const [aethexUser, setAethexUser] = useState("");
|
||||
const [aethexPass, setAethexPass] = useState("");
|
||||
const [matrixUser, setMatrixUser] = useState("");
|
||||
|
|
@ -38,16 +74,49 @@ export default function AccountLinker({ onLinked }) {
|
|||
}
|
||||
};
|
||||
|
||||
// Demo login handler
|
||||
const handleDemoLogin = async () => {
|
||||
setAethexUser('demo');
|
||||
setAethexPass('demo123');
|
||||
setStep(2);
|
||||
setTimeout(async () => {
|
||||
setMatrixUser('@mrpiglr:matrix.org');
|
||||
setMatrixPass('Max!FTW2023!');
|
||||
setTimeout(async () => {
|
||||
localStorage.setItem("aethex-matrix-link", JSON.stringify({ aethexUser: 'demo', matrixUser: '@mrpiglr:matrix.org' }));
|
||||
setError(null);
|
||||
if (login) {
|
||||
try {
|
||||
await login('@mrpiglr:matrix.org', 'Max!FTW2023!');
|
||||
} catch (e) {
|
||||
setError(e.message || 'Login failed.');
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (onLinked) onLinked({ aethexUser: 'demo', matrixUser: '@mrpiglr:matrix.org', matrixPass: 'Max!FTW2023!' });
|
||||
// window.location.href = '/';
|
||||
}, 500);
|
||||
}, 500);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="account-linker bg-[#181818] p-6 rounded-lg max-w-md mx-auto mt-10 shadow-lg">
|
||||
<h2 className="text-xl font-bold mb-4 text-white">Link AeThex & Matrix Accounts</h2>
|
||||
{error && <div className="mb-2 text-red-400">{error}</div>}
|
||||
<div className="login-bg min-h-screen flex flex-col items-center justify-center" style={{background: "linear-gradient(135deg, #1a1a2e 0%, #16213e 50%, #0f3460 100%)"}}>
|
||||
<div className="account-linker bg-[#181818cc] p-8 rounded-2xl max-w-md w-full mx-auto shadow-2xl border border-[#23234a] flex flex-col items-center animate-fade-in">
|
||||
<img src="/favicon.svg" alt="AeThex Logo" className="w-16 h-16 mb-4 drop-shadow-lg" />
|
||||
<h1 className="text-3xl font-extrabold mb-2 text-white tracking-tight text-center">AeThex Connect</h1>
|
||||
<h2 className="text-lg font-semibold mb-6 text-blue-300 text-center">Sign in to your account</h2>
|
||||
<button onClick={handleDemoLogin} className="mb-4 w-full bg-gradient-to-r from-yellow-400 to-pink-500 text-white rounded-lg py-2 font-bold shadow hover:from-yellow-500 hover:to-pink-600 transition">Demo Login</button>
|
||||
{error && <div className="mb-2 text-red-400 text-center w-full">{error}</div>}
|
||||
{/* Show MatrixProvider error if present */}
|
||||
{matrixCtx && matrixCtx.error && (
|
||||
<div className="mb-2 text-red-400 text-center w-full">Matrix error: {matrixCtx.error}</div>
|
||||
)}
|
||||
{step === 1 && (
|
||||
<form onSubmit={handleAethexLogin} className="flex flex-col gap-3">
|
||||
<form onSubmit={handleAethexLogin} className="flex flex-col gap-4 w-full">
|
||||
<input
|
||||
type="text"
|
||||
placeholder="AeThex Username"
|
||||
className="px-3 py-2 rounded bg-[#222] text-white border border-[#333]"
|
||||
className="px-4 py-3 rounded-lg bg-[#23234a] text-white border border-[#2d2d5a] focus:outline-none focus:ring-2 focus:ring-blue-500 transition"
|
||||
value={aethexUser}
|
||||
onChange={e => setAethexUser(e.target.value)}
|
||||
autoFocus
|
||||
|
|
@ -55,19 +124,19 @@ export default function AccountLinker({ onLinked }) {
|
|||
<input
|
||||
type="password"
|
||||
placeholder="AeThex Password"
|
||||
className="px-3 py-2 rounded bg-[#222] text-white border border-[#333]"
|
||||
className="px-4 py-3 rounded-lg bg-[#23234a] text-white border border-[#2d2d5a] focus:outline-none focus:ring-2 focus:ring-blue-500 transition"
|
||||
value={aethexPass}
|
||||
onChange={e => setAethexPass(e.target.value)}
|
||||
/>
|
||||
<button type="submit" className="bg-blue-600 text-white rounded py-2 font-semibold mt-2">Continue to Matrix</button>
|
||||
<button type="submit" className="bg-gradient-to-r from-blue-600 to-purple-600 text-white rounded-lg py-3 font-bold mt-2 shadow-lg hover:from-blue-700 hover:to-purple-700 transition">Continue to Matrix</button>
|
||||
</form>
|
||||
)}
|
||||
{step === 2 && (
|
||||
<form onSubmit={handleMatrixLogin} className="flex flex-col gap-3">
|
||||
<form onSubmit={handleMatrixLogin} className="flex flex-col gap-4 w-full">
|
||||
<input
|
||||
type="text"
|
||||
placeholder="Matrix Username (@user:matrix.org)"
|
||||
className="px-3 py-2 rounded bg-[#222] text-white border border-[#333]"
|
||||
className="px-4 py-3 rounded-lg bg-[#23234a] text-white border border-[#2d2d5a] focus:outline-none focus:ring-2 focus:ring-green-500 transition"
|
||||
value={matrixUser}
|
||||
onChange={e => setMatrixUser(e.target.value)}
|
||||
autoFocus
|
||||
|
|
@ -75,13 +144,21 @@ export default function AccountLinker({ onLinked }) {
|
|||
<input
|
||||
type="password"
|
||||
placeholder="Matrix Password"
|
||||
className="px-3 py-2 rounded bg-[#222] text-white border border-[#333]"
|
||||
className="px-4 py-3 rounded-lg bg-[#23234a] text-white border border-[#2d2d5a] focus:outline-none focus:ring-2 focus:ring-green-500 transition"
|
||||
value={matrixPass}
|
||||
onChange={e => setMatrixPass(e.target.value)}
|
||||
/>
|
||||
<button type="submit" className="bg-green-600 text-white rounded py-2 font-semibold mt-2">Link Accounts & Login</button>
|
||||
<button type="submit" className="bg-gradient-to-r from-green-500 to-blue-500 text-white rounded-lg py-3 font-bold mt-2 shadow-lg hover:from-green-600 hover:to-blue-600 transition">Link Accounts & Login</button>
|
||||
</form>
|
||||
)}
|
||||
<div className="mt-6 text-center text-gray-400 text-xs w-full">
|
||||
<span>By continuing, you agree to the <a href="/terms" className="underline hover:text-blue-300">Terms of Service</a> and <a href="/privacy" className="underline hover:text-blue-300">Privacy Policy</a>.</span>
|
||||
</div>
|
||||
</div>
|
||||
<style>{`
|
||||
.animate-fade-in { animation: fadeIn 0.8s cubic-bezier(.4,0,.2,1) both; }
|
||||
@keyframes fadeIn { from { opacity: 0; transform: translateY(30px); } to { opacity: 1; transform: none; } }
|
||||
`}</style>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
11
astro-site/src/components/auth/LoginIsland.jsx
Normal file
11
astro-site/src/components/auth/LoginIsland.jsx
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
import React from "react";
|
||||
import { MatrixProvider } from "../matrix/MatrixProvider.jsx";
|
||||
import AccountLinker from "./AccountLinker.jsx";
|
||||
|
||||
export default function LoginIsland() {
|
||||
return (
|
||||
<MatrixProvider>
|
||||
<AccountLinker onLinked={() => {}} />
|
||||
</MatrixProvider>
|
||||
);
|
||||
}
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
import React, { createContext, useContext, useEffect, useState, useCallback } from "react";
|
||||
import sdk from "matrix-js-sdk";
|
||||
import * as sdk from "matrix-js-sdk";
|
||||
|
||||
const MatrixContext = createContext(null);
|
||||
|
||||
|
|
|
|||
|
|
@ -2,12 +2,13 @@ import React, { useEffect } from "react";
|
|||
import Message from "./Message";
|
||||
import MessageInput from "./MessageInput";
|
||||
import { useMatrix } from "../matrix/MatrixProvider.jsx";
|
||||
import DemoLoginButton from "./DemoLoginButton.jsx";
|
||||
|
||||
// Default room to join (replace with your Matrix room ID)
|
||||
const DEFAULT_ROOM_ID = "!foundation:matrix.org";
|
||||
|
||||
export default function ChatArea() {
|
||||
const { messages, joinRoom, currentRoomId, user } = useMatrix();
|
||||
const { messages, joinRoom, currentRoomId, user, login, loading } = useMatrix();
|
||||
|
||||
// Join the default room on login
|
||||
useEffect(() => {
|
||||
|
|
@ -16,6 +17,22 @@ export default function ChatArea() {
|
|||
}
|
||||
}, [user, currentRoomId, joinRoom]);
|
||||
|
||||
// Demo login handler
|
||||
const handleDemoLogin = () => {
|
||||
// Use a public Matrix test account or a known demo account
|
||||
// You can change these credentials as needed
|
||||
login("@mrpiglr:matrix.org", "Max!FTW2023!", "https://matrix.org");
|
||||
};
|
||||
|
||||
if (!user) {
|
||||
return (
|
||||
<div className="chat-area flex flex-col flex-1 bg-[#0a0a0a] items-center justify-center">
|
||||
<DemoLoginButton onDemoLogin={handleDemoLogin} />
|
||||
{loading && <div className="text-gray-400 mt-4">Logging in as demo user...</div>}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="chat-area flex flex-col flex-1 bg-[#0a0a0a]">
|
||||
{/* Chat Header */}
|
||||
|
|
@ -43,9 +60,11 @@ export default function ChatArea() {
|
|||
<MessageInput />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
// Helper to convert Matrix event to Message props
|
||||
function matrixToMessageProps(event) {
|
||||
if (!event) return {};
|
||||
|
|
|
|||
13
astro-site/src/components/mockup/DemoLoginButton.jsx
Normal file
13
astro-site/src/components/mockup/DemoLoginButton.jsx
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
import React from "react";
|
||||
|
||||
export default function DemoLoginButton({ onDemoLogin }) {
|
||||
return (
|
||||
<button
|
||||
className="demo-login-btn px-4 py-2 rounded bg-blue-600 text-white hover:bg-blue-700 transition"
|
||||
onClick={onDemoLogin}
|
||||
style={{ margin: "1rem auto", display: "block" }}
|
||||
>
|
||||
Login as Demo User
|
||||
</button>
|
||||
);
|
||||
}
|
||||
|
|
@ -1,4 +1,9 @@
|
|||
|
||||
import { WebRTCProvider } from "../webrtc/WebRTCProvider.jsx";
|
||||
import ServerList from "./ServerList.jsx";
|
||||
import ChannelSidebar from "./ChannelSidebar.jsx";
|
||||
import ChatArea from "./ChatArea.jsx";
|
||||
import MemberSidebar from "./MemberSidebar.jsx";
|
||||
|
||||
export default function MainLayout() {
|
||||
return (
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
|
||||
import React, { createContext, useContext, useRef, useState, useEffect, useCallback } from "react";
|
||||
import Peer from "simple-peer";
|
||||
import { useMatrix } from "../matrix/MatrixProvider.jsx";
|
||||
|
|
@ -8,11 +9,17 @@ export function useWebRTC() {
|
|||
return useContext(WebRTCContext);
|
||||
}
|
||||
|
||||
export function WebRTCProvider({ children }) {
|
||||
const [peers, setPeers] = useState([]); // [{ peerId, peer, stream }]
|
||||
const [localStream, setLocalStream] = useState(null);
|
||||
const [joined, setJoined] = useState(false);
|
||||
const peersRef = useRef({});
|
||||
const { client, user, currentRoomId } = useMatrix();
|
||||
const matrix = useMatrix();
|
||||
if (!matrix) {
|
||||
// Optionally render a fallback or nothing if Matrix context is not available
|
||||
return null;
|
||||
}
|
||||
const { client, user, currentRoomId } = matrix;
|
||||
const SIGNAL_EVENT = "org.aethex.voice.signal";
|
||||
const VOICE_ROOM = currentRoomId || "!foundation:matrix.org";
|
||||
|
||||
|
|
|
|||
7
astro-site/src/pages/_mockup.jsx
Normal file
7
astro-site/src/pages/_mockup.jsx
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
import React from "react";
|
||||
import MainLayout from "../components/mockup/MainLayout";
|
||||
import "../components/mockup/global.css";
|
||||
|
||||
export default function MockupPage() {
|
||||
return <MainLayout />;
|
||||
}
|
||||
|
|
@ -1,231 +1,176 @@
|
|||
---
|
||||
import Layout from '../layouts/Layout.astro';
|
||||
import MainLayout from '../components/mockup/MainLayout.jsx';
|
||||
import AccountLinker from '../components/auth/AccountLinker.jsx';
|
||||
import { useState } from 'react';
|
||||
import { MatrixProvider } from '../components/matrix/MatrixProvider.jsx';
|
||||
---
|
||||
|
||||
<Layout title="AeThex Connect">
|
||||
<AccountLinker client:load onLinked={({ matrixUser, matrixPass }) => {
|
||||
// Optionally, auto-login to Matrix here
|
||||
// This is a placeholder; actual login logic should be in a React component
|
||||
}} />
|
||||
<MatrixProvider>
|
||||
<MainLayout client:load />
|
||||
</MatrixProvider>
|
||||
</ul>
|
||||
<Layout title="AeThex Connect – Next-Gen Gaming Communication">
|
||||
<section class="landing-hero">
|
||||
<div class="hero-content">
|
||||
<img src="/favicon.svg" alt="AeThex Logo" class="hero-logo" />
|
||||
<h1 class="hero-title">AeThex Connect</h1>
|
||||
<p class="hero-subtitle">Next-generation voice & chat for gamers.<br />Own your identity. Connect everywhere.</p>
|
||||
<a href="/login" class="hero-btn">Get Started</a>
|
||||
</div>
|
||||
<div>
|
||||
<h4>Company</h4>
|
||||
<ul>
|
||||
<li><a href="/about">About</a></li>
|
||||
<li><a href="/blog">Blog</a></li>
|
||||
<li><a href="/careers">Careers</a></li>
|
||||
</ul>
|
||||
</section>
|
||||
<section class="landing-features">
|
||||
<div class="features-row">
|
||||
<div class="feature-card">
|
||||
<span class="feature-icon">🔒</span>
|
||||
<h3>Private & Secure</h3>
|
||||
<p>End-to-end encrypted chat and voice. Your data, your rules.</p>
|
||||
</div>
|
||||
<div>
|
||||
<h4>Support</h4>
|
||||
<ul>
|
||||
<li><a href="/docs">Documentation</a></li>
|
||||
<li><a href="/help">Help Center</a></li>
|
||||
<li><a href="/contact">Contact</a></li>
|
||||
</ul>
|
||||
<div class="feature-card">
|
||||
<span class="feature-icon">🌐</span>
|
||||
<h3>Cross-Platform</h3>
|
||||
<p>Works on web, desktop, and mobile. Seamless everywhere.</p>
|
||||
</div>
|
||||
<div class="feature-card">
|
||||
<span class="feature-icon">🎮</span>
|
||||
<h3>For Gamers</h3>
|
||||
<p>Channels, roles, and integrations built for gaming communities.</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<footer class="landing-footer">
|
||||
<div class="footer-branding">
|
||||
<img src="/favicon.svg" alt="AeThex Logo" class="footer-logo" />
|
||||
<span class="footer-title">AeThex Connect</span>
|
||||
</div>
|
||||
<div class="footer-bottom">
|
||||
<p>© 2026 AeThex Corporation. All rights reserved.</p>
|
||||
<div class="footer-legal">
|
||||
<div class="footer-meta">
|
||||
<span>© 2026 AeThex Corporation</span>
|
||||
<a href="/privacy">Privacy</a>
|
||||
<a href="/terms">Terms</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
</main>
|
||||
</Layout>
|
||||
|
||||
<style>
|
||||
main {
|
||||
background: #000;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.download {
|
||||
padding: 6rem 2rem;
|
||||
.landing-hero {
|
||||
min-height: 70vh;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background: linear-gradient(135deg, #1a1a2e 0%, #16213e 50%, #0f3460 100%);
|
||||
text-align: center;
|
||||
background: linear-gradient(180deg, #000000 0%, #0a0a0f 100%);
|
||||
}
|
||||
|
||||
.download .container {
|
||||
max-width: 1000px;
|
||||
margin: 0 auto;
|
||||
.hero-content {
|
||||
background: rgba(20, 20, 40, 0.85);
|
||||
border-radius: 2rem;
|
||||
padding: 3rem 2rem 2.5rem 2rem;
|
||||
box-shadow: 0 8px 48px 0 #0f3460cc;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.download h2 {
|
||||
font-size: 3rem;
|
||||
font-weight: 700;
|
||||
margin-bottom: 1rem;
|
||||
.hero-logo {
|
||||
width: 64px;
|
||||
height: 64px;
|
||||
margin-bottom: 1.5rem;
|
||||
}
|
||||
|
||||
.gradient-text {
|
||||
background: linear-gradient(135deg, #00d9ff 0%, #00ff88 100%);
|
||||
-webkit-background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
background-clip: text;
|
||||
.hero-title {
|
||||
font-size: 2.5rem;
|
||||
font-weight: 900;
|
||||
color: #fff;
|
||||
margin-bottom: 0.5rem;
|
||||
letter-spacing: 0.04em;
|
||||
}
|
||||
|
||||
.download p {
|
||||
.hero-subtitle {
|
||||
color: #b0c4e0;
|
||||
font-size: 1.25rem;
|
||||
color: #b0b0b0;
|
||||
margin-bottom: 3rem;
|
||||
margin-bottom: 2rem;
|
||||
}
|
||||
|
||||
.download-buttons {
|
||||
.hero-btn {
|
||||
display: inline-block;
|
||||
background: linear-gradient(90deg, #00d9ff 0%, #7f53ff 100%);
|
||||
color: #fff;
|
||||
font-weight: 700;
|
||||
padding: 0.9rem 2.2rem;
|
||||
border-radius: 999px;
|
||||
font-size: 1.1rem;
|
||||
text-decoration: none;
|
||||
box-shadow: 0 2px 16px #00d9ff44;
|
||||
transition: background 0.2s, box-shadow 0.2s;
|
||||
}
|
||||
.hero-btn:hover {
|
||||
background: linear-gradient(90deg, #7f53ff 0%, #00d9ff 100%);
|
||||
box-shadow: 0 4px 32px #7f53ff44;
|
||||
}
|
||||
.landing-features {
|
||||
background: #101024;
|
||||
padding: 3rem 0 2rem 0;
|
||||
}
|
||||
.features-row {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
gap: 1.5rem;
|
||||
gap: 2.5rem;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.download-btn {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 1rem;
|
||||
background: rgba(255, 255, 255, 0.05);
|
||||
border: 1px solid rgba(255, 255, 255, 0.1);
|
||||
padding: 1rem 2rem;
|
||||
border-radius: 12px;
|
||||
text-decoration: none;
|
||||
color: #fff;
|
||||
transition: all 0.2s;
|
||||
}
|
||||
|
||||
.download-btn:hover {
|
||||
background: rgba(255, 255, 255, 0.1);
|
||||
transform: translateY(-2px);
|
||||
}
|
||||
|
||||
.download-btn .icon {
|
||||
font-size: 2.5rem;
|
||||
}
|
||||
|
||||
.download-btn .label {
|
||||
font-size: 0.75rem;
|
||||
color: #b0b0b0;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.download-btn .platform {
|
||||
font-size: 1.125rem;
|
||||
font-weight: 600;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.footer {
|
||||
background: #000;
|
||||
padding: 4rem 2rem 2rem;
|
||||
border-top: 1px solid rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
|
||||
.footer .container {
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.footer-content {
|
||||
display: grid;
|
||||
grid-template-columns: 2fr 3fr;
|
||||
gap: 4rem;
|
||||
margin-bottom: 3rem;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.footer-content {
|
||||
grid-template-columns: 1fr;
|
||||
gap: 2rem;
|
||||
}
|
||||
}
|
||||
|
||||
.footer-brand h3 {
|
||||
font-size: 1.5rem;
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.footer-brand p {
|
||||
color: #b0b0b0;
|
||||
}
|
||||
|
||||
.footer-links {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
gap: 2rem;
|
||||
}
|
||||
|
||||
@media (max-width: 640px) {
|
||||
.footer-links {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
|
||||
.footer-links h4 {
|
||||
font-size: 0.875rem;
|
||||
text-transform: uppercase;
|
||||
color: #707070;
|
||||
margin-bottom: 1rem;
|
||||
font-weight: 600;
|
||||
letter-spacing: 0.5px;
|
||||
}
|
||||
|
||||
.footer-links ul {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.footer-links li {
|
||||
margin-bottom: 0.75rem;
|
||||
}
|
||||
|
||||
.footer-links a {
|
||||
color: #b0b0b0;
|
||||
text-decoration: none;
|
||||
transition: color 0.2s;
|
||||
}
|
||||
|
||||
.footer-links a:hover {
|
||||
color: #00d9ff;
|
||||
}
|
||||
|
||||
.footer-bottom {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding-top: 2rem;
|
||||
border-top: 1px solid rgba(255, 255, 255, 0.05);
|
||||
color: #707070;
|
||||
font-size: 0.875rem;
|
||||
}
|
||||
|
||||
@media (max-width: 640px) {
|
||||
.footer-bottom {
|
||||
flex-direction: column;
|
||||
gap: 1rem;
|
||||
.feature-card {
|
||||
background: rgba(30, 30, 60, 0.95);
|
||||
border-radius: 1.25rem;
|
||||
padding: 2rem 1.5rem;
|
||||
min-width: 220px;
|
||||
max-width: 300px;
|
||||
box-shadow: 0 2px 16px #0f346044;
|
||||
text-align: center;
|
||||
}
|
||||
.feature-icon {
|
||||
font-size: 2.2rem;
|
||||
margin-bottom: 0.7rem;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.footer-legal {
|
||||
.feature-card h3 {
|
||||
color: #7ddaff;
|
||||
font-size: 1.2rem;
|
||||
font-weight: 700;
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
.feature-card p {
|
||||
color: #b0c4e0;
|
||||
font-size: 1rem;
|
||||
}
|
||||
.landing-footer {
|
||||
background: rgba(20, 20, 40, 0.85);
|
||||
border-radius: 1.5rem 1.5rem 0 0;
|
||||
margin: 3rem auto 0 auto;
|
||||
max-width: 480px;
|
||||
padding: 2rem 1.5rem 1.2rem 1.5rem;
|
||||
text-align: center;
|
||||
box-shadow: 0 2px 24px #0f346044;
|
||||
}
|
||||
.footer-branding {
|
||||
display: flex;
|
||||
gap: 2rem;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 0.75rem;
|
||||
margin-bottom: 0.7rem;
|
||||
}
|
||||
|
||||
.footer-legal a {
|
||||
color: #707070;
|
||||
.footer-logo {
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
}
|
||||
.footer-title {
|
||||
color: #fff;
|
||||
font-weight: 800;
|
||||
font-size: 1.1rem;
|
||||
letter-spacing: 0.04em;
|
||||
}
|
||||
.footer-meta {
|
||||
color: #b0c4e0;
|
||||
font-size: 0.95rem;
|
||||
display: flex;
|
||||
gap: 1.5rem;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
.footer-meta a {
|
||||
color: #7ddaff;
|
||||
text-decoration: none;
|
||||
font-weight: 500;
|
||||
transition: color 0.2s;
|
||||
}
|
||||
|
||||
.footer-legal a:hover {
|
||||
color: #00d9ff;
|
||||
.footer-meta a:hover {
|
||||
color: #fff;
|
||||
text-shadow: 0 0 8px #00d9ff99;
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
1
astro-site/src/pages/landing.astro
Normal file
1
astro-site/src/pages/landing.astro
Normal file
|
|
@ -0,0 +1 @@
|
|||
|
||||
9
astro-site/src/pages/login.astro
Normal file
9
astro-site/src/pages/login.astro
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
---
|
||||
import Layout from '../layouts/Layout.astro';
|
||||
import LoginIsland from '../components/auth/LoginIsland.jsx';
|
||||
---
|
||||
|
||||
|
||||
<Layout title="AeThex Connect – Login">
|
||||
<LoginIsland client:load />
|
||||
</Layout>
|
||||
Loading…
Reference in a new issue