document.addEventListener('DOMContentLoaded', function() { const shuffleContainers = document.querySelectorAll('.shuffle-container'); const seed = Date.now(); shuffleContainers.forEach(container => { seededShuffleChildren(container, seed); }); const starterkits = document.querySelectorAll('.starterkit'); starterkits.forEach(kit => { const authorAccount = kit.querySelector('.autor .account'); if (authorAccount) { try { const url = new URL(authorAccount.getAttribute('href')); const pathParts = url.pathname.split('/'); if (pathParts.length > 1 && pathParts[1].startsWith('@')) { const handle = pathParts[1].substring(1); const instance = url.hostname; const lookupUrl = `https://${config.homeInstance}/api/v1/accounts/lookup?acct=${handle}@${instance}`; fetch(lookupUrl) .then(response => response.json()) .then(data => { const avatarImage = document.createElement('img'); avatarImage.classList.add('account-avatar'); avatarImage.alt = data.avatar ? `Profilbild von ${data.username}` : 'Profilbild nicht verfügbar'; avatarImage.src = data.avatar || ''; authorAccount.prepend(avatarImage); // Ergänze die Klasse basierend auf der Instanz const serverClass = getServerClass(instance); if (serverClass) { authorAccount.classList.add(serverClass); } }) .catch(error => { console.error('Fehler beim Abrufen des Autoren-Profils:', error); }); } else { console.error('Ungültiger Benutzer-Handle in URL:', url.href); } } catch (error) { console.error('Fehler bei der Verarbeitung der URL:', error); } } const accounts = kit.querySelectorAll('.account'); accounts.forEach(account => { const parent = account.closest('.autor'); if (!parent) { account.style.display = 'none'; } }); // Zeige die Anzahl der Accounts auf der StarterKit-Kachel const accountCount = kit.querySelectorAll('.account:not(.autor .account)').length; const accountCountElement = document.createElement('div'); accountCountElement.classList.add('account-count'); accountCountElement.textContent = `${accountCount} Profile`; kit.appendChild(accountCountElement); // Füge Event-Listener für StarterKit-Kacheln hinzu kit.addEventListener('click', function() { const title = kit.querySelector('h3').textContent; const accountsForPopup = Array.from(kit.querySelectorAll('.account')).filter(account => !account.closest('.autor')); const popup = createRecommendationPopup(accountsForPopup, title); document.body.appendChild(popup); }); }); }); /** * Funktion zum Erstellen eines Pop-ups. * @param {NodeList} accounts - Die Liste der Accounts für das Pop-up. * @param {string} title - Der Titel des StarterKits. * @returns {HTMLElement} - Das erzeugte Pop-up-Element. */ function createRecommendationPopup(accounts, title) { // Overlay erstellen const overlay = document.createElement('div'); overlay.classList.add('recommendation-popup'); // Pop-up-Inhalt const content = document.createElement('div'); content.classList.add('recommendation-popup-content'); // Header des Pop-ups const header = document.createElement('div'); header.classList.add('recommendation-popup-header'); const titleElement = document.createElement('h3'); titleElement.textContent = title; const closeButton = document.createElement('button'); closeButton.classList.add('close-popup'); closeButton.textContent = '×'; closeButton.addEventListener('click', () => overlay.remove()); // Schließen-Funktion header.appendChild(titleElement); header.appendChild(closeButton); // Body des Pop-ups const body = document.createElement('div'); body.classList.add('recommendation-popup-body'); accounts.forEach(account => { try { const url = new URL(account.getAttribute('href')); const pathParts = url.pathname.split('/'); if (pathParts.length > 1 && pathParts[1].startsWith('@')) { const handle = pathParts[1].substring(1); const instance = url.hostname; const lookupUrl = `https://${config.homeInstance}/api/v1/accounts/lookup?acct=${handle}@${instance}`; fetch(lookupUrl) .then(response => response.json()) .then(data => { const card = createAccountCard(data, account.href, instance); body.appendChild(card); }) .catch(error => { console.error('Fehler beim Abrufen des Profils:', error); }); } else { console.error('Ungültiger Benutzer-Handle in URL:', url.href); } } catch (error) { console.error('Fehler bei der Verarbeitung der URL:', error); } }); // Pop-up zusammenfügen content.appendChild(header); content.appendChild(body); overlay.appendChild(content); // Event-Listener für Overlay (schließt Pop-up bei Klick auf Hintergrund) overlay.addEventListener('click', function(event) { if (event.target === overlay) { overlay.remove(); } }); return overlay; } /** * Funktion zum Erstellen einer Account-Kachel. * @param {Object} data - Die Account-Daten von der API. * @param {string} href - Die URL des Accounts. * @param {string} instance - Der Instanz-Name. * @returns {HTMLElement} - Die erzeugte Account-Kachel. */ function createAccountCard(data, href, instance) { const link = document.createElement('a'); link.classList.add('account-card-link'); link.href = href; link.target = '_blank'; const card = document.createElement('div'); card.classList.add('account-card'); const avatarImage = document.createElement('img'); avatarImage.classList.add('account-avatar'); avatarImage.alt = data.avatar ? `Profilbild von ${data.username}` : 'Profilbild nicht verfügbar'; avatarImage.src = data.avatar || ''; const infoContainer = document.createElement('div'); infoContainer.classList.add('account-info'); const displayNameElement = document.createElement('p'); displayNameElement.classList.add('display-name'); displayNameElement.textContent = data.display_name || data.username; const handleElement = document.createElement('p'); handleElement.classList.add('handle'); const serverHandleElement = document.createElement('span'); serverHandleElement.classList.add('server-handle'); serverHandleElement.textContent = `@${instance}`; // Ergänze die Klasse basierend auf der Instanz const serverClass = getServerClass(instance); if (serverClass) { serverHandleElement.classList.add(serverClass); } handleElement.textContent = `@${data.username}`; handleElement.appendChild(serverHandleElement); infoContainer.appendChild(displayNameElement); infoContainer.appendChild(handleElement); card.appendChild(avatarImage); card.appendChild(infoContainer); link.appendChild(card); return link; } /** * Funktion, um die Kinder eines Containers deterministisch neu anzuordnen. * @param {HTMLElement} container - Der Container, dessen Kinder durchmischt werden sollen. * @param {number} seed - Der Seed für das deterministische Shuffle. */ function seededShuffleChildren(container, seed) { const children = Array.from(container.children); const shuffled = seededShuffle(children, seed); shuffled.forEach(child => container.appendChild(child)); } /** * Funktion für einen deterministischen Shuffle-Algorithmus. * @param {Array} array - Das Array, das gemischt werden soll. * @param {number} seed - Der Seed für das deterministische Shuffle. * @returns {Array} - Das gemischte Array. */ function seededShuffle(array, seed) { for (let i = array.length - 1; i > 0; i--) { const j = Math.floor(seededRandom(seed++) * (i + 1)); [array[i], array[j]] = [array[j], array[i]]; } return array; } /** * Funktion für einen deterministischen Zufallswert. * @param {number} seed - Der Seed für den Zufallswert. * @returns {number} - Der generierte Zufallswert. */ function seededRandom(seed) { const x = Math.sin(seed++) * 10000; return x - Math.floor(x); } /** * Funktion zur Zuordnung von Instanzen zu CSS-Klassen. * @param {string} instance - Der Name der Instanz. * @returns {string|null} - Die zugehörige CSS-Klasse oder null, wenn keine Übereinstimmung vorliegt. */ function getServerClass(instance) { const serverClasses = { 'libori.social': 'liboriSocial', 'reliverse.social': 'reliverseSocial', 'kirche.social': 'kircheSocial', 'katholisch.social': 'katholischSocial' }; return serverClasses[instance] || null; }