@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
@@ -9,21 +9,17 @@
9
9
  <div>
10
10
  <div class="my-3 grid grid-cols-12 gap-3">
11
11
  <!-- Profile tag -->
12
- <div class="input-wrapper col-span-4">
13
- <label class="label-override mb-2">
14
- Profile Tag
15
- <TagIcon />
16
- </label>
12
+ <FormField label="Profile Tag" :icon="TagIcon" z-index="0" class="col-span-12 md:col-span-4" noWrapper>
17
13
  <Dropdown
18
14
  :class="`input-default dropdown w-full`"
19
15
  :default="ui.profile.tags[0]"
20
16
  :options="ui.profile.tags"
21
- :onClick="(f) => (profile.tag = f)"
17
+ :onClick="(f) => (formProfile.tag = f)"
22
18
  :capitalize="true" />
23
- </div>
19
+ </FormField>
24
20
 
25
21
  <!-- Card Number -->
26
- <FormField label="Card Number" :icon="CartIcon" :error="errors.includes('cardNumber')" z-index="0" class="col-span-8">
22
+ <FormField label="Card Number" :icon="CartIcon" :error="errors.includes('cardNumber')" z-index="0" class="col-span-12 md:col-span-8">
27
23
  <input
28
24
  ref="cardNumberInput"
29
25
  placeholder="Enter card number"
@@ -35,51 +31,39 @@
35
31
  </FormField>
36
32
 
37
33
  <!-- Country chooser -->
38
- <div class="input-wrapper col-span-2">
39
- <label class="label-override mb-2">
40
- Country
41
- <StadiumIcon />
42
- </label>
34
+ <FormField label="Country" :icon="StadiumIcon" z-index="0" class="col-span-12 md:col-span-2" noWrapper>
43
35
  <ProfileCountryChooser
44
- class="h-8"
45
- :value="profile.country"
36
+ class="h-10"
37
+ :value="formProfile.country"
46
38
  :onClick="chooseCountry"
47
39
  :disabled="true" />
48
- </div>
40
+ </FormField>
49
41
 
50
42
  <!-- Exp Year -->
51
- <div class="input-wrapper col-span-5">
52
- <label class="label-override mb-2">
53
- Expiry Year
54
- <TimerIcon />
55
- </label>
43
+ <FormField label="Expiry Year" :icon="TimerIcon" :error="errors.includes('expYear')" z-index="0" class="col-span-6 md:col-span-5" noWrapper>
56
44
  <Dropdown
57
45
  :class="`input-default dropdown w-full ${errors.includes('expYear') ? 'error' : ''}`"
58
46
  default="Expiry Year"
59
47
  :value="
60
- profile.expYear && !profile?.expYear?.startsWith('20')
61
- ? '20' + profile.expYear
62
- : profile.expYear
63
- ? profile.expYear
48
+ formProfile.expYear && !formProfile?.expYear?.startsWith('20')
49
+ ? '20' + formProfile.expYear
50
+ : formProfile.expYear
51
+ ? formProfile.expYear
64
52
  : undefined
65
53
  "
66
54
  :options="['2025', '2026', '2027', '2028', '2029', '2030', '2031']"
67
- :onClick="(f) => (profile.expYear = f)" />
68
- </div>
55
+ :onClick="(f) => (formProfile.expYear = f)" />
56
+ </FormField>
69
57
 
70
58
  <!-- Exp Month -->
71
- <div class="input-wrapper col-span-5">
72
- <label class="label-override mb-2">
73
- Expiry Month
74
- <TimerIcon />
75
- </label>
59
+ <FormField label="Expiry Month" :icon="TimerIcon" :error="errors.includes('expMonth')" z-index="0" class="col-span-6 md:col-span-5" noWrapper>
76
60
  <Dropdown
77
61
  :class="`input-default dropdown w-full ${errors.includes('expMonth') ? 'error' : ''}`"
78
62
  default="Expiry Month"
79
- :value="profile.expMonth ? profile.expMonth : undefined"
63
+ :value="formProfile.expMonth ? formProfile.expMonth : undefined"
80
64
  :options="['01', '02', '03', '04', '05', '06', '07', '08', '09', '10', '11', '12']"
