wip bsky client for the web & android
bbell.vt3e.cat
1<script setup lang="ts">
2import { useId } from 'vue'
3
4defineProps<{
5 label?: string
6}>()
7
8const model = defineModel<boolean>()
9const id = useId()
10
11const toggle = (e: MouseEvent) => {
12 model.value = !model.value
13}
14</script>
15
16<template>
17 <div class="toggle-wrapper" @click.stop="toggle">
18 <div class="label" v-if="label" :id="`${id}-label`">{{ label }}</div>
19 <button
20 type="button"
21 role="switch"
22 :aria-checked="model"
23 :aria-labelledby="label ? `${id}-label` : undefined"
24 class="toggle-track"
25 :class="{ 'is-checked': model }"
26 >
27 <span class="toggle-thumb"></span>
28 </button>
29 </div>
30</template>
31
32<style scoped lang="scss">
33@use '@/assets/variables' as *;
34
35.toggle-wrapper {
36 display: flex;
37 align-items: center;
38 justify-content: space-between;
39 gap: 0.75rem;
40 cursor: pointer;
41}
42
43.label {
44 color: hsl(var(--text));
45 font-weight: 500;
46}
47
48.toggle-track {
49 display: inline-flex;
50 width: 3rem;
51 height: 1.75rem;
52 background-color: hsla(var(--surface1) / 0.85);
53 border-radius: 1rem;
54 border: none;
55 position: relative;
56 cursor: pointer;
57 flex-shrink: 0;
58
59 box-sizing: unset;
60
61 transition-timing-function: $ease-spring;
62 transition-duration: 0.3s;
63 outline-width: 4px;
64 outline-offset: -1px;
65
66 &:active,
67 &:focus-visible {
68 .toggle-thumb {
69 transform: translateX(0.1rem);
70 background-color: hsl(var(--base) / 0.8);
71 }
72 }
73
74 &:focus-visible {
75 outline-color: hsl(var(--accent));
76 outline-offset: -1px;
77 }
78
79 &:hover {
80 background-color: hsla(var(--surface1) / 1);
81 }
82
83 &:active {
84 .toggle-thumb {
85 width: calc(var(--width) + var(--pressed-grow));
86 }
87 }
88
89 &.is-checked {
90 background: hsl(var(--accent));
91
92 .toggle-thumb {
93 transform: translateX(1.25rem);
94 }
95 .toggle-label {
96 color: hsl(var(--text));
97 }
98
99 &:active {
100 .toggle-thumb {
101 transform: translateX(calc(1.15rem - (var(--pressed-grow))));
102 }
103 }
104 }
105}
106
107.toggle-thumb {
108 --width: 1.35rem;
109 --pressed-grow: 0.4rem;
110
111 position: absolute;
112 top: 0.2rem;
113 left: 0.2rem;
114 width: var(--width);
115 height: 1.35rem;
116 background: hsl(var(--base));
117 border-radius: 2rem;
118
119 transition-timing-function: $ease-spring;
120 transition-duration: 0.3s;
121 transition-property: $transition-properties, width;
122}
123</style>