@necrolab/dashboard 0.5.12 → 0.5.14

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 (54) hide show
  1. package/.playwright-mcp/verification-accounts-desktop.png +0 -0
  2. package/.playwright-mcp/verification-tasks-desktop.png +0 -0
  3. package/.playwright-mcp/verification-tasks-mobile.png +0 -0
  4. package/README.md +21 -0
  5. package/docs/plans/2026-02-08-tailwind-consolidation-results.md +476 -0
  6. package/docs/plans/2026-02-08-tailwind-consolidation.md +2416 -0
  7. package/package.json +1 -1
  8. package/src/App.vue +2 -163
  9. package/src/assets/css/components/buttons.scss +43 -95
  10. package/src/assets/css/components/forms.scss +10 -28
  11. package/src/assets/css/components/search-groups.scss +80 -0
  12. package/src/assets/css/components/tables.scss +0 -8
  13. package/src/assets/css/main.scss +2 -43
  14. package/src/components/Editors/Account/Account.vue +14 -220
  15. package/src/components/Editors/Account/AccountCreator.vue +0 -4
  16. package/src/components/Editors/Account/AccountView.vue +0 -1
  17. package/src/components/Editors/Account/CreateAccount.vue +36 -107
  18. package/src/components/Editors/Profile/CreateProfile.vue +46 -135
  19. package/src/components/Editors/Profile/Profile.vue +10 -213
  20. package/src/components/Editors/Profile/ProfileView.vue +0 -1
  21. package/src/components/Filter/Filter.vue +14 -17
  22. package/src/components/Filter/FilterPreview.vue +0 -6
  23. package/src/components/Table/Row.vue +1 -1
  24. package/src/components/Table/Table.vue +2 -16
  25. package/src/components/Tasks/CreateTaskAXS.vue +45 -104
  26. package/src/components/Tasks/CreateTaskTM.vue +58 -96
  27. package/src/components/Tasks/Task.vue +22 -209
  28. package/src/components/Tasks/TaskView.vue +5 -4
  29. package/src/components/Tasks/ViewTask.vue +201 -214
  30. package/src/components/icons/Copy.vue +6 -0
  31. package/src/components/icons/index.js +3 -1
  32. package/src/components/ui/ActionButtonGroup.vue +70 -0
  33. package/src/components/ui/FormField.vue +74 -0
  34. package/src/components/ui/InfoRow.vue +100 -0
  35. package/src/components/ui/Modal.vue +6 -47
  36. package/src/components/ui/Navbar.vue +15 -43
  37. package/src/components/ui/ReconnectIndicator.vue +4 -4
  38. package/src/components/ui/SectionCard.vue +24 -0
  39. package/src/components/ui/Splash.vue +1 -6
  40. package/src/components/ui/StatusBadge.vue +37 -0
  41. package/src/components/ui/controls/CountryChooser.vue +14 -58
  42. package/src/components/ui/controls/atomic/Dropdown.vue +16 -24
  43. package/src/components/ui/controls/atomic/MultiDropdown.vue +7 -1
  44. package/src/components/ui/controls/atomic/Switch.vue +13 -29
  45. package/src/composables/useCopyToClipboard.js +25 -0
  46. package/src/composables/useRowSelection.js +48 -0
  47. package/src/views/Accounts.vue +0 -81
  48. package/src/views/Console.vue +4 -21
  49. package/src/views/Editor.vue +48 -138
  50. package/src/views/FilterBuilder.vue +0 -23
  51. package/src/views/Login.vue +14 -63
  52. package/src/views/Profiles.vue +0 -82
  53. package/src/views/Tasks.vue +3 -24
  54. package/tailwind.config.js +47 -5
@@ -6,12 +6,9 @@
6
6
  <style lang="scss">
7
7
  .table-component {
8
8
  @apply flex-col bg-clip-padding rounded relative box-border border border-dark-600 bg-dark-500;
9
+ @apply overflow-x-auto overflow-y-auto touch-pan-x touch-pan-y;
9
10
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
10
- overflow-x: auto !important;
11
- overflow-y: auto !important;
12
- overscroll-behavior: auto !important;
13
- // Prevent pinch-to-zoom while allowing scrolling
14
- touch-action: pan-x pan-y !important;
11
+ overscroll-behavior: auto;
15
12
  max-height: calc(100vh - 200px);
16
13
  -webkit-overflow-scrolling: touch;
17
14
  }
