Commit 6143b157 authored by Mahmoud Aglan's avatar Mahmoud Aglan

fix: mobile ergonomics — push boards down, move emotes off board, enlarge touch targets

Board content now aligns to bottom (thumb zone) instead of center.
Emote button repositioned to fixed bottom-right, off the chess squares.
Control buttons enlarged to 48px+ with safe-area padding.
Co-Authored-By: 's avatarClaude Opus 4.6 <noreply@anthropic.com>
parent 51e59856
...@@ -35,10 +35,10 @@ export function create(container, onSend) { ...@@ -35,10 +35,10 @@ export function create(container, onSend) {
const style = document.createElement('style'); const style = document.createElement('style');
style.textContent = ` style.textContent = `
.emote-bar { position:absolute;bottom:52px;right:8px;z-index:30;display:flex;flex-direction:column;align-items:flex-end;gap:6px; } .emote-bar { position:fixed;bottom:140px;right:8px;z-index:30;display:flex;flex-direction:column;align-items:flex-end;gap:6px; }
.emote-toggle { width:40px;height:40px;border-radius:50%;background:#1e1e3a;border:1px solid rgba(255,255,255,0.1);color:#f8fafc;font-size:18px;cursor:pointer;display:flex;align-items:center;justify-content:center;transition:transform 0.15s,background 0.15s;box-shadow:0 2px 8px rgba(0,0,0,0.3); } .emote-toggle { width:38px;height:38px;border-radius:50%;background:#1e1e3a;border:1px solid rgba(255,255,255,0.1);color:#f8fafc;font-size:16px;cursor:pointer;display:flex;align-items:center;justify-content:center;transition:transform 0.15s,background 0.15s;box-shadow:0 2px 8px rgba(0,0,0,0.3); }
.emote-toggle:active { transform:scale(0.9);background:#2a2a5a; } .emote-toggle:active { transform:scale(0.9);background:#2a2a5a; }
.emote-panel { display:flex;gap:6px;padding:8px;background:#1e1e3a;border-radius:12px;border:1px solid rgba(255,255,255,0.08);box-shadow:0 4px 20px rgba(0,0,0,0.5);animation:slideUpBounce 0.3s cubic-bezier(0.16,1,0.3,1); } .emote-panel { display:flex;flex-wrap:wrap;gap:6px;padding:8px;background:#1e1e3a;border-radius:12px;border:1px solid rgba(255,255,255,0.08);box-shadow:0 4px 20px rgba(0,0,0,0.5);animation:slideUpBounce 0.3s cubic-bezier(0.16,1,0.3,1);max-width:200px; }
.emote-panel.hidden { display:none; } .emote-panel.hidden { display:none; }
.emote-btn { width:40px;height:40px;border-radius:8px;background:rgba(255,255,255,0.05);border:none;cursor:pointer;display:flex;align-items:center;justify-content:center;transition:transform 0.1s,background 0.15s; } .emote-btn { width:40px;height:40px;border-radius:8px;background:rgba(255,255,255,0.05);border:none;cursor:pointer;display:flex;align-items:center;justify-content:center;transition:transform 0.1s,background 0.15s; }
.emote-btn:hover { background:rgba(255,255,255,0.1); } .emote-btn:hover { background:rgba(255,255,255,0.1); }
......
...@@ -98,25 +98,25 @@ export function mountGame(el, params) { ...@@ -98,25 +98,25 @@ export function mountGame(el, params) {
el.innerHTML = ` el.innerHTML = `
<div class="chess-layout" style="display:flex;flex-direction:column;height:100%;background:#1a1a2e;"> <div class="chess-layout" style="display:flex;flex-direction:column;height:100%;background:#1a1a2e;">
<!-- Opponent Bar --> <!-- Opponent Bar (compact — keep minimal at top) -->
<div class="chess-bar" style="display:flex;align-items:center;justify-content:space-between;padding:6px 12px;background:#0f0f1e;"> <div class="chess-bar" style="display:flex;align-items:center;justify-content:space-between;padding:4px 12px;background:#0f0f1e;">
<div style="display:flex;align-items:center;gap:8px;"> <div style="display:flex;align-items:center;gap:8px;">
<div id="opponent-avatar" style="width:34px;height:34px;border-radius:50%;background:#2a2a4a;display:flex;align-items:center;justify-content:center;overflow:hidden;border:2px solid ${mode === 'bot' ? '#64748b' : '#3B82F6'};"> <div id="opponent-avatar" style="width:30px;height:30px;border-radius:50%;background:#2a2a4a;display:flex;align-items:center;justify-content:center;overflow:hidden;border:2px solid ${mode === 'bot' ? '#64748b' : '#3B82F6'};">
${mode === 'bot' ? `<img src="https://stockfishapi.caprover.al-arcade.com/portraits/${botId || 'amina'}.png" style="width:100%;height:100%;object-fit:cover;" onerror="this.style.display='none';this.parentNode.textContent='🤖'">` : '<span style="font-size:16px;">👤</span>'} ${mode === 'bot' ? `<img src="https://stockfishapi.caprover.al-arcade.com/portraits/${botId || 'amina'}.png" style="width:100%;height:100%;object-fit:cover;" onerror="this.style.display='none';this.parentNode.textContent='🤖'">` : '<span style="font-size:14px;">👤</span>'}
</div> </div>
<div> <div>
<div style="font-size:13px;font-weight:600;color:#f8fafc;" id="opponent-name">${mode === 'bot' ? (botId || 'Bot') : 'جاري التحميل...'}</div> <div style="font-size:12px;font-weight:600;color:#f8fafc;" id="opponent-name">${mode === 'bot' ? (botId || 'Bot') : 'جاري التحميل...'}</div>
<div style="display:flex;gap:6px;align-items:center;"> <div style="display:flex;gap:6px;align-items:center;">
<div id="opponent-level" style="font-size:10px;color:#64748b;">${mode === 'bot' ? 'بوت' : ''}</div> <div id="opponent-level" style="font-size:10px;color:#64748b;">${mode === 'bot' ? 'بوت' : ''}</div>
<div id="opponent-captured" style="font-size:11px;color:#94a3b8;letter-spacing:1px;"></div> <div id="opponent-captured" style="font-size:11px;color:#94a3b8;letter-spacing:1px;"></div>
</div> </div>
</div> </div>
</div> </div>
<div id="clock-opponent" class="chess-clock" style="font-size:18px;font-weight:700;font-family:Inter,monospace;background:#1e1e3a;padding:4px 12px;border-radius:6px;color:#f8fafc;min-width:60px;text-align:center;">${clock.format(tc.time)}</div> <div id="clock-opponent" class="chess-clock" style="font-size:16px;font-weight:700;font-family:Inter,monospace;background:#1e1e3a;padding:3px 10px;border-radius:6px;color:#f8fafc;min-width:56px;text-align:center;">${clock.format(tc.time)}</div>
</div> </div>
<!-- Board --> <!-- Board -->
<div id="board-container" style="flex:1;display:flex;align-items:center;justify-content:center;padding:2px 4px;position:relative;min-height:0;max-height:calc(100vw + 20px);"> <div id="board-container" style="flex:1;display:flex;align-items:flex-end;justify-content:center;padding:2px 4px;position:relative;min-height:0;max-height:calc(100vw + 20px);">
<div id="bot-thinking" style="display:none;position:absolute;top:8px;left:50%;transform:translateX(-50%);background:rgba(0,0,0,0.8);color:#E4AC38;padding:4px 12px;border-radius:12px;font-size:12px;font-weight:600;z-index:10;"> <div id="bot-thinking" style="display:none;position:absolute;top:8px;left:50%;transform:translateX(-50%);background:rgba(0,0,0,0.8);color:#E4AC38;padding:4px 12px;border-radius:12px;font-size:12px;font-weight:600;z-index:10;">
${t('game.thinking')} <span class="pulse">${emoji('thinking_dots', '●●●', 12)}</span> ${t('game.thinking')} <span class="pulse">${emoji('thinking_dots', '●●●', 12)}</span>
</div> </div>
...@@ -150,15 +150,15 @@ export function mountGame(el, params) { ...@@ -150,15 +150,15 @@ export function mountGame(el, params) {
<span style="color:#475569;">1.</span> <span style="color:#475569;">1.</span>
</div> </div>
<!-- Controls --> <!-- Controls — sticky bottom bar for thumb reach -->
<div style="display:flex;gap:6px;padding:8px 12px;background:#0f0f1e;border-top:1px solid rgba(255,255,255,0.05);"> <div style="display:flex;gap:8px;padding:10px 12px;background:#0f0f1e;border-top:1px solid rgba(255,255,255,0.05);padding-bottom:max(10px, var(--safe-bottom, 0px));">
<button class="ctrl-btn" id="btn-resign">${emoji('flag', '⚐', 12)} ${t('game.resign')}</button> <button class="ctrl-btn" id="btn-resign">${emoji('flag', '⚐', 12)} ${t('game.resign')}</button>
<button class="ctrl-btn" id="btn-draw">½ ${t('game.draw')}</button> <button class="ctrl-btn" id="btn-draw">½ ${t('game.draw')}</button>
<button class="ctrl-btn" id="btn-flip">⟲ ${t('game.flip')}</button> <button class="ctrl-btn" id="btn-flip">⟲ ${t('game.flip')}</button>
</div> </div>
</div> </div>
<style> <style>
.ctrl-btn { flex:1;background:#1e1e3a;border:1px solid rgba(255,255,255,0.1);color:#e2e8f0;font-size:13px;font-weight:600;padding:10px 8px;border-radius:8px;cursor:pointer;font-family:inherit;transition:background 0.15s;min-height:44px; } .ctrl-btn { flex:1;background:#1e1e3a;border:1px solid rgba(255,255,255,0.1);color:#e2e8f0;font-size:13px;font-weight:600;padding:12px 8px;border-radius:10px;cursor:pointer;font-family:inherit;transition:background 0.15s,transform 0.1s;min-height:48px; }
.ctrl-btn:active { background:#2a2a5a;transform:scale(0.95); } .ctrl-btn:active { background:#2a2a5a;transform:scale(0.95); }
.chess-clock.low-time { color:#EF4444!important;animation:clockPulse 1s infinite; } .chess-clock.low-time { color:#EF4444!important;animation:clockPulse 1s infinite; }
@keyframes clockPulse { 0%,100%{opacity:1}50%{opacity:0.5} } @keyframes clockPulse { 0%,100%{opacity:1}50%{opacity:0.5} }
...@@ -301,7 +301,7 @@ export function mountGame(el, params) { ...@@ -301,7 +301,7 @@ export function mountGame(el, params) {
}); });
} }
const emoteContainer = el.querySelector('#board-container'); const emoteContainer = el.querySelector('.chess-layout');
emoteSystem.create(emoteContainer, (emote) => { emoteSystem.create(emoteContainer, (emote) => {
audio.play('notification'); audio.play('notification');
const myBar = el.querySelectorAll('.chess-bar')[1]; const myBar = el.querySelectorAll('.chess-bar')[1];
......
...@@ -81,16 +81,16 @@ export function mountGame(el, params) { ...@@ -81,16 +81,16 @@ export function mountGame(el, params) {
${renderPanel(panels[1])} ${renderPanel(panels[1])}
${renderPanel(panels[2])} ${renderPanel(panels[2])}
</div> </div>
<div id="ludo-wrap" style="flex:1;display:flex;align-items:center;justify-content:center;padding:4px;min-height:0;"></div> <div id="ludo-wrap" style="flex:1;display:flex;align-items:flex-end;justify-content:center;padding:4px 4px 8px;min-height:0;">
<div style="display:flex;justify-content:space-between;padding:6px 12px;background:#0f0f1e;direction:ltr;"> <div style="display:flex;justify-content:space-between;padding:6px 12px;background:#0f0f1e;direction:ltr;">
${renderPanel(panels[0])} ${renderPanel(panels[0])}
${renderPanel(panels[3])} ${renderPanel(panels[3])}
</div> </div>
<div id="dice-area" style="display:flex;align-items:center;gap:12px;padding:10px 16px;background:#0f0f1e;border-top:1px solid rgba(255,255,255,0.06);justify-content:center;"> <div id="dice-area" style="display:flex;align-items:center;gap:12px;padding:12px 16px;background:#0f0f1e;border-top:1px solid rgba(255,255,255,0.06);justify-content:center;padding-bottom:max(12px, var(--safe-bottom, 0px));">
<button class="btn btn-secondary" id="exit-btn" style="min-height:44px;min-width:44px;padding:0;font-size:14px;color:#EF4444;border-radius:50%;">✕</button> <button class="btn btn-secondary" id="exit-btn" style="min-height:48px;min-width:48px;padding:0;font-size:14px;color:#EF4444;border-radius:50%;">✕</button>
<div id="dice-box" style="width:50px;height:50px;background:#f8fafc;border-radius:10px;display:grid;grid-template:repeat(3,1fr)/repeat(3,1fr);padding:6px;box-shadow:0 3px 10px rgba(0,0,0,0.4),inset 0 1px 0 rgba(255,255,255,0.8);transition:transform 0.15s cubic-bezier(0.34,1.56,0.64,1);"> <div id="dice-box" style="width:52px;height:52px;background:#f8fafc;border-radius:10px;display:grid;grid-template:repeat(3,1fr)/repeat(3,1fr);padding:6px;box-shadow:0 3px 10px rgba(0,0,0,0.4),inset 0 1px 0 rgba(255,255,255,0.8);transition:transform 0.15s cubic-bezier(0.34,1.56,0.64,1);">
</div> </div>
<button class="btn btn-primary" id="roll-btn" style="font-size:15px;padding:12px 32px;min-height:48px;" disabled>ارمِ النرد</button> <button class="btn btn-primary" id="roll-btn" style="font-size:15px;padding:14px 32px;min-height:52px;border-radius:12px;" disabled>ارمِ النرد</button>
</div> </div>
</div> </div>
<style> <style>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment