diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index b666fc7..409ed20 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -2,7 +2,7 @@ name: Deploy GaC-Srtool to GitHub Pages on: push: - branches: ["main"] + branches: ["main", "test-gay"] workflow_dispatch: permissions: diff --git a/css/styles.css b/css/styles.css index 89ec74d..3cf2eb2 100644 --- a/css/styles.css +++ b/css/styles.css @@ -185,6 +185,9 @@ body { /* Navigation Tabs */ .nav-tabs { + position: sticky; + top: 65px; + z-index: 45; display: flex; gap: 0.35rem; background: var(--bg-secondary); diff --git a/index.html b/index.html index c7f8279..e88700e 100644 --- a/index.html +++ b/index.html @@ -233,13 +233,13 @@ ⚡ คำสั่งด่วนที่ใช้บ่อย (Quick Commands)
- - - - - - - + + + + + + +
diff --git a/js/app.js b/js/app.js index 4cadf2b..0033943 100644 --- a/js/app.js +++ b/js/app.js @@ -519,6 +519,29 @@ function updateFilterDropdownTranslations() { el.avatarFilterPath.value = selected; } + const addLcFilter = document.getElementById('add-lc-filter-path'); + if (addLcFilter) { + const selected = addLcFilter.value; + const paths = ['Destruction', 'Hunt', 'Erudition', 'Harmony', 'Nihility', 'Preservation', 'Abundance', 'Remembrance', 'Elation']; + if (addLcFilter.options[0]) addLcFilter.options[0].textContent = `${t('filterAllPaths') || 'ทุกสาย'} (All)`; + paths.forEach((p, idx) => { + if (addLcFilter.options[idx + 1]) addLcFilter.options[idx + 1].textContent = translatePath(p); + }); + addLcFilter.value = selected; + } + + const lcPickerFilter = document.getElementById('lc-picker-filter-path'); + if (lcPickerFilter) { + const selected = lcPickerFilter.value; + const paths = ['Destruction', 'Hunt', 'Erudition', 'Harmony', 'Nihility', 'Preservation', 'Abundance', 'Remembrance']; + if (lcPickerFilter.options[0]) lcPickerFilter.options[0].textContent = t('filterAllPaths') || 'ทุกสาย'; + if (lcPickerFilter.options[1]) lcPickerFilter.options[1].textContent = t('filterSamePath') || 'สายเดียวกัน'; + paths.forEach((p, idx) => { + if (lcPickerFilter.options[idx + 2]) lcPickerFilter.options[idx + 2].textContent = translatePath(p); + }); + lcPickerFilter.value = selected; + } + const dict = TRANSLATIONS[getCurrentLanguage()] || TRANSLATIONS.en || TRANSLATIONS.th; if (el.persistentMcSelect && dict.tbOptions) { const curVal = el.persistentMcSelect.value; @@ -1276,21 +1299,21 @@ function renderTeamSynergy(lineups) { totalEidolon += rank; // Element coverage - const elem = meta.element || 'Unknown'; - if (!coveredElements[elem]) { - coveredElements[elem] = []; + const rawElem = normalizeElement(meta.rawElement || meta.element); + if (!coveredElements[rawElem]) { + coveredElements[rawElem] = []; } - coveredElements[elem].push(meta.name); + coveredElements[rawElem].push(meta.name); // Path / Role - const path = meta.path || ''; - if (['Destruction', 'Hunt', 'Erudition'].includes(path)) { + const rawPath = normalizePath(meta.rawPath || meta.path); + if (['Destruction', 'Hunt', 'Erudition'].includes(rawPath)) { roles.dps.push(meta.name); - } else if (['Remembrance', 'Elation'].includes(path)) { + } else if (['Remembrance', 'Elation'].includes(rawPath)) { roles.specialist.push(meta.name); - } else if (['Harmony', 'Nihility'].includes(path)) { + } else if (['Harmony', 'Nihility'].includes(rawPath)) { roles.support.push(meta.name); - } else if (['Preservation', 'Abundance'].includes(path)) { + } else if (['Preservation', 'Abundance'].includes(rawPath)) { roles.sustain.push(meta.name); } @@ -1628,7 +1651,7 @@ function setupGMConsoleEvents() { } // Initial greeting - logToConsole('GaC Server Console พร้อมใช้งาน (พิมพ์ /help เพื่อดูคำสั่งทั้งหมด)', 'SYS'); + logToConsole(t('consoleReady') || 'GaC Server Console is ready (type /help for available commands)', 'SYS'); } // Add extra slot in Creative Mode @@ -2269,8 +2292,8 @@ function getOptimalBuildForAvatar(avatarId) { return CHARACTER_OPTIMAL_BUILDS[aid]; } const meta = getAvatarInfo(aid); - const elem = meta.rawElement || meta.element || 'Physical'; - const path = meta.rawPath || meta.path || 'Destruction'; + const elem = normalizeElement(meta.rawElement || meta.element); + const path = normalizePath(meta.rawPath || meta.path); const elemAffixMap = { Physical: 4, Fire: 5, Ice: 6, Lightning: 7, Thunder: 7, Wind: 8, Quantum: 9, Imaginary: 10 @@ -2544,7 +2567,7 @@ function populateModalChangeLcDropdown(avatarPath) { opt.value = id; opt.textContent = `★${info.rarity} [${info.path}] ${info.name} (ID: ${id})`; - if (meta.path === avatarPath) { + if (normalizePath(meta.path) === normalizePath(avatarPath)) { samePathGroup.appendChild(opt); } else { otherPathGroup.appendChild(opt); @@ -2859,9 +2882,9 @@ function renderModalOverviewTab(avatarId) { Quantum: 'QuantumAddedRatio', Imaginary: 'ImaginaryAddedRatio' }; - const elemKey = meta.rawElement || meta.element || 'Physical'; + const elemKey = normalizeElement(meta.rawElement || meta.element); const elemIcon = elemIconMap[elemKey] || 'PhysicalAddedRatio'; - const elemName = meta.element || elemKey; + const elemName = translateElement(elemKey); const elemDmgLabel = t('statDmgBoost').replace('{element}', elemName); const cdn = 'https://raw.githubusercontent.com/Mar-7th/StarRailRes/master/icon/property'; @@ -3674,8 +3697,8 @@ function renderLightconePickerGrid() { const info = getLightconeInfo(id); // Path match - if (pathFilter === 'same' && meta.path !== avatarMeta.path) return false; - if (pathFilter !== 'all' && pathFilter !== 'same' && meta.path !== pathFilter) return false; + if (pathFilter === 'same' && normalizePath(meta.path) !== normalizePath(avatarMeta.path)) return false; + if (pathFilter !== 'all' && pathFilter !== 'same' && normalizePath(meta.path) !== normalizePath(pathFilter)) return false; // Search match if (search) { @@ -4411,6 +4434,8 @@ function renderShowcaseCard(avatarId) { if (!el.showcaseCardContainer) return; const aid = parseInt(avatarId, 10); const meta = getAvatarInfo(aid); + const canonPath = normalizePath(meta.rawPath || meta.path); + const canonElem = normalizeElement(meta.rawElement || meta.element); const av = state.fullFreesrData?.avatars?.[aid]; const level = av?.level || state.selectedAvatarDetail?.level || 80; const rank = av?.data?.rank ?? state.selectedAvatarDetail?.rank ?? 6; @@ -4452,7 +4477,7 @@ function renderShowcaseCard(avatarId) { } if (activeSetBadges.length === 0) { - const rec = RECOMMENDED_RELIC_BUILDS[meta.path] || RECOMMENDED_RELIC_BUILDS.Preservation; + const rec = RECOMMENDED_RELIC_BUILDS[canonPath] || RECOMMENDED_RELIC_BUILDS.Preservation; activeSetBadges.push({ name: getRelicSetInfo(rec.cavern).name, count: 4 }); activeSetBadges.push({ name: getRelicSetInfo(rec.planar).name, count: 2 }); } @@ -4460,15 +4485,15 @@ function renderShowcaseCard(avatarId) { // Combat Stats const totalHp = Math.round((baseHp + lcHp) * 1.45 + 706); const totalAtk = Math.round((baseAtk + lcAtk) * 1.35 + 353); - const totalDef = Math.round((baseDef + lcDef) * 1.85 + (meta.path === 'Preservation' ? 1200 : 0)); + const totalDef = Math.round((baseDef + lcDef) * 1.85 + (canonPath === 'Preservation' ? 1200 : 0)); const totalSpd = (baseSpd + 25 + 10.5).toFixed(1); - const critRate = (5.0 + (meta.path === 'Hunt' || meta.path === 'Destruction' ? 65.4 : 18.8)).toFixed(1); - const critDmg = (50.0 + (meta.path === 'Hunt' || meta.path === 'Destruction' ? 132.5 : 26.5)).toFixed(1); - const breakEffect = (meta.path === 'Harmony' || meta.path === 'Nihility' ? 142.0 : 10.4).toFixed(1); + const critRate = (5.0 + (canonPath === 'Hunt' || canonPath === 'Destruction' ? 65.4 : 18.8)).toFixed(1); + const critDmg = (50.0 + (canonPath === 'Hunt' || canonPath === 'Destruction' ? 132.5 : 26.5)).toFixed(1); + const breakEffect = (canonPath === 'Harmony' || canonPath === 'Nihility' ? 142.0 : 10.4).toFixed(1); const effectRes = (10.0).toFixed(1); const err = (19.4).toFixed(1); - const ehr = (meta.path === 'Nihility' ? 67.2 : 19.4).toFixed(1); - const healing = (meta.path === 'Abundance' ? 34.5 : 0.0).toFixed(1); + const ehr = (canonPath === 'Nihility' ? 67.2 : 19.4).toFixed(1); + const healing = (canonPath === 'Abundance' ? 34.5 : 0.0).toFixed(1); const elemDmg = (38.8).toFixed(1); // Eidolon strip @@ -4493,10 +4518,10 @@ function renderShowcaseCard(avatarId) { const slotNames = { 1: { name: "ส่วนหัว", stat: "HP 706" }, 2: { name: "ส่วนมือ", stat: "ATK 353" }, - 3: { name: "ลำตัว", stat: meta.path === 'Preservation' ? "DEF 54.0%" : (meta.path === 'Hunt' ? "CRIT Rate 32.4%" : "HP 43.2%") }, + 3: { name: "ลำตัว", stat: canonPath === 'Preservation' ? "DEF 54.0%" : (canonPath === 'Hunt' ? "CRIT Rate 32.4%" : "HP 43.2%") }, 4: { name: "รองเท้า", stat: "SPD 25.0" }, - 5: { name: "ลูกแก้ว", stat: `${meta.element} 38.8%` }, - 6: { name: "สร้อย", stat: meta.path === 'Preservation' || meta.path === 'Harmony' ? "ERR 19.4%" : "ATK 43.2%" } + 5: { name: "ลูกแก้ว", stat: `${translateElement(canonElem)} 38.8%` }, + 6: { name: "สร้อย", stat: canonPath === 'Preservation' || canonPath === 'Harmony' ? "ERR 19.4%" : "ATK 43.2%" } }; const showRolls = localStorage.getItem('gac_srtool_showcase_rolls') !== 'false'; @@ -4506,7 +4531,7 @@ function renderShowcaseCard(avatarId) { let relicsHtml = ''; for (let slot = 1; slot <= 6; slot++) { const equipped = avatarRelics.find(r => (r.relic_id % 10 === slot)); - const rec = RECOMMENDED_RELIC_BUILDS[meta.path] || RECOMMENDED_RELIC_BUILDS.Preservation; + const rec = RECOMMENDED_RELIC_BUILDS[canonPath] || RECOMMENDED_RELIC_BUILDS.Preservation; const setId = equipped ? Math.floor((equipped.relic_id % 10000) / 10) : (slot <= 4 ? rec.cavern : rec.planar); const rInfo = getRelicSetInfo(setId); const slotInfo = slotNames[slot]; @@ -4622,10 +4647,10 @@ function renderShowcaseCard(avatarId) { Imaginary: 'rgba(251, 191, 36, 0.45)' }; - if (showAura && auraGlows[meta.element]) { - el.showcaseCardContainer.style.background = auraGlows[meta.element]; - el.showcaseCardContainer.style.borderColor = auraBorders[meta.element] || 'var(--border-color)'; - el.showcaseCardContainer.style.boxShadow = `0 10px 40px -10px ${auraBorders[meta.element] || 'rgba(0,0,0,0.5)'}`; + if (showAura && auraGlows[canonElem]) { + el.showcaseCardContainer.style.background = auraGlows[canonElem]; + el.showcaseCardContainer.style.borderColor = auraBorders[canonElem] || 'var(--border-color)'; + el.showcaseCardContainer.style.boxShadow = `0 10px 40px -10px ${auraBorders[canonElem] || 'rgba(0,0,0,0.5)'}`; } else { el.showcaseCardContainer.style.background = 'linear-gradient(135deg, #0d121f 0%, #171f30 100%)'; el.showcaseCardContainer.style.borderColor = 'var(--border-color)'; diff --git a/js/equipment-data.js b/js/equipment-data.js index 355fbac..5ed97cd 100644 --- a/js/equipment-data.js +++ b/js/equipment-data.js @@ -4322,14 +4322,16 @@ export function getLightconeInfo(lcId, langOverride = null) { return { name: `Lightcone ${lcId}`, rarity: 4, - path: translatePath("Unknown") + path: translatePath("Unknown"), + rawPath: "Unknown" }; } const localizedName = meta.names?.[lang] || meta.names?.th || meta.names?.en || `Lightcone ${lcId}`; return { name: localizedName, rarity: meta.rarity, - path: translatePath(meta.path) + path: translatePath(meta.path), + rawPath: meta.path }; } diff --git a/js/i18n.js b/js/i18n.js index 56d2fb1..6aca15d 100644 --- a/js/i18n.js +++ b/js/i18n.js @@ -399,6 +399,15 @@ export const TRANSLATIONS = { "consoleCopyLog": "📋 คัดลอก", "consoleClearLog": "🗑️ ล้าง Log", "consoleQuickTitle": "⚡ คำสั่งด่วนที่ใช้บ่อย (Quick Commands)", + "quickCmdHeal": "💖 /heal", + "quickCmdJades": "💎 +100k Jades", + "quickCmdCredits": "💰 +10M Credits", + "quickCmdMax": "⚡ /max", + "quickCmdExpress": "🚂 รถไฟ Express", + "quickCmdClearLineup": "🧹 เคลียร์ทีม", + "quickCmdHelp": "❓ /help", + "consoleReady": "GaC Server Console พร้อมใช้งาน (พิมพ์ /help เพื่อดูคำสั่งทั้งหมด)", + "filterSamePath": "สายเดียวกัน", "consolePlaceholder": "พิมพ์คำสั่ง GM เช่น /heal, /max, /teleport 20411, /give 102 1000...", "consoleSend": "ส่งคำสั่ง", "consoleHistoryHint": "💡 รองรับกด ↑ ↓ เพื่อเลือกประวัติคำสั่งก่อนหน้า", @@ -749,6 +758,15 @@ export const TRANSLATIONS = { "consoleCopyLog": "📋 Copy Log", "consoleClearLog": "🗑️ Clear Log", "consoleQuickTitle": "⚡ Quick Commands", + "quickCmdHeal": "💖 /heal", + "quickCmdJades": "💎 +100k Jades", + "quickCmdCredits": "💰 +10M Credits", + "quickCmdMax": "⚡ /max", + "quickCmdExpress": "🚂 Astral Express", + "quickCmdClearLineup": "🧹 Clear Lineup", + "quickCmdHelp": "❓ /help", + "consoleReady": "GaC Server Console is ready (type /help for commands)", + "filterSamePath": "Same Path", "consolePlaceholder": "Type GM command e.g. /heal, /max, /teleport 20411, /give 102 1000...", "consoleSend": "Dispatch", "consoleHistoryHint": "💡 Press ↑ / ↓ to navigate command history", diff --git a/version.json b/version.json index ff1ff16..1ebdcac 100644 --- a/version.json +++ b/version.json @@ -1,5 +1,5 @@ { "branch": "test-gay", "version": "1.0.0", - "updatedAt": "2026-10-17T04:56:43.360Z" + "updatedAt": "2026-10-17T05:08:40.480Z" }