summaryrefslogtreecommitdiff
path: root/themes/theme/source/js
diff options
context:
space:
mode:
Diffstat (limited to 'themes/theme/source/js')
-rw-r--r--themes/theme/source/js/format.js23
-rw-r--r--themes/theme/source/js/menu.js27
-rw-r--r--themes/theme/source/js/mermaid-zoom.js169
-rw-r--r--themes/theme/source/js/search.js68
-rw-r--r--themes/theme/source/js/theme-switch.js31
5 files changed, 318 insertions, 0 deletions
diff --git a/themes/theme/source/js/format.js b/themes/theme/source/js/format.js
new file mode 100644
index 00000000..9d79edce
--- /dev/null
+++ b/themes/theme/source/js/format.js
@@ -0,0 +1,23 @@
+function detectTaskList() {
+ var taskListObjects = document.getElementsByTagName("input");
+ for (var i = 0; i < taskListObjects.length; i++) {
+ var par = taskListObjects[i].parentNode;
+ par.classList.add("task-list-item");
+ par.parentNode.classList.add("task-list");
+ }
+}
+
+function detectBlockTable() {
+ var tableListObjects = document.getElementsByTagName("thead");
+ for (var i = 0; i < tableListObjects.length; i++) {
+ var par = tableListObjects[i].parentNode;
+ par.classList.add("block-table");
+ }
+}
+
+function detectors(){
+ detectTaskList();
+ detectBlockTable();
+}
+
+
diff --git a/themes/theme/source/js/menu.js b/themes/theme/source/js/menu.js
new file mode 100644
index 00000000..fd84fcc3
--- /dev/null
+++ b/themes/theme/source/js/menu.js
@@ -0,0 +1,27 @@
+function toggleMenu() {
+ var menuList = document.getElementsByClassName("menu-list")[0];
+ var menuButton = document.getElementById("menu-btn");
+ if (menuList.classList.contains("active")) {
+ menuList.classList.remove("active");
+ menuButton.innerHTML = "菜单";
+ } else {
+ menuList.classList.add("active");
+ menuButton.innerHTML = "菜单";
+ }
+}
+
+function closeMenu() {
+ var menuList = document.getElementsByClassName("menu-list")[0];
+ var menuButton = document.getElementById("menu-btn");
+ if (menuList.classList.contains("active")) {
+ menuList.classList.remove("active");
+ menuButton.innerHTML = "菜单";
+ }
+}
+
+document.addEventListener("DOMContentLoaded", function() {
+ var menuItems = document.querySelectorAll(".menu-item a");
+ menuItems.forEach(function(item) {
+ item.addEventListener("click", closeMenu);
+ });
+}); \ No newline at end of file
diff --git a/themes/theme/source/js/mermaid-zoom.js b/themes/theme/source/js/mermaid-zoom.js
new file mode 100644
index 00000000..6b4f0e17
--- /dev/null
+++ b/themes/theme/source/js/mermaid-zoom.js
@@ -0,0 +1,169 @@
+// Mermaid 图表点击放大功能
+
+(function() {
+ 'use strict';
+
+ // 等待 DOM 加载完成
+ function initMermaidZoom() {
+ const mermaidElements = document.querySelectorAll('.mermaid');
+
+ if (mermaidElements.length === 0) return;
+
+ // 检测是否为移动端
+ const isMobile = window.innerWidth <= 688;
+
+ // 移动端:为 mermaid 元素添加提示样式
+ if (isMobile) {
+ mermaidElements.forEach(function(el) {
+ el.style.position = 'relative';
+ // 创建提示元素
+ const hint = document.createElement('span');
+ hint.textContent = '点击放大';
+ hint.style.cssText = 'position:absolute;bottom:4px;right:4px;font-size:10px;padding:2px 6px;background:rgba(0,0,0,0.5);color:#fff;border-radius:4px;pointer-events:none;';
+ el.appendChild(hint);
+ });
+ }
+
+ // 创建模态框
+ const modal = document.createElement('div');
+ modal.className = 'mermaid-modal';
+ modal.innerHTML = `
+ <button class="mermaid-close" aria-label="关闭">&times;</button>
+ <div class="mermaid-content"></div>
+ `;
+ document.body.appendChild(modal);
+
+ const closeBtn = modal.querySelector('.mermaid-close');
+ const content = modal.querySelector('.mermaid-content');
+
+ // 关闭模态框函数
+ function closeModal() {
+ modal.classList.remove('active');
+ document.body.style.overflow = '';
+ }
+
+ // 为每个 mermaid 图表添加点击事件
+ mermaidElements.forEach(function(el) {
+ el.addEventListener('click', function(e) {
+ // 等待 mermaid 渲染完成
+ const svg = el.querySelector('svg');
+ if (!svg) return;
+
+ // 复制 SVG 到模态框
+ content.innerHTML = '';
+ const clonedSvg = svg.cloneNode(true);
+
+ // 获取原始 SVG 的尺寸
+ const originalWidth = svg.viewBox.baseVal.width || svg.width.baseVal.value || 800;
+ const originalHeight = svg.viewBox.baseVal.height || svg.height.baseVal.value || 600;
+
+ // 检测是否为移动端
+ const isMobile = window.innerWidth <= 688;
+
+ // 计算放大比例
+ let targetWidth;
+ if (isMobile) {
+ // 移动端:适配屏幕宽度,留出边距
+ targetWidth = window.innerWidth - 32; // 16px padding × 2
+ } else {
+ // 桌面端:85% 视口宽度,最大 1600px
+ targetWidth = Math.min(window.innerWidth * 0.85, 1600);
+ }
+
+ const scale = targetWidth / originalWidth;
+ const newWidth = originalWidth * scale;
+ const newHeight = originalHeight * scale;
+
+ // 设置放大后的尺寸
+ clonedSvg.setAttribute('width', newWidth + 'px');
+ clonedSvg.setAttribute('height', newHeight + 'px');
+ clonedSvg.style.width = newWidth + 'px';
+ clonedSvg.style.height = newHeight + 'px';
+ clonedSvg.style.maxWidth = 'none';
+ clonedSvg.style.maxHeight = 'none';
+
+ // 确保 viewBox 存在
+ if (!clonedSvg.getAttribute('viewBox')) {
+ clonedSvg.setAttribute('viewBox', '0 0 ' + originalWidth + ' ' + originalHeight);
+ }
+
+ content.appendChild(clonedSvg);
+
+ // 显示模态框
+ modal.classList.add('active');
+ document.body.style.overflow = 'hidden';
+
+ // 移动端样式调整
+ if (isMobile) {
+ content.style.maxWidth = '100vw';
+ content.style.maxHeight = '100vh';
+ content.style.padding = '12px';
+ content.style.borderRadius = '0';
+ modal.style.padding = '0';
+ } else {
+ // 恢复桌面端样式
+ content.style.maxWidth = '';
+ content.style.maxHeight = '';
+ content.style.padding = '';
+ content.style.borderRadius = '';
+ modal.style.padding = '';
+ }
+ });
+ });
+
+ // 关闭按钮事件
+ closeBtn.addEventListener('click', closeModal);
+
+ // 点击背景关闭
+ modal.addEventListener('click', function(e) {
+ if (e.target === modal) {
+ closeModal();
+ }
+ });
+
+ // ESC 键关闭
+ document.addEventListener('keydown', function(e) {
+ if (e.key === 'Escape' && modal.classList.contains('active')) {
+ closeModal();
+ }
+ });
+ }
+
+ // 等待 mermaid 渲染完成后再初始化
+ function waitForMermaid() {
+ const mermaidElements = document.querySelectorAll('.mermaid');
+ let renderedCount = 0;
+
+ function checkRendered() {
+ let allRendered = true;
+ mermaidElements.forEach(function(el) {
+ if (!el.querySelector('svg')) {
+ allRendered = false;
+ }
+ });
+
+ if (allRendered) {
+ initMermaidZoom();
+ } else {
+ // 如果还没渲染完,继续等待
+ if (renderedCount < 50) { // 最多等待 5 秒
+ renderedCount++;
+ setTimeout(checkRendered, 100);
+ } else {
+ // 超时,仍然初始化(可能有些图表渲染失败)
+ initMermaidZoom();
+ }
+ }
+ }
+
+ // 开始检查
+ setTimeout(checkRendered, 500);
+ }
+
+ // 页面加载完成后初始化
+ if (document.readyState === 'loading') {
+ document.addEventListener('DOMContentLoaded', waitForMermaid);
+ } else {
+ waitForMermaid();
+ }
+})();
diff --git a/themes/theme/source/js/search.js b/themes/theme/source/js/search.js
new file mode 100644
index 00000000..27abb4e0
--- /dev/null
+++ b/themes/theme/source/js/search.js
@@ -0,0 +1,68 @@
+// Search functionality for standalone search page
+
+(function () {
+ 'use strict';
+
+ let localSearch = null;
+ let isDataLoaded = false;
+
+ function initSearch() {
+ const input = document.getElementById('search-input');
+ const container = document.getElementById('search-results');
+
+ if (!input || !container || typeof LocalSearch === 'undefined') {
+ container.innerHTML = '<div class="search-result-message">搜索功能初始化失败</div>';
+ return;
+ }
+
+ localSearch = new LocalSearch({
+ path: searchConfig.path,
+ top_n_per_article: searchConfig.top_n_per_article,
+ unescape: searchConfig.unescape
+ });
+
+ localSearch.fetchData();
+
+ window.addEventListener('search:loaded', function () {
+ isDataLoaded = true;
+ container.innerHTML = '<div class="search-result-message"></div>';
+ });
+
+ function displaySearchResult() {
+ if (!isDataLoaded) {
+ container.innerHTML = '<div class="search-result-message">加载中...</div>';
+ return;
+ }
+
+ const searchText = input.value.trim().toLowerCase();
+
+ if (searchText.length === 0) {
+ container.innerHTML = '<div class="search-result-message"></div>';
+ return;
+ }
+
+ const keywords = searchText.split(/[-\s]+/);
+ const resultItems = localSearch.getResultItems(keywords);
+
+ if (resultItems.length === 0) {
+ container.innerHTML = '<div class="search-result-message">未找到相关结果</div>';
+ } else {
+ container.innerHTML = `
+ <div class="search-result-message">找到 ${resultItems.length} 个结果</div>
+ <ul class="search-result-list">
+ ${resultItems.map(result => result.item).join('')}
+ </ul>
+ `;
+ }
+ }
+
+ input.addEventListener('input', displaySearchResult);
+ input.focus();
+ }
+
+ if (document.readyState === 'loading') {
+ document.addEventListener('DOMContentLoaded', initSearch);
+ } else {
+ initSearch();
+ }
+})();
diff --git a/themes/theme/source/js/theme-switch.js b/themes/theme/source/js/theme-switch.js
new file mode 100644
index 00000000..4dddd304
--- /dev/null
+++ b/themes/theme/source/js/theme-switch.js
@@ -0,0 +1,31 @@
+document.addEventListener('DOMContentLoaded', () => {
+ const themeSwitch = document.getElementById('theme-switch-btn');
+ const prefersDarkScheme = window.matchMedia('(prefers-color-scheme: dark)');
+
+ // 检查本地存储中的主题设置
+ const currentTheme = localStorage.getItem('theme');
+ if (currentTheme === 'dark') {
+ document.body.classList.add('dark-theme');
+ themeSwitch.querySelector('i').classList.replace('icon-moon', 'icon-sun');
+ } else if (currentTheme === 'light') {
+ document.body.classList.remove('dark-theme');
+ } else if (prefersDarkScheme.matches) {
+ document.body.classList.add('dark-theme');
+ themeSwitch.querySelector('i').classList.replace('icon-moon', 'icon-sun');
+ }
+
+ // 切换主题
+ themeSwitch.addEventListener('click', (e) => {
+ e.preventDefault();
+
+ if (document.body.classList.contains('dark-theme')) {
+ document.body.classList.remove('dark-theme');
+ localStorage.setItem('theme', 'light');
+ themeSwitch.querySelector('i').classList.replace('icon-sun', 'icon-moon');
+ } else {
+ document.body.classList.add('dark-theme');
+ localStorage.setItem('theme', 'dark');
+ themeSwitch.querySelector('i').classList.replace('icon-moon', 'icon-sun');
+ }
+ });
+}); \ No newline at end of file