feat: リノートと引用ボタンの表示方法を選択できる
This commit is contained in:
parent
887a6d59aa
commit
7e20164a5e
|
@ -52,6 +52,7 @@
|
|||
- Feat: Scratchpad에서 Async: 계열 함수나 버튼 콜백 등의 오류에도 대화창을 띄우도록(시험적이라 Play 등에는 미구현) (misskey-dev/misskey#11850)
|
||||
- Feat: 민감한 미디어를 돋보이게 하는 설정 추가 (misskey-dev/misskey#11851)
|
||||
- Feat: 알림에서 답글이 달린 노트의 상위 노트를 표시하지 않도록 하는 설정 추가
|
||||
- Feat: 리노트와 인용 버튼을 표시하는 방법을 선택할 수 있음
|
||||
- Spec: 사용자 정의 이모티콘 라이센스를 여러 항목으로 추가할 수 있도록 (MisskeyIO/misskey#130)
|
||||
- Enhance: 새로운 신고가 있는 경우, 네비게이션 바의 제어판 아이콘과 제어판 페이지의 신고 섹션에 점을 표시
|
||||
- Enhance: 스크롤 시 요소 표시 기능을 Friendly 이외의 UI에도 대응
|
||||
|
|
|
@ -1223,6 +1223,7 @@ _cherrypick:
|
|||
renameTheButtonInPostFormToNya: "Change the \"Note\" button on the note-posting form to \"Nyan!\""
|
||||
renameTheButtonInPostFormToNyaDescription: "Outside of the note-posting form, they are still as \"Note\"."
|
||||
showReplyInNotification: "Show parent note of notes with replies in notifications"
|
||||
renoteQuoteButtonSeparation: "Separate Renote and Quote buttons"
|
||||
_displayHeaderNavBarWhenScroll:
|
||||
all: "Display all"
|
||||
hideHeaderOnly: "Hide header only"
|
||||
|
|
1
locales/index.d.ts
vendored
1
locales/index.d.ts
vendored
|
@ -1234,6 +1234,7 @@ export interface Locale {
|
|||
"renameTheButtonInPostFormToNya": string;
|
||||
"renameTheButtonInPostFormToNyaDescription": string;
|
||||
"showReplyInNotification": string;
|
||||
"renoteQuoteButtonSeparation": string;
|
||||
};
|
||||
"_displayHeaderNavBarWhenScroll": {
|
||||
"all": string;
|
||||
|
|
|
@ -1232,6 +1232,7 @@ _cherrypick:
|
|||
renameTheButtonInPostFormToNya: "ノート作成画面の「ノート」ボタンを「にゃ!」に変更する"
|
||||
renameTheButtonInPostFormToNyaDescription: "にゃあにゃんにゃんにゃんにゃにゃん?"
|
||||
showReplyInNotification: "通知で返信があるノートの親ノートを表示する"
|
||||
renoteQuoteButtonSeparation: "リノートと引用ボタンを分けて表示する"
|
||||
|
||||
_displayHeaderNavBarWhenScroll:
|
||||
all: "全て表示"
|
||||
|
|
|
@ -1219,6 +1219,7 @@ _cherrypick:
|
|||
renameTheButtonInPostFormToNya: "노트 작성 화면의 \"노트\" 버튼을 \"냥!\"으로 변경"
|
||||
renameTheButtonInPostFormToNyaDescription: "냐앙냥냥냥냐냥?"
|
||||
showReplyInNotification: "알림에서 답글이 달린 노트의 상위 노트 표시하기"
|
||||
renoteQuoteButtonSeparation: "리노트와 인용 버튼을 분리해서 표시하기"
|
||||
_displayHeaderNavBarWhenScroll:
|
||||
all: "모두 표시"
|
||||
hideHeaderOnly: "헤더만 숨기기"
|
||||
|
|
|
@ -51,7 +51,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<MkNoteSub v-if="appearNote.reply && !renoteCollapsed && notification && defaultStore.state.showReplyInNotification" :note="appearNote.reply" :class="$style.replyTo"/>
|
||||
<MkNoteSub v-if="appearNote.reply && !renoteCollapsed && notification && defaultStore.state.showReplyInNotification" :note="appearNote.reply" :class="$style.replyTo"/>
|
||||
<MkNoteSub v-else-if="appearNote.reply && !renoteCollapsed && !notification" :note="appearNote.reply" :class="$style.replyTo"/>
|
||||
<div v-if="renoteCollapsed" :class="$style.collapsedRenoteTarget">
|
||||
<MkAvatar v-if="!defaultStore.state.hideAvatarsInNote" :class="$style.collapsedRenoteTargetAvatar" :user="appearNote.user" link preview/>
|
||||
|
@ -125,7 +125,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
v-tooltip="i18n.ts.renote"
|
||||
:class="$style.footerButton"
|
||||
class="_button"
|
||||
@mousedown="renote()"
|
||||
@mousedown="defaultStore.state.renoteQuoteButtonSeparation ? renoteOnly() : renote()"
|
||||
>
|
||||
<i class="ti ti-repeat"></i>
|
||||
<p v-if="appearNote.renoteCount > 0" :class="$style.footerButtonCount">{{ appearNote.renoteCount }}</p>
|
||||
|
@ -143,7 +143,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
<button v-if="appearNote.myReaction != null && appearNote.reactionAcceptance == 'likeOnly'" ref="reactButton" :class="$style.footerButton" class="_button" @click="undoReact(appearNote)">
|
||||
<i class="ti ti-heart-minus"></i>
|
||||
</button>
|
||||
<button v-if="canRenote" v-tooltip="i18n.ts.quote" class="_button" :class="$style.footerButton" @mousedown="quote()"><i class="ti ti-quote"></i></button>
|
||||
<button v-if="canRenote && defaultStore.state.renoteQuoteButtonSeparation" v-tooltip="i18n.ts.quote" class="_button" :class="$style.footerButton" @mousedown="quote()"><i class="ti ti-quote"></i></button>
|
||||
<button v-if="defaultStore.state.showClipButtonInNoteFooter" ref="clipButton" v-tooltip="i18n.ts.clip" :class="$style.footerButton" class="_button" @mousedown="clip()">
|
||||
<i class="ti ti-paperclip"></i>
|
||||
</button>
|
||||
|
@ -216,7 +216,7 @@ const props = withDefaults(defineProps<{
|
|||
pinned?: boolean;
|
||||
notification?: boolean;
|
||||
}>(), {
|
||||
notification: false,
|
||||
notification: false,
|
||||
});
|
||||
|
||||
const inChannel = inject('inChannel', null);
|
||||
|
@ -275,7 +275,7 @@ const keymap = {
|
|||
};
|
||||
|
||||
onMounted(() => {
|
||||
globalEvents.on('showEl', (showEl_receive) => {
|
||||
globalEvents.on('showEl', (showEl_receive) => {
|
||||
showEl = showEl_receive;
|
||||
});
|
||||
});
|
||||
|
@ -315,7 +315,89 @@ function smallerVisibility(a: Visibility | string, b: Visibility | string): Visi
|
|||
return 'public';
|
||||
}
|
||||
|
||||
async function renote() {
|
||||
function renote(viaKeyboard = false) {
|
||||
pleaseLogin();
|
||||
showMovedDialog();
|
||||
|
||||
let items = [] as MenuItem[];
|
||||
|
||||
if (appearNote.channel) {
|
||||
items = items.concat([{
|
||||
text: i18n.ts.inChannelRenote,
|
||||
icon: 'ti ti-repeat',
|
||||
action: () => {
|
||||
const el = renoteButton.value 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(MkRippleEffect, { x, y }, {}, 'end');
|
||||
}
|
||||
|
||||
os.api('notes/create', {
|
||||
renoteId: appearNote.id,
|
||||
channelId: appearNote.channelId,
|
||||
}).then(() => {
|
||||
os.noteToast(i18n.ts.renoted);
|
||||
});
|
||||
},
|
||||
}, {
|
||||
text: i18n.ts.inChannelQuote,
|
||||
icon: 'ti ti-quote',
|
||||
action: () => {
|
||||
os.post({
|
||||
renote: appearNote,
|
||||
channel: appearNote.channel,
|
||||
});
|
||||
},
|
||||
}, null]);
|
||||
}
|
||||
|
||||
items = items.concat([{
|
||||
text: i18n.ts.renote,
|
||||
icon: 'ti ti-repeat',
|
||||
action: () => {
|
||||
const el = renoteButton.value 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(MkRippleEffect, { x, y }, {}, 'end');
|
||||
}
|
||||
|
||||
const configuredVisibility = defaultStore.state.rememberNoteVisibility ? defaultStore.state.visibility : defaultStore.state.defaultNoteVisibility;
|
||||
const localOnly = defaultStore.state.rememberNoteVisibility ? defaultStore.state.localOnly : defaultStore.state.defaultNoteLocalOnly;
|
||||
|
||||
let visibility = appearNote.visibility;
|
||||
visibility = smallerVisibility(visibility, configuredVisibility);
|
||||
if (appearNote.channel?.isSensitive) {
|
||||
visibility = smallerVisibility(visibility, 'home');
|
||||
}
|
||||
|
||||
os.api('notes/create', {
|
||||
localOnly,
|
||||
visibility,
|
||||
renoteId: appearNote.id,
|
||||
}).then(() => {
|
||||
os.noteToast(i18n.ts.renoted);
|
||||
});
|
||||
},
|
||||
}, {
|
||||
text: i18n.ts.quote,
|
||||
icon: 'ti ti-quote',
|
||||
action: () => {
|
||||
os.post({
|
||||
renote: appearNote,
|
||||
});
|
||||
},
|
||||
}]);
|
||||
|
||||
os.popupMenu(items, renoteButton.value, {
|
||||
viaKeyboard,
|
||||
});
|
||||
}
|
||||
|
||||
async function renoteOnly() {
|
||||
pleaseLogin();
|
||||
showMovedDialog();
|
||||
|
||||
|
|
|
@ -139,7 +139,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
v-tooltip="i18n.ts.renote"
|
||||
class="_button"
|
||||
:class="$style.noteFooterButton"
|
||||
@mousedown="renote()"
|
||||
@mousedown="defaultStore.state.renoteQuoteButtonSeparation ? renoteOnly() : renote()"
|
||||
>
|
||||
<i class="ti ti-repeat"></i>
|
||||
<p v-if="appearNote.renoteCount > 0" :class="$style.noteFooterButtonCount">{{ appearNote.renoteCount }}</p>
|
||||
|
@ -157,7 +157,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
<button v-if="appearNote.myReaction != null && appearNote.reactionAcceptance == 'likeOnly'" ref="reactButton" :class="[$style.noteFooterButton, $style.reacted]" class="_button" @click="undoReact(appearNote)">
|
||||
<i class="ti ti-heart-minus"></i>
|
||||
</button>
|
||||
<button v-if="canRenote" v-tooltip="i18n.ts.quote" class="_button" :class="$style.noteFooterButton" @mousedown="quote()"><i class="ti ti-quote"></i></button>
|
||||
<button v-if="canRenote && defaultStore.state.renoteQuoteButtonSeparation" v-tooltip="i18n.ts.quote" class="_button" :class="$style.noteFooterButton" @mousedown="quote()"><i class="ti ti-quote"></i></button>
|
||||
<button v-if="defaultStore.state.showClipButtonInNoteFooter" ref="clipButton" v-tooltip="i18n.ts.clip" class="_button" :class="$style.noteFooterButton" @mousedown="clip()">
|
||||
<i class="ti ti-paperclip"></i>
|
||||
</button>
|
||||
|
@ -353,7 +353,78 @@ useTooltip(renoteButton, async (showing) => {
|
|||
}, {}, 'closed');
|
||||
});
|
||||
|
||||
async function renote() {
|
||||
function renote(viaKeyboard = false) {
|
||||
pleaseLogin();
|
||||
showMovedDialog();
|
||||
|
||||
let items = [] as MenuItem[];
|
||||
|
||||
if (appearNote.channel) {
|
||||
items = items.concat([{
|
||||
text: i18n.ts.inChannelRenote,
|
||||
icon: 'ti ti-repeat',
|
||||
action: () => {
|
||||
const el = renoteButton.value 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(MkRippleEffect, { x, y }, {}, 'end');
|
||||
}
|
||||
|
||||
os.api('notes/create', {
|
||||
renoteId: appearNote.id,
|
||||
channelId: appearNote.channelId,
|
||||
}).then(() => {
|
||||
os.noteToast(i18n.ts.renoted);
|
||||
});
|
||||
},
|
||||
}, {
|
||||
text: i18n.ts.inChannelQuote,
|
||||
icon: 'ti ti-quote',
|
||||
action: () => {
|
||||
os.post({
|
||||
renote: appearNote,
|
||||
channel: appearNote.channel,
|
||||
});
|
||||
},
|
||||
}, null]);
|
||||
}
|
||||
|
||||
items = items.concat([{
|
||||
text: i18n.ts.renote,
|
||||
icon: 'ti ti-repeat',
|
||||
action: () => {
|
||||
const el = renoteButton.value 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(MkRippleEffect, { x, y }, {}, 'end');
|
||||
}
|
||||
|
||||
os.api('notes/create', {
|
||||
renoteId: appearNote.id,
|
||||
}).then(() => {
|
||||
os.noteToast(i18n.ts.renoted);
|
||||
});
|
||||
},
|
||||
}, {
|
||||
text: i18n.ts.quote,
|
||||
icon: 'ti ti-quote',
|
||||
action: () => {
|
||||
os.post({
|
||||
renote: appearNote,
|
||||
});
|
||||
},
|
||||
}]);
|
||||
|
||||
os.popupMenu(items, renoteButton.value, {
|
||||
viaKeyboard,
|
||||
});
|
||||
}
|
||||
|
||||
async function renoteOnly() {
|
||||
pleaseLogin();
|
||||
showMovedDialog();
|
||||
|
||||
|
|
|
@ -62,7 +62,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
v-tooltip="i18n.ts.renote"
|
||||
:class="$style.footerButton"
|
||||
class="_button"
|
||||
@mousedown="renote()"
|
||||
@mousedown="defaultStore.state.renoteQuoteButtonSeparation ? renoteOnly() : renote()"
|
||||
>
|
||||
<i class="ti ti-repeat"></i>
|
||||
<p v-if="note.renoteCount > 0" :class="$style.footerButtonCount">{{ note.renoteCount }}</p>
|
||||
|
@ -80,7 +80,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
<i v-if="note.reactionAcceptance !== 'likeOnly'" class="ti ti-mood-minus"></i>
|
||||
<i v-else class="ti ti-heart-minus"></i>
|
||||
</button>
|
||||
<button v-if="canRenote" v-tooltip="i18n.ts.quote" class="_button" :class="$style.footerButton" @mousedown="quote()"><i class="ti ti-quote"></i></button>
|
||||
<button v-if="canRenote && defaultStore.state.renoteQuoteButtonSeparation" v-tooltip="i18n.ts.quote" class="_button" :class="$style.footerButton" @mousedown="quote()"><i class="ti ti-quote"></i></button>
|
||||
<button v-if="defaultStore.state.showClipButtonInNoteFooter" ref="clipButton" v-tooltip="i18n.ts.clip" :class="$style.footerButton" class="_button" @mousedown="clip()">
|
||||
<i class="ti ti-paperclip"></i>
|
||||
</button>
|
||||
|
@ -120,6 +120,7 @@ import { deepClone } from '@/scripts/clone.js';
|
|||
import { reactionPicker } from '@/scripts/reaction-picker.js';
|
||||
import { claimAchievement } from '@/scripts/achievements.js';
|
||||
import { useNoteCapture } from '@/scripts/use-note-capture.js';
|
||||
import { MenuItem } from '@/types/menu.js';
|
||||
|
||||
const el = shallowRef<HTMLElement>();
|
||||
const menuButton = shallowRef<HTMLElement>();
|
||||
|
@ -192,7 +193,78 @@ useTooltip(renoteButton, async (showing) => {
|
|||
}, {}, 'closed');
|
||||
});
|
||||
|
||||
async function renote() {
|
||||
function renote(viaKeyboard = false) {
|
||||
pleaseLogin();
|
||||
showMovedDialog();
|
||||
|
||||
let items = [] as MenuItem[];
|
||||
|
||||
if (props.note.channel) {
|
||||
items = items.concat([{
|
||||
text: i18n.ts.inChannelRenote,
|
||||
icon: 'ti ti-repeat',
|
||||
action: () => {
|
||||
const el = renoteButton.value 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(MkRippleEffect, { x, y }, {}, 'end');
|
||||
}
|
||||
|
||||
os.api('notes/create', {
|
||||
renoteId: props.note.id,
|
||||
channelId: props.note.channelId,
|
||||
}).then(() => {
|
||||
os.noteToast(i18n.ts.renoted);
|
||||
});
|
||||
},
|
||||
}, {
|
||||
text: i18n.ts.inChannelQuote,
|
||||
icon: 'ti ti-quote',
|
||||
action: () => {
|
||||
os.post({
|
||||
renote: props.note,
|
||||
channel: props.note.channel,
|
||||
});
|
||||
},
|
||||
}, null]);
|
||||
}
|
||||
|
||||
items = items.concat([{
|
||||
text: i18n.ts.renote,
|
||||
icon: 'ti ti-repeat',
|
||||
action: () => {
|
||||
const el = renoteButton.value 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(MkRippleEffect, { x, y }, {}, 'end');
|
||||
}
|
||||
|
||||
os.api('notes/create', {
|
||||
renoteId: props.note.id,
|
||||
}).then(() => {
|
||||
os.noteToast(i18n.ts.renoted);
|
||||
});
|
||||
},
|
||||
}, {
|
||||
text: i18n.ts.quote,
|
||||
icon: 'ti ti-quote',
|
||||
action: () => {
|
||||
os.post({
|
||||
renote: props.note,
|
||||
});
|
||||
},
|
||||
}]);
|
||||
|
||||
os.popupMenu(items, renoteButton.value, {
|
||||
viaKeyboard,
|
||||
});
|
||||
}
|
||||
|
||||
async function renoteOnly() {
|
||||
pleaseLogin();
|
||||
showMovedDialog();
|
||||
|
||||
|
@ -200,7 +272,7 @@ async function renote() {
|
|||
const { canceled } = await os.confirm({
|
||||
type: 'info',
|
||||
text: i18n.ts.renoteConfirm,
|
||||
caption: i18n.ts.renoteConfirmDescription,
|
||||
caption: i18n.ts.renoteConfirmDescription,
|
||||
});
|
||||
if (canceled) return;
|
||||
}
|
||||
|
|
|
@ -59,6 +59,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
<template #caption>{{ i18n.ts._cherrypick.renameTheButtonInPostFormToNyaDescription }}</template>
|
||||
</MkSwitch>
|
||||
<MkSwitch v-model="showReplyInNotification">{{ i18n.ts._cherrypick.showReplyInNotification }}</MkSwitch>
|
||||
<MkSwitch v-model="renoteQuoteButtonSeparation">{{ i18n.ts._cherrypick.renoteQuoteButtonSeparation }}</MkSwitch>
|
||||
</div>
|
||||
</FormSection>
|
||||
</div>
|
||||
|
@ -96,12 +97,14 @@ const mobileTimelineHeaderChange = computed(defaultStore.makeGetterSetter('mobil
|
|||
const displayHeaderNavBarWhenScroll = computed(defaultStore.makeGetterSetter('displayHeaderNavBarWhenScroll'));
|
||||
const renameTheButtonInPostFormToNya = computed(defaultStore.makeGetterSetter('renameTheButtonInPostFormToNya'));
|
||||
const showReplyInNotification = computed(defaultStore.makeGetterSetter('showReplyInNotification'));
|
||||
const renoteQuoteButtonSeparation = computed(defaultStore.makeGetterSetter('renoteQuoteButtonSeparation'));
|
||||
|
||||
watch([
|
||||
infoButtonForNoteActionsEnabled,
|
||||
reactableRemoteReactionEnabled,
|
||||
renameTheButtonInPostFormToNya,
|
||||
showReplyInNotification,
|
||||
renoteQuoteButtonSeparation,
|
||||
], async () => {
|
||||
await reloadAsk();
|
||||
});
|
||||
|
|
|
@ -121,6 +121,7 @@ const defaultStoreSaveKeys: (keyof typeof defaultStore['state'])[] = [
|
|||
'mobileTimelineHeaderChange',
|
||||
'renameTheButtonInPostFormToNya',
|
||||
'showReplyInNotification',
|
||||
'renoteQuoteButtonSeparation',
|
||||
];
|
||||
const coldDeviceStorageSaveKeys: (keyof typeof ColdDeviceStorage.default)[] = [
|
||||
'lightTheme',
|
||||
|
|
|
@ -521,6 +521,10 @@ export const defaultStore = markRaw(new Storage('base', {
|
|||
where: 'device',
|
||||
default: false,
|
||||
},
|
||||
renoteQuoteButtonSeparation: {
|
||||
where: 'device',
|
||||
default: true,
|
||||
},
|
||||
|
||||
// - etc
|
||||
friendlyEnableNotifications: {
|
||||
|
|
Loading…
Reference in a new issue