summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--packages/client/src/components/form/checkbox.vue143
-rw-r--r--packages/client/src/components/form/switch.vue47
-rw-r--r--packages/client/src/themes/_dark.json54
-rw-r--r--packages/client/src/themes/_light.json54
4 files changed, 174 insertions, 24 deletions
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)',