popupの制御を出す側で行うように

This commit is contained in:
kakkokari-gtyih 2024-07-15 11:53:32 +09:00
parent 8d144c8fdc
commit 87a7d1a8ea
10 changed files with 52 additions and 52 deletions

View File

@ -18,11 +18,11 @@ SPDX-License-Identifier: AGPL-3.0-only
<!--<div v-if="appearNote._featuredId_" class="tip"><i class="ti ti-bolt"></i> {{ i18n.ts.featured }}</div>--> <!--<div v-if="appearNote._featuredId_" class="tip"><i class="ti ti-bolt"></i> {{ i18n.ts.featured }}</div>-->
<div v-if="isRenote" :class="$style.renote"> <div v-if="isRenote" :class="$style.renote">
<div v-if="note.channel" :class="$style.colorBar" :style="{ background: note.channel.color }"></div> <div v-if="note.channel" :class="$style.colorBar" :style="{ background: note.channel.color }"></div>
<MkAvatar :class="$style.renoteAvatar" :user="note.user" link preview/> <MkAvatar :class="$style.renoteAvatar" :user="note.user" link :preview="!inEmbedPage && !mock"/>
<i class="ti ti-repeat" style="margin-right: 4px;"></i> <i class="ti ti-repeat" style="margin-right: 4px;"></i>
<I18n :src="i18n.ts.renotedBy" tag="span" :class="$style.renoteText"> <I18n :src="i18n.ts.renotedBy" tag="span" :class="$style.renoteText">
<template #user> <template #user>
<MkA v-user-preview="note.userId" :class="$style.renoteUserName" :to="userPage(note.user)"> <MkA v-user-preview="inEmbedPage ? undefined : note.userId" :class="$style.renoteUserName" :to="userPage(note.user)">
<MkUserName :user="note.user"/> <MkUserName :user="note.user"/>
</MkA> </MkA>
</template> </template>
@ -42,12 +42,12 @@ SPDX-License-Identifier: AGPL-3.0-only
</div> </div>
</div> </div>
<div v-if="renoteCollapsed" :class="$style.collapsedRenoteTarget"> <div v-if="renoteCollapsed" :class="$style.collapsedRenoteTarget">
<MkAvatar :class="$style.collapsedRenoteTargetAvatar" :user="appearNote.user" link preview/> <MkAvatar :class="$style.collapsedRenoteTargetAvatar" :user="appearNote.user" link :preview="!inEmbedPage && !mock"/>
<Mfm :text="getNoteSummary(appearNote)" :plain="true" :nowrap="true" :author="appearNote.user" :nyaize="'respect'" :class="$style.collapsedRenoteTargetText" @click="renoteCollapsed = false"/> <Mfm :text="getNoteSummary(appearNote)" :plain="true" :nowrap="true" :author="appearNote.user" :nyaize="'respect'" :class="$style.collapsedRenoteTargetText" @click="renoteCollapsed = false"/>
</div> </div>
<article v-else :class="$style.article" @contextmenu.stop="onContextmenu"> <article v-else :class="$style.article" @contextmenu.stop="onContextmenu">
<div v-if="appearNote.channel" :class="$style.colorBar" :style="{ background: appearNote.channel.color }"></div> <div v-if="appearNote.channel" :class="$style.colorBar" :style="{ background: appearNote.channel.color }"></div>
<MkAvatar :class="$style.avatar" :user="appearNote.user" :link="!mock" :preview="!mock"/> <MkAvatar :class="$style.avatar" :user="appearNote.user" :link="!mock" :preview="!inEmbedPage && !mock"/>
<div :class="$style.main"> <div :class="$style.main">
<MkNoteHeader :note="appearNote" :mini="true"/> <MkNoteHeader :note="appearNote" :mini="true"/>
<MkInstanceTicker v-if="showTicker" :instance="appearNote.user.instance"/> <MkInstanceTicker v-if="showTicker" :instance="appearNote.user.instance"/>
@ -67,7 +67,7 @@ SPDX-License-Identifier: AGPL-3.0-only
:author="appearNote.user" :author="appearNote.user"
:nyaize="'respect'" :nyaize="'respect'"
:emojiUrls="appearNote.emojis" :emojiUrls="appearNote.emojis"
:enableEmojiMenu="true" :enableEmojiMenu="!inEmbedPage"
:enableEmojiMenuReaction="true" :enableEmojiMenuReaction="true"
/> />
<div v-if="translating || translation" :class="$style.translation"> <div v-if="translating || translation" :class="$style.translation">
@ -81,8 +81,8 @@ SPDX-License-Identifier: AGPL-3.0-only
<div v-if="appearNote.files && appearNote.files.length > 0"> <div v-if="appearNote.files && appearNote.files.length > 0">
<MkMediaList ref="galleryEl" :mediaList="appearNote.files" :originalEntityUrl="`${url}/notes/${appearNote.id}`"/> <MkMediaList ref="galleryEl" :mediaList="appearNote.files" :originalEntityUrl="`${url}/notes/${appearNote.id}`"/>
</div> </div>
<MkPoll v-if="appearNote.poll" :noteId="appearNote.id" :poll="appearNote.poll" :class="$style.poll"/> <MkPoll v-if="appearNote.poll" :noteId="appearNote.id" :poll="appearNote.poll" :readOnly="inEmbedPage" :class="$style.poll"/>
<div v-if="isEnabledUrlPreview && !inEmbedPage"> <div v-if="isEnabledUrlPreview">
<MkUrlPreview v-for="url in urls" :key="url" :url="url" :compact="true" :detail="false" :class="$style.urlPreview"/> <MkUrlPreview v-for="url in urls" :key="url" :url="url" :compact="true" :detail="false" :class="$style.urlPreview"/>
</div> </div>
<div v-if="appearNote.renote" :class="$style.quote"><MkNoteSimple :note="appearNote.renote" :class="$style.quoteNote"/></div> <div v-if="appearNote.renote" :class="$style.quote"><MkNoteSimple :note="appearNote.renote" :class="$style.quoteNote"/></div>
@ -156,14 +156,14 @@ SPDX-License-Identifier: AGPL-3.0-only
<div v-else-if="!hardMuted" :class="$style.muted" @click="muted = false"> <div v-else-if="!hardMuted" :class="$style.muted" @click="muted = false">
<I18n v-if="muted === 'sensitiveMute'" :src="i18n.ts.userSaysSomethingSensitive" tag="small"> <I18n v-if="muted === 'sensitiveMute'" :src="i18n.ts.userSaysSomethingSensitive" tag="small">
<template #name> <template #name>
<MkA v-user-preview="appearNote.userId" :to="userPage(appearNote.user)"> <MkA v-user-preview="inEmbedPage ? undefined : appearNote.userId" :to="userPage(appearNote.user)">
<MkUserName :user="appearNote.user"/> <MkUserName :user="appearNote.user"/>
</MkA> </MkA>
</template> </template>
</I18n> </I18n>
<I18n v-else :src="i18n.ts.userSaysSomething" tag="small"> <I18n v-else :src="i18n.ts.userSaysSomething" tag="small">
<template #name> <template #name>
<MkA v-user-preview="appearNote.userId" :to="userPage(appearNote.user)"> <MkA v-user-preview="inEmbedPage ? undefined : appearNote.userId" :to="userPage(appearNote.user)">
<MkUserName :user="appearNote.user"/> <MkUserName :user="appearNote.user"/>
</MkA> </MkA>
</template> </template>

