Skip to content

Commit 47dc252

Browse files
committed
Adding light/dark mode fixes to support cookies and localstorage
1 parent 05d9063 commit 47dc252

File tree

6 files changed

+69
-6
lines changed

6 files changed

+69
-6
lines changed
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
<?php
2+
3+
namespace App\Http\Middleware;
4+
5+
use Closure;
6+
use Illuminate\Http\Request;
7+
use Illuminate\Support\Facades\View;
8+
use Symfony\Component\HttpFoundation\Response;
9+
10+
class HandleAppearance
11+
{
12+
/**
13+
* Handle an incoming request.
14+
*
15+
* @param \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response) $next
16+
*/
17+
public function handle(Request $request, Closure $next): Response
18+
{
19+
View::share('appearance', $request->cookie('appearance') ?? 'system');
20+
21+
return $next($request);
22+
}
23+
}

bootstrap/app.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
<?php
22

3+
use App\Http\Middleware\HandleAppearance;
34
use App\Http\Middleware\HandleInertiaRequests;
45
use Illuminate\Foundation\Application;
56
use Illuminate\Foundation\Configuration\Exceptions;
@@ -13,7 +14,10 @@
1314
health: '/up',
1415
)
1516
->withMiddleware(function (Middleware $middleware) {
17+
$middleware->encryptCookies(except: ['appearance']);
18+
1619
$middleware->web(append: [
20+
HandleAppearance::class,
1721
HandleInertiaRequests::class,
1822
AddLinkHeadersForPreloadedAssets::class,
1923
]);

resources/js/composables/useAppearance.ts

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,15 @@ export function updateTheme(value: Appearance) {
1616
}
1717
}
1818

19+
const setCookie = (name: string, value: string, days = 365) => {
20+
if (typeof document === 'undefined') {
21+
return;
22+
}
23+
24+
const maxAge = days * 24 * 60 * 60;
25+
document.cookie = `${name}=${value};path=/;max-age=${maxAge};SameSite=Lax`;
26+
};
27+
1928
const mediaQuery = () => {
2029
if (typeof window === 'undefined') {
2130
return null;
@@ -64,10 +73,14 @@ export function useAppearance() {
6473

6574
function updateAppearance(value: Appearance) {
6675
appearance.value = value;
67-
if (typeof window !== 'undefined') {
68-
localStorage.setItem('appearance', value);
69-
updateTheme(value);
70-
}
76+
77+
// Store in localStorage for client-side persistence...
78+
localStorage.setItem('appearance', value);
79+
80+
// Store in cookie for SSR...
81+
setCookie('appearance', value);
82+
83+
updateTheme(value);
7184
}
7285

7386
return {

resources/views/app.blade.php

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,32 @@
11
<!DOCTYPE html>
2-
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
2+
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}" @class(['dark' => ($appearance ?? 'system') == 'dark'])>
33
<head>
44
<meta charset="utf-8">
55
<meta name="viewport" content="width=device-width, initial-scale=1">
66

7+
{{-- Inline script to detect system dark mode preference and apply it immediately --}}
8+
<script>
9+
(function() {
10+
const appearance = '{{ $appearance ?? "system" }}';
11+
if (appearance === 'system') {
12+
const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
13+
if (prefersDark) {
14+
document.documentElement.classList.add('dark');
15+
}
16+
}
17+
})();
18+
</script>
19+
20+
{{-- Inline style to set the HTML background color based on our theme in app.css --}}
21+
<style>
22+
html {
23+
background-color: oklch(1 0 0);
24+
}
25+
html.dark {
26+
background-color: oklch(0.145 0 0);
27+
}
28+
</style>
29+
730
<title inertia>{{ config('app.name', 'Laravel') }}</title>
831

932
<link rel="preconnect" href="https://fonts.bunny.net">

vite.config.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ export default defineConfig({
1010
plugins: [
1111
laravel({
1212
input: ['resources/js/app.ts'],
13-
ssr: 'resources/js/ssr.tsx',
13+
ssr: 'resources/js/ssr.ts',
1414
refresh: true,
1515
}),
1616
vue({

0 commit comments

Comments
 (0)