@necrolab/dashboard 0.4.49 → 0.4.50

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/.prettierrc CHANGED
@@ -11,12 +11,23 @@
11
11
  "htmlWhitespaceSensitivity": "ignore",
12
12
  "bracketSameLine": true,
13
13
  "singleAttributePerLine": false,
14
+ "endOfLine": "lf",
14
15
  "overrides": [
15
16
  {
16
17
  "files": "*.vue",
17
18
  "options": {
18
19
  "vueIndentScriptAndStyle": false,
19
- "htmlWhitespaceSensitivity": "ignore"
20
+ "htmlWhitespaceSensitivity": "ignore",
21
+ "singleAttributePerLine": false,
22
+ "bracketSameLine": true,
23
+ "printWidth": 120,
24
+ "tabWidth": 4,
25
+ "useTabs": false,
26
+ "semi": true,
27
+ "singleQuote": false,
28
+ "trailingComma": "none",
29
+ "bracketSpacing": true,
30
+ "arrowParens": "always"
20
31
  }
21
32
  }
22
33
  ]
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@necrolab/dashboard",
3
- "version": "0.4.49",
3
+ "version": "0.4.50",
4
4
  "type": "module",
5
5
  "scripts": {
6
6
  "build": "rm -rf dist && npx workbox-cli generateSW workbox-config.cjs && vite build",
@@ -2,20 +2,20 @@
2
2
  <div class="form-section">
3
3
  <!-- Username -->
4
4
  <div class="input-wrapper mb-4">
5
- <label class="label-override">
6
- Username
7
- <ProfileIcon />
8
- </label>
5
+ <label class="label-override">
6
+ <span>Username</span>
7
+ <ProfileIcon class="ml-2" />
8
+ </label>
9
9
  <div class="input-default">
10
10
  <input v-model="user" placeholder="Username" />
11
11
  </div>
12
12
  </div>
13
13
  <!-- Password -->
14
14
  <div class="input-wrapper">
15
- <label class="label-override">
16
- Password
17
- <KeyIcon />
18
- </label>
15
+ <label class="label-override">
16
+ <span>Password</span>
17
+ <KeyIcon class="ml-2" />
18
+ </label>
19
19
  <div class="input-default">
20
20
  <input v-model="password" type="password" placeholder="Password" />
21
21
  </div>
@@ -30,6 +30,7 @@
30
30
  </button>
31
31
  </div>
32
32
  </template>
33
+
33
34
  <script setup>
34
35
  import { useUIStore } from "@/stores/ui";
35
36
  import { ref } from "vue";
@@ -53,3 +54,45 @@ async function login() {
53
54
  buttonDisabled.value = false;
54
55
  }
55
56
  </script>
57
+
58
+ <style lang="scss" scoped>
59
+ .label-override {
60
+ @apply flex items-center text-sm mb-2;
61
+ color: #e1e1e4 !important;
62
+
63
+ svg {
64
+ width: 16px;
65
+ height: 16px;
66
+ path {
67
+ fill: #e1e1e4 !important;
68
+ }
69
+ }
70
+ }
71
+
72
+ .input-default {
73
+ @apply bg-dark-400 border border-dark-650 rounded-lg px-4 py-2 flex items-center;
74
+ min-height: 40px;
75
+
76
+ input {
77
+ @apply bg-transparent border-none outline-none w-full text-white;
78
+ &::placeholder {
79
+ color: #a0a0a6;
80
+ }
81
+ }
82
+ }
83
+
84
+ @media (max-height: 500px) and (orientation: landscape) {
85
+ .label-override {
86
+ @apply text-xs mb-1;
87
+
88
+ svg {
89
+ width: 14px;
90
+ height: 14px;
91
+ }
92
+ }
93
+
94
+ .input-default {
95
+ min-height: 36px;
96
+ }
97
+ }
98
+ </style>
@@ -1,5 +1,5 @@
1
1
  <template>
2
- <div class="flex text-white font-bold lg:gap-5 gap-1 lg:mb-1 min-h-[2.5rem]" v-if="show" :key="key">
2
+ <div class="flex text-white font-bold lg:gap-5 gap-1 lg:mb-1 min-h-[2.5rem]" v-if="ui.queueStats.show" :key="key">
3
3
  <div
4
4
  v-if="ui.queueStats.total"
5
5
  class="stats-card lg:mb-2 mb-1 text-sm rounded-xl lg:p-3 p-2 lg:gap-3 gap-2 flex justify-between items-center min-w-0 h-8">
@@ -68,7 +68,6 @@ const getQueuePassAmount = (width) => {
68
68
  return 1;
69
69
  };
70
70
 
71
- let show = ref(true);
72
71
  let key = ref(0);
73
72
  let queuePassAmount = ref(getQueuePassAmount(window.innerWidth));
74
73
 
@@ -330,83 +330,93 @@ h4 {
330
330
  @media (max-width: 480px) and (orientation: portrait) {
331
331
  /* Position adjustment for mobile taskId */
332
332
  .block.md\\:hidden {
333
- left: 4rem !important; /* Move further right to avoid checkbox collision */
333
+ left: 4rem !important;
334
334
  top: 0.25rem !important;
335
335
  z-index: 1 !important;
336
336
  }
337
337
 
338
- /* Ultra-compact button layout for mobile portrait */
338
+ /* Improved button layout for mobile portrait */
339
339
  .task-buttons {
340
340
  padding: 1px;
341
- gap: 0;
341
+ gap: 1px;
342
342
  border-radius: 4px;
343
- border: none !important;
344
- box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1) !important;
343
+ border: 1px solid #3d3e44 !important;
344
+ box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1) !important;
345
345
  max-width: 100%;
346
- overflow: visible;
346
+ min-height: 28px;
347
+ height: auto;
347
348
  flex-wrap: wrap;
348
349
  justify-content: center;
349
- min-height: 18px;
350
- height: auto;
350
+ align-items: center;
351
+ background: #2e2f34;
351
352
 
352
353
  button {
353
- width: 15px;
354
- height: 15px;
355
- border-radius: 2px;
356
- min-width: 15px;
354
+ width: 20px;
355
+ height: 20px;
356
+ border-radius: 3px;
357
+ min-width: 20px;
357
358
  border: none !important;
358
359
  flex-shrink: 0;
359
360
  margin: 0.5px;
361
+ background: transparent;
360
362
 
361
363
  &:hover {
362
- transform: scale(1.1);
364
+ background: rgba(255, 255, 255, 0.1);
365
+ transform: scale(1.05);
366
+ }
367
+
368
+ &:active {
369
+ background: rgba(255, 255, 255, 0.15);
370
+ transform: scale(0.95);
363
371
  }
364
372
  }
365
373
 
366
374
  svg,
367
375
  img {
368
- width: 7px;
369
- height: 7px;
376
+ width: 10px;
377
+ height: 10px;
370
378
  }
371
379
 
372
380
  span {
373
- font-size: 0.5rem;
381
+ font-size: 0.7rem;
374
382
  line-height: 1;
375
383
  }
376
384
 
377
- /* Allow buttons to wrap to second row if needed */
385
+ /* Improved list item layout */
378
386
  li {
379
387
  display: flex;
380
388
  margin: 0;
389
+ padding: 0;
381
390
  }
382
391
  }
383
392
 
384
- /* Make the actions column slightly more flexible */
393
+ /* Make the actions column more flexible */
385
394
  .col-span-2.lg\\:col-span-3 {
386
395
  min-width: 0;
387
396
  flex-shrink: 0;
388
397
  display: flex;
389
398
  align-items: center;
390
399
  justify-content: center;
400
+ padding: 0 2px;
391
401
  }
392
402
 
393
403
  /* Compact status container */
394
404
  .status-container {
395
405
  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;
406
+ box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1) !important;
407
+ padding: 2px 4px;
408
+ font-size: 0.7rem;
399
409
  max-width: 100%;
400
410
  }
