feat(combo-planning): enhance modal UI and styling for combination planning editing
All checks were successful
Deploy Development / deploy (push) Successful in 44s
Test Suite / pytest-backend (push) Successful in 35s
Test Suite / lint-backend (push) Successful in 1s
Test Suite / build-frontend (push) Successful in 12s
Test Suite / playwright-tests (push) Successful in 58s

- Updated the TrainingUnitSectionsEditor to integrate new CSS classes for the combo planning modal, improving the visual consistency with the exercise preview.
- Added responsive design features to the modal, including max-width and max-height adjustments for better usability on different screen sizes.
- Introduced new toolbar and hint elements to enhance user interaction and provide clearer guidance within the combo planning context.
- Refactored existing modal structure for improved accessibility and user experience.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Lars 2026-05-13 14:25:58 +02:00
parent a8942a9e4e
commit ed15f73727
2 changed files with 122 additions and 109 deletions

View File

@ -6382,6 +6382,47 @@ a.analysis-split__nav-item {
margin-top: 0.65rem;
}
/* Kombi-Planung bearbeiten (Planungseditor): gleiches Modal-Chrome wie Übungs-Vorschau */
.combo-planning-edit-backdrop.admin-modal-backdrop {
z-index: 10060;
}
.combo-planning-edit-sheet.admin-modal-sheet {
max-width: min(880px, calc(100vw - 24px));
}
@media (min-width: 640px) {
.combo-planning-edit-sheet.admin-modal-sheet {
max-height: min(88vh, 860px);
}
}
.combo-planning-edit-toolbar {
display: flex;
flex-wrap: wrap;
gap: 8px;
margin-bottom: 14px;
}
.combo-planning-edit-hint {
margin: 0 0 14px;
font-size: 0.8rem;
color: var(--text2);
line-height: 1.45;
}
.combo-planning-edit-card {
margin-top: 4px;
padding: 14px 16px 16px;
border-radius: 12px;
border: 1px solid var(--border);
background: var(--surface2);
border-left: 4px solid var(--accent);
}
.combo-planning-edit-card__title {
margin: 0 0 12px;
font-size: 0.72rem;
font-weight: 700;
letter-spacing: 0.05em;
text-transform: uppercase;
color: var(--text3);
}
@media print {
.desktop-sidebar,
.bottom-nav,

View File

@ -1537,134 +1537,106 @@ export default function TrainingUnitSectionsEditor({
comboPlanningModalSX != null &&
comboPlanningModalIX != null ? (
<div
className="tu-textedit-backdrop"
className="admin-modal-backdrop combo-planning-edit-backdrop"
role="presentation"
onMouseDown={(e) => {
if (e.target === e.currentTarget) setComboPlanningModal(null)
}}
>
<div
className="tu-textedit-panel tu-textedit-panel--combo-planning"
className="admin-modal-sheet combo-planning-edit-sheet"
role="dialog"
aria-modal="true"
aria-labelledby="tu-combo-planning-title"
onMouseDown={(e) => e.stopPropagation()}
style={{
maxWidth: 'min(920px, 96vw)',
maxHeight: 'min(800px, 88vh)',
overflow: 'auto',
}}
>
<h4 id="tu-combo-planning-title" className="tu-textedit-title">
Ablaufprofil dieser Kombination für diese Planung
</h4>
<p
style={{
margin: '0 0 0.85rem',
fontSize: '0.82rem',
color: 'var(--text2)',
lineHeight: 1.45,
}}
>
<strong style={{ fontWeight: 600, color: 'var(--text1)' }}>
{(comboPlanningModalItem.exercise_title || '').trim() ||
`Kombination #${comboPlanningModalItem.exercise_id}`}
</strong>
<span style={{ marginLeft: 8 }}>
({compactComboPlanningCaption(comboPlanningModalItem)})
</span>
</p>
<div style={{ display: 'flex', flexWrap: 'wrap', gap: 8, marginBottom: 12 }}>
<button
type="button"
className="btn btn-secondary framework-ctrl framework-ctrl--xs"
onClick={() =>
updateItem(comboPlanningModalSX, comboPlanningModalIX, 'planning_method_profile', null)
}
>
Planung wie Katalog
</button>
<button
type="button"
className="btn btn-secondary framework-ctrl framework-ctrl--xs"
title="Bearbeitbare Kopie der Katalog-Vorgaben setzen"
onClick={() =>
updateItem(comboPlanningModalSX, comboPlanningModalIX, 'planning_method_profile', {
...(comboPlanningModalItem.catalog_method_profile || {}),
})
}
>
Aus Katalog kopieren
</button>
</div>
<p
style={{
margin: '0 0 12px',
fontSize: '0.8rem',
color: 'var(--text2)',
lineHeight: 1.45,
}}
>
Stationen und Einzelübungen entsprechen der Kombination im Katalog. Einzelübungen hier auszutauschen ist
derzeit nicht vorgesehen (würde die Katalog-Übung ändern). Die Bereiche unten überschreiben nur diesen
Termin, sofern du von den Katalogvorgaben abweichst.
</p>
{comboPlanningResolvedSlots.length > 0 ? (
<div style={{ marginBottom: 16 }}>
<CombinationPlanBracket
methodArchetype={(comboPlanningModalItem.catalog_method_archetype || '').trim()}
methodProfile={comboPlanningEffectiveProfile}
combinationSlots={comboPlanningResolvedSlots}
planningAdjusted={
comboPlanningModalItem.planning_method_profile != null &&
typeof comboPlanningModalItem.planning_method_profile === 'object' &&
!Array.isArray(comboPlanningModalItem.planning_method_profile)
}
/>
<div className="admin-modal-sheet__header">
<div style={{ minWidth: 0 }}>
<h3 id="tu-combo-planning-title" className="admin-modal-sheet__title">
{(comboPlanningModalItem.exercise_title || '').trim() ||
`Kombination #${comboPlanningModalItem.exercise_id}`}
</h3>
<p style={{ margin: '6px 0 0', fontSize: '0.82rem', color: 'var(--text2)', lineHeight: 1.4 }}>
Planung für diesen Termin · {compactComboPlanningCaption(comboPlanningModalItem)}
</p>
</div>
) : (
<p style={{ margin: '0 0 14px', fontSize: '0.82rem', color: 'var(--text3)', lineHeight: 1.45 }}>
Stationen werden geladen oder die Kombination hat im Katalog keine Stationsliste.
</p>
)}
<h5
style={{
margin: '0 0 10px',
fontSize: '0.95rem',
fontWeight: 700,
color: 'var(--text1)',
}}
>
Zeiten und Steuerung für diesen Termin
</h5>
<CombinationMethodProfileEditor
plannerMode
methodArchetype={(comboPlanningModalItem.catalog_method_archetype || '').trim()}
methodProfileJson={comboPlanningProfileJsonForEditor(
comboPlanningModalItem.catalog_method_profile || {},
comboPlanningModalItem.planning_method_profile
)}
onChangeMethodProfileJson={(json) => {
try {
const obj = JSON.parse(json || '{}')
if (obj && typeof obj === 'object' && !Array.isArray(obj)) {
updateItem(comboPlanningModalSX, comboPlanningModalIX, 'planning_method_profile', obj)
}
} catch {
/* Ungültiges JSON — Hinweis im Editor */
}
}}
comboSlotsOutline={comboPlanningSlotsOutline}
/>
<div className="tu-textedit-actions" style={{ marginTop: '0.95rem', paddingTop: '0.25rem' }}>
<button
type="button"
className="btn btn-primary"
className="btn btn-secondary admin-modal-sheet__close"
onClick={() => setComboPlanningModal(null)}
>
Schließen
</button>
</div>
<div className="admin-modal-sheet__body">
<div className="combo-planning-edit-toolbar">
<button
type="button"
className="btn btn-secondary framework-ctrl framework-ctrl--xs"
onClick={() =>
updateItem(comboPlanningModalSX, comboPlanningModalIX, 'planning_method_profile', null)
}
>
Planung wie Katalog
</button>
<button
type="button"
className="btn btn-secondary framework-ctrl framework-ctrl--xs"
title="Bearbeitbare Kopie der Katalog-Vorgaben für diese Einheit setzen"
onClick={() =>
updateItem(comboPlanningModalSX, comboPlanningModalIX, 'planning_method_profile', {
...(comboPlanningModalItem.catalog_method_profile || {}),
})
}
>
Aus Katalog kopieren
</button>
</div>
<p className="combo-planning-edit-hint">
Vorschau unten entspricht der effektiven Planung (Katalog oder Anpassung). Stationen und Einzelübungen
kommen aus dem Katalog; hier änderst du nur Zeiten, Runden und Steuerung für diese Einheit.
</p>
{comboPlanningResolvedSlots.length > 0 ? (
<div style={{ marginBottom: 18 }}>
<CombinationPlanBracket
methodArchetype={(comboPlanningModalItem.catalog_method_archetype || '').trim()}
methodProfile={comboPlanningEffectiveProfile}
combinationSlots={comboPlanningResolvedSlots}
planningAdjusted={
comboPlanningModalItem.planning_method_profile != null &&
typeof comboPlanningModalItem.planning_method_profile === 'object' &&
!Array.isArray(comboPlanningModalItem.planning_method_profile)
}
/>
</div>
) : (
<p style={{ margin: '0 0 18px', fontSize: '0.82rem', color: 'var(--text3)', lineHeight: 1.45 }}>
Stationen werden geladen oder die Kombination hat im Katalog keine Stationsliste.
</p>
)}
<div className="combo-planning-edit-card">
<h4 className="combo-planning-edit-card__title">Globale und stationsbezogene Anpassungen</h4>
<CombinationMethodProfileEditor
plannerMode
methodArchetype={(comboPlanningModalItem.catalog_method_archetype || '').trim()}
methodProfileJson={comboPlanningProfileJsonForEditor(
comboPlanningModalItem.catalog_method_profile || {},
comboPlanningModalItem.planning_method_profile
)}
onChangeMethodProfileJson={(json) => {
try {
const obj = JSON.parse(json || '{}')
if (obj && typeof obj === 'object' && !Array.isArray(obj)) {
updateItem(comboPlanningModalSX, comboPlanningModalIX, 'planning_method_profile', obj)
}
} catch {
/* Ungültiges JSON — Hinweis im Editor */
}
}}
comboSlotsOutline={comboPlanningSlotsOutline}
/>
</div>
</div>
</div>
</div>
) : null}