From 413f7bfb44e885c82ba49fc098b620831830d0c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=81=8A=E3=81=95=E3=82=80=E3=81=AE=E3=81=B2=E3=81=A8?= <46447427+samunohito@users.noreply.github.com> Date: Thu, 30 Nov 2023 08:15:13 +0900 Subject: [PATCH] =?UTF-8?q?Fix:=20navigator.share=E6=9C=AA=E3=82=B5?= =?UTF-8?q?=E3=83=9D=E3=83=BC=E3=83=88=E3=81=AE=E5=A0=B4=E5=90=88=E3=81=AF?= =?UTF-8?q?=E5=85=B1=E6=9C=89=E3=83=9C=E3=82=BF=E3=83=B3=E3=82=92=E9=9D=9E?= =?UTF-8?q?=E8=A1=A8=E7=A4=BA=E3=81=AB=E3=81=99=E3=82=8B=EF=BC=88=EF=BC=8B?= =?UTF-8?q?URL=E3=81=AE=E3=82=B3=E3=83=94=E3=83=BC=E3=83=9C=E3=82=BF?= =?UTF-8?q?=E3=83=B3=E3=82=92=E8=A8=AD=E7=BD=AE=EF=BC=89=20(#12506)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * navigator.share未サポートの場合は共有ボタンを非表示にする * fix CHANGELOG.md * ライセンス表示追加 * URLのコピーボタンを設置 --- CHANGELOG.md | 2 + .../src/components/global/MkPageHeader.vue | 8 +-- packages/frontend/src/pages/channel.vue | 53 +++++++++++++------ packages/frontend/src/pages/clip.vue | 9 ++++ packages/frontend/src/pages/flash/flash.vue | 10 +++- packages/frontend/src/pages/gallery/post.vue | 10 +++- packages/frontend/src/pages/page.vue | 10 +++- .../frontend/src/scripts/get-note-menu.ts | 7 +-- packages/frontend/src/scripts/navigator.ts | 8 +++ packages/frontend/src/types/page-header.ts | 11 ++++ 10 files changed, 99 insertions(+), 29 deletions(-) create mode 100644 packages/frontend/src/scripts/navigator.ts create mode 100644 packages/frontend/src/types/page-header.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index 1ed930437e..d2e6702a92 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -26,11 +26,13 @@ - Enhance: リアクション選択時に音を鳴らせるように - Enhance: サウンドにドライブのファイルを使用できるように - Enhance: Shareページで投稿を完了すると、親ウィンドウ(親フレーム)にpostMessageするように +- Enhance: チャンネル、クリップ、ページ、Play、ギャラリーにURLのコピーボタンを設置 #11305 - fix: 「設定のバックアップ」で一部の項目がバックアップに含まれていなかった問題を修正 - Fix: ウィジェットのジョブキューにて音声の発音方法変更に追従できていなかったのを修正 #12367 - Fix: コードエディタが正しく表示されない問題を修正 - Fix: プロフィールの「ファイル」にセンシティブな画像がある際のデザインを修正 - Fix: 一度に大量の通知が入った際に通知音が音割れする問題を修正 +- Fix: 共有機能をサポートしていないブラウザの場合は共有ボタンを非表示にする #11305 - Fix: 通知のグルーピング設定を変更してもリロードされるまで表示が変わらない問題を修正 #12470 ### Server diff --git a/packages/frontend/src/components/global/MkPageHeader.vue b/packages/frontend/src/components/global/MkPageHeader.vue index 580816abaa..935ca33eb5 100644 --- a/packages/frontend/src/components/global/MkPageHeader.vue +++ b/packages/frontend/src/components/global/MkPageHeader.vue @@ -48,16 +48,12 @@ import { scrollToTop } from '@/scripts/scroll.js'; import { globalEvents } from '@/events.js'; import { injectPageMetadata } from '@/scripts/page-metadata.js'; import { $i, openAccountMenu as openAccountMenu_ } from '@/account.js'; +import { PageHeaderItem } from '@/types/page-header.js'; const props = withDefaults(defineProps<{ tabs?: Tab[]; tab?: string; - actions?: { - text: string; - icon: string; - highlighted?: boolean; - handler: (ev: MouseEvent) => void; - }[]; + actions?: PageHeaderItem[]; thin?: boolean; displayMyAvatar?: boolean; }>(), { diff --git a/packages/frontend/src/pages/channel.vue b/packages/frontend/src/pages/channel.vue index 1d41fe7529..dc374e2925 100644 --- a/packages/frontend/src/pages/channel.vue +++ b/packages/frontend/src/pages/channel.vue @@ -86,6 +86,9 @@ import { defaultStore } from '@/store.js'; import MkNote from '@/components/MkNote.vue'; import MkInfo from '@/components/MkInfo.vue'; import MkFoldableSection from '@/components/MkFoldableSection.vue'; +import { PageHeaderItem } from '@/types/page-header.js'; +import { isSupportShare } from '@/scripts/navigator.js'; +import copyToClipboard from '@/scripts/copy-to-clipboard.js'; const router = useRouter(); @@ -167,24 +170,40 @@ async function search() { const headerActions = $computed(() => { if (channel && channel.userId) { - const share = { - icon: 'ti ti-share', - text: i18n.ts.share, - handler: async (): Promise => { - navigator.share({ - title: channel.name, - text: channel.description, - url: `${url}/channels/${channel.id}`, - }); - }, - }; + const headerItems: PageHeaderItem[] = []; - const canEdit = ($i && $i.id === channel.userId) || iAmModerator; - return canEdit ? [share, { - icon: 'ti ti-settings', - text: i18n.ts.edit, - handler: edit, - }] : [share]; + headerItems.push({ + icon: 'ti ti-link', + text: i18n.ts.copyUrl, + handler: async (): Promise => { + copyToClipboard(`${url}/channels/${channel.id}`); + os.success(); + }, + }); + + if (isSupportShare()) { + headerItems.push({ + icon: 'ti ti-share', + text: i18n.ts.share, + handler: async (): Promise => { + navigator.share({ + title: channel.name, + text: channel.description, + url: `${url}/channels/${channel.id}`, + }); + }, + }); + } + + if (($i && $i.id === channel.userId) || iAmModerator) { + headerItems.push({ + icon: 'ti ti-settings', + text: i18n.ts.edit, + handler: edit, + }); + } + + return headerItems.length > 0 ? headerItems : null; } else { return null; } diff --git a/packages/frontend/src/pages/clip.vue b/packages/frontend/src/pages/clip.vue index 4573bbb81c..b32c8a3864 100644 --- a/packages/frontend/src/pages/clip.vue +++ b/packages/frontend/src/pages/clip.vue @@ -36,6 +36,8 @@ import { definePageMetadata } from '@/scripts/page-metadata.js'; import { url } from '@/config.js'; import MkButton from '@/components/MkButton.vue'; import { clipsCache } from '@/cache'; +import { isSupportShare } from '@/scripts/navigator.js'; +import copyToClipboard from '@/scripts/copy-to-clipboard.js'; const props = defineProps<{ clipId: string, @@ -118,6 +120,13 @@ const headerActions = $computed(() => clip && isOwned ? [{ clipsCache.delete(); }, }, ...(clip.isPublic ? [{ + icon: 'ti ti-link', + text: i18n.ts.copyUrl, + handler: async (): Promise => { + copyToClipboard(`${url}/clips/${clip.id}`); + os.success(); + }, +}] : []), ...(clip.isPublic && isSupportShare() ? [{ icon: 'ti ti-share', text: i18n.ts.share, handler: async (): Promise => { diff --git a/packages/frontend/src/pages/flash/flash.vue b/packages/frontend/src/pages/flash/flash.vue index ebf117ffbf..4755eb5062 100644 --- a/packages/frontend/src/pages/flash/flash.vue +++ b/packages/frontend/src/pages/flash/flash.vue @@ -18,7 +18,8 @@ SPDX-License-Identifier: AGPL-3.0-only {{ flash.likedCount }} {{ flash.likedCount }} - + +
@@ -70,6 +71,8 @@ import MkFolder from '@/components/MkFolder.vue'; import MkCode from '@/components/MkCode.vue'; import { defaultStore } from '@/store.js'; import { $i } from '@/account.js'; +import { isSupportShare } from '@/scripts/navigator.js'; +import copyToClipboard from '@/scripts/copy-to-clipboard.js'; const props = defineProps<{ id: string; @@ -89,6 +92,11 @@ function fetchFlash() { }); } +function copyLink() { + copyToClipboard(`${url}/play/${flash.id}`); + os.success(); +} + function share() { navigator.share({ title: flash.title, diff --git a/packages/frontend/src/pages/gallery/post.vue b/packages/frontend/src/pages/gallery/post.vue index 3863348eae..5b551f75b5 100644 --- a/packages/frontend/src/pages/gallery/post.vue +++ b/packages/frontend/src/pages/gallery/post.vue @@ -29,7 +29,8 @@ SPDX-License-Identifier: AGPL-3.0-only
- + +
@@ -74,6 +75,8 @@ import { i18n } from '@/i18n.js'; import { definePageMetadata } from '@/scripts/page-metadata.js'; import { defaultStore } from '@/store.js'; import { $i } from '@/account.js'; +import { isSupportShare } from '@/scripts/navigator.js'; +import copyToClipboard from '@/scripts/copy-to-clipboard.js'; const router = useRouter(); @@ -102,6 +105,11 @@ function fetchPost() { }); } +function copyLink() { + copyToClipboard(`${url}/gallery/${post.id}`); + os.success(); +} + function share() { navigator.share({ title: post.title, diff --git a/packages/frontend/src/pages/page.vue b/packages/frontend/src/pages/page.vue index 98cbaab2bb..2bc053ccfe 100644 --- a/packages/frontend/src/pages/page.vue +++ b/packages/frontend/src/pages/page.vue @@ -34,7 +34,8 @@ SPDX-License-Identifier: AGPL-3.0-only
- + +
@@ -90,6 +91,8 @@ import { definePageMetadata } from '@/scripts/page-metadata.js'; import { pageViewInterruptors, defaultStore } from '@/store.js'; import { deepClone } from '@/scripts/clone.js'; import { $i } from '@/account.js'; +import { isSupportShare } from '@/scripts/navigator.js'; +import copyToClipboard from '@/scripts/copy-to-clipboard.js'; const props = defineProps<{ pageName: string; @@ -136,6 +139,11 @@ function share() { }); } +function copyLink() { + copyToClipboard(`${url}/@${page.user.username}/pages/${page.name}`); + os.success(); +} + function shareWithNote() { os.post({ initialText: `${page.title || page.name} ${url}/@${page.user.username}/pages/${page.name}`, diff --git a/packages/frontend/src/scripts/get-note-menu.ts b/packages/frontend/src/scripts/get-note-menu.ts index d0753872ff..763f6ff513 100644 --- a/packages/frontend/src/scripts/get-note-menu.ts +++ b/packages/frontend/src/scripts/get-note-menu.ts @@ -18,6 +18,7 @@ import { getUserMenu } from '@/scripts/get-user-menu.js'; import { clipsCache } from '@/cache.js'; import { MenuItem } from '@/types/menu.js'; import MkRippleEffect from '@/components/MkRippleEffect.vue'; +import { isSupportShare } from '@/scripts/navigator.js'; export async function getNoteClipMenu(props: { note: Misskey.entities.Note; @@ -280,11 +281,11 @@ export function getNoteMenu(props: { window.open(appearNote.url ?? appearNote.uri, '_blank'); }, } : undefined, - { + ...(isSupportShare() ? [{ icon: 'ti ti-share', text: i18n.ts.share, action: share, - }, + }] : []), $i && $i.policies.canUseTranslator && instance.translatorAvailable ? { icon: 'ti ti-language-hiragana', text: i18n.ts.translate, @@ -484,7 +485,7 @@ export function getRenoteMenu(props: { }]); } - if (!appearNote.channel || appearNote.channel?.allowRenoteToExternal) { + if (!appearNote.channel || appearNote.channel.allowRenoteToExternal) { normalRenoteItems.push(...[{ text: i18n.ts.renote, icon: 'ti ti-repeat', diff --git a/packages/frontend/src/scripts/navigator.ts b/packages/frontend/src/scripts/navigator.ts new file mode 100644 index 0000000000..b13186a10e --- /dev/null +++ b/packages/frontend/src/scripts/navigator.ts @@ -0,0 +1,8 @@ +/* + * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-License-Identifier: AGPL-3.0-only + */ + +export function isSupportShare(): boolean { + return 'share' in navigator; +} diff --git a/packages/frontend/src/types/page-header.ts b/packages/frontend/src/types/page-header.ts new file mode 100644 index 0000000000..295b97a7fd --- /dev/null +++ b/packages/frontend/src/types/page-header.ts @@ -0,0 +1,11 @@ +/* + * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-License-Identifier: AGPL-3.0-only + */ + +export type PageHeaderItem = { + text: string; + icon: string; + highlighted?: boolean; + handler: (ev: MouseEvent) => void; +};