tenseleyflow/shithub / c4e73d4

Browse files

Align PR conversation layout

Authored by espadonne
SHA
c4e73d406f1716c9ea287532e8ec9a5294526c4c
Parents
8c78ecd
Tree
64d424d

4 changed files

StatusFile+-
M internal/web/handlers/repo/pulls.go 33 7
M internal/web/render/octicons.go 10 0
M internal/web/static/css/shithub.css 314 41
M internal/web/templates/repo/pull_view.html 198 105
internal/web/handlers/repo/pulls.gomodified
@@ -3,6 +3,7 @@
33
 package repo
44
 
55
 import (
6
+	"context"
67
 	"encoding/json"
78
 	"errors"
89
 	"html/template"
@@ -272,14 +273,23 @@ func (h *Handlers) renderPullPage(w http.ResponseWriter, r *http.Request, tab st
272273
 			authorName = u.Username
273274
 		}
274275
 	}
276
+	mergedByName := ""
277
+	if pr.MergedByUserID.Valid {
278
+		if u, err := h.uq.GetUserByID(r.Context(), h.d.Pool, pr.MergedByUserID.Int64); err == nil {
279
+			mergedByName = u.Username
280
+		}
281
+	}
282
+	stats := h.pullTabStats(r.Context(), pr.IID)
275283
 	data := map[string]any{
276
-		"Title":      "#" + strconv.FormatInt(pr.INumber, 10) + " " + pr.ITitle + " · " + row.Name,
277
-		"Owner":      owner.Username,
278
-		"Repo":       row,
279
-		"PR":         pr,
280
-		"AuthorName": authorName,
281
-		"Tab":        tab,
282
-		"CSRFToken":  middleware.CSRFTokenForRequest(r),
284
+		"Title":        "#" + strconv.FormatInt(pr.INumber, 10) + " " + pr.ITitle + " · " + row.Name,
285
+		"Owner":        owner.Username,
286
+		"Repo":         row,
287
+		"PR":           pr,
288
+		"AuthorName":   authorName,
289
+		"MergedByName": mergedByName,
290
+		"PullStats":    stats,
291
+		"Tab":          tab,
292
+		"CSRFToken":    middleware.CSRFTokenForRequest(r),
283293
 	}
284294
 	viewer := middleware.CurrentUserFromContext(r.Context())
285295
 	actor := policy.UserActor(viewer.ID, viewer.Username, viewer.IsSuspended, false)
@@ -300,6 +310,22 @@ func (h *Handlers) renderPullPage(w http.ResponseWriter, r *http.Request, tab st
300310
 	_ = h.d.Render.RenderPage(w, r, "repo/pull_view", data)
301311
 }
302312
 
313
+type pullTabStats struct {
314
+	Commits int
315
+	Files   int
316
+}
317
+
318
+func (h *Handlers) pullTabStats(ctx context.Context, prID int64) pullTabStats {
319
+	var out pullTabStats
320
+	if commits, err := h.pq.ListPullRequestCommits(ctx, h.d.Pool, prID); err == nil {
321
+		out.Commits = len(commits)
322
+	}
323
+	if files, err := h.pq.ListPullRequestFiles(ctx, h.d.Pool, prID); err == nil {
324
+		out.Files = len(files)
325
+	}
326
+	return out
327
+}
328
+
303329
 // pullView renders the Conversation tab.
