diff options
| author | syuilo <Syuilotan@yahoo.co.jp> | 2023-03-08 08:56:47 +0900 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2023-03-08 08:56:47 +0900 |
| commit | dd6569a1bb025f2e295c9d19d870febcde712ea1 (patch) | |
| tree | 7ac4c4b1674c7aab27db9cf4b657bb2966e1e37d /packages/frontend/src/components | |
| parent | feat: Per-user renote mute (#10249) (diff) | |
| download | sharkey-dd6569a1bb025f2e295c9d19d870febcde712ea1.tar.gz sharkey-dd6569a1bb025f2e295c9d19d870febcde712ea1.tar.bz2 sharkey-dd6569a1bb025f2e295c9d19d870febcde712ea1.zip | |
feat: Reaction acceptance (#10256)
* wip
* wip
* デフォルト設定
Diffstat (limited to 'packages/frontend/src/components')
| -rw-r--r-- | packages/frontend/src/components/MkNote.vue | 33 | ||||
| -rw-r--r-- | packages/frontend/src/components/MkNoteDetailed.vue | 33 | ||||
| -rw-r--r-- | packages/frontend/src/components/MkPostForm.vue | 27 |
3 files changed, 74 insertions, 19 deletions
diff --git a/packages/frontend/src/components/MkNote.vue b/packages/frontend/src/components/MkNote.vue index bb1269562d..af81051a54 100644 --- a/packages/frontend/src/components/MkNote.vue +++ b/packages/frontend/src/components/MkNote.vue @@ -103,7 +103,8 @@ <i class="ti ti-ban"></i> </button> <button v-if="appearNote.myReaction == null" ref="reactButton" :class="$style.footerButton" class="_button" @mousedown="react()"> - <i class="ti ti-plus"></i> + <i v-if="appearNote.reactionAcceptance === 'likeOnly'" class="ti ti-heart"></i> + <i v-else class="ti ti-plus"></i> </button> <button v-if="appearNote.myReaction != null" ref="reactButton" :class="$style.footerButton" class="_button" @click="undoReact(appearNote)"> <i class="ti ti-minus"></i> @@ -329,18 +330,32 @@ function reply(viaKeyboard = false): void { function react(viaKeyboard = false): void { pleaseLogin(); - blur(); - reactionPicker.show(reactButton.value, reaction => { + if (appearNote.reactionAcceptance === 'likeOnly') { os.api('notes/reactions/create', { noteId: appearNote.id, - reaction: reaction, + reaction: '❤️', }); - if (appearNote.text && appearNote.text.length > 100 && (Date.now() - new Date(appearNote.createdAt).getTime() < 1000 * 3)) { - claimAchievement('reactWithoutRead'); + const el = reactButton.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'); } - }, () => { - focus(); - }); + } else { + blur(); + reactionPicker.show(reactButton.value, reaction => { + os.api('notes/reactions/create', { + noteId: appearNote.id, + reaction: reaction, + }); + if (appearNote.text && appearNote.text.length > 100 && (Date.now() - new Date(appearNote.createdAt).getTime() < 1000 * 3)) { + claimAchievement('reactWithoutRead'); + } + }, () => { + focus(); + }); + } } function undoReact(note): void { diff --git a/packages/frontend/src/components/MkNoteDetailed.vue b/packages/frontend/src/components/MkNoteDetailed.vue index f5f4a2afc1..ea72e1b517 100644 --- a/packages/frontend/src/components/MkNoteDetailed.vue +++ b/packages/frontend/src/components/MkNoteDetailed.vue @@ -108,7 +108,8 @@ <i class="ti ti-ban"></i> </button> <button v-if="appearNote.myReaction == null" ref="reactButton" class="button _button" @mousedown="react()"> - <i class="ti ti-plus"></i> + <i v-if="appearNote.reactionAcceptance === 'likeOnly'" class="ti ti-heart"></i> + <i v-else class="ti ti-plus"></i> </button> <button v-if="appearNote.myReaction != null" ref="reactButton" class="button _button reacted" @click="undoReact(appearNote)"> <i class="ti ti-minus"></i> @@ -323,18 +324,32 @@ function reply(viaKeyboard = false): void { function react(viaKeyboard = false): void { pleaseLogin(); - blur(); - reactionPicker.show(reactButton.value, reaction => { + if (appearNote.reactionAcceptance === 'likeOnly') { os.api('notes/reactions/create', { noteId: appearNote.id, - reaction: reaction, + reaction: '❤️', }); - if (appearNote.text && appearNote.text.length > 100 && (Date.now() - new Date(appearNote.createdAt).getTime() < 1000 * 3)) { - claimAchievement('reactWithoutRead'); + const el = reactButton.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'); } - }, () => { - focus(); - }); + } else { + blur(); + reactionPicker.show(reactButton.value, reaction => { + os.api('notes/reactions/create', { + noteId: appearNote.id, + reaction: reaction, + }); + if (appearNote.text && appearNote.text.length > 100 && (Date.now() - new Date(appearNote.createdAt).getTime() < 1000 * 3)) { + claimAchievement('reactWithoutRead'); + } + }, () => { + focus(); + }); + } } function undoReact(note): void { diff --git a/packages/frontend/src/components/MkPostForm.vue b/packages/frontend/src/components/MkPostForm.vue index f610569f6d..ee5a9e1810 100644 --- a/packages/frontend/src/components/MkPostForm.vue +++ b/packages/frontend/src/components/MkPostForm.vue @@ -53,14 +53,23 @@ <XPostFormAttaches v-model="files" :class="$style.attaches" @detach="detachFile" @change-sensitive="updateFileSensitive" @change-name="updateFileName"/> <MkPollEditor v-if="poll" v-model="poll" @destroyed="poll = null"/> <XNotePreview v-if="showPreview" :class="$style.preview" :text="text"/> + <div v-if="showingOptions" style="padding: 0 16px;"> + <MkSelect v-model="reactionAcceptance" small> + <template #label>{{ i18n.ts.reactionAcceptance }}</template> + <option :value="null">{{ i18n.ts.all }}</option> + <option value="likeOnly">{{ i18n.ts.likeOnly }}</option> + <option value="likeOnlyForRemote">{{ i18n.ts.likeOnlyForRemote }}</option> + </MkSelect> + </div> + <button v-tooltip="i18n.ts.emoji" class="_button" :class="$style.emojiButton" @click="insertEmoji"><i class="ti ti-mood-happy"></i></button> <footer :class="$style.footer"> <button v-tooltip="i18n.ts.attachFile" class="_button" :class="$style.footerButton" @click="chooseFileFrom"><i class="ti ti-photo-plus"></i></button> <button v-tooltip="i18n.ts.poll" class="_button" :class="[$style.footerButton, { [$style.footerButtonActive]: poll }]" @click="togglePoll"><i class="ti ti-chart-arrows"></i></button> <button v-tooltip="i18n.ts.useCw" class="_button" :class="[$style.footerButton, { [$style.footerButtonActive]: useCw }]" @click="useCw = !useCw"><i class="ti ti-eye-off"></i></button> <button v-tooltip="i18n.ts.mention" class="_button" :class="$style.footerButton" @click="insertMention"><i class="ti ti-at"></i></button> <button v-tooltip="i18n.ts.hashtags" class="_button" :class="[$style.footerButton, { [$style.footerButtonActive]: withHashtags }]" @click="withHashtags = !withHashtags"><i class="ti ti-hash"></i></button> - <button v-tooltip="i18n.ts.emoji" class="_button" :class="$style.footerButton" @click="insertEmoji"><i class="ti ti-mood-happy"></i></button> <button v-if="postFormActions.length > 0" v-tooltip="i18n.ts.plugin" class="_button" :class="$style.footerButton" @click="showActions"><i class="ti ti-plug"></i></button> + <button v-tooltip="i18n.ts.more" class="_button" :class="$style.footerButton" @click="showingOptions = !showingOptions"><i class="ti ti-dots"></i></button> </footer> <datalist id="hashtags"> <option v-for="hashtag in recentHashtags" :key="hashtag" :value="hashtag"/> @@ -76,6 +85,7 @@ import * as misskey from 'misskey-js'; import insertTextAtCursor from 'insert-text-at-cursor'; import { toASCII } from 'punycode/'; import * as Acct from 'misskey-js/built/acct'; +import MkSelect from './MkSelect.vue'; import MkNoteSimple from '@/components/MkNoteSimple.vue'; import XNotePreview from '@/components/MkNotePreview.vue'; import XPostFormAttaches from '@/components/MkPostFormAttaches.vue'; @@ -151,12 +161,14 @@ let visibleUsers = $ref([]); if (props.initialVisibleUsers) { props.initialVisibleUsers.forEach(pushVisibleUser); } +let reactionAcceptance = $ref(defaultStore.state.reactionAcceptance); let autocomplete = $ref(null); let draghover = $ref(false); let quoteId = $ref(null); let hasNotSpecifiedMentions = $ref(false); let recentHashtags = $ref(JSON.parse(miLocalStorage.getItem('hashtags') ?? '[]')); let imeText = $ref(''); +let showingOptions = $ref(false); const draftKey = $computed((): string => { let key = props.channel ? `channel:${props.channel.id}` : ''; @@ -614,6 +626,7 @@ async function post(ev?: MouseEvent) { localOnly: localOnly, visibility: visibility, visibleUserIds: visibility === 'specified' ? visibleUsers.map(u => u.id) : undefined, + reactionAcceptance, }; if (withHashtags && hashtags && hashtags.trim() !== '') { @@ -1030,6 +1043,18 @@ defineExpose({ } } +.emojiButton { + position: absolute; + top: 55px; + right: 13px; + display: inline-block; + padding: 0; + margin: 0; + font-size: 1em; + width: 32px; + height: 32px; +} + @container (max-width: 500px) { .header { height: 50px; |