Page target navigation

This commit is contained in:
Simon Martens
2025-09-19 16:41:00 +02:00
parent 04d62d9e67
commit 2574124588
22 changed files with 1582 additions and 203 deletions

View File

@@ -0,0 +1,31 @@
{{ $model := .model }}
{{ if $model.Images.HasImages }}
<!-- Container with proper padding -->
<div class="">
<!-- Two-column layout for piece view -->
<div class="flex flex-col lg:flex-row gap-6 w-full min-h-screen">
<!-- Column 1: Table of Contents ONLY -->
<div class="lg:w-1/3 xl:w-1/4 flex-shrink-0 bg-slate-50 px-8 py-4">
<div class="lg:sticky lg:top-8 lg:overflow-y-auto">
{{ template "_piece_inhaltsverzeichnis" . }}
</div>
</div>
<!-- Column 2: Sequential Page Layout -->
<div class="lg:w-2/3 xl:w-3/4 flex-1 py-4">
{{ template "_piece_sequential_layout" . }}
</div>
</div>
</div>
{{ else }}
<!-- No images fallback -->
<div class="container mx-auto px-4 py-8">
<div class="bg-yellow-50 border border-yellow-200 rounded-lg p-6">
<h2 class="text-xl font-semibold text-yellow-800 mb-2">Keine Bilder verfügbar</h2>
<p class="text-yellow-700">
Für diesen Beitrag sind derzeit keine Seitenbilder verfügbar.
</p>
</div>
</div>
{{ end }}

View File

@@ -0,0 +1,61 @@
{{ $model := .model }}
<div class="w-full hyphens-auto">
<div class="space-y-4">
<!-- Header with icon and type (small) -->
<div class="flex items-center gap-2 mb-2">
<i class="ri-file-text-line text-slate-600"></i>
<h3 class="text-sm font-medium text-slate-600">Einzelbeitrag</h3>
</div>
<!-- Main piece entry -->
<div class="mb-6">
<!-- Get the first page to generate the actual content description -->
{{ if $model.ContinuousPages.Pages }}
{{ $firstPageNum := index $model.ContinuousPages.Pages 0 }}
{{ $firstPageEntries := index $model.ContinuousPages.Items $firstPageNum }}
{{ if $firstPageEntries }}
{{ $firstPiece := index $firstPageEntries 0 }}
<!-- Actual piece content description (larger) -->
<div class="mb-3">
<div class="text-base font-semibold text-slate-800 leading-snug">
{{ template "_inhaltsverzeichnis_eintrag" $firstPiece.PieceByIssue }}
</div>
</div>
{{ end }}
{{ end }}
<!-- Summary with boxed numbers -->
<div class="mb-4">
<p class="text-sm text-slate-600">
<span class="inline-flex items-center gap-1">
<span class="bg-slate-800 text-white px-1.5 py-0.5 rounded text-xs font-bold">{{ $model.TotalPageCount }}</span>
Seiten in
<span class="bg-slate-800 text-white px-1.5 py-0.5 rounded text-xs font-bold">{{ len $model.IssueContexts }}</span>
Ausgaben gefunden:
</span>
</p>
</div>
<!-- Issue and page links with highlighting data attributes -->
<div class="space-y-1">
{{ range $pageEntry := $model.AllPages }}
<!-- Find the issue ref for this page to get date -->
{{ range $issueRef := $model.AllIssueRefs }}
{{ if and (eq $issueRef.When.Year $pageEntry.IssueYear) (eq $issueRef.Nr $pageEntry.IssueNumber) (le $issueRef.Von $pageEntry.PageNumber) (ge $issueRef.Bis $pageEntry.PageNumber) }}
<div class="inhalts-entry issue-link-entry pl-4 border-l-4 border-slate-300 hover:bg-slate-100">
<a href="/{{ $pageEntry.IssueYear }}/{{ $pageEntry.IssueNumber }}/{{ $pageEntry.PageNumber }}"
class="page-number-inhalts text-slate-700 hover:text-red-700 text-sm hover:underline transition-colors duration-200 bg-blue-50 hover:bg-blue-100 relative"
data-page-number="{{ $pageEntry.PageNumber }}">
{{ if $issueRef.When.Day }}{{ $issueRef.When.Day }}.{{ end }}{{ if $issueRef.When.Month }}{{ $issueRef.When.Month }}.{{ end }}{{ $issueRef.When.Year }} [Nr. {{ $pageEntry.IssueNumber }}], {{ $pageEntry.PageNumber }}
{{ template "_page_link_indicator" (dict "pageNumber" $pageEntry.PageNumber "targetPage" $.targetPage) }}
</a>
</div>
{{ break }}
{{ end }}
{{ end }}
{{ end }}
</div>
</div>
</div>
</div>

View File

