vomebook commited on
Commit
c35d100
·
1 Parent(s): cecef69

Upload 2 files

Browse files
Files changed (2) hide show
  1. static/app.js +36 -4
  2. static/style.css +4 -0
static/app.js CHANGED
@@ -6,6 +6,7 @@ const STATE = {
6
  pageSize: 100,
7
  total: 0,
8
  results: [],
 
9
  sources: [],
10
  sourceMap: {},
11
  folderTree: [],
@@ -372,6 +373,7 @@ function syncUrl(replace = true) {
372
  if (!STATE.leftSidebarOpen) params.set("sidebar", "0");
373
  if (DOM.leftSidebar.classList.contains("expanded-wide")) params.set("wide", "1");
374
  if (STATE.rightSidebarOpen) params.set("filters", "1");
 
375
  const basePath = STATE.source ? `/${encodeURIComponent(STATE.source)}` : "/";
376
  const nextUrl = params.toString() ? `${basePath}?${params.toString()}` : basePath;
377
  if (replace) history.replaceState(null, "", nextUrl);
@@ -398,6 +400,7 @@ function loadUrlState() {
398
  DOM.sortSelect.value = sort;
399
  STATE.leftSidebarOpen = !STATE.isMobile && params.get("sidebar") !== "0";
400
  STATE.rightSidebarOpen = params.get("filters") === "1";
 
401
  DOM.leftSidebar.classList.toggle("expanded-wide", params.get("wide") === "1" && !STATE.isMobile);
402
  if (DOM.sidebarExpandBtn) DOM.sidebarExpandBtn.textContent = params.get("wide") === "1" && !STATE.isMobile ? "→" : "↔";
403
  if (STATE.minSize !== null) DOM.filterMinSize.value = STATE.minSize;
@@ -574,7 +577,7 @@ function renderResults() {
574
  DOM.multiActionBar.style.display = STATE.multiSelect ? "" : "none";
575
  }
576
 
577
- async function openPreview(docId, keyword) {
578
  try {
579
  const data = await API.preview(docId);
580
  if (data.error) {
@@ -590,18 +593,39 @@ async function openPreview(docId, keyword) {
590
  }
591
  DOM.previewPanel.innerHTML = `
592
  <div class="preview-header">
593
- <div class="preview-title">${escapeHTML(data.title)}</div>
594
- <div class="preview-path">${escapeHTML(data.source)} / ${escapeHTML(data.path)}</div>
 
 
 
595
  </div>
596
  <pre class="preview-body">${text}</pre>`;
597
  DOM.previewPanel.style.display = "block";
598
- DOM.previewPanel.scrollIntoView({ behavior: "smooth", block: "start" });
 
 
599
  } catch (error) {
600
  console.error(error);
601
  showToast("预览失败");
602
  }
603
  }
604
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
605
  function renderCheckboxList(container, items, selected, onChange) {
606
  container.innerHTML = items.map((item) => `
607
  <label class="filter-checkbox-item">
@@ -1312,6 +1336,10 @@ function attachEvents() {
1312
  doSearch();
1313
  }
1314
  });
 
 
 
 
1315
  document.addEventListener("keydown", (event) => {
1316
  if (event.key === "/" && document.activeElement !== DOM.searchInput) {
1317
  event.preventDefault();
@@ -1321,8 +1349,11 @@ function attachEvents() {
1321
  });
1322
  window.addEventListener("popstate", async () => {
1323
  syncRoute();
 
1324
  await renderSidebar();
1325
  await renderFolderTree();
 
 
1326
  doSearch();
1327
  });
1328
  }
@@ -1352,6 +1383,7 @@ async function init() {
1352
  }
1353
  updateSidebarVisibility();
1354
  syncUrl();
 
1355
  doSearch();
1356
  }
1357
 
 
6
  pageSize: 100,
7
  total: 0,
8
  results: [],
9
+ previewDocId: null,
10
  sources: [],
11
  sourceMap: {},
12
  folderTree: [],
 
373
  if (!STATE.leftSidebarOpen) params.set("sidebar", "0");
374
  if (DOM.leftSidebar.classList.contains("expanded-wide")) params.set("wide", "1");
375
  if (STATE.rightSidebarOpen) params.set("filters", "1");
376
+ if (STATE.previewDocId) params.set("preview", STATE.previewDocId);
377
  const basePath = STATE.source ? `/${encodeURIComponent(STATE.source)}` : "/";
378
  const nextUrl = params.toString() ? `${basePath}?${params.toString()}` : basePath;
379
  if (replace) history.replaceState(null, "", nextUrl);
 
400
  DOM.sortSelect.value = sort;
401
  STATE.leftSidebarOpen = !STATE.isMobile && params.get("sidebar") !== "0";
402
  STATE.rightSidebarOpen = params.get("filters") === "1";
403
+ STATE.previewDocId = params.get("preview") || null;
404
  DOM.leftSidebar.classList.toggle("expanded-wide", params.get("wide") === "1" && !STATE.isMobile);
405
  if (DOM.sidebarExpandBtn) DOM.sidebarExpandBtn.textContent = params.get("wide") === "1" && !STATE.isMobile ? "→" : "↔";
406
  if (STATE.minSize !== null) DOM.filterMinSize.value = STATE.minSize;
 
577
  DOM.multiActionBar.style.display = STATE.multiSelect ? "" : "none";
578
  }
579
 
580
+ async function openPreview(docId, keyword, options = {}) {
581
  try {
582
  const data = await API.preview(docId);
583
  if (data.error) {
 
593
  }
594
  DOM.previewPanel.innerHTML = `
595
  <div class="preview-header">
596
+ <div>
597
+ <div class="preview-title">${escapeHTML(data.title)}</div>
598
+ <div class="preview-path">${escapeHTML(data.source)} / ${escapeHTML(data.path)}</div>
599
+ </div>
600
+ <button type="button" class="icon-btn-sm" data-action="close-preview" aria-label="关闭预览">×</button>
601
  </div>
602
  <pre class="preview-body">${text}</pre>`;
603
  DOM.previewPanel.style.display = "block";
604
+ STATE.previewDocId = docId;
605
+ if (options.sync !== false) syncUrl();
606
+ if (options.scroll !== false) DOM.previewPanel.scrollIntoView({ behavior: "smooth", block: "start" });
607
  } catch (error) {
608
  console.error(error);
609
  showToast("预览失败");
610
  }
611
  }
612
 
613
+ function closePreview() {
614
+ STATE.previewDocId = null;
615
+ DOM.previewPanel.innerHTML = "";
616
+ DOM.previewPanel.style.display = "none";
617
+ syncUrl();
618
+ }
619
+
620
+ function restorePreviewFromUrl(options = {}) {
621
+ if (!STATE.previewDocId) {
622
+ DOM.previewPanel.innerHTML = "";
623
+ DOM.previewPanel.style.display = "none";
624
+ return;
625
+ }
626
+ openPreview(STATE.previewDocId, STATE.query, { sync: false, scroll: options.scroll === true });
627
+ }
628
+
629
  function renderCheckboxList(container, items, selected, onChange) {
630
  container.innerHTML = items.map((item) => `
631
  <label class="filter-checkbox-item">
 
1336
  doSearch();
1337
  }
1338
  });
1339
+ DOM.previewPanel.addEventListener("click", (event) => {
1340
+ const closeBtn = event.target.closest("[data-action='close-preview']");
1341
+ if (closeBtn) closePreview();
1342
+ });
1343
  document.addEventListener("keydown", (event) => {
1344
  if (event.key === "/" && document.activeElement !== DOM.searchInput) {
1345
  event.preventDefault();
 
1349
  });
1350
  window.addEventListener("popstate", async () => {
1351
  syncRoute();
1352
+ loadUrlState();
1353
  await renderSidebar();
1354
  await renderFolderTree();
1355
+ updateSidebarVisibility();
1356
+ restorePreviewFromUrl({ scroll: false });
1357
  doSearch();
1358
  });
1359
  }
 
1383
  }
1384
  updateSidebarVisibility();
1385
  syncUrl();
1386
+ restorePreviewFromUrl({ scroll: false });
1387
  doSearch();
1388
  }
1389
 
static/style.css CHANGED
@@ -448,6 +448,10 @@ ul, li {
448
  }
449
 
450
  .preview-header {
 
 
 
 
451
  padding: 12px 14px;
452
  border-bottom: 1px solid var(--outline-variant);
453
  }
 
448
  }
449
 
450
  .preview-header {
451
+ display: flex;
452
+ align-items: flex-start;
453
+ justify-content: space-between;
454
+ gap: 12px;
455
  padding: 12px 14px;
456
  border-bottom: 1px solid var(--outline-variant);
457
  }