feat: improve schedule view layout and controls for match overview
All checks were successful
Deploy tt-tagebuch / deploy (push) Successful in 52s

This commit is contained in:
Torsten Schulz (local)
2026-07-22 14:57:13 +02:00
parent 48f0f9afb0
commit 8140283b7a
3 changed files with 67 additions and 73 deletions

View File

@@ -104,10 +104,12 @@
<div class="schedule-workspace">
<div class="schedule-workspace-header">
<div>
<span class="workspace-eyebrow">{{ $t('schedule.activeSelection') }}</span>
<h3 v-if="selectedLeague">{{ selectedLeague }}</h3>
<h3 v-if="selectedLeague" class="schedule-workspace-selection">
<span class="workspace-eyebrow-inline">{{ $t('schedule.activeSelection') }}:</span>
<span>{{ selectedLeague }}</span>
<span v-if="workspaceDescription" class="schedule-workspace-selection-meta">· {{ workspaceDescription }}</span>
</h3>
<h3 v-else>{{ $t('schedule.noSelectionTitle') }}</h3>
<p v-if="selectedLeague">{{ workspaceDescription }}</p>
<p v-else>{{ $t('schedule.noSelectionMessage') }}</p>
</div>
<div v-if="selectedLeague" class="schedule-workspace-actions">
@@ -276,6 +278,20 @@ export default {
margin: 0;
}
.schedule-workspace-selection {
display: flex;
flex-wrap: wrap;
align-items: baseline;
gap: 0.35rem;
}
.workspace-eyebrow-inline,
.schedule-workspace-selection-meta {
font-size: 0.92rem;
color: var(--text-muted);
font-weight: 500;
}
.schedule-page-title p,
.schedule-workspace-header p {
margin: 0.25rem 0 0;

View File

@@ -751,6 +751,7 @@ import {
formatMemberTtAgeClassLabels,
formatSeasonSlash
} from '../utils/ttAgeClass.js';
import { PRODUCT_CLUB, resolveCurrentProduct } from '../config/products.js';
import PDFGenerator from '../components/PDFGenerator.js';
import InfoDialog from '../components/InfoDialog.vue';
@@ -775,6 +776,8 @@ const defaultMemberDataQualityRequirements = () => ({
requireEmail: true,
});
const currentProduct = resolveCurrentProduct();
export default {
name: 'MembersView',
components: {
@@ -821,6 +824,9 @@ export default {
},
canViewMemberFinancialData() {
if (currentProduct !== PRODUCT_CLUB) {
return false;
}
return this.hasPermission('finance_invoices', 'read')
|| this.hasPermission('finance_invoices', 'write')
|| this.hasPermission('finance_accounts', 'read')

View File

@@ -82,45 +82,35 @@
</div>
<div v-if="selectedTeam" class="league-match-scope-card">
<div class="league-match-scope-header">
<strong>{{ $t('schedule.matchOverviewTitle') }}</strong>
<span>{{ $t('schedule.matchOverviewDescription') }}</span>
</div>
<div class="league-match-scope-controls">
<button
type="button"
class="team-filter-chip"
:class="{ active: leagueMatchScope === 'own' }"
@click="setLeagueMatchScope('own')"
>
{{ $t('schedule.ownTeamMatches') }}
</button>
<button
type="button"
class="team-filter-chip"
:class="{ active: leagueMatchScope === 'all' }"
@click="setLeagueMatchScope('all')"
>
{{ $t('schedule.allLeagueMatches') }}
</button>
<button
type="button"
class="team-filter-chip"
:class="{ active: leagueMatchScope === 'other' }"
@click="setLeagueMatchScope('other')"
>
{{ $t('schedule.otherTeamMatches') }}
</button>
<select
v-if="leagueMatchScope === 'other'"
v-model="selectedComparisonTeamName"
class="league-match-scope-select"
@change="applyLeagueMatchScope"
>
<option value="">{{ $t('schedule.selectOtherTeam') }}</option>
<option v-for="teamName in leagueTeamOptions" :key="teamName" :value="teamName">
{{ teamName }}
</option>
</select>
<strong>Spielübersicht für</strong>
<div class="league-match-scope-controls">
<select
v-model="leagueMatchScope"
class="league-match-scope-select"
@change="applyLeagueMatchScope"
>
<option value="own">
{{ $t('schedule.ownTeamMatches') }}
</option>
<option value="all">
{{ $t('schedule.allLeagueMatches') }}
</option>
<option value="other">
{{ $t('schedule.otherTeamMatches') }}
</option>
</select>
<select
v-if="leagueMatchScope === 'other'"
v-model="selectedComparisonTeamName"
class="league-match-scope-select"
@change="applyLeagueMatchScope"
>
<option value="">{{ $t('schedule.selectOtherTeam') }}</option>
<option v-for="teamName in leagueTeamOptions" :key="teamName" :value="teamName">
{{ teamName }}
</option>
</select>
</div>
</div>
</div>
<div v-if="matches.length > 0">
@@ -3944,8 +3934,8 @@ li {
border: 1px solid var(--border-color, #dee2e6);
border-radius: 14px;
background: linear-gradient(180deg, rgba(47, 122, 95, 0.08), rgba(47, 122, 95, 0.03));
padding: 14px;
margin-bottom: 12px;
padding: 10px 14px;
margin-bottom: 8px;
position: sticky;
top: 12px;
z-index: 5;
@@ -3954,14 +3944,9 @@ li {
.league-match-scope-header {
display: flex;
flex-direction: column;
gap: 4px;
margin-bottom: 10px;
}
.league-match-scope-header span {
color: var(--text-muted, #6c757d);
font-size: 14px;
align-items: center;
justify-content: space-between;
gap: 10px;
}
.league-match-scope-controls {
@@ -3971,25 +3956,9 @@ li {
align-items: center;
}
.team-filter-chip {
border: 1px solid var(--border-color, #dee2e6);
border-radius: 999px;
background: var(--surface-color, #fff);
color: var(--text-color, #333);
padding: 8px 12px;
cursor: pointer;
font-weight: 600;
}
.team-filter-chip.active {
border-color: var(--primary-soft, #5f9b82);
color: var(--primary-strong, #1f5f49);
background: rgba(47, 122, 95, 0.12);
}
.league-match-scope-select {
min-width: 220px;
padding: 8px 10px;
min-width: 210px;
padding: 7px 10px;
border: 1px solid var(--border-color, #dee2e6);
border-radius: 10px;
background: var(--surface-color, #fff);
@@ -4119,12 +4088,15 @@ li {
padding: 12px;
}
.league-match-scope-controls {
flex-direction: column;
.league-match-scope-header {
align-items: stretch;
flex-direction: column;
}
.league-match-scope-controls {
width: 100%;
}
.team-filter-chip,
.league-match-scope-select {
width: 100%;
min-width: 0;