increase header add spot timing

pull/6/head
accius 3 days ago
parent 5f29957704
commit 99c8644dbc

@ -229,8 +229,8 @@ const App = () => {
transform: `scale(${scale})`, transform: `scale(${scale})`,
transformOrigin: 'center center', transformOrigin: 'center center',
display: 'grid', display: 'grid',
gridTemplateColumns: '260px 1fr 300px', gridTemplateColumns: '270px 1fr 300px',
gridTemplateRows: '50px 1fr', gridTemplateRows: '65px 1fr',
gap: '8px', gap: '8px',
padding: '8px', padding: '8px',
overflow: 'hidden', overflow: 'hidden',
@ -255,31 +255,31 @@ const App = () => {
{/* LEFT SIDEBAR */} {/* LEFT SIDEBAR */}
<div style={{ display: 'flex', flexDirection: 'column', gap: '8px', overflowY: 'auto', overflowX: 'hidden' }}> <div style={{ display: 'flex', flexDirection: 'column', gap: '8px', overflowY: 'auto', overflowX: 'hidden' }}>
{/* DE Location */} {/* DE Location */}
<div className="panel" style={{ padding: '12px', flex: '0 0 auto' }}> <div className="panel" style={{ padding: '14px', flex: '0 0 auto' }}>
<div style={{ fontSize: '13px', color: 'var(--accent-cyan)', fontWeight: '700', marginBottom: '8px' }}>📍 DE - YOUR LOCATION</div> <div style={{ fontSize: '14px', color: 'var(--accent-cyan)', fontWeight: '700', marginBottom: '10px' }}>📍 DE - YOUR LOCATION</div>
<div style={{ fontFamily: 'JetBrains Mono', fontSize: '13px' }}> <div style={{ fontFamily: 'JetBrains Mono', fontSize: '14px' }}>
<div style={{ color: 'var(--accent-amber)', fontSize: '18px', fontWeight: '700' }}>{deGrid}</div> <div style={{ color: 'var(--accent-amber)', fontSize: '22px', fontWeight: '700', letterSpacing: '1px' }}>{deGrid}</div>
<div style={{ color: 'var(--text-secondary)', fontSize: '12px', marginTop: '2px' }}>{config.location.lat.toFixed(2)}°, {config.location.lon.toFixed(2)}°</div> <div style={{ color: 'var(--text-secondary)', fontSize: '13px', marginTop: '4px' }}>{config.location.lat.toFixed(4)}°, {config.location.lon.toFixed(4)}°</div>
<div style={{ marginTop: '6px', fontSize: '12px' }}> <div style={{ marginTop: '8px', fontSize: '13px' }}>
<span style={{ color: 'var(--text-secondary)' }}> </span> <span style={{ color: 'var(--text-secondary)' }}> </span>
<span style={{ color: 'var(--accent-amber)' }}>{deSunTimes.sunrise}</span> <span style={{ color: 'var(--accent-amber)', fontWeight: '600' }}>{deSunTimes.sunrise}</span>
<span style={{ color: 'var(--text-secondary)' }}> </span> <span style={{ color: 'var(--text-secondary)' }}> </span>
<span style={{ color: 'var(--accent-purple)' }}>{deSunTimes.sunset}</span> <span style={{ color: 'var(--accent-purple)', fontWeight: '600' }}>{deSunTimes.sunset}</span>
</div> </div>
</div> </div>
</div> </div>
{/* DX Location */} {/* DX Location */}
<div className="panel" style={{ padding: '12px', flex: '0 0 auto' }}> <div className="panel" style={{ padding: '14px', flex: '0 0 auto' }}>
<div style={{ fontSize: '13px', color: 'var(--accent-green)', fontWeight: '700', marginBottom: '8px' }}>🎯 DX - TARGET</div> <div style={{ fontSize: '14px', color: 'var(--accent-green)', fontWeight: '700', marginBottom: '10px' }}>🎯 DX - TARGET</div>
<div style={{ fontFamily: 'JetBrains Mono', fontSize: '13px' }}> <div style={{ fontFamily: 'JetBrains Mono', fontSize: '14px' }}>
<div style={{ color: 'var(--accent-amber)', fontSize: '18px', fontWeight: '700' }}>{dxGrid}</div> <div style={{ color: 'var(--accent-amber)', fontSize: '22px', fontWeight: '700', letterSpacing: '1px' }}>{dxGrid}</div>
<div style={{ color: 'var(--text-secondary)', fontSize: '12px', marginTop: '2px' }}>{dxLocation.lat.toFixed(2)}°, {dxLocation.lon.toFixed(2)}°</div> <div style={{ color: 'var(--text-secondary)', fontSize: '13px', marginTop: '4px' }}>{dxLocation.lat.toFixed(4)}°, {dxLocation.lon.toFixed(4)}°</div>
<div style={{ marginTop: '6px', fontSize: '12px' }}> <div style={{ marginTop: '8px', fontSize: '13px' }}>
<span style={{ color: 'var(--text-secondary)' }}> </span> <span style={{ color: 'var(--text-secondary)' }}> </span>
<span style={{ color: 'var(--accent-amber)' }}>{dxSunTimes.sunrise}</span> <span style={{ color: 'var(--accent-amber)', fontWeight: '600' }}>{dxSunTimes.sunrise}</span>
<span style={{ color: 'var(--text-secondary)' }}> </span> <span style={{ color: 'var(--text-secondary)' }}> </span>
<span style={{ color: 'var(--accent-purple)' }}>{dxSunTimes.sunset}</span> <span style={{ color: 'var(--accent-purple)', fontWeight: '600' }}>{dxSunTimes.sunset}</span>
</div> </div>
</div> </div>
</div> </div>

@ -1,6 +1,6 @@
/** /**
* DXFilterManager Component * DXFilterManager Component
* Filter modal with tabs for Zones, Bands, Modes, Watchlist, Exclude * Filter modal with tabs for Zones, Bands, Modes, Watchlist, Exclude, Settings
*/ */
import React, { useState } from 'react'; import React, { useState } from 'react';
@ -313,6 +313,77 @@ export const DXFilterManager = ({ filters, onFilterChange, isOpen, onClose }) =>
</div> </div>
); );
const renderSettingsTab = () => {
const retentionMinutes = filters?.spotRetentionMinutes || 30;
return (
<div>
<div style={{ marginBottom: '24px' }}>
<div style={{ fontSize: '13px', fontWeight: '600', color: 'var(--text-primary)', marginBottom: '12px' }}>
Spot Retention Time
</div>
<div style={{ fontSize: '12px', color: 'var(--text-muted)', marginBottom: '12px' }}>
How long to keep DX spots on the map before they expire. Shorter times show only the most recent activity.
</div>
<div style={{ display: 'flex', alignItems: 'center', gap: '16px' }}>
<input
type="range"
min="5"
max="30"
step="5"
value={retentionMinutes}
onChange={(e) => onFilterChange({ ...filters, spotRetentionMinutes: parseInt(e.target.value) })}
style={{ flex: 1, cursor: 'pointer' }}
/>
<div style={{
minWidth: '80px',
textAlign: 'center',
padding: '8px 12px',
background: 'var(--bg-tertiary)',
borderRadius: '4px',
fontFamily: 'JetBrains Mono',
fontSize: '14px',
fontWeight: '600',
color: 'var(--accent-cyan)'
}}>
{retentionMinutes} min
</div>
</div>
<div style={{ display: 'flex', justifyContent: 'space-between', marginTop: '8px', fontSize: '11px', color: 'var(--text-muted)' }}>
<span>5 min (freshest)</span>
<span>30 min (default)</span>
</div>
</div>
<div style={{ marginBottom: '24px' }}>
<div style={{ fontSize: '13px', fontWeight: '600', color: 'var(--text-primary)', marginBottom: '12px' }}>
Quick Presets
</div>
<div style={{ display: 'flex', gap: '8px' }}>
{[5, 10, 15, 20, 30].map(mins => (
<button
key={mins}
onClick={() => onFilterChange({ ...filters, spotRetentionMinutes: mins })}
style={{
padding: '8px 16px',
background: retentionMinutes === mins ? 'rgba(0, 221, 255, 0.2)' : 'var(--bg-tertiary)',
border: `1px solid ${retentionMinutes === mins ? 'var(--accent-cyan)' : 'var(--border-color)'}`,
borderRadius: '4px',
color: retentionMinutes === mins ? 'var(--accent-cyan)' : 'var(--text-secondary)',
fontSize: '13px',
cursor: 'pointer',
fontFamily: 'JetBrains Mono'
}}
>
{mins} min
</button>
))}
</div>
</div>
</div>
);
};
return ( return (
<div style={{ <div style={{
position: 'fixed', position: 'fixed',
@ -391,6 +462,7 @@ export const DXFilterManager = ({ filters, onFilterChange, isOpen, onClose }) =>
<button onClick={() => setActiveTab('modes')} style={tabStyle(activeTab === 'modes')}>Modes</button> <button onClick={() => setActiveTab('modes')} style={tabStyle(activeTab === 'modes')}>Modes</button>
<button onClick={() => setActiveTab('watchlist')} style={tabStyle(activeTab === 'watchlist')}>Watchlist</button> <button onClick={() => setActiveTab('watchlist')} style={tabStyle(activeTab === 'watchlist')}>Watchlist</button>
<button onClick={() => setActiveTab('exclude')} style={tabStyle(activeTab === 'exclude')}>Exclude</button> <button onClick={() => setActiveTab('exclude')} style={tabStyle(activeTab === 'exclude')}>Exclude</button>
<button onClick={() => setActiveTab('settings')} style={tabStyle(activeTab === 'settings')}> Settings</button>
</div> </div>
{/* Tab Content */} {/* Tab Content */}
@ -400,6 +472,7 @@ export const DXFilterManager = ({ filters, onFilterChange, isOpen, onClose }) =>
{activeTab === 'modes' && renderModesTab()} {activeTab === 'modes' && renderModesTab()}
{activeTab === 'watchlist' && renderWatchlistTab()} {activeTab === 'watchlist' && renderWatchlistTab()}
{activeTab === 'exclude' && renderExcludeTab()} {activeTab === 'exclude' && renderExcludeTab()}
{activeTab === 'settings' && renderSettingsTab()}
</div> </div>
</div> </div>
</div> </div>

@ -27,13 +27,14 @@ export const Header = ({
background: 'var(--bg-panel)', background: 'var(--bg-panel)',
border: '1px solid var(--border-color)', border: '1px solid var(--border-color)',
borderRadius: '6px', borderRadius: '6px',
padding: '0 16px', padding: '8px 20px',
minHeight: '60px',
fontFamily: 'JetBrains Mono, monospace' fontFamily: 'JetBrains Mono, monospace'
}}> }}>
{/* Callsign & Settings */} {/* Callsign & Settings */}
<div style={{ display: 'flex', alignItems: 'center', gap: '16px' }}> <div style={{ display: 'flex', alignItems: 'center', gap: '16px' }}>
<span <span
style={{ fontSize: '20px', fontWeight: '900', color: 'var(--accent-amber)', cursor: 'pointer', fontFamily: 'Orbitron, monospace' }} style={{ fontSize: '24px', fontWeight: '900', color: 'var(--accent-amber)', cursor: 'pointer', fontFamily: 'Orbitron, monospace' }}
onClick={onSettingsClick} onClick={onSettingsClick}
title="Click for settings" title="Click for settings"
> >
@ -43,25 +44,25 @@ export const Header = ({
</div> </div>
{/* UTC Clock */} {/* UTC Clock */}
<div style={{ display: 'flex', alignItems: 'center', gap: '8px' }}> <div style={{ display: 'flex', alignItems: 'center', gap: '10px' }}>
<span style={{ fontSize: '12px', color: 'var(--accent-cyan)' }}>UTC</span> <span style={{ fontSize: '14px', color: 'var(--accent-cyan)', fontWeight: '600' }}>UTC</span>
<span style={{ fontSize: '22px', fontWeight: '700', color: 'var(--accent-cyan)', fontFamily: 'Orbitron, monospace' }}>{utcTime}</span> <span style={{ fontSize: '28px', fontWeight: '700', color: 'var(--accent-cyan)', fontFamily: 'Orbitron, monospace' }}>{utcTime}</span>
<span style={{ fontSize: '12px', color: 'var(--text-muted)' }}>{utcDate}</span> <span style={{ fontSize: '13px', color: 'var(--text-muted)' }}>{utcDate}</span>
</div> </div>
{/* Local Clock - Clickable to toggle 12/24 hour format */} {/* Local Clock - Clickable to toggle 12/24 hour format */}
<div <div
style={{ display: 'flex', alignItems: 'center', gap: '8px', cursor: 'pointer' }} style={{ display: 'flex', alignItems: 'center', gap: '10px', cursor: 'pointer' }}
onClick={onTimeFormatToggle} onClick={onTimeFormatToggle}
title={`Click to switch to ${use12Hour ? '24-hour' : '12-hour'} format`} title={`Click to switch to ${use12Hour ? '24-hour' : '12-hour'} format`}
> >
<span style={{ fontSize: '12px', color: 'var(--accent-amber)' }}>LOCAL</span> <span style={{ fontSize: '14px', color: 'var(--accent-amber)', fontWeight: '600' }}>LOCAL</span>
<span style={{ fontSize: '22px', fontWeight: '700', color: 'var(--accent-amber)', fontFamily: 'Orbitron, monospace' }}>{localTime}</span> <span style={{ fontSize: '28px', fontWeight: '700', color: 'var(--accent-amber)', fontFamily: 'Orbitron, monospace' }}>{localTime}</span>
<span style={{ fontSize: '12px', color: 'var(--text-muted)' }}>{localDate}</span> <span style={{ fontSize: '13px', color: 'var(--text-muted)' }}>{localDate}</span>
</div> </div>
{/* Weather & Solar Stats */} {/* Weather & Solar Stats */}
<div style={{ display: 'flex', gap: '16px', fontSize: '13px' }}> <div style={{ display: 'flex', gap: '20px', fontSize: '14px' }}>
{localWeather?.data && ( {localWeather?.data && (
<div title={`${localWeather.data.description} • Wind: ${localWeather.data.windSpeed} mph`}> <div title={`${localWeather.data.description} • Wind: ${localWeather.data.windSpeed} mph`}>
<span style={{ marginRight: '4px' }}>{localWeather.data.icon}</span> <span style={{ marginRight: '4px' }}>{localWeather.data.icon}</span>
@ -72,17 +73,17 @@ export const Header = ({
)} )}
<div> <div>
<span style={{ color: 'var(--text-muted)' }}>SFI </span> <span style={{ color: 'var(--text-muted)' }}>SFI </span>
<span style={{ color: 'var(--accent-amber)', fontWeight: '600' }}>{spaceWeather?.data?.solarFlux || '--'}</span> <span style={{ color: 'var(--accent-amber)', fontWeight: '700', fontSize: '16px' }}>{spaceWeather?.data?.solarFlux || '--'}</span>
</div> </div>
<div> <div>
<span style={{ color: 'var(--text-muted)' }}>K </span> <span style={{ color: 'var(--text-muted)' }}>K </span>
<span style={{ color: parseInt(spaceWeather?.data?.kIndex) >= 4 ? 'var(--accent-red)' : 'var(--accent-green)', fontWeight: '600' }}> <span style={{ color: parseInt(spaceWeather?.data?.kIndex) >= 4 ? 'var(--accent-red)' : 'var(--accent-green)', fontWeight: '700', fontSize: '16px' }}>
{spaceWeather?.data?.kIndex ?? '--'} {spaceWeather?.data?.kIndex ?? '--'}
</span> </span>
</div> </div>
<div> <div>
<span style={{ color: 'var(--text-muted)' }}>SSN </span> <span style={{ color: 'var(--text-muted)' }}>SSN </span>
<span style={{ color: 'var(--accent-cyan)', fontWeight: '600' }}>{spaceWeather?.data?.sunspotNumber || '--'}</span> <span style={{ color: 'var(--accent-cyan)', fontWeight: '700', fontSize: '16px' }}>{spaceWeather?.data?.sunspotNumber || '--'}</span>
</div> </div>
</div> </div>
@ -95,7 +96,7 @@ export const Header = ({
style={{ style={{
background: 'linear-gradient(135deg, #ff813f 0%, #ffdd00 100%)', background: 'linear-gradient(135deg, #ff813f 0%, #ffdd00 100%)',
border: 'none', border: 'none',
padding: '6px 12px', padding: '8px 14px',
borderRadius: '4px', borderRadius: '4px',
color: '#000', color: '#000',
fontSize: '13px', fontSize: '13px',
@ -115,7 +116,7 @@ export const Header = ({
style={{ style={{
background: 'var(--bg-tertiary)', background: 'var(--bg-tertiary)',
border: '1px solid var(--border-color)', border: '1px solid var(--border-color)',
padding: '6px 12px', padding: '8px 14px',
borderRadius: '4px', borderRadius: '4px',
color: 'var(--text-secondary)', color: 'var(--text-secondary)',
fontSize: '13px', fontSize: '13px',
@ -129,7 +130,7 @@ export const Header = ({
style={{ style={{
background: isFullscreen ? 'rgba(0, 255, 136, 0.15)' : 'var(--bg-tertiary)', background: isFullscreen ? 'rgba(0, 255, 136, 0.15)' : 'var(--bg-tertiary)',
border: `1px solid ${isFullscreen ? 'var(--accent-green)' : 'var(--border-color)'}`, border: `1px solid ${isFullscreen ? 'var(--accent-green)' : 'var(--border-color)'}`,
padding: '6px 12px', padding: '8px 14px',
borderRadius: '4px', borderRadius: '4px',
color: isFullscreen ? 'var(--accent-green)' : 'var(--text-secondary)', color: isFullscreen ? 'var(--accent-green)' : 'var(--text-secondary)',
fontSize: '13px', fontSize: '13px',

@ -10,7 +10,9 @@ export const useDXCluster = (source = 'auto', filters = {}) => {
const [data, setData] = useState([]); // Filtered spots for display const [data, setData] = useState([]); // Filtered spots for display
const [loading, setLoading] = useState(true); const [loading, setLoading] = useState(true);
const [activeSource, setActiveSource] = useState(''); const [activeSource, setActiveSource] = useState('');
const spotRetentionMs = 30 * 60 * 1000; // 30 minutes
// Get retention time from filters, default to 30 minutes
const spotRetentionMs = (filters?.spotRetentionMinutes || 30) * 60 * 1000;
const pollInterval = 5000; // 5 seconds const pollInterval = 5000; // 5 seconds
// Apply filters to spots // Apply filters to spots
@ -126,7 +128,15 @@ export const useDXCluster = (source = 'auto', filters = {}) => {
fetchData(); fetchData();
const interval = setInterval(fetchData, pollInterval); const interval = setInterval(fetchData, pollInterval);
return () => clearInterval(interval); return () => clearInterval(interval);
}, [source]); }, [source, spotRetentionMs]);
// Clean up spots immediately when retention time changes
useEffect(() => {
setAllSpots(prev => {
const now = Date.now();
return prev.filter(s => (now - (s.timestamp || now)) < spotRetentionMs);
});
}, [spotRetentionMs]);
// Apply filters whenever allSpots or filters change // Apply filters whenever allSpots or filters change
useEffect(() => { useEffect(() => {

Loading…
Cancel
Save

Powered by TurnKey Linux.