Merge pull request #11 from samunohito/feature/post-channel-everywhere-fix
Feature/post channel everywhere fix
This commit is contained in:
commit
5faa410a83
|
@ -2164,6 +2164,9 @@ export interface Locale {
|
||||||
"followersDescription": string;
|
"followersDescription": string;
|
||||||
"specified": string;
|
"specified": string;
|
||||||
"specifiedDescription": string;
|
"specifiedDescription": string;
|
||||||
|
"channel": string;
|
||||||
|
"channelDescription": string;
|
||||||
|
"channelSelected": string;
|
||||||
"disableFederation": string;
|
"disableFederation": string;
|
||||||
"disableFederationDescription": string;
|
"disableFederationDescription": string;
|
||||||
};
|
};
|
||||||
|
|
|
@ -2068,6 +2068,9 @@ _visibility:
|
||||||
followersDescription: "自分のフォロワーのみに公開"
|
followersDescription: "自分のフォロワーのみに公開"
|
||||||
specified: "ダイレクト"
|
specified: "ダイレクト"
|
||||||
specifiedDescription: "指定したユーザーのみに公開"
|
specifiedDescription: "指定したユーザーのみに公開"
|
||||||
|
channel: "チャンネル"
|
||||||
|
channelDescription: "選択したチャンネルに公開"
|
||||||
|
channelSelected: "選択中:{name}"
|
||||||
disableFederation: "連合なし"
|
disableFederation: "連合なし"
|
||||||
disableFederationDescription: "他サーバーへの配信を行いません"
|
disableFederationDescription: "他サーバーへの配信を行いません"
|
||||||
|
|
||||||
|
|
|
@ -22,18 +22,18 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<button ref="visibilityButton" v-click-anime v-tooltip="i18n.ts.visibility" :class="['_button', $style.headerRightItem, $style.visibility]" @click="setVisibility">
|
<button ref="visibilityButton" v-click-anime v-tooltip="i18n.ts.visibility" :class="['_button', $style.headerRightItem, $style.visibility]" @click="setVisibility">
|
||||||
<template v-if="postChannel">
|
<template v-if="postChannel">
|
||||||
<span><i class="ti ti-device-tv"></i></span>
|
<span><i class="ti ti-device-tv"></i></span>
|
||||||
<span v-if="postChannel" :class="$style.headerRightButtonText">{{ postChannel.name }}</span>
|
<span v-if="postChannel" :class="$style.headerRightButtonText">{{ postChannelName }}</span>
|
||||||
</template>
|
</template>
|
||||||
<template v-else>
|
<template v-else>
|
||||||
<span v-if="visibility === 'public'"><i class="ti ti-world"></i></span>
|
<span v-if="actualVisibility === 'public'"><i class="ti ti-world"></i></span>
|
||||||
<span v-if="visibility === 'home'"><i class="ti ti-home"></i></span>
|
<span v-if="actualVisibility === 'home'"><i class="ti ti-home"></i></span>
|
||||||
<span v-if="visibility === 'followers'"><i class="ti ti-lock"></i></span>
|
<span v-if="actualVisibility === 'followers'"><i class="ti ti-lock"></i></span>
|
||||||
<span v-if="visibility === 'specified'"><i class="ti ti-mail"></i></span>
|
<span v-if="actualVisibility === 'specified'"><i class="ti ti-mail"></i></span>
|
||||||
<span :class="$style.headerRightButtonText">{{ i18n.ts._visibility[visibility] }}</span>
|
<span :class="$style.headerRightButtonText">{{ i18n.ts._visibility[actualVisibility] }}</span>
|
||||||
</template>
|
</template>
|
||||||
</button>
|
</button>
|
||||||
<button v-click-anime v-tooltip="i18n.ts._visibility.disableFederation" class="_button" :class="[$style.headerRightItem, { [$style.danger]: localOnly }]" :disabled="postChannel != null || visibility === 'specified'" @click="toggleLocalOnly">
|
<button v-click-anime v-tooltip="i18n.ts._visibility.disableFederation" class="_button" :class="[$style.headerRightItem, { [$style.danger]: actualLocalOnly }]" :disabled="postChannel != null || actualVisibility === 'specified'" @click="toggleLocalOnly">
|
||||||
<span v-if="!localOnly"><i class="ti ti-rocket"></i></span>
|
<span v-if="!actualLocalOnly"><i class="ti ti-rocket"></i></span>
|
||||||
<span v-else><i class="ti ti-rocket-off"></i></span>
|
<span v-else><i class="ti ti-rocket-off"></i></span>
|
||||||
</button>
|
</button>
|
||||||
<button v-click-anime v-tooltip="i18n.ts.reactionAcceptance" class="_button" :class="[$style.headerRightItem, { [$style.danger]: reactionAcceptance === 'likeOnly' }]" @click="toggleReactionAcceptance">
|
<button v-click-anime v-tooltip="i18n.ts.reactionAcceptance" class="_button" :class="[$style.headerRightItem, { [$style.danger]: reactionAcceptance === 'likeOnly' }]" @click="toggleReactionAcceptance">
|
||||||
|
@ -54,7 +54,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<MkNoteSimple v-if="reply" :class="$style.targetNote" :note="reply"/>
|
<MkNoteSimple v-if="reply" :class="$style.targetNote" :note="reply"/>
|
||||||
<MkNoteSimple v-if="renote" :class="$style.targetNote" :note="renote"/>
|
<MkNoteSimple v-if="renote" :class="$style.targetNote" :note="renote"/>
|
||||||
<div v-if="quoteId" :class="$style.withQuote"><i class="ti ti-quote"></i> {{ i18n.ts.quoteAttached }}<button @click="quoteId = null"><i class="ti ti-x"></i></button></div>
|
<div v-if="quoteId" :class="$style.withQuote"><i class="ti ti-quote"></i> {{ i18n.ts.quoteAttached }}<button @click="quoteId = null"><i class="ti ti-x"></i></button></div>
|
||||||
<div v-if="visibility === 'specified'" :class="$style.toSpecified">
|
<div v-if="actualVisibility === 'specified'" :class="$style.toSpecified">
|
||||||
<span style="margin-right: 8px;">{{ i18n.ts.recipient }}</span>
|
<span style="margin-right: 8px;">{{ i18n.ts.recipient }}</span>
|
||||||
<div :class="$style.visibleUsers">
|
<div :class="$style.visibleUsers">
|
||||||
<span v-for="u in visibleUsers" :key="u.id" :class="$style.visibleUser">
|
<span v-for="u in visibleUsers" :key="u.id" :class="$style.visibleUser">
|
||||||
|
@ -67,7 +67,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<MkInfo v-if="hasNotSpecifiedMentions" warn :class="$style.hasNotSpecifiedMentions">{{ i18n.ts.notSpecifiedMentionWarning }} - <button class="_textButton" @click="addMissingMention()">{{ i18n.ts.add }}</button></MkInfo>
|
<MkInfo v-if="hasNotSpecifiedMentions" warn :class="$style.hasNotSpecifiedMentions">{{ i18n.ts.notSpecifiedMentionWarning }} - <button class="_textButton" @click="addMissingMention()">{{ i18n.ts.add }}</button></MkInfo>
|
||||||
<input v-show="useCw" ref="cwInputEl" v-model="cw" :class="$style.cw" :placeholder="i18n.ts.annotation" @keydown="onKeydown">
|
<input v-show="useCw" ref="cwInputEl" v-model="cw" :class="$style.cw" :placeholder="i18n.ts.annotation" @keydown="onKeydown">
|
||||||
<div :class="[$style.textOuter, { [$style.withCw]: useCw }]">
|
<div :class="[$style.textOuter, { [$style.withCw]: useCw }]">
|
||||||
<div v-if="channel" :class="$style.colorBar" :style="{ background: channel.color }"></div>
|
<div v-if="postChannel" :class="$style.colorBar" :style="{ background: postChannel.color }"></div>
|
||||||
<textarea ref="textareaEl" v-model="text" :class="[$style.text]" :disabled="posting || posted" :readonly="textAreaReadOnly" :placeholder="placeholder" data-cy-post-form-text @keydown="onKeydown" @paste="onPaste" @compositionupdate="onCompositionUpdate" @compositionend="onCompositionEnd"/>
|
<textarea ref="textareaEl" v-model="text" :class="[$style.text]" :disabled="posting || posted" :readonly="textAreaReadOnly" :placeholder="placeholder" data-cy-post-form-text @keydown="onKeydown" @paste="onPaste" @compositionupdate="onCompositionUpdate" @compositionend="onCompositionEnd"/>
|
||||||
<div v-if="maxTextLength - textLength < 100" :class="['_acrylic', $style.textCount, { [$style.textOver]: textLength > maxTextLength }]">{{ maxTextLength - textLength }}</div>
|
<div v-if="maxTextLength - textLength < 100" :class="['_acrylic', $style.textCount, { [$style.textOver]: textLength > maxTextLength }]">{{ maxTextLength - textLength }}</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -132,7 +132,7 @@ const modal = inject('modal');
|
||||||
const props = withDefaults(defineProps<{
|
const props = withDefaults(defineProps<{
|
||||||
reply?: Misskey.entities.Note;
|
reply?: Misskey.entities.Note;
|
||||||
renote?: Misskey.entities.Note;
|
renote?: Misskey.entities.Note;
|
||||||
channel?: Misskey.entities.Channel; // TODO
|
channel?: Misskey.entities.Channel;
|
||||||
mention?: Misskey.entities.User;
|
mention?: Misskey.entities.User;
|
||||||
specified?: Misskey.entities.User;
|
specified?: Misskey.entities.User;
|
||||||
initialText?: string;
|
initialText?: string;
|
||||||
|
@ -153,8 +153,6 @@ const props = withDefaults(defineProps<{
|
||||||
mock: false,
|
mock: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
let postChannel = ref<Misskey.entities.Channel | null>(props.channel);
|
|
||||||
|
|
||||||
provide('mock', props.mock);
|
provide('mock', props.mock);
|
||||||
|
|
||||||
const emit = defineEmits<{
|
const emit = defineEmits<{
|
||||||
|
@ -201,6 +199,20 @@ const imeText = ref('');
|
||||||
const showingOptions = ref(false);
|
const showingOptions = ref(false);
|
||||||
const textAreaReadOnly = ref(false);
|
const textAreaReadOnly = ref(false);
|
||||||
|
|
||||||
|
const postChannel = ref<Misskey.entities.Channel | null>(props.channel ?? null);
|
||||||
|
const postChannelName = computed<string>(() => postChannel.value?.name ?? '');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@link localOnly}が持つ値にチャンネル選択有無を加味した値を計算する(チャンネル選択時は強制的にfalse)
|
||||||
|
* チャンネル選択有無を考慮する必要がある場面では{@link localOnly}ではなくこの値を使用する。
|
||||||
|
*/
|
||||||
|
const actualLocalOnly = computed<boolean>(() => postChannel.value ? true : localOnly.value);
|
||||||
|
/**
|
||||||
|
* {@link visibility}が持つ値にチャンネル選択有無を加味した値を計算する(チャンネル選択時は強制的にpublic)。
|
||||||
|
* チャンネル選択有無を考慮する必要がある場面では{@link actualVisibility}ではなくこの値を使用する。
|
||||||
|
*/
|
||||||
|
const actualVisibility = computed<typeof Misskey.noteVisibilities[number]>(() => postChannel.value ? 'public' : visibility.value);
|
||||||
|
|
||||||
const draftKey = computed((): string => {
|
const draftKey = computed((): string => {
|
||||||
let key = postChannel.value ? `channel:${postChannel.value.id}` : '';
|
let key = postChannel.value ? `channel:${postChannel.value.id}` : '';
|
||||||
|
|
||||||
|
@ -265,7 +277,7 @@ watch(text, () => {
|
||||||
checkMissingMention();
|
checkMissingMention();
|
||||||
}, { immediate: true });
|
}, { immediate: true });
|
||||||
|
|
||||||
watch(visibility, () => {
|
watch(actualVisibility, () => {
|
||||||
checkMissingMention();
|
checkMissingMention();
|
||||||
}, { immediate: true });
|
}, { immediate: true });
|
||||||
|
|
||||||
|
@ -309,11 +321,6 @@ if ($i?.isSilenced && visibility.value === 'public') {
|
||||||
visibility.value = 'home';
|
visibility.value = 'home';
|
||||||
}
|
}
|
||||||
|
|
||||||
if (postChannel.value) {
|
|
||||||
visibility.value = 'public';
|
|
||||||
localOnly.value = true; // TODO: チャンネルが連合するようになった折には消す
|
|
||||||
}
|
|
||||||
|
|
||||||
// 公開以外へのリプライ時は元の公開範囲を引き継ぐ
|
// 公開以外へのリプライ時は元の公開範囲を引き継ぐ
|
||||||
if (props.reply && ['home', 'followers', 'specified'].includes(props.reply.visibility)) {
|
if (props.reply && ['home', 'followers', 'specified'].includes(props.reply.visibility)) {
|
||||||
if (props.reply.visibility === 'home' && visibility.value === 'followers') {
|
if (props.reply.visibility === 'home' && visibility.value === 'followers') {
|
||||||
|
@ -363,7 +370,7 @@ function watchForDraft() {
|
||||||
}
|
}
|
||||||
|
|
||||||
function checkMissingMention() {
|
function checkMissingMention() {
|
||||||
if (visibility.value === 'specified') {
|
if (actualVisibility.value === 'specified') {
|
||||||
const ast = mfm.parse(text.value);
|
const ast = mfm.parse(text.value);
|
||||||
|
|
||||||
for (const x of extractMentions(ast)) {
|
for (const x of extractMentions(ast)) {
|
||||||
|
@ -451,9 +458,10 @@ function upload(file: File, name?: string): void {
|
||||||
|
|
||||||
function setVisibility() {
|
function setVisibility() {
|
||||||
os.popup(defineAsyncComponent(() => import('@/components/MkVisibilityPicker.vue')), {
|
os.popup(defineAsyncComponent(() => import('@/components/MkVisibilityPicker.vue')), {
|
||||||
currentVisibility: visibility.value,
|
currentVisibility: actualVisibility.value,
|
||||||
isSilenced: $i?.isSilenced,
|
isSilenced: $i?.isSilenced,
|
||||||
localOnly: localOnly.value,
|
// チャンネル→ダイレクトの選択変更ができなくなるので、チャンネル選択中の場合は意図的にfalseを渡すようにする
|
||||||
|
localOnly: postChannel.value ? false : actualLocalOnly.value,
|
||||||
src: visibilityButton.value,
|
src: visibilityButton.value,
|
||||||
currentChannel: postChannel.value,
|
currentChannel: postChannel.value,
|
||||||
}, {
|
}, {
|
||||||
|
@ -465,20 +473,13 @@ function setVisibility() {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
changeChannel: channel => {
|
changeChannel: channel => {
|
||||||
|
// computedで読み替えをするので、localOnlyとvisibilityの変更はしない
|
||||||
postChannel.value = channel;
|
postChannel.value = channel;
|
||||||
visibility.value = 'public';
|
},
|
||||||
localOnly.value = true;
|
|
||||||
}
|
|
||||||
}, 'closed');
|
}, 'closed');
|
||||||
}
|
}
|
||||||
|
|
||||||
async function toggleLocalOnly() {
|
async function toggleLocalOnly() {
|
||||||
if (postChannel.value) {
|
|
||||||
visibility.value = 'public';
|
|
||||||
localOnly.value = true; // TODO: チャンネルが連合するようになった折には消す
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const neverShowInfo = miLocalStorage.getItem('neverShowLocalOnlyInfo');
|
const neverShowInfo = miLocalStorage.getItem('neverShowLocalOnlyInfo');
|
||||||
|
|
||||||
if (!localOnly.value && neverShowInfo !== 'true') {
|
if (!localOnly.value && neverShowInfo !== 'true') {
|
||||||
|
@ -711,7 +712,8 @@ async function post(ev?: MouseEvent) {
|
||||||
text.value.includes('$[scale') ||
|
text.value.includes('$[scale') ||
|
||||||
text.value.includes('$[position');
|
text.value.includes('$[position');
|
||||||
|
|
||||||
if (annoying && visibility.value === 'public') {
|
// チャンネル投稿時はサーバサイド側でpublicに変更されているため警告を出す意味がない
|
||||||
|
if (annoying && actualVisibility.value === 'public' && !postChannel.value) {
|
||||||
const { canceled, result } = await os.actions({
|
const { canceled, result } = await os.actions({
|
||||||
type: 'warning',
|
type: 'warning',
|
||||||
text: i18n.ts.thisPostMayBeAnnoying,
|
text: i18n.ts.thisPostMayBeAnnoying,
|
||||||
|
@ -743,9 +745,9 @@ async function post(ev?: MouseEvent) {
|
||||||
channelId: postChannel.value ? postChannel.value.id : undefined,
|
channelId: postChannel.value ? postChannel.value.id : undefined,
|
||||||
poll: poll.value,
|
poll: poll.value,
|
||||||
cw: useCw.value ? cw.value ?? '' : null,
|
cw: useCw.value ? cw.value ?? '' : null,
|
||||||
localOnly: localOnly.value,
|
localOnly: actualLocalOnly.value,
|
||||||
visibility: visibility.value,
|
visibility: actualVisibility.value,
|
||||||
visibleUserIds: visibility.value === 'specified' ? visibleUsers.value.map(u => u.id) : undefined,
|
visibleUserIds: actualVisibility.value === 'specified' ? visibleUsers.value.map(u => u.id) : undefined,
|
||||||
reactionAcceptance: reactionAcceptance.value,
|
reactionAcceptance: reactionAcceptance.value,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -9,37 +9,46 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<div :class="[$style.label, $style.item]">
|
<div :class="[$style.label, $style.item]">
|
||||||
{{ i18n.ts.visibility }}
|
{{ i18n.ts.visibility }}
|
||||||
</div>
|
</div>
|
||||||
<button key="public" :disabled="isSilenced" class="_button" :class="[$style.item, { [$style.active]: v === 'public' && currentChannel == null }]" data-index="1" @click="choose('public')">
|
<button key="public" :disabled="isSilenced" class="_button" :class="[$style.item, { [$style.active]: v === 'public' &&!currentChannel }]" data-index="1" @click="choose('public')">
|
||||||
<div :class="$style.icon"><i class="ti ti-world"></i></div>
|
<div :class="$style.icon"><i class="ti ti-world"></i></div>
|
||||||
<div :class="$style.body">
|
<div :class="$style.body">
|
||||||
<span :class="$style.itemTitle">{{ i18n.ts._visibility.public }}</span>
|
<span :class="$style.itemTitle">{{ i18n.ts._visibility.public }}</span>
|
||||||
<span :class="$style.itemDescription">{{ i18n.ts._visibility.publicDescription }}</span>
|
<span :class="$style.itemDescription">{{ i18n.ts._visibility.publicDescription }}</span>
|
||||||
</div>
|
</div>
|
||||||
</button>
|
</button>
|
||||||
<button key="home" class="_button" :class="[$style.item, { [$style.active]: v === 'home' && currentChannel == null }]" data-index="2" @click="choose('home')">
|
<button key="home" class="_button" :class="[$style.item, { [$style.active]: v === 'home' && !currentChannel }]" data-index="2" @click="choose('home')">
|
||||||
<div :class="$style.icon"><i class="ti ti-home"></i></div>
|
<div :class="$style.icon"><i class="ti ti-home"></i></div>
|
||||||
<div :class="$style.body">
|
<div :class="$style.body">
|
||||||
<span :class="$style.itemTitle">{{ i18n.ts._visibility.home }}</span>
|
<span :class="$style.itemTitle">{{ i18n.ts._visibility.home }}</span>
|
||||||
<span :class="$style.itemDescription">{{ i18n.ts._visibility.homeDescription }}</span>
|
<span :class="$style.itemDescription">{{ i18n.ts._visibility.homeDescription }}</span>
|
||||||
</div>
|
</div>
|
||||||
</button>
|
</button>
|
||||||
<button key="followers" class="_button" :class="[$style.item, { [$style.active]: v === 'followers' && currentChannel == null }]" data-index="3" @click="choose('followers')">
|
<button key="followers" class="_button" :class="[$style.item, { [$style.active]: v === 'followers' && !currentChannel }]" data-index="3" @click="choose('followers')">
|
||||||
<div :class="$style.icon"><i class="ti ti-lock"></i></div>
|
<div :class="$style.icon"><i class="ti ti-lock"></i></div>
|
||||||
<div :class="$style.body">
|
<div :class="$style.body">
|
||||||
<span :class="$style.itemTitle">{{ i18n.ts._visibility.followers }}</span>
|
<span :class="$style.itemTitle">{{ i18n.ts._visibility.followers }}</span>
|
||||||
<span :class="$style.itemDescription">{{ i18n.ts._visibility.followersDescription }}</span>
|
<span :class="$style.itemDescription">{{ i18n.ts._visibility.followersDescription }}</span>
|
||||||
</div>
|
</div>
|
||||||
</button>
|
</button>
|
||||||
<button key="specified" :disabled="localOnly" class="_button" :class="[$style.item, { [$style.active]: v === 'specified'&& currentChannel == null }]" data-index="4" @click="choose('specified')">
|
<button key="specified" :disabled="localOnly" class="_button" :class="[$style.item, { [$style.active]: v === 'specified' && !currentChannel }]" data-index="4" @click="choose('specified')">
|
||||||
<div :class="$style.icon"><i class="ti ti-mail"></i></div>
|
<div :class="$style.icon"><i class="ti ti-mail"></i></div>
|
||||||
<div :class="$style.body">
|
<div :class="$style.body">
|
||||||
<span :class="$style.itemTitle">{{ i18n.ts._visibility.specified }}</span>
|
<span :class="$style.itemTitle">{{ i18n.ts._visibility.specified }}</span>
|
||||||
<span :class="$style.itemDescription">{{ i18n.ts._visibility.specifiedDescription }}</span>
|
<span :class="$style.itemDescription">{{ i18n.ts._visibility.specifiedDescription }}</span>
|
||||||
</div>
|
</div>
|
||||||
</button>
|
</button>
|
||||||
<button v-for="channel in channels" :class="[$style.item, {[$style.active]: channel.id == currentChannel?.id}]" class="_button" @click="chooseChannel(channel)">
|
<button ref="channelsButton" class="_button" :class="[$style.item, { [$style.active]: currentChannel }]" data-index="5" @click="chooseChannel">
|
||||||
<div :class="$style.body" :style="{borderLeft: `solid 2px ${channel.color}`, paddingLeft: '8px'}">
|
<div :class="$style.channelWrapper" :style="[currentChannel ? {borderLeftColor: `${currentChannel.color}`} : {}]">
|
||||||
<span :class="$style.itemTitle">{{ channel.name }}</span>
|
<div :class="$style.icon">
|
||||||
|
<i class="ti ti-device-tv"></i>
|
||||||
|
</div>
|
||||||
|
<div :class="$style.body">
|
||||||
|
<span :class="$style.itemTitle">{{ i18n.ts._visibility.channel }}</span>
|
||||||
|
<span :class="$style.itemDescription">
|
||||||
|
<span v-if="currentChannelName">{{ i18n.t('_visibility.channelSelected', { name: currentChannelName }) }}</span>
|
||||||
|
<span v-else>{{ i18n.ts._visibility.channelDescription }}</span>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
@ -47,13 +56,15 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { nextTick, shallowRef, ref } from 'vue';
|
import { nextTick, shallowRef, ref, computed } from 'vue';
|
||||||
import * as Misskey from 'misskey-js';
|
import * as Misskey from 'misskey-js';
|
||||||
import MkModal from '@/components/MkModal.vue';
|
import MkModal from '@/components/MkModal.vue';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
import * as os from '@/os.js';
|
import * as os from '@/os.js';
|
||||||
|
import { api } from '@/scripts/api.js';
|
||||||
|
|
||||||
const modal = shallowRef<InstanceType<typeof MkModal>>();
|
const modal = shallowRef<InstanceType<typeof MkModal>>();
|
||||||
|
const channelsButton = shallowRef<InstanceType<typeof HTMLButtonElement>>();
|
||||||
|
|
||||||
const props = withDefaults(defineProps<{
|
const props = withDefaults(defineProps<{
|
||||||
currentVisibility: typeof Misskey.noteVisibilities[number];
|
currentVisibility: typeof Misskey.noteVisibilities[number];
|
||||||
|
@ -83,19 +94,28 @@ const v = ref(props.currentVisibility);
|
||||||
}
|
}
|
||||||
|
|
||||||
*/
|
*/
|
||||||
const channels = ref([]);
|
const channels = ref<Misskey.entities.Channel[]>([]);
|
||||||
|
const currentChannel = ref<Misskey.entities.Channel | undefined>(props.currentChannel);
|
||||||
|
const currentChannelName = computed<string | null>(() => currentChannel.value?.name ?? null);
|
||||||
|
|
||||||
async function getChannel() {
|
async function fetchChannels() {
|
||||||
const res = await os.api('channels/my-favorites', {
|
const res = await api('channels/my-favorites', {
|
||||||
limit: 100,
|
limit: 100,
|
||||||
});
|
});
|
||||||
channels.value.splice(0, 0, ...res);
|
channels.value.splice(0, 0, ...res);
|
||||||
}
|
}
|
||||||
|
|
||||||
getChannel();
|
async function chooseChannel() {
|
||||||
|
let selectedChannel: Misskey.entities.Channel | null = null;
|
||||||
|
await os.popupMenu(
|
||||||
|
channels.value.map(it => ({ type: 'button', text: it.name, action: (_) => selectedChannel = it })),
|
||||||
|
channelsButton.value,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (selectedChannel) {
|
||||||
|
emit('changeChannel', selectedChannel);
|
||||||
|
}
|
||||||
|
|
||||||
async function chooseChannel(channel: string ) {
|
|
||||||
emit('changeChannel', channel);
|
|
||||||
await nextTick();
|
await nextTick();
|
||||||
if (modal.value) modal.value.close();
|
if (modal.value) modal.value.close();
|
||||||
}
|
}
|
||||||
|
@ -107,6 +127,8 @@ function choose(visibility: typeof Misskey.noteVisibilities[number]): void {
|
||||||
if (modal.value) modal.value.close();
|
if (modal.value) modal.value.close();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fetchChannels();
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" module>
|
<style lang="scss" module>
|
||||||
|
@ -190,4 +212,13 @@ function choose(visibility: typeof Misskey.noteVisibilities[number]): void {
|
||||||
.itemDescription {
|
.itemDescription {
|
||||||
opacity: 0.6;
|
opacity: 0.6;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.channelWrapper {
|
||||||
|
display: flex;
|
||||||
|
margin-left: -6px;
|
||||||
|
padding-left: 4px;
|
||||||
|
border-left-width: 2px;
|
||||||
|
border-left-style: solid;
|
||||||
|
border-left-color: transparent;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
Loading…
Reference in New Issue