FEATURE: Beiträge auf der Almanach-Seite filtern

This commit is contained in:
Simon Martens
2025-03-07 14:10:59 +01:00
parent f01b7aa9ad
commit 1e37649a7a
4 changed files with 161 additions and 19 deletions

View File

@@ -11,7 +11,7 @@ import (
) )
const ( const (
URL_ALMANACH = "/almanach/{id}" URL_ALMANACH = "/almanach/{id}/"
TEMPLATE_ALMANACH = "/almanach/" TEMPLATE_ALMANACH = "/almanach/"
) )
@@ -35,11 +35,13 @@ func (p *AlmanachPage) Setup(router *router.Router[*core.RequestEvent], app core
router.GET(p.URL, func(e *core.RequestEvent) error { router.GET(p.URL, func(e *core.RequestEvent) error {
id := e.Request.PathValue("id") id := e.Request.PathValue("id")
data := make(map[string]interface{}) data := make(map[string]interface{})
result, err := NewAlmanachResult(app, id) filters := NewBeitraegeFilterParameters(e)
result, err := NewAlmanachResult(app, id, filters)
if err != nil { if err != nil {
engine.Response404(e, err, nil) engine.Response404(e, err, nil)
} }
data["result"] = result data["result"] = result
data["filters"] = filters
abbrs, err := pagemodels.GetAbks(app) abbrs, err := pagemodels.GetAbks(app)
if err == nil { if err == nil {
@@ -62,11 +64,11 @@ type AlmanachResult struct {
EntriesAgents []*dbmodels.REntriesAgents EntriesAgents []*dbmodels.REntriesAgents
ContentsAgents map[string][]*dbmodels.RContentsAgents // <- Key is content id ContentsAgents map[string][]*dbmodels.RContentsAgents // <- Key is content id
CInfoByCollection map[string]dbmodels.CollectionInfo Types []string
CInfoByContent map[int][]dbmodels.CollectionInfo HasScans bool
} }
func NewAlmanachResult(app core.App, id string) (*AlmanachResult, error) { func NewAlmanachResult(app core.App, id string, params BeitraegeFilterParameters) (*AlmanachResult, error) {
// INFO: what about sql.ErrNoRows? // INFO: what about sql.ErrNoRows?
// We don't get sql.ErrNoRows here, since dbx converts every empty slice or // We don't get sql.ErrNoRows here, since dbx converts every empty slice or
// empty id to a WHERE 0=1 query, which will not error. // empty id to a WHERE 0=1 query, which will not error.
@@ -102,6 +104,33 @@ func NewAlmanachResult(app core.App, id string) (*AlmanachResult, error) {
return nil, err return nil, err
} }
types := Types_Contents(contents)
hs := HasScans(contents)
if params.OnlyScans {
cscans := []*dbmodels.Content{}
for _, c := range contents {
if len(c.Scans()) > 0 {
cscans = append(cscans, c)
}
}
contents = cscans
}
if params.Type != "" {
cfiltered := []*dbmodels.Content{}
outer:
for _, c := range contents {
for _, t := range c.MusenalmType() {
if t == params.Type {
cfiltered = append(cfiltered, c)
continue outer
}
}
}
contents = cfiltered
}
dbmodels.Sort_Contents_Numbering(contents) dbmodels.Sort_Contents_Numbering(contents)
contentsagents, err := dbmodels.RContentsAgents_Contents(app, dbmodels.Ids(contents)) contentsagents, err := dbmodels.RContentsAgents_Contents(app, dbmodels.Ids(contents))
@@ -140,6 +169,8 @@ func NewAlmanachResult(app core.App, id string) (*AlmanachResult, error) {
EntriesSeries: srelationsMap, EntriesSeries: srelationsMap,
EntriesAgents: entriesagents, EntriesAgents: entriesagents,
ContentsAgents: caMap, ContentsAgents: caMap,
Types: types,
HasScans: hs,
} }
ret.Collections() ret.Collections()
@@ -158,5 +189,29 @@ func (r *AlmanachResult) Collections() {
} }
} }
} }
}
func Types_Contents(contents []*dbmodels.Content) []string {
types := map[string]bool{}
for _, c := range contents {
for _, t := range c.MusenalmType() {
types[t] = true
}
}
ret := make([]string, 0, len(types))
for t, _ := range types {
ret = append(ret, t)
}
return ret
}
func HasScans(contents []*dbmodels.Content) bool {
for _, c := range contents {
if len(c.Scans()) > 0 {
return true
}
}
return false
} }

File diff suppressed because one or more lines are too long

View File

