Skip to content

Commit

Permalink
feat: add theme switch component, fix switch and theme toggle rtl mode
Browse files Browse the repository at this point in the history
  • Loading branch information
driss-chelouati committed May 20, 2023
1 parent 4a68e23 commit 6cce995
Show file tree
Hide file tree
Showing 5 changed files with 80 additions and 6 deletions.
8 changes: 8 additions & 0 deletions .playground/pages/tests/form/switch.vue
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ definePageMeta({
description: 'SVG icons',
section: 'form',
})
const ball = ref(false)
</script>

<template>
Expand All @@ -13,6 +15,12 @@ definePageMeta({
>
<div>
<BaseHeading size="xl" weight="medium" class="mb-10">Switch</BaseHeading>
<div class="flex items-center gap-8" dir="ltr">
<BaseThemeSwitch />
<BaseThemeToggle />
<BaseSwitchBall v-model="ball" />
<BaseSwitchThin v-model="ball" />
</div>
</div>
</div>
</template>
66 changes: 66 additions & 0 deletions components/base/BaseThemeSwitch.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
<script setup lang="ts">
const props = withDefaults(
defineProps<{
/**
* Disables transitions when toggling between light and dark mode.
*/
disableTransitions?: boolean
}>(),
{
disableTransitions: false,
}
)
const colorMode = useColorMode()
const isDark = computed({
get() {
return colorMode.value === 'dark'
},
set(value) {
// disable transitions
if (process.client && props.disableTransitions) {
document.documentElement.classList.add('nui-no-transition')
}
colorMode.preference = value ? 'dark' : 'light'
// re-enable transitions
if (process.client && props.disableTransitions) {
setTimeout(() => {
document.documentElement.classList.remove('nui-no-transition')
}, 0)
}
},
})
</script>

<template>
<label
class="bg-muted-200 dark:bg-muted-700 relative block h-6 w-14 scale-[0.8] rounded-full"
>
<input
class="peer absolute start-0 top-0 z-10 h-full w-full cursor-pointer opacity-0"
type="checkbox"
v-model="isDark"
/>
<span
class="dark:bg-muted-900 border-muted-200 dark:border-muted-800 absolute -start-1 -top-2 -ms-1 flex h-10 w-10 items-center justify-center rounded-full border bg-white transition-all duration-300 peer-checked:ms-[45%] peer-checked:rotate-[360deg]"
>
<IconSun
class="pointer-events-none block h-6 w-6 text-yellow-400 transition-all duration-300"
:class="[!isDark ? 'block' : 'hidden']"
/>
<IconMoon
class="pointer-events-none block h-6 w-6 text-yellow-400 transition-all duration-300"
:class="[!isDark ? 'hidden' : 'block']"
/>
</span>
</label>
</template>

<style>
.nui-no-transition * {
transition-property: none !important;
transition-duration: 0 !important;
}
</style>
8 changes: 4 additions & 4 deletions components/base/BaseThemeToggle.vue
Original file line number Diff line number Diff line change
Expand Up @@ -65,17 +65,17 @@ const isDark = computed({
class="pointer-events-none absolute start-1/2 top-1/2 block h-5 w-5 text-yellow-400 transition-all duration-300"
:class="[
!isDark
? '-translate-y-1/2 translate-x-[-50%] opacity-100'
: 'translate-x-[-50%] translate-y-[-150%] opacity-0',
? '-translate-y-1/2 opacity-100 ltr:translate-x-[-50%] rtl:translate-x-[50%]'
: 'translate-y-[-150%] opacity-0 ltr:translate-x-[-50%] rtl:translate-x-[50%]',
]"
/>

<IconMoon
class="pointer-events-none absolute start-1/2 top-1/2 block h-5 w-5 text-yellow-400 transition-all duration-300"
:class="[
!isDark
? 'translate-x-[-45%] translate-y-[-150%] opacity-0'
: '-translate-y-1/2 translate-x-[-45%] opacity-100',
? 'translate-y-[-150%] opacity-0 ltr:translate-x-[-45%] rtl:translate-x-[45%]'
: '-translate-y-1/2 opacity-100 ltr:translate-x-[-45%] rtl:translate-x-[45%]',
]"
/>
</span>
Expand Down
2 changes: 1 addition & 1 deletion components/form/BaseSwitchBall.vue
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ defineExpose({
@change="value = !value"
/>
<span
class="border-muted-300 dark:border-muted-600 dark:bg-muted-700 absolute start-0.5 top-1/2 z-10 flex h-5 w-5 -translate-y-1/2 items-center justify-center rounded-full border bg-white shadow transition focus:w-6 peer-checked:-translate-y-1/2 peer-checked:translate-x-full"
class="border-muted-300 dark:border-muted-600 dark:bg-muted-700 absolute start-0.5 top-1/2 z-10 flex h-5 w-5 -translate-y-1/2 items-center justify-center rounded-full border bg-white shadow transition focus:w-6 peer-checked:-translate-y-1/2 ltr:peer-checked:translate-x-full rtl:peer-checked:-translate-x-full"
></span>
<span
class="bg-muted-300 peer-focus:outline-muted-300 dark:bg-muted-600 dark:peer-focus:outline-muted-600 block h-6 w-11 rounded-full shadow-inner outline-1 outline-transparent transition-all duration-300 peer-focus:outline-dashed peer-focus:outline-offset-2 peer-focus:ring-0"
Expand Down
2 changes: 1 addition & 1 deletion components/form/BaseSwitchThin.vue
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ defineExpose({
@change="value = !value"
/>
<span
class="border-muted-300 dark:border-muted-600 dark:bg-muted-700 absolute -start-1 top-1/2 flex h-6 w-6 -translate-y-1/2 items-center justify-center rounded-full border bg-white shadow transition peer-checked:-translate-y-1/2 peer-checked:translate-x-full"
class="border-muted-300 dark:border-muted-600 dark:bg-muted-700 absolute -start-1 top-1/2 flex h-6 w-6 -translate-y-1/2 items-center justify-center rounded-full border bg-white shadow transition peer-checked:-translate-y-1/2 ltr:peer-checked:translate-x-full rtl:peer-checked:-translate-x-full"
></span>
<span
class="bg-muted-300 peer-focus:outline-muted-300 dark:bg-muted-600 dark:peer-focus:outline-muted-600 block h-4 w-10 rounded-full shadow-inner outline-1 outline-transparent transition-all duration-300 peer-focus:outline-dashed peer-focus:outline-offset-2 peer-focus:ring-0"
Expand Down

0 comments on commit 6cce995

Please sign in to comment.