diff --git a/client/src/App.css b/client/src/App.css
index 23cd564..852971a 100644
--- a/client/src/App.css
+++ b/client/src/App.css
@@ -6421,3 +6421,44 @@ body.app-tour-active .feedback-modal-overlay--tour .disclaimer-modal-panel {
color: #e2e8f0;
word-break: break-word;
}
+
+/* Accordion Styling */
+.accordion-header {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ cursor: pointer;
+ user-select: none;
+ padding: 8px 12px;
+ margin: -8px -12px;
+ border-radius: 8px;
+ transition: background-color 0.2s ease, color 0.2s ease;
+}
+
+.accordion-header:hover {
+ background-color: var(--app-surface-hover, rgba(255, 255, 255, 0.03));
+}
+
+.accordion-header-title {
+ display: flex;
+ align-items: center;
+ gap: 8px;
+}
+
+.accordion-chevron {
+ color: var(--app-text-muted, #94a3b8);
+ transition: transform 0.2s ease;
+}
+
+/* Specific styling for nested member-editor-card header */
+.member-editor-card .accordion-header {
+ margin: 0 0 16px 0;
+ padding: 8px 12px;
+ border-radius: 6px;
+ background: rgba(255, 255, 255, 0.01);
+ border: 1px solid rgba(255, 255, 255, 0.03);
+}
+
+.member-editor-card .accordion-header:hover {
+ background: var(--app-surface-hover, rgba(255, 255, 255, 0.03));
+}
diff --git a/client/src/components/LogEntryEditor.tsx b/client/src/components/LogEntryEditor.tsx
index c960258..e4939a4 100644
--- a/client/src/components/LogEntryEditor.tsx
+++ b/client/src/components/LogEntryEditor.tsx
@@ -296,6 +296,9 @@ export default function LogEntryEditor({
const [evLocationName, setEvLocationName] = useState('')
const [activeCourseTab, setActiveCourseTab] = useState<'mgk' | 'rwk'>('mgk')
+ const [eventsCollapsed, setEventsCollapsed] = useState(true)
+ const [addEventFormCollapsed, setAddEventFormCollapsed] = useState(false)
+
const [loading, setLoading] = useState(false)
const [saving, setSaving] = useState(false)
const [exporting, setExporting] = useState(false)
@@ -1407,6 +1410,7 @@ export default function LogEntryEditor({
if (!ev) return
fillEventForm(ev)
setEditingEventIndex(index)
+ setAddEventFormCollapsed(false)
}
const handleCancelEventEdit = () => {
@@ -1853,78 +1857,153 @@ export default function LogEntryEditor({
{/* Section 3: Event Journal Entries */}
-
-
-
{t('logs.event_title')}
+
setEventsCollapsed(!eventsCollapsed)}
+ onKeyDown={(e) => {
+ if (e.key === 'Enter' || e.key === ' ') {
+ e.preventDefault()
+ setEventsCollapsed(!eventsCollapsed)
+ }
+ }}
+ role="button"
+ aria-expanded={!eventsCollapsed}
+ tabIndex={0}
+ >
+
+
+
{t('logs.event_title')}
+
+ {eventsCollapsed ? (
+
+ ) : (
+
+ )}
{/* List existing events */}
- {events.length === 0 ? (
-
{t('logs.no_events')}
- ) : (
- <>
- {/* Desktop view */}
-
-
-
-
- | {t('logs.event_time')} |
- {t('logs.event_creator')} |
- {t('logs.event_mgk')} |
- {t('logs.event_rwk')} |
- {t('logs.event_wind_direction')} |
- {t('logs.event_wind_strength')} |
- {t('logs.event_sea_state')} |
- {t('logs.event_weather')} |
- {t('logs.event_log')} |
- {t('logs.event_gps')} |
- {t('logs.event_remarks')} |
- {!readOnly && | }
-
-
-
- {events.map((ev, idx) => (
-
- | {ev.time} |
-
-
- |
- {ev.mgk ? `${ev.mgk}°` : '—'} |
- {ev.rwk ? `${ev.rwk}°` : '—'} |
- {ev.windDirection || '—'} |
- {ev.windStrength || '—'} |
- {ev.seaState || '—'} |
-
- {ev.weatherIcon ? (
- {t('logs.no_events')}
+ ) : (
+ <>
+ {/* Desktop view */}
+
+
+
+
+ | {t('logs.event_time')} |
+ {t('logs.event_creator')} |
+ {t('logs.event_mgk')} |
+ {t('logs.event_rwk')} |
+ {t('logs.event_wind_direction')} |
+ {t('logs.event_wind_strength')} |
+ {t('logs.event_sea_state')} |
+ {t('logs.event_weather')} |
+ {t('logs.event_log')} |
+ {t('logs.event_gps')} |
+ {t('logs.event_remarks')} |
+ {!readOnly && | }
+
+
+
+ {events.map((ev, idx) => (
+
+ | {ev.time} |
+
+
- ) : (
- '—'
+ |
+ {ev.mgk ? `${ev.mgk}°` : '—'} |
+ {ev.rwk ? `${ev.rwk}°` : '—'} |
+ {ev.windDirection || '—'} |
+ {ev.windStrength || '—'} |
+ {ev.seaState || '—'} |
+
+ {ev.weatherIcon ? (
+
+ ) : (
+ '—'
+ )}
+ |
+ {ev.logReading ? `${ev.logReading} nm` : '—'} |
+
+ {ev.gpsLat && ev.gpsLng ? `${ev.gpsLat}, ${ev.gpsLng}` : '—'}
+ |
+
+
+ |
+ {!readOnly && (
+
+
+
+
+
+ |
)}
-
- {ev.logReading ? `${ev.logReading} nm` : '—'} |
-
- {ev.gpsLat && ev.gpsLng ? `${ev.gpsLat}, ${ev.gpsLng}` : '—'}
- |
-
-
- |
- {!readOnly && (
-
-
+ |
+ ))}
+
+
+
+
+ {/* Mobile view */}
+
+ {events.map((ev, idx) => {
+ const hasCourse = ev.mgk || ev.rwk;
+ const hasWind = ev.windDirection || ev.windStrength || ev.windPressure;
+ const hasSeaState = ev.seaState;
+ const hasWeather = ev.weatherIcon;
+ const hasLog = ev.logReading;
+ const hasGps = ev.gpsLat && ev.gpsLng;
+ const hasVisibility = ev.visibility;
+ const hasHeel = ev.heel;
+ const hasSailsOrMotor = ev.sailsOrMotor;
+
+ return (
+ |
- )}
-
- ))}
-
-
-
+ )}
+
- {/* Mobile view */}
-
- {events.map((ev, idx) => {
- const hasCourse = ev.mgk || ev.rwk;
- const hasWind = ev.windDirection || ev.windStrength || ev.windPressure;
- const hasSeaState = ev.seaState;
- const hasWeather = ev.weatherIcon;
- const hasLog = ev.logReading;
- const hasGps = ev.gpsLat && ev.gpsLng;
- const hasVisibility = ev.visibility;
- const hasHeel = ev.heel;
- const hasSailsOrMotor = ev.sailsOrMotor;
+
- return (
-
-
-
-
-
- {ev.time}
-
-
+ {hasCourse && (
+
+
+
+ {ev.mgk ? `MgK: ${ev.mgk}°` : ''}
+ {ev.mgk && ev.rwk ? ' / ' : ''}
+ {ev.rwk ? `rwK: ${ev.rwk}°` : ''}
+
+
+ )}
+
+ {hasWind && (
+
+
+ Wind:{' '}
+ {[
+ ev.windDirection,
+ ev.windStrength ? `${ev.windStrength} Bft` : '',
+ ev.windPressure ? `${ev.windPressure} hPa` : ''
+ ]
+ .filter(Boolean)
+ .join(' / ')}
+
+
+ )}
+
+ {hasSeaState && (
+
+ {t('logs.event_sea_state')}: {ev.seaState}
+
+ )}
+
+ {hasWeather && (
+
+
+
+ )}
+
+ {hasLog && (
+
+ Log: {ev.logReading} nm
+
+ )}
+
+ {hasGps && (
+
+
+ {ev.gpsLat}, {ev.gpsLng}
+
+ )}
+
+ {hasVisibility && (
+
+ {t('logs.event_visibility')}: {ev.visibility}
+
+ )}
+
+ {hasHeel && (
+
+ {t('logs.event_heel')}: {ev.heel}°
+
+ )}
+
+ {hasSailsOrMotor && (
+
+ {ev.sailsOrMotor}
+
+ )}
+
+
+
+
- {!readOnly && (
-
-
-
-
- )}
-
-
-
-
- {hasCourse && (
-
-
-
- {ev.mgk ? `MgK: ${ev.mgk}°` : ''}
- {ev.mgk && ev.rwk ? ' / ' : ''}
- {ev.rwk ? `rwK: ${ev.rwk}°` : ''}
-
-
- )}
-
- {hasWind && (
-
-
- Wind:{' '}
- {[
- ev.windDirection,
- ev.windStrength ? `${ev.windStrength} Bft` : '',
- ev.windPressure ? `${ev.windPressure} hPa` : ''
- ]
- .filter(Boolean)
- .join(' / ')}
-
-
- )}
-
- {hasSeaState && (
-
- {t('logs.event_sea_state')}: {ev.seaState}
-
- )}
-
- {hasWeather && (
-
-
-
- )}
-
- {hasLog && (
-
- Log: {ev.logReading} nm
-
- )}
-
- {hasGps && (
-
-
- {ev.gpsLat}, {ev.gpsLng}
-
- )}
-
- {hasVisibility && (
-
- {t('logs.event_visibility')}: {ev.visibility}
-
- )}
-
- {hasHeel && (
-
- {t('logs.event_heel')}: {ev.heel}°
-
- )}
-
- {hasSailsOrMotor && (
-
- {ev.sailsOrMotor}
-
- )}
-
-
-
-
-
-
- );
- })}
-
- >
+ );
+ })}
+
+ >
+ )
)}
{/* Add New Event Form Sub-Card */}
{!readOnly && (
-
- {editingEventIndex !== null ? t('logs.edit_event') : t('logs.add_event')}
-
+
setAddEventFormCollapsed(!addEventFormCollapsed)}
+ onKeyDown={(e) => {
+ if (e.key === 'Enter' || e.key === ' ') {
+ e.preventDefault()
+ setAddEventFormCollapsed(!addEventFormCollapsed)
+ }
+ }}
+ role="button"
+ aria-expanded={!addEventFormCollapsed}
+ tabIndex={0}
+ style={{
+ margin: '0 0 16px 0',
+ padding: '8px 12px',
+ borderRadius: '6px',
+ background: 'rgba(255, 255, 255, 0.01)',
+ border: '1px solid rgba(255, 255, 255, 0.03)'
+ }}
+ >
+
+ {editingEventIndex !== null ? t('logs.edit_event') : t('logs.add_event')}
+
+ {addEventFormCollapsed ? (
+
+ ) : (
+
+ )}
+
-
+ {!addEventFormCollapsed && (
+ <>
+
+ >
+ )}
)}