Align profile activity and stars UI
Authored by
mfwolffe <wolffemf@dukes.jmu.edu>
- SHA
373ed2fb03f574ef0289179b5045371658c614f1- Parents
-
142e85f - Tree
21103a4
373ed2f
373ed2fb03f574ef0289179b5045371658c614f1142e85f
21103a4| Status | File | + | - |
|---|---|---|---|
| M |
docs/internal/profile.md
|
31 | 1 |
| M |
internal/web/static/css/shithub.css
|
218 | 2 |
| M |
internal/web/templates/_layout.html
|
14 | 0 |
| M |
internal/web/templates/profile/stars_tab.html
|
133 | 36 |
| M |
internal/web/templates/profile/view.html
|
40 | 9 |
docs/internal/profile.mdmodified@@ -7,8 +7,10 @@ S09 shipped the public `/{username}` page and the `/avatars/{username}` route. L | |||
| 7 | | Route | Source | Notes | | 7 | | Route | Source | Notes | |
| 8 | |---|---|---| | 8 | |---|---|---| |
| 9 | | `GET /{username}` | profile.serveProfile | Public profile. citext lookup; canonical-case 301; reserved short-circuit. | | 9 | | `GET /{username}` | profile.serveProfile | Public profile. citext lookup; canonical-case 301; reserved short-circuit. | |
| 10 | +| `GET /{username}?tab=repositories` | profile.serveRepositoriesTab | Visibility-filtered user-owned repositories. | | ||
| 11 | +| `GET /{username}?tab=stars` | profile.serveStarsTab | Visibility-filtered starred repositories with search, type, language, and sort controls. | | ||
| 10 | | `POST /{username}/contribution-settings` | profile.contributionSettingsUpdate | Auth required. Profile owner toggles private contribution counts. | | 12 | | `POST /{username}/contribution-settings` | profile.contributionSettingsUpdate | Auth required. Profile owner toggles private contribution counts. | |
| 11 | -| `POST /{username}/pins` | profile.pinsUpdate | Auth required. Profile owner saves up to six public owned repositories. | | 13 | +| `POST /{username}/pins` | profile.pinsUpdate | Auth required. Profile owner saves up to six public affiliated repositories. | |
| 12 | | `GET /avatars/{username}` | profile.serveAvatar | Streams uploaded avatar OR falls back to deterministic SVG identicon. | | 14 | | `GET /avatars/{username}` | profile.serveAvatar | Streams uploaded avatar OR falls back to deterministic SVG identicon. | |
| 13 | 15 | ||
| 14 | `/{username}` is the **catch-all** — chi matches static routes in registration order, so the wildcard is registered last via the `ProfileMounter` hook. The reserved-name list (`internal/auth/reserved.go`) is the second line of defense if a future top-level route is added but not registered before the wildcard. | 16 | `/{username}` is the **catch-all** — chi matches static routes in registration order, so the wildcard is registered last via the `ProfileMounter` hook. The reserved-name list (`internal/auth/reserved.go`) is the second line of defense if a future top-level route is added but not registered before the wildcard. |
@@ -106,6 +108,34 @@ The overview contribution calendar is computed from local Git history: | |||
| 106 | - Arbitrary public repositories outside the user's affiliation remain verified-email-only to avoid spoofed username/display-name commits. | 108 | - Arbitrary public repositories outside the user's affiliation remain verified-email-only to avoid spoofed username/display-name commits. |
| 107 | - Private repositories are excluded by default. When the profile owner enables "Private contributions", private user-owned and member-org repositories contribute to the aggregate graph counts, but repository names and commit metadata are not exposed. | 109 | - Private repositories are excluded by default. When the profile owner enables "Private contributions", private user-owned and member-org repositories contribute to the aggregate graph counts, but repository names and commit metadata are not exposed. |
| 108 | 110 | ||
| 111 | +The "Contribution activity" timeline below the graph reuses the same | ||
| 112 | +visibility gates: | ||
| 113 | + | ||
| 114 | +- Commit rows are grouped by month and repository, with private repository | ||
| 115 | + names collapsed to "Private repositories". | ||
| 116 | +- Public user-owned repositories created during the selected contribution | ||
| 117 | + window are shown as "Created repositories" entries. | ||
| 118 | +- Issues and pull requests authored by the profile user are loaded through | ||
| 119 | + the issues sqlc package and then post-filtered with `policy.IsVisibleTo` | ||
| 120 | + before rendering. PR rows distinguish open, closed, and merged counts. | ||
| 121 | +- The first month is shown initially; the "Show more activity" button expands | ||
| 122 | + older months in place without another request. | ||
| 123 | + | ||
| 124 | +## Stars tab | ||
| 125 | + | ||
| 126 | +`/{username}?tab=stars` uses the same profile shell as the GitHub stars page: | ||
| 127 | + | ||
| 128 | +- The left profile sidebar matches the overview profile metadata and | ||
| 129 | + organization badges. | ||
| 130 | +- The placeholder Lists panel is rendered so the page layout matches GitHub | ||
| 131 | + while list management remains future work. | ||
| 132 | +- Starred repositories are loaded in one bounded scan (`starsTabScanLimit`) and | ||
| 133 | + then visibility-filtered with `policy.IsVisibleTo`. | ||
| 134 | +- Both user-owned and organization-owned repository stars render from the | ||
| 135 | + stored owner slug, so org-owned stars do not require an extra owner lookup. | ||
| 136 | +- Filters are applied server-side for search text, repository type, language, | ||
| 137 | + and sort order (`recently-starred`, `recently-active`, `stars`). | ||
| 138 | + | ||
| 109 | ## Self-view enrichment | 139 | ## Self-view enrichment |
| 110 | 140 | ||
| 111 | When the viewer's session matches the profile's user (`viewer.ID == user.ID`): | 141 | When the viewer's session matches the profile's user (`viewer.ID == user.ID`): |
internal/web/static/css/shithub.cssmodified@@ -1627,12 +1627,15 @@ button.shithub-contrib-setting-item:hover { | |||
| 1627 | .shithub-profile-activity h2 { | 1627 | .shithub-profile-activity h2 { |
| 1628 | margin-bottom: 1.5rem; | 1628 | margin-bottom: 1.5rem; |
| 1629 | } | 1629 | } |
| 1630 | +.shithub-profile-activity-timeline { | ||
| 1631 | + display: grid; | ||
| 1632 | + gap: 1.5rem; | ||
| 1633 | +} | ||
| 1630 | .shithub-profile-activity-row { | 1634 | .shithub-profile-activity-row { |
| 1631 | display: grid; | 1635 | display: grid; |
| 1632 | grid-template-columns: 96px minmax(0, 1fr); | 1636 | grid-template-columns: 96px minmax(0, 1fr); |
| 1633 | gap: 1.5rem; | 1637 | gap: 1.5rem; |
| 1634 | align-items: start; | 1638 | align-items: start; |
| 1635 | - margin-bottom: 1.5rem; | ||
| 1636 | } | 1639 | } |
| 1637 | .shithub-profile-activity-month { | 1640 | .shithub-profile-activity-month { |
| 1638 | color: var(--fg-muted); | 1641 | color: var(--fg-muted); |
@@ -1640,10 +1643,15 @@ button.shithub-contrib-setting-item:hover { | |||
| 1640 | font-size: 0.875rem; | 1643 | font-size: 0.875rem; |
| 1641 | padding-top: 0.15rem; | 1644 | padding-top: 0.15rem; |
| 1642 | } | 1645 | } |
| 1646 | +.shithub-profile-activity-list { | ||
| 1647 | + display: grid; | ||
| 1648 | + gap: 1.25rem; | ||
| 1649 | + min-width: 0; | ||
| 1650 | +} | ||
| 1643 | .shithub-profile-activity-item { | 1651 | .shithub-profile-activity-item { |
| 1644 | position: relative; | 1652 | position: relative; |
| 1645 | display: flex; | 1653 | display: flex; |
| 1646 | - align-items: center; | 1654 | + align-items: flex-start; |
| 1647 | gap: 0.75rem; | 1655 | gap: 0.75rem; |
| 1648 | min-height: 2.25rem; | 1656 | min-height: 2.25rem; |
| 1649 | color: var(--fg-default); | 1657 | color: var(--fg-default); |
@@ -1671,6 +1679,201 @@ button.shithub-contrib-setting-item:hover { | |||
| 1671 | color: var(--fg-muted); | 1679 | color: var(--fg-muted); |
| 1672 | flex: 0 0 auto; | 1680 | flex: 0 0 auto; |
| 1673 | } | 1681 | } |
| 1682 | +.shithub-profile-activity-body { | ||
| 1683 | + min-width: 0; | ||
| 1684 | + padding-top: 0.35rem; | ||
| 1685 | +} | ||
| 1686 | +.shithub-profile-activity-body strong { | ||
| 1687 | + display: block; | ||
| 1688 | + font-weight: 600; | ||
| 1689 | +} | ||
| 1690 | +.shithub-profile-activity-repos { | ||
| 1691 | + list-style: none; | ||
| 1692 | + margin: 0.5rem 0 0; | ||
| 1693 | + padding: 0; | ||
| 1694 | + display: grid; | ||
| 1695 | + gap: 0.2rem; | ||
| 1696 | + color: var(--fg-muted); | ||
| 1697 | + font-size: 0.875rem; | ||
| 1698 | +} | ||
| 1699 | +.shithub-profile-activity-repos li { | ||
| 1700 | + display: flex; | ||
| 1701 | + flex-wrap: wrap; | ||
| 1702 | + align-items: center; | ||
| 1703 | + gap: 0.45rem; | ||
| 1704 | + min-width: 0; | ||
| 1705 | +} | ||
| 1706 | +.shithub-profile-activity-repos a { | ||
| 1707 | + color: var(--fg-muted); | ||
| 1708 | + text-decoration: none; | ||
| 1709 | +} | ||
| 1710 | +.shithub-profile-activity-repos a:hover { | ||
| 1711 | + color: var(--accent-fg); | ||
| 1712 | + text-decoration: underline; | ||
| 1713 | +} | ||
| 1714 | +.shithub-profile-activity-lang { | ||
| 1715 | + display: inline-flex; | ||
| 1716 | + align-items: center; | ||
| 1717 | + gap: 0.25rem; | ||
| 1718 | +} | ||
| 1719 | +.shithub-profile-activity-state { | ||
| 1720 | + display: inline-flex; | ||
| 1721 | + align-items: center; | ||
| 1722 | + gap: 0.25rem; | ||
| 1723 | +} | ||
| 1724 | +.shithub-profile-activity-state b { | ||
| 1725 | + display: inline-flex; | ||
| 1726 | + align-items: center; | ||
| 1727 | + justify-content: center; | ||
| 1728 | + min-width: 1.25rem; | ||
| 1729 | + height: 1.25rem; | ||
| 1730 | + padding: 0 0.35rem; | ||
| 1731 | + border-radius: 999px; | ||
| 1732 | + color: #fff; | ||
| 1733 | + background: var(--fg-muted); | ||
| 1734 | + font-size: 0.75rem; | ||
| 1735 | + font-weight: 600; | ||
| 1736 | +} | ||
| 1737 | +.shithub-profile-activity-state.is-open b { | ||
| 1738 | + background: #2da44e; | ||
| 1739 | +} | ||
| 1740 | +.shithub-profile-activity-state.is-merged b { | ||
| 1741 | + background: #8250df; | ||
| 1742 | +} | ||
| 1743 | +.shithub-profile-activity-state.is-closed b { | ||
| 1744 | + background: #cf222e; | ||
| 1745 | +} | ||
| 1746 | +.shithub-profile-stars-page .shithub-user-profile-container { | ||
| 1747 | + align-items: start; | ||
| 1748 | +} | ||
| 1749 | +.shithub-stars-main { | ||
| 1750 | + display: grid; | ||
| 1751 | + gap: 2rem; | ||
| 1752 | +} | ||
| 1753 | +.shithub-stars-section-head { | ||
| 1754 | + display: flex; | ||
| 1755 | + align-items: center; | ||
| 1756 | + justify-content: space-between; | ||
| 1757 | + gap: 1rem; | ||
| 1758 | + margin-bottom: 1rem; | ||
| 1759 | +} | ||
| 1760 | +.shithub-stars-section-head h2, | ||
| 1761 | +.shithub-stars-results h2 { | ||
| 1762 | + margin: 0; | ||
| 1763 | + font-size: 1rem; | ||
| 1764 | + font-weight: 400; | ||
| 1765 | +} | ||
| 1766 | +.shithub-stars-section-head h2 span { | ||
| 1767 | + color: var(--fg-muted); | ||
| 1768 | +} | ||
| 1769 | +.shithub-stars-list-actions { | ||
| 1770 | + display: flex; | ||
| 1771 | + gap: 0.5rem; | ||
| 1772 | +} | ||
| 1773 | +.shithub-stars-empty-list { | ||
| 1774 | + min-height: 148px; | ||
| 1775 | + border: 1px solid var(--border-default); | ||
| 1776 | + border-radius: 6px; | ||
| 1777 | + display: grid; | ||
| 1778 | + place-items: center; | ||
| 1779 | + align-content: center; | ||
| 1780 | + gap: 0.55rem; | ||
| 1781 | + padding: 1.5rem; | ||
| 1782 | + text-align: center; | ||
| 1783 | + color: var(--fg-default); | ||
| 1784 | +} | ||
| 1785 | +.shithub-stars-empty-list > span { | ||
| 1786 | + color: var(--fg-muted); | ||
| 1787 | +} | ||
| 1788 | +.shithub-stars-empty-list p { | ||
| 1789 | + margin: 0; | ||
| 1790 | + color: var(--fg-muted); | ||
| 1791 | + font-size: 0.875rem; | ||
| 1792 | +} | ||
| 1793 | +.shithub-stars-results { | ||
| 1794 | + min-width: 0; | ||
| 1795 | +} | ||
| 1796 | +.shithub-stars-toolbar { | ||
| 1797 | + display: flex; | ||
| 1798 | + align-items: center; | ||
| 1799 | + gap: 0.5rem; | ||
| 1800 | + margin: 1rem 0; | ||
| 1801 | +} | ||
| 1802 | +.shithub-stars-search { | ||
| 1803 | + position: relative; | ||
| 1804 | + flex: 1 1 240px; | ||
| 1805 | + min-width: 180px; | ||
| 1806 | +} | ||
| 1807 | +.shithub-stars-search svg { | ||
| 1808 | + position: absolute; | ||
| 1809 | + left: 0.65rem; | ||
| 1810 | + top: 50%; | ||
| 1811 | + transform: translateY(-50%); | ||
| 1812 | + color: var(--fg-muted); | ||
| 1813 | + pointer-events: none; | ||
| 1814 | +} | ||
| 1815 | +.shithub-stars-search input { | ||
| 1816 | + width: 100%; | ||
| 1817 | + padding-left: 2rem; | ||
| 1818 | +} | ||
| 1819 | +.shithub-stars-toolbar select { | ||
| 1820 | + min-height: 32px; | ||
| 1821 | + padding: 0 1.75rem 0 0.75rem; | ||
| 1822 | + border: 1px solid var(--border-default); | ||
| 1823 | + border-radius: 6px; | ||
| 1824 | + background: var(--canvas-subtle); | ||
| 1825 | + color: var(--fg-default); | ||
| 1826 | + font: inherit; | ||
| 1827 | +} | ||
| 1828 | +.shithub-stars-list { | ||
| 1829 | + list-style: none; | ||
| 1830 | + margin: 0; | ||
| 1831 | + padding: 0; | ||
| 1832 | + border-top: 1px solid var(--border-default); | ||
| 1833 | +} | ||
| 1834 | +.shithub-stars-row { | ||
| 1835 | + display: grid; | ||
| 1836 | + grid-template-columns: minmax(0, 1fr) auto; | ||
| 1837 | + gap: 1rem; | ||
| 1838 | + align-items: start; | ||
| 1839 | + padding: 1.25rem 0; | ||
| 1840 | + border-bottom: 1px solid var(--border-default); | ||
| 1841 | +} | ||
| 1842 | +.shithub-stars-row h3 { | ||
| 1843 | + margin: 0; | ||
| 1844 | + font-size: 1.125rem; | ||
| 1845 | + font-weight: 600; | ||
| 1846 | +} | ||
| 1847 | +.shithub-stars-row h3 a { | ||
| 1848 | + color: var(--accent-fg); | ||
| 1849 | + text-decoration: none; | ||
| 1850 | +} | ||
| 1851 | +.shithub-stars-row h3 a:hover { | ||
| 1852 | + text-decoration: underline; | ||
| 1853 | +} | ||
| 1854 | +.shithub-stars-row p { | ||
| 1855 | + margin: 0.45rem 0 0; | ||
| 1856 | + color: var(--fg-muted); | ||
| 1857 | +} | ||
| 1858 | +.shithub-stars-meta { | ||
| 1859 | + list-style: none; | ||
| 1860 | + margin: 0.65rem 0 0; | ||
| 1861 | + padding: 0; | ||
| 1862 | + display: flex; | ||
| 1863 | + flex-wrap: wrap; | ||
| 1864 | + align-items: center; | ||
| 1865 | + gap: 0.75rem; | ||
| 1866 | + color: var(--fg-muted); | ||
| 1867 | + font-size: 0.875rem; | ||
| 1868 | +} | ||
| 1869 | +.shithub-stars-meta li { | ||
| 1870 | + display: inline-flex; | ||
| 1871 | + align-items: center; | ||
| 1872 | + gap: 0.25rem; | ||
| 1873 | +} | ||
| 1874 | +.shithub-stars-starred svg:first-child { | ||
| 1875 | + color: #d29922; | ||
| 1876 | +} | ||
| 1674 | @media (max-width: 980px) { | 1877 | @media (max-width: 980px) { |
| 1675 | .shithub-profile-tabs-shell .shithub-profile-tabs { | 1878 | .shithub-profile-tabs-shell .shithub-profile-tabs { |
| 1676 | padding: 0 1rem; | 1879 | padding: 0 1rem; |
@@ -1754,6 +1957,19 @@ button.shithub-contrib-setting-item:hover { | |||
| 1754 | .shithub-profile-activity-item::before { | 1957 | .shithub-profile-activity-item::before { |
| 1755 | display: none; | 1958 | display: none; |
| 1756 | } | 1959 | } |
| 1960 | + .shithub-stars-toolbar, | ||
| 1961 | + .shithub-stars-row, | ||
| 1962 | + .shithub-stars-section-head { | ||
| 1963 | + align-items: stretch; | ||
| 1964 | + flex-direction: column; | ||
| 1965 | + display: flex; | ||
| 1966 | + } | ||
| 1967 | + .shithub-stars-list-actions { | ||
| 1968 | + width: 100%; | ||
| 1969 | + } | ||
| 1970 | + .shithub-stars-list-actions .shithub-button { | ||
| 1971 | + flex: 1; | ||
| 1972 | + } | ||
| 1757 | } | 1973 | } |
| 1758 | 1974 | ||
| 1759 | /* ----- settings shell (S10) ----- */ | 1975 | /* ----- settings shell (S10) ----- */ |
internal/web/templates/_layout.htmlmodified@@ -331,6 +331,20 @@ | |||
| 331 | refreshPins(); | 331 | refreshPins(); |
| 332 | })(); | 332 | })(); |
| 333 | 333 | ||
| 334 | + (function () { | ||
| 335 | + document.querySelectorAll("[data-profile-activity]").forEach(function (root) { | ||
| 336 | + var button = root.querySelector("[data-profile-activity-show-more]"); | ||
| 337 | + if (!button) return; | ||
| 338 | + button.addEventListener("click", function () { | ||
| 339 | + root.querySelectorAll("[data-profile-activity-more]").forEach(function (row) { | ||
| 340 | + row.hidden = false; | ||
| 341 | + row.removeAttribute("data-profile-activity-more"); | ||
| 342 | + }); | ||
| 343 | + button.hidden = true; | ||
| 344 | + }); | ||
| 345 | + }); | ||
| 346 | + })(); | ||
| 347 | + | ||
| 334 | (function () { | 348 | (function () { |
| 335 | var copyIcon = '<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16" fill="currentColor" aria-hidden="true"><path d="M0 6.75C0 5.784.784 5 1.75 5h1.5a.75.75 0 0 1 0 1.5h-1.5a.25.25 0 0 0-.25.25v7.5c0 .138.112.25.25.25h7.5a.25.25 0 0 0 .25-.25v-1.5a.75.75 0 0 1 1.5 0v1.5A1.75 1.75 0 0 1 9.25 16h-7.5A1.75 1.75 0 0 1 0 14.25Z"></path><path d="M5 1.75C5 .784 5.784 0 6.75 0h7.5C15.216 0 16 .784 16 1.75v7.5A1.75 1.75 0 0 1 14.25 11h-7.5A1.75 1.75 0 0 1 5 9.25Zm1.75-.25a.25.25 0 0 0-.25.25v7.5c0 .138.112.25.25.25h7.5a.25.25 0 0 0 .25-.25v-7.5a.25.25 0 0 0-.25-.25Z"></path></svg>'; | 349 | var copyIcon = '<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16" fill="currentColor" aria-hidden="true"><path d="M0 6.75C0 5.784.784 5 1.75 5h1.5a.75.75 0 0 1 0 1.5h-1.5a.25.25 0 0 0-.25.25v7.5c0 .138.112.25.25.25h7.5a.25.25 0 0 0 .25-.25v-1.5a.75.75 0 0 1 1.5 0v1.5A1.75 1.75 0 0 1 9.25 16h-7.5A1.75 1.75 0 0 1 0 14.25Z"></path><path d="M5 1.75C5 .784 5.784 0 6.75 0h7.5C15.216 0 16 .784 16 1.75v7.5A1.75 1.75 0 0 1 14.25 11h-7.5A1.75 1.75 0 0 1 5 9.25Zm1.75-.25a.25.25 0 0 0-.25.25v7.5c0 .138.112.25.25.25h7.5a.25.25 0 0 0 .25-.25v-7.5a.25.25 0 0 0-.25-.25Z"></path></svg>'; |
| 336 | var checkIcon = '<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16" fill="currentColor" aria-hidden="true"><path d="M13.78 4.22a.75.75 0 0 1 0 1.06l-7.25 7.25a.75.75 0 0 1-1.06 0L2.22 9.28a.751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018L6 10.94l6.72-6.72a.75.75 0 0 1 1.06 0Z"></path></svg>'; | 350 | var checkIcon = '<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16" fill="currentColor" aria-hidden="true"><path d="M13.78 4.22a.75.75 0 0 1 0 1.06l-7.25 7.25a.75.75 0 0 1-1.06 0L2.22 9.28a.751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018L6 10.94l6.72-6.72a.75.75 0 0 1 1.06 0Z"></path></svg>'; |
internal/web/templates/profile/stars_tab.htmlmodified@@ -1,39 +1,136 @@ | |||
| 1 | {{ define "page" -}} | 1 | {{ define "page" -}} |
| 2 | -<section class="shithub-profile"> | 2 | +<section class="shithub-user-profile shithub-profile-stars-page"> |
| 3 | - <header class="shithub-profile-header"> | 3 | + <div class="shithub-profile-tabs-shell"> |
| 4 | - <img class="shithub-profile-avatar" src="{{ .AvatarURL }}" alt="" width="120" height="120"> | 4 | + {{ template "profile-tabs" . }} |
| 5 | - <div class="shithub-profile-id"> | 5 | + </div> |
| 6 | - <h1 class="shithub-profile-name"> | 6 | + |
| 7 | - {{ if .User.DisplayName }}{{ .User.DisplayName }}{{ else }}{{ .User.Username }}{{ end }} | 7 | + <div class="shithub-user-profile-container"> |
| 8 | - </h1> | 8 | + <aside class="shithub-user-profile-sidebar" aria-label="{{ .User.Username }} profile"> |
| 9 | - <p class="shithub-profile-handle">@{{ .User.Username }}</p> | 9 | + <a class="shithub-profile-avatar-link" href="{{ .AvatarURL }}"> |
| 10 | - </div> | 10 | + <img class="shithub-profile-avatar" src="{{ .AvatarURL }}" alt="@{{ .User.Username }}" width="296" height="296"> |
| 11 | - </header> | 11 | + </a> |
| 12 | - | 12 | + <div class="shithub-profile-names"> |
| 13 | - {{ template "profile-tabs" . }} | 13 | + <h1> |
| 14 | - | 14 | + <span class="shithub-profile-name">{{ .DisplayName }}</span> |
| 15 | - {{ if .Stars }} | 15 | + <span class="shithub-profile-handle">{{ .User.Username }}</span> |
| 16 | - <ul class="shithub-social-list"> | 16 | + </h1> |
| 17 | - {{ range .Stars }} | 17 | + {{ if .User.Pronouns }}<span class="shithub-profile-pronouns">{{ .User.Pronouns }}</span>{{ end }} |
| 18 | - <li> | 18 | + </div> |
| 19 | - <a href="/{{ .OwnerName }}/{{ .RepoName }}"><strong>{{ .OwnerName }}/{{ .RepoName }}</strong></a> | 19 | + |
| 20 | - {{ if eq .Visibility "private" }}<span class="shithub-pill shithub-pill-private">private</span>{{ end }} | 20 | + {{ if .User.Bio }}<div class="shithub-profile-bio">{{ .User.Bio }}</div>{{ end }} |
| 21 | - {{ if .PrimaryLanguage }}<small>{{ .PrimaryLanguage }}</small>{{ end }} | 21 | + {{ if .IsSelf }}<a href="/settings/profile" class="shithub-button shithub-button-block">Edit profile</a>{{ end }} |
| 22 | - <small>★ {{ .StarCount }}</small> | 22 | + |
| 23 | - <small><time datetime="{{ .StarredAt.Format "2006-01-02T15:04:05Z" }}">starred {{ relativeTime .StarredAt }}</time></small> | 23 | + <p class="shithub-profile-follow-counts"> |
| 24 | - {{ if .Description }}<p class="shithub-meta">{{ .Description }}</p>{{ end }} | 24 | + {{ octicon "people" }} |
| 25 | - </li> | 25 | + <a href="/{{ .User.Username }}?tab=followers"><strong>{{ .FollowersCount }}</strong> followers</a> |
| 26 | - {{ end }} | 26 | + <span class="shithub-profile-dot" aria-hidden="true">·</span> |
| 27 | - </ul> | 27 | + <a href="/{{ .User.Username }}?tab=following"><strong>{{ .FollowingCount }}</strong> following</a> |
| 28 | - {{ else }} | 28 | + </p> |
| 29 | - <p class="shithub-empty">No starred repositories visible.</p> | 29 | + |
| 30 | - {{ end }} | 30 | + <ul class="shithub-profile-vcard"> |
| 31 | - | 31 | + {{ if .User.Company }}<li>{{ octicon "organization" }} <span>{{ .User.Company }}</span></li>{{ end }} |
| 32 | - {{ if or .HasPrev .HasNext }} | 32 | + {{ if .User.Location }}<li>{{ octicon "location" }} <span>{{ .User.Location }}</span></li>{{ end }} |
| 33 | - <nav class="shithub-pagination"> | 33 | + {{ if .WebsiteSafe }}<li>{{ octicon "link" }} <a href="{{ .WebsiteSafe }}" rel="nofollow noopener">{{ .User.Website }}</a></li>{{ end }} |
| 34 | - {{ if .HasPrev }}<a href="?tab=stars&page={{ sub .Page 1 }}" class="shithub-button">Previous</a>{{ end }} | 34 | + <li>{{ octicon "calendar" }} <span>Joined {{ .JoinedFormatted }}</span></li> |
| 35 | - {{ if .HasNext }}<a href="?tab=stars&page={{ add .Page 1 }}" class="shithub-button">Next</a>{{ end }} | 35 | + </ul> |
| 36 | - </nav> | 36 | + |
| 37 | - {{ end }} | 37 | + {{ if .Orgs }} |
| 38 | + <section class="shithub-profile-sidebar-section" aria-labelledby="stars-profile-orgs-heading"> | ||
| 39 | + <h2 id="stars-profile-orgs-heading">Organizations</h2> | ||
| 40 | + <div class="shithub-profile-orgs"> | ||
| 41 | + {{ range .Orgs }} | ||
| 42 | + <a href="/{{ .Slug }}" aria-label="{{ .DisplayName }}"> | ||
| 43 | + <img src="{{ .AvatarURL }}" alt="" width="32" height="32"> | ||
| 44 | + </a> | ||
| 45 | + {{ end }} | ||
| 46 | + </div> | ||
| 47 | + </section> | ||
| 48 | + {{ end }} | ||
| 49 | + </aside> | ||
| 50 | + | ||
| 51 | + <main class="shithub-user-profile-main shithub-stars-main"> | ||
| 52 | + <section class="shithub-stars-lists" aria-labelledby="stars-lists-heading"> | ||
| 53 | + <div class="shithub-stars-section-head"> | ||
| 54 | + <h2 id="stars-lists-heading">Lists <span>(0)</span></h2> | ||
| 55 | + <div class="shithub-stars-list-actions"> | ||
| 56 | + <button type="button" class="shithub-button" disabled>Sort {{ octicon "triangle-down" }}</button> | ||
| 57 | + <button type="button" class="shithub-button shithub-button-primary" disabled>Create list</button> | ||
| 58 | + </div> | ||
| 59 | + </div> | ||
| 60 | + <div class="shithub-stars-empty-list"> | ||
| 61 | + <span>{{ octicon "star" }}</span> | ||
| 62 | + <strong>Create your first list</strong> | ||
| 63 | + <p>Lists make it easier to organize and curate repositories that you have starred. <a href="/{{ .User.Username }}?tab=stars">Create your first list.</a></p> | ||
| 64 | + </div> | ||
| 65 | + </section> | ||
| 66 | + | ||
| 67 | + <section class="shithub-stars-results" aria-labelledby="stars-heading"> | ||
| 68 | + <h2 id="stars-heading">Stars</h2> | ||
| 69 | + <form class="shithub-stars-toolbar" method="get" action="/{{ .User.Username }}" aria-label="{{ .StarsSearchLabel }}"> | ||
| 70 | + <input type="hidden" name="tab" value="stars"> | ||
| 71 | + <label class="shithub-stars-search"> | ||
| 72 | + <span class="sr-only">Search stars</span> | ||
| 73 | + {{ octicon "search" }} | ||
| 74 | + <input type="search" name="q" value="{{ .StarFilters.Query }}" placeholder="Search stars" autocomplete="off"> | ||
| 75 | + </label> | ||
| 76 | + <button type="submit" class="shithub-button">Search</button> | ||
| 77 | + <label> | ||
| 78 | + <span class="sr-only">Repository type</span> | ||
| 79 | + <select name="type" onchange="this.form.submit()"> | ||
| 80 | + <option value="all"{{ if eq .StarFilters.Type "all" }} selected{{ end }}>Type: All</option> | ||
| 81 | + <option value="public"{{ if eq .StarFilters.Type "public" }} selected{{ end }}>Public</option> | ||
| 82 | + <option value="private"{{ if eq .StarFilters.Type "private" }} selected{{ end }}>Private</option> | ||
| 83 | + </select> | ||
| 84 | + </label> | ||
| 85 | + <label> | ||
| 86 | + <span class="sr-only">Language</span> | ||
| 87 | + <select name="language" onchange="this.form.submit()"> | ||
| 88 | + <option value=""{{ if not .StarFilters.Language }} selected{{ end }}>Language</option> | ||
| 89 | + {{ range .LanguageOptions }}<option value="{{ . }}"{{ if eq $.StarFilters.Language . }} selected{{ end }}>{{ . }}</option>{{ end }} | ||
| 90 | + </select> | ||
| 91 | + </label> | ||
| 92 | + <label> | ||
| 93 | + <span class="sr-only">Sort</span> | ||
| 94 | + <select name="sort" onchange="this.form.submit()"> | ||
| 95 | + <option value="recently-starred"{{ if eq .StarFilters.Sort "recently-starred" }} selected{{ end }}>Sort by: Recently starred</option> | ||
| 96 | + <option value="recently-active"{{ if eq .StarFilters.Sort "recently-active" }} selected{{ end }}>Recently active</option> | ||
| 97 | + <option value="stars"{{ if eq .StarFilters.Sort "stars" }} selected{{ end }}>Most stars</option> | ||
| 98 | + </select> | ||
| 99 | + </label> | ||
| 100 | + </form> | ||
| 101 | + | ||
| 102 | + {{ if .Stars }} | ||
| 103 | + <ol class="shithub-stars-list"> | ||
| 104 | + {{ range .Stars }} | ||
| 105 | + <li class="shithub-stars-row"> | ||
| 106 | + <div class="shithub-stars-row-main"> | ||
| 107 | + <h3> | ||
| 108 | + <a href="{{ .URL }}">{{ .FullName }}</a> | ||
| 109 | + {{ if .IsPrivate }}<span class="shithub-pill shithub-pill-private">Private</span>{{ end }} | ||
| 110 | + </h3> | ||
| 111 | + {{ if .Description }}<p>{{ .Description }}</p>{{ end }} | ||
| 112 | + <ul class="shithub-stars-meta"> | ||
| 113 | + {{ if .PrimaryLanguage }}<li><span class="shithub-language-dot" style="background-color: {{ .LanguageColor }};"></span>{{ .PrimaryLanguage }}</li>{{ end }} | ||
| 114 | + <li>{{ octicon "star" }} {{ .StarCount }}</li> | ||
| 115 | + <li>Updated <time datetime="{{ .UpdatedAt.Format "2006-01-02T15:04:05Z" }}">{{ relativeTime .UpdatedAt }}</time></li> | ||
| 116 | + </ul> | ||
| 117 | + </div> | ||
| 118 | + <button type="button" class="shithub-button shithub-stars-starred" disabled>{{ octicon "star" }} Starred {{ octicon "triangle-down" }}</button> | ||
| 119 | + </li> | ||
| 120 | + {{ end }} | ||
| 121 | + </ol> | ||
| 122 | + {{ else }} | ||
| 123 | + <p class="shithub-empty">No starred repositories visible.</p> | ||
| 124 | + {{ end }} | ||
| 125 | + | ||
| 126 | + {{ if or .HasPrev .HasNext }} | ||
| 127 | + <nav class="shithub-pagination"> | ||
| 128 | + {{ if .HasPrev }}<a href="{{ .PrevHref }}" class="shithub-button">Previous</a>{{ end }} | ||
| 129 | + {{ if .HasNext }}<a href="{{ .NextHref }}" class="shithub-button">Next</a>{{ end }} | ||
| 130 | + </nav> | ||
| 131 | + {{ end }} | ||
| 132 | + </section> | ||
| 133 | + </main> | ||
| 134 | + </div> | ||
| 38 | </section> | 135 | </section> |
| 39 | {{- end }} | 136 | {{- end }} |
internal/web/templates/profile/view.htmlmodified@@ -175,20 +175,51 @@ | |||
| 175 | </div> | 175 | </div> |
| 176 | </section> | 176 | </section> |
| 177 | 177 | ||
| 178 | - <section class="shithub-profile-activity" aria-labelledby="activity-h"> | 178 | + <section class="shithub-profile-activity" aria-labelledby="activity-h" data-profile-activity> |
| 179 | <h2 id="activity-h">Contribution activity</h2> | 179 | <h2 id="activity-h">Contribution activity</h2> |
| 180 | + {{ if .Contributions.Activity }} | ||
| 181 | + <div class="shithub-profile-activity-timeline"> | ||
| 182 | + {{ range .Contributions.Activity }} | ||
| 183 | + <div class="shithub-profile-activity-row"{{ if .InitiallyHidden }} hidden data-profile-activity-more{{ end }}> | ||
| 184 | + <div class="shithub-profile-activity-month">{{ .Label }}</div> | ||
| 185 | + <div class="shithub-profile-activity-list"> | ||
| 186 | + {{ range .Items }} | ||
| 187 | + <article class="shithub-profile-activity-item shithub-profile-activity-item-{{ .Kind }}"> | ||
| 188 | + <span class="shithub-profile-activity-icon">{{ octicon .Icon }}</span> | ||
| 189 | + <div class="shithub-profile-activity-body"> | ||
| 190 | + <strong>{{ .Summary }}</strong> | ||
| 191 | + {{ if .Repos }} | ||
| 192 | + <ol class="shithub-profile-activity-repos"> | ||
| 193 | + {{ range .Repos }} | ||
| 194 | + <li> | ||
| 195 | + {{ if .URL }}<a href="{{ .URL }}">{{ .FullName }}</a>{{ else }}<span>{{ .FullName }}</span>{{ end }} | ||
| 196 | + {{ if .Language }}<span class="shithub-profile-activity-lang"><span class="shithub-language-dot" style="background-color: {{ .LanguageColor }};"></span>{{ .Language }}</span>{{ end }} | ||
| 197 | + {{ if .CountLabel }}<span>{{ .CountLabel }}</span>{{ end }} | ||
| 198 | + {{ range .StateCounts }}<span class="shithub-profile-activity-state is-{{ .Class }}"><b>{{ .Count }}</b> {{ .Label }}</span>{{ end }} | ||
| 199 | + {{ if .DateLabel }}<time>{{ .DateLabel }}</time>{{ end }} | ||
| 200 | + </li> | ||
| 201 | + {{ end }} | ||
| 202 | + </ol> | ||
| 203 | + {{ end }} | ||
| 204 | + </div> | ||
| 205 | + </article> | ||
| 206 | + {{ end }} | ||
| 207 | + </div> | ||
| 208 | + </div> | ||
| 209 | + {{ end }} | ||
| 210 | + </div> | ||
| 211 | + {{ if .Contributions.HasMoreActivity }}<button type="button" class="shithub-button shithub-button-block" data-profile-activity-show-more>Show more activity</button>{{ end }} | ||
| 212 | + {{ else }} | ||
| 180 | <div class="shithub-profile-activity-row"> | 213 | <div class="shithub-profile-activity-row"> |
| 181 | <div class="shithub-profile-activity-month">{{ .Contributions.MonthLabel }}</div> | 214 | <div class="shithub-profile-activity-month">{{ .Contributions.MonthLabel }}</div> |
| 182 | - <div class="shithub-profile-activity-item"> | 215 | + <div class="shithub-profile-activity-list"> |
| 183 | - <span class="shithub-profile-activity-icon">{{ octicon "repo" }}</span> | 216 | + <article class="shithub-profile-activity-item"> |
| 184 | - {{ if .Contributions.MonthCommitCount }} | 217 | + <span class="shithub-profile-activity-icon">{{ octicon "repo" }}</span> |
| 185 | - <strong>Created {{ .Contributions.MonthCommitCount }} commit{{ pluralize .Contributions.MonthCommitCount "" "s" }} in {{ .Contributions.MonthRepoCount }} repositor{{ pluralize .Contributions.MonthRepoCount "y" "ies" }}</strong> | 218 | + <div class="shithub-profile-activity-body"><strong>No activity in {{ .Contributions.MonthLabel }}</strong></div> |
| 186 | - {{ else }} | 219 | + </article> |
| 187 | - <strong>No activity in {{ .Contributions.MonthLabel }}</strong> | ||
| 188 | - {{ end }} | ||
| 189 | </div> | 220 | </div> |
| 190 | </div> | 221 | </div> |
| 191 | - <button type="button" class="shithub-button shithub-button-block" disabled>Show more activity</button> | 222 | + {{ end }} |
| 192 | </section> | 223 | </section> |
| 193 | </main> | 224 | </main> |
| 194 | </div> | 225 | </div> |