generated from dellevin/template
22
This commit is contained in:
@@ -34,7 +34,9 @@
|
||||
padding: 0 20px 24px;
|
||||
border-bottom: 1px solid #e0e0e0;
|
||||
margin-bottom: 20px;
|
||||
display: flex; align-items: flex-start; justify-content: space-between;
|
||||
}
|
||||
.sidebar-header-left { flex: 1; }
|
||||
|
||||
.sidebar-title {
|
||||
font-size: 18px;
|
||||
@@ -48,6 +50,14 @@
|
||||
margin-top: 4px;
|
||||
}
|
||||
|
||||
.sidebar-settings-btn {
|
||||
width: 30px; height: 30px; border: none; background: none;
|
||||
border-radius: 8px; cursor: pointer; font-size: 14px; color: #bbb;
|
||||
display: flex; align-items: center; justify-content: center;
|
||||
transition: all 0.15s; flex-shrink: 0; margin-top: 2px;
|
||||
}
|
||||
.sidebar-settings-btn:hover { background: #f0f0f0; color: #666; }
|
||||
|
||||
.nav-section {
|
||||
padding: 0 12px;
|
||||
margin-bottom: 24px;
|
||||
@@ -125,20 +135,6 @@
|
||||
.sidebar-search-input input::placeholder { color: #bbb; }
|
||||
.nav-item.hidden { display: none; }
|
||||
|
||||
/* 侧边栏底部设置按钮 */
|
||||
.sidebar-footer {
|
||||
margin-top: auto; padding: 12px 16px 8px;
|
||||
border-top: 1px solid #e0e0e0;
|
||||
}
|
||||
.sidebar-settings-btn {
|
||||
display: flex; align-items: center; gap: 8px;
|
||||
width: 100%; padding: 8px 10px; border: none; background: none;
|
||||
border-radius: 8px; cursor: pointer; font-size: 13px; color: #999;
|
||||
transition: all 0.15s;
|
||||
}
|
||||
.sidebar-settings-btn:hover { background: #f0f0f0; color: #666; }
|
||||
.sidebar-settings-btn i { width: 20px; text-align: center; }
|
||||
|
||||
/* 功能设置弹窗 */
|
||||
.feat-modal-overlay {
|
||||
display: none; position: fixed; top: 0; left: 0; width: 100%; height: 100%;
|
||||
@@ -556,8 +552,13 @@
|
||||
<!-- 侧边栏 -->
|
||||
<aside class="sidebar">
|
||||
<div class="sidebar-header">
|
||||
<div class="sidebar-title">LEVIN工具集</div>
|
||||
<div class="sidebar-subtitle">私人工具合集</div>
|
||||
<div class="sidebar-header-left">
|
||||
<div class="sidebar-title">LEVIN工具集</div>
|
||||
<div class="sidebar-subtitle">私人工具合集</div>
|
||||
</div>
|
||||
<button class="sidebar-settings-btn" onclick="openFeatModal()" title="功能显示设置">
|
||||
<i class="fas fa-gear"></i>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="sidebar-search">
|
||||
@@ -567,100 +568,13 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<nav class="nav-section">
|
||||
<nav class="nav-section" id="nav-section-overview">
|
||||
<div class="nav-section-title">概览</div>
|
||||
<a class="nav-item active" id="nav-dashboard" data-feature="dashboard" onclick="showDashboard()">
|
||||
<i class="fas fa-chart-bar"></i>
|
||||
仪表盘
|
||||
</a>
|
||||
<a class="nav-item" data-url="/data-manage" data-feature="data-manage" onclick="loadTool(this, '/data-manage')">
|
||||
<i class="fas fa-database"></i>
|
||||
数据管理
|
||||
</a>
|
||||
</nav>
|
||||
|
||||
<nav class="nav-section">
|
||||
<nav class="nav-section" id="nav-section-tools">
|
||||
<div class="nav-section-title">工具</div>
|
||||
|
||||
<a class="nav-item" data-url="/pin-tu" data-feature="pin-tu" onclick="loadTool(this, '/pin-tu')">
|
||||
<i class="fas fa-images"></i>
|
||||
路径文件查阅器
|
||||
</a>
|
||||
<a class="nav-item" data-url="/down-video" data-feature="down-video" onclick="loadTool(this, '/down-video')">
|
||||
<i class="fas fa-video"></i>
|
||||
XBIY视频下载器
|
||||
</a>
|
||||
<a class="nav-item" data-url="/content-tag" data-feature="content-tag" onclick="loadTool(this, '/content-tag')">
|
||||
<i class="fas fa-tags"></i>
|
||||
AI生成文章标签
|
||||
</a>
|
||||
<a class="nav-item" data-url="/audio-slicer" data-feature="audio-slicer" onclick="loadTool(this, '/audio-slicer')">
|
||||
<i class="fas fa-scissors"></i>
|
||||
AS 音频分割
|
||||
</a>
|
||||
<a class="nav-item" data-url="/stt" data-feature="stt" onclick="loadTool(this, '/stt')">
|
||||
<i class="fas fa-microphone"></i>
|
||||
STT 语音转文字
|
||||
</a>
|
||||
<a class="nav-item" data-url="/uvr-sep" data-feature="uvr-sep" onclick="loadTool(this, '/uvr-sep')">
|
||||
<i class="fas fa-exchange-alt"></i>
|
||||
UVR 人声分离
|
||||
</a>
|
||||
<a class="nav-item" data-url="/rvc" data-feature="rvc" onclick="loadTool(this, '/rvc')">
|
||||
<i class="fas fa-microphone"></i>
|
||||
RVC 音色转换
|
||||
</a>
|
||||
<a class="nav-item" data-url="/ai-dubbing" data-feature="ai-dubbing" onclick="loadTool(this, '/ai-dubbing')">
|
||||
<i class="fas fa-microphone"></i>
|
||||
GPT-SoVITS (引擎版)
|
||||
</a>
|
||||
|
||||
|
||||
<a class="nav-item" data-url="/sovits-tts" data-feature="sovits-tts" onclick="loadTool(this, '/sovits-tts')">
|
||||
<i class="fas fa-microphone"></i>
|
||||
GPT-SoVITS (接口版)
|
||||
</a>
|
||||
<a class="nav-item" data-url="/fen-ci" data-feature="fen-ci" onclick="loadTool(this, '/fen-ci')">
|
||||
<i class="fas fa-scissors"></i>
|
||||
Jieba 分词网页版
|
||||
</a>
|
||||
<a class="nav-item" data-url="/base64-de-in-code" data-feature="base64" onclick="loadTool(this, '/base64-de-in-code')">
|
||||
<i class="fas fa-lock"></i>
|
||||
Base64 编码/解码
|
||||
</a>
|
||||
<a class="nav-item" data-url="/json-format" data-feature="json-format" onclick="loadTool(this, '/json-format')">
|
||||
<i class="fas fa-code"></i>
|
||||
JSON 美化/压缩
|
||||
</a>
|
||||
|
||||
<a class="nav-item" data-url="/http-status" data-feature="http-status" onclick="loadTool(this, '/http-status')">
|
||||
<i class="fas fa-info-circle"></i>
|
||||
HTTP 状态码查询
|
||||
</a>
|
||||
<a class="nav-item" data-url="/url-parser" data-feature="url-parser" onclick="loadTool(this, '/url-parser')">
|
||||
<i class="fas fa-link"></i>
|
||||
URL 路径解析器
|
||||
</a>
|
||||
<a class="nav-item" data-url="/chmod-calc" data-feature="chmod-calc" onclick="loadTool(this, '/chmod-calc')">
|
||||
<i class="fas fa-key"></i>
|
||||
Chmod 计算器
|
||||
</a>
|
||||
<a class="nav-item" data-url="/token-gen" data-feature="token-gen" onclick="loadTool(this, '/token-gen')">
|
||||
<i class="fas fa-lock"></i>
|
||||
Token 随机生成器
|
||||
</a>
|
||||
<a class="nav-item" data-url="/qr-code" data-feature="qr-code" onclick="loadTool(this, '/qr-code')">
|
||||
<i class="fas fa-qrcode"></i>
|
||||
Qr-code 生成器
|
||||
</a>
|
||||
|
||||
</nav>
|
||||
|
||||
<div class="sidebar-footer">
|
||||
<button class="sidebar-settings-btn" onclick="openFeatModal()">
|
||||
<i class="fas fa-eye"></i> 功能显示设置
|
||||
</button>
|
||||
</div>
|
||||
</aside>
|
||||
|
||||
<!-- 功能显示设置弹窗 -->
|
||||
@@ -1342,58 +1256,67 @@
|
||||
Object.values(charts).forEach(c => c && c.resize());
|
||||
});
|
||||
|
||||
// ===== 功能显示设置 =====
|
||||
var FEATURES = [
|
||||
{ id: 'dashboard', name: '仪表盘', section: '概览' },
|
||||
{ id: 'data-manage', name: '数据管理', section: '概览' },
|
||||
{ id: 'pin-tu', name: '路径文件查阅器', section: '工具' },
|
||||
{ id: 'down-video', name: 'XBIY视频下载器', section: '工具' },
|
||||
{ id: 'content-tag', name: 'AI生成文章标签', section: '工具' },
|
||||
{ id: 'stt', name: 'STT 语音转文字', section: '工具' },
|
||||
{ id: 'audio-slicer', name: 'AudioSlicer 音频分割', section: '工具' },
|
||||
{ id: 'uvr-sep', name: 'UVR 人声分离', section: '工具' },
|
||||
{ id: 'ai-dubbing', name: 'GPT-SoVITS (引擎版)', section: '工具' },
|
||||
{ id: 'rvc', name: 'RVC 语音音色转换', section: '工具' },
|
||||
{ id: 'fen-ci', name: 'Jieba 分词网页版', section: '工具' },
|
||||
{ id: 'base64', name: 'Base64 编码/解码', section: '工具' },
|
||||
{ id: 'json-format', name: 'JSON 美化/压缩', section: '工具' },
|
||||
{ id: 'http-status', name: 'HTTP 状态码查询', section: '工具' },
|
||||
{ id: 'url-parser', name: 'URL 路径解析器', section: '工具' },
|
||||
{ id: 'chmod-calc', name: 'Chmod 计算器', section: '工具' },
|
||||
{ id: 'token-gen', name: 'Token 随机生成器', section: '工具' },
|
||||
{ id: 'qr-code', name: 'Qr-code 生成器', section: '工具' },
|
||||
{ id: 'sovits-tts', name: 'GPT-SoVITS (接口版)', section: '不常用' }
|
||||
// ===== 侧边栏动态生成 =====
|
||||
var NAV_ITEMS = [
|
||||
{ id: 'dashboard', name: '仪表盘', icon: 'fa-chart-bar', url: null, section: '概览' },
|
||||
{ id: 'data-manage', name: '数据管理', icon: 'fa-database', url: '/data-manage', section: '概览' },
|
||||
{ id: 'pin-tu', name: '路径文件查阅器', icon: 'fa-images', url: '/pin-tu', section: '工具' },
|
||||
{ id: 'down-video', name: 'XBIY视频下载器', icon: 'fa-video', url: '/down-video', section: '工具' },
|
||||
{ id: 'ai-translate', name: 'NLLB 翻译与字幕', icon: 'fa-language', url: '/ai-translate',section: '工具' },
|
||||
{ id: 'content-tag', name: 'AI生成文章标签', icon: 'fa-tags', url: '/content-tag', section: '工具' },
|
||||
{ id: 'mp4-to-audio', name: 'VTA 视频转音频', icon: 'fa-video', url: '/mp4-to-audio',section: '工具' },
|
||||
{ id: 'audio-slicer', name: 'AS 智能音频分割', icon: 'fa-scissors', url: '/audio-slicer',section: '工具' },
|
||||
{ id: 'stt', name: 'STT 语音转文字', icon: 'fa-microphone', url: '/stt', section: '工具' },
|
||||
{ id: 'uvr-sep', name: 'UVR5 人声分离', icon: 'fa-exchange-alt', url: '/uvr-sep', section: '工具' },
|
||||
{ id: 'rvc', name: 'RVC 语音音色转换', icon: 'fa-microphone', url: '/rvc', section: '工具' },
|
||||
{ id: 'ai-dubbing', name: 'GPT-SoVITS (引擎版)', icon: 'fa-microphone', url: '/ai-dubbing', section: '工具' },
|
||||
{ id: 'sovits-tts', name: 'GPT-SoVITS (接口版)', icon: 'fa-microphone', url: '/sovits-tts', section: '工具' },
|
||||
{ id: 'fen-ci', name: 'Jieba 分词网页版', icon: 'fa-scissors', url: '/fen-ci', section: '工具' },
|
||||
{ id: 'base64', name: 'Base64 编码/解码', icon: 'fa-lock', url: '/base64-de-in-code', section: '工具' },
|
||||
{ id: 'json-format', name: 'JSON 美化/压缩', icon: 'fa-code', url: '/json-format', section: '工具' },
|
||||
{ id: 'http-status', name: 'HTTP 状态码查询', icon: 'fa-info-circle', url: '/http-status', section: '工具' },
|
||||
{ id: 'url-parser', name: 'URL 路径解析器', icon: 'fa-link', url: '/url-parser', section: '工具' },
|
||||
{ id: 'chmod-calc', name: 'Chmod 计算器', icon: 'fa-key', url: '/chmod-calc', section: '工具' },
|
||||
{ id: 'token-gen', name: 'Token 随机生成器', icon: 'fa-lock', url: '/token-gen', section: '工具' },
|
||||
|
||||
{ id: 'qr-code', name: 'Qr-code 生成器', icon: 'fa-qrcode', url: '/qr-code', section: '工具' }
|
||||
];
|
||||
|
||||
function getHiddenFeatures() {
|
||||
try { return JSON.parse(localStorage.getItem('hidden_features') || '[]'); } catch(e) { return []; }
|
||||
}
|
||||
var _hiddenFeatures = [];
|
||||
|
||||
function applyFeatSettings() {
|
||||
var hidden = getHiddenFeatures();
|
||||
document.querySelectorAll('.nav-item[data-feature]').forEach(function(item) {
|
||||
var fid = item.getAttribute('data-feature');
|
||||
item.style.display = hidden.indexOf(fid) !== -1 ? 'none' : '';
|
||||
});
|
||||
// 隐藏空的 section-title
|
||||
document.querySelectorAll('.nav-section').forEach(function(section) {
|
||||
var hasVisible = false;
|
||||
section.querySelectorAll('.nav-item[data-feature]').forEach(function(item) {
|
||||
if (item.style.display !== 'none') hasVisible = true;
|
||||
});
|
||||
var title = section.querySelector('.nav-section-title');
|
||||
if (title && title.textContent.trim() !== '概览') {
|
||||
title.style.display = hasVisible ? '' : 'none';
|
||||
function buildSidebar() {
|
||||
var hidden = _hiddenFeatures;
|
||||
var overviewSection = document.getElementById('nav-section-overview');
|
||||
var toolsSection = document.getElementById('nav-section-tools');
|
||||
|
||||
overviewSection.querySelectorAll('.nav-item').forEach(function(el) { el.remove(); });
|
||||
toolsSection.querySelectorAll('.nav-item').forEach(function(el) { el.remove(); });
|
||||
|
||||
NAV_ITEMS.forEach(function(item) {
|
||||
if (hidden.indexOf(item.id) !== -1) return;
|
||||
var a = document.createElement('a');
|
||||
a.className = 'nav-item';
|
||||
a.setAttribute('data-feature', item.id);
|
||||
if (item.id === 'dashboard') {
|
||||
a.id = 'nav-dashboard';
|
||||
a.classList.add('active');
|
||||
a.onclick = function() { showDashboard(); };
|
||||
} else {
|
||||
a.setAttribute('data-url', item.url);
|
||||
a.onclick = function() { loadTool(this, item.url); };
|
||||
}
|
||||
a.innerHTML = '<i class="fas ' + item.icon + '"></i>' + item.name;
|
||||
if (item.section === '概览') overviewSection.appendChild(a);
|
||||
else toolsSection.appendChild(a);
|
||||
});
|
||||
}
|
||||
|
||||
function openFeatModal() {
|
||||
var hidden = getHiddenFeatures();
|
||||
var hidden = _hiddenFeatures;
|
||||
var body = document.getElementById('featModalBody');
|
||||
var html = '';
|
||||
var currentSection = '';
|
||||
FEATURES.forEach(function(f) {
|
||||
NAV_ITEMS.forEach(function(f) {
|
||||
if (f.section !== currentSection) {
|
||||
currentSection = f.section;
|
||||
html += '<div class="feat-group-title">' + currentSection + '</div>';
|
||||
@@ -1415,15 +1338,31 @@
|
||||
document.querySelectorAll('#featModalBody input[type="checkbox"]').forEach(function(cb) {
|
||||
if (!cb.checked) hidden.push(cb.getAttribute('data-feature-id'));
|
||||
});
|
||||
localStorage.setItem('hidden_features', JSON.stringify(hidden));
|
||||
applyFeatSettings();
|
||||
document.getElementById('featModalOverlay').classList.remove('show');
|
||||
fetch('/api/sidebar-config', {
|
||||
method: 'POST',
|
||||
headers: {'Content-Type': 'application/json'},
|
||||
body: JSON.stringify({hidden_features: hidden})
|
||||
})
|
||||
.then(function(r) { return r.json(); })
|
||||
.then(function() {
|
||||
_hiddenFeatures = hidden;
|
||||
buildSidebar();
|
||||
document.getElementById('featModalOverlay').classList.remove('show');
|
||||
});
|
||||
}
|
||||
|
||||
// 页面加载时应用功能显示设置
|
||||
applyFeatSettings();
|
||||
|
||||
loadDashboard();
|
||||
// 页面加载时从接口获取配置再构建侧边栏
|
||||
fetch('/api/sidebar-config')
|
||||
.then(function(r) { return r.json(); })
|
||||
.then(function(data) {
|
||||
_hiddenFeatures = data.hidden_features || [];
|
||||
buildSidebar();
|
||||
loadDashboard();
|
||||
})
|
||||
.catch(function() {
|
||||
buildSidebar();
|
||||
loadDashboard();
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
Reference in New Issue
Block a user