Move project from bordanlage/ to repo root
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
77
dashboard/src/components/layout/TopBar.jsx
Normal file
77
dashboard/src/components/layout/TopBar.jsx
Normal file
@@ -0,0 +1,77 @@
|
||||
import { useState } from 'react'
|
||||
import { useNMEA } from '../../hooks/useNMEA.js'
|
||||
|
||||
const isDev = import.meta.env.DEV
|
||||
|
||||
function formatTime() {
|
||||
return new Date().toLocaleTimeString('en-GB', { hour: '2-digit', minute: '2-digit' })
|
||||
}
|
||||
|
||||
export default function TopBar() {
|
||||
const { sog, heading, connected } = useNMEA()
|
||||
const [time, setTime] = useState(formatTime())
|
||||
|
||||
// Clock tick
|
||||
useState(() => {
|
||||
const t = setInterval(() => setTime(formatTime()), 5000)
|
||||
return () => clearInterval(t)
|
||||
})
|
||||
|
||||
return (
|
||||
<header style={styles.bar}>
|
||||
<div style={styles.left}>
|
||||
<span style={styles.logo}>⚓ Bordanlage</span>
|
||||
{isDev && <span style={styles.devBadge}>DEV · MOCK DATA</span>}
|
||||
</div>
|
||||
|
||||
<div style={styles.center}>
|
||||
{connected && sog != null && (
|
||||
<span style={styles.stat}>
|
||||
<span style={styles.val}>{sog.toFixed(1)}</span>
|
||||
<span style={styles.unit}>kn</span>
|
||||
</span>
|
||||
)}
|
||||
{connected && heading != null && (
|
||||
<span style={styles.stat}>
|
||||
<span style={styles.val}>{Math.round(heading)}°</span>
|
||||
<span style={styles.unit}>HDG</span>
|
||||
</span>
|
||||
)}
|
||||
{!connected && (
|
||||
<span style={{ color: 'var(--muted)', fontSize: 13 }}>No signal</span>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div style={styles.right}>
|
||||
<span style={styles.time}>{time}</span>
|
||||
</div>
|
||||
</header>
|
||||
)
|
||||
}
|
||||
|
||||
const styles = {
|
||||
bar: {
|
||||
height: 52,
|
||||
background: 'var(--surface)',
|
||||
borderBottom: '1px solid var(--border)',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
padding: '0 16px',
|
||||
gap: 16,
|
||||
flexShrink: 0,
|
||||
},
|
||||
left: { display: 'flex', alignItems: 'center', gap: 10, flex: 1 },
|
||||
center: { display: 'flex', gap: 20, alignItems: 'center' },
|
||||
right: { flex: 1, display: 'flex', justifyContent: 'flex-end' },
|
||||
logo: { fontWeight: 700, fontSize: 15, color: 'var(--accent)', letterSpacing: '0.04em' },
|
||||
devBadge: {
|
||||
fontSize: 10, fontWeight: 600, padding: '2px 7px',
|
||||
background: '#f59e0b22', color: 'var(--warning)',
|
||||
border: '1px solid var(--warning)', borderRadius: 4,
|
||||
letterSpacing: '0.06em',
|
||||
},
|
||||
stat: { display: 'flex', alignItems: 'baseline', gap: 3 },
|
||||
val: { fontFamily: 'var(--font-mono)', fontSize: 16, color: 'var(--text)' },
|
||||
unit: { fontSize: 10, color: 'var(--muted)' },
|
||||
time: { fontFamily: 'var(--font-mono)', fontSize: 14, color: 'var(--muted)' },
|
||||
}
|
||||
Reference in New Issue
Block a user