This commit is contained in:
syuilo 2025-05-06 12:36:32 +09:00
parent 9d30b683f2
commit b79fa38223
3 changed files with 65 additions and 17 deletions

4
locales/index.d.ts vendored
View File

@ -3162,10 +3162,6 @@ export interface Locale extends ILocale {
*
*/
"makeExplorableDescription": string;
/**
*
*/
"showGapBetweenNotesInTimeline": string;
/**
*
*/

View File

@ -35,7 +35,15 @@ SPDX-License-Identifier: AGPL-3.0-only
tag="div"
>
<template v-for="(note, i) in paginator.items.value" :key="note.id">
<div v-if="note._shouldInsertAd_" :data-scroll-anchor="note.id">
<div v-if="i > 0 && isSeparatorNeeded(paginator.items.value[i -1].createdAt, note.createdAt)" :data-scroll-anchor="note.id">
<div :class="$style.date">
<span><i class="ti ti-chevron-up"></i> {{ getSeparatorInfo(paginator.items.value[i -1].createdAt, note.createdAt).prevText }}</span>
<span style="height: 1em; width: 1px; background: var(--MI_THEME-divider);"></span>
<span>{{ getSeparatorInfo(paginator.items.value[i -1].createdAt, note.createdAt).nextText }} <i class="ti ti-chevron-down"></i></span>
</div>
<MkNote :class="$style.note" :note="note" :withHardMute="true"/>
</div>
<div v-else-if="note._shouldInsertAd_" :data-scroll-anchor="note.id">
<MkNote :class="$style.note" :note="note" :withHardMute="true"/>
<div :class="$style.ad">
<MkAd :preferForms="['horizontal', 'horizontal-big']"/>
@ -72,6 +80,7 @@ import MkButton from '@/components/MkButton.vue';
import { i18n } from '@/i18n.js';
import { infoImageUrl } from '@/instance.js';
import { globalEvents, useGlobalEvent } from '@/events.js';
import { isSeparatorNeeded, getSeparatorInfo } from '@/utility/timeline-date-separate.js';
const props = withDefaults(defineProps<{
src: BasicTimelineType | 'mentions' | 'directs' | 'list' | 'antenna' | 'channel' | 'role';
@ -414,17 +423,10 @@ defineExpose({
.notes {
container-type: inline-size;
background: var(--MI_THEME-panel);
}
.note:not(:last-child) {
.note {
border-bottom: solid 0.5px var(--MI_THEME-divider);
}
.ad {
padding: 8px;
background-size: auto auto;
background-image: repeating-linear-gradient(45deg, transparent, transparent 8px, var(--MI_THEME-bg) 8px, var(--MI_THEME-bg) 14px);
border-bottom: solid 0.5px var(--MI_THEME-divider);
}
}
.new {
@ -501,8 +503,27 @@ defineExpose({
}
}
.ad:empty {
.date {
display: flex;
font-size: 85%;
align-items: center;
justify-content: center;
gap: 1em;
opacity: 0.75;
padding: 8px 8px;
margin: 0 auto;
border-bottom: solid 0.5px var(--MI_THEME-divider);
}
.ad {
padding: 8px;
background-size: auto auto;
background-image: repeating-linear-gradient(45deg, transparent, transparent 8px, var(--MI_THEME-bg) 8px, var(--MI_THEME-bg) 14px);
border-bottom: solid 0.5px var(--MI_THEME-divider);
&:empty {
display: none;
}
}
.more {

View File

@ -25,6 +25,37 @@ export type DateSeparetedTimelineItem<T> = {
nextText: string;
};
// TODO: いちいちDateインスタンス作成するのは無駄感あるから文字列のまま解析したい
export function isSeparatorNeeded(
prev: string | null,
next: string | null,
) {
if (prev == null || next == null) return false;
const prevDate = new Date(prev);
const nextDate = new Date(next);
return (
prevDate.getFullYear() !== nextDate.getFullYear() ||
prevDate.getMonth() !== nextDate.getMonth() ||
prevDate.getDate() !== nextDate.getDate()
);
}
// TODO: いちいちDateインスタンス作成するのは無駄感あるから文字列のまま解析したい
export function getSeparatorInfo(
prev: string | null,
next: string | null,
) {
if (prev == null || next == null) return null;
const prevDate = new Date(prev);
const nextDate = new Date(next);
return {
prevDate,
prevText: getDateText(prevDate),
nextDate,
nextText: getDateText(nextDate),
};
}
export function makeDateSeparatedTimelineComputedRef<T extends { id: string; createdAt: string; }>(items: Ref<T[]>) {
return computed<DateSeparetedTimelineItem<T>[]>(() => {
const tl: DateSeparetedTimelineItem<T>[] = [];