diff --git a/frontend/src/app.css b/frontend/src/app.css
index a43cfc8..e19d511 100644
--- a/frontend/src/app.css
+++ b/frontend/src/app.css
@@ -1186,56 +1186,203 @@ a.analysis-split__nav-item {
.form-action-bar__inner {
display: flex;
flex-wrap: wrap;
- align-items: center;
- justify-content: space-between;
+ align-items: stretch;
+ justify-content: flex-start;
gap: 8px;
max-width: min(1100px, 100%);
margin: 0 auto;
-}
-.form-action-bar__spacer {
- flex: 0 0 auto;
min-width: 0;
}
.form-action-bar__primary-group {
display: flex;
flex-wrap: wrap;
- align-items: center;
+ align-items: stretch;
justify-content: flex-end;
gap: 8px;
margin-left: auto;
+ min-width: 0;
+ flex: 1 1 auto;
}
.form-action-bar__btn {
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ gap: 6px;
min-height: 44px;
padding: 8px 14px;
font-size: 0.88rem;
font-weight: 600;
white-space: nowrap;
+ min-width: 0;
}
.form-action-bar__btn--cancel {
min-width: 5.5rem;
}
+.form-action-bar__icon {
+ flex-shrink: 0;
+ display: none;
+}
+.form-action-bar__text--short {
+ display: none;
+}
+.form-action-bar__saving {
+ font-size: 0.82rem;
+ letter-spacing: 0.02em;
+}
+/* Form-Modale: Overlay + Panel (Desktop zentriert, Mobile Vollbild) */
+.modal-overlay--form {
+ position: fixed;
+ inset: 0;
+ z-index: 1000;
+ background: rgba(0, 0, 0, 0.5);
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ padding: 1rem;
+ overflow: hidden;
+ box-sizing: border-box;
+}
+.modal-overlay--form.modal-overlay--raised {
+ z-index: 1100;
+}
.modal-panel--form {
display: flex;
flex-direction: column;
- max-height: min(92vh, 100%);
+ background: var(--surface);
+ border-radius: 12px;
+ padding: clamp(12px, 3vw, 2rem);
+ width: 100%;
+ max-width: min(1100px, 100%);
+ max-height: min(92vh, 100dvh);
overflow: hidden;
min-height: 0;
+ min-width: 0;
+ box-sizing: border-box;
+}
+.modal-panel--form.modal-panel--narrow {
+ max-width: min(560px, 100%);
+}
+.modal-panel--form.card {
+ /* card-Klasse nur für Desktop-Rahmen; Mobile überschreibt unten */
+}
+.modal-panel__title {
+ margin: 0 0 1rem;
+ flex-shrink: 0;
+ font-size: clamp(1.05rem, 4vw, 1.25rem);
+ line-height: 1.25;
+ min-width: 0;
+}
+.modal-panel__intro {
+ font-size: 0.88rem;
+ color: var(--text2);
+ line-height: 1.45;
+ margin: 0 0 1rem;
+ flex-shrink: 0;
+ min-width: 0;
}
.modal-form-shell {
display: flex;
flex-direction: column;
flex: 1 1 auto;
min-height: 0;
+ min-width: 0;
overflow: hidden;
}
.modal-form-shell__body {
flex: 1 1 auto;
min-height: 0;
+ min-width: 0;
+ overflow-x: hidden;
overflow-y: auto;
+ overscroll-behavior-x: none;
-webkit-overflow-scrolling: touch;
padding-bottom: 4px;
}
+.modal-panel--form > *,
+.modal-form-shell__body > * {
+ max-width: 100%;
+ min-width: 0;
+}
+
+@media (max-width: 639px) {
+ .modal-overlay--form {
+ padding: 0;
+ align-items: stretch;
+ }
+ .modal-panel--form {
+ max-width: 100%;
+ max-height: 100dvh;
+ height: 100dvh;
+ border-radius: 0;
+ padding: 12px;
+ padding-top: max(12px, env(safe-area-inset-top, 0px));
+ padding-bottom: max(0px, env(safe-area-inset-bottom, 0px));
+ }
+ .modal-panel--form.card {
+ border: none;
+ border-radius: 0;
+ padding: 12px;
+ padding-top: max(12px, env(safe-area-inset-top, 0px));
+ padding-bottom: max(0px, env(safe-area-inset-bottom, 0px));
+ }
+ .modal-panel__title {
+ margin-bottom: 0.75rem;
+ font-size: 1.05rem;
+ }
+ .modal-panel__intro {
+ margin-bottom: 0.75rem;
+ font-size: 0.85rem;
+ }
+
+ .form-action-bar {
+ padding: 5px 6px;
+ padding-bottom: max(5px, env(safe-area-inset-bottom, 0px));
+ }
+ .form-action-bar__inner {
+ flex-wrap: nowrap;
+ gap: 6px;
+ max-width: none;
+ }
+ .form-action-bar__primary-group {
+ flex: 1 1 0;
+ flex-wrap: nowrap;
+ gap: 6px;
+ margin-left: 0;
+ min-width: 0;
+ }
+ .form-action-bar__btn {
+ min-height: 38px;
+ padding: 6px 8px;
+ font-size: 0.75rem;
+ gap: 4px;
+ flex: 1 1 0;
+ }
+ .form-action-bar__btn--cancel {
+ flex: 0 0 38px;
+ width: 38px;
+ min-width: 38px;
+ max-width: 38px;
+ padding: 0;
+ }
+ .form-action-bar__btn--cancel .form-action-bar__text--long,
+ .form-action-bar__btn--cancel .form-action-bar__text--short {
+ display: none !important;
+ }
+ .form-action-bar__icon {
+ display: inline;
+ }
+ .form-action-bar__text--long {
+ display: none;
+ }
+ .form-action-bar__text--short {
+ display: inline;
+ }
+ .form-action-bar--single-primary .form-action-bar__primary-group .form-action-bar__btn {
+ flex: 1 1 auto;
+ }
+}
+
.page-form-shell {
display: flex;
flex-direction: column;
diff --git a/frontend/src/components/FormActionBar.jsx b/frontend/src/components/FormActionBar.jsx
index 00614eb..e177b94 100644
--- a/frontend/src/components/FormActionBar.jsx
+++ b/frontend/src/components/FormActionBar.jsx
@@ -1,13 +1,32 @@
+import { Check, Save, X } from 'lucide-react'
+
/**
* Feste Aktionsleiste für Formulare/Modale: Speichern, Speichern & schließen, Abbrechen.
* Bleibt sichtbar (sticky), während der Formularinhalt scrollt.
*/
+function ActionLabel({ Icon, long, short, saving, savingShort = '…' }) {
+ if (saving) {
+ return {savingShort}
+ }
+ return (
+ <>
+ {Icon ?
+
Es werden die gespeicherten Übungspositionen der Einheit vom{' '} {unitLabel || '…'} verwendet. Speichere die Planung vorher, wenn du den aktuellen Stand brauchst. @@ -296,6 +276,7 @@ export default function SaveExercisesAsModuleModal({ saving={submitting} showSave={false} saveAndCloseLabel="Modul anlegen" + saveAndCloseShortLabel="Anlegen" onCancel={onClose} /> diff --git a/frontend/src/components/planning/TrainingPlanningUnitFormModal.jsx b/frontend/src/components/planning/TrainingPlanningUnitFormModal.jsx index 14f3032..b15004a 100644 --- a/frontend/src/components/planning/TrainingPlanningUnitFormModal.jsx +++ b/frontend/src/components/planning/TrainingPlanningUnitFormModal.jsx @@ -57,37 +57,9 @@ export default function TrainingPlanningUnitFormModal({ const formId = 'planning-unit-form' return ( -
+
Es wird der zuletzt gespeicherte Ablauf dieser Einheit aus der Datenbank übernommen. Nicht gespeicherte Änderungen im Formular sind nicht enthalten — bitte vorher die Einheit speichern.
@@ -415,6 +395,7 @@ export default function TrainingPublishToFrameworkModal({ saving={submitting} showSave={false} saveAndCloseLabel="In Rahmen übernehmen" + saveAndCloseShortLabel="Übernehmen" onCancel={resetAndClose} />