Skip to content

Commit 1f27433

Browse files
committed
feat(listItem): rework list item to separate by date
1 parent c90ed78 commit 1f27433

File tree

12 files changed

+195
-78
lines changed

12 files changed

+195
-78
lines changed

src/components/common/background/GridBackground.vue

+3-3
Original file line numberDiff line numberDiff line change
@@ -63,13 +63,13 @@ onBeforeUnmount(() => window.removeEventListener('resize', handleResize));
6363
.grid-item {
6464
width: var(--grid-size);
6565
height: var(--grid-size);
66-
border-top: 0.1px solid var(--bg-blur-bg);
67-
border-left: 0.1px solid var(--bg-blur-bg);
66+
border-top: 0.1px solid var(--bg-color);
67+
border-left: 0.1px solid var(--bg-color);
6868
transition: background-color 0.25s var(--n-bezier);
6969
will-change: background-color;
7070
7171
&:hover {
72-
background-color: var(--bg-blur-bg-hover);
72+
background-color: var(--bg-color-hover);
7373
transition: none;
7474
}
7575
}

src/components/common/list/ListItem.vue

+72-18
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { NFlex, NImage, NTimelineItem } from 'naive-ui';
44
import { computed, type PropType, toRefs } from 'vue';
55
66
import PosterPlaceholder from '~/assets/images/poster-placholder.webp';
7+
import { Colors } from '~/styles/colors.style';
78
89
const props = defineProps({
910
id: {
@@ -19,16 +20,21 @@ const props = defineProps({
1920
required: false,
2021
default: PosterPlaceholder,
2122
},
22-
type: {
23-
type: String as PropType<'default' | 'error' | 'info' | 'success' | 'warning'>,
23+
color: {
24+
type: String,
2425
required: false,
25-
default: 'default',
26+
default: Colors.traktRedDark,
2627
},
2728
lineType: {
2829
type: String as PropType<'dashed' | 'default'>,
2930
required: false,
3031
default: 'default',
3132
},
33+
tag: {
34+
type: Boolean,
35+
required: false,
36+
default: true,
37+
},
3238
});
3339
3440
const { id, index } = toRefs(props);
@@ -40,31 +46,55 @@ const isLoading = computed(() => id?.value < 0);
4046
<NTimelineItem
4147
:key="id"
4248
class="timeline-item"
49+
:class="{ 'no-tag': !tag }"
4350
:data-key="id"
4451
:data-index="index"
45-
:type="isLoading ? type : 'success'"
46-
:line-type="isLoading ? lineType : 'default'"
52+
:line-type="isLoading ? 'dashed' : lineType"
53+
:color="isLoading ? 'grey' : color"
4754
>
48-
<NFlex>
49-
<NImage
50-
alt="poster-image"
51-
class="poster"
52-
lazy
53-
preview-disabled
54-
:src="poster"
55-
:preview-src="poster"
56-
:fallback-src="PosterPlaceholder"
57-
/>
58-
<slot :id="id" :index="index" :loading="isLoading" />
59-
</NFlex>
55+
<template #icon>
56+
<slot name="tag" />
57+
</template>
58+
<template #header>
59+
<slot name="before" />
60+
</template>
61+
<template #default>
62+
<NFlex class="content">
63+
<NImage
64+
alt="poster-image"
65+
class="poster"
66+
lazy
67+
preview-disabled
68+
:src="poster"
69+
:preview-src="poster"
70+
:fallback-src="PosterPlaceholder"
71+
/>
72+
<slot :id="id" :index="index" :loading="isLoading" />
73+
</NFlex>
74+
</template>
75+
<template #footer>
76+
<slot name="after" />
77+
</template>
6078
</NTimelineItem>
6179
</template>
6280

6381
<style lang="scss" scoped>
82+
@use '~/styles/mixin' as mixin;
83+
6484
.timeline-item {
65-
font-variant-numeric: tabular-nums;
6685
margin: 0 1rem;
6786
87+
.content {
88+
@include mixin.hover-background(
89+
$from: transparent,
90+
$to: var(--bg-color-20),
91+
$transition: 0.2s var(--n-bezier)
92+
);
93+
94+
padding: 0.5rem;
95+
border-top: 1px solid rgba(255 255 255 / 10%);
96+
}
97+
6898
.poster {
6999
justify-content: center;
70100
width: 5.5rem;
@@ -73,3 +103,27 @@ const isLoading = computed(() => id?.value < 0);
73103
}
74104
}
75105
</style>
106+
107+
<style lang="scss">
108+
/* stylelint-disable selector-class-pattern -- library class name */
109+
110+
.timeline-item.n-timeline-item .n-timeline-item-content .n-timeline-item-content__meta {
111+
margin: 0;
112+
}
113+
114+
.n-timeline.n-timeline--left-placement {
115+
.timeline-item.n-timeline-item .n-timeline-item-timeline {
116+
top: -6px;
117+
}
118+
119+
.timeline-item.no-tag.n-timeline-item .n-timeline-item-timeline {
120+
.n-timeline-item-timeline__line {
121+
top: 0;
122+
}
123+
124+
.n-timeline-item-timeline__circle {
125+
display: none;
126+
}
127+
}
128+
}
129+
</style>

src/components/common/list/ListScroll.vue

+16-8
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import type { TraktClientPagination } from '~/models/trakt/trakt-client.model';
1313
1414
import ListEmpty from '~/components/common/list/ListEmpty.vue';
1515
import ListItem from '~/components/common/list/ListItem.vue';
16+
import { debounce } from '~/utils/debounce.utils';
1617
1718
const virtualList = ref<VirtualListRef>();
1819
@@ -40,7 +41,8 @@ const props = defineProps({
4041
});
4142
4243
const emits = defineEmits<{
43-
(e: 'onScroll', listRef: Ref<VirtualListRef | undefined>): void;
44+
(e: 'onScrollBottom', listRef: Ref<VirtualListRef | undefined>): void;
45+
(e: 'onScrollTop', listRef: Ref<VirtualListRef | undefined>): void;
4446
(e: 'onUpdated', listRef: Ref<VirtualListRef | undefined>): void;
4547
}>();
4648
@@ -49,16 +51,19 @@ const { items, loading, pagination } = toRefs(props);
4951
const onScrollHandler = async (e: Event) => {
5052
if (loading.value) return;
5153
if (!e?.target) return;
52-
const { scrollTop, scrollHeight, clientHeight } = e.target as HTMLDivElement;
53-
if (!scrollTop || scrollHeight !== scrollTop + clientHeight) return;
54+
const { scrollTop, scrollHeight, clientHeight } = e.target as HTMLElement;
55+
if (scrollHeight === clientHeight) return;
56+
if (!scrollTop) return emits('onScrollTop', virtualList);
57+
if (scrollHeight !== scrollTop + clientHeight) return;
5458
if (pagination?.value?.page === pagination?.value?.pageCount) return;
55-
56-
return emits('onScroll', virtualList);
59+
return emits('onScrollBottom', virtualList);
5760
};
5861
5962
const onUpdatedHandler = () => {
6063
return emits('onUpdated', virtualList);
6164
};
65+
66+
const debounceLog = debounce(e => console.info('top', e), 100);
6267
</script>
6368

6469
<template>
@@ -69,11 +74,14 @@ const onUpdatedHandler = () => {
6974
class="list-scroll"
7075
:data-length="items.length"
7176
:data-page-size="pageSize"
72-
:item-size="listOptions?.itemSize ?? 148"
77+
:item-size="listOptions?.itemSize ?? 145"
7378
:items="items"
7479
:visible-items-tag="listOptions?.visibleItemsTag ?? NTimeline"
75-
:visible-items-props="{ size: 'large', ...listOptions?.visibleItemsProps }"
76-
:padding-top="listOptions?.paddingTop ?? 56"
80+
:visible-items-props="{
81+
size: 'large',
82+
...listOptions?.visibleItemsProps,
83+
}"
84+
:padding-top="listOptions?.paddingTop ?? 60"
7785
:padding-bottom="listOptions?.paddingBottom ?? 16"
7886
@scroll="onScrollHandler"
7987
@vue:updated="onUpdatedHandler"

src/components/container/ContainerComponent.ce.vue

+14-15
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,12 @@ import { computed, ref } from 'vue';
1414
import LoadingBarProvider from '~/components/container/LoadingBarProvider.vue';
1515
import MessageProvider from '~/components/container/MessageProvider.vue';
1616
import NotificationProvider from '~/components/container/NotificationProvider.vue';
17-
import { watchPreferDark } from '~/utils';
1817
import { lazyComponent } from '~/utils/lazy.utils';
1918
2019
const AppComponent = lazyComponent(() => import('~/components/AppComponent.vue'));
2120
22-
const isDark = watchPreferDark();
23-
const theme = computed(() => (isDark.value ? darkTheme : lightTheme));
21+
const isLight = ref(false); // watchPreferLight(); TODO implement light theme
22+
const theme = computed(() => (isLight.value ? lightTheme : darkTheme));
2423
2524
const override: GlobalThemeOverrides = {
2625
// TODO red palette
@@ -92,35 +91,35 @@ const root = ref<HTMLElement>();
9291
.n-dropdown-menu,
9392
.n-date-panel,
9493
.n-virtual-list {
95-
@include mixin.hover-background;
94+
@include mixin.hover-background(var(--bg-color-80), var(--bg-color-90));
9695
97-
@media (prefers-color-scheme: light) {
98-
@include mixin.hover-background;
96+
@media (prefers-color-scheme: dark) {
97+
@include mixin.hover-background(var(--bg-color-80), var(--bg-color-90));
9998
}
10099
101-
@media (prefers-color-scheme: dark) {
102-
@include mixin.hover-background(var(--bg-black-80), var(--bg-black-90));
100+
@media (prefers-color-scheme: light) {
101+
@include mixin.hover-background(var(--bg-color-80), var(--bg-color-90));
103102
}
104103
}
105104
106105
.n-select-menu {
107-
@include mixin.hover-background(var(--bg-red-20), var(--bg-red-80));
106+
@include mixin.hover-background(var(--bg-color-20), var(--bg-color-80));
108107
109-
@media (prefers-color-scheme: light) {
110-
@include mixin.hover-background(var(--bg-red-20), var(--bg-red-80));
108+
@media (prefers-color-scheme: dark) {
109+
@include mixin.hover-background(var(--bg-color-20), var(--bg-color-80));
111110
}
112111
113-
@media (prefers-color-scheme: dark) {
114-
@include mixin.hover-background(var(--bg-black-20), var(--bg-black-80));
112+
@media (prefers-color-scheme: light) {
113+
@include mixin.hover-background(var(--bg-color-20), var(--bg-color-80));
115114
}
116115
}
117116
118117
.n-tooltip.n-tooltip {
119-
background: var(--bg-blur-bg);
118+
background: var(--bg-color);
120119
backdrop-filter: blur(var(--bg-blur));
121120
122121
&:hover {
123-
background: var(--bg-blur-bg-hover);
122+
background: var(--bg-color-hover);
124123
}
125124
126125
@media (prefers-color-scheme: light) {

src/components/views/history/HistoryComponent.vue

+2-1
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,8 @@ const onUpdated: OnUpdated = listRef => {
6363
:loading="loading"
6464
:pagination="pagination"
6565
:page-size="pageSize"
66-
@on-scroll="onScroll"
66+
@on-scroll-bottom="onScroll"
67+
@on-scroll-top="() => console.info('Scrolled to top')"
6768
@on-updated="onUpdated"
6869
>
6970
<template #default="{ item, loading: itemLoading }">

0 commit comments

Comments
 (0)