mirror of
https://github.com/xiaoqidun/ofdgo.git
synced 2026-10-29 16:44:23 +08:00
This commit is contained in:
1 parent
90bc7b93dc
commit
c2899deff1
7 files changed
+238
-17
No files matched your search
@@ -54,8 +54,13 @@
|
||||
|
||||
<main class="workspace">
|
||||
<aside class="page-list-panel">
|
||||
<div class="panel-title">页面</div>
|
||||
<div id="pageList" class="page-list"></div>
|
||||
<div id="pageListTitle" class="panel-title">页面</div>
|
||||
<div id="navigationTabs" class="navigation-tabs" role="tablist" aria-label="文档导航" hidden>
|
||||
<button id="pagesTab" type="button" role="tab" aria-selected="true" aria-controls="pageList">页面</button>
|
||||
<button id="outlinesTab" type="button" role="tab" aria-selected="false" aria-controls="outlineList" tabindex="-1">目录</button>
|
||||
</div>
|
||||
<div id="pageList" class="page-list" role="tabpanel" aria-label="页面"></div>
|
||||
<div id="outlineList" role="tabpanel" aria-label="目录" hidden></div>
|
||||
</aside>
|
||||
|
||||
<section class="viewer-panel" tabindex="0">
|
||||
|
||||
@@ -371,6 +371,84 @@ body[data-hide-meta] .meta-panel {
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.navigation-tabs {
|
||||
display: flex;
|
||||
gap: 16px;
|
||||
margin-bottom: 10px;
|
||||
border-bottom: 1px solid var(--line);
|
||||
}
|
||||
|
||||
.navigation-tabs button {
|
||||
height: 28px;
|
||||
padding: 0 0 6px;
|
||||
border: 0;
|
||||
border-bottom: 2px solid transparent;
|
||||
background: transparent;
|
||||
color: var(--text-muted);
|
||||
font-size: 12px;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.navigation-tabs button[aria-selected="true"] {
|
||||
border-bottom-color: var(--accent);
|
||||
color: var(--accent-strong);
|
||||
}
|
||||
|
||||
.outline-list {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
.outline-list .outline-list {
|
||||
padding-left: 14px;
|
||||
}
|
||||
|
||||
.outline-list summary {
|
||||
margin-left: 14px;
|
||||
color: var(--text-muted);
|
||||
cursor: pointer;
|
||||
list-style-position: outside;
|
||||
}
|
||||
|
||||
.outline-leaf {
|
||||
padding-left: 14px;
|
||||
}
|
||||
|
||||
.outline-link {
|
||||
display: inline-flex;
|
||||
align-items: baseline;
|
||||
gap: 8px;
|
||||
width: 100%;
|
||||
min-height: 30px;
|
||||
height: auto;
|
||||
padding: 5px 4px;
|
||||
border: 0;
|
||||
background: transparent;
|
||||
font-size: 13px;
|
||||
line-height: 1.5;
|
||||
text-align: left;
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
.outline-link > :first-child {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
overflow-wrap: anywhere;
|
||||
}
|
||||
|
||||
.outline-page {
|
||||
flex-shrink: 0;
|
||||
color: var(--text-muted);
|
||||
font-size: 12px;
|
||||
font-variant-numeric: tabular-nums;
|
||||
}
|
||||
|
||||
button.outline-link:hover {
|
||||
background: #e4f3ef;
|
||||
color: var(--accent-strong);
|
||||
}
|
||||
|
||||
.page-list {
|
||||
display: grid;
|
||||
gap: 8px;
|
||||
@@ -470,6 +548,8 @@ body[data-hide-meta] .meta-panel {
|
||||
}
|
||||
|
||||
.empty-state[hidden],
|
||||
.navigation-tabs[hidden],
|
||||
.page-list[hidden],
|
||||
.page-frame[hidden],
|
||||
.progress-panel[hidden] {
|
||||
display: none;
|
||||
|
||||
@@ -93,7 +93,12 @@ const el = {
|
||||
viewerPanel: document.querySelector(".viewer-panel"),
|
||||
svgHost: document.querySelector("#svgHost"),
|
||||
pageListPanel: document.querySelector(".page-list-panel"),
|
||||
pageListTitle: document.querySelector("#pageListTitle"),
|
||||
navigationTabs: document.querySelector("#navigationTabs"),
|
||||
pagesTab: document.querySelector("#pagesTab"),
|
||||
outlinesTab: document.querySelector("#outlinesTab"),
|
||||
pageList: document.querySelector("#pageList"),
|
||||
outlineList: document.querySelector("#outlineList"),
|
||||
metaPanel: document.querySelector(".meta-panel"),
|
||||
appPanel: document.querySelector("#appPanel"),
|
||||
offlineStatus: document.querySelector("#offlineStatus"),
|
||||
@@ -119,6 +124,16 @@ const el = {
|
||||
el.ofdButton.addEventListener("click", openOFDFile);
|
||||
el.togglePagesButton.addEventListener("click", () => toggleSidebar("pages"));
|
||||
el.toggleMetaButton.addEventListener("click", () => toggleSidebar("meta"));
|
||||
el.pagesTab.addEventListener("click", () => showOutlines(false));
|
||||
el.outlinesTab.addEventListener("click", () => showOutlines(true));
|
||||
el.navigationTabs.addEventListener("keydown", (event) => {
|
||||
if (["ArrowLeft", "ArrowRight", "Home", "End"].includes(event.key)) {
|
||||
event.preventDefault();
|
||||
const outlines = event.key === "End" || (event.key !== "Home" && el.outlineList.hidden);
|
||||
showOutlines(outlines);
|
||||
(outlines ? el.outlinesTab : el.pagesTab).focus();
|
||||
}
|
||||
});
|
||||
el.fontAddButton.addEventListener("click", () => openFontFile(el.fontInput));
|
||||
el.fontDirectoryButton.addEventListener("click", () => openFontFile(el.fontDirectoryInput));
|
||||
el.localFontButton.addEventListener("click", loadLocalFonts);
|
||||
@@ -1178,6 +1193,9 @@ async function openDocument(options = {}) {
|
||||
}
|
||||
resetPageFlow();
|
||||
renderPageList();
|
||||
if (options.resetScroll || el.outlineList.childElementCount === 0) {
|
||||
renderOutlines();
|
||||
}
|
||||
renderMeta();
|
||||
renderPageFlow();
|
||||
if (options.resetScroll) {
|
||||
@@ -1748,6 +1766,68 @@ function prefixSVGIds(svg, prefix) {
|
||||
}
|
||||
}
|
||||
|
||||
function showOutlines(show) {
|
||||
el.pageList.hidden = show;
|
||||
el.outlineList.hidden = !show;
|
||||
el.pagesTab.setAttribute("aria-selected", String(!show));
|
||||
el.outlinesTab.setAttribute("aria-selected", String(show));
|
||||
el.pagesTab.tabIndex = show ? -1 : 0;
|
||||
el.outlinesTab.tabIndex = show ? 0 : -1;
|
||||
el.pageListPanel.scrollTop = 0;
|
||||
}
|
||||
|
||||
function renderOutlines() {
|
||||
const outlines = state.doc.outlines || [];
|
||||
el.pageListTitle.hidden = outlines.length > 0;
|
||||
el.navigationTabs.hidden = outlines.length === 0;
|
||||
el.outlineList.replaceChildren();
|
||||
if (outlines.length > 0) {
|
||||
el.outlineList.append(createOutlineList(outlines));
|
||||
}
|
||||
showOutlines(false);
|
||||
}
|
||||
|
||||
function createOutlineList(outlines) {
|
||||
const list = document.createElement("ul");
|
||||
list.className = "outline-list";
|
||||
for (const outline of outlines) {
|
||||
const item = document.createElement("li");
|
||||
const hasChildren = outline.children?.length > 0;
|
||||
const row = document.createElement(hasChildren ? "summary" : "div");
|
||||
if (!hasChildren) {
|
||||
row.className = "outline-leaf";
|
||||
}
|
||||
const link = document.createElement(outline.page ? "button" : "span");
|
||||
link.className = "outline-link";
|
||||
const title = document.createElement("span");
|
||||
title.textContent = outline.title;
|
||||
link.append(title);
|
||||
if (outline.page) {
|
||||
link.type = "button";
|
||||
const page = document.createElement("span");
|
||||
page.className = "outline-page";
|
||||
page.textContent = String(outline.page);
|
||||
page.setAttribute("aria-label", `第 ${outline.page} 页`);
|
||||
link.append(page);
|
||||
link.addEventListener("click", (event) => {
|
||||
event.preventDefault();
|
||||
renderPage(outline.page - 1);
|
||||
});
|
||||
}
|
||||
row.append(link);
|
||||
if (hasChildren) {
|
||||
const details = document.createElement("details");
|
||||
details.open = outline.expanded;
|
||||
details.append(row, createOutlineList(outline.children));
|
||||
item.append(details);
|
||||
} else {
|
||||
item.append(row);
|
||||
}
|
||||
list.append(item);
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
function renderPageList() {
|
||||
el.pageList.replaceChildren();
|
||||
if (!state.doc) {
|
||||
|
||||
Reference in new issue
Block a user