Align repo and issue navigation
- SHA
51fc2ceeceeef5b211a044a6fa19193f008566e6- Parents
-
24a480c - Tree
4188611
51fc2ce
51fc2ceeceeef5b211a044a6fa19193f008566e624a480c
4188611internal/web/handlers/repo/code.gomodified@@ -69,13 +69,7 @@ func (h *Handlers) loadCodeContext(w http.ResponseWriter, r *http.Request) (*cod | ||
| 69 | 69 | if err != nil { |
| 70 | 70 | h.d.Logger.WarnContext(r.Context(), "code: ListRefs", "error", err) |
| 71 | 71 | } |
| 72 | - allNames := make([]string, 0, len(refs.Branches)+len(refs.Tags)) | |
| 73 | - for _, b := range refs.Branches { | |
| 74 | - allNames = append(allNames, b.Name) | |
| 75 | - } | |
| 76 | - for _, t := range refs.Tags { | |
| 77 | - allNames = append(allNames, t.Name) | |
| 78 | - } | |
| 72 | + allNames := refNames(refs) | |
| 79 | 73 | |
| 80 | 74 | rest := chi.URLParam(r, "*") |
| 81 | 75 | rest = strings.Trim(rest, "/") |
@@ -120,6 +114,10 @@ func (h *Handlers) codeTree(w http.ResponseWriter, r *http.Request) { | ||
| 120 | 114 | if !ok { |
| 121 | 115 | return |
| 122 | 116 | } |
| 117 | + h.renderRepoTree(w, r, cc) | |
| 118 | +} | |
| 119 | + | |
| 120 | +func (h *Handlers) renderRepoTree(w http.ResponseWriter, r *http.Request, cc *codeContext) { | |
| 123 | 121 | kind, _, _, err := repogit.StatPath(r.Context(), cc.gitDir, cc.ref, cc.subpath) |
| 124 | 122 | if err != nil { |
| 125 | 123 | if errors.Is(err, repogit.ErrPathNotFound) { |
@@ -146,6 +144,11 @@ func (h *Handlers) codeTree(w http.ResponseWriter, r *http.Request) { | ||
| 146 | 144 | } |
| 147 | 145 | // README detection on the requested directory only. |
| 148 | 146 | readmeHTML := h.findAndRenderREADME(r, cc, entries) |
| 147 | + head, headFound, headErr := repogit.HeadOf(r.Context(), cc.gitDir, cc.ref) | |
| 148 | + if headErr != nil { | |
| 149 | + h.d.Logger.WarnContext(r.Context(), "code: HeadOf", "error", headErr) | |
| 150 | + } | |
| 151 | + topics, _ := h.rq.ListRepoTopics(r.Context(), h.d.Pool, cc.row.ID) | |
| 149 | 152 | |
| 150 | 153 | h.d.Render.RenderPage(w, r, "repo/tree", map[string]any{ |
| 151 | 154 | "Title": cc.row.Name + " · " + cc.owner, |
@@ -158,16 +161,30 @@ func (h *Handlers) codeTree(w http.ResponseWriter, r *http.Request) { | ||
| 158 | 161 | "Entries": entries, |
| 159 | 162 | "Branches": cc.refs.Branches, |
| 160 | 163 | "Tags": cc.refs.Tags, |
| 164 | + "Head": head, | |
| 165 | + "HeadFound": headFound, | |
| 161 | 166 | "README": template.HTML(readmeHTML), //nolint:gosec // sanitized by mdrender |
| 162 | 167 | "HTTPSCloneURL": h.cloneHTTPS(cc.owner, cc.row.Name), |
| 163 | 168 | "SSHEnabled": h.d.CloneURLs.SSHEnabled, |
| 164 | 169 | "SSHCloneURL": h.cloneSSH(cc.owner, cc.row.Name), |
| 170 | + "RepoTopics": topics, | |
| 165 | 171 | "RepoCounts": h.subnavCounts(r.Context(), cc.row.ID, cc.row.ForkCount), |
| 166 | 172 | "CanSettings": h.canViewSettings(middleware.CurrentUserFromContext(r.Context())), |
| 167 | 173 | "ActiveSubnav": "code", |
| 168 | 174 | }) |
| 169 | 175 | } |
| 170 | 176 | |
| 177 | +func refNames(refs repogit.RefListing) []string { | |
| 178 | + allNames := make([]string, 0, len(refs.Branches)+len(refs.Tags)) | |
| 179 | + for _, b := range refs.Branches { | |
| 180 | + allNames = append(allNames, b.Name) | |
| 181 | + } | |
| 182 | + for _, t := range refs.Tags { | |
| 183 | + allNames = append(allNames, t.Name) | |
| 184 | + } | |
| 185 | + return allNames | |
| 186 | +} | |
| 187 | + | |
| 171 | 188 | // findAndRenderREADME looks for README* in the supplied entries (case- |
| 172 | 189 | // insensitive). Returns rendered HTML for markdown sources; returns a |
| 173 | 190 | // `<pre>`-wrapped escaped string for non-markdown text. Empty when |
internal/web/handlers/repo/issues.gomodified@@ -172,10 +172,13 @@ func (h *Handlers) issueNewForm(w http.ResponseWriter, r *http.Request) { | ||
| 172 | 172 | } |
| 173 | 173 | w.Header().Set("Content-Type", "text/html; charset=utf-8") |
| 174 | 174 | _ = h.d.Render.RenderPage(w, r, "repo/issue_new", map[string]any{ |
| 175 | - "Title": "New issue · " + row.Name, | |
| 176 | - "Owner": owner.Username, | |
| 177 | - "Repo": row, | |
| 178 | - "CSRFToken": middleware.CSRFTokenForRequest(r), | |
| 175 | + "Title": "New issue · " + row.Name, | |
| 176 | + "Owner": owner.Username, | |
| 177 | + "Repo": row, | |
| 178 | + "CSRFToken": middleware.CSRFTokenForRequest(r), | |
| 179 | + "RepoCounts": h.subnavCounts(r.Context(), row.ID, row.ForkCount), | |
| 180 | + "CanSettings": h.canViewSettings(middleware.CurrentUserFromContext(r.Context())), | |
| 181 | + "ActiveSubnav": "issues", | |
| 179 | 182 | }) |
| 180 | 183 | } |
| 181 | 184 | |
@@ -228,13 +231,16 @@ func (h *Handlers) renderIssueCreateError(w http.ResponseWriter, r *http.Request | ||
| 228 | 231 | w.Header().Set("Content-Type", "text/html; charset=utf-8") |
| 229 | 232 | w.WriteHeader(http.StatusBadRequest) |
| 230 | 233 | _ = h.d.Render.RenderPage(w, r, "repo/issue_new", map[string]any{ |
| 231 | - "Title": "New issue · " + row.Name, | |
| 232 | - "Owner": owner, | |
| 233 | - "Repo": row, | |
| 234 | - "FormTitle": title, | |
| 235 | - "FormBody": body, | |
| 236 | - "Error": msg, | |
| 237 | - "CSRFToken": middleware.CSRFTokenForRequest(r), | |
| 234 | + "Title": "New issue · " + row.Name, | |
| 235 | + "Owner": owner, | |
| 236 | + "Repo": row, | |
| 237 | + "FormTitle": title, | |
| 238 | + "FormBody": body, | |
| 239 | + "Error": msg, | |
| 240 | + "CSRFToken": middleware.CSRFTokenForRequest(r), | |
| 241 | + "RepoCounts": h.subnavCounts(r.Context(), row.ID, row.ForkCount), | |
| 242 | + "CanSettings": h.canViewSettings(middleware.CurrentUserFromContext(r.Context())), | |
| 243 | + "ActiveSubnav": "issues", | |
| 238 | 244 | }) |
| 239 | 245 | } |
| 240 | 246 | |
@@ -343,6 +349,9 @@ func (h *Handlers) issueView(w http.ResponseWriter, r *http.Request) { | ||
| 343 | 349 | "CanEditIssueMilestone": policy.Can(r.Context(), pdeps, actor, policy.ActionIssueLabel, repoRef).Allow, |
| 344 | 350 | "CanLockIssue": policy.Can(r.Context(), pdeps, actor, policy.ActionIssueClose, repoRef).Allow, |
| 345 | 351 | "CSRFToken": middleware.CSRFTokenForRequest(r), |
| 352 | + "RepoCounts": h.subnavCounts(r.Context(), row.ID, row.ForkCount), | |
| 353 | + "CanSettings": h.canViewSettings(viewer), | |
| 354 | + "ActiveSubnav": "issues", | |
| 346 | 355 | }) |
| 347 | 356 | } |
| 348 | 357 | |
internal/web/handlers/repo/labels_milestones.gomodified@@ -35,6 +35,9 @@ func (h *Handlers) labelsList(w http.ResponseWriter, r *http.Request) { | ||
| 35 | 35 | "Labels": labels, |
| 36 | 36 | "CanManageIssue": canManage, |
| 37 | 37 | "CSRFToken": middleware.CSRFTokenForRequest(r), |
| 38 | + "RepoCounts": h.subnavCounts(r.Context(), row.ID, row.ForkCount), | |
| 39 | + "CanSettings": h.canViewSettings(viewer), | |
| 40 | + "ActiveSubnav": "issues", | |
| 38 | 41 | }) |
| 39 | 42 | } |
| 40 | 43 | |
@@ -134,6 +137,9 @@ func (h *Handlers) milestonesList(w http.ResponseWriter, r *http.Request) { | ||
| 134 | 137 | "Milestones": ms, |
| 135 | 138 | "CanManageIssue": canManage, |
| 136 | 139 | "CSRFToken": middleware.CSRFTokenForRequest(r), |
| 140 | + "RepoCounts": h.subnavCounts(r.Context(), row.ID, row.ForkCount), | |
| 141 | + "CanSettings": h.canViewSettings(viewer), | |
| 142 | + "ActiveSubnav": "issues", | |
| 137 | 143 | }) |
| 138 | 144 | } |
| 139 | 145 | |
internal/web/handlers/repo/repo.gomodified@@ -311,10 +311,8 @@ func (h *Handlers) ownerOptions(r *http.Request) []ownerOption { | ||
| 311 | 311 | return out |
| 312 | 312 | } |
| 313 | 313 | |
| 314 | -// repoHome serves GET /{owner}/{repo}. Forks on whether the bare repo | |
| 315 | -// has any branches: empty → quick-setup placeholder; populated → a slim | |
| 316 | -// "post-push" view with the head commit on the default branch. The full | |
| 317 | -// tree/file listing is S17. | |
| 314 | +// repoHome serves GET /{owner}/{repo}. Empty repos render the quick setup | |
| 315 | +// placeholder; populated repos render the Code tab at the repository home URL. | |
| 318 | 316 | func (h *Handlers) repoHome(w http.ResponseWriter, r *http.Request) { |
| 319 | 317 | owner := chi.URLParam(r, "owner") |
| 320 | 318 | name := chi.URLParam(r, "repo") |
@@ -332,9 +330,8 @@ func (h *Handlers) repoHome(w http.ResponseWriter, r *http.Request) { | ||
| 332 | 330 | return |
| 333 | 331 | } |
| 334 | 332 | |
| 335 | - // S17: when the repo has any branch, the canonical view is the | |
| 336 | - // tree at default_branch. The S11 quick-setup placeholder still | |
| 337 | - // covers the empty case. | |
| 333 | + // Keep the populated repository home at /owner/name, matching GitHub's | |
| 334 | + // Code tab instead of forcing users through the /tree/default-branch URL. | |
| 338 | 335 | diskPath, fsErr := h.d.RepoFS.RepoPath(owner, row.Name) |
| 339 | 336 | hasBranch := false |
| 340 | 337 | if fsErr == nil { |
@@ -345,7 +342,19 @@ func (h *Handlers) repoHome(w http.ResponseWriter, r *http.Request) { | ||
| 345 | 342 | } |
| 346 | 343 | } |
| 347 | 344 | if hasBranch { |
| 348 | - http.Redirect(w, r, "/"+owner+"/"+row.Name+"/tree/"+row.DefaultBranch, http.StatusSeeOther) | |
| 345 | + refs, refsErr := repogit.ListRefs(r.Context(), diskPath) | |
| 346 | + if refsErr != nil { | |
| 347 | + h.d.Logger.WarnContext(r.Context(), "repo: ListRefs", "error", refsErr) | |
| 348 | + } | |
| 349 | + h.renderRepoTree(w, r, &codeContext{ | |
| 350 | + owner: owner, | |
| 351 | + row: row, | |
| 352 | + gitDir: diskPath, | |
| 353 | + refs: refs, | |
| 354 | + allRefs: refNames(refs), | |
| 355 | + ref: row.DefaultBranch, | |
| 356 | + subpath: "", | |
| 357 | + }) | |
| 349 | 358 | return |
| 350 | 359 | } |
| 351 | 360 | |
internal/web/render/octicons.gomodified@@ -31,6 +31,22 @@ func BuiltinOcticons() OcticonResolver { | ||
| 31 | 31 | `><path d="M9.598 1.591a.75.75 0 0 1 .785-.175 7 7 0 1 1-8.967 8.967.75.75 0 0 1 .961-.96 5.5 5.5 0 0 0 7.046-7.046.75.75 0 0 1 .175-.786z"/></svg>`), |
| 32 | 32 | "alert": trustedSVG(`<svg xmlns="http://www.w3.org/2000/svg" ` + cls + |
| 33 | 33 | `><path d="M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575zM8 5a.75.75 0 0 0-.75.75v2.5a.75.75 0 0 0 1.5 0v-2.5A.75.75 0 0 0 8 5zm1 6a1 1 0 1 1-2 0 1 1 0 0 1 2 0z"/></svg>`), |
| 34 | + "repo": trustedSVG(`<svg xmlns="http://www.w3.org/2000/svg" ` + cls + | |
| 35 | + `><path d="M2 2.5A2.5 2.5 0 0 1 4.5 0h8.75A.75.75 0 0 1 14 .75v12.5a.75.75 0 0 1-.75.75H4.5a1 1 0 0 0 0 2h8.75a.75.75 0 0 1 0 1.5H4.5A2.5 2.5 0 0 1 2 15V2.5Zm2.5-1A1 1 0 0 0 3.5 2.5v10.21c.31-.13.648-.21 1-.21h8V1.5Z"/></svg>`), | |
| 36 | + "code": trustedSVG(`<svg xmlns="http://www.w3.org/2000/svg" ` + cls + | |
| 37 | + `><path d="M5.22 4.22a.75.75 0 0 1 1.06 1.06L3.56 8l2.72 2.72a.75.75 0 1 1-1.06 1.06L1.97 8.53a.75.75 0 0 1 0-1.06Zm5.56 0a.75.75 0 0 1 1.06 0l3.25 3.25a.75.75 0 0 1 0 1.06l-3.25 3.25a.75.75 0 1 1-1.06-1.06L13.5 8l-2.72-2.72a.75.75 0 0 1 0-1.06Z"/></svg>`), | |
| 38 | + "git-pull-request": trustedSVG(`<svg xmlns="http://www.w3.org/2000/svg" ` + cls + | |
| 39 | + `><path d="M1.5 3.25a2.25 2.25 0 1 1 3 2.122v5.256a2.251 2.251 0 1 1-1.5 0V5.372A2.25 2.25 0 0 1 1.5 3.25Zm2.25-.75a.75.75 0 1 0 0 1.5.75.75 0 0 0 0-1.5Zm0 9.5a.75.75 0 1 0 0 1.5.75.75 0 0 0 0-1.5Zm8.5-9.5a.75.75 0 0 0-.75.75v1.5h1.5a.75.75 0 0 1 0 1.5h-1.5v1.5a.75.75 0 0 1-1.5 0v-1.5H8.5a.75.75 0 0 1 0-1.5H10v-1.5a.75.75 0 0 0-.75-.75H7.75A2.75 2.75 0 0 0 5 5.25V6a.75.75 0 0 1-1.5 0v-.75A4.25 4.25 0 0 1 7.75 1h1.5a2.25 2.25 0 0 1 2.25 2.25Z"/></svg>`), | |
| 40 | + "git-branch": trustedSVG(`<svg xmlns="http://www.w3.org/2000/svg" ` + cls + | |
| 41 | + `><path d="M4.25 5.372v5.256a2.251 2.251 0 1 1-1.5 0V5.372a2.25 2.25 0 1 1 1.5 0ZM3.5 2.5a.75.75 0 1 0 0 1.5.75.75 0 0 0 0-1.5Zm0 9.5a.75.75 0 1 0 0 1.5.75.75 0 0 0 0-1.5Zm6.25-9.5a.75.75 0 0 0-.75.75V5.5h1.75A2.75 2.75 0 0 1 13.5 8.25v2.378a2.251 2.251 0 1 1-1.5 0V8.25A1.25 1.25 0 0 0 10.75 7H8.25A.75.75 0 0 1 7.5 6.25v-3a2.25 2.25 0 1 1 2.25 2.25V4a.75.75 0 0 0 0-1.5ZM12.75 12a.75.75 0 1 0 0 1.5.75.75 0 0 0 0-1.5Z"/></svg>`), | |
| 42 | + "repo-forked": trustedSVG(`<svg xmlns="http://www.w3.org/2000/svg" ` + cls + | |
| 43 | + `><path d="M5 3.25a2.25 2.25 0 1 1-3 2.122v1.878A2.75 2.75 0 0 0 4.75 10H7.25v-4.628a2.25 2.25 0 1 1 1.5 0V10h2.5A2.75 2.75 0 0 0 14 7.25V5.372a2.25 2.25 0 1 1 1.5 0V7.25a4.25 4.25 0 0 1-4.25 4.25h-2.5v2.128a2.251 2.251 0 1 1-1.5 0V11.5H4.75A4.25 4.25 0 0 1 .5 7.25V5.372A2.25 2.25 0 0 1 5 3.25Zm-2.25-.75a.75.75 0 1 0 0 1.5.75.75 0 0 0 0-1.5Zm5.25 0a.75.75 0 1 0 0 1.5.75.75 0 0 0 0-1.5Zm5.25 0a.75.75 0 1 0 0 1.5.75.75 0 0 0 0-1.5ZM8 13.5a.75.75 0 1 0 0 1.5.75.75 0 0 0 0-1.5Z"/></svg>`), | |
| 44 | + "eye": trustedSVG(`<svg xmlns="http://www.w3.org/2000/svg" ` + cls + | |
| 45 | + `><path d="M8 2c3.767 0 6.313 3.148 7.33 4.655a2.33 2.33 0 0 1 0 2.69C14.313 10.852 11.767 14 8 14S1.687 10.852.67 9.345a2.33 2.33 0 0 1 0-2.69C1.687 5.148 4.233 2 8 2Zm0 1.5c-3.07 0-5.248 2.621-6.087 3.865a.83.83 0 0 0 0 .97C2.752 9.579 4.93 12.5 8 12.5s5.248-2.921 6.087-4.165a.83.83 0 0 0 0-.97C13.248 6.121 11.07 3.5 8 3.5ZM8 5a3 3 0 1 1 0 6 3 3 0 0 1 0-6Zm0 1.5a1.5 1.5 0 1 0 0 3 1.5 1.5 0 0 0 0-3Z"/></svg>`), | |
| 46 | + "book": trustedSVG(`<svg xmlns="http://www.w3.org/2000/svg" ` + cls + | |
| 47 | + `><path d="M0 1.75A.75.75 0 0 1 .75 1h4.5C6.768 1 8 2.232 8 3.75A2.75 2.75 0 0 1 10.75 1h4.5a.75.75 0 0 1 .75.75v11.5a.75.75 0 0 1-.75.75h-4.5A1.25 1.25 0 0 0 9.5 15.25a.75.75 0 0 1-1.5 0A1.25 1.25 0 0 0 6.75 14H.75A.75.75 0 0 1 0 13.25ZM1.5 2.5v10h5.25c.63 0 1.21.23 1.75.61V3.75A1.25 1.25 0 0 0 7.25 2.5Zm7 10.61c.54-.38 1.12-.61 1.75-.61h4.25v-10h-3.75A1.25 1.25 0 0 0 9.5 3.75v9.36Z"/></svg>`), | |
| 48 | + "law": trustedSVG(`<svg xmlns="http://www.w3.org/2000/svg" ` + cls + | |
| 49 | + `><path d="M8.75.75a.75.75 0 0 0-1.5 0V2h-4.5a.75.75 0 0 0 0 1.5h.48L.34 9.13a.75.75 0 0 0-.09.36C.25 11.43 1.82 13 3.75 13s3.5-1.57 3.5-3.51a.75.75 0 0 0-.09-.36L4.27 3.5h2.98v10H5.75a.75.75 0 0 0 0 1.5h4.5a.75.75 0 0 0 0-1.5h-1.5v-10h2.98L8.84 9.13a.75.75 0 0 0-.09.36c0 1.94 1.57 3.51 3.5 3.51s3.5-1.57 3.5-3.51a.75.75 0 0 0-.09-.36L12.77 3.5h.48a.75.75 0 0 0 0-1.5h-4.5ZM3.75 11.5a2 2 0 0 1-1.88-1.31h3.76a2 2 0 0 1-1.88 1.31Zm8.5 0a2 2 0 0 1-1.88-1.31h3.76a2 2 0 0 1-1.88 1.31ZM2.2 8.69l1.55-3.02 1.55 3.02Zm8.5 0 1.55-3.02 1.55 3.02Z"/></svg>`), | |
| 34 | 50 | "issue-opened": trustedSVG(`<svg xmlns="http://www.w3.org/2000/svg" ` + cls + |
| 35 | 51 | `><path d="M8 1.5a6.5 6.5 0 1 0 0 13 6.5 6.5 0 0 0 0-13ZM0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8Zm8-3.25a.75.75 0 0 1 .75.75v2.75a.75.75 0 0 1-1.5 0V5.5A.75.75 0 0 1 8 4.75ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z"/></svg>`), |
| 36 | 52 | "issue-closed": trustedSVG(`<svg xmlns="http://www.w3.org/2000/svg" ` + cls + |
internal/web/static/css/shithub.cssmodified@@ -903,7 +903,7 @@ code { | ||
| 903 | 903 | column. */ |
| 904 | 904 | .shithub-repo-page { |
| 905 | 905 | max-width: 1280px; |
| 906 | - margin: 1.5rem auto; | |
| 906 | + margin: 1rem auto 2rem; | |
| 907 | 907 | padding: 0 1.25rem; |
| 908 | 908 | } |
| 909 | 909 | .shithub-code, .shithub-blob, .shithub-finder { |
@@ -913,32 +913,34 @@ code { | ||
| 913 | 913 | /* Code body (tree + blob source) sits in a bordered panel so it |
| 914 | 914 | reads as a distinct surface — matches the panelled "Code" view in |
| 915 | 915 | the GitHub reference screenshots. */ |
| 916 | -.shithub-tree, .shithub-blob-source { | |
| 916 | +.shithub-blob-source { | |
| 917 | 917 | border: 1px solid var(--border-default); |
| 918 | 918 | border-radius: 6px; |
| 919 | 919 | background: var(--canvas-subtle); |
| 920 | 920 | overflow-x: auto; |
| 921 | 921 | } |
| 922 | -.shithub-tree { background: var(--canvas-default); } | |
| 923 | 922 | .shithub-blob-source { background: var(--canvas-default); } |
| 924 | 923 | .shithub-code-head { |
| 925 | 924 | display: flex; |
| 926 | 925 | align-items: center; |
| 927 | 926 | justify-content: space-between; |
| 928 | - margin-bottom: 1rem; | |
| 929 | - padding-bottom: 0.5rem; | |
| 930 | - border-bottom: 1px solid var(--border-default); | |
| 927 | + gap: 0.75rem; | |
| 928 | + margin-bottom: 0.75rem; | |
| 929 | + flex-wrap: wrap; | |
| 931 | 930 | } |
| 932 | 931 | .shithub-code-crumbs { font-size: 1rem; } |
| 933 | 932 | .shithub-code-crumbs a { color: var(--fg-default); } |
| 934 | 933 | .shithub-code-sep { color: var(--fg-muted); margin: 0 0.25rem; } |
| 935 | 934 | .shithub-code-actions { display: flex; gap: 0.5rem; align-items: center; } |
| 935 | +.shithub-code-primary-actions { display: flex; align-items: center; gap: 0.75rem; flex-wrap: wrap; } | |
| 936 | +.shithub-code-count { color: var(--fg-muted); display: inline-flex; align-items: center; gap: 0.35rem; font-size: 0.9rem; } | |
| 936 | 937 | |
| 937 | 938 | .shithub-ref-switcher { position: relative; } |
| 938 | 939 | .shithub-ref-switcher > summary { |
| 939 | 940 | list-style: none; |
| 940 | 941 | display: inline-flex; |
| 941 | 942 | align-items: center; |
| 943 | + gap: 0.35rem; | |
| 942 | 944 | padding: 0.3rem 0.7rem; |
| 943 | 945 | border: 1px solid var(--border-default); |
| 944 | 946 | border-radius: 6px; |
@@ -1041,16 +1043,41 @@ code { | ||
| 1041 | 1043 | .shithub-repo-list-meta { color: var(--fg-muted); font-size: 0.8rem; display: flex; gap: 1rem; flex-wrap: wrap; margin: 0.4rem 0 0; } |
| 1042 | 1044 | .shithub-pill-archived { background: #ffd35a; color: #3b2300; } |
| 1043 | 1045 | |
| 1044 | -/* Repo subnav (S30 polish): GitHub-style Code / Issues / Pulls / Settings tabs. */ | |
| 1045 | -.shithub-repo-page-head { | |
| 1046 | - margin-bottom: 0.25rem; | |
| 1046 | +.shithub-repo-header { margin-bottom: 1.25rem; } | |
| 1047 | +.shithub-repo-header-inner { | |
| 1048 | + display: flex; | |
| 1049 | + align-items: center; | |
| 1050 | + justify-content: space-between; | |
| 1051 | + gap: 1rem; | |
| 1052 | + padding: 0.25rem 0 0.75rem; | |
| 1047 | 1053 | } |
| 1048 | -.shithub-repo-page-title { font-size: 1.4rem; margin: 0.5rem 0; display: flex; align-items: center; gap: 0.4rem; flex-wrap: wrap; } | |
| 1054 | +.shithub-repo-page-title { font-size: 1.4rem; margin: 0; display: flex; align-items: center; gap: 0.4rem; flex-wrap: wrap; } | |
| 1049 | 1055 | .shithub-repo-page-title a { color: var(--accent-fg, #4493f8); } |
| 1056 | +.shithub-repo-page-title .shithub-repo-name { font-weight: 600; } | |
| 1057 | +.shithub-repo-title-icon { color: var(--fg-muted); display: inline-flex; align-items: center; } | |
| 1058 | +.shithub-repo-actions { display: flex; align-items: center; gap: 0.5rem; flex-wrap: wrap; } | |
| 1059 | +.shithub-repo-action { | |
| 1060 | + display: inline-flex; | |
| 1061 | + align-items: center; | |
| 1062 | + gap: 0.35rem; | |
| 1063 | + padding: 0.35rem 0.7rem; | |
| 1064 | + border: 1px solid var(--border-default); | |
| 1065 | + border-radius: 6px; | |
| 1066 | + color: var(--fg-default); | |
| 1067 | + background: var(--canvas-subtle); | |
| 1068 | + font-size: 0.875rem; | |
| 1069 | + font-weight: 600; | |
| 1070 | +} | |
| 1071 | +.shithub-repo-action span { | |
| 1072 | + color: var(--fg-muted); | |
| 1073 | + font-weight: 600; | |
| 1074 | + padding-left: 0.35rem; | |
| 1075 | + border-left: 1px solid var(--border-default); | |
| 1076 | +} | |
| 1050 | 1077 | .shithub-repo-subnav { |
| 1051 | 1078 | display: flex; |
| 1052 | 1079 | gap: 0.25rem; |
| 1053 | - margin: 0 0 1.25rem; | |
| 1080 | + margin: 0; | |
| 1054 | 1081 | border-bottom: 1px solid var(--border-default); |
| 1055 | 1082 | flex-wrap: wrap; |
| 1056 | 1083 | } |
@@ -1074,15 +1101,49 @@ code { | ||
| 1074 | 1101 | .shithub-repo-new-owner select { padding: 0.4rem 0.5rem; } |
| 1075 | 1102 | .shithub-repo-new-sep { font-size: 1.5rem; color: var(--fg-muted); padding-bottom: 0.4rem; } |
| 1076 | 1103 | |
| 1104 | +.shithub-repo-content-grid { | |
| 1105 | + display: grid; | |
| 1106 | + grid-template-columns: minmax(0, 1fr) 296px; | |
| 1107 | + gap: 1.5rem; | |
| 1108 | + align-items: start; | |
| 1109 | +} | |
| 1110 | +.shithub-repo-main { min-width: 0; } | |
| 1111 | +.shithub-tree-panel { | |
| 1112 | + border: 1px solid var(--border-default); | |
| 1113 | + border-radius: 6px; | |
| 1114 | + background: var(--canvas-default); | |
| 1115 | + overflow: hidden; | |
| 1116 | +} | |
| 1117 | +.shithub-tree-commit { | |
| 1118 | + display: flex; | |
| 1119 | + justify-content: space-between; | |
| 1120 | + align-items: center; | |
| 1121 | + gap: 1rem; | |
| 1122 | + padding: 0.75rem 1rem; | |
| 1123 | + background: var(--canvas-subtle); | |
| 1124 | + border-bottom: 1px solid var(--border-default); | |
| 1125 | + font-size: 0.9rem; | |
| 1126 | +} | |
| 1127 | +.shithub-tree-commit-message, | |
| 1128 | +.shithub-tree-commit-meta { | |
| 1129 | + display: flex; | |
| 1130 | + align-items: center; | |
| 1131 | + gap: 0.5rem; | |
| 1132 | + min-width: 0; | |
| 1133 | +} | |
| 1134 | +.shithub-tree-commit-message span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } | |
| 1135 | +.shithub-tree-commit-meta { color: var(--fg-muted); flex: 0 0 auto; } | |
| 1077 | 1136 | .shithub-tree { |
| 1078 | 1137 | width: 100%; |
| 1079 | 1138 | border-collapse: collapse; |
| 1080 | 1139 | font-size: 0.9rem; |
| 1140 | + background: var(--canvas-default); | |
| 1081 | 1141 | } |
| 1082 | 1142 | .shithub-tree td { |
| 1083 | - padding: 0.4rem 0.5rem; | |
| 1143 | + padding: 0.5rem 0.75rem; | |
| 1084 | 1144 | border-bottom: 1px solid var(--border-default); |
| 1085 | 1145 | } |
| 1146 | +.shithub-tree tr:last-child td { border-bottom: 0; } | |
| 1086 | 1147 | .shithub-tree-icon { width: 24px; color: var(--fg-muted); } |
| 1087 | 1148 | .shithub-tree-icon svg { display: block; } |
| 1088 | 1149 | .shithub-tree-name a { color: var(--fg-default); } |
@@ -1090,17 +1151,68 @@ code { | ||
| 1090 | 1151 | .shithub-tree-symlink, .shithub-tree-submodule { color: var(--fg-muted); font-style: italic; font-size: 0.8rem; } |
| 1091 | 1152 | |
| 1092 | 1153 | .shithub-readme { |
| 1093 | - margin-top: 2rem; | |
| 1094 | - padding: 1.25rem; | |
| 1154 | + margin-top: 1rem; | |
| 1155 | + padding: 0; | |
| 1095 | 1156 | border: 1px solid var(--border-default); |
| 1096 | 1157 | border-radius: 6px; |
| 1097 | - background: var(--canvas-subtle); | |
| 1158 | + background: var(--canvas-default); | |
| 1159 | + overflow: hidden; | |
| 1098 | 1160 | } |
| 1161 | +.shithub-readme-head { | |
| 1162 | + display: flex; | |
| 1163 | + align-items: center; | |
| 1164 | + gap: 0.45rem; | |
| 1165 | + padding: 0.75rem 1rem; | |
| 1166 | + border-bottom: 1px solid var(--border-default); | |
| 1167 | + font-weight: 600; | |
| 1168 | +} | |
| 1169 | +.shithub-readme-body { padding: 1rem; } | |
| 1099 | 1170 | .shithub-readme h1, .shithub-readme h2 { border-bottom: 1px solid var(--border-default); padding-bottom: 0.3rem; } |
| 1100 | 1171 | .shithub-readme code { font-family: monospace; padding: 0.1em 0.3em; background: var(--canvas-default); border-radius: 3px; } |
| 1101 | 1172 | .shithub-readme pre code { padding: 0; background: none; } |
| 1102 | 1173 | .shithub-readme-plain { white-space: pre-wrap; } |
| 1103 | 1174 | |
| 1175 | +.shithub-repo-about { font-size: 0.9rem; } | |
| 1176 | +.shithub-repo-about-heading { | |
| 1177 | + display: flex; | |
| 1178 | + justify-content: space-between; | |
| 1179 | + align-items: center; | |
| 1180 | + gap: 0.75rem; | |
| 1181 | + margin-bottom: 0.75rem; | |
| 1182 | +} | |
| 1183 | +.shithub-repo-about-heading h2 { font-size: 1rem; margin: 0; } | |
| 1184 | +.shithub-repo-about-heading a { color: var(--fg-muted); display: inline-flex; } | |
| 1185 | +.shithub-repo-about-desc { margin: 0 0 0.85rem; font-size: 1rem; line-height: 1.45; } | |
| 1186 | +.shithub-repo-topics { display: flex; flex-wrap: wrap; gap: 0.4rem; margin-bottom: 0.9rem; } | |
| 1187 | +.shithub-topic { | |
| 1188 | + display: inline-flex; | |
| 1189 | + padding: 0.18rem 0.55rem; | |
| 1190 | + border-radius: 999px; | |
| 1191 | + background: color-mix(in srgb, var(--accent-fg, #4493f8) 12%, transparent); | |
| 1192 | + color: var(--accent-fg, #4493f8); | |
| 1193 | + font-size: 0.8rem; | |
| 1194 | + font-weight: 600; | |
| 1195 | +} | |
| 1196 | +.shithub-repo-about-list { | |
| 1197 | + list-style: none; | |
| 1198 | + padding: 0.85rem 0 0; | |
| 1199 | + margin: 0; | |
| 1200 | + border-top: 1px solid var(--border-default); | |
| 1201 | + color: var(--fg-muted); | |
| 1202 | +} | |
| 1203 | +.shithub-repo-about-list li { | |
| 1204 | + display: flex; | |
| 1205 | + align-items: center; | |
| 1206 | + gap: 0.55rem; | |
| 1207 | + margin: 0.55rem 0; | |
| 1208 | +} | |
| 1209 | +.shithub-repo-about-list svg { flex: 0 0 auto; } | |
| 1210 | +@media (max-width: 900px) { | |
| 1211 | + .shithub-repo-header-inner { align-items: flex-start; flex-direction: column; } | |
| 1212 | + .shithub-repo-content-grid { grid-template-columns: 1fr; } | |
| 1213 | + .shithub-tree-commit { align-items: flex-start; flex-direction: column; } | |
| 1214 | +} | |
| 1215 | + | |
| 1104 | 1216 | .shithub-blob-meta { color: var(--fg-muted); font-size: 0.85rem; margin-right: 0.5rem; } |
| 1105 | 1217 | /* Blob source: a row-per-line <table>. We render the gutter + code |
| 1106 | 1218 | ourselves and feed Chroma only token spans (no <pre>, no <table>) |
@@ -1366,9 +1478,8 @@ code { | ||
| 1366 | 1478 | |
| 1367 | 1479 | /* ========== Issues / Labels / Milestones (S21) ========== */ |
| 1368 | 1480 | .shithub-issues, .shithub-issue-view, .shithub-issue-new, .shithub-labels, .shithub-milestones { |
| 1369 | - max-width: 64rem; | |
| 1370 | - margin: 1.5rem auto; | |
| 1371 | - padding: 0 1rem; | |
| 1481 | + margin: 0; | |
| 1482 | + padding: 0; | |
| 1372 | 1483 | } |
| 1373 | 1484 | .shithub-issues-head { display: flex; justify-content: space-between; align-items: center; gap: 1rem; flex-wrap: wrap; } |
| 1374 | 1485 | .shithub-issues-actions { display: flex; gap: 0.4rem; } |
internal/web/templates/_repo_header.htmladded@@ -0,0 +1,19 @@ | ||
| 1 | +{{ define "repo-header" -}} | |
| 2 | +<header class="shithub-repo-header"> | |
| 3 | + <div class="shithub-repo-header-inner"> | |
| 4 | + <h1 class="shithub-repo-page-title"> | |
| 5 | + <span class="shithub-repo-title-icon">{{ octicon "repo" }}</span> | |
| 6 | + <a href="/{{ .Owner }}">{{ .Owner }}</a> | |
| 7 | + <span class="shithub-code-sep">/</span> | |
| 8 | + <a href="/{{ .Owner }}/{{ .Repo.Name }}" class="shithub-repo-name">{{ .Repo.Name }}</a> | |
| 9 | + {{ if eq (printf "%s" .Repo.Visibility) "private" }}<span class="shithub-pill shithub-pill-private">Private</span>{{ else }}<span class="shithub-pill">Public</span>{{ end }} | |
| 10 | + </h1> | |
| 11 | + <div class="shithub-repo-actions" aria-label="Repository actions"> | |
| 12 | + <a href="/{{ .Owner }}/{{ .Repo.Name }}/watchers" class="shithub-repo-action">{{ octicon "eye" }} Watch <span>{{ .Repo.WatcherCount }}</span></a> | |
| 13 | + <a href="/{{ .Owner }}/{{ .Repo.Name }}/forks" class="shithub-repo-action">{{ octicon "repo-forked" }} Fork <span>{{ .Repo.ForkCount }}</span></a> | |
| 14 | + <a href="/{{ .Owner }}/{{ .Repo.Name }}/stargazers" class="shithub-repo-action">{{ octicon "star" }} Star <span>{{ .Repo.StarCount }}</span></a> | |
| 15 | + </div> | |
| 16 | + </div> | |
| 17 | + {{ template "repo-subnav" . }} | |
| 18 | +</header> | |
| 19 | +{{- end }} | |
internal/web/templates/repo/issue_new.htmlmodified@@ -1,9 +1,9 @@ | ||
| 1 | 1 | {{ define "page" -}} |
| 2 | -<section class="shithub-issue-new"> | |
| 2 | +<section class="shithub-repo-page"> | |
| 3 | + {{ template "repo-header" . }} | |
| 4 | + <section class="shithub-issue-new"> | |
| 3 | 5 | <header class="shithub-issues-head"> |
| 4 | 6 | <h1> |
| 5 | - <a href="/{{ .Owner }}/{{ .Repo.Name }}">{{ .Owner }}/{{ .Repo.Name }}</a> | |
| 6 | - <span class="shithub-code-sep">/</span> | |
| 7 | 7 | <a href="/{{ .Owner }}/{{ .Repo.Name }}/issues">Issues</a> |
| 8 | 8 | <span class="shithub-code-sep">/</span> |
| 9 | 9 | New |
@@ -27,5 +27,6 @@ | ||
| 27 | 27 | <button type="submit" class="shithub-button shithub-button-primary">Submit new issue</button> |
| 28 | 28 | </div> |
| 29 | 29 | </form> |
| 30 | + </section> | |
| 30 | 31 | </section> |
| 31 | 32 | {{- end }} |
internal/web/templates/repo/issue_view.htmlmodified@@ -1,26 +1,28 @@ | ||
| 1 | 1 | {{ define "page" -}} |
| 2 | -<section class="shithub-issue-view"> | |
| 3 | - <header class="shithub-issue-view-head"> | |
| 4 | - <div class="shithub-issue-title-row"> | |
| 5 | - <h1 class="shithub-issue-title"> | |
| 6 | - <span>{{ .Issue.Title }}</span> | |
| 7 | - <span class="shithub-issue-num">#{{ .Issue.Number }}</span> | |
| 8 | - </h1> | |
| 9 | - <div class="shithub-issue-head-actions"> | |
| 10 | - <a href="/{{ .Owner }}/{{ .Repo.Name }}/issues/new" class="shithub-button shithub-button-primary">New issue</a> | |
| 2 | +<section class="shithub-repo-page"> | |
| 3 | + {{ template "repo-header" . }} | |
| 4 | + <section class="shithub-issue-view"> | |
| 5 | + <header class="shithub-issue-view-head"> | |
| 6 | + <div class="shithub-issue-title-row"> | |
| 7 | + <h1 class="shithub-issue-title"> | |
| 8 | + <span>{{ .Issue.Title }}</span> | |
| 9 | + <span class="shithub-issue-num">#{{ .Issue.Number }}</span> | |
| 10 | + </h1> | |
| 11 | + <div class="shithub-issue-head-actions"> | |
| 12 | + <a href="/{{ .Owner }}/{{ .Repo.Name }}/issues/new" class="shithub-button shithub-button-primary">New issue</a> | |
| 13 | + </div> | |
| 14 | + </div> | |
| 15 | + <div class="shithub-issue-meta"> | |
| 16 | + <span class="shithub-pill shithub-issues-state-{{ printf "%s" .Issue.State }}"> | |
| 17 | + {{ if eq (printf "%s" .Issue.State) "open" }}{{ octicon "issue-opened" }} Open{{ else }}{{ octicon "issue-closed" }} Closed{{ end }} | |
| 18 | + </span> | |
| 19 | + {{ if .AuthorName }}<a href="/{{ .AuthorName }}">{{ .AuthorName }}</a>{{ end }} | |
| 20 | + opened this issue | |
| 21 | + <time datetime="{{ .Issue.CreatedAt.Time.Format "2006-01-02T15:04:05Z" }}">{{ relativeTime .Issue.CreatedAt.Time }}</time> | |
| 22 | + · {{ .CommentCount }} comment{{ if ne .CommentCount 1 }}s{{ end }} | |
| 23 | + {{ if .Issue.Locked }}<span class="shithub-pill">{{ octicon "lock" }} locked</span>{{ end }} | |
| 11 | 24 | </div> |
| 12 | - </div> | |
| 13 | - <div class="shithub-issue-meta"> | |
| 14 | - <span class="shithub-pill shithub-issues-state-{{ printf "%s" .Issue.State }}"> | |
| 15 | - {{ if eq (printf "%s" .Issue.State) "open" }}{{ octicon "issue-opened" }} Open{{ else }}{{ octicon "issue-closed" }} Closed{{ end }} | |
| 16 | - </span> | |
| 17 | - {{ if .AuthorName }}<a href="/{{ .AuthorName }}">{{ .AuthorName }}</a>{{ end }} | |
| 18 | - opened this issue | |
| 19 | - <time datetime="{{ .Issue.CreatedAt.Time.Format "2006-01-02T15:04:05Z" }}">{{ relativeTime .Issue.CreatedAt.Time }}</time> | |
| 20 | - · {{ .CommentCount }} comment{{ if ne .CommentCount 1 }}s{{ end }} | |
| 21 | - {{ if .Issue.Locked }}<span class="shithub-pill">{{ octicon "lock" }} locked</span>{{ end }} | |
| 22 | - </div> | |
| 23 | - </header> | |
| 25 | + </header> | |
| 24 | 26 | |
| 25 | 27 | <div class="shithub-issue-grid"> |
| 26 | 28 | <article class="shithub-issue-thread"> |
@@ -243,5 +245,6 @@ | ||
| 243 | 245 | {{ end }} |
| 244 | 246 | </aside> |
| 245 | 247 | </div> |
| 248 | + </section> | |
| 246 | 249 | </section> |
| 247 | 250 | {{- end }} |
internal/web/templates/repo/issues_list.htmlmodified@@ -1,15 +1,7 @@ | ||
| 1 | 1 | {{ define "page" -}} |
| 2 | 2 | <section class="shithub-repo-page"> |
| 3 | - <header class="shithub-repo-page-head"> | |
| 4 | - <h1 class="shithub-repo-page-title"> | |
| 5 | - <a href="/{{ .Owner }}">{{ .Owner }}</a> | |
| 6 | - <span class="shithub-code-sep">/</span> | |
| 7 | - <a href="/{{ .Owner }}/{{ .Repo.Name }}">{{ .Repo.Name }}</a> | |
| 8 | - {{ if eq (printf "%s" .Repo.Visibility) "private" }}<span class="shithub-pill shithub-pill-private">private</span>{{ else }}<span class="shithub-pill">public</span>{{ end }} | |
| 9 | - </h1> | |
| 10 | - </header> | |
| 11 | - {{ template "repo-subnav" . }} | |
| 12 | -<section class="shithub-issues"> | |
| 3 | + {{ template "repo-header" . }} | |
| 4 | + <section class="shithub-issues"> | |
| 13 | 5 | <header class="shithub-issues-head"> |
| 14 | 6 | <h1>Issues</h1> |
| 15 | 7 | <div class="shithub-issues-actions"> |
internal/web/templates/repo/labels.htmlmodified@@ -1,9 +1,9 @@ | ||
| 1 | 1 | {{ define "page" -}} |
| 2 | -<section class="shithub-labels"> | |
| 2 | +<section class="shithub-repo-page"> | |
| 3 | + {{ template "repo-header" . }} | |
| 4 | + <section class="shithub-labels"> | |
| 3 | 5 | <header class="shithub-issues-head"> |
| 4 | 6 | <h1> |
| 5 | - <a href="/{{ .Owner }}/{{ .Repo.Name }}">{{ .Owner }}/{{ .Repo.Name }}</a> | |
| 6 | - <span class="shithub-code-sep">/</span> | |
| 7 | 7 | Labels |
| 8 | 8 | </h1> |
| 9 | 9 | </header> |
@@ -45,5 +45,6 @@ | ||
| 45 | 45 | </li> |
| 46 | 46 | {{ end }} |
| 47 | 47 | </ul> |
| 48 | + </section> | |
| 48 | 49 | </section> |
| 49 | 50 | {{- end }} |
internal/web/templates/repo/milestones.htmlmodified@@ -1,9 +1,9 @@ | ||
| 1 | 1 | {{ define "page" -}} |
| 2 | -<section class="shithub-milestones"> | |
| 2 | +<section class="shithub-repo-page"> | |
| 3 | + {{ template "repo-header" . }} | |
| 4 | + <section class="shithub-milestones"> | |
| 3 | 5 | <header class="shithub-issues-head"> |
| 4 | 6 | <h1> |
| 5 | - <a href="/{{ .Owner }}/{{ .Repo.Name }}">{{ .Owner }}/{{ .Repo.Name }}</a> | |
| 6 | - <span class="shithub-code-sep">/</span> | |
| 7 | 7 | Milestones |
| 8 | 8 | </h1> |
| 9 | 9 | </header> |
@@ -48,5 +48,6 @@ | ||
| 48 | 48 | </li> |
| 49 | 49 | {{ end }} |
| 50 | 50 | </ul> |
| 51 | + </section> | |
| 51 | 52 | </section> |
| 52 | 53 | {{- end }} |
internal/web/templates/repo/tree.htmlmodified@@ -1,99 +1,117 @@ | ||
| 1 | 1 | {{ define "page" -}} |
| 2 | 2 | <section class="shithub-repo-page"> |
| 3 | - <header class="shithub-repo-page-head"> | |
| 4 | - <h1 class="shithub-repo-page-title"> | |
| 5 | - <a href="/{{ .Owner }}">{{ .Owner }}</a> | |
| 6 | - <span class="shithub-code-sep">/</span> | |
| 7 | - <a href="/{{ .Owner }}/{{ .Repo.Name }}">{{ .Repo.Name }}</a> | |
| 8 | - {{ if eq (printf "%s" .Repo.Visibility) "private" }}<span class="shithub-pill shithub-pill-private">private</span>{{ else }}<span class="shithub-pill">public</span>{{ end }} | |
| 9 | - </h1> | |
| 10 | - </header> | |
| 11 | - {{ template "repo-subnav" . }} | |
| 3 | + {{ template "repo-header" . }} | |
| 12 | 4 | |
| 13 | -<section class="shithub-code"> | |
| 14 | - <header class="shithub-code-head"> | |
| 15 | - <nav class="shithub-code-crumbs" aria-label="Breadcrumb"> | |
| 16 | - {{ range $i, $c := .Crumbs }} | |
| 17 | - {{ if $i }}<span class="shithub-code-sep">/</span>{{ end }} | |
| 18 | - <a href="{{ $c.URL }}">{{ $c.Name }}</a> | |
| 19 | - {{ end }} | |
| 20 | - </nav> | |
| 21 | - <div class="shithub-code-actions"> | |
| 22 | - <details class="shithub-ref-switcher"> | |
| 23 | - <summary>{{ .Ref }}</summary> | |
| 24 | - <div class="shithub-ref-panel"> | |
| 25 | - {{ if .Branches }} | |
| 26 | - <strong>Branches</strong> | |
| 27 | - {{ range .Branches }} | |
| 28 | - <a href="/{{ $.Owner }}/{{ $.Repo.Name }}/tree/{{ .Name }}">{{ .Name }}</a> | |
| 29 | - {{ end }} | |
| 30 | - {{ end }} | |
| 31 | - {{ if .Tags }} | |
| 32 | - <strong>Tags</strong> | |
| 33 | - {{ range .Tags }} | |
| 34 | - <a href="/{{ $.Owner }}/{{ $.Repo.Name }}/tree/{{ .Name }}">{{ .Name }}</a> | |
| 35 | - {{ end }} | |
| 5 | + <div class="shithub-repo-content-grid"> | |
| 6 | + <main class="shithub-repo-main"> | |
| 7 | + <section class="shithub-code"> | |
| 8 | + <header class="shithub-code-head"> | |
| 9 | + <div class="shithub-code-primary-actions"> | |
| 10 | + <details class="shithub-ref-switcher"> | |
| 11 | + <summary>{{ octicon "git-branch" }} {{ .Ref }}</summary> | |
| 12 | + <div class="shithub-ref-panel"> | |
| 13 | + {{ if .Branches }} | |
| 14 | + <strong>Branches</strong> | |
| 15 | + {{ range .Branches }} | |
| 16 | + <a href="/{{ $.Owner }}/{{ $.Repo.Name }}/tree/{{ .Name }}">{{ .Name }}</a> | |
| 17 | + {{ end }} | |
| 18 | + {{ end }} | |
| 19 | + {{ if .Tags }} | |
| 20 | + <strong>Tags</strong> | |
| 21 | + {{ range .Tags }} | |
| 22 | + <a href="/{{ $.Owner }}/{{ $.Repo.Name }}/tree/{{ .Name }}">{{ .Name }}</a> | |
| 23 | + {{ end }} | |
| 24 | + {{ end }} | |
| 25 | + </div> | |
| 26 | + </details> | |
| 27 | + <a href="/{{ .Owner }}/{{ .Repo.Name }}/branches" class="shithub-code-count">{{ octicon "git-branch" }} {{ len .Branches }} Branches</a> | |
| 28 | + <a href="/{{ .Owner }}/{{ .Repo.Name }}/tags" class="shithub-code-count">{{ octicon "tag" }} {{ len .Tags }} Tags</a> | |
| 29 | + </div> | |
| 30 | + <div class="shithub-code-actions"> | |
| 31 | + <a href="/{{ .Owner }}/{{ .Repo.Name }}/find/{{ .Ref }}" class="shithub-button">Go to file</a> | |
| 32 | + <details class="shithub-clone-dropdown"> | |
| 33 | + <summary class="shithub-button shithub-button-primary">{{ octicon "code" }} Code</summary> | |
| 34 | + <div class="shithub-clone-panel" role="dialog" aria-label="Clone this repository"> | |
| 35 | + <div class="shithub-clone-row"> | |
| 36 | + <label for="clone-https">Clone with HTTPS</label> | |
| 37 | + <div class="shithub-clone-input"> | |
| 38 | + <input id="clone-https" type="text" readonly value="{{ .HTTPSCloneURL }}" onclick="this.select()"> | |
| 39 | + <button type="button" class="shithub-button" data-clone-copy="#clone-https" title="Copy">{{ octicon "copy" }}</button> | |
| 40 | + </div> | |
| 41 | + </div> | |
| 42 | + {{ if .SSHEnabled }} | |
| 43 | + <div class="shithub-clone-row"> | |
| 44 | + <label for="clone-ssh">Clone with SSH</label> | |
| 45 | + <div class="shithub-clone-input"> | |
| 46 | + <input id="clone-ssh" type="text" readonly value="{{ .SSHCloneURL }}" onclick="this.select()"> | |
| 47 | + <button type="button" class="shithub-button" data-clone-copy="#clone-ssh" title="Copy">{{ octicon "copy" }}</button> | |
| 48 | + </div> | |
| 49 | + </div> | |
| 50 | + {{ end }} | |
| 51 | + <p class="shithub-clone-hint">Use Git or checkout with SVN using the web URL.</p> | |
| 52 | + </div> | |
| 53 | + </details> | |
| 54 | + </div> | |
| 55 | + </header> | |
| 56 | + | |
| 57 | + {{ if .Path }} | |
| 58 | + <nav class="shithub-code-crumbs" aria-label="Breadcrumb"> | |
| 59 | + {{ range $i, $c := .Crumbs }} | |
| 60 | + {{ if $i }}<span class="shithub-code-sep">/</span>{{ end }} | |
| 61 | + <a href="{{ $c.URL }}">{{ $c.Name }}</a> | |
| 36 | 62 | {{ end }} |
| 37 | - </div> | |
| 38 | - </details> | |
| 39 | - <a href="/{{ .Owner }}/{{ .Repo.Name }}/find/{{ .Ref }}" class="shithub-button">Go to file</a> | |
| 40 | - <details class="shithub-clone-dropdown"> | |
| 41 | - <summary class="shithub-button shithub-button-primary">{{ octicon "download" }} Code</summary> | |
| 42 | - <div class="shithub-clone-panel" role="dialog" aria-label="Clone this repository"> | |
| 43 | - <div class="shithub-clone-row"> | |
| 44 | - <label for="clone-https">Clone with HTTPS</label> | |
| 45 | - <div class="shithub-clone-input"> | |
| 46 | - <input id="clone-https" type="text" readonly value="{{ .HTTPSCloneURL }}" onclick="this.select()"> | |
| 47 | - <button type="button" class="shithub-button" data-clone-copy="#clone-https" title="Copy">{{ octicon "copy" }}</button> | |
| 63 | + </nav> | |
| 64 | + {{ end }} | |
| 65 | + | |
| 66 | + <div class="shithub-tree-panel"> | |
| 67 | + {{ if .HeadFound }} | |
| 68 | + <div class="shithub-tree-commit"> | |
| 69 | + <div class="shithub-tree-commit-message"> | |
| 70 | + <strong>{{ .Head.AuthorName }}</strong> | |
| 71 | + <span>{{ .Head.Subject }}</span> | |
| 48 | 72 | </div> |
| 49 | - </div> | |
| 50 | - {{ if .SSHEnabled }} | |
| 51 | - <div class="shithub-clone-row"> | |
| 52 | - <label for="clone-ssh">Clone with SSH</label> | |
| 53 | - <div class="shithub-clone-input"> | |
| 54 | - <input id="clone-ssh" type="text" readonly value="{{ .SSHCloneURL }}" onclick="this.select()"> | |
| 55 | - <button type="button" class="shithub-button" data-clone-copy="#clone-ssh" title="Copy">{{ octicon "copy" }}</button> | |
| 73 | + <div class="shithub-tree-commit-meta"> | |
| 74 | + <code title="{{ .Head.OID }}">{{ slice .Head.OID 0 7 }}</code> | |
| 75 | + <time datetime="{{ .Head.AuthorWhen.Format "2006-01-02T15:04:05Z" }}">{{ relativeTime .Head.AuthorWhen }}</time> | |
| 56 | 76 | </div> |
| 57 | 77 | </div> |
| 58 | 78 | {{ end }} |
| 59 | - <p class="shithub-clone-hint">Use Git or checkout with SVN using the web URL.</p> | |
| 79 | + <table class="shithub-tree"> | |
| 80 | + <tbody> | |
| 81 | + {{ range .Entries }} | |
| 82 | + <tr> | |
| 83 | + <td class="shithub-tree-icon" aria-hidden="true"> | |
| 84 | + {{ if eq (printf "%s" .Kind) "tree" }}{{ octicon "directory" }} | |
| 85 | + {{ else if eq (printf "%s" .Kind) "commit" }}{{ octicon "submodule" }} | |
| 86 | + {{ else if eq (printf "%s" .Kind) "symlink" }}{{ octicon "symlink" }} | |
| 87 | + {{ else }}{{ octicon "file" }}{{ end }} | |
| 88 | + </td> | |
| 89 | + <td class="shithub-tree-name"> | |
| 90 | + {{ if eq (printf "%s" .Kind) "tree" }} | |
| 91 | + <a href="/{{ $.Owner }}/{{ $.Repo.Name }}/tree/{{ $.Ref }}/{{ if $.Path }}{{ $.Path }}/{{ end }}{{ .Name }}">{{ .Name }}</a> | |
| 92 | + {{ else if eq (printf "%s" .Kind) "blob" }} | |
| 93 | + <a href="/{{ $.Owner }}/{{ $.Repo.Name }}/blob/{{ $.Ref }}/{{ if $.Path }}{{ $.Path }}/{{ end }}{{ .Name }}">{{ .Name }}</a> | |
| 94 | + {{ else if eq (printf "%s" .Kind) "symlink" }} | |
| 95 | + {{ .Name }} <em class="shithub-tree-symlink">(symlink)</em> | |
| 96 | + {{ else }} | |
| 97 | + {{ .Name }} <em class="shithub-tree-submodule">@ {{ slice .OID 0 7 }}</em> | |
| 98 | + {{ end }} | |
| 99 | + </td> | |
| 100 | + <td class="shithub-tree-size">{{ if gt .Size 0 }}{{ .Size }}{{ end }}</td> | |
| 101 | + </tr> | |
| 102 | + {{ end }} | |
| 103 | + </tbody> | |
| 104 | + </table> | |
| 60 | 105 | </div> |
| 61 | - </details> | |
| 62 | - </div> | |
| 63 | - </header> | |
| 64 | - | |
| 65 | - <table class="shithub-tree"> | |
| 66 | - <tbody> | |
| 67 | - {{ range .Entries }} | |
| 68 | - <tr> | |
| 69 | - <td class="shithub-tree-icon" aria-hidden="true"> | |
| 70 | - {{ if eq (printf "%s" .Kind) "tree" }}{{ octicon "directory" }} | |
| 71 | - {{ else if eq (printf "%s" .Kind) "commit" }}{{ octicon "submodule" }} | |
| 72 | - {{ else if eq (printf "%s" .Kind) "symlink" }}{{ octicon "symlink" }} | |
| 73 | - {{ else }}{{ octicon "file" }}{{ end }} | |
| 74 | - </td> | |
| 75 | - <td class="shithub-tree-name"> | |
| 76 | - {{ if eq (printf "%s" .Kind) "tree" }} | |
| 77 | - <a href="/{{ $.Owner }}/{{ $.Repo.Name }}/tree/{{ $.Ref }}/{{ if $.Path }}{{ $.Path }}/{{ end }}{{ .Name }}">{{ .Name }}</a> | |
| 78 | - {{ else if eq (printf "%s" .Kind) "blob" }} | |
| 79 | - <a href="/{{ $.Owner }}/{{ $.Repo.Name }}/blob/{{ $.Ref }}/{{ if $.Path }}{{ $.Path }}/{{ end }}{{ .Name }}">{{ .Name }}</a> | |
| 80 | - {{ else if eq (printf "%s" .Kind) "symlink" }} | |
| 81 | - {{ .Name }} <em class="shithub-tree-symlink">(symlink)</em> | |
| 82 | - {{ else }} | |
| 83 | - {{ .Name }} <em class="shithub-tree-submodule">@ {{ slice .OID 0 7 }}</em> | |
| 84 | - {{ end }} | |
| 85 | - </td> | |
| 86 | - <td class="shithub-tree-size">{{ if gt .Size 0 }}{{ .Size }}{{ end }}</td> | |
| 87 | - </tr> | |
| 106 | + </section> | |
| 107 | + {{ if .README }} | |
| 108 | + <section class="shithub-readme markdown-body" id="readme" aria-label="README"> | |
| 109 | + <div class="shithub-readme-head">{{ octicon "book" }} README</div> | |
| 110 | + <div class="shithub-readme-body">{{ .README }}</div> | |
| 111 | + </section> | |
| 88 | 112 | {{ end }} |
| 89 | - </tbody> | |
| 90 | - </table> | |
| 91 | - | |
| 92 | - </section> | |
| 93 | - {{ if .README }} | |
| 94 | - <section class="shithub-readme" aria-label="README"> | |
| 95 | - {{ .README }} | |
| 96 | - </section> | |
| 97 | - {{ end }} | |
| 113 | + </main> | |
| 114 | + {{ template "repo-about-sidebar" . }} | |
| 115 | + </div> | |
| 98 | 116 | </section> |
| 99 | 117 | {{- end }} |