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: cookie storage #221

Open
wants to merge 27 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
ecf89c0
chore: add option
Mar 17, 2023
9b0d263
feat: get preference from cookies and set new preference in cookie
Mar 17, 2023
c049126
Merge branch 'master' into feat/sync-cookie
Hossein-Mirazimi Jul 22, 2023
f401f46
chore(deps): update devdependency typescript to v5 (#187)
renovate[bot] Mar 19, 2023
1dea526
fix: wrap injected script with iife (#196)
antfu Jun 21, 2023
e342256
chore: switch to pnpm
antfu Jun 21, 2023
e1c5ff9
chore: fix test
antfu Jun 21, 2023
94eac61
chore(release): 3.3.0
antfu Jun 21, 2023
b32d65c
Merge branch 'feat/sync-cookie' of github.com:Hossein-Mirazimi/color-…
Aug 7, 2023
23cb4b0
feat: add storage option
Aug 11, 2023
8a89267
Merge branch 'master' into feat/sync-cookie
Hossein-Mirazimi Aug 11, 2023
af696e7
fix: check window object for prevent error occured
Aug 11, 2023
9ee19d9
Merge branch 'nuxt-modules:master' into feat/sync-cookie
Hossein-Mirazimi Sep 9, 2023
922e397
chore: update nuxt versions
danielroe Nov 15, 2023
e1cb818
test: ensure routes are prerendered
danielroe Nov 15, 2023
6c1d2ac
chore(deps): update all non-major dependencies (#161)
renovate[bot] Nov 15, 2023
94fa261
chore(deps): update commitlint monorepo to v18 (major) (#213)
renovate[bot] Nov 15, 2023
0055047
chore(deps): update actions/checkout action to v4 (#208)
renovate[bot] Nov 15, 2023
36e83cd
chore(deps): update actions/setup-node action to v4 (#214)
renovate[bot] Nov 15, 2023
2b7633a
fix: initialise helper to empty object when testing
danielroe Nov 15, 2023
07c704f
chore(release): 3.3.1
danielroe Nov 15, 2023
4a5dd55
fix: use `ref` for island color-mode stub and check it is truthy
danielroe Nov 15, 2023
49563d8
chore(release): 3.3.2
danielroe Nov 15, 2023
388cfb5
fix: window reference on build
manniL Nov 25, 2023
957d9d4
chore: lint
manniL Nov 25, 2023
c8eab90
feat: read cookie from server
manniL Nov 25, 2023
427e5bd
Merge remote-tracking branch 'upstream/master' into cookie-storage
manniL Nov 25, 2023
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
10 changes: 8 additions & 2 deletions src/module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ import { promises as fsp } from 'fs'
import { join, resolve } from 'pathe'
import template from 'lodash.template'
import { addPlugin, addTemplate, defineNuxtModule, isNuxt2, addComponent, addImports, createResolver } from '@nuxt/kit'

import { name, version } from '../package.json'
import type { ColorModeStorage } from './runtime/types'

const DEFAULTS: ModuleOptions = {
preference: 'system',
Expand All @@ -14,7 +14,8 @@ const DEFAULTS: ModuleOptions = {
classPrefix: '',
classSuffix: '-mode',
dataValue: '',
storageKey: 'nuxt-color-mode'
storageKey: 'nuxt-color-mode',
storage: 'localStorage'
}

export default defineNuxtModule({
Expand Down Expand Up @@ -158,6 +159,11 @@ export interface ModuleOptions {
* @default 'nuxt-color-mode'
*/
storageKey: string
/**
* The default storage
* @default `localStorage`
*/
storage?: ColorModeStorage
/**
* The script that will be injected into the head of the page
*/
Expand Down
19 changes: 17 additions & 2 deletions 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, storage } from '#color-mode-options'

// Initialise to empty object to avoid hard error when hydrating app in test mode
const helper = (window[globalName] || {}) as unknown as {
Expand Down Expand Up @@ -72,6 +72,20 @@ export default defineNuxtPlugin((nuxtApp) => {
})
}

function setPreferenceToStorage (storageType: typeof storage, preference: string) {
switch (storageType) {
case 'cookie':
window.document.cookie = storageKey + '=' + preference
break
case 'sessionStorage':
window.sessionStorage?.setItem(storageKey, preference)
break
case 'localStorage':
default:
window.localStorage?.setItem(storageKey, preference)
}
}

watch(() => colorMode.preference, (preference) => {
if (colorMode.forced) {
return
Expand All @@ -83,8 +97,9 @@ export default defineNuxtPlugin((nuxtApp) => {
colorMode.value = preference
}

setPreferenceToStorage(storage, preference)
// Local storage to sync with other tabs
window.localStorage?.setItem(storageKey, preference)
// window.localStorage?.setItem(storageKey, preference)
}, { immediate: true })

watch(() => colorMode.value, (newValue, oldValue) => {
Expand Down
11 changes: 9 additions & 2 deletions src/runtime/plugin.server.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { reactive, ref } 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 { defineNuxtPlugin, isVue2, isVue3, useHead, useState, useRouter, useRequestHeaders } from '#imports'
import { preference, hid, script, dataValue, storage, storageKey } from '#color-mode-options'

const addScript = (head) => {
head.script = head.script || []
Expand Down Expand Up @@ -45,6 +45,13 @@ export default defineNuxtPlugin((nuxtApp) => {
}

if (isVue3) {
if (storage === 'cookie') {
const { cookie } = useRequestHeaders(['cookie'])
const [, value] = cookie?.split('; ').map(s => s.split('=')).find(([k]) => k === storageKey) ?? []
if (value) {
colorMode.preference = value
}
}
useHead({ htmlAttrs })
}

Expand Down
2 changes: 2 additions & 0 deletions src/runtime/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ export interface ColorModeInstance {
forced: boolean
}

export type ColorModeStorage = 'localStorage'|'sessionStorage'|'cookie';

// @ts-ignore
declare module 'vue/types/vue' {
interface Vue {
Expand Down
25 changes: 24 additions & 1 deletion src/script.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

const knownColorSchemes = ['dark', 'light']

const preference = (window && window.localStorage && window.localStorage.getItem && window.localStorage.getItem('<%= options.storageKey %>')) || '<%= options.preference %>'
const preference = getStorageValue('<%= options.storage %>', '<%= options.storageKey %>') || '<%= options.preference %>'
let value = preference === 'system' ? getColorScheme() : preference
// Applied forced color mode
const forcedColorMode = de.getAttribute('data-color-mode-forced')
Expand Down Expand Up @@ -71,3 +71,26 @@
return '<%= options.fallback %>'
}
})()

// @ts-ignore
function getStorageValue (storageType, storageKey) {
if (window?.document === 'undefined') { return null }

switch (storageType) {
case 'localStorage':
return window.localStorage.getItem(storageKey)
case 'sessionStorage':
return window.sessionStorage.getItem(storageKey)
case 'cookie':
return getCookie(storageKey)
default:
return null
}
}

// @ts-ignore
function getCookie (name) {
const value = '; ' + window.document.cookie
const parts = value.split('; ' + name + '=')
if (parts.length === 2) { return parts.pop()?.split(';').shift() }
}
Loading