diff --git a/locales/index.d.ts b/locales/index.d.ts index 9d307734d9..3a3b94b89d 100644 --- a/locales/index.d.ts +++ b/locales/index.d.ts @@ -10809,6 +10809,10 @@ export interface Locale extends ILocale { * Date */ "date": string; + /** + * Boost (hold Shift for visibility menu) + */ + "renoteShift": string; /** * Quoted. */ diff --git a/packages/frontend/src/components/MkNote.vue b/packages/frontend/src/components/MkNote.vue index 25d04a0b6a..5c6c6f45bb 100644 --- a/packages/frontend/src/components/MkNote.vue +++ b/packages/frontend/src/components/MkNote.vue @@ -128,11 +128,12 @@ SPDX-License-Identifier: AGPL-3.0-only <button v-if="canRenote" ref="renoteButton" + v-tooltip="renoteTooltip" :class="$style.footerButton" class="_button" :style="renoted ? 'color: var(--MI_THEME-accent) !important;' : ''" @click.stop - @mousedown.prevent="renoted ? undoRenote(appearNote) : boostVisibility()" + @mousedown.prevent="renoted ? undoRenote(appearNote) : boostVisibility($event.shiftKey)" > <i class="ti ti-repeat"></i> <p v-if="appearNote.renoteCount > 0" :class="$style.footerButtonCount">{{ number(appearNote.renoteCount) }}</p> @@ -238,7 +239,7 @@ import { getNoteSummary } from '@/scripts/get-note-summary.js'; import MkRippleEffect from '@/components/MkRippleEffect.vue'; import { showMovedDialog } from '@/scripts/show-moved-dialog.js'; import { useRouter } from '@/router/supplier.js'; -import { boostMenuItems, type Visibility } from '@/scripts/boost-quote.js'; +import { boostMenuItems, type Visibility, computeRenoteTooltip } from '@/scripts/boost-quote.js'; import { isEnabledUrlPreview } from '@/instance.js'; import { type Keymap } from '@/scripts/hotkey.js'; import { focusPrev, focusNext } from '@/scripts/focus.js'; @@ -338,6 +339,8 @@ const pleaseLoginContext = computed<OpenOnRemoteOptions>(() => ({ url: `https://${host}/notes/${appearNote.value.id}`, })); +const renoteTooltip = computeRenoteTooltip(renoted); + /* Overload FunctionにLintが対応していないのでコメントアウト function checkMute(noteToCheck: Misskey.entities.Note, mutedWords: Array<string | string[]> | undefined | null, checkOnly: true): boolean; function checkMute(noteToCheck: Misskey.entities.Note, mutedWords: Array<string | string[]> | undefined | null, checkOnly: false): boolean | 'sensitiveMute'; @@ -506,10 +509,10 @@ if (!props.mock) { } } -function boostVisibility() { +function boostVisibility(forceMenu: boolean = false) { if (renoting) return; - if (!defaultStore.state.showVisibilitySelectorOnBoost) { + if (!defaultStore.state.showVisibilitySelectorOnBoost && !forceMenu) { renote(defaultStore.state.visibilityOnBoost); } else { os.popupMenu(boostMenuItems(appearNote, renote), renoteButton.value); diff --git a/packages/frontend/src/components/MkNoteDetailed.vue b/packages/frontend/src/components/MkNoteDetailed.vue index 243b95215a..93a543dff1 100644 --- a/packages/frontend/src/components/MkNoteDetailed.vue +++ b/packages/frontend/src/components/MkNoteDetailed.vue @@ -140,10 +140,11 @@ SPDX-License-Identifier: AGPL-3.0-only <button v-if="canRenote" ref="renoteButton" + v-tooltip="renoteTooltip" class="_button" :class="$style.noteFooterButton" :style="renoted ? 'color: var(--MI_THEME-accent) !important;' : ''" - @mousedown.prevent="renoted ? undoRenote() : boostVisibility()" + @mousedown.prevent="renoted ? undoRenote() : boostVisibility($event.shiftKey)" > <i class="ti ti-repeat"></i> <p v-if="appearNote.renoteCount > 0" :class="$style.noteFooterButtonCount">{{ number(appearNote.renoteCount) }}</p> @@ -280,7 +281,7 @@ import MkUserCardMini from '@/components/MkUserCardMini.vue'; import MkPagination, { type Paging } from '@/components/MkPagination.vue'; import MkReactionIcon from '@/components/MkReactionIcon.vue'; import MkButton from '@/components/MkButton.vue'; -import { boostMenuItems, type Visibility } from '@/scripts/boost-quote.js'; +import { boostMenuItems, type Visibility, computeRenoteTooltip } from '@/scripts/boost-quote.js'; import { isEnabledUrlPreview } from '@/instance.js'; import { getAppearNote } from '@/scripts/get-appear-note.js'; import { type Keymap } from '@/scripts/hotkey.js'; @@ -347,6 +348,8 @@ const quotes = ref<Misskey.entities.Note[]>([]); const canRenote = computed(() => ['public', 'home'].includes(appearNote.value.visibility) || (appearNote.value.visibility === 'followers' && appearNote.value.userId === $i?.id)); const defaultLike = computed(() => defaultStore.state.like ? defaultStore.state.like : null); +const renoteTooltip = computeRenoteTooltip(renoted); + watch(() => props.expandAllCws, (expandAllCws) => { if (expandAllCws !== showContent.value) showContent.value = expandAllCws; }); @@ -478,10 +481,10 @@ useTooltip(quoteButton, async (showing) => { }); }); -function boostVisibility() { +function boostVisibility(forceMenu: boolean = false) { if (renoting) return; - if (!defaultStore.state.showVisibilitySelectorOnBoost) { + if (!defaultStore.state.showVisibilitySelectorOnBoost && !forceMenu) { renote(defaultStore.state.visibilityOnBoost); } else { os.popupMenu(boostMenuItems(appearNote, renote), renoteButton.value); diff --git a/packages/frontend/src/components/MkNoteSub.vue b/packages/frontend/src/components/MkNoteSub.vue index 3523babe46..9febc1219c 100644 --- a/packages/frontend/src/components/MkNoteSub.vue +++ b/packages/frontend/src/components/MkNoteSub.vue @@ -28,10 +28,11 @@ SPDX-License-Identifier: AGPL-3.0-only <button v-if="canRenote" ref="renoteButton" + v-tooltip="renoteTooltip" class="_button" :class="$style.noteFooterButton" :style="renoted ? 'color: var(--MI_THEME-accent) !important;' : ''" - @mousedown="renoted ? undoRenote() : boostVisibility()" + @mousedown="renoted ? undoRenote() : boostVisibility($event.shiftKey)" > <i class="ph-rocket-launch ph-bold ph-lg"></i> <p v-if="note.renoteCount > 0" :class="$style.noteFooterButtonCount">{{ note.renoteCount }}</p> @@ -106,7 +107,7 @@ import { reactionPicker } from '@/scripts/reaction-picker.js'; import { claimAchievement } from '@/scripts/achievements.js'; import { getNoteMenu } from '@/scripts/get-note-menu.js'; import { useNoteCapture } from '@/scripts/use-note-capture.js'; -import { boostMenuItems, type Visibility } from '@/scripts/boost-quote.js'; +import { boostMenuItems, type Visibility, computeRenoteTooltip } from '@/scripts/boost-quote.js'; const canRenote = computed(() => ['public', 'home'].includes(props.note.visibility) || props.note.userId === $i.id); @@ -135,6 +136,8 @@ const quoteButton = shallowRef<HTMLElement>(); const menuButton = shallowRef<HTMLElement>(); const likeButton = shallowRef<HTMLElement>(); +const renoteTooltip = computeRenoteTooltip(computed); + let appearNote = computed(() => isRenote ? props.note.renote as Misskey.entities.Note : props.note); const defaultLike = computed(() => defaultStore.state.like ? defaultStore.state.like : null); const replies = ref<Misskey.entities.Note[]>([]); @@ -285,8 +288,8 @@ watch(() => props.expandAllCws, (expandAllCws) => { if (expandAllCws !== showContent.value) showContent.value = expandAllCws; }); -function boostVisibility() { - if (!defaultStore.state.showVisibilitySelectorOnBoost) { +function boostVisibility(forceMenu: boolean = false) { + if (!defaultStore.state.showVisibilitySelectorOnBoost && !forceMenu) { renote(defaultStore.state.visibilityOnBoost); } else { os.popupMenu(boostMenuItems(appearNote, renote), renoteButton.value); diff --git a/packages/frontend/src/components/SkNote.vue b/packages/frontend/src/components/SkNote.vue index b4a9fa34cc..7dc513ff0b 100644 --- a/packages/frontend/src/components/SkNote.vue +++ b/packages/frontend/src/components/SkNote.vue @@ -129,11 +129,12 @@ SPDX-License-Identifier: AGPL-3.0-only <button v-if="canRenote" ref="renoteButton" + v-tooltip="renoteTooltip" :class="$style.footerButton" class="_button" :style="renoted ? 'color: var(--MI_THEME-accent) !important;' : ''" @click.stop - @mousedown.prevent="renoted ? undoRenote(appearNote) : boostVisibility()" + @mousedown.prevent="renoted ? undoRenote(appearNote) : boostVisibility($event.shiftKey)" > <i class="ti ti-repeat"></i> <p v-if="appearNote.renoteCount > 0" :class="$style.footerButtonCount">{{ number(appearNote.renoteCount) }}</p> @@ -238,7 +239,7 @@ import { getNoteSummary } from '@/scripts/get-note-summary.js'; import MkRippleEffect from '@/components/MkRippleEffect.vue'; import { showMovedDialog } from '@/scripts/show-moved-dialog.js'; import { useRouter } from '@/router/supplier.js'; -import { boostMenuItems, type Visibility } from '@/scripts/boost-quote.js'; +import { boostMenuItems, type Visibility, computeRenoteTooltip } from '@/scripts/boost-quote.js'; import { isEnabledUrlPreview } from '@/instance.js'; import { type Keymap } from '@/scripts/hotkey.js'; import { focusPrev, focusNext } from '@/scripts/focus.js'; @@ -333,6 +334,8 @@ const defaultLike = computed(() => defaultStore.state.like ? defaultStore.state. const animated = computed(() => parsed.value ? checkAnimationFromMfm(parsed.value) : null); const allowAnim = ref(defaultStore.state.advancedMfm && defaultStore.state.animatedMfm ? true : false); +const renoteTooltip = computeRenoteTooltip(renoted); + const pleaseLoginContext = computed<OpenOnRemoteOptions>(() => ({ type: 'lookup', url: `https://${host}/notes/${appearNote.value.id}`, @@ -506,10 +509,10 @@ if (!props.mock) { } } -function boostVisibility() { +function boostVisibility(forceMenu: boolean = false) { if (renoting) return; - if (!defaultStore.state.showVisibilitySelectorOnBoost) { + if (!defaultStore.state.showVisibilitySelectorOnBoost && !forceMenu) { renote(defaultStore.state.visibilityOnBoost); } else { os.popupMenu(boostMenuItems(appearNote, renote), renoteButton.value); diff --git a/packages/frontend/src/components/SkNoteDetailed.vue b/packages/frontend/src/components/SkNoteDetailed.vue index 8d7b47ae6d..69e2898264 100644 --- a/packages/frontend/src/components/SkNoteDetailed.vue +++ b/packages/frontend/src/components/SkNoteDetailed.vue @@ -145,10 +145,11 @@ SPDX-License-Identifier: AGPL-3.0-only <button v-if="canRenote" ref="renoteButton" + v-tooltip="renoteTooltip" class="_button" :class="$style.noteFooterButton" :style="renoted ? 'color: var(--MI_THEME-accent) !important;' : ''" - @mousedown.prevent="renoted ? undoRenote() : boostVisibility()" + @mousedown.prevent="renoted ? undoRenote() : boostVisibility($event.shiftKey)" > <i class="ti ti-repeat"></i> <p v-if="appearNote.renoteCount > 0" :class="$style.noteFooterButtonCount">{{ number(appearNote.renoteCount) }}</p> @@ -285,7 +286,7 @@ import MkUserCardMini from '@/components/MkUserCardMini.vue'; import MkPagination, { type Paging } from '@/components/MkPagination.vue'; import MkReactionIcon from '@/components/MkReactionIcon.vue'; import MkButton from '@/components/MkButton.vue'; -import { boostMenuItems, type Visibility } from '@/scripts/boost-quote.js'; +import { boostMenuItems, type Visibility, computeRenoteTooltip } from '@/scripts/boost-quote.js'; import { isEnabledUrlPreview } from '@/instance.js'; import { getAppearNote } from '@/scripts/get-appear-note.js'; import { type Keymap } from '@/scripts/hotkey.js'; @@ -353,6 +354,8 @@ const quotes = ref<Misskey.entities.Note[]>([]); const canRenote = computed(() => ['public', 'home'].includes(appearNote.value.visibility) || (appearNote.value.visibility === 'followers' && appearNote.value.userId === $i?.id)); const defaultLike = computed(() => defaultStore.state.like ? defaultStore.state.like : null); +const renoteTooltip = computeRenoteTooltip(renoted); + watch(() => props.expandAllCws, (expandAllCws) => { if (expandAllCws !== showContent.value) showContent.value = expandAllCws; }); @@ -484,10 +487,10 @@ useTooltip(quoteButton, async (showing) => { }); }); -function boostVisibility() { +function boostVisibility(forceMenu: boolean = false) { if (renoting) return; - if (!defaultStore.state.showVisibilitySelectorOnBoost) { + if (!defaultStore.state.showVisibilitySelectorOnBoost && !forceMenu) { renote(defaultStore.state.visibilityOnBoost); } else { os.popupMenu(boostMenuItems(appearNote, renote), renoteButton.value); diff --git a/packages/frontend/src/components/SkNoteSub.vue b/packages/frontend/src/components/SkNoteSub.vue index bd25e1e3ad..a3d27c9e16 100644 --- a/packages/frontend/src/components/SkNoteSub.vue +++ b/packages/frontend/src/components/SkNoteSub.vue @@ -36,10 +36,11 @@ SPDX-License-Identifier: AGPL-3.0-only <button v-if="canRenote" ref="renoteButton" + v-tooltip="renoteTooltip" class="_button" :class="$style.noteFooterButton" :style="renoted ? 'color: var(--MI_THEME-accent) !important;' : ''" - @mousedown="renoted ? undoRenote() : boostVisibility()" + @mousedown="renoted ? undoRenote() : boostVisibility($event.shiftKey)" > <i class="ph-rocket-launch ph-bold ph-lg"></i> <p v-if="note.renoteCount > 0" :class="$style.noteFooterButtonCount">{{ note.renoteCount }}</p> @@ -114,7 +115,7 @@ import { reactionPicker } from '@/scripts/reaction-picker.js'; import { claimAchievement } from '@/scripts/achievements.js'; import { getNoteMenu } from '@/scripts/get-note-menu.js'; import { useNoteCapture } from '@/scripts/use-note-capture.js'; -import { boostMenuItems, type Visibility } from '@/scripts/boost-quote.js'; +import { boostMenuItems, type Visibility, computeRenoteTooltip } from '@/scripts/boost-quote.js'; const canRenote = computed(() => ['public', 'home'].includes(props.note.visibility) || props.note.userId === $i.id); const hideLine = computed(() => { return props.detail ? true : false; }); @@ -149,6 +150,8 @@ const quoteButton = shallowRef<HTMLElement>(); const menuButton = shallowRef<HTMLElement>(); const likeButton = shallowRef<HTMLElement>(); +const renoteTooltip = computeRenoteTooltip(renoted); + let appearNote = computed(() => isRenote ? props.note.renote as Misskey.entities.Note : props.note); const defaultLike = computed(() => defaultStore.state.like ? defaultStore.state.like : null); const replies = ref<Misskey.entities.Note[]>([]); @@ -299,8 +302,8 @@ watch(() => props.expandAllCws, (expandAllCws) => { if (expandAllCws !== showContent.value) showContent.value = expandAllCws; }); -function boostVisibility() { - if (!defaultStore.state.showVisibilitySelectorOnBoost) { +function boostVisibility(forceMenu: boolean = false) { + if (!defaultStore.state.showVisibilitySelectorOnBoost && !forceMenu) { renote(defaultStore.state.visibilityOnBoost); } else { os.popupMenu(boostMenuItems(appearNote, renote), renoteButton.value); diff --git a/packages/frontend/src/scripts/boost-quote.ts b/packages/frontend/src/scripts/boost-quote.ts index 4e025f5d4f..feb949772b 100644 --- a/packages/frontend/src/scripts/boost-quote.ts +++ b/packages/frontend/src/scripts/boost-quote.ts @@ -3,7 +3,7 @@ * SPDX-License-Identifier: AGPL-3.0-only */ -import { ref, Ref } from 'vue'; +import { ref, Ref, computed, ComputedRef } from 'vue'; import * as Misskey from 'misskey-js'; import { i18n } from '@/i18n.js'; import { defaultStore } from '@/store.js'; @@ -79,3 +79,11 @@ export function boostMenuItems(appearNote: Ref<Misskey.entities.Note>, renote: ( } as MenuItem, ]; } + +export function computeRenoteTooltip(renoted: Ref<boolean>): ComputedRef<string> { + return computed(() => { + if (renoted.value) return i18n.ts.unrenote; + if (defaultStore.state.showVisibilitySelectorOnBoost) return i18n.ts.renote; + return i18n.ts.renoteShift; + }); +} diff --git a/sharkey-locales/en-US.yml b/sharkey-locales/en-US.yml index 202d0f71a2..6b3c099411 100644 --- a/sharkey-locales/en-US.yml +++ b/sharkey-locales/en-US.yml @@ -17,6 +17,7 @@ emailDestination: "Destination address" date: "Date" renote: "Boost" unrenote: "Remove boost" +renoteShift: "Boost (hold Shift for visibility menu)" renoted: "Boosted." quoted: "Quoted." rmboost: "Unboosted."