From fdb44524473a9570e9451e519eba5ef6970beefc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matej=20Glasn=C3=A1k?= Date: Wed, 14 Jan 2026 06:25:43 +0100 Subject: [PATCH] feat(timeline): add visual indication for timeblocks outside working hours --- app/dist/js/index.js | 6 ++-- .../a-employee-timeblock-timeline.vue | 32 ++++++++++++++++++- 2 files changed, 34 insertions(+), 4 deletions(-) diff --git a/app/dist/js/index.js b/app/dist/js/index.js index 08db615..6010e2b 100644 --- a/app/dist/js/index.js +++ b/app/dist/js/index.js @@ -840,7 +840,7 @@ eval("{__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _no /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; -eval("{__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _node_modules_css_loader_dist_runtime_noSourceMaps_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../../../../../../node_modules/css-loader/dist/runtime/noSourceMaps.js */ \"./node_modules/css-loader/dist/runtime/noSourceMaps.js\");\n/* harmony import */ var _node_modules_css_loader_dist_runtime_noSourceMaps_js__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_node_modules_css_loader_dist_runtime_noSourceMaps_js__WEBPACK_IMPORTED_MODULE_0__);\n/* harmony import */ var _node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../../../../../../node_modules/css-loader/dist/runtime/api.js */ \"./node_modules/css-loader/dist/runtime/api.js\");\n/* harmony import */ var _node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(_node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_1__);\n// Imports\n\n\nvar ___CSS_LOADER_EXPORT___ = _node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_1___default()((_node_modules_css_loader_dist_runtime_noSourceMaps_js__WEBPACK_IMPORTED_MODULE_0___default()));\n// Module\n___CSS_LOADER_EXPORT___.push([module.id, \".timeline-scroll[data-v-5ca7dec4] {\\n overflow-x: auto;\\n overflow-y: hidden;\\n position: relative;\\n width: 100%;\\n scrollbar-width: none;\\n cursor: crosshair;\\n}\\n.timeline-scroll[data-v-5ca7dec4]::-webkit-scrollbar {\\n display: none;\\n}\\n.timeline-bar[data-v-5ca7dec4] {\\n position: relative;\\n height: 30px;\\n width: 1440px;\\n background: #fafafa;\\n border-radius: 4px;\\n}\\n@media (max-width: 768px) {\\n.timeline-bar[data-v-5ca7dec4] {\\n width: 1200px;\\n}\\n}\\n.non-working-hours[data-v-5ca7dec4] {\\n position: absolute;\\n top: 0;\\n height: 100%;\\n background: repeating-linear-gradient(45deg, transparent, transparent 10px, rgba(224, 224, 224, 0.3) 10px, rgba(224, 224, 224, 0.3) 20px);\\n z-index: 1;\\n pointer-events: none;\\n}\\n.work-hours-bar[data-v-5ca7dec4] {\\n position: absolute;\\n top: 0;\\n height: 100%;\\n background: transparent;\\n z-index: 1;\\n pointer-events: none;\\n}\\n.weekend-overlay[data-v-5ca7dec4] {\\n position: absolute;\\n top: 0;\\n left: 0;\\n width: 100%;\\n height: 100%;\\n background: rgba(255, 124, 124, 0.3) !important;\\n z-index: 1;\\n pointer-events: none;\\n border-radius: 4px;\\n}\\n.scheduled-block[data-v-5ca7dec4] {\\n position: absolute;\\n top: 5px;\\n height: 22px;\\n background: #7f39fb;\\n border: 1px solid #6a1bf7;\\n opacity: 0.6;\\n border-radius: 2px;\\n z-index: 2;\\n pointer-events: none;\\n}\\n.scheduled-block--blocker[data-v-5ca7dec4] {\\n background: rgb(176, 0, 32);\\n border: 1px solid rgb(156, 0, 28);\\n opacity: 0.7;\\n}\\n.other-timeblock[data-v-5ca7dec4] {\\n position: absolute;\\n top: 5px;\\n height: 22px;\\n background: #FFA726;\\n opacity: 0.5;\\n border: 2px dashed #FF9800;\\n border-radius: 2px;\\n z-index: 2;\\n pointer-events: none;\\n}\\n.preview-block[data-v-5ca7dec4] {\\n position: absolute;\\n top: 5px;\\n height: 22px;\\n background: #4CAF50;\\n opacity: 0.6;\\n border: 2px dashed #388E3C;\\n border-radius: 2px;\\n z-index: 5;\\n cursor: crosshair;\\n transition: opacity 0.2s, box-shadow 0.2s;\\n display: flex;\\n align-items: center;\\n justify-content: center;\\n pointer-events: none;\\n}\\n.preview-block[data-v-5ca7dec4]:hover {\\n opacity: 0.8;\\n box-shadow: 0 2px 8px rgba(76, 175, 80, 0.4);\\n}\\n.preview-block.is-stretching[data-v-5ca7dec4] {\\n opacity: 0.8;\\n box-shadow: 0 4px 12px rgba(76, 175, 80, 0.6);\\n cursor: ew-resize;\\n}\\n.preview-time-label[data-v-5ca7dec4] {\\n font-size: 11px;\\n font-weight: 600;\\n color: white;\\n text-shadow: 0 1px 2px rgba(0, 0, 0, 0.5);\\n white-space: nowrap;\\n pointer-events: none;\\n -webkit-user-select: none;\\n -moz-user-select: none;\\n user-select: none;\\n}\\n.current-timeblock[data-v-5ca7dec4] {\\n position: absolute;\\n top: 5px;\\n height: 22px;\\n background: #2196F3;\\n opacity: 0.7;\\n border: 2px solid #1976D2;\\n border-radius: 2px;\\n z-index: 3;\\n transition: box-shadow 0.2s;\\n}\\n.current-timeblock.has-collision[data-v-5ca7dec4] {\\n border-color: #ff5252;\\n}\\n.current-timeblock.is-resizing[data-v-5ca7dec4] {\\n opacity: 0.8;\\n box-shadow: 0 4px 12px rgba(33, 150, 243, 0.6);\\n z-index: 6;\\n}\\n.resize-handle[data-v-5ca7dec4] {\\n position: absolute;\\n top: 0;\\n width: 8px;\\n height: 100%;\\n cursor: ew-resize;\\n z-index: 4;\\n}\\n.resize-handle[data-v-5ca7dec4]:hover {\\n background: rgba(255, 255, 255, 0.3);\\n}\\n.resize-handle--left[data-v-5ca7dec4] {\\n left: 0;\\n border-top-left-radius: 2px;\\n border-bottom-left-radius: 2px;\\n}\\n.resize-handle--right[data-v-5ca7dec4] {\\n right: 0;\\n border-top-right-radius: 2px;\\n border-bottom-right-radius: 2px;\\n}\\n.collision-segment[data-v-5ca7dec4] {\\n position: absolute;\\n top: 5px;\\n height: 22px;\\n background: #ff5252;\\n opacity: 0.6;\\n border-radius: 2px;\\n z-index: 4;\\n pointer-events: none;\\n}\\n.timeline-cursor[data-v-5ca7dec4] {\\n position: absolute;\\n top: 0;\\n bottom: 0;\\n width: 2px;\\n background: rgba(0, 0, 0, 0.3);\\n z-index: 10;\\n pointer-events: none;\\n}\\n.timeblock-duration[data-v-5ca7dec4] {\\n position: absolute;\\n top: 50%;\\n left: 50%;\\n transform: translate(-50%, -50%);\\n font-size: 14px;\\n font-weight: bold;\\n color: white;\\n text-shadow: 0 1px 2px rgba(0, 0, 0, 0.3);\\n pointer-events: none;\\n -webkit-user-select: none;\\n -moz-user-select: none;\\n user-select: none;\\n}\\n.timeline-loading[data-v-5ca7dec4] {\\n height: 60px;\\n display: flex;\\n align-items: center;\\n justify-content: center;\\n font-size: 14px;\\n opacity: 0.5;\\n}\", \"\"]);\n// Exports\n/* harmony default export */ __webpack_exports__[\"default\"] = (___CSS_LOADER_EXPORT___);\n\n\n//# sourceURL=webpack://jandl/./src/plugins/tm@modal/task/_components/employees/a-employee-timeblock-timeline.vue?./node_modules/css-loader/dist/cjs.js??clonedRuleSet-27.use%5B1%5D!./node_modules/vue-loader/dist/stylePostLoader.js!./node_modules/postcss-loader/dist/cjs.js??clonedRuleSet-27.use%5B2%5D!./node_modules/sass-loader/dist/cjs.js??clonedRuleSet-27.use%5B3%5D!./node_modules/vue-loader/dist/index.js??ruleSet%5B0%5D.use%5B0%5D\n}"); +eval("{__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _node_modules_css_loader_dist_runtime_noSourceMaps_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../../../../../../node_modules/css-loader/dist/runtime/noSourceMaps.js */ \"./node_modules/css-loader/dist/runtime/noSourceMaps.js\");\n/* harmony import */ var _node_modules_css_loader_dist_runtime_noSourceMaps_js__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_node_modules_css_loader_dist_runtime_noSourceMaps_js__WEBPACK_IMPORTED_MODULE_0__);\n/* harmony import */ var _node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../../../../../../node_modules/css-loader/dist/runtime/api.js */ \"./node_modules/css-loader/dist/runtime/api.js\");\n/* harmony import */ var _node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(_node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_1__);\n// Imports\n\n\nvar ___CSS_LOADER_EXPORT___ = _node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_1___default()((_node_modules_css_loader_dist_runtime_noSourceMaps_js__WEBPACK_IMPORTED_MODULE_0___default()));\n// Module\n___CSS_LOADER_EXPORT___.push([module.id, \".timeline-scroll[data-v-5ca7dec4] {\\n overflow-x: auto;\\n overflow-y: hidden;\\n position: relative;\\n width: 100%;\\n scrollbar-width: none;\\n cursor: crosshair;\\n}\\n.timeline-scroll[data-v-5ca7dec4]::-webkit-scrollbar {\\n display: none;\\n}\\n.timeline-bar[data-v-5ca7dec4] {\\n position: relative;\\n height: 30px;\\n width: 1440px;\\n background: #fafafa;\\n border-radius: 4px;\\n}\\n@media (max-width: 768px) {\\n.timeline-bar[data-v-5ca7dec4] {\\n width: 1200px;\\n}\\n}\\n.non-working-hours[data-v-5ca7dec4] {\\n position: absolute;\\n top: 0;\\n height: 100%;\\n background: repeating-linear-gradient(45deg, transparent, transparent 10px, rgba(224, 224, 224, 0.3) 10px, rgba(224, 224, 224, 0.3) 20px);\\n z-index: 1;\\n pointer-events: none;\\n}\\n.work-hours-bar[data-v-5ca7dec4] {\\n position: absolute;\\n top: 0;\\n height: 100%;\\n background: transparent;\\n z-index: 1;\\n pointer-events: none;\\n}\\n.weekend-overlay[data-v-5ca7dec4] {\\n position: absolute;\\n top: 0;\\n left: 0;\\n width: 100%;\\n height: 100%;\\n background: rgba(255, 124, 124, 0.3) !important;\\n z-index: 1;\\n pointer-events: none;\\n border-radius: 4px;\\n}\\n.scheduled-block[data-v-5ca7dec4] {\\n position: absolute;\\n top: 5px;\\n height: 22px;\\n background: #7f39fb;\\n border: 1px solid #6a1bf7;\\n opacity: 0.6;\\n border-radius: 2px;\\n z-index: 2;\\n pointer-events: none;\\n}\\n.scheduled-block--blocker[data-v-5ca7dec4] {\\n background: rgb(176, 0, 32);\\n border: 1px solid rgb(156, 0, 28);\\n opacity: 0.7;\\n}\\n.other-timeblock[data-v-5ca7dec4] {\\n position: absolute;\\n top: 5px;\\n height: 22px;\\n background: #FFA726;\\n opacity: 0.5;\\n border: 2px dashed #FF9800;\\n border-radius: 2px;\\n z-index: 2;\\n pointer-events: none;\\n}\\n.preview-block[data-v-5ca7dec4] {\\n position: absolute;\\n top: 5px;\\n height: 22px;\\n background: #4CAF50;\\n opacity: 0.6;\\n border: 2px dashed #388E3C;\\n border-radius: 2px;\\n z-index: 5;\\n cursor: crosshair;\\n transition: opacity 0.2s, box-shadow 0.2s;\\n display: flex;\\n align-items: center;\\n justify-content: center;\\n pointer-events: none;\\n}\\n.preview-block[data-v-5ca7dec4]:hover {\\n opacity: 0.8;\\n box-shadow: 0 2px 8px rgba(76, 175, 80, 0.4);\\n}\\n.preview-block.is-stretching[data-v-5ca7dec4] {\\n opacity: 0.8;\\n box-shadow: 0 4px 12px rgba(76, 175, 80, 0.6);\\n cursor: ew-resize;\\n}\\n.preview-time-label[data-v-5ca7dec4] {\\n font-size: 11px;\\n font-weight: 600;\\n color: white;\\n text-shadow: 0 1px 2px rgba(0, 0, 0, 0.5);\\n white-space: nowrap;\\n pointer-events: none;\\n -webkit-user-select: none;\\n -moz-user-select: none;\\n user-select: none;\\n}\\n.current-timeblock[data-v-5ca7dec4] {\\n position: absolute;\\n top: 5px;\\n height: 22px;\\n background: #2196F3;\\n opacity: 0.7;\\n border: 2px solid #1976D2;\\n border-radius: 2px;\\n z-index: 3;\\n transition: box-shadow 0.2s;\\n}\\n.current-timeblock.has-collision[data-v-5ca7dec4] {\\n border-color: #ff5252;\\n}\\n.current-timeblock.outside-working-hours[data-v-5ca7dec4] {\\n border-color: #ff0000;\\n}\\n.current-timeblock.is-resizing[data-v-5ca7dec4] {\\n opacity: 0.8;\\n box-shadow: 0 4px 12px rgba(33, 150, 243, 0.6);\\n z-index: 6;\\n}\\n.resize-handle[data-v-5ca7dec4] {\\n position: absolute;\\n top: 0;\\n width: 8px;\\n height: 100%;\\n cursor: ew-resize;\\n z-index: 4;\\n}\\n.resize-handle[data-v-5ca7dec4]:hover {\\n background: rgba(255, 255, 255, 0.3);\\n}\\n.resize-handle--left[data-v-5ca7dec4] {\\n left: 0;\\n border-top-left-radius: 2px;\\n border-bottom-left-radius: 2px;\\n}\\n.resize-handle--right[data-v-5ca7dec4] {\\n right: 0;\\n border-top-right-radius: 2px;\\n border-bottom-right-radius: 2px;\\n}\\n.collision-segment[data-v-5ca7dec4] {\\n position: absolute;\\n top: 5px;\\n height: 22px;\\n background: #ff5252;\\n opacity: 0.6;\\n border-radius: 2px;\\n z-index: 4;\\n pointer-events: none;\\n}\\n.timeline-cursor[data-v-5ca7dec4] {\\n position: absolute;\\n top: 0;\\n bottom: 0;\\n width: 2px;\\n background: rgba(0, 0, 0, 0.3);\\n z-index: 10;\\n pointer-events: none;\\n}\\n.timeblock-duration[data-v-5ca7dec4] {\\n position: absolute;\\n top: 50%;\\n left: 50%;\\n transform: translate(-50%, -50%);\\n font-size: 14px;\\n font-weight: bold;\\n color: white;\\n text-shadow: 0 1px 2px rgba(0, 0, 0, 0.3);\\n pointer-events: none;\\n -webkit-user-select: none;\\n -moz-user-select: none;\\n user-select: none;\\n}\\n.timeline-loading[data-v-5ca7dec4] {\\n height: 60px;\\n display: flex;\\n align-items: center;\\n justify-content: center;\\n font-size: 14px;\\n opacity: 0.5;\\n}\", \"\"]);\n// Exports\n/* harmony default export */ __webpack_exports__[\"default\"] = (___CSS_LOADER_EXPORT___);\n\n\n//# sourceURL=webpack://jandl/./src/plugins/tm@modal/task/_components/employees/a-employee-timeblock-timeline.vue?./node_modules/css-loader/dist/cjs.js??clonedRuleSet-27.use%5B1%5D!./node_modules/vue-loader/dist/stylePostLoader.js!./node_modules/postcss-loader/dist/cjs.js??clonedRuleSet-27.use%5B2%5D!./node_modules/sass-loader/dist/cjs.js??clonedRuleSet-27.use%5B3%5D!./node_modules/vue-loader/dist/index.js??ruleSet%5B0%5D.use%5B0%5D\n}"); /***/ }), @@ -1242,7 +1242,7 @@ eval("{__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var cor /***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; -eval("{__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var core_js_modules_esnext_iterator_constructor_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! core-js/modules/esnext.iterator.constructor.js */ \"./node_modules/core-js/modules/esnext.iterator.constructor.js\");\n/* harmony import */ var core_js_modules_esnext_iterator_constructor_js__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(core_js_modules_esnext_iterator_constructor_js__WEBPACK_IMPORTED_MODULE_0__);\n/* harmony import */ var core_js_modules_esnext_iterator_filter_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! core-js/modules/esnext.iterator.filter.js */ \"./node_modules/core-js/modules/esnext.iterator.filter.js\");\n/* harmony import */ var core_js_modules_esnext_iterator_filter_js__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(core_js_modules_esnext_iterator_filter_js__WEBPACK_IMPORTED_MODULE_1__);\n/* harmony import */ var core_js_modules_esnext_iterator_map_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! core-js/modules/esnext.iterator.map.js */ \"./node_modules/core-js/modules/esnext.iterator.map.js\");\n/* harmony import */ var core_js_modules_esnext_iterator_map_js__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(core_js_modules_esnext_iterator_map_js__WEBPACK_IMPORTED_MODULE_2__);\n/* harmony import */ var vue__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! vue */ \"./node_modules/vue/dist/vue.runtime.esm-bundler.js\");\n/* harmony import */ var moment__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! moment */ \"./node_modules/moment/moment.js\");\n/* harmony import */ var moment__WEBPACK_IMPORTED_MODULE_4___default = /*#__PURE__*/__webpack_require__.n(moment__WEBPACK_IMPORTED_MODULE_4__);\n/* harmony import */ var _a_employee_timeblock_timeline_header_vue__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./a-employee-timeblock-timeline-header.vue */ \"./src/plugins/tm@modal/task/_components/employees/a-employee-timeblock-timeline-header.vue\");\n\n\n\n\n\n\n\n/* harmony default export */ __webpack_exports__[\"default\"] = (/*@__PURE__*/(0,vue__WEBPACK_IMPORTED_MODULE_3__.defineComponent)({\n __name: 'a-employee-timeblock-timeline',\n props: {\n isLoading: {\n type: Boolean,\n required: true\n },\n employee: {\n type: Object,\n required: true\n },\n date: {\n type: [Date, String, null],\n required: true\n },\n scheduledBlocks: {\n type: Array,\n required: true\n },\n otherTimeblocks: {\n type: Array,\n required: false,\n default: () => []\n },\n currentTimeblockRange: {\n type: Object,\n required: true\n },\n collision: {\n type: Object,\n required: true\n },\n collisionSegments: {\n type: Array,\n required: true\n },\n timeblockDuration: {\n type: Number,\n required: true\n },\n startHour: {\n type: Number,\n required: true\n },\n endHour: {\n type: Number,\n required: true\n },\n hourWidth: {\n type: Number,\n required: true\n }\n },\n emits: [\"timeblockUpdated\"],\n setup(__props, {\n expose: __expose,\n emit: __emit\n }) {\n const props = __props;\n const emit = __emit;\n const timelineContainer = (0,vue__WEBPACK_IMPORTED_MODULE_3__.ref)(null);\n const timelineScroll = (0,vue__WEBPACK_IMPORTED_MODULE_3__.ref)(null);\n const timelineBar = (0,vue__WEBPACK_IMPORTED_MODULE_3__.ref)(null);\n // Check if mobile device\n const isMobile = (0,vue__WEBPACK_IMPORTED_MODULE_3__.ref)(false);\n // Interactive state\n const showPreview = (0,vue__WEBPACK_IMPORTED_MODULE_3__.ref)(false);\n const previewBlock = (0,vue__WEBPACK_IMPORTED_MODULE_3__.ref)(null);\n const dragState = (0,vue__WEBPACK_IMPORTED_MODULE_3__.ref)({\n isStretching: false,\n isResizingCurrent: false,\n resizeEdge: null,\n startX: 0,\n initialStart: null,\n initialEnd: null\n });\n const resizedCurrentBlock = (0,vue__WEBPACK_IMPORTED_MODULE_3__.ref)(null);\n // Cursor line state\n const showCursor = (0,vue__WEBPACK_IMPORTED_MODULE_3__.ref)(false);\n const cursorPosition = (0,vue__WEBPACK_IMPORTED_MODULE_3__.ref)(null);\n // Check if the current date is a weekend (Saturday or Sunday)\n const isWeekend = (0,vue__WEBPACK_IMPORTED_MODULE_3__.computed)(() => {\n // Use the explicit date prop first, fallback to currentTimeblockRange.start\n const date = props.date || props.currentTimeblockRange.start;\n if (!date) return false;\n const dayOfWeek = moment__WEBPACK_IMPORTED_MODULE_4___default()(date).day(); // 0 = Sunday, 6 = Saturday\n return dayOfWeek === 0 || dayOfWeek === 6;\n });\n // Convert other timeblocks to renderable format\n const otherTimeblocksRendered = (0,vue__WEBPACK_IMPORTED_MODULE_3__.computed)(() => {\n return props.otherTimeblocks.map(tb => {\n if (!tb.date || !tb.starts_at_time || !tb.ends_at_time) return null;\n const [startHour, startMinute] = tb.starts_at_time.split(':').map(Number);\n const [endHour, endMinute] = tb.ends_at_time.split(':').map(Number);\n const start = moment__WEBPACK_IMPORTED_MODULE_4___default()(tb.date).set({\n hour: startHour,\n minute: startMinute,\n second: 0\n }).toDate();\n const end = moment__WEBPACK_IMPORTED_MODULE_4___default()(tb.date).set({\n hour: endHour,\n minute: endMinute,\n second: 0\n }).toDate();\n return {\n _start: start,\n _end: end\n };\n }).filter(tb => tb !== null);\n });\n // Position calculations\n const getHourPosition = hour => {\n return (hour - props.startHour) * props.hourWidth;\n };\n const getHourWidth = hours => {\n return hours * props.hourWidth;\n };\n const getTimePosition = date => {\n const hour = date.getHours();\n const minute = date.getMinutes();\n const totalHours = hour + minute / 60;\n return (totalHours - props.startHour) * props.hourWidth + 1;\n };\n const getTimeWidth = (start, end) => {\n const startHour = start.getHours() + start.getMinutes() / 60;\n const endHour = end.getHours() + end.getMinutes() / 60;\n return (endHour - startHour) * props.hourWidth - 2;\n };\n // Time snapping utility - snap to 15 minute intervals\n const snapToInterval = (date, intervalMinutes = 15) => {\n const minutes = date.getMinutes();\n const snappedMinutes = Math.round(minutes / intervalMinutes) * intervalMinutes;\n return moment__WEBPACK_IMPORTED_MODULE_4___default()(date).set({\n minute: snappedMinutes,\n second: 0,\n millisecond: 0\n }).toDate();\n };\n // Convert pixel position to time\n const positionToTime = pixelX => {\n const hoursFromStart = pixelX / props.hourWidth;\n const totalHours = props.startHour + hoursFromStart;\n const hour = Math.floor(totalHours);\n const minute = totalHours % 1 * 60;\n // Use current date from currentTimeblockRange or today\n const baseDate = props.currentTimeblockRange.start ? moment__WEBPACK_IMPORTED_MODULE_4___default()(props.currentTimeblockRange.start) : moment__WEBPACK_IMPORTED_MODULE_4___default()();\n return baseDate.set({\n hour,\n minute,\n second: 0,\n millisecond: 0\n }).toDate();\n };\n // Format time as HH:mm\n const formatTime = date => {\n return moment__WEBPACK_IMPORTED_MODULE_4___default()(date).format('HH:mm');\n };\n // Check if mouse is over an existing block (x is already relative position with scroll)\n // Note: This does NOT check the current timeblock because we want to allow\n // clicking elsewhere to change the current timeblock to a new time\n const isOverExistingBlock = relativeX => {\n // Check if over any scheduled block (saved tasks from database)\n for (const task of props.scheduledBlocks) {\n const blockLeft = getTimePosition(task._real_start);\n const blockWidth = getTimeWidth(task._real_start, task._real_end);\n if (relativeX >= blockLeft && relativeX <= blockLeft + blockWidth) {\n return true;\n }\n }\n // Check if over any other timeblock (from other rows in the modal)\n for (const tb of otherTimeblocksRendered.value) {\n const blockLeft = getTimePosition(tb._start);\n const blockWidth = getTimeWidth(tb._start, tb._end);\n if (relativeX >= blockLeft && relativeX <= blockLeft + blockWidth) {\n return true;\n }\n }\n // Don't check current timeblock - allow changing it by clicking elsewhere\n return false;\n };\n // Mouse move handler - show preview\n const handleMouseMove = event => {\n // Disable hover preview on mobile\n if (isMobile.value) {\n return;\n }\n if (dragState.value.isStretching) {\n handleStretchMove(event);\n return;\n }\n if (dragState.value.isResizingCurrent) {\n handleResizeCurrentMove(event);\n return;\n }\n if (!timelineScroll.value || !timelineBar.value) return;\n // Get position relative to scroll container\n const rect = timelineScroll.value.getBoundingClientRect();\n const scrollLeft = timelineScroll.value.scrollLeft;\n // Calculate X position relative to timeline\n const x = event.clientX - rect.left + scrollLeft;\n // Always calculate cursor position (with 15-min snapping)\n const rawTime = positionToTime(x);\n const snappedTime = snapToInterval(rawTime);\n const cursorHour = snappedTime.getHours() + snappedTime.getMinutes() / 60;\n // Check if cursor is in working hours\n const isInWorkHours = cursorHour >= props.employee.work_start && cursorHour < props.employee.work_end;\n // Only show cursor line if in working hours\n if (isInWorkHours) {\n cursorPosition.value = snappedTime;\n showCursor.value = true;\n } else {\n showCursor.value = false;\n }\n // Update cursor style based on work hours\n if (timelineScroll.value) {\n timelineScroll.value.style.cursor = isInWorkHours ? 'crosshair' : 'not-allowed';\n }\n // Allow preview to show even over existing blocks\n // This allows creating conflicting timeblocks\n // Convert to time and snap\n const snappedStart = snappedTime;\n // Calculate default end time (1 hour later)\n let snappedEnd = moment__WEBPACK_IMPORTED_MODULE_4___default()(snappedStart).add(1, 'hour').toDate();\n // Only show preview if start is within work hours\n if (isInWorkHours) {\n // If the end would exceed work hours, cap it at work_end\n const endHour = snappedEnd.getHours() + snappedEnd.getMinutes() / 60;\n if (endHour > props.employee.work_end) {\n // Create end time at exactly work_end\n snappedEnd = moment__WEBPACK_IMPORTED_MODULE_4___default()(snappedStart).set({\n hour: Math.floor(props.employee.work_end),\n minute: props.employee.work_end % 1 * 60,\n second: 0,\n millisecond: 0\n }).toDate();\n }\n showPreview.value = true;\n previewBlock.value = {\n start: snappedStart,\n end: snappedEnd\n };\n } else {\n showPreview.value = false;\n }\n };\n // Mouse leave handler\n const handleMouseLeave = () => {\n if (!dragState.value.isStretching && !dragState.value.isResizingCurrent) {\n showPreview.value = false;\n showCursor.value = false;\n // Reset cursor style to default crosshair\n if (timelineScroll.value) {\n timelineScroll.value.style.cursor = 'crosshair';\n }\n }\n };\n // Handle mousedown on timeline (including header area)\n const handleTimelineMouseDown = event => {\n if (isMobile.value) return;\n if (!timelineScroll.value || !cursorPosition.value) return;\n // Get the target element\n const target = event.target;\n // Only allow resize handles to work - don't interfere with them\n if (target.classList.contains('resize-handle')) {\n return;\n }\n // Allow clicking anywhere else, including over the current timeblock,\n // to create/redraw the block at the cursor position\n // Allow creating blocks even over existing blocks (scheduled or other timeblocks)\n // This enables creating conflicting timeblocks\n // Check if cursor is in work hours (cursor line must be visible)\n if (!showCursor.value || !showPreview.value || !previewBlock.value) {\n return;\n }\n // Start creating/stretching block at the snapped cursor position\n dragState.value.isStretching = true;\n dragState.value.startX = event.clientX;\n dragState.value.initialStart = cursorPosition.value;\n // Calculate initial end time (1 hour later, capped at work_end)\n let initialEnd = moment__WEBPACK_IMPORTED_MODULE_4___default()(cursorPosition.value).add(1, 'hour').toDate();\n const endHour = initialEnd.getHours() + initialEnd.getMinutes() / 60;\n if (endHour > props.employee.work_end) {\n initialEnd = moment__WEBPACK_IMPORTED_MODULE_4___default()(cursorPosition.value).set({\n hour: Math.floor(props.employee.work_end),\n minute: props.employee.work_end % 1 * 60,\n second: 0,\n millisecond: 0\n }).toDate();\n }\n dragState.value.initialEnd = initialEnd;\n // Set initial preview block (already has 1 hour duration from preview)\n previewBlock.value = {\n start: cursorPosition.value,\n end: initialEnd\n };\n event.preventDefault();\n };\n // Handle stretch move\n const handleStretchMove = event => {\n if (!dragState.value.initialStart || !timelineScroll.value) return;\n const rect = timelineScroll.value.getBoundingClientRect();\n const x = event.clientX - rect.left + timelineScroll.value.scrollLeft;\n const currentTime = positionToTime(x);\n let snappedTime = snapToInterval(currentTime);\n const initialStartTime = dragState.value.initialStart.getTime();\n const snappedTimeValue = snappedTime.getTime();\n if (snappedTimeValue >= initialStartTime) {\n // Stretching right (extending end)\n // Ensure minimum 15-minute block\n let endTime = snappedTime;\n if (snappedTimeValue === initialStartTime) {\n endTime = moment__WEBPACK_IMPORTED_MODULE_4___default()(snappedTime).add(15, 'minutes').toDate();\n }\n // Cap at work_end\n const endHour = endTime.getHours() + endTime.getMinutes() / 60;\n if (endHour > props.employee.work_end) {\n endTime = moment__WEBPACK_IMPORTED_MODULE_4___default()(endTime).set({\n hour: Math.floor(props.employee.work_end),\n minute: props.employee.work_end % 1 * 60,\n second: 0,\n millisecond: 0\n }).toDate();\n }\n previewBlock.value = {\n start: dragState.value.initialStart,\n end: endTime\n };\n // Update cursor to show at the actual block edge (end)\n cursorPosition.value = endTime;\n showCursor.value = true;\n } else {\n // Stretching left (extending start)\n // Cap at work_start\n const snappedStartHour = snappedTime.getHours() + snappedTime.getMinutes() / 60;\n if (snappedStartHour < props.employee.work_start) {\n snappedTime = moment__WEBPACK_IMPORTED_MODULE_4___default()(snappedTime).set({\n hour: Math.floor(props.employee.work_start),\n minute: props.employee.work_start % 1 * 60,\n second: 0,\n millisecond: 0\n }).toDate();\n }\n previewBlock.value = {\n start: snappedTime,\n end: dragState.value.initialStart\n };\n // Update cursor to show at the actual block edge (start)\n cursorPosition.value = snappedTime;\n showCursor.value = true;\n }\n };\n // Handle stretch end\n const handleStretchEnd = () => {\n if (dragState.value.isStretching && previewBlock.value) {\n // Only emit if we have a valid block (start != end)\n const startTime = previewBlock.value.start.getTime();\n const endTime = previewBlock.value.end.getTime();\n if (endTime > startTime) {\n // Emit the new timeblock\n emit('timeblockUpdated', {\n starts_at_time: formatTime(previewBlock.value.start),\n ends_at_time: formatTime(previewBlock.value.end)\n });\n }\n }\n dragState.value.isStretching = false;\n dragState.value.initialStart = null;\n dragState.value.initialEnd = null;\n showPreview.value = false;\n };\n // Resize handle mouse down - start resizing\n const handleResizeMouseDown = (event, edge) => {\n if (!props.currentTimeblockRange.start || !props.currentTimeblockRange.end) return;\n dragState.value.isResizingCurrent = true;\n dragState.value.resizeEdge = edge;\n dragState.value.startX = event.clientX;\n dragState.value.initialStart = props.currentTimeblockRange.start;\n dragState.value.initialEnd = props.currentTimeblockRange.end;\n resizedCurrentBlock.value = {\n start: props.currentTimeblockRange.start,\n end: props.currentTimeblockRange.end\n };\n event.preventDefault();\n };\n // Handle resize current block move\n const handleResizeCurrentMove = event => {\n if (!dragState.value.initialStart || !dragState.value.initialEnd || !timelineScroll.value) return;\n const rect = timelineScroll.value.getBoundingClientRect();\n const x = event.clientX - rect.left + timelineScroll.value.scrollLeft;\n const currentTime = positionToTime(x);\n let snappedTime = snapToInterval(currentTime);\n if (dragState.value.resizeEdge === 'left') {\n // Resizing left edge (changing start time)\n // Cap at work_start\n const snappedStartHour = snappedTime.getHours() + snappedTime.getMinutes() / 60;\n if (snappedStartHour < props.employee.work_start) {\n snappedTime = moment__WEBPACK_IMPORTED_MODULE_4___default()(snappedTime).set({\n hour: Math.floor(props.employee.work_start),\n minute: props.employee.work_start % 1 * 60,\n second: 0,\n millisecond: 0\n }).toDate();\n }\n // Make sure new start is before end\n if (snappedTime < dragState.value.initialEnd) {\n resizedCurrentBlock.value = {\n start: snappedTime,\n end: dragState.value.initialEnd\n };\n // Update cursor to show at the actual block edge\n cursorPosition.value = snappedTime;\n showCursor.value = true;\n }\n } else if (dragState.value.resizeEdge === 'right') {\n // Resizing right edge (changing end time)\n // Cap at work_end\n const snappedEndHour = snappedTime.getHours() + snappedTime.getMinutes() / 60;\n if (snappedEndHour > props.employee.work_end) {\n snappedTime = moment__WEBPACK_IMPORTED_MODULE_4___default()(snappedTime).set({\n hour: Math.floor(props.employee.work_end),\n minute: props.employee.work_end % 1 * 60,\n second: 0,\n millisecond: 0\n }).toDate();\n }\n // Make sure new end is after start\n if (snappedTime > dragState.value.initialStart) {\n resizedCurrentBlock.value = {\n start: dragState.value.initialStart,\n end: snappedTime\n };\n // Update cursor to show at the actual block edge\n cursorPosition.value = snappedTime;\n showCursor.value = true;\n }\n }\n };\n // Handle resize current block end\n const handleResizeCurrentEnd = () => {\n if (dragState.value.isResizingCurrent && resizedCurrentBlock.value) {\n // Emit the updated timeblock\n emit('timeblockUpdated', {\n starts_at_time: formatTime(resizedCurrentBlock.value.start),\n ends_at_time: formatTime(resizedCurrentBlock.value.end)\n });\n }\n dragState.value.isResizingCurrent = false;\n dragState.value.resizeEdge = null;\n dragState.value.initialStart = null;\n dragState.value.initialEnd = null;\n resizedCurrentBlock.value = null;\n };\n // Global mouse up handler\n const handleGlobalMouseUp = () => {\n if (dragState.value.isStretching) {\n handleStretchEnd();\n } else if (dragState.value.isResizingCurrent) {\n handleResizeCurrentEnd();\n }\n };\n // Global mouse move handler\n const handleGlobalMouseMove = event => {\n if (dragState.value.isStretching) {\n handleStretchMove(event);\n } else if (dragState.value.isResizingCurrent) {\n handleResizeCurrentMove(event);\n }\n };\n // Setup global listeners\n (0,vue__WEBPACK_IMPORTED_MODULE_3__.onMounted)(() => {\n // Detect mobile device\n isMobile.value = window.innerWidth <= 768;\n // Listen for resize to update mobile status\n const handleResize = () => {\n isMobile.value = window.innerWidth <= 768;\n };\n window.addEventListener('resize', handleResize);\n document.addEventListener('mouseup', handleGlobalMouseUp);\n document.addEventListener('mousemove', handleGlobalMouseMove);\n });\n (0,vue__WEBPACK_IMPORTED_MODULE_3__.onUnmounted)(() => {\n document.removeEventListener('mouseup', handleGlobalMouseUp);\n document.removeEventListener('mousemove', handleGlobalMouseMove);\n });\n // Expose refs for parent component\n __expose({\n timelineScroll\n });\n const __returned__ = {\n props,\n emit,\n timelineContainer,\n timelineScroll,\n timelineBar,\n isMobile,\n showPreview,\n previewBlock,\n dragState,\n resizedCurrentBlock,\n showCursor,\n cursorPosition,\n isWeekend,\n otherTimeblocksRendered,\n getHourPosition,\n getHourWidth,\n getTimePosition,\n getTimeWidth,\n snapToInterval,\n positionToTime,\n formatTime,\n isOverExistingBlock,\n handleMouseMove,\n handleMouseLeave,\n handleTimelineMouseDown,\n handleStretchMove,\n handleStretchEnd,\n handleResizeMouseDown,\n handleResizeCurrentMove,\n handleResizeCurrentEnd,\n handleGlobalMouseUp,\n handleGlobalMouseMove,\n AEmployeeTimeblockTimelineHeader: _a_employee_timeblock_timeline_header_vue__WEBPACK_IMPORTED_MODULE_5__[\"default\"]\n };\n Object.defineProperty(__returned__, '__isScriptSetup', {\n enumerable: false,\n value: true\n });\n return __returned__;\n }\n}));\n\n//# sourceURL=webpack://jandl/./src/plugins/tm@modal/task/_components/employees/a-employee-timeblock-timeline.vue?./node_modules/webpack-plugin-vuetify/dist/scriptLoader.js!./node_modules/babel-loader/lib/index.js!./node_modules/ts-loader/index.js??clonedRuleSet-41.use%5B1%5D!./node_modules/vue-loader/dist/index.js??ruleSet%5B0%5D.use%5B0%5D\n}"); +eval("{__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var core_js_modules_esnext_iterator_constructor_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! core-js/modules/esnext.iterator.constructor.js */ \"./node_modules/core-js/modules/esnext.iterator.constructor.js\");\n/* harmony import */ var core_js_modules_esnext_iterator_constructor_js__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(core_js_modules_esnext_iterator_constructor_js__WEBPACK_IMPORTED_MODULE_0__);\n/* harmony import */ var core_js_modules_esnext_iterator_filter_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! core-js/modules/esnext.iterator.filter.js */ \"./node_modules/core-js/modules/esnext.iterator.filter.js\");\n/* harmony import */ var core_js_modules_esnext_iterator_filter_js__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(core_js_modules_esnext_iterator_filter_js__WEBPACK_IMPORTED_MODULE_1__);\n/* harmony import */ var core_js_modules_esnext_iterator_map_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! core-js/modules/esnext.iterator.map.js */ \"./node_modules/core-js/modules/esnext.iterator.map.js\");\n/* harmony import */ var core_js_modules_esnext_iterator_map_js__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(core_js_modules_esnext_iterator_map_js__WEBPACK_IMPORTED_MODULE_2__);\n/* harmony import */ var vue__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! vue */ \"./node_modules/vue/dist/vue.runtime.esm-bundler.js\");\n/* harmony import */ var moment__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! moment */ \"./node_modules/moment/moment.js\");\n/* harmony import */ var moment__WEBPACK_IMPORTED_MODULE_4___default = /*#__PURE__*/__webpack_require__.n(moment__WEBPACK_IMPORTED_MODULE_4__);\n/* harmony import */ var _a_employee_timeblock_timeline_header_vue__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./a-employee-timeblock-timeline-header.vue */ \"./src/plugins/tm@modal/task/_components/employees/a-employee-timeblock-timeline-header.vue\");\n\n\n\n\n\n\n\n/* harmony default export */ __webpack_exports__[\"default\"] = (/*@__PURE__*/(0,vue__WEBPACK_IMPORTED_MODULE_3__.defineComponent)({\n __name: 'a-employee-timeblock-timeline',\n props: {\n isLoading: {\n type: Boolean,\n required: true\n },\n employee: {\n type: Object,\n required: true\n },\n date: {\n type: [Date, String, null],\n required: true\n },\n scheduledBlocks: {\n type: Array,\n required: true\n },\n otherTimeblocks: {\n type: Array,\n required: false,\n default: () => []\n },\n currentTimeblockRange: {\n type: Object,\n required: true\n },\n collision: {\n type: Object,\n required: true\n },\n collisionSegments: {\n type: Array,\n required: true\n },\n timeblockDuration: {\n type: Number,\n required: true\n },\n startHour: {\n type: Number,\n required: true\n },\n endHour: {\n type: Number,\n required: true\n },\n hourWidth: {\n type: Number,\n required: true\n }\n },\n emits: [\"timeblockUpdated\"],\n setup(__props, {\n expose: __expose,\n emit: __emit\n }) {\n const props = __props;\n const emit = __emit;\n const timelineContainer = (0,vue__WEBPACK_IMPORTED_MODULE_3__.ref)(null);\n const timelineScroll = (0,vue__WEBPACK_IMPORTED_MODULE_3__.ref)(null);\n const timelineBar = (0,vue__WEBPACK_IMPORTED_MODULE_3__.ref)(null);\n // Check if mobile device\n const isMobile = (0,vue__WEBPACK_IMPORTED_MODULE_3__.ref)(false);\n // Interactive state\n const showPreview = (0,vue__WEBPACK_IMPORTED_MODULE_3__.ref)(false);\n const previewBlock = (0,vue__WEBPACK_IMPORTED_MODULE_3__.ref)(null);\n const dragState = (0,vue__WEBPACK_IMPORTED_MODULE_3__.ref)({\n isStretching: false,\n isResizingCurrent: false,\n resizeEdge: null,\n startX: 0,\n initialStart: null,\n initialEnd: null\n });\n const resizedCurrentBlock = (0,vue__WEBPACK_IMPORTED_MODULE_3__.ref)(null);\n // Cursor line state\n const showCursor = (0,vue__WEBPACK_IMPORTED_MODULE_3__.ref)(false);\n const cursorPosition = (0,vue__WEBPACK_IMPORTED_MODULE_3__.ref)(null);\n // Check if the current date is a weekend (Saturday or Sunday)\n const isWeekend = (0,vue__WEBPACK_IMPORTED_MODULE_3__.computed)(() => {\n // Use the explicit date prop first, fallback to currentTimeblockRange.start\n const date = props.date || props.currentTimeblockRange.start;\n if (!date) return false;\n const dayOfWeek = moment__WEBPACK_IMPORTED_MODULE_4___default()(date).day(); // 0 = Sunday, 6 = Saturday\n return dayOfWeek === 0 || dayOfWeek === 6;\n });\n // Check if the current timeblock is outside working hours\n const isOutsideWorkingHours = (0,vue__WEBPACK_IMPORTED_MODULE_3__.computed)(() => {\n if (!props.currentTimeblockRange.start || !props.currentTimeblockRange.end) {\n return false;\n }\n const startHour = props.currentTimeblockRange.start.getHours() + props.currentTimeblockRange.start.getMinutes() / 60;\n const endHour = props.currentTimeblockRange.end.getHours() + props.currentTimeblockRange.end.getMinutes() / 60;\n // Check if any part of the timeblock is outside working hours\n const isStartOutside = startHour < props.employee.work_start || startHour >= props.employee.work_end;\n const isEndOutside = endHour <= props.employee.work_start || endHour > props.employee.work_end;\n return isStartOutside || isEndOutside;\n });\n // Convert other timeblocks to renderable format\n const otherTimeblocksRendered = (0,vue__WEBPACK_IMPORTED_MODULE_3__.computed)(() => {\n return props.otherTimeblocks.map(tb => {\n if (!tb.date || !tb.starts_at_time || !tb.ends_at_time) return null;\n const [startHour, startMinute] = tb.starts_at_time.split(':').map(Number);\n const [endHour, endMinute] = tb.ends_at_time.split(':').map(Number);\n const start = moment__WEBPACK_IMPORTED_MODULE_4___default()(tb.date).set({\n hour: startHour,\n minute: startMinute,\n second: 0\n }).toDate();\n const end = moment__WEBPACK_IMPORTED_MODULE_4___default()(tb.date).set({\n hour: endHour,\n minute: endMinute,\n second: 0\n }).toDate();\n return {\n _start: start,\n _end: end\n };\n }).filter(tb => tb !== null);\n });\n // Position calculations\n const getHourPosition = hour => {\n return (hour - props.startHour) * props.hourWidth;\n };\n const getHourWidth = hours => {\n return hours * props.hourWidth;\n };\n const getTimePosition = date => {\n const hour = date.getHours();\n const minute = date.getMinutes();\n const totalHours = hour + minute / 60;\n return (totalHours - props.startHour) * props.hourWidth + 1;\n };\n const getTimeWidth = (start, end) => {\n const startHour = start.getHours() + start.getMinutes() / 60;\n const endHour = end.getHours() + end.getMinutes() / 60;\n return (endHour - startHour) * props.hourWidth - 2;\n };\n // Time snapping utility - snap to 15 minute intervals\n const snapToInterval = (date, intervalMinutes = 15) => {\n const minutes = date.getMinutes();\n const snappedMinutes = Math.round(minutes / intervalMinutes) * intervalMinutes;\n return moment__WEBPACK_IMPORTED_MODULE_4___default()(date).set({\n minute: snappedMinutes,\n second: 0,\n millisecond: 0\n }).toDate();\n };\n // Convert pixel position to time\n const positionToTime = pixelX => {\n const hoursFromStart = pixelX / props.hourWidth;\n const totalHours = props.startHour + hoursFromStart;\n const hour = Math.floor(totalHours);\n const minute = totalHours % 1 * 60;\n // Use current date from currentTimeblockRange or today\n const baseDate = props.currentTimeblockRange.start ? moment__WEBPACK_IMPORTED_MODULE_4___default()(props.currentTimeblockRange.start) : moment__WEBPACK_IMPORTED_MODULE_4___default()();\n return baseDate.set({\n hour,\n minute,\n second: 0,\n millisecond: 0\n }).toDate();\n };\n // Format time as HH:mm\n const formatTime = date => {\n return moment__WEBPACK_IMPORTED_MODULE_4___default()(date).format('HH:mm');\n };\n // Check if mouse is over an existing block (x is already relative position with scroll)\n // Note: This does NOT check the current timeblock because we want to allow\n // clicking elsewhere to change the current timeblock to a new time\n const isOverExistingBlock = relativeX => {\n // Check if over any scheduled block (saved tasks from database)\n for (const task of props.scheduledBlocks) {\n const blockLeft = getTimePosition(task._real_start);\n const blockWidth = getTimeWidth(task._real_start, task._real_end);\n if (relativeX >= blockLeft && relativeX <= blockLeft + blockWidth) {\n return true;\n }\n }\n // Check if over any other timeblock (from other rows in the modal)\n for (const tb of otherTimeblocksRendered.value) {\n const blockLeft = getTimePosition(tb._start);\n const blockWidth = getTimeWidth(tb._start, tb._end);\n if (relativeX >= blockLeft && relativeX <= blockLeft + blockWidth) {\n return true;\n }\n }\n // Don't check current timeblock - allow changing it by clicking elsewhere\n return false;\n };\n // Mouse move handler - show preview\n const handleMouseMove = event => {\n // Disable hover preview on mobile\n if (isMobile.value) {\n return;\n }\n if (dragState.value.isStretching) {\n handleStretchMove(event);\n return;\n }\n if (dragState.value.isResizingCurrent) {\n handleResizeCurrentMove(event);\n return;\n }\n if (!timelineScroll.value || !timelineBar.value) return;\n // Get position relative to scroll container\n const rect = timelineScroll.value.getBoundingClientRect();\n const scrollLeft = timelineScroll.value.scrollLeft;\n // Calculate X position relative to timeline\n const x = event.clientX - rect.left + scrollLeft;\n // Always calculate cursor position (with 15-min snapping)\n const rawTime = positionToTime(x);\n const snappedTime = snapToInterval(rawTime);\n const cursorHour = snappedTime.getHours() + snappedTime.getMinutes() / 60;\n // Check if cursor is in working hours\n const isInWorkHours = cursorHour >= props.employee.work_start && cursorHour < props.employee.work_end;\n // Only show cursor line if in working hours\n if (isInWorkHours) {\n cursorPosition.value = snappedTime;\n showCursor.value = true;\n } else {\n showCursor.value = false;\n }\n // Update cursor style based on work hours\n if (timelineScroll.value) {\n timelineScroll.value.style.cursor = isInWorkHours ? 'crosshair' : 'not-allowed';\n }\n // Allow preview to show even over existing blocks\n // This allows creating conflicting timeblocks\n // Convert to time and snap\n const snappedStart = snappedTime;\n // Calculate default end time (1 hour later)\n let snappedEnd = moment__WEBPACK_IMPORTED_MODULE_4___default()(snappedStart).add(1, 'hour').toDate();\n // Only show preview if start is within work hours\n if (isInWorkHours) {\n // If the end would exceed work hours, cap it at work_end\n const endHour = snappedEnd.getHours() + snappedEnd.getMinutes() / 60;\n if (endHour > props.employee.work_end) {\n // Create end time at exactly work_end\n snappedEnd = moment__WEBPACK_IMPORTED_MODULE_4___default()(snappedStart).set({\n hour: Math.floor(props.employee.work_end),\n minute: props.employee.work_end % 1 * 60,\n second: 0,\n millisecond: 0\n }).toDate();\n }\n showPreview.value = true;\n previewBlock.value = {\n start: snappedStart,\n end: snappedEnd\n };\n } else {\n showPreview.value = false;\n }\n };\n // Mouse leave handler\n const handleMouseLeave = () => {\n if (!dragState.value.isStretching && !dragState.value.isResizingCurrent) {\n showPreview.value = false;\n showCursor.value = false;\n // Reset cursor style to default crosshair\n if (timelineScroll.value) {\n timelineScroll.value.style.cursor = 'crosshair';\n }\n }\n };\n // Handle mousedown on timeline (including header area)\n const handleTimelineMouseDown = event => {\n if (isMobile.value) return;\n if (!timelineScroll.value || !cursorPosition.value) return;\n // Get the target element\n const target = event.target;\n // Only allow resize handles to work - don't interfere with them\n if (target.classList.contains('resize-handle')) {\n return;\n }\n // Allow clicking anywhere else, including over the current timeblock,\n // to create/redraw the block at the cursor position\n // Allow creating blocks even over existing blocks (scheduled or other timeblocks)\n // This enables creating conflicting timeblocks\n // Check if cursor is in work hours (cursor line must be visible)\n if (!showCursor.value || !showPreview.value || !previewBlock.value) {\n return;\n }\n // Start creating/stretching block at the snapped cursor position\n dragState.value.isStretching = true;\n dragState.value.startX = event.clientX;\n dragState.value.initialStart = cursorPosition.value;\n // Calculate initial end time (1 hour later, capped at work_end)\n let initialEnd = moment__WEBPACK_IMPORTED_MODULE_4___default()(cursorPosition.value).add(1, 'hour').toDate();\n const endHour = initialEnd.getHours() + initialEnd.getMinutes() / 60;\n if (endHour > props.employee.work_end) {\n initialEnd = moment__WEBPACK_IMPORTED_MODULE_4___default()(cursorPosition.value).set({\n hour: Math.floor(props.employee.work_end),\n minute: props.employee.work_end % 1 * 60,\n second: 0,\n millisecond: 0\n }).toDate();\n }\n dragState.value.initialEnd = initialEnd;\n // Set initial preview block (already has 1 hour duration from preview)\n previewBlock.value = {\n start: cursorPosition.value,\n end: initialEnd\n };\n event.preventDefault();\n };\n // Handle stretch move\n const handleStretchMove = event => {\n if (!dragState.value.initialStart || !timelineScroll.value) return;\n const rect = timelineScroll.value.getBoundingClientRect();\n const x = event.clientX - rect.left + timelineScroll.value.scrollLeft;\n const currentTime = positionToTime(x);\n let snappedTime = snapToInterval(currentTime);\n const initialStartTime = dragState.value.initialStart.getTime();\n const snappedTimeValue = snappedTime.getTime();\n if (snappedTimeValue >= initialStartTime) {\n // Stretching right (extending end)\n // Ensure minimum 15-minute block\n let endTime = snappedTime;\n if (snappedTimeValue === initialStartTime) {\n endTime = moment__WEBPACK_IMPORTED_MODULE_4___default()(snappedTime).add(15, 'minutes').toDate();\n }\n // Cap at work_end\n const endHour = endTime.getHours() + endTime.getMinutes() / 60;\n if (endHour > props.employee.work_end) {\n endTime = moment__WEBPACK_IMPORTED_MODULE_4___default()(endTime).set({\n hour: Math.floor(props.employee.work_end),\n minute: props.employee.work_end % 1 * 60,\n second: 0,\n millisecond: 0\n }).toDate();\n }\n previewBlock.value = {\n start: dragState.value.initialStart,\n end: endTime\n };\n // Update cursor to show at the actual block edge (end)\n cursorPosition.value = endTime;\n showCursor.value = true;\n } else {\n // Stretching left (extending start)\n // Cap at work_start\n const snappedStartHour = snappedTime.getHours() + snappedTime.getMinutes() / 60;\n if (snappedStartHour < props.employee.work_start) {\n snappedTime = moment__WEBPACK_IMPORTED_MODULE_4___default()(snappedTime).set({\n hour: Math.floor(props.employee.work_start),\n minute: props.employee.work_start % 1 * 60,\n second: 0,\n millisecond: 0\n }).toDate();\n }\n previewBlock.value = {\n start: snappedTime,\n end: dragState.value.initialStart\n };\n // Update cursor to show at the actual block edge (start)\n cursorPosition.value = snappedTime;\n showCursor.value = true;\n }\n };\n // Handle stretch end\n const handleStretchEnd = () => {\n if (dragState.value.isStretching && previewBlock.value) {\n // Only emit if we have a valid block (start != end)\n const startTime = previewBlock.value.start.getTime();\n const endTime = previewBlock.value.end.getTime();\n if (endTime > startTime) {\n // Emit the new timeblock\n emit('timeblockUpdated', {\n starts_at_time: formatTime(previewBlock.value.start),\n ends_at_time: formatTime(previewBlock.value.end)\n });\n }\n }\n dragState.value.isStretching = false;\n dragState.value.initialStart = null;\n dragState.value.initialEnd = null;\n showPreview.value = false;\n };\n // Resize handle mouse down - start resizing\n const handleResizeMouseDown = (event, edge) => {\n if (!props.currentTimeblockRange.start || !props.currentTimeblockRange.end) return;\n dragState.value.isResizingCurrent = true;\n dragState.value.resizeEdge = edge;\n dragState.value.startX = event.clientX;\n dragState.value.initialStart = props.currentTimeblockRange.start;\n dragState.value.initialEnd = props.currentTimeblockRange.end;\n resizedCurrentBlock.value = {\n start: props.currentTimeblockRange.start,\n end: props.currentTimeblockRange.end\n };\n event.preventDefault();\n };\n // Handle resize current block move\n const handleResizeCurrentMove = event => {\n if (!dragState.value.initialStart || !dragState.value.initialEnd || !timelineScroll.value) return;\n const rect = timelineScroll.value.getBoundingClientRect();\n const x = event.clientX - rect.left + timelineScroll.value.scrollLeft;\n const currentTime = positionToTime(x);\n let snappedTime = snapToInterval(currentTime);\n if (dragState.value.resizeEdge === 'left') {\n // Resizing left edge (changing start time)\n // Cap at work_start\n const snappedStartHour = snappedTime.getHours() + snappedTime.getMinutes() / 60;\n if (snappedStartHour < props.employee.work_start) {\n snappedTime = moment__WEBPACK_IMPORTED_MODULE_4___default()(snappedTime).set({\n hour: Math.floor(props.employee.work_start),\n minute: props.employee.work_start % 1 * 60,\n second: 0,\n millisecond: 0\n }).toDate();\n }\n // Make sure new start is before end\n if (snappedTime < dragState.value.initialEnd) {\n resizedCurrentBlock.value = {\n start: snappedTime,\n end: dragState.value.initialEnd\n };\n // Update cursor to show at the actual block edge\n cursorPosition.value = snappedTime;\n showCursor.value = true;\n }\n } else if (dragState.value.resizeEdge === 'right') {\n // Resizing right edge (changing end time)\n // Cap at work_end\n const snappedEndHour = snappedTime.getHours() + snappedTime.getMinutes() / 60;\n if (snappedEndHour > props.employee.work_end) {\n snappedTime = moment__WEBPACK_IMPORTED_MODULE_4___default()(snappedTime).set({\n hour: Math.floor(props.employee.work_end),\n minute: props.employee.work_end % 1 * 60,\n second: 0,\n millisecond: 0\n }).toDate();\n }\n // Make sure new end is after start\n if (snappedTime > dragState.value.initialStart) {\n resizedCurrentBlock.value = {\n start: dragState.value.initialStart,\n end: snappedTime\n };\n // Update cursor to show at the actual block edge\n cursorPosition.value = snappedTime;\n showCursor.value = true;\n }\n }\n };\n // Handle resize current block end\n const handleResizeCurrentEnd = () => {\n if (dragState.value.isResizingCurrent && resizedCurrentBlock.value) {\n // Emit the updated timeblock\n emit('timeblockUpdated', {\n starts_at_time: formatTime(resizedCurrentBlock.value.start),\n ends_at_time: formatTime(resizedCurrentBlock.value.end)\n });\n }\n dragState.value.isResizingCurrent = false;\n dragState.value.resizeEdge = null;\n dragState.value.initialStart = null;\n dragState.value.initialEnd = null;\n resizedCurrentBlock.value = null;\n };\n // Global mouse up handler\n const handleGlobalMouseUp = () => {\n if (dragState.value.isStretching) {\n handleStretchEnd();\n } else if (dragState.value.isResizingCurrent) {\n handleResizeCurrentEnd();\n }\n };\n // Global mouse move handler\n const handleGlobalMouseMove = event => {\n if (dragState.value.isStretching) {\n handleStretchMove(event);\n } else if (dragState.value.isResizingCurrent) {\n handleResizeCurrentMove(event);\n }\n };\n // Setup global listeners\n (0,vue__WEBPACK_IMPORTED_MODULE_3__.onMounted)(() => {\n // Detect mobile device\n isMobile.value = window.innerWidth <= 768;\n // Listen for resize to update mobile status\n const handleResize = () => {\n isMobile.value = window.innerWidth <= 768;\n };\n window.addEventListener('resize', handleResize);\n document.addEventListener('mouseup', handleGlobalMouseUp);\n document.addEventListener('mousemove', handleGlobalMouseMove);\n });\n (0,vue__WEBPACK_IMPORTED_MODULE_3__.onUnmounted)(() => {\n document.removeEventListener('mouseup', handleGlobalMouseUp);\n document.removeEventListener('mousemove', handleGlobalMouseMove);\n });\n // Expose refs for parent component\n __expose({\n timelineScroll\n });\n const __returned__ = {\n props,\n emit,\n timelineContainer,\n timelineScroll,\n timelineBar,\n isMobile,\n showPreview,\n previewBlock,\n dragState,\n resizedCurrentBlock,\n showCursor,\n cursorPosition,\n isWeekend,\n isOutsideWorkingHours,\n otherTimeblocksRendered,\n getHourPosition,\n getHourWidth,\n getTimePosition,\n getTimeWidth,\n snapToInterval,\n positionToTime,\n formatTime,\n isOverExistingBlock,\n handleMouseMove,\n handleMouseLeave,\n handleTimelineMouseDown,\n handleStretchMove,\n handleStretchEnd,\n handleResizeMouseDown,\n handleResizeCurrentMove,\n handleResizeCurrentEnd,\n handleGlobalMouseUp,\n handleGlobalMouseMove,\n AEmployeeTimeblockTimelineHeader: _a_employee_timeblock_timeline_header_vue__WEBPACK_IMPORTED_MODULE_5__[\"default\"]\n };\n Object.defineProperty(__returned__, '__isScriptSetup', {\n enumerable: false,\n value: true\n });\n return __returned__;\n }\n}));\n\n//# sourceURL=webpack://jandl/./src/plugins/tm@modal/task/_components/employees/a-employee-timeblock-timeline.vue?./node_modules/webpack-plugin-vuetify/dist/scriptLoader.js!./node_modules/babel-loader/lib/index.js!./node_modules/ts-loader/index.js??clonedRuleSet-41.use%5B1%5D!./node_modules/vue-loader/dist/index.js??ruleSet%5B0%5D.use%5B0%5D\n}"); /***/ }), @@ -1319,7 +1319,7 @@ eval("{__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpa /***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; -eval("{__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ render: function() { return /* binding */ render; }\n/* harmony export */ });\n/* harmony import */ var vue__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! vue */ \"./node_modules/vue/dist/vue.runtime.esm-bundler.js\");\n\nconst _hoisted_1 = {\n class: \"timeline\"\n};\nconst _hoisted_2 = {\n key: 0,\n class: \"timeline-loading\"\n};\nconst _hoisted_3 = {\n key: 1,\n ref: \"timelineContainer\",\n class: \"timeline__content\"\n};\nconst _hoisted_4 = {\n ref: \"timelineBar\",\n class: \"timeline-bar\"\n};\nconst _hoisted_5 = {\n key: 0,\n class: \"weekend-overlay\"\n};\nconst _hoisted_6 = [\"title\"];\nconst _hoisted_7 = {\n class: \"preview-time-label\"\n};\nconst _hoisted_8 = {\n key: 0\n};\nconst _hoisted_9 = {\n key: 1\n};\nconst _hoisted_10 = {\n key: 0,\n class: \"timeblock-duration\"\n};\nconst _hoisted_11 = {\n key: 0,\n class: \"preview-time-label\"\n};\nconst _hoisted_12 = {\n key: 1,\n class: \"preview-time-label\"\n};\nfunction render(_ctx, _cache, $props, $setup, $data, $options) {\n return (0,vue__WEBPACK_IMPORTED_MODULE_0__.openBlock)(), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementBlock)(\"div\", _hoisted_1, [$props.isLoading ? ((0,vue__WEBPACK_IMPORTED_MODULE_0__.openBlock)(), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementBlock)(\"div\", _hoisted_2, [...(_cache[2] || (_cache[2] = [(0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)(\"span\", null, \"Načítavam...\", -1 /* CACHED */)]))])) : ((0,vue__WEBPACK_IMPORTED_MODULE_0__.openBlock)(), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementBlock)(\"div\", _hoisted_3, [(0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)(\"div\", {\n ref: \"timelineScroll\",\n class: \"timeline-scroll\",\n onMousemove: $setup.handleMouseMove,\n onMouseleave: $setup.handleMouseLeave,\n onMousedown: $setup.handleTimelineMouseDown\n }, [(0,vue__WEBPACK_IMPORTED_MODULE_0__.createVNode)($setup[\"AEmployeeTimeblockTimelineHeader\"], {\n \"start-hour\": $props.startHour,\n \"end-hour\": $props.endHour,\n \"hour-width\": $props.hourWidth\n }, null, 8 /* PROPS */, [\"start-hour\", \"end-hour\", \"hour-width\"]), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)(\"div\", _hoisted_4, [(0,vue__WEBPACK_IMPORTED_MODULE_0__.createCommentVNode)(\" Non-working hours - before work \"), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)(\"div\", {\n class: \"non-working-hours\",\n style: (0,vue__WEBPACK_IMPORTED_MODULE_0__.normalizeStyle)({\n left: '0px',\n width: `${$setup.getHourPosition($props.employee.work_start)}px`\n })\n }, null, 4 /* STYLE */), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createCommentVNode)(\" Non-working hours - after work \"), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)(\"div\", {\n class: \"non-working-hours\",\n style: (0,vue__WEBPACK_IMPORTED_MODULE_0__.normalizeStyle)({\n left: `${$setup.getHourPosition($props.employee.work_end)}px`,\n width: `${$setup.getHourWidth(24 - $props.employee.work_end)}px`\n })\n }, null, 4 /* STYLE */), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createCommentVNode)(\" Work hours background (transparent/white) \"), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)(\"div\", {\n class: \"work-hours-bar\",\n style: (0,vue__WEBPACK_IMPORTED_MODULE_0__.normalizeStyle)({\n left: `${$setup.getHourPosition($props.employee.work_start)}px`,\n width: `${$setup.getHourWidth($props.employee.work_end - $props.employee.work_start)}px`\n })\n }, null, 4 /* STYLE */), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createCommentVNode)(\" Weekend background overlay \"), $setup.isWeekend ? ((0,vue__WEBPACK_IMPORTED_MODULE_0__.openBlock)(), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementBlock)(\"div\", _hoisted_5)) : (0,vue__WEBPACK_IMPORTED_MODULE_0__.createCommentVNode)(\"v-if\", true), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createCommentVNode)(\" Existing scheduled blocks \"), ((0,vue__WEBPACK_IMPORTED_MODULE_0__.openBlock)(true), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementBlock)(vue__WEBPACK_IMPORTED_MODULE_0__.Fragment, null, (0,vue__WEBPACK_IMPORTED_MODULE_0__.renderList)($props.scheduledBlocks, (task, index) => {\n return (0,vue__WEBPACK_IMPORTED_MODULE_0__.openBlock)(), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementBlock)(\"div\", {\n key: `task-${index}`,\n class: (0,vue__WEBPACK_IMPORTED_MODULE_0__.normalizeClass)([\"scheduled-block\", {\n 'scheduled-block--blocker': ['blocker', 'adhoc', 'home_office', 'vacation', 'free_day', 'office365_blocker'].includes(task.type)\n }]),\n style: (0,vue__WEBPACK_IMPORTED_MODULE_0__.normalizeStyle)({\n left: `${$setup.getTimePosition(task._real_start)}px`,\n width: `${$setup.getTimeWidth(task._real_start, task._real_end)}px`\n }),\n title: `${task.subtask?.title || task.blocker?.type || 'Task'}`\n }, null, 14 /* CLASS, STYLE, PROPS */, _hoisted_6);\n }), 128 /* KEYED_FRAGMENT */)), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createCommentVNode)(\" Other timeblocks for same date \"), ((0,vue__WEBPACK_IMPORTED_MODULE_0__.openBlock)(true), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementBlock)(vue__WEBPACK_IMPORTED_MODULE_0__.Fragment, null, (0,vue__WEBPACK_IMPORTED_MODULE_0__.renderList)($setup.otherTimeblocksRendered, (timeblock, index) => {\n return (0,vue__WEBPACK_IMPORTED_MODULE_0__.openBlock)(), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementBlock)(\"div\", {\n key: `other-${index}`,\n class: \"other-timeblock\",\n style: (0,vue__WEBPACK_IMPORTED_MODULE_0__.normalizeStyle)({\n left: `${$setup.getTimePosition(timeblock._start)}px`,\n width: `${$setup.getTimeWidth(timeblock._start, timeblock._end)}px`\n }),\n title: `Other timeblock`\n }, null, 4 /* STYLE */);\n }), 128 /* KEYED_FRAGMENT */)), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createCommentVNode)(\" Hover preview block \"), $setup.showPreview && $setup.previewBlock ? ((0,vue__WEBPACK_IMPORTED_MODULE_0__.openBlock)(), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementBlock)(\"div\", {\n key: 1,\n class: (0,vue__WEBPACK_IMPORTED_MODULE_0__.normalizeClass)([\"preview-block\", {\n 'is-stretching': $setup.dragState.isStretching\n }]),\n style: (0,vue__WEBPACK_IMPORTED_MODULE_0__.normalizeStyle)({\n left: `${$setup.getTimePosition($setup.previewBlock.start)}px`,\n width: `${$setup.getTimeWidth($setup.previewBlock.start, $setup.previewBlock.end)}px`\n })\n }, [(0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)(\"div\", _hoisted_7, [$setup.getTimeWidth($setup.previewBlock.start, $setup.previewBlock.end) <= 58 ? ((0,vue__WEBPACK_IMPORTED_MODULE_0__.openBlock)(), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementBlock)(\"div\", _hoisted_8, (0,vue__WEBPACK_IMPORTED_MODULE_0__.toDisplayString)($setup.formatTime($setup.previewBlock.start)), 1 /* TEXT */)) : ((0,vue__WEBPACK_IMPORTED_MODULE_0__.openBlock)(), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementBlock)(\"div\", _hoisted_9, (0,vue__WEBPACK_IMPORTED_MODULE_0__.toDisplayString)($setup.formatTime($setup.previewBlock.start)) + \" - \" + (0,vue__WEBPACK_IMPORTED_MODULE_0__.toDisplayString)($setup.formatTime($setup.previewBlock.end)), 1 /* TEXT */))])], 6 /* CLASS, STYLE */)) : (0,vue__WEBPACK_IMPORTED_MODULE_0__.createCommentVNode)(\"v-if\", true), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createCommentVNode)(\" Current timeblock (if valid) \"), $props.currentTimeblockRange.start && $props.currentTimeblockRange.end && !$setup.dragState.isResizingCurrent ? ((0,vue__WEBPACK_IMPORTED_MODULE_0__.openBlock)(), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementBlock)(\"div\", {\n key: 2,\n class: (0,vue__WEBPACK_IMPORTED_MODULE_0__.normalizeClass)([\"current-timeblock\", {\n 'has-collision': $props.collision.hasCollision\n }]),\n style: (0,vue__WEBPACK_IMPORTED_MODULE_0__.normalizeStyle)({\n left: `${$setup.getTimePosition($props.currentTimeblockRange.start)}px`,\n width: `${$setup.getTimeWidth($props.currentTimeblockRange.start, $props.currentTimeblockRange.end)}px`\n })\n }, [(0,vue__WEBPACK_IMPORTED_MODULE_0__.createCommentVNode)(\" Duration display (centered in current timeblock) \"), $props.timeblockDuration > 0 ? ((0,vue__WEBPACK_IMPORTED_MODULE_0__.openBlock)(), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementBlock)(\"div\", _hoisted_10, (0,vue__WEBPACK_IMPORTED_MODULE_0__.toDisplayString)($props.timeblockDuration.toFixed(2)) + \"h \", 1 /* TEXT */)) : (0,vue__WEBPACK_IMPORTED_MODULE_0__.createCommentVNode)(\"v-if\", true), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createCommentVNode)(\" Resize handles \"), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)(\"div\", {\n class: \"resize-handle resize-handle--left\",\n onMousedown: _cache[0] || (_cache[0] = (0,vue__WEBPACK_IMPORTED_MODULE_0__.withModifiers)($event => $setup.handleResizeMouseDown($event, 'left'), [\"stop\"]))\n }, null, 32 /* NEED_HYDRATION */), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)(\"div\", {\n class: \"resize-handle resize-handle--right\",\n onMousedown: _cache[1] || (_cache[1] = (0,vue__WEBPACK_IMPORTED_MODULE_0__.withModifiers)($event => $setup.handleResizeMouseDown($event, 'right'), [\"stop\"]))\n }, null, 32 /* NEED_HYDRATION */)], 6 /* CLASS, STYLE */)) : (0,vue__WEBPACK_IMPORTED_MODULE_0__.createCommentVNode)(\"v-if\", true), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createCommentVNode)(\" Resizing current timeblock preview \"), $setup.dragState.isResizingCurrent && $setup.resizedCurrentBlock ? ((0,vue__WEBPACK_IMPORTED_MODULE_0__.openBlock)(), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementBlock)(\"div\", {\n key: 3,\n class: (0,vue__WEBPACK_IMPORTED_MODULE_0__.normalizeClass)([\"current-timeblock is-resizing\", {\n 'has-collision': $props.collision.hasCollision\n }]),\n style: (0,vue__WEBPACK_IMPORTED_MODULE_0__.normalizeStyle)({\n left: `${$setup.getTimePosition($setup.resizedCurrentBlock.start)}px`,\n width: `${$setup.getTimeWidth($setup.resizedCurrentBlock.start, $setup.resizedCurrentBlock.end)}px`\n })\n }, [$setup.getTimeWidth($setup.resizedCurrentBlock.start, $setup.resizedCurrentBlock.end) <= 58 ? ((0,vue__WEBPACK_IMPORTED_MODULE_0__.openBlock)(), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementBlock)(\"div\", _hoisted_11, (0,vue__WEBPACK_IMPORTED_MODULE_0__.toDisplayString)($setup.formatTime($setup.resizedCurrentBlock.start)), 1 /* TEXT */)) : ((0,vue__WEBPACK_IMPORTED_MODULE_0__.openBlock)(), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementBlock)(\"div\", _hoisted_12, (0,vue__WEBPACK_IMPORTED_MODULE_0__.toDisplayString)($setup.formatTime($setup.resizedCurrentBlock.start)) + \" - \" + (0,vue__WEBPACK_IMPORTED_MODULE_0__.toDisplayString)($setup.formatTime($setup.resizedCurrentBlock.end)), 1 /* TEXT */))], 6 /* CLASS, STYLE */)) : (0,vue__WEBPACK_IMPORTED_MODULE_0__.createCommentVNode)(\"v-if\", true), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createCommentVNode)(\" Collision segments \"), ((0,vue__WEBPACK_IMPORTED_MODULE_0__.openBlock)(true), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementBlock)(vue__WEBPACK_IMPORTED_MODULE_0__.Fragment, null, (0,vue__WEBPACK_IMPORTED_MODULE_0__.renderList)($props.collisionSegments, (segment, index) => {\n return (0,vue__WEBPACK_IMPORTED_MODULE_0__.openBlock)(), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementBlock)(\"div\", {\n key: `collision-${index}`,\n class: \"collision-segment\",\n style: (0,vue__WEBPACK_IMPORTED_MODULE_0__.normalizeStyle)({\n left: `${$setup.getTimePosition(segment.start)}px`,\n width: `${$setup.getTimeWidth(segment.start, segment.end)}px`\n })\n }, null, 4 /* STYLE */);\n }), 128 /* KEYED_FRAGMENT */)), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createCommentVNode)(\" Cursor line (snapped to 15-min intervals) \"), $setup.showCursor && $setup.cursorPosition ? ((0,vue__WEBPACK_IMPORTED_MODULE_0__.openBlock)(), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementBlock)(\"div\", {\n key: 4,\n class: \"timeline-cursor\",\n style: (0,vue__WEBPACK_IMPORTED_MODULE_0__.normalizeStyle)({\n left: `${$setup.getTimePosition($setup.cursorPosition)}px`\n })\n }, null, 4 /* STYLE */)) : (0,vue__WEBPACK_IMPORTED_MODULE_0__.createCommentVNode)(\"v-if\", true)], 512 /* NEED_PATCH */)], 544 /* NEED_HYDRATION, NEED_PATCH */)], 512 /* NEED_PATCH */))]);\n}\n\n//# sourceURL=webpack://jandl/./src/plugins/tm@modal/task/_components/employees/a-employee-timeblock-timeline.vue?./node_modules/webpack-plugin-vuetify/dist/scriptLoader.js!./node_modules/babel-loader/lib/index.js!./node_modules/ts-loader/index.js??clonedRuleSet-41.use%5B1%5D!./node_modules/vue-loader/dist/templateLoader.js??ruleSet%5B1%5D.rules%5B5%5D!./node_modules/vue-loader/dist/index.js??ruleSet%5B0%5D.use%5B0%5D\n}"); +eval("{__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ render: function() { return /* binding */ render; }\n/* harmony export */ });\n/* harmony import */ var vue__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! vue */ \"./node_modules/vue/dist/vue.runtime.esm-bundler.js\");\n\nconst _hoisted_1 = {\n class: \"timeline\"\n};\nconst _hoisted_2 = {\n key: 0,\n class: \"timeline-loading\"\n};\nconst _hoisted_3 = {\n key: 1,\n ref: \"timelineContainer\",\n class: \"timeline__content\"\n};\nconst _hoisted_4 = {\n ref: \"timelineBar\",\n class: \"timeline-bar\"\n};\nconst _hoisted_5 = {\n key: 0,\n class: \"weekend-overlay\"\n};\nconst _hoisted_6 = [\"title\"];\nconst _hoisted_7 = {\n class: \"preview-time-label\"\n};\nconst _hoisted_8 = {\n key: 0\n};\nconst _hoisted_9 = {\n key: 1\n};\nconst _hoisted_10 = {\n key: 0,\n class: \"timeblock-duration\"\n};\nconst _hoisted_11 = {\n key: 0,\n class: \"preview-time-label\"\n};\nconst _hoisted_12 = {\n key: 1,\n class: \"preview-time-label\"\n};\nfunction render(_ctx, _cache, $props, $setup, $data, $options) {\n return (0,vue__WEBPACK_IMPORTED_MODULE_0__.openBlock)(), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementBlock)(\"div\", _hoisted_1, [$props.isLoading ? ((0,vue__WEBPACK_IMPORTED_MODULE_0__.openBlock)(), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementBlock)(\"div\", _hoisted_2, [...(_cache[2] || (_cache[2] = [(0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)(\"span\", null, \"Načítavam...\", -1 /* CACHED */)]))])) : ((0,vue__WEBPACK_IMPORTED_MODULE_0__.openBlock)(), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementBlock)(\"div\", _hoisted_3, [(0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)(\"div\", {\n ref: \"timelineScroll\",\n class: \"timeline-scroll\",\n onMousemove: $setup.handleMouseMove,\n onMouseleave: $setup.handleMouseLeave,\n onMousedown: $setup.handleTimelineMouseDown\n }, [(0,vue__WEBPACK_IMPORTED_MODULE_0__.createVNode)($setup[\"AEmployeeTimeblockTimelineHeader\"], {\n \"start-hour\": $props.startHour,\n \"end-hour\": $props.endHour,\n \"hour-width\": $props.hourWidth\n }, null, 8 /* PROPS */, [\"start-hour\", \"end-hour\", \"hour-width\"]), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)(\"div\", _hoisted_4, [(0,vue__WEBPACK_IMPORTED_MODULE_0__.createCommentVNode)(\" Non-working hours - before work \"), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)(\"div\", {\n class: \"non-working-hours\",\n style: (0,vue__WEBPACK_IMPORTED_MODULE_0__.normalizeStyle)({\n left: '0px',\n width: `${$setup.getHourPosition($props.employee.work_start)}px`\n })\n }, null, 4 /* STYLE */), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createCommentVNode)(\" Non-working hours - after work \"), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)(\"div\", {\n class: \"non-working-hours\",\n style: (0,vue__WEBPACK_IMPORTED_MODULE_0__.normalizeStyle)({\n left: `${$setup.getHourPosition($props.employee.work_end)}px`,\n width: `${$setup.getHourWidth(24 - $props.employee.work_end)}px`\n })\n }, null, 4 /* STYLE */), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createCommentVNode)(\" Work hours background (transparent/white) \"), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)(\"div\", {\n class: \"work-hours-bar\",\n style: (0,vue__WEBPACK_IMPORTED_MODULE_0__.normalizeStyle)({\n left: `${$setup.getHourPosition($props.employee.work_start)}px`,\n width: `${$setup.getHourWidth($props.employee.work_end - $props.employee.work_start)}px`\n })\n }, null, 4 /* STYLE */), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createCommentVNode)(\" Weekend background overlay \"), $setup.isWeekend ? ((0,vue__WEBPACK_IMPORTED_MODULE_0__.openBlock)(), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementBlock)(\"div\", _hoisted_5)) : (0,vue__WEBPACK_IMPORTED_MODULE_0__.createCommentVNode)(\"v-if\", true), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createCommentVNode)(\" Existing scheduled blocks \"), ((0,vue__WEBPACK_IMPORTED_MODULE_0__.openBlock)(true), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementBlock)(vue__WEBPACK_IMPORTED_MODULE_0__.Fragment, null, (0,vue__WEBPACK_IMPORTED_MODULE_0__.renderList)($props.scheduledBlocks, (task, index) => {\n return (0,vue__WEBPACK_IMPORTED_MODULE_0__.openBlock)(), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementBlock)(\"div\", {\n key: `task-${index}`,\n class: (0,vue__WEBPACK_IMPORTED_MODULE_0__.normalizeClass)([\"scheduled-block\", {\n 'scheduled-block--blocker': ['blocker', 'adhoc', 'home_office', 'vacation', 'free_day', 'office365_blocker'].includes(task.type)\n }]),\n style: (0,vue__WEBPACK_IMPORTED_MODULE_0__.normalizeStyle)({\n left: `${$setup.getTimePosition(task._real_start)}px`,\n width: `${$setup.getTimeWidth(task._real_start, task._real_end)}px`\n }),\n title: `${task.subtask?.title || task.blocker?.type || 'Task'}`\n }, null, 14 /* CLASS, STYLE, PROPS */, _hoisted_6);\n }), 128 /* KEYED_FRAGMENT */)), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createCommentVNode)(\" Other timeblocks for same date \"), ((0,vue__WEBPACK_IMPORTED_MODULE_0__.openBlock)(true), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementBlock)(vue__WEBPACK_IMPORTED_MODULE_0__.Fragment, null, (0,vue__WEBPACK_IMPORTED_MODULE_0__.renderList)($setup.otherTimeblocksRendered, (timeblock, index) => {\n return (0,vue__WEBPACK_IMPORTED_MODULE_0__.openBlock)(), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementBlock)(\"div\", {\n key: `other-${index}`,\n class: \"other-timeblock\",\n style: (0,vue__WEBPACK_IMPORTED_MODULE_0__.normalizeStyle)({\n left: `${$setup.getTimePosition(timeblock._start)}px`,\n width: `${$setup.getTimeWidth(timeblock._start, timeblock._end)}px`\n }),\n title: `Other timeblock`\n }, null, 4 /* STYLE */);\n }), 128 /* KEYED_FRAGMENT */)), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createCommentVNode)(\" Hover preview block \"), $setup.showPreview && $setup.previewBlock ? ((0,vue__WEBPACK_IMPORTED_MODULE_0__.openBlock)(), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementBlock)(\"div\", {\n key: 1,\n class: (0,vue__WEBPACK_IMPORTED_MODULE_0__.normalizeClass)([\"preview-block\", {\n 'is-stretching': $setup.dragState.isStretching\n }]),\n style: (0,vue__WEBPACK_IMPORTED_MODULE_0__.normalizeStyle)({\n left: `${$setup.getTimePosition($setup.previewBlock.start)}px`,\n width: `${$setup.getTimeWidth($setup.previewBlock.start, $setup.previewBlock.end)}px`\n })\n }, [(0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)(\"div\", _hoisted_7, [$setup.getTimeWidth($setup.previewBlock.start, $setup.previewBlock.end) <= 58 ? ((0,vue__WEBPACK_IMPORTED_MODULE_0__.openBlock)(), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementBlock)(\"div\", _hoisted_8, (0,vue__WEBPACK_IMPORTED_MODULE_0__.toDisplayString)($setup.formatTime($setup.previewBlock.start)), 1 /* TEXT */)) : ((0,vue__WEBPACK_IMPORTED_MODULE_0__.openBlock)(), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementBlock)(\"div\", _hoisted_9, (0,vue__WEBPACK_IMPORTED_MODULE_0__.toDisplayString)($setup.formatTime($setup.previewBlock.start)) + \" - \" + (0,vue__WEBPACK_IMPORTED_MODULE_0__.toDisplayString)($setup.formatTime($setup.previewBlock.end)), 1 /* TEXT */))])], 6 /* CLASS, STYLE */)) : (0,vue__WEBPACK_IMPORTED_MODULE_0__.createCommentVNode)(\"v-if\", true), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createCommentVNode)(\" Current timeblock (if valid) \"), $props.currentTimeblockRange.start && $props.currentTimeblockRange.end && !$setup.dragState.isResizingCurrent ? ((0,vue__WEBPACK_IMPORTED_MODULE_0__.openBlock)(), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementBlock)(\"div\", {\n key: 2,\n class: (0,vue__WEBPACK_IMPORTED_MODULE_0__.normalizeClass)([\"current-timeblock\", {\n 'has-collision': $props.collision.hasCollision,\n 'outside-working-hours': $setup.isOutsideWorkingHours\n }]),\n style: (0,vue__WEBPACK_IMPORTED_MODULE_0__.normalizeStyle)({\n left: `${$setup.getTimePosition($props.currentTimeblockRange.start)}px`,\n width: `${$setup.getTimeWidth($props.currentTimeblockRange.start, $props.currentTimeblockRange.end)}px`\n })\n }, [(0,vue__WEBPACK_IMPORTED_MODULE_0__.createCommentVNode)(\" Duration display (centered in current timeblock) \"), $props.timeblockDuration > 0 ? ((0,vue__WEBPACK_IMPORTED_MODULE_0__.openBlock)(), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementBlock)(\"div\", _hoisted_10, (0,vue__WEBPACK_IMPORTED_MODULE_0__.toDisplayString)($props.timeblockDuration.toFixed(2)) + \"h \", 1 /* TEXT */)) : (0,vue__WEBPACK_IMPORTED_MODULE_0__.createCommentVNode)(\"v-if\", true), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createCommentVNode)(\" Resize handles \"), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)(\"div\", {\n class: \"resize-handle resize-handle--left\",\n onMousedown: _cache[0] || (_cache[0] = (0,vue__WEBPACK_IMPORTED_MODULE_0__.withModifiers)($event => $setup.handleResizeMouseDown($event, 'left'), [\"stop\"]))\n }, null, 32 /* NEED_HYDRATION */), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)(\"div\", {\n class: \"resize-handle resize-handle--right\",\n onMousedown: _cache[1] || (_cache[1] = (0,vue__WEBPACK_IMPORTED_MODULE_0__.withModifiers)($event => $setup.handleResizeMouseDown($event, 'right'), [\"stop\"]))\n }, null, 32 /* NEED_HYDRATION */)], 6 /* CLASS, STYLE */)) : (0,vue__WEBPACK_IMPORTED_MODULE_0__.createCommentVNode)(\"v-if\", true), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createCommentVNode)(\" Resizing current timeblock preview \"), $setup.dragState.isResizingCurrent && $setup.resizedCurrentBlock ? ((0,vue__WEBPACK_IMPORTED_MODULE_0__.openBlock)(), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementBlock)(\"div\", {\n key: 3,\n class: (0,vue__WEBPACK_IMPORTED_MODULE_0__.normalizeClass)([\"current-timeblock is-resizing\", {\n 'has-collision': $props.collision.hasCollision,\n 'outside-working-hours': $setup.isOutsideWorkingHours\n }]),\n style: (0,vue__WEBPACK_IMPORTED_MODULE_0__.normalizeStyle)({\n left: `${$setup.getTimePosition($setup.resizedCurrentBlock.start)}px`,\n width: `${$setup.getTimeWidth($setup.resizedCurrentBlock.start, $setup.resizedCurrentBlock.end)}px`\n })\n }, [$setup.getTimeWidth($setup.resizedCurrentBlock.start, $setup.resizedCurrentBlock.end) <= 58 ? ((0,vue__WEBPACK_IMPORTED_MODULE_0__.openBlock)(), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementBlock)(\"div\", _hoisted_11, (0,vue__WEBPACK_IMPORTED_MODULE_0__.toDisplayString)($setup.formatTime($setup.resizedCurrentBlock.start)), 1 /* TEXT */)) : ((0,vue__WEBPACK_IMPORTED_MODULE_0__.openBlock)(), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementBlock)(\"div\", _hoisted_12, (0,vue__WEBPACK_IMPORTED_MODULE_0__.toDisplayString)($setup.formatTime($setup.resizedCurrentBlock.start)) + \" - \" + (0,vue__WEBPACK_IMPORTED_MODULE_0__.toDisplayString)($setup.formatTime($setup.resizedCurrentBlock.end)), 1 /* TEXT */))], 6 /* CLASS, STYLE */)) : (0,vue__WEBPACK_IMPORTED_MODULE_0__.createCommentVNode)(\"v-if\", true), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createCommentVNode)(\" Collision segments \"), ((0,vue__WEBPACK_IMPORTED_MODULE_0__.openBlock)(true), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementBlock)(vue__WEBPACK_IMPORTED_MODULE_0__.Fragment, null, (0,vue__WEBPACK_IMPORTED_MODULE_0__.renderList)($props.collisionSegments, (segment, index) => {\n return (0,vue__WEBPACK_IMPORTED_MODULE_0__.openBlock)(), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementBlock)(\"div\", {\n key: `collision-${index}`,\n class: \"collision-segment\",\n style: (0,vue__WEBPACK_IMPORTED_MODULE_0__.normalizeStyle)({\n left: `${$setup.getTimePosition(segment.start)}px`,\n width: `${$setup.getTimeWidth(segment.start, segment.end)}px`\n })\n }, null, 4 /* STYLE */);\n }), 128 /* KEYED_FRAGMENT */)), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createCommentVNode)(\" Cursor line (snapped to 15-min intervals) \"), $setup.showCursor && $setup.cursorPosition ? ((0,vue__WEBPACK_IMPORTED_MODULE_0__.openBlock)(), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementBlock)(\"div\", {\n key: 4,\n class: \"timeline-cursor\",\n style: (0,vue__WEBPACK_IMPORTED_MODULE_0__.normalizeStyle)({\n left: `${$setup.getTimePosition($setup.cursorPosition)}px`\n })\n }, null, 4 /* STYLE */)) : (0,vue__WEBPACK_IMPORTED_MODULE_0__.createCommentVNode)(\"v-if\", true)], 512 /* NEED_PATCH */)], 544 /* NEED_HYDRATION, NEED_PATCH */)], 512 /* NEED_PATCH */))]);\n}\n\n//# sourceURL=webpack://jandl/./src/plugins/tm@modal/task/_components/employees/a-employee-timeblock-timeline.vue?./node_modules/webpack-plugin-vuetify/dist/scriptLoader.js!./node_modules/babel-loader/lib/index.js!./node_modules/ts-loader/index.js??clonedRuleSet-41.use%5B1%5D!./node_modules/vue-loader/dist/templateLoader.js??ruleSet%5B1%5D.rules%5B5%5D!./node_modules/vue-loader/dist/index.js??ruleSet%5B0%5D.use%5B0%5D\n}"); /***/ }), diff --git a/app/src/plugins/tm@modal/task/_components/employees/a-employee-timeblock-timeline.vue b/app/src/plugins/tm@modal/task/_components/employees/a-employee-timeblock-timeline.vue index ba7abaf..2b0a1fb 100644 --- a/app/src/plugins/tm@modal/task/_components/employees/a-employee-timeblock-timeline.vue +++ b/app/src/plugins/tm@modal/task/_components/employees/a-employee-timeblock-timeline.vue @@ -117,6 +117,7 @@ class="current-timeblock" :class="{ 'has-collision': collision.hasCollision, + 'outside-working-hours': isOutsideWorkingHours, }" :style="{ left: `${getTimePosition(currentTimeblockRange.start)}px`, @@ -146,7 +147,10 @@