vole
Clone
Read only, no credentials:
https://rodent.software/git/vole.git
Write over SSH with a registered key:
git clone ssh://git@0.0.0.0:2222/vole.git
A free and open-source forge that lives in your Git repo.
Make the change request sidebar compact and live
d3dcf54d8b7eb81fcc2b944296329098db7f14f4 · Keenan Nemetz · 11d ago · parent 7137f372
Make the change request sidebar compact and live Move the review and approval explanations into tooltips, show only the state in each section, and use the overview's run rows for checks. The aside now polls a new fragment endpoint so approvals, checks and landing facts appear without a reload.
server/web/static/vole.css +69−6
| @@ -1517,14 +1517,74 @@ details[open] > summary .tree-chevron { transform: rotate(90deg); } | |||
| 1517 | 1517 | } | |
| 1518 | 1518 | .thread-main { min-width: 0; } | |
| 1519 | 1519 | .thread-side section { padding: 12px 0 14px; border-bottom: 1px solid var(--border); } | |
| 1520 | .thread-side > section:first-child { padding-top: 0; } | ||
| 1520 | .thread-side > section:first-child, | ||
| 1521 | .thread-side #request-aside > section:first-child { padding-top: 0; } | ||
| 1521 | 1522 | .thread-side > section:last-child, | |
| 1522 | 1523 | .thread-side #request-sidebar > section:last-child { border-bottom: 0; } | |
| 1523 | .section-link { margin: 9px 0 0; font-size: calc(13.2px * var(--font-scale)); } | ||
| 1524 | 1524 | .thread-side h2 { margin: 0 0 8px; } | |
| 1525 | 1525 | .thread-side form { margin: 8px 0 0; } | |
| 1526 | 1526 | .thread-side .meta-list { margin-bottom: 0; } | |
| 1527 | 1527 | ||
| 1528 | /* The run rows beside a change use the same compact shape as the recent runs | ||
| 1529 | on the overview: status and job, then the context under them. */ | ||
| 1530 | .thread-side .side-meta { flex-wrap: wrap; white-space: normal; } | ||
| 1531 | .thread-side .side-meta > span { min-width: 0; overflow: hidden; text-overflow: ellipsis; } | ||
| 1532 | |||
| 1533 | /* A `?` next to a section heading: the explanation is a tooltip rather than a | ||
| 1534 | paragraph, so the panel keeps only the state it is about. The tooltip opens | ||
| 1535 | to the left because the sidebar sits at the right edge of the page. */ | ||
| 1536 | .help { | ||
| 1537 | position: relative; | ||
| 1538 | display: inline-grid; | ||
| 1539 | place-items: center; | ||
| 1540 | width: 15px; | ||
| 1541 | height: 15px; | ||
| 1542 | margin-left: 6px; | ||
| 1543 | border: 1px solid var(--border-strong); | ||
| 1544 | border-radius: 50%; | ||
| 1545 | color: var(--fg-faint); | ||
| 1546 | font-family: var(--font); | ||
| 1547 | font-size: calc(10px * var(--font-scale)); | ||
| 1548 | font-weight: 600; | ||
| 1549 | line-height: 1; | ||
| 1550 | vertical-align: 1px; | ||
| 1551 | cursor: help; | ||
| 1552 | user-select: none; | ||
| 1553 | } | ||
| 1554 | .help:hover, | ||
| 1555 | .help:focus-visible { color: var(--accent); border-color: var(--accent); outline: none; } | ||
| 1556 | .help::after { | ||
| 1557 | content: attr(data-tip); | ||
| 1558 | position: absolute; | ||
| 1559 | top: 50%; | ||
| 1560 | right: calc(100% + 8px); | ||
| 1561 | z-index: 20; | ||
| 1562 | width: max-content; | ||
| 1563 | max-width: 210px; | ||
| 1564 | padding: 7px 9px; | ||
| 1565 | border: 1px solid var(--border-strong); | ||
| 1566 | border-radius: var(--radius); | ||
| 1567 | background: var(--bg-raised); | ||
| 1568 | color: var(--fg); | ||
| 1569 | font-size: calc(12.1px * var(--font-scale)); | ||
| 1570 | font-weight: 400; | ||
| 1571 | line-height: 1.45; | ||
| 1572 | letter-spacing: normal; | ||
| 1573 | text-align: left; | ||
| 1574 | white-space: normal; | ||
| 1575 | transform: translateY(-50%); | ||
| 1576 | opacity: 0; | ||
| 1577 | visibility: hidden; | ||
| 1578 | pointer-events: none; | ||
| 1579 | box-shadow: 0 6px 20px rgba(0, 0, 0, 0.35); | ||
| 1580 | } | ||
| 1581 | .help:hover::after, | ||
| 1582 | .help:focus::after, | ||
| 1583 | .help:focus-visible::after { opacity: 1; visibility: visible; } | ||
| 1584 | @media (prefers-reduced-motion: no-preference) { | ||
| 1585 | .help::after { transition: opacity 120ms ease; } | ||
| 1586 | } | ||
| 1587 | |||
| 1528 | 1588 | /* Scope the card to the article that renders it. Prism calls a syntax token | |
| 1529 | 1589 | "comment" too, and an unscoped .comment rule put a rounded panel behind every | |
| 1530 | 1590 | comment-coloured line in a blob or diff. */ | |
| @@ -1795,7 +1855,7 @@ article.comment.editing > .comment-snippet { display: none; } | |||
| 1795 | 1855 | .label-row { display: inline-flex; flex-wrap: wrap; gap: 4px; } | |
| 1796 | 1856 | .label-row .label { margin-left: 0; } | |
| 1797 | 1857 | ||
| 1798 | .approval-list, .check-list { | ||
| 1858 | .approval-list { | ||
| 1799 | 1859 | list-style: none; | |
| 1800 | 1860 | padding: 0; | |
| 1801 | 1861 | margin: 0; | |
| @@ -1804,8 +1864,8 @@ article.comment.editing > .comment-snippet { display: none; } | |||
| 1804 | 1864 | gap: 6px; | |
| 1805 | 1865 | font-size: calc(13.2px * var(--font-scale)); | |
| 1806 | 1866 | } | |
| 1807 | .approval-list li, .check-list li { display: flex; align-items: center; gap: 7px; min-width: 0; } | ||
| 1808 | .approval-list .cname, .check-list a { | ||
| 1867 | .approval-list li { display: flex; align-items: center; gap: 7px; min-width: 0; } | ||
| 1868 | .approval-list .cname { | ||
| 1809 | 1869 | flex: 1; | |
| 1810 | 1870 | min-width: 0; | |
| 1811 | 1871 | overflow: hidden; | |
| @@ -1816,8 +1876,11 @@ article.comment.editing > .comment-snippet { display: none; } | |||
| 1816 | 1876 | ||
| 1817 | 1877 | @media (max-width: 900px) { | |
| 1818 | 1878 | .thread { grid-template-columns: 1fr; } | |
| 1819 | .thread-side { display: grid; grid-template-columns: repeat(auto-fit, minmax(14rem, 1fr)); gap: 0 24px; } | ||
| 1879 | .thread-side { display: block; } | ||
| 1880 | .thread-side #request-aside { display: grid; grid-template-columns: repeat(auto-fit, minmax(14rem, 1fr)); gap: 0 24px; } | ||
| 1881 | .thread-side #request-sidebar { display: contents; } | ||
| 1820 | 1882 | .thread-side section:first-child { padding-top: 12px; } | |
| 1883 | .help::after { top: calc(100% + 7px); right: auto; left: 0; transform: none; } | ||
| 1821 | 1884 | .page-head { flex-wrap: wrap; } | |
| 1822 | 1885 | .page-head-actions { width: 100%; justify-content: flex-start; } | |
| 1823 | 1886 | } | |