@necrolab/dashboard 0.4.49 → 0.4.51

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.
@@ -1,459 +1,423 @@
1
1
  <template>
2
- <Row
3
- class="relative text-white grid-cols-10 gap-2 lg:grid-cols-12"
4
- @click="ui.setOpenContextMenu('')"
5
- >
6
- <div class="block md:hidden absolute left-1 top-1">
7
- <h4
8
- class="text-xs text-white font-bold"
9
- style="
10
- background: transparent !important;
11
- border: none !important;
12
- padding: 0 !important;
13
- margin: 0 !important;
14
- color: #c9cad1 !important;
15
- font-size: 11px !important;
16
- font-weight: 600 !important;
17
- letter-spacing: 0.4px !important;
18
- "
19
- >
20
- {{ props.task.taskId }}
21
- </h4>
22
- </div>
23
- <div class="col-span-1 lg:col-span-2 flex items-center justify-start">
24
- <Checkbox
25
- class="ml-2 mr-4 flex-shrink-0"
26
- :toggled="props.task.selected"
27
- @valueUpdate="ui.toggleTaskSelected(props.task.taskId)"
28
- />
29
- <h4
30
- class="task-event-id mx-auto hidden lg:block text-white cursor-pointer hover:text-light-300"
31
- @click="copy(props.task.eventId)"
32
- >
33
- {{ props.task.eventId }}
34
- </h4>
35
- </div>
36
- <div class="col-span-2">
37
- <h4 class="text-white">
38
- <span v-if="!props.task.reservedTicketsList">-</span>
39
- <div v-else>
40
- <div v-for="l in props.task.reservedTicketsList.split(' | ')" :key="l">
41
- <span v-if="!!l.trim()">{{ l.trim() }}</span>
42
- </div>
2
+ <Row class="relative text-white grid-cols-10 gap-2 lg:grid-cols-12" @click="ui.setOpenContextMenu('')">
3
+ <div class="block md:hidden absolute left-1 top-1">
4
+ <h4
5
+ class="text-xs text-white font-bold"
6
+ style="
7
+ background: transparent !important;
8
+ border: none !important;
9
+ padding: 0 !important;
10
+ margin: 0 !important;
11
+ color: #c9cad1 !important;
12
+ font-size: 11px !important;
13
+ font-weight: 600 !important;
14
+ letter-spacing: 0.4px !important;
15
+ ">
16
+ {{ props.task.taskId }}
17
+ </h4>
43
18
  </div>