401
411
 
402
412
  .status-text {
403
- font-size: 0.7rem;
413
+ font-size: 0.65rem;
404
414
  letter-spacing: 0;
405
415
  }
406
416
 
407
417
  /* Reduce row height to accommodate smaller elements */
408
418
  .task-row-container {
409
- min-height: 50px !important;
419
+ min-height: 45px !important;
410
420
  }
411
421
  }
412
422
 
@@ -1,138 +1,188 @@
1
1
  <template>
2
- <div class="table-component">
3
- <Header class="text-center grid-cols-10 gap-2 lg:grid-cols-12">
4
- <div class="col-span-1 lg:col-span-2 flex items-center justify-start">
5
- <Checkbox class="ml-2 mr-4 flex-shrink-0" :toggled="ui.mainCheckbox.tasks" @valueUpdate="ui.toggleMainCheckbox('tasks')" :isHeader="true" />
6
- <div class="mx-auto hidden lg:flex items-center" @click="ui.toggleSort('eventId')">
7
- <EventIcon class="lg:mr-3" />
8
- <h4 class="hidden lg:flex">Event</h4>
9
- <DownIcon v-if="ui.sortData.sortBy === 'eventId' && !ui.sortData.reversed" class="ml-1" />
10
- <UpIcon v-if="ui.sortData.sortBy === 'eventId' && ui.sortData.reversed" class="ml-1" />
11
- </div>
12
- </div>
13
- <div class="col-span-2 flex-center" v-once>
14
- <TicketIcon class="mr-0 lg:mr-3" />
15
- <h4 class="hidden lg:flex">Tickets</h4>
16
- </div>
17
- <div class="col-span-5 md:col-span-4 lg:col-span-5 flex-center" @click="ui.toggleSort('status')">
18
- <StatusIcon class="mr-0 lg:mr-3" />
19
- <h4 class="hidden lg:flex">Status</h4>
20
- <DownIcon v-if="ui.sortData.sortBy === 'status' && !ui.sortData.reversed" class="ml-1" />
21
- <UpIcon v-if="ui.sortData.sortBy === 'status' && ui.sortData.reversed" class="ml-1" />
22
- </div>
23
- <div class="col-span-2 lg:col-span-3 flex-center" v-once>
24
- <ClickIcon class="mr-0 lg:mr-3" />
25
- <h4 class="hidden lg:flex">Actions</h4>
26
- </div>
27
- <div class="absolute right-5 hidden lg:flex items-center top-3.5" @click="ui.toggleSort('taskId')">
28
- <h4 class="text-center text-xs">ID</h4>
29
- <DownIcon v-if="ui.sortData.sortBy === 'taskId' && !ui.sortData.reversed" class="ml-1" />
30
- <UpIcon v-if="ui.sortData.sortBy === 'taskId' && ui.sortData.reversed" class="ml-1" />
31
- </div>
32
- </Header>
2
+ <div class="table-component">
3
+ <Header class="text-center grid-cols-10 gap-2 lg:grid-cols-12">
4
+ <div class="col-span-1 lg:col-span-2 flex items-center justify-start">
5
+ <Checkbox
6
+ class="ml-2 mr-4 flex-shrink-0"
7
+ :toggled="ui.mainCheckbox.tasks"
8
+ @valueUpdate="ui.toggleMainCheckbox('tasks')"
9
+ :isHeader="true"
10
+ />
33
11
  <div
