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.
Simplify the home page around the instance introduction
ff9870f1a26a17d54c21d411000a6c7d58ab5c0d · Keenan Nemetz · 1d ago · parent 6ce635a8
Simplify the home page around the instance introduction Drop the page header and its hero actions. The instance name and sign-in links already live in the top bar, and the introduction is the place to say what the forge is. Move New repository into the Repositories heading, where it sits with the list it creates. Remove the introduction card header and its in-page editor. The introduction is profile/README.md in the instance repository, so it is read and pushed like every other customization. The POST / handler and its editor code go with it; an instance admin without an instance repository still gets the setup hint.
server/web/static/vole.css +7−61
| @@ -2729,70 +2729,17 @@ textarea:focus-visible { | |||
| 2729 | 2729 | ||
| 2730 | 2730 | /* ---------- landing page ---------- */ | |
| 2731 | 2731 | ||
| 2732 | /* The identity strip, the editable introduction, the repository grid and the | ||
| 2733 | merged feed as a rail. The feed has a full page at /activity; here it is a | ||
| 2734 | sign the forge is alive, not the subject of the page. */ | ||
| 2735 | .hero { | ||
| 2736 | display: flex; | ||
| 2737 | align-items: flex-end; | ||
| 2738 | justify-content: space-between; | ||
| 2739 | gap: 24px; | ||
| 2740 | padding: 26px 0 20px; | ||
| 2741 | border-bottom: 1px solid var(--border); | ||
| 2742 | margin-bottom: 20px; | ||
| 2743 | } | ||
| 2744 | .hero-main { min-width: 0; } | ||
| 2745 | .hero h1 { | ||
| 2746 | font-size: calc(28.6px * var(--font-scale)); | ||
| 2747 | line-height: 1.2; | ||
| 2748 | letter-spacing: -0.025em; | ||
| 2749 | margin: 0; | ||
| 2750 | overflow: hidden; | ||
| 2751 | text-overflow: ellipsis; | ||
| 2752 | white-space: nowrap; | ||
| 2753 | } | ||
| 2754 | .hero-actions { display: flex; flex: 0 0 auto; flex-wrap: wrap; align-items: center; gap: 8px; } | ||
| 2755 | |||
| 2756 | /* The introduction card spans the page: it is the one piece of custom prose an | ||
| 2757 | instance has, and the repository grid below is the work. */ | ||
| 2732 | /* The introduction, the repository grid and the merged feed as a rail. The feed | ||
| 2733 | has a full page at /activity; here it is a sign the forge is alive, not the | ||
| 2734 | subject of the page. The introduction is the instance's own prose, read from | ||
| 2735 | the instance repository, so it has no header or editor of its own. */ | ||
| 2758 | 2736 | .readme-card { margin: 0 0 20px; } | |
| 2759 | .readme-head { | ||
| 2760 | display: flex; | ||
| 2761 | align-items: center; | ||
| 2762 | justify-content: space-between; | ||
| 2763 | gap: 10px; | ||
| 2764 | padding: 8px 16px; | ||
| 2765 | border-bottom: 1px solid var(--border); | ||
| 2766 | background: var(--bg-raised); | ||
| 2767 | } | ||
| 2768 | .readme-name { | ||
| 2769 | display: inline-flex; | ||
| 2770 | align-items: center; | ||
| 2771 | gap: 6px; | ||
| 2772 | color: var(--fg-muted); | ||
| 2773 | font-size: calc(12.65px * var(--font-scale)); | ||
| 2774 | font-weight: 500; | ||
| 2775 | } | ||
| 2776 | .readme-name .icon { width: 13px; height: 13px; } | ||
| 2777 | .readme-edit { | ||
| 2778 | display: inline-flex; | ||
| 2779 | align-items: center; | ||
| 2780 | padding: 3px; | ||
| 2781 | border-radius: var(--radius); | ||
| 2782 | color: var(--fg-faint); | ||
| 2783 | } | ||
| 2784 | .readme-edit:hover { color: var(--accent); background: var(--bg-panel); text-decoration: none; } | ||
| 2785 | .readme-edit .icon { width: 15px; height: 15px; } | ||
| 2786 | 2737 | .readme-body { padding: 18px 20px; } | |
| 2787 | 2738 | .readme-empty { | |
| 2788 | margin: 0; | ||
| 2789 | padding: 20px; | ||
| 2739 | margin: 0 0 20px; | ||
| 2790 | 2740 | color: var(--fg-muted); | |
| 2791 | 2741 | font-size: calc(13.75px * var(--font-scale)); | |
| 2792 | 2742 | } | |
| 2793 | .readme-form { display: flex; flex-direction: column; gap: 8px; padding: 16px 20px 18px; } | ||
| 2794 | .readme-form textarea { width: 100%; font-family: var(--mono); font-size: calc(13.2px * var(--font-scale)); } | ||
| 2795 | .readme-form .form-actions { margin: 2px 0 0; justify-content: flex-start; } | ||
| 2796 | 2743 | ||
| 2797 | 2744 | /* Repositories beside the rail. */ | |
| 2798 | 2745 | .home-grid { | |
| @@ -2815,6 +2762,8 @@ textarea:focus-visible { | |||
| 2815 | 2762 | .section-head .more { font-size: calc(12.65px * var(--font-scale)); color: var(--fg-muted); } | |
| 2816 | 2763 | .section-head .more:hover { color: var(--accent); } | |
| 2817 | 2764 | .section-head .muted { font-size: calc(12.65px * var(--font-scale)); } | |
| 2765 | .section-actions { display: flex; align-items: center; gap: 12px; } | ||
| 2766 | .section-actions .button { font-size: calc(12.65px * var(--font-scale)); padding: 4px 10px; } | ||
| 2818 | 2767 | ||
| 2819 | 2768 | .repo-grid { | |
| 2820 | 2769 | display: grid; | |
| @@ -2886,9 +2835,6 @@ textarea:focus-visible { | |||
| 2886 | 2835 | .home-main { order: 1; } | |
| 2887 | 2836 | } | |
| 2888 | 2837 | @media (max-width: 720px) { | |
| 2889 | .hero { flex-wrap: wrap; align-items: flex-start; padding-top: 18px; } | ||
| 2890 | .hero-actions { width: 100%; } | ||
| 2891 | .hero h1 { font-size: calc(24.2px * var(--font-scale)); } | ||
| 2892 | 2838 | .repo-grid { grid-template-columns: 1fr; } | |
| 2893 | 2839 | } | |
| 2894 | 2840 | ||