diff --git a/www/html/Admin/admin.css b/www/html/Admin/admin.css index 355bd35..4b5daa5 100644 --- a/www/html/Admin/admin.css +++ b/www/html/Admin/admin.css @@ -669,14 +669,92 @@ legend { border-radius: 999px; white-space: nowrap; } -.sq-card-grid { + +/* —— เลือกการ์ดพิเศษ (card-1..7 จาก trycss/10-Game-1-result) —— */ +.sq-card-picker-wrap { + display: flex; + flex-wrap: wrap; + gap: 1.25rem; + align-items: flex-start; + margin-bottom: 1rem; +} +.sq-card-picker { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(88px, 1fr)); + gap: 0.65rem; + flex: 1 1 420px; + max-width: 720px; +} +.sq-card-pick { + display: flex; + flex-direction: column; + align-items: center; + gap: 0.35rem; + padding: 0.45rem 0.35rem 0.5rem; + border: 2px solid var(--border); + border-radius: 12px; + background: rgba(255, 255, 255, 0.03); + cursor: pointer; + transition: border-color 0.15s, box-shadow 0.15s, transform 0.12s; +} +.sq-card-pick:hover { + border-color: rgba(122, 162, 247, 0.55); + transform: translateY(-1px); +} +.sq-card-pick.is-selected { + border-color: var(--accent); + box-shadow: 0 0 0 2px rgba(122, 162, 247, 0.35), 0 4px 16px rgba(0, 0, 0, 0.25); + background: var(--accent-dim); +} +.sq-card-pick img { + width: 72px; + height: auto; + max-height: 96px; + object-fit: contain; + display: block; + image-rendering: auto; +} +.sq-card-pick-cap { + font-size: 0.68rem; + font-weight: 600; + color: var(--muted); + text-align: center; + line-height: 1.15; + max-width: 100%; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} +.sq-card-pick.is-selected .sq-card-pick-cap { color: var(--accent); } +.sq-card-preview { + flex: 0 0 auto; + padding: 0.75rem; + border: 1px solid var(--border); + border-radius: var(--radius); + background: rgba(0, 0, 0, 0.25); + text-align: center; +} +.sq-card-preview-label { + margin: 0 0 0.5rem; + font-size: 0.78rem; + color: var(--muted); +} +.sq-card-preview-img { + width: 120px; + height: auto; + max-height: 160px; + object-fit: contain; + display: block; + margin: 0 auto; +} +.sq-card-meta { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 0.85rem; + margin-top: 0.25rem; } -.sq-card-grid .sq-card-url { grid-column: 1 / -1; } -.sq-card-grid input, -.sq-card-grid select { width: 100%; } +.sq-card-meta input, +.sq-card-meta select { width: 100%; } .sq-count { font-weight: 400; font-size: 0.8rem; diff --git a/www/html/Admin/admin.js b/www/html/Admin/admin.js index 715309a..024ea11 100644 --- a/www/html/Admin/admin.js +++ b/www/html/Admin/admin.js @@ -248,8 +248,129 @@ /* ===== ชุดคำถามพิเศษ (Level×Case = 15 ชุด) รับการ์ดพิเศษ ===== */ var SPECIAL_CARD_RARITIES = ['common', 'rare', 'legendary']; + var SPECIAL_CARD_ASSET_BASE = '/Game/img/special-cards/'; + var SPECIAL_CARD_CATALOG = [ + { id: 1, en: 'Time Dilation', th: 'เพิ่มเวลาเล่นมินิเกมทันที (+10 วินาที)' }, + { id: 2, en: 'Extension', th: 'เพิ่มเวลาในห้องพิจารณาคดี (+10 วิ FINAL VOTE)' }, + { id: 3, en: 'Ban Card', th: 'ห้ามเล่นมินิเกม 1 ตา' }, + { id: 4, en: 'Silence Card', th: 'การ์ดปิดปาก' }, + { id: 5, en: 'Bail Coin', th: 'เหรียญประกันตัว' }, + { id: 6, en: 'Fund', th: 'รับ coin เพิ่ม' }, + { id: 7, en: 'Free Evidence', th: 'รับหลักฐานฟรี' }, + ]; var specialQuizSetsState = {}; var specialQuizCurrentKey = 'L1_C1'; + var specialCardPickerBuilt = false; + + function specialCardTxtFilename(id) { + return id === 7 ? 'card--7txt.png' : 'card-' + id + '-txt.png'; + } + + function specialCardImageUrl(id) { + return SPECIAL_CARD_ASSET_BASE + 'card-' + id + '.png'; + } + + function specialCardTxtImageUrl(id) { + return SPECIAL_CARD_ASSET_BASE + specialCardTxtFilename(id); + } + + function specialCardCatalogEntry(id) { + for (var i = 0; i < SPECIAL_CARD_CATALOG.length; i++) { + if (SPECIAL_CARD_CATALOG[i].id === id) return SPECIAL_CARD_CATALOG[i]; + } + return null; + } + + function resolveSpecialCardIdFromSaved(card) { + if (!card || typeof card !== 'object') return null; + var cid = Number(card.cardId); + if (cid >= 1 && cid <= 7) return cid; + var url = String(card.imageUrl || ''); + var m = url.match(/\/card-(\d)\.png/i); + return m ? Number(m[1]) : null; + } + + function updateSpecialCardPreview() { + var prev = el('special-card-preview'); + var img = el('special-card-preview-img'); + var cid = parseInt(el('special-card-id') && el('special-card-id').value, 10); + if (!prev || !img) return; + if (!(cid >= 1 && cid <= 7)) { + prev.hidden = true; + img.removeAttribute('src'); + return; + } + img.src = specialCardImageUrl(cid); + img.alt = (specialCardCatalogEntry(cid) || {}).en || ('Card ' + cid); + prev.hidden = false; + } + + function setSpecialCardPickerSelection(cardId) { + var picker = el('special-card-picker'); + if (!picker) return; + picker.querySelectorAll('.sq-card-pick').forEach(function (btn) { + var on = String(btn.getAttribute('data-card-id')) === String(cardId); + btn.classList.toggle('is-selected', on); + btn.setAttribute('aria-checked', on ? 'true' : 'false'); + }); + } + + function selectSpecialCard(cardId, fillMeta) { + var idInp = el('special-card-id'); + var imgInp = el('special-card-image'); + var txtInp = el('special-card-txt-image'); + if (!(cardId >= 1 && cardId <= 7)) { + if (idInp) idInp.value = ''; + if (imgInp) imgInp.value = ''; + if (txtInp) txtInp.value = ''; + setSpecialCardPickerSelection(null); + updateSpecialCardPreview(); + return; + } + var entry = specialCardCatalogEntry(cardId); + if (idInp) idInp.value = String(cardId); + if (imgInp) imgInp.value = specialCardImageUrl(cardId); + if (txtInp) txtInp.value = specialCardTxtImageUrl(cardId); + if (fillMeta && entry) { + if (el('special-card-th')) el('special-card-th').value = entry.th; + if (el('special-card-en')) el('special-card-en').value = entry.en; + } + setSpecialCardPickerSelection(cardId); + updateSpecialCardPreview(); + } + + function ensureSpecialCardPicker() { + if (specialCardPickerBuilt) return; + var picker = el('special-card-picker'); + if (!picker) return; + picker.innerHTML = ''; + SPECIAL_CARD_CATALOG.forEach(function (entry) { + var btn = document.createElement('button'); + btn.type = 'button'; + btn.className = 'sq-card-pick'; + btn.setAttribute('role', 'radio'); + btn.setAttribute('aria-checked', 'false'); + btn.setAttribute('data-card-id', String(entry.id)); + btn.title = entry.en + ' — ' + entry.th; + var img = document.createElement('img'); + img.src = specialCardImageUrl(entry.id); + img.alt = entry.en; + img.width = 72; + img.height = 96; + img.decoding = 'async'; + img.loading = 'lazy'; + var cap = document.createElement('span'); + cap.className = 'sq-card-pick-cap'; + cap.textContent = entry.en; + btn.appendChild(img); + btn.appendChild(cap); + btn.addEventListener('click', function () { + selectSpecialCard(entry.id, true); + }); + picker.appendChild(btn); + }); + specialCardPickerBuilt = true; + } function specialQuizSelectorKey() { var L = el('special-quiz-level'); @@ -260,7 +381,7 @@ function updateSpecialQuizCount() { var c = el('special-quiz-count'); if (!c) return; - var n = document.querySelectorAll('#special-quiz-questions-list .quiz-admin-q-row').length; + var n = document.querySelectorAll('#special-quiz-questions-list .sq-mcq-row').length; c.textContent = '(' + n + ' ข้อ)'; } @@ -345,14 +466,18 @@ } function renderSpecialQuizSet(key) { + ensureSpecialCardPicker(); var set = specialQuizSetsState[key] || { questions: [], specialCard: {} }; var card = (set.specialCard && typeof set.specialCard === 'object') ? set.specialCard : {}; - if (el('special-card-th')) el('special-card-th').value = card.th || ''; - if (el('special-card-en')) el('special-card-en').value = card.en || ''; + var cardId = resolveSpecialCardIdFromSaved(card); + selectSpecialCard(cardId, false); + if (el('special-card-th')) el('special-card-th').value = card.th || (cardId ? (specialCardCatalogEntry(cardId) || {}).th : '') || ''; + if (el('special-card-en')) el('special-card-en').value = card.en || (cardId ? (specialCardCatalogEntry(cardId) || {}).en : '') || ''; if (el('special-card-rarity')) { el('special-card-rarity').value = SPECIAL_CARD_RARITIES.indexOf(card.rarity) >= 0 ? card.rarity : 'rare'; } - if (el('special-card-image')) el('special-card-image').value = card.imageUrl || ''; + if (cardId && el('special-card-image')) el('special-card-image').value = card.imageUrl || specialCardImageUrl(cardId); + if (cardId && el('special-card-txt-image')) el('special-card-txt-image').value = card.txtImageUrl || specialCardTxtImageUrl(cardId); var list = el('special-quiz-questions-list'); if (list) { list.innerHTML = ''; @@ -386,13 +511,17 @@ questions.push({ type: 'mcq', text: t, choices: choices, correctIndex: correctIndex }); }); var rar = el('special-card-rarity') ? el('special-card-rarity').value : 'rare'; + var cardId = parseInt(el('special-card-id') && el('special-card-id').value, 10); + if (!(cardId >= 1 && cardId <= 7)) cardId = null; specialQuizSetsState[key] = { questions: questions, specialCard: { + cardId: cardId, th: el('special-card-th') ? String(el('special-card-th').value || '').trim() : '', en: el('special-card-en') ? String(el('special-card-en').value || '').trim() : '', rarity: SPECIAL_CARD_RARITIES.indexOf(rar) >= 0 ? rar : 'rare', imageUrl: el('special-card-image') ? String(el('special-card-image').value || '').trim() : '', + txtImageUrl: el('special-card-txt-image') ? String(el('special-card-txt-image').value || '').trim() : '', }, }; } diff --git a/www/html/Admin/index.html b/www/html/Admin/index.html index 6478626..2407bb0 100644 --- a/www/html/Admin/index.html +++ b/www/html/Admin/index.html @@ -10,7 +10,7 @@ - +
ข้ามไปเนื้อหา @@ -269,12 +269,23 @@