Skip to content

Commit b13440e

Browse files
committed
Improve resource navigation and mobile layout
1 parent 02c4302 commit b13440e

2 files changed

Lines changed: 38 additions & 10 deletions

File tree

project-site.css

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,8 +71,10 @@ footer a { color: var(--accent); }
7171
.problem-archive .resource-grid { margin: 0 0 20px; }
7272

7373
@media (max-width: 700px) {
74-
nav { gap: 12px; }
75-
nav a:first-child { display: none; }
74+
.topbar-inner { min-height: 60px; flex-wrap: wrap; padding-block: 11px; }
75+
nav { width: 100%; gap: 16px; overflow-x: auto; padding-bottom: 3px; scrollbar-width: none; }
76+
nav::-webkit-scrollbar { display: none; }
77+
nav a { flex: 0 0 auto; }
7678
.hero { padding-block: 70px; }
7779
.hero h1 { font-size: clamp(3.1rem, 16vw, 5rem); }
7880
.content, .repo-index-head { grid-template-columns: 1fr; }

project-viewer.js

Lines changed: 34 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -177,8 +177,6 @@
177177
if (href) {
178178
var link = doc.createElement('a');
179179
link.href = href;
180-
link.target = '_blank';
181-
link.rel = 'noopener noreferrer';
182180
appendText(link, linkMatch[1]);
183181
parent.appendChild(link);
184182
} else {
@@ -277,6 +275,7 @@
277275
button.className = className;
278276
button.dataset.viewerAction = action;
279277
button.textContent = label;
278+
if (action === 'close') button.setAttribute('aria-label', 'Close resource viewer');
280279
return button;
281280
}
282281

@@ -294,8 +293,10 @@
294293
this.downloadObjectUrl = '';
295294
this.requestId = 0;
296295
this.initialized = false;
296+
this.historyEntry = false;
297297
this.onDocumentClick = this.onDocumentClick.bind(this);
298298
this.onDocumentKeydown = this.onDocumentKeydown.bind(this);
299+
this.onPopState = this.onPopState.bind(this);
299300
this.onDialogClick = this.onDialogClick.bind(this);
300301
this.onDialogCancel = this.onDialogCancel.bind(this);
301302
this.init();
@@ -307,6 +308,7 @@
307308
this.buildDialog();
308309
doc.addEventListener('click', this.onDocumentClick);
309310
doc.addEventListener('keydown', this.onDocumentKeydown);
311+
global.addEventListener('popstate', this.onPopState);
310312
this.initialized = true;
311313
return this;
312314
};
@@ -358,13 +360,9 @@
358360
var download = doc.createElement('a');
359361
download.className = 'resource-viewer-action';
360362
download.textContent = 'Download';
361-
download.target = '_blank';
362-
download.rel = 'noopener';
363363
var original = doc.createElement('a');
364364
original.className = 'resource-viewer-action secondary';
365365
original.textContent = 'Open original';
366-
original.target = '_blank';
367-
original.rel = 'noopener';
368366
actions.appendChild(download);
369367
actions.appendChild(original);
370368
footer.appendChild(note);
@@ -393,6 +391,23 @@
393391
this.open(link);
394392
};
395393

394+
ProjectResourceViewer.prototype.onPopState = function (event) {
395+
if (event.state && event.state.projectViewerPath) {
396+
var links = doc.querySelectorAll('a.resource-link');
397+
var link = Array.prototype.find.call(links, function (candidate) {
398+
return candidate.dataset.path === event.state.projectViewerPath;
399+
});
400+
if (link) {
401+
this.open(link, { fromHistory: true });
402+
return;
403+
}
404+
}
405+
if (this.isOpen()) {
406+
this.historyEntry = false;
407+
this.close({ fromPopstate: true });
408+
}
409+
};
410+
396411
ProjectResourceViewer.prototype.onDocumentKeydown = function (event) {
397412
if (!this.isOpen()) return;
398413
if (event.key === 'Escape' || event.key === 'Esc') {
@@ -434,7 +449,8 @@
434449
}
435450
};
436451

437-
ProjectResourceViewer.prototype.open = function (link) {
452+
ProjectResourceViewer.prototype.open = function (link, options) {
453+
options = options || {};
438454
var pathValue = link.dataset.path || link.getAttribute('href') || '';
439455
var url = safeUrl(pathValue, doc.baseURI);
440456
if (!url) {
@@ -448,6 +464,10 @@
448464
try { problemFiles = JSON.parse(link.dataset.problemFiles); } catch (error) { problemFiles = []; }
449465
}
450466
var item = { kind: kind, path: pathValue, url: url, title: title, fileName: link.dataset.fileName || basename(pathValue), problemFiles: problemFiles };
467+
if (!options.fromHistory) {
468+
global.history.pushState({ projectViewerPath: pathValue }, '', global.location.href);
469+
this.historyEntry = true;
470+
}
451471
this.previousFocus = doc.activeElement;
452472
this.requestId += 1;
453473
var requestId = this.requestId;
@@ -741,7 +761,12 @@
741761
this.downloadObjectUrl = '';
742762
};
743763

744-
ProjectResourceViewer.prototype.close = function () {
764+
ProjectResourceViewer.prototype.close = function (options) {
765+
options = options || {};
766+
if (this.historyEntry && !options.fromPopstate) {
767+
this.historyEntry = false;
768+
global.history.back();
769+
}
745770
this.requestId += 1;
746771
if (this.abortController && typeof this.abortController.abort === 'function') this.abortController.abort();
747772
this.abortController = null;
@@ -762,6 +787,7 @@
762787
this.close();
763788
doc.removeEventListener('click', this.onDocumentClick);
764789
doc.removeEventListener('keydown', this.onDocumentKeydown);
790+
global.removeEventListener('popstate', this.onPopState);
765791
if (this.dialog) this.dialog.remove();
766792
this.dialog = null;
767793
this.initialized = false;

0 commit comments

Comments
 (0)