feat: enhance UI and functionality in Training Framework pages
Some checks failed
Deploy Development / deploy (push) Successful in 35s
Test Suite / pytest-backend (push) Successful in 7s
Test Suite / lint-backend (push) Successful in 0s
Test Suite / build-frontend (push) Successful in 6s
Test Suite / playwright-tests (push) Failing after 53s
Some checks failed
Deploy Development / deploy (push) Successful in 35s
Test Suite / pytest-backend (push) Successful in 7s
Test Suite / lint-backend (push) Successful in 0s
Test Suite / build-frontend (push) Successful in 6s
Test Suite / playwright-tests (push) Failing after 53s
- Added new CSS styles for segment buttons and admin assignment matrix, improving layout and responsiveness. - Refactored AssignmentsTab component to utilize new styles and improve accessibility with aria-labels. - Introduced collapsible details for framework edit introduction, enhancing user guidance. - Updated TrainingPlanningPage to streamline button styling and improve visual consistency across components.
This commit is contained in:
parent
14884e6e55
commit
18a58cb5a5
|
|
@ -1213,6 +1213,22 @@ button.capture-shell__nav-item {
|
||||||
border-left: 1.5px solid var(--border2);
|
border-left: 1.5px solid var(--border2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Gleich breite Segment-Buttons (z. B. mobile Rahmenprogramm-Tabs) */
|
||||||
|
.planning-segment-group--equal {
|
||||||
|
flex: 1;
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
.planning-segment-group--equal .planning-segment-group__btn {
|
||||||
|
flex: 1;
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Etwas größere Segmente (Planung: Liste / Kalender) */
|
||||||
|
.planning-segment-group--comfort .planning-segment-group__btn {
|
||||||
|
padding: 10px 18px;
|
||||||
|
font-size: 0.92rem;
|
||||||
|
}
|
||||||
|
|
||||||
/* Ausklappbare Kontext-Hilfe (Filterzeile Planung) */
|
/* Ausklappbare Kontext-Hilfe (Filterzeile Planung) */
|
||||||
.planning-filter-help {
|
.planning-filter-help {
|
||||||
flex: 1 1 100%;
|
flex: 1 1 100%;
|
||||||
|
|
@ -1246,6 +1262,109 @@ button.capture-shell__nav-item {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Rahmenprogramm-Editor: Kurz-Einstieg ausklappbar */
|
||||||
|
.framework-edit-intro {
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
}
|
||||||
|
.framework-edit-intro__summary {
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 0.88rem;
|
||||||
|
font-weight: 600;
|
||||||
|
color: var(--accent-dark);
|
||||||
|
list-style: none;
|
||||||
|
user-select: none;
|
||||||
|
padding: 10px 12px;
|
||||||
|
border-radius: 10px;
|
||||||
|
border: 1px dashed var(--border2);
|
||||||
|
background: var(--surface2);
|
||||||
|
}
|
||||||
|
.framework-edit-intro__summary::-webkit-details-marker {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
.framework-edit-intro__body {
|
||||||
|
margin-top: 10px;
|
||||||
|
padding: 12px 14px;
|
||||||
|
font-size: 0.88rem;
|
||||||
|
line-height: 1.55;
|
||||||
|
color: var(--text2);
|
||||||
|
border-radius: 10px;
|
||||||
|
border: 1px solid var(--border);
|
||||||
|
background: var(--surface);
|
||||||
|
}
|
||||||
|
@media (prefers-color-scheme: dark) {
|
||||||
|
.framework-edit-intro__summary {
|
||||||
|
color: var(--accent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Admin: Zuordnungsmatrix (Stilrichtungen ↔ Zielgruppen) */
|
||||||
|
.admin-assignments-wrap {
|
||||||
|
background: var(--surface);
|
||||||
|
border-radius: 12px;
|
||||||
|
padding: 20px;
|
||||||
|
}
|
||||||
|
.admin-assignments-wrap__title {
|
||||||
|
margin-top: 0;
|
||||||
|
font-size: 1.15rem;
|
||||||
|
font-weight: 700;
|
||||||
|
}
|
||||||
|
.admin-assignments-matrix-container {
|
||||||
|
overflow-x: auto;
|
||||||
|
margin-top: 20px;
|
||||||
|
-webkit-overflow-scrolling: touch;
|
||||||
|
}
|
||||||
|
.admin-assignments-matrix {
|
||||||
|
width: 100%;
|
||||||
|
border-collapse: collapse;
|
||||||
|
min-width: 600px;
|
||||||
|
}
|
||||||
|
.admin-assignments-matrix th,
|
||||||
|
.admin-assignments-matrix td {
|
||||||
|
border: 1px solid var(--border);
|
||||||
|
padding: 12px;
|
||||||
|
}
|
||||||
|
.admin-assignments-matrix th {
|
||||||
|
background: var(--surface2);
|
||||||
|
font-weight: 600;
|
||||||
|
color: var(--text1);
|
||||||
|
}
|
||||||
|
.admin-assignments-matrix__corner {
|
||||||
|
position: sticky;
|
||||||
|
left: 0;
|
||||||
|
background: var(--surface);
|
||||||
|
z-index: 2;
|
||||||
|
}
|
||||||
|
.admin-assignments-matrix__row-label {
|
||||||
|
position: sticky;
|
||||||
|
left: 0;
|
||||||
|
background: var(--surface);
|
||||||
|
z-index: 1;
|
||||||
|
padding: 12px;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
.admin-assignments-matrix tbody tr:hover {
|
||||||
|
background: var(--surface2);
|
||||||
|
}
|
||||||
|
.admin-assignments-matrix__focus-header td {
|
||||||
|
background: var(--surface2);
|
||||||
|
padding: 8px 12px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: var(--text2);
|
||||||
|
}
|
||||||
|
.admin-assignments-matrix__th-narrow {
|
||||||
|
text-align: center;
|
||||||
|
padding: 12px;
|
||||||
|
}
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
.admin-assignments-matrix {
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
.admin-assignments-matrix th,
|
||||||
|
.admin-assignments-matrix td {
|
||||||
|
padding: 8px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Admin: Split-Layout wie .analysis-split (nur Gruppen in der Nav) */
|
/* Admin: Split-Layout wie .analysis-split (nur Gruppen in der Nav) */
|
||||||
.admin-shell {
|
.admin-shell {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
|
@ -2962,36 +3081,26 @@ button.capture-shell__nav-item {
|
||||||
}
|
}
|
||||||
.framework-edit__tabbar {
|
.framework-edit__tabbar {
|
||||||
display: flex;
|
display: flex;
|
||||||
gap: 6px;
|
align-items: stretch;
|
||||||
|
gap: 8px;
|
||||||
margin-bottom: 14px;
|
margin-bottom: 14px;
|
||||||
padding: 2px 0 12px;
|
padding: 6px 0 12px;
|
||||||
border-bottom: 1px solid var(--border);
|
border-bottom: 1px solid var(--border);
|
||||||
flex-wrap: nowrap;
|
flex-wrap: nowrap;
|
||||||
overflow-x: auto;
|
overflow-x: auto;
|
||||||
-webkit-overflow-scrolling: touch;
|
-webkit-overflow-scrolling: touch;
|
||||||
scrollbar-width: none;
|
scrollbar-width: none;
|
||||||
|
position: sticky;
|
||||||
|
top: 0;
|
||||||
|
z-index: 6;
|
||||||
|
background: var(--bg);
|
||||||
}
|
}
|
||||||
.framework-edit__tabbar::-webkit-scrollbar {
|
.framework-edit__tabbar::-webkit-scrollbar {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
.framework-edit__tab {
|
.framework-edit__tabbar .planning-segment-group {
|
||||||
flex: 1 1 0;
|
flex: 1;
|
||||||
min-width: 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__plan-stack {
|
.framework-edit__plan-stack {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|
|
||||||
|
|
@ -5,22 +5,24 @@ function AssignmentsTab({ styleDirections, targetGroups, assignments, loading, e
|
||||||
const [saving, setSaving] = useState(false)
|
const [saving, setSaving] = useState(false)
|
||||||
|
|
||||||
if (loading) {
|
if (loading) {
|
||||||
return <div style={{ textAlign: 'center', padding: '40px' }}><div className="spinner"></div></div>
|
return (
|
||||||
|
<div className="empty-state" style={{ padding: '2.5rem' }}>
|
||||||
|
<div className="spinner" />
|
||||||
|
</div>
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
async function toggleAssignment(styleDirectionId, targetGroupId, currentlyAssigned) {
|
async function toggleAssignment(styleDirectionId, targetGroupId, currentlyAssigned) {
|
||||||
setSaving(true)
|
setSaving(true)
|
||||||
try {
|
try {
|
||||||
if (currentlyAssigned) {
|
if (currentlyAssigned) {
|
||||||
// Find and delete the assignment
|
|
||||||
const assignment = assignments.find(
|
const assignment = assignments.find(
|
||||||
a => a.style_direction_id === styleDirectionId && a.target_group_id === targetGroupId
|
(a) => a.style_direction_id === styleDirectionId && a.target_group_id === targetGroupId
|
||||||
)
|
)
|
||||||
if (assignment) {
|
if (assignment) {
|
||||||
await api.deleteStyleDirectionTargetGroup(assignment.id)
|
await api.deleteStyleDirectionTargetGroup(assignment.id)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Create new assignment
|
|
||||||
await api.createStyleDirectionTargetGroup({
|
await api.createStyleDirectionTargetGroup({
|
||||||
style_direction_id: styleDirectionId,
|
style_direction_id: styleDirectionId,
|
||||||
target_group_id: targetGroupId,
|
target_group_id: targetGroupId,
|
||||||
|
|
@ -37,11 +39,10 @@ function AssignmentsTab({ styleDirections, targetGroups, assignments, loading, e
|
||||||
|
|
||||||
function isAssigned(styleDirectionId, targetGroupId) {
|
function isAssigned(styleDirectionId, targetGroupId) {
|
||||||
return assignments.some(
|
return assignments.some(
|
||||||
a => a.style_direction_id === styleDirectionId && a.target_group_id === targetGroupId
|
(a) => a.style_direction_id === styleDirectionId && a.target_group_id === targetGroupId
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Group style directions by focus area
|
|
||||||
const groupedStyles = styleDirections.reduce((acc, sd) => {
|
const groupedStyles = styleDirections.reduce((acc, sd) => {
|
||||||
const key = sd.focus_area_name || 'Ohne Fokusbereich'
|
const key = sd.focus_area_name || 'Ohne Fokusbereich'
|
||||||
if (!acc[key]) acc[key] = []
|
if (!acc[key]) acc[key] = []
|
||||||
|
|
@ -50,30 +51,30 @@ function AssignmentsTab({ styleDirections, targetGroups, assignments, loading, e
|
||||||
}, {})
|
}, {})
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div style={{ background: 'var(--surface)', borderRadius: '12px', padding: '20px' }}>
|
<div className="admin-assignments-wrap">
|
||||||
<h2 style={{ marginTop: 0 }}>Zuordnungen: Stilrichtungen ↔ Zielgruppen</h2>
|
<h2 className="admin-assignments-wrap__title">Zuordnungen: Stilrichtungen ↔ Zielgruppen</h2>
|
||||||
{error && <div style={{ color: 'var(--danger)', padding: '16px', background: 'var(--surface2)', borderRadius: '8px', marginBottom: '16px' }}>{error}</div>}
|
{error && <div className="admin-matrix-alert">{error}</div>}
|
||||||
|
|
||||||
{targetGroups.length === 0 && (
|
{targetGroups.length === 0 && (
|
||||||
<div style={{ textAlign: 'center', color: 'var(--text3)', padding: '40px' }}>
|
<div className="empty-state" style={{ padding: '2rem 1rem' }}>
|
||||||
Keine Zielgruppen vorhanden. Bitte erst im Tab "Kataloge" anlegen.
|
Keine Zielgruppen vorhanden. Bitte zuerst unter <strong>Kataloge</strong> anlegen.
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{styleDirections.length === 0 && (
|
{styleDirections.length === 0 && (
|
||||||
<div style={{ textAlign: 'center', color: 'var(--text3)', padding: '40px' }}>
|
<div className="empty-state" style={{ padding: '2rem 1rem' }}>
|
||||||
Keine Stilrichtungen vorhanden. Bitte erst im Tab "Hierarchie" anlegen.
|
Keine Stilrichtungen vorhanden. Bitte zuerst unter <strong>Hierarchie</strong> anlegen.
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{targetGroups.length > 0 && styleDirections.length > 0 && (
|
{targetGroups.length > 0 && styleDirections.length > 0 && (
|
||||||
<div className="assignment-matrix-container">
|
<div className="admin-assignments-matrix-container">
|
||||||
<table className="assignment-matrix">
|
<table className="admin-assignments-matrix">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th style={{ position: 'sticky', left: 0, background: 'var(--surface)', zIndex: 2 }}>Stilrichtung</th>
|
<th className="admin-assignments-matrix__corner">Stilrichtung</th>
|
||||||
{targetGroups.map(tg => (
|
{targetGroups.map((tg) => (
|
||||||
<th key={tg.id} style={{ textAlign: 'center', padding: '12px' }}>
|
<th key={tg.id} className="admin-assignments-matrix__th-narrow">
|
||||||
{tg.name}
|
{tg.name}
|
||||||
</th>
|
</th>
|
||||||
))}
|
))}
|
||||||
|
|
@ -82,17 +83,18 @@ function AssignmentsTab({ styleDirections, targetGroups, assignments, loading, e
|
||||||
<tbody>
|
<tbody>
|
||||||
{Object.entries(groupedStyles).map(([focusAreaName, styles]) => (
|
{Object.entries(groupedStyles).map(([focusAreaName, styles]) => (
|
||||||
<React.Fragment key={focusAreaName}>
|
<React.Fragment key={focusAreaName}>
|
||||||
<tr className="focus-area-header">
|
<tr>
|
||||||
<td colSpan={targetGroups.length + 1} style={{ background: 'var(--surface2)', padding: '8px 12px', fontWeight: 600, color: 'var(--text2)' }}>
|
<td
|
||||||
|
className="admin-assignments-matrix__focus-header"
|
||||||
|
colSpan={targetGroups.length + 1}
|
||||||
|
>
|
||||||
{focusAreaName}
|
{focusAreaName}
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
{styles.map(sd => (
|
{styles.map((sd) => (
|
||||||
<tr key={sd.id}>
|
<tr key={sd.id}>
|
||||||
<td style={{ position: 'sticky', left: 0, background: 'var(--surface)', zIndex: 1, padding: '12px', fontWeight: 500 }}>
|
<td className="admin-assignments-matrix__row-label">{sd.name}</td>
|
||||||
{sd.name}
|
{targetGroups.map((tg) => {
|
||||||
</td>
|
|
||||||
{targetGroups.map(tg => {
|
|
||||||
const assigned = isAssigned(sd.id, tg.id)
|
const assigned = isAssigned(sd.id, tg.id)
|
||||||
return (
|
return (
|
||||||
<td key={tg.id} style={{ textAlign: 'center', padding: '12px' }}>
|
<td key={tg.id} style={{ textAlign: 'center', padding: '12px' }}>
|
||||||
|
|
@ -101,7 +103,8 @@ function AssignmentsTab({ styleDirections, targetGroups, assignments, loading, e
|
||||||
checked={assigned}
|
checked={assigned}
|
||||||
onChange={() => toggleAssignment(sd.id, tg.id, assigned)}
|
onChange={() => toggleAssignment(sd.id, tg.id, assigned)}
|
||||||
disabled={saving}
|
disabled={saving}
|
||||||
style={{ width: '20px', height: '20px', cursor: 'pointer' }}
|
aria-label={`${sd.name} — ${tg.name}`}
|
||||||
|
style={{ width: '20px', height: '20px', cursor: 'pointer', accentColor: 'var(--accent)' }}
|
||||||
/>
|
/>
|
||||||
</td>
|
</td>
|
||||||
)
|
)
|
||||||
|
|
@ -114,45 +117,6 @@ function AssignmentsTab({ styleDirections, targetGroups, assignments, loading, e
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<style>{`
|
|
||||||
.assignment-matrix-container {
|
|
||||||
overflow-x: auto;
|
|
||||||
margin-top: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.assignment-matrix {
|
|
||||||
width: 100%;
|
|
||||||
border-collapse: collapse;
|
|
||||||
min-width: 600px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.assignment-matrix th,
|
|
||||||
.assignment-matrix td {
|
|
||||||
border: 1px solid var(--border);
|
|
||||||
padding: 12px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.assignment-matrix th {
|
|
||||||
background: var(--surface2);
|
|
||||||
font-weight: 600;
|
|
||||||
color: var(--text1);
|
|
||||||
}
|
|
||||||
|
|
||||||
.assignment-matrix tbody tr:hover {
|
|
||||||
background: var(--surface2);
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (max-width: 768px) {
|
|
||||||
.assignment-matrix {
|
|
||||||
font-size: 14px;
|
|
||||||
}
|
|
||||||
.assignment-matrix th,
|
|
||||||
.assignment-matrix td {
|
|
||||||
padding: 8px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`}</style>
|
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -663,37 +663,20 @@ export default function TrainingFrameworkProgramEditPage() {
|
||||||
|
|
||||||
<h1 style={{ marginBottom: '0.75rem' }}>{isNew ? 'Neues Rahmenprogramm' : 'Rahmenprogramm bearbeiten'}</h1>
|
<h1 style={{ marginBottom: '0.75rem' }}>{isNew ? 'Neues Rahmenprogramm' : 'Rahmenprogramm bearbeiten'}</h1>
|
||||||
|
|
||||||
<div className="card" style={{ marginBottom: '1rem', background: 'var(--surface2)', borderStyle: 'dashed' }}>
|
<details className="framework-edit-intro">
|
||||||
<p style={{ fontSize: '0.88rem', color: 'var(--text2)', lineHeight: 1.55, margin: 0 }}>
|
<summary className="framework-edit-intro__summary">
|
||||||
|
Kurz erklärt: Was ist ein Rahmenprogramm?
|
||||||
|
</summary>
|
||||||
|
<div className="framework-edit-intro__body">
|
||||||
<strong style={{ color: 'var(--text1)' }}>Rahmenprogramm (Bibliothek):</strong> Wiederverwendbare Vorlage mit
|
<strong style={{ color: 'var(--text1)' }}>Rahmenprogramm (Bibliothek):</strong> Wiederverwendbare Vorlage mit
|
||||||
Zielen und Session‑Slots. <strong>Zuordnung zu Gruppe oder Kalendertermin</strong> erfolgt aus der{' '}
|
Zielen und Session‑Slots. Die <strong>Zuordnung zu Gruppe oder Kalendertermin</strong> erfolgt aus der{' '}
|
||||||
<strong>Gruppen‑Planung</strong> („Übernahme“). Pro Slot planst du den Ablauf wie bei einer Trainingsseinheit:{' '}
|
<strong>Gruppen‑Planung</strong> („Übernahme“). Pro Slot planst du den Ablauf wie bei einer Trainingsseinheit:{' '}
|
||||||
<strong>Abschnitte</strong>, Übungen mit Varianten und Dauer, <strong>Zwischen‑Anmerkungen</strong>.
|
<strong>Abschnitte</strong>, Übungen mit Varianten und Dauer, <strong>Zwischen‑Anmerkungen</strong>.
|
||||||
</p>
|
|
||||||
</div>
|
</div>
|
||||||
|
</details>
|
||||||
|
|
||||||
<div
|
<div className="framework-edit__tabbar" role="tablist" aria-label="Bereiche">
|
||||||
className="framework-edit__tabbar"
|
<div className="planning-segment-group planning-segment-group--equal">
|
||||||
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: 'plan', label: 'Plan (Ziele & Sessions)' },
|
{ id: 'plan', label: 'Plan (Ziele & Sessions)' },
|
||||||
|
|
@ -703,13 +686,17 @@ export default function TrainingFrameworkProgramEditPage() {
|
||||||
type="button"
|
type="button"
|
||||||
role="tab"
|
role="tab"
|
||||||
aria-selected={frameworkTab === t.id}
|
aria-selected={frameworkTab === t.id}
|
||||||
className={'framework-edit__tab' + (frameworkTab === t.id ? ' framework-edit__tab--active' : '')}
|
className={
|
||||||
|
'planning-segment-group__btn' +
|
||||||
|
(frameworkTab === t.id ? ' planning-segment-group__btn--active' : '')
|
||||||
|
}
|
||||||
onClick={() => setFrameworkTab(t.id)}
|
onClick={() => setFrameworkTab(t.id)}
|
||||||
>
|
>
|
||||||
{t.label}
|
{t.label}
|
||||||
</button>
|
</button>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
className={
|
className={
|
||||||
|
|
|
||||||
|
|
@ -100,12 +100,23 @@ export default function TrainingFrameworkProgramsListPage() {
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div>
|
<div>
|
||||||
<h1 style={{ marginBottom: '0.35rem' }}>Trainingsrahmenprogramme</h1>
|
<h1 className="page-title" style={{ marginBottom: '0.35rem' }}>
|
||||||
<p style={{ color: 'var(--text2)', fontSize: '0.95rem', maxWidth: '36rem' }}>
|
Trainingsrahmenprogramme
|
||||||
Wiederverwendbare Vorlagen für Ziele und Sessions. Die Verknüpfung mit{' '}
|
</h1>
|
||||||
<strong>konkreten Gruppeneinheiten</strong> erfolgt aus der <strong>Planung der Gruppe</strong> (Übernahme
|
<p style={{ color: 'var(--text2)', fontSize: '0.95rem', maxWidth: '36rem', margin: 0 }}>
|
||||||
mit Bezug zum Rahmen).
|
Vorlagen für Ziele und Sessions — die Verknüpfung mit Gruppenterminen erfolgt in der{' '}
|
||||||
|
<Link to="/planning" style={{ fontWeight: 600, color: 'var(--accent-dark)' }}>
|
||||||
|
Trainingsplanung
|
||||||
|
</Link>
|
||||||
|
.
|
||||||
</p>
|
</p>
|
||||||
|
<details className="planning-filter-help" style={{ marginTop: '10px', maxWidth: '36rem' }}>
|
||||||
|
<summary className="planning-filter-help__summary">Mehr zur Übernahme in die Planung</summary>
|
||||||
|
<div className="planning-filter-help__body">
|
||||||
|
Unter <strong>Planung</strong> wählst du eine Gruppe und übernimmst Slots aus einem Rahmenprogramm in
|
||||||
|
echte Termine. So bleibt die Bibliothek wiederverwendbar, ohne dass Einzelgruppen fest verdrahtet sind.
|
||||||
|
</div>
|
||||||
|
</details>
|
||||||
</div>
|
</div>
|
||||||
<Link
|
<Link
|
||||||
to="/planning/framework-programs/new"
|
to="/planning/framework-programs/new"
|
||||||
|
|
|
||||||
|
|
@ -865,31 +865,18 @@ function TrainingPlanningPage() {
|
||||||
Ansicht
|
Ansicht
|
||||||
</span>
|
</span>
|
||||||
<div
|
<div
|
||||||
|
className="planning-segment-group planning-segment-group--comfort"
|
||||||
role="group"
|
role="group"
|
||||||
aria-label="Darstellung Liste oder Kalender"
|
aria-label="Darstellung Liste oder Kalender"
|
||||||
style={{
|
|
||||||
display: 'inline-flex',
|
|
||||||
borderRadius: '10px',
|
|
||||||
border: '1.5px solid var(--border2)',
|
|
||||||
overflow: 'hidden',
|
|
||||||
background: 'var(--surface2)',
|
|
||||||
boxSizing: 'border-box',
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
aria-pressed={planView === 'list'}
|
aria-pressed={planView === 'list'}
|
||||||
onClick={() => setPlanView('list')}
|
onClick={() => setPlanView('list')}
|
||||||
style={{
|
className={
|
||||||
border: 'none',
|
'planning-segment-group__btn' +
|
||||||
padding: '10px 20px',
|
(planView === 'list' ? ' planning-segment-group__btn--active' : '')
|
||||||
fontWeight: 600,
|
}
|
||||||
fontSize: '0.92rem',
|
|
||||||
cursor: 'pointer',
|
|
||||||
background: planView === 'list' ? 'var(--accent-dark)' : 'transparent',
|
|
||||||
color: planView === 'list' ? '#fff' : 'var(--text1)',
|
|
||||||
whiteSpace: 'nowrap',
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
Liste
|
Liste
|
||||||
</button>
|
</button>
|
||||||
|
|
@ -904,17 +891,10 @@ function TrainingPlanningPage() {
|
||||||
return prev || new Date().toISOString().slice(0, 7)
|
return prev || new Date().toISOString().slice(0, 7)
|
||||||
})
|
})
|
||||||
}}
|
}}
|
||||||
style={{
|
className={
|
||||||
border: 'none',
|
'planning-segment-group__btn' +
|
||||||
borderLeft: '1.5px solid var(--border2)',
|
(planView === 'calendar' ? ' planning-segment-group__btn--active' : '')
|
||||||
padding: '10px 20px',
|
}
|
||||||
fontWeight: 600,
|
|
||||||
fontSize: '0.92rem',
|
|
||||||
cursor: 'pointer',
|
|
||||||
background: planView === 'calendar' ? 'var(--accent-dark)' : 'transparent',
|
|
||||||
color: planView === 'calendar' ? '#fff' : 'var(--text1)',
|
|
||||||
whiteSpace: 'nowrap',
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
Kalender
|
Kalender
|
||||||
</button>
|
</button>
|
||||||
|
|
@ -927,8 +907,8 @@ function TrainingPlanningPage() {
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<p style={{ color: 'var(--text2)', fontSize: '0.95rem', marginBottom: '1.25rem' }}>
|
<p style={{ color: 'var(--text2)', fontSize: '0.95rem', marginBottom: '1.25rem' }}>
|
||||||
Wähle eine Trainingsgruppe, lege dann Termine mit Inhalt (Abschnitte und Übungen) an — ein Plan entsteht aus einer oder mehreren{' '}
|
Wähle eine Trainingsgruppe und lege <strong>Trainingseinheiten</strong> für den Zeitraum an (Inhalt: Abschnitte
|
||||||
<strong>Trainingseinheiten</strong> im gewählten Zeitraum.
|
und Übungen).
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<div className="card" style={{ marginBottom: '1.25rem', padding: '12px 14px' }}>
|
<div className="card" style={{ marginBottom: '1.25rem', padding: '12px 14px' }}>
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user