81
- :onClick="(f) => (profile.expMonth = f)" />
82
- </div>
65
+ :onClick="(f) => (formProfile.expMonth = f)" />
66
+ </FormField>
83
67
 
84
68
  <!-- CVV -->
85
69
  <FormField label="CVV" :icon="ShieldIcon" :error="errors.includes('cvv')" z-index="0" class="col-span-6 md:col-span-4">
@@ -89,55 +73,45 @@
89
73
  max="9999"
90
74
  maxlength="4"
91
75
  minlength="3"
92
- v-model="profile.cvv" />
76
+ v-model="formProfile.cvv" />
93
77
  </FormField>
94
78
 
95
79
  <!-- City -->
96
80
  <FormField label="City" :icon="StadiumIcon" :error="errors.includes('city')" z-index="0" class="col-span-6 md:col-span-4">
97
- <input placeholder="Denver" v-model="profile.city" />
81
+ <input placeholder="Denver" v-model="formProfile.city" />
98
82
  </FormField>
99
83
 
100
84
  <!-- State -->
101
- <div class="input-wrapper col-span-6 md:col-span-4">
102
- <label class="label-override mb-2">
103
- State
104
- <SandclockIcon />
105
- </label>
106
- <div v-if="profile.country === 'US'">
107
- <Dropdown
108
- class="input-default w-full"
109
- default="Select State"
110
- :onClick="(state) => (profile.state = state)"
111
- :options="usStates"
112
- :allowDefault="false"
113
- rightAmount="right-2"
114
- :value="profile.state" />
115
- </div>
85
+ <FormField label="State" :icon="SandclockIcon" z-index="0" class="col-span-6 md:col-span-4" noWrapper>
86
+ <Dropdown
87
+ v-if="formProfile.country === 'US'"
88
+ class="input-default w-full"
89
+ default="Select State"
90
+ :onClick="(state) => (formProfile.state = state)"
91
+ :options="usStates"
92
+ :allowDefault="false"
93
+ rightAmount="right-2"
94
+ :value="formProfile.state" />
116
95
  <div v-else class="input-default">
117
96
  <input disabled placeholder="N/A" value="" />
118
97
  </div>
119
- </div>
98
+ </FormField>
120
99
 
121
100
  <!-- Zip -->
122
101
  <FormField label="Zip" :icon="KeyIcon" :error="errors.includes('zipCode')" z-index="0" class="col-span-6 md:col-span-4">
123
- <input placeholder="10005" type="number" min="1" max="12" v-model="profile.zipCode" />
102
+ <input placeholder="10005" type="number" min="1" max="12" v-model="formProfile.zipCode" />
124
103
  </FormField>
125
104
 
126
105
  <!-- Address -->
127
106
  <FormField label="Address" :icon="HandIcon" :error="errors.includes('address')" z-index="0" class="col-span-6 md:col-span-4">
128
- <input placeholder="100 5th Avenue" v-model="profile.address" />
107
+ <input placeholder="100 5th Avenue" v-model="formProfile.address" />
129
108
  </FormField>
130
109
 
131
110
  <!-- Generate -->
132
- <div class="input-wrapper z-0 col-span-6 md:col-span-4">
133
- <label class="label-override mb-2">
134
- Fake ID
135
- <WildcardIcon />
136
- </label>
137
- <div class="input-default mt-2 flex h-10 w-full items-center">
138
- <button
139
- @click="generate"
140
- class="flex w-full items-center justify-center gap-2 text-xs text-white">
111
+ <FormField label="Fake ID" :icon="WildcardIcon" z-index="0" class="col-span-6 md:col-span-4">
112
+ <button
113
+ @click="generate"
114
+ class="flex h-full w-full items-center justify-center gap-2 text-xs text-white">
141
115
  <svg
142
116
  xmlns="http://www.w3.org/2000/svg"
143
117
  width="14"
@@ -153,80 +127,49 @@
153
127
  <line x1="17" y1="2" x2="17" y2="6" />
154
128
  </svg>
155
129
  <span>Generate</span>
156
- </button>
157
- </div>
158
- </div>
130
+ </button>
131
+ </FormField>
159
132
  </div>
160
133
 
