feat: implement collapsible accordions for event protocol list and form
This commit is contained in:
@@ -6421,3 +6421,44 @@ body.app-tour-active .feedback-modal-overlay--tour .disclaimer-modal-panel {
|
|||||||
color: #e2e8f0;
|
color: #e2e8f0;
|
||||||
word-break: break-word;
|
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));
|
||||||
|
}
|
||||||
|
|||||||
@@ -296,6 +296,9 @@ export default function LogEntryEditor({
|
|||||||
const [evLocationName, setEvLocationName] = useState('')
|
const [evLocationName, setEvLocationName] = useState('')
|
||||||
const [activeCourseTab, setActiveCourseTab] = useState<'mgk' | 'rwk'>('mgk')
|
const [activeCourseTab, setActiveCourseTab] = useState<'mgk' | 'rwk'>('mgk')
|
||||||
|
|
||||||
|
const [eventsCollapsed, setEventsCollapsed] = useState(true)
|
||||||
|
const [addEventFormCollapsed, setAddEventFormCollapsed] = useState(false)
|
||||||
|
|
||||||
const [loading, setLoading] = useState(false)
|
const [loading, setLoading] = useState(false)
|
||||||
const [saving, setSaving] = useState(false)
|
const [saving, setSaving] = useState(false)
|
||||||
const [exporting, setExporting] = useState(false)
|
const [exporting, setExporting] = useState(false)
|
||||||
@@ -1407,6 +1410,7 @@ export default function LogEntryEditor({
|
|||||||
if (!ev) return
|
if (!ev) return
|
||||||
fillEventForm(ev)
|
fillEventForm(ev)
|
||||||
setEditingEventIndex(index)
|
setEditingEventIndex(index)
|
||||||
|
setAddEventFormCollapsed(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleCancelEventEdit = () => {
|
const handleCancelEventEdit = () => {
|
||||||
@@ -1853,78 +1857,153 @@ export default function LogEntryEditor({
|
|||||||
|
|
||||||
{/* Section 3: Event Journal Entries */}
|
{/* Section 3: Event Journal Entries */}
|
||||||
<div className="form-card">
|
<div className="form-card">
|
||||||
<div className="form-header mb-4">
|
<div
|
||||||
<Compass size={20} className="form-icon" />
|
className="form-header mb-4 accordion-header"
|
||||||
<h3>{t('logs.event_title')}</h3>
|
onClick={() => setEventsCollapsed(!eventsCollapsed)}
|
||||||
|
onKeyDown={(e) => {
|
||||||
|
if (e.key === 'Enter' || e.key === ' ') {
|
||||||
|
e.preventDefault()
|
||||||
|
setEventsCollapsed(!eventsCollapsed)
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
role="button"
|
||||||
|
aria-expanded={!eventsCollapsed}
|
||||||
|
tabIndex={0}
|
||||||
|
>
|
||||||
|
<div className="accordion-header-title">
|
||||||
|
<Compass size={20} className="form-icon" />
|
||||||
|
<h3>{t('logs.event_title')}</h3>
|
||||||
|
</div>
|
||||||
|
{eventsCollapsed ? (
|
||||||
|
<ChevronDown size={20} className="accordion-chevron" />
|
||||||
|
) : (
|
||||||
|
<ChevronUp size={20} className="accordion-chevron" />
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* List existing events */}
|
{/* List existing events */}
|
||||||
{events.length === 0 ? (
|
{!eventsCollapsed && (
|
||||||
<div className="dashboard-status-msg mb-6">{t('logs.no_events')}</div>
|
events.length === 0 ? (
|
||||||
) : (
|
<div className="dashboard-status-msg mb-6">{t('logs.no_events')}</div>
|
||||||
<>
|
) : (
|
||||||
{/* Desktop view */}
|
<>
|
||||||
<div className="events-scroll-container mb-6 events-desktop-only">
|
{/* Desktop view */}
|
||||||
<table className="events-table">
|
<div className="events-scroll-container mb-6 events-desktop-only">
|
||||||
<thead>
|
<table className="events-table">
|
||||||
<tr>
|
<thead>
|
||||||
<th>{t('logs.event_time')}</th>
|
<tr>
|
||||||
<th>{t('logs.event_creator')}</th>
|
<th>{t('logs.event_time')}</th>
|
||||||
<th>{t('logs.event_mgk')}</th>
|
<th>{t('logs.event_creator')}</th>
|
||||||
<th>{t('logs.event_rwk')}</th>
|
<th>{t('logs.event_mgk')}</th>
|
||||||
<th>{t('logs.event_wind_direction')}</th>
|
<th>{t('logs.event_rwk')}</th>
|
||||||
<th>{t('logs.event_wind_strength')}</th>
|
<th>{t('logs.event_wind_direction')}</th>
|
||||||
<th>{t('logs.event_sea_state')}</th>
|
<th>{t('logs.event_wind_strength')}</th>
|
||||||
<th>{t('logs.event_weather')}</th>
|
<th>{t('logs.event_sea_state')}</th>
|
||||||
<th>{t('logs.event_log')}</th>
|
<th>{t('logs.event_weather')}</th>
|
||||||
<th>{t('logs.event_gps')}</th>
|
<th>{t('logs.event_log')}</th>
|
||||||
<th>{t('logs.event_remarks')}</th>
|
<th>{t('logs.event_gps')}</th>
|
||||||
{!readOnly && <th></th>}
|
<th>{t('logs.event_remarks')}</th>
|
||||||
</tr>
|
{!readOnly && <th></th>}
|
||||||
</thead>
|
</tr>
|
||||||
<tbody>
|
</thead>
|
||||||
{events.map((ev, idx) => (
|
<tbody>
|
||||||
<tr key={idx}>
|
{events.map((ev, idx) => (
|
||||||
<td className="font-mono">{ev.time}</td>
|
<tr key={idx}>
|
||||||
<td style={{ textAlign: 'center', width: '40px', verticalAlign: 'middle' }}>
|
<td className="font-mono">{ev.time}</td>
|
||||||
<CreatorAvatar
|
<td style={{ textAlign: 'center', width: '40px', verticalAlign: 'middle' }}>
|
||||||
creatorId={ev.creatorId}
|
<CreatorAvatar
|
||||||
crewSnapshotsById={entryCrew.crewSnapshotsById}
|
creatorId={ev.creatorId}
|
||||||
size={24}
|
crewSnapshotsById={entryCrew.crewSnapshotsById}
|
||||||
/>
|
size={24}
|
||||||
</td>
|
|
||||||
<td>{ev.mgk ? `${ev.mgk}°` : '—'}</td>
|
|
||||||
<td>{ev.rwk ? `${ev.rwk}°` : '—'}</td>
|
|
||||||
<td>{ev.windDirection || '—'}</td>
|
|
||||||
<td>{ev.windStrength || '—'}</td>
|
|
||||||
<td>{ev.seaState || '—'}</td>
|
|
||||||
<td>
|
|
||||||
{ev.weatherIcon ? (
|
|
||||||
<img
|
|
||||||
src={`https://openweathermap.org/img/wn/${ev.weatherIcon}.png`}
|
|
||||||
alt="Weather"
|
|
||||||
title="Weather Icon"
|
|
||||||
className="table-weather-img"
|
|
||||||
/>
|
/>
|
||||||
) : (
|
</td>
|
||||||
'—'
|
<td>{ev.mgk ? `${ev.mgk}°` : '—'}</td>
|
||||||
|
<td>{ev.rwk ? `${ev.rwk}°` : '—'}</td>
|
||||||
|
<td>{ev.windDirection || '—'}</td>
|
||||||
|
<td>{ev.windStrength || '—'}</td>
|
||||||
|
<td>{ev.seaState || '—'}</td>
|
||||||
|
<td>
|
||||||
|
{ev.weatherIcon ? (
|
||||||
|
<img
|
||||||
|
src={`https://openweathermap.org/img/wn/${ev.weatherIcon}.png`}
|
||||||
|
alt="Weather"
|
||||||
|
title="Weather Icon"
|
||||||
|
className="table-weather-img"
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
'—'
|
||||||
|
)}
|
||||||
|
</td>
|
||||||
|
<td>{ev.logReading ? `${ev.logReading} nm` : '—'}</td>
|
||||||
|
<td className="font-mono text-sm">
|
||||||
|
{ev.gpsLat && ev.gpsLng ? `${ev.gpsLat}, ${ev.gpsLng}` : '—'}
|
||||||
|
</td>
|
||||||
|
<td className="remarks-td">
|
||||||
|
<EventRemarksCell
|
||||||
|
event={ev}
|
||||||
|
logbookId={logbookId}
|
||||||
|
voiceMemoLookup={voiceMemoLookup}
|
||||||
|
readOnly={readOnly}
|
||||||
|
/>
|
||||||
|
</td>
|
||||||
|
{!readOnly && (
|
||||||
|
<td className="events-actions-td">
|
||||||
|
<div className="events-actions-cell">
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
className="btn-icon"
|
||||||
|
onClick={() => handleEditEvent(idx)}
|
||||||
|
title={t('logs.edit_event')}
|
||||||
|
disabled={editingEventIndex !== null && editingEventIndex !== idx}
|
||||||
|
>
|
||||||
|
<Pencil size={14} />
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
className="btn-icon danger"
|
||||||
|
onClick={() => handleDeleteEvent(idx)}
|
||||||
|
title={t('logs.delete_event')}
|
||||||
|
>
|
||||||
|
<Trash2 size={14} />
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
)}
|
)}
|
||||||
</td>
|
</tr>
|
||||||
<td>{ev.logReading ? `${ev.logReading} nm` : '—'}</td>
|
))}
|
||||||
<td className="font-mono text-sm">
|
</tbody>
|
||||||
{ev.gpsLat && ev.gpsLng ? `${ev.gpsLat}, ${ev.gpsLng}` : '—'}
|
</table>
|
||||||
</td>
|
</div>
|
||||||
<td className="remarks-td">
|
|
||||||
<EventRemarksCell
|
{/* Mobile view */}
|
||||||
event={ev}
|
<div className="events-mobile-only mb-6">
|
||||||
logbookId={logbookId}
|
{events.map((ev, idx) => {
|
||||||
voiceMemoLookup={voiceMemoLookup}
|
const hasCourse = ev.mgk || ev.rwk;
|
||||||
readOnly={readOnly}
|
const hasWind = ev.windDirection || ev.windStrength || ev.windPressure;
|
||||||
/>
|
const hasSeaState = ev.seaState;
|
||||||
</td>
|
const hasWeather = ev.weatherIcon;
|
||||||
{!readOnly && (
|
const hasLog = ev.logReading;
|
||||||
<td className="events-actions-td">
|
const hasGps = ev.gpsLat && ev.gpsLng;
|
||||||
<div className="events-actions-cell">
|
const hasVisibility = ev.visibility;
|
||||||
|
const hasHeel = ev.heel;
|
||||||
|
const hasSailsOrMotor = ev.sailsOrMotor;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="event-mobile-card" key={idx}>
|
||||||
|
<div className="event-card-header">
|
||||||
|
<div className="event-card-meta">
|
||||||
|
<div className="event-card-time">
|
||||||
|
<Clock size={14} />
|
||||||
|
<span>{ev.time}</span>
|
||||||
|
</div>
|
||||||
|
<CreatorAvatar
|
||||||
|
creatorId={ev.creatorId}
|
||||||
|
crewSnapshotsById={entryCrew.crewSnapshotsById}
|
||||||
|
size={24}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
{!readOnly && (
|
||||||
|
<div className="event-card-actions">
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
className="btn-icon"
|
className="btn-icon"
|
||||||
@@ -1943,164 +2022,138 @@ export default function LogEntryEditor({
|
|||||||
<Trash2 size={14} />
|
<Trash2 size={14} />
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</td>
|
)}
|
||||||
)}
|
</div>
|
||||||
</tr>
|
|
||||||
))}
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Mobile view */}
|
<hr className="event-card-divider" />
|
||||||
<div className="events-mobile-only mb-6">
|
|
||||||
{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 (
|
<div className="event-card-grid">
|
||||||
<div className="event-mobile-card" key={idx}>
|
{hasCourse && (
|
||||||
<div className="event-card-header">
|
<span className="event-card-chip" title={t('logs.event_course_section')}>
|
||||||
<div className="event-card-meta">
|
<Compass size={12} />
|
||||||
<div className="event-card-time">
|
<span>
|
||||||
<Clock size={14} />
|
{ev.mgk ? `MgK: ${ev.mgk}°` : ''}
|
||||||
<span>{ev.time}</span>
|
{ev.mgk && ev.rwk ? ' / ' : ''}
|
||||||
</div>
|
{ev.rwk ? `rwK: ${ev.rwk}°` : ''}
|
||||||
<CreatorAvatar
|
</span>
|
||||||
creatorId={ev.creatorId}
|
</span>
|
||||||
crewSnapshotsById={entryCrew.crewSnapshotsById}
|
)}
|
||||||
size={24}
|
|
||||||
|
{hasWind && (
|
||||||
|
<span className="event-card-chip" title={t('logs.event_wind_direction')}>
|
||||||
|
<span>
|
||||||
|
Wind:{' '}
|
||||||
|
{[
|
||||||
|
ev.windDirection,
|
||||||
|
ev.windStrength ? `${ev.windStrength} Bft` : '',
|
||||||
|
ev.windPressure ? `${ev.windPressure} hPa` : ''
|
||||||
|
]
|
||||||
|
.filter(Boolean)
|
||||||
|
.join(' / ')}
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{hasSeaState && (
|
||||||
|
<span className="event-card-chip" title={t('logs.event_sea_state')}>
|
||||||
|
<span>{t('logs.event_sea_state')}: {ev.seaState}</span>
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{hasWeather && (
|
||||||
|
<span className="event-card-chip" title={t('logs.event_weather')}>
|
||||||
|
<img
|
||||||
|
src={`https://openweathermap.org/img/wn/${ev.weatherIcon}.png`}
|
||||||
|
alt="Weather"
|
||||||
|
className="event-card-weather-img"
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{hasLog && (
|
||||||
|
<span className="event-card-chip" title={t('logs.event_log')}>
|
||||||
|
<span>Log: {ev.logReading} nm</span>
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{hasGps && (
|
||||||
|
<span className="event-card-chip" title={t('logs.event_gps')}>
|
||||||
|
<MapPin size={12} />
|
||||||
|
<span className="font-mono text-xs">{ev.gpsLat}, {ev.gpsLng}</span>
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{hasVisibility && (
|
||||||
|
<span className="event-card-chip" title={t('logs.event_visibility')}>
|
||||||
|
<span>{t('logs.event_visibility')}: {ev.visibility}</span>
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{hasHeel && (
|
||||||
|
<span className="event-card-chip" title={t('logs.event_heel')}>
|
||||||
|
<span>{t('logs.event_heel')}: {ev.heel}°</span>
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{hasSailsOrMotor && (
|
||||||
|
<span className="event-card-chip" title={t('logs.event_sails')}>
|
||||||
|
<span>{ev.sailsOrMotor}</span>
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="event-card-remarks">
|
||||||
|
<EventRemarksCell
|
||||||
|
event={ev}
|
||||||
|
logbookId={logbookId}
|
||||||
|
voiceMemoLookup={voiceMemoLookup}
|
||||||
|
readOnly={readOnly}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
{!readOnly && (
|
|
||||||
<div className="event-card-actions">
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
className="btn-icon"
|
|
||||||
onClick={() => handleEditEvent(idx)}
|
|
||||||
title={t('logs.edit_event')}
|
|
||||||
disabled={editingEventIndex !== null && editingEventIndex !== idx}
|
|
||||||
>
|
|
||||||
<Pencil size={14} />
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
className="btn-icon danger"
|
|
||||||
onClick={() => handleDeleteEvent(idx)}
|
|
||||||
title={t('logs.delete_event')}
|
|
||||||
>
|
|
||||||
<Trash2 size={14} />
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
|
);
|
||||||
<hr className="event-card-divider" />
|
})}
|
||||||
|
</div>
|
||||||
<div className="event-card-grid">
|
</>
|
||||||
{hasCourse && (
|
)
|
||||||
<span className="event-card-chip" title={t('logs.event_course_section')}>
|
|
||||||
<Compass size={12} />
|
|
||||||
<span>
|
|
||||||
{ev.mgk ? `MgK: ${ev.mgk}°` : ''}
|
|
||||||
{ev.mgk && ev.rwk ? ' / ' : ''}
|
|
||||||
{ev.rwk ? `rwK: ${ev.rwk}°` : ''}
|
|
||||||
</span>
|
|
||||||
</span>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{hasWind && (
|
|
||||||
<span className="event-card-chip" title={t('logs.event_wind_direction')}>
|
|
||||||
<span>
|
|
||||||
Wind:{' '}
|
|
||||||
{[
|
|
||||||
ev.windDirection,
|
|
||||||
ev.windStrength ? `${ev.windStrength} Bft` : '',
|
|
||||||
ev.windPressure ? `${ev.windPressure} hPa` : ''
|
|
||||||
]
|
|
||||||
.filter(Boolean)
|
|
||||||
.join(' / ')}
|
|
||||||
</span>
|
|
||||||
</span>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{hasSeaState && (
|
|
||||||
<span className="event-card-chip" title={t('logs.event_sea_state')}>
|
|
||||||
<span>{t('logs.event_sea_state')}: {ev.seaState}</span>
|
|
||||||
</span>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{hasWeather && (
|
|
||||||
<span className="event-card-chip" title={t('logs.event_weather')}>
|
|
||||||
<img
|
|
||||||
src={`https://openweathermap.org/img/wn/${ev.weatherIcon}.png`}
|
|
||||||
alt="Weather"
|
|
||||||
className="event-card-weather-img"
|
|
||||||
/>
|
|
||||||
</span>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{hasLog && (
|
|
||||||
<span className="event-card-chip" title={t('logs.event_log')}>
|
|
||||||
<span>Log: {ev.logReading} nm</span>
|
|
||||||
</span>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{hasGps && (
|
|
||||||
<span className="event-card-chip" title={t('logs.event_gps')}>
|
|
||||||
<MapPin size={12} />
|
|
||||||
<span className="font-mono text-xs">{ev.gpsLat}, {ev.gpsLng}</span>
|
|
||||||
</span>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{hasVisibility && (
|
|
||||||
<span className="event-card-chip" title={t('logs.event_visibility')}>
|
|
||||||
<span>{t('logs.event_visibility')}: {ev.visibility}</span>
|
|
||||||
</span>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{hasHeel && (
|
|
||||||
<span className="event-card-chip" title={t('logs.event_heel')}>
|
|
||||||
<span>{t('logs.event_heel')}: {ev.heel}°</span>
|
|
||||||
</span>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{hasSailsOrMotor && (
|
|
||||||
<span className="event-card-chip" title={t('logs.event_sails')}>
|
|
||||||
<span>{ev.sailsOrMotor}</span>
|
|
||||||
</span>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="event-card-remarks">
|
|
||||||
<EventRemarksCell
|
|
||||||
event={ev}
|
|
||||||
logbookId={logbookId}
|
|
||||||
voiceMemoLookup={voiceMemoLookup}
|
|
||||||
readOnly={readOnly}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</div>
|
|
||||||
</>
|
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{/* Add New Event Form Sub-Card */}
|
{/* Add New Event Form Sub-Card */}
|
||||||
{!readOnly && (
|
{!readOnly && (
|
||||||
<div className="member-editor-card glass">
|
<div className="member-editor-card glass">
|
||||||
<h4 style={{ margin: '0 0 16px 0', color: '#fbbf24' }}>
|
<div
|
||||||
{editingEventIndex !== null ? t('logs.edit_event') : t('logs.add_event')}
|
className="accordion-header"
|
||||||
</h4>
|
onClick={() => 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)'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<h4 style={{ margin: 0, color: '#fbbf24' }}>
|
||||||
|
{editingEventIndex !== null ? t('logs.edit_event') : t('logs.add_event')}
|
||||||
|
</h4>
|
||||||
|
{addEventFormCollapsed ? (
|
||||||
|
<ChevronDown size={18} style={{ color: '#fbbf24' }} className="accordion-chevron" />
|
||||||
|
) : (
|
||||||
|
<ChevronUp size={18} style={{ color: '#fbbf24' }} className="accordion-chevron" />
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
<div className="form-grid mb-4">
|
{!addEventFormCollapsed && (
|
||||||
|
<>
|
||||||
|
<div className="form-grid mb-4">
|
||||||
<div className="input-group">
|
<div className="input-group">
|
||||||
<label>
|
<label>
|
||||||
<Clock size={12} style={{ display: 'inline', marginRight: 4 }} />
|
<Clock size={12} style={{ display: 'inline', marginRight: 4 }} />
|
||||||
@@ -2445,6 +2498,8 @@ export default function LogEntryEditor({
|
|||||||
{editingEventIndex !== null ? t('logs.save_event_btn') : t('logs.add_event_btn')}
|
{editingEventIndex !== null ? t('logs.save_event_btn') : t('logs.add_event_btn')}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user