From bd3c6f4157366e34b41d35eefefce03d110dd415 Mon Sep 17 00:00:00 2001 From: syuilo <Syuilotan@yahoo.co.jp> Date: Sun, 26 Jun 2022 16:38:27 +0900 Subject: [PATCH] chore(client): tweak ui :art: --- .../client/src/components/form/checkbox.vue | 143 ++++++++++++++++++ .../client/src/components/form/switch.vue | 47 +++--- packages/client/src/themes/_dark.json5 | 4 + packages/client/src/themes/_light.json5 | 4 + 4 files changed, 174 insertions(+), 24 deletions(-) create mode 100644 packages/client/src/components/form/checkbox.vue diff --git a/packages/client/src/components/form/checkbox.vue b/packages/client/src/components/form/checkbox.vue new file mode 100644 index 0000000000..fadb770aee --- /dev/null +++ b/packages/client/src/components/form/checkbox.vue @@ -0,0 +1,143 @@ +<template> +<div + class="ziffeoms" + :class="{ disabled, checked }" +> + <input + ref="input" + type="checkbox" + :disabled="disabled" + @keydown.enter="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"> + <!-- TODO: 無名slotの方は廃止 --> + <span @click="toggle"><slot name="label"></slot><slot></slot></span> + <p class="caption"><slot name="caption"></slot></p> + </span> +</div> +</template> + +<script lang="ts" setup> +import { toRefs, Ref } from 'vue'; +import * as os from '@/os'; +import Ripple from '@/components/ripple.vue'; + +const props = defineProps<{ + modelValue: boolean | Ref<boolean>; + disabled?: boolean; +}>(); + +const emit = defineEmits<{ + (ev: 'update:modelValue', v: boolean): void; +}>(); + +let button = $ref<HTMLElement>(); +const checked = toRefs(props).modelValue; +const toggle = () => { + if (props.disabled) return; + emit('update:modelValue', !checked.value); + + if (!checked.value) { + 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'); + } +}; +</script> + +<style lang="scss" scoped> +.ziffeoms { + position: relative; + display: flex; + transition: all 0.2s ease; + + > * { + user-select: none; + } + + > input { + position: absolute; + width: 0; + height: 0; + opacity: 0; + margin: 0; + } + + > .button { + position: relative; + display: inline-flex; + flex-shrink: 0; + margin: 0; + box-sizing: border-box; + width: 23px; + height: 23px; + outline: none; + background: var(--panel); + border: solid 1px var(--panel); + border-radius: 4px; + cursor: pointer; + transition: inherit; + + > .check { + margin: auto; + opacity: 0; + color: var(--fgOnAccent); + font-size: 13px; + transform: scale(0.5); + transition: all 0.2s ease; + } + } + + &:hover { + > .button { + border-color: var(--inputBorderHover) !important; + } + } + + > .label { + margin-left: 12px; + margin-top: 2px; + display: block; + transition: inherit; + color: var(--fg); + + > span { + display: block; + line-height: 20px; + cursor: pointer; + transition: inherit; + } + + > .caption { + margin: 8px 0 0 0; + color: var(--fgTransparentWeak); + font-size: 0.85em; + + &:empty { + display: none; + } + } + } + + &.disabled { + opacity: 0.6; + cursor: not-allowed; + } + + &.checked { + > .button { + background-color: var(--accent) !important; + border-color: var(--accent) !important; + + > .check { + opacity: 1; + transform: scale(1); + } + } + } +} +</style> diff --git a/packages/client/src/components/form/switch.vue b/packages/client/src/components/form/switch.vue index fadb770aee..22b307a46f 100644 --- a/packages/client/src/components/form/switch.vue +++ b/packages/client/src/components/form/switch.vue @@ -1,6 +1,6 @@ <template> <div - class="ziffeoms" + class="ziffeomt" :class="{ disabled, checked }" > <input @@ -9,8 +9,8 @@ :disabled="disabled" @keydown.enter="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 ref="button" v-tooltip="checked ? $ts.itsOn : $ts.itsOff" class="button" @click.prevent="toggle"> + <div class="knob"></div> </span> <span class="label"> <!-- TODO: 無名slotの方は廃止 --> @@ -23,7 +23,6 @@ <script lang="ts" setup> import { toRefs, Ref } from 'vue'; import * as os from '@/os'; -import Ripple from '@/components/ripple.vue'; const props = defineProps<{ modelValue: boolean | Ref<boolean>; @@ -41,16 +40,13 @@ const toggle = () => { emit('update:modelValue', !checked.value); if (!checked.value) { - 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'); + } }; </script> <style lang="scss" scoped> -.ziffeoms { +.ziffeomt { position: relative; display: flex; transition: all 0.2s ease; @@ -73,21 +69,24 @@ const toggle = () => { flex-shrink: 0; margin: 0; box-sizing: border-box; - width: 23px; + width: 32px; height: 23px; outline: none; - background: var(--panel); - border: solid 1px var(--panel); - border-radius: 4px; + background: var(--swutchOffBg); + background-clip: content-box; + border: solid 1px var(--swutchOffBg); + border-radius: 999px; cursor: pointer; transition: inherit; - > .check { - margin: auto; - opacity: 0; - color: var(--fgOnAccent); - font-size: 13px; - transform: scale(0.5); + > .knob { + position: absolute; + top: 3px; + left: 3px; + width: 15px; + height: 15px; + background: var(--swutchOffFg); + border-radius: 999px; transition: all 0.2s ease; } } @@ -130,12 +129,12 @@ const toggle = () => { &.checked { > .button { - background-color: var(--accent) !important; - border-color: var(--accent) !important; + background-color: var(--swutchOnBg) !important; + border-color: var(--swutchOnBg) !important; - > .check { - opacity: 1; - transform: scale(1); + > .knob { + left: 12px; + background: var(--swutchOnFg); } } } diff --git a/packages/client/src/themes/_dark.json5 b/packages/client/src/themes/_dark.json5 index e159f73b83..5c6e7755e4 100644 --- a/packages/client/src/themes/_dark.json5 +++ b/packages/client/src/themes/_dark.json5 @@ -60,6 +60,10 @@ buttonHoverBg: 'rgba(255, 255, 255, 0.1)', buttonGradateA: '@accent', buttonGradateB: ':hue<20<@accent', + swutchOffBg: 'rgba(255, 255, 255, 0.1)', + swutchOffFg: '@fg', + swutchOnBg: '@accentedBg', + swutchOnFg: '@accent', inputBorder: 'rgba(255, 255, 255, 0.1)', inputBorderHover: 'rgba(255, 255, 255, 0.2)', listItemHoverBg: 'rgba(255, 255, 255, 0.03)', diff --git a/packages/client/src/themes/_light.json5 b/packages/client/src/themes/_light.json5 index 87fdbd86b7..66e70d5e19 100644 --- a/packages/client/src/themes/_light.json5 +++ b/packages/client/src/themes/_light.json5 @@ -60,6 +60,10 @@ buttonHoverBg: 'rgba(0, 0, 0, 0.1)', buttonGradateA: '@accent', buttonGradateB: ':hue<20<@accent', + swutchOffBg: 'rgba(0, 0, 0, 0.1)', + swutchOffFg: '@panel', + swutchOnBg: '@accent', + swutchOnFg: '@fgOnAccent', inputBorder: 'rgba(0, 0, 0, 0.1)', inputBorderHover: 'rgba(0, 0, 0, 0.2)', listItemHoverBg: 'rgba(0, 0, 0, 0.03)',