@necrolab/dashboard 0.4.33 → 0.4.34

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.
@@ -38,7 +38,10 @@
38
38
  "Bash(sudo chown:*)",
39
39
  "Bash(sudo npm install:*)",
40
40
  "Bash(node:*)",
41
- "Bash(git checkout:*)"
41
+ "Bash(git checkout:*)",
42
+ "Bash(npx vue-tsc:*)",
43
+ "Bash(npx vite build:*)",
44
+ "Bash(npx eslint:*)"
42
45
  ],
43
46
  "deny": []
44
47
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@necrolab/dashboard",
3
- "version": "0.4.33",
3
+ "version": "0.4.34",
4
4
  "scripts": {
5
5
  "build": "rm -rf dist && vite build && npx workbox-cli generateSW workbox-config.js",
6
6
  "dev": "vite",
package/src/App.vue CHANGED
@@ -264,14 +264,6 @@ watch(
264
264
  const layout = computed(() => router.currentRoute.value.meta.layout);
265
265
  </script>
266
266
  <style lang="scss">
267
- .task-buttons {
268
- @apply flex mx-auto gap-x-4;
269
-
270
- svg {
271
- width: 15px;
272
- height: 15px;
273
- }
274
- }
275
267
 
276
268
  .dropdown {
277
269
  position: relative;
@@ -123,7 +123,7 @@ input[type="number"] {
123
123
  }
124
124
  // Ant Design Select styling
125
125
  .ant-select-dropdown {
126
- z-index: 20000000000;
126
+ z-index: 10000 !important;
127
127
  position: relative;
128
128
  @apply rounded-lg #{!important};
129
129
  }
@@ -1,5 +1,29 @@
1
1
  @use "input";
2
2
 
3
+ /* Global input styling fixes for iOS and other platforms */
4
+ input, textarea, select, button {
5
+ /* Remove iOS blue highlight/border */
6
+ -webkit-tap-highlight-color: transparent;
7
+ -webkit-touch-callout: none;
8
+
9
+ /* Remove default focus outline */
10
+ outline: none;
11
+ }
12
+
13
+ input, textarea, select {
14
+ /* Remove browser default styling */
15
+ -webkit-appearance: none;
16
+ -moz-appearance: none;
17
+ appearance: none;
18
+ }
19
+
20
+ /* Enhanced focus state removal for iOS */
21
+ input:focus, textarea:focus, select:focus {
22
+ outline: none !important;
23
+ -webkit-tap-highlight-color: transparent !important;
24
+ box-shadow: none !important;
25
+ }
26
+
3
27
  // Base styles
4
28
  html {
5
29
  overscroll-behavior: contain;
@@ -88,16 +112,42 @@ img {
88
112
 
89
113
  svg {
90
114
  @apply ml-2;
115
+ color: #6e7084 !important;
116
+ width: 16px;
117
+ height: 16px;
118
+ fill: #6e7084 !important;
91
119
  }
92
120
  }
93
121
 
94
122
  // Use CSS custom property to avoid global path selector
95
123
  .label-override svg {
96
- color: #6e7084;
124
+ color: #6e7084 !important;
125
+ fill: #6e7084 !important;
97
126
  }
98
127
 
99
128
  .label-override svg path {
100
- fill: currentColor;
129
+ fill: #6e7084 !important;
130
+ color: #6e7084 !important;
131
+ }
132
+
133
+ .label-override svg * {
134
+ fill: #6e7084 !important;
135
+ color: #6e7084 !important;
136
+ }
137
+
138
+ .switch-wrapper svg {
139
+ color: #6e7084 !important;
140
+ fill: #6e7084 !important;
141
+ }
142
+
143
+ .switch-wrapper svg path {
144
+ fill: #6e7084 !important;
145
+ color: #6e7084 !important;
146
+ }
147
+
148
+ .switch-wrapper svg * {
149
+ fill: #6e7084 !important;
150
+ color: #6e7084 !important;
101
151
  }
102
152
 
103
153
  // Component utilities
@@ -109,9 +159,6 @@ img {
109
159
  @apply w-2 h-2 rounded-full;
110
160
  }
111
161
 
112
- .task-buttons {
113
- @apply bg-dark-600 px-1 lg:px-2 rounded-full shadow-lg items-center flex gap-x-1;
114
- }
115
162
 
116
163
  .mobile-icons {
117
164
  @apply flex lg:hidden ml-auto items-center gap-x-2;
@@ -60,28 +60,76 @@ h4 {
60
60
  @apply text-center;
61
61
  }
62
62
  .task-buttons {
63
- @apply flex mx-auto gap-x-2;
64
-
63
+ @apply flex items-center justify-center mx-auto;
64
+ background: linear-gradient(135deg, rgba(45, 47, 74, 0.8), rgba(32, 32, 54, 0.9));
65
+ border: 1px solid rgba(74, 74, 97, 0.3);
66
+ border-radius: 10px;
67
+ padding: 2px;
68
+ gap: 1px;
69
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15), inset 0 1px 0 rgba(255, 255, 255, 0.1);
70
+ backdrop-filter: blur(8px);
71
+
65
72
  button {
66
- @apply p-1 rounded transition-colors hover:bg-dark-500;
73
+ @apply flex items-center justify-center text-white transition-all duration-150 border-0 outline-0 relative;
74
+ background: transparent;
75
+ border-radius: 7px;
76
+ width: 28px;
77
+ height: 28px;
78
+ position: relative;
79
+
80
+ &:hover {
81
+ background: rgba(74, 74, 97, 0.3);
82
+ transform: scale(1.05);
83
+ }
84
+
85
+ &:active {
86
+ background: rgba(74, 74, 97, 0.5);
87
+ transform: scale(0.95);
88
+ }
67
89
  }
68
-
90
+
69
91
  svg {
70
- @apply w-4 h-4;
92
+ width: 14px;
93
+ height: 14px;
94
+ position: relative;
95
+ z-index: 1;
96
+
97
+ path {
98
+ fill: currentColor;
99
+ }
71
100
  }
72
-
101
+
73
102
  img {
74
- @apply w-4 h-4;
103
+ width: 14px;
104
+ height: 14px;
105
+ position: relative;
106
+ z-index: 1;
75
107
  }
76
108
  }
77
109
 
110
+ // Tablet optimization
78
111
  @media (max-width: 1024px) {
79
112
  h4 {
80
113
  font-size: 10px !important;
81
114
  }
115
+
82
116
  .task-buttons {
83
- @apply gap-x-3;
117
+ padding: 2px;
118
+ gap: 1px;
119
+ border-radius: 8px;
120
+
121
+ button {
122
+ width: 26px;
123
+ height: 26px;
124
+ border-radius: 6px;
125
+ }
126
+
127
+ svg, img {
128
+ width: 13px;
129
+ height: 13px;
130
+ }
84
131
  }
132
+
85
133
  .task-id {
86
134
  font-size: 6px !important;
87
135
  margin-right: -12px;
@@ -91,6 +139,51 @@ h4 {
91
139
  font-size: 7px !important;
92
140
  }
93
141
  }
142
+
143
+ // Mobile optimization
144
+ @media (max-width: 768px) {
145
+ .task-buttons {
146
+ padding: 1px;
147
+ gap: 0;
148
+ border-radius: 7px;
149
+ box-shadow: 0 1px 6px rgba(0, 0, 0, 0.15), inset 0 1px 0 rgba(255, 255, 255, 0.08);
150
+
151
+ button {
152
+ width: 22px;
153
+ height: 22px;
154
+ border-radius: 5px;
155
+ }
156
+
157
+ svg, img {
158
+ width: 11px;
159
+ height: 11px;
160
+ }
161
+ }
162
+ }
163
+
164
+ // iPhone vertical (portrait) specific
165
+ @media (max-width: 480px) and (orientation: portrait) {
166
+ .task-buttons {
167
+ padding: 1px;
168
+ gap: 0;
169
+ border-radius: 6px;
170
+
171
+ button {
172
+ width: 18px;
173
+ height: 18px;
174
+ border-radius: 4px;
175
+
176
+ &:hover {
177
+ transform: scale(1.1);
178
+ }
179
+ }
180
+
181
+ svg, img {
182
+ width: 9px;
183
+ height: 9px;
184
+ }
185
+ }
186
+ }
94
187
  </style>
95
188
  <script setup>
96
189
  import { Row } from "@/components/Table";
@@ -6,6 +6,7 @@
6
6
  class="mr-3"
7
7
  :toggled="ui.mainCheckbox.accounts"
8
8
  @valueUpdate="ui.toggleMainCheckbox('accounts')"
9
+ :isHeader="true"
9
10
  />
10
11
  <div class="mx-auto flex items-center" @click="ui.toggleSort('eventId')">
11
12
  <MailIcon class="mr-0 ipadlg:mr-3 w-4 h-4" />
@@ -9,7 +9,9 @@
9
9
  <div>
10
10
  <div class="my-3 grid grid-cols-12 gap-3 mt-7 mb-4">
11
11
  <div class="input-wrapper col-span-4 z-10">
12
- <label class="label-override">Profile Tag </label>
12
+ <label class="label-override">Profile Tag
13
+ <TagIcon />
14
+ </label>
13
15
  <Dropdown
14
16
  :class="`input-default dropdown w-full ${errors.includes('profileTag') ? 'error' : ''}`"
15
17
  :default="ui.profile.accountTags[0]"
@@ -19,7 +21,9 @@
19
21
  />
20
22
  </div>
21
23
  <div class="input-wrapper col-span-8">
22
- <label class="label-override">Email </label>
24
+ <label class="label-override">Email
25
+ <MailIcon />
26
+ </label>
23
27
  <div :class="`input-default required ${errors.includes('email') ? 'error' : ''}`">
24
28
  <input
25
29
  placeholder="email@example.com"
@@ -39,7 +43,9 @@
39
43
  </div>
40
44
  </div>
41
45
  <div class="input-wrapper col-span-12">
42
- <label class="label-override">Password </label>
46
+ <label class="label-override">Password
47
+ <KeyIcon />
48
+ </label>
43
49
  <div :class="`input-default required ${errors.includes('password') ? 'error' : ''}`">
44
50
  <input
45
51
  placeholder="***********"
@@ -72,7 +78,7 @@
72
78
  </style>
73
79
  <script setup>
74
80
  import Modal from "@/components/ui/Modal.vue";
75
- import { EditIcon } from "@/components/icons";
81
+ import { EditIcon, MailIcon, KeyIcon, ProfileIcon, TimerIcon, SandclockIcon, TagIcon } from "@/components/icons";
76
82
  import { useUIStore } from "@/stores/ui";
77
83
  import Dropdown from "@/components/ui/controls/atomic/Dropdown.vue";
78
84
 
@@ -10,7 +10,9 @@
10
10
  <div class="grid grid-cols-12 gap-3 my-3">
11
11
  <!-- Profile tag -->
12
12
  <div class="input-wrapper col-span-4" style="z-index: 30 !important">
13
- <label class="label-override mb-2">Profile Tag </label>
13
+ <label class="label-override mb-2">Profile Tag
14
+ <TagIcon />
15
+ </label>
14
16
  <Dropdown
15
17
  :class="`input-default dropdown w-full ${errors.includes('profileTag') ? 'error' : ''}`"
16
18
  :default="ui.profile.accountTags[0]"
@@ -22,7 +24,9 @@
22
24
 
23
25
  <!-- Card Number -->
24
26
  <div class="input-wrapper col-span-8 z-0">
25
- <label class="label-override mb-2">Card Number </label>
27
+ <label class="label-override mb-2">Card Number
28
+ <CartIcon />
29
+ </label>
26
30
  <div :class="`input-default ${errors.includes('cardNumber') ? 'error' : ''}`">
27
31
  <input
28
32
  ref="cardNumberInput"
@@ -38,7 +42,9 @@
38
42
 
39
43
  <!-- Country chooser -->
40
44
  <div class="input-wrapper col-span-2">
41
- <label class="label-override mb-2">Country </label>
45
+ <label class="label-override mb-2">Country
46
+ <SandclockIcon />
47
+ </label>
42
48
  <ProfileCountryChooser
43
49
  class="h-8"
44
50
  :value="profile.country"
@@ -49,7 +55,9 @@
49
55
 
50
56
  <!-- Exp Year -->
51
57
  <div class="input-wrapper col-span-5">
52
- <label class="label-override mb-2 z-0">Expiry Year </label>
58
+ <label class="label-override mb-2 z-0">Expiry Year
59
+ <TimerIcon />
60
+ </label>
53
61
  <Dropdown
54
62
  :class="`input-default dropdown w-full ${errors.includes('expYear') ? 'error' : ''}`"
55
63
  default="Expiry Year"
@@ -66,8 +74,10 @@
66
74
  </div>
67
75
 
68
76
  <!-- Exp Month -->
69
- <div class="input-wrapper col-span-5">
70
- <label class="label-override mb-2">Expiry Month </label>
77
+ <div class="input-wrapper col-span-5 z-2">
78
+ <label class="label-override mb-2">Expiry Month
79
+ <TimerIcon />
80
+ </label>
71
81
  <Dropdown
72
82
  :class="`input-default dropdown w-full ${errors.includes('expMonth') ? 'error' : ''}`"
73
83
  default="Expiry Month"
@@ -79,7 +89,9 @@
79
89
 
80
90
  <!-- CVV -->
81
91
  <div class="input-wrapper col-span-6 md:col-span-4 z-0">
82
- <label class="label-override mb-2">CVV </label>
92
+ <label class="label-override mb-2">CVV
93
+ <ShieldIcon />
94
+ </label>
83
95
  <div :class="`input-default ${errors.includes('cvv') ? 'error' : ''}`">
84
96
  <input
85
97
  placeholder="183"
@@ -94,20 +106,24 @@
94
106
 
95
107
  <!-- City -->
96
108
  <div class="input-wrapper col-span-6 md:col-span-4 z-0">
97
- <label class="label-override mb-2">City </label>
109
+ <label class="label-override mb-2">City
110
+ <StadiumIcon />
111
+ </label>
98
112
  <div :class="`input-default ${errors.includes('city') ? 'error' : ''}`">
99
113
  <input placeholder="Denver" v-model="profile.city" />
100
114
  </div>
101
115
  </div>
102
116
 
103
117
  <!-- State -->
104
- <div class="input-wrapper col-span-6 md:col-span-4 z-50">
105
- <label class="label-override mb-2">State </label>
118
+ <div class="input-wrapper col-span-6 md:col-span-4 z-1">
119
+ <label class="label-override mb-2">State
120
+ <SandclockIcon />
121
+ </label>
106
122
  <div v-if="profile.country === 'US'" :class="`${errors.includes('state') ? 'error' : ''}`">
107
123
  <Dropdown
108
124
  class="input-default w-full"
109
125
  default="Select State"
110
- :onClick="(state) => profile.state = state"
126
+ :onClick="(state) => (profile.state = state)"
111
127
  :options="usStates"
112
128
  :allowDefault="false"
113
129
  rightAmount="right-2"
@@ -121,26 +137,45 @@
121
137
 
122
138
  <!-- Zip -->
123
139
  <div class="input-wrapper col-span-6 md:col-span-4 z-0">
124
- <label class="label-override mb-2">Zip </label>
140
+ <label class="label-override mb-2">Zip
141
+ <KeyIcon />
142
+ </label>
125
143
  <div :class="`input-default ${errors.includes('zipCode') ? 'error' : ''}`">
126
- <input placeholder="80281" type="number" min="1" max="12" v-model="profile.zipCode" />
144
+ <input placeholder="10005" type="number" min="1" max="12" v-model="profile.zipCode" />
127
145
  </div>
128
146
  </div>
129
147
 
130
148
  <!-- Address -->
131
149
  <div class="input-wrapper col-span-6 md:col-span-4 z-0">
132
- <label class="label-override mb-2">Address </label>
150
+ <label class="label-override mb-2">Address
151
+ <HandIcon />
152
+ </label>
133
153
  <div :class="`input-default ${errors.includes('address') ? 'error' : ''}`">
134
- <input placeholder="Denver" v-model="profile.address" />
154
+ <input placeholder="100 5th Avenue" v-model="profile.address" />
135
155
  </div>
136
156
  </div>
137
157
 
138
158
  <!-- Generate -->
139
159
  <div class="input-wrapper col-span-6 md:col-span-4 z-0">
140
- <label class="label-override mb-2 z-0"> Fake ID</label>
160
+ <label class="label-override mb-2"> Fake ID
161
+ <WildcardIcon />
162
+ </label>
141
163
  <div class="input-default mt-2 w-full h-10 flex items-center">
142
- <button @click="generate" class="text-white w-full text-xs flex items-center justify-center gap-2">
143
- <svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
164
+ <button
165
+ @click="generate"
166
+ class="text-white w-full text-xs flex items-center justify-center gap-2"
167
+ >
168
+ <svg
169
+ xmlns="http://www.w3.org/2000/svg"
170
+ width="14"
171
+ height="14"
172
+ viewBox="0 0 24 24"
173
+ fill="none"
174
+ stroke="currentColor"
175
+ stroke-width="2"
176
+ stroke-linecap="round"
177
+ stroke-linejoin="round"
178
+ >
144
179
  <rect x="3" y="4" width="18" height="16" rx="2" />
145
180
  <line x1="7" y1="2" x2="7" y2="6" />
146
181
  <line x1="17" y1="2" x2="17" y2="6" />
@@ -169,6 +204,12 @@
169
204
  .z-0 {
170
205
  z-index: 0 !important;
171
206
  }
207
+ .z-1 {
208
+ z-index: 1 !important;
209
+ }
210
+ .z-1 {
211
+ z-index: 2 !important;
212
+ }
172
213
 
173
214
  .error {
174
215
  border-width: 2px !important;
@@ -177,6 +218,7 @@
177
218
  </style>
178
219
  <script setup>
179
220
  import Modal from "@/components/ui/Modal.vue";
221
+ import { MailIcon, CartIcon, ShieldIcon, StadiumIcon, KeyIcon, HandIcon, ProfileIcon, SandclockIcon, TimerIcon, TagIcon, WildcardIcon } from "@/components/icons";
180
222
  import { EditIcon } from "@/components/icons";
181
223
  import ProfileCountryChooser from "@/components/Editors/Profile/ProfileCountryChooser.vue";
182
224
  import { useUIStore } from "@/stores/ui";
@@ -191,7 +233,55 @@ const ui = useUIStore();
191
233
 
192
234
  // US States list (excluding GA and PR, alphabetically ordered)
193
235
  const usStates = [
194
- "AK", "AL", "AR", "AZ", "CA", "CO", "CT", "DE", "FL", "HI", "IA", "ID", "IL", "IN", "KS", "KY", "LA", "MA", "MD", "ME", "MI", "MN", "MO", "MS", "MT", "NC", "ND", "NE", "NH", "NJ", "NM", "NV", "NY", "OH", "OK", "OR", "PA", "RI", "SC", "SD", "TN", "TX", "UT", "VA", "VT", "WA", "WI", "WV", "WY"
236
+ "AK",
237
+ "AL",
238
+ "AR",
239
+ "AZ",
240
+ "CA",
241
+ "CO",
242
+ "CT",
243
+ "DE",
244
+ "FL",
245
+ "HI",
246
+ "IA",
247
+ "ID",
248
+ "IL",
249
+ "IN",
250
+ "KS",
251
+ "KY",
252
+ "LA",
253
+ "MA",
254
+ "MD",
255
+ "ME",
256
+ "MI",
257
+ "MN",
258
+ "MO",
259
+ "MS",
260
+ "MT",
261
+ "NC",
262
+ "ND",
263
+ "NE",
264
+ "NH",
265
+ "NJ",
266
+ "NM",
267
+ "NV",
268
+ "NY",
269
+ "OH",
270
+ "OK",
271
+ "OR",
272
+ "PA",
273
+ "RI",
274
+ "SC",
275
+ "SD",
276
+ "TN",
277
+ "TX",
278
+ "UT",
279
+ "VA",
280
+ "VT",
281
+ "WA",
282
+ "WI",
283
+ "WV",
284
+ "WY"
195
285
  ];
196
286
  const cardNumberInput = ref(null);
197
287
  const profile = ref({
@@ -232,17 +322,20 @@ const formatCardNumberDisplay = () => {
232
322
  };
233
323
 
234
324
  // Watch for changes in profile.cardNumber to sync with display
235
- watch(() => profile.value.cardNumber, (newValue) => {
236
- if (newValue) {
237
- const cleanNumber = newValue.replace(/\s+/g, "");
238
- if (cleanNumber) {
239
- const cardInfo = validateCard(cleanNumber);
240
- displayCardNumber.value = cardInfo.formatted;
325
+ watch(
326
+ () => profile.value.cardNumber,
327
+ (newValue) => {
328
+ if (newValue) {
329
+ const cleanNumber = newValue.replace(/\s+/g, "");
330
+ if (cleanNumber) {
331
+ const cardInfo = validateCard(cleanNumber);
332
+ displayCardNumber.value = cardInfo.formatted;
333
+ }
334
+ } else {
335
+ displayCardNumber.value = "";
241
336
  }
242
- } else {
243
- displayCardNumber.value = "";
244
337
  }
245
- });
338
+ );
246
339
 
247
340
  // Initialize on modal open
248
341
  onMounted(() => {
@@ -277,9 +370,10 @@ const validate = (p) => {
277
370
  if (!/^\d{3,4}$/.test(`${p.cvv}`)) errors.value.push("cvv");
278
371
  const cleanCardNumber = p.cardNumber.replace(/\s+/g, "");
279
372
  // Validate card number based on type and length
280
- const isValidCard = cleanCardNumber.match(/^4\d{15}$/) || // Visa (16 digits)
281
- cleanCardNumber.match(/^5[1-5]\d{14}$/) || // Mastercard (16 digits)
282
- cleanCardNumber.match(/^3[47]\d{13}$/); // AMEX (15 digits)
373
+ const isValidCard =
374
+ cleanCardNumber.match(/^4\d{15}$/) || // Visa (16 digits)
375
+ cleanCardNumber.match(/^5[1-5]\d{14}$/) || // Mastercard (16 digits)
376
+ cleanCardNumber.match(/^3[47]\d{13}$/); // AMEX (15 digits)
283
377
  if (!isValidCard) errors.value.push("cardNumber");
284
378
  if (!p.expYear) errors.value.push("expYear");
285
379
  if (!p.expMonth) errors.value.push("expMonth");
@@ -289,18 +383,18 @@ const validate = (p) => {
289
383
 
290
384
  const handleCreditCardUpdate = (event) => {
291
385
  const value = event.target.value.replace(/\D/g, "");
292
-
386
+
293
387
  // Determine max length based on card type
294
388
  let maxLength = 16; // Default for Visa/Mastercard
295
- if (value.startsWith('3')) {
389
+ if (value.startsWith("3")) {
296
390
  maxLength = 15; // AMEX
297
- } else if (value.startsWith('4') || value.startsWith('5')) {
391
+ } else if (value.startsWith("4") || value.startsWith("5")) {
298
392
  maxLength = 16; // Visa/Mastercard
299
393
  }
300
-
394
+
301
395
  const subs = value.substring(0, maxLength);
302
396
  const cardInfo = validateCard(subs);
303
-
397
+
304
398
  // Store clean number (without spaces) in profile
305
399
  profile.value.cardNumber = subs;
306
400
  // Display formatted number in input
@@ -309,10 +403,10 @@ const handleCreditCardUpdate = (event) => {
309
403
 
310
404
  function done() {
311
405
  // Clear state if country is not US
312
- if (profile.value.country !== 'US') {
313
- profile.value.state = '';
406
+ if (profile.value.country !== "US") {
407
+ profile.value.state = "";
314
408
  }
315
-
409
+
316
410
  ui.logger.Info("Created profile", profile.value);
317
411
  if (validate(profile.value) !== true) return;
318
412
  ui.toggleModal("");