[FEATURE] Dark Theme
This commit is contained in:
@@ -24,16 +24,6 @@ public final class DialectTheme {
|
||||
private static final String FONT_FAMILY =
|
||||
"'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif";
|
||||
|
||||
/**
|
||||
* Mirrors {@code --dialect-border} in styles.css. Charts render via JS/SVG,
|
||||
* not CSS, so this can't read the custom property directly — keep both in sync
|
||||
* by hand if the token changes.
|
||||
*/
|
||||
private static final String BORDER_COLOR = "#E6EAF0";
|
||||
|
||||
/** Mirrors {@code --dialect-ink} in styles.css. See {@link #BORDER_COLOR} note. */
|
||||
private static final String INK_COLOR = "#14171F";
|
||||
|
||||
private DialectTheme() {
|
||||
}
|
||||
|
||||
@@ -50,20 +40,13 @@ public final class DialectTheme {
|
||||
|
||||
options.put("colors", COLORS);
|
||||
|
||||
options.put("grid", Map.of(
|
||||
"borderColor", BORDER_COLOR,
|
||||
"strokeDashArray", 4
|
||||
));
|
||||
|
||||
options.put("legend", Map.of(
|
||||
"position", "bottom",
|
||||
"labels", Map.of("colors", INK_COLOR)
|
||||
));
|
||||
|
||||
// grid.borderColor, legend.labels.colors and tooltip.theme are theme-varying
|
||||
// (light vs. dark) and get overlaid client-side from the --dialect-* CSS
|
||||
// tokens — see applyThemeOverlay() in apex-chart.ts.
|
||||
options.put("grid", Map.of("strokeDashArray", 4));
|
||||
options.put("legend", Map.of("position", "bottom"));
|
||||
options.put("dataLabels", Map.of("enabled", false));
|
||||
|
||||
options.put("tooltip", Map.of("theme", "light"));
|
||||
|
||||
if ("line".equals(chartType)) {
|
||||
options.put("stroke", Map.of("curve", "smooth", "width", 3));
|
||||
} else if ("bar".equals(chartType)) {
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
package com.example.js;
|
||||
|
||||
public final class CommonJS {
|
||||
|
||||
private CommonJS() {}
|
||||
|
||||
/** Sets color-scheme on <html> from the saved choice, falling back to the OS
|
||||
* preference (prefers-color-scheme) when no choice was saved, and
|
||||
* returns "light"/"dark" so the button's initial icon can match. */
|
||||
public static final String INIT_THEME_JS = """
|
||||
const saved = localStorage.getItem('dialect-theme');
|
||||
const theme = saved
|
||||
|| (window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light');
|
||||
document.documentElement.style.colorScheme = theme;
|
||||
return theme;
|
||||
""";
|
||||
|
||||
public static final String TOGGLE_THEME_JS = """
|
||||
const next = document.documentElement.style.colorScheme === 'dark' ? 'light' : 'dark';
|
||||
document.documentElement.style.colorScheme = next;
|
||||
localStorage.setItem('dialect-theme', next);
|
||||
window.dispatchEvent(new CustomEvent('dialect-theme-change'));
|
||||
return next;
|
||||
""";
|
||||
}
|
||||
@@ -1,7 +1,10 @@
|
||||
package com.example.views;
|
||||
|
||||
import com.example.js.CommonJS;
|
||||
import com.vaadin.flow.component.applayout.AppLayout;
|
||||
import com.vaadin.flow.component.applayout.DrawerToggle;
|
||||
import com.vaadin.flow.component.button.Button;
|
||||
import com.vaadin.flow.component.button.ButtonVariant;
|
||||
import com.vaadin.flow.component.html.Span;
|
||||
import com.vaadin.flow.component.icon.VaadinIcon;
|
||||
import com.vaadin.flow.component.sidenav.SideNav;
|
||||
@@ -11,13 +14,25 @@ import com.vaadin.flow.router.Layout;
|
||||
@Layout
|
||||
public class MainLayout extends AppLayout {
|
||||
|
||||
private final Button themeToggle = new Button(VaadinIcon.MOON.create());
|
||||
|
||||
public MainLayout() {
|
||||
DrawerToggle toggle = new DrawerToggle();
|
||||
|
||||
Span title = new Span("Chart App");
|
||||
title.addClassName("dialect-title");
|
||||
|
||||
addToNavbar(toggle, title);
|
||||
Span spacer = new Span();
|
||||
spacer.getStyle().set("flex-grow", "1");
|
||||
|
||||
themeToggle.addThemeVariants(ButtonVariant.TERTIARY, ButtonVariant.LUMO_ICON);
|
||||
themeToggle.setAriaLabel("Farbschema wechseln");
|
||||
themeToggle.addClickListener(e ->
|
||||
getElement().executeJs(CommonJS.TOGGLE_THEME_JS).then(String.class, this::applyIconFor));
|
||||
|
||||
addToNavbar(toggle, title, spacer, themeToggle);
|
||||
|
||||
getElement().executeJs(CommonJS.INIT_THEME_JS).then(String.class, this::applyIconFor);
|
||||
|
||||
SideNav nav = new SideNav();
|
||||
nav.addItem(new SideNavItem("Dashboard", DashboardView.class,
|
||||
@@ -27,4 +42,8 @@ public class MainLayout extends AppLayout {
|
||||
|
||||
addToDrawer(nav);
|
||||
}
|
||||
|
||||
private void applyIconFor(String theme) {
|
||||
themeToggle.setIcon("dark".equals(theme) ? VaadinIcon.SUN_O.create() : VaadinIcon.MOON.create());
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user