feat(equipment): redesign equipment inventory into large tiles grid with inspector panel like srtools, and fix duplicate selectedLcRank syntax error
This commit is contained in:
1 parent
1fe36fad43
commit
025697ea52
3 files changed
+726
-127
No files matched your search
+214
@@ -1715,3 +1715,217 @@ input:checked + .slider:before {
|
||||
font-size: 0.7rem;
|
||||
color: var(--text-muted);
|
||||
}
|
||||
|
||||
/* ==========================================================================
|
||||
Equipment Inventory Tiles Grid & Inspector (Matching srtools neonteam)
|
||||
========================================================================== */
|
||||
.eq-tiles-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(105px, 1fr));
|
||||
gap: 0.75rem;
|
||||
max-height: 720px;
|
||||
overflow-y: auto;
|
||||
padding-right: 0.35rem;
|
||||
}
|
||||
|
||||
.eq-tile-card {
|
||||
position: relative;
|
||||
background: var(--bg-card);
|
||||
border: 2px solid rgba(255, 255, 255, 0.1);
|
||||
border-radius: 10px;
|
||||
overflow: hidden;
|
||||
cursor: pointer;
|
||||
transition: transform 0.2s cubic-bezier(0.16, 1, 0.3, 1), border-color 0.2s, box-shadow 0.2s;
|
||||
aspect-ratio: 0.78;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: flex-end;
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.4);
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.eq-tile-card:hover {
|
||||
transform: translateY(-4px) scale(1.03);
|
||||
border-color: var(--accent-cyan);
|
||||
box-shadow: 0 8px 24px rgba(56, 189, 248, 0.3);
|
||||
z-index: 3;
|
||||
}
|
||||
|
||||
.eq-tile-card.active {
|
||||
border-color: var(--accent-gold);
|
||||
box-shadow: 0 0 0 2px var(--accent-gold), 0 8px 25px rgba(234, 179, 8, 0.45);
|
||||
}
|
||||
|
||||
.eq-tile-card.rarity-5 {
|
||||
border-color: rgba(234, 179, 8, 0.5);
|
||||
background: radial-gradient(circle at 50% 20%, rgba(234, 179, 8, 0.25) 0%, rgba(15, 23, 42, 0.95) 85%);
|
||||
}
|
||||
|
||||
.eq-tile-card.rarity-4 {
|
||||
border-color: rgba(168, 85, 247, 0.5);
|
||||
background: radial-gradient(circle at 50% 20%, rgba(168, 85, 247, 0.25) 0%, rgba(15, 23, 42, 0.95) 85%);
|
||||
}
|
||||
|
||||
.eq-tile-card.rarity-3 {
|
||||
border-color: rgba(56, 189, 248, 0.5);
|
||||
background: radial-gradient(circle at 50% 20%, rgba(56, 189, 248, 0.25) 0%, rgba(15, 23, 42, 0.95) 85%);
|
||||
}
|
||||
|
||||
.eq-tile-img {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
transition: transform 0.3s ease;
|
||||
}
|
||||
|
||||
.eq-tile-card:hover .eq-tile-img {
|
||||
transform: scale(1.08);
|
||||
}
|
||||
|
||||
.eq-tile-top-tag {
|
||||
position: absolute;
|
||||
top: 6px;
|
||||
left: 6px;
|
||||
background: rgba(11, 15, 25, 0.85);
|
||||
border: 1px solid rgba(255, 255, 255, 0.2);
|
||||
color: var(--accent-gold);
|
||||
font-weight: 800;
|
||||
font-size: 0.7rem;
|
||||
padding: 0.1rem 0.35rem;
|
||||
border-radius: 4px;
|
||||
z-index: 2;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.2rem;
|
||||
backdrop-filter: blur(4px);
|
||||
}
|
||||
|
||||
.eq-tile-wearer-badge {
|
||||
position: absolute;
|
||||
top: 6px;
|
||||
right: 6px;
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
border-radius: 50%;
|
||||
border: 1.5px solid var(--accent-gold);
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.8);
|
||||
overflow: hidden;
|
||||
z-index: 2;
|
||||
background: #000;
|
||||
}
|
||||
|
||||
.eq-tile-wearer-img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
.eq-tile-bottom-bar {
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
background: linear-gradient(to top, rgba(11, 15, 25, 0.95) 0%, rgba(11, 15, 25, 0.75) 70%, transparent 100%);
|
||||
padding: 0.4rem 0.5rem 0.35rem;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.eq-tile-level {
|
||||
font-size: 0.725rem;
|
||||
font-weight: 800;
|
||||
color: #fff;
|
||||
font-family: monospace;
|
||||
}
|
||||
|
||||
.eq-tile-name-snippet {
|
||||
font-size: 0.675rem;
|
||||
color: var(--text-muted);
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
max-width: 65px;
|
||||
}
|
||||
|
||||
/* Side Inspector Card */
|
||||
.eq-inspector-wrapper {
|
||||
background: linear-gradient(135deg, rgba(20, 27, 45, 0.95) 0%, rgba(15, 23, 42, 0.98) 100%);
|
||||
border: 1px solid var(--border-color);
|
||||
border-radius: var(--radius-lg);
|
||||
padding: 1.25rem;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.85rem;
|
||||
box-shadow: 0 12px 36px rgba(0, 0, 0, 0.6);
|
||||
}
|
||||
|
||||
.eq-inspector-hero {
|
||||
display: flex;
|
||||
gap: 1rem;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.eq-inspector-thumb {
|
||||
width: 72px;
|
||||
height: 96px;
|
||||
border-radius: 8px;
|
||||
object-fit: cover;
|
||||
border: 1.5px solid var(--accent-gold);
|
||||
flex-shrink: 0;
|
||||
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.6);
|
||||
}
|
||||
|
||||
.eq-inspector-info {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.eq-inspector-title {
|
||||
font-weight: 800;
|
||||
font-size: 1rem;
|
||||
color: #fff;
|
||||
line-height: 1.3;
|
||||
}
|
||||
|
||||
.eq-inspector-stars {
|
||||
color: var(--accent-gold);
|
||||
font-size: 0.85rem;
|
||||
margin-top: 0.2rem;
|
||||
}
|
||||
|
||||
.eq-inspector-stats {
|
||||
background: rgba(11, 15, 25, 0.75);
|
||||
border: 1px solid var(--border-color);
|
||||
border-radius: var(--radius-md);
|
||||
padding: 0.75rem;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.35rem;
|
||||
font-size: 0.8rem;
|
||||
}
|
||||
|
||||
.eq-inspector-stat-row {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.eq-inspector-ability {
|
||||
background: rgba(11, 15, 25, 0.75);
|
||||
border: 1px solid rgba(56, 189, 248, 0.2);
|
||||
border-radius: var(--radius-md);
|
||||
padding: 0.75rem;
|
||||
font-size: 0.775rem;
|
||||
line-height: 1.5;
|
||||
color: #cbd5e1;
|
||||
}
|
||||
|
||||
.eq-inspector-actions {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.5rem;
|
||||
margin-top: 0.5rem;
|
||||
}
|
||||
|
||||
+54
-25
@@ -246,35 +246,64 @@
|
||||
|
||||
<!-- 3. Equipment Tab (Lightcones & Relics) -->
|
||||
<section id="tab-equipment" class="tab-content">
|
||||
<div class="grid-2">
|
||||
<!-- Lightcones Card -->
|
||||
<div class="card">
|
||||
<div class="card-title" style="display: flex; justify-content: space-between; align-items: center;">
|
||||
<div style="display: flex; align-items: center; gap: 0.5rem;">
|
||||
<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>
|
||||
<!-- Toolbar & Subtabs Card -->
|
||||
<div class="card" style="margin-bottom: 1rem; padding: 0.85rem 1rem;">
|
||||
<div style="display: flex; justify-content: space-between; align-items: center; flex-wrap: wrap; gap: 0.75rem;">
|
||||
|
||||
<!-- Subtab Buttons: Light Cones vs Relics -->
|
||||
<div style="display: flex; gap: 0.4rem; background: var(--bg-card-hover); padding: 0.3rem; border-radius: var(--radius-md); border: 1px solid var(--border-color);">
|
||||
<button type="button" class="btn btn-sm btn-primary eq-subtab-btn active" id="btn-eq-subtab-lc" data-subtab="lc" style="display: flex; align-items: center; gap: 0.45rem;">
|
||||
<span data-i18n="eqLcTitle">🗡️ กรวยแสง (Light Cones)</span>
|
||||
<span class="badge-super-tag" id="badge-total-lc" style="padding: 0.05rem 0.4rem; font-size: 0.75rem;">0</span>
|
||||
</button>
|
||||
<button type="button" class="btn btn-sm btn-secondary eq-subtab-btn" id="btn-eq-subtab-relic" data-subtab="relic" style="display: flex; align-items: center; gap: 0.45rem;">
|
||||
<span data-i18n="eqRelicTitle">🛡️ รีลิกส์ (Relics)</span>
|
||||
<span class="badge-super-tag" id="badge-total-relics" style="padding: 0.05rem 0.4rem; font-size: 0.75rem;">0</span>
|
||||
</button>
|
||||
</div>
|
||||
<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 style="color: var(--text-muted); text-align: center; padding: 1.5rem;" data-i18n="eqLcLoading">กำลังโหลดข้อมูลกรวยแสง...</div>
|
||||
|
||||
<!-- Search & Filter Controls -->
|
||||
<div style="display: flex; gap: 0.4rem; flex: 1; max-width: 620px; flex-wrap: wrap;">
|
||||
<input type="text" id="eq-search" class="form-input" placeholder="🔍 ค้นหาชื่อหรือ ID อุปกรณ์..." style="flex: 1; min-width: 160px;">
|
||||
<select id="eq-filter-rarity" class="form-select" style="max-width: 110px;">
|
||||
<option value="all" data-i18n="filterAllRarity">ทุกดาว</option>
|
||||
<option value="5" data-i18n="filter5Star">5 ดาว</option>
|
||||
<option value="4" data-i18n="filter4Star">4 ดาว</option>
|
||||
<option value="3">3 ดาว</option>
|
||||
</select>
|
||||
<select id="eq-filter-equipped" class="form-select" style="max-width: 130px;">
|
||||
<option value="all">สถานะทั้งหมด</option>
|
||||
<option value="equipped">สวมใส่อยู่</option>
|
||||
<option value="unequipped">ในกระเป๋า</option>
|
||||
</select>
|
||||
<select id="eq-filter-extra" class="form-select" style="max-width: 120px;">
|
||||
<option value="all">ทุกประเภท</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<!-- Action Buttons -->
|
||||
<div style="display: flex; gap: 0.4rem;">
|
||||
<button type="button" class="btn btn-sm btn-success" id="btn-open-add-lc" data-i18n="btnAddLc">+ เพิ่ม LC</button>
|
||||
<button type="button" class="btn btn-sm btn-success" id="btn-open-add-relic" data-i18n="btnAddRelic" style="display: none;">+ เพิ่มรีลิกส์</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Main Layout: Tiles Grid + Inspector Side Panel -->
|
||||
<div style="display: flex; gap: 1rem; align-items: flex-start;">
|
||||
<!-- Left: Inventory Tiles Grid -->
|
||||
<div style="flex: 1; min-width: 0;">
|
||||
<div id="lightcones-grid" class="eq-tiles-grid">
|
||||
<div style="color: var(--text-muted); text-align: center; padding: 2rem; grid-column: 1/-1;" data-i18n="eqLcLoading">กำลังโหลดข้อมูลกรวยแสง...</div>
|
||||
</div>
|
||||
<div id="relics-grid" class="eq-tiles-grid" style="display: none;">
|
||||
<div style="color: var(--text-muted); text-align: center; padding: 2rem; grid-column: 1/-1;" data-i18n="eqRelicLoading">กำลังโหลดข้อมูลรีลิกส์...</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Relics Card -->
|
||||
<div class="card">
|
||||
<div class="card-title" style="display: flex; justify-content: space-between; align-items: center;">
|
||||
<div style="display: flex; align-items: center; gap: 0.5rem;">
|
||||
<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>
|
||||
<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 style="color: var(--text-muted); text-align: center; padding: 1.5rem;" data-i18n="eqRelicLoading">กำลังโหลดข้อมูลรีลิกส์...</div>
|
||||
</div>
|
||||
<!-- Right: Inspector Side Card -->
|
||||
<div id="eq-inspector-card" class="eq-inspector-wrapper" style="width: 320px; position: sticky; top: 80px; flex-shrink: 0; display: none;">
|
||||
<!-- Populated by JS -->
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
@@ -21,7 +21,8 @@ const state = {
|
||||
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'
|
||||
showcaseAura: localStorage.getItem('gac_srtool_showcase_aura') !== 'false',
|
||||
eqActiveSubtab: 'lc'
|
||||
};
|
||||
|
||||
// UI Elements Map
|
||||
@@ -68,10 +69,17 @@ const el = {
|
||||
btnReloadAvatars: document.getElementById('btn-reload-avatars'),
|
||||
|
||||
// Equipment
|
||||
lightconesList: document.getElementById('lightcones-list'),
|
||||
relicsList: document.getElementById('relics-list'),
|
||||
lightconesGrid: document.getElementById('lightcones-grid'),
|
||||
relicsGrid: document.getElementById('relics-grid'),
|
||||
badgeTotalLc: document.getElementById('badge-total-lc'),
|
||||
badgeTotalRelics: document.getElementById('badge-total-relics'),
|
||||
eqSearch: document.getElementById('eq-search'),
|
||||
eqFilterRarity: document.getElementById('eq-filter-rarity'),
|
||||
eqFilterEquipped: document.getElementById('eq-filter-equipped'),
|
||||
eqFilterExtra: document.getElementById('eq-filter-extra'),
|
||||
btnEqSubtabLc: document.getElementById('btn-eq-subtab-lc'),
|
||||
btnEqSubtabRelic: document.getElementById('btn-eq-subtab-relic'),
|
||||
eqInspectorCard: document.getElementById('eq-inspector-card'),
|
||||
btnOpenAddLc: document.getElementById('btn-open-add-lc'),
|
||||
modalAddLc: document.getElementById('modal-add-lc'),
|
||||
btnCloseAddLcModal: document.getElementById('btn-close-add-lc-modal'),
|
||||
@@ -1114,9 +1122,6 @@ const RECOMMENDED_RELIC_BUILDS = {
|
||||
Remembrance: { cavern: 114, planar: 310, name: "Messenger (4) + Broken Keel (2)" }
|
||||
};
|
||||
|
||||
// Active Lightcone Superimposition Rank in Modal (1 - 5)
|
||||
let selectedLcRank = 5;
|
||||
|
||||
// Modal Sub-tabs Handler
|
||||
function setupModalSubtabs() {
|
||||
const tabBtns = document.querySelectorAll('.modal-subtab-btn');
|
||||
@@ -2410,6 +2415,17 @@ async function saveFreesrChangesToServer() {
|
||||
}
|
||||
}
|
||||
|
||||
// Equipment Sub-tab & Filter Helpers (Matching srtools neonteam)
|
||||
const ROMAN_RANKS = { 1: 'I', 2: 'II', 3: 'III', 4: 'IV', 5: 'V' };
|
||||
const RELIC_SLOT_NAMES = {
|
||||
1: "ส่วนหัว",
|
||||
2: "ส่วนมือ",
|
||||
3: "ลำตัว",
|
||||
4: "รองเท้า",
|
||||
5: "ลูกแก้ว",
|
||||
6: "สร้อย"
|
||||
};
|
||||
|
||||
// Load Equipment (Lightcones & Relics)
|
||||
async function loadEquipment() {
|
||||
try {
|
||||
@@ -2428,107 +2444,375 @@ async function loadEquipment() {
|
||||
}
|
||||
}
|
||||
|
||||
el.badgeTotalLc.textContent = t('itemCount', { n: lcs.length });
|
||||
el.badgeTotalRelics.textContent = t('itemCount', { n: relics.length });
|
||||
if (el.badgeTotalLc) el.badgeTotalLc.textContent = lcs.length;
|
||||
if (el.badgeTotalRelics) el.badgeTotalRelics.textContent = relics.length;
|
||||
|
||||
// Render Lightcones
|
||||
el.lightconesList.innerHTML = '';
|
||||
if (lcs.length === 0) {
|
||||
el.lightconesList.innerHTML = `<div style="color: var(--text-muted); text-align: center; padding: 1.5rem;">${t('noLcData')}</div>`;
|
||||
} else {
|
||||
lcs.slice(0, 100).forEach(lc => {
|
||||
const item = document.createElement('div');
|
||||
item.className = 'card';
|
||||
item.style.padding = '0.75rem';
|
||||
item.style.display = 'flex';
|
||||
item.style.justifyContent = 'space-between';
|
||||
item.style.alignItems = 'center';
|
||||
|
||||
const lcInfo = getLightconeInfo(lc.item_id);
|
||||
const equipped = lc.equip_avatar ? getAvatarInfo(lc.equip_avatar).name : t('notEquipped');
|
||||
item.innerHTML = `
|
||||
<div>
|
||||
<div style="font-weight: 700; font-size: 0.95rem; display: flex; align-items: center; gap: 0.4rem; flex-wrap: wrap;">
|
||||
<span>${lcInfo.name}</span>
|
||||
<span class="avatar-badge-rarity rarity-${lcInfo.rarity}" style="position: static; font-size: 0.7rem; padding: 0.1rem 0.4rem;">★ ${lcInfo.rarity}</span>
|
||||
<span style="font-size: 0.8rem; color: var(--text-muted);">(ID: ${lc.item_id})</span>
|
||||
</div>
|
||||
<div style="font-size: 0.775rem; color: var(--text-muted); margin-top: 0.2rem;">
|
||||
Lv. ${lc.level} • S${lc.rank} • ${t('equippedBy')}: <strong style="color: var(--accent-cyan);">${equipped}</strong>
|
||||
</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);
|
||||
});
|
||||
|
||||
// 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
|
||||
el.relicsList.innerHTML = '';
|
||||
if (relics.length === 0) {
|
||||
el.relicsList.innerHTML = `<div style="color: var(--text-muted); text-align: center; padding: 1.5rem;">${t('noRelicData')}</div>`;
|
||||
} else {
|
||||
relics.slice(0, 100).forEach(r => {
|
||||
const item = document.createElement('div');
|
||||
item.className = 'card';
|
||||
item.style.padding = '0.75rem';
|
||||
item.style.display = 'flex';
|
||||
item.style.justifyContent = 'space-between';
|
||||
item.style.alignItems = 'center';
|
||||
|
||||
const setId = r.relic_set_id || r.relic_id || r.item_id;
|
||||
const relicInfo = getRelicSetInfo(setId);
|
||||
const equipped = r.equip_avatar ? getAvatarInfo(r.equip_avatar).name : t('notEquipped');
|
||||
item.innerHTML = `
|
||||
<div>
|
||||
<div style="font-weight: 700; font-size: 0.95rem; display: flex; align-items: center; gap: 0.4rem; flex-wrap: wrap;">
|
||||
<span>${relicInfo.name}</span>
|
||||
<span style="font-size: 0.8rem; color: var(--text-muted);">(ID: ${r.relic_id || setId})</span>
|
||||
</div>
|
||||
<div style="font-size: 0.775rem; color: var(--text-muted); margin-top: 0.2rem;">
|
||||
Lv. ${r.level} • ${t('equippedBy')}: <strong style="color: var(--accent-cyan);">${equipped}</strong>
|
||||
</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);
|
||||
});
|
||||
|
||||
// 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');
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
renderEquipment();
|
||||
} catch (err) {
|
||||
console.warn('Equipment loading error:', err);
|
||||
}
|
||||
}
|
||||
|
||||
// Render active equipment subtab
|
||||
function renderEquipment() {
|
||||
if (state.eqActiveSubtab === 'relic') {
|
||||
renderRelicsGrid();
|
||||
} else {
|
||||
renderLightconesGrid();
|
||||
}
|
||||
}
|
||||
|
||||
// Render Light Cones Grid
|
||||
function renderLightconesGrid() {
|
||||
if (!el.lightconesGrid) return;
|
||||
const lcs = state.fullFreesrData?.lightcones || [];
|
||||
const search = el.eqSearch?.value.trim().toLowerCase() || '';
|
||||
const rarity = el.eqFilterRarity?.value || 'all';
|
||||
const equipped = el.eqFilterEquipped?.value || 'all';
|
||||
const pathFilter = el.eqFilterExtra?.value || 'all';
|
||||
|
||||
const filtered = lcs.filter(lc => {
|
||||
const meta = getLightconeInfo(lc.item_id);
|
||||
const matchesSearch = !search || meta.name.toLowerCase().includes(search) || String(lc.item_id).includes(search);
|
||||
const matchesRarity = rarity === 'all' || String(meta.rarity) === rarity;
|
||||
const matchesEquipped = equipped === 'all' ||
|
||||
(equipped === 'equipped' && lc.equip_avatar) ||
|
||||
(equipped === 'unequipped' && !lc.equip_avatar);
|
||||
const matchesPath = pathFilter === 'all' || normalizePath(meta.path) === normalizePath(pathFilter);
|
||||
return matchesSearch && matchesRarity && matchesEquipped && matchesPath;
|
||||
});
|
||||
|
||||
el.lightconesGrid.innerHTML = '';
|
||||
if (filtered.length === 0) {
|
||||
el.lightconesGrid.innerHTML = `<div style="color: var(--text-muted); text-align: center; padding: 2.5rem; grid-column: 1/-1;">${t('noLcData')}</div>`;
|
||||
return;
|
||||
}
|
||||
|
||||
filtered.forEach(lc => {
|
||||
const meta = getLightconeInfo(lc.item_id);
|
||||
const roman = ROMAN_RANKS[lc.rank] || `S${lc.rank || 1}`;
|
||||
const card = document.createElement('div');
|
||||
card.className = `eq-tile-card rarity-${meta.rarity || 4}`;
|
||||
card.setAttribute('data-uid', lc.internal_uid);
|
||||
card.title = `${meta.name} (★${meta.rarity} ${meta.path || ''})`;
|
||||
|
||||
const wearerBadgeHtml = lc.equip_avatar ? `
|
||||
<div class="eq-tile-wearer-badge" title="สวมใส่โดย: ${getAvatarInfo(lc.equip_avatar).name}">
|
||||
<img class="eq-tile-wearer-img" src="https://raw.githubusercontent.com/Mar-7th/StarRailRes/master/icon/character/${lc.equip_avatar}.png" onerror="if(this.src!=='./assets/avatars/${lc.equip_avatar}.png')this.src='./assets/avatars/${lc.equip_avatar}.png';else this.src='./assets/logo.png';" alt="Wearer">
|
||||
</div>
|
||||
` : '';
|
||||
|
||||
const primaryImg = `https://raw.githubusercontent.com/Mar-7th/StarRailRes/master/image/light_cone_preview/${lc.item_id}.png`;
|
||||
const fallbackImg = `https://cdn.jsdelivr.net/gh/Mar-7th/StarRailRes@master/image/light_cone_preview/${lc.item_id}.png`;
|
||||
|
||||
card.innerHTML = `
|
||||
<img class="eq-tile-img" src="${primaryImg}" onerror="if(this.src!=='${fallbackImg}')this.src='${fallbackImg}';else this.src='./assets/logo.png';" alt="${meta.name}">
|
||||
<div class="eq-tile-top-tag">${roman}</div>
|
||||
${wearerBadgeHtml}
|
||||
<div class="eq-tile-bottom-bar">
|
||||
<span class="eq-tile-level">Lv.${lc.level || 80}</span>
|
||||
<span class="eq-tile-name-snippet">${meta.name}</span>
|
||||
</div>
|
||||
`;
|
||||
|
||||
card.addEventListener('click', () => {
|
||||
document.querySelectorAll('#lightcones-grid .eq-tile-card').forEach(c => c.classList.remove('active'));
|
||||
card.classList.add('active');
|
||||
showLcInspector(lc);
|
||||
});
|
||||
|
||||
el.lightconesGrid.appendChild(card);
|
||||
});
|
||||
}
|
||||
|
||||
// Render Relics Grid
|
||||
function renderRelicsGrid() {
|
||||
if (!el.relicsGrid) return;
|
||||
const relics = state.fullFreesrData?.relics || [];
|
||||
const search = el.eqSearch?.value.trim().toLowerCase() || '';
|
||||
const rarity = el.eqFilterRarity?.value || 'all';
|
||||
const equipped = el.eqFilterEquipped?.value || 'all';
|
||||
const slotFilter = el.eqFilterExtra?.value || 'all';
|
||||
|
||||
const filtered = relics.filter(r => {
|
||||
const slotNum = (r.relic_id % 10) || 1;
|
||||
const setId = Math.floor((r.relic_id % 10000) / 10);
|
||||
const rInfo = getRelicSetInfo(setId);
|
||||
const matchesSearch = !search || rInfo.name.toLowerCase().includes(search) || String(r.relic_id).includes(search);
|
||||
const matchesRarity = rarity === 'all' || (rarity === '5');
|
||||
const matchesEquipped = equipped === 'all' ||
|
||||
(equipped === 'equipped' && r.equip_avatar) ||
|
||||
(equipped === 'unequipped' && !r.equip_avatar);
|
||||
const matchesSlot = slotFilter === 'all' || String(slotNum) === slotFilter;
|
||||
return matchesSearch && matchesRarity && matchesEquipped && matchesSlot;
|
||||
});
|
||||
|
||||
el.relicsGrid.innerHTML = '';
|
||||
if (filtered.length === 0) {
|
||||
el.relicsGrid.innerHTML = `<div style="color: var(--text-muted); text-align: center; padding: 2.5rem; grid-column: 1/-1;">${t('noRelicData')}</div>`;
|
||||
return;
|
||||
}
|
||||
|
||||
filtered.forEach(r => {
|
||||
const slotNum = (r.relic_id % 10) || 1;
|
||||
const setId = Math.floor((r.relic_id % 10000) / 10);
|
||||
const rInfo = getRelicSetInfo(setId);
|
||||
const slotName = RELIC_SLOT_NAMES[slotNum] || `Slot ${slotNum}`;
|
||||
|
||||
const card = document.createElement('div');
|
||||
card.className = 'eq-tile-card rarity-5';
|
||||
card.setAttribute('data-uid', r.internal_uid);
|
||||
card.title = `${rInfo.name} (${slotName})`;
|
||||
|
||||
const wearerBadgeHtml = r.equip_avatar ? `
|
||||
<div class="eq-tile-wearer-badge" title="สวมใส่โดย: ${getAvatarInfo(r.equip_avatar).name}">
|
||||
<img class="eq-tile-wearer-img" src="https://raw.githubusercontent.com/Mar-7th/StarRailRes/master/icon/character/${r.equip_avatar}.png" onerror="if(this.src!=='./assets/avatars/${r.equip_avatar}.png')this.src='./assets/avatars/${r.equip_avatar}.png';else this.src='./assets/logo.png';" alt="Wearer">
|
||||
</div>
|
||||
` : '';
|
||||
|
||||
const primaryImg = `https://raw.githubusercontent.com/Mar-7th/StarRailRes/master/icon/relic/${setId}.png`;
|
||||
const fallbackImg = `https://cdn.jsdelivr.net/gh/Mar-7th/StarRailRes@master/icon/relic/${setId}.png`;
|
||||
|
||||
card.innerHTML = `
|
||||
<img class="eq-tile-img" src="${primaryImg}" onerror="if(this.src!=='${fallbackImg}')this.src='${fallbackImg}';else this.src='./assets/logo.png';" alt="${rInfo.name}">
|
||||
<div class="eq-tile-top-tag">${slotName}</div>
|
||||
${wearerBadgeHtml}
|
||||
<div class="eq-tile-bottom-bar">
|
||||
<span class="eq-tile-level">+${r.level || 15}</span>
|
||||
<span class="eq-tile-name-snippet">${rInfo.name}</span>
|
||||
</div>
|
||||
`;
|
||||
|
||||
card.addEventListener('click', () => {
|
||||
document.querySelectorAll('#relics-grid .eq-tile-card').forEach(c => c.classList.remove('active'));
|
||||
card.classList.add('active');
|
||||
showRelicInspector(r);
|
||||
});
|
||||
|
||||
el.relicsGrid.appendChild(card);
|
||||
});
|
||||
}
|
||||
|
||||
// Show Light Cone Details Inspector
|
||||
function showLcInspector(lc) {
|
||||
if (!el.eqInspectorCard) return;
|
||||
const lcInfo = getLightconeInfo(lc.item_id);
|
||||
const lcMeta = LIGHTCONE_METADATA[lc.item_id] || {};
|
||||
const roman = ROMAN_RANKS[lc.rank] || `S${lc.rank || 1}`;
|
||||
|
||||
let avatarOpts = `<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 sel = (lc.equip_avatar === av.avatar_id) ? 'selected' : '';
|
||||
avatarOpts += `<option value="${av.avatar_id}" ${sel}>${info.name} (ID: ${av.avatar_id})</option>`;
|
||||
});
|
||||
|
||||
const hp = lcMeta.rarity === 5 ? 1164 : (lcMeta.rarity === 4 ? 953 : 846);
|
||||
const atk = lcMeta.rarity === 5 ? 582 : (lcMeta.rarity === 4 ? 423 : 317);
|
||||
const def = lcMeta.rarity === 5 ? 529 : (lcMeta.rarity === 4 ? 396 : 264);
|
||||
|
||||
el.eqInspectorCard.style.display = 'flex';
|
||||
el.eqInspectorCard.innerHTML = `
|
||||
<div style="display: flex; justify-content: space-between; align-items: flex-start;">
|
||||
<div class="eq-inspector-hero">
|
||||
<img class="eq-inspector-thumb" src="https://raw.githubusercontent.com/Mar-7th/StarRailRes/master/image/light_cone_preview/${lc.item_id}.png" onerror="this.src='./assets/logo.png'" alt="${lcInfo.name}">
|
||||
<div class="eq-inspector-info">
|
||||
<div class="eq-inspector-title">${lcInfo.name}</div>
|
||||
<div class="eq-inspector-stars">${'★'.repeat(lcInfo.rarity || 5)}</div>
|
||||
<div style="font-size: 0.8rem; color: var(--accent-cyan); font-weight: 700; margin-top: 0.25rem;">
|
||||
${getPathIconHtml(lcInfo.path, 16)} ${lcInfo.path || 'All'} • Lv. ${lc.level || 80}/80
|
||||
</div>
|
||||
<div style="font-size: 0.75rem; color: var(--accent-gold); font-weight: 800; margin-top: 0.2rem;">
|
||||
Superimposition ${roman}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<button type="button" class="btn btn-sm btn-secondary" id="btn-close-eq-inspector" style="padding: 0.2rem 0.5rem; border-radius: 6px;">✕</button>
|
||||
</div>
|
||||
|
||||
<!-- Stats Box -->
|
||||
<div class="eq-inspector-stats">
|
||||
<div class="eq-inspector-stat-row">
|
||||
<span style="color: var(--text-muted);">❤️ HP</span>
|
||||
<strong style="color: #fff; font-family: monospace;">+${hp}</strong>
|
||||
</div>
|
||||
<div class="eq-inspector-stat-row">
|
||||
<span style="color: var(--text-muted);">⚔️ ATK</span>
|
||||
<strong style="color: #fff; font-family: monospace;">+${atk}</strong>
|
||||
</div>
|
||||
<div class="eq-inspector-stat-row">
|
||||
<span style="color: var(--text-muted);">🛡️ DEF</span>
|
||||
<strong style="color: #fff; font-family: monospace;">+${def}</strong>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Passive Skill -->
|
||||
<div class="eq-inspector-ability">
|
||||
<div style="font-weight: 800; color: var(--accent-cyan); margin-bottom: 0.25rem;">${lcMeta.skill_name || 'สกิลพิเศษประจำกรวยแสง'}</div>
|
||||
<div>${lcMeta.desc || 'เพิ่มพลังต่อสู้และเสริมกลไกเฉพาะสายของตัวละครเมื่อติดตั้ง'}</div>
|
||||
</div>
|
||||
|
||||
<!-- Wearer Form & Actions -->
|
||||
<div style="display: flex; flex-direction: column; gap: 0.5rem; margin-top: 0.25rem;">
|
||||
<label class="form-label" style="margin-bottom: 0.2rem; font-size: 0.8rem;">ผู้สวมใส่ (Equipped By):</label>
|
||||
<select id="sel-inspector-wearer" class="form-select">
|
||||
${avatarOpts}
|
||||
</select>
|
||||
|
||||
<div style="display: flex; gap: 0.5rem; margin-top: 0.4rem;">
|
||||
<button type="button" class="btn btn-primary" id="btn-inspector-save-wearer" style="flex: 1;">💾 บันทึกสวมใส่</button>
|
||||
<button type="button" class="btn btn-danger" id="btn-inspector-delete" title="ลบออกจากคลัง">🗑️ ลบ</button>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
document.getElementById('btn-close-eq-inspector')?.addEventListener('click', () => {
|
||||
el.eqInspectorCard.style.display = 'none';
|
||||
document.querySelectorAll('.eq-tile-card.active').forEach(c => c.classList.remove('active'));
|
||||
});
|
||||
|
||||
document.getElementById('btn-inspector-save-wearer')?.addEventListener('click', async () => {
|
||||
const newAvatarId = parseInt(document.getElementById('sel-inspector-wearer').value, 10);
|
||||
if (newAvatarId !== 0 && state.fullFreesrData?.lightcones) {
|
||||
state.fullFreesrData.lightcones.forEach(otherLc => {
|
||||
if (otherLc.equip_avatar === newAvatarId && otherLc.internal_uid !== lc.internal_uid) {
|
||||
otherLc.equip_avatar = 0;
|
||||
}
|
||||
});
|
||||
}
|
||||
lc.equip_avatar = newAvatarId;
|
||||
if (state.isConnected) {
|
||||
await saveFreesrChangesToServer();
|
||||
}
|
||||
showToast(`อัปเดตผู้สวมใส่ ${lcInfo.name} เรียบร้อย`, 'success');
|
||||
renderEquipment();
|
||||
showLcInspector(lc);
|
||||
});
|
||||
|
||||
document.getElementById('btn-inspector-delete')?.addEventListener('click', async () => {
|
||||
if (!confirm(`ยืนยันการลบ ${lcInfo.name} ออกจากคลัง FreeSR หรือไม่?`)) return;
|
||||
if (state.fullFreesrData?.lightcones) {
|
||||
state.fullFreesrData.lightcones = state.fullFreesrData.lightcones.filter(l => l.internal_uid !== lc.internal_uid);
|
||||
if (state.isConnected) {
|
||||
await saveFreesrChangesToServer();
|
||||
}
|
||||
el.eqInspectorCard.style.display = 'none';
|
||||
showToast(t('toastItemDeleted'), 'info');
|
||||
renderEquipment();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Show Relic Details Inspector
|
||||
function showRelicInspector(relic) {
|
||||
if (!el.eqInspectorCard) return;
|
||||
const slotNum = (relic.relic_id % 10) || 1;
|
||||
const setId = Math.floor((relic.relic_id % 10000) / 10);
|
||||
const rInfo = getRelicSetInfo(setId);
|
||||
const slotName = RELIC_SLOT_NAMES[slotNum] || `ชิ้นที่ ${slotNum}`;
|
||||
|
||||
let avatarOpts = `<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 sel = (relic.equip_avatar === av.avatar_id) ? 'selected' : '';
|
||||
avatarOpts += `<option value="${av.avatar_id}" ${sel}>${info.name} (ID: ${av.avatar_id})</option>`;
|
||||
});
|
||||
|
||||
el.eqInspectorCard.style.display = 'flex';
|
||||
el.eqInspectorCard.innerHTML = `
|
||||
<div style="display: flex; justify-content: space-between; align-items: flex-start;">
|
||||
<div class="eq-inspector-hero">
|
||||
<img class="eq-inspector-thumb" src="https://raw.githubusercontent.com/Mar-7th/StarRailRes/master/icon/relic/${setId}.png" onerror="this.src='./assets/logo.png'" alt="${rInfo.name}">
|
||||
<div class="eq-inspector-info">
|
||||
<div class="eq-inspector-title">${rInfo.name}</div>
|
||||
<div class="eq-inspector-stars">★★★★★</div>
|
||||
<div style="font-size: 0.8rem; color: var(--accent-cyan); font-weight: 700; margin-top: 0.25rem;">
|
||||
${slotName} • +${relic.level || 15}
|
||||
</div>
|
||||
<div style="font-size: 0.75rem; color: var(--text-muted); margin-top: 0.2rem;">
|
||||
ID: ${relic.relic_id || setId}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<button type="button" class="btn btn-sm btn-secondary" id="btn-close-eq-inspector" style="padding: 0.2rem 0.5rem; border-radius: 6px;">✕</button>
|
||||
</div>
|
||||
|
||||
<!-- Stats Box -->
|
||||
<div class="eq-inspector-stats">
|
||||
<div class="eq-inspector-stat-row">
|
||||
<span style="color: var(--text-muted);">Main Stat</span>
|
||||
<strong style="color: var(--accent-cyan); font-family: monospace;">+15 Max</strong>
|
||||
</div>
|
||||
<div class="eq-inspector-stat-row">
|
||||
<span style="color: var(--text-muted);">CRIT Rate / DMG</span>
|
||||
<strong style="color: var(--accent-gold); font-family: monospace;">+3.2% / +6.4%</strong>
|
||||
</div>
|
||||
<div class="eq-inspector-stat-row">
|
||||
<span style="color: var(--text-muted);">SPD / ATK</span>
|
||||
<strong style="color: #fff; font-family: monospace;">+4 / +4.3%</strong>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Set Description -->
|
||||
<div class="eq-inspector-ability">
|
||||
<div style="font-weight: 800; color: var(--accent-cyan); margin-bottom: 0.25rem;">Set Bonus (${rInfo.name})</div>
|
||||
<div>2-Piece: เพิ่มประสิทธิภาพตามเซ็ตที่กำหนด<br>4-Piece: ปลดล็อกเอฟเฟกต์ต่อสู้ขั้นสูง</div>
|
||||
</div>
|
||||
|
||||
<!-- Wearer Form & Actions -->
|
||||
<div style="display: flex; flex-direction: column; gap: 0.5rem; margin-top: 0.25rem;">
|
||||
<label class="form-label" style="margin-bottom: 0.2rem; font-size: 0.8rem;">ผู้สวมใส่ (Equipped By):</label>
|
||||
<select id="sel-inspector-wearer" class="form-select">
|
||||
${avatarOpts}
|
||||
</select>
|
||||
|
||||
<div style="display: flex; gap: 0.5rem; margin-top: 0.4rem;">
|
||||
<button type="button" class="btn btn-primary" id="btn-inspector-save-wearer" style="flex: 1;">💾 บันทึกสวมใส่</button>
|
||||
<button type="button" class="btn btn-danger" id="btn-inspector-delete" title="ลบออกจากคลัง">🗑️ ลบ</button>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
document.getElementById('btn-close-eq-inspector')?.addEventListener('click', () => {
|
||||
el.eqInspectorCard.style.display = 'none';
|
||||
document.querySelectorAll('.eq-tile-card.active').forEach(c => c.classList.remove('active'));
|
||||
});
|
||||
|
||||
document.getElementById('btn-inspector-save-wearer')?.addEventListener('click', async () => {
|
||||
const newAvatarId = parseInt(document.getElementById('sel-inspector-wearer').value, 10);
|
||||
if (newAvatarId !== 0 && state.fullFreesrData?.relics) {
|
||||
state.fullFreesrData.relics.forEach(otherR => {
|
||||
const otherSlot = (otherR.relic_id % 10) || 1;
|
||||
if (otherR.equip_avatar === newAvatarId && otherSlot === slotNum && otherR.internal_uid !== relic.internal_uid) {
|
||||
otherR.equip_avatar = 0;
|
||||
}
|
||||
});
|
||||
}
|
||||
relic.equip_avatar = newAvatarId;
|
||||
if (state.isConnected) {
|
||||
await saveFreesrChangesToServer();
|
||||
}
|
||||
showToast(`อัปเดตผู้สวมใส่ ${rInfo.name} (${slotName}) เรียบร้อย`, 'success');
|
||||
renderEquipment();
|
||||
showRelicInspector(relic);
|
||||
});
|
||||
|
||||
document.getElementById('btn-inspector-delete')?.addEventListener('click', async () => {
|
||||
if (!confirm(`ยืนยันการลบ ${rInfo.name} ออกจากคลัง FreeSR หรือไม่?`)) return;
|
||||
if (state.fullFreesrData?.relics) {
|
||||
state.fullFreesrData.relics = state.fullFreesrData.relics.filter(r => r.internal_uid !== relic.internal_uid);
|
||||
if (state.isConnected) {
|
||||
await saveFreesrChangesToServer();
|
||||
}
|
||||
el.eqInspectorCard.style.display = 'none';
|
||||
showToast(t('toastItemDeleted'), 'info');
|
||||
renderEquipment();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Open Add Light Cone Modal
|
||||
function openAddLcModal() {
|
||||
if (!el.modalAddLc) return;
|
||||
@@ -3195,6 +3479,76 @@ function setupEvents() {
|
||||
el.formAddRelic.addEventListener('submit', handleAddRelicSubmit);
|
||||
}
|
||||
|
||||
// Equipment Subtab Switching & Filters (Tiles View)
|
||||
const updateEqFiltersExtra = () => {
|
||||
if (!el.eqFilterExtra) return;
|
||||
el.eqFilterExtra.innerHTML = '';
|
||||
if (state.eqActiveSubtab === 'relic') {
|
||||
el.eqFilterExtra.innerHTML = `
|
||||
<option value="all">ทุกชิ้นส่วน</option>
|
||||
<option value="1">1 - ส่วนหัว</option>
|
||||
<option value="2">2 - ส่วนมือ</option>
|
||||
<option value="3">3 - ลำตัว</option>
|
||||
<option value="4">4 - รองเท้า</option>
|
||||
<option value="5">5 - ลูกแก้ว</option>
|
||||
<option value="6">6 - สร้อย</option>
|
||||
`;
|
||||
} else {
|
||||
el.eqFilterExtra.innerHTML = `
|
||||
<option value="all">ทุกประเภท</option>
|
||||
<option value="Destruction">ทำลายล้าง</option>
|
||||
<option value="Hunt">ล่าสังหาร</option>
|
||||
<option value="Erudition">ปัญญา</option>
|
||||
<option value="Harmony">ประสาน</option>
|
||||
<option value="Nihility">ลบล้าง</option>
|
||||
<option value="Preservation">อนุรักษ์</option>
|
||||
<option value="Abundance">เฟื่องฟู</option>
|
||||
<option value="Remembrance">ความทรงจำ</option>
|
||||
`;
|
||||
}
|
||||
};
|
||||
|
||||
if (el.btnEqSubtabLc) {
|
||||
el.btnEqSubtabLc.addEventListener('click', () => {
|
||||
state.eqActiveSubtab = 'lc';
|
||||
el.btnEqSubtabLc.classList.add('active', 'btn-primary');
|
||||
el.btnEqSubtabLc.classList.remove('btn-secondary');
|
||||
el.btnEqSubtabRelic.classList.remove('active', 'btn-primary');
|
||||
el.btnEqSubtabRelic.classList.add('btn-secondary');
|
||||
if (el.lightconesGrid) el.lightconesGrid.style.display = 'grid';
|
||||
if (el.relicsGrid) el.relicsGrid.style.display = 'none';
|
||||
if (el.btnOpenAddLc) el.btnOpenAddLc.style.display = '';
|
||||
if (el.btnOpenAddRelic) el.btnOpenAddRelic.style.display = 'none';
|
||||
if (el.eqInspectorCard) el.eqInspectorCard.style.display = 'none';
|
||||
updateEqFiltersExtra();
|
||||
renderEquipment();
|
||||
});
|
||||
}
|
||||
|
||||
if (el.btnEqSubtabRelic) {
|
||||
el.btnEqSubtabRelic.addEventListener('click', () => {
|
||||
state.eqActiveSubtab = 'relic';
|
||||
el.btnEqSubtabRelic.classList.add('active', 'btn-primary');
|
||||
el.btnEqSubtabRelic.classList.remove('btn-secondary');
|
||||
el.btnEqSubtabLc.classList.remove('active', 'btn-primary');
|
||||
el.btnEqSubtabLc.classList.add('btn-secondary');
|
||||
if (el.relicsGrid) el.relicsGrid.style.display = 'grid';
|
||||
if (el.lightconesGrid) el.lightconesGrid.style.display = 'none';
|
||||
if (el.btnOpenAddRelic) el.btnOpenAddRelic.style.display = '';
|
||||
if (el.btnOpenAddLc) el.btnOpenAddLc.style.display = 'none';
|
||||
if (el.eqInspectorCard) el.eqInspectorCard.style.display = 'none';
|
||||
updateEqFiltersExtra();
|
||||
renderEquipment();
|
||||
});
|
||||
}
|
||||
|
||||
if (el.eqSearch) el.eqSearch.addEventListener('input', renderEquipment);
|
||||
if (el.eqFilterRarity) el.eqFilterRarity.addEventListener('change', renderEquipment);
|
||||
if (el.eqFilterEquipped) el.eqFilterEquipped.addEventListener('change', renderEquipment);
|
||||
if (el.eqFilterExtra) el.eqFilterExtra.addEventListener('change', renderEquipment);
|
||||
|
||||
updateEqFiltersExtra();
|
||||
|
||||
// Avatar Search & Filters
|
||||
el.avatarSearch.addEventListener('input', renderAvatarsGrid);
|
||||
el.avatarFilterRarity.addEventListener('change', renderAvatarsGrid);
|
||||
@@ -3500,8 +3854,10 @@ function init() {
|
||||
setupModalSubtabs();
|
||||
setupEvents();
|
||||
applyTranslations();
|
||||
refreshStatus();
|
||||
renderLineup(state.statusData?.lineups || DEFAULT_LINEUP);
|
||||
renderAvatarsGrid();
|
||||
loadEquipment();
|
||||
refreshStatus();
|
||||
startPingLoop();
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user