34
- class="flex flex-col divide-y divide-dark-650 overflow-y-auto hidden-scrollbars overflow-x-hidden stop-pan"
35
- :style="{ maxHeight: dynamicTableHeight }">
36
- <div v-for="(task, i) in getTasksInOrder()" :key="task.taskId" class="task-row-container">
37
- <Task :task="task" :class="i % 2 == 1 ? 'table-row-even' : 'table-row-odd'" />
38
- </div>
39
- <div
40
- v-if="getTasksInOrder().length === 0"
41
- class="flex flex-col items-center justify-center py-8 empty-state text-center">
42
- <div v-if="ui.queueStats.total === 0">
43
- <TasksIcon class="w-12 h-12 text-dark-400 mb-3 opacity-50 mx-auto" />
44
- <p class="text-light-400 text-sm">No tasks yet</p>
45
- <p class="text-light-500 text-xs mt-1">Create tasks to get started</p>
46
- </div>
47
- <div v-else>
48
- <TasksIcon class="w-12 h-12 text-dark-400 mb-3 opacity-50 mx-auto" />
49
- <p class="text-light-400 text-sm">
50
- {{ ui.queueStats.total }} hidden task{{ ui.queueStats.total === 1 ? "" : "s" }}
51
- </p>
52
- <p class="text-light-500 text-xs mt-1">Adjust filters to see tasks</p>
53
- </div>
54
- </div>
12
+ class="mx-auto hidden lg:flex items-center"
13
+ @click="ui.toggleSort('eventId')"
14
+ >
15
+ <EventIcon class="lg:mr-3" />
16
+ <h4 class="hidden lg:flex">Event</h4>
17
+ <DownIcon
18
+ v-if="ui.sortData.sortBy === 'eventId' && !ui.sortData.reversed"
19
+ class="ml-1"
20
+ />
21
+ <UpIcon
22
+ v-if="ui.sortData.sortBy === 'eventId' && ui.sortData.reversed"
23
+ class="ml-1"
24
+ />
55
25
  </div>