44
- <span
45
- class="ml-1 font-bold"
46
- :class="{
47
- 'text-red-400':
48
- props.task._timeLeftString === '00:00' ||
49
- props.task._timeLeftString === 'No Cartholds',
50
- }"
51
- >
52
- {{
53
- props.task._timeLeftString !== "00:00"
54
- ? props.task._timeLeftString
55
- : "Expired"
56
- }}
57
- </span>
58
- </h4>
59
- </div>
60
- <div class="col-span-5 md:col-span-4 lg:col-span-5 text-center justify-center">
61
- <div class="status-container">
62
- <div
63
- class="status-indicator"
64
- :class="
65
- colorToClass(
66
- props.task.active || props.task.status.toLowerCase() === 'idle'
67
- ? props.task.statusColor
68
- : 'red'
69
- )
70
- "
71
- ></div>
72
- <span class="status-text">{{ props.task.status }}</span>
73
- </div>
74
- </div>
75
- <div class="col-span-2 lg:col-span-3 flex">
76
- <ul class="task-buttons">
77
- <li>
78
- <button v-if="task.active" @click="ui.stopTask(task.taskId)">
79
- <PauseIcon />
80
- </button>
81
- <button v-else @click="ui.startTask(task.taskId)">
82
- <PlayIcon />
83
- </button>
84
- </li>
85
- <li
86
- v-if="
87
- task.status?.toLowerCase() == 'waiting' &&
88
- props.task._timeLeftString !== '00:00'
89
- "
90
- >
91
- <button @click="ui.continueTask(task.taskId, 'autocheckout')">
92
- <BagWhiteIcon />
93
- </button>
94
- </li>
95
- <li v-if="task.status?.toLowerCase() == 'waiting'">
96
- <button @click="ui.continueTask(task.taskId, 'change_reservation')">
97
- <EditIcon />
98
- </button>
99
- </li>
100
- <li>
101
- <button @click="ui.deleteTask(task.taskId)">
102
- <TrashIcon />
103
- </button>
104
- </li>
105
- <li @contextmenu.prevent="handleRightClick">
106
- <button @click="props.task.isExpanded = !props.task.isExpanded">
107
- <span>{{ props.task.isExpanded ? "−" : "+" }}</span>
108
- </button>
109
- </li>
110
- </ul>
111
- </div>
112
- <div
113
- class="hidden md:block col-span-1 absolute right-5 top-4 lg:flex items-center justify-center"
114
- >
115
- <h4 class="text-center text-xs task-id text-white">
116
- {{ props.task.taskId }}
117
- </h4>
118
- </div>
119
- <transition name="fade">
120
- <div
121
- class="col-span-10 lg:col-span-12 flex flex-wrap gap-x-4 gap-y-4 lg:gap-x-10 pt-8 pb-2 xl:justify-around will-change-auto"
122
- v-if="props.task.isExpanded"
123
- >
124
- <!-- Details -->
125
- <TaskLabel
126
- class="md:hidden"
127
- image="stadium_w"
128
- :text="props.task.eventId"
129
- @click="copy(props.task.eventId)"
130
- />
131
-
132
- <TaskLabel class="md:hidden" image="bag_w" :text="String(props.task.quantity)" />
133
- <TaskLabel
134
- v-if="props.task.email"
135
- image="mail"
136
- :text="props.task.email"
137
- @click="copy(props.task.email)"
138
- />
139
- <TaskLabel
140
- v-if="props.task.password"
141
- image="key"
142
- :text="props.task.password"
143
- @click="copy(props.task.password)"
144
- />
145
- <TaskLabel
146
- v-if="!props.task.email && !props.task.password"
147
- image="mail"
148
- text="No account chosen yet"
149
- />
150
- <TaskLabel
151
- v-if="props.task.profileName"
152
- image="profile"
153
- :text="props.task.profileName"
154
- />
155
- <TaskLabel image="timer" :text="props.task.smartTimer ? 'On' : 'Off'" />
156
- <TaskLabel image="groups" :text="props.task.loginAfterCart ? 'On' : 'Off'" />
157
- <TaskLabel image="hand" :text="props.task.manual ? 'On' : 'Off'" />
158
- <TaskLabel image="savings" :text="props.task.doNotPay ? 'On' : 'Off'" />
159
- <TaskLabel image="loyalty" :text="props.task.presaleMode ? 'On' : 'Off'" />
160
- <TaskLabel image="ski" :text="props.task.quickQueue ? 'On' : 'Off'" />
161
- <TaskLabel image="scanner" :text="props.task.accountTag" />
162
- <TaskLabel image="sell" :text="props.task.profileTags.join(', ')" />
163
- <TaskLabel
164
- v-if="props.task.presaleCode"
165
- @click="copy(props.task.presaleCode)"
166
- image="pencil"
167
- :text="props.task.presaleCode"
168
- />
169
-
170
- <TaskLabel
171
- v-if="props.task.eventName"
172
- image="stadium_w"
173
- :text="props.task.eventName"
174
- />
175
- <TaskLabel
176
- v-if="props.task.eventVenue"
177
- image="stadium_w"
178
- :text="props.task.eventVenue"
179
- />
180
- <TaskLabel
181
- v-if="props.task.eventLocalDate"
182
- image="stadium_w"
183
- :text="formatDate(props.task.eventLocalDate)"
184
- />
185
- <TaskLabel image="sandclock" :text="props.task.agedAccount ? 'On' : 'Off'" />
186
- </div>
187
- </transition>
188
-
189
- <!-- Context menu -->
190
- <transition name="fade">
191
- <div
192
- v-if="ui.openContextMenu === task.taskId"
193
- ref="contextMenuRef"
194
- class="fixed bg-dark-500 text-white w-42 grid grid-cols-1 p-1 gap-1 rounded-lg shadow-xl border border-dark-650 context-menu z-max"
195
- :style="contextMenuPosition"
196
- >
197
- <button
198
- class="btn-primary"
199
- @click="openInNewTab(`${ui.currentCountry.url}/event/${task.eventId}`)"
200
- >
201
- Open Event
202
- </button>
203
- <button v-if="task.openerLink" class="btn-primary" @click="openInBrowser(false)">
204
- Open in browser (proxy)
205
- </button>
206
- <button v-if="task.openerLink" class="btn-primary" @click="openInBrowser(true)">
207
- Open in browser (debug)
208
- </button>
209
- </div>
210
- </transition>
211
- </Row>
19
+ <div class="col-span-1 lg:col-span-2 flex items-center justify-start">
20
+ <Checkbox
21
+ class="ml-2 mr-4 flex-shrink-0"
22
+ :toggled="props.task.selected"
23
+ @valueUpdate="ui.toggleTaskSelected(props.task.taskId)" />
24
+ <h4
25
+ class="task-event-id mx-auto hidden lg:block text-white cursor-pointer hover:text-light-300"
26
+ @click="copy(props.task.eventId)">
27
+ {{ props.task.eventId }}
28
+ </h4>
29
+ </div>
30
+ <div class="col-span-2">
31
+ <h4 class="text-white">
32
+ <span v-if="!props.task.reservedTicketsList">-</span>
33
+ <div v-else>
34
+ <div v-for="l in props.task.reservedTicketsList.split(' | ')" :key="l">
35
+ <span v-if="!!l.trim()">{{ l.trim() }}</span>
36
+ </div>
37
+ </div>
38
+ <span
39
+ class="ml-1 font-bold"
40
+ :class="{
41
+ 'text-red-400':
42
+ props.task._timeLeftString === '00:00' || props.task._timeLeftString === 'No Cartholds'
43
+ }">
44
+ {{ props.task._timeLeftString !== "00:00" ? props.task._timeLeftString : "Expired" }}
45
+ </span>
46
+ </h4>
47
+ </div>
48
+ <div class="col-span-5 md:col-span-4 lg:col-span-5 text-center justify-center">
49
+ <div class="status-container">
50
+ <div
51
+ class="status-indicator"
52
+ :class="
53
+ colorToClass(
54
+ props.task.active || props.task.status.toLowerCase() === 'idle'
55
+ ? props.task.statusColor
56
+ : 'red'
57
+ )
58
+ "></div>
59
+ <span class="status-text">{{ props.task.status }}</span>
60
+ </div>
61
+ </div>
62
+ <div class="col-span-2 lg:col-span-3 flex">
63
+ <ul class="task-buttons">
64
+ <li>
65
+ <button v-if="task.active" @click="ui.stopTask(task.taskId)">
66
+ <PauseIcon />
67
+ </button>
68
+ <button v-else @click="ui.startTask(task.taskId)">
69
+ <PlayIcon />
70
+ </button>
71
+ </li>
72
+ <li v-if="task.status?.toLowerCase() == 'waiting' && props.task._timeLeftString !== '00:00'">
73
+ <button @click="ui.continueTask(task.taskId, 'autocheckout')">
74
+ <BagWhiteIcon />
75
+ </button>
76
+ </li>
77
+ <li v-if="task.status?.toLowerCase() == 'waiting'">
78
+ <button @click="ui.continueTask(task.taskId, 'change_reservation')">
79
+ <EditIcon />
80
+ </button>
81
+ </li>
82
+ <li>
83
+ <button @click="ui.deleteTask(task.taskId)">
84
+ <TrashIcon />
85
+ </button>
86
+ </li>
87
+ <li @contextmenu.prevent="handleRightClick">
88
+ <button @click="props.task.isExpanded = !props.task.isExpanded">
89
+ <span>{{ props.task.isExpanded ? "−" : "+" }}</span>
90
+ </button>
91
+ </li>
92
+ </ul>
93
+ </div>
94
+ <div class="hidden md:block col-span-1 absolute right-5 top-4 lg:flex items-center justify-center">
95
+ <h4 class="text-center text-xs task-id text-white">
96
+ {{ props.task.taskId }}
97
+ </h4>
98
+ </div>
99
+ <transition name="fade">
100
+ <div
101
+ class="col-span-10 lg:col-span-12 flex flex-wrap gap-x-4 gap-y-4 lg:gap-x-10 pt-8 pb-2 xl:justify-around will-change-auto"
102
+ v-if="props.task.isExpanded">
103
+ <!-- Details -->
104
+ <TaskLabel
105
+ class="md:hidden"
106
+ image="stadium_w"
107
+ :text="props.task.eventId"
108
+ @click="copy(props.task.eventId)" />
109
+
110
+ <TaskLabel class="md:hidden" image="bag_w" :text="String(props.task.quantity)" />
111
+ <TaskLabel
112
+ v-if="props.task.email"
113
+ image="mail"
114
+ :text="props.task.email"
115
+ @click="copy(props.task.email)" />
116
+ <TaskLabel
117
+ v-if="props.task.password"
118
+ image="key"
119
+ :text="props.task.password"
120
+ @click="copy(props.task.password)" />
121
+ <TaskLabel v-if="!props.task.email && !props.task.password" image="mail" text="No account chosen yet" />
122
+ <TaskLabel v-if="props.task.profileName" image="profile" :text="props.task.profileName" />
123
+ <TaskLabel image="timer" :text="props.task.smartTimer ? 'On' : 'Off'" />
124
+ <TaskLabel image="groups" :text="props.task.loginAfterCart ? 'On' : 'Off'" />
125
+ <TaskLabel image="hand" :text="props.task.manual ? 'On' : 'Off'" />
126
+ <TaskLabel image="savings" :text="props.task.doNotPay ? 'On' : 'Off'" />
127
+ <TaskLabel image="loyalty" :text="props.task.presaleMode ? 'On' : 'Off'" />
128
+ <TaskLabel image="ski" :text="props.task.quickQueue ? 'On' : 'Off'" />
129
+ <TaskLabel image="scanner" :text="props.task.accountTag" />
130
+ <TaskLabel image="sell" :text="props.task.profileTags.join(', ')" />
131
+ <TaskLabel
132
+ v-if="props.task.presaleCode"
133
+ @click="copy(props.task.presaleCode)"
134
+ image="pencil"
135
+ :text="props.task.presaleCode" />
136
+
137
+ <TaskLabel v-if="props.task.eventName" image="stadium_w" :text="props.task.eventName" />
138
+ <TaskLabel v-if="props.task.eventVenue" image="stadium_w" :text="props.task.eventVenue" />
139
+ <TaskLabel
140
+ v-if="props.task.eventLocalDate"
141
+ image="stadium_w"
142
+ :text="formatDate(props.task.eventLocalDate)" />
143
+ <TaskLabel image="sandclock" :text="props.task.agedAccount ? 'On' : 'Off'" />
144
+ </div>
145
+ </transition>
146
+
147
+ <!-- Context menu -->
148
+ <transition name="fade">
149
+ <div
150
+ v-if="ui.openContextMenu === task.taskId"
151
+ ref="contextMenuRef"
152
+ class="fixed bg-dark-500 text-white w-42 grid grid-cols-1 p-1 gap-1 rounded-lg shadow-xl border border-dark-650 context-menu z-max"
153
+ :style="contextMenuPosition">
154
+ <button class="btn-primary" @click="openInNewTab(`${ui.currentCountry.url}/event/${task.eventId}`)">
155
+ Open Event
156
+ </button>
157
+ <button v-if="task.openerLink" class="btn-primary" @click="openInBrowser(false)">
158
+ Open in browser (proxy)
159
+ </button>
160
+ <button v-if="task.openerLink" class="btn-primary" @click="openInBrowser(true)">
161
+ Open in browser (debug)
162
+ </button>
163
+ </div>
164
+ </transition>
165
+ </Row>
212
166
  </template>
