0.1.6 updates and add changelog
This commit is contained in:
116
standalone/changelog.go
Normal file
116
standalone/changelog.go
Normal file
@@ -0,0 +1,116 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"html"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func ChangelogPage(w http.ResponseWriter, r *http.Request) {
|
||||
markdown := readChangelog()
|
||||
body := `
|
||||
<header class="tool-header">
|
||||
<h2 class="tool-title">Changelog</h2>
|
||||
<p class="tool-description">Loaded from CHANGELOG.md.</p>
|
||||
</header>
|
||||
<section class="tool-panel changelog-panel">
|
||||
<div class="panel-body changelog-content">
|
||||
` + renderChangelogMarkdown(markdown) + `
|
||||
</div>
|
||||
</section>
|
||||
<style>
|
||||
.changelog-panel { max-width: 840px; }
|
||||
.changelog-content h1 { margin: 0 0 14px; font-size: 20px; line-height: 1.25; }
|
||||
.changelog-content h2 { margin: 18px 0 8px; padding-top: 12px; border-top: 1px solid #333; font-size: 15px; line-height: 1.3; }
|
||||
.changelog-content ul { margin: 6px 0 12px; padding-left: 20px; }
|
||||
.changelog-content li { margin: 4px 0; line-height: 1.45; }
|
||||
.changelog-content p { margin: 8px 0; line-height: 1.5; }
|
||||
</style>`
|
||||
|
||||
w.Header().Set("Content-Type", "text/html; charset=utf-8")
|
||||
_, _ = w.Write([]byte(Page("/changelog", "Changelog", body)))
|
||||
}
|
||||
|
||||
func readChangelog() string {
|
||||
for _, start := range changelogSearchRoots() {
|
||||
for _, candidate := range changelogCandidates(start) {
|
||||
data, err := os.ReadFile(candidate)
|
||||
if err == nil {
|
||||
return string(data)
|
||||
}
|
||||
}
|
||||
}
|
||||
return "# Changelog\n\nCHANGELOG.md was not found."
|
||||
}
|
||||
|
||||
func changelogSearchRoots() []string {
|
||||
roots := []string{}
|
||||
if wd, err := os.Getwd(); err == nil {
|
||||
roots = append(roots, wd)
|
||||
}
|
||||
roots = append(roots, appDir())
|
||||
return roots
|
||||
}
|
||||
|
||||
func changelogCandidates(start string) []string {
|
||||
candidates := []string{}
|
||||
dir := filepath.Clean(start)
|
||||
for i := 0; i < 5; i++ {
|
||||
candidates = append(candidates, filepath.Join(dir, "CHANGELOG.md"))
|
||||
parent := filepath.Dir(dir)
|
||||
if parent == dir {
|
||||
break
|
||||
}
|
||||
dir = parent
|
||||
}
|
||||
return candidates
|
||||
}
|
||||
|
||||
func renderChangelogMarkdown(markdown string) string {
|
||||
lines := strings.Split(strings.ReplaceAll(markdown, "\r\n", "\n"), "\n")
|
||||
var out strings.Builder
|
||||
inList := false
|
||||
closeList := func() {
|
||||
if inList {
|
||||
out.WriteString("</ul>")
|
||||
inList = false
|
||||
}
|
||||
}
|
||||
|
||||
for _, rawLine := range lines {
|
||||
line := strings.TrimSpace(rawLine)
|
||||
if line == "" {
|
||||
closeList()
|
||||
continue
|
||||
}
|
||||
if strings.HasPrefix(line, "### ") {
|
||||
closeList()
|
||||
out.WriteString("<h2>" + html.EscapeString(strings.TrimSpace(line[4:])) + "</h2>")
|
||||
continue
|
||||
}
|
||||
if strings.HasPrefix(line, "## ") {
|
||||
closeList()
|
||||
out.WriteString("<h2>" + html.EscapeString(strings.TrimSpace(line[3:])) + "</h2>")
|
||||
continue
|
||||
}
|
||||
if strings.HasPrefix(line, "# ") {
|
||||
closeList()
|
||||
out.WriteString("<h1>" + html.EscapeString(strings.TrimSpace(line[2:])) + "</h1>")
|
||||
continue
|
||||
}
|
||||
if strings.HasPrefix(line, "- ") {
|
||||
if !inList {
|
||||
out.WriteString("<ul>")
|
||||
inList = true
|
||||
}
|
||||
out.WriteString("<li>" + html.EscapeString(strings.TrimSpace(line[2:])) + "</li>")
|
||||
continue
|
||||
}
|
||||
closeList()
|
||||
out.WriteString("<p>" + html.EscapeString(line) + "</p>")
|
||||
}
|
||||
closeList()
|
||||
return out.String()
|
||||
}
|
||||
Reference in New Issue
Block a user