View File

@ -11,12 +11,12 @@ SPDX-License-Identifier: AGPL-3.0-only
> >
<MkNoteSub v-if="appearNote.reply" :note="appearNote.reply" :class="$style.replyTo"/> <MkNoteSub v-if="appearNote.reply" :note="appearNote.reply" :class="$style.replyTo"/>
<div v-if="isRenote" :class="$style.renote"> <div v-if="isRenote" :class="$style.renote">
<MkAvatar :class="$style.renoteAvatar" :user="note.user" link preview/> <MkAvatar :class="$style.renoteAvatar" :user="note.user" link/>
<i class="ti ti-repeat" style="margin-right: 4px;"></i> <i class="ti ti-repeat" style="margin-right: 4px;"></i>
<span :class="$style.renoteText"> <span :class="$style.renoteText">
<I18n :src="i18n.ts.renotedBy" tag="span"> <I18n :src="i18n.ts.renotedBy" tag="span">
<template #user> <template #user>
<MkA v-user-preview="note.userId" :class="$style.renoteName" :to="userPage(note.user)"> <MkA :class="$style.renoteName" :to="userPage(note.user)">
<MkUserName :user="note.user"/> <MkUserName :user="note.user"/>
</MkA> </MkA>
</template> </template>
@ -36,12 +36,12 @@ SPDX-License-Identifier: AGPL-3.0-only
</div> </div>
<article :class="$style.note"> <article :class="$style.note">
<header :class="$style.noteHeader"> <header :class="$style.noteHeader">
<MkAvatar :class="$style.noteHeaderAvatar" :user="appearNote.user" indicator link preview/> <MkAvatar :class="$style.noteHeaderAvatar" :user="appearNote.user" indicator link/>
<div :class="$style.noteHeaderBody"> <div :class="$style.noteHeaderBody">
<div :class="$style.noteHeaderBodyUpper"> <div :class="$style.noteHeaderBodyUpper">
<div style="min-width: 0;"> <div style="min-width: 0;">
<div class="_nowrap"> <div class="_nowrap">
<MkA v-user-preview="appearNote.user.id" :class="$style.noteHeaderName" :to="userPage(appearNote.user)"> <MkA :class="$style.noteHeaderName" :to="userPage(appearNote.user)">
<MkUserName :nowrap="true" :user="appearNote.user"/> <MkUserName :nowrap="true" :user="appearNote.user"/>
</MkA> </MkA>
<span v-if="appearNote.user.isBot" :class="$style.isBot">bot</span> <span v-if="appearNote.user.isBot" :class="$style.isBot">bot</span>
@ -72,14 +72,12 @@ SPDX-License-Identifier: AGPL-3.0-only
:author="appearNote.user" :author="appearNote.user"
:nyaize="'respect'" :nyaize="'respect'"
:emojiUrls="appearNote.emojis" :emojiUrls="appearNote.emojis"
:enableEmojiMenu="true"
:enableEmojiMenuReaction="true"
/> />
<a v-if="appearNote.renote != null" :class="$style.rn">RN:</a> <a v-if="appearNote.renote != null" :class="$style.rn">RN:</a>
<div v-if="appearNote.files && appearNote.files.length > 0"> <div v-if="appearNote.files && appearNote.files.length > 0">
<MkMediaList :mediaList="appearNote.files" :originalEntityUrl="`${url}/notes/${appearNote.id}`"/> <MkMediaList :mediaList="appearNote.files" :originalEntityUrl="`${url}/notes/${appearNote.id}`"/>
</div> </div>
<MkPoll v-if="appearNote.poll" ref="pollViewer" :noteId="appearNote.id" :poll="appearNote.poll" :class="$style.poll"/> <MkPoll v-if="appearNote.poll" ref="pollViewer" :noteId="appearNote.id" :poll="appearNote.poll" :readOnly="true" :class="$style.poll"/>
<div v-if="appearNote.renote" :class="$style.quote"><MkNoteSimple :note="appearNote.renote" :class="$style.quoteNote"/></div> <div v-if="appearNote.renote" :class="$style.quote"><MkNoteSimple :note="appearNote.renote" :class="$style.quoteNote"/></div>
<button v-if="isLong && collapsed" :class="$style.collapsed" class="_button" @click="collapsed = false"> <button v-if="isLong && collapsed" :class="$style.collapsed" class="_button" @click="collapsed = false">
<span :class="$style.collapsedLabel">{{ i18n.ts.showMore }}</span> <span :class="$style.collapsedLabel">{{ i18n.ts.showMore }}</span>

