vole
Clone
Read only, no credentials:
https://rodent.software/vole.git
Write over SSH with a registered key:
git clone ssh://git@rodent.software:2222/vole.git
A free and open-source forge that lives in your Git repo.
Build a landing page and simplify the forge chrome
074ae1605e177e99533af02d8c69ccd1a6a947bb · Keenan Nemetz · 14d ago · parent 62576fa8
Build a landing page and simplify the forge chrome The instance root is now a landing page rather than the full activity feed: forge identity, project cards with top language, last commit, issue/change counts and latest release, a short activity rail, and a first-run empty state. The full feed moves to /activity with type filters and pagination. Feeds now cover issues, changes, comments, and releases only; commits and CI runs already have their own pages. Configuration gains instance_name and instance_tagline. Navigation: the crowded global bar becomes Runners, Activity, search, and an account menu holding Admin, Status, and Log out. Repository pages show the name and description above the tabs at the home-page header scale, while tab-page titles stay small. Top-level pages keep the larger header. Drop the workflow run chip, assigned-issues strip, repository size stat, and footer Status link.
server/web/static/vole.css +297−50
| @@ -110,20 +110,84 @@ img { max-width: 100%; } | |||
| 110 | 110 | font: 700 12px/1 var(--mono); | |
| 111 | 111 | } | |
| 112 | 112 | ||
| 113 | .topnav { display: flex; gap: 16px; } | ||
| 114 | .topnav a { color: var(--fg-muted); font-size: 12.5px; } | ||
| 115 | .topnav a:hover { color: var(--fg); text-decoration: none; } | ||
| 113 | .topnav { display: flex; gap: 2px; } | ||
| 114 | .topnav a { | ||
| 115 | display: inline-flex; | ||
| 116 | align-items: center; | ||
| 117 | gap: 5px; | ||
| 118 | padding: 4px 8px; | ||
| 119 | border-radius: var(--radius); | ||
| 120 | color: var(--fg-muted); | ||
| 121 | font-size: 12.5px; | ||
| 122 | } | ||
| 123 | .topnav a:hover { background: var(--bg-hover); color: var(--fg); text-decoration: none; } | ||
| 124 | .topnav a.active { background: var(--bg-raised); color: var(--fg); } | ||
| 125 | |||
| 126 | .topsearch { margin-left: auto; } | ||
| 127 | .topsearch input[type="search"] { width: 12rem; max-width: 28vw; } | ||
| 116 | 128 | ||
| 117 | 129 | .topright { | |
| 118 | margin-left: auto; | ||
| 119 | 130 | display: flex; | |
| 120 | 131 | align-items: center; | |
| 121 | 132 | gap: 12px; | |
| 122 | 133 | font-size: 12.5px; | |
| 123 | 134 | color: var(--fg-muted); | |
| 124 | 135 | } | |
| 125 | .topright .account { color: var(--fg-muted); } | ||
| 126 | .topright .account:hover { color: var(--fg); text-decoration: none; } | ||
| 136 | .topright > a { display: inline-flex; align-items: center; gap: 5px; color: var(--fg-muted); } | ||
| 137 | .topright > a:hover { color: var(--fg); text-decoration: none; } | ||
| 138 | |||
| 139 | .account-menu { position: relative; } | ||
| 140 | .account-menu > summary { | ||
| 141 | display: flex; | ||
| 142 | align-items: center; | ||
| 143 | gap: 6px; | ||
| 144 | padding: 4px 8px; | ||
| 145 | border-radius: var(--radius); | ||
| 146 | color: var(--fg-muted); | ||
| 147 | white-space: nowrap; | ||
| 148 | list-style: none; | ||
| 149 | cursor: pointer; | ||
| 150 | } | ||
| 151 | .account-menu > summary::-webkit-details-marker { display: none; } | ||
| 152 | .account-menu > summary:hover { background: var(--bg-hover); color: var(--fg); } | ||
| 153 | .account-menu[open] > summary { background: var(--bg-raised); color: var(--fg); } | ||
| 154 | .account-name { max-width: 12rem; overflow: hidden; text-overflow: ellipsis; } | ||
| 155 | .account-caret { display: inline-flex; color: var(--fg-faint); } | ||
| 156 | .account-caret .icon { width: 12px; height: 12px; transform: rotate(90deg); transition: transform 0.12s ease; } | ||
| 157 | .account-menu[open] .account-caret .icon { transform: rotate(-90deg); } | ||
| 158 | .account-pop { | ||
| 159 | position: absolute; | ||
| 160 | top: calc(100% + 6px); | ||
| 161 | right: 0; | ||
| 162 | z-index: 30; | ||
| 163 | width: 13rem; | ||
| 164 | padding: 4px; | ||
| 165 | background: var(--bg-raised); | ||
| 166 | border: 1px solid var(--border-strong); | ||
| 167 | border-radius: var(--radius-lg); | ||
| 168 | box-shadow: 0 12px 32px rgba(0, 0, 0, 0.4); | ||
| 169 | } | ||
| 170 | .account-pop a, | ||
| 171 | .account-pop button { | ||
| 172 | display: flex; | ||
| 173 | align-items: center; | ||
| 174 | justify-content: flex-start; | ||
| 175 | gap: 8px; | ||
| 176 | width: 100%; | ||
| 177 | padding: 6px 8px; | ||
| 178 | border: 0; | ||
| 179 | border-radius: var(--radius); | ||
| 180 | background: none; | ||
| 181 | color: var(--fg); | ||
| 182 | font: inherit; | ||
| 183 | font-size: 12.5px; | ||
| 184 | text-align: left; | ||
| 185 | cursor: pointer; | ||
| 186 | } | ||
| 187 | .account-pop a:hover, | ||
| 188 | .account-pop button:hover { background: var(--bg-hover); color: var(--accent); text-decoration: none; } | ||
| 189 | .account-pop form { margin: 0; } | ||
| 190 | .account-sep { border-top: 1px solid var(--border); margin: 4px 0; } | ||
| 127 | 191 | ||
| 128 | 192 | .page { | |
| 129 | 193 | width: min(100%, 1440px); | |
| @@ -133,29 +197,79 @@ img { max-width: 100%; } | |||
| 133 | 197 | ||
| 134 | 198 | @media (max-width: 720px) { | |
| 135 | 199 | .tabs { mask-image: linear-gradient(to right, #000 calc(100% - 28px), transparent); } | |
| 136 | .topbar { padding: 0 12px; gap: 12px; } | ||
| 200 | .topbar { | ||
| 201 | height: auto; | ||
| 202 | flex-wrap: wrap; | ||
| 203 | padding: 8px 12px; | ||
| 204 | gap: 8px 12px; | ||
| 205 | } | ||
| 206 | .topsearch { order: 3; flex: 1 1 100%; margin-left: 0; } | ||
| 207 | .topsearch input[type="search"] { width: 100%; max-width: none; } | ||
| 208 | .topright { margin-left: auto; } | ||
| 209 | .topnav { gap: 0; } | ||
| 210 | /* The icon is enough on a phone; the menu keeps the full name. */ | ||
| 211 | .account-name { display: none; } | ||
| 137 | 212 | .page { padding: 16px 12px 56px; } | |
| 138 | .topnav { gap: 10px; } | ||
| 139 | 213 | } | |
| 140 | 214 | ||
| 141 | 215 | /* ---------- repository header ---------- */ | |
| 142 | 216 | ||
| 143 | 217 | .repohead { | |
| 144 | display: flex; | ||
| 145 | flex-wrap: wrap; | ||
| 146 | align-items: baseline; | ||
| 147 | gap: 6px 16px; | ||
| 148 | padding-bottom: 0; | ||
| 149 | 218 | margin-bottom: 16px; | |
| 150 | 219 | border-bottom: 1px solid var(--border); | |
| 151 | 220 | } | |
| 221 | .repo-title { padding: 26px 0 12px; } | ||
| 222 | .repo-name { | ||
| 223 | display: flex; | ||
| 224 | align-items: center; | ||
| 225 | gap: 8px; | ||
| 226 | min-width: 0; | ||
| 227 | color: var(--fg); | ||
| 228 | font-size: 26px; | ||
| 229 | line-height: 1.2; | ||
| 230 | font-weight: 600; | ||
| 231 | letter-spacing: -0.025em; | ||
| 232 | } | ||
| 233 | .repo-name .repo-vis .icon { width: 16px; height: 16px; } | ||
| 234 | .repo-desc { | ||
| 235 | margin: 6px 0 0; | ||
| 236 | color: var(--fg-muted); | ||
| 237 | font-size: 13px; | ||
| 238 | overflow: hidden; | ||
| 239 | text-overflow: ellipsis; | ||
| 240 | white-space: nowrap; | ||
| 241 | } | ||
| 242 | |||
| 243 | /* The tab pages are a level below the repository identity: their own headers | ||
| 244 | stay small. Top-level pages (Runners, Account, Status, Admin) keep the | ||
| 245 | home-page header scale. */ | ||
| 246 | .repohead + .page-head { | ||
| 247 | align-items: flex-start; | ||
| 248 | gap: 16px; | ||
| 249 | padding: 0; | ||
| 250 | margin-bottom: 12px; | ||
| 251 | border-bottom: 0; | ||
| 252 | } | ||
| 253 | .repohead + .page-head h1 { | ||
| 254 | font-size: 18px; | ||
| 255 | line-height: 1.35; | ||
| 256 | letter-spacing: -0.005em; | ||
| 257 | margin: 0 0 3px; | ||
| 258 | } | ||
| 259 | .repohead + .page-head .page-sub { font-size: 12.5px; } | ||
| 260 | |||
| 261 | @media (max-width: 720px) { | ||
| 262 | .repo-title { padding: 18px 0 10px; } | ||
| 263 | .repo-name { font-size: 22px; } | ||
| 264 | .repo-name .repo-vis .icon { width: 14px; height: 14px; } | ||
| 265 | } | ||
| 152 | 266 | ||
| 153 | 267 | .tabs { | |
| 154 | 268 | display: flex; | |
| 155 | 269 | gap: 2px; | |
| 156 | 270 | overflow-x: auto; | |
| 157 | 271 | scrollbar-width: none; | |
| 158 | margin-left: -8px; | ||
| 272 | margin-left: -10px; | ||
| 159 | 273 | } | |
| 160 | 274 | .tabs::-webkit-scrollbar { display: none; } | |
| 161 | 275 | .tabs a { | |
| @@ -167,7 +281,6 @@ img { max-width: 100%; } | |||
| 167 | 281 | } | |
| 168 | 282 | .tabs a:hover { color: var(--fg); text-decoration: none; } | |
| 169 | 283 | .tabs a.active { color: var(--fg); border-bottom-color: var(--accent); } | |
| 170 | .tabs a.repotab { color: var(--fg); font-weight: 600; } | ||
| 171 | 284 | ||
| 172 | 285 | /* ---------- panels and tables ---------- */ | |
| 173 | 286 | ||
| @@ -711,6 +824,7 @@ pre code { background: none; border: 0; padding: 0; font-size: inherit; } | |||
| 711 | 824 | .chip { | |
| 712 | 825 | display: inline-flex; | |
| 713 | 826 | align-items: center; | |
| 827 | gap: 5px; | ||
| 714 | 828 | padding: 3px 9px; | |
| 715 | 829 | border: 1px solid var(--border-strong); | |
| 716 | 830 | border-radius: 12px; | |
| @@ -718,6 +832,7 @@ pre code { background: none; border: 0; padding: 0; font-size: inherit; } | |||
| 718 | 832 | color: var(--fg-muted); | |
| 719 | 833 | background: var(--bg-panel); | |
| 720 | 834 | } | |
| 835 | .chip .icon { width: 12px; height: 12px; } | ||
| 721 | 836 | .chip:hover { color: var(--fg); border-color: var(--fg-faint); text-decoration: none; } | |
| 722 | 837 | .chip.active { color: var(--accent); border-color: var(--accent); background: var(--accent-soft); } | |
| 723 | 838 | ||
| @@ -895,7 +1010,7 @@ details[open] > summary .tree-chevron { transform: rotate(90deg); } | |||
| 895 | 1010 | .code-main .readme > *, | |
| 896 | 1011 | .code-main .filebody > * { max-width: none; } | |
| 897 | 1012 | .code-main .highlight, | |
| 898 | .code-main .blob { max-height: calc(100vh - 230px); } | ||
| 1013 | .code-main .blob { max-height: calc(100vh - 240px); } | ||
| 899 | 1014 | .empty-code { margin-top: 0; } | |
| 900 | 1015 | ||
| 901 | 1016 | .dirlist td { padding: 2px 10px; } | |
| @@ -1040,18 +1155,24 @@ details[open] > summary .tree-chevron { transform: rotate(90deg); } | |||
| 1040 | 1155 | } | |
| 1041 | 1156 | .side-run-top { display: flex; align-items: baseline; gap: 6px; min-width: 0; } | |
| 1042 | 1157 | .side-run-top .status { flex: 0 0 auto; } | |
| 1043 | .side-size { font-size: 19px; font-weight: 600; letter-spacing: -0.02em; margin: 0 0 2px; } | ||
| 1044 | 1158 | ||
| 1045 | 1159 | /* ---------- issues and changes ---------- */ | |
| 1046 | 1160 | ||
| 1047 | 1161 | .page-head { | |
| 1048 | 1162 | display: flex; | |
| 1049 | align-items: flex-start; | ||
| 1163 | align-items: flex-end; | ||
| 1050 | 1164 | justify-content: space-between; | |
| 1051 | gap: 16px; | ||
| 1052 | margin-bottom: 12px; | ||
| 1165 | gap: 24px; | ||
| 1166 | padding: 26px 0 20px; | ||
| 1167 | margin-bottom: 20px; | ||
| 1168 | border-bottom: 1px solid var(--border); | ||
| 1169 | } | ||
| 1170 | .page-head h1 { | ||
| 1171 | font-size: 26px; | ||
| 1172 | line-height: 1.2; | ||
| 1173 | letter-spacing: -0.025em; | ||
| 1174 | margin: 0 0 4px; | ||
| 1053 | 1175 | } | |
| 1054 | .page-head h1 { margin: 0 0 3px; } | ||
| 1055 | 1176 | .page-head-main { min-width: 0; } | |
| 1056 | 1177 | .page-head-actions { | |
| 1057 | 1178 | display: flex; | |
| @@ -1063,7 +1184,12 @@ details[open] > summary .tree-chevron { transform: rotate(90deg); } | |||
| 1063 | 1184 | margin-left: auto; | |
| 1064 | 1185 | } | |
| 1065 | 1186 | .page-head-actions .clone-pop { left: auto; right: 0; } | |
| 1066 | .page-sub { color: var(--fg-muted); font-size: 12.5px; margin: 0; } | ||
| 1187 | .page-sub { color: var(--fg-muted); font-size: 13px; margin: 0; max-width: 80ch; } | ||
| 1188 | |||
| 1189 | @media (max-width: 720px) { | ||
| 1190 | .page-head { padding: 18px 0 16px; } | ||
| 1191 | .page-head h1 { font-size: 22px; } | ||
| 1192 | } | ||
| 1067 | 1193 | ||
| 1068 | 1194 | /* Secondary navigation inside a change: conversation and the review files. */ | |
| 1069 | 1195 | .subtabs { | |
| @@ -1546,7 +1672,6 @@ button.link, .link { min-height: 0; } | |||
| 1546 | 1672 | /* Icons are inline SVG from Lucide. They inherit currentColor and size with | |
| 1547 | 1673 | the text around them. */ | |
| 1548 | 1674 | .icon { width: 14px; height: 14px; flex: 0 0 auto; } | |
| 1549 | .topnav a, .topright .account { display: inline-flex; align-items: center; gap: 5px; } | ||
| 1550 | 1675 | .tabs a { display: inline-flex; align-items: center; gap: 5px; } | |
| 1551 | 1676 | h2 .icon { width: 13px; height: 13px; margin-right: 4px; vertical-align: -2px; color: var(--fg-faint); } | |
| 1552 | 1677 | ||
| @@ -1610,11 +1735,9 @@ form.htmx-request .label-tokens { opacity: 0.6; } | |||
| 1610 | 1735 | color: var(--fg-muted); | |
| 1611 | 1736 | } | |
| 1612 | 1737 | .activity-icon .icon { width: 13px; height: 13px; } | |
| 1613 | .activity-icon.commit { color: var(--accent); } | ||
| 1614 | 1738 | .activity-icon.issue { color: var(--good); } | |
| 1615 | 1739 | .activity-icon.change { color: #c792ea; } | |
| 1616 | 1740 | .activity-icon.release { color: var(--warn); } | |
| 1617 | .activity-icon.run { color: var(--fg-muted); } | ||
| 1618 | 1741 | .activity-body { min-width: 0; flex: 1; } | |
| 1619 | 1742 | .activity-title { | |
| 1620 | 1743 | display: block; | |
| @@ -1634,16 +1757,6 @@ form.htmx-request .label-tokens { opacity: 0.6; } | |||
| 1634 | 1757 | .state.active { color: var(--good); } | |
| 1635 | 1758 | .state.retired { color: var(--fg-faint); } | |
| 1636 | 1759 | ||
| 1637 | /* Global repository search lives in the chrome on wide screens; the index page | ||
| 1638 | keeps its own visible form so the control is still reachable on mobile. */ | ||
| 1639 | .topsearch { margin-left: auto; } | ||
| 1640 | .topsearch input[type="search"] { width: 12rem; max-width: 28vw; } | ||
| 1641 | .topright { margin-left: 0; } | ||
| 1642 | @media (max-width: 720px) { | ||
| 1643 | .topsearch { display: none; } | ||
| 1644 | .topright { margin-left: auto; } | ||
| 1645 | } | ||
| 1646 | |||
| 1647 | 1760 | /* Keyboard users get out of the chrome before the tabs. */ | |
| 1648 | 1761 | .skip-link { | |
| 1649 | 1762 | position: absolute; | |
| @@ -1731,20 +1844,135 @@ textarea:focus-visible { | |||
| 1731 | 1844 | .blame td.ln { width: 6ch; text-align: right; color: var(--fg-faint); font-family: var(--mono); font-size: 11px; } | |
| 1732 | 1845 | .blame td.code { font-family: var(--mono); font-size: 12px; white-space: pre; } | |
| 1733 | 1846 | ||
| 1734 | /* Home: the instance feed is the main column and the repository list is a | ||
| 1735 | compact index beside it. On narrow screens the list comes first. */ | ||
| 1736 | .home { display: grid; grid-template-columns: minmax(0, 1fr) 20rem; gap: 24px; align-items: start; } | ||
| 1737 | .home-side { position: sticky; top: 60px; } | ||
| 1738 | .home-side h2 { margin-top: 0; } | ||
| 1739 | .side-search { margin: 0 0 8px; } | ||
| 1740 | .side-search input[type="search"] { width: 100%; max-width: none; } | ||
| 1741 | .repo-side .side-row { display: block; padding: 7px 0; border-bottom: 1px solid var(--border); } | ||
| 1742 | .repo-side .side-row:last-child { border-bottom: 0; } | ||
| 1743 | .repo-side .row-title { display: block; } | ||
| 1744 | .repo-side .muted { display: block; font-size: 11.5px; margin-top: 1px; } | ||
| 1847 | /* Landing page: identity, a project grid, and the merged feed as a rail. The | ||
| 1848 | feed has a full page at /activity; here it is a sign the forge is alive, not | ||
| 1849 | the subject of the page. */ | ||
| 1850 | .hero { | ||
| 1851 | display: flex; | ||
| 1852 | align-items: flex-end; | ||
| 1853 | justify-content: space-between; | ||
| 1854 | gap: 24px; | ||
| 1855 | padding: 26px 0 20px; | ||
| 1856 | border-bottom: 1px solid var(--border); | ||
| 1857 | margin-bottom: 20px; | ||
| 1858 | } | ||
| 1859 | .hero-main { min-width: 0; } | ||
| 1860 | .hero h1 { | ||
| 1861 | font-size: 26px; | ||
| 1862 | line-height: 1.2; | ||
| 1863 | letter-spacing: -0.025em; | ||
| 1864 | margin: 0 0 6px; | ||
| 1865 | } | ||
| 1866 | .hero-tagline { color: var(--fg-muted); font-size: 13px; margin: 0 0 8px; max-width: 62ch; } | ||
| 1867 | .hero-vitals { color: var(--fg-faint); font: 11.5px/1.5 var(--mono); margin: 0; } | ||
| 1868 | .hero-vitals a { color: var(--fg-muted); } | ||
| 1869 | .hero-actions { display: flex; flex: 0 0 auto; flex-wrap: wrap; align-items: center; gap: 8px; } | ||
| 1870 | |||
| 1871 | .home-grid { | ||
| 1872 | display: grid; | ||
| 1873 | grid-template-columns: minmax(0, 1fr) 20rem; | ||
| 1874 | gap: 28px; | ||
| 1875 | align-items: start; | ||
| 1876 | } | ||
| 1877 | .home-main { min-width: 0; } | ||
| 1878 | .home-rail { position: sticky; top: 60px; } | ||
| 1879 | .section-head { | ||
| 1880 | display: flex; | ||
| 1881 | align-items: baseline; | ||
| 1882 | justify-content: space-between; | ||
| 1883 | gap: 12px; | ||
| 1884 | margin-bottom: 9px; | ||
| 1885 | } | ||
| 1886 | .section-head h2 { margin: 0; } | ||
| 1887 | .section-head .more { font-size: 11.5px; color: var(--fg-muted); } | ||
| 1888 | .section-head .more:hover { color: var(--accent); } | ||
| 1889 | .section-head .muted { font-size: 11.5px; } | ||
| 1890 | |||
| 1891 | .repo-grid { | ||
| 1892 | display: grid; | ||
| 1893 | grid-template-columns: repeat(auto-fill, minmax(19rem, 1fr)); | ||
| 1894 | gap: 10px; | ||
| 1895 | } | ||
| 1896 | .repo-card { | ||
| 1897 | display: flex; | ||
| 1898 | flex-direction: column; | ||
| 1899 | gap: 5px; | ||
| 1900 | min-width: 0; | ||
| 1901 | padding: 12px 13px; | ||
| 1902 | background: var(--bg-panel); | ||
| 1903 | border: 1px solid var(--border); | ||
| 1904 | border-radius: var(--radius-lg); | ||
| 1905 | } | ||
| 1906 | .repo-card:hover { border-color: var(--border-strong); background: var(--bg-raised); } | ||
| 1907 | .repo-card-top { display: flex; align-items: baseline; gap: 7px; min-width: 0; } | ||
| 1908 | .repo-card h3 { font-size: 13.5px; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } | ||
| 1909 | .repo-card h3 a { color: var(--fg); font-weight: 600; } | ||
| 1910 | .repo-card h3 a:hover { color: var(--accent); text-decoration: none; } | ||
| 1911 | .repo-vis { display: inline-flex; flex: 0 0 auto; color: var(--fg-faint); } | ||
| 1912 | .repo-vis .icon { width: 12px; height: 12px; } | ||
| 1913 | .repo-lang { display: inline-flex; align-items: center; gap: 4px; flex: 0 0 auto; font-size: 10.5px; color: var(--fg-faint); } | ||
| 1914 | .lang-dot { display: inline-block; width: 8px; height: 8px; border-radius: 50%; background: var(--fg-faint); } | ||
| 1915 | .repo-updated { margin-left: auto; flex: 0 0 auto; color: var(--fg-faint); font-size: 11px; } | ||
| 1916 | .repo-desc { | ||
| 1917 | color: var(--fg-muted); | ||
| 1918 | font-size: 12px; | ||
| 1919 | margin: 0; | ||
| 1920 | overflow: hidden; | ||
| 1921 | display: -webkit-box; | ||
| 1922 | -webkit-line-clamp: 2; | ||
| 1923 | -webkit-box-orient: vertical; | ||
| 1924 | } | ||
| 1925 | .repo-meta { | ||
| 1926 | display: flex; | ||
| 1927 | flex-wrap: wrap; | ||
| 1928 | gap: 2px 8px; | ||
| 1929 | margin: 0; | ||
| 1930 | color: var(--fg-faint); | ||
| 1931 | font-size: 11px; | ||
| 1932 | min-width: 0; | ||
| 1933 | } | ||
| 1934 | .repo-meta .repo-subject { color: var(--fg-muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 100%; } | ||
| 1935 | .repo-meta .sha { font-size: 11px; color: var(--fg-faint); } | ||
| 1936 | .repo-chips { display: flex; flex-wrap: wrap; gap: 5px; margin-top: 3px; } | ||
| 1937 | .repo-chips .chip { padding: 1px 7px; font-size: 10.5px; gap: 4px; } | ||
| 1938 | .repo-chips .chip .icon { width: 11px; height: 11px; } | ||
| 1939 | .repo-chips .status { font-size: 9.5px; letter-spacing: 0.03em; } | ||
| 1940 | .repo-chips .status::before { width: 5px; height: 5px; } | ||
| 1941 | |||
| 1942 | .empty-state.first-run { | ||
| 1943 | display: flex; | ||
| 1944 | flex-direction: column; | ||
| 1945 | align-items: center; | ||
| 1946 | text-align: center; | ||
| 1947 | padding: 44px 20px; | ||
| 1948 | } | ||
| 1949 | .first-run .empty-icon { | ||
| 1950 | display: grid; | ||
| 1951 | place-items: center; | ||
| 1952 | width: 44px; | ||
| 1953 | height: 44px; | ||
| 1954 | margin-bottom: 12px; | ||
| 1955 | border-radius: 50%; | ||
| 1956 | background: var(--bg-raised); | ||
| 1957 | color: var(--fg-faint); | ||
| 1958 | } | ||
| 1959 | .first-run .empty-icon .icon { width: 20px; height: 20px; } | ||
| 1960 | .first-run h2 { margin: 0 0 6px; font-size: 16px; color: var(--fg); } | ||
| 1961 | .first-run p { margin: 0 0 14px; } | ||
| 1962 | .first-run .empty-actions { margin: 0 0 10px; } | ||
| 1963 | .first-run .empty-hint { margin: 0; font-size: 11.5px; color: var(--fg-faint); } | ||
| 1964 | .first-run .empty-hint code { font-size: 11px; } | ||
| 1965 | |||
| 1745 | 1966 | @media (max-width: 900px) { | |
| 1746 | .home { grid-template-columns: 1fr; } | ||
| 1747 | .home-side { position: static; order: -1; } | ||
| 1967 | .home-grid { grid-template-columns: 1fr; } | ||
| 1968 | .home-rail { position: static; order: 2; } | ||
| 1969 | .home-main { order: 1; } | ||
| 1970 | } | ||
| 1971 | @media (max-width: 720px) { | ||
| 1972 | .hero { flex-wrap: wrap; align-items: flex-start; padding-top: 18px; } | ||
| 1973 | .hero-actions { width: 100%; } | ||
| 1974 | .hero h1 { font-size: 22px; } | ||
| 1975 | .repo-grid { grid-template-columns: 1fr; } | ||
| 1748 | 1976 | } | |
| 1749 | 1977 | ||
| 1750 | 1978 | /* Status page: a small metrics row above the per-service checks. */ | |
| @@ -1755,8 +1983,6 @@ textarea:focus-visible { | |||
| 1755 | 1983 | .check-state.ok { color: var(--good); } | |
| 1756 | 1984 | .check-state.warn { color: var(--warn); } | |
| 1757 | 1985 | .check-state.fail { color: var(--bad); } | |
| 1758 | .pagefoot { max-width: 1440px; margin: 0 auto; padding: 0 24px 32px; color: var(--fg-faint); font-size: 11.5px; } | ||
| 1759 | @media (max-width: 720px) { .pagefoot { padding: 0 12px 24px; } } | ||
| 1760 | 1986 | ||
| 1761 | 1987 | /* Language hints for file rows. Active tree rows still win through specificity. */ | |
| 1762 | 1988 | .tree-icon.lang-go, .dirlist a.file.lang-go .icon { color: #00add8; } | |
| @@ -1779,3 +2005,24 @@ textarea:focus-visible { | |||
| 1779 | 2005 | .tree-icon.lang-image, .dirlist a.file.lang-image .icon { color: #a074c4; } | |
| 1780 | 2006 | .tree-icon.lang-lock, .dirlist a.file.lang-lock .icon { color: var(--fg-muted); } | |
| 1781 | 2007 | .tree-icon.lang-build, .dirlist a.file.lang-build .icon { color: var(--fg-muted); } | |
| 2008 | |||
| 2009 | /* The same palette marks a repository's top language on the landing page. */ | ||
| 2010 | .lang-dot.lang-go { background: #00add8; } | ||
| 2011 | .lang-dot.lang-rust { background: #dea584; } | ||
| 2012 | .lang-dot.lang-js { background: #f1e05a; } | ||
| 2013 | .lang-dot.lang-ts { background: #3178c6; } | ||
| 2014 | .lang-dot.lang-py { background: #3572a5; } | ||
| 2015 | .lang-dot.lang-rb { background: #cc342d; } | ||
| 2016 | .lang-dot.lang-jvm { background: #b07219; } | ||
| 2017 | .lang-dot.lang-c { background: #a8b9cc; } | ||
| 2018 | .lang-dot.lang-cpp { background: #f34b7d; } | ||
| 2019 | .lang-dot.lang-cs { background: #178600; } | ||
| 2020 | .lang-dot.lang-php { background: #8f9ad8; } | ||
| 2021 | .lang-dot.lang-sh { background: #89e051; } | ||
| 2022 | .lang-dot.lang-html { background: #e34c26; } | ||
| 2023 | .lang-dot.lang-css { background: #a074c4; } | ||
| 2024 | .lang-dot.lang-config { background: #cbcb41; } | ||
| 2025 | .lang-dot.lang-text { background: #519aba; } | ||
| 2026 | .lang-dot.lang-sql { background: #e38c00; } | ||
| 2027 | .lang-dot.lang-image { background: #a074c4; } | ||
| 2028 | .lang-dot.lang-lock, .lang-dot.lang-build { background: var(--fg-muted); } | ||