enhance(frontend): タイムラインをスワイプで切り替えられるように

Resolve #15722
This commit is contained in:
syuilo 2025-04-27 17:38:48 +09:00
parent 889295d621
commit 14d3439a42
2 changed files with 38 additions and 42 deletions

View File

@ -8,7 +8,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<MkStickyContainer> <MkStickyContainer>
<template #header><MkPageHeader v-model:tab="tab" v-bind="pageHeaderProps"/></template> <template #header><MkPageHeader v-model:tab="tab" v-bind="pageHeaderProps"/></template>
<div :class="$style.body"> <div :class="$style.body">
<MkSwiper v-if="swipable" v-model:tab="tab" :tabs="props.tabs"> <MkSwiper v-if="swipable" v-model:tab="tab" :class="$style.swiper" :tabs="props.tabs">
<slot></slot> <slot></slot>
</MkSwiper> </MkSwiper>
<slot v-else></slot> <slot v-else></slot>
@ -24,6 +24,7 @@ import { scrollInContainer } from '@@/js/scroll.js';
import type { PageHeaderProps } from './MkPageHeader.vue'; import type { PageHeaderProps } from './MkPageHeader.vue';
import { useScrollPositionKeeper } from '@/use/use-scroll-position-keeper.js'; import { useScrollPositionKeeper } from '@/use/use-scroll-position-keeper.js';
import MkSwiper from '@/components/MkSwiper.vue'; import MkSwiper from '@/components/MkSwiper.vue';
import { useRouter } from '@/router.js';
const props = defineProps<PageHeaderProps & { const props = defineProps<PageHeaderProps & {
reversed?: boolean; reversed?: boolean;
@ -40,10 +41,18 @@ const rootEl = useTemplateRef('rootEl');
useScrollPositionKeeper(rootEl); useScrollPositionKeeper(rootEl);
const router = useRouter();
router.useListener('same', () => {
scrollToTop();
});
function scrollToTop() {
if (rootEl.value) scrollInContainer(rootEl.value, { top: 0, behavior: 'smooth' });
}
defineExpose({ defineExpose({
scrollToTop: () => { scrollToTop,
if (rootEl.value) scrollInContainer(rootEl.value, { top: 0, behavior: 'smooth' });
},
}); });
</script> </script>
@ -52,7 +61,7 @@ defineExpose({
} }
.body { .body, .swiper {
min-height: calc(100cqh - (var(--MI-stickyTop, 0px) + var(--MI-stickyBottom, 0px))); min-height: calc(100cqh - (var(--MI-stickyTop, 0px) + var(--MI-stickyBottom, 0px)));
} }
</style> </style>

View File

@ -4,36 +4,32 @@ SPDX-License-Identifier: AGPL-3.0-only
--> -->
<template> <template>
<div ref="rootEl" class="_pageScrollable"> <PageWithHeader ref="pageComponent" v-model:tab="src" :actions="headerActions" :tabs="$i ? headerTabs : headerTabsWhenNotLogin" :swipable="true" :displayMyAvatar="true">
<MkStickyContainer> <MkSpacer :contentMax="800">
<template #header><MkPageHeader v-model:tab="src" :displayMyAvatar="true" :actions="headerActions" :tabs="$i ? headerTabs : headerTabsWhenNotLogin"/></template> <MkInfo v-if="isBasicTimeline(src) && !store.r.timelineTutorials.value[src]" style="margin-bottom: var(--MI-margin);" closable @close="closeTutorial()">
<MkSpacer :contentMax="800"> {{ i18n.ts._timelineDescription[src] }}
<MkInfo v-if="isBasicTimeline(src) && !store.r.timelineTutorials.value[src]" style="margin-bottom: var(--MI-margin);" closable @close="closeTutorial()"> </MkInfo>
{{ i18n.ts._timelineDescription[src] }} <MkPostForm v-if="prefer.r.showFixedPostForm.value" :class="$style.postForm" class="_panel" fixed style="margin-bottom: var(--MI-margin);"/>
</MkInfo> <div v-if="queue > 0" :class="$style.new"><button class="_buttonPrimary" :class="$style.newButton" @click="top()">{{ i18n.ts.newNoteRecived }}</button></div>
<MkPostForm v-if="prefer.r.showFixedPostForm.value" :class="$style.postForm" class="_panel" fixed style="margin-bottom: var(--MI-margin);"/> <MkTimeline
<div v-if="queue > 0" :class="$style.new"><button class="_buttonPrimary" :class="$style.newButton" @click="top()">{{ i18n.ts.newNoteRecived }}</button></div> ref="tlComponent"
<MkTimeline :key="src + withRenotes + withReplies + onlyFiles + withSensitive"
ref="tlComponent" :class="$style.tl"
:key="src + withRenotes + withReplies + onlyFiles + withSensitive" :src="src.split(':')[0]"
:class="$style.tl" :list="src.split(':')[1]"
:src="src.split(':')[0]" :withRenotes="withRenotes"
:list="src.split(':')[1]" :withReplies="withReplies"
:withRenotes="withRenotes" :withSensitive="withSensitive"
:withReplies="withReplies" :onlyFiles="onlyFiles"
:withSensitive="withSensitive" :sound="true"
:onlyFiles="onlyFiles" @queue="queueUpdated"
:sound="true" />
@queue="queueUpdated" </MkSpacer>
/> </PageWithHeader>
</MkSpacer>
</MkStickyContainer>
</div>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { computed, watch, provide, useTemplateRef, ref, onMounted, onActivated } from 'vue'; import { computed, watch, provide, useTemplateRef, ref, onMounted, onActivated } from 'vue';
import { scrollInContainer } from '@@/js/scroll.js';
import type { Tab } from '@/components/global/MkPageHeader.tabs.vue'; import type { Tab } from '@/components/global/MkPageHeader.tabs.vue';
import type { MenuItem } from '@/types/menu.js'; import type { MenuItem } from '@/types/menu.js';
import type { BasicTimelineType } from '@/timelines.js'; import type { BasicTimelineType } from '@/timelines.js';
@ -51,20 +47,11 @@ import { deepMerge } from '@/utility/merge.js';
import { miLocalStorage } from '@/local-storage.js'; import { miLocalStorage } from '@/local-storage.js';
import { availableBasicTimelines, hasWithReplies, isAvailableBasicTimeline, isBasicTimeline, basicTimelineIconClass } from '@/timelines.js'; import { availableBasicTimelines, hasWithReplies, isAvailableBasicTimeline, isBasicTimeline, basicTimelineIconClass } from '@/timelines.js';
import { prefer } from '@/preferences.js'; import { prefer } from '@/preferences.js';
import { useRouter } from '@/router.js';
import { useScrollPositionKeeper } from '@/use/use-scroll-position-keeper.js';
provide('shouldOmitHeaderTitle', true); provide('shouldOmitHeaderTitle', true);
const tlComponent = useTemplateRef('tlComponent'); const tlComponent = useTemplateRef('tlComponent');
const rootEl = useTemplateRef('rootEl'); const pageComponent = useTemplateRef('pageComponent');
useScrollPositionKeeper(rootEl);
const router = useRouter();
router.useListener('same', () => {
top();
});
type TimelinePageSrc = BasicTimelineType | `list:${string}`; type TimelinePageSrc = BasicTimelineType | `list:${string}`;
@ -132,7 +119,7 @@ function queueUpdated(q: number): void {
} }
function top(): void { function top(): void {
if (rootEl.value) scrollInContainer(rootEl.value, { top: 0, behavior: 'instant' }); if (pageComponent.value) pageComponent.value.scrollToTop();
} }
async function chooseList(ev: MouseEvent): Promise<void> { async function chooseList(ev: MouseEvent): Promise<void> {