Files
kgpz_web/views/routes/ausgabe/components/_fullwidth_layout.gohtml
Simon Martens 9c287701bb Var fixes
2025-09-14 23:04:33 +02:00

346 lines
11 KiB
Plaintext

{{ $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) {
// Check if this is a double-spread container
const doubleSpread = entry.target.querySelector('.double-spread');
if (doubleSpread) {
// Handle double-spread: highlight both pages
const pageImages = entry.target.querySelectorAll('img[data-page]');
const pageNumbers = Array.from(pageImages).map(img => img.getAttribute('data-page'));
markCurrentPagesInInhaltsverzeichnis(pageNumbers);
} else {
// Handle single page
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) {
markCurrentPagesInInhaltsverzeichnis([pageNumber]);
}
function markCurrentPagesInInhaltsverzeichnis(pageNumbers) {
// Reset all page numbers in Inhaltsverzeichnis
document.querySelectorAll('.page-number-inhalts').forEach(pageNum => {
pageNum.classList.remove('bg-red-500', 'text-white');
pageNum.classList.add('text-slate-700');
// Restore original background colors
if (pageNum.classList.contains('bg-amber-50')) {
// Keep amber background for Beilage pages
} else {
pageNum.classList.remove('bg-amber-50');
pageNum.classList.add('bg-blue-50');
}
});
// Find and highlight the current page numbers
const highlightedElements = [];
const highlightedRanges = new Set(); // Track which ranges we've already highlighted
pageNumbers.forEach(pageNumber => {
// Look for all entries that should be highlighted for this page
const allPageNumbers = document.querySelectorAll('.page-number-inhalts');
for (const pageNumElement of allPageNumbers) {
const startPage = parseInt(pageNumElement.getAttribute('data-page-number'));
const endPage = parseInt(pageNumElement.getAttribute('data-end-page'));
const rangeKey = `${startPage}-${endPage}`;
// Check if this page falls within this range
if (pageNumber >= startPage && pageNumber <= endPage) {
// Only highlight this range once, even if multiple visible pages fall within it
if (!highlightedRanges.has(rangeKey)) {
pageNumElement.classList.remove('bg-blue-50', 'bg-amber-50', 'text-slate-700');
pageNumElement.classList.add('bg-red-500', 'text-white');
highlightedElements.push(pageNumElement);
highlightedRanges.add(rangeKey);
}
}
}
});
// Auto-scroll to first highlighted element if it exists
if (highlightedElements.length > 0) {
scrollToHighlightedPage(highlightedElements[0]);
}
// 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');
});
// Highlight page indicators for all current pages
pageNumbers.forEach(pageNumber => {
const pageIndicator = document.querySelector(`.page-indicator[data-page="${pageNumber}"]`);
if (pageIndicator) {
pageIndicator.classList.remove('bg-blue-50', 'bg-green-50', 'bg-amber-50', 'text-slate-600');
pageIndicator.classList.add('bg-red-500', 'text-white');
}
});
}
function scrollToHighlightedPage(element) {
// Check if the element is in a scrollable container
const inhaltsContainer = element.closest('.lg\\:overflow-y-auto');
if (inhaltsContainer) {
// Calculate position
const containerRect = inhaltsContainer.getBoundingClientRect();
const elementRect = element.getBoundingClientRect();
// Check if element is not fully visible
const isAboveContainer = elementRect.top < containerRect.top;
const isBelowContainer = elementRect.bottom > containerRect.bottom;
if (isAboveContainer || isBelowContainer) {
// Scroll to make element visible with some padding
element.scrollIntoView({
behavior: 'smooth',
block: 'center'
});
}
}
}
// 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();
}
});
function shareCurrentPage() {
const button = document.getElementById('shareLinkBtn');
// Get current page information
let pageInfo = '';
// Try to get the currently visible page number from active containers
if (window.currentActiveIndex !== undefined && window.currentPageContainers && window.currentPageContainers[window.currentActiveIndex]) {
const activeContainer = window.currentPageContainers[window.currentActiveIndex];
const pageElement = activeContainer.querySelector('[data-page]');
if (pageElement) {
const pageNumber = pageElement.getAttribute('data-page');
pageInfo = `#page-${pageNumber}`;
}
}
// Construct the shareable URL
const currentUrl = window.location.origin + window.location.pathname + pageInfo;
// Try to use Web Share API if available (mobile browsers)
if (navigator.share) {
navigator.share({
title: document.title,
url: currentUrl
}).catch(err => {
console.log('Error sharing:', err);
// Fallback to clipboard
copyToClipboard(currentUrl, button);
});
} else {
// Fallback: copy to clipboard
copyToClipboard(currentUrl, button);
}
}
function copyToClipboard(text, button) {
if (navigator.clipboard) {
navigator.clipboard.writeText(text).then(() => {
// Show temporary notification
showNotification('Link kopiert!', 'success', button);
}).catch(err => {
console.error('Failed to copy:', err);
showNotification('Kopieren fehlgeschlagen', 'error', button);
});
} else {
// Fallback for older browsers
const textarea = document.createElement('textarea');
textarea.value = text;
document.body.appendChild(textarea);
textarea.select();
try {
document.execCommand('copy');
showNotification('Link kopiert!', 'success', button);
} catch (err) {
console.error('Fallback copy failed:', err);
showNotification('Kopieren fehlgeschlagen', 'error', button);
}
document.body.removeChild(textarea);
}
}
function generateCitation() {
const button = document.getElementById('citationBtn');
// Get current page and issue information
const issueInfo = document.title || 'KGPZ';
const currentUrl = window.location.href;
// Basic citation format (can be expanded later)
const currentDate = new Date().toLocaleDateString('de-DE');
const citation = `Königsberger Gelehrte und Politische Zeitung (KGPZ). ${issueInfo}. Digital verfügbar unter: ${currentUrl} (Zugriff: ${currentDate}).`;
// Copy citation to clipboard
copyToClipboard(citation, button);
}
function showNotification(message, type = 'success', button) {
// Remove any existing notifications
const existingNotification = document.getElementById('notification');
if (existingNotification) {
existingNotification.remove();
}
// Create notification element
const notification = document.createElement('div');
notification.id = 'notification';
notification.className = `fixed px-3 py-2 rounded-md text-white text-sm font-medium z-50 transition-opacity duration-300 ${
type === 'success' ? 'bg-green-500' : 'bg-red-500'
}`;
notification.textContent = message;
// Position notification next to button if button is provided
if (button) {
const buttonRect = button.getBoundingClientRect();
notification.style.left = `${buttonRect.left - 80}px`; // Position to the left of button
notification.style.top = `${buttonRect.top + buttonRect.height / 2 - 20}px`; // Center vertically with button
} else {
// Fallback to top-right corner
notification.className += ' top-4 right-4';
}
// Add to page
document.body.appendChild(notification);
// Auto-remove after 3 seconds
setTimeout(() => {
notification.style.opacity = '0';
setTimeout(() => {
notification.remove();
}, 300);
}, 3000);
}
</script>