Files
menav/src/runtime/app/ui.js
rbetree 89c1c0330b refactor: 统一错误处理机制
- 引入 ConfigError/TemplateError/BuildError/FileError 与 wrapAsyncError,统一错误输出
- generator 入口接入 wrapAsyncError,确保命令行执行路径一致
- 兜底逻辑使用 instanceof,保留 BuildError/TemplateError 上下文信息
- 合并格式化提交(仅缩进/换行调整)
2026-01-16 16:34:46 +08:00

181 lines
5.4 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.
module.exports = function initUi(state, dom) {
const {
searchInput,
searchBox,
menuToggle,
searchToggle,
sidebar,
searchContainer,
overlay,
sidebarToggle,
content,
themeToggle,
themeIcon,
} = dom;
// 移除预加载类,允许 CSS 过渡效果
document.documentElement.classList.remove('preload');
// 应用从 localStorage 读取的主题设置(预加载阶段已写入 class
if (document.documentElement.classList.contains('theme-preload')) {
document.documentElement.classList.remove('theme-preload');
document.body.classList.add('light-theme');
state.isLightTheme = true;
}
// 应用从 localStorage 读取的侧边栏状态(预加载阶段已写入 class
if (document.documentElement.classList.contains('sidebar-collapsed-preload')) {
document.documentElement.classList.remove('sidebar-collapsed-preload');
sidebar.classList.add('collapsed');
content.classList.add('expanded');
state.isSidebarCollapsed = true;
}
// 即时移除 loading 类,确保侧边栏可见
document.body.classList.remove('loading');
document.body.classList.add('loaded');
function isMobile() {
return window.innerWidth <= 768;
}
// 侧边栏折叠功能
function toggleSidebarCollapse() {
// 仅在交互时启用布局相关动画,避免首屏闪烁
document.documentElement.classList.add('with-anim');
state.isSidebarCollapsed = !state.isSidebarCollapsed;
// 使用 requestAnimationFrame 确保平滑过渡
requestAnimationFrame(() => {
sidebar.classList.toggle('collapsed', state.isSidebarCollapsed);
content.classList.toggle('expanded', state.isSidebarCollapsed);
// 保存折叠状态到 localStorage
localStorage.setItem('sidebarCollapsed', state.isSidebarCollapsed ? 'true' : 'false');
});
}
// 初始化侧边栏折叠状态 - 已在页面加载前处理,此处仅完成图标状态初始化等次要任务
function initSidebarState() {
// 从 localStorage 获取侧边栏状态
const savedState = localStorage.getItem('sidebarCollapsed');
// 图标状态与折叠状态保持一致
if (savedState === 'true' && !isMobile()) {
state.isSidebarCollapsed = true;
} else {
state.isSidebarCollapsed = false;
}
}
// 主题切换功能
function toggleTheme() {
state.isLightTheme = !state.isLightTheme;
document.body.classList.toggle('light-theme', state.isLightTheme);
// 更新图标
if (state.isLightTheme) {
themeIcon.classList.remove('fa-moon');
themeIcon.classList.add('fa-sun');
} else {
themeIcon.classList.remove('fa-sun');
themeIcon.classList.add('fa-moon');
}
// 保存主题偏好到 localStorage
localStorage.setItem('theme', state.isLightTheme ? 'light' : 'dark');
}
// 初始化主题 - 已在页面加载前处理,此处仅完成图标状态初始化等次要任务
function initTheme() {
// 从 localStorage 获取主题偏好
const savedTheme = localStorage.getItem('theme');
// 更新图标状态以匹配当前主题
if (savedTheme === 'light') {
state.isLightTheme = true;
themeIcon.classList.remove('fa-moon');
themeIcon.classList.add('fa-sun');
} else {
state.isLightTheme = false;
themeIcon.classList.remove('fa-sun');
themeIcon.classList.add('fa-moon');
}
}
// 移动端菜单切换
function toggleSidebar() {
state.isSidebarOpen = !state.isSidebarOpen;
sidebar.classList.toggle('active', state.isSidebarOpen);
overlay.classList.toggle('active', state.isSidebarOpen);
}
// 移动端搜索框常驻显示CSS 控制),无需“搜索面板”开关;点击仅聚焦输入框
function toggleSearch() {
searchInput && searchInput.focus();
}
// 关闭所有移动端面板
function closeAllPanels() {
if (state.isSidebarOpen) {
toggleSidebar();
}
}
// 侧边栏折叠按钮点击事件
if (sidebarToggle) {
sidebarToggle.addEventListener('click', toggleSidebarCollapse);
}
// 主题切换按钮点击事件
themeToggle.addEventListener('click', toggleTheme);
// 移动端事件监听
menuToggle.addEventListener('click', toggleSidebar);
searchToggle.addEventListener('click', toggleSearch);
overlay.addEventListener('click', closeAllPanels);
// 全局快捷键Ctrl/Cmd + K 聚焦搜索
document.addEventListener('keydown', (e) => {
const key = (e.key || '').toLowerCase();
if (key !== 'k') return;
if ((!e.ctrlKey && !e.metaKey) || e.altKey) return;
const target = e.target;
const isTypingTarget =
target &&
(target.tagName === 'INPUT' || target.tagName === 'TEXTAREA' || target.isContentEditable);
if (isTypingTarget && target !== searchInput) return;
e.preventDefault();
searchInput && searchInput.focus();
});
// 窗口大小改变时处理
window.addEventListener('resize', () => {
if (!isMobile()) {
sidebar.classList.remove('active');
searchContainer.classList.remove('active');
overlay.classList.remove('active');
state.isSidebarOpen = false;
} else {
// 在移动设备下,重置侧边栏折叠状态
sidebar.classList.remove('collapsed');
content.classList.remove('expanded');
}
});
// 仅用于静态检查:确保未用变量不被 lint 报错(未来可用于搜索 UI 状态)
void searchBox;
return {
isMobile,
closeAllPanels,
initTheme,
initSidebarState,
};
};