Build RoomScan AI starter app
This commit is contained in:
54
src/components/InstructionOverlay.tsx
Normal file
54
src/components/InstructionOverlay.tsx
Normal file
@@ -0,0 +1,54 @@
|
||||
import { StyleSheet, Text, View } from 'react-native';
|
||||
|
||||
import { colors } from '../theme/colors';
|
||||
|
||||
type InstructionOverlayProps = {
|
||||
title: string;
|
||||
detail: string;
|
||||
tone?: 'info' | 'warning' | 'danger';
|
||||
};
|
||||
|
||||
export function InstructionOverlay({ title, detail, tone = 'info' }: InstructionOverlayProps) {
|
||||
const toneColor = tone === 'warning' ? colors.warning : tone === 'danger' ? colors.danger : colors.primary;
|
||||
|
||||
return (
|
||||
<View style={[styles.container, { borderColor: toneColor }]}>
|
||||
<View style={[styles.indicator, { backgroundColor: toneColor }]} />
|
||||
<View style={styles.textBlock}>
|
||||
<Text style={styles.title}>{title}</Text>
|
||||
<Text style={styles.detail}>{detail}</Text>
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
alignItems: 'center',
|
||||
backgroundColor: 'rgba(8, 17, 31, 0.92)',
|
||||
borderRadius: 20,
|
||||
borderWidth: 1,
|
||||
flexDirection: 'row',
|
||||
gap: 14,
|
||||
padding: 16,
|
||||
},
|
||||
indicator: {
|
||||
borderRadius: 999,
|
||||
height: 14,
|
||||
width: 14,
|
||||
},
|
||||
textBlock: {
|
||||
flex: 1,
|
||||
},
|
||||
title: {
|
||||
color: colors.textPrimary,
|
||||
fontSize: 16,
|
||||
fontWeight: '800',
|
||||
},
|
||||
detail: {
|
||||
color: colors.textSecondary,
|
||||
fontSize: 13,
|
||||
lineHeight: 19,
|
||||
marginTop: 4,
|
||||
},
|
||||
});
|
||||
51
src/components/PrimaryButton.tsx
Normal file
51
src/components/PrimaryButton.tsx
Normal file
@@ -0,0 +1,51 @@
|
||||
import { Pressable, StyleSheet, Text } from 'react-native';
|
||||
|
||||
import { colors } from '../theme/colors';
|
||||
|
||||
type PrimaryButtonProps = {
|
||||
label: string;
|
||||
onPress: () => void;
|
||||
variant?: 'primary' | 'secondary';
|
||||
};
|
||||
|
||||
export function PrimaryButton({ label, onPress, variant = 'primary' }: PrimaryButtonProps) {
|
||||
return (
|
||||
<Pressable
|
||||
accessibilityRole="button"
|
||||
onPress={onPress}
|
||||
style={({ pressed }) => [
|
||||
styles.button,
|
||||
variant === 'secondary' && styles.secondary,
|
||||
pressed && styles.pressed,
|
||||
]}
|
||||
>
|
||||
<Text style={[styles.label, variant === 'secondary' && styles.secondaryLabel]}>{label}</Text>
|
||||
</Pressable>
|
||||
);
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
button: {
|
||||
alignItems: 'center',
|
||||
backgroundColor: colors.primary,
|
||||
borderRadius: 18,
|
||||
paddingHorizontal: 22,
|
||||
paddingVertical: 16,
|
||||
},
|
||||
secondary: {
|
||||
backgroundColor: colors.surfaceRaised,
|
||||
borderColor: colors.border,
|
||||
borderWidth: 1,
|
||||
},
|
||||
pressed: {
|
||||
opacity: 0.82,
|
||||
},
|
||||
label: {
|
||||
color: colors.background,
|
||||
fontSize: 16,
|
||||
fontWeight: '800',
|
||||
},
|
||||
secondaryLabel: {
|
||||
color: colors.textPrimary,
|
||||
},
|
||||
});
|
||||
62
src/components/ScanProgressCard.tsx
Normal file
62
src/components/ScanProgressCard.tsx
Normal file
@@ -0,0 +1,62 @@
|
||||
import { StyleSheet, Text, View } from 'react-native';
|
||||
|
||||
import { colors } from '../theme/colors';
|
||||
|
||||
type ScanProgressCardProps = {
|
||||
progress: number;
|
||||
};
|
||||
|
||||
export function ScanProgressCard({ progress }: ScanProgressCardProps) {
|
||||
return (
|
||||
<View style={styles.card}>
|
||||
<View style={styles.row}>
|
||||
<Text style={styles.label}>Scan-Fortschritt</Text>
|
||||
<Text style={styles.value}>{progress}%</Text>
|
||||
</View>
|
||||
<View style={styles.track}>
|
||||
<View style={[styles.fill, { width: `${progress}%` }]} />
|
||||
</View>
|
||||
<Text style={styles.hint}>Halte das iPhone ruhig und bewege dich entlang der Wandkontur.</Text>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
card: {
|
||||
backgroundColor: colors.surface,
|
||||
borderColor: colors.border,
|
||||
borderRadius: 22,
|
||||
borderWidth: 1,
|
||||
padding: 18,
|
||||
},
|
||||
row: {
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'space-between',
|
||||
},
|
||||
label: {
|
||||
color: colors.textSecondary,
|
||||
fontSize: 14,
|
||||
},
|
||||
value: {
|
||||
color: colors.textPrimary,
|
||||
fontSize: 18,
|
||||
fontWeight: '800',
|
||||
},
|
||||
track: {
|
||||
backgroundColor: colors.surfaceRaised,
|
||||
borderRadius: 999,
|
||||
height: 10,
|
||||
marginTop: 14,
|
||||
overflow: 'hidden',
|
||||
},
|
||||
fill: {
|
||||
backgroundColor: colors.accent,
|
||||
height: '100%',
|
||||
},
|
||||
hint: {
|
||||
color: colors.textSecondary,
|
||||
fontSize: 13,
|
||||
lineHeight: 19,
|
||||
marginTop: 14,
|
||||
},
|
||||
});
|
||||
29
src/navigation/AppNavigator.tsx
Normal file
29
src/navigation/AppNavigator.tsx
Normal file
@@ -0,0 +1,29 @@
|
||||
import { NavigationContainer } from '@react-navigation/native';
|
||||
import { createNativeStackNavigator } from '@react-navigation/native-stack';
|
||||
|
||||
import { HomeScreen } from '../screens/HomeScreen';
|
||||
import { ResultScreen } from '../screens/ResultScreen';
|
||||
import { ScanScreen } from '../screens/ScanScreen';
|
||||
import { colors } from '../theme/colors';
|
||||
import type { RootStackParamList } from './types';
|
||||
|
||||
const Stack = createNativeStackNavigator<RootStackParamList>();
|
||||
|
||||
export function AppNavigator() {
|
||||
return (
|
||||
<NavigationContainer>
|
||||
<Stack.Navigator
|
||||
screenOptions={{
|
||||
headerStyle: { backgroundColor: colors.background },
|
||||
headerTintColor: colors.textPrimary,
|
||||
headerTitleStyle: { fontWeight: '700' },
|
||||
contentStyle: { backgroundColor: colors.background },
|
||||
}}
|
||||
>
|
||||
<Stack.Screen name="Home" component={HomeScreen} options={{ title: 'RoomScan AI' }} />
|
||||
<Stack.Screen name="Scan" component={ScanScreen} options={{ title: 'Raum scannen' }} />
|
||||
<Stack.Screen name="Result" component={ResultScreen} options={{ title: '3D Ergebnis' }} />
|
||||
</Stack.Navigator>
|
||||
</NavigationContainer>
|
||||
);
|
||||
}
|
||||
5
src/navigation/types.ts
Normal file
5
src/navigation/types.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
export type RootStackParamList = {
|
||||
Home: undefined;
|
||||
Scan: undefined;
|
||||
Result: undefined;
|
||||
};
|
||||
108
src/screens/HomeScreen.tsx
Normal file
108
src/screens/HomeScreen.tsx
Normal file
@@ -0,0 +1,108 @@
|
||||
import type { NativeStackScreenProps } from '@react-navigation/native-stack';
|
||||
import { ScrollView, StyleSheet, Text, View } from 'react-native';
|
||||
import { SafeAreaView } from 'react-native-safe-area-context';
|
||||
|
||||
import { PrimaryButton } from '../components/PrimaryButton';
|
||||
import type { RootStackParamList } from '../navigation/types';
|
||||
import { colors } from '../theme/colors';
|
||||
|
||||
type HomeScreenProps = NativeStackScreenProps<RootStackParamList, 'Home'>;
|
||||
|
||||
const steps = ['Startpunkt wählen', 'Langsam entlang der Wand bewegen', 'Hinweise beachten', '3D Modell prüfen'];
|
||||
|
||||
export function HomeScreen({ navigation }: HomeScreenProps) {
|
||||
return (
|
||||
<SafeAreaView style={styles.safeArea} edges={['bottom']}>
|
||||
<ScrollView contentContainerStyle={styles.content}>
|
||||
<View style={styles.hero}>
|
||||
<Text style={styles.eyebrow}>ARKit + RoomPlan vorbereitet</Text>
|
||||
<Text style={styles.title}>Geführte 3D Raumscans fuer iOS</Text>
|
||||
<Text style={styles.subtitle}>
|
||||
RoomScan AI fuehrt Nutzer Schritt fuer Schritt durch den Scan und bereitet die App auf eine
|
||||
native RoomPlan-Integration per Expo Prebuild vor.
|
||||
</Text>
|
||||
</View>
|
||||
|
||||
<View style={styles.card}>
|
||||
<Text style={styles.cardTitle}>Scan Ablauf</Text>
|
||||
{steps.map((step, index) => (
|
||||
<View key={step} style={styles.stepRow}>
|
||||
<Text style={styles.stepNumber}>{index + 1}</Text>
|
||||
<Text style={styles.stepText}>{step}</Text>
|
||||
</View>
|
||||
))}
|
||||
</View>
|
||||
|
||||
<PrimaryButton label="Mock Scan starten" onPress={() => navigation.navigate('Scan')} />
|
||||
</ScrollView>
|
||||
</SafeAreaView>
|
||||
);
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
safeArea: {
|
||||
flex: 1,
|
||||
},
|
||||
content: {
|
||||
gap: 24,
|
||||
padding: 24,
|
||||
},
|
||||
hero: {
|
||||
backgroundColor: colors.surface,
|
||||
borderColor: colors.border,
|
||||
borderRadius: 28,
|
||||
borderWidth: 1,
|
||||
padding: 24,
|
||||
},
|
||||
eyebrow: {
|
||||
color: colors.primary,
|
||||
fontSize: 13,
|
||||
fontWeight: '800',
|
||||
letterSpacing: 0.5,
|
||||
textTransform: 'uppercase',
|
||||
},
|
||||
title: {
|
||||
color: colors.textPrimary,
|
||||
fontSize: 34,
|
||||
fontWeight: '900',
|
||||
lineHeight: 39,
|
||||
marginTop: 12,
|
||||
},
|
||||
subtitle: {
|
||||
color: colors.textSecondary,
|
||||
fontSize: 16,
|
||||
lineHeight: 24,
|
||||
marginTop: 14,
|
||||
},
|
||||
card: {
|
||||
backgroundColor: colors.surfaceRaised,
|
||||
borderRadius: 24,
|
||||
padding: 20,
|
||||
},
|
||||
cardTitle: {
|
||||
color: colors.textPrimary,
|
||||
fontSize: 18,
|
||||
fontWeight: '800',
|
||||
marginBottom: 14,
|
||||
},
|
||||
stepRow: {
|
||||
alignItems: 'center',
|
||||
flexDirection: 'row',
|
||||
gap: 12,
|
||||
paddingVertical: 9,
|
||||
},
|
||||
stepNumber: {
|
||||
backgroundColor: colors.primaryDark,
|
||||
borderRadius: 999,
|
||||
color: colors.textPrimary,
|
||||
fontWeight: '800',
|
||||
overflow: 'hidden',
|
||||
paddingHorizontal: 10,
|
||||
paddingVertical: 6,
|
||||
},
|
||||
stepText: {
|
||||
color: colors.textSecondary,
|
||||
flex: 1,
|
||||
fontSize: 15,
|
||||
},
|
||||
});
|
||||
130
src/screens/ResultScreen.tsx
Normal file
130
src/screens/ResultScreen.tsx
Normal file
@@ -0,0 +1,130 @@
|
||||
import type { NativeStackScreenProps } from '@react-navigation/native-stack';
|
||||
import { StyleSheet, Text, View } from 'react-native';
|
||||
import { SafeAreaView } from 'react-native-safe-area-context';
|
||||
|
||||
import { PrimaryButton } from '../components/PrimaryButton';
|
||||
import type { RootStackParamList } from '../navigation/types';
|
||||
import { colors } from '../theme/colors';
|
||||
|
||||
type ResultScreenProps = NativeStackScreenProps<RootStackParamList, 'Result'>;
|
||||
|
||||
export function ResultScreen({ navigation }: ResultScreenProps) {
|
||||
return (
|
||||
<SafeAreaView style={styles.safeArea} edges={['bottom']}>
|
||||
<View style={styles.container}>
|
||||
<View style={styles.modelPreview}>
|
||||
<View style={styles.floorPlan}>
|
||||
<View style={styles.wallLong} />
|
||||
<View style={styles.wallShort} />
|
||||
<View style={styles.roomBlockLarge} />
|
||||
<View style={styles.roomBlockSmall} />
|
||||
</View>
|
||||
<Text style={styles.previewLabel}>Mock 3D Modell</Text>
|
||||
</View>
|
||||
|
||||
<View style={styles.summaryCard}>
|
||||
<Text style={styles.title}>Scan bereit zur Auswertung</Text>
|
||||
<Text style={styles.body}>
|
||||
Diese Ansicht ist ein Platzhalter fuer das spaetere RoomPlan-Ergebnis. Nach der nativen iOS
|
||||
Integration werden hier erkannte Waende, Tueren, Fenster und Moebel angezeigt.
|
||||
</Text>
|
||||
</View>
|
||||
|
||||
<View style={styles.actions}>
|
||||
<PrimaryButton label="Neuen Scan starten" onPress={() => navigation.navigate('Scan')} />
|
||||
<PrimaryButton label="Zur Startseite" variant="secondary" onPress={() => navigation.navigate('Home')} />
|
||||
</View>
|
||||
</View>
|
||||
</SafeAreaView>
|
||||
);
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
safeArea: {
|
||||
flex: 1,
|
||||
},
|
||||
container: {
|
||||
flex: 1,
|
||||
gap: 20,
|
||||
padding: 20,
|
||||
},
|
||||
modelPreview: {
|
||||
alignItems: 'center',
|
||||
backgroundColor: colors.surface,
|
||||
borderColor: colors.border,
|
||||
borderRadius: 30,
|
||||
borderWidth: 1,
|
||||
flex: 1,
|
||||
justifyContent: 'center',
|
||||
minHeight: 360,
|
||||
padding: 24,
|
||||
},
|
||||
floorPlan: {
|
||||
borderColor: colors.primary,
|
||||
borderRadius: 24,
|
||||
borderWidth: 3,
|
||||
height: 220,
|
||||
transform: [{ rotateX: '58deg' }, { rotateZ: '-18deg' }],
|
||||
width: 220,
|
||||
},
|
||||
wallLong: {
|
||||
backgroundColor: colors.primary,
|
||||
borderRadius: 10,
|
||||
height: 14,
|
||||
left: 20,
|
||||
position: 'absolute',
|
||||
top: 72,
|
||||
width: 150,
|
||||
},
|
||||
wallShort: {
|
||||
backgroundColor: colors.accent,
|
||||
borderRadius: 10,
|
||||
height: 110,
|
||||
position: 'absolute',
|
||||
right: 48,
|
||||
top: 54,
|
||||
width: 14,
|
||||
},
|
||||
roomBlockLarge: {
|
||||
backgroundColor: 'rgba(98, 214, 255, 0.24)',
|
||||
borderRadius: 18,
|
||||
bottom: 28,
|
||||
height: 70,
|
||||
left: 34,
|
||||
position: 'absolute',
|
||||
width: 88,
|
||||
},
|
||||
roomBlockSmall: {
|
||||
backgroundColor: 'rgba(181, 240, 109, 0.28)',
|
||||
borderRadius: 14,
|
||||
height: 52,
|
||||
position: 'absolute',
|
||||
right: 32,
|
||||
top: 24,
|
||||
width: 58,
|
||||
},
|
||||
previewLabel: {
|
||||
color: colors.textSecondary,
|
||||
fontSize: 15,
|
||||
marginTop: 32,
|
||||
},
|
||||
summaryCard: {
|
||||
backgroundColor: colors.surfaceRaised,
|
||||
borderRadius: 24,
|
||||
padding: 20,
|
||||
},
|
||||
title: {
|
||||
color: colors.textPrimary,
|
||||
fontSize: 21,
|
||||
fontWeight: '900',
|
||||
},
|
||||
body: {
|
||||
color: colors.textSecondary,
|
||||
fontSize: 15,
|
||||
lineHeight: 23,
|
||||
marginTop: 10,
|
||||
},
|
||||
actions: {
|
||||
gap: 12,
|
||||
},
|
||||
});
|
||||
135
src/screens/ScanScreen.tsx
Normal file
135
src/screens/ScanScreen.tsx
Normal file
@@ -0,0 +1,135 @@
|
||||
import type { NativeStackScreenProps } from '@react-navigation/native-stack';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { StyleSheet, Text, View } from 'react-native';
|
||||
import { SafeAreaView } from 'react-native-safe-area-context';
|
||||
|
||||
import { InstructionOverlay } from '../components/InstructionOverlay';
|
||||
import { PrimaryButton } from '../components/PrimaryButton';
|
||||
import { ScanProgressCard } from '../components/ScanProgressCard';
|
||||
import type { RootStackParamList } from '../navigation/types';
|
||||
import { getGuidanceForProgress } from '../services/scanGuidance';
|
||||
import { colors } from '../theme/colors';
|
||||
|
||||
type ScanScreenProps = NativeStackScreenProps<RootStackParamList, 'Scan'>;
|
||||
|
||||
export function ScanScreen({ navigation }: ScanScreenProps) {
|
||||
const [progress, setProgress] = useState(10);
|
||||
const guidance = getGuidanceForProgress(progress);
|
||||
|
||||
// Simulates RoomPlan scan updates until native iOS capture is connected.
|
||||
useEffect(() => {
|
||||
const intervalId = setInterval(() => {
|
||||
setProgress((current) => Math.min(current + 5, 92));
|
||||
}, 1200);
|
||||
|
||||
return () => clearInterval(intervalId);
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<SafeAreaView style={styles.safeArea} edges={['bottom']}>
|
||||
<View style={styles.container}>
|
||||
<View style={styles.cameraMock}>
|
||||
<View style={styles.gridLineVertical} />
|
||||
<View style={styles.gridLineHorizontal} />
|
||||
<View style={styles.scanFrame}>
|
||||
<Text style={styles.roomLabel}>Wohnzimmer</Text>
|
||||
<View style={styles.cornerMarkerTop} />
|
||||
<View style={styles.cornerMarkerBottom} />
|
||||
</View>
|
||||
<View style={styles.overlayPosition}>
|
||||
<InstructionOverlay title={guidance.title} detail={guidance.detail} tone={guidance.tone} />
|
||||
</View>
|
||||
</View>
|
||||
|
||||
<ScanProgressCard progress={progress} />
|
||||
|
||||
<View style={styles.actions}>
|
||||
<PrimaryButton label="Scan abschliessen" onPress={() => navigation.navigate('Result')} />
|
||||
<PrimaryButton label="Neu starten" variant="secondary" onPress={() => setProgress(10)} />
|
||||
</View>
|
||||
</View>
|
||||
</SafeAreaView>
|
||||
);
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
safeArea: {
|
||||
flex: 1,
|
||||
},
|
||||
container: {
|
||||
flex: 1,
|
||||
gap: 18,
|
||||
padding: 20,
|
||||
},
|
||||
cameraMock: {
|
||||
backgroundColor: '#0b1628',
|
||||
borderColor: colors.border,
|
||||
borderRadius: 30,
|
||||
borderWidth: 1,
|
||||
flex: 1,
|
||||
minHeight: 380,
|
||||
overflow: 'hidden',
|
||||
},
|
||||
gridLineVertical: {
|
||||
backgroundColor: 'rgba(98, 214, 255, 0.16)',
|
||||
height: '100%',
|
||||
left: '50%',
|
||||
position: 'absolute',
|
||||
width: 1,
|
||||
},
|
||||
gridLineHorizontal: {
|
||||
backgroundColor: 'rgba(98, 214, 255, 0.16)',
|
||||
height: 1,
|
||||
position: 'absolute',
|
||||
top: '50%',
|
||||
width: '100%',
|
||||
},
|
||||
scanFrame: {
|
||||
borderColor: colors.primary,
|
||||
borderRadius: 24,
|
||||
borderWidth: 2,
|
||||
bottom: 70,
|
||||
left: 34,
|
||||
position: 'absolute',
|
||||
right: 34,
|
||||
top: 70,
|
||||
},
|
||||
roomLabel: {
|
||||
alignSelf: 'center',
|
||||
backgroundColor: colors.primary,
|
||||
borderRadius: 999,
|
||||
color: colors.background,
|
||||
fontWeight: '900',
|
||||
marginTop: -16,
|
||||
overflow: 'hidden',
|
||||
paddingHorizontal: 16,
|
||||
paddingVertical: 8,
|
||||
},
|
||||
cornerMarkerTop: {
|
||||
backgroundColor: colors.accent,
|
||||
borderRadius: 8,
|
||||
height: 16,
|
||||
position: 'absolute',
|
||||
right: 20,
|
||||
top: 42,
|
||||
width: 16,
|
||||
},
|
||||
cornerMarkerBottom: {
|
||||
backgroundColor: colors.warning,
|
||||
borderRadius: 8,
|
||||
bottom: 34,
|
||||
height: 16,
|
||||
left: 24,
|
||||
position: 'absolute',
|
||||
width: 16,
|
||||
},
|
||||
overlayPosition: {
|
||||
bottom: 18,
|
||||
left: 18,
|
||||
position: 'absolute',
|
||||
right: 18,
|
||||
},
|
||||
actions: {
|
||||
gap: 12,
|
||||
},
|
||||
});
|
||||
33
src/services/scanGuidance.ts
Normal file
33
src/services/scanGuidance.ts
Normal file
@@ -0,0 +1,33 @@
|
||||
export type ScanGuidance = {
|
||||
title: string;
|
||||
detail: string;
|
||||
tone: 'info' | 'warning' | 'danger';
|
||||
};
|
||||
|
||||
const guidanceSteps: ScanGuidance[] = [
|
||||
{
|
||||
title: 'Startpunkt setzen',
|
||||
detail: 'Richte die Kamera auf eine freie Ecke und beginne dort mit dem Raumscan.',
|
||||
tone: 'info',
|
||||
},
|
||||
{
|
||||
title: 'Langsamer bewegen',
|
||||
detail: 'Die Kamera verliert Details. Reduziere die Geschwindigkeit fuer stabilere Messpunkte.',
|
||||
tone: 'warning',
|
||||
},
|
||||
{
|
||||
title: 'Richtung ändern',
|
||||
detail: 'Schwenke leicht nach rechts, damit die Wandkante vollstaendig erkannt wird.',
|
||||
tone: 'info',
|
||||
},
|
||||
{
|
||||
title: 'Bereich erneut erfassen',
|
||||
detail: 'Ein Objekt wurde unklar erkannt. Gehe einen Schritt zurueck und scanne die Zone erneut.',
|
||||
tone: 'danger',
|
||||
},
|
||||
];
|
||||
|
||||
export function getGuidanceForProgress(progress: number) {
|
||||
const index = Math.min(Math.floor(progress / 25), guidanceSteps.length - 1);
|
||||
return guidanceSteps[index];
|
||||
}
|
||||
13
src/theme/colors.ts
Normal file
13
src/theme/colors.ts
Normal file
@@ -0,0 +1,13 @@
|
||||
export const colors = {
|
||||
background: '#08111f',
|
||||
surface: '#101d31',
|
||||
surfaceRaised: '#17263d',
|
||||
primary: '#62d6ff',
|
||||
primaryDark: '#0f8fbf',
|
||||
accent: '#b5f06d',
|
||||
warning: '#ffcf5a',
|
||||
danger: '#ff7a7a',
|
||||
textPrimary: '#f4f8ff',
|
||||
textSecondary: '#a7b5c9',
|
||||
border: '#263854',
|
||||
};
|
||||
Reference in New Issue
Block a user