@@ -66,21 +66,108 @@
<div class="flex relative justify-center"> <div class="flex relative justify-center">
<div class="-translate-y-[50%] flex flex-col items-center"> <div class="-translate-y-[50%] flex flex-col items-center">
<h2 class="relative bg-stone-50 px-5 font-bold text-3xl w-max mb-1">Inhalt</h2> <h2 class="relative bg-stone-50 px-5 font-bold text-3xl w-max mb-1">Inhalt</h2>
<div class="bg-stone-200 text-sm px-3 py-0.5 rounded mt-1"> <div class="flex flex-row justify-center">
<b>{{- len $model.result.Contents }}</b> erfasste Beiträge &middot; <div class="bg-stone-200 text-sm px-3 py-0.5 rounded mt-1">
<i class="ri-sort-number-asc"></i> Anzeige nach Reihenfolge {{- if $model.filters.Type -}}
{{- $i := len $model.result.Contents -}}
{{- if eq $i 1 -}}
<b>{{- $i }}</b> Beitrag der Kategorie <b>{{ $model.filters.Type }}</b> &middot;
{{- else -}}
<b>{{- $i }}</b> Beiträge der Kategorie <b>{{ $model.filters.Type }}</b> &middot;
{{- end -}}
{{- else if $model.filters.OnlyScans -}}
<i class="ri-image-line"></i>&nbsp;
{{- $i := len $model.result.Contents -}}
{{- if eq $i 1 -}}
<b>{{- $i }} Digitalisat &middot; </b>
{{- else -}}
<b>{{- $i }} Digitalisate &middot;</b>
{{- end -}}
{{- else -}}
{{- if eq (len $model.result.Contents) 1 -}}
<b>{{- len $model.result.Contents }}</b> erfasster Beitrag &middot;
{{- else -}}
<b>{{- len $model.result.Contents }}</b> erfasste Beiträge &middot;
{{- end -}}
{{- end -}}
<i class="ri-sort-number-asc"></i> Anzeige nach Reihenfolge
</div>
{{- if or $model.filters.Type $model.filters.OnlyScans -}}
<div class="flex flex-row items-center justify-center ml-2.5">
<div class="block bg-stone-200 text-sm px-3 py-0.5 rounded mt-1">
<i class="ri-arrow-left-long-line"></i>
<a
href="./"
hx-target="#almanachcontents"
hx-select="#almanachcontents"
hx-swap="outerHTML show:none"
hx-indicator="body">
Alle Beiträge anzeigen
</a>
</div>
</div>
{{- end -}}
</div> </div>
</div> </div>
</div> </div>
<div class="flex justify-center"></div> <div>
<div class="mt-8"> <div class="flex flex-row justify-end">
{{- range $i, $c := $model.result.Contents -}} {{- if gt (len $model.result.Types) 1 -}}
{{- $rels := index $model.result.ContentsAgents $c.Id -}} <div>
{{- $coll := index $model.result.CInfoByContent $c.MusenalmID -}} <label
{{- if and $coll (index $coll 0) -}} for="typefilter"
class="align-baseline h-min self-end pb-1 mr-1.5 text-sm font-sans text-stone-700">
Kategorie
</label>
<select
class="h-min pb-1 border-b-4 border-zinc-300 px-1.5 mr-8"
name="typefilter"
id="typefilter"
autocomplete="off"
hx-get="./"
trigger="change"
hx-indicator="body"
hx-select="#almanachcontents"
hx-target="#almanachcontents"
hx-swap="outerHTML show:none">
<option value="">Alle</option>
{{- range $i, $t := $model.result.Types -}}
<option value="{{- $t -}}" {{- if eq $model.filters.Type $t -}}selected{{- end -}}>
{{- $t -}}
</option>
{{- end -}}
</select>
</div>
{{- end -}} {{- end -}}
{{- template "_content" Arr $c $model.result.Entry $rels $model.result.Agents -}} {{- if and $model.result.HasScans (gt (len $model.result.Contents) 1) -}}
{{- end -}} <div>
<label
for="onlyscans"
class="align-baseline h-min self-end pb-1 mr-1.5 text-sm font-sans text-stone-700">
Nur Digitalisate anzeigen
</label>
<input
class=""
type="checkbox"
id="onlyscans"
name="onlyscans"
autocomplete="off"
hx-get="./"
trigger="change"
hx-select="#almanachcontents"
hx-target="#almanachcontents"
hx-swap="outerHTML show:none"
hx-indicator="body"
{{ if $model.filters.OnlyScans -}}checked{{- end -}} />
</div>
{{- end -}}
</div>
<div class="mt-8">
{{- range $i, $c := $model.result.Contents -}}
{{- $rels := index $model.result.ContentsAgents $c.Id -}}
{{- template "_content" Arr $c $model.result.Entry $rels $model.result.Agents -}}
{{- end -}}
</div>
</div> </div>
</div> </div>
{{- end -}} {{- end -}}

View File

@@ -1,5 +1,5 @@
{{ if and .result .result.Entry }} {{ if and .result .result.Entry }}
<title>Musenalm &ndash; result.Entry.PreferredTitle</title> <title>Musenalm &ndash; {{ .result.Entry.PreferredTitle -}}</title>
<meta name="description" content="Almanach: {{ .result.Entry.PreferredTitle }}" /> <meta name="description" content="Almanach: {{ .result.Entry.PreferredTitle }}" />
{{ else }} {{ else }}
<title>Musenalm &ndash; Almanach</title> <title>Musenalm &ndash; Almanach</title>