feat: add overlay while websocket connects

This commit is contained in:
2026-06-19 04:00:04 -03:00
parent d15930a1c3
commit 79f6748a35
3 changed files with 136 additions and 6 deletions
+3
View File
@@ -2,6 +2,7 @@ import type { Metadata } from "next";
import Sidebar from "../components/Sidebar"; import Sidebar from "../components/Sidebar";
import styles from "../styles/Layout.module.css"; import styles from "../styles/Layout.module.css";
import "./globals.css"; import "./globals.css";
import AppContainer from "@/components/Container";
export const metadata: Metadata = { export const metadata: Metadata = {
title: "Hex: Unlocked", title: "Hex: Unlocked",
@@ -16,12 +17,14 @@ export default function RootLayout({
return ( return (
<html lang="en"> <html lang="en">
<body> <body>
<AppContainer>
<div className={styles.layoutContainer}> <div className={styles.layoutContainer}>
<Sidebar /> <Sidebar />
<main className={styles.mainContent}> <main className={styles.mainContent}>
{children} {children}
</main> </main>
</div> </div>
</AppContainer>
</body> </body>
</html> </html>
); );
+44
View File
@@ -0,0 +1,44 @@
"use client";
import { useEffect, useState } from "react";
import { useWebsocketStore } from "../store/useWebsocketStore";
import styles from "../styles/AppContainer.module.css";
export default function AppContainer({ children }: { children: React.ReactNode }) {
const { connect, isConnected } = useWebsocketStore();
const [showHelp, setShowHelp] = useState(false);
useEffect(() => {
connect();
const timer = setTimeout(() => {
setShowHelp(true);
}, 3000);
return () => clearTimeout(timer);
}, [connect]);
if (!isConnected) {
return (
<div className={styles.overlay}>
<div className={styles.card}>
<h1 className={styles.title}>Hex: Unlocked</h1>
<p className={styles.subtitle}>Awaiting unlocker connection</p>
<div className={styles.spinner}></div>
{showHelp && (
<div className={styles.helpText}>
<p style={{ marginBottom: '0.5rem' }}>Make sure the client is running.</p>
<p>
Don't have it? Download it <a href="https://git.neru.rip/neru/HexUnlocked" target="_blank" rel="noreferrer" className={styles.link}>here</a>
</p>
</div>
)}
</div>
</div>
);
}
return <>{children}</>;
}
+83
View File
@@ -0,0 +1,83 @@
.overlay {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 100vh;
width: 100vw;
background: #000000;
color: #ffffff;
font-family: 'Roboto Condensed', sans-serif;
text-align: center;
}
.card {
background: #050505;
border: 1px solid #1a1a1a;
border-top: 3px solid #a30000;
padding: 3rem 4rem;
display: flex;
flex-direction: column;
align-items: center;
box-shadow: 0 0 20px rgba(0, 0, 0, 0.6);
min-width: 400px;
}
.title {
font-size: 2.25rem;
text-transform: uppercase;
color: #ffffff;
letter-spacing: 0.05em;
margin: 0 0 0.5rem 0;
text-shadow: 2px 2px 5px rgba(0, 0, 0, 0.8);
font-family: 'Oswald', sans-serif;
}
.subtitle {
font-size: 0.9rem;
color: #777777;
text-transform: uppercase;
letter-spacing: 0.1em;
margin: 0 0 2rem 0;
}
.spinner {
width: 36px;
height: 36px;
border: 3px solid #1a1a1a;
border-top: 3px solid #a30000;
border-radius: 50%;
animation: spin 1s linear infinite;
margin-bottom: 2rem;
}
.helpText {
color: #555555;
font-size: 0.85rem;
margin-top: 1rem;
letter-spacing: 0.05em;
text-transform: uppercase;
animation: fadeIn 1s ease-in;
}
.link {
color: #a30000;
text-decoration: none;
font-weight: bold;
transition: all 0.2s ease;
}
.link:hover {
color: #ff0000;
text-shadow: 0 0 10px rgba(163, 0, 0, 0.4);
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
@keyframes fadeIn {
from { opacity: 0; }
to { opacity: 1; }
}