@necrolab/dashboard 0.5.15 → 0.5.16
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.
- package/backend/api.js +2 -3
- package/eslint.config.js +46 -0
- package/index.html +2 -1
- package/package.json +5 -2
- package/src/App.vue +140 -170
- package/src/assets/css/base/mixins.scss +72 -0
- package/src/assets/css/base/reset.scss +0 -2
- package/src/assets/css/base/scroll.scss +43 -36
- package/src/assets/css/base/typography.scss +9 -10
- package/src/assets/css/base/variables.scss +43 -0
- package/src/assets/css/components/accessibility.scss +37 -0
- package/src/assets/css/components/buttons.scss +58 -15
- package/src/assets/css/components/forms.scss +31 -32
- package/src/assets/css/components/headers.scss +12 -20
- package/src/assets/css/components/modals.scss +2 -2
- package/src/assets/css/components/search-groups.scss +28 -22
- package/src/assets/css/components/tables.scss +5 -7
- package/src/assets/css/components/toasts.scss +7 -7
- package/src/assets/css/components/utilities.scss +220 -0
- package/src/assets/css/main.scss +66 -77
- package/src/components/Auth/LoginForm.vue +5 -84
- package/src/components/Editors/Account/Account.vue +8 -10
- package/src/components/Editors/Account/AccountCreator.vue +28 -59
- package/src/components/Editors/Account/AccountView.vue +38 -86
- package/src/components/Editors/Account/CreateAccount.vue +8 -50
- package/src/components/Editors/Profile/CreateProfile.vue +74 -131
- package/src/components/Editors/Profile/Profile.vue +15 -17
- package/src/components/Editors/Profile/ProfileCountryChooser.vue +16 -60
- package/src/components/Editors/Profile/ProfileView.vue +46 -96
- package/src/components/Editors/TagLabel.vue +16 -55
- package/src/components/Editors/TagToggle.vue +20 -8
- package/src/components/Filter/Filter.vue +62 -75
- package/src/components/Filter/FilterPreview.vue +161 -135
- package/src/components/Filter/PriceSortToggle.vue +36 -43
- package/src/components/Table/Header.vue +1 -1
- package/src/components/Table/Table.vue +45 -51
- package/src/components/Tasks/CheckStock.vue +7 -16
- package/src/components/Tasks/Controls/DesktopControls.vue +15 -60
- package/src/components/Tasks/Controls/MobileControls.vue +5 -20
- package/src/components/Tasks/CreateTaskAXS.vue +20 -118
- package/src/components/Tasks/CreateTaskTM.vue +33 -189
- package/src/components/Tasks/EventDetailRow.vue +21 -0
- package/src/components/Tasks/MassEdit.vue +6 -16
- package/src/components/Tasks/QuickSettings.vue +140 -216
- package/src/components/Tasks/ScrapeVenue.vue +4 -13
- package/src/components/Tasks/Stats.vue +19 -38
- package/src/components/Tasks/Task.vue +65 -268
- package/src/components/Tasks/TaskLabel.vue +9 -3
- package/src/components/Tasks/TaskView.vue +43 -63
- package/src/components/Tasks/Utilities.vue +10 -44
- package/src/components/Tasks/ViewTask.vue +23 -107
- package/src/components/icons/Close.vue +2 -8
- package/src/components/icons/Gear.vue +8 -8
- package/src/components/icons/Hash.vue +5 -0
- package/src/components/icons/Key.vue +2 -8
- package/src/components/icons/Pencil.vue +2 -8
- package/src/components/icons/Profile.vue +2 -8
- package/src/components/icons/Sell.vue +2 -8
- package/src/components/icons/Spinner.vue +4 -7
- package/src/components/icons/SquareCheck.vue +2 -8
- package/src/components/icons/SquareUncheck.vue +2 -8
- package/src/components/icons/Wildcard.vue +2 -8
- package/src/components/icons/index.js +3 -1
- package/src/components/ui/ActionButtonGroup.vue +113 -52
- package/src/components/ui/BalanceIndicator.vue +60 -0
- package/src/components/ui/EmptyState.vue +24 -0
- package/src/components/ui/EnableDisableToggle.vue +23 -0
- package/src/components/ui/FormField.vue +48 -48
- package/src/components/ui/IconLabel.vue +23 -0
- package/src/components/ui/InfoRow.vue +21 -54
- package/src/components/ui/Modal.vue +89 -56
- package/src/components/ui/Navbar.vue +60 -41
- package/src/components/ui/ReadonlyFieldsSection.vue +31 -0
- package/src/components/ui/ReconnectIndicator.vue +111 -124
- package/src/components/ui/SectionCard.vue +6 -14
- package/src/components/ui/Splash.vue +2 -10
- package/src/components/ui/StatusBadge.vue +26 -28
- package/src/components/ui/TaskToggle.vue +54 -0
- package/src/components/ui/controls/CountryChooser.vue +27 -64
- package/src/components/ui/controls/EyeToggle.vue +1 -1
- package/src/components/ui/controls/atomic/Checkbox.vue +40 -121
- package/src/components/ui/controls/atomic/Dropdown.vue +103 -139
- package/src/components/ui/controls/atomic/MultiDropdown.vue +71 -119
- package/src/components/ui/controls/atomic/Switch.vue +21 -84
- package/src/composables/useColorMapping.js +15 -0
- package/src/composables/useCopyToClipboard.js +1 -1
- package/src/composables/useDateFormatting.js +21 -0
- package/src/composables/useDeviceDetection.js +14 -0
- package/src/composables/useDropdownPosition.js +3 -4
- package/src/composables/useDynamicTableHeight.js +31 -0
- package/src/composables/useRowSelection.js +0 -3
- package/src/composables/useTicketPricing.js +16 -0
- package/src/composables/useWindowDimensions.js +21 -0
- package/src/libs/Filter.js +14 -20
- package/src/libs/panzoom.js +1 -5
- package/src/libs/utils/array.js +60 -0
- package/src/{stores/utils.js → libs/utils/dataGeneration.js} +2 -250
- package/src/libs/utils/eventUrl.js +40 -0
- package/src/libs/utils/string.js +28 -0
- package/src/libs/utils/time.js +20 -0
- package/src/libs/utils/validation.js +88 -0
- package/src/main.js +0 -2
- package/src/stores/connection.js +1 -4
- package/src/stores/logger.js +6 -12
- package/src/stores/sampleData.js +1 -2
- package/src/stores/ui.js +59 -36
- package/src/views/Accounts.vue +13 -24
- package/src/views/Console.vue +70 -172
- package/src/views/Editor.vue +211 -379
- package/src/views/FilterBuilder.vue +188 -371
- package/src/views/Login.vue +3 -28
- package/src/views/Profiles.vue +8 -15
- package/src/views/Tasks.vue +49 -36
- package/tailwind.config.js +82 -71
- package/workbox-config.cjs +47 -5
- package/docs/plans/2026-02-08-tailwind-consolidation.md +0 -2438
- package/exit +0 -209
- package/run +0 -177
- package/src/assets/css/base/color-fallbacks.scss +0 -10
- package/switch-branch.sh +0 -41
- /package/public/{reconnect-logo.png → img/reconnect-logo.png} +0 -0
|
@@ -1,96 +1,33 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<label
|
|
3
|
-
|
|
4
|
-
|
|
2
|
+
<label
|
|
3
|
+
class="relative inline-block w-[51px] h-[31px] max-modal:w-11 max-modal:min-w-11 max-modal:h-6.5"
|
|
4
|
+
:class="disabled ? 'pointer-events-none' : ''"
|
|
5
|
+
>
|
|
6
|
+
<input
|
|
7
|
+
type="checkbox"
|
|
8
|
+
v-model="value"
|
|
9
|
+
:disabled="disabled"
|
|
10
|
+
class="opacity-0 w-0 h-0 peer"
|
|
11
|
+
role="switch"
|
|
12
|
+
:aria-checked="value"
|
|
13
|
+
/>
|
|
14
|
+
<span
|
|
15
|
+
class="absolute inset-0 cursor-pointer border-2 rounded-[31px] transition-all duration-300 ease-out
|
|
16
|
+
before:absolute before:content-[''] before:size-[23px] before:left-0.5 before:bottom-0.5 before:rounded-full before:shadow-switch before:transition-all before:duration-300 before:ease-out
|
|
17
|
+
bg-dark-550 border-dark-550 before:bg-dark-200
|
|
18
|
+
peer-checked:bg-accent-green peer-checked:border-accent-green peer-checked:before:bg-white peer-checked:before:translate-x-5
|
|
19
|
+
peer-disabled:opacity-50 peer-disabled:cursor-not-allowed peer-disabled:before:opacity-70
|
|
20
|
+
max-modal:before:size-[22px] max-modal:peer-checked:before:translate-x-[18px]"
|
|
21
|
+
></span>
|
|
5
22
|
</label>
|
|
6
23
|
</template>
|
|
7
24
|
|
|
8
25
|
<script setup>
|
|
9
26
|
const value = defineModel();
|
|
10
|
-
|
|
27
|
+
defineProps({
|
|
11
28
|
disabled: {
|
|
12
29
|
type: Boolean,
|
|
13
30
|
default: false
|
|
14
31
|
}
|
|
15
32
|
});
|
|
16
33
|
</script>
|
|
17
|
-
|
|
18
|
-
<style lang="scss" scoped>
|
|
19
|
-
/* iOS-style switch */
|
|
20
|
-
.switch {
|
|
21
|
-
@apply relative inline-block;
|
|
22
|
-
width: 51px;
|
|
23
|
-
height: 31px;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
/* Hide default HTML checkbox */
|
|
27
|
-
.switch input {
|
|
28
|
-
@apply opacity-0 w-0 h-0;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
/* The slider */
|
|
32
|
-
.slider {
|
|
33
|
-
@apply absolute cursor-pointer inset-0;
|
|
34
|
-
@apply border-2;
|
|
35
|
-
background-color: oklch(0.26 0 0);
|
|
36
|
-
border-color: oklch(0.35 0 0);
|
|
37
|
-
transition: 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
.slider:before {
|
|
41
|
-
@apply absolute;
|
|
42
|
-
@apply w-[23px] h-[23px] left-0.5 bottom-0.5;
|
|
43
|
-
content: "";
|
|
44
|
-
background-color: oklch(0.50 0 0);
|
|
45
|
-
transition: 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
|
46
|
-
box-shadow: 0 1px 3px oklch(0 0 0 / 0.3);
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
input:checked + .slider {
|
|
50
|
-
background-color: oklch(0.72 0.15 145);
|
|
51
|
-
border-color: oklch(0.72 0.15 145);
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
input:checked + .slider:before {
|
|
55
|
-
background-color: oklch(1 0 0);
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
input:checked + .slider:before {
|
|
59
|
-
transform: translateX(20px);
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
.switch.disabled {
|
|
63
|
-
@apply pointer-events-none;
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
input:disabled + .slider {
|
|
67
|
-
@apply opacity-50 cursor-not-allowed;
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
input:disabled + .slider:before {
|
|
71
|
-
@apply opacity-70;
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
/* Rounded sliders */
|
|
75
|
-
.slider.round {
|
|
76
|
-
border-radius: 31px;
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
.slider.round:before {
|
|
80
|
-
border-radius: 50%;
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
@media (max-width: 810px) {
|
|
84
|
-
.switch {
|
|
85
|
-
@apply w-11 min-w-11 h-[26px];
|
|
86
|
-
|
|
87
|
-
.slider:before {
|
|
88
|
-
@apply w-[22px] h-[22px] left-0.5 bottom-0.5;
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
input:checked + .slider:before {
|
|
93
|
-
@apply translate-x-[18px];
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
</style>
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export function useColorMapping() {
|
|
2
|
+
const colorToClass = (color) => {
|
|
3
|
+
const colorMap = {
|
|
4
|
+
green: "bg-green-400",
|
|
5
|
+
red: "bg-red-400",
|
|
6
|
+
yellow: "bg-yellow-400",
|
|
7
|
+
blue: "bg-blue-400",
|
|
8
|
+
error: "bg-red-400",
|
|
9
|
+
success: "bg-green-400"
|
|
10
|
+
};
|
|
11
|
+
return colorMap[color?.toLowerCase()] || "bg-white";
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
return { colorToClass };
|
|
15
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export function useDateFormatting() {
|
|
2
|
+
const formatEventDate = (dateString) => {
|
|
3
|
+
if (!dateString) return '';
|
|
4
|
+
try {
|
|
5
|
+
const date = new Date(dateString);
|
|
6
|
+
const options = {
|
|
7
|
+
month: 'short',
|
|
8
|
+
day: 'numeric',
|
|
9
|
+
year: 'numeric',
|
|
10
|
+
hour: 'numeric',
|
|
11
|
+
minute: '2-digit',
|
|
12
|
+
hour12: true
|
|
13
|
+
};
|
|
14
|
+
return date.toLocaleString('en-US', options).replace(',', '');
|
|
15
|
+
} catch {
|
|
16
|
+
return dateString;
|
|
17
|
+
}
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
return { formatEventDate };
|
|
21
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export function useDeviceDetection() {
|
|
2
|
+
const isIOS = () => {
|
|
3
|
+
if (/iPad|iPhone|iPod/.test(navigator.platform)) {
|
|
4
|
+
return true;
|
|
5
|
+
}
|
|
6
|
+
return navigator.maxTouchPoints && navigator.maxTouchPoints > 2 && /MacIntel/.test(navigator.platform);
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
const isIpadOS = () => {
|
|
10
|
+
return navigator.maxTouchPoints && navigator.maxTouchPoints > 2 && /MacIntel/.test(navigator.platform);
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
return { isIOS, isIpadOS };
|
|
14
|
+
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { ref, nextTick, onMounted, onUnmounted } from "vue";
|
|
2
|
+
import { DEBUG } from "@/utils/debug";
|
|
2
3
|
|
|
3
4
|
export function useDropdownPosition(dropdownRef, options = {}) {
|
|
4
5
|
const menuStyle = ref({});
|
|
@@ -8,8 +9,7 @@ export function useDropdownPosition(dropdownRef, options = {}) {
|
|
|
8
9
|
minWidth = null,
|
|
9
10
|
maxHeight = window.innerHeight * 0.8, // Use 80% of viewport height
|
|
10
11
|
estimateHeight = null,
|
|
11
|
-
includeAdjacentButtons = false
|
|
12
|
-
containerSelector = null
|
|
12
|
+
includeAdjacentButtons = false
|
|
13
13
|
} = options;
|
|
14
14
|
|
|
15
15
|
const calculateMenuPosition = () => {
|
|
@@ -109,8 +109,7 @@ export function useDropdownPosition(dropdownRef, options = {}) {
|
|
|
109
109
|
maxHeight: `${maxHeight}px`
|
|
110
110
|
};
|
|
111
111
|
} catch (error) {
|
|
112
|
-
console.warn("Error calculating dropdown position:", error);
|
|
113
|
-
// Fallback to basic positioning
|
|
112
|
+
if (DEBUG) console.warn("Error calculating dropdown position:", error);
|
|
114
113
|
menuStyle.value = {
|
|
115
114
|
position: "fixed",
|
|
116
115
|
top: "0px",
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { computed } from "vue";
|
|
2
|
+
import { useWindowDimensions } from "./useWindowDimensions";
|
|
3
|
+
|
|
4
|
+
export function useDynamicTableHeight(options = {}) {
|
|
5
|
+
const { windowHeight, windowWidth } = useWindowDimensions();
|
|
6
|
+
|
|
7
|
+
const {
|
|
8
|
+
topReservedSpace = 243,
|
|
9
|
+
bottomBuffer = 16,
|
|
10
|
+
rowHeight = 64,
|
|
11
|
+
minRowsToShow = 2
|
|
12
|
+
} = options;
|
|
13
|
+
|
|
14
|
+
const dynamicTableHeight = computed(() => {
|
|
15
|
+
// Detect PWA mode and small screens
|
|
16
|
+
const isPWA = window.matchMedia('(display-mode: standalone)').matches;
|
|
17
|
+
const isMobile = windowWidth.value <= 768;
|
|
18
|
+
|
|
19
|
+
// Extra buffer for iPhone PWA to prevent overflow
|
|
20
|
+
const extraBuffer = isPWA && isMobile ? 60 : 0;
|
|
21
|
+
|
|
22
|
+
const availableHeight = windowHeight.value - topReservedSpace - bottomBuffer - extraBuffer;
|
|
23
|
+
const minHeight = minRowsToShow * rowHeight;
|
|
24
|
+
const maxCompleteRows = Math.floor(Math.max(availableHeight, minHeight) / rowHeight);
|
|
25
|
+
const exactHeight = maxCompleteRows * rowHeight;
|
|
26
|
+
|
|
27
|
+
return exactHeight + "px";
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
return { dynamicTableHeight };
|
|
31
|
+
}
|
|
@@ -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,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
|
+
}
|
package/src/libs/Filter.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
const log = (...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
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
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
|
-
|
|
40
|
-
|
|
39
|
+
const aA = a.replace(reA, "");
|
|
40
|
+
const bA = b.replace(reA, "");
|
|
41
41
|
if (aA === bA) {
|
|
42
|
-
|
|
43
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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());
|
package/src/libs/panzoom.js
CHANGED
|
@@ -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
|
-
|
|
1111
|
-
}
|
|
1107
|
+
}
|
|
1112
1108
|
easing = animations.ease;
|
|
1113
1109
|
}
|
|
1114
1110
|
var step = typeof options.step === "function" ? options.step : noop;
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
const removeDuplicates = (arr) => [...new Set(arr)];
|
|
2
|
+
|
|
3
|
+
const pickRandom = (arr) => arr[Math.floor(Math.random() * arr.length)];
|
|
4
|
+
|
|
5
|
+
function betterSort(a, b) {
|
|
6
|
+
if (a === undefined || a === null) return b === undefined || b === null ? 0 : -1;
|
|
7
|
+
if (b === undefined || b === null) return 1;
|
|
8
|
+
|
|
9
|
+
const aStr = String(a);
|
|
10
|
+
const bStr = String(b);
|
|
11
|
+
|
|
12
|
+
if (!isNaN(aStr) && !isNaN(bStr)) {
|
|
13
|
+
return Number(aStr) - Number(bStr);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const aParts = aStr.split(/(\d+)/).filter(Boolean);
|
|
17
|
+
const bParts = bStr.split(/(\d+)/).filter(Boolean);
|
|
18
|
+
|
|
19
|
+
const len = Math.min(aParts.length, bParts.length);
|
|
20
|
+
for (let i = 0; i < len; i++) {
|
|
21
|
+
if (!isNaN(aParts[i]) && !isNaN(bParts[i])) {
|
|
22
|
+
const numA = parseInt(aParts[i], 10);
|
|
23
|
+
const numB = parseInt(bParts[i], 10);
|
|
24
|
+
if (numA !== numB) return numA - numB;
|
|
25
|
+
} else {
|
|
26
|
+
const cmp = aParts[i].localeCompare(bParts[i]);
|
|
27
|
+
if (cmp !== 0) return cmp;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
return aParts.length - bParts.length;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function sortTaskIds(a, b) {
|
|
35
|
+
const parseId = (id) => {
|
|
36
|
+
if (!id) return { prefix: "", num: -1 };
|
|
37
|
+
|
|
38
|
+
if (/^\d+$/.test(id)) {
|
|
39
|
+
return { prefix: "", num: parseInt(id, 10) };
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const match = id.match(/^([A-Za-z-]+)(\d+)$/);
|
|
43
|
+
if (match) {
|
|
44
|
+
return { prefix: match[1], num: parseInt(match[2], 10) };
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
return { prefix: id, num: -1 };
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
const aInfo = parseId(a);
|
|
51
|
+
const bInfo = parseId(b);
|
|
52
|
+
|
|
53
|
+
if (aInfo.prefix !== bInfo.prefix) {
|
|
54
|
+
return aInfo.prefix.localeCompare(bInfo.prefix);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
return aInfo.num - bInfo.num;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export { removeDuplicates, pickRandom, betterSort, sortTaskIds };
|