Brief {{ .Number }}
+Home
-{{ .Message }}
+Lenz-Briefe
+Digitale Edition der Briefe von Jakob Michael Reinhold Lenz
+diff --git a/server/brief.go b/server/brief.go index 77a8eb3..ba26616 100644 --- a/server/brief.go +++ b/server/brief.go @@ -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 { diff --git a/server/endpoints.go b/server/endpoints.go index f9f8b5a..3dde0b4 100644 --- a/server/endpoints.go +++ b/server/endpoints.go @@ -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) } diff --git a/server/letterhead.go b/server/letterhead.go new file mode 100644 index 0000000..2e81cb9 --- /dev/null +++ b/server/letterhead.go @@ -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] + } +} diff --git a/server/letters.go b/server/letters.go new file mode 100644 index 0000000..5f1e1f8 --- /dev/null +++ b/server/letters.go @@ -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 +} diff --git a/templates/components/letterhead.gohtml b/templates/components/letterhead.gohtml new file mode 100644 index 0000000..2eb7097 --- /dev/null +++ b/templates/components/letterhead.gohtml @@ -0,0 +1,27 @@ +{{ define "letterhead" }} +
{{ .Message }}
+Digitale Edition der Briefe von Jakob Michael Reinhold Lenz
+