From b0151afa9a921198074a78940fca4cf674420739 Mon Sep 17 00:00:00 2001
From: Oni-Men <sensyaheis@gmail.com>
Date: Fri, 20 Mar 2020 14:30:37 +0900
Subject: [PATCH] =?UTF-8?q?Add=20range=20component,=20=E9=9F=B3=E9=87=8F?=
 =?UTF-8?q?=E8=A8=AD=E5=AE=9A=E3=81=A7=E4=BD=BF=E7=94=A8=E3=81=99=E3=82=8B?=
 =?UTF-8?q?=20(#6146)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

* add range component, use range component at volume setting

* refactor

* refactor 2

* Update range.vue

Co-authored-by: syuilo <Syuilotan@yahoo.co.jp>
---
 src/client/components/ui/range.vue     | 138 +++++++++++++++++++++++++
 src/client/pages/preferences/index.vue |  18 +++-
 2 files changed, 152 insertions(+), 4 deletions(-)
 create mode 100644 src/client/components/ui/range.vue

diff --git a/src/client/components/ui/range.vue b/src/client/components/ui/range.vue
new file mode 100644
index 0000000000..ab59bf516c
--- /dev/null
+++ b/src/client/components/ui/range.vue
@@ -0,0 +1,138 @@
+<template>
+<div class="timctyfi" :class="{ focused, disabled }">
+	<div class="icon"><slot name="icon"></slot></div>
+	<span class="title"><slot name="title"></slot></span>
+	<input
+		type="range"
+		ref="input"
+		v-model="v"
+		:disabled="disabled"
+		:min="min"
+		:max="max"
+		:step="step"
+		:autofocus="autofocus"
+		@focus="focused = true"
+		@blur="focused = false"
+		@input="$emit('input', $event.target.value)"
+	/>
+</div>
+</template>
+
+<script lang="ts">
+import Vue from "vue";
+export default Vue.extend({
+	props: {
+		value: {
+			type: Number,
+			required: false,
+			default: 0
+		},
+		disabled: {
+			type: Boolean,
+			required: false,
+			default: false
+		},
+		min: {
+			type: String,
+			required: false,
+			default: "0"
+		},
+		max: {
+			type: String,
+			required: false,
+			default: "100"
+		},
+		step: {
+			type: String,
+			required: false,
+			default: "1"
+		},
+		autofocus: {
+			type: Boolean,
+			required: false
+		}
+	},
+	data() {
+		return {
+			v: this.value,
+			focused: false
+		};
+	},
+	watch: {
+		value(v) {
+			this.v = parseFloat(v);
+		}
+	},
+	mounted() {
+		if (this.autofocus) {
+			this.$nextTick(() => {
+				this.$refs.input.focus();
+			});
+		}
+	}
+});
+</script>
+
+<style lang="scss" scoped>
+.timctyfi {
+	position: relative;
+	margin: 8px;
+
+	> .icon {
+		display: inline-block;
+		width: 24px;
+		text-align: center;
+	}
+
+	> .title {
+		pointer-events: none;
+		font-size: 16px;
+		color: var(--inputLabel);
+		overflow: hidden;
+	}
+
+	> input {
+		-webkit-appearance: none;
+		-moz-appearance: none;
+		appearance: none;
+		background: var(--xxubwiul);
+		height: 7px;
+		margin: 0 8px;
+		outline: 0;
+		border: 0;
+		border-radius: 7px;
+
+		&.disabled {
+			opacity: 0.6;
+			cursor: not-allowed;
+		}
+
+		&::-webkit-slider-thumb {
+			-webkit-appearance: none;
+			appearance: none;
+			cursor: pointer;
+			width: 20px;
+			height: 20px;
+			display: block;
+			border-radius: 50%;
+			border: none;
+			background: var(--accent);
+			box-shadow: 0 0 6px rgba(0, 0, 0, 0.3);
+			box-sizing: content-box;
+		}
+
+		&::-moz-range-thumb {
+			-moz-appearance: none;
+			appearance: none;
+			cursor: pointer;
+			width: 20px;
+			height: 20px;
+			display: block;
+			border-radius: 50%;
+			border: none;
+			background: var(--accent);
+			box-shadow: 0 0 6px rgba(0, 0, 0, 0.3);
+		}
+	}
+}
+</style>
diff --git a/src/client/pages/preferences/index.vue b/src/client/pages/preferences/index.vue
index eddf69653d..3bc305a229 100644
--- a/src/client/pages/preferences/index.vue
+++ b/src/client/pages/preferences/index.vue
@@ -8,8 +8,10 @@
 	<section class="_card">
 		<div class="_title"><fa :icon="faMusic"/> {{ $t('sounds') }}</div>
 		<div class="_content">
-			{{ $t('volume') }}
-			<input type="range" v-model="sfxVolume" min="0" max="1" step="0.1"/>
+			<mk-range v-model="sfxVolume" min="0" max="1" step="0.1">
+				<fa slot="icon" :icon="volumeIcon"/>
+				<span slot="title">{{ $t('volume') }}</span>
+			</mk-range>
 		</div>
 		<div class="_content">
 			<mk-select v-model="sfxNote">
@@ -85,12 +87,13 @@
 
 <script lang="ts">
 import Vue from 'vue';
-import { faImage, faCog, faMusic, faPlay } from '@fortawesome/free-solid-svg-icons';
+import { faImage, faCog, faMusic, faPlay, faVolumeUp, faVolumeMute } from '@fortawesome/free-solid-svg-icons';
 import MkInput from '../../components/ui/input.vue';
 import MkButton from '../../components/ui/button.vue';
 import MkSwitch from '../../components/ui/switch.vue';
 import MkSelect from '../../components/ui/select.vue';
 import MkRadio from '../../components/ui/radio.vue';
+import MkRange from '../../components/ui/range.vue';
 import XTheme from './theme.vue';
 import i18n from '../../i18n';
 import { langs } from '../../config';
@@ -128,6 +131,7 @@ export default Vue.extend({
 		MkSwitch,
 		MkSelect,
 		MkRadio,
+		MkRange
 	},
 
 	data() {
@@ -136,7 +140,7 @@ export default Vue.extend({
 			lang: localStorage.getItem('lang'),
 			fontSize: localStorage.getItem('fontSize'),
 			sounds,
-			faImage, faCog, faMusic, faPlay
+			faImage, faCog, faMusic, faPlay, faVolumeUp, faVolumeMute
 		}
 	},
 
@@ -210,6 +214,12 @@ export default Vue.extend({
 			get() { return this.$store.state.device.sfxAntenna; },
 			set(value) { this.$store.commit('device/set', { key: 'sfxAntenna', value }); }
 		},
+
+		volumeIcon: {
+			get() {
+				return this.sfxVolume === 0 ? faVolumeMute : faVolumeUp;
+			}
+		}
 	},
 
 	watch: {