newWebsite2.0
This commit is contained in:
102
mini/js/main.js
Normal file
102
mini/js/main.js
Normal file
@@ -0,0 +1,102 @@
|
||||
import { initTodayPage } from './modules/today.js';
|
||||
import { initSequencePage } from './modules/sequence.js';
|
||||
import { initKnowledgePage } from './modules/knowledge.js';
|
||||
|
||||
document.addEventListener("DOMContentLoaded", () => {
|
||||
const container = document.getElementById("content-container");
|
||||
const triggers = document.querySelectorAll("[data-file]");
|
||||
const settingsBtn = document.getElementById('settingsBtn');
|
||||
const settingsModal = document.getElementById('settingsModal');
|
||||
const closeSettingsBtn = document.getElementById('closeSettingsBtn');
|
||||
const darkModeToggle = document.getElementById('darkModeToggle');
|
||||
|
||||
settingsBtn.addEventListener('click', () => {
|
||||
settingsModal.classList.add('active');
|
||||
});
|
||||
|
||||
closeSettingsBtn.addEventListener('click', () => {
|
||||
settingsModal.classList.remove('active');
|
||||
});
|
||||
|
||||
settingsModal.addEventListener('click', (e) => {
|
||||
if (e.target === settingsModal) {
|
||||
settingsModal.classList.remove('active');
|
||||
}
|
||||
});
|
||||
|
||||
document.addEventListener('keydown', (e) => {
|
||||
if (e.key === 'Escape' && settingsModal.classList.contains('active')) {
|
||||
settingsModal.classList.remove('active');
|
||||
}
|
||||
});
|
||||
|
||||
const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)');
|
||||
const systemPrefersDark = mediaQuery.matches;
|
||||
|
||||
const storedDarkMode = localStorage.getItem('darkMode');
|
||||
|
||||
let isDark;
|
||||
if (storedDarkMode !== null) {
|
||||
isDark = storedDarkMode === 'true';
|
||||
} else {
|
||||
isDark = systemPrefersDark;
|
||||
}
|
||||
|
||||
function applyDarkMode(enable) {
|
||||
document.body.classList.toggle('dark-mode', enable);
|
||||
if (darkModeToggle) {
|
||||
darkModeToggle.checked = enable;
|
||||
}
|
||||
}
|
||||
|
||||
applyDarkMode(isDark);
|
||||
|
||||
darkModeToggle.addEventListener('change', () => {
|
||||
const isDarkNow = darkModeToggle.checked;
|
||||
applyDarkMode(isDarkNow);
|
||||
localStorage.setItem('darkMode', isDarkNow);
|
||||
});
|
||||
|
||||
function handleSystemChange(e) {
|
||||
if (localStorage.getItem('darkMode') === null) {
|
||||
applyDarkMode(e.matches);
|
||||
}
|
||||
}
|
||||
|
||||
if (mediaQuery.addEventListener) {
|
||||
mediaQuery.addEventListener('change', handleSystemChange);
|
||||
} else {
|
||||
mediaQuery.addListener(handleSystemChange);
|
||||
}
|
||||
|
||||
|
||||
async function loadPage(file) {
|
||||
try {
|
||||
const response = await fetch(file);
|
||||
if (!response.ok) throw new Error("Error loading page: " + response.statusText);
|
||||
|
||||
container.innerHTML = await response.text();
|
||||
|
||||
triggers.forEach(item => {
|
||||
item.classList.toggle("active", item.getAttribute("data-file") === file);
|
||||
});
|
||||
|
||||
if (file.includes("today")) initTodayPage();
|
||||
if (file.includes("sequence")) initSequencePage();
|
||||
if (file.includes("knowledge")) initKnowledgePage();
|
||||
|
||||
} catch (error) {
|
||||
container.innerHTML = "<p>Error loading content.</p>";
|
||||
console.error(error);
|
||||
}
|
||||
}
|
||||
|
||||
loadPage("pages/today.html");
|
||||
|
||||
triggers.forEach(trigger => {
|
||||
trigger.addEventListener("click", (e) => {
|
||||
e.preventDefault();
|
||||
loadPage(trigger.getAttribute("data-file"));
|
||||
});
|
||||
});
|
||||
});
|
||||
95
mini/js/modules/knowledge.js
Normal file
95
mini/js/modules/knowledge.js
Normal file
@@ -0,0 +1,95 @@
|
||||
export async function initKnowledgePage() {
|
||||
const wissenList = document.getElementById('wissen-list');
|
||||
const gebeteList = document.getElementById('gebete-list');
|
||||
|
||||
if (wissenList) {
|
||||
try {
|
||||
const knowledgeResponse = await fetch('data/knowledge/knowledge.json');
|
||||
const knowledgeItems = await knowledgeResponse.json();
|
||||
renderKnowledgeList(wissenList, knowledgeItems);
|
||||
} catch (error) {
|
||||
console.error('Fehler beim Laden der Wissens-Übersicht:', error);
|
||||
}
|
||||
}
|
||||
|
||||
if (gebeteList) {
|
||||
try {
|
||||
const gebeteResponse = await fetch('data/prayers/prayers.json');
|
||||
const gebeteItems = await gebeteResponse.json();
|
||||
renderGebeteList(gebeteList, gebeteItems);
|
||||
} catch (error) {
|
||||
console.error('Fehler beim Laden der Gebete:', error);
|
||||
}
|
||||
}
|
||||
|
||||
const tabs = document.querySelectorAll('.wissen-tab');
|
||||
const panelGebete = document.getElementById('panel-gebete');
|
||||
const panelWissen = document.getElementById('panel-wissen');
|
||||
|
||||
tabs.forEach(tab => {
|
||||
tab.addEventListener('click', () => {
|
||||
tabs.forEach(t => t.classList.remove('active'));
|
||||
tab.classList.add('active');
|
||||
|
||||
const target = tab.dataset.tab;
|
||||
if (panelGebete) panelGebete.classList.toggle('active', target === 'gebete');
|
||||
if (panelWissen) panelWissen.classList.toggle('active', target === 'wissen');
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function createAccordionItem(title, filename, basePath) {
|
||||
const element = document.createElement('div');
|
||||
element.className = 'wissen-item';
|
||||
|
||||
element.innerHTML = `
|
||||
<button class="wissen-header">
|
||||
<span class="wissen-title">${title}</span>
|
||||
<img src="assets/icons/arrow_down.svg" alt="Pfeil nach unten" class="wissen-arrow">
|
||||
</button>
|
||||
<div class="wissen-content">
|
||||
<p class="loading">Loading...</p>
|
||||
</div>
|
||||
`;
|
||||
|
||||
const header = element.querySelector('.wissen-header');
|
||||
const contentDiv = element.querySelector('.wissen-content');
|
||||
let isLoaded = false;
|
||||
|
||||
header.addEventListener('click', async () => {
|
||||
element.classList.toggle('active');
|
||||
|
||||
if (element.classList.contains('active') && !isLoaded) {
|
||||
try {
|
||||
const contentResponse = await fetch(`${basePath}/${filename}`);
|
||||
if (!contentResponse.ok) throw new Error('Failed to load file');
|
||||
|
||||
const htmlContent = await contentResponse.text();
|
||||
contentDiv.innerHTML = htmlContent;
|
||||
isLoaded = true;
|
||||
} catch (err) {
|
||||
contentDiv.innerHTML = '<p>Failed to load content.</p>';
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return element;
|
||||
}
|
||||
|
||||
function renderKnowledgeList(container, items) {
|
||||
container.innerHTML = '';
|
||||
items.forEach(item => {
|
||||
const title = item.titel || item.title;
|
||||
const element = createAccordionItem(title, item.file, 'data/knowledge');
|
||||
container.appendChild(element);
|
||||
});
|
||||
}
|
||||
|
||||
function renderGebeteList(container, items) {
|
||||
container.innerHTML = '';
|
||||
items.forEach(item => {
|
||||
const title = item.title || item.titel;
|
||||
const element = createAccordionItem(title, item.file, 'data/prayers');
|
||||
container.appendChild(element);
|
||||
});
|
||||
}
|
||||
120
mini/js/modules/sequence.js
Normal file
120
mini/js/modules/sequence.js
Normal file
@@ -0,0 +1,120 @@
|
||||
export async function initSequencePage() {
|
||||
|
||||
const listContainer = document.getElementById('sequence-list') || document.getElementById('ablauf-list');
|
||||
const filterChips = document.querySelectorAll('.filter-chip');
|
||||
|
||||
if (!listContainer) {
|
||||
console.warn('Sequence container not found.');
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await fetch('data/sequence/sequence.json');
|
||||
if (!response.ok) throw new Error('Sequence data could not be loaded.');
|
||||
|
||||
const sequenceSteps = await response.json();
|
||||
|
||||
renderSequenceList(listContainer, sequenceSteps);
|
||||
setupFilterLogic(filterChips);
|
||||
|
||||
} catch (error) {
|
||||
console.error('Error loading sequence:', error);
|
||||
listContainer.innerHTML = '<p>Sequence could not be loaded.</p>';
|
||||
}
|
||||
}
|
||||
|
||||
function renderSequenceList(container, steps) {
|
||||
container.innerHTML = '';
|
||||
|
||||
steps.forEach(step => {
|
||||
const item = document.createElement('div');
|
||||
item.className = 'ablauf-item';
|
||||
item.dataset.categories = step.categories.join(',');
|
||||
|
||||
item.innerHTML = `
|
||||
<button class="sequence-header">
|
||||
<span class="sequence-title">${step.title}</span>
|
||||
<i data-lucide="chevron-down" class="ablauf-arrow"></i>
|
||||
</button>
|
||||
<div class="sequence-content">
|
||||
<p class="loading">Loading...</p>
|
||||
</div>
|
||||
`;
|
||||
|
||||
const header = item.querySelector('.sequence-header');
|
||||
const contentDiv = item.querySelector('.sequence-content');
|
||||
let isLoaded = false;
|
||||
|
||||
header.addEventListener('click', async () => {
|
||||
item.classList.toggle('active');
|
||||
|
||||
if (item.classList.contains('active') && !isLoaded) {
|
||||
try {
|
||||
const contentResponse = await fetch(`data/sequence/${step.file}`);
|
||||
if (!contentResponse.ok) throw new Error('Content not found.');
|
||||
|
||||
const htmlContent = await contentResponse.text();
|
||||
contentDiv.innerHTML = htmlContent;
|
||||
isLoaded = true;
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
contentDiv.innerHTML = '<p>Content could not be loaded.</p>';
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
container.appendChild(item);
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
function setupFilterLogic(filterChips) {
|
||||
if (!filterChips || filterChips.length === 0) return;
|
||||
|
||||
let activeFilters = new Set(['alle']);
|
||||
|
||||
function applyFilters() {
|
||||
document.querySelectorAll('.ablauf-item').forEach(item => {
|
||||
const categories = item.dataset.categories ? item.dataset.categories.split(',') : [];
|
||||
|
||||
const isVisible = activeFilters.has('alle') ||
|
||||
categories.some(cat => activeFilters.has(cat));
|
||||
|
||||
item.style.display = isVisible ? '' : 'none';
|
||||
});
|
||||
}
|
||||
|
||||
filterChips.forEach(chip => {
|
||||
chip.addEventListener('click', () => {
|
||||
const filter = chip.dataset.filter;
|
||||
|
||||
if (filter === 'alle') {
|
||||
activeFilters = new Set(['alle']);
|
||||
filterChips.forEach(c => c.classList.remove('active'));
|
||||
chip.classList.add('active');
|
||||
} else {
|
||||
if (activeFilters.has('alle')) {
|
||||
activeFilters.delete('alle');
|
||||
document.querySelector('.filter-chip[data-filter="alle"]')?.classList.remove('active');
|
||||
}
|
||||
|
||||
if (activeFilters.has(filter)) {
|
||||
activeFilters.delete(filter);
|
||||
chip.classList.remove('active');
|
||||
} else {
|
||||
activeFilters.add(filter);
|
||||
chip.classList.add('active');
|
||||
}
|
||||
|
||||
if (activeFilters.size === 0) {
|
||||
activeFilters.add('alle');
|
||||
document.querySelector('.filter-chip[data-filter="alle"]')?.classList.add('active');
|
||||
}
|
||||
}
|
||||
|
||||
applyFilters();
|
||||
});
|
||||
});
|
||||
|
||||
applyFilters();
|
||||
}
|
||||
227
mini/js/modules/today.js
Normal file
227
mini/js/modules/today.js
Normal file
@@ -0,0 +1,227 @@
|
||||
export async function initTodayPage() {
|
||||
|
||||
const today = new Date();
|
||||
document.getElementById('weekday').textContent = today.toLocaleDateString('de-DE', { weekday: 'long' });
|
||||
document.getElementById('date').textContent = today.toLocaleDateString('de-DE', { day: '2-digit', month: 'long', year: 'numeric' });
|
||||
|
||||
const miniColor = getMiniColor(today);
|
||||
const miniAmount = getMiniAmount(today);
|
||||
|
||||
document.getElementById('summary-color').textContent = miniColor;
|
||||
document.getElementById('summary-count').textContent = miniAmount;
|
||||
|
||||
const modal = document.getElementById('task-modal');
|
||||
if (!modal) return;
|
||||
|
||||
try {
|
||||
const [tasksResponse, placementsResponse] = await Promise.all([
|
||||
fetch('data/tasks.json'),
|
||||
fetch('data/placements.json')
|
||||
]);
|
||||
|
||||
const taskData = await tasksResponse.json();
|
||||
const placementData = await placementsResponse.json();
|
||||
|
||||
setupTaskModal(modal, taskData);
|
||||
setupPlacementViewer(placementData);
|
||||
} catch (error) {
|
||||
console.error('Error while loading data:', error);
|
||||
}
|
||||
}
|
||||
|
||||
function setupTaskModal(modal, taskData) {
|
||||
const modalIcon = document.getElementById('modal-icon');
|
||||
const modalTitle = document.getElementById('modal-title');
|
||||
const modalDescription = document.getElementById('modal-description');
|
||||
const modalSteps = document.getElementById('modal-steps');
|
||||
const closeBtn = modal.querySelector('.modal-close');
|
||||
const segContainer = document.getElementById('task-segmented-control');
|
||||
|
||||
document.querySelectorAll('.task-card').forEach(card => {
|
||||
card.addEventListener('click', () => {
|
||||
const data = taskData[card.dataset.task];
|
||||
if (!data) return;
|
||||
|
||||
modalIcon.src = data.icon;
|
||||
modalTitle.textContent = data.title;
|
||||
|
||||
if (data.description) {
|
||||
modalDescription.textContent = data.description;
|
||||
modalDescription.style.display = '';
|
||||
} else {
|
||||
modalDescription.style.display = 'none';
|
||||
}
|
||||
|
||||
const steps = data.steps;
|
||||
let sections = [];
|
||||
let isFlat = false;
|
||||
|
||||
if (Array.isArray(steps) && steps.length > 0) {
|
||||
if (typeof steps[0] === 'object' && steps[0].steps && Array.isArray(steps[0].steps)) {
|
||||
sections = steps;
|
||||
} else {
|
||||
sections = [{ title: null, steps: steps }];
|
||||
isFlat = true;
|
||||
}
|
||||
} else {
|
||||
sections = [{ title: null, steps: [] }];
|
||||
isFlat = true;
|
||||
}
|
||||
|
||||
const renderSteps = (stepsArray) => {
|
||||
modalSteps.innerHTML = stepsArray.map(step => `<li>${step}</li>`).join('');
|
||||
};
|
||||
|
||||
if (sections.length > 1 && !isFlat) {
|
||||
segContainer.style.display = 'flex';
|
||||
segContainer.innerHTML = '';
|
||||
|
||||
sections.forEach((section, index) => {
|
||||
const btn = document.createElement('button');
|
||||
btn.className = 'segmented-btn' + (index === 0 ? ' active' : '');
|
||||
btn.textContent = section.title;
|
||||
btn.dataset.index = index;
|
||||
btn.addEventListener('click', () => {
|
||||
segContainer.querySelectorAll('.segmented-btn').forEach(b => b.classList.remove('active'));
|
||||
btn.classList.add('active');
|
||||
renderSteps(sections[index].steps);
|
||||
});
|
||||
segContainer.appendChild(btn);
|
||||
});
|
||||
|
||||
renderSteps(sections[0].steps);
|
||||
} else {
|
||||
segContainer.style.display = 'none';
|
||||
if (sections.length === 1) {
|
||||
renderSteps(sections[0].steps);
|
||||
} else {
|
||||
renderSteps(steps); // Fallback
|
||||
}
|
||||
}
|
||||
|
||||
modal.classList.add('active');
|
||||
});
|
||||
});
|
||||
|
||||
// Schließen
|
||||
closeBtn?.addEventListener('click', () => modal.classList.remove('active'));
|
||||
modal.addEventListener('click', (e) => {
|
||||
if (e.target === modal) modal.classList.remove('active');
|
||||
});
|
||||
}
|
||||
function setupPlacementViewer(placementData) {
|
||||
let currentIndex = 0;
|
||||
let showIncense = false;
|
||||
|
||||
const placementImage = document.getElementById('placement-image');
|
||||
const placementLabel = document.getElementById('placement-label');
|
||||
const prevBtn = document.getElementById('placement-prev');
|
||||
const nextBtn = document.getElementById('placement-next');
|
||||
const weihrauchToggle = document.getElementById('incense-toggle');
|
||||
const koerbchenLegend = document.getElementById('basket-toggle');
|
||||
const weihrauchLegend = document.getElementById('incense-legend');
|
||||
const kerzeLabel = document.getElementById('kerze-label');
|
||||
|
||||
function updatePlacement() {
|
||||
const dataset = showIncense ? placementData.withWeihrauch : placementData.standard;
|
||||
const currentItem = dataset[currentIndex];
|
||||
|
||||
if (!currentItem) return;
|
||||
|
||||
placementImage.src = currentItem.image;
|
||||
placementLabel.textContent = currentItem.label;
|
||||
kerzeLabel.textContent = showIncense ? 'Kerze & Kollekte' : 'Kerze';
|
||||
|
||||
const isEntranceWithIncense = showIncense && currentIndex === 0;
|
||||
koerbchenLegend.style.display = isEntranceWithIncense ? 'none' : '';
|
||||
weihrauchLegend.style.display = isEntranceWithIncense ? '' : 'none';
|
||||
}
|
||||
|
||||
prevBtn?.addEventListener('click', () => {
|
||||
currentIndex = (currentIndex - 1 + 3) % 3;
|
||||
updatePlacement();
|
||||
});
|
||||
|
||||
nextBtn?.addEventListener('click', () => {
|
||||
currentIndex = (currentIndex + 1) % 3;
|
||||
updatePlacement();
|
||||
});
|
||||
|
||||
weihrauchToggle?.addEventListener('click', () => {
|
||||
showIncense = !showIncense;
|
||||
weihrauchToggle.classList.toggle('active', showIncense);
|
||||
updatePlacement();
|
||||
});
|
||||
|
||||
updatePlacement();
|
||||
}
|
||||
|
||||
function getOstern(jahr) {
|
||||
const a = jahr % 19;
|
||||
const b = jahr % 4;
|
||||
const c = jahr % 7;
|
||||
const k = Math.floor(jahr / 100);
|
||||
const p = Math.floor((13 + 8 * k) / 25);
|
||||
const q = Math.floor(k / 4);
|
||||
const M = (15 - p + k - q) % 30;
|
||||
const N = (4 + k - q) % 7;
|
||||
const d = (19 * a + M) % 30;
|
||||
const e = (2 * b + 4 * c + 6 * d + N) % 7;
|
||||
const days = 22 + d + e;
|
||||
|
||||
if (days <= 31) {
|
||||
return new Date(jahr, 2, days);
|
||||
} else {
|
||||
return new Date(jahr, 3, days - 31);
|
||||
}
|
||||
}
|
||||
|
||||
function tageDifferenz(datum1, datum2) {
|
||||
const day = 24 * 60 * 60 * 1000;
|
||||
return Math.round((datum1 - datum2) / day);
|
||||
}
|
||||
|
||||
function getMiniColor(targetDate) {
|
||||
const year = targetDate.getFullYear();
|
||||
const easter = getOstern(year);
|
||||
const diffToEaster = tageDifferenz(targetDate, easter);
|
||||
|
||||
const month = targetDate.getMonth();
|
||||
const day = targetDate.getDate();
|
||||
const wochentag = targetDate.getDay();
|
||||
|
||||
if ((month === 11 && day >= 24) || (month === 0 && day <= 10)) {
|
||||
return "GRÜN";
|
||||
}
|
||||
|
||||
if (diffToEaster >= -46 && diffToEaster <= -1) {
|
||||
if (diffToEaster === -7 || diffToEaster === -2) {
|
||||
return "ROT";
|
||||
}
|
||||
return "LILA";
|
||||
}
|
||||
|
||||
if (diffToEaster >= 0 && diffToEaster <= 50) {
|
||||
if (diffToEaster === 50) {
|
||||
return "ROT";
|
||||
}
|
||||
return "GRÜN";
|
||||
}
|
||||
|
||||
let holyEvening = new Date(year, 11, 24);
|
||||
let fourthAdvent = new Date(year, 11, 24 - holyEvening.getDay());
|
||||
let firstAdvent = new Date(fourthAdvent);
|
||||
firstAdvent.setDate(fourthAdvent.getDate() - 21);
|
||||
|
||||
if (targetDate >= firstAdvent && targetDate < holyEvening) {
|
||||
return "LILA";
|
||||
}
|
||||
|
||||
return "GRÜN";
|
||||
}
|
||||
|
||||
function getMiniAmount(targetDate) {
|
||||
const amount = (targetDate.getDay() === 0 || targetDate.getDay() === 6) ? 6 : 4;
|
||||
|
||||
return amount;
|
||||
}
|
||||
Reference in New Issue
Block a user