@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.
Files changed (121) 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 +140 -170
  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 +58 -15
  13. package/src/assets/css/components/forms.scss +31 -32
  14. package/src/assets/css/components/headers.scss +12 -20
  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 +220 -0
  20. package/src/assets/css/main.scss +66 -77
  21. package/src/components/Auth/LoginForm.vue +5 -84
  22. package/src/components/Editors/Account/Account.vue +8 -10
  23. package/src/components/Editors/Account/AccountCreator.vue +28 -59
  24. package/src/components/Editors/Account/AccountView.vue +38 -86
  25. package/src/components/Editors/Account/CreateAccount.vue +8 -50
  26. package/src/components/Editors/Profile/CreateProfile.vue +74 -131
  27. package/src/components/Editors/Profile/Profile.vue +15 -17
  28. package/src/components/Editors/Profile/ProfileCountryChooser.vue +16 -60
  29. package/src/components/Editors/Profile/ProfileView.vue +46 -96
  30. package/src/components/Editors/TagLabel.vue +16 -55
  31. package/src/components/Editors/TagToggle.vue +20 -8
  32. package/src/components/Filter/Filter.vue +62 -75
  33. package/src/components/Filter/FilterPreview.vue +161 -135
  34. package/src/components/Filter/PriceSortToggle.vue +36 -43
  35. package/src/components/Table/Header.vue +1 -1
  36. package/src/components/Table/Table.vue +45 -51
  37. package/src/components/Tasks/CheckStock.vue +7 -16
  38. package/src/components/Tasks/Controls/DesktopControls.vue +15 -60
  39. package/src/components/Tasks/Controls/MobileControls.vue +5 -20
  40. package/src/components/Tasks/CreateTaskAXS.vue +20 -118
  41. package/src/components/Tasks/CreateTaskTM.vue +33 -189
  42. package/src/components/Tasks/EventDetailRow.vue +21 -0
  43. package/src/components/Tasks/MassEdit.vue +6 -16
  44. package/src/components/Tasks/QuickSettings.vue +140 -216
  45. package/src/components/Tasks/ScrapeVenue.vue +4 -13
  46. package/src/components/Tasks/Stats.vue +19 -38
  47. package/src/components/Tasks/Task.vue +65 -268
  48. package/src/components/Tasks/TaskLabel.vue +9 -3
  49. package/src/components/Tasks/TaskView.vue +43 -63
  50. package/src/components/Tasks/Utilities.vue +10 -44
  51. package/src/components/Tasks/ViewTask.vue +23 -107
  52. package/src/components/icons/Close.vue +2 -8
  53. package/src/components/icons/Gear.vue +8 -8
  54. package/src/components/icons/Hash.vue +5 -0
  55. package/src/components/icons/Key.vue +2 -8
  56. package/src/components/icons/Pencil.vue +2 -8
  57. package/src/components/icons/Profile.vue +2 -8
  58. package/src/components/icons/Sell.vue +2 -8
  59. package/src/components/icons/Spinner.vue +4 -7
  60. package/src/components/icons/SquareCheck.vue +2 -8
  61. package/src/components/icons/SquareUncheck.vue +2 -8
  62. package/src/components/icons/Wildcard.vue +2 -8
  63. package/src/components/icons/index.js +3 -1
  64. package/src/components/ui/ActionButtonGroup.vue +113 -52
  65. package/src/components/ui/BalanceIndicator.vue +60 -0
  66. package/src/components/ui/EmptyState.vue +24 -0
  67. package/src/components/ui/EnableDisableToggle.vue +23 -0
  68. package/src/components/ui/FormField.vue +48 -48
  69. package/src/components/ui/IconLabel.vue +23 -0
  70. package/src/components/ui/InfoRow.vue +21 -54
  71. package/src/components/ui/Modal.vue +89 -56
  72. package/src/components/ui/Navbar.vue +60 -41
  73. package/src/components/ui/ReadonlyFieldsSection.vue +31 -0
  74. package/src/components/ui/ReconnectIndicator.vue +111 -124
  75. package/src/components/ui/SectionCard.vue +6 -14
  76. package/src/components/ui/Splash.vue +2 -10
  77. package/src/components/ui/StatusBadge.vue +26 -28
  78. package/src/components/ui/TaskToggle.vue +54 -0
  79. package/src/components/ui/controls/CountryChooser.vue +27 -64
  80. package/src/components/ui/controls/EyeToggle.vue +1 -1
  81. package/src/components/ui/controls/atomic/Checkbox.vue +40 -121
  82. package/src/components/ui/controls/atomic/Dropdown.vue +103 -139
  83. package/src/components/ui/controls/atomic/MultiDropdown.vue +71 -119
  84. package/src/components/ui/controls/atomic/Switch.vue +21 -84
  85. package/src/composables/useColorMapping.js +15 -0
  86. package/src/composables/useCopyToClipboard.js +1 -1
  87. package/src/composables/useDateFormatting.js +21 -0
  88. package/src/composables/useDeviceDetection.js +14 -0
  89. package/src/composables/useDropdownPosition.js +3 -4
  90. package/src/composables/useDynamicTableHeight.js +31 -0
  91. package/src/composables/useRowSelection.js +0 -3
  92. package/src/composables/useTicketPricing.js +16 -0
  93. package/src/composables/useWindowDimensions.js +21 -0
  94. package/src/libs/Filter.js +14 -20
  95. package/src/libs/panzoom.js +1 -5
  96. package/src/libs/utils/array.js +60 -0
  97. package/src/{stores/utils.js → libs/utils/dataGeneration.js} +2 -250
  98. package/src/libs/utils/eventUrl.js +40 -0
  99. package/src/libs/utils/string.js +28 -0
  100. package/src/libs/utils/time.js +20 -0
  101. package/src/libs/utils/validation.js +88 -0
  102. package/src/main.js +0 -2
  103. package/src/stores/connection.js +1 -4
  104. package/src/stores/logger.js +6 -12
  105. package/src/stores/sampleData.js +1 -2
  106. package/src/stores/ui.js +59 -36
  107. package/src/views/Accounts.vue +13 -24
  108. package/src/views/Console.vue +70 -172
  109. package/src/views/Editor.vue +211 -379
  110. package/src/views/FilterBuilder.vue +188 -371
  111. package/src/views/Login.vue +3 -28
  112. package/src/views/Profiles.vue +8 -15
  113. package/src/views/Tasks.vue +49 -36
  114. package/tailwind.config.js +82 -71
  115. package/workbox-config.cjs +47 -5
  116. package/docs/plans/2026-02-08-tailwind-consolidation.md +0 -2438
  117. package/exit +0 -209
  118. package/run +0 -177
  119. package/src/assets/css/base/color-fallbacks.scss +0 -10
  120. package/switch-branch.sh +0 -41
  121. /package/public/{reconnect-logo.png → img/reconnect-logo.png} +0 -0