@@ -24,15 +21,4 @@
24
21
  min-width: 640px;
25
22
  }
26
23
  }
27
-
28
- /* iPhone landscape mode table optimization */
29
- @media screen and (max-height: 500px) and (orientation: landscape) {
30
- .table-component {
31
- max-height: calc(100vh - 160px) !important; // Leave even more space at bottom
32
- width: 100% !important;
33
- overflow-x: auto !important; // Allow horizontal scrolling if needed
34
- overflow-y: auto !important; // Allow vertical scrolling
35
- margin-bottom: 2rem !important; // Increase bottom margin for better spacing
36
- }
37
- }
38
24
  </style>
@@ -8,69 +8,36 @@
8
8
  <!-- Task Form -->
9
9
  <div class="form-grid mb-4 mt-4">
10
10
  <!-- Event ID -->
11
- <div class="input-wrapper">
12
- <label class="label-override mb-2">
13
- Event ID
14
- <StadiumIcon />
15
- </label>
16
- <div class="input-default required">
17
- <input placeholder="827474" v-model="task.eventId" required />
18
- </div>
19
- </div>
11
+ <FormField label="Event ID" :icon="StadiumIcon" required>
12
+ <input placeholder="827474" v-model="task.eventId" required />
13
+ </FormField>
14
+
20
15
  <!-- Email -->
21
- <div class="input-wrapper">
22
- <label class="label-override mb-2">
23
- Email
24
- <MailIcon />
25
- </label>
26
- <div class="input-default">
27
- <input
28
- placeholder="Email"
29
- v-model="task.email"
30
- autocomplete="off"
31
- data-form-type="other"
32
- name="axs_email_not_for_auth" />
33
- </div>
34
- </div>
16
+ <FormField label="Email" :icon="MailIcon">
17
+ <input
18
+ placeholder="Email"
19
+ v-model="task.email"
20
+ autocomplete="off"
21
+ data-form-type="other"
22
+ name="axs_email_not_for_auth" />
23
+ </FormField>
24
+
35
25
  <!-- Proxy -->
36
- <div class="input-wrapper">
37
- <label class="label-override mb-2">
38
- Proxy
39
- <CameraIcon />
40
- </label>
41
- <div class="input-default">
42
- <input placeholder="Proxy" v-model="task.proxy" autocomplete="off" />
43
- </div>
44
- </div>
26
+ <FormField label="Proxy" :icon="CameraIcon">
27
+ <input placeholder="Proxy" v-model="task.proxy" autocomplete="off" />
28
+ </FormField>
29
+
45
30
  <!-- Presale Code -->
46
- <div class="input-wrapper">
47
- <label class="label-override mb-2">
48
- Presale Code
49
- <AwardIcon />
50
- </label>
51
- <div class="input-default">
52
- <input placeholder="Code" v-model="task.presaleCode" maxlength="15" autocomplete="off" />
53
- </div>
54
- </div>
55
- <!-- Ticket Quantity -->
56
- <div class="input-wrapper">
57
- <label class="label-override mb-2">
58
- Ticket Quantity
59
- <BagIcon />
60
- </label>
61
- <div class="input-default">
62
- <input placeholder="20" min="1" type="number" pattern="\d*" v-model="task.quantity" />
63
- <div class="input-incrementer">
64
- <button @click="task.quantity++">
65
- <UpIcon />
66
- </button>
67
- <button @click="if (task.quantity > 1) task.quantity--;">
68
- <DownIcon />
69
- </button>
70
- </div>
71
- </div>
72
- </div>
31
+ <FormField label="Presale Code" :icon="AwardIcon">
32
+ <input placeholder="Code" v-model="task.presaleCode" maxlength="15" autocomplete="off" />
33
+ </FormField>
34
+
73
35
  <!-- Ticket Quantity -->
36
+ <FormField label="Ticket Quantity" :icon="BagIcon" incrementer @increment="task.quantity++" @decrement="task.quantity > 1 && task.quantity--">
37
+ <input placeholder="20" min="1" type="number" pattern="\d*" v-model="task.quantity" />
38
+ </FormField>
39
+
40
+ <!-- Task Amount -->
74
41
  <div class="input-wrapper">
