mirror of
https://github.com/Theodor-Springmann-Stiftung/kgpz_web.git
synced 2025-10-28 16:45:32 +00:00
Some refinements; anonymous authors
This commit is contained in:
11
CLAUDE.md
11
CLAUDE.md
@@ -256,16 +256,15 @@ The application supports viewing pieces/articles that span multiple issues throu
|
|||||||
|
|
||||||
### URL Structure & Routing
|
### URL Structure & Routing
|
||||||
|
|
||||||
**URL Pattern**: `/beitrag/:id` where ID format is `YYYY-NNN-PPP` (year-issue-page)
|
**URL Pattern**: `/beitrag/:id` where ID is the piece's XML ID
|
||||||
- **Example**: `/beitrag/1768-020-079` (piece starting at year 1768, issue 20, page 79)
|
- **Example**: `/beitrag/piece-abc123` (piece with XML ID "piece-abc123")
|
||||||
- **Route Definition**: `PIECE_URL = "/beitrag/:id"` in `app/kgpz.go`
|
- **Route Definition**: `PIECE_URL = "/beitrag/:id"` in `app/kgpz.go`
|
||||||
- **Controller**: `controllers.GetPiece(k.Library)` handles piece lookup and rendering
|
- **Controller**: `controllers.GetPiece(k.Library)` handles piece lookup and rendering
|
||||||
|
|
||||||
### Architecture & Components
|
### Architecture & Components
|
||||||
|
|
||||||
**Controller** (`controllers/piece_controller.go`):
|
**Controller** (`controllers/piece_controller.go`):
|
||||||
- Parses YYYY-NNN-PPP ID format using regex pattern matching
|
- Looks up pieces directly by XML ID
|
||||||
- Looks up pieces by year/issue/page when XML IDs aren't reliable
|
|
||||||
- Handles piece aggregation across multiple issues
|
- Handles piece aggregation across multiple issues
|
||||||
- Returns 404 for invalid IDs or non-existent pieces
|
- Returns 404 for invalid IDs or non-existent pieces
|
||||||
|
|
||||||
@@ -327,7 +326,7 @@ The application supports viewing pieces/articles that span multiple issues throu
|
|||||||
|
|
||||||
**Linking to Pieces**:
|
**Linking to Pieces**:
|
||||||
```gohtml
|
```gohtml
|
||||||
<a href="{{ GetPieceURL $piece.Reference.When.Year $piece.Reference.Nr $piece.Reference.Von }}">
|
<a href="{{ GetPieceURL $piece.ID }}">
|
||||||
gesamten beitrag anzeigen
|
gesamten beitrag anzeigen
|
||||||
</a>
|
</a>
|
||||||
```
|
```
|
||||||
@@ -342,7 +341,7 @@ The application supports viewing pieces/articles that span multiple issues throu
|
|||||||
|
|
||||||
### Error Handling
|
### Error Handling
|
||||||
|
|
||||||
**Invalid IDs**: Returns 404 for malformed YYYY-NNN-PPP format
|
**Invalid IDs**: Returns 404 for non-existent piece IDs
|
||||||
**Missing Pieces**: Returns 404 when piece lookup fails in XML data
|
**Missing Pieces**: Returns 404 when piece lookup fails in XML data
|
||||||
**Missing Images**: Graceful fallback with "Keine Bilder verfügbar" message
|
**Missing Images**: Graceful fallback with "Keine Bilder verfügbar" message
|
||||||
**Cross-Issue Navigation**: Handles pieces spanning non-consecutive issues
|
**Cross-Issue Navigation**: Handles pieces spanning non-consecutive issues
|
||||||
|
|||||||
10
app/kgpz.go
10
app/kgpz.go
@@ -202,6 +202,16 @@ func (k *KGPZ) Funcs() map[string]interface{} {
|
|||||||
e["LookupPieces"] = k.Library.Pieces.ReverseLookup
|
e["LookupPieces"] = k.Library.Pieces.ReverseLookup
|
||||||
e["LookupWorks"] = k.Library.Works.ReverseLookup
|
e["LookupWorks"] = k.Library.Works.ReverseLookup
|
||||||
e["LookupIssues"] = k.Library.Issues.ReverseLookup
|
e["LookupIssues"] = k.Library.Issues.ReverseLookup
|
||||||
|
e["LookupAnonymWorks"] = func() []xmlmodels.Work {
|
||||||
|
var anonymWorks []xmlmodels.Work
|
||||||
|
for _, work := range k.Library.Works.Array {
|
||||||
|
// Check if work has no agents
|
||||||
|
if len(work.AgentRefs) == 0 {
|
||||||
|
anonymWorks = append(anonymWorks, work)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return anonymWorks
|
||||||
|
}
|
||||||
|
|
||||||
return e
|
return e
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,6 +31,20 @@ func GetAgents(kgpz *xmlmodels.Library) fiber.Handler {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Handle special "anonym" route
|
||||||
|
if a == "anonym" {
|
||||||
|
anonymAgent := viewmodels.AnonymView(kgpz)
|
||||||
|
return c.Render(
|
||||||
|
"/akteure/",
|
||||||
|
fiber.Map{"model": &viewmodels.AgentsListView{
|
||||||
|
Search: "anonym",
|
||||||
|
AvailableLetters: []string{},
|
||||||
|
Agents: map[string]xmlmodels.Agent{"anonym": *anonymAgent},
|
||||||
|
Sorted: []string{"anonym"},
|
||||||
|
}},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
// Handle normal letter/id lookup
|
// Handle normal letter/id lookup
|
||||||
agents := viewmodels.AgentsView(a, kgpz)
|
agents := viewmodels.AgentsView(a, kgpz)
|
||||||
if len(agents.Agents) == 0 {
|
if len(agents.Agents) == 0 {
|
||||||
|
|||||||
@@ -19,26 +19,7 @@ func GetPiece(kgpz *xmlmodels.Library) fiber.Handler {
|
|||||||
return c.SendStatus(fiber.StatusNotFound)
|
return c.SendStatus(fiber.StatusNotFound)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse the generated ID format: YYYY-NNN-PPP
|
piece := kgpz.Pieces.Item(id)
|
||||||
var piece *xmlmodels.Piece
|
|
||||||
if strings.Contains(id, "-") {
|
|
||||||
parts := strings.Split(id, "-")
|
|
||||||
if len(parts) == 3 {
|
|
||||||
year, yearErr := strconv.Atoi(parts[0])
|
|
||||||
issueNum, issueErr := strconv.Atoi(parts[1])
|
|
||||||
page, pageErr := strconv.Atoi(parts[2])
|
|
||||||
|
|
||||||
if yearErr == nil && issueErr == nil && pageErr == nil {
|
|
||||||
piece = findPieceByYearIssuePage(kgpz, year, issueNum, page)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fallback to original ID lookup if generated ID doesn't work
|
|
||||||
if piece == nil {
|
|
||||||
piece = kgpz.Pieces.Item(id)
|
|
||||||
}
|
|
||||||
|
|
||||||
if piece == nil {
|
if piece == nil {
|
||||||
logging.Error(nil, "Piece could not be found with ID: "+id)
|
logging.Error(nil, "Piece could not be found with ID: "+id)
|
||||||
return c.SendStatus(fiber.StatusNotFound)
|
return c.SendStatus(fiber.StatusNotFound)
|
||||||
@@ -98,25 +79,7 @@ func GetPieceWithPage(kgpz *xmlmodels.Library) fiber.Handler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse the generated ID format: YYYY-NNN-PPP
|
piece := kgpz.Pieces.Item(id)
|
||||||
var piece *xmlmodels.Piece
|
|
||||||
if strings.Contains(id, "-") {
|
|
||||||
parts := strings.Split(id, "-")
|
|
||||||
if len(parts) == 3 {
|
|
||||||
year, yearErr := strconv.Atoi(parts[0])
|
|
||||||
issueNum, issueErr := strconv.Atoi(parts[1])
|
|
||||||
page, pageErr := strconv.Atoi(parts[2])
|
|
||||||
|
|
||||||
if yearErr == nil && issueErr == nil && pageErr == nil {
|
|
||||||
piece = findPieceByYearIssuePage(kgpz, year, issueNum, page)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fallback to original ID lookup if generated ID doesn't work
|
|
||||||
if piece == nil {
|
|
||||||
piece = kgpz.Pieces.Item(id)
|
|
||||||
}
|
|
||||||
|
|
||||||
if piece == nil {
|
if piece == nil {
|
||||||
logging.Error(nil, "Piece could not be found with ID: "+id)
|
logging.Error(nil, "Piece could not be found with ID: "+id)
|
||||||
@@ -155,17 +118,3 @@ func GetPieceWithPage(kgpz *xmlmodels.Library) fiber.Handler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// findPieceByYearIssuePage finds a piece that starts on the given year, issue, and page
|
|
||||||
func findPieceByYearIssuePage(kgpz *xmlmodels.Library, year, issueNum, page int) *xmlmodels.Piece {
|
|
||||||
kgpz.Pieces.Lock()
|
|
||||||
defer kgpz.Pieces.Unlock()
|
|
||||||
|
|
||||||
for _, piece := range kgpz.Pieces.Array {
|
|
||||||
for _, issueRef := range piece.IssueRefs {
|
|
||||||
if issueRef.When.Year == year && issueRef.Nr == issueNum && issueRef.Von == page {
|
|
||||||
return &piece
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
@@ -69,15 +69,9 @@ func PageIcon(iconType string) template.HTML {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetPieceURL generates a piece view URL from year, issue number, page, and optional piece ID
|
// GetPieceURL generates a piece view URL from piece ID
|
||||||
func GetPieceURL(year, issueNum, page int, pieceID ...string) string {
|
func GetPieceURL(pieceID string) string {
|
||||||
if len(pieceID) > 0 && pieceID[0] != "" && pieceID[0] != "0" {
|
return "/beitrag/" + pieceID
|
||||||
// Use just the piece ID (no year/issue prefix in URL)
|
|
||||||
return "/beitrag/" + pieceID[0]
|
|
||||||
}
|
|
||||||
// Fallback to old format for backward compatibility
|
|
||||||
id := fmt.Sprintf("%d-%03d-%03d", year, issueNum, page)
|
|
||||||
return "/beitrag/" + id
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// IssueContext formats an issue reference into a readable context string
|
// IssueContext formats an issue reference into a readable context string
|
||||||
|
|||||||
@@ -77,3 +77,12 @@ func AuthorsView(lib *xmlmodels.Library) *AgentsListView {
|
|||||||
|
|
||||||
return &res
|
return &res
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AnonymView creates a synthetic agent for works without associated authors
|
||||||
|
func AnonymView(lib *xmlmodels.Library) *xmlmodels.Agent {
|
||||||
|
return &xmlmodels.Agent{
|
||||||
|
Identifier: xmlmodels.Identifier{ID: "anonym"},
|
||||||
|
Names: []string{"anonym"},
|
||||||
|
Org: false, // person, not organization
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ class H extends HTMLElement {
|
|||||||
if (this.sections = document.querySelectorAll(".author-section"), this.navLinks = document.querySelectorAll(".scrollspy-link"), this.sections.length === 0 || this.navLinks.length === 0) {
|
if (this.sections = document.querySelectorAll(".author-section"), this.navLinks = document.querySelectorAll(".scrollspy-link"), this.sections.length === 0 || this.navLinks.length === 0) {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
this.sections = document.querySelectorAll(".author-section"), this.navLinks = document.querySelectorAll(".scrollspy-link"), this.sections.length > 0 && this.navLinks.length > 0 && this.initializeScrollspy();
|
this.sections = document.querySelectorAll(".author-section"), this.navLinks = document.querySelectorAll(".scrollspy-link"), this.sections.length > 0 && this.navLinks.length > 0 && this.initializeScrollspy();
|
||||||
}, 200);
|
}, 500);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.initializeScrollspy();
|
this.initializeScrollspy();
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -15,6 +15,20 @@
|
|||||||
|
|
||||||
|
|
||||||
<link href="/assets/css/remixicon.css" rel="stylesheet" />
|
<link href="/assets/css/remixicon.css" rel="stylesheet" />
|
||||||
|
<script>
|
||||||
|
// Configure HTMX scroll behavior
|
||||||
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
|
if (typeof htmx !== 'undefined') {
|
||||||
|
htmx.config.scrollBehavior = 'instant';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
// Fallback configuration
|
||||||
|
window.addEventListener('load', function() {
|
||||||
|
if (typeof htmx !== 'undefined') {
|
||||||
|
htmx.config.scrollBehavior = 'instant';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
<script src="/assets/js/alpine.min.js" defer></script>
|
<script src="/assets/js/alpine.min.js" defer></script>
|
||||||
<script src="/assets/js/htmx.min.js" defer></script>
|
<script src="/assets/js/htmx.min.js" defer></script>
|
||||||
<script src="/assets/js/htmx-response-targets.js" defer></script>
|
<script src="/assets/js/htmx-response-targets.js" defer></script>
|
||||||
|
|||||||
@@ -13,11 +13,18 @@
|
|||||||
<div class="max-w-7xl mx-auto px-8 py-8">
|
<div class="max-w-7xl mx-auto px-8 py-8">
|
||||||
<div class="bg-white px-6 py-6 rounded">
|
<div class="bg-white px-6 py-6 rounded">
|
||||||
<div class="mb-6">
|
<div class="mb-6">
|
||||||
{{ $letter := Upper (FirstLetter $agent.ID) }}
|
{{ if eq $agent.ID "anonym" }}
|
||||||
<a href="/akteure/{{ $letter }}" class="inline-flex items-center text-black hover:text-gray-700 transition-colors text-xl no-underline font-bold">
|
<a href="/akteure/a" class="inline-flex items-center text-black hover:text-gray-700 transition-colors text-xl no-underline font-bold">
|
||||||
<i class="ri-arrow-left-line mr-3 text-xl font-bold"></i>
|
<i class="ri-arrow-left-line mr-3 text-xl font-bold"></i>
|
||||||
{{ $letter }}
|
A
|
||||||
</a>
|
</a>
|
||||||
|
{{ else }}
|
||||||
|
{{ $letter := Upper (FirstLetter $agent.ID) }}
|
||||||
|
<a href="/akteure/{{ $letter }}" class="inline-flex items-center text-black hover:text-gray-700 transition-colors text-xl no-underline font-bold">
|
||||||
|
<i class="ri-arrow-left-line mr-3 text-xl font-bold"></i>
|
||||||
|
{{ $letter }}
|
||||||
|
</a>
|
||||||
|
{{ end }}
|
||||||
</div>
|
</div>
|
||||||
{{ template "_akteur" $agent }}
|
{{ template "_akteur" $agent }}
|
||||||
</div>
|
</div>
|
||||||
@@ -66,6 +73,13 @@
|
|||||||
<a href="/akteure/{{ $l }}" class="no-underline leading-none !m-0 !p-0 text-2xl font-medium text-gray-700 hover:text-red-600 transition-colors">{{ $l }}</a>
|
<a href="/akteure/{{ $l }}" class="no-underline leading-none !m-0 !p-0 text-2xl font-medium text-gray-700 hover:text-red-600 transition-colors">{{ $l }}</a>
|
||||||
{{ end }}
|
{{ end }}
|
||||||
{{ end }}
|
{{ end }}
|
||||||
|
<!-- Separator and Anonym link -->
|
||||||
|
<span class="text-gray-400 text-2xl">|</span>
|
||||||
|
{{ if eq $.model.Search "anonym" }}
|
||||||
|
<span class="no-underline leading-none !m-0 !p-0 text-4xl font-bold text-red-600 pointer-events-none" aria-current="true">anonym</span>
|
||||||
|
{{ else }}
|
||||||
|
<a href="/akteure/anonym" class="no-underline leading-none !m-0 !p-0 text-2xl font-medium text-gray-700 hover:text-red-600 transition-colors">anonym</a>
|
||||||
|
{{ end }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -93,7 +93,7 @@
|
|||||||
duration-200">
|
duration-200">
|
||||||
<i class="ri-file-copy-2-line text-xs"></i>
|
<i class="ri-file-copy-2-line text-xs"></i>
|
||||||
<a
|
<a
|
||||||
href="{{ GetPieceURL $individualPiece.PieceByIssue.Reference.When.Year $individualPiece.PieceByIssue.Reference.Nr $individualPiece.PieceByIssue.Reference.Von (index $individualPiece.PieceByIssue.Keys 0) }}"
|
href="{{ GetPieceURL $individualPiece.PieceByIssue.ID }}"
|
||||||
class="">
|
class="">
|
||||||
Ganzer Beitrag
|
Ganzer Beitrag
|
||||||
</a>
|
</a>
|
||||||
@@ -228,7 +228,7 @@
|
|||||||
duration-200">
|
duration-200">
|
||||||
<i class="ri-file-copy-2-line text-xs"></i>
|
<i class="ri-file-copy-2-line text-xs"></i>
|
||||||
<a
|
<a
|
||||||
href="{{ GetPieceURL $individualPiece.PieceByIssue.Reference.When.Year $individualPiece.PieceByIssue.Reference.Nr $individualPiece.PieceByIssue.Reference.Von (index $individualPiece.PieceByIssue.Keys 0) }}"
|
href="{{ GetPieceURL $individualPiece.PieceByIssue.ID }}"
|
||||||
class="">
|
class="">
|
||||||
Ganzer Beitrag
|
Ganzer Beitrag
|
||||||
</a>
|
</a>
|
||||||
|
|||||||
@@ -8,19 +8,12 @@
|
|||||||
</h2>
|
</h2>
|
||||||
</div>
|
</div>
|
||||||
<div class="space-y-2">
|
<div class="space-y-2">
|
||||||
{{- /* Group pieces by title and work reference */ -}}
|
{{- /* Group pieces by their own title/incipit, not by work being reviewed */ -}}
|
||||||
{{- $groupedPieces := dict -}}
|
{{- $groupedPieces := dict -}}
|
||||||
{{- range $_, $p := SortPiecesByDate $pieces -}}
|
{{- range $_, $p := SortPiecesByDate $pieces -}}
|
||||||
{{- $groupKey := "" -}}
|
{{- $groupKey := "" -}}
|
||||||
{{- if $p.Item.Title -}}
|
{{- if $p.Item.Title -}}
|
||||||
{{- $groupKey = index $p.Item.Title 0 -}}
|
{{- $groupKey = index $p.Item.Title 0 -}}
|
||||||
{{- else if $p.Item.WorkRefs -}}
|
|
||||||
{{- $work := GetWork (index $p.Item.WorkRefs 0).Ref -}}
|
|
||||||
{{- if $work.PreferredTitle -}}
|
|
||||||
{{- $groupKey = $work.PreferredTitle -}}
|
|
||||||
{{- else if $work.Citation.Title -}}
|
|
||||||
{{- $groupKey = $work.Citation.Title -}}
|
|
||||||
{{- end -}}
|
|
||||||
{{- else if $p.Item.Incipit -}}
|
{{- else if $p.Item.Incipit -}}
|
||||||
{{- $groupKey = index $p.Item.Incipit 0 -}}
|
{{- $groupKey = index $p.Item.Incipit 0 -}}
|
||||||
{{- else -}}
|
{{- else -}}
|
||||||
@@ -55,7 +48,7 @@
|
|||||||
{{- if gt (len $firstGroupItem.Item.IssueRefs) 1 -}}
|
{{- if gt (len $firstGroupItem.Item.IssueRefs) 1 -}}
|
||||||
{{ " " }}<div class="inline-flex items-center gap-1 px-2 py-1 bg-blue-50 hover:bg-blue-100 text-blue-700 hover:text-blue-800 border border-blue-200 hover:border-blue-300 rounded text-xs font-medium transition-colors duration-200">
|
{{ " " }}<div class="inline-flex items-center gap-1 px-2 py-1 bg-blue-50 hover:bg-blue-100 text-blue-700 hover:text-blue-800 border border-blue-200 hover:border-blue-300 rounded text-xs font-medium transition-colors duration-200">
|
||||||
<i class="ri-file-copy-2-line text-xs"></i>
|
<i class="ri-file-copy-2-line text-xs"></i>
|
||||||
<a href="{{ GetPieceURL (index $firstGroupItem.Item.IssueRefs 0).When.Year (index $firstGroupItem.Item.IssueRefs 0).Nr (index $firstGroupItem.Item.IssueRefs 0).Von (index $firstGroupItem.Item.Keys 0) }}" class="">
|
<a href="{{ GetPieceURL $firstGroupItem.Item.ID }}" class="">
|
||||||
Ganzer Beitrag
|
Ganzer Beitrag
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,17 +1,15 @@
|
|||||||
{{ $a := . }}
|
{{ $a := . }}
|
||||||
{{ $works := LookupWorks $a }}
|
{{ $works := slice }}
|
||||||
{{ $allPieces := LookupPieces $a }}
|
{{ if eq $a.ID "anonym" }}
|
||||||
|
{{ $anonymWorks := LookupAnonymWorks }}
|
||||||
|
{{ range $_, $work := $anonymWorks }}
|
||||||
|
{{ $works = append $works (dict "Item" $work) }}
|
||||||
|
{{ end }}
|
||||||
|
{{ else }}
|
||||||
|
{{ $works = LookupWorks $a }}
|
||||||
|
{{ end }}
|
||||||
|
|
||||||
{{- /* Filter pieces for work-related categories */ -}}
|
{{ if ne (len $works) 0 }}
|
||||||
{{- $workPieces := slice -}}
|
|
||||||
{{- range $_, $p := $allPieces -}}
|
|
||||||
{{- $categoryFlags := GetCategoryFlags $p.Item -}}
|
|
||||||
{{- if or $categoryFlags.Rezension $categoryFlags.Auszug $categoryFlags.Theaterkritik $categoryFlags.Uebersetzung $categoryFlags.Kommentar $categoryFlags.Replik $categoryFlags.Anzeige $categoryFlags.Provinienz -}}
|
|
||||||
{{- $workPieces = append $workPieces $p -}}
|
|
||||||
{{- end -}}
|
|
||||||
{{- end -}}
|
|
||||||
|
|
||||||
{{- if or (ne (len $works) 0) (ne (len $workPieces) 0) -}}
|
|
||||||
<div class="mt-4 akteur-werke-section">
|
<div class="mt-4 akteur-werke-section">
|
||||||
<div class="py-1 rounded-lg mb-1">
|
<div class="py-1 rounded-lg mb-1">
|
||||||
<h2 class="font-bold">
|
<h2 class="font-bold">
|
||||||
@@ -20,7 +18,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="">
|
<div class="">
|
||||||
{{ range $_, $w := $works }}
|
{{ range $_, $w := $works }}
|
||||||
<div class="mb-1.5 break-inside-avoid max-w-[95ch]">
|
<div class="mb-2 break-inside-avoid max-w-[95ch]">
|
||||||
{{- if ne (len $w.Item.Citation.InnerXML ) 0 -}}
|
{{- if ne (len $w.Item.Citation.InnerXML ) 0 -}}
|
||||||
<div class="indent-6">
|
<div class="indent-6">
|
||||||
{{- Safe $w.Item.Citation.HTML -}}
|
{{- Safe $w.Item.Citation.HTML -}}
|
||||||
@@ -33,95 +31,38 @@
|
|||||||
{{- end -}}
|
{{- end -}}
|
||||||
</div>
|
</div>
|
||||||
{{- end -}}
|
{{- end -}}
|
||||||
|
|
||||||
|
{{- /* Find all pieces that reference this work */ -}}
|
||||||
{{ $workPieces := LookupPieces $w.Item }}
|
{{ $workPieces := LookupPieces $w.Item }}
|
||||||
{{ if len $workPieces }}
|
{{ if len $workPieces }}
|
||||||
<div class="mt-1">
|
<div class="">
|
||||||
{{- /* Group pieces by piece ID first to combine all categories per piece, then by additional authors */ -}}
|
{{- /* Group pieces by category + author combination */ -}}
|
||||||
{{- $pieceData := dict -}}
|
{{- $pieceGroups := dict -}}
|
||||||
{{- range $_, $p := $workPieces -}}
|
{{- range $_, $p := $workPieces -}}
|
||||||
|
{{- /* Get categories for this piece */ -}}
|
||||||
{{- $categoryFlags := GetCategoryFlags $p.Item -}}
|
{{- $categoryFlags := GetCategoryFlags $p.Item -}}
|
||||||
{{- $categories := slice -}}
|
{{- $categories := slice -}}
|
||||||
{{- if $categoryFlags.Rezension -}}
|
{{- if $categoryFlags.Rezension -}}
|
||||||
{{- $categories = append $categories "Rezension" -}}
|
{{- $categories = append $categories "Rezension" -}}
|
||||||
{{- end -}}
|
{{- end -}}
|
||||||
{{- if $categoryFlags.Gedicht -}}
|
{{- if $categoryFlags.Auszug -}}
|
||||||
{{- $categories = append $categories "Gedicht" -}}
|
{{- $categories = append $categories "Auszug" -}}
|
||||||
{{- end -}}
|
|
||||||
{{- if $categoryFlags.Aufsatz -}}
|
|
||||||
{{- $categories = append $categories "Aufsatz" -}}
|
|
||||||
{{- end -}}
|
{{- end -}}
|
||||||
{{- if $categoryFlags.Theaterkritik -}}
|
{{- if $categoryFlags.Theaterkritik -}}
|
||||||
{{- $categories = append $categories "Theaterkritik" -}}
|
{{- $categories = append $categories "Theaterkritik" -}}
|
||||||
{{- end -}}
|
{{- end -}}
|
||||||
{{- if $categoryFlags.Brief -}}
|
{{- if $categoryFlags.Uebersetzung -}}
|
||||||
{{- $categories = append $categories "Brief" -}}
|
{{- $categories = append $categories "Übersetzung" -}}
|
||||||
{{- end -}}
|
|
||||||
{{- if $categoryFlags.Erzaehlung -}}
|
|
||||||
{{- $categories = append $categories "Erzählung" -}}
|
|
||||||
{{- end -}}
|
{{- end -}}
|
||||||
{{- if $categoryFlags.Kommentar -}}
|
{{- if $categoryFlags.Kommentar -}}
|
||||||
{{- $categories = append $categories "Kommentar" -}}
|
{{- $categories = append $categories "Kommentar" -}}
|
||||||
{{- end -}}
|
{{- end -}}
|
||||||
{{- if $categoryFlags.Uebersetzung -}}
|
|
||||||
{{- $categories = append $categories "Übersetzung" -}}
|
|
||||||
{{- end -}}
|
|
||||||
{{- if $categoryFlags.Auszug -}}
|
|
||||||
{{- $categories = append $categories "Auszug" -}}
|
|
||||||
{{- end -}}
|
|
||||||
{{- if $categoryFlags.Replik -}}
|
{{- if $categoryFlags.Replik -}}
|
||||||
{{- $categories = append $categories "Replik" -}}
|
{{- $categories = append $categories "Replik" -}}
|
||||||
{{- end -}}
|
{{- end -}}
|
||||||
{{- if $categoryFlags.Lokalnachrichten -}}
|
|
||||||
{{- $categories = append $categories "Lokalnachrichten" -}}
|
|
||||||
{{- end -}}
|
|
||||||
{{- if $categoryFlags.Lotterie -}}
|
|
||||||
{{- $categories = append $categories "Lotterie" -}}
|
|
||||||
{{- end -}}
|
|
||||||
{{- if $categoryFlags.Nachruf -}}
|
|
||||||
{{- $categories = append $categories "Nachruf" -}}
|
|
||||||
{{- end -}}
|
|
||||||
{{- if $categoryFlags.Weltnachrichten -}}
|
|
||||||
{{- $categories = append $categories "Weltnachrichten" -}}
|
|
||||||
{{- end -}}
|
|
||||||
{{- if $categoryFlags.EinkommendeFremde -}}
|
|
||||||
{{- $categories = append $categories "Einkommende Fremde" -}}
|
|
||||||
{{- end -}}
|
|
||||||
{{- if $categoryFlags.Wechselkurse -}}
|
|
||||||
{{- $categories = append $categories "Wechselkurse" -}}
|
|
||||||
{{- end -}}
|
|
||||||
{{- if $categoryFlags.Buecher -}}
|
|
||||||
{{- $categories = append $categories "Bücher" -}}
|
|
||||||
{{- end -}}
|
|
||||||
{{- if $categoryFlags.Lokalanzeigen -}}
|
|
||||||
{{- $categories = append $categories "Lokalanzeigen" -}}
|
|
||||||
{{- end -}}
|
|
||||||
{{- if $categoryFlags.Vorladung -}}
|
|
||||||
{{- $categories = append $categories "Vorladung" -}}
|
|
||||||
{{- end -}}
|
|
||||||
{{- if $categoryFlags.GelehrteNachrichten -}}
|
|
||||||
{{- $categories = append $categories "Gelehrte Nachrichten" -}}
|
|
||||||
{{- end -}}
|
|
||||||
{{- if $categoryFlags.Anzeige -}}
|
{{- if $categoryFlags.Anzeige -}}
|
||||||
{{- $categories = append $categories "Anzeige" -}}
|
{{- $categories = append $categories "Anzeige" -}}
|
||||||
{{- end -}}
|
{{- end -}}
|
||||||
{{- if $categoryFlags.Proklamation -}}
|
|
||||||
{{- $categories = append $categories "Proklamation" -}}
|
|
||||||
{{- end -}}
|
|
||||||
{{- if $categoryFlags.Desertionsliste -}}
|
|
||||||
{{- $categories = append $categories "Desertionsliste" -}}
|
|
||||||
{{- end -}}
|
|
||||||
{{- if $categoryFlags.Notenblatt -}}
|
|
||||||
{{- $categories = append $categories "Notenblatt" -}}
|
|
||||||
{{- end -}}
|
|
||||||
{{- if $categoryFlags.Vorlesungsverzeichnis -}}
|
|
||||||
{{- $categories = append $categories "Vorlesungsverzeichnis" -}}
|
|
||||||
{{- end -}}
|
|
||||||
{{- if $categoryFlags.Abbildung -}}
|
|
||||||
{{- $categories = append $categories "Abbildung" -}}
|
|
||||||
{{- end -}}
|
|
||||||
{{- if $categoryFlags.Ineigenersache -}}
|
|
||||||
{{- $categories = append $categories "In eigener Sache" -}}
|
|
||||||
{{- end -}}
|
|
||||||
{{- if $categoryFlags.Provinienz -}}
|
{{- if $categoryFlags.Provinienz -}}
|
||||||
{{- $categories = append $categories "Provinienz" -}}
|
{{- $categories = append $categories "Provinienz" -}}
|
||||||
{{- end -}}
|
{{- end -}}
|
||||||
@@ -129,71 +70,83 @@
|
|||||||
{{- $categories = append $categories "Beitrag" -}}
|
{{- $categories = append $categories "Beitrag" -}}
|
||||||
{{- end -}}
|
{{- end -}}
|
||||||
|
|
||||||
{{- /* Get additional authors for this specific piece */ -}}
|
{{- /* Get authors for this piece (excluding current person) */ -}}
|
||||||
{{- $pieceAdditionalAuthorIDs := slice -}}
|
{{- $pieceAuthors := slice -}}
|
||||||
{{- range $agentref := $p.Item.AgentRefs -}}
|
{{- range $agentref := $p.Item.AgentRefs -}}
|
||||||
{{- if and (or (eq $agentref.Category "") (eq $agentref.Category "autor")) (ne $agentref.Ref $a.ID) -}}
|
{{- if and (or (eq $agentref.Category "") (eq $agentref.Category "autor")) (ne $agentref.Ref $a.ID) -}}
|
||||||
{{- $pieceAdditionalAuthorIDs = append $pieceAdditionalAuthorIDs $agentref.Ref -}}
|
{{- $pieceAuthors = append $pieceAuthors $agentref.Ref -}}
|
||||||
{{- end -}}
|
{{- end -}}
|
||||||
{{- end -}}
|
{{- end -}}
|
||||||
{{- $sortedAdditionalAuthorIDs := sortStrings $pieceAdditionalAuthorIDs -}}
|
{{- $sortedAuthors := sortStrings $pieceAuthors -}}
|
||||||
|
|
||||||
{{- /* Store piece data by ID to combine categories and avoid duplicates */ -}}
|
{{- /* Create group key: categories + authors */ -}}
|
||||||
{{- $pieceData = merge $pieceData (dict $p.Item.ID (dict "piece" $p "categories" $categories "additionalAuthorIDs" $sortedAdditionalAuthorIDs)) -}}
|
{{- $sortedCategories := sortStrings $categories -}}
|
||||||
{{- end -}}
|
{{- $groupKey := printf "%s|%s" (joinWithUnd $sortedCategories) (joinWithUnd $sortedAuthors) -}}
|
||||||
|
|
||||||
{{- /* Now group by combined categories and additional authors */ -}}
|
{{- /* Add piece to group (check for duplicates by ID) */ -}}
|
||||||
{{- $groupedByCategory := dict -}}
|
{{- $existing := index $pieceGroups $groupKey -}}
|
||||||
{{- range $pieceID, $data := $pieceData -}}
|
|
||||||
{{- $sortedCategories := sortStrings $data.categories -}}
|
|
||||||
{{- $categoryName := joinWithUnd $sortedCategories -}}
|
|
||||||
{{- $groupKey := printf "%s|%s" $categoryName (joinWithUnd $data.additionalAuthorIDs) -}}
|
|
||||||
|
|
||||||
{{- $existing := index $groupedByCategory $groupKey -}}
|
|
||||||
{{- if $existing -}}
|
{{- if $existing -}}
|
||||||
{{- $groupedByCategory = merge $groupedByCategory (dict $groupKey (append $existing $data.piece)) -}}
|
{{- /* Check if piece is already in group */ -}}
|
||||||
{{- else -}}
|
{{- $found := false -}}
|
||||||
{{- $groupedByCategory = merge $groupedByCategory (dict $groupKey (slice $data.piece)) -}}
|
{{- range $existingPiece := $existing -}}
|
||||||
{{- end -}}
|
{{- if eq $existingPiece.Item.ID $p.Item.ID -}}
|
||||||
{{- end -}}
|
{{- $found = true -}}
|
||||||
|
|
||||||
{{- /* Display each category group */ -}}
|
|
||||||
{{- range $groupKey, $categoryPieces := $groupedByCategory -}}
|
|
||||||
<div>
|
|
||||||
<span class="inline-block">
|
|
||||||
{{- /* Extract category and additional authors from group key */ -}}
|
|
||||||
{{- $keyParts := split $groupKey "|" -}}
|
|
||||||
{{- $categoryName := index $keyParts 0 -}}
|
|
||||||
|
|
||||||
{{ $categoryName }}
|
|
||||||
{{- /* Get additional authors from first piece in group */ -}}
|
|
||||||
{{- $firstPiece := index $categoryPieces 0 -}}
|
|
||||||
{{- $additionalAuthorIDs := slice -}}
|
|
||||||
{{- range $agentref := $firstPiece.Item.AgentRefs -}}
|
|
||||||
{{- if and (or (eq $agentref.Category "") (eq $agentref.Category "autor")) (ne $agentref.Ref $a.ID) -}}
|
|
||||||
{{- $additionalAuthorIDs = append $additionalAuthorIDs $agentref.Ref -}}
|
|
||||||
{{- end -}}
|
{{- end -}}
|
||||||
{{- end -}}
|
{{- end -}}
|
||||||
{{- if $additionalAuthorIDs -}}
|
{{- if not $found -}}
|
||||||
{{ " " }}von {{ range $i, $authorID := $additionalAuthorIDs }}{{- if gt $i 0 }} und {{ end }}{{- $agent := GetAgent $authorID -}}{{- if and $agent (gt (len $agent.Names) 0) -}}<a href="/akteure/{{ $authorID }}" class="">{{ index $agent.Names 0 }}</a>{{- end -}}{{ end }}
|
{{- $pieceGroups = merge $pieceGroups (dict $groupKey (append $existing $p)) -}}
|
||||||
{{- end -}}{{ ":" }}
|
{{- end -}}
|
||||||
</span>
|
{{- else -}}
|
||||||
{{- /* Show all citations for this category inline with commas */ -}}
|
{{- $pieceGroups = merge $pieceGroups (dict $groupKey (slice $p)) -}}
|
||||||
{{ " " }}{{- range $pieceIndex, $p := $categoryPieces -}}
|
|
||||||
{{- range $issueIndex, $issue := $p.Item.IssueRefs -}}
|
|
||||||
{{- if or (gt $pieceIndex 0) (gt $issueIndex 0) }}, {{ end -}}
|
|
||||||
<span class="text-blue-600 hover:text-blue-700 underline decoration-dotted hover:decoration-solid [&>a]:text-blue-600 [&>a:hover]:text-blue-700">{{- template "_citation" $issue -}}</span>{{- end -}}
|
|
||||||
{{- end -}}
|
|
||||||
{{- /* Add "Ganzer Beitrag" link if piece spans multiple issues */ -}}
|
|
||||||
{{- $firstPiece := index $categoryPieces 0 -}}
|
|
||||||
{{- if gt (len $firstPiece.Item.IssueRefs) 1 -}}
|
|
||||||
{{ " " }}<div class="inline-flex items-center gap-1 px-2 py-1 bg-blue-50 hover:bg-blue-100 text-blue-700 hover:text-blue-800 border border-blue-200 hover:border-blue-300 rounded text-xs font-medium transition-colors duration-200">
|
|
||||||
<i class="ri-file-copy-2-line text-xs"></i>
|
|
||||||
<a href="{{ GetPieceURL (index $firstPiece.Item.IssueRefs 0).When.Year (index $firstPiece.Item.IssueRefs 0).Nr (index $firstPiece.Item.IssueRefs 0).Von (index $firstPiece.Item.Keys 0) }}" class="">
|
|
||||||
Ganzer Beitrag
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
{{- end -}}
|
{{- end -}}
|
||||||
|
{{- end -}}
|
||||||
|
|
||||||
|
{{- /* Display each group */ -}}
|
||||||
|
{{- range $groupKey, $groupPieces := $pieceGroups -}}
|
||||||
|
<div class="mb-1 text-gray-600">
|
||||||
|
{{- /* Extract categories and authors from group key */ -}}
|
||||||
|
{{- $keyParts := split $groupKey "|" -}}
|
||||||
|
{{- $categoryName := index $keyParts 0 -}}
|
||||||
|
{{- $authorPart := index $keyParts 1 -}}
|
||||||
|
|
||||||
|
{{- /* Use plural if multiple pieces grouped together */ -}}
|
||||||
|
{{- $displayCategory := $categoryName -}}
|
||||||
|
{{- if gt (len $groupPieces) 1 -}}
|
||||||
|
{{- if eq $categoryName "Rezension" -}}
|
||||||
|
{{- $displayCategory = "Rezensionen" -}}
|
||||||
|
{{- else if eq $categoryName "Auszug" -}}
|
||||||
|
{{- $displayCategory = "Auszüge" -}}
|
||||||
|
{{- else if eq $categoryName "Theaterkritik" -}}
|
||||||
|
{{- $displayCategory = "Theaterkritiken" -}}
|
||||||
|
{{- else if eq $categoryName "Übersetzung" -}}
|
||||||
|
{{- $displayCategory = "Übersetzungen" -}}
|
||||||
|
{{- else if eq $categoryName "Kommentar" -}}
|
||||||
|
{{- $displayCategory = "Kommentare" -}}
|
||||||
|
{{- else if eq $categoryName "Replik" -}}
|
||||||
|
{{- $displayCategory = "Repliken" -}}
|
||||||
|
{{- else if eq $categoryName "Anzeige" -}}
|
||||||
|
{{- $displayCategory = "Anzeigen" -}}
|
||||||
|
{{- else if eq $categoryName "Beitrag" -}}
|
||||||
|
{{- $displayCategory = "Beiträge" -}}
|
||||||
|
{{- end -}}
|
||||||
|
{{- end -}}
|
||||||
|
{{ $displayCategory }}{{- if ne $authorPart "" }} von {{ range $i, $authorID := (split $authorPart " und ") }}{{- if gt $i 0 }} und {{ end }}{{- $agent := GetAgent $authorID -}}{{- if and $agent (gt (len $agent.Names) 0) -}}<a href="/akteure/{{ $authorID }}" class="text-slate-700 hover:text-slate-900 underline decoration-slate-400 hover:decoration-slate-600">{{ index $agent.Names 0 }}</a>{{- end -}}{{ end }}{{- end }}:
|
||||||
|
{{- /* Show citations separated by commas */ -}}
|
||||||
|
{{ " " }}{{- range $pieceIndex, $p := $groupPieces -}}
|
||||||
|
{{- range $issueIndex, $issue := $p.Item.IssueRefs -}}
|
||||||
|
{{- if or (gt $pieceIndex 0) (gt $issueIndex 0) }}, {{ end -}}
|
||||||
|
<span class="text-blue-600 hover:text-blue-700 underline decoration-dotted hover:decoration-solid [&>a]:text-blue-600 [&>a:hover]:text-blue-700">{{- template "_citation" $issue -}}</span>
|
||||||
|
{{- end -}}
|
||||||
|
{{- /* Add "Ganzer Beitrag" link if piece spans multiple issues */ -}}
|
||||||
|
{{- if gt (len $p.Item.IssueRefs) 1 -}}
|
||||||
|
{{ " " }}<div class="inline-flex items-center gap-1 px-2 py-1 bg-blue-50 hover:bg-blue-100 text-blue-700 hover:text-blue-800 border border-blue-200 hover:border-blue-300 rounded text-xs font-medium transition-colors duration-200">
|
||||||
|
<i class="ri-file-copy-2-line text-xs"></i>
|
||||||
|
<a href="{{ GetPieceURL $p.Item.ID }}" class="">
|
||||||
|
Ganzer Beitrag
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
{{- end -}}
|
||||||
|
{{- end -}}
|
||||||
</div>
|
</div>
|
||||||
{{- end -}}
|
{{- end -}}
|
||||||
</div>
|
</div>
|
||||||
@@ -201,125 +154,6 @@
|
|||||||
</div>
|
</div>
|
||||||
{{ end }}
|
{{ end }}
|
||||||
|
|
||||||
{{- /* Process standalone work pieces that aren't linked to specific works */ -}}
|
|
||||||
{{- if ne (len $workPieces) 0 -}}
|
|
||||||
{{- /* Group standalone work pieces by piece ID first to combine categories, then by additional authors */ -}}
|
|
||||||
{{- $standalonePieceData := dict -}}
|
|
||||||
{{- range $_, $p := $workPieces -}}
|
|
||||||
{{- /* Skip pieces that are already covered by works above */ -}}
|
|
||||||
{{- $isPieceInWorks := false -}}
|
|
||||||
{{- range $_, $w := $works -}}
|
|
||||||
{{- $workPiecesCheck := LookupPieces $w.Item -}}
|
|
||||||
{{- range $_, $wp := $workPiecesCheck -}}
|
|
||||||
{{- if eq $wp.Item.ID $p.Item.ID -}}
|
|
||||||
{{- $isPieceInWorks = true -}}
|
|
||||||
{{- end -}}
|
|
||||||
{{- end -}}
|
|
||||||
{{- end -}}
|
|
||||||
|
|
||||||
{{- if not $isPieceInWorks -}}
|
|
||||||
{{- /* Get categories for this piece */ -}}
|
|
||||||
{{- $categoryFlags := GetCategoryFlags $p.Item -}}
|
|
||||||
{{- $categories := slice -}}
|
|
||||||
{{- if $categoryFlags.Rezension -}}
|
|
||||||
{{- $categories = append $categories "Rezension" -}}
|
|
||||||
{{- end -}}
|
|
||||||
{{- if $categoryFlags.Auszug -}}
|
|
||||||
{{- $categories = append $categories "Auszug" -}}
|
|
||||||
{{- end -}}
|
|
||||||
{{- if $categoryFlags.Theaterkritik -}}
|
|
||||||
{{- $categories = append $categories "Theaterkritik" -}}
|
|
||||||
{{- end -}}
|
|
||||||
{{- if $categoryFlags.Uebersetzung -}}
|
|
||||||
{{- $categories = append $categories "Übersetzung" -}}
|
|
||||||
{{- end -}}
|
|
||||||
{{- if $categoryFlags.Kommentar -}}
|
|
||||||
{{- $categories = append $categories "Kommentar" -}}
|
|
||||||
{{- end -}}
|
|
||||||
{{- if $categoryFlags.Replik -}}
|
|
||||||
{{- $categories = append $categories "Replik" -}}
|
|
||||||
{{- end -}}
|
|
||||||
{{- if $categoryFlags.Anzeige -}}
|
|
||||||
{{- $categories = append $categories "Anzeige" -}}
|
|
||||||
{{- end -}}
|
|
||||||
{{- if $categoryFlags.Provinienz -}}
|
|
||||||
{{- $categories = append $categories "Provinienz" -}}
|
|
||||||
{{- end -}}
|
|
||||||
|
|
||||||
{{- if ne (len $categories) 0 -}}
|
|
||||||
{{- /* Get additional authors for this specific piece */ -}}
|
|
||||||
{{- $pieceAdditionalAuthorIDs := slice -}}
|
|
||||||
{{- range $agentref := $p.Item.AgentRefs -}}
|
|
||||||
{{- if and (or (eq $agentref.Category "") (eq $agentref.Category "autor")) (ne $agentref.Ref $a.ID) -}}
|
|
||||||
{{- $pieceAdditionalAuthorIDs = append $pieceAdditionalAuthorIDs $agentref.Ref -}}
|
|
||||||
{{- end -}}
|
|
||||||
{{- end -}}
|
|
||||||
{{- $sortedAdditionalAuthorIDs := sortStrings $pieceAdditionalAuthorIDs -}}
|
|
||||||
|
|
||||||
{{- /* Store piece data by ID to combine categories and avoid duplicates */ -}}
|
|
||||||
{{- $standalonePieceData = merge $standalonePieceData (dict $p.Item.ID (dict "piece" $p "categories" $categories "additionalAuthorIDs" $sortedAdditionalAuthorIDs)) -}}
|
|
||||||
{{- end -}}
|
|
||||||
{{- end -}}
|
|
||||||
{{- end -}}
|
|
||||||
|
|
||||||
{{- /* Now group by combined categories and additional authors */ -}}
|
|
||||||
{{- $standaloneGrouped := dict -}}
|
|
||||||
{{- range $pieceID, $data := $standalonePieceData -}}
|
|
||||||
{{- $sortedCategories := sortStrings $data.categories -}}
|
|
||||||
{{- $categoryName := joinWithUnd $sortedCategories -}}
|
|
||||||
{{- $groupKey := printf "%s|%s" $categoryName (joinWithUnd $data.additionalAuthorIDs) -}}
|
|
||||||
|
|
||||||
{{- $existing := index $standaloneGrouped $groupKey -}}
|
|
||||||
{{- if $existing -}}
|
|
||||||
{{- $standaloneGrouped = merge $standaloneGrouped (dict $groupKey (append $existing $data.piece)) -}}
|
|
||||||
{{- else -}}
|
|
||||||
{{- $standaloneGrouped = merge $standaloneGrouped (dict $groupKey (slice $data.piece)) -}}
|
|
||||||
{{- end -}}
|
|
||||||
{{- end -}}
|
|
||||||
|
|
||||||
{{- /* Display standalone work pieces */ -}}
|
|
||||||
{{- range $groupKey, $categoryPieces := $standaloneGrouped -}}
|
|
||||||
<div class="mb-1.5 break-inside-avoid max-w-[95ch]">
|
|
||||||
<div class="">
|
|
||||||
<span class="inline-block">
|
|
||||||
{{- /* Extract category and additional authors from group key */ -}}
|
|
||||||
{{- $keyParts := split $groupKey "|" -}}
|
|
||||||
{{- $categoryName := index $keyParts 0 -}}
|
|
||||||
|
|
||||||
{{ $categoryName }}
|
|
||||||
{{- /* Get additional authors from first piece in group */ -}}
|
|
||||||
{{- $firstPiece := index $categoryPieces 0 -}}
|
|
||||||
{{- $additionalAuthorIDs := slice -}}
|
|
||||||
{{- range $agentref := $firstPiece.Item.AgentRefs -}}
|
|
||||||
{{- if and (or (eq $agentref.Category "") (eq $agentref.Category "autor")) (ne $agentref.Ref $a.ID) -}}
|
|
||||||
{{- $additionalAuthorIDs = append $additionalAuthorIDs $agentref.Ref -}}
|
|
||||||
{{- end -}}
|
|
||||||
{{- end -}}
|
|
||||||
{{- if $additionalAuthorIDs -}}
|
|
||||||
{{ " " }}von {{ range $i, $authorID := $additionalAuthorIDs }}{{- if gt $i 0 }} und {{ end }}{{- $agent := GetAgent $authorID -}}{{- if and $agent (gt (len $agent.Names) 0) -}}<a href="/akteure/{{ $authorID }}" class="">{{ index $agent.Names 0 }}</a>{{- end -}}{{ end }}
|
|
||||||
{{- end -}}{{ ":" }}
|
|
||||||
</span>
|
|
||||||
{{- /* Show all citations for this category inline with commas */ -}}
|
|
||||||
{{ " " }}{{- range $pieceIndex, $p := $categoryPieces -}}
|
|
||||||
{{- range $issueIndex, $issue := $p.Item.IssueRefs -}}
|
|
||||||
{{- if or (gt $pieceIndex 0) (gt $issueIndex 0) }}, {{ end -}}
|
|
||||||
<span class="text-blue-600 hover:text-blue-700 underline decoration-dotted hover:decoration-solid [&>a]:text-blue-600 [&>a:hover]:text-blue-700">{{- template "_citation" $issue -}}</span>{{- end -}}
|
|
||||||
{{- end -}}
|
|
||||||
{{- /* Add "Ganzer Beitrag" link if piece spans multiple issues */ -}}
|
|
||||||
{{- $firstPiece := index $categoryPieces 0 -}}
|
|
||||||
{{- if gt (len $firstPiece.Item.IssueRefs) 1 -}}
|
|
||||||
{{ " " }}<div class="inline-flex items-center gap-1 px-2 py-1 bg-blue-50 hover:bg-blue-100 text-blue-700 hover:text-blue-800 border border-blue-200 hover:border-blue-300 rounded text-xs font-medium transition-colors duration-200">
|
|
||||||
<i class="ri-file-copy-2-line text-xs"></i>
|
|
||||||
<a href="{{ GetPieceURL (index $firstPiece.Item.IssueRefs 0).When.Year (index $firstPiece.Item.IssueRefs 0).Nr (index $firstPiece.Item.IssueRefs 0).Von (index $firstPiece.Item.Keys 0) }}" class="">
|
|
||||||
Ganzer Beitrag
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
{{- end -}}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{{- end -}}
|
|
||||||
{{- end -}}
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{{ end }}
|
{{ end }}
|
||||||
@@ -23,7 +23,9 @@
|
|||||||
{{ if eq .Search "autoren" }}checked{{ end }}
|
{{ if eq .Search "autoren" }}checked{{ end }}
|
||||||
autocomplete="off"
|
autocomplete="off"
|
||||||
hx-get="{{ if eq .Search "autoren" }}/akteure/a{{ else }}/akteure/autoren{{ end }}"
|
hx-get="{{ if eq .Search "autoren" }}/akteure/a{{ else }}/akteure/autoren{{ end }}"
|
||||||
hx-target="body"
|
hx-select="main"
|
||||||
|
hx-target="main"
|
||||||
|
hx-swap="innerHTML show:window:top focus-scroll:false"
|
||||||
hx-push-url="true">
|
hx-push-url="true">
|
||||||
<span class="ml-2 text-base text-gray-700">Nur Autor:innen anzeigen</span>
|
<span class="ml-2 text-base text-gray-700">Nur Autor:innen anzeigen</span>
|
||||||
</label>
|
</label>
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ export class AkteureScrollspy extends HTMLElement {
|
|||||||
if (this.sections.length > 0 && this.navLinks.length > 0) {
|
if (this.sections.length > 0 && this.navLinks.length > 0) {
|
||||||
this.initializeScrollspy();
|
this.initializeScrollspy();
|
||||||
}
|
}
|
||||||
}, 200);
|
}, 500);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -402,4 +402,3 @@ export class AkteureScrollspy extends HTMLElement {
|
|||||||
|
|
||||||
// Register the web component
|
// Register the web component
|
||||||
customElements.define("akteure-scrollspy", AkteureScrollspy);
|
customElements.define("akteure-scrollspy", AkteureScrollspy);
|
||||||
|
|
||||||
|
|||||||
@@ -1,12 +1,8 @@
|
|||||||
package xmlmodels
|
package xmlmodels
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/sha256"
|
|
||||||
"encoding/hex"
|
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"encoding/xml"
|
"encoding/xml"
|
||||||
"fmt"
|
|
||||||
"sort"
|
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
@@ -37,68 +33,6 @@ func (p Piece) String() string {
|
|||||||
return string(data)
|
return string(data)
|
||||||
}
|
}
|
||||||
|
|
||||||
// generateContentBasedID creates a deterministic ID based on piece content
|
|
||||||
func (p Piece) generateContentBasedID() string {
|
|
||||||
var parts []string
|
|
||||||
|
|
||||||
// Add title if available
|
|
||||||
if len(p.Title) > 0 && p.Title[0] != "" {
|
|
||||||
parts = append(parts, "title:"+strings.ToLower(strings.TrimSpace(p.Title[0])))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add incipit if available
|
|
||||||
if len(p.Incipit) > 0 && p.Incipit[0] != "" {
|
|
||||||
incipit := strings.ToLower(strings.TrimSpace(p.Incipit[0]))
|
|
||||||
// Limit incipit to first 50 characters to avoid overly long IDs
|
|
||||||
if len(incipit) > 50 {
|
|
||||||
incipit = incipit[:50]
|
|
||||||
}
|
|
||||||
parts = append(parts, "incipit:"+incipit)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add author references
|
|
||||||
var authors []string
|
|
||||||
for _, agent := range p.AgentRefs {
|
|
||||||
if agent.Category == "" || agent.Category == "autor" {
|
|
||||||
authors = append(authors, agent.Ref)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
sort.Strings(authors) // Ensure consistent ordering
|
|
||||||
if len(authors) > 0 {
|
|
||||||
parts = append(parts, "authors:"+strings.Join(authors, ","))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add categories
|
|
||||||
var categories []string
|
|
||||||
for _, cat := range p.CategoryRefs {
|
|
||||||
if cat.Category != "" {
|
|
||||||
categories = append(categories, cat.Category)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
sort.Strings(categories) // Ensure consistent ordering
|
|
||||||
if len(categories) > 0 {
|
|
||||||
parts = append(parts, "categories:"+strings.Join(categories, ","))
|
|
||||||
}
|
|
||||||
|
|
||||||
// If we have no meaningful content, create a minimal hash from issue refs
|
|
||||||
if len(parts) == 0 {
|
|
||||||
// Use issue references as fallback content
|
|
||||||
for _, issue := range p.IssueRefs {
|
|
||||||
parts = append(parts, fmt.Sprintf("issue:%d-%d-%d-%d", issue.When.Year, issue.Nr, issue.Von, issue.Bis))
|
|
||||||
}
|
|
||||||
// If still no content, use a generic identifier
|
|
||||||
if len(parts) == 0 {
|
|
||||||
parts = append(parts, "unknown-piece")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create hash of combined content
|
|
||||||
content := strings.Join(parts, "|")
|
|
||||||
hash := sha256.Sum256([]byte(content))
|
|
||||||
|
|
||||||
// Return first 12 characters of hex hash for reasonable ID length
|
|
||||||
return hex.EncodeToString(hash[:])[:12]
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p Piece) Categories() map[string]bool {
|
func (p Piece) Categories() map[string]bool {
|
||||||
cats := make(map[string]bool)
|
cats := make(map[string]bool)
|
||||||
@@ -136,24 +70,8 @@ func (p Piece) Categories() map[string]bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (p Piece) Keys() []string {
|
func (p Piece) Keys() []string {
|
||||||
// Always regenerate keys to ensure we use the new content-based logic
|
// All pieces now have XML IDs, so we just return the ID
|
||||||
ret := make([]string, 0, 3)
|
return []string{p.ID}
|
||||||
|
|
||||||
// Primary ID: Use existing ID if available, otherwise content-based ID
|
|
||||||
var primaryID string
|
|
||||||
if p.ID != "" {
|
|
||||||
primaryID = p.ID
|
|
||||||
} else {
|
|
||||||
primaryID = p.generateContentBasedID()
|
|
||||||
}
|
|
||||||
ret = append(ret, primaryID)
|
|
||||||
|
|
||||||
// Create issue-specific keys using the primary ID for lookup
|
|
||||||
for _, i := range p.IssueRefs {
|
|
||||||
ret = append(ret, strconv.Itoa(i.When.Year)+"-"+strconv.Itoa(i.Nr)+"-"+primaryID)
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p Piece) ReferencesIssue(y, no int) (*IssueRef, bool) {
|
func (p Piece) ReferencesIssue(y, no int) (*IssueRef, bool) {
|
||||||
|
|||||||
Reference in New Issue
Block a user