diff --git a/assets/elements/Fire.png b/assets/elements/Fire.png new file mode 100644 index 0000000..fa02f71 Binary files /dev/null and b/assets/elements/Fire.png differ diff --git a/assets/elements/Ice.png b/assets/elements/Ice.png new file mode 100644 index 0000000..5a1613e Binary files /dev/null and b/assets/elements/Ice.png differ diff --git a/assets/elements/Imaginary.png b/assets/elements/Imaginary.png new file mode 100644 index 0000000..508cfe4 Binary files /dev/null and b/assets/elements/Imaginary.png differ diff --git a/assets/elements/Lightning.png b/assets/elements/Lightning.png new file mode 100644 index 0000000..bf6ab1f Binary files /dev/null and b/assets/elements/Lightning.png differ diff --git a/assets/elements/Physical.png b/assets/elements/Physical.png new file mode 100644 index 0000000..8f97556 Binary files /dev/null and b/assets/elements/Physical.png differ diff --git a/assets/elements/Quantum.png b/assets/elements/Quantum.png new file mode 100644 index 0000000..b9dbd15 Binary files /dev/null and b/assets/elements/Quantum.png differ diff --git a/assets/elements/Wind.png b/assets/elements/Wind.png new file mode 100644 index 0000000..fde5a68 Binary files /dev/null and b/assets/elements/Wind.png differ diff --git a/assets/logo.png b/assets/logo.png new file mode 100644 index 0000000..6f92627 Binary files /dev/null and b/assets/logo.png differ diff --git a/assets/paths/Abundance.png b/assets/paths/Abundance.png new file mode 100644 index 0000000..ea40bd4 Binary files /dev/null and b/assets/paths/Abundance.png differ diff --git a/assets/paths/Destruction.png b/assets/paths/Destruction.png new file mode 100644 index 0000000..7145de4 Binary files /dev/null and b/assets/paths/Destruction.png differ diff --git a/assets/paths/Elation.png b/assets/paths/Elation.png new file mode 100644 index 0000000..83607bb Binary files /dev/null and b/assets/paths/Elation.png differ diff --git a/assets/paths/Erudition.png b/assets/paths/Erudition.png new file mode 100644 index 0000000..bd2ca43 Binary files /dev/null and b/assets/paths/Erudition.png differ diff --git a/assets/paths/Harmony.png b/assets/paths/Harmony.png new file mode 100644 index 0000000..44bb182 Binary files /dev/null and b/assets/paths/Harmony.png differ diff --git a/assets/paths/Hunt.png b/assets/paths/Hunt.png new file mode 100644 index 0000000..22a8bfb Binary files /dev/null and b/assets/paths/Hunt.png differ diff --git a/assets/paths/Nihility.png b/assets/paths/Nihility.png new file mode 100644 index 0000000..bce213b Binary files /dev/null and b/assets/paths/Nihility.png differ diff --git a/assets/paths/Preservation.png b/assets/paths/Preservation.png new file mode 100644 index 0000000..75ae109 Binary files /dev/null and b/assets/paths/Preservation.png differ diff --git a/assets/paths/Remembrance.png b/assets/paths/Remembrance.png new file mode 100644 index 0000000..d54f639 Binary files /dev/null and b/assets/paths/Remembrance.png differ diff --git a/assets/paths/The Hunt.png b/assets/paths/The Hunt.png new file mode 100644 index 0000000..22a8bfb Binary files /dev/null and b/assets/paths/The Hunt.png differ diff --git a/css/styles.css b/css/styles.css index 7af9422..290278c 100644 --- a/css/styles.css +++ b/css/styles.css @@ -69,6 +69,21 @@ body { gap: 0.85rem; } +.brand-logo-img { + width: 44px; + height: 44px; + border-radius: 50%; + object-fit: cover; + border: 2px solid var(--accent-cyan); + box-shadow: 0 0 12px rgba(56, 189, 248, 0.45); + transition: transform 0.25s ease; + flex-shrink: 0; +} + +.brand-logo-img:hover { + transform: rotate(8deg) scale(1.08); +} + .brand-icon { width: 42px; height: 42px; @@ -536,6 +551,50 @@ body { font-weight: 600; } +/* Star Rail Official Element & Path Icon Badges */ +.icon-badge { + display: inline-flex; + align-items: center; + justify-content: center; + width: 26px; + height: 26px; + border-radius: 6px; + background: rgba(0, 0, 0, 0.45); + border: 1px solid var(--border-color); + padding: 3px; + transition: transform 0.15s ease, box-shadow 0.15s ease; + vertical-align: middle; +} + +.icon-badge:hover { + transform: scale(1.18); +} + +.icon-badge img { + width: 100%; + height: 100%; + object-fit: contain; + display: block; +} + +.icon-badge.elem-fire { border-color: rgba(239, 68, 68, 0.6); background: rgba(239, 68, 68, 0.18); box-shadow: 0 0 8px rgba(239, 68, 68, 0.3); } +.icon-badge.elem-ice { border-color: rgba(56, 189, 248, 0.6); background: rgba(56, 189, 248, 0.18); box-shadow: 0 0 8px rgba(56, 189, 248, 0.3); } +.icon-badge.elem-lightning { border-color: rgba(168, 85, 247, 0.6); background: rgba(168, 85, 247, 0.18); box-shadow: 0 0 8px rgba(168, 85, 247, 0.3); } +.icon-badge.elem-wind { border-color: rgba(16, 185, 129, 0.6); background: rgba(16, 185, 129, 0.18); box-shadow: 0 0 8px rgba(16, 185, 129, 0.3); } +.icon-badge.elem-physical { border-color: rgba(156, 163, 175, 0.6); background: rgba(156, 163, 175, 0.18); box-shadow: 0 0 8px rgba(156, 163, 175, 0.3); } +.icon-badge.elem-quantum { border-color: rgba(99, 102, 241, 0.6); background: rgba(99, 102, 241, 0.18); box-shadow: 0 0 8px rgba(99, 102, 241, 0.3); } +.icon-badge.elem-imaginary { border-color: rgba(245, 158, 11, 0.6); background: rgba(245, 158, 11, 0.18); box-shadow: 0 0 8px rgba(245, 158, 11, 0.3); } + +.path-icon-badge { + border-color: rgba(255, 255, 255, 0.25); + background: rgba(255, 255, 255, 0.08); +} + +.path-icon-badge:hover { + border-color: rgba(255, 255, 255, 0.6); + box-shadow: 0 0 8px rgba(255, 255, 255, 0.25); +} + /* Avatar Card Footer & Status */ .avatar-card-footer { display: flex; diff --git a/index.html b/index.html index 6cddd5d..51fb1ac 100644 --- a/index.html +++ b/index.html @@ -5,14 +5,14 @@ GaC-Srtool — Ultimate Star Rail Server & Build Manager - +
-
✦
+ GaC Logo
GaC-Srtool
Star Rail FreeSR & Server Controller
@@ -140,14 +140,14 @@
-
- - + - @@ -157,6 +157,18 @@ +
diff --git a/js/app.js b/js/app.js index 8381cbd..e2e07ef 100644 --- a/js/app.js +++ b/js/app.js @@ -50,6 +50,7 @@ const el = { avatarSearch: document.getElementById('avatar-search'), avatarFilterRarity: document.getElementById('avatar-filter-rarity'), avatarFilterElement: document.getElementById('avatar-filter-element'), + avatarFilterPath: document.getElementById('avatar-filter-path'), btnMaxAllAvatars: document.getElementById('btn-max-all-avatars'), btnReloadAvatars: document.getElementById('btn-reload-avatars'), @@ -205,6 +206,30 @@ function getElementClass(elem) { return map[elem] || 'elem-physical'; } +// Render Element Icon HTML (Official Star Rail Game Icon) +function getElementIconHtml(element, size = 20) { + if (!element) return ''; + const elemClass = getElementClass(element); + return ` + ${element} + `; +} + +// Render Path Icon HTML (Official Star Rail Game Icon) +function getPathIconHtml(path, size = 20) { + if (!path) return ''; + const safePath = path === 'The Hunt' ? 'Hunt' : path; + return ` + ${path} + `; +} + // Apply multi-language translations across UI function applyTranslations() { document.querySelectorAll('[data-i18n]').forEach(elem => { @@ -400,7 +425,6 @@ function renderLineup(lineups) { `; } else { const info = getAvatarInfo(avatarId); - const elemClass = getElementClass(info.element); slotCard.innerHTML = `
Slot ${slot + 1}
${info.name}
${info.name}
-
- ${info.element} - ${info.path} +
+ ${getElementIconHtml(info.element, 20)} + ${getPathIconHtml(info.path, 20)}
`; } @@ -459,7 +483,6 @@ function renderPickerGrid() { return; } - const elemClass = getElementClass(meta.element); const card = document.createElement('div'); card.className = `card avatar-card card-rarity-${meta.rarity}`; card.style.minHeight = 'auto'; @@ -476,9 +499,10 @@ function renderPickerGrid() {
${meta.name}
-
- ${meta.element} - Lv. ${item.level} • E${item.rank} +
+ ${getElementIconHtml(meta.element, 16)} + ${getPathIconHtml(meta.path, 16)} + Lv. ${item.level} • E${item.rank}
@@ -544,13 +568,15 @@ function renderAvatarsGrid() { const searchTerm = el.avatarSearch.value.trim().toLowerCase(); const rarityFilter = el.avatarFilterRarity.value; const elementFilter = el.avatarFilterElement.value; + const pathFilter = el.avatarFilterPath ? el.avatarFilterPath.value : 'all'; const filtered = state.avatarsList.filter(item => { const meta = getAvatarInfo(item.avatar_id); const matchesSearch = meta.name.toLowerCase().includes(searchTerm) || String(item.avatar_id).includes(searchTerm); const matchesRarity = rarityFilter === 'all' || String(meta.rarity) === rarityFilter; const matchesElement = elementFilter === 'all' || meta.element === elementFilter; - return matchesSearch && matchesRarity && matchesElement; + const matchesPath = pathFilter === 'all' || meta.path === pathFilter || (pathFilter === 'Hunt' && (meta.path === 'Hunt' || meta.path === 'The Hunt')); + return matchesSearch && matchesRarity && matchesElement && matchesPath; }); if (filtered.length === 0) { @@ -561,7 +587,6 @@ function renderAvatarsGrid() { el.avatarsGrid.innerHTML = ''; filtered.forEach(item => { const meta = getAvatarInfo(item.avatar_id); - const elemClass = getElementClass(meta.element); const card = document.createElement('div'); card.className = `card avatar-card card-rarity-${meta.rarity}`; @@ -578,8 +603,8 @@ function renderAvatarsGrid() {
${meta.name}
- ${translateElement(meta.element)} - ${translatePath(meta.path)} + ${getElementIconHtml(meta.element, 20)} + ${getPathIconHtml(meta.path, 20)}
@@ -650,7 +675,6 @@ async function maxSingleAvatar(avatarId) { function openAvatarDetailModal(avatarItem) { state.selectedAvatarDetail = avatarItem; const meta = getAvatarInfo(avatarItem.avatar_id); - const elemClass = getElementClass(meta.element); el.modalCharTitle.textContent = `ปรับแต่งตัวละคร: ${meta.name} (ID: ${avatarItem.avatar_id})`; el.modalCharImg.src = `./assets/avatars/${avatarItem.avatar_id}.png`; @@ -659,9 +683,9 @@ function openAvatarDetailModal(avatarItem) { }; el.modalCharName.textContent = meta.name; el.modalCharMeta.innerHTML = ` - ${meta.element} - ${meta.path} - ★ ${meta.rarity} + ${getElementIconHtml(meta.element, 24)} + ${getPathIconHtml(meta.path, 24)} + ★ ${meta.rarity} `; el.modalCharLevel.value = avatarItem.level || 80; @@ -963,7 +987,6 @@ function renderExRanks(exList) { item.style.gap = '1rem'; const info = getAvatarInfo(ex.avatar_id); - const elemClass = getElementClass(info.element); item.innerHTML = `
@@ -975,10 +998,10 @@ function renderExRanks(exList) {
${info.name}
-
- ${info.element} - ${info.path} - Ex-Rank ID: ${ex.ex_rank_id} +
+ ${getElementIconHtml(info.element, 20)} + ${getPathIconHtml(info.path, 20)} + Ex-Rank ID: ${ex.ex_rank_id}
@@ -986,7 +1009,7 @@ function renderExRanks(exList) {
`; @@ -1259,6 +1282,7 @@ function setupEvents() { el.avatarSearch.addEventListener('input', renderAvatarsGrid); el.avatarFilterRarity.addEventListener('change', renderAvatarsGrid); el.avatarFilterElement.addEventListener('change', renderAvatarsGrid); + el.avatarFilterPath?.addEventListener('change', renderAvatarsGrid); el.btnReloadAvatars.addEventListener('click', loadAvatars); // Ex-Rank All Controls