fix(ui): Segel-Picker auf Mobile weiter verdichten

Einklappbare Badge-Liste bei vielen Segeln, kompaktere Pills und aktive Auswahl bleibt oben sichtbar.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-05-31 11:50:23 +02:00
parent 3992db9d61
commit adf02acd45
4 changed files with 115 additions and 13 deletions
+53 -4
View File
@@ -2435,15 +2435,29 @@ html.scheme-dark .themed-select-option.is-selected {
} }
.sails-picker-pills { .sails-picker-pills {
display: grid; gap: 4px;
grid-template-columns: repeat(auto-fill, minmax(min(100%, 128px), 1fr)); }
gap: 6px;
.sails-picker-container.is-collapsible .sails-picker-toggle {
display: inline-flex;
} }
.sail-pill { .sail-pill {
text-align: center;
padding: 3px 8px; padding: 3px 8px;
font-size: 11px; font-size: 11px;
border-radius: 12px;
line-height: 1.2;
}
}
@media (max-width: 480px) {
.sails-picker-container.is-collapsible.is-collapsed .sails-picker-pills {
max-height: 3.25rem;
}
.sail-pill {
padding: 2px 7px;
font-size: 10px;
} }
} }
@@ -2706,12 +2720,47 @@ html.theme-cupertino .events-scroll-container {
/* Event Editor Interactive Sails Picker */ /* Event Editor Interactive Sails Picker */
.sails-picker-container { .sails-picker-container {
grid-column: 1 / -1; grid-column: 1 / -1;
margin-top: -4px;
} }
.sails-picker-pills { .sails-picker-pills {
display: flex; display: flex;
flex-wrap: wrap; flex-wrap: wrap;
gap: 6px; gap: 6px;
position: relative;
}
.sails-picker-container.is-collapsible.is-collapsed .sails-picker-pills {
max-height: 3.75rem;
overflow: hidden;
}
.sails-picker-container.is-collapsible.is-collapsed .sails-picker-pills::after {
content: '';
position: absolute;
bottom: 0;
left: 0;
right: 0;
height: 1.25rem;
background: linear-gradient(to bottom, transparent, var(--app-surface, #0f172a));
pointer-events: none;
}
.sails-picker-toggle {
display: none;
align-items: center;
gap: 4px;
margin: 4px auto 0;
padding: 2px 8px;
background: none;
border: none;
color: var(--app-text-muted, #94a3b8);
font-size: 12px;
cursor: pointer;
}
.sails-picker-toggle:hover {
color: var(--app-accent, #fbbf24);
} }
.sail-pill { .sail-pill {
+58 -9
View File
@@ -6,7 +6,7 @@ import { getLogbookKey } from '../services/logbookKeys.js'
import { encryptJson, decryptJson } from '../services/crypto.js' import { encryptJson, decryptJson } from '../services/crypto.js'
import { syncLogbook } from '../services/sync.js' import { syncLogbook } from '../services/sync.js'
import { downloadLogbookPagePdf } from '../services/pdfExport.js' import { downloadLogbookPagePdf } from '../services/pdfExport.js'
import { FileText, Save, ChevronLeft, Check, Compass, Plus, Trash2, MapPin, CloudSun, Clock, Download, Upload, Pencil, X } from 'lucide-react' import { FileText, Save, ChevronLeft, Check, Compass, Plus, Trash2, MapPin, CloudSun, Clock, Download, Upload, Pencil, X, ChevronDown, ChevronUp } from 'lucide-react'
import PhotoCapture from './PhotoCapture.tsx' import PhotoCapture from './PhotoCapture.tsx'
import SignatureSection from './SignatureSection.tsx' import SignatureSection from './SignatureSection.tsx'
import TrackMap from './TrackMap.tsx' import TrackMap from './TrackMap.tsx'
@@ -176,6 +176,7 @@ export default function LogEntryEditor({
const [evCurrent, setEvCurrent] = useState('') const [evCurrent, setEvCurrent] = useState('')
const [evHeel, setEvHeel] = useState('') const [evHeel, setEvHeel] = useState('')
const [evSailsOrMotor, setEvSailsOrMotor] = useState('') const [evSailsOrMotor, setEvSailsOrMotor] = useState('')
const [sailsPickerExpanded, setSailsPickerExpanded] = useState(false)
const [evLogReading, setEvLogReading] = useState('') const [evLogReading, setEvLogReading] = useState('')
const [evDistance, setEvDistance] = useState('') const [evDistance, setEvDistance] = useState('')
const [evGpsLat, setEvGpsLat] = useState('') const [evGpsLat, setEvGpsLat] = useState('')
@@ -842,6 +843,9 @@ export default function LogEntryEditor({
? ['Großsegel', 'Genua', 'Fock', 'Spinnaker', 'Gennaker'] ? ['Großsegel', 'Genua', 'Fock', 'Spinnaker', 'Gennaker']
: ['Mainsail', 'Genoa', 'Jib', 'Spinnaker', 'Gennaker'] : ['Mainsail', 'Genoa', 'Jib', 'Spinnaker', 'Gennaker']
const eventSailOptions = yachtSails.length > 0 ? yachtSails : defaultSails
const showSailsPickerToggle = eventSailOptions.length + 1 > 6
const toggleSailOrMotor = (item: string) => { const toggleSailOrMotor = (item: string) => {
let currentItems = evSailsOrMotor let currentItems = evSailsOrMotor
.split(/\s*(?:\+|\bplus\b|,)\s*/i) .split(/\s*(?:\+|\bplus\b|,)\s*/i)
@@ -865,6 +869,15 @@ export default function LogEntryEditor({
return currentItems.includes(item.toLowerCase()) return currentItems.includes(item.toLowerCase())
} }
const motorPropulsionLabel = t('logs.motor_propulsion')
const sortedEventSailOptions = [...eventSailOptions].sort((a, b) => {
const aActive = isItemActive(a)
const bActive = isItemActive(b)
if (aActive === bActive) return 0
return aActive ? -1 : 1
})
const isMotorActive = isItemActive(motorPropulsionLabel)
const clearEventForm = () => { const clearEventForm = () => {
setEvTime(currentLocalTimeHHMM()) setEvTime(currentLocalTimeHHMM())
setEvMgk('') setEvMgk('')
@@ -1573,9 +1586,23 @@ export default function LogEntryEditor({
/> />
</div> </div>
<div className="sails-picker-container grid-span-2"> <div
className={[
'sails-picker-container grid-span-2',
showSailsPickerToggle ? 'is-collapsible' : '',
showSailsPickerToggle && !sailsPickerExpanded ? 'is-collapsed' : '',
].filter(Boolean).join(' ')}
>
<div className="sails-picker-pills"> <div className="sails-picker-pills">
{(yachtSails.length > 0 ? yachtSails : defaultSails).map((sail) => ( {isMotorActive && (
<span
className={`sail-pill motor-pill active`}
onClick={() => toggleSailOrMotor(motorPropulsionLabel)}
>
{motorPropulsionLabel}
</span>
)}
{sortedEventSailOptions.map((sail) => (
<span <span
key={sail} key={sail}
className={`sail-pill ${isItemActive(sail) ? 'active' : ''}`} className={`sail-pill ${isItemActive(sail) ? 'active' : ''}`}
@@ -1584,13 +1611,35 @@ export default function LogEntryEditor({
{sail} {sail}
</span> </span>
))} ))}
<span {!isMotorActive && (
className={`sail-pill motor-pill ${isItemActive(t('logs.motor_propulsion')) ? 'active' : ''}`} <span
onClick={() => toggleSailOrMotor(t('logs.motor_propulsion'))} className="sail-pill motor-pill"
> onClick={() => toggleSailOrMotor(motorPropulsionLabel)}
{t('logs.motor_propulsion')} >
</span> {motorPropulsionLabel}
</span>
)}
</div> </div>
{showSailsPickerToggle && (
<button
type="button"
className="sails-picker-toggle"
onClick={() => setSailsPickerExpanded((prev) => !prev)}
aria-expanded={sailsPickerExpanded}
>
{sailsPickerExpanded ? (
<>
<ChevronUp size={14} aria-hidden="true" />
{t('logs.sails_picker_show_less')}
</>
) : (
<>
<ChevronDown size={14} aria-hidden="true" />
{t('logs.sails_picker_show_more')}
</>
)}
</button>
)}
</div> </div>
<div className="input-group grid-span-2"> <div className="input-group grid-span-2">
+2
View File
@@ -222,6 +222,8 @@
"event_heel": "Krängung (°)", "event_heel": "Krängung (°)",
"event_sails": "Segelführung / Motor", "event_sails": "Segelführung / Motor",
"motor_propulsion": "Maschinenfahrt", "motor_propulsion": "Maschinenfahrt",
"sails_picker_show_more": "Alle Segel anzeigen",
"sails_picker_show_less": "Weniger anzeigen",
"motor_hours": "Maschinenstunden (gesamt)", "motor_hours": "Maschinenstunden (gesamt)",
"fuel_per_motor_hour": "Verbrauch pro Maschinenstunde", "fuel_per_motor_hour": "Verbrauch pro Maschinenstunde",
"event_distance": "Distanz (sm)", "event_distance": "Distanz (sm)",
+2
View File
@@ -222,6 +222,8 @@
"event_heel": "Heel Angle (°)", "event_heel": "Heel Angle (°)",
"event_sails": "Sails / Motor Status", "event_sails": "Sails / Motor Status",
"motor_propulsion": "Engine Propulsion", "motor_propulsion": "Engine Propulsion",
"sails_picker_show_more": "Show all sails",
"sails_picker_show_less": "Show less",
"motor_hours": "Engine hours (total)", "motor_hours": "Engine hours (total)",
"fuel_per_motor_hour": "Consumption per engine hour", "fuel_per_motor_hour": "Consumption per engine hour",
"event_distance": "Distance (nm)", "event_distance": "Distance (nm)",