7 files changed,
+119,
-14
+10,
-1
1@@ -4,7 +4,11 @@
2
3 {{define "content"}}
4 <div>
5- <div class="commit-message">{{.Commit.Message}}</div>
6+ <div class="commit-message"><div class="commit-message__summary">{{.Commit.SummaryStr}}</div>
7+ {{- if .Commit.MessageBodyOnly -}}
8+ <div class="commit-message__body">{{.Commit.MessageBodyOnly}}</div>
9+ {{- end -}}
10+ </div>
11
12 <div class="metadata">
13 <div class="metadata__label">commit</div>
14@@ -18,6 +22,11 @@
15
16 <div class="metadata__label">date</div>
17 <div class="metadata__value">{{.Commit.WhenISO}}</div>
18+
19+ {{- range .Commit.Trailers -}}
20+ <div class="metadata__label">{{.Key}}</div>
21+ <div class="metadata__value">{{.Value}}</div>
22+ {{- end -}}
23 </div>
24 </div>
25
+1,
-1
1@@ -10,7 +10,7 @@
2 <div class="commit-item">
3 <div class="commit-item__header">
4 <div class="commit-item__content">
5- <div class="commit-item__message"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-git-commit-vertical-icon lucide-git-commit-vertical"><path d="M12 3v6"/><circle cx="12" cy="12" r="3"/><path d="M12 15v6"/></svg><a href="{{.URL}}">{{.Message}}</a></div>
6+ <div class="commit-item__message"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-git-commit-vertical-icon lucide-git-commit-vertical"><path d="M12 3v6"/><circle cx="12" cy="12" r="3"/><path d="M12 15v6"/></svg><a href="{{.URL}}">{{.SummaryStr}}</a></div>
7 <div class="commit-item__meta">
8 <span class="font-bold">{{.AuthorStr}}</span>
9 <span> · </span>
M
main.go
+98,
-10
1@@ -13,6 +13,7 @@ import (
2 "math"
3 "os"
4 "path/filepath"
5+ "regexp"
6 "sort"
7 "strings"
8 "sync"
9@@ -120,6 +121,11 @@ type TagData struct {
10 URL template.URL
11 }
12
13+type Trailer struct {
14+ Key string
15+ Value string
16+}
17+
18 type CommitData struct {
19 SummaryStr string
20 URL template.URL
21@@ -130,6 +136,9 @@ type CommitData struct {
22 ShortID string
23 ParentID string
24 Refs []*RefInfo
25+ Trailers []Trailer
26+ // MessageBodyOnly is the commit message body without summary line and trailers
27+ MessageBodyOnly string
28 *git.Commit
29 }
30
31@@ -770,6 +779,82 @@ func (c *Config) getCommitURL(commitID string) template.URL {
32 return template.URL(url)
33 }
34
35+// parseCommitMessage extracts git trailer lines from a commit message and returns
36+// the trailers and the message body without summary line and trailers.
37+// Trailers are lines at the end of the message in "Key: value" format.
38+func parseCommitMessage(message string) ([]Trailer, string) {
39+ var trailers []Trailer
40+
41+ // Trailer pattern: key with alphanumeric/hyphens, colon, space, value
42+ // Examples: "Signed-off-by: John Doe", "Co-authored-by: Jane Smith"
43+ trailerRe := regexp.MustCompile(`^([A-Za-z0-9-]+): (.+)$`)
44+
45+ // Trim trailing newlines to avoid empty last line
46+ message = strings.TrimRight(message, "\n")
47+ lines := strings.Split(message, "\n")
48+
49+ // Find where trailers start (index of first trailer line)
50+ trailerStartIdx := -1
51+
52+ // Collect trailer lines from the end of the message
53+ for i := len(lines) - 1; i >= 0; i-- {
54+ line := strings.TrimSpace(lines[i])
55+
56+ // Stop at empty line (separator between message body and trailers)
57+ if line == "" {
58+ trailerStartIdx = i + 1
59+ break
60+ }
61+
62+ matches := trailerRe.FindStringSubmatch(line)
63+ if matches != nil {
64+ trailers = append([]Trailer{
65+ {Key: matches[1], Value: matches[2]},
66+ }, trailers...)
67+ } else {
68+ // Not a trailer line, stop collecting
69+ trailerStartIdx = i + 1
70+ break
71+ }
72+ }
73+
74+ // If no trailers found, treat entire message as body
75+ bodyLines := lines
76+ if len(trailers) > 0 && trailerStartIdx > 0 {
77+ // trailerStartIdx is the first line of trailers, so body is everything before it
78+ bodyLines = lines[:trailerStartIdx]
79+ }
80+
81+ // Remove trailing empty lines from body
82+ bodyEndIdx := len(bodyLines)
83+ for i := len(bodyLines) - 1; i >= 0; i-- {
84+ if strings.TrimSpace(bodyLines[i]) != "" {
85+ bodyEndIdx = i + 1
86+ break
87+ }
88+ }
89+ bodyLines = bodyLines[:bodyEndIdx]
90+
91+ // Extract body without summary (everything after first line)
92+ messageBodyOnly := ""
93+ if len(bodyLines) > 1 {
94+ bodyOnlyLines := bodyLines[1:]
95+ // Remove leading empty lines
96+ startIdx := 0
97+ for i, line := range bodyOnlyLines {
98+ if strings.TrimSpace(line) != "" {
99+ startIdx = i
100+ break
101+ }
102+ }
103+ if startIdx < len(bodyOnlyLines) {
104+ messageBodyOnly = strings.Join(bodyOnlyLines[startIdx:], "\n")
105+ }
106+ }
107+
108+ return trailers, messageBodyOnly
109+}
110+
111 func (c *Config) getURLs() *SiteURLs {
112 return &SiteURLs{
113 HomeURL: c.HomeURL,
114@@ -1170,17 +1255,20 @@ func (c *Config) writeRevision(repo *git.Repository, pageData *PageData, refs []
115 } else {
116 parentID = parentSha.String()
117 }
118+ trailers, messageBodyOnly := parseCommitMessage(commit.Message)
119 cd := &CommitData{
120- ParentID: parentID,
121- URL: c.getCommitURL(commit.ID.String()),
122- ShortID: getShortID(commit.ID.String()),
123- SummaryStr: commit.Summary(),
124- AuthorStr: commit.Author.Name,
125- WhenStr: commit.Author.When.Format(time.DateOnly),
126- WhenISO: commit.Author.When.UTC().Format(time.RFC3339),
127- WhenDisplay: formatDateForDisplay(commit.Author.When),
128- Commit: commit,
129- Refs: tags,
130+ ParentID: parentID,
131+ URL: c.getCommitURL(commit.ID.String()),
132+ ShortID: getShortID(commit.ID.String()),
133+ SummaryStr: commit.Summary(),
134+ AuthorStr: commit.Author.Name,
135+ WhenStr: commit.Author.When.Format(time.DateOnly),
136+ WhenISO: commit.Author.When.UTC().Format(time.RFC3339),
137+ WhenDisplay: formatDateForDisplay(commit.Author.When),
138+ Commit: commit,
139+ Refs: tags,
140+ Trailers: trailers,
141+ MessageBodyOnly: messageBodyOnly,
142 }
143 logs = append(logs, cd)
144 if i == 0 {
+9,
-1
1@@ -1104,12 +1104,20 @@ sup {
2 margin: 0;
3 margin-bottom: calc(var(--line-height) * 2);
4 white-space: break-spaces;
5- font-weight: bold;
6 font-size: 1rem;
7 line-height: var(--line-height);
8 text-transform: none;
9 }
10
11+.commit-message__summary {
12+ font-weight: 700;
13+ margin-bottom: var(--line-height);
14+}
15+
16+.commit-message__body {
17+ font-weight: 400;
18+}
19+
20 /* File List Summary (in commit page) */
21 .file-list-summary {
22 margin-top: var(--grid-height);
+1,
-1
1@@ -1 +1 @@
2-6b045bbefb0f27ea3972bf1ea5ec74b17111586d
3+dac8123e5796000d7a1d8acad91a9275ae510fd3