AeThex-Connect/packages/mobile/src/screens/FriendsScreen.tsx
MrPiglr 651cba733d
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
2026-01-12 03:28:16 +00:00

222 lines
5.9 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* 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,
},
});