Skip to content

Commit 7c8b825

Browse files
feat: add toggle component
1 parent 8825b0a commit 7c8b825

3 files changed

Lines changed: 55 additions & 102 deletions

File tree

app/components/Toggle.client.vue

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
<script setup lang="ts">
2+
defineProps<{
3+
label: string
4+
}>()
5+
6+
const checked = defineModel<boolean>({
7+
default: false,
8+
})
9+
</script>
10+
11+
<template>
12+
<button
13+
type="button"
14+
class="w-full flex items-center justify-between gap-4 group"
15+
role="switch"
16+
:aria-checked="checked"
17+
@click="checked = !checked"
18+
>
19+
<span class="text-sm text-fg font-medium text-start">
20+
{{ label }}
21+
</span>
22+
<span
23+
class="relative inline-flex h-6 w-11 shrink-0 items-center rounded-full border-2 border-transparent transition-colors duration-200 ease-in-out motion-reduce:transition-none shadow-sm cursor-pointer"
24+
:class="checked ? 'bg-accent' : 'bg-bg border border-border'"
25+
aria-hidden="true"
26+
>
27+
<span
28+
class="pointer-events-none inline-block h-5 w-5 rounded-full shadow-sm ring-0 transition-transform duration-200 ease-in-out motion-reduce:transition-none"
29+
:class="checked ? 'bg-bg' : 'bg-fg-muted'"
30+
/>
31+
</span>
32+
</button>
33+
</template>
34+
35+
<style scoped>
36+
button[aria-checked='false'] > span:last-of-type > span {
37+
translate: 0;
38+
}
39+
button[aria-checked='true'] > span:last-of-type > span {
40+
translate: calc(100%);
41+
}
42+
html[dir='rtl'] button[aria-checked='true'] > span:last-of-type > span {
43+
translate: calc(-100%);
44+
}
45+
</style>

app/pages/settings.vue

