Fix Player Panel, Player Info Overlay and Emoji Table responsive and scrollable on small viewports (#2410)

## Description: Fixes a usability issue where the Player Info Panel and
Emoji Table overflowed the viewport on smaller screens, hiding key
controls (like Stop Trade) behind the Build Bar/Menu. Makes these panels
responsive and scrollable with minimal, low-risk CSS changes.
According to : https://github.com/openfrontio/OpenFrontIO/issues/2367

<img width="1120" height="774" alt="Ekran Resmi 2025-11-07 23 06 01"
src="https://github.com/user-attachments/assets/6fe23c23-ab5b-4254-8872-9880c322e164"
/>

Changes:
- Increased overlay z-index from 1001 to 10001 to ensure it renders
above Build Menu.
- Replaced static layout with scrollable inner container:
- Applied `max-height: calc(100vh - 120px -
env(safe-area-inset-bottom))`
- Enabled scrolling with `overflow: auto` and
`-webkit-overflow-scrolling: touch`
- Added sticky header with close (✕) button for persistent visibility
during scroll.
- Removed unused `init()` method for cleanup.

Discord: bilgehandk
This commit is contained in:
Bilgehan Demirkaya
2025-11-07 16:00:14 -08:00
committed by GitHub
parent cde2967ef6
commit b44dca16e9
+58 -53
View File
@@ -77,7 +77,6 @@ export class PlayerPanel extends LitElement implements Layer {
} }
}); });
} }
init() { init() {
this.eventBus.on(MouseUpEvent, () => this.hide()); this.eventBus.on(MouseUpEvent, () => this.hide());
@@ -801,7 +800,7 @@ export class PlayerPanel extends LitElement implements Layer {
</style> </style>
<div <div
class="fixed inset-0 z-[1001] flex items-center justify-center overflow-auto class="fixed inset-0 z-[10001] flex items-center justify-center overflow-auto
bg-black/15 backdrop-brightness-110 pointer-events-auto" bg-black/15 backdrop-brightness-110 pointer-events-auto"
@contextmenu=${(e: MouseEvent) => e.preventDefault()} @contextmenu=${(e: MouseEvent) => e.preventDefault()}
@wheel=${(e: MouseEvent) => e.stopPropagation()} @wheel=${(e: MouseEvent) => e.stopPropagation()}
@@ -816,70 +815,76 @@ export class PlayerPanel extends LitElement implements Layer {
class="absolute inset-2 -z-10 rounded-2xl bg-black/25 backdrop-blur-[2px]" class="absolute inset-2 -z-10 rounded-2xl bg-black/25 backdrop-blur-[2px]"
></div> ></div>
<div <div
class=${`relative w-full bg-zinc-900/95 p-6 rounded-2xl text-zinc-100 overflow-visible shadow-2xl shadow-black/50 class=${`relative w-full bg-zinc-900/95 rounded-2xl text-zinc-100 shadow-2xl shadow-black/50
${other.isTraitor() ? "traitor-ring" : "ring-1 ring-white/5"}`} ${other.isTraitor() ? "traitor-ring" : "ring-1 ring-white/5"}`}
> >
<!-- Close button --> <div style="overflow: visible;">
<button <div
@click=${this.handleClose} style="max-height: calc(100vh - 120px - env(safe-area-inset-bottom)); overflow:auto; -webkit-overflow-scrolling: touch; resize: vertical;"
class="absolute -top-3 -right-3 flex h-7 w-7 items-center justify-center >
rounded-full bg-zinc-700 text-white shadow hover:bg-red-500 transition-colors" <div class="sticky top-0 z-20 flex justify-end p-2">
aria-label=${translateText("common.close") || "Close"} <button
title=${translateText("common.close") || "Close"} @click=${this.handleClose}
> class="flex h-7 w-7 items-center justify-center rounded-full bg-zinc-700 text-white shadow hover:bg-red-500 transition-colors"
aria-label=${translateText("common.close") || "Close"}
</button> title=${translateText("common.close") || "Close"}
>
</button>
</div>
<div <div
class="flex flex-col gap-2 font-sans antialiased text-[14.5px] leading-relaxed" class="p-6 flex flex-col gap-2 font-sans antialiased text-[14.5px] leading-relaxed"
> >
<!-- Identity (flag, name, type, traitor, relation) --> <!-- Identity (flag, name, type, traitor, relation) -->
<div class="mb-1">${this.renderIdentityRow(other, my)}</div> <div class="mb-1">${this.renderIdentityRow(other, my)}</div>
${this.sendTarget ${this.sendTarget
? html` ? html`
<send-resource-modal <send-resource-modal
.open=${this.sendMode !== "none"} .open=${this.sendMode !== "none"}
.mode=${this.sendMode} .mode=${this.sendMode}
.total=${this.sendMode === "troops" .total=${this.sendMode === "troops"
? myTroopsNum ? myTroopsNum
: myGoldNum} : myGoldNum}
.uiState=${this.uiState} .uiState=${this.uiState}
.myPlayer=${my} .myPlayer=${my}
.target=${this.sendTarget} .target=${this.sendTarget}
.gameView=${this.g} .gameView=${this.g}
.eventBus=${this.eventBus} .eventBus=${this.eventBus}
.format=${this.sendMode === "troops" .format=${this.sendMode === "troops"
? renderTroops ? renderTroops
: renderNumber} : renderNumber}
@confirm=${this.confirmSend} @confirm=${this.confirmSend}
@close=${this.closeSend} @close=${this.closeSend}
></send-resource-modal> ></send-resource-modal>
` `
: ""} : ""}
<ui-divider></ui-divider> <ui-divider></ui-divider>
<!-- Resources --> <!-- Resources -->
${this.renderResources(other)} ${this.renderResources(other)}
<ui-divider></ui-divider> <ui-divider></ui-divider>
<!-- Stats: betrayals / trading --> <!-- Stats: betrayals / trading -->
${this.renderStats(other, my)} ${this.renderStats(other, my)}
<ui-divider></ui-divider> <ui-divider></ui-divider>
<!-- Alliances list --> <!-- Alliances list -->
${this.renderAlliances(other)} ${this.renderAlliances(other)}
<!-- Alliance time remaining --> <!-- Alliance time remaining -->
${this.renderAllianceExpiry()} ${this.renderAllianceExpiry()}
<ui-divider class="mt-1"></ui-divider> <ui-divider class="mt-1"></ui-divider>
<!-- Actions --> <!-- Actions -->
${this.renderActions(my, other)} ${this.renderActions(my, other)}
</div>
</div>
</div> </div>
</div> </div>
</div> </div>