0 directories, 7 files

util

Home / testing / ai / tinai / util
/**
 * Theme loading, dynamic stylesheet injection, and page loader transitions.
 */

import { queryEl, queryAll } from './dom-utils.js';

export const VALID_THEMES = ['theme_dark', 'theme_light'];
export const DEFAULT_THEME = 'theme_dark';

/**
 * Fades out and hides the page loader element.
 * @param {HTMLElement|null} [loaderEl=null] - Optional loader element reference.
 */
export function fadeOutLoader(loaderEl = null) {
	const loader = loaderEl || queryEl('.page-loader');
	if (loader) {
		loader.style.opacity = '0';
		loader.addEventListener('transitionend', () => {
			loader.style.display = 'none';
		}, { once: true });
	}
}

/**
 * Applies a theme by swapping dynamic stylesheet link tags and updating highlight.js theme if specified.
 * @param {string} theme - The theme identifier ('theme_dark' | 'theme_light').
 * @param {boolean} [includeHljs=true] - Whether to also swap the Highlight.js theme stylesheet.
 * @param {Function} [onComplete] - Optional callback once theme stylesheets finish loading.
 */
export function applyTheme(theme, includeHljs = true, onComplete = null) {
	const activeTheme = VALID_THEMES.includes(theme) ? theme : DEFAULT_THEME;
	const loader = queryEl('.page-loader');

	const requiredHrefs = [
		'dynamic.php?s=base&t=' + activeTheme,
		'dynamic.php?s=style&t=' + activeTheme
	];

	if (includeHljs) {
		const hljsTheme = activeTheme.includes('light')
			? 'https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.11.1/styles/default.min.css'
			: 'https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.11.1/styles/dark.min.css';
		requiredHrefs.unshift(hljsTheme);
	}

	const existingLinks = queryAll('link[rel="stylesheet"]');
	const currentHrefs = existingLinks.map(link => link.getAttribute('href'));

	const isAlreadyApplied = requiredHrefs.every(href => currentHrefs.includes(href));

	if (isAlreadyApplied) {
		fadeOutLoader(loader);
		if (typeof onComplete === 'function') onComplete(activeTheme);
		return;
	}

	if (loader) {
		loader.style.display = 'block';
		loader.style.opacity = '0';
		// Force reflow for transition
		void loader.offsetHeight;
		loader.style.opacity = '1';
	}

	const oldLinks = existingLinks.filter(link => {
		const href = link.getAttribute('href') || '';
		return href.includes('dynamic.php?s=') || href.includes('highlight.js/11.11.1/styles/');
	});

	let loadedCount = 0;
	const onLinkLoad = () => {
		loadedCount++;
		if (loadedCount === requiredHrefs.length) {
			oldLinks.forEach(link => link.remove());
			fadeOutLoader(loader);
			if (typeof onComplete === 'function') onComplete(activeTheme);
		}
	};

	requiredHrefs.forEach(href => {
		const link = document.createElement('link');
		link.rel = 'stylesheet';
		link.href = href;
		link.onload = onLinkLoad;
		link.onerror = onLinkLoad;
		document.head.appendChild(link);
	});
}
🌐
theme-utils.js ×
Type: Web, text/x-java
2.75 Kilobytes
Last Modified 2026-09-04 14:23:31
⬇ Download File