26
+ </div>
27
+ <div class="col-span-2 flex-center" v-once>
28
+ <TicketIcon class="mr-0 lg:mr-3" />
29
+ <h4 class="hidden lg:flex">Tickets</h4>
30
+ </div>
31
+ <div
32
+ class="col-span-5 md:col-span-4 lg:col-span-5 flex-center"
33
+ @click="ui.toggleSort('status')"
34
+ >
35
+ <StatusIcon class="mr-0 lg:mr-3" />
36
+ <h4 class="hidden lg:flex">Status</h4>
37
+ <DownIcon
38
+ v-if="ui.sortData.sortBy === 'status' && !ui.sortData.reversed"
39
+ class="ml-1"
40
+ />
41
+ <UpIcon
42
+ v-if="ui.sortData.sortBy === 'status' && ui.sortData.reversed"
43
+ class="ml-1"
44
+ />
45
+ </div>
46
+ <div class="col-span-2 lg:col-span-3 flex-center" v-once>
47
+ <ClickIcon class="mr-0 lg:mr-3" />
48
+ <h4 class="hidden lg:flex">Actions</h4>
49
+ </div>
50
+ <div
51
+ class="absolute right-5 hidden lg:flex items-center top-3.5"
52
+ @click="ui.toggleSort('taskId')"
53
+ >
54
+ <h4 class="text-center text-xs">ID</h4>
55
+ <DownIcon
56
+ v-if="ui.sortData.sortBy === 'taskId' && !ui.sortData.reversed"
57
+ class="ml-1"
58
+ />
59
+ <UpIcon
60
+ v-if="ui.sortData.sortBy === 'taskId' && ui.sortData.reversed"
61
+ class="ml-1"
62
+ />
63
+ </div>
64
+ </Header>
65
+ <div
66
+ class="flex flex-col divide-y divide-dark-650 overflow-y-auto hidden-scrollbars overflow-x-hidden stop-pan"
67
+ :style="{ maxHeight: dynamicTableHeight }"
68
+ >
69
+ <div
70
+ v-for="(task, i) in getTasksInOrder()"
71
+ :key="task.taskId"
72
+ class="task-row-container"
73
+ >
74
+ <Task :task="task" :class="i % 2 == 1 ? 'table-row-even' : 'table-row-odd'" />
75
+ </div>
76
+ <div
77
+ v-if="getTasksInOrder().length === 0"
78
+ class="flex flex-col items-center justify-center py-8 empty-state text-center"
79
+ >
80
+ <div
81
+ v-if="
82
+ !ui.queueStats.queued &&
83
+ !ui.queueStats.sleeping &&
84
+ ui.queueStats.nextQueuePasses.length === 0
85
+ "
86
+ >
87
+ <TasksIcon class="w-12 h-12 text-dark-400 mb-3 opacity-50 mx-auto" />
88
+ <p class="text-light-400 text-sm">No tasks yet</p>
89
+ <p class="text-light-500 text-xs mt-1">Create tasks to get started</p>
90
+ </div>
91
+ <div v-else>
92
+ <TasksIcon class="w-12 h-12 text-dark-400 mb-3 opacity-50 mx-auto" />
93
+ <p class="text-light-400 text-sm">No tasks match current filters</p>
94
+ <p class="text-light-500 text-xs mt-1">Adjust filters to see tasks</p>
95
+ </div>
96
+ </div>
56
97
  </div>
