feat(前端界面): 导出面板居中显示,统一弹窗样式
build.yaml / build (push) Successful in 36s

This commit is contained in:
xiaoqidun committed 2026-09-14 12:43:32 +08:00
1 parent ee0606cf78
commit a7e86a322f
3 files changed
+56 -49

No files matched your search

+9 -9
View File
@@ -50,29 +50,29 @@
<option value="600">600</option> <option value="600">600</option>
</select> </select>
<button id="exportPageButton" class="button" type="button" data-short="单" title="导出单页" aria-label="导出单页" disabled>单页</button> <button id="exportPageButton" class="button" type="button" data-short="单" title="导出单页" aria-label="导出单页" disabled>单页</button>
<button id="exportButton" class="button" type="button" data-short="多" title="导出文档" aria-label="导出文档" aria-haspopup="dialog" popovertarget="exportPanel" disabled>文档</button> <button id="exportButton" class="button" type="button" data-short="多" title="导出文档" aria-label="导出文档" aria-haspopup="dialog" aria-controls="exportPanel" disabled>文档</button>
</div> </div>
</header> </header>
<div id="exportPanel" class="export-panel" popover role="dialog" aria-label="导出文档"> <dialog id="exportPanel" class="form-dialog" aria-label="导出文档">
<form id="exportForm"> <form id="exportForm">
<div class="export-row"> <div class="form-row">
<span id="exportScopeLabel">范围</span> <span id="exportScopeLabel">范围</span>
<div class="export-options" role="radiogroup" aria-labelledby="exportScopeLabel"> <div class="form-options" role="radiogroup" aria-labelledby="exportScopeLabel">
<label><input id="exportAll" type="radio" name="scope" value="all" checked autofocus><span>全部</span></label> <label><input id="exportAll" type="radio" name="scope" value="all" checked autofocus><span>全部</span></label>
<label><input id="exportSpecified" type="radio" name="scope" value="specified"><span>指定</span></label> <label><input id="exportSpecified" type="radio" name="scope" value="specified"><span>指定</span></label>
</div> </div>
</div> </div>
<div id="exportRangeRow" class="export-row" hidden> <div id="exportRangeRow" class="form-row" hidden>
<label for="exportRange">页码</label> <label for="exportRange">页码</label>
<input id="exportRange" type="text" aria-describedby="exportRangeStatus" autocomplete="off" spellcheck="false"> <input id="exportRange" type="text" aria-describedby="exportRangeStatus" autocomplete="off" spellcheck="false">
</div> </div>
<div class="export-actions"> <div class="form-actions">
<div id="exportRangeStatus" class="export-range-status" role="status" aria-live="polite"></div> <div id="exportRangeStatus" class="form-status" role="status" aria-live="polite"></div>
<button class="button" type="button" popovertarget="exportPanel" popovertargetaction="hide">取消</button> <button id="exportCancel" class="button" type="button">取消</button>
<button id="exportSubmit" class="button" type="submit">导出</button> <button id="exportSubmit" class="button" type="submit">导出</button>
</div> </div>
</form> </form>
</div> </dialog>
<main class="workspace"> <main class="workspace">
<aside class="page-list-panel"> <aside class="page-list-panel">
+30 -29
View File
@@ -256,15 +256,13 @@ button:not(:disabled):hover {
width: 54px; width: 54px;
} }
.export-panel { .form-dialog {
top: calc(var(--bar-height) + 8px); inset: 0;
right: 0; width: 320px;
bottom: auto; max-width: calc(100% - 24px);
left: auto; max-height: calc(100dvh - 24px);
width: var(--sidebar-width); margin: auto;
max-height: calc(100dvh - var(--bar-height) - 18px); padding: 0;
margin: 0;
padding: 12px;
border: 1px solid var(--line); border: 1px solid var(--line);
background: var(--panel); background: var(--panel);
color: #1f2428; color: #1f2428;
@@ -272,7 +270,15 @@ button:not(:disabled):hover {
font-size: 14px; font-size: 14px;
} }
.export-row { .form-dialog::backdrop {
background: rgb(31 36 40 / 18%);
}
.form-dialog > form {
padding: 12px;
}
.form-row {
display: grid; display: grid;
grid-template-columns: 2em minmax(0, 1fr); grid-template-columns: 2em minmax(0, 1fr);
align-items: center; align-items: center;
@@ -280,22 +286,22 @@ button:not(:disabled):hover {
margin-bottom: 12px; margin-bottom: 12px;
} }
.export-options { .form-options {
display: flex; display: flex;
} }
.export-options label { .form-options label {
position: relative; position: relative;
flex: 1; flex: 1;
cursor: pointer; cursor: pointer;
} }
.export-options input { .form-options input {
position: absolute; position: absolute;
opacity: 0; opacity: 0;
} }
.export-options span { .form-options span {
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
@@ -304,22 +310,22 @@ button:not(:disabled):hover {
background: #ffffff; background: #ffffff;
} }
.export-options label + label span { .form-options label + label span {
border-left: 0; border-left: 0;
} }
.export-options input:checked + span { .form-options input:checked + span {
background: #e4f3ef; background: #e4f3ef;
color: var(--accent-strong); color: var(--accent-strong);
box-shadow: 0 0 0 1px var(--accent) inset; box-shadow: 0 0 0 1px var(--accent) inset;
} }
.export-options input:focus-visible + span { .form-options input:focus-visible + span {
outline: 2px solid var(--focus); outline: 2px solid var(--focus);
outline-offset: 2px; outline-offset: 2px;
} }
.export-row input[type="text"] { .form-row input[type="text"] {
width: 100%; width: 100%;
min-width: 0; min-width: 0;
height: var(--control-height); height: var(--control-height);
@@ -330,11 +336,11 @@ button:not(:disabled):hover {
color: #1f2428; color: #1f2428;
} }
.export-row input[aria-invalid="true"] { .form-row input[aria-invalid="true"] {
border-color: #b14343; border-color: #b14343;
} }
.export-range-status { .form-status {
min-width: 0; min-width: 0;
color: var(--text-muted); color: var(--text-muted);
font-size: 12px; font-size: 12px;
@@ -342,20 +348,20 @@ button:not(:disabled):hover {
overflow-wrap: anywhere; overflow-wrap: anywhere;
} }
.export-actions { .form-actions {
display: grid; display: grid;
grid-template-columns: minmax(0, 1fr) auto auto; grid-template-columns: minmax(0, 1fr) auto auto;
align-items: center; align-items: center;
gap: 8px; gap: 8px;
} }
#exportSubmit { .form-actions button[type="submit"] {
border-color: var(--accent); border-color: var(--accent);
background: var(--accent); background: var(--accent);
color: #ffffff; color: #ffffff;
} }
#exportSubmit:not(:disabled):hover { .form-actions button[type="submit"]:not(:disabled):hover {
background: var(--accent-strong); background: var(--accent-strong);
} }
@@ -794,7 +800,7 @@ button.outline-link:hover {
.empty-state[hidden], .empty-state[hidden],
.meta-list > [hidden], .meta-list > [hidden],
.navigation-tabs[hidden], .navigation-tabs[hidden],
.export-row[hidden], .form-row[hidden],
.page-list[hidden], .page-list[hidden],
.page-frame[hidden], .page-frame[hidden],
.progress-panel[hidden] { .progress-panel[hidden] {
@@ -1430,11 +1436,6 @@ button.outline-link:hover {
--sidebar-width: min(78vw, 292px); --sidebar-width: min(78vw, 292px);
} }
.export-panel {
right: 10px;
width: min(300px, calc(100% - 20px));
}
.toolbar { .toolbar {
--tool-gap: 6px; --tool-gap: 6px;
} }
+17 -11
View File
@@ -67,6 +67,7 @@ const state = {
visibleThumbnails: new Set(), visibleThumbnails: new Set(),
exportFormats: [], exportFormats: [],
exportPages: null, exportPages: null,
exportBackdrop: false,
showPages: !COMPACT_LAYOUT.matches, showPages: !COMPACT_LAYOUT.matches,
showMeta: !COMPACT_LAYOUT.matches, showMeta: !COMPACT_LAYOUT.matches,
}; };
@@ -105,6 +106,7 @@ const el = {
exportRangeRow: document.querySelector("#exportRangeRow"), exportRangeRow: document.querySelector("#exportRangeRow"),
exportRange: document.querySelector("#exportRange"), exportRange: document.querySelector("#exportRange"),
exportRangeStatus: document.querySelector("#exportRangeStatus"), exportRangeStatus: document.querySelector("#exportRangeStatus"),
exportCancel: document.querySelector("#exportCancel"),
exportSubmit: document.querySelector("#exportSubmit"), exportSubmit: document.querySelector("#exportSubmit"),
emptyState: document.querySelector("#emptyState"), emptyState: document.querySelector("#emptyState"),
progressPanel: document.querySelector("#progressPanel"), progressPanel: document.querySelector("#progressPanel"),
@@ -210,7 +212,16 @@ document.addEventListener("selectionchange", () => {
}); });
el.exportFormat.addEventListener("change", () => updateDPIControl()); el.exportFormat.addEventListener("change", () => updateDPIControl());
el.exportPageButton.addEventListener("click", () => exportFile(false)); el.exportPageButton.addEventListener("click", () => exportFile(false));
el.exportPanel.addEventListener("beforetoggle", prepareExportPanel); el.exportButton.addEventListener("click", openExportPanel);
el.exportCancel.addEventListener("click", () => el.exportPanel.close());
el.exportPanel.addEventListener("pointerdown", (event) => {
state.exportBackdrop = event.target === el.exportPanel;
});
el.exportPanel.addEventListener("click", (event) => {
if (state.exportBackdrop && event.target === el.exportPanel) {
el.exportPanel.close();
}
});
el.exportAll.addEventListener("change", updateExportRange); el.exportAll.addEventListener("change", updateExportRange);
el.exportSpecified.addEventListener("change", () => { el.exportSpecified.addEventListener("change", () => {
updateExportRange(); updateExportRange();
@@ -275,7 +286,7 @@ updateSidebarState();
boot(); boot();
function handleKeyDown(event) { function handleKeyDown(event) {
if (event.defaultPrevented || event.isComposing || event.altKey || document.body.hasAttribute("aria-busy") || el.exportPanel.matches(":popover-open")) { if (event.defaultPrevented || event.isComposing || event.altKey || document.body.hasAttribute("aria-busy") || el.exportPanel.open) {
return; return;
} }
const key = event.key; const key = event.key;
@@ -1508,16 +1519,13 @@ async function downloadAttachment(attachment) {
} }
} }
function prepareExportPanel(event) { function openExportPanel() {
if (event.newState !== "open") {
return;
}
if (!state.doc || document.body.hasAttribute("aria-busy")) { if (!state.doc || document.body.hasAttribute("aria-busy")) {
event.preventDefault();
return; return;
} }
el.exportForm.reset(); el.exportForm.reset();
updateExportRange(); updateExportRange();
el.exportPanel.showModal();
} }
async function updateExportRange() { async function updateExportRange() {
@@ -1532,7 +1540,7 @@ async function updateExportRange() {
if (!specified || !value) { if (!specified || !value) {
return; return;
} }
const current = () => openSeq === state.openSeq && el.exportPanel.matches(":popover-open") const current = () => openSeq === state.openSeq && el.exportPanel.open
&& el.exportSpecified.checked && value === el.exportRange.value.trim(); && el.exportSpecified.checked && value === el.exportRange.value.trim();
try { try {
const indices = await callWASM("ofdgoParsePageRange", value); const indices = await callWASM("ofdgoParsePageRange", value);
@@ -3322,9 +3330,7 @@ function setBusy(busy, text = "", percent = 0, status = "") {
} }
return; return;
} }
if (el.exportPanel.matches(":popover-open")) { el.exportPanel.close();
el.exportPanel.hidePopover();
}
endPan(); endPan();
el.progressPanel.hidden = false; el.progressPanel.hidden = false;
setProgress(text, percent, status); setProgress(text, percent, status);