more stuff

This commit is contained in:
Simon Martens
2026-03-04 16:39:47 +01:00
parent 5a00333266
commit d7f7571470
22 changed files with 620 additions and 482 deletions

View File

@@ -15,10 +15,11 @@ import (
)
type briefPageModel struct {
Number int
Prev int
Next int
Pages []briefRenderPage
Number int
Prev int
Next int
Heading letterHeadModel
Pages []briefRenderPage
}
type briefRenderPage struct {
@@ -57,7 +58,9 @@ func (s *Server) Brief(c *echo.Context) error {
return c.String(http.StatusNotFound, "brief not found")
}
meta := s.app.Library().Metas.Item(num)
model := renderBrief(*letter)
model.Heading = buildLetterHead(s.app.Library(), meta)
model.Prev, model.Next = briefNeighbors(s.app, num)
var out bytes.Buffer
if err := s.tmpl.ExecuteTemplate(&out, "brief", model); err != nil {

View File

@@ -19,5 +19,7 @@ func MapStatic(e *echo.Echo) {
}
func MapEndpoints(e *echo.Echo, s *Server) {
e.GET("/", s.Home)
e.GET("/briefe", s.Home)
e.GET("/brief/:number", s.Brief)
}

114
server/letterhead.go Normal file
View File

@@ -0,0 +1,114 @@
package server
import (
"strconv"
"strings"
"github.com/Theodor-Springmann-Stiftung/lenz-web/xmlmodels"
)
type letterHeadModel struct {
Number int
DateText string
IsDraft bool
HasOriginal bool
Pairs []letterHeadPairModel
}
type letterHeadPairModel struct {
Sent string
Received string
}
func buildLetterHead(lib *xmlmodels.Library, meta *xmlmodels.Meta) letterHeadModel {
head := letterHeadModel{
Pairs: make([]letterHeadPairModel, 0),
}
if meta == nil {
return head
}
head.Number = meta.Letter
head.IsDraft = meta.IsDraft.IsTrue()
head.HasOriginal = meta.HasOriginal.IsTrue()
if earliest := meta.Earliest(); earliest != nil {
head.DateText = strings.TrimSpace(earliest.Text)
}
for _, pair := range meta.SendReceivedPairs() {
sentNames := resolveNames(lib, pair.Sent.Persons, true)
receivedText := "Unbekannt"
if pair.Received != nil {
receivedNames := resolveNames(lib, pair.Received.Persons, true)
receivedPlaces := resolveNames(lib, pair.Received.Places, false)
if len(receivedNames) > 0 {
receivedText = joinGerman(receivedNames)
} else if len(receivedPlaces) > 0 {
receivedText = joinGerman(receivedPlaces)
} else {
receivedText = ""
}
if len(receivedPlaces) > 0 && len(receivedNames) > 0 {
receivedText += " (" + joinGerman(receivedPlaces) + ")"
}
}
head.Pairs = append(head.Pairs, letterHeadPairModel{
Sent: joinGerman(sentNames),
Received: receivedText,
})
}
return head
}
func resolveNames(lib *xmlmodels.Library, refs []xmlmodels.RefElement, person bool) []string {
ret := make([]string, 0, len(refs))
for _, ref := range refs {
name := ""
if person {
if def := lib.Person(ref.Reference); def != nil {
name = strings.TrimSpace(def.Name)
if name == "" {
name = strings.TrimSpace(def.FirstName + " " + def.LastName)
}
}
} else {
if def := lib.Place(ref.Reference); def != nil {
name = strings.TrimSpace(def.Name)
}
}
if name == "" {
name = strings.TrimSpace(ref.Text)
}
if name == "" && ref.Reference > 0 {
if person {
name = "Person " + strconv.Itoa(ref.Reference)
} else {
name = "Ort " + strconv.Itoa(ref.Reference)
}
}
if name != "" {
ret = append(ret, name)
}
}
return ret
}
func joinGerman(items []string) string {
switch len(items) {
case 0:
return ""
case 1:
return items[0]
case 2:
return items[0] + " und " + items[1]
default:
return strings.Join(items[:len(items)-1], ", ") + " und " + items[len(items)-1]
}
}

107
server/letters.go Normal file
View File

@@ -0,0 +1,107 @@
package server
import (
"bytes"
"net/http"
"strings"
"github.com/Theodor-Springmann-Stiftung/lenz-web/xmlmodels"
"github.com/labstack/echo/v5"
)
type dateRange struct {
Label string
Start int
End int
Letters []letterHeadModel
}
type lettersPageModel struct {
Ranges []dateRange
SelectedRange string
ShowAll bool
ActiveRanges []dateRange
}
func (s *Server) Home(c *echo.Context) error {
rangeParam := c.Request().URL.Query().Get("range")
if rangeParam == "" {
rangeParam = "all"
}
model := buildLettersPageModel(s.app.Library(), rangeParam)
var out bytes.Buffer
if err := s.tmpl.ExecuteTemplate(&out, "home", model); err != nil {
return c.String(http.StatusInternalServerError, "template render failed: "+err.Error())
}
return c.HTML(http.StatusOK, out.String())
}
func buildLettersPageModel(lib *xmlmodels.Library, rangeParam string) lettersPageModel {
ranges := []dateRange{
{Label: "1756-1770", Start: 1756, End: 1770, Letters: []letterHeadModel{}},
{Label: "1771-1775", Start: 1771, End: 1775, Letters: []letterHeadModel{}},
{Label: "1776", Start: 1776, End: 1776, Letters: []letterHeadModel{}},
{Label: "1777-1779", Start: 1777, End: 1779, Letters: []letterHeadModel{}},
{Label: "1780-1792", Start: 1780, End: 1792, Letters: []letterHeadModel{}},
}
years, yearMap := lib.Years()
for _, year := range years {
letters, ok := yearMap[year]
if !ok {
continue
}
target := -1
for i := range ranges {
if year >= ranges[i].Start && year <= ranges[i].End {
target = i
break
}
}
if target == -1 {
continue
}
for _, meta := range letters {
metaCopy := meta
ranges[target].Letters = append(ranges[target].Letters, buildLetterHead(lib, &metaCopy))
}
}
selected := strings.TrimSpace(rangeParam)
if selected == "" {
selected = "all"
}
model := lettersPageModel{
Ranges: ranges,
SelectedRange: selected,
ShowAll: selected == "all",
ActiveRanges: make([]dateRange, 0, len(ranges)),
}
if model.ShowAll {
for _, r := range ranges {
if len(r.Letters) > 0 {
model.ActiveRanges = append(model.ActiveRanges, r)
}
}
return model
}
for _, r := range ranges {
if r.Label == selected && len(r.Letters) > 0 {
model.ActiveRanges = append(model.ActiveRanges, r)
return model
}
}
model.ShowAll = true
model.SelectedRange = "all"
for _, r := range ranges {
if len(r.Letters) > 0 {
model.ActiveRanges = append(model.ActiveRanges, r)
}
}
return model
}