@@ -1,5 +1,16 @@
1
1
  <template>
2
- <div @click="toggleOpened" class="dropdown" :class="[props.variant, { 'opened': opened }]" ref="dropdownRef">
2
+ <div
3
+ @click="toggleOpened"
4
+ class="dropdown"
5
+ :class="[props.variant, { 'opened': opened }]"
6
+ ref="dropdownRef"
7
+ role="combobox"
8
+ :aria-expanded="opened"
9
+ :aria-label="props.default"
10
+ tabindex="0"
11
+ @keydown.enter="toggleOpened"
12
+ @keydown.space.prevent="toggleOpened"
13
+ @keydown.escape="opened && ui.setCurrentDropdown('')">
3
14
  <span class="dropdown-display">
4
15
  <span class="dropdown-value" :class="capitalize ? 'capitalize' : ''">
5
16
  {{ currentValue ? currentValue : props.default }}
@@ -12,6 +23,7 @@
12
23
  v-if="opened"
13
24
  class="dropdown-menu-portal scrollable"
14
25
  :style="menuStyle"
26
+ role="listbox"
15
27
  @click.stop
16
28
  @wheel.stop>
17
29
  <button
@@ -19,11 +31,13 @@
19
31
  class="dropdown-item"
20
32
  :class="i !== 0 ? 'border-t border-dark-650' : ''"
21
33
  v-for="(f, i) in !allowDefault ? props.options : ['', ...props.options]"
