From f25ee52a8bc9cc9b84dfaa3882a7ed3cacd79bc8 Mon Sep 17 00:00:00 2001
From: Jamie Hurst
Date: Mon, 27 Oct 2025 10:52:56 +0000
Subject: [PATCH] Configurable excerpt through environment variables for index
page
---
README.md | 1 +
internal/app/app.go | 6 ++++++
internal/app/controller/web/index.go | 5 +++++
internal/app/model/journal.go | 25 +++----------------------
internal/app/model/journal_test.go | 24 ++++++++++++------------
web/templates/index.html.tmpl | 2 +-
6 files changed, 28 insertions(+), 35 deletions(-)
diff --git a/README.md b/README.md
index 2b817fb..c52f8e8 100644
--- a/README.md
+++ b/README.md
@@ -53,6 +53,7 @@ The application uses environment variables to configure all aspects.
* `J_DB_PATH` - Path to SQLite DB - default is `$GOPATH/data/journal.db`
* `J_DESCRIPTION` - Set the HTML description of the Journal
* `J_EDIT` - Set to `0` to disable article modification
+* `J_EXCERPT_WORDS` - The length of the article shown as a preview/excerpt in the index, default `50`
* `J_GA_CODE` - Google Analytics tag value, starts with `UA-`, or ignore to disable Google Analytics
* `J_PORT` - Port to expose over HTTP, default is `3000`
* `J_THEME` - Theme to use from within the _web/themes_ folder, defaults to `default`
diff --git a/internal/app/app.go b/internal/app/app.go
index 2e583bc..6fabe83 100644
--- a/internal/app/app.go
+++ b/internal/app/app.go
@@ -37,6 +37,7 @@ type Configuration struct {
Description string
EnableCreate bool
EnableEdit bool
+ ExcerptWords int
GoogleAnalyticsCode string
Port string
SSLCertificate string
@@ -55,6 +56,7 @@ func DefaultConfiguration() Configuration {
Description: "A private journal containing Jamie's innermost thoughts",
EnableCreate: true,
EnableEdit: true,
+ ExcerptWords: 50,
GoogleAnalyticsCode: "",
Port: "3000",
SSLCertificate: "",
@@ -88,6 +90,10 @@ func ApplyEnvConfiguration(config *Configuration) {
if enableEdit == "0" {
config.EnableEdit = false
}
+ excerptWords, _ := strconv.Atoi(os.Getenv("J_EXCERPT_WORDS"))
+ if excerptWords > 0 {
+ config.ExcerptWords = excerptWords
+ }
config.GoogleAnalyticsCode = os.Getenv("J_GA_CODE")
port := os.Getenv("J_PORT")
if port != "" {
diff --git a/internal/app/controller/web/index.go b/internal/app/controller/web/index.go
index e134ee4..052c967 100644
--- a/internal/app/controller/web/index.go
+++ b/internal/app/controller/web/index.go
@@ -18,6 +18,7 @@ type Index struct {
type indexTemplateData struct {
Container interface{}
+ Excerpt func(model.Journal) string
Journals []model.Journal
Pages []int
Pagination database.PaginationDisplay
@@ -49,6 +50,10 @@ func (c *Index) Run(response http.ResponseWriter, request *http.Request) {
i++
}
+ data.Excerpt = func(j model.Journal) string {
+ return j.GetHTMLExcerpt(container.Configuration.ExcerptWords)
+ }
+
c.SaveSession(response)
template, _ := template.ParseFiles(
"./web/templates/_layout/default.html.tmpl",
diff --git a/internal/app/model/journal.go b/internal/app/model/journal.go
index 4d52b87..a13fb33 100644
--- a/internal/app/model/journal.go
+++ b/internal/app/model/journal.go
@@ -52,27 +52,8 @@ func (j Journal) GetEditableDate() string {
return re.FindString(j.Date)
}
-// GetExcerpt returns a small extract of the entry as plain text
-func (j Journal) GetExcerpt() string {
- strip := regexp.MustCompile("\b+")
- // Markdown handling - replace newlines with spaces
- text := strings.ReplaceAll(j.Content, "\n", " ")
- text = strip.ReplaceAllString(text, " ")
-
- // Clean up multiple spaces
- spaceRegex := regexp.MustCompile(`\s+`)
- text = spaceRegex.ReplaceAllString(text, " ")
-
- words := strings.Split(text, " ")
-
- if len(words) > 50 {
- return strings.Join(words[:50], " ") + "..."
- }
- return strings.TrimSpace(strings.Join(words, " "))
-}
-
// GetHTMLExcerpt returns a small extract of the entry rendered as HTML
-func (j Journal) GetHTMLExcerpt() string {
+func (j Journal) GetHTMLExcerpt(maxWords int) string {
if j.Content == "" {
return ""
}
@@ -86,7 +67,7 @@ func (j Journal) GetHTMLExcerpt() string {
for _, paragraph := range paragraphs {
// Skip if we've already got 50+ words
- if wordCount >= 50 {
+ if wordCount >= maxWords {
break
}
@@ -98,7 +79,7 @@ func (j Journal) GetHTMLExcerpt() string {
lineWords := strings.Fields(line)
// Calculate how many words we can take from this line
- wordsToTake := 50 - wordCount
+ wordsToTake := maxWords - wordCount
if wordsToTake <= 0 {
break
}
diff --git a/internal/app/model/journal_test.go b/internal/app/model/journal_test.go
index 748dde6..11274d9 100644
--- a/internal/app/model/journal_test.go
+++ b/internal/app/model/journal_test.go
@@ -49,42 +49,42 @@ func TestJournal_GetEditableDate(t *testing.T) {
}
}
-func TestJournal_GetExcerpt(t *testing.T) {
+func TestJournal_GetHTMLExcerpt(t *testing.T) {
tables := []struct {
input string
output string
}{
- {"Some simple text", "Some simple text"},
- {"Multiple\n\nparagraphs, some with\n\nmultiple words", "Multiple paragraphs, some with multiple words"},
+ {"Some **bold** text", "Some bold text
\n"},
+ {"Multiple\n\nparagraphs", "Multiple
\n\nparagraphs
\n"},
{"", ""},
- {"\n\n", ""},
- {"a b c d e f g h i j k l m n o p q r s t u v w x y z a b c d e f g h i j k l m n o p q r s t u v w x y z", "a b c d e f g h i j k l m n o p q r s t u v w x y z a b c d e f g h i j k l m n o p q r s t u v w x..."},
+ {"*Italic* and **bold**", "Italic and bold
\n"},
+ {"Line 1\nLine 2\nLine 3", "Line 1\nLine 2\nLine 3
\n"},
}
for _, table := range tables {
j := Journal{Content: table.input}
- actual := j.GetExcerpt()
+ actual := j.GetHTMLExcerpt(50)
if actual != table.output {
- t.Errorf("Expected GetExcerpt() to produce result of '%s', got '%s'", table.output, actual)
+ t.Errorf("Expected GetHTMLExcerpt() to produce result of '%s', got '%s'", table.output, actual)
}
}
}
-func TestJournal_GetHTMLExcerpt(t *testing.T) {
+func TestJournal_GetHTMLExcerpt_ShortWords(t *testing.T) {
tables := []struct {
input string
output string
}{
- {"Some **bold** text", "Some bold text
\n"},
+ {"Some **bold** text", "Some bold…
\n"},
{"Multiple\n\nparagraphs", "Multiple
\n\nparagraphs
\n"},
{"", ""},
- {"*Italic* and **bold**", "Italic and bold
\n"},
- {"Line 1\nLine 2\nLine 3", "Line 1\nLine 2\nLine 3
\n"},
+ {"*Italic* and **bold**", "Italic and…
\n"},
+ {"Line 1\nLine 2\nLine 3", "Line 1
\n"},
}
for _, table := range tables {
j := Journal{Content: table.input}
- actual := j.GetHTMLExcerpt()
+ actual := j.GetHTMLExcerpt(2)
if actual != table.output {
t.Errorf("Expected GetHTMLExcerpt() to produce result of '%s', got '%s'", table.output, actual)
}
diff --git a/web/templates/index.html.tmpl b/web/templates/index.html.tmpl
index 36d35c1..4229f72 100644
--- a/web/templates/index.html.tmpl
+++ b/web/templates/index.html.tmpl
@@ -13,7 +13,7 @@
{{.GetDate}}
- {{.GetHTMLExcerpt}}
+ {{call $.Excerpt . }}
{{if $enableEdit}}
Edit{{end}}
Read More