diff --git a/app/src/plugins/app/_theme/_components/modals.sass b/app/src/plugins/app/_theme/_components/modals.sass
index a31a814..d1b0f25 100644
--- a/app/src/plugins/app/_theme/_components/modals.sass
+++ b/app/src/plugins/app/_theme/_components/modals.sass
@@ -37,7 +37,7 @@
justify-content: space-between
.left
- width: 70% !important
+ width: calc(75% - 15px) !important
.right
- width: 25% !important
\ No newline at end of file
+ width: calc(25% - 15px) !important
\ No newline at end of file
diff --git a/app/src/plugins/tm@modal/_components/a-close-button.vue b/app/src/plugins/tm@modal/_components/a-close-button.vue
new file mode 100644
index 0000000..3134360
--- /dev/null
+++ b/app/src/plugins/tm@modal/_components/a-close-button.vue
@@ -0,0 +1,37 @@
+
+
+
+
+ Close
+
+
+
+
+
+
+
+
diff --git a/app/src/plugins/tm@modal/_components/a-reset-size-button.vue b/app/src/plugins/tm@modal/_components/a-reset-size-button.vue
new file mode 100644
index 0000000..05ca165
--- /dev/null
+++ b/app/src/plugins/tm@modal/_components/a-reset-size-button.vue
@@ -0,0 +1,41 @@
+
+
+
+
+ Reset modal size
+
+
+
+
+
+
+
+
diff --git a/app/src/plugins/tm@modal/_components/a-resize-handle.vue b/app/src/plugins/tm@modal/_components/a-resize-handle.vue
new file mode 100644
index 0000000..78efeb6
--- /dev/null
+++ b/app/src/plugins/tm@modal/_components/a-resize-handle.vue
@@ -0,0 +1,166 @@
+
+
+
+
+
+
+
+
+
diff --git a/app/src/plugins/tm@modal/_mixins/modal.mixin.ts b/app/src/plugins/tm@modal/_mixins/modal.mixin.ts
index 4850377..19a78d0 100644
--- a/app/src/plugins/tm@modal/_mixins/modal.mixin.ts
+++ b/app/src/plugins/tm@modal/_mixins/modal.mixin.ts
@@ -1,12 +1,107 @@
+import modalResizeUtils from '@/plugins/tm@modal/_utils/modal-resize.utils'
+
export default {
+ data() {
+ return {
+ modalWidth: '100%',
+ modalHeight: '100%',
+ modalName: '' // Should be set by component
+ }
+ },
+
+ computed: {
+ modalWidthPx() {
+ return this.modalWidth
+ },
+ modalHeightPx() {
+ return this.modalHeight
+ }
+ },
+
mounted() {
window.addEventListener('keydown', this.handleKeyDown)
+ window.addEventListener('resize', this.handleWindowResize)
+ this.initModalSize()
+ },
+
+ beforeUnmount() {
+ window.removeEventListener('keydown', this.handleKeyDown)
+ window.removeEventListener('resize', this.handleWindowResize)
},
methods: {
handleKeyDown(event) {
// if (event.keyCode === 27) this.closeModal()
if (event.keyCode === 27) this.visible = false
+ },
+
+ /**
+ * Initialize modal size from localStorage or defaults
+ */
+ initModalSize() {
+ if (!this.modalName) {
+ console.warn('Modal name not set for resize functionality')
+ return
+ }
+
+ const size = modalResizeUtils.getModalSize(this.modalName)
+ this.modalWidth = typeof size.width === 'number' ? `${size.width}px` : size.width
+ this.modalHeight = typeof size.height === 'number' ? `${size.height}px` : size.height
+ },
+
+ /**
+ * Handle window resize - adjust modal if on mobile
+ */
+ handleWindowResize() {
+ if (modalResizeUtils.isMobile()) {
+ this.modalWidth = '100%'
+ this.modalHeight = '100%'
+ } else {
+ // Reload stored or default size on desktop
+ this.initModalSize()
+ }
+ },
+
+ /**
+ * Handle modal resize from resize handle
+ */
+ handleModalResize({ width, height }) {
+ if (modalResizeUtils.isMobile()) {
+ return // Don't resize on mobile
+ }
+
+ const constrained = modalResizeUtils.constrainSize(width, height)
+ this.modalWidth = `${constrained.width}px`
+ this.modalHeight = `${constrained.height}px`
+ },
+
+ /**
+ * Handle resize end - save to localStorage
+ */
+ handleResizeEnd() {
+ if (!this.modalName || modalResizeUtils.isMobile()) {
+ return
+ }
+
+ // Parse current dimensions
+ const width = parseFloat(this.modalWidth)
+ const height = parseFloat(this.modalHeight)
+
+ if (!isNaN(width) && !isNaN(height)) {
+ modalResizeUtils.saveSize(this.modalName, width, height)
+ }
+ },
+
+ /**
+ * Reset modal size to defaults
+ */
+ resetModalSize() {
+ if (!this.modalName) {
+ return
+ }
+
+ modalResizeUtils.resetSize(this.modalName)
+ this.initModalSize()
}
- },
+ }
}
\ No newline at end of file
diff --git a/app/src/plugins/tm@modal/_utils/modal-resize.utils.ts b/app/src/plugins/tm@modal/_utils/modal-resize.utils.ts
new file mode 100644
index 0000000..a5335ac
--- /dev/null
+++ b/app/src/plugins/tm@modal/_utils/modal-resize.utils.ts
@@ -0,0 +1,162 @@
+interface ModalSize {
+ width: string | number
+ height: string | number
+}
+
+interface StoredModalSize {
+ width: number
+ height: number
+ timestamp: number
+}
+
+const MOBILE_BREAKPOINT = 768
+const DEFAULT_DESKTOP_WIDTH_PERCENT = 80
+const DEFAULT_DESKTOP_MAX_WIDTH = 1440
+const DEFAULT_DESKTOP_HEIGHT_PERCENT = 90
+
+export default {
+ /**
+ * Check if the current viewport is mobile
+ */
+ isMobile(): boolean {
+ return window.innerWidth <= MOBILE_BREAKPOINT
+ },
+
+ /**
+ * Get default modal size based on viewport
+ */
+ getDefaultSize(): ModalSize {
+ if (this.isMobile()) {
+ return {
+ width: '100%',
+ height: '100%'
+ }
+ }
+
+ const viewportWidth = window.innerWidth
+ const calculatedWidth = Math.min(
+ (viewportWidth * DEFAULT_DESKTOP_WIDTH_PERCENT) / 100,
+ DEFAULT_DESKTOP_MAX_WIDTH
+ )
+ const calculatedHeight = (window.innerHeight * DEFAULT_DESKTOP_HEIGHT_PERCENT) / 100
+
+ return {
+ width: calculatedWidth,
+ height: calculatedHeight
+ }
+ },
+
+ /**
+ * Get stored modal size from localStorage
+ */
+ getStoredSize(modalName: string): ModalSize | null {
+ try {
+ const key = `modal-size-${modalName}`
+ const stored = localStorage.getItem(key)
+
+ if (!stored) {
+ return null
+ }
+
+ const parsed: StoredModalSize = JSON.parse(stored)
+
+ // Return stored size if it exists and is valid
+ if (parsed && typeof parsed.width === 'number' && typeof parsed.height === 'number') {
+ return {
+ width: parsed.width,
+ height: parsed.height
+ }
+ }
+
+ return null
+ } catch (error) {
+ console.error('Error reading stored modal size:', error)
+ return null
+ }
+ },
+
+ /**
+ * Save modal size to localStorage
+ */
+ saveSize(modalName: string, width: number, height: number): void {
+ try {
+ const key = `modal-size-${modalName}`
+ const data: StoredModalSize = {
+ width,
+ height,
+ timestamp: Date.now()
+ }
+ localStorage.setItem(key, JSON.stringify(data))
+ } catch (error) {
+ console.error('Error saving modal size:', error)
+ }
+ },
+
+ /**
+ * Reset modal size (clear from localStorage)
+ */
+ resetSize(modalName: string): void {
+ try {
+ const key = `modal-size-${modalName}`
+ localStorage.removeItem(key)
+ } catch (error) {
+ console.error('Error resetting modal size:', error)
+ }
+ },
+
+ /**
+ * Get modal size (stored or default)
+ */
+ getModalSize(modalName: string): ModalSize {
+ // On mobile, always return 100%
+ if (this.isMobile()) {
+ return {
+ width: '100%',
+ height: '100%'
+ }
+ }
+
+ // Check for stored size
+ const storedSize = this.getStoredSize(modalName)
+ if (storedSize) {
+ return storedSize
+ }
+
+ // Return default size
+ return this.getDefaultSize()
+ },
+
+ /**
+ * Convert size to pixels if percentage, otherwise return as is
+ */
+ normalizeSize(size: string | number): number {
+ if (typeof size === 'number') {
+ return size
+ }
+
+ // If it's a percentage, calculate pixel value
+ if (size.includes('%')) {
+ const percent = parseFloat(size)
+ return (window.innerWidth * percent) / 100
+ }
+
+ // If it's already pixels, parse it
+ return parseFloat(size)
+ },
+
+ /**
+ * Constrain size within reasonable bounds
+ */
+ constrainSize(width: number, height: number): { width: number; height: number } {
+ const minWidth = 400
+ const minHeight = 300
+ const maxWidth = window.innerWidth
+ const maxHeight = window.innerHeight
+
+ return {
+ width: Math.max(minWidth, Math.min(width, maxWidth)),
+ height: Math.max(minHeight, Math.min(height, maxHeight))
+ }
+ }
+}
+
diff --git a/app/src/plugins/tm@modal/blocker/z-blocker-modal.vue b/app/src/plugins/tm@modal/blocker/z-blocker-modal.vue
index 9b04962..cd0b535 100644
--- a/app/src/plugins/tm@modal/blocker/z-blocker-modal.vue
+++ b/app/src/plugins/tm@modal/blocker/z-blocker-modal.vue
@@ -1,10 +1,13 @@
-
+
-
+
@@ -30,6 +33,7 @@
{{ blocker.id ? "UPRAVIŤ" : "VYTVORIŤ" }}
+
@@ -45,6 +49,9 @@ import { mapGetters } from "vuex"
import moment from "moment"
import AutocompleteMixin from '@/plugins/tm@_mixins/autocomplete.mixin'
import modalMixin from '@/plugins/tm@modal/_mixins/modal.mixin'
+import AResizeHandle from '@/plugins/tm@modal/_components/a-resize-handle.vue'
+import AResetSizeButton from '@/plugins/tm@modal/_components/a-reset-size-button.vue'
+import ACloseButton from '@/plugins/tm@modal/_components/a-close-button.vue'
export default {
mixins: [VuetifyFixFocusMixin, AutocompleteMixin, modalMixin],
@@ -54,6 +61,8 @@ export default {
components: {
Datepicker,
// ZAutocomplete
+ AResizeHandle,
+ AResetSizeButton, ACloseButton,
},
data() {
@@ -65,7 +74,8 @@ export default {
datepicker: null,
starts_at_time: null,
ends_at_time: null,
- employee: null
+ employee: null,
+ modalName: 'z-blocker-modal',
}
},
diff --git a/app/src/plugins/tm@modal/blocker/z-delete-blocker-modal.vue b/app/src/plugins/tm@modal/blocker/z-delete-blocker-modal.vue
index 4eb39af..6488433 100644
--- a/app/src/plugins/tm@modal/blocker/z-delete-blocker-modal.vue
+++ b/app/src/plugins/tm@modal/blocker/z-delete-blocker-modal.vue
@@ -1,36 +1,44 @@
-
-
+
+
Ste si istý, že chcete zmazať {{ blocker.name }}?
-
+
ÁNO
ZRUŠIŤ
+