@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,94 +1,69 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<
|
|
3
|
-
<Header class="grid-cols-
|
|
4
|
-
<div class="col-span-3
|
|
2
|
+
<div class="table-component relative box-border flex flex-col rounded-lg bg-dark-500 bg-clip-padding overflow-hidden shadow-sm">
|
|
3
|
+
<Header class="grid-cols-4 text-center sm:grid-cols-5 md:grid-cols-7 lg:grid-cols-8">
|
|
4
|
+
<div class="col-span-2 sm:col-span-2 md:col-span-3 lg:col-span-2 flex items-center justify-start">
|
|
5
5
|
<Checkbox
|
|
6
|
-
class="mr-
|
|
6
|
+
class="ml-2 mr-4 flex-shrink-0"
|
|
7
7
|
:toggled="ui.mainCheckbox.profiles"
|
|
8
8
|
@valueUpdate="ui.toggleMainCheckbox('profiles')"
|
|
9
9
|
:isHeader="true" />
|
|
10
|
-
<div class="mx-auto flex items-center" @click="ui.toggleSort('eventId')">
|
|
11
|
-
<ProfileIcon class="
|
|
12
|
-
<h4 class="hidden md:flex">Profile Name</h4>
|
|
10
|
+
<div class="mx-auto flex cursor-pointer items-center" @click="ui.toggleSort('eventId')">
|
|
11
|
+
<ProfileIcon class="h-4 w-4" />
|
|
12
|
+
<h4 class="hidden text-white md:flex md:ml-3">Profile Name</h4>
|
|
13
13
|
</div>
|
|
14
14
|
</div>
|
|
15
|
-
<div class="col-span-1 flex items-center justify-center
|
|
16
|
-
<CartIcon class="
|
|
17
|
-
<h4 class="hidden md:flex">Card Number</h4>
|
|
15
|
+
<div class="col-span-1 lg:col-span-2 hidden md:flex items-center justify-center" v-once>
|
|
16
|
+
<CartIcon class="h-4 w-4" />
|
|
17
|
+
<h4 class="hidden text-white md:flex md:ml-3">Card Number</h4>
|
|
18
18
|
</div>
|
|
19
|
-
<div class="col-span-1 flex items-center justify-center" v-once>
|
|
20
|
-
<TimerIcon class="
|
|
21
|
-
<h4 class="hidden md:flex">Expiration</h4>
|
|
19
|
+
<div class="col-span-1 hidden md:flex items-center justify-center" v-once>
|
|
20
|
+
<TimerIcon class="h-4 w-4" />
|
|
21
|
+
<h4 class="hidden text-white md:flex md:ml-3">Expiration</h4>
|
|
22
22
|
</div>
|
|
23
23
|
<div class="col-span-1 flex items-center justify-center" v-once>
|
|
24
|
-
<CheckmarkIcon class="
|
|
25
|
-
<h4 class="hidden md:flex">Enabled</h4>
|
|
24
|
+
<CheckmarkIcon class="h-4 w-4" />
|
|
25
|
+
<h4 class="hidden text-white md:flex md:ml-3">Enabled</h4>
|
|
26
26
|
</div>
|
|
27
|
-
<div class="col-span-1 hidden items-center justify-center
|
|
28
|
-
<TicketIcon class="
|
|
29
|
-
<h4 class="hidden lg:flex">Tags</h4>
|
|
27
|
+
<div class="col-span-1 hidden lg:flex items-center justify-center" v-once>
|
|
28
|
+
<TicketIcon class="h-4 w-4" />
|
|
29
|
+
<h4 class="hidden text-white lg:flex lg:ml-3">Tags</h4>
|
|
30
30
|
</div>
|
|
31
31
|
<div class="col-span-1 flex items-center justify-center" v-once>
|
|
32
|
-
<ClickIcon class="
|
|
33
|
-
<h4 class="hidden md:flex">Actions</h4>
|
|
32
|
+
<ClickIcon class="h-4 w-4" />
|
|
33
|
+
<h4 class="hidden text-white md:flex md:ml-3">Actions</h4>
|
|
34
34
|
</div>
|
|
35
35
|
</Header>
|
|
36
36
|
<div
|
|
37
37
|
v-if="toRender.length != 0"
|
|
38
|
-
class="hidden-scrollbars
|
|
38
|
+
class="hidden-scrollbars flex flex-col divide-y divide-dark-650 overflow-y-auto overflow-x-hidden transition-colors duration-150 table-scroll"
|
|
39
39
|
:style="{ maxHeight: dynamicTableHeight }">
|
|
40
|
-
<div
|
|
40
|
+
<div
|
|
41
|
+
v-for="(profile, i) in toRender"
|
|
42
|
+
:key="profile.id || profile.index"
|
|
43
|
+
class="min-h-16 flex-shrink-0 hover:bg-dark-550">
|
|
41
44
|
<Profile
|
|
42
45
|
:class="i % 2 == 1 ? 'table-row-even' : 'table-row-odd'"
|
|
43
46
|
:profile="profile" />
|
|
44
47
|
</div>
|
|
45
48
|
</div>
|
|
46
|
-
<
|
|
47
|
-
|
|
48
|
-
<p class="text-sm text-light-400">No profiles found</p>
|
|
49
|
-
<p class="mt-1 text-xs text-light-500">Create profiles to get started</p>
|
|
50
|
-
</div>
|
|
51
|
-
</Table>
|
|
49
|
+
<EmptyState v-else :icon="ProfileIcon" message="No profiles found" subtitle="Create profiles to get started" />
|
|
50
|
+
</div>
|
|
52
51
|
</template>
|
|
53
|
-
<style lang="scss" scoped>
|
|
54
|
-
.profile-row-container {
|
|
55
|
-
min-height: 64px;
|
|
56
|
-
flex-shrink: 0;
|
|
57
|
-
transition: background-color 0.15s ease;
|
|
58
|
-
|
|
59
|
-
&:hover {
|
|
60
|
-
@apply bg-dark-550 !important;
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
h4 {
|
|
65
|
-
@apply text-white;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
.stop-pan {
|
|
69
|
-
touch-action: pan-y pan-up pan-down;
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
.max-h-big-prof {
|
|
73
|
-
max-height: calc(100vh - 20rem);
|
|
74
|
-
overflow: hidden;
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
.empty-state {
|
|
78
|
-
font-size: 14px;
|
|
79
|
-
font-weight: 500;
|
|
80
|
-
}
|
|
81
|
-
</style>
|
|
82
52
|
<script setup>
|
|
83
|
-
import {
|
|
53
|
+
import { Header } from "@/components/Table";
|
|
84
54
|
import { CartIcon, TicketIcon, ClickIcon, TimerIcon, ProfileIcon, CheckmarkIcon } from "@/components/icons";
|
|
85
55
|
import Profile from "./Profile.vue";
|
|
86
56
|
import Checkbox from "@/components/ui/controls/atomic/Checkbox.vue";
|
|
57
|
+
import EmptyState from "@/components/ui/EmptyState.vue";
|
|
87
58
|
import { useUIStore } from "@/stores/ui";
|
|
88
|
-
import {
|
|
59
|
+
import { useDynamicTableHeight } from "@/composables/useDynamicTableHeight";
|
|
60
|
+
import { computed, ref } from "vue";
|
|
89
61
|
|
|
90
62
|
const props = defineProps({
|
|
91
|
-
profiles: {
|
|
63
|
+
profiles: {
|
|
64
|
+
type: Object,
|
|
65
|
+
required: true
|
|
66
|
+
}
|
|
92
67
|
});
|
|
93
68
|
|
|
94
69
|
const ui = useUIStore();
|
|
@@ -111,43 +86,18 @@ const toRender = computed(() => {
|
|
|
111
86
|
return rendered;
|
|
112
87
|
});
|
|
113
88
|
|
|
114
|
-
//
|
|
115
|
-
const
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
windowWidth.value = window.innerWidth;
|
|
89
|
+
// Layout constants for dynamic table height calculation
|
|
90
|
+
const LAYOUT_CONSTANTS = {
|
|
91
|
+
TOP_RESERVED_SPACE: 180, // Page header + search controls + gaps (router-wrapper handles navbar, no UTILS section)
|
|
92
|
+
BOTTOM_BUFFER: 40, // Margin at bottom
|
|
93
|
+
ROW_HEIGHT: 64, // Profile row height in pixels
|
|
94
|
+
MIN_ROWS_TO_SHOW: 2 // Minimum number of rows to display
|
|
121
95
|
};
|
|
122
96
|
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
window.removeEventListener("resize", updateDimensions);
|
|
129
|
-
});
|
|
130
|
-
|
|
131
|
-
const dynamicTableHeight = computed(() => {
|
|
132
|
-
// Calculate available space for profiles table with conservative buffer
|
|
133
|
-
const headerHeight = 60; // Header + navbar
|
|
134
|
-
const titleHeight = 50; // Profiles title and controls
|
|
135
|
-
const searchHeight = 50; // Search and filter controls
|
|
136
|
-
const margins = windowWidth.value >= 1024 ? 40 : 25;
|
|
137
|
-
const bufferSpace = 50; // Conservative buffer to prevent partial items
|
|
138
|
-
|
|
139
|
-
const totalUsedSpace = headerHeight + titleHeight + searchHeight + margins + bufferSpace;
|
|
140
|
-
const availableHeight = windowHeight.value - totalUsedSpace;
|
|
141
|
-
|
|
142
|
-
// Profile row height is always 64px
|
|
143
|
-
const rowHeight = 64;
|
|
144
|
-
const minRowsToShow = 2;
|
|
145
|
-
const minHeight = minRowsToShow * rowHeight;
|
|
146
|
-
|
|
147
|
-
// Calculate exact number of complete rows that fit with conservative approach
|
|
148
|
-
const maxCompleteRows = Math.floor(Math.max(availableHeight, minHeight) / rowHeight);
|
|
149
|
-
const exactHeight = maxCompleteRows * rowHeight;
|
|
150
|
-
|
|
151
|
-
return exactHeight + "px";
|
|
97
|
+
const { dynamicTableHeight } = useDynamicTableHeight({
|
|
98
|
+
topReservedSpace: LAYOUT_CONSTANTS.TOP_RESERVED_SPACE,
|
|
99
|
+
bottomBuffer: LAYOUT_CONSTANTS.BOTTOM_BUFFER,
|
|
100
|
+
rowHeight: LAYOUT_CONSTANTS.ROW_HEIGHT,
|
|
101
|
+
minRowsToShow: LAYOUT_CONSTANTS.MIN_ROWS_TO_SHOW
|
|
152
102
|
});
|
|
153
103
|
</script>
|
|
@@ -1,64 +1,25 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<div class="
|
|
3
|
-
|
|
2
|
+
<div class="inline-flex min-w-8 max-w-20 items-center justify-center rounded-full border-2 border-accent-green/25 bg-accent-green/12 px-2.5 py-1
|
|
3
|
+
lg:max-w-16 lg:px-2 lg:py-[3.2px]
|
|
4
|
+
md:max-w-14 md:px-[6.4px] md:py-[3.2px]
|
|
5
|
+
max-md:max-w-12 max-md:px-[5.6px] max-md:py-[2.4px]">
|
|
6
|
+
<span class="truncate text-xs+ font-semibold leading-tight tracking-[0.015em] text-accent-green
|
|
7
|
+
lg:text-2xs
|
|
8
|
+
md:text-[9.6px]
|
|
9
|
+
max-md:text-[9.2px]">
|
|
10
|
+
{{ formatText(props.text) }}
|
|
11
|
+
</span>
|
|
4
12
|
</div>
|
|
5
13
|
</template>
|
|
6
14
|
|
|
7
|
-
<style lang="scss" scoped>
|
|
8
|
-
.tag-pill {
|
|
9
|
-
@apply inline-flex items-center justify-center rounded-full;
|
|
10
|
-
background: oklch(0.72 0.15 145 / 0.12);
|
|
11
|
-
border: 1.5px solid oklch(0.72 0.15 145 / 0.25);
|
|
12
|
-
padding: 0.25rem 0.625rem;
|
|
13
|
-
min-width: 2rem;
|
|
14
|
-
max-width: 5rem;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
.tag-text {
|
|
18
|
-
@apply truncate font-semibold;
|
|
19
|
-
color: oklch(0.72 0.15 145);
|
|
20
|
-
font-size: 0.6875rem;
|
|
21
|
-
line-height: 1.2;
|
|
22
|
-
letter-spacing: 0.015em;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
// Responsive design
|
|
26
|
-
@media (max-width: 1024px) {
|
|
27
|
-
.tag-pill {
|
|
28
|
-
padding: 0.2rem 0.5rem;
|
|
29
|
-
max-width: 4rem;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
.tag-text {
|
|
33
|
-
font-size: 0.625rem;
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
@media (max-width: 768px) {
|
|
38
|
-
.tag-pill {
|
|
39
|
-
padding: 0.1875rem 0.4rem;
|
|
40
|
-
max-width: 3.5rem;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
.tag-text {
|
|
44
|
-
font-size: 0.6rem;
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
@media (max-width: 480px) {
|
|
49
|
-
.tag-pill {
|
|
50
|
-
padding: 0.15rem 0.35rem;
|
|
51
|
-
max-width: 3rem;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
.tag-text {
|
|
55
|
-
font-size: 0.575rem;
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
</style>
|
|
59
15
|
|
|
60
16
|
<script setup>
|
|
61
|
-
const props = defineProps({
|
|
17
|
+
const props = defineProps({
|
|
18
|
+
text: {
|
|
19
|
+
type: String,
|
|
20
|
+
required: true
|
|
21
|
+
}
|
|
22
|
+
});
|
|
62
23
|
|
|
63
24
|
const formatText = (text) => {
|
|
64
25
|
if (!text) return "";
|
|
@@ -10,9 +10,6 @@
|
|
|
10
10
|
<span v-else-if="sortOptions[currentOpt % sortOptions.length] === 'Disabled'"
|
|
11
11
|
><img class="mx-auto" height="16px" width="14px" src="@/assets/img/square_uncheck.svg"
|
|
12
12
|
/></span>
|
|
13
|
-
<!-- <span v-else-if="sortOptions[currentOpt % sortOptions.length] === 'All'"
|
|
14
|
-
><img height="16px" width="14px" src="@/assets/img/wildcard.svg"
|
|
15
|
-
/></span> -->
|
|
16
13
|
<span v-else>{{ sortOptions[currentOpt % sortOptions.length] }}</span>
|
|
17
14
|
</button>
|
|
18
15
|
</template>
|
|
@@ -24,11 +21,26 @@ let sortOptions = ref([]);
|
|
|
24
21
|
const currentOpt = ref(0);
|
|
25
22
|
|
|
26
23
|
const props = defineProps({
|
|
27
|
-
filter:
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
24
|
+
filter: {
|
|
25
|
+
type: Object,
|
|
26
|
+
default: () => ({})
|
|
27
|
+
},
|
|
28
|
+
index: {
|
|
29
|
+
type: Number,
|
|
30
|
+
default: 0
|
|
31
|
+
},
|
|
32
|
+
expandedFilter: {
|
|
33
|
+
type: Number,
|
|
34
|
+
default: null
|
|
35
|
+
},
|
|
36
|
+
filterBuilder: {
|
|
37
|
+
type: Object,
|
|
38
|
+
default: () => ({})
|
|
39
|
+
},
|
|
40
|
+
options: {
|
|
41
|
+
type: Array,
|
|
42
|
+
required: true
|
|
43
|
+
},
|
|
32
44
|
noBorder: {
|
|
33
45
|
type: Boolean,
|
|
34
46
|
default: false
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<div
|
|
2
|
+
<div
|
|
3
3
|
class="filter-card group text-white text-sm transition-all duration-200 hover:bg-dark-400 relative"
|
|
4
4
|
:class="{
|
|
5
5
|
'expanded-filter': filterBuilder.expandedFilter === filter.id,
|
|
@@ -19,7 +19,6 @@
|
|
|
19
19
|
</div>
|
|
20
20
|
</div>
|
|
21
21
|
<div class="expanded-content mt-4 mx-2 sm:mx-0" v-if="filterBuilder.expandedFilter === filter.id">
|
|
22
|
-
<!-- NORMAL -->
|
|
23
22
|
<div v-if="filterType === 2" class="space-y-2">
|
|
24
23
|
<div class="info-row">
|
|
25
24
|
<span class="label">Section:</span>
|
|
@@ -34,7 +33,6 @@
|
|
|
34
33
|
<span class="value">{{ filter?.event || filter?.eventId || "-" }}</span>
|
|
35
34
|
</div>
|
|
36
35
|
</div>
|
|
37
|
-
<!-- NORMAL_FIRSTROW -->
|
|
38
36
|
<div v-if="filterType === 3" class="space-y-2">
|
|
39
37
|
<div class="info-row">
|
|
40
38
|
<span class="label">Section:</span>
|
|
@@ -49,7 +47,6 @@
|
|
|
49
47
|
<span class="value">{{ filter?.event || "-" }}</span>
|
|
50
48
|
</div>
|
|
51
49
|
</div>
|
|
52
|
-
<!-- CATCH_ALL_GA -->
|
|
53
50
|
<div v-if="filterType === 1">
|
|
54
51
|
<button
|
|
55
52
|
@click.stop="update({ buyAny: true, floor: false, generalAdmission: false })"
|
|
@@ -59,7 +56,6 @@
|
|
|
59
56
|
Convert to wildcard
|
|
60
57
|
</button>
|
|
61
58
|
</div>
|
|
62
|
-
<!-- CATCH_ALL -->
|
|
63
59
|
<div v-if="filterType === 0">
|
|
64
60
|
<button
|
|
65
61
|
@click.stop="update({ floor: true, buyAny: false, generalAdmission: false })"
|
|
@@ -69,7 +65,6 @@
|
|
|
69
65
|
Convert to Floor Wildcard
|
|
70
66
|
</button>
|
|
71
67
|
</div>
|
|
72
|
-
<!-- CATCH_ALL_FLOOR -->
|
|
73
68
|
<div v-if="filterType === 5">
|
|
74
69
|
<button
|
|
75
70
|
@click.stop="update({ generalAdmission: true, floor: false, buyAny: false })"
|
|
@@ -131,16 +126,15 @@
|
|
|
131
126
|
</div>
|
|
132
127
|
</div>
|
|
133
128
|
</div>
|
|
134
|
-
<div class="col-span-3 sm:col-span-2 flex justify-end items-center gap-
|
|
135
|
-
<div class="drag-handle handle
|
|
136
|
-
<MenuIcon class="
|
|
129
|
+
<div class="col-span-3 sm:col-span-2 flex justify-end items-center gap-2">
|
|
130
|
+
<div class="drag-handle handle drag-btn cursor-grab active:cursor-grabbing" title="Drag to reorder">
|
|
131
|
+
<MenuIcon class="h-4 w-4" />
|
|
137
132
|
</div>
|
|
138
|
-
<button
|
|
139
|
-
@click="filterBuilder.deleteFilterById(filter.id)"
|
|
140
|
-
class="delete-btn
|
|
141
|
-
title="Delete filter"
|
|
142
|
-
|
|
143
|
-
<TrashIcon class="w-3 h-3 sm:w-4 sm:h-4" />
|
|
133
|
+
<button
|
|
134
|
+
@click="filterBuilder.deleteFilterById(filter.id)"
|
|
135
|
+
class="delete-btn"
|
|
136
|
+
title="Delete filter">
|
|
137
|
+
<TrashIcon class="h-4 w-4" />
|
|
144
138
|
</button>
|
|
145
139
|
</div>
|
|
146
140
|
</div>
|
|
@@ -155,16 +149,27 @@ import { ref } from "vue";
|
|
|
155
149
|
import { useUIStore } from "@/stores/ui";
|
|
156
150
|
const ui = useUIStore();
|
|
157
151
|
|
|
158
|
-
|
|
159
|
-
import { UpIcon, DownIcon, ReloadIcon, TrashIcon, MenuIcon, WildcardIcon, BoxIcon, GroupIcon, FilterIcon, StadiumIcon } from "@/components/icons";
|
|
152
|
+
import { TrashIcon, MenuIcon, WildcardIcon, BoxIcon, GroupIcon, FilterIcon, StadiumIcon } from "@/components/icons";
|
|
160
153
|
|
|
161
154
|
let isAllRows = ref(false);
|
|
162
155
|
|
|
163
156
|
const props = defineProps({
|
|
164
|
-
filter:
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
157
|
+
filter: {
|
|
158
|
+
type: Object,
|
|
159
|
+
required: true
|
|
160
|
+
},
|
|
161
|
+
index: {
|
|
162
|
+
type: Number,
|
|
163
|
+
required: true
|
|
164
|
+
},
|
|
165
|
+
expandedFilter: {
|
|
166
|
+
type: String,
|
|
167
|
+
default: null
|
|
168
|
+
},
|
|
169
|
+
filterBuilder: {
|
|
170
|
+
type: Object,
|
|
171
|
+
required: true
|
|
172
|
+
}
|
|
168
173
|
});
|
|
169
174
|
|
|
170
175
|
const handleFilterClick = (id) => {
|
|
@@ -282,17 +287,20 @@ props.filterBuilder.onUpdate(() => {
|
|
|
282
287
|
else {
|
|
283
288
|
filterTitle.value = getFilterTitle();
|
|
284
289
|
}
|
|
285
|
-
// else if (newData.id === filter.value.id) update(newData);
|
|
286
290
|
});
|
|
287
291
|
</script>
|
|
288
292
|
|
|
289
293
|
<style scoped>
|
|
290
294
|
.filter-card {
|
|
291
|
-
@apply bg-dark-500 border-dark-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
295
|
+
@apply bg-dark-500 border border-dark-625/30 relative mb-2 transition-all duration-200;
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
.filter-card:hover {
|
|
299
|
+
transform: scale(1.03);
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
.filter-card:active {
|
|
303
|
+
transform: scale(0.98);
|
|
296
304
|
}
|
|
297
305
|
|
|
298
306
|
.filter-card:hover:not(.expanded-filter) {
|
|
@@ -332,59 +340,39 @@ props.filterBuilder.onUpdate(() => {
|
|
|
332
340
|
}
|
|
333
341
|
|
|
334
342
|
.filter-input {
|
|
335
|
-
@apply border border-dark-550 rounded px-2 py-1.5 text-sm text-white focus:outline-none transition-
|
|
336
|
-
@apply bg-dark-450/90;
|
|
337
|
-
}
|
|
338
|
-
|
|
339
|
-
.filter-input:focus {
|
|
340
|
-
border-color: oklch(0.28 0 0);
|
|
341
|
-
@apply bg-dark-475/90;
|
|
343
|
+
@apply border border-dark-550 rounded px-2 py-1.5 text-sm text-white bg-dark-450/90 focus:bg-dark-475/90 focus:outline-none transition-all duration-200 placeholder:text-light-400;
|
|
342
344
|
}
|
|
343
345
|
|
|
344
|
-
|
|
345
|
-
|
|
346
|
+
/* Filter action buttons - drag and delete */
|
|
347
|
+
.drag-btn,
|
|
348
|
+
.delete-btn {
|
|
349
|
+
@apply flex items-center justify-center rounded-full transition-all duration-200;
|
|
350
|
+
@apply w-8 h-8 flex-shrink-0 p-0;
|
|
351
|
+
@apply border border-dark-500 bg-dark-450;
|
|
346
352
|
}
|
|
347
353
|
|
|
348
|
-
.
|
|
349
|
-
@apply
|
|
350
|
-
width: 28px;
|
|
351
|
-
height: 28px;
|
|
352
|
-
@apply text-light-400;
|
|
353
|
-
background-color: rgba(35, 36, 41, 0.8);
|
|
354
|
-
backdrop-filter: blur(4px);
|
|
355
|
-
}
|
|
354
|
+
.drag-btn {
|
|
355
|
+
@apply text-light-500;
|
|
356
356
|
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
width: 32px;
|
|
360
|
-
height: 32px;
|
|
357
|
+
&:hover {
|
|
358
|
+
@apply bg-dark-300 border-dark-550 text-yellow-400 shadow-md;
|
|
361
359
|
}
|
|
362
360
|
}
|
|
363
361
|
|
|
364
|
-
.
|
|
365
|
-
|
|
366
|
-
transform: scale(1.15);
|
|
367
|
-
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
|
|
368
|
-
}
|
|
369
|
-
|
|
370
|
-
.drag-btn:hover {
|
|
371
|
-
@apply bg-dark-675/80;
|
|
372
|
-
border-color: oklch(0.28 0 0);
|
|
373
|
-
}
|
|
362
|
+
.delete-btn {
|
|
363
|
+
@apply bg-error-500/30 border-error-400/50 text-error-300;
|
|
374
364
|
|
|
375
|
-
|
|
376
|
-
|
|
365
|
+
&:hover {
|
|
366
|
+
@apply bg-error-400/80 border-error-500 text-white shadow-md;
|
|
367
|
+
}
|
|
377
368
|
}
|
|
378
369
|
|
|
379
370
|
.drag-handle.sortable-chosen {
|
|
380
|
-
border
|
|
381
|
-
@apply bg-dark-675/20;
|
|
371
|
+
@apply border border-dark-550 bg-dark-675/20;
|
|
382
372
|
}
|
|
383
373
|
|
|
384
374
|
.filter-card.sortable-ghost {
|
|
385
|
-
@apply opacity-50;
|
|
386
|
-
border: 1px solid oklch(0.28 0 0);
|
|
387
|
-
@apply bg-dark-675/10;
|
|
375
|
+
@apply opacity-50 border border-dark-550 bg-dark-675/10;
|
|
388
376
|
}
|
|
389
377
|
|
|
390
378
|
.filter-card.sortable-drag {
|
|
@@ -392,27 +380,26 @@ props.filterBuilder.onUpdate(() => {
|
|
|
392
380
|
}
|
|
393
381
|
|
|
394
382
|
.expanded-filter {
|
|
395
|
-
border-
|
|
396
|
-
background-color: rgba(26, 27, 30, 0.95);
|
|
383
|
+
@apply border-l-4 border-l-dark-550 bg-dark-300/95;
|
|
397
384
|
}
|
|
398
385
|
|
|
399
386
|
.expanded-content {
|
|
400
|
-
|
|
401
|
-
border-radius: 6px;
|
|
402
|
-
padding: 12px;
|
|
387
|
+
@apply rounded-md p-3 bg-dark-300/95;
|
|
403
388
|
}
|
|
404
389
|
|
|
405
390
|
.controls-section {
|
|
406
|
-
|
|
407
|
-
border-radius: 6px;
|
|
408
|
-
padding: 12px;
|
|
391
|
+
@apply rounded-md p-3 bg-dark-350/[0.98];
|
|
409
392
|
}
|
|
410
393
|
|
|
411
394
|
.excluded-filter {
|
|
412
|
-
@apply border-l-4 border-l-error-
|
|
395
|
+
@apply border-l-4 border-l-error-400 bg-error-500/30;
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
.excluded-filter .delete-btn {
|
|
399
|
+
@apply bg-error-400/50 border-error-500 text-error-300;
|
|
413
400
|
}
|
|
414
401
|
|
|
415
402
|
.normal-filter {
|
|
416
|
-
border-
|
|
403
|
+
@apply border-l-4 border-l-transparent;
|
|
417
404
|
}
|
|
418
405
|
</style>
|