From 7a49e5be4a47e04fbd598c7f7bd376b42d6f02a8 Mon Sep 17 00:00:00 2001 From: whereareiam Date: Sun, 4 Oct 2026 11:03:00 +0200 Subject: [PATCH] Pull request: Draw timeline connectors only between neighbouring entries GitHub runs one continuous line down the timeline, so it trails past the last entry and runs alongside boxes it does not connect. This is our own rule instead: a connector joins two neighbouring entries and nothing else. It never runs past the last entry, alongside a review box, or out of a review group. On pull request pages the single full-height line is replaced by per-entry halves. On issue pages the last entry's line now stops at its badge. The "closed this pull request" badge is red, matching the state label. Co-Authored-By: Claude Opus 5.5 --- .../components/issues/issue_conversation.ts | 16 ++-- styles/components/issues/pull_review.ts | 73 +++++++++++++++++++ 2 files changed, 78 insertions(+), 11 deletions(-) diff --git a/styles/components/issues/issue_conversation.ts b/styles/components/issues/issue_conversation.ts index 0e98e50..9a913b1 100644 --- a/styles/components/issues/issue_conversation.ts +++ b/styles/components/issues/issue_conversation.ts @@ -412,6 +412,11 @@ export default css` top: -16px; } } + /* The last entry's line stops at its badge instead of trailing below it. */ + & .comment-list .timeline-item.event:not(:has(~ .timeline-item:not(.form)))::before { + bottom: auto; + height: 24px; + } } & .comment-editor-heading { font-size: 16px; @@ -423,17 +428,6 @@ export default css` & .comment.form > .timeline-avatar { top: 0 !important; } - /* The timeline's line runs its full height; end it at the last item instead of in the gap above the form. */ - & .timeline-item.comment.form::before { - content: ""; - display: block !important; - position: absolute; - top: -44px; - left: 0; - width: 100%; - height: 44px; - background: ${themeVars.color.body}; - } & .comment.form { z-index: 1; margin-top: 32px; diff --git a/styles/components/issues/pull_review.ts b/styles/components/issues/pull_review.ts index 9e2b250..0bda39a 100644 --- a/styles/components/issues/pull_review.ts +++ b/styles/components/issues/pull_review.ts @@ -90,6 +90,10 @@ export default css` border-color: ${themeVars.github.bgColor.danger.emphasis} !important; box-shadow: none; } + /* The "closed this pull request" entry in the timeline is red too. */ + & .timeline-item.event .badge.tw-bg-red { + background-color: ${themeVars.github.bgColor.danger.emphasis} !important; + } /* A draft is a solid grey label. */ & .issue-title-meta .ui.label.issue-state-label.grey { color: ${themeVars.github.fgColor.onEmphasis} !important; @@ -171,6 +175,75 @@ export default css` margin-left: 40px; padding-left: 16px; } + /* + * Timeline connectors. Our own rule, not GitHub's continuous line: a connector is drawn only + * between two neighbouring entries. Nothing runs past the last entry, alongside a box, or + * out of a review group, whose boxes are indented away from the rail. + */ + &.github-conversation .issue-content-left > .ui.timeline { + --rail: color-mix(in srgb, ${themeVars.color.light.border} 70%, transparent); + --rail-line: linear-gradient(var(--rail), var(--rail)); + &::before { + display: none; + } + /* Events and commit rows sit left of their own box, so their halves are pseudo-elements. */ + & > .timeline-item:is(.event, .commits-list)::before, + & > .timeline-item:is(.event, .commits-list)::after, + & > .timeline-item-group > .timeline-item.event:first-child::before { + content: ""; + position: absolute; + left: -2px; + width: 2px; + background: var(--rail); + } + /* Upper half: from the entry above down to this badge. */ + & > .timeline-item.event::before, + & > .timeline-item-group > .timeline-item.event:first-child::before { + top: 0; + height: 12px; + } + & > .timeline-item.commits-list::before { + top: 0; + bottom: 27px; + } + /* Lower half: only when another entry follows. */ + & > .timeline-item:is(.event, .commits-list)::after { + display: none; + bottom: 0; + } + & > .timeline-item:is(.event, .commits-list):has(~ :is(.timeline-item:not(.form), .timeline-item-group))::after { + display: block; + } + & > .timeline-item.event::after { + top: 46px; + } + & > .timeline-item.commits-list::after { + height: 27px; + } + /* Comment and merge boxes cover the rail; they only draw stubs in the gaps above and below. */ + & > .timeline-item.comment:not(.form) { + --rail-up: var(--rail-line) 14px 0 / 2px 12px no-repeat; + --rail-down: var(--rail-line) 14px 100% / 0 0 no-repeat; + background: var(--rail-up), var(--rail-down); + } + & > .timeline-item.comment:not(.form):has(~ :is(.timeline-item:not(.form), .timeline-item-group)) { + --rail-down: var(--rail-line) 14px 100% / 2px 12px no-repeat; + } + & > .timeline-item.comment.first { + --rail-up: var(--rail-line) 14px 0 / 0 0 no-repeat; + } + /* Nothing leaves a review group. */ + & > .timeline-item-group + .timeline-item.comment, + & > .timeline-item-group + div:empty + .timeline-item.comment { + --rail-up: var(--rail-line) 14px 0 / 0 0 no-repeat; + } + & > .timeline-item-group + .timeline-item:is(.event, .commits-list)::before, + & > .timeline-item-group + div:empty + .timeline-item:is(.event, .commits-list)::before, + & > .timeline-item-group + .timeline-item-group > .timeline-item.event:first-child::before, + & > .timeline-item-group + div:empty + .timeline-item-group > .timeline-item.event:first-child::before { + display: none; + } + } &.github-conversation .timeline-item.comment > .timeline-avatar { display: block; left: -56px;