213
167
  <style lang="scss" scoped>
214
168
  h4 {
215
- @apply text-center;
216
- color: #e2e2e5;
169
+ @apply text-center;
170
+ color: #e2e2e5;
217
171
  }
218
172
 
219
173
  .status-container {
220
- @apply flex items-center justify-center mx-auto w-fit bg-dark-500 border border-dark-650 rounded-lg;
221
- padding: 6px 12px;
222
- gap: 6px;
223
- transition: all 0.15s ease;
224
- max-width: 100%;
225
-
226
- &:hover {
227
- @apply bg-dark-550 border-dark-700;
228
- }
229
- }
230
-
231
- .status-text {
232
- @apply font-medium text-sm truncate uppercase;
233
- color: #e2e2e5;
234
- letter-spacing: 0.025em;
235
- }
236
-
237
- .task-buttons {
238
- @apply flex items-center justify-center mx-auto bg-dark-500 border border-dark-650 rounded;
239
- padding: 2px;
240
- gap: 1px;
241
-
242
- button {
243
- @apply flex items-center justify-center transition-all duration-150 border-0 outline-0 relative rounded;
244
- background: transparent;
245
- width: 22px;
246
- height: 22px;
247
- color: #cccccc;
248
- border-radius: 4px;
174
+ @apply flex items-center justify-center mx-auto w-fit bg-dark-500 border border-dark-650 rounded-lg;
175
+ padding: 6px 12px;
176
+ gap: 6px;
177
+ transition: all 0.15s ease;
178
+ max-width: 100%;
249
179
 
250
180
  &:hover {
251
- background: rgba(255, 255, 255, 0.1);
252
- color: #ffffff;
253
- transform: scale(1.05);
181
+ @apply bg-dark-550 border-dark-700;
254
182
  }
183
+ }
255
184
 
256
- &:active {
257
- background: rgba(255, 255, 255, 0.2);
258
- transform: scale(0.95);
259
- }
260
- }
261
-
262
- svg,
263
- img {
264
- width: 12px;
265
- height: 12px;
266
- position: relative;
267
- z-index: 1;
268
- }
269
-
270
- svg path {
271
- fill: currentColor;
272
- }
273
-
274
- span {
275
- @apply text-xs font-medium relative z-[1];
276
- }
185
+ .status-text {
186
+ @apply font-medium text-sm truncate uppercase;
187
+ color: #e2e2e5;
188
+ letter-spacing: 0.025em;
277
189
  }