Lines changed: 10 additions & 102 deletions
Original file line numberDiff line numberDiff line change
@@ -100,71 +100,17 @@ defineOgImageComponent('Default', {
100100
</h2>
101101
<div class="bg-bg-subtle border border-border rounded-lg p-4 sm:p-6 space-y-4">
102102
<!-- Relative dates toggle -->
103-
<div class="space-y-2">
104-
<ClientOnly>
105-
<button
106-
type="button"
107-
class="w-full flex items-center justify-between gap-4 group"
108-
role="switch"
109-
:aria-checked="settings.relativeDates"
110-
@click="settings.relativeDates = !settings.relativeDates"
111-
>
112-
<span class="text-sm text-fg font-medium text-start">
113-
{{ $t('settings.relative_dates') }}
114-
</span>
115-
<span
116-
class="relative inline-flex h-6 w-11 shrink-0 items-center rounded-full border-2 border-transparent transition-colors duration-200 ease-in-out motion-reduce:transition-none shadow-sm cursor-pointer"
117-
:class="settings.relativeDates ? 'bg-accent' : 'bg-bg border border-border'"
118-
aria-hidden="true"
119-
>
120-
<span
121-
class="pointer-events-none inline-block h-5 w-5 rounded-full shadow-sm ring-0 transition-transform duration-200 ease-in-out motion-reduce:transition-none"
122-
:class="settings.relativeDates ? 'bg-bg' : 'bg-fg-muted'"
123-
/>
124-
</span>
125-
</button>
126-
<template #fallback>
127-
<ToggleSkeleton :label="$t('settings.relative_dates')" />
128-
</template>
129-
</ClientOnly>
130-
<p class="text-sm text-fg-muted">
131-
{{ $t('settings.relative_dates_description') }}
132-
</p>
133-
</div>
103+
<Toggle :label="$t('settings.relative_dates')" v-model="settings.relativeDates" />
134104

135105
<!-- Divider -->
136106
<div class="border-t border-border" />
137107

138108
<!-- Include @types in install toggle -->
139109
<div class="space-y-2">
140-
<ClientOnly>
141-
<button
142-
type="button"
143-
class="w-full flex items-center justify-between gap-4 group"
144-
role="switch"
145-
:aria-checked="settings.includeTypesInInstall"
146-
@click="settings.includeTypesInInstall = !settings.includeTypesInInstall"
147-
>
148-
<span class="text-sm text-fg font-medium text-start">
149-
{{ $t('settings.include_types') }}
150-
</span>
151-
<span
152-
class="relative inline-flex h-6 w-11 shrink-0 items-center rounded-full border-2 border-transparent transition-colors duration-200 ease-in-out motion-reduce:transition-none shadow-sm cursor-pointer"
153-
:class="
154-
settings.includeTypesInInstall ? 'bg-accent' : 'bg-bg border border-border'
155-
"
156-
aria-hidden="true"
157-
>
158-
<span
159-
class="pointer-events-none inline-block h-5 w-5 rounded-full shadow-sm ring-0 transition-transform duration-200 ease-in-out motion-reduce:transition-none"
160-
:class="settings.includeTypesInInstall ? 'bg-bg' : 'bg-fg-muted'"
161-
/>
162-
</span>
163-
</button>
164-
<template #fallback>
165-
<ToggleSkeleton :label="$t('settings.include_types')" />
166-
</template>
167-
</ClientOnly>
110+
<Toggle
111+
:label="$t('settings.include_types')"
112+
v-model="settings.includeTypesInInstall"
113+
/>
168114
<p class="text-sm text-fg-muted">
169115
{{ $t('settings.include_types_description') }}
170116
</p>
@@ -175,38 +121,12 @@ defineOgImageComponent('Default', {
175121

176122
<!-- Hide platform-specific packages toggle -->
177123
<div class="space-y-2">
178-
<ClientOnly>
179-
<button
180-
type="button"
181-
class="w-full flex items-center justify-between gap-4 group"
182-
role="switch"
183-
:aria-checked="settings.hidePlatformPackages"
184-
@click="settings.hidePlatformPackages = !settings.hidePlatformPackages"
185-
>
186-
<span class="text-sm text-fg font-medium text-start">
187-
{{ $t('settings.hide_platform_packages') }}
188-
</span>
189-
<span
190-
class="relative inline-flex h-6 w-11 shrink-0 items-center rounded-full border-2 border-transparent transition-colors duration-200 ease-in-out motion-reduce:transition-none shadow-sm cursor-pointer"
191-
:class="
192-
settings.hidePlatformPackages ? 'bg-accent' : 'bg-bg border border-border'
193-
"
194-
aria-hidden="true"
195-
>
196-
<span
197-
class="pointer-events-none inline-block h-5 w-5 rounded-full shadow-sm ring-0 transition-transform duration-200 ease-in-out motion-reduce:transition-none"
198-
:class="settings.hidePlatformPackages ? 'bg-bg' : 'bg-fg-muted'"
199-
/>
200-
</span>
201-
</button>
202-
<template #fallback>
203-
<p class="text-sm text-fg-muted">
204-
{{ $t('settings.hide_platform_packages') }}
205-
</p>
206-
</template>
207-
</ClientOnly>
124+
<Toggle
125+
:label="$t('settings.hide_platform_packages')"
126+
v-model="settings.hidePlatformPackages"
127+
/>
208128
<p class="text-sm text-fg-muted">
209-
{{ $t('settings.hide_platform_packages_description') }}
129+
{{ $t('settings.hide_platform_packages') }}
210130
</p>
211131
</div>
212132
</div>
@@ -271,15 +191,3 @@ defineOgImageComponent('Default', {
271191
</article>
272192
</main>
273193
</template>
274-
275-
<style scoped>
276-
button[aria-checked='false'] > span:last-of-type > span {
277-
translate: 0;
278-
}
279-
button[aria-checked='true'] > span:last-of-type > span {
280-
translate: calc(100%);
281-
}
282-
html[dir='rtl'] button[aria-checked='true'] > span:last-of-type > span {
283-
translate: calc(-100%);
284-
}
285-
</style>

0 commit comments

Comments
 (0)