304330
 func (h *Handlers) pullView(w http.ResponseWriter, r *http.Request) {
305331
 	// Resolve to grab issue id for comments+events.
internal/web/render/octicons.gomodified
@@ -45,6 +45,10 @@ func BuiltinOcticons() OcticonResolver {
4545
 			`><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>`),
4646
 		"git-pull-request": trustedSVG(`<svg xmlns="http://www.w3.org/2000/svg" ` + cls +
4747
 			`><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>`),
48
+		"git-merge": trustedSVG(`<svg xmlns="http://www.w3.org/2000/svg" ` + cls +
49
+			`><path d="M5.45 5.154A4.25 4.25 0 0 0 9.25 7.5h1.378a2.251 2.251 0 1 1 0 1.5H9.25A5.734 5.734 0 0 1 5 7.123v3.505a2.25 2.25 0 1 1-1.5 0V5.372a2.25 2.25 0 1 1 1.95-.218ZM4.25 13.5a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5Zm8.5-4.5a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5ZM5 3.25a.75.75 0 1 0 0 .005V3.25Z"/></svg>`),
50
+		"git-commit": trustedSVG(`<svg xmlns="http://www.w3.org/2000/svg" ` + cls +
51
+			`><path d="M11.93 8.5a4.002 4.002 0 0 1-7.86 0H.75a.75.75 0 0 1 0-1.5h3.32a4.002 4.002 0 0 1 7.86 0h3.32a.75.75 0 0 1 0 1.5Zm-1.43-.75a2.5 2.5 0 1 0-5 0 2.5 2.5 0 0 0 5 0Z"/></svg>`),
4852
 		"git-branch": trustedSVG(`<svg xmlns="http://www.w3.org/2000/svg" ` + cls +
4953
 			`><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>`),
5054
 		"repo-forked": trustedSVG(`<svg xmlns="http://www.w3.org/2000/svg" ` + cls +
@@ -63,6 +67,12 @@ func BuiltinOcticons() OcticonResolver {
6367
 			`><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 8Zm11.03-1.78a.75.75 0 0 1 0 1.06l-3.25 3.25a.75.75 0 0 1-1.06 0L4.97 8.78a.75.75 0 0 1 1.06-1.06l1.22 1.22 2.72-2.72a.75.75 0 0 1 1.06 0Z"/></svg>`),
6468
 		"comment": trustedSVG(`<svg xmlns="http://www.w3.org/2000/svg" ` + cls +
6569
 			`><path d="M1 2.75C1 1.784 1.784 1 2.75 1h10.5c.966 0 1.75.784 1.75 1.75v6.5A1.75 1.75 0 0 1 13.25 11H8.06l-3.31 2.48A.75.75 0 0 1 3.5 12.88V11h-.75A1.75 1.75 0 0 1 1 9.25Zm1.75-.25a.25.25 0 0 0-.25.25v6.5c0 .138.112.25.25.25h1.5a.75.75 0 0 1 .75.75v1.13l2.36-1.77a.75.75 0 0 1 .45-.15h5.44a.25.25 0 0 0 .25-.25v-6.5a.25.25 0 0 0-.25-.25Z"/></svg>`),
70
+		"comment-discussion": trustedSVG(`<svg xmlns="http://www.w3.org/2000/svg" ` + cls +
71
+			`><path d="M1.75 1h8.5c.966 0 1.75.784 1.75 1.75v5.5A1.75 1.75 0 0 1 10.25 10H7.061l-2.574 2.573A1.458 1.458 0 0 1 2 11.543V10h-.25A1.75 1.75 0 0 1 0 8.25v-5.5C0 1.784.784 1 1.75 1ZM1.5 2.75v5.5c0 .138.112.25.25.25h1a.75.75 0 0 1 .75.75v2.19l2.72-2.72a.749.749 0 0 1 .53-.22h3.5a.25.25 0 0 0 .25-.25v-5.5a.25.25 0 0 0-.25-.25h-8.5a.25.25 0 0 0-.25.25Zm13 2a.25.25 0 0 0-.25-.25h-.5a.75.75 0 0 1 0-1.5h.5c.966 0 1.75.784 1.75 1.75v5.5A1.75 1.75 0 0 1 14.25 12H14v1.543a1.458 1.458 0 0 1-2.487 1.03L9.22 12.28a.749.749 0 0 1 .326-1.275.749.749 0 0 1 .734.215l2.22 2.22v-2.19a.75.75 0 0 1 .75-.75h1a.25.25 0 0 0 .25-.25Z"/></svg>`),
72
+		"checklist": trustedSVG(`<svg xmlns="http://www.w3.org/2000/svg" ` + cls +
73
+			`><path d="M2.5 1.75v11.5c0 .138.112.25.25.25h3.17a.75.75 0 0 1 0 1.5H2.75A1.75 1.75 0 0 1 1 13.25V1.75C1 .784 1.784 0 2.75 0h8.5C12.216 0 13 .784 13 1.75v7.736a.75.75 0 0 1-1.5 0V1.75a.25.25 0 0 0-.25-.25h-8.5a.25.25 0 0 0-.25.25Zm13.274 9.537v-.001l-4.557 4.45a.75.75 0 0 1-1.055-.008l-1.943-1.95a.75.75 0 0 1 1.062-1.058l1.419 1.425 4.026-3.932a.75.75 0 1 1 1.048 1.074ZM4.75 4h4.5a.75.75 0 0 1 0 1.5h-4.5a.75.75 0 0 1 0-1.5ZM4 7.75A.75.75 0 0 1 4.75 7h2a.75.75 0 0 1 0 1.5h-2A.75.75 0 0 1 4 7.75Z"/></svg>`),
74
+		"file-diff": trustedSVG(`<svg xmlns="http://www.w3.org/2000/svg" ` + cls +
75
+			`><path d="M1 1.75C1 .784 1.784 0 2.75 0h7.586c.464 0 .909.184 1.237.513l2.914 2.914c.329.328.513.773.513 1.237v9.586A1.75 1.75 0 0 1 13.25 16H2.75A1.75 1.75 0 0 1 1 14.25Zm1.75-.25a.25.25 0 0 0-.25.25v12.5c0 .138.112.25.25.25h10.5a.25.25 0 0 0 .25-.25V4.664a.25.25 0 0 0-.073-.177l-2.914-2.914a.25.25 0 0 0-.177-.073ZM8 3.25a.75.75 0 0 1 .75.75v1.5h1.5a.75.75 0 0 1 0 1.5h-1.5v1.5a.75.75 0 0 1-1.5 0V7h-1.5a.75.75 0 0 1 0-1.5h1.5V4A.75.75 0 0 1 8 3.25Zm-3 8a.75.75 0 0 1 .75-.75h4.5a.75.75 0 0 1 0 1.5h-4.5a.75.75 0 0 1-.75-.75Z"/></svg>`),
6676
 		"history": trustedSVG(`<svg xmlns="http://www.w3.org/2000/svg" ` + cls +
6777
 			`><path d="M1.643 3.143.427 1.927A.25.25 0 0 0 0 2.104V5.75c0 .138.112.25.25.25h3.646a.25.25 0 0 0 .177-.427L2.715 4.215A6.5 6.5 0 1 1 8 14.5a.75.75 0 0 0 0 1.5 8 8 0 1 0-6.357-12.857ZM7.25 4.75a.75.75 0 0 1 1.5 0v3.19l2.03 2.03a.75.75 0 1 1-1.06 1.06L7.47 8.78a.75.75 0 0 1-.22-.53Z"/></svg>`),
6878
 		"gear": trustedSVG(`<svg xmlns="http://www.w3.org/2000/svg" ` + cls +
internal/web/static/css/shithub.cssmodified
@@ -2908,71 +2908,310 @@ button.shithub-repo-action {
29082908
 .shithub-muted { color: var(--fg-muted); }
29092909
 
29102910
 /* ========== Pull Requests (S22) ========== */
2911
-.shithub-pulls, .shithub-pull-view {
2911
+.shithub-pulls {
29122912
   max-width: 64rem;
29132913
   margin: 1.5rem auto;
29142914
   padding: 0 1rem;
29152915
 }
2916
-.shithub-pull-head { margin-bottom: 0.75rem; }
2917
-.shithub-pull-merged { background: #8250df22; color: #8250df; }
2916
+.shithub-pull-view {
2917
+  max-width: 80rem;
2918
+  margin: 1.25rem auto 2rem;
2919
+  padding: 0 1rem;
2920
+}
2921
+.shithub-pull-head {
2922
+  margin-bottom: 0.75rem;
2923
+}
2924
+.shithub-pull-head h1 {
2925
+  margin: 0 0 0.45rem;
2926
+  font-size: 1.625rem;
2927
+  font-weight: 400;
2928
+  line-height: 1.25;
2929
+}
2930
+.shithub-pull-head h1 span:first-child {
2931
+  font-weight: 400;
2932
+}
2933
+.shithub-pull-summary {
2934
+  display: flex;
2935
+  align-items: center;
2936
+  gap: 0.5rem;
2937
+  flex-wrap: wrap;
2938
+  color: var(--fg-muted);
2939
+  font-size: 0.875rem;
2940
+}
2941
+.shithub-pull-state-label {
2942
+  display: inline-flex;
2943
+  align-items: center;
2944
+  gap: 0.35rem;
2945
+  padding: 0.32rem 0.75rem;
2946
+  border-radius: 999px;
2947
+  color: #fff;
2948
+  font-weight: 600;
2949
+  line-height: 1;
2950
+}
2951
+.shithub-pull-state-label.is-open { background: #1a7f37; }
2952
+.shithub-pull-state-label.is-draft { background: #6e7781; }
2953
+.shithub-pull-state-label.is-closed { background: #cf222e; }
2954
+.shithub-pull-state-label.is-merged { background: #8250df; }
2955
+.shithub-branch-name {
2956
+  display: inline-flex;
2957
+  align-items: center;
2958
+  max-width: 18rem;
2959
+  padding: 0.08rem 0.35rem;
2960
+  border-radius: 6px;
2961
+  background: var(--accent-subtle, #ddf4ff);
2962
+  color: var(--accent-fg, #0969da);
2963
+  font-family: var(--mono, ui-monospace, SFMono-Regular, Menlo, Consolas, monospace);
2964
+  font-size: 0.8rem;
2965
+  white-space: nowrap;
2966
+  overflow: hidden;
2967
+  text-overflow: ellipsis;
2968
+  vertical-align: middle;
2969
+}
29182970
 .shithub-pull-tabs {
2919
-  display: flex; gap: 1.5rem;
2971
+  display: flex;
2972
+  align-items: flex-end;
2973
+  gap: 0.25rem;
29202974
   border-bottom: 1px solid var(--border-default);
2921
-  margin: 0.75rem 0 1rem;
2975
+  margin: 1rem 0 1.5rem;
2976
+  overflow-x: auto;
29222977
 }
29232978
 .shithub-pull-tab {
2924
-  color: var(--fg-muted);
2925
-  padding: 0.4rem 0;
2979
+  display: inline-flex;
2980
+  align-items: center;
2981
+  gap: 0.38rem;
2982
+  min-height: 3rem;
2983
+  padding: 0.75rem 1rem;
29262984
   border-bottom: 2px solid transparent;
2985
+  color: var(--fg-muted);
2986
+  font-size: 0.875rem;
2987
+  white-space: nowrap;
29272988
 }
29282989
 .shithub-pull-tab-active {
29292990
   color: var(--fg-default);
2930
-  border-bottom-color: var(--accent-emphasis, #0969da);
2991
+  border-bottom-color: #fd8c73;
29312992
   font-weight: 600;
29322993
 }
2933
-.shithub-pull-grid { display: grid; grid-template-columns: 1fr 16rem; gap: 1.5rem; }
2934
-@media (max-width: 768px) { .shithub-pull-grid { grid-template-columns: 1fr; } }
2935
-.shithub-pull-merge { padding: 0.75rem; border: 1px solid var(--border-default); border-radius: 6px; }
2936
-.shithub-pull-merge h3 { font-size: 0.85rem; text-transform: uppercase; color: var(--fg-muted); margin: 0 0 0.5rem; }
2937
-.shithub-pull-state-clean { color: #1a7f37; font-weight: 600; }
2938
-.shithub-pull-state-dirty { color: #cf222e; font-weight: 600; }
2939
-.shithub-pull-state-behind { color: #9a6700; }
2940
-.shithub-pull-state-unknown { color: var(--fg-muted); }
2941
-.shithub-pull-merge-form { display: flex; flex-direction: column; gap: 0.5rem; margin-bottom: 0.5rem; }
2942
-.shithub-pull-merge-form select { padding: 0.4rem; border: 1px solid var(--border-default); border-radius: 6px; font: inherit; }
2943
-.shithub-pull-state-form { margin-top: 0.5rem; }
2944
-.shithub-pull-refs { display: flex; gap: 0.4rem; align-items: flex-end; }
2945
-.shithub-pull-refs label { flex: 1; }
2946
-.shithub-pull-arrow { font-size: 1.4rem; padding: 0 0.4rem; align-self: center; }
2947
-.shithub-pull-commits { list-style: none; padding: 0; }
2948
-.shithub-pull-commits li {
2949
-  padding: 0.4rem 0; border-bottom: 1px solid var(--border-default);
2950
-  display: flex; gap: 0.6rem; align-items: baseline;
2994
+.shithub-tab-count {
2995
+  display: inline-flex;
2996
+  align-items: center;
2997
+  justify-content: center;
2998
+  min-width: 1.25rem;
2999
+  height: 1.25rem;
3000
+  padding: 0 0.4rem;
3001
+  border-radius: 999px;
3002
+  background: var(--neutral-muted, #afb8c133);
3003
+  color: var(--fg-default);
3004
+  font-size: 0.75rem;
3005
+  font-weight: 500;
29513006
 }
2952
-
2953
-/* ========== PR Reviews (S23) ========== */
2954
-.shithub-pull-reviews, .shithub-pull-reviewers {
3007
+.shithub-pull-conversation-layout {
3008
+  display: grid;
3009
+  grid-template-columns: minmax(0, 1fr) 18.5rem;
3010
+  gap: 2rem;
3011
+  align-items: start;
3012
+}
3013
+.shithub-pull-conversation-main {
3014
+  min-width: 0;
3015
+}
3016
+.shithub-pull-timeline {
3017
+  position: relative;
3018
+  padding-left: 2.5rem;
3019
+}
3020
+.shithub-pull-timeline::before {
3021
+  content: "";
3022
+  position: absolute;
3023
+  top: 2rem;
3024
+  bottom: -1rem;
3025
+  left: 1rem;
3026
+  width: 2px;
3027
+  background: var(--border-default);
3028
+}
3029
+.shithub-pull-timeline-item {
3030
+  position: relative;
3031
+  margin-bottom: 1rem;
3032
+}
3033
+.shithub-pull-timeline-marker {
3034
+  position: absolute;
3035
+  top: 0.45rem;
3036
+  left: -2.5rem;
3037
+  z-index: 1;
3038
+  display: inline-flex;
3039
+  align-items: center;
3040
+  justify-content: center;
3041
+  width: 2rem;
3042
+  height: 2rem;
3043
+  border: 2px solid var(--canvas-default);
3044
+  border-radius: 50%;
3045
+  background: var(--canvas-subtle);
3046
+  color: var(--fg-muted);
3047
+}
3048
+.shithub-pull-comment {
3049
+  width: 100%;
3050
+}
3051
+.shithub-pull-timeline-event {
3052
+  position: relative;
3053
+  display: flex;
3054
+  align-items: center;
3055
+  gap: 0.4rem;
3056
+  margin: 0.65rem 0 0.65rem -0.55rem;
3057
+  color: var(--fg-muted);
3058
+  font-size: 0.875rem;
3059
+}
3060
+.shithub-pull-timeline-dot {
3061
+  position: relative;
3062
+  z-index: 1;
3063
+  display: inline-flex;
3064
+  align-items: center;
3065
+  justify-content: center;
3066
+  width: 1rem;
3067
+  height: 1rem;
3068
+  border: 2px solid var(--canvas-default);
3069
+  border-radius: 50%;
3070
+  background: var(--canvas-default);
3071
+  color: var(--border-default);
3072
+}
3073
+.shithub-pull-merge-box {
3074
+  margin: 1rem 0 0 2.5rem;
3075
+  border: 1px solid var(--border-default);
3076
+  border-radius: 6px;
3077
+  background: var(--canvas-default);
3078
+}
3079
+.shithub-pull-merge-box-head {
3080
+  display: flex;
3081
+  gap: 0.8rem;
3082
+  padding: 1rem;
3083
+}
3084
+.shithub-pull-merge-box h2 {
3085
+  margin: 0 0 0.2rem;
3086
+  font-size: 1rem;
3087
+  line-height: 1.35;
3088
+}
3089
+.shithub-pull-merge-box p {
3090
+  margin: 0;
3091
+  color: var(--fg-muted);
3092
+  font-size: 0.875rem;
3093
+}
3094
+.shithub-pull-merge-icon {
3095
+  display: inline-flex;
3096
+  align-items: center;
3097
+  justify-content: center;
3098
+  flex: 0 0 auto;
3099
+  width: 2rem;
3100
+  height: 2rem;
3101
+  border-radius: 50%;
3102
+  color: #fff;
3103
+}
3104
+.shithub-pull-merge-icon.is-clean,
3105
+.shithub-pull-merge-icon.is-merged { background: #1a7f37; }
3106
+.shithub-pull-merge-icon.is-dirty,
3107
+.shithub-pull-merge-icon.is-closed { background: #cf222e; }
3108
+.shithub-pull-merge-icon.is-behind,
3109
+.shithub-pull-merge-icon.is-blocked { background: #9a6700; }
3110
+.shithub-pull-merge-icon.is-unknown { background: #6e7781; }
3111
+.shithub-pull-merge-state-dirty { border-color: #ffcecb; }
3112
+.shithub-pull-merge-state-blocked,
3113
+.shithub-pull-merge-state-behind { border-color: #d4a72c66; }
3114
+.shithub-pull-merge-actions {
3115
+  display: flex;
3116
+  align-items: center;
3117
+  gap: 0.5rem;
3118
+  flex-wrap: wrap;
3119
+  padding: 0.75rem 1rem;
3120
+  border-top: 1px solid var(--border-default);
3121
+  background: var(--canvas-subtle);
3122
+  border-radius: 0 0 6px 6px;
3123
+}
3124
+.shithub-pull-merge-form {
3125
+  display: flex;
3126
+  gap: 0.5rem;
3127
+  flex-wrap: wrap;
3128
+}
3129
+.shithub-pull-merge-form select {
3130
+  min-width: 13rem;
3131
+  padding: 0.35rem 0.5rem;
3132
+  border: 1px solid var(--border-default);
3133
+  border-radius: 6px;
3134
+  background: var(--canvas-default);
3135
+  color: var(--fg-default);
3136
+  font: inherit;
3137
+}
3138
+.shithub-pull-state-form {
3139
+  margin: 0;
3140
+}
3141
+.shithub-pull-sidebar {
3142
+  min-width: 0;
3143
+  color: var(--fg-muted);
3144
+  font-size: 0.875rem;
3145
+}
3146
+.shithub-pull-sidebar-section {
3147
+  padding: 1rem 0;
29553148
   border-top: 1px solid var(--border-default);
2956
-  padding: 0.6rem 0;
29573149
 }
2958
-.shithub-pull-reviews h3, .shithub-pull-reviewers h3 {
2959
-  font-size: 0.85rem; text-transform: uppercase; color: var(--fg-muted); margin: 0 0 0.4rem;
3150
+.shithub-pull-sidebar-section:first-child {
3151
+  padding-top: 0;
3152
+  border-top: 0;
3153
+}
3154
+.shithub-pull-sidebar-section h3 {
3155
+  margin: 0 0 0.45rem;
3156
+  color: var(--fg-default);
3157
+  font-size: 0.875rem;
3158
+  font-weight: 600;
3159
+}
3160
+.shithub-pull-sidebar-section p {
3161
+  margin: 0;
3162
+}
3163
+.shithub-pull-sidebar-list,
3164
+.shithub-pull-reviews-list {
3165
+  list-style: none;
3166
+  padding: 0;
3167
+  margin: 0;
3168
+}
3169
+.shithub-pull-sidebar-list li,
3170
+.shithub-pull-reviews-list li {
3171
+  display: flex;
3172
+  align-items: baseline;
3173
+  justify-content: space-between;
3174
+  gap: 0.5rem;
3175
+  padding: 0.2rem 0;
3176
+}
3177
+.shithub-sidebar-button {
3178
+  width: 100%;
3179
+  justify-content: center;
29603180
 }
2961
-.shithub-pull-reviews-list, .shithub-pull-reviewers-list {
2962
-  list-style: none; padding: 0; margin: 0; font-size: 0.9rem;
3181
+.shithub-pull-request-reviewer summary,
3182
+.shithub-pull-submit-review summary {
3183
+  margin: 0;
3184
+}
3185
+.shithub-pull-request-reviewer form,
3186
+.shithub-pull-review-form {
3187
+  display: flex;
3188
+  flex-direction: column;
3189
+  gap: 0.45rem;
3190
+  padding-top: 0.5rem;
3191
+}
3192
+.shithub-pull-request-reviewer input,
3193
+.shithub-pull-review-form textarea,
3194
+.shithub-pull-review-form select {
3195
+  width: 100%;
3196
+  padding: 0.4rem 0.5rem;
3197
+  border: 1px solid var(--border-default);
3198
+  border-radius: 6px;
3199
+  background: var(--canvas-default);
3200
+  color: var(--fg-default);
3201
+  font: inherit;
29633202
 }
2964
-.shithub-pull-reviews-list li { padding: 0.2rem 0; display: flex; gap: 0.35rem; flex-wrap: wrap; align-items: baseline; }
29653203
 .shithub-pull-review-state { font-weight: 600; }
29663204
 .shithub-pull-review-approve .shithub-pull-review-state { color: #1a7f37; }
29673205
 .shithub-pull-review-request_changes .shithub-pull-review-state { color: #cf222e; }
29683206
 .shithub-pull-review-comment .shithub-pull-review-state { color: var(--fg-muted); }
29693207
 .shithub-pull-review-dismissed { opacity: 0.5; text-decoration: line-through; }
2970
-.shithub-pull-request-reviewer summary, .shithub-pull-submit-review summary {
2971
-  margin: 0.5rem 0 0.25rem;
2972
-}
2973
-.shithub-pull-review-form { display: flex; flex-direction: column; gap: 0.4rem; padding: 0.4rem 0; }
2974
-.shithub-pull-review-form textarea, .shithub-pull-review-form select {
2975
-  padding: 0.4rem; border: 1px solid var(--border-default); border-radius: 6px; font: inherit;
3208
+.shithub-pull-refs { display: flex; gap: 0.4rem; align-items: flex-end; }
3209
+.shithub-pull-refs label { flex: 1; }
3210
+.shithub-pull-arrow { font-size: 1.4rem; padding: 0 0.4rem; align-self: center; }
3211
+.shithub-pull-commits { list-style: none; padding: 0; }
3212
+.shithub-pull-commits li {
3213
+  padding: 0.4rem 0; border-bottom: 1px solid var(--border-default);
3214
+  display: flex; gap: 0.6rem; align-items: baseline;
29763215
 }
29773216
 .shithub-pull-threads { margin-top: 1.5rem; padding: 0.75rem; border: 1px solid var(--border-default); border-radius: 6px; }
29783217
 .shithub-pull-thread-file { padding: 0.4rem 0; border-bottom: 1px solid var(--border-default); }
@@ -2990,6 +3229,40 @@ button.shithub-repo-action {
29903229
 .shithub-pull-add-comment input, .shithub-pull-add-comment textarea {
29913230
   padding: 0.3rem 0.5rem; border: 1px solid var(--border-default); border-radius: 6px; font: inherit;
29923231
 }
3232
+@media (max-width: 960px) {
3233
+  .shithub-pull-conversation-layout {
3234
+    grid-template-columns: 1fr;
3235
+    gap: 1.25rem;
3236
+  }
3237
+  .shithub-pull-sidebar {
3238
+    border-top: 1px solid var(--border-default);
3239
+  }
3240
+}
3241
+@media (max-width: 640px) {
3242
+  .shithub-pull-head h1 {
3243
+    font-size: 1.35rem;
3244
+  }
3245
+  .shithub-pull-tab {
3246
+    padding-inline: 0.75rem;
3247
+  }
3248
+  .shithub-pull-timeline {
3249
+    padding-left: 1.75rem;
3250
+  }
3251
+  .shithub-pull-timeline::before {
3252
+    left: 0.75rem;
3253
+  }
3254
+  .shithub-pull-timeline-marker {
3255
+    left: -1.75rem;
3256
+    width: 1.5rem;
3257
+    height: 1.5rem;
3258
+  }
3259
+  .shithub-pull-merge-box {
3260
+    margin-left: 1.75rem;
3261
+  }
3262
+  .shithub-pull-merge-box-head {
3263
+    padding: 0.75rem;
3264
+  }
3265
+}
29933266
 
29943267
 /* ========== PR Checks tab (S24) ========== */
29953268
 .shithub-pull-checks { display: flex; flex-direction: column; gap: 0.75rem; padding: 0.5rem 0; }
internal/web/templates/repo/pull_view.htmlmodified
@@ -5,111 +5,218 @@
55
       <span>{{ .PR.ITitle }}</span>
66
       <span class="shithub-issue-num">#{{ .PR.INumber }}</span>
77
     </h1>
8
-    <div class="shithub-issue-meta">
8
+    <div class="shithub-pull-summary">
99
       {{ if .PR.MergedAt.Valid }}
10
-        <span class="shithub-pill shithub-pull-merged">⏵ Merged</span>
10
+        <span class="shithub-pull-state-label is-merged">{{ octicon "git-merge" }} Merged</span>
11
+        <span>
12
+          {{ if .MergedByName }}<a href="/{{ .MergedByName }}">{{ .MergedByName }}</a>{{ else }}Someone{{ end }}
13
+          merged {{ .PullStats.Commits }} {{ pluralize .PullStats.Commits "commit" "commits" }} into
14
+          <a class="shithub-branch-name" href="/{{ .Owner }}/{{ .Repo.Name }}/tree/{{ .PR.BaseRef }}">{{ .PR.BaseRef }}</a>
15
+          from <a class="shithub-branch-name" href="/{{ .Owner }}/{{ .Repo.Name }}/tree/{{ .PR.HeadRef }}">{{ .PR.HeadRef }}</a>
16
+        </span>
1117
       {{ else if eq (printf "%s" .PR.IState) "open" }}
12
-        <span class="shithub-pill shithub-issues-state-open">{{ if .PR.Draft }}◔ Draft{{ else }}● Open{{ end }}</span>
18
+        <span class="shithub-pull-state-label {{ if .PR.Draft }}is-draft{{ else }}is-open{{ end }}">{{ octicon "git-pull-request" }} {{ if .PR.Draft }}Draft{{ else }}Open{{ end }}</span>
19
+        <span>
20
+          {{ if .AuthorName }}<a href="/{{ .AuthorName }}">{{ .AuthorName }}</a>{{ end }}
21
+          wants to merge {{ .PullStats.Commits }} {{ pluralize .PullStats.Commits "commit" "commits" }} into
22
+          <a class="shithub-branch-name" href="/{{ .Owner }}/{{ .Repo.Name }}/tree/{{ .PR.BaseRef }}">{{ .PR.BaseRef }}</a>
23
+          from <a class="shithub-branch-name" href="/{{ .Owner }}/{{ .Repo.Name }}/tree/{{ .PR.HeadRef }}">{{ .PR.HeadRef }}</a>
24
+        </span>
1325
       {{ else }}
14
-        <span class="shithub-pill shithub-issues-state-closed">✗ Closed</span>
26
+        <span class="shithub-pull-state-label is-closed">{{ octicon "x" }} Closed</span>
27
+        <span>
28
+          {{ if .AuthorName }}<a href="/{{ .AuthorName }}">{{ .AuthorName }}</a>{{ end }}
29
+          closed this pull request without merging.
30
+        </span>
1531
       {{ end }}
16
-      {{ if .AuthorName }}<a href="/{{ .AuthorName }}">{{ .AuthorName }}</a>{{ end }}
17
-      wants to merge <code>{{ .PR.HeadRef }}</code> into <code>{{ .PR.BaseRef }}</code>
1832
     </div>
1933
   </header>
2034
 
21
-  <nav class="shithub-pull-tabs">
35
+  <nav class="shithub-pull-tabs" aria-label="Pull request">
2236
     <a class="shithub-pull-tab {{ if eq .Tab "conversation" }}shithub-pull-tab-active{{ end }}"
23
-       href="/{{ .Owner }}/{{ .Repo.Name }}/pulls/{{ .PR.INumber }}">Conversation</a>
37
+       href="/{{ .Owner }}/{{ .Repo.Name }}/pulls/{{ .PR.INumber }}">{{ octicon "comment-discussion" }} Conversation</a>
2438
     <a class="shithub-pull-tab {{ if eq .Tab "commits" }}shithub-pull-tab-active{{ end }}"
25
-       href="/{{ .Owner }}/{{ .Repo.Name }}/pulls/{{ .PR.INumber }}/commits">Commits</a>
26
-    <a class="shithub-pull-tab {{ if eq .Tab "files" }}shithub-pull-tab-active{{ end }}"
27
-       href="/{{ .Owner }}/{{ .Repo.Name }}/pulls/{{ .PR.INumber }}/files">Files changed</a>
39
+       href="/{{ .Owner }}/{{ .Repo.Name }}/pulls/{{ .PR.INumber }}/commits">{{ octicon "git-commit" }} Commits <span class="shithub-tab-count">{{ .PullStats.Commits }}</span></a>
2840
     <a class="shithub-pull-tab {{ if eq .Tab "checks" }}shithub-pull-tab-active{{ end }}"
29
-       href="/{{ .Owner }}/{{ .Repo.Name }}/pulls/{{ .PR.INumber }}/checks">Checks</a>
41
+       href="/{{ .Owner }}/{{ .Repo.Name }}/pulls/{{ .PR.INumber }}/checks">{{ octicon "checklist" }} Checks</a>
42
+    <a class="shithub-pull-tab {{ if eq .Tab "files" }}shithub-pull-tab-active{{ end }}"
43
+       href="/{{ .Owner }}/{{ .Repo.Name }}/pulls/{{ .PR.INumber }}/files">{{ octicon "file-diff" }} Files changed <span class="shithub-tab-count">{{ .PullStats.Files }}</span></a>
3044
   </nav>
3145
 
3246
   {{ if eq .Tab "conversation" }}
33
-    <div class="shithub-pull-grid">
34
-      <article class="shithub-issue-thread">
35
-        <div class="shithub-comment">
36
-          <div class="shithub-comment-head">
37
-            {{ if .AuthorName }}<a href="/{{ .AuthorName }}">{{ .AuthorName }}</a>{{ end }}
38
-            <time datetime="{{ .PR.ICreatedAt.Time.Format "2006-01-02T15:04:05Z" }}">{{ relativeTime .PR.ICreatedAt.Time }}</time>
39
-          </div>
40
-          <div class="shithub-comment-body markdown-body">
41
-            {{ if .PR.IBodyHtmlCached.Valid }}{{ safeHTML .PR.IBodyHtmlCached.String }}{{ else }}<p>{{ .PR.IBody }}</p>{{ end }}
47
+    <div class="shithub-pull-conversation-layout">
48
+      <div class="shithub-pull-conversation-main">
49
+        <article class="shithub-pull-timeline" aria-label="Pull request timeline">
50
+          <div class="shithub-pull-timeline-item">
51
+            <div class="shithub-pull-timeline-marker">{{ octicon "comment-discussion" }}</div>
52
+            <div class="shithub-comment shithub-pull-comment">
53
+              <div class="shithub-comment-head">
54
+                {{ if .AuthorName }}<a href="/{{ .AuthorName }}">{{ .AuthorName }}</a>{{ end }}
55
+                <span class="shithub-muted">commented</span>
56
+                <time datetime="{{ .PR.ICreatedAt.Time.Format "2006-01-02T15:04:05Z" }}">{{ relativeTime .PR.ICreatedAt.Time }}</time>
57
+              </div>
58
+              <div class="shithub-comment-body markdown-body">
59
+                {{ if .PR.IBodyHtmlCached.Valid }}{{ safeHTML .PR.IBodyHtmlCached.String }}{{ else }}<p>{{ .PR.IBody }}</p>{{ end }}
60
+              </div>
61
+            </div>
4262
           </div>
43
-        </div>
4463
         {{ range .Comments }}
45
-        <div class="shithub-comment">
46
-          <div class="shithub-comment-head">
47
-            {{ if .AuthorName }}<a href="/{{ .AuthorName }}">{{ .AuthorName }}</a>{{ end }}
48
-            commented
49
-            <time datetime="{{ .C.CreatedAt.Time.Format "2006-01-02T15:04:05Z" }}">{{ relativeTime .C.CreatedAt.Time }}</time>
50
-          </div>
51
-          <div class="shithub-comment-body markdown-body">
52
-            {{ if .C.BodyHtmlCached.Valid }}{{ safeHTML .C.BodyHtmlCached.String }}{{ else }}<p>{{ .C.Body }}</p>{{ end }}
64
+          <div class="shithub-pull-timeline-item">
65
+            <div class="shithub-pull-timeline-marker">{{ octicon "comment" }}</div>
66
+            <div class="shithub-comment shithub-pull-comment">
67
+              <div class="shithub-comment-head">
68
+                {{ if .AuthorName }}<a href="/{{ .AuthorName }}">{{ .AuthorName }}</a>{{ end }}
69
+                <span class="shithub-muted">commented</span>
70
+                <time datetime="{{ .C.CreatedAt.Time.Format "2006-01-02T15:04:05Z" }}">{{ relativeTime .C.CreatedAt.Time }}</time>
71
+              </div>
72
+              <div class="shithub-comment-body markdown-body">
73
+                {{ if .C.BodyHtmlCached.Valid }}{{ safeHTML .C.BodyHtmlCached.String }}{{ else }}<p>{{ .C.Body }}</p>{{ end }}
74
+              </div>
75
+            </div>
5376
           </div>
54
-        </div>
5577
         {{ end }}
5678
         {{ range .Events }}
57
-        <div class="shithub-event">
58
-          <span class="shithub-event-kind">{{ .Kind }}</span>
59
-          <time datetime="{{ .CreatedAt.Time.Format "2006-01-02T15:04:05Z" }}">{{ relativeTime .CreatedAt.Time }}</time>
60
-        </div>
79
+          <div class="shithub-pull-timeline-event">
80
+            <span class="shithub-pull-timeline-dot">{{ octicon "dot-fill" }}</span>
81
+            <span class="shithub-event-kind">{{ .Kind }}</span>
82
+            <time datetime="{{ .CreatedAt.Time.Format "2006-01-02T15:04:05Z" }}">{{ relativeTime .CreatedAt.Time }}</time>
83
+          </div>
6184
         {{ end }}
62
-      </article>
85
+        </article>
86
+
87
+        <section class="shithub-pull-merge-box shithub-pull-merge-state-{{ printf "%s" .PR.MergeableState }}">
88
+          {{ if .PR.MergedAt.Valid }}
89
+            <div class="shithub-pull-merge-box-head">
90
+              <span class="shithub-pull-merge-icon is-merged">{{ octicon "git-merge" }}</span>
91
+              <div>
92
+                <h2>Pull request successfully merged and closed</h2>
93
+                <p>Merged using <code>{{ printf "%s" .PR.MergeMethod.PrMergeMethod }}</code>.</p>
94
+              </div>
95
+            </div>
96
+          {{ else if eq (printf "%s" .PR.IState) "closed" }}
97
+            <div class="shithub-pull-merge-box-head">
98
+              <span class="shithub-pull-merge-icon is-closed">{{ octicon "x" }}</span>
99
+              <div>
100
+                <h2>Closed without merge</h2>
101
+                <p>This pull request is closed.</p>
102
+              </div>
103
+            </div>
104
+          {{ else }}
105
+            <div class="shithub-pull-merge-box-head">
106
+              {{ if eq (printf "%s" .PR.MergeableState) "clean" }}
107
+                <span class="shithub-pull-merge-icon is-clean">{{ octicon "checklist" }}</span>
108
+                <div>
109
+                  <h2>This branch has no conflicts with the base branch</h2>
110
+                  <p>Merging can be performed automatically.</p>
111
+                </div>
112
+              {{ else if eq (printf "%s" .PR.MergeableState) "dirty" }}
113
+                <span class="shithub-pull-merge-icon is-dirty">{{ octicon "x" }}</span>
114
+                <div>
115
+                  <h2>This branch has conflicts that must be resolved</h2>
116
+                  <p>Resolve conflicts locally, then push the fixed branch.</p>
117
+                </div>
118
+              {{ else if eq (printf "%s" .PR.MergeableState) "behind" }}
119
+                <span class="shithub-pull-merge-icon is-behind">{{ octicon "git-commit" }}</span>
120
+                <div>
121
+                  <h2>There are no commits to merge</h2>
122
+                  <p>The head branch has no commits ahead of the base branch.</p>
123
+                </div>
124
+              {{ else if eq (printf "%s" .PR.MergeableState) "blocked" }}
125
+                <span class="shithub-pull-merge-icon is-blocked">{{ octicon "alert" }}</span>
126
+                <div>
127
+                  <h2>Merging is blocked</h2>
128
+                  <p>Required reviews or status checks have not passed yet.</p>
129
+                </div>
130
+              {{ else }}
131
+                <span class="shithub-pull-merge-icon is-unknown">{{ octicon "dot-fill" }}</span>
132
+                <div>
133
+                  <h2>Checking mergeability</h2>
134
+                  <p>Merge status is being computed.</p>
135
+                </div>
136
+              {{ end }}
137
+            </div>
138
+            {{ if or .CanMergePull .CanSetPullState .CanReadyPull }}
139
+            <div class="shithub-pull-merge-actions">
140
+              {{ if .CanMergePull }}
141
+              {{ if eq (printf "%s" .PR.MergeableState) "clean" }}
142
+                <form method="post" action="/{{ .Owner }}/{{ .Repo.Name }}/pulls/{{ .PR.INumber }}/merge" class="shithub-pull-merge-form">
143
+                  <input type="hidden" name="csrf_token" value="{{ .CSRFToken }}">
144
+                  <select name="method" aria-label="Merge method">
145
+                    {{ if .Repo.AllowMergeCommit }}<option value="merge" {{ if eq (printf "%s" .Repo.DefaultMergeMethod) "merge" }}selected{{ end }}>Create a merge commit</option>{{ end }}
146
+                    {{ if .Repo.AllowSquashMerge }}<option value="squash" {{ if eq (printf "%s" .Repo.DefaultMergeMethod) "squash" }}selected{{ end }}>Squash and merge</option>{{ end }}
147
+                    {{ if .Repo.AllowRebaseMerge }}<option value="rebase" {{ if eq (printf "%s" .Repo.DefaultMergeMethod) "rebase" }}selected{{ end }}>Rebase and merge</option>{{ end }}
148
+                  </select>
149
+                  <button type="submit" class="shithub-button shithub-button-primary">Merge pull request</button>
150
+                </form>
151
+              {{ end }}
152
+              {{ end }}
153
+              {{ if .CanSetPullState }}
154
+              <form method="post" action="/{{ .Owner }}/{{ .Repo.Name }}/pulls/{{ .PR.INumber }}/state" class="shithub-pull-state-form">
155
+                <input type="hidden" name="csrf_token" value="{{ .CSRFToken }}">
156
+                <button type="submit" name="state" value="closed" class="shithub-button">Close pull request</button>
157
+              </form>
158
+              {{ end }}
159
+              {{ if and .CanReadyPull .PR.Draft }}
160
+                <form method="post" action="/{{ .Owner }}/{{ .Repo.Name }}/pulls/{{ .PR.INumber }}/ready">
161
+                  <input type="hidden" name="csrf_token" value="{{ .CSRFToken }}">
162
+                  <button type="submit" class="shithub-button">Ready for review</button>
163
+                </form>
164
+              {{ end }}
165
+            </div>
166
+            {{ end }}
167
+          {{ end }}
168
+        </section>
169
+      </div>
170
+
171
+      <aside class="shithub-pull-sidebar" aria-label="Pull request metadata">
172
+        <section class="shithub-pull-sidebar-section">
173
+          <h3>Reviewers</h3>
174
+          {{ if .ReviewRequests }}
175
+          <ul class="shithub-pull-sidebar-list">
176
+          {{ range .ReviewRequests }}
177
+            {{ if not .R.DismissedAt.Valid }}
178
+            <li><a href="/{{ .Username }}">@{{ .Username }}</a> <span>{{ if .R.SatisfiedByReviewID.Valid }}reviewed{{ else }}pending{{ end }}</span></li>
179
+            {{ end }}
180
+          {{ end }}
181
+          </ul>
182
+          {{ else }}
183
+          <p>No reviews</p>
184
+          {{ end }}
185
+        </section>
63186
 
64
-      <aside class="shithub-pull-merge">
65187
         {{ if .Reviews }}
66
-        <section class="shithub-pull-reviews">
67
-          <h3>Reviews</h3>
188
+        <section class="shithub-pull-sidebar-section">
189
+          <h3>Review activity</h3>
68190
           <ul class="shithub-pull-reviews-list">
69
-            {{ range .Reviews }}
191
+          {{ range .Reviews }}
70192
             <li class="shithub-pull-review-{{ printf "%s" .R.State }}{{ if .R.DismissedAt.Valid }} shithub-pull-review-dismissed{{ end }}">
71193
               <span class="shithub-pull-review-state">
72
-                {{ if eq (printf "%s" .R.State) "approve" }}✓ approved{{ else if eq (printf "%s" .R.State) "request_changes" }}✗ changes requested{{ else }}● commented{{ end }}
194
+                {{ if eq (printf "%s" .R.State) "approve" }}approved{{ else if eq (printf "%s" .R.State) "request_changes" }}changes requested{{ else }}commented{{ end }}
73195
               </span>
74196
               {{ if .AuthorName }}<a href="/{{ .AuthorName }}">{{ .AuthorName }}</a>{{ end }}
75
-              <time datetime="{{ .R.SubmittedAt.Time.Format "2006-01-02T15:04:05Z" }}">{{ relativeTime .R.SubmittedAt.Time }}</time>
76
-              {{ if .R.DismissedAt.Valid }}<small>dismissed</small>{{ end }}
77197
             </li>
78
-            {{ end }}
79
-          </ul>
80
-        </section>
81
-        {{ end }}
82
-
83
-        {{ if .ReviewRequests }}
84
-        <section class="shithub-pull-reviewers">
85
-          <h3>Reviewers</h3>
86
-          <ul class="shithub-pull-reviewers-list">
87
-            {{ range .ReviewRequests }}
88
-              {{ if not .R.DismissedAt.Valid }}
89
-              <li>
90
-                <a href="/{{ .Username }}">@{{ .Username }}</a>
91
-                {{ if .R.SatisfiedByReviewID.Valid }}<small>reviewed</small>{{ else }}<small>pending</small>{{ end }}
92
-              </li>
93
-              {{ end }}
94
-            {{ end }}
198
+          {{ end }}
95199
           </ul>
96200
         </section>
97201
         {{ end }}
98202
 
99203
         {{ if .CanReviewPull }}
204
+        <section class="shithub-pull-sidebar-section">
100205
         <details class="shithub-pull-request-reviewer">
101
-          <summary class="shithub-button">Request review</summary>
206
+          <summary class="shithub-link-button">Request review</summary>
102207
           <form method="post" action="/{{ .Owner }}/{{ .Repo.Name }}/pulls/{{ .PR.INumber }}/reviewers">
103208
             <input type="hidden" name="csrf_token" value="{{ .CSRFToken }}">
104209
             <input type="text" name="username" placeholder="username" required>
105210
             <button type="submit" class="shithub-button">Request</button>
106211
           </form>
107212
         </details>
213
+        </section>
108214
 
109215
         {{ if not .PR.MergedAt.Valid }}
110216
         {{ if eq (printf "%s" .PR.IState) "open" }}
217
+        <section class="shithub-pull-sidebar-section">
111218
         <details class="shithub-pull-submit-review">
112
-          <summary class="shithub-button">Submit review</summary>
219
+          <summary class="shithub-link-button">Submit review</summary>
113220
           <form method="post" action="/{{ .Owner }}/{{ .Repo.Name }}/pulls/{{ .PR.INumber }}/reviews" class="shithub-pull-review-form">
114221
             <input type="hidden" name="csrf_token" value="{{ .CSRFToken }}">
115222
             <textarea name="body" rows="4" placeholder="Leave a review comment (optional)"></textarea>
@@ -123,53 +230,39 @@
123230
             <button type="submit" class="shithub-button shithub-button-primary">Submit</button>
124231
           </form>
125232
         </details>
233
+        </section>
126234
         {{ end }}
127235
         {{ end }}
128236
         {{ end }}
129237
 
130
-        {{ if .PR.MergedAt.Valid }}
131
-          <p>Merged via <code>{{ printf "%s" .PR.MergeMethod.PrMergeMethod }}</code>.</p>
132
-        {{ else if eq (printf "%s" .PR.IState) "closed" }}
133
-          <p>This PR is closed without being merged.</p>
134
-        {{ else }}
135
-          <h3>Mergeability</h3>
136
-          <p class="shithub-pull-state-{{ printf "%s" .PR.MergeableState }}">
137
-            {{ printf "%s" .PR.MergeableState }}
138
-          </p>
139
-        {{ if or .CanMergePull .CanSetPullState .CanReadyPull }}
140
-            {{ if .CanMergePull }}
141
-            {{ if eq (printf "%s" .PR.MergeableState) "clean" }}
142
-              <form method="post" action="/{{ .Owner }}/{{ .Repo.Name }}/pulls/{{ .PR.INumber }}/merge" class="shithub-pull-merge-form">
143
-                <input type="hidden" name="csrf_token" value="{{ .CSRFToken }}">
144
-                <select name="method">
145
-                  {{ if .Repo.AllowMergeCommit }}<option value="merge" {{ if eq (printf "%s" .Repo.DefaultMergeMethod) "merge" }}selected{{ end }}>Merge commit</option>{{ end }}
146
-                  {{ if .Repo.AllowSquashMerge }}<option value="squash" {{ if eq (printf "%s" .Repo.DefaultMergeMethod) "squash" }}selected{{ end }}>Squash and merge</option>{{ end }}
147
-                  {{ if .Repo.AllowRebaseMerge }}<option value="rebase" {{ if eq (printf "%s" .Repo.DefaultMergeMethod) "rebase" }}selected{{ end }}>Rebase and merge</option>{{ end }}
148
-                </select>
149
-                <button type="submit" class="shithub-button shithub-button-primary">Merge pull request</button>
150
-              </form>
151
-            {{ else if eq (printf "%s" .PR.MergeableState) "dirty" }}
152
-              <p class="shithub-error">This branch has conflicts that must be resolved manually.</p>
153
-            {{ else if eq (printf "%s" .PR.MergeableState) "behind" }}
154
-              <p class="shithub-muted">Head has no commits ahead of base.</p>
155
-            {{ else }}
156
-              <p class="shithub-muted">Mergeability is being computed…</p>
157
-            {{ end }}
158
-            {{ end }}
159
-            {{ if .CanSetPullState }}
160
-            <form method="post" action="/{{ .Owner }}/{{ .Repo.Name }}/pulls/{{ .PR.INumber }}/state" class="shithub-pull-state-form">
161
-              <input type="hidden" name="csrf_token" value="{{ .CSRFToken }}">
162
-              <button type="submit" name="state" value="closed" class="shithub-button">Close pull request</button>
163
-            </form>
164
-            {{ end }}
165
-            {{ if and .CanReadyPull .PR.Draft }}
166
-              <form method="post" action="/{{ .Owner }}/{{ .Repo.Name }}/pulls/{{ .PR.INumber }}/ready">
167
-                <input type="hidden" name="csrf_token" value="{{ .CSRFToken }}">
168
-                <button type="submit" class="shithub-button">Ready for review</button>
169
-              </form>
170
-            {{ end }}
171
-          {{ end }}
172
-        {{ end }}
238
+        <section class="shithub-pull-sidebar-section">
239
+          <h3>Assignees</h3>
240
+          <p>No one assigned</p>
241
+        </section>
242
+        <section class="shithub-pull-sidebar-section">
243
+          <h3>Labels</h3>
244
+          <p>None yet</p>
245
+        </section>
246
+        <section class="shithub-pull-sidebar-section">
247
+          <h3>Projects</h3>
248
+          <p>None yet</p>
249
+        </section>
250
+        <section class="shithub-pull-sidebar-section">
251
+          <h3>Milestone</h3>
252
+          <p>No milestone</p>
253
+        </section>
254
+        <section class="shithub-pull-sidebar-section">
255
+          <h3>Development</h3>
256
+          <p>No linked issues or branches</p>
257
+        </section>
258
+        <section class="shithub-pull-sidebar-section">
259
+          <h3>Notifications</h3>
260
+          <button type="button" class="shithub-button shithub-sidebar-button" disabled>{{ octicon "bell" }} Subscribe</button>
261
+        </section>
262
+        <section class="shithub-pull-sidebar-section">
263
+          <h3>Participants</h3>
264
+          {{ if .AuthorName }}<a href="/{{ .AuthorName }}">@{{ .AuthorName }}</a>{{ else }}<p>None yet</p>{{ end }}
265
+        </section>
173266
       </aside>
174267
     </div>
175268
   {{ else if eq .Tab "commits" }}