Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add general attribute support #215

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion docs/content/1.index.md
Original file line number Diff line number Diff line change
Expand Up @@ -142,14 +142,16 @@ export default defineNuxtConfig({
componentName: 'ColorScheme',
classPrefix: '',
classSuffix: '-mode',
dataValue: '',
attrName: '',
storageKey: 'nuxt-color-mode'
}
})
```

Notes:
- `'system'` is a special value; it will automatically detect the color mode based on the system preferences (see [prefers-color-mode spec](https://drafts.csswg.org/mediaqueries-5/#descdef-media-prefers-color-mode)). The value injected will be either `'light'` or `'dark'`. If `no-preference` is detected or the browser does not handle color-mode, it will set the `fallback` value.
- Optional `dataValue` lets you add dataset to the `html`, for example if you currently have `class="dark"` on `html`, `dataValue: 'theme'` will also set `data-theme="dark"` on `html`. This is useful when using library like daisyUI that uses `data-theme="light"` on `html` to apply theme.
- Optional `dataValue` and `attrName` lets you add dataset or general attribute to the `html`. for example, if you currently have `class="dark"` on `html`, `dataValue: 'theme'` will also set `data-theme="dark"` on `html`, `attrName: 'theme-mode'` will set `theme-mode="dark"` on `html`. This is useful when using library like daisyUI or TDesign that uses `data-theme="light"` or `theme-mode="dark"` on `html` to apply theme.

## Caveats

Expand Down
7 changes: 7 additions & 0 deletions src/module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ const DEFAULTS: ModuleOptions = {
classPrefix: '',
classSuffix: '-mode',
dataValue: '',
attrName: '',
storageKey: 'nuxt-color-mode'
}

Expand Down Expand Up @@ -154,6 +155,12 @@ export interface ModuleOptions {
* @default ''
*/
dataValue: string
/**
* Whether to add an attribute to the html tag. If set, it defines the name of the attribute.
* For example, setting this to `theme-mode` will output `<html theme-mode="dark">` if dark mode is enabled.
* @default ''
*/
attrName: string
/**
* @default 'nuxt-color-mode'
*/
Expand Down
19 changes: 18 additions & 1 deletion src/runtime/plugin.client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { computed, reactive, watch } from 'vue'

import type { ColorModeInstance } from './types'
import { defineNuxtPlugin, isVue2, isVue3, useRouter, useHead, useState } from '#imports'
import { globalName, storageKey, dataValue } from '#color-mode-options'
import { globalName, storageKey, dataValue, attrName } from '#color-mode-options'

const helper = window[globalName] as unknown as {
preference: string
Expand Down Expand Up @@ -38,6 +38,23 @@ export default defineNuxtPlugin((nuxtApp) => {
}
}

if (attrName) {
if (isVue3) {
useHead({
htmlAttrs: { [attrName]: computed(() => colorMode.value) }
})
} else {
const app = nuxtApp.nuxt2Context.app
const originalHead = app.head
app.head = function () {
const head = (typeof originalHead === 'function' ? originalHead.call(this) : originalHead) || {}
head.htmlAttrs = head.htmlAttrs || {}
head.htmlAttrs[attrName] = colorMode.value
return head
}
}
}

useRouter().afterEach((to) => {
const forcedColorMode = isVue2
? (to.matched[0]?.components.default as any)?.options.colorMode
Expand Down
5 changes: 4 additions & 1 deletion src/runtime/plugin.server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { reactive } from 'vue'

import type { ColorModeInstance } from './types'
import { defineNuxtPlugin, isVue2, isVue3, useHead, useState, useRouter } from '#imports'
import { preference, hid, script, dataValue } from '#color-mode-options'
import { preference, hid, script, dataValue, attrName } from '#color-mode-options'

const addScript = (head) => {
head.script = head.script || []
Expand Down Expand Up @@ -58,6 +58,9 @@ export default defineNuxtPlugin((nuxtApp) => {
if (dataValue) {
htmlAttrs[`data-${dataValue}`] = colorMode.value
}
if (attrName) {
htmlAttrs[attrName] = colorMode.value
}
colorMode.forced = true
} else if (forcedColorMode === 'system') {
// eslint-disable-next-line no-console
Expand Down
8 changes: 8 additions & 0 deletions src/script.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
function addColorScheme (value) {
const className = '<%= options.classPrefix %>' + value + '<%= options.classSuffix %>'
const dataValue = '<%= options.dataValue %>'
const attrName = '<%= options.attrName %>'
if (de.classList) {
de.classList.add(className)
} else {
Expand All @@ -37,12 +38,16 @@
if (dataValue) {
de.setAttribute('data-' + dataValue, value)
}
if (attrName) {
de.setAttribute(attrName, value)
}
}

// @ts-ignore
function removeColorScheme (value) {
const className = '<%= options.classPrefix %>' + value + '<%= options.classSuffix %>'
const dataValue = '<%= options.dataValue %>'
const attrName = '<%= options.attrName %>'
if (de.classList) {
de.classList.remove(className)
} else {
Expand All @@ -51,6 +56,9 @@
if (dataValue) {
de.removeAttribute('data-' + dataValue)
}
if (attrName) {
de.removeAttribute(attrName)
}
}

// @ts-ignore
Expand Down