feat(Scheduler, MatchService, PredefinedActivity): enhance scheduling and match fetching features
- Added new scheduler routes to manage scheduling functionalities. - Updated match fetching logic to include a scope parameter for more flexible data retrieval. - Introduced a new field `excludeFromStats` in the PredefinedActivity model to manage activity visibility in statistics. - Enhanced the diary date activity controller to handle predefined activities, improving activity management. - Refactored various services to support new features and improve overall data handling.
This commit is contained in:
@@ -14,35 +14,35 @@
|
||||
<span class="dropdown-arrow">▼</span>
|
||||
</button>
|
||||
<div v-if="userDropdownOpen" class="user-dropdown">
|
||||
<router-link to="/mytischtennis-account" class="dropdown-item" @click="userDropdownOpen = false">
|
||||
<button type="button" class="dropdown-item" @click="openUserMenuDialog('MyTischtennisAccount', $t('navigation.myTischtennisAccount'))">
|
||||
<span class="dropdown-icon">🔗</span>
|
||||
{{ $t('navigation.myTischtennisAccount') }}
|
||||
</router-link>
|
||||
<router-link to="/clicktt-account" class="dropdown-item" @click="userDropdownOpen = false">
|
||||
</button>
|
||||
<button type="button" class="dropdown-item" @click="openUserMenuDialog('ClickTtAccount', $t('navigation.clickTtAccount'))">
|
||||
<span class="dropdown-icon">🏓</span>
|
||||
HTTV / click-TT Account
|
||||
</router-link>
|
||||
<router-link v-if="canManagePermissions" to="/permissions" class="dropdown-item" @click="userDropdownOpen = false">
|
||||
{{ $t('navigation.clickTtAccount') }}
|
||||
</button>
|
||||
<button v-if="canManagePermissions" type="button" class="dropdown-item" @click="openUserMenuDialog('PermissionsView', $t('navigation.permissions'))">
|
||||
<span class="dropdown-icon">🔐</span>
|
||||
{{ $t('navigation.permissions') }}
|
||||
</router-link>
|
||||
<router-link v-if="hasPermission('members', 'write')" to="/member-transfer-settings" class="dropdown-item" @click="userDropdownOpen = false">
|
||||
</button>
|
||||
<button v-if="hasPermission('members', 'write')" type="button" class="dropdown-item" @click="openUserMenuDialog('MemberTransferSettingsView', $t('navigation.memberTransfer'))">
|
||||
<span class="dropdown-icon">📤</span>
|
||||
{{ $t('navigation.memberTransfer') }}
|
||||
</router-link>
|
||||
<router-link v-if="isAdmin" to="/logs" class="dropdown-item" @click="userDropdownOpen = false">
|
||||
</button>
|
||||
<button v-if="isAdmin" type="button" class="dropdown-item" @click="openUserMenuDialog('LogsView', $t('navigation.logs'))">
|
||||
<span class="dropdown-icon">📋</span>
|
||||
{{ $t('navigation.logs') }}
|
||||
</router-link>
|
||||
<router-link v-if="canManagePermissions" to="/clicktt" class="dropdown-item" @click="userDropdownOpen = false">
|
||||
</button>
|
||||
<button v-if="canManagePermissions" type="button" class="dropdown-item" @click="openUserMenuDialog('ClickTtView', $t('navigation.clickTtBrowser'))">
|
||||
<span class="dropdown-icon">🌐</span>
|
||||
HTTV / click-TT
|
||||
</router-link>
|
||||
{{ $t('navigation.clickTtBrowser') }}
|
||||
</button>
|
||||
<div class="dropdown-divider"></div>
|
||||
<router-link to="/personal-settings" class="dropdown-item" @click="userDropdownOpen = false">
|
||||
<button type="button" class="dropdown-item" @click="openUserMenuDialog('PersonalSettings', $t('navigation.personalSettings'))">
|
||||
<span class="dropdown-icon">⚙️</span>
|
||||
{{ $t('navigation.personalSettings') }}
|
||||
</router-link>
|
||||
</button>
|
||||
<div class="dropdown-divider"></div>
|
||||
<button @click="logout" class="dropdown-item logout-item">
|
||||
<span class="dropdown-icon">🚪</span>
|
||||
@@ -303,7 +303,18 @@ export default {
|
||||
this.confirmDialog.isOpen = false;
|
||||
},
|
||||
|
||||
...mapActions(['setCurrentClub', 'setClubs', 'logout', 'toggleSidebar']),
|
||||
...mapActions(['setCurrentClub', 'setClubs', 'logout', 'toggleSidebar', 'openDialog']),
|
||||
|
||||
openUserMenuDialog(component, title) {
|
||||
this.userDropdownOpen = false;
|
||||
this.openDialog({
|
||||
title,
|
||||
component,
|
||||
props: {
|
||||
embedded: true
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
async loadUserData() {
|
||||
try {
|
||||
@@ -399,9 +410,11 @@ export default {
|
||||
|
||||
/* Header */
|
||||
.app-header {
|
||||
background: linear-gradient(135deg, var(--primary-color), var(--primary-hover));
|
||||
color: white;
|
||||
box-shadow: var(--shadow-medium);
|
||||
background:
|
||||
linear-gradient(135deg, rgba(24, 70, 54, 0.96), rgba(47, 122, 95, 0.94)),
|
||||
linear-gradient(90deg, rgba(255, 255, 255, 0.06), transparent);
|
||||
color: var(--text-on-primary);
|
||||
box-shadow: 0 8px 24px rgba(24, 70, 54, 0.18);
|
||||
position: relative;
|
||||
z-index: 1000;
|
||||
flex-shrink: 0;
|
||||
@@ -423,7 +436,7 @@ export default {
|
||||
.app-header h1 {
|
||||
margin: 0;
|
||||
font-weight: 700;
|
||||
color: white;
|
||||
color: var(--text-on-primary);
|
||||
text-align: center;
|
||||
/* Schriftgröße bleibt wie in der main.scss definiert */
|
||||
}
|
||||
@@ -437,17 +450,19 @@ export default {
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
padding: 0.5rem 1rem;
|
||||
background-color: rgba(255, 255, 255, 0.1);
|
||||
border-radius: 20px;
|
||||
background-color: rgba(255, 255, 255, 0.12);
|
||||
border: 1px solid rgba(255, 255, 255, 0.16);
|
||||
border-radius: 999px;
|
||||
font-size: 0.9rem;
|
||||
color: white;
|
||||
color: var(--text-on-primary);
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
transition: background-color 0.2s ease;
|
||||
transition: var(--transition);
|
||||
}
|
||||
|
||||
.user-info:hover {
|
||||
background-color: rgba(255, 255, 255, 0.2);
|
||||
background-color: rgba(255, 255, 255, 0.18);
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
.user-icon {
|
||||
@@ -468,10 +483,11 @@ export default {
|
||||
position: absolute;
|
||||
top: calc(100% + 0.5rem);
|
||||
right: 0;
|
||||
background: white;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
|
||||
min-width: 200px;
|
||||
background: var(--surface-color);
|
||||
border: 1px solid rgba(24, 70, 54, 0.08);
|
||||
border-radius: 12px;
|
||||
box-shadow: 0 16px 36px rgba(24, 70, 54, 0.16);
|
||||
min-width: 240px;
|
||||
max-height: 70vh;
|
||||
overflow-y: auto;
|
||||
overflow-x: hidden;
|
||||
@@ -495,7 +511,7 @@ export default {
|
||||
align-items: center;
|
||||
gap: 0.75rem;
|
||||
padding: 0.75rem 1rem;
|
||||
color: #333;
|
||||
color: var(--text-primary);
|
||||
text-decoration: none;
|
||||
background: none;
|
||||
border: none;
|
||||
@@ -503,11 +519,18 @@ export default {
|
||||
text-align: left;
|
||||
cursor: pointer;
|
||||
font-size: 0.9rem;
|
||||
transition: background-color 0.15s ease;
|
||||
border-radius: 0;
|
||||
box-shadow: none;
|
||||
margin: 0;
|
||||
min-height: 0;
|
||||
justify-content: flex-start;
|
||||
transition: var(--transition-fast);
|
||||
}
|
||||
|
||||
.dropdown-item:hover {
|
||||
background-color: #f5f5f5;
|
||||
background-color: var(--primary-light);
|
||||
color: var(--primary-strong);
|
||||
transform: none;
|
||||
}
|
||||
|
||||
.dropdown-icon {
|
||||
@@ -516,7 +539,7 @@ export default {
|
||||
|
||||
.dropdown-divider {
|
||||
height: 1px;
|
||||
background-color: #e0e0e0;
|
||||
background-color: var(--border-color);
|
||||
margin: 0.25rem 0;
|
||||
}
|
||||
|
||||
@@ -526,7 +549,8 @@ export default {
|
||||
}
|
||||
|
||||
.logout-item:hover {
|
||||
background-color: #fff5f5;
|
||||
background-color: #fff1f3;
|
||||
color: var(--danger-color);
|
||||
}
|
||||
|
||||
.home-link {
|
||||
@@ -554,9 +578,10 @@ export default {
|
||||
/* Sidebar */
|
||||
.sidebar {
|
||||
width: 280px;
|
||||
background: white;
|
||||
border-right: 1px solid var(--border-color);
|
||||
box-shadow: var(--shadow-small);
|
||||
background:
|
||||
linear-gradient(180deg, var(--surface-color), var(--surface-muted));
|
||||
border-right: 1px solid rgba(24, 70, 54, 0.08);
|
||||
box-shadow: inset -1px 0 0 rgba(24, 70, 54, 0.04);
|
||||
overflow-y: auto;
|
||||
flex-shrink: 0;
|
||||
display: flex;
|
||||
@@ -573,15 +598,19 @@ export default {
|
||||
}
|
||||
|
||||
.club-selector {
|
||||
padding: 0.75rem;
|
||||
padding: 0.9rem;
|
||||
margin-bottom: 0.5rem;
|
||||
flex-shrink: 0;
|
||||
background: rgba(255, 255, 255, 0.78);
|
||||
border: 1px solid rgba(24, 70, 54, 0.08);
|
||||
border-radius: 12px;
|
||||
box-shadow: 0 8px 20px rgba(24, 70, 54, 0.05);
|
||||
}
|
||||
|
||||
.club-selector .card-title {
|
||||
font-size: 0.875rem;
|
||||
margin-bottom: 0.5rem;
|
||||
color: var(--text-color);
|
||||
color: var(--primary-strong);
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
@@ -598,7 +627,7 @@ export default {
|
||||
border-radius: var(--border-radius-small);
|
||||
font-size: 0.75rem;
|
||||
background: white;
|
||||
color: var(--text-color);
|
||||
color: var(--text-primary);
|
||||
}
|
||||
|
||||
.select-group .btn-primary {
|
||||
@@ -636,7 +665,7 @@ export default {
|
||||
.nav-title {
|
||||
font-size: 0.75rem;
|
||||
font-weight: 600;
|
||||
color: var(--text-muted);
|
||||
color: var(--primary-strong);
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.025em;
|
||||
margin-bottom: 0.25rem;
|
||||
@@ -648,17 +677,26 @@ export default {
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
padding: 0.5rem 0.5rem;
|
||||
color: var(--text-color);
|
||||
color: var(--text-primary);
|
||||
text-decoration: none;
|
||||
border-radius: var(--border-radius-small);
|
||||
transition: all var(--transition-fast);
|
||||
border-radius: 10px;
|
||||
transition: var(--transition-fast);
|
||||
font-size: 1rem;
|
||||
border: 1px solid transparent;
|
||||
}
|
||||
|
||||
.nav-link:hover {
|
||||
background: var(--primary-light);
|
||||
color: var(--primary-color);
|
||||
color: var(--primary-strong);
|
||||
transform: translateX(0.125rem);
|
||||
border-color: rgba(47, 122, 95, 0.08);
|
||||
}
|
||||
|
||||
.nav-link.router-link-active {
|
||||
background: linear-gradient(135deg, var(--primary-soft), rgba(255, 255, 255, 0.92));
|
||||
color: var(--primary-strong);
|
||||
border-color: rgba(47, 122, 95, 0.14);
|
||||
box-shadow: inset 0 0 0 1px rgba(47, 122, 95, 0.03);
|
||||
}
|
||||
|
||||
.nav-icon {
|
||||
@@ -685,8 +723,8 @@ export default {
|
||||
/* Auth Navigation */
|
||||
.auth-nav {
|
||||
width: 260px;
|
||||
background: white;
|
||||
border-right: 1px solid var(--border-color);
|
||||
background: linear-gradient(180deg, var(--surface-color), var(--surface-muted));
|
||||
border-right: 1px solid rgba(24, 70, 54, 0.08);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
@@ -722,15 +760,16 @@ export default {
|
||||
.main-content {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
background: var(--background-light);
|
||||
background: var(--bg-canvas);
|
||||
min-height: 0;
|
||||
padding-bottom: 32px; /* Platz für Statusleiste (24px + 8px padding) */
|
||||
}
|
||||
|
||||
/* Footer */
|
||||
.app-footer {
|
||||
background: white;
|
||||
border-top: 1px solid var(--border-color);
|
||||
background: rgba(255, 255, 255, 0.86);
|
||||
border-top: 1px solid rgba(24, 70, 54, 0.08);
|
||||
backdrop-filter: blur(6px);
|
||||
padding: 0.75rem 1rem;
|
||||
}
|
||||
|
||||
|
||||
@@ -34,21 +34,21 @@
|
||||
}
|
||||
|
||||
.alert-success {
|
||||
background-color: rgba(40, 167, 69, 0.08);
|
||||
border-color: rgba(40, 167, 69, 0.25);
|
||||
color: #155724;
|
||||
background-color: rgba(47, 122, 95, 0.1);
|
||||
border-color: rgba(47, 122, 95, 0.2);
|
||||
color: var(--primary-strong);
|
||||
}
|
||||
|
||||
.alert-info {
|
||||
background-color: rgba(23, 162, 184, 0.08);
|
||||
border-color: rgba(23, 162, 184, 0.25);
|
||||
color: #0c5460;
|
||||
background-color: rgba(51, 111, 168, 0.08);
|
||||
border-color: rgba(51, 111, 168, 0.18);
|
||||
color: #204a78;
|
||||
}
|
||||
|
||||
.alert-warning {
|
||||
background-color: rgba(255, 193, 7, 0.08);
|
||||
border-color: rgba(255, 193, 7, 0.25);
|
||||
color: #856404;
|
||||
background-color: rgba(181, 110, 65, 0.1);
|
||||
border-color: rgba(181, 110, 65, 0.18);
|
||||
color: #7a4a2c;
|
||||
}
|
||||
|
||||
.alert-danger {
|
||||
@@ -61,56 +61,71 @@
|
||||
.badge {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
padding: 0.125rem 0.625rem;
|
||||
padding: 0.22rem 0.7rem;
|
||||
font-size: 0.7rem;
|
||||
font-weight: 500;
|
||||
font-weight: 600;
|
||||
line-height: 1;
|
||||
text-align: center;
|
||||
white-space: nowrap;
|
||||
vertical-align: baseline;
|
||||
border-radius: 9999px;
|
||||
background-color: var(--text-light);
|
||||
color: white;
|
||||
border: 1px solid transparent;
|
||||
background-color: rgba(51, 51, 51, 0.08);
|
||||
color: var(--text-primary);
|
||||
}
|
||||
|
||||
.badge-primary {
|
||||
background-color: var(--primary-color);
|
||||
background-color: var(--primary-soft);
|
||||
border-color: rgba(47, 122, 95, 0.14);
|
||||
color: var(--primary-strong);
|
||||
}
|
||||
|
||||
.badge-secondary {
|
||||
background-color: var(--secondary-color);
|
||||
background-color: var(--secondary-soft);
|
||||
border-color: rgba(181, 110, 65, 0.14);
|
||||
color: #7a4a2c;
|
||||
}
|
||||
|
||||
.badge-success {
|
||||
background-color: #28a745;
|
||||
background-color: rgba(47, 122, 95, 0.1);
|
||||
border-color: rgba(47, 122, 95, 0.16);
|
||||
color: var(--primary-strong);
|
||||
}
|
||||
|
||||
.badge-danger {
|
||||
background-color: #dc3545;
|
||||
background-color: rgba(220, 53, 69, 0.1);
|
||||
border-color: rgba(220, 53, 69, 0.18);
|
||||
color: #962d2d;
|
||||
}
|
||||
|
||||
.badge-warning {
|
||||
background-color: #ffc107;
|
||||
color: #212529;
|
||||
background-color: rgba(181, 110, 65, 0.1);
|
||||
border-color: rgba(181, 110, 65, 0.18);
|
||||
color: #7a4a2c;
|
||||
}
|
||||
|
||||
.badge-info {
|
||||
background-color: #17a2b8;
|
||||
background-color: rgba(51, 111, 168, 0.1);
|
||||
border-color: rgba(51, 111, 168, 0.18);
|
||||
color: #204a78;
|
||||
}
|
||||
|
||||
.badge-light {
|
||||
background-color: #f8f9fa;
|
||||
color: #212529;
|
||||
background-color: var(--surface-muted);
|
||||
border-color: var(--border-color);
|
||||
color: var(--text-primary);
|
||||
}
|
||||
|
||||
.badge-dark {
|
||||
background-color: #343a40;
|
||||
background-color: rgba(24, 70, 54, 0.12);
|
||||
border-color: rgba(24, 70, 54, 0.2);
|
||||
color: var(--primary-strong);
|
||||
}
|
||||
|
||||
/* Progress-Bar */
|
||||
.progress {
|
||||
height: 0.625rem;
|
||||
background-color: #e9ecef;
|
||||
background-color: rgba(24, 70, 54, 0.08);
|
||||
border-radius: var(--border-radius);
|
||||
overflow: hidden;
|
||||
margin: 0.75rem 0;
|
||||
@@ -123,7 +138,7 @@
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: white;
|
||||
color: var(--text-on-primary);
|
||||
font-size: 0.7rem;
|
||||
font-weight: 500;
|
||||
}
|
||||
@@ -137,8 +152,8 @@
|
||||
.tooltip .tooltip-text {
|
||||
visibility: hidden;
|
||||
width: 180px;
|
||||
background-color: #333;
|
||||
color: white;
|
||||
background-color: rgba(24, 70, 54, 0.96);
|
||||
color: var(--text-on-primary);
|
||||
text-align: center;
|
||||
border-radius: var(--border-radius);
|
||||
padding: 0.375rem;
|
||||
@@ -161,7 +176,7 @@
|
||||
margin-left: -4px;
|
||||
border-width: 4px;
|
||||
border-style: solid;
|
||||
border-color: #333 transparent transparent transparent;
|
||||
border-color: rgba(24, 70, 54, 0.96) transparent transparent transparent;
|
||||
}
|
||||
|
||||
.tooltip:hover .tooltip-text {
|
||||
@@ -176,7 +191,7 @@
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: rgba(0, 0, 0, 0.4);
|
||||
background-color: rgba(19, 33, 28, 0.34);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
@@ -192,13 +207,13 @@
|
||||
}
|
||||
|
||||
.overlay-content {
|
||||
background: white;
|
||||
background: var(--surface-color);
|
||||
border-radius: var(--border-radius-large);
|
||||
padding: 1.5rem;
|
||||
max-width: 90vw;
|
||||
max-height: 90vh;
|
||||
overflow-y: auto;
|
||||
box-shadow: var(--shadow-heavy);
|
||||
box-shadow: 0 20px 48px rgba(19, 33, 28, 0.2);
|
||||
transform: scale(0.9);
|
||||
transition: transform 0.25s ease;
|
||||
}
|
||||
@@ -258,6 +273,48 @@
|
||||
gap: 0.375rem;
|
||||
}
|
||||
|
||||
.form-group {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.4rem;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.form-group label {
|
||||
font-size: 0.82rem;
|
||||
font-weight: 600;
|
||||
color: var(--primary-strong);
|
||||
}
|
||||
|
||||
.filter-select,
|
||||
.filter-input {
|
||||
background: var(--surface-color);
|
||||
border: 1px solid rgba(24, 70, 54, 0.12);
|
||||
border-radius: 10px;
|
||||
color: var(--text-primary);
|
||||
min-height: 2.35rem;
|
||||
}
|
||||
|
||||
.filter-select:focus,
|
||||
.filter-input:focus {
|
||||
border-color: rgba(47, 122, 95, 0.45);
|
||||
box-shadow: 0 0 0 3px rgba(47, 122, 95, 0.1);
|
||||
}
|
||||
|
||||
.dialog-content {
|
||||
background: linear-gradient(180deg, var(--surface-color), var(--surface-muted));
|
||||
}
|
||||
|
||||
.table-container,
|
||||
.logs-table-container,
|
||||
.participants-table-container {
|
||||
background: var(--surface-color);
|
||||
border: 1px solid rgba(24, 70, 54, 0.08);
|
||||
border-radius: 14px;
|
||||
box-shadow: 0 10px 24px rgba(24, 70, 54, 0.05);
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.tab-item {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
@@ -3,26 +3,38 @@
|
||||
|
||||
/* Modernes, frisches Design für TrainingsTagebuch */
|
||||
:root {
|
||||
/* Bestehende Farben beibehalten */
|
||||
--primary-color: #4CAF50;
|
||||
--primary-hover: #45a049;
|
||||
--secondary-color: #a07040;
|
||||
--secondary-hover: #804b29;
|
||||
/* Zentrale Farbpalette */
|
||||
--primary-color: #2f7a5f;
|
||||
--primary-hover: #245f49;
|
||||
--primary-soft: #e8f2ed;
|
||||
--primary-strong: #184636;
|
||||
--secondary-color: #b56e41;
|
||||
--secondary-hover: #915734;
|
||||
--secondary-soft: #f6ebe2;
|
||||
--danger-color: #dc3545;
|
||||
--danger-hover: #c82333;
|
||||
--nav-bg: #e0f0e8;
|
||||
--nav-bg: #edf4f0;
|
||||
--text-primary: #333;
|
||||
--text-secondary: #666;
|
||||
--text-light: #999;
|
||||
--text-muted: #888;
|
||||
--text-on-primary: #ffffff;
|
||||
--text-on-secondary: #ffffff;
|
||||
--bg-light: #f8f9fa;
|
||||
--bg-canvas: #f4f6f3;
|
||||
--surface-color: #ffffff;
|
||||
--surface-muted: #f7faf8;
|
||||
--border-color: #e9ecef;
|
||||
--primary-light: #e8f2ed;
|
||||
--shadow-light: 0 1px 3px rgba(0, 0, 0, 0.08);
|
||||
--shadow-medium: 0 2px 8px rgba(0, 0, 0, 0.12);
|
||||
--shadow-heavy: 0 4px 16px rgba(0, 0, 0, 0.15);
|
||||
--shadow-small: var(--shadow-light);
|
||||
--border-radius: 6px;
|
||||
--border-radius-small: 6px;
|
||||
--border-radius-large: 8px;
|
||||
--transition: all 0.25s cubic-bezier(0.4, 0, 0.2, 1);
|
||||
--transition-fast: 0.18s ease;
|
||||
}
|
||||
|
||||
html, body {
|
||||
@@ -34,7 +46,7 @@ html, body {
|
||||
font-size: 14px;
|
||||
line-height: 1.5;
|
||||
color: var(--text-primary);
|
||||
background-color: var(--bg-light);
|
||||
background-color: var(--bg-canvas);
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
@@ -81,7 +93,7 @@ h3 {
|
||||
/* Kompaktere Button-Styles */
|
||||
button {
|
||||
background: linear-gradient(135deg, var(--primary-color), var(--primary-hover));
|
||||
color: white;
|
||||
color: var(--text-on-primary);
|
||||
border: none;
|
||||
border-radius: var(--border-radius);
|
||||
padding: 0.5rem 1rem;
|
||||
@@ -135,7 +147,7 @@ button.cancel-action {
|
||||
|
||||
button.cancel-action:hover {
|
||||
background: var(--primary-color);
|
||||
color: white;
|
||||
color: var(--text-on-primary);
|
||||
transform: translateY(-1px);
|
||||
box-shadow: var(--shadow-medium);
|
||||
}
|
||||
@@ -155,7 +167,7 @@ button.delete-btn:hover,
|
||||
button[onclick*="delete"]:hover,
|
||||
button[onclick*="remove"]:hover {
|
||||
background: var(--danger-color);
|
||||
color: white;
|
||||
color: var(--text-on-primary);
|
||||
transform: translateY(-1px);
|
||||
box-shadow: var(--shadow-medium);
|
||||
}
|
||||
@@ -177,7 +189,7 @@ button.trash-btn {
|
||||
|
||||
button.trash-btn:hover {
|
||||
background: var(--danger-color) !important;
|
||||
color: white !important;
|
||||
color: var(--text-on-primary) !important;
|
||||
transform: translateY(-1px);
|
||||
box-shadow: var(--shadow-medium);
|
||||
}
|
||||
@@ -185,6 +197,7 @@ button.trash-btn:hover {
|
||||
/* Sekundäre Buttons */
|
||||
button.secondary {
|
||||
background: linear-gradient(135deg, var(--secondary-color), var(--secondary-hover));
|
||||
color: var(--text-on-secondary);
|
||||
}
|
||||
|
||||
button.secondary:hover {
|
||||
@@ -308,7 +321,7 @@ ul li.checkbox-item label {
|
||||
input:focus, select:focus, textarea:focus {
|
||||
outline: none;
|
||||
border-color: var(--primary-color);
|
||||
box-shadow: 0 0 0 2px rgba(76, 175, 80, 0.1);
|
||||
box-shadow: 0 0 0 2px rgba(47, 122, 95, 0.14);
|
||||
}
|
||||
|
||||
input:hover, select:hover, textarea:hover {
|
||||
@@ -368,7 +381,7 @@ th, td {
|
||||
|
||||
th {
|
||||
background: linear-gradient(135deg, var(--primary-color), var(--primary-hover));
|
||||
color: white;
|
||||
color: var(--text-on-primary);
|
||||
font-weight: 600;
|
||||
text-transform: uppercase;
|
||||
font-size: 0.75rem;
|
||||
@@ -376,7 +389,7 @@ th {
|
||||
}
|
||||
|
||||
tr:hover {
|
||||
background-color: rgba(76, 175, 80, 0.03);
|
||||
background-color: rgba(47, 122, 95, 0.04);
|
||||
}
|
||||
|
||||
/* Kompaktere Listen */
|
||||
@@ -526,4 +539,4 @@ a:hover::after {
|
||||
@keyframes spin {
|
||||
0% { transform: rotate(0deg); }
|
||||
100% { transform: rotate(360deg); }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -213,10 +213,12 @@ export default {
|
||||
.form-select,
|
||||
.form-textarea {
|
||||
width: 100%;
|
||||
padding: 0.5rem;
|
||||
padding: 0.75rem 0.875rem;
|
||||
border: 1px solid var(--border-color);
|
||||
border-radius: 4px;
|
||||
border-radius: 10px;
|
||||
font-family: inherit;
|
||||
background: var(--surface-muted);
|
||||
color: var(--text-color);
|
||||
}
|
||||
|
||||
.form-textarea {
|
||||
@@ -251,16 +253,17 @@ export default {
|
||||
.accident-item {
|
||||
padding: 0.5rem;
|
||||
margin-bottom: 0.5rem;
|
||||
background: var(--background-light);
|
||||
border-radius: 4px;
|
||||
background: var(--surface-muted);
|
||||
border: 1px solid var(--border-color);
|
||||
border-radius: 10px;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
.btn-primary,
|
||||
.btn-secondary {
|
||||
padding: 0.5rem 1.5rem;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
border: 1px solid transparent;
|
||||
border-radius: 10px;
|
||||
font-size: 0.875rem;
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
@@ -269,11 +272,12 @@ export default {
|
||||
|
||||
.btn-primary {
|
||||
background: linear-gradient(135deg, var(--primary-color), var(--primary-hover));
|
||||
color: white;
|
||||
color: var(--text-on-primary);
|
||||
}
|
||||
|
||||
.btn-primary:hover:not(:disabled) {
|
||||
opacity: 0.9;
|
||||
opacity: 0.95;
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
.btn-primary:disabled {
|
||||
@@ -282,12 +286,13 @@ export default {
|
||||
}
|
||||
|
||||
.btn-secondary {
|
||||
background: #6c757d;
|
||||
color: white;
|
||||
background: var(--surface-color);
|
||||
color: var(--text-color);
|
||||
border-color: var(--border-color);
|
||||
}
|
||||
|
||||
.btn-secondary:hover {
|
||||
background: #5a6268;
|
||||
background: var(--surface-muted);
|
||||
border-color: var(--primary-soft);
|
||||
}
|
||||
</style>
|
||||
|
||||
|
||||
@@ -341,7 +341,7 @@ export default {
|
||||
}
|
||||
|
||||
.close-btn:hover {
|
||||
background: #dc3545;
|
||||
background: rgba(200, 74, 56, 0.72);
|
||||
}
|
||||
|
||||
/* Body */
|
||||
@@ -376,4 +376,3 @@ export default {
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
|
||||
@@ -131,17 +131,22 @@ export default {
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.modal-overlay { position: fixed; inset: 0; background: rgba(0,0,0,0.5); display: flex; justify-content: center; align-items: center; z-index: 1000; }
|
||||
.modal { background: white; border-radius: 8px; box-shadow: 0 4px 20px rgba(0,0,0,0.3); max-width: 600px; width: 90%; max-height: 90vh; overflow-y: auto; display: flex; flex-direction: column; }
|
||||
.modal-header { padding: 1.5rem; border-bottom: 1px solid #dee2e6; }
|
||||
.modal-overlay { position: fixed; inset: 0; background: rgba(15, 23, 42, 0.38); display: flex; justify-content: center; align-items: center; z-index: 1000; }
|
||||
.modal { background: var(--surface-color); border: 1px solid var(--border-color); border-radius: 14px; box-shadow: 0 18px 48px rgba(15, 23, 42, 0.18); max-width: 600px; width: 90%; max-height: 90vh; overflow-y: auto; display: flex; flex-direction: column; }
|
||||
.modal-header { padding: 1.5rem; border-bottom: 1px solid var(--border-color); background: linear-gradient(180deg, rgba(47, 122, 95, 0.12), rgba(47, 122, 95, 0.04)); }
|
||||
.modal-header h3 { margin: 0; color: var(--text-color); }
|
||||
.modal-body { padding: 1.5rem; flex: 1; }
|
||||
.modal-footer { padding: 1rem 1.5rem; border-top: 1px solid #dee2e6; display: flex; justify-content: flex-end; gap: 1rem; }
|
||||
.modal-footer { padding: 1rem 1.5rem; border-top: 1px solid var(--border-color); display: flex; justify-content: flex-end; gap: 1rem; background: var(--surface-muted); }
|
||||
.form-group { margin-bottom: 1.5rem; }
|
||||
.form-group label { display: block; margin-bottom: 0.5rem; font-weight: 600; color: #495057; }
|
||||
.form-group input[type="text"], .form-group input[type="password"] { width: 100%; padding: 0.75rem; border: 1px solid #ced4da; border-radius: 4px; font-size: 1rem; box-sizing: border-box; }
|
||||
.form-group label { display: block; margin-bottom: 0.5rem; font-weight: 600; color: var(--text-color); }
|
||||
.form-group input[type="text"], .form-group input[type="password"] { width: 100%; padding: 0.75rem 0.875rem; border: 1px solid var(--border-color); border-radius: 10px; font-size: 1rem; box-sizing: border-box; background: var(--surface-muted); color: var(--text-color); }
|
||||
.form-group input[type="text"]:focus, .form-group input[type="password"]:focus { outline: none; border-color: var(--primary-color); box-shadow: 0 0 0 3px rgba(47, 122, 95, 0.16); }
|
||||
.checkbox-group label { display: flex; align-items: center; gap: 0.5rem; font-weight: normal; }
|
||||
.error-message { padding: 0.75rem; background-color: #f8d7da; border: 1px solid #f5c6cb; border-radius: 4px; color: #721c24; margin-top: 1rem; }
|
||||
.btn-primary, .btn-secondary { padding: 0.75rem 1.5rem; border: none; border-radius: 4px; font-size: 1rem; cursor: pointer; }
|
||||
.btn-primary { background-color: #007bff; color: white; }
|
||||
.btn-secondary { background-color: #6c757d; color: white; }
|
||||
.error-message { padding: 0.75rem; background: rgba(200, 74, 56, 0.12); border: 1px solid rgba(200, 74, 56, 0.24); border-radius: 10px; color: #7a2e21; margin-top: 1rem; }
|
||||
.btn-primary, .btn-secondary { padding: 0.75rem 1.5rem; border: 1px solid transparent; border-radius: 10px; font-size: 0.95rem; font-weight: 600; cursor: pointer; transition: background-color 0.2s ease, border-color 0.2s ease, transform 0.2s ease; }
|
||||
.btn-primary { background: linear-gradient(135deg, var(--primary-color), var(--primary-hover)); color: var(--text-on-primary); }
|
||||
.btn-primary:hover:not(:disabled) { transform: translateY(-1px); }
|
||||
.btn-secondary { background: var(--surface-color); border-color: var(--border-color); color: var(--text-color); }
|
||||
.btn-secondary:hover:not(:disabled) { background: var(--surface-muted); border-color: var(--primary-soft); }
|
||||
.btn-primary:disabled, .btn-secondary:disabled { opacity: 0.55; cursor: not-allowed; }
|
||||
</style>
|
||||
|
||||
@@ -171,8 +171,8 @@ export default {
|
||||
.btn-warning,
|
||||
.btn-danger {
|
||||
padding: 0.5rem 1.5rem;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
border: 1px solid transparent;
|
||||
border-radius: 10px;
|
||||
font-size: 0.875rem;
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
@@ -180,39 +180,42 @@ export default {
|
||||
}
|
||||
|
||||
.btn-secondary {
|
||||
background: #6c757d;
|
||||
color: white;
|
||||
background: var(--surface-color);
|
||||
border-color: var(--border-color);
|
||||
color: var(--text-color);
|
||||
}
|
||||
|
||||
.btn-secondary:hover {
|
||||
background: #5a6268;
|
||||
background: var(--surface-muted);
|
||||
border-color: var(--primary-soft);
|
||||
}
|
||||
|
||||
.btn-primary {
|
||||
background: linear-gradient(135deg, var(--primary-color), var(--primary-hover));
|
||||
color: white;
|
||||
color: var(--text-on-primary);
|
||||
}
|
||||
|
||||
.btn-primary:hover {
|
||||
opacity: 0.9;
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
.btn-warning {
|
||||
background: #ffc107;
|
||||
color: #212529;
|
||||
background: rgba(181, 110, 65, 0.14);
|
||||
border-color: rgba(181, 110, 65, 0.24);
|
||||
color: #8a4f28;
|
||||
}
|
||||
|
||||
.btn-warning:hover {
|
||||
background: #e0a800;
|
||||
background: rgba(181, 110, 65, 0.2);
|
||||
}
|
||||
|
||||
.btn-danger {
|
||||
background: #dc3545;
|
||||
color: white;
|
||||
background: rgba(200, 74, 56, 0.12);
|
||||
border-color: rgba(200, 74, 56, 0.24);
|
||||
color: #8b3327;
|
||||
}
|
||||
|
||||
.btn-danger:hover {
|
||||
background: #c82333;
|
||||
background: rgba(200, 74, 56, 0.18);
|
||||
}
|
||||
</style>
|
||||
|
||||
|
||||
@@ -157,8 +157,8 @@ export default {
|
||||
.btn-primary,
|
||||
.btn-secondary {
|
||||
padding: 0.5rem 1.5rem;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
border: 1px solid transparent;
|
||||
border-radius: 10px;
|
||||
font-size: 0.875rem;
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
@@ -167,11 +167,12 @@ export default {
|
||||
|
||||
.btn-primary {
|
||||
background: linear-gradient(135deg, var(--primary-color), var(--primary-hover));
|
||||
color: white;
|
||||
color: var(--text-on-primary);
|
||||
}
|
||||
|
||||
.btn-primary:hover:not(:disabled) {
|
||||
opacity: 0.9;
|
||||
opacity: 0.95;
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
.btn-primary:disabled {
|
||||
@@ -180,12 +181,13 @@ export default {
|
||||
}
|
||||
|
||||
.btn-secondary {
|
||||
background: #6c757d;
|
||||
color: white;
|
||||
background: var(--surface-color);
|
||||
color: var(--text-color);
|
||||
border-color: var(--border-color);
|
||||
}
|
||||
|
||||
.btn-secondary:hover {
|
||||
background: #5a6268;
|
||||
background: var(--surface-muted);
|
||||
border-color: var(--primary-soft);
|
||||
}
|
||||
</style>
|
||||
|
||||
|
||||
@@ -689,18 +689,18 @@ canvas {
|
||||
.btn-animate {
|
||||
padding: 0.5rem 1rem;
|
||||
font-size: 0.9rem;
|
||||
font-weight: 500;
|
||||
border: 1px solid #007bff;
|
||||
border-radius: 4px;
|
||||
background-color: #007bff;
|
||||
color: white;
|
||||
font-weight: 600;
|
||||
border: 1px solid transparent;
|
||||
border-radius: 10px;
|
||||
background: linear-gradient(135deg, var(--primary-color), var(--primary-hover));
|
||||
color: var(--text-on-primary);
|
||||
cursor: pointer;
|
||||
transition: background-color 0.2s, border-color 0.2s;
|
||||
transition: opacity 0.2s ease, transform 0.2s ease;
|
||||
}
|
||||
|
||||
.btn-animate:hover:not(:disabled) {
|
||||
background-color: #0056b3;
|
||||
border-color: #0056b3;
|
||||
opacity: 0.95;
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
.btn-animate:disabled {
|
||||
@@ -711,4 +711,3 @@ canvas {
|
||||
}
|
||||
</style>
|
||||
|
||||
|
||||
|
||||
@@ -1672,14 +1672,13 @@ canvas {
|
||||
}
|
||||
|
||||
.btn-primary {
|
||||
background-color: #007bff;
|
||||
color: white;
|
||||
border-color: #007bff;
|
||||
background: linear-gradient(135deg, var(--primary-color), var(--primary-hover));
|
||||
color: var(--text-on-primary);
|
||||
border-color: transparent;
|
||||
}
|
||||
|
||||
.btn-primary:hover {
|
||||
background-color: #0056b3;
|
||||
border-color: #0056b3;
|
||||
opacity: 0.95;
|
||||
}
|
||||
|
||||
.btn-secondary {
|
||||
@@ -1695,14 +1694,13 @@ canvas {
|
||||
|
||||
/* Schlagart-Buttons (VH/RH) - Grün */
|
||||
.btn-stroke {
|
||||
background-color: #28a745;
|
||||
color: white;
|
||||
border-color: #28a745;
|
||||
background: linear-gradient(135deg, var(--primary-color), var(--primary-hover));
|
||||
color: var(--text-on-primary);
|
||||
border-color: transparent;
|
||||
}
|
||||
|
||||
.btn-stroke:hover {
|
||||
background-color: #218838;
|
||||
border-color: #218838;
|
||||
opacity: 0.95;
|
||||
}
|
||||
|
||||
.btn-stroke.btn-secondary {
|
||||
@@ -1865,7 +1863,7 @@ input[type="range"] {
|
||||
margin: 0;
|
||||
border: none;
|
||||
border-radius: 2px;
|
||||
background: #28a745; /* grün, auch wenn nichts ausgewählt ist */
|
||||
background: var(--primary-color);
|
||||
color: #ffffff;
|
||||
font-size: 12px;
|
||||
font-weight: 500;
|
||||
|
||||
@@ -92,6 +92,7 @@ export default {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 1rem;
|
||||
padding: 0.25rem;
|
||||
}
|
||||
|
||||
.form-group {
|
||||
@@ -106,32 +107,36 @@ export default {
|
||||
}
|
||||
|
||||
.file-input {
|
||||
padding: 0.5rem;
|
||||
padding: 0.75rem 0.875rem;
|
||||
border: 1px solid var(--border-color);
|
||||
border-radius: 4px;
|
||||
border-radius: 10px;
|
||||
cursor: pointer;
|
||||
background: var(--surface-muted);
|
||||
color: var(--text-color);
|
||||
}
|
||||
|
||||
.file-input::-webkit-file-upload-button {
|
||||
padding: 0.375rem 0.75rem;
|
||||
padding: 0.5rem 0.9rem;
|
||||
border: 1px solid var(--border-color);
|
||||
border-radius: 4px;
|
||||
background: white;
|
||||
border-radius: 8px;
|
||||
background: var(--surface-color);
|
||||
color: var(--text-color);
|
||||
cursor: pointer;
|
||||
margin-right: 0.5rem;
|
||||
}
|
||||
|
||||
.file-input::-webkit-file-upload-button:hover {
|
||||
background: var(--background-light);
|
||||
background: var(--surface-muted);
|
||||
}
|
||||
|
||||
.file-info {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
padding: 0.5rem;
|
||||
background: var(--background-light);
|
||||
border-radius: 4px;
|
||||
padding: 0.75rem 0.875rem;
|
||||
background: var(--surface-muted);
|
||||
border: 1px solid var(--border-color);
|
||||
border-radius: 10px;
|
||||
font-size: 0.875rem;
|
||||
}
|
||||
|
||||
@@ -150,9 +155,9 @@ export default {
|
||||
|
||||
.btn-primary,
|
||||
.btn-secondary {
|
||||
padding: 0.5rem 1.5rem;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
padding: 0.65rem 1.4rem;
|
||||
border: 1px solid transparent;
|
||||
border-radius: 10px;
|
||||
font-size: 0.875rem;
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
@@ -161,7 +166,7 @@ export default {
|
||||
|
||||
.btn-primary {
|
||||
background: linear-gradient(135deg, var(--primary-color), var(--primary-hover));
|
||||
color: white;
|
||||
color: var(--text-on-primary);
|
||||
}
|
||||
|
||||
.btn-primary:hover:not(:disabled) {
|
||||
@@ -174,12 +179,13 @@ export default {
|
||||
}
|
||||
|
||||
.btn-secondary {
|
||||
background: #6c757d;
|
||||
color: white;
|
||||
background: var(--surface-color);
|
||||
border-color: var(--border-color);
|
||||
color: var(--text-color);
|
||||
}
|
||||
|
||||
.btn-secondary:hover {
|
||||
background: #5a6268;
|
||||
background: var(--surface-muted);
|
||||
border-color: var(--primary-soft);
|
||||
}
|
||||
</style>
|
||||
|
||||
|
||||
@@ -56,12 +56,26 @@ import { mapGetters, mapActions } from 'vuex';
|
||||
import MatchReportDialog from './MatchReportDialog.vue';
|
||||
import MatchReportApiDialog from './MatchReportApiDialog.vue';
|
||||
import MatchReportHeaderActions from './MatchReportHeaderActions.vue';
|
||||
import MyTischtennisAccount from '../views/MyTischtennisAccount.vue';
|
||||
import ClickTtAccount from '../views/ClickTtAccount.vue';
|
||||
import PermissionsView from '../views/PermissionsView.vue';
|
||||
import MemberTransferSettingsView from '../views/MemberTransferSettingsView.vue';
|
||||
import LogsView from '../views/LogsView.vue';
|
||||
import ClickTtView from '../views/ClickTtView.vue';
|
||||
import PersonalSettings from '../views/PersonalSettings.vue';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
MatchReportDialog,
|
||||
MatchReportApiDialog,
|
||||
MatchReportHeaderActions
|
||||
MatchReportHeaderActions,
|
||||
MyTischtennisAccount,
|
||||
ClickTtAccount,
|
||||
PermissionsView,
|
||||
MemberTransferSettingsView,
|
||||
LogsView,
|
||||
ClickTtView,
|
||||
PersonalSettings
|
||||
},
|
||||
name: 'DialogManager',
|
||||
computed: {
|
||||
@@ -74,7 +88,14 @@ export default {
|
||||
const components = {
|
||||
'MatchReportDialog': MatchReportDialog,
|
||||
'MatchReportApiDialog': MatchReportApiDialog,
|
||||
'MatchReportHeaderActions': MatchReportHeaderActions
|
||||
'MatchReportHeaderActions': MatchReportHeaderActions,
|
||||
'MyTischtennisAccount': MyTischtennisAccount,
|
||||
'ClickTtAccount': ClickTtAccount,
|
||||
'PermissionsView': PermissionsView,
|
||||
'MemberTransferSettingsView': MemberTransferSettingsView,
|
||||
'LogsView': LogsView,
|
||||
'ClickTtView': ClickTtView,
|
||||
'PersonalSettings': PersonalSettings
|
||||
};
|
||||
const component = components[componentName] || null;
|
||||
return component;
|
||||
@@ -193,7 +214,7 @@ export default {
|
||||
|
||||
.dialog-header {
|
||||
background: linear-gradient(135deg, var(--primary-color), var(--primary-hover));
|
||||
color: white;
|
||||
color: var(--text-on-primary);
|
||||
padding: 12px 16px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
@@ -207,6 +228,7 @@ export default {
|
||||
font-size: 1rem;
|
||||
font-weight: 600;
|
||||
flex: 1;
|
||||
color: var(--text-on-primary);
|
||||
}
|
||||
|
||||
.dialog-header-actions {
|
||||
@@ -225,7 +247,7 @@ export default {
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
background: rgba(255, 255, 255, 0.2);
|
||||
color: white;
|
||||
color: var(--text-on-primary);
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
@@ -240,7 +262,7 @@ export default {
|
||||
}
|
||||
|
||||
.close-btn:hover {
|
||||
background: #dc3545;
|
||||
background: rgba(200, 74, 56, 0.72);
|
||||
}
|
||||
|
||||
.dialog-content {
|
||||
@@ -254,7 +276,7 @@ export default {
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
background: linear-gradient(135deg, rgba(160, 112, 64, 0.95), rgba(128, 75, 41, 0.95));
|
||||
background: linear-gradient(135deg, rgba(24, 70, 54, 0.96), rgba(47, 122, 95, 0.94));
|
||||
padding: 4px 16px;
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
@@ -272,7 +294,7 @@ export default {
|
||||
|
||||
.minimized-dialog-button {
|
||||
background: var(--primary-color);
|
||||
color: white;
|
||||
color: var(--text-on-primary);
|
||||
border: none;
|
||||
padding: 8px 16px;
|
||||
border-radius: 4px;
|
||||
|
||||
@@ -79,9 +79,10 @@ export default {
|
||||
|
||||
.activity-empty-state {
|
||||
padding: 0.7rem 0.75rem;
|
||||
border-radius: 8px;
|
||||
background: #f3f7fa;
|
||||
color: #516978;
|
||||
border-radius: 10px;
|
||||
background: var(--surface-muted);
|
||||
border: 1px solid var(--border-color);
|
||||
color: var(--text-muted);
|
||||
margin-bottom: 0.75rem;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -144,10 +144,10 @@ export default {
|
||||
|
||||
.participant-gallery-button {
|
||||
padding: 0.45rem 0.75rem;
|
||||
border: 1px solid #ccd8e0;
|
||||
border-radius: 8px;
|
||||
background: #f3f7fa;
|
||||
color: #365266;
|
||||
border: 1px solid var(--border-color);
|
||||
border-radius: 10px;
|
||||
background: var(--surface-muted);
|
||||
color: var(--text-color);
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
}
|
||||
@@ -159,10 +159,17 @@ export default {
|
||||
|
||||
.participant-search-input {
|
||||
width: 100%;
|
||||
padding: 0.55rem 0.7rem;
|
||||
border: 1px solid #ccd8e0;
|
||||
border-radius: 8px;
|
||||
background: #fff;
|
||||
padding: 0.65rem 0.8rem;
|
||||
border: 1px solid var(--border-color);
|
||||
border-radius: 10px;
|
||||
background: var(--surface-color);
|
||||
color: var(--text-color);
|
||||
}
|
||||
|
||||
.participant-search-input:focus {
|
||||
outline: none;
|
||||
border-color: var(--primary-color);
|
||||
box-shadow: 0 0 0 3px rgba(47, 122, 95, 0.14);
|
||||
}
|
||||
|
||||
.participant-filter-chips {
|
||||
@@ -172,19 +179,20 @@ export default {
|
||||
}
|
||||
|
||||
.participant-filter-chip {
|
||||
border: 1px solid #ccd8e0;
|
||||
background: #f3f7fa;
|
||||
color: #365266;
|
||||
border: 1px solid var(--border-color);
|
||||
background: var(--surface-muted);
|
||||
color: var(--text-color);
|
||||
border-radius: 999px;
|
||||
padding: 0.35rem 0.75rem;
|
||||
font-size: 0.85rem;
|
||||
cursor: pointer;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.participant-filter-chip.active {
|
||||
background: #dcebf5;
|
||||
border-color: #8eb7d1;
|
||||
color: #14374c;
|
||||
background: rgba(47, 122, 95, 0.12);
|
||||
border-color: var(--primary-soft);
|
||||
color: var(--primary-strong);
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
@@ -193,9 +201,9 @@ export default {
|
||||
font-size: 10px;
|
||||
width: 5em;
|
||||
padding: 2px 4px;
|
||||
border: 1px solid #ccc;
|
||||
border-radius: 3px;
|
||||
background-color: white;
|
||||
color: #333;
|
||||
border: 1px solid var(--border-color);
|
||||
border-radius: 6px;
|
||||
background-color: var(--surface-color);
|
||||
color: var(--text-color);
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -87,7 +87,7 @@ export default {
|
||||
max-width: 100%;
|
||||
max-height: 70vh;
|
||||
object-fit: contain;
|
||||
border-radius: 4px;
|
||||
border-radius: 12px;
|
||||
}
|
||||
|
||||
.no-image {
|
||||
@@ -106,18 +106,19 @@ export default {
|
||||
|
||||
.btn-secondary {
|
||||
padding: 0.5rem 1.5rem;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
border: 1px solid var(--border-color);
|
||||
border-radius: 10px;
|
||||
font-size: 0.875rem;
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s ease;
|
||||
background: #6c757d;
|
||||
color: white;
|
||||
background: var(--surface-color);
|
||||
color: var(--text-color);
|
||||
}
|
||||
|
||||
.btn-secondary:hover {
|
||||
background: #5a6268;
|
||||
background: var(--surface-muted);
|
||||
border-color: var(--primary-soft);
|
||||
}
|
||||
|
||||
/* Responsive */
|
||||
@@ -127,4 +128,3 @@ export default {
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
|
||||
@@ -201,8 +201,8 @@ export default {
|
||||
.btn-warning,
|
||||
.btn-danger {
|
||||
padding: 0.5rem 1.5rem;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
border: 1px solid transparent;
|
||||
border-radius: 10px;
|
||||
font-size: 0.875rem;
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
@@ -212,16 +212,16 @@ export default {
|
||||
|
||||
.btn-primary {
|
||||
background: linear-gradient(135deg, var(--primary-color), var(--primary-hover));
|
||||
color: white;
|
||||
color: var(--text-on-primary);
|
||||
}
|
||||
|
||||
.btn-primary:hover {
|
||||
opacity: 0.9;
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
.btn-success {
|
||||
background: var(--primary-color);
|
||||
color: white;
|
||||
color: var(--text-on-primary);
|
||||
}
|
||||
|
||||
.btn-success:hover {
|
||||
@@ -229,21 +229,22 @@ export default {
|
||||
}
|
||||
|
||||
.btn-warning {
|
||||
background: #ffc107;
|
||||
color: #212529;
|
||||
background: rgba(181, 110, 65, 0.14);
|
||||
border-color: rgba(181, 110, 65, 0.24);
|
||||
color: #8a4f28;
|
||||
}
|
||||
|
||||
.btn-warning:hover {
|
||||
background: #e0a800;
|
||||
background: rgba(181, 110, 65, 0.2);
|
||||
}
|
||||
|
||||
.btn-danger {
|
||||
background: #dc3545;
|
||||
color: white;
|
||||
background: rgba(200, 74, 56, 0.12);
|
||||
border-color: rgba(200, 74, 56, 0.24);
|
||||
color: #8b3327;
|
||||
}
|
||||
|
||||
.btn-danger:hover {
|
||||
background: #c82333;
|
||||
background: rgba(200, 74, 56, 0.18);
|
||||
}
|
||||
</style>
|
||||
|
||||
|
||||
@@ -4650,7 +4650,7 @@ Wir wünschen den Spielen einen schönen, spannenden und fairen Verlauf und begr
|
||||
}
|
||||
|
||||
.double-btn.active {
|
||||
background-color: #28a745;
|
||||
background-color: var(--primary-color);
|
||||
color: white;
|
||||
border-color: white;
|
||||
}
|
||||
@@ -4818,13 +4818,13 @@ Wir wünschen den Spielen einen schönen, spannenden und fairen Verlauf und begr
|
||||
/* Zertifizierung-Styles */
|
||||
.section-btn.certified {
|
||||
background-color: #d4edda;
|
||||
border-color: #28a745;
|
||||
border-color: var(--primary-color);
|
||||
color: #155724;
|
||||
}
|
||||
|
||||
.certified-badge {
|
||||
font-size: 0.8em;
|
||||
background-color: #28a745;
|
||||
background-color: var(--primary-color);
|
||||
color: white;
|
||||
padding: 0 6px;
|
||||
border-radius: 10px;
|
||||
@@ -5019,20 +5019,20 @@ Wir wünschen den Spielen einen schönen, spannenden und fairen Verlauf und begr
|
||||
}
|
||||
|
||||
.copy-json-btn {
|
||||
background: #007bff;
|
||||
color: white;
|
||||
border: none;
|
||||
background: linear-gradient(135deg, var(--primary-color), var(--primary-hover));
|
||||
color: var(--text-on-primary);
|
||||
border: 1px solid transparent;
|
||||
padding: 10px 20px;
|
||||
border-radius: 6px;
|
||||
border-radius: 10px;
|
||||
cursor: pointer;
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
font-weight: 600;
|
||||
transition: all 0.2s;
|
||||
align-self: flex-start;
|
||||
}
|
||||
|
||||
.copy-json-btn:hover {
|
||||
background: #0056b3;
|
||||
opacity: 0.95;
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
@@ -5179,19 +5179,19 @@ Wir wünschen den Spielen einen schönen, spannenden und fairen Verlauf und begr
|
||||
}
|
||||
|
||||
.time-btn-small {
|
||||
background-color: #28a745;
|
||||
color: white;
|
||||
border: none;
|
||||
background: linear-gradient(135deg, var(--primary-color), var(--primary-hover));
|
||||
color: var(--text-on-primary);
|
||||
border: 1px solid transparent;
|
||||
padding: 4px 8px;
|
||||
border-radius: 4px;
|
||||
border-radius: 8px;
|
||||
font-size: 12px;
|
||||
font-weight: 500;
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
.time-btn-small:hover:not(:disabled) {
|
||||
background-color: #218838;
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
.time-btn-small:disabled {
|
||||
@@ -5209,11 +5209,11 @@ Wir wünschen den Spielen einen schönen, spannenden und fairen Verlauf und begr
|
||||
}
|
||||
|
||||
.time-btn {
|
||||
background-color: #28a745;
|
||||
color: white;
|
||||
border: none;
|
||||
background: linear-gradient(135deg, var(--primary-color), var(--primary-hover));
|
||||
color: var(--text-on-primary);
|
||||
border: 1px solid transparent;
|
||||
padding: 8px 16px;
|
||||
border-radius: 6px;
|
||||
border-radius: 10px;
|
||||
font-weight: 500;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s ease;
|
||||
@@ -5224,7 +5224,6 @@ Wir wünschen den Spielen einen schönen, spannenden und fairen Verlauf und begr
|
||||
}
|
||||
|
||||
.time-btn:hover:not(:disabled) {
|
||||
background-color: #218838;
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
@@ -5236,11 +5235,11 @@ Wir wünschen den Spielen einen schönen, spannenden und fairen Verlauf und begr
|
||||
}
|
||||
|
||||
.autofill-btn {
|
||||
background-color: #28a745;
|
||||
color: white;
|
||||
border: none;
|
||||
background: linear-gradient(135deg, var(--primary-color), var(--primary-hover));
|
||||
color: var(--text-on-primary);
|
||||
border: 1px solid transparent;
|
||||
padding: 12px 20px;
|
||||
border-radius: 8px;
|
||||
border-radius: 10px;
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
@@ -5248,13 +5247,12 @@ Wir wünschen den Spielen einen schönen, spannenden und fairen Verlauf und begr
|
||||
gap: 8px;
|
||||
transition: all 0.3s ease;
|
||||
font-size: 14px;
|
||||
box-shadow: 0 4px 12px rgba(40, 167, 69, 0.3);
|
||||
box-shadow: 0 8px 18px rgba(47, 122, 95, 0.18);
|
||||
}
|
||||
|
||||
.autofill-btn:hover:not(:disabled) {
|
||||
background-color: #218838;
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 6px 16px rgba(40, 167, 69, 0.4);
|
||||
box-shadow: 0 12px 24px rgba(47, 122, 95, 0.24);
|
||||
}
|
||||
|
||||
.autofill-btn:disabled {
|
||||
@@ -5307,10 +5305,10 @@ Wir wünschen den Spielen einen schönen, spannenden und fairen Verlauf und begr
|
||||
}
|
||||
|
||||
.pin-modal-error {
|
||||
color: #dc3545;
|
||||
background-color: #f8d7da;
|
||||
border: 1px solid #f5c6cb;
|
||||
border-radius: 4px;
|
||||
color: #8b3327;
|
||||
background-color: rgba(200, 74, 56, 0.12);
|
||||
border: 1px solid rgba(200, 74, 56, 0.24);
|
||||
border-radius: 10px;
|
||||
padding: 10px;
|
||||
margin-top: 10px;
|
||||
}
|
||||
@@ -5324,28 +5322,31 @@ Wir wünschen den Spielen einen schönen, spannenden und fairen Verlauf und begr
|
||||
}
|
||||
|
||||
.btn-secondary {
|
||||
background-color: #6c757d;
|
||||
color: white;
|
||||
border: none;
|
||||
background: var(--surface-color);
|
||||
color: var(--text-color);
|
||||
border: 1px solid var(--border-color);
|
||||
padding: 10px 20px;
|
||||
border-radius: 4px;
|
||||
border-radius: 10px;
|
||||
cursor: pointer;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.btn-secondary:hover {
|
||||
background-color: #5a6268;
|
||||
background: var(--surface-muted);
|
||||
border-color: var(--primary-soft);
|
||||
}
|
||||
|
||||
.btn-primary {
|
||||
background-color: var(--primary-color);
|
||||
color: white;
|
||||
border: none;
|
||||
background: linear-gradient(135deg, var(--primary-color), var(--primary-hover));
|
||||
color: var(--text-on-primary);
|
||||
border: 1px solid transparent;
|
||||
padding: 10px 20px;
|
||||
border-radius: 4px;
|
||||
border-radius: 10px;
|
||||
cursor: pointer;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.btn-primary:hover {
|
||||
background-color: var(--primary-hover);
|
||||
opacity: 0.95;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -159,10 +159,10 @@ export default {
|
||||
.section-title {
|
||||
font-weight: 600;
|
||||
font-size: 1.1rem;
|
||||
color: var(--primary-color);
|
||||
color: var(--primary-strong);
|
||||
margin: 0;
|
||||
padding-bottom: 0.5rem;
|
||||
border-bottom: 2px solid var(--background-light);
|
||||
border-bottom: 1px solid var(--border-color);
|
||||
}
|
||||
|
||||
.participations-list,
|
||||
@@ -178,11 +178,11 @@ export default {
|
||||
|
||||
.participation-date-header {
|
||||
font-weight: 600;
|
||||
color: var(--primary-color);
|
||||
color: var(--primary-strong);
|
||||
font-size: 0.95rem;
|
||||
margin-bottom: 0.5rem;
|
||||
padding-bottom: 0.25rem;
|
||||
border-bottom: 1px solid var(--background-light);
|
||||
border-bottom: 1px solid var(--border-color);
|
||||
}
|
||||
|
||||
.participation-activities {
|
||||
@@ -198,14 +198,15 @@ export default {
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 0.75rem;
|
||||
background: var(--background-light);
|
||||
border-radius: 4px;
|
||||
background: var(--surface-muted);
|
||||
border: 1px solid var(--border-color);
|
||||
border-radius: 10px;
|
||||
transition: background-color 0.3s ease;
|
||||
}
|
||||
|
||||
.participation-item:hover,
|
||||
.stat-item:hover {
|
||||
background: var(--background-hover, rgba(0, 0, 0, 0.05));
|
||||
background: rgba(47, 122, 95, 0.08);
|
||||
}
|
||||
|
||||
.participation-name,
|
||||
@@ -222,7 +223,7 @@ export default {
|
||||
|
||||
.stat-count {
|
||||
font-weight: 600;
|
||||
color: var(--primary-color);
|
||||
color: var(--primary-strong);
|
||||
font-size: 1.1rem;
|
||||
}
|
||||
|
||||
@@ -233,4 +234,3 @@ export default {
|
||||
font-style: italic;
|
||||
}
|
||||
</style>
|
||||
|
||||
|
||||
@@ -238,7 +238,7 @@ export default {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
background: #f9f9f9;
|
||||
background: var(--surface-muted);
|
||||
flex-shrink: 0;
|
||||
position: relative;
|
||||
z-index: 10;
|
||||
@@ -250,11 +250,12 @@ export default {
|
||||
}
|
||||
|
||||
.gallery-controls select {
|
||||
padding: 6px 12px;
|
||||
padding: 0.6rem 0.8rem;
|
||||
border: 1px solid var(--border-color, #ddd);
|
||||
border-radius: 4px;
|
||||
border-radius: 10px;
|
||||
font-size: 14px;
|
||||
background: white;
|
||||
background: var(--surface-color);
|
||||
color: var(--text-color, #333);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
@@ -324,8 +325,8 @@ export default {
|
||||
.gallery-member-name {
|
||||
font-size: 12px;
|
||||
text-align: center;
|
||||
color: #ff6b6b;
|
||||
font-weight: 500;
|
||||
color: #fff7e8;
|
||||
font-weight: 600;
|
||||
margin: 0;
|
||||
padding: 4px 8px;
|
||||
position: absolute;
|
||||
@@ -339,16 +340,16 @@ export default {
|
||||
}
|
||||
|
||||
.gallery-member-item.is-participant .gallery-member-name {
|
||||
color: #51cf66;
|
||||
color: #d9f7df;
|
||||
}
|
||||
|
||||
.gallery-member-placeholder {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background-color: #f0f0f0;
|
||||
background-color: var(--surface-muted);
|
||||
border-radius: 0;
|
||||
color: #999;
|
||||
color: var(--text-muted);
|
||||
font-size: 12px;
|
||||
margin: 0;
|
||||
position: absolute;
|
||||
@@ -359,4 +360,3 @@ export default {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
</style>
|
||||
|
||||
|
||||
@@ -130,8 +130,9 @@ export default {
|
||||
|
||||
.notes-header-info {
|
||||
padding: 0.5rem;
|
||||
background: var(--background-light);
|
||||
border-radius: 4px;
|
||||
background: var(--surface-muted);
|
||||
border: 1px solid var(--border-color);
|
||||
border-radius: 10px;
|
||||
font-size: 0.9rem;
|
||||
color: var(--text-muted);
|
||||
}
|
||||
@@ -173,11 +174,13 @@ export default {
|
||||
|
||||
.note-textarea {
|
||||
width: 100%;
|
||||
padding: 0.5rem;
|
||||
padding: 0.75rem 0.875rem;
|
||||
border: 1px solid var(--border-color);
|
||||
border-radius: 4px;
|
||||
border-radius: 10px;
|
||||
font-family: inherit;
|
||||
resize: vertical;
|
||||
background: var(--surface-muted);
|
||||
color: var(--text-color);
|
||||
}
|
||||
|
||||
.notes-list h4 {
|
||||
@@ -197,8 +200,9 @@ export default {
|
||||
gap: 0.5rem;
|
||||
padding: 0.5rem;
|
||||
margin-bottom: 0.5rem;
|
||||
background: var(--background-light);
|
||||
border-radius: 4px;
|
||||
background: var(--surface-muted);
|
||||
border: 1px solid var(--border-color);
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
.note-content {
|
||||
@@ -221,17 +225,18 @@ export default {
|
||||
.btn-primary {
|
||||
align-self: flex-start;
|
||||
padding: 0.5rem 1rem;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
border: 1px solid transparent;
|
||||
border-radius: 10px;
|
||||
background: linear-gradient(135deg, var(--primary-color), var(--primary-hover));
|
||||
color: white;
|
||||
color: var(--text-on-primary);
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
transition: opacity 0.2s;
|
||||
transition: opacity 0.2s ease, transform 0.2s ease;
|
||||
}
|
||||
|
||||
.btn-primary:hover {
|
||||
opacity: 0.9;
|
||||
opacity: 0.95;
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
@@ -246,4 +251,3 @@ export default {
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
|
||||
@@ -141,6 +141,7 @@ export default {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 1rem;
|
||||
padding: 0.25rem;
|
||||
}
|
||||
|
||||
.controls-bar {
|
||||
@@ -167,8 +168,8 @@ export default {
|
||||
.recommendations-column h4 {
|
||||
margin: 0 0 0.75rem 0;
|
||||
padding-bottom: 0.5rem;
|
||||
border-bottom: 2px solid var(--primary-color);
|
||||
color: var(--primary-color);
|
||||
border-bottom: 1px solid var(--primary-soft);
|
||||
color: var(--primary-strong);
|
||||
}
|
||||
|
||||
.checkbox-list {
|
||||
@@ -176,22 +177,23 @@ export default {
|
||||
overflow-y: auto;
|
||||
max-height: 500px;
|
||||
border: 1px solid var(--border-color);
|
||||
border-radius: 4px;
|
||||
padding: 0.5rem;
|
||||
border-radius: 12px;
|
||||
padding: 0.625rem;
|
||||
background: var(--surface-muted);
|
||||
}
|
||||
|
||||
.checkbox-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
padding: 0.5rem;
|
||||
padding: 0.625rem 0.7rem;
|
||||
cursor: pointer;
|
||||
border-radius: 4px;
|
||||
border-radius: 10px;
|
||||
transition: background-color 0.2s;
|
||||
}
|
||||
|
||||
.checkbox-item:hover {
|
||||
background: var(--background-light);
|
||||
background: rgba(47, 122, 95, 0.08);
|
||||
}
|
||||
|
||||
.checkbox-item input[type="checkbox"] {
|
||||
@@ -215,9 +217,9 @@ export default {
|
||||
|
||||
.btn-primary,
|
||||
.btn-secondary {
|
||||
padding: 0.5rem 1.5rem;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
padding: 0.65rem 1.4rem;
|
||||
border: 1px solid transparent;
|
||||
border-radius: 10px;
|
||||
font-size: 0.875rem;
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
@@ -226,7 +228,7 @@ export default {
|
||||
|
||||
.btn-primary {
|
||||
background: linear-gradient(135deg, var(--primary-color), var(--primary-hover));
|
||||
color: white;
|
||||
color: var(--text-on-primary);
|
||||
}
|
||||
|
||||
.btn-primary:hover:not(:disabled) {
|
||||
@@ -239,12 +241,14 @@ export default {
|
||||
}
|
||||
|
||||
.btn-secondary {
|
||||
background: #6c757d;
|
||||
color: white;
|
||||
background: var(--surface-color);
|
||||
border-color: var(--border-color);
|
||||
color: var(--text-color);
|
||||
}
|
||||
|
||||
.btn-secondary:hover {
|
||||
background: #5a6268;
|
||||
background: var(--surface-muted);
|
||||
border-color: var(--primary-soft);
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
@@ -257,4 +261,3 @@ export default {
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
|
||||
@@ -604,16 +604,17 @@ export default {
|
||||
display: inline-block;
|
||||
margin-top: 1rem;
|
||||
padding: 0.75rem 1.5rem;
|
||||
background-color: #007bff;
|
||||
color: white;
|
||||
background: linear-gradient(135deg, var(--primary-color), var(--primary-hover));
|
||||
color: var(--text-on-primary);
|
||||
text-decoration: none;
|
||||
border-radius: 4px;
|
||||
font-weight: 500;
|
||||
transition: background-color 0.2s;
|
||||
border-radius: 10px;
|
||||
font-weight: 600;
|
||||
transition: transform 0.2s ease, opacity 0.2s ease;
|
||||
}
|
||||
|
||||
.btn-link:hover {
|
||||
background-color: #0056b3;
|
||||
opacity: 0.95;
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
.config-summary {
|
||||
@@ -656,10 +657,10 @@ export default {
|
||||
|
||||
.btn-link-small {
|
||||
display: inline-block;
|
||||
color: #007bff;
|
||||
color: var(--primary-color);
|
||||
text-decoration: none;
|
||||
font-size: 0.9em;
|
||||
font-weight: 500;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.btn-link-small:hover {
|
||||
@@ -674,18 +675,19 @@ export default {
|
||||
}
|
||||
|
||||
.btn-primary {
|
||||
background-color: #007bff;
|
||||
color: white;
|
||||
border: none;
|
||||
background: linear-gradient(135deg, var(--primary-color), var(--primary-hover));
|
||||
color: var(--text-on-primary);
|
||||
border: 1px solid transparent;
|
||||
padding: 0.5rem 1.5rem;
|
||||
border-radius: 4px;
|
||||
border-radius: 10px;
|
||||
cursor: pointer;
|
||||
font-weight: 500;
|
||||
transition: background-color 0.2s;
|
||||
font-weight: 600;
|
||||
transition: transform 0.2s ease, opacity 0.2s ease;
|
||||
}
|
||||
|
||||
.btn-primary:hover:not(:disabled) {
|
||||
background-color: #0056b3;
|
||||
opacity: 0.95;
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
.btn-primary:disabled {
|
||||
@@ -695,18 +697,18 @@ export default {
|
||||
}
|
||||
|
||||
.btn-secondary {
|
||||
background-color: #6c757d;
|
||||
color: white;
|
||||
border: none;
|
||||
background: var(--surface-color);
|
||||
color: var(--text-color);
|
||||
border: 1px solid var(--border-color);
|
||||
padding: 0.5rem 1.5rem;
|
||||
border-radius: 4px;
|
||||
border-radius: 10px;
|
||||
cursor: pointer;
|
||||
font-weight: 500;
|
||||
transition: background-color 0.2s;
|
||||
font-weight: 600;
|
||||
transition: background-color 0.2s ease, border-color 0.2s ease;
|
||||
}
|
||||
|
||||
.btn-secondary:hover {
|
||||
background-color: #5a6268;
|
||||
background: var(--surface-muted);
|
||||
border-color: var(--primary-soft);
|
||||
}
|
||||
</style>
|
||||
|
||||
|
||||
@@ -235,7 +235,7 @@ export default {
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background-color: rgba(0, 0, 0, 0.5);
|
||||
background: rgba(15, 23, 42, 0.38);
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
@@ -243,9 +243,10 @@ export default {
|
||||
}
|
||||
|
||||
.modal {
|
||||
background: white;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.3);
|
||||
background: var(--surface-color);
|
||||
border: 1px solid var(--border-color);
|
||||
border-radius: 14px;
|
||||
box-shadow: 0 18px 48px rgba(15, 23, 42, 0.18);
|
||||
max-width: 600px;
|
||||
width: 90%;
|
||||
max-height: 90vh;
|
||||
@@ -256,12 +257,13 @@ export default {
|
||||
|
||||
.modal-header {
|
||||
padding: 1.5rem;
|
||||
border-bottom: 1px solid #dee2e6;
|
||||
border-bottom: 1px solid var(--border-color);
|
||||
background: linear-gradient(180deg, rgba(47, 122, 95, 0.12), rgba(47, 122, 95, 0.04));
|
||||
}
|
||||
|
||||
.modal-header h3 {
|
||||
margin: 0;
|
||||
color: #495057;
|
||||
color: var(--text-color);
|
||||
}
|
||||
|
||||
.modal-body {
|
||||
@@ -271,10 +273,11 @@ export default {
|
||||
|
||||
.modal-footer {
|
||||
padding: 1rem 1.5rem;
|
||||
border-top: 1px solid #dee2e6;
|
||||
border-top: 1px solid var(--border-color);
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
gap: 1rem;
|
||||
background: var(--surface-muted);
|
||||
}
|
||||
|
||||
.form-group {
|
||||
@@ -285,26 +288,28 @@ export default {
|
||||
display: block;
|
||||
margin-bottom: 0.5rem;
|
||||
font-weight: 600;
|
||||
color: #495057;
|
||||
color: var(--text-color);
|
||||
}
|
||||
|
||||
.form-group input[type="text"],
|
||||
.form-group input[type="email"],
|
||||
.form-group input[type="password"] {
|
||||
width: 100%;
|
||||
padding: 0.75rem;
|
||||
border: 1px solid #ced4da;
|
||||
border-radius: 4px;
|
||||
padding: 0.75rem 0.875rem;
|
||||
border: 1px solid var(--border-color);
|
||||
border-radius: 10px;
|
||||
font-size: 1rem;
|
||||
box-sizing: border-box;
|
||||
background: var(--surface-muted);
|
||||
color: var(--text-color);
|
||||
}
|
||||
|
||||
.form-group input[type="text"]:focus,
|
||||
.form-group input[type="email"]:focus,
|
||||
.form-group input[type="password"]:focus {
|
||||
outline: none;
|
||||
border-color: #007bff;
|
||||
box-shadow: 0 0 0 0.2rem rgba(0, 123, 255, 0.25);
|
||||
border-color: var(--primary-color);
|
||||
box-shadow: 0 0 0 3px rgba(47, 122, 95, 0.16);
|
||||
}
|
||||
|
||||
.checkbox-group label {
|
||||
@@ -324,57 +329,58 @@ export default {
|
||||
.hint {
|
||||
margin-top: 0.5rem;
|
||||
font-size: 0.875rem;
|
||||
color: #6c757d;
|
||||
font-style: italic;
|
||||
color: var(--text-muted);
|
||||
}
|
||||
|
||||
.warning {
|
||||
margin-top: 0.5rem;
|
||||
font-size: 0.875rem;
|
||||
color: #dc3545;
|
||||
color: var(--danger-color);
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.error-message {
|
||||
padding: 0.75rem;
|
||||
background-color: #f8d7da;
|
||||
border: 1px solid #f5c6cb;
|
||||
border-radius: 4px;
|
||||
color: #721c24;
|
||||
background: rgba(200, 74, 56, 0.12);
|
||||
border: 1px solid rgba(200, 74, 56, 0.24);
|
||||
border-radius: 10px;
|
||||
color: #7a2e21;
|
||||
margin-top: 1rem;
|
||||
}
|
||||
|
||||
.btn-primary, .btn-secondary {
|
||||
padding: 0.75rem 1.5rem;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
font-size: 1rem;
|
||||
border: 1px solid transparent;
|
||||
border-radius: 10px;
|
||||
font-size: 0.95rem;
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
transition: background-color 0.2s ease;
|
||||
transition: background-color 0.2s ease, border-color 0.2s ease, transform 0.2s ease;
|
||||
}
|
||||
|
||||
.btn-primary {
|
||||
background-color: #007bff;
|
||||
color: white;
|
||||
background: linear-gradient(135deg, var(--primary-color), var(--primary-hover));
|
||||
color: var(--text-on-primary);
|
||||
}
|
||||
|
||||
.btn-primary:hover:not(:disabled) {
|
||||
background-color: #0056b3;
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
.btn-primary:disabled {
|
||||
background-color: #6c757d;
|
||||
cursor: not-allowed;
|
||||
opacity: 0.6;
|
||||
opacity: 0.55;
|
||||
}
|
||||
|
||||
.btn-secondary {
|
||||
background-color: #6c757d;
|
||||
color: white;
|
||||
background: var(--surface-color);
|
||||
border-color: var(--border-color);
|
||||
color: var(--text-color);
|
||||
}
|
||||
|
||||
.btn-secondary:hover:not(:disabled) {
|
||||
background-color: #545b62;
|
||||
background: var(--surface-muted);
|
||||
border-color: var(--primary-soft);
|
||||
}
|
||||
|
||||
.btn-secondary:disabled {
|
||||
@@ -382,4 +388,3 @@ export default {
|
||||
opacity: 0.6;
|
||||
}
|
||||
</style>
|
||||
|
||||
|
||||
@@ -446,16 +446,16 @@ export default {
|
||||
}
|
||||
|
||||
.download-btn:hover:not(:disabled) {
|
||||
background: #0056b3;
|
||||
background: var(--secondary-hover);
|
||||
}
|
||||
|
||||
.create-btn {
|
||||
background: #28a745;
|
||||
color: white;
|
||||
background: linear-gradient(135deg, var(--primary-color), var(--primary-hover));
|
||||
color: var(--text-on-primary);
|
||||
}
|
||||
|
||||
.create-btn:hover:not(:disabled) {
|
||||
background: #218838;
|
||||
opacity: 0.95;
|
||||
}
|
||||
|
||||
.analyze-btn:disabled, .download-btn:disabled, .create-btn:disabled {
|
||||
@@ -525,4 +525,4 @@ export default {
|
||||
.log-entry {
|
||||
margin-bottom: 2px;
|
||||
}
|
||||
</style>
|
||||
</style>
|
||||
|
||||
@@ -130,6 +130,7 @@ export default {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 1rem;
|
||||
padding: 0.25rem;
|
||||
}
|
||||
|
||||
.form-row {
|
||||
@@ -153,11 +154,13 @@ export default {
|
||||
.form-input,
|
||||
.form-select {
|
||||
width: 100%;
|
||||
padding: 0.5rem;
|
||||
padding: 0.75rem 0.875rem;
|
||||
border: 1px solid var(--border-color);
|
||||
border-radius: 4px;
|
||||
border-radius: 10px;
|
||||
font-family: inherit;
|
||||
font-size: 0.9rem;
|
||||
background: var(--surface-muted);
|
||||
color: var(--text-color);
|
||||
}
|
||||
|
||||
.form-input:focus,
|
||||
@@ -169,9 +172,9 @@ export default {
|
||||
|
||||
.btn-primary,
|
||||
.btn-secondary {
|
||||
padding: 0.5rem 1.5rem;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
padding: 0.65rem 1.4rem;
|
||||
border: 1px solid transparent;
|
||||
border-radius: 10px;
|
||||
font-size: 0.875rem;
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
@@ -180,7 +183,7 @@ export default {
|
||||
|
||||
.btn-primary {
|
||||
background: linear-gradient(135deg, var(--primary-color), var(--primary-hover));
|
||||
color: white;
|
||||
color: var(--text-on-primary);
|
||||
}
|
||||
|
||||
.btn-primary:hover:not(:disabled) {
|
||||
@@ -193,12 +196,14 @@ export default {
|
||||
}
|
||||
|
||||
.btn-secondary {
|
||||
background: #6c757d;
|
||||
color: white;
|
||||
background: var(--surface-color);
|
||||
border-color: var(--border-color);
|
||||
color: var(--text-color);
|
||||
}
|
||||
|
||||
.btn-secondary:hover {
|
||||
background: #5a6268;
|
||||
background: var(--surface-muted);
|
||||
border-color: var(--primary-soft);
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
@@ -207,4 +212,3 @@ export default {
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
|
||||
@@ -453,17 +453,18 @@ export default {
|
||||
}
|
||||
|
||||
.btn-primary {
|
||||
background: #28a745;
|
||||
color: #fff;
|
||||
border: none;
|
||||
background: linear-gradient(135deg, var(--primary-color), var(--primary-hover));
|
||||
color: var(--text-on-primary);
|
||||
border: 1px solid transparent;
|
||||
padding: 8px 16px;
|
||||
border-radius: 4px;
|
||||
border-radius: 10px;
|
||||
cursor: pointer;
|
||||
font-size: 0.9rem;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.btn-primary:hover {
|
||||
background: #218838;
|
||||
opacity: 0.95;
|
||||
}
|
||||
|
||||
.btn-secondary {
|
||||
@@ -480,4 +481,3 @@ export default {
|
||||
background: #5a6268;
|
||||
}
|
||||
</style>
|
||||
|
||||
|
||||
@@ -75,6 +75,8 @@
|
||||
"logs": "System-Logs",
|
||||
"memberTransfer": "Mitgliederübertragung",
|
||||
"myTischtennisAccount": "myTischtennis-Account",
|
||||
"clickTtAccount": "HTTV / click-TT Account",
|
||||
"clickTtBrowser": "HTTV / click-TT",
|
||||
"personalSettings": "Persönliche Einstellungen",
|
||||
"logout": "Ausloggen",
|
||||
"login": "Einloggen",
|
||||
@@ -441,6 +443,9 @@
|
||||
"addGroup": "Gruppe hinzufügen",
|
||||
"activityOrTimeblock": "Aktivität / Zeitblock",
|
||||
"durationMinutes": "Dauer (Min)",
|
||||
"standardActivities": "Standard-Aktivitäten",
|
||||
"standardDurationShort": "Min",
|
||||
"standardActivityAddError": "Standard-Aktivität konnte nicht hinzugefügt werden.",
|
||||
"addGroupActivity": "Gruppen-Aktivität hinzufügen",
|
||||
"addGroupButton": "+ Gruppe",
|
||||
"all": "Alle",
|
||||
@@ -497,7 +502,7 @@
|
||||
"errorOccurred": "Ein Fehler ist aufgetreten. Bitte versuchen Sie es erneut.",
|
||||
"trainingTimesUpdated": "Trainingszeiten erfolgreich aktualisiert.",
|
||||
"noActiveTrainingDay": "Kein Trainingstag ausgewählt.",
|
||||
"statusReady": "Zeiten, Teilnehmer und Trainingsplan sind gepflegt.",
|
||||
"statusReady": "Zeiten und Trainingsplan sind gepflegt.",
|
||||
"statusEmpty": "Dieser Trainingstag ist noch leer.",
|
||||
"statusInProgress": "Dieser Trainingstag ist teilweise vorbereitet.",
|
||||
"formMarkedAsHandedOver": "Mitgliedsformular als ausgehändigt markiert",
|
||||
@@ -1090,6 +1095,9 @@
|
||||
"title": "Vordefinierte Aktivitäten",
|
||||
"new": "Neu",
|
||||
"reload": "Neu laden",
|
||||
"filterAll": "Alle",
|
||||
"filterStandard": "Standard-Aktivitäten",
|
||||
"filterCustom": "Selbstdefiniert",
|
||||
"searchPlaceholder": "Kürzel suchen (z.B. 'as vh us' oder 'vh as us')...",
|
||||
"deduplicate": "Doppelungen zusammenführen",
|
||||
"selectSource": "Quelle wählen…",
|
||||
@@ -1104,6 +1112,7 @@
|
||||
"duration": "Dauer (Minuten)",
|
||||
"durationText": "Dauer (Text)",
|
||||
"durationTextPlaceholder": "z.B. 2x7",
|
||||
"excludeFromStats": "Nicht in Statistik berücksichtigen",
|
||||
"description": "Beschreibung",
|
||||
"addImage": "Bild hinzufügen",
|
||||
"imageHelp": "Du kannst entweder einen Link zu einem Bild eingeben oder ein Bild hochladen:",
|
||||
@@ -1130,15 +1139,31 @@
|
||||
},
|
||||
"schedule": {
|
||||
"title": "Spielpläne",
|
||||
"subtitle": "Teams auswählen, Spieltage prüfen und Ligatabellen im Blick behalten.",
|
||||
"importSchedule": "Spielplanimport",
|
||||
"galleryLoading": "Galerie wird geladen…",
|
||||
"gallery": "Mitglieder-Galerie",
|
||||
"overallSchedule": "Gesamtspielplan",
|
||||
"adultSchedule": "Spielplan Erwachsene",
|
||||
"noTeamsFound": "Keine Teams für diese Saison gefunden",
|
||||
"noMatchingTeams": "Keine Teams passen zur aktuellen Suche.",
|
||||
"searchTeams": "Team oder Liga suchen",
|
||||
"selection": "Auswahl",
|
||||
"activeSelection": "Aktive Auswahl",
|
||||
"noSelectionTitle": "Noch keine Auswahl aktiv",
|
||||
"noSelectionMessage": "Wählen Sie links einen Gesamtspielplan, den Erwachsenenspielplan oder ein Team aus.",
|
||||
"scheduleTab": "Spielplan",
|
||||
"tableTab": "Tabelle",
|
||||
"downloadPDF": "Download PDF",
|
||||
"refreshTable": "Tabelle aktualisieren",
|
||||
"tableLoading": "Tabelle wird geladen…",
|
||||
"fetchTeamData": "Spielplan & Ergebnisse abrufen",
|
||||
"fetchingTeamData": "Abruf läuft…",
|
||||
"fetchStartFailed": "Abruf konnte nicht gestartet werden.",
|
||||
"fetchDataFailed": "Teamdaten konnten nicht abgerufen werden.",
|
||||
"fetchTimedOut": "Zeitüberschreitung beim Abruf.",
|
||||
"teamDataFetched": "Teamdaten erfolgreich aktualisiert.",
|
||||
"teamDataFetchedDetails": "Mannschaft: {team}\nVerarbeitete Datensätze: {count}",
|
||||
"gamesFor": "Spiele für",
|
||||
"date": "Datum",
|
||||
"time": "Uhrzeit",
|
||||
@@ -1153,7 +1178,19 @@
|
||||
"leagueTable": "Ligatabelle",
|
||||
"position": "Platz",
|
||||
"team": "Team",
|
||||
"teams": "Teams",
|
||||
"matches": "Matches",
|
||||
"completedShort": "Abgeschlossen",
|
||||
"pendingShort": "Offen",
|
||||
"nextMatch": "Nächstes Spiel",
|
||||
"workspaceScheduleDescription": "{matches} Spiele, davon {completed} abgeschlossen und {pending} offen.",
|
||||
"workspaceTableDescription": "{count} Tabellenzeilen aktuell geladen.",
|
||||
"matchOverviewTitle": "Spielübersicht",
|
||||
"matchOverviewDescription": "Steuert, welche Spiele aus der aktuell gewählten Liga im Spielplan angezeigt werden.",
|
||||
"ownTeamMatches": "Eigene Mannschaft",
|
||||
"allLeagueMatches": "Alle Spiele",
|
||||
"otherTeamMatches": "Andere Mannschaft",
|
||||
"selectOtherTeam": "Andere Mannschaft wählen",
|
||||
"sets": "Sätze",
|
||||
"points": "Pkt.",
|
||||
"balls": "Bälle",
|
||||
@@ -1196,6 +1233,7 @@
|
||||
},
|
||||
"teamManagement": {
|
||||
"title": "Team-Verwaltung",
|
||||
"subtitle": "Teams auswählen, Konfiguration prüfen und Liga-Daten an einem Ort pflegen.",
|
||||
"ratingUpdates": "Rating-Updates",
|
||||
"lastRun": "Zuletzt",
|
||||
"updated": "aktualisiert",
|
||||
@@ -1204,16 +1242,24 @@
|
||||
"fetched": "abgerufen",
|
||||
"newTeam": "Neues Team",
|
||||
"basicSettings": "Grundeinstellungen",
|
||||
"basicSettingsIntro": "Teamname und Liga in einem ruhigen Formular prüfen und anpassen.",
|
||||
"editTeam": "Team bearbeiten",
|
||||
"createNewTeam": "Neues Team anlegen",
|
||||
"teamName": "Team-Name",
|
||||
"teamNamePlaceholder": "z.B. Herren 1, Damen 2",
|
||||
"league": "Spielklasse",
|
||||
"team": "Team",
|
||||
"teamId": "Team-ID",
|
||||
"groupId": "Gruppen-ID",
|
||||
"association": "Verband",
|
||||
"groupName": "Gruppenname",
|
||||
"noLeague": "Keine Spielklasse",
|
||||
"change": "Ändern",
|
||||
"createAndEdit": "Anlegen & Bearbeiten",
|
||||
"clearFields": "Felder leeren",
|
||||
"playerStats": "Spieleinsätze",
|
||||
"playerStatsIntro": "Schneller Überblick über Einsätze der Mannschaft in dieser Saison.",
|
||||
"refreshStats": "Aktualisieren",
|
||||
"loadingStats": "Lade Statistiken...",
|
||||
"noPlayerStats": "Keine Spieleinsätze erfasst.",
|
||||
"player": "Spieler",
|
||||
@@ -1225,6 +1271,14 @@
|
||||
"secondHalf": "Rückrunde",
|
||||
"secondHalfFull": "Rückrunde (ab 1. Januar)",
|
||||
"documents": "Dokumente",
|
||||
"documentsIntro": "Code- und PIN-Listen hochladen, prüfen und bei Bedarf erneut parsen.",
|
||||
"documentAvailable": "Vorhanden",
|
||||
"documentMissing": "Fehlt",
|
||||
"latestUpload": "Zuletzt hochgeladen: {date}",
|
||||
"noDocumentUploadYet": "Noch kein Dokument hochgeladen.",
|
||||
"uploadNewVersion": "Neue Version hochladen",
|
||||
"openDocument": "Anzeigen",
|
||||
"parseDocument": "Neu parsen",
|
||||
"codeList": "Code-Liste",
|
||||
"pinList": "Pin-Liste",
|
||||
"automaticJobs": "Automatische Jobs",
|
||||
@@ -1233,10 +1287,16 @@
|
||||
"successful": "Erfolgreich",
|
||||
"noAutomaticUpdate": "Noch keine automatische Aktualisierung",
|
||||
"myTischtennis": "MyTischtennis",
|
||||
"myTischtennisIntro": "URL einfügen, Konfiguration prüfen und bei Bedarf Daten manuell abrufen.",
|
||||
"configurationStatus": "Konfigurationsstatus",
|
||||
"manualFetch": "Abrufen",
|
||||
"noIssues": "Keine offenen Konfigurationsprobleme.",
|
||||
"parseUrlAction": "URL prüfen",
|
||||
"myTischtennisUrlPlaceholder": "MyTischtennis URL...",
|
||||
"teams": "Teams",
|
||||
"activeTeam": "Aktives Team",
|
||||
"searchTeams": "Team suchen",
|
||||
"openInWorkspace": "Zum Bearbeiten öffnen",
|
||||
"filterAll": "Alle",
|
||||
"filterConfigured": "Konfiguriert",
|
||||
"filterNeedsAttention": "Prüfen",
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
"edit": "Edit",
|
||||
"add": "Add",
|
||||
"close": "Close",
|
||||
"details": "Details",
|
||||
"confirm": "Confirm",
|
||||
"yes": "Yes",
|
||||
"no": "No",
|
||||
@@ -41,6 +42,8 @@
|
||||
"logs": "System Logs",
|
||||
"memberTransfer": "Member Transfer",
|
||||
"myTischtennisAccount": "myTischtennis Account",
|
||||
"clickTtAccount": "HTTV / click-TT Account",
|
||||
"clickTtBrowser": "HTTV / click-TT",
|
||||
"personalSettings": "Personal Settings",
|
||||
"logout": "Logout",
|
||||
"login": "Login",
|
||||
@@ -126,6 +129,18 @@
|
||||
"confirm": "Confirm",
|
||||
"cancel": "Cancel"
|
||||
},
|
||||
"diary": {
|
||||
"standardActivities": "Standard activities",
|
||||
"standardDurationShort": "Min",
|
||||
"standardActivityAddError": "Standard activity could not be added.",
|
||||
"statusReady": "Times and training plan are set."
|
||||
},
|
||||
"predefinedActivities": {
|
||||
"excludeFromStats": "Exclude from statistics",
|
||||
"filterAll": "All",
|
||||
"filterStandard": "Standard activities",
|
||||
"filterCustom": "Custom"
|
||||
},
|
||||
"tournaments": {
|
||||
"numberOfTables": "Number of tables",
|
||||
"table": "Table",
|
||||
@@ -364,6 +379,100 @@
|
||||
"statusActionGenerate": "Generate",
|
||||
"statusActionStart": "Start"
|
||||
},
|
||||
"schedule": {
|
||||
"title": "Schedules",
|
||||
"subtitle": "Select teams, review fixtures and keep league tables in view.",
|
||||
"importSchedule": "Import schedule",
|
||||
"galleryLoading": "Loading gallery…",
|
||||
"gallery": "Member gallery",
|
||||
"overallSchedule": "Overall schedule",
|
||||
"adultSchedule": "Adult schedule",
|
||||
"noTeamsFound": "No teams found for this season",
|
||||
"noMatchingTeams": "No teams match the current search.",
|
||||
"searchTeams": "Search team or league",
|
||||
"selection": "Selection",
|
||||
"activeSelection": "Active selection",
|
||||
"noSelectionTitle": "No active selection yet",
|
||||
"noSelectionMessage": "Choose the overall schedule, the adult schedule or a team from the left.",
|
||||
"scheduleTab": "Schedule",
|
||||
"tableTab": "Table",
|
||||
"downloadPDF": "Download PDF",
|
||||
"refreshTable": "Refresh table",
|
||||
"tableLoading": "Loading table…",
|
||||
"fetchTeamData": "Fetch schedule & results",
|
||||
"fetchingTeamData": "Fetching…",
|
||||
"fetchStartFailed": "The fetch could not be started.",
|
||||
"fetchDataFailed": "Team data could not be fetched.",
|
||||
"fetchTimedOut": "Timed out while fetching data.",
|
||||
"teamDataFetched": "Team data updated successfully.",
|
||||
"teamDataFetchedDetails": "Team: {team}\nProcessed records: {count}",
|
||||
"gamesFor": "Matches for",
|
||||
"date": "Date",
|
||||
"time": "Time",
|
||||
"homeTeam": "Home team",
|
||||
"guestTeam": "Away team",
|
||||
"result": "Result",
|
||||
"ageClass": "Age group",
|
||||
"code": "Code",
|
||||
"homePin": "Home PIN",
|
||||
"guestPin": "Away PIN",
|
||||
"noGames": "No matches available",
|
||||
"leagueTable": "League table",
|
||||
"position": "Position",
|
||||
"team": "Team",
|
||||
"teams": "Teams",
|
||||
"matches": "Matches",
|
||||
"completedShort": "Completed",
|
||||
"pendingShort": "Open",
|
||||
"nextMatch": "Next match",
|
||||
"workspaceScheduleDescription": "{matches} matches, {completed} completed and {pending} open.",
|
||||
"workspaceTableDescription": "{count} table rows currently loaded.",
|
||||
"matchOverviewTitle": "Match overview",
|
||||
"matchOverviewDescription": "Controls which matches from the currently selected league are shown in the schedule.",
|
||||
"ownTeamMatches": "Own team",
|
||||
"allLeagueMatches": "All matches",
|
||||
"otherTeamMatches": "Other team",
|
||||
"selectOtherTeam": "Select other team",
|
||||
"sets": "Sets",
|
||||
"points": "Pts",
|
||||
"balls": "Balls",
|
||||
"noTableData": "No table data available",
|
||||
"galleryTitle": "Member gallery - click an image to mark as ready",
|
||||
"imageSize": "Image size",
|
||||
"noMembersWithImages": "No members with images found.",
|
||||
"playerSelection": "Player selection",
|
||||
"vs": "vs",
|
||||
"loadingMembers": "Loading members...",
|
||||
"player": "Player",
|
||||
"ready": "Ready",
|
||||
"planned": "Planned",
|
||||
"played": "Played",
|
||||
"noActiveMembers": "No active members found",
|
||||
"save": "Save",
|
||||
"cancel": "Cancel",
|
||||
"openMatchReport": "Open match report",
|
||||
"copyCode": "Copy code",
|
||||
"copyHomePin": "Copy home PIN",
|
||||
"copyGuestPin": "Copy away PIN",
|
||||
"errorLoadingMembers": "Failed to load the member list.",
|
||||
"playerSelectionSaved": "Player selection saved",
|
||||
"errorSavingPlayerSelection": "Failed to save the player selection",
|
||||
"pleaseSelectGame": "Please select a match first",
|
||||
"errorLoadingGallery": "The gallery could not be loaded.",
|
||||
"errorLoadingTeams": "Failed to load teams",
|
||||
"noLeagueForTeam": "No league is assigned to this team. Please assign a league first.",
|
||||
"errorLoadingMatches": "Failed to load matches",
|
||||
"errorLoadingOverallSchedule": "Failed to load the overall schedule",
|
||||
"errorLoadingAdultSchedule": "Failed to load the adult schedule",
|
||||
"noMatchesForPDF": "No matches found to generate a PDF.",
|
||||
"errorCopying": "Error while copying",
|
||||
"schedulePDF": "Schedules.pdf",
|
||||
"selectSpecificLeague": "Please select a specific league to load the table.",
|
||||
"tableDataLoaded": "League table data loaded successfully from myTischtennis.",
|
||||
"errorLoadingTable": "Failed to load league table data from myTischtennis",
|
||||
"scheduleImportSuccess": "Schedule imported successfully.",
|
||||
"errorImportingCSV": "Failed to import the CSV file"
|
||||
},
|
||||
"members": {
|
||||
"subtitle": "Search, filter and edit members directly.",
|
||||
"closeEditor": "Close editor",
|
||||
@@ -466,5 +575,142 @@
|
||||
"composeEmail": "Compose email",
|
||||
"copyContactSummary": "Copy contact summary",
|
||||
"copyContactSummarySuccess": "Contact summary copied to clipboard."
|
||||
},
|
||||
"teamManagement": {
|
||||
"title": "Team Management",
|
||||
"subtitle": "Select teams, review configuration and maintain league data in one place.",
|
||||
"ratingUpdates": "Rating updates",
|
||||
"lastRun": "Last run",
|
||||
"updated": "updated",
|
||||
"error": "Error",
|
||||
"matchResults": "Match results",
|
||||
"fetched": "fetched",
|
||||
"newTeam": "New team",
|
||||
"basicSettings": "Basic settings",
|
||||
"basicSettingsIntro": "Review and adjust team name and league in a calmer form.",
|
||||
"editTeam": "Edit team",
|
||||
"createNewTeam": "Create new team",
|
||||
"teamName": "Team name",
|
||||
"teamNamePlaceholder": "e.g. Men 1, Women 2",
|
||||
"league": "League",
|
||||
"team": "Team",
|
||||
"teamId": "Team ID",
|
||||
"groupId": "Group ID",
|
||||
"association": "Association",
|
||||
"groupName": "Group name",
|
||||
"noLeague": "No league",
|
||||
"change": "Change",
|
||||
"createAndEdit": "Create & edit",
|
||||
"clearFields": "Clear fields",
|
||||
"playerStats": "Appearances",
|
||||
"playerStatsIntro": "Quick overview of this team's appearances in the current season.",
|
||||
"refreshStats": "Refresh",
|
||||
"loadingStats": "Loading statistics...",
|
||||
"noPlayerStats": "No appearances recorded.",
|
||||
"player": "Player",
|
||||
"qttr": "(Q)TTR rating",
|
||||
"season": "Season",
|
||||
"seasonFull": "Full season (from 1 July)",
|
||||
"firstHalf": "First half",
|
||||
"firstHalfFull": "First half (July - December)",
|
||||
"secondHalf": "Second half",
|
||||
"secondHalfFull": "Second half (from 1 January)",
|
||||
"documents": "Documents",
|
||||
"documentsIntro": "Upload, review and re-parse code lists and PIN lists when needed.",
|
||||
"documentAvailable": "Available",
|
||||
"documentMissing": "Missing",
|
||||
"latestUpload": "Last uploaded: {date}",
|
||||
"noDocumentUploadYet": "No document uploaded yet.",
|
||||
"uploadNewVersion": "Upload new version",
|
||||
"openDocument": "Open",
|
||||
"parseDocument": "Parse again",
|
||||
"codeList": "Code list",
|
||||
"pinList": "PIN list",
|
||||
"automaticJobs": "Automatic jobs",
|
||||
"lastUpdated": "Last updated",
|
||||
"status": "Status",
|
||||
"successful": "Successful",
|
||||
"noAutomaticUpdate": "No automatic update yet",
|
||||
"myTischtennis": "myTischtennis",
|
||||
"myTischtennisIntro": "Paste a URL, review the configuration and fetch data manually when needed.",
|
||||
"configurationStatus": "Configuration status",
|
||||
"manualFetch": "Fetch",
|
||||
"noIssues": "No open configuration issues.",
|
||||
"parseUrlAction": "Check URL",
|
||||
"myTischtennisUrlPlaceholder": "myTischtennis URL...",
|
||||
"teams": "Teams",
|
||||
"activeTeam": "Active team",
|
||||
"searchTeams": "Search team",
|
||||
"openInWorkspace": "Open to edit",
|
||||
"filterAll": "All",
|
||||
"filterConfigured": "Configured",
|
||||
"filterNeedsAttention": "Needs review",
|
||||
"filterNoLeague": "Without league",
|
||||
"seasonUnknown": "unknown",
|
||||
"noTeamsYet": "No teams yet. Create your first team.",
|
||||
"noMatchingTeams": "No teams match the current search or filter.",
|
||||
"edit": "Edit",
|
||||
"delete": "Delete",
|
||||
"noAssignment": "No assignment",
|
||||
"created": "Created",
|
||||
"unknown": "Unknown",
|
||||
"fullyConfigured": "Fully configured",
|
||||
"partiallyConfigured": "Partially configured",
|
||||
"notConfigured": "Not configured",
|
||||
"never": "Never",
|
||||
"showCodeList": "Show code list",
|
||||
"showPinList": "Show PIN list",
|
||||
"deleteTeamTitle": "Delete club team",
|
||||
"deleteTeamConfirm": "Do you really want to delete the club team \"{name}\"?",
|
||||
"errorDeletingTeam": "Failed to delete the club team.",
|
||||
"teamHasNoLeague": "This team is not assigned to a league.",
|
||||
"assignLeagueBeforeDocuments": "Please assign a league to the team first so documents can be processed.",
|
||||
"assignLeagueBeforeParsing": "Please assign a league to the team first to parse PDF files.",
|
||||
"documentParsedSummary": "{label} uploaded and parsed successfully.\n\nMatches found: {matchesFound}\nNew matches created: {created}\nMatches updated: {updated}",
|
||||
"errorsCount": "Errors: {count}",
|
||||
"moreErrors": "... and {count} more",
|
||||
"noMatchesFoundTitle": "No matches found",
|
||||
"noMatchesFoundDetails": "Note: No matches detected.\nLines in document: {lines}",
|
||||
"documentUploaded": "{label} \"{fileName}\" was uploaded successfully.",
|
||||
"errorUploadingDocument": "Failed to upload and parse the file.",
|
||||
"matchesSummary": "Matches found: {matchesFound}\nNew matches created: {created}\nMatches updated: {updated}",
|
||||
"errorParsingPdf": "Failed to parse the PDF file",
|
||||
"documentNotFound": "The selected document could not be found.",
|
||||
"missingLeagueForTeam": "No league was provided for the selected team.",
|
||||
"pdfFileNotFound": "The PDF file could not be found.",
|
||||
"reuploadFile": "Please upload the file again and try once more.",
|
||||
"errorLoadingPdf": "Failed to load the PDF.",
|
||||
"errorParsingUrl": "The URL could not be parsed. Please check the format.",
|
||||
"configureLeagueTitle": "Configure league?",
|
||||
"tableUrlDetected": "Table URL detected",
|
||||
"configureLeagueDetails": "Association: {association}\nSeason: {season}\nLeague: {league}\nGroup ID: {groupId}\n\nDo you want to configure this league in the database? This enables automatic table data retrieval.",
|
||||
"selectTeamTitle": "Select team",
|
||||
"selectTeamFirst": "Please select a team first",
|
||||
"selectTeamForConfiguration": "To activate the myTischtennis configuration, you must first select a team from the list.",
|
||||
"teamConfiguredSuccess": "Team configured successfully. Automatic data retrieval is now active.",
|
||||
"teamConfiguredDetails": "League: {league}\nSeason: {season}\nAutomatic data retrieval is now active.",
|
||||
"errorConfiguringTeam": "The team could not be configured.",
|
||||
"leagueConfiguredSuccess": "League configured successfully. Table data can now be retrieved automatically.",
|
||||
"leagueConfiguredDetails": "League: {league}\nSeason: {season}\nAssociation: {association}\nGroup ID: {groupId}\n\nTable data can now be retrieved automatically.",
|
||||
"errorConfiguringLeague": "The league could not be configured.",
|
||||
"notCreated": "Not created",
|
||||
"autoFetchEnabled": "Automatic data retrieval is enabled",
|
||||
"missingItems": "Missing: {items}",
|
||||
"enterUrlForAutoConfig": "Enter a myTischtennis URL for automatic configuration",
|
||||
"errorLoadingStats": "Statistics could not be loaded.",
|
||||
"asyncJobStartFailed": "The async job could not be started.",
|
||||
"dataFetchFailed": "Data could not be fetched.",
|
||||
"fetchTimedOut": "Timed out while fetching data (async job took too long).",
|
||||
"teamDataFetched": "Team data fetched successfully.",
|
||||
"unknownTeam": "Unknown team",
|
||||
"teamDataFetchedDetails": "Team: {team}\nFetched records: {count}",
|
||||
"tableUpdateLabel": "Table update:",
|
||||
"mytischtennisLoginRequired": "Login to myTischtennis required",
|
||||
"fetchTimeoutShort": "Timed out while fetching data.",
|
||||
"invalidFileTypeTitle": "Invalid file type",
|
||||
"invalidFileExtension": "{label} must have one of the following extensions: {extensions}.",
|
||||
"invalidMimeType": "{label} has an unexpected MIME type: {type}.",
|
||||
"fileTooLargeTitle": "File too large",
|
||||
"fileTooLarge": "{label} must not exceed 10 MB."
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div class="mytt-account-page">
|
||||
<div class="mytt-account-page" :class="{ 'embedded-dialog-view': embedded }">
|
||||
<div class="page-container">
|
||||
<h1>HTTV / click-TT Account</h1>
|
||||
<h1 v-if="!embedded">{{ $t('navigation.clickTtAccount') }}</h1>
|
||||
|
||||
<div class="account-container">
|
||||
<div v-if="loading" class="loading">Lade Account…</div>
|
||||
@@ -86,6 +86,12 @@ import ConfirmDialog from '../components/ConfirmDialog.vue';
|
||||
export default {
|
||||
name: 'ClickTtAccount',
|
||||
components: { ClickTtAccountDialog, InfoDialog, ConfirmDialog },
|
||||
props: {
|
||||
embedded: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
loading: true,
|
||||
@@ -196,8 +202,37 @@ export default {
|
||||
.info-row { display: flex; gap: 1rem; margin-bottom: 1rem; }
|
||||
.info-row label { min-width: 220px; font-weight: 600; }
|
||||
.button-group { display: flex; gap: 1rem; margin-top: 1.5rem; }
|
||||
.btn-primary, .btn-secondary, .btn-danger { padding: 0.75rem 1rem; border: none; border-radius: 6px; cursor: pointer; }
|
||||
.btn-primary { background: #007bff; color: white; }
|
||||
.btn-secondary { background: #6c757d; color: white; }
|
||||
.btn-danger { background: #dc3545; color: white; }
|
||||
.btn-primary, .btn-secondary, .btn-danger {
|
||||
padding: 0.75rem 1rem;
|
||||
border: 1px solid transparent;
|
||||
border-radius: 10px;
|
||||
cursor: pointer;
|
||||
font-weight: 600;
|
||||
transition: background-color 0.2s ease, border-color 0.2s ease, transform 0.2s ease;
|
||||
}
|
||||
.btn-primary {
|
||||
background: linear-gradient(135deg, var(--primary-color), var(--primary-hover));
|
||||
color: var(--text-on-primary);
|
||||
}
|
||||
.btn-primary:hover {
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
.btn-secondary {
|
||||
background: var(--surface-color);
|
||||
border-color: var(--border-color);
|
||||
color: var(--text-color);
|
||||
}
|
||||
.btn-secondary:hover {
|
||||
background: var(--surface-muted);
|
||||
border-color: var(--primary-soft);
|
||||
}
|
||||
.btn-danger {
|
||||
background: rgba(200, 74, 56, 0.12);
|
||||
border-color: rgba(200, 74, 56, 0.24);
|
||||
color: #8b3327;
|
||||
}
|
||||
.btn-danger:hover {
|
||||
background: rgba(200, 74, 56, 0.18);
|
||||
}
|
||||
.embedded-dialog-view .page-container { max-width: none; padding: 0; }
|
||||
</style>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div class="clicktt-view">
|
||||
<div class="header">
|
||||
<h1>HTTV / click-TT Seiten</h1>
|
||||
<div class="clicktt-view" :class="{ 'embedded-dialog-view': embedded }">
|
||||
<div v-if="!embedded" class="header">
|
||||
<h1>{{ $t('navigation.clickTtBrowser') }}</h1>
|
||||
<p class="subtitle">
|
||||
Lade und bediene click-TT-Seiten (Ligenübersicht, Vereinsinfo, Spielplan) im iframe.
|
||||
Alle Aufrufe werden geloggt.
|
||||
@@ -98,6 +98,12 @@ const presetUrls = {
|
||||
|
||||
export default {
|
||||
name: 'ClickTtView',
|
||||
props: {
|
||||
embedded: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
setup() {
|
||||
const pageType = ref('leaguePage');
|
||||
const association = ref('HeTTV');
|
||||
@@ -175,6 +181,10 @@ export default {
|
||||
max-width: 1400px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
.clicktt-view.embedded-dialog-view {
|
||||
padding: 0;
|
||||
max-width: none;
|
||||
}
|
||||
|
||||
.header {
|
||||
margin-bottom: 1.5rem;
|
||||
|
||||
@@ -256,10 +256,6 @@
|
||||
<span>{{ $t('diary.trainingWindow') }}</span>
|
||||
<strong>{{ Boolean(trainingStart || trainingEnd) ? $t('diary.statusReadyShort') : $t('diary.statusOpenShort') }}</strong>
|
||||
</div>
|
||||
<div class="diary-readiness-item" :class="{ 'ready': participants.length > 0 }">
|
||||
<span>{{ $t('diary.participants') }}</span>
|
||||
<strong>{{ participants.length > 0 ? $t('diary.statusReadyShort') : $t('diary.statusOpenShort') }}</strong>
|
||||
</div>
|
||||
<div class="diary-readiness-item" :class="{ 'ready': trainingPlan.length > 0 }">
|
||||
<span>{{ $t('diary.trainingPlan') }}</span>
|
||||
<strong>{{ trainingPlan.length > 0 ? $t('diary.statusReadyShort') : $t('diary.statusOpenShort') }}</strong>
|
||||
@@ -281,6 +277,23 @@
|
||||
</strong>
|
||||
<button type="button" class="btn-secondary" @click="cancelAddItem">{{ $t('common.cancel') }}</button>
|
||||
</div>
|
||||
<div v-if="addNewItem && standardDiaryActivities.length" class="plan-quick-actions">
|
||||
<span class="plan-quick-actions-label">{{ $t('diary.standardActivities') }}</span>
|
||||
<div class="plan-quick-actions-list">
|
||||
<button
|
||||
v-for="activity in standardDiaryActivities"
|
||||
:key="activity.name"
|
||||
type="button"
|
||||
class="plan-quick-action"
|
||||
@click="addStandardPlanActivity(activity)"
|
||||
>
|
||||
{{ activity.name }}
|
||||
<span v-if="activity.duration" class="plan-quick-action-meta">
|
||||
· {{ activity.duration }} {{ $t('diary.standardDurationShort') }}
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="plan-composer-grid">
|
||||
<div v-if="addNewItem || addNewGroupActivity" class="plan-composer-field">
|
||||
<label>{{ $t('diary.activityOrTimeblock') }}</label>
|
||||
@@ -489,7 +502,7 @@
|
||||
: (item.predefinedActivity ? item.predefinedActivity.name :
|
||||
item.activity) }}
|
||||
</span>
|
||||
<span class="plan-status-badge" :class="`plan-status-badge-${getPlanItemStatus(item).tone}`" :title="getPlanItemStatus(item).reason || ''">
|
||||
<span v-if="!isStructuralPlanItem(item)" class="plan-status-badge" :class="`plan-status-badge-${getPlanItemStatus(item).tone}`" :title="getPlanItemStatus(item).reason || ''">
|
||||
{{ getPlanItemStatus(item).label }}
|
||||
</span>
|
||||
</div>
|
||||
@@ -510,7 +523,7 @@
|
||||
<td>
|
||||
<div class="plan-row-actions">
|
||||
<button v-if="!item.isTimeblock" @click="startActivityEdit(item)" class="plan-row-action-button">{{ $t('common.edit') }}</button>
|
||||
<button v-if="!item.isTimeblock" @click="toggleActivityMembers(item)" :title="$t('diary.assignParticipants')"
|
||||
<button v-if="!item.isTimeblock && !isStructuralPlanItem(item)" @click="toggleActivityMembers(item)" :title="$t('diary.assignParticipants')"
|
||||
class="plan-row-action-button">{{ $t('diary.assignShort') }}</button>
|
||||
<button v-if="item.isTimeblock" @click="addGroupActivityToTimeblock(item.id)" :title="$t('diary.addGroupActivity')"
|
||||
class="plan-row-action-button plan-row-action-button-primary">{{ $t('diary.addGroupButton') }}</button>
|
||||
@@ -570,7 +583,7 @@
|
||||
? groupItem.groupPredefinedActivity.code
|
||||
: groupItem.groupPredefinedActivity.name }}
|
||||
</span>
|
||||
<span class="plan-status-badge" :class="`plan-status-badge-${getPlanItemStatus(groupItem).tone}`" :title="getPlanItemStatus(groupItem).reason || ''">
|
||||
<span v-if="!isStructuralPlanItem(groupItem)" class="plan-status-badge" :class="`plan-status-badge-${getPlanItemStatus(groupItem).tone}`" :title="getPlanItemStatus(groupItem).reason || ''">
|
||||
{{ getPlanItemStatus(groupItem).label }}
|
||||
</span>
|
||||
</div>
|
||||
@@ -580,7 +593,7 @@
|
||||
<td>
|
||||
<div class="plan-row-actions">
|
||||
<button @click="startGroupActivityEdit(groupItem)" class="plan-row-action-button">{{ $t('common.edit') }}</button>
|
||||
<button @click="toggleGroupActivityMembers(groupItem)" :title="$t('diary.assignParticipants')"
|
||||
<button v-if="!isStructuralPlanItem(groupItem)" @click="toggleGroupActivityMembers(groupItem)" :title="$t('diary.assignParticipants')"
|
||||
class="plan-row-action-button">{{ $t('diary.assignShort') }}</button>
|
||||
<button @click="removeGroupActivity(groupItem.id)" class="plan-row-action-button plan-row-action-button-danger" :title="$t('diary.delete')">{{ $t('common.delete') }}</button>
|
||||
</div>
|
||||
@@ -807,6 +820,20 @@ import {
|
||||
offGroupChanged
|
||||
} from '../services/socketService.js';
|
||||
|
||||
const STANDARD_DIARY_ACTIVITY_NAMES = [
|
||||
'Begrüßung',
|
||||
'Aktivierung',
|
||||
'Aufbauen',
|
||||
'Turnier',
|
||||
'Abbauen',
|
||||
'Abschlussgespräch',
|
||||
];
|
||||
|
||||
const normalizeStandardActivityFlag = (activity) => ({
|
||||
...(activity || {}),
|
||||
excludeFromStats: Boolean(activity?.excludeFromStats ?? activity?.exclude_from_stats),
|
||||
});
|
||||
|
||||
export default {
|
||||
name: 'DiaryView',
|
||||
components: {
|
||||
@@ -881,7 +908,9 @@ export default {
|
||||
predefinedActivityId: null,
|
||||
isTimeBlock: false,
|
||||
},
|
||||
standardDiaryActivityDefinitions: STANDARD_DIARY_ACTIVITY_NAMES.map((name) => ({ name })),
|
||||
predefinedActivities: [],
|
||||
standardPredefinedActivities: [],
|
||||
showDropdown: false,
|
||||
showImage: false,
|
||||
imageUrl: '',
|
||||
@@ -1041,17 +1070,41 @@ export default {
|
||||
openPlanItems() {
|
||||
const result = [];
|
||||
for (const item of this.trainingPlan || []) {
|
||||
if (!item?.isTimeblock && this.getPlanItemStatus(item).key === 'open') {
|
||||
if (!item?.isTimeblock && !this.isStructuralPlanItem(item) && this.getPlanItemStatus(item).key === 'open') {
|
||||
result.push(item);
|
||||
}
|
||||
for (const groupItem of item.groupActivities || []) {
|
||||
if (this.getPlanItemStatus(groupItem).key === 'open') {
|
||||
if (!this.isStructuralPlanItem(groupItem) && this.getPlanItemStatus(groupItem).key === 'open') {
|
||||
result.push(groupItem);
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
},
|
||||
standardDiaryActivities() {
|
||||
if (this.standardPredefinedActivities.length > 0) {
|
||||
return [...this.standardPredefinedActivities].sort((a, b) => {
|
||||
const aIndex = STANDARD_DIARY_ACTIVITY_NAMES.indexOf(a.name);
|
||||
const bIndex = STANDARD_DIARY_ACTIVITY_NAMES.indexOf(b.name);
|
||||
if (aIndex !== -1 && bIndex !== -1) return aIndex - bIndex;
|
||||
if (aIndex !== -1) return -1;
|
||||
if (bIndex !== -1) return 1;
|
||||
return a.name.localeCompare(b.name, 'de-DE');
|
||||
});
|
||||
}
|
||||
|
||||
return this.standardDiaryActivityDefinitions.map((definition) => {
|
||||
const existing = this.predefinedActivities.find((activity) => activity.name === definition.name);
|
||||
return existing || definition;
|
||||
}).sort((a, b) => {
|
||||
const aIndex = STANDARD_DIARY_ACTIVITY_NAMES.indexOf(a.name);
|
||||
const bIndex = STANDARD_DIARY_ACTIVITY_NAMES.indexOf(b.name);
|
||||
if (aIndex !== -1 && bIndex !== -1) return aIndex - bIndex;
|
||||
if (aIndex !== -1) return -1;
|
||||
if (bIndex !== -1) return 1;
|
||||
return a.name.localeCompare(b.name, 'de-DE');
|
||||
});
|
||||
},
|
||||
filteredDiaryMembers() {
|
||||
const search = (this.participantSearchQuery || '').trim().toLowerCase();
|
||||
|
||||
@@ -1120,15 +1173,14 @@ export default {
|
||||
}
|
||||
|
||||
const hasTimes = Boolean(this.trainingStart || this.trainingEnd);
|
||||
const hasParticipants = this.participants.length > 0;
|
||||
const hasPlan = this.trainingPlan.length > 0;
|
||||
const hasActivities = this.activities.length > 0;
|
||||
|
||||
if (hasTimes && hasParticipants && hasPlan && this.openPlanItems.length === 0) {
|
||||
if (hasTimes && hasPlan && this.openPlanItems.length === 0) {
|
||||
return this.$t('diary.statusReady');
|
||||
}
|
||||
|
||||
if (!hasParticipants && !hasPlan && !hasActivities && !hasTimes) {
|
||||
if (!hasPlan && !hasActivities && !hasTimes) {
|
||||
return this.$t('diary.statusEmpty');
|
||||
}
|
||||
|
||||
@@ -1138,9 +1190,8 @@ export default {
|
||||
methods: {
|
||||
isDiaryDayConfigured() {
|
||||
const hasTimes = Boolean(this.trainingStart || this.trainingEnd);
|
||||
const hasParticipants = Array.isArray(this.participants) && this.participants.length > 0;
|
||||
const hasPlan = Array.isArray(this.trainingPlan) && this.trainingPlan.length > 0;
|
||||
return hasTimes && hasParticipants && hasPlan;
|
||||
return hasTimes && hasPlan;
|
||||
},
|
||||
toggleOverviewPanel(panel) {
|
||||
this.activeOverviewPanel = this.activeOverviewPanel === panel ? null : panel;
|
||||
@@ -1619,12 +1670,23 @@ export default {
|
||||
async loadPredefinedActivities() {
|
||||
try {
|
||||
const response = await apiClient.get('/predefined-activities');
|
||||
this.predefinedActivities = response.data;
|
||||
this.predefinedActivities = (response.data || []).map(normalizeStandardActivityFlag);
|
||||
} catch (error) {
|
||||
this.showInfo(this.$t('messages.error'), this.$t('diary.errorLoadingPredefinedActivities'), '', 'error');
|
||||
}
|
||||
},
|
||||
|
||||
async loadStandardPredefinedActivities() {
|
||||
try {
|
||||
const response = await apiClient.get('/predefined-activities', {
|
||||
params: { scope: 'standard' }
|
||||
});
|
||||
this.standardPredefinedActivities = (response.data || []).map(normalizeStandardActivityFlag);
|
||||
} catch (error) {
|
||||
this.standardPredefinedActivities = [];
|
||||
}
|
||||
},
|
||||
|
||||
async loadGroups() {
|
||||
try {
|
||||
const response = await apiClient.get(`/group/${this.currentClub}/${this.date.id}`);
|
||||
@@ -1908,9 +1970,60 @@ export default {
|
||||
this.newPlanItem.activity = activity.name;
|
||||
this.newPlanItem.durationText = activity.durationText;
|
||||
this.newPlanItem.duration = activity.duration || '';
|
||||
this.newPlanItem.predefinedActivityId = activity.id || null;
|
||||
this.showDropdown = false;
|
||||
},
|
||||
|
||||
async ensureStandardDiaryActivity(definition) {
|
||||
const existing = this.predefinedActivities.find((activity) => activity.name === definition.name);
|
||||
|
||||
if (existing) {
|
||||
if (existing.excludeFromStats) {
|
||||
return existing;
|
||||
}
|
||||
|
||||
await apiClient.put(`/predefined-activities/${existing.id}`, {
|
||||
name: existing.name,
|
||||
code: existing.code,
|
||||
description: existing.description,
|
||||
durationText: existing.durationText,
|
||||
duration: existing.duration,
|
||||
imageLink: existing.imageLink,
|
||||
drawingData: existing.drawingData,
|
||||
excludeFromStats: true,
|
||||
});
|
||||
await this.loadPredefinedActivities();
|
||||
await this.loadStandardPredefinedActivities();
|
||||
return this.predefinedActivities.find((activity) => activity.name === definition.name) || existing;
|
||||
}
|
||||
|
||||
const created = await apiClient.post('/predefined-activities', {
|
||||
name: definition.name,
|
||||
code: definition.code || null,
|
||||
description: definition.description || '',
|
||||
durationText: definition.durationText || '',
|
||||
duration: definition.duration || null,
|
||||
excludeFromStats: true,
|
||||
}).then((response) => response.data);
|
||||
await this.loadPredefinedActivities();
|
||||
await this.loadStandardPredefinedActivities();
|
||||
return created;
|
||||
},
|
||||
|
||||
async addStandardPlanActivity(activity) {
|
||||
try {
|
||||
const standardActivity = await this.ensureStandardDiaryActivity(activity);
|
||||
this.newPlanItem.activity = standardActivity.name;
|
||||
this.newPlanItem.durationText = standardActivity.durationText || (standardActivity.duration ? String(standardActivity.duration) : '');
|
||||
this.newPlanItem.duration = standardActivity.duration || '';
|
||||
this.newPlanItem.predefinedActivityId = standardActivity.id || null;
|
||||
await this.addPlanItem();
|
||||
} catch (error) {
|
||||
const msg = getSafeErrorMessage(error, this.$t('diary.standardActivityAddError'));
|
||||
this.showInfo(this.$t('messages.error'), msg, '', 'error');
|
||||
}
|
||||
},
|
||||
|
||||
async addPlanItem() {
|
||||
try {
|
||||
if (this.addNewItem || this.addNewTimeblock) {
|
||||
@@ -1924,6 +2037,7 @@ export default {
|
||||
await apiClient.post(`/diary-date-activities/${this.currentClub}`, {
|
||||
diaryDateId: this.date.id,
|
||||
activity: this.addNewTimeblock ? '' : this.newPlanItem.activity,
|
||||
predefinedActivityId: this.newPlanItem.predefinedActivityId,
|
||||
isTimeblock: this.addNewTimeblock,
|
||||
duration: this.newPlanItem.duration,
|
||||
durationText: this.newPlanItem.durationText,
|
||||
@@ -3013,11 +3127,19 @@ export default {
|
||||
const map = this.participantMapByMemberId || {};
|
||||
return map[memberId];
|
||||
},
|
||||
isStructuralPlanItem(item) {
|
||||
const activity = item?.groupPredefinedActivity || item?.predefinedActivity || null;
|
||||
return Boolean(activity?.excludeFromStats);
|
||||
},
|
||||
getPlanItemStatus(item) {
|
||||
if (!item) {
|
||||
return { key: 'open', label: this.$t('diary.statusOpenShort'), tone: 'open' };
|
||||
}
|
||||
|
||||
if (this.isStructuralPlanItem(item)) {
|
||||
return { key: 'ready', label: '', tone: 'ready' };
|
||||
}
|
||||
|
||||
if (item.isTimeblock) {
|
||||
const groupActivities = item.groupActivities || [];
|
||||
if (groupActivities.length === 0) {
|
||||
@@ -3584,6 +3706,7 @@ export default {
|
||||
},
|
||||
async mounted() {
|
||||
await this.init();
|
||||
await this.loadStandardPredefinedActivities();
|
||||
|
||||
// Socket.IO verbinden
|
||||
if (this.currentClub) {
|
||||
@@ -4271,9 +4394,10 @@ img {
|
||||
}
|
||||
|
||||
.modal {
|
||||
background: white;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.3);
|
||||
background: var(--surface-color);
|
||||
border: 1px solid var(--border-color);
|
||||
border-radius: 14px;
|
||||
box-shadow: 0 18px 48px rgba(15, 23, 42, 0.18);
|
||||
max-width: 500px;
|
||||
width: 90%;
|
||||
max-height: 90vh;
|
||||
@@ -4284,12 +4408,13 @@ img {
|
||||
|
||||
.modal-header {
|
||||
padding: 1rem 1.5rem;
|
||||
border-bottom: 1px solid #dee2e6;
|
||||
border-bottom: 1px solid var(--border-color);
|
||||
background: linear-gradient(180deg, rgba(47, 122, 95, 0.12), rgba(47, 122, 95, 0.04));
|
||||
}
|
||||
|
||||
.modal-header h3 {
|
||||
margin: 0;
|
||||
color: #495057;
|
||||
color: var(--text-color);
|
||||
}
|
||||
|
||||
.modal-body {
|
||||
@@ -4318,7 +4443,7 @@ img {
|
||||
gap: 0.5rem;
|
||||
margin-top: 1rem;
|
||||
padding-top: 1rem;
|
||||
border-top: 1px solid #dee2e6;
|
||||
border-top: 1px solid var(--border-color);
|
||||
flex-wrap: nowrap;
|
||||
}
|
||||
|
||||
@@ -4330,54 +4455,57 @@ img {
|
||||
display: block;
|
||||
margin-bottom: 0.5rem;
|
||||
font-weight: 500;
|
||||
color: #495057;
|
||||
color: var(--text-color);
|
||||
}
|
||||
|
||||
.form-group input,
|
||||
.form-group select {
|
||||
width: 100%;
|
||||
padding: 0.5rem;
|
||||
border: 1px solid #ced4da;
|
||||
border-radius: 4px;
|
||||
padding: 0.75rem 0.875rem;
|
||||
border: 1px solid var(--border-color);
|
||||
border-radius: 10px;
|
||||
font-size: 1rem;
|
||||
background: var(--surface-muted);
|
||||
color: var(--text-color);
|
||||
}
|
||||
|
||||
.form-group input:focus,
|
||||
.form-group select:focus {
|
||||
outline: none;
|
||||
border-color: #80bdff;
|
||||
box-shadow: 0 0 0 0.2rem rgba(0, 123, 255, 0.25);
|
||||
border-color: var(--primary-color);
|
||||
box-shadow: 0 0 0 3px rgba(47, 122, 95, 0.14);
|
||||
}
|
||||
|
||||
.modal .btn-secondary {
|
||||
background-color: #6c757d !important;
|
||||
color: white !important;
|
||||
border: none !important;
|
||||
background: var(--surface-color) !important;
|
||||
color: var(--text-color) !important;
|
||||
border: 1px solid var(--border-color) !important;
|
||||
padding: 0.5rem 1rem !important;
|
||||
border-radius: 4px !important;
|
||||
border-radius: 10px !important;
|
||||
cursor: pointer !important;
|
||||
font-size: 0.9rem !important;
|
||||
}
|
||||
|
||||
.modal .btn-secondary:hover {
|
||||
background-color: #5a6268 !important;
|
||||
background: var(--surface-muted) !important;
|
||||
border-color: var(--primary-soft) !important;
|
||||
}
|
||||
|
||||
.modal .btn-primary {
|
||||
background-color: #007bff !important;
|
||||
color: white !important;
|
||||
border: none !important;
|
||||
background: linear-gradient(135deg, var(--primary-color), var(--primary-hover)) !important;
|
||||
color: var(--text-on-primary) !important;
|
||||
border: 1px solid transparent !important;
|
||||
padding: 0.5rem 1rem !important;
|
||||
border-radius: 4px !important;
|
||||
border-radius: 10px !important;
|
||||
cursor: pointer !important;
|
||||
font-size: 0.9rem !important;
|
||||
}
|
||||
|
||||
.btn-palette {
|
||||
background: linear-gradient(135deg, #4CAF50, #45a049);
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
background: linear-gradient(135deg, var(--primary-color), var(--primary-hover));
|
||||
color: var(--text-on-primary);
|
||||
border: 1px solid transparent;
|
||||
border-radius: 8px;
|
||||
padding: 0.25rem;
|
||||
font-size: 1rem;
|
||||
cursor: pointer;
|
||||
@@ -4392,12 +4520,12 @@ img {
|
||||
}
|
||||
|
||||
.btn-palette:hover {
|
||||
background: linear-gradient(135deg, #45a049, #3d8b40);
|
||||
opacity: 0.95;
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
.modal .btn-primary:hover {
|
||||
background-color: #0056b3 !important;
|
||||
opacity: 0.95 !important;
|
||||
}
|
||||
|
||||
.modal .btn-primary:disabled {
|
||||
@@ -4725,6 +4853,37 @@ img {
|
||||
margin-bottom: 0.85rem;
|
||||
}
|
||||
|
||||
.plan-quick-actions {
|
||||
margin-bottom: 0.9rem;
|
||||
padding: 0.85rem;
|
||||
border: 1px solid var(--border-color, #d9e4ec);
|
||||
border-radius: 10px;
|
||||
background: var(--surface-subtle, #f3f7fa);
|
||||
}
|
||||
|
||||
.plan-quick-actions-label {
|
||||
display: block;
|
||||
margin-bottom: 0.65rem;
|
||||
font-size: 0.82rem;
|
||||
font-weight: 700;
|
||||
color: var(--text-muted, #4d6979);
|
||||
}
|
||||
|
||||
.plan-quick-actions-list {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
|
||||
gap: 0.65rem;
|
||||
}
|
||||
|
||||
.plan-quick-action {
|
||||
justify-content: flex-start;
|
||||
}
|
||||
|
||||
.plan-quick-action-meta {
|
||||
color: var(--text-muted, #4d6979);
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.plan-composer-grid {
|
||||
display: grid;
|
||||
grid-template-columns: 1.8fr 1fr 1.2fr;
|
||||
@@ -5276,12 +5435,12 @@ img {
|
||||
}
|
||||
|
||||
.dialog-actions .btn-primary {
|
||||
background: #28a745;
|
||||
color: #fff;
|
||||
background: linear-gradient(135deg, var(--primary-color), var(--primary-hover));
|
||||
color: var(--text-on-primary);
|
||||
}
|
||||
|
||||
.dialog-actions .btn-primary:hover:not(:disabled) {
|
||||
background: #218838;
|
||||
opacity: 0.95;
|
||||
}
|
||||
|
||||
.dialog-actions .btn-primary:disabled {
|
||||
|
||||
@@ -651,78 +651,94 @@ export default {
|
||||
}
|
||||
|
||||
.log-type-badge {
|
||||
display: inline-block;
|
||||
padding: 0.25rem 0.5rem;
|
||||
border-radius: 4px;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
padding: 0.25rem 0.55rem;
|
||||
border-radius: 999px;
|
||||
font-size: 0.8em;
|
||||
font-weight: 500;
|
||||
font-weight: 600;
|
||||
border: 1px solid transparent;
|
||||
}
|
||||
|
||||
.log-type-api_request {
|
||||
background: #e0f2fe;
|
||||
color: #0369a1;
|
||||
background: rgba(47, 122, 95, 0.1);
|
||||
color: var(--primary-strong);
|
||||
border-color: rgba(47, 122, 95, 0.18);
|
||||
}
|
||||
|
||||
.log-type-scheduler {
|
||||
background: #fef3c7;
|
||||
color: #92400e;
|
||||
background: rgba(181, 110, 65, 0.14);
|
||||
color: #8a4f28;
|
||||
border-color: rgba(181, 110, 65, 0.24);
|
||||
}
|
||||
|
||||
.log-type-cron_job {
|
||||
background: #fce7f3;
|
||||
color: #9f1239;
|
||||
background: rgba(87, 92, 144, 0.12);
|
||||
color: #454b79;
|
||||
border-color: rgba(87, 92, 144, 0.22);
|
||||
}
|
||||
|
||||
.method-badge {
|
||||
display: inline-block;
|
||||
padding: 0.25rem 0.5rem;
|
||||
border-radius: 4px;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
padding: 0.25rem 0.55rem;
|
||||
border-radius: 999px;
|
||||
font-size: 0.8em;
|
||||
font-weight: 600;
|
||||
font-family: monospace;
|
||||
border: 1px solid transparent;
|
||||
}
|
||||
|
||||
.method-GET {
|
||||
background: #dbeafe;
|
||||
color: #1e40af;
|
||||
background: rgba(67, 97, 168, 0.12);
|
||||
color: #28457e;
|
||||
border-color: rgba(67, 97, 168, 0.24);
|
||||
}
|
||||
|
||||
.method-POST {
|
||||
background: #dcfce7;
|
||||
color: #166534;
|
||||
background: rgba(47, 122, 95, 0.12);
|
||||
color: #1f5f49;
|
||||
border-color: rgba(47, 122, 95, 0.24);
|
||||
}
|
||||
|
||||
.method-PUT {
|
||||
background: #fef3c7;
|
||||
color: #92400e;
|
||||
background: rgba(181, 110, 65, 0.14);
|
||||
color: #8a4f28;
|
||||
border-color: rgba(181, 110, 65, 0.24);
|
||||
}
|
||||
|
||||
.method-DELETE {
|
||||
background: #fee2e2;
|
||||
color: #991b1b;
|
||||
background: rgba(200, 74, 56, 0.12);
|
||||
color: #8b3327;
|
||||
border-color: rgba(200, 74, 56, 0.24);
|
||||
}
|
||||
|
||||
.status-badge {
|
||||
display: inline-block;
|
||||
padding: 0.25rem 0.5rem;
|
||||
border-radius: 4px;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
padding: 0.25rem 0.55rem;
|
||||
border-radius: 999px;
|
||||
font-size: 0.8em;
|
||||
font-weight: 600;
|
||||
border: 1px solid transparent;
|
||||
}
|
||||
|
||||
.status-success {
|
||||
background: #dcfce7;
|
||||
color: #166534;
|
||||
background: rgba(47, 122, 95, 0.12);
|
||||
color: #1f5f49;
|
||||
border-color: rgba(47, 122, 95, 0.24);
|
||||
}
|
||||
|
||||
.status-client-error {
|
||||
background: #fef3c7;
|
||||
color: #92400e;
|
||||
background: rgba(181, 110, 65, 0.14);
|
||||
color: #8a4f28;
|
||||
border-color: rgba(181, 110, 65, 0.24);
|
||||
}
|
||||
|
||||
.status-server-error {
|
||||
background: #fee2e2;
|
||||
color: #991b1b;
|
||||
background: rgba(200, 74, 56, 0.12);
|
||||
color: #8b3327;
|
||||
border-color: rgba(200, 74, 56, 0.24);
|
||||
}
|
||||
|
||||
.path-cell {
|
||||
@@ -782,4 +798,3 @@ export default {
|
||||
font-weight: 500;
|
||||
}
|
||||
</style>
|
||||
|
||||
|
||||
@@ -1321,18 +1321,19 @@ address={{address}}`;
|
||||
.btn-import {
|
||||
align-self: flex-start;
|
||||
padding: 0.6rem 1.2rem;
|
||||
background-color: #28a745;
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
background: linear-gradient(135deg, var(--primary-color), var(--primary-hover));
|
||||
color: var(--text-on-primary);
|
||||
border: 1px solid transparent;
|
||||
border-radius: 10px;
|
||||
cursor: pointer;
|
||||
font-weight: 500;
|
||||
transition: background-color 0.2s;
|
||||
font-weight: 600;
|
||||
transition: transform 0.2s ease, opacity 0.2s ease;
|
||||
font-size: 0.95em;
|
||||
}
|
||||
|
||||
.btn-import:hover:not(:disabled) {
|
||||
background-color: #218838;
|
||||
opacity: 0.95;
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
.btn-import:disabled {
|
||||
@@ -1350,39 +1351,38 @@ address={{address}}`;
|
||||
}
|
||||
|
||||
.btn-primary {
|
||||
background-color: #007bff;
|
||||
color: white;
|
||||
border: none;
|
||||
background: linear-gradient(135deg, var(--primary-color), var(--primary-hover));
|
||||
color: var(--text-on-primary);
|
||||
border: 1px solid transparent;
|
||||
padding: 0.75rem 1.5rem;
|
||||
border-radius: 4px;
|
||||
border-radius: 10px;
|
||||
cursor: pointer;
|
||||
font-weight: 500;
|
||||
transition: background-color 0.2s;
|
||||
font-weight: 600;
|
||||
transition: background-color 0.2s ease, transform 0.2s ease;
|
||||
}
|
||||
|
||||
.btn-primary:hover:not(:disabled) {
|
||||
background-color: #0056b3;
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
.btn-primary:disabled {
|
||||
background-color: #6c757d;
|
||||
cursor: not-allowed;
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
.btn-danger {
|
||||
background-color: #dc3545;
|
||||
color: white;
|
||||
border: none;
|
||||
background: rgba(200, 74, 56, 0.12);
|
||||
color: #8b3327;
|
||||
border: 1px solid rgba(200, 74, 56, 0.24);
|
||||
padding: 0.75rem 1.5rem;
|
||||
border-radius: 4px;
|
||||
border-radius: 10px;
|
||||
cursor: pointer;
|
||||
font-weight: 500;
|
||||
transition: background-color 0.2s;
|
||||
font-weight: 600;
|
||||
transition: background-color 0.2s ease;
|
||||
}
|
||||
|
||||
.btn-danger:hover:not(:disabled) {
|
||||
background-color: #c82333;
|
||||
background: rgba(200, 74, 56, 0.18);
|
||||
}
|
||||
|
||||
.btn-danger:disabled {
|
||||
@@ -1391,4 +1391,3 @@ address={{address}}`;
|
||||
opacity: 0.6;
|
||||
}
|
||||
</style>
|
||||
|
||||
|
||||
@@ -2528,18 +2528,20 @@ table td {
|
||||
}
|
||||
|
||||
.btn-update-ratings {
|
||||
background-color: #28a745;
|
||||
color: white;
|
||||
border: none;
|
||||
background: linear-gradient(135deg, var(--primary-color), var(--primary-hover));
|
||||
color: var(--text-on-primary);
|
||||
border: 1px solid transparent;
|
||||
padding: 0.5rem 1rem;
|
||||
border-radius: 4px;
|
||||
border-radius: 10px;
|
||||
cursor: pointer;
|
||||
font-size: 0.9em;
|
||||
transition: background-color 0.2s ease;
|
||||
font-weight: 600;
|
||||
transition: transform 0.2s ease, opacity 0.2s ease;
|
||||
}
|
||||
|
||||
.btn-update-ratings:hover:not(:disabled) {
|
||||
background-color: #218838;
|
||||
transform: translateY(-1px);
|
||||
opacity: 0.95;
|
||||
}
|
||||
|
||||
.btn-update-ratings:disabled {
|
||||
@@ -2579,22 +2581,21 @@ table td {
|
||||
}
|
||||
|
||||
.rotate-btn {
|
||||
background-color: #007bff;
|
||||
color: white;
|
||||
border: none;
|
||||
background: linear-gradient(135deg, var(--primary-color), var(--primary-hover));
|
||||
color: var(--text-on-primary);
|
||||
border: 1px solid transparent;
|
||||
padding: 0.75rem 1rem;
|
||||
border-radius: 6px;
|
||||
border-radius: 10px;
|
||||
cursor: pointer;
|
||||
font-size: 0.9em;
|
||||
font-weight: 500;
|
||||
font-weight: 600;
|
||||
transition: all 0.2s ease;
|
||||
min-width: 120px;
|
||||
}
|
||||
|
||||
.rotate-btn:hover {
|
||||
background-color: #0056b3;
|
||||
transform: translateY(-1px);
|
||||
box-shadow: 0 2px 8px rgba(0, 123, 255, 0.3);
|
||||
box-shadow: 0 8px 18px rgba(47, 122, 95, 0.18);
|
||||
}
|
||||
|
||||
.rotate-btn:active {
|
||||
@@ -2608,17 +2609,18 @@ table td {
|
||||
|
||||
.btn-primary {
|
||||
padding: 0.5rem 1rem;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
border: 1px solid transparent;
|
||||
border-radius: 10px;
|
||||
background: linear-gradient(135deg, var(--primary-color), var(--primary-hover));
|
||||
color: white;
|
||||
color: var(--text-on-primary);
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
transition: opacity 0.2s;
|
||||
transition: opacity 0.2s, transform 0.2s ease;
|
||||
}
|
||||
|
||||
.btn-primary:hover {
|
||||
opacity: 0.9;
|
||||
opacity: 0.95;
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
/* Dropdown Styles */
|
||||
@@ -2628,28 +2630,30 @@ table td {
|
||||
}
|
||||
|
||||
.btn-dropdown {
|
||||
background-color: #007bff;
|
||||
color: white;
|
||||
border: none;
|
||||
background: linear-gradient(135deg, var(--primary-color), var(--primary-hover));
|
||||
color: var(--text-on-primary);
|
||||
border: 1px solid transparent;
|
||||
padding: 0.5rem 1rem;
|
||||
border-radius: 4px;
|
||||
border-radius: 10px;
|
||||
cursor: pointer;
|
||||
font-size: 0.9em;
|
||||
transition: background-color 0.2s ease;
|
||||
font-weight: 600;
|
||||
transition: transform 0.2s ease, opacity 0.2s ease;
|
||||
}
|
||||
|
||||
.btn-dropdown:hover {
|
||||
background-color: #0056b3;
|
||||
opacity: 0.95;
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
.dropdown-content {
|
||||
position: absolute;
|
||||
top: 100%;
|
||||
left: 0;
|
||||
background: white;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 4px;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
|
||||
background: var(--surface-color);
|
||||
border: 1px solid var(--border-color);
|
||||
border-radius: 10px;
|
||||
box-shadow: 0 10px 24px rgba(15, 23, 42, 0.14);
|
||||
z-index: 1000;
|
||||
min-width: 200px;
|
||||
margin-top: 4px;
|
||||
@@ -2688,18 +2692,20 @@ table td {
|
||||
/* Button Styles */
|
||||
.btn-activities {
|
||||
margin-left: 0.5rem;
|
||||
background-color: #28a745;
|
||||
color: white;
|
||||
border: none;
|
||||
background: linear-gradient(135deg, var(--primary-color), var(--primary-hover));
|
||||
color: var(--text-on-primary);
|
||||
border: 1px solid transparent;
|
||||
padding: 0.5rem 1rem;
|
||||
border-radius: 4px;
|
||||
border-radius: 10px;
|
||||
cursor: pointer;
|
||||
font-size: 0.9em;
|
||||
transition: background-color 0.2s ease;
|
||||
font-weight: 600;
|
||||
transition: transform 0.2s ease, opacity 0.2s ease;
|
||||
}
|
||||
|
||||
.btn-activities:hover {
|
||||
background-color: #218838;
|
||||
transform: translateY(-1px);
|
||||
opacity: 0.95;
|
||||
}
|
||||
|
||||
/* Filter Styles */
|
||||
@@ -3241,30 +3247,31 @@ table td {
|
||||
.btn-add-contact {
|
||||
margin-top: 0.5rem;
|
||||
padding: 0.4rem 0.8rem;
|
||||
background-color: #28a745;
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
background: linear-gradient(135deg, var(--primary-color), var(--primary-hover));
|
||||
color: var(--text-on-primary);
|
||||
border: 1px solid transparent;
|
||||
border-radius: 10px;
|
||||
cursor: pointer;
|
||||
font-size: 0.9em;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.btn-add-contact:hover {
|
||||
background-color: #218838;
|
||||
opacity: 0.95;
|
||||
}
|
||||
|
||||
.btn-remove-contact {
|
||||
padding: 0.2rem 0.5rem;
|
||||
background-color: #dc3545;
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
background: rgba(200, 74, 56, 0.12);
|
||||
color: #8b3327;
|
||||
border: 1px solid rgba(200, 74, 56, 0.24);
|
||||
border-radius: 8px;
|
||||
cursor: pointer;
|
||||
font-size: 0.9em;
|
||||
}
|
||||
|
||||
.btn-remove-contact:hover {
|
||||
background-color: #c82333;
|
||||
background: rgba(200, 74, 56, 0.18);
|
||||
}
|
||||
|
||||
.member-groups-list {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div class="mytt-account-page">
|
||||
<div class="mytt-account-page" :class="{ 'embedded-dialog-view': embedded }">
|
||||
<div class="page-container">
|
||||
<h1>{{ $t('myTischtennisAccount.title') }}</h1>
|
||||
<h1 v-if="!embedded">{{ $t('myTischtennisAccount.title') }}</h1>
|
||||
|
||||
<div class="account-container">
|
||||
<div v-if="loading" class="loading">{{ $t('myTischtennisAccount.loading') }}</div>
|
||||
@@ -107,6 +107,12 @@ import InfoDialog from '../components/InfoDialog.vue';
|
||||
import ConfirmDialog from '../components/ConfirmDialog.vue';
|
||||
export default {
|
||||
name: 'MyTischtennisAccount',
|
||||
props: {
|
||||
embedded: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
components: {
|
||||
MyTischtennisDialog,
|
||||
InfoDialog,
|
||||
@@ -428,29 +434,32 @@ h1 {
|
||||
|
||||
.btn-primary, .btn-secondary, .btn-danger {
|
||||
padding: 0.75rem 1.5rem;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
border: 1px solid transparent;
|
||||
border-radius: 10px;
|
||||
font-size: 1rem;
|
||||
cursor: pointer;
|
||||
transition: background-color 0.2s ease;
|
||||
font-weight: 600;
|
||||
transition: background-color 0.2s ease, border-color 0.2s ease, transform 0.2s ease;
|
||||
}
|
||||
|
||||
.btn-primary {
|
||||
background-color: #007bff;
|
||||
color: white;
|
||||
background: linear-gradient(135deg, var(--primary-color), var(--primary-hover));
|
||||
color: var(--text-on-primary);
|
||||
}
|
||||
|
||||
.btn-primary:hover {
|
||||
background-color: #0056b3;
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
.btn-secondary {
|
||||
background-color: #6c757d;
|
||||
color: white;
|
||||
background: var(--surface-color);
|
||||
border-color: var(--border-color);
|
||||
color: var(--text-color);
|
||||
}
|
||||
|
||||
.btn-secondary:hover {
|
||||
background-color: #545b62;
|
||||
background: var(--surface-muted);
|
||||
border-color: var(--primary-soft);
|
||||
}
|
||||
|
||||
.btn-secondary:disabled {
|
||||
@@ -555,21 +564,22 @@ h1 {
|
||||
}
|
||||
|
||||
.btn-danger {
|
||||
background-color: #dc3545;
|
||||
color: white;
|
||||
background: rgba(200, 74, 56, 0.12);
|
||||
color: #8b3327;
|
||||
border: 1px solid rgba(200, 74, 56, 0.24);
|
||||
}
|
||||
|
||||
.btn-danger:hover {
|
||||
background-color: #c82333;
|
||||
background: rgba(200, 74, 56, 0.18);
|
||||
}
|
||||
|
||||
.btn-info {
|
||||
background-color: #17a2b8;
|
||||
color: white;
|
||||
background: rgba(47, 122, 95, 0.12);
|
||||
color: var(--primary-strong);
|
||||
border: 1px solid rgba(47, 122, 95, 0.24);
|
||||
}
|
||||
|
||||
.btn-info:hover {
|
||||
background-color: #138496;
|
||||
background: rgba(47, 122, 95, 0.18);
|
||||
}
|
||||
</style>
|
||||
|
||||
|
||||
@@ -2063,21 +2063,21 @@ th, td { border-bottom: 1px solid var(--border-color); padding: 0.5rem; text-ali
|
||||
}
|
||||
|
||||
.btn-register {
|
||||
background-color: #007bff;
|
||||
color: white;
|
||||
background: linear-gradient(135deg, var(--primary-color), var(--primary-hover));
|
||||
color: var(--text-on-primary);
|
||||
}
|
||||
|
||||
.btn-register:hover {
|
||||
background-color: #0056b3;
|
||||
opacity: 0.95;
|
||||
}
|
||||
|
||||
.btn-participate {
|
||||
background-color: #28a745;
|
||||
color: white;
|
||||
background: linear-gradient(135deg, var(--primary-color), var(--primary-hover));
|
||||
color: var(--text-on-primary);
|
||||
}
|
||||
|
||||
.btn-participate:hover {
|
||||
background-color: #1e7e34;
|
||||
opacity: 0.95;
|
||||
}
|
||||
|
||||
.btn-reset {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<div class="page-container">
|
||||
<h1>{{ $t('settings.personalSettings') }}</h1>
|
||||
<div class="page-container" :class="{ 'embedded-dialog-view': embedded }">
|
||||
<h1 v-if="!embedded">{{ $t('settings.personalSettings') }}</h1>
|
||||
|
||||
<div class="settings-container">
|
||||
<div class="settings-section card">
|
||||
@@ -34,6 +34,12 @@ import { mapGetters, mapActions } from 'vuex';
|
||||
|
||||
export default {
|
||||
name: 'PersonalSettings',
|
||||
props: {
|
||||
embedded: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
selectedLanguage: this.$i18n.locale,
|
||||
@@ -77,6 +83,10 @@ export default {
|
||||
margin: 0 auto;
|
||||
padding: 2rem;
|
||||
}
|
||||
.page-container.embedded-dialog-view {
|
||||
max-width: none;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
h1 {
|
||||
color: var(--text-color, #333);
|
||||
@@ -157,4 +167,3 @@ h1 {
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
|
||||
@@ -17,6 +17,32 @@
|
||||
/>
|
||||
<button v-if="searchQuery" @click="clearSearch" class="btn-clear-search">✕</button>
|
||||
</div>
|
||||
<div class="scope-filters">
|
||||
<button
|
||||
type="button"
|
||||
class="scope-filter"
|
||||
:class="{ active: selectedScope === 'all' }"
|
||||
@click="selectedScope = 'all'"
|
||||
>
|
||||
{{ $t('predefinedActivities.filterAll') }}
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
class="scope-filter"
|
||||
:class="{ active: selectedScope === 'standard' }"
|
||||
@click="selectedScope = 'standard'"
|
||||
>
|
||||
{{ $t('predefinedActivities.filterStandard') }}
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
class="scope-filter"
|
||||
:class="{ active: selectedScope === 'custom' }"
|
||||
@click="selectedScope = 'custom'"
|
||||
>
|
||||
{{ $t('predefinedActivities.filterCustom') }}
|
||||
</button>
|
||||
</div>
|
||||
<div>
|
||||
<button @click="deduplicate" class="btn-secondary">{{ $t('predefinedActivities.deduplicate') }}</button>
|
||||
</div>
|
||||
@@ -40,6 +66,7 @@
|
||||
<div class="meta">
|
||||
<span v-if="a.duration">{{ a.duration }} {{ $t('predefinedActivities.min') }}</span>
|
||||
<span v-if="a.durationText"> ({{ a.durationText }})</span>
|
||||
<span v-if="a.excludeFromStats" class="meta-chip">{{ $t('predefinedActivities.excludeFromStats') }}</span>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
@@ -65,6 +92,10 @@
|
||||
<label>{{ $t('predefinedActivities.durationText') }}
|
||||
<input type="text" v-model="editModel.durationText" :placeholder="$t('predefinedActivities.durationTextPlaceholder')" />
|
||||
</label>
|
||||
<label class="checkbox-field">
|
||||
<input type="checkbox" v-model="editModel.excludeFromStats" />
|
||||
<span>{{ $t('predefinedActivities.excludeFromStats') }}</span>
|
||||
</label>
|
||||
<label>{{ $t('predefinedActivities.description') }}
|
||||
<textarea v-model="editModel.description" rows="4" />
|
||||
</label>
|
||||
@@ -146,6 +177,21 @@ import ConfirmDialog from '../components/ConfirmDialog.vue';
|
||||
import { mapGetters } from 'vuex';
|
||||
import { debounce } from '../utils/debounce.js';
|
||||
import { buildInfoConfig, buildConfirmConfig, safeErrorMessage } from '../utils/dialogUtils.js';
|
||||
|
||||
const STANDARD_ACTIVITY_NAMES = new Set([
|
||||
'Begrüßung',
|
||||
'Aktivierung',
|
||||
'Aufbauen',
|
||||
'Turnier',
|
||||
'Abbauen',
|
||||
'Abschlussgespräch',
|
||||
]);
|
||||
|
||||
const normalizeStandardActivityFlag = (activity) => ({
|
||||
...(activity || {}),
|
||||
excludeFromStats: Boolean(activity?.excludeFromStats ?? activity?.exclude_from_stats) || STANDARD_ACTIVITY_NAMES.has(activity?.name),
|
||||
});
|
||||
|
||||
export default {
|
||||
name: 'PredefinedActivities',
|
||||
components: {
|
||||
@@ -182,14 +228,25 @@ export default {
|
||||
searchResults: [],
|
||||
isSearching: false,
|
||||
showDrawingDialog: false,
|
||||
selectedScope: 'all',
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
isStandardActivity() {
|
||||
return (activity) => Boolean(activity?.excludeFromStats) || STANDARD_ACTIVITY_NAMES.has(activity?.name);
|
||||
},
|
||||
filteredActivities() {
|
||||
const activitiesToFilter = this.searchQuery.trim() ? this.searchResults : this.activities;
|
||||
if (this.selectedScope === 'standard') {
|
||||
return (activitiesToFilter || []).filter((activity) => this.isStandardActivity(activity));
|
||||
}
|
||||
if (this.selectedScope === 'custom') {
|
||||
return (activitiesToFilter || []).filter((activity) => !this.isStandardActivity(activity));
|
||||
}
|
||||
return activitiesToFilter || [];
|
||||
},
|
||||
sortedActivities() {
|
||||
// Wenn gesucht wird, zeige Suchergebnisse, sonst alle Aktivitäten
|
||||
const activitiesToSort = this.searchQuery.trim() ? this.searchResults : this.activities;
|
||||
|
||||
return [...(activitiesToSort || [])].sort((a, b) => {
|
||||
return [...this.filteredActivities].sort((a, b) => {
|
||||
const ac = (a.code || '').toLocaleLowerCase('de-DE');
|
||||
const bc = (b.code || '').toLocaleLowerCase('de-DE');
|
||||
const aEmpty = ac === '';
|
||||
@@ -247,7 +304,7 @@ export default {
|
||||
const response = await apiClient.get('/predefined-activities/search/query', {
|
||||
params: { q: query, limit: 50 }
|
||||
});
|
||||
this.searchResults = response.data || [];
|
||||
this.searchResults = (response.data || []).map((activity) => normalizeStandardActivityFlag(activity));
|
||||
} catch (error) {
|
||||
console.error('Error searching activities:', error);
|
||||
this.searchResults = [];
|
||||
@@ -268,11 +325,11 @@ export default {
|
||||
},
|
||||
normalizeActivity(activity, images) {
|
||||
const drawingData = this.parseDrawingData(activity && activity.drawingData);
|
||||
return { ...(activity || {}), drawingData };
|
||||
return { ...normalizeStandardActivityFlag(activity), drawingData };
|
||||
},
|
||||
async reload() {
|
||||
const r = await apiClient.get('/predefined-activities');
|
||||
this.activities = r.data || [];
|
||||
this.activities = (r.data || []).map((activity) => normalizeStandardActivityFlag(activity));
|
||||
},
|
||||
async select(a) {
|
||||
this.selectedActivity = a;
|
||||
@@ -324,6 +381,7 @@ export default {
|
||||
description: '',
|
||||
duration: null,
|
||||
durationText: '',
|
||||
excludeFromStats: false,
|
||||
imageLink: '',
|
||||
drawingData: '',
|
||||
};
|
||||
@@ -545,6 +603,17 @@ select { max-width: 220px; }
|
||||
.items li:hover { background: var(--primary-light);
|
||||
}
|
||||
.items li.active { background: var(--primary-light); color: var(--primary-color); }
|
||||
.meta-chip {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
margin-left: 0.4rem;
|
||||
padding: 0.1rem 0.4rem;
|
||||
border-radius: 999px;
|
||||
background: rgba(41, 110, 78, 0.12);
|
||||
color: var(--primary-strong, #296e4e);
|
||||
font-size: 0.72rem;
|
||||
font-weight: 700;
|
||||
}
|
||||
.detail {
|
||||
background: white;
|
||||
border: 1px solid var(--border-color);
|
||||
@@ -557,6 +626,14 @@ select { max-width: 220px; }
|
||||
overflow: auto;
|
||||
}
|
||||
label { display: block; margin-bottom: 0.5rem; }
|
||||
.checkbox-field {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
.checkbox-field input[type="checkbox"] {
|
||||
width: auto;
|
||||
}
|
||||
input[type="text"], input[type="number"], textarea { width: 100%; }
|
||||
.actions { margin-top: 0.75rem; display: flex; gap: 0.5rem; }
|
||||
.image-section {
|
||||
@@ -624,14 +701,14 @@ input[type="text"], input[type="number"], textarea { width: 100%; }
|
||||
}
|
||||
|
||||
.btn-danger {
|
||||
background: #dc3545;
|
||||
color: white;
|
||||
border: none;
|
||||
background: rgba(200, 74, 56, 0.12);
|
||||
color: #8b3327;
|
||||
border: 1px solid rgba(200, 74, 56, 0.24);
|
||||
border-radius: var(--border-radius-small);
|
||||
}
|
||||
|
||||
.btn-danger:hover {
|
||||
background: #c82333;
|
||||
background: rgba(200, 74, 56, 0.18);
|
||||
}
|
||||
|
||||
.drawing-button-section {
|
||||
@@ -644,6 +721,28 @@ input[type="text"], input[type="number"], textarea { width: 100%; }
|
||||
margin: 1rem 0;
|
||||
}
|
||||
|
||||
.scope-filters {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 0.45rem;
|
||||
margin: 0 0 1rem;
|
||||
}
|
||||
|
||||
.scope-filter {
|
||||
border: 1px solid var(--border-color);
|
||||
background: var(--surface-subtle, #f3f7fa);
|
||||
color: var(--text-color);
|
||||
border-radius: 999px;
|
||||
padding: 0.35rem 0.75rem;
|
||||
}
|
||||
|
||||
.scope-filter.active {
|
||||
background: rgba(41, 110, 78, 0.12);
|
||||
border-color: rgba(41, 110, 78, 0.28);
|
||||
color: var(--primary-strong, #296e4e);
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.search-input {
|
||||
width: 100%;
|
||||
padding: 0.75rem 2.5rem 0.75rem 1rem;
|
||||
@@ -685,4 +784,3 @@ input[type="text"], input[type="number"], textarea { width: 100%; }
|
||||
color: #333;
|
||||
}
|
||||
</style>
|
||||
|
||||
|
||||
@@ -1,49 +1,137 @@
|
||||
<template>
|
||||
<div>
|
||||
<h2>{{ $t('schedule.title') }}</h2>
|
||||
|
||||
<SeasonSelector v-model="selectedSeasonId" @season-change="onSeasonChange" :show-current-season="true" />
|
||||
|
||||
<button @click="openImportModal">{{ $t('schedule.importSchedule') }}</button>
|
||||
<button
|
||||
v-if="playerSelectionDialog.match"
|
||||
@click="openGalleryDialog"
|
||||
class="btn-secondary"
|
||||
:disabled="galleryLoading"
|
||||
>
|
||||
{{ galleryLoading ? $t('schedule.galleryLoading') : $t('schedule.gallery') }}
|
||||
</button>
|
||||
<div class="schedule-view">
|
||||
<div class="schedule-page-header">
|
||||
<div class="schedule-page-title">
|
||||
<h2>{{ $t('schedule.title') }}</h2>
|
||||
<p>{{ $t('schedule.subtitle') }}</p>
|
||||
</div>
|
||||
<div class="schedule-page-actions">
|
||||
<SeasonSelector v-model="selectedSeasonId" @season-change="onSeasonChange" :show-current-season="true" />
|
||||
<button @click="openImportModal">{{ $t('schedule.importSchedule') }}</button>
|
||||
<button
|
||||
v-if="playerSelectionDialog.match"
|
||||
@click="openGalleryDialog"
|
||||
class="btn-secondary"
|
||||
:disabled="galleryLoading"
|
||||
>
|
||||
{{ galleryLoading ? $t('schedule.galleryLoading') : $t('schedule.gallery') }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="hoveredMatch && hoveredMatch.location" class="hover-info">
|
||||
<p><strong>{{ hoveredMatch.location.name || 'N/A' }}</strong></p>
|
||||
<p>{{ hoveredMatch.location.address || 'N/A' }}</p>
|
||||
<p>{{ hoveredMatch.location.zip || '' }} {{ hoveredMatch.location.city || 'N/A' }}</p>
|
||||
</div>
|
||||
<div class="output">
|
||||
<ul>
|
||||
<li class="special-link" @click="loadAllMatches">{{ $t('schedule.overallSchedule') }}</li>
|
||||
<li class="special-link" @click="loadAdultMatches">{{ $t('schedule.adultSchedule') }}</li>
|
||||
<li class="divider"></li>
|
||||
<li v-for="team in teams" :key="team.id" @click="loadMatchesForTeam(team)"
|
||||
:class="{ active: selectedTeam && selectedTeam.id === team.id }">
|
||||
{{ team.name }}<span class="team-league" v-if="team.league && team.league.name"> ({{ team.league.name }})</span>
|
||||
</li>
|
||||
<li v-if="teams.length === 0" class="no-leagues">{{ $t('schedule.noTeamsFound') }}</li>
|
||||
</ul>
|
||||
|
||||
<div class="schedule-summary-bar">
|
||||
<div class="schedule-summary-item">
|
||||
<span class="schedule-summary-label">{{ $t('schedule.teams') }}</span>
|
||||
<strong>{{ filteredScheduleTeams.length }}/{{ teams.length }}</strong>
|
||||
</div>
|
||||
<div class="schedule-summary-item">
|
||||
<span class="schedule-summary-label">{{ $t('schedule.matches') }}</span>
|
||||
<strong>{{ matches.length }}</strong>
|
||||
</div>
|
||||
<div class="schedule-summary-item">
|
||||
<span class="schedule-summary-label">{{ $t('schedule.completedShort') }}</span>
|
||||
<strong>{{ completedMatchesCount }}</strong>
|
||||
</div>
|
||||
<div class="schedule-summary-item">
|
||||
<span class="schedule-summary-label">{{ $t('schedule.pendingShort') }}</span>
|
||||
<strong>{{ pendingMatchesCount }}</strong>
|
||||
</div>
|
||||
<div class="schedule-summary-item" v-if="nextScheduledMatchLabel">
|
||||
<span class="schedule-summary-label">{{ $t('schedule.nextMatch') }}</span>
|
||||
<strong>{{ nextScheduledMatchLabel }}</strong>
|
||||
</div>
|
||||
</div>
|
||||
<div class="output schedule-layout">
|
||||
<aside class="schedule-sidebar">
|
||||
<div class="schedule-sidebar-card">
|
||||
<div class="schedule-sidebar-header">
|
||||
<h3>{{ $t('schedule.selection') }}</h3>
|
||||
<span class="schedule-selection-count">{{ filteredScheduleTeams.length }}/{{ teams.length }}</span>
|
||||
</div>
|
||||
<input
|
||||
v-model.trim="teamSearchQuery"
|
||||
type="search"
|
||||
class="schedule-team-search"
|
||||
:placeholder="$t('schedule.searchTeams')"
|
||||
/>
|
||||
<div class="schedule-quick-links">
|
||||
<button
|
||||
type="button"
|
||||
class="schedule-quick-link"
|
||||
:class="{ active: selectedLeague === $t('schedule.overallSchedule') }"
|
||||
@click="loadAllMatches"
|
||||
>
|
||||
{{ $t('schedule.overallSchedule') }}
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
class="schedule-quick-link"
|
||||
:class="{ active: selectedLeague === $t('schedule.adultSchedule') }"
|
||||
@click="loadAdultMatches"
|
||||
>
|
||||
{{ $t('schedule.adultSchedule') }}
|
||||
</button>
|
||||
</div>
|
||||
<ul class="schedule-team-list">
|
||||
<li v-for="team in filteredScheduleTeams" :key="team.id" @click="loadMatchesForTeam(team)"
|
||||
:class="{ active: selectedTeam && selectedTeam.id === team.id }">
|
||||
<span class="schedule-team-name">{{ team.name }}</span>
|
||||
<span class="team-league" v-if="team.league && team.league.name">{{ team.league.name }}</span>
|
||||
</li>
|
||||
<li v-if="teams.length === 0" class="no-leagues">{{ $t('schedule.noTeamsFound') }}</li>
|
||||
<li v-else-if="filteredScheduleTeams.length === 0" class="no-leagues">{{ $t('schedule.noMatchingTeams') }}</li>
|
||||
</ul>
|
||||
</div>
|
||||
</aside>
|
||||
|
||||
<div class="flex-item" ref="scheduleContainer">
|
||||
<div class="schedule-workspace-header">
|
||||
<div>
|
||||
<span class="workspace-eyebrow">{{ $t('schedule.activeSelection') }}</span>
|
||||
<h3 v-if="selectedLeague">{{ selectedLeague }}</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">
|
||||
<button
|
||||
v-if="activeTab === 'schedule' && selectedTeam"
|
||||
type="button"
|
||||
class="btn-secondary"
|
||||
@click="fetchTeamDataManually"
|
||||
:disabled="fetchingTeamData"
|
||||
>
|
||||
{{ fetchingTeamData ? $t('schedule.fetchingTeamData') : $t('schedule.fetchTeamData') }}
|
||||
</button>
|
||||
<button v-if="activeTab === 'schedule'" @click="generatePDF">{{ $t('schedule.downloadPDF') }}</button>
|
||||
<button
|
||||
v-if="activeTab === 'table' && selectedTeam"
|
||||
type="button"
|
||||
class="btn-secondary"
|
||||
@click="fetchTableFromMyTischtennis"
|
||||
:disabled="fetchingTable"
|
||||
>
|
||||
{{ fetchingTable ? $t('schedule.tableLoading') : $t('schedule.refreshTable') }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Tab Navigation - nur anzeigen wenn Liga ausgewählt -->
|
||||
<div v-if="selectedLeague && selectedLeague !== ''" class="tab-navigation">
|
||||
<button
|
||||
:class="['tab-button', { active: activeTab === 'schedule' }]"
|
||||
@click="activeTab = 'schedule'"
|
||||
>
|
||||
📅 {{ $t('schedule.scheduleTab') }}
|
||||
📅 {{ $t('schedule.scheduleTab') }} <span class="tab-count">{{ matches.length }}</span>
|
||||
</button>
|
||||
<button
|
||||
:class="['tab-button', { active: activeTab === 'table' }]"
|
||||
@click="activeTab = 'table'"
|
||||
>
|
||||
📊 {{ $t('schedule.tableTab') }}
|
||||
📊 {{ $t('schedule.tableTab') }} <span class="tab-count">{{ leagueTable.length }}</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@@ -51,9 +139,50 @@
|
||||
<div v-if="selectedLeague && selectedLeague !== ''" class="tab-content">
|
||||
<!-- Spielplan Tab -->
|
||||
<div v-show="activeTab === 'schedule'" class="tab-panel">
|
||||
<button @click="generatePDF">{{ $t('schedule.downloadPDF') }}</button>
|
||||
<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>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="matches.length > 0">
|
||||
<h3>{{ $t('schedule.gamesFor') }} {{ selectedLeague }}</h3>
|
||||
<table id="schedule-table">
|
||||
<thead>
|
||||
<tr>
|
||||
@@ -164,6 +293,10 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else class="schedule-empty-state">
|
||||
<h3>{{ $t('schedule.noSelectionTitle') }}</h3>
|
||||
<p>{{ $t('schedule.noSelectionMessage') }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -323,6 +456,52 @@ export default {
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(['isAuthenticated', 'currentClub', 'clubs', 'currentClubName']),
|
||||
filteredScheduleTeams() {
|
||||
const query = this.teamSearchQuery.trim().toLowerCase();
|
||||
if (!query) {
|
||||
return this.teams;
|
||||
}
|
||||
return this.teams.filter((team) => {
|
||||
const teamName = team.name?.toLowerCase() || '';
|
||||
const leagueName = team.league?.name?.toLowerCase() || '';
|
||||
return teamName.includes(query) || leagueName.includes(query);
|
||||
});
|
||||
},
|
||||
completedMatchesCount() {
|
||||
return this.matches.filter(match => match.isCompleted).length;
|
||||
},
|
||||
pendingMatchesCount() {
|
||||
return this.matches.length - this.completedMatchesCount;
|
||||
},
|
||||
nextScheduledMatchLabel() {
|
||||
const today = new Date();
|
||||
today.setHours(0, 0, 0, 0);
|
||||
const nextMatch = this.matches
|
||||
.filter(match => match.date)
|
||||
.map(match => ({ ...match, _date: new Date(match.date) }))
|
||||
.filter(match => !isNaN(match._date.getTime()) && match._date >= today)
|
||||
.sort((a, b) => a._date - b._date)[0];
|
||||
return nextMatch ? this.formatDate(nextMatch.date) : '';
|
||||
},
|
||||
workspaceDescription() {
|
||||
if (!this.selectedLeague) return '';
|
||||
return this.activeTab === 'table'
|
||||
? this.$t('schedule.workspaceTableDescription', { count: this.leagueTable.length })
|
||||
: this.$t('schedule.workspaceScheduleDescription', {
|
||||
matches: this.matches.length,
|
||||
completed: this.completedMatchesCount,
|
||||
pending: this.pendingMatchesCount
|
||||
});
|
||||
},
|
||||
leagueTeamOptions() {
|
||||
const ownTeamName = this.selectedTeam?.name;
|
||||
return Array.from(new Set(this.allLeagueMatches.flatMap(match => [
|
||||
match.homeTeam?.name,
|
||||
match.guestTeam?.name
|
||||
].filter(Boolean))))
|
||||
.filter(teamName => teamName !== ownTeamName)
|
||||
.sort((a, b) => a.localeCompare(b));
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
currentClub: {
|
||||
@@ -369,6 +548,12 @@ export default {
|
||||
activeTab: 'schedule',
|
||||
leagueTable: [],
|
||||
fetchingTable: false,
|
||||
fetchingTeamData: false,
|
||||
teamSearchQuery: '',
|
||||
ownLeagueMatches: [],
|
||||
allLeagueMatches: [],
|
||||
leagueMatchScope: 'own',
|
||||
selectedComparisonTeamName: '',
|
||||
|
||||
// Player Selection Dialog
|
||||
playerSelectionDialog: {
|
||||
@@ -790,6 +975,10 @@ export default {
|
||||
if (idxA !== idxB) return idxA - idxB;
|
||||
return a.name.localeCompare(b.name);
|
||||
});
|
||||
|
||||
if (!this.selectedLeague && this.teams.length > 0) {
|
||||
await this.loadMatchesForSpecificTeam(this.teams[0], { resetScope: true });
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('ScheduleView: Error loading teams:', error);
|
||||
this.showInfo(this.$t('messages.error'), this.$t('schedule.errorLoadingTeams'), '', 'error');
|
||||
@@ -804,6 +993,9 @@ export default {
|
||||
this.selectedTeam = null;
|
||||
},
|
||||
async loadMatchesForTeam(team) {
|
||||
await this.loadMatchesForSpecificTeam(team, { resetScope: true });
|
||||
},
|
||||
async loadMatchesForSpecificTeam(team, { resetScope = false } = {}) {
|
||||
if (!team || !team.league) {
|
||||
this.showInfo(this.$t('messages.warning'), this.$t('schedule.noLeagueForTeam'), '', 'warning');
|
||||
return;
|
||||
@@ -811,20 +1003,69 @@ export default {
|
||||
this.selectedTeam = team;
|
||||
this.selectedLeague = `${team.name}${team.league?.name ? ` (${team.league.name})` : ''}`;
|
||||
this.activeTab = 'schedule';
|
||||
if (resetScope) {
|
||||
this.leagueMatchScope = 'own';
|
||||
this.selectedComparisonTeamName = '';
|
||||
}
|
||||
try {
|
||||
const response = await apiClient.get(`/matches/leagues/${this.currentClub}/matches/${team.league.id}`);
|
||||
this.matches = response.data;
|
||||
|
||||
const ownResponse = await apiClient.get(`/matches/leagues/${this.currentClub}/matches/${team.league.id}`);
|
||||
this.ownLeagueMatches = ownResponse.data;
|
||||
await this.loadLeagueMatches(team.league.id);
|
||||
this.applyLeagueMatchScope();
|
||||
// Lade auch die Tabellendaten für diese Liga
|
||||
await this.loadLeagueTable(team.league.id);
|
||||
} catch (error) {
|
||||
this.showInfo(this.$t('messages.error'), this.$t('schedule.errorLoadingMatches'), '', 'error');
|
||||
this.matches = [];
|
||||
this.ownLeagueMatches = [];
|
||||
this.allLeagueMatches = [];
|
||||
}
|
||||
},
|
||||
async loadLeagueMatches(leagueId) {
|
||||
const response = await apiClient.get(`/matches/leagues/${this.currentClub}/matches/${leagueId}?scope=all`);
|
||||
this.allLeagueMatches = response.data;
|
||||
},
|
||||
applyLeagueMatchScope() {
|
||||
if (!this.selectedTeam) {
|
||||
return;
|
||||
}
|
||||
const ownTeamName = this.selectedTeam.name;
|
||||
if (this.leagueMatchScope === 'all') {
|
||||
this.matches = this.allLeagueMatches;
|
||||
return;
|
||||
}
|
||||
if (this.leagueMatchScope === 'other') {
|
||||
if (!this.selectedComparisonTeamName && this.leagueTeamOptions.length > 0) {
|
||||
this.selectedComparisonTeamName = this.leagueTeamOptions[0];
|
||||
}
|
||||
this.matches = this.selectedComparisonTeamName
|
||||
? this.allLeagueMatches.filter(match =>
|
||||
match.homeTeam?.name === this.selectedComparisonTeamName ||
|
||||
match.guestTeam?.name === this.selectedComparisonTeamName
|
||||
)
|
||||
: [];
|
||||
return;
|
||||
}
|
||||
this.matches = this.ownLeagueMatches.length > 0
|
||||
? this.ownLeagueMatches
|
||||
: this.allLeagueMatches.filter(match =>
|
||||
match.homeTeam?.name === ownTeamName || match.guestTeam?.name === ownTeamName
|
||||
);
|
||||
},
|
||||
setLeagueMatchScope(scope) {
|
||||
this.leagueMatchScope = scope;
|
||||
if (scope !== 'other') {
|
||||
this.selectedComparisonTeamName = '';
|
||||
}
|
||||
this.applyLeagueMatchScope();
|
||||
},
|
||||
async loadAllMatches() {
|
||||
this.selectedLeague = this.$t('schedule.overallSchedule');
|
||||
this.selectedTeam = null;
|
||||
this.ownLeagueMatches = [];
|
||||
this.allLeagueMatches = [];
|
||||
this.leagueMatchScope = 'own';
|
||||
this.selectedComparisonTeamName = '';
|
||||
try {
|
||||
const seasonParam = this.selectedSeasonId ? `?seasonid=${this.selectedSeasonId}` : '';
|
||||
const response = await apiClient.get(`/matches/leagues/${this.currentClub}/matches${seasonParam}`);
|
||||
@@ -837,6 +1078,10 @@ export default {
|
||||
async loadAdultMatches() {
|
||||
this.selectedLeague = this.$t('schedule.adultSchedule');
|
||||
this.selectedTeam = null;
|
||||
this.ownLeagueMatches = [];
|
||||
this.allLeagueMatches = [];
|
||||
this.leagueMatchScope = 'own';
|
||||
this.selectedComparisonTeamName = '';
|
||||
try {
|
||||
const seasonParam = this.selectedSeasonId ? `?seasonid=${this.selectedSeasonId}` : '';
|
||||
const response = await apiClient.get(`/matches/leagues/${this.currentClub}/matches${seasonParam}`);
|
||||
@@ -1039,11 +1284,58 @@ export default {
|
||||
this.fetchingTable = false;
|
||||
}
|
||||
},
|
||||
async fetchTeamDataManually() {
|
||||
if (!this.selectedTeam?.id) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.fetchingTeamData = true;
|
||||
try {
|
||||
const response = await apiClient.post('/scheduler/match_results', {
|
||||
clubTeamId: this.selectedTeam.id
|
||||
});
|
||||
const result = response?.data;
|
||||
|
||||
if (!result?.success) {
|
||||
throw new Error(result?.error || result?.message || this.$t('schedule.fetchDataFailed'));
|
||||
}
|
||||
|
||||
await this.loadMatchesForSpecificTeam(this.selectedTeam);
|
||||
if (this.selectedTeam?.league?.id) {
|
||||
await this.loadLeagueTable(this.selectedTeam.league.id);
|
||||
}
|
||||
|
||||
const fetchedCount =
|
||||
result?.result?.totalFetched ??
|
||||
result?.result?.fetchedCount ??
|
||||
result?.result?.data?.fetchedCount ??
|
||||
0;
|
||||
|
||||
await this.showInfo(
|
||||
this.$t('messages.success'),
|
||||
this.$t('schedule.teamDataFetched'),
|
||||
this.$t('schedule.teamDataFetchedDetails', {
|
||||
team: this.selectedTeam.name,
|
||||
count: fetchedCount
|
||||
}),
|
||||
'success'
|
||||
);
|
||||
} catch (error) {
|
||||
await this.showInfo(
|
||||
this.$t('messages.error'),
|
||||
getSafeErrorMessage(error, this.$t('schedule.fetchDataFailed')),
|
||||
'',
|
||||
'error'
|
||||
);
|
||||
} finally {
|
||||
this.fetchingTeamData = false;
|
||||
}
|
||||
},
|
||||
|
||||
refreshScheduleData() {
|
||||
if (!this.selectedLeague) return;
|
||||
if (this.selectedTeam) {
|
||||
this.loadMatchesForTeam(this.selectedTeam);
|
||||
this.loadMatchesForSpecificTeam(this.selectedTeam);
|
||||
} else if (this.selectedLeague === this.$t('schedule.overallSchedule')) {
|
||||
this.loadAllMatches();
|
||||
} else if (this.selectedLeague === this.$t('schedule.adultSchedule')) {
|
||||
@@ -1443,18 +1735,20 @@ li {
|
||||
}
|
||||
|
||||
.fetch-table-btn {
|
||||
background-color: #28a745;
|
||||
color: white;
|
||||
border: none;
|
||||
background: linear-gradient(135deg, var(--primary-color), var(--primary-hover));
|
||||
color: var(--text-on-primary);
|
||||
border: 1px solid transparent;
|
||||
padding: 8px 16px;
|
||||
border-radius: 4px;
|
||||
border-radius: 10px;
|
||||
cursor: pointer;
|
||||
font-size: 14px;
|
||||
transition: background-color 0.3s ease;
|
||||
font-weight: 600;
|
||||
transition: transform 0.2s ease, opacity 0.2s ease;
|
||||
}
|
||||
|
||||
.fetch-table-btn:hover:not(:disabled) {
|
||||
background-color: #218838;
|
||||
transform: translateY(-1px);
|
||||
opacity: 0.95;
|
||||
}
|
||||
|
||||
.fetch-table-btn:disabled {
|
||||
@@ -1673,23 +1967,284 @@ li {
|
||||
}
|
||||
|
||||
.btn-save {
|
||||
background-color: #28a745;
|
||||
color: white;
|
||||
background: linear-gradient(135deg, var(--primary-color), var(--primary-hover));
|
||||
color: var(--text-on-primary);
|
||||
}
|
||||
|
||||
.btn-save:hover {
|
||||
background-color: #218838;
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
.btn-cancel {
|
||||
background-color: #6c757d;
|
||||
color: white;
|
||||
background: var(--surface-color);
|
||||
color: var(--text-color);
|
||||
border-color: var(--border-color);
|
||||
}
|
||||
|
||||
.btn-cancel:hover {
|
||||
background-color: #5a6268;
|
||||
}
|
||||
|
||||
.schedule-view {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
.schedule-page-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
gap: 16px;
|
||||
align-items: flex-start;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.schedule-page-title h2 {
|
||||
margin: 0 0 4px;
|
||||
}
|
||||
|
||||
.schedule-page-title p {
|
||||
margin: 0;
|
||||
color: var(--text-muted, #6c757d);
|
||||
}
|
||||
|
||||
.schedule-page-actions {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
align-items: center;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.schedule-summary-bar {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.schedule-summary-item {
|
||||
min-width: 120px;
|
||||
padding: 10px 12px;
|
||||
border: 1px solid var(--border-color, #dee2e6);
|
||||
border-radius: 10px;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
.schedule-summary-label {
|
||||
display: block;
|
||||
font-size: 12px;
|
||||
color: var(--text-muted, #6c757d);
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
.schedule-layout {
|
||||
display: grid;
|
||||
grid-template-columns: 280px minmax(0, 1fr);
|
||||
gap: 16px;
|
||||
align-items: start;
|
||||
}
|
||||
|
||||
.schedule-sidebar {
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.schedule-sidebar-card,
|
||||
.schedule-workspace-header,
|
||||
.schedule-empty-state {
|
||||
border: 1px solid var(--border-color, #dee2e6);
|
||||
border-radius: 12px;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
.schedule-sidebar-card {
|
||||
padding: 14px;
|
||||
}
|
||||
|
||||
.schedule-sidebar-header,
|
||||
.schedule-workspace-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
gap: 16px;
|
||||
align-items: flex-start;
|
||||
}
|
||||
|
||||
.schedule-sidebar-header h3,
|
||||
.schedule-workspace-header h3 {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.schedule-selection-count,
|
||||
.workspace-eyebrow {
|
||||
font-size: 12px;
|
||||
color: var(--text-muted, #6c757d);
|
||||
}
|
||||
|
||||
.workspace-eyebrow {
|
||||
display: block;
|
||||
margin-bottom: 4px;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.04em;
|
||||
}
|
||||
|
||||
.schedule-workspace-header {
|
||||
padding: 14px 16px;
|
||||
margin-bottom: 14px;
|
||||
}
|
||||
|
||||
.schedule-workspace-header p {
|
||||
margin: 6px 0 0;
|
||||
color: var(--text-muted, #6c757d);
|
||||
}
|
||||
|
||||
.schedule-workspace-actions {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.schedule-team-search {
|
||||
width: 100%;
|
||||
margin-top: 12px;
|
||||
margin-bottom: 12px;
|
||||
padding: 10px 12px;
|
||||
border: 1px solid var(--border-color, #ced4da);
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.schedule-quick-links {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.schedule-quick-link {
|
||||
width: 100%;
|
||||
text-align: left;
|
||||
padding: 10px 12px;
|
||||
border: 1px solid var(--border-color, #dee2e6);
|
||||
border-radius: 8px;
|
||||
background: #fff;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.schedule-quick-link.active,
|
||||
.schedule-team-list li.active {
|
||||
border-color: var(--primary-color, #2b7cff);
|
||||
color: var(--primary-color, #2b7cff);
|
||||
background: rgba(43, 124, 255, 0.08);
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.schedule-team-list {
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.schedule-team-list li {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 4px;
|
||||
padding: 10px 12px;
|
||||
border: 1px solid var(--border-color, #dee2e6);
|
||||
border-radius: 8px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.schedule-team-name {
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.league-match-scope-card {
|
||||
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;
|
||||
}
|
||||
|
||||
.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;
|
||||
}
|
||||
|
||||
.league-match-scope-controls {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 8px;
|
||||
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;
|
||||
border: 1px solid var(--border-color, #dee2e6);
|
||||
border-radius: 10px;
|
||||
background: var(--surface-color, #fff);
|
||||
color: var(--text-color, #333);
|
||||
}
|
||||
|
||||
.league-match-scope-select:focus {
|
||||
outline: none;
|
||||
border-color: var(--primary-color, #2f7a5f);
|
||||
box-shadow: 0 0 0 3px rgba(47, 122, 95, 0.14);
|
||||
}
|
||||
|
||||
.tab-count {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
min-width: 22px;
|
||||
height: 22px;
|
||||
padding: 0 6px;
|
||||
margin-left: 6px;
|
||||
border-radius: 999px;
|
||||
background: rgba(47, 122, 95, 0.12);
|
||||
color: var(--primary-strong, #1f5f49);
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.schedule-empty-state {
|
||||
padding: 28px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.schedule-empty-state h3 {
|
||||
margin-top: 0;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.schedule-empty-state p {
|
||||
margin: 0;
|
||||
color: var(--text-muted, #6c757d);
|
||||
}
|
||||
|
||||
.output ul li.active {
|
||||
font-weight: 600;
|
||||
color: var(--primary-color, #2b7cff);
|
||||
@@ -1698,4 +2253,10 @@ li {
|
||||
.team-league {
|
||||
color: var(--text-muted, #6c757d);
|
||||
}
|
||||
|
||||
@media (max-width: 960px) {
|
||||
.schedule-layout {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,24 +1,55 @@
|
||||
<template>
|
||||
<div>
|
||||
<h2>{{ t('teamManagement.title') }}</h2>
|
||||
|
||||
<SeasonSelector
|
||||
v-model="selectedSeasonId"
|
||||
@season-change="onSeasonChange"
|
||||
:show-current-season="true"
|
||||
/>
|
||||
|
||||
<div v-if="schedulerJobs.rating_updates || schedulerJobs.match_results" class="scheduler-jobs-summary">
|
||||
<div class="scheduler-jobs-summary-copy">
|
||||
<strong>{{ t('teamManagement.automaticJobs') }}</strong>
|
||||
<span v-if="schedulerJobs.rating_updates?.lastRun || schedulerJobs.match_results?.lastRun" class="scheduler-jobs-summary-text">
|
||||
{{ t('teamManagement.lastRun') }}:
|
||||
{{ formatJobDate(schedulerJobs.match_results?.lastRun || schedulerJobs.rating_updates?.lastRun) }}
|
||||
</span>
|
||||
<div class="team-management-view">
|
||||
<div class="team-management-hero">
|
||||
<div class="team-management-hero-header">
|
||||
<div class="team-management-hero-copy">
|
||||
<h2>{{ t('teamManagement.title') }}</h2>
|
||||
<p>{{ t('teamManagement.subtitle') }}</p>
|
||||
</div>
|
||||
<div class="team-management-hero-actions">
|
||||
<div class="team-management-season-selector">
|
||||
<span class="team-management-hero-label">{{ t('teamManagement.season') }}</span>
|
||||
<SeasonSelector
|
||||
v-model="selectedSeasonId"
|
||||
@season-change="onSeasonChange"
|
||||
:show-current-season="true"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-if="schedulerJobs.rating_updates || schedulerJobs.match_results" class="scheduler-jobs-summary">
|
||||
<div class="scheduler-jobs-summary-copy">
|
||||
<strong>{{ t('teamManagement.automaticJobs') }}</strong>
|
||||
<span v-if="schedulerJobs.rating_updates?.lastRun || schedulerJobs.match_results?.lastRun" class="scheduler-jobs-summary-text">
|
||||
{{ t('teamManagement.lastRun') }}:
|
||||
{{ formatJobDate(schedulerJobs.match_results?.lastRun || schedulerJobs.rating_updates?.lastRun) }}
|
||||
</span>
|
||||
</div>
|
||||
<button type="button" class="scheduler-jobs-toggle" @click="showGlobalJobDetails = !showGlobalJobDetails">
|
||||
<span class="scheduler-jobs-toggle-icon">{{ showGlobalJobDetails ? '▾' : '▸' }}</span>
|
||||
<span class="scheduler-jobs-toggle-text">{{ showGlobalJobDetails ? t('common.close') : t('common.details') }}</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="team-management-summary">
|
||||
<div class="team-summary-card">
|
||||
<span class="team-summary-label">{{ t('teamManagement.teams') }}</span>
|
||||
<strong class="team-summary-value">{{ teams.length }}</strong>
|
||||
</div>
|
||||
<div class="team-summary-card">
|
||||
<span class="team-summary-label">{{ t('teamManagement.fullyConfigured') }}</span>
|
||||
<strong class="team-summary-value">{{ fullyConfiguredTeamsCount }}</strong>
|
||||
</div>
|
||||
<div class="team-summary-card">
|
||||
<span class="team-summary-label">{{ t('teamManagement.partiallyConfigured') }}</span>
|
||||
<strong class="team-summary-value">{{ partiallyConfiguredTeamsCount }}</strong>
|
||||
</div>
|
||||
<div class="team-summary-card">
|
||||
<span class="team-summary-label">{{ t('teamManagement.noLeague') }}</span>
|
||||
<strong class="team-summary-value">{{ teamsWithoutLeagueCount }}</strong>
|
||||
</div>
|
||||
</div>
|
||||
<button type="button" class="scheduler-jobs-toggle" @click="showGlobalJobDetails = !showGlobalJobDetails">
|
||||
{{ showGlobalJobDetails ? t('common.close') : t('common.details') }}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div v-if="showGlobalJobDetails && (schedulerJobs.rating_updates || schedulerJobs.match_results)" class="scheduler-jobs-info">
|
||||
@@ -53,25 +84,6 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="team-management-summary">
|
||||
<div class="team-summary-card">
|
||||
<span class="team-summary-label">{{ t('teamManagement.teams') }}</span>
|
||||
<strong class="team-summary-value">{{ teams.length }}</strong>
|
||||
</div>
|
||||
<div class="team-summary-card">
|
||||
<span class="team-summary-label">{{ t('teamManagement.fullyConfigured') }}</span>
|
||||
<strong class="team-summary-value">{{ fullyConfiguredTeamsCount }}</strong>
|
||||
</div>
|
||||
<div class="team-summary-card">
|
||||
<span class="team-summary-label">{{ t('teamManagement.partiallyConfigured') }}</span>
|
||||
<strong class="team-summary-value">{{ partiallyConfiguredTeamsCount }}</strong>
|
||||
</div>
|
||||
<div class="team-summary-card">
|
||||
<span class="team-summary-label">{{ t('teamManagement.noLeague') }}</span>
|
||||
<strong class="team-summary-value">{{ teamsWithoutLeagueCount }}</strong>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="teams-list">
|
||||
<div class="teams-list-header">
|
||||
<h3>{{ t('teamManagement.teams') }} ({{ filteredTeams.length }}) - {{ t('teamManagement.season') }} {{ currentSeason?.season || t('teamManagement.seasonUnknown') }}</h3>
|
||||
@@ -115,11 +127,9 @@
|
||||
<span class="team-league-inline">
|
||||
{{ team.league ? team.league.name : t('teamManagement.noLeague') }}
|
||||
</span>
|
||||
<span class="team-open-hint">{{ t('teamManagement.openInWorkspace') }}</span>
|
||||
</div>
|
||||
<div class="team-actions">
|
||||
<button @click.stop="editTeam(team)" class="btn-edit" :title="t('teamManagement.edit')">
|
||||
✏️
|
||||
</button>
|
||||
<button @click.stop="deleteTeam(team)" class="btn-delete" :title="t('teamManagement.delete')">
|
||||
🗑️
|
||||
</button>
|
||||
@@ -225,21 +235,42 @@
|
||||
</div>
|
||||
|
||||
<div v-if="activeEditorSection === 'basic'" class="workspace-section-panel basic-settings">
|
||||
<label>
|
||||
<span>{{ t('teamManagement.teamName') }}:</span>
|
||||
<input type="text" v-model="newTeamName" :placeholder="t('teamManagement.teamNamePlaceholder')">
|
||||
</label>
|
||||
|
||||
<label>
|
||||
<span>{{ t('teamManagement.league') }}:</span>
|
||||
<select v-model="newLeagueId">
|
||||
<option value="">{{ t('teamManagement.noLeague') }}</option>
|
||||
<option v-for="league in filteredLeagues" :key="league.id" :value="league.id">
|
||||
{{ league.name }}
|
||||
</option>
|
||||
</select>
|
||||
</label>
|
||||
|
||||
<div class="workspace-panel-header">
|
||||
<div>
|
||||
<span class="section-title">⚙️ {{ t('teamManagement.basicSettings') }}</span>
|
||||
<p class="workspace-panel-copy">{{ t('teamManagement.basicSettingsIntro') }}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="teamToEdit" class="settings-summary-grid">
|
||||
<div class="settings-summary-card">
|
||||
<span class="settings-summary-label">{{ t('teamManagement.teamName') }}</span>
|
||||
<strong>{{ teamToEdit.name }}</strong>
|
||||
</div>
|
||||
<div class="settings-summary-card">
|
||||
<span class="settings-summary-label">{{ t('teamManagement.league') }}</span>
|
||||
<strong>{{ teamToEdit.league ? teamToEdit.league.name : t('teamManagement.noLeague') }}</strong>
|
||||
</div>
|
||||
<div class="settings-summary-card">
|
||||
<span class="settings-summary-label">{{ t('teamManagement.season') }}</span>
|
||||
<strong>{{ teamToEdit.season?.season || t('teamManagement.seasonUnknown') }}</strong>
|
||||
</div>
|
||||
</div>
|
||||
<div class="settings-form-grid">
|
||||
<label>
|
||||
<span>{{ t('teamManagement.teamName') }}:</span>
|
||||
<input type="text" v-model="newTeamName" :placeholder="t('teamManagement.teamNamePlaceholder')">
|
||||
</label>
|
||||
|
||||
<label>
|
||||
<span>{{ t('teamManagement.league') }}:</span>
|
||||
<select v-model="newLeagueId">
|
||||
<option value="">{{ t('teamManagement.noLeague') }}</option>
|
||||
<option v-for="league in filteredLeagues" :key="league.id" :value="league.id">
|
||||
{{ league.name }}
|
||||
</option>
|
||||
</select>
|
||||
</label>
|
||||
</div>
|
||||
<div class="form-actions">
|
||||
<button @click="addNewTeam" :disabled="!newTeamName.trim()">
|
||||
{{ teamToEdit ? t('teamManagement.change') : t('teamManagement.createAndEdit') }}
|
||||
@@ -254,12 +285,29 @@
|
||||
</div>
|
||||
|
||||
<div v-if="teamToEdit && teamToEdit.leagueId && activeEditorSection === 'stats'" class="workspace-section-panel player-stats">
|
||||
<div class="stats-header">
|
||||
<span class="section-title">📊 {{ t('teamManagement.playerStats') }}</span>
|
||||
<div class="workspace-panel-header">
|
||||
<div>
|
||||
<span class="section-title">📊 {{ t('teamManagement.playerStats') }}</span>
|
||||
<p class="workspace-panel-copy">{{ t('teamManagement.playerStatsIntro') }}</p>
|
||||
</div>
|
||||
<button @click="refreshPlayerStats" :disabled="loadingStats" class="btn-sm">
|
||||
{{ loadingStats ? '⏳' : '🔄' }}
|
||||
{{ loadingStats ? '⏳' : '🔄' }} {{ t('teamManagement.refreshStats') }}
|
||||
</button>
|
||||
</div>
|
||||
<div v-if="playerStats.length > 0" class="stats-summary-grid">
|
||||
<div class="settings-summary-card">
|
||||
<span class="settings-summary-label">{{ t('teamManagement.player') }}</span>
|
||||
<strong>{{ playerStats.length }}</strong>
|
||||
</div>
|
||||
<div class="settings-summary-card">
|
||||
<span class="settings-summary-label">{{ t('teamManagement.season') }}</span>
|
||||
<strong>{{ totalSeasonAppearances }}</strong>
|
||||
</div>
|
||||
<div class="settings-summary-card">
|
||||
<span class="settings-summary-label">{{ isSecondHalf ? t('teamManagement.secondHalf') : t('teamManagement.firstHalf') }}</span>
|
||||
<strong>{{ totalHalfAppearances }}</strong>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-if="loadingStats" class="loading-stats">{{ t('teamManagement.loadingStats') }}</div>
|
||||
|
||||
@@ -295,15 +343,78 @@
|
||||
</div>
|
||||
|
||||
<div v-if="teamToEdit && activeEditorSection === 'documents'" class="workspace-section-panel advanced-settings">
|
||||
<div class="upload-actions compact">
|
||||
<div class="workspace-panel-header">
|
||||
<div>
|
||||
<span class="section-title">📋 {{ t('teamManagement.documents') }}</span>
|
||||
<div class="upload-buttons-compact">
|
||||
<button @click="uploadCodeList" class="btn-upload-sm">
|
||||
📋 {{ t('teamManagement.codeList') }}
|
||||
</button>
|
||||
<button @click="uploadPinList" class="btn-upload-sm">
|
||||
🔐 {{ t('teamManagement.pinList') }}
|
||||
</button>
|
||||
<p class="workspace-panel-copy">{{ t('teamManagement.documentsIntro') }}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="document-status-grid">
|
||||
<div class="document-status-card">
|
||||
<div class="document-status-head">
|
||||
<strong>{{ t('teamManagement.codeList') }}</strong>
|
||||
<span class="document-status-badge" :class="getTeamDocuments(teamToEdit.id, 'code_list').length ? 'complete' : 'missing'">
|
||||
{{ getTeamDocuments(teamToEdit.id, 'code_list').length ? t('teamManagement.documentAvailable') : t('teamManagement.documentMissing') }}
|
||||
</span>
|
||||
</div>
|
||||
<p class="document-status-meta">
|
||||
{{ getLatestTeamDocument(teamToEdit.id, 'code_list') ? t('teamManagement.latestUpload', { date: formatDate(getLatestTeamDocument(teamToEdit.id, 'code_list').createdAt) }) : t('teamManagement.noDocumentUploadYet') }}
|
||||
</p>
|
||||
<div class="document-status-actions">
|
||||
<button @click="uploadCodeList" class="btn-upload-sm">
|
||||
📋 {{ getTeamDocuments(teamToEdit.id, 'code_list').length ? t('teamManagement.uploadNewVersion') : t('teamManagement.codeList') }}
|
||||
</button>
|
||||
<button
|
||||
v-if="getLatestTeamDocument(teamToEdit.id, 'code_list')"
|
||||
type="button"
|
||||
class="btn-secondary btn-upload-sm"
|
||||
@click="showPDFDialog(teamToEdit.id, 'code_list')"
|
||||
>
|
||||
{{ t('teamManagement.openDocument') }}
|
||||
</button>
|
||||
<button
|
||||
v-if="getLatestTeamDocument(teamToEdit.id, 'code_list')"
|
||||
type="button"
|
||||
class="btn-secondary btn-upload-sm"
|
||||
@click="parsePDF(getLatestTeamDocument(teamToEdit.id, 'code_list'))"
|
||||
:disabled="!!parsingDocuments[getLatestTeamDocument(teamToEdit.id, 'code_list').id]"
|
||||
>
|
||||
{{ t('teamManagement.parseDocument') }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="document-status-card">
|
||||
<div class="document-status-head">
|
||||
<strong>{{ t('teamManagement.pinList') }}</strong>
|
||||
<span class="document-status-badge" :class="getTeamDocuments(teamToEdit.id, 'pin_list').length ? 'complete' : 'missing'">
|
||||
{{ getTeamDocuments(teamToEdit.id, 'pin_list').length ? t('teamManagement.documentAvailable') : t('teamManagement.documentMissing') }}
|
||||
</span>
|
||||
</div>
|
||||
<p class="document-status-meta">
|
||||
{{ getLatestTeamDocument(teamToEdit.id, 'pin_list') ? t('teamManagement.latestUpload', { date: formatDate(getLatestTeamDocument(teamToEdit.id, 'pin_list').createdAt) }) : t('teamManagement.noDocumentUploadYet') }}
|
||||
</p>
|
||||
<div class="document-status-actions">
|
||||
<button @click="uploadPinList" class="btn-upload-sm">
|
||||
🔐 {{ getTeamDocuments(teamToEdit.id, 'pin_list').length ? t('teamManagement.uploadNewVersion') : t('teamManagement.pinList') }}
|
||||
</button>
|
||||
<button
|
||||
v-if="getLatestTeamDocument(teamToEdit.id, 'pin_list')"
|
||||
type="button"
|
||||
class="btn-secondary btn-upload-sm"
|
||||
@click="showPDFDialog(teamToEdit.id, 'pin_list')"
|
||||
>
|
||||
{{ t('teamManagement.openDocument') }}
|
||||
</button>
|
||||
<button
|
||||
v-if="getLatestTeamDocument(teamToEdit.id, 'pin_list')"
|
||||
type="button"
|
||||
class="btn-secondary btn-upload-sm"
|
||||
@click="parsePDF(getLatestTeamDocument(teamToEdit.id, 'pin_list'))"
|
||||
:disabled="!!parsingDocuments[getLatestTeamDocument(teamToEdit.id, 'pin_list').id]"
|
||||
>
|
||||
{{ t('teamManagement.parseDocument') }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -330,12 +441,10 @@
|
||||
|
||||
<div v-if="teamToEdit && activeEditorSection === 'myTischtennis'" class="workspace-section-panel advanced-settings">
|
||||
<div class="mytischtennis-config compact">
|
||||
<div class="mytischtennis-header-compact">
|
||||
<span class="section-title">🏓 {{ t('teamManagement.myTischtennis') }}</span>
|
||||
<div class="status-inline">
|
||||
<span v-if="getMyTischtennisStatus(teamToEdit).complete" class="badge-sm complete">✓</span>
|
||||
<span v-else-if="getMyTischtennisStatus(teamToEdit).partial" class="badge-sm partial">⚠</span>
|
||||
<span v-else class="badge-sm missing">✗</span>
|
||||
<div class="workspace-panel-header">
|
||||
<div>
|
||||
<span class="section-title">🏓 {{ t('teamManagement.myTischtennis') }}</span>
|
||||
<p class="workspace-panel-copy">{{ t('teamManagement.myTischtennisIntro') }}</p>
|
||||
</div>
|
||||
<button
|
||||
v-if="getMyTischtennisStatus(teamToEdit).complete"
|
||||
@@ -343,9 +452,23 @@
|
||||
:disabled="fetchingTeamData"
|
||||
class="btn-sm"
|
||||
>
|
||||
{{ fetchingTeamData ? '⏳' : '🔄' }}
|
||||
{{ fetchingTeamData ? '⏳' : '🔄' }} {{ t('teamManagement.manualFetch') }}
|
||||
</button>
|
||||
</div>
|
||||
<div class="mytt-status-card">
|
||||
<div class="mytt-status-line">
|
||||
<span class="mytt-status-label">{{ t('teamManagement.configurationStatus') }}</span>
|
||||
<span v-if="getMyTischtennisStatus(teamToEdit).complete" class="status-badge complete">✓ {{ t('teamManagement.fullyConfigured') }}</span>
|
||||
<span v-else-if="getMyTischtennisStatus(teamToEdit).partial" class="status-badge partial">⚠ {{ t('teamManagement.partiallyConfigured') }}</span>
|
||||
<span v-else class="status-badge missing">✗ {{ t('teamManagement.notConfigured') }}</span>
|
||||
</div>
|
||||
<p v-if="getMyTischtennisStatus(teamToEdit).missing" class="mytt-status-copy">
|
||||
{{ getMyTischtennisStatus(teamToEdit).missing }}
|
||||
</p>
|
||||
<p v-else class="mytt-status-copy">
|
||||
{{ t('teamManagement.noIssues') }}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="compact-input-row">
|
||||
<input
|
||||
@@ -356,7 +479,9 @@
|
||||
class="compact-url-input"
|
||||
:disabled="parsingUrl"
|
||||
>
|
||||
<span v-if="parsingUrl" class="inline-status">⏳</span>
|
||||
<button type="button" class="btn-secondary btn-upload-sm" @click="parseMyTischtennisUrl" :disabled="parsingUrl || !myTischtennisUrl.trim()">
|
||||
{{ parsingUrl ? '⏳' : t('teamManagement.parseUrlAction') }}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div v-if="myTischtennisError" class="compact-message error">⚠️ {{ myTischtennisError }}</div>
|
||||
@@ -510,6 +635,8 @@ export default {
|
||||
const fullyConfiguredTeamsCount = computed(() => teams.value.filter(team => getMyTischtennisStatus(team).complete).length);
|
||||
const partiallyConfiguredTeamsCount = computed(() => teams.value.filter(team => getMyTischtennisStatus(team).partial).length);
|
||||
const teamsWithoutLeagueCount = computed(() => teams.value.filter(team => !team.leagueId).length);
|
||||
const totalSeasonAppearances = computed(() => playerStats.value.reduce((sum, stat) => sum + (Number(stat.totalSeason) || 0), 0));
|
||||
const totalHalfAppearances = computed(() => playerStats.value.reduce((sum, stat) => sum + (Number(isSecondHalf.value ? stat.totalSecondHalf : stat.totalFirstHalf) || 0), 0));
|
||||
const filteredTeams = computed(() => {
|
||||
const search = teamSearchQuery.value.trim().toLowerCase();
|
||||
return teams.value.filter(team => {
|
||||
@@ -980,6 +1107,12 @@ export default {
|
||||
doc.clubTeamId === teamId && doc.documentType === documentType
|
||||
);
|
||||
};
|
||||
|
||||
const getLatestTeamDocument = (teamId, documentType) => {
|
||||
return getTeamDocuments(teamId, documentType)
|
||||
.slice()
|
||||
.sort((a, b) => new Date(b.createdAt || 0) - new Date(a.createdAt || 0))[0] || null;
|
||||
};
|
||||
|
||||
const showPDFDialog = async (teamId, documentType) => {
|
||||
const documents = getTeamDocuments(teamId, documentType);
|
||||
@@ -1226,7 +1359,7 @@ export default {
|
||||
if (!hasLeague) missingItems.push(t('teamManagement.league'));
|
||||
if (hasLeague && !team.league.myTischtennisGroupId) missingItems.push(t('teamManagement.groupId'));
|
||||
if (hasLeague && !team.league.association) missingItems.push(t('teamManagement.association'));
|
||||
if (hasLeague && !team.league.groupName) missingItems.push(t('teamManagement.groupName'));
|
||||
if (hasLeague && !team.league.groupname) missingItems.push(t('teamManagement.groupName'));
|
||||
|
||||
const complete = hasTeamId && hasLeagueConfig;
|
||||
const partial = (hasTeamId || hasLeagueConfig) && !complete;
|
||||
@@ -1468,6 +1601,8 @@ export default {
|
||||
fullyConfiguredTeamsCount,
|
||||
partiallyConfiguredTeamsCount,
|
||||
teamsWithoutLeagueCount,
|
||||
totalSeasonAppearances,
|
||||
totalHalfAppearances,
|
||||
toggleNewTeam,
|
||||
resetToNewTeam,
|
||||
resetNewTeam,
|
||||
@@ -1480,6 +1615,7 @@ export default {
|
||||
loadAllTeamDocuments,
|
||||
parsePDF,
|
||||
getTeamDocuments,
|
||||
getLatestTeamDocument,
|
||||
showPDFDialog,
|
||||
closePDFDialog,
|
||||
formatDate,
|
||||
@@ -1504,6 +1640,57 @@ export default {
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.team-management-view {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 1rem;
|
||||
}
|
||||
|
||||
.team-management-hero {
|
||||
border: 1px solid var(--border-color);
|
||||
border-radius: var(--border-radius);
|
||||
background: var(--background-light);
|
||||
padding: 0.9rem;
|
||||
}
|
||||
|
||||
.team-management-hero-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
gap: 1rem;
|
||||
align-items: flex-start;
|
||||
flex-wrap: wrap;
|
||||
margin-bottom: 0.85rem;
|
||||
}
|
||||
|
||||
.team-management-hero-copy h2 {
|
||||
margin: 0 0 0.25rem;
|
||||
}
|
||||
|
||||
.team-management-hero-copy p {
|
||||
margin: 0;
|
||||
color: var(--text-muted);
|
||||
}
|
||||
|
||||
.team-management-hero-actions {
|
||||
display: flex;
|
||||
gap: 0.75rem;
|
||||
align-items: flex-start;
|
||||
}
|
||||
|
||||
.team-management-season-selector {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.3rem;
|
||||
}
|
||||
|
||||
.team-management-hero-label {
|
||||
font-size: 0.75rem;
|
||||
font-weight: 700;
|
||||
letter-spacing: 0.03em;
|
||||
text-transform: uppercase;
|
||||
color: var(--text-muted);
|
||||
}
|
||||
|
||||
.scheduler-jobs-summary {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
@@ -1528,12 +1715,27 @@ export default {
|
||||
}
|
||||
|
||||
.scheduler-jobs-toggle {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.35rem;
|
||||
min-width: 96px;
|
||||
padding: 0.4rem 0.75rem;
|
||||
border: 1px solid var(--border-color);
|
||||
border-radius: 999px;
|
||||
background: white;
|
||||
cursor: pointer;
|
||||
font-weight: 600;
|
||||
color: var(--text-color);
|
||||
line-height: 1;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.scheduler-jobs-toggle-icon {
|
||||
color: var(--text-muted);
|
||||
}
|
||||
|
||||
.scheduler-jobs-toggle-text {
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
.team-management-summary {
|
||||
@@ -1808,10 +2010,17 @@ export default {
|
||||
|
||||
.team-search-input {
|
||||
width: 100%;
|
||||
padding: 0.55rem 0.7rem;
|
||||
padding: 0.65rem 0.8rem;
|
||||
border: 1px solid var(--border-color);
|
||||
border-radius: 8px;
|
||||
background: white;
|
||||
border-radius: 10px;
|
||||
background: var(--surface-color);
|
||||
color: var(--text-color);
|
||||
}
|
||||
|
||||
.team-search-input:focus {
|
||||
outline: none;
|
||||
border-color: var(--primary-color);
|
||||
box-shadow: 0 0 0 3px rgba(47, 122, 95, 0.14);
|
||||
}
|
||||
|
||||
.team-filter-chips {
|
||||
@@ -1822,18 +2031,19 @@ export default {
|
||||
|
||||
.team-filter-chip {
|
||||
border: 1px solid var(--border-color);
|
||||
background: var(--background-light);
|
||||
background: var(--surface-muted);
|
||||
color: var(--text-color);
|
||||
border-radius: 999px;
|
||||
padding: 0.35rem 0.75rem;
|
||||
font-size: 0.85rem;
|
||||
cursor: pointer;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.team-filter-chip.active {
|
||||
background: var(--primary-light);
|
||||
border-color: var(--primary-color);
|
||||
color: var(--primary-dark);
|
||||
background: rgba(47, 122, 95, 0.12);
|
||||
border-color: var(--primary-soft);
|
||||
color: var(--primary-strong);
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
@@ -1896,6 +2106,11 @@ export default {
|
||||
color: var(--text-muted);
|
||||
}
|
||||
|
||||
.team-open-hint {
|
||||
font-size: 0.78rem;
|
||||
color: var(--primary-color);
|
||||
}
|
||||
|
||||
.team-actions {
|
||||
display: flex;
|
||||
gap: 0.5rem;
|
||||
@@ -1910,10 +2125,6 @@ export default {
|
||||
transition: var(--transition);
|
||||
}
|
||||
|
||||
.btn-edit:hover {
|
||||
background: var(--primary-light);
|
||||
}
|
||||
|
||||
.btn-delete:hover {
|
||||
background: #fee;
|
||||
}
|
||||
@@ -1938,7 +2149,114 @@ export default {
|
||||
line-height: 1.35;
|
||||
}
|
||||
|
||||
.workspace-panel-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
gap: 1rem;
|
||||
align-items: flex-start;
|
||||
margin-bottom: 0.9rem;
|
||||
}
|
||||
|
||||
.workspace-panel-copy {
|
||||
margin: 0.25rem 0 0;
|
||||
color: var(--text-muted);
|
||||
font-size: 0.92rem;
|
||||
}
|
||||
|
||||
.document-status-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
|
||||
gap: 0.9rem;
|
||||
}
|
||||
|
||||
.document-status-card,
|
||||
.mytt-status-card {
|
||||
border: 1px solid var(--border-color);
|
||||
border-radius: var(--border-radius);
|
||||
background: var(--background-light);
|
||||
padding: 0.9rem;
|
||||
}
|
||||
|
||||
.document-status-head,
|
||||
.mytt-status-line {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
gap: 0.75rem;
|
||||
align-items: flex-start;
|
||||
}
|
||||
|
||||
.document-status-badge {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.25rem;
|
||||
font-size: 0.8rem;
|
||||
font-weight: 600;
|
||||
padding: 0.22rem 0.55rem;
|
||||
border-radius: 999px;
|
||||
}
|
||||
|
||||
.document-status-badge.complete {
|
||||
background: #d9f5e3;
|
||||
color: #1f7a3f;
|
||||
}
|
||||
|
||||
.document-status-badge.missing {
|
||||
background: #fdeaea;
|
||||
color: #b23b3b;
|
||||
}
|
||||
|
||||
.document-status-meta,
|
||||
.mytt-status-copy {
|
||||
margin: 0.55rem 0 0;
|
||||
color: var(--text-muted);
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
.document-status-actions {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 0.55rem;
|
||||
margin-top: 0.8rem;
|
||||
}
|
||||
|
||||
.settings-summary-grid,
|
||||
.stats-summary-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
|
||||
gap: 0.75rem;
|
||||
margin-bottom: 0.9rem;
|
||||
}
|
||||
|
||||
.settings-summary-card {
|
||||
border: 1px solid var(--border-color);
|
||||
border-radius: var(--border-radius);
|
||||
background: var(--background-light);
|
||||
padding: 0.8rem 0.9rem;
|
||||
}
|
||||
|
||||
.settings-summary-label {
|
||||
display: block;
|
||||
font-size: 0.8rem;
|
||||
color: var(--text-muted);
|
||||
margin-bottom: 0.25rem;
|
||||
}
|
||||
|
||||
.settings-form-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
|
||||
gap: 0.9rem;
|
||||
}
|
||||
|
||||
.mytt-status-label {
|
||||
font-weight: 600;
|
||||
color: var(--text-color);
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.team-management-hero-header {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.scheduler-jobs-summary {
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
@@ -1993,17 +2311,17 @@ export default {
|
||||
.btn-upload-sm {
|
||||
padding: 4px 10px;
|
||||
font-size: 0.85rem;
|
||||
border: none;
|
||||
border-radius: 3px;
|
||||
font-weight: 500;
|
||||
border: 1px solid transparent;
|
||||
border-radius: 8px;
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
transition: var(--transition);
|
||||
background-color: #007bff;
|
||||
color: white;
|
||||
background: linear-gradient(135deg, var(--primary-color), var(--primary-hover));
|
||||
color: var(--text-on-primary);
|
||||
}
|
||||
|
||||
.btn-upload-sm:hover {
|
||||
background-color: #0056b3;
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
/* Legacy styles */
|
||||
@@ -2029,8 +2347,8 @@ export default {
|
||||
|
||||
.upload-btn {
|
||||
padding: 0.4rem 1rem;
|
||||
border: none;
|
||||
border-radius: var(--border-radius-small);
|
||||
border: 1px solid transparent;
|
||||
border-radius: 10px;
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
transition: var(--transition);
|
||||
@@ -2041,21 +2359,22 @@ export default {
|
||||
}
|
||||
|
||||
.code-list-btn {
|
||||
background: #4CAF50;
|
||||
color: white;
|
||||
background: linear-gradient(135deg, var(--primary-color), var(--primary-hover));
|
||||
color: var(--text-on-primary);
|
||||
}
|
||||
|
||||
.code-list-btn:hover {
|
||||
background: #45a049;
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
.pin-list-btn {
|
||||
background: #FF9800;
|
||||
color: white;
|
||||
background: rgba(181, 110, 65, 0.14);
|
||||
border-color: rgba(181, 110, 65, 0.24);
|
||||
color: #8a4f28;
|
||||
}
|
||||
|
||||
.pin-list-btn:hover {
|
||||
background: #e68900;
|
||||
background: rgba(181, 110, 65, 0.2);
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
@@ -2072,13 +2391,13 @@ export default {
|
||||
.upload-confirmation {
|
||||
margin-top: 0.75rem;
|
||||
padding: 0.75rem;
|
||||
background: #f8f9fa;
|
||||
background: var(--surface-muted);
|
||||
border-radius: var(--border-radius);
|
||||
border: 1px solid #dee2e6;
|
||||
border: 1px solid var(--border-color);
|
||||
}
|
||||
|
||||
.selected-file-info {
|
||||
background: #e9ecef;
|
||||
background: rgba(15, 23, 42, 0.05);
|
||||
padding: 0.5rem;
|
||||
border-radius: var(--border-radius-small);
|
||||
margin-bottom: 0.5rem;
|
||||
@@ -2094,11 +2413,11 @@ export default {
|
||||
|
||||
|
||||
.confirm-parse-btn {
|
||||
background: #4caf50;
|
||||
color: white;
|
||||
border: none;
|
||||
background: linear-gradient(135deg, var(--primary-color), var(--primary-hover));
|
||||
color: var(--text-on-primary);
|
||||
border: 1px solid transparent;
|
||||
padding: 0.4rem 1rem;
|
||||
border-radius: var(--border-radius-small);
|
||||
border-radius: 10px;
|
||||
font-size: 0.875rem;
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
@@ -2106,20 +2425,20 @@ export default {
|
||||
}
|
||||
|
||||
.confirm-parse-btn:hover:not(:disabled) {
|
||||
background: #45a049;
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
.confirm-parse-btn:disabled {
|
||||
background: #cccccc;
|
||||
cursor: not-allowed;
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
.cancel-parse-btn {
|
||||
background: #6c757d;
|
||||
color: white;
|
||||
border: none;
|
||||
background: var(--surface-color);
|
||||
color: var(--text-color);
|
||||
border: 1px solid var(--border-color);
|
||||
padding: 0.4rem 1rem;
|
||||
border-radius: var(--border-radius-small);
|
||||
border-radius: 10px;
|
||||
font-size: 0.875rem;
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
@@ -2127,7 +2446,8 @@ export default {
|
||||
}
|
||||
|
||||
.cancel-parse-btn:hover {
|
||||
background: #5a6268;
|
||||
background: var(--surface-muted);
|
||||
border-color: var(--primary-soft);
|
||||
}
|
||||
|
||||
.selected-file {
|
||||
@@ -2683,30 +3003,33 @@ export default {
|
||||
}
|
||||
|
||||
.status-badge {
|
||||
display: inline-block;
|
||||
padding: 0.25rem 0.75rem;
|
||||
border-radius: var(--border-radius-small);
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.3rem;
|
||||
padding: 0.28rem 0.78rem;
|
||||
border-radius: 999px;
|
||||
font-size: 0.85rem;
|
||||
font-weight: 600;
|
||||
white-space: nowrap;
|
||||
border: 1px solid transparent;
|
||||
}
|
||||
|
||||
.status-badge.complete {
|
||||
background: #e8f5e9;
|
||||
color: #2e7d32;
|
||||
border: 1px solid #4caf50;
|
||||
background: rgba(47, 122, 95, 0.12);
|
||||
color: #1f5f49;
|
||||
border-color: rgba(47, 122, 95, 0.24);
|
||||
}
|
||||
|
||||
.status-badge.partial {
|
||||
background: #fff3e0;
|
||||
color: #e65100;
|
||||
border: 1px solid #ff9800;
|
||||
background: rgba(181, 110, 65, 0.14);
|
||||
color: #8a4f28;
|
||||
border-color: rgba(181, 110, 65, 0.28);
|
||||
}
|
||||
|
||||
.status-badge.missing {
|
||||
background: #ffebee;
|
||||
color: #c62828;
|
||||
border: 1px solid #ef5350;
|
||||
background: rgba(200, 74, 56, 0.12);
|
||||
color: #8b3327;
|
||||
border-color: rgba(200, 74, 56, 0.24);
|
||||
}
|
||||
|
||||
.mytischtennis-status {
|
||||
|
||||
@@ -4700,7 +4700,7 @@ button {
|
||||
|
||||
/* Beendete Spiele */
|
||||
.match-finished-win {
|
||||
background-color: #28a745; /* Dunkelgrün */
|
||||
background-color: var(--primary-color);
|
||||
color: white;
|
||||
font-weight: bold;
|
||||
}
|
||||
@@ -4952,42 +4952,49 @@ button {
|
||||
min-width: 200px;
|
||||
max-width: 300px;
|
||||
padding: 0.4rem;
|
||||
border: 1px solid #ccc;
|
||||
border-radius: 4px;
|
||||
border: 1px solid var(--border-color);
|
||||
border-radius: 8px;
|
||||
background: var(--surface-color);
|
||||
color: var(--text-color);
|
||||
}
|
||||
|
||||
.btn-add {
|
||||
padding: 0.4rem 0.8rem;
|
||||
background-color: #007bff;
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
background: linear-gradient(135deg, var(--primary-color), var(--primary-hover));
|
||||
color: var(--text-on-primary);
|
||||
border: 1px solid transparent;
|
||||
border-radius: 10px;
|
||||
cursor: pointer;
|
||||
font-size: 0.9em;
|
||||
white-space: nowrap;
|
||||
font-weight: 600;
|
||||
transition: transform 0.2s ease, opacity 0.2s ease;
|
||||
}
|
||||
|
||||
.btn-add:hover {
|
||||
background-color: #0056b3;
|
||||
transform: translateY(-1px);
|
||||
opacity: 0.95;
|
||||
}
|
||||
|
||||
.training-btn {
|
||||
background-color: #28a745;
|
||||
color: white;
|
||||
border: none;
|
||||
background: linear-gradient(135deg, var(--primary-color), var(--primary-hover));
|
||||
color: var(--text-on-primary);
|
||||
border: 1px solid transparent;
|
||||
padding: 0.5rem 1rem;
|
||||
border-radius: 4px;
|
||||
border-radius: 10px;
|
||||
cursor: pointer;
|
||||
font-size: 0.9em;
|
||||
transition: background-color 0.2s ease;
|
||||
font-weight: 600;
|
||||
transition: transform 0.2s ease, opacity 0.2s ease;
|
||||
}
|
||||
|
||||
.training-btn:hover {
|
||||
background-color: #218838;
|
||||
transform: translateY(-1px);
|
||||
opacity: 0.95;
|
||||
}
|
||||
|
||||
.training-btn:active {
|
||||
background-color: #1e7e34;
|
||||
transform: translateY(0);
|
||||
}
|
||||
|
||||
.tournament-classes {
|
||||
@@ -5430,14 +5437,14 @@ tbody tr:hover:not(.active-match) {
|
||||
}
|
||||
|
||||
.btn-live.active {
|
||||
background-color: #28a745;
|
||||
border-color: #28a745;
|
||||
background-color: var(--primary-color);
|
||||
border-color: var(--primary-color);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.btn-live.active:hover {
|
||||
background-color: #218838;
|
||||
border-color: #1e7e34;
|
||||
background-color: var(--primary-hover);
|
||||
border-color: var(--primary-hover);
|
||||
}
|
||||
|
||||
/* Button für "Korrigieren" - weißer Hintergrund mit grüner Schrift */
|
||||
@@ -5446,8 +5453,8 @@ tbody tr:hover:not(.active-match) {
|
||||
background: white !important;
|
||||
background-color: white !important;
|
||||
background-image: none !important;
|
||||
color: #4CAF50 !important;
|
||||
border: 1px solid #4CAF50 !important;
|
||||
color: var(--primary-color) !important;
|
||||
border: 1px solid var(--primary-color) !important;
|
||||
padding: 0.25rem 0.5rem;
|
||||
font-size: 0.9em;
|
||||
border-radius: 3px;
|
||||
@@ -5467,8 +5474,8 @@ tbody tr:hover:not(.active-match) {
|
||||
background: #f8f9fa !important;
|
||||
background-color: #f8f9fa !important;
|
||||
background-image: none !important;
|
||||
border-color: #45a049 !important;
|
||||
color: #45a049 !important;
|
||||
border-color: var(--primary-hover) !important;
|
||||
color: var(--primary-hover) !important;
|
||||
transform: none !important;
|
||||
}
|
||||
.pairings-section {
|
||||
@@ -5560,7 +5567,7 @@ tbody tr:hover:not(.active-match) {
|
||||
}
|
||||
|
||||
.pairings-table thead {
|
||||
background-color: #28a745;
|
||||
background-color: var(--primary-color);
|
||||
color: white;
|
||||
}
|
||||
|
||||
@@ -5583,17 +5590,17 @@ tbody tr:hover:not(.active-match) {
|
||||
|
||||
.btn-random-pairings {
|
||||
padding: 0.5rem 1rem;
|
||||
background-color: #28a745;
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
background: linear-gradient(135deg, var(--primary-color), var(--primary-hover));
|
||||
color: var(--text-on-primary);
|
||||
border: 1px solid transparent;
|
||||
border-radius: 10px;
|
||||
cursor: pointer;
|
||||
font-size: 0.95em;
|
||||
font-weight: 500;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.btn-random-pairings:hover {
|
||||
background-color: #218838;
|
||||
opacity: 0.95;
|
||||
}
|
||||
|
||||
.btn-random-pairings:disabled {
|
||||
@@ -5609,17 +5616,17 @@ tbody tr:hover:not(.active-match) {
|
||||
|
||||
.btn-random-pairings {
|
||||
padding: 0.5rem 1rem;
|
||||
background-color: #28a745;
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
background: linear-gradient(135deg, var(--primary-color), var(--primary-hover));
|
||||
color: var(--text-on-primary);
|
||||
border: 1px solid transparent;
|
||||
border-radius: 10px;
|
||||
cursor: pointer;
|
||||
font-size: 0.95em;
|
||||
font-weight: 500;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.btn-random-pairings:hover {
|
||||
background-color: #218838;
|
||||
opacity: 0.95;
|
||||
}
|
||||
|
||||
.btn-random-pairings:disabled {
|
||||
|
||||
Reference in New Issue
Block a user