This commit is contained in:
parent
e07bb1dcbc
commit
8b7cba1ede
|
@ -38,7 +38,14 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
:moveClass="prefer.s.animation ? $style.transition_x_move : ''"
|
:moveClass="prefer.s.animation ? $style.transition_x_move : ''"
|
||||||
tag="div" class="_gaps"
|
tag="div" class="_gaps"
|
||||||
>
|
>
|
||||||
<XMessage v-for="message in messages.toReversed()" :key="message.id" :message="message"/>
|
<template v-for="item in timeline.toReversed()" :key="item.id">
|
||||||
|
<XMessage v-if="item.type === 'item'" :message="item.data"/>
|
||||||
|
<div v-else-if="item.type === 'date'" :class="$style.dateDivider">
|
||||||
|
<span><i class="ti ti-chevron-up"></i> {{ item.nextText }}</span>
|
||||||
|
<span style="height: 1em; width: 1px; background: var(--MI_THEME-divider);"></span>
|
||||||
|
<span>{{ item.prevText }} <i class="ti ti-chevron-down"></i></span>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
</TransitionGroup>
|
</TransitionGroup>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -101,6 +108,7 @@ import MkButton from '@/components/MkButton.vue';
|
||||||
import { useRouter } from '@/router.js';
|
import { useRouter } from '@/router.js';
|
||||||
import { useMutationObserver } from '@/use/use-mutation-observer.js';
|
import { useMutationObserver } from '@/use/use-mutation-observer.js';
|
||||||
import MkInfo from '@/components/MkInfo.vue';
|
import MkInfo from '@/components/MkInfo.vue';
|
||||||
|
import { makeDateSeparatedTimelineComputedRef } from '@/utility/timeline-date-separate.js';
|
||||||
|
|
||||||
const $i = ensureSignin();
|
const $i = ensureSignin();
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
@ -126,6 +134,7 @@ const room = ref<Misskey.entities.ChatRoom | null>(null);
|
||||||
const connection = ref<Misskey.IChannelConnection<Misskey.Channels['chatUser']> | Misskey.IChannelConnection<Misskey.Channels['chatRoom']> | null>(null);
|
const connection = ref<Misskey.IChannelConnection<Misskey.Channels['chatUser']> | Misskey.IChannelConnection<Misskey.Channels['chatRoom']> | null>(null);
|
||||||
const showIndicator = ref(false);
|
const showIndicator = ref(false);
|
||||||
const timelineEl = useTemplateRef('timelineEl');
|
const timelineEl = useTemplateRef('timelineEl');
|
||||||
|
const timeline = makeDateSeparatedTimelineComputedRef(messages);
|
||||||
|
|
||||||
const SCROLL_HEAD_THRESHOLD = 200;
|
const SCROLL_HEAD_THRESHOLD = 200;
|
||||||
|
|
||||||
|
@ -489,4 +498,18 @@ definePage(computed(() => {
|
||||||
transition: opacity 0.5s;
|
transition: opacity 0.5s;
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.dateDivider {
|
||||||
|
display: flex;
|
||||||
|
font-size: 85%;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 0.5em;
|
||||||
|
opacity: 0.75;
|
||||||
|
border: solid 0.5px var(--MI_THEME-divider);
|
||||||
|
border-radius: 999px;
|
||||||
|
width: fit-content;
|
||||||
|
padding: 0.5em 1em;
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -0,0 +1,63 @@
|
||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: syuilo and misskey-project
|
||||||
|
* SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { computed } from 'vue';
|
||||||
|
import type { Ref } from 'vue';
|
||||||
|
|
||||||
|
function getDateText(dateInstance: Date) {
|
||||||
|
const date = dateInstance.getDate();
|
||||||
|
const month = dateInstance.getMonth() + 1;
|
||||||
|
return `${month.toString()}/${date.toString()}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type DateSeparetedTimelineItem<T> = {
|
||||||
|
id: string;
|
||||||
|
type: 'item';
|
||||||
|
data: T;
|
||||||
|
} | {
|
||||||
|
id: string;
|
||||||
|
type: 'date';
|
||||||
|
prev: Date;
|
||||||
|
prevText: string;
|
||||||
|
next: Date;
|
||||||
|
nextText: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export function makeDateSeparatedTimelineComputedRef<T extends { id: string; createdAt: string; }>(items: Ref<T[]>) {
|
||||||
|
return computed<DateSeparetedTimelineItem<T>[]>(() => {
|
||||||
|
const tl: DateSeparetedTimelineItem<T>[] = [];
|
||||||
|
for (let i = 0; i < items.value.length; i++) {
|
||||||
|
const item = items.value[i];
|
||||||
|
|
||||||
|
const date = new Date(item.createdAt);
|
||||||
|
const nextDate = items.value[i + 1] ? new Date(items.value[i + 1].createdAt) : null;
|
||||||
|
|
||||||
|
tl.push({
|
||||||
|
id: item.id,
|
||||||
|
type: 'item',
|
||||||
|
data: item,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (
|
||||||
|
i !== items.value.length - 1 &&
|
||||||
|
nextDate != null && (
|
||||||
|
date.getFullYear() !== nextDate.getFullYear() ||
|
||||||
|
date.getMonth() !== nextDate.getMonth() ||
|
||||||
|
date.getDate() !== nextDate.getDate()
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
tl.push({
|
||||||
|
id: `date-${item.id}`,
|
||||||
|
type: 'date',
|
||||||
|
prev: date,
|
||||||
|
prevText: getDateText(date),
|
||||||
|
next: nextDate,
|
||||||
|
nextText: getDateText(nextDate),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return tl;
|
||||||
|
});
|
||||||
|
}
|
Loading…
Reference in New Issue