Files
wordpress-theme-aksrt/assets/js/core/theme.js
T
kate522andClaude Opus 5 35bb96e82f refactor: rename the theme brand and every identifier from AKSRT to Jio
Full-project rename. `git grep -i aksrt` is now empty apart from the
DBMigrator 3.3.0 changelog note that documents the rename itself.

Code identifiers
- PHP namespace AKSRT\ -> Jio\ (composer PSR-4 + 378 declarations)
- global constants AKSRT_* -> JIO_* (VERSION/DIR/URI, PAY_TYPE_*, CAPTCHA_*)
- procedural functions, hooks, options, meta keys, table names,
  cookies, query vars, ajax actions and nonces: aksrt_ -> jio_
- text domain aksrt -> jio; Theme Name -> Jio
- JS globals: aksrtData/aksrtAdminData/... -> jioData/jioAdminData/...,
  window.AKSRTCaptcha & friends -> window.JioCaptcha, Aksrt* -> Jio*
- Vue components Aks*.vue -> Jio*.vue (15 files renamed + imports)
- CSS classes/data-attrs/custom properties: aksrt- -> jio-
- REST namespace aksrt/v1 -> jio/v1 (incl. payment gateway callbacks)

Storage layer
- DB tables {prefix}aksrt_* -> {prefix}jio_*; SCHEMA_VERSION 3.2.0 -> 3.3.0
  so dbDelta creates the new names on install
- widget id_base aksrt_widget_* -> jio_widget_*
- uninstall.php drop list rebuilt from the actual migrator tables
  (dropped 3 stale entries, added the 17 missing ones)

Removed
- hardcoded https://api.aksrt.com/version.json default update endpoint;
  get_endpoint() now reads the 「更新端点」 setting and do_check() no-ops
  when it is empty

Files renamed: inc/helpers/aksrt-*.php -> jio-*.php (54),
assets/admin/src/components/form/Aks*.vue -> Jio*.vue (15).
Build artifacts regenerated: assets/css/build, assets/js/runtime,
assets/admin/build.

Verified: audit-psr4-paths errors=0, audit-admin-contracts errors=0
(warnings=56, unchanged baseline), 813/813 widget-system tests,
44/44 phpunit, php -l clean across all PHP.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-11-01 20:05:04 +08:00

268 lines
9.0 KiB
JavaScript

