1
1
<script setup lang="ts">
2
- import { NFlex , NImage , NTimelineItem } from ' naive-ui' ;
2
+ import { NFlex , NImage , NSkeleton , NTime , NTimelineItem } from ' naive-ui' ;
3
3
4
- import { type PropType } from ' vue' ;
4
+ import { computed , type PropType } from ' vue' ;
5
5
6
6
import type { ListScrollItem } from ' ~/components/common/list/ListScroll.model' ;
7
7
@@ -33,23 +33,53 @@ const props = defineProps({
33
33
required: false ,
34
34
default: ' default' ,
35
35
},
36
- noTag: {
36
+ noHeader: {
37
+ type: Boolean ,
38
+ required: false ,
39
+ },
40
+ nextHasHeader: {
41
+ type: Boolean ,
42
+ required: false ,
43
+ },
44
+ hideDate: {
45
+ type: Boolean ,
46
+ required: false ,
47
+ },
48
+ hover: {
37
49
type: Boolean ,
38
50
required: false ,
39
51
},
40
52
});
53
+
54
+ const emit = defineEmits <{
55
+ (e : ' onHover' , event : { index: number ; item: ListScrollItem ; hover: boolean }): void ;
56
+ }>();
57
+
58
+ const onHover = (hover : boolean ) => {
59
+ emit (' onHover' , { index: props .index , item: props .item , hover });
60
+ };
61
+
62
+ const noHeader = computed (() => props .noHeader || props .item .date ?.sameDayAsPrevious );
63
+ const nextHasHead = computed (
64
+ () => props .nextHasHeader || ! props .item .date ?.sameDayAsNext ,
65
+ );
66
+ const date = computed (() => props .item .date ?.current );
67
+ const year = new Date ().getFullYear ();
68
+ const sameYear = computed (() => date .value ?.getFullYear () === year );
69
+ const loading = computed (() => props .item .loading );
41
70
</script >
42
71
43
72
<template >
44
73
<NTimelineItem
45
74
:key =" item.id"
46
75
class =" timeline-item"
47
- :data-tag =" JSON.stringify(item.date)"
48
- :class =" { 'no-tag': noTag || item.date?.sameDay }"
76
+ :class =" { 'no-header': noHeader, 'next-has-header': nextHasHead }"
49
77
:data-key =" item.id"
50
78
:data-index =" index"
51
79
:line-type =" item.loading ? 'dashed' : lineType"
52
80
:color =" item.loading ? 'grey' : color"
81
+ @mouseenter =" onHover(true)"
82
+ @mouseleave =" onHover(false)"
53
83
>
54
84
<template #icon >
55
85
<slot name =" tag" />
@@ -58,19 +88,43 @@ const props = defineProps({
58
88
<slot name =" before" />
59
89
</template >
60
90
<template #default >
61
- <NFlex class =" content" :class =" { 'no-border': noTag || item.date?.sameDay }" >
62
- <NImage
63
- alt =" poster-image"
64
- class =" poster"
65
- lazy
66
- preview-disabled
67
- :src =" poster"
68
- :preview-src =" poster"
69
- :fallback-src =" PosterPlaceholder"
70
- />
71
- <ListItemPanel :item =" item" :loading =" item.loading" >
72
- <slot :item =" item" :index =" index" :loading =" item.loading" />
73
- </ListItemPanel >
91
+ <NFlex class =" content" :class =" { 'no-border': noHeader }" :wrap =" false" >
92
+ <NFlex
93
+ v-if =" !hideDate"
94
+ class =" header"
95
+ :class =" { hover }"
96
+ vertical
97
+ justify =" flex-start"
98
+ align =" center"
99
+ size =" small"
100
+ :theme-overrides =" { gapSmall: '0.25rem' }"
101
+ >
102
+ <template v-if =" date && ! noHeader " >
103
+ <NTime class =" month" :time =" date" format =" MMM" />
104
+ <NTime class =" day" :time =" date" format =" dd" />
105
+ <NTime :time =" date" format =" eee" />
106
+ <NTime v-if =" !sameYear" class =" year" :time =" date" format =" yyyy" />
107
+ </template >
108
+ <template v-else-if =" loading " >
109
+ <NSkeleton text style =" width : 1rem " />
110
+ <NSkeleton text style =" width : 2rem " />
111
+ <NSkeleton text style =" width : 1rem " />
112
+ </template >
113
+ </NFlex >
114
+ <NFlex class =" tile" :wrap =" false" >
115
+ <NImage
116
+ alt =" poster-image"
117
+ class =" poster"
118
+ lazy
119
+ preview-disabled
120
+ :src =" poster"
121
+ :preview-src =" poster"
122
+ :fallback-src =" PosterPlaceholder"
123
+ />
124
+ <ListItemPanel :item =" item" :loading =" item.loading" >
125
+ <slot :item =" item" :index =" index" :loading =" item.loading" />
126
+ </ListItemPanel >
127
+ </NFlex >
74
128
</NFlex >
75
129
</template >
76
130
<template #footer >
@@ -81,21 +135,48 @@ const props = defineProps({
81
135
82
136
<style lang="scss" scoped>
83
137
@use ' ~/styles/mixin' as mixin ;
138
+ @use ' ~/styles/z-index' as layers ;
84
139
85
140
.timeline-item {
86
141
margin : 0 1rem ;
87
142
88
143
.content {
89
- @include mixin .hover-background (
90
- $from : transparent ,
91
- $to : var (--bg-color-20 ),
92
- $transition : 0.2s var (--n-bezier )
93
- );
94
-
95
144
padding : 0.5rem ;
96
145
97
- & :not (.no-border ) {
98
- border-top : 1px solid rgba (255 255 255 / 10% );
146
+ .tile {
147
+ @include mixin .hover-background (
148
+ $from : transparent ,
149
+ $to : var (--bg-color-20 ),
150
+ $transition : 0.2s var (--n-bezier )
151
+ );
152
+
153
+ flex : 1 1 auto ;
154
+ }
155
+ }
156
+
157
+ .header {
158
+ width : 2.5rem ;
159
+ margin : 0.25rem 0.5rem 0 -0.25rem ;
160
+ color : var (--n-text-color );
161
+ font-size : 14px ;
162
+
163
+ & .hover {
164
+ color : var (--trakt-red );
165
+ transition : color 0.2s var (--n-bezier );
166
+ will-change : color ;
167
+ }
168
+
169
+ .month {
170
+ font-weight : bold ;
171
+ }
172
+
173
+ .day {
174
+ font-weight : bold ;
175
+ font-size : 1.5rem ;
176
+ }
177
+
178
+ .year {
179
+ color : var (--n-meta-text-color );
99
180
}
100
181
}
101
182
@@ -117,10 +198,10 @@ const props = defineProps({
117
198
118
199
.n-timeline.n-timeline--left-placement {
119
200
.timeline-item.n-timeline-item .n-timeline-item-timeline {
120
- top : -6 px ;
201
+ top : calc ( 0 % - var ( --n-icon-size ) / 2 ) ;
121
202
}
122
203
123
- .timeline-item.no-tag .n-timeline-item .n-timeline-item-timeline {
204
+ .timeline-item.no-header .n-timeline-item .n-timeline-item-timeline {
124
205
.n-timeline-item-timeline__line {
125
206
top : 0 ;
126
207
}
@@ -129,5 +210,17 @@ const props = defineProps({
129
210
display : none ;
130
211
}
131
212
}
213
+
214
+ .timeline-item.n-timeline-item .n-timeline-item-content {
215
+ border-top : 1px solid transparent ;
216
+
217
+ .n-timeline-item-content__title {
218
+ margin : 0 ;
219
+ }
220
+ }
221
+
222
+ .timeline-item.n-timeline-item :not (.no-header ) .n-timeline-item-content {
223
+ border-top : 1px solid rgba (255 255 255 / 10% );
224
+ }
132
225
}
133
226
</style >
0 commit comments