refactor: enhance layout and responsiveness across multiple pages
- Updated app.css to improve responsive design, introducing new classes for consistent page widths and grid layouts. - Refactored various page components to utilize the new layout classes, ensuring better adaptability on different screen sizes. - Adjusted padding and margin properties for improved visual consistency and user experience across the application.
This commit is contained in:
parent
b1af59b134
commit
83ee300192
|
|
@ -71,6 +71,76 @@ body { font-family: var(--font); background: var(--bg); color: var(--text1); -we
|
|||
}
|
||||
}
|
||||
.app-logo { font-size: 18px; font-weight: 700; color: var(--accent); letter-spacing: -0.02em; }
|
||||
|
||||
/* === Seiten-Inhalt: einheitlich volle Breite bis 1023px; ab Desktop optionale Max-Breite === */
|
||||
.app-page {
|
||||
width: 100%;
|
||||
max-width: 100%;
|
||||
min-width: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
@media (min-width: 1024px) {
|
||||
.app-page--constrained-lg {
|
||||
max-width: 1200px;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
}
|
||||
.app-page--constrained-md {
|
||||
max-width: 900px;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
}
|
||||
.app-page--constrained-sm {
|
||||
max-width: 720px;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
}
|
||||
.app-page--reading {
|
||||
max-width: 640px;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
}
|
||||
}
|
||||
|
||||
/* Form-Grids: minmax(0,…) verhindert Grid-Overflow; eine Spalte bis zum ersten Breakpoint */
|
||||
.responsive-grid-2 {
|
||||
display: grid;
|
||||
gap: 12px;
|
||||
grid-template-columns: minmax(0, 1fr);
|
||||
}
|
||||
@media (min-width: 480px) {
|
||||
.responsive-grid-2 {
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
}
|
||||
}
|
||||
|
||||
.responsive-grid-3 {
|
||||
display: grid;
|
||||
gap: 1rem;
|
||||
grid-template-columns: minmax(0, 1fr);
|
||||
}
|
||||
@media (min-width: 560px) {
|
||||
.responsive-grid-3 {
|
||||
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||||
}
|
||||
}
|
||||
|
||||
.responsive-grid-4 {
|
||||
display: grid;
|
||||
gap: 1rem;
|
||||
grid-template-columns: minmax(0, 1fr);
|
||||
}
|
||||
@media (min-width: 560px) {
|
||||
.responsive-grid-4 {
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
}
|
||||
}
|
||||
@media (min-width: 900px) {
|
||||
.responsive-grid-4 {
|
||||
grid-template-columns: repeat(4, minmax(0, 1fr));
|
||||
}
|
||||
}
|
||||
/* unten: Tab-Leiste + Abstand nach oben zur Leiste + Home-Indicator (iPhone) */
|
||||
.app-main {
|
||||
flex: 1;
|
||||
|
|
@ -163,6 +233,7 @@ body { font-family: var(--font); background: var(--bg); color: var(--text1); -we
|
|||
gap: 8px;
|
||||
padding: 0;
|
||||
margin-bottom: 16px;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.form-label {
|
||||
|
|
@ -183,6 +254,7 @@ body { font-family: var(--font); background: var(--bg); color: var(--text1); -we
|
|||
|
||||
.form-input {
|
||||
width: 100%;
|
||||
min-width: 0;
|
||||
padding: 10px 12px;
|
||||
text-align: left;
|
||||
font-family: var(--font);
|
||||
|
|
@ -2741,14 +2813,16 @@ a.analysis-split__nav-item {
|
|||
|
||||
/* Rahmenprogramm bearbeiten — Mobile: Stammdaten | Plan; Desktop: untereinander Ziele → Slots (synchron zu FRAMEWORK_DESKTOP_MIN_PX) */
|
||||
.framework-edit {
|
||||
max-width: 800px;
|
||||
margin: 0 auto;
|
||||
max-width: 100%;
|
||||
margin: 0;
|
||||
width: 100%;
|
||||
min-width: 0;
|
||||
}
|
||||
@media (min-width: 900px) {
|
||||
.framework-edit {
|
||||
max-width: min(1200px, 100%);
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
}
|
||||
.framework-edit__tabbar {
|
||||
display: none !important;
|
||||
|
|
@ -2834,6 +2908,12 @@ a.analysis-split__nav-item {
|
|||
scrollbar-gutter: stable;
|
||||
}
|
||||
|
||||
@media (max-width: 1023px) {
|
||||
.framework-slots-board-outer {
|
||||
scrollbar-gutter: auto;
|
||||
}
|
||||
}
|
||||
|
||||
.framework-slots-board {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
|
|
|
|||
|
|
@ -98,7 +98,7 @@ function AccountSettingsPage() {
|
|||
}
|
||||
|
||||
return (
|
||||
<div className="page-padding" style={{ padding: '1rem', maxWidth: '640px', margin: '0 auto' }}>
|
||||
<div className="page-padding app-page app-page--reading" style={{ padding: '1rem' }}>
|
||||
<h1 style={{ marginBottom: '0.35rem', fontSize: '1.5rem' }}>Einstellungen</h1>
|
||||
<p style={{ color: 'var(--text2)', marginBottom: '1.25rem', fontSize: '0.95rem' }}>
|
||||
Konto & Sicherheit
|
||||
|
|
|
|||
|
|
@ -313,7 +313,7 @@ export default function AdminCatalogsPage() {
|
|||
}
|
||||
|
||||
return (
|
||||
<div style={{ padding: '16px', maxWidth: '1200px', margin: '0 auto' }}>
|
||||
<div className="app-page app-page--constrained-lg">
|
||||
<AdminPageNav />
|
||||
|
||||
<h1 style={{ marginBottom: '24px' }}>Stammdaten-Kataloge</h1>
|
||||
|
|
|
|||
|
|
@ -93,7 +93,7 @@ function AdminHierarchyPage() {
|
|||
]
|
||||
|
||||
return (
|
||||
<div style={{ padding: '20px' }}>
|
||||
<div className="app-page app-page--constrained-lg">
|
||||
<AdminPageNav />
|
||||
|
||||
<h1 style={{ marginTop: 0 }}>Admin: Katalog-Hierarchie</h1>
|
||||
|
|
|
|||
|
|
@ -143,8 +143,7 @@ function ClubsPage() {
|
|||
}
|
||||
|
||||
return (
|
||||
<div style={{ padding: '2rem' }}>
|
||||
<div style={{ maxWidth: '1200px', margin: '0 auto' }}>
|
||||
<div className="app-page app-page--constrained-lg">
|
||||
<h1 style={{ marginBottom: '0.75rem' }}>Vereinsverwaltung</h1>
|
||||
<p style={{ color: 'var(--text2)', marginBottom: '1.35rem', maxWidth: '46rem', lineHeight: 1.55 }}>
|
||||
Für die Trainingsplanung wird mindestens ein <strong>Verein</strong> und eine <strong>Trainingsgruppe</strong> gebraucht.
|
||||
|
|
@ -696,7 +695,6 @@ function ClubsPage() {
|
|||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ function Dashboard() {
|
|||
|
||||
if (loading) {
|
||||
return (
|
||||
<div style={{ padding: '2rem', textAlign: 'center' }}>
|
||||
<div className="app-page" style={{ padding: '2rem 0', textAlign: 'center' }}>
|
||||
<div className="spinner"></div>
|
||||
<p>Laden...</p>
|
||||
</div>
|
||||
|
|
@ -38,8 +38,7 @@ function Dashboard() {
|
|||
}
|
||||
|
||||
return (
|
||||
<div style={{ minHeight: '100vh', background: 'var(--bg)', padding: '2rem' }}>
|
||||
<div style={{ maxWidth: '1200px', margin: '0 auto' }}>
|
||||
<div className="app-page app-page--constrained-lg">
|
||||
<h1>Dashboard</h1>
|
||||
<p style={{ color: 'var(--text2)', marginTop: '0.5rem' }}>
|
||||
Willkommen, {user?.name || user?.email}!
|
||||
|
|
@ -56,7 +55,7 @@ function Dashboard() {
|
|||
{/* Status Grid */}
|
||||
<div style={{
|
||||
display: 'grid',
|
||||
gridTemplateColumns: 'repeat(auto-fit, minmax(300px, 1fr))',
|
||||
gridTemplateColumns: 'repeat(auto-fit, minmax(min(100%, 260px), 1fr))',
|
||||
gap: '1rem',
|
||||
marginBottom: '1.5rem'
|
||||
}}>
|
||||
|
|
@ -122,7 +121,6 @@ function Dashboard() {
|
|||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -144,7 +144,7 @@ function ExerciseDetailPage() {
|
|||
if (error) {
|
||||
const msg = error.message || String(error)
|
||||
return (
|
||||
<div style={{ padding: '1rem', maxWidth: '640px', margin: '0 auto' }}>
|
||||
<div style={{ padding: '1rem' }} className="app-page app-page--reading">
|
||||
<div className="card">
|
||||
<h2>Übung</h2>
|
||||
<p style={{ color: 'var(--danger)' }}>{msg}</p>
|
||||
|
|
|
|||
|
|
@ -699,7 +699,7 @@ function ExerciseFormPage() {
|
|||
}
|
||||
|
||||
return (
|
||||
<div style={{ padding: '12px', maxWidth: '720px', margin: '0 auto' }}>
|
||||
<div style={{ padding: '12px' }} className="app-page app-page--constrained-sm">
|
||||
<div style={{ marginBottom: '12px' }}>
|
||||
<button type="button" className="btn btn-secondary" onClick={() => navigate('/exercises')}>
|
||||
← Übersicht
|
||||
|
|
|
|||
|
|
@ -352,7 +352,7 @@ function ExercisesListPage() {
|
|||
}
|
||||
|
||||
return (
|
||||
<div style={{ padding: '12px', maxWidth: '1200px', margin: '0 auto' }}>
|
||||
<div className="app-page app-page--constrained-lg">
|
||||
<div
|
||||
style={{
|
||||
display: 'flex',
|
||||
|
|
|
|||
|
|
@ -103,7 +103,7 @@ export default function MediaWikiImportPage() {
|
|||
}
|
||||
|
||||
return (
|
||||
<div style={{ padding: '20px', maxWidth: '1200px', margin: '0 auto' }}>
|
||||
<div className="app-page app-page--constrained-lg">
|
||||
<AdminPageNav />
|
||||
|
||||
<h1>MediaWiki Import (Semantic MediaWiki)</h1>
|
||||
|
|
|
|||
|
|
@ -143,8 +143,7 @@ function SkillsPage() {
|
|||
const methodsByCategory = groupByCategory(methods)
|
||||
|
||||
return (
|
||||
<div style={{ padding: '2rem' }}>
|
||||
<div style={{ maxWidth: '1200px', margin: '0 auto' }}>
|
||||
<div className="app-page app-page--constrained-lg">
|
||||
<h1 style={{ marginBottom: '1.5rem' }}>Fähigkeiten & Methoden</h1>
|
||||
|
||||
{/* Tabs */}
|
||||
|
|
@ -509,7 +508,6 @@ function SkillsPage() {
|
|||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -95,7 +95,7 @@ export default function TrainerContextsPage() {
|
|||
}
|
||||
|
||||
return (
|
||||
<div style={{ padding: '24px', maxWidth: '1200px', margin: '0 auto' }}>
|
||||
<div className="app-page app-page--constrained-lg">
|
||||
<h1>Meine Trainer-Bereiche</h1>
|
||||
<p style={{ color: 'var(--text2)', marginBottom: '32px' }}>
|
||||
Definiere deine Tätigkeitsbereiche für fokussierte Ansichten und Filter.
|
||||
|
|
|
|||
|
|
@ -542,7 +542,7 @@ export default function TrainingFrameworkProgramEditPage() {
|
|||
|
||||
if (loading) {
|
||||
return (
|
||||
<div style={{ padding: '2rem', textAlign: 'center' }}>
|
||||
<div className="app-page" style={{ padding: '2rem 0', textAlign: 'center' }}>
|
||||
<div className="spinner" />
|
||||
<p>Laden…</p>
|
||||
</div>
|
||||
|
|
@ -550,7 +550,7 @@ export default function TrainingFrameworkProgramEditPage() {
|
|||
}
|
||||
|
||||
return (
|
||||
<div style={{ padding: '2rem' }}>
|
||||
<div className="app-page">
|
||||
<div className="framework-edit">
|
||||
<p style={{ marginBottom: '0.75rem' }}>
|
||||
<Link to="/planning/framework-programs" style={{ color: 'var(--accent-dark)' }}>
|
||||
|
|
@ -672,7 +672,7 @@ export default function TrainingFrameworkProgramEditPage() {
|
|||
</div>
|
||||
)}
|
||||
|
||||
<div className="form-row" style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: '12px' }}>
|
||||
<div className="responsive-grid-2" style={{ marginBottom: '16px' }}>
|
||||
<div>
|
||||
<label className="form-label">Zeitraum von</label>
|
||||
<input
|
||||
|
|
@ -693,7 +693,7 @@ export default function TrainingFrameworkProgramEditPage() {
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div className="form-row" style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: '12px' }}>
|
||||
<div className="responsive-grid-2" style={{ marginBottom: '16px' }}>
|
||||
<div>
|
||||
<label className="form-label">Sichtbarkeit</label>
|
||||
<select
|
||||
|
|
@ -736,6 +736,8 @@ export default function TrainingFrameworkProgramEditPage() {
|
|||
<div
|
||||
style={{
|
||||
display: 'flex',
|
||||
flexWrap: 'wrap',
|
||||
gap: '8px',
|
||||
justifyContent: 'space-between',
|
||||
alignItems: 'center',
|
||||
marginBottom: '0.75rem',
|
||||
|
|
@ -817,7 +819,7 @@ export default function TrainingFrameworkProgramEditPage() {
|
|||
</div>
|
||||
|
||||
<div className="card framework-plan-slots" style={{ marginBottom: '1.5rem' }}>
|
||||
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: '0.75rem' }}>
|
||||
<div style={{ display: 'flex', flexWrap: 'wrap', gap: '8px', justifyContent: 'space-between', alignItems: 'center', marginBottom: '0.75rem' }}>
|
||||
<h3 className="card-title" style={{ marginBottom: 0 }}>
|
||||
Session‑Slots & Übungen
|
||||
</h3>
|
||||
|
|
|
|||
|
|
@ -41,8 +41,7 @@ export default function TrainingFrameworkProgramsListPage() {
|
|||
}
|
||||
|
||||
return (
|
||||
<div style={{ padding: '2rem' }}>
|
||||
<div style={{ maxWidth: '900px', margin: '0 auto' }}>
|
||||
<div className="app-page app-page--constrained-md">
|
||||
<div
|
||||
style={{
|
||||
display: 'flex',
|
||||
|
|
@ -154,7 +153,6 @@ export default function TrainingFrameworkProgramsListPage() {
|
|||
))}
|
||||
</ul>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -524,7 +524,7 @@ function TrainingPlanningPage() {
|
|||
|
||||
if (loading) {
|
||||
return (
|
||||
<div style={{ padding: '2rem', textAlign: 'center' }}>
|
||||
<div className="app-page" style={{ padding: '2rem 0', textAlign: 'center' }}>
|
||||
<div className="spinner"></div>
|
||||
<p>Laden...</p>
|
||||
</div>
|
||||
|
|
@ -534,8 +534,7 @@ function TrainingPlanningPage() {
|
|||
const selectedGroup = groups.find((g) => g.id === parseInt(selectedGroupId, 10))
|
||||
|
||||
return (
|
||||
<div style={{ padding: '2rem' }}>
|
||||
<div style={{ maxWidth: '1200px', margin: '0 auto' }}>
|
||||
<div className="app-page app-page--constrained-lg">
|
||||
<h1 style={{ marginBottom: '0.35rem' }}>Trainingsplanung</h1>
|
||||
<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{' '}
|
||||
|
|
@ -730,12 +729,14 @@ function TrainingPlanningPage() {
|
|||
<div
|
||||
style={{
|
||||
display: 'flex',
|
||||
flexWrap: 'wrap',
|
||||
justifyContent: 'space-between',
|
||||
alignItems: 'start',
|
||||
alignItems: 'flex-start',
|
||||
gap: '12px',
|
||||
marginBottom: '1rem'
|
||||
}}
|
||||
>
|
||||
<div>
|
||||
<div style={{ minWidth: 0, flex: '1 1 200px' }}>
|
||||
<h3 style={{ marginBottom: '0.25rem' }}>
|
||||
{unit.planned_date}
|
||||
{unit.planned_time_start &&
|
||||
|
|
@ -790,7 +791,16 @@ function TrainingPlanningPage() {
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div style={{ display: 'flex', gap: '0.5rem', flexWrap: 'wrap' }}>
|
||||
<div
|
||||
style={{
|
||||
display: 'flex',
|
||||
gap: '0.5rem',
|
||||
flexWrap: 'wrap',
|
||||
justifyContent: 'flex-end',
|
||||
flex: '1 1 180px',
|
||||
minWidth: 0
|
||||
}}
|
||||
>
|
||||
<Link
|
||||
to={`/planning/run/${unit.id}`}
|
||||
className="btn btn-secondary"
|
||||
|
|
@ -849,12 +859,14 @@ function TrainingPlanningPage() {
|
|||
style={{
|
||||
background: 'var(--surface)',
|
||||
borderRadius: '12px',
|
||||
padding: '2rem',
|
||||
maxWidth: '960px',
|
||||
padding: 'clamp(12px, 3vw, 2rem)',
|
||||
maxWidth: 'min(960px, 100%)',
|
||||
width: '100%',
|
||||
maxHeight: '92vh',
|
||||
overflowY: 'auto',
|
||||
margin: '1rem'
|
||||
margin: 'max(0px, env(safe-area-inset-top, 0px)) auto',
|
||||
boxSizing: 'border-box',
|
||||
minWidth: 0
|
||||
}}
|
||||
>
|
||||
<h2 style={{ marginBottom: '1rem' }}>
|
||||
|
|
@ -885,14 +897,7 @@ function TrainingPlanningPage() {
|
|||
<form onSubmit={handleSubmit}>
|
||||
<h3 style={{ marginBottom: '1rem' }}>Planung</h3>
|
||||
|
||||
<div
|
||||
style={{
|
||||
display: 'grid',
|
||||
gridTemplateColumns: '1fr 1fr 1fr',
|
||||
gap: '1rem',
|
||||
marginBottom: '1rem'
|
||||
}}
|
||||
>
|
||||
<div className="responsive-grid-3" style={{ marginBottom: '1rem' }}>
|
||||
<div className="form-row">
|
||||
<label className="form-label">Datum *</label>
|
||||
<input
|
||||
|
|
@ -1064,12 +1069,13 @@ function TrainingPlanningPage() {
|
|||
key={`ex-${sIdx}-${iIdx}`}
|
||||
style={{
|
||||
display: 'grid',
|
||||
gridTemplateColumns: '32px minmax(0,1fr) 88px auto',
|
||||
gridTemplateColumns: '32px minmax(0, 1fr) minmax(0, 72px) 40px',
|
||||
gap: '6px',
|
||||
alignItems: 'start',
|
||||
marginTop: '0.75rem',
|
||||
paddingTop: '0.5rem',
|
||||
borderTop: '1px solid rgba(0,0,0,0.06)'
|
||||
borderTop: '1px solid rgba(0,0,0,0.06)',
|
||||
minWidth: 0
|
||||
}}
|
||||
>
|
||||
<div style={{ display: 'flex', flexDirection: 'column', paddingTop: '6px' }}>
|
||||
|
|
@ -1267,14 +1273,7 @@ function TrainingPlanningPage() {
|
|||
<>
|
||||
<h3 style={{ marginTop: '0.5rem', marginBottom: '1rem' }}>Durchführung</h3>
|
||||
|
||||
<div
|
||||
style={{
|
||||
display: 'grid',
|
||||
gridTemplateColumns: '1fr 1fr 1fr 1fr',
|
||||
gap: '1rem',
|
||||
marginBottom: '1rem'
|
||||
}}
|
||||
>
|
||||
<div className="responsive-grid-4" style={{ marginBottom: '1rem' }}>
|
||||
<div className="form-row">
|
||||
<label className="form-label">Tatsächliches Datum</label>
|
||||
<input
|
||||
|
|
@ -1407,7 +1406,6 @@ function TrainingPlanningPage() {
|
|||
exerciseId={planningPeekExerciseId}
|
||||
onClose={() => setPlanningPeekExerciseId(null)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -141,7 +141,7 @@ export default function TrainingUnitRunPage() {
|
|||
}
|
||||
|
||||
return (
|
||||
<div className="training-run-page" style={{ maxWidth: '720px', margin: '0 auto', paddingBottom: '2rem' }}>
|
||||
<div className="training-run-page app-page app-page--constrained-sm" style={{ paddingBottom: '2rem' }}>
|
||||
<ExercisePeekModal
|
||||
open={peekExerciseId != null}
|
||||
exerciseId={peekExerciseId}
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user