@necrolab/dashboard 0.5.1 → 0.5.2
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/index.html
CHANGED
|
@@ -8,6 +8,8 @@
|
|
|
8
8
|
content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, viewport-fit=cover"
|
|
9
9
|
/>
|
|
10
10
|
<meta name="description" content="Necro Lab - dashboard" />
|
|
11
|
+
<meta name="darkreader-lock" />
|
|
12
|
+
<meta name="color-scheme" content="dark" />
|
|
11
13
|
<title>Necro Lab - Dashboard</title>
|
|
12
14
|
<!-- DNS prefetch for external resources -->
|
|
13
15
|
<link rel="dns-prefetch" href="https://fonts.googleapis.com" />
|
package/package.json
CHANGED
|
Binary file
|
package/src/assets/css/main.scss
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/* ==========================================================================
|
|
2
|
-
NECRO DASHBOARD
|
|
2
|
+
NECRO DASHBOARD
|
|
3
3
|
Modular SCSS architecture with @use imports
|
|
4
4
|
========================================================================== */
|
|
5
5
|
|
|
@@ -47,14 +47,14 @@ img {
|
|
|
47
47
|
|
|
48
48
|
/* Global icon color consistency */
|
|
49
49
|
svg {
|
|
50
|
-
color: oklch(0.
|
|
50
|
+
color: oklch(0.9 0 0) !important;
|
|
51
51
|
}
|
|
52
52
|
|
|
53
53
|
/* For stroke icons (Eye, etc) - stroke on svg element */
|
|
54
54
|
svg[stroke] path,
|
|
55
55
|
svg[stroke] circle,
|
|
56
56
|
svg[stroke] line {
|
|
57
|
-
stroke: oklch(0.
|
|
57
|
+
stroke: oklch(0.9 0 0) !important;
|
|
58
58
|
}
|
|
59
59
|
|
|
60
60
|
/* For filled icons with explicit fill */
|
|
@@ -62,7 +62,7 @@ svg path[fill]:not([fill="none"]),
|
|
|
62
62
|
svg circle[fill]:not([fill="none"]),
|
|
63
63
|
svg rect[fill]:not([fill="none"]),
|
|
64
64
|
svg polygon[fill]:not([fill="none"]) {
|
|
65
|
-
fill: oklch(0.
|
|
65
|
+
fill: oklch(0.9 0 0) !important;
|
|
66
66
|
}
|
|
67
67
|
|
|
68
68
|
/* For filled icons without explicit fill attribute */
|
|
@@ -70,7 +70,7 @@ svg:not([stroke]):not([fill="none"]) path:not([fill]),
|
|
|
70
70
|
svg:not([stroke]):not([fill="none"]) circle:not([fill]),
|
|
71
71
|
svg:not([stroke]):not([fill="none"]) rect:not([fill]),
|
|
72
72
|
svg:not([stroke]):not([fill="none"]) polygon:not([fill]) {
|
|
73
|
-
fill: oklch(0.
|
|
73
|
+
fill: oklch(0.9 0 0) !important;
|
|
74
74
|
}
|
|
75
75
|
|
|
76
76
|
/* ==========================================================================
|
|
@@ -82,31 +82,32 @@ svg:not([stroke]):not([fill="none"]) polygon:not([fill]) {
|
|
|
82
82
|
}
|
|
83
83
|
|
|
84
84
|
.status-indicator {
|
|
85
|
-
@apply
|
|
85
|
+
@apply h-2 w-2 flex-shrink-0 rounded-full;
|
|
86
86
|
min-width: 4px;
|
|
87
87
|
min-height: 4px;
|
|
88
88
|
}
|
|
89
89
|
|
|
90
90
|
.mobile-icons {
|
|
91
|
-
@apply
|
|
91
|
+
@apply ml-auto flex items-center gap-x-2 lg:hidden;
|
|
92
92
|
|
|
93
93
|
button {
|
|
94
|
-
@apply
|
|
94
|
+
@apply flex h-8 w-8 items-center justify-center rounded transition-all duration-150;
|
|
95
95
|
background-color: oklch(0.2046 0 0);
|
|
96
96
|
border: 2px solid oklch(0.2809 0 0);
|
|
97
97
|
color: oklch(0.82 0 0);
|
|
98
98
|
|
|
99
|
-
&:hover,
|
|
99
|
+
&:hover,
|
|
100
|
+
&:active {
|
|
100
101
|
border-color: oklch(0.72 0.15 145);
|
|
101
102
|
outline: 1px solid oklch(0.72 0.15 145);
|
|
102
103
|
outline-offset: 0;
|
|
103
|
-
color: oklch(0.
|
|
104
|
+
color: oklch(0.9 0 0);
|
|
104
105
|
}
|
|
105
106
|
}
|
|
106
107
|
}
|
|
107
108
|
|
|
108
109
|
.loading-spinner {
|
|
109
|
-
@apply
|
|
110
|
+
@apply h-4 w-4 animate-spin rounded-full border-2 border-white border-t-transparent;
|
|
110
111
|
}
|
|
111
112
|
|
|
112
113
|
/* ==========================================================================
|
|
@@ -114,7 +115,7 @@ svg:not([stroke]):not([fill="none"]) polygon:not([fill]) {
|
|
|
114
115
|
========================================================================== */
|
|
115
116
|
|
|
116
117
|
.label-override {
|
|
117
|
-
@apply flex items-center text-xs
|
|
118
|
+
@apply mb-2 flex items-center text-xs;
|
|
118
119
|
color: oklch(0.65 0 0);
|
|
119
120
|
|
|
120
121
|
svg {
|
|
@@ -128,10 +129,10 @@ svg:not([stroke]):not([fill="none"]) polygon:not([fill]) {
|
|
|
128
129
|
|
|
129
130
|
.task-switches {
|
|
130
131
|
h4 {
|
|
131
|
-
color: oklch(0.
|
|
132
|
+
color: oklch(0.9 0 0);
|
|
132
133
|
font-size: 0.8125rem;
|
|
133
134
|
font-weight: 500;
|
|
134
|
-
@apply
|
|
135
|
+
@apply mx-auto mb-2 flex items-center gap-x-2 text-center;
|
|
135
136
|
}
|
|
136
137
|
|
|
137
138
|
.switch-wrapper {
|
|
@@ -141,7 +142,7 @@ svg:not([stroke]):not([fill="none"]) polygon:not([fill]) {
|
|
|
141
142
|
svg {
|
|
142
143
|
width: 15px !important;
|
|
143
144
|
height: 15px !important;
|
|
144
|
-
color: oklch(0.
|
|
145
|
+
color: oklch(0.9 0 0) !important;
|
|
145
146
|
margin-left: 0.25rem !important;
|
|
146
147
|
}
|
|
147
148
|
}
|
|
@@ -223,11 +224,11 @@ svg:not([stroke]):not([fill="none"]) polygon:not([fill]) {
|
|
|
223
224
|
@screen md {
|
|
224
225
|
.btn-primary,
|
|
225
226
|
.btn-secondary {
|
|
226
|
-
@apply
|
|
227
|
+
@apply px-3 py-1.5 text-sm;
|
|
227
228
|
}
|
|
228
229
|
|
|
229
230
|
.btn-action {
|
|
230
|
-
@apply
|
|
231
|
+
@apply h-12 px-6 text-sm;
|
|
231
232
|
min-height: 48px;
|
|
232
233
|
}
|
|
233
234
|
|
|
@@ -241,7 +242,7 @@ svg:not([stroke]):not([fill="none"]) polygon:not([fill]) {
|
|
|
241
242
|
|
|
242
243
|
@screen mobile-portrait {
|
|
243
244
|
.btn-action {
|
|
244
|
-
@apply
|
|
245
|
+
@apply h-14 px-8 text-base;
|
|
245
246
|
min-height: 56px;
|
|
246
247
|
font-weight: 600;
|
|
247
248
|
border-radius: 8px;
|
|
@@ -257,7 +258,7 @@ svg:not([stroke]):not([fill="none"]) polygon:not([fill]) {
|
|
|
257
258
|
|
|
258
259
|
@screen mobile-landscape {
|
|
259
260
|
.btn-action {
|
|
260
|
-
@apply
|
|
261
|
+
@apply h-14 px-8 text-base;
|
|
261
262
|
min-height: 56px;
|
|
262
263
|
font-weight: 600;
|
|
263
264
|
}
|
|
@@ -1,31 +1,42 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div class="form-section">
|
|
3
3
|
<!-- Username -->
|
|
4
|
-
<div class="input-
|
|
5
|
-
<
|
|
6
|
-
<
|
|
7
|
-
<
|
|
8
|
-
</
|
|
9
|
-
<div class="
|
|
10
|
-
<input
|
|
4
|
+
<div class="input-container mb-3">
|
|
5
|
+
<div class="flex items-center gap-2">
|
|
6
|
+
<ProfileIcon class="w-4 h-4" />
|
|
7
|
+
<span class="text-light-300 font-medium text-sm">Username</span>
|
|
8
|
+
</div>
|
|
9
|
+
<div class="flex-1 flex items-center">
|
|
10
|
+
<input
|
|
11
|
+
type="text"
|
|
12
|
+
class="login-input"
|
|
13
|
+
v-model="user"
|
|
14
|
+
/>
|
|
11
15
|
</div>
|
|
12
16
|
</div>
|
|
13
17
|
<!-- Password -->
|
|
14
|
-
<div class="input-
|
|
15
|
-
<
|
|
16
|
-
<
|
|
17
|
-
<
|
|
18
|
-
</
|
|
19
|
-
<div class="
|
|
20
|
-
<input
|
|
18
|
+
<div class="input-container mb-4">
|
|
19
|
+
<div class="flex items-center gap-2">
|
|
20
|
+
<KeyIcon class="w-4 h-4" />
|
|
21
|
+
<span class="text-light-300 font-medium text-sm">Password</span>
|
|
22
|
+
</div>
|
|
23
|
+
<div class="flex-1 flex items-center">
|
|
24
|
+
<input
|
|
25
|
+
type="password"
|
|
26
|
+
class="login-input"
|
|
27
|
+
v-model="password"
|
|
28
|
+
/>
|
|
21
29
|
</div>
|
|
22
30
|
</div>
|
|
23
31
|
<button
|
|
24
|
-
class="
|
|
32
|
+
class="login-btn mt-6 mx-auto"
|
|
25
33
|
@click="login()"
|
|
26
34
|
:disabled="buttonDisabled"
|
|
27
35
|
>
|
|
28
36
|
<span v-if="!buttonDisabled">Login</span>
|
|
37
|
+
<svg v-if="!buttonDisabled" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" class="w-5 h-5">
|
|
38
|
+
<path d="M15 3h4a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2h-4M10 17l5-5-5-5M13.8 12H3"/>
|
|
39
|
+
</svg>
|
|
29
40
|
<div v-else class="loading-spinner"></div>
|
|
30
41
|
</button>
|
|
31
42
|
</div>
|
|
@@ -56,43 +67,65 @@ async function login() {
|
|
|
56
67
|
</script>
|
|
57
68
|
|
|
58
69
|
<style lang="scss" scoped>
|
|
59
|
-
.
|
|
60
|
-
@apply flex items-center
|
|
61
|
-
|
|
70
|
+
.login-btn {
|
|
71
|
+
@apply flex items-center justify-center gap-2 rounded-lg transition-all duration-150;
|
|
72
|
+
background: oklch(0.72 0.15 145);
|
|
73
|
+
border: 2px solid oklch(0.72 0.15 145);
|
|
74
|
+
color: oklch(1 0 0);
|
|
75
|
+
height: 3rem;
|
|
76
|
+
width: 12rem;
|
|
77
|
+
font-size: 0.9375rem;
|
|
78
|
+
font-weight: 600;
|
|
79
|
+
letter-spacing: 0.05em;
|
|
80
|
+
text-transform: uppercase;
|
|
81
|
+
|
|
82
|
+
&:hover:not(:disabled) {
|
|
83
|
+
background: oklch(0.68 0.15 145);
|
|
84
|
+
border-color: oklch(0.68 0.15 145);
|
|
85
|
+
transform: translateY(-1px);
|
|
86
|
+
box-shadow: 0 4px 12px oklch(0.72 0.15 145 / 0.3);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
&:active:not(:disabled) {
|
|
90
|
+
transform: translateY(0);
|
|
91
|
+
box-shadow: 0 2px 4px oklch(0.72 0.15 145 / 0.2);
|
|
92
|
+
}
|
|
62
93
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
path {
|
|
67
|
-
fill: #e1e1e4 !important;
|
|
68
|
-
}
|
|
94
|
+
&:disabled {
|
|
95
|
+
opacity: 0.7;
|
|
96
|
+
cursor: not-allowed;
|
|
69
97
|
}
|
|
70
98
|
}
|
|
71
99
|
|
|
72
|
-
.input-
|
|
73
|
-
@apply bg-dark-
|
|
74
|
-
|
|
100
|
+
.input-container {
|
|
101
|
+
@apply text-white bg-dark-500 px-3 rounded-lg border-2 border-dark-550 flex items-center justify-between h-11;
|
|
102
|
+
overflow: visible;
|
|
103
|
+
transition: border-color 0.15s ease;
|
|
75
104
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
105
|
+
&:hover {
|
|
106
|
+
border-color: oklch(0.30 0 0);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
&:focus-within {
|
|
110
|
+
border-color: oklch(0.72 0.15 145) !important;
|
|
111
|
+
outline: 1px solid oklch(0.72 0.15 145);
|
|
112
|
+
outline-offset: 0;
|
|
81
113
|
}
|
|
82
114
|
}
|
|
83
115
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
116
|
+
.login-input {
|
|
117
|
+
@apply w-full h-full text-sm text-white bg-transparent border-0 outline-none px-2 py-1;
|
|
118
|
+
|
|
119
|
+
&:focus {
|
|
120
|
+
@apply outline-none border-0 shadow-none bg-transparent;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
&:hover:not(:focus) {
|
|
124
|
+
background: transparent;
|
|
92
125
|
}
|
|
93
126
|
|
|
94
|
-
|
|
95
|
-
|
|
127
|
+
&::placeholder {
|
|
128
|
+
color: oklch(0.50 0 0);
|
|
96
129
|
}
|
|
97
130
|
}
|
|
98
131
|
</style>
|
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
|
|
38
38
|
<script setup>
|
|
39
39
|
import { ref, onMounted, onUnmounted } from "vue";
|
|
40
|
-
import logoIcon from "/
|
|
40
|
+
import logoIcon from "/reconnect-logo.png";
|
|
41
41
|
|
|
42
42
|
const dotIndex = ref(0);
|
|
43
43
|
const progressWidth = ref(0);
|
|
@@ -119,7 +119,7 @@ const props = defineProps({
|
|
|
119
119
|
left: 0;
|
|
120
120
|
right: 0;
|
|
121
121
|
bottom: 0;
|
|
122
|
-
background:
|
|
122
|
+
background: oklch(0.1822 0 0 / 0.98);
|
|
123
123
|
backdrop-filter: blur(12px);
|
|
124
124
|
-webkit-backdrop-filter: blur(12px);
|
|
125
125
|
}
|
|
@@ -269,7 +269,7 @@ const props = defineProps({
|
|
|
269
269
|
left: -100%;
|
|
270
270
|
width: 100%;
|
|
271
271
|
height: 100%;
|
|
272
|
-
background: linear-gradient(90deg, transparent,
|
|
272
|
+
background: linear-gradient(90deg, transparent, oklch(1 0 0 / 0.2), transparent);
|
|
273
273
|
animation: shimmer 2s ease-in-out infinite;
|
|
274
274
|
}
|
|
275
275
|
|
package/src/views/Login.vue
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div class="login-container" v-once>
|
|
3
3
|
<div class="login-card">
|
|
4
|
-
<div class="flex justify-center
|
|
5
|
-
<img src="@/assets/img/logo_trans.png" class="h-16 object-cover" alt="Logo:
|
|
4
|
+
<div class="mb-10 flex justify-center">
|
|
5
|
+
<img src="@/assets/img/logo_trans.png" class="mb-3 h-16 object-cover" alt="Logo: NecroLab" />
|
|
6
6
|
</div>
|
|
7
|
-
<h2 class="text-l text-white text-center font-bold mb-6">Please login to proceed</h2>
|
|
8
7
|
|
|
9
8
|
<LoginForm />
|
|
10
9
|
</div>
|
|
@@ -15,7 +14,7 @@ import LoginForm from "@/components/Auth/LoginForm.vue";
|
|
|
15
14
|
</script>
|
|
16
15
|
<style lang="scss" scoped>
|
|
17
16
|
.login-container {
|
|
18
|
-
@apply flex flex-col items-center
|
|
17
|
+
@apply flex min-h-screen flex-col items-center px-4;
|
|
19
18
|
margin-top: 3vh;
|
|
20
19
|
|
|
21
20
|
// Mobile devices
|
|
@@ -33,7 +32,7 @@ import LoginForm from "@/components/Auth/LoginForm.vue";
|
|
|
33
32
|
}
|
|
34
33
|
|
|
35
34
|
.login-card {
|
|
36
|
-
@apply
|
|
35
|
+
@apply rounded-lg border border-dark-650 bg-dark-400 shadow-xl;
|
|
37
36
|
backdrop-filter: blur(10px);
|
|
38
37
|
box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.5);
|
|
39
38
|
width: 100%;
|
|
@@ -52,7 +51,7 @@ import LoginForm from "@/components/Auth/LoginForm.vue";
|
|
|
52
51
|
margin: 0.25rem 0;
|
|
53
52
|
|
|
54
53
|
h2 {
|
|
55
|
-
@apply text-lg
|
|
54
|
+
@apply mb-2 text-lg;
|
|
56
55
|
}
|
|
57
56
|
|
|
58
57
|
.flex.justify-center {
|
|
@@ -79,11 +78,11 @@ import LoginForm from "@/components/Auth/LoginForm.vue";
|
|
|
79
78
|
// Title responsive sizing
|
|
80
79
|
.login-card h2 {
|
|
81
80
|
@media (max-width: 480px) {
|
|
82
|
-
@apply text-lg
|
|
81
|
+
@apply mb-3 text-lg;
|
|
83
82
|
}
|
|
84
83
|
|
|
85
84
|
@media (orientation: landscape) {
|
|
86
|
-
@apply text-base
|
|
85
|
+
@apply mb-2 text-base;
|
|
87
86
|
}
|
|
88
87
|
}
|
|
89
88
|
</style>
|