[FEATURE] Dark Theme
This commit is contained in:
@@ -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();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user