75
42
  <label class="label-override mb-2">
76
43
  Amount
@@ -90,13 +57,13 @@
90
57
  </div>
91
58
 
92
59
  <!-- Profile Tag(s) -->
93
- <div class="input-wrapper relative-positioned z-tooltip">
60
+ <div class="input-wrapper">
94
61
  <label class="label-override mb-2">
95
62
  Profile Tag(s)
96
63
  <TagIcon />
97
64
  </label>
98
65
  <MultiDropdown
99
- class="input-default w-full will-change-auto"
66
+ class="w-full will-change-auto"
100
67
  :onSelect="(v) => (task.profileTags = v)"
101
68
  default="Any"
102
69
  :options="
@@ -107,12 +74,11 @@
107
74
  </div>
108
75
 
109
76
  <!-- Account Tag -->
110
- <div class="input-wrapper relative-positioned z-dropdown">
77
+ <div class="input-wrapper">
111
78
  <label class="label-override mb-2">
112
79
  Account Tag
113
80
  <ScannerIcon />
114
81
  </label>
115
-
116
82
  <Dropdown
117
83
  :onClick="(f) => (task.accountTag = f)"
118
84
  default="Default tag"
@@ -120,28 +86,18 @@
120
86
  :options="accountTagOptions"
121
87
  :allowDefault="false"
122
88
  :capitalize="true"
123
- class="input-default dropdown w-full p-4" />
89
+ class="dropdown w-full" />
124
90
  </div>
125
91
 
126
- <div class="input-wrapper">
127
- <label class="label-override mb-2">
128
- Start Offset (Minutes)
129
- <ShieldIcon />
130
- </label>
131
- <div class="input-default">
132
- <input placeholder="120" type="number" pattern="\d*" v-model="task.startOffset" />
133
- </div>
134
- </div>
92
+ <!-- Start Offset -->
93
+ <FormField label="Start Offset (Minutes)" :icon="ShieldIcon" incrementer @increment="task.startOffset = (task.startOffset || 0) + 1" @decrement="task.startOffset > 0 && task.startOffset--">
94
+ <input placeholder="120" type="number" pattern="\d*" v-model.number="task.startOffset" />
95
+ </FormField>
135
96
 
136
- <div class="input-wrapper">
137
- <label class="label-override mb-2">
138
- Promo ID
139
- <AwardIcon />
140
- </label>
141
- <div class="input-default">
142
- <input placeholder="63668" v-model="task.promoId" />
143
- </div>
144
- </div>
97
+ <!-- Promo ID -->
98
+ <FormField label="Promo ID" :icon="AwardIcon">
99
+ <input placeholder="63668" v-model="task.promoId" />
100
+ </FormField>
145
101
  </div>
146
102
  <div class="mb-3 border border-dark-650" />
147
103
  <!-- Task Switches -->
@@ -194,6 +150,7 @@
194
150
  import { ref, watch } from "vue";
195
151
  import { countries } from "@/stores/countries";
196
152
  import Modal from "@/components/ui/Modal.vue";
153
+ import FormField from "@/components/ui/FormField.vue";
197
154
  import Switch from "@/components/ui/controls/atomic/Switch.vue";
