This commit is contained in:
mattyatea 2024-02-11 20:23:39 +09:00
parent 0cf3082902
commit 399f7c451b
11 changed files with 691 additions and 613 deletions

4
locales/index.d.ts vendored
View File

@ -84,6 +84,10 @@ export interface Locale extends ILocale {
*
*/
"ruby": string;
/**
*
*/
"pinnedChannel": string;
/**
*
*/

View File

@ -17,6 +17,7 @@ notificationIndicator: "通知のインジケーターの数字を表示する"
hanntenn: "アイコンとバナーを反転させる"
hanntennInfo: "ダークだったらライトのアイコンに、ライトだったらダークのアイコンに。"
ruby: "ルビ"
pinnedChannel: "ピン留めされたチャンネル"
gotIt: "わかった"
cancel: "キャンセル"
myLists: "自分の作成したリスト"

View File

@ -12,3 +12,5 @@ export const rolesCache = new Cache(1000 * 60 * 30, () => misskeyApi('admin/role
export const userListsCache = new Cache<Misskey.entities.UserList[]>(1000 * 60 * 30, () => misskeyApi('users/lists/list'));
export const antennasCache = new Cache<Misskey.entities.Antenna[]>(1000 * 60 * 30, () => misskeyApi('antennas/list'));
export const userFavoriteListsCache = new Cache(1000 * 60 * 30, () => misskeyApi('users/lists/list-favorite'));
export const userChannelsCache = new Cache<Misskey.entities.UserChannel[]>(1000 * 60 * 30, () => misskeyApi('channels/owned'));
export const userChannelFollowingsCache = new Cache<Misskey.entities.UserChannelFollowing[]>(1000 * 60 * 30, () => misskeyApi('channels/followed'));

File diff suppressed because it is too large Load Diff

View File

@ -38,6 +38,7 @@ const props = withDefaults(defineProps<{
withRenotes?: boolean;
withReplies?: boolean;
onlyFiles?: boolean;
}>(), {
withRenotes: true,
withReplies: false,

View File

@ -177,7 +177,6 @@ onUnmounted(() => {
margin-left: 0;
}
> .titleContainer {
margin: 0 auto;
max-width: 100%;
}
}

View File

@ -38,7 +38,6 @@ SPDX-License-Identifier: AGPL-3.0-only
<!-- スマホタブレットの場合キーボードが表示されると投稿が見づらくなるのでデスクトップ場合のみ自動でフォーカスを当てる -->
<MkPostForm v-if="$i && defaultStore.reactiveState.showFixedPostFormInChannel.value" :channel="channel" class="post-form _panel" fixed :autofocus="deviceKind === 'desktop'"/>
<MkTimeline :key="channelId" src="channel" :channel="channelId" @before="before" @after="after" @note="miLocalStorage.setItemAsJson(`channelLastReadedAt:${channel.id}`, Date.now())"/>
</div>
<div v-else-if="tab === 'featured'" key="featured">

View File

@ -23,7 +23,7 @@ SPDX-License-Identifier: AGPL-3.0-only
</template>
<script lang="ts" setup>
import { computed, ref } from 'vue';
import { computed, onMounted, ref } from 'vue';
import XNotifications from '@/components/MkNotifications.vue';
import MkNotes from '@/components/MkNotes.vue';
import MkHorizontalSwipe from '@/components/MkHorizontalSwipe.vue';
@ -74,7 +74,7 @@ const headerActions = computed(() => [{
highlighted: includeTypes.value != null,
handler: setFilter,
}].filter(x => x !== undefined));
misskeyApi('notifications/mark-all-as-read');
const headerTabs = computed(() => [{
key: 'all',
title: i18n.ts.all,
@ -93,6 +93,9 @@ definePageMetadata(computed(() => ({
title: i18n.ts.notifications,
icon: 'ti ti-bell',
})));
onMounted(() => {
misskeyApi('notifications/mark-all-as-read');
});
</script>
<style module lang="scss">

View File

@ -45,10 +45,18 @@ SPDX-License-Identifier: AGPL-3.0-only
<MkButton v-if="pinnedMax > defaultStore.reactiveState.pinnedUserLists.value.length " @click="setPinnedList()">{{ i18n.ts.add }}</MkButton>
<MkButton v-if="defaultStore.reactiveState.pinnedUserLists.value.length " danger @click="removePinnedList('all')"><i class="ti ti-trash"></i> {{ i18n.ts.all }}{{ i18n.ts.remove }}</MkButton>
</MkFolder>
<MkFolder>
<template #label>{{ i18n.ts.pinnedChannel }}</template>
<div v-for="pinnedLists in defaultStore.reactiveState.pinnedChannels.value" class="_margin">
{{ pinnedLists.name }}
<MkButton danger @click="removePinnedChannel(pinnedLists.id,pinnedLists.name)"><i class="ti ti-trash"></i> {{ i18n.ts.remove }}</MkButton>
</div>
<MkButton v-if="pinnedMax > defaultStore.reactiveState.pinnedChannels.value.length " @click="setPinnedChannel()">{{ i18n.ts.add }}</MkButton>
<MkButton v-if="defaultStore.reactiveState.pinnedChannels.value.length " danger @click="removePinnedChannel('all')"><i class="ti ti-trash"></i> {{ i18n.ts.all }}{{ i18n.ts.remove }}</MkButton>
</MkFolder>
<MkFoldableSection :expanded="false" class="item">
<template #header>{{ i18n.ts.topbarCustom }}</template>
{{ i18n.ts._timelines.home }}
<MkSwitch v-model="showHomeTimeline">{{ i18n.ts.enable }}</MkSwitch>
<br>
@ -379,7 +387,7 @@ import { claimAchievement } from '@/scripts/achievements.js';
import MkColorInput from '@/components/MkColorInput.vue';
import MkFoldableSection from '@/components/MkFoldableSection.vue';
import MkInput from '@/components/MkInput.vue';
import { userFavoriteListsCache, userListsCache } from '@/cache.js';
import { userChannelFollowingsCache, userChannelsCache, userFavoriteListsCache, userListsCache } from '@/cache.js';
const lang = ref(miLocalStorage.getItem('lang'));
const fontSize = ref(miLocalStorage.getItem('fontSize'));
@ -638,7 +646,7 @@ async function setPinnedList() {
}
}
async function removePinnedList(id, name) {
async function removePinnedList(id, name?:string) {
if (!id) return;
const { canceled } = await os.confirm({
type: 'warning',
@ -658,6 +666,46 @@ async function removePinnedList(id, name) {
defaultStore.set('pinnedUserLists', newPinnedLists);
}
async function setPinnedChannel() {
const myChannels = await userChannelsCache.fetch();
const favoriteChannels = await userChannelFollowingsCache.fetch();
let channels = [...new Set([...myChannels, ...favoriteChannels])];
const { canceled, result: channel } = await os.select({
title: i18n.ts.selectList,
items: channels.map(x => ({
value: x, text: x.name,
})),
});
if (canceled) return;
let pinnedChannels = defaultStore.state.pinnedChannels;
// Check if the id is already present in pinnedLists
if (!pinnedChannels.some(pinnedChannel => pinnedChannel.id === channel.id)) {
pinnedChannels.push(channel);
defaultStore.set('pinnedChannels', pinnedChannels);
}
}
async function removePinnedChannel(id, name?:string) {
if (!id) return;
const { canceled } = await os.confirm({
type: 'warning',
text: i18n.tsx.removeAreYouSure({ x: name ?? id }),
});
if (canceled) return;
if (id === 'all') {
if (canceled) return;
defaultStore.set('pinnedChannels', []);
return;
}
const pinnedChannels = defaultStore.state.pinnedChannels;
const newPinnedChannels = pinnedChannels.filter(pinnedchannel => pinnedchannel.id !== id);
defaultStore.set('pinnedChannels', newPinnedChannels);
}
let smashCount = 0;
let smashTimer: number | null = null;

View File

@ -12,7 +12,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<MkInfo v-if="['home', 'local', 'social', 'global'].includes(src) && !defaultStore.reactiveState.timelineTutorials.value[src]" style="margin-bottom: var(--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(--margin);"/>
<MkPostForm v-if="$i && defaultStore.reactiveState.showFixedPostForm.value" :channel="channelInfo" :autofocus="deviceKind === 'desktop'" :class="$style.postForm" class="post-form _panel" fixed style="margin-bottom: var(--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
@ -20,6 +20,7 @@ SPDX-License-Identifier: AGPL-3.0-only
:key="src + withRenotes + withReplies + onlyFiles"
:src="src.split(':')[0]"
:list="src.split(':')[1]"
:channel="src.split(':')[1]"
:withRenotes="withRenotes"
:withReplies="withReplies"
:onlyFiles="onlyFiles"
@ -112,8 +113,19 @@ const remoteLocalTimelineEnable4 = ref(defaultStore.state.remoteLocalTimelineEna
const remoteLocalTimelineEnable5 = ref(defaultStore.state.remoteLocalTimelineEnable5);
const showHomeTimeline = ref(defaultStore.state.showHomeTimeline);
const showSocialTimeline = ref(defaultStore.state.showSocialTimeline);
watch(src, () => {
const channelInfo = ref();
if (src.value.split(':')[0] === 'channel') {
const channelId = src.value.split(':')[1];
channelInfo.value = misskeyApi('channels/show', { channelId });
}
watch(src, async () => {
queue.value = 0;
if (src.value.split(':')[0] === 'channel') {
const channelId = src.value.split(':')[1];
channelInfo.value = misskeyApi('channels/show', { channelId });
} else {
channelInfo.value = null;
}
});
function queueUpdated(q: number): void {
@ -285,6 +297,11 @@ const headerTabs = computed(() => [...(defaultStore.reactiveState.pinnedUserList
title: l.name,
icon: 'ti ti-star',
iconOnly: defaultStore.state.topBarNameShown ?? false,
}))), ...(defaultStore.reactiveState.pinnedChannels.value.map(l => ({
key: 'channel:' + l.id,
title: l.name,
icon: 'ti ti-star',
iconOnly: defaultStore.state.topBarNameShown ?? false,
}))), ...(showHomeTimeline.value ? [{
key: 'home',
title: i18n.ts._timelines.home,

View File

@ -280,7 +280,10 @@ export const defaultStore = markRaw(new Storage('base', {
where: 'deviceAccount',
default: [] as Misskey.entities.UserList[],
},
pinnedChannels: {
where: 'deviceAccount',
default: [] as Misskey.entities.Channel[],
},
overridedDeviceKind: {
where: 'device',
default: null as null | 'smartphone' | 'tablet' | 'desktop',