98
+ </div>
57
99
  </template>
58
100
  <style lang="scss" scoped>
59
101
  h4 {
60
- @apply text-white;
102
+ @apply text-white;
61
103
  }
62
104
 
63
105
  .stop-pan {
64
- touch-action: pan-y pan-up pan-down;
106
+ touch-action: pan-y pan-up pan-down;
65
107
  }
66
108
 
67
109
  .task-row-container {
68
- min-height: 69px;
69
- flex-shrink: 0;
70
- transition: background-color 0.15s ease;
110
+ min-height: 69px;
111
+ flex-shrink: 0;
112
+ transition: background-color 0.15s ease;
71
113
 
72
- &:hover {
73
- @apply bg-dark-550 !important;
74
- }
114
+ &:hover {
115
+ @apply bg-dark-550 !important;
116
+ }
75
117
 
76
- @media (max-width: 768px) {
77
- min-height: 58px;
78
- }
118
+ @media (max-width: 768px) {
119
+ min-height: 58px;
120
+ }
79
121
 
80
- @media (max-width: 480px) and (orientation: portrait) {
81
- min-height: 50px;
82
- }
122
+ @media (max-width: 480px) and (orientation: portrait) {
123
+ min-height: 50px;
124
+ }
83
125
  }
84
126
 
85
127
  .empty-state {
86
- @apply bg-dark-400;
87
- color: #969696;
88
- font-size: 14px;
89
- font-weight: 500;
128
+ @apply bg-dark-400;
129
+ color: #969696;
130
+ font-size: 14px;
131
+ font-weight: 500;
90
132
  }
91
133
  </style>
92
134
  <script setup>
93
135
  import { computed, ref, onMounted, onUnmounted } from "vue";
94
136
  import { Table, Header } from "@/components/Table";
95
- import { EventIcon, TicketIcon, StatusIcon, ClickIcon, DownIcon, UpIcon, TasksIcon } from "@/components/icons";
137
+ import {
138
+ EventIcon,
139
+ TicketIcon,
140
+ StatusIcon,
141
+ ClickIcon,
142
+ DownIcon,
143
+ UpIcon,
144
+ TasksIcon,
145
+ } from "@/components/icons";
96
146
  import Task from "./Task.vue";
97
147
  import Checkbox from "@/components/ui/controls/atomic/Checkbox.vue";
98
148
  import { useUIStore } from "@/stores/ui";
99
149
 
100
150
  const props = defineProps({
101
- tasks: { type: Object }
151
+ tasks: { type: Object },
102
152
  });
103
153
 
104
154
  const shouldTaskShow = (task) => {
105
- if (ui.taskFilter === "All") return true;
106
- else if (ui.taskFilter === "Checkout") return task.expirationTime || task.noCartholds;
107
- else return true;
155
+ if (ui.taskFilter === "All") return true;
156
+ else if (ui.taskFilter === "Checkout") return task.expirationTime || task.noCartholds;
157
+ else return true;
108
158
  };
109
159
 
110
160
  const ui = useUIStore();
111
161
 
112
162
  const siteIdEdgeCases = {
113
- LN_US: ["TM_US"],
114
- TM_CA: ["TM_US"],
115
- TM_IE: ["TM_UK"],
116
- TM_NZ: ["TM_AU"]
163
+ LN_US: ["TM_US"],
164
+ TM_CA: ["TM_US"],
165
+ TM_IE: ["TM_UK"],
166
+ TM_NZ: ["TM_AU"],
117
167
  };
118
168
 
