@necrolab/dashboard 0.5.15 → 0.5.17

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (137) hide show
  1. package/backend/api.js +2 -3
  2. package/eslint.config.js +46 -0
  3. package/index.html +2 -1
  4. package/package.json +5 -2
  5. package/src/App.vue +70 -566
  6. package/src/assets/css/base/mixins.scss +72 -0
  7. package/src/assets/css/base/reset.scss +0 -2
  8. package/src/assets/css/base/scroll.scss +43 -36
  9. package/src/assets/css/base/typography.scss +9 -10
  10. package/src/assets/css/base/variables.scss +43 -0
  11. package/src/assets/css/components/accessibility.scss +37 -0
  12. package/src/assets/css/components/buttons.scss +61 -74
  13. package/src/assets/css/components/forms.scss +31 -32
  14. package/src/assets/css/components/headers.scss +13 -21
  15. package/src/assets/css/components/modals.scss +2 -2
  16. package/src/assets/css/components/search-groups.scss +28 -22
  17. package/src/assets/css/components/tables.scss +5 -7
  18. package/src/assets/css/components/toasts.scss +7 -7
  19. package/src/assets/css/components/utilities.scss +295 -0
  20. package/src/assets/css/main.scss +55 -139
  21. package/src/components/Auth/LoginForm.vue +7 -86
  22. package/src/components/Console/ConsoleToolbar.vue +123 -0
  23. package/src/components/Editors/Account/Account.vue +12 -12
  24. package/src/components/Editors/Account/AccountView.vue +38 -111
  25. package/src/components/Editors/Account/CreateAccount.vue +11 -61
  26. package/src/components/Editors/Account/{AccountCreator.vue → CreateAccountBatch.vue} +28 -59
  27. package/src/components/Editors/AdminFileEditor.vue +179 -0
  28. package/src/components/Editors/Profile/CreateProfile.vue +77 -150
  29. package/src/components/Editors/Profile/Profile.vue +20 -21
  30. package/src/components/Editors/Profile/ProfileCountryChooser.vue +16 -60
  31. package/src/components/Editors/Profile/ProfileView.vue +41 -116
  32. package/src/components/Editors/ProxyFileEditor.vue +86 -0
  33. package/src/components/Editors/TagLabel.vue +16 -55
  34. package/src/components/Editors/TagToggle.vue +20 -8
  35. package/src/components/Filter/Filter.vue +66 -79
  36. package/src/components/Filter/FilterPreview.vue +153 -135
  37. package/src/components/Filter/PriceSortToggle.vue +36 -43
  38. package/src/components/Table/Header.vue +1 -1
  39. package/src/components/Table/Table.vue +45 -51
  40. package/src/components/Tasks/CheckStock.vue +7 -16
  41. package/src/components/Tasks/Controls/DesktopControls.vue +15 -60
  42. package/src/components/Tasks/Controls/MobileControls.vue +5 -20
  43. package/src/components/Tasks/CreateTaskAXS.vue +20 -118
  44. package/src/components/Tasks/CreateTaskTM.vue +33 -189
  45. package/src/components/Tasks/EventDetailRow.vue +21 -0
  46. package/src/components/Tasks/MassEdit.vue +6 -16
  47. package/src/components/Tasks/QuickSettings.vue +140 -216
  48. package/src/components/Tasks/ScrapeVenue.vue +4 -13
  49. package/src/components/Tasks/Stats.vue +20 -39
  50. package/src/components/Tasks/Task.vue +64 -270
  51. package/src/components/Tasks/TaskLabel.vue +9 -3
  52. package/src/components/Tasks/TaskView.vue +45 -64
  53. package/src/components/Tasks/Utilities.vue +10 -44
  54. package/src/components/Tasks/ViewTask.vue +23 -107
  55. package/src/components/icons/Close.vue +2 -8
  56. package/src/components/icons/Gear.vue +8 -8
  57. package/src/components/icons/Hash.vue +5 -0
  58. package/src/components/icons/Key.vue +2 -8
  59. package/src/components/icons/Pencil.vue +2 -8
  60. package/src/components/icons/Profile.vue +2 -8
  61. package/src/components/icons/Sell.vue +2 -8
  62. package/src/components/icons/Spinner.vue +4 -7
  63. package/src/components/icons/Wildcard.vue +2 -8
  64. package/src/components/icons/index.js +3 -5
  65. package/src/components/ui/ActionButtonGroup.vue +113 -52
  66. package/src/components/ui/BalanceIndicator.vue +60 -0
  67. package/src/components/ui/EmptyState.vue +24 -0
  68. package/src/components/ui/EnableDisableToggle.vue +23 -0
  69. package/src/components/ui/FormField.vue +49 -49
  70. package/src/components/ui/IconLabel.vue +23 -0
  71. package/src/components/ui/InfoRow.vue +21 -54
  72. package/src/components/ui/Modal.vue +161 -54
  73. package/src/components/ui/Navbar.vue +63 -44
  74. package/src/components/ui/ReadonlyFieldsSection.vue +31 -0
  75. package/src/components/ui/ReconnectIndicator.vue +111 -124
  76. package/src/components/ui/SectionCard.vue +6 -14
  77. package/src/components/ui/Splash.vue +2 -10
  78. package/src/components/ui/StatusBadge.vue +26 -28
  79. package/src/components/ui/TaskToggle.vue +54 -0
  80. package/src/components/ui/controls/CountryChooser.vue +29 -66
  81. package/src/components/ui/controls/EyeToggle.vue +1 -1
  82. package/src/components/ui/controls/atomic/Checkbox.vue +40 -121
  83. package/src/components/ui/controls/atomic/Dropdown.vue +103 -139
  84. package/src/components/ui/controls/atomic/MultiDropdown.vue +72 -120
  85. package/src/components/ui/controls/atomic/Switch.vue +21 -84
  86. package/src/composables/useCodeEditor.js +117 -0
  87. package/src/composables/useColorMapping.js +15 -0
  88. package/src/composables/useCopyToClipboard.js +1 -1
  89. package/src/composables/useDateFormatting.js +21 -0
  90. package/src/composables/useDeviceDetection.js +14 -0
  91. package/src/composables/useDropdownPosition.js +1 -4
  92. package/src/composables/useDynamicTableHeight.js +31 -0
  93. package/src/composables/useEnableDisable.js +6 -0
  94. package/src/composables/useFilterCSS.js +71 -0
  95. package/src/composables/useFormValidation.js +92 -0
  96. package/src/composables/useGetAllTags.js +9 -0
  97. package/src/composables/useIOSViewportHandling.js +76 -0
  98. package/src/composables/useNotchHandling.js +306 -0
  99. package/src/composables/useRowSelection.js +0 -3
  100. package/src/composables/useTableRender.js +23 -0
  101. package/src/composables/useTicketPricing.js +16 -0
  102. package/src/composables/useWindowDimensions.js +21 -0
  103. package/src/composables/useZoomPrevention.js +96 -0
  104. package/src/constants/tableLayout.js +14 -0
  105. package/src/libs/Filter.js +14 -20
  106. package/src/libs/panzoom.js +1 -5
  107. package/src/libs/utils/array.js +58 -0
  108. package/src/{stores/utils.js → libs/utils/dataGeneration.js} +2 -250
  109. package/src/libs/utils/eventUrl.js +40 -0
  110. package/src/libs/utils/string.js +3 -0
  111. package/src/libs/utils/time.js +20 -0
  112. package/src/libs/utils/validation.js +64 -0
  113. package/src/main.js +0 -2
  114. package/src/stores/connection.js +1 -29
  115. package/src/stores/logger.js +6 -12
  116. package/src/stores/sampleData.js +1 -2
  117. package/src/stores/ui.js +80 -71
  118. package/src/utils/tableHelpers.js +1 -0
  119. package/src/views/Accounts.vue +19 -38
  120. package/src/views/Console.vue +74 -253
  121. package/src/views/Editor.vue +47 -1114
  122. package/src/views/FilterBuilder.vue +190 -461
  123. package/src/views/Login.vue +3 -28
  124. package/src/views/Profiles.vue +17 -32
  125. package/src/views/Tasks.vue +51 -38
  126. package/tailwind.config.js +82 -71
  127. package/workbox-config.cjs +47 -5
  128. package/docs/plans/2026-02-08-tailwind-consolidation.md +0 -2438
  129. package/exit +0 -209
  130. package/run +0 -177
  131. package/src/assets/css/base/color-fallbacks.scss +0 -10
  132. package/src/assets/img/background.svg.backup +0 -11
  133. package/src/components/icons/SquareCheck.vue +0 -18
  134. package/src/components/icons/SquareUncheck.vue +0 -18
  135. package/src/components/ui/controls/atomic/LoadingButton.vue +0 -45
  136. package/switch-branch.sh +0 -41
  137. /package/public/{reconnect-logo.png → img/reconnect-logo.png} +0 -0
