@necrolab/dashboard 0.4.220 → 0.5.1

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 (140) hide show
  1. package/.prettierrc +27 -1
  2. package/.vscode/extensions.json +1 -1
  3. package/README.md +64 -2
  4. package/artwork/image.png +0 -0
  5. package/backend/api.js +26 -24
  6. package/backend/auth.js +2 -2
  7. package/backend/batching.js +1 -1
  8. package/backend/endpoints.js +8 -11
  9. package/backend/index.js +2 -2
  10. package/backend/mock-data.js +27 -36
  11. package/backend/mock-src/classes/logger.js +5 -7
  12. package/backend/mock-src/classes/utils.js +3 -2
  13. package/backend/mock-src/ticketmaster.js +4 -4
  14. package/backend/validator.js +2 -2
  15. package/config/configs.json +0 -1
  16. package/dev-server.js +134 -0
  17. package/exit +209 -0
  18. package/index.html +78 -8
  19. package/index.js +1 -1
  20. package/jsconfig.json +16 -0
  21. package/package.json +39 -25
  22. package/postcss.config.js +1 -1
  23. package/postinstall.js +124 -20
  24. package/public/android-chrome-192x192.png +0 -0
  25. package/public/android-chrome-512x512.png +0 -0
  26. package/public/apple-touch-icon.png +0 -0
  27. package/public/favicon-16x16.png +0 -0
  28. package/public/favicon-32x32.png +0 -0
  29. package/public/favicon.ico +0 -0
  30. package/public/img/logo_trans.png +0 -0
  31. package/public/img/necro_logo.png +0 -0
  32. package/public/manifest.json +16 -10
  33. package/run +176 -9
  34. package/src/App.vue +498 -85
  35. package/src/assets/css/base/reset.scss +43 -0
  36. package/src/assets/css/base/scroll.scss +114 -0
  37. package/src/assets/css/base/typography.scss +37 -0
  38. package/src/assets/css/components/buttons.scss +216 -0
  39. package/src/assets/css/components/forms.scss +221 -0
  40. package/src/assets/css/components/modals.scss +13 -0
  41. package/src/assets/css/components/tables.scss +27 -0
  42. package/src/assets/css/components/toasts.scss +100 -0
  43. package/src/assets/css/main.scss +201 -122
  44. package/src/assets/img/background.svg +2 -2
  45. package/src/assets/img/background.svg.backup +11 -0
  46. package/src/assets/img/logo_trans.png +0 -0
  47. package/src/components/Auth/LoginForm.vue +62 -11
  48. package/src/components/Editors/Account/Account.vue +116 -40
  49. package/src/components/Editors/Account/AccountCreator.vue +88 -39
  50. package/src/components/Editors/Account/AccountView.vue +102 -34
  51. package/src/components/Editors/Account/CreateAccount.vue +80 -32
  52. package/src/components/Editors/Profile/CreateProfile.vue +269 -83
  53. package/src/components/Editors/Profile/Profile.vue +132 -47
  54. package/src/components/Editors/Profile/ProfileCountryChooser.vue +82 -20
  55. package/src/components/Editors/Profile/ProfileView.vue +89 -32
  56. package/src/components/Editors/TagLabel.vue +67 -6
  57. package/src/components/Editors/TagToggle.vue +7 -2
  58. package/src/components/Filter/Filter.vue +288 -71
  59. package/src/components/Filter/FilterPreview.vue +202 -31
  60. package/src/components/Filter/PriceSortToggle.vue +76 -6
  61. package/src/components/Table/Header.vue +1 -1
  62. package/src/components/Table/Row.vue +1 -1
  63. package/src/components/Table/Table.vue +19 -2
  64. package/src/components/Tasks/CheckStock.vue +6 -8
  65. package/src/components/Tasks/Controls/DesktopControls.vue +27 -17
  66. package/src/components/Tasks/Controls/MobileControls.vue +8 -45
  67. package/src/components/Tasks/CreateTaskAXS.vue +80 -72
  68. package/src/components/Tasks/CreateTaskTM.vue +95 -141
  69. package/src/components/Tasks/MassEdit.vue +4 -6
  70. package/src/components/Tasks/QuickSettings.vue +199 -30
  71. package/src/components/Tasks/ScrapeVenue.vue +5 -6
  72. package/src/components/Tasks/Stats.vue +50 -24
  73. package/src/components/Tasks/Task.vue +384 -179
  74. package/src/components/Tasks/TaskLabel.vue +2 -2
  75. package/src/components/Tasks/TaskView.vue +136 -48
  76. package/src/components/Tasks/Utilities.vue +25 -10
  77. package/src/components/Tasks/ViewTask.vue +321 -0
  78. package/src/components/icons/Bag.vue +1 -1
  79. package/src/components/icons/Check.vue +5 -0
  80. package/src/components/icons/Close.vue +21 -0
  81. package/src/components/icons/CloseX.vue +5 -0
  82. package/src/components/icons/Eye.vue +6 -0
  83. package/src/components/icons/Key.vue +21 -0
  84. package/src/components/icons/Loyalty.vue +1 -1
  85. package/src/components/icons/Mail.vue +2 -2
  86. package/src/components/icons/Pencil.vue +21 -0
  87. package/src/components/icons/Play.vue +2 -2
  88. package/src/components/icons/Profile.vue +18 -0
  89. package/src/components/icons/Reload.vue +4 -5
  90. package/src/components/icons/Sandclock.vue +2 -2
  91. package/src/components/icons/Sell.vue +21 -0
  92. package/src/components/icons/Spinner.vue +42 -0
  93. package/src/components/icons/SquareCheck.vue +18 -0
  94. package/src/components/icons/SquareUncheck.vue +18 -0
  95. package/src/components/icons/Stadium.vue +1 -1
  96. package/src/components/icons/Wildcard.vue +18 -0
  97. package/src/components/icons/index.js +26 -1
  98. package/src/components/ui/Modal.vue +107 -13
  99. package/src/components/ui/Navbar.vue +175 -40
  100. package/src/components/ui/ReconnectIndicator.vue +351 -55
  101. package/src/components/ui/Splash.vue +5 -35
  102. package/src/components/ui/controls/CountryChooser.vue +200 -62
  103. package/src/components/ui/controls/atomic/Checkbox.vue +119 -10
  104. package/src/components/ui/controls/atomic/Dropdown.vue +216 -39
  105. package/src/components/ui/controls/atomic/LoadingButton.vue +45 -0
  106. package/src/components/ui/controls/atomic/MultiDropdown.vue +300 -37
  107. package/src/components/ui/controls/atomic/Switch.vue +53 -25
  108. package/src/composables/useClickOutside.js +21 -0
  109. package/src/composables/useDropdownPosition.js +174 -0
  110. package/src/libs/Filter.js +60 -24
  111. package/src/registerServiceWorker.js +1 -1
  112. package/src/stores/connection.js +4 -4
  113. package/src/stores/sampleData.js +172 -199
  114. package/src/stores/ui.js +55 -20
  115. package/src/stores/utils.js +30 -4
  116. package/src/types/index.js +41 -0
  117. package/src/utils/debug.js +1 -0
  118. package/src/views/Accounts.vue +116 -50
  119. package/src/views/Console.vue +394 -79
  120. package/src/views/Editor.vue +1176 -123
  121. package/src/views/FilterBuilder.vue +528 -250
  122. package/src/views/Login.vue +76 -14
  123. package/src/views/Profiles.vue +119 -34
  124. package/src/views/Tasks.vue +266 -98
  125. package/static/offline.html +192 -50
  126. package/switch-branch.sh +41 -0
  127. package/tailwind.config.js +119 -27
  128. package/vite.config.js +73 -16
  129. package/workbox-config.cjs +63 -0
  130. package/ICONS.md +0 -21
  131. package/public/img/background.svg +0 -14
  132. package/public/img/logo.png +0 -0
  133. package/public/img/logo_icon.png +0 -0
  134. package/public/img/logo_icon_2.png +0 -0
  135. package/src/assets/css/_input.scss +0 -143
  136. package/src/assets/img/logo.png +0 -0
  137. package/src/assets/img/logo_icon.png +0 -0
  138. package/src/assets/img/logo_icon_2.png +0 -0
  139. package/vue.config.js +0 -32
  140. package/workbox-config.js +0 -7