119
169
  const getTasksInOrder = () => {
120
- let out = [];
121
- ui.taskIdOrder.forEach((id) => {
122
- if (props.tasks[id] && !props.tasks[id]?.hidden) {
123
- const task = props.tasks[id];
124
-
125
- if (
126
- task.siteId !== ui.currentCountry.siteId &&
127
- !siteIdEdgeCases[task.siteId]?.includes(ui.currentCountry.siteId)
128
- )
129
- return;
130
- if (ui.currentEvent && task.eventId !== ui.currentEvent) return;
131
- if (!shouldTaskShow(task)) return;
132
- out.push(task);
133
- }
134
- });
135
- return out;
170
+ let out = [];
171
+ ui.taskIdOrder.forEach((id) => {
172
+ if (props.tasks[id] && !props.tasks[id]?.hidden) {
173
+ const task = props.tasks[id];
174
+
175
+ if (
176
+ task.siteId !== ui.currentCountry.siteId &&
177
+ !siteIdEdgeCases[task.siteId]?.includes(ui.currentCountry.siteId)
178
+ )
179
+ return;
180
+ if (ui.currentEvent && task.eventId !== ui.currentEvent) return;
181
+ if (!shouldTaskShow(task)) return;
182
+ out.push(task);
183
+ }
184
+ });
185
+ return out;
136
186
  };
137
187
 
138
188
  // Dynamic height calculation to prevent page scrolling
@@ -140,42 +190,54 @@ const windowHeight = ref(window.innerHeight);
140
190
  const windowWidth = ref(window.innerWidth);
141
191
 
142
192
  const updateDimensions = () => {
143
- windowHeight.value = window.innerHeight;
144
- windowWidth.value = window.innerWidth;
193
+ windowHeight.value = window.innerHeight;
194
+ windowWidth.value = window.innerWidth;
145
195
  };
146
196
 
147
197
  onMounted(() => {
148
- window.addEventListener("resize", updateDimensions);
198
+ window.addEventListener("resize", updateDimensions);
149
199
  });
150
200
 
151
201
  onUnmounted(() => {
152
- window.removeEventListener("resize", updateDimensions);
202
+ window.removeEventListener("resize", updateDimensions);
153
203
  });
154
204
 
155
205
  const dynamicTableHeight = computed(() => {
156
- // Calculate available space for table
157
- const headerHeight = 60; // Header + navbar
158
- const titleHeight = 50; // Tasks title and mobile controls
159
- const statsHeight = 50; // Queue stats
160
- const controlsHeight = windowWidth.value >= 650 ? 60 : 0; // Desktop controls
161
- const filtersHeight = 50; // Event dropdown and filter toggle
162
- const utilitiesHeight = windowWidth.value <= 480 && windowHeight.value > windowWidth.value ? 150 : 200; // Reduce utilities height in mobile portrait
163
- const margins =
164
- windowWidth.value >= 1024 ? 40 : windowWidth.value <= 480 && windowHeight.value > windowWidth.value ? 15 : 20; // Reduce margins in mobile portrait
165
-
166
- const totalUsedSpace =
167
- headerHeight + titleHeight + statsHeight + controlsHeight + filtersHeight + utilitiesHeight + margins;
168
- const availableHeight = windowHeight.value - totalUsedSpace;
169
-
170
- // Calculate row height based on screen size
171
- const rowHeight = windowWidth.value <= 768 ? 58 : 69; // Mobile vs desktop row height
172
- const minRowsToShow = 2; // Always show at least 2 rows
173
- const minHeight = minRowsToShow * rowHeight;
174
-
175
- // Calculate how many complete rows can fit
176
- const maxCompleteRows = Math.floor(Math.max(availableHeight, minHeight) / rowHeight) + 1;
177
- const exactHeight = maxCompleteRows * rowHeight;
178
-
179
- return exactHeight + "px";
206
+ // Calculate available space for table
207
+ const headerHeight = 60; // Header + navbar
208
+ const titleHeight = 50; // Tasks title and mobile controls
209
+ const statsHeight = 50; // Queue stats
210
+ const controlsHeight = windowWidth.value >= 650 ? 60 : 0; // Desktop controls
211
+ const filtersHeight = 50; // Event dropdown and filter toggle
212
+ const utilitiesHeight =
213
+ windowWidth.value <= 480 && windowHeight.value > windowWidth.value ? 150 : 200; // Reduce utilities height in mobile portrait
214
+ const margins =
215
+ windowWidth.value >= 1024
216
+ ? 40
217
+ : windowWidth.value <= 480 && windowHeight.value > windowWidth.value
218
+ ? 15
219
+ : 20; // Reduce margins in mobile portrait
220
+
221
+ const totalUsedSpace =
222
+ headerHeight +
223
+ titleHeight +
224
+ statsHeight +
225
+ controlsHeight +
226
+ filtersHeight +
227
+ utilitiesHeight +
228
+ margins;
229
+ const availableHeight = windowHeight.value - totalUsedSpace;
230
+
231
+ // Calculate row height based on screen size
232
+ const rowHeight = windowWidth.value <= 768 ? 58 : 69; // Mobile vs desktop row height
233
+ const minRowsToShow = 2; // Always show at least 2 rows
234
+ const minHeight = minRowsToShow * rowHeight;
235
+
236
+ // Calculate how many complete rows can fit
237
+ const maxCompleteRows =
238
+ Math.floor(Math.max(availableHeight, minHeight) / rowHeight) + 1;
239
+ const exactHeight = maxCompleteRows * rowHeight;
240
+
241
+ return exactHeight + "px";
180
242
  });
