feat: update layout and styles for TrainingFrameworkProgramEditPage
- Adjusted responsive design breakpoints for mobile and desktop views in app.css. - Introduced a new horizontal layout for slots in the framework editor, enhancing usability on wider screens. - Updated versioning for TrainingFrameworkProgramEditPage to 1.2.0 to reflect recent changes. - Improved tab visibility and layout management based on screen size in TrainingFrameworkProgramEditPage.jsx. - Enhanced user guidance in TrainingFrameworkProgramsListPage with additional context on layout behavior.
This commit is contained in:
parent
eade9af2fe
commit
88fc9d9ba5
|
|
@ -2713,12 +2713,12 @@ a.analysis-split__nav-item {
|
||||||
accent-color: var(--accent);
|
accent-color: var(--accent);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Rahmenprogramm bearbeiten — Mobile Tabs, Desktop Ziele | Slots nebeneinander */
|
/* Rahmenprogramm bearbeiten — Mobile Tabs, Desktop Ziele | Slots nebeneinander (synchron zu FRAMEWORK_DESKTOP_MIN_PX im Editor) */
|
||||||
.framework-edit {
|
.framework-edit {
|
||||||
max-width: 800px;
|
max-width: 800px;
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
}
|
}
|
||||||
@media (min-width: 1024px) {
|
@media (min-width: 900px) {
|
||||||
.framework-edit {
|
.framework-edit {
|
||||||
max-width: min(1200px, 100%);
|
max-width: min(1200px, 100%);
|
||||||
}
|
}
|
||||||
|
|
@ -2772,12 +2772,42 @@ a.analysis-split__nav-item {
|
||||||
.framework-edit__goals-slots {
|
.framework-edit__goals-slots {
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
@media (max-width: 1023px) {
|
@media (max-width: 899px) {
|
||||||
.framework-edit .framework-edit__panel:not(.framework-edit__panel--active) {
|
.framework-edit .framework-edit__panel:not(.framework-edit__panel--active) {
|
||||||
display: none !important;
|
display: none !important;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Rahmen-Editor: Slots (= Session‑Spalten) horizontal, scrollbar */
|
||||||
|
.framework-slots-board {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
flex-wrap: nowrap;
|
||||||
|
gap: 12px;
|
||||||
|
align-items: stretch;
|
||||||
|
overflow-x: auto;
|
||||||
|
overflow-y: hidden;
|
||||||
|
padding: 4px 2px 12px;
|
||||||
|
margin: 0 -4px;
|
||||||
|
-webkit-overflow-scrolling: touch;
|
||||||
|
scroll-snap-type: x proximity;
|
||||||
|
}
|
||||||
|
.framework-slots-board .framework-slot-card {
|
||||||
|
flex: 0 0 min(320px, calc(100vw - 48px));
|
||||||
|
min-width: min(320px, calc(100vw - 48px));
|
||||||
|
max-height: min(70vh, 720px);
|
||||||
|
overflow-x: hidden;
|
||||||
|
overflow-y: auto;
|
||||||
|
scroll-snap-align: start;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
@media (min-width: 900px) {
|
||||||
|
.framework-slots-board .framework-slot-card {
|
||||||
|
flex-basis: 300px;
|
||||||
|
min-width: 280px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@media print {
|
@media print {
|
||||||
.desktop-sidebar,
|
.desktop-sidebar,
|
||||||
.bottom-nav,
|
.bottom-nav,
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,9 @@ import api from '../utils/api'
|
||||||
import ExercisePickerModal from '../components/ExercisePickerModal'
|
import ExercisePickerModal from '../components/ExercisePickerModal'
|
||||||
import ExercisePeekModal from '../components/ExercisePeekModal'
|
import ExercisePeekModal from '../components/ExercisePeekModal'
|
||||||
|
|
||||||
|
/** Unter dieser Breite: Registerkarten; darüber: Ziele | Slots nebeneinander (muss zu app.css passen) */
|
||||||
|
const FRAMEWORK_DESKTOP_MIN_PX = 900
|
||||||
|
|
||||||
function emptyGoal() {
|
function emptyGoal() {
|
||||||
return { title: '', notes: '' }
|
return { title: '', notes: '' }
|
||||||
}
|
}
|
||||||
|
|
@ -178,11 +181,13 @@ export default function TrainingFrameworkProgramEditPage() {
|
||||||
/** Nur schmal: welcher Block sichtbar — Desktop zeigt Stammdaten + zwei Spalten Ziele|Slots */
|
/** Nur schmal: welcher Block sichtbar — Desktop zeigt Stammdaten + zwei Spalten Ziele|Slots */
|
||||||
const [frameworkTab, setFrameworkTab] = useState('meta')
|
const [frameworkTab, setFrameworkTab] = useState('meta')
|
||||||
const [desktopLayout, setDesktopLayout] = useState(
|
const [desktopLayout, setDesktopLayout] = useState(
|
||||||
typeof window !== 'undefined' ? window.matchMedia('(min-width: 1024px)').matches : false
|
typeof window !== 'undefined'
|
||||||
|
? window.matchMedia(`(min-width: ${FRAMEWORK_DESKTOP_MIN_PX}px)`).matches
|
||||||
|
: false
|
||||||
)
|
)
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const mq = window.matchMedia('(min-width: 1024px)')
|
const mq = window.matchMedia(`(min-width: ${FRAMEWORK_DESKTOP_MIN_PX}px)`)
|
||||||
const apply = () => setDesktopLayout(!!mq.matches)
|
const apply = () => setDesktopLayout(!!mq.matches)
|
||||||
apply()
|
apply()
|
||||||
mq.addEventListener('change', apply)
|
mq.addEventListener('change', apply)
|
||||||
|
|
@ -444,6 +449,10 @@ export default function TrainingFrameworkProgramEditPage() {
|
||||||
|
|
||||||
const panelActive = (key) => desktopLayout || frameworkTab === key
|
const panelActive = (key) => desktopLayout || frameworkTab === key
|
||||||
|
|
||||||
|
/** Schmale Ansicht: Sichtbarkeit per Inline (falls globales CSS nicht greift / altes Bundle) */
|
||||||
|
const panelVisibilityStyle = (key) =>
|
||||||
|
desktopLayout ? undefined : { display: panelActive(key) ? 'block' : 'none' }
|
||||||
|
|
||||||
if (loading) {
|
if (loading) {
|
||||||
return (
|
return (
|
||||||
<div style={{ padding: '2rem', textAlign: 'center' }}>
|
<div style={{ padding: '2rem', textAlign: 'center' }}>
|
||||||
|
|
@ -467,16 +476,38 @@ export default function TrainingFrameworkProgramEditPage() {
|
||||||
<div className="card" style={{ marginBottom: '1rem', background: 'var(--surface2)', borderStyle: 'dashed' }}>
|
<div className="card" style={{ marginBottom: '1rem', background: 'var(--surface2)', borderStyle: 'dashed' }}>
|
||||||
<p style={{ fontSize: '0.88rem', color: 'var(--text2)', lineHeight: 1.55, margin: 0 }}>
|
<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
|
<strong style={{ color: 'var(--text1)' }}>Stand dieser Funktion:</strong> Der Rahmen speichert Ziele, Slots
|
||||||
und Übungslisten — noch <strong>ohne</strong> die feinere{' '}
|
und pro Slot eine <strong>Übungsliste</strong> (Stückliste). Eine <strong>volle Einheiten‑Struktur</strong> wie
|
||||||
<strong>Trainingsplan‑Struktur pro Einheit</strong> (Abschnitte wie in der Einheitenplanung) und{' '}
|
in der Trainingsplanung (Abschnitte, Notizen, Mikrovorlage pro Slot) ist im Konzept optional (
|
||||||
<strong>ohne Übernahme</strong> in die nächste konkrete Trainingseinheit (geplanter Schritt „Warenkorb“).
|
<strong>CURR‑010</strong>: <code>training_plan_template_id</code> pro Slot) — in der DB derzeit{' '}
|
||||||
<strong> Ziele</strong> lassen sich noch nicht einzelnen Einheiten oder Übungen zuordnen;{' '}
|
<strong>noch nicht</strong> umgesetzt.{' '}
|
||||||
<strong>Progressionsketten</strong> aus dem Übungs‑Graph sind hier noch nicht eingebunden — dafür sind
|
<strong>Übernahme</strong> in konkrete Trainingseinheiten mit Referenz auf den Rahmen (Kopie, editierbar){' '}
|
||||||
API‑/Daten‑Erweiterungen und ein Folgerelease vorgesehen.
|
ist <strong>Stufe 3 / Lineage</strong> vorgesehen. Die Slot‑Spalten unten sind die geplanten
|
||||||
|
Session‑Positionen <strong>ohne feste Termine</strong> am Rahmen.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="framework-edit__tabbar" role="tablist" aria-label="Bereiche">
|
<div
|
||||||
|
className="framework-edit__tabbar"
|
||||||
|
role="tablist"
|
||||||
|
aria-label="Bereiche"
|
||||||
|
style={
|
||||||
|
desktopLayout
|
||||||
|
? { display: 'none' }
|
||||||
|
: {
|
||||||
|
display: 'flex',
|
||||||
|
gap: 6,
|
||||||
|
marginBottom: 14,
|
||||||
|
padding: '6px 0 12px',
|
||||||
|
borderBottom: '2px solid var(--accent)',
|
||||||
|
flexWrap: 'nowrap',
|
||||||
|
overflowX: 'auto',
|
||||||
|
position: 'sticky',
|
||||||
|
top: 0,
|
||||||
|
zIndex: 6,
|
||||||
|
background: 'var(--bg)',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
>
|
||||||
{[
|
{[
|
||||||
{ id: 'meta', label: 'Stammdaten' },
|
{ id: 'meta', label: 'Stammdaten' },
|
||||||
{ id: 'goals', label: 'Ziele' },
|
{ id: 'goals', label: 'Ziele' },
|
||||||
|
|
@ -500,7 +531,7 @@ export default function TrainingFrameworkProgramEditPage() {
|
||||||
'framework-edit__panel framework-edit__panel--meta card' +
|
'framework-edit__panel framework-edit__panel--meta card' +
|
||||||
(panelActive('meta') ? ' framework-edit__panel--active' : '')
|
(panelActive('meta') ? ' framework-edit__panel--active' : '')
|
||||||
}
|
}
|
||||||
style={{ marginBottom: '1rem' }}
|
style={{ marginBottom: '1rem', ...(panelVisibilityStyle('meta') || {}) }}
|
||||||
>
|
>
|
||||||
<h3 className="card-title">Stammdaten</h3>
|
<h3 className="card-title">Stammdaten</h3>
|
||||||
<div className="form-row">
|
<div className="form-row">
|
||||||
|
|
@ -607,13 +638,25 @@ export default function TrainingFrameworkProgramEditPage() {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="framework-edit__goals-slots">
|
<div
|
||||||
|
className="framework-edit__goals-slots"
|
||||||
|
style={
|
||||||
|
desktopLayout
|
||||||
|
? {
|
||||||
|
display: 'grid',
|
||||||
|
gridTemplateColumns: '1fr 1fr',
|
||||||
|
gap: 16,
|
||||||
|
alignItems: 'start',
|
||||||
|
}
|
||||||
|
: undefined
|
||||||
|
}
|
||||||
|
>
|
||||||
<div
|
<div
|
||||||
className={
|
className={
|
||||||
'framework-edit__panel framework-edit__panel--goals card' +
|
'framework-edit__panel framework-edit__panel--goals card' +
|
||||||
(panelActive('goals') ? ' framework-edit__panel--active' : '')
|
(panelActive('goals') ? ' framework-edit__panel--active' : '')
|
||||||
}
|
}
|
||||||
style={{ marginBottom: '1rem' }}
|
style={{ marginBottom: '1rem', ...(panelVisibilityStyle('goals') || {}) }}
|
||||||
>
|
>
|
||||||
<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 }}>
|
||||||
|
|
@ -681,7 +724,7 @@ export default function TrainingFrameworkProgramEditPage() {
|
||||||
'framework-edit__panel framework-edit__panel--slots card' +
|
'framework-edit__panel framework-edit__panel--slots card' +
|
||||||
(panelActive('slots') ? ' framework-edit__panel--active' : '')
|
(panelActive('slots') ? ' framework-edit__panel--active' : '')
|
||||||
}
|
}
|
||||||
style={{ marginBottom: '1.5rem' }}
|
style={{ marginBottom: '1.5rem', ...(panelVisibilityStyle('slots') || {}) }}
|
||||||
>
|
>
|
||||||
<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 }}>
|
||||||
|
|
@ -694,15 +737,21 @@ export default function TrainingFrameworkProgramEditPage() {
|
||||||
|
|
||||||
{form.slots.length === 0 ? (
|
{form.slots.length === 0 ? (
|
||||||
<p style={{ color: 'var(--text2)', fontSize: '0.9rem' }}>
|
<p style={{ color: 'var(--text2)', fontSize: '0.9rem' }}>
|
||||||
Noch keine Slots — mit <strong>+ Slot</strong> legst du z. B. „Woche 1 / Einheit A“ an und ordnest Übungen zu.
|
Noch keine Slots — mit <strong>+ Slot</strong> legst du Einheiten‑Spalten an (z. B. „Woche 1“, „Einheit
|
||||||
|
A“) und ordnest Übungen zu. Spalten kannst du horizontal scrollen.
|
||||||
</p>
|
</p>
|
||||||
) : null}
|
) : (
|
||||||
|
<p style={{ fontSize: '0.8rem', color: 'var(--text3)', marginBottom: '10px' }}>
|
||||||
|
Slots = geplante Einheiten/Sessions im Überblick — nach rechts scrollen, wenn es viele sind.
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<div className="framework-slots-board">
|
||||||
{form.slots.map((slot, si) => (
|
{form.slots.map((slot, si) => (
|
||||||
<div
|
<div
|
||||||
key={si}
|
key={si}
|
||||||
className="card"
|
className="card framework-slot-card"
|
||||||
style={{ marginBottom: '12px', background: 'var(--surface)', borderStyle: 'dashed' }}
|
style={{ marginBottom: 0, background: 'var(--surface)', borderStyle: 'dashed' }}
|
||||||
>
|
>
|
||||||
<div style={{ display: 'flex', flexWrap: 'wrap', gap: '6px', marginBottom: '10px' }}>
|
<div style={{ display: 'flex', flexWrap: 'wrap', gap: '6px', marginBottom: '10px' }}>
|
||||||
<button type="button" className="btn btn-secondary" onClick={() => moveSlot(si, -1)}>
|
<button type="button" className="btn btn-secondary" onClick={() => moveSlot(si, -1)}>
|
||||||
|
|
@ -845,6 +894,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}>
|
||||||
|
|
|
||||||
|
|
@ -57,7 +57,11 @@ export default function TrainingFrameworkProgramsListPage() {
|
||||||
<h1 style={{ marginBottom: '0.35rem' }}>Trainingsrahmenprogramme</h1>
|
<h1 style={{ marginBottom: '0.35rem' }}>Trainingsrahmenprogramme</h1>
|
||||||
<p style={{ color: 'var(--text2)', fontSize: '0.95rem', maxWidth: '36rem' }}>
|
<p style={{ color: 'var(--text2)', fontSize: '0.95rem', maxWidth: '36rem' }}>
|
||||||
Mehrere Entwicklungsziele und Übungen über Session‑Slots verteilen — als Vorlage in der Bibliothek oder
|
Mehrere Entwicklungsziele und Übungen über Session‑Slots verteilen — als Vorlage in der Bibliothek oder
|
||||||
im Kontext einer Gruppe.
|
im Kontext einer Gruppe.{' '}
|
||||||
|
<span style={{ color: 'var(--text3)', fontSize: '0.88rem' }}>
|
||||||
|
In der <strong>Bearbeitungsansicht</strong> gibt es auf schmalen Fenstern Registerkarten, auf breiten
|
||||||
|
Bildschirmen zwei Spalten (Ziele | Slots).
|
||||||
|
</span>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<Link
|
<Link
|
||||||
|
|
|
||||||
|
|
@ -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.1.0",
|
TrainingFrameworkProgramEditPage: "1.2.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