design: align visual style with bincio_autarchive

- Add src/theme.ts with centralised color palette
- Backgrounds: #111 → #09090b, surfaces #1e1e1e → #18181b
- All cards get 1px #27272a borders (matches autarchive cards)
- Text: #fff/#888/#555 → #f4f4f5/#a1a1aa/#71717a
- Accent: #3b82f6 → #60a5fa (autarchive default palette)
- Tab icons: colored emoji → monochromatic Unicode (◉ ☰ ⚙)
- Action buttons use muted palette (#16a34a / #d97706 / #dc2626)
- Keep-awake toggle uses ◑/◌ symbols, border highlights accent on active
- Connect/Scan buttons match autarchive surface+border style
This commit is contained in:
Davide Scaini
2026-06-03 09:50:05 +02:00
parent 6e47ced264
commit ea938e5644
7 changed files with 165 additions and 137 deletions
+28 -30
View File
@@ -7,12 +7,13 @@ import { Map, Camera, GeoJSONSource, Layer, UserLocation } from '@maplibre/mapli
import type { LineLayerStyle } from '@maplibre/maplibre-react-native';
import { useRecordingStore } from '../store/recording';
import { startGpsRecording, stopGpsRecording, requestLocationPermissions } from '../services/gps';
import { RootStackParamList, TrackPoint } from '../types';
import { RootStackParamList } from '../types';
import { colors } from '../theme';
const MAP_STYLE = 'https://tiles.openfreemap.org/styles/liberty';
const trackLineStyle: LineLayerStyle = {
lineColor: '#3b82f6',
lineColor: colors.accent,
lineWidth: 3,
lineJoin: 'round',
lineCap: 'round',
@@ -41,10 +42,7 @@ export function RecordingScreen() {
const trackGeoJSON = useMemo<GeoJSON.Feature<GeoJSON.LineString>>(() => ({
type: 'Feature',
geometry: {
type: 'LineString',
coordinates: trackPoints.map((p) => [p.lon, p.lat]),
},
geometry: { type: 'LineString', coordinates: trackPoints.map((p) => [p.lon, p.lat]) },
properties: {},
}), [trackPoints]);
@@ -84,14 +82,14 @@ export function RecordingScreen() {
return (
<View style={styles.container}>
<View style={styles.statsGrid}>
<StatBox label="Time" value={formatDuration(stats.elapsedSeconds)} />
<StatBox label="Distance" value={`${(stats.distanceMeters / 1000).toFixed(2)} km`} />
<StatBox label="Speed" value={`${stats.currentSpeedKph.toFixed(1)} km/h`} />
<StatBox label="Time" value={formatDuration(stats.elapsedSeconds)} />
<StatBox label="Distance" value={`${(stats.distanceMeters / 1000).toFixed(2)} km`} />
<StatBox label="Speed" value={`${stats.currentSpeedKph.toFixed(1)} km/h`} />
<StatBox label="Avg Speed" value={`${stats.avgSpeedKph.toFixed(1)} km/h`} />
<StatBox label="Elevation" value={`+${stats.elevationGainMeters.toFixed(0)} m`} />
<StatBox label="HR" value={ble.hr ? `${ble.hr} bpm` : '—'} />
<StatBox label="Power" value={ble.power ? `${ble.power} W` : '—'} />
<StatBox label="Cadence" value={ble.cadence ? `${ble.cadence} rpm` : '—'} />
<StatBox label="HR" value={ble.hr ? `${ble.hr} bpm` : '—'} />
<StatBox label="Power" value={ble.power ? `${ble.power} W` : '—'} />
<StatBox label="Cadence" value={ble.cadence ? `${ble.cadence} rpm` : '—'} />
</View>
<View style={styles.mapArea}>
@@ -118,7 +116,7 @@ export function RecordingScreen() {
style={[styles.awakeBtn, keepAwake && styles.awakeBtnOn]}
onPress={() => setKeepAwake(!keepAwake)}
>
<Text style={styles.awakeBtnText}>{keepAwake ? '☀️ Awake' : '💤 Sleep'}</Text>
<Text style={styles.awakeBtnText}>{keepAwake ? ' Awake' : ' Sleep'}</Text>
</TouchableOpacity>
{status === 'idle' && (
@@ -161,21 +159,21 @@ function StatBox({ label, value }: { label: string; value: string }) {
}
const styles = StyleSheet.create({
container: { flex: 1, backgroundColor: '#111' },
statsGrid: { flexDirection: 'row', flexWrap: 'wrap', padding: 8 },
statBox: { width: '25%', padding: 8, alignItems: 'center' },
statLabel: { color: '#888', fontSize: 11, textTransform: 'uppercase' },
statValue: { color: '#fff', fontSize: 18, fontWeight: '600', marginTop: 2 },
mapArea: { flex: 1, overflow: 'hidden' },
sensorBtn: { position: 'absolute', top: 10, right: 10, backgroundColor: 'rgba(17,17,17,0.85)', borderRadius: 8, paddingVertical: 6, paddingHorizontal: 12 },
sensorBtnText: { color: '#3b82f6', fontSize: 13, fontWeight: '600' },
controls: { flexDirection: 'row', alignItems: 'center', justifyContent: 'center', gap: 12, padding: 20 },
awakeBtn: { backgroundColor: '#1e1e1e', borderRadius: 20, paddingVertical: 8, paddingHorizontal: 14 },
awakeBtnOn: { backgroundColor: '#2a2a1a' },
awakeBtnText: { color: '#aaa', fontSize: 13 },
btn: { paddingVertical: 16, paddingHorizontal: 32, borderRadius: 50 },
btnStart: { backgroundColor: '#22c55e' },
btnPause: { backgroundColor: '#f59e0b' },
btnStop: { backgroundColor: '#ef4444' },
btnText: { color: '#fff', fontSize: 18, fontWeight: '700' },
container: { flex: 1, backgroundColor: colors.bg },
statsGrid: { flexDirection: 'row', flexWrap: 'wrap', padding: 8, borderBottomWidth: 1, borderBottomColor: colors.border },
statBox: { width: '25%', padding: 8, alignItems: 'center' },
statLabel: { color: colors.textMuted, fontSize: 10, textTransform: 'uppercase', letterSpacing: 0.5 },
statValue: { color: colors.text, fontSize: 17, fontWeight: '600', marginTop: 2 },
mapArea: { flex: 1, overflow: 'hidden' },
sensorBtn: { position: 'absolute', top: 10, right: 10, backgroundColor: 'rgba(9,9,11,0.8)', borderRadius: 8, borderWidth: 1, borderColor: colors.border, paddingVertical: 6, paddingHorizontal: 12 },
sensorBtnText: { color: colors.accent, fontSize: 13, fontWeight: '600' },
controls: { flexDirection: 'row', alignItems: 'center', justifyContent: 'center', gap: 12, padding: 20, borderTopWidth: 1, borderTopColor: colors.border },
awakeBtn: { backgroundColor: colors.surface, borderRadius: 20, borderWidth: 1, borderColor: colors.border, paddingVertical: 8, paddingHorizontal: 14 },
awakeBtnOn: { borderColor: colors.accent },
awakeBtnText: { color: colors.textSub, fontSize: 13 },
btn: { paddingVertical: 15, paddingHorizontal: 30, borderRadius: 50 },
btnStart: { backgroundColor: colors.btnStart },
btnPause: { backgroundColor: colors.btnPause },
btnStop: { backgroundColor: colors.btnStop },
btnText: { color: '#fff', fontSize: 17, fontWeight: '700' },
});