feat(i18n): add support for all 13 official Star Rail languages
This commit is contained in:
1 parent
08e2440ca5
commit
9d90c2b845
5 files changed
+2108
-223
No files matched your search
+77
-73
@@ -14,30 +14,35 @@
|
||||
<div class="brand">
|
||||
<div class="brand-icon">✦</div>
|
||||
<div>
|
||||
<div class="brand-title">GaC-Srtool</div>
|
||||
<div class="brand-subtitle">Star Rail FreeSR & Server Controller</div>
|
||||
<div class="brand-title" data-i18n="appName">GaC-Srtool</div>
|
||||
<div class="brand-subtitle" data-i18n="appSubtitle">Star Rail FreeSR & Server Controller</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="header-controls">
|
||||
<div class="connection-pill" id="btn-open-settings" title="คลิกเพื่อตั้งค่าการเชื่อมต่อ API">
|
||||
<!-- Language Selector -->
|
||||
<select id="lang-select" class="form-select btn-sm" style="width: auto; padding: 0.35rem 0.65rem; background: var(--bg-secondary); cursor: pointer;" title="Language / 语言 / 言語 / ภาษา">
|
||||
<!-- Injected by i18n.js -->
|
||||
</select>
|
||||
|
||||
<div class="connection-pill" id="btn-open-settings" title="Click to configure API connection">
|
||||
<span class="status-dot" id="status-dot"></span>
|
||||
<span id="connection-status-text">กำลังตรวจสอบ...</span>
|
||||
<span id="connection-status-text" data-i18n="checking">กำลังตรวจสอบ...</span>
|
||||
</div>
|
||||
<button class="btn btn-secondary btn-sm" id="btn-quick-ping" title="ทดสอบการเชื่อมต่อใหม่">
|
||||
🔄 รีเฟรช
|
||||
<button class="btn btn-secondary btn-sm" id="btn-quick-ping" title="Refresh connection">
|
||||
<span data-i18n="refresh">🔄 รีเฟรช</span>
|
||||
</button>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<!-- Navigation Bar -->
|
||||
<nav class="nav-tabs">
|
||||
<button class="tab-btn active" data-tab="tab-dashboard">📊 แดชบอร์ด (Overview)</button>
|
||||
<button class="tab-btn" data-tab="tab-avatars">👥 ตัวละคร (Avatars)</button>
|
||||
<button class="tab-btn" data-tab="tab-exrank">⚡ Ex-Rank (สกิลพิเศษ)</button>
|
||||
<button class="tab-btn" data-tab="tab-teleport">🚀 วาร์ปฉาก (Teleport)</button>
|
||||
<button class="tab-btn" data-tab="tab-json">📝 จัดการไฟล์ JSON</button>
|
||||
<button class="tab-btn" data-tab="tab-settings">⚙️ ตั้งค่า & คู่มือ Host</button>
|
||||
<button class="tab-btn active" data-tab="tab-dashboard" data-i18n="tabDashboard">📊 แดชบอร์ด (Overview)</button>
|
||||
<button class="tab-btn" data-tab="tab-avatars" data-i18n="tabAvatars">👥 ตัวละคร (Avatars)</button>
|
||||
<button class="tab-btn" data-tab="tab-exrank" data-i18n="tabExrank">⚡ Ex-Rank (สกิลพิเศษ)</button>
|
||||
<button class="tab-btn" data-tab="tab-teleport" data-i18n="tabTeleport">🚀 วาร์ปฉาก (Teleport)</button>
|
||||
<button class="tab-btn" data-tab="tab-json" data-i18n="tabJson">📝 จัดการไฟล์ JSON</button>
|
||||
<button class="tab-btn" data-tab="tab-settings" data-i18n="tabSettings">⚙️ ตั้งค่า & คู่มือ Host</button>
|
||||
</nav>
|
||||
|
||||
<!-- Main Container -->
|
||||
@@ -48,15 +53,15 @@
|
||||
<div class="grid-3" style="margin-bottom: 1.5rem;">
|
||||
<div class="card stat-box">
|
||||
<div class="stat-number" id="stat-avatars">0</div>
|
||||
<div class="stat-label">ตัวละครที่ครอบครอง (Avatars)</div>
|
||||
<div class="stat-label" data-i18n="statAvatars">ตัวละครที่ครอบครอง (Avatars)</div>
|
||||
</div>
|
||||
<div class="card stat-box">
|
||||
<div class="stat-number" id="stat-lightcones">0</div>
|
||||
<div class="stat-label">กรวยแสง (Lightcones)</div>
|
||||
<div class="stat-label" data-i18n="statLightcones">กรวยแสง (Lightcones)</div>
|
||||
</div>
|
||||
<div class="card stat-box">
|
||||
<div class="stat-number" id="stat-relics">0</div>
|
||||
<div class="stat-label">รีลิกส์ (Relics)</div>
|
||||
<div class="stat-label" data-i18n="statRelics">รีลิกส์ (Relics)</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -64,12 +69,12 @@
|
||||
<!-- Server & Map Card -->
|
||||
<div class="card">
|
||||
<div class="card-title">
|
||||
<span>📍 สถานะเซิร์ฟเวอร์ & ตำแหน่งปัจจุบัน</span>
|
||||
<span data-i18n="serverStatusTitle">📍 สถานะเซิร์ฟเวอร์ & ตำแหน่งปัจจุบัน</span>
|
||||
<span class="btn-sm btn-secondary" id="badge-version">API Live</span>
|
||||
</div>
|
||||
<div style="display: flex; flex-direction: column; gap: 0.75rem;">
|
||||
<div>
|
||||
<span class="form-label">API Gateway Endpoint</span>
|
||||
<span class="form-label" data-i18n="lblApiGatewayUrl">API Gateway Endpoint</span>
|
||||
<code id="lbl-api-url" style="color: var(--accent-cyan); font-size: 0.9rem;">-</code>
|
||||
</div>
|
||||
<div style="display: flex; gap: 1rem;">
|
||||
@@ -83,7 +88,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<span class="form-label">พิกัดตัวละคร (X, Y, Z)</span>
|
||||
<span class="form-label" data-i18n="coords">พิกัดตัวละคร (X, Y, Z)</span>
|
||||
<span id="lbl-coordinates" style="color: var(--text-muted); font-size: 0.85rem;">-</span>
|
||||
</div>
|
||||
</div>
|
||||
@@ -91,17 +96,17 @@
|
||||
|
||||
<!-- Quick Actions Card -->
|
||||
<div class="card">
|
||||
<div class="card-title">⚡ ดำเนินการด่วน (Quick Actions)</div>
|
||||
<p class="card-subtitle">สั่งการส่งไปยัง REST API Gateway ทันที</p>
|
||||
<div class="card-title" data-i18n="quickActionsTitle">⚡ ดำเนินการด่วน (Quick Actions)</div>
|
||||
<p class="card-subtitle" data-i18n="quickActionsSubtitle">สั่งการส่งไปยัง REST API Gateway ทันที</p>
|
||||
<div style="display: flex; flex-direction: column; gap: 0.75rem;">
|
||||
<button class="btn btn-gold" id="btn-quick-max-all">
|
||||
⭐ ปรับเลเวล 80 & ปลด E6 ตัวละครทั้งหมด (Max All)
|
||||
<span data-i18n="btnMaxAll">⭐ ปรับเลเวล 80 & ปลด E6 ตัวละครทั้งหมด (Max All)</span>
|
||||
</button>
|
||||
<button class="btn btn-primary" id="btn-quick-warp-express">
|
||||
🚂 วาร์ปกลับรถไฟ Astral Express ทันที
|
||||
<span data-i18n="btnWarpExpress">🚂 วาร์ปกลับรถไฟ Astral Express ทันที</span>
|
||||
</button>
|
||||
<button class="btn btn-secondary" id="btn-quick-sync-persistent">
|
||||
💾 ซิงค์ข้อมูล Persistent ล่าสุด
|
||||
<span data-i18n="btnSyncPersistent">💾 ซิงค์ข้อมูล Persistent ล่าสุด</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -109,7 +114,7 @@
|
||||
|
||||
<!-- Current Lineup -->
|
||||
<div class="card" style="margin-top: 1.5rem;">
|
||||
<div class="card-title">🎮 ทีมปัจจุบัน (Current Lineup)</div>
|
||||
<div class="card-title" data-i18n="currentLineupTitle">🎮 ทีมปัจจุบัน (Current Lineup)</div>
|
||||
<div id="lineup-container" class="grid-4" style="margin-top: 0.5rem;">
|
||||
<div class="card" style="text-align: center; color: var(--text-muted);">กำลังโหลดข้อมูลทีม...</div>
|
||||
</div>
|
||||
@@ -120,16 +125,16 @@
|
||||
<section id="tab-avatars" class="tab-content">
|
||||
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 1.25rem; flex-wrap: wrap; gap: 1rem;">
|
||||
<div style="display: flex; gap: 0.75rem; flex: 1; max-width: 480px;">
|
||||
<input type="text" id="avatar-search" class="form-input" placeholder="🔍 ค้นหาชื่อหรือ ID ตัวละคร...">
|
||||
<input type="text" id="avatar-search" class="form-input" data-i18n-placeholder="searchPlaceholder" placeholder="🔍 ค้นหาชื่อหรือ ID ตัวละคร...">
|
||||
<select id="avatar-filter-rarity" class="form-select" style="max-width: 140px;">
|
||||
<option value="all">ทุกระดับดาว</option>
|
||||
<option value="5">5 ดาว (SSR)</option>
|
||||
<option value="4">4 ดาว (SR)</option>
|
||||
<option value="all" data-i18n="filterAllRarity">ทุกระดับดาว</option>
|
||||
<option value="5" data-i18n="filter5Star">5 ดาว (SSR)</option>
|
||||
<option value="4" data-i18n="filter4Star">4 ดาว (SR)</option>
|
||||
</select>
|
||||
</div>
|
||||
<div style="display: flex; gap: 0.5rem;">
|
||||
<button class="btn btn-gold" id="btn-max-all-avatars">⭐ ปรับ Max E6 ทุกตัว</button>
|
||||
<button class="btn btn-secondary" id="btn-reload-avatars">🔄 รีโหลด</button>
|
||||
<button class="btn btn-gold" id="btn-max-all-avatars" data-i18n="btnMaxAll">⭐ ปรับ Max E6 ทุกตัว</button>
|
||||
<button class="btn btn-secondary" id="btn-reload-avatars" data-i18n="btnReload">🔄 รีโหลด</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -144,13 +149,13 @@
|
||||
<section id="tab-exrank" class="tab-content">
|
||||
<div class="card" style="margin-bottom: 1.5rem;">
|
||||
<div class="card-title">
|
||||
<span>⚡ ระบบปลดล็อค Ex-Rank Skill</span>
|
||||
<span data-i18n="exrankTitle">⚡ ระบบปลดล็อค Ex-Rank Skill</span>
|
||||
<div style="display: flex; gap: 0.5rem;">
|
||||
<button class="btn btn-success btn-sm" id="btn-exrank-enable-all">เปิด Ex-Rank ทั้งหมด</button>
|
||||
<button class="btn btn-secondary btn-sm" id="btn-exrank-disable-all">ปิด Ex-Rank ทั้งหมด</button>
|
||||
<button class="btn btn-success btn-sm" id="btn-exrank-enable-all" data-i18n="btnEnableAll">เปิด Ex-Rank ทั้งหมด</button>
|
||||
<button class="btn btn-secondary btn-sm" id="btn-exrank-disable-all" data-i18n="btnDisableAll">ปิด Ex-Rank ทั้งหมด</button>
|
||||
</div>
|
||||
</div>
|
||||
<p class="card-subtitle">
|
||||
<p class="card-subtitle" data-i18n="exrankSubtitle">
|
||||
เปิดใช้งานพรสวรรค์และกลไกพิเศษ Ex-Rank สำหรับตัวละครเฉพาะใน FreeSR (เช่น Jing Yuan โดน CC ไม่หยุดชะงัก, Dan Heng IL, Acheron)
|
||||
</p>
|
||||
</div>
|
||||
@@ -167,8 +172,8 @@
|
||||
<div class="grid-2">
|
||||
<!-- Presets -->
|
||||
<div class="card">
|
||||
<div class="card-title">📍 จุดวาร์ปปลอดภัยยอดนิยม (Safe Presets)</div>
|
||||
<p class="card-subtitle">คลิกจุดวาร์ปเพื่อย้ายฉากของผู้เล่นในไฟล์เซฟได้ทันที</p>
|
||||
<div class="card-title" data-i18n="presetsTitle">📍 จุดวาร์ปปลอดภัยยอดนิยม (Safe Presets)</div>
|
||||
<p class="card-subtitle" data-i18n="presetsSubtitle">คลิกจุดวาร์ปเพื่อย้ายฉากของผู้เล่นในไฟล์เซฟได้ทันที</p>
|
||||
<div id="teleport-presets-list" style="display: flex; flex-direction: column; gap: 0.6rem;">
|
||||
<!-- Rendered by JS -->
|
||||
</div>
|
||||
@@ -176,23 +181,23 @@
|
||||
|
||||
<!-- Custom Coordinate Warp -->
|
||||
<div class="card">
|
||||
<div class="card-title">🎯 กำหนดพิกัดวาร์ปเอง (Custom Teleport)</div>
|
||||
<p class="card-subtitle">ใส่ PlaneID, FloorID และ EntryID ตามต้องการ</p>
|
||||
<div class="card-title" data-i18n="customTeleportTitle">🎯 กำหนดพิกัดวาร์ปเอง (Custom Teleport)</div>
|
||||
<p class="card-subtitle" data-i18n="customTeleportSubtitle">ใส่ PlaneID, FloorID และ EntryID ตามต้องการ</p>
|
||||
|
||||
<form id="form-custom-teleport">
|
||||
<div class="grid-2" style="gap: 0.75rem;">
|
||||
<div class="form-group">
|
||||
<label class="form-label">Plane ID</label>
|
||||
<input type="number" id="tp-plane" class="form-input" required placeholder="เช่น 20001">
|
||||
<input type="number" id="tp-plane" class="form-input" required placeholder="20001">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="form-label">Floor ID</label>
|
||||
<input type="number" id="tp-floor" class="form-input" required placeholder="เช่น 20001001">
|
||||
<input type="number" id="tp-floor" class="form-input" required placeholder="20001001">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="form-label">Entry ID</label>
|
||||
<input type="number" id="tp-entry" class="form-input" required placeholder="เช่น 2000101">
|
||||
<input type="number" id="tp-entry" class="form-input" required placeholder="2000101">
|
||||
</div>
|
||||
|
||||
<div class="grid-3" style="gap: 0.75rem;">
|
||||
@@ -210,7 +215,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button type="submit" class="btn btn-primary" style="width: 100%; margin-top: 0.5rem;">
|
||||
<button type="submit" class="btn btn-primary" style="width: 100%; margin-top: 0.5rem;" data-i18n="btnExecuteWarp">
|
||||
🚀 ยืนยันการวาร์ป (Execute Teleport)
|
||||
</button>
|
||||
</form>
|
||||
@@ -223,24 +228,24 @@
|
||||
<div class="card">
|
||||
<div class="card-title" style="flex-wrap: wrap; gap: 0.75rem;">
|
||||
<div style="display: flex; gap: 0.5rem;">
|
||||
<button class="btn btn-sm btn-primary active" id="btn-select-freesr">📄 freesr-data.json</button>
|
||||
<button class="btn btn-sm btn-secondary" id="btn-select-persistent">💾 persistent (Save)</button>
|
||||
<button class="btn btn-sm btn-primary active" id="btn-select-freesr" data-i18n="btnFreesr">📄 freesr-data.json</button>
|
||||
<button class="btn btn-sm btn-secondary" id="btn-select-persistent" data-i18n="btnPersistent">💾 persistent (Save)</button>
|
||||
</div>
|
||||
<div style="display: flex; gap: 0.5rem;">
|
||||
<button class="btn btn-sm btn-secondary" id="btn-json-beautify">✨ จัดรูปแบบ JSON</button>
|
||||
<button class="btn btn-sm btn-secondary" id="btn-json-download">📥 ดาวน์โหลด Backup</button>
|
||||
<button class="btn btn-sm btn-secondary" id="btn-json-beautify" data-i18n="btnBeautify">✨ จัดรูปแบบ JSON</button>
|
||||
<button class="btn btn-sm btn-secondary" id="btn-json-download" data-i18n="btnDownload">📥 ดาวน์โหลด Backup</button>
|
||||
<label class="btn btn-sm btn-secondary" style="cursor: pointer; margin: 0;">
|
||||
📤 อัปโหลดไฟล์ <input type="file" id="json-file-input" accept=".json,text/plain" style="display: none;">
|
||||
<span data-i18n="btnUpload">📤 อัปโหลดไฟล์</span> <input type="file" id="json-file-input" accept=".json,text/plain" style="display: none;">
|
||||
</label>
|
||||
<button class="btn btn-sm btn-success" id="btn-json-save">💾 บันทึกไปยังเซิร์ฟเวอร์</button>
|
||||
<button class="btn btn-sm btn-success" id="btn-json-save" data-i18n="btnSaveServer">💾 บันทึกไปยังเซิร์ฟเวอร์</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="json-editor-wrapper">
|
||||
<textarea id="json-editor" class="json-textarea" spellcheck="false" placeholder="กำลังโหลดข้อมูล JSON..."></textarea>
|
||||
<textarea id="json-editor" class="json-textarea" spellcheck="false" placeholder="..."></textarea>
|
||||
<div style="display: flex; justify-content: space-between; font-size: 0.8rem; color: var(--text-muted);">
|
||||
<span id="json-status-info">พร้อมใช้งาน</span>
|
||||
<span>Tip: สามารถแก้ไขค่าดิบแล้วกด 'บันทึกไปยังเซิร์ฟเวอร์' ได้ทันที</span>
|
||||
<span id="json-status-info" data-i18n="jsonStatusReady">พร้อมใช้งาน</span>
|
||||
<span data-i18n="jsonTip">Tip: สามารถแก้ไขค่าดิบแล้วกด 'บันทึกไปยังเซิร์ฟเวอร์' ได้ทันที</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -251,51 +256,50 @@
|
||||
<div class="grid-2">
|
||||
<!-- Endpoint config -->
|
||||
<div class="card">
|
||||
<div class="card-title">⚙️ ตั้งค่าการเชื่อมต่อ API Gateway</div>
|
||||
<p class="card-subtitle">ปรับเปลี่ยนพอร์ตหรือ IP ได้ตามไฟล์ server.json ของคุณ</p>
|
||||
<div class="card-title" data-i18n="apiSettingsTitle">⚙️ ตั้งค่าการเชื่อมต่อ API Gateway</div>
|
||||
<p class="card-subtitle" data-i18n="apiSettingsSubtitle">ปรับเปลี่ยนพอร์ตหรือ IP ได้ตามไฟล์ server.json ของคุณ</p>
|
||||
|
||||
<form id="form-settings">
|
||||
<div class="form-group">
|
||||
<label class="form-label">REST API Gateway URL</label>
|
||||
<label class="form-label" data-i18n="lblApiGatewayUrl">REST API Gateway URL</label>
|
||||
<input type="text" id="setting-api-url" class="form-input" placeholder="http://localhost:21000">
|
||||
<small style="color: var(--text-muted); display: block; margin-top: 0.35rem;">
|
||||
* ค่าเริ่มต้นของ GaC-hkrpg-go คือพอร์ต 21000 (SDK server)
|
||||
* Port 21000 by default (GaC-hkrpg-go SDK Server)
|
||||
</small>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="form-label">ความถี่ในการตรวจสอบสถานะ (วินาที)</label>
|
||||
<label class="form-label" data-i18n="lblPingInterval">ความถี่ในการตรวจสอบสถานะ (วินาที)</label>
|
||||
<input type="number" id="setting-ping-interval" class="form-input" min="3" max="60" value="10">
|
||||
</div>
|
||||
<div style="display: flex; gap: 0.75rem;">
|
||||
<button type="submit" class="btn btn-success" style="flex: 1;">💾 บันทึกการตั้งค่า</button>
|
||||
<button type="button" class="btn btn-secondary" id="btn-reset-settings">คืนค่าเริ่มต้น</button>
|
||||
<button type="submit" class="btn btn-success" style="flex: 1;" data-i18n="btnSaveSettings">💾 บันทึกการตั้งค่า</button>
|
||||
<button type="button" class="btn btn-secondary" id="btn-reset-settings" data-i18n="btnResetDefault">คืนค่าเริ่มต้น</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<!-- GitHub Pages Hosting Guide -->
|
||||
<div class="card">
|
||||
<div class="card-title">🌐 วิธีนำขึ้นโฮสต์ GitHub Pages (ฟรี 100%)</div>
|
||||
<p class="card-subtitle">สามารถเปิดใช้งานเว็บนี้บนอินเทอร์เน็ตได้โดยไม่ต้องเสียค่าโฮสต์ใดๆ</p>
|
||||
<div class="card-title" data-i18n="hostGuideTitle">🌐 วิธีนำขึ้นโฮสต์ GitHub Pages (ฟรี 100%)</div>
|
||||
<p class="card-subtitle" data-i18n="hostGuideSubtitle">สามารถเปิดใช้งานเว็บนี้บนอินเทอร์เน็ตได้โดยไม่ต้องเสียค่าโฮสต์ใดๆ</p>
|
||||
|
||||
<ol style="margin-left: 1.25rem; font-size: 0.875rem; color: var(--text-muted); display: flex; flex-direction: column; gap: 0.65rem;">
|
||||
<li>
|
||||
<strong style="color: var(--text-main);">1. สร้าง Repository บน GitHub:</strong><br>
|
||||
สร้าง GitHub Repo ใหม่ (Public หรือ Private ก็ได้) เช่นชื่อ <code>GaC-srtool</code>
|
||||
<strong style="color: var(--text-main);">1. Create GitHub Repository:</strong><br>
|
||||
Create new repo e.g. <code>GaC-srtool</code>
|
||||
</li>
|
||||
<li>
|
||||
<strong style="color: var(--text-main);">2. Push โฟลเดอร์นี้ขึ้น GitHub:</strong><br>
|
||||
<strong style="color: var(--text-main);">2. Push to GitHub:</strong><br>
|
||||
<code>git remote add origin https://github.com/<user>/GaC-srtool.git</code><br>
|
||||
<code>git add . && git commit -m "Init GaC-srtool" && git push -u origin main</code>
|
||||
<code>git add . && git commit -m "Init" && git push -u origin main</code>
|
||||
</li>
|
||||
<li>
|
||||
<strong style="color: var(--text-main);">3. เปิดใช้งาน GitHub Pages:</strong><br>
|
||||
เข้าไปที่ Repo บน GitHub > <strong>Settings</strong> > <strong>Pages</strong><br>
|
||||
ใต้หัวข้อ <em>Build and deployment</em> เลือก Source เป็น <strong>Deploy from a branch</strong> > เลือก Branch: <strong>main</strong>, Folder: <strong>/ (root)</strong> > กด <strong>Save</strong>
|
||||
<strong style="color: var(--text-main);">3. Enable GitHub Pages:</strong><br>
|
||||
Go to Repo > <strong>Settings</strong> > <strong>Pages</strong> > Source: <strong>Deploy from a branch</strong> > Branch: <strong>main</strong> / (root) > Click <strong>Save</strong>
|
||||
</li>
|
||||
<li>
|
||||
<strong style="color: var(--text-main);">4. ใช้งานได้ทันที:</strong><br>
|
||||
เว็บจะออนไลน์ที่ <code>https://<user>.github.io/GaC-srtool/</code> ไม่เสียค่าใช้จ่ายตลอดชีพ!
|
||||
<strong style="color: var(--text-main);">4. Done:</strong><br>
|
||||
Your dashboard will be online at <code>https://<user>.github.io/GaC-srtool/</code>!
|
||||
</li>
|
||||
</ol>
|
||||
</div>
|
||||
@@ -308,17 +312,17 @@
|
||||
<div class="modal-overlay" id="modal-settings">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h3 style="font-weight: 700;">⚙️ ตั้งค่าการเชื่อมต่อ API Server</h3>
|
||||
<h3 style="font-weight: 700;" data-i18n="apiSettingsTitle">⚙️ ตั้งค่าการเชื่อมต่อ API Server</h3>
|
||||
<button class="btn btn-sm btn-secondary" id="btn-close-modal">✕</button>
|
||||
</div>
|
||||
<div>
|
||||
<div class="form-group">
|
||||
<label class="form-label">Server REST API URL</label>
|
||||
<label class="form-label" data-i18n="lblApiGatewayUrl">Server REST API URL</label>
|
||||
<input type="text" id="modal-api-url" class="form-input">
|
||||
</div>
|
||||
<div style="display: flex; justify-content: flex-end; gap: 0.5rem; margin-top: 1rem;">
|
||||
<button class="btn btn-secondary" id="btn-modal-cancel">ยกเลิก</button>
|
||||
<button class="btn btn-primary" id="btn-modal-save">บันทึก & ทดสอบ</button>
|
||||
<button class="btn btn-secondary" id="btn-modal-cancel">Cancel</button>
|
||||
<button class="btn btn-primary" id="btn-modal-save" data-i18n="btnSaveSettings">บันทึก & ทดสอบ</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { AVATAR_METADATA, getAvatarInfo } from './avatars-data.js';
|
||||
import { PRESET_TELEPORTS } from './teleports-data.js';
|
||||
import { PRESET_TELEPORTS, getTeleportName } from './teleports-data.js';
|
||||
import { SUPPORTED_LANGUAGES, getCurrentLanguage, setLanguage, t } from './i18n.js';
|
||||
|
||||
// Application State
|
||||
const state = {
|
||||
@@ -14,6 +15,7 @@ const state = {
|
||||
|
||||
// UI Elements
|
||||
const el = {
|
||||
langSelect: document.getElementById('lang-select'),
|
||||
statusDot: document.getElementById('status-dot'),
|
||||
connectionStatusText: document.getElementById('connection-status-text'),
|
||||
btnQuickPing: document.getElementById('btn-quick-ping'),
|
||||
@@ -139,15 +141,59 @@ function setConnectionStatus(connected, extraText = '') {
|
||||
state.isConnected = connected;
|
||||
if (connected) {
|
||||
el.statusDot.classList.add('connected');
|
||||
el.connectionStatusText.textContent = extraText || 'เชื่อมต่อแล้ว (Online)';
|
||||
el.connectionStatusText.textContent = extraText || t('online');
|
||||
el.connectionStatusText.style.color = 'var(--accent-green)';
|
||||
} else {
|
||||
el.statusDot.classList.remove('connected');
|
||||
el.connectionStatusText.textContent = extraText || 'ออฟไลน์ (Offline)';
|
||||
el.connectionStatusText.textContent = extraText || t('offline');
|
||||
el.connectionStatusText.style.color = 'var(--accent-red)';
|
||||
}
|
||||
}
|
||||
|
||||
// Apply multi-language translations across whole UI
|
||||
function applyTranslations() {
|
||||
document.querySelectorAll('[data-i18n]').forEach(elem => {
|
||||
const key = elem.getAttribute('data-i18n');
|
||||
elem.textContent = t(key);
|
||||
});
|
||||
|
||||
document.querySelectorAll('[data-i18n-placeholder]').forEach(elem => {
|
||||
const key = elem.getAttribute('data-i18n-placeholder');
|
||||
elem.placeholder = t(key);
|
||||
});
|
||||
|
||||
// Re-render localized UI parts
|
||||
if (state.statusData) {
|
||||
renderLineup(state.statusData.lineups);
|
||||
renderExRanks(state.statusData.ex_ranks || []);
|
||||
}
|
||||
renderTeleportPresets();
|
||||
if (state.avatarsList.length > 0) {
|
||||
renderAvatarsGrid();
|
||||
}
|
||||
}
|
||||
|
||||
// Language selector initialization
|
||||
function setupLanguageSelector() {
|
||||
el.langSelect.innerHTML = '';
|
||||
SUPPORTED_LANGUAGES.forEach(lang => {
|
||||
const opt = document.createElement('option');
|
||||
opt.value = lang.code;
|
||||
opt.textContent = `${lang.flag} ${lang.name}`;
|
||||
if (lang.code === getCurrentLanguage()) {
|
||||
opt.selected = true;
|
||||
}
|
||||
el.langSelect.appendChild(opt);
|
||||
});
|
||||
|
||||
el.langSelect.addEventListener('change', (e) => {
|
||||
const newLang = e.target.value;
|
||||
setLanguage(newLang);
|
||||
applyTranslations();
|
||||
showToast(`Language switched to ${SUPPORTED_LANGUAGES.find(l => l.code === newLang)?.name || newLang}`, 'info');
|
||||
});
|
||||
}
|
||||
|
||||
// Refresh status from /api/status
|
||||
async function refreshStatus() {
|
||||
try {
|
||||
@@ -173,14 +219,14 @@ async function refreshStatus() {
|
||||
renderLineup(data.lineups);
|
||||
renderExRanks(data.ex_ranks || []);
|
||||
} catch (err) {
|
||||
setConnectionStatus(false, 'เชื่อมต่อไม่สำเร็จ');
|
||||
setConnectionStatus(false, t('connectFailed'));
|
||||
}
|
||||
}
|
||||
|
||||
// Render current lineup cards
|
||||
function renderLineup(lineups) {
|
||||
if (!lineups || Object.keys(lineups).length === 0) {
|
||||
el.lineupContainer.innerHTML = '<div style="color: var(--text-muted); grid-column: 1/-1;">ไม่มีข้อมูลทีม</div>';
|
||||
el.lineupContainer.innerHTML = `<div style="color: var(--text-muted); grid-column: 1/-1;">${t('slotEmpty')}</div>`;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -193,13 +239,13 @@ function renderLineup(lineups) {
|
||||
|
||||
if (avatarId === 0) {
|
||||
card.innerHTML = `
|
||||
<div style="font-size: 0.75rem; color: var(--text-muted);">ตำแหน่งที่ ${slot + 1}</div>
|
||||
<div style="font-weight: 600; color: var(--text-muted); margin-top: 0.25rem;">(ว่าง)</div>
|
||||
<div style="font-size: 0.75rem; color: var(--text-muted);">${t('slot')} ${slot + 1}</div>
|
||||
<div style="font-weight: 600; color: var(--text-muted); margin-top: 0.25rem;">${t('slotEmpty')}</div>
|
||||
`;
|
||||
} else {
|
||||
const info = getAvatarInfo(avatarId);
|
||||
card.innerHTML = `
|
||||
<div style="font-size: 0.75rem; color: var(--accent-cyan);">ตำแหน่งที่ ${slot + 1}</div>
|
||||
<div style="font-size: 0.75rem; color: var(--accent-cyan);">${t('slot')} ${slot + 1}</div>
|
||||
<div style="font-weight: 700; margin-top: 0.25rem;">${info.name}</div>
|
||||
<div style="font-size: 0.75rem; color: var(--text-muted);">${info.element} • ${info.path}</div>
|
||||
`;
|
||||
@@ -211,12 +257,12 @@ function renderLineup(lineups) {
|
||||
// Load and Render Avatars
|
||||
async function loadAvatars() {
|
||||
try {
|
||||
el.avatarsGrid.innerHTML = '<div style="grid-column: 1/-1; text-align: center; color: var(--text-muted);">กำลังโหลด...</div>';
|
||||
el.avatarsGrid.innerHTML = `<div style="grid-column: 1/-1; text-align: center; color: var(--text-muted);">${t('checking')}</div>`;
|
||||
const res = await apiCall('/api/freesr/avatars');
|
||||
state.avatarsList = res.avatars || [];
|
||||
renderAvatarsGrid();
|
||||
} catch (err) {
|
||||
el.avatarsGrid.innerHTML = `<div style="grid-column: 1/-1; text-align: center; color: var(--accent-red);">ดึงข้อมูลตัวละครไม่สำเร็จ: ${err.message}</div>`;
|
||||
el.avatarsGrid.innerHTML = `<div style="grid-column: 1/-1; text-align: center; color: var(--accent-red);">${err.message}</div>`;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -232,7 +278,7 @@ function renderAvatarsGrid() {
|
||||
});
|
||||
|
||||
if (filtered.length === 0) {
|
||||
el.avatarsGrid.innerHTML = '<div style="grid-column: 1/-1; text-align: center; color: var(--text-muted); padding: 2rem;">ไม่พบตัวละครที่ตรงกับเงื่อนไข</div>';
|
||||
el.avatarsGrid.innerHTML = '<div style="grid-column: 1/-1; text-align: center; color: var(--text-muted); padding: 2rem;">No matching avatars</div>';
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -267,7 +313,7 @@ function renderAvatarsGrid() {
|
||||
</div>
|
||||
|
||||
<div class="eidolon-selector">
|
||||
<span style="font-size: 0.75rem; color: var(--text-muted); font-weight: 600;">EIDOLON (E):</span>
|
||||
<span style="font-size: 0.75rem; color: var(--text-muted); font-weight: 600;">${t('eidolonLabel')}</span>
|
||||
<div class="eidolon-buttons">
|
||||
${pipsHtml}
|
||||
</div>
|
||||
@@ -292,7 +338,7 @@ function renderAvatarsGrid() {
|
||||
async function setAvatarRank(avatarId, rank) {
|
||||
try {
|
||||
await apiCall('/api/avatar/rank', 'POST', { avatar_id: avatarId, rank });
|
||||
showToast(`ปรับตัวละคร ${avatarId} เป็น E${rank} สำเร็จ`, 'success');
|
||||
showToast(t('avatarRankSuccess', { id: avatarId, rank }), 'success');
|
||||
|
||||
// Update local state and re-render
|
||||
const target = state.avatarsList.find(a => a.avatar_id === avatarId);
|
||||
@@ -301,27 +347,27 @@ async function setAvatarRank(avatarId, rank) {
|
||||
renderAvatarsGrid();
|
||||
}
|
||||
} catch (err) {
|
||||
showToast(`เกิดข้อผิดพลาด: ${err.message}`, 'error');
|
||||
showToast(`Error: ${err.message}`, 'error');
|
||||
}
|
||||
}
|
||||
|
||||
// Max all avatars API
|
||||
async function maxAllAvatars() {
|
||||
if (!confirm('ยืนยันปรับตัวละครทั้งหมดให้เป็นเลเวล 80 และปลด E6 หรือไม่?')) return;
|
||||
if (!confirm(t('confirmMaxAll'))) return;
|
||||
try {
|
||||
await apiCall('/api/avatar/max_all', 'POST', {});
|
||||
showToast('ปรับ Max ทุกตัวละครสำเร็จแล้ว!', 'success');
|
||||
showToast(t('maxAllSuccess'), 'success');
|
||||
loadAvatars();
|
||||
refreshStatus();
|
||||
} catch (err) {
|
||||
showToast(`เกิดข้อผิดพลาด: ${err.message}`, 'error');
|
||||
showToast(`Error: ${err.message}`, 'error');
|
||||
}
|
||||
}
|
||||
|
||||
// Render Ex-Ranks
|
||||
function renderExRanks(exList) {
|
||||
if (!exList || exList.length === 0) {
|
||||
el.exrankList.innerHTML = '<div style="color: var(--text-muted); text-align: center; padding: 1rem;">ไม่มีข้อมูลตัวละคร Ex-Rank</div>';
|
||||
el.exrankList.innerHTML = '<div style="color: var(--text-muted); text-align: center; padding: 1rem;">No Ex-Rank Avatars</div>';
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -329,10 +375,11 @@ function renderExRanks(exList) {
|
||||
exList.forEach(item => {
|
||||
const card = document.createElement('div');
|
||||
card.className = 'ex-switch-card';
|
||||
const localizedMeta = getAvatarInfo(item.avatar_id);
|
||||
|
||||
card.innerHTML = `
|
||||
<div>
|
||||
<div style="font-weight: 700; font-size: 1rem;">${item.name}</div>
|
||||
<div style="font-weight: 700; font-size: 1rem;">${localizedMeta.name}</div>
|
||||
<div style="font-size: 0.8rem; color: var(--text-muted);">
|
||||
Avatar ID: ${item.avatar_id} • Ex-Rank Skill ID: ${item.ex_rank_id}
|
||||
</div>
|
||||
@@ -348,10 +395,11 @@ function renderExRanks(exList) {
|
||||
const avatarId = item.avatar_id;
|
||||
try {
|
||||
await apiCall('/api/exrank/toggle', 'POST', { avatar_id: avatarId, unlocked });
|
||||
showToast(`${item.name}: ${unlocked ? 'เปิดใช้งาน' : 'ปิดใช้งาน'} Ex-Rank สำเร็จ`, 'success');
|
||||
const statusText = unlocked ? t('enabled') : t('disabled');
|
||||
showToast(t('exrankToggleSuccess', { name: localizedMeta.name, status: statusText }), 'success');
|
||||
} catch (err) {
|
||||
e.target.checked = !unlocked;
|
||||
showToast(`เกิดข้อผิดพลาด: ${err.message}`, 'error');
|
||||
showToast(`Error: ${err.message}`, 'error');
|
||||
}
|
||||
});
|
||||
|
||||
@@ -370,15 +418,17 @@ function renderTeleportPresets() {
|
||||
item.style.justifyContent = 'space-between';
|
||||
item.style.alignItems = 'center';
|
||||
|
||||
const displayName = getTeleportName(preset);
|
||||
|
||||
item.innerHTML = `
|
||||
<div>
|
||||
<div style="font-weight: 700; font-size: 0.95rem;">${preset.name}</div>
|
||||
<div style="font-weight: 700; font-size: 0.95rem;">${displayName}</div>
|
||||
<div style="font-size: 0.75rem; color: var(--text-muted); margin-top: 0.2rem;">
|
||||
Plane: ${preset.plane_id} • Floor: ${preset.floor_id} • Entry: ${preset.entry_id}
|
||||
</div>
|
||||
</div>
|
||||
<button class="btn btn-sm btn-primary btn-warp" style="white-space: nowrap;">
|
||||
🚀 วาร์ป
|
||||
${t('warpBtn')}
|
||||
</button>
|
||||
`;
|
||||
|
||||
@@ -390,7 +440,7 @@ function renderTeleportPresets() {
|
||||
x: preset.x,
|
||||
y: preset.y,
|
||||
z: preset.z
|
||||
}, preset.name);
|
||||
}, displayName);
|
||||
});
|
||||
|
||||
el.teleportPresetsList.appendChild(item);
|
||||
@@ -401,10 +451,10 @@ function renderTeleportPresets() {
|
||||
async function executeTeleport(payload, label = '') {
|
||||
try {
|
||||
await apiCall('/api/teleport', 'POST', payload);
|
||||
showToast(`วาร์ปไปยัง ${label || 'จุดที่ระบุ'} สำเร็จ (บันทึกลง Persistent)`, 'success');
|
||||
showToast(t('warpSuccess', { label: label || `Plane ${payload.plane_id}` }), 'success');
|
||||
refreshStatus();
|
||||
} catch (err) {
|
||||
showToast(`วาร์ปไม่สำเร็จ: ${err.message}`, 'error');
|
||||
showToast(t('warpFailed', { err: err.message }), 'error');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -414,22 +464,22 @@ async function loadJsonData(mode) {
|
||||
if (mode === 'freesr') {
|
||||
el.btnSelectFreesr.className = 'btn btn-sm btn-primary active';
|
||||
el.btnSelectPersistent.className = 'btn btn-sm btn-secondary';
|
||||
el.jsonStatusInfo.textContent = 'กำลังเปิด: freesr-data.json';
|
||||
el.jsonStatusInfo.textContent = t('jsonStatusOpening', { name: 'freesr-data.json' });
|
||||
try {
|
||||
const res = await apiCall('/api/freesr');
|
||||
el.jsonEditor.value = JSON.stringify(res.data, null, 2);
|
||||
} catch (err) {
|
||||
showToast(`โหลด freesr-data ไม่สำเร็จ: ${err.message}`, 'error');
|
||||
showToast(`Load failed: ${err.message}`, 'error');
|
||||
}
|
||||
} else {
|
||||
el.btnSelectPersistent.className = 'btn btn-sm btn-primary active';
|
||||
el.btnSelectFreesr.className = 'btn btn-sm btn-secondary';
|
||||
el.jsonStatusInfo.textContent = 'กำลังเปิด: persistent';
|
||||
el.jsonStatusInfo.textContent = t('jsonStatusOpening', { name: 'persistent' });
|
||||
try {
|
||||
const res = await apiCall('/api/persistent');
|
||||
el.jsonEditor.value = JSON.stringify(res.persistent, null, 2);
|
||||
} catch (err) {
|
||||
showToast(`โหลด persistent ไม่สำเร็จ: ${err.message}`, 'error');
|
||||
showToast(`Load failed: ${err.message}`, 'error');
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -438,7 +488,7 @@ async function loadJsonData(mode) {
|
||||
async function saveJsonData() {
|
||||
const text = el.jsonEditor.value.trim();
|
||||
if (!text) {
|
||||
showToast('ไม่มีข้อมูล JSON ให้บันทึก', 'error');
|
||||
showToast('No JSON data to save', 'error');
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -446,17 +496,17 @@ async function saveJsonData() {
|
||||
try {
|
||||
parsed = JSON.parse(text);
|
||||
} catch (err) {
|
||||
showToast(`JSON ไม่ถูกต้อง: ${err.message}`, 'error');
|
||||
showToast(`${t('jsonInvalid')}: ${err.message}`, 'error');
|
||||
return;
|
||||
}
|
||||
|
||||
const endpoint = state.currentJsonMode === 'freesr' ? '/api/freesr' : '/api/persistent';
|
||||
try {
|
||||
await apiCall(endpoint, 'POST', parsed);
|
||||
showToast(`บันทึกไฟล์ ${state.currentJsonMode} เรียบร้อยแล้ว`, 'success');
|
||||
showToast(t('jsonSaveSuccess', { name: state.currentJsonMode }), 'success');
|
||||
refreshStatus();
|
||||
} catch (err) {
|
||||
showToast(`บันทึกไม่สำเร็จ: ${err.message}`, 'error');
|
||||
showToast(`Save failed: ${err.message}`, 'error');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -465,7 +515,7 @@ function setupTabs() {
|
||||
const tabs = document.querySelectorAll('.tab-btn');
|
||||
tabs.forEach(tab => {
|
||||
tab.addEventListener('click', () => {
|
||||
tabs.forEach(t => t.classList.remove('active'));
|
||||
tabs.forEach(tBtn => tBtn.classList.remove('active'));
|
||||
document.querySelectorAll('.tab-content').forEach(c => c.classList.remove('active'));
|
||||
|
||||
tab.classList.add('active');
|
||||
@@ -490,7 +540,7 @@ function setupTabs() {
|
||||
function setupEvents() {
|
||||
// Quick Ping & Refresh
|
||||
el.btnQuickPing.addEventListener('click', () => {
|
||||
showToast('กำลังตรวจสอบการเชื่อมต่อ...', 'info');
|
||||
showToast(t('checking'), 'info');
|
||||
refreshStatus();
|
||||
});
|
||||
|
||||
@@ -509,7 +559,7 @@ function setupEvents() {
|
||||
state.apiUrl = newUrl;
|
||||
localStorage.setItem('gac_srtool_api_url', newUrl);
|
||||
el.modalSettings.classList.remove('active');
|
||||
showToast('บันทึกการตั้งค่าแล้ว กำลังเชื่อมต่อใหม่...', 'info');
|
||||
showToast(t('settingsSaved'), 'info');
|
||||
refreshStatus();
|
||||
}
|
||||
});
|
||||
@@ -520,16 +570,16 @@ function setupEvents() {
|
||||
|
||||
el.btnQuickWarpExpress.addEventListener('click', () => {
|
||||
const express = PRESET_TELEPORTS[0];
|
||||
executeTeleport(express, express.name);
|
||||
executeTeleport(express, getTeleportName(express));
|
||||
});
|
||||
|
||||
el.btnQuickSyncPersistent.addEventListener('click', async () => {
|
||||
try {
|
||||
await apiCall('/api/persistent');
|
||||
showToast('ซิงค์ข้อมูล Persistent เรียบร้อย', 'success');
|
||||
showToast('Persistent data synced', 'success');
|
||||
refreshStatus();
|
||||
} catch (err) {
|
||||
showToast(`ซิงค์ไม่สำเร็จ: ${err.message}`, 'error');
|
||||
showToast(`Sync failed: ${err.message}`, 'error');
|
||||
}
|
||||
});
|
||||
|
||||
@@ -542,20 +592,20 @@ function setupEvents() {
|
||||
el.btnExrankEnableAll.addEventListener('click', async () => {
|
||||
try {
|
||||
await apiCall('/api/exrank/toggle', 'POST', { all: true, unlocked: true });
|
||||
showToast('เปิดใช้งาน Ex-Rank ทุกตัวละครสำเร็จ', 'success');
|
||||
showToast(t('exrankAllSuccess', { status: t('enabled') }), 'success');
|
||||
refreshStatus();
|
||||
} catch (err) {
|
||||
showToast(`เกิดข้อผิดพลาด: ${err.message}`, 'error');
|
||||
showToast(`Error: ${err.message}`, 'error');
|
||||
}
|
||||
});
|
||||
|
||||
el.btnExrankDisableAll.addEventListener('click', async () => {
|
||||
try {
|
||||
await apiCall('/api/exrank/toggle', 'POST', { all: true, unlocked: false });
|
||||
showToast('ปิดใช้งาน Ex-Rank ทุกตัวละครสำเร็จ', 'success');
|
||||
showToast(t('exrankAllSuccess', { status: t('disabled') }), 'success');
|
||||
refreshStatus();
|
||||
} catch (err) {
|
||||
showToast(`เกิดข้อผิดพลาด: ${err.message}`, 'error');
|
||||
showToast(`Error: ${err.message}`, 'error');
|
||||
}
|
||||
});
|
||||
|
||||
@@ -581,9 +631,9 @@ function setupEvents() {
|
||||
try {
|
||||
const parsed = JSON.parse(el.jsonEditor.value);
|
||||
el.jsonEditor.value = JSON.stringify(parsed, null, 2);
|
||||
showToast('จัดรูปแบบ JSON สวยงามแล้ว', 'info');
|
||||
showToast('JSON beautified', 'info');
|
||||
} catch (err) {
|
||||
showToast('JSON ไม่ถูกต้อง ไม่สามารถจัดรูปแบบได้', 'error');
|
||||
showToast(t('jsonInvalid'), 'error');
|
||||
}
|
||||
});
|
||||
|
||||
@@ -596,7 +646,7 @@ function setupEvents() {
|
||||
a.href = URL.createObjectURL(blob);
|
||||
a.download = `${state.currentJsonMode}-${Date.now()}.json`;
|
||||
a.click();
|
||||
showToast(`ดาวน์โหลด backup ไฟล์ ${a.download} แล้ว`, 'success');
|
||||
showToast(`Downloaded ${a.download}`, 'success');
|
||||
});
|
||||
|
||||
el.jsonFileInput.addEventListener('change', (e) => {
|
||||
@@ -607,9 +657,9 @@ function setupEvents() {
|
||||
try {
|
||||
const parsed = JSON.parse(event.target.result);
|
||||
el.jsonEditor.value = JSON.stringify(parsed, null, 2);
|
||||
showToast(`โหลดเนื้อหาไฟล์ ${file.name} เข้าสู่อิดิเตอร์แล้ว`, 'success');
|
||||
showToast(`Loaded ${file.name}`, 'success');
|
||||
} catch (err) {
|
||||
showToast('ไฟล์ไม่ใช่ JSON ที่ถูกต้อง', 'error');
|
||||
showToast(t('jsonInvalid'), 'error');
|
||||
}
|
||||
};
|
||||
reader.readAsText(file);
|
||||
@@ -627,7 +677,7 @@ function setupEvents() {
|
||||
localStorage.setItem('gac_srtool_api_url', state.apiUrl);
|
||||
localStorage.setItem('gac_srtool_ping_interval', state.pingIntervalSec);
|
||||
|
||||
showToast('บันทึกการตั้งค่าสำเร็จ!', 'success');
|
||||
showToast(t('settingsSaved'), 'success');
|
||||
refreshStatus();
|
||||
});
|
||||
|
||||
@@ -638,7 +688,7 @@ function setupEvents() {
|
||||
el.settingPingInterval.value = state.pingIntervalSec;
|
||||
localStorage.removeItem('gac_srtool_api_url');
|
||||
localStorage.removeItem('gac_srtool_ping_interval');
|
||||
showToast('คืนค่าเริ่มต้นเรียบร้อย', 'info');
|
||||
showToast(t('settingsReset'), 'info');
|
||||
refreshStatus();
|
||||
});
|
||||
}
|
||||
@@ -652,9 +702,10 @@ function startPingLoop() {
|
||||
|
||||
// Initialize Application
|
||||
function init() {
|
||||
setupLanguageSelector();
|
||||
setupTabs();
|
||||
setupEvents();
|
||||
renderTeleportPresets();
|
||||
applyTranslations();
|
||||
refreshStatus();
|
||||
startPingLoop();
|
||||
}
|
||||
|
||||
+547
-83
@@ -1,99 +1,563 @@
|
||||
// Metadata dictionary for Star Rail Avatars / Characters
|
||||
import { getCurrentLanguage, translateElement, translatePath } from './i18n.js';
|
||||
|
||||
export const AVATAR_METADATA = {
|
||||
// Trailblazers
|
||||
8001: { name: "Trailblazer (Physical)", path: "Destruction", element: "Physical", rarity: 5 },
|
||||
8002: { name: "Trailblazer (Physical ♀)", path: "Destruction", element: "Physical", rarity: 5 },
|
||||
8003: { name: "Trailblazer (Fire)", path: "Preservation", element: "Fire", rarity: 5 },
|
||||
8004: { name: "Trailblazer (Fire ♀)", path: "Preservation", element: "Fire", rarity: 5 },
|
||||
8005: { name: "Trailblazer (Harmony)", path: "Harmony", element: "Imaginary", rarity: 5 },
|
||||
8006: { name: "Trailblazer (Harmony ♀)", path: "Harmony", element: "Imaginary", rarity: 5 },
|
||||
8007: { name: "Trailblazer (Remembrance)", path: "Remembrance", element: "Ice", rarity: 5 },
|
||||
8008: { name: "Trailblazer (Remembrance ♀)", path: "Remembrance", element: "Ice", rarity: 5 },
|
||||
8001: {
|
||||
names: {
|
||||
en: "Trailblazer (Physical ♂)",
|
||||
th: "ผู้บุกเบิก (กายภาพ ♂)",
|
||||
"zh-CN": "开拓者 (物理 ♂)",
|
||||
"zh-TW": "開拓者 (物理 ♂)",
|
||||
ja: "開拓者 (物理 ♂)",
|
||||
ko: "개척자 (물리 ♂)",
|
||||
ru: "Первопроходец (Физ. ♂)"
|
||||
},
|
||||
path: "Destruction",
|
||||
element: "Physical",
|
||||
rarity: 5
|
||||
},
|
||||
8002: {
|
||||
names: {
|
||||
en: "Trailblazer (Physical ♀)",
|
||||
th: "ผู้บุกเบิก (กายภาพ ♀)",
|
||||
"zh-CN": "开拓者 (物理 ♀)",
|
||||
"zh-TW": "開拓者 (物理 ♀)",
|
||||
ja: "開拓者 (物理 ♀)",
|
||||
ko: "개척자 (물리 ♀)",
|
||||
ru: "Первопроходец (Физ. ♀)"
|
||||
},
|
||||
path: "Destruction",
|
||||
element: "Physical",
|
||||
rarity: 5
|
||||
},
|
||||
8003: {
|
||||
names: {
|
||||
en: "Trailblazer (Fire ♂)",
|
||||
th: "ผู้บุกเบิก (ไฟ ♂)",
|
||||
"zh-CN": "开拓者 (火 ♂)",
|
||||
"zh-TW": "開拓者 (火 ♂)",
|
||||
ja: "開拓者 (炎 ♂)",
|
||||
ko: "개척자 (화염 ♂)",
|
||||
ru: "Первопроходец (Огонь ♂)"
|
||||
},
|
||||
path: "Preservation",
|
||||
element: "Fire",
|
||||
rarity: 5
|
||||
},
|
||||
8004: {
|
||||
names: {
|
||||
en: "Trailblazer (Fire ♀)",
|
||||
th: "ผู้บุกเบิก (ไฟ ♀)",
|
||||
"zh-CN": "开拓者 (火 ♀)",
|
||||
"zh-TW": "開拓者 (火 ♀)",
|
||||
ja: "開拓者 (炎 ♀)",
|
||||
ko: "개척자 (화염 ♀)",
|
||||
ru: "Первопроходец (Огонь ♀)"
|
||||
},
|
||||
path: "Preservation",
|
||||
element: "Fire",
|
||||
rarity: 5
|
||||
},
|
||||
8005: {
|
||||
names: {
|
||||
en: "Trailblazer (Harmony ♂)",
|
||||
th: "ผู้บุกเบิก (ประสาน ♂)",
|
||||
"zh-CN": "开拓者 (同谐 ♂)",
|
||||
"zh-TW": "開拓者 (同諧 ♂)",
|
||||
ja: "開拓者 (調和 ♂)",
|
||||
ko: "개척자 (화합 ♂)",
|
||||
ru: "Первопроходец (Гармония ♂)"
|
||||
},
|
||||
path: "Harmony",
|
||||
element: "Imaginary",
|
||||
rarity: 5
|
||||
},
|
||||
8006: {
|
||||
names: {
|
||||
en: "Trailblazer (Harmony ♀)",
|
||||
th: "ผู้บุกเบิก (ประสาน ♀)",
|
||||
"zh-CN": "开拓者 (同谐 ♀)",
|
||||
"zh-TW": "開拓者 (同諧 ♀)",
|
||||
ja: "開拓者 (調和 ♀)",
|
||||
ko: "개척자 (화합 ♀)",
|
||||
ru: "Первопроходец (Гармония ♀)"
|
||||
},
|
||||
path: "Harmony",
|
||||
element: "Imaginary",
|
||||
rarity: 5
|
||||
},
|
||||
8007: {
|
||||
names: {
|
||||
en: "Trailblazer (Remembrance ♂)",
|
||||
th: "ผู้บุกเบิก (ความทรงจำ ♂)",
|
||||
"zh-CN": "开拓者 (记忆 ♂)",
|
||||
"zh-TW": "開拓者 (記憶 ♂)",
|
||||
ja: "開拓者 (記憶 ♂)",
|
||||
ko: "개척자 (기억 ♂)",
|
||||
ru: "Первопроходец (Память ♂)"
|
||||
},
|
||||
path: "Remembrance",
|
||||
element: "Ice",
|
||||
rarity: 5
|
||||
},
|
||||
8008: {
|
||||
names: {
|
||||
en: "Trailblazer (Remembrance ♀)",
|
||||
th: "ผู้บุกเบิก (ความทรงจำ ♀)",
|
||||
"zh-CN": "开拓者 (记忆 ♀)",
|
||||
"zh-TW": "開拓者 (記憶 ♀)",
|
||||
ja: "開拓者 (記憶 ♀)",
|
||||
ko: "개척자 (기억 ♀)",
|
||||
ru: "Первопроходец (Память ♀)"
|
||||
},
|
||||
path: "Remembrance",
|
||||
element: "Ice",
|
||||
rarity: 5
|
||||
},
|
||||
|
||||
// Astral Express & Herta Station
|
||||
1001: { name: "March 7th", path: "Preservation", element: "Ice", rarity: 4 },
|
||||
1224: { name: "March 7th (Hunt)", path: "Hunt", element: "Imaginary", rarity: 4 },
|
||||
1002: { name: "Dan Heng", path: "Hunt", element: "Wind", rarity: 4 },
|
||||
1003: { name: "Himeko", path: "Erudition", element: "Fire", rarity: 5 },
|
||||
1004: { name: "Welt", path: "Nihility", element: "Imaginary", rarity: 5 },
|
||||
1008: { name: "Arlan", path: "Destruction", element: "Lightning", rarity: 4 },
|
||||
1009: { name: "Asta", path: "Harmony", element: "Fire", rarity: 4 },
|
||||
1013: { name: "Herta", path: "Erudition", element: "Ice", rarity: 4 },
|
||||
1001: {
|
||||
names: { en: "March 7th", th: "March 7th (มาร์ช)", "zh-CN": "三月七", "zh-TW": "三月七", ja: "三月なのか", ko: "March 7th", ru: "Март 7" },
|
||||
path: "Preservation",
|
||||
element: "Ice",
|
||||
rarity: 4
|
||||
},
|
||||
1224: {
|
||||
names: { en: "March 7th (The Hunt)", th: "March 7th (ล่าสังหาร)", "zh-CN": "三月七 (巡猎)", "zh-TW": "三月七 (巡獵)", ja: "三月なのか (巡狩)", ko: "March 7th (수렵)", ru: "Март 7 (Охота)" },
|
||||
path: "Hunt",
|
||||
element: "Imaginary",
|
||||
rarity: 4
|
||||
},
|
||||
1002: {
|
||||
names: { en: "Dan Heng", th: "Dan Heng (ดันเฮง)", "zh-CN": "丹恒", "zh-TW": "丹恆", ja: "丹恒", ko: "단항", ru: "Дань Хэн" },
|
||||
path: "Hunt",
|
||||
element: "Wind",
|
||||
rarity: 4
|
||||
},
|
||||
1003: {
|
||||
names: { en: "Himeko", th: "Himeko (ฮิเมโกะ)", "zh-CN": "姬子", "zh-TW": "姬子", ja: "姫子", ko: "히메코", ru: "Химеко" },
|
||||
path: "Erudition",
|
||||
element: "Fire",
|
||||
rarity: 5
|
||||
},
|
||||
1004: {
|
||||
names: { en: "Welt", th: "Welt (เวลท์)", "zh-CN": "瓦尔特", "zh-TW": "瓦爾特", ja: "ヴェルト", ko: "웰트", ru: "Вельт" },
|
||||
path: "Nihility",
|
||||
element: "Imaginary",
|
||||
rarity: 5
|
||||
},
|
||||
1008: {
|
||||
names: { en: "Arlan", th: "Arlan (อาร์ลัน)", "zh-CN": "阿兰", "zh-TW": "阿蘭", ja: "アーラン", ko: "아를란", ru: "Арлан" },
|
||||
path: "Destruction",
|
||||
element: "Lightning",
|
||||
rarity: 4
|
||||
},
|
||||
1009: {
|
||||
names: { en: "Asta", th: "Asta (แอสต้า)", "zh-CN": "艾丝妲", "zh-TW": "艾絲妲", ja: "アスター", ko: "아스타", ru: "Аста" },
|
||||
path: "Harmony",
|
||||
element: "Fire",
|
||||
rarity: 4
|
||||
},
|
||||
1013: {
|
||||
names: { en: "Herta", th: "Herta (เฮอร์ทา)", "zh-CN": "黑塔", "zh-TW": "黑塔", ja: "ヘルタ", ko: "헤르타", ru: "Герта" },
|
||||
path: "Erudition",
|
||||
element: "Ice",
|
||||
rarity: 4
|
||||
},
|
||||
|
||||
// Belobog
|
||||
1101: { name: "Bronya", path: "Harmony", element: "Wind", rarity: 5 },
|
||||
1102: { name: "Seele", path: "Hunt", element: "Quantum", rarity: 5 },
|
||||
1103: { name: "Serval", path: "Erudition", element: "Lightning", rarity: 4 },
|
||||
1104: { name: "Gepard", path: "Preservation", element: "Ice", rarity: 5 },
|
||||
1105: { name: "Natasha", path: "Abundance", element: "Physical", rarity: 4 },
|
||||
1106: { name: "Pela", path: "Nihility", element: "Ice", rarity: 4 },
|
||||
1107: { name: "Clara", path: "Destruction", element: "Physical", rarity: 5 },
|
||||
1108: { name: "Sampo", path: "Nihility", element: "Wind", rarity: 4 },
|
||||
1109: { name: "Hook", path: "Destruction", element: "Fire", rarity: 4 },
|
||||
1110: { name: "Lynx", path: "Abundance", element: "Quantum", rarity: 4 },
|
||||
1111: { name: "Luka", path: "Nihility", element: "Physical", rarity: 4 },
|
||||
1112: { name: "Topaz & Numby", path: "Hunt", element: "Fire", rarity: 5 },
|
||||
1101: {
|
||||
names: { en: "Bronya", th: "Bronya (โบรเนีย)", "zh-CN": "布洛妮娅", "zh-TW": "布洛妮婭", ja: "ブローニャ", ko: "브로냐", ru: "Броня" },
|
||||
path: "Harmony",
|
||||
element: "Wind",
|
||||
rarity: 5
|
||||
},
|
||||
1102: {
|
||||
names: { en: "Seele", th: "Seele (เซเล่)", "zh-CN": "希儿", "zh-TW": "希兒", ja: "ゼーレ", ko: "제레", ru: "Зеле" },
|
||||
path: "Hunt",
|
||||
element: "Quantum",
|
||||
rarity: 5
|
||||
},
|
||||
1103: {
|
||||
names: { en: "Serval", th: "Serval (เซอวัล)", "zh-CN": "希露瓦", "zh-TW": "希露瓦", ja: "セーバル", ko: "서벌", ru: "Сервал" },
|
||||
path: "Erudition",
|
||||
element: "Lightning",
|
||||
rarity: 4
|
||||
},
|
||||
1104: {
|
||||
names: { en: "Gepard", th: "Gepard (เกพาร์ด)", "zh-CN": "杰帕德", "zh-TW": "傑帕德", ja: "ジェパード", ko: "게파드", ru: "Гепард" },
|
||||
path: "Preservation",
|
||||
element: "Ice",
|
||||
rarity: 5
|
||||
},
|
||||
1105: {
|
||||
names: { en: "Natasha", th: "Natasha (นาตาชา)", "zh-CN": "娜塔莎", "zh-TW": "娜塔莎", ja: "ナターシャ", ko: "나타샤", ru: "Наташа" },
|
||||
path: "Abundance",
|
||||
element: "Physical",
|
||||
rarity: 4
|
||||
},
|
||||
1106: {
|
||||
names: { en: "Pela", th: "Pela (เพล่า)", "zh-CN": "佩拉", "zh-TW": "佩拉", ja: "ペラ", ko: "페라", ru: "Пела" },
|
||||
path: "Nihility",
|
||||
element: "Ice",
|
||||
rarity: 4
|
||||
},
|
||||
1107: {
|
||||
names: { en: "Clara", th: "Clara (คลาร่า)", "zh-CN": "克拉拉", "zh-TW": "克拉拉", ja: "クラーラ", ko: "클라라", ru: "Клара" },
|
||||
path: "Destruction",
|
||||
element: "Physical",
|
||||
rarity: 5
|
||||
},
|
||||
1108: {
|
||||
names: { en: "Sampo", th: "Sampo (ซัมโป)", "zh-CN": "桑博", "zh-TW": "桑博", ja: "サンポ", ko: "삼포", ru: "Сампо" },
|
||||
path: "Nihility",
|
||||
element: "Wind",
|
||||
rarity: 4
|
||||
},
|
||||
1109: {
|
||||
names: { en: "Hook", th: "Hook (ฮุก)", "zh-CN": "虎克", "zh-TW": "虎克", ja: "フック", ko: "후크", ru: "Хук" },
|
||||
path: "Destruction",
|
||||
element: "Fire",
|
||||
rarity: 4
|
||||
},
|
||||
1110: {
|
||||
names: { en: "Lynx", th: "Lynx (ลิงซ์)", "zh-CN": "玲可", "zh-TW": "玲可", ja: "リンクス", ko: "링스", ru: "Рысь" },
|
||||
path: "Abundance",
|
||||
element: "Quantum",
|
||||
rarity: 4
|
||||
},
|
||||
1111: {
|
||||
names: { en: "Luka", th: "Luka (ลูก้า)", "zh-CN": "卢卡", "zh-TW": "盧卡", ja: "ルカ", ko: "루카", ru: "Лука" },
|
||||
path: "Nihility",
|
||||
element: "Physical",
|
||||
rarity: 4
|
||||
},
|
||||
1112: {
|
||||
names: { en: "Topaz & Numby", th: "Topaz & Numby (โทพาส)", "zh-CN": "托帕&账账", "zh-TW": "托帕&帳帳", ja: "トパーズ&カブ", ko: "토파즈&복순이", ru: "Топаз и Счетовод" },
|
||||
path: "Hunt",
|
||||
element: "Fire",
|
||||
rarity: 5
|
||||
},
|
||||
|
||||
// Xianzhou Luofu
|
||||
1201: { name: "Qingque", path: "Erudition", element: "Quantum", rarity: 4 },
|
||||
1202: { name: "Tingyun", path: "Harmony", element: "Lightning", rarity: 4 },
|
||||
1203: { name: "Luocha", path: "Abundance", element: "Imaginary", rarity: 5 },
|
||||
1204: { name: "Jing Yuan", path: "Erudition", element: "Lightning", rarity: 5, hasExRank: true },
|
||||
1205: { name: "Blade", path: "Destruction", element: "Wind", rarity: 5 },
|
||||
1206: { name: "Sushang", path: "Hunt", element: "Physical", rarity: 4 },
|
||||
1207: { name: "Yukong", path: "Harmony", element: "Imaginary", rarity: 4 },
|
||||
1208: { name: "Fu Xuan", path: "Preservation", element: "Quantum", rarity: 5 },
|
||||
1209: { name: "Yanqing", path: "Hunt", element: "Ice", rarity: 5 },
|
||||
1210: { name: "Guinaifen", path: "Nihility", element: "Fire", rarity: 4 },
|
||||
1211: { name: "Bailu", path: "Abundance", element: "Lightning", rarity: 5 },
|
||||
1212: { name: "Jingliu", path: "Destruction", element: "Ice", rarity: 5 },
|
||||
1213: { name: "Dan Heng • Imbibitor Lunae", path: "Destruction", element: "Imaginary", rarity: 5, hasExRank: true },
|
||||
1214: { name: "Xueyi", path: "Destruction", element: "Quantum", rarity: 4 },
|
||||
1215: { name: "Hanya", path: "Harmony", element: "Physical", rarity: 4 },
|
||||
1217: { name: "Huohuo", path: "Abundance", element: "Wind", rarity: 5 },
|
||||
1218: { name: "Jiaoqiu", path: "Nihility", element: "Fire", rarity: 5 },
|
||||
1220: { name: "Feixiao", path: "Hunt", element: "Wind", rarity: 5 },
|
||||
1221: { name: "Yunli", path: "Destruction", element: "Physical", rarity: 5 },
|
||||
1222: { name: "Lingsha", path: "Abundance", element: "Fire", rarity: 5 },
|
||||
1223: { name: "Moze", path: "Hunt", element: "Lightning", rarity: 4 },
|
||||
1225: { name: "Fugue", path: "Nihility", element: "Fire", rarity: 5 },
|
||||
1201: {
|
||||
names: { en: "Qingque", th: "Qingque (ชิงเชว่)", "zh-CN": "青雀", "zh-TW": "青雀", ja: "青雀", ko: "청작", ru: "Цинцюэ" },
|
||||
path: "Erudition",
|
||||
element: "Quantum",
|
||||
rarity: 4
|
||||
},
|
||||
1202: {
|
||||
names: { en: "Tingyun", th: "Tingyun (ถิงหยุน)", "zh-CN": "停云", "zh-TW": "停雲", ja: "停雲", ko: "정운", ru: "Тинъюнь" },
|
||||
path: "Harmony",
|
||||
element: "Lightning",
|
||||
rarity: 4
|
||||
},
|
||||
1203: {
|
||||
names: { en: "Luocha", th: "Luocha (หลัวชา)", "zh-CN": "罗刹", "zh-TW": "羅剎", ja: "羅刹", ko: "나찰", ru: "Лоча" },
|
||||
path: "Abundance",
|
||||
element: "Imaginary",
|
||||
rarity: 5
|
||||
},
|
||||
1204: {
|
||||
names: { en: "Jing Yuan", th: "Jing Yuan (จิ่งหยวน)", "zh-CN": "景元", "zh-TW": "景元", ja: "景元", ko: "경원", ru: "Цзин Юань" },
|
||||
path: "Erudition",
|
||||
element: "Lightning",
|
||||
rarity: 5,
|
||||
hasExRank: true
|
||||
},
|
||||
1205: {
|
||||
names: { en: "Blade", th: "Blade (เบลด)", "zh-CN": "刃", "zh-TW": "刃", ja: "刃", ko: "블레이드", ru: "Блэйд" },
|
||||
path: "Destruction",
|
||||
element: "Wind",
|
||||
rarity: 5
|
||||
},
|
||||
1206: {
|
||||
names: { en: "Sushang", th: "Sushang (ซู่ซาง)", "zh-CN": "素裳", "zh-TW": "素裳", ja: "素裳", ko: "소상", ru: "Сушан" },
|
||||
path: "Hunt",
|
||||
element: "Physical",
|
||||
rarity: 4
|
||||
},
|
||||
1207: {
|
||||
names: { en: "Yukong", th: "Yukong (ยู่คง)", "zh-CN": "驭空", "zh-TW": "馭空", ja: "御空", ko: "어공", ru: "Юйкун" },
|
||||
path: "Harmony",
|
||||
element: "Imaginary",
|
||||
rarity: 4
|
||||
},
|
||||
1208: {
|
||||
names: { en: "Fu Xuan", th: "Fu Xuan (ฟู่เสวียน)", "zh-CN": "符玄", "zh-TW": "符玄", ja: "符玄", ko: "부현", ru: "Фу Сюань" },
|
||||
path: "Preservation",
|
||||
element: "Quantum",
|
||||
rarity: 5
|
||||
},
|
||||
1209: {
|
||||
names: { en: "Yanqing", th: "Yanqing (เยี่ยนชิง)", "zh-CN": "彦卿", "zh-TW": "彥卿", ja: "彦卿", ko: "연경", ru: "Яньцин" },
|
||||
path: "Hunt",
|
||||
element: "Ice",
|
||||
rarity: 5
|
||||
},
|
||||
1210: {
|
||||
names: { en: "Guinaifen", th: "Guinaifen (กุ้ยหน่ายเฟิน)", "zh-CN": "桂乃芬", "zh-TW": "桂乃芬", ja: "桂乃芬", ko: "계네빈", ru: "Гуйнайфэнь" },
|
||||
path: "Nihility",
|
||||
element: "Fire",
|
||||
rarity: 4
|
||||
},
|
||||
1211: {
|
||||
names: { en: "Bailu", th: "Bailu (ไป่ลู่)", "zh-CN": "白露", "zh-TW": "白露", ja: "白露", ko: "백로", ru: "Байлу" },
|
||||
path: "Abundance",
|
||||
element: "Lightning",
|
||||
rarity: 5
|
||||
},
|
||||
1212: {
|
||||
names: { en: "Jingliu", th: "Jingliu (จิ้งหลิว)", "zh-CN": "镜流", "zh-TW": "鏡流", ja: "鏡流", ko: "경류", ru: "Цзинлю" },
|
||||
path: "Destruction",
|
||||
element: "Ice",
|
||||
rarity: 5
|
||||
},
|
||||
1213: {
|
||||
names: { en: "Dan Heng • Imbibitor Lunae", th: "Dan Heng • IL (ดันเฮง จ้าวยลจันทรา)", "zh-CN": "丹恒·饮月", "zh-TW": "丹恆·飲月", ja: "丹恒・飲月", ko: "단항·음월", ru: "Дань Хэн: Пожиратель Луны" },
|
||||
path: "Destruction",
|
||||
element: "Imaginary",
|
||||
rarity: 5,
|
||||
hasExRank: true
|
||||
},
|
||||
1214: {
|
||||
names: { en: "Xueyi", th: "Xueyi (เสวียอี้)", "zh-CN": "雪衣", "zh-TW": "雪衣", ja: "雪衣", ko: "설의", ru: "Сюэи" },
|
||||
path: "Destruction",
|
||||
element: "Quantum",
|
||||
rarity: 4
|
||||
},
|
||||
1215: {
|
||||
names: { en: "Hanya", th: "Hanya (ฮั่นหยา)", "zh-CN": "寒鸦", "zh-TW": "寒鴉", ja: "寒鴉", ko: "한아", ru: "Ханья" },
|
||||
path: "Harmony",
|
||||
element: "Physical",
|
||||
rarity: 4
|
||||
},
|
||||
1217: {
|
||||
names: { en: "Huohuo", th: "Huohuo (ฮั่วฮั่ว)", "zh-CN": "藿藿", "zh-TW": "藿藿", ja: "フォフォ", ko: "곽향", ru: "Хохо" },
|
||||
path: "Abundance",
|
||||
element: "Wind",
|
||||
rarity: 5
|
||||
},
|
||||
1218: {
|
||||
names: { en: "Jiaoqiu", th: "Jiaoqiu (เจียวชิว)", "zh-CN": "椒丘", "zh-TW": "椒丘", ja: "椒丘", ko: "초구", ru: "Цзяоцю" },
|
||||
path: "Nihility",
|
||||
element: "Fire",
|
||||
rarity: 5
|
||||
},
|
||||
1220: {
|
||||
names: { en: "Feixiao", th: "Feixiao (เฟยเซียว)", "zh-CN": "飞霄", "zh-TW": "飛霄", ja: "飛霄", ko: "비소", ru: "Фэйсяо" },
|
||||
path: "Hunt",
|
||||
element: "Wind",
|
||||
rarity: 5
|
||||
},
|
||||
1221: {
|
||||
names: { en: "Yunli", th: "Yunli (หยุนหลี่)", "zh-CN": "云璃", "zh-TW": "雲璃", ja: "雲璃", ko: "운리", ru: "Юньли" },
|
||||
path: "Destruction",
|
||||
element: "Physical",
|
||||
rarity: 5
|
||||
},
|
||||
1222: {
|
||||
names: { en: "Lingsha", th: "Lingsha (หลิงซา)", "zh-CN": "灵砂", "zh-TW": "靈砂", ja: "霊砂", ko: "영사", ru: "Линша" },
|
||||
path: "Abundance",
|
||||
element: "Fire",
|
||||
rarity: 5
|
||||
},
|
||||
1223: {
|
||||
names: { en: "Moze", th: "Moze (มั่วเจ๋อ)", "zh-CN": "貊泽", "zh-TW": "貊澤", ja: "モゼ", ko: "맥택", ru: "Моцзэ" },
|
||||
path: "Hunt",
|
||||
element: "Lightning",
|
||||
rarity: 4
|
||||
},
|
||||
1225: {
|
||||
names: { en: "Fugue", th: "Fugue (ฟูก)", "zh-CN": "忘归人", "zh-TW": "忘歸人", ja: "帰忘の流離人", ko: "망귀인", ru: "Фуга" },
|
||||
path: "Nihility",
|
||||
element: "Fire",
|
||||
rarity: 5
|
||||
},
|
||||
|
||||
// Penacony & Stellar Hunters
|
||||
1005: { name: "Kafka", path: "Nihility", element: "Lightning", rarity: 5 },
|
||||
1006: { name: "Silver Wolf", path: "Nihility", element: "Quantum", rarity: 5 },
|
||||
1301: { name: "Gallagher", path: "Abundance", element: "Fire", rarity: 4 },
|
||||
1302: { name: "Argenti", path: "Erudition", element: "Physical", rarity: 5 },
|
||||
1303: { name: "Ruan Mei", path: "Harmony", element: "Ice", rarity: 5 },
|
||||
1304: { name: "Aventurine", path: "Preservation", element: "Imaginary", rarity: 5 },
|
||||
1305: { name: "Dr. Ratio", path: "Hunt", element: "Imaginary", rarity: 5 },
|
||||
1306: { name: "Sparkle", path: "Harmony", element: "Quantum", rarity: 5 },
|
||||
1307: { name: "Black Swan", path: "Nihility", element: "Wind", rarity: 5 },
|
||||
1308: { name: "Acheron", path: "Nihility", element: "Lightning", rarity: 5, hasExRank: true },
|
||||
1309: { name: "Robin", path: "Harmony", element: "Physical", rarity: 5 },
|
||||
1310: { name: "Firefly", path: "Destruction", element: "Fire", rarity: 5 },
|
||||
1312: { name: "Misha", path: "Destruction", element: "Ice", rarity: 4 },
|
||||
1313: { name: "Sunday", path: "Harmony", element: "Imaginary", rarity: 5 },
|
||||
1314: { name: "Jade", path: "Erudition", element: "Quantum", rarity: 5 },
|
||||
1315: { name: "Boothill", path: "Hunt", element: "Physical", rarity: 5 },
|
||||
1317: { name: "Rappa", path: "Erudition", element: "Imaginary", rarity: 5 },
|
||||
1005: {
|
||||
names: { en: "Kafka", th: "Kafka (คาฟคา)", "zh-CN": "卡芙卡", "zh-TW": "卡芙卡", ja: "カフカ", ko: "카프카", ru: "Кафка" },
|
||||
path: "Nihility",
|
||||
element: "Lightning",
|
||||
rarity: 5
|
||||
},
|
||||
1006: {
|
||||
names: { en: "Silver Wolf", th: "Silver Wolf (ซิลเวอร์วูล์ฟ)", "zh-CN": "银狼", "zh-TW": "銀狼", ja: "銀狼", ko: "은랑", ru: "Серебряный Волк" },
|
||||
path: "Nihility",
|
||||
element: "Quantum",
|
||||
rarity: 5
|
||||
},
|
||||
1301: {
|
||||
names: { en: "Gallagher", th: "Gallagher (กัลลาเกอร์)", "zh-CN": "加拉赫", "zh-TW": "加拉赫", ja: "ギャラガー", ko: "갤러거", ru: "Галлахер" },
|
||||
path: "Abundance",
|
||||
element: "Fire",
|
||||
rarity: 4
|
||||
},
|
||||
1302: {
|
||||
names: { en: "Argenti", th: "Argenti (อาร์เจนติ)", "zh-CN": "银枝", "zh-TW": "銀枝", ja: "アルジェンティ", ko: "아젠티", ru: "Аргенти" },
|
||||
path: "Erudition",
|
||||
element: "Physical",
|
||||
rarity: 5
|
||||
},
|
||||
1303: {
|
||||
names: { en: "Ruan Mei", th: "Ruan Mei (หร่วนเหมย)", "zh-CN": "阮·梅", "zh-TW": "阮·梅", ja: "ルアン・メェイ", ko: "완·매", ru: "Жуань Мэй" },
|
||||
path: "Harmony",
|
||||
element: "Ice",
|
||||
rarity: 5
|
||||
},
|
||||
1304: {
|
||||
names: { en: "Aventurine", th: "Aventurine (อเวนจูรีน)", "zh-CN": "砂金", "zh-TW": "砂金", ja: "アベンチュリン", ko: "어벤츄린", ru: "Авантюрин" },
|
||||
path: "Preservation",
|
||||
element: "Imaginary",
|
||||
rarity: 5
|
||||
},
|
||||
1305: {
|
||||
names: { en: "Dr. Ratio", th: "Dr. Ratio (ดร.เรโช)", "zh-CN": "真理医生", "zh-TW": "真理醫生", ja: "Dr.レイシオ", ko: "Dr. 레이시오", ru: "Д-р Рацио" },
|
||||
path: "Hunt",
|
||||
element: "Imaginary",
|
||||
rarity: 5
|
||||
},
|
||||
1306: {
|
||||
names: { en: "Sparkle", th: "Sparkle (สปาร์เคิล)", "zh-CN": "花火", "zh-TW": "花火", ja: "花火", ko: "스파클", ru: "Искорка" },
|
||||
path: "Harmony",
|
||||
element: "Quantum",
|
||||
rarity: 5
|
||||
},
|
||||
1307: {
|
||||
names: { en: "Black Swan", th: "Black Swan (แบล็กสวอน)", "zh-CN": "黑天鹅", "zh-TW": "黑天鵝", ja: "ブラックスワン", ko: "블랙 스완", ru: "Чёрный Лебедь" },
|
||||
path: "Nihility",
|
||||
element: "Wind",
|
||||
rarity: 5
|
||||
},
|
||||
1308: {
|
||||
names: { en: "Acheron", th: "Acheron (อาเคอรอน)", "zh-CN": "黄泉", "zh-TW": "黃泉", ja: "黄泉", ko: "아케론", ru: "Ахерон" },
|
||||
path: "Nihility",
|
||||
element: "Lightning",
|
||||
rarity: 5,
|
||||
hasExRank: true
|
||||
},
|
||||
1309: {
|
||||
names: { en: "Robin", th: "Robin (โรบิน)", "zh-CN": "知更鸟", "zh-TW": "知更鳥", ja: "ロビン", ko: "로빈", ru: "Зарянка" },
|
||||
path: "Harmony",
|
||||
element: "Physical",
|
||||
rarity: 5
|
||||
},
|
||||
1310: {
|
||||
names: { en: "Firefly", th: "Firefly (ไฟร์ฟลาย)", "zh-CN": "流萤", "zh-TW": "流螢", ja: "ホタル", ko: "반디", ru: "Светлячок" },
|
||||
path: "Destruction",
|
||||
element: "Fire",
|
||||
rarity: 5
|
||||
},
|
||||
1312: {
|
||||
names: { en: "Misha", th: "Misha (มิชา)", "zh-CN": "米沙", "zh-TW": "米沙", ja: "ミーシャ", ko: "미샤", ru: "Миша" },
|
||||
path: "Destruction",
|
||||
element: "Ice",
|
||||
rarity: 4
|
||||
},
|
||||
1313: {
|
||||
names: { en: "Sunday", th: "Sunday (ซันเดย์)", "zh-CN": "星期日", "zh-TW": "星期日", ja: "サンデー", ko: "선데이", ru: "Воскресенье" },
|
||||
path: "Harmony",
|
||||
element: "Imaginary",
|
||||
rarity: 5
|
||||
},
|
||||
1314: {
|
||||
names: { en: "Jade", th: "Jade (เจด)", "zh-CN": "翡翠", "zh-TW": "翡翠", ja: "ジェイド", ko: "제이드", ru: "Яшма" },
|
||||
path: "Erudition",
|
||||
element: "Quantum",
|
||||
rarity: 5
|
||||
},
|
||||
1315: {
|
||||
names: { en: "Boothill", th: "Boothill (บูตฮิลล์)", "zh-CN": "波提欧", "zh-TW": "波提歐", ja: "ブートヒル", ko: "부트힐", ru: "Бутхилл" },
|
||||
path: "Hunt",
|
||||
element: "Physical",
|
||||
rarity: 5
|
||||
},
|
||||
1317: {
|
||||
names: { en: "Rappa", th: "Rappa (รัปป้า)", "zh-CN": "乱破", "zh-TW": "亂破", ja: "乱破", ko: "라파", ru: "Раппа" },
|
||||
path: "Erudition",
|
||||
element: "Imaginary",
|
||||
rarity: 5
|
||||
},
|
||||
|
||||
// Amphoreus / 3.x+
|
||||
1401: { name: "Aglaea", path: "Remembrance", element: "Lightning", rarity: 5 },
|
||||
1402: { name: "The Herta", path: "Erudition", element: "Ice", rarity: 5 },
|
||||
1403: { name: "Tribbie", path: "Harmony", element: "Quantum", rarity: 5 },
|
||||
1404: { name: "Mydei", path: "Destruction", element: "Imaginary", rarity: 5 },
|
||||
1405: { name: "Anaxa", path: "Erudition", element: "Wind", rarity: 5 },
|
||||
1407: { name: "Castorice", path: "Remembrance", element: "Quantum", rarity: 5 },
|
||||
1408: { name: "Cipher", path: "Nihility", element: "Imaginary", rarity: 5 },
|
||||
1409: { name: "Phainon", path: "Destruction", element: "Physical", rarity: 5 },
|
||||
1410: { name: "Hyacine", path: "Remembrance", element: "Wind", rarity: 5 }
|
||||
1401: {
|
||||
names: { en: "Aglaea", th: "Aglaea (อกลาเอีย)", "zh-CN": "阿格莱雅", "zh-TW": "阿格萊雅", ja: "アグライア", ko: "아글라이아", ru: "Аглая" },
|
||||
path: "Remembrance",
|
||||
element: "Lightning",
|
||||
rarity: 5
|
||||
},
|
||||
1402: {
|
||||
names: { en: "The Herta", th: "The Herta (เดอะเฮอร์ทา)", "zh-CN": "大黑塔", "zh-TW": "大黑塔", ja: "マダム・ヘルタ", ko: "더 헤르타", ru: "Великая Герта" },
|
||||
path: "Erudition",
|
||||
element: "Ice",
|
||||
rarity: 5
|
||||
},
|
||||
1403: {
|
||||
names: { en: "Tribbie", th: "Tribbie (ทริบบี้)", "zh-CN": "特里比", "zh-TW": "特里比", ja: "トリビー", ko: "트리비", ru: "Трибби" },
|
||||
path: "Harmony",
|
||||
element: "Quantum",
|
||||
rarity: 5
|
||||
},
|
||||
1404: {
|
||||
names: { en: "Mydei", th: "Mydei (ไมเดย์)", "zh-CN": "麦狄", "zh-TW": "麥狄", ja: "マイディ", ko: "마이데이", ru: "Мидей" },
|
||||
path: "Destruction",
|
||||
element: "Imaginary",
|
||||
rarity: 5
|
||||
},
|
||||
1405: {
|
||||
names: { en: "Anaxa", th: "Anaxa (อนากซา)", "zh-CN": "阿那克萨", "zh-TW": "阿那克薩", ja: "アナクサ", ko: "아낙사", ru: "Анакса" },
|
||||
path: "Erudition",
|
||||
element: "Wind",
|
||||
rarity: 5
|
||||
},
|
||||
1407: {
|
||||
names: { en: "Castorice", th: "Castorice (คาสโตริเซ่)", "zh-CN": "遐蝶", "zh-TW": "遐蝶", ja: "カストリセ", ko: "카스토리체", ru: "Касторисе" },
|
||||
path: "Remembrance",
|
||||
element: "Quantum",
|
||||
rarity: 5
|
||||
},
|
||||
1408: {
|
||||
names: { en: "Cipher", th: "Cipher (ไซเฟอร์)", "zh-CN": "赛弗", "zh-TW": "賽弗", ja: "サイファー", ko: "사이퍼", ru: "Сайфер" },
|
||||
path: "Nihility",
|
||||
element: "Imaginary",
|
||||
rarity: 5
|
||||
},
|
||||
1409: {
|
||||
names: { en: "Phainon", th: "Phainon (ฟานอน)", "zh-CN": "法埃农", "zh-TW": "法埃農", ja: "ファイノン", ko: "파이논", ru: "Файнон" },
|
||||
path: "Destruction",
|
||||
element: "Physical",
|
||||
rarity: 5
|
||||
},
|
||||
1410: {
|
||||
names: { en: "Hyacine", th: "Hyacine (ไฮยาซีน)", "zh-CN": "风信子", "zh-TW": "風信子", ja: "ヒヤシンス", ko: "히아신스", ru: "Гиацинт" },
|
||||
path: "Remembrance",
|
||||
element: "Wind",
|
||||
rarity: 5
|
||||
}
|
||||
};
|
||||
|
||||
export function getAvatarInfo(avatarId) {
|
||||
return AVATAR_METADATA[avatarId] || {
|
||||
name: `Avatar ${avatarId}`,
|
||||
path: "Unknown",
|
||||
element: "Unknown",
|
||||
rarity: 4
|
||||
export function getAvatarInfo(avatarId, langOverride = null) {
|
||||
const lang = langOverride || getCurrentLanguage();
|
||||
const meta = AVATAR_METADATA[avatarId];
|
||||
|
||||
if (!meta) {
|
||||
return {
|
||||
name: `Avatar ${avatarId}`,
|
||||
path: translatePath("Unknown"),
|
||||
element: translateElement("Unknown"),
|
||||
rarity: 4,
|
||||
hasExRank: false
|
||||
};
|
||||
}
|
||||
|
||||
const localizedName = meta.names?.[lang] || meta.names?.en || meta.names?.th || `Avatar ${avatarId}`;
|
||||
|
||||
return {
|
||||
name: localizedName,
|
||||
path: translatePath(meta.path),
|
||||
element: translateElement(meta.element),
|
||||
rarity: meta.rarity,
|
||||
hasExRank: !!meta.hasExRank
|
||||
};
|
||||
}
|
||||
+1311
File diff suppressed because it is too large.
Load diff
+70
-15
@@ -1,8 +1,16 @@
|
||||
// Safe preset teleports for Star Rail maps
|
||||
import { getCurrentLanguage } from './i18n.js';
|
||||
|
||||
export const PRESET_TELEPORTS = [
|
||||
{
|
||||
name: "Astral Express - Parlor Car (รถไฟขบวนแอสทรัล)",
|
||||
world: "Astral Express",
|
||||
names: {
|
||||
th: "Astral Express - ขบวนรถไฟแอสทรัล (ห้องรับรอง)",
|
||||
en: "Astral Express - Parlor Car",
|
||||
"zh-CN": "星穹列车 - 观景车厢",
|
||||
"zh-TW": "星穹列車 - 觀景車廂",
|
||||
ja: "星穹列車 - 客室",
|
||||
ko: "은하열차 - 객실",
|
||||
ru: "Звёздный экспресс - Общий вагон"
|
||||
},
|
||||
plane_id: 20001,
|
||||
floor_id: 20001001,
|
||||
entry_id: 2000101,
|
||||
@@ -11,8 +19,15 @@ export const PRESET_TELEPORTS = [
|
||||
z: 0
|
||||
},
|
||||
{
|
||||
name: "Herta Space Station - Master Control Zone (สถานีอวกาศ Herta - โซนควบคุมหลัก)",
|
||||
world: "Herta Space Station",
|
||||
names: {
|
||||
th: "สถานีอวกาศ Herta - โซนควบคุมหลัก (Master Control Zone)",
|
||||
en: "Herta Space Station - Master Control Zone",
|
||||
"zh-CN": "空间站「黑塔」 - 主控舱段",
|
||||
"zh-TW": "太空站「黑塔」 - 主控艙段",
|
||||
ja: "宇宙ステーション「ヘルタ」 - 主制御部分",
|
||||
ko: "우주정거장 「헤르타」 - 메인 컨트롤 구역",
|
||||
ru: "Космическая станция «Герта» - Главная контрольная зона"
|
||||
},
|
||||
plane_id: 10001,
|
||||
floor_id: 10001001,
|
||||
entry_id: 1000101,
|
||||
@@ -21,8 +36,15 @@ export const PRESET_TELEPORTS = [
|
||||
z: 0
|
||||
},
|
||||
{
|
||||
name: "Jarilo-VI - Administrative District (เขตการปกครอง)",
|
||||
world: "Jarilo-VI (Belobog)",
|
||||
names: {
|
||||
th: "Jarilo-VI (Belobog) - เขตการปกครอง (Administrative District)",
|
||||
en: "Jarilo-VI - Administrative District",
|
||||
"zh-CN": "雅利洛-VI - 行政区",
|
||||
"zh-TW": "雅利洛-VI - 行政區",
|
||||
ja: "ヤリーロ-VI - 行政区",
|
||||
ko: "야릴로-VI - 행정구역",
|
||||
ru: "Ярило-VI - Административный район"
|
||||
},
|
||||
plane_id: 10101,
|
||||
floor_id: 10101001,
|
||||
entry_id: 1010101,
|
||||
@@ -31,8 +53,15 @@ export const PRESET_TELEPORTS = [
|
||||
z: 32670
|
||||
},
|
||||
{
|
||||
name: "Jarilo-VI - Boulder Town (เมือง Boulder)",
|
||||
world: "Jarilo-VI (Underworld)",
|
||||
names: {
|
||||
th: "Jarilo-VI (Underworld) - เมือง Boulder (Boulder Town)",
|
||||
en: "Jarilo-VI - Boulder Town",
|
||||
"zh-CN": "雅利洛-VI - 磐岩镇",
|
||||
"zh-TW": "雅利洛-VI - 磐岩鎮",
|
||||
ja: "ヤリーロ-VI - ボルダータウン",
|
||||
ko: "야릴로-VI - 볼더 타운",
|
||||
ru: "Ярило-VI - Камнеград"
|
||||
},
|
||||
plane_id: 10102,
|
||||
floor_id: 10102001,
|
||||
entry_id: 1010201,
|
||||
@@ -41,8 +70,15 @@ export const PRESET_TELEPORTS = [
|
||||
z: 57320
|
||||
},
|
||||
{
|
||||
name: "Xianzhou Luofu - Central Starskiff Haven (ท่าเรือเรือบินดาวกลาง)",
|
||||
world: "Xianzhou Luofu",
|
||||
names: {
|
||||
th: "Xianzhou Luofu - ท่าเรือเรือบินดาวกลาง (Central Starskiff Haven)",
|
||||
en: "Xianzhou Luofu - Central Starskiff Haven",
|
||||
"zh-CN": "仙舟「罗浮」 - 星槎海中枢",
|
||||
"zh-TW": "仙舟「羅浮」 - 星槎海中樞",
|
||||
ja: "仙舟「羅浮」 - 星槎海中枢",
|
||||
ko: "선주 「나부」 - 별뗏목 바다 중추",
|
||||
ru: "Сяньчжоу: Лофу - Центральная гавань Приюта звёздных яликов"
|
||||
},
|
||||
plane_id: 10202,
|
||||
floor_id: 10202001,
|
||||
entry_id: 1020201,
|
||||
@@ -51,8 +87,15 @@ export const PRESET_TELEPORTS = [
|
||||
z: -25080
|
||||
},
|
||||
{
|
||||
name: "Penacony - The Reverie (Dreamscape Hotel)",
|
||||
world: "Penacony",
|
||||
names: {
|
||||
th: "Penacony - The Reverie (Dreamscape Hotel)",
|
||||
en: "Penacony - The Reverie (Dreamscape)",
|
||||
"zh-CN": "匹诺康尼 - 「白日梦」酒店-梦境",
|
||||
"zh-TW": "匹諾康尼 - 「白日夢」飯店-夢境",
|
||||
ja: "ピノコニー - 「レバリー」ホテル-夢境",
|
||||
ko: "페나코니 - 「레버리」 호텔-꿈속",
|
||||
ru: "Пенакония - Отель «Грёзы» (Мир грёз)"
|
||||
},
|
||||
plane_id: 10301,
|
||||
floor_id: 10301001,
|
||||
entry_id: 1030101,
|
||||
@@ -61,8 +104,15 @@ export const PRESET_TELEPORTS = [
|
||||
z: 0
|
||||
},
|
||||
{
|
||||
name: "Penacony - Golden Hour (ชั่วโมงทอง)",
|
||||
world: "Penacony",
|
||||
names: {
|
||||
th: "Penacony - ชั่วโมงทอง (Golden Hour)",
|
||||
en: "Penacony - Golden Hour",
|
||||
"zh-CN": "匹诺康尼 - 黄金的时刻",
|
||||
"zh-TW": "匹諾康尼 - 黃金的時刻",
|
||||
ja: "ピノコニー - 黄金の刻",
|
||||
ko: "페나코니 - 황금의 순간",
|
||||
ru: "Пенакония - Золотой миг"
|
||||
},
|
||||
plane_id: 10302,
|
||||
floor_id: 10302001,
|
||||
entry_id: 1030201,
|
||||
@@ -71,3 +121,8 @@ export const PRESET_TELEPORTS = [
|
||||
z: -378220
|
||||
}
|
||||
];
|
||||
|
||||
export function getTeleportName(preset, langOverride = null) {
|
||||
const lang = langOverride || getCurrentLanguage();
|
||||
return preset.names?.[lang] || preset.names?.en || preset.names?.th || "Teleport Point";
|
||||
}
|
||||
Reference in new issue
Block a user