/**
* Jio Theme Toggle — dark/light mode switching with transitions
*/
(function () {
"use strict";
var THEME_KEY = "jio-theme";
var THEME_COOKIE_KEY = "theme_mode";
function normalizeStoredTheme(value) {
if (value === "dark" || value === "dark-theme") return "dark";
if (value === "light" || value === "white-theme") return "light";
return null;
}
function toCookieTheme(value) {
return value === "dark" ? "dark-theme" : "white-theme";
}
function getCookie(name) {
var parts = document.cookie ? document.cookie.split("; ") : [];
for (var i = 0; i < parts.length; i++) {
var pair = parts[i].split("=");
if (decodeURIComponent(pair[0]) === name) {
return decodeURIComponent(pair.slice(1).join("="));
}
}
return "";
}
function setCookie(name, value, days) {
var maxAge = days ? "; max-age=" + (days * 24 * 60 * 60) : "";
var secure = window.location && window.location.protocol === "https:" ? "; Secure" : "";
document.cookie = encodeURIComponent(name) + "=" + encodeURIComponent(value) + maxAge + "; path=/; SameSite=Lax" + secure;
}
function getStoredTheme() {
var localTheme = null;
try {
localTheme = normalizeStoredTheme(localStorage.getItem(THEME_KEY));
} catch (e) {
localTheme = null;
}
var theme = normalizeStoredTheme(getCookie(THEME_COOKIE_KEY)) || localTheme;
if (theme) {
setStoredTheme(theme);
}
return theme;
}
function setStoredTheme(value) {
var theme = normalizeStoredTheme(value);
if (!theme) return;
try {
localStorage.setItem(THEME_KEY, theme);
} catch (e) {}
setCookie(THEME_COOKIE_KEY, toCookieTheme(theme), 365);
}
function getTimeAutoTheme() {
var hour = (new Date()).getHours();
return hour >= 20 || hour < 8 ? "dark" : "light";
}
function resolveConfiguredTheme(mode) {
var normalized = normalizeStoredTheme(mode);
if (normalized) return normalized;
if (mode === "time-auto" || mode === "auto") {
return getTimeAutoTheme();
}
return "light";
}
function syncBrandLogos(isDark) {
document.querySelectorAll("[data-logo-light]").forEach(function (img) {
var lightSrc = img.getAttribute("data-logo-light") || "";
var darkSrc = img.getAttribute("data-logo-dark") || "";
if (!lightSrc) return;
img.setAttribute("src", isDark && darkSrc ? darkSrc : lightSrc);
});
}
function syncThemeColorMeta(isDark) {
var meta = document.querySelector('meta[name="theme-color"]');
if (!meta) {
meta = document.createElement("meta");
meta.setAttribute("name", "theme-color");
document.head.appendChild(meta);
}
meta.setAttribute("content", isDark ? "#2F3135" : "#FDFCFE");
}
function getThemeImageAttr(img, name) {
return img.getAttribute(name) || img.getAttribute("data-" + name) || "";
}
function setThemeImageSource(img, src) {
if (!src || img.getAttribute("src") === src) return;
img.setAttribute("src", src);
}
function syncThemeImages(isDark) {
document.querySelectorAll("img[switch-src], img[data-switch-src]").forEach(function (img) {
var darkSrc = getThemeImageAttr(img, "switch-src");
if (!img.dataset.jioThemeLightSrc) {
img.dataset.jioThemeLightSrc = img.getAttribute("src") || "";
}
setThemeImageSource(img, isDark && darkSrc ? darkSrc : img.dataset.jioThemeLightSrc);
});
document.querySelectorAll("img[white-src], img[dark-src], img[data-white-src], img[data-dark-src]").forEach(function (img) {
var lightSrc = getThemeImageAttr(img, "white-src") || img.dataset.jioThemeLightSrc || img.getAttribute("src") || "";
var darkSrc = getThemeImageAttr(img, "dark-src");
if (!img.dataset.jioThemeLightSrc && lightSrc) {
img.dataset.jioThemeLightSrc = lightSrc;
}
setThemeImageSource(img, isDark && darkSrc ? darkSrc : lightSrc);
});
}
function syncCodeHighlightTheme(isDark) {
if (typeof window.JioPrecodeApplyTheme === "function") {
window.JioPrecodeApplyTheme(isDark);
return;
}
var settings = (window.jioData && window.jioData.codeHighlight) || {};
var theme = isDark ? (settings.darkTheme || "monokai") : (settings.lightTheme || "enlighter");
document.querySelectorAll(".enlighter-default").forEach(function (el) {
el.className = el.className.replace(/\benlighter-t-[\w-]+\b/g, "").replace(/\s+/g, " ").trim();
el.classList.add("enlighter-t-" + theme);
});
}
function dispatchThemeChange(isDark) {
try {
document.dispatchEvent(new CustomEvent("jio:theme-change", {
detail: {
theme: isDark ? "dark" : "light",
isDark: isDark
}
}));
} catch (e) {}
}
function applyTheme(mode) {
var isDark = mode === "dark";
document.documentElement.classList.toggle("dark", isDark);
document.documentElement.setAttribute("data-theme", isDark ? "dark" : "light");
document.body.classList.toggle("theme-dark", isDark);
document.body.classList.toggle("dark-theme", isDark);
document.body.classList.toggle("white-theme", !isDark);
document.body.setAttribute("data-theme", isDark ? "dark" : "light");
syncBrandLogos(isDark);
syncThemeColorMeta(isDark);
syncThemeImages(isDark);
syncCodeHighlightTheme(isDark);
dispatchThemeChange(isDark);
// Icon visibility is CSS-driven via html.dark / body.theme-dark.
// Only sync a11y state here — do not set inline display (fights !important CSS).
document.querySelectorAll("#theme-toggle, #theme-toggle-desktop, #theme-toggle-mobile, #dropdown-theme-toggle, .toggle-theme, [data-action='toggle-theme']").forEach(function (btn) {
if (!btn) return;
btn.setAttribute("aria-pressed", isDark ? "true" : "false");
btn.classList.toggle("is-dark", isDark);
var moon = btn.querySelector(".theme-icon-moon");
var sun = btn.querySelector(".theme-icon-sun");
if (moon) {
moon.removeAttribute("style");
moon.setAttribute("aria-hidden", isDark ? "true" : "false");
}
if (sun) {
sun.removeAttribute("style");
sun.setAttribute("aria-hidden", isDark ? "false" : "true");
}
});
var ddBtn = document.getElementById("dropdown-theme-toggle");
if (ddBtn) ddBtn.setAttribute("aria-pressed", isDark ? "true" : "false");
}
var themeInitialized = false;
function initTheme() {
if (themeInitialized) return;
themeInitialized = true;
var stored = getStoredTheme();
var configuredMode = (window.jioData && window.jioData.themeMode) || "light";
if (stored === "dark" || stored === "light") {
applyTheme(stored);
} else {
applyTheme(resolveConfiguredTheme(configuredMode));
}
function prefersReducedMotion() {
return window.matchMedia && window.matchMedia("(prefers-reduced-motion: reduce)").matches;
}
function getThemeTransitionPoint(event) {
if (event && typeof event.clientX === "number" && typeof event.clientY === "number") {
return { x: event.clientX, y: event.clientY };
}
return { x: window.innerWidth / 2, y: window.innerHeight / 2 };
}
function runThemeTransition(next, event) {
if (!document.startViewTransition || prefersReducedMotion()) {
applyTheme(next);
return;
}
var point = getThemeTransitionPoint(event);
var endRadius = Math.hypot(
Math.max(point.x, window.innerWidth - point.x),
Math.max(point.y, window.innerHeight - point.y)
);
var clipPath = [
"circle(0px at " + point.x + "px " + point.y + "px)",
"circle(" + endRadius + "px at " + point.x + "px " + point.y + "px)"
];
var enteringDark = next === "dark";
try {
var transition = document.startViewTransition(function () {
applyTheme(next);
});
transition.ready.then(function () {
try {
document.documentElement.animate(
{ clipPath: enteringDark ? clipPath : clipPath.slice().reverse() },
{
duration: 500,
easing: enteringDark ? "ease-in" : "ease-out",
fill: "both",
pseudoElement: enteringDark ? "::view-transition-new(root)" : "::view-transition-old(root)"
}
);
} catch (e) {}
}).catch(function () {});
} catch (e) {
applyTheme(next);
}
}
function bindToggle(id) {
var el = document.getElementById(id);
if (!el) return;
el.addEventListener("click", function (event) {
var next = document.body.classList.contains("theme-dark") ? "light" : "dark";
setStoredTheme(next);
runThemeTransition(next, event);
});
}
bindToggle("theme-toggle");
bindToggle("theme-toggle-desktop");
bindToggle("dropdown-theme-toggle");
bindToggle("theme-toggle-mobile");
}
if (document.readyState === "loading") {
document.addEventListener("DOMContentLoaded", initTheme);
} else {
initTheme();
}
})();