From 0e8fe41aaaa14aa8132f6d136b779c1f726fc012 Mon Sep 17 00:00:00 2001 From: naskya Date: Sat, 1 Apr 2023 06:53:29 +0000 Subject: [PATCH] feat: add option to boost with Home and Followers-only visibility (#9788) Closes: #9777 This pull request includes UI changes (please check the attached images). Co-authored-by: naskya Reviewed-on: https://codeberg.org/calckey/calckey/pulls/9788 Co-authored-by: naskya Co-committed-by: naskya --- locales/en-US.yml | 3 + locales/ja-JP.yml | 3 + packages/client/src/components/MkMenu.vue | 24 +++- .../client/src/components/MkRenoteButton.vue | 103 +++++++++++++++--- packages/client/src/types/menu.ts | 27 ++++- 5 files changed, 134 insertions(+), 26 deletions(-) diff --git a/locales/en-US.yml b/locales/en-US.yml index 9f675778aa..8802039220 100644 --- a/locales/en-US.yml +++ b/locales/en-US.yml @@ -96,6 +96,9 @@ unfollow: "Unfollow" followRequestPending: "Follow request pending" enterEmoji: "Enter an emoji" renote: "Boost" +renoteAsUnlisted: "Boost (Unlisted)" +renoteToFollowers: "Boost (Followers)" +renoteToRecipients: "Boost (Recipients)" unrenote: "Take back boost" renoted: "Boosted." cantRenote: "This post can't be boosted." diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml index b7ead22e88..0bdc4af1db 100644 --- a/locales/ja-JP.yml +++ b/locales/ja-JP.yml @@ -96,6 +96,9 @@ unfollow: "フォロー解除" followRequestPending: "フォロー許可待ち" enterEmoji: "絵文字を入力" renote: "ブースト" +renoteAsUnlisted: "ホームにブースト" +renoteToFollowers: "フォロワー限定でブースト" +renoteToRecipients: "宛先のユーザーにブースト" unrenote: "ブースト解除" renoted: "ブーストしました。" cantRenote: "この投稿はブーストできません。" diff --git a/packages/client/src/components/MkMenu.vue b/packages/client/src/components/MkMenu.vue index 1b8a609c95..c0502387a6 100644 --- a/packages/client/src/components/MkMenu.vue +++ b/packages/client/src/components/MkMenu.vue @@ -10,20 +10,26 @@ diff --git a/packages/client/src/components/MkRenoteButton.vue b/packages/client/src/components/MkRenoteButton.vue index 5a9369a900..11bcd8bd51 100644 --- a/packages/client/src/components/MkRenoteButton.vue +++ b/packages/client/src/components/MkRenoteButton.vue @@ -64,24 +64,91 @@ const renote = async (viaKeyboard = false, ev?: MouseEvent) => { const users = renotes.map(x => x.user.id); const hasRenotedBefore = users.includes($i.id); - let buttonActions = [{ - text: i18n.ts.renote, - icon: 'ph-repeat ph-bold ph-lg', - danger: false, - action: () => { - os.api('notes/create', { - renoteId: props.note.id, - visibility: props.note.visibility, - }); - const el = ev && (ev.currentTarget ?? ev.target) as HTMLElement | null | undefined; - if (el) { - const rect = el.getBoundingClientRect(); - const x = rect.left + (el.offsetWidth / 2); - const y = rect.top + (el.offsetHeight / 2); - os.popup(Ripple, { x, y }, {}, 'end'); - } - }, - }]; + let buttonActions = []; + + if (props.note.visibility === 'public') { + buttonActions.push({ + text: i18n.ts.renote, + textStyle: 'font-weight: bold', + icon: 'ph-repeat ph-bold ph-lg', + danger: false, + action: () => { + os.api('notes/create', { + renoteId: props.note.id, + visibility: 'public', + }); + const el = ev && (ev.currentTarget ?? ev.target) as HTMLElement | null | undefined; + if (el) { + const rect = el.getBoundingClientRect(); + const x = rect.left + (el.offsetWidth / 2); + const y = rect.top + (el.offsetHeight / 2); + os.popup(Ripple, { x, y }, {}, 'end'); + } + }, + }); + } + + if (['public', 'home'].includes(props.note.visibility)) { + buttonActions.push({ + text: i18n.ts.renoteAsUnlisted, + icons: ['ph-repeat ph-bold ph-lg', 'ph-house ph-bold ph-lg'], + danger: false, + action: () => { + os.api('notes/create', { + renoteId: props.note.id, + visibility: 'home', + }); + const el = ev && (ev.currentTarget ?? ev.target) as HTMLElement | null | undefined; + if (el) { + const rect = el.getBoundingClientRect(); + const x = rect.left + (el.offsetWidth / 2); + const y = rect.top + (el.offsetHeight / 2); + os.popup(Ripple, { x, y }, {}, 'end'); + } + }, + }); + } + + if (props.note.visibility === 'specified') { + buttonActions.push({ + text: i18n.ts.renoteToRecipients, + icons: ['ph-repeat ph-bold ph-lg', 'ph-envelope-simple-open ph-bold ph-lg'], + danger: false, + action: () => { + os.api('notes/create', { + renoteId: props.note.id, + visibility: 'specified', + visibleUserIds: props.note.visibleUserIds, + }); + const el = ev && (ev.currentTarget ?? ev.target) as HTMLElement | null | undefined; + if (el) { + const rect = el.getBoundingClientRect(); + const x = rect.left + (el.offsetWidth / 2); + const y = rect.top + (el.offsetHeight / 2); + os.popup(Ripple, { x, y }, {}, 'end'); + } + }, + }); + } else { + buttonActions.push({ + text: i18n.ts.renoteToFollowers, + icons: ['ph-repeat ph-bold ph-lg', 'ph-lock-simple-open ph-bold ph-lg'], + danger: false, + action: () => { + os.api('notes/create', { + renoteId: props.note.id, + visibility: 'followers', + }); + const el = ev && (ev.currentTarget ?? ev.target) as HTMLElement | null | undefined; + if (el) { + const rect = el.getBoundingClientRect(); + const x = rect.left + (el.offsetWidth / 2); + const y = rect.top + (el.offsetHeight / 2); + os.popup(Ripple, { x, y }, {}, 'end'); + } + }, + }); + } if (!defaultStore.state.seperateRenoteQuote) { buttonActions.push({ diff --git a/packages/client/src/types/menu.ts b/packages/client/src/types/menu.ts index e1bfc20a33..a7ce81c714 100644 --- a/packages/client/src/types/menu.ts +++ b/packages/client/src/types/menu.ts @@ -5,11 +5,16 @@ export type MenuAction = (ev: MouseEvent) => void; export type MenuDivider = null; export type MenuNull = undefined; -export type MenuLabel = { type: "label"; text: string }; +export type MenuLabel = { + type: "label"; + text: string; + textStyle?: string; +}; export type MenuLink = { type: "link"; to: string; text: string; + textStyle?: string; icon?: string; indicate?: boolean; avatar?: Misskey.entities.User; @@ -20,6 +25,7 @@ export type MenuA = { target?: string; download?: string; text: string; + textStyle?: string; icon?: string; indicate?: boolean; }; @@ -35,11 +41,13 @@ export type MenuSwitch = { type: "switch"; ref: Ref; text: string; + textStyle?: string; disabled?: boolean; }; export type MenuButton = { type?: "button"; text: string; + textStyle?: string; icon?: string; indicate?: boolean; danger?: boolean; @@ -48,9 +56,22 @@ export type MenuButton = { avatar?: Misskey.entities.User; action: MenuAction; }; +export type MenuButtonMultipleIcons = { + type?: "button"; + text: string; + textStyle?: string; + icons: string[]; + indicate?: boolean; + danger?: boolean; + active?: boolean; + hidden?: boolean; + avatar?: Misskey.entities.User; + action: MenuAction; +}; export type MenuParent = { type: "parent"; text: string; + textStyle?: string; icon?: string; children: OuterMenuItem[]; }; @@ -66,9 +87,10 @@ type OuterMenuItem = | MenuUser | MenuSwitch | MenuButton + | MenuButtonMultipleIcons | MenuParent; type OuterPromiseMenuItem = Promise< - MenuLabel | MenuLink | MenuA | MenuUser | MenuSwitch | MenuButton | MenuParent + MenuLabel | MenuLink | MenuA | MenuUser | MenuSwitch | MenuButton | MenuButtonMultipleIcons | MenuParent >; export type MenuItem = OuterMenuItem | OuterPromiseMenuItem; export type InnerMenuItem = @@ -80,4 +102,5 @@ export type InnerMenuItem = | MenuUser | MenuSwitch | MenuButton + | MenuButtonMultipleIcons | MenuParent;