@@ -0,0 +1,306 @@
1
+ import { ref, watch, onMounted } from 'vue';
2
+ import { useRouter } from 'vue-router';
3
+ import { useDeviceDetection } from './useDeviceDetection';
4
+ import { DEBUG } from '@/utils/debug';
5
+
6
+ export function useNotchHandling(logger) {
7
+ const { isIOS, isIpadOS } = useDeviceDetection();
8
+ const router = useRouter();
9
+ const showLandscapeLock = ref(false);
10
+
11
+ let notchTimeout;
12
+ let isNotchBusy = false;
13
+ let lastNotchState = null;
14
+
15
+ function isLandscapeMode() {
16
+ let orientationLandscape = false;
17
+
18
+ if (typeof window.orientation !== "undefined") {
19
+ orientationLandscape = Math.abs(window.orientation) === 90;
20
+ } else if (screen.orientation && typeof screen.orientation.angle !== "undefined") {
21
+ orientationLandscape = Math.abs(screen.orientation.angle) === 90;
22
+ }
23
+
24
+ const dimensionLandscape = window.innerWidth > window.innerHeight;
25
+ const hasStrongLandscapeRatio = window.innerWidth / window.innerHeight > 1.5;
26
+
27
+ if (isIOS() && !isIpadOS() && dimensionLandscape && hasStrongLandscapeRatio) {
28
+ return true;
29
+ }
30
+
31
+ return orientationLandscape || (dimensionLandscape && hasStrongLandscapeRatio);
32
+ }
33
+
34
+ function hasDeviceNotch() {
35
+ if (!isIOS() || isIpadOS()) return false;
36
+
37
+ return (
38
+ CSS.supports("padding-left: env(safe-area-inset-left)") &&
39
+ CSS.supports("padding-right: env(safe-area-inset-right)")
40
+ );
41
+ }
42
+
43
+ function handleNotch(force = false) {
44
+ if (isNotchBusy && !force) return;
45
+
46
+ try {
47
+ if (!isIOS() || isIpadOS()) return;
48
+
49
+ const wrappers = document.querySelectorAll(".ios-wrapper");
50
+ if (wrappers.length === 0) {
51
+ setTimeout(() => handleNotch(force), 100);
52
+ return;
53
+ }
54
+
55
+ const isLandscape = isLandscapeMode();
56
+ const hasNotch = hasDeviceNotch();
57
+
58
+ let orientation = window.orientation;
59
+ if (typeof orientation === "undefined" && screen.orientation) {
60
+ orientation = screen.orientation.angle;
61
+ }
62
+
63
+ const currentState = `${isLandscape}-${hasNotch}-${orientation}-${window.innerWidth}x${window.innerHeight}`;
64
+ if (lastNotchState === currentState && !force) {
65
+ return;
66
+ }
67
+ lastNotchState = currentState;
68
+
69
+ isNotchBusy = true;
70
+
71
+ if (DEBUG && logger) {
72
+ logger.Debug("🔥 Notch Debug:", {
73
+ isLandscape,
74
+ hasNotch,
75
+ orientation,
76
+ dimensions: `${window.innerWidth}x${window.innerHeight}`,
77
+ state: currentState
78
+ });
79
+ }
80
+
81
+ if (hasNotch && isLandscape) {
82
+ const testDiv = document.createElement("div");
83
+ testDiv.style.position = "fixed";
84
+ testDiv.style.top = "0";
85
+ testDiv.style.left = "0";
86
+ testDiv.style.visibility = "hidden";
87
+ testDiv.style.paddingLeft = "env(safe-area-inset-left)";
88
+ testDiv.style.paddingRight = "env(safe-area-inset-right)";
89
+ document.body.appendChild(testDiv);
90
+
91
+ const computedStyle = getComputedStyle(testDiv);
92
+ const leftInset = parseFloat(computedStyle.paddingLeft) || 0;
93
+ const rightInset = parseFloat(computedStyle.paddingRight) || 0;
94
+
95
+ document.body.removeChild(testDiv);
96
+
97
+ if (DEBUG && logger) logger.Debug("🔍 Safe area insets:", { leftInset, rightInset });
98
+
99
+ wrappers.forEach((wrapper) => {
100
+ if (leftInset > 0) {
101
+ wrapper.style.paddingLeft = "env(safe-area-inset-left)";
102
+ wrapper.style.paddingRight = "0.5rem";
103
+ } else if (rightInset > 0) {
104
+ wrapper.style.paddingLeft = "0.5rem";
105
+ wrapper.style.paddingRight = "env(safe-area-inset-right)";
106
+ } else {
107
+ wrapper.style.paddingLeft = "0.5rem";
108
+ wrapper.style.paddingRight = "0.5rem";
109
+ }
110
+ });
111
+ } else {
112
+ const RESPONSIVE_PADDING = {
113
+ XL: { minWidth: 1280, padding: "2.5rem" },
114
+ LG: { minWidth: 1030, padding: "1.5rem" },
115
+ MD: { minWidth: 768, padding: "0.5rem" },
116
+ DEFAULT: { padding: "0.5rem" }
117
+ };
118
+
119
+ const padding =
120
+ window.innerWidth > RESPONSIVE_PADDING.XL.minWidth
121
+ ? RESPONSIVE_PADDING.XL.padding
122
+ : window.innerWidth > RESPONSIVE_PADDING.LG.minWidth
123
+ ? RESPONSIVE_PADDING.LG.padding
124
+ : window.innerWidth > RESPONSIVE_PADDING.MD.minWidth
125
+ ? RESPONSIVE_PADDING.MD.padding
126
+ : RESPONSIVE_PADDING.DEFAULT.padding;
127
+
128
+ wrappers.forEach((wrapper) => {
129
+ wrapper.style.paddingLeft = padding;
130
+ wrapper.style.paddingRight = padding;
131
+ });
132
+ }
133
+
134
+ isNotchBusy = false;
135
+ } catch (error) {
136
+ if (DEBUG && logger) logger.Yellow("Notch error:", error);
137
+ isNotchBusy = false;
138
+ }
139
+ }
140
+
141
+ function triggerNotch() {
142
+ clearTimeout(notchTimeout);
143
+ notchTimeout = setTimeout(handleNotch, 50);
144
+ }
145
+
146
+ function updateLandscapeLock() {
147
+ if (isIOS() && !isIpadOS()) {
148
+ showLandscapeLock.value = isLandscapeMode();
149
+ }
150
+ }
151
+
152
+ function initNotchHandling() {
153
+ handleNotch(true);
154
+ setTimeout(() => handleNotch(true), 50);
155
+ setTimeout(() => handleNotch(true), 150);
156
+ setTimeout(() => handleNotch(true), 300);
157
+ setTimeout(() => handleNotch(true), 500);
158
+ setTimeout(() => handleNotch(true), 1000);
159
+ setTimeout(() => handleNotch(true), 2000);
160
+ }
161
+
162
+ // Event listeners
163
+ window.addEventListener("orientationchange", () => {
164
+ updateLandscapeLock();
165
+ triggerNotch();
166
+ });
167
+
168
+ window.addEventListener("resize", () => {
169
+ updateLandscapeLock();
170
+ triggerNotch();
171
+ });
172
+
173
+ if (screen.orientation) {
174
+ screen.orientation.addEventListener("change", triggerNotch);
175
+ }
176
+
177
+ // Multiple initialization points
178
+ if (document.readyState === "loading") {
179
+ document.addEventListener("DOMContentLoaded", initNotchHandling);
180
+ } else {
181
+ initNotchHandling();
182
+ }
183
+
184
+ window.addEventListener("load", initNotchHandling);
185
+
186
+ document.addEventListener("visibilitychange", () => {
187
+ if (!document.hidden) {
188
+ setTimeout(handleNotch, 100);
189
+ }
190
+ });
191
+
192
+ window.addEventListener("focus", () => {
193
+ setTimeout(handleNotch, 100);
194
+ });
195
+
196
+ // Watch for ios-wrapper elements appearing in DOM
197
+ const observer = new MutationObserver((mutations) => {
198
+ let shouldTrigger = false;
199
+
200
+ mutations.forEach((mutation) => {
201
+ if (mutation.type === "childList") {
202
+ mutation.addedNodes.forEach((node) => {
203
+ if (node.nodeType === Node.ELEMENT_NODE) {
204
+ if (node.classList?.contains("ios-wrapper") || node.querySelector?.(".ios-wrapper")) {
205
+ shouldTrigger = true;
206
+ }
207
+ }
208
+ });
209
+ }
210
+ });
211
+
212
+ if (shouldTrigger) {
213
+ setTimeout(() => handleNotch(true), 10);
214
+ setTimeout(() => handleNotch(true), 100);
215
+ }
216
+ });
217
+
218
+ if (document.body) {
219
+ observer.observe(document.body, {
220
+ childList: true,
221
+ subtree: true
222
+ });
223
+ } else {
224
+ document.addEventListener("DOMContentLoaded", () => {
225
+ observer.observe(document.body, {
226
+ childList: true,
227
+ subtree: true
228
+ });
229
+ });
230
+ }
231
+
232
+ // Navigation handling
233
+ const originalPushState = history.pushState;
234
+ const originalReplaceState = history.replaceState;
235
+
236
+ history.pushState = function (...args) {
237
+ originalPushState.apply(this, args);
238
+ triggerNotch();
239
+ };
240
+
241
+ history.replaceState = function (...args) {
242
+ originalReplaceState.apply(this, args);
243
+ triggerNotch();
244
+ };
245
+
246
+ window.addEventListener("popstate", triggerNotch);
247
+
248
+ // Expose for manual triggering
249
+ window.simulateRotate = handleNotch;
250
+
251
+ // Initial landscape lock check
252
+ updateLandscapeLock();
253
+
254
+ // Vue-specific watchers
255
+ onMounted(() => {
256
+ let attempts = 0;
257
+ const maxAttempts = 5;
258
+ const delays = [0, 50, 150, 300, 500];
259
+
260
+ const scheduleNextAttempt = (index) => {
261
+ if (index >= maxAttempts) return;
262
+ setTimeout(() => {
263
+ handleNotch();
264
+ scheduleNextAttempt(index + 1);
265
+ }, delays[index]);
266
+ };
267
+
268
+ scheduleNextAttempt(0);
269
+ });
270
+
271
+ if (router) {
272
+ watch(
273
+ () => router.currentRoute.value.name,
274
+ () => {
275
+ handleNotch();
276
+ triggerNotch();
277
+
278
+ setTimeout(handleNotch, 10);
279
+ setTimeout(handleNotch, 50);
280
+ setTimeout(handleNotch, 150);
281
+ setTimeout(handleNotch, 300);
282
+ setTimeout(handleNotch, 500);
283
+ }
284
+ );
285
+
286
+ watch(
287
+ () => router.currentRoute.value.path,
288
+ () => {
289
+ handleNotch();
290
+ triggerNotch();
291
+
292
+ setTimeout(handleNotch, 25);
293
+ setTimeout(handleNotch, 100);
294
+ setTimeout(handleNotch, 250);
295
+ }
296
+ );
297
+ }
298
+
299
+ return {
300
+ showLandscapeLock,
301
+ handleNotch,
302
+ triggerNotch,
303
+ updateLandscapeLock,
304
+ isLandscapeMode
305
+ };
306
+ }
@@ -12,7 +12,6 @@ export function useRowSelection(toggleCallback) {
12
12
  const DOUBLE_TAP_DELAY = 300
13
13
 
14
14
  const handleDoubleClick = (event) => {
15
- // Don't trigger on button or checkbox clicks
16
15
  if (event.target.closest('button') || event.target.closest('.checkbox')) {
17
16
  return
18
17
  }
@@ -24,7 +23,6 @@ export function useRowSelection(toggleCallback) {
24
23
  const tapGap = currentTime - lastTapTime
25
24
 
26
25
  if (tapGap < DOUBLE_TAP_DELAY && tapGap > 0) {
27
- // Don't trigger on button or checkbox taps
28
26
  if (!event.target.closest('button') && !event.target.closest('.checkbox')) {
29
27
  event.preventDefault()
30
28
  toggleCallback()
@@ -34,7 +32,6 @@ export function useRowSelection(toggleCallback) {
34
32
  }
35
33
 
36
34
  const handleTouchEnd = (event) => {
37
- // Prevent default touch behavior on buttons/checkboxes
38
35
  if (event.target.closest('button') || event.target.closest('.checkbox')) {
39
36
  return
40
37
  }
@@ -0,0 +1,23 @@
1
+ import { ref, computed } from 'vue';
2
+
3
+ export function useTableRender(items) {
4
+ const i = ref({});
5
+
6
+ const toRender = computed(() => {
7
+ let c = 0;
8
+ const rendered = items.value.map((t) => ({ ...t, index: c++ }));
9
+
10
+ rendered.forEach((t) => {
11
+ if (t.id && !(t.id in i.value)) {
12
+ i.value[t.id] = 0;
13
+ }
14
+ if (!(t.index in i.value)) {
15
+ i.value[t.index] = 0;
16
+ }
17
+ });
18
+
19
+ return rendered;
20
+ });
21
+
22
+ return { toRender };
23
+ }
@@ -0,0 +1,16 @@
1
+ export function useTicketPricing() {
2
+ const isTotalPrice = (line, index, lines) => {
3
+ const trimmed = line.trim();
4
+ if (!trimmed) return false;
5
+
6
+ const nonEmptyLines = lines.filter(l => l.trim());
7
+ const isLastLine = index === lines.lastIndexOf(nonEmptyLines[nonEmptyLines.length - 1]);
8
+
9
+ if (!isLastLine) return false;
10
+
11
+ const totalPricePattern = /^([$€£¥₹₽¢]|[A-Z]{3})\s*[\d,]+\.?\d*$/;
12
+ return totalPricePattern.test(trimmed) && !trimmed.includes('(') && !trimmed.includes(')');
13
+ };
14
+
15
+ return { isTotalPrice };
16
+ }
@@ -0,0 +1,21 @@
1
+ import { ref, onMounted, onUnmounted } from "vue";
2
+
3
+ export function useWindowDimensions() {
4
+ const windowHeight = ref(window.innerHeight);
5
+ const windowWidth = ref(window.innerWidth);
6
+
7
+ const updateDimensions = () => {
8
+ windowHeight.value = window.innerHeight;
9
+ windowWidth.value = window.innerWidth;
10
+ };
11
+
12
+ onMounted(() => {
13
+ window.addEventListener("resize", updateDimensions);
14
+ });
15
+
16
+ onUnmounted(() => {
17
+ window.removeEventListener("resize", updateDimensions);
18
+ });
19
+
20
+ return { windowHeight, windowWidth };
21
+ }
@@ -0,0 +1,96 @@
1
+ export function useZoomPrevention() {
2
+ const KEY_CODES = {
3
+ ESCAPE: 27,
4
+ EQUAL: 61,
5
+ NUMPAD_PLUS: 107,
6
+ FIREFOX_MINUS: 173,
7
+ NUMPAD_MINUS: 109,
8
+ CHROME_EQUAL: 187,
9
+ MINUS: 189
10
+ };
11
+
12
+ // Prevent pinch-to-zoom gestures
13
+ document.addEventListener('touchstart', (e) => {
14
+ if (e.touches.length > 1) {
15
+ e.preventDefault();
16
+ }
17
+ }, { passive: false });
18
+
19
+ document.addEventListener('touchmove', (e) => {
20
+ if (e.touches.length > 1) {
21
+ e.preventDefault();
22
+ }
23
+ }, { passive: false });
24
+
25
+ document.addEventListener('gesturestart', (e) => {
26
+ e.preventDefault();
27
+ }, { passive: false });
28
+
29
+ document.addEventListener('gesturechange', (e) => {
30
+ e.preventDefault();
31
+ }, { passive: false });
32
+
33
+ document.addEventListener('gestureend', (e) => {
34
+ e.preventDefault();
35
+ }, { passive: false });
36
+
37
+ // Prevent double-tap zoom
38
+ let lastTouchEnd = 0;
39
+ document.addEventListener('touchend', (e) => {
40
+ const now = Date.now();
41
+ if (now - lastTouchEnd <= 300) {
42
+ e.preventDefault();
43
+ }
44
+ lastTouchEnd = now;
45
+ }, { passive: false });
46
+
47
+ // Prevent ALL keyboard zoom combinations
48
+ document.addEventListener("keydown", function (event) {
49
+ if (
50
+ (event.ctrlKey || event.metaKey) &&
51
+ (event.which === KEY_CODES.EQUAL ||
52
+ event.which === KEY_CODES.NUMPAD_PLUS ||
53
+ event.which === KEY_CODES.FIREFOX_MINUS ||
54
+ event.which === KEY_CODES.NUMPAD_MINUS ||
55
+ event.which === KEY_CODES.CHROME_EQUAL ||
56
+ event.which === KEY_CODES.MINUS ||
57
+ event.keyCode === KEY_CODES.EQUAL ||
58
+ event.keyCode === KEY_CODES.NUMPAD_PLUS ||
59
+ event.keyCode === KEY_CODES.FIREFOX_MINUS ||
60
+ event.keyCode === KEY_CODES.NUMPAD_MINUS ||
61
+ event.keyCode === KEY_CODES.CHROME_EQUAL ||
62
+ event.keyCode === KEY_CODES.MINUS ||
63
+ event.key === '+' ||
64
+ event.key === '-' ||
65
+ event.key === '=' ||
66
+ event.key === '0')
67
+ ) {
68
+ event.preventDefault();
69
+ }
70
+ }, { passive: false });
71
+
72
+ // Prevent Ctrl/Cmd + Mouse wheel zoom (desktop)
73
+ document.addEventListener("wheel", function (event) {
74
+ if (event.ctrlKey || event.metaKey) {
75
+ event.preventDefault();
76
+ }
77
+ }, { passive: false });
78
+
79
+ // Also block mousewheel for older browsers
80
+ document.addEventListener("mousewheel", function (event) {
81
+ if (event.ctrlKey || event.metaKey) {
82
+ event.preventDefault();
83
+ }
84
+ }, { passive: false });
85
+
86
+ // Block DOMMouseScroll for Firefox
87
+ document.addEventListener("DOMMouseScroll", function (event) {
88
+ if (event.ctrlKey || event.metaKey) {
89
+ event.preventDefault();
90
+ }
91
+ }, { passive: false });
92
+
93
+ return {
94
+ KEY_CODES
95
+ };
96
+ }
@@ -0,0 +1,14 @@
1
+ export const TABLE_LAYOUT = {
2
+ PROFILES: {
3
+ TOP_RESERVED_SPACE: 180,
4
+ BOTTOM_BUFFER: 40,
5
+ ROW_HEIGHT: 64,
6
+ MIN_ROWS_TO_SHOW: 2
7
+ },
8
+ ACCOUNTS: {
9
+ TOP_RESERVED_SPACE: 180,
10
+ BOTTOM_BUFFER: 50,
11
+ ROW_HEIGHT: 64,
12
+ MIN_ROWS_TO_SHOW: 2
13
+ }
14
+ };
@@ -1,5 +1,5 @@
1
- const debug = false;
2
- const log = (...args) => debug && console.log("[filter]", ...args);
1
+ import { DEBUG } from "@/utils/debug";
2
+ const log = (...args) => DEBUG && console.log("[filter]", ...args);
3
3
 
4
4
  const colors = {
5
5
  HIGHLIGHT: "#d3f8e2",
@@ -30,27 +30,23 @@ const isWheelchair = (p) => {
30
30
  };
31
31
 
32
32
  const sortAlphaNum = (a, b) => {
33
- var reA = /[^a-zA-Z]/g;
34
- var reN = /[^0-9]/g;
35
- var AInt = parseInt(a, 10);
36
- var BInt = parseInt(b, 10);
33
+ const reA = /[^a-zA-Z]/g;
34
+ const reN = /[^0-9]/g;
35
+ const AInt = parseInt(a, 10);
36
+ const BInt = parseInt(b, 10);
37
37
 
38
38
  if (isNaN(AInt) && isNaN(BInt)) {
39
- var aA = a.replace(reA, "");
40
- var bA = b.replace(reA, "");
39
+ const aA = a.replace(reA, "");
40
+ const bA = b.replace(reA, "");
41
41
  if (aA === bA) {
42
- var aN = parseInt(a.replace(reN, ""), 10);
43
- var bN = parseInt(b.replace(reN, ""), 10);
42
+ const aN = parseInt(a.replace(reN, ""), 10);
43
+ const bN = parseInt(b.replace(reN, ""), 10);
44
44
  return aN === bN ? 0 : aN > bN ? 1 : -1;
45
45
  } else {
46
46
  return aA > bA ? 1 : -1;
47
47
  }
48
- } else if (isNaN(AInt)) {
49
- //A is not an Int
50
- return 1; //to make alphanumeric sort first return -1 here
51
48
  } else if (isNaN(BInt)) {
52
- //B is not an Int
53
- return -1; //to make alphanumeric sort first return 1 here
49
+ return -1;
54
50
  } else {
55
51
  return AInt > BInt ? 1 : -1;
56
52
  }
@@ -313,7 +309,7 @@ export default class FilterBuilder {
313
309
  });
314
310
 
315
311
  if (existingFilter) {
316
- console.log("Filter already exists:", existingFilter);
312
+ if (DEBUG) log("Filter already exists:", existingFilter);
317
313
  return; // Don't add the filter if it already exists
318
314
  }
319
315
 
@@ -385,7 +381,7 @@ export default class FilterBuilder {
385
381
  } else {
386
382
  color = this.expandedFilter === filter.id ? colors.SELECTED_EXPANDED : colors.SELECTED;
387
383
  }
388
-
384
+
389
385
  switch (type) {
390
386
  case this.filterTypes.NORMAL:
391
387
  // If it has no 'rows' property
@@ -416,7 +412,6 @@ export default class FilterBuilder {
416
412
  break;
417
413
 
418
414
  case this.filterTypes.CATCH_ALL_FLOOR:
419
- // this.cssClasses += floors.map((f) => `path[name="${f}"] {fill: ${color} !important;}`).join("\n") + "\n";
420
415
  break;
421
416
 
422
417
  case this.filterTypes.INVALID:
@@ -432,7 +427,7 @@ export default class FilterBuilder {
432
427
  const color = colors.UNSELECTABLE;
433
428
  this.cssClasses += `.svg-wrapper path[section="${section}"][row="${row}"] {stroke: ${color} !important;}\n`;
434
429
  });
435
-
430
+
436
431
  log("Generated CSS:", this.cssClasses);
437
432
  }
438
433
 
@@ -533,7 +528,6 @@ export default class FilterBuilder {
533
528
 
534
529
  deleteFilterById(id) {
535
530
  this.filters = this.filters.filter((f) => f.id !== id);
536
- // this.updateHooks = this.updateHooks.filter((i) => id !== i);
537
531
  if (this.expandedFilter === id) this.expandedFilter = "";
538
532
  this.updateCss();
539
533
  this.updateHooks.forEach((fn) => fn());
@@ -1,7 +1,6 @@
1
1
  export default (function (f) {
2
2
  const panzoom = f();
3
3
  window.panzoom = panzoom;
4
- // module.exports = panzoom;
5
4
  return panzoom;
6
5
  })(function () {
7
6
  var define, module, exports;
@@ -718,7 +717,6 @@ export default (function (f) {
718
717
  failTransformOrigin();
719
718
  }
720
719
  function failTransformOrigin(options) {
721
- console.error(options);
722
720
  throw new Error(
723
721
  [
724
722
  "Cannot parse transform origin.",
@@ -783,7 +781,6 @@ export default (function (f) {
783
781
  setTimeout(tryAttach, 100);
784
782
  return;
785
783
  }
786
- console.error("Cannot find the panzoom element", globalName);
787
784
  return;
788
785
  }
789
786
  var options = collectOptions(panzoomScript);
@@ -1107,8 +1104,7 @@ export default (function (f) {
1107
1104
  var easing = typeof options.easing === "function" ? options.easing : animations[options.easing];
1108
1105
  if (!easing) {
1109
1106
  if (options.easing) {
1110
- console.warn("Unknown easing function in amator: " + options.easing);
1111
- }
1107
+ }
1112
1108
  easing = animations.ease;
1113
1109
  }
1114
1110
  var step = typeof options.step === "function" ? options.step : noop;
@@ -0,0 +1,58 @@
1
+ const removeDuplicates = (arr) => [...new Set(arr)];
2
+
3
+ function betterSort(a, b) {
4
+ if (a === undefined || a === null) return b === undefined || b === null ? 0 : -1;
5
+ if (b === undefined || b === null) return 1;
6
+
7
+ const aStr = String(a);
8
+ const bStr = String(b);
9
+
10
+ if (!isNaN(aStr) && !isNaN(bStr)) {
11
+ return Number(aStr) - Number(bStr);
12
+ }
13
+
14
+ const aParts = aStr.split(/(\d+)/).filter(Boolean);
15
+ const bParts = bStr.split(/(\d+)/).filter(Boolean);
16
+
17
+ const len = Math.min(aParts.length, bParts.length);
18
+ for (let i = 0; i < len; i++) {
19
+ if (!isNaN(aParts[i]) && !isNaN(bParts[i])) {
20
+ const numA = parseInt(aParts[i], 10);
21
+ const numB = parseInt(bParts[i], 10);
22
+ if (numA !== numB) return numA - numB;
23
+ } else {
24
+ const cmp = aParts[i].localeCompare(bParts[i]);
25
+ if (cmp !== 0) return cmp;
26
+ }
27
+ }
28
+
29
+ return aParts.length - bParts.length;
30
+ }
31
+
32
+ function sortTaskIds(a, b) {
33
+ const parseId = (id) => {
34
+ if (!id) return { prefix: "", num: -1 };
35
+
36
+ if (/^\d+$/.test(id)) {
37
+ return { prefix: "", num: parseInt(id, 10) };
38
+ }
39
+
40
+ const match = id.match(/^([A-Za-z-]+)(\d+)$/);
41
+ if (match) {
42
+ return { prefix: match[1], num: parseInt(match[2], 10) };
43
+ }
44
+
45
+ return { prefix: id, num: -1 };
46
+ };
47
+
48
+ const aInfo = parseId(a);
49
+ const bInfo = parseId(b);
50
+
51
+ if (aInfo.prefix !== bInfo.prefix) {
52
+ return aInfo.prefix.localeCompare(bInfo.prefix);
53
+ }
54
+
55
+ return aInfo.num - bInfo.num;
56
+ }
57
+
58
+ export { removeDuplicates, betterSort, sortTaskIds };