File size: 13,269 Bytes
6812842 d5cb752 fbe729d 6812842 3d104ce 218784c 66de2cb 63e5da3 6812842 0af7fa0 6812842 e9de0d6 6812842 eb88517 6812842 d20d6b0 6812842 eb88517 6812842 077a90a 6812842 077a90a 6b8d48e fcf504e 6b8d48e 077a90a 6812842 1bc540d 6812842 78c490a 6812842 27c4b90 6812842 fcf504e e9de0d6 45cb842 5f3f559 094309f 5f3f559 dc91f34 a9741bd dc91f34 6812842 7184e6e 6812842 7184e6e 6812842 7184e6e 6812842 7184e6e 6812842 3ec41fd 6812842 3ec41fd 6812842 eb88517 6812842 9956b4b a80fa01 9956b4b a80fa01 9956b4b 6812842 eb88517 6812842 3d104ce eb88517 fbe729d 6812842 fcf504e | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 | <!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script>if (matchMedia("(max-width: 768px)").matches && localStorage.getItem("mobileMode") !== "desktop") document.documentElement.classList.add("mobile-boot");</script>
<title>VoiceOfML Search</title>
<link rel="manifest" href="/manifest.json">
<meta name="theme-color" content="#1a1c1e">
<meta name="mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
<meta name="apple-mobile-web-app-title" content="VoiceOfML">
<link rel="apple-touch-icon" href="/icons/icon-192.png">
<link rel="icon" type="image/png" sizes="192x192" href="/icons/icon-192.png">
<link rel="icon" type="image/png" sizes="512x512" href="/icons/icon-512.png">
<link rel="icon" type="image/svg+xml" href="/icons/icon.svg">
<script>fetch("/api/ping", { cache: "no-store" }).catch(() => {});</script>
<link rel="preload" href="/api/reader-assets" as="fetch" crossorigin="anonymous">
<link rel="stylesheet" href="/static/style.css">
</head>
<body class="dark">
<header id="header">
<div class="header-left">
<button id="hamburger-btn" class="icon-btn" aria-label="菜单" title="侧边栏 (Ctrl+B)">
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round">
<line x1="4" y1="6" x2="20" y2="6"/>
<line x1="4" y1="12" x2="20" y2="12"/>
<line x1="4" y1="18" x2="20" y2="18"/>
</svg>
</button>
<a id="header-logo" class="header-logo" href="/" title="VoiceOfML">
<img class="header-logo-icon header-logo-icon-dark" src="/icons/logo-dark.svg" alt="" width="28" height="28">
<img class="header-logo-icon header-logo-icon-light" src="/icons/logo.svg" alt="" width="28" height="28">
<span id="header-title">VoiceOfML</span>
</a>
</div>
<div class="header-center">
<div class="search-box" id="search-box">
<svg class="search-icon" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<circle cx="11" cy="11" r="8"/>
<line x1="21" y1="21" x2="16.65" y2="16.65"/>
</svg>
<input type="search" id="search-input" class="search-input"
placeholder="搜索 VoiceOfML 数据仓库..."
autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false">
<kbd class="search-kbd" id="search-kbd">/</kbd>
<div id="search-history-dropdown" class="search-history-dropdown" style="display:none"></div>
</div>
</div>
<div class="header-right">
<button id="settings-btn" class="icon-btn" aria-label="搜索设置" title="搜索过滤">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<circle cx="11" cy="11" r="8"/>
<line x1="21" y1="21" x2="16.65" y2="16.65"/>
<line x1="8" y1="11" x2="14" y2="11"/>
<line x1="11" y1="8" x2="11" y2="14"/>
</svg>
</button>
<button id="theme-btn" class="icon-btn" aria-label="切换主题" title="深色/浅色模式">
<svg id="theme-icon-light" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" style="display:none">
<circle cx="12" cy="12" r="5"/>
<line x1="12" y1="1" x2="12" y2="3"/><line x1="12" y1="21" x2="12" y2="23"/>
<line x1="4.22" y1="4.22" x2="5.64" y2="5.64"/><line x1="18.36" y1="18.36" x2="19.78" y2="19.78"/>
<line x1="1" y1="12" x2="3" y2="12"/><line x1="21" y1="12" x2="23" y2="12"/>
<line x1="4.22" y1="19.78" x2="5.64" y2="18.36"/><line x1="18.36" y1="5.64" x2="19.78" y2="4.22"/>
</svg>
<svg id="theme-icon-dark" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path d="M21 12.79A9 9 0 1111.21 3 7 7 0 0021 12.79z"/>
</svg>
</button>
<button id="mobile-toggle-btn" class="icon-btn" aria-label="切换视图" title="手机/电脑版">
<svg id="mobile-icon-phone" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" style="display:none">
<rect x="5" y="2" width="14" height="20" rx="2" ry="2"/>
<line x1="12" y1="18" x2="12.01" y2="18"/>
</svg>
<svg id="mobile-icon-desktop" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<rect x="2" y="3" width="20" height="14" rx="2" ry="2"/>
<line x1="8" y1="21" x2="16" y2="21"/>
<line x1="12" y1="17" x2="12" y2="21"/>
</svg>
</button>
</div>
</header>
<div id="app-body" class="app-body">
<aside id="left-sidebar" class="sidebar left-sidebar">
<div class="sidebar-header">
<span id="sidebar-title">仓库列表</span>
<button id="sidebar-expand-btn" class="icon-btn-sm" title="展开/收起侧边栏" style="display:none">↔</button>
</div>
<div id="sidebar-content" class="sidebar-content">
<div class="sidebar-loading">加载中...</div>
</div>
</aside>
<main id="main-content" class="main-content">
<div id="status-bar" class="status-bar">
<div class="status-left">
<span id="result-count" class="result-count"></span>
<label class="multi-toggle" id="multi-toggle-label" style="display:none">
<input type="checkbox" id="multi-select-toggle">
<span>多选</span>
</label>
</div>
<div class="status-right">
<button id="clear-filters-btn" class="text-btn" style="display:none">清空筛选</button>
<div class="sort-group">
<span class="sort-label">排序:</span>
<select id="sort-select" class="sort-select">
<option value="relevance">相关度</option>
<option value="name">文件名</option>
<option value="size">文件大小</option>
</select>
</div>
</div>
</div>
<div id="multi-action-bar" class="multi-action-bar" style="display:none">
<button id="multi-select-all" class="multi-action-btn">全选</button>
<button id="multi-deselect" class="multi-action-btn">取消选择</button>
<button id="multi-copy-links" class="multi-action-btn">复制链接</button>
<button id="multi-batch-download" class="multi-action-btn primary">批量下载</button>
<span id="multi-selected-count" class="multi-selected-count"></span>
</div>
<div id="results-container" class="results-container">
<div id="results-list" class="results-list" role="listbox" aria-label="搜索结果"></div>
<div id="results-loading" class="loading-spinner" style="display:none">
<div class="spinner"></div>
</div>
<div id="empty-state" class="empty-state" style="display:none">
<svg class="empty-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5">
<circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/>
<line x1="8" y1="11" x2="14" y2="11"/>
</svg>
<div class="empty-title">没有找到结果</div>
<div id="empty-desc" class="empty-desc">试试其他关键词</div>
<button id="empty-random-btn" class="random-big-btn">
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path d="M2 3h6a4 4 0 014 4v14a3 3 0 00-3-3H2z"/>
<path d="M22 3h-6a4 4 0 00-4 4v14a3 3 0 013-3h7z"/>
</svg>
随机来本书
</button>
</div>
</div>
<div id="load-info" class="load-info" style="display:none">
<span id="mobile-selected-count" class="mobile-selected-count" style="display:none"></span>
已加载 <span id="loaded-count">0</span> / <span id="total-count">0</span> 条
</div>
<div id="scroll-track" class="scroll-track">
<div id="scroll-thumb" class="scroll-thumb"></div>
</div>
</main>
<aside id="right-sidebar" class="sidebar right-sidebar">
<div class="sidebar-header">
<span>搜索过滤</span>
<button id="close-filters-btn" class="icon-btn-sm" aria-label="关闭过滤">×</button>
</div>
<div class="sidebar-content">
<div class="filter-section" id="mirror-links-section">
<label class="toggle-row">
<span class="toggle-label">镜像链接</span>
<input type="checkbox" id="mirror-links-toggle" checked>
<span class="toggle-switch"></span>
</label>
</div>
<div class="filter-section" id="history-toggle-section">
<label class="toggle-row">
<span class="toggle-label">记录搜索历史</span>
<input type="checkbox" id="history-toggle" checked>
<span class="toggle-switch"></span>
</label>
</div>
<div class="filter-section" id="search-folders-section">
<label class="toggle-row">
<span class="toggle-label">搜索文件夹名</span>
<input type="checkbox" id="search-folders-toggle" checked>
<span class="toggle-switch"></span>
</label>
</div>
<div class="filter-section" id="exact-search-section">
<label class="toggle-row">
<span class="toggle-label">精准搜索(支持通配符*和?)</span>
<input type="checkbox" id="exact-search-toggle" checked>
<span class="toggle-switch"></span>
</label>
</div>
<div id="filter-repo-section" class="filter-section">
<div class="filter-section-title">
<span class="filter-title-leading"><span>仓库过滤</span><button id="repo-filter-cancel" class="text-btn-sm" hidden>取消</button></span>
</div>
<div id="filter-repo-list" class="filter-checkbox-list"></div>
</div>
<div id="filter-folder-section" class="filter-section">
<div class="filter-section-title">
<span class="filter-title-leading"><span>路径过滤</span><button id="folder-filter-cancel" class="text-btn-sm" hidden>取消</button></span>
<span class="filter-actions">
<button id="folder-select-all" class="text-btn-sm">全选</button>
<button id="folder-deselect-all" class="text-btn-sm">反选</button>
</span>
</div>
<div id="filter-folder-tree" class="filter-folder-tree"></div>
</div>
<div id="filter-ext-section" class="filter-section">
<div class="filter-section-title">
<span class="filter-title-leading"><span>文件类型</span><button id="ext-filter-cancel" class="text-btn-sm" hidden>取消</button></span>
<span class="filter-actions">
<button id="ext-select-all" class="text-btn-sm">全选</button>
<button id="ext-deselect-all" class="text-btn-sm">反选</button>
</span>
</div>
<div id="filter-ext-list" class="filter-checkbox-list"></div>
</div>
<div class="filter-section">
<div class="filter-section-title">文件大小</div>
<div class="filter-size-row">
<input type="number" id="filter-min-size" class="size-input" placeholder="最小" min="0" step="0.1">
<select id="filter-min-unit" class="size-unit">
<option value="B">B</option>
<option value="KB">KB</option>
<option value="MB" selected>MB</option>
<option value="GB">GB</option>
</select>
<span class="size-sep">—</span>
<input type="number" id="filter-max-size" class="size-input" placeholder="最大" min="0" step="0.1">
<select id="filter-max-unit" class="size-unit">
<option value="B">B</option>
<option value="KB">KB</option>
<option value="MB" selected>MB</option>
<option value="GB">GB</option>
</select>
</div>
</div>
</div>
</aside>
</div>
<footer id="footer" class="footer">
<div id="hitokoto" class="hitokoto"></div>
<button id="random-book-btn" class="random-txt-btn" title="随机下本书">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path d="M14 2H6a2 2 0 00-2 2v16a2 2 0 002 2h12a2 2 0 002-2V8z"/>
<polyline points="14 2 14 8 20 8"/>
<line x1="8" y1="13" x2="16" y2="13"/>
<line x1="8" y1="17" x2="14" y2="17"/>
</svg>
随机下本书
</button>
<button id="random-txt-btn" class="random-book-btn" title="随机来本书">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path d="M2 3h6a4 4 0 014 4v14a3 3 0 00-3-3H2z"/>
<path d="M22 3h-6a4 4 0 00-4 4v14a3 3 0 013-3h7z"/>
</svg>
随机来本书
</button>
</footer>
<div id="overlay" class="overlay" style="display:none"></div>
<div id="toast" class="toast" style="display:none"></div>
<script>
if ("serviceWorker" in navigator) {
navigator.serviceWorker.register("/sw.js", { scope: "/" });
}
</script>
<script src="/static/reader-contract.js"></script>
<script src="/static/app.js"></script>
</body>
</html>
|