feat: Add sleek mobile-first design and Astro landing site

- Update design tokens with dark gaming theme (OLED-friendly)
  - Pure black backgrounds (#000000)
  - Cyan primary (#00d9ff) and neon green accent (#00ff88)
  - Glassmorphism effects and mobile-specific tokens

- Build complete React Native mobile app screens
  - HomeScreen: Chat list with dark cards and status indicators
  - MessagesScreen: Chat view with gradient bubbles and typing indicators
  - FriendsScreen: Friend list with online/offline sections and game presence
  - GamesScreen: GameForge projects with team channels
  - ProfileScreen: User profile with .aethex domain display
  - AppNavigator: Bottom tab navigation with glow effects

- Create Astro marketing landing site
  - Hero section with animated gradients and phone mockup
  - Features showcase (6 cards)
  - Pricing tiers (Free/Premium/Enterprise)
  - Download section for all platforms
  - Fully responsive dark theme

Design inspiration: BitChat, Root, Discord Dark, Telegram
Mobile-first approach with 48px touch targets and safe areas
This commit is contained in:
Anderson 2026-01-12 03:28:16 +00:00 committed by GitHub
parent 5abfbb60f8
commit 651cba733d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
17 changed files with 2762 additions and 68 deletions

67
astro-site/README.md Normal file
View file

@ -0,0 +1,67 @@
# AeThex Connect - Astro Landing Site
Modern, sleek landing page for AeThex Connect built with Astro and Tailwind CSS.
## Quick Start
```bash
# Install dependencies
npm install
# Start development server
npm run dev
# Build for production
npm run build
# Preview production build
npm run preview
```
## Structure
```
astro-site/
├── src/
│ ├── pages/
│ │ └── index.astro # Homepage
│ ├── components/
│ │ ├── Hero.astro # Hero section with phone mockup
│ │ ├── Features.astro # Feature cards
│ │ └── Pricing.astro # Pricing tiers
│ └── layouts/
│ └── Layout.astro # Base layout
├── public/ # Static assets
├── astro.config.mjs
├── tailwind.config.mjs
└── package.json
```
## Features
- ⚡ Lightning-fast static site generation
- 🎨 Sleek dark gaming theme
- 📱 Mobile-first responsive design
- ✨ Animated gradients and smooth transitions
- 🎯 SEO optimized
- 🚀 Ready to deploy (Vercel, Netlify, Cloudflare Pages)
## Deploy
### Vercel
```bash
npm i -g vercel
vercel
```
### Netlify
```bash
npm i -g netlify-cli
netlify deploy
```
### Cloudflare Pages
Connect your GitHub repo to Cloudflare Pages dashboard.
Build command: `npm run build`
Output directory: `dist`

View file

@ -0,0 +1,7 @@
import { defineConfig } from 'astro/config';
import tailwind from '@astrojs/tailwind';
export default defineConfig({
integrations: [tailwind()],
site: 'https://aethex-connect.com',
});

17
astro-site/package.json Normal file
View file

@ -0,0 +1,17 @@
{
"name": "aethex-connect-site",
"version": "1.0.0",
"private": true,
"scripts": {
"dev": "astro dev",
"build": "astro build",
"preview": "astro preview"
},
"dependencies": {
"astro": "^4.0.0"
},
"devDependencies": {
"@astrojs/tailwind": "^5.0.0",
"tailwindcss": "^3.4.0"
}
}

View file

@ -0,0 +1,136 @@
---
// Features showcase
const features = [
{
icon: '🔐',
title: 'Own Your Identity',
description: 'Your .aethex domain is an NFT. It\'s yours forever. No company can take it away.',
},
{
icon: '💬',
title: 'Cross-Game Chat',
description: 'Voice and text that follows you across every game. Start in Valorant, join in Fortnite.',
},
{
icon: '🎮',
title: 'GameForge Integration',
description: 'Building a game? Auto-created team channels with role-based access for your dev team.',
},
{
icon: '📞',
title: 'Crystal Clear Calls',
description: 'Low-latency voice optimized for competitive gaming. HD video with screen sharing.',
},
{
icon: '👥',
title: 'Persistent Friends',
description: 'See which games your friends are playing. Join their lobbies with one click.',
},
{
icon: '💎',
title: 'Premium Tiers',
description: 'Free tier to get started. Premium for serious gamers. Enterprise for game studios.',
},
];
---
<section id="features" class="features">
<div class="container">
<div class="section-header">
<h2>Built for <span class="gradient-text">Gamers</span></h2>
<p>Everything you need to stay connected with your squad across all games.</p>
</div>
<div class="features-grid">
{features.map(feature => (
<div class="feature-card">
<div class="feature-icon">{feature.icon}</div>
<h3>{feature.title}</h3>
<p>{feature.description}</p>
</div>
))}
</div>
</div>
</section>
<style>
.features {
padding: 6rem 2rem;
background: #0a0a0f;
}
.container {
max-width: 1200px;
margin: 0 auto;
}
.section-header {
text-align: center;
margin-bottom: 4rem;
}
.section-header 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;
}
.section-header p {
font-size: 1.25rem;
color: #b0b0b0;
}
.features-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
gap: 2rem;
}
.feature-card {
background: rgba(255, 255, 255, 0.03);
border: 1px solid rgba(0, 217, 255, 0.1);
border-radius: 16px;
padding: 2rem;
transition: all 0.3s;
}
.feature-card:hover {
transform: translateY(-4px);
background: rgba(255, 255, 255, 0.05);
border-color: rgba(0, 217, 255, 0.3);
box-shadow: 0 8px 24px rgba(0, 217, 255, 0.2);
}
.feature-icon {
font-size: 3rem;
margin-bottom: 1rem;
}
.feature-card h3 {
font-size: 1.5rem;
font-weight: 600;
margin-bottom: 0.75rem;
color: #fff;
}
.feature-card p {
color: #b0b0b0;
line-height: 1.6;
}
@media (max-width: 768px) {
.section-header h2 {
font-size: 2rem;
}
.features-grid {
grid-template-columns: 1fr;
}
}
</style>

View file

