From 32cb37884ed7b622cdac03f314d6d6aff4d22856 Mon Sep 17 00:00:00 2001 From: daydreamer-json Date: Sun, 8 Mar 2026 03:37:48 +0900 Subject: [PATCH] pages: Add Web (Raw) tab --- pages/src/assets/ts/index.ts | 4 + pages/src/assets/ts/renderers/web.ts | 157 +++++++++++++++++++++++++++ 2 files changed, 161 insertions(+) create mode 100644 pages/src/assets/ts/renderers/web.ts diff --git a/pages/src/assets/ts/index.ts b/pages/src/assets/ts/index.ts index 161668b..d251d22 100644 --- a/pages/src/assets/ts/index.ts +++ b/pages/src/assets/ts/index.ts @@ -4,6 +4,7 @@ import { renderLaunchers } from './renderers/launchers.js'; import { renderOverview } from './renderers/overview.js'; import { renderPatches } from './renderers/patches.js'; import { renderResources } from './renderers/resources.js'; +import { renderWeb } from './renderers/web.js'; import type { MirrorFileEntry } from './types.js'; import { BASE_URL } from './utils/constants.js'; @@ -32,6 +33,7 @@ async function main() { +
@@ -39,6 +41,7 @@ async function main() {
+
`; contentDiv.innerHTML = tabsHtml; @@ -49,5 +52,6 @@ async function main() { renderPatches(document.getElementById('tab-patch')!, mirrorFileDb), renderResources(document.getElementById('tab-resources')!), renderLaunchers(document.getElementById('tab-launcher')!, mirrorFileDb), + renderWeb(document.getElementById('tab-web')!), ]); } diff --git a/pages/src/assets/ts/renderers/web.ts b/pages/src/assets/ts/renderers/web.ts new file mode 100644 index 0000000..8919f92 --- /dev/null +++ b/pages/src/assets/ts/renderers/web.ts @@ -0,0 +1,157 @@ +import { DateTime } from 'luxon'; +import { fetchJson } from '../api.js'; +import type { StoredData } from '../types.js'; +import { BASE_URL, gameTargets, launcherWebApiLang } from '../utils/constants.js'; + +const apiTypes = ['announcement', 'banner', 'main_bg_image', 'sidebar', 'single_ent']; + +export async function renderWeb(container: HTMLElement) { + for (const target of gameTargets) { + const section = document.createElement('div'); + section.className = 'mb-5'; + section.innerHTML = `

${target.region === 'cn' ? 'China' : 'Global'}, ${target.name}

`; + + const langs = launcherWebApiLang[target.region] || []; + const defaultLang = target.region === 'os' ? 'en-us' : 'zh-cn'; + + // Language Selector + const langSelectGroup = document.createElement('div'); + langSelectGroup.className = 'input-group mb-3'; + langSelectGroup.innerHTML = 'Language'; + + const langSelect = document.createElement('select'); + langSelect.className = 'form-select'; + + langs.forEach((lang) => { + const option = document.createElement('option'); + option.value = lang; + option.textContent = lang; + if (lang === defaultLang) { + option.selected = true; + } + langSelect.appendChild(option); + }); + langSelectGroup.appendChild(langSelect); + + if (langs.length <= 1) { + langSelectGroup.style.display = 'none'; + } + + section.appendChild(langSelectGroup); + + const accordion = document.createElement('div'); + accordion.className = 'accordion'; + accordion.id = `accordion-web-${target.dirName}`; + + const renderApiList = async (lang: string) => { + accordion.innerHTML = '
Loading...
'; + + const results = await Promise.all( + apiTypes.map(async (apiType) => { + const url = `${BASE_URL}/akEndfield/launcher/web/${target.dirName}/${apiType}/${lang}/all.json`; + try { + const data = await fetchJson[]>(url); + if (!data || data.length === 0) return null; + return { apiType, list: [...data].reverse() }; + } catch (e) { + console.warn(`Failed to load ${url}`, e); + return null; + } + }), + ); + + accordion.innerHTML = ''; + const validResults = results.filter((r): r is NonNullable => r !== null); + + if (validResults.length === 0) { + accordion.innerHTML = '
No data found.
'; + return; + } + + validResults.forEach(({ apiType, list }, idx) => { + const itemId = `web-${target.dirName}-${lang}-${apiType}`; + + const item = document.createElement('div'); + item.className = 'accordion-item'; + + // Header + const header = document.createElement('h2'); + header.className = 'accordion-header'; + header.id = `heading-${itemId}`; + header.innerHTML = ` + + `; + item.appendChild(header); + + // Body + const collapse = document.createElement('div'); + collapse.id = `collapse-${itemId}`; + collapse.className = 'accordion-collapse collapse'; + collapse.setAttribute('aria-labelledby', `heading-${itemId}`); + collapse.setAttribute('data-bs-parent', `#${accordion.id}`); + + const body = document.createElement('div'); + body.className = 'accordion-body'; + + // Select for UpdatedAt + const selectGroup = document.createElement('div'); + selectGroup.className = 'input-group mb-3'; + selectGroup.innerHTML = `History`; + + const select = document.createElement('select'); + select.className = 'form-select'; + select.ariaLabel = 'Select version'; + + list.forEach((entry, idx) => { + const dateStr = DateTime.fromISO(entry.updatedAt).toFormat('yyyy/MM/dd HH:mm:ss'); + const option = document.createElement('option'); + option.value = idx.toString(); + option.textContent = `${dateStr}`; + select.appendChild(option); + }); + selectGroup.appendChild(select); + body.appendChild(selectGroup); + + // Content Area + const contentArea = document.createElement('pre'); + contentArea.className = 'p-3 border rounded overflow-auto'; + contentArea.style.maxHeight = '500px'; + contentArea.style.fontSize = '0.875rem'; + + const updateContent = (index: number) => { + const entry = list[index]; + if (entry) { + contentArea.textContent = JSON.stringify(entry.rsp, null, 2); + } + }; + + // Initial render for this item + updateContent(0); + + select.addEventListener('change', (e) => { + const val = parseInt((e.target as HTMLSelectElement).value, 10); + updateContent(val); + }); + + body.appendChild(contentArea); + collapse.appendChild(body); + item.appendChild(collapse); + accordion.appendChild(item); + }); + }; + + langSelect.addEventListener('change', (e) => { + renderApiList((e.target as HTMLSelectElement).value); + }); + + section.appendChild(accordion); + container.appendChild(section); + + // Initial load + if (defaultLang) { + renderApiList(defaultLang); + } + } +}