161
134
  <!-- Readonly fields when editing -->
162
- <div v-if="ui.currentlyEditing?.profileName" class="mt-6 grid grid-cols-12 gap-3 pt-4 border-t border-dark-600">
163
- <div v-if="ui.currentlyEditing.tags && ui.currentlyEditing.tags.length > 0" class="col-span-6">
164
- <label class="label-override mb-2">Tags</label>
165
- <div class="flex gap-2 flex-wrap">
166
- <TagLabel v-for="tag in ui.currentlyEditing.tags" :key="tag" :text="tag" />
167
- </div>
168
- </div>
169
- <div class="col-span-6">
170
- <label class="label-override mb-2">Status</label>
171
- <div class="flex items-center gap-3 h-10">
172
- <StatusBadge :enabled="ui.currentlyEditing.enabled" size="large" />
173
- <span class="text-sm font-medium" :class="ui.currentlyEditing.enabled ? 'text-green-400' : 'text-red-400'">
174
- {{ ui.currentlyEditing.enabled ? 'Enabled' : 'Disabled' }}
175
- </span>
176
- </div>
177
- </div>
178
- </div>
135
+ <ReadonlyFieldsSection v-if="ui.currentlyEditing?.profileName" :data="ui.currentlyEditing" />
179
136
  </div>
180
137
 
181
- <button
182
- class="button-default ml-auto mt-4 flex w-48 items-center justify-center gap-x-2 bg-dark-400 text-xs"
183
- @click="done()">
138
+ <button class="btn-modal ml-auto mt-4 w-48" @click="done()">
184
139
  Save
185
- <EditIcon />
140
+ <EditIcon class="ml-2" />
186
141
  </button>
187
142
  </Modal>
188
143
  </template>
189
- <style lang="scss" scoped>
190
- .label-override {
191
- @apply flex items-center;
192
- color: #e1e1e4 !important;
193
-
194
- svg {
195
- @apply ml-2;
196
-
197
- path {
198
- fill: #e1e1e4 !important;
199
- }
200
- }
201
- }
202
- </style>
203
144
  <script setup>
204
145
  import Modal from "@/components/ui/Modal.vue";
205
146
  import FormField from "@/components/ui/FormField.vue";
206
147
  import {
207
- MailIcon,
208
148
  CartIcon,
209
149
  ShieldIcon,
210
150
  StadiumIcon,
211
151
  KeyIcon,
212
152
  HandIcon,
213
- ProfileIcon,
214
153
  SandclockIcon,
215
154
  TimerIcon,
216
155
  TagIcon,
217
156
  WildcardIcon
218
157
  } from "@/components/icons";
219
158
  import { EditIcon } from "@/components/icons";
220
- import StatusBadge from "@/components/ui/StatusBadge.vue";
221
- import TagLabel from "@/components/Editors/TagLabel.vue";
159
+ import ReadonlyFieldsSection from "@/components/ui/ReadonlyFieldsSection.vue";
222
160
  import ProfileCountryChooser from "@/components/Editors/Profile/ProfileCountryChooser.vue";
223
161
  import { useUIStore } from "@/stores/ui";
224
162
  import Dropdown from "@/components/ui/controls/atomic/Dropdown.vue";
225
- import { ref, computed, watch, nextTick, onMounted } from "vue";
226
- import { fakeId } from "@/stores/utils";
227
- import { validateCard } from "@/stores/utils";
228
-
229
- const props = defineProps({ profile: { type: Object, required: false } });
163
+ import { ref, watch, nextTick, onMounted } from "vue";
164
+ import { fakeId } from "@/libs/utils/dataGeneration";
165
+ import { validateCard } from "@/libs/utils/validation";
166
+
167
+ defineProps({
168
+ profile: {
169
+ type: Object,
170
+ default: null
171
+ }
172
+ });
230
173
  const errors = ref([]);
231
174
  const ui = useUIStore();
232
175
 
@@ -283,7 +226,7 @@ const usStates = [
283
226
  "WY"
284
227
  ];
285
228
  const cardNumberInput = ref(null);
