diff --git a/controllers/baende.go b/controllers/baende.go index bd70624..7814357 100644 --- a/controllers/baende.go +++ b/controllers/baende.go @@ -12,6 +12,7 @@ import ( "github.com/Theodor-Springmann-Stiftung/musenalm/pagemodels" "github.com/Theodor-Springmann-Stiftung/musenalm/templating" "github.com/pocketbase/dbx" + "github.com/pocketbase/pocketbase/core" "github.com/pocketbase/pocketbase/tools/router" ) @@ -20,6 +21,7 @@ const ( URL_BAENDE = "/baende/" URL_BAENDE_RESULTS = "/baende/results/" TEMPLATE_BAENDE = "/baende/" + URL_BAENDE_DETAILS = "/baende/details/{id}" ) func init() { @@ -48,12 +50,26 @@ type BaendeResult struct { Items map[string][]*dbmodels.Item } +type BaendeDetailsResult struct { + Entry *dbmodels.Entry + Series []*dbmodels.Series + Places []*dbmodels.Place + Agents []*dbmodels.Agent + Items []*dbmodels.Item + SeriesRels []*dbmodels.REntriesSeries + AgentRels []*dbmodels.REntriesAgents + IsAdmin bool + CSRFToken string +} + func (p *BaendePage) Setup(router *router.Router[*core.RequestEvent], ia pagemodels.IApp, engine *templating.Engine) error { app := ia.Core() rg := router.Group(URL_BAENDE) rg.BindFunc(middleware.Authenticated(app)) rg.GET("", p.handlePage(engine, app)) rg.GET("results/", p.handleResults(engine, app)) + rg.GET("details/{id}", p.handleDetails(engine, app)) + rg.GET("row/{id}", p.handleRow(engine, app)) return nil } @@ -89,6 +105,104 @@ func (p *BaendePage) handleResults(engine *templating.Engine, app core.App) Hand } } +func (p *BaendePage) handleRow(engine *templating.Engine, app core.App) HandleFunc { + return func(e *core.RequestEvent) error { + req := templating.NewRequest(e) + if req.User() == nil { + return e.Redirect(303, "/login/") + } + + id := e.Request.PathValue("id") + if id == "" { + return engine.Response404(e, nil, nil) + } + + entry, err := dbmodels.Entries_MusenalmID(app, id) + if err != nil { + return engine.Response404(e, err, nil) + } + + items, err := dbmodels.Items_Entry(app, entry.Id) + if err != nil { + app.Logger().Error("Failed to get items for entry", "error", err) + } + + data := map[string]any{ + "entry": entry, + "items": items, + "is_admin": req.IsAdmin(), + "csrf_token": req.Session().Token, + } + + return engine.Response200(e, "/baende/row/", data, "fragment") + } +} + +func (p *BaendePage) handleDetails(engine *templating.Engine, app core.App) HandleFunc { + return func(e *core.RequestEvent) error { + req := templating.NewRequest(e) + if req.User() == nil { + return e.Redirect(303, "/login/") + } + + id := e.Request.PathValue("id") + if id == "" { + return engine.Response404(e, nil, nil) + } + + entry, err := dbmodels.Entries_MusenalmID(app, id) + if err != nil { + return engine.Response404(e, err, nil) + } + + entryIDs := []any{entry.Id} + + series, relations, err := Series_Entries(app, []*dbmodels.Entry{entry}) + if err != nil { + app.Logger().Error("Failed to get series for entry", "error", err) + } + + agents, arelations, err := Agents_Entries_IDs(app, entryIDs) + if err != nil { + app.Logger().Error("Failed to get agents for entry", "error", err) + } + + toStringAny := func(ss []string) []any { + res := make([]any, len(ss)) + for i, s := range ss { + res[i] = s + } + return res + } + + places, err := dbmodels.Places_IDs(app, toStringAny(entry.Places())) + if err != nil { + app.Logger().Error("Failed to get places for entry", "error", err) + } + + items, err := dbmodels.Items_Entry(app, entry.Id) + if err != nil { + app.Logger().Error("Failed to get items for entry", "error", err) + } + + data := map[string]any{ + "result": &BaendeDetailsResult{ + Entry: entry, + Series: series, + Places: places, + Agents: agents, + Items: items, + SeriesRels: relations, + AgentRels: arelations, + IsAdmin: req.IsAdmin(), + CSRFToken: req.Session().Token, + }, + } + + return engine.Response200(e, "/baende/details/", data, "fragment") + } +} + func (p *BaendePage) buildResultData(app core.App, e *core.RequestEvent, req *templating.Request) (map[string]any, error) { data := map[string]any{} @@ -177,13 +291,28 @@ func (p *BaendePage) buildResultData(app core.App, e *core.RequestEvent, req *te } itemsMap := map[string][]*dbmodels.Item{} - for _, entry := range entries { - items, err := dbmodels.Items_Entry(app, entry.Id) + if len(entryIDs) > 0 { + // 1. Fetch all items related to any of the entry IDs in a single query. + allItems, err := dbmodels.Items_Entries(app, entryIDs) if err != nil { return data, err } - if len(items) > 0 { - itemsMap[entry.Id] = items + + // 2. Create a lookup map for the entries we are interested in. + interestedEntries := make(map[string]struct{}) + for _, id := range entryIDs { + interestedEntries[id.(string)] = struct{}{} + } + + // 3. Group the fetched items by their associated entry ID. + for _, item := range allItems { + // An item can be related to multiple entries. We need to check which of its entries are in our current list. + for _, entryID := range item.Entries() { + // If the item's entry ID is in our list of interested entries, add the item to the map. + if _, ok := interestedEntries[entryID]; ok { + itemsMap[entryID] = append(itemsMap[entryID], item) + } + } } } diff --git a/dbmodels/item.go b/dbmodels/item.go index 6940f04..6b6c399 100644 --- a/dbmodels/item.go +++ b/dbmodels/item.go @@ -30,6 +30,25 @@ func (a *Item) Entry() string { return a.GetString(ENTRIES_TABLE) } +func (i *Item) Entries() []string { + // Get the raw string value of the 'entries' field + raw := i.GetString(ENTRIES_TABLE) + + // Check if it's likely a JSON array (starts with '[') + if len(raw) > 0 && raw[0] == '[' { + // If it is JSON, GetStringSlice will handle unmarshalling it + return i.GetStringSlice(ENTRIES_TABLE) + } + + // If it's not a JSON array, it's a single ID. Return it as a slice. + if raw != "" { + return []string{raw} + } + + // Return an empty slice if the field is empty + return []string{} +} + func (a *Item) SetEntry(entry string) { a.Set(ENTRIES_TABLE, entry) } diff --git a/dbmodels/queries.go b/dbmodels/queries.go index df492fe..8ae7a6c 100644 --- a/dbmodels/queries.go +++ b/dbmodels/queries.go @@ -1,6 +1,10 @@ package dbmodels import ( + "fmt" + "strconv" + "strings" + "github.com/pocketbase/dbx" "github.com/pocketbase/pocketbase/core" ) @@ -240,6 +244,37 @@ func Items_Entry(app core.App, id string) ([]*Item, error) { return ret, err } +func Items_Entries(app core.App, ids []any) ([]*Item, error) { + if len(ids) == 0 { + return []*Item{}, nil + } + + params := dbx.Params{} + idPlaceholders := make([]string, len(ids)) + for i, id := range ids { + placeholder := "p" + strconv.Itoa(i) + params[placeholder] = id + idPlaceholders[i] = "{:" + placeholder + "}" + } + inClause := strings.Join(idPlaceholders, ", ") + + fullExpression := fmt.Sprintf( + "%s IN (%s) OR (json_valid(%s) = 1 AND EXISTS (SELECT 1 FROM json_each(%s) WHERE value IN (%s)))", + ENTRIES_TABLE, + inClause, + ENTRIES_TABLE, + ENTRIES_TABLE, + inClause, + ) + + var ret []*Item + err := app.RecordQuery(ITEMS_TABLE). + Where(dbx.NewExp(fullExpression, params)). + All(&ret) + + return ret, err +} + func Contents_MusenalmID(app core.App, id string) (*Content, error) { ret, err := TableByField[Content](app, CONTENTS_TABLE, MUSENALMID_FIELD, id) return &ret, err diff --git a/views/routes/baende/components/_baende_table.gohtml b/views/routes/baende/components/_baende_table.gohtml index 87ba8a5..2e337a1 100644 --- a/views/routes/baende/components/_baende_table.gohtml +++ b/views/routes/baende/components/_baende_table.gohtml @@ -15,7 +15,13 @@ {{- range $_, $entry := $model.result.Entries -}} - +
Alm {{ $entry.MusenalmID }} @@ -167,238 +173,6 @@ {{- end -}} - - -
- Alm {{ $entry.MusenalmID }} - {{- if $entry.References -}} - {{ $entry.References }} - {{- end -}} -
- - - - -
Ansehen
-
- {{- if (IsAdminOrEditor $model.request.user) -}} - - - - -
Bearbeiten
-
-
- - - -
Löschen
-
-
- {{- end -}} - - -
Zuklappen
-
-
-
- - -
-
-
- {{- if $entry.PreferredTitle -}} - {{ $entry.PreferredTitle }} - {{- else if ne $entry.Year 0 -}} - {{ $entry.Year }} - {{- else -}} - [o.J.] - {{- end -}} - - -
- {{- if eq $entry.EditState "Unknown" -}} - Gesucht - {{- else if eq $entry.EditState "ToDo" -}} - Zu erledigen - {{- else if eq $entry.EditState "Review" -}} - Überprüfen - {{- else if eq $entry.EditState "Seen" -}} - Autopsiert - {{- else if eq $entry.EditState "Edited" -}} - Vollständig Erfasst - {{- else -}} - {{ $entry.EditState }} - {{- end -}} -
-
-
-
-
-
- {{- if or $entry.TitleStmt $entry.SubtitleStmt $entry.VariantTitle $entry.ParallelTitle $entry.IncipitStmt -}} -
-
Titelangaben
-
- {{- if $entry.TitleStmt -}}
Titel: {{ $entry.TitleStmt }}
{{- end -}} - {{- if $entry.SubtitleStmt -}}
Untertitel: {{ $entry.SubtitleStmt }}
{{- end -}} - {{- if $entry.VariantTitle -}}
Varianten: {{ $entry.VariantTitle }}
{{- end -}} - {{- if $entry.ParallelTitle -}}
Parallel: {{ $entry.ParallelTitle }}
{{- end -}} - {{- if $entry.IncipitStmt -}}
Incipit: {{ $entry.IncipitStmt }}
{{- end -}} -
-
- {{- end -}} - {{- if or $entry.ResponsibilityStmt $entry.PublicationStmt $entry.PlaceStmt -}} -
-
Erscheinung
-
- {{- if and $entry.ResponsibilityStmt (not (eq $entry.ResponsibilityStmt "unbezeichnet")) -}}
Herausgaberangabe: {{ $entry.ResponsibilityStmt }}
{{- end -}} - {{- if $entry.PublicationStmt -}}
Publikationsangabe: {{ $entry.PublicationStmt }}
{{- end -}} - {{- if $entry.PlaceStmt -}}
Ortsangabe: {{ $entry.PlaceStmt }}
{{- end -}} -
-
- {{- end -}} - {{- if $entry.Annotation -}} -
-
Annotation
-
{{ $entry.Annotation }}
-
- {{- end -}} - {{- $srels := index $model.result.EntriesSeries $entry.Id -}} - {{- if $srels -}} -
-
Reihen
-
- {{- range $_, $rel := $srels -}} - {{- $s := index $model.result.Series $rel.Series -}} - {{- if $s -}} -
- {{- if not (eq $rel.Type "Bevorzugter Reihentitel") -}} - {{ $rel.Type }} - {{- end -}} - {{ $s.Title }} -
- {{- end -}} - {{- end -}} -
-
- {{- end -}} - {{- if $entry.Places -}} -
-
Orte
-
- {{- $sep := false -}} - {{- range $_, $pid := $entry.Places -}} - {{- $p := index $model.result.Places $pid -}} - {{- if $p -}} - {{- if $sep }}, {{ end -}} - {{ $p.Name }} - {{- $sep = true -}} - {{- end -}} - {{- end -}} -
-
- {{- end -}} - {{- $arels := index $model.result.EntriesAgents $entry.Id -}} - {{- if $arels -}} -
-
Personen
-
- {{- range $_, $arel := $arels -}} - {{- $a := index $model.result.Agents $arel.Agent -}} - {{- if $a -}} -
- {{ $a.Name }} - {{ $arel.Type }} -
- {{- end -}} - {{- end -}} -
-
- {{- end -}} -
-
- {{- if $entry.Comment -}} -
-
Kommentar
-
{{ $entry.Comment }}
-
- {{- end -}} - {{- if $entry.Language -}} -
-
Sprachen
-
- {{- range $i, $lang := $entry.Language -}}{{- if $i }}, {{ end -}}{{ LanguageNameGerman $lang }}{{- end -}} -
-
- {{- end -}} - {{- if or $entry.Extent $entry.Dimensions -}} -
-
Umfang / Maße
-
- {{- if $entry.Extent -}}
Struktur{{ $entry.Extent }}
{{- end -}} - {{- if $entry.Dimensions -}}
Maße: {{ $entry.Dimensions }}
{{- end -}} -
-
- {{- end -}} - {{- if $entry.References -}} -
-
Nachweise
-
{{ $entry.References }}
-
- {{- end -}} - {{- if ne $entry.Year 0 -}} -
-
Jahr
-
{{ $entry.Year }}
-
- {{- end -}} - {{- $items := index $model.result.Items $entry.Id -}} - {{- if $items -}} -
-
Exemplare
-
- {{- range $_, $item := $items -}} -
-
-
- {{- if $item.Identifier -}} -
{{ $item.Identifier }}
- {{- end -}} - {{- if $item.Media -}} -
- {{- range $i, $media := $item.Media -}}{{- if $i }}, {{ end -}}{{ $media }}{{- end -}} -
- {{- end -}} -
-
- {{- if or $item.Location $item.Owner -}} -
- {{- if $item.Location -}}{{ $item.Location }}{{- end -}} - {{- if $item.Owner -}}{{ $item.Owner }}{{- end -}} -
- {{- end -}} -
-
- {{- if or $item.Location $item.Owner -}} -
- {{- if $item.Location -}}{{ $item.Location }}{{- end -}} - {{- if $item.Owner -}}{{ $item.Owner }}{{- end -}} -
- {{- end -}} -
- {{- end -}} -
-
- {{- end -}} -
-
- - {{- end -}} @@ -421,32 +195,5 @@ }); }); } - - document.querySelectorAll('[data-role="baende-row"]').forEach((row) => { - row.addEventListener("click", (event) => { - if (event.target.closest("a, button, form, tool-tip")) { - return; - } - const entryId = row.getAttribute("data-entry-id"); - if (!entryId) return; - const details = document.querySelector(`[data-role="baende-details"][data-entry-id="${entryId}"]`); - if (!details) return; - row.classList.add("hidden"); - details.classList.remove("hidden"); - }); - }); - - document.querySelectorAll('[data-role="baende-collapse"]').forEach((button) => { - button.addEventListener("click", (event) => { - event.stopPropagation(); - const entryId = button.getAttribute("data-entry-id"); - if (!entryId) return; - const row = document.querySelector(`[data-role="baende-row"][data-entry-id="${entryId}"]`); - const details = document.querySelector(`[data-role="baende-details"][data-entry-id="${entryId}"]`); - if (!row || !details) return; - row.classList.remove("hidden"); - details.classList.add("hidden"); - }); - }); })(); diff --git a/views/routes/baende/details/body.gohtml b/views/routes/baende/details/body.gohtml new file mode 100644 index 0000000..aafe8ce --- /dev/null +++ b/views/routes/baende/details/body.gohtml @@ -0,0 +1,239 @@ +{{ $result := .result }} +{{ $entry := $result.Entry }} + + +
+ Alm {{ $entry.MusenalmID }} + {{- if $entry.References -}} + {{ $entry.References }} + {{- end -}} +
+ + + + +
Ansehen
+
+ {{- if $result.IsAdmin -}} + + + + +
Bearbeiten
+
+
+ + + +
Löschen
+
+
+ {{- end -}} + + +
Zuklappen
+
+
+
+ + +
+
+
+ {{- if $entry.PreferredTitle -}} + {{ $entry.PreferredTitle }} + {{- else if ne $entry.Year 0 -}} + {{ $entry.Year }} + {{- else -}} + [o.J.] + {{- end -}} + + +
+ {{- if eq $entry.EditState "Unknown" -}} + Gesucht + {{- else if eq $entry.EditState "ToDo" -}} + Zu erledigen + {{- else if eq $entry.EditState "Review" -}} + Überprüfen + {{- else if eq $entry.EditState "Seen" -}} + Autopsiert + {{- else if eq $entry.EditState "Edited" -}} + Vollständig Erfasst + {{- else -}} + {{ $entry.EditState }} + {{- end -}} +
+
+
+
+
+
+ {{- if or $entry.TitleStmt $entry.SubtitleStmt $entry.VariantTitle $entry.ParallelTitle $entry.IncipitStmt -}} +
+
Titelangaben
+
+ {{- if $entry.TitleStmt -}}
Titel: {{ $entry.TitleStmt }}
{{- end -}} + {{- if $entry.SubtitleStmt -}}
Untertitel: {{ $entry.SubtitleStmt }}
{{- end -}} + {{- if $entry.VariantTitle -}}
Varianten: {{ $entry.VariantTitle }}
{{- end -}} + {{- if $entry.ParallelTitle -}}
Parallel: {{ $entry.ParallelTitle }}
{{- end -}} + {{- if $entry.IncipitStmt -}}
Incipit: {{ $entry.IncipitStmt }}
{{- end -}} +
+
+ {{- end -}} + {{- if or $entry.ResponsibilityStmt $entry.PublicationStmt $entry.PlaceStmt -}} +
+
Erscheinung
+
+ {{- if and $entry.ResponsibilityStmt (not (eq $entry.ResponsibilityStmt "unbezeichnet")) -}}
Herausgaberangabe: {{ $entry.ResponsibilityStmt }}
{{- end -}} + {{- if $entry.PublicationStmt -}}
Publikationsangabe: {{ $entry.PublicationStmt }}
{{- end -}} + {{- if $entry.PlaceStmt -}}
Ortsangabe: {{ $entry.PlaceStmt }}
{{- end -}} +
+
+ {{- end -}} + {{- if $entry.Annotation -}} +
+
Annotation
+
{{ $entry.Annotation }}
+
+ {{- end -}} + {{- if $result.SeriesRels -}} +
+
Reihen
+
+ {{- range $_, $rel := $result.SeriesRels -}} + {{- range $_, $s := $result.Series -}} + {{- if eq $s.Id $rel.Series -}} +
+ {{- if not (eq $rel.Type "Bevorzugter Reihentitel") -}} + {{ $rel.Type }} + {{- end -}} + {{ $s.Title }} +
+ {{- end -}} + {{- end -}} + {{- end -}} +
+
+ {{- end -}} + {{- if $entry.Places -}} +
+
Orte
+
+ {{- $sep := false -}} + {{- range $_, $p := $result.Places -}} + {{- if $sep }}, {{ end -}} + {{ $p.Name }} + {{- $sep = true -}} + {{- end -}} +
+
+ {{- end -}} + {{- if $result.AgentRels -}} +
+
Personen
+
+ {{- range $_, $arel := $result.AgentRels -}} + {{- range $_, $a := $result.Agents -}} + {{- if eq $a.Id $arel.Agent -}} +
+ {{ $a.Name }} + {{ $arel.Type }} +
+ {{- end -}} + {{- end -}} + {{- end -}} +
+
+ {{- end -}} +
+
+ {{- if $entry.Comment -}} +
+
Kommentar
+
{{ $entry.Comment }}
+
+ {{- end -}} + {{- if $entry.Language -}} +
+
Sprachen
+
+ {{- range $i, $lang := $entry.Language -}}{{- if $i }}, {{ end -}}{{ LanguageNameGerman $lang }}{{- end -}} +
+
+ {{- end -}} + {{- if or $entry.Extent $entry.Dimensions -}} +
+
Umfang / Maße
+
+ {{- if $entry.Extent -}}
Struktur{{ $entry.Extent }}
{{- end -}} + {{- if $entry.Dimensions -}}
Maße: {{ $entry.Dimensions }}
{{- end -}} +
+
+ {{- end -}} + {{- if $entry.References -}} +
+
Nachweise
+
{{ $entry.References }}
+
+ {{- end -}} + {{- if ne $entry.Year 0 -}} +
+
Jahr
+
{{ $entry.Year }}
+
+ {{- end -}} + {{- if $result.Items -}} +
+
Exemplare
+
+ {{- range $_, $item := $result.Items -}} +
+
+
+ {{- if $item.Identifier -}} +
{{ $item.Identifier }}
+ {{- end -}} + {{- if $item.Media -}} +
+ {{- range $i, $media := $item.Media -}}{{- if $i }}, {{ end -}}{{ $media }}{{- end -}} +
+ {{- end -}} +
+
+ {{- if or $item.Location $item.Owner -}} +
+ {{- if $item.Location -}}{{ $item.Location }}{{- end -}} + {{- if $item.Owner -}}{{ $item.Owner }}{{- end -}} +
+ {{- end -}} +
+
+ {{- if or $item.Location $item.Owner -}} +
+ {{- if $item.Location -}}{{ $item.Location }}{{- end -}} + {{- if $item.Owner -}}{{ $item.Owner }}{{- end -}} +
+ {{- end -}} +
+ {{- end -}} +
+
+ {{- end -}} +
+
+
+ + + diff --git a/views/routes/baende/details/head.gohtml b/views/routes/baende/details/head.gohtml new file mode 100644 index 0000000..e69de29 diff --git a/views/routes/baende/row/body.gohtml b/views/routes/baende/row/body.gohtml new file mode 100644 index 0000000..6ec0312 --- /dev/null +++ b/views/routes/baende/row/body.gohtml @@ -0,0 +1,160 @@ +{{ $entry := .entry }} +{{ $model := . }} + + +
+ Alm {{ $entry.MusenalmID }} + {{- if $entry.References -}} + {{ $entry.References }} + {{- end -}} +
+ + + + +
Ansehen
+
+ {{- if .is_admin -}} + + + + +
Bearbeiten
+
+
+ + + +
Löschen
+
+
+ {{- end -}} +
+
+ + +
+ {{- if $entry.PreferredTitle -}} + {{ $entry.PreferredTitle }} + {{- else if ne $entry.Year 0 -}} + {{ $entry.Year }} + {{- else -}} + [o.J.] + {{- end -}} + + +
+ {{- if eq $entry.EditState "Unknown" -}} + Gesucht + {{- else if eq $entry.EditState "ToDo" -}} + Zu erledigen + {{- else if eq $entry.EditState "Review" -}} + Überprüfen + {{- else if eq $entry.EditState "Seen" -}} + Autopsiert + {{- else if eq $entry.EditState "Edited" -}} + Vollständig Erfasst + {{- else -}} + {{ $entry.EditState }} + {{- end -}} +
+
+
+ {{- if $entry.TitleStmt -}} +
+ {{ $entry.TitleStmt }} +
+ {{- end -}} + {{- if or $entry.SubtitleStmt $entry.VariantTitle $entry.ParallelTitle $entry.IncipitStmt -}} +
+ {{- if $entry.SubtitleStmt -}} +
Untertitel: {{ $entry.SubtitleStmt }}
+ {{- end -}} + {{- if $entry.VariantTitle -}} +
Varianten: {{ $entry.VariantTitle }}
+ {{- end -}} + {{- if $entry.ParallelTitle -}} +
Parallel: {{ $entry.ParallelTitle }}
+ {{- end -}} + {{- if $entry.IncipitStmt -}} +
Incipit: {{ $entry.IncipitStmt }}
+ {{- end -}} +
+ {{- end -}} + + + {{- if or $entry.ResponsibilityStmt $entry.PublicationStmt $entry.PlaceStmt -}} +
+ {{- if and $entry.ResponsibilityStmt (not (eq $entry.ResponsibilityStmt "unbezeichnet")) -}} +
+
Herausgaberangabe
+
{{ $entry.ResponsibilityStmt }}
+
+ {{- end -}} + {{- if $entry.PublicationStmt -}} +
+
Publikationsangabe
+
{{ $entry.PublicationStmt }}
+
+ {{- end -}} + {{- if $entry.PlaceStmt -}} +
+
Ortsangabe
+
{{ $entry.PlaceStmt }}
+
+ {{- end -}} +
+ {{- end -}} + + + {{- if ne $entry.Year 0 -}} + {{ $entry.Year }} + {{- end -}} + + + {{- if $entry.Language -}} + {{- range $i, $lang := $entry.Language -}} + {{- if $i }}, {{ end -}}{{ LanguageNameGerman $lang }} + {{- end -}} + {{- end -}} + + + {{- if or $entry.Extent $entry.Dimensions -}} +
+ {{- if $entry.Extent -}} +
Struktur{{ $entry.Extent }}
+ {{- end -}} + {{- if $entry.Dimensions -}} +
Maße: {{ $entry.Dimensions }}
+ {{- end -}} +
+ {{- end -}} + + + {{- $items := .items -}} + {{- if $items -}} +
+ {{- range $_, $item := $items -}} +
+ {{- if $item.Identifier -}} +
{{ $item.Identifier }}
+ {{- end -}} + {{- if $item.Media -}} +
+ {{- range $i, $media := $item.Media -}}{{- if $i }}, {{ end -}}{{ $media }}{{- end -}} +
+ {{- end -}} +
+ {{- end -}} +
+ {{- end -}} + + diff --git a/views/routes/baende/row/head.gohtml b/views/routes/baende/row/head.gohtml new file mode 100644 index 0000000..e69de29