22
- @click.prevent.stop="chose(f)">
23
- <CheckmarkIcon v-if="(f || props.default) === currentValue" class="mr-2 flex-shrink-0" />
34
+ role="option"
35
+ :aria-selected="(f || props.default) === currentValue"
36
+ @click.stop="chose(f)">
24
37
  <span class="dropdown-item-text" :class="capitalize ? 'capitalize' : ''">
25
38
  {{ f ? f : props.default }}
26
39
  </span>
40
+ <CheckmarkIcon v-if="(f || props.default) === currentValue" class="ml-2" />
27
41
  </button>
28
42
  </div>
29
43
  </transition>
@@ -40,16 +54,47 @@ import { useDropdownPosition } from "@/composables/useDropdownPosition";
40
54
  const ui = useUIStore();
41
55
 
42
56
  const props = defineProps({
43
- onClick: { type: Function },
44
- default: { type: String },
45
- value: { type: String },
46
- options: { type: Object },
47
- allowDefault: { type: Boolean },
48
- rightAmount: { type: String },
49
- topPadding: { type: String },
50
- capitalize: { type: Boolean },
51
- includeAdjacentButtons: { type: Boolean, default: false },
52
- variant: { type: String, default: "default" }
57
+ onClick: {
58
+ type: Function,
59
+ default: null
60
+ },
61
+ default: {
62
+ type: String,
63
+ default: ''
64
+ },
65
+ value: {
66
+ type: String,
67
+ default: ''
68
+ },
69
+ options: {
70
+ type: Object,
71
+ required: true
72
+ },
73
+ allowDefault: {
74
+ type: Boolean,
75
+ default: false
76
+ },
77
+ rightAmount: {
78
+ type: String,
79
+ default: ''
80
+ },
81
+ topPadding: {
82
+ type: String,
83
+ default: ''
84
+ },
85
+ capitalize: {
86
+ type: Boolean,
87
+ default: false
88
+ },
89
+ includeAdjacentButtons: {
90
+ type: Boolean,
91
+ default: false
92
+ },
93
+ variant: {
94
+ type: String,
95
+ default: 'default',
96
+ validator: (value) => ['default', 'transparent'].includes(value)
97
+ }
53
98
  });
54
99
 
55
100
  const currentValue = ref(props.value);
@@ -66,11 +111,11 @@ const id = Math.random();
66
111
  const opened = computed(() => ui.currentDropdown === id);
67
112
 
68
113
  const { menuStyle, updatePosition } = useDropdownPosition(dropdownRef, {
69
- maxHeight: Math.floor(window.innerHeight * 0.85), // 85% of viewport
114
+ maxHeight: 200,
70
115
  includeAdjacentButtons: props.includeAdjacentButtons,
71
116
  estimateHeight: () => {
72
117
  const optionsCount = !props.allowDefault ? props.options?.length || 0 : (props.options?.length || 0) + 1;
73
- return Math.min(optionsCount * 44, Math.floor(window.innerHeight * 0.85));
118
+ return Math.min(optionsCount * 44, 200);
74
119
  }
75
120
  });
76
121
 
@@ -102,39 +147,6 @@ const toggleOpened = () => {
102
147
  } else {
103
148
  ui.setCurrentDropdown(id);
104
149
  updatePosition();
105
- // Set all items to same width only if horizontal scrolling is needed
106
- setTimeout(() => {
107
- const portal = document.querySelector('.dropdown-menu-portal');
108
- const items = portal?.querySelectorAll('.dropdown-item');
109
- if (items && items.length > 0) {
110
- let maxWidth = 0;
111
- // Reset styles first to get accurate measurements
112
- items.forEach(item => {
113
- item.style.width = '';
114
- item.style.minWidth = '';
115
- });
116
- portal.style.overflowX = '';
117
-
118
- // Measure actual content width
119
- items.forEach(item => {
120
- const contentWidth = item.scrollWidth;
121
- maxWidth = Math.max(maxWidth, contentWidth);
122
- });
123
-
124
- // Only enable horizontal scrolling if content is truly wider than the max allowed width
125
- const maxAllowedWidth = Math.min(400, window.innerWidth * 0.9);
126
- if (maxWidth > maxAllowedWidth) {
127
- // Enable horizontal scrolling for long items
128
- portal.style.overflowX = 'auto';
129
- items.forEach(item => {
130
- item.style.minWidth = maxWidth + 'px';
131
- });
132
- } else {
133
- // Normal display - no horizontal scrolling needed
134
- portal.style.overflowX = 'hidden';
135
- }
136
- }
137
- }, 50);
138
150
  }
