Files
gemini-banlancer/web/static/js/main.js
2025-11-21 19:33:05 +08:00

214 lines
7.2 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import {
CustomSelect,
modalManager,
taskCenterManager,
toastManager,
uiPatterns
} from "./chunk-EZAP7GR4.js";
import {
apiFetch,
apiFetchJson
} from "./chunk-PLQL6WIO.js";
// frontend/js/components/slidingTabs.js
var SlidingTabs = class {
/**
* @param {HTMLElement} containerElement - The main container element with the `data-sliding-tabs-container` attribute.
*/
constructor(containerElement) {
this.container = containerElement;
this.indicator = this.container.querySelector("[data-tab-indicator]");
this.tabs = this.container.querySelectorAll("[data-tab-item]");
this.activeTab = this.container.querySelector(".tab-active");
if (!this.indicator || this.tabs.length === 0) {
console.error("SlidingTabs component is missing required elements (indicator or items).", this.container);
return;
}
this.init();
}
init() {
if (this.activeTab) {
setTimeout(() => this.updateIndicator(this.activeTab), 50);
}
this.bindEvents();
}
updateIndicator(targetTab) {
if (!targetTab) return;
const containerRect = this.container.getBoundingClientRect();
const targetRect = targetTab.getBoundingClientRect();
const left = targetRect.left - containerRect.left;
const width = targetRect.width;
this.indicator.style.left = `${left}px`;
this.indicator.style.width = `${width}px`;
}
bindEvents() {
this.tabs.forEach((tab) => {
tab.addEventListener("click", (e) => {
if (this.activeTab) {
this.activeTab.classList.remove("tab-active");
}
tab.classList.add("tab-active");
this.activeTab = tab;
this.updateIndicator(this.activeTab);
});
tab.addEventListener("mouseenter", () => {
this.updateIndicator(tab);
});
});
this.container.addEventListener("mouseleave", () => {
this.updateIndicator(this.activeTab);
});
}
};
document.addEventListener("DOMContentLoaded", () => {
const allTabContainers = document.querySelectorAll("[data-sliding-tabs-container]");
allTabContainers.forEach((container) => {
new SlidingTabs(container);
});
});
// frontend/js/components/themeManager.js
var themeManager = {
// 用于存储图标的 SVG HTML
icons: {},
init: function() {
this.html = document.documentElement;
this.buttons = document.querySelectorAll(".theme-btn");
this.cyclerBtn = document.getElementById("theme-cycler-btn");
this.cyclerIconContainer = document.getElementById("theme-cycler-icon");
if (!this.html || this.buttons.length === 0 || !this.cyclerBtn || !this.cyclerIconContainer) {
console.warn("ThemeManager init failed: one or more required elements not found.");
return;
}
this.mediaQuery = window.matchMedia("(prefers-color-scheme: dark)");
this.storeIcons();
this.buttons.forEach((btn) => {
btn.addEventListener("click", () => this.setTheme(btn.dataset.theme));
});
this.cyclerBtn.addEventListener("click", () => this.cycleTheme());
this.mediaQuery.addEventListener("change", () => this.applyTheme());
this.applyTheme();
},
// 从现有按钮中提取并存储 SVG 图标
storeIcons: function() {
this.buttons.forEach((btn) => {
const theme = btn.dataset.theme;
const svg = btn.querySelector("svg");
if (theme && svg) {
this.icons[theme] = svg.outerHTML;
}
});
},
// 循环切换主题的核心逻辑
cycleTheme: function() {
const themes = ["system", "light", "dark"];
const currentTheme = this.getTheme();
const currentIndex = themes.indexOf(currentTheme);
const nextIndex = (currentIndex + 1) % themes.length;
this.setTheme(themes[nextIndex]);
},
applyTheme: function() {
let theme = this.getTheme();
if (theme === "system") {
theme = this.mediaQuery.matches ? "dark" : "light";
}
if (theme === "dark") {
this.html.classList.add("dark");
} else {
this.html.classList.remove("dark");
}
this.updateButtons();
this.updateCyclerIcon();
},
setTheme: function(theme) {
localStorage.setItem("theme", theme);
this.applyTheme();
},
getTheme: function() {
return localStorage.getItem("theme") || "system";
},
updateButtons: function() {
const currentTheme = this.getTheme();
this.buttons.forEach((btn) => {
if (btn.dataset.theme === currentTheme) {
btn.classList.add("bg-white", "dark:bg-zinc-700");
} else {
btn.classList.remove("bg-white", "dark:bg-zinc-700");
}
});
},
// 更新移动端循环按钮的图标
updateCyclerIcon: function() {
if (this.cyclerIconContainer) {
const currentTheme = this.getTheme();
if (this.icons[currentTheme]) {
this.cyclerIconContainer.innerHTML = this.icons[currentTheme];
}
}
}
};
// frontend/js/layout/base.js
function initActiveNav() {
const currentPath = window.location.pathname;
const navLinks = document.querySelectorAll(".nav-link");
navLinks.forEach((link) => {
const linkPath = link.getAttribute("href");
if (linkPath && linkPath !== "/" && currentPath.startsWith(linkPath)) {
const wrapper = link.closest(".nav-item-wrapper");
if (wrapper) {
wrapper.dataset.active = "true";
}
}
});
}
function bridgeApiToGlobal() {
window.apiFetch = apiFetch;
window.apiFetchJson = apiFetchJson;
console.log("[Bridge] apiFetch and apiFetchJson are now globally available.");
}
function initLayout() {
console.log("[Init] Executing global layout JavaScript...");
initActiveNav();
themeManager.init();
bridgeApiToGlobal();
}
var base_default = initLayout;
// frontend/js/main.js
var pageModules = {
// 键 'dashboard' 对应一个函数,该函数调用 import() 返回一个 Promise
// esbuild 看到这个 import() 语法,就会自动将 dashboard.js 及其依赖打包成一个独立的 chunk 文件
"dashboard": () => import("./dashboard-CJJWKYPR.js"),
"keys": () => import("./keys-4GCIJ7HW.js"),
"logs": () => import("./logs-AG4TD2DO.js")
// 'settings': () => import('./pages/settings.js'), // 未来启用 settings 页面
// 未来新增的页面只需在这里添加一行映射esbuild会自动处理
};
document.addEventListener("DOMContentLoaded", async () => {
base_default();
const allTabContainers = document.querySelectorAll("[data-sliding-tabs-container]");
allTabContainers.forEach((container) => new SlidingTabs(container));
const allSelectContainers = document.querySelectorAll("[data-custom-select-container]");
allSelectContainers.forEach((container) => new CustomSelect(container));
taskCenterManager.init();
const pageContainer = document.querySelector("[data-page-id]");
if (pageContainer) {
const pageId = pageContainer.dataset.pageId;
if (pageId && pageModules[pageId]) {
try {
const pageModule = await pageModules[pageId]();
if (pageModule.default && typeof pageModule.default === "function") {
pageModule.default();
}
} catch (error) {
console.error(`Failed to load module for page: ${pageId}`, error);
}
}
}
});
window.modalManager = modalManager;
window.taskCenterManager = taskCenterManager;
window.toastManager = toastManager;
window.uiPatterns = uiPatterns;