1
1
<script setup lang="ts">
2
2
import { NButton , NCard , NFlex , NH4 } from ' naive-ui' ;
3
3
4
- import type { ButtonProps } from ' naive-ui ' ;
4
+ import { computed , onMounted , type PropType , ref , toRefs , watch } from ' vue ' ;
5
5
6
- import type { PropType } from ' vue ' ;
6
+ import type { ButtonProps } from ' naive-ui ' ;
7
7
8
8
import Logo from ' ~/assets/logo.svg' ;
9
9
10
10
import { useI18n } from ' ~/utils/i18n.utils' ;
11
11
12
12
const i18n = useI18n (' login' );
13
13
14
- defineProps ({
14
+ const props = defineProps ({
15
15
logo: {
16
16
type: String ,
17
17
required: false ,
@@ -27,6 +27,7 @@ defineProps({
27
27
message: {
28
28
type: String ,
29
29
required: false ,
30
+ default: ' ' ,
30
31
},
31
32
buttonDisabled: {
32
33
type: Boolean ,
@@ -40,11 +41,59 @@ defineProps({
40
41
type: Object as PropType <ButtonProps & Pick <HTMLAnchorElement , ' href' >>,
41
42
required: false ,
42
43
},
44
+ minWidth: {
45
+ type: String ,
46
+ required: false ,
47
+ },
48
+ progress: {
49
+ type: Number ,
50
+ required: false ,
51
+ },
52
+ interval: {
53
+ type: Number ,
54
+ required: false ,
55
+ default: 0 ,
56
+ },
43
57
});
44
58
45
59
const emits = defineEmits <{
46
60
(name : ' onSignIn' , e : MouseEvent ): void ;
47
61
}>();
62
+
63
+ const { message, interval, progress } = toRefs (props );
64
+
65
+ const debounceMessage = ref <string >(message .value );
66
+ const _message = computed (() => debounceMessage .value || i18n (' sub_title' ));
67
+
68
+ const changed = ref (false );
69
+ const timeout = ref <ReturnType <typeof setTimeout >>();
70
+
71
+ const reverse = ref (false );
72
+ const _interval = ref <ReturnType <typeof setInterval >>();
73
+
74
+ const _progress = computed (() => {
75
+ if (interval .value ) return reverse .value ? 0 : 100 ;
76
+ return progress ?.value ;
77
+ });
78
+
79
+ onMounted (() => {
80
+ watch (message , (_new , _old ) => {
81
+ changed .value = _old !== _new ;
82
+ if (! changed .value ) return ;
83
+ if (timeout .value ) clearTimeout (timeout .value );
84
+ timeout .value = setTimeout (() => {
85
+ changed .value = false ;
86
+ debounceMessage .value = _new ;
87
+ }, 250 );
88
+ });
89
+ watch (interval , _new => {
90
+ if (_interval .value ) clearInterval (_interval .value );
91
+ if (! _new ) return ;
92
+ _interval .value = setInterval (() => {
93
+ reverse .value = ! reverse .value ;
94
+ }, _new );
95
+ });
96
+ });
48
97
</script >
49
98
50
99
<template >
@@ -56,7 +105,20 @@ const emits = defineEmits<{
56
105
57
106
<NFlex class =" content" vertical justify =" space-evenly" >
58
107
<slot name =" message" >
59
- <NH4 class =" title" prefix =" bar" >{{ message ?? i18n('sub_title') }}</NH4 >
108
+ <NH4
109
+ class =" title"
110
+ :class =" { progress, interval }"
111
+ prefix =" bar"
112
+ :style =" {
113
+ minWidth: minWidth ?? `${ _message?.length }ch`,
114
+ '--progress': `${ _progress }%`,
115
+ '--interval': `${interval}ms`,
116
+ }"
117
+ >
118
+ <span class =" title-content" :class =" { changed }" >
119
+ {{ _message }}
120
+ </span >
121
+ </NH4 >
60
122
</slot >
61
123
62
124
<slot name =" main" />
@@ -108,12 +170,44 @@ const emits = defineEmits<{
108
170
height : 100% ;
109
171
110
172
.title {
173
+ --progress-color : rgb (99 226 184 / 10% );
174
+ --color : rgb (99 226 184 / 5% );
175
+
176
+ min-width : 0 ;
111
177
margin : 0 ;
112
178
padding : 1rem ;
113
179
white-space : pre-line ;
114
- background : rgb (99 226 184 / 5% );
115
- transition : background 0.5s ;
116
- will-change : background ;
180
+ background : var (--color );
181
+ transition :
182
+ min-width 0.5s var (--n-bezier ),
183
+ background 0.5s var (--n-bezier ),
184
+ --progress 0.5s var (--n-bezier );
185
+
186
+ & .progress {
187
+ @include mixin .progress-background ($rail : var (--color ));
188
+ }
189
+
190
+ & .interval {
191
+ @include mixin .progress-background (
192
+ $rail : var (--color ),
193
+ $color : var (--progress-color )
194
+ );
195
+
196
+ transition :
197
+ min-width 0.5s var (--n-bezier ),
198
+ background var (--interval ) linear ,
199
+ --progress var (--interval ) linear ;
200
+ }
201
+
202
+ & -content {
203
+ display : flex ;
204
+ opacity : 1 ;
205
+ transition : opacity 0.25s var (--n-bezier );
206
+
207
+ & .changed {
208
+ opacity : 0.25 ;
209
+ }
210
+ }
117
211
}
118
212
119
213
.button {
@@ -125,8 +219,9 @@ const emits = defineEmits<{
125
219
}
126
220
127
221
& :hover {
128
- .title {
129
- background : rgb (99 226 184 / 9% );
222
+ .title :not (&.progress ) {
223
+ --color : rgb (99 226 184 / 9% );
224
+ --progress-color : rgb (99 226 184 / 14% );
130
225
}
131
226
}
132
227
}
0 commit comments