feat(settings): replace health check interval with practical presets, ping latency test, battle defaults and cache diagnostics

This commit is contained in:
CAtlas0784 committed 2026-10-17 01:40:58 +07:00
1 parent 1b8d1744b2
commit 1fe36fad43
3 files changed
+433 -66

No files matched your search

+134 -29
View File
@@ -419,38 +419,143 @@
<!-- 8. Settings --> <!-- 8. Settings -->
<section id="tab-settings" class="tab-content"> <section id="tab-settings" class="tab-content">
<div style="max-width: 620px; margin: 0 auto;"> <div style="max-width: 900px; margin: 0 auto; display: flex; flex-direction: column; gap: 1.25rem;">
<!-- Endpoint config -->
<div class="card"> <div class="grid-2">
<div class="card-title" data-i18n="apiSettingsTitle">⚙️ ตั้งค่าการเชื่อมต่อ API Gateway</div> <!-- Card 1: Server & Gateway Connection -->
<p class="card-subtitle" data-i18n="apiSettingsSubtitle">ปรับเปลี่ยนพอร์ตหรือ IP ได้ตามเซิร์ฟเวอร์ที่คุณใช้</p> <div class="card">
<div class="card-title" data-i18n="settingsConnTitle">⚙️ ตั้งค่าการเชื่อมต่อ API Gateway</div>
<p class="card-subtitle" data-i18n="settingsConnSubtitle">กำหนด Endpoint และโหมดของเซิร์ฟเวอร์ที่ต้องการสั่งการ</p>
<form id="form-settings"> <form id="form-settings">
<div class="form-group"> <div class="form-group">
<label class="form-label" data-i18n="lblServerMode">โหมดเซิร์ฟเวอร์</label> <label class="form-label" data-i18n="lblServerMode">โหมดเซิร์ฟเวอร์</label>
<select id="setting-server-mode" class="form-select"> <select id="setting-server-mode" class="form-select">
<option value="gac">GaC-hkrpg-go</option> <option value="gac">GaC-hkrpg-go (Official GaC Server)</option>
<option value="firefly">FireflyGo</option> <option value="firefly">FireflyGo (CBT / FreeSR)</option>
<option value="robin">RobinSR</option> <option value="robin">RobinSR (Proxy Gateway)</option>
</select> </select>
</div>
<div class="form-group">
<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">
<div style="display: flex; gap: 0.35rem; margin-top: 0.5rem; flex-wrap: wrap;">
<button type="button" class="btn btn-sm btn-secondary btn-quick-url" data-url="http://localhost:21000">localhost:21000</button>
<button type="button" class="btn btn-sm btn-secondary btn-quick-url" data-url="http://127.0.0.1:21000">127.0.0.1:21000</button>
<button type="button" class="btn btn-sm btn-secondary btn-quick-url" data-url="http://localhost:8080">localhost:8080</button>
</div>
</div>
<div style="display: flex; gap: 0.5rem; margin-top: 1.25rem;">
<button type="button" class="btn btn-secondary" id="btn-test-connection" style="display: flex; align-items: center; gap: 0.4rem;">
<span data-i18n="btnTestPing">⚡ ทดสอบการเชื่อมต่อ</span>
<span id="ping-latency-badge" class="badge-super-tag" style="display: none; padding: 0.1rem 0.45rem; font-size: 0.75rem;">-</span>
</button>
<button type="submit" class="btn btn-success" style="flex: 1;" data-i18n="btnSaveSettings">💾 บันทึกการตั้งค่า</button>
</div>
</form>
</div>
<!-- Card 2: Battle & Gameplay Preferences -->
<div class="card">
<div class="card-title" data-i18n="settingsBattleTitle">🎮 ค่าเริ่มต้นการต่อสู้ & FreeSR</div>
<p class="card-subtitle" data-i18n="settingsBattleSubtitle">ปรับแต่งพฤติกรรมเริ่มต้นของระบบในเกมและการจัดทีม</p>
<div style="display: flex; flex-direction: column; gap: 1rem;">
<!-- Default Energy -->
<div class="form-group" style="margin-bottom: 0;">
<label class="form-label" data-i18n="lblDefaultEnergy">พลังงานเริ่มต้นของทีม (Battle Starting Energy)</label>
<div style="display: flex; gap: 0.4rem; flex-wrap: wrap; margin-top: 0.35rem;">
<button type="button" class="btn btn-sm btn-primary btn-setting-energy active" data-energy="50">⚡ 50% (มาตรฐานเกม)</button>
<button type="button" class="btn btn-sm btn-secondary btn-setting-energy" data-energy="100">🔥 100% (อัลติพร้อมใช้)</button>
<button type="button" class="btn btn-sm btn-secondary btn-setting-energy" data-energy="0">❄️ 0% (ท้าทาย)</button>
</div>
</div>
<!-- Auto-Sync Toggle -->
<div style="display: flex; justify-content: space-between; align-items: center; padding-top: 0.75rem; border-top: 1px solid var(--border-color);">
<div>
<div style="font-weight: 700; font-size: 0.9rem;" data-i18n="lblAutoSync">ซิงค์ไปยังเซิร์ฟเวอร์อัตโนมัติ (Auto-Sync)</div>
<div style="font-size: 0.75rem; color: var(--text-muted);" data-i18n="descAutoSync">ส่งการเปลี่ยนแปลงไปยังเซิร์ฟเวอร์ทันทีเมื่อแก้ไขตัวละครหรือไอเทม</div>
</div>
<label class="switch">
<input type="checkbox" id="setting-auto-sync" checked>
<span class="slider"></span>
</label>
</div>
<!-- Creative Mode Default -->
<div style="display: flex; justify-content: space-between; align-items: center; padding-top: 0.75rem; border-top: 1px solid var(--border-color);">
<div>
<div style="font-weight: 700; font-size: 0.9rem;" data-i18n="lblDefaultCreative">เปิดโหมดสร้างสรรค์เมื่อเริ่มต้น (Creative Mode)</div>
<div style="font-size: 0.75rem; color: var(--text-muted);" data-i18n="descDefaultCreative">อนุญาตให้ใส่ตัวละครซ้ำหรือจัดทีมได้มากกว่า 4 ช่องตลอดเวลา</div>
</div>
<label class="switch">
<input type="checkbox" id="setting-default-creative">
<span class="slider"></span>
</label>
</div>
</div> </div>
<div class="form-group"> </div>
<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;">
* พอร์ตเริ่มต้น 21000 สำหรับ SDK server
</small>
</div>
<div class="form-group">
<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;" data-i18n="btnSaveSettings">💾 บันทึกการตั้งค่า</button>
<button type="button" class="btn btn-secondary" id="btn-reset-settings" data-i18n="btnResetDefault">คืนค่าเริ่มต้น</button>
</div>
</form>
</div> </div>
<div class="grid-2">
<!-- Card 3: Showcase Card Display Settings -->
<div class="card">
<div class="card-title" data-i18n="settingsShowcaseTitle">🖼️ การแสดงผลการ์ด Showcase</div>
<p class="card-subtitle" data-i18n="settingsShowcaseSubtitle">ปรับแต่งความสวยงามและรายละเอียดในหน้าการ์ดแสดงผล Build</p>
<div style="display: flex; flex-direction: column; gap: 0.85rem;">
<!-- Show Roll Counts on Relics -->
<div style="display: flex; justify-content: space-between; align-items: center;">
<div>
<div style="font-weight: 700; font-size: 0.9rem;" data-i18n="lblShowRolls">แสดงจำนวน Roll ของซับสเตตัสรีลิกส์</div>
<div style="font-size: 0.75rem; color: var(--text-muted);" data-i18n="descShowRolls">แสดงแท็กจำนวนครั้งที่สุ่มลงสเตตัสย่อย (Sub-stat Roll Counts)</div>
</div>
<label class="switch">
<input type="checkbox" id="setting-showcase-rolls" checked>
<span class="slider"></span>
</label>
</div>
<!-- Dynamic Element Aura Glow -->
<div style="display: flex; justify-content: space-between; align-items: center; padding-top: 0.75rem; border-top: 1px solid var(--border-color);">
<div>
<div style="font-weight: 700; font-size: 0.9rem;" data-i18n="lblElementAura">เอฟเฟกต์แสงเรืองตามธาตุ (Element Aura Glow)</div>
<div style="font-size: 0.75rem; color: var(--text-muted);" data-i18n="descElementAura">เปลี่ยนสีพื้นหลังและการเรืองแสงของการ์ดตามธาตุของตัวละครนั้นๆ</div>
</div>
<label class="switch">
<input type="checkbox" id="setting-showcase-aura" checked>
<span class="slider"></span>
</label>
</div>
</div>
</div>
<!-- Card 4: Diagnostics & Cache Reset -->
<div class="card">
<div class="card-title" data-i18n="settingsCacheTitle">🧹 จัดการข้อมูลแคช & รีเซ็ตระบบ</div>
<p class="card-subtitle" data-i18n="settingsCacheSubtitle">ล้างข้อมูลชั่วคราวในเบราว์เซอร์หรือคืนค่าเครื่องมือเป็นค่าเริ่มต้น</p>
<div style="display: flex; flex-direction: column; gap: 0.75rem;">
<div style="display: flex; justify-content: space-between; align-items: center; font-size: 0.85rem;">
<span style="color: var(--text-muted);" data-i18n="lblCacheSize">สถานะหน่วยความจำ LocalStorage:</span>
<strong id="lbl-cache-usage" style="color: var(--accent-cyan); font-family: monospace;">ตรวจวัด...</strong>
</div>
<div style="display: flex; gap: 0.75rem; margin-top: 0.5rem; flex-wrap: wrap;">
<button type="button" class="btn btn-secondary" id="btn-clear-browser-cache" style="flex: 1; min-width: 140px;" data-i18n="btnClearCache">
🧹 ล้างแคชเบราว์เซอร์
</button>
<button type="button" class="btn btn-danger" id="btn-reset-settings" style="flex: 1; min-width: 140px;" data-i18n="btnFactoryReset">
🔄 คืนค่าเริ่มต้นทั้งหมด
</button>
</div>
</div>
</div>
</div>
</div> </div>
</section> </section>
+247 -31
View File
@@ -6,7 +6,7 @@ import { SUPPORTED_LANGUAGES, TRANSLATIONS, getCurrentLanguage, setLanguage, t,
const state = { const state = {
serverMode: localStorage.getItem('gac_srtool_mode') || 'gac', // 'gac' | 'firefly' | 'robin' serverMode: localStorage.getItem('gac_srtool_mode') || 'gac', // 'gac' | 'firefly' | 'robin'
apiUrl: localStorage.getItem('gac_srtool_api_url') || 'http://localhost:21000', apiUrl: localStorage.getItem('gac_srtool_api_url') || 'http://localhost:21000',
pingIntervalSec: parseInt(localStorage.getItem('gac_srtool_ping_interval') || '10', 10), pingIntervalSec: 10,
isConnected: false, isConnected: false,
statusData: null, statusData: null,
avatarsList: [], avatarsList: [],
@@ -16,7 +16,12 @@ const state = {
activeTab: 'tab-dashboard', activeTab: 'tab-dashboard',
selectedLineupSlot: null, selectedLineupSlot: null,
selectedAvatarDetail: null, selectedAvatarDetail: null,
creativeMode: localStorage.getItem('gac_srtool_creative_mode') === 'true' creativeMode: localStorage.getItem('gac_srtool_creative_mode') === 'true' || localStorage.getItem('gac_srtool_default_creative') === 'true',
defaultEnergy: parseInt(localStorage.getItem('gac_srtool_default_energy') || '50', 10),
autoSync: localStorage.getItem('gac_srtool_auto_sync') !== 'false',
defaultCreative: localStorage.getItem('gac_srtool_default_creative') === 'true',
showcaseRolls: localStorage.getItem('gac_srtool_showcase_rolls') !== 'false',
showcaseAura: localStorage.getItem('gac_srtool_showcase_aura') !== 'false'
}; };
// UI Elements Map // UI Elements Map
@@ -117,7 +122,14 @@ const el = {
// Settings // Settings
formSettings: document.getElementById('form-settings'), formSettings: document.getElementById('form-settings'),
settingApiUrl: document.getElementById('setting-api-url'), settingApiUrl: document.getElementById('setting-api-url'),
settingPingInterval: document.getElementById('setting-ping-interval'), btnTestConnection: document.getElementById('btn-test-connection'),
pingLatencyBadge: document.getElementById('ping-latency-badge'),
settingAutoSync: document.getElementById('setting-auto-sync'),
settingDefaultCreative: document.getElementById('setting-default-creative'),
settingShowcaseRolls: document.getElementById('setting-showcase-rolls'),
settingShowcaseAura: document.getElementById('setting-showcase-aura'),
lblCacheUsage: document.getElementById('lbl-cache-usage'),
btnClearBrowserCache: document.getElementById('btn-clear-browser-cache'),
btnResetSettings: document.getElementById('btn-reset-settings'), btnResetSettings: document.getElementById('btn-reset-settings'),
// Character Detail Modal // Character Detail Modal
@@ -1830,6 +1842,10 @@ function renderShowcaseCard(avatarId) {
6: { name: "สร้อย", stat: meta.path === 'Preservation' || meta.path === 'Harmony' ? "ERR 19.4%" : "ATK 43.2%" } 6: { name: "สร้อย", stat: meta.path === 'Preservation' || meta.path === 'Harmony' ? "ERR 19.4%" : "ATK 43.2%" }
}; };
const showRolls = localStorage.getItem('gac_srtool_showcase_rolls') !== 'false';
const showAura = localStorage.getItem('gac_srtool_showcase_aura') !== 'false';
const rollBadge = (rolls) => showRolls ? `<span style="display:inline-block; font-size:0.65rem; color:var(--accent-gold); font-weight:800; background:rgba(234,179,8,0.18); border-radius:3px; padding:0 3px; margin-left:3px;">+${rolls}</span>` : '';
let relicsHtml = ''; let relicsHtml = '';
for (let slot = 1; slot <= 6; slot++) { for (let slot = 1; slot <= 6; slot++) {
const equipped = avatarRelics.find(r => (r.relic_id % 10 === slot)); const equipped = avatarRelics.find(r => (r.relic_id % 10 === slot));
@@ -1850,10 +1866,10 @@ function renderShowcaseCard(avatarId) {
<span style="color: var(--accent-cyan); font-weight: 800;">${slotInfo.stat}</span> <span style="color: var(--accent-cyan); font-weight: 800;">${slotInfo.stat}</span>
</div> </div>
<div class="showcase-relic-subs"> <div class="showcase-relic-subs">
<span>CRIT Rate +${(3.2 + slot * 1.5).toFixed(1)}%</span> <span>CRIT Rate +${(3.2 + slot * 1.5).toFixed(1)}%${rollBadge(slot % 2 === 0 ? 3 : 2)}</span>
<span>CRIT DMG +${(5.8 + slot * 2.1).toFixed(1)}%</span> <span>CRIT DMG +${(5.8 + slot * 2.1).toFixed(1)}%${rollBadge(slot % 3 === 0 ? 4 : 2)}</span>
<span>ATK +${(3.8 + slot * 0.8).toFixed(1)}%</span> <span>ATK +${(3.8 + slot * 0.8).toFixed(1)}%${rollBadge(1)}</span>
<span>DEF +${(4.8 + slot * 1.2).toFixed(1)}%</span> <span>DEF +${(4.8 + slot * 1.2).toFixed(1)}%${rollBadge(1)}</span>
</div> </div>
</div> </div>
</div> </div>
@@ -1929,6 +1945,36 @@ function renderShowcaseCard(avatarId) {
${relicsHtml} ${relicsHtml}
</div> </div>
`; `;
// Apply Element Aura Glow
const auraGlows = {
Physical: 'linear-gradient(135deg, rgba(30, 41, 59, 0.95) 0%, rgba(15, 23, 42, 0.98) 100%)',
Fire: 'linear-gradient(135deg, rgba(79, 15, 15, 0.95) 0%, rgba(15, 23, 42, 0.98) 100%)',
Ice: 'linear-gradient(135deg, rgba(12, 74, 96, 0.95) 0%, rgba(15, 23, 42, 0.98) 100%)',
Lightning: 'linear-gradient(135deg, rgba(68, 15, 110, 0.95) 0%, rgba(15, 23, 42, 0.98) 100%)',
Wind: 'linear-gradient(135deg, rgba(6, 78, 59, 0.95) 0%, rgba(15, 23, 42, 0.98) 100%)',
Quantum: 'linear-gradient(135deg, rgba(49, 46, 129, 0.95) 0%, rgba(15, 23, 42, 0.98) 100%)',
Imaginary: 'linear-gradient(135deg, rgba(88, 40, 5, 0.95) 0%, rgba(15, 23, 42, 0.98) 100%)'
};
const auraBorders = {
Physical: 'rgba(203, 213, 225, 0.35)',
Fire: 'rgba(239, 68, 68, 0.45)',
Ice: 'rgba(56, 189, 248, 0.45)',
Lightning: 'rgba(168, 85, 247, 0.45)',
Wind: 'rgba(52, 211, 153, 0.45)',
Quantum: 'rgba(129, 140, 248, 0.45)',
Imaginary: 'rgba(251, 191, 36, 0.45)'
};
if (showAura && auraGlows[meta.element]) {
el.showcaseCardContainer.style.background = auraGlows[meta.element];
el.showcaseCardContainer.style.borderColor = auraBorders[meta.element] || 'var(--border-color)';
el.showcaseCardContainer.style.boxShadow = `0 10px 40px -10px ${auraBorders[meta.element] || 'rgba(0,0,0,0.5)'}`;
} else {
el.showcaseCardContainer.style.background = 'linear-gradient(135deg, #0d121f 0%, #171f30 100%)';
el.showcaseCardContainer.style.borderColor = 'var(--border-color)';
el.showcaseCardContainer.style.boxShadow = '0 10px 30px rgba(0,0,0,0.5)';
}
} }
// Auto-equip recommended 6-piece relics for avatar // Auto-equip recommended 6-piece relics for avatar
@@ -2843,6 +2889,24 @@ async function saveJsonData() {
} }
} }
// Cache Usage Status for Diagnostics
function updateCacheUsageDisplay() {
if (!el.lblCacheUsage) return;
try {
let totalBytes = 0;
for (let key in localStorage) {
if (Object.prototype.hasOwnProperty.call(localStorage, key)) {
totalBytes += (localStorage[key].length + key.length) * 2;
}
}
const kb = (totalBytes / 1024).toFixed(1);
const count = Object.keys(localStorage).length;
el.lblCacheUsage.textContent = `${kb} KB (${count} keys)`;
} catch (err) {
el.lblCacheUsage.textContent = 'ไม่สามารถตรวจสอบได้';
}
}
// Tab Switching // Tab Switching
function setupTabs() { function setupTabs() {
const tabs = document.querySelectorAll('.tab-btn'); const tabs = document.querySelectorAll('.tab-btn');
@@ -2867,6 +2931,8 @@ function setupTabs() {
loadPersistentSettings(); loadPersistentSettings();
} else if (targetId === 'tab-json') { } else if (targetId === 'tab-json') {
loadJsonData(state.currentJsonMode); loadJsonData(state.currentJsonMode);
} else if (targetId === 'tab-settings') {
updateCacheUsageDisplay();
} }
} }
}); });
@@ -3222,33 +3288,183 @@ function setupEvents() {
reader.readAsText(file); reader.readAsText(file);
}); });
// Settings Form // -------------------------------------------------------------
el.settingApiUrl.value = state.apiUrl; // Settings Tab Controls & Diagnostics
el.settingPingInterval.value = state.pingIntervalSec; // -------------------------------------------------------------
if (el.settingApiUrl) {
el.formSettings.addEventListener('submit', (e) => {
e.preventDefault();
state.apiUrl = el.settingApiUrl.value.trim();
state.pingIntervalSec = parseInt(el.settingPingInterval.value, 10) || 10;
localStorage.setItem('gac_srtool_api_url', state.apiUrl);
localStorage.setItem('gac_srtool_ping_interval', state.pingIntervalSec);
showToast(t('settingsSaved'), 'success');
refreshStatus();
});
el.btnResetSettings.addEventListener('click', () => {
state.apiUrl = 'http://localhost:21000';
state.pingIntervalSec = 10;
el.settingApiUrl.value = state.apiUrl; el.settingApiUrl.value = state.apiUrl;
el.settingPingInterval.value = state.pingIntervalSec; }
localStorage.removeItem('gac_srtool_api_url');
localStorage.removeItem('gac_srtool_ping_interval'); // Quick URL Preset Chips
showToast(t('settingsReset'), 'info'); document.querySelectorAll('.btn-quick-url').forEach(btn => {
refreshStatus(); btn.addEventListener('click', () => {
if (el.settingApiUrl) {
el.settingApiUrl.value = btn.dataset.url;
showToast(`เลือก Endpoint: ${btn.dataset.url}`, 'info');
}
});
}); });
// Ping Latency Test
if (el.btnTestConnection) {
el.btnTestConnection.addEventListener('click', async () => {
const targetUrl = (el.settingApiUrl?.value || state.apiUrl).trim().replace(/\/+$/, '');
if (el.pingLatencyBadge) {
el.pingLatencyBadge.style.display = 'inline-block';
el.pingLatencyBadge.textContent = '⏳ ...';
el.pingLatencyBadge.style.backgroundColor = 'var(--bg-card)';
el.pingLatencyBadge.style.color = 'var(--text-muted)';
}
const t0 = performance.now();
try {
const res = await fetch(`${targetUrl}/api/status`, { signal: AbortSignal.timeout(3500) });
if (!res.ok) throw new Error(`HTTP ${res.status}`);
const latency = Math.round(performance.now() - t0);
if (el.pingLatencyBadge) {
el.pingLatencyBadge.textContent = `${latency} ms`;
el.pingLatencyBadge.style.backgroundColor = latency < 80 ? 'rgba(34, 197, 94, 0.2)' : 'rgba(234, 179, 8, 0.2)';
el.pingLatencyBadge.style.color = latency < 80 ? 'var(--accent-green)' : 'var(--accent-gold)';
}
showToast(t('toastPingSuccess', { ms: latency }), 'success');
setConnectionStatus(true);
} catch (err) {
if (el.pingLatencyBadge) {
el.pingLatencyBadge.textContent = 'ERR';
el.pingLatencyBadge.style.backgroundColor = 'rgba(239, 68, 68, 0.2)';
el.pingLatencyBadge.style.color = '#ef4444';
}
showToast(t('toastPingFailed'), 'error');
setConnectionStatus(false);
}
});
}
// Save Connection Settings
if (el.formSettings) {
el.formSettings.addEventListener('submit', (e) => {
e.preventDefault();
state.apiUrl = el.settingApiUrl.value.trim().replace(/\/+$/, '') || 'http://localhost:21000';
localStorage.setItem('gac_srtool_api_url', state.apiUrl);
showToast(t('settingsSaved'), 'success');
refreshStatus();
});
}
// Battle Starting Energy Presets
const curEnergy = localStorage.getItem('gac_srtool_default_energy') || '50';
document.querySelectorAll('.btn-setting-energy').forEach(btn => {
if (btn.dataset.energy === curEnergy) {
btn.classList.add('active', 'btn-primary');
btn.classList.remove('btn-secondary');
} else {
btn.classList.remove('active', 'btn-primary');
btn.classList.add('btn-secondary');
}
btn.addEventListener('click', () => {
document.querySelectorAll('.btn-setting-energy').forEach(b => {
b.classList.remove('active', 'btn-primary');
b.classList.add('btn-secondary');
});
btn.classList.add('active', 'btn-primary');
btn.classList.remove('btn-secondary');
localStorage.setItem('gac_srtool_default_energy', btn.dataset.energy);
state.defaultEnergy = parseInt(btn.dataset.energy, 10);
showToast(`ตั้งค่าพลังงานเริ่มต้น: ${btn.dataset.energy}%`, 'info');
});
});
// Auto-Sync Toggle
if (el.settingAutoSync) {
el.settingAutoSync.checked = localStorage.getItem('gac_srtool_auto_sync') !== 'false';
el.settingAutoSync.addEventListener('change', (e) => {
localStorage.setItem('gac_srtool_auto_sync', e.target.checked);
state.autoSync = e.target.checked;
});
}
// Creative Mode by Default Toggle
if (el.settingDefaultCreative) {
el.settingDefaultCreative.checked = localStorage.getItem('gac_srtool_default_creative') === 'true';
el.settingDefaultCreative.addEventListener('change', (e) => {
const val = e.target.checked;
localStorage.setItem('gac_srtool_default_creative', val);
state.defaultCreative = val;
if (val && !state.creativeMode) {
state.creativeMode = true;
localStorage.setItem('gac_srtool_creative_mode', 'true');
if (el.toggleCreativeMode) el.toggleCreativeMode.checked = true;
if (el.badgeCreativeMode) el.badgeCreativeMode.style.display = 'inline-flex';
renderLineup(state.statusData?.lineups);
}
});
}
// Showcase Sub-stat Rolls Toggle
if (el.settingShowcaseRolls) {
el.settingShowcaseRolls.checked = localStorage.getItem('gac_srtool_showcase_rolls') !== 'false';
el.settingShowcaseRolls.addEventListener('change', (e) => {
localStorage.setItem('gac_srtool_showcase_rolls', e.target.checked);
state.showcaseRolls = e.target.checked;
if (state.selectedAvatarDetail?.avatar_id) {
renderShowcaseCard(state.selectedAvatarDetail.avatar_id);
}
});
}
// Showcase Element Aura Glow Toggle
if (el.settingShowcaseAura) {
el.settingShowcaseAura.checked = localStorage.getItem('gac_srtool_showcase_aura') !== 'false';
el.settingShowcaseAura.addEventListener('change', (e) => {
localStorage.setItem('gac_srtool_showcase_aura', e.target.checked);
state.showcaseAura = e.target.checked;
if (state.selectedAvatarDetail?.avatar_id) {
renderShowcaseCard(state.selectedAvatarDetail.avatar_id);
}
});
}
// Clear Browser Cache Button
if (el.btnClearBrowserCache) {
el.btnClearBrowserCache.addEventListener('click', () => {
const keepUrl = localStorage.getItem('gac_srtool_api_url');
const keepMode = localStorage.getItem('gac_srtool_mode');
const keepLang = localStorage.getItem('gac_srtool_lang');
localStorage.clear();
if (keepUrl) localStorage.setItem('gac_srtool_api_url', keepUrl);
if (keepMode) localStorage.setItem('gac_srtool_mode', keepMode);
if (keepLang) localStorage.setItem('gac_srtool_lang', keepLang);
updateCacheUsageDisplay();
showToast(t('toastCacheCleared'), 'success');
});
}
// Factory Reset Button
if (el.btnResetSettings) {
el.btnResetSettings.addEventListener('click', () => {
localStorage.clear();
state.apiUrl = 'http://localhost:21000';
state.serverMode = 'gac';
state.creativeMode = false;
state.defaultEnergy = 50;
state.autoSync = true;
state.showcaseRolls = true;
state.showcaseAura = true;
if (el.settingApiUrl) el.settingApiUrl.value = state.apiUrl;
if (el.settingServerMode) el.settingServerMode.value = 'gac';
if (el.settingAutoSync) el.settingAutoSync.checked = true;
if (el.settingDefaultCreative) el.settingDefaultCreative.checked = false;
if (el.settingShowcaseRolls) el.settingShowcaseRolls.checked = true;
if (el.settingShowcaseAura) el.settingShowcaseAura.checked = true;
if (el.toggleCreativeMode) el.toggleCreativeMode.checked = false;
if (el.badgeCreativeMode) el.badgeCreativeMode.style.display = 'none';
updateCacheUsageDisplay();
showToast(t('settingsReset'), 'info');
refreshStatus();
});
}
updateCacheUsageDisplay();
// Modal Backdrop Click to close // Modal Backdrop Click to close
[el.modalAvatarDetail, el.modalLineupPicker, el.modalSettings].forEach(modal => { [el.modalAvatarDetail, el.modalLineupPicker, el.modalSettings].forEach(modal => {
if (modal) { if (modal) {
+52 -6
View File
@@ -158,13 +158,36 @@ export const TRANSLATIONS = {
"jsonStatusOpening": "กำลังเปิด: {name}", "jsonStatusOpening": "กำลังเปิด: {name}",
"jsonSaveSuccess": "บันทึกไฟล์ {name} เรียบร้อยแล้ว", "jsonSaveSuccess": "บันทึกไฟล์ {name} เรียบร้อยแล้ว",
"jsonInvalid": "รูปแบบ JSON ไม่ถูกต้อง", "jsonInvalid": "รูปแบบ JSON ไม่ถูกต้อง",
"apiSettingsTitle": "⚙️ ตั้งค่าการเชื่อมต่อ API Gateway", "settingsConnTitle": "⚙️ ตั้งค่าการเชื่อมต่อ API Gateway",
"apiSettingsSubtitle": "ปรับเปลี่ยนพอร์ตหรือ IP ได้ตามไฟล์ server.json ของคุณ", "settingsConnSubtitle": "กำหนด Endpoint และโหมดของเซิร์ฟเวอร์ที่ต้องการสั่งการ",
"lblServerMode": "โหมดเซิร์ฟเวอร์", "lblServerMode": "โหมดเซิร์ฟเวอร์",
"lblApiGatewayUrl": "REST API Gateway URL", "lblApiGatewayUrl": "REST API Gateway URL",
"lblPingInterval": "ความถี่ในการตรวจสอบสถานะ (วินาที)", "btnTestPing": "⚡ ทดสอบการเชื่อมต่อ",
"btnSaveSettings": "💾 บันทึกการตั้งค่า", "btnSaveSettings": "💾 บันทึกการตั้งค่า",
"btnResetDefault": "คืนค่าเริ่มต้น", "btnResetDefault": "คืนค่าเริ่มต้น",
"settingsBattleTitle": "🎮 ค่าเริ่มต้นการต่อสู้ & FreeSR",
"settingsBattleSubtitle": "ปรับแต่งพฤติกรรมเริ่มต้นของระบบในเกมและการจัดทีม",
"lblDefaultEnergy": "พลังงานเริ่มต้นของทีม (Battle Starting Energy)",
"lblAutoSync": "ซิงค์ไปยังเซิร์ฟเวอร์อัตโนมัติ (Auto-Sync)",
"descAutoSync": "ส่งการเปลี่ยนแปลงไปยังเซิร์ฟเวอร์ทันทีเมื่อแก้ไขตัวละครหรือไอเทม",
"lblDefaultCreative": "เปิดโหมดสร้างสรรค์เมื่อเริ่มต้น (Creative Mode)",
"descDefaultCreative": "อนุญาตให้ใส่ตัวละครซ้ำหรือจัดทีมได้มากกว่า 4 ช่องตลอดเวลา",
"settingsShowcaseTitle": "🖼️ การแสดงผลการ์ด Showcase",
"settingsShowcaseSubtitle": "ปรับแต่งความสวยงามและรายละเอียดในหน้าการ์ดแสดงผล Build",
"lblShowRolls": "แสดงจำนวน Roll ของซับสเตตัสรีลิกส์",
"descShowRolls": "แสดงแท็กจำนวนครั้งที่สุ่มลงสเตตัสย่อย (Sub-stat Roll Counts)",
"lblElementAura": "เอฟเฟกต์แสงเรืองตามธาตุ (Element Aura Glow)",
"descElementAura": "เปลี่ยนสีพื้นหลังและการเรืองแสงของการ์ดตามธาตุของตัวละครนั้นๆ",
"settingsCacheTitle": "🧹 จัดการข้อมูลแคช & รีเซ็ตระบบ",
"settingsCacheSubtitle": "ล้างข้อมูลชั่วคราวในเบราว์เซอร์หรือคืนค่าเครื่องมือเป็นค่าเริ่มต้น",
"lblCacheSize": "สถานะหน่วยความจำ LocalStorage:",
"btnClearCache": "🧹 ล้างแคชเบราว์เซอร์",
"btnFactoryReset": "🔄 คืนค่าเริ่มต้นทั้งหมด",
"toastPingSuccess": "⚡ เชื่อมต่อสำเร็จ! Latency: {ms} ms",
"toastPingFailed": "❌ ไม่สามารถเชื่อมต่อกับ Gateway ได้ กรุณาตรวจสอบเซิร์ฟเวอร์",
"toastCacheCleared": "🧹 ล้างข้อมูลแคชเบราว์เซอร์เรียบร้อยแล้ว",
"apiSettingsTitle": "⚙️ ตั้งค่าการเชื่อมต่อ API Gateway",
"apiSettingsSubtitle": "ปรับเปลี่ยนพอร์ตหรือ IP ได้ตามไฟล์ server.json ของคุณ",
"modalTitleCharEdit": "ปรับแต่งตัวละคร", "modalTitleCharEdit": "ปรับแต่งตัวละคร",
"modalBtnMaxAllChar": "⭐ ปรับเต็มทั้งหมด", "modalBtnMaxAllChar": "⭐ ปรับเต็มทั้งหมด",
"modalTabSkills": "⚡ สกิลและร่องรอย", "modalTabSkills": "⚡ สกิลและร่องรอย",
@@ -387,13 +410,36 @@ export const TRANSLATIONS = {
"jsonStatusOpening": "Opening: {name}", "jsonStatusOpening": "Opening: {name}",
"jsonSaveSuccess": "File {name} saved successfully", "jsonSaveSuccess": "File {name} saved successfully",
"jsonInvalid": "Invalid JSON format", "jsonInvalid": "Invalid JSON format",
"apiSettingsTitle": "⚙️ API Gateway Connection Settings", "settingsConnTitle": "⚙️ API Gateway Connection",
"apiSettingsSubtitle": "Adjust port or IP according to your server.json", "settingsConnSubtitle": "Configure server mode and REST endpoint",
"lblServerMode": "Server Mode", "lblServerMode": "Server Mode",
"lblApiGatewayUrl": "REST API Gateway URL", "lblApiGatewayUrl": "REST API Gateway URL",
"lblPingInterval": "Health Check Interval (seconds)", "btnTestPing": "⚡ Test Connection",
"btnSaveSettings": "💾 Save Settings", "btnSaveSettings": "💾 Save Settings",
"btnResetDefault": "Reset Defaults", "btnResetDefault": "Reset Defaults",
"settingsBattleTitle": "🎮 Battle & FreeSR Defaults",
"settingsBattleSubtitle": "Customize gameplay behavior and lineup defaults",
"lblDefaultEnergy": "Battle Starting Energy",
"lblAutoSync": "Auto-Sync to Server",
"descAutoSync": "Instantly send character and equipment updates to the server",
"lblDefaultCreative": "Creative Mode by Default",
"descDefaultCreative": "Allow duplicate characters and more than 4 lineup slots",
"settingsShowcaseTitle": "🖼️ Showcase Card Display",
"settingsShowcaseSubtitle": "Customize character build card styling and details",
"lblShowRolls": "Show Sub-stat Roll Counts",
"descShowRolls": "Display roll tags for relic sub-affixes",
"lblElementAura": "Element Aura Glow Effect",
"descElementAura": "Dynamic card background and ambient glow matching character element",
"settingsCacheTitle": "🧹 Cache Management & Reset",
"settingsCacheSubtitle": "Clear temporary browser data or restore default settings",
"lblCacheSize": "LocalStorage Memory Usage:",
"btnClearCache": "🧹 Clear Browser Cache",
"btnFactoryReset": "🔄 Factory Reset",
"toastPingSuccess": "⚡ Connected successfully! Latency: {ms} ms",
"toastPingFailed": "❌ Failed to connect to Gateway. Please check server status",
"toastCacheCleared": "🧹 Browser cache cleared successfully",
"apiSettingsTitle": "⚙️ API Gateway Connection Settings",
"apiSettingsSubtitle": "Adjust port or IP according to your server.json",
"modalTitleCharEdit": "Character Customization", "modalTitleCharEdit": "Character Customization",
"modalBtnMaxAllChar": "⭐ Max All", "modalBtnMaxAllChar": "⭐ Max All",
"modalTabSkills": "⚡ Skills & Traces", "modalTabSkills": "⚡ Skills & Traces",