Compare commits
11
Commits
9378f19c14
...
b11121e27e
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b11121e27e | ||
|
|
e8952ecde8 | ||
|
|
51302e36c8 | ||
|
|
1e98bfea7e | ||
|
|
141798c629 | ||
|
|
3575261aa4 | ||
|
|
a2e0f186d1 | ||
|
|
99ecd84499 | ||
|
|
8de2fb5e44 | ||
|
|
5fc5c9e0da | ||
|
|
45456e7df6 |
No files matched your search
@@ -2,7 +2,7 @@ name: Deploy GaC-Srtool to GitHub Pages
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: ["main", "test-gay"]
|
||||
branches: ["main"]
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
@@ -16,6 +16,7 @@ concurrency:
|
||||
|
||||
jobs:
|
||||
deploy:
|
||||
if: github.ref == 'refs/heads/main'
|
||||
environment:
|
||||
name: github-pages
|
||||
url: ${{ steps.deployment.outputs.page_url }}
|
||||
@@ -25,6 +26,11 @@ jobs:
|
||||
uses: actions/checkout@v4
|
||||
- name: Setup Pages
|
||||
uses: actions/configure-pages@v4
|
||||
- name: Generate deployment branch metadata
|
||||
env:
|
||||
DEPLOY_BRANCH: ${{ github.ref_name }}
|
||||
run: |
|
||||
node -e 'const fs = require("node:fs"); const data = { branch: process.env.DEPLOY_BRANCH, version: "1.0.0", updatedAt: new Date().toISOString() }; fs.writeFileSync("version.json", JSON.stringify(data, null, 2) + "\n");'
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-pages-artifact@v3
|
||||
with:
|
||||
|
||||
@@ -40,6 +40,7 @@
|
||||
|
||||
### 👥 4. ระบบจัดการตัวละคร (Avatars & Character Builder)
|
||||
- **ข้อมูลครบถ้วน:** ครอบคลุมตัวละครทั้งหมดในเกมตาม Resource มาตรฐานและเนื้อหาล่าสุด
|
||||
- **คู่มือ Build รายตัว:** เปิดดูกรวยแสง, เซ็ตรีลิกส์/มิติ และออฟหลักที่พบบ่อยจากข้อมูลตัวอย่าง Endgame พร้อมโหมด/จำนวนตัวอย่าง วันที่เก็บข้อมูล และลิงก์คู่มือเต็มของ Prydwen
|
||||
- **ปรับแต่งสถานะ:** เลเวล (1-80), เลื่อนขั้น (Ascension 0-6), ระดับ Eidolon (E0-E6), และร่องรอยสกิล (Traces 10/10)
|
||||
- **ปุ่มลัดจัดการด่วน:**
|
||||
- ⚡ *ปรับ E0S1 ทุกตัว:* ตั้งค่าตัวละครทุกตัวเป็น E0 พร้อมกรวยแสงประจำตัว S1 เลเวล 80
|
||||
@@ -122,3 +123,9 @@ GaC-Srtool สื่อสารกับเซิร์ฟเวอร์ GaC-h
|
||||
### บันทึกตัวละครและ Traces
|
||||
|
||||
การบันทึกจากหน้ารายละเอียดส่งข้อมูลตัวละครทั้งชุดผ่าน `/api/freesr` ในคำขอเดียว รวมถึง `data.skills` และ `data.skills_by_anchor_type` สำหรับ Traces เพื่อไม่ให้ server sync ข้อมูลระดับ/Eidolon ระหว่างทางก่อนข้อมูล Trace จะถูกบันทึก `saveAvatarDetails(closeModal = true)` ยังรองรับการเรียกจากปุ่ม build ที่ไม่ต้องปิดหน้าต่าง ถ้า server ตอบผิดพลาดจะแสดงข้อความบันทึกไม่สำเร็จแทนการแจ้งว่าสำเร็จ
|
||||
|
||||
### ข้อมูล Build และแหล่งที่มา
|
||||
|
||||
หน้า **รายละเอียดตัวละคร → แนวทางบิลด์** แสดงอุปกรณ์และออฟหลักที่พบบ่อยในตัวอย่าง Endgame จากข้อมูลที่แสดงบน Prydwen โดยใส่โหมด/จำนวนผู้เล่นและวันที่เก็บ snapshot ไว้กำกับ ตัวเลขเป็นสัดส่วนการใช้งานในกลุ่มตัวอย่าง ไม่ใช่คะแนนจัดอันดับหรือคำแนะนำทางการ ตัวละครที่ snapshot ไม่มีตัวอย่างจะแสดงลิงก์ไปคู่มือของ Prydwen แทนการแสดงข้อมูลสำรองที่อาจทำให้เข้าใจผิด
|
||||
|
||||
ข้อมูลที่สร้างไว้ใน `js/build-guides-data.js` ใช้ชุดข้อมูล MIT จาก [LvlUrArti/MocDataProcessed](https://huggingface.co/datasets/LvlUrArti/MocDataProcessed) ซึ่งระบุว่าเป็นข้อมูลที่ประมวลผลจากเว็บไซต์ Prydwen โปรดให้เครดิต LvlUrArti เมื่อเผยแพร่หรือวิเคราะห์ข้อมูลต่อ สามารถอัปเดต snapshot ด้วย `npm run sync-build-guides` ได้ โดยสคริปต์จะเลือกเวอร์ชันล่าสุดที่มีใน dataset และจับคู่ตัวละครตาม ID จาก `js/avatars-data.js`.
|
||||
+202
-20
@@ -2593,32 +2593,80 @@ input:checked + .slider:before {
|
||||
/* ==========================================
|
||||
GM Command Dispatcher & Live Log Console
|
||||
========================================== */
|
||||
.console-quick-pills {
|
||||
.console-suggestions {
|
||||
margin-top: -0.45rem;
|
||||
border: 1px solid rgba(56, 189, 248, 0.25);
|
||||
border-radius: 7px;
|
||||
overflow: hidden;
|
||||
background: #080c13;
|
||||
box-shadow: 0 12px 28px rgba(0, 0, 0, 0.42);
|
||||
font-family: 'Consolas', 'Monaco', 'Courier New', monospace;
|
||||
}
|
||||
|
||||
.console-suggestions[hidden] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.console-suggestions-header {
|
||||
display: flex;
|
||||
gap: 0.4rem;
|
||||
flex-wrap: wrap;
|
||||
justify-content: space-between;
|
||||
padding: 0.32rem 0.65rem;
|
||||
color: #94a3b8;
|
||||
background: rgba(255, 255, 255, 0.035);
|
||||
border-bottom: 1px solid rgba(255, 255, 255, 0.07);
|
||||
font-size: 0.7rem;
|
||||
}
|
||||
|
||||
.console-pill-btn {
|
||||
background: rgba(255, 255, 255, 0.04);
|
||||
border: 1px solid rgba(255, 255, 255, 0.1);
|
||||
color: #e2e8f0;
|
||||
padding: 0.3rem 0.65rem;
|
||||
border-radius: 9999px;
|
||||
font-size: 0.775rem;
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
transition: all 0.15s ease;
|
||||
display: inline-flex;
|
||||
.console-suggestion-count {
|
||||
color: #fbbf24;
|
||||
}
|
||||
|
||||
.console-suggestion-option {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
align-items: center;
|
||||
gap: 0.3rem;
|
||||
gap: 0.75rem;
|
||||
padding: 0.35rem 0.65rem;
|
||||
color: #38e8f2;
|
||||
text-align: left;
|
||||
background: transparent;
|
||||
border: 0;
|
||||
cursor: pointer;
|
||||
font: inherit;
|
||||
}
|
||||
|
||||
.console-pill-btn:hover {
|
||||
background: rgba(56, 189, 248, 0.15);
|
||||
border-color: rgba(56, 189, 248, 0.4);
|
||||
color: var(--accent-cyan);
|
||||
transform: translateY(-1px);
|
||||
.console-suggestion-option:hover,
|
||||
.console-suggestion-option[aria-selected="true"] {
|
||||
color: #fff;
|
||||
background: rgba(56, 189, 248, 0.13);
|
||||
}
|
||||
|
||||
.console-suggestion-option::before {
|
||||
content: ">";
|
||||
color: #34d399;
|
||||
font-weight: 800;
|
||||
}
|
||||
|
||||
.console-suggestion-command {
|
||||
font-size: 0.8rem;
|
||||
}
|
||||
|
||||
.console-suggestion-description {
|
||||
margin-left: auto;
|
||||
color: #64748b;
|
||||
font-family: inherit;
|
||||
font-size: 0.68rem;
|
||||
}
|
||||
|
||||
.console-suggestion-option:hover .console-suggestion-description,
|
||||
.console-suggestion-option[aria-selected="true"] .console-suggestion-description {
|
||||
color: #94a3b8;
|
||||
}
|
||||
|
||||
@media (max-width: 640px) {
|
||||
.console-suggestion-description {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.console-terminal-wrapper {
|
||||
@@ -3209,3 +3257,137 @@ input:checked + .slider:before {
|
||||
flex-shrink: 0;
|
||||
opacity: 0.85;
|
||||
}
|
||||
|
||||
.build-guide-content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.8rem;
|
||||
}
|
||||
|
||||
.build-guide-topline,
|
||||
.build-guide-footer {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 0.75rem;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.build-guide-title {
|
||||
color: var(--text-highlight);
|
||||
font-size: 1.05rem;
|
||||
font-weight: 800;
|
||||
}
|
||||
|
||||
.build-guide-meta,
|
||||
.build-guide-note,
|
||||
.build-guide-sample,
|
||||
.build-guide-footer {
|
||||
color: var(--text-muted);
|
||||
font-size: 0.78rem;
|
||||
}
|
||||
|
||||
.build-guide-note {
|
||||
margin: 0;
|
||||
line-height: 1.55;
|
||||
}
|
||||
|
||||
.build-guide-sample {
|
||||
display: inline-flex;
|
||||
align-self: flex-start;
|
||||
border: 1px solid rgba(56, 189, 248, 0.28);
|
||||
border-radius: 999px;
|
||||
background: rgba(56, 189, 248, 0.08);
|
||||
color: #bae6fd;
|
||||
padding: 0.3rem 0.7rem;
|
||||
}
|
||||
|
||||
.build-guide-low-sample {
|
||||
color: var(--accent-gold);
|
||||
font-size: 0.75rem;
|
||||
}
|
||||
|
||||
.build-guide-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
gap: 0.7rem;
|
||||
}
|
||||
|
||||
.build-guide-card {
|
||||
min-width: 0;
|
||||
padding: 0.85rem;
|
||||
border: 1px solid var(--border-color);
|
||||
border-radius: var(--radius-sm);
|
||||
background: rgba(18, 24, 38, 0.72);
|
||||
}
|
||||
|
||||
.build-guide-card h4 {
|
||||
margin: 0 0 0.6rem;
|
||||
color: var(--accent-cyan);
|
||||
font-size: 0.85rem;
|
||||
}
|
||||
|
||||
.build-guide-ranked-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.4rem;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
.build-guide-ranked-list li {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
justify-content: space-between;
|
||||
gap: 0.6rem;
|
||||
font-size: 0.78rem;
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
.build-guide-ranked-list li span {
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.build-guide-ranked-list li strong {
|
||||
flex-shrink: 0;
|
||||
color: var(--accent-gold);
|
||||
font-size: 0.72rem;
|
||||
}
|
||||
|
||||
.build-guide-empty,
|
||||
.build-guide-no-data {
|
||||
color: var(--text-muted);
|
||||
font-size: 0.78rem;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.build-guide-stat-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
gap: 0.65rem;
|
||||
}
|
||||
|
||||
.build-guide-stat-grid > div > span {
|
||||
display: block;
|
||||
margin-bottom: 0.4rem;
|
||||
color: var(--text-muted);
|
||||
font-size: 0.72rem;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.build-guide-footer {
|
||||
border-top: 1px solid var(--border-color);
|
||||
padding-top: 0.65rem;
|
||||
}
|
||||
|
||||
.build-guide-footer a:not(.btn) {
|
||||
color: var(--accent-cyan);
|
||||
}
|
||||
|
||||
@media (max-width: 640px) {
|
||||
.build-guide-grid,
|
||||
.build-guide-stat-grid {
|
||||
grid-template-columns: minmax(0, 1fr);
|
||||
}
|
||||
}
|
||||
+108
-109
@@ -3,8 +3,8 @@
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>[test-gay] GaC-Srtool — Ultimate Star Rail Server & Build Manager</title>
|
||||
<link rel="stylesheet" href="css/styles.css?v=2.1">
|
||||
<title>GaC-Srtool</title>
|
||||
<link rel="stylesheet" href="css/styles.css?v=2.3">
|
||||
<link rel="icon" type="image/png" href="assets/logo.png">
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/html2canvas/1.4.1/html2canvas.min.js"></script>
|
||||
</head>
|
||||
@@ -17,7 +17,7 @@
|
||||
<div>
|
||||
<div class="brand-title" style="display: flex; align-items: center; gap: 0.5rem;">
|
||||
<span>GaC-Srtool</span>
|
||||
<span class="badge-branch" id="header-branch-badge">test-gay</span>
|
||||
<span class="badge-branch" id="header-branch-badge" style="display: none;"></span>
|
||||
</div>
|
||||
<div class="brand-subtitle" data-i18n="appSubtitle">Star Rail FreeSR & Server Controller</div>
|
||||
</div>
|
||||
@@ -25,7 +25,7 @@
|
||||
|
||||
<div class="header-controls">
|
||||
<!-- Server Mode Selector -->
|
||||
<div class="server-mode-badge" title="โหมดการเชื่อมต่อเซิร์ฟเวอร์">
|
||||
<div class="server-mode-badge" title="โหมดการเชื่อมต่อเซิร์ฟเวอร์" data-i18n-title="lblServerModeActive">
|
||||
<span>🌐</span>
|
||||
<select id="server-mode-select" class="server-mode-select">
|
||||
<option value="gac" selected>GaC-hkrpg-go</option>
|
||||
@@ -35,16 +35,16 @@
|
||||
</div>
|
||||
|
||||
<!-- Language Selector (13 Languages) -->
|
||||
<select id="lang-select" class="form-select btn-sm" style="width: auto; padding: 0.4rem 0.75rem; background: var(--bg-secondary); cursor: pointer;" title="Language / ภาษา">
|
||||
<select id="lang-select" class="form-select btn-sm" style="width: auto; padding: 0.4rem 0.75rem; background: var(--bg-secondary); cursor: pointer;" title="Language / ภาษา" data-i18n-title="languageSelectorTitle">
|
||||
</select>
|
||||
|
||||
<!-- Connection Pill -->
|
||||
<div class="connection-pill" id="btn-open-settings" title="คลิกเพื่อตั้งค่าการเชื่อมต่อ API">
|
||||
<div class="connection-pill" id="btn-open-settings" title="คลิกเพื่อตั้งค่าการเชื่อมต่อ API" data-i18n-title="apiSettingsTooltip">
|
||||
<span class="status-dot" id="status-dot"></span>
|
||||
<span id="connection-status-text">กำลังตรวจสอบ...</span>
|
||||
</div>
|
||||
|
||||
<button class="btn btn-secondary btn-sm" id="btn-quick-ping" title="รีเฟรชการเชื่อมต่อ" data-i18n="refresh">
|
||||
<button class="btn btn-secondary btn-sm" id="btn-quick-ping" title="รีเฟรชการเชื่อมต่อ" data-i18n="refresh" data-i18n-title="refresh">
|
||||
🔄 รีเฟรช
|
||||
</button>
|
||||
</div>
|
||||
@@ -61,11 +61,11 @@
|
||||
<button class="tab-btn" data-tab="tab-exrank" id="tab-btn-exrank" data-i18n="tabExrank">⚡ สกิลพิเศษ Ex-Rank</button>
|
||||
<button class="tab-btn" data-tab="tab-json" data-i18n="tabJson">📝 จัดการไฟล์ JSON</button>
|
||||
<button class="tab-btn" data-tab="tab-settings" data-i18n="tabSettings">⚙️ ตั้งค่า</button>
|
||||
<div class="nav-branch-pill" id="nav-branch-pill" title="Git Branch ที่ใช้งานอยู่">
|
||||
<div class="nav-branch-pill" id="nav-branch-pill" title="Git Branch ที่ใช้งานอยู่" data-i18n-title="branchTooltip" style="display: none;">
|
||||
<svg class="branch-icon" viewBox="0 0 16 16" width="12" height="12" fill="currentColor">
|
||||
<path fill-rule="evenodd" d="M11.75 2.5a.75.75 0 100 1.5.75.75 0 000-1.5zm-2.25.75a2.25 2.25 0 113 2.122V6A2.5 2.5 0 0110 8.5H6a1 1 0 00-1 1v1.128a2.251 2.251 0 11-1.5 0V5.372a2.25 2.25 0 111.5 0v1.836A2.492 2.492 0 016 7h4a1 1 0 001-1v-.628A2.25 2.25 0 019.5 3.25zM4.25 12a.75.75 0 100 1.5.75.75 0 000-1.5zM3.5 3.25a.75.75 0 111.5 0 .75.75 0 01-1.5 0z"></path>
|
||||
</svg>
|
||||
<span id="nav-branch-name">test-gay</span>
|
||||
<span id="nav-branch-name"></span>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
@@ -118,7 +118,7 @@
|
||||
<div class="card">
|
||||
<div class="card-title">
|
||||
<span data-i18n="serverStatusTitle">📍 สถานะเซิร์ฟเวอร์ & พิกัดปัจจุบัน</span>
|
||||
<span class="btn-sm btn-secondary" id="badge-version">API Live</span>
|
||||
<span class="btn-sm btn-secondary" id="badge-version" data-i18n="apiLive">API Live</span>
|
||||
</div>
|
||||
<div style="display: flex; flex-direction: column; gap: 0.75rem;">
|
||||
<div>
|
||||
@@ -154,7 +154,7 @@
|
||||
<span data-i18n="miniBattleTitle">สรุปการต่อสู้ล่าสุด & ดาเมจทีม</span>
|
||||
</span>
|
||||
<div style="display: flex; align-items: center; gap: 0.4rem;">
|
||||
<span class="badge-super-tag" id="badge-mini-battle-status" style="background: rgba(156, 163, 175, 0.12); color: var(--text-muted); font-weight: 800; border: 1px solid rgba(156, 163, 175, 0.25);">
|
||||
<span class="badge-super-tag" id="badge-mini-battle-status" data-i18n="miniNoBattleTitle" style="background: rgba(156, 163, 175, 0.12); color: var(--text-muted); font-weight: 800; border: 1px solid rgba(156, 163, 175, 0.25);">
|
||||
ยังไม่มีข้อมูลการต่อสู้
|
||||
</span>
|
||||
<button type="button" class="btn btn-sm btn-secondary" id="btn-mini-view-full-analyst" style="font-size: 0.725rem; padding: 0.2rem 0.55rem; color: var(--accent-cyan); border-color: rgba(56, 189, 248, 0.35); font-weight: 700;" title="เปิดหน้า Damage Analyst ตัวเต็ม" data-i18n="miniViewFullAnalyst">
|
||||
@@ -228,34 +228,18 @@
|
||||
<div class="card-title" style="display: flex; justify-content: space-between; align-items: center; flex-wrap: wrap; gap: 0.5rem;">
|
||||
<span style="display: flex; align-items: center; gap: 0.5rem;">
|
||||
<span>💻</span>
|
||||
<span data-i18n="consoleTitle">คอนโซลคำสั่ง GM & Log สด</span>
|
||||
<span>GM Command Console & Live Log</span>
|
||||
</span>
|
||||
<div style="display: flex; gap: 0.35rem;">
|
||||
<button type="button" class="btn btn-sm btn-secondary" id="btn-console-copy-log" title="คัดลอก Log ทั้งหมด" style="padding: 0.2rem 0.6rem; font-size: 0.75rem;" data-i18n="consoleCopyLog">
|
||||
📋 คัดลอก
|
||||
<button type="button" class="btn btn-sm btn-secondary" id="btn-console-copy-log" title="Copy all logs" style="padding: 0.2rem 0.6rem; font-size: 0.75rem;">
|
||||
📋 Copy
|
||||
</button>
|
||||
<button type="button" class="btn btn-sm btn-secondary" id="btn-console-clear-log" title="ล้างหน้าจอ Terminal" style="padding: 0.2rem 0.6rem; font-size: 0.75rem;" data-i18n="consoleClearLog">
|
||||
🗑️ ล้าง Log
|
||||
<button type="button" class="btn btn-sm btn-secondary" id="btn-console-clear-log" title="Clear terminal log" style="padding: 0.2rem 0.6rem; font-size: 0.75rem;">
|
||||
🗑️ Clear
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<p class="card-subtitle" style="margin-bottom: 0.25rem;" data-i18n="consoleSubtitle">ส่งคำสั่ง GM / Server commands แบบเรียลไทม์ พร้อมติดตามสถานะและ Packet Log</p>
|
||||
|
||||
<!-- Quick GM Command Pills -->
|
||||
<div>
|
||||
<div style="font-size: 0.75rem; font-weight: 700; color: var(--text-muted); text-transform: uppercase; letter-spacing: 0.5px; margin-bottom: 0.35rem;" data-i18n="consoleQuickTitle">
|
||||
⚡ คำสั่งด่วนที่ใช้บ่อย (Quick Commands)
|
||||
</div>
|
||||
<div class="console-quick-pills">
|
||||
<button type="button" class="console-pill-btn" data-cmd="/heal" title="ฟื้นฟู HP/Energy ทั้งทีม" data-i18n="quickCmdHeal">💖 /heal</button>
|
||||
<button type="button" class="console-pill-btn" data-cmd="/give 102 100000" title="รับ 100,000 Stellar Jades" data-i18n="quickCmdJades">💎 +100k Jades</button>
|
||||
<button type="button" class="console-pill-btn" data-cmd="/give 2 10000000" title="รับ 10,000,000 Credits" data-i18n="quickCmdCredits">💰 +10M Credits</button>
|
||||
<button type="button" class="console-pill-btn" data-cmd="/max" title="อัปเต็มเลเวล 80 E6 ทุกตัว" data-i18n="quickCmdMax">⚡ /max</button>
|
||||
<button type="button" class="console-pill-btn" data-cmd="/teleport 20001 1" title="วาร์ปไปรถไฟ Astral Express" data-i18n="quickCmdExpress">🚂 รถไฟ Express</button>
|
||||
<button type="button" class="console-pill-btn" data-cmd="/clear lineup" title="ล้างตัวละครในทีม" data-i18n="quickCmdClearLineup">🧹 เคลียร์ทีม</button>
|
||||
<button type="button" class="console-pill-btn" data-cmd="/help" title="ดูรายการคำสั่งทั้งหมด" data-i18n="quickCmdHelp">❓ /help</button>
|
||||
</div>
|
||||
</div>
|
||||
<p class="card-subtitle" style="margin-bottom: 0.25rem;">Send GM and server commands, with live status and packet logs.</p>
|
||||
|
||||
<!-- Interactive Terminal Screen -->
|
||||
<div class="console-terminal-wrapper">
|
||||
@@ -274,15 +258,22 @@
|
||||
<form id="form-console-cmd" style="display: flex; gap: 0.5rem; align-items: center; margin-top: 0.25rem;">
|
||||
<div class="console-input-wrap" style="flex: 1; display: flex; align-items: center; background: rgba(0,0,0,0.4); border: 1px solid var(--border-color); border-radius: 6px; padding: 0 0.75rem;">
|
||||
<span style="color: var(--accent-cyan); font-family: monospace; font-weight: 800; font-size: 1.1rem; margin-right: 0.5rem;">></span>
|
||||
<input type="text" id="console-cmd-input" class="form-input" data-i18n-placeholder="consolePlaceholder" placeholder="พิมพ์คำสั่ง GM เช่น /heal, /max, /teleport 20411, /give 102 1000..." style="background: transparent; border: none; padding: 0.6rem 0; font-family: monospace; font-size: 0.85rem; box-shadow: none;" autocomplete="off">
|
||||
<input type="text" id="console-cmd-input" class="form-input" placeholder="Type a command, e.g. /heal, /teleport 20411, /give 102 1000" style="background: transparent; border: none; padding: 0.6rem 0; font-family: monospace; font-size: 0.85rem; box-shadow: none;" autocomplete="off" role="combobox" aria-autocomplete="list" aria-controls="console-suggestion-options" aria-expanded="false">
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary" id="btn-console-cmd-send" data-i18n="consoleSend" style="padding: 0.6rem 1.25rem; font-weight: 700; white-space: nowrap;">
|
||||
ส่งคำสั่ง
|
||||
<button type="submit" class="btn btn-primary" id="btn-console-cmd-send" style="padding: 0.6rem 1.25rem; font-weight: 700; white-space: nowrap;">
|
||||
Run
|
||||
</button>
|
||||
</form>
|
||||
<div id="console-command-suggestions" class="console-suggestions" hidden>
|
||||
<div class="console-suggestions-header">
|
||||
<span>Command suggestions</span>
|
||||
<span id="console-suggestion-count" class="console-suggestion-count">‹ 0/0 ›</span>
|
||||
</div>
|
||||
<div id="console-suggestion-options" role="listbox" aria-label="Command suggestions"></div>
|
||||
</div>
|
||||
<div style="font-size: 0.725rem; color: var(--text-muted); display: flex; justify-content: space-between; align-items: center;">
|
||||
<span data-i18n="consoleHistoryHint">💡 รองรับกด <kbd style="background: rgba(255,255,255,0.1); padding: 0.1rem 0.35rem; border-radius: 3px; font-family: monospace;">↑</kbd> <kbd style="background: rgba(255,255,255,0.1); padding: 0.1rem 0.35rem; border-radius: 3px; font-family: monospace;">↓</kbd> เพื่อเลือกประวัติคำสั่งก่อนหน้า</span>
|
||||
<span id="lbl-console-conn-status" style="color: var(--accent-green);">● เซิร์ฟเวอร์ออนไลน์</span>
|
||||
<span>Use ↑ / ↓ to browse suggestions or command history. Press Tab to complete.</span>
|
||||
<span id="lbl-console-conn-status" style="color: var(--accent-green);">● Server Online</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -355,20 +346,20 @@
|
||||
|
||||
<!-- 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;">
|
||||
<input type="text" id="eq-search" class="form-input" data-i18n-placeholder="equipmentSearchPlaceholder" 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>
|
||||
<option value="3" data-i18n="filter3Star">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>
|
||||
<option value="all" data-i18n="filterAllStatus">สถานะทั้งหมด</option>
|
||||
<option value="equipped" data-i18n="filterEquipped">สวมใส่อยู่</option>
|
||||
<option value="unequipped" data-i18n="filterInInventory">ในกระเป๋า</option>
|
||||
</select>
|
||||
<select id="eq-filter-extra" class="form-select" style="max-width: 120px;">
|
||||
<option value="all">ทุกประเภท</option>
|
||||
<option value="all" data-i18n="filterAllTypes">ทุกประเภท</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
@@ -488,7 +479,7 @@
|
||||
<div class="card" style="padding: 1.2rem; border-left: 4px solid #f59e0b; background: linear-gradient(135deg, rgba(245,158,11,0.06) 0%, rgba(20,20,28,0.7) 100%);">
|
||||
<div style="font-size: 0.775rem; font-weight: 700; color: var(--text-muted); text-transform: uppercase;" data-i18n="analystCycles">จำนวนรอบ (Cycles)</div>
|
||||
<div style="font-size: 1.85rem; font-weight: 900; color: #fbbf24; letter-spacing: -0.5px; margin: 0.25rem 0;" id="analyst-cycles">0 รอบ</div>
|
||||
<div style="font-size: 0.75rem; color: var(--text-muted);" id="analyst-cycles-note">MoC / PF / AS Standard</div>
|
||||
<div style="font-size: 0.75rem; color: var(--text-muted);" id="analyst-cycles-note" data-i18n="analystCyclesNote">MoC / PF / AS Standard</div>
|
||||
</div>
|
||||
|
||||
<div class="card" style="padding: 1.2rem; border-left: 4px solid #38bdf8; background: linear-gradient(135deg, rgba(56,189,248,0.06) 0%, rgba(20,20,28,0.7) 100%);">
|
||||
@@ -587,7 +578,7 @@
|
||||
<div style="display: flex; flex-direction: column; gap: 1rem; margin-top: 1rem;">
|
||||
<div class="ex-switch-card">
|
||||
<div>
|
||||
<div style="font-weight: 700;">Silver Wolf Global Feature</div>
|
||||
<div style="font-weight: 700;" data-i18n="globalFeatureSilverWolf">Silver Wolf Global Feature</div>
|
||||
<div style="font-size: 0.8rem; color: var(--text-muted);" data-i18n="swGlobalDesc">เปิดใช้งานฟังก์ชันพิเศษ SW ทั่วทั้งเซิร์ฟเวอร์</div>
|
||||
</div>
|
||||
<label class="switch">
|
||||
@@ -598,7 +589,7 @@
|
||||
|
||||
<div class="ex-switch-card">
|
||||
<div>
|
||||
<div style="font-weight: 700;">Castorice Global Feature</div>
|
||||
<div style="font-weight: 700;" data-i18n="globalFeatureCastorice">Castorice Global Feature</div>
|
||||
<div style="font-size: 0.8rem; color: var(--text-muted);" data-i18n="castoriceGlobalDesc">เปิดใช้งานฟังก์ชันพิเศษ Castorice ทั่วทั้งเซิร์ฟเวอร์</div>
|
||||
</div>
|
||||
<label class="switch">
|
||||
@@ -609,7 +600,7 @@
|
||||
|
||||
<div class="ex-switch-card">
|
||||
<div>
|
||||
<div style="font-weight: 700;">Aeon ★ Aha Global Feature</div>
|
||||
<div style="font-weight: 700;" data-i18n="globalFeatureAha">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">
|
||||
@@ -727,7 +718,7 @@
|
||||
<span style="font-weight: 700; font-size: 0.875rem;" data-i18n="lblPersistenceInfo">ระบบบันทึกทีมและข้อมูล (Lineup Storage)</span>
|
||||
<span id="badge-persistence-mode" class="badge-super-tag" style="padding: 0.15rem 0.55rem; font-size: 0.75rem;">Persistent API (GaC)</span>
|
||||
</div>
|
||||
<div style="font-size: 0.75rem; color: var(--text-muted); margin-top: 0.35rem;" id="desc-persistence-mode">
|
||||
<div style="font-size: 0.75rem; color: var(--text-muted); margin-top: 0.35rem;" id="desc-persistence-mode" data-i18n="persistentDescription">
|
||||
GaC Server เก็บทีมใน persistent.json (รองรับโหมดสร้างสรรค์) • สำหรับ FireflyGo เก็บใน freesr-data.json
|
||||
</div>
|
||||
</div>
|
||||
@@ -800,7 +791,7 @@
|
||||
<div style="display: flex; flex-direction: column; gap: 0.75rem;">
|
||||
<div style="display: flex; justify-content: space-between; align-items: center; font-size: 0.85rem;">
|
||||
<span style="color: var(--text-muted);" data-i18n="lblCacheSize">สถานะหน่วยความจำ LocalStorage:</span>
|
||||
<strong id="lbl-cache-usage" style="color: var(--accent-cyan); font-family: monospace;">ตรวจวัด...</strong>
|
||||
<strong id="lbl-cache-usage" style="color: var(--accent-cyan); font-family: monospace;">—</strong>
|
||||
</div>
|
||||
|
||||
<div style="display: flex; gap: 0.75rem; margin-top: 0.5rem; flex-wrap: wrap;">
|
||||
@@ -869,6 +860,9 @@
|
||||
<button type="button" class="modal-subtab-btn" data-modaltab="modaltab-showcase" data-i18n="modalTabShowcase">
|
||||
🖼️ การ์ดสรุปบิลด์
|
||||
</button>
|
||||
<button type="button" class="modal-subtab-btn" data-modaltab="modaltab-build-guide" data-i18n="modalTabBuildGuide">
|
||||
📖 แนวทาง Build
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- Sub Tab 0: Overview & Combat Stats (Neonteam style https://srtools.neonteam.dev/1001/detail) -->
|
||||
@@ -876,7 +870,7 @@
|
||||
<div class="overview-layout">
|
||||
<!-- Left: Big portrait art & character identity -->
|
||||
<div class="overview-portrait-box">
|
||||
<img id="overview-portrait-img" class="overview-portrait-img" src="" alt="Character Art">
|
||||
<img id="overview-portrait-img" class="overview-portrait-img" src="" alt="Character Art" data-i18n-alt="characterArtwork">
|
||||
<div class="overview-portrait-info">
|
||||
<div id="overview-char-name" style="font-size: 1.35rem; font-weight: 800; color: #fff;">-</div>
|
||||
<div id="overview-char-meta" style="display: flex; gap: 0.4rem; align-items: center; margin-top: 0.35rem; flex-wrap: wrap;"></div>
|
||||
@@ -903,10 +897,10 @@
|
||||
<!-- Quick Equipped Equipment Glance -->
|
||||
<div style="display: grid; grid-template-columns: 1fr 1fr; gap: 0.85rem;">
|
||||
<!-- LC Glance -->
|
||||
<div class="card" id="overview-lc-card" style="background: rgba(18, 24, 38, 0.7); border: 1px solid var(--border-color); padding: 0.85rem; cursor: pointer; transition: all 0.2s;" title="คลิกเพื่อจัดการ Light Cone">
|
||||
<div class="card" id="overview-lc-card" style="background: rgba(18, 24, 38, 0.7); border: 1px solid var(--border-color); padding: 0.85rem; cursor: pointer; transition: all 0.2s;" title="คลิกเพื่อจัดการ Light Cone" data-i18n-title="overviewEquippedLc">
|
||||
<div style="font-size: 0.75rem; color: var(--text-muted); font-weight: 700; margin-bottom: 0.5rem; display: flex; justify-content: space-between;">
|
||||
<span data-i18n="overviewEquippedLc">🗡️ กรวยแสงที่สวมใส่</span>
|
||||
<span style="color: var(--accent-cyan); font-size: 0.7rem;">จัดการ ➔</span>
|
||||
<span style="color: var(--accent-cyan); font-size: 0.7rem;" data-i18n="btnManage">จัดการ ➔</span>
|
||||
</div>
|
||||
<div style="display: flex; gap: 0.65rem; align-items: center;">
|
||||
<img id="overview-lc-thumb" src="" alt="" style="width: 44px; height: 60px; border-radius: 4px; object-fit: cover; border: 1px solid var(--border-color);">
|
||||
@@ -918,10 +912,10 @@
|
||||
</div>
|
||||
|
||||
<!-- Relics Glance -->
|
||||
<div class="card" id="overview-relics-card" style="background: rgba(18, 24, 38, 0.7); border: 1px solid var(--border-color); padding: 0.85rem; cursor: pointer; transition: all 0.2s;" title="คลิกเพื่อจัดการรีลิกส์">
|
||||
<div class="card" id="overview-relics-card" style="background: rgba(18, 24, 38, 0.7); border: 1px solid var(--border-color); padding: 0.85rem; cursor: pointer; transition: all 0.2s;" title="คลิกเพื่อจัดการรีลิกส์" data-i18n-title="overviewEquippedRelics">
|
||||
<div style="font-size: 0.75rem; color: var(--text-muted); font-weight: 700; margin-bottom: 0.5rem; display: flex; justify-content: space-between;">
|
||||
<span data-i18n="overviewEquippedRelics">🛡️ รีลิกส์และเซ็ต</span>
|
||||
<span style="color: var(--accent-cyan); font-size: 0.7rem;">จัดการ ➔</span>
|
||||
<span style="color: var(--accent-cyan); font-size: 0.7rem;" data-i18n="btnManage">จัดการ ➔</span>
|
||||
</div>
|
||||
<div id="overview-relics-summary" style="display: flex; flex-direction: column; gap: 0.25rem; font-size: 0.75rem;">
|
||||
<!-- Set bonuses active -->
|
||||
@@ -954,10 +948,10 @@
|
||||
</div>
|
||||
|
||||
<!-- Equipped Lightcone Slot in Equipment Tab -->
|
||||
<div class="card" id="relics-equipped-lc-box" style="background: rgba(18, 24, 38, 0.75); border: 1px solid var(--border-color); padding: 0.85rem 1rem; margin-bottom: 1rem; cursor: pointer; transition: all 0.2s;" title="คลิกเพื่อเลือกเปลี่ยน Light Cone">
|
||||
<div class="card" id="relics-equipped-lc-box" style="background: rgba(18, 24, 38, 0.75); border: 1px solid var(--border-color); padding: 0.85rem 1rem; margin-bottom: 1rem; cursor: pointer; transition: all 0.2s;" title="คลิกเพื่อเลือกเปลี่ยน Light Cone" data-i18n-title="overviewEquippedLc">
|
||||
<div style="font-size: 0.75rem; color: var(--text-muted); font-weight: 700; margin-bottom: 0.5rem; display: flex; justify-content: space-between; align-items: center;">
|
||||
<span style="color: var(--accent-cyan); font-weight: 800;">🗡️ กรวยแสงที่สวมใส่ (คลิกเพื่อเลือกเปลี่ยน)</span>
|
||||
<span style="color: var(--accent-gold); font-size: 0.75rem; font-weight: 700;">เปลี่ยนกรวยแสง ➔</span>
|
||||
<span style="color: var(--accent-cyan); font-weight: 800;" data-i18n="overviewEquippedLc">🗡️ กรวยแสงที่สวมใส่ (คลิกเพื่อเลือกเปลี่ยน)</span>
|
||||
<span style="color: var(--accent-gold); font-size: 0.75rem; font-weight: 700;" data-i18n="btnChangeLc">เปลี่ยนกรวยแสง ➔</span>
|
||||
</div>
|
||||
<div style="display: flex; gap: 0.85rem; align-items: center;">
|
||||
<img id="relics-tab-lc-thumb" src="" alt="" style="width: 46px; height: 64px; border-radius: 6px; object-fit: cover; border: 1px solid var(--accent-gold);">
|
||||
@@ -974,7 +968,7 @@
|
||||
<span id="relics-tab-lc-stats" style="color: var(--accent-cyan); font-family: monospace;">HP 952 / ATK 582 / DEF 529</span>
|
||||
</div>
|
||||
</div>
|
||||
<button type="button" class="btn btn-sm btn-primary" style="pointer-events: none;">เลือกเปลี่ยน</button>
|
||||
<button type="button" class="btn btn-sm btn-primary" style="pointer-events: none;" data-i18n="btnChangeLc">เลือกเปลี่ยน</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1011,7 +1005,7 @@
|
||||
<div class="skill-row-card">
|
||||
<div class="skill-row-header">
|
||||
<div style="display: flex; align-items: center; gap: 0.65rem;">
|
||||
<img id="skill-icon-basic" class="skill-row-icon" src="" alt="Basic ATK">
|
||||
<img id="skill-icon-basic" class="skill-row-icon" src="" alt="Basic ATK" data-i18n-alt="modalSkillBasic">
|
||||
<div>
|
||||
<div style="display: flex; align-items: center; gap: 0.4rem;">
|
||||
<span class="skill-type-tag" data-i18n="modalSkillBasic">โจมตีปกติ</span>
|
||||
@@ -1034,7 +1028,7 @@
|
||||
<div class="skill-row-card">
|
||||
<div class="skill-row-header">
|
||||
<div style="display: flex; align-items: center; gap: 0.65rem;">
|
||||
<img id="skill-icon-skill" class="skill-row-icon" src="" alt="Skill">
|
||||
<img id="skill-icon-skill" class="skill-row-icon" src="" alt="Skill" data-i18n-alt="modalSkillSkill">
|
||||
<div>
|
||||
<div style="display: flex; align-items: center; gap: 0.4rem;">
|
||||
<span class="skill-type-tag" data-i18n="modalSkillSkill">สกิลต่อสู้</span>
|
||||
@@ -1057,7 +1051,7 @@
|
||||
<div class="skill-row-card">
|
||||
<div class="skill-row-header">
|
||||
<div style="display: flex; align-items: center; gap: 0.65rem;">
|
||||
<img id="skill-icon-ultra" class="skill-row-icon" src="" alt="Ultimate">
|
||||
<img id="skill-icon-ultra" class="skill-row-icon" src="" alt="Ultimate" data-i18n-alt="modalSkillUltra">
|
||||
<div>
|
||||
<div style="display: flex; align-items: center; gap: 0.4rem;">
|
||||
<span class="skill-type-tag" data-i18n="modalSkillUltra">ท่าไม้ตาย</span>
|
||||
@@ -1080,7 +1074,7 @@
|
||||
<div class="skill-row-card">
|
||||
<div class="skill-row-header">
|
||||
<div style="display: flex; align-items: center; gap: 0.65rem;">
|
||||
<img id="skill-icon-talent" class="skill-row-icon" src="" alt="Talent">
|
||||
<img id="skill-icon-talent" class="skill-row-icon" src="" alt="Talent" data-i18n-alt="modalSkillTalent">
|
||||
<div>
|
||||
<div style="display: flex; align-items: center; gap: 0.4rem;">
|
||||
<span class="skill-type-tag" data-i18n="modalSkillTalent">พรสวรรค์</span>
|
||||
@@ -1110,7 +1104,7 @@
|
||||
<div class="skill-row-card" style="padding: 0.75rem 1rem;">
|
||||
<div style="display: flex; justify-content: space-between; align-items: center;">
|
||||
<div style="display: flex; align-items: center; gap: 0.65rem;">
|
||||
<img id="skill-icon-technique" class="skill-row-icon" src="" alt="Technique">
|
||||
<img id="skill-icon-technique" class="skill-row-icon" src="" alt="Technique" data-i18n-alt="modalTraceTechnique">
|
||||
<div>
|
||||
<span class="skill-type-tag" data-i18n="modalTraceTechnique">เทคนิค</span>
|
||||
<span id="skill-real-name-technique" class="skill-name">-</span>
|
||||
@@ -1129,8 +1123,8 @@
|
||||
<div class="trace-card-item">
|
||||
<div style="display: flex; justify-content: space-between; align-items: center;">
|
||||
<div style="display: flex; align-items: center; gap: 0.5rem;">
|
||||
<img id="trace-icon-a2" class="trace-icon-small" src="" alt="A2">
|
||||
<span id="trace-name-a2" style="font-weight: 700; font-size: 0.875rem;">🌟 ร่องรอยพิเศษ A2</span>
|
||||
<img id="trace-icon-a2" class="trace-icon-small" src="" alt="A2" data-i18n-alt="traceA2">
|
||||
<span id="trace-name-a2" style="font-weight: 700; font-size: 0.875rem;" data-i18n="traceA2">🌟 ร่องรอยพิเศษ A2</span>
|
||||
</div>
|
||||
<label class="switch">
|
||||
<input type="checkbox" id="check-trace-a2" checked>
|
||||
@@ -1143,8 +1137,8 @@
|
||||
<div class="trace-card-item">
|
||||
<div style="display: flex; justify-content: space-between; align-items: center;">
|
||||
<div style="display: flex; align-items: center; gap: 0.5rem;">
|
||||
<img id="trace-icon-a4" class="trace-icon-small" src="" alt="A4">
|
||||
<span id="trace-name-a4" style="font-weight: 700; font-size: 0.875rem;">🌟 ร่องรอยพิเศษ A4</span>
|
||||
<img id="trace-icon-a4" class="trace-icon-small" src="" alt="A4" data-i18n-alt="traceA4">
|
||||
<span id="trace-name-a4" style="font-weight: 700; font-size: 0.875rem;" data-i18n="traceA4">🌟 ร่องรอยพิเศษ A4</span>
|
||||
</div>
|
||||
<label class="switch">
|
||||
<input type="checkbox" id="check-trace-a4" checked>
|
||||
@@ -1157,8 +1151,8 @@
|
||||
<div class="trace-card-item">
|
||||
<div style="display: flex; justify-content: space-between; align-items: center;">
|
||||
<div style="display: flex; align-items: center; gap: 0.5rem;">
|
||||
<img id="trace-icon-a6" class="trace-icon-small" src="" alt="A6">
|
||||
<span id="trace-name-a6" style="font-weight: 700; font-size: 0.875rem;">🌟 ร่องรอยพิเศษ A6</span>
|
||||
<img id="trace-icon-a6" class="trace-icon-small" src="" alt="A6" data-i18n-alt="traceA6">
|
||||
<span id="trace-name-a6" style="font-weight: 700; font-size: 0.875rem;" data-i18n="traceA6">🌟 ร่องรอยพิเศษ A6</span>
|
||||
</div>
|
||||
<label class="switch">
|
||||
<input type="checkbox" id="check-trace-a6" checked>
|
||||
@@ -1227,9 +1221,9 @@
|
||||
<div class="lc-preview-container">
|
||||
<!-- Left: Full vertical artwork card -->
|
||||
<div class="lc-art-wrapper" id="modal-lc-art-wrapper">
|
||||
<img id="modal-lc-full-img" class="lc-full-img" src="" alt="Light Cone Artwork">
|
||||
<img id="modal-lc-full-img" class="lc-full-img" src="" alt="Light Cone Artwork" data-i18n-alt="lightConeArtwork">
|
||||
<div id="modal-lc-no-art" class="lc-placeholder-text" style="display: none;">
|
||||
🗡️ ไม่มีรูปตัวอย่าง
|
||||
<span data-i18n="lightConeArtworkMissing">🗡️ ไม่มีรูปตัวอย่าง</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1294,7 +1288,7 @@
|
||||
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 1rem; flex-wrap: wrap; gap: 0.5rem;">
|
||||
<div style="font-weight: 800; font-size: 1rem; color: var(--text-highlight); display: flex; align-items: center; gap: 0.5rem;">
|
||||
<span data-i18n="modalTabShowcase">🖼️ การ์ดแสดงผล</span>
|
||||
<span class="btn-sm btn-secondary" id="showcase-build-tag">Build Overview</span>
|
||||
<span class="btn-sm btn-secondary" id="showcase-build-tag" data-i18n="overviewStatsTitle">Build Overview</span>
|
||||
</div>
|
||||
<div style="display: flex; gap: 0.5rem; flex-wrap: wrap;">
|
||||
<button type="button" class="btn btn-sm btn-gold" id="btn-showcase-auto-relics" data-i18n="showcaseAutoRelics">
|
||||
@@ -1317,6 +1311,11 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Sub Tab 5: Per-character build data and Prydwen guide -->
|
||||
<div id="modaltab-build-guide" class="modal-subtab-content" style="display: none;">
|
||||
<div id="build-guide-content" class="build-guide-content"></div>
|
||||
</div>
|
||||
|
||||
<!-- Modal Footer -->
|
||||
<div style="display: flex; gap: 0.75rem; margin-top: 1.5rem; justify-content: flex-end; flex-wrap: wrap;">
|
||||
<button type="button" class="btn btn-secondary" id="btn-modal-cancel-avatar" data-i18n="modalBtnClose">
|
||||
@@ -1379,7 +1378,7 @@
|
||||
<img id="add-lc-preview-thumb" src="" alt="" style="width: 44px; height: 60px; border-radius: 4px; object-fit: cover; border: 1px solid var(--accent-gold); background: #0b0d14; flex-shrink: 0;">
|
||||
<div style="flex: 1; min-width: 0;">
|
||||
<div style="font-size: 0.7rem; color: var(--accent-gold); font-weight: 800; text-transform: uppercase;">
|
||||
✓ กรวยแสงที่เลือก (Selected)
|
||||
<span data-i18n="selectedLightConeLabel">✓ กรวยแสงที่เลือก (Selected)</span>
|
||||
</div>
|
||||
<div id="add-lc-preview-name" style="font-weight: 800; font-size: 0.95rem; color: #fff; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;">-</div>
|
||||
<div id="add-lc-preview-meta" style="display: flex; gap: 0.65rem; font-size: 0.72rem; color: var(--text-muted); margin-top: 0.15rem; align-items: center; flex-wrap: wrap;">
|
||||
@@ -1392,7 +1391,7 @@
|
||||
|
||||
<!-- 2. Search & Filter Bar -->
|
||||
<div style="display: flex; gap: 0.5rem; margin-bottom: 0.6rem; flex-wrap: wrap;">
|
||||
<input type="text" id="add-lc-search" class="form-input" placeholder="🔍 ค้นหากรวยแสง (ชื่อหรือ ID)..." style="flex: 1; min-width: 160px;">
|
||||
<input type="text" id="add-lc-search" class="form-input" data-i18n-placeholder="lightConeSearchPlaceholder" placeholder="🔍 ค้นหากรวยแสง (ชื่อหรือ ID)..." style="flex: 1; min-width: 160px;">
|
||||
<select id="add-lc-filter-path" class="form-select" style="max-width: 140px;">
|
||||
<option value="all">ทุกสาย (All)</option>
|
||||
<option value="Destruction">ทำลายล้าง</option>
|
||||
@@ -1406,10 +1405,10 @@
|
||||
<option value="Elation">ปีติ</option>
|
||||
</select>
|
||||
<select id="add-lc-filter-rarity" class="form-select" style="max-width: 110px;">
|
||||
<option value="all">ทุกระดับดาว</option>
|
||||
<option value="5" selected>★5 ดาว</option>
|
||||
<option value="4">★4 ดาว</option>
|
||||
<option value="3">★3 ดาว</option>
|
||||
<option value="all" data-i18n="filterAllRarity">ทุกระดับดาว</option>
|
||||
<option value="5" selected data-i18n="filter5Star">★5 ดาว</option>
|
||||
<option value="4" data-i18n="filter4Star">★4 ดาว</option>
|
||||
<option value="3" data-i18n="filter3Star">★3 ดาว</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
@@ -1429,13 +1428,13 @@
|
||||
<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" style="font-size: 0.75rem;">Superimpose (ขัดเกลา)</label>
|
||||
<label class="form-label" data-i18n="superimpositionLabel" style="font-size: 0.75rem;">Superimpose (ขัดเกลา)</label>
|
||||
<select id="add-lc-rank" class="form-select" required>
|
||||
<option value="5" selected>S5 (ขัดเกลา 5)</option>
|
||||
<option value="4">S4 (ขัดเกลา 4)</option>
|
||||
<option value="3">S3 (ขัดเกลา 3)</option>
|
||||
<option value="2">S2 (ขัดเกลา 2)</option>
|
||||
<option value="1">S1 (ขัดเกลา 1)</option>
|
||||
<option value="5" selected data-superimposition-rank>S5 (ขัดเกลา 5)</option>
|
||||
<option value="4" data-superimposition-rank>S4 (ขัดเกลา 4)</option>
|
||||
<option value="3" data-superimposition-rank>S3 (ขัดเกลา 3)</option>
|
||||
<option value="2" data-superimposition-rank>S2 (ขัดเกลา 2)</option>
|
||||
<option value="1" data-superimposition-rank>S1 (ขัดเกลา 1)</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-group" style="margin-bottom: 0;">
|
||||
@@ -1474,12 +1473,12 @@
|
||||
<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>
|
||||
<option value="1" data-relic-slot="head">1: ส่วนหัว (Head / HP)</option>
|
||||
<option value="2" data-relic-slot="hands">2: ส่วนมือ (Hands / ATK)</option>
|
||||
<option value="3" data-relic-slot="body">3: ลำตัว (Body)</option>
|
||||
<option value="4" data-relic-slot="feet">4: รองเท้า (Feet)</option>
|
||||
<option value="5" data-relic-slot="sphere">5: ลูกแก้ว (Planar Sphere)</option>
|
||||
<option value="6" data-relic-slot="rope">6: สร้อยเชื่อมต่อ (Link Rope)</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-group" style="margin-bottom: 0;">
|
||||
@@ -1513,12 +1512,12 @@
|
||||
<div class="modal-content relic-picker-modal-content">
|
||||
<div class="modal-header" style="margin-bottom: 0.75rem;">
|
||||
<div style="display: flex; align-items: center; gap: 0.65rem;">
|
||||
<img id="modal-slot-picker-icon" src="" alt="Slot" style="width: 28px; height: 28px; object-fit: contain;">
|
||||
<img id="modal-slot-picker-icon" src="" alt="Slot" data-i18n-alt="slot" style="width: 28px; height: 28px; object-fit: contain;">
|
||||
<div>
|
||||
<h3 id="modal-slot-picker-title" style="font-weight: 800; font-size: 1.15rem; margin: 0;" data-i18n="slotPickerTitle">
|
||||
🛡️ เลือกสวมใส่รีลิกส์
|
||||
</h3>
|
||||
<div id="modal-slot-picker-subtitle" style="font-size: 0.75rem; color: var(--text-muted); margin-top: 2px;">
|
||||
<div id="modal-slot-picker-subtitle" style="font-size: 0.75rem; color: var(--text-muted); margin-top: 2px;" data-i18n="slotPickerSubtitle">
|
||||
เลือกสวมใส่ชิ้นที่มีอยู่ หรือสร้างชิ้นใหม่ตรงตามบิลด์ที่แนะนำ
|
||||
</div>
|
||||
</div>
|
||||
@@ -1567,15 +1566,15 @@
|
||||
<!-- Substats Customizer -->
|
||||
<div class="slot-picker-substats-section">
|
||||
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 0.5rem; flex-wrap: wrap; gap: 0.5rem;">
|
||||
<div style="font-weight: 700; font-size: 0.85rem; color: var(--text-highlight);">
|
||||
<div style="font-weight: 700; font-size: 0.85rem; color: var(--text-highlight);" data-i18n="substatCustomizerTitle">
|
||||
🔧 ปรับแต่งออฟรอง (Substats Customizer):
|
||||
</div>
|
||||
<div class="substat-presets-strip">
|
||||
<button type="button" class="btn-substat-preset" data-preset="god" title="ออฟแนะนำตามตัวละคร">⭐ ออฟเทพแนะนำ</button>
|
||||
<button type="button" class="btn-substat-preset" data-preset="crit" title="เน้นคริล้วน">🎯 คริ Rate/DMG</button>
|
||||
<button type="button" class="btn-substat-preset" data-preset="spd" title="เน้นความเร็ว">⚡ สปีด SPD</button>
|
||||
<button type="button" class="btn-substat-preset" data-preset="break" title="เน้นทำลายล้าง">🔨 Break Effect</button>
|
||||
<button type="button" class="btn-substat-preset" data-preset="tank" title="เน้นถึก ป้องกัน เลือด">🛡️ ถึก HP/DEF</button>
|
||||
<button type="button" class="btn-substat-preset" data-preset="god" data-i18n="substatPresetRecommended" data-i18n-title="substatPresetRecommended" title="ออฟแนะนำตามตัวละคร">⭐ ออฟเทพแนะนำ</button>
|
||||
<button type="button" class="btn-substat-preset" data-preset="crit" data-i18n="substatPresetCrit" data-i18n-title="substatPresetCrit" title="เน้นคริล้วน">🎯 คริ Rate/DMG</button>
|
||||
<button type="button" class="btn-substat-preset" data-preset="spd" data-i18n="substatPresetSpeed" data-i18n-title="substatPresetSpeed" title="เน้นความเร็ว">⚡ สปีด SPD</button>
|
||||
<button type="button" class="btn-substat-preset" data-preset="break" data-i18n="substatPresetBreak" data-i18n-title="substatPresetBreak" title="เน้นทำลายล้าง">🔨 Break Effect</button>
|
||||
<button type="button" class="btn-substat-preset" data-preset="tank" data-i18n="substatPresetTank" data-i18n-title="substatPresetTank" title="เน้นถึก ป้องกัน เลือด">🛡️ ถึก HP/DEF</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1585,9 +1584,9 @@
|
||||
|
||||
<div style="display: flex; justify-content: space-between; align-items: center; margin-top: 0.65rem; padding: 0.4rem 0.75rem; background: rgba(10, 14, 23, 0.75); border-radius: var(--radius-sm); border: 1px solid var(--border-color); font-size: 0.775rem;">
|
||||
<span style="color: var(--text-muted);">
|
||||
💡 รวมจำนวนโรล (Rolls): <strong id="slot-picker-total-rolls" style="color: var(--accent-gold); font-family: monospace; font-size: 0.9rem;">9</strong> / 9 โรล (ระดับ 5★ เลเวล 15)
|
||||
<span data-i18n="substatRollCountLabel">💡 รวมจำนวนโรล (Rolls):</span> <strong id="slot-picker-total-rolls" style="color: var(--accent-gold); font-family: monospace; font-size: 0.9rem;">9</strong> <span id="slot-picker-roll-limit" data-i18n="substatRollLimit">/ 9 โรล (ระดับ 5★ เลเวล 15)</span>
|
||||
</span>
|
||||
<button type="button" class="btn btn-sm btn-secondary" id="btn-reset-substats" style="font-size: 0.725rem; padding: 0.2rem 0.6rem;">↺ คืนค่าเดิม</button>
|
||||
<button type="button" class="btn btn-sm btn-secondary" id="btn-reset-substats" data-i18n="substatResetButton" style="font-size: 0.725rem; padding: 0.2rem 0.6rem;">↺ คืนค่าเดิม</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1621,7 +1620,7 @@
|
||||
|
||||
<!-- Search & Filters -->
|
||||
<div style="display: flex; gap: 0.5rem; margin-bottom: 0.75rem; flex-wrap: wrap;">
|
||||
<input type="text" id="lc-picker-search" class="form-input" placeholder="🔍 ค้นหาชื่อหรือ ID กรวยแสง..." style="flex: 1; min-width: 160px;">
|
||||
<input type="text" id="lc-picker-search" class="form-input" data-i18n-placeholder="lightConeSearchPlaceholder" placeholder="🔍 ค้นหาชื่อหรือ ID กรวยแสง..." style="flex: 1; min-width: 160px;">
|
||||
<select id="lc-picker-filter-path" class="form-select" style="max-width: 140px;">
|
||||
<option value="all">ทุกสาย</option>
|
||||
<option value="same" selected>ตรงสายตัวละคร</option>
|
||||
@@ -1635,12 +1634,12 @@
|
||||
<option value="Remembrance">ความทรงจำ</option>
|
||||
<option value="Elation">ปีติ</option>
|
||||
</select>
|
||||
<select id="lc-picker-rank" class="form-select" style="max-width: 110px;" title="ระดับการขัดเกลาเมื่อสวมใส่">
|
||||
<option value="5" selected>ขัดเกลา S5</option>
|
||||
<option value="4">ขัดเกลา S4</option>
|
||||
<option value="3">ขัดเกลา S3</option>
|
||||
<option value="2">ขัดเกลา S2</option>
|
||||
<option value="1">ขัดเกลา S1</option>
|
||||
<select id="lc-picker-rank" class="form-select" style="max-width: 110px;" data-i18n-title="superimpositionSelectTitle" title="ระดับการขัดเกลาเมื่อสวมใส่">
|
||||
<option value="5" selected data-superimposition-rank>ขัดเกลา S5</option>
|
||||
<option value="4" data-superimposition-rank>ขัดเกลา S4</option>
|
||||
<option value="3" data-superimposition-rank>ขัดเกลา S3</option>
|
||||
<option value="2" data-superimposition-rank>ขัดเกลา S2</option>
|
||||
<option value="1" data-superimposition-rank>ขัดเกลา S1</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
@@ -1673,6 +1672,6 @@
|
||||
<div class="toast-container" id="toast-container"></div>
|
||||
|
||||
<!-- Script Modules -->
|
||||
<script type="module" src="js/app.js?v=2.1"></script>
|
||||
<script type="module" src="js/app.js?v=2.9"></script>
|
||||
</body>
|
||||
</html>
|
||||
File diff suppressed because it is too large.
Load diff
+1859
-2
File diff suppressed because it is too large.
Load diff
@@ -5,6 +5,7 @@
|
||||
"main": "index.html",
|
||||
"scripts": {
|
||||
"sync-branch": "node scripts/sync-branch.js",
|
||||
"sync-build-guides": "node scripts/sync-build-guides.mjs",
|
||||
"dev": "node scripts/sync-branch.js && npx serve . -l 5173",
|
||||
"start": "node scripts/sync-branch.js && npx serve . -l 5173",
|
||||
"serve": "npx serve . -l 5173"
|
||||
|
||||
@@ -0,0 +1,151 @@
|
||||
import { mkdir, readFile, writeFile } from 'node:fs/promises';
|
||||
import { dirname, resolve } from 'node:path';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
|
||||
const repoRoot = resolve(dirname(fileURLToPath(import.meta.url)), '..');
|
||||
const avatarSource = await readFile(resolve(repoRoot, 'js/avatars-data.js'), 'utf8');
|
||||
const metadataMatch = avatarSource.match(/export const AVATAR_METADATA = (\{[\s\S]*?\n\});/);
|
||||
if (!metadataMatch) throw new Error('Could not read AVATAR_METADATA from js/avatars-data.js');
|
||||
const avatarMetadata = JSON.parse(metadataMatch[1]);
|
||||
|
||||
const headers = { 'User-Agent': 'GaC-Srtool build guide data sync' };
|
||||
const treeResponse = await fetch('https://huggingface.co/api/datasets/LvlUrArti/MocDataProcessed/tree/main?recursive=true', { headers });
|
||||
if (!treeResponse.ok) throw new Error(`Dataset file listing failed: HTTP ${treeResponse.status}`);
|
||||
const files = await treeResponse.json();
|
||||
const versions = [...new Set(files
|
||||
.filter(file => file.type === 'directory' && /^\d+\.\d+\.\d+$/.test(file.path))
|
||||
.map(file => file.path))]
|
||||
.sort((left, right) => left.localeCompare(right, undefined, { numeric: true }));
|
||||
const version = versions.at(-1);
|
||||
if (!version) throw new Error('No versioned build snapshot was found in the dataset');
|
||||
|
||||
const [configResponse, buildsResponse] = await Promise.all([
|
||||
fetch('https://huggingface.co/datasets/LvlUrArti/MocDataProcessed/resolve/main/config.json', { headers }),
|
||||
fetch(`https://huggingface.co/datasets/LvlUrArti/MocDataProcessed/resolve/main/${version}/builds.json`, { headers })
|
||||
]);
|
||||
if (!configResponse.ok || !buildsResponse.ok) {
|
||||
throw new Error(`Could not download snapshot ${version} (config ${configResponse.status}, builds ${buildsResponse.status})`);
|
||||
}
|
||||
const [config, sourceBuilds] = await Promise.all([configResponse.json(), buildsResponse.json()]);
|
||||
const snapshot = config[version];
|
||||
if (!snapshot?.collect_date || !Array.isArray(sourceBuilds)) {
|
||||
throw new Error(`Snapshot ${version} is missing its date or build rows`);
|
||||
}
|
||||
|
||||
const slugOverrides = {
|
||||
'1001': 'march-7th',
|
||||
'1112': 'topaz',
|
||||
'1213': 'imbibitor-lunae',
|
||||
'1225': 'tingyun-fugue',
|
||||
'1224': 'march-7th-swordmaster',
|
||||
'1413': 'march-7th-evernight',
|
||||
'1414': 'dan-heng-permansor-terrae',
|
||||
'1506': 'silver-wolf-lv-999',
|
||||
'1507': 'blade-mortenax',
|
||||
'1510': 'himeko-nova',
|
||||
'1511': 'aeon-aha',
|
||||
'1512': 'robin-summeretto',
|
||||
'1513': 'aventurine-waveflair',
|
||||
'8001': 'trailblazer-destruction',
|
||||
'8002': 'trailblazer-destruction',
|
||||
'8003': 'trailblazer-preservation',
|
||||
'8004': 'trailblazer-preservation',
|
||||
'8005': 'trailblazer-harmony',
|
||||
'8006': 'trailblazer-harmony',
|
||||
'8007': 'trailblazer-remembrance',
|
||||
'8008': 'trailblazer-remembrance',
|
||||
'8009': 'trailblazer-elation',
|
||||
'8010': 'trailblazer-elation'
|
||||
};
|
||||
|
||||
function slugify(name = '') {
|
||||
return name.toLowerCase()
|
||||
.replace(/•/g, ' ')
|
||||
.replace(/&/g, ' ')
|
||||
.replace(/[^a-z0-9]+/g, '-')
|
||||
.replace(/^-|-$/g, '');
|
||||
}
|
||||
|
||||
function rankedValues(row, namePrefix, usagePrefix, count = 4) {
|
||||
const values = [];
|
||||
for (let index = 1; index <= count; index += 1) {
|
||||
const name = String(row[`${namePrefix}${index}`] || '').trim();
|
||||
const usage = Number(row[`${usagePrefix}${index}_app`] ?? row[`${namePrefix}${index}_app`] ?? 0);
|
||||
if (name && usage > 0) values.push({ name, usage: Math.round(usage * 100) / 100 });
|
||||
}
|
||||
return values.sort((left, right) => right.usage - left.usage);
|
||||
}
|
||||
|
||||
function rankedStats(row, statPrefix) {
|
||||
const stats = [];
|
||||
for (let index = 1; index <= 3; index += 1) {
|
||||
const name = String(row[`${statPrefix}_stats_${index}`] || '').trim();
|
||||
const usage = Number(row[`${statPrefix}_stats_${index}_app`] || 0);
|
||||
if (name && usage > 0) stats.push({ name, usage: Math.round(usage * 100) / 100 });
|
||||
}
|
||||
return stats.sort((left, right) => right.usage - left.usage);
|
||||
}
|
||||
|
||||
const endgameModes = [
|
||||
['moc', 'Memory of Chaos'],
|
||||
['pf', 'Pure Fiction'],
|
||||
['as', 'Apocalyptic Shadow'],
|
||||
['aa', 'Anomaly Arbitration']
|
||||
];
|
||||
const getLargestSample = row => endgameModes.reduce((best, [key, label]) => {
|
||||
const count = Number(row[`sample_size_players_${key}`] || 0);
|
||||
return count > best.count ? { count, mode: label } : best;
|
||||
}, { count: 0, mode: '' });
|
||||
|
||||
// The source file includes current and comparison rows with duplicate slugs; keep
|
||||
// the row with the largest current endgame sample instead of letting the last
|
||||
// comparison row silently replace it.
|
||||
const sourceBySlug = new Map();
|
||||
for (const row of sourceBuilds) {
|
||||
const previous = sourceBySlug.get(row.char);
|
||||
if (!previous || getLargestSample(row).count > getLargestSample(previous).count) {
|
||||
sourceBySlug.set(row.char, row);
|
||||
}
|
||||
}
|
||||
const profiles = {};
|
||||
const missingSlugs = new Set();
|
||||
|
||||
for (const [avatarId, metadata] of Object.entries(avatarMetadata)) {
|
||||
const slug = slugOverrides[avatarId] || slugify(metadata.names?.en);
|
||||
const row = sourceBySlug.get(slug);
|
||||
if (!row) {
|
||||
missingSlugs.add(slug);
|
||||
continue;
|
||||
}
|
||||
|
||||
profiles[avatarId] = {
|
||||
slug,
|
||||
...getLargestSample(row),
|
||||
lightCones: rankedValues(row, 'weapons_', 'weapons_', 5),
|
||||
relicSets: rankedValues(row, 'artifacts_', 'artifacts_', 5),
|
||||
planarSets: rankedValues(row, 'planars_', 'planars_', 5),
|
||||
mainStats: {
|
||||
body: rankedStats(row, 'body'),
|
||||
feet: rankedStats(row, 'feet'),
|
||||
sphere: rankedStats(row, 'sphere'),
|
||||
rope: rankedStats(row, 'rope')
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
const output = {
|
||||
source: {
|
||||
dataset: 'LvlUrArti/MocDataProcessed',
|
||||
license: 'MIT',
|
||||
credit: 'LvlUrArti',
|
||||
version,
|
||||
collectedAt: snapshot.collect_date,
|
||||
note: 'Prydwen endgame build usage sample; not a curated or official ranking.'
|
||||
},
|
||||
profiles
|
||||
};
|
||||
const outputPath = resolve(repoRoot, 'js/build-guides-data.js');
|
||||
await mkdir(dirname(outputPath), { recursive: true });
|
||||
await writeFile(outputPath, `// Generated by scripts/sync-build-guides.mjs; see README for source and attribution.\nexport const PRYDWEN_BUILD_GUIDES = ${JSON.stringify(output, null, 2)};\n`, 'utf8');
|
||||
console.log(`Wrote ${Object.keys(profiles).length} avatar profiles from snapshot ${version} (${snapshot.collect_date}).`);
|
||||
if (missingSlugs.size) console.log(`No dataset row for: ${[...missingSlugs].sort().join(', ')}`);
|
||||
Reference in new issue
Block a user