@ -0,0 +1,250 @@
---
// Hero component with animated gradient
---
<section class="hero">
<div class="container">
<div class="hero-content">
<h1 class="hero-title">
Chat Across <span class="gradient-text">All Games</span>
</h1>
<p class="hero-subtitle">
Your gaming identity and friends follow you everywhere.
Own your <span class="highlight">.aethex</span> domain, connect with your squad across every game.
</p>
<div class="cta-buttons">
<a href="#download" class="btn-primary">
📱 Download App
</a>
<a href="#features" class="btn-secondary">
Learn More →
</a>
</div>
<p class="hero-caption">
Available on iOS, Android, Windows, macOS & Linux
</p>
</div>
<div class="hero-visual">
<div class="phone-mockup">
<div class="phone-screen">
<div class="chat-preview">
<div class="chat-item">
<span class="avatar">🎮</span>
<div>
<div class="chat-name">Squad Goals</div>
<div class="chat-msg">Let's run Valorant</div>
</div>
<span class="chat-badge">3</span>
</div>
<div class="chat-item">
<span class="avatar">👤</span>
<div>
<div class="chat-name">john.aethex</div>
<div class="chat-msg">yo wanna play?</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</section>
<style>
.hero {
min-height: 100vh;
display: flex;
align-items: center;
background: linear-gradient(180deg, #000000 0%, #0a0a0f 100%);
position: relative;
overflow: hidden;
}
.hero::before {
content: '';
position: absolute;
top: -50%;
left: -50%;
width: 200%;
height: 200%;
background: radial-gradient(circle, rgba(0,217,255,0.1) 0%, transparent 70%);
animation: pulse 8s ease-in-out infinite;
}
@keyframes pulse {
0%, 100% { transform: scale(1); opacity: 0.5; }
50% { transform: scale(1.1); opacity: 0.3; }
}
.container {
max-width: 1200px;
margin: 0 auto;
padding: 2rem;
display: grid;
grid-template-columns: 1fr 1fr;
gap: 4rem;
align-items: center;
position: relative;
z-index: 1;
}
@media (max-width: 768px) {
.container {
grid-template-columns: 1fr;
gap: 2rem;
}
}
.hero-content {
max-width: 600px;
}
.hero-title {
font-size: 3.5rem;
font-weight: 700;
line-height: 1.1;
margin-bottom: 1.5rem;
}
@media (max-width: 768px) {
.hero-title {
font-size: 2.5rem;
}
}
.gradient-text {
background: linear-gradient(135deg, #00d9ff 0%, #00ff88 100%);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
}
.hero-subtitle {
font-size: 1.25rem;
color: #b0b0b0;
line-height: 1.6;
margin-bottom: 2rem;
}
.highlight {
color: #00d9ff;
font-weight: 600;
}
.cta-buttons {
display: flex;
gap: 1rem;
margin-bottom: 1rem;
flex-wrap: wrap;
}
.btn-primary, .btn-secondary {
padding: 1rem 2rem;
border-radius: 12px;
font-size: 1.125rem;
font-weight: 600;
text-decoration: none;
transition: all 0.2s;
display: inline-block;
}
.btn-primary {
background: linear-gradient(135deg, #00d9ff 0%, #00b8d9 100%);
color: #000;
box-shadow: 0 8px 24px rgba(0,217,255,0.3);
}
.btn-primary:hover {
transform: translateY(-2px);
box-shadow: 0 12px 32px rgba(0,217,255,0.4);
}
.btn-secondary {
background: rgba(255,255,255,0.05);
color: #fff;
border: 1px solid rgba(255,255,255,0.1);
}
.btn-secondary:hover {
background: rgba(255,255,255,0.1);
}
.hero-caption {
font-size: 0.875rem;
color: #707070;
}
.hero-visual {
display: flex;
justify-content: center;
align-items: center;
}
.phone-mockup {
width: 300px;
height: 600px;
background: linear-gradient(135deg, #1a1a1a 0%, #0f0f0f 100%);
border-radius: 40px;
padding: 12px;
box-shadow: 0 20px 60px rgba(0,0,0,0.8);
border: 1px solid rgba(255,255,255,0.1);
}
.phone-screen {
width: 100%;
height: 100%;
background: #000;
border-radius: 32px;
overflow: hidden;
padding: 1.5rem 1rem;
}
.chat-preview {
display: flex;
flex-direction: column;
gap: 1rem;
}
.chat-item {
display: flex;
align-items: center;
gap: 0.75rem;
background: rgba(255,255,255,0.05);
padding: 1rem;
border-radius: 12px;
border: 1px solid rgba(255,255,255,0.05);
}
.avatar {
font-size: 2rem;
}
.chat-name {
font-size: 0.9rem;
font-weight: 600;
color: #fff;
}
.chat-msg {
font-size: 0.8rem;
color: #b0b0b0;
}
.chat-badge {
margin-left: auto;
background: #00d9ff;
color: #000;
padding: 0.25rem 0.5rem;
border-radius: 999px;
font-size: 0.75rem;
font-weight: 700;
}
@media (max-width: 768px) {
.phone-mockup {
width: 250px;
height: 500px;
}
}
</style>

View file

@ -0,0 +1,225 @@
---
// Pricing section
const tiers = [
{
name: 'Free',
price: '$0',
period: 'forever',
features: [
'5 friends maximum',
'Basic text messaging',
'Subdomain identity',
'100 MB storage',
'Community support',
],
cta: 'Get Started',
highlight: false,
},
{
name: 'Premium',
price: '$100',
period: 'per year',
features: [
'Blockchain .aethex domain (NFT)',
'Unlimited friends',
'HD voice & video (1080p)',
'10 GB storage',
'Priority support',
'Custom profile branding',
],
cta: 'Go Premium',
highlight: true,
},
{
name: 'Enterprise',
price: 'Custom',
period: 'contact us',
features: [
'Everything in Premium',
'White-label platform',
'Custom domain',
'Unlimited storage',
'99.9% SLA guarantee',
'Dedicated account manager',
],
cta: 'Contact Sales',
highlight: false,
},
];
---
<section id="pricing" class="pricing">
<div class="container">
<div class="section-header">
<h2>Choose Your <span class="gradient-text">Tier</span></h2>
<p>Start free, upgrade when you're ready.</p>
</div>
<div class="pricing-grid">
{tiers.map(tier => (
<div class:list={['pricing-card', { highlight: tier.highlight }]}>
{tier.highlight && <div class="popular-badge">Most Popular</div>}
<div class="tier-name">{tier.name}</div>
<div class="tier-price">
{tier.price}
<span class="tier-period">/{tier.period}</span>
</div>
<ul class="tier-features">
{tier.features.map(feature => (
<li>✓ {feature}</li>
))}
</ul>
<a href="#download" class:list={['tier-cta', { primary: tier.highlight }]}>
{tier.cta}
</a>
</div>
))}
</div>
</div>
</section>
<style>
.pricing {
padding: 6rem 2rem;
background: linear-gradient(180deg, #0a0a0f 0%, #000000 100%);
}
.container {
max-width: 1200px;
margin: 0 auto;
}
.section-header {
text-align: center;
margin-bottom: 4rem;
}
.section-header h2 {
font-size: 3rem;
font-weight: 700;
margin-bottom: 1rem;
}
.gradient-text {
background: linear-gradient(135deg, #00d9ff 0%, #a855f7 100%);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
}
.section-header p {
font-size: 1.25rem;
color: #b0b0b0;
}
.pricing-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
gap: 2rem;
max-width: 1000px;
margin: 0 auto;
}
.pricing-card {
background: rgba(255, 255, 255, 0.03);
border: 1px solid rgba(255, 255, 255, 0.1);
border-radius: 16px;
padding: 2rem;
position: relative;
transition: all 0.3s;
}
.pricing-card.highlight {
border-color: #00d9ff;
background: rgba(0, 217, 255, 0.05);
transform: scale(1.05);
}
.pricing-card:hover {
transform: translateY(-8px) scale(1.02);
}
.pricing-card.highlight:hover {
transform: translateY(-8px) scale(1.07);
}
.popular-badge {
position: absolute;
top: -12px;
left: 50%;
transform: translateX(-50%);
background: linear-gradient(135deg, #00d9ff 0%, #00b8d9 100%);
color: #000;
padding: 0.5rem 1rem;
border-radius: 999px;
font-size: 0.75rem;
font-weight: 700;
text-transform: uppercase;
}
.tier-name {
font-size: 1.5rem;
font-weight: 700;
margin-bottom: 1rem;
}
.tier-price {
font-size: 3rem;
font-weight: 700;
margin-bottom: 2rem;
color: #00d9ff;
}
.tier-period {
font-size: 1rem;
color: #707070;
}
.tier-features {
list-style: none;
padding: 0;
margin-bottom: 2rem;
}
.tier-features li {
padding: 0.5rem 0;
color: #b0b0b0;
}
.tier-cta {
display: block;
width: 100%;
padding: 1rem;
border-radius: 8px;
text-align: center;
text-decoration: none;
font-weight: 600;
transition: all 0.2s;
background: rgba(255, 255, 255, 0.05);
color: #fff;
border: 1px solid rgba(255, 255, 255, 0.1);
}
.tier-cta:hover {
background: rgba(255, 255, 255, 0.1);
}
.tier-cta.primary {
background: linear-gradient(135deg, #00d9ff 0%, #00b8d9 100%);
color: #000;
border: none;
}
.tier-cta.primary:hover {
box-shadow: 0 8px 24px rgba(0, 217, 255, 0.4);
}
@media (max-width: 768px) {
.section-header h2 {
font-size: 2rem;
}
.pricing-card.highlight {
transform: scale(1);
}
}
</style>

View file

@ -0,0 +1,35 @@
---
const { title = 'AeThex Connect - Gaming Communication Platform' } = Astro.props;
---
<!DOCTYPE html>
<html lang="en" class="dark">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>{title}</title>
<meta name="description" content="Next-generation communication platform for gamers. Own your identity with blockchain domains, connect across all games." />
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
</head>
<body class="bg-dark-bg text-white antialiased">
<slot />
</body>
</html>
<style is:global>
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
html {
scroll-behavior: smooth;
}
</style>

View file

@ -0,0 +1,275 @@
---
import Layout from '../layouts/Layout.astro';
import Hero from '../components/Hero.astro';
import Features from '../components/Features.astro';
import Pricing from '../components/Pricing.astro';
---
<Layout title="AeThex Connect - Gaming Communication Platform">
<main>
<Hero />
<Features />
<Pricing />
<!-- Download Section -->
<section id="download" class="download">
<div class="container">
<h2>Download <span class="gradient-text">AeThex Connect</span></h2>
<p>Available on all platforms</p>
<div class="download-buttons">
<a href="#" class="download-btn">
<span class="icon">🍎</span>
<div>
<div class="label">Download on the</div>
<div class="platform">App Store</div>
</div>
</a>
<a href="#" class="download-btn">
<span class="icon">🤖</span>
<div>
<div class="label">Get it on</div>
<div class="platform">Google Play</div>
</div>
</a>
<a href="#" class="download-btn">
<span class="icon">💻</span>
<div>
<div class="label">Desktop for</div>
<div class="platform">Windows/Mac/Linux</div>
</div>
</a>
</div>
</div>
</section>
<!-- Footer -->
<footer class="footer">
<div class="container">
<div class="footer-content">
<div class="footer-brand">
<h3>AeThex Connect</h3>
<p>Next-generation communication for gamers</p>
</div>
<div class="footer-links">
<div>
<h4>Product</h4>
<ul>
<li><a href="#features">Features</a></li>
<li><a href="#pricing">Pricing</a></li>
<li><a href="#download">Download</a></li>
</ul>
</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>
</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>
</div>
</div>
<div class="footer-bottom">
<p>&copy; 2026 AeThex Corporation. All rights reserved.</p>
<div class="footer-legal">
<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;
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 {
font-size: 1.25rem;
color: #b0b0b0;
margin-bottom: 3rem;
}
.download-buttons {
display: flex;
justify-content: center;
gap: 1.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;
text-align: center;
}
}
.footer-legal {
display: flex;
gap: 2rem;
}
.footer-legal a {
color: #707070;
text-decoration: none;
}
.footer-legal a:hover {
color: #00d9ff;
}
</style>

View file

@ -0,0 +1,22 @@
/** @type {import('tailwindcss').Config} */
export default {
content: ['./src/**/*.{astro,html,js,jsx,md,mdx,svelte,ts,tsx,vue}'],
theme: {
extend: {
colors: {
primary: '#00d9ff',
accent: '#00ff88',
secondary: '#a855f7',
dark: {
bg: '#000000',
card: '#0f0f0f',
elevated: '#1a1a1a',
},
},
fontFamily: {
sans: ['-apple-system', 'BlinkMacSystemFont', 'Segoe UI', 'Roboto', 'sans-serif'],
},
},
},
plugins: [],
};

View file

@ -0,0 +1,120 @@
/**
* App Navigator
* Bottom tab navigation with sleek design
*/
import React from 'react';
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
import { NavigationContainer } from '@react-navigation/native';
import { StyleSheet, View, Text } from 'react-native';
import { theme } from '../theme';
// Screens
import HomeScreen from '../screens/HomeScreen';
import MessagesScreen from '../screens/MessagesScreen';
import GamesScreen from '../screens/GamesScreen';
import FriendsScreen from '../screens/FriendsScreen';
import ProfileScreen from '../screens/ProfileScreen';
const Tab = createBottomTabNavigator();
const TabIcon = ({ focused, emoji }: { focused: boolean; emoji: string }) => (
<View style={[styles.tabIcon, focused && styles.tabIconActive]}>
<Text style={styles.tabEmoji}>{emoji}</Text>
</View>
);
export default function AppNavigator() {
return (
<NavigationContainer
theme={{
dark: true,
colors: {
primary: theme.colors.primary,
background: theme.colors.background,
card: theme.colors.background,
text: theme.colors.text,
border: theme.colors.gray800,
notification: theme.colors.primary,
},
}}
>
<Tab.Navigator
screenOptions={{
headerShown: false,
tabBarStyle: styles.tabBar,
tabBarActiveTintColor: theme.colors.primary,
tabBarInactiveTintColor: theme.colors.gray600,
tabBarLabelStyle: styles.tabLabel,
}}
>
<Tab.Screen
name="Home"
component={HomeScreen}
options={{
tabBarIcon: ({ focused }) => <TabIcon focused={focused} emoji="🏠" />,
}}
/>
<Tab.Screen
name="Messages"
component={MessagesScreen}
options={{
tabBarIcon: ({ focused }) => <TabIcon focused={focused} emoji="💬" />,
tabBarBadge: 3, // Unread count
}}
/>
<Tab.Screen
name="Games"
component={GamesScreen}
options={{
tabBarIcon: ({ focused }) => <TabIcon focused={focused} emoji="🎮" />,
}}
/>
<Tab.Screen
name="Friends"
component={FriendsScreen}
options={{
tabBarIcon: ({ focused }) => <TabIcon focused={focused} emoji="👥" />,
}}
/>
<Tab.Screen
name="Profile"
component={ProfileScreen}
options={{
tabBarIcon: ({ focused }) => <TabIcon focused={focused} emoji="👤" />,
}}
/>
</Tab.Navigator>
</NavigationContainer>
);
}
const styles = StyleSheet.create({
tabBar: {
backgroundColor: theme.colors.background,
borderTopWidth: 1,
borderTopColor: theme.colors.gray900,
height: theme.layout.tabBarHeight,
paddingBottom: 8,
paddingTop: 8,
},
tabLabel: {
fontSize: theme.typography.fontSize.xs,
fontWeight: theme.typography.fontWeight.medium,
},
tabIcon: {
width: 40,
height: 40,
borderRadius: theme.borderRadius.md,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: 'transparent',
},
tabIconActive: {
backgroundColor: theme.colors.backgroundTertiary,
...theme.shadows.glow,
},
tabEmoji: {
fontSize: 24,
},
});

View file

@ -0,0 +1,222 @@
/**
* Friends Screen
* Cross-game friends list with status
*/
import React, { useState } from 'react';
import {
View,
Text,
StyleSheet,
FlatList,
TouchableOpacity,
SafeAreaView,
SectionList,
} from 'react-native';
import { theme } from '../theme';
interface Friend {
id: string;
username: string;
status: 'online' | 'offline' | 'idle' | 'dnd';
game?: string;
avatar: string;
}
export default function FriendsScreen({ navigation }: any) {
const [friends] = useState<Friend[]>([
{ id: '1', username: 'john.aethex', status: 'online', game: 'Valorant', avatar: 'J' },
{ id: '2', username: 'sarah.aethex', status: 'online', game: 'Fortnite', avatar: 'S' },
{ id: '3', username: 'mike.aethex', status: 'idle', avatar: 'M' },
{ id: '4', username: 'alex.aethex', status: 'offline', avatar: 'A' },
]);
const onlineFriends = friends.filter(f => f.status === 'online');
const offlineFriends = friends.filter(f => f.status !== 'online');
const sections = [
{ title: `ONLINE (${onlineFriends.length})`, data: onlineFriends },
{ title: `OFFLINE (${offlineFriends.length})`, data: offlineFriends },
];
const getStatusColor = (status: Friend['status']) => {
switch (status) {
case 'online': return theme.colors.online;
case 'idle': return theme.colors.idle;
case 'dnd': return theme.colors.dnd;
default: return theme.colors.offline;
}
};
const renderFriend = ({ item }: { item: Friend }) => (
<TouchableOpacity style={styles.friendCard} activeOpacity={0.7}>
<View style={styles.avatarContainer}>
<View style={styles.avatar}>
<Text style={styles.avatarText}>{item.avatar}</Text>
</View>
<View style={[styles.statusDot, { backgroundColor: getStatusColor(item.status) }]} />
</View>
<View style={styles.friendInfo}>
<Text style={styles.username}>{item.username}</Text>
{item.game && (
<View style={styles.gameRow}>
<Text style={styles.gameIcon}>🎮</Text>
<Text style={styles.gameText}>Playing {item.game}</Text>
</View>
)}
{!item.game && item.status === 'offline' && (
<Text style={styles.lastSeen}>Last seen 2h ago</Text>
)}
</View>
<View style={styles.actions}>
<TouchableOpacity style={styles.actionButton}>
<Text style={styles.actionIcon}>💬</Text>
</TouchableOpacity>
{item.status === 'online' && (
<TouchableOpacity style={styles.actionButton}>
<Text style={styles.actionIcon}>📞</Text>
</TouchableOpacity>
)}
</View>
</TouchableOpacity>
);
return (
<SafeAreaView style={styles.container}>
<View style={styles.header}>
<Text style={styles.headerTitle}>Friends</Text>
<TouchableOpacity style={styles.addButton}>
<Text style={styles.addIcon}></Text>
</TouchableOpacity>
</View>
<SectionList
sections={sections}
renderItem={renderFriend}
renderSectionHeader={({ section }) => (
<View style={styles.sectionHeader}>
<Text style={styles.sectionTitle}>{section.title}</Text>
</View>
)}
keyExtractor={(item) => item.id}
contentContainerStyle={styles.listContent}
stickySectionHeadersEnabled={false}
/>
</SafeAreaView>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: theme.colors.background,
},
header: {
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'space-between',
paddingHorizontal: theme.spacing.md,
paddingVertical: theme.spacing.md,
},
headerTitle: {
fontSize: theme.typography.fontSize.xxl,
fontWeight: theme.typography.fontWeight.bold,
color: theme.colors.text,
},
addButton: {
width: theme.layout.touchTarget,
height: theme.layout.touchTarget,
justifyContent: 'center',
alignItems: 'center',
},
addIcon: {
fontSize: 24,
},
listContent: {
paddingHorizontal: theme.spacing.md,
},
sectionHeader: {
paddingVertical: theme.spacing.md,
},
sectionTitle: {
fontSize: theme.typography.fontSize.sm,
fontWeight: theme.typography.fontWeight.semibold,
color: theme.colors.textTertiary,
letterSpacing: 0.5,
},
friendCard: {
flexDirection: 'row',
alignItems: 'center',
backgroundColor: theme.colors.card,
borderRadius: theme.borderRadius.lg,
padding: theme.spacing.md,
marginBottom: theme.spacing.md,
borderWidth: 1,
borderColor: 'rgba(255, 255, 255, 0.05)',
},
avatarContainer: {
position: 'relative',
marginRight: theme.spacing.md,
},
avatar: {
width: 48,
height: 48,
borderRadius: theme.borderRadius.full,
backgroundColor: theme.colors.primary,
justifyContent: 'center',
alignItems: 'center',
},
avatarText: {
fontSize: 20,
fontWeight: theme.typography.fontWeight.bold,
color: '#000',
},
statusDot: {
position: 'absolute',
bottom: 0,
right: 0,
width: 14,
height: 14,
borderRadius: 7,
borderWidth: 2,
borderColor: theme.colors.card,
},
friendInfo: {
flex: 1,
},
username: {
fontSize: theme.typography.fontSize.base,
fontWeight: theme.typography.fontWeight.semibold,
color: theme.colors.text,
marginBottom: 4,
},
gameRow: {
flexDirection: 'row',
alignItems: 'center',
},
gameIcon: {
fontSize: 14,
marginRight: 4,
},
gameText: {
fontSize: theme.typography.fontSize.sm,
color: theme.colors.textSecondary,
},
lastSeen: {
fontSize: theme.typography.fontSize.sm,
color: theme.colors.textTertiary,
},
actions: {
flexDirection: 'row',
},
actionButton: {
width: 40,
height: 40,
justifyContent: 'center',
alignItems: 'center',
marginLeft: theme.spacing.sm,
},
actionIcon: {
fontSize: 20,
},
});

View file

@ -0,0 +1,221 @@
/**
* Games Screen (GameForge)
* Game development projects and team channels
*/
import React, { useState } from 'react';
import {
View,
Text,
StyleSheet,
ScrollView,
TouchableOpacity,
SafeAreaView,
} from 'react-native';
import { theme } from '../theme';
export default function GamesScreen() {
return (
<SafeAreaView style={styles.container}>
<View style={styles.header}>
<Text style={styles.headerTitle}>GameForge Projects</Text>
<TouchableOpacity style={styles.addButton}>
<Text style={styles.addIcon}></Text>
</TouchableOpacity>
</View>
<ScrollView contentContainerStyle={styles.content}>
{/* Project Card */}
<View style={styles.projectCard}>
<View style={styles.projectHeader}>
<Text style={styles.projectIcon}>🎮</Text>
<View style={styles.projectInfo}>
<Text style={styles.projectName}>Project Phoenix</Text>
<Text style={styles.projectMeta}>5 members 3 online</Text>
</View>
</View>
<View style={styles.channels}>
{['#general', '#dev', '#art', '#test'].map(channel => (
<TouchableOpacity key={channel} style={styles.channelButton}>
<Text style={styles.channelText}>{channel}</Text>
</TouchableOpacity>
))}
</View>
<View style={styles.notification}>
<Text style={styles.notificationDot}>🔴</Text>
<Text style={styles.notificationText}>Build failed 2m ago</Text>
</View>
</View>
{/* Another Project */}
<View style={styles.projectCard}>
<View style={styles.projectHeader}>
<Text style={styles.projectIcon}>🎮</Text>
<View style={styles.projectInfo}>
<Text style={styles.projectName}>Indie Shooter</Text>
<Text style={styles.projectMeta}>2 members 1 online</Text>
</View>
</View>
<View style={styles.channels}>
{['#general', '#dev'].map(channel => (
<TouchableOpacity key={channel} style={styles.channelButton}>
<Text style={styles.channelText}>{channel}</Text>
</TouchableOpacity>
))}
</View>
</View>
{/* Team Status */}
<View style={styles.section}>
<Text style={styles.sectionTitle}>TEAM STATUS</Text>
<View style={styles.teamList}>
{[
{ name: 'sarah.aethex', role: 'Developer', online: true },
{ name: 'mike.aethex', role: 'Artist', online: true },
{ name: 'alex.aethex', role: 'Designer', online: false },
].map(member => (
<View key={member.name} style={styles.teamMember}>
<View style={[styles.memberDot, { backgroundColor: member.online ? theme.colors.online : theme.colors.offline }]} />
<Text style={styles.memberName}>{member.name}</Text>
<Text style={styles.memberRole}>({member.role})</Text>
</View>
))}
</View>
</View>
</ScrollView>
</SafeAreaView>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: theme.colors.background,
},
header: {
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'space-between',
paddingHorizontal: theme.spacing.md,
paddingVertical: theme.spacing.md,
},
headerTitle: {
fontSize: theme.typography.fontSize.xxl,
fontWeight: theme.typography.fontWeight.bold,
color: theme.colors.text,
},
addButton: {
width: theme.layout.touchTarget,
height: theme.layout.touchTarget,
justifyContent: 'center',
alignItems: 'center',
},
addIcon: {
fontSize: 24,
},
content: {
padding: theme.spacing.md,
},
projectCard: {
backgroundColor: theme.colors.card,
borderRadius: theme.borderRadius.lg,
padding: theme.spacing.lg,
marginBottom: theme.spacing.md,
borderWidth: 1,
borderColor: 'rgba(255, 255, 255, 0.05)',
},
projectHeader: {
flexDirection: 'row',
alignItems: 'center',
marginBottom: theme.spacing.md,
},
projectIcon: {
fontSize: 32,
marginRight: theme.spacing.md,
},
projectInfo: {
flex: 1,
},
projectName: {
fontSize: theme.typography.fontSize.lg,
fontWeight: theme.typography.fontWeight.semibold,
color: theme.colors.text,
marginBottom: 4,
},
projectMeta: {
fontSize: theme.typography.fontSize.sm,
color: theme.colors.textSecondary,
},
channels: {
flexDirection: 'row',
flexWrap: 'wrap',
marginBottom: theme.spacing.md,
},
channelButton: {
backgroundColor: theme.colors.backgroundSecondary,
paddingHorizontal: theme.spacing.md,
paddingVertical: theme.spacing.sm,
borderRadius: theme.borderRadius.base,
marginRight: theme.spacing.sm,
marginBottom: theme.spacing.sm,
},
channelText: {
fontSize: theme.typography.fontSize.sm,
color: theme.colors.textSecondary,
},
notification: {
flexDirection: 'row',
alignItems: 'center',
backgroundColor: 'rgba(239, 68, 68, 0.1)',
padding: theme.spacing.sm,
borderRadius: theme.borderRadius.base,
},
notificationDot: {
fontSize: 12,
marginRight: theme.spacing.sm,
},
notificationText: {
fontSize: theme.typography.fontSize.sm,
color: theme.colors.error,
},
section: {
marginTop: theme.spacing.lg,
},
sectionTitle: {
fontSize: theme.typography.fontSize.sm,
fontWeight: theme.typography.fontWeight.semibold,
color: theme.colors.textTertiary,
marginBottom: theme.spacing.md,
letterSpacing: 0.5,
},
teamList: {
backgroundColor: theme.colors.card,
borderRadius: theme.borderRadius.lg,
padding: theme.spacing.md,
borderWidth: 1,
borderColor: 'rgba(255, 255, 255, 0.05)',
},
teamMember: {
flexDirection: 'row',
alignItems: 'center',
paddingVertical: theme.spacing.sm,
},
memberDot: {
width: 8,
height: 8,
borderRadius: 4,
marginRight: theme.spacing.sm,
},
memberName: {
fontSize: theme.typography.fontSize.base,
color: theme.colors.text,
marginRight: theme.spacing.sm,
},
memberRole: {
fontSize: theme.typography.fontSize.sm,
color: theme.colors.textSecondary,
},
});

View file

@ -0,0 +1,267 @@
/**
* Home Screen (Chat List)
* Main conversation list with sleek dark design
*/
import React, { useState, useEffect } from 'react';
import {
View,
Text,
StyleSheet,
FlatList,
TouchableOpacity,
TextInput,
SafeAreaView,
StatusBar,
} from 'react-native';
import { theme } from '../theme';
interface Conversation {
id: string;
name: string;
lastMessage: string;
timestamp: string;
unread: number;
isOnline: boolean;
isGroup: boolean;
avatar: string;
}
export default function HomeScreen({ navigation }: any) {
const [conversations, setConversations] = useState<Conversation[]>([
{
id: '1',
name: 'john.aethex',
lastMessage: 'yo wanna play valorant',
timestamp: '2:30 PM',
unread: 0,
isOnline: true,
isGroup: false,
avatar: '👤',
},
{
id: '2',
name: 'Squad Goals',
lastMessage: "Sarah: let's go",
timestamp: '1:15 PM',
unread: 3,
isOnline: true,
isGroup: true,
avatar: '🎮',
},
{
id: '3',
name: 'mike.aethex',
lastMessage: 'gg bro',
timestamp: 'Yesterday',
unread: 0,
isOnline: false,
isGroup: false,
avatar: '👤',
},
{
id: '4',
name: 'Project Phoenix',
lastMessage: 'Dev team meeting 3pm',
timestamp: 'Yesterday',
unread: 0,
isOnline: true,
isGroup: true,
avatar: '🎮',
},
]);
const renderConversation = ({ item }: { item: Conversation }) => (
<TouchableOpacity
style={styles.conversationCard}
onPress={() => navigation.navigate('Chat', { conversation: item })}
activeOpacity={0.7}
>
<View style={styles.conversationContent}>
{/* Avatar with status */}
<View style={styles.avatarContainer}>
<View style={styles.avatar}>
<Text style={styles.avatarEmoji}>{item.avatar}</Text>
</View>
{item.isOnline && <View style={styles.statusDot} />}
</View>
{/* Message preview */}
<View style={styles.messagePreview}>
<View style={styles.headerRow}>
<Text style={styles.conversationName} numberOfLines={1}>
{item.name}
</Text>
<Text style={styles.timestamp}>{item.timestamp}</Text>
</View>
<View style={styles.lastMessageRow}>
<Text style={styles.lastMessage} numberOfLines={1}>
{item.lastMessage}
</Text>
{item.unread > 0 && (
<View style={styles.unreadBadge}>
<Text style={styles.unreadText}>{item.unread}</Text>
</View>
)}
</View>
</View>
</View>
</TouchableOpacity>
);
return (
<SafeAreaView style={styles.container}>
<StatusBar barStyle="light-content" backgroundColor={theme.colors.background} />
{/* Header */}
<View style={styles.header}>
<TouchableOpacity style={styles.menuButton}>
<Text style={styles.menuIcon}></Text>
</TouchableOpacity>
<Text style={styles.headerTitle}>AeThex Connect</Text>
<TouchableOpacity style={styles.searchButton}>
<Text style={styles.searchIcon}>🔍</Text>
</TouchableOpacity>
</View>
{/* Conversation List */}
<FlatList
data={conversations}
renderItem={renderConversation}
keyExtractor={(item) => item.id}
contentContainerStyle={styles.listContent}
showsVerticalScrollIndicator={false}
/>
</SafeAreaView>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: theme.colors.background,
},
header: {
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'space-between',
paddingHorizontal: theme.spacing.md,
paddingVertical: theme.spacing.md,
backgroundColor: theme.colors.background,
},
headerTitle: {
fontSize: theme.typography.fontSize.xl,
fontWeight: theme.typography.fontWeight.semibold,
color: theme.colors.text,
flex: 1,
marginLeft: theme.spacing.md,
},
menuButton: {
width: theme.layout.touchTarget,
height: theme.layout.touchTarget,
justifyContent: 'center',
alignItems: 'center',
},
menuIcon: {
fontSize: 24,
color: theme.colors.text,
},
searchButton: {
width: theme.layout.touchTarget,
height: theme.layout.touchTarget,
justifyContent: 'center',
alignItems: 'center',
},
searchIcon: {
fontSize: 20,
},
listContent: {
paddingHorizontal: theme.spacing.md,
paddingBottom: theme.spacing.xl,
},
conversationCard: {
backgroundColor: theme.colors.card,
borderRadius: theme.borderRadius.lg,
marginBottom: theme.spacing.md,
padding: theme.spacing.md,
borderWidth: 1,
borderColor: 'rgba(255, 255, 255, 0.05)',
},
conversationContent: {
flexDirection: 'row',
alignItems: 'center',
},
avatarContainer: {
position: 'relative',
marginRight: theme.spacing.md,
},
avatar: {
width: 56,
height: 56,
borderRadius: theme.borderRadius.full,
backgroundColor: theme.colors.backgroundSecondary,
justifyContent: 'center',
alignItems: 'center',
borderWidth: 2,
borderColor: theme.colors.gray800,
},
avatarEmoji: {
fontSize: 28,
},
statusDot: {
position: 'absolute',
bottom: 2,
right: 2,
width: 14,
height: 14,
borderRadius: 7,
backgroundColor: theme.colors.online,
borderWidth: 2,
borderColor: theme.colors.card,
},
messagePreview: {
flex: 1,
},
headerRow: {
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'center',
marginBottom: 4,
},
conversationName: {
fontSize: theme.typography.fontSize.base,
fontWeight: theme.typography.fontWeight.semibold,
color: theme.colors.text,
flex: 1,
},
timestamp: {
fontSize: theme.typography.fontSize.xs,
color: theme.colors.textTertiary,
marginLeft: theme.spacing.sm,
},
lastMessageRow: {
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'space-between',
},
lastMessage: {
fontSize: theme.typography.fontSize.sm,
color: theme.colors.textSecondary,
flex: 1,
},
unreadBadge: {
backgroundColor: theme.colors.primary,
borderRadius: theme.borderRadius.full,
paddingHorizontal: 8,
paddingVertical: 2,
marginLeft: theme.spacing.sm,
minWidth: 24,
alignItems: 'center',
...theme.shadows.glow,
},
unreadText: {
fontSize: theme.typography.fontSize.xs,
fontWeight: theme.typography.fontWeight.bold,
color: '#000',
},
});

View file

@ -0,0 +1,347 @@
/**
* Messages Screen (Chat View)
* Individual chat conversation with message bubbles
*/
import React, { useState } from 'react';
import {
View,
Text,
StyleSheet,
FlatList,
TextInput,
TouchableOpacity,
SafeAreaView,
KeyboardAvoidingView,
Platform,
} from 'react-native';
import { theme } from '../theme';
interface Message {
id: string;
text: string;
timestamp: string;
isOwn: boolean;
status?: 'sent' | 'delivered' | 'read';
}
export default function MessagesScreen({ route, navigation }: any) {
const { conversation } = route?.params || { conversation: { name: 'john.aethex' } };
const [messages, setMessages] = useState<Message[]>([
{
id: '1',
text: "hey what's up? 🎮",
timestamp: '2:28 PM',
isOwn: true,
status: 'read',
},
{
id: '2',
text: 'yo wanna run some valorant?',
timestamp: '2:30 PM',
isOwn: false,
},
{
id: '3',
text: 'bet, im in 🔥',
timestamp: '2:31 PM',
isOwn: true,
status: 'delivered',
},
]);
const [inputText, setInputText] = useState('');
const [isTyping] = useState(true);
const renderMessage = ({ item }: { item: Message }) => (
<View style={[styles.messageContainer, item.isOwn && styles.messageContainerOwn]}>
<View style={[styles.messageBubble, item.isOwn && styles.messageBubbleOwn]}>
<Text style={[styles.messageText, item.isOwn && styles.messageTextOwn]}>
{item.text}
</Text>
</View>
<View style={[styles.messageFooter, item.isOwn && styles.messageFooterOwn]}>
<Text style={styles.messageTimestamp}>{item.timestamp}</Text>
{item.isOwn && (
<Text style={styles.messageStatus}>
{item.status === 'read' && '✓✓'}
{item.status === 'delivered' && '✓'}
{item.status === 'sent' && '•'}
</Text>
)}
</View>
</View>
);
const handleSend = () => {
if (inputText.trim()) {
const newMessage: Message = {
id: Date.now().toString(),
text: inputText.trim(),
timestamp: new Date().toLocaleTimeString('en-US', { hour: 'numeric', minute: '2-digit' }),
isOwn: true,
status: 'sent',
};
setMessages([...messages, newMessage]);
setInputText('');
}
};
return (
<SafeAreaView style={styles.container}>
<KeyboardAvoidingView
behavior={Platform.OS === 'ios' ? 'padding' : 'height'}
style={styles.keyboardView}
keyboardVerticalOffset={0}
>
{/* Header */}
<View style={styles.header}>
<TouchableOpacity onPress={() => navigation.goBack()} style={styles.backButton}>
<Text style={styles.backIcon}></Text>
</TouchableOpacity>
<View style={styles.headerInfo}>
<Text style={styles.headerTitle}>{conversation.name}</Text>
<View style={styles.statusRow}>
<View style={styles.onlineDot} />
<Text style={styles.statusText}>Online Playing Valorant</Text>
</View>
</View>
<TouchableOpacity style={styles.iconButton}>
<Text style={styles.callIcon}>📞</Text>
</TouchableOpacity>
<TouchableOpacity style={styles.iconButton}>
<Text style={styles.videoIcon}>📹</Text>
</TouchableOpacity>
</View>
{/* Messages List */}
<FlatList
data={messages}
renderItem={renderMessage}
keyExtractor={(item) => item.id}
contentContainerStyle={styles.messagesList}
showsVerticalScrollIndicator={false}
inverted={false}
/>
{/* Typing Indicator */}
{isTyping && (
<View style={styles.typingContainer}>
<Text style={styles.typingText}>{conversation.name} is typing...</Text>
<View style={styles.typingDots}>
<View style={[styles.dot, styles.dot1]} />
<View style={[styles.dot, styles.dot2]} />
<View style={[styles.dot, styles.dot3]} />
</View>
</View>
)}
{/* Input Bar */}
<View style={styles.inputContainer}>
<TouchableOpacity style={styles.attachButton}>
<Text style={styles.attachIcon}>+</Text>
</TouchableOpacity>
<TextInput
style={styles.input}
placeholder="Message..."
placeholderTextColor={theme.colors.textMuted}
value={inputText}
onChangeText={setInputText}
multiline
maxLength={2000}
/>
<TouchableOpacity style={styles.sendButton} onPress={handleSend}>
<Text style={styles.sendIcon}>🎤</Text>
</TouchableOpacity>
</View>
</KeyboardAvoidingView>
</SafeAreaView>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: theme.colors.background,
},
keyboardView: {
flex: 1,
},
header: {
flexDirection: 'row',
alignItems: 'center',
paddingHorizontal: theme.spacing.md,
paddingVertical: theme.spacing.sm,
backgroundColor: theme.colors.backgroundSecondary,
borderBottomWidth: 1,
borderBottomColor: theme.colors.gray900,
},
backButton: {
width: 40,
height: 40,
justifyContent: 'center',
alignItems: 'center',
marginRight: theme.spacing.sm,
},
backIcon: {
fontSize: 24,
color: theme.colors.primary,
},
headerInfo: {
flex: 1,
},
headerTitle: {
fontSize: theme.typography.fontSize.base,
fontWeight: theme.typography.fontWeight.semibold,
color: theme.colors.text,
},
statusRow: {
flexDirection: 'row',
alignItems: 'center',
marginTop: 2,
},
onlineDot: {
width: 8,
height: 8,
borderRadius: 4,
backgroundColor: theme.colors.online,
marginRight: 6,
},
statusText: {
fontSize: theme.typography.fontSize.xs,
color: theme.colors.textSecondary,
},
iconButton: {
width: 40,
height: 40,
justifyContent: 'center',
alignItems: 'center',
marginLeft: theme.spacing.sm,
},
callIcon: {
fontSize: 20,
},
videoIcon: {
fontSize: 20,
},
messagesList: {
paddingHorizontal: theme.spacing.md,
paddingVertical: theme.spacing.lg,
},
messageContainer: {
marginBottom: theme.spacing.md,
alignItems: 'flex-start',
maxWidth: '80%',
},
messageContainerOwn: {
alignSelf: 'flex-end',
alignItems: 'flex-end',
},
messageBubble: {
backgroundColor: theme.colors.card,
borderRadius: theme.borderRadius.xl,
padding: theme.spacing.md,
borderWidth: 1,
borderColor: 'rgba(255, 255, 255, 0.05)',
},
messageBubbleOwn: {
backgroundColor: 'transparent',
borderWidth: 0,
backgroundImage: `linear-gradient(135deg, ${theme.colors.primary}, ${theme.colors.secondary})`,
},
messageText: {
fontSize: theme.typography.fontSize.base,
color: theme.colors.text,
lineHeight: 22,
},
messageTextOwn: {
color: '#ffffff',
},
messageFooter: {
flexDirection: 'row',
alignItems: 'center',
marginTop: 4,
paddingHorizontal: theme.spacing.sm,
},
messageFooterOwn: {
flexDirection: 'row-reverse',
},
messageTimestamp: {
fontSize: theme.typography.fontSize.xs,
color: theme.colors.textTertiary,
},
messageStatus: {
fontSize: theme.typography.fontSize.xs,
color: theme.colors.primary,
marginLeft: 4,
},
typingContainer: {
flexDirection: 'row',
alignItems: 'center',
paddingHorizontal: theme.spacing.lg,
paddingVertical: theme.spacing.sm,
},
typingText: {
fontSize: theme.typography.fontSize.sm,
color: theme.colors.textSecondary,
marginRight: theme.spacing.sm,
},
typingDots: {
flexDirection: 'row',
},
dot: {
width: 6,
height: 6,
borderRadius: 3,
backgroundColor: theme.colors.textSecondary,
marginHorizontal: 2,
},
dot1: {},
dot2: {},
dot3: {},
inputContainer: {
flexDirection: 'row',
alignItems: 'center',
paddingHorizontal: theme.spacing.md,
paddingVertical: theme.spacing.md,
backgroundColor: theme.colors.backgroundSecondary,
borderTopWidth: 1,
borderTopColor: theme.colors.gray900,
},
attachButton: {
width: 40,
height: 40,
borderRadius: theme.borderRadius.full,
backgroundColor: theme.colors.card,
justifyContent: 'center',
alignItems: 'center',
marginRight: theme.spacing.sm,
},
attachIcon: {
fontSize: 24,
color: theme.colors.primary,
},
input: {
flex: 1,
backgroundColor: theme.colors.card,
borderRadius: theme.borderRadius.lg,
paddingHorizontal: theme.spacing.md,
paddingVertical: theme.spacing.sm,
fontSize: theme.typography.fontSize.base,
color: theme.colors.text,
maxHeight: 100,
},
sendButton: {
width: 40,
height: 40,
borderRadius: theme.borderRadius.full,
backgroundColor: theme.colors.card,
justifyContent: 'center',
alignItems: 'center',
marginLeft: theme.spacing.sm,
},
sendIcon: {
fontSize: 20,
},
});

View file

@ -0,0 +1,226 @@
/**
* Profile Screen
* User profile with .aethex domain and settings
*/
import React from 'react';
import {
View,
Text,
StyleSheet,
ScrollView,
TouchableOpacity,
SafeAreaView,
} from 'react-native';
import { theme } from '../theme';
export default function ProfileScreen() {
return (
<SafeAreaView style={styles.container}>
<View style={styles.header}>
<Text style={styles.headerTitle}>Settings</Text>
</View>
<ScrollView contentContainerStyle={styles.content}>
{/* Profile Section */}
<View style={styles.profileSection}>
<View style={styles.avatarLarge}>
<Text style={styles.avatarText}>A</Text>
</View>
<Text style={styles.username}>alice.aethex </Text>
<Text style={styles.membershipBadge}>Premium Member</Text>
</View>
{/* Domain Card */}
<View style={styles.domainCard}>
<Text style={styles.domainIcon}>🌐</Text>
<View style={styles.domainInfo}>
<Text style={styles.domainName}>alice.aethex</Text>
<Text style={styles.domainDetail}>NFT Token: 0x742f...</Text>
<Text style={styles.domainDetail}>Owned since: Jan 2026</Text>
</View>
<TouchableOpacity style={styles.domainButton}>
<Text style={styles.domainButtonText}>View on Polygon </Text>
</TouchableOpacity>
</View>
{/* Settings Sections */}
<View style={styles.section}>
<Text style={styles.sectionTitle}>ACCOUNT</Text>
<TouchableOpacity style={styles.settingItem}>
<Text style={styles.settingIcon}></Text>
<Text style={styles.settingLabel}>Premium</Text>
<Text style={styles.settingArrow}></Text>
</TouchableOpacity>
<TouchableOpacity style={styles.settingItem}>
<Text style={styles.settingIcon}>🔔</Text>
<Text style={styles.settingLabel}>Notifications</Text>
<Text style={styles.settingArrow}></Text>
</TouchableOpacity>
<TouchableOpacity style={styles.settingItem}>
<Text style={styles.settingIcon}>🔒</Text>
<Text style={styles.settingLabel}>Privacy</Text>
<Text style={styles.settingArrow}></Text>
</TouchableOpacity>
<TouchableOpacity style={styles.settingItem}>
<Text style={styles.settingIcon}>🎮</Text>
<Text style={styles.settingLabel}>Connected Games</Text>
<Text style={styles.settingArrow}></Text>
</TouchableOpacity>
</View>
{/* About Section */}
<View style={styles.section}>
<Text style={styles.sectionTitle}>ABOUT</Text>
<TouchableOpacity style={styles.settingItem}>
<Text style={styles.settingIcon}></Text>
<Text style={styles.settingLabel}>Help & Support</Text>
<Text style={styles.settingArrow}></Text>
</TouchableOpacity>
<TouchableOpacity style={styles.settingItem}>
<Text style={styles.settingIcon}>📄</Text>
<Text style={styles.settingLabel}>Terms & Privacy</Text>
<Text style={styles.settingArrow}></Text>
</TouchableOpacity>
</View>
{/* Version */}
<Text style={styles.version}>Version 1.0.0</Text>
</ScrollView>
</SafeAreaView>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: theme.colors.background,
},
header: {
flexDirection: 'row',
alignItems: 'center',
paddingHorizontal: theme.spacing.md,
paddingVertical: theme.spacing.md,
},
headerTitle: {
fontSize: theme.typography.fontSize.xxl,
fontWeight: theme.typography.fontWeight.bold,
color: theme.colors.text,
},
content: {
padding: theme.spacing.md,
},
profileSection: {
alignItems: 'center',
paddingVertical: theme.spacing.xl,
},
avatarLarge: {
width: 100,
height: 100,
borderRadius: 50,
backgroundColor: theme.colors.primary,
justifyContent: 'center',
alignItems: 'center',
marginBottom: theme.spacing.md,
...theme.shadows.glow,
},
avatarText: {
fontSize: 48,
fontWeight: theme.typography.fontWeight.bold,
color: '#000',
},
username: {
fontSize: theme.typography.fontSize.xxl,
fontWeight: theme.typography.fontWeight.bold,
color: theme.colors.text,
marginBottom: 4,
},
membershipBadge: {
fontSize: theme.typography.fontSize.sm,
color: theme.colors.secondary,
},
domainCard: {
backgroundColor: theme.colors.card,
borderRadius: theme.borderRadius.lg,
padding: theme.spacing.lg,
marginBottom: theme.spacing.xl,
borderWidth: 1,
borderColor: theme.colors.primary + '30',
},
domainIcon: {
fontSize: 32,
marginBottom: theme.spacing.md,
},
domainInfo: {
marginBottom: theme.spacing.md,
},
domainName: {
fontSize: theme.typography.fontSize.lg,
fontWeight: theme.typography.fontWeight.semibold,
color: theme.colors.text,
marginBottom: theme.spacing.sm,
},
domainDetail: {
fontSize: theme.typography.fontSize.sm,
color: theme.colors.textSecondary,
marginBottom: 4,
},
domainButton: {
backgroundColor: theme.colors.backgroundSecondary,
padding: theme.spacing.md,
borderRadius: theme.borderRadius.base,
alignItems: 'center',
},
domainButtonText: {
fontSize: theme.typography.fontSize.sm,
color: theme.colors.primary,
fontWeight: theme.typography.fontWeight.medium,
},
section: {
marginBottom: theme.spacing.xl,
},
sectionTitle: {
fontSize: theme.typography.fontSize.sm,
fontWeight: theme.typography.fontWeight.semibold,
color: theme.colors.textTertiary,
marginBottom: theme.spacing.md,
letterSpacing: 0.5,
},
settingItem: {
flexDirection: 'row',
alignItems: 'center',
backgroundColor: theme.colors.card,
padding: theme.spacing.lg,
borderRadius: theme.borderRadius.lg,
marginBottom: theme.spacing.sm,
borderWidth: 1,
borderColor: 'rgba(255, 255, 255, 0.05)',
},
settingIcon: {
fontSize: 20,
marginRight: theme.spacing.md,
width: 24,
},
settingLabel: {
flex: 1,
fontSize: theme.typography.fontSize.base,
color: theme.colors.text,
},
settingArrow: {
fontSize: 20,
color: theme.colors.textTertiary,
},
version: {
textAlign: 'center',
fontSize: theme.typography.fontSize.sm,
color: theme.colors.textMuted,
marginTop: theme.spacing.xl,
marginBottom: theme.spacing.xxl,
},
});

View file

@ -0,0 +1,150 @@
/**
* Mobile Theme
* Imports design tokens and adapts for React Native
*/
// Import design tokens from UI package
import { colors, spacing, typography, borderRadius, shadows } from '@aethex/ui';
export const theme = {
colors: {
// Background
background: colors.background.primary,
backgroundSecondary: colors.background.secondary,
backgroundTertiary: colors.background.tertiary,
// Card
card: colors.background.tertiary,
cardElevated: colors.background.elevated,
// Text
text: colors.text.primary,
textSecondary: colors.text.secondary,
textTertiary: colors.text.tertiary,
textMuted: colors.text.muted,
// Brand
primary: colors.primary[500],
primaryLight: colors.primary[400],
primaryDark: colors.primary[600],
accent: colors.accent[500],
accentLight: colors.accent[400],
accentDark: colors.accent[600],
secondary: colors.secondary[500],
// Semantic
success: colors.success,
warning: colors.warning,
error: colors.error,
info: colors.info,
// Status
online: colors.status.online,
idle: colors.status.idle,
dnd: colors.status.dnd,
offline: colors.status.offline,
// Effects
glass: colors.effects.glass,
glassBorder: colors.effects.glassBorder,
overlay: colors.effects.overlay,
// Gray scale
gray50: colors.gray[50],
gray100: colors.gray[100],
gray200: colors.gray[200],
gray300: colors.gray[300],
gray400: colors.gray[400],
gray500: colors.gray[500],
gray600: colors.gray[600],
gray700: colors.gray[700],
gray800: colors.gray[800],
gray900: colors.gray[900],
gray950: colors.gray[950],
},
spacing: {
xs: 4,
sm: 8,
md: 16,
lg: 24,
xl: 32,
xxl: 48,
xxxl: 64,
},
typography: {
fontFamily: typography.fontFamily.sans,
fontSize: {
xs: 12,
sm: 14,
base: 16,
lg: 18,
xl: 20,
xxl: 24,
xxxl: 28,
huge: 32,
},
fontWeight: {
light: '300' as const,
normal: '400' as const,
medium: '500' as const,
semibold: '600' as const,
bold: '700' as const,
},
},
borderRadius: {
sm: 6,
base: 8,
md: 12,
lg: 16,
xl: 18,
xxl: 24,
full: 9999,
},
shadows: {
sm: {
shadowColor: '#000',
shadowOffset: { width: 0, height: 1 },
shadowOpacity: 0.3,
shadowRadius: 2,
elevation: 2,
},
md: {
shadowColor: '#000',
shadowOffset: { width: 0, height: 4 },
shadowOpacity: 0.4,
shadowRadius: 8,
elevation: 4,
},
lg: {
shadowColor: '#000',
shadowOffset: { width: 0, height: 8 },
shadowOpacity: 0.5,
shadowRadius: 16,
elevation: 8,
},
glow: {
shadowColor: colors.primary[500],
shadowOffset: { width: 0, height: 0 },
shadowOpacity: 0.4,
shadowRadius: 20,
elevation: 10,
},
},
layout: {
headerHeight: 56,
tabBarHeight: 56,
touchTarget: 48,
messageBubbleMaxWidth: '80%',
},
};
export type Theme = typeof theme;

View file

@ -1,71 +1,109 @@
/**
* Design System Tokens
* Shared design tokens across all platforms
*
* SLEEK DARK GAMING THEME
* Inspired by: BitChat, Root, Discord Dark, Telegram
*/
export const colors = {
// Brand colors
// Brand colors (Cyan primary - modern gaming)
primary: {
50: '#ecfeff',
100: '#cffafe',
200: '#a5f3fc',
300: '#67e8f9',
400: '#22d3ee',
500: '#00d9ff', // Primary cyan
600: '#00b8d9',
700: '#0097b3',
800: '#007a8f',
900: '#006073',
},
// Accent colors (Neon green gaming)
accent: {
50: '#f0fdf4',
100: '#dcfce7',
200: '#bbf7d0',
300: '#86efac',
400: '#4ade80',
500: '#00ff88', // Neon green
600: '#00e070',
700: '#00c05d',
800: '#009f4a',
900: '#00803b',
},
// Secondary accent (Purple for premium)
secondary: {
50: '#faf5ff',
100: '#f3e8ff',
200: '#e9d5ff',
300: '#d8b4fe',
400: '#c084fc',
500: '#a855f7',
500: '#a855f7', // Premium purple
600: '#9333ea',
700: '#7e22ce',
800: '#6b21a8',
900: '#581c87',
},
// Accent colors
accent: {
50: '#fdf4ff',
100: '#fae8ff',
200: '#f5d0fe',
300: '#f0abfc',
400: '#e879f9',
500: '#d946ef',
600: '#c026d3',
700: '#a21caf',
800: '#86198f',
900: '#701a75',
},
// Neutral colors (dark theme)
// Neutral colors (OLED-friendly blacks)
gray: {
50: '#fafafa',
100: '#f4f4f5',
200: '#e4e4e7',
300: '#d4d4d8',
400: '#a1a1aa',
500: '#71717a',
600: '#52525b',
700: '#3f3f46',
800: '#27272a',
900: '#18181b',
950: '#09090b',
100: '#f5f5f5',
200: '#e5e5e5',
300: '#d4d4d4',
400: '#a3a3a3',
500: '#737373',
600: '#525252',
700: '#404040',
800: '#262626',
900: '#171717',
950: '#0a0a0a', // Pure black for OLED
},
// Semantic colors
success: '#22c55e',
warning: '#f59e0b',
error: '#ef4444',
info: '#3b82f6',
success: '#10b981', // Green
warning: '#f59e0b', // Orange
error: '#ef4444', // Red
info: '#00d9ff', // Cyan (matches primary)
// Background
// Background (OLED-optimized)
background: {
primary: '#0a0a0f',
secondary: '#18181b',
tertiary: '#27272a',
primary: '#000000', // Pure black for OLED battery saving
secondary: '#0f0f0f', // Slightly elevated
tertiary: '#1a1a1a', // Cards
elevated: '#262626', // Modals/overlays
},
// Text
// Text (High contrast for readability)
text: {
primary: '#e4e4e7',
secondary: '#a1a1aa',
tertiary: '#71717a',
muted: '#52525b',
primary: '#ffffff', // White
secondary: '#b0b0b0', // Light gray
tertiary: '#707070', // Medium gray
muted: '#505050', // Dark gray
disabled: '#3a3a3a', // Very dark gray
},
// Special effects
effects: {
glass: 'rgba(20, 20, 20, 0.7)', // Glassmorphism background
glassBorder: 'rgba(255, 255, 255, 0.1)', // Glass border
glow: 'rgba(0, 217, 255, 0.3)', // Cyan glow
glowGreen: 'rgba(0, 255, 136, 0.3)', // Green glow
glowPurple: 'rgba(168, 85, 247, 0.3)', // Purple glow
overlay: 'rgba(0, 0, 0, 0.8)', // Dark overlay
overlayLight: 'rgba(0, 0, 0, 0.5)', // Lighter overlay
},
// Status indicators
status: {
online: '#3ba55c', // Discord green
idle: '#faa61a', // Yellow
dnd: '#ed4245', // Red
offline: '#747f8d', // Gray
},
};
@ -79,7 +117,8 @@ export const spacing = {
6: '1.5rem', // 24px
8: '2rem', // 32px
10: '2.5rem', // 40px
12: '3rem', // 48px
12: '3rem', // 48px - Touch target minimum
14: '3.5rem', // 56px - Bottom nav height
16: '4rem', // 64px
20: '5rem', // 80px
24: '6rem', // 96px
@ -87,23 +126,25 @@ export const spacing = {
export const typography = {
fontFamily: {
// Use native system fonts for best mobile performance
sans: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif',
mono: '"Fira Code", Consolas, Monaco, "Courier New", monospace',
mono: 'ui-monospace, "SF Mono", Monaco, "Cascadia Code", "Roboto Mono", Consolas, monospace',
},
fontSize: {
xs: '0.75rem', // 12px
sm: '0.875rem', // 14px
base: '1rem', // 16px
lg: '1.125rem', // 18px
xl: '1.25rem', // 20px
'2xl': '1.5rem', // 24px
'3xl': '1.875rem', // 30px
'4xl': '2.25rem', // 36px
'5xl': '3rem', // 48px
xs: '0.75rem', // 12px - Captions, timestamps
sm: '0.875rem', // 14px - Labels, secondary text
base: '1rem', // 16px - Body text (mobile readable)
lg: '1.125rem', // 18px - Emphasized text
xl: '1.25rem', // 20px - Subheadings
'2xl': '1.5rem', // 24px - Section headers
'3xl': '1.75rem', // 28px - Screen titles
'4xl': '2rem', // 32px - Hero text
'5xl': '2.5rem', // 40px - Large hero
},
fontWeight: {
light: 300,
normal: 400,
medium: 500,
semibold: 600,
@ -114,7 +155,7 @@ export const typography = {
none: 1,
tight: 1.25,
snug: 1.375,
normal: 1.5,
normal: 1.5, // Default for readability
relaxed: 1.625,
loose: 2,
},
@ -122,33 +163,44 @@ export const typography = {
export const borderRadius = {
none: '0',
sm: '0.25rem', // 4px
sm: '0.375rem', // 6px
base: '0.5rem', // 8px
md: '0.75rem', // 12px
lg: '1rem', // 16px
xl: '1.5rem', // 24px
full: '9999px',
lg: '1rem', // 16px - Message bubbles
xl: '1.125rem', // 18px - Message bubbles rounded
'2xl': '1.5rem', // 24px - Cards
full: '9999px', // Pills
};
export const shadows = {
sm: '0 1px 2px 0 rgba(0, 0, 0, 0.05)',
base: '0 1px 3px 0 rgba(0, 0, 0, 0.1), 0 1px 2px 0 rgba(0, 0, 0, 0.06)',
md: '0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06)',
lg: '0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05)',
xl: '0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04)',
'2xl': '0 25px 50px -12px rgba(0, 0, 0, 0.25)',
glow: '0 0 20px rgba(139, 92, 246, 0.4)',
// Subtle shadows for dark theme
sm: '0 1px 2px 0 rgba(0, 0, 0, 0.3)',
base: '0 2px 4px 0 rgba(0, 0, 0, 0.4)',
md: '0 4px 8px -2px rgba(0, 0, 0, 0.5)',
lg: '0 8px 16px -4px rgba(0, 0, 0, 0.6)',
xl: '0 16px 32px -8px rgba(0, 0, 0, 0.7)',
'2xl': '0 25px 50px -12px rgba(0, 0, 0, 0.8)',
// Glow effects for gaming aesthetic
glowCyan: '0 0 20px rgba(0, 217, 255, 0.4)',
glowCyanStrong: '0 0 30px rgba(0, 217, 255, 0.6)',
glowGreen: '0 0 20px rgba(0, 255, 136, 0.4)',
glowPurple: '0 0 20px rgba(168, 85, 247, 0.4)',
glowSubtle: '0 0 10px rgba(255, 255, 255, 0.1)',
};
export const breakpoints = {
sm: '640px',
md: '768px',
lg: '1024px',
xl: '1280px',
'2xl': '1536px',
// Mobile-first breakpoints
xs: '375px', // Small phones
sm: '640px', // Large phones
md: '768px', // Tablets
lg: '1024px', // Small laptops
xl: '1280px', // Desktop
'2xl': '1536px', // Large desktop
};
export const zIndex = {
base: 0,
dropdown: 1000,
sticky: 1100,
fixed: 1200,
@ -156,6 +208,7 @@ export const zIndex = {
modal: 1400,
popover: 1500,
tooltip: 1600,
toast: 1700,
};
export const transitions = {
@ -163,4 +216,58 @@ export const transitions = {
base: '200ms cubic-bezier(0.4, 0, 0.2, 1)',
slow: '300ms cubic-bezier(0.4, 0, 0.2, 1)',
slower: '500ms cubic-bezier(0.4, 0, 0.2, 1)',
// Easing functions
easeInOut: 'cubic-bezier(0.4, 0, 0.2, 1)',
easeOut: 'cubic-bezier(0, 0, 0.2, 1)',
easeIn: 'cubic-bezier(0.4, 0, 1, 1)',
spring: 'cubic-bezier(0.68, -0.55, 0.265, 1.55)',
};
// Mobile-specific tokens
export const mobile = {
touchTarget: {
minimum: '44px', // iOS HIG minimum
comfortable: '48px', // Material Design
large: '56px', // Bottom nav, FABs
},
safeArea: {
top: 'env(safe-area-inset-top)',
bottom: 'env(safe-area-inset-bottom)',
left: 'env(safe-area-inset-left)',
right: 'env(safe-area-inset-right)',
},
statusBar: {
height: '44px', // iOS status bar
heightAndroid: '24px',
},
navbar: {
height: '56px', // Standard mobile nav
heightLarge: '64px', // Large title nav
},
tabBar: {
height: '56px', // Bottom tab bar
heightSafe: 'calc(56px + env(safe-area-inset-bottom))',
},
};
// Glassmorphism effect tokens
export const glass = {
blur: '20px',
blurStrong: '30px',
blurSubtle: '10px',
background: {
light: 'rgba(255, 255, 255, 0.05)',
medium: 'rgba(255, 255, 255, 0.1)',
dark: 'rgba(0, 0, 0, 0.3)',
darker: 'rgba(0, 0, 0, 0.5)',
},
border: 'rgba(255, 255, 255, 0.1)',
borderBright: 'rgba(255, 255, 255, 0.2)',
};