@necrolab/dashboard 0.4.61 → 0.4.208
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 +1 -27
- package/.vscode/extensions.json +1 -1
- package/README.md +79 -43
- package/backend/api.js +48 -40
- package/backend/auth.js +3 -3
- package/backend/batching.js +1 -1
- package/backend/endpoints.js +77 -13
- package/backend/index.js +2 -2
- package/backend/mock-data.js +38 -29
- package/backend/mock-src/classes/logger.js +8 -8
- package/backend/mock-src/classes/utils.js +3 -7
- package/backend/mock-src/database.js +0 -0
- package/backend/mock-src/ticketmaster.js +79 -79
- package/backend/validator.js +2 -2
- package/config/configs.json +3 -2
- package/config/filter.json +3 -2
- package/index.html +10 -81
- package/index.js +1 -1
- package/package.json +25 -40
- package/postcss.config.js +1 -1
- package/postinstall.js +17 -98
- package/public/android-chrome-192x192.png +0 -0
- package/public/android-chrome-512x512.png +0 -0
- package/public/apple-touch-icon.png +0 -0
- package/public/favicon-16x16.png +0 -0
- package/public/favicon-32x32.png +0 -0
- package/public/favicon.ico +0 -0
- package/public/manifest.json +7 -12
- package/public/sw.js +2 -0
- package/public/workbox-49fdaf31.js +2 -0
- package/public/workbox-49fdaf31.js.map +1 -0
- package/public/workbox-88575b92.js +2 -0
- package/public/workbox-88575b92.js.map +1 -0
- package/public/workbox-a67a7b11.js +2 -0
- package/public/workbox-a67a7b11.js.map +1 -0
- package/public/workbox-d4314735.js +2 -0
- package/public/workbox-d4314735.js.map +1 -0
- package/public/workbox-e0f89ef3.js +2 -0
- package/public/workbox-e0f89ef3.js.map +1 -0
- package/run +9 -176
- package/src/App.vue +85 -498
- package/src/assets/css/_input.scss +99 -144
- package/src/assets/css/main.scss +99 -450
- package/src/assets/img/background.svg +2 -2
- package/src/assets/img/logo_icon.png +0 -0
- package/src/components/Auth/LoginForm.vue +11 -62
- package/src/components/Editors/Account/Account.vue +40 -116
- package/src/components/Editors/Account/AccountCreator.vue +39 -88
- package/src/components/Editors/Account/AccountView.vue +34 -102
- package/src/components/Editors/Account/CreateAccount.vue +32 -80
- package/src/components/Editors/Profile/CreateProfile.vue +83 -269
- package/src/components/Editors/Profile/Profile.vue +47 -132
- package/src/components/Editors/Profile/ProfileCountryChooser.vue +20 -82
- package/src/components/Editors/Profile/ProfileView.vue +34 -91
- package/src/components/Editors/TagLabel.vue +6 -67
- package/src/components/Filter/Filter.vue +72 -289
- package/src/components/Filter/FilterPreview.vue +30 -171
- package/src/components/Filter/PriceSortToggle.vue +4 -74
- package/src/components/Table/Header.vue +1 -1
- package/src/components/Table/Row.vue +1 -1
- package/src/components/Table/Table.vue +2 -19
- package/src/components/Tasks/CheckStock.vue +13 -28
- package/src/components/Tasks/Controls/DesktopControls.vue +17 -17
- package/src/components/Tasks/Controls/MobileControls.vue +45 -8
- package/src/components/Tasks/CreateTaskAXS.vue +73 -79
- package/src/components/Tasks/CreateTaskTM.vue +142 -94
- package/src/components/Tasks/MassEdit.vue +7 -9
- package/src/components/Tasks/QuickSettings.vue +55 -169
- package/src/components/Tasks/ScrapeVenue.vue +4 -7
- package/src/components/Tasks/Stats.vue +23 -52
- package/src/components/Tasks/Task.vue +136 -378
- package/src/components/Tasks/TaskView.vue +47 -107
- package/src/components/Tasks/Utilities.vue +6 -5
- package/src/components/icons/Bag.vue +1 -1
- package/src/components/icons/Loyalty.vue +1 -1
- package/src/components/icons/Mail.vue +2 -2
- package/src/components/icons/Play.vue +2 -2
- package/src/components/icons/Reload.vue +5 -4
- package/src/components/icons/Sandclock.vue +2 -2
- package/src/components/icons/Stadium.vue +1 -1
- package/src/components/icons/index.js +1 -24
- package/src/components/ui/Modal.vue +13 -105
- package/src/components/ui/Navbar.vue +38 -171
- package/src/components/ui/ReconnectIndicator.vue +55 -351
- package/src/components/ui/Splash.vue +35 -5
- package/src/components/ui/controls/CountryChooser.vue +62 -200
- package/src/components/ui/controls/atomic/Checkbox.vue +10 -119
- package/src/components/ui/controls/atomic/Dropdown.vue +39 -208
- package/src/components/ui/controls/atomic/MultiDropdown.vue +37 -300
- package/src/libs/Filter.js +170 -200
- package/src/registerServiceWorker.js +1 -1
- package/src/stores/connection.js +53 -51
- package/src/stores/logger.js +3 -11
- package/src/stores/sampleData.js +235 -207
- package/src/stores/ui.js +44 -112
- package/src/stores/utils.js +6 -90
- package/src/views/Accounts.vue +35 -44
- package/src/views/Console.vue +90 -341
- package/src/views/Editor.vue +123 -1176
- package/src/views/FilterBuilder.vue +251 -607
- package/src/views/Login.vue +14 -76
- package/src/views/Profiles.vue +25 -44
- package/src/views/Tasks.vue +100 -187
- package/static/offline.html +50 -192
- package/tailwind.config.js +26 -104
- package/vite.config.js +16 -73
- package/vue.config.js +32 -0
- package/workbox-config.js +11 -0
- package/artwork/image.png +0 -0
- package/dev-server.js +0 -136
- package/exit +0 -209
- package/jsconfig.json +0 -16
- package/src/assets/css/_utilities.scss +0 -388
- package/src/assets/img/background.svg.backup +0 -11
- package/src/components/icons/Check.vue +0 -5
- package/src/components/icons/Close.vue +0 -21
- package/src/components/icons/CloseX.vue +0 -5
- package/src/components/icons/Key.vue +0 -21
- package/src/components/icons/Pencil.vue +0 -21
- package/src/components/icons/Profile.vue +0 -18
- package/src/components/icons/Sell.vue +0 -21
- package/src/components/icons/Spinner.vue +0 -42
- package/src/components/icons/SquareCheck.vue +0 -18
- package/src/components/icons/SquareUncheck.vue +0 -18
- package/src/components/icons/Wildcard.vue +0 -18
- package/src/components/ui/controls/atomic/LoadingButton.vue +0 -45
- package/src/composables/useClickOutside.js +0 -21
- package/src/composables/useDropdownPosition.js +0 -174
- package/src/types/index.js +0 -41
- package/src/utils/debug.js +0 -1
- package/switch-branch.sh +0 -41
- package/workbox-config.cjs +0 -63
- /package/src/assets/img/{logo_icon-old.png → logo_icon_2.png} +0 -0
|
@@ -1,64 +1,64 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<Row
|
|
3
|
-
class="relative grid-cols-7
|
|
3
|
+
class="relative text-white grid-cols-7 lg:grid-cols-8"
|
|
4
4
|
@click="ui.setOpenContextMenu('')"
|
|
5
|
-
@click.right.prevent="ui.setOpenContextMenu('')"
|
|
6
|
-
|
|
5
|
+
@click.right.prevent="ui.setOpenContextMenu('')"
|
|
6
|
+
>
|
|
7
|
+
<div class="col-span-3 lg:col-span-2 flex">
|
|
7
8
|
<Checkbox
|
|
8
9
|
class="ml-0 mr-4"
|
|
9
|
-
:toggled="props.
|
|
10
|
-
@valueUpdate="ui.toggleProfileSelected(props.
|
|
10
|
+
:toggled="props.task.selected"
|
|
11
|
+
@valueUpdate="ui.toggleProfileSelected(props.task._id)"
|
|
12
|
+
/>
|
|
11
13
|
<h4 class="mx-auto text-white">
|
|
12
|
-
{{ props.
|
|
14
|
+
{{ props.task.profileName }}
|
|
13
15
|
</h4>
|
|
14
16
|
</div>
|
|
15
17
|
<div class="col-span-1 lg:col-span-2">
|
|
16
|
-
<h4 class="flex
|
|
17
|
-
<span class="hidden
|
|
18
|
-
|
|
19
|
-
props.
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
</span>
|
|
26
|
-
<img class="h-6 w-6" :src="getAccountType()" />
|
|
18
|
+
<h4 class="text-white flex justify-center items-center gap-2">
|
|
19
|
+
<span class="hidden ipadlg:block">{{
|
|
20
|
+
props.task.privacy
|
|
21
|
+
? props.task.cardNumber[0] +
|
|
22
|
+
"•".repeat(props.task.cardNumber.length - 5) +
|
|
23
|
+
props.task.cardNumber.slice(-4)
|
|
24
|
+
: validateCard(props.task.cardNumber).formatted
|
|
25
|
+
}}</span>
|
|
26
|
+
<img width="22 px" :src="getAccountType()" />
|
|
27
27
|
</h4>
|
|
28
28
|
</div>
|
|
29
29
|
<div class="col-span-1">
|
|
30
30
|
<h4 class="text-white">{{ expDate() }}</h4>
|
|
31
31
|
</div>
|
|
32
32
|
<div class="col-span-1">
|
|
33
|
-
<h4 v-if="props.
|
|
34
|
-
<img
|
|
33
|
+
<h4 v-if="props.task.enabled" class="text-green-400 flex justify-center">
|
|
34
|
+
<img width="12px" height="12px" class="green" src="/img/controls/enable.svg" />
|
|
35
35
|
</h4>
|
|
36
|
-
<h4 v-else class="flex justify-center
|
|
37
|
-
<img
|
|
36
|
+
<h4 v-else class="text-red-400 flex justify-center">
|
|
37
|
+
<img width="12px" height="12px" class="fill-red-400" src="/img/close.svg" />
|
|
38
38
|
</h4>
|
|
39
39
|
</div>
|
|
40
40
|
|
|
41
41
|
<div class="col-span-1 hidden lg:block">
|
|
42
|
-
<h4 class="flex justify-center gap-1
|
|
43
|
-
<TagLabel v-for="tag in props.
|
|
42
|
+
<h4 class="text-white flex justify-center gap-1">
|
|
43
|
+
<TagLabel v-for="tag in props.task.tags" :key="tag" :text="tag" />
|
|
44
44
|
</h4>
|
|
45
45
|
</div>
|
|
46
46
|
|
|
47
47
|
<div class="col-span-1 flex">
|
|
48
|
-
<ul class="
|
|
48
|
+
<ul class="task-buttons bg-dark-600 px-2 rounded-full shadow-3xl py-1 items-center">
|
|
49
49
|
<li>
|
|
50
50
|
<button @click="edit">
|
|
51
51
|
<EditIcon />
|
|
52
52
|
</button>
|
|
53
53
|
</li>
|
|
54
|
-
<li v-if="props.
|
|
54
|
+
<li v-if="props.task.enabled">
|
|
55
55
|
<button @click="disable">
|
|
56
|
-
<img class="
|
|
56
|
+
<img width="16px" height="16px" class="mt-0.5" src="/img/controls/disable.svg" />
|
|
57
57
|
</button>
|
|
58
58
|
</li>
|
|
59
59
|
<li v-else>
|
|
60
60
|
<button @click="enable">
|
|
61
|
-
<img class="
|
|
61
|
+
<img width="16px" height="16px" class="mt-0.5" src="/img/controls/enable.svg" />
|
|
62
62
|
</button>
|
|
63
63
|
</li>
|
|
64
64
|
<li>
|
|
@@ -76,111 +76,28 @@
|
|
|
76
76
|
h4 {
|
|
77
77
|
@apply text-center;
|
|
78
78
|
}
|
|
79
|
-
.
|
|
80
|
-
@apply mx-auto
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
button {
|
|
85
|
-
@apply relative flex items-center justify-center rounded border-0 outline-0 transition-all duration-150;
|
|
86
|
-
background: transparent;
|
|
87
|
-
width: 28px;
|
|
88
|
-
height: 28px;
|
|
89
|
-
color: #d0d0d3;
|
|
90
|
-
|
|
91
|
-
&:hover {
|
|
92
|
-
background: rgba(255, 255, 255, 0.1);
|
|
93
|
-
color: #ffffff;
|
|
94
|
-
transform: scale(1.05);
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
&:active {
|
|
98
|
-
background: rgba(255, 255, 255, 0.2);
|
|
99
|
-
transform: scale(0.95);
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
svg,
|
|
104
|
-
img {
|
|
105
|
-
width: 16px;
|
|
106
|
-
height: 16px;
|
|
107
|
-
position: relative;
|
|
108
|
-
z-index: 1;
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
svg path {
|
|
112
|
-
fill: currentColor;
|
|
79
|
+
.task-buttons {
|
|
80
|
+
@apply flex mx-auto gap-x-3;
|
|
81
|
+
svg {
|
|
82
|
+
width: 15px;
|
|
83
|
+
height: 15px;
|
|
113
84
|
}
|
|
114
85
|
}
|
|
115
86
|
|
|
116
|
-
// Tablet optimization
|
|
117
87
|
@media (max-width: 1024px) {
|
|
118
88
|
h4 {
|
|
119
89
|
font-size: 10px !important;
|
|
120
90
|
}
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
padding: 3px;
|
|
124
|
-
gap: 2px;
|
|
125
|
-
|
|
126
|
-
button {
|
|
127
|
-
width: 26px;
|
|
128
|
-
height: 26px;
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
svg,
|
|
132
|
-
img {
|
|
133
|
-
width: 14px;
|
|
134
|
-
height: 14px;
|
|
135
|
-
}
|
|
91
|
+
.task-buttons {
|
|
92
|
+
@apply gap-x-3;
|
|
136
93
|
}
|
|
137
|
-
|
|
138
|
-
.profile-id {
|
|
94
|
+
.task-id {
|
|
139
95
|
font-size: 6px !important;
|
|
140
96
|
margin-right: -12px;
|
|
141
97
|
margin-top: 20px;
|
|
142
98
|
}
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
// Mobile optimization
|
|
146
|
-
@media (max-width: 768px) {
|
|
147
|
-
.profile-buttons {
|
|
148
|
-
padding: 2px;
|
|
149
|
-
gap: 1px;
|
|
150
|
-
|
|
151
|
-
button {
|
|
152
|
-
width: 22px;
|
|
153
|
-
height: 22px;
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
svg,
|
|
157
|
-
img {
|
|
158
|
-
width: 12px;
|
|
159
|
-
height: 12px;
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
// iPhone vertical (portrait) specific
|
|
165
|
-
@media (max-width: 480px) and (orientation: portrait) {
|
|
166
|
-
.profile-buttons {
|
|
167
|
-
padding: 2px;
|
|
168
|
-
gap: 1px;
|
|
169
|
-
|
|
170
|
-
button {
|
|
171
|
-
width: 18px;
|
|
172
|
-
height: 18px;
|
|
173
|
-
|
|
174
|
-
&:hover {
|
|
175
|
-
transform: scale(1.1);
|
|
176
|
-
}
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
svg,
|
|
180
|
-
img {
|
|
181
|
-
width: 10px;
|
|
182
|
-
height: 10px;
|
|
183
|
-
}
|
|
99
|
+
.task-id-alt {
|
|
100
|
+
font-size: 7px !important;
|
|
184
101
|
}
|
|
185
102
|
}
|
|
186
103
|
</style>
|
|
@@ -190,30 +107,28 @@ import { PlayIcon, TrashIcon, BagWhiteIcon, PauseIcon, EditIcon } from "@/compon
|
|
|
190
107
|
import Checkbox from "@/components/ui/controls/atomic/Checkbox.vue";
|
|
191
108
|
import { useUIStore } from "@/stores/ui";
|
|
192
109
|
import { validateCard } from "@/stores/utils";
|
|
193
|
-
import TagLabel from "@/components/
|
|
110
|
+
import TagLabel from "@/components/editors/TagLabel.vue";
|
|
194
111
|
|
|
195
112
|
const ui = useUIStore();
|
|
196
113
|
|
|
197
114
|
const props = defineProps({
|
|
198
|
-
|
|
115
|
+
task: { type: Object }
|
|
199
116
|
});
|
|
200
117
|
|
|
201
118
|
const getAccountType = () => {
|
|
202
|
-
var cn = props.
|
|
203
|
-
if (cn.startsWith("4"))
|
|
204
|
-
|
|
205
|
-
else if (cn.startsWith("3"))
|
|
206
|
-
return `/img/banks/amex.svg`; // amex
|
|
119
|
+
var cn = props.task.cardNumber;
|
|
120
|
+
if (cn.startsWith("4")) return `/img/banks/visa.svg`; // visa
|
|
121
|
+
else if (cn.startsWith("3")) return `/img/banks/amex.svg`; // amex
|
|
207
122
|
else if (cn.startsWith("5")) return `/img/banks/mastercard.svg`; // master
|
|
208
123
|
};
|
|
209
124
|
|
|
210
125
|
const expDate = () =>
|
|
211
|
-
props.
|
|
212
|
-
const enable = async () => await ui.addProfile({ ...props.
|
|
213
|
-
const disable = async () => await ui.addProfile({ ...props.
|
|
126
|
+
props.task.privacy ? "••/••" : `${props.task.expMonth}/${props.task.expYear?.replace("20", "")}`;
|
|
127
|
+
const enable = async () => await ui.addProfile({ ...props.task, enabled: true });
|
|
128
|
+
const disable = async () => await ui.addProfile({ ...props.task, enabled: false });
|
|
214
129
|
const edit = () => {
|
|
215
|
-
ui.currentlyEditing = props.
|
|
130
|
+
ui.currentlyEditing = props.task;
|
|
216
131
|
ui.toggleModal("create-profile");
|
|
217
132
|
};
|
|
218
|
-
const deleteProfile = async () => await ui.deleteProfile(props.
|
|
133
|
+
const deleteProfile = async () => await ui.deleteProfile(props.task._id);
|
|
219
134
|
</script>
|
|
@@ -1,75 +1,43 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div>
|
|
3
|
-
<div class="dropdown input-default p-4 w-16 bg-dark-550 small-dropdown rounded-lg"
|
|
4
|
-
<span @click="
|
|
3
|
+
<div class="dropdown input-default p-4 w-16 bg-dark-550 small-dropdown rounded-lg">
|
|
4
|
+
<span @click="open = !open" class="flex justify-between items-center z-inf text-white">
|
|
5
5
|
<div class="flex gap-3 justify-center">
|
|
6
6
|
<img class="w-5" :src="`/flags/${current?.toLowerCase()}.svg`" />
|
|
7
7
|
</div>
|
|
8
8
|
</span>
|
|
9
|
-
<
|
|
9
|
+
<div
|
|
10
|
+
v-if="open && !disabled"
|
|
11
|
+
class="dropdown-content special-dropdown snap-mandatory snap-y z-inf max-h-48 overflow-scroll hidden-scrollbars"
|
|
12
|
+
>
|
|
10
13
|
<div
|
|
11
|
-
v-
|
|
12
|
-
|
|
13
|
-
:
|
|
14
|
-
@click
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
v-bind:key="country"
|
|
20
|
-
:class="`cursor-pointer w-12 ${i === 0 ? '' : 'my-2'}`"
|
|
21
|
-
@click="set(country)">
|
|
22
|
-
<div class="flex justify-center items-center smooth-hover">
|
|
23
|
-
<span class="text-sm">{{ country }}</span>
|
|
24
|
-
<img class="w-5 ml-3" :src="`/flags/${country?.toLowerCase()}.svg`" />
|
|
25
|
-
</div>
|
|
14
|
+
v-for="(country, i) in countries"
|
|
15
|
+
v-bind:key="country"
|
|
16
|
+
:class="`cursor-pointer w-12 snap-start ${i === 0 ? '' : 'my-2'}`"
|
|
17
|
+
@click="set(country)"
|
|
18
|
+
>
|
|
19
|
+
<div class="flex gap-3 justify-between smooth-hover">
|
|
20
|
+
<span class="text-sm">{{ country }} </span>
|
|
21
|
+
<img class="w-5" :src="`/flags/${country?.toLowerCase()}.svg`" />
|
|
26
22
|
</div>
|
|
27
23
|
</div>
|
|
28
|
-
</
|
|
24
|
+
</div>
|
|
29
25
|
</div>
|
|
30
26
|
</div>
|
|
31
27
|
</template>
|
|
32
28
|
|
|
33
29
|
<script setup>
|
|
34
30
|
import { ref, watch } from "vue";
|
|
35
|
-
import { useDropdownPosition } from "@/composables/useDropdownPosition";
|
|
36
|
-
import { useClickOutside } from "@/composables/useClickOutside";
|
|
37
|
-
|
|
38
31
|
const countries = ["US", "CA", "DE", "FR", "DK"];
|
|
39
32
|
const open = ref(false);
|
|
40
|
-
const dropdownRef = ref(null);
|
|
41
33
|
|
|
42
34
|
const props = defineProps({
|
|
43
35
|
value: { type: String },
|
|
44
36
|
onClick: { type: Function },
|
|
45
37
|
disabled: { type: Boolean, required: false }
|
|
46
38
|
});
|
|
47
|
-
|
|
48
39
|
const current = ref(props.value || "US");
|
|
49
40
|
|
|
50
|
-
// Use composables for positioning and click outside
|
|
51
|
-
const { menuStyle, updatePosition } = useDropdownPosition(dropdownRef, {
|
|
52
|
-
offset: { x: -17.6, y: 4 },
|
|
53
|
-
minWidth: 80,
|
|
54
|
-
maxHeight: 192,
|
|
55
|
-
zIndex: 99999999999999,
|
|
56
|
-
estimateHeight: () => Math.min(countries.length * 32, 192)
|
|
57
|
-
});
|
|
58
|
-
|
|
59
|
-
useClickOutside(dropdownRef, () => {
|
|
60
|
-
if (open.value) {
|
|
61
|
-
open.value = false;
|
|
62
|
-
}
|
|
63
|
-
});
|
|
64
|
-
|
|
65
|
-
const toggleOpen = () => {
|
|
66
|
-
if (props.disabled) return;
|
|
67
|
-
open.value = !open.value;
|
|
68
|
-
if (open.value) {
|
|
69
|
-
updatePosition();
|
|
70
|
-
}
|
|
71
|
-
};
|
|
72
|
-
|
|
73
41
|
const set = (c) => {
|
|
74
42
|
if (props.disabled) return;
|
|
75
43
|
current.value = c;
|
|
@@ -89,49 +57,19 @@ watch(
|
|
|
89
57
|
}
|
|
90
58
|
|
|
91
59
|
.small-dropdown {
|
|
92
|
-
@apply h-10 !important;
|
|
93
60
|
background-clip: border-box !important;
|
|
94
61
|
/* border-radius: 100% !important; */
|
|
95
62
|
padding: 0;
|
|
96
63
|
width: 3em !important;
|
|
64
|
+
/* height: 3em !important; */
|
|
97
65
|
display: flex;
|
|
98
66
|
justify-items: center;
|
|
99
67
|
justify-content: center;
|
|
100
68
|
}
|
|
101
69
|
|
|
102
|
-
|
|
103
|
-
.
|
|
104
|
-
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
.dropdown-content-portal {
|
|
109
|
-
@apply bg-dark-400 border border-dark-650 rounded-lg shadow-2xl z-50;
|
|
110
|
-
padding: 0.5rem;
|
|
111
|
-
max-height: 192px !important;
|
|
112
|
-
overflow-y: auto !important;
|
|
113
|
-
overscroll-behavior: contain !important;
|
|
114
|
-
touch-action: pan-y !important;
|
|
115
|
-
-webkit-overflow-scrolling: touch !important;
|
|
116
|
-
scrollbar-width: none;
|
|
117
|
-
-ms-overflow-style: none;
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
.dropdown-content-portal::-webkit-scrollbar {
|
|
121
|
-
display: none;
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
.dropdown-content-portal > div {
|
|
125
|
-
@apply px-3 py-2 text-sm text-white cursor-pointer;
|
|
126
|
-
border-radius: 6px;
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
.dropdown-content-portal > div:hover {
|
|
130
|
-
/* Removed hover background */
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
.dropdown-content-portal > div .flex {
|
|
134
|
-
@apply items-center justify-center;
|
|
135
|
-
gap: 0.75rem;
|
|
70
|
+
.dropdown-content {
|
|
71
|
+
left: -1.1rem;
|
|
72
|
+
z-index: 99999999999999;
|
|
136
73
|
}
|
|
137
74
|
</style>
|
|
75
|
+
, watch
|
|
@@ -1,64 +1,64 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<Table>
|
|
3
|
-
<Header class="grid-cols-7
|
|
4
|
-
<div class="col-span-3
|
|
3
|
+
<Header class="text-center grid-cols-7 lg:grid-cols-8">
|
|
4
|
+
<div class="col-span-3 lg:col-span-2 flex">
|
|
5
5
|
<Checkbox
|
|
6
6
|
class="mr-3"
|
|
7
7
|
:toggled="ui.mainCheckbox.profiles"
|
|
8
8
|
@valueUpdate="ui.toggleMainCheckbox('profiles')"
|
|
9
|
-
|
|
9
|
+
/>
|
|
10
10
|
<div class="mx-auto flex items-center" @click="ui.toggleSort('eventId')">
|
|
11
|
-
<
|
|
12
|
-
<h4 class="hidden
|
|
11
|
+
<img src="/img/profile.svg" width="14" class="mr-0 ipadlg:mr-3" />
|
|
12
|
+
<h4 class="hidden ipadlg:flex">Profile Name</h4>
|
|
13
|
+
<!-- <DownIcon v-if="ui.sortData.sortBy === 'eventId'" class="ml-1" /> -->
|
|
13
14
|
</div>
|
|
14
15
|
</div>
|
|
15
|
-
<div class="col-span-1
|
|
16
|
-
<CartIcon class="mr-0
|
|
17
|
-
<h4 class="hidden
|
|
16
|
+
<div class="lg:col-span-2 col-span-1 items-center justify-center flex" v-once>
|
|
17
|
+
<CartIcon class="mr-0 ipadlg:mr-3" />
|
|
18
|
+
<h4 class="hidden ipadlg:flex">Card Number</h4>
|
|
18
19
|
</div>
|
|
19
20
|
<div class="col-span-1 flex items-center justify-center" v-once>
|
|
20
|
-
<TimerIcon class="mr-0
|
|
21
|
-
<h4 class="hidden
|
|
21
|
+
<TimerIcon class="mr-0 ipadlg:mr-3" />
|
|
22
|
+
<h4 class="hidden ipadlg:flex">Exp. Date</h4>
|
|
22
23
|
</div>
|
|
23
24
|
<div class="col-span-1 flex items-center justify-center" v-once>
|
|
24
|
-
<
|
|
25
|
-
<h4 class="hidden
|
|
25
|
+
<img src="/img/controls/enable.svg" width="14" class="mr-0 ipadlg:mr-3" />
|
|
26
|
+
<h4 class="hidden ipadlg:flex">Enabled</h4>
|
|
26
27
|
</div>
|
|
27
|
-
<div class="col-span-1 hidden items-center justify-center
|
|
28
|
-
<TicketIcon class="mr-0
|
|
28
|
+
<div class="col-span-1 hidden lg:flex items-center justify-center" v-once>
|
|
29
|
+
<TicketIcon class="mr-0 lg:mr-3" />
|
|
29
30
|
<h4 class="hidden lg:flex">Tags</h4>
|
|
30
31
|
</div>
|
|
31
32
|
<div class="col-span-1 flex items-center justify-center" v-once>
|
|
32
|
-
<ClickIcon class="mr-0
|
|
33
|
-
<h4 class="hidden
|
|
33
|
+
<ClickIcon class="mr-0 ipadlg:mr-3" />
|
|
34
|
+
<h4 class="hidden ipadlg:flex">Actions</h4>
|
|
34
35
|
</div>
|
|
35
36
|
</Header>
|
|
36
|
-
<div v-if="toRender.length
|
|
37
|
+
<div v-if="toRender.length > 0">
|
|
37
38
|
<RecycleScroller
|
|
38
39
|
:items="toRender"
|
|
39
40
|
:item-size="64"
|
|
40
41
|
key-field="index"
|
|
41
|
-
class="scroller vue-recycle-scroller ready direction-vertical
|
|
42
|
-
|
|
43
|
-
<template #default="props">
|
|
44
|
-
<div class="
|
|
42
|
+
class="scroller max-h-big vue-recycle-scroller ready direction-vertical flex flex-col divide-y-2 divide-border overflow-y-auto hidden-scrollbars overflow-x-hidden stop-pan"
|
|
43
|
+
>
|
|
44
|
+
<template #default="props" :key="i[props.item.idex]">
|
|
45
|
+
<div class="task">
|
|
45
46
|
<Profile
|
|
46
47
|
@click="i[props.item.index]++"
|
|
47
|
-
:class="props.item.index % 2 == 1 ? '
|
|
48
|
-
:
|
|
48
|
+
:class="[props.item.index % 2 == 1 ? 'bg-dark-500' : 'bg-dark-550']"
|
|
49
|
+
:task="props.item"
|
|
50
|
+
/>
|
|
49
51
|
</div>
|
|
50
52
|
</template>
|
|
51
53
|
</RecycleScroller>
|
|
52
54
|
</div>
|
|
53
|
-
<div v-else class="
|
|
54
|
-
|
|
55
|
-
<p class="text-sm text-light-400">No profiles found</p>
|
|
56
|
-
<p class="mt-1 text-xs text-light-500">Create profiles to get started</p>
|
|
55
|
+
<div v-else class="flex justify-center text-light-400 py-2 bg-dark-500 border-b-2 border-border">
|
|
56
|
+
No profiles found
|
|
57
57
|
</div>
|
|
58
58
|
</Table>
|
|
59
59
|
</template>
|
|
60
60
|
<style lang="scss" scoped>
|
|
61
|
-
.
|
|
61
|
+
.task {
|
|
62
62
|
height: 64px;
|
|
63
63
|
}
|
|
64
64
|
h4 {
|
|
@@ -73,82 +73,25 @@ h4 {
|
|
|
73
73
|
max-height: calc(100vh - 20rem);
|
|
74
74
|
overflow: hidden;
|
|
75
75
|
}
|
|
76
|
-
|
|
77
|
-
.empty-state {
|
|
78
|
-
color: #969696;
|
|
79
|
-
font-size: 14px;
|
|
80
|
-
font-weight: 500;
|
|
81
|
-
}
|
|
82
76
|
</style>
|
|
83
77
|
<script setup>
|
|
84
78
|
import { Table, Header } from "@/components/Table";
|
|
85
|
-
import { CartIcon, TicketIcon, ClickIcon, TimerIcon
|
|
79
|
+
import { CartIcon, TicketIcon, ClickIcon, TimerIcon } from "@/components/icons";
|
|
86
80
|
import Profile from "./Profile.vue";
|
|
87
81
|
import Checkbox from "@/components/ui/controls/atomic/Checkbox.vue";
|
|
88
82
|
import { useUIStore } from "@/stores/ui";
|
|
89
|
-
import { computed, ref
|
|
83
|
+
import { computed, ref } from "vue";
|
|
90
84
|
|
|
91
85
|
const props = defineProps({
|
|
92
|
-
|
|
86
|
+
tasks: { type: Object }
|
|
93
87
|
});
|
|
88
|
+
const i = ref({});
|
|
89
|
+
props.tasks.forEach((t) => (i.value[t._id] = 0));
|
|
94
90
|
|
|
95
91
|
const ui = useUIStore();
|
|
96
92
|
|
|
97
|
-
const i = ref({});
|
|
98
93
|
const toRender = computed(() => {
|
|
99
94
|
let c = 0;
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
// Initialize reactive refs for click tracking
|
|
103
|
-
rendered.forEach((t) => {
|
|
104
|
-
if (t.id && !(t.id in i.value)) {
|
|
105
|
-
i.value[t.id] = 0;
|
|
106
|
-
}
|
|
107
|
-
if (!(t.index in i.value)) {
|
|
108
|
-
i.value[t.index] = 0;
|
|
109
|
-
}
|
|
110
|
-
});
|
|
111
|
-
|
|
112
|
-
return rendered;
|
|
113
|
-
});
|
|
114
|
-
|
|
115
|
-
// Dynamic height calculation for perfect item fitting
|
|
116
|
-
const windowHeight = ref(window.innerHeight);
|
|
117
|
-
const windowWidth = ref(window.innerWidth);
|
|
118
|
-
|
|
119
|
-
const updateDimensions = () => {
|
|
120
|
-
windowHeight.value = window.innerHeight;
|
|
121
|
-
windowWidth.value = window.innerWidth;
|
|
122
|
-
};
|
|
123
|
-
|
|
124
|
-
onMounted(() => {
|
|
125
|
-
window.addEventListener("resize", updateDimensions);
|
|
126
|
-
});
|
|
127
|
-
|
|
128
|
-
onUnmounted(() => {
|
|
129
|
-
window.removeEventListener("resize", updateDimensions);
|
|
130
|
-
});
|
|
131
|
-
|
|
132
|
-
const dynamicTableHeight = computed(() => {
|
|
133
|
-
// Calculate available space for profiles table with conservative buffer
|
|
134
|
-
const headerHeight = 60; // Header + navbar
|
|
135
|
-
const titleHeight = 50; // Profiles title and controls
|
|
136
|
-
const searchHeight = 50; // Search and filter controls
|
|
137
|
-
const margins = windowWidth.value >= 1024 ? 40 : 25;
|
|
138
|
-
const bufferSpace = 50; // Conservative buffer to prevent partial items
|
|
139
|
-
|
|
140
|
-
const totalUsedSpace = headerHeight + titleHeight + searchHeight + margins + bufferSpace;
|
|
141
|
-
const availableHeight = windowHeight.value - totalUsedSpace;
|
|
142
|
-
|
|
143
|
-
// Profile row height is always 64px
|
|
144
|
-
const rowHeight = 64;
|
|
145
|
-
const minRowsToShow = 2;
|
|
146
|
-
const minHeight = minRowsToShow * rowHeight;
|
|
147
|
-
|
|
148
|
-
// Calculate exact number of complete rows that fit with conservative approach
|
|
149
|
-
const maxCompleteRows = Math.floor(Math.max(availableHeight, minHeight) / rowHeight);
|
|
150
|
-
const exactHeight = maxCompleteRows * rowHeight;
|
|
151
|
-
|
|
152
|
-
return exactHeight + "px";
|
|
95
|
+
return props.tasks.map((t) => ({ ...t, index: c++ }));
|
|
153
96
|
});
|
|
154
97
|
</script>
|
|
@@ -1,77 +1,16 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<div class="
|
|
3
|
-
<span class="
|
|
2
|
+
<div class="flex rounded-2xl w-fit shadow-3xl items-center justify-center bg-dark-600">
|
|
3
|
+
<span class="font-bold p-2 truncate small">{{ props.text }}</span>
|
|
4
4
|
</div>
|
|
5
5
|
</template>
|
|
6
6
|
|
|
7
|
-
<style
|
|
8
|
-
.
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
border: 1px solid #4b4c53;
|
|
12
|
-
padding: 0.1875rem 0.5rem;
|
|
13
|
-
min-width: 2rem;
|
|
14
|
-
max-width: 4.5rem;
|
|
15
|
-
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2), inset 0 1px 0 rgba(255, 255, 255, 0.05);
|
|
16
|
-
|
|
17
|
-
&:hover {
|
|
18
|
-
background: linear-gradient(145deg, #44454b, #3d3e44);
|
|
19
|
-
border-color: #52535a;
|
|
20
|
-
transform: translateY(-0.5px);
|
|
21
|
-
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.25), inset 0 1px 0 rgba(255, 255, 255, 0.08);
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
.tag-text {
|
|
26
|
-
@apply text-white font-semibold truncate;
|
|
27
|
-
font-size: 0.6875rem;
|
|
28
|
-
line-height: 1.1;
|
|
29
|
-
letter-spacing: 0.025em;
|
|
30
|
-
text-shadow: 0 1px 1px rgba(0, 0, 0, 0.4);
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
// Ultra responsive design
|
|
34
|
-
@media (max-width: 1024px) {
|
|
35
|
-
.tag-pill {
|
|
36
|
-
padding: 0.1rem 0.3rem;
|
|
37
|
-
max-width: 3.5rem;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
.tag-text {
|
|
41
|
-
font-size: 0.575rem;
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
@media (max-width: 768px) {
|
|
46
|
-
.tag-pill {
|
|
47
|
-
padding: 0.075rem 0.25rem;
|
|
48
|
-
max-width: 3rem;
|
|
49
|
-
min-width: 1.25rem;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
.tag-text {
|
|
53
|
-
font-size: 0.55rem;
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
@media (max-width: 480px) {
|
|
58
|
-
.tag-pill {
|
|
59
|
-
padding: 0.05rem 0.2rem;
|
|
60
|
-
max-width: 2.5rem;
|
|
61
|
-
min-width: 1rem;
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
.tag-text {
|
|
65
|
-
font-size: 0.5rem;
|
|
66
|
-
}
|
|
7
|
+
<style scoped>
|
|
8
|
+
.small {
|
|
9
|
+
font-size: 0.6rem;
|
|
10
|
+
line-height: 0.8rem;
|
|
67
11
|
}
|
|
68
12
|
</style>
|
|
69
13
|
|
|
70
14
|
<script setup>
|
|
71
15
|
const props = defineProps({ text: { type: String } });
|
|
72
|
-
|
|
73
|
-
const formatText = (text) => {
|
|
74
|
-
if (!text) return "";
|
|
75
|
-
return text.toUpperCase();
|
|
76
|
-
};
|
|
77
16
|
</script>
|