@@ -1,7 +1,8 @@
1
1
  <template>
2
2
  <button
3
3
  @click="increase"
4
- class="h-10 px-1 text-white bg-dark-500 relative border-2 border-dark-550 overflow-hidden"
4
+ class="h-10 px-1 text-white bg-dark-500 relative overflow-hidden"
5
+ :class="noBorder ? 'border-0' : 'border-2 border-dark-550'"
5
6
  >
6
7
  <span v-if="sortOptions[currentOpt % sortOptions.length] === 'Enabled'"
7
8
  ><img class="mx-auto" height="16px" width="14px" src="@/assets/img/square_check.svg"
@@ -27,7 +28,11 @@ const props = defineProps({
27
28
  index: Number,
28
29
  expandedFilter: Number,
29
30
  filterBuilder: Object,
30
- options: Object
31
+ options: Object,
32
+ noBorder: {
33
+ type: Boolean,
34
+ default: false
35
+ }
31
36
  });
32
37
 
33
38
  sortOptions.value = props.options;
@@ -1,104 +1,147 @@
1
1
  <template>
2
- <div class="text-white text-sm border-t-2 border-t-dark-550">
3
- <div class="grid grid-cols-7 items-center">
4
- <div class="col-span-6 m-4 sm:m-1 mr-4">
5
- <div class="flex items-center h-7 gap-2">
6
- <h3 @click="handleFilterClick(filter.id)">{{ filterTitle }}</h3>
7
- <Checkbox
8
- :class="`${filterBuilder.selectedFilters.includes(filter.id) ? 'border-green-400' : null}`"
9
- :toggled="filterBuilder.isForCurrentEvent(props.filter)"
10
- @click="
11
- filterBuilder.selectedFilters.includes(filter.id)
12
- ? filterBuilder.unselectFilter(filter.id)
13
- : filterBuilder.selectFilter(filter.id)
14
- "
15
- />
2
+ <div
3
+ class="filter-card group text-white text-sm transition-all duration-200 hover:bg-dark-400 relative"
4
+ :class="{
5
+ 'expanded-filter': filterBuilder.expandedFilter === filter.id,
6
+ 'excluded-filter': filter.exclude,
7
+ 'normal-filter': !filterBuilder.expandedFilter && !filter.exclude
8
+ }"
9
+ >
10
+ <div class="grid grid-cols-12 items-center py-3 px-2 sm:px-4 gap-2 sm:gap-3">
11
+ <div class="col-span-9 sm:col-span-10">
12
+ <div class="flex items-center gap-2 sm:gap-3 cursor-pointer flex-1" @click="handleFilterClick(filter.id)">
13
+ <div class="filter-type-badge flex-shrink-0">
14
+ <component :is="getFilterIcon()" class="w-3 h-3 sm:w-4 sm:h-4" />
15
+ </div>
16
+ <div class="flex-1 min-w-0">
17
+ <h3 class="font-medium text-white group-hover:text-light-400 transition-colors text-sm sm:text-base truncate">{{ filterTitle }}</h3>
18
+ <p class="text-xs mt-1 truncate text-light-400" v-if="getFilterSubtitle()">{{ getFilterSubtitle() }}</p>
19
+ </div>
16
20
  </div>