View File

@ -8,7 +8,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<div v-if="mock" :class="$style.name"> <div v-if="mock" :class="$style.name">
<MkUserName :user="note.user"/> <MkUserName :user="note.user"/>
</div> </div>
<MkA v-else v-user-preview="note.user.id" :class="$style.name" :to="userPage(note.user)"> <MkA v-else v-user-preview="inEmbedPage ? undefined : note.user.id" :class="$style.name" :to="userPage(note.user)">
<MkUserName :user="note.user"/> <MkUserName :user="note.user"/>
</MkA> </MkA>
<div v-if="note.user.isBot" :class="$style.isBot">bot</div> <div v-if="note.user.isBot" :class="$style.isBot">bot</div>
@ -46,6 +46,7 @@ defineProps<{
}>(); }>();
const mock = inject<boolean>('mock', false); const mock = inject<boolean>('mock', false);
const inEmbedPage = inject<boolean>('EMBED_PAGE', false);
</script> </script>
<style lang="scss" module> <style lang="scss" module>

View File

@ -5,7 +5,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<template> <template>
<div :class="$style.root"> <div :class="$style.root">
<MkAvatar :class="$style.avatar" :user="note.user" link preview/> <MkAvatar :class="$style.avatar" :user="note.user" link :preview="!inEmbedPage"/>
<div :class="$style.main"> <div :class="$style.main">
<MkNoteHeader :class="$style.header" :note="note" :mini="true"/> <MkNoteHeader :class="$style.header" :note="note" :mini="true"/>
<div> <div>
@ -22,7 +22,7 @@ SPDX-License-Identifier: AGPL-3.0-only
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { ref } from 'vue'; import { ref, inject } from 'vue';
import * as Misskey from 'misskey-js'; import * as Misskey from 'misskey-js';
import MkNoteHeader from '@/components/MkNoteHeader.vue'; import MkNoteHeader from '@/components/MkNoteHeader.vue';
import MkSubNoteContent from '@/components/MkSubNoteContent.vue'; import MkSubNoteContent from '@/components/MkSubNoteContent.vue';
@ -32,6 +32,8 @@ const props = defineProps<{
note: Misskey.entities.Note; note: Misskey.entities.Note;
}>(); }>();
const inEmbedPage = inject<boolean>('EMBED_PAGE', false);
const showContent = ref(false); const showContent = ref(false);
</script> </script>

