Skip to content

Commit b0dd2e6

Browse files
committed
add system theme support back
It was removed by mistake
1 parent 78e040b commit b0dd2e6

File tree

2 files changed

+48
-16
lines changed

2 files changed

+48
-16
lines changed

app/root.tsx

Lines changed: 40 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ import { Icon, href as iconsHref } from './components/ui/icon.tsx'
4343
import fontStylestylesheetUrl from './styles/font.css'
4444
import tailwindStylesheetUrl from './styles/tailwind.css'
4545
import { authenticator, getUserId } from './utils/auth.server.ts'
46-
import { ClientHintCheck, getHints } from './utils/client-hints.tsx'
46+
import { ClientHintCheck, getHints, useHints } from './utils/client-hints.tsx'
4747
import { getConfetti } from './utils/confetti.server.ts'
4848
import { prisma } from './utils/db.server.ts'
4949
import { getEnv } from './utils/env.server.ts'
@@ -54,6 +54,7 @@ import {
5454
invariantResponse,
5555
} from './utils/misc.tsx'
5656
import { useNonce } from './utils/nonce-provider.ts'
57+
import { useRequestInfo } from './utils/request-info.ts'
5758
import { type Theme, setTheme, getTheme } from './utils/theme.server.ts'
5859
import { makeTimings, time } from './utils/timing.server.ts'
5960
import { getToast } from './utils/toast.server.ts'
@@ -167,7 +168,7 @@ export const headers: HeadersFunction = ({ loaderHeaders }) => {
167168
}
168169

169170
const ThemeFormSchema = z.object({
170-
theme: z.enum(['light', 'dark']),
171+
theme: z.enum(['system', 'light', 'dark']),
171172
})
172173

173174
export async function action({ request }: DataFunctionArgs) {
@@ -202,7 +203,7 @@ function Document({
202203
}: {
203204
children: React.ReactNode
204205
nonce: string
205-
theme?: 'dark' | 'light'
206+
theme?: Theme
206207
env?: Record<string, string>
207208
}) {
208209
return (
@@ -344,20 +345,40 @@ function UserDropdown() {
344345
)
345346
}
346347

347-
function useTheme() {
348-
const data = useLoaderData<typeof loader>()
348+
/**
349+
* @returns the user's theme preference, or the client hint theme if the user
350+
* has not set a preference.
351+
*/
352+
export function useTheme() {
353+
const hints = useHints()
354+
const requestInfo = useRequestInfo()
355+
const optimisticMode = useOptimisticThemeMode()
356+
if (optimisticMode) {
357+
return optimisticMode === 'system' ? hints.theme : optimisticMode
358+
}
359+
return requestInfo.userPrefs.theme ?? hints.theme
360+
}
361+
362+
/**
363+
* If the user's changing their theme mode preference, this will return the
364+
* value it's being changed to.
365+
*/
366+
export function useOptimisticThemeMode() {
349367
const fetchers = useFetchers()
368+
350369
const themeFetcher = fetchers.find(
351370
f => f.formData?.get('intent') === 'update-theme',
352371
)
353-
const optimisticTheme = themeFetcher?.formData?.get('theme')
354-
if (optimisticTheme === 'light' || optimisticTheme === 'dark') {
355-
return optimisticTheme
372+
373+
if (themeFetcher && themeFetcher.formData) {
374+
const submission = parse(themeFetcher.formData, {
375+
schema: ThemeFormSchema,
376+
})
377+
return submission.value?.theme
356378
}
357-
return data.requestInfo.userPrefs.theme
358379
}
359380

360-
function ThemeSwitch({ userPreference }: { userPreference?: Theme }) {
381+
function ThemeSwitch({ userPreference }: { userPreference?: Theme | null }) {
361382
const fetcher = useFetcher<typeof action>()
362383

363384
const [form] = useForm({
@@ -368,8 +389,10 @@ function ThemeSwitch({ userPreference }: { userPreference?: Theme }) {
368389
},
369390
})
370391

371-
const mode = userPreference ?? 'light'
372-
const nextMode = mode === 'light' ? 'dark' : 'light'
392+
const optimisticMode = useOptimisticThemeMode()
393+
const mode = optimisticMode ?? userPreference ?? 'system'
394+
const nextMode =
395+
mode === 'system' ? 'light' : mode === 'light' ? 'dark' : 'system'
373396
const modeLabel = {
374397
light: (
375398
<Icon name="sun">
@@ -381,6 +404,11 @@ function ThemeSwitch({ userPreference }: { userPreference?: Theme }) {
381404
<span className="sr-only">Dark</span>
382405
</Icon>
383406
),
407+
system: (
408+
<Icon name="laptop">
409+
<span className="sr-only">System</span>
410+
</Icon>
411+
),
384412
}
385413

386414
return (

app/utils/theme.server.ts

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,17 @@ import * as cookie from 'cookie'
33
const cookieName = 'en_theme'
44
export type Theme = 'light' | 'dark'
55

6-
export function getTheme(request: Request): Theme {
6+
export function getTheme(request: Request): Theme | null {
77
const cookieHeader = request.headers.get('cookie')
88
const parsed = cookieHeader ? cookie.parse(cookieHeader)[cookieName] : 'light'
99
if (parsed === 'light' || parsed === 'dark') return parsed
10-
return 'light'
10+
return null
1111
}
1212

13-
export function setTheme(theme: Theme) {
14-
return cookie.serialize(cookieName, theme, { path: '/' })
13+
export function setTheme(theme: Theme | 'system') {
14+
if (theme === 'system') {
15+
return cookie.serialize(cookieName, '', { path: '/', maxAge: -1 })
16+
} else {
17+
return cookie.serialize(cookieName, theme, { path: '/' })
18+
}
1519
}

0 commit comments

Comments
 (0)