import { DateTime } from 'luxon'; import { fetchJson } from '../../api.js'; import type { LauncherWebSingleEnt, StoredData } from '../../types.js'; import { BASE_URL, gameTargets, launcherWebApiLang } from '../../utils/constants.js'; export async function renderSingleEnt(container: HTMLElement) { const outerCard = document.createElement('div'); outerCard.className = 'card mb-3'; const header = document.createElement('div'); header.className = 'card-header d-flex justify-content-between align-items-center'; header.style.cursor = 'pointer'; header.setAttribute('data-bs-toggle', 'collapse'); header.setAttribute('data-bs-target', '#collapseSingleEnt'); header.setAttribute('role', 'button'); header.innerHTML = '

Single Ent.

'; outerCard.appendChild(header); const collapseDiv = document.createElement('div'); collapseDiv.id = 'collapseSingleEnt'; collapseDiv.className = 'collapse'; outerCard.appendChild(collapseDiv); const outerCardBody = document.createElement('div'); outerCardBody.className = 'card-body'; collapseDiv.appendChild(outerCardBody); // --- UI Controls --- const controls = document.createElement('div'); controls.className = 'row g-3 mb-4'; const targetCol = document.createElement('div'); targetCol.className = 'col-md-6'; targetCol.innerHTML = ''; const targetSelect = document.createElement('select'); targetSelect.className = 'form-select'; gameTargets.forEach((target, idx) => { const option = document.createElement('option'); option.value = idx.toString(); option.textContent = `${target.region === 'cn' ? 'China' : 'Global'} - ${target.name}`; targetSelect.appendChild(option); }); targetCol.appendChild(targetSelect); const langCol = document.createElement('div'); langCol.className = 'col-md-6'; langCol.innerHTML = ''; const langSelect = document.createElement('select'); langSelect.className = 'form-select'; langCol.appendChild(langSelect); controls.appendChild(targetCol); controls.appendChild(langCol); outerCardBody.appendChild(controls); const contentDiv = document.createElement('div'); outerCardBody.appendChild(contentDiv); // --- Logic --- const updateLanguages = () => { const targetIdx = parseInt(targetSelect.value, 10); const target = gameTargets[targetIdx]!; const langs = launcherWebApiLang[target.region] || []; const defaultLang = target.region === 'os' ? 'en-us' : 'zh-cn'; langSelect.innerHTML = ''; langs.forEach((lang) => { const option = document.createElement('option'); option.value = lang; option.textContent = lang; if (lang === defaultLang) option.selected = true; langSelect.appendChild(option); }); langCol.style.display = langs.length <= 1 ? 'none' : 'block'; }; const getMirrorUrl = (url: string) => { if (!url) return ''; try { const u = new URL(url); return `https://raw.githubusercontent.com/daydreamer-json/ak-endfield-api-archive/refs/heads/main/output/raw/${u.hostname}${u.pathname}`; } catch { return url; } }; const renderContent = async () => { const targetIdx = parseInt(targetSelect.value, 10); const target = gameTargets[targetIdx]!; const lang = langSelect.value; if (!lang) { contentDiv.innerHTML = '
No language selected.
'; return; } contentDiv.innerHTML = '
Loading single entry data...
'; const url = `${BASE_URL}/akEndfield/launcher/web/${target.dirName}/single_ent/${lang}/all.json`; try { const data = await fetchJson[]>(url); if (!data || data.length === 0) { contentDiv.innerHTML = '
No data found.
'; return; } // Collect unique visuals by MD5 from the entire history const entMap = new Map(); const sortedData = [...data].sort( (a, b) => DateTime.fromISO(b.updatedAt).toMillis() - DateTime.fromISO(a.updatedAt).toMillis(), ); for (const entry of sortedData) { if (!entry.rsp || !entry.rsp.single_ent) continue; const ent = entry.rsp.single_ent; const key = ent.version_md5 || ent.version_url; if (!entMap.has(key)) { entMap.set(key, { ent, firstSeen: entry.updatedAt }); } } contentDiv.innerHTML = ''; if (entMap.size === 0) { contentDiv.innerHTML = '
No data found.
'; return; } const row = document.createElement('div'); row.className = 'row row-cols-1 row-cols-md-2 g-4'; contentDiv.appendChild(row); for (const [_key, { ent, firstSeen }] of entMap) { const col = document.createElement('div'); col.className = 'col'; const card = document.createElement('div'); card.className = 'card h-100 shadow-sm'; let innerHtml = `
First seen: ${DateTime.fromISO(firstSeen).toFormat('yyyy/MM/dd HH:mm')} ${ent.need_token ? 'Auth' : ''}
Version Image

MD5: ${ent.version_md5}

`; if (ent.button_url) { innerHtml += `
Button

Normal

${ ent.button_hover_url ? `
Button Hover

Hover

` : '' }
`; } if (ent.jump_url) { innerHtml += ` Jump URL `; } innerHtml += '
'; card.innerHTML = innerHtml; col.appendChild(card); row.appendChild(col); } } catch (e) { console.warn(`Failed to load ${url}`, e); contentDiv.innerHTML = '
Failed to load data.
'; } }; targetSelect.addEventListener('change', () => { updateLanguages(); renderContent(); }); langSelect.addEventListener('change', renderContent); updateLanguages(); renderContent(); container.appendChild(outerCard); }