feat: fix multilingual element/path icons, sort avatars descending, add LC & Relic creators for freesr, and add Aha global toggle
This commit is contained in:
1 parent
6438b86450
commit
29a78b4e10
4 files changed
+683
-20
No files matched your search
+118
-6
@@ -187,9 +187,12 @@
|
|||||||
<div class="grid-2">
|
<div class="grid-2">
|
||||||
<!-- Lightcones Card -->
|
<!-- Lightcones Card -->
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<div class="card-title">
|
<div class="card-title" style="display: flex; justify-content: space-between; align-items: center;">
|
||||||
<span data-i18n="eqLcTitle">🗡️ กรวยแสงในคลัง</span>
|
<div style="display: flex; align-items: center; gap: 0.5rem;">
|
||||||
<span class="btn-sm btn-secondary" id="badge-total-lc">0 ชิ้น</span>
|
<span data-i18n="eqLcTitle">🗡️ กรวยแสงในคลัง</span>
|
||||||
|
<span class="btn-sm btn-secondary" id="badge-total-lc">0 ชิ้น</span>
|
||||||
|
</div>
|
||||||
|
<button type="button" class="btn btn-sm btn-primary" id="btn-open-add-lc" data-i18n="btnAddLc">+ เพิ่ม LC</button>
|
||||||
</div>
|
</div>
|
||||||
<p class="card-subtitle" data-i18n="eqLcSubtitle">รายการกรวยแสงทั้งหมดจาก freesr-data.json</p>
|
<p class="card-subtitle" data-i18n="eqLcSubtitle">รายการกรวยแสงทั้งหมดจาก freesr-data.json</p>
|
||||||
<div id="lightcones-list" style="max-height: 520px; overflow-y: auto; display: flex; flex-direction: column; gap: 0.6rem;">
|
<div id="lightcones-list" style="max-height: 520px; overflow-y: auto; display: flex; flex-direction: column; gap: 0.6rem;">
|
||||||
@@ -199,9 +202,12 @@
|
|||||||
|
|
||||||
<!-- Relics Card -->
|
<!-- Relics Card -->
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<div class="card-title">
|
<div class="card-title" style="display: flex; justify-content: space-between; align-items: center;">
|
||||||
<span data-i18n="eqRelicTitle">🛡️ รีลิกส์ในคลัง</span>
|
<div style="display: flex; align-items: center; gap: 0.5rem;">
|
||||||
<span class="btn-sm btn-secondary" id="badge-total-relics">0 ชิ้น</span>
|
<span data-i18n="eqRelicTitle">🛡️ รีลิกส์ในคลัง</span>
|
||||||
|
<span class="btn-sm btn-secondary" id="badge-total-relics">0 ชิ้น</span>
|
||||||
|
</div>
|
||||||
|
<button type="button" class="btn btn-sm btn-primary" id="btn-open-add-relic" data-i18n="btnAddRelic">+ เพิ่มรีลิกส์</button>
|
||||||
</div>
|
</div>
|
||||||
<p class="card-subtitle" data-i18n="eqRelicSubtitle">รายการรีลิกส์ทั้งหมดจาก freesr-data.json</p>
|
<p class="card-subtitle" data-i18n="eqRelicSubtitle">รายการรีลิกส์ทั้งหมดจาก freesr-data.json</p>
|
||||||
<div id="relics-list" style="max-height: 520px; overflow-y: auto; display: flex; flex-direction: column; gap: 0.6rem;">
|
<div id="relics-list" style="max-height: 520px; overflow-y: auto; display: flex; flex-direction: column; gap: 0.6rem;">
|
||||||
@@ -282,6 +288,17 @@
|
|||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="ex-switch-card">
|
||||||
|
<div>
|
||||||
|
<div style="font-weight: 700;">Aeon ★ Aha Global Feature</div>
|
||||||
|
<div style="font-size: 0.8rem; color: var(--text-muted);" data-i18n="ahaGlobalDesc">เปิดใช้งานฟังก์ชันพิเศษ Aeon ★ Aha ทั่วทั้งเซิร์ฟเวอร์</div>
|
||||||
|
</div>
|
||||||
|
<label class="switch">
|
||||||
|
<input type="checkbox" id="toggle-aha-global">
|
||||||
|
<span class="slider"></span>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
<button class="btn btn-success" id="btn-save-persistent-toggles" data-i18n="btnSaveGlobalSwitch">
|
<button class="btn btn-success" id="btn-save-persistent-toggles" data-i18n="btnSaveGlobalSwitch">
|
||||||
💾 บันทึกสวิตช์ Global
|
💾 บันทึกสวิตช์ Global
|
||||||
</button>
|
</button>
|
||||||
@@ -653,6 +670,101 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Add Light Cone Modal -->
|
||||||
|
<div class="modal-overlay" id="modal-add-lc">
|
||||||
|
<div class="modal-content" style="max-width: 540px;">
|
||||||
|
<div class="modal-header">
|
||||||
|
<h3 style="font-weight: 800;" data-i18n="modalAddLcTitle">🗡️ เพิ่มกรวยแสงลง FreeSR</h3>
|
||||||
|
<button type="button" class="btn btn-sm btn-secondary" id="btn-close-add-lc-modal">✕</button>
|
||||||
|
</div>
|
||||||
|
<form id="form-add-lc">
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="form-label" data-i18n="lblSelectLc">เลือกกรวยแสง</label>
|
||||||
|
<select id="add-lc-select" class="form-select" required style="max-height: 200px;">
|
||||||
|
<!-- Injected by JS -->
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="grid-3" style="gap: 0.75rem; margin-bottom: 1rem;">
|
||||||
|
<div class="form-group" style="margin-bottom: 0;">
|
||||||
|
<label class="form-label" data-i18n="modalColLevel">เลเวล (1-80)</label>
|
||||||
|
<input type="number" id="add-lc-level" class="form-input" min="1" max="80" value="80" required>
|
||||||
|
</div>
|
||||||
|
<div class="form-group" style="margin-bottom: 0;">
|
||||||
|
<label class="form-label" data-i18n="lblPromotion">ขัดเกลา (0-6)</label>
|
||||||
|
<input type="number" id="add-lc-promotion" class="form-input" min="0" max="6" value="6" required>
|
||||||
|
</div>
|
||||||
|
<div class="form-group" style="margin-bottom: 0;">
|
||||||
|
<label class="form-label">Superimpose (1-5)</label>
|
||||||
|
<input type="number" id="add-lc-rank" class="form-input" min="1" max="5" value="5" required>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="form-label" data-i18n="lblEquipAvatar">สวมใส่ให้ตัวละคร (ถ้าต้องการ)</label>
|
||||||
|
<select id="add-lc-avatar" class="form-select">
|
||||||
|
<option value="0" data-i18n="unassigned">-- ยังไม่สวมใส่ (เก็บในคลัง) --</option>
|
||||||
|
<!-- Injected by JS -->
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div style="display: flex; justify-content: flex-end; gap: 0.5rem; margin-top: 1.25rem;">
|
||||||
|
<button type="button" class="btn btn-secondary" id="btn-cancel-add-lc" data-i18n="btnCancel">ยกเลิก</button>
|
||||||
|
<button type="submit" class="btn btn-success" data-i18n="btnAddLcSubmit">💾 เพิ่มลง FreeSR</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Add Relic Modal -->
|
||||||
|
<div class="modal-overlay" id="modal-add-relic">
|
||||||
|
<div class="modal-content" style="max-width: 580px;">
|
||||||
|
<div class="modal-header">
|
||||||
|
<h3 style="font-weight: 800;" data-i18n="modalAddRelicTitle">🛡️ เพิ่มรีลิกส์ลง FreeSR</h3>
|
||||||
|
<button type="button" class="btn btn-sm btn-secondary" id="btn-close-add-relic-modal">✕</button>
|
||||||
|
</div>
|
||||||
|
<form id="form-add-relic">
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="form-label" data-i18n="lblSelectRelicSet">เลือกเซ็ตรีลิกส์</label>
|
||||||
|
<select id="add-relic-set" class="form-select" required>
|
||||||
|
<!-- Injected by JS -->
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="grid-2" style="gap: 0.75rem; margin-bottom: 1rem;">
|
||||||
|
<div class="form-group" style="margin-bottom: 0;">
|
||||||
|
<label class="form-label" data-i18n="lblRelicSlot">ชิ้นส่วน (Slot)</label>
|
||||||
|
<select id="add-relic-slot" class="form-select" required>
|
||||||
|
<option value="1">1: ส่วนหัว (Head / HP)</option>
|
||||||
|
<option value="2">2: ส่วนมือ (Hands / ATK)</option>
|
||||||
|
<option value="3">3: ลำตัว (Body)</option>
|
||||||
|
<option value="4">4: รองเท้า (Feet)</option>
|
||||||
|
<option value="5">5: ลูกแก้ว (Planar Sphere)</option>
|
||||||
|
<option value="6">6: สร้อยเชื่อมต่อ (Link Rope)</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="form-group" style="margin-bottom: 0;">
|
||||||
|
<label class="form-label" data-i18n="modalColLevel">เลเวล (0-15)</label>
|
||||||
|
<input type="number" id="add-relic-level" class="form-input" min="0" max="15" value="15" required>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="form-label" data-i18n="lblMainAffix">สเตตัสหลัก (Main Affix)</label>
|
||||||
|
<select id="add-relic-main-affix" class="form-select" required>
|
||||||
|
<!-- Dynamic according to selected slot -->
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="form-label" data-i18n="lblEquipAvatar">สวมใส่ให้ตัวละคร (ถ้าต้องการ)</label>
|
||||||
|
<select id="add-relic-avatar" class="form-select">
|
||||||
|
<option value="0" data-i18n="unassigned">-- ยังไม่สวมใส่ (เก็บในคลัง) --</option>
|
||||||
|
<!-- Injected by JS -->
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div style="display: flex; justify-content: flex-end; gap: 0.5rem; margin-top: 1.25rem;">
|
||||||
|
<button type="button" class="btn btn-secondary" id="btn-cancel-add-relic" data-i18n="btnCancel">ยกเลิก</button>
|
||||||
|
<button type="submit" class="btn btn-success" data-i18n="btnAddRelicSubmit">💾 เพิ่มลง FreeSR</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- Toast Notification Container -->
|
<!-- Toast Notification Container -->
|
||||||
<div class="toast-container" id="toast-container"></div>
|
<div class="toast-container" id="toast-container"></div>
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { AVATAR_METADATA, getAvatarInfo } from './avatars-data.js';
|
import { AVATAR_METADATA, getAvatarInfo } from './avatars-data.js';
|
||||||
import { getLightconeInfo, getRelicSetInfo } from './equipment-data.js';
|
import { LIGHTCONE_METADATA, RELIC_SET_METADATA, getLightconeInfo, getRelicSetInfo } from './equipment-data.js';
|
||||||
import { SUPPORTED_LANGUAGES, TRANSLATIONS, getCurrentLanguage, setLanguage, t, translateElement, translatePath } from './i18n.js';
|
import { SUPPORTED_LANGUAGES, TRANSLATIONS, getCurrentLanguage, setLanguage, t, translateElement, translatePath } from './i18n.js';
|
||||||
|
|
||||||
// Application State
|
// Application State
|
||||||
@@ -60,6 +60,26 @@ const el = {
|
|||||||
relicsList: document.getElementById('relics-list'),
|
relicsList: document.getElementById('relics-list'),
|
||||||
badgeTotalLc: document.getElementById('badge-total-lc'),
|
badgeTotalLc: document.getElementById('badge-total-lc'),
|
||||||
badgeTotalRelics: document.getElementById('badge-total-relics'),
|
badgeTotalRelics: document.getElementById('badge-total-relics'),
|
||||||
|
btnOpenAddLc: document.getElementById('btn-open-add-lc'),
|
||||||
|
modalAddLc: document.getElementById('modal-add-lc'),
|
||||||
|
btnCloseAddLcModal: document.getElementById('btn-close-add-lc-modal'),
|
||||||
|
btnCancelAddLc: document.getElementById('btn-cancel-add-lc'),
|
||||||
|
formAddLc: document.getElementById('form-add-lc'),
|
||||||
|
addLcSelect: document.getElementById('add-lc-select'),
|
||||||
|
addLcLevel: document.getElementById('add-lc-level'),
|
||||||
|
addLcPromotion: document.getElementById('add-lc-promotion'),
|
||||||
|
addLcRank: document.getElementById('add-lc-rank'),
|
||||||
|
addLcAvatar: document.getElementById('add-lc-avatar'),
|
||||||
|
btnOpenAddRelic: document.getElementById('btn-open-add-relic'),
|
||||||
|
modalAddRelic: document.getElementById('modal-add-relic'),
|
||||||
|
btnCloseAddRelicModal: document.getElementById('btn-close-add-relic-modal'),
|
||||||
|
btnCancelAddRelic: document.getElementById('btn-cancel-add-relic'),
|
||||||
|
formAddRelic: document.getElementById('form-add-relic'),
|
||||||
|
addRelicSet: document.getElementById('add-relic-set'),
|
||||||
|
addRelicSlot: document.getElementById('add-relic-slot'),
|
||||||
|
addRelicLevel: document.getElementById('add-relic-level'),
|
||||||
|
addRelicMainAffix: document.getElementById('add-relic-main-affix'),
|
||||||
|
addRelicAvatar: document.getElementById('add-relic-avatar'),
|
||||||
|
|
||||||
// Persistent Tab
|
// Persistent Tab
|
||||||
tabBtnPersistent: document.getElementById('tab-btn-persistent'),
|
tabBtnPersistent: document.getElementById('tab-btn-persistent'),
|
||||||
@@ -68,6 +88,7 @@ const el = {
|
|||||||
persistentMarchSelect: document.getElementById('persistent-march-select'),
|
persistentMarchSelect: document.getElementById('persistent-march-select'),
|
||||||
toggleSwGlobal: document.getElementById('toggle-sw-global'),
|
toggleSwGlobal: document.getElementById('toggle-sw-global'),
|
||||||
toggleCastoriceGlobal: document.getElementById('toggle-castorice-global'),
|
toggleCastoriceGlobal: document.getElementById('toggle-castorice-global'),
|
||||||
|
toggleAhaGlobal: document.getElementById('toggle-aha-global'),
|
||||||
btnSavePersistentToggles: document.getElementById('btn-save-persistent-toggles'),
|
btnSavePersistentToggles: document.getElementById('btn-save-persistent-toggles'),
|
||||||
|
|
||||||
// Ex-Rank
|
// Ex-Rank
|
||||||
@@ -236,7 +257,45 @@ function setConnectionStatus(connected, extraText = '') {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Helper to get element CSS class
|
// Helper to get element CSS class
|
||||||
|
// Canonical element & path maps (handles English and all 13 supported languages)
|
||||||
|
const CANONICAL_ELEMENTS = {
|
||||||
|
physical: 'Physical', fire: 'Fire', ice: 'Ice', lightning: 'Lightning',
|
||||||
|
wind: 'Wind', quantum: 'Quantum', imaginary: 'Imaginary', thunder: 'Lightning'
|
||||||
|
};
|
||||||
|
|
||||||
|
const CANONICAL_PATHS = {
|
||||||
|
destruction: 'Destruction', hunt: 'Hunt', 'the hunt': 'Hunt', erudition: 'Erudition',
|
||||||
|
harmony: 'Harmony', nihility: 'Nihility', preservation: 'Preservation',
|
||||||
|
abundance: 'Abundance', remembrance: 'Remembrance', elation: 'Elation'
|
||||||
|
};
|
||||||
|
|
||||||
|
// Dynamically index all translated element and path strings across languages
|
||||||
|
for (const langKey in TRANSLATIONS) {
|
||||||
|
const tr = TRANSLATIONS[langKey];
|
||||||
|
if (tr.elements) {
|
||||||
|
for (const [enKey, locVal] of Object.entries(tr.elements)) {
|
||||||
|
if (locVal) CANONICAL_ELEMENTS[String(locVal).trim().toLowerCase()] = enKey;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (tr.paths) {
|
||||||
|
for (const [enKey, locVal] of Object.entries(tr.paths)) {
|
||||||
|
if (locVal) CANONICAL_PATHS[String(locVal).trim().toLowerCase()] = (enKey === 'The Hunt' ? 'Hunt' : enKey);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function normalizeElement(elem) {
|
||||||
|
if (!elem) return 'Physical';
|
||||||
|
return CANONICAL_ELEMENTS[String(elem).trim().toLowerCase()] || elem;
|
||||||
|
}
|
||||||
|
|
||||||
|
function normalizePath(p) {
|
||||||
|
if (!p) return 'Destruction';
|
||||||
|
return CANONICAL_PATHS[String(p).trim().toLowerCase()] || (p === 'The Hunt' ? 'Hunt' : p);
|
||||||
|
}
|
||||||
|
|
||||||
function getElementClass(elem) {
|
function getElementClass(elem) {
|
||||||
|
const canonical = normalizeElement(elem);
|
||||||
const map = {
|
const map = {
|
||||||
Fire: 'elem-fire',
|
Fire: 'elem-fire',
|
||||||
Ice: 'elem-ice',
|
Ice: 'elem-ice',
|
||||||
@@ -246,30 +305,31 @@ function getElementClass(elem) {
|
|||||||
Quantum: 'elem-quantum',
|
Quantum: 'elem-quantum',
|
||||||
Imaginary: 'elem-imaginary'
|
Imaginary: 'elem-imaginary'
|
||||||
};
|
};
|
||||||
return map[elem] || 'elem-physical';
|
return map[canonical] || 'elem-physical';
|
||||||
}
|
}
|
||||||
|
|
||||||
// Render Element Icon HTML (Official Star Rail Game Icon)
|
// Render Element Icon HTML (Official Star Rail Game Icon)
|
||||||
function getElementIconHtml(element, size = 20) {
|
function getElementIconHtml(element, size = 20) {
|
||||||
if (!element) return '';
|
if (!element) return '';
|
||||||
const elemClass = getElementClass(element);
|
const canonical = normalizeElement(element);
|
||||||
|
const elemClass = getElementClass(canonical);
|
||||||
return `<span class="icon-badge element-icon-badge ${elemClass}" title="${element}">
|
return `<span class="icon-badge element-icon-badge ${elemClass}" title="${element}">
|
||||||
<img src="assets/elements/${element}.png"
|
<img src="assets/elements/${canonical}.png"
|
||||||
alt="${element}"
|
alt="${element}"
|
||||||
style="width: ${size}px; height: ${size}px;"
|
style="width: ${size}px; height: ${size}px;"
|
||||||
onerror="if(this.src.indexOf('StarRailRes')===-1){this.src='https://raw.githubusercontent.com/Mar-7th/StarRailRes/master/icon/element/${element === 'Lightning' ? 'Thunder' : element}.png';}">
|
onerror="if(this.src.indexOf('StarRailRes')===-1){this.src='https://raw.githubusercontent.com/Mar-7th/StarRailRes/master/icon/element/${canonical === 'Lightning' ? 'Thunder' : canonical}.png';}">
|
||||||
</span>`;
|
</span>`;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Render Path Icon HTML (Official Star Rail Game Icon)
|
// Render Path Icon HTML (Official Star Rail Game Icon)
|
||||||
function getPathIconHtml(path, size = 20) {
|
function getPathIconHtml(path, size = 20) {
|
||||||
if (!path) return '';
|
if (!path) return '';
|
||||||
const safePath = path === 'The Hunt' ? 'Hunt' : path;
|
const canonical = normalizePath(path);
|
||||||
return `<span class="icon-badge path-icon-badge" title="${path}">
|
return `<span class="icon-badge path-icon-badge" title="${path}">
|
||||||
<img src="assets/paths/${path}.png"
|
<img src="assets/paths/${canonical}.png"
|
||||||
alt="${path}"
|
alt="${path}"
|
||||||
style="width: ${size}px; height: ${size}px;"
|
style="width: ${size}px; height: ${size}px;"
|
||||||
onerror="if(this.src.indexOf('StarRailRes')===-1){this.src='https://raw.githubusercontent.com/Mar-7th/StarRailRes/master/icon/path/${safePath}.png';}">
|
onerror="if(this.src.indexOf('StarRailRes')===-1){this.src='https://raw.githubusercontent.com/Mar-7th/StarRailRes/master/icon/path/${canonical}.png';}">
|
||||||
</span>`;
|
</span>`;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -442,6 +502,7 @@ function initAvatarsList() {
|
|||||||
rank: 6
|
rank: 6
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
list.sort((a, b) => b.avatar_id - a.avatar_id);
|
||||||
state.avatarsList = list;
|
state.avatarsList = list;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -580,8 +641,9 @@ function renderPickerGrid() {
|
|||||||
});
|
});
|
||||||
el.pickerAvatarsGrid.appendChild(removeCard);
|
el.pickerAvatarsGrid.appendChild(removeCard);
|
||||||
|
|
||||||
// Available avatars
|
// Available avatars (sorted descending by avatar_id)
|
||||||
state.avatarsList.forEach(item => {
|
const sortedAvatars = [...state.avatarsList].sort((a, b) => b.avatar_id - a.avatar_id);
|
||||||
|
sortedAvatars.forEach(item => {
|
||||||
const meta = getAvatarInfo(item.avatar_id);
|
const meta = getAvatarInfo(item.avatar_id);
|
||||||
if (search && !meta.name.toLowerCase().includes(search) && !String(item.avatar_id).includes(search)) {
|
if (search && !meta.name.toLowerCase().includes(search) && !String(item.avatar_id).includes(search)) {
|
||||||
return;
|
return;
|
||||||
@@ -665,6 +727,7 @@ async function loadAvatars() {
|
|||||||
console.warn('Live avatar list fetch failed, using local list:', err);
|
console.warn('Live avatar list fetch failed, using local list:', err);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
state.avatarsList.sort((a, b) => b.avatar_id - a.avatar_id);
|
||||||
renderAvatarsGrid();
|
renderAvatarsGrid();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -678,11 +741,15 @@ function renderAvatarsGrid() {
|
|||||||
const meta = getAvatarInfo(item.avatar_id);
|
const meta = getAvatarInfo(item.avatar_id);
|
||||||
const matchesSearch = meta.name.toLowerCase().includes(searchTerm) || String(item.avatar_id).includes(searchTerm);
|
const matchesSearch = meta.name.toLowerCase().includes(searchTerm) || String(item.avatar_id).includes(searchTerm);
|
||||||
const matchesRarity = rarityFilter === 'all' || String(meta.rarity) === rarityFilter;
|
const matchesRarity = rarityFilter === 'all' || String(meta.rarity) === rarityFilter;
|
||||||
const matchesElement = elementFilter === 'all' || meta.element === elementFilter;
|
const elemCanonical = normalizeElement(meta.rawElement || meta.element);
|
||||||
const matchesPath = pathFilter === 'all' || meta.path === pathFilter || (pathFilter === 'Hunt' && (meta.path === 'Hunt' || meta.path === 'The Hunt'));
|
const matchesElement = elementFilter === 'all' || elemCanonical === normalizeElement(elementFilter);
|
||||||
|
const pathCanonical = normalizePath(meta.rawPath || meta.path);
|
||||||
|
const matchesPath = pathFilter === 'all' || pathCanonical === normalizePath(pathFilter);
|
||||||
return matchesSearch && matchesRarity && matchesElement && matchesPath;
|
return matchesSearch && matchesRarity && matchesElement && matchesPath;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
filtered.sort((a, b) => b.avatar_id - a.avatar_id);
|
||||||
|
|
||||||
if (filtered.length === 0) {
|
if (filtered.length === 0) {
|
||||||
el.avatarsGrid.innerHTML = `<div style="grid-column: 1/-1; text-align: center; color: var(--text-muted); padding: 2rem;">${t('noAvatarsFound')}</div>`;
|
el.avatarsGrid.innerHTML = `<div style="grid-column: 1/-1; text-align: center; color: var(--text-muted); padding: 2rem;">${t('noAvatarsFound')}</div>`;
|
||||||
return;
|
return;
|
||||||
@@ -1294,9 +1361,25 @@ async function loadEquipment() {
|
|||||||
Lv. ${lc.level} • S${lc.rank} • ${t('equippedBy')}: <strong style="color: var(--accent-cyan);">${equipped}</strong>
|
Lv. ${lc.level} • S${lc.rank} • ${t('equippedBy')}: <strong style="color: var(--accent-cyan);">${equipped}</strong>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div>
|
||||||
|
<button type="button" class="btn btn-sm btn-danger btn-delete-lc" data-uid="${lc.internal_uid}" title="${t('deleteItem')}">🗑️</button>
|
||||||
|
</div>
|
||||||
`;
|
`;
|
||||||
el.lightconesList.appendChild(item);
|
el.lightconesList.appendChild(item);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Bind delete LC buttons
|
||||||
|
el.lightconesList.querySelectorAll('.btn-delete-lc').forEach(btn => {
|
||||||
|
btn.addEventListener('click', async (e) => {
|
||||||
|
const uid = parseInt(e.currentTarget.getAttribute('data-uid'), 10);
|
||||||
|
if (state.fullFreesrData?.lightcones) {
|
||||||
|
state.fullFreesrData.lightcones = state.fullFreesrData.lightcones.filter(l => l.internal_uid !== uid);
|
||||||
|
await saveFreesrChangesToServer();
|
||||||
|
loadEquipment();
|
||||||
|
showToast(t('toastItemDeleted'), 'info');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Render Relics
|
// Render Relics
|
||||||
@@ -1325,15 +1408,214 @@ async function loadEquipment() {
|
|||||||
Lv. ${r.level} • ${t('equippedBy')}: <strong style="color: var(--accent-cyan);">${equipped}</strong>
|
Lv. ${r.level} • ${t('equippedBy')}: <strong style="color: var(--accent-cyan);">${equipped}</strong>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div>
|
||||||
|
<button type="button" class="btn btn-sm btn-danger btn-delete-relic" data-uid="${r.internal_uid}" title="${t('deleteItem')}">🗑️</button>
|
||||||
|
</div>
|
||||||
`;
|
`;
|
||||||
el.relicsList.appendChild(item);
|
el.relicsList.appendChild(item);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Bind delete Relic buttons
|
||||||
|
el.relicsList.querySelectorAll('.btn-delete-relic').forEach(btn => {
|
||||||
|
btn.addEventListener('click', async (e) => {
|
||||||
|
const uid = parseInt(e.currentTarget.getAttribute('data-uid'), 10);
|
||||||
|
if (state.fullFreesrData?.relics) {
|
||||||
|
state.fullFreesrData.relics = state.fullFreesrData.relics.filter(r => r.internal_uid !== uid);
|
||||||
|
await saveFreesrChangesToServer();
|
||||||
|
loadEquipment();
|
||||||
|
showToast(t('toastItemDeleted'), 'info');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.warn('Equipment loading error:', err);
|
console.warn('Equipment loading error:', err);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Open Add Light Cone Modal
|
||||||
|
function openAddLcModal() {
|
||||||
|
if (!el.modalAddLc) return;
|
||||||
|
el.addLcSelect.innerHTML = '';
|
||||||
|
const lcIds = Object.keys(LIGHTCONE_METADATA).sort((a, b) => parseInt(b, 10) - parseInt(a, 10));
|
||||||
|
lcIds.forEach(id => {
|
||||||
|
const meta = getLightconeInfo(id);
|
||||||
|
const opt = document.createElement('option');
|
||||||
|
opt.value = id;
|
||||||
|
opt.textContent = `★${meta.rarity} [${meta.path || 'LC'}] ${meta.name} (ID: ${id})`;
|
||||||
|
el.addLcSelect.appendChild(opt);
|
||||||
|
});
|
||||||
|
|
||||||
|
el.addLcAvatar.innerHTML = `<option value="0">${t('unassigned')}</option>`;
|
||||||
|
const sortedAvatars = [...state.avatarsList].sort((a, b) => b.avatar_id - a.avatar_id);
|
||||||
|
sortedAvatars.forEach(av => {
|
||||||
|
const info = getAvatarInfo(av.avatar_id);
|
||||||
|
const opt = document.createElement('option');
|
||||||
|
opt.value = av.avatar_id;
|
||||||
|
opt.textContent = `${info.name} (ID: ${av.avatar_id})`;
|
||||||
|
el.addLcAvatar.appendChild(opt);
|
||||||
|
});
|
||||||
|
|
||||||
|
el.addLcLevel.value = 80;
|
||||||
|
el.addLcPromotion.value = 6;
|
||||||
|
el.addLcRank.value = 5;
|
||||||
|
|
||||||
|
el.modalAddLc.classList.add('active');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Open Add Relic Modal
|
||||||
|
function openAddRelicModal() {
|
||||||
|
if (!el.modalAddRelic) return;
|
||||||
|
el.addRelicSet.innerHTML = '';
|
||||||
|
const setIds = Object.keys(RELIC_SET_METADATA).sort((a, b) => parseInt(b, 10) - parseInt(a, 10));
|
||||||
|
setIds.forEach(setId => {
|
||||||
|
const meta = getRelicSetInfo(setId);
|
||||||
|
const opt = document.createElement('option');
|
||||||
|
opt.value = setId;
|
||||||
|
opt.textContent = `${meta.name} (Set ID: ${setId})`;
|
||||||
|
el.addRelicSet.appendChild(opt);
|
||||||
|
});
|
||||||
|
|
||||||
|
el.addRelicAvatar.innerHTML = `<option value="0">${t('unassigned')}</option>`;
|
||||||
|
const sortedAvatars = [...state.avatarsList].sort((a, b) => b.avatar_id - a.avatar_id);
|
||||||
|
sortedAvatars.forEach(av => {
|
||||||
|
const info = getAvatarInfo(av.avatar_id);
|
||||||
|
const opt = document.createElement('option');
|
||||||
|
opt.value = av.avatar_id;
|
||||||
|
opt.textContent = `${info.name} (ID: ${av.avatar_id})`;
|
||||||
|
el.addRelicAvatar.appendChild(opt);
|
||||||
|
});
|
||||||
|
|
||||||
|
el.addRelicSlot.value = "1";
|
||||||
|
el.addRelicLevel.value = 15;
|
||||||
|
updateRelicMainAffixes("1");
|
||||||
|
|
||||||
|
el.modalAddRelic.classList.add('active');
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateRelicMainAffixes(slot) {
|
||||||
|
if (!el.addRelicMainAffix) return;
|
||||||
|
el.addRelicMainAffix.innerHTML = '';
|
||||||
|
|
||||||
|
const affixesBySlot = {
|
||||||
|
"1": [{ id: 1, name: "HP (Flat)" }],
|
||||||
|
"2": [{ id: 1, name: "ATK (Flat)" }],
|
||||||
|
"3": [
|
||||||
|
{ id: 1, name: "HP%" }, { id: 2, name: "ATK%" }, { id: 3, name: "DEF%" },
|
||||||
|
{ id: 4, name: "CRIT Rate%" }, { id: 5, name: "CRIT DMG%" },
|
||||||
|
{ id: 6, name: "Outgoing Healing Boost%" }, { id: 7, name: "Effect Hit Rate%" }
|
||||||
|
],
|
||||||
|
"4": [
|
||||||
|
{ id: 1, name: "HP%" }, { id: 2, name: "ATK%" }, { id: 3, name: "DEF%" },
|
||||||
|
{ id: 4, name: "SPD" }
|
||||||
|
],
|
||||||
|
"5": [
|
||||||
|
{ id: 1, name: "HP%" }, { id: 2, name: "ATK%" }, { id: 3, name: "DEF%" },
|
||||||
|
{ id: 4, name: "Physical DMG Boost%" }, { id: 5, name: "Fire DMG Boost%" },
|
||||||
|
{ id: 6, name: "Ice DMG Boost%" }, { id: 7, name: "Lightning DMG Boost%" },
|
||||||
|
{ id: 8, name: "Wind DMG Boost%" }, { id: 9, name: "Quantum DMG Boost%" },
|
||||||
|
{ id: 10, name: "Imaginary DMG Boost%" }
|
||||||
|
],
|
||||||
|
"6": [
|
||||||
|
{ id: 1, name: "Break Effect%" }, { id: 2, name: "Energy Regeneration Rate%" },
|
||||||
|
{ id: 3, name: "HP%" }, { id: 4, name: "ATK%" }, { id: 5, name: "DEF%" }
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
|
const list = affixesBySlot[slot] || [{ id: 1, name: "Main Stat" }];
|
||||||
|
list.forEach(a => {
|
||||||
|
const opt = document.createElement('option');
|
||||||
|
opt.value = a.id;
|
||||||
|
opt.textContent = a.name;
|
||||||
|
el.addRelicMainAffix.appendChild(opt);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async function handleAddLcSubmit(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
const itemId = parseInt(el.addLcSelect.value, 10);
|
||||||
|
const level = parseInt(el.addLcLevel.value, 10) || 80;
|
||||||
|
const promotion = parseInt(el.addLcPromotion.value, 10) || 6;
|
||||||
|
const rank = parseInt(el.addLcRank.value, 10) || 5;
|
||||||
|
const equipAvatar = parseInt(el.addLcAvatar.value, 10) || 0;
|
||||||
|
|
||||||
|
if (!state.fullFreesrData) {
|
||||||
|
state.fullFreesrData = { lightcones: [], relics: [], avatars: {} };
|
||||||
|
}
|
||||||
|
if (!state.fullFreesrData.lightcones) {
|
||||||
|
state.fullFreesrData.lightcones = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (equipAvatar !== 0) {
|
||||||
|
state.fullFreesrData.lightcones.forEach(lc => {
|
||||||
|
if (lc.equip_avatar === equipAvatar) lc.equip_avatar = 0;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const maxUid = state.fullFreesrData.lightcones.reduce((m, lc) => Math.max(m, lc.internal_uid || 0), 0);
|
||||||
|
const newLc = {
|
||||||
|
level,
|
||||||
|
item_id: itemId,
|
||||||
|
equip_avatar: equipAvatar,
|
||||||
|
rank,
|
||||||
|
promotion,
|
||||||
|
internal_uid: maxUid + 1
|
||||||
|
};
|
||||||
|
|
||||||
|
state.fullFreesrData.lightcones.unshift(newLc);
|
||||||
|
await saveFreesrChangesToServer();
|
||||||
|
loadEquipment();
|
||||||
|
el.modalAddLc.classList.remove('active');
|
||||||
|
showToast(t('toastLcAdded'), 'success');
|
||||||
|
}
|
||||||
|
|
||||||
|
async function handleAddRelicSubmit(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
const setId = parseInt(el.addRelicSet.value, 10);
|
||||||
|
const slot = parseInt(el.addRelicSlot.value, 10) || 1;
|
||||||
|
const level = parseInt(el.addRelicLevel.value, 10) || 15;
|
||||||
|
const mainAffixId = parseInt(el.addRelicMainAffix.value, 10) || 1;
|
||||||
|
const equipAvatar = parseInt(el.addRelicAvatar.value, 10) || 0;
|
||||||
|
|
||||||
|
const relicId = 60000 + (setId * 10) + slot;
|
||||||
|
|
||||||
|
if (!state.fullFreesrData) {
|
||||||
|
state.fullFreesrData = { lightcones: [], relics: [], avatars: {} };
|
||||||
|
}
|
||||||
|
if (!state.fullFreesrData.relics) {
|
||||||
|
state.fullFreesrData.relics = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (equipAvatar !== 0) {
|
||||||
|
state.fullFreesrData.relics.forEach(r => {
|
||||||
|
if (r.equip_avatar === equipAvatar && (r.relic_id % 10 === slot)) {
|
||||||
|
r.equip_avatar = 0;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const maxUid = state.fullFreesrData.relics.reduce((m, r) => Math.max(m, r.internal_uid || 0), 0);
|
||||||
|
const newRelic = {
|
||||||
|
level,
|
||||||
|
relic_id: relicId,
|
||||||
|
main_affix_id: mainAffixId,
|
||||||
|
sub_affixes: [
|
||||||
|
{ sub_affix_id: 1, cnt: 2, step: 1 },
|
||||||
|
{ sub_affix_id: 2, cnt: 2, step: 1 },
|
||||||
|
{ sub_affix_id: 3, cnt: 3, step: 2 },
|
||||||
|
{ sub_affix_id: 4, cnt: 4, step: 2 }
|
||||||
|
],
|
||||||
|
internal_uid: maxUid + 1,
|
||||||
|
equip_avatar: equipAvatar
|
||||||
|
};
|
||||||
|
|
||||||
|
state.fullFreesrData.relics.unshift(newRelic);
|
||||||
|
await saveFreesrChangesToServer();
|
||||||
|
loadEquipment();
|
||||||
|
el.modalAddRelic.classList.remove('active');
|
||||||
|
showToast(t('toastRelicAdded'), 'success');
|
||||||
|
}
|
||||||
|
|
||||||
// Load Persistent Save Settings (Exclusive to GaC-hkrpg-go)
|
// Load Persistent Save Settings (Exclusive to GaC-hkrpg-go)
|
||||||
async function loadPersistentSettings() {
|
async function loadPersistentSettings() {
|
||||||
if (state.serverMode !== 'gac') return;
|
if (state.serverMode !== 'gac') return;
|
||||||
@@ -1351,6 +1633,7 @@ async function loadPersistentSettings() {
|
|||||||
|
|
||||||
el.toggleSwGlobal.checked = res.data.enable_sw_global !== false;
|
el.toggleSwGlobal.checked = res.data.enable_sw_global !== false;
|
||||||
el.toggleCastoriceGlobal.checked = res.data.enable_castorice_global !== false;
|
el.toggleCastoriceGlobal.checked = res.data.enable_castorice_global !== false;
|
||||||
|
if (el.toggleAhaGlobal) el.toggleAhaGlobal.checked = res.data.enable_aha_global !== false;
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.warn('Persistent settings loading error:', err);
|
console.warn('Persistent settings loading error:', err);
|
||||||
}
|
}
|
||||||
@@ -1704,18 +1987,50 @@ function setupEvents() {
|
|||||||
el.btnSavePersistentToggles.addEventListener('click', async () => {
|
el.btnSavePersistentToggles.addEventListener('click', async () => {
|
||||||
const sw = el.toggleSwGlobal.checked;
|
const sw = el.toggleSwGlobal.checked;
|
||||||
const castorice = el.toggleCastoriceGlobal.checked;
|
const castorice = el.toggleCastoriceGlobal.checked;
|
||||||
|
const aha = el.toggleAhaGlobal ? el.toggleAhaGlobal.checked : true;
|
||||||
try {
|
try {
|
||||||
await apiCall('/api/persistent', 'POST', {
|
await apiCall('/api/persistent', 'POST', {
|
||||||
enable_sw_global: sw,
|
enable_sw_global: sw,
|
||||||
enable_castorice_global: castorice
|
enable_castorice_global: castorice,
|
||||||
|
enable_aha_global: aha
|
||||||
});
|
});
|
||||||
showToast('บันทึกสวิตช์ Global เรียบร้อย!', 'success');
|
showToast(t('btnSaveGlobalSwitch') || 'บันทึกสวิตช์ Global เรียบร้อย!', 'success');
|
||||||
refreshStatus();
|
refreshStatus();
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
showToast(`เกิดข้อผิดพลาด: ${err.message}`, 'error');
|
showToast(`เกิดข้อผิดพลาด: ${err.message}`, 'error');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Equipment Add Modal Controls
|
||||||
|
if (el.btnOpenAddLc) {
|
||||||
|
el.btnOpenAddLc.addEventListener('click', openAddLcModal);
|
||||||
|
}
|
||||||
|
if (el.btnCloseAddLcModal) {
|
||||||
|
el.btnCloseAddLcModal.addEventListener('click', () => el.modalAddLc.classList.remove('active'));
|
||||||
|
}
|
||||||
|
if (el.btnCancelAddLc) {
|
||||||
|
el.btnCancelAddLc.addEventListener('click', () => el.modalAddLc.classList.remove('active'));
|
||||||
|
}
|
||||||
|
if (el.formAddLc) {
|
||||||
|
el.formAddLc.addEventListener('submit', handleAddLcSubmit);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (el.btnOpenAddRelic) {
|
||||||
|
el.btnOpenAddRelic.addEventListener('click', openAddRelicModal);
|
||||||
|
}
|
||||||
|
if (el.btnCloseAddRelicModal) {
|
||||||
|
el.btnCloseAddRelicModal.addEventListener('click', () => el.modalAddRelic.classList.remove('active'));
|
||||||
|
}
|
||||||
|
if (el.btnCancelAddRelic) {
|
||||||
|
el.btnCancelAddRelic.addEventListener('click', () => el.modalAddRelic.classList.remove('active'));
|
||||||
|
}
|
||||||
|
if (el.addRelicSlot) {
|
||||||
|
el.addRelicSlot.addEventListener('change', (e) => updateRelicMainAffixes(e.target.value));
|
||||||
|
}
|
||||||
|
if (el.formAddRelic) {
|
||||||
|
el.formAddRelic.addEventListener('submit', handleAddRelicSubmit);
|
||||||
|
}
|
||||||
|
|
||||||
// Avatar Search & Filters
|
// Avatar Search & Filters
|
||||||
el.avatarSearch.addEventListener('input', renderAvatarsGrid);
|
el.avatarSearch.addEventListener('input', renderAvatarsGrid);
|
||||||
el.avatarFilterRarity.addEventListener('change', renderAvatarsGrid);
|
el.avatarFilterRarity.addEventListener('change', renderAvatarsGrid);
|
||||||
|
|||||||
@@ -2102,6 +2102,8 @@ export function getAvatarInfo(avatarId, langOverride = null) {
|
|||||||
name: localizedName,
|
name: localizedName,
|
||||||
path: translatePath(meta.path),
|
path: translatePath(meta.path),
|
||||||
element: translateElement(meta.element),
|
element: translateElement(meta.element),
|
||||||
|
rawPath: meta.path,
|
||||||
|
rawElement: meta.element,
|
||||||
rarity: meta.rarity,
|
rarity: meta.rarity,
|
||||||
hasExRank: !!meta.hasExRank
|
hasExRank: !!meta.hasExRank
|
||||||
};
|
};
|
||||||
|
|||||||
+234
@@ -19,6 +19,24 @@ export const SUPPORTED_LANGUAGES = [
|
|||||||
|
|
||||||
export const TRANSLATIONS = {
|
export const TRANSLATIONS = {
|
||||||
"th": {
|
"th": {
|
||||||
|
"ahaGlobalDesc": "เปิดใช้งานฟังก์ชันพิเศษ Aeon ★ Aha ทั่วทั้งเซิร์ฟเวอร์",
|
||||||
|
"btnAddLc": "+ เพิ่ม LC",
|
||||||
|
"btnAddRelic": "+ เพิ่มรีลิกส์",
|
||||||
|
"modalAddLcTitle": "🗡️ เพิ่มกรวยแสงลง FreeSR",
|
||||||
|
"modalAddRelicTitle": "🛡️ เพิ่มรีลิกส์ลง FreeSR",
|
||||||
|
"lblSelectLc": "เลือกกรวยแสง",
|
||||||
|
"lblSelectRelicSet": "เลือกเซ็ตรีลิกส์",
|
||||||
|
"lblRelicSlot": "ชิ้นส่วน (Slot)",
|
||||||
|
"lblMainAffix": "สเตตัสหลัก (Main Affix)",
|
||||||
|
"lblEquipAvatar": "สวมใส่ให้ตัวละคร",
|
||||||
|
"unassigned": "-- ยังไม่สวมใส่ (เก็บในคลัง) --",
|
||||||
|
"btnAddLcSubmit": "💾 เพิ่มลง FreeSR",
|
||||||
|
"btnAddRelicSubmit": "💾 เพิ่มลง FreeSR",
|
||||||
|
"toastLcAdded": "เพิ่มกรวยแสงลงใน FreeSR สำเร็จแล้ว",
|
||||||
|
"toastRelicAdded": "เพิ่มรีลิกส์ลงใน FreeSR สำเร็จแล้ว",
|
||||||
|
"deleteItem": "ลบ",
|
||||||
|
"toastItemDeleted": "ลบไอเทมสำเร็จแล้ว",
|
||||||
|
|
||||||
"appName": "GaC-Srtool",
|
"appName": "GaC-Srtool",
|
||||||
"appSubtitle": "Star Rail FreeSR & Server Controller",
|
"appSubtitle": "Star Rail FreeSR & Server Controller",
|
||||||
"online": "เชื่อมต่อแล้ว",
|
"online": "เชื่อมต่อแล้ว",
|
||||||
@@ -195,6 +213,24 @@ export const TRANSLATIONS = {
|
|||||||
"settingsReset": "คืนค่าเริ่มต้นเรียบร้อย"
|
"settingsReset": "คืนค่าเริ่มต้นเรียบร้อย"
|
||||||
},
|
},
|
||||||
"en": {
|
"en": {
|
||||||
|
"ahaGlobalDesc": "Enable server-wide Aeon ★ Aha special trait",
|
||||||
|
"btnAddLc": "+ Add LC",
|
||||||
|
"btnAddRelic": "+ Add Relic",
|
||||||
|
"modalAddLcTitle": "🗡️ Add Light Cone to FreeSR",
|
||||||
|
"modalAddRelicTitle": "🛡️ Add Relic to FreeSR",
|
||||||
|
"lblSelectLc": "Select Light Cone",
|
||||||
|
"lblSelectRelicSet": "Select Relic Set",
|
||||||
|
"lblRelicSlot": "Relic Slot",
|
||||||
|
"lblMainAffix": "Main Stat",
|
||||||
|
"lblEquipAvatar": "Equip to Avatar",
|
||||||
|
"unassigned": "-- Unassigned (Inventory) --",
|
||||||
|
"btnAddLcSubmit": "💾 Add to FreeSR",
|
||||||
|
"btnAddRelicSubmit": "💾 Add to FreeSR",
|
||||||
|
"toastLcAdded": "Light Cone added to FreeSR",
|
||||||
|
"toastRelicAdded": "Relic added to FreeSR",
|
||||||
|
"deleteItem": "Delete",
|
||||||
|
"toastItemDeleted": "Item deleted successfully",
|
||||||
|
|
||||||
"appName": "GaC-Srtool",
|
"appName": "GaC-Srtool",
|
||||||
"appSubtitle": "Star Rail FreeSR & Server Controller",
|
"appSubtitle": "Star Rail FreeSR & Server Controller",
|
||||||
"online": "Connected",
|
"online": "Connected",
|
||||||
@@ -371,6 +407,24 @@ export const TRANSLATIONS = {
|
|||||||
"settingsReset": "Reset to default settings"
|
"settingsReset": "Reset to default settings"
|
||||||
},
|
},
|
||||||
"zh-CN": {
|
"zh-CN": {
|
||||||
|
"ahaGlobalDesc": "全服启用星神·阿哈特殊被动",
|
||||||
|
"btnAddLc": "+ 添加光锥",
|
||||||
|
"btnAddRelic": "+ 添加遗器",
|
||||||
|
"modalAddLcTitle": "🗡️ 添加光锥至 FreeSR",
|
||||||
|
"modalAddRelicTitle": "🛡️ 添加遗器至 FreeSR",
|
||||||
|
"lblSelectLc": "选择光锥",
|
||||||
|
"lblSelectRelicSet": "选择遗器套装",
|
||||||
|
"lblRelicSlot": "遗器部位",
|
||||||
|
"lblMainAffix": "主词条属性",
|
||||||
|
"lblEquipAvatar": "装备给角色",
|
||||||
|
"unassigned": "-- 暂不装备(存入背包) --",
|
||||||
|
"btnAddLcSubmit": "💾 添加至 FreeSR",
|
||||||
|
"btnAddRelicSubmit": "💾 添加至 FreeSR",
|
||||||
|
"toastLcAdded": "已成功添加光锥至 FreeSR",
|
||||||
|
"toastRelicAdded": "已成功添加遗器至 FreeSR",
|
||||||
|
"deleteItem": "删除",
|
||||||
|
"toastItemDeleted": "道具已成功删除",
|
||||||
|
|
||||||
"appName": "GaC-Srtool",
|
"appName": "GaC-Srtool",
|
||||||
"appSubtitle": "星穹铁道 FreeSR 与服务器控制器",
|
"appSubtitle": "星穹铁道 FreeSR 与服务器控制器",
|
||||||
"online": "已连接",
|
"online": "已连接",
|
||||||
@@ -547,6 +601,24 @@ export const TRANSLATIONS = {
|
|||||||
"settingsReset": "已恢复默认设置"
|
"settingsReset": "已恢复默认设置"
|
||||||
},
|
},
|
||||||
"zh-TW": {
|
"zh-TW": {
|
||||||
|
"ahaGlobalDesc": "全服啟用星神·阿哈特殊被動",
|
||||||
|
"btnAddLc": "+ 新增光錐",
|
||||||
|
"btnAddRelic": "+ 新增遺器",
|
||||||
|
"modalAddLcTitle": "🗡️ 新增光錐至 FreeSR",
|
||||||
|
"modalAddRelicTitle": "🛡️ 新增遺器至 FreeSR",
|
||||||
|
"lblSelectLc": "選擇光錐",
|
||||||
|
"lblSelectRelicSet": "選擇遺器套裝",
|
||||||
|
"lblRelicSlot": "遺器部位",
|
||||||
|
"lblMainAffix": "主詞條屬性",
|
||||||
|
"lblEquipAvatar": "裝備給角色",
|
||||||
|
"unassigned": "-- 暫不裝備(存入背包) --",
|
||||||
|
"btnAddLcSubmit": "💾 新增至 FreeSR",
|
||||||
|
"btnAddRelicSubmit": "💾 新增至 FreeSR",
|
||||||
|
"toastLcAdded": "已成功新增光錐至 FreeSR",
|
||||||
|
"toastRelicAdded": "已成功新增遺器至 FreeSR",
|
||||||
|
"deleteItem": "刪除",
|
||||||
|
"toastItemDeleted": "道具已成功刪除",
|
||||||
|
|
||||||
"appName": "GaC-Srtool",
|
"appName": "GaC-Srtool",
|
||||||
"appSubtitle": "星穹鐵道 FreeSR 與伺服器控制器",
|
"appSubtitle": "星穹鐵道 FreeSR 與伺服器控制器",
|
||||||
"online": "已連線",
|
"online": "已連線",
|
||||||
@@ -723,6 +795,24 @@ export const TRANSLATIONS = {
|
|||||||
"settingsReset": "已恢復預設設定"
|
"settingsReset": "已恢復預設設定"
|
||||||
},
|
},
|
||||||
"ja": {
|
"ja": {
|
||||||
|
"ahaGlobalDesc": "全サーバーで星神・アッハの特殊パッシブを有効化",
|
||||||
|
"btnAddLc": "+ 光円錐を追加",
|
||||||
|
"btnAddRelic": "+ 遺物を追加",
|
||||||
|
"modalAddLcTitle": "🗡️ FreeSRに光円錐を追加",
|
||||||
|
"modalAddRelicTitle": "🛡️ FreeSRに遺物を追加",
|
||||||
|
"lblSelectLc": "光円錐を選択",
|
||||||
|
"lblSelectRelicSet": "遺物セットを選択",
|
||||||
|
"lblRelicSlot": "部位",
|
||||||
|
"lblMainAffix": "メインステータス",
|
||||||
|
"lblEquipAvatar": "キャラクターに装備",
|
||||||
|
"unassigned": "-- 未装備(インベントリ) --",
|
||||||
|
"btnAddLcSubmit": "💾 FreeSRに追加",
|
||||||
|
"btnAddRelicSubmit": "💾 FreeSRに追加",
|
||||||
|
"toastLcAdded": "FreeSRに光円錐を追加しました",
|
||||||
|
"toastRelicAdded": "FreeSRに遺物を追加しました",
|
||||||
|
"deleteItem": "削除",
|
||||||
|
"toastItemDeleted": "アイテムを削除しました",
|
||||||
|
|
||||||
"appName": "GaC-Srtool",
|
"appName": "GaC-Srtool",
|
||||||
"appSubtitle": "スターレイル FreeSR & サーバーコントローラー",
|
"appSubtitle": "スターレイル FreeSR & サーバーコントローラー",
|
||||||
"online": "接続完了",
|
"online": "接続完了",
|
||||||
@@ -899,6 +989,24 @@ export const TRANSLATIONS = {
|
|||||||
"settingsReset": "デフォルト設定に戻しました"
|
"settingsReset": "デフォルト設定に戻しました"
|
||||||
},
|
},
|
||||||
"ko": {
|
"ko": {
|
||||||
|
"ahaGlobalDesc": "서버 전체 에이언즈★아하 특수 패시브 활성화",
|
||||||
|
"btnAddLc": "+ 광추 추가",
|
||||||
|
"btnAddRelic": "+ 유물 추가",
|
||||||
|
"modalAddLcTitle": "🗡️ FreeSR에 광추 추가",
|
||||||
|
"modalAddRelicTitle": "🛡️ FreeSR에 유물 추가",
|
||||||
|
"lblSelectLc": "광추 선택",
|
||||||
|
"lblSelectRelicSet": "유물 세트 선택",
|
||||||
|
"lblRelicSlot": "부위",
|
||||||
|
"lblMainAffix": "메인 속성",
|
||||||
|
"lblEquipAvatar": "캐릭터에 장착",
|
||||||
|
"unassigned": "-- 미장착 (인벤토리) --",
|
||||||
|
"btnAddLcSubmit": "💾 FreeSR에 추가",
|
||||||
|
"btnAddRelicSubmit": "💾 FreeSR에 추가",
|
||||||
|
"toastLcAdded": "FreeSR에 광추가 추가되었습니다",
|
||||||
|
"toastRelicAdded": "FreeSR에 유물이 추가되었습니다",
|
||||||
|
"deleteItem": "삭제",
|
||||||
|
"toastItemDeleted": "아이템이 삭제되었습니다",
|
||||||
|
|
||||||
"appName": "GaC-Srtool",
|
"appName": "GaC-Srtool",
|
||||||
"appSubtitle": "스타레일 FreeSR & 서버 컨트롤러",
|
"appSubtitle": "스타레일 FreeSR & 서버 컨트롤러",
|
||||||
"online": "연결됨",
|
"online": "연결됨",
|
||||||
@@ -1075,6 +1183,24 @@ export const TRANSLATIONS = {
|
|||||||
"settingsReset": "기본 설정으로 복원되었습니다"
|
"settingsReset": "기본 설정으로 복원되었습니다"
|
||||||
},
|
},
|
||||||
"vi": {
|
"vi": {
|
||||||
|
"ahaGlobalDesc": "Bật cơ chế đặc biệt Aeon ★ Aha toàn máy chủ",
|
||||||
|
"btnAddLc": "+ Thêm Nón Ánh Sáng",
|
||||||
|
"btnAddRelic": "+ Thêm Di Vật",
|
||||||
|
"modalAddLcTitle": "🗡️ Thêm Nón Ánh Sáng vào FreeSR",
|
||||||
|
"modalAddRelicTitle": "🛡️ Thêm Di Vật vào FreeSR",
|
||||||
|
"lblSelectLc": "Chọn Nón Ánh Sáng",
|
||||||
|
"lblSelectRelicSet": "Chọn Bộ Di Vật",
|
||||||
|
"lblRelicSlot": "Vị trí Di Vật",
|
||||||
|
"lblMainAffix": "Thuộc tính chính",
|
||||||
|
"lblEquipAvatar": "Trang bị cho nhân vật",
|
||||||
|
"unassigned": "-- Chưa trang bị (Kho đồ) --",
|
||||||
|
"btnAddLcSubmit": "💾 Thêm vào FreeSR",
|
||||||
|
"btnAddRelicSubmit": "💾 Thêm vào FreeSR",
|
||||||
|
"toastLcAdded": "Đã thêm Nón Ánh Sáng vào FreeSR",
|
||||||
|
"toastRelicAdded": "Đã thêm Di Vật vào FreeSR",
|
||||||
|
"deleteItem": "Xóa",
|
||||||
|
"toastItemDeleted": "Đã xóa vật phẩm thành công",
|
||||||
|
|
||||||
"appName": "GaC-Srtool",
|
"appName": "GaC-Srtool",
|
||||||
"appSubtitle": "Bộ điều khiển máy chủ & FreeSR Star Rail",
|
"appSubtitle": "Bộ điều khiển máy chủ & FreeSR Star Rail",
|
||||||
"online": "Đã kết nối",
|
"online": "Đã kết nối",
|
||||||
@@ -1251,6 +1377,24 @@ export const TRANSLATIONS = {
|
|||||||
"settingsReset": "Đã khôi phục cài đặt mặc định"
|
"settingsReset": "Đã khôi phục cài đặt mặc định"
|
||||||
},
|
},
|
||||||
"id": {
|
"id": {
|
||||||
|
"ahaGlobalDesc": "Aktifkan kemampuan khusus Aeon ★ Aha di seluruh server",
|
||||||
|
"btnAddLc": "+ Tambah Light Cone",
|
||||||
|
"btnAddRelic": "+ Tambah Relic",
|
||||||
|
"modalAddLcTitle": "🗡️ Tambah Light Cone ke FreeSR",
|
||||||
|
"modalAddRelicTitle": "🛡️ Tambah Relic ke FreeSR",
|
||||||
|
"lblSelectLc": "Pilih Light Cone",
|
||||||
|
"lblSelectRelicSet": "Pilih Set Relic",
|
||||||
|
"lblRelicSlot": "Slot Relic",
|
||||||
|
"lblMainAffix": "Stat Utama",
|
||||||
|
"lblEquipAvatar": "Pasang ke Karakter",
|
||||||
|
"unassigned": "-- Belum Dipasang (Tas) --",
|
||||||
|
"btnAddLcSubmit": "💾 Tambah ke FreeSR",
|
||||||
|
"btnAddRelicSubmit": "💾 Tambah ke FreeSR",
|
||||||
|
"toastLcAdded": "Light Cone berhasil ditambahkan ke FreeSR",
|
||||||
|
"toastRelicAdded": "Relic berhasil ditambahkan ke FreeSR",
|
||||||
|
"deleteItem": "Hapus",
|
||||||
|
"toastItemDeleted": "Item berhasil dihapus",
|
||||||
|
|
||||||
"appName": "GaC-Srtool",
|
"appName": "GaC-Srtool",
|
||||||
"appSubtitle": "Pengontrol Server & FreeSR Star Rail",
|
"appSubtitle": "Pengontrol Server & FreeSR Star Rail",
|
||||||
"online": "Terhubung",
|
"online": "Terhubung",
|
||||||
@@ -1427,6 +1571,24 @@ export const TRANSLATIONS = {
|
|||||||
"settingsReset": "Pengaturan dikembalikan ke default"
|
"settingsReset": "Pengaturan dikembalikan ke default"
|
||||||
},
|
},
|
||||||
"es": {
|
"es": {
|
||||||
|
"ahaGlobalDesc": "Activar rasgo especial de Eón ★ Aha en todo el servidor",
|
||||||
|
"btnAddLc": "+ Añadir cono de luz",
|
||||||
|
"btnAddRelic": "+ Añadir reliquia",
|
||||||
|
"modalAddLcTitle": "🗡️ Añadir cono de luz a FreeSR",
|
||||||
|
"modalAddRelicTitle": "🛡️ Añadir reliquia a FreeSR",
|
||||||
|
"lblSelectLc": "Seleccionar cono de luz",
|
||||||
|
"lblSelectRelicSet": "Seleccionar conjunto de reliquias",
|
||||||
|
"lblRelicSlot": "Ranura de reliquia",
|
||||||
|
"lblMainAffix": "Atributo principal",
|
||||||
|
"lblEquipAvatar": "Equipar a personaje",
|
||||||
|
"unassigned": "-- Sin equipar (Inventario) --",
|
||||||
|
"btnAddLcSubmit": "💾 Añadir a FreeSR",
|
||||||
|
"btnAddRelicSubmit": "💾 Añadir a FreeSR",
|
||||||
|
"toastLcAdded": "Cono de luz añadido a FreeSR",
|
||||||
|
"toastRelicAdded": "Reliquia añadida a FreeSR",
|
||||||
|
"deleteItem": "Eliminar",
|
||||||
|
"toastItemDeleted": "Objeto eliminado correctamente",
|
||||||
|
|
||||||
"appName": "GaC-Srtool",
|
"appName": "GaC-Srtool",
|
||||||
"appSubtitle": "Controlador de servidor y FreeSR de Star Rail",
|
"appSubtitle": "Controlador de servidor y FreeSR de Star Rail",
|
||||||
"online": "Conectado",
|
"online": "Conectado",
|
||||||
@@ -1603,6 +1765,24 @@ export const TRANSLATIONS = {
|
|||||||
"settingsReset": "Ajustes restablecidos por defecto"
|
"settingsReset": "Ajustes restablecidos por defecto"
|
||||||
},
|
},
|
||||||
"fr": {
|
"fr": {
|
||||||
|
"ahaGlobalDesc": "Activer le trait spécial d'Éon ★ Aha sur tout le serveur",
|
||||||
|
"btnAddLc": "+ Ajouter cône de lumière",
|
||||||
|
"btnAddRelic": "+ Ajouter relique",
|
||||||
|
"modalAddLcTitle": "🗡️ Ajouter cône de lumière à FreeSR",
|
||||||
|
"modalAddRelicTitle": "🛡️ Ajouter relique à FreeSR",
|
||||||
|
"lblSelectLc": "Sélectionner cône de lumière",
|
||||||
|
"lblSelectRelicSet": "Sélectionner ensemble de reliques",
|
||||||
|
"lblRelicSlot": "Emplacement de relique",
|
||||||
|
"lblMainAffix": "Statistique principale",
|
||||||
|
"lblEquipAvatar": "Équiper au personnage",
|
||||||
|
"unassigned": "-- Non équipé (Inventaire) --",
|
||||||
|
"btnAddLcSubmit": "💾 Ajouter à FreeSR",
|
||||||
|
"btnAddRelicSubmit": "💾 Ajouter à FreeSR",
|
||||||
|
"toastLcAdded": "Cône de lumière ajouté à FreeSR",
|
||||||
|
"toastRelicAdded": "Relique ajoutée à FreeSR",
|
||||||
|
"deleteItem": "Supprimer",
|
||||||
|
"toastItemDeleted": "Objet supprimé avec succès",
|
||||||
|
|
||||||
"appName": "GaC-Srtool",
|
"appName": "GaC-Srtool",
|
||||||
"appSubtitle": "Contrôleur de serveur et FreeSR Star Rail",
|
"appSubtitle": "Contrôleur de serveur et FreeSR Star Rail",
|
||||||
"online": "Connecté",
|
"online": "Connecté",
|
||||||
@@ -1779,6 +1959,24 @@ export const TRANSLATIONS = {
|
|||||||
"settingsReset": "Paramètres réinitialisés par défaut"
|
"settingsReset": "Paramètres réinitialisés par défaut"
|
||||||
},
|
},
|
||||||
"de": {
|
"de": {
|
||||||
|
"ahaGlobalDesc": "Serverweite Äon ★ Aha-Spezialmechanik aktivieren",
|
||||||
|
"btnAddLc": "+ Lichtkegel hinzufügen",
|
||||||
|
"btnAddRelic": "+ Relikt hinzufügen",
|
||||||
|
"modalAddLcTitle": "🗡️ Lichtkegel zu FreeSR hinzufügen",
|
||||||
|
"modalAddRelicTitle": "🛡️ Relikt zu FreeSR hinzufügen",
|
||||||
|
"lblSelectLc": "Lichtkegel auswählen",
|
||||||
|
"lblSelectRelicSet": "Reliktset auswählen",
|
||||||
|
"lblRelicSlot": "Reliktslot",
|
||||||
|
"lblMainAffix": "Hauptwert",
|
||||||
|
"lblEquipAvatar": "Figur ausrüsten",
|
||||||
|
"unassigned": "-- Nicht ausgerüstet (Inventar) --",
|
||||||
|
"btnAddLcSubmit": "💾 Zu FreeSR hinzufügen",
|
||||||
|
"btnAddRelicSubmit": "💾 Zu FreeSR hinzufügen",
|
||||||
|
"toastLcAdded": "Lichtkegel zu FreeSR hinzugefügt",
|
||||||
|
"toastRelicAdded": "Relikt zu FreeSR hinzugefügt",
|
||||||
|
"deleteItem": "Löschen",
|
||||||
|
"toastItemDeleted": "Gegenstand erfolgreich gelöscht",
|
||||||
|
|
||||||
"appName": "GaC-Srtool",
|
"appName": "GaC-Srtool",
|
||||||
"appSubtitle": "Star Rail FreeSR- & Server-Controller",
|
"appSubtitle": "Star Rail FreeSR- & Server-Controller",
|
||||||
"online": "Verbunden",
|
"online": "Verbunden",
|
||||||
@@ -1955,6 +2153,24 @@ export const TRANSLATIONS = {
|
|||||||
"settingsReset": "Auf Standardeinstellungen zurückgesetzt"
|
"settingsReset": "Auf Standardeinstellungen zurückgesetzt"
|
||||||
},
|
},
|
||||||
"ru": {
|
"ru": {
|
||||||
|
"ahaGlobalDesc": "Включить особый пассивный навык Эона ★ Аха по всему серверу",
|
||||||
|
"btnAddLc": "+ Добавить световой конус",
|
||||||
|
"btnAddRelic": "+ Добавить реликвию",
|
||||||
|
"modalAddLcTitle": "🗡️ Добавить световой конус в FreeSR",
|
||||||
|
"modalAddRelicTitle": "🛡️ Добавить реликвию в FreeSR",
|
||||||
|
"lblSelectLc": "Выберите световой конус",
|
||||||
|
"lblSelectRelicSet": "Выберите набор реликвий",
|
||||||
|
"lblRelicSlot": "Слот реликвии",
|
||||||
|
"lblMainAffix": "Основная характеристика",
|
||||||
|
"lblEquipAvatar": "Экипировать персонажу",
|
||||||
|
"unassigned": "-- Не экипировано (инвентарь) --",
|
||||||
|
"btnAddLcSubmit": "💾 Добавить в FreeSR",
|
||||||
|
"btnAddRelicSubmit": "💾 Добавить в FreeSR",
|
||||||
|
"toastLcAdded": "Световой конус добавлен в FreeSR",
|
||||||
|
"toastRelicAdded": "Реликвия добавлена в FreeSR",
|
||||||
|
"deleteItem": "Удалить",
|
||||||
|
"toastItemDeleted": "Предмет успешно удален",
|
||||||
|
|
||||||
"appName": "GaC-Srtool",
|
"appName": "GaC-Srtool",
|
||||||
"appSubtitle": "Контроллер сервера и FreeSR Star Rail",
|
"appSubtitle": "Контроллер сервера и FreeSR Star Rail",
|
||||||
"online": "Подключено",
|
"online": "Подключено",
|
||||||
@@ -2131,6 +2347,24 @@ export const TRANSLATIONS = {
|
|||||||
"settingsReset": "Настройки сброшены по умолчанию"
|
"settingsReset": "Настройки сброшены по умолчанию"
|
||||||
},
|
},
|
||||||
"pt": {
|
"pt": {
|
||||||
|
"ahaGlobalDesc": "Ativar habilidade passiva especial de Aeon ★ Aha em todo o servidor",
|
||||||
|
"btnAddLc": "+ Adicionar Cone de Luz",
|
||||||
|
"btnAddRelic": "+ Adicionar Relíquia",
|
||||||
|
"modalAddLcTitle": "🗡️ Adicionar Cone de Luz ao FreeSR",
|
||||||
|
"modalAddRelicTitle": "🛡️ Adicionar Relíquia ao FreeSR",
|
||||||
|
"lblSelectLc": "Selecionar Cone de Luz",
|
||||||
|
"lblSelectRelicSet": "Selecionar Conjunto de Relíquias",
|
||||||
|
"lblRelicSlot": "Espaço de Relíquia",
|
||||||
|
"lblMainAffix": "Atributo Principal",
|
||||||
|
"lblEquipAvatar": "Equipar ao Personagem",
|
||||||
|
"unassigned": "-- Não Equipado (Inventário) --",
|
||||||
|
"btnAddLcSubmit": "💾 Adicionar ao FreeSR",
|
||||||
|
"btnAddRelicSubmit": "💾 Adicionar ao FreeSR",
|
||||||
|
"toastLcAdded": "Cone de Luz adicionado ao FreeSR",
|
||||||
|
"toastRelicAdded": "Relíquia adicionada ao FreeSR",
|
||||||
|
"deleteItem": "Excluir",
|
||||||
|
"toastItemDeleted": "Item excluído com sucesso",
|
||||||
|
|
||||||
"appName": "GaC-Srtool",
|
"appName": "GaC-Srtool",
|
||||||
"appSubtitle": "Controlador de Servidor e FreeSR de Star Rail",
|
"appSubtitle": "Controlador de Servidor e FreeSR de Star Rail",
|
||||||
"online": "Conectado",
|
"online": "Conectado",
|
||||||
|
|||||||
Reference in new issue
Block a user