Files
nl-tools/UI设计.html
2025-12-11 09:47:00 +08:00

461 lines
27 KiB
HTML
Raw Permalink 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.
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>奶酪云工具箱 | Cheese Cloud Tools</title>
<!-- 引入 Tailwind CSS -->
<script src="https://cdn.tailwindcss.com"></script>
<!-- 引入 Phosphor Icons 图标库 -->
<script src="https://unpkg.com/@phosphor-icons/web"></script>
<!-- Google Fonts: Inter -->
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600&display=swap" rel="stylesheet">
<script>
tailwind.config = {
darkMode: 'class',
theme: {
extend: {
fontFamily: {
sans: ['Inter', 'sans-serif'],
},
colors: {
cheese: {
50: '#fffbeb',
100: '#fef3c7',
200: '#fde68a',
300: '#fcd34d',
400: '#fbbf24', // 主色
500: '#f59e0b', // 深色
600: '#d97706',
900: '#78350f',
},
darkbg: {
900: '#0f172a', // 主背景
800: '#1e293b', // 侧边栏
700: '#334155', // 边框/悬浮
}
},
animation: {
'fade-in': 'fadeIn 0.3s ease-out',
'slide-up': 'slideUp 0.4s ease-out',
'pulse-slow': 'pulse 3s cubic-bezier(0.4, 0, 0.6, 1) infinite',
},
keyframes: {
fadeIn: {
'0%': { opacity: '0' },
'100%': { opacity: '1' },
},
slideUp: {
'0%': { transform: 'translateY(10px)', opacity: '0' },
'100%': { transform: 'translateY(0)', opacity: '1' },
}
}
}
}
}
</script>
<style>
::-webkit-scrollbar { width: 6px; height: 6px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb { background: #334155; border-radius: 3px; }
::-webkit-scrollbar-thumb:hover { background: #475569; }
.glass-panel {
background: rgba(30, 41, 59, 0.7);
backdrop-filter: blur(12px);
-webkit-backdrop-filter: blur(12px);
border: 1px solid rgba(255, 255, 255, 0.05);
}
.active-nav-item::before {
content: '';
position: absolute;
left: 0;
top: 50%;
transform: translateY(-50%);
height: 60%;
width: 3px;
background-color: #fbbf24;
border-radius: 0 4px 4px 0;
box-shadow: 0 0 10px #fbbf24;
}
/* 模拟 PDF 页面选中效果 */
.pdf-page-selected {
border-color: #fbbf24;
box-shadow: 0 0 0 2px rgba(251, 191, 36, 0.3);
}
.pdf-page-selected .check-icon {
opacity: 1;
}
</style>
</head>
<body class="bg-darkbg-900 text-slate-300 font-sans h-screen w-screen overflow-hidden flex selection:bg-cheese-500 selection:text-white">
<!-- 1. 左侧一级菜单 -->
<aside class="w-20 bg-darkbg-800 flex flex-col items-center py-6 border-r border-darkbg-700 z-20 flex-shrink-0 shadow-2xl">
<div class="mb-8 relative group cursor-pointer">
<div class="w-12 h-12 rounded-2xl bg-gradient-to-br from-cheese-400 to-cheese-600 flex items-center justify-center shadow-lg shadow-cheese-500/20 transform group-hover:scale-105 transition-all duration-300 overflow-hidden">
<i class="ph-fill ph-cheese text-2xl text-white"></i>
</div>
<span class="absolute left-14 top-1/2 -translate-y-1/2 bg-black text-xs px-2 py-1 rounded opacity-0 group-hover:opacity-100 transition pointer-events-none whitespace-nowrap z-50">奶酪云</span>
</div>
<nav class="flex-1 w-full space-y-4">
<div onclick="switchCategory('image')" id="nav-image" class="group relative w-full flex items-center justify-center cursor-pointer active-nav-item">
<div class="w-10 h-10 rounded-xl bg-darkbg-700/50 group-hover:bg-cheese-500/20 text-cheese-400 flex items-center justify-center transition-all duration-300">
<i class="ph ph-image text-2xl"></i>
</div>
</div>
<div onclick="switchCategory('pdf')" id="nav-pdf" class="group relative w-full flex items-center justify-center cursor-pointer">
<div class="w-10 h-10 rounded-xl group-hover:bg-darkbg-700 text-slate-400 group-hover:text-cheese-400 flex items-center justify-center transition-all duration-300">
<i class="ph ph-file-pdf text-2xl"></i>
</div>
</div>
<div onclick="switchCategory('excel')" id="nav-excel" class="group relative w-full flex items-center justify-center cursor-pointer">
<div class="w-10 h-10 rounded-xl group-hover:bg-darkbg-700 text-slate-400 group-hover:text-cheese-400 flex items-center justify-center transition-all duration-300">
<i class="ph ph-file-xls text-2xl"></i>
</div>
</div>
</nav>
<div class="mt-auto">
<div class="w-10 h-10 rounded-xl hover:bg-darkbg-700 text-slate-500 hover:text-white flex items-center justify-center transition-all cursor-pointer">
<i class="ph ph-gear text-2xl"></i>
</div>
</div>
</aside>
<!-- 2. 中间二级菜单 -->
<div class="w-64 bg-darkbg-800/50 backdrop-blur-md border-r border-darkbg-700 flex flex-col z-10 flex-shrink-0 transition-all duration-300" id="secondary-sidebar">
<div class="h-20 flex items-center px-6 border-b border-darkbg-700/50">
<h2 class="text-xl font-semibold text-white tracking-wide" id="category-title">图片工具</h2>
</div>
<div class="p-4">
<div class="relative group">
<i class="ph ph-magnifying-glass absolute left-3 top-1/2 -translate-y-1/2 text-slate-500 group-focus-within:text-cheese-400 transition-colors"></i>
<input type="text" placeholder="搜索功能..." class="w-full bg-darkbg-900 border border-darkbg-700 text-sm text-slate-200 rounded-lg pl-9 pr-3 py-2.5 focus:outline-none focus:border-cheese-500/50 focus:ring-1 focus:ring-cheese-500/50 transition-all placeholder-slate-600">
</div>
</div>
<div class="flex-1 overflow-y-auto px-3 pb-4 space-y-1" id="tool-list">
<!-- 动态生成内容 -->
</div>
<div class="p-4 border-t border-darkbg-700/50 bg-darkbg-800/30">
<div class="flex items-center gap-3">
<div class="w-8 h-8 rounded-full bg-gradient-to-r from-purple-500 to-indigo-500 flex items-center justify-center text-xs font-bold text-white shadow-inner">SV</div>
<div class="flex-1 overflow-hidden">
<p class="text-xs font-medium text-white truncate">超级会员</p>
<p class="text-[10px] text-slate-400 truncate">有效期至 2026-10</p>
</div>
</div>
</div>
</div>
<!-- 3. 右侧大区域 -->
<main class="flex-1 bg-darkbg-900 relative flex flex-col h-full overflow-hidden">
<div class="absolute top-0 left-0 w-full h-full overflow-hidden pointer-events-none">
<div class="absolute -top-[10%] -right-[10%] w-[500px] h-[500px] bg-cheese-500/10 rounded-full blur-[100px]"></div>
<div class="absolute top-[20%] left-[10%] w-[300px] h-[300px] bg-purple-500/5 rounded-full blur-[80px]"></div>
</div>
<header class="h-20 flex items-center justify-between px-8 border-b border-darkbg-700/30 z-10 glass-panel bg-opacity-30 flex-shrink-0">
<div class="flex flex-col">
<div class="flex items-center gap-2 text-xs text-slate-500 mb-1">
<span id="breadcrumb-category">首页</span>
<i class="ph ph-caret-right"></i>
<span id="breadcrumb-tool" class="text-cheese-400">控制台</span>
</div>
<h1 class="text-2xl font-bold text-white flex items-center gap-2 animate-slide-up" id="workspace-title">欢迎回来</h1>
</div>
<div class="flex gap-3">
<button class="px-4 py-2 text-sm rounded-lg border border-darkbg-700 text-slate-300 hover:bg-darkbg-700 transition flex items-center gap-2">
<i class="ph ph-clock-counter-clockwise"></i> 历史
</button>
<button class="px-4 py-2 text-sm rounded-lg bg-cheese-500 hover:bg-cheese-400 text-white shadow-lg shadow-cheese-500/20 transition transform hover:scale-105 flex items-center gap-2 font-medium">
<i class="ph ph-export"></i> 导出
</button>
</div>
</header>
<div class="flex-1 p-8 overflow-y-auto z-10 scroll-smooth" id="workspace-content">
<!-- 默认欢迎页 -->
<div class="h-full flex flex-col items-center justify-center text-center animate-fade-in">
<div class="w-32 h-32 mb-6 rounded-full bg-darkbg-800 border border-darkbg-700 flex items-center justify-center shadow-2xl relative">
<div class="absolute inset-0 rounded-full bg-cheese-500/20 blur-xl animate-pulse-slow"></div>
<i class="ph-duotone ph-cheese text-6xl text-cheese-400"></i>
</div>
<h2 class="text-3xl font-bold text-white mb-3">开始你的创作</h2>
<p class="text-slate-400 max-w-md mx-auto mb-8">
从左侧选择一个工具。无论是压缩图片、拆分PDF还是处理数据我们都能搞定。
</p>
<div class="grid grid-cols-1 md:grid-cols-3 gap-4 w-full max-w-3xl">
<div onclick="simulateClickTool('img-compress', 'image')" class="p-4 rounded-xl bg-darkbg-800/50 border border-darkbg-700 hover:border-cheese-500/50 hover:bg-darkbg-800 transition cursor-pointer group text-left">
<div class="w-10 h-10 rounded-lg bg-blue-500/10 text-blue-400 flex items-center justify-center mb-3 group-hover:scale-110 transition"><i class="ph ph-image-square text-xl"></i></div>
<h3 class="text-white font-medium mb-1">图片压缩</h3>
<p class="text-xs text-slate-500">智能无损压缩</p>
</div>
<div onclick="simulateClickTool('pdf-split', 'pdf')" class="p-4 rounded-xl bg-darkbg-800/50 border border-darkbg-700 hover:border-cheese-500/50 hover:bg-darkbg-800 transition cursor-pointer group text-left">
<div class="w-10 h-10 rounded-lg bg-red-500/10 text-red-400 flex items-center justify-center mb-3 group-hover:scale-110 transition"><i class="ph ph-scissors text-xl"></i></div>
<h3 class="text-white font-medium mb-1">PDF 拆分</h3>
<p class="text-xs text-slate-500">提取特定页面</p>
</div>
<div onclick="simulateClickTool('img-convert', 'image')" class="p-4 rounded-xl bg-darkbg-800/50 border border-darkbg-700 hover:border-cheese-500/50 hover:bg-darkbg-800 transition cursor-pointer group text-left">
<div class="w-10 h-10 rounded-lg bg-green-500/10 text-green-400 flex items-center justify-center mb-3 group-hover:scale-110 transition"><i class="ph ph-arrows-left-right text-xl"></i></div>
<h3 class="text-white font-medium mb-1">格式转换</h3>
<p class="text-xs text-slate-500">格式互转工具</p>
</div>
</div>
</div>
</div>
</main>
<script>
const toolsData = {
image: {
title: "图片工具",
items: [
{ id: "img-compress", name: "图片压缩", icon: "ph-arrows-in-line-horizontal", desc: "智能无损压缩" },
{ id: "img-convert", name: "格式转换", icon: "ph-arrows-left-right", desc: "JPG/PNG/WEBP" },
{ id: "img-watermark", name: "图片加水印", icon: "ph-stamp", desc: "批量添加水印" },
]
},
pdf: {
title: "PDF 工具箱",
items: [
{ id: "pdf-split", name: "PDF 拆分", icon: "ph-scissors", desc: "提取指定页面" },
{ id: "pdf-merge", name: "PDF 合并", icon: "ph-files", desc: "多文件合并" },
{ id: "pdf-word", name: "PDF 转 Word", icon: "ph-microsoft-word-logo", desc: "保持排版转换" },
]
},
excel: {
title: "Excel 表格",
items: [
{ id: "xls-view", name: "Excel 预览", icon: "ph-eye", desc: "在线查看表格" },
{ id: "xls-chart", name: "图表生成", icon: "ph-chart-bar", desc: "数据可视化" },
]
}
};
let currentCategory = 'image';
let currentToolId = null;
document.addEventListener('DOMContentLoaded', () => { renderToolList('image'); });
function switchCategory(cat) {
currentCategory = cat;
document.querySelectorAll('.active-nav-item').forEach(el => {
el.classList.remove('active-nav-item');
el.querySelector('div').classList.remove('bg-darkbg-700/50', 'text-cheese-400');
el.querySelector('div').classList.add('text-slate-400');
});
const activeBtn = document.getElementById(`nav-${cat}`);
activeBtn.classList.add('active-nav-item');
activeBtn.querySelector('div').classList.replace('text-slate-400', 'text-cheese-400');
activeBtn.querySelector('div').classList.add('bg-darkbg-700/50');
document.getElementById('category-title').innerText = toolsData[cat].title;
renderToolList(cat);
const sidebar = document.getElementById('secondary-sidebar');
sidebar.classList.remove('opacity-100'); sidebar.classList.add('opacity-0');
setTimeout(() => { sidebar.classList.remove('opacity-0'); sidebar.classList.add('opacity-100'); }, 50);
}
function renderToolList(cat) {
const listContainer = document.getElementById('tool-list');
listContainer.innerHTML = '';
toolsData[cat].items.forEach(tool => {
const item = document.createElement('div');
item.className = `p-3 rounded-lg cursor-pointer transition-all duration-200 group hover:bg-darkbg-700/50 ${currentToolId === tool.id ? 'bg-darkbg-700 border-l-2 border-cheese-400' : ''}`;
item.onclick = () => selectTool(tool);
item.id = `tool-item-${tool.id}`;
item.innerHTML = `
<div class="flex items-center gap-3">
<div class="w-8 h-8 rounded-md bg-darkbg-900 border border-darkbg-700 flex items-center justify-center text-slate-400 group-hover:text-cheese-400 group-hover:border-cheese-500/30 transition-colors">
<i class="ph ${tool.icon} text-lg"></i>
</div>
<div>
<h4 class="text-sm font-medium text-slate-200 group-hover:text-white">${tool.name}</h4>
<p class="text-[10px] text-slate-500 truncate w-32">${tool.desc}</p>
</div>
</div>`;
listContainer.appendChild(item);
});
}
function selectTool(tool) {
currentToolId = tool.id;
renderToolList(currentCategory);
const workspace = document.getElementById('workspace-content');
document.getElementById('breadcrumb-category').innerText = toolsData[currentCategory].title;
document.getElementById('breadcrumb-tool').innerText = tool.name;
document.getElementById('workspace-title').innerHTML = `${tool.name} <span class="text-sm font-normal text-slate-500 ml-2 bg-darkbg-800 px-2 py-0.5 rounded border border-darkbg-700">v2.1</span>`;
workspace.innerHTML = `<div class="h-full flex items-center justify-center"><i class="ph ph-spinner animate-spin text-4xl text-cheese-400"></i></div>`;
setTimeout(() => {
let contentHTML = '';
// 现在所有功能都先生成头部,再生成各自独特的内容
if (tool.id === 'img-compress') contentHTML = renderCompressUI(tool);
else if (tool.id === 'img-convert') contentHTML = renderConvertUI(tool);
else if (tool.id === 'pdf-split') contentHTML = renderPDFSplitUI(tool);
else if (tool.id === 'pdf-merge') contentHTML = renderPDFMergeUI(tool);
else contentHTML = renderDefaultUI(tool);
workspace.innerHTML = `<div class="animate-slide-up max-w-6xl mx-auto flex flex-col gap-6">${contentHTML}</div>`;
}, 300);
}
function simulateClickTool(toolId, cat) {
switchCategory(cat);
setTimeout(() => {
const tool = toolsData[cat].items.find(t => t.id === toolId);
if (tool) selectTool(tool);
}, 100);
}
// ==================== 统一的上传区域组件 ====================
function getUploadAreaHTML(toolName) {
return `
<div class="w-full h-52 border-2 border-dashed border-darkbg-700 rounded-2xl bg-darkbg-800/30 flex flex-col items-center justify-center hover:border-cheese-500/50 hover:bg-darkbg-800/50 transition-all cursor-pointer group relative overflow-hidden flex-shrink-0">
<div class="absolute inset-0 bg-gradient-to-tr from-cheese-500/5 to-transparent opacity-0 group-hover:opacity-100 transition duration-500"></div>
<div class="z-10 flex flex-col items-center">
<div class="w-14 h-14 rounded-full bg-darkbg-700 flex items-center justify-center mb-3 group-hover:scale-110 transition duration-300 shadow-lg">
<i class="ph ph-cloud-arrow-up text-3xl text-cheese-400"></i>
</div>
<h3 class="text-lg font-medium text-white mb-1">点击或拖拽文件到此处</h3>
<p class="text-sm text-slate-500">支持批量上传 (${toolName})</p>
</div>
</div>
`;
}
/* ==================== 1. 图片压缩 UI ==================== */
function renderCompressUI(tool) {
// 下方功能区:左侧预览,右侧设置
const specificContent = `
<div class="grid grid-cols-1 lg:grid-cols-3 gap-6 flex-1">
<!-- 预览区 -->
<div class="lg:col-span-2 bg-darkbg-800/50 border border-darkbg-700 rounded-2xl p-4 flex items-center justify-center relative min-h-[300px]">
<div class="text-center">
<i class="ph ph-image text-5xl text-slate-600 mb-3"></i>
<p class="text-slate-400 text-sm">上传图片后在此处预览效果</p>
</div>
<span class="absolute top-4 left-4 bg-black/50 text-white text-xs px-2 py-1 rounded backdrop-blur">原始预览</span>
</div>
<!-- 设置区 -->
<div class="bg-darkbg-800 border border-darkbg-700 rounded-2xl p-6 h-fit">
<h3 class="font-bold text-white mb-4 flex items-center gap-2"><i class="ph ph-sliders"></i> 压缩设置</h3>
<div class="mb-6">
<div class="flex justify-between mb-2">
<span class="text-sm text-slate-300">压缩强度</span>
<span class="text-sm text-cheese-400 font-bold">75%</span>
</div>
<input type="range" class="w-full h-2 bg-darkbg-900 rounded-lg appearance-none cursor-pointer accent-cheese-500" value="75">
</div>
<button class="w-full py-3 bg-cheese-500 hover:bg-cheese-400 text-white rounded-xl font-bold shadow-lg shadow-cheese-500/20 flex items-center justify-center gap-2">
<i class="ph ph-download-simple"></i> 开始压缩
</button>
</div>
</div>
`;
return getUploadAreaHTML(tool.name) + specificContent;
}
/* ==================== 2. 格式转换 UI ==================== */
function renderConvertUI(tool) {
const formats = ['JPG', 'PNG', 'WEBP', 'PDF', 'ICO'];
const specificContent = `
<div class="bg-darkbg-800/50 backdrop-blur border border-darkbg-700 rounded-2xl p-8 text-center mt-2">
<h3 class="text-lg text-white mb-6">选择目标格式</h3>
<div class="flex flex-wrap justify-center gap-4 mb-8">
${formats.map(fmt => `
<label class="cursor-pointer">
<input type="radio" name="format" class="peer sr-only" ${fmt === 'WEBP' ? 'checked' : ''}>
<div class="px-6 py-3 rounded-xl border border-darkbg-600 bg-darkbg-900 text-slate-400 hover:bg-darkbg-700 peer-checked:bg-cheese-500 peer-checked:text-white peer-checked:border-cheese-500 peer-checked:shadow-lg transition-all text-sm font-medium">
${fmt}
</div>
</label>
`).join('')}
</div>
<div class="border-t border-darkbg-700 pt-6 flex justify-end">
<button class="px-8 py-2.5 bg-white text-darkbg-900 rounded-lg font-bold hover:bg-slate-200 transition">开始转换</button>
</div>
</div>
`;
return getUploadAreaHTML(tool.name) + specificContent;
}
/* ==================== 3. PDF 拆分 UI ==================== */
function renderPDFSplitUI(tool) {
let pagesHTML = '';
for(let i=1; i<=12; i++) {
pagesHTML += `
<div class="relative group cursor-pointer" onclick="this.querySelector('.page-card').classList.toggle('pdf-page-selected')">
<div class="page-card aspect-[1/1.4] bg-white rounded-lg border-2 border-transparent hover:shadow-lg transition-all relative overflow-hidden flex items-center justify-center">
<div class="text-xs text-slate-400">Page ${i}</div>
<div class="absolute inset-0 bg-cheese-500/10 hidden group-hover:block"></div>
<div class="check-icon absolute top-2 right-2 w-5 h-5 bg-cheese-500 rounded-full flex items-center justify-center text-white text-xs opacity-0 transition-opacity shadow"><i class="ph-bold ph-check"></i></div>
</div>
</div>
`;
}
const specificContent = `
<div class="flex flex-col h-full mt-2">
<div class="flex items-center justify-between mb-4">
<h3 class="text-lg font-bold text-white">选择页面</h3>
<div class="flex gap-3">
<button class="text-xs text-cheese-400 hover:text-cheese-300">全选</button>
<button class="text-xs text-slate-400 hover:text-white">清空</button>
</div>
</div>
<div class="bg-darkbg-800/30 border border-darkbg-700 rounded-2xl p-6 overflow-y-auto max-h-[400px]">
<div class="grid grid-cols-2 sm:grid-cols-4 md:grid-cols-6 gap-6">
${pagesHTML}
</div>
</div>
<div class="mt-6 flex justify-end">
<button class="px-6 py-2 bg-cheese-500 hover:bg-cheese-400 text-white rounded-lg font-bold shadow-lg shadow-cheese-500/20">拆分选定页</button>
</div>
</div>
`;
return getUploadAreaHTML(tool.name) + specificContent;
}
/* ==================== 4. PDF 合并 UI ==================== */
function renderPDFMergeUI(tool) {
const files = [
{ name: '2023年度财务报表.pdf', size: '2.4 MB' },
{ name: 'Q4 销售数据分析.pdf', size: '1.1 MB' },
];
const specificContent = `
<div class="mt-4">
<h3 class="text-lg font-bold text-white mb-4">待合并文件列表 (可拖拽排序)</h3>
<div class="space-y-3 mb-8">
${files.map(file => `
<div class="bg-darkbg-800 border border-darkbg-700 rounded-lg p-3 flex items-center gap-4 hover:border-cheese-500/30 transition group">
<div class="cursor-grab text-slate-600 hover:text-slate-300 px-2"><i class="ph ph-dots-six-vertical text-xl"></i></div>
<div class="w-10 h-10 bg-red-500/10 rounded text-red-400 flex items-center justify-center"><i class="ph ph-file-pdf text-xl"></i></div>
<div class="flex-1"><h4 class="text-sm text-slate-200 font-medium">${file.name}</h4><p class="text-xs text-slate-500">${file.size}</p></div>
<button class="p-2 hover:bg-darkbg-700 rounded text-slate-400 hover:text-red-400"><i class="ph ph-trash"></i></button>
</div>
`).join('')}
</div>
<button class="w-full py-3 bg-cheese-500 hover:bg-cheese-400 text-white rounded-xl font-bold text-lg shadow-lg shadow-cheese-500/20">合并为单个 PDF</button>
</div>
`;
return getUploadAreaHTML(tool.name) + specificContent;
}
/* ==================== 5. 默认 UI ==================== */
function renderDefaultUI(tool) {
return getUploadAreaHTML(tool.name);
}
</script>
</body>
</html>