<!-- SPDX-FileCopyrightText: syuilo and misskey-project SPDX-License-Identifier: AGPL-3.0-only --> <template> <XColumn :menu="menu" :column="column" :isStacked="isStacked" :refresher="async () => { await timeline?.reloadTimeline() }"> <template #header> <i v-if="column.tl != null" :class="basicTimelineIconClass(column.tl)"/> <span style="margin-left: 8px;">{{ column.name }}</span> </template> <div v-if="!isAvailableBasicTimeline(column.tl)" :class="$style.disabled"> <p :class="$style.disabledTitle"> <i class="ti ti-circle-minus"></i> {{ i18n.ts._disabledTimeline.title }} </p> <p :class="$style.disabledDescription">{{ i18n.ts._disabledTimeline.description }}</p> </div> <MkTimeline v-else-if="column.tl" ref="timeline" :key="column.tl + withRenotes + withReplies + onlyFiles" :src="column.tl" :withRenotes="withRenotes" :withReplies="withReplies" :onlyFiles="onlyFiles" @note="onNote" /> </XColumn> </template> <script lang="ts" setup> import { onMounted, watch, ref, shallowRef, computed } from 'vue'; import XColumn from './column.vue'; import { removeColumn, updateColumn, Column } from './deck-store.js'; import type { MenuItem } from '@/types/menu.js'; import MkTimeline from '@/components/MkTimeline.vue'; import * as os from '@/os.js'; import { i18n } from '@/i18n.js'; import { hasWithReplies, isAvailableBasicTimeline, basicTimelineIconClass } from '@/timelines.js'; import { instance } from '@/instance.js'; import { SoundStore } from '@/store.js'; import { soundSettingsButton } from '@/ui/deck/tl-note-notification.js'; import * as sound from '@/scripts/sound.js'; const props = defineProps<{ column: Column; isStacked: boolean; }>(); const timeline = shallowRef<InstanceType<typeof MkTimeline>>(); const soundSetting = ref<SoundStore>(props.column.soundSetting ?? { type: null, volume: 1 }); const withRenotes = ref(props.column.withRenotes ?? true); const withReplies = ref(props.column.withReplies ?? false); const onlyFiles = ref(props.column.onlyFiles ?? false); watch(withRenotes, v => { updateColumn(props.column.id, { withRenotes: v, }); }); watch(withReplies, v => { updateColumn(props.column.id, { withReplies: v, }); }); watch(onlyFiles, v => { updateColumn(props.column.id, { onlyFiles: v, }); }); watch(soundSetting, v => { updateColumn(props.column.id, { soundSetting: v }); }); onMounted(() => { if (props.column.tl == null) { setType(); } }); async function setType() { const { canceled, result: src } = await os.select({ title: i18n.ts.timeline, items: [{ value: 'home' as const, text: i18n.ts._timelines.home, }, { value: 'local' as const, text: i18n.ts._timelines.local, }, { value: 'social' as const, text: i18n.ts._timelines.social, }, { value: 'global' as const, text: i18n.ts._timelines.global, }], }); if (canceled) { if (props.column.tl == null) { removeColumn(props.column.id); } return; } if (src == null) return; updateColumn(props.column.id, { tl: src ?? undefined, }); } function onNote() { sound.playMisskeySfxFile(soundSetting.value); } const menu = computed<MenuItem[]>(() => [{ icon: 'ti ti-pencil', text: i18n.ts.timeline, action: setType, }, { icon: 'ti ti-bell', text: i18n.ts._deck.newNoteNotificationSettings, action: () => soundSettingsButton(soundSetting), }, { type: 'switch', text: i18n.ts.showRenotes, ref: withRenotes, }, hasWithReplies(props.column.tl) ? { type: 'switch', text: i18n.ts.showRepliesToOthersInTimeline, ref: withReplies, disabled: onlyFiles, } : undefined, { type: 'switch', text: i18n.ts.fileAttachedOnly, ref: onlyFiles, disabled: hasWithReplies(props.column.tl) ? withReplies : false, }]); </script> <style lang="scss" module> .disabled { text-align: center; } .disabledTitle { margin: 16px; } .disabledDescription { font-size: 90%; } </style>