UI Customize: add custom-theme flag for default theme (#33042)
This commit is contained in:
parent
eeb2f593bf
commit
a8c4dfd372
7 changed files with 50 additions and 1 deletions
|
|
@ -9,7 +9,7 @@ export function getThemePreference(): THEME | null {
|
|||
if (theme && Object.values(THEME).includes(theme)) {
|
||||
return theme;
|
||||
}
|
||||
return THEME.AUTO;
|
||||
return window.evcc?.customTheme || THEME.AUTO;
|
||||
}
|
||||
|
||||
export function setThemePreference(theme: THEME) {
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ declare global {
|
|||
customWebsite: string;
|
||||
customEmail: string;
|
||||
customPhone: string;
|
||||
customTheme: THEME;
|
||||
};
|
||||
}
|
||||
interface Window {
|
||||
|
|
|
|||
|
|
@ -46,6 +46,9 @@ const (
|
|||
flagCustomPhone = "custom-phone"
|
||||
flagCustomPhoneDescription = "Support phone number shown in the UI"
|
||||
|
||||
flagCustomTheme = "custom-theme"
|
||||
flagCustomThemeDescription = "Default UI theme (auto, light, dark). Users can override in the UI."
|
||||
|
||||
flagBatteryMode = "battery-mode"
|
||||
flagBatteryModeDescription = "Set battery mode (normal, hold, charge, holdcharge)"
|
||||
flagBatteryModeWait = "battery-mode-wait"
|
||||
|
|
|
|||
|
|
@ -113,6 +113,7 @@ func init() {
|
|||
rootCmd.Flags().StringVar(&customization.Website, flagCustomWebsite, os.Getenv("EVCC_CUSTOM_WEBSITE"), flagCustomWebsiteDescription)
|
||||
rootCmd.Flags().StringVar(&customization.Email, flagCustomEmail, os.Getenv("EVCC_CUSTOM_EMAIL"), flagCustomEmailDescription)
|
||||
rootCmd.Flags().StringVar(&customization.Phone, flagCustomPhone, os.Getenv("EVCC_CUSTOM_PHONE"), flagCustomPhoneDescription)
|
||||
rootCmd.Flags().StringVar(&customization.Theme, flagCustomTheme, os.Getenv("EVCC_CUSTOM_THEME"), flagCustomThemeDescription)
|
||||
}
|
||||
|
||||
// initConfig reads in config file and ENV variables if set
|
||||
|
|
|
|||
|
|
@ -55,6 +55,7 @@ type Customization struct {
|
|||
Website string
|
||||
Email string
|
||||
Phone string
|
||||
Theme string
|
||||
}
|
||||
|
||||
// NewHTTPd creates HTTP server with configured routes for loadpoint
|
||||
|
|
@ -112,6 +113,12 @@ func NewHTTPd(addr string, hub *SocketHub, custom Customization) *HTTPd {
|
|||
log.FATAL.Fatal("custom logo requires both light and dark variants")
|
||||
}
|
||||
|
||||
switch custom.Theme {
|
||||
case "", "auto", "light", "dark":
|
||||
default:
|
||||
log.FATAL.Fatalf("invalid custom theme: %s (expected auto, light, dark)", custom.Theme)
|
||||
}
|
||||
|
||||
for path, file := range map[string]string{
|
||||
"/custom-logo-light": custom.LogoLight,
|
||||
"/custom-logo-dark": custom.LogoDark,
|
||||
|
|
|
|||
|
|
@ -59,6 +59,7 @@ func globalsJsHandler(custom Customization) http.HandlerFunc {
|
|||
Website string `json:"customWebsite"`
|
||||
Email string `json:"customEmail"`
|
||||
Phone string `json:"customPhone"`
|
||||
Theme string `json:"customTheme"`
|
||||
}{
|
||||
Version: util.Version,
|
||||
CustomCss: custom.Css != "",
|
||||
|
|
@ -67,6 +68,7 @@ func globalsJsHandler(custom Customization) http.HandlerFunc {
|
|||
Website: custom.Website,
|
||||
Email: custom.Email,
|
||||
Phone: custom.Phone,
|
||||
Theme: custom.Theme,
|
||||
}
|
||||
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
|
|
|
|||
35
tests/theme.spec.ts
Normal file
35
tests/theme.spec.ts
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
import { test, expect } from "@playwright/test";
|
||||
import { start, stop, baseUrl } from "./evcc";
|
||||
import { openMoreMenu, expectModalVisible } from "./utils";
|
||||
|
||||
test.use({ baseURL: baseUrl() });
|
||||
|
||||
test.beforeAll(async () => {
|
||||
await start("basics.evcc.yaml", null, ["--disable-auth", "--custom-theme", "dark"]);
|
||||
});
|
||||
|
||||
test.afterAll(async () => {
|
||||
await stop();
|
||||
});
|
||||
|
||||
test.describe("custom theme", async () => {
|
||||
test("starts dark, user choice wins and survives reload", async ({ page }) => {
|
||||
await page.goto("/");
|
||||
await expect(page.locator("html")).toHaveAttribute("data-bs-theme", "dark");
|
||||
|
||||
const menu = await openMoreMenu(page);
|
||||
await menu.getByRole("button", { name: "User Interface" }).click();
|
||||
const modal = page.getByTestId("global-settings-modal");
|
||||
await expectModalVisible(modal);
|
||||
await expect(modal.getByRole("radio", { name: "dark" })).toHaveAttribute(
|
||||
"aria-checked",
|
||||
"true"
|
||||
);
|
||||
|
||||
await modal.getByRole("radio", { name: "light" }).click();
|
||||
await expect(page.locator("html")).toHaveAttribute("data-bs-theme", "light");
|
||||
|
||||
await page.reload();
|
||||
await expect(page.locator("html")).toHaveAttribute("data-bs-theme", "light");
|
||||
});
|
||||
});
|
||||
Loading…
Add table
Add a link
Reference in a new issue