@necrolab/dashboard 0.4.48 → 0.4.49
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/.claude/settings.local.json +2 -1
- package/exit +209 -0
- package/index.html +1 -1
- package/package.json +1 -1
- package/public/manifest.json +8 -3
- package/src/assets/css/_input.scss +104 -111
- package/src/assets/css/_utilities.scss +441 -0
- package/src/assets/css/main.scss +228 -154
- package/src/components/Auth/LoginForm.vue +8 -8
- package/src/components/Editors/Account/Account.vue +156 -146
- package/src/components/Editors/Account/AccountCreator.vue +1 -1
- package/src/components/Editors/Account/AccountView.vue +13 -13
- package/src/components/Editors/Account/CreateAccount.vue +25 -16
- package/src/components/Editors/Profile/CreateProfile.vue +1 -1
- package/src/components/Editors/Profile/Profile.vue +1 -1
- package/src/components/Editors/Profile/ProfileCountryChooser.vue +83 -19
- package/src/components/Editors/Profile/ProfileView.vue +11 -11
- package/src/components/Tasks/CreateTaskAXS.vue +3 -3
- package/src/components/Tasks/CreateTaskTM.vue +7 -35
- package/src/components/Tasks/QuickSettings.vue +112 -9
- package/src/components/Tasks/Stats.vue +29 -25
- package/src/components/Tasks/Task.vue +489 -365
- package/src/components/Tasks/TaskView.vue +21 -23
- package/src/components/icons/Sandclock.vue +2 -2
- package/src/components/icons/Stadium.vue +1 -1
- package/src/components/ui/Modal.vue +37 -35
- package/src/components/ui/controls/CountryChooser.vue +200 -62
- package/src/components/ui/controls/atomic/Dropdown.vue +177 -91
- package/src/components/ui/controls/atomic/MultiDropdown.vue +247 -168
- package/src/composables/useClickOutside.js +21 -0
- package/src/composables/useDropdownPosition.js +174 -0
- package/src/stores/ui.js +5 -4
- package/src/views/Accounts.vue +2 -2
- package/src/views/Console.vue +25 -45
- package/src/views/Editor.vue +1194 -730
- package/src/views/Profiles.vue +2 -2
- package/src/views/Tasks.vue +170 -137
- package/tailwind.config.js +47 -21
|
@@ -1,164 +1,250 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
2
|
+
<div @click="toggleOpened" class="dropdown" :class="props.variant" ref="dropdownRef">
|
|
3
|
+
<span class="dropdown-display">
|
|
4
|
+
<span class="dropdown-value" :class="capitalize ? 'capitalize' : ''">
|
|
5
|
+
{{ currentValue ? currentValue : props.default }}
|
|
6
|
+
</span>
|
|
7
|
+
<DownIcon class="dropdown-arrow" :class="opened ? 'rotate-180' : ''" />
|
|
8
|
+
</span>
|
|
9
|
+
<Teleport to="body">
|
|
10
|
+
<transition name="dropdown-fade">
|
|
11
|
+
<div
|
|
12
|
+
v-if="opened"
|
|
13
|
+
class="dropdown-menu-portal scrollable"
|
|
14
|
+
:style="menuStyle"
|
|
15
|
+
@click.stop
|
|
16
|
+
@wheel.stop
|
|
17
|
+
@touchmove.stop
|
|
18
|
+
>
|
|
19
|
+
<button
|
|
20
|
+
v-bind:key="f"
|
|
21
|
+
class="dropdown-item"
|
|
22
|
+
:class="i !== 0 ? 'border-t border-dark-650' : ''"
|
|
23
|
+
v-for="(f, i) in !allowDefault ? props.options : ['', ...props.options]"
|
|
24
|
+
@click.stop="chose(f)"
|
|
25
|
+
>
|
|
26
|
+
<span class="dropdown-item-text" :class="capitalize ? 'capitalize' : ''">
|
|
27
|
+
{{ f ? f : props.default }}
|
|
6
28
|
</span>
|
|
7
|
-
<
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
@click.stop
|
|
14
|
-
@wheel.stop
|
|
15
|
-
@touchmove.stop
|
|
16
|
-
>
|
|
17
|
-
<button
|
|
18
|
-
v-bind:key="f"
|
|
19
|
-
class="dropdown-item"
|
|
20
|
-
:class="i !== 0 ? 'border-t border-dark-650' : ''"
|
|
21
|
-
v-for="(f, i) in !allowDefault ? props.options : ['', ...props.options]"
|
|
22
|
-
@click.stop="chose(f)"
|
|
23
|
-
>
|
|
24
|
-
<span class="dropdown-item-text" :class="capitalize ? 'capitalize' : ''">
|
|
25
|
-
{{f ? f : props.default}}
|
|
26
|
-
</span>
|
|
27
|
-
<CheckmarkIcon v-if="(f || props.default) === currentValue" class="ml-2" />
|
|
28
|
-
</button>
|
|
29
|
-
</div>
|
|
30
|
-
</transition>
|
|
31
|
-
</div>
|
|
29
|
+
<CheckmarkIcon v-if="(f || props.default) === currentValue" class="ml-2" />
|
|
30
|
+
</button>
|
|
31
|
+
</div>
|
|
32
|
+
</transition>
|
|
33
|
+
</Teleport>
|
|
34
|
+
</div>
|
|
32
35
|
</template>
|
|
33
36
|
|
|
34
37
|
<script setup>
|
|
35
38
|
import { ref, computed, watch } from "vue";
|
|
36
39
|
import { DownIcon, CheckmarkIcon } from "@/components/icons";
|
|
37
40
|
import { useUIStore } from "@/stores/ui";
|
|
41
|
+
import { useDropdownPosition } from "@/composables/useDropdownPosition";
|
|
42
|
+
import { useClickOutside } from "@/composables/useClickOutside";
|
|
43
|
+
|
|
38
44
|
const ui = useUIStore();
|
|
39
45
|
|
|
40
46
|
const props = defineProps({
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
47
|
+
onClick: { type: Function },
|
|
48
|
+
default: { type: String },
|
|
49
|
+
value: { type: String },
|
|
50
|
+
options: { type: Object },
|
|
51
|
+
allowDefault: { type: Boolean },
|
|
52
|
+
rightAmount: { type: String },
|
|
53
|
+
topPadding: { type: String },
|
|
54
|
+
capitalize: { type: Boolean },
|
|
55
|
+
includeAdjacentButtons: { type: Boolean, default: false },
|
|
56
|
+
variant: { type: String, default: 'default' }
|
|
49
57
|
});
|
|
50
58
|
|
|
51
59
|
const currentValue = ref(props.value);
|
|
60
|
+
const dropdownRef = ref(null);
|
|
52
61
|
|
|
53
62
|
// Watch for changes to the value prop and update currentValue
|
|
54
|
-
watch(
|
|
63
|
+
watch(
|
|
64
|
+
() => props.value,
|
|
65
|
+
(newValue) => {
|
|
55
66
|
currentValue.value = newValue;
|
|
56
|
-
}
|
|
67
|
+
}
|
|
68
|
+
);
|
|
69
|
+
|
|
57
70
|
const id = Math.random();
|
|
58
71
|
const opened = computed(() => ui.currentDropdown === id);
|
|
59
72
|
|
|
73
|
+
// Use composables for positioning and click outside
|
|
74
|
+
const { menuStyle, updatePosition } = useDropdownPosition(dropdownRef, {
|
|
75
|
+
maxHeight: 200,
|
|
76
|
+
includeAdjacentButtons: props.includeAdjacentButtons,
|
|
77
|
+
estimateHeight: () => {
|
|
78
|
+
const optionsCount = !props.allowDefault
|
|
79
|
+
? props.options?.length || 0
|
|
80
|
+
: (props.options?.length || 0) + 1;
|
|
81
|
+
return Math.min(optionsCount * 44, 200);
|
|
82
|
+
},
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
useClickOutside(dropdownRef, () => {
|
|
86
|
+
if (opened.value) {
|
|
87
|
+
ui.setCurrentDropdown("");
|
|
88
|
+
}
|
|
89
|
+
});
|
|
90
|
+
|
|
60
91
|
const toggleOpened = () => {
|
|
61
|
-
|
|
62
|
-
|
|
92
|
+
if (opened.value) {
|
|
93
|
+
ui.setCurrentDropdown("");
|
|
94
|
+
} else {
|
|
95
|
+
ui.setCurrentDropdown(id);
|
|
96
|
+
updatePosition();
|
|
97
|
+
}
|
|
63
98
|
};
|
|
64
99
|
|
|
65
100
|
const chose = (f) => {
|
|
66
|
-
|
|
67
|
-
|
|
101
|
+
ui.logger.Info("Dropdown: chosen", f, "hiding...");
|
|
102
|
+
currentValue.value = f;
|
|
103
|
+
ui.setCurrentDropdown("");
|
|
104
|
+
if (props.onClick) props.onClick(f);
|
|
105
|
+
// Ensure dropdown closes
|
|
106
|
+
setTimeout(() => {
|
|
68
107
|
ui.setCurrentDropdown("");
|
|
69
|
-
|
|
70
|
-
// Ensure dropdown closes
|
|
71
|
-
setTimeout(() => {
|
|
72
|
-
ui.setCurrentDropdown("");
|
|
73
|
-
}, 50);
|
|
108
|
+
}, 50);
|
|
74
109
|
};
|
|
75
|
-
|
|
76
110
|
</script>
|
|
77
111
|
|
|
78
112
|
<style scoped>
|
|
79
113
|
.dropdown {
|
|
80
|
-
|
|
114
|
+
@apply relative w-full text-white ml-auto rounded-lg ring-0;
|
|
115
|
+
background: linear-gradient(135deg, #2a2b30 0%, #2e2f34 100%);
|
|
116
|
+
border: 1px solid #3d3e44;
|
|
117
|
+
padding: 0.75rem;
|
|
118
|
+
height: 3.45em;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
.dropdown.transparent {
|
|
122
|
+
background: transparent !important;
|
|
123
|
+
border: none !important;
|
|
124
|
+
box-shadow: none !important;
|
|
125
|
+
padding: 0 !important;
|
|
126
|
+
height: 40px !important;
|
|
81
127
|
}
|
|
82
128
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
129
|
+
.dropdown.transparent:hover,
|
|
130
|
+
.dropdown.transparent:focus-within {
|
|
131
|
+
border: none !important;
|
|
132
|
+
background: transparent !important;
|
|
133
|
+
box-shadow: none !important;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
.dropdown:not(.transparent):hover {
|
|
137
|
+
@apply border-dark-400;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
.dropdown:not(.transparent):focus-within {
|
|
141
|
+
@apply border-blue-500;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
@media (min-width: 768px) {
|
|
145
|
+
.dropdown {
|
|
146
|
+
height: 40px;
|
|
147
|
+
padding: 0.625rem;
|
|
148
|
+
}
|
|
87
149
|
}
|
|
88
150
|
|
|
89
151
|
.dropdown-display {
|
|
90
|
-
|
|
152
|
+
@apply flex items-center justify-between z-10 w-full h-full;
|
|
91
153
|
}
|
|
92
154
|
|
|
93
155
|
.dropdown-value {
|
|
94
|
-
|
|
156
|
+
@apply overflow-hidden truncate min-w-0 flex-1 mr-2 text-sm;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
@media (min-width: 768px) {
|
|
160
|
+
.dropdown-value {
|
|
161
|
+
font-size: 12px;
|
|
162
|
+
}
|
|
95
163
|
}
|
|
96
164
|
|
|
97
165
|
.dropdown-arrow {
|
|
98
|
-
|
|
166
|
+
@apply w-4 h-4 transition-all duration-300 flex-shrink-0;
|
|
99
167
|
}
|
|
100
168
|
|
|
101
|
-
.dropdown-menu {
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
169
|
+
.dropdown-menu-portal {
|
|
170
|
+
@apply rounded-xl shadow-2xl overflow-hidden;
|
|
171
|
+
background: linear-gradient(135deg, #2a2b30 0%, #2e2f34 100%);
|
|
172
|
+
border: 1px solid #3d3e44;
|
|
173
|
+
backdrop-filter: blur(12px);
|
|
174
|
+
box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.4), 0 10px 10px -5px rgba(0, 0, 0, 0.2),
|
|
175
|
+
0 0 0 1px rgba(255, 255, 255, 0.05);
|
|
176
|
+
overflow-y: auto !important;
|
|
177
|
+
overscroll-behavior: contain !important;
|
|
178
|
+
touch-action: pan-y !important;
|
|
179
|
+
-webkit-overflow-scrolling: touch !important;
|
|
180
|
+
scrollbar-width: none;
|
|
181
|
+
-ms-overflow-style: none;
|
|
114
182
|
}
|
|
115
183
|
|
|
116
|
-
.dropdown-menu::-webkit-scrollbar {
|
|
117
|
-
|
|
184
|
+
.dropdown-menu-portal::-webkit-scrollbar {
|
|
185
|
+
display: none;
|
|
118
186
|
}
|
|
119
187
|
|
|
120
|
-
.dropdown-
|
|
121
|
-
|
|
188
|
+
.dropdown-item {
|
|
189
|
+
@apply cursor-pointer text-left w-full text-white transition-all duration-200 flex items-center justify-between;
|
|
190
|
+
padding: 0.75rem 1rem;
|
|
191
|
+
font-size: 0.875rem;
|
|
192
|
+
font-weight: 500;
|
|
193
|
+
border-bottom: 1px solid rgba(61, 62, 68, 0.3);
|
|
122
194
|
}
|
|
123
195
|
|
|
124
|
-
.dropdown-
|
|
125
|
-
|
|
126
|
-
border-radius: 4px;
|
|
196
|
+
.dropdown-item:last-child {
|
|
197
|
+
border-bottom: none;
|
|
127
198
|
}
|
|
128
199
|
|
|
129
|
-
.dropdown-
|
|
130
|
-
|
|
200
|
+
.dropdown-item:hover {
|
|
201
|
+
@apply bg-dark-600;
|
|
202
|
+
color: #ffffff;
|
|
131
203
|
}
|
|
132
204
|
|
|
133
|
-
.dropdown-item {
|
|
134
|
-
|
|
205
|
+
.dropdown-item:active {
|
|
206
|
+
@apply bg-dark-650;
|
|
207
|
+
box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.4);
|
|
135
208
|
}
|
|
136
209
|
|
|
137
210
|
.dropdown-item:first-child {
|
|
138
|
-
|
|
211
|
+
@apply rounded-t-xl;
|
|
139
212
|
}
|
|
140
213
|
|
|
141
214
|
.dropdown-item:last-child {
|
|
142
|
-
|
|
215
|
+
@apply rounded-b-xl;
|
|
143
216
|
}
|
|
144
217
|
|
|
145
218
|
.dropdown-item-text {
|
|
146
|
-
|
|
219
|
+
@apply overflow-hidden truncate pr-2;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
.dropdown-item svg {
|
|
223
|
+
@apply w-4 h-4;
|
|
224
|
+
color: #10b981;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
.dropdown-fade-enter-active {
|
|
228
|
+
@apply transition-all duration-300;
|
|
147
229
|
}
|
|
148
230
|
|
|
149
|
-
/* Transition animations */
|
|
150
|
-
.dropdown-fade-enter-active,
|
|
151
231
|
.dropdown-fade-leave-active {
|
|
152
|
-
|
|
232
|
+
@apply transition-all duration-200;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
.dropdown-fade-enter-from {
|
|
236
|
+
@apply opacity-0;
|
|
237
|
+
transform: translateY(-8px) scale(0.95);
|
|
153
238
|
}
|
|
154
239
|
|
|
155
|
-
.dropdown-fade-enter-from,
|
|
156
240
|
.dropdown-fade-leave-to {
|
|
157
|
-
|
|
241
|
+
@apply opacity-0;
|
|
242
|
+
transform: translateY(-4px) scale(0.98);
|
|
158
243
|
}
|
|
159
244
|
|
|
160
245
|
.dropdown-fade-enter-to,
|
|
161
246
|
.dropdown-fade-leave-from {
|
|
162
|
-
|
|
247
|
+
@apply opacity-100;
|
|
248
|
+
transform: translateY(0) scale(1);
|
|
163
249
|
}
|
|
164
|
-
</style>
|
|
250
|
+
</style>
|