diff --git a/packages/client/src/components/emoji-picker.vue b/packages/client/src/components/emoji-picker.vue index ff450246f9..a8eed1ca21 100644 --- a/packages/client/src/components/emoji-picker.vue +++ b/packages/client/src/components/emoji-picker.vue @@ -77,7 +77,7 @@ import { defineComponent, markRaw } from 'vue'; import { emojilist } from '@/scripts/emojilist'; import { getStaticImageUrl } from '@/scripts/get-static-image-url'; -import Particle from '@/components/particle.vue'; +import Ripple from '@/components/ripple.vue'; import * as os from '@/os'; import { isTouchUsing } from '@/scripts/touch'; import { isMobile } from '@/scripts/is-mobile'; @@ -296,9 +296,9 @@ export default defineComponent({ if (ev) { const el = ev.currentTarget || ev.target; const rect = el.getBoundingClientRect(); - const x = rect.left + (el.clientWidth / 2); - const y = rect.top + (el.clientHeight / 2); - os.popup(Particle, { x, y }, {}, 'end'); + const x = rect.left + (el.offsetWidth / 2); + const y = rect.top + (el.offsetHeight / 2); + os.popup(Ripple, { x, y }, {}, 'end'); } const key = this.getKey(emoji); diff --git a/packages/client/src/components/form/switch.vue b/packages/client/src/components/form/switch.vue index aa28292b97..aa9b09215e 100644 --- a/packages/client/src/components/form/switch.vue +++ b/packages/client/src/components/form/switch.vue @@ -9,7 +9,7 @@ :disabled="disabled" @keydown.enter="toggle" > - <span v-adaptive-border v-tooltip="checked ? $ts.itsOn : $ts.itsOff" class="button" @click.prevent="toggle"> + <span ref="button" v-adaptive-border v-tooltip="checked ? $ts.itsOn : $ts.itsOff" class="button" @click.prevent="toggle"> <i class="check fas fa-check"></i> </span> <span class="label"> @@ -20,7 +20,9 @@ </template> <script lang="ts"> -import { defineComponent } from 'vue'; +import { defineComponent, ref, toRefs } from 'vue'; +import * as os from '@/os'; +import Ripple from '@/components/ripple.vue'; export default defineComponent({ props: { @@ -33,17 +35,28 @@ export default defineComponent({ default: false } }, - computed: { - checked(): boolean { - return this.modelValue; - } + + setup(props, context) { + const button = ref<HTMLElement>(); + const checked = toRefs(props).modelValue; + const toggle = () => { + if (props.disabled) return; + context.emit('update:modelValue', !checked.value); + + if (!checked.value) { + const rect = button.value.getBoundingClientRect(); + const x = rect.left + (button.value.offsetWidth / 2); + const y = rect.top + (button.value.offsetHeight / 2); + os.popup(Ripple, { x, y, particle: false }, {}, 'end'); + } + }; + + return { + button, + checked, + toggle, + }; }, - methods: { - toggle() { - if (this.disabled) return; - this.$emit('update:modelValue', !this.checked); - } - } }); </script> @@ -51,7 +64,7 @@ export default defineComponent({ .ziffeoms { position: relative; display: flex; - transition: all 0.2s; + transition: all 0.2s ease; > * { user-select: none; @@ -85,6 +98,8 @@ export default defineComponent({ opacity: 0; color: var(--fgOnAccent); font-size: 13px; + transform: scale(0.5); + transition: all 0.2s ease; } } @@ -131,6 +146,7 @@ export default defineComponent({ > .check { opacity: 1; + transform: scale(1); } } } diff --git a/packages/client/src/components/reactions-viewer.reaction.vue b/packages/client/src/components/reactions-viewer.reaction.vue index a1de99f018..bbf518549c 100644 --- a/packages/client/src/components/reactions-viewer.reaction.vue +++ b/packages/client/src/components/reactions-viewer.reaction.vue @@ -2,7 +2,7 @@ <button v-if="count > 0" ref="buttonRef" - v-particle="canToggle" + v-ripple="canToggle" class="hkzvhatu _button" :class="{ reacted: note.myReaction == reaction, canToggle }" @click="toggleReaction()" diff --git a/packages/client/src/components/particle.vue b/packages/client/src/components/ripple.vue similarity index 65% rename from packages/client/src/components/particle.vue rename to packages/client/src/components/ripple.vue index d82705c1e8..272eacbc6e 100644 --- a/packages/client/src/components/particle.vue +++ b/packages/client/src/components/ripple.vue @@ -1,5 +1,5 @@ <template> -<div class="vswabwbm" :style="{ top: `${y - 64}px`, left: `${x - 64}px` }" :class="{ active }"> +<div class="vswabwbm" :style="{ zIndex, top: `${y - 64}px`, left: `${x - 64}px` }" :class="{ active }"> <svg width="128" height="128" viewBox="0 0 128 128" xmlns="http://www.w3.org/2000/svg"> <circle fill="none" cx="64" cy="64"> <animate attributeName="r" @@ -52,7 +52,8 @@ </template> <script lang="ts"> -import { defineComponent } from 'vue'; +import { defineComponent, onMounted } from 'vue'; +import * as os from '@/os'; export default defineComponent({ props: { @@ -63,37 +64,46 @@ export default defineComponent({ y: { type: Number, required: true + }, + particle: { + type: Boolean, + required: false, + default: true, } }, emits: ['end'], - data() { + setup(props, context) { const particles = []; const origin = 64; const colors = ['#FF1493', '#00FFFF', '#FFE202']; - for (let i = 0; i < 12; i++) { - const angle = Math.random() * (Math.PI * 2); - const pos = Math.random() * 16; - const velocity = 16 + (Math.random() * 48); - particles.push({ - size: 4 + (Math.random() * 8), - xA: origin + (Math.sin(angle) * pos), - yA: origin + (Math.cos(angle) * pos), - xB: origin + (Math.sin(angle) * (pos + velocity)), - yB: origin + (Math.cos(angle) * (pos + velocity)), - color: colors[Math.floor(Math.random() * colors.length)] - }); + if (props.particle) { + for (let i = 0; i < 12; i++) { + const angle = Math.random() * (Math.PI * 2); + const pos = Math.random() * 16; + const velocity = 16 + (Math.random() * 48); + particles.push({ + size: 4 + (Math.random() * 8), + xA: origin + (Math.sin(angle) * pos), + yA: origin + (Math.cos(angle) * pos), + xB: origin + (Math.sin(angle) * (pos + velocity)), + yB: origin + (Math.cos(angle) * (pos + velocity)), + color: colors[Math.floor(Math.random() * colors.length)] + }); + } } + onMounted(() => { + setTimeout(() => { + context.emit('end'); + }, 1100); + }); + return { - particles + particles, + zIndex: os.claimZIndex('high'), }; }, - mounted() { - setTimeout(() => { - this.$emit('end'); - }, 1100); - } }); </script> @@ -101,7 +111,6 @@ export default defineComponent({ .vswabwbm { pointer-events: none; position: fixed; - z-index: 1000000; width: 128px; height: 128px; diff --git a/packages/client/src/directives/index.ts b/packages/client/src/directives/index.ts index 8f13e792f3..fc9b6f86da 100644 --- a/packages/client/src/directives/index.ts +++ b/packages/client/src/directives/index.ts @@ -3,7 +3,7 @@ import { App } from 'vue'; import userPreview from './user-preview'; import size from './size'; import getSize from './get-size'; -import particle from './particle'; +import ripple from './ripple'; import tooltip from './tooltip'; import hotkey from './hotkey'; import appear from './appear'; @@ -18,7 +18,7 @@ export default function(app: App) { app.directive('user-preview', userPreview); app.directive('size', size); app.directive('get-size', getSize); - app.directive('particle', particle); + app.directive('ripple', ripple); app.directive('tooltip', tooltip); app.directive('hotkey', hotkey); app.directive('appear', appear); diff --git a/packages/client/src/directives/particle.ts b/packages/client/src/directives/ripple.ts similarity index 59% rename from packages/client/src/directives/particle.ts rename to packages/client/src/directives/ripple.ts index c90df89a5e..f1d41ddb0e 100644 --- a/packages/client/src/directives/particle.ts +++ b/packages/client/src/directives/ripple.ts @@ -1,4 +1,4 @@ -import Particle from '@/components/particle.vue'; +import Ripple from '@/components/ripple.vue'; import { popup } from '@/os'; export default { @@ -9,10 +9,10 @@ export default { el.addEventListener('click', () => { const rect = el.getBoundingClientRect(); - const x = rect.left + (el.clientWidth / 2); - const y = rect.top + (el.clientHeight / 2); + const x = rect.left + (el.offsetWidth / 2); + const y = rect.top + (el.offsetHeight / 2); - popup(Particle, { x, y }, {}, 'end'); + popup(Ripple, { x, y }, {}, 'end'); }); } };