Skip to content

Commit

Permalink
Add handling for OS color mode to the composable
Browse files Browse the repository at this point in the history
  • Loading branch information
dhruvkb committed Sep 3, 2024
1 parent eefd5a3 commit f4bd777
Show file tree
Hide file tree
Showing 2 changed files with 65 additions and 9 deletions.
38 changes: 38 additions & 0 deletions frontend/src/composables/use-dark-mode.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { computed, useUiStore } from "#imports"

import { usePreferredColorScheme } from "@vueuse/core"

import { useFeatureFlagStore } from "~/stores/feature-flag"

export const DARK_MODE_CLASS = "dark-mode"
Expand All @@ -22,13 +24,47 @@ export function useDarkMode() {
featureFlagStore.isOn("dark_mode_ui_toggle")
)

/**
* the color mode setting for the app;
*
* This can be one of "dark", "light" or "system". If the toggle
* feature is disabled, we default to "light".
*/
const colorMode = computed(() => {
if (darkModeToggleable.value) {
return uiStore.colorMode
}
return "light"
})

/**
* the color mode setting for the OS;
*
* This can be one of "dark" or "light". If the OS does not specify
* a preference, we default to "light".
*/
const osColorMode = computed(() => {
const pref = usePreferredColorScheme()
return pref.value === "no-preference" ? "light" : pref.value
})

/**
* the effective color mode of the app;
*
* This can be one of "dark" or "light". This is a combination of the
* toggle feature flag, the user's preference at the app and OS levels
* and the default value of "light".
*/
const effectiveColorMode = computed(() => {
if (!darkModeToggleable.value) {
return "light"
}
if (colorMode.value === "system") {
return osColorMode.value
}
return colorMode.value
})

const cssClass = computed(() => {
return {
light: LIGHT_MODE_CLASS,
Expand All @@ -39,6 +75,8 @@ export function useDarkMode() {

return {
colorMode,
osColorMode,
effectiveColorMode,
cssClass,
}
}
36 changes: 27 additions & 9 deletions frontend/test/unit/specs/composables/use-dark-mode.spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import { describe, expect, test } from "vitest"
import { describe, expect, test, vi } from "vitest"

import { usePreferredColorScheme } from "@vueuse/core"

import {
DARK_MODE_CLASS,
Expand All @@ -9,16 +11,31 @@ import { OFF, ON } from "~/constants/feature-flag"
import { useFeatureFlagStore } from "~/stores/feature-flag"
import { useUiStore } from "~/stores/ui"

vi.mock("@vueuse/core", () => ({
usePreferredColorScheme: vi.fn(),
}))

describe("useDarkMode", () => {
test.each`
description | featureFlags | uiColorMode | expectedColorMode | expectedCssClass
${"Disable toggling"} | ${{ dark_mode_ui_toggle: OFF }} | ${"dark"} | ${"light"} | ${LIGHT_MODE_CLASS}
${"Enable toggling, User preference: light"} | ${{ dark_mode_ui_toggle: ON }} | ${"light"} | ${"light"} | ${LIGHT_MODE_CLASS}
${"Enable toggling, User preference: dark"} | ${{ dark_mode_ui_toggle: ON }} | ${"dark"} | ${"dark"} | ${DARK_MODE_CLASS}
${"Enable toggling, User preference: system"} | ${{ dark_mode_ui_toggle: ON }} | ${"system"} | ${"system"} | ${""}
description | featureFlags | uiColorMode | osColorMode | expectedColorMode | expectedEffectiveColorMode | expectedCssClass
${"Toggle: off"} | ${{ dark_mode_ui_toggle: OFF }} | ${"dark"} | ${"dark"} | ${"light"} | ${"light"} | ${LIGHT_MODE_CLASS}
${"Toggle: on, Preference: light"} | ${{ dark_mode_ui_toggle: ON }} | ${"light"} | ${"dark"} | ${"light"} | ${"light"} | ${LIGHT_MODE_CLASS}
${"Toggle: on, Preference: dark"} | ${{ dark_mode_ui_toggle: ON }} | ${"dark"} | ${"light"} | ${"dark"} | ${"dark"} | ${DARK_MODE_CLASS}
${"Toggle: on, Preference: system, System: light"} | ${{ dark_mode_ui_toggle: ON }} | ${"system"} | ${"light"} | ${"system"} | ${"light"} | ${""}
${"Toggle: on, Preference: system, System: dark"} | ${{ dark_mode_ui_toggle: ON }} | ${"system"} | ${"dark"} | ${"system"} | ${"dark"} | ${""}
${"Toggle: on, Preference: system, System: no-preference"} | ${{ dark_mode_ui_toggle: ON }} | ${"system"} | ${"no-preference"} | ${"system"} | ${"light"} | ${""}
`(
"$description: should report colorMode as $expectedColorMode and cssClass as $expectedCssClass",
({ featureFlags, uiColorMode, expectedColorMode, expectedCssClass }) => {
"$description: should report colorMode as $expectedColorMode, effectiveColorMode as $expectedEffectiveColorMode and cssClass as $expectedCssClass",
({
featureFlags,
uiColorMode,
osColorMode,
expectedColorMode,
expectedEffectiveColorMode,
expectedCssClass,
}) => {
usePreferredColorScheme.mockImplementation(() => ({ value: osColorMode }))

const featureFlagStore = useFeatureFlagStore()

featureFlagStore.toggleFeature(
Expand All @@ -31,10 +48,11 @@ describe("useDarkMode", () => {
uiStore.colorMode = uiColorMode

// Call the composable
const { colorMode, cssClass } = useDarkMode()
const { colorMode, effectiveColorMode, cssClass } = useDarkMode()

// Assert the computed properties
expect(colorMode.value).toBe(expectedColorMode)
expect(effectiveColorMode.value).toBe(expectedEffectiveColorMode)
expect(cssClass.value).toBe(expectedCssClass)
}
)
Expand Down

0 comments on commit f4bd777

Please sign in to comment.