Skip to content

Commit

Permalink
feat(useIsDarkTheme): add useIsDarkTheme composable
Browse files Browse the repository at this point in the history
Signed-off-by: Grigorii K. Shartsev <[email protected]>
  • Loading branch information
ShGKme committed Nov 6, 2024
1 parent 9c51326 commit 8dc23cf
Show file tree
Hide file tree
Showing 5 changed files with 121 additions and 0 deletions.
72 changes: 72 additions & 0 deletions docs/composables/useIsDarkTheme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
<!--
- SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
- SPDX-License-Identifier: AGPL-3.0-or-later
-->

```ts static
import {
useIsDarkTheme,
useIsDarkThemeElement,
} from '@nextcloud/vue/dist/Composables/useIsDarkTheme.js'
```

Same as `isDarkTheme` functions, but with reactivity.

## Definition

```ts static
/**
* Check whether the dark theme is enabled on a specific element.
* If you need to check an entire page, use `useIsDarkTheme` instead for better performance.
* Reacts on element attributes change and system theme change.
* @param el - The element to check for the dark theme enabled on, default is document.body
* @return - computed boolean whether the dark theme is enabled
*/
declare function useIsDarkThemeElement(el: MaybeRef<HTMLElement> = document.body): DeepReadonly<Ref<boolean>>

/**
* Shared composable to check whether the dark theme is enabled on the page.
* Reacts on body data-theme-* attributes change and system theme change.
* @return - computed boolean whether the dark theme is enabled
*/
declare function useIsDarkTheme(): DeepReadonly<Ref<boolean>>
```

## Example

```vue
<template>
<div>
<div :style="{ backgroundColor: isDarkTheme ? 'black' : 'white' }">
Is dark theme enabled? {{ isDarkTheme }}
</div>
<NcButton @click="switchTheme">Switch theme</NcButton>
</div>
</template>
<script>
export default {
setup() {
const isDarkTheme = useIsDarkTheme()
// For documentation only. Do not use in production.
function switchTheme() {
if (isDarkTheme.value) {
document.body.setAttribute('data-theme-light', '')
document.body.removeAttribute('data-theme-dark')
document.body.setAttribute('data-themes', 'light')
} else {
document.body.setAttribute('data-theme-dark', '')
document.body.removeAttribute('data-theme-light')
document.body.setAttribute('data-themes', 'dark')
}
}
return {
isDarkTheme,
switchTheme,
}
},
}
</script>
```
1 change: 1 addition & 0 deletions src/composables/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@ export * from './useIsFullscreen/index.js'
export * from './useIsMobile/index.js'
export * from './useFormatDateTime.ts'
export * from './useHotKey/index.js'
export * from './useIsDarkTheme/index.ts'
40 changes: 40 additions & 0 deletions src/composables/useIsDarkTheme/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/**
* SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/

import type { DeepReadonly, Ref } from 'vue'
import { ref, readonly, watch } from 'vue'
import { createSharedComposable, usePreferredDark, useMutationObserver } from '@vueuse/core'
import { checkIfDarkTheme } from '../../functions/isDarkTheme/index.ts'

/**
* Check whether the dark theme is enabled on a specific element.
* If you need to check an entire page, use `useIsDarkTheme` instead for better performance.
* Reacts on element attributes change and system theme change.
* @param el - The element to check for the dark theme enabled on (default is `document.body`)
* @return {DeepReadonly<Ref<boolean>>} - computed boolean whether the dark theme is enabled
*/
export function useIsDarkThemeElement(el: HTMLElement = document.body): DeepReadonly<Ref<boolean>> {
const isDarkTheme = ref(checkIfDarkTheme(el))
const isDarkSystemTheme = usePreferredDark()

/** Update the isDarkTheme */
function updateIsDarkTheme() {
isDarkTheme.value = checkIfDarkTheme(el)
}

// Watch for element change to handle data-theme* attributes change
useMutationObserver(el, updateIsDarkTheme, { attributes: true })
// Watch for system theme change for the default theme
watch(isDarkSystemTheme, updateIsDarkTheme, { immediate: true })

return readonly(isDarkTheme)
}

/**
* Shared composable to check whether the dark theme is enabled on the page.
* Reacts on body data-theme-* attributes change and system theme change.
* @return {DeepReadonly<Ref<boolean>>} - computed boolean whether the dark theme is enabled
*/
export const useIsDarkTheme = createSharedComposable(() => useIsDarkThemeElement())
5 changes: 5 additions & 0 deletions styleguide.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,11 @@ module.exports = async () => {
{
name: 'useHotKey',
content: 'docs/composables/useHotKey.md',

},
{
name: 'useIsDarkTheme',
content: 'docs/composables/useIsDarkTheme.md',
},
],
},
Expand Down
3 changes: 3 additions & 0 deletions styleguide/global.requires.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import usernameToColor from '../src/functions/usernameToColor/index.js'
import Tooltip from './../src/directives/Tooltip/index.js'
import Focus from './../src/directives/Focus/index.js'
import Linkify from './../src/directives/Linkify/index.js'
import { useIsDarkTheme } from '../src/composables/index.js'

import axios from '@nextcloud/axios'

Expand Down Expand Up @@ -166,6 +167,8 @@ window.emojiAddRecent = emojiAddRecent
window.getCurrentSkinTone = getCurrentSkinTone
window.setCurrentSkinTone = setCurrentSkinTone
window.usernameToColor = usernameToColor
// Exported composables
window.useIsDarkTheme = useIsDarkTheme

// Directives
Vue.directive('Tooltip', Tooltip)
Expand Down

0 comments on commit 8dc23cf

Please sign in to comment.