Compare commits
7 Commits
29aa86471f
...
bfe00cc98f
| Author | SHA1 | Date |
|---|---|---|
|
|
bfe00cc98f | |
|
|
0f531d1b91 | |
|
|
e4fc12140c | |
|
|
67537d6995 | |
|
|
56cd3108ed | |
|
|
b646d9ef39 | |
|
|
b39e0c7f28 |
|
|
@ -44,11 +44,11 @@
|
||||||
--slate-900: #111827;
|
--slate-900: #111827;
|
||||||
|
|
||||||
/* Indigo Palette (Primary) - Slightly more sophisticated */
|
/* Indigo Palette (Primary) - Slightly more sophisticated */
|
||||||
--indigo-50: #eef2ff;
|
--indigo-50: #FFFFFF;
|
||||||
--indigo-100: #e0e7ff;
|
--indigo-100: #f3f4f5;
|
||||||
--indigo-500: #6366f1;
|
--indigo-500: #0949ec;
|
||||||
--indigo-600: #4f46e5;
|
--indigo-600: #003dd6;
|
||||||
--indigo-700: #4338ca;
|
--indigo-700: rgb(45, 32, 185);
|
||||||
|
|
||||||
/* Semantic Mapping */
|
/* Semantic Mapping */
|
||||||
--color-primary: var(--indigo-600);
|
--color-primary: var(--indigo-600);
|
||||||
|
|
|
||||||
|
|
@ -56,6 +56,8 @@
|
||||||
#immersive-toc-area.immersive-panel {
|
#immersive-toc-area.immersive-panel {
|
||||||
padding: var(--spacing-xs) var(--spacing-sm) 0 var(--spacing-sm);
|
padding: var(--spacing-xs) var(--spacing-sm) 0 var(--spacing-sm);
|
||||||
border-right: 1px solid var(--color-border-light);
|
border-right: 1px solid var(--color-border-light);
|
||||||
|
/* 隐藏沉浸模式侧边栏 */
|
||||||
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
#immersive-chatbot-area.immersive-panel {
|
#immersive-chatbot-area.immersive-panel {
|
||||||
|
|
@ -788,6 +790,7 @@ body.immersive-active #immersive-main-content-area .container {
|
||||||
|
|
||||||
#immersive-toc-area {
|
#immersive-toc-area {
|
||||||
min-width: 200px;
|
min-width: 200px;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#immersive-chatbot-area {
|
#immersive-chatbot-area {
|
||||||
|
|
|
||||||
|
|
@ -34,7 +34,7 @@ body {
|
||||||
display: flex;
|
display: flex;
|
||||||
gap: 1.5rem; /* 大幅增加间距,更现代 */
|
gap: 1.5rem; /* 大幅增加间距,更现代 */
|
||||||
border-bottom: 1px solid var(--color-border-light);
|
border-bottom: 1px solid var(--color-border-light);
|
||||||
margin-bottom: 2.5rem;
|
/* margin-bottom: 2.5rem; */
|
||||||
padding-bottom: 0;
|
padding-bottom: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -78,7 +78,7 @@ h2 {
|
||||||
|
|
||||||
.history-export-controls {
|
.history-export-controls {
|
||||||
position: relative;
|
position: relative;
|
||||||
margin-bottom: 16px;
|
/* margin-bottom: 16px; */
|
||||||
}
|
}
|
||||||
|
|
||||||
.export-panel-backdrop {
|
.export-panel-backdrop {
|
||||||
|
|
|
||||||
|
|
@ -48,7 +48,8 @@
|
||||||
color: #94a3b8 !important; /* slate-400 */
|
color: #94a3b8 !important; /* slate-400 */
|
||||||
border: 1px solid #e2e8f0 !important;
|
border: 1px solid #e2e8f0 !important;
|
||||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05) !important;
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05) !important;
|
||||||
display: flex !important;
|
/* 隐藏沉浸模式的出口 */
|
||||||
|
display: flex;
|
||||||
align-items: center !important;
|
align-items: center !important;
|
||||||
justify-content: center !important;
|
justify-content: center !important;
|
||||||
cursor: pointer !important;
|
cursor: pointer !important;
|
||||||
|
|
|
||||||
|
|
@ -986,6 +986,7 @@ body.immersive-dragging .immersive-resize-handle {
|
||||||
|
|
||||||
#immersive-toc-area {
|
#immersive-toc-area {
|
||||||
min-width: 200px;
|
min-width: 200px;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#immersive-chatbot-area {
|
#immersive-chatbot-area {
|
||||||
|
|
|
||||||
150
index.html
150
index.html
|
|
@ -543,80 +543,43 @@
|
||||||
<!-- 侧边栏 (Responsive) -->
|
<!-- 侧边栏 (Responsive) -->
|
||||||
<!-- ===================== -->
|
<!-- ===================== -->
|
||||||
<aside id="appSidebar" class="app-sidebar">
|
<aside id="appSidebar" class="app-sidebar">
|
||||||
<div class="px-6 py-5 flex items-center justify-between transition-all" id="sidebarHeader">
|
|
||||||
<!-- <a href="views/landing/landing-page.html" class="hover:opacity-80 transition-opacity" title="返回落地页">
|
|
||||||
<img id="sidebarLogo" src="public/h_with_name.svg" class="h-8 transition-all" alt="Paper Burner X">
|
|
||||||
</a> -->
|
|
||||||
<!-- 占位元素 -->
|
|
||||||
<span></span>
|
|
||||||
<!-- Desktop Collapse Button -->
|
|
||||||
<button id="sidebarToggleBtn" class="hidden md:flex text-slate-400 hover:text-slate-600 p-1.5 hover:bg-slate-100 rounded-md transition-colors" title="切换侧边栏">
|
|
||||||
<iconify-icon id="sidebarToggleIcon" icon="carbon:side-panel-close" width="20"></iconify-icon>
|
|
||||||
</button>
|
|
||||||
<!-- Mobile Close Button -->
|
|
||||||
<button id="sidebarCloseBtn" class="md:flex md:hidden p-2 text-slate-400 hover:text-slate-700 hover:bg-slate-100 rounded-lg transition-colors">
|
|
||||||
<iconify-icon icon="carbon:close" width="20"></iconify-icon>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<nav class="flex-1 px-3 py-4 space-y-1 overflow-y-auto custom-scrollbar overflow-x-hidden">
|
<nav class="flex-1 px-3 py-4 space-y-1 overflow-y-auto custom-scrollbar overflow-x-hidden">
|
||||||
<div class="nav-section-title px-3 mb-2 text-[11px] font-bold text-slate-400 uppercase tracking-wider transition-opacity">
|
|
||||||
主要功能
|
|
||||||
</div>
|
|
||||||
<div class="nav-item active cursor-pointer" title="工作台">
|
|
||||||
<iconify-icon icon="carbon:dashboard" class="nav-icon"></iconify-icon>
|
|
||||||
<span class="nav-text transition-opacity">工作台</span>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- 可折叠的历史记录菜单 (Split Action) -->
|
<!-- 可折叠的历史记录菜单 (Split Action) -->
|
||||||
<div id="historyMenuContainer">
|
<div id="historyMenuContainer" class="mb-4">
|
||||||
<div class="flex items-stretch mb-0.5 select-none group">
|
<div
|
||||||
<div id="sidebarHistoryMainBtn" class="flex-1 flex items-center px-[0.875rem] py-[0.75rem] text-[0.9375rem] font-medium text-slate-600 hover:bg-slate-100 hover:text-slate-900 cursor-pointer rounded-lg transition-all" title="打开完整历史记录面板">
|
class="flex items-stretch select-none group bg-white border border-slate-200 overflow-hidden">
|
||||||
<iconify-icon icon="carbon:time" class="nav-icon mr-[0.75rem] text-[1.25rem] text-slate-400 group-hover:text-slate-500 transition-colors"></iconify-icon>
|
<div id="sidebarHistoryMainBtn"
|
||||||
<span class="nav-text transition-opacity">历史记录</span>
|
class="flex-1 flex items-center px-4 py-3 text-sm font-medium text-slate-600 hover:bg-[#000f33] hover:text-[#ffffff] cursor-pointer transition-all"
|
||||||
|
title="打开完整历史记录面板">
|
||||||
|
<!-- <iconify-icon icon="carbon:time"
|
||||||
|
class="mr-3 text-lg text-[#000f33] group-hover:text-[#ffffff] transition-colors"></iconify-icon> -->
|
||||||
|
<span>历史记录</span>
|
||||||
|
</div>
|
||||||
|
<button id="sidebarHistoryToggleBtn"
|
||||||
|
class="flex items-center justify-center px-3 hover:bg-[#000f33] text-slate-300 hover:text-slate-500 cursor-pointer transition-colors"
|
||||||
|
title="展开/收起最近记录">
|
||||||
|
<iconify-icon icon="carbon:chevron-right" class="transition-transform duration-200"
|
||||||
|
id="sidebarHistoryChevron" width="16"></iconify-icon>
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<button id="sidebarHistoryToggleBtn" class="flex items-center justify-center px-2 hover:bg-slate-100 text-slate-300 hover:text-slate-500 cursor-pointer rounded-r-lg transition-colors" title="展开/收起最近记录">
|
<div id="sidebarHistoryQuickList"
|
||||||
<iconify-icon icon="carbon:chevron-right" class="transition-transform duration-200" id="sidebarHistoryChevron" width="16"></iconify-icon>
|
class="hidden py-1 space-y-0.5 pl-2 transition-all bg-white border border-slate-200">
|
||||||
</button>
|
<!-- JS 将在此处填充最近记录 -->
|
||||||
</div>
|
<div class="px-3 py-2 text-xs text-slate-400 text-center">加载中...</div>
|
||||||
<div id="sidebarHistoryQuickList" class="hidden py-1 space-y-0.5 pl-2 transition-all">
|
</div>
|
||||||
<!-- JS 将在此处填充最近记录 -->
|
</div>
|
||||||
<div class="px-3 py-2 text-xs text-slate-400 text-center">加载中...</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="my-4 border-t border-slate-100 mx-3 transition-all" id="sidebarDivider"></div>
|
<div class="my-4 border-t border-slate-100 mx-3 transition-all" id="sidebarDivider"></div>
|
||||||
<!-- <div class="nav-section-title px-3 mb-2 text-[11px] font-bold text-slate-400 uppercase tracking-wider transition-opacity">
|
|
||||||
系统
|
|
||||||
</div>
|
|
||||||
<div id="sidebarSettingsBtn" class="nav-item cursor-pointer" title="全局设置">
|
|
||||||
<iconify-icon icon="carbon:settings" class="nav-icon"></iconify-icon>
|
|
||||||
<span class="nav-text transition-opacity">全局设置</span>
|
|
||||||
</div> -->
|
|
||||||
</nav>
|
</nav>
|
||||||
<!-- 删除界面会加载不出来 -->
|
|
||||||
<div class="p-3 transition-all" id="sidebarFooter">
|
|
||||||
<div class="p-4 overflow-hidden">
|
|
||||||
|
|
||||||
</div>
|
|
||||||
<div class="text-center py-1 mt-1 nav-text transition-opacity">
|
|
||||||
<span id="showCopyrightModal" class="text-[11px] text-slate-400 hover:text-slate-600 transition-colors cursor-pointer select-none">
|
|
||||||
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<!-- 收起状态的底部按钮 -->
|
|
||||||
<div id="sidebarFooterCollapsed" class="hidden flex-col items-center p-3">
|
|
||||||
<a href="https://github.com/Feather-2/paper-burner" target="_blank" class="w-10 h-10 flex items-center justify-center text-slate-400 hover:text-slate-600 transition-colors" title="GitHub 仓库">
|
|
||||||
<iconify-icon icon="mdi:github" width="28"></iconify-icon>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
</aside>
|
</aside>
|
||||||
|
|
||||||
<!-- ===================== -->
|
<!-- ===================== -->
|
||||||
<!-- 主内容区 -->
|
<!-- 主内容区 -->
|
||||||
<!-- ===================== -->
|
<!-- ===================== -->
|
||||||
<main class="app-main flex flex-col">
|
<main class="app-main flex flex-col">
|
||||||
<!-- 移动端 Header -->
|
<!-- 移动端 Header
|
||||||
<header class="md:hidden bg-white/80 backdrop-blur-md border-b border-slate-200 px-4 py-3 flex items-center justify-between sticky top-0 z-10">
|
<header class="md:hidden bg-white/80 backdrop-blur-md border-b border-slate-200 px-4 py-3 flex items-center justify-between sticky top-0 z-10">
|
||||||
<a href="views/landing/landing-page.html" class="text-lg font-bold flex items-center gap-2 text-slate-800">
|
<a href="views/landing/landing-page.html" class="text-lg font-bold flex items-center gap-2 text-slate-800">
|
||||||
<img src="public/pure.svg" class="w-7 h-7" alt="PBX Logo">
|
<img src="public/pure.svg" class="w-7 h-7" alt="PBX Logo">
|
||||||
|
|
@ -630,16 +593,16 @@
|
||||||
<iconify-icon icon="carbon:menu" width="24"></iconify-icon>
|
<iconify-icon icon="carbon:menu" width="24"></iconify-icon>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</header>
|
</header> -->
|
||||||
|
|
||||||
<!-- 滚动内容容器 -->
|
<!-- 滚动内容容器 -->
|
||||||
<div class="flex-1 overflow-y-auto custom-scrollbar">
|
<div class="flex-1 overflow-y-auto custom-scrollbar">
|
||||||
<div id="mainAppContainer" class="container mx-auto px-4 py-6 md:py-8 max-w-6xl animate-fade-in-up">
|
<div id="mainAppContainer" class="container h-full flex flex-col justify-center mx-auto px-4 py-6 md:py-8 max-w-6xl animate-fade-in-up">
|
||||||
|
|
||||||
<!-- ===================== -->
|
<!-- ===================== -->
|
||||||
<!-- 顶部欢迎区 (Modern Dashboard Style) -->
|
<!-- 顶部欢迎区 (Modern Dashboard Style) -->
|
||||||
<!-- ===================== -->
|
<!-- ===================== -->
|
||||||
<div class="workspace-header">
|
<!-- <div class="workspace-header">
|
||||||
<div class="workspace-header-content">
|
<div class="workspace-header-content">
|
||||||
<h1 class="text-3xl md:text-4xl font-bold text-slate-900 mb-4 tracking-tight" style="color: var(--slate-900);">
|
<h1 class="text-3xl md:text-4xl font-bold text-slate-900 mb-4 tracking-tight" style="color: var(--slate-900);">
|
||||||
可学可学可学可学可学,测试提交后,vercel更新是否成功
|
可学可学可学可学可学,测试提交后,vercel更新是否成功
|
||||||
|
|
@ -648,7 +611,7 @@
|
||||||
配置多种OCR 引擎与 AI 翻译模型。上传文档后,Paper Burner X将给您流畅的阅读与处理体验。
|
配置多种OCR 引擎与 AI 翻译模型。上传文档后,Paper Burner X将给您流畅的阅读与处理体验。
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div> -->
|
||||||
|
|
||||||
<!-- ===================== -->
|
<!-- ===================== -->
|
||||||
<!-- 主功能区 -->
|
<!-- 主功能区 -->
|
||||||
|
|
@ -660,8 +623,8 @@
|
||||||
<!-- ===================== -->
|
<!-- ===================== -->
|
||||||
<!-- 卡片 1: OCR 文档解析 -->
|
<!-- 卡片 1: OCR 文档解析 -->
|
||||||
<!-- ===================== -->
|
<!-- ===================== -->
|
||||||
<div class="modern-card p-4 md:p-6">
|
<div class="modern-card p-4 md:p-6 hidden">
|
||||||
<!--
|
|
||||||
<div class="mb-6">
|
<div class="mb-6">
|
||||||
<h2 class="text-xl font-semibold text-gray-800 mb-4 flex items-center">
|
<h2 class="text-xl font-semibold text-gray-800 mb-4 flex items-center">
|
||||||
<iconify-icon icon="carbon:api" class="mr-2 text-indigo-500" width="24"></iconify-icon>
|
<iconify-icon icon="carbon:api" class="mr-2 text-indigo-500" width="24"></iconify-icon>
|
||||||
|
|
@ -682,12 +645,12 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
-->
|
|
||||||
|
|
||||||
<!-- ===================== -->
|
<!-- ===================== -->
|
||||||
<!-- OCR 设置 -->
|
<!-- OCR 设置 -->
|
||||||
<!-- ===================== -->
|
<!-- ===================== -->
|
||||||
<div>
|
<div>
|
||||||
<div class="section-header justify-between">
|
<div class="section-header justify-between">
|
||||||
<h2 class="section-title">
|
<h2 class="section-title">
|
||||||
<div class="w-9 h-9 rounded-xl bg-gradient-to-br from-indigo-50 to-indigo-100/80 border border-indigo-100 text-indigo-600 flex items-center justify-center mr-3 shadow-sm" style="background: var(--indigo-50); color: var(--color-primary); border-color: var(--indigo-100);">
|
<div class="w-9 h-9 rounded-xl bg-gradient-to-br from-indigo-50 to-indigo-100/80 border border-indigo-100 text-indigo-600 flex items-center justify-center mr-3 shadow-sm" style="background: var(--indigo-50); color: var(--color-primary); border-color: var(--indigo-100);">
|
||||||
|
|
@ -695,14 +658,14 @@
|
||||||
</div>
|
</div>
|
||||||
OCR 文档解析
|
OCR 文档解析
|
||||||
</h2>
|
</h2>
|
||||||
<!-- <div class="flex items-center">
|
<div class="flex items-center">
|
||||||
<span id="flashConfigTip" class="flash-tip-anim text-sm font-medium mr-2" style="color: var(--color-primary);">配置模型与Key</span>
|
<span id="flashConfigTip" class="flash-tip-anim text-sm font-medium mr-2" style="color: var(--color-primary);">配置模型与Key</span>
|
||||||
<button id="modelKeyManagerBtn" class="flex items-center gap-1.5 px-3 py-1.5 text-sm font-medium text-slate-600 bg-slate-100 hover:bg-slate-200 rounded-lg transition-colors" title="模型与Key管理">
|
<button id="modelKeyManagerBtn" class="flex items-center gap-1.5 px-3 py-1.5 text-sm font-medium text-slate-600 bg-slate-100 hover:bg-slate-200 rounded-lg transition-colors" title="模型与Key管理">
|
||||||
<iconify-icon icon="carbon:settings" width="18"></iconify-icon>
|
<iconify-icon icon="carbon:settings" width="18"></iconify-icon>
|
||||||
<span>设置</span>
|
<span>设置</span>
|
||||||
</button>
|
</button>
|
||||||
</div> -->
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- OCR 引擎选择(简化版) -->
|
<!-- OCR 引擎选择(简化版) -->
|
||||||
<div>
|
<div>
|
||||||
|
|
@ -717,10 +680,10 @@
|
||||||
<div id="localOcrHint" class="text-xs text-gray-500 mt-1 hidden">
|
<div id="localOcrHint" class="text-xs text-gray-500 mt-1 hidden">
|
||||||
<strong>本地解析</strong>:适用于文字型 PDF(非扫描件),免费且快速,但不支持图片和复杂排版的识别
|
<strong>本地解析</strong>:适用于文字型 PDF(非扫描件),免费且快速,但不支持图片和复杂排版的识别
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- MinerU 翻译模式配置(仅当选择 MinerU 时显示) -->
|
<!-- MinerU 翻译模式配置(仅当选择 MinerU 时显示) -->
|
||||||
<div id="mineruTranslationModeConfig" class="hidden mt-4">
|
<div id="mineruTranslationModeConfig" class="hidden mt-4">
|
||||||
<div class="border border-gray-200 rounded-lg bg-gray-50 p-4">
|
<div class="border border-gray-200 rounded-lg bg-gray-50 p-4">
|
||||||
<label class="block text-sm font-medium text-gray-700 mb-3">MinerU 翻译模式</label>
|
<label class="block text-sm font-medium text-gray-700 mb-3">MinerU 翻译模式</label>
|
||||||
<div class="space-y-2">
|
<div class="space-y-2">
|
||||||
|
|
@ -740,14 +703,14 @@
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div><!-- /.modern-card (OCR) -->
|
|
||||||
|
|
||||||
<!-- ===================== -->
|
<!-- ===================== -->
|
||||||
<!-- 卡片 2: 翻译与分析 -->
|
<!-- 卡片 2: 翻译与分析 -->
|
||||||
<!-- ===================== -->
|
<!-- ===================== -->
|
||||||
<div class="modern-card p-4 md:p-6">
|
<div class="modern-card p-4 md:p-6 hidden">
|
||||||
<div class="section-header">
|
<div class="section-header">
|
||||||
<h2 class="section-title">
|
<h2 class="section-title">
|
||||||
<div class="w-9 h-9 rounded-xl border flex items-center justify-center mr-3 shadow-sm" style="background: var(--indigo-50); color: var(--color-primary); border-color: var(--indigo-100);">
|
<div class="w-9 h-9 rounded-xl border flex items-center justify-center mr-3 shadow-sm" style="background: var(--indigo-50); color: var(--color-primary); border-color: var(--indigo-100);">
|
||||||
|
|
@ -990,7 +953,7 @@
|
||||||
<!-- ===================== -->
|
<!-- ===================== -->
|
||||||
<!-- 卡片 3: 高级设置 -->
|
<!-- 卡片 3: 高级设置 -->
|
||||||
<!-- ===================== -->
|
<!-- ===================== -->
|
||||||
<div class="modern-card p-4 md:p-6">
|
<div class="modern-card p-4 md:p-6 hidden">
|
||||||
<!-- 展开/收起高级设置的头部 -->
|
<!-- 展开/收起高级设置的头部 -->
|
||||||
<div id="advancedSettingsToggle" class="section-header justify-between cursor-pointer select-none hover:opacity-80 transition-opacity -mb-4 pb-4">
|
<div id="advancedSettingsToggle" class="section-header justify-between cursor-pointer select-none hover:opacity-80 transition-opacity -mb-4 pb-4">
|
||||||
<h2 class="section-title">
|
<h2 class="section-title">
|
||||||
|
|
@ -1237,7 +1200,7 @@
|
||||||
<div class="section-header justify-between">
|
<div class="section-header justify-between">
|
||||||
<h2 class="section-title">
|
<h2 class="section-title">
|
||||||
<div class="w-9 h-9 rounded-xl text-white flex items-center justify-center mr-3 shadow-md" style="background: var(--color-primary); box-shadow: var(--shadow-sm);">
|
<div class="w-9 h-9 rounded-xl text-white flex items-center justify-center mr-3 shadow-md" style="background: var(--color-primary); box-shadow: var(--shadow-sm);">
|
||||||
<iconify-icon icon="carbon:cloud-upload" width="20"></iconify-icon>
|
<iconify-icon icon="mdi:upload" width="20"></iconify-icon>
|
||||||
</div>
|
</div>
|
||||||
文件上传
|
文件上传
|
||||||
</h2>
|
</h2>
|
||||||
|
|
@ -1253,7 +1216,7 @@
|
||||||
<input type="file" id="folderInput" class="hidden" webkitdirectory mozdirectory multiple>
|
<input type="file" id="folderInput" class="hidden" webkitdirectory mozdirectory multiple>
|
||||||
|
|
||||||
<div class="mx-auto mb-4 w-20 h-20 flex items-center justify-center rounded-full transition-all duration-300" style="background-color: var(--indigo-50); color: var(--color-primary);">
|
<div class="mx-auto mb-4 w-20 h-20 flex items-center justify-center rounded-full transition-all duration-300" style="background-color: var(--indigo-50); color: var(--color-primary);">
|
||||||
<iconify-icon icon="carbon:cloud-upload" width="40"></iconify-icon>
|
<iconify-icon icon="mdi:upload" width="40"></iconify-icon>
|
||||||
</div>
|
</div>
|
||||||
<h3 class="text-lg font-semibold text-slate-700 mb-2">点击或拖拽文件到此处</h3>
|
<h3 class="text-lg font-semibold text-slate-700 mb-2">点击或拖拽文件到此处</h3>
|
||||||
<p class="text-sm text-slate-500 mb-6 max-w-md mx-auto">
|
<p class="text-sm text-slate-500 mb-6 max-w-md mx-auto">
|
||||||
|
|
@ -1270,17 +1233,6 @@
|
||||||
选择文件夹
|
选择文件夹
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="mt-4 flex flex-wrap justify-center gap-4 text-sm">
|
|
||||||
<button id="urlImportBtn" class="text-slate-500 hover:text-purple-600 transition-colors flex items-center gap-1.5">
|
|
||||||
<iconify-icon icon="carbon:link" width="16"></iconify-icon>
|
|
||||||
URL 导入
|
|
||||||
</button>
|
|
||||||
<span class="text-slate-300">|</span>
|
|
||||||
<button id="githubImportBtn" class="text-slate-500 hover:text-slate-800 transition-colors flex items-center gap-1.5">
|
|
||||||
<iconify-icon icon="carbon:logo-github" width="16"></iconify-icon>
|
|
||||||
GitHub 导入
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 已选文件列表 -->
|
<!-- 已选文件列表 -->
|
||||||
|
|
@ -1373,9 +1325,13 @@
|
||||||
|
|
||||||
<!-- 处理按钮 -->
|
<!-- 处理按钮 -->
|
||||||
<div class="flex justify-center mt-8 mb-12">
|
<div class="flex justify-center mt-8 mb-12">
|
||||||
<button id="processBtn" class="btn-primary-large px-10 py-4 text-lg font-semibold text-white rounded-2xl transition-all disabled:opacity-50 disabled:cursor-not-allowed flex items-center gap-3 hover:scale-[1.02] active:scale-[0.98]" style="background: var(--color-primary);">
|
<button id="processBtn" class="btn-primary-large px-10 hidden py-4 text-lg font-semibold text-white rounded-2xl transition-all disabled:opacity-50 disabled:cursor-not-allowed flex items-center gap-3 hover:scale-[1.02] active:scale-[0.98]" style="background: var(--color-primary);">
|
||||||
<iconify-icon icon="carbon:rocket" width="24"></iconify-icon>
|
<iconify-icon icon="carbon:rocket" width="24"></iconify-icon>
|
||||||
<span>开始智能处理</span>
|
<span>开始处理</span>
|
||||||
|
</button>
|
||||||
|
<button id="onlyReadBtn" class="btn-primary-large px-10 py-4 text-lg font-semibold text-white rounded-2xl transition-all disabled:opacity-50 disabled:cursor-not-allowed flex items-center gap-3 hover:scale-[1.02] active:scale-[0.98]" style="background: var(--color-primary);">
|
||||||
|
<iconify-icon icon="carbon:rocket" width="24"></iconify-icon>
|
||||||
|
<span>仅阅读</span>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -1452,12 +1408,6 @@
|
||||||
<span>下载全部结果 (ZIP)</span>
|
<span>下载全部结果 (ZIP)</span>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<!-- Moved disclaimer text inside the scrollable container -->
|
|
||||||
<div class="flex justify-center mt-8 mb-6">
|
|
||||||
<p class="text-center text-gray-400 text-xs select-none px-4">
|
|
||||||
注意:AI 模型翻译结果仅供参考,最终内容请以原文为准
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div><!-- /#mainAppContainer -->
|
</div><!-- /#mainAppContainer -->
|
||||||
</div><!-- /.flex-1.overflow-y-auto -->
|
</div><!-- /.flex-1.overflow-y-auto -->
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@
|
||||||
<title>Paper Burner X - AI文献阅读与智能分析平台</title>
|
<title>Paper Burner X - AI文献阅读与智能分析平台</title>
|
||||||
<link rel="icon" type="image/svg+xml" href="public/pure.svg">
|
<link rel="icon" type="image/svg+xml" href="public/pure.svg">
|
||||||
<!-- CDN 性能优化:DNS 预连接 - 提前建立连接,节省 100-300ms --> <link rel="dns-prefetch" href="https://gcore.jsdelivr.net"> <link rel="preconnect" href="https://gcore.jsdelivr.net" crossorigin> <link rel="dns-prefetch" href="https://cdnjs.cloudflare.com"> <link rel="preconnect" href="https://cdnjs.cloudflare.com" crossorigin> <link rel="dns-prefetch" href="https://cdn.tailwindcss.com"> <link rel="preconnect" href="https://cdn.tailwindcss.com" crossorigin>
|
<!-- CDN 性能优化:DNS 预连接 - 提前建立连接,节省 100-300ms --> <link rel="dns-prefetch" href="https://gcore.jsdelivr.net"> <link rel="preconnect" href="https://gcore.jsdelivr.net" crossorigin> <link rel="dns-prefetch" href="https://cdnjs.cloudflare.com"> <link rel="preconnect" href="https://cdnjs.cloudflare.com" crossorigin> <link rel="dns-prefetch" href="https://cdn.tailwindcss.com"> <link rel="preconnect" href="https://cdn.tailwindcss.com" crossorigin>
|
||||||
123
|
|
||||||
<!-- XSS 防护:DOMPurify - 用于清理 AI 生成的 HTML 内容 -->
|
<!-- XSS 防护:DOMPurify - 用于清理 AI 生成的 HTML 内容 -->
|
||||||
<script src="https://gcore.jsdelivr.net/npm/dompurify@3.0.6/dist/purify.min.js"></script>
|
<script src="https://gcore.jsdelivr.net/npm/dompurify@3.0.6/dist/purify.min.js"></script>
|
||||||
|
|
||||||
|
|
@ -231,7 +231,7 @@
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
}
|
}
|
||||||
/* 新增:右侧大 Logo 背景装饰 */
|
/* 新增:右侧大 Logo 背景装饰 */
|
||||||
.workspace-header::after {
|
/* .workspace-header::after {
|
||||||
content: '';
|
content: '';
|
||||||
position: absolute;
|
position: absolute;
|
||||||
right: -20px;
|
right: -20px;
|
||||||
|
|
@ -242,10 +242,11 @@
|
||||||
background-repeat: no-repeat;
|
background-repeat: no-repeat;
|
||||||
background-position: center;
|
background-position: center;
|
||||||
background-size: contain;
|
background-size: contain;
|
||||||
opacity: 0.07; /* 极低透明度,仅作纹理 */
|
极低透明度,仅作纹理
|
||||||
|
opacity: 0.07;
|
||||||
transform: rotate(-10deg);
|
transform: rotate(-10deg);
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
}
|
} */
|
||||||
.workspace-header-content {
|
.workspace-header-content {
|
||||||
position: relative;
|
position: relative;
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
|
|
@ -532,30 +533,7 @@
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body class="bg-slate-50 min-h-screen">
|
<body class="bg-slate-50 min-h-screen">
|
||||||
<script>
|
|
||||||
// 可选:每天一次跳转到落地页(仅在非后端模式且未强制 backend 时启用)
|
|
||||||
(function() {
|
|
||||||
try {
|
|
||||||
var currentPath = window.location.pathname;
|
|
||||||
// 如果明确进入后端模式(通过查询参数或全局变量),则不跳转落地页,避免影响使用
|
|
||||||
var params = new URLSearchParams(window.location.search);
|
|
||||||
var forcedMode = (params.get('mode') || '').toLowerCase();
|
|
||||||
var envMode = (window.ENV_DEPLOYMENT_MODE || '').toLowerCase();
|
|
||||||
var shouldSkip = (forcedMode === 'backend') || (envMode === 'backend');
|
|
||||||
|
|
||||||
if (shouldSkip) return;
|
|
||||||
if (currentPath.indexOf('landing-page.html') !== -1) return;
|
|
||||||
|
|
||||||
var today = new Date().toDateString();
|
|
||||||
var lastShownDate = localStorage.getItem('paperBurnerLandingLastShown');
|
|
||||||
if (lastShownDate !== today) {
|
|
||||||
localStorage.setItem('paperBurnerLandingLastShown', today);
|
|
||||||
var basePath = currentPath.substring(0, currentPath.lastIndexOf('/') + 1);
|
|
||||||
window.location.href = basePath + 'views/landing/landing-page.html';
|
|
||||||
}
|
|
||||||
} catch (e) { /* ignore */ }
|
|
||||||
})();
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<!-- Mobile Sidebar Overlay -->
|
<!-- Mobile Sidebar Overlay -->
|
||||||
<div id="sidebarOverlay" class="sidebar-overlay md:hidden"></div>
|
<div id="sidebarOverlay" class="sidebar-overlay md:hidden"></div>
|
||||||
|
|
@ -566,9 +544,11 @@
|
||||||
<!-- ===================== -->
|
<!-- ===================== -->
|
||||||
<aside id="appSidebar" class="app-sidebar">
|
<aside id="appSidebar" class="app-sidebar">
|
||||||
<div class="px-6 py-5 flex items-center justify-between transition-all" id="sidebarHeader">
|
<div class="px-6 py-5 flex items-center justify-between transition-all" id="sidebarHeader">
|
||||||
<a href="views/landing/landing-page.html" class="hover:opacity-80 transition-opacity" title="返回落地页">
|
<!-- <a href="views/landing/landing-page.html" class="hover:opacity-80 transition-opacity" title="返回落地页">
|
||||||
<img id="sidebarLogo" src="public/h_with_name.svg" class="h-8 transition-all" alt="Paper Burner X">
|
<img id="sidebarLogo" src="public/h_with_name.svg" class="h-8 transition-all" alt="Paper Burner X">
|
||||||
</a>
|
</a> -->
|
||||||
|
<!-- 占位元素 -->
|
||||||
|
<span></span>
|
||||||
<!-- Desktop Collapse Button -->
|
<!-- Desktop Collapse Button -->
|
||||||
<button id="sidebarToggleBtn" class="hidden md:flex text-slate-400 hover:text-slate-600 p-1.5 hover:bg-slate-100 rounded-md transition-colors" title="切换侧边栏">
|
<button id="sidebarToggleBtn" class="hidden md:flex text-slate-400 hover:text-slate-600 p-1.5 hover:bg-slate-100 rounded-md transition-colors" title="切换侧边栏">
|
||||||
<iconify-icon id="sidebarToggleIcon" icon="carbon:side-panel-close" width="20"></iconify-icon>
|
<iconify-icon id="sidebarToggleIcon" icon="carbon:side-panel-close" width="20"></iconify-icon>
|
||||||
|
|
@ -579,13 +559,7 @@
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<nav class="flex-1 px-3 py-4 space-y-1 overflow-y-auto custom-scrollbar overflow-x-hidden">
|
<nav class="flex-1 px-3 py-4 space-y-1 overflow-y-auto custom-scrollbar overflow-x-hidden">
|
||||||
<div class="nav-section-title px-3 mb-2 text-[11px] font-bold text-slate-400 uppercase tracking-wider transition-opacity">
|
|
||||||
主要功能
|
|
||||||
</div>
|
|
||||||
<div class="nav-item active cursor-pointer" title="工作台">
|
|
||||||
<iconify-icon icon="carbon:dashboard" class="nav-icon"></iconify-icon>
|
|
||||||
<span class="nav-text transition-opacity">工作台</span>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- 可折叠的历史记录菜单 (Split Action) -->
|
<!-- 可折叠的历史记录菜单 (Split Action) -->
|
||||||
<div id="historyMenuContainer">
|
<div id="historyMenuContainer">
|
||||||
|
|
@ -605,34 +579,22 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="my-4 border-t border-slate-100 mx-3 transition-all" id="sidebarDivider"></div>
|
<div class="my-4 border-t border-slate-100 mx-3 transition-all" id="sidebarDivider"></div>
|
||||||
<div class="nav-section-title px-3 mb-2 text-[11px] font-bold text-slate-400 uppercase tracking-wider transition-opacity">
|
<!-- <div class="nav-section-title px-3 mb-2 text-[11px] font-bold text-slate-400 uppercase tracking-wider transition-opacity">
|
||||||
系统
|
系统
|
||||||
</div>
|
</div>
|
||||||
<div id="sidebarSettingsBtn" class="nav-item cursor-pointer" title="全局设置">
|
<div id="sidebarSettingsBtn" class="nav-item cursor-pointer" title="全局设置">
|
||||||
<iconify-icon icon="carbon:settings" class="nav-icon"></iconify-icon>
|
<iconify-icon icon="carbon:settings" class="nav-icon"></iconify-icon>
|
||||||
<span class="nav-text transition-opacity">全局设置</span>
|
<span class="nav-text transition-opacity">全局设置</span>
|
||||||
</div>
|
</div> -->
|
||||||
</nav>
|
</nav>
|
||||||
|
<!-- 删除界面会加载不出来 -->
|
||||||
<div class="p-3 transition-all" id="sidebarFooter">
|
<div class="p-3 transition-all" id="sidebarFooter">
|
||||||
<div class="p-4 bg-slate-50 rounded-2xl border border-slate-100 overflow-hidden">
|
<div class="p-4 overflow-hidden">
|
||||||
<a href="https://github.com/Feather-2/paper-burner" target="_blank" class="flex items-start gap-3 hover:opacity-80 transition-opacity" title="GitHub 仓库">
|
|
||||||
<div class="w-10 h-10 rounded-xl bg-white border border-slate-200 flex items-center justify-center text-slate-400 shadow-sm shrink-0">
|
|
||||||
<iconify-icon icon="carbon:logo-github" width="24"></iconify-icon>
|
|
||||||
</div>
|
|
||||||
<div class="flex-1 min-w-0 nav-text transition-opacity">
|
|
||||||
<div class="flex items-center gap-1.5 mb-1">
|
|
||||||
<span id="githubStars" class="inline-flex items-center gap-1 text-xs text-slate-500 bg-slate-100 px-2 py-0.5 rounded-full">
|
|
||||||
<iconify-icon icon="carbon:star" width="10"></iconify-icon>
|
|
||||||
<span>加载中...</span>
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
<p class="text-xs text-slate-500">支持自部署,欢迎星标</p>
|
|
||||||
</div>
|
|
||||||
</a>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="text-center py-1 mt-1 nav-text transition-opacity">
|
<div class="text-center py-1 mt-1 nav-text transition-opacity">
|
||||||
<span id="showCopyrightModal" class="text-[11px] text-slate-400 hover:text-slate-600 transition-colors cursor-pointer select-none">
|
<span id="showCopyrightModal" class="text-[11px] text-slate-400 hover:text-slate-600 transition-colors cursor-pointer select-none">
|
||||||
Paper Burner X 丨 关于
|
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -648,7 +610,7 @@
|
||||||
<!-- 主内容区 -->
|
<!-- 主内容区 -->
|
||||||
<!-- ===================== -->
|
<!-- ===================== -->
|
||||||
<main class="app-main flex flex-col">
|
<main class="app-main flex flex-col">
|
||||||
<!-- 移动端 Header -->
|
<!-- 移动端 Header
|
||||||
<header class="md:hidden bg-white/80 backdrop-blur-md border-b border-slate-200 px-4 py-3 flex items-center justify-between sticky top-0 z-10">
|
<header class="md:hidden bg-white/80 backdrop-blur-md border-b border-slate-200 px-4 py-3 flex items-center justify-between sticky top-0 z-10">
|
||||||
<a href="views/landing/landing-page.html" class="text-lg font-bold flex items-center gap-2 text-slate-800">
|
<a href="views/landing/landing-page.html" class="text-lg font-bold flex items-center gap-2 text-slate-800">
|
||||||
<img src="public/pure.svg" class="w-7 h-7" alt="PBX Logo">
|
<img src="public/pure.svg" class="w-7 h-7" alt="PBX Logo">
|
||||||
|
|
@ -662,7 +624,7 @@
|
||||||
<iconify-icon icon="carbon:menu" width="24"></iconify-icon>
|
<iconify-icon icon="carbon:menu" width="24"></iconify-icon>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</header>
|
</header> -->
|
||||||
|
|
||||||
<!-- 滚动内容容器 -->
|
<!-- 滚动内容容器 -->
|
||||||
<div class="flex-1 overflow-y-auto custom-scrollbar">
|
<div class="flex-1 overflow-y-auto custom-scrollbar">
|
||||||
|
|
@ -671,7 +633,7 @@
|
||||||
<!-- ===================== -->
|
<!-- ===================== -->
|
||||||
<!-- 顶部欢迎区 (Modern Dashboard Style) -->
|
<!-- 顶部欢迎区 (Modern Dashboard Style) -->
|
||||||
<!-- ===================== -->
|
<!-- ===================== -->
|
||||||
<div class="workspace-header">
|
<!-- <div class="workspace-header">
|
||||||
<div class="workspace-header-content">
|
<div class="workspace-header-content">
|
||||||
<h1 class="text-3xl md:text-4xl font-bold text-slate-900 mb-4 tracking-tight" style="color: var(--slate-900);">
|
<h1 class="text-3xl md:text-4xl font-bold text-slate-900 mb-4 tracking-tight" style="color: var(--slate-900);">
|
||||||
可学可学可学可学可学,测试提交后,vercel更新是否成功
|
可学可学可学可学可学,测试提交后,vercel更新是否成功
|
||||||
|
|
@ -680,7 +642,7 @@
|
||||||
配置多种OCR 引擎与 AI 翻译模型。上传文档后,Paper Burner X将给您流畅的阅读与处理体验。
|
配置多种OCR 引擎与 AI 翻译模型。上传文档后,Paper Burner X将给您流畅的阅读与处理体验。
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div> -->
|
||||||
|
|
||||||
<!-- ===================== -->
|
<!-- ===================== -->
|
||||||
<!-- 主功能区 -->
|
<!-- 主功能区 -->
|
||||||
|
|
@ -692,8 +654,8 @@
|
||||||
<!-- ===================== -->
|
<!-- ===================== -->
|
||||||
<!-- 卡片 1: OCR 文档解析 -->
|
<!-- 卡片 1: OCR 文档解析 -->
|
||||||
<!-- ===================== -->
|
<!-- ===================== -->
|
||||||
<div class="modern-card p-4 md:p-6">
|
<div class="modern-card p-4 md:p-6 hidden">
|
||||||
<!--
|
|
||||||
<div class="mb-6">
|
<div class="mb-6">
|
||||||
<h2 class="text-xl font-semibold text-gray-800 mb-4 flex items-center">
|
<h2 class="text-xl font-semibold text-gray-800 mb-4 flex items-center">
|
||||||
<iconify-icon icon="carbon:api" class="mr-2 text-indigo-500" width="24"></iconify-icon>
|
<iconify-icon icon="carbon:api" class="mr-2 text-indigo-500" width="24"></iconify-icon>
|
||||||
|
|
@ -714,12 +676,12 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
-->
|
|
||||||
|
|
||||||
<!-- ===================== -->
|
<!-- ===================== -->
|
||||||
<!-- OCR 设置 -->
|
<!-- OCR 设置 -->
|
||||||
<!-- ===================== -->
|
<!-- ===================== -->
|
||||||
<div>
|
<div>
|
||||||
<div class="section-header justify-between">
|
<div class="section-header justify-between">
|
||||||
<h2 class="section-title">
|
<h2 class="section-title">
|
||||||
<div class="w-9 h-9 rounded-xl bg-gradient-to-br from-indigo-50 to-indigo-100/80 border border-indigo-100 text-indigo-600 flex items-center justify-center mr-3 shadow-sm" style="background: var(--indigo-50); color: var(--color-primary); border-color: var(--indigo-100);">
|
<div class="w-9 h-9 rounded-xl bg-gradient-to-br from-indigo-50 to-indigo-100/80 border border-indigo-100 text-indigo-600 flex items-center justify-center mr-3 shadow-sm" style="background: var(--indigo-50); color: var(--color-primary); border-color: var(--indigo-100);">
|
||||||
|
|
@ -734,7 +696,7 @@
|
||||||
<span>设置</span>
|
<span>设置</span>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- OCR 引擎选择(简化版) -->
|
<!-- OCR 引擎选择(简化版) -->
|
||||||
<div>
|
<div>
|
||||||
|
|
@ -749,10 +711,10 @@
|
||||||
<div id="localOcrHint" class="text-xs text-gray-500 mt-1 hidden">
|
<div id="localOcrHint" class="text-xs text-gray-500 mt-1 hidden">
|
||||||
<strong>本地解析</strong>:适用于文字型 PDF(非扫描件),免费且快速,但不支持图片和复杂排版的识别
|
<strong>本地解析</strong>:适用于文字型 PDF(非扫描件),免费且快速,但不支持图片和复杂排版的识别
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- MinerU 翻译模式配置(仅当选择 MinerU 时显示) -->
|
<!-- MinerU 翻译模式配置(仅当选择 MinerU 时显示) -->
|
||||||
<div id="mineruTranslationModeConfig" class="hidden mt-4">
|
<div id="mineruTranslationModeConfig" class="hidden mt-4">
|
||||||
<div class="border border-gray-200 rounded-lg bg-gray-50 p-4">
|
<div class="border border-gray-200 rounded-lg bg-gray-50 p-4">
|
||||||
<label class="block text-sm font-medium text-gray-700 mb-3">MinerU 翻译模式</label>
|
<label class="block text-sm font-medium text-gray-700 mb-3">MinerU 翻译模式</label>
|
||||||
<div class="space-y-2">
|
<div class="space-y-2">
|
||||||
|
|
@ -772,14 +734,14 @@
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div><!-- /.modern-card (OCR) -->
|
|
||||||
|
|
||||||
<!-- ===================== -->
|
<!-- ===================== -->
|
||||||
<!-- 卡片 2: 翻译与分析 -->
|
<!-- 卡片 2: 翻译与分析 -->
|
||||||
<!-- ===================== -->
|
<!-- ===================== -->
|
||||||
<div class="modern-card p-4 md:p-6">
|
<div class="modern-card p-4 md:p-6 hidden">
|
||||||
<div class="section-header">
|
<div class="section-header">
|
||||||
<h2 class="section-title">
|
<h2 class="section-title">
|
||||||
<div class="w-9 h-9 rounded-xl border flex items-center justify-center mr-3 shadow-sm" style="background: var(--indigo-50); color: var(--color-primary); border-color: var(--indigo-100);">
|
<div class="w-9 h-9 rounded-xl border flex items-center justify-center mr-3 shadow-sm" style="background: var(--indigo-50); color: var(--color-primary); border-color: var(--indigo-100);">
|
||||||
|
|
@ -1022,7 +984,7 @@
|
||||||
<!-- ===================== -->
|
<!-- ===================== -->
|
||||||
<!-- 卡片 3: 高级设置 -->
|
<!-- 卡片 3: 高级设置 -->
|
||||||
<!-- ===================== -->
|
<!-- ===================== -->
|
||||||
<div class="modern-card p-4 md:p-6">
|
<div class="modern-card p-4 md:p-6 hidden">
|
||||||
<!-- 展开/收起高级设置的头部 -->
|
<!-- 展开/收起高级设置的头部 -->
|
||||||
<div id="advancedSettingsToggle" class="section-header justify-between cursor-pointer select-none hover:opacity-80 transition-opacity -mb-4 pb-4">
|
<div id="advancedSettingsToggle" class="section-header justify-between cursor-pointer select-none hover:opacity-80 transition-opacity -mb-4 pb-4">
|
||||||
<h2 class="section-title">
|
<h2 class="section-title">
|
||||||
|
|
@ -1516,6 +1478,8 @@
|
||||||
<script src="js/utils/github-stars.js"></script>
|
<script src="js/utils/github-stars.js"></script>
|
||||||
<!-- 自动探测后端:若 /api/健康检查通过将切换为 backend;也可用 ?mode=backend 强制 -->
|
<!-- 自动探测后端:若 /api/健康检查通过将切换为 backend;也可用 ?mode=backend 强制 -->
|
||||||
<script>window.ENV_DEPLOYMENT_MODE = 'auto';</script>
|
<script>window.ENV_DEPLOYMENT_MODE = 'auto';</script>
|
||||||
|
<!-- 代理服务器地址统一配置(必须在其他 API 相关脚本之前加载) -->
|
||||||
|
<script src="js/config/proxy-config.js"></script>
|
||||||
<script src="js/api/api.js?v=2"></script>
|
<script src="js/api/api.js?v=2"></script>
|
||||||
<script src="js/storage/storage.js"></script>
|
<script src="js/storage/storage.js"></script>
|
||||||
<!-- 先初始化存储适配器(提供 isFrontendMode 标记) -->
|
<!-- 先初始化存储适配器(提供 isFrontendMode 标记) -->
|
||||||
|
|
|
||||||
119
js/app.js
119
js/app.js
|
|
@ -43,6 +43,24 @@ function escapeHtml(str) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将 ArrayBuffer 转换为 Base64 字符串
|
||||||
|
* @param {ArrayBuffer} buffer - 需要转换的 ArrayBuffer
|
||||||
|
* @returns {string} Base64 编码的字符串
|
||||||
|
*/
|
||||||
|
function arrayBufferToBase64(buffer) {
|
||||||
|
if (!buffer) return null;
|
||||||
|
const bytes = buffer instanceof ArrayBuffer ? new Uint8Array(buffer) : new Uint8Array(buffer.buffer || []);
|
||||||
|
if (!bytes.length) return null;
|
||||||
|
let binary = '';
|
||||||
|
const chunkSize = 0x8000;
|
||||||
|
for (let i = 0; i < bytes.length; i += chunkSize) {
|
||||||
|
const chunk = bytes.subarray(i, i + chunkSize);
|
||||||
|
binary += String.fromCharCode.apply(null, chunk);
|
||||||
|
}
|
||||||
|
return btoa(binary);
|
||||||
|
}
|
||||||
|
|
||||||
// =====================
|
// =====================
|
||||||
// 全局状态变量
|
// 全局状态变量
|
||||||
// =====================
|
// =====================
|
||||||
|
|
@ -523,6 +541,7 @@ function setupEventListeners() {
|
||||||
const githubImportBtn = document.getElementById('githubImportBtn');
|
const githubImportBtn = document.getElementById('githubImportBtn');
|
||||||
const clearBtn = document.getElementById('clearFilesBtn');
|
const clearBtn = document.getElementById('clearFilesBtn');
|
||||||
const processBtn = document.getElementById('processBtn');
|
const processBtn = document.getElementById('processBtn');
|
||||||
|
const onlyReadBtn = document.getElementById('onlyReadBtn');
|
||||||
const downloadBtn = document.getElementById('downloadAllBtn');
|
const downloadBtn = document.getElementById('downloadAllBtn');
|
||||||
const formatFilterContainer = document.getElementById('fileFormatFilters');
|
const formatFilterContainer = document.getElementById('fileFormatFilters');
|
||||||
const batchToggle = document.getElementById('batchModeToggle');
|
const batchToggle = document.getElementById('batchModeToggle');
|
||||||
|
|
@ -752,6 +771,7 @@ function setupEventListeners() {
|
||||||
|
|
||||||
// 处理和下载
|
// 处理和下载
|
||||||
processBtn.addEventListener('click', handleProcessClick);
|
processBtn.addEventListener('click', handleProcessClick);
|
||||||
|
onlyReadBtn.addEventListener('click', handleReadClick);
|
||||||
downloadBtn.addEventListener('click', handleDownloadClick);
|
downloadBtn.addEventListener('click', handleDownloadClick);
|
||||||
|
|
||||||
if (typeof window.updateDeeplxTargetLangHint === 'function') {
|
if (typeof window.updateDeeplxTargetLangHint === 'function') {
|
||||||
|
|
@ -1119,7 +1139,7 @@ function refreshFormatFilters() {
|
||||||
`);
|
`);
|
||||||
});
|
});
|
||||||
|
|
||||||
fragments.push('<div class="flex-grow"></div><button type="button" id="resetFormatFilters" class="text-xs text-blue-600">重置</button>');
|
// fragments.push('<div class="flex-grow"></div><button type="button" id="resetFormatFilters" class="text-xs text-blue-600">重置</button>');
|
||||||
container.innerHTML = `<div class="flex flex-wrap gap-2 items-center">${fragments.join('')}</div>`;
|
container.innerHTML = `<div class="flex flex-wrap gap-2 items-center">${fragments.join('')}</div>`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1868,7 +1888,8 @@ async function handleProcessClick() {
|
||||||
retryAttempts.clear();
|
retryAttempts.clear();
|
||||||
allResults = new Array(filesToProcess.length);
|
allResults = new Array(filesToProcess.length);
|
||||||
updateProcessButtonState(pdfFiles, isProcessing);
|
updateProcessButtonState(pdfFiles, isProcessing);
|
||||||
showProgressSection();
|
// 隐藏处理进度
|
||||||
|
// showProgressSection();
|
||||||
addProgressLog('=== 开始批量处理 ===');
|
addProgressLog('=== 开始批量处理 ===');
|
||||||
|
|
||||||
// 5. 获取并发和重试设置等...
|
// 5. 获取并发和重试设置等...
|
||||||
|
|
@ -2131,8 +2152,17 @@ async function handleProcessClick() {
|
||||||
activeBatchSession = null;
|
activeBatchSession = null;
|
||||||
isProcessing = false;
|
isProcessing = false;
|
||||||
updateProcessButtonState(pdfFiles, isProcessing);
|
updateProcessButtonState(pdfFiles, isProcessing);
|
||||||
showResultsSection(successCount, skippedCount, errorCount, filesToProcess.length);
|
// 不显示处理完成
|
||||||
|
// showResultsSection(successCount, skippedCount, errorCount, filesToProcess.length);
|
||||||
saveProcessedFilesRecord(processedFilesRecord);
|
saveProcessedFilesRecord(processedFilesRecord);
|
||||||
|
// 跳转到历史细节界面
|
||||||
|
const successfulResult = allResults.find(r => r && r.file && !r.error && !r.skipped);
|
||||||
|
if (filesToProcess.length === 1 && successfulResult && successfulResult.file) {
|
||||||
|
const recordId = `${successfulResult.file.name}_${successfulResult.file.size}`;
|
||||||
|
window.location.href = `views/history/history_detail.html?id=${encodeURIComponent(recordId)}`;
|
||||||
|
} else {
|
||||||
|
window.location.href = 'history.html';
|
||||||
|
}
|
||||||
|
|
||||||
allResults = allResults.filter(r => r !== undefined && r !== null);
|
allResults = allResults.filter(r => r !== undefined && r !== null);
|
||||||
console.log("Final results count:", allResults.length);
|
console.log("Final results count:", allResults.length);
|
||||||
|
|
@ -2154,6 +2184,89 @@ function handleDownloadClick() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// =====================
|
||||||
|
// 仅阅读(不做处理直接跳转)
|
||||||
|
// =====================
|
||||||
|
/**
|
||||||
|
* 处理点击"仅阅读"按钮的事件。
|
||||||
|
* 如果已有处理结果,直接跳转历史详情。
|
||||||
|
* 如果没有处理结果但有上传文件,则将文件保存到历史记录后跳转。
|
||||||
|
*/
|
||||||
|
async function handleReadClick() {
|
||||||
|
// 1. 优先检查是否有已处理的结果
|
||||||
|
if (allResults.length > 0) {
|
||||||
|
const successfulResult = allResults.find(r => r && r.file && !r.error && !r.skipped);
|
||||||
|
if (successfulResult && successfulResult.file) {
|
||||||
|
const recordId = `${successfulResult.file.name}_${successfulResult.file.size}`;
|
||||||
|
window.location.href = `views/history/history_detail.html?id=${encodeURIComponent(recordId)}`;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. 检查是否有上传的文件,直接保存到历史记录
|
||||||
|
if (pdfFiles.length > 0) {
|
||||||
|
const file = pdfFiles[0]; // 只处理第一个文件
|
||||||
|
const recordId = `${file.name}_${file.size}`;
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 读取文件内容为 base64
|
||||||
|
const arrayBuffer = await file.arrayBuffer();
|
||||||
|
const base64Content = arrayBufferToBase64(arrayBuffer);
|
||||||
|
|
||||||
|
// 获取文件扩展名和类型
|
||||||
|
const ext = file.name.split('.').pop().toLowerCase();
|
||||||
|
const fileType = ext;
|
||||||
|
|
||||||
|
// 创建历史记录对象
|
||||||
|
const record = {
|
||||||
|
id: recordId,
|
||||||
|
name: file.name,
|
||||||
|
size: file.size,
|
||||||
|
time: new Date().toISOString(),
|
||||||
|
ocr: '',
|
||||||
|
translation: '',
|
||||||
|
images: [],
|
||||||
|
ocrChunks: [],
|
||||||
|
translatedChunks: [],
|
||||||
|
fileType: fileType,
|
||||||
|
targetLanguage: '',
|
||||||
|
originalEncoding: 'binary',
|
||||||
|
originalBinary: base64Content,
|
||||||
|
originalExtension: ext,
|
||||||
|
ocrEngine: null,
|
||||||
|
ocrSource: null,
|
||||||
|
translationModelName: 'none',
|
||||||
|
batchId: null,
|
||||||
|
batchOrder: null,
|
||||||
|
batchTotal: null,
|
||||||
|
batchTemplate: null,
|
||||||
|
batchFormats: null,
|
||||||
|
batchStartedAt: null
|
||||||
|
};
|
||||||
|
|
||||||
|
// 保存到数据库
|
||||||
|
if (typeof window.storageAdapter !== 'undefined' && typeof window.storageAdapter.saveResultToDB === 'function') {
|
||||||
|
await window.storageAdapter.saveResultToDB(record);
|
||||||
|
} else if (typeof saveResultToDB === 'function') {
|
||||||
|
await saveResultToDB(record);
|
||||||
|
} else {
|
||||||
|
showNotification('存储功能不可用', 'error');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 跳转到历史详情页面
|
||||||
|
window.location.href = `views/history/history_detail.html?id=${encodeURIComponent(recordId)}`;
|
||||||
|
} catch (error) {
|
||||||
|
console.error('保存文件到历史记录失败:', error);
|
||||||
|
showNotification(`保存失败: ${error.message}`, 'error');
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
showNotification('请先上传文件', 'warning');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// =====================
|
// =====================
|
||||||
// 内置提示模板获取
|
// 内置提示模板获取
|
||||||
// =====================
|
// =====================
|
||||||
|
|
|
||||||
|
|
@ -1222,7 +1222,7 @@ function initChatbotUI() {
|
||||||
</div>
|
</div>
|
||||||
<!-- 标题栏 (可拖拽移动窗口) -->
|
<!-- 标题栏 (可拖拽移动窗口) -->
|
||||||
<div id="chatbot-title-bar" class="chatbot-draggable-header" style="padding:12px 24px;display:flex;align-items:center;gap:8px;border-bottom:1px dashed rgba(0,0,0,0.1);flex-shrink:0;">
|
<div id="chatbot-title-bar" class="chatbot-draggable-header" style="padding:12px 24px;display:flex;align-items:center;gap:8px;border-bottom:1px dashed rgba(0,0,0,0.1);flex-shrink:0;">
|
||||||
<div style="width:32px;height:32px;border-radius:16px;background:linear-gradient(135deg,#3b82f6,#1d4ed8);display:flex;align-items:center;justify-content:center;">
|
<div style="width:32px;height:32px;border-radius:16px;background:linear-gradient(135deg,#3b82f6,#1d4ed8);display:flex;align-items:center;justify-content:center;display:none;">
|
||||||
<i class="fa-solid fa-robot" style="font-size: 14px; color: white;"></i>
|
<i class="fa-solid fa-robot" style="font-size: 14px; color: white;"></i>
|
||||||
</div>
|
</div>
|
||||||
<span style="font-weight:600;font-size:1.05em;color:#111;">AI 智能助手</span>
|
<span style="font-weight:600;font-size:1.05em;color:#111;">AI 智能助手</span>
|
||||||
|
|
|
||||||
|
|
@ -63,8 +63,8 @@ document.addEventListener('DOMContentLoaded', function() {
|
||||||
const timeStr = `${timeObj.getMonth() + 1}/${timeObj.getDate()} ${String(timeObj.getHours()).padStart(2, '0')}:${String(timeObj.getMinutes()).padStart(2, '0')}`;
|
const timeStr = `${timeObj.getMonth() + 1}/${timeObj.getDate()} ${String(timeObj.getHours()).padStart(2, '0')}:${String(timeObj.getMinutes()).padStart(2, '0')}`;
|
||||||
|
|
||||||
return `
|
return `
|
||||||
<div class="group flex items-center gap-2 px-2 py-1.5 text-[13px] text-slate-600 hover:bg-slate-100 hover:text-slate-900 transition-colors cursor-pointer rounded-md mx-2 mb-0.5" onclick="showHistoryDetail('${safeId}')" title="${name}\n${timeObj.toLocaleString()}">
|
<div class="group flex items-center gap-2 px-2 py-1.5 text-[13px] text-[#000f33] hover:bg-[#000f33] hover:text-[#ffffff] transition-colors cursor-pointer rounded-md mx-2 mb-0.5" onclick="showHistoryDetail('${safeId}')" title="${name}\n${timeObj.toLocaleString()}">
|
||||||
<iconify-icon icon="carbon:document" width="14" class="flex-shrink-0 text-slate-400 group-hover:text-slate-500 transition-colors"></iconify-icon>
|
|
||||||
<span class="truncate flex-1">${name}</span>
|
<span class="truncate flex-1">${name}</span>
|
||||||
<span class="text-[10px] text-slate-400 flex-shrink-0 opacity-0 group-hover:opacity-100 transition-opacity">${timeStr}</span>
|
<span class="text-[10px] text-slate-400 flex-shrink-0 opacity-0 group-hover:opacity-100 transition-opacity">${timeStr}</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -466,15 +466,11 @@ async function triggerReprocess(includeTranslation) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 显示处理中 Toast
|
|
||||||
showToast('正在准备文档...', 'info');
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// 将 Base64 转为 File 对象
|
// 将 Base64 转为 File 对象
|
||||||
const file = base64ToFile(pdfBase64, docName);
|
const file = base64ToFile(pdfBase64, docName);
|
||||||
|
|
||||||
// 执行 OCR
|
|
||||||
showToast('正在进行 OCR 识别...', 'info');
|
|
||||||
|
|
||||||
const ocrResult = await performOcr(file, (current, total, msg) => {
|
const ocrResult = await performOcr(file, (current, total, msg) => {
|
||||||
showToast(`${msg || 'OCR 处理中'} (${current}/${total})`, 'info', 5000);
|
showToast(`${msg || 'OCR 处理中'} (${current}/${total})`, 'info', 5000);
|
||||||
|
|
@ -493,7 +489,6 @@ async function triggerReprocess(includeTranslation) {
|
||||||
|
|
||||||
// 如果需要翻译,执行翻译
|
// 如果需要翻译,执行翻译
|
||||||
if (includeTranslation) {
|
if (includeTranslation) {
|
||||||
showToast('正在进行翻译...', 'info');
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const translationResult = await performTranslation(ocrResult.markdown, (current, total, msg) => {
|
const translationResult = await performTranslation(ocrResult.markdown, (current, total, msg) => {
|
||||||
|
|
@ -515,7 +510,6 @@ async function triggerReprocess(includeTranslation) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// 保存到 IndexedDB
|
// 保存到 IndexedDB
|
||||||
showToast('正在保存...', 'info');
|
|
||||||
await saveResultToDB(window.data);
|
await saveResultToDB(window.data);
|
||||||
|
|
||||||
// 刷新页面显示
|
// 刷新页面显示
|
||||||
|
|
@ -710,7 +704,6 @@ async function triggerReprocessWithMinerU() {
|
||||||
const savedMineruMode = localStorage.getItem('mineruMode');
|
const savedMineruMode = localStorage.getItem('mineruMode');
|
||||||
|
|
||||||
try {
|
try {
|
||||||
showToast('正在使用 MinerU 处理文档...', 'info');
|
|
||||||
|
|
||||||
// 临时设置 OCR 配置为 MinerU + 结构化翻译模式
|
// 临时设置 OCR 配置为 MinerU + 结构化翻译模式
|
||||||
localStorage.setItem('ocrEngine', 'mineru');
|
localStorage.setItem('ocrEngine', 'mineru');
|
||||||
|
|
|
||||||
|
|
@ -218,10 +218,17 @@
|
||||||
isTocDockResizing = false; // Reset flag
|
isTocDockResizing = false; // Reset flag
|
||||||
}
|
}
|
||||||
|
|
||||||
function enterImmersiveMode() {
|
function enterImmersiveMode(options = {}) {
|
||||||
|
const { silent = false } = options;
|
||||||
|
|
||||||
// 检查是否为移动端设备
|
// 检查是否为移动端设备
|
||||||
if (window.innerWidth <= 700) {
|
if (window.innerWidth <= 700) {
|
||||||
console.warn('拒绝在移动端(≤700px)进入沉浸式布局');
|
console.warn('拒绝在移动端(≤700px)进入沉浸式布局');
|
||||||
|
// 即使不进入沉浸模式,也需要显示页面
|
||||||
|
document.documentElement.classList.remove('immersive-pending');
|
||||||
|
document.documentElement.classList.add('immersive-ready');
|
||||||
|
document.body.classList.remove('immersive-pending');
|
||||||
|
document.body.classList.add('immersive-ready');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -238,19 +245,41 @@
|
||||||
if (!immersiveChatbotArea) missingElements.push('immersiveChatbotArea');
|
if (!immersiveChatbotArea) missingElements.push('immersiveChatbotArea');
|
||||||
if (!immersiveDockPlaceholderElement) missingElements.push('immersiveDockPlaceholderElement (logic error if this happens)');
|
if (!immersiveDockPlaceholderElement) missingElements.push('immersiveDockPlaceholderElement (logic error if this happens)');
|
||||||
|
|
||||||
|
console.log('[enterImmersiveMode] 元素检查:', {
|
||||||
|
immersiveContainer: !!immersiveContainer,
|
||||||
|
mainPageContainer: !!mainPageContainer,
|
||||||
|
tocPopupElement: !!tocPopupElement,
|
||||||
|
chatbotModalElement: !!chatbotModalElement,
|
||||||
|
dockElement: !!dockElement,
|
||||||
|
immersiveTocArea: !!immersiveTocArea,
|
||||||
|
immersiveMainArea: !!immersiveMainArea,
|
||||||
|
immersiveChatbotArea: !!immersiveChatbotArea
|
||||||
|
});
|
||||||
|
|
||||||
if (missingElements.length > 0) {
|
if (missingElements.length > 0) {
|
||||||
console.warn('Immersive mode elements not found:', missingElements.join(', '));
|
console.warn('Immersive mode elements not found:', missingElements.join(', '));
|
||||||
|
// 元素缺失时也需要显示页面
|
||||||
|
document.body.classList.remove('immersive-pending');
|
||||||
|
document.body.classList.add('immersive-ready');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
isImmersiveActive = true;
|
isImmersiveActive = true;
|
||||||
storeOriginalPositions();
|
storeOriginalPositions();
|
||||||
|
|
||||||
// 添加进入动画类
|
// 静默模式:跳过动画,直接设置状态
|
||||||
document.body.classList.add('immersive-entering');
|
if (silent) {
|
||||||
immersiveContainer.style.opacity = '0';
|
document.body.classList.add('immersive-active', 'no-scroll');
|
||||||
immersiveContainer.style.transform = 'scale(0.95)';
|
immersiveContainer.style.display = 'flex';
|
||||||
immersiveContainer.style.transition = 'opacity 0.4s ease, transform 0.4s ease';
|
immersiveContainer.style.opacity = '1';
|
||||||
|
immersiveContainer.style.transform = 'scale(1)';
|
||||||
|
} else {
|
||||||
|
// 添加进入动画类
|
||||||
|
document.body.classList.add('immersive-entering');
|
||||||
|
immersiveContainer.style.opacity = '0';
|
||||||
|
immersiveContainer.style.transform = 'scale(0.95)';
|
||||||
|
immersiveContainer.style.transition = 'opacity 0.4s ease, transform 0.4s ease';
|
||||||
|
}
|
||||||
|
|
||||||
// Append TOC content first
|
// Append TOC content first
|
||||||
if (tocPopupElement && immersiveTocArea) {
|
if (tocPopupElement && immersiveTocArea) {
|
||||||
|
|
@ -305,26 +334,35 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
document.body.classList.add('immersive-active', 'no-scroll');
|
// 静默模式下已经设置了 display 和 opacity,跳过动画
|
||||||
immersiveContainer.style.display = 'flex';
|
if (!silent) {
|
||||||
|
document.body.classList.add('immersive-active', 'no-scroll');
|
||||||
// 简单的强制重新计算,修复初始化时的布局问题
|
immersiveContainer.style.display = 'flex';
|
||||||
setTimeout(() => {
|
|
||||||
if (immersiveContainer) {
|
// 简单的强制重新计算,修复初始化时的布局问题
|
||||||
immersiveContainer.offsetHeight; // 触发重新布局
|
|
||||||
}
|
|
||||||
}, 0);
|
|
||||||
|
|
||||||
// 动画进入效果
|
|
||||||
requestAnimationFrame(() => {
|
|
||||||
immersiveContainer.style.opacity = '1';
|
|
||||||
immersiveContainer.style.transform = 'scale(1)';
|
|
||||||
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
document.body.classList.remove('immersive-entering');
|
if (immersiveContainer) {
|
||||||
immersiveContainer.style.transition = '';
|
immersiveContainer.offsetHeight; // 触发重新布局
|
||||||
}, 400);
|
}
|
||||||
});
|
}, 0);
|
||||||
|
|
||||||
|
// 动画进入效果
|
||||||
|
requestAnimationFrame(() => {
|
||||||
|
immersiveContainer.style.opacity = '1';
|
||||||
|
immersiveContainer.style.transform = 'scale(1)';
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
document.body.classList.remove('immersive-entering');
|
||||||
|
immersiveContainer.style.transition = '';
|
||||||
|
}, 400);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 显示页面(移除 pending 状态)
|
||||||
|
document.documentElement.classList.remove('immersive-pending');
|
||||||
|
document.documentElement.classList.add('immersive-ready');
|
||||||
|
document.body.classList.remove('immersive-pending');
|
||||||
|
document.body.classList.add('immersive-ready');
|
||||||
|
|
||||||
if (toggleBtn) {
|
if (toggleBtn) {
|
||||||
toggleBtn.innerHTML = '<i class="fas fa-compress-alt"></i>';
|
toggleBtn.innerHTML = '<i class="fas fa-compress-alt"></i>';
|
||||||
|
|
@ -393,7 +431,6 @@
|
||||||
localStorage.setItem(LS_IMMERSIVE_KEY, 'true');
|
localStorage.setItem(LS_IMMERSIVE_KEY, 'true');
|
||||||
document.dispatchEvent(new CustomEvent('immersiveModeEntered'));
|
document.dispatchEvent(new CustomEvent('immersiveModeEntered'));
|
||||||
}
|
}
|
||||||
|
|
||||||
function exitImmersiveMode() {
|
function exitImmersiveMode() {
|
||||||
reQueryDynamicElements();
|
reQueryDynamicElements();
|
||||||
isImmersiveActive = false;
|
isImmersiveActive = false;
|
||||||
|
|
@ -697,11 +734,21 @@
|
||||||
simpleToggleBtn.innerHTML = '<i class="fas fa-eye-slash"></i>';
|
simpleToggleBtn.innerHTML = '<i class="fas fa-eye-slash"></i>';
|
||||||
simpleToggleBtn.title = '退出简单沉浸模式';
|
simpleToggleBtn.title = '退出简单沉浸模式';
|
||||||
localStorage.setItem(LS_SIMPLE_IMMERSIVE_KEY, 'true');
|
localStorage.setItem(LS_SIMPLE_IMMERSIVE_KEY, 'true');
|
||||||
|
|
||||||
|
// 自动进入全屏
|
||||||
|
document.documentElement.requestFullscreen().catch(err => {
|
||||||
|
console.warn('无法进入全屏模式:', err);
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
// 退出简单沉浸模式
|
// 退出简单沉浸模式
|
||||||
document.body.classList.remove('simple-immersive-pdf-mode');
|
document.body.classList.remove('simple-immersive-pdf-mode');
|
||||||
document.body.classList.remove('simple-immersive-pdf-mode');
|
document.body.classList.remove('simple-immersive-pdf-mode');
|
||||||
|
|
||||||
|
// 如果在全屏状态,退出全屏
|
||||||
|
if (document.fullscreenElement) {
|
||||||
|
document.exitFullscreen();
|
||||||
|
}
|
||||||
|
|
||||||
// 恢复container的padding
|
// 恢复container的padding
|
||||||
if (mainContainer && mainContainer.dataset.originalPadding !== undefined) {
|
if (mainContainer && mainContainer.dataset.originalPadding !== undefined) {
|
||||||
mainContainer.style.padding = mainContainer.dataset.originalPadding;
|
mainContainer.style.padding = mainContainer.dataset.originalPadding;
|
||||||
|
|
@ -758,21 +805,36 @@
|
||||||
|
|
||||||
// Restore immersive state from localStorage
|
// Restore immersive state from localStorage
|
||||||
const savedImmersiveState = localStorage.getItem(LS_IMMERSIVE_KEY);
|
const savedImmersiveState = localStorage.getItem(LS_IMMERSIVE_KEY);
|
||||||
if (savedImmersiveState === 'true') {
|
|
||||||
|
// 历史详情页默认进入沉浸模式,只有用户明确退出过才不进入
|
||||||
|
// 注意:null 表示首次访问,'true' 表示用户之前处于沉浸模式
|
||||||
|
// 只有 'false' 才表示用户主动退出过沉浸模式
|
||||||
|
const shouldEnterImmersive = savedImmersiveState !== 'false';
|
||||||
|
|
||||||
|
console.log('[ImmersiveLayout] savedImmersiveState:', savedImmersiveState, 'shouldEnterImmersive:', shouldEnterImmersive);
|
||||||
|
|
||||||
|
if (shouldEnterImmersive) {
|
||||||
// 检查是否为移动端,如果是则不恢复沉浸模式
|
// 检查是否为移动端,如果是则不恢复沉浸模式
|
||||||
if (window.innerWidth <= 700) {
|
if (window.innerWidth <= 700) {
|
||||||
console.log('检测到移动端设备,不恢复沉浸式布局状态');
|
console.log('检测到移动端设备,不进入沉浸式布局');
|
||||||
localStorage.setItem(LS_IMMERSIVE_KEY, 'false'); // 清除保存的状态
|
localStorage.setItem(LS_IMMERSIVE_KEY, 'false');
|
||||||
return;
|
// 显示页面
|
||||||
|
document.documentElement.classList.remove('immersive-pending');
|
||||||
|
document.documentElement.classList.add('immersive-ready');
|
||||||
|
document.body.classList.remove('immersive-pending');
|
||||||
|
document.body.classList.add('immersive-ready');
|
||||||
|
} else {
|
||||||
|
// 立即进入沉浸模式(静默模式,无动画)
|
||||||
|
console.log('[ImmersiveLayout] 准备进入沉浸模式, isImmersiveActive:', isImmersiveActive);
|
||||||
|
enterImmersiveMode({ silent: true });
|
||||||
|
console.log('[ImmersiveLayout] enterImmersiveMode 调用完成, isImmersiveActive:', isImmersiveActive);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
// Slight delay to ensure other initializations (like TOC, Chatbot) can occur first
|
// 不需要沉浸模式,直接显示页面
|
||||||
// especially if they also interact with elements moved by immersive mode.
|
document.documentElement.classList.remove('immersive-pending');
|
||||||
setTimeout(() => {
|
document.documentElement.classList.add('immersive-ready');
|
||||||
if (!isImmersiveActive) { // Check again in case of race conditions or manual toggle
|
document.body.classList.remove('immersive-pending');
|
||||||
enterImmersiveMode();
|
document.body.classList.add('immersive-ready');
|
||||||
}
|
|
||||||
}, 200); // Adjust delay if needed
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Restore simple immersive state from localStorage
|
// Restore simple immersive state from localStorage
|
||||||
|
|
|
||||||
|
|
@ -2000,7 +2000,7 @@
|
||||||
--doorhanger-icon-opacity: 0.9;
|
--doorhanger-icon-opacity: 0.9;
|
||||||
|
|
||||||
--main-color: rgba(12, 12, 13, 1);
|
--main-color: rgba(12, 12, 13, 1);
|
||||||
--body-bg-color: rgba(212, 212, 215, 1);
|
--body-bg-color: #f3f4f5;
|
||||||
--progressBar-color: rgba(10, 132, 255, 1);
|
--progressBar-color: rgba(10, 132, 255, 1);
|
||||||
--progressBar-bg-color: rgba(221, 221, 222, 1);
|
--progressBar-bg-color: rgba(221, 221, 222, 1);
|
||||||
--progressBar-blend-color: rgba(116, 177, 239, 1);
|
--progressBar-blend-color: rgba(116, 177, 239, 1);
|
||||||
|
|
@ -2011,7 +2011,7 @@
|
||||||
|
|
||||||
--sidebar-narrow-bg-color: rgba(212, 212, 215, 0.9);
|
--sidebar-narrow-bg-color: rgba(212, 212, 215, 0.9);
|
||||||
--sidebar-toolbar-bg-color: rgba(245, 246, 247, 1);
|
--sidebar-toolbar-bg-color: rgba(245, 246, 247, 1);
|
||||||
--toolbar-bg-color: rgba(249, 249, 250, 1);
|
--toolbar-bg-color: #ffffff;
|
||||||
--toolbar-border-color: rgba(184, 184, 184, 1);
|
--toolbar-border-color: rgba(184, 184, 184, 1);
|
||||||
--toolbar-box-shadow: 0 1px 0 var(--toolbar-border-color);
|
--toolbar-box-shadow: 0 1px 0 var(--toolbar-border-color);
|
||||||
--toolbar-border-bottom: none;
|
--toolbar-border-bottom: none;
|
||||||
|
|
@ -2019,7 +2019,7 @@
|
||||||
rgba(0, 0, 0, 0.25),
|
rgba(0, 0, 0, 0.25),
|
||||||
0 1px 0 rgba(0, 0, 0, 0.15), 0 0 1px rgba(0, 0, 0, 0.1);
|
0 1px 0 rgba(0, 0, 0, 0.15), 0 0 1px rgba(0, 0, 0, 0.1);
|
||||||
--toolbarSidebar-border-bottom: none;
|
--toolbarSidebar-border-bottom: none;
|
||||||
--button-hover-color: rgba(221, 222, 223, 1);
|
--button-hover-color: #e6ecfb;
|
||||||
--toggled-btn-color: rgba(0, 0, 0, 1);
|
--toggled-btn-color: rgba(0, 0, 0, 1);
|
||||||
--toggled-btn-bg-color: rgba(0, 0, 0, 0.3);
|
--toggled-btn-bg-color: rgba(0, 0, 0, 0.3);
|
||||||
--toggled-hover-active-btn-color: rgba(0, 0, 0, 0.4);
|
--toggled-hover-active-btn-color: rgba(0, 0, 0, 0.4);
|
||||||
|
|
@ -2308,6 +2308,7 @@ body {
|
||||||
z-index: 9999;
|
z-index: 9999;
|
||||||
cursor: default;
|
cursor: default;
|
||||||
font: message-box;
|
font: message-box;
|
||||||
|
background-color: var(--toolbar-bg-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
:is(.toolbar, .editorParamsToolbar, .findbar, #sidebarContainer)
|
:is(.toolbar, .editorParamsToolbar, .findbar, #sidebarContainer)
|
||||||
|
|
@ -2345,7 +2346,7 @@ body {
|
||||||
position: relative;
|
position: relative;
|
||||||
height: 32px;
|
height: 32px;
|
||||||
background-color: var(--toolbar-bg-color);
|
background-color: var(--toolbar-bg-color);
|
||||||
box-shadow: var(--toolbar-box-shadow);
|
/* box-shadow: var(--toolbar-box-shadow); */
|
||||||
border-bottom: var(--toolbar-border-bottom);
|
border-bottom: var(--toolbar-border-bottom);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -3181,7 +3182,7 @@ a:is(.toolbarButton, .secondaryToolbarButton)[href="#"] {
|
||||||
user-select: none;
|
user-select: none;
|
||||||
}
|
}
|
||||||
#thumbnailView {
|
#thumbnailView {
|
||||||
width: calc(100% - 60px);
|
width: 100%;
|
||||||
padding: 10px 30px 0;
|
padding: 10px 30px 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -29,6 +29,9 @@ See https://github.com/adobe-type-tools/cmap-resources
|
||||||
|
|
||||||
<!-- This snippet is used in production (included from viewer.html) -->
|
<!-- This snippet is used in production (included from viewer.html) -->
|
||||||
<link rel="resource" type="application/l10n" href="locale/locale.properties">
|
<link rel="resource" type="application/l10n" href="locale/locale.properties">
|
||||||
|
<!-- 引入tailwindcss -->
|
||||||
|
<link href="https://cdn.jsdelivr.net/npm/tailwindcss@2.2.19/dist/tailwind.min.css" rel="stylesheet">
|
||||||
|
|
||||||
<script src="../build/pdf.js"></script>
|
<script src="../build/pdf.js"></script>
|
||||||
|
|
||||||
<link rel="stylesheet" href="viewer.css">
|
<link rel="stylesheet" href="viewer.css">
|
||||||
|
|
@ -269,19 +272,20 @@ See https://github.com/adobe-type-tools/cmap-resources
|
||||||
<span id="numPages" class="toolbarLabel"></span>
|
<span id="numPages" class="toolbarLabel"></span>
|
||||||
</div>
|
</div>
|
||||||
<div id="toolbarViewerRight">
|
<div id="toolbarViewerRight">
|
||||||
<button id="openFile" class="toolbarButton hiddenLargeView" title="Open File" tabindex="31" data-l10n-id="open_file">
|
<!-- 直接注释会PDF加载失败 -->
|
||||||
|
<button id="openFile" class="toolbarButton hiddenLargeView hidden" title="Open File" tabindex="31" data-l10n-id="open_file">
|
||||||
<span data-l10n-id="open_file_label">Open</span>
|
<span data-l10n-id="open_file_label">Open</span>
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<button id="print" class="toolbarButton hiddenMediumView" title="Print" tabindex="32" data-l10n-id="print">
|
<button id="print" class="toolbarButton hiddenMediumView hidden" title="Print" tabindex="32" data-l10n-id="print">
|
||||||
<span data-l10n-id="print_label">Print</span>
|
<span data-l10n-id="print_label">Print</span>
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<button id="download" class="toolbarButton hiddenMediumView" title="Save" tabindex="33" data-l10n-id="save">
|
<button id="download" class="toolbarButton hiddenMediumView hidden" title="Save" tabindex="33" data-l10n-id="save">
|
||||||
<span data-l10n-id="save_label">Save</span>
|
<span data-l10n-id="save_label">Save</span>
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<div class="verticalToolbarSeparator hiddenMediumView"></div>
|
<div class="verticalToolbarSeparator hiddenMediumView hidden"></div>
|
||||||
|
|
||||||
<div id="editorModeButtons" class="splitToolbarButton toggled" role="radiogroup">
|
<div id="editorModeButtons" class="splitToolbarButton toggled" role="radiogroup">
|
||||||
<button id="editorFreeText" class="toolbarButton" disabled="disabled" title="Text" role="radio" aria-checked="false" aria-controls="editorFreeTextParamsToolbar" tabindex="34" data-l10n-id="editor_free_text2">
|
<button id="editorFreeText" class="toolbarButton" disabled="disabled" title="Text" role="radio" aria-checked="false" aria-controls="editorFreeTextParamsToolbar" tabindex="34" data-l10n-id="editor_free_text2">
|
||||||
|
|
|
||||||
|
|
@ -86,10 +86,27 @@
|
||||||
<link rel="stylesheet" href="../../css/history_detail.css" />
|
<link rel="stylesheet" href="../../css/history_detail.css" />
|
||||||
|
|
||||||
<!-- All CSS now imported via history_detail.css (Phase 9 完成) -->
|
<!-- All CSS now imported via history_detail.css (Phase 9 完成) -->
|
||||||
|
|
||||||
|
<!-- 页面初始隐藏,等待沉浸模式初始化 -->
|
||||||
|
<style>
|
||||||
|
html.immersive-pending body,
|
||||||
|
body.immersive-pending {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
html.immersive-ready body,
|
||||||
|
body.immersive-ready {
|
||||||
|
opacity: 1;
|
||||||
|
transition: opacity 0.2s ease;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<script>
|
||||||
|
// 在 DOM 解析前就添加类,避免闪烁
|
||||||
|
document.documentElement.classList.add('immersive-pending');
|
||||||
|
</script>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body class="immersive-pending">
|
||||||
<!-- Standard Immersive Mode Toggle Button -->
|
<!-- Standard Immersive Mode Toggle Button -->
|
||||||
<button id="toggle-immersive-btn" class="tiny-round-btn" title="进入沉浸式布局">
|
<button id="toggle-immersive-btn" class="tiny-round-btn hidden" style="display: none;" title="进入沉浸式布局">
|
||||||
<i class="fas fa-expand-alt"></i>
|
<i class="fas fa-expand-alt"></i>
|
||||||
<!-- Default icon for entering immersive mode -->
|
<!-- Default icon for entering immersive mode -->
|
||||||
</button>
|
</button>
|
||||||
|
|
@ -400,9 +417,9 @@
|
||||||
<h2 id="fileName">历史详情</h2>
|
<h2 id="fileName">历史详情</h2>
|
||||||
<div class="meta" id="fileMeta">
|
<div class="meta" id="fileMeta">
|
||||||
<div class="meta-info">
|
<div class="meta-info">
|
||||||
<span id="fileMetaTime"></span>
|
<!-- <span id="fileMetaTime"></span>
|
||||||
<span class="meta-separator">|</span>
|
<span class="meta-separator">|</span>
|
||||||
<span id="fileMetaImages"></span>
|
<span id="fileMetaImages"></span> -->
|
||||||
</div>
|
</div>
|
||||||
<button
|
<button
|
||||||
class="meta-export-trigger"
|
class="meta-export-trigger"
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue