minigame 4 font table question

This commit is contained in:
2026-04-29 13:54:51 +00:00
parent aab6489640
commit 9e2cff2935
8 changed files with 286 additions and 48 deletions
+33 -1
View File
@@ -520,11 +520,26 @@
var bw = bwEl ? parseInt(String(bwEl.value || '2'), 10) : 2;
if (!Number.isFinite(bw)) bw = 2;
bw = Math.max(0, Math.min(12, Math.round(bw)));
var qfMinEl = el('quiz-carry-theme-qfont-min');
var qfMaxEl = el('quiz-carry-theme-qfont-max');
var qMin = qfMinEl ? parseInt(String(qfMinEl.value || '10'), 10) : 10;
var qMax = qfMaxEl ? parseInt(String(qfMaxEl.value || '24'), 10) : 24;
if (!Number.isFinite(qMin)) qMin = 10;
if (!Number.isFinite(qMax)) qMax = 24;
qMin = Math.max(10, Math.min(40, Math.round(qMin)));
qMax = Math.max(14, Math.min(56, Math.round(qMax)));
if (qMax < qMin) {
var swap = qMin;
qMin = qMax;
qMax = swap;
}
return {
panelBg: (sBg && sBg.trim()) ? sBg.trim().slice(0, 120) : quizCarryRgbToRgbaString(fbBg),
panelBorder: (sBr && sBr.trim()) ? sBr.trim().slice(0, 120) : quizCarryRgbToRgbaString(fbBr),
textColor: (sTx && sTx.trim()) ? sTx.trim().slice(0, 120) : quizCarryRgbToRgbaString(fbTx),
borderWidthPx: bw,
questionFontMinPx: qMin,
questionFontMaxPx: qMax,
};
}
@@ -1223,7 +1238,14 @@
gameQuizFetch('GET').then(function (data) {
if (opts.themeOverride && typeof opts.themeOverride === 'object') {
var ov = opts.themeOverride;
if (ov.panelBg != null || ov.borderWidthPx != null || ov.panelBorder != null || ov.textColor != null) {
if (
ov.panelBg != null ||
ov.borderWidthPx != null ||
ov.panelBorder != null ||
ov.textColor != null ||
ov.questionFontMinPx != null ||
ov.questionFontMaxPx != null
) {
data.carryMapPanelTheme = ov;
} else if (ov.carryMapPanelTheme && typeof ov.carryMapPanelTheme === 'object') {
data.carryMapPanelTheme = ov.carryMapPanelTheme;
@@ -1279,6 +1301,16 @@
var bw = parseInt(String(th.borderWidthPx), 10);
bwInp.value = String(Number.isFinite(bw) && bw >= 0 ? Math.min(12, bw) : 2);
}
var qfMinInp = el('quiz-carry-theme-qfont-min');
var qfMaxInp = el('quiz-carry-theme-qfont-max');
if (qfMinInp) {
var qm = parseInt(String(th.questionFontMinPx), 10);
qfMinInp.value = String(Number.isFinite(qm) ? Math.max(10, Math.min(40, qm)) : 10);
}
if (qfMaxInp) {
var qx = parseInt(String(th.questionFontMaxPx), 10);
qfMaxInp.value = String(Number.isFinite(qx) ? Math.max(14, Math.min(56, qx)) : 24);
}
quizCarryEcdFillForm(data.carryEmbedCountdownTheme || {});
quizCarryPlaqueFillAllFromApi(data);
if (opts.clearMsg !== false) setMsg('quiz-carry-settings-msg', '', '');
+10 -1
View File
@@ -226,6 +226,15 @@
</div>
<input type="hidden" id="quiz-carry-theme-text" value="" />
</div>
<div class="quiz-carry-theme-row quiz-carry-theme-row--narrow" style="flex-wrap:wrap;gap:0.75rem 1.25rem;align-items:flex-end">
<label class="admin-field quiz-carry-theme-label">ขั้นต่ำ (px)
<input type="number" id="quiz-carry-theme-qfont-min" class="admin-inp-num" min="10" max="40" step="1" value="10" title="ขั้นต่ำ px หลังสูตรเดียวกับป้ายคำตอบ" aria-describedby="quiz-carry-theme-qfont-hint" />
</label>
<label class="admin-field quiz-carry-theme-label">เพดานขนาด (px)
<input type="number" id="quiz-carry-theme-qfont-max" class="admin-inp-num" min="14" max="56" step="1" value="24" title="เพดาน px (ค่าเริ่ม 24 = เหมือนป้ายคำตอบ)" />
</label>
</div>
<p id="quiz-carry-theme-qfont-hint" class="muted" style="margin:-0.25rem 0 0;font-size:0.78rem;line-height:1.45">ในเกมใช้<strong>สูตรเดียวกับป้ายคำตอบบนพื้น</strong>: <code>clamp(10, 24, tileSize×zoom×0.24×carryChoicePlaqueMapScale)</code> แล้ว clamp อีกชั้นด้วยค่าสองช่องนี้ · <em>English:</em> Same px formula as floor answer plaques; theme min/max clamp on top.</p>
</div>
</fieldset>
<fieldset class="quiz-carry-theme-fieldset" style="margin:0.75rem 0 1rem;padding:0.75rem 1rem;border:1px solid var(--border);border-radius:var(--radius);background:var(--bg-elevated)">
@@ -661,6 +670,6 @@
</div>
</main>
</div>
<script src="admin.js?v=47"></script>
<script src="admin.js?v=51"></script>
</body>
</html>
+5 -3
View File
@@ -9,11 +9,13 @@
"panelBg": "rgba(255, 0, 0, 0)",
"panelBorder": "rgba(255, 255, 255, 0)",
"textColor": "rgba(241, 245, 249, 1)",
"borderWidthPx": 0
"borderWidthPx": 0,
"questionFontMinPx": 10,
"questionFontMaxPx": 24
},
"carryEmbedCountdownTheme": {
"overlayBackdrop": "rgba(8, 10, 20, 0.42)",
"innerBg": "rgba(12, 14, 28, 0.82)",
"overlayBackdrop": "rgba(8, 10, 20, 0)",
"innerBg": "rgba(12, 14, 28, 0)",
"innerBorder": "rgba(122, 162, 247, 0.45)",
"innerBorderWpx": 1,
"innerRadiusPx": 12,
+153 -28
View File
@@ -406,17 +406,10 @@
for (let li = 0; li < PLAY_LAYER_ORDER.length; li++) {
const layerName = PLAY_LAYER_ORDER[li];
if (diskLayers && layerName !== 'shadow' && !diskLayers.has(layerName)) continue;
/* ห้าม fallback face จากทิศ down เมื่อเป็น up/left/right — จะได้ตาอยู่หลังหัวเพราะวางหน้าหน้าบนร่างหันหลัง */
const urls = layerName === 'shadow'
? shadowUrlCandidates(id, dir, frameIndex)
: (layerName === 'face' && dir !== 'down'
? (() => {
const u = layerUrlCandidates(id, dir, layerName, frameIndex);
layerUrlCandidates(id, 'down', layerName, frameIndex).forEach((x) => {
if (u.indexOf(x) === -1) u.push(x);
});
return u;
})()
: layerUrlCandidates(id, dir, layerName, frameIndex));
: layerUrlCandidates(id, dir, layerName, frameIndex);
const r = resolvePlayLayerImage(urls);
/* เงาโหลดช้า/404 บ่อย — อย่าให้บล็อกทั้งคอมโพส (ไม่งั้นตกไป fallback แถบแนวตั้งแทนเลเยอร์จริง) */
if (r.status === 'pending' && layerName === 'shadow') {
@@ -446,8 +439,8 @@
/* เหมือนเดิม: มีเลเยอร์แยกไฟล์เมื่อ API บอก hasLayerFiles หรือ probe เจอ — gen สีทำบน canvas จาก *_layer_* เท่านั้น */
const charHasLayerFiles = apiFlag === true
|| (apiFlag == null && playCharAnyDirectionLayered(characterId));
/* ct2: ยกเลิก composite เก่าที่เคย cache จาก fallback ย้อมทั้งสไปรต์ */
const cacheKey = [characterId, dir, frameIndex, tint.head, tint.hair, tint.body, 'ct2'].join('|');
/* ct3: ไม่ใช้ face จาก down บนทิศอื่น (แก้ตาหลังหัว) */
const cacheKey = [characterId, dir, frameIndex, tint.head, tint.hair, tint.body, 'ct3'].join('|');
const hit = playLayerCompositeCache.get(cacheKey);
if (hit) return hit;
@@ -810,6 +803,12 @@
textEl.style.removeProperty('--qmap-text-shadow');
textEl.style.removeProperty('color');
textEl.style.removeProperty('text-shadow');
textEl.style.removeProperty('font-size');
textEl.style.removeProperty('line-height');
textEl.style.removeProperty('width');
textEl.style.removeProperty('box-sizing');
textEl.style.removeProperty('max-height');
textEl.style.removeProperty('overflow');
}
/** ค่าเริ่มต้นแผงคำถามบนแผนที่ (ตรงกับ server defaultCarryMapPanelTheme) — ใช้เมื่อยังไม่โหลดจาก API */
@@ -819,9 +818,74 @@
panelBorder: 'rgba(255, 214, 102, 0.7)',
borderWidthPx: 2,
textColor: '#f1f5f9',
questionFontMinPx: 10,
questionFontMaxPx: 24,
};
}
/** ตรงกับ drawQuizCarryChoiceLabels — carryChoicePlaqueMapScale */
function quizCarryPlaqueMapScaleClampedPlay() {
const sc = Number(quizCarryPlaqueMapScale);
if (!Number.isFinite(sc)) return 1.25;
return Math.max(0.85, Math.min(2.5, sc));
}
/**
* ขนาดตวอกษรแผงคำถาม DOM ใหเทาปายคำตอบบนพ: Math.max(10, Math.min(24, tileSize*zoom*0.24*ps))
* แล clamp วย questionFontMinPx / questionFontMaxPx จากธ (าตองการใหญกวาปายไดโดยยกเพดาน max)
*/
function quizMapQuestionFontPxLikeCarryPlaques(th, zoomVal) {
const ts = tileSize * zoomVal;
const ps = quizCarryPlaqueMapScaleClampedPlay();
const base = Math.max(10, Math.min(24, ts * 0.24 * ps));
const fb = defaultCarryMapPanelThemePlay();
let mn = Number(th && th.questionFontMinPx);
let mx = Number(th && th.questionFontMaxPx);
if (!Number.isFinite(mn)) mn = fb.questionFontMinPx;
if (!Number.isFinite(mx)) mx = fb.questionFontMaxPx;
mn = Math.round(Math.max(8, Math.min(40, mn)));
mx = Math.round(Math.max(10, Math.min(72, mx)));
if (mx < mn) {
const s = mn;
mn = mx;
mx = s;
}
return Math.max(mn, Math.min(mx, base));
}
/**
* ลด px ละ 1 จนเนอหาไมนกลอง (ไมใช scrollbar)
* zoom out กลองเตยมาก: อนญาตตำกว questionFontMinPx ของธมได hardMin (6) ไมใหบรรทดถกต
* แผงใช justify-content:flex-start ใน CSS ไมดกงกลางแนวตงแลวโดน overflow ดบน-าง
*/
function fitQuizMapQuestionFontToPanel(panel, textEl, startPx, minPx) {
const cs = window.getComputedStyle(panel);
const padT = parseFloat(cs.paddingTop) || 0;
const padB = parseFloat(cs.paddingBottom) || 0;
const padL = parseFloat(cs.paddingLeft) || 0;
const padR = parseFloat(cs.paddingRight) || 0;
const availH = Math.max(12, panel.clientHeight - padT - padB);
const availW = Math.max(24, panel.clientWidth - padL - padR);
const themeMin = Math.max(8, Math.floor(Number(minPx) || 8));
const hardMin = Math.min(themeMin, Math.max(6, Math.floor(availH / 7)));
let px = Math.round(Math.min(80, Math.max(hardMin, Number(startPx) || hardMin)));
textEl.style.setProperty('line-height', '1.28', 'important');
textEl.style.setProperty('width', '100%', 'important');
textEl.style.setProperty('box-sizing', 'border-box', 'important');
textEl.style.removeProperty('max-height');
textEl.style.setProperty('overflow', 'hidden', 'important');
for (let i = 0; i < 96 && px > hardMin; i++) {
textEl.style.setProperty('font-size', String(px) + 'px', 'important');
const sh = textEl.scrollHeight;
const sw = textEl.scrollWidth;
if (sh <= availH + 2 && sw <= availW + 2) break;
px -= 1;
}
textEl.style.setProperty('font-size', String(px) + 'px', 'important');
textEl.style.setProperty('max-height', availH + 'px', 'important');
}
/** ธีมจาก quiz-settings / join API — ถ้า JSON ไม่มีฟอนต์ให้ใช้ค่าเริ่มต้น */
function parseCarryMapPanelThemeObject(raw) {
let t = raw;
if (typeof t === 'string') {
@@ -834,14 +898,71 @@
if (!t || typeof t !== 'object') return null;
const bw = Number(t.borderWidthPx);
const borderWidthPx = Number.isFinite(bw) ? Math.max(0, Math.min(12, Math.round(bw))) : 2;
const fb = defaultCarryMapPanelThemePlay();
let qMin = Number(t.questionFontMinPx);
let qMax = Number(t.questionFontMaxPx);
if (!Number.isFinite(qMin)) qMin = fb.questionFontMinPx;
if (!Number.isFinite(qMax)) qMax = fb.questionFontMaxPx;
qMin = Math.round(Math.max(10, Math.min(40, qMin)));
qMax = Math.round(Math.max(14, Math.min(56, qMax)));
if (qMax < qMin) {
const s = qMin;
qMin = qMax;
qMax = s;
}
return {
panelBg: String(t.panelBg || '').trim().slice(0, 120),
panelBorder: String(t.panelBorder || '').trim().slice(0, 120),
borderWidthPx,
textColor: String(t.textColor || '').trim().slice(0, 120),
questionFontMinPx: qMin,
questionFontMaxPx: qMax,
};
}
/**
* นทบจาก carryMapPanelTheme ในไฟลแมป ฟอนตใสเฉพาะเม JSON key จร
* (นธมแมปมแคแลวไปทบขนาดฟอนตจาก Admin เปนคาเร 16/24)
*/
function parseCarryMapPanelThemeMapOverlay(raw) {
let t = raw;
if (typeof t === 'string') {
try {
t = JSON.parse(t);
} catch (e) {
t = null;
}
}
if (!t || typeof t !== 'object') return null;
const bw = Number(t.borderWidthPx);
const borderWidthPx = Number.isFinite(bw) ? Math.max(0, Math.min(12, Math.round(bw))) : 2;
const out = {
panelBg: String(t.panelBg || '').trim().slice(0, 120),
panelBorder: String(t.panelBorder || '').trim().slice(0, 120),
borderWidthPx,
textColor: String(t.textColor || '').trim().slice(0, 120),
};
const hasMin = Object.prototype.hasOwnProperty.call(t, 'questionFontMinPx');
const hasMax = Object.prototype.hasOwnProperty.call(t, 'questionFontMaxPx');
if (hasMin || hasMax) {
const fb = defaultCarryMapPanelThemePlay();
let qMin = hasMin ? Number(t.questionFontMinPx) : fb.questionFontMinPx;
let qMax = hasMax ? Number(t.questionFontMaxPx) : fb.questionFontMaxPx;
if (!Number.isFinite(qMin)) qMin = fb.questionFontMinPx;
if (!Number.isFinite(qMax)) qMax = fb.questionFontMaxPx;
qMin = Math.round(Math.max(10, Math.min(40, qMin)));
qMax = Math.round(Math.max(14, Math.min(56, qMax)));
if (qMax < qMin) {
const s = qMin;
qMin = qMax;
qMax = s;
}
out.questionFontMinPx = qMin;
out.questionFontMaxPx = qMax;
}
return out;
}
function setQuizCarryMapPanelThemeFromApi(s) {
quizCarryMapPanelTheme = null;
if (!s || typeof s !== 'object') return;
@@ -1103,14 +1224,16 @@
}
}
/** ธีมจากแผนที่ (ถ้ามี) ชนะค่าจาก API — ใส่ carryMapPanelTheme ใน JSON แมปได้โดยตรง */
/** default ← quiz-settings/API ← แมป (สีจากแมปทับได้; ฟอนต์จากแมปเฉพาะเมื่อแมประบุ key) */
function getEffectiveCarryMapPanelThemeForApply() {
const d = defaultCarryMapPanelThemePlay();
const api = quizCarryMapPanelTheme != null && typeof quizCarryMapPanelTheme === 'object' ? quizCarryMapPanelTheme : null;
let merged = api ? { ...d, ...api } : { ...d };
if (mapData && mapData.carryMapPanelTheme != null) {
const parsed = parseCarryMapPanelThemeObject(mapData.carryMapPanelTheme);
if (parsed) return parsed;
const mp = parseCarryMapPanelThemeMapOverlay(mapData.carryMapPanelTheme);
if (mp) merged = { ...merged, ...mp };
}
if (quizCarryMapPanelTheme != null) return quizCarryMapPanelTheme;
return defaultCarryMapPanelThemePlay();
return merged;
}
function applyQuizCarryMapPanelThemeIfNeeded(panel, textEl) {
@@ -1185,6 +1308,10 @@
panel.classList.remove('is-hidden');
panel.setAttribute('aria-hidden', 'false');
applyQuizCarryMapPanelThemeIfNeeded(panel, textEl);
const thFont = getEffectiveCarryMapPanelThemeForApply();
const startFontPx = quizMapQuestionFontPxLikeCarryPlaques(thFont, zoom);
const mnFont = Math.max(8, Math.round(Number(thFont.questionFontMinPx) || 10));
fitQuizMapQuestionFontToPanel(panel, textEl, startFontPx, mnFont);
}
function carryEmbedCountdownAnchorResolved() {
@@ -2397,11 +2524,7 @@
if (!choices || !choices.length) return;
const maxSlots = choices.length;
const ts = tileSize * zoom;
const ps = (() => {
const sc = Number(quizCarryPlaqueMapScale);
if (!Number.isFinite(sc)) return 1.25;
return Math.max(0.85, Math.min(2.5, sc));
})();
const ps = quizCarryPlaqueMapScaleClampedPlay();
ctx.save();
for (let i = 0; i < Math.min(choices.length, maxSlots); i++) {
if (quizCarryOptionHeldByAnyone(i)) continue;
@@ -7378,6 +7501,11 @@
return s;
}
/** ร่าง (cw×ch) ของผู้เล่นที่ (px,py) ครอบคลุมช่อง (tx,ty) หรือไม่ — ใช้กับ blockPlayer แทนการเช็คแค่มุมซ้ายบน */
function playEntityFootprintContainsTile(px, py, tx, ty) {
return quizTilesFootprintPlay(px, py).has(tx + ',' + ty);
}
/** Footprint ชนกำแพง (objects=1) เท่านั้น — hub / interactive / blockPlayer / quiz ใช้ quizTilesFootprintPlay = เต็ม characterCells */
function quizTilesWallCollisionFootprintPlay(px, py) {
const s = new Set();
@@ -7488,7 +7616,7 @@
const tx = +p[0], ty = +p[1];
if (!bp[ty] || bp[ty][tx] !== 1) continue;
for (const [, o] of others) {
if (Math.floor(o.x) === tx && Math.floor(o.y) === ty) return false;
if (playEntityFootprintContainsTile(o.x, o.y, tx, ty)) return false;
}
}
}
@@ -7528,8 +7656,9 @@
if (!bp[ty] || bp[ty][tx] !== 1) continue;
for (const [, peer] of others) {
if (o && peer === o) continue;
if (Math.floor(peer.x) === tx && Math.floor(peer.y) === ty) return false;
if (playEntityFootprintContainsTile(peer.x, peer.y, tx, ty)) return false;
}
if (o && playEntityFootprintContainsTile(me.x, me.y, tx, ty)) return false;
}
}
if (isQuiz()) {
@@ -8830,11 +8959,7 @@
const raw = String(signText || '').trim();
if (!raw && !imgUrlSan && !gridHeldDraw) return;
ctx.save();
const heldPs = (() => {
const sc = Number(quizCarryPlaqueMapScale);
if (!Number.isFinite(sc)) return 1.25;
return Math.max(0.85, Math.min(2.5, sc));
})();
const heldPs = quizCarryPlaqueMapScaleClampedPlay();
const bodyH = Math.max(18, feetSy - spriteTopY);
const midBodyY = spriteTopY + bodyH * 0.48;
const bodyCx = sxFeet;
+1 -1
View File
@@ -897,7 +897,7 @@
if (bp && bp[ty] && bp[ty][tx] === 1) {
for (const [id, p] of peers) {
if (id === socket.id) continue;
if (Math.floor(p.x) === tx && Math.floor(p.y) === ty) return false;
if (quizTilesFootprintLobby(p.x, p.y).has(tx + ',' + ty)) return false;
}
}
if (mapData.gameType === 'quiz' && quizModeActive && quizPlayerLocal && !quizPlayerLocal.eliminated) {
+41 -8
View File
@@ -123,10 +123,13 @@
box-sizing: border-box;
padding: clamp(6px, 1.5vw, 14px);
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
align-items: stretch;
justify-content: flex-start;
text-align: center;
overflow: auto;
overflow: hidden;
scrollbar-width: none;
-ms-overflow-style: none;
--qmap-bg: rgba(12, 14, 28, 0.88);
--qmap-border: rgba(255, 214, 102, 0.7);
--qmap-border-w: 2px;
@@ -137,17 +140,37 @@
box-shadow: var(--qmap-shadow);
}
#quiz-map-question-panel.is-hidden { display: none !important; }
#quiz-map-question-panel::-webkit-scrollbar {
display: none;
width: 0;
height: 0;
}
/* ขนาดตั้งต้น — โหมด quiz_carry ถูกทับด้วย play.js ตามสัดส่วนกล่อง + ธีม */
#quiz-map-question-text {
margin: 0;
font-size: clamp(0.78rem, 2.4vmin, 1.12rem);
font-size: 22px;
font-weight: 600;
line-height: 1.45;
--qmap-text: #f1f5f9;
--qmap-text-shadow: 0 1px 10px rgba(0, 0, 0, 0.55);
color: var(--qmap-text);
text-shadow: var(--qmap-text-shadow);
width: 100%;
box-sizing: border-box;
flex: 0 1 auto;
min-height: 0;
max-height: 100%;
overflow: auto;
overflow: hidden;
overflow-wrap: anywhere;
word-break: break-word;
white-space: pre-line;
scrollbar-width: none;
-ms-overflow-style: none;
}
#quiz-map-question-text::-webkit-scrollbar {
display: none;
width: 0;
height: 0;
}
#quiz-carry-embed-countdown {
position: fixed;
@@ -196,11 +219,21 @@
#quiz-carry-embed-countdown-q {
display: none;
margin: 0;
font: 600 clamp(0.88rem, 3.2vmin, 1.28rem) / 1.45 system-ui, "Kanit", sans-serif;
font: 600 clamp(14px, 3.2vmin, 20px) / 1.45 system-ui, "Kanit", sans-serif;
color: #f8fafc;
text-shadow: 0 2px 20px rgba(0, 0, 0, 0.75);
max-height: min(32vh, 220px);
overflow: auto;
overflow: hidden;
overflow-wrap: anywhere;
word-break: break-word;
white-space: pre-line;
scrollbar-width: none;
-ms-overflow-style: none;
}
#quiz-carry-embed-countdown-q::-webkit-scrollbar {
display: none;
width: 0;
height: 0;
}
#quiz-carry-embed-countdown-num {
font: 800 min(var(--carry-ecd-screen-vw, 28vw), var(--carry-ecd-screen-max, 132px)) / 1.05 system-ui, "Kanit", sans-serif;
@@ -980,7 +1013,7 @@
</div>
<script src="/Game/socket.io/socket.io.js"></script>
<script src="js/version.js?v=0.0166"></script>
<script src="js/play.js?v=0.145"></script>
<script src="js/play.js?v=0.155"></script>
<div class="version-tag">v —</div>
</body>
</html>
+28 -6
View File
@@ -676,10 +676,13 @@
box-sizing: border-box;
padding: clamp(6px, 1.5vw, 14px);
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
align-items: stretch;
justify-content: flex-start;
text-align: center;
overflow: auto;
overflow: hidden;
scrollbar-width: none;
-ms-overflow-style: none;
--qmap-bg: rgba(12, 14, 28, 0.88);
--qmap-border: rgba(255, 214, 102, 0.7);
--qmap-border-w: 2px;
@@ -692,6 +695,11 @@
#quiz-map-question-panel.is-hidden {
display: none !important;
}
#quiz-map-question-panel::-webkit-scrollbar {
display: none;
width: 0;
height: 0;
}
/* ตอนเล่น quiz ซ่อนปุ่ม READY กลางล่าง — ไม่ให้ทับ/แย่งโฟกัสกับแถบคำถาม */
body.room-lobby--quiz-active .room-lobby-ready-fixed {
visibility: hidden;
@@ -700,15 +708,29 @@
#quiz-map-question-text {
margin: 0;
font-family: 'Kanit', system-ui, sans-serif;
font-size: clamp(0.78rem, 2.4vmin, 1.12rem);
font-size: clamp(14px, 2.5vmin, 18px);
font-weight: 600;
line-height: 1.45;
--qmap-text: #f1f5f9;
--qmap-text-shadow: 0 1px 10px rgba(0, 0, 0, 0.55);
color: var(--qmap-text);
text-shadow: var(--qmap-text-shadow);
width: 100%;
box-sizing: border-box;
flex: 0 1 auto;
min-height: 0;
max-height: 100%;
overflow: auto;
overflow: hidden;
overflow-wrap: anywhere;
word-break: break-word;
white-space: pre-line;
scrollbar-width: none;
-ms-overflow-style: none;
}
#quiz-map-question-text::-webkit-scrollbar {
display: none;
width: 0;
height: 0;
}
#quiz-feedback-banner {
position: fixed;
@@ -1021,7 +1043,7 @@
</div>
<script src="/Game/socket.io/socket.io.js"></script>
<script src="js/version.js?v=0.0122"></script>
<script src="js/room-lobby.js?v=0.0180"></script>
<script src="js/room-lobby.js?v=0.0182"></script>
<div class="version-tag">v —</div>
</body>
</html>
+15
View File
@@ -123,6 +123,8 @@ function defaultCarryMapPanelTheme() {
panelBorder: 'rgba(255, 214, 102, 0.7)',
borderWidthPx: 2,
textColor: '#f1f5f9',
questionFontMinPx: 10,
questionFontMaxPx: 24,
};
}
@@ -141,6 +143,17 @@ function sanitizeCssColorToken(input, fallback) {
function sanitizeCarryMapPanelTheme(raw) {
const d = defaultCarryMapPanelTheme();
if (!raw || typeof raw !== 'object') return d;
let qMin = Number(raw.questionFontMinPx);
let qMax = Number(raw.questionFontMaxPx);
if (!Number.isFinite(qMin)) qMin = d.questionFontMinPx;
if (!Number.isFinite(qMax)) qMax = d.questionFontMaxPx;
qMin = Math.round(Math.max(10, Math.min(40, qMin)));
qMax = Math.round(Math.max(14, Math.min(56, qMax)));
if (qMax < qMin) {
const t = qMin;
qMin = qMax;
qMax = t;
}
return {
panelBg: sanitizeCssColorToken(raw.panelBg, d.panelBg),
panelBorder: sanitizeCssColorToken(raw.panelBorder, d.panelBorder),
@@ -150,6 +163,8 @@ function sanitizeCarryMapPanelTheme(raw) {
return Math.max(0, Math.min(12, Math.round(w)));
})(),
textColor: sanitizeCssColorToken(raw.textColor, d.textColor),
questionFontMinPx: qMin,
questionFontMaxPx: qMax,
};
}