17
- <div @click="handleFilterClick(filter.id)" v-if="filterBuilder.expandedFilter === filter.id">
21
+ <div class="expanded-content mt-4 mx-2 sm:mx-0" v-if="filterBuilder.expandedFilter === filter.id">
18
22
  <!-- NORMAL -->
19
- <div v-if="filterType === 2">
20
- <p>Section: {{ filter?.section }}</p>
21
- <p v-if="filter.rows?.length">Rows: {{ filter?.rows?.join(", ") }}</p>
22
- <p>Event: {{ filter?.event || filter?.eventId || "-" }}</p>
23
+ <div v-if="filterType === 2" class="space-y-2">
24
+ <div class="info-row">
25
+ <span class="label">Section:</span>
26
+ <span class="value">{{ filter?.section }}</span>
27
+ </div>
28
+ <div class="info-row" v-if="filter.rows?.length">
29
+ <span class="label">Rows:</span>
30
+ <span class="value">{{ filter?.rows?.join(", ") }}</span>
31
+ </div>
32
+ <div class="info-row">
33
+ <span class="label">Event:</span>
34
+ <span class="value">{{ filter?.event || filter?.eventId || "-" }}</span>
35
+ </div>
23
36
  </div>
24
37
  <!-- NORMAL_FIRSTROW -->
