From 87a7d1a8ea41c8b874de11ede8d381fb5c7eff2a Mon Sep 17 00:00:00 2001 From: kakkokari-gtyih <67428053+kakkokari-gtyih@users.noreply.github.com> Date: Mon, 15 Jul 2024 11:53:32 +0900 Subject: [PATCH] =?UTF-8?q?popup=E3=81=AE=E5=88=B6=E5=BE=A1=E3=82=92?= =?UTF-8?q?=E5=87=BA=E3=81=99=E5=81=B4=E3=81=A7=E8=A1=8C=E3=81=86=E3=82=88?= =?UTF-8?q?=E3=81=86=E3=81=AB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/frontend/src/components/MkNote.vue | 18 +++++------ .../frontend/src/components/MkNoteEmbed.vue | 12 +++---- .../frontend/src/components/MkNoteHeader.vue | 3 +- .../frontend/src/components/MkNoteSimple.vue | 6 ++-- .../frontend/src/components/MkNoteSub.vue | 6 ++-- packages/frontend/src/components/MkPoll.vue | 8 ++--- .../src/components/MkSubNoteContent.vue | 6 ++-- packages/frontend/src/instance.ts | 3 +- packages/frontend/src/os.ts | 11 ------- packages/frontend/src/scripts/please-login.ts | 31 +++++++++++-------- 10 files changed, 52 insertions(+), 52 deletions(-) diff --git a/packages/frontend/src/components/MkNote.vue b/packages/frontend/src/components/MkNote.vue index 9ea036ee57..d187f683f7 100644 --- a/packages/frontend/src/components/MkNote.vue +++ b/packages/frontend/src/components/MkNote.vue @@ -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="isRenote" :class="$style.renote"> <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> <I18n :src="i18n.ts.renotedBy" tag="span" :class="$style.renoteText"> <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"/> </MkA> </template> @@ -42,12 +42,12 @@ SPDX-License-Identifier: AGPL-3.0-only </div> </div> <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"/> </div> <article v-else :class="$style.article" @contextmenu.stop="onContextmenu"> <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"> <MkNoteHeader :note="appearNote" :mini="true"/> <MkInstanceTicker v-if="showTicker" :instance="appearNote.user.instance"/> @@ -67,7 +67,7 @@ SPDX-License-Identifier: AGPL-3.0-only :author="appearNote.user" :nyaize="'respect'" :emojiUrls="appearNote.emojis" - :enableEmojiMenu="true" + :enableEmojiMenu="!inEmbedPage" :enableEmojiMenuReaction="true" /> <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"> <MkMediaList ref="galleryEl" :mediaList="appearNote.files" :originalEntityUrl="`${url}/notes/${appearNote.id}`"/> </div> - <MkPoll v-if="appearNote.poll" :noteId="appearNote.id" :poll="appearNote.poll" :class="$style.poll"/> - <div v-if="isEnabledUrlPreview && !inEmbedPage"> + <MkPoll v-if="appearNote.poll" :noteId="appearNote.id" :poll="appearNote.poll" :readOnly="inEmbedPage" :class="$style.poll"/> + <div v-if="isEnabledUrlPreview"> <MkUrlPreview v-for="url in urls" :key="url" :url="url" :compact="true" :detail="false" :class="$style.urlPreview"/> </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"> <I18n v-if="muted === 'sensitiveMute'" :src="i18n.ts.userSaysSomethingSensitive" tag="small"> <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"/> </MkA> </template> </I18n> <I18n v-else :src="i18n.ts.userSaysSomething" tag="small"> <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"/> </MkA> </template> diff --git a/packages/frontend/src/components/MkNoteEmbed.vue b/packages/frontend/src/components/MkNoteEmbed.vue index 7a5d17520b..c8ab641385 100644 --- a/packages/frontend/src/components/MkNoteEmbed.vue +++ b/packages/frontend/src/components/MkNoteEmbed.vue @@ -11,12 +11,12 @@ SPDX-License-Identifier: AGPL-3.0-only > <MkNoteSub v-if="appearNote.reply" :note="appearNote.reply" :class="$style.replyTo"/> <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> <span :class="$style.renoteText"> <I18n :src="i18n.ts.renotedBy" tag="span"> <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"/> </MkA> </template> @@ -36,12 +36,12 @@ SPDX-License-Identifier: AGPL-3.0-only </div> <article :class="$style.note"> <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.noteHeaderBodyUpper"> <div style="min-width: 0;"> <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"/> </MkA> <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" :nyaize="'respect'" :emojiUrls="appearNote.emojis" - :enableEmojiMenu="true" - :enableEmojiMenuReaction="true" /> <a v-if="appearNote.renote != null" :class="$style.rn">RN:</a> <div v-if="appearNote.files && appearNote.files.length > 0"> <MkMediaList :mediaList="appearNote.files" :originalEntityUrl="`${url}/notes/${appearNote.id}`"/> </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> <button v-if="isLong && collapsed" :class="$style.collapsed" class="_button" @click="collapsed = false"> <span :class="$style.collapsedLabel">{{ i18n.ts.showMore }}</span> diff --git a/packages/frontend/src/components/MkNoteHeader.vue b/packages/frontend/src/components/MkNoteHeader.vue index be5829d92f..e8ed82e2b8 100644 --- a/packages/frontend/src/components/MkNoteHeader.vue +++ b/packages/frontend/src/components/MkNoteHeader.vue @@ -8,7 +8,7 @@ SPDX-License-Identifier: AGPL-3.0-only <div v-if="mock" :class="$style.name"> <MkUserName :user="note.user"/> </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"/> </MkA> <div v-if="note.user.isBot" :class="$style.isBot">bot</div> @@ -46,6 +46,7 @@ defineProps<{ }>(); const mock = inject<boolean>('mock', false); +const inEmbedPage = inject<boolean>('EMBED_PAGE', false); </script> <style lang="scss" module> diff --git a/packages/frontend/src/components/MkNoteSimple.vue b/packages/frontend/src/components/MkNoteSimple.vue index c3f3c42b42..403db994cf 100644 --- a/packages/frontend/src/components/MkNoteSimple.vue +++ b/packages/frontend/src/components/MkNoteSimple.vue @@ -5,7 +5,7 @@ SPDX-License-Identifier: AGPL-3.0-only <template> <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"> <MkNoteHeader :class="$style.header" :note="note" :mini="true"/> <div> @@ -22,7 +22,7 @@ SPDX-License-Identifier: AGPL-3.0-only </template> <script lang="ts" setup> -import { ref } from 'vue'; +import { ref, inject } from 'vue'; import * as Misskey from 'misskey-js'; import MkNoteHeader from '@/components/MkNoteHeader.vue'; import MkSubNoteContent from '@/components/MkSubNoteContent.vue'; @@ -32,6 +32,8 @@ const props = defineProps<{ note: Misskey.entities.Note; }>(); +const inEmbedPage = inject<boolean>('EMBED_PAGE', false); + const showContent = ref(false); </script> diff --git a/packages/frontend/src/components/MkNoteSub.vue b/packages/frontend/src/components/MkNoteSub.vue index 829b37e7a7..75dce2f840 100644 --- a/packages/frontend/src/components/MkNoteSub.vue +++ b/packages/frontend/src/components/MkNoteSub.vue @@ -7,7 +7,7 @@ SPDX-License-Identifier: AGPL-3.0-only <div v-if="!muted" :class="[$style.root, { [$style.children]: depth > 1 }]"> <div :class="$style.main"> <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"> <MkNoteHeader :class="$style.header" :note="note" :mini="true"/> <div> @@ -40,7 +40,7 @@ SPDX-License-Identifier: AGPL-3.0-only </template> <script lang="ts" setup> -import { ref } from 'vue'; +import { ref, inject } from 'vue'; import * as Misskey from 'misskey-js'; import MkNoteHeader from '@/components/MkNoteHeader.vue'; import MkSubNoteContent from '@/components/MkSubNoteContent.vue'; @@ -62,6 +62,8 @@ const props = withDefaults(defineProps<{ depth: 1, }); +const inEmbedPage = inject<boolean>('EMBED_PAGE', false); + const muted = ref($i ? checkWordMute(props.note, $i, $i.mutedWords) : false); const showContent = ref(false); diff --git a/packages/frontend/src/components/MkPoll.vue b/packages/frontend/src/components/MkPoll.vue index 72bd8f4f6c..917eb0819d 100644 --- a/packages/frontend/src/components/MkPoll.vue +++ b/packages/frontend/src/components/MkPoll.vue @@ -4,7 +4,7 @@ SPDX-License-Identifier: AGPL-3.0-only --> <template> -<div :class="{ [$style.done]: closed || isVoted }"> +<div :class="{ [$style.done]: closed || isVoted || readOnly }"> <ul :class="$style.choices"> <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> @@ -83,10 +83,10 @@ if (props.poll.expiresAt) { } const vote = async (id) => { - pleaseLogin(undefined, pleaseLoginContext.value); - if (props.readOnly || closed.value || isVoted.value) return; + pleaseLogin(undefined, pleaseLoginContext.value); + const { canceled } = await os.confirm({ type: 'question', text: i18n.tsx.voteConfirm({ choice: props.poll.choices[id].text }), @@ -145,7 +145,7 @@ const vote = async (id) => { .done { .choice { - cursor: default; + cursor: initial; } } </style> diff --git a/packages/frontend/src/components/MkSubNoteContent.vue b/packages/frontend/src/components/MkSubNoteContent.vue index 2b26e449ca..e9d1fa9a89 100644 --- a/packages/frontend/src/components/MkSubNoteContent.vue +++ b/packages/frontend/src/components/MkSubNoteContent.vue @@ -18,7 +18,7 @@ SPDX-License-Identifier: AGPL-3.0-only </details> <details v-if="note.poll"> <summary>{{ i18n.ts.poll }}</summary> - <MkPoll :noteId="note.id" :poll="note.poll"/> + <MkPoll :noteId="note.id" :poll="note.poll" :readOnly="inEmbedPage"/> </details> <button v-if="isLong && collapsed" :class="$style.fade" class="_button" @click="collapsed = false"> <span :class="$style.fadeLabel">{{ i18n.ts.showMore }}</span> @@ -30,7 +30,7 @@ SPDX-License-Identifier: AGPL-3.0-only </template> <script lang="ts" setup> -import { ref } from 'vue'; +import { ref, inject } from 'vue'; import * as Misskey from 'misskey-js'; import MkMediaList from '@/components/MkMediaList.vue'; import MkPoll from '@/components/MkPoll.vue'; @@ -44,6 +44,8 @@ const props = defineProps<{ const isLong = shouldCollapsed(props.note, []); +const inEmbedPage = inject<boolean>('EMBED_PAGE', false); + const collapsed = ref(isLong); </script> diff --git a/packages/frontend/src/instance.ts b/packages/frontend/src/instance.ts index 6847321d6c..0067543411 100644 --- a/packages/frontend/src/instance.ts +++ b/packages/frontend/src/instance.ts @@ -8,6 +8,7 @@ import * as Misskey from 'misskey-js'; import { misskeyApi } from '@/scripts/misskey-api.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 { embedPage } from '@/config.js'; // 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 isEnabledUrlPreview = computed(() => instance.enableUrlPreview ?? true); +export const isEnabledUrlPreview = computed(() => (instance.enableUrlPreview ?? true) && !embedPage); export async function fetchInstance(force = false): Promise<Misskey.entities.MetaDetailed> { if (!force) { diff --git a/packages/frontend/src/os.ts b/packages/frontend/src/os.ts index 768aa269eb..984a2fb0b1 100644 --- a/packages/frontend/src/os.ts +++ b/packages/frontend/src/os.ts @@ -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]; }; -type PopupOptions = { - callEvenOnEmbedPage?: boolean; -}; - export function popup<T extends Component>( component: T, props: ComponentProps<T>, events: ComponentEmit<T> = {} as ComponentEmit<T>, - options: PopupOptions = {}, ): { dispose: () => void } { - const _options = Object.assign({ - callEvenOnEmbedPage: false, - }, options) as Required<PopupOptions>; - - if (embedPage && !_options.callEvenOnEmbedPage) return { dispose: () => {} }; - markRaw(component); const id = ++popupIdCount; diff --git a/packages/frontend/src/scripts/please-login.ts b/packages/frontend/src/scripts/please-login.ts index 18f05bc7f4..93db66fe43 100644 --- a/packages/frontend/src/scripts/please-login.ts +++ b/packages/frontend/src/scripts/please-login.ts @@ -3,10 +3,11 @@ * SPDX-License-Identifier: AGPL-3.0-only */ -import { defineAsyncComponent } from 'vue'; +import { defineAsyncComponent, inject } from 'vue'; import { $i } from '@/account.js'; import { i18n } from '@/i18n.js'; import { popup } from '@/os.js'; +import { embedPage } from '@/config.js'; export type OpenOnRemoteOptions = { /** @@ -47,18 +48,22 @@ export type OpenOnRemoteOptions = { export function pleaseLogin(path?: string, openOnRemote?: OpenOnRemoteOptions) { if ($i) return; - const { dispose } = popup(defineAsyncComponent(() => import('@/components/MkSigninDialog.vue')), { - autoSet: true, - message: openOnRemote ? i18n.ts.signinOrContinueOnRemote : i18n.ts.signinRequired, - openOnRemote, - }, { - cancelled: () => { - if (path) { - window.location.href = path; - } - }, - closed: () => dispose(), - }); + if (embedPage) { + window.open(path ?? '/', '_blank', 'noopener'); + } else { + const { dispose } = popup(defineAsyncComponent(() => import('@/components/MkSigninDialog.vue')), { + autoSet: true, + message: openOnRemote ? i18n.ts.signinOrContinueOnRemote : i18n.ts.signinRequired, + openOnRemote, + }, { + cancelled: () => { + if (path) { + window.location.href = path; + } + }, + closed: () => dispose(), + }); + } throw new Error('signin required'); }