Skip to content

Commit 322a72f

Browse files
author
iexitdev
committed
docs: refresh chart docs and previews
1 parent f7d49a4 commit 322a72f

31 files changed

Lines changed: 1976 additions & 190 deletions

apps/site/astro.config.mjs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,10 @@ export default defineConfig({
7777
sidebar: [
7878
{
7979
label: "Start",
80-
items: [{ slug: "docs/getting-started/installation" }]
80+
items: [
81+
{ slug: "docs/getting-started/installation" },
82+
{ slug: "docs/getting-started/contributing" }
83+
]
8184
},
8285
{
8386
label: "Charts",
Lines changed: 218 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,218 @@
1+
import {
2+
applyChartThemePreset,
3+
chartThemeOptions,
4+
getCurrentChartThemePreset,
5+
isChartThemePreset
6+
} from "./previews/chartTheme";
7+
8+
type ColorTheme = "dark" | "light";
9+
10+
const controlSelector = "[data-chart-theme-control]";
11+
const docsThemeToggleSelector = "[data-docs-theme-toggle]";
12+
const selectSelector = "[data-chart-theme-select]";
13+
const starlightThemeStorageKey = "starlight-theme";
14+
const themeColor = {
15+
dark: "#06070a",
16+
light: "#f7f8fb"
17+
};
18+
19+
const isColorTheme = (value: string | null): value is ColorTheme =>
20+
value === "dark" || value === "light";
21+
22+
const getCurrentColorTheme = (): ColorTheme => {
23+
try {
24+
const stored = localStorage.getItem(starlightThemeStorageKey);
25+
26+
if (isColorTheme(stored)) {
27+
return stored;
28+
}
29+
} catch {
30+
// Storage can be blocked in restricted browser contexts.
31+
}
32+
33+
return document.documentElement.dataset.theme === "light" ? "light" : "dark";
34+
};
35+
36+
const syncStarlightThemeSelects = (theme: ColorTheme) => {
37+
document
38+
.querySelectorAll<HTMLSelectElement>("starlight-theme-select select")
39+
.forEach((select) => {
40+
if (select.value !== theme) {
41+
select.value = theme;
42+
}
43+
});
44+
};
45+
46+
const syncDocsThemeToggles = (theme: ColorTheme) => {
47+
const nextTheme = theme === "dark" ? "light" : "dark";
48+
49+
document
50+
.querySelectorAll<HTMLButtonElement>(docsThemeToggleSelector)
51+
.forEach((button) => {
52+
button.dataset.themeCurrent = theme;
53+
button.dataset.themeNext = nextTheme;
54+
button.setAttribute("aria-label", `Switch to ${nextTheme} mode`);
55+
button.setAttribute("title", `Switch to ${nextTheme} mode`);
56+
});
57+
};
58+
59+
const updateThemeColor = (theme: ColorTheme) => {
60+
const meta = document.querySelector<HTMLMetaElement>(
61+
'meta[name="theme-color"]'
62+
);
63+
64+
if (meta) {
65+
meta.content = themeColor[theme];
66+
}
67+
};
68+
69+
const applyColorTheme = (theme: ColorTheme) => {
70+
document.documentElement.dataset.theme = theme;
71+
document.documentElement.style.colorScheme = theme;
72+
73+
try {
74+
localStorage.setItem(starlightThemeStorageKey, theme);
75+
} catch {
76+
// Persisting the preference is best-effort.
77+
}
78+
79+
syncStarlightThemeSelects(theme);
80+
syncDocsThemeToggles(theme);
81+
updateThemeColor(theme);
82+
window.StarlightThemeProvider?.updatePickers(theme);
83+
};
84+
85+
const syncChartThemeControls = () => {
86+
const theme = getCurrentChartThemePreset();
87+
88+
document
89+
.querySelectorAll<HTMLSelectElement>(selectSelector)
90+
.forEach((select) => {
91+
if (select.value !== theme) {
92+
select.value = theme;
93+
}
94+
});
95+
};
96+
97+
const createChartThemeControl = () => {
98+
const label = document.createElement("label");
99+
label.className = "chartkit-chart-theme-control";
100+
label.dataset.chartThemeControl = "true";
101+
102+
const text = document.createElement("span");
103+
text.className = "chartkit-chart-theme-control__label";
104+
text.textContent = "Chart theme";
105+
106+
const select = document.createElement("select");
107+
select.className = "chartkit-chart-theme-control__select";
108+
select.dataset.chartThemeSelect = "true";
109+
select.setAttribute("aria-label", "Chart theme");
110+
111+
chartThemeOptions.forEach((option) => {
112+
const item = document.createElement("option");
113+
item.value = option.value;
114+
item.textContent = option.label;
115+
select.append(item);
116+
});
117+
118+
label.append(text, select);
119+
120+
return label;
121+
};
122+
123+
const createDocsThemeToggle = () => {
124+
const button = document.createElement("button");
125+
button.className = "chartkit-docs-theme-toggle";
126+
button.dataset.docsThemeToggle = "true";
127+
button.type = "button";
128+
button.innerHTML = `
129+
<svg aria-hidden="true" focusable="false" viewBox="0 0 24 24">
130+
<path d="M12 3a6 6 0 0 0 9 9 9 9 0 1 1-9-9Z"></path>
131+
</svg>
132+
`;
133+
134+
return button;
135+
};
136+
137+
const enhanceThemeSelectors = () => {
138+
document
139+
.querySelectorAll<HTMLElement>("starlight-theme-select")
140+
.forEach((themeSelect) => {
141+
const previousElement = themeSelect.previousElementSibling;
142+
143+
if (!previousElement?.matches(controlSelector)) {
144+
themeSelect.before(createChartThemeControl());
145+
}
146+
147+
if (themeSelect.dataset.chartkitIconToggle !== "true") {
148+
themeSelect.dataset.chartkitIconToggle = "true";
149+
themeSelect.append(createDocsThemeToggle());
150+
}
151+
});
152+
153+
syncChartThemeControls();
154+
syncDocsThemeToggles(getCurrentColorTheme());
155+
};
156+
157+
const handleChartThemeChange = (event: Event) => {
158+
const select = (event.target as Element | null)?.closest<HTMLSelectElement>(
159+
selectSelector
160+
);
161+
162+
if (!select || !isChartThemePreset(select.value)) {
163+
return;
164+
}
165+
166+
applyChartThemePreset(select.value);
167+
syncChartThemeControls();
168+
};
169+
170+
const handleDocsThemeClick = (event: Event) => {
171+
const button = (event.target as Element | null)?.closest<HTMLButtonElement>(
172+
docsThemeToggleSelector
173+
);
174+
175+
if (!button) {
176+
return;
177+
}
178+
179+
const nextTheme = getCurrentColorTheme() === "dark" ? "light" : "dark";
180+
applyColorTheme(nextTheme);
181+
};
182+
183+
const bootChartThemeControls = () => {
184+
enhanceThemeSelectors();
185+
applyChartThemePreset(getCurrentChartThemePreset(), { dispatch: false });
186+
applyColorTheme(getCurrentColorTheme());
187+
188+
if (!window.__chartkitChartThemeControlBound) {
189+
window.__chartkitChartThemeControlBound = true;
190+
document.addEventListener("change", handleChartThemeChange);
191+
document.addEventListener("click", handleDocsThemeClick);
192+
}
193+
};
194+
195+
if (document.readyState === "loading") {
196+
document.addEventListener("DOMContentLoaded", bootChartThemeControls, {
197+
once: true
198+
});
199+
} else {
200+
bootChartThemeControls();
201+
}
202+
203+
customElements.whenDefined("starlight-theme-select").then(() => {
204+
bootChartThemeControls();
205+
});
206+
207+
document.addEventListener("astro:page-load", bootChartThemeControls);
208+
209+
declare global {
210+
interface Window {
211+
StarlightThemeProvider?: {
212+
updatePickers: (theme?: string) => void;
213+
};
214+
__chartkitChartThemeControlBound?: boolean;
215+
}
216+
}
217+
218+
export {};

apps/site/src/components/Head.astro

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,12 +60,40 @@ const reactRefreshPreamble = `
6060
color-scheme: dark;
6161
}
6262
</style>
63-
{head.map(({ tag: Tag, attrs, content }) => <Tag {...attrs} set:html={content} />)}
63+
{
64+
head.map(({ tag: Tag, attrs, content }) => (
65+
<Tag {...attrs} set:html={content} />
66+
))
67+
}
6468
{
6569
isDev ? (
6670
<script type="module" is:inline set:html={reactRefreshPreamble} />
6771
) : null
6872
}
6973
<script>
74+
import "../chart-theme-controls";
7075
import "../previews/client.tsx";
7176
</script>
77+
<script is:inline>
78+
(() => {
79+
const enhanceCodeCopyButtons = () => {
80+
document
81+
.querySelectorAll(".expressive-code .copy button[title]")
82+
.forEach((button) => {
83+
const label = button.getAttribute("title") || "Copy to clipboard";
84+
button.setAttribute("aria-label", label);
85+
button.removeAttribute("title");
86+
});
87+
};
88+
89+
if (document.readyState === "loading") {
90+
document.addEventListener("DOMContentLoaded", enhanceCodeCopyButtons, {
91+
once: true
92+
});
93+
} else {
94+
enhanceCodeCopyButtons();
95+
}
96+
97+
document.addEventListener("astro:page-load", enhanceCodeCopyButtons);
98+
})();
99+
</script>

apps/site/src/components/ThemeInit.astro

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,19 @@
11
<script is:inline>
22
(() => {
33
const storageKey = "starlight-theme";
4+
const chartThemeStorageKey = "chartkit-chart-theme";
5+
const chartThemes = new Set([
6+
"default",
7+
"analytics",
8+
"fintech",
9+
"health",
10+
"ios",
11+
"material",
12+
"minimal",
13+
"highContrast",
14+
"darkFintech",
15+
"studio"
16+
]);
417
const getStoredTheme = () => {
518
try {
619
const stored = localStorage.getItem(storageKey);
@@ -9,13 +22,24 @@
922
return "dark";
1023
}
1124
};
25+
const getStoredChartTheme = () => {
26+
try {
27+
const stored = localStorage.getItem(chartThemeStorageKey);
28+
return chartThemes.has(stored) ? stored : "default";
29+
} catch {
30+
return "default";
31+
}
32+
};
1233
const theme = getStoredTheme();
34+
const chartTheme = getStoredChartTheme();
1335

1436
try {
1537
localStorage.setItem(storageKey, theme);
38+
localStorage.setItem(chartThemeStorageKey, chartTheme);
1639
} catch {}
1740

1841
document.documentElement.dataset.theme = theme;
42+
document.documentElement.dataset.chartTheme = chartTheme;
1943
document.documentElement.style.colorScheme = theme;
2044
})();
2145
</script>

apps/site/src/lib/remark-strip-duplicate-title.mjs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,12 @@ const escapeAttribute = (value) =>
9898
.replace(/"/g, "&quot;")
9999
.replace(/</g, "&lt;");
100100

101+
const escapeHtml = (value) =>
102+
String(value)
103+
.replace(/&/g, "&amp;")
104+
.replace(/</g, "&lt;")
105+
.replace(/>/g, "&gt;");
106+
101107
const encodeCodeAttribute = (value) => encodeURIComponent(String(value));
102108

103109
const playgroundDocs = new Set([
@@ -143,7 +149,9 @@ const getPlaygroundHtml = (id, code, title) => {
143149
id
144150
)}" data-code="${escapeAttribute(
145151
encodeCodeAttribute(code)
146-
)}"${titleAttribute}><div class="chart-kit-preview-fallback">Loading chart playground</div></chart-kit-playground>`;
152+
)}"${titleAttribute}><div class="chart-kit-preview-fallback"><pre><code>${escapeHtml(
153+
code
154+
)}</code></pre></div></chart-kit-playground>`;
147155
};
148156

149157
const isRenderableChartExample = (node, docsPath) =>

0 commit comments

Comments
 (0)