modified: astro-site/src/components/mockup/ChatArea.jsx

This commit is contained in:
Anderson 2026-01-19 05:06:41 +00:00 committed by GitHub
parent e6ab906dc0
commit 313b7d2518
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
14 changed files with 608 additions and 269 deletions

50
PROGRESS-README.md Normal file
View 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.*

View file

@ -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",

View file

@ -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",

View file

@ -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">Were 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>
);
}

View 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>
);
}

View file

@ -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);

View file

@ -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 {};

View 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>
);
}

View file

@ -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 (

View file

@ -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";

View 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 />;
}

View file

@ -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>&copy; 2026 AeThex Corporation. All rights reserved.</p>
<div class="footer-legal">
<div class="footer-meta">
<span>&copy; 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;
}
.download h2 {
font-size: 3rem;
font-weight: 700;
margin-bottom: 1rem;
}
.gradient-text {
background: linear-gradient(135deg, #00d9ff 0%, #00ff88 100%);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
}
.download p {
}
.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;
}
.hero-logo {
width: 64px;
height: 64px;
margin-bottom: 1.5rem;
}
.hero-title {
font-size: 2.5rem;
font-weight: 900;
color: #fff;
margin-bottom: 0.5rem;
letter-spacing: 0.04em;
}
.hero-subtitle {
color: #b0c4e0;
font-size: 1.25rem;
color: #b0b0b0;
margin-bottom: 3rem;
}
.download-buttons {
margin-bottom: 2rem;
}
.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;
}
}
.footer-legal {
}
.feature-icon {
font-size: 2.2rem;
margin-bottom: 0.7rem;
display: block;
}
.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;
}
.footer-legal a {
color: #707070;
align-items: center;
justify-content: center;
gap: 0.75rem;
margin-bottom: 0.7rem;
}
.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;
}
.footer-legal a:hover {
color: #00d9ff;
}
font-weight: 500;
transition: color 0.2s;
}
.footer-meta a:hover {
color: #fff;
text-shadow: 0 0 8px #00d9ff99;
}
</style>

View file

@ -0,0 +1 @@

View 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>