diff --git a/explorer/app.js b/explorer/app.js
index 4bd2a51..bd29c9f 100644
--- a/explorer/app.js
+++ b/explorer/app.js
@@ -629,10 +629,24 @@ function wireGlobal() {
for (const tab of els.tabs) tab.addEventListener('click', () => setView(tab.dataset.view));
document.getElementById('print').addEventListener('click', () => window.print());
// The PDF and PNG are rendered by CI next to the deployed site; local previews don't have them.
- for (const link of document.querySelectorAll('[data-download]')) {
+ const download = document.getElementById('download');
+ for (const link of download.querySelectorAll('[data-download]')) {
fetch(link.getAttribute('href'), { method: 'HEAD', cache: 'no-cache' })
- .then((response) => { link.hidden = !response.ok; }, () => {});
+ .then((response) => {
+ link.hidden = !response.ok;
+ if (response.ok) download.hidden = false;
+ }, () => {});
+ link.addEventListener('click', () => { download.open = false; });
}
+ document.addEventListener('pointerdown', (e) => {
+ if (download.open && !download.contains(e.target)) download.open = false;
+ });
+ download.addEventListener('keydown', (e) => {
+ if (e.key !== 'Escape' || !download.open) return;
+ e.stopPropagation();
+ download.open = false;
+ download.querySelector('summary').focus();
+ });
// Printing always produces the diagram, whatever view is open.
let viewBeforePrint = null;
window.addEventListener('beforeprint', () => {
diff --git a/explorer/index.html b/explorer/index.html
index 24a61bf..0fc4297 100644
--- a/explorer/index.html
+++ b/explorer/index.html
@@ -38,12 +38,15 @@
-
- PDF
-
-
- PNG
-
+
diff --git a/explorer/styles.css b/explorer/styles.css
index 536f786..10d2fd6 100644
--- a/explorer/styles.css
+++ b/explorer/styles.css
@@ -351,16 +351,59 @@ button {
background: var(--chip-hover);
}
-.text-btn {
- width: auto;
- grid-auto-flow: column;
- gap: 6px;
- padding: 0 11px;
- font-size: 13px;
- font-weight: 600;
+.download-menu {
+ position: relative;
+}
+
+.download-menu > summary {
+ list-style: none;
+}
+
+.download-menu > summary::-webkit-details-marker {
+ display: none;
+}
+
+.download-menu[open] > summary {
+ border-color: var(--accent);
+}
+
+.download-panel {
+ position: absolute;
+ top: calc(100% + 8px);
+ right: 0;
+ display: grid;
+ gap: 2px;
+ min-width: 190px;
+ padding: 6px;
+ border: 1px solid var(--border);
+ border-radius: var(--radius);
+ background: var(--surface-solid);
+ box-shadow: var(--shadow);
+}
+
+.download-item {
+ display: grid;
+ gap: 1px;
+ padding: 8px 10px;
+ border-radius: 8px;
+ color: var(--text);
text-decoration: none;
}
+.download-item:hover,
+.download-item:focus-visible {
+ background: var(--chip-hover);
+}
+
+.download-item b {
+ font-size: 14px;
+}
+
+.download-item span {
+ color: var(--muted);
+ font-size: 12px;
+}
+
/* Layout */
.layout {
@@ -1128,14 +1171,6 @@ button {
#print {
display: none;
}
-
- .text-btn {
- padding: 0 9px;
- }
-
- .text-btn svg {
- display: none;
- }
}
@media (prefers-reduced-motion: reduce) {