@@ -0,0 +1,85 @@
{{ $model := .model }}
<!-- Sequential page layout for piece view -->
<div class="space-y-8 h-full relative" id="piece-content">
{{ if $model.Images.AllPages }}
<!-- Two-column newspaper layout -->
<div class="grid grid-cols-2 gap-4">
{{ range $pageIndex, $page := $model.Images.AllPages }}
{{ $pageEntry := index $model.AllPages $pageIndex }}
{{ $issueContext := printf "%d Nr. %d" $pageEntry.IssueYear $pageEntry.IssueNumber }}
<!-- Page container -->
<div class="piece-page-container newspaper-page-container" id="piece-page-{{ $page.PageNumber }}" data-page-container="{{ $page.PageNumber }}">
<!-- Page indicator row -->
<div class="flex justify-start items-center gap-2 mb-3">
<span class="page-indicator text-sm font-bold text-slate-600 bg-blue-50 px-2 py-1 rounded transition-all duration-300 flex items-center gap-1 relative" data-page="{{ $page.PageNumber }}">
{{ PageIcon "single" }}
{{ $issueContext }}, {{ $page.PageNumber }}
{{ template "_page_link_indicator" (dict "pageNumber" $page.PageNumber "targetPage" $.targetPage) }}
</span>
<!-- Action buttons -->
<button onclick="copyPagePermalink('{{ $page.PageNumber }}', this)"
class="w-6 h-6 bg-blue-100 hover:bg-blue-200 text-blue-700 border border-blue-300 rounded flex items-center justify-center transition-colors duration-200 cursor-pointer"
title="Link zu Seite {{ $page.PageNumber }} kopieren">
<i class="ri-share-line text-xs"></i>
</button>
<button onclick="generatePageCitation('{{ $page.PageNumber }}', this)"
class="w-6 h-6 bg-green-100 hover:bg-green-200 text-green-700 border border-green-300 rounded flex items-center justify-center transition-colors duration-200 cursor-pointer"
title="Zitation für Seite {{ $page.PageNumber }} generieren">
<i class="ri-file-text-line text-xs"></i>
</button>
<button onclick="enlargePage(document.querySelector('#piece-page-{{ $page.PageNumber }} .piece-page-image'), {{ $page.PageNumber }}, false)"
class="w-6 h-6 bg-purple-100 hover:bg-purple-200 text-purple-700 border border-purple-300 rounded flex items-center justify-center transition-colors duration-200 cursor-pointer"
title="Seite {{ $page.PageNumber }} vergrößern">
<i class="ri-zoom-in-line text-xs"></i>
</button>
</div>
<!-- Page image -->
<div class="single-page bg-white p-4 rounded border border-slate-200 hover:border-slate-300 transition-colors duration-200">
{{ if $page.Available }}
<img src="{{ $page.ImagePath }}"
alt="Seite {{ $page.PageNumber }} ({{ $issueContext }})"
class="piece-page-image newspaper-page-image cursor-zoom-in rounded-sm hover:scale-[1.02] transition-transform duration-200 w-full"
onclick="enlargePage(this, {{ $page.PageNumber }}, false)"
data-page="{{ $page.PageNumber }}"
loading="lazy" />
{{ else }}
<div class="bg-slate-100 border border-slate-200 rounded p-8 text-center">
<i class="ri-image-line text-4xl text-slate-400 mb-2 block"></i>
<p class="text-slate-500">Bild nicht verfügbar</p>
</div>
{{ end }}
</div>
</div>
{{ end }}
</div>
{{ else }}
<!-- No pages available -->
<div class="text-center text-slate-500 py-16">
<i class="ri-file-list-line text-6xl mb-4 block"></i>
<h3 class="text-xl font-semibold mb-2">Keine Seiten verfügbar</h3>
<p>Für diesen Beitrag sind derzeit keine Seitenbilder verfügbar.</p>
</div>
{{ end }}
</div>
<!-- Modal for enlarged view - reuse existing modal -->
<div
id="pageModal"
class="absolute inset-0 bg-black bg-opacity-75 hidden z-50 flex items-center justify-center backdrop-blur-sm"
onclick="closeModal()">
<div class="relative max-w-full max-h-full p-4">
<img id="modalImage" src="" alt="" class="max-w-full max-h-full object-contain rounded-lg" />
<button
onclick="closeModal()"
class="absolute top-2 right-2 text-white bg-slate-800 bg-opacity-80 rounded-full w-10 h-10 flex items-center justify-center hover:bg-opacity-100 transition-all duration-200">
<i class="ri-close-line text-xl"></i>
</button>
</div>
</div>

View File

@@ -0,0 +1,32 @@
<title>KGPZ &ndash; {{ if .model.Title }}{{ .model.Title }}{{ else }}Beitrag{{ end }} ({{ len .model.IssueContexts }} Teil{{ if gt (len .model.IssueContexts) 1 }}e{{ end }})</title>
<script>
// Make template data available to JavaScript
window.templateData = {
targetPage: {{ if .targetPage }}{{ .targetPage }}{{ else }}0{{ end }}
};
</script>
{{ if .targetPage }}
<script>
// Auto-scroll to target page when page loads
document.addEventListener('DOMContentLoaded', function() {
// Wait for newspaper layout to be initialized
setTimeout(function() {
const targetPage = {{ .targetPage }};
const pageContainer = document.querySelector('[data-page-container="' + targetPage + '"]');
if (pageContainer) {
pageContainer.scrollIntoView({
behavior: 'smooth',
block: 'start'
});
// Highlight the page in the Inhaltsverzeichnis if function exists
if (typeof markCurrentPageInInhaltsverzeichnis === 'function') {
markCurrentPageInInhaltsverzeichnis(targetPage);
}
}
}, 500); // Give time for layout initialization
});
</script>
{{ end }}