mirror of
https://github.com/openfrontio/OpenFrontIO.git
synced 2026-06-21 13:50:43 +00:00
79330af2b2
Relates #2260 ## Description: Move outgoing & incoming boat & land attacks to a new "AttacksDisplay" layer that sits on top of the ControlPanel. The idea is to break up EventsDisplay so it's easier to find information. It's also more mobile friendly. It still needs more styling, but this just a first pass. <img width="356" height="199" alt="Screenshot 2026-02-09 at 4 44 38 PM" src="https://github.com/user-attachments/assets/c8e32972-be3b-469b-b7c7-982197c1d572" /> <img width="750" height="436" alt="Screenshot 2026-02-09 at 4 44 18 PM" src="https://github.com/user-attachments/assets/5359459b-015e-432f-81bf-1561cc64babe" /> <img width="537" height="537" alt="Screenshot 2026-02-09 at 4 43 33 PM" src="https://github.com/user-attachments/assets/edc7a07e-3589-4107-b017-38e00768c5cf" /> <img width="487" height="283" alt="Screenshot 2026-02-09 at 4 44 05 PM" src="https://github.com/user-attachments/assets/1a3886c7-57e3-4247-92c5-3a13876c2a71" /> ## Please complete the following: - [x] I have added screenshots for all UI updates - [x] I process any text displayed to the user through translateText() and I've added it to the en.json file - [x] I have added relevant tests to the test directory - [x] I confirm I have thoroughly tested these changes and take full responsibility for any bugs introduced ## Please put your Discord username so you can be contacted if a bug or regression is found: evan
379 lines
12 KiB
HTML
379 lines
12 KiB
HTML
<!doctype html>
|
|
<html lang="en" class="h-full preload" translate="no">
|
|
<head>
|
|
<meta charset="UTF-8" />
|
|
<meta
|
|
name="viewport"
|
|
content="width=device-width, initial-scale=1.0, viewport-fit=cover"
|
|
/>
|
|
<title data-i18n="main.title">OpenFront (ALPHA)</title>
|
|
<link rel="manifest" href="/manifest.json" />
|
|
<link rel="icon" type="image/x-icon" href="/images/Favicon.svg" />
|
|
|
|
<!-- Preload styles -->
|
|
<style>
|
|
.preload {
|
|
visibility: hidden;
|
|
opacity: 0;
|
|
transition: opacity 0.5s ease-out;
|
|
}
|
|
|
|
/* iOS safe area support */
|
|
body {
|
|
padding-top: env(safe-area-inset-top);
|
|
padding-right: env(safe-area-inset-right);
|
|
padding-bottom: env(safe-area-inset-bottom);
|
|
padding-left: env(safe-area-inset-left);
|
|
}
|
|
|
|
/* Ensure full viewport height on iOS */
|
|
html,
|
|
body {
|
|
height: 100%;
|
|
height: -webkit-fill-available;
|
|
min-height: 100%;
|
|
min-height: -webkit-fill-available;
|
|
}
|
|
</style>
|
|
|
|
<!-- SEO -->
|
|
<link rel="canonical" href="https://openfront.io/" />
|
|
<meta
|
|
name="description"
|
|
content="Conquer the world in this multiplayer battle royale! Expand your nation, eliminate opponents, and dominate the map in this fast-paced IO game."
|
|
/>
|
|
|
|
<!-- Open Graph -->
|
|
<meta property="og:url" content="https://openfront.io/" />
|
|
<meta property="og:title" content="OpenFront - Battle Royale" />
|
|
<meta
|
|
property="og:description"
|
|
content="Conquer the world in this multiplayer battle royale! Expand your nation, eliminate opponents, and dominate the map in this fast-paced IO game."
|
|
/>
|
|
<meta
|
|
property="og:image"
|
|
content="https://openfront.io/images/GameplayScreenshot.png"
|
|
/>
|
|
<meta property="og:type" content="game" />
|
|
|
|
<!-- Injected from Server env -->
|
|
<script>
|
|
window.GIT_COMMIT = <%- gitCommit %>;
|
|
window.INSTANCE_ID = <%- instanceId %>;
|
|
</script>
|
|
|
|
<!-- CrazyGames SDK -->
|
|
<script
|
|
src="https://sdk.crazygames.com/crazygames-sdk-v3.js"
|
|
async
|
|
></script>
|
|
|
|
<!-- Cloudflare Turnstile -->
|
|
<script
|
|
src="https://challenges.cloudflare.com/turnstile/v0/api.js"
|
|
async
|
|
defer
|
|
></script>
|
|
|
|
<script data-cfasync="false">
|
|
window.ramp = window.ramp || {};
|
|
window.ramp.que = window.ramp.que || [];
|
|
window.ramp.passiveMode = true;
|
|
</script>
|
|
|
|
<script>
|
|
window.googletag = window.googletag || { cmd: [] };
|
|
googletag.cmd.push(function () {
|
|
googletag.pubads().set("page_url", "http://openfront.io ");
|
|
});
|
|
</script>
|
|
|
|
<!-- Analytics -->
|
|
<script
|
|
async
|
|
src="https://www.googletagmanager.com/gtag/js?id=AW-16702609763"
|
|
></script>
|
|
<script>
|
|
window.dataLayer = window.dataLayer || [];
|
|
|
|
function gtag() {
|
|
dataLayer.push(arguments);
|
|
}
|
|
|
|
gtag("js", new Date());
|
|
gtag("config", "AW-16702609763");
|
|
</script>
|
|
<!-- Google tag (gtag.js) -->
|
|
<script
|
|
async
|
|
src="https://www.googletagmanager.com/gtag/js?id=G-WQGQQ8RDN4"
|
|
></script>
|
|
<script>
|
|
window.dataLayer = window.dataLayer || [];
|
|
function gtag() {
|
|
dataLayer.push(arguments);
|
|
}
|
|
gtag("js", new Date());
|
|
|
|
gtag("config", "G-WQGQQ8RDN4");
|
|
</script>
|
|
</head>
|
|
|
|
<body
|
|
class="h-full select-none font-sans min-h-screen bg-cover bg-center bg-fixed transition-opacity duration-300 ease-in-out flex flex-row overflow-hidden"
|
|
>
|
|
<div
|
|
class="fixed inset-0 w-full h-full -z-50 bg-cover bg-center bg-fixed pointer-events-none brightness-[0.5]"
|
|
style="
|
|
background-image: url("/images/EuropeBackgroundBlurred.webp");
|
|
"
|
|
></div>
|
|
|
|
<!-- LEFT SIDEBAR MENU -->
|
|
|
|
<div
|
|
id="mobile-menu-backdrop"
|
|
class="lg:hidden! in-[.in-game]:hidden hidden pointer-events-none [&.open]:block [&.open]:pointer-events-auto [&.open]:fixed [&.open]:inset-0 [&.open]:bg-black/60 [&.open]:z-[40000] transition-opacity"
|
|
role="presentation"
|
|
aria-hidden="true"
|
|
></div>
|
|
|
|
<mobile-nav-bar
|
|
id="sidebar-menu"
|
|
class="peer in-[.in-game]:hidden z-40001 fixed left-0 top-0 h-full flex flex-col justify-start overflow-visible bg-black/60 backdrop-blur-md transition-transform duration-500 ease-out transform -translate-x-full w-[80%] [&.open]:translate-x-0 lg:hidden"
|
|
role="dialog"
|
|
data-i18n-aria-label="main.menu"
|
|
aria-hidden="true"
|
|
></mobile-nav-bar>
|
|
|
|
<!-- MAIN CONTENT AREA -->
|
|
<div
|
|
class="in-[.in-game]:hidden flex-1 relative overflow-hidden h-full transition-[margin] duration-500 ease-out will-change-[margin-left] flex flex-col"
|
|
>
|
|
<!-- Desktop Top Bar -->
|
|
<desktop-nav-bar></desktop-nav-bar>
|
|
|
|
<div
|
|
id="turnstile-container"
|
|
class="fixed top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 z-99999"
|
|
></div>
|
|
|
|
<gutter-ads></gutter-ads>
|
|
|
|
<!-- Main container with responsive padding -->
|
|
<main-layout class="contents">
|
|
<play-page class="contents"></play-page>
|
|
|
|
<news-modal
|
|
id="page-news"
|
|
inline
|
|
class="hidden w-full h-full page-content"
|
|
></news-modal>
|
|
<single-player-modal
|
|
id="page-single-player"
|
|
inline
|
|
class="hidden w-full h-full page-content"
|
|
></single-player-modal>
|
|
<host-lobby-modal
|
|
id="page-host-lobby"
|
|
inline
|
|
class="hidden w-full h-full page-content"
|
|
></host-lobby-modal>
|
|
<join-lobby-modal
|
|
id="page-join-lobby"
|
|
inline
|
|
class="hidden w-full h-full page-content"
|
|
></join-lobby-modal>
|
|
<territory-patterns-modal
|
|
id="page-item-store"
|
|
inline
|
|
class="hidden w-full h-full page-content"
|
|
></territory-patterns-modal>
|
|
<user-setting
|
|
id="page-settings"
|
|
inline
|
|
class="hidden w-full h-full page-content"
|
|
></user-setting>
|
|
<leaderboard-modal
|
|
id="page-leaderboard"
|
|
inline
|
|
class="hidden w-full h-full page-content"
|
|
></leaderboard-modal>
|
|
<troubleshooting-modal
|
|
id="page-troubleshooting"
|
|
inline
|
|
class="hidden w-full h-full page-content"
|
|
></troubleshooting-modal>
|
|
|
|
<account-modal
|
|
id="page-account"
|
|
inline
|
|
class="hidden w-full h-full page-content"
|
|
></account-modal>
|
|
<help-modal
|
|
id="page-help"
|
|
inline
|
|
class="hidden w-full h-full page-content"
|
|
></help-modal>
|
|
<language-modal
|
|
id="page-language"
|
|
inline
|
|
class="hidden w-full h-full page-content"
|
|
></language-modal>
|
|
<flag-input-modal
|
|
id="flag-input-modal"
|
|
inline
|
|
class="hidden w-full h-full page-content"
|
|
></flag-input-modal>
|
|
</main-layout>
|
|
|
|
<!-- Desktop Footer -->
|
|
<page-footer></page-footer>
|
|
|
|
<!-- Global Modals -->
|
|
<territory-patterns-modal
|
|
id="territory-patterns-modal"
|
|
></territory-patterns-modal>
|
|
</div>
|
|
|
|
<!-- Game components -->
|
|
<div id="app"></div>
|
|
|
|
<div
|
|
class="fixed left-0 bottom-0 min-[1200px]:left-4 min-[1200px]:bottom-4 w-full flex flex-col sm:flex-row sm:items-end z-50 pointer-events-none"
|
|
>
|
|
<div
|
|
class="order-2 sm:order-none w-full sm:w-1/2 min-[1200px]:w-auto lg:max-w-[400px]"
|
|
>
|
|
<attacks-display></attacks-display>
|
|
<control-panel></control-panel>
|
|
</div>
|
|
<div
|
|
class="order-1 sm:order-none w-full sm:w-1/2 min-[1200px]:w-auto min-[1200px]:fixed min-[1200px]:right-0 min-[1200px]:bottom-0 flex flex-col sm:items-end pointer-events-none"
|
|
>
|
|
<chat-display></chat-display>
|
|
<events-display></events-display>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Game modals and overlays -->
|
|
<emoji-table></emoji-table>
|
|
<build-menu></build-menu>
|
|
<win-modal></win-modal>
|
|
<game-starting-modal></game-starting-modal>
|
|
<unit-display></unit-display>
|
|
<div class="flex flex-col items-end fixed top-4 right-4 z-1000 gap-2">
|
|
<game-right-sidebar></game-right-sidebar>
|
|
<replay-panel></replay-panel>
|
|
</div>
|
|
<settings-modal></settings-modal>
|
|
<player-panel></player-panel>
|
|
<spawn-timer></spawn-timer>
|
|
<immunity-timer></immunity-timer>
|
|
<in-game-header-ad></in-game-header-ad>
|
|
<spawn-video-ad></spawn-video-ad>
|
|
<game-info-modal></game-info-modal>
|
|
<alert-frame></alert-frame>
|
|
<chat-modal></chat-modal>
|
|
<multi-tab-modal></multi-tab-modal>
|
|
<game-left-sidebar></game-left-sidebar>
|
|
<performance-overlay></performance-overlay>
|
|
<player-info-overlay></player-info-overlay>
|
|
<leader-board></leader-board>
|
|
<team-stats></team-stats>
|
|
<heads-up-message></heads-up-message>
|
|
|
|
<!-- Scripts -->
|
|
<script>
|
|
// Remove preload class after everything is loaded
|
|
window.addEventListener("load", function () {
|
|
requestAnimationFrame(() => {
|
|
document.documentElement.classList.remove("preload");
|
|
});
|
|
});
|
|
|
|
// Fallback: remove preload class after timeout in case DOMContentLoaded never fires
|
|
setTimeout(function () {
|
|
document.documentElement.classList.remove("preload");
|
|
}, 3000);
|
|
</script>
|
|
|
|
<script>
|
|
// Fallback sidebar toggle so hamburger works even if module bundle fails to load
|
|
window.__toggleSidebar = function (e) {
|
|
try {
|
|
const sidebar = document.getElementById("sidebar-menu");
|
|
const backdrop = document.getElementById("mobile-menu-backdrop");
|
|
if (!sidebar || !backdrop) return;
|
|
|
|
const isOpen = sidebar.classList.contains("open");
|
|
|
|
if (isOpen) {
|
|
sidebar.classList.remove("open");
|
|
backdrop.classList.remove("open");
|
|
document.documentElement.classList.remove("overflow-hidden");
|
|
sidebar.setAttribute("aria-hidden", "true");
|
|
sidebar.removeAttribute("aria-modal");
|
|
backdrop.setAttribute("aria-hidden", "true");
|
|
} else {
|
|
sidebar.classList.add("open");
|
|
backdrop.classList.add("open");
|
|
document.documentElement.classList.add("overflow-hidden");
|
|
sidebar.setAttribute("aria-hidden", "false");
|
|
sidebar.setAttribute("aria-modal", "true");
|
|
backdrop.setAttribute("aria-hidden", "false");
|
|
}
|
|
|
|
const hb = document.getElementById("hamburger-btn");
|
|
if (hb) hb.setAttribute("aria-expanded", (!isOpen).toString());
|
|
} catch (err) {
|
|
console.error("Toggle failed", err);
|
|
}
|
|
};
|
|
|
|
// Wire up the hamburger button inline
|
|
const hamburger = document.getElementById("hamburger-btn");
|
|
if (hamburger) {
|
|
hamburger.onclick = window.__toggleSidebar;
|
|
hamburger.setAttribute("aria-expanded", "false");
|
|
}
|
|
|
|
// Wire up backdrop click to close menu
|
|
const backdrop = document.getElementById("mobile-menu-backdrop");
|
|
if (backdrop) {
|
|
backdrop.onclick = function (e) {
|
|
const sidebar = document.getElementById("sidebar-menu");
|
|
if (sidebar && sidebar.classList.contains("open")) {
|
|
window.__toggleSidebar(e);
|
|
}
|
|
};
|
|
}
|
|
|
|
// Wire up Escape key to close menu
|
|
document.addEventListener("keydown", function (e) {
|
|
if (e.key === "Escape" || e.key === "Esc") {
|
|
const sidebar = document.getElementById("sidebar-menu");
|
|
if (sidebar && sidebar.classList.contains("open")) {
|
|
window.__toggleSidebar(e);
|
|
}
|
|
}
|
|
});
|
|
</script>
|
|
|
|
<!-- Analytics -->
|
|
<script
|
|
defer
|
|
src="https://static.cloudflareinsights.com/beacon.min.js"
|
|
data-cf-beacon='{"token": "03d93e6fefb349c28ee69b408fa25a13"}'
|
|
></script>
|
|
<script type="module" src="/src/client/Main.ts"></script>
|
|
<footer>
|
|
<script
|
|
data-cfasync="false"
|
|
async
|
|
src="//cdn.intergient.com/1025558/75940/ramp.js"
|
|
></script>
|
|
</footer>
|
|
</body>
|
|
</html>
|