From a1e71006f0f09859358863318ef8f3a7f964ec5e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matej=20Glasn=C3=A1k?= Date: Tue, 2 Dec 2025 15:30:55 +0100 Subject: [PATCH 1/2] feat(datepicker): introduce ZDatepicker component for enhanced date selection functionality --- .../plugins/tm@_components/z-datepicker.vue | 331 ++++++++++++++++++ .../tm@modal/_mixins/vuetify-fix-focus.ts | 68 +++- .../master-task/z-master-task-modal.vue | 67 ++-- .../plugins/tm@modal/task/z-task-modal.vue | 69 +++- 4 files changed, 506 insertions(+), 29 deletions(-) create mode 100644 app/src/plugins/tm@_components/z-datepicker.vue diff --git a/app/src/plugins/tm@_components/z-datepicker.vue b/app/src/plugins/tm@_components/z-datepicker.vue new file mode 100644 index 0000000..c2e1573 --- /dev/null +++ b/app/src/plugins/tm@_components/z-datepicker.vue @@ -0,0 +1,331 @@ + + + + + diff --git a/app/src/plugins/tm@modal/_mixins/vuetify-fix-focus.ts b/app/src/plugins/tm@modal/_mixins/vuetify-fix-focus.ts index a3b544d..c48f2d3 100644 --- a/app/src/plugins/tm@modal/_mixins/vuetify-fix-focus.ts +++ b/app/src/plugins/tm@modal/_mixins/vuetify-fix-focus.ts @@ -9,9 +9,20 @@ export default { methods: { setFocusEvent() { - document.querySelectorAll('.v-autocomplete input').forEach((input) => { + const inputs = document.querySelectorAll('.v-autocomplete input'); + console.log( + '🟒 [VuetifyFixFocusMixin] setFocusEvent - Found', + inputs.length, + 'autocomplete inputs', + ); + inputs.forEach((input) => { input.addEventListener('focus', this.onInputFocus); }); + console.log( + '🟒 [VuetifyFixFocusMixin] Attached focus listeners to', + inputs.length, + 'inputs', + ); }, onDateFocus($event) { @@ -21,31 +32,69 @@ export default { }, onDateOpen($event) { + console.log( + '🟒 [VuetifyFixFocusMixin] onDateOpen called at:', + new Date().toISOString(), + 'with event:', + $event, + ); // $event should be the element reference (or any truthy value to trigger saving) if ($event) { // Find the scrollable modal container const modalContent = document.querySelector('.v-dialog .modal-content'); if (modalContent) { this.savedScrollPosition = modalContent.scrollTop; + console.log( + '🟒 [VuetifyFixFocusMixin] Saved scroll position:', + this.savedScrollPosition, + ); + } else { + console.log('🟒 [VuetifyFixFocusMixin] Modal content not found'); } this.preventInputFocus = true; + console.log( + '🟒 [VuetifyFixFocusMixin] preventInputFocus set to:', + this.preventInputFocus, + ); // Reset after datepicker is opened setTimeout(() => { this.preventInputFocus = false; this.savedScrollPosition = null; + console.log( + '🟒 [VuetifyFixFocusMixin] Reset preventInputFocus and savedScrollPosition after 500ms', + ); }, 500); } }, onInputFocus($event) { + const target = $event.target; + console.log('🟒 [VuetifyFixFocusMixin] onInputFocus triggered on:', { + tagName: target.tagName, + type: target.type, + id: target.id, + className: target.className, + preventInputFocus: this.preventInputFocus, + savedScrollPosition: this.savedScrollPosition, + }); + // If we have a saved scroll position and an unwanted focus happened if (this.preventInputFocus && this.savedScrollPosition !== null) { const target = $event.target; // Only intercept text input focus (autocomplete fields) if (target.tagName === 'INPUT' && target.type === 'text') { + console.log('🟒 [VuetifyFixFocusMixin] PREVENTING FOCUS on:', target); + const scrollBefore = document.querySelector( + '.v-dialog .modal-content', + )?.scrollTop; + console.log( + '🟒 [VuetifyFixFocusMixin] Scroll position before:', + scrollBefore, + ); + // Blur the focused element setTimeout(() => { target.blur(); @@ -55,9 +104,26 @@ export default { ); if (modalContent && this.savedScrollPosition !== null) { modalContent.scrollTop = this.savedScrollPosition; + const scrollAfter = modalContent.scrollTop; + console.log( + '🟒 [VuetifyFixFocusMixin] Scroll position restored to:', + scrollAfter, + ); } }, 0); + } else { + console.log( + '🟒 [VuetifyFixFocusMixin] Not a text input, skipping prevention', + ); } + } else { + console.log( + '🟒 [VuetifyFixFocusMixin] Focus allowed (preventInputFocus:', + this.preventInputFocus, + ', savedScrollPosition:', + this.savedScrollPosition, + ')', + ); } }, }, diff --git a/app/src/plugins/tm@modal/master-task/z-master-task-modal.vue b/app/src/plugins/tm@modal/master-task/z-master-task-modal.vue index e0f4425..093018e 100644 --- a/app/src/plugins/tm@modal/master-task/z-master-task-modal.vue +++ b/app/src/plugins/tm@modal/master-task/z-master-task-modal.vue @@ -57,24 +57,22 @@
-
- +
@@ -118,7 +116,7 @@ class="modal-input" variant="solo" type="number" - :label="`${mastertask.duration} h`" + label="NaplΓ‘novanΓ© hodiny" :disabled="true" > @@ -312,7 +310,7 @@