Skip to content

Commit 2feaefe

Browse files
committed
feat: introduce dark mode toggle/theme
1 parent daa718c commit 2feaefe

4 files changed

Lines changed: 191 additions & 7 deletions

File tree

resources/css/style.css

Lines changed: 131 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
@import "swiper/css/pagination";
66
@import "slim-select/styles";
77
@plugin "daisyui/index.js" {
8-
themes: cakephp --default;
8+
themes: cakephp --default, cakephp-dark;
99
}
1010

1111
@plugin "daisyui/theme" {
@@ -45,6 +45,43 @@
4545
--noise: 0;
4646
}
4747

48+
@plugin "daisyui/theme" {
49+
name: "cakephp-dark";
50+
default: false;
51+
prefersdark: true;
52+
color-scheme: dark;
53+
54+
--color-base-100: hsl(0 0% 10%);
55+
--color-base-200: hsl(0 0% 13%);
56+
--color-base-300: hsl(0 0% 17%);
57+
--color-base-content: hsl(0 0% 88%);
58+
59+
--color-primary: var(--color-cake-red);
60+
--color-primary-content: hsl(0 0% 100%);
61+
--color-secondary: var(--color-cake-blue);
62+
--color-secondary-content: hsl(0 0% 100%);
63+
--color-accent: hsl(199 89% 58%);
64+
--color-accent-content: hsl(0 0% 100%);
65+
--color-neutral: hsl(0 0% 88%);
66+
--color-neutral-content: hsl(0 0% 10%);
67+
68+
--color-info: hsl(198 93% 60%);
69+
--color-info-content: hsl(198 100% 88%);
70+
--color-success: hsl(158 64% 52%);
71+
--color-success-content: hsl(158 100% 88%);
72+
--color-warning: hsl(43 96% 56%);
73+
--color-warning-content: hsl(43 100% 88%);
74+
--color-error: hsl(0 72% 56%);
75+
--color-error-content: hsl(0 0% 100%);
76+
77+
--radius-box: 1.5rem;
78+
--radius-field: 1rem;
79+
--radius-selector: 1rem;
80+
--border: 1px;
81+
--depth: 1;
82+
--noise: 0;
83+
}
84+
4885
@theme {
4986
--font-raleway: "Raleway", sans-serif;
5087
--color-cake-red: #d33c44;
@@ -87,6 +124,99 @@
87124
--ss-primary-color: var(--color-cake-blue);
88125
}
89126