181
243
  </script>
@@ -1,3 +1,5 @@
1
+ const queueStats = false;
2
+
1
3
  export default {
2
4
  Profile: {
3
5
  name: "Admin",
@@ -17,7 +19,7 @@ export default {
17
19
  email: "grantelam@hotmail.com",
18
20
  password: "Dkstrhf4srth56Gksj",
19
21
  status: "Event already happened long long long long long long longlong long long long",
20
- inQueue: true,
22
+ inQueue: queueStats,
21
23
  statusColor: "red",
22
24
  manual: false,
23
25
  incapsulaBypass: false,
@@ -324,7 +326,7 @@ export default {
324
326
  active: true,
325
327
  email: "taylortaxjbr26248@gmail.com",
326
328
  password: "OwZz9PfKtWsrS7",
327
- status: "Waiting for Queue",
329
+ status: queueStats ? "Waiting for Queue" : "Waiting for Stock",
328
330
  statusColor: "white",
329
331
  manual: false,
330
332
  incapsulaBypass: false,
package/src/stores/ui.js CHANGED
@@ -233,10 +233,7 @@ export const useUIStore = defineStore("ui", () => {
233
233
  let relevantTasks = Object.values(tasks.value).filter((t) => t.siteId === currentCountry.value.siteId);
234
234
  if (currentEvent.value) relevantTasks = relevantTasks.filter((t) => t.eventId === currentEvent.value);
235
235
 
236
- queueStats.value.total = 0;
237
236
  queueStats.value.queued = relevantTasks.filter((t) => t.inQueue).length || 0;
238
- // if (DEBUG) queueStats.value.queued += 50000;
239
- queueStats.value.show = queueStats.value.total > 0;
240
237
  const sleepingStatuses = ["sleeping in queue", "waiting for drop", "waiting for carting", "waiting for queue"];
241
238
  queueStats.value.sleeping = relevantTasks.filter((t) =>
242
239
  sleepingStatuses.includes(t.status.toLowerCase())
@@ -246,6 +243,10 @@ export const useUIStore = defineStore("ui", () => {
246
243
  .filter((e) => !isNaN(e))
247
244
  .filter(Boolean);
248
245
  queueStats.value.nextQueuePasses = positions.sort((a, b) => a - b);
246
+
247
+ // Only show stats if there are any queued tasks, sleeping tasks, or queue positions
248
+ queueStats.value.show =
249
+ queueStats.value.queued > 0 || queueStats.value.sleeping > 0 || queueStats.value.nextQueuePasses.length > 0;
249
250
  };
250
251
 
251
252
  const toggleModal = (name, clearValue = false) => {