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.
Move Clone and Site into the repository header
816cc543d34ab52df01c62cfd8878ae70327a21f · Keenan Nemetz · 11d ago · parent a196e404
Move Clone and Site into the repository header The repository header now carries the controls that act on the repository as a whole. Clone appears once beside the name on every tab, with a copy button for the HTTPS URL and one for the SSH command. Site joins it only when a site would answer: pages are enabled, the repository is public, and its pages branch exists. The per-tab Clone popovers and the Overview/Code Site buttons are gone, so a tab's page header holds only that tab's own actions. Copy feedback now restores innerHTML, keeping the icon on an icon-only button and surviving a repeated click.
server/web/static/vole.css +28−1
| @@ -343,6 +343,20 @@ img { max-width: 100%; } | |||
| 343 | 343 | border-bottom: 1px solid var(--border); | |
| 344 | 344 | } | |
| 345 | 345 | .repo-title { padding: 26px 0 12px; } | |
| 346 | /* The repository actions sit on the title line, at the far right of the header. */ | ||
| 347 | .repo-title-row { | ||
| 348 | display: flex; | ||
| 349 | align-items: center; | ||
| 350 | gap: 16px; | ||
| 351 | } | ||
| 352 | .repo-title-row .repo-name { flex: 1 1 auto; min-width: 0; } | ||
| 353 | .repo-title-actions { | ||
| 354 | display: flex; | ||
| 355 | align-items: center; | ||
| 356 | gap: 8px; | ||
| 357 | flex: 0 0 auto; | ||
| 358 | } | ||
| 359 | .repo-title-row .clone-pop { left: auto; right: 0; } | ||
| 346 | 360 | .repo-name { | |
| 347 | 361 | display: flex; | |
| 348 | 362 | align-items: center; | |
| @@ -650,6 +664,20 @@ details.clone[open] > summary { border-color: var(--accent); } | |||
| 650 | 664 | } | |
| 651 | 665 | .clone-pop p { margin: 8px 0 2px; } | |
| 652 | 666 | .clone-pop code { display: block; } | |
| 667 | /* Each advertised transport is one row: the command takes the width, the copy | ||
| 668 | button stays put at its end. */ | ||
| 669 | .clone-field { | ||
| 670 | display: flex; | ||
| 671 | align-items: center; | ||
| 672 | gap: 6px; | ||
| 673 | } | ||
| 674 | .clone-field code { | ||
| 675 | flex: 1 1 auto; | ||
| 676 | min-width: 0; | ||
| 677 | overflow-x: auto; | ||
| 678 | white-space: nowrap; | ||
| 679 | } | ||
| 680 | .clone-field button { flex: 0 0 auto; padding: 5px 8px; } | ||
| 653 | 681 | ||
| 654 | 682 | .row { display: flex; gap: 16px; flex-wrap: wrap; } | |
| 655 | 683 | .row > div { flex: 1 1 18rem; min-width: 0; } | |
| @@ -1416,7 +1444,6 @@ details[open] > summary .tree-chevron { transform: rotate(90deg); } | |||
| 1416 | 1444 | gap: 8px; | |
| 1417 | 1445 | margin-left: auto; | |
| 1418 | 1446 | } | |
| 1419 | .page-head-actions .clone-pop { left: auto; right: 0; } | ||
| 1420 | 1447 | /* Search and branch pickers are filters, not inline prose: a row layout keeps the | |
| 1421 | 1448 | input, its icon button, and the select on the same baseline. */ | |
| 1422 | 1449 | .page-head-actions form.inline { | |