127+
/* SlimSelect dark mode overrides */
128+
[data-theme="cakephp-dark"] .ss-main {
129+
--ss-primary-color: #d33c44;
130+
--ss-bg-color: hsl(0 0% 13%);
131+
--ss-font-color: hsl(0 0% 88%);
132+
--ss-border-color: hsl(0 0% 22%);
133+
--ss-highlight-color: hsl(0 0% 17%);
134+
--ss-spinner-color: hsl(0 0% 88%);
135+
}
136+
137+
[data-theme="cakephp-dark"] [data-is-php-filter] + .ss-main {
138+
--ss-primary-color: var(--color-cake-blue);
139+
}
140+
141+
[data-theme="cakephp-dark"] .ss-content {
142+
background: hsl(0 0% 13%);
143+
border-color: hsl(0 0% 22%);
144+
}
145+
146+
[data-theme="cakephp-dark"] .ss-content .ss-search input {
147+
background: hsl(0 0% 17%);
148+
border-color: hsl(0 0% 22%);
149+
color: hsl(0 0% 88%);
150+
}
151+
152+
[data-theme="cakephp-dark"] .ss-content .ss-list .ss-option {
153+
color: hsl(0 0% 80%);
154+
}
155+
156+
[data-theme="cakephp-dark"] .ss-content .ss-list .ss-option:hover,
157+
[data-theme="cakephp-dark"] .ss-content .ss-list .ss-option.ss-highlighted {
158+
background: hsl(0 0% 17%);
159+
color: hsl(0 0% 88%);
160+
}
161+
162+
[data-theme="cakephp-dark"] .ss-content .ss-list .ss-option.ss-selected {
163+
color: #d33c44;
164+
background: hsl(0 0% 17%);
165+
}
166+
167+
[data-theme="cakephp-dark"] .ss-content .ss-list .ss-option.ss-disabled {
168+
color: hsl(0 0% 35%);
169+
}
170+
171+
[data-theme="cakephp-dark"] .ss-single-selected {
172+
background: hsl(0 0% 13%);
173+
border-color: hsl(0 0% 22%);
174+
color: hsl(0 0% 88%);
175+
}
176+
177+
[data-theme="cakephp-dark"] .ss-single-selected .ss-arrow span {
178+
border-color: hsl(0 0% 60%);
179+
}
180+
181+
[data-theme="cakephp-dark"] .ss-multi-selected {
182+
background: hsl(0 0% 13%);
183+
border-color: hsl(0 0% 22%);
184+
color: hsl(0 0% 88%);
185+
}
186+
187+
[data-theme="cakephp-dark"] .ss-multi-selected .ss-values .ss-value {
188+
background: hsl(0 0% 22%);
189+
color: hsl(0 0% 88%);
190+
}
191+
192+
[data-theme="cakephp-dark"] .ss-multi-selected .ss-values .ss-value .ss-value-delete svg path {
193+
fill: hsl(0 0% 60%);
194+
}
195+
196+
[data-theme="cakephp-dark"] .ss-content .ss-list .ss-option[aria-selected="true"] {
197+
background: #d33c44;
198+
color: #fff;
199+
}
200+
201+
/* Dark mode: darker navbar background */
202+
[data-theme="cakephp-dark"] .navbar-top {
203+
background-color: hsl(0 65% 12%) !important;
204+
border-bottom-color: hsl(0 65% 18%) !important;
205+
}
206+
207+
/* Dark mode: placeholder text contrast */
208+
[data-theme="cakephp-dark"] input::placeholder,
209+
[data-theme="cakephp-dark"] textarea::placeholder,
210+
[data-theme="cakephp-dark"] select::placeholder {
211+
color: hsl(0 0% 50%) !important;
212+
opacity: 1;
213+
}
214+
215+
[data-theme="cakephp-dark"] .input input::placeholder {
216+
color: hsl(0 0% 50%) !important;
217+
opacity: 1;
218+
}
219+
90220
.htmx-indicator {
91221
opacity: 1;
92222
transition: opacity 0.2s ease;

templates/element/navbar.php

Lines changed: 49 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
* @var \App\View\AppView $this
66
*/
77
?>
8-
<div class="sticky top-0 z-40 border-b border-cake-red/70 bg-cake-red backdrop-blur-md">
8+
<div class="sticky top-0 z-40 border-b border-cake-red/70 bg-cake-red backdrop-blur-md navbar-top">
99
<div class="navbar container mx-auto px-4 sm:px-6 lg:px-8 gap-5">
1010
<div class="navbar-start">
1111
<div class="flex items-center gap-6">
@@ -31,8 +31,29 @@
3131
</div>
3232
<div class="navbar-end">
3333
<?= $this->element('search') ?>
34+
35+
<!-- Theme toggle -->
36+
<button type="button"
37+
id="theme-toggle"
38+
class="btn btn-ghost btn-circle hover:bg-white/10 text-white hidden lg:flex ml-2"
39+
aria-label="<?= __('Toggle theme') ?>"
40+
x-data="{ dark: document.documentElement.getAttribute('data-theme') === 'cakephp-dark' }"
41+
@click="
42+
dark = !dark;
43+
document.documentElement.setAttribute('data-theme', dark ? 'cakephp-dark' : 'cakephp');
44+
localStorage.setItem('theme', dark ? 'cakephp-dark' : 'cakephp');
45+
"
46+
>
47+
<svg x-show="!dark" xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true">
48+
<path stroke-linecap="round" stroke-linejoin="round" d="M21.752 15.002A9.72 9.72 0 0 1 18 15.75c-5.385 0-9.75-4.365-9.75-9.75 0-1.33.266-2.597.748-3.752A9.753 9.753 0 0 0 3 11.25C3 16.635 7.365 21 12.75 21a9.753 9.753 0 0 0 9.002-5.998Z" />
49+
</svg>
50+
<svg x-show="dark" xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true" style="display: none;">
51+
<path stroke-linecap="round" stroke-linejoin="round" d="M12 3v2.25m6.364.386-1.591 1.591M21 12h-2.25m-.386 6.364-1.591-1.591M12 18.75V21m-4.773-4.227-1.591 1.591M5.25 12H3m4.227-4.773L5.636 5.636M15.75 12a3.75 3.75 0 1 1-7.5 0 3.75 3.75 0 0 1 7.5 0Z" />
52+
</svg>
53+
</button>
54+
3455
<?php if ($this->Identity->isLoggedIn()) : ?>
35-
<div class="ml-4 dropdown dropdown-end">
56+
<div class="ml-2 dropdown dropdown-end">
3657
<label tabindex="0" class="btn btn-ghost btn-circle avatar cursor-pointer" aria-label="<?= __('User menu') ?>">
3758
<div class="w-9 rounded-full ring-2 ring-white/30 overflow-hidden">
3859
<?= $this->User->avatar(80, ['class' => 'w-full h-full object-cover']) ?>
@@ -59,7 +80,7 @@
5980
</ul>
6081
</div>
6182
<?php else : ?>
62-
<div class="hidden lg:block lg:ml-4">
83+
<div class="hidden lg:block lg:ml-2">
6384
<?= $this->Form->postLink(
6485
'<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4" viewBox="0 0 24 24" fill="currentColor"><path d="M12 0C5.37 0 0 5.37 0 12c0 5.31 3.435 9.795 8.205 11.385.6.105.825-.255.825-.57 0-.285-.015-1.23-.015-2.235-3.015.555-3.795-.735-4.035-1.41-.135-.345-.72-1.41-1.23-1.695-.42-.225-1.02-.78-.015-.795.945-.015 1.62.87 1.845 1.23 1.08 1.815 2.805 1.305 3.495.99.105-.78.42-1.305.765-1.605-2.67-.3-5.46-1.335-5.46-5.925 0-1.305.465-2.385 1.23-3.225-.12-.3-.54-1.53.12-3.18 0 0 1.005-.315 3.3 1.23.96-.27 1.98-.405 3-.405s2.04.135 3 .405c2.295-1.56 3.3-1.23 3.3-1.23.66 1.65.24 2.88.12 3.18.765.84 1.23 1.905 1.23 3.225 0 4.605-2.805 5.625-5.475 5.925.435.375.81 1.095.81 2.22 0 1.605-.015 2.895-.015 3.3 0 .315.225.69.825.57A12.02 12.02 0 0 0 24 12c0-6.63-5.37-12-12-12z"/></svg> Sign in'
6586
,
@@ -72,7 +93,7 @@
7293
'?' => ['redirect' => $this->request->getQuery('redirect')],
7394
],
7495
[
75-
'class' => 'btn btn-sm bg-white/10 text-white hover:bg-white/25 gap-2',
96+
'class' => 'btn btn-sm bg-white/10 text-white hover:bg-white/25 gap-2 whitespace-nowrap',
7697
'escape' => false,
7798
],
7899
) ?>
@@ -105,6 +126,30 @@
105126
) ?>
106127
</li>
107128
<?php endif; ?>
129+
<li class="border-t border-base-300">
130+
<button type="button"
131+
id="theme-toggle-mobile"
132+
class="flex items-center gap-2"
133+
x-data="{ dark: document.documentElement.getAttribute('data-theme') === 'cakephp-dark' }"
134+
@click="
135+
dark = !dark;
136+
document.documentElement.setAttribute('data-theme', dark ? 'cakephp-dark' : 'cakephp');
137+
localStorage.setItem('theme', dark ? 'cakephp-dark' : 'cakephp');
138+
"
139+
>
140+
<template x-if="!dark">
141+
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
142+
<path stroke-linecap="round" stroke-linejoin="round" d="M21.752 15.002A9.72 9.72 0 0 1 18 15.75c-5.385 0-9.75-4.365-9.75-9.75 0-1.33.266-2.597.748-3.752A9.753 9.753 0 0 0 3 11.25C3 16.635 7.365 21 12.75 21a9.753 9.753 0 0 0 9.002-5.998Z" />
143+
</svg>
144+
</template>
145+
<template x-if="dark">
146+
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
147+
<path stroke-linecap="round" stroke-linejoin="round" d="M12 3v2.25m6.364.386-1.591 1.591M21 12h-2.25m-.386 6.364-1.591-1.591M12 18.75V21m-4.773-4.227-1.591 1.591M5.25 12H3m4.227-4.773L5.636 5.636M15.75 12a3.75 3.75 0 1 1-7.5 0 3.75 3.75 0 0 1 7.5 0Z" />
148+
</svg>
149+
</template>
150+
<span x-text="dark ? 'Light mode' : 'Dark mode'"></span>
151+
</button>
152+
</li>
108153
</ul>
109154
</div>
110155
</div>

