mirror of
https://github.com/Theodor-Springmann-Stiftung/musenalm.git
synced 2025-10-29 01:05:32 +00:00
Einzelbeitragsansicht
This commit is contained in:
@@ -58,6 +58,15 @@ func RContentsAgents_Contents(app core.App, id []any) ([]*RContentsAgents, error
|
||||
)
|
||||
}
|
||||
|
||||
func RContentsAgents_Content(app core.App, id string) ([]*RContentsAgents, error) {
|
||||
return TableByFields[[]*RContentsAgents](
|
||||
app,
|
||||
RelationTableName(CONTENTS_TABLE, AGENTS_TABLE),
|
||||
CONTENTS_TABLE,
|
||||
id,
|
||||
)
|
||||
}
|
||||
|
||||
func REntriesSeries_Entries(app core.App, ids []any) ([]*REntriesSeries, error) {
|
||||
return TableByFields[[]*REntriesSeries](
|
||||
app,
|
||||
@@ -139,6 +148,11 @@ func Contents_Entry(app core.App, id string) ([]*Content, error) {
|
||||
)
|
||||
}
|
||||
|
||||
func Contents_MusenalmID(app core.App, id string) (*Content, error) {
|
||||
ret, err := TableByField[Content](app, CONTENTS_TABLE, MUSENALMID_FIELD, id)
|
||||
return &ret, err
|
||||
}
|
||||
|
||||
func Places_ID(app core.App, id string) (*Place, error) {
|
||||
ret, err := TableByField[Place](app, PLACES_TABLE, ID_FIELD, id)
|
||||
return &ret, err
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package pagemodels
|
||||
|
||||
const (
|
||||
P_BEITRAG_NAME = "beitrag"
|
||||
P_DATENSCHUTZ_NAME = "datenschutz"
|
||||
|
||||
P_SUCHE_NAME = "suche"
|
||||
|
||||
@@ -19,6 +19,9 @@ func init() {
|
||||
rp := &AlmanachPage{
|
||||
StaticPage: pagemodels.StaticPage{
|
||||
Name: pagemodels.P_REIHEN_NAME,
|
||||
URL: URL_ALMANACH,
|
||||
Template: TEMPLATE_ALMANACH,
|
||||
Layout: templating.DEFAULT_LAYOUT_NAME,
|
||||
},
|
||||
}
|
||||
app.Register(rp)
|
||||
@@ -29,40 +32,26 @@ type AlmanachPage struct {
|
||||
}
|
||||
|
||||
func (p *AlmanachPage) Setup(router *router.Router[*core.RequestEvent], app core.App, engine *templating.Engine) error {
|
||||
router.GET(URL_ALMANACH, func(e *core.RequestEvent) error {
|
||||
router.GET(p.URL, func(e *core.RequestEvent) error {
|
||||
id := e.Request.PathValue("id")
|
||||
data := make(map[string]interface{})
|
||||
result, err := NewAlmanachResult(app, id)
|
||||
if err != nil {
|
||||
engine.Response404(e, err, nil)
|
||||
}
|
||||
|
||||
data["result"] = result
|
||||
err = p.getAbbr(app, data)
|
||||
if err != nil {
|
||||
return engine.Response404(e, err, data)
|
||||
|
||||
abbrs, err := pagemodels.GetAbks(app)
|
||||
if err == nil {
|
||||
data["abbrs"] = abbrs
|
||||
}
|
||||
|
||||
return p.Get(e, engine, data)
|
||||
return engine.Response200(e, p.Template, data)
|
||||
})
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *AlmanachPage) getAbbr(app core.App, data map[string]interface{}) error {
|
||||
abbrs, err := pagemodels.GetAbks(app)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
data["abbrs"] = abbrs
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *AlmanachPage) Get(request *core.RequestEvent, engine *templating.Engine, data map[string]interface{}) error {
|
||||
return engine.Response200(request, TEMPLATE_ALMANACH, data)
|
||||
}
|
||||
|
||||
type AlmanachResult struct {
|
||||
Entry *dbmodels.Entry
|
||||
Places []*dbmodels.Place
|
||||
|
||||
140
pages/beitrag.go
Normal file
140
pages/beitrag.go
Normal file
@@ -0,0 +1,140 @@
|
||||
package pages
|
||||
|
||||
import (
|
||||
"github.com/Theodor-Springmann-Stiftung/musenalm/app"
|
||||
"github.com/Theodor-Springmann-Stiftung/musenalm/dbmodels"
|
||||
"github.com/Theodor-Springmann-Stiftung/musenalm/helpers/datatypes"
|
||||
"github.com/Theodor-Springmann-Stiftung/musenalm/pagemodels"
|
||||
"github.com/Theodor-Springmann-Stiftung/musenalm/templating"
|
||||
"github.com/pocketbase/pocketbase/core"
|
||||
"github.com/pocketbase/pocketbase/tools/router"
|
||||
)
|
||||
|
||||
const (
|
||||
URL_BEITRAG = "/beitrag/{id}"
|
||||
TEMPLATE_BEITRAG = "/beitrag/"
|
||||
)
|
||||
|
||||
func init() {
|
||||
rp := &BeitragPage{
|
||||
StaticPage: pagemodels.StaticPage{
|
||||
Name: pagemodels.P_BEITRAG_NAME,
|
||||
URL: URL_BEITRAG,
|
||||
Template: TEMPLATE_BEITRAG,
|
||||
Layout: templating.DEFAULT_LAYOUT_NAME,
|
||||
},
|
||||
}
|
||||
app.Register(rp)
|
||||
}
|
||||
|
||||
type BeitragPage struct {
|
||||
pagemodels.StaticPage
|
||||
}
|
||||
|
||||
func (p *BeitragPage) Setup(router *router.Router[*core.RequestEvent], app core.App, engine *templating.Engine) error {
|
||||
router.GET(p.URL, func(e *core.RequestEvent) error {
|
||||
id := e.Request.PathValue("id")
|
||||
data := make(map[string]interface{})
|
||||
result, err := NewBeitragResult(app, id)
|
||||
if err != nil {
|
||||
engine.Response404(e, err, nil)
|
||||
}
|
||||
data["result"] = result
|
||||
|
||||
abbrs, err := pagemodels.GetAbks(app)
|
||||
if err == nil {
|
||||
data["abbrs"] = abbrs
|
||||
}
|
||||
|
||||
return engine.Response200(e, p.Template, data)
|
||||
})
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
type BeitragResult struct {
|
||||
Entry *dbmodels.Entry
|
||||
Places []*dbmodels.Place
|
||||
Series []*dbmodels.Series
|
||||
Content *dbmodels.Content
|
||||
Agents map[string]*dbmodels.Agent // <- Key is agent id
|
||||
EntriesSeries map[string]*dbmodels.REntriesSeries // <- Key is series id
|
||||
EntriesAgents []*dbmodels.REntriesAgents
|
||||
ContentsAgents []*dbmodels.RContentsAgents // <- Key is content id
|
||||
}
|
||||
|
||||
func NewBeitragResult(app core.App, id string) (*BeitragResult, error) {
|
||||
content, err := dbmodels.Contents_MusenalmID(app, id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
entry, err := dbmodels.Entries_ID(app, content.Entry())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
places, err := dbmodels.Places_IDs(app, datatypes.ToAny(entry.Places()))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
srelations, err := dbmodels.REntriesSeries_Entry(app, entry.Id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
sids := []any{}
|
||||
srelationsMap := make(map[string]*dbmodels.REntriesSeries)
|
||||
for _, s := range srelations {
|
||||
sids = append(sids, s.Series())
|
||||
srelationsMap[s.Series()] = s
|
||||
}
|
||||
|
||||
series, err := dbmodels.Series_IDs(app, sids)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
arelations, err := dbmodels.REntriesAgents_Entry(app, entry.Id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
acrelations, err := dbmodels.RContentsAgents_Content(app, content.Id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
aids := []any{}
|
||||
arelationsMap := make(map[string]*dbmodels.REntriesAgents)
|
||||
for _, r := range arelations {
|
||||
aids = append(aids, r.Agent())
|
||||
arelationsMap[r.Agent()] = r
|
||||
}
|
||||
|
||||
for _, r := range acrelations {
|
||||
aids = append(aids, r.Agent())
|
||||
}
|
||||
|
||||
agents, err := dbmodels.Agents_IDs(app, aids)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
agentsMap := make(map[string]*dbmodels.Agent)
|
||||
for _, a := range agents {
|
||||
agentsMap[a.Id] = a
|
||||
}
|
||||
|
||||
return &BeitragResult{
|
||||
Entry: entry,
|
||||
Places: places,
|
||||
Series: series,
|
||||
Content: content,
|
||||
Agents: agentsMap,
|
||||
EntriesSeries: srelationsMap,
|
||||
EntriesAgents: arelations,
|
||||
ContentsAgents: acrelations,
|
||||
}, nil
|
||||
}
|
||||
@@ -60,8 +60,19 @@
|
||||
|
||||
{{ template "entrydata" $model }}
|
||||
|
||||
|
||||
<div class="container-oversize" id="almanachcontents">
|
||||
{{- if $model.result.Contents | len -}}
|
||||
<div class="container-oversize mt-0 pt-0" id="almanachcontents">
|
||||
<div class="flex relative justify-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>
|
||||
<div class="bg-stone-200 text-sm px-3 py-0.5 rounded mt-1">
|
||||
<b>{{- len $model.result.Contents }}</b> erfasste Beiträge ·
|
||||
<i class="ri-sort-number-asc"></i> Anzeige nach Reihenfolge
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex justify-center"></div>
|
||||
<div class="mt-8">
|
||||
{{- range $i, $c := $model.result.Contents -}}
|
||||
{{- $rels := index $model.result.ContentsAgents $c.Id -}}
|
||||
{{- $coll := index $model.result.CInfoByContent $c.MusenalmID -}}
|
||||
@@ -69,4 +80,6 @@
|
||||
{{- end -}}
|
||||
{{- template "_content" Arr $c $model.result.Entry $rels $model.result.Agents -}}
|
||||
{{- end -}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{- end -}}
|
||||
|
||||
@@ -15,13 +15,14 @@
|
||||
{{ $isFra := false }}
|
||||
{{ $isEng := false }}
|
||||
|
||||
{{- $hasContents := len $model.result.Contents -}}
|
||||
|
||||
<div class="container-oversize mt-12">
|
||||
|
||||
<div class="container-oversize mt-12 pb-0 mb-0">
|
||||
<div class="pb-1.5 ml-32"><i class="ri-book-line"></i> Almanach</div>
|
||||
<div class=" border relative pt-0">
|
||||
<div class="ml-32 relative pt-2 bg-stone-50 mt-0 w-max flex flex-col"></div>
|
||||
<div class="container-normal !py-8" id="">
|
||||
<div class="flex flex-col" id="entrydata">
|
||||
<div class="pt-0 {{ if $hasContents -}}contentsentrydata{{- end -}}" id="entrydata">
|
||||
<div class="container-normal !py-8">
|
||||
<div class="flex flex-col">
|
||||
<div class="entryrow">
|
||||
<div class="fieldlabel">Almanach-Nummer</div>
|
||||
<div class="fieldvalue">{{ $model.result.Entry.MusenalmID }}</div>
|
||||
|
||||
64
views/routes/beitrag/body.gohtml
Normal file
64
views/routes/beitrag/body.gohtml
Normal file
@@ -0,0 +1,64 @@
|
||||
{{- $model := . }}
|
||||
{{/* type BeitragResult struct {
|
||||
Entry *dbmodels.Entry
|
||||
Places []*dbmodels.Place
|
||||
Series []*dbmodels.Series
|
||||
Content *dbmodels.Content
|
||||
Agents map[string]*dbmodels.Agent // <- Key is agent id
|
||||
EntriesSeries map[string]*dbmodels.REntriesSeries // <- Key is series id
|
||||
EntriesAgents []*dbmodels.REntriesAgents
|
||||
ContentsAgents []*dbmodels.RContentsAgents // <- Key is content id
|
||||
}
|
||||
*/}}
|
||||
|
||||
|
||||
<div id="breadcrumbs">
|
||||
<div>
|
||||
<div class="">Almanache <i class="ri-arrow-right-wide-line"></i></div>
|
||||
<div>
|
||||
<a href="/almanach/{{- $model.result.Entry.MusenalmID -}}">
|
||||
{{- $model.result.Entry.PreferredTitle -}}
|
||||
</a>
|
||||
</div>
|
||||
<div>
|
||||
<i class="ri-arrow-right-wide-line"></i>Beitrag Nr.
|
||||
<b>{{ $model.result.Content.MusenalmID }}</b>
|
||||
</div>
|
||||
<div class="grow"></div>
|
||||
<div class="backbutton">
|
||||
<a href="/almanach/{{- $model.result.Entry.MusenalmID -}}" class="no-underline">
|
||||
<i class="ri-arrow-left-long-line"></i> Zum Almanach
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="container-normal mt-12 flex flex-col font-serif">
|
||||
<div class="font-sans"><i class="ri-article-line"></i> Einzelbeitrag</div>
|
||||
<h1 class="text-3xl font-bold">
|
||||
{{ $model.result.Entry.PreferredTitle }},
|
||||
{{ if $model.result.Content.Extent -}}
|
||||
S.
|
||||
{{ $model.result.Content.Extent }}
|
||||
{{ else -}}
|
||||
Nr.
|
||||
{{ $model.result.Content.MusenalmID }}
|
||||
{{- end -}}
|
||||
</h1>
|
||||
<span class="">
|
||||
{{- $arr := $model.result.Content.MusenalmType -}}
|
||||
{{- if $arr -}}
|
||||
{{- range $i, $p := $arr -}}
|
||||
<span
|
||||
class="inline-block align-middle bg-slate-200 px-2 font-sans text-sm py-0.5
|
||||
rounded mx-1 mt-1.5 hover:text-slate-900 no-underline">
|
||||
{{- $p -}}
|
||||
</span>
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
</span>
|
||||
|
||||
<div class="mt-7">
|
||||
{{- template "_content" Arr $model.result.Content $model.result.Entry $model.result.ContentsAgents $model.result.Agents true -}}
|
||||
</div>
|
||||
</div>
|
||||
@@ -3,6 +3,7 @@
|
||||
.2 - *Entry
|
||||
.3 - []*RContentsAgents
|
||||
.4 - map[string]*Agent
|
||||
.5 bool SingleView
|
||||
*/}}
|
||||
|
||||
{{- $content := index . 0 -}}
|
||||
@@ -10,8 +11,14 @@
|
||||
{{- $rcas := index . 2 -}}
|
||||
{{- $agents := index . 3 -}}
|
||||
|
||||
{{- $singleView := false -}}
|
||||
{{- if gt (len .) 4 -}}
|
||||
{{- $singleView = index . 4 -}}
|
||||
{{- end -}}
|
||||
|
||||
|
||||
<div class="content flex flex-row font-serif" id="{{- $content.Id -}}">
|
||||
{{- if not $singleView -}}
|
||||
<div class="w-36 shrink-0 grow-0 flex flex-col items-end columnone">
|
||||
{{- if $content.Extent -}}
|
||||
<div>
|
||||
@@ -28,11 +35,24 @@
|
||||
{{- end -}}
|
||||
</div>
|
||||
{{- end -}}
|
||||
|
||||
</div>
|
||||
{{- end -}}
|
||||
|
||||
|
||||
<div class="grow columntwo">
|
||||
<div class="fields">
|
||||
{{- if $singleView -}}
|
||||
<div class="fieldlabel">Almanach</div>
|
||||
<div class="fieldvalue">
|
||||
<a href="/almanach/{{- $entry.MusenalmID -}}">
|
||||
{{- $entry.PreferredTitle -}}
|
||||
</a>
|
||||
{{- if $content.Extent -}}
|
||||
, <span class="font-sans text-sm">S. </span>
|
||||
<b>{{- $content.Extent -}}</b>
|
||||
{{- end -}}
|
||||
</div>
|
||||
{{- end -}}
|
||||
{{- if $content.TitleStmt -}}
|
||||
<div class="fieldlabel">Titel</div>
|
||||
<div class="italic fieldvalue">{{- $content.TitleStmt -}}</div>
|
||||
@@ -48,17 +68,15 @@
|
||||
{{- if $rcas -}}
|
||||
<div class="fieldlabel">Personen</div>
|
||||
<div class="fieldvalue">
|
||||
<div class="flex flex-col">
|
||||
{{- range $_, $rca := $rcas -}}
|
||||
<div class="flex flex-col gap-y-2">
|
||||
{{- $agent := index $agents $rca.Agent -}}
|
||||
{{- if $agent -}}
|
||||
<div class="font-sans text-base bg-stone-100 px-1 py-0.5 rounded w-max mb-1">
|
||||
<div class="font-sans text-base bg-stone-100 px-1 py-0.5 rounded w-max">
|
||||
<a href="/person/{{- $agent.Id -}}">{{- $agent.Name -}}</a>
|
||||
({{ $agent.BiographicalData -}})
|
||||
</div>
|
||||
{{- end -}}
|
||||
</div>
|
||||
{{- end -}}
|
||||
</div>
|
||||
{{- end -}}
|
||||
{{- if $content.Annotation -}}
|
||||
@@ -72,6 +90,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{- if not $singleView -}}
|
||||
{{- $scans := $content.ImagePaths -}}
|
||||
{{- $slen := len $scans -}}
|
||||
{{- $double := false -}}
|
||||
@@ -109,10 +128,37 @@
|
||||
</div>
|
||||
<div class="font-sans py-0.5 text-xs">
|
||||
<a
|
||||
href="/beitreag/{{ $content.MusenalmID }}"
|
||||
href="/beitrag/{{ $content.MusenalmID }}"
|
||||
class="no-underline rounded bg-stone-100 px-1.5">
|
||||
<i class="ri-links-line"></i> Permalink
|
||||
Einzelansicht <i class="ri-links-line"></i>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
{{- end -}}
|
||||
</div>
|
||||
|
||||
{{- if $singleView -}}
|
||||
{{- $scans := $content.ImagePaths -}}
|
||||
{{- $slen := len $scans -}}
|
||||
{{- $double := false -}}
|
||||
{{- if gt $slen 2 -}}
|
||||
{{- $double = true -}}
|
||||
{{- end -}}
|
||||
<div class="">
|
||||
{{- if $scans -}}
|
||||
<div class="flex flex-row row-auto gap-4 mt-6 flex-wrap">
|
||||
{{- range $i, $scan := $scans -}}
|
||||
<div
|
||||
class="transition-all duration-75
|
||||
border-zinc-100 overflow-hidden">
|
||||
<popup-image data-image-url="{{- $scan -}}">
|
||||
<img
|
||||
src="{{- $scan -}}?thumb=0x1000"
|
||||
class="max-h-[32rem] border-6 hover:border-zinc-400 object-cover cursor-pointer" />
|
||||
</popup-image>
|
||||
</div>
|
||||
{{- end -}}
|
||||
</div>
|
||||
{{- end -}}
|
||||
</div>
|
||||
{{- end -}}
|
||||
|
||||
@@ -361,6 +361,25 @@
|
||||
}
|
||||
|
||||
#entrydata {
|
||||
@apply relative;
|
||||
}
|
||||
|
||||
#entrydata:not(#entrydata.contentsentrydata) {
|
||||
@apply border border-zinc-300;
|
||||
}
|
||||
|
||||
#entrydata.contentsentrydata {
|
||||
@apply border-t border-r border-zinc-300 pb-16;
|
||||
}
|
||||
|
||||
#entrydata.contentsentrydata:after {
|
||||
content: "";
|
||||
@apply absolute top-0 left-0 w-[1px] h-[50%] bg-zinc-300;
|
||||
}
|
||||
|
||||
#entrydata.contentsentrydata:before {
|
||||
content: "";
|
||||
@apply absolute bottom-0 right-0 h-[1px] w-[50%] bg-zinc-300;
|
||||
}
|
||||
|
||||
int-link {
|
||||
|
||||
Reference in New Issue
Block a user