diff options
-rw-r--r--assets/cgit.css36
-rw-r--r--assets/cgit.js46
2 files changed, 76 insertions, 6 deletions
diff --git a/assets/cgit.css b/assets/cgit.css
index 540480c..8c6f7a4 100644
--- a/assets/cgit.css
+++ b/assets/cgit.css
@@ -263,16 +263,40 @@ div#cgit .tabs {
div#cgit .tabs ul {
display: flex;
- flex-wrap: wrap;
align-items: flex-end;
flex: 1 1 auto;
- gap: 0.1em 0.15em;
+ min-width: 0;
+ gap: 0.15em;
list-style: none;
margin: 0;
padding: 0;
+ overflow-x: auto;
+ scrollbar-width: none;
+}
+
+div#cgit .tabs ul::-webkit-scrollbar {
+ display: none;
+}
+
+div#cgit .tabs ul.fade-start {
+ -webkit-mask-image: linear-gradient(to right, transparent, #000 1.5em);
+ mask-image: linear-gradient(to right, transparent, #000 1.5em);
+}
+
+div#cgit .tabs ul.fade-end {
+ -webkit-mask-image: linear-gradient(to left, transparent, #000 1.5em);
+ mask-image: linear-gradient(to left, transparent, #000 1.5em);
+}
+
+div#cgit .tabs ul.fade-start.fade-end {
+ -webkit-mask-image: linear-gradient(to right, transparent, #000 1.5em,
+ #000 calc(100% - 1.5em), transparent);
+ mask-image: linear-gradient(to right, transparent, #000 1.5em,
+ #000 calc(100% - 1.5em), transparent);
}
div#cgit .tabs li {
+ flex: none;
margin: 0;
}
@@ -283,6 +307,10 @@ div#cgit .tabs a {
border-radius: var(--radius) var(--radius) 0 0;
}
+div#cgit .tabs a:focus-visible {
+ outline-offset: -2px;
+}
+
div#cgit .tabs a:hover {
color: var(--fg);
background-color: var(--surface);
@@ -1310,6 +1338,10 @@ div#cgit table.ssdiff td.space {
}
@media (max-width: 640px) {
+ div#cgit .tabs a {
+ padding: 0.3em 0.4em;
+ }
+
div#cgit .col-desc,
div#cgit .col-owner,
div#cgit .col-links {
diff --git a/assets/cgit.js b/assets/cgit.js
index 807f15f..90f06c0 100644
--- a/assets/cgit.js
+++ b/assets/cgit.js
@@ -2,10 +2,11 @@
* The client side script that cgit serves with every page. Its main job is
* to refresh the relative ages that cgit_print_age renders in
* source/ui-shared.c, so the thresholds, suffixes and class names tabulated
- * below mirror the constants there and the two have to move together. One
- * smaller piece follows, the highlight laid over the source line a URL
- * fragment names. Each piece is wrapped in a function of its own so that
- * nothing is left behind in the global scope.
+ * below mirror the constants there and the two have to move together. Two
+ * smaller pieces follow, the highlight laid over the source line a URL
+ * fragment names, and the tabs kept in view on a window too narrow for them.
+ * Each piece is wrapped in a function of its own so that nothing is left
+ * behind in the global scope.
*/
(function () {
@@ -166,3 +167,40 @@ window.cgit = window.cgit || {};
window.cgit.highlightLines = place_bar;
})();
+
+/*
+ * The tabs scroll sideways when the window is too narrow for them, so the
+ * active one is brought into view, and the edge past which more tabs are
+ * hidden is faded to show that the row goes on.
+ */
+
+(function () {
+
+function fade_tabs(list) {
+ var hidden = list.scrollWidth - list.clientWidth;
+
+ // A fractional scroll position can stop a pixel short of either end.
+ list.classList.toggle("fade-start", list.scrollLeft > 1);
+ list.classList.toggle("fade-end", list.scrollLeft < hidden - 1);
+}
+
+function fit_tabs() {
+ var list = document.querySelector("nav.tabs ul");
+ var active, list_box, tab_box;
+
+ if (!list)
+ return;
+ active = list.querySelector("a.active");
+ if (active && list.scrollWidth > list.clientWidth) {
+ list_box = list.getBoundingClientRect();
+ tab_box = active.getBoundingClientRect();
+ list.scrollLeft += tab_box.left - list_box.left - (list_box.width - tab_box.width) / 2;
+ }
+ fade_tabs(list);
+ list.addEventListener("scroll", function () { fade_tabs(list); }, { passive: true });
+ window.addEventListener("resize", function () { fade_tabs(list); }, false);
+}
+
+document.addEventListener("DOMContentLoaded", fit_tabs, false);
+
+})();