278
190
 
279
- /* Tablet sizing - medium buttons */
280
- @media (min-width: 768px) and (max-width: 1023px) {
281
- .task-buttons {
191
+ .task-buttons {
192
+ @apply flex items-center justify-center mx-auto bg-dark-500 border border-dark-650 rounded;
282
193
  padding: 2px;
283
194
  gap: 1px;
284
- border-radius: 6px;
285
195
 
286
196
  button {
287
- width: 26px;
288
- height: 26px;
289
- border-radius: 5px;
197
+ @apply flex items-center justify-center transition-all duration-150 border-0 outline-0 relative rounded;
198
+ background: transparent;
199
+ width: 22px;
200
+ height: 22px;
201
+ color: #cccccc;
202
+ border-radius: 4px;
203
+
204
+ &:hover {
205
+ background: rgba(255, 255, 255, 0.1);
206
+ color: #ffffff;
207
+ transform: scale(1.05);
208
+ }
209
+
210
+ &:active {
211
+ background: rgba(255, 255, 255, 0.2);
212
+ transform: scale(0.95);
213
+ }
290
214
  }
291
215
 
292
216
  svg,
293
217
  img {
294
- width: 14px;
295
- height: 14px;
218
+ width: 12px;
219
+ height: 12px;
220
+ position: relative;
221
+ z-index: 1;
296
222
  }
297
223
 
298
- span {
299
- font-size: 0.75rem;
224
+ svg path {
225
+ fill: currentColor;
300
226
  }
301
- }
302
- }
303
227
 
304
- /* Desktop sizing - large buttons */
305
- @media (min-width: 1024px) {
306
- .task-buttons {
307
- padding: 3px;
308
- gap: 2px;
309
- border-radius: 8px;
310
-
311
- button {
312
- width: 28px;
313
- height: 28px;
314
- border-radius: 6px;
228
+ span {
229
+ @apply text-xs font-medium relative z-[1];
315
230
  }
231
+ }
316
232
 
317
- svg,
318
- img {
319
- width: 16px;
320
- height: 16px;
233
+ /* Tablet sizing - medium buttons */
234
+ @media (min-width: 768px) and (max-width: 1023px) {
235
+ .task-buttons {
236
+ padding: 2px;
237
+ gap: 1px;
238
+ border-radius: 6px;
239
+
240
+ button {
241
+ width: 26px;
242
+ height: 26px;
243
+ border-radius: 5px;
244
+ }
245
+
246
+ svg,
247
+ img {
248
+ width: 14px;
249
+ height: 14px;
250
+ }
251
+
252
+ span {
253
+ font-size: 0.75rem;
254
+ }
321
255
  }
256
+ }
322
257
 
323
- span {
324
- font-size: 0.875rem;
258
+ /* Desktop sizing - large buttons */
259
+ @media (min-width: 1024px) {
260
+ .task-buttons {
261
+ padding: 3px;
262
+ gap: 2px;
263
+ border-radius: 8px;
264
+
265
+ button {
266
+ width: 28px;
267
+ height: 28px;
268
+ border-radius: 6px;
269
+ }
270
+
271
+ svg,
272
+ img {
273
+ width: 16px;
274
+ height: 16px;
275
+ }
276
+
277
+ span {
278
+ font-size: 0.875rem;
279
+ }
325
280
  }
326
- }
327
281
  }
328
282
 
329
283
  /* Mobile portrait specific styling */
330
284
  @media (max-width: 480px) and (orientation: portrait) {
331
- /* Position adjustment for mobile taskId */
332
- .block.md\\:hidden {
333
- left: 4rem !important; /* Move further right to avoid checkbox collision */
334
- top: 0.25rem !important;
335
- z-index: 1 !important;
336
- }
337
-
338
- /* Ultra-compact button layout for mobile portrait */
339
- .task-buttons {
340
- padding: 1px;
341
- gap: 0;
342
- border-radius: 4px;
343
- border: none !important;
344
- box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1) !important;
345
- max-width: 100%;
346
- overflow: visible;
347
- flex-wrap: wrap;
348
- justify-content: center;
349
- min-height: 18px;
350
- height: auto;
351
-
352
- button {
353
- width: 15px;
354
- height: 15px;
355
- border-radius: 2px;
356
- min-width: 15px;
357
- border: none !important;
358
- flex-shrink: 0;
359
- margin: 0.5px;
360
-
361
- &:hover {
362
- transform: scale(1.1);
363
- }
285
+ /* Position adjustment for mobile taskId */
286
+ .block.md\\:hidden {
287
+ left: 4rem !important;
288
+ top: 0.25rem !important;
289
+ z-index: 1 !important;
364
290
  }
365
291
 
366
- svg,
367
- img {
368
- width: 7px;
369
- height: 7px;
292
+ /* Improved button layout for mobile portrait */
293
+ .task-buttons {
294
+ padding: 1px;
295
+ gap: 1px;
296
+ border-radius: 4px;
297
+ border: 1px solid #3d3e44 !important;
298
+ box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1) !important;
299
+ max-width: 100%;
300
+ min-height: 28px;
301
+ height: auto;
302
+ flex-wrap: wrap;
303
+ justify-content: center;
304
+ align-items: center;
305
+ background: #2e2f34;
306
+
307
+ button {
308
+ width: 20px;
309
+ height: 20px;
310
+ border-radius: 3px;
311
+ min-width: 20px;
312
+ border: none !important;
313
+ flex-shrink: 0;
314
+ margin: 0.5px;
315
+ background: transparent;
316
+
317
+ &:hover {
318
+ background: rgba(255, 255, 255, 0.1);
319
+ transform: scale(1.05);
320
+ }
321
+
322
+ &:active {
323
+ background: rgba(255, 255, 255, 0.15);
324
+ transform: scale(0.95);
325
+ }
326
+ }
327
+
328
+ svg,
329
+ img {
330
+ width: 10px;
331
+ height: 10px;
332
+ }
333
+
334
+ span {
335
+ font-size: 0.7rem;
336
+ line-height: 1;
337
+ }
338
+
339
+ /* Improved list item layout */
340
+ li {
341
+ display: flex;
342
+ margin: 0;
343
+ padding: 0;
344
+ }
370
345
  }
371
346
 
372
- span {
373
- font-size: 0.5rem;
374
- line-height: 1;
347
+ /* Make the actions column more flexible */
348
+ .col-span-2.lg\\:col-span-3 {
349
+ min-width: 0;
350
+ flex-shrink: 0;
351
+ display: flex;
352
+ align-items: center;
353
+ justify-content: center;
354
+ padding: 0 2px;
375
355
  }
376
356
 
377
- /* Allow buttons to wrap to second row if needed */
378
- li {
379
- display: flex;
380
- margin: 0;
357
+ /* Compact status container */
358
+ .status-container {
359
+ border: none !important;
360
+ box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1) !important;
361
+ padding: 2px 4px;
362
+ font-size: 0.7rem;
363
+ max-width: 100%;
381
364
  }
382
- }
383
-
384
- /* Make the actions column slightly more flexible */
385
- .col-span-2.lg\\:col-span-3 {
386
- min-width: 0;
387
- flex-shrink: 0;
388
- display: flex;
389
- align-items: center;
390
- justify-content: center;
391
- }
392
-
393
- /* Compact status container */
394
- .status-container {
395
- border: none !important;
396
- box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1) !important;
397
- padding: 3px 6px;
398
- font-size: 0.75rem;
399
- max-width: 100%;
400
- }
401
365
 
402
- .status-text {
403
- font-size: 0.7rem;
404
- letter-spacing: 0;
405
- }
366
+ .status-text {
367
+ font-size: 0.65rem;
368
+ letter-spacing: 0;
369
+ }
406
370
 
407
- /* Reduce row height to accommodate smaller elements */
408
- .task-row-container {
409
- min-height: 50px !important;
410
- }
371
+ /* Reduce row height to accommodate smaller elements */
372
+ .task-row-container {
373
+ min-height: 45px !important;
374
+ }
411
375
  }
412
376
 
413
377
  .task-id {
414
- font-size: 10px;
415
- font-weight: 600;
416
- letter-spacing: 0.5px;
417
- margin: 0;
418
- color: #a0a0a6;
419
- background: rgba(46, 47, 52, 0.4);
420
- padding: 2px 6px;
421
- border-radius: 4px;
422
- border: 1px solid #3d3e44;
378
+ font-size: 10px;
379
+ font-weight: 600;
380
+ letter-spacing: 0.5px;
381
+ margin: 0;
382
+ color: #a0a0a6;
383
+ background: rgba(46, 47, 52, 0.4);
384
+ padding: 2px 6px;
385
+ border-radius: 4px;
386
+ border: 1px solid #3d3e44;
423
387
  }
424
388
 
425
389
  .task-event-id {
426
- font-size: 11px;
427
- font-weight: 500;
428
- text-align: center;
429
- color: #d0d0d3;
390
+ font-size: 11px;
391
+ font-weight: 500;
392
+ text-align: center;
393
+ color: #d0d0d3;
430
394
 
431
- &:hover {
432
- color: #ffffff;
433
- }
395
+ &:hover {
396
+ color: #ffffff;
397
+ }
434
398
 
435
- @media (max-width: 1024px) {
436
- font-size: 10px;
437
- }
399
+ @media (max-width: 1024px) {
400
+ font-size: 10px;
401
+ }
438
402
 
439
- @media (max-width: 768px) {
440
- font-size: 9px;
441
- }
403
+ @media (max-width: 768px) {
404
+ font-size: 9px;
405
+ }
442
406
  }
443
407
 
444
408
  /* Responsive task styling */
445
409
  @screen lg {
446
- h4 {
447
- font-size: 10px;
448
- }
410
+ h4 {
411
+ font-size: 10px;
412
+ }
449
413
 
450
- .task-id {
451
- font-size: 8px;
452
- }
414
+ .task-id {
415
+ font-size: 8px;
416
+ }
453
417
 
454
- .task-event-id {
455
- font-size: 10px;
456
- }
418
+ .task-event-id {
419
+ font-size: 10px;
420
+ }
457
421
  }
458
422
  </style>
459
423
 
@@ -461,13 +425,7 @@ h4 {
461
425
  /// <reference path="@/types/index.js" />
462
426
 
463
427
  import { Row } from "@/components/Table";
464
- import {
465
- PlayIcon,
466
- TrashIcon,
467
- BagWhiteIcon,
468
- PauseIcon,
469
- EditIcon,
470
- } from "@/components/icons";
428
+ import { PlayIcon, TrashIcon, BagWhiteIcon, PauseIcon, EditIcon } from "@/components/icons";
471
429
  import Checkbox from "@/components/ui/controls/atomic/Checkbox.vue";
472
430
  import { useUIStore } from "@/stores/ui";
473
431
  import TaskLabel from "@/components/Tasks/TaskLabel.vue";
@@ -477,7 +435,7 @@ const ui = useUIStore();
477
435
 
478
436
  /** @type {{ task: Task }} */
479
437
  const props = defineProps({
480
- task: { type: Object },
438
+ task: { type: Object }
481
439
  });
482
440
 
483
441
  // Context menu positioning
@@ -486,51 +444,51 @@ const contextMenuRef = ref(null);
486
444
 
487
445
  // Handle right-click to position context menu
488
446
  const handleRightClick = (event) => {
489
- const menuWidth = 168; // w-42 = 10.5rem = 168px
490
- const menuHeight = 200; // Approximate height
491
-
492
- let x = event.clientX;
493
- let y = event.clientY - 55;
494
-
495
- // Prevent menu from going off screen
496
- if (x + menuWidth > window.innerWidth) {
497
- x = event.clientX - menuWidth; // Show to the left instead
498
- }
499
- if (y + menuHeight > window.innerHeight) {
500
- y = event.clientY - menuHeight; // Show above instead
501
- }
502
-
503
- contextMenuPosition.value = {
504
- left: `${x}px`,
505
- top: `${y}px`,
506
- };
507
-
508
- // Open the context menu for this task
509
- ui.setOpenContextMenu(props.task.taskId);
510
-
511
- // Add click outside listener after menu opens
512
- nextTick(() => {
513
- document.addEventListener("click", handleClickOutside);
514
- });
447
+ const menuWidth = 168; // w-42 = 10.5rem = 168px
448
+ const menuHeight = 200; // Approximate height
449
+
450
+ let x = event.clientX;
451
+ let y = event.clientY - 55;
452
+
453
+ // Prevent menu from going off screen
454
+ if (x + menuWidth > window.innerWidth) {
455
+ x = event.clientX - menuWidth; // Show to the left instead
456
+ }
457
+ if (y + menuHeight > window.innerHeight) {
458
+ y = event.clientY - menuHeight; // Show above instead
459
+ }
460
+
461
+ contextMenuPosition.value = {
462
+ left: `${x}px`,
463
+ top: `${y}px`
464
+ };
465
+
466
+ // Open the context menu for this task
467
+ ui.setOpenContextMenu(props.task.taskId);
468
+
469
+ // Add click outside listener after menu opens
470
+ nextTick(() => {
471
+ document.addEventListener("click", handleClickOutside);
472
+ });
515
473
  };
516
474
 
517
475
  // Handle clicking outside the context menu
518
476
  const handleClickOutside = (event) => {
519
- if (contextMenuRef.value && !contextMenuRef.value.contains(event.target)) {
520
- ui.setOpenContextMenu("");
521
- document.removeEventListener("click", handleClickOutside);
522
- }
477
+ if (contextMenuRef.value && !contextMenuRef.value.contains(event.target)) {
478
+ ui.setOpenContextMenu("");
479
+ document.removeEventListener("click", handleClickOutside);
480
+ }
523
481
  };
524
482
 
525
483
  // Cleanup on unmount
526
484
  onUnmounted(() => {
527
- document.removeEventListener("click", handleClickOutside);
485
+ document.removeEventListener("click", handleClickOutside);
528
486
  });
529
487
 
530
488
  const copy = (txt) => {
531
- if (!txt) return;
532
- navigator.clipboard.writeText(txt);
533
- ui.showSuccess("Copied text");
489
+ if (!txt) return;
490
+ navigator.clipboard.writeText(txt);
491
+ ui.showSuccess("Copied text");
534
492
  };
535
493
 
536
494
  const colorMapping = new Map();
@@ -539,52 +497,39 @@ colorMapping.set("red", "bg-red-400");
539
497
  colorMapping.set("error", "bg-red-400");
540
498
  colorMapping.set("success", "bg-green-400");
541
499
  const colorToClass = (color) => {
542
- return colorMapping.get(color) || "bg-white";
500
+ return colorMapping.get(color) || "bg-white";
543
501
  };
544
502
 
545
503
  const openInBrowser = (debug) => {
546
- if (!props.task.openerLink) return;
547
- ui.showSuccess(`Opening in browser ${debug ? "(debug)" : ""}`);
548
- const input = props.task.openerLink;
549
- const data = JSON.parse(atob(input.split("://")[1]));
550
- data.config.debug = debug;
551
- const out = "necro://" + btoa(JSON.stringify(data));
552
- openInNewTab(out);
504
+ if (!props.task.openerLink) return;
505
+ ui.showSuccess(`Opening in browser ${debug ? "(debug)" : ""}`);
506
+ const input = props.task.openerLink;
507
+ const data = JSON.parse(atob(input.split("://")[1]));
508
+ data.config.debug = debug;
509
+ const out = "necro://" + btoa(JSON.stringify(data));
510
+ openInNewTab(out);
553
511
  };
554
512
 
555
513
  const formatDate = (date) => {
556
- if (!date) return "-";
557
- const d = new Date(date);
558
- const iso = d.toISOString();
559
- const [year, month, day] = iso.substring(0, 10).split("-");
560
- const time = iso.substring(11, 16);
561
- const dayNames = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
562
- const dayName = dayNames[d.getUTCDay()];
563
- const monthNames = [
564
- "Jan",
565
- "Feb",
566
- "Mar",
567
- "Apr",
568
- "May",
569
- "Jun",
570
- "Jul",
571
- "Aug",
572
- "Sep",
573
- "Oct",
574
- "Nov",
575
- "Dec",
576
- ];
577
- const monthName = monthNames[parseInt(month) - 1];
578
- return `${dayName} ${monthName} ${parseInt(day)} ${year} ${time}`;
514
+ if (!date) return "-";
515
+ const d = new Date(date);
516
+ const iso = d.toISOString();
517
+ const [year, month, day] = iso.substring(0, 10).split("-");
518
+ const time = iso.substring(11, 16);
519
+ const dayNames = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
520
+ const dayName = dayNames[d.getUTCDay()];
521
+ const monthNames = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
522
+ const monthName = monthNames[parseInt(month) - 1];
523
+ return `${dayName} ${monthName} ${parseInt(day)} ${year} ${time}`;
579
524
  };
580
525
 
581
526
  const openInNewTab = (href) => {
582
- if (!href) return;
583
- ui.logger.Info("Opening", href);
584
- Object.assign(document.createElement("a"), {
585
- target: "_blank",
586
- rel: "noopener noreferrer",
587
- href: href,
588
- }).click();
527
+ if (!href) return;
528
+ ui.logger.Info("Opening", href);
529
+ Object.assign(document.createElement("a"), {
530
+ target: "_blank",
531
+ rel: "noopener noreferrer",
532
+ href: href
533
+ }).click();
589
534
  };
590
535
  </script>