139
151
  };
140
152
 
@@ -151,34 +163,41 @@ const chose = (f) => {
151
163
 
152
164
  <style scoped>
153
165
  .dropdown {
154
- @apply relative w-full text-white ml-auto rounded-lg ring-0 h-10 bg-dark-300 border border-dark-600;
155
- padding: 0.75rem;
166
+ @apply relative w-full text-white ml-auto rounded-lg ring-0 h-10 border-2 bg-bg-input border-border p-3;
156
167
  }
157
168
 
158
169
  .dropdown.transparent {
159
- @apply bg-transparent border-0 shadow-none p-0 h-10;
170
+ @apply !bg-transparent !border-none !shadow-none !p-0 !h-10;
160
171
  }
161
172
 
162
173
  .dropdown.transparent:hover,
163
174
  .dropdown.transparent:focus-within,
164
175
  .dropdown.transparent.opened {
165
- @apply border-0 bg-transparent shadow-none outline-none;
176
+ @apply !border-none !bg-transparent !shadow-none !outline-none;
177
+ }
178
+
179
+ .unified-search-group .dropdown:hover {
180
+ @apply !border-transparent;
166
181
  }
167
182
 
168
- .dropdown:not(.transparent):hover {
169
- border-color: oklch(0.30 0 0);
183
+ .dropdown:not(.transparent):not(.unified-search-group .dropdown):hover {
184
+ @apply border-dark-700;
170
185
  }
171
186
 
172
- .dropdown:not(.transparent):focus-within,
173
- .dropdown:not(.transparent).opened {
174
- @apply border-border-focus outline outline-1 outline-border-focus;
175
- outline-offset: 0;
187
+ .unified-search-group .dropdown:focus-within,
188
+ .unified-search-group .dropdown.opened {
189
+ @apply !border-0 !outline-0 !border-transparent;
190
+ }
191
+
192
+ .dropdown:not(.transparent):not(.unified-search-group .dropdown):focus-within,
193
+ .dropdown:not(.transparent):not(.unified-search-group .dropdown).opened {
194
+ @apply !border-primary !outline !outline-1 !outline-primary;
195
+ outline-offset: 0 !important;
176
196
  }
177
197
 
178
198
  @media (min-width: 768px) {
179
199
  .dropdown {
180
- @apply h-10;
181
- padding: 0.625rem;
200
+ @apply h-10 py-2.5 px-2.5;
182
201
  }
183
202
  }
184
203
 
@@ -187,44 +206,25 @@ const chose = (f) => {
187
206
  }
188
207
 
189
208
  .dropdown-value {
190
- @apply overflow-hidden truncate min-w-0 flex-1 mr-2 text-sm;
191
- padding-right: 2rem; /* Extra space to prevent collision with arrow */
192
- }
193
-
194
- @media (min-width: 768px) {
195
- .dropdown-value {
196
- font-size: 12px;
197
- }
209
+ @apply overflow-hidden truncate min-w-0 flex-1 text-sm md:text-xs;
198
210
  }
199
211
 
200
212
  .dropdown-arrow {
201
- @apply w-4 h-4 transition-all duration-300;
202
- position: absolute;
203
- right: 0.75rem;
204
- top: 50%;
205
- transform: translateY(-50%);
206
- display: flex;
207
- align-items: center;
208
- justify-content: center;
213
+ @apply w-4 h-4 transition-all duration-300 flex-shrink-0;
209
214
  }
210
215
 
211
216
  .dropdown-menu-portal {
212
- @apply rounded-xl shadow-2xl bg-dark-300 border border-dark-600;
213
- backdrop-filter: blur(12px);
214
- box-shadow: 0 20px 25px -5px oklch(0 0 0 / 0.4), 0 10px 10px -5px oklch(0 0 0 / 0.2),
215
- 0 0 0 1px oklch(1 0 0 / 0.05);
216
- overflow-x: hidden;
217
+ @apply rounded-xl z-modal border-2 border-dark-650 bg-dark-400 shadow-dropdown;
218
+ min-width: 200px;
219
+ max-width: min(90vw, 600px);
220
+ overflow-x: auto;
217
221
  overflow-y: auto;
218
222
  overscroll-behavior: contain;
223
+ touch-action: pan-x pan-y;
219
224
  -webkit-overflow-scrolling: touch;
220
- touch-action: pan-y;
221
225
  scrollbar-width: thin;
222
- scrollbar-color: oklch(0.35 0 0) oklch(0.19 0 0);
223
- z-index: 1000;
224
- min-width: 200px;
225
- max-width: min(400px, 90vw);
226
- display: flex;
227
- flex-direction: column;
226
+ scrollbar-color: theme('colors.dark.750') theme('colors.dark.350');
227
+ scrollbar-gutter: stable;
228
228
  }
229
229
 
230
230
  .dropdown-menu-portal::-webkit-scrollbar {
@@ -233,48 +233,40 @@ const chose = (f) => {
233
233
  }
234
234
 
235
235
  .dropdown-menu-portal::-webkit-scrollbar-track {
236
- background: oklch(0.19 0 0);
236
+ @apply bg-transparent;
237
+ margin: 12px 0;
237
238
  }
238
239
 
239
240
  .dropdown-menu-portal::-webkit-scrollbar-thumb {
240
- background: oklch(0.35 0 0);
241
- border-radius: 3px;
241
+ @apply bg-dark-750 rounded-full;
242
+ border: 2px solid transparent;
243
+ background-clip: padding-box;
242
244
  }
243
245
 
244
246
  .dropdown-menu-portal::-webkit-scrollbar-thumb:hover {
245
- background: oklch(0.45 0 0);
247
+ @apply bg-dark-800;
246
248
  }
247
249
 
248
250
  .dropdown-item {
249
- @apply cursor-pointer text-left text-white transition-all duration-200;
250
- padding: 0.75rem 1rem;
251
- font-size: 0.875rem;
252
- font-weight: 500;
253
- border-bottom: 1px solid rgba(61, 62, 68, 0.3);
254
- display: flex !important;
255
- align-items: center;
256
- gap: 1rem;
257
- width: 100%;
258
- flex-shrink: 0;
251
+ @apply cursor-pointer text-left text-white transition-all duration-200 flex items-center justify-between;
252
+ @apply px-4 py-3 text-sm font-medium border-b border-dark-625/30;
253
+ min-width: 100%;
259
254
  }
260
255
 
261
256
  .dropdown-item:last-child {
262
- border-bottom: none;
257
+ @apply border-b-0;
263
258
  }
264
259
 
265
260
  .dropdown-item:hover {
266
- background: oklch(0.2809 0 0) !important; /* Full width background */
267
- color: oklch(1 0 0);
261
+ @apply bg-dark-550 text-white;
268
262
  }
269
263
 
270
264
  .dropdown-item:active {
271
- @apply bg-dark-650;
272
- box-shadow: inset 0 2px 4px oklch(0 0 0 / 0.4);
265
+ @apply bg-dark-650 shadow-input-inset;
273
266
  }
274
267
 
275
268
  .dropdown-item.selected {
276
- background: oklch(0.72 0.15 145 / 0.15);
277
- color: oklch(0.72 0.15 145);
269
+ @apply bg-primary/15 text-primary;
278
270
  }
279
271
 
280
272
  .dropdown-item:first-child {
@@ -286,38 +278,10 @@ const chose = (f) => {
286
278
  }
287
279
 
288
280
  .dropdown-item-text {
289
- @apply pr-2 flex-1;
290
- white-space: nowrap;
291
- overflow: hidden;
292
- text-overflow: ellipsis;
281
+ @apply pr-2 whitespace-nowrap;
293
282
  }
294
283
 
295
284
  .dropdown-item svg {
296
- @apply w-4 h-4;
297
- color: oklch(0.72 0.15 145);
298
- }
299
-
300
- .dropdown-fade-enter-active {
301
- @apply transition-all duration-300;
302
- }
303
-
304
- .dropdown-fade-leave-active {
305
- @apply transition-all duration-200;
306
- }
307
-
308
- .dropdown-fade-enter-from {
309
- @apply opacity-0;
310
- transform: translateY(-8px) scale(0.95);
311
- }
312
-
313
- .dropdown-fade-leave-to {
314
- @apply opacity-0;
315
- transform: translateY(-4px) scale(0.98);
316
- }
317
-
318
- .dropdown-fade-enter-to,
319
- .dropdown-fade-leave-from {
320
- @apply opacity-100;
321
- transform: translateY(0) scale(1);
285
+ @apply w-4 h-4 text-primary;
322
286
  }
323
287
  </style>
@@ -71,13 +71,34 @@ import { useClickOutside } from "@/composables/useClickOutside";
71
71
  const ui = useUIStore();
72
72
 
73
73
  const props = defineProps({
74
- onSelect: { type: Function },
75
- default: { type: String },
76
- options: { type: Array, required: true },
77
- rightAmount: { type: String },
78
- topPadding: { type: String },
79
- capitalize: { type: Boolean },
80
- includeAdjacentButtons: { type: Boolean, default: false }
74
+ onSelect: {
75
+ type: Function,
76
+ default: null
77
+ },
78
+ default: {
79
+ type: String,
80
+ default: 'Select options...'
81
+ },
82
+ options: {
83
+ type: Array,
84
+ required: true
85
+ },
86
+ rightAmount: {
87
+ type: String,
88
+ default: ''
89
+ },
90
+ topPadding: {
91
+ type: String,
92
+ default: ''
93
+ },
94
+ capitalize: {
95
+ type: Boolean,
96
+ default: false
97
+ },
98
+ includeAdjacentButtons: {
99
+ type: Boolean,
100
+ default: false
101
+ }
81
102
  });
82
103
 
83
104
  const selectedOptions = ref([]);
@@ -132,33 +153,6 @@ const toggleOpened = () => {
132
153
  } else {
133
154
  ui.setCurrentDropdown(id);
134
155
  updatePosition();
135
- // Set all items to same width only if horizontal scrolling is needed
136
- setTimeout(() => {
137
- const portal = document.querySelector('.dropdown-menu-portal');
138
- const items = portal?.querySelectorAll('.dropdown-item');
139
- if (items && items.length > 0) {
140
- let maxWidth = 0;
141
- items.forEach(item => {
142
- item.style.width = 'max-content';
143
- maxWidth = Math.max(maxWidth, item.scrollWidth);
144
- });
145
-
146
- // Only set explicit widths if content is wider than container
147
- if (maxWidth > portal.offsetWidth) {
148
- // Enable horizontal scrolling for long items
149
- portal.style.overflowX = 'auto';
150
- items.forEach(item => {
151
- item.style.width = maxWidth + 'px';
152
- });
153
- } else {
154
- // Disable horizontal scrolling for short items
155
- portal.style.overflowX = 'hidden';
156
- items.forEach(item => {
157
- item.style.width = '100%';
158
- });
159
- }
160
- }
161
- }, 50);
162
156
  }
163
157
  };
164
158
 
@@ -218,24 +212,22 @@ if (props.default && !selectedOptions.value.includes(props.default)) {
218
212
 
219
213
  <style scoped>
220
214
  .dropdown {
221
- @apply relative w-full h-10 text-white ml-auto rounded-lg ring-0;
222
- background: linear-gradient(135deg, oklch(0.18 0 0) 0%, oklch(0.20 0 0) 100%);
223
- border: 1px solid oklch(0.26 0 0);
215
+ @apply relative w-full h-10 text-white ml-auto rounded-lg ring-0 border-2;
216
+ @apply bg-bg-input border-border;
224
217
  padding: 0.75rem;
225
218
  }
226
219
 
227
220
  .dropdown:hover {
228
- border-color: oklch(0.30 0 0);
221
+ @apply border-dark-650;
229
222
  }
230
223
 
231
224
  .dropdown:focus-within,
232
225
  .dropdown.opened {
233
- border-color: oklch(0.72 0.15 145) !important;
234
- outline: 1px solid oklch(0.72 0.15 145) !important;
235
- outline-offset: 0;
226
+ @apply border-primary outline outline-1 outline-primary;
227
+ outline-offset: 0 !important;
236
228
  }
237
229
 
238
- @media (max-width: 810px) {
230
+ @screen modal {
239
231
  .dropdown {
240
232
  @apply h-10;
241
233
  padding: 0.625rem;
@@ -251,40 +243,30 @@ if (props.default && !selectedOptions.value.includes(props.default)) {
251
243
  }
252
244
 
253
245
  .dropdown-counter {
254
- @apply flex items-center gap-2 absolute;
255
- right: 0.75rem;
256
- top: 50%;
257
- transform: translateY(-50%);
246
+ @apply flex items-center gap-2 absolute right-2;
258
247
  }
259
248
 
260
249
  .counter-badge {
261
- @apply text-white text-xs font-semibold px-1.5 py-0.5 rounded-full text-center min-w-[18px] shadow-sm;
262
- background: oklch(0.72 0.15 145);
250
+ @apply text-white text-xs font-semibold px-1.5 py-0.5 rounded-full text-center min-w-4.5 shadow-sm;
251
+ @apply bg-primary;
263
252
  }
264
253
 
265
254
  .dropdown-arrow {
266
255
  @apply min-w-4 min-h-4 transition-all duration-300;
267
- display: flex;
268
- align-items: center;
269
- justify-content: center;
270
256
  }
271
257
 
272
258
  .dropdown-menu-portal {
273
- @apply rounded-xl shadow-2xl;
274
- background: linear-gradient(135deg, oklch(0.18 0 0) 0%, oklch(0.20 0 0) 100%);
275
- border: 1px solid oklch(0.26 0 0);
276
- backdrop-filter: blur(12px);
277
- box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.4), 0 10px 10px -5px rgba(0, 0, 0, 0.2),
278
- 0 0 0 1px rgba(255, 255, 255, 0.05);
279
- overflow-x: auto !important;
280
- overflow-y: auto !important;
281
- overscroll-behavior: contain !important;
282
- touch-action: pan-x pan-y !important;
283
- -webkit-overflow-scrolling: touch !important;
284
- scrollbar-width: thin;
285
- scrollbar-color: oklch(0.35 0 0) oklch(0.19 0 0);
259
+ @apply rounded-xl z-modal border-2 border-dark-650 bg-dark-400 shadow-dropdown;
286
260
  min-width: 200px;
287
- max-width: 90vw;
261
+ max-width: min(90vw, 600px);
262
+ overflow-x: auto;
263
+ overflow-y: auto;
264
+ overscroll-behavior: contain;
265
+ touch-action: pan-x pan-y;
266
+ -webkit-overflow-scrolling: touch;
267
+ scrollbar-width: thin;
268
+ scrollbar-color: theme('colors.dark.750') theme('colors.dark.350');
269
+ scrollbar-gutter: stable;
288
270
  }
289
271
 
290
272
  .dropdown-menu-portal::-webkit-scrollbar {
@@ -293,31 +275,37 @@ if (props.default && !selectedOptions.value.includes(props.default)) {
293
275
  }
294
276
 
295
277
  .dropdown-menu-portal::-webkit-scrollbar-track {
296
- background: oklch(0.19 0 0);
278
+ @apply bg-transparent;
279
+ margin: 12px 0;
297
280
  }
298
281
 
299
282
  .dropdown-menu-portal::-webkit-scrollbar-thumb {
300
- background: oklch(0.35 0 0);
301
- border-radius: 3px;
283
+ @apply bg-dark-750 rounded-full;
284
+ border: 2px solid transparent;
285
+ background-clip: padding-box;
302
286
  }
303
287
 
304
288
  .dropdown-menu-portal::-webkit-scrollbar-thumb:hover {
305
- background: oklch(0.45 0 0);
289
+ @apply bg-dark-800;
306
290
  }
307
291
 
308
292
  .dropdown-menu-portal.multi .option-list {
309
293
  @apply max-h-48 overflow-y-auto;
310
- overscroll-behavior: contain !important;
311
- touch-action: pan-y !important;
312
- -webkit-overflow-scrolling: touch !important;
294
+ overscroll-behavior: contain;
295
+ -webkit-overflow-scrolling: touch;
296
+ scrollbar-width: none;
297
+ -ms-overflow-style: none;
298
+ touch-action: pan-y;
299
+ }
300
+
301
+ .dropdown-menu-portal.multi .option-list::-webkit-scrollbar {
302
+ display: none;
313
303
  }
314
304
 
315
305
  .dropdown-item {
316
306
  @apply cursor-pointer text-left w-full text-white transition-all duration-200 flex justify-between items-center;
317
- padding: 0.75rem 1rem;
318
- font-size: 0.875rem;
319
- font-weight: 500;
320
- border-bottom: 1px solid rgba(61, 62, 68, 0.3);
307
+ @apply px-4 py-3 text-sm font-medium;
308
+ border-bottom: 1px solid theme('colors.dark.500 / 0.3');
321
309
  }
322
310
 
323
311
  .dropdown-item:last-child {
@@ -325,13 +313,11 @@ if (props.default && !selectedOptions.value.includes(props.default)) {
325
313
  }
326
314
 
327
315
  .dropdown-item:hover {
328
- @apply bg-dark-600;
329
- color: oklch(1 0 0);
316
+ @apply bg-dark-550 text-white;
330
317
  }
331
318
 
332
319
  .dropdown-item:active {
333
- @apply bg-dark-650;
334
- box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.4);
320
+ @apply bg-dark-650 shadow-input-inset;
335
321
  }
336
322
 
337
323
  .dropdown-item:first-child {
@@ -349,13 +335,12 @@ if (props.default && !selectedOptions.value.includes(props.default)) {
349
335
 
350
336
  /* Checkmark styling */
351
337
  .dropdown-item svg {
352
- @apply w-4 h-4;
353
- color: oklch(0.72 0.15 145);
338
+ @apply w-4 h-4 text-primary;
354
339
  }
355
340
 
356
341
  .selected-summary {
357
342
  @apply border-t bg-dark-550 w-full px-4 py-3;
358
- border-top: 1px solid rgba(61, 62, 68, 0.5);
343
+ border-top: 1px solid theme('colors.dark.500 / 0.5');
359
344
  }
360
345
 
361
346
  .selected-count {
@@ -364,7 +349,7 @@ if (props.default && !selectedOptions.value.includes(props.default)) {
364
349
 
365
350
  .count-badge {
366
351
  @apply text-white text-xs font-semibold px-2 py-1 rounded-full shadow-sm;
367
- background: oklch(0.72 0.15 145);
352
+ @apply bg-primary;
368
353
  }
369
354
 
370
355
  .count-label {
@@ -373,53 +358,20 @@ if (props.default && !selectedOptions.value.includes(props.default)) {
373
358
 
374
359
  .clear-button {
375
360
  @apply text-xs text-white transition-all duration-200 font-medium px-2 py-1.5 rounded-lg shadow-sm flex items-center justify-center;
376
- background: oklch(0.55 0.22 25);
361
+ @apply bg-red-400 hover:bg-red-300;
377
362
  min-width: 32px;
378
363
  }
379
364
 
380
- .clear-button:hover {
381
- background: oklch(0.60 0.22 25);
382
- }
383
-
384
365
  .done-button {
385
366
  @apply text-xs text-white transition-all duration-200 font-medium px-2 py-1.5 rounded-lg shadow-sm flex items-center justify-center;
386
- background: oklch(0.72 0.15 145);
367
+ @apply bg-primary hover:bg-green-400;
387
368
  min-width: 32px;
388
369
  }
389
370
 
390
- .done-button:hover {
391
- background: oklch(0.68 0.15 145);
392
- }
393
-
394
371
  @media (min-width: 640px) {
395
372
  .clear-button,
396
373
  .done-button {
397
374
  padding: 0.375rem 0.75rem;
398
375
  }
399
376
  }
400
-
401
- /* Transition animations */
402
- .dropdown-fade-enter-active {
403
- @apply transition-all duration-300;
404
- }
405
-
406
- .dropdown-fade-leave-active {
407
- @apply transition-all duration-200;
408
- }
409
-
410
- .dropdown-fade-enter-from {
411
- @apply opacity-0;
412
- transform: translateY(-8px) scale(0.95);
413
- }
414
-
415
- .dropdown-fade-leave-to {
416
- @apply opacity-0;
417
- transform: translateY(-4px) scale(0.98);
418
- }
419
-
420
- .dropdown-fade-enter-to,
421
- .dropdown-fade-leave-from {
422
- @apply opacity-100;
423
- transform: translateY(0) scale(1);
424
- }
425
377
  </style>