Handles dark mode by enables CSS transitions to avoid flashing, automatically switching based on OS preference and check for time range (if enabled Eg. 6pm-6am) as a fallback every minute.
Note: It’s better if added the ‘API’ module to your CMS, else you need to include the drkmd.js script manually.
| File | Folder Link |
|---|---|
| default.css | \\SYNAS\Allan\DOCUMENTATION\Component\Dark Mode\rckuc\public\themes\rckuc\css |
| All .js | \\SYNAS\Allan\DOCUMENTATION\Component\Dark Mode\rckuc\public\themes\rckuc\js |
| SettingController.php | \\SYNAS\Allan\DOCUMENTATION\Component\Dark Mode\rckuc\wolf\app\controllers |
Update: All Layout in your wolf CMS
// Include the drkmd.js script in every layout just before the closing </body> tag:
<?php $dark_mode = ModuleSetting::findSetting('page', 'Dark Mode by OS Preference'); ?>
<script src="<?php echo THEME_PATH ?>js/drkmd-js.min-1.0.12.js"
data-drkmd-attach
data-drkmd-opts='<?php echo json_encode([
"localStorage" => false,
"cookie" => false,
"autoMatchOsTheme" => ($dark_mode == 1) ? true : false
]); ?>'>
</script>
// Note: Adding 'data-drkmd-attach' inside your script link to show a dark mode toggle button for developer testing purpose, remove it after testing.
// Or if you have 'API' module, insert this sql record in database:
INSERT INTO `wolf_api` (`id`, `name`, `description`, `all_page_status`, `page_id`, `section`, `code`, `status`, `sequence`, `created_on`, `updated_on`, `created_by_id`, `updated_by_id`) VALUES (NULL, 'Dark Mode', NULL, '1', NULL, 'body_end', '<?php $dark_mode = ModuleSetting::findSetting('page', 'Dark Mode by OS Preference'); ?>
<script src="<?php echo THEME_PATH ?>js/drkmd-js.min-1.0.12.js"
data-drkmd-attach
data-drkmd-opts='<?php echo json_encode([
"localStorage" => false,
"cookie" => false,
"autoMatchOsTheme" => ($dark_mode == 1) ? true : false
]); ?>'>
</script>', '1', NULL, NULL, NULL, NULL, NULL);
// Include the drkmd.js script in every layout just before the closing </body> tag:
<?php $dark_mode = ModuleSetting::findSetting('page', 'Dark Mode by OS Preference'); ?>
<script src="<?php echo THEME_PATH ?>js/drkmd-js.min-1.0.12.js"
data-drkmd-attach
data-drkmd-opts='<?php echo json_encode([
"localStorage" => false,
"cookie" => false,
"autoMatchOsTheme" => ($dark_mode == 1) ? true : false
]); ?>'>
</script>
// Note: Adding 'data-drkmd-attach' inside your script link to show a dark mode toggle button for developer testing purpose, remove it after testing.
// Or if you have 'API' module, insert this sql record in database:
INSERT INTO `wolf_api` (`id`, `name`, `description`, `all_page_status`, `page_id`, `section`, `code`, `status`, `sequence`, `created_on`, `updated_on`, `created_by_id`, `updated_by_id`) VALUES (NULL, 'Dark Mode', NULL, '1', NULL, 'body_end', '<?php $dark_mode = ModuleSetting::findSetting('page', 'Dark Mode by OS Preference'); ?>
<script src="<?php echo THEME_PATH ?>js/drkmd-js.min-1.0.12.js"
data-drkmd-attach
data-drkmd-opts='<?php echo json_encode([
"localStorage" => false,
"cookie" => false,
"autoMatchOsTheme" => ($dark_mode == 1) ? true : false
]); ?>'>
</script>', '1', NULL, NULL, NULL, NULL, NULL);
Update: default.css
Adjust the CSS root color settings to match your website design; here are some example adjustments:
Key Feature:
/* ---------- drkmd.js ---------- */
/* Background Color:
body → #121212
section → #1e1e1e
sub-section → #212121
card → #242424
*/
/* Change Root Setting here */
.theme-dark {
--bg-color-blue: #1a70d1;
}
.theme-ready,
.theme-ready #header-holder,
.theme-ready #search_form,
.theme-ready #venue-zone,
.theme-ready #highlights,
.theme-ready #footer,
.theme-ready #menu > #menulist > li > .thumb,
.theme-ready #donate-zone,
.theme-ready .breadcrumb,
.theme-ready #president-message,
.theme-ready #quotes,
.theme-ready #ry-menu,
.theme-ready #search_box,
.theme-ready #search_box::placeholder,
.theme-ready #search_form button img,
.theme-ready #whatsapp,
.theme-ready img.bg-light,
.theme-ready img.bg-dark {
/* For animation transition purpose only */
transition: opacity 1s ease, background-color 1s ease, color 1s ease, border-color 1s ease, filter 1s ease, background-image 1s ease, background-size 1s ease;
}
/* ----- Title ----- */
.theme-dark h1,
.theme-dark h2,
.theme-dark h3,
.theme-dark h4,
.theme-dark h5,
.theme-dark h6 {
color: #1a70d1;
}
/* ----- Background Color → body ----- */
body.theme-dark {
background: #121212;
color: #e5e5e5;
}
.theme-dark #header-holder {
border-bottom-color: #121212;
}
/* ----- Background Color → section ----- */
.theme-dark #header-holder,
.theme-dark #highlights,
.theme-dark #menu > #menulist > li > .thumb,
.theme-dark #menu ul ul a,
.theme-dark #footer {
background: #121212;
}
/* ----- Background Color → sub-section ----- */
.theme-dark #search_form,
.theme-dark .breadcrumb,
.theme-dark #venue-zone,
.theme-dark #president-message,
.theme-dark #ry-menu {
background: #1e1e1e;
}
/* ----- Background Color → card ----- */
.theme-dark #donate-zone,
.theme-dark #quotes {
background: #212121;
}
/* ----- search box ----- */
.theme-dark #search_box {
background: #242424;
border-color: #242424;
}
.theme-dark #search_box::placeholder {
color: #e5e5e5;
}
/* ----- Example to filter black image to white ----- */
.theme-dark #search_form button img {
filter: invert(1);
}
/* ----- <img class="bg-dark"> ----- */
.theme-dark img.bg-light {
display: none !important;
}
.theme-light img.bg-dark {
display: none !important;
}
/* ----- css replace background-image ----- */
.theme-dark #whatsapp {
background-color: white;
background-size: 2.5rem;
background-position: center;
background-image: url(themes/icon-whatsapp-dark.png);
}
/* ----- menu ----- */
.theme-dark #menu #menulist > li > a {
color: #1a70d1;
}
.theme-dark #menu #menulist > li > a:hover,
.theme-dark #menu #menulist > li ul > li > a:hover {
color: #d89b3a !important;
}
/* ----- hyper link ----- */
.theme-dark #menu a.active,
.theme-dark .copyright a,
.theme-dark #footer #webdesign a {
color: #d89b3a !important;
}
/* ----- button -----*/
.theme-dark .btn-blue,
.theme-dark a.btn-blue {
background-color: #1a70d1;
color: #d89b3a;
}
.theme-dark .btn-blue:hover,
.theme-dark a.btn-blue:hover {
color: white;
background-color: #d89b3a;
}
/* ---------- drkmd.js ---------- */
/* Background Color:
body → #121212
section → #1e1e1e
sub-section → #212121
card → #242424
*/
/* Change Root Setting here */
.theme-dark {
--bg-color-blue: #1a70d1;
}
.theme-ready,
.theme-ready #header-holder,
.theme-ready #search_form,
.theme-ready #venue-zone,
.theme-ready #highlights,
.theme-ready #footer,
.theme-ready #menu > #menulist > li > .thumb,
.theme-ready #donate-zone,
.theme-ready .breadcrumb,
.theme-ready #president-message,
.theme-ready #quotes,
.theme-ready #ry-menu,
.theme-ready #search_box,
.theme-ready #search_box::placeholder,
.theme-ready #search_form button img,
.theme-ready #whatsapp,
.theme-ready img.bg-light,
.theme-ready img.bg-dark {
/* For animation transition purpose only */
transition: opacity 1s ease, background-color 1s ease, color 1s ease, border-color 1s ease, filter 1s ease, background-image 1s ease, background-size 1s ease;
}
/* ----- Title ----- */
.theme-dark h1,
.theme-dark h2,
.theme-dark h3,
.theme-dark h4,
.theme-dark h5,
.theme-dark h6 {
color: #1a70d1;
}
/* ----- Background Color → body ----- */
body.theme-dark {
background: #121212;
color: #e5e5e5;
}
.theme-dark #header-holder {
border-bottom-color: #121212;
}
/* ----- Background Color → section ----- */
.theme-dark #header-holder,
.theme-dark #highlights,
.theme-dark #menu > #menulist > li > .thumb,
.theme-dark #menu ul ul a,
.theme-dark #footer {
background: #121212;
}
/* ----- Background Color → sub-section ----- */
.theme-dark #search_form,
.theme-dark .breadcrumb,
.theme-dark #venue-zone,
.theme-dark #president-message,
.theme-dark #ry-menu {
background: #1e1e1e;
}
/* ----- Background Color → card ----- */
.theme-dark #donate-zone,
.theme-dark #quotes {
background: #212121;
}
/* ----- search box ----- */
.theme-dark #search_box {
background: #242424;
border-color: #242424;
}
.theme-dark #search_box::placeholder {
color: #e5e5e5;
}
/* ----- Example to filter black image to white ----- */
.theme-dark #search_form button img {
filter: invert(1);
}
/* ----- <img class="bg-dark"> ----- */
.theme-dark img.bg-light {
display: none !important;
}
.theme-light img.bg-dark {
display: none !important;
}
/* ----- css replace background-image ----- */
.theme-dark #whatsapp {
background-color: white;
background-size: 2.5rem;
background-position: center;
background-image: url(themes/icon-whatsapp-dark.png);
}
/* ----- menu ----- */
.theme-dark #menu #menulist > li > a {
color: #1a70d1;
}
.theme-dark #menu #menulist > li > a:hover,
.theme-dark #menu #menulist > li ul > li > a:hover {
color: #d89b3a !important;
}
/* ----- hyper link ----- */
.theme-dark #menu a.active,
.theme-dark .copyright a,
.theme-dark #footer #webdesign a {
color: #d89b3a !important;
}
/* ----- button -----*/
.theme-dark .btn-blue,
.theme-dark a.btn-blue {
background-color: #1a70d1;
color: #d89b3a;
}
.theme-dark .btn-blue:hover,
.theme-dark a.btn-blue:hover {
color: white;
background-color: #d89b3a;
}
(Optional) Update: rckuc.js (Only if you want to apply css transition for dark mode and toggle dark mode by time range)
To enable toggleDarkModeByTimeRange() feature, set timeRange such as '6pm-6am' or '7:30pm-8:30am'. Set it to null to disable toggleDarkModeByTimeRange().
In this js file:
We handles dark mode by enables CSS transitions to avoid flashing and check for timeRange (if not null) every minute to toggle dark mode.
// drkmd.js
$(document).ready(function () {
// Add these 3 line of code only if you want CSS transition for dark mode and dont want toggle dark mode by time range
// Enable transitions AFTER initial paint
requestAnimationFrame(() => {
document.body.classList.add('theme-ready');
});
// You can remove the below code or set 'timeRange' to null if you wish to disable toggleDarkModeByTimeRange()
// To check if current OS preference is light
const mediaQuery = window.matchMedia('(prefers-color-scheme: light)');
// Set a time range such as '6pm-6am' or '7:30pm-8:30am'.
let timeRange = '6pm-6am'; // Set to null to disable toggleDarkModeByTimeRange()
let toggle_dark_interval = null;
// Check on page load
if (mediaQuery.matches && timeRange) {
toggleDark();
}
// Check if user change OS theme
mediaQuery.addEventListener('change', (e) => {
if (e.matches && timeRange) {
toggleDark();
} else {
toggle_dark_interval = null;
}
});
// Helper function
function toggleDark() {
if (toggle_dark_interval) return;
// Run once on page load in case the exact minute is already matched
toggleDarkModeByTimeRange(timeRange);
// Check every minute
toggle_dark_interval = setInterval(() => {
toggleDarkModeByTimeRange(timeRange);
}, 60 * 1000);
function toggleDarkModeByTimeRange(timeRangeStr) {
const now = new Date();
const [startStr, endStr] = timeRangeStr.split('-');
function parseTime(tStr) {
const [time, meridian] = tStr.split(/(am|pm)/i);
let [hours, minutes] = time.split(':').map(Number);
if (!minutes) minutes = 0; // if no minutes provided
if (meridian.toLowerCase() === 'pm' && hours < 12) hours += 12;
if (meridian.toLowerCase() === 'am' && hours === 12) hours = 0;
return { hours, minutes };
}
const start = parseTime(startStr);
const end = parseTime(endStr);
const nowMinutes = now.getHours() * 60 + now.getMinutes();
const startMinutes = start.hours * 60 + start.minutes;
const endMinutes = end.hours * 60 + end.minutes;
let isDark = false;
if (startMinutes < endMinutes) {
isDark = nowMinutes >= startMinutes && nowMinutes < endMinutes;
} else {
isDark = nowMinutes >= startMinutes || nowMinutes < endMinutes;
}
if (isDark) {
darkmode.toDark();
}
}
}
})
// drkmd.js
$(document).ready(function () {
// Add these 3 line of code only if you want CSS transition for dark mode and dont want toggle dark mode by time range
// Enable transitions AFTER initial paint
requestAnimationFrame(() => {
document.body.classList.add('theme-ready');
});
// You can remove the below code or set 'timeRange' to null if you wish to disable toggleDarkModeByTimeRange()
// To check if current OS preference is light
const mediaQuery = window.matchMedia('(prefers-color-scheme: light)');
// Set a time range such as '6pm-6am' or '7:30pm-8:30am'.
let timeRange = '6pm-6am'; // Set to null to disable toggleDarkModeByTimeRange()
let toggle_dark_interval = null;
// Check on page load
if (mediaQuery.matches && timeRange) {
toggleDark();
}
// Check if user change OS theme
mediaQuery.addEventListener('change', (e) => {
if (e.matches && timeRange) {
toggleDark();
} else {
toggle_dark_interval = null;
}
});
// Helper function
function toggleDark() {
if (toggle_dark_interval) return;
// Run once on page load in case the exact minute is already matched
toggleDarkModeByTimeRange(timeRange);
// Check every minute
toggle_dark_interval = setInterval(() => {
toggleDarkModeByTimeRange(timeRange);
}, 60 * 1000);
function toggleDarkModeByTimeRange(timeRangeStr) {
const now = new Date();
const [startStr, endStr] = timeRangeStr.split('-');
function parseTime(tStr) {
const [time, meridian] = tStr.split(/(am|pm)/i);
let [hours, minutes] = time.split(':').map(Number);
if (!minutes) minutes = 0; // if no minutes provided
if (meridian.toLowerCase() === 'pm' && hours < 12) hours += 12;
if (meridian.toLowerCase() === 'am' && hours === 12) hours = 0;
return { hours, minutes };
}
const start = parseTime(startStr);
const end = parseTime(endStr);
const nowMinutes = now.getHours() * 60 + now.getMinutes();
const startMinutes = start.hours * 60 + start.minutes;
const endMinutes = end.hours * 60 + end.minutes;
let isDark = false;
if (startMinutes < endMinutes) {
isDark = nowMinutes >= startMinutes && nowMinutes < endMinutes;
} else {
isDark = nowMinutes >= startMinutes || nowMinutes < endMinutes;
}
if (isDark) {
darkmode.toDark();
}
}
}
})
Alternate Images for Dark Mode <img>
To use a different image in dark mode, follow the HTML structure below, add a class 'bg-light' to your original <img>, then add a dark mode <img> with class 'bg-dark'.
Note: It’s better if both images have the same ratio, but it’s not required.
<img class="bg-light" src="https://allan.webdesignkuching.com/rckuc/public/images/love-banner.jpg" />
<img class="bg-dark" src="https://allan.webdesignkuching.com/rckuc/public/images/rotary_cover.webp" />
<img class="bg-light" src="https://allan.webdesignkuching.com/rckuc/public/images/love-banner.jpg" />
<img class="bg-dark" src="https://allan.webdesignkuching.com/rckuc/public/images/rotary_cover.webp" />
Insert SQL Record into wolf_module_setting:
INSERT INTO `wolf_module_setting` (`id`, `module`, `name`, `value_type`, `value`, `created_on`, `updated_on`, `created_by_id`, `updated_by_id`) VALUES (NULL, 'page', 'Dark Mode by OS Preference', 'checkbox', '1', NOW(), NULL, NULL, NULL);
INSERT INTO `wolf_module_setting` (`id`, `module`, `name`, `value_type`, `value`, `created_on`, `updated_on`, `created_by_id`, `updated_by_id`) VALUES (NULL, 'page', 'Dark Mode by OS Preference', 'checkbox', '1', NOW(), NULL, NULL, NULL);
Copy all related files to your project