@necrolab/dashboard 0.5.7 → 0.5.8

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@necrolab/dashboard",
3
- "version": "0.5.7",
3
+ "version": "0.5.8",
4
4
  "type": "module",
5
5
  "scripts": {
6
6
  "build": "rm -rf dist && npx workbox-cli generateSW workbox-config.cjs && vite build",
@@ -5,34 +5,62 @@
5
5
  @dblclick="handleDoubleClick"
6
6
  @touchstart="handleTouchStart"
7
7
  @touchend="handleTouchEnd">
8
- <div class="col-span-1 flex items-center justify-start lg:col-span-2">
8
+ <div class="col-span-1 flex items-start justify-start lg:col-span-2 py-2">
9
9
  <Checkbox
10
10
  class="ml-2 mr-4 flex-shrink-0"
11
11
  :toggled="props.task.selected"
12
12
  @valueUpdate="ui.toggleTaskSelected(props.task.taskId)" />
13
13
  <div
14
14
  v-if="props.preferEventName && props.task.eventName"
15
- class="event-details hidden cursor-pointer lg:flex flex-col gap-0.5"
15
+ class="event-details hidden cursor-pointer lg:flex flex-col gap-0.5 justify-center"
16
16
  @click="copy(props.task.eventId)"
17
17
  :title="`Event ID: ${props.task.eventId}`">
18
- <div class="event-name text-white text-xs font-semibold leading-tight">
18
+ <div class="event-name text-white text-[11px] font-semibold leading-tight">
19
19
  {{ props.task.eventName }}
20
20
  </div>
21
- <div v-if="props.task.eventVenue" class="event-venue flex items-center gap-1 text-[10px] text-light-400">
22
- <StadiumIcon class="w-2.5 h-2.5 flex-shrink-0" />
23
- <span class="truncate">{{ props.task.eventVenue }}</span>
21
+ <div v-if="props.task.venueName || props.task.eventCity" class="event-venue flex items-start gap-1 text-[9px] leading-tight">
22
+ <svg class="event-icon mt-[1px]" width="10" height="10" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24">
23
+ <path d="M21 10c0 7-9 13-9 13s-9-6-9-13a9 9 0 0 1 18 0z"></path>
24
+ <circle cx="12" cy="10" r="3"></circle>
25
+ </svg>
26
+ <span class="truncate text-light-500">{{ [props.task.venueName, props.task.eventCity].filter(Boolean).join(', ') }}</span>
24
27
  </div>
25
- <div v-if="props.task.eventLocalDate" class="event-date flex items-center gap-1 text-[10px] text-light-400">
26
- <TimerIcon class="w-2.5 h-2.5 flex-shrink-0" />
27
- <span>{{ formatEventDate(props.task.eventLocalDate) }}</span>
28
+ <div v-if="props.task.eventLocalDate" class="event-date flex items-start gap-1 text-[9px] leading-tight">
29
+ <svg class="event-icon mt-[1px]" width="10" height="10" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24">
30
+ <rect x="3" y="4" width="18" height="18" rx="2" ry="2"></rect>
31
+ <line x1="16" y1="2" x2="16" y2="6"></line>
32
+ <line x1="8" y1="2" x2="8" y2="6"></line>
33
+ <line x1="3" y1="10" x2="21" y2="10"></line>
34
+ </svg>
35
+ <span class="text-light-500">{{ formatEventDate(props.task.eventLocalDate) }}</span>
36
+ </div>
37
+ <div v-if="props.task.email" class="event-email flex items-start gap-1 text-[9px] leading-tight">
38
+ <svg class="event-icon mt-[1px]" width="10" height="10" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24">
39
+ <path d="M4 4h16c1.1 0 2 .9 2 2v12c0 1.1-.9 2-2 2H4c-1.1 0-2-.9-2-2V6c0-1.1.9-2 2-2z"></path>
40
+ <polyline points="22,6 12,13 2,6"></polyline>
41
+ </svg>
42
+ <span class="truncate text-light-500">{{ props.task.email }}</span>
28
43
  </div>
29
44
  </div>
30
- <h4
45
+ <div
31
46
  v-else
32
- class="task-event-id mx-auto hidden cursor-pointer text-white hover:text-light-300 lg:block"
47
+ class="event-id-details hidden cursor-pointer lg:flex flex-col gap-0.5 justify-center"
33
48
  @click="copy(props.task.eventId)">
34
- {{ props.task.eventId }}
35
- </h4>
49
+ <div class="event-id-row flex items-center gap-1 text-[11px] text-white font-semibold">
50
+ <svg class="event-icon" width="11" height="11" fill="none" stroke="currentColor" stroke-width="2.5" viewBox="0 0 24 24">
51
+ <path d="M9 11l3 3L22 4"></path>
52
+ <path d="M21 12v7a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11"></path>
53
+ </svg>
54
+ <span>{{ props.task.eventId }}</span>
55
+ </div>
56
+ <div v-if="props.task.email" class="event-email flex items-start gap-1 text-[9px] leading-tight">
57
+ <svg class="event-icon mt-[1px]" width="10" height="10" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24">
58
+ <path d="M4 4h16c1.1 0 2 .9 2 2v12c0 1.1-.9 2-2 2H4c-1.1 0-2-.9-2-2V6c0-1.1.9-2 2-2z"></path>
59
+ <polyline points="22,6 12,13 2,6"></polyline>
60
+ </svg>
61
+ <span class="truncate text-light-500">{{ props.task.email }}</span>
62
+ </div>
63
+ </div>
36
64
  </div>
37
65
  <div class="col-span-2 overflow-hidden">
38
66
  <h4 class="text-white text-xs leading-tight">
@@ -133,6 +161,54 @@ h4 {
133
161
  color: oklch(0.90 0 0);
134
162
  }
135
163
 
164
+ .event-details,
165
+ .event-id-details {
166
+ max-width: 100%;
167
+ min-width: 0;
168
+ gap: 2px;
169
+
170
+ .event-name,
171
+ .event-id-row {
172
+ max-width: 180px;
173
+ overflow: hidden;
174
+ text-overflow: ellipsis;
175
+ white-space: nowrap;
176
+ font-size: 11px;
177
+ line-height: 1.3;
178
+ }
179
+
180
+ .event-icon {
181
+ min-width: 10px !important;
182
+ min-height: 10px !important;
183
+ flex-shrink: 0 !important;
184
+ color: oklch(0.60 0 0) !important;
185
+ stroke: oklch(0.60 0 0) !important;
186
+ fill: none !important;
187
+
188
+ path,
189
+ rect,
190
+ line,
191
+ circle,
192
+ polyline {
193
+ stroke: oklch(0.60 0 0) !important;
194
+ fill: none !important;
195
+ }
196
+ }
197
+
198
+ .event-venue,
199
+ .event-date,
200
+ .event-email {
201
+ line-height: 1.2;
202
+ min-height: 11px;
203
+
204
+ span {
205
+ color: oklch(0.60 0 0);
206
+ font-size: 9px;
207
+ line-height: 1.2;
208
+ }
209
+ }
210
+ }
211
+
136
212
  .status-container {
137
213
  @apply mx-auto flex w-fit items-center justify-center rounded-lg border border-dark-650 bg-dark-500;
138
214
  padding: 6px 12px;
@@ -532,9 +608,9 @@ const isTotalPrice = (line, index, lines) => {
532
608
  if (!isLastLine) return false;
533
609
 
534
610
  // Check if line is a standalone price (not in parentheses)
535
- // Matches: $345.88, €345.88, £345.88, ¥345.88, etc.
611
+ // Matches: $345.88, €345.88, USD 345.88, EUR 345.88, etc.
536
612
  // Does NOT match: ($86.47) or 2× 301/E ($86.47)
537
- const totalPricePattern = /^[$€£¥₹₽¢]\s*[\d,]+\.?\d*$/;
613
+ const totalPricePattern = /^([$€£¥₹₽¢]|[A-Z]{3})\s*[\d,]+\.?\d*$/;
538
614
  return totalPricePattern.test(trimmed) && !trimmed.includes('(') && !trimmed.includes(')');
539
615
  };
540
616
 
@@ -14,7 +14,7 @@
14
14
  <UpIcon v-if="ui.sortData.sortBy === 'eventId' && ui.sortData.reversed" class="ml-1" />
15
15
  </div>
16
16
  </div>
17
- <div class="col-span-2 flex items-center justify-start lg:justify-center" v-once>
17
+ <div class="col-span-2 flex items-center justify-center" v-once>
18
18
  <TicketIcon class="mr-0 lg:mr-3" />
19
19
  <h4 class="hidden lg:flex">Tickets</h4>
20
20
  </div>
@@ -78,6 +78,11 @@ h4 {
78
78
  @apply bg-dark-550 !important;
79
79
  }
80
80
 
81
+ // Increase height when showing eventName to accommodate multi-line display
82
+ &:has(.event-details) {
83
+ min-height: 75px;
84
+ }
85
+
81
86
  @media (max-width: 768px) {
82
87
  min-height: 58px;
83
88
  }
@@ -23,10 +23,10 @@
23
23
  <span class="info-label">Event Name</span>
24
24
  <span class="info-value">{{ task.eventName }}</span>
25
25
  </div>
26
- <div class="info-row" v-if="task.eventVenue">
26
+ <div class="info-row" v-if="task.venueName || task.eventCity">
27
27
  <StadiumWhiteIcon class="info-icon" />
28
28
  <span class="info-label">Venue</span>
29
- <span class="info-value">{{ task.eventVenue }}</span>
29
+ <span class="info-value">{{ [task.venueName, task.eventCity].filter(Boolean).join(', ') }}</span>
30
30
  </div>
31
31
  <div class="info-row" v-if="task.eventLocalDate">
32
32
  <StadiumWhiteIcon class="info-icon" />
@@ -40,6 +40,24 @@
40
40
  </div>
41
41
  <span class="info-value uppercase font-semibold whitespace-normal break-words">{{ task.status }}</span>
42
42
  </div>
43
+ <div class="info-row" v-if="task._timeLeftString && task._timeLeftString !== 'No Cartholds'">
44
+ <TimerIcon class="info-icon" />
45
+ <span class="info-label">Cart Expiration</span>
46
+ <span class="info-value font-semibold" :class="{ 'text-red-400': task._timeLeftString === '00:00' }">
47
+ {{ task._timeLeftString !== '00:00' ? task._timeLeftString : 'Expired' }}
48
+ </span>
49
+ </div>
50
+ <div class="info-row" v-if="task.reservedTicketsList">
51
+ <TicketIcon class="info-icon" />
52
+ <span class="info-label">Reserved Tickets</span>
53
+ <div class="info-value text-left">
54
+ <div v-for="(line, index) in task.reservedTicketsList.split('\n')" :key="index" class="text-xs leading-tight">
55
+ <span v-if="line.trim()" :class="{ 'text-green-400 font-bold': isTotalPrice(line, index, task.reservedTicketsList.split('\n')) }">
56
+ {{ line.trim() }}
57
+ </span>
58
+ </div>
59
+ </div>
60
+ </div>
43
61
  </div>
44
62
  </div>
45
63
 
@@ -173,6 +191,7 @@ import {
173
191
  EyeIcon,
174
192
  StadiumIcon,
175
193
  StadiumWhiteIcon,
194
+ TicketIcon,
176
195
  MailIcon,
177
196
  KeyIcon,
178
197
  ProfileIcon,
@@ -218,8 +237,30 @@ const copy = (text) => {
218
237
 
219
238
  const formatDate = (dateString) => {
220
239
  if (!dateString) return '';
221
- const date = new Date(dateString);
222
- return date.toLocaleString();
240
+ try {
241
+ const date = new Date(dateString);
242
+ const options = {
243
+ month: 'short',
244
+ day: 'numeric',
245
+ year: 'numeric',
246
+ hour: 'numeric',
247
+ minute: '2-digit',
248
+ hour12: true
249
+ };
250
+ return date.toLocaleString('en-US', options).replace(',', '');
251
+ } catch {
252
+ return dateString;
253
+ }
254
+ };
255
+
256
+ const isTotalPrice = (line, index, lines) => {
257
+ const trimmed = line.trim();
258
+ const nonEmptyLines = lines.filter((l) => l.trim());
259
+ const isLastLine = index === lines.lastIndexOf(nonEmptyLines[nonEmptyLines.length - 1]);
260
+ if (!isLastLine) return false;
261
+ // Match currency symbols ($, €, £, etc.) OR currency codes (USD, EUR, AUD, etc.)
262
+ const totalPricePattern = /^([$€£¥₹₽¢]|[A-Z]{3})\s*[\d,]+\.?\d*$/;
263
+ return totalPricePattern.test(trimmed) && !trimmed.includes('(');
223
264
  };
224
265
 
225
266
  const colorToClass = (color) => {
@@ -38,6 +38,7 @@ export default {
38
38
  profileTags: ["Any"],
39
39
  eventName: "Taylor Swift | The Eras Tour",
40
40
  eventDate: "2023-05-19T22:30:00.000Z",
41
+ eventLocalDate: "2023-05-19T22:30:00.000Z",
41
42
  venueName: "Gillette Stadium",
42
43
  eventCity: "Foxborough, MA",
43
44
  eventUrl:
@@ -72,6 +73,7 @@ export default {
72
73
  profileTags: ["Any"],
73
74
  eventName: "Morgan Wallen: One Night At A Time World Tour",
74
75
  eventDate: "2024-06-06T23:00:00.000Z",
76
+ eventLocalDate: "2024-06-06T23:00:00.000Z",
75
77
  venueName: "Veterans United Home Loans Amphitheater at Virginia Beach",
76
78
  eventCity: "Virginia Beach, VA",
77
79
  eventUrl:
@@ -105,6 +107,7 @@ export default {
105
107
  profileTags: ["Any"],
106
108
  eventName: "Taylor Swift | The Eras Tour",
107
109
  eventDate: "2023-05-21T22:30:00.000Z",
110
+ eventLocalDate: "2023-05-21T22:30:00.000Z",
108
111
  venueName: "Gillette Stadium",
109
112
  eventCity: "Foxborough, MA",
110
113
  eventUrl:
@@ -138,6 +141,7 @@ export default {
138
141
  profileTags: ["Any"],
139
142
  eventName: "Taylor Swift | The Eras Tour",
140
143
  eventDate: "2023-05-19T22:30:00.000Z",
144
+ eventLocalDate: "2023-05-19T22:30:00.000Z",
141
145
  venueName: "Gillette Stadium",
142
146
  eventCity: "Foxborough, MA",
143
147
  eventUrl:
@@ -171,6 +175,7 @@ export default {
171
175
  profileTags: ["Any"],
172
176
  eventName: "Taylor Swift | The Eras Tour",
173
177
  eventDate: "2023-05-19T22:30:00.000Z",
178
+ eventLocalDate: "2023-05-19T22:30:00.000Z",
174
179
  venueName: "Gillette Stadium",
175
180
  eventCity: "Foxborough, MA",
176
181
  eventUrl:
@@ -303,6 +308,7 @@ export default {
303
308
  profileTags: ["Any"],
304
309
  eventName: "Taylor Swift | The Eras Tour",
305
310
  eventDate: "2023-05-21T22:30:00.000Z",
311
+ eventLocalDate: "2023-05-21T22:30:00.000Z",
306
312
  venueName: "Gillette Stadium",
307
313
  eventCity: "Foxborough, MA",
308
314
  eventUrl:
@@ -336,6 +342,7 @@ export default {
336
342
  profileTags: ["Any"],
337
343
  eventName: "Taylor Swift | The Eras Tour",
338
344
  eventDate: "2023-05-21T22:30:00.000Z",
345
+ eventLocalDate: "2023-05-21T22:30:00.000Z",
339
346
  venueName: "Gillette Stadium",
340
347
  eventCity: "Foxborough, MA",
341
348
  eventUrl:
@@ -369,6 +376,7 @@ export default {
369
376
  profileTags: ["Any"],
370
377
  eventName: "Taylor Swift | The Eras Tour",
371
378
  eventDate: "2023-05-21T22:30:00.000Z",
379
+ eventLocalDate: "2023-05-21T22:30:00.000Z",
372
380
  venueName: "Gillette Stadium",
373
381
  eventCity: "Foxborough, MA",
374
382
  eventUrl:
@@ -402,6 +410,7 @@ export default {
402
410
  profileTags: ["Any"],
403
411
  eventName: "Taylor Swift | The Eras Tour",
404
412
  eventDate: "2023-05-21T22:30:00.000Z",
413
+ eventLocalDate: "2023-05-21T22:30:00.000Z",
405
414
  venueName: "Gillette Stadium",
406
415
  eventCity: "Foxborough, MA",
407
416
  eventUrl:
@@ -435,6 +444,7 @@ export default {
435
444
  profileTags: ["Any"],
436
445
  eventName: "Taylor Swift | The Eras Tour",
437
446
  eventDate: "2023-05-21T22:30:00.000Z",
447
+ eventLocalDate: "2023-05-21T22:30:00.000Z",
438
448
  venueName: "Gillette Stadium",
439
449
  eventCity: "Foxborough, MA",
440
450
  hidden: true,
@@ -465,6 +475,7 @@ export default {
465
475
  profileTags: ["Any"],
466
476
  eventName: "Taylor Swift | The Eras Tour",
467
477
  eventDate: "2023-05-21T22:30:00.000Z",
478
+ eventLocalDate: "2023-05-21T22:30:00.000Z",
468
479
  venueName: "Gillette Stadium",
469
480
  eventCity: "Foxborough, MA",
470
481
  hidden: true,
@@ -495,6 +506,7 @@ export default {
495
506
  profileTags: ["Any"],
496
507
  eventName: "Taylor Swift | The Eras Tour",
497
508
  eventDate: "2023-05-21T22:30:00.000Z",
509
+ eventLocalDate: "2023-05-21T22:30:00.000Z",
498
510
  venueName: "Gillette Stadium",
499
511
  eventCity: "Foxborough, MA",
500
512
  hidden: true,
@@ -525,6 +537,7 @@ export default {
525
537
  profileTags: ["Any"],
526
538
  eventName: "Taylor Swift | The Eras Tour",
527
539
  eventDate: "2023-05-21T22:30:00.000Z",
540
+ eventLocalDate: "2023-05-21T22:30:00.000Z",
528
541
  venueName: "Gillette Stadium",
529
542
  eventCity: "Foxborough, MA",
530
543
  hidden: true,
@@ -555,6 +568,7 @@ export default {
555
568
  profileTags: ["Any"],
556
569
  eventName: "Taylor Swift | The Eras Tour",
557
570
  eventDate: "2023-05-21T22:30:00.000Z",
571
+ eventLocalDate: "2023-05-21T22:30:00.000Z",
558
572
  venueName: "Gillette Stadium",
559
573
  eventCity: "Foxborough, MA",
560
574
  hidden: false,
@@ -585,6 +599,7 @@ export default {
585
599
  profileTags: ["Any"],
586
600
  eventName: "Taylor Swift | The Eras Tour",
587
601
  eventDate: "2023-05-21T22:30:00.000Z",
602
+ eventLocalDate: "2023-05-21T22:30:00.000Z",
588
603
  venueName: "Gillette Stadium",
589
604
  eventCity: "Foxborough, MA",
590
605
  hidden: true,
@@ -615,6 +630,7 @@ export default {
615
630
  profileTags: ["Any"],
616
631
  eventName: "Taylor Swift | The Eras Tour",
617
632
  eventDate: "2023-05-21T22:30:00.000Z",
633
+ eventLocalDate: "2023-05-21T22:30:00.000Z",
618
634
  venueName: "Gillette Stadium",
619
635
  eventCity: "Foxborough, MA",
620
636
  hidden: true,
@@ -645,6 +661,7 @@ export default {
645
661
  profileTags: ["Any"],
646
662
  eventName: "Taylor Swift | The Eras Tour",
647
663
  eventDate: "2023-05-21T22:30:00.000Z",
664
+ eventLocalDate: "2023-05-21T22:30:00.000Z",
648
665
  venueName: "Gillette Stadium",
649
666
  eventCity: "Foxborough, MA",
650
667
  hidden: true,
@@ -675,6 +692,7 @@ export default {
675
692
  profileTags: ["Any"],
676
693
  eventName: "Taylor Swift | The Eras Tour",
677
694
  eventDate: "2023-05-21T22:30:00.000Z",
695
+ eventLocalDate: "2023-05-21T22:30:00.000Z",
678
696
  venueName: "Gillette Stadium",
679
697
  eventCity: "Foxborough, MA",
680
698
  hidden: true,