@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
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="input-wrapper" :class="{ 'relative-positioned': zIndex, [`z-${zIndex}`]: zIndex }">
|
|
3
|
+
<slot name="label">
|
|
4
|
+
<label v-if="label" class="label-override mb-2">
|
|
5
|
+
{{ label }}
|
|
6
|
+
<component v-if="icon" :is="icon" />
|
|
7
|
+
</label>
|
|
8
|
+
</slot>
|
|
9
|
+
<div :class="`input-default ${required ? 'required' : ''} ${error ? 'error' : ''}`">
|
|
10
|
+
<slot />
|
|
11
|
+
<div v-if="incrementer" class="input-incrementer">
|
|
12
|
+
<button @click="$emit('increment')" type="button">
|
|
13
|
+
<UpIcon />
|
|
14
|
+
</button>
|
|
15
|
+
<button @click="$emit('decrement')" type="button">
|
|
16
|
+
<DownIcon />
|
|
17
|
+
</button>
|
|
18
|
+
</div>
|
|
19
|
+
</div>
|
|
20
|
+
</div>
|
|
21
|
+
</template>
|
|
22
|
+
|
|
23
|
+
<script setup>
|
|
24
|
+
import { UpIcon, DownIcon } from '@/components/icons';
|
|
25
|
+
|
|
26
|
+
defineProps({
|
|
27
|
+
label: { type: String, default: '' },
|
|
28
|
+
icon: { type: Object, default: null },
|
|
29
|
+
required: { type: Boolean, default: false },
|
|
30
|
+
error: { type: Boolean, default: false },
|
|
31
|
+
incrementer: { type: Boolean, default: false },
|
|
32
|
+
zIndex: { type: String, default: '' }
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
defineEmits(['increment', 'decrement']);
|
|
36
|
+
</script>
|
|
37
|
+
|
|
38
|
+
<style lang="scss" scoped>
|
|
39
|
+
.input-wrapper {
|
|
40
|
+
label {
|
|
41
|
+
@apply flex items-center;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
.relative-positioned {
|
|
46
|
+
@apply relative;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
.z-0 {
|
|
50
|
+
z-index: 0;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
.z-1 {
|
|
54
|
+
z-index: 1;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
.z-2 {
|
|
58
|
+
z-index: 2;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
.z-dropdown {
|
|
62
|
+
z-index: 100;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
.z-tooltip {
|
|
66
|
+
z-index: 2000;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
.error {
|
|
70
|
+
@apply border-2 border-error-300;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// Incrementer styles handled by forms.scss
|
|
74
|
+
</style>
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div
|
|
3
|
+
class="info-row"
|
|
4
|
+
:class="{ 'items-start': alignStart, [customClass]: customClass }">
|
|
5
|
+
<component v-if="icon" :is="icon" class="info-icon" :class="{ 'flex-shrink-0': alignStart }" />
|
|
6
|
+
<span v-if="iconText" class="info-icon flex items-center justify-center text-base font-bold" :class="{ 'flex-shrink-0': alignStart }">
|
|
7
|
+
{{ iconText }}
|
|
8
|
+
</span>
|
|
9
|
+
<span class="info-label" :class="{ 'flex-shrink-0': alignStart }">{{ label }}</span>
|
|
10
|
+
<span class="info-value" :class="valueClass">
|
|
11
|
+
<slot>{{ value }}</slot>
|
|
12
|
+
</span>
|
|
13
|
+
<button
|
|
14
|
+
v-if="copyable"
|
|
15
|
+
@click="handleCopy"
|
|
16
|
+
class="copy-button"
|
|
17
|
+
:class="{ 'copied': showCopied }">
|
|
18
|
+
<component :is="showCopied ? CheckIcon : CopyIcon" class="w-4 h-4" />
|
|
19
|
+
</button>
|
|
20
|
+
<slot name="action" />
|
|
21
|
+
</div>
|
|
22
|
+
</template>
|
|
23
|
+
|
|
24
|
+
<script setup>
|
|
25
|
+
import { ref } from 'vue';
|
|
26
|
+
import { CopyIcon, CheckIcon } from '@/components/icons';
|
|
27
|
+
|
|
28
|
+
const props = defineProps({
|
|
29
|
+
icon: { type: Object, default: null },
|
|
30
|
+
iconText: { type: String, default: '' },
|
|
31
|
+
label: { type: String, required: true },
|
|
32
|
+
value: { type: String, default: '' },
|
|
33
|
+
copyable: { type: Boolean, default: false },
|
|
34
|
+
copyValue: { type: String, default: '' },
|
|
35
|
+
copyMessage: { type: String, default: 'Copied' },
|
|
36
|
+
customClass: { type: String, default: '' },
|
|
37
|
+
valueClass: { type: String, default: '' },
|
|
38
|
+
alignStart: { type: Boolean, default: false }
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
const showCopied = ref(false);
|
|
42
|
+
|
|
43
|
+
const handleCopy = () => {
|
|
44
|
+
const textToCopy = props.copyValue || props.value;
|
|
45
|
+
navigator.clipboard.writeText(textToCopy);
|
|
46
|
+
|
|
47
|
+
// Show checkmark for 2 seconds
|
|
48
|
+
showCopied.value = true;
|
|
49
|
+
setTimeout(() => {
|
|
50
|
+
showCopied.value = false;
|
|
51
|
+
}, 2000);
|
|
52
|
+
};
|
|
53
|
+
</script>
|
|
54
|
+
|
|
55
|
+
<style lang="scss" scoped>
|
|
56
|
+
.info-row {
|
|
57
|
+
@apply flex items-center gap-3 px-3 py-2 rounded-lg;
|
|
58
|
+
@apply bg-dark-500 border border-dark-600;
|
|
59
|
+
@apply min-h-10;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
.info-icon {
|
|
63
|
+
@apply w-4 h-4 flex-shrink-0 text-light-300;
|
|
64
|
+
|
|
65
|
+
svg {
|
|
66
|
+
@apply text-light-300 w-4 h-4;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
.info-label {
|
|
71
|
+
@apply text-xs font-medium flex-shrink-0 text-light-500;
|
|
72
|
+
@apply min-w-[100px];
|
|
73
|
+
|
|
74
|
+
@media (max-width: 768px) {
|
|
75
|
+
@apply min-w-20 text-[11px];
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
.info-value {
|
|
80
|
+
@apply text-sm flex-1 text-light-300;
|
|
81
|
+
@apply break-words overflow-hidden;
|
|
82
|
+
min-width: 0; // Allow flex item to shrink below content size
|
|
83
|
+
|
|
84
|
+
@media (max-width: 768px) {
|
|
85
|
+
@apply text-[13px];
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
.copy-button {
|
|
90
|
+
@apply flex items-center justify-center;
|
|
91
|
+
@apply w-8 h-8 rounded transition-all duration-150;
|
|
92
|
+
@apply bg-transparent text-light-500 hover:text-light-300 hover:bg-dark-600;
|
|
93
|
+
@apply flex-shrink-0;
|
|
94
|
+
@apply ml-2; // Ensure spacing from value
|
|
95
|
+
|
|
96
|
+
&.copied {
|
|
97
|
+
@apply text-accent-green;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
</style>
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<div class="modal-mask scrollable overflow-y-auto" role="dialog" @touchmove.stop>
|
|
3
|
-
<div class="component-modal" ref="target">
|
|
2
|
+
<div class="modal-mask fixed inset-0 z-modal bg-overlay-dark backdrop-blur-xs flex pt-14 scrollable overflow-y-auto" role="dialog" @touchmove.stop>
|
|
3
|
+
<div class="component-modal mb-8 mobile-portrait:mb-16" ref="target">
|
|
4
4
|
<div class="modal-header">
|
|
5
5
|
<slot name="header" />
|
|
6
6
|
<button @click="ui.toggleModal()" class="btn-icon border-none hover:bg-dark-400">
|
|
@@ -56,14 +56,10 @@ onClickOutside(target, (event) => {
|
|
|
56
56
|
</script>
|
|
57
57
|
<style lang="scss" scoped>
|
|
58
58
|
.modal-mask {
|
|
59
|
-
@apply
|
|
60
|
-
z-index: 25000;
|
|
59
|
+
@apply w-screen duration-300 ease-in-out;
|
|
61
60
|
align-items: flex-start;
|
|
62
61
|
justify-content: center;
|
|
63
62
|
padding: 1rem;
|
|
64
|
-
padding-top: 3.5rem;
|
|
65
|
-
background-color: rgba(17, 17, 17, 0.85);
|
|
66
|
-
backdrop-filter: blur(4px);
|
|
67
63
|
height: 100dvh;
|
|
68
64
|
overflow-y: auto;
|
|
69
65
|
-webkit-overflow-scrolling: touch;
|
|
@@ -76,14 +72,9 @@ onClickOutside(target, (event) => {
|
|
|
76
72
|
|
|
77
73
|
.component-modal {
|
|
78
74
|
width: 640px;
|
|
79
|
-
margin-bottom: 20rem;
|
|
80
75
|
overflow-y: visible;
|
|
81
76
|
@apply flex flex-col rounded-lg bg-dark-300 px-5 py-5;
|
|
82
77
|
|
|
83
|
-
@media (max-width: 480px) {
|
|
84
|
-
margin-bottom: 25rem;
|
|
85
|
-
}
|
|
86
|
-
|
|
87
78
|
.modal-header {
|
|
88
79
|
@apply flex font-bold text-white;
|
|
89
80
|
|
|
@@ -93,7 +84,7 @@ onClickOutside(target, (event) => {
|
|
|
93
84
|
}
|
|
94
85
|
|
|
95
86
|
.modal-body {
|
|
96
|
-
@apply flex flex-col;
|
|
87
|
+
@apply flex flex-col pb-6 md:pb-4;
|
|
97
88
|
flex: 1;
|
|
98
89
|
}
|
|
99
90
|
}
|
|
@@ -104,16 +95,14 @@ onClickOutside(target, (event) => {
|
|
|
104
95
|
justify-content: center;
|
|
105
96
|
padding: 1rem;
|
|
106
97
|
padding-top: 3rem;
|
|
107
|
-
padding-bottom: 15rem !important;
|
|
108
98
|
}
|
|
109
99
|
|
|
110
100
|
.component-modal {
|
|
111
101
|
width: calc(100vw - 2rem);
|
|
112
|
-
margin-bottom:
|
|
102
|
+
margin-bottom: 3rem;
|
|
113
103
|
}
|
|
114
104
|
|
|
115
105
|
.modal-body {
|
|
116
|
-
padding-bottom: 4rem;
|
|
117
106
|
overflow-y: visible;
|
|
118
107
|
flex: 1;
|
|
119
108
|
min-height: 0;
|
|
@@ -122,38 +111,8 @@ onClickOutside(target, (event) => {
|
|
|
122
111
|
|
|
123
112
|
/* iPhone portrait mode - extra spacing for create button */
|
|
124
113
|
@media (max-width: 480px) and (orientation: portrait) {
|
|
125
|
-
.modal-mask {
|
|
126
|
-
padding-bottom: 3rem !important;
|
|
127
|
-
}
|
|
128
|
-
|
|
129
114
|
.component-modal {
|
|
130
|
-
|
|
131
|
-
max-height: none !important;
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
.modal-body {
|
|
135
|
-
padding-bottom: 1rem !important;
|
|
115
|
+
max-height: none;
|
|
136
116
|
}
|
|
137
117
|
}
|
|
138
|
-
|
|
139
|
-
// iPhone landscape mode - proper modal centering with consistent spacing
|
|
140
|
-
// @media (max-height: 500px) and (orientation: landscape) {
|
|
141
|
-
// .modal-mask {
|
|
142
|
-
// padding: 1rem 1rem 4rem 1rem !important;
|
|
143
|
-
// align-items: center !important;
|
|
144
|
-
// justify-content: center !important;
|
|
145
|
-
// padding-bottom: 3rem !important; // Extra padding for create button on iPhone
|
|
146
|
-
// }
|
|
147
|
-
|
|
148
|
-
// .component-modal {
|
|
149
|
-
// max-height: calc(100vh - 10rem) !important;
|
|
150
|
-
// overflow-y: auto !important;
|
|
151
|
-
// margin: 0 !important;
|
|
152
|
-
// margin-bottom: 30px;
|
|
153
|
-
// }
|
|
154
|
-
|
|
155
|
-
// .modal-body {
|
|
156
|
-
// padding-bottom: 1rem !important;
|
|
157
|
-
// }
|
|
158
|
-
// }
|
|
159
118
|
</style>
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<div class="navbar" :class="{ '
|
|
3
|
-
<div :class="['component-container ios-wrapper flex items-center relative', { 'ios-wrapper': landscapeIos }]">
|
|
2
|
+
<div class="navbar" :class="{ 'z-max': menuOpen }">
|
|
3
|
+
<div :class="['component-container ios-wrapper flex items-center relative px-2 sm:px-3 lg:px-4', { 'ios-wrapper': landscapeIos }]">
|
|
4
4
|
<router-link to="/">
|
|
5
5
|
<img src="@/assets/img/logo_trans.png" class="h-6 lg:h-8 mr-4 z-30 object-cover cursor-pointer" alt="Logo: Necro" />
|
|
6
6
|
</router-link>
|
|
@@ -111,14 +111,10 @@
|
|
|
111
111
|
</template>
|
|
112
112
|
<style lang="scss" scoped>
|
|
113
113
|
.navbar {
|
|
114
|
-
@apply border-b py-5 fixed w-full;
|
|
114
|
+
@apply border-b py-5 fixed w-full bg-dark-300/95 backdrop-blur border-dark-600;
|
|
115
115
|
top: 0;
|
|
116
116
|
left: 0;
|
|
117
117
|
z-index: 1000;
|
|
118
|
-
background: oklch(0.1822 0 0 / 0.95);
|
|
119
|
-
backdrop-filter: blur(23px);
|
|
120
|
-
-webkit-backdrop-filter: blur(23px);
|
|
121
|
-
border-color: oklch(0.26 0 0);
|
|
122
118
|
|
|
123
119
|
// Consistent padding base
|
|
124
120
|
padding-top: 1.25rem;
|
|
@@ -148,25 +144,14 @@
|
|
|
148
144
|
ul {
|
|
149
145
|
@apply gap-x-4;
|
|
150
146
|
|
|
151
|
-
// Global SVG normalization - force all icons to be identical
|
|
152
|
-
svg {
|
|
153
|
-
width: 20px !important;
|
|
154
|
-
height: 20px !important;
|
|
155
|
-
display: block !important;
|
|
156
|
-
flex-shrink: 0 !important;
|
|
157
|
-
box-sizing: border-box !important;
|
|
158
|
-
}
|
|
159
|
-
|
|
160
147
|
li a {
|
|
161
|
-
@apply flex text-white text-sm items-center rounded-lg;
|
|
162
|
-
height: 40px;
|
|
163
|
-
border: 1px solid transparent;
|
|
148
|
+
@apply flex text-white text-sm items-center rounded-lg h-10 border-b-2 border-transparent;
|
|
164
149
|
border-left: 3px solid transparent;
|
|
165
150
|
transition: all 0.25s cubic-bezier(0.4, 0, 0.2, 1);
|
|
166
151
|
position: relative;
|
|
167
152
|
|
|
168
153
|
svg {
|
|
169
|
-
@apply mr-2;
|
|
154
|
+
@apply mr-2 w-5 h-5;
|
|
170
155
|
}
|
|
171
156
|
|
|
172
157
|
&.router-link-exact-active {
|
|
@@ -190,35 +175,26 @@
|
|
|
190
175
|
// Desktop mode (lg to xl): icon-only view with perfect centering
|
|
191
176
|
@media (min-width: 1024px) and (max-width: 1279px) {
|
|
192
177
|
li a {
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
padding: 0 !important;
|
|
196
|
-
display: flex !important;
|
|
197
|
-
align-items: center !important;
|
|
198
|
-
justify-content: center !important;
|
|
178
|
+
@apply w-10 h-10 flex items-center justify-center;
|
|
179
|
+
padding: 0;
|
|
199
180
|
position: relative;
|
|
200
181
|
|
|
201
182
|
// Hide text completely in icon-only mode
|
|
202
183
|
span {
|
|
203
|
-
display: none
|
|
184
|
+
display: none;
|
|
204
185
|
}
|
|
205
186
|
|
|
206
187
|
svg {
|
|
207
|
-
|
|
208
|
-
padding: 0 !important;
|
|
209
|
-
position: absolute;
|
|
210
|
-
top: 50%;
|
|
211
|
-
left: 50%;
|
|
188
|
+
@apply m-0 absolute top-1/2 left-1/2;
|
|
212
189
|
transform: translate(-50%, -50%);
|
|
190
|
+
padding: 0;
|
|
213
191
|
}
|
|
214
192
|
|
|
215
193
|
&.router-link-exact-active {
|
|
216
|
-
border
|
|
217
|
-
color: oklch(0.72 0.15 145)
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
width: 40px !important;
|
|
221
|
-
height: 40px !important;
|
|
194
|
+
@apply border-2 w-10 h-10 rounded-lg;
|
|
195
|
+
border-color: oklch(0.72 0.15 145);
|
|
196
|
+
color: oklch(0.72 0.15 145);
|
|
197
|
+
background: oklch(0.72 0.15 145 / 0.08);
|
|
222
198
|
}
|
|
223
199
|
}
|
|
224
200
|
}
|
|
@@ -226,8 +202,7 @@
|
|
|
226
202
|
// XL and above: full width with text
|
|
227
203
|
@media (min-width: 1280px) {
|
|
228
204
|
li a {
|
|
229
|
-
@apply px-4;
|
|
230
|
-
height: 40px;
|
|
205
|
+
@apply px-4 h-10;
|
|
231
206
|
|
|
232
207
|
svg {
|
|
233
208
|
@apply mr-2;
|
|
@@ -237,9 +212,6 @@
|
|
|
237
212
|
}
|
|
238
213
|
}
|
|
239
214
|
|
|
240
|
-
.force-z {
|
|
241
|
-
z-index: 20000;
|
|
242
|
-
}
|
|
243
215
|
|
|
244
216
|
.mobile-menu {
|
|
245
217
|
margin-top: 0;
|
|
@@ -166,7 +166,7 @@ const props = defineProps({
|
|
|
166
166
|
width: 160px;
|
|
167
167
|
height: 160px;
|
|
168
168
|
border-top: 4px solid oklch(0.78 0.12 145);
|
|
169
|
-
border-
|
|
169
|
+
@apply border-r-4 border-r-accent-green/30;
|
|
170
170
|
border-bottom: 4px solid transparent;
|
|
171
171
|
border-left: 4px solid transparent;
|
|
172
172
|
animation: breathe-slow 3s ease-in-out infinite;
|
|
@@ -178,7 +178,7 @@ const props = defineProps({
|
|
|
178
178
|
width: 120px;
|
|
179
179
|
height: 120px;
|
|
180
180
|
border-top: 4px solid oklch(0.72 0.15 145);
|
|
181
|
-
border-
|
|
181
|
+
@apply border-r-4 border-r-accent-green/40;
|
|
182
182
|
border-bottom: 4px solid transparent;
|
|
183
183
|
border-left: 4px solid transparent;
|
|
184
184
|
animation: breathe-medium 2.5s ease-in-out infinite reverse;
|
|
@@ -190,7 +190,7 @@ const props = defineProps({
|
|
|
190
190
|
width: 80px;
|
|
191
191
|
height: 80px;
|
|
192
192
|
border-top: 4px solid oklch(0.68 0.15 145);
|
|
193
|
-
border-
|
|
193
|
+
@apply border-r-4 border-r-accent-green/50;
|
|
194
194
|
border-bottom: 4px solid transparent;
|
|
195
195
|
border-left: 4px solid transparent;
|
|
196
196
|
animation: breathe-fast 2s ease-in-out infinite;
|
|
@@ -204,7 +204,7 @@ const props = defineProps({
|
|
|
204
204
|
border-radius: 50%;
|
|
205
205
|
object-fit: cover;
|
|
206
206
|
z-index: 10;
|
|
207
|
-
border
|
|
207
|
+
@apply border-2 border-accent-green/30;
|
|
208
208
|
box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.1);
|
|
209
209
|
}
|
|
210
210
|
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="section-card">
|
|
3
|
+
<h3 v-if="title" class="section-title">{{ title }}</h3>
|
|
4
|
+
<slot />
|
|
5
|
+
</div>
|
|
6
|
+
</template>
|
|
7
|
+
|
|
8
|
+
<script setup>
|
|
9
|
+
defineProps({
|
|
10
|
+
title: { type: String, default: '' }
|
|
11
|
+
});
|
|
12
|
+
</script>
|
|
13
|
+
|
|
14
|
+
<style lang="scss" scoped>
|
|
15
|
+
.section-card {
|
|
16
|
+
@apply rounded-lg border p-4;
|
|
17
|
+
@apply bg-dark-400 border-dark-600;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
.section-title {
|
|
21
|
+
@apply text-sm font-semibold mb-3;
|
|
22
|
+
@apply text-light-300;
|
|
23
|
+
}
|
|
24
|
+
</style>
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<div class="
|
|
2
|
+
<div class="bg-dark-300 h-screen w-screen z-[1000] fixed flex items-center flex-col justify-center gap-y-3">
|
|
3
3
|
<img src="@/assets/img/logo_trans.png" class="w-[300px] mx-auto" />
|
|
4
4
|
<SpinnerIcon />
|
|
5
5
|
</div>
|
|
@@ -8,11 +8,6 @@
|
|
|
8
8
|
<script setup>
|
|
9
9
|
import { SpinnerIcon } from "@/components/icons";
|
|
10
10
|
</script>
|
|
11
|
-
<style lang="scss" scoped>
|
|
12
|
-
.darkBG {
|
|
13
|
-
background-color: rgba(28, 28, 49, 100%);
|
|
14
|
-
}
|
|
15
|
-
</style>
|
|
16
11
|
|
|
17
12
|
<style>
|
|
18
13
|
img {
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
import { defineProps } from 'vue'
|
|
3
|
+
import { CheckmarkIcon, CloseXIcon } from '@/components/icons'
|
|
4
|
+
|
|
5
|
+
const props = defineProps({
|
|
6
|
+
enabled: {
|
|
7
|
+
type: Boolean,
|
|
8
|
+
required: true
|
|
9
|
+
},
|
|
10
|
+
size: {
|
|
11
|
+
type: String,
|
|
12
|
+
default: 'small',
|
|
13
|
+
validator: (value) => ['small', 'large'].includes(value)
|
|
14
|
+
}
|
|
15
|
+
})
|
|
16
|
+
|
|
17
|
+
const sizeClasses = {
|
|
18
|
+
small: 'w-6 h-6',
|
|
19
|
+
large: 'w-[26px] h-[26px]'
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const enabledClasses = 'bg-accent-green/20 border-accent-green/30'
|
|
23
|
+
const disabledClasses = 'bg-red-500/20 border-red-500/30'
|
|
24
|
+
</script>
|
|
25
|
+
|
|
26
|
+
<template>
|
|
27
|
+
<div
|
|
28
|
+
:class="[
|
|
29
|
+
'flex items-center justify-center rounded-full border-2 transition-all duration-200',
|
|
30
|
+
enabled ? enabledClasses : disabledClasses,
|
|
31
|
+
sizeClasses[size]
|
|
32
|
+
]"
|
|
33
|
+
>
|
|
34
|
+
<CheckmarkIcon v-if="enabled" class="w-3 h-3 text-accent-green" />
|
|
35
|
+
<CloseXIcon v-else class="w-3 h-3 text-red-500" />
|
|
36
|
+
</div>
|
|
37
|
+
</template>
|
|
@@ -113,24 +113,16 @@ const selectCountry = (country, module) => {
|
|
|
113
113
|
}
|
|
114
114
|
|
|
115
115
|
.small-dropdown {
|
|
116
|
-
|
|
117
|
-
border-radius: 100% !important;
|
|
116
|
+
@apply bg-clip-border rounded-full w-12 h-12 flex justify-center items-center;
|
|
118
117
|
padding: 0;
|
|
119
|
-
width: 3em !important;
|
|
120
|
-
height: 3em !important;
|
|
121
|
-
display: flex;
|
|
122
|
-
justify-items: center;
|
|
123
|
-
justify-content: center;
|
|
124
118
|
}
|
|
125
119
|
|
|
126
120
|
.dropdown-content-portal {
|
|
127
121
|
@apply bg-dark-400 border border-dark-650 rounded-lg shadow-2xl z-50;
|
|
122
|
+
@apply max-h-52 overflow-y-auto touch-pan-y;
|
|
128
123
|
padding: 0.5rem;
|
|
129
|
-
|
|
130
|
-
overflow-
|
|
131
|
-
overscroll-behavior: contain !important;
|
|
132
|
-
touch-action: pan-y !important;
|
|
133
|
-
-webkit-overflow-scrolling: touch !important;
|
|
124
|
+
overscroll-behavior: contain;
|
|
125
|
+
-webkit-overflow-scrolling: touch;
|
|
134
126
|
scrollbar-width: none;
|
|
135
127
|
-ms-overflow-style: none;
|
|
136
128
|
min-width: 100px;
|
|
@@ -142,32 +134,24 @@ const selectCountry = (country, module) => {
|
|
|
142
134
|
}
|
|
143
135
|
|
|
144
136
|
.header-item {
|
|
145
|
-
text-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
cursor: default;
|
|
151
|
-
pointer-events: none;
|
|
152
|
-
margin: 4px 2px;
|
|
153
|
-
position: relative;
|
|
137
|
+
@apply text-center text-xs font-bold text-white;
|
|
138
|
+
@apply py-2 px-1 mx-0.5 my-1 rounded-md;
|
|
139
|
+
@apply flex items-center justify-center;
|
|
140
|
+
@apply pointer-events-none cursor-default;
|
|
141
|
+
@apply relative;
|
|
154
142
|
background: linear-gradient(
|
|
155
143
|
135deg,
|
|
156
144
|
rgba(255, 255, 255, 0.08) 0%,
|
|
157
145
|
rgba(255, 255, 255, 0.04) 100%
|
|
158
146
|
);
|
|
159
147
|
border: 1px solid rgba(255, 255, 255, 0.1);
|
|
160
|
-
border-radius: 6px;
|
|
161
148
|
letter-spacing: 0.5px;
|
|
162
149
|
text-shadow: 0 1px 2px rgba(0, 0, 0, 0.3);
|
|
163
150
|
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
|
164
|
-
display: flex;
|
|
165
|
-
align-items: center;
|
|
166
|
-
justify-content: center;
|
|
167
151
|
}
|
|
168
152
|
|
|
169
153
|
.header-item:first-child {
|
|
170
|
-
|
|
154
|
+
@apply mt-0.5;
|
|
171
155
|
}
|
|
172
156
|
|
|
173
157
|
.header-item::before {
|
|
@@ -187,39 +171,11 @@ const selectCountry = (country, module) => {
|
|
|
187
171
|
}
|
|
188
172
|
|
|
189
173
|
.country-item {
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
cursor: pointer;
|
|
194
|
-
border-radius: 6px;
|
|
195
|
-
margin: 1px 2px;
|
|
174
|
+
@apply py-2 px-1 mx-0.5 my-px text-sm text-white;
|
|
175
|
+
@apply cursor-pointer rounded-md min-h-8;
|
|
176
|
+
@apply flex items-center justify-center;
|
|
196
177
|
transition: all 0.15s ease;
|
|
197
|
-
display: flex;
|
|
198
|
-
align-items: center;
|
|
199
|
-
justify-content: center;
|
|
200
|
-
min-height: 32px;
|
|
201
178
|
}
|
|
202
179
|
|
|
203
|
-
|
|
204
|
-
display: flex;
|
|
205
|
-
align-items: center;
|
|
206
|
-
justify-content: center;
|
|
207
|
-
gap: 6px;
|
|
208
|
-
width: 100%;
|
|
209
|
-
flex-wrap: nowrap;
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
.country-item .flex span {
|
|
213
|
-
font-size: 0.75rem;
|
|
214
|
-
font-weight: 500;
|
|
215
|
-
white-space: nowrap;
|
|
216
|
-
flex-shrink: 0;
|
|
217
|
-
text-align: center;
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
.country-item .flex img {
|
|
221
|
-
width: 18px;
|
|
222
|
-
height: 14px;
|
|
223
|
-
flex-shrink: 0;
|
|
224
|
-
}
|
|
180
|
+
/* Flex layout already defined in template with Tailwind classes */
|
|
225
181
|
</style>
|