Skip to content

Commit 3294111

Browse files
spike on mainteance
1 parent 51db184 commit 3294111

File tree

3 files changed

+319
-4
lines changed

3 files changed

+319
-4
lines changed

website/src/App.jsx

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import BattleScreen from './components/BattleScreen';
88
import GameOverScreen from './components/GameOverScreen';
99
import LoadingScreen from './components/LoadingScreen';
1010
import EventExplorer from './components/EventExplorer';
11+
import MaintenancePage from './components/MaintenancePage';
1112

1213
function App() {
1314
const [gameState, setGameState] = useState('loading');
@@ -119,9 +120,23 @@ function App() {
119120
// Don't set up event handlers here - we'll do it in a separate useEffect
120121
} catch (err) {
121122
console.error('Failed to initialize client:', err);
122-
console.error('Error details:', err.message, err.stack);
123-
setError(`Failed to connect to server: ${err.message || 'Unknown error'}`);
124-
setGameState('error');
123+
console.error('Error details:', err?.message, err?.stack);
124+
125+
const message = err?.message || 'Unknown error';
126+
const normalizedMessage = typeof message === 'string' ? message.toLowerCase() : '';
127+
const isNetworkError =
128+
err instanceof TypeError ||
129+
normalizedMessage.includes('network') ||
130+
normalizedMessage.includes('fetch') ||
131+
normalizedMessage.includes('socket') ||
132+
normalizedMessage.includes('connect');
133+
134+
if (isNetworkError) {
135+
setGameState('maintenance');
136+
} else {
137+
setError(`Failed to connect to server: ${message}`);
138+
setGameState('error');
139+
}
125140
}
126141
}
127142

@@ -301,6 +316,10 @@ function App() {
301316
return <LoadingScreen />;
302317
}
303318

