@necrolab/dashboard 0.5.12 → 0.5.13
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/.playwright-mcp/verification-accounts-desktop.png +0 -0
- package/.playwright-mcp/verification-tasks-desktop.png +0 -0
- package/.playwright-mcp/verification-tasks-mobile.png +0 -0
- package/README.md +21 -0
- package/docs/plans/2026-02-08-tailwind-consolidation-results.md +476 -0
- package/docs/plans/2026-02-08-tailwind-consolidation.md +2416 -0
- package/package.json +1 -1
- package/src/App.vue +2 -163
- package/src/assets/css/components/buttons.scss +43 -95
- package/src/assets/css/components/forms.scss +10 -28
- package/src/assets/css/components/search-groups.scss +80 -0
- package/src/assets/css/components/tables.scss +0 -8
- package/src/assets/css/main.scss +2 -43
- package/src/components/Editors/Account/Account.vue +14 -220
- package/src/components/Editors/Account/AccountCreator.vue +0 -4
- package/src/components/Editors/Account/AccountView.vue +0 -1
- package/src/components/Editors/Account/CreateAccount.vue +36 -107
- package/src/components/Editors/Profile/CreateProfile.vue +46 -135
- package/src/components/Editors/Profile/Profile.vue +10 -213
- package/src/components/Editors/Profile/ProfileView.vue +0 -1
- package/src/components/Filter/Filter.vue +14 -17
- package/src/components/Filter/FilterPreview.vue +0 -6
- package/src/components/Table/Row.vue +1 -1
- package/src/components/Table/Table.vue +2 -16
- package/src/components/Tasks/CreateTaskAXS.vue +45 -104
- package/src/components/Tasks/CreateTaskTM.vue +58 -96
- package/src/components/Tasks/Task.vue +22 -209
- package/src/components/Tasks/TaskView.vue +5 -4
- package/src/components/Tasks/ViewTask.vue +201 -214
- package/src/components/icons/Copy.vue +6 -0
- package/src/components/icons/index.js +3 -1
- package/src/components/ui/ActionButtonGroup.vue +70 -0
- package/src/components/ui/FormField.vue +74 -0
- package/src/components/ui/InfoRow.vue +98 -0
- package/src/components/ui/Modal.vue +6 -47
- package/src/components/ui/Navbar.vue +15 -43
- package/src/components/ui/ReconnectIndicator.vue +4 -4
- package/src/components/ui/SectionCard.vue +24 -0
- package/src/components/ui/Splash.vue +1 -6
- package/src/components/ui/StatusBadge.vue +37 -0
- package/src/components/ui/controls/CountryChooser.vue +14 -58
- package/src/components/ui/controls/atomic/Dropdown.vue +16 -24
- package/src/components/ui/controls/atomic/MultiDropdown.vue +7 -1
- package/src/components/ui/controls/atomic/Switch.vue +13 -29
- package/src/composables/useCopyToClipboard.js +25 -0
- package/src/composables/useRowSelection.js +48 -0
- package/src/views/Accounts.vue +0 -81
- package/src/views/Console.vue +4 -21
- package/src/views/Editor.vue +48 -138
- package/src/views/FilterBuilder.vue +0 -23
- package/src/views/Login.vue +14 -63
- package/src/views/Profiles.vue +0 -82
- package/src/views/Tasks.vue +3 -24
- package/tailwind.config.js +47 -5
|
@@ -9,13 +9,13 @@
|
|
|
9
9
|
<div>
|
|
10
10
|
<div class="my-3 grid grid-cols-12 gap-3">
|
|
11
11
|
<!-- Profile tag -->
|
|
12
|
-
<div class="input-wrapper
|
|
12
|
+
<div class="input-wrapper col-span-4">
|
|
13
13
|
<label class="label-override mb-2">
|
|
14
14
|
Profile Tag
|
|
15
15
|
<TagIcon />
|
|
16
16
|
</label>
|
|
17
17
|
<Dropdown
|
|
18
|
-
:class="`input-default dropdown w-full
|
|
18
|
+
:class="`input-default dropdown w-full`"
|
|
19
19
|
:default="ui.profile.tags[0]"
|
|
20
20
|
:options="ui.profile.tags"
|
|
21
21
|
:onClick="(f) => (profile.tag = f)"
|
|
@@ -23,22 +23,16 @@
|
|
|
23
23
|
</div>
|
|
24
24
|
|
|
25
25
|
<!-- Card Number -->
|
|
26
|
-
<
|
|
27
|
-
<
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
maxlength="23"
|
|
37
|
-
inputmode="numeric"
|
|
38
|
-
@input="handleCreditCardUpdate"
|
|
39
|
-
@focus="formatCardNumberDisplay" />
|
|
40
|
-
</div>
|
|
41
|
-
</div>
|
|
26
|
+
<FormField label="Card Number" :icon="CartIcon" :error="errors.includes('cardNumber')" z-index="0" class="col-span-8">
|
|
27
|
+
<input
|
|
28
|
+
ref="cardNumberInput"
|
|
29
|
+
placeholder="Enter card number"
|
|
30
|
+
v-model="displayCardNumber"
|
|
31
|
+
maxlength="23"
|
|
32
|
+
inputmode="numeric"
|
|
33
|
+
@input="handleCreditCardUpdate"
|
|
34
|
+
@focus="formatCardNumberDisplay" />
|
|
35
|
+
</FormField>
|
|
42
36
|
|
|
43
37
|
<!-- Country chooser -->
|
|
44
38
|
<div class="input-wrapper col-span-2">
|
|
@@ -55,7 +49,7 @@
|
|
|
55
49
|
|
|
56
50
|
<!-- Exp Year -->
|
|
57
51
|
<div class="input-wrapper col-span-5">
|
|
58
|
-
<label class="label-override
|
|
52
|
+
<label class="label-override mb-2">
|
|
59
53
|
Expiry Year
|
|
60
54
|
<TimerIcon />
|
|
61
55
|
</label>
|
|
@@ -74,7 +68,7 @@
|
|
|
74
68
|
</div>
|
|
75
69
|
|
|
76
70
|
<!-- Exp Month -->
|
|
77
|
-
<div class="input-wrapper
|
|
71
|
+
<div class="input-wrapper col-span-5">
|
|
78
72
|
<label class="label-override mb-2">
|
|
79
73
|
Expiry Month
|
|
80
74
|
<TimerIcon />
|
|
@@ -88,40 +82,28 @@
|
|
|
88
82
|
</div>
|
|
89
83
|
|
|
90
84
|
<!-- CVV -->
|
|
91
|
-
<
|
|
92
|
-
<
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
max="9999"
|
|
101
|
-
maxlength="4"
|
|
102
|
-
minlength="3"
|
|
103
|
-
v-model="profile.cvv" />
|
|
104
|
-
</div>
|
|
105
|
-
</div>
|
|
85
|
+
<FormField label="CVV" :icon="ShieldIcon" :error="errors.includes('cvv')" z-index="0" class="col-span-6 md:col-span-4">
|
|
86
|
+
<input
|
|
87
|
+
placeholder="183"
|
|
88
|
+
min="100"
|
|
89
|
+
max="9999"
|
|
90
|
+
maxlength="4"
|
|
91
|
+
minlength="3"
|
|
92
|
+
v-model="profile.cvv" />
|
|
93
|
+
</FormField>
|
|
106
94
|
|
|
107
95
|
<!-- City -->
|
|
108
|
-
<
|
|
109
|
-
<
|
|
110
|
-
|
|
111
|
-
<StadiumIcon />
|
|
112
|
-
</label>
|
|
113
|
-
<div :class="`input-default ${errors.includes('city') ? 'error' : ''}`">
|
|
114
|
-
<input placeholder="Denver" v-model="profile.city" />
|
|
115
|
-
</div>
|
|
116
|
-
</div>
|
|
96
|
+
<FormField label="City" :icon="StadiumIcon" :error="errors.includes('city')" z-index="0" class="col-span-6 md:col-span-4">
|
|
97
|
+
<input placeholder="Denver" v-model="profile.city" />
|
|
98
|
+
</FormField>
|
|
117
99
|
|
|
118
100
|
<!-- State -->
|
|
119
|
-
<div class="input-wrapper
|
|
101
|
+
<div class="input-wrapper col-span-6 md:col-span-4">
|
|
120
102
|
<label class="label-override mb-2">
|
|
121
103
|
State
|
|
122
104
|
<SandclockIcon />
|
|
123
105
|
</label>
|
|
124
|
-
<div v-if="profile.country === 'US'"
|
|
106
|
+
<div v-if="profile.country === 'US'">
|
|
125
107
|
<Dropdown
|
|
126
108
|
class="input-default w-full"
|
|
127
109
|
default="Select State"
|
|
@@ -131,32 +113,20 @@
|
|
|
131
113
|
rightAmount="right-2"
|
|
132
114
|
:value="profile.state" />
|
|
133
115
|
</div>
|
|
134
|
-
<div v-else
|
|
116
|
+
<div v-else class="input-default">
|
|
135
117
|
<input disabled placeholder="N/A" value="" />
|
|
136
118
|
</div>
|
|
137
119
|
</div>
|
|
138
120
|
|
|
139
121
|
<!-- Zip -->
|
|
140
|
-
<
|
|
141
|
-
<
|
|
142
|
-
|
|
143
|
-
<KeyIcon />
|
|
144
|
-
</label>
|
|
145
|
-
<div :class="`input-default ${errors.includes('zipCode') ? 'error' : ''}`">
|
|
146
|
-
<input placeholder="10005" type="number" min="1" max="12" v-model="profile.zipCode" />
|
|
147
|
-
</div>
|
|
148
|
-
</div>
|
|
122
|
+
<FormField label="Zip" :icon="KeyIcon" :error="errors.includes('zipCode')" z-index="0" class="col-span-6 md:col-span-4">
|
|
123
|
+
<input placeholder="10005" type="number" min="1" max="12" v-model="profile.zipCode" />
|
|
124
|
+
</FormField>
|
|
149
125
|
|
|
150
126
|
<!-- Address -->
|
|
151
|
-
<
|
|
152
|
-
<
|
|
153
|
-
|
|
154
|
-
<HandIcon />
|
|
155
|
-
</label>
|
|
156
|
-
<div :class="`input-default ${errors.includes('address') ? 'error' : ''}`">
|
|
157
|
-
<input placeholder="100 5th Avenue" v-model="profile.address" />
|
|
158
|
-
</div>
|
|
159
|
-
</div>
|
|
127
|
+
<FormField label="Address" :icon="HandIcon" :error="errors.includes('address')" z-index="0" class="col-span-6 md:col-span-4">
|
|
128
|
+
<input placeholder="100 5th Avenue" v-model="profile.address" />
|
|
129
|
+
</FormField>
|
|
160
130
|
|
|
161
131
|
<!-- Generate -->
|
|
162
132
|
<div class="input-wrapper z-0 col-span-6 md:col-span-4">
|
|
@@ -199,12 +169,7 @@
|
|
|
199
169
|
<div class="col-span-6">
|
|
200
170
|
<label class="label-override mb-2">Status</label>
|
|
201
171
|
<div class="flex items-center gap-3 h-10">
|
|
202
|
-
<
|
|
203
|
-
<CheckmarkIcon />
|
|
204
|
-
</div>
|
|
205
|
-
<div v-else class="disabled-badge-large">
|
|
206
|
-
<CloseXIcon />
|
|
207
|
-
</div>
|
|
172
|
+
<StatusBadge :enabled="ui.currentlyEditing.enabled" size="large" />
|
|
208
173
|
<span class="text-sm font-medium" :class="ui.currentlyEditing.enabled ? 'text-green-400' : 'text-red-400'">
|
|
209
174
|
{{ ui.currentlyEditing.enabled ? 'Enabled' : 'Disabled' }}
|
|
210
175
|
</span>
|
|
@@ -222,75 +187,22 @@
|
|
|
222
187
|
</Modal>
|
|
223
188
|
</template>
|
|
224
189
|
<style lang="scss" scoped>
|
|
225
|
-
.
|
|
226
|
-
@apply flex items-center
|
|
227
|
-
|
|
228
|
-
border: 1.5px solid oklch(0.72 0.15 145);
|
|
229
|
-
width: 26px;
|
|
230
|
-
height: 26px;
|
|
231
|
-
padding: 0;
|
|
232
|
-
|
|
233
|
-
svg {
|
|
234
|
-
color: oklch(0.72 0.15 145) !important;
|
|
235
|
-
width: 14px !important;
|
|
236
|
-
height: auto !important;
|
|
237
|
-
max-height: 14px !important;
|
|
238
|
-
display: block;
|
|
239
|
-
margin: 0;
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
svg path {
|
|
243
|
-
stroke: oklch(0.72 0.15 145) !important;
|
|
244
|
-
fill: oklch(0.72 0.15 145) !important;
|
|
245
|
-
}
|
|
246
|
-
}
|
|
247
|
-
|
|
248
|
-
.disabled-badge-large {
|
|
249
|
-
@apply flex items-center justify-center rounded-full;
|
|
250
|
-
background: oklch(0.60 0.20 25 / 0.12);
|
|
251
|
-
border: 1.5px solid oklch(0.60 0.20 25);
|
|
252
|
-
width: 26px;
|
|
253
|
-
height: 26px;
|
|
254
|
-
padding: 0;
|
|
255
|
-
color: oklch(0.60 0.20 25) !important;
|
|
190
|
+
.label-override {
|
|
191
|
+
@apply flex items-center;
|
|
192
|
+
color: #e1e1e4 !important;
|
|
256
193
|
|
|
257
194
|
svg {
|
|
258
|
-
|
|
259
|
-
width: 14px !important;
|
|
260
|
-
height: 14px !important;
|
|
261
|
-
display: block;
|
|
262
|
-
margin: 0;
|
|
263
|
-
fill: oklch(0.60 0.20 25) !important;
|
|
264
|
-
}
|
|
265
|
-
|
|
266
|
-
svg path {
|
|
267
|
-
stroke: oklch(0.60 0.20 25) !important;
|
|
268
|
-
fill: oklch(0.60 0.20 25) !important;
|
|
269
|
-
}
|
|
270
|
-
}
|
|
195
|
+
@apply ml-2;
|
|
271
196
|
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
197
|
+
path {
|
|
198
|
+
fill: #e1e1e4 !important;
|
|
199
|
+
}
|
|
275
200
|
}
|
|
276
201
|
}
|
|
277
|
-
.z-0 {
|
|
278
|
-
z-index: 0 !important;
|
|
279
|
-
}
|
|
280
|
-
.z-1 {
|
|
281
|
-
z-index: 1 !important;
|
|
282
|
-
}
|
|
283
|
-
.z-2 {
|
|
284
|
-
z-index: 2 !important;
|
|
285
|
-
}
|
|
286
|
-
|
|
287
|
-
.error {
|
|
288
|
-
border-width: 2px !important;
|
|
289
|
-
border-color: rgb(238 130 130) !important;
|
|
290
|
-
}
|
|
291
202
|
</style>
|
|
292
203
|
<script setup>
|
|
293
204
|
import Modal from "@/components/ui/Modal.vue";
|
|
205
|
+
import FormField from "@/components/ui/FormField.vue";
|
|
294
206
|
import {
|
|
295
207
|
MailIcon,
|
|
296
208
|
CartIcon,
|
|
@@ -302,11 +214,10 @@ import {
|
|
|
302
214
|
SandclockIcon,
|
|
303
215
|
TimerIcon,
|
|
304
216
|
TagIcon,
|
|
305
|
-
WildcardIcon
|
|
306
|
-
CheckmarkIcon,
|
|
307
|
-
CloseXIcon
|
|
217
|
+
WildcardIcon
|
|
308
218
|
} from "@/components/icons";
|
|
309
219
|
import { EditIcon } from "@/components/icons";
|
|
220
|
+
import StatusBadge from "@/components/ui/StatusBadge.vue";
|
|
310
221
|
import TagLabel from "@/components/Editors/TagLabel.vue";
|
|
311
222
|
import ProfileCountryChooser from "@/components/Editors/Profile/ProfileCountryChooser.vue";
|
|
312
223
|
import { useUIStore } from "@/stores/ui";
|
|
@@ -32,13 +32,8 @@
|
|
|
32
32
|
<div class="col-span-1">
|
|
33
33
|
<h4 class="text-white">{{ expDate() }}</h4>
|
|
34
34
|
</div>
|
|
35
|
-
<div class="col-span-1">
|
|
36
|
-
<
|
|
37
|
-
<CheckmarkIcon class="w-3.5 h-3.5" />
|
|
38
|
-
</div>
|
|
39
|
-
<div v-else class="disabled-badge">
|
|
40
|
-
<CloseXIcon class="w-3.5 h-3.5" />
|
|
41
|
-
</div>
|
|
35
|
+
<div class="col-span-1 flex justify-center">
|
|
36
|
+
<StatusBadge :enabled="props.profile.enabled" size="small" />
|
|
42
37
|
</div>
|
|
43
38
|
|
|
44
39
|
<div class="col-span-1 hidden lg:block">
|
|
@@ -48,7 +43,7 @@
|
|
|
48
43
|
</div>
|
|
49
44
|
|
|
50
45
|
<div class="col-span-1 flex">
|
|
51
|
-
<
|
|
46
|
+
<ActionButtonGroup>
|
|
52
47
|
<li>
|
|
53
48
|
<button @click="edit">
|
|
54
49
|
<EditIcon />
|
|
@@ -67,192 +62,25 @@
|
|
|
67
62
|
<li>
|
|
68
63
|
<button @click="deleteProfile"><TrashIcon /></button>
|
|
69
64
|
</li>
|
|
70
|
-
</
|
|
65
|
+
</ActionButtonGroup>
|
|
71
66
|
</div>
|
|
72
67
|
</Row>
|
|
73
68
|
</template>
|
|
74
69
|
<style lang="scss" scoped>
|
|
75
|
-
.enabled-badge {
|
|
76
|
-
@apply flex items-center justify-center mx-auto rounded-full;
|
|
77
|
-
background: oklch(0.72 0.15 145 / 0.12);
|
|
78
|
-
border: 1.5px solid oklch(0.72 0.15 145);
|
|
79
|
-
width: 24px;
|
|
80
|
-
height: 24px;
|
|
81
|
-
padding: 0;
|
|
82
|
-
|
|
83
|
-
svg {
|
|
84
|
-
color: oklch(0.72 0.15 145) !important;
|
|
85
|
-
width: 12px !important;
|
|
86
|
-
height: auto !important;
|
|
87
|
-
max-height: 12px !important;
|
|
88
|
-
display: block;
|
|
89
|
-
margin: 0;
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
svg path {
|
|
93
|
-
stroke: oklch(0.72 0.15 145) !important;
|
|
94
|
-
fill: oklch(0.72 0.15 145) !important;
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
.disabled-badge {
|
|
99
|
-
@apply flex items-center justify-center mx-auto rounded-full;
|
|
100
|
-
background: oklch(0.60 0.20 25 / 0.12);
|
|
101
|
-
border: 1.5px solid oklch(0.60 0.20 25);
|
|
102
|
-
width: 24px;
|
|
103
|
-
height: 24px;
|
|
104
|
-
padding: 0;
|
|
105
|
-
color: oklch(0.60 0.20 25) !important;
|
|
106
|
-
|
|
107
|
-
svg {
|
|
108
|
-
color: oklch(0.60 0.20 25) !important;
|
|
109
|
-
width: 12px !important;
|
|
110
|
-
height: 12px !important;
|
|
111
|
-
display: block;
|
|
112
|
-
margin: 0;
|
|
113
|
-
fill: oklch(0.60 0.20 25) !important;
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
svg path {
|
|
117
|
-
stroke: oklch(0.60 0.20 25) !important;
|
|
118
|
-
fill: oklch(0.60 0.20 25) !important;
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
|
|
122
70
|
h4 {
|
|
123
71
|
@apply text-center;
|
|
124
72
|
}
|
|
125
|
-
.profile-buttons {
|
|
126
|
-
@apply mx-auto flex items-center justify-center rounded;
|
|
127
|
-
background: oklch(0.2046 0 0);
|
|
128
|
-
border: 2px solid oklch(0.2809 0 0);
|
|
129
|
-
padding: 3px;
|
|
130
|
-
gap: 2px;
|
|
131
|
-
flex-shrink: 0;
|
|
132
|
-
overflow: visible;
|
|
133
|
-
|
|
134
|
-
button {
|
|
135
|
-
@apply relative flex items-center justify-center rounded border-0 outline-0 transition-all duration-150;
|
|
136
|
-
background: transparent;
|
|
137
|
-
width: 28px;
|
|
138
|
-
height: 28px;
|
|
139
|
-
color: oklch(0.90 0 0);
|
|
140
|
-
border-radius: 6px;
|
|
141
|
-
|
|
142
|
-
&:hover {
|
|
143
|
-
background: oklch(0.72 0.15 145 / 0.15);
|
|
144
|
-
color: oklch(1 0 0);
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
&:active {
|
|
148
|
-
background: oklch(0.72 0.15 145 / 0.25);
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
svg,
|
|
153
|
-
img {
|
|
154
|
-
width: 16px;
|
|
155
|
-
height: 16px;
|
|
156
|
-
position: relative;
|
|
157
|
-
z-index: 1;
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
svg path {
|
|
161
|
-
fill: currentColor;
|
|
162
|
-
}
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
// Tablet sizing - medium buttons
|
|
166
|
-
@media (min-width: 768px) and (max-width: 1023px) {
|
|
167
|
-
.profile-buttons {
|
|
168
|
-
padding: 2px;
|
|
169
|
-
gap: 1px;
|
|
170
|
-
border-radius: 6px;
|
|
171
|
-
|
|
172
|
-
button {
|
|
173
|
-
width: 26px;
|
|
174
|
-
height: 26px;
|
|
175
|
-
border-radius: 5px;
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
svg,
|
|
179
|
-
img {
|
|
180
|
-
width: 14px;
|
|
181
|
-
height: 14px;
|
|
182
|
-
}
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
// Desktop sizing - large buttons
|
|
187
|
-
@media (min-width: 1024px) {
|
|
188
|
-
.profile-buttons {
|
|
189
|
-
padding: 3px;
|
|
190
|
-
gap: 2px;
|
|
191
|
-
border-radius: 8px;
|
|
192
|
-
|
|
193
|
-
button {
|
|
194
|
-
width: 28px;
|
|
195
|
-
height: 28px;
|
|
196
|
-
border-radius: 6px;
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
svg,
|
|
200
|
-
img {
|
|
201
|
-
width: 16px;
|
|
202
|
-
height: 16px;
|
|
203
|
-
}
|
|
204
|
-
}
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
// Mobile specific styling
|
|
208
|
-
@media (max-width: 640px) {
|
|
209
|
-
.profile-buttons {
|
|
210
|
-
padding: 1px;
|
|
211
|
-
gap: 1px;
|
|
212
|
-
border-radius: 4px;
|
|
213
|
-
border: 2px solid oklch(0.2809 0 0) !important;
|
|
214
|
-
max-width: 100%;
|
|
215
|
-
min-height: 28px;
|
|
216
|
-
height: auto;
|
|
217
|
-
flex-wrap: wrap;
|
|
218
|
-
justify-content: center;
|
|
219
|
-
align-items: center;
|
|
220
|
-
background: oklch(0.2046 0 0);
|
|
221
|
-
|
|
222
|
-
button {
|
|
223
|
-
width: 20px;
|
|
224
|
-
height: 20px;
|
|
225
|
-
border-radius: 3px;
|
|
226
|
-
min-width: 20px;
|
|
227
|
-
border: none !important;
|
|
228
|
-
flex-shrink: 0;
|
|
229
|
-
margin: 0.5px;
|
|
230
|
-
background: transparent;
|
|
231
|
-
|
|
232
|
-
&:hover {
|
|
233
|
-
background: oklch(0.72 0.15 145 / 0.15);
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
&:active {
|
|
237
|
-
background: oklch(0.72 0.15 145 / 0.25);
|
|
238
|
-
}
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
svg,
|
|
242
|
-
img {
|
|
243
|
-
width: 12px;
|
|
244
|
-
height: 12px;
|
|
245
|
-
}
|
|
246
|
-
}
|
|
247
|
-
}
|
|
248
73
|
</style>
|
|
249
74
|
<script setup>
|
|
250
75
|
import { Row } from "@/components/Table";
|
|
251
|
-
import { PlayIcon, TrashIcon, BagWhiteIcon, PauseIcon, EditIcon
|
|
76
|
+
import { PlayIcon, TrashIcon, BagWhiteIcon, PauseIcon, EditIcon } from "@/components/icons";
|
|
252
77
|
import Checkbox from "@/components/ui/controls/atomic/Checkbox.vue";
|
|
78
|
+
import StatusBadge from "@/components/ui/StatusBadge.vue";
|
|
79
|
+
import ActionButtonGroup from "@/components/ui/ActionButtonGroup.vue";
|
|
253
80
|
import { useUIStore } from "@/stores/ui";
|
|
254
81
|
import { validateCard } from "@/stores/utils";
|
|
255
82
|
import TagLabel from "@/components/Editors/TagLabel.vue";
|
|
83
|
+
import { useRowSelection } from "@/composables/useRowSelection";
|
|
256
84
|
|
|
257
85
|
const ui = useUIStore();
|
|
258
86
|
|
|
@@ -280,38 +108,7 @@ const edit = () => {
|
|
|
280
108
|
const deleteProfile = async () => await ui.deleteProfile(props.profile.id);
|
|
281
109
|
|
|
282
110
|
// Double-click/tap selection
|
|
283
|
-
|
|
284
|
-
const DOUBLE_TAP_DELAY = 300; // ms
|
|
285
|
-
|
|
286
|
-
const handleDoubleClick = (event) => {
|
|
287
|
-
// Prevent if clicking on buttons or checkbox
|
|
288
|
-
if (event.target.closest('button') || event.target.closest('.checkbox')) {
|
|
289
|
-
return;
|
|
290
|
-
}
|
|
111
|
+
const { handleDoubleClick, handleTouchStart, handleTouchEnd } = useRowSelection(() => {
|
|
291
112
|
ui.toggleProfileSelected(props.profile.id);
|
|
292
|
-
};
|
|
293
|
-
|
|
294
|
-
const handleTouchStart = (event) => {
|
|
295
|
-
// Store touch time for double-tap detection
|
|
296
|
-
const currentTime = Date.now();
|
|
297
|
-
const tapGap = currentTime - lastTapTime;
|
|
298
|
-
|
|
299
|
-
if (tapGap < DOUBLE_TAP_DELAY && tapGap > 0) {
|
|
300
|
-
// Double-tap detected
|
|
301
|
-
if (!event.target.closest('button') && !event.target.closest('.checkbox')) {
|
|
302
|
-
event.preventDefault(); // Prevent zoom
|
|
303
|
-
ui.toggleProfileSelected(props.profile.id);
|
|
304
|
-
}
|
|
305
|
-
}
|
|
306
|
-
|
|
307
|
-
lastTapTime = currentTime;
|
|
308
|
-
};
|
|
309
|
-
|
|
310
|
-
const handleTouchEnd = (event) => {
|
|
311
|
-
// Prevent default to avoid potential zoom issues
|
|
312
|
-
// but only if not interacting with buttons/checkbox
|
|
313
|
-
if (event.target.closest('button') || event.target.closest('.checkbox')) {
|
|
314
|
-
return;
|
|
315
|
-
}
|
|
316
|
-
};
|
|
113
|
+
});
|
|
317
114
|
</script>
|
|
@@ -289,22 +289,22 @@ props.filterBuilder.onUpdate(() => {
|
|
|
289
289
|
<style scoped>
|
|
290
290
|
.filter-card {
|
|
291
291
|
@apply bg-dark-500 border-dark-550 relative;
|
|
292
|
-
border
|
|
292
|
+
@apply border-dark-625/30;
|
|
293
|
+
border-width: 1px;
|
|
293
294
|
margin-bottom: 8px;
|
|
294
295
|
transition: all 0.15s ease-out;
|
|
295
296
|
}
|
|
296
297
|
|
|
297
298
|
.filter-card:hover:not(.expanded-filter) {
|
|
298
|
-
border-
|
|
299
|
-
background-color: rgba(46, 47, 52, 0.8);
|
|
299
|
+
@apply border-dark-625/60 bg-dark-475/80;
|
|
300
300
|
}
|
|
301
301
|
|
|
302
302
|
.expanded-filter:hover {
|
|
303
|
-
border-
|
|
303
|
+
@apply border-dark-625/80;
|
|
304
304
|
}
|
|
305
305
|
|
|
306
306
|
.filter-card + .filter-card {
|
|
307
|
-
border-
|
|
307
|
+
@apply border-t border-t-dark-625/20;
|
|
308
308
|
}
|
|
309
309
|
|
|
310
310
|
.filter-type-badge {
|
|
@@ -333,24 +333,23 @@ props.filterBuilder.onUpdate(() => {
|
|
|
333
333
|
|
|
334
334
|
.filter-input {
|
|
335
335
|
@apply border border-dark-550 rounded px-2 py-1.5 text-sm text-white focus:outline-none transition-colors;
|
|
336
|
-
|
|
337
|
-
color: white;
|
|
336
|
+
@apply bg-dark-450/90;
|
|
338
337
|
}
|
|
339
338
|
|
|
340
339
|
.filter-input:focus {
|
|
341
340
|
border-color: oklch(0.28 0 0);
|
|
342
|
-
|
|
341
|
+
@apply bg-dark-475/90;
|
|
343
342
|
}
|
|
344
343
|
|
|
345
344
|
.filter-input::placeholder {
|
|
346
|
-
|
|
345
|
+
@apply text-light-400;
|
|
347
346
|
}
|
|
348
347
|
|
|
349
348
|
.filter-action-btn {
|
|
350
349
|
@apply flex items-center justify-center rounded-full transition-all duration-200 border-2 border-transparent;
|
|
351
350
|
width: 28px;
|
|
352
351
|
height: 28px;
|
|
353
|
-
|
|
352
|
+
@apply text-light-400;
|
|
354
353
|
background-color: rgba(35, 36, 41, 0.8);
|
|
355
354
|
backdrop-filter: blur(4px);
|
|
356
355
|
}
|
|
@@ -369,25 +368,23 @@ props.filterBuilder.onUpdate(() => {
|
|
|
369
368
|
}
|
|
370
369
|
|
|
371
370
|
.drag-btn:hover {
|
|
372
|
-
|
|
371
|
+
@apply bg-dark-675/80;
|
|
373
372
|
border-color: oklch(0.28 0 0);
|
|
374
373
|
}
|
|
375
374
|
|
|
376
375
|
.delete-btn:hover {
|
|
377
|
-
|
|
378
|
-
border-color: #F87171;
|
|
379
|
-
color: #F87171;
|
|
376
|
+
@apply bg-error-500/80 border-error-400 text-error-400;
|
|
380
377
|
}
|
|
381
378
|
|
|
382
379
|
.drag-handle.sortable-chosen {
|
|
383
380
|
border: 1px solid oklch(0.28 0 0);
|
|
384
|
-
|
|
381
|
+
@apply bg-dark-675/20;
|
|
385
382
|
}
|
|
386
383
|
|
|
387
384
|
.filter-card.sortable-ghost {
|
|
388
385
|
@apply opacity-50;
|
|
389
386
|
border: 1px solid oklch(0.28 0 0);
|
|
390
|
-
|
|
387
|
+
@apply bg-dark-675/10;
|
|
391
388
|
}
|
|
392
389
|
|
|
393
390
|
.filter-card.sortable-drag {
|
|
@@ -412,7 +409,7 @@ props.filterBuilder.onUpdate(() => {
|
|
|
412
409
|
}
|
|
413
410
|
|
|
414
411
|
.excluded-filter {
|
|
415
|
-
border-
|
|
412
|
+
@apply border-l-4 border-l-error-300;
|
|
416
413
|
}
|
|
417
414
|
|
|
418
415
|
.normal-filter {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<div class="px-2 md:px-4 text-xs grid text-white py-4 items-center h-full hover:bg-dark-500 transition-colors">
|
|
2
|
+
<div class="px-2 md:px-4 text-xs grid text-white py-4 items-center min-h-full hover:bg-dark-500 transition-colors">
|
|
3
3
|
<slot />
|
|
4
4
|
</div>
|
|
5
5
|
</template>
|