View File

@ -7,7 +7,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<div v-if="!muted" :class="[$style.root, { [$style.children]: depth > 1 }]"> <div v-if="!muted" :class="[$style.root, { [$style.children]: depth > 1 }]">
<div :class="$style.main"> <div :class="$style.main">
<div v-if="note.channel" :class="$style.colorBar" :style="{ background: note.channel.color }"></div> <div v-if="note.channel" :class="$style.colorBar" :style="{ background: note.channel.color }"></div>
<MkAvatar :class="$style.avatar" :user="note.user" link preview/> <MkAvatar :class="$style.avatar" :user="note.user" link :preview="!inEmbedPage"/>
<div :class="$style.body"> <div :class="$style.body">
<MkNoteHeader :class="$style.header" :note="note" :mini="true"/> <MkNoteHeader :class="$style.header" :note="note" :mini="true"/>
<div> <div>
@ -40,7 +40,7 @@ SPDX-License-Identifier: AGPL-3.0-only
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { ref } from 'vue'; import { ref, inject } from 'vue';
import * as Misskey from 'misskey-js'; import * as Misskey from 'misskey-js';
import MkNoteHeader from '@/components/MkNoteHeader.vue'; import MkNoteHeader from '@/components/MkNoteHeader.vue';
import MkSubNoteContent from '@/components/MkSubNoteContent.vue'; import MkSubNoteContent from '@/components/MkSubNoteContent.vue';
@ -62,6 +62,8 @@ const props = withDefaults(defineProps<{
depth: 1, depth: 1,
}); });
const inEmbedPage = inject<boolean>('EMBED_PAGE', false);
const muted = ref($i ? checkWordMute(props.note, $i, $i.mutedWords) : false); const muted = ref($i ? checkWordMute(props.note, $i, $i.mutedWords) : false);
const showContent = ref(false); const showContent = ref(false);

