[FEATURE] Dark Theme

This commit is contained in:
Pit Friedrich
2026-07-11 22:31:08 +02:00
parent aa8fbb4838
commit 9df764d065
7 changed files with 140 additions and 52 deletions
+70 -2
View File
@@ -2,14 +2,78 @@ import { html, LitElement } from 'lit';
import { customElement } from 'lit/decorators.js';
import ApexCharts from 'apexcharts';
/**
* Resolves a CSS custom property (which may be a `light-dark()` value) to its
* currently active value for the given scheme. Reading the custom property
* directly (e.g. via getComputedStyle on an element that just has the var set)
* returns the raw `light-dark(...)` text, not the resolved color — resolution
* only happens when the property is used as an actual style value, hence the
* throwaway probe element.
*/
function resolveColor(varName: string): string {
const probe = document.createElement('span');
probe.style.color = `var(${varName})`;
probe.style.display = 'none';
document.documentElement.appendChild(probe);
const resolved = getComputedStyle(probe).color;
probe.remove();
return resolved;
}
function isDarkScheme(): boolean {
return getComputedStyle(document.documentElement).colorScheme.includes('dark');
}
/** Overlays theme-varying option keys with values resolved from the current
* --dialect-* CSS tokens, so charts follow the light/dark toggle without a
* server round-trip. */
function applyThemeOverlay(options: any): any {
const borderColor = resolveColor('--dialect-border');
const inkColor = resolveColor('--dialect-ink');
const dark = isDarkScheme();
options.grid = { ...options.grid, borderColor };
options.legend = {
...options.legend,
labels: { ...options.legend?.labels, colors: inkColor },
};
options.tooltip = { ...options.tooltip, theme: dark ? 'dark' : 'light' };
if (options.xaxis) {
options.xaxis = {
...options.xaxis,
labels: { ...options.xaxis.labels, style: { ...options.xaxis.labels?.style, colors: inkColor } },
};
}
if (options.yaxis) {
options.yaxis = {
...options.yaxis,
labels: { ...options.yaxis.labels, style: { ...options.yaxis.labels?.style, colors: inkColor } },
};
}
return options;
}
@customElement('apex-chart')
export class ApexChart extends LitElement {
private chart?: ApexCharts;
private lastOptions?: any;
private readonly onThemeChange = () => {
if (!this.chart || !this.lastOptions) return;
this.chart.updateOptions(applyThemeOverlay(this.lastOptions));
};
protected createRenderRoot() {
return this;
}
connectedCallback() {
super.connectedCallback();
window.addEventListener('dialect-theme-change', this.onThemeChange);
}
render() {
return html`<div id="container" style="width:100%;height:100%"></div>`;
}
@@ -27,17 +91,21 @@ export class ApexChart extends LitElement {
},
};
this.lastOptions = options;
const themed = applyThemeOverlay(options);
const container = this.querySelector('#container') as HTMLElement;
if (this.chart) {
await this.chart.updateOptions(options);
await this.chart.updateOptions(themed);
} else {
this.chart = new ApexCharts(container, options);
this.chart = new ApexCharts(container, themed);
await this.chart.render();
}
}
disconnectedCallback() {
super.disconnectedCallback();
window.removeEventListener('dialect-theme-change', this.onThemeChange);
this.chart?.destroy();
}
}