templates/element/search.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@
3535
}
3636
?>
3737
<div class="w-full" x-data="packageSearch" @click.outside="close()" @keydown="onKeydown($event)">
38-
<label class="input w-full bg-white text-base-content">
38+
<label class="input w-full bg-base-100 text-base-content">
3939
<svg class="h-4 w-4 shrink-0 opacity-60" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" aria-hidden="true">
4040
<g stroke-linejoin="round" stroke-linecap="round" stroke-width="2.5" fill="none" stroke="currentColor">
4141
<circle cx="11" cy="11" r="8"></circle>

templates/layout/default.php

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
$canonicalUrl = $this->Url->build($request->getPath() ?: '/', ['fullBase' => true]);
2020
?>
2121
<!DOCTYPE html>
22-
<html class="bg-base-100">
22+
<html class="bg-base-100" data-theme="cakephp">
2323
<head>
2424
<?= $this->Html->charset() ?>
2525
<meta name="viewport" content="width=device-width, initial-scale=1">
@@ -32,6 +32,15 @@
3232
<?php if ($request->getQueryParams() !== []) : ?>
3333
<meta name="robots" content="noindex,nofollow">
3434
<?php endif; ?>
35+
<script>
36+
(function() {
37+
var theme = localStorage.getItem('theme');
38+
if (!theme) {
39+
theme = matchMedia('(prefers-color-scheme: dark)').matches ? 'cakephp-dark' : 'cakephp';
40+
}
41+
document.documentElement.setAttribute('data-theme', theme);
42+
})();
43+
</script>
3544

3645
<?= $this->Html->css(['cake']) ?>
3746

0 commit comments

Comments
 (0)