feat: implement mobile and desktop layouts for framework editing
- Added responsive design for the framework editing page, including mobile tabs and a grid layout for goals and slots on desktop. - Introduced state management for tab selection and layout detection based on screen size. - Enhanced user interface with a tabbed navigation system for better organization of content. - Updated styles in app.css to support new layout features and improve overall aesthetics.
This commit is contained in:
parent
17f0513821
commit
eade9af2fe
|
|
@ -2713,6 +2713,71 @@ a.analysis-split__nav-item {
|
||||||
accent-color: var(--accent);
|
accent-color: var(--accent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Rahmenprogramm bearbeiten — Mobile Tabs, Desktop Ziele | Slots nebeneinander */
|
||||||
|
.framework-edit {
|
||||||
|
max-width: 800px;
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
||||||
|
@media (min-width: 1024px) {
|
||||||
|
.framework-edit {
|
||||||
|
max-width: min(1200px, 100%);
|
||||||
|
}
|
||||||
|
.framework-edit__tabbar {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
.framework-edit__goals-slots {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 1fr 1fr;
|
||||||
|
gap: 16px;
|
||||||
|
align-items: start;
|
||||||
|
}
|
||||||
|
/* breit: alle Bereiche sichtbar */
|
||||||
|
.framework-edit__panel {
|
||||||
|
display: block !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.framework-edit__tabbar {
|
||||||
|
display: flex;
|
||||||
|
gap: 6px;
|
||||||
|
margin-bottom: 14px;
|
||||||
|
padding: 2px 0 12px;
|
||||||
|
border-bottom: 1px solid var(--border);
|
||||||
|
flex-wrap: nowrap;
|
||||||
|
overflow-x: auto;
|
||||||
|
-webkit-overflow-scrolling: touch;
|
||||||
|
scrollbar-width: none;
|
||||||
|
}
|
||||||
|
.framework-edit__tabbar::-webkit-scrollbar {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
.framework-edit__tab {
|
||||||
|
flex: 1 1 0;
|
||||||
|
min-width: 0;
|
||||||
|
padding: 10px 8px;
|
||||||
|
border: 1px solid var(--border2);
|
||||||
|
border-radius: 10px;
|
||||||
|
background: var(--surface2);
|
||||||
|
color: var(--text2);
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: 600;
|
||||||
|
cursor: pointer;
|
||||||
|
white-space: nowrap;
|
||||||
|
font-family: var(--font);
|
||||||
|
}
|
||||||
|
.framework-edit__tab--active {
|
||||||
|
background: var(--accent-light);
|
||||||
|
color: var(--accent-dark);
|
||||||
|
border-color: var(--accent);
|
||||||
|
}
|
||||||
|
.framework-edit__goals-slots {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
@media (max-width: 1023px) {
|
||||||
|
.framework-edit .framework-edit__panel:not(.framework-edit__panel--active) {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@media print {
|
@media print {
|
||||||
.desktop-sidebar,
|
.desktop-sidebar,
|
||||||
.bottom-nav,
|
.bottom-nav,
|
||||||
|
|
|
||||||
|
|
@ -175,6 +175,19 @@ export default function TrainingFrameworkProgramEditPage() {
|
||||||
const [units, setUnits] = useState([])
|
const [units, setUnits] = useState([])
|
||||||
const [pickerSlotIdx, setPickerSlotIdx] = useState(null)
|
const [pickerSlotIdx, setPickerSlotIdx] = useState(null)
|
||||||
const [peekId, setPeekId] = useState(null)
|
const [peekId, setPeekId] = useState(null)
|
||||||
|
/** Nur schmal: welcher Block sichtbar — Desktop zeigt Stammdaten + zwei Spalten Ziele|Slots */
|
||||||
|
const [frameworkTab, setFrameworkTab] = useState('meta')
|
||||||
|
const [desktopLayout, setDesktopLayout] = useState(
|
||||||
|
typeof window !== 'undefined' ? window.matchMedia('(min-width: 1024px)').matches : false
|
||||||
|
)
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const mq = window.matchMedia('(min-width: 1024px)')
|
||||||
|
const apply = () => setDesktopLayout(!!mq.matches)
|
||||||
|
apply()
|
||||||
|
mq.addEventListener('change', apply)
|
||||||
|
return () => mq.removeEventListener('change', apply)
|
||||||
|
}, [])
|
||||||
|
|
||||||
const loadMeta = useCallback(async () => {
|
const loadMeta = useCallback(async () => {
|
||||||
try {
|
try {
|
||||||
|
|
@ -429,6 +442,8 @@ export default function TrainingFrameworkProgramEditPage() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const panelActive = (key) => desktopLayout || frameworkTab === key
|
||||||
|
|
||||||
if (loading) {
|
if (loading) {
|
||||||
return (
|
return (
|
||||||
<div style={{ padding: '2rem', textAlign: 'center' }}>
|
<div style={{ padding: '2rem', textAlign: 'center' }}>
|
||||||
|
|
@ -440,16 +455,53 @@ export default function TrainingFrameworkProgramEditPage() {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div style={{ padding: '2rem' }}>
|
<div style={{ padding: '2rem' }}>
|
||||||
<div style={{ maxWidth: '800px', margin: '0 auto' }}>
|
<div className="framework-edit">
|
||||||
<p style={{ marginBottom: '0.75rem' }}>
|
<p style={{ marginBottom: '0.75rem' }}>
|
||||||
<Link to="/planning/framework-programs" style={{ color: 'var(--accent-dark)' }}>
|
<Link to="/planning/framework-programs" style={{ color: 'var(--accent-dark)' }}>
|
||||||
← Alle Rahmenprogramme
|
← Alle Rahmenprogramme
|
||||||
</Link>
|
</Link>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<h1 style={{ marginBottom: '1rem' }}>{isNew ? 'Neues Rahmenprogramm' : 'Rahmenprogramm bearbeiten'}</h1>
|
<h1 style={{ marginBottom: '0.75rem' }}>{isNew ? 'Neues Rahmenprogramm' : 'Rahmenprogramm bearbeiten'}</h1>
|
||||||
|
|
||||||
<div className="card" style={{ marginBottom: '1rem' }}>
|
<div className="card" style={{ marginBottom: '1rem', background: 'var(--surface2)', borderStyle: 'dashed' }}>
|
||||||
|
<p style={{ fontSize: '0.88rem', color: 'var(--text2)', lineHeight: 1.55, margin: 0 }}>
|
||||||
|
<strong style={{ color: 'var(--text1)' }}>Stand dieser Funktion:</strong> Der Rahmen speichert Ziele, Slots
|
||||||
|
und Übungslisten — noch <strong>ohne</strong> die feinere{' '}
|
||||||
|
<strong>Trainingsplan‑Struktur pro Einheit</strong> (Abschnitte wie in der Einheitenplanung) und{' '}
|
||||||
|
<strong>ohne Übernahme</strong> in die nächste konkrete Trainingseinheit (geplanter Schritt „Warenkorb“).
|
||||||
|
<strong> Ziele</strong> lassen sich noch nicht einzelnen Einheiten oder Übungen zuordnen;{' '}
|
||||||
|
<strong>Progressionsketten</strong> aus dem Übungs‑Graph sind hier noch nicht eingebunden — dafür sind
|
||||||
|
API‑/Daten‑Erweiterungen und ein Folgerelease vorgesehen.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="framework-edit__tabbar" role="tablist" aria-label="Bereiche">
|
||||||
|
{[
|
||||||
|
{ id: 'meta', label: 'Stammdaten' },
|
||||||
|
{ id: 'goals', label: 'Ziele' },
|
||||||
|
{ id: 'slots', label: 'Slots & Übungen' },
|
||||||
|
].map((t) => (
|
||||||
|
<button
|
||||||
|
key={t.id}
|
||||||
|
type="button"
|
||||||
|
role="tab"
|
||||||
|
aria-selected={frameworkTab === t.id}
|
||||||
|
className={'framework-edit__tab' + (frameworkTab === t.id ? ' framework-edit__tab--active' : '')}
|
||||||
|
onClick={() => setFrameworkTab(t.id)}
|
||||||
|
>
|
||||||
|
{t.label}
|
||||||
|
</button>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div
|
||||||
|
className={
|
||||||
|
'framework-edit__panel framework-edit__panel--meta card' +
|
||||||
|
(panelActive('meta') ? ' framework-edit__panel--active' : '')
|
||||||
|
}
|
||||||
|
style={{ marginBottom: '1rem' }}
|
||||||
|
>
|
||||||
<h3 className="card-title">Stammdaten</h3>
|
<h3 className="card-title">Stammdaten</h3>
|
||||||
<div className="form-row">
|
<div className="form-row">
|
||||||
<label className="form-label">Titel *</label>
|
<label className="form-label">Titel *</label>
|
||||||
|
|
@ -555,7 +607,14 @@ export default function TrainingFrameworkProgramEditPage() {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="card" style={{ marginBottom: '1rem' }}>
|
<div className="framework-edit__goals-slots">
|
||||||
|
<div
|
||||||
|
className={
|
||||||
|
'framework-edit__panel framework-edit__panel--goals card' +
|
||||||
|
(panelActive('goals') ? ' framework-edit__panel--active' : '')
|
||||||
|
}
|
||||||
|
style={{ marginBottom: '1rem' }}
|
||||||
|
>
|
||||||
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: '0.75rem' }}>
|
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: '0.75rem' }}>
|
||||||
<h3 className="card-title" style={{ marginBottom: 0 }}>
|
<h3 className="card-title" style={{ marginBottom: 0 }}>
|
||||||
Entwicklungsziele
|
Entwicklungsziele
|
||||||
|
|
@ -617,7 +676,13 @@ export default function TrainingFrameworkProgramEditPage() {
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="card" style={{ marginBottom: '1.5rem' }}>
|
<div
|
||||||
|
className={
|
||||||
|
'framework-edit__panel framework-edit__panel--slots card' +
|
||||||
|
(panelActive('slots') ? ' framework-edit__panel--active' : '')
|
||||||
|
}
|
||||||
|
style={{ marginBottom: '1.5rem' }}
|
||||||
|
>
|
||||||
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: '0.75rem' }}>
|
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: '0.75rem' }}>
|
||||||
<h3 className="card-title" style={{ marginBottom: 0 }}>
|
<h3 className="card-title" style={{ marginBottom: 0 }}>
|
||||||
Session‑Slots & Übungen
|
Session‑Slots & Übungen
|
||||||
|
|
@ -779,6 +844,7 @@ export default function TrainingFrameworkProgramEditPage() {
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div style={{ display: 'flex', flexWrap: 'wrap', gap: '10px', alignItems: 'center' }}>
|
<div style={{ display: 'flex', flexWrap: 'wrap', gap: '10px', alignItems: 'center' }}>
|
||||||
<button type="button" className="btn btn-primary" disabled={saving} onClick={handleSave}>
|
<button type="button" className="btn btn-primary" disabled={saving} onClick={handleSave}>
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@ export const PAGE_VERSIONS = {
|
||||||
SkillsPage: "1.0.0",
|
SkillsPage: "1.0.0",
|
||||||
TrainingPlanningPage: "1.3.1",
|
TrainingPlanningPage: "1.3.1",
|
||||||
TrainingFrameworkProgramsListPage: "1.0.0",
|
TrainingFrameworkProgramsListPage: "1.0.0",
|
||||||
TrainingFrameworkProgramEditPage: "1.0.1",
|
TrainingFrameworkProgramEditPage: "1.1.0",
|
||||||
TrainingUnitRunPage: "1.1.0",
|
TrainingUnitRunPage: "1.1.0",
|
||||||
TrainingCoachPage: "1.0.0",
|
TrainingCoachPage: "1.0.0",
|
||||||
AdminCatalogsPage: "2.2.0", // Updated: Frontend API Calls & Field Names für renamed tables
|
AdminCatalogsPage: "2.2.0", // Updated: Frontend API Calls & Field Names für renamed tables
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user