198
155
  import {
199
156
  MailIcon,
@@ -306,11 +263,15 @@ watch(
306
263
 
307
264
  <style lang="scss" scoped>
308
265
  .label-override {
309
- @apply flex;
266
+ @apply flex items-center;
310
267
  color: #e1e1e4 !important;
311
268
 
312
- img {
269
+ svg {
313
270
  @apply ml-2;
271
+
272
+ path {
273
+ fill: #e1e1e4 !important;
274
+ }
314
275
  }
315
276
  }
316
277
 
@@ -332,18 +293,6 @@ watch(
332
293
  }
333
294
  }
334
295
  }
335
- </style>
336
- <style lang="scss" scoped>
337
- .label-override {
338
- svg {
339
- @apply ml-2;
340
-
341
- path {
342
- fill: #e1e1e4 !important;
343
- }
344
- }
345
- @apply flex items-center;
346
- }
347
296
 
348
297
  .switch-wrapper {
349
298
  svg {
@@ -352,12 +301,4 @@ watch(
352
301
  }
353
302
  }
354
303
  }
355
-
356
- .z-inf {
357
- z-index: 1000;
358
- }
359
-
360
- .z-inf2 {
361
- z-index: 2000;
362
- }
363
304
  </style>
@@ -10,72 +10,39 @@
10
10
  <!-- Task Form -->
11
11
  <div class="grid-responsive-1-2 gap-responsive mb-4 mt-4">
12
12
  <!-- Event ID -->
13
- <div class="input-wrapper">
14
- <label class="label-override mb-2">
15
- Event ID
16
- <StadiumIcon />
17
- </label>
18
- <div class="input-default required">
19
- <input
20
- :placeholder="!isEU(ui.currentCountry.siteId) ? '102PDA9125510GYU' : '529171'"
21
- v-model="task.eventId"
22
- required />
23
- </div>
24
- </div>
13
+ <FormField label="Event ID" :icon="StadiumIcon" required>
14
+ <input
15
+ :placeholder="!isEU(ui.currentCountry.siteId) ? '102PDA9125510GYU' : '529171'"
16
+ v-model="task.eventId"
17
+ required />
18
+ </FormField>
19
+
25
20
  <!-- Email -->
26
- <div class="input-wrapper">
27
- <label class="label-override mb-2">
28
- Email
29
- <MailIcon />
30
- </label>
31
- <div class="input-default">
32
- <input
33
- placeholder="Email"
34
- v-model="task.email"
35
- autocomplete="off"
36
- data-form-type="other"
37
- name="tm_email_disableautocomplete" />
38
- </div>
39
- </div>
21
+ <FormField label="Email" :icon="MailIcon">
22
+ <input
23
+ placeholder="Email"
24
+ v-model="task.email"
25
+ autocomplete="off"
26
+ data-form-type="other"
27
+ name="tm_email_disableautocomplete" />
28
+ </FormField>
29
+
40
30
  <!-- Proxy -->
41
- <div class="input-wrapper">
42
- <label class="label-override mb-2">
43
- Proxy
44
- <CameraIcon />
45
- </label>
46
- <div class="input-default">
47
- <input placeholder="Proxy" v-model="task.proxy" autocomplete="off" />
48
- </div>
49
- </div>
31
+ <FormField label="Proxy" :icon="CameraIcon">
32
+ <input placeholder="Proxy" v-model="task.proxy" autocomplete="off" />
33
+ </FormField>
34
+
50
35
  <!-- Presale Code -->
51
- <div class="input-wrapper">
52
- <label class="label-override mb-2">
53
- Presale Code
54
- <AwardIcon />
55
- </label>
56
- <div class="input-default">
57
- <input placeholder="Code" v-model="task.presaleCode" maxlength="15" autocomplete="off" />
58
- </div>
59
- </div>
60
- <!-- Ticket Quantity -->
61
- <div class="input-wrapper">
62
- <label class="label-override mb-2">
63
- Ticket Quantity
64
- <BagIcon />
65
- </label>
66
- <div class="input-default">
67
- <input placeholder="20" min="1" type="number" pattern="\d*" v-model="task.quantity" />
68
- <div class="input-incrementer">
69
- <button @click="task.quantity++">
70
- <UpIcon />
71
- </button>
72
- <button @click="if (task.quantity > 1) task.quantity--;">
73
- <DownIcon />
74
- </button>
75
- </div>
76
- </div>
77
- </div>
36
+ <FormField label="Presale Code" :icon="AwardIcon">
37
+ <input placeholder="Code" v-model="task.presaleCode" maxlength="15" autocomplete="off" />
38
+ </FormField>
39
+
78
40
  <!-- Ticket Quantity -->
41
+ <FormField label="Ticket Quantity" :icon="BagIcon" incrementer @increment="task.quantity++" @decrement="task.quantity > 1 && task.quantity--">
42
+ <input placeholder="20" min="1" type="number" pattern="\d*" v-model="task.quantity" />
43
+ </FormField>
44
+
45
+ <!-- Task Amount -->
79
46
  <div class="input-wrapper">
80
47
  <label class="label-override mb-2">
81
48
  Amount
@@ -95,13 +62,13 @@
95
62
  </div>
96
63
 
97
64
  <!-- Profile Tag(s) -->
98
- <div class="input-wrapper relative-positioned z-tooltip">
65
+ <div class="input-wrapper">
99
66
  <label class="label-override mb-2">
100
67
  Profile Tag(s)
101
68
  <TagIcon />
102
69
  </label>
103
70
  <MultiDropdown
104
- class="input-default w-full will-change-auto"
71
+ class="w-full will-change-auto"
105
72
  :onSelect="(v) => (task.profileTags = v)"
106
73
  default="Any"
107
74
  :options="
@@ -112,23 +79,16 @@
112
79
  </div>
113
80
 
114
81
  <!-- CL Origin -->
115
- <div v-if="isEU(ui.currentCountry.siteId)" class="input-wrapper">
116
- <label class="label-override mb-2">
117
- CL Origin
118
- <AwardIcon />
119
- </label>
120
- <div class="input-default">
121
- <input placeholder="ORIGIN2" type="text" v-model="task.clOrigin" maxlength="15" />
122
- </div>
123
- </div>
82
+ <FormField v-if="isEU(ui.currentCountry.siteId)" label="CL Origin" :icon="AwardIcon">
83
+ <input placeholder="ORIGIN2" type="text" v-model="task.clOrigin" maxlength="15" />
84
+ </FormField>
124
85
 
125
86
  <!-- Account Tag -->
126
- <div class="input-wrapper relative-positioned z-dropdown">
87
+ <div class="input-wrapper">
127
88
  <label class="label-override mb-2">
128
89
  Account Tag
129
90
  <ScannerIcon />
130
91
  </label>
131
-
132
92
  <Dropdown
133
93
  :onClick="(f) => (task.accountTag = f)"
134
94
  default="Default tag"
@@ -136,30 +96,18 @@
136
96
  :options="accountTagOptions"
137
97
  :allowDefault="false"
138
98
  :capitalize="true"
139
- class="input-default dropdown w-full p-4" />
99
+ class="dropdown w-full" />
140
100
  </div>
141
101
 
142
- <div class="input-wrapper">
143
- <label class="label-override mb-2">
144
- Start Offset (Minutes)
145
- <ShieldIcon />
146
- </label>
147
- <div class="input-default">
148
- <input placeholder="120" type="number" pattern="\d*" v-model="task.startOffset" />
149
- </div>
150
- </div>
102
+ <!-- Start Offset -->
103
+ <FormField label="Start Offset (Minutes)" :icon="ShieldIcon" incrementer @increment="task.startOffset = (task.startOffset || 0) + 1" @decrement="task.startOffset > 0 && task.startOffset--">
104
+ <input placeholder="120" type="number" pattern="\d*" v-model.number="task.startOffset" />
105
+ </FormField>
151
106
 
152
- <div v-if="!isEU(ui.currentCountry.siteId)">
153
- <div class="input-wrapper">
154
- <label class="label-override mb-2">
155
- Presale DID
156
- <AwardIcon />
157
- </label>
158
- <div class="input-default">
159
- <input placeholder="uklnfan2ps" v-model="task.eventDid" maxlength="15" />
160
- </div>
161
- </div>
162
- </div>
107
+ <!-- Presale DID -->
108
+ <FormField v-if="!isEU(ui.currentCountry.siteId)" label="Presale DID" :icon="AwardIcon">
109
+ <input placeholder="uklnfan2ps" v-model="task.eventDid" maxlength="15" />
110
+ </FormField>
163
111
  </div>
164
112
  <div class="mb-3 border border-dark-650" />
165
113
  <!-- Task Switches -->
@@ -314,6 +262,7 @@
314
262
  <script setup>
315
263
  import { ref, watch } from "vue";
316
264
  import Modal from "@/components/ui/Modal.vue";
265
+ import FormField from "@/components/ui/FormField.vue";
317
266
  import Switch from "@/components/ui/controls/atomic/Switch.vue";
318
267
  import {
319
268
  MailIcon,
@@ -440,6 +389,19 @@ watch(
440
389
  </script>
441
390
 
442
391
  <style lang="scss" scoped>
392
+ .label-override {
393
+ @apply flex items-center;
394
+ color: #e1e1e4 !important;
395
+
396
+ svg {
397
+ @apply ml-2;
398
+
399
+ path {
400
+ fill: #e1e1e4 !important;
401
+ }
402
+ }
403
+ }
404
+
443
405
  .switch-wrapper {
444
406
  svg path {
445
407
  fill: oklch(0.65 0 0) !important;