Skip to content

Conversation

@miaohf
Copy link

@miaohf miaohf commented Nov 30, 2025

  • This PR is not from my main or master branch 💩, but a separate branch ✅
  • Each commit has a valid ✒️ Signed-off-by: <my@email.address> row (via git commit --signoff)
  • Each commit and PR title has a valid 📝 <package name>: title first line subject for packages
  • Incremented 🆙 any PKG_VERSION in the Makefile
  • Tested on: (OpenWrt 24.10.4, MT798x (Xiaomi Router), Chrome Version 142.0.7444.59 (Official Build) (64-bit)) ✅
  • ( Preferred ) Mention: @ the original code author for feedback
  • ( Preferred ) Screenshot or mp4 of changes:
  • ( Optional ) Closes: e.g. openwrt/luci#issue-number
  • ( Optional ) Depends on: e.g. openwrt/packages#pr-number in sister repo
  • Description: (describe the changes proposed in this PR)

Description

Add dark mode support to luci-theme-openwrt theme.

Features

  • 🌙 Dark Mode Toggle: Click the 🌙/☀️ button in the top menu bar to switch between light and dark modes
  • 🔄 System Preference Detection: Automatically follows the system's dark mode preference on first visit
  • 💾 Persistent Preference: User's choice is saved to localStorage and persists across sessions
  • 📊 Full Coverage: Dark mode applies to all standard LuCI pages including:
    • Main navigation and content areas
    • Forms, inputs, buttons, and dropdowns
    • Tables and data displays
    • Real-time graphs (System Load, Bandwidth, Wireless, etc.)
    • Channel Analysis page
    • Page loading transitions

Implementation

  • Uses CSS custom properties (variables) for theming
  • Grayscale color palette for dark mode (no blue tint)
  • Early initialization script in <head> to prevent flash of light mode
  • Minimal changes to existing code structure

Files Changed

  • cascade.css - Added CSS variables and dark mode style overrides
  • header.ut - Added dark mode toggle button and early initialization script
  • menu-openwrt.js - Added dark mode toggle logic and localStorage handling
  • README.md - Added documentation for dark mode feature

Screenshots

Dark Mode:

image]

Light Mode:

[image]

Toggle Button:

image

Testing

  • Tested on: ImmortalWrt 24.10.4, x86_64, Chrome
  • Verified dark mode toggle functionality
  • Verified system preference detection
  • Verified persistence across page reloads
  • Verified all major LuCI pages render correctly in dark mode

- Add CSS variables for theming
- Add dark mode toggle button in header
- Support automatic system preference detection
- Save user preference to localStorage

Signed-off-by: Miao,Haifeng <miaohf@sina.com>
Signed-off-by: miaohf <miaohf@sina.com>
@miaohf miaohf force-pushed the miaohaifeng-20251130 branch from d4f3bbc to 7610677 Compare November 30, 2025 09:02
@hnyman hnyman requested a review from jow- November 30, 2025 09:14
@miaohf miaohf closed this Nov 30, 2025
@miaohf miaohf reopened this Nov 30, 2025
@miaohf
Copy link
Author

miaohf commented Nov 30, 2025

comment message updated.

@Neustradamus
Copy link

@miaohf: Good job, thanks!
More and more people would like Dark mode (dark theme) in projects/softwares.

@hnyman
Copy link
Contributor

hnyman commented Dec 4, 2025

More and more people would like Dark mode

That is actually pretty funny for a guy who has started computing in the era of "only dark mode available", as computer monitors were only CRTs with black background and green or yellow dots on the 80x24 monitor screen.

isDark = prefersDark;
}

this.updateDarkModeUI(isDark, icon);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

	let isDark = savedMode === null ? media.matches : (savedMode === 'true');

	const setMode = (dark, save=false) => {
		document.documentElement.setAttribute('data-darkmode', dark);
		if (save)
			localStorage.setItem('luci-darkmode', dark);
		this.updateDarkModeUI(dark, icon);
	};
	setMode(isDark);


// Get saved preference or detect system preference
const savedMode = localStorage.getItem('luci-darkmode');
const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

const media = window.matchMedia('(prefers-color-scheme: dark)');

if (localStorage.getItem('luci-darkmode') === null) {
this.updateDarkModeUI(e.matches, icon);
}
});
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

	toggle.addEventListener('click', () => {
		const next = document.documentElement.getAttribute('data-darkmode') !== 'true';
		setMode(next, true);
	});

	// Change when user has not set a preference
	media.addEventListener('change', e => {
		if (localStorage.getItem('luci-darkmode') === null)
			setMode(e.matches);
	});

@miaohf
Copy link
Author

miaohf commented Dec 31, 2025

:)

@systemcrash
Copy link
Contributor

@miaohf

1 - remove the merge commit - just rebase on master
2 - fix your SoB line
3 - squash your commits

@systemcrash
Copy link
Contributor

The network interface header names need adjusting because the white text on bright backgrounds are illegible. Same in firewall.

Screenshot 2026-01-03 at 17 42 18 Screenshot 2026-01-03 at 17 41 58

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants