From 8a3f860213a0221383e68ed545712f30757516b6 Mon Sep 17 00:00:00 2001
From: syuilo <Syuilotan@yahoo.co.jp>
Date: Sat, 4 Dec 2021 20:35:08 +0900
Subject: [PATCH] fix(client): fix range slider rendering

---
 .../client/src/components/form-dialog.vue     |  2 +-
 packages/client/src/components/form/range.vue | 28 +++++++++++++++----
 packages/client/src/pages/settings/sounds.vue |  1 +
 3 files changed, 24 insertions(+), 7 deletions(-)

diff --git a/packages/client/src/components/form-dialog.vue b/packages/client/src/components/form-dialog.vue
index fbf49af5d2..efd0da443d 100644
--- a/packages/client/src/components/form-dialog.vue
+++ b/packages/client/src/components/form-dialog.vue
@@ -40,7 +40,7 @@
 					<template #caption><span v-text="form[item].label || item"></span><span v-if="form[item].required === false"> ({{ $ts.optional }})</span></template>
 					<option v-for="item in form[item].options" :key="item.value" :value="item.value">{{ item.label }}</option>
 				</FormRadios>
-				<FormRange v-else-if="form[item].type === 'range'" v-model="values[item]" :min="form[item].mim" :max="form[item].max" :step="form[item].step" class="_formBlock">
+				<FormRange v-else-if="form[item].type === 'range'" v-model="values[item]" :min="form[item].mim" :max="form[item].max" :step="form[item].step" :text-converter="form[item].textConverter" class="_formBlock">
 					<template #label><span v-text="form[item].label || item"></span><span v-if="form[item].required === false"> ({{ $ts.optional }})</span></template>
 					<template v-if="form[item].description" #caption>{{ form[item].description }}</template>
 				</FormRange>
diff --git a/packages/client/src/components/form/range.vue b/packages/client/src/components/form/range.vue
index 79a83d6a93..3e02cacb9b 100644
--- a/packages/client/src/components/form/range.vue
+++ b/packages/client/src/components/form/range.vue
@@ -16,7 +16,7 @@
 </template>
 
 <script lang="ts">
-import { computed, defineComponent, ref, watch } from 'vue';
+import { computed, defineComponent, onMounted, onUnmounted, ref, watch } from 'vue';
 import * as os from '@/os';
 
 export default defineComponent({
@@ -58,6 +58,9 @@ export default defineComponent({
 	},
 
 	setup(props, context) {
+		const containerEl = ref<HTMLElement>();
+		const thumbEl = ref<HTMLElement>();
+
 		const rawValue = ref((props.modelValue - props.min) / (props.max - props.min));
 		const steppedValue = computed(() => {
 			if (props.step) {
@@ -78,10 +81,25 @@ export default defineComponent({
 			if (thumbEl.value == null) return 0;
 			return thumbEl.value!.offsetWidth;
 		});
-		const thumbPosition = computed(() => {
-			if (containerEl.value == null) return 0;
-			return (containerEl.value.offsetWidth - thumbWidth.value) * steppedValue.value;
+		const thumbPosition = ref(0);
+		const calcThumbPosition = () => {
+			if (containerEl.value == null) {
+				thumbPosition.value = 0;
+			} else {
+				thumbPosition.value = (containerEl.value.offsetWidth - thumbWidth.value) * steppedValue.value;
+			}
+		};
+		watch([steppedValue, containerEl], calcThumbPosition);
+		onMounted(() => {
+			const ro = new ResizeObserver((entries, observer) => {
+				calcThumbPosition();
+			});
+			ro.observe(containerEl.value);
+			onUnmounted(() => {
+				ro.disconnect();
+			});
 		});
+
 		const steps = computed(() => {
 			if (props.step) {
 				return (props.max - props.min) / props.step;
@@ -89,8 +107,6 @@ export default defineComponent({
 				return 0;
 			}
 		});
-		const containerEl = ref<HTMLElement>();
-		const thumbEl = ref<HTMLElement>();
 
 		const onMousedown = (ev: MouseEvent | TouchEvent) => {
 			ev.preventDefault();
diff --git a/packages/client/src/pages/settings/sounds.vue b/packages/client/src/pages/settings/sounds.vue
index 1492a989a2..0977dd8322 100644
--- a/packages/client/src/pages/settings/sounds.vue
+++ b/packages/client/src/pages/settings/sounds.vue
@@ -119,6 +119,7 @@ export default defineComponent({
 					mim: 0,
 					max: 1,
 					step: 0.05,
+					textConverter: (v) => `${Math.floor(v * 100)}%`,
 					label: this.$ts.volume,
 					default: this.sounds[type].volume
 				},