feat: update lake water data, implement service worker and manifest, and add favicon

This commit is contained in:
David Fencl
2026-06-08 20:06:23 +02:00
parent f8a7be7fa3
commit 7a7abdd3e5
61 changed files with 1455 additions and 184 deletions
+47 -7
View File
@@ -22,6 +22,7 @@ interface LipnoData {
fullness: number;
temperature?: number | null;
precipitation?: number | null;
qn?: string;
}
interface Props {
@@ -89,12 +90,21 @@ const CustomTooltip = ({ active, payload, label, language, isWeather, isRiver }:
if (!labelStr || entry.value === null || entry.value === undefined) return null;
return (
<div key={index} style={{ margin: 0, color: 'var(--text-main)', display: 'flex', alignItems: 'center', marginBottom: '4px' }}>
<span style={{ display: 'inline-block', width: '8px', height: '8px', borderRadius: '50%', backgroundColor: color, marginRight: '8px' }}></span>
{labelStr}: <span style={{ fontWeight: 'bold', marginLeft: '4px' }}>{entry.value.toFixed(entry.dataKey === 'level' ? (isRiver ? 0 : 2) : 1)} {unit}</span>
</div>
);
<div key={index} style={{ margin: 0, color: 'var(--text-main)', display: 'flex', alignItems: 'center', marginBottom: '4px' }}>
<span style={{ display: 'inline-block', width: '8px', height: '8px', borderRadius: '50%', backgroundColor: color, marginRight: '8px' }}></span>
{labelStr}: <span style={{ fontWeight: 'bold', marginLeft: '4px' }}>{entry.value.toFixed(entry.dataKey === 'level' ? (isRiver ? 0 : 2) : 1)} {unit}</span>
</div>
);
})}
{payload[0]?.payload?.qn ? (
<div style={{ marginTop: '8px', paddingTop: '8px', borderTop: '1px solid var(--border-color)', fontSize: '0.8rem', color: '#f59e0b', display: 'flex', alignItems: 'center', gap: '4px' }}>
{language === 'cs' ? `Neověřené měření (QN: ${payload[0].payload.qn})` : `Unverified measurement (QN: ${payload[0].payload.qn})`}
</div>
) : (
<div style={{ marginTop: '8px', paddingTop: '8px', borderTop: '1px solid var(--border-color)', fontSize: '0.8rem', color: 'var(--color-green)', display: 'flex', alignItems: 'center', gap: '4px' }}>
{language === 'cs' ? 'Měření ověřeno dispečinkem' : 'Measurement verified'}
</div>
)}
</div>
);
}
@@ -162,7 +172,8 @@ const LakeDetail = ({ language, lakeId, windUnit = 'kmh' }: Props) => {
volume: item.volume || 0,
fullness: 0,
temperature: item.temperature,
precipitation: item.precipitation === null ? undefined : item.precipitation
precipitation: item.precipitation === null ? undefined : item.precipitation,
qn: item.qn || ''
};
});
setData(formattedData);
@@ -350,9 +361,38 @@ const LakeDetail = ({ language, lakeId, windUnit = 'kmh' }: Props) => {
</>
)}
<div style={{ color: 'var(--text-muted)', fontSize: '0.9rem', marginTop: '-0.5rem', display: 'flex', alignItems: 'center', gap: '0.5rem' }}>
<div style={{ color: 'var(--text-muted)', fontSize: '0.9rem', marginTop: '-0.5rem', display: 'flex', alignItems: 'center', gap: '0.75rem', flexWrap: 'wrap' }}>
<span>{topbarDict.updated} {new Date().toLocaleDateString(language === 'cs' ? 'cs-CZ' : 'en-GB', { day: '2-digit', month: '2-digit', year: 'numeric' })}, {new Date().toLocaleTimeString(language === 'cs' ? 'cs-CZ' : 'en-GB', { hour: '2-digit', minute: '2-digit' })} UTC</span>
<div className="status-dot"></div>
{latestData.qn ? (
<span style={{
fontSize: '0.75rem',
padding: '0.15rem 0.4rem',
borderRadius: '4px',
backgroundColor: 'rgba(245, 158, 11, 0.1)',
color: '#f59e0b',
border: '1px solid rgba(245, 158, 11, 0.2)',
display: 'inline-flex',
alignItems: 'center',
gap: '0.25rem'
}}>
{language === 'cs' ? `Neověřená data (QN: ${latestData.qn})` : `Unverified data (QN: ${latestData.qn})`}
</span>
) : (
<span style={{
fontSize: '0.75rem',
padding: '0.15rem 0.4rem',
borderRadius: '4px',
backgroundColor: 'rgba(34, 197, 94, 0.1)',
color: 'var(--color-green)',
border: '1px solid rgba(34, 197, 94, 0.2)',
display: 'inline-flex',
alignItems: 'center',
gap: '0.25rem'
}}>
{language === 'cs' ? 'Ověřená data dispečinkem' : 'Data verified by dispatch'}
</span>
)}
</div>
<div className="kpi-grid-container">