feat(match-report): implement floating keyboard for set input in MatchReportApiDialog
- Added a floating keyboard overlay for set input, allowing users to enter scores without using the system keyboard. - Updated input fields to be read-only and disabled system keyboard interactions, enhancing user experience. - Implemented methods to manage keyboard interactions, including key input, backspace, and confirmation actions. - Improved styling for the floating keyboard to ensure clarity and usability during score entry.
This commit is contained in:
@@ -386,27 +386,13 @@
|
||||
<div class="set-input-wrapper">
|
||||
<input
|
||||
class="set-input"
|
||||
:class="{ 'gap-warning': shouldHighlightSetInput(idx, sIdx) }"
|
||||
:class="{ 'gap-warning': shouldHighlightSetInput(idx, sIdx), 'keyboard-open': isSetKeyboardOpen(idx, sIdx) }"
|
||||
v-model="m.sets[sIdx]"
|
||||
placeholder=":"
|
||||
:readonly="true"
|
||||
:disabled="isSetInputDisabled(idx, sIdx)"
|
||||
inputmode="numeric"
|
||||
pattern="[0-9:\-]*"
|
||||
@keyup.enter="processScoreInput(idx, sIdx)"
|
||||
@blur="processScoreInput(idx, sIdx)"
|
||||
@click="openSetKeyboard(idx, sIdx)"
|
||||
/>
|
||||
<div class="set-extra-buttons">
|
||||
<button
|
||||
type="button"
|
||||
class="set-extra-btn"
|
||||
@click="appendToSet(idx, sIdx, ':')"
|
||||
>:</button>
|
||||
<button
|
||||
type="button"
|
||||
class="set-extra-btn"
|
||||
@click="appendToSet(idx, sIdx, '-')"
|
||||
>-</button>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
<td class="state-cell">
|
||||
@@ -455,6 +441,23 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Schwebende Tastatur für Satzeingabe (unterdrückt System-Tastatur) -->
|
||||
<div v-if="editingSetCell" class="set-keyboard-overlay" @click.self="closeSetKeyboard">
|
||||
<div class="set-keyboard" @click.stop>
|
||||
<div class="set-keyboard-value" :class="{ 'placeholder': !editingSetValue }">
|
||||
{{ editingSetValue || 'Satz z.B. 11:9' }}
|
||||
</div>
|
||||
<div class="set-keyboard-keys">
|
||||
<button type="button" v-for="n in 9" :key="n" class="set-key" @click="setKeyboardKey(String(n))">{{ n }}</button>
|
||||
<button type="button" class="set-key" @click="setKeyboardKey(':')">:</button>
|
||||
<button type="button" class="set-key" @click="setKeyboardKey('0')">0</button>
|
||||
<button type="button" class="set-key" @click="setKeyboardKey('-')">−</button>
|
||||
<button type="button" class="set-key set-key-backspace" @click="setKeyboardBackspace">⌫</button>
|
||||
<button type="button" class="set-key set-key-ok" @click="setKeyboardOk">OK</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-else-if="activeSection === 'completion'" class="completion-content">
|
||||
@@ -713,6 +716,8 @@ export default {
|
||||
results: [],
|
||||
// Fehlermeldungen für Satzeingaben
|
||||
errors: [],
|
||||
// Aktive Zelle der schwebenden Satz-Tastatur: { matchIndex, setIndex } oder null
|
||||
editingSetCell: null,
|
||||
// Abschluss-Felder
|
||||
protestText: '',
|
||||
finalHomePin: '',
|
||||
@@ -788,6 +793,11 @@ Wir wünschen den Spielen einen schönen, spannenden und fairen Verlauf und begr
|
||||
.trim();
|
||||
return norm(this.meetingData.league) === norm(this.meetingData.group);
|
||||
},
|
||||
editingSetValue() {
|
||||
if (!this.editingSetCell || !this.results[this.editingSetCell.matchIndex]) return '';
|
||||
const sets = this.results[this.editingSetCell.matchIndex].sets || [];
|
||||
return sets[this.editingSetCell.setIndex] || '';
|
||||
},
|
||||
canOpenNextStages() {
|
||||
// Wenn das Match bereits abgeschlossen ist, dürfen keine Änderungen mehr gemacht werden
|
||||
if (this.isMatchCompleted) {
|
||||
@@ -2144,6 +2154,38 @@ Wir wünschen den Spielen einen schönen, spannenden und fairen Verlauf und begr
|
||||
}
|
||||
this.results[matchIndex].sets[setIndex] = current + char;
|
||||
},
|
||||
|
||||
isSetKeyboardOpen(matchIndex, setIndex) {
|
||||
return this.editingSetCell && this.editingSetCell.matchIndex === matchIndex && this.editingSetCell.setIndex === setIndex;
|
||||
},
|
||||
openSetKeyboard(matchIndex, setIndex) {
|
||||
if (this.isSetInputDisabled(matchIndex, setIndex)) return;
|
||||
this.editingSetCell = { matchIndex, setIndex };
|
||||
},
|
||||
closeSetKeyboard() {
|
||||
this.editingSetCell = null;
|
||||
},
|
||||
setKeyboardKey(char) {
|
||||
if (!this.editingSetCell || !this.results[this.editingSetCell.matchIndex]) return;
|
||||
const { matchIndex, setIndex } = this.editingSetCell;
|
||||
const sets = this.results[matchIndex].sets || [];
|
||||
const current = sets[setIndex] || '';
|
||||
if (current.length >= 6) return;
|
||||
this.results[matchIndex].sets[setIndex] = current + char;
|
||||
},
|
||||
setKeyboardBackspace() {
|
||||
if (!this.editingSetCell || !this.results[this.editingSetCell.matchIndex]) return;
|
||||
const { matchIndex, setIndex } = this.editingSetCell;
|
||||
const sets = this.results[matchIndex].sets || [];
|
||||
const current = sets[setIndex] || '';
|
||||
this.results[matchIndex].sets[setIndex] = current.slice(0, -1);
|
||||
},
|
||||
setKeyboardOk() {
|
||||
if (!this.editingSetCell) return;
|
||||
const { matchIndex, setIndex } = this.editingSetCell;
|
||||
this.processScoreInput(matchIndex, setIndex);
|
||||
this.closeSetKeyboard();
|
||||
},
|
||||
reopenMatch(idx) {
|
||||
const m = this.results[idx];
|
||||
m.completed = false;
|
||||
@@ -3762,6 +3804,78 @@ Wir wünschen den Spielen einen schönen, spannenden und fairen Verlauf und begr
|
||||
background-color: #f0f0f0;
|
||||
}
|
||||
|
||||
/* Schwebende Satz-Tastatur (ersetzt System-Tastatur) */
|
||||
.set-keyboard-overlay {
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
background: rgba(0, 0, 0, 0.4);
|
||||
display: flex;
|
||||
align-items: flex-end;
|
||||
justify-content: center;
|
||||
z-index: 10000;
|
||||
padding: 0;
|
||||
}
|
||||
.set-keyboard {
|
||||
background: #f0f0f0;
|
||||
border-radius: 12px 12px 0 0;
|
||||
padding: 12px;
|
||||
padding-bottom: max(12px, env(safe-area-inset-bottom));
|
||||
box-shadow: 0 -4px 20px rgba(0, 0, 0, 0.2);
|
||||
width: 100%;
|
||||
max-width: 360px;
|
||||
}
|
||||
.set-keyboard-value {
|
||||
text-align: center;
|
||||
font-size: 1.25rem;
|
||||
font-family: monospace;
|
||||
padding: 10px 12px;
|
||||
margin-bottom: 10px;
|
||||
background: #fff;
|
||||
border: 1px solid #ccc;
|
||||
border-radius: 8px;
|
||||
min-height: 44px;
|
||||
line-height: 1.4;
|
||||
}
|
||||
.set-keyboard-value.placeholder {
|
||||
color: #999;
|
||||
}
|
||||
.set-keyboard-keys {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(4, 1fr);
|
||||
gap: 8px;
|
||||
}
|
||||
.set-key {
|
||||
min-height: 48px;
|
||||
font-size: 1.25rem;
|
||||
border: 1px solid #bbb;
|
||||
border-radius: 8px;
|
||||
background: #fff;
|
||||
cursor: pointer;
|
||||
font-family: inherit;
|
||||
-webkit-tap-highlight-color: transparent;
|
||||
touch-action: manipulation;
|
||||
}
|
||||
.set-key:active {
|
||||
background: #e0e0e0;
|
||||
}
|
||||
.set-key-backspace {
|
||||
font-size: 1.1rem;
|
||||
}
|
||||
.set-key-ok {
|
||||
grid-column: span 2;
|
||||
background: var(--primary-color, #1976d2);
|
||||
color: #fff;
|
||||
border-color: var(--primary-hover, #1565c0);
|
||||
font-weight: 600;
|
||||
}
|
||||
.set-key-ok:active {
|
||||
opacity: 0.9;
|
||||
}
|
||||
.set-input.keyboard-open {
|
||||
border-color: var(--primary-color);
|
||||
box-shadow: 0 0 0 2px rgba(var(--primary-rgb, 25, 118, 210), 0.3);
|
||||
}
|
||||
|
||||
/* Mobile-spezifische Optimierungen */
|
||||
@media (max-width: 768px) {
|
||||
.set-input {
|
||||
@@ -3769,14 +3883,9 @@ Wir wünschen den Spielen einen schönen, spannenden und fairen Verlauf und begr
|
||||
padding: 8px;
|
||||
font-size: 16px; /* Verhindert Zoom auf iOS */
|
||||
-webkit-appearance: none;
|
||||
appearance: none;
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
.set-extra-buttons {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 2px;
|
||||
}
|
||||
}
|
||||
.state-cell { text-align: center; }
|
||||
.state-content { display: flex; flex-direction: row; align-items: center; gap: 8px; }
|
||||
|
||||
Reference in New Issue
Block a user