@necrolab/dashboard 0.5.12 → 0.5.14
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 +100 -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
|
@@ -120,27 +120,18 @@ const chose = (f) => {
|
|
|
120
120
|
|
|
121
121
|
<style scoped>
|
|
122
122
|
.dropdown {
|
|
123
|
-
@apply relative w-full text-white ml-auto rounded-lg ring-0 h-10;
|
|
124
|
-
background: linear-gradient(135deg, oklch(0.18 0 0) 0%, oklch(0.20 0 0) 100%);
|
|
125
|
-
border: 1px solid oklch(0.26 0 0);
|
|
123
|
+
@apply relative w-full text-white ml-auto rounded-lg ring-0 h-10 bg-dark-300 border border-dark-600;
|
|
126
124
|
padding: 0.75rem;
|
|
127
125
|
}
|
|
128
126
|
|
|
129
127
|
.dropdown.transparent {
|
|
130
|
-
|
|
131
|
-
border: none !important;
|
|
132
|
-
box-shadow: none !important;
|
|
133
|
-
padding: 0 !important;
|
|
134
|
-
height: 40px !important;
|
|
128
|
+
@apply bg-transparent border-0 shadow-none p-0 h-10;
|
|
135
129
|
}
|
|
136
130
|
|
|
137
131
|
.dropdown.transparent:hover,
|
|
138
132
|
.dropdown.transparent:focus-within,
|
|
139
133
|
.dropdown.transparent.opened {
|
|
140
|
-
border
|
|
141
|
-
background: transparent !important;
|
|
142
|
-
box-shadow: none !important;
|
|
143
|
-
outline: none !important;
|
|
134
|
+
@apply border-0 bg-transparent shadow-none outline-none;
|
|
144
135
|
}
|
|
145
136
|
|
|
146
137
|
.dropdown:not(.transparent):hover {
|
|
@@ -149,14 +140,13 @@ const chose = (f) => {
|
|
|
149
140
|
|
|
150
141
|
.dropdown:not(.transparent):focus-within,
|
|
151
142
|
.dropdown:not(.transparent).opened {
|
|
152
|
-
border-
|
|
153
|
-
outline: 1px solid oklch(0.72 0.15 145) !important;
|
|
143
|
+
@apply border-border-focus outline outline-1 outline-border-focus;
|
|
154
144
|
outline-offset: 0;
|
|
155
145
|
}
|
|
156
146
|
|
|
157
147
|
@media (min-width: 768px) {
|
|
158
148
|
.dropdown {
|
|
159
|
-
|
|
149
|
+
@apply h-10;
|
|
160
150
|
padding: 0.625rem;
|
|
161
151
|
}
|
|
162
152
|
}
|
|
@@ -176,21 +166,23 @@ const chose = (f) => {
|
|
|
176
166
|
}
|
|
177
167
|
|
|
178
168
|
.dropdown-arrow {
|
|
179
|
-
@apply w-4 h-4 transition-all duration-300
|
|
169
|
+
@apply w-4 h-4 transition-all duration-300;
|
|
170
|
+
position: absolute;
|
|
171
|
+
right: 0.75rem;
|
|
172
|
+
top: 50%;
|
|
173
|
+
transform: translateY(-50%);
|
|
174
|
+
display: flex;
|
|
175
|
+
align-items: center;
|
|
176
|
+
justify-content: center;
|
|
180
177
|
}
|
|
181
178
|
|
|
182
179
|
.dropdown-menu-portal {
|
|
183
|
-
@apply rounded-xl shadow-2xl;
|
|
184
|
-
background: linear-gradient(135deg, oklch(0.18 0 0) 0%, oklch(0.20 0 0) 100%);
|
|
185
|
-
border: 1px solid oklch(0.26 0 0);
|
|
180
|
+
@apply rounded-xl shadow-2xl bg-dark-300 border border-dark-600 overflow-x-auto overflow-y-auto touch-pan-x touch-pan-y;
|
|
186
181
|
backdrop-filter: blur(12px);
|
|
187
182
|
box-shadow: 0 20px 25px -5px oklch(0 0 0 / 0.4), 0 10px 10px -5px oklch(0 0 0 / 0.2),
|
|
188
183
|
0 0 0 1px oklch(1 0 0 / 0.05);
|
|
189
|
-
|
|
190
|
-
overflow-
|
|
191
|
-
overscroll-behavior: contain !important;
|
|
192
|
-
touch-action: pan-x pan-y !important;
|
|
193
|
-
-webkit-overflow-scrolling: touch !important;
|
|
184
|
+
overscroll-behavior: contain;
|
|
185
|
+
-webkit-overflow-scrolling: touch;
|
|
194
186
|
scrollbar-width: thin;
|
|
195
187
|
scrollbar-color: oklch(0.35 0 0) oklch(0.19 0 0);
|
|
196
188
|
z-index: 1000;
|
|
@@ -225,7 +225,10 @@ if (props.default && !selectedOptions.value.includes(props.default)) {
|
|
|
225
225
|
}
|
|
226
226
|
|
|
227
227
|
.dropdown-counter {
|
|
228
|
-
@apply flex items-center gap-2 absolute
|
|
228
|
+
@apply flex items-center gap-2 absolute;
|
|
229
|
+
right: 0.75rem;
|
|
230
|
+
top: 50%;
|
|
231
|
+
transform: translateY(-50%);
|
|
229
232
|
}
|
|
230
233
|
|
|
231
234
|
.counter-badge {
|
|
@@ -235,6 +238,9 @@ if (props.default && !selectedOptions.value.includes(props.default)) {
|
|
|
235
238
|
|
|
236
239
|
.dropdown-arrow {
|
|
237
240
|
@apply min-w-4 min-h-4 transition-all duration-300;
|
|
241
|
+
display: flex;
|
|
242
|
+
align-items: center;
|
|
243
|
+
justify-content: center;
|
|
238
244
|
}
|
|
239
245
|
|
|
240
246
|
.dropdown-menu-portal {
|
|
@@ -18,39 +18,29 @@ const props = defineProps({
|
|
|
18
18
|
<style lang="scss" scoped>
|
|
19
19
|
/* iOS-style switch */
|
|
20
20
|
.switch {
|
|
21
|
-
|
|
22
|
-
display: inline-block;
|
|
21
|
+
@apply relative inline-block;
|
|
23
22
|
width: 51px;
|
|
24
23
|
height: 31px;
|
|
25
24
|
}
|
|
26
25
|
|
|
27
26
|
/* Hide default HTML checkbox */
|
|
28
27
|
.switch input {
|
|
29
|
-
opacity
|
|
30
|
-
width: 0;
|
|
31
|
-
height: 0;
|
|
28
|
+
@apply opacity-0 w-0 h-0;
|
|
32
29
|
}
|
|
33
30
|
|
|
34
31
|
/* The slider */
|
|
35
32
|
.slider {
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
top: 0;
|
|
39
|
-
left: 0;
|
|
40
|
-
right: 0;
|
|
41
|
-
bottom: 0;
|
|
33
|
+
@apply absolute cursor-pointer inset-0;
|
|
34
|
+
@apply border-2;
|
|
42
35
|
background-color: oklch(0.26 0 0);
|
|
43
|
-
border:
|
|
36
|
+
border-color: oklch(0.35 0 0);
|
|
44
37
|
transition: 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
|
45
38
|
}
|
|
46
39
|
|
|
47
40
|
.slider:before {
|
|
48
|
-
|
|
41
|
+
@apply absolute;
|
|
42
|
+
@apply w-[23px] h-[23px] left-0.5 bottom-0.5;
|
|
49
43
|
content: "";
|
|
50
|
-
height: 23px;
|
|
51
|
-
width: 23px;
|
|
52
|
-
left: 2px;
|
|
53
|
-
bottom: 2px;
|
|
54
44
|
background-color: oklch(0.50 0 0);
|
|
55
45
|
transition: 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
|
56
46
|
box-shadow: 0 1px 3px oklch(0 0 0 / 0.3);
|
|
@@ -70,16 +60,15 @@ input:checked + .slider:before {
|
|
|
70
60
|
}
|
|
71
61
|
|
|
72
62
|
.switch.disabled {
|
|
73
|
-
pointer-events
|
|
63
|
+
@apply pointer-events-none;
|
|
74
64
|
}
|
|
75
65
|
|
|
76
66
|
input:disabled + .slider {
|
|
77
|
-
opacity
|
|
78
|
-
cursor: not-allowed;
|
|
67
|
+
@apply opacity-50 cursor-not-allowed;
|
|
79
68
|
}
|
|
80
69
|
|
|
81
70
|
input:disabled + .slider:before {
|
|
82
|
-
opacity
|
|
71
|
+
@apply opacity-70;
|
|
83
72
|
}
|
|
84
73
|
|
|
85
74
|
/* Rounded sliders */
|
|
@@ -93,20 +82,15 @@ input:disabled + .slider:before {
|
|
|
93
82
|
|
|
94
83
|
@media (max-width: 810px) {
|
|
95
84
|
.switch {
|
|
96
|
-
|
|
97
|
-
min-width: 44px;
|
|
98
|
-
height: 26px;
|
|
85
|
+
@apply w-11 min-w-11 h-[26px];
|
|
99
86
|
|
|
100
87
|
.slider:before {
|
|
101
|
-
|
|
102
|
-
height: 22px;
|
|
103
|
-
left: 2px;
|
|
104
|
-
bottom: 2px;
|
|
88
|
+
@apply w-[22px] h-[22px] left-0.5 bottom-0.5;
|
|
105
89
|
}
|
|
106
90
|
}
|
|
107
91
|
|
|
108
92
|
input:checked + .slider:before {
|
|
109
|
-
|
|
93
|
+
@apply translate-x-[18px];
|
|
110
94
|
}
|
|
111
95
|
}
|
|
112
96
|
</style>
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { useUIStore } from '@/stores/ui'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* useCopyToClipboard - Composable for copying text with user feedback
|
|
5
|
+
*
|
|
6
|
+
* @returns {Object} Copy function with success notification
|
|
7
|
+
*/
|
|
8
|
+
export function useCopyToClipboard() {
|
|
9
|
+
const ui = useUIStore()
|
|
10
|
+
|
|
11
|
+
const copy = (text, message = 'Copied to clipboard') => {
|
|
12
|
+
if (!text) return
|
|
13
|
+
|
|
14
|
+
navigator.clipboard.writeText(text)
|
|
15
|
+
.then(() => {
|
|
16
|
+
ui.showSuccess(message)
|
|
17
|
+
})
|
|
18
|
+
.catch((err) => {
|
|
19
|
+
ui.showError('Failed to copy')
|
|
20
|
+
console.error('Copy failed:', err)
|
|
21
|
+
})
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
return { copy }
|
|
25
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* useRowSelection - Composable for handling row selection via double-click/tap
|
|
3
|
+
*
|
|
4
|
+
* Provides consistent double-click and double-tap behavior for table rows.
|
|
5
|
+
* Prevents selection when clicking on buttons or checkboxes.
|
|
6
|
+
*
|
|
7
|
+
* @param {Function} toggleCallback - Function to call when row is double-clicked/tapped
|
|
8
|
+
* @returns {Object} Event handlers for @dblclick, @touchstart, @touchend
|
|
9
|
+
*/
|
|
10
|
+
export function useRowSelection(toggleCallback) {
|
|
11
|
+
let lastTapTime = 0
|
|
12
|
+
const DOUBLE_TAP_DELAY = 300
|
|
13
|
+
|
|
14
|
+
const handleDoubleClick = (event) => {
|
|
15
|
+
// Don't trigger on button or checkbox clicks
|
|
16
|
+
if (event.target.closest('button') || event.target.closest('.checkbox')) {
|
|
17
|
+
return
|
|
18
|
+
}
|
|
19
|
+
toggleCallback()
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const handleTouchStart = (event) => {
|
|
23
|
+
const currentTime = Date.now()
|
|
24
|
+
const tapGap = currentTime - lastTapTime
|
|
25
|
+
|
|
26
|
+
if (tapGap < DOUBLE_TAP_DELAY && tapGap > 0) {
|
|
27
|
+
// Don't trigger on button or checkbox taps
|
|
28
|
+
if (!event.target.closest('button') && !event.target.closest('.checkbox')) {
|
|
29
|
+
event.preventDefault()
|
|
30
|
+
toggleCallback()
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
lastTapTime = currentTime
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const handleTouchEnd = (event) => {
|
|
37
|
+
// Prevent default touch behavior on buttons/checkboxes
|
|
38
|
+
if (event.target.closest('button') || event.target.closest('.checkbox')) {
|
|
39
|
+
return
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
return {
|
|
44
|
+
handleDoubleClick,
|
|
45
|
+
handleTouchStart,
|
|
46
|
+
handleTouchEnd
|
|
47
|
+
}
|
|
48
|
+
}
|
package/src/views/Accounts.vue
CHANGED
|
@@ -94,12 +94,6 @@
|
|
|
94
94
|
</div>
|
|
95
95
|
</template>
|
|
96
96
|
<style lang="scss" scoped>
|
|
97
|
-
.custom-dropdown-content {
|
|
98
|
-
top: 2.6rem !important;
|
|
99
|
-
left: -13px;
|
|
100
|
-
@apply border border-dark-650;
|
|
101
|
-
}
|
|
102
|
-
|
|
103
97
|
/* Page buttons styling - match Tasks page */
|
|
104
98
|
button.bg-dark-400 {
|
|
105
99
|
&:active,
|
|
@@ -110,81 +104,6 @@ button.bg-dark-400 {
|
|
|
110
104
|
}
|
|
111
105
|
}
|
|
112
106
|
|
|
113
|
-
/* Unified search component group */
|
|
114
|
-
.unified-search-group {
|
|
115
|
-
border: 2px solid oklch(0.2809 0 0);
|
|
116
|
-
border-radius: 0.5rem;
|
|
117
|
-
overflow: hidden;
|
|
118
|
-
background: oklch(0.2603 0 0);
|
|
119
|
-
transition: all 0.15s ease;
|
|
120
|
-
display: flex;
|
|
121
|
-
|
|
122
|
-
:deep(.tag-toggle),
|
|
123
|
-
:deep(.dropdown),
|
|
124
|
-
input {
|
|
125
|
-
border: none !important;
|
|
126
|
-
border-width: 0 !important;
|
|
127
|
-
border-radius: 0 !important;
|
|
128
|
-
height: 40px !important;
|
|
129
|
-
background: transparent !important;
|
|
130
|
-
box-shadow: none !important;
|
|
131
|
-
min-width: fit-content !important;
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
:deep(.tag-toggle) {
|
|
135
|
-
padding: 0;
|
|
136
|
-
border: 0 solid transparent !important;
|
|
137
|
-
border-top: 0 !important;
|
|
138
|
-
border-bottom: 0 !important;
|
|
139
|
-
border-left: 0 !important;
|
|
140
|
-
border-right: 0 !important;
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
:deep(.tag-toggle button) {
|
|
144
|
-
font-size: 0.875rem;
|
|
145
|
-
padding: 0.5rem 0.75rem;
|
|
146
|
-
min-width: fit-content;
|
|
147
|
-
border: 0 solid transparent !important;
|
|
148
|
-
border-top: 0 !important;
|
|
149
|
-
border-bottom: 0 !important;
|
|
150
|
-
border-left: 0 !important;
|
|
151
|
-
border-right: 0 !important;
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
:deep(.dropdown) {
|
|
155
|
-
width: 120px !important;
|
|
156
|
-
min-width: 120px !important;
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
:deep(.dropdown-display) {
|
|
160
|
-
padding: 0 0.75rem;
|
|
161
|
-
font-size: 0.875rem;
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
input {
|
|
165
|
-
padding-left: 0.75rem;
|
|
166
|
-
padding-right: 0.75rem;
|
|
167
|
-
flex: 1;
|
|
168
|
-
|
|
169
|
-
&::placeholder {
|
|
170
|
-
color: oklch(0.50 0 0);
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
&:focus {
|
|
174
|
-
outline: none !important;
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
&:hover {
|
|
179
|
-
border-color: oklch(0.30 0 0);
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
&:focus-within {
|
|
183
|
-
border-color: oklch(0.72 0.15 145);
|
|
184
|
-
outline: 1px solid oklch(0.72 0.15 145);
|
|
185
|
-
outline-offset: 0;
|
|
186
|
-
}
|
|
187
|
-
}
|
|
188
107
|
.max-h-big-acc {
|
|
189
108
|
max-height: calc(100vh - 14rem);
|
|
190
109
|
overflow: auto;
|
package/src/views/Console.vue
CHANGED
|
@@ -139,31 +139,25 @@
|
|
|
139
139
|
</template>
|
|
140
140
|
<style lang="scss" scoped>
|
|
141
141
|
.console-page {
|
|
142
|
-
|
|
143
|
-
@media (max-width: 768px) {
|
|
144
|
-
padding-bottom: 4rem;
|
|
145
|
-
margin-bottom: 2rem;
|
|
146
|
-
}
|
|
142
|
+
@apply pb-16 mb-8 md:pb-0 md:mb-0;
|
|
147
143
|
|
|
148
144
|
@media (max-width: 480px) and (orientation: portrait) {
|
|
149
|
-
|
|
150
|
-
margin-bottom: 3rem;
|
|
145
|
+
@apply pb-24 mb-12;
|
|
151
146
|
}
|
|
152
147
|
}
|
|
153
148
|
|
|
154
149
|
.console-switches {
|
|
155
150
|
@media (max-width: 480px) and (orientation: portrait) {
|
|
156
|
-
|
|
157
|
-
margin-bottom: 4rem !important;
|
|
151
|
+
@apply mt-6 mb-16;
|
|
158
152
|
}
|
|
159
153
|
}
|
|
160
154
|
|
|
161
155
|
.console {
|
|
162
156
|
@apply relative rounded border-2 border-dark-550 bg-dark-400 p-2 lg:p-5;
|
|
157
|
+
@apply touch-pan-x touch-pan-y;
|
|
163
158
|
height: calc(100vh - 18rem);
|
|
164
159
|
scrollbar-width: thin;
|
|
165
160
|
scrollbar-color: oklch(0.35 0 0) oklch(0.19 0 0);
|
|
166
|
-
touch-action: pan-x pan-y !important;
|
|
167
161
|
-webkit-overflow-scrolling: touch;
|
|
168
162
|
|
|
169
163
|
// Use fixed height on mobile portrait to ensure switches are visible
|
|
@@ -293,17 +287,6 @@
|
|
|
293
287
|
}
|
|
294
288
|
}
|
|
295
289
|
|
|
296
|
-
.text-xxs {
|
|
297
|
-
font-size: 0.5rem;
|
|
298
|
-
line-height: 0.8rem;
|
|
299
|
-
}
|
|
300
|
-
|
|
301
|
-
.header-wrapper {
|
|
302
|
-
svg {
|
|
303
|
-
width: 30px;
|
|
304
|
-
height: 30px;
|
|
305
|
-
}
|
|
306
|
-
}
|
|
307
290
|
/* Console-specific styles handled by utilities */
|
|
308
291
|
</style>
|
|
309
292
|
<script setup>
|