11/**
2- * Client-side JavaScript for the page
2+ * Inline scripts for SSG pages
3+ *
4+ * These scripts are embedded inline in the HTML to run before external scripts load.
5+ * Main functionality is in client.ts which is bundled as a module.
36 */
47
58/** Theme initialization script (runs before render to prevent FOUC) */
@@ -9,188 +12,3 @@ export const themeInitScript = `(function() {
912 const theme = stored || (systemPrefersDark ? 'dark' : 'light');
1013 document.documentElement.setAttribute('data-theme', theme);
1114})();` ;
12-
13- /** Main page scripts */
14- export const mainScript = `
15- const HLJS_CDN = 'https://cdn.jsdelivr.net/gh/highlightjs/cdn-release@11.9.0/build';
16- const HLJS_THEMES = {
17- dark: 'https://cdn.jsdelivr.net/gh/highlightjs/cdn-release@11.9.0/build/styles/github-dark.min.css',
18- light: 'https://cdn.jsdelivr.net/gh/highlightjs/cdn-release@11.9.0/build/styles/github.min.css'
19- };
20-
21- function loadScript(src) {
22- return new Promise((resolve, reject) => {
23- const script = document.createElement('script');
24- script.src = src;
25- script.async = true;
26- script.onload = resolve;
27- script.onerror = reject;
28- document.head.appendChild(script);
29- });
30- }
31-
32- async function ensureHljs() {
33- if (window.hljs) return;
34- await loadScript(\`\${HLJS_CDN}/highlight.min.js\`);
35- await loadScript(\`\${HLJS_CDN}/languages/typescript.min.js\`);
36- await loadScript(\`\${HLJS_CDN}/languages/json.min.js\`);
37- }
38-
39- function updateHljsTheme(theme) {
40- const themeLink = document.getElementById('hljs-theme');
41- if (!themeLink) return;
42- themeLink.href = HLJS_THEMES[theme];
43- }
44-
45- function toggleTheme() {
46- const current = document.documentElement.getAttribute('data-theme');
47- const next = current === 'light' ? 'dark' : 'light';
48- document.documentElement.setAttribute('data-theme', next);
49- localStorage.setItem('theme', next);
50- updateHljsTheme(next);
51- }
52-
53- function toggleMobileMenu() {
54- const header = document.querySelector('.global-header');
55- header.classList.toggle('menu-open');
56- document.body.classList.toggle('menu-open');
57- }
58-
59- function closeMobileMenu() {
60- const header = document.querySelector('.global-header');
61- header.classList.remove('menu-open');
62- document.body.classList.remove('menu-open');
63- }
64-
65- function initCarousel() {
66- const tabs = document.querySelectorAll('.carousel-tab');
67- const slides = document.querySelectorAll('.carousel-slide');
68- const prevBtn = document.querySelector('.carousel-prev');
69- const nextBtn = document.querySelector('.carousel-next');
70-
71- // Skip if carousel elements not found
72- if (!tabs.length || !slides.length || !prevBtn || !nextBtn) return;
73-
74- const totalSlides = slides.length;
75-
76- function goToSlide(index) {
77- tabs.forEach(t => t.classList.remove('active'));
78- tabs[index].classList.add('active');
79- slides.forEach(s => s.classList.remove('active'));
80- slides[index].classList.add('active');
81- if (window.hljs) {
82- slides[index].querySelectorAll('pre code:not([data-highlighted])').forEach(block => {
83- hljs.highlightElement(block);
84- });
85- }
86- }
87-
88- function getCurrentIndex() {
89- return [...tabs].findIndex(t => t.classList.contains('active'));
90- }
91-
92- tabs.forEach(tab => {
93- tab.addEventListener('click', () => {
94- goToSlide(parseInt(tab.dataset.index));
95- });
96- });
97-
98- prevBtn.addEventListener('click', () => {
99- const current = getCurrentIndex();
100- goToSlide((current - 1 + totalSlides) % totalSlides);
101- });
102-
103- nextBtn.addEventListener('click', () => {
104- const current = getCurrentIndex();
105- goToSlide((current + 1) % totalSlides);
106- });
107- }
108-
109- function initScrollableNavFade() {
110- document.querySelectorAll('.scrollable-nav').forEach(el => {
111- function updateFade() {
112- const atTop = el.scrollTop <= 10;
113- const atBottom = el.scrollTop + el.clientHeight >= el.scrollHeight - 10;
114-
115- el.classList.toggle('scroll-top', atTop);
116- el.classList.toggle('scroll-bottom', atBottom);
117- }
118-
119- updateFade();
120- el.addEventListener('scroll', updateFade, { passive: true });
121- });
122- }
123-
124- function initCodeCopyButtons() {
125- document.querySelectorAll('pre').forEach(pre => {
126- const code = pre.querySelector('code');
127- if (!code) return;
128-
129- const wrapper = document.createElement('div');
130- wrapper.className = 'code-block-wrapper';
131- pre.parentNode.insertBefore(wrapper, pre);
132- wrapper.appendChild(pre);
133-
134- const btn = document.createElement('button');
135- btn.type = 'button';
136- btn.className = 'code-copy-btn';
137- btn.title = 'Copy code';
138- btn.innerHTML = '<i class="ti ti-copy"></i>';
139- wrapper.appendChild(btn);
140-
141- btn.addEventListener('click', async () => {
142- try {
143- await navigator.clipboard.writeText(code.textContent || '');
144- btn.innerHTML = '<i class="ti ti-check"></i>';
145- btn.classList.add('copied');
146- setTimeout(() => {
147- btn.innerHTML = '<i class="ti ti-copy"></i>';
148- btn.classList.remove('copied');
149- }, 2000);
150- } catch (err) {
151- console.error('Failed to copy:', err);
152- }
153- });
154- });
155- }
156-
157- function initSignatureScrollFade() {
158- document.querySelectorAll('.api-signature pre code').forEach(code => {
159- function updateFade() {
160- const canScrollLeft = code.scrollLeft > 5;
161- const canScrollRight = code.scrollLeft + code.clientWidth < code.scrollWidth - 5;
162-
163- code.classList.toggle('scroll-left', canScrollLeft);
164- code.classList.toggle('scroll-right', canScrollRight);
165- }
166-
167- // Initial check
168- updateFade();
169-
170- // Update on scroll
171- code.addEventListener('scroll', updateFade, { passive: true });
172-
173- // Also check on window resize (content width may change)
174- window.addEventListener('resize', updateFade, { passive: true });
175- });
176- }
177-
178- document.addEventListener('DOMContentLoaded', async () => {
179- updateHljsTheme(document.documentElement.getAttribute('data-theme') || 'dark');
180- initCarousel();
181- initScrollableNavFade();
182- initCodeCopyButtons();
183- initSignatureScrollFade();
184- try {
185- await ensureHljs();
186- if (window.hljs) {
187- // Highlight all code blocks, including those in hidden carousel slides
188- document.querySelectorAll('pre code').forEach(block => {
189- hljs.highlightElement(block);
190- });
191- }
192- } catch (err) {
193- console.warn('Failed to load highlight.js', err);
194- }
195- });
196- ` ;
0 commit comments