merge upstream
This commit is contained in:
@@ -4,15 +4,14 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||
-->
|
||||
|
||||
<template>
|
||||
<MkStickyContainer>
|
||||
<template #header><MkPageHeader v-model:tab="src" :actions="headerActions" :tabs="$i ? headerTabs : headerTabsWhenNotLogin" :displayMyAvatar="true"/></template>
|
||||
<PageWithHeader v-model:tab="src" :actions="headerActions" :tabs="$i ? headerTabs : headerTabsWhenNotLogin" :displayMyAvatar="true">
|
||||
<MkSpacer :contentMax="800">
|
||||
<MkHorizontalSwipe v-model:tab="src" :tabs="$i ? headerTabs : headerTabsWhenNotLogin">
|
||||
<div :key="src" ref="rootEl">
|
||||
<MkInfo v-if="isBasicTimeline(src) && !defaultStore.reactiveState.timelineTutorials.value[src]" style="margin-bottom: var(--MI-margin);" closable @close="closeTutorial()">
|
||||
<div ref="rootEl">
|
||||
<MkInfo v-if="isBasicTimeline(src) && !store.r.timelineTutorials.value[src]" style="margin-bottom: var(--MI-margin);" closable @close="closeTutorial()">
|
||||
{{ i18n.ts._timelineDescription[src] }}
|
||||
</MkInfo>
|
||||
<MkPostForm v-if="defaultStore.reactiveState.showFixedPostForm.value" :class="$style.postForm" class="post-form _panel" fixed style="margin-bottom: var(--MI-margin);"/>
|
||||
<MkPostForm v-if="prefer.r.showFixedPostForm.value" :class="$style.postForm" class="post-form _panel" fixed style="margin-bottom: var(--MI-margin);"/>
|
||||
<div v-if="queue > 0" :class="$style.new"><button class="_buttonPrimary" :class="$style.newButton" @click="top()">{{ i18n.ts.newNoteRecived }}</button></div>
|
||||
<div :class="$style.tl">
|
||||
<MkTimeline
|
||||
@@ -32,56 +31,60 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||
</div>
|
||||
</MkHorizontalSwipe>
|
||||
</MkSpacer>
|
||||
</MkStickyContainer>
|
||||
</PageWithHeader>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed, watch, provide, shallowRef, ref, onMounted, onActivated } from 'vue';
|
||||
import { computed, watch, provide, useTemplateRef, ref, onMounted, onActivated } from 'vue';
|
||||
import { scroll } from '@@/js/scroll.js';
|
||||
import type { Tab } from '@/components/global/MkPageHeader.tabs.vue';
|
||||
import type { MenuItem } from '@/types/menu.js';
|
||||
import type { BasicTimelineType } from '@/timelines.js';
|
||||
import MkTimeline from '@/components/MkTimeline.vue';
|
||||
import MkInfo from '@/components/MkInfo.vue';
|
||||
import MkPostForm from '@/components/MkPostForm.vue';
|
||||
import MkHorizontalSwipe from '@/components/MkHorizontalSwipe.vue';
|
||||
import { scroll } from '@@/js/scroll.js';
|
||||
import * as os from '@/os.js';
|
||||
import { misskeyApi } from '@/scripts/misskey-api.js';
|
||||
import { defaultStore } from '@/store.js';
|
||||
import { misskeyApi } from '@/utility/misskey-api.js';
|
||||
import { store } from '@/store.js';
|
||||
import { i18n } from '@/i18n.js';
|
||||
import { $i } from '@/account.js';
|
||||
import { definePageMetadata } from '@/scripts/page-metadata.js';
|
||||
import { $i } from '@/i.js';
|
||||
import { definePage } from '@/page.js';
|
||||
import { antennasCache, userListsCache, favoritedChannelsCache } from '@/cache.js';
|
||||
import { deviceKind } from '@/scripts/device-kind.js';
|
||||
import { deepMerge } from '@/scripts/merge.js';
|
||||
import type { MenuItem } from '@/types/menu.js';
|
||||
import { deviceKind } from '@/utility/device-kind.js';
|
||||
import { deepMerge } from '@/utility/merge.js';
|
||||
import { miLocalStorage } from '@/local-storage.js';
|
||||
import { availableBasicTimelines, hasWithReplies, isAvailableBasicTimeline, isBasicTimeline, basicTimelineIconClass } from '@/timelines.js';
|
||||
import type { BasicTimelineType } from '@/timelines.js';
|
||||
import { useRouter } from '@/router/supplier.js';
|
||||
import { prefer } from '@/preferences.js';
|
||||
import { useRouter } from '@/router.js';
|
||||
|
||||
provide('shouldOmitHeaderTitle', true);
|
||||
|
||||
const router = useRouter();
|
||||
const tlComponent = useTemplateRef('tlComponent');
|
||||
const rootEl = useTemplateRef('rootEl');
|
||||
|
||||
const tlComponent = shallowRef<InstanceType<typeof MkTimeline>>();
|
||||
const rootEl = shallowRef<HTMLElement>();
|
||||
const router = useRouter();
|
||||
router.useListener('same', () => {
|
||||
top();
|
||||
});
|
||||
|
||||
type TimelinePageSrc = BasicTimelineType | `list:${string}`;
|
||||
|
||||
const queue = ref(0);
|
||||
const srcWhenNotSignin = ref<'local' | 'global'>(isAvailableBasicTimeline('local') ? 'local' : 'global');
|
||||
const src = computed<TimelinePageSrc>({
|
||||
get: () => ($i ? defaultStore.reactiveState.tl.value.src : srcWhenNotSignin.value),
|
||||
get: () => ($i ? store.r.tl.value.src : srcWhenNotSignin.value),
|
||||
set: (x) => saveSrc(x),
|
||||
});
|
||||
const withRenotes = computed<boolean>({
|
||||
get: () => defaultStore.reactiveState.tl.value.filter.withRenotes,
|
||||
get: () => store.r.tl.value.filter.withRenotes,
|
||||
set: (x) => saveTlFilter('withRenotes', x),
|
||||
});
|
||||
|
||||
// computed内での無限ループを防ぐためのフラグ
|
||||
const localSocialTLFilterSwitchStore = ref<'withReplies' | 'onlyFiles' | false>(
|
||||
defaultStore.reactiveState.tl.value.filter.withReplies ? 'withReplies' :
|
||||
defaultStore.reactiveState.tl.value.filter.onlyFiles ? 'onlyFiles' :
|
||||
store.r.tl.value.filter.withReplies ? 'withReplies' :
|
||||
store.r.tl.value.filter.onlyFiles ? 'onlyFiles' :
|
||||
false,
|
||||
);
|
||||
|
||||
@@ -91,7 +94,7 @@ const withReplies = computed<boolean>({
|
||||
if (['local', 'social'].includes(src.value) && localSocialTLFilterSwitchStore.value === 'onlyFiles') {
|
||||
return false;
|
||||
} else {
|
||||
return defaultStore.reactiveState.tl.value.filter.withReplies;
|
||||
return store.r.tl.value.filter.withReplies;
|
||||
}
|
||||
},
|
||||
set: (x) => saveTlFilter('withReplies', x),
|
||||
@@ -106,7 +109,7 @@ const onlyFiles = computed<boolean>({
|
||||
if (['local', 'social'].includes(src.value) && localSocialTLFilterSwitchStore.value === 'withReplies') {
|
||||
return false;
|
||||
} else {
|
||||
return defaultStore.reactiveState.tl.value.filter.onlyFiles;
|
||||
return store.r.tl.value.filter.onlyFiles;
|
||||
}
|
||||
},
|
||||
set: (x) => saveTlFilter('onlyFiles', x),
|
||||
@@ -123,7 +126,7 @@ watch([withReplies, onlyFiles], ([withRepliesTo, onlyFilesTo]) => {
|
||||
});
|
||||
|
||||
const withSensitive = computed<boolean>({
|
||||
get: () => defaultStore.reactiveState.tl.value.filter.withSensitive,
|
||||
get: () => store.r.tl.value.filter.withSensitive,
|
||||
set: (x) => saveTlFilter('withSensitive', x),
|
||||
});
|
||||
|
||||
@@ -136,7 +139,7 @@ function queueUpdated(q: number): void {
|
||||
}
|
||||
|
||||
function top(): void {
|
||||
if (rootEl.value) scroll(rootEl.value, { top: 0 });
|
||||
if (rootEl.value) scroll(rootEl.value, { top: 0, behavior: 'smooth' });
|
||||
}
|
||||
|
||||
async function chooseList(ev: MouseEvent): Promise<void> {
|
||||
@@ -204,23 +207,23 @@ async function chooseChannel(ev: MouseEvent): Promise<void> {
|
||||
}
|
||||
|
||||
function saveSrc(newSrc: TimelinePageSrc): void {
|
||||
const out = deepMerge({ src: newSrc }, defaultStore.state.tl);
|
||||
const out = deepMerge({ src: newSrc }, store.s.tl);
|
||||
|
||||
if (newSrc.startsWith('userList:')) {
|
||||
const id = newSrc.substring('userList:'.length);
|
||||
out.userList = defaultStore.reactiveState.pinnedUserLists.value.find(l => l.id === id) ?? null;
|
||||
out.userList = prefer.r.pinnedUserLists.value.find(l => l.id === id) ?? null;
|
||||
}
|
||||
|
||||
defaultStore.set('tl', out);
|
||||
store.set('tl', out);
|
||||
if (['local', 'global'].includes(newSrc)) {
|
||||
srcWhenNotSignin.value = newSrc as 'local' | 'global';
|
||||
}
|
||||
}
|
||||
|
||||
function saveTlFilter(key: keyof typeof defaultStore.state.tl.filter, newValue: boolean) {
|
||||
function saveTlFilter(key: keyof typeof store.s.tl.filter, newValue: boolean) {
|
||||
if (key !== 'withReplies' || $i) {
|
||||
const out = deepMerge({ filter: { [key]: newValue } }, defaultStore.state.tl);
|
||||
defaultStore.set('tl', out);
|
||||
const out = deepMerge({ filter: { [key]: newValue } }, store.s.tl);
|
||||
store.set('tl', out);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -239,9 +242,9 @@ function focus(): void {
|
||||
|
||||
function closeTutorial(): void {
|
||||
if (!isBasicTimeline(src.value)) return;
|
||||
const before = defaultStore.state.timelineTutorials;
|
||||
const before = store.s.timelineTutorials;
|
||||
before[src.value] = true;
|
||||
defaultStore.set('timelineTutorials', before);
|
||||
store.set('timelineTutorials', before);
|
||||
}
|
||||
|
||||
function switchTlIfNeeded() {
|
||||
@@ -311,7 +314,7 @@ const headerActions = computed(() => {
|
||||
return tmp;
|
||||
});
|
||||
|
||||
const headerTabs = computed(() => [...(defaultStore.reactiveState.pinnedUserLists.value.map(l => ({
|
||||
const headerTabs = computed(() => [...(prefer.r.pinnedUserLists.value.map(l => ({
|
||||
key: 'list:' + l.id,
|
||||
title: l.name,
|
||||
icon: 'ti ti-star',
|
||||
@@ -350,7 +353,7 @@ const headerTabsWhenNotLogin = computed(() => [...availableBasicTimelines().map(
|
||||
iconOnly: true,
|
||||
}))] as Tab[]);
|
||||
|
||||
definePageMetadata(() => ({
|
||||
definePage(() => ({
|
||||
title: i18n.ts.timeline,
|
||||
icon: isBasicTimeline(src.value) ? basicTimelineIconClass(src.value) : 'ti ti-home',
|
||||
}));
|
||||
|
||||
Reference in New Issue
Block a user