25
- <div v-if="filterType === 3">
26
- <p>Section: {{ filter?.section }}</p>
27
- <p>Row: {{ filter?._row }}</p>
28
- <p>Event: {{ filter?.event || "-" }}</p>
38
+ <div v-if="filterType === 3" class="space-y-2">
39
+ <div class="info-row">
40
+ <span class="label">Section:</span>
41
+ <span class="value">{{ filter?.section }}</span>
42
+ </div>
43
+ <div class="info-row">
44
+ <span class="label">Row:</span>
45
+ <span class="value">{{ filter?._row }}</span>
46
+ </div>
47
+ <div class="info-row">
48
+ <span class="label">Event:</span>
49
+ <span class="value">{{ filter?.event || "-" }}</span>
50
+ </div>
29
51
  </div>
30
52
  <!-- CATCH_ALL_GA -->
31
53
  <div v-if="filterType === 1">
32
54
  <button
33
- @click="update({ buyAny: true, floor: false, generalAdmission: false })"
34
- class="border-2 rounded border-dark-550 px-1 h-8 my-2 text-gray bg-dark-550 overflow-hidden"
55
+ @click.stop="update({ buyAny: true, floor: false, generalAdmission: false })"
56
+ class="conversion-btn"
35
57
  >
58
+ <component :is="'WildcardIcon'" class="w-4 h-4" />
36
59
  Convert to wildcard
37
60
  </button>
38
61
  </div>
39
62
  <!-- CATCH_ALL -->
40
63
  <div v-if="filterType === 0">
41
64
  <button
42
- @click="update({ floor: true, buyAny: false, generalAdmission: false })"
43
- class="border-2 rounded border-dark-550 px-1 h-8 text-gray my-2 bg-dark-550 overflow-hidden"
65
+ @click.stop="update({ floor: true, buyAny: false, generalAdmission: false })"
66
+ class="conversion-btn"
44
67
  >
68
+ <component :is="'BoxIcon'" class="w-4 h-4" />
45
69
  Convert to Floor Wildcard
46
70
  </button>
47
71
  </div>
48
72
  <!-- CATCH_ALL_FLOOR -->
49
73
  <div v-if="filterType === 5">
50
74
  <button
51
- @click="update({ generalAdmission: true, floor: false, buyAny: false })"
52
- class="border-2 rounded border-dark-550 px-1 h-8 text-gray my-2 bg-dark-550 overflow-hidden"
75
+ @click.stop="update({ generalAdmission: true, floor: false, buyAny: false })"
76
+ class="conversion-btn"
53
77
  >
