From ae2d71553e92b324f59c15d2b151b2583a6e65ab Mon Sep 17 00:00:00 2001
From: syuilo <Syuilotan@yahoo.co.jp>
Date: Mon, 27 Dec 2021 22:59:14 +0900
Subject: [PATCH] enhance(client): :art:

---
 .../client/src/components/emoji-picker.vue    |  8 +--
 .../client/src/components/form/switch.vue     | 42 ++++++++++-----
 .../components/reactions-viewer.reaction.vue  |  2 +-
 .../components/{particle.vue => ripple.vue}   | 53 +++++++++++--------
 packages/client/src/directives/index.ts       |  4 +-
 .../src/directives/{particle.ts => ripple.ts} |  8 +--
 6 files changed, 71 insertions(+), 46 deletions(-)
 rename packages/client/src/components/{particle.vue => ripple.vue} (65%)
 rename packages/client/src/directives/{particle.ts => ripple.ts} (59%)

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');
 		});
 	}
 };