|
@@ -6,10 +6,30 @@
|
|
|
<meta name="google" content="notranslate">
|
|
<meta name="google" content="notranslate">
|
|
|
<title>PDF.js viewer</title>
|
|
<title>PDF.js viewer</title>
|
|
|
|
|
|
|
|
- <link rel="resource" type="application/l10n" href="locale/locale.json">
|
|
|
|
|
- <script src="../build/pdf.mjs" type="module"></script>
|
|
|
|
|
- <link rel="stylesheet" href="viewer.css">
|
|
|
|
|
- <script src="viewer.mjs" type="module"></script>
|
|
|
|
|
|
|
+ <link rel="resource" type="application/l10n" href="locale/locale.json">
|
|
|
|
|
+ <script src="../build/pdf.mjs" type="module"></script>
|
|
|
|
|
+ <link rel="stylesheet" href="viewer.css">
|
|
|
|
|
+ <script>
|
|
|
|
|
+ (function () {
|
|
|
|
|
+ const NIGHT_MODE_STORAGE_KEY = 'reader_pro.night_mode';
|
|
|
|
|
+ const PDFJS_PREFERENCES_KEY = 'pdfjs.preferences';
|
|
|
|
|
+ const nightModeEnabled = localStorage.getItem(NIGHT_MODE_STORAGE_KEY) === '1';
|
|
|
|
|
+ let preferences = {};
|
|
|
|
|
+
|
|
|
|
|
+ try {
|
|
|
|
|
+ preferences = JSON.parse(localStorage.getItem(PDFJS_PREFERENCES_KEY)) || {};
|
|
|
|
|
+ } catch (e) {
|
|
|
|
|
+ preferences = {};
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ preferences.forcePageColors = nightModeEnabled;
|
|
|
|
|
+ preferences.pageColorsBackground = '#0b0b0b';
|
|
|
|
|
+ preferences.pageColorsForeground = '#f5f5f5';
|
|
|
|
|
+
|
|
|
|
|
+ localStorage.setItem(PDFJS_PREFERENCES_KEY, JSON.stringify(preferences));
|
|
|
|
|
+ })();
|
|
|
|
|
+ </script>
|
|
|
|
|
+ <script src="viewer.mjs" type="module"></script>
|
|
|
|
|
|
|
|
<style>
|
|
<style>
|
|
|
/* 模态窗口样式 */
|
|
/* 模态窗口样式 */
|
|
@@ -78,9 +98,14 @@
|
|
|
color: black;
|
|
color: black;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- .button-stop {
|
|
|
|
|
- background-color: #dc3545;
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ .button-stop {
|
|
|
|
|
+ background-color: #dc3545;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .button-night {
|
|
|
|
|
+ background-color: #1f2937;
|
|
|
|
|
+ color: #f9fafb;
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
/* 底部按钮栏 */
|
|
/* 底部按钮栏 */
|
|
|
.bottom-bar {
|
|
.bottom-bar {
|
|
@@ -198,10 +223,34 @@
|
|
|
font-size: 14px;
|
|
font-size: 14px;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- .pagination button:disabled {
|
|
|
|
|
- background-color: #6c757d;
|
|
|
|
|
- cursor: not-allowed;
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ .pagination button:disabled {
|
|
|
|
|
+ background-color: #6c757d;
|
|
|
|
|
+ cursor: not-allowed;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ body.night-reading-mode {
|
|
|
|
|
+ background: #0b1220;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ body.night-reading-mode #viewerContainer {
|
|
|
|
|
+ background: #0f172a;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ body.night-reading-mode .toolbar,
|
|
|
|
|
+ body.night-reading-mode #loading-indicator,
|
|
|
|
|
+ body.night-reading-mode .user-menu-trigger,
|
|
|
|
|
+ body.night-reading-mode .user-menu-panel,
|
|
|
|
|
+ body.night-reading-mode .modal {
|
|
|
|
|
+ box-shadow: 0 5px 15px rgba(0, 0, 0, 0.45);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ body.night-reading-mode .bottom-bar {
|
|
|
|
|
+ background-color: rgba(15, 23, 42, 0.18);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ body.night-reading-mode .pdfViewer .page {
|
|
|
|
|
+ box-shadow: 0 8px 24px rgba(0, 0, 0, 0.55);
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
/* 手机端优化 */
|
|
/* 手机端优化 */
|
|
|
@media (max-width: 768px) {
|
|
@media (max-width: 768px) {
|
|
@@ -240,14 +289,15 @@
|
|
|
|
|
|
|
|
<audio id="audio-player" controls></audio>
|
|
<audio id="audio-player" controls></audio>
|
|
|
|
|
|
|
|
- <div class="bottom-bar">
|
|
|
|
|
- <button id="uploadButton" class="button">上传 PDF</button>
|
|
|
|
|
- <button id="openDirectoryButton" class="button">打开目录</button>
|
|
|
|
|
- <button id="select-all-text" class="button button-light">阅读整页</button>
|
|
|
|
|
- <button id="pause-play-button" class="button button-pause">暂停播放</button>
|
|
|
|
|
- <button id="stop-play-button" class="button button-stop">停止</button>
|
|
|
|
|
- <button id="toggle-text-select" class="button button-success">文本选择</button>
|
|
|
|
|
- </div>
|
|
|
|
|
|
|
+ <div class="bottom-bar">
|
|
|
|
|
+ <button id="uploadButton" class="button">上传 PDF</button>
|
|
|
|
|
+ <button id="openDirectoryButton" class="button">打开目录</button>
|
|
|
|
|
+ <button id="nightModeButton" class="button button-night">夜间模式</button>
|
|
|
|
|
+ <button id="select-all-text" class="button button-light">阅读整页</button>
|
|
|
|
|
+ <button id="pause-play-button" class="button button-pause">暂停播放</button>
|
|
|
|
|
+ <button id="stop-play-button" class="button button-stop">停止</button>
|
|
|
|
|
+ <button id="toggle-text-select" class="button button-success">文本选择</button>
|
|
|
|
|
+ </div>
|
|
|
|
|
|
|
|
<input type="file" id="pdfInput" accept="application/pdf" style="display: none;" />
|
|
<input type="file" id="pdfInput" accept="application/pdf" style="display: none;" />
|
|
|
|
|
|
|
@@ -1099,24 +1149,60 @@
|
|
|
const pdfList = document.getElementById('pdfList');
|
|
const pdfList = document.getElementById('pdfList');
|
|
|
const prevPageButton = document.getElementById('prevPage');
|
|
const prevPageButton = document.getElementById('prevPage');
|
|
|
const nextPageButton = document.getElementById('nextPage');
|
|
const nextPageButton = document.getElementById('nextPage');
|
|
|
- const pageInfo = document.getElementById('pageInfo');
|
|
|
|
|
- const readPageButton = document.getElementById('select-all-text');
|
|
|
|
|
- const pausePlayButton = document.getElementById('pause-play-button');
|
|
|
|
|
- const stopPlayButton = document.getElementById('stop-play-button');
|
|
|
|
|
- const bottomBar = document.querySelector('.bottom-bar');
|
|
|
|
|
- const userMenu = document.getElementById('userMenu');
|
|
|
|
|
- const userMenuTrigger = document.getElementById('userMenuTrigger');
|
|
|
|
|
- const userMenuPanel = document.getElementById('userMenuPanel');
|
|
|
|
|
- const userLogoutBtn = document.getElementById('userLogoutBtn');
|
|
|
|
|
|
|
+ const pageInfo = document.getElementById('pageInfo');
|
|
|
|
|
+ const readPageButton = document.getElementById('select-all-text');
|
|
|
|
|
+ const pausePlayButton = document.getElementById('pause-play-button');
|
|
|
|
|
+ const stopPlayButton = document.getElementById('stop-play-button');
|
|
|
|
|
+ const nightModeButton = document.getElementById('nightModeButton');
|
|
|
|
|
+ const bottomBar = document.querySelector('.bottom-bar');
|
|
|
|
|
+ const userMenu = document.getElementById('userMenu');
|
|
|
|
|
+ const userMenuTrigger = document.getElementById('userMenuTrigger');
|
|
|
|
|
+ const userMenuPanel = document.getElementById('userMenuPanel');
|
|
|
|
|
+ const userLogoutBtn = document.getElementById('userLogoutBtn');
|
|
|
const userAdminBtn = document.getElementById('userAdminBtn');
|
|
const userAdminBtn = document.getElementById('userAdminBtn');
|
|
|
|
|
|
|
|
let selectedFile = null;
|
|
let selectedFile = null;
|
|
|
let currentPage = 1;
|
|
let currentPage = 1;
|
|
|
const itemsPerPage = 10;
|
|
const itemsPerPage = 10;
|
|
|
- let allFiles = [];
|
|
|
|
|
- let selectedStartContext = null;
|
|
|
|
|
- const currentFilePath = new URLSearchParams(window.location.search).get('file') || '';
|
|
|
|
|
- let isRestoringProgress = false;
|
|
|
|
|
|
|
+ let allFiles = [];
|
|
|
|
|
+ let selectedStartContext = null;
|
|
|
|
|
+ const currentFilePath = new URLSearchParams(window.location.search).get('file') || '';
|
|
|
|
|
+ let isRestoringProgress = false;
|
|
|
|
|
+ const NIGHT_MODE_STORAGE_KEY = 'reader_pro.night_mode';
|
|
|
|
|
+
|
|
|
|
|
+ function updateNightModeButton(isEnabled) {
|
|
|
|
|
+ nightModeButton.textContent = isEnabled ? '日间模式' : '夜间模式';
|
|
|
|
|
+ nightModeButton.classList.toggle('button-light', isEnabled);
|
|
|
|
|
+ nightModeButton.classList.toggle('button-night', !isEnabled);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ function setNightMode(enabled) {
|
|
|
|
|
+ document.body.classList.toggle('night-reading-mode', enabled);
|
|
|
|
|
+ updateNightModeButton(enabled);
|
|
|
|
|
+ localStorage.setItem(NIGHT_MODE_STORAGE_KEY, enabled ? '1' : '0');
|
|
|
|
|
+ syncPdfJsNightPreferences(enabled);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ function syncPdfJsNightPreferences(enabled) {
|
|
|
|
|
+ const pdfjsPreferencesKey = 'pdfjs.preferences';
|
|
|
|
|
+ let preferences = {};
|
|
|
|
|
+
|
|
|
|
|
+ try {
|
|
|
|
|
+ preferences = JSON.parse(localStorage.getItem(pdfjsPreferencesKey)) || {};
|
|
|
|
|
+ } catch (e) {
|
|
|
|
|
+ preferences = {};
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ preferences.forcePageColors = enabled;
|
|
|
|
|
+ preferences.pageColorsBackground = '#0b0b0b';
|
|
|
|
|
+ preferences.pageColorsForeground = '#f5f5f5';
|
|
|
|
|
+ localStorage.setItem(pdfjsPreferencesKey, JSON.stringify(preferences));
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ function initNightMode() {
|
|
|
|
|
+ const enabled = localStorage.getItem(NIGHT_MODE_STORAGE_KEY) === '1';
|
|
|
|
|
+ setNightMode(enabled);
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
async function ensureLoggedIn() {
|
|
async function ensureLoggedIn() {
|
|
|
try {
|
|
try {
|
|
@@ -1155,11 +1241,17 @@
|
|
|
window.location.href = '/login';
|
|
window.location.href = '/login';
|
|
|
}
|
|
}
|
|
|
});
|
|
});
|
|
|
- userAdminBtn.addEventListener('click', function () {
|
|
|
|
|
- window.location.href = '/admin';
|
|
|
|
|
- });
|
|
|
|
|
-
|
|
|
|
|
- function syncBottomBarToPage() {
|
|
|
|
|
|
|
+ userAdminBtn.addEventListener('click', function () {
|
|
|
|
|
+ window.location.href = '/admin';
|
|
|
|
|
+ });
|
|
|
|
|
+ initNightMode();
|
|
|
|
|
+ nightModeButton.addEventListener('click', function () {
|
|
|
|
|
+ const nextEnabled = !document.body.classList.contains('night-reading-mode');
|
|
|
|
|
+ setNightMode(nextEnabled);
|
|
|
|
|
+ window.location.reload();
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ function syncBottomBarToPage() {
|
|
|
if (!bottomBar) return;
|
|
if (!bottomBar) return;
|
|
|
|
|
|
|
|
const app = window.PDFViewerApplication;
|
|
const app = window.PDFViewerApplication;
|