78
+ <component :is="'GroupIcon'" class="w-4 h-4" />
54
79
  Convert to GA Wildcard
55
80
  </button>
56
81
  </div>
57
82
  </div>
58
- <div v-if="filterBuilder.expandedFilter === filter.id" class="flex gap-2 items-center">
59
- <div class="flex items-center gap-2">
60
- <Checkbox :toggled="filter.exclude || false" @valueUpdate="handleExcludeClick" />
61
- <p>Excluded</p>
83
+ <div v-if="filterBuilder.expandedFilter === filter.id" class="controls-section mt-4 mx-2 sm:mx-0">
84
+ <div class="flex flex-col sm:flex-row flex-wrap gap-3 sm:items-center">
85
+ <div class="flex items-center gap-2 control-group">
86
+ <Checkbox :toggled="filter.exclude || false" @valueUpdate="handleExcludeClick" />
87
+ <label class="text-sm font-medium">Excluded</label>
88
+ </div>
89
+ <div class="flex items-center gap-2 control-group">
90
+ <label class="text-xs whitespace-nowrap text-light-400">Min:</label>
91
+ <input
92
+ type="number"
93
+ :value="filter.minPrice"
94
+ @change="
95
+ (e) =>
96
+ update(
97
+ {
98
+ minPrice: e.target.value - 0
99
+ },
100
+ true
101
+ )
102
+ "
103
+ placeholder="0"
104
+ class="filter-input w-16 sm:w-20"
105
+ />
106
+ </div>
107
+ <div class="flex items-center gap-2 control-group">
108
+ <label class="text-xs whitespace-nowrap text-light-400">Max:</label>
109
+ <input
110
+ type="number"
111
+ :value="filter.maxPrice"
112
+ @change="
113
+ (e) =>
114
+ update(
115
+ {
116
+ maxPrice: e.target.value - 0
117
+ },
118
+ true
119
+ )
120
+ "
121
+ placeholder="1000"
122
+ class="filter-input w-16 sm:w-20"
123
+ />
124
+ </div>
125
+ <div class="control-group">
126
+ <PriceSortToggle
127
+ :current="filter.priceSort"
128
+ @change="(e) => props.filterBuilder.replaceById(filter.id, { priceSort: e })"
129
+ />
130
+ </div>
62
131
  </div>
63
- <input
64
- type="text"
65
- :value="filter.minPrice"
66
- @change="
67
- (e) =>
68
- update(
69
- {
70
- minPrice: e.target.value - 0
71
- },
72
- true
73
- )
74
- "
75
- placeholder="min"
76
- class="w-16 bg-dark-500 border-2 rounded border-dark-550 px-1 h-8"
77
- />
78
- <input
79
- type="number"
80
- :value="filter.maxPrice"
81
- @change="
82
- (e) =>
83
- update(
84
- {
85
- maxPrice: e.target.value - 0
86
- },
87
- true
88
- )
89
- "
90
- placeholder="max"
91
- class="w-16 bg-dark-500 border-2 rounded border-dark-550 px-1 h-8"
92
- />
93
- <PriceSortToggle
94
- :current="filter.priceSort"
95
- @change="(e) => props.filterBuilder.replaceById(filter.id, { priceSort: e })"
96
- />
97
132
  </div>
98
133
  </div>
99
- <div class="col-span-1 flex justify-self-end m-1 items-center gap-2">
100
- <MenuIcon class="scale-75 cursor-grab handle" />
101
- <TrashIcon class="cursor-pointer" @click="filterBuilder.deleteFilterById(filter.id)" />
134
+ <div class="col-span-3 sm:col-span-2 flex justify-end items-center gap-1 sm:gap-2">
135
+ <div class="drag-handle handle filter-action-btn drag-btn cursor-grab active:cursor-grabbing" title="Drag to reorder">
136
+ <MenuIcon class="w-3 h-3 sm:w-4 sm:h-4" />
137
+ </div>
138
+ <button
139
+ @click="filterBuilder.deleteFilterById(filter.id)"
140
+ class="delete-btn filter-action-btn"
141
+ title="Delete filter"
142
+ >
143
+ <TrashIcon class="w-3 h-3 sm:w-4 sm:h-4" />
144
+ </button>
102
145
  </div>
103
146
  </div>
104
147
  </div>
@@ -113,7 +156,7 @@ import { useUIStore } from "@/stores/ui";
113
156
  const ui = useUIStore();
114
157
 
115
158
  // eslint-disable-next-line no-unused-vars
116
- import { UpIcon, DownIcon, ReloadIcon, TrashIcon, MenuIcon } from "@/components/icons";
159
+ import { UpIcon, DownIcon, ReloadIcon, TrashIcon, MenuIcon, WildcardIcon, BoxIcon, GroupIcon, FilterIcon, StadiumIcon } from "@/components/icons";
117
160
 
118
161
  let isAllRows = ref(false);
119
162
 
@@ -136,6 +179,46 @@ const handleFilterClick = (id) => {
136
179
  };
137
180
 
138
181
  const filterTypes = props.filterBuilder.filterTypes;
182
+
183
+ const getFilterIcon = () => {
184
+ switch (filterType.value) {
185
+ case filterTypes.CATCH_ALL:
186
+ return WildcardIcon;
187
+ case filterTypes.CATCH_ALL_GA:
188
+ return GroupIcon;
189
+ case filterTypes.CATCH_ALL_FLOOR:
190
+ return BoxIcon;
191
+ case filterTypes.NORMAL:
192
+ case filterTypes.NORMAL_FIRSTROW:
193
+ return StadiumIcon;
194
+ default:
195
+ return FilterIcon;
196
+ }
197
+ };
198
+
199
+ const getFilterSubtitle = () => {
200
+ switch (filterType.value) {
201
+ case filterTypes.NORMAL: {
202
+ const selectedRowAmount = filter.value?.rows?.length;
203
+ if (filter.value?.rows?.length && selectedRowAmount <= 5) {
204
+ return `Rows: ${filter.value.rows.join(", ")}`;
205
+ } else if (selectedRowAmount > 5) {
206
+ return `${selectedRowAmount} rows selected`;
207
+ }
208
+ return selectedRowAmount === 0 ? "Full section" : null;
209
+ }
210
+ case filterTypes.NORMAL_FIRSTROW:
211
+ return `First row in ${filter.value.section}`;
212
+ case filterTypes.CATCH_ALL:
213
+ return "Matches all tickets";
214
+ case filterTypes.CATCH_ALL_GA:
215
+ return "Matches all GA tickets";
216
+ case filterTypes.CATCH_ALL_FLOOR:
217
+ return "Matches all floor tickets";
218
+ default:
219
+ return null;
220
+ }
221
+ };
139
222
  const getFilterTitle = () => {
140
223
  const excluded = filter.value.exclude ? "[BL]" : "";
141
224
  switch (filterType.value) {
@@ -202,3 +285,137 @@ props.filterBuilder.onUpdate(() => {
202
285
  // else if (newData.id === filter.value.id) update(newData);
203
286
  });
204
287
  </script>
288
+
289
+ <style scoped>
290
+ .filter-card {
291
+ @apply bg-dark-500 border-dark-550 relative;
292
+ border: 1px solid rgba(61, 62, 68, 0.3);
293
+ margin-bottom: 8px;
294
+ transition: all 0.15s ease-out;
295
+ }
296
+
297
+ .filter-card:hover:not(.expanded-filter) {
298
+ border-color: rgba(61, 62, 68, 0.6);
299
+ background-color: rgba(46, 47, 52, 0.8);
300
+ }
301
+
302
+ .expanded-filter:hover {
303
+ border-color: rgba(61, 62, 68, 0.8);
304
+ }
305
+
306
+ .filter-card + .filter-card {
307
+ border-top: 1px solid rgba(61, 62, 68, 0.2);
308
+ }
309
+
310
+ .filter-type-badge {
311
+ @apply w-6 h-6 sm:w-8 sm:h-8 rounded-full bg-dark-400 flex items-center justify-center flex-shrink-0;
312
+ }
313
+
314
+ .info-row {
315
+ @apply flex justify-between items-center;
316
+ }
317
+
318
+ .label {
319
+ @apply text-xs font-medium text-light-400;
320
+ }
321
+
322
+ .value {
323
+ @apply text-sm text-white;
324
+ }
325
+
326
+ .conversion-btn {
327
+ @apply flex items-center gap-2 px-3 py-2 bg-dark-400 hover:bg-dark-300 border border-dark-550 rounded-md text-sm font-medium transition-colors;
328
+ }
329
+
330
+ .control-group {
331
+ @apply flex items-center gap-2;
332
+ }
333
+
334
+ .filter-input {
335
+ @apply border border-dark-550 rounded px-2 py-1.5 text-sm text-white focus:outline-none transition-colors;
336
+ background-color: rgba(35, 36, 41, 0.9);
337
+ color: white;
338
+ }
339
+
340
+ .filter-input:focus {
341
+ border-color: oklch(0.28 0 0);
342
+ background-color: rgba(46, 47, 52, 0.9);
343
+ }
344
+
345
+ .filter-input::placeholder {
346
+ color: #9CA3AF;
347
+ }
348
+
349
+ .filter-action-btn {
350
+ @apply flex items-center justify-center rounded-full transition-all duration-200 border-2 border-transparent;
351
+ width: 28px;
352
+ height: 28px;
353
+ color: #9CA3AF;
354
+ background-color: rgba(35, 36, 41, 0.8);
355
+ backdrop-filter: blur(4px);
356
+ }
357
+
358
+ @media (min-width: 640px) {
359
+ .filter-action-btn {
360
+ width: 32px;
361
+ height: 32px;
362
+ }
363
+ }
364
+
365
+ .filter-action-btn:hover {
366
+ color: white;
367
+ transform: scale(1.15);
368
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
369
+ }
370
+
371
+ .drag-btn:hover {
372
+ background-color: rgba(68, 69, 75, 0.8);
373
+ border-color: oklch(0.28 0 0);
374
+ }
375
+
376
+ .delete-btn:hover {
377
+ background-color: rgba(239, 68, 68, 0.8);
378
+ border-color: #F87171;
379
+ color: #F87171;
380
+ }
381
+
382
+ .drag-handle.sortable-chosen {
383
+ border: 1px solid oklch(0.28 0 0);
384
+ background-color: rgba(68, 69, 75, 0.2);
385
+ }
386
+
387
+ .filter-card.sortable-ghost {
388
+ @apply opacity-50;
389
+ border: 1px solid oklch(0.28 0 0);
390
+ background-color: rgba(68, 69, 75, 0.1);
391
+ }
392
+
393
+ .filter-card.sortable-drag {
394
+ @apply shadow-lg transform rotate-2 scale-105;
395
+ }
396
+
397
+ .expanded-filter {
398
+ border-left: 4px solid oklch(0.28 0 0);
399
+ background-color: rgba(26, 27, 30, 0.95);
400
+ }
401
+
402
+ .expanded-content {
403
+ background-color: rgba(26, 27, 30, 0.95);
404
+ border-radius: 6px;
405
+ padding: 12px;
406
+ }
407
+
408
+ .controls-section {
409
+ background-color: rgba(26, 27, 30, 0.98);
410
+ border-radius: 6px;
411
+ padding: 12px;
412
+ }
413
+
414
+ .excluded-filter {
415
+ border-left: 4px solid #EE8282;
416
+ }
417
+
418
+ .normal-filter {
419
+ border-left: 4px solid transparent;
420
+ }
421
+ </style>