88 lines
1.9 KiB
Vue
88 lines
1.9 KiB
Vue
<template>
|
|
<label class="shared-toggle" :class="{ 'is-on': model, 'is-disabled': disabled }">
|
|
<input
|
|
type="checkbox"
|
|
:disabled="disabled"
|
|
v-model="model"
|
|
/>
|
|
<span class="track">
|
|
<span class="thumb" />
|
|
</span>
|
|
<span v-if="$slots.default" class="toggle-label"><slot /></span>
|
|
</label>
|
|
</template>
|
|
|
|
<script setup>
|
|
const props = defineProps({
|
|
disabled: {
|
|
type: Boolean,
|
|
default: false,
|
|
},
|
|
})
|
|
|
|
const model = defineModel()
|
|
</script>
|
|
|
|
<style lang="scss">
|
|
.shared-toggle {
|
|
--t-duration: 250ms;
|
|
--t-ease: var(--ease-out-quad);
|
|
--track-w: #{rs(36px)};
|
|
--track-h: #{rs(20px)};
|
|
--thumb-size: #{rs(14px)};
|
|
display: inline-flex;
|
|
align-items: center;
|
|
gap: rs(10px);
|
|
cursor: pointer;
|
|
user-select: none;
|
|
|
|
input[type='checkbox'] {
|
|
position: absolute;
|
|
opacity: 0;
|
|
width: 0;
|
|
height: 0;
|
|
pointer-events: none;
|
|
}
|
|
|
|
.track {
|
|
flex-shrink: 0;
|
|
width: var(--track-w);
|
|
height: var(--track-h);
|
|
border-radius: var(--track-h);
|
|
background: var(--grey-400);
|
|
position: relative;
|
|
transition: background var(--t-duration) var(--t-ease);
|
|
}
|
|
|
|
.thumb {
|
|
position: absolute;
|
|
top: 50%;
|
|
left: rs(3px);
|
|
transform: translateY(-50%);
|
|
width: var(--thumb-size);
|
|
height: var(--thumb-size);
|
|
border-radius: 50%;
|
|
background: var(--ivory);
|
|
transition: transform var(--t-duration) var(--t-ease), left var(--t-duration) var(--t-ease);
|
|
}
|
|
|
|
.toggle-label {
|
|
@include p;
|
|
}
|
|
|
|
&.is-on {
|
|
.track {
|
|
background: var(--theme-contrast);
|
|
}
|
|
|
|
.thumb {
|
|
left: calc(var(--track-w) - var(--thumb-size) - rs(3px));
|
|
}
|
|
}
|
|
|
|
&.is-disabled {
|
|
opacity: 0.3;
|
|
pointer-events: none;
|
|
}
|
|
}
|
|
</style>
|