mirror of
https://github.com/Theodor-Springmann-Stiftung/kgpz_web.git
synced 2025-10-28 16:45:32 +00:00
Further styling
This commit is contained in:
File diff suppressed because one or more lines are too long
@@ -1,20 +1,35 @@
|
||||
{{ $model := .model }}
|
||||
|
||||
{{ if $model.Images.HasImages }}
|
||||
<div class="flex flex-col lg:flex-row gap-6 w-full min-h-screen mt-8">
|
||||
<!-- Left side: Sticky Inhaltsverzeichnis -->
|
||||
<div class="lg:w-1/3 xl:w-1/4 flex-shrink-0">
|
||||
<div class="lg:sticky lg:top-12 lg:max-h-[calc(100vh-2rem)] lg:overflow-y-auto">
|
||||
{{ template "_title_nav" . }}
|
||||
{{ template "_inhaltsverzeichnis" . }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Right side: Newspaper pages -->
|
||||
<div class="lg:w-2/3 xl:w-3/4 flex-1">
|
||||
{{ template "_newspaper_layout" . }}
|
||||
</div>
|
||||
</div>
|
||||
{{ $layout := .Request.URL.Query.Get "layout" }}
|
||||
{{ if eq $layout "fullwidth" }}
|
||||
{{ template "_fullwidth_layout" . }}
|
||||
{{ else }}
|
||||
<!-- Default sidebar layout -->
|
||||
<div class="flex flex-col lg:flex-row gap-6 w-full min-h-screen mt-8">
|
||||
<!-- Left side: Sticky Inhaltsverzeichnis -->
|
||||
<div class="lg:w-1/3 xl:w-1/4 flex-shrink-0">
|
||||
<div class="lg:sticky lg:top-12 lg:max-h-[calc(100vh-2rem)] lg:overflow-y-auto">
|
||||
{{ template "_title_nav" . }}
|
||||
{{ template "_inhaltsverzeichnis" . }}
|
||||
<!-- Switch to fullwidth button -->
|
||||
<div class="mt-4">
|
||||
<a href="?layout=fullwidth" class="flex items-center justify-center px-3 py-2 bg-blue-600 hover:bg-blue-700 text-white rounded-md transition-colors text-sm">
|
||||
<i class="ri-fullscreen-line mr-1"></i>
|
||||
Vollbild
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Right side: Newspaper pages -->
|
||||
<div class="lg:w-2/3 xl:w-3/4 flex-1">
|
||||
{{ template "_newspaper_layout" . }}
|
||||
</div>
|
||||
</div>
|
||||
{{ end }}
|
||||
|
||||
{{ else }}
|
||||
<div class="max-w-4xl">
|
||||
{{ template "_title_nav" . }}
|
||||
|
||||
164
views/routes/ausgabe/components/_fullwidth_layout.gohtml
Normal file
164
views/routes/ausgabe/components/_fullwidth_layout.gohtml
Normal file
@@ -0,0 +1,164 @@
|
||||
{{ $model := .model }}
|
||||
|
||||
<div class="w-full min-h-screen">
|
||||
<!-- Navigation Bar -->
|
||||
<div class="sticky top-0 z-40 bg-white border-b border-gray-200 shadow-sm mb-6">
|
||||
<div class="max-w-7xl mx-auto px-4 py-4">
|
||||
<div class="flex items-center justify-between">
|
||||
<div class="flex items-center space-x-4">
|
||||
{{ template "_title_nav" . }}
|
||||
</div>
|
||||
<div class="flex items-center space-x-3">
|
||||
<!-- Navigation buttons -->
|
||||
<button onclick="scrollToPreviousPage()" class="flex items-center px-3 py-2 bg-blue-600 hover:bg-blue-700 text-white rounded-md transition-colors">
|
||||
<i class="ri-arrow-up-line mr-1"></i>
|
||||
Vorherige Seite
|
||||
</button>
|
||||
<button onclick="scrollToNextPage()" class="flex items-center px-3 py-2 bg-blue-600 hover:bg-blue-700 text-white rounded-md transition-colors">
|
||||
<i class="ri-arrow-down-line mr-1"></i>
|
||||
Nächste Seite
|
||||
</button>
|
||||
{{ if $model.Images.AdditionalPages }}
|
||||
<button onclick="scrollToBeilage()" class="flex items-center px-3 py-2 bg-amber-600 hover:bg-amber-700 text-white rounded-md transition-colors">
|
||||
<i class="ri-attachment-line mr-1"></i>
|
||||
Zu Beilage
|
||||
</button>
|
||||
{{ end }}
|
||||
<!-- Switch back to sidebar layout -->
|
||||
<a href="?layout=sidebar" class="flex items-center px-3 py-2 bg-gray-600 hover:bg-gray-700 text-white rounded-md transition-colors">
|
||||
<i class="ri-sidebar-unfold-line mr-1"></i>
|
||||
Seitenleiste
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="max-w-7xl mx-auto px-4">
|
||||
<div class="flex flex-col lg:flex-row gap-6 w-full">
|
||||
<!-- Left side: Collapsible Inhaltsverzeichnis -->
|
||||
<div class="lg:w-1/4 xl:w-1/5 flex-shrink-0">
|
||||
<div class="lg:sticky lg:top-24 lg:max-h-[calc(100vh-6rem)] lg:overflow-y-auto">
|
||||
{{ template "_inhaltsverzeichnis" . }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Right side: Full-width Newspaper pages -->
|
||||
<div class="lg:w-3/4 xl:w-4/5 flex-1">
|
||||
{{ template "_newspaper_layout" . }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
let currentPageContainers = [];
|
||||
let currentActiveIndex = 0;
|
||||
|
||||
// Initialize page tracking for full-width layout
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
// Get all page containers
|
||||
currentPageContainers = document.querySelectorAll('.newspaper-page-container');
|
||||
|
||||
// Set up intersection observer for active page tracking
|
||||
const observer = new IntersectionObserver((entries) => {
|
||||
entries.forEach((entry) => {
|
||||
if (entry.isIntersecting) {
|
||||
// Get page number from the container
|
||||
const pageImg = entry.target.querySelector('img[data-page]');
|
||||
if (pageImg) {
|
||||
const pageNumber = pageImg.getAttribute('data-page');
|
||||
markCurrentPageInInhaltsverzeichnis(pageNumber);
|
||||
}
|
||||
|
||||
// Update current active index
|
||||
const containerIndex = Array.from(currentPageContainers).indexOf(entry.target);
|
||||
if (containerIndex !== -1) {
|
||||
currentActiveIndex = containerIndex;
|
||||
}
|
||||
}
|
||||
});
|
||||
}, {
|
||||
rootMargin: '-20% 0px -70% 0px' // Trigger when page is mostly in view
|
||||
});
|
||||
|
||||
// Observe all page containers
|
||||
currentPageContainers.forEach(container => {
|
||||
observer.observe(container);
|
||||
});
|
||||
});
|
||||
|
||||
function scrollToPreviousPage() {
|
||||
if (currentActiveIndex > 0) {
|
||||
currentActiveIndex--;
|
||||
currentPageContainers[currentActiveIndex].scrollIntoView({
|
||||
behavior: 'smooth',
|
||||
block: 'start'
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function scrollToNextPage() {
|
||||
if (currentActiveIndex < currentPageContainers.length - 1) {
|
||||
currentActiveIndex++;
|
||||
currentPageContainers[currentActiveIndex].scrollIntoView({
|
||||
behavior: 'smooth',
|
||||
block: 'start'
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function scrollToBeilage() {
|
||||
const beilageElement = document.querySelector('[id^="beilage-"]');
|
||||
if (beilageElement) {
|
||||
beilageElement.scrollIntoView({
|
||||
behavior: 'smooth',
|
||||
block: 'start'
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function markCurrentPageInInhaltsverzeichnis(pageNumber) {
|
||||
// Reset all entries in Inhaltsverzeichnis
|
||||
document.querySelectorAll('.inhalts-entry').forEach(entry => {
|
||||
entry.classList.remove('bg-red-100', 'border-red-300');
|
||||
entry.classList.add('bg-slate-50');
|
||||
});
|
||||
|
||||
// Find and highlight the current page entry
|
||||
const pageEntry = document.querySelector(`.inhalts-entry[data-page="${pageNumber}"]`);
|
||||
if (pageEntry) {
|
||||
pageEntry.classList.remove('bg-slate-50');
|
||||
pageEntry.classList.add('bg-red-100', 'border-red-300');
|
||||
}
|
||||
|
||||
// Also highlight page indicators
|
||||
document.querySelectorAll('.page-indicator').forEach(indicator => {
|
||||
indicator.classList.remove('bg-red-500', 'text-white');
|
||||
indicator.classList.add('bg-blue-50', 'text-slate-600');
|
||||
});
|
||||
|
||||
const pageIndicator = document.querySelector(`.page-indicator[data-page="${pageNumber}"]`);
|
||||
if (pageIndicator) {
|
||||
pageIndicator.classList.remove('bg-blue-50', 'bg-green-50', 'text-slate-600');
|
||||
pageIndicator.classList.add('bg-red-500', 'text-white');
|
||||
}
|
||||
}
|
||||
|
||||
// Keyboard navigation
|
||||
document.addEventListener('keydown', function(e) {
|
||||
if (e.key === 'Escape') {
|
||||
// Close modal if open
|
||||
const modal = document.getElementById('pageModal');
|
||||
if (modal && !modal.classList.contains('hidden')) {
|
||||
modal.classList.add('hidden');
|
||||
}
|
||||
} else if (e.key === 'ArrowUp' || e.key === 'PageUp') {
|
||||
e.preventDefault();
|
||||
scrollToPreviousPage();
|
||||
} else if (e.key === 'ArrowDown' || e.key === 'PageDown') {
|
||||
e.preventDefault();
|
||||
scrollToNextPage();
|
||||
}
|
||||
});
|
||||
</script>
|
||||
@@ -16,7 +16,7 @@
|
||||
</div>
|
||||
<div class="space-y-3">
|
||||
{{ range $piece := (index $model.Pieces.Items $page) }}
|
||||
<div class="py-2 px-3 bg-slate-50 rounded hover:bg-slate-100 transition-colors duration-200">
|
||||
<div class="inhalts-entry py-2 px-3 bg-slate-50 rounded hover:bg-slate-100 transition-colors duration-200" data-page="{{ $page }}">
|
||||
{{ template "_inhaltsverzeichnis_eintrag" $piece }}
|
||||
|
||||
|
||||
@@ -71,7 +71,7 @@
|
||||
</div>
|
||||
<div class="space-y-3">
|
||||
{{ range $piece := (index $model.AdditionalPieces.Items $page) }}
|
||||
<div class="py-2 px-3 bg-slate-50 rounded hover:bg-slate-100 transition-colors duration-200">
|
||||
<div class="inhalts-entry py-2 px-3 bg-slate-50 rounded hover:bg-slate-100 transition-colors duration-200" data-page="{{ $page }}">
|
||||
{{ template "_inhaltsverzeichnis_eintrag" $piece }}
|
||||
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
<div class="mb-3">
|
||||
<div class="flex items-center gap-2 mb-2">
|
||||
<i class="ri-file-image-line text-blue-600"></i>
|
||||
<span class="text-sm font-medium text-slate-600 bg-blue-50 px-2 py-1 rounded">{{ $firstPage.PageNumber }}</span>
|
||||
<span class="page-indicator text-sm font-medium text-slate-600 bg-blue-50 px-2 py-1 rounded transition-all duration-300" data-page="{{ $firstPage.PageNumber }}">{{ $firstPage.PageNumber }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="single-page bg-white p-4 rounded-lg border border-slate-200 hover:border-slate-300 transition-colors duration-200">
|
||||
@@ -41,7 +41,7 @@
|
||||
<div class="mb-3">
|
||||
<div class="flex items-center gap-2 mb-2">
|
||||
<i class="ri-file-copy-2-line text-green-600"></i>
|
||||
<span class="text-sm font-medium text-slate-600 bg-green-50 px-2 py-1 rounded">{{ $middlePage1.PageNumber }}-{{ $middlePage2.PageNumber }}</span>
|
||||
<span class="page-indicator text-sm font-medium text-slate-600 bg-green-50 px-2 py-1 rounded transition-all duration-300" data-page="{{ $middlePage1.PageNumber }}">{{ $middlePage1.PageNumber }}-{{ $middlePage2.PageNumber }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="double-spread bg-white p-4 rounded-lg border border-slate-200 hover:border-slate-300 transition-colors duration-200">
|
||||
@@ -70,7 +70,7 @@
|
||||
<div class="mb-3">
|
||||
<div class="flex items-center gap-2 mb-2">
|
||||
<i class="ri-file-image-line text-blue-600"></i>
|
||||
<span class="text-sm font-medium text-slate-600 bg-blue-50 px-3 py-1 rounded-full">Seite {{ $lastPage.PageNumber }}</span>
|
||||
<span class="page-indicator text-sm font-medium text-slate-600 bg-blue-50 px-2 py-1 rounded transition-all duration-300" data-page="{{ $lastPage.PageNumber }}">{{ $lastPage.PageNumber }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="single-page bg-white p-4 rounded-lg border border-slate-200 hover:border-slate-300 transition-colors duration-200">
|
||||
@@ -265,6 +265,60 @@
|
||||
</style>
|
||||
|
||||
<script>
|
||||
// Initialize page tracking
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
// Get all page containers
|
||||
const pageContainers = document.querySelectorAll('.newspaper-page-container');
|
||||
|
||||
// Set up intersection observer for active page tracking
|
||||
const observer = new IntersectionObserver((entries) => {
|
||||
entries.forEach((entry) => {
|
||||
if (entry.isIntersecting) {
|
||||
// Get page number from the container
|
||||
const pageImg = entry.target.querySelector('img[data-page]');
|
||||
if (pageImg) {
|
||||
const pageNumber = pageImg.getAttribute('data-page');
|
||||
markCurrentPageInInhaltsverzeichnis(pageNumber);
|
||||
}
|
||||
}
|
||||
});
|
||||
}, {
|
||||
rootMargin: '-20% 0px -70% 0px' // Trigger when page is mostly in view
|
||||
});
|
||||
|
||||
// Observe all page containers
|
||||
pageContainers.forEach(container => {
|
||||
observer.observe(container);
|
||||
});
|
||||
});
|
||||
|
||||
function markCurrentPageInInhaltsverzeichnis(pageNumber) {
|
||||
// Reset all entries in Inhaltsverzeichnis
|
||||
document.querySelectorAll('.inhalts-entry').forEach(entry => {
|
||||
entry.classList.remove('bg-red-100', 'border-red-300');
|
||||
entry.classList.add('bg-slate-50');
|
||||
});
|
||||
|
||||
// Find and highlight the current page entry
|
||||
const pageEntry = document.querySelector(`.inhalts-entry[data-page="${pageNumber}"]`);
|
||||
if (pageEntry) {
|
||||
pageEntry.classList.remove('bg-slate-50');
|
||||
pageEntry.classList.add('bg-red-100', 'border-red-300');
|
||||
}
|
||||
|
||||
// Also highlight page indicators
|
||||
document.querySelectorAll('.page-indicator').forEach(indicator => {
|
||||
indicator.classList.remove('bg-red-500', 'text-white');
|
||||
indicator.classList.add('bg-blue-50', 'text-slate-600');
|
||||
});
|
||||
|
||||
const pageIndicator = document.querySelector(`.page-indicator[data-page="${pageNumber}"]`);
|
||||
if (pageIndicator) {
|
||||
pageIndicator.classList.remove('bg-blue-50', 'bg-green-50', 'text-slate-600');
|
||||
pageIndicator.classList.add('bg-red-500', 'text-white');
|
||||
}
|
||||
}
|
||||
|
||||
function enlargePage(imgElement, pageNumber, isFromSpread) {
|
||||
const modal = document.getElementById('pageModal');
|
||||
const modalImage = document.getElementById('modalImage');
|
||||
@@ -274,8 +328,8 @@ function enlargePage(imgElement, pageNumber, isFromSpread) {
|
||||
|
||||
modal.classList.remove('hidden');
|
||||
|
||||
// Highlight current page in Inhaltsverzeichnis if you implement that
|
||||
// markCurrentPage(pageNumber);
|
||||
// Mark current page when enlarged
|
||||
markCurrentPageInInhaltsverzeichnis(pageNumber);
|
||||
}
|
||||
|
||||
function closeModal() {
|
||||
|
||||
Reference in New Issue
Block a user