diff --git a/packages/frontend/src/components/MkEmojiPicker.vue b/packages/frontend/src/components/MkEmojiPicker.vue index c94da97747..fe098c9de6 100644 --- a/packages/frontend/src/components/MkEmojiPicker.vue +++ b/packages/frontend/src/components/MkEmojiPicker.vue @@ -12,7 +12,7 @@ tabindex="0" @click="chosen(emoji, $event)" > - <MkEmoji class="emoji" :emoji="`:${emoji.name}:`" /> + <MkEmoji class="emoji" :emoji="`:${emoji.name}:`"/> </button> </div> <div v-if="searchResultUnicode.length > 0" class="body"> @@ -81,7 +81,7 @@ import { ref, computed, watch, onMounted } from 'vue'; import * as Misskey from 'misskey-js'; import XSection from '@/components/MkEmojiPicker.section.vue'; import { emojilist, UnicodeEmojiDef, unicodeEmojiCategories as categories } from '@/scripts/emojilist'; -import Ripple from '@/components/MkRipple.vue'; +import MkRippleEffect from '@/components/MkRippleEffect.vue'; import * as os from '@/os'; import { isTouchUsing } from '@/scripts/touch'; import { deviceKind } from '@/scripts/device-kind'; @@ -288,7 +288,7 @@ function chosen(emoji: any, ev?: MouseEvent) { const rect = el.getBoundingClientRect(); const x = rect.left + (el.offsetWidth / 2); const y = rect.top + (el.offsetHeight / 2); - os.popup(Ripple, { x, y }, {}, 'end'); + os.popup(MkRippleEffect, { x, y }, {}, 'end'); } const key = getKey(emoji); diff --git a/packages/frontend/src/components/MkPlusOneEffect.vue b/packages/frontend/src/components/MkPlusOneEffect.vue new file mode 100644 index 0000000000..a0bb22db92 --- /dev/null +++ b/packages/frontend/src/components/MkPlusOneEffect.vue @@ -0,0 +1,66 @@ +<template> +<div :class="$style.root" :style="{ zIndex, top: `${y - 64}px`, left: `${x - 64}px` }"> + <span class="text" :class="{ up }">+1</span> +</div> +</template> + +<script lang="ts" setup> +import { onMounted } from 'vue'; +import * as os from '@/os'; + +const props = withDefaults(defineProps<{ + x: number; + y: number; +}>(), { +}); + +const emit = defineEmits<{ + (ev: 'end'): void; +}>(); + +let up = $ref(false); +const zIndex = os.claimZIndex('high'); + +onMounted(() => { + window.setTimeout(() => { + up = true; + }, 10); + + window.setTimeout(() => { + emit('end'); + }, 1100); +}); +</script> + +<style lang="scss" module> +.root { + pointer-events: none; + position: fixed; + width: 128px; + height: 128px; + + &:global { + > .text { + display: block; + height: 1em; + text-align: center; + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + margin: auto; + color: var(--accent); + font-size: 18px; + font-weight: bold; + transform: translateY(-30px); + transition: transform 1s cubic-bezier(0,.5,0,1), opacity 1s cubic-bezier(.5,0,1,.5); + + &.up { + opacity: 0; + transform: translateY(-50px); + } + } + } +} +</style> diff --git a/packages/frontend/src/components/MkPostForm.vue b/packages/frontend/src/components/MkPostForm.vue index b8784620c0..5088de7353 100644 --- a/packages/frontend/src/components/MkPostForm.vue +++ b/packages/frontend/src/components/MkPostForm.vue @@ -97,7 +97,7 @@ import { instance } from '@/instance'; import { $i, getAccounts, openAccountMenu as openAccountMenu_ } from '@/account'; import { uploadFile } from '@/scripts/upload'; import { deepClone } from '@/scripts/clone'; -import Ripple from '@/components/MkRipple.vue'; +import MkRippleEffect from '@/components/MkRippleEffect.vue'; const modal = inject('modal'); @@ -575,7 +575,7 @@ async function post(ev?: MouseEvent) { const rect = el.getBoundingClientRect(); const x = rect.left + (el.offsetWidth / 2); const y = rect.top + (el.offsetHeight / 2); - os.popup(Ripple, { x, y }, {}, 'end'); + os.popup(MkRippleEffect, { x, y }, {}, 'end'); } let postData = { diff --git a/packages/frontend/src/components/MkReactionsViewer.reaction.vue b/packages/frontend/src/components/MkReactionsViewer.reaction.vue index f3c77231db..b10c7009f5 100644 --- a/packages/frontend/src/components/MkReactionsViewer.reaction.vue +++ b/packages/frontend/src/components/MkReactionsViewer.reaction.vue @@ -19,6 +19,7 @@ import XReactionIcon from '@/components/MkReactionIcon.vue'; import * as os from '@/os'; import { useTooltip } from '@/scripts/use-tooltip'; import { $i } from '@/account'; +import MkPlusOneEffect from '@/components/MkPlusOneEffect.vue'; const props = defineProps<{ reaction: string; @@ -57,7 +58,10 @@ const toggleReaction = () => { const anime = () => { if (document.hidden) return; - // TODO: 新しくリアクションが付いたことが視覚的に分かりやすいアニメーション + const rect = buttonRef.value.getBoundingClientRect(); + const x = rect.left + (buttonRef.value.offsetWidth / 2); + const y = rect.top + (buttonRef.value.offsetHeight / 2); + os.popup(MkPlusOneEffect, { x, y }, {}, 'end'); }; watch(() => props.count, (newCount, oldCount) => { diff --git a/packages/frontend/src/components/MkRipple.vue b/packages/frontend/src/components/MkRippleEffect.vue similarity index 100% rename from packages/frontend/src/components/MkRipple.vue rename to packages/frontend/src/components/MkRippleEffect.vue diff --git a/packages/frontend/src/components/form/checkbox.vue b/packages/frontend/src/components/form/checkbox.vue index ba3b2dc146..d869b600c9 100644 --- a/packages/frontend/src/components/form/checkbox.vue +++ b/packages/frontend/src/components/form/checkbox.vue @@ -23,7 +23,7 @@ <script lang="ts" setup> import { toRefs, Ref } from 'vue'; import * as os from '@/os'; -import Ripple from '@/components/MkRipple.vue'; +import MkRippleEffect from '@/components/MkRippleEffect.vue'; import { i18n } from '@/i18n'; const props = defineProps<{ @@ -45,7 +45,7 @@ const toggle = () => { const rect = button.getBoundingClientRect(); const x = rect.left + (button.offsetWidth / 2); const y = rect.top + (button.offsetHeight / 2); - os.popup(Ripple, { x, y, particle: false }, {}, 'end'); + os.popup(MkRippleEffect, { x, y, particle: false }, {}, 'end'); } }; </script> diff --git a/packages/frontend/src/directives/ripple.ts b/packages/frontend/src/directives/ripple.ts index d32f7ab441..5611777347 100644 --- a/packages/frontend/src/directives/ripple.ts +++ b/packages/frontend/src/directives/ripple.ts @@ -1,4 +1,4 @@ -import Ripple from '@/components/MkRipple.vue'; +import MkRippleEffect from '@/components/MkRippleEffect.vue'; import { popup } from '@/os'; export default { @@ -12,7 +12,7 @@ export default { const x = rect.left + (el.offsetWidth / 2); const y = rect.top + (el.offsetHeight / 2); - popup(Ripple, { x, y }, {}, 'end'); + popup(MkRippleEffect, { x, y }, {}, 'end'); }); }, };