319+
if (gameState === 'maintenance') {
320+
return <MaintenancePage />;
321+
}
322+
304323
if (gameState === 'error') {
305324
return (
306325
<div className="min-h-screen bg-retro-blue flex items-center justify-center p-2 sm:p-4 lg:p-8">
@@ -393,4 +412,4 @@ function App() {
393412
);
394413
}
395414

396-
export default App;
415+
export default App;
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
.dvd-container {
2+
position: fixed;
3+
top: 0;
4+
left: 0;
5+
width: 100vw;
6+
height: 100vh;
7+
background-color: #000;
8+
overflow: hidden;
9+
font-family: 'Inconsolata', 'Consolas', 'Monaco', 'Courier New', monospace;
10+
}
11+
12+
.dvd-logo {
13+
position: absolute;
14+
padding: 30px 25px;
15+
background-color: currentColor;
16+
border: 4px solid;
17+
user-select: none;
18+
box-shadow: 0 0 20px rgba(255, 255, 255, 0.15);
19+
max-width: 350px;
20+
transform: translateZ(0);
21+
cursor: pointer;
22+
animation: glow 3s infinite ease-in-out;
23+
}
24+
25+
.logo-content {
26+
display: flex;
27+
flex-direction: column;
28+
align-items: center;
29+
justify-content: center;
30+
text-align: center;
31+
color: #000;
32+
width: 100%;
33+
}
34+
35+
.maintenance-text {
36+
font-size: 32px;
37+
font-weight: bold;
38+
word-wrap: break-word;
39+
width: 100%;
40+
}
41+
42+
.small-text {
43+
font-size: 18px;
44+
margin-top: 16px;
45+
word-wrap: break-word;
46+
width: 100%;
47+
}
48+
49+
.link-text {
50+
text-decoration: underline;
51+
}
52+
53+
.dvd-logo:hover .link-text {
54+
opacity: 0.8;
55+
}
56+
57+
@keyframes glow {
58+
0% {
59+
box-shadow: 0 0 5px currentColor;
60+
}
61+
50% {
62+
box-shadow: 0 0 20px currentColor;
63+
}
64+
100% {
65+
box-shadow: 0 0 5px currentColor;
66+
}
67+
}
68+
69+
@media (max-width: 480px) {
70+
.dvd-logo {
71+
max-width: 220px;
72+
padding: 15px 20px;
73+
border-width: 3px;
74+
}
75+
76+
.maintenance-text {
77+
font-size: 20px;
78+
}
79+
80+
.small-text {
81+
font-size: 14px;
82+
margin-top: 8px;
83+
}
84+
}
Lines changed: 212 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,212 @@
1+
import React, { useState, useEffect, useRef } from 'react';
2+
import './MaintenancePage.css';
3+
4+
const MaintenancePage = () => {
5+
const containerRef = useRef(null);
6+
const logoRef = useRef(null);
7+
const positionRef = useRef({ x: 50, y: 50 });
8+
const directionRef = useRef({ x: 1, y: 1 });
9+
const [color, setColor] = useState('#0000ee');
10+
const currentColorRef = useRef('#0000ee');
11+
const animationFrameRef = useRef(null);
12+
const initializedRef = useRef(false);
13+
const speed = 0.5; // pixels per frame
14+
const logoDimensionsRef = useRef({ width: 0, height: 0 });
15+
16+
const handleLogoClick = () => {
17+
window.open('https://x.com/commonwarexyz', '_blank', 'noopener,noreferrer');
18+
};
19+
20+
useEffect(() => {
21+
const measureLogo = () => {
22+
if (logoRef.current && containerRef.current) {
23+
const rect = logoRef.current.getBoundingClientRect();
24+
logoDimensionsRef.current = {
25+
width: rect.width,
26+
height: rect.height,
27+
};
28+
}
29+
};
30+
31+
measureLogo();
32+
const timer = setTimeout(measureLogo, 200);
33+
34+
return () => clearTimeout(timer);
35+
}, []);
36+
37+
useEffect(() => {
38+
const initTimeout = setTimeout(() => {
39+
if (!initializedRef.current && containerRef.current && logoRef.current) {
40+
const containerWidth = containerRef.current.clientWidth;
41+
const containerHeight = containerRef.current.clientHeight;
42+
43+
if (logoDimensionsRef.current.width === 0) {
44+
const rect = logoRef.current.getBoundingClientRect();
45+
logoDimensionsRef.current = {
46+
width: rect.width,
47+
height: rect.height,
48+
};
49+
}
50+
51+
const logoWidth = logoDimensionsRef.current.width;
52+
const logoHeight = logoDimensionsRef.current.height;
53+
54+
positionRef.current = {
55+
x: Math.random() * (containerWidth - logoWidth),
56+
y: Math.random() * (containerHeight - logoHeight),
57+
};
58+
59+
initializedRef.current = true;
60+
logoRef.current.style.left = `${positionRef.current.x}px`;
61+
logoRef.current.style.top = `${positionRef.current.y}px`;
62+
}
63+
}, 100);
64+
65+
return () => clearTimeout(initTimeout);
66+
}, []);
67+
68+
useEffect(() => {
69+
const colors = [
70+
'#0000ee',
71+
'#ee0000',
72+
'#00ee00',
73+
'#ee00ee',
74+
'#eeee00',
75+
'#00eeee',
76+
'#ff7700',
77+
'#7700ff',
78+
];
79+
80+
const getRandomColor = () => {
81+
const filteredColors = colors.filter((c) => c !== currentColorRef.current);
82+
return filteredColors[Math.floor(Math.random() * filteredColors.length)];
83+
};
84+
85+
const updateColor = () => {
86+
const newColor = getRandomColor();
87+
currentColorRef.current = newColor;
88+
setColor(newColor);
89+
};
90+
91+
const animate = () => {
92+
if (!containerRef.current || !logoRef.current) {
93+
animationFrameRef.current = requestAnimationFrame(animate);
94+
return;
95+
}
96+
97+
const containerWidth = containerRef.current.clientWidth;
98+
const containerHeight = containerRef.current.clientHeight;
99+
const logoWidth = logoDimensionsRef.current.width;
100+
const logoHeight = logoDimensionsRef.current.height;
101+
102+
let newX = positionRef.current.x + speed * directionRef.current.x;
103+
let newY = positionRef.current.y + speed * directionRef.current.y;
104+
let colorChanged = false;
105+
const rightEdgeThreshold = containerWidth - logoWidth;
106+
107+
if (newX <= 0) {
108+
directionRef.current.x = Math.abs(directionRef.current.x);
109+
newX = 0;
110+
if (!colorChanged) {
111+
updateColor();
112+
colorChanged = true;
113+
}
114+
} else if (newX >= rightEdgeThreshold) {
115+
directionRef.current.x = -Math.abs(directionRef.current.x);
116+
newX = rightEdgeThreshold;
117+
if (!colorChanged) {
118+
updateColor();
119+
colorChanged = true;
120+
}
121+
}
122+
123+
const bottomEdgeThreshold = containerHeight - logoHeight;
124+
if (newY <= 0) {
125+
directionRef.current.y = Math.abs(directionRef.current.y);
126+
newY = 0;
127+
if (!colorChanged) {
128+
updateColor();
129+
colorChanged = true;
130+
}
131+
} else if (newY >= bottomEdgeThreshold) {
132+
directionRef.current.y = -Math.abs(directionRef.current.y);
133+
newY = bottomEdgeThreshold;
134+
if (!colorChanged) {
135+
updateColor();
136+
colorChanged = true;
137+
}
138+
}
139+
140+
positionRef.current = { x: newX, y: newY };
141+
142+
logoRef.current.style.left = `${newX}px`;
143+
logoRef.current.style.top = `${newY}px`;
144+
145+
animationFrameRef.current = requestAnimationFrame(animate);
146+
};
147+
148+
animationFrameRef.current = requestAnimationFrame(animate);
149+
150+
return () => {
151+
if (animationFrameRef.current !== null) {
152+
cancelAnimationFrame(animationFrameRef.current);
153+
}
154+
};
155+
}, []);
156+
157+
useEffect(() => {
158+
const handleResize = () => {
159+
if (containerRef.current && logoRef.current) {
160+
const containerWidth = containerRef.current.clientWidth;
161+
const containerHeight = containerRef.current.clientHeight;
162+
const logoWidth = logoRef.current.clientWidth;
163+
const logoHeight = logoRef.current.clientHeight;
164+
165+
let newX = positionRef.current.x;
166+
let newY = positionRef.current.y;
167+
168+
if (newX + logoWidth > containerWidth) {
169+
newX = containerWidth - logoWidth;
170+
}
171+
172+
if (newY + logoHeight > containerHeight) {
173+
newY = containerHeight - logoHeight;
174+
}
175+
176+
positionRef.current = { x: newX, y: newY };
177+
logoRef.current.style.left = `${newX}px`;
178+
logoRef.current.style.top = `${newY}px`;
179+
}
180+
};
181+
182+
window.addEventListener('resize', handleResize);
183+
return () => {
184+
window.removeEventListener('resize', handleResize);
185+
};
186+
}, []);
187+
188+
return (
189+
<div className="dvd-container" ref={containerRef}>
190+
<div
191+
className="dvd-logo"
192+
ref={logoRef}
193+
style={{
194+
color: color,
195+
borderColor: color,
196+
}}
197+
onClick={handleLogoClick}
198+
>
199+
<div className="logo-content">
200+
<div className="maintenance-text">
201+
<p>SYSTEM MAINTENANCE</p>
202+
<p className="small-text">
203+
Follow <span className="link-text">@commonwarexyz</span> for updates and new releases.
204+
</p>
205+
</div>
206+
</div>
207+
</div>
208+
</div>
209+
);
210+
};
211+
212+
export default MaintenancePage;

0 commit comments

Comments
 (0)