View File

@ -4,7 +4,7 @@ SPDX-License-Identifier: AGPL-3.0-only
--> -->
<template> <template>
<div :class="{ [$style.done]: closed || isVoted }"> <div :class="{ [$style.done]: closed || isVoted || readOnly }">
<ul :class="$style.choices"> <ul :class="$style.choices">
<li v-for="(choice, i) in poll.choices" :key="i" :class="$style.choice" @click="vote(i)"> <li v-for="(choice, i) in poll.choices" :key="i" :class="$style.choice" @click="vote(i)">
<div :class="$style.bg" :style="{ 'width': `${showResult ? (choice.votes / total * 100) : 0}%` }"></div> <div :class="$style.bg" :style="{ 'width': `${showResult ? (choice.votes / total * 100) : 0}%` }"></div>
@ -83,10 +83,10 @@ if (props.poll.expiresAt) {
} }
const vote = async (id) => { const vote = async (id) => {
pleaseLogin(undefined, pleaseLoginContext.value);
if (props.readOnly || closed.value || isVoted.value) return; if (props.readOnly || closed.value || isVoted.value) return;
pleaseLogin(undefined, pleaseLoginContext.value);
const { canceled } = await os.confirm({ const { canceled } = await os.confirm({
type: 'question', type: 'question',
text: i18n.tsx.voteConfirm({ choice: props.poll.choices[id].text }), text: i18n.tsx.voteConfirm({ choice: props.poll.choices[id].text }),
@ -145,7 +145,7 @@ const vote = async (id) => {
.done { .done {
.choice { .choice {
cursor: default; cursor: initial;
} }
} }
</style> </style>

View File

@ -18,7 +18,7 @@ SPDX-License-Identifier: AGPL-3.0-only
</details> </details>
<details v-if="note.poll"> <details v-if="note.poll">
<summary>{{ i18n.ts.poll }}</summary> <summary>{{ i18n.ts.poll }}</summary>
<MkPoll :noteId="note.id" :poll="note.poll"/> <MkPoll :noteId="note.id" :poll="note.poll" :readOnly="inEmbedPage"/>
</details> </details>
<button v-if="isLong && collapsed" :class="$style.fade" class="_button" @click="collapsed = false"> <button v-if="isLong && collapsed" :class="$style.fade" class="_button" @click="collapsed = false">
<span :class="$style.fadeLabel">{{ i18n.ts.showMore }}</span> <span :class="$style.fadeLabel">{{ i18n.ts.showMore }}</span>
@ -30,7 +30,7 @@ SPDX-License-Identifier: AGPL-3.0-only
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { ref } from 'vue'; import { ref, inject } from 'vue';
import * as Misskey from 'misskey-js'; import * as Misskey from 'misskey-js';
import MkMediaList from '@/components/MkMediaList.vue'; import MkMediaList from '@/components/MkMediaList.vue';
import MkPoll from '@/components/MkPoll.vue'; import MkPoll from '@/components/MkPoll.vue';
@ -44,6 +44,8 @@ const props = defineProps<{
const isLong = shouldCollapsed(props.note, []); const isLong = shouldCollapsed(props.note, []);
const inEmbedPage = inject<boolean>('EMBED_PAGE', false);
const collapsed = ref(isLong); const collapsed = ref(isLong);
</script> </script>

View File

@ -8,6 +8,7 @@ import * as Misskey from 'misskey-js';
import { misskeyApi } from '@/scripts/misskey-api.js'; import { misskeyApi } from '@/scripts/misskey-api.js';
import { miLocalStorage } from '@/local-storage.js'; import { miLocalStorage } from '@/local-storage.js';
import { DEFAULT_INFO_IMAGE_URL, DEFAULT_NOT_FOUND_IMAGE_URL, DEFAULT_SERVER_ERROR_IMAGE_URL } from '@/const.js'; import { DEFAULT_INFO_IMAGE_URL, DEFAULT_NOT_FOUND_IMAGE_URL, DEFAULT_SERVER_ERROR_IMAGE_URL } from '@/const.js';
import { embedPage } from '@/config.js';
// TODO: 他のタブと永続化されたstateを同期 // TODO: 他のタブと永続化されたstateを同期
@ -36,7 +37,7 @@ export const infoImageUrl = computed(() => instance.infoImageUrl ?? DEFAULT_INFO
export const notFoundImageUrl = computed(() => instance.notFoundImageUrl ?? DEFAULT_NOT_FOUND_IMAGE_URL); export const notFoundImageUrl = computed(() => instance.notFoundImageUrl ?? DEFAULT_NOT_FOUND_IMAGE_URL);
export const isEnabledUrlPreview = computed(() => instance.enableUrlPreview ?? true); export const isEnabledUrlPreview = computed(() => (instance.enableUrlPreview ?? true) && !embedPage);
export async function fetchInstance(force = false): Promise<Misskey.entities.MetaDetailed> { export async function fetchInstance(force = false): Promise<Misskey.entities.MetaDetailed> {
if (!force) { if (!force) {

View File

@ -172,22 +172,11 @@ type EmitsExtractor<T> = {
[K in keyof T as K extends `onVnode${string}` ? never : K extends `on${infer E}` ? Uncapitalize<E> : K extends string ? never : K]: T[K]; [K in keyof T as K extends `onVnode${string}` ? never : K extends `on${infer E}` ? Uncapitalize<E> : K extends string ? never : K]: T[K];
}; };
type PopupOptions = {
callEvenOnEmbedPage?: boolean;
};
export function popup<T extends Component>( export function popup<T extends Component>(
component: T, component: T,
props: ComponentProps<T>, props: ComponentProps<T>,
events: ComponentEmit<T> = {} as ComponentEmit<T>, events: ComponentEmit<T> = {} as ComponentEmit<T>,
options: PopupOptions = {},
): { dispose: () => void } { ): { dispose: () => void } {
const _options = Object.assign({
callEvenOnEmbedPage: false,
}, options) as Required<PopupOptions>;
if (embedPage && !_options.callEvenOnEmbedPage) return { dispose: () => {} };
markRaw(component); markRaw(component);
const id = ++popupIdCount; const id = ++popupIdCount;

View File

@ -3,10 +3,11 @@
* SPDX-License-Identifier: AGPL-3.0-only * SPDX-License-Identifier: AGPL-3.0-only
*/ */
import { defineAsyncComponent } from 'vue'; import { defineAsyncComponent, inject } from 'vue';
import { $i } from '@/account.js'; import { $i } from '@/account.js';
import { i18n } from '@/i18n.js'; import { i18n } from '@/i18n.js';
import { popup } from '@/os.js'; import { popup } from '@/os.js';
import { embedPage } from '@/config.js';
export type OpenOnRemoteOptions = { export type OpenOnRemoteOptions = {
/** /**
@ -47,18 +48,22 @@ export type OpenOnRemoteOptions = {
export function pleaseLogin(path?: string, openOnRemote?: OpenOnRemoteOptions) { export function pleaseLogin(path?: string, openOnRemote?: OpenOnRemoteOptions) {
if ($i) return; if ($i) return;
const { dispose } = popup(defineAsyncComponent(() => import('@/components/MkSigninDialog.vue')), { if (embedPage) {
autoSet: true, window.open(path ?? '/', '_blank', 'noopener');
message: openOnRemote ? i18n.ts.signinOrContinueOnRemote : i18n.ts.signinRequired, } else {
openOnRemote, const { dispose } = popup(defineAsyncComponent(() => import('@/components/MkSigninDialog.vue')), {
}, { autoSet: true,
cancelled: () => { message: openOnRemote ? i18n.ts.signinOrContinueOnRemote : i18n.ts.signinRequired,
if (path) { openOnRemote,
window.location.href = path; }, {
} cancelled: () => {
}, if (path) {
closed: () => dispose(), window.location.href = path;
}); }
},
closed: () => dispose(),
});
}
throw new Error('signin required'); throw new Error('signin required');
} }