286
- const profile = ref({
229
+ const formProfile = ref({
287
230
  cvv: "",
288
231
  cardNumber: "",
289
232
  city: "",
@@ -293,15 +236,15 @@ const profile = ref({
293
236
  zipCode: ""
294
237
  });
295
238
 
296
- if (ui.currentlyEditing?.profileName) profile.value = ui.currentlyEditing;
239
+ if (ui.currentlyEditing?.profileName) formProfile.value = ui.currentlyEditing;
297
240
 
298
241
  // Reactive display value for the formatted card number
299
242
  const displayCardNumber = ref("");
300
243
 
301
244
  // Initialize display card number with formatting
302
245
  const initializeCardNumberDisplay = () => {
303
- if (profile.value.cardNumber) {
304
- const cleanNumber = profile.value.cardNumber.replace(/\s+/g, "");
246
+ if (formProfile.value.cardNumber) {
247
+ const cleanNumber = formProfile.value.cardNumber.replace(/\s+/g, "");
305
248
  if (cleanNumber) {
306
249
  const cardInfo = validateCard(cleanNumber);
307
250
  displayCardNumber.value = cardInfo.formatted;
@@ -311,8 +254,8 @@ const initializeCardNumberDisplay = () => {
311
254
 
312
255
  // Format card number display on focus
313
256
  const formatCardNumberDisplay = () => {
314
- if (profile.value.cardNumber) {
315
- const cleanNumber = profile.value.cardNumber.replace(/\s+/g, "");
257
+ if (formProfile.value.cardNumber) {
258
+ const cleanNumber = formProfile.value.cardNumber.replace(/\s+/g, "");
316
259
  if (cleanNumber) {
317
260
  const cardInfo = validateCard(cleanNumber);
318
261
  displayCardNumber.value = cardInfo.formatted;
@@ -322,7 +265,7 @@ const formatCardNumberDisplay = () => {
322
265
 
323
266
  // Watch for changes in profile.cardNumber to sync with display
324
267
  watch(
325
- () => profile.value.cardNumber,
268
+ () => formProfile.value.cardNumber,
326
269
  (newValue) => {
327
270
  if (newValue) {
328
271
  const cleanNumber = newValue.replace(/\s+/g, "");
@@ -345,16 +288,16 @@ onMounted(() => {
345
288
 
346
289
  const generate = () => {
347
290
  const fake = fakeId();
348
- profile.value.city = fake.city;
349
- profile.value.zipCode = fake?.zipCode;
350
- profile.value.address = fake.address;
351
- profile.value.state = fake.state;
352
- profile.value.country = "US";
291
+ formProfile.value.city = fake.city;
292
+ formProfile.value.zipCode = fake?.zipCode;
293
+ formProfile.value.address = fake.address;
294
+ formProfile.value.state = fake.state;
295
+ formProfile.value.country = "US";
353
296
  };
354
297
 
355
298
  const chooseCountry = (f) => {
356
- profile.value.country = f;
357
- if (f !== "US") profile.value.state = "";
299
+ formProfile.value.country = f;
300
+ if (f !== "US") formProfile.value.state = "";
358
301
  };
359
302
 
360
303
  const validate = (p) => {
@@ -395,20 +338,20 @@ const handleCreditCardUpdate = (event) => {
395
338
  const cardInfo = validateCard(subs);
396
339
 
397
340
  // Store clean number (without spaces) in profile
398
- profile.value.cardNumber = subs;
341
+ formProfile.value.cardNumber = subs;
399
342
  // Display formatted number in input
400
343
  displayCardNumber.value = cardInfo.formatted;
401
344
  };
402
345
 
403
346
  function done() {
404
347
  // Clear state if country is not US
405
- if (profile.value.country !== "US") {
406
- profile.value.state = "";
348
+ if (formProfile.value.country !== "US") {
349
+ formProfile.value.state = "";
407
350
  }
408
351
 
409
- ui.logger.Info("Created profile", profile.value);
410
- if (validate(profile.value) !== true) return;
352
+ ui.logger.Info("Created profile", formProfile.value);
353
+ if (validate(formProfile.value) !== true) return;
411
354
  ui.toggleModal("");
412
- ui.addProfile(profile.value);
355
+ ui.addProfile(formProfile.value);
413
356
  }
414
357
  </script>
@@ -1,22 +1,22 @@
1
1
  <template>
2
2
  <Row
3
- class="relative grid-cols-7 text-white lg:grid-cols-8"
3
+ class="relative h-16 grid-cols-4 sm:grid-cols-5 md:grid-cols-7 lg:grid-cols-8 text-white"
4
4
  @click="ui.setOpenContextMenu('')"
5
5
  @click.right.prevent="ui.setOpenContextMenu('')"
6
6
  @dblclick="handleDoubleClick"
7
7
  @touchstart="handleTouchStart"
8
8
  @touchend="handleTouchEnd">
9
- <div class="col-span-3 flex lg:col-span-2">
9
+ <div class="col-span-2 sm:col-span-2 md:col-span-3 lg:col-span-2 flex">
10
10
  <Checkbox
11
11
  class="ml-0 mr-4"
12
12
  :toggled="props.profile.selected"
13
13
  @valueUpdate="ui.toggleProfileSelected(props.profile.id)" />
14
- <h4 class="mx-auto text-white">
14
+ <h4 class="mx-auto text-center text-white">
15
15
  {{ props.profile.profileName }}
16
16
  </h4>
17
17
  </div>
18
- <div class="col-span-1 lg:col-span-2">
19
- <h4 class="flex items-center justify-center gap-2 text-white">
18
+ <div class="col-span-1 hidden md:block lg:col-span-2">
19
+ <h4 class="flex items-center justify-center gap-2 text-center text-white">
20
20
  <span class="hidden sm:block">
21
21
  {{
22
22
  props.profile.privacy
@@ -29,20 +29,20 @@
29
29
  <img class="h-6 w-6" :src="getAccountType()" />
30
30
  </h4>
31
31
  </div>
32
- <div class="col-span-1">
33
- <h4 class="text-white">{{ expDate() }}</h4>
32
+ <div class="col-span-1 hidden md:block">
33
+ <h4 class="text-center text-white">{{ expDate() }}</h4>
34
34
  </div>
35
35
  <div class="col-span-1 flex justify-center">
36
36
  <StatusBadge :enabled="props.profile.enabled" size="small" />
37
37
  </div>
38
38
 
39
39
  <div class="col-span-1 hidden lg:block">
40
- <h4 class="flex justify-center gap-1 text-white">
40
+ <h4 class="flex justify-center gap-1 text-center text-white">
41
41
  <TagLabel v-for="tag in props.profile.tags" :key="tag" :text="tag" />
42
42
  </h4>
43
43
  </div>
44
44
 
45
- <div class="col-span-1 flex">
45
+ <div class="col-span-1 sm:col-span-1 flex">
46
46
  <ActionButtonGroup>
47
47
  <li>
48
48
  <button @click="edit">
@@ -66,26 +66,24 @@
66
66
  </div>
67
67
  </Row>
68
68
  </template>
69
- <style lang="scss" scoped>
70
- h4 {
71
- @apply text-center;
72
- }
73
- </style>
74
69
  <script setup>
75
70
  import { Row } from "@/components/Table";
76
- import { PlayIcon, TrashIcon, BagWhiteIcon, PauseIcon, EditIcon } from "@/components/icons";
71
+ import { TrashIcon, EditIcon } from "@/components/icons";
77
72
  import Checkbox from "@/components/ui/controls/atomic/Checkbox.vue";
78
73
  import StatusBadge from "@/components/ui/StatusBadge.vue";
79
74
  import ActionButtonGroup from "@/components/ui/ActionButtonGroup.vue";
80
75
  import { useUIStore } from "@/stores/ui";
81
- import { validateCard } from "@/stores/utils";
76
+ import { validateCard } from "@/libs/utils/validation";
82
77
  import TagLabel from "@/components/Editors/TagLabel.vue";
83
78
  import { useRowSelection } from "@/composables/useRowSelection";
84
79
 
85
80
  const ui = useUIStore();
86
81
 
87
82
  const props = defineProps({
88
- profile: { type: Object }
83
+ profile: {
84
+ type: Object,
85
+ required: true
86
+ }
89
87
  });
90
88
 
91
89
  const getAccountType = () => {
@@ -1,6 +1,6 @@
1
1
  <template>
2
2
  <div>
3
- <div class="dropdown input-default p-4 w-16 bg-dark-550 small-dropdown rounded-lg" ref="dropdownRef">
3
+ <div class="dropdown input-default h-10 w-12 md:h-10 flex justify-center items-center p-0 bg-dark-550 rounded-lg [background-clip:border-box]" ref="dropdownRef">
4
4
  <span @click="toggleOpen" class="flex justify-between items-center z-50 text-white">
5
5
  <div class="flex gap-3 justify-center">
6
6
  <img class="w-5" :src="`/flags/${current?.toLowerCase()}.svg`" />
@@ -9,7 +9,7 @@
9
9
  <Teleport to="body">
10
10
  <div
11
11
  v-if="open && !disabled"
12
- class="dropdown-content-portal special-dropdown"
12
+ class="min-w-20 bg-dark-400 border border-dark-650 rounded-lg shadow-2xl z-50 p-2 [max-height:192px] overflow-y-auto custom-scrollbar-y"
13
13
  :style="menuStyle"
14
14
  @click.stop
15
15
  @wheel.stop
@@ -17,9 +17,9 @@
17
17
  <div
18
18
  v-for="(country, i) in countries"
19
19
  v-bind:key="country"
20
- :class="`cursor-pointer w-12 ${i === 0 ? '' : 'my-2'}`"
20
+ :class="`px-3 py-2 text-sm text-white cursor-pointer rounded-md ${i === 0 ? '' : 'my-2'}`"
21
21
  @click="set(country)">
22
- <div class="flex justify-center items-center smooth-hover">
22
+ <div class="flex items-center justify-center gap-3 smooth-hover">
23
23
  <span class="text-sm">{{ country }}</span>
24
24
  <img class="w-5 ml-3" :src="`/flags/${country?.toLowerCase()}.svg`" />
25
25
  </div>
@@ -40,9 +40,18 @@ const open = ref(false);
40
40
  const dropdownRef = ref(null);
41
41
 
42
42
  const props = defineProps({
43
- value: { type: String },
44
- onClick: { type: Function },
45
- disabled: { type: Boolean, required: false }
43
+ value: {
44
+ type: String,
45
+ default: 'US'
46
+ },
47
+ onClick: {
48
+ type: Function,
49
+ required: true
50
+ },
51
+ disabled: {
52
+ type: Boolean,
53
+ default: false
54
+ }
46
55
  });
47
56
 
48
57
  const current = ref(props.value || "US");
@@ -82,56 +91,3 @@ watch(
82
91
  (n) => (current.value = n)
83
92
  );
84
93
  </script>
85
-
86
- <style scoped>
87
- .special-dropdown {
88
- @apply min-w-20;
89
- }
90
-
91
- .small-dropdown {
92
- @apply h-10 !important;
93
- background-clip: border-box !important;
94
- /* border-radius: 100% !important; */
95
- padding: 0;
96
- width: 3em !important;
97
- display: flex;
98
- justify-items: center;
99
- justify-content: center;
100
- }
101
-
102
- @media (min-width: 768px) {
103
- .small-dropdown {
104
- height: 40px !important; /* Match input-default responsive height */
105
- }
106
- }
107
-
108
- .dropdown-content-portal {
109
- @apply bg-dark-400 border border-dark-650 rounded-lg shadow-2xl z-50;
110
- padding: 0.5rem;
111
- max-height: 192px !important;
112
- overflow-y: auto !important;
113
- overscroll-behavior: contain !important;
114
- touch-action: pan-y !important;
115
- -webkit-overflow-scrolling: touch !important;
116
- scrollbar-width: none;
117
- -ms-overflow-style: none;
118
- }
119
-
120
- .dropdown-content-portal::-webkit-scrollbar {
121
- display: none;
122
- }
123
-
124
- .dropdown-content-portal > div {
125
- @apply px-3 py-2 text-sm text-white cursor-pointer;
126
- border-radius: 6px;
127
- }
128
-
129
- .dropdown-content-portal > div:hover {
130
- /* Removed hover background */
131
- }
132
-
133
- .dropdown-content-portal > div .flex {
134
- @apply items-center justify-center;
135
- gap: 0.75rem;
136
- }
137
- </style>