Skip to content

Commit 474e1a7

Browse files
committed
made the terminal buttons work
1 parent 4a4212c commit 474e1a7

File tree

2 files changed

+154
-64
lines changed

2 files changed

+154
-64
lines changed

site/app/page.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ export default function Home() {
9696
</Button>
9797
</div>
9898
</div>
99-
<div className="hidden md:block">
99+
<div className="hidden md:block relative">
100100
<LogScroller />
101101
</div>
102102
</div>

site/components/log-scroller.tsx

Lines changed: 153 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,10 @@ export function LogScroller() {
1818
const [isPaused, setIsPaused] = useState(false);
1919
const [isVisible, setIsVisible] = useState(true);
2020
const [isStandalone, setIsStandalone] = useState(false);
21+
const [isMinimized, setIsMinimized] = useState(false);
22+
const [isMaximized, setIsMaximized] = useState(false);
2123
const scrollerRef = useRef<HTMLDivElement>(null);
24+
const containerRef = useRef<HTMLDivElement>(null);
2225

2326
// Check if we're in standalone mode based on window width
2427
useEffect(() => {
@@ -87,23 +90,41 @@ export function LogScroller() {
8790
setLogs([generatePumaBootLogEntry()]);
8891
}, [generatePumaBootLogEntry]);
8992

90-
// Add a new log entry at an interval, but not when user is hovering (isPaused)
93+
// Add a new log entry at an interval, but not when user is hovering (isPaused) unless maximized
9194
useInterval(() => {
92-
if (!isPaused) {
95+
if (!isPaused || isMaximized) {
9396
setLogs((prevLogs) => {
9497
const newLogs = [...prevLogs, generateLogEntry()];
95-
// Keep only the last 15 logs
96-
return newLogs.slice(-15);
98+
// Keep only the last 15 logs when normal, more when maximized
99+
return newLogs.slice(-(isMaximized ? 30 : 15));
97100
});
98101
}
99102
}, 2500);
100103

101104
// Scroll to the bottom when logs change
102105
useEffect(() => {
103-
if (scrollerRef.current && !isPaused) {
106+
if (scrollerRef.current && (!isPaused || isMaximized)) {
104107
scrollerRef.current.scrollTop = scrollerRef.current.scrollHeight;
105108
}
106-
}, [logs, isPaused]);
109+
}, [logs, isPaused, isMaximized]);
110+
111+
// Toggle the minimized state
112+
const handleMinimize = () => {
113+
setIsMinimized(true);
114+
setIsMaximized(false);
115+
};
116+
117+
// Toggle the maximized state
118+
const handleMaximize = () => {
119+
setIsMaximized(true);
120+
setIsMinimized(false);
121+
};
122+
123+
// Restore the window to normal state
124+
const handleRestore = () => {
125+
setIsMinimized(false);
126+
setIsMaximized(false);
127+
};
107128

108129
// If not visible, return an empty div of the same height
109130
if (!isVisible) {
@@ -117,68 +138,126 @@ export function LogScroller() {
117138
'0 10px 30px rgba(0, 0, 0, 0.2), 0 1px 3px rgba(0, 0, 0, 0.3), -5px 5px 15px rgba(0, 0, 0, 0.15)',
118139
};
119140

120-
// Different styles based on layout
121-
const perspectiveStyle = isStandalone
122-
? {
123-
// Straight style for standalone mode
124-
transform: 'scale(1)',
125-
marginLeft: '0',
126-
marginRight: '0',
127-
...baseStyle,
128-
}
129-
: {
130-
// 3D perspective for side-by-side mode
131-
transform:
132-
'perspective(1500px) rotateX(4deg) rotateY(-8deg) rotateZ(1deg)',
133-
transformOrigin: 'center center',
134-
marginLeft: '-40px',
135-
marginRight: '80px',
136-
...baseStyle,
137-
};
141+
// Different styles based on window state and layout
142+
let perspectiveStyle = {};
143+
144+
if (isMinimized) {
145+
// Minimized state - small window in bottom right
146+
perspectiveStyle = {
147+
transform: 'scale(0.25)',
148+
position: 'fixed' as const,
149+
bottom: '20px',
150+
right: '20px',
151+
width: '400px',
152+
zIndex: 100,
153+
transformOrigin: 'bottom right',
154+
...baseStyle,
155+
};
156+
} else if (isMaximized) {
157+
// Maximized state - fixed position to cover the entire hero section
158+
perspectiveStyle = {
159+
transform: 'scale(1)',
160+
position: 'fixed' as const,
161+
top: '0',
162+
left: '0',
163+
width: '100vw',
164+
height: '100vh',
165+
marginLeft: '0',
166+
marginRight: '0',
167+
zIndex: 999,
168+
...baseStyle,
169+
boxShadow: '0 10px 50px rgba(0, 0, 0, 0.4), 0 1px 3px rgba(0, 0, 0, 0.3)',
170+
borderRadius: '0',
171+
};
172+
} else {
173+
// Regular state - depends on standalone
174+
perspectiveStyle = isStandalone
175+
? {
176+
// Straight style for standalone mode
177+
transform: 'scale(1)',
178+
marginLeft: '0',
179+
marginRight: '0',
180+
...baseStyle,
181+
}
182+
: {
183+
// 3D perspective for side-by-side mode
184+
transform:
185+
'perspective(1500px) rotateX(4deg) rotateY(-8deg) rotateZ(1deg)',
186+
transformOrigin: 'center center',
187+
marginLeft: '-40px',
188+
marginRight: '80px',
189+
...baseStyle,
190+
};
191+
}
138192

139-
const onMouseOverStyle = isStandalone
140-
? {
141-
transform: 'scale(1.01)',
142-
boxShadow:
143-
'0 15px 35px rgba(0, 0, 0, 0.25), 0 3px 5px rgba(0, 0, 0, 0.35)',
144-
}
145-
: {
146-
transform:
147-
'perspective(1500px) rotateX(3deg) rotateY(-6deg) rotateZ(0.5deg) scale(1.01)',
148-
boxShadow:
149-
'0 15px 35px rgba(0, 0, 0, 0.25), 0 3px 5px rgba(0, 0, 0, 0.35), -8px 8px 20px rgba(0, 0, 0, 0.15)',
150-
};
193+
// Mouse over effects - only for non-minimized state
194+
const onMouseOverStyle = isMinimized
195+
? {}
196+
: isStandalone
197+
? {
198+
transform: 'scale(1.01)',
199+
boxShadow:
200+
'0 15px 35px rgba(0, 0, 0, 0.25), 0 3px 5px rgba(0, 0, 0, 0.35)',
201+
}
202+
: {
203+
transform:
204+
'perspective(1500px) rotateX(3deg) rotateY(-6deg) rotateZ(0.5deg) scale(1.01)',
205+
boxShadow:
206+
'0 15px 35px rgba(0, 0, 0, 0.25), 0 3px 5px rgba(0, 0, 0, 0.35), -8px 8px 20px rgba(0, 0, 0, 0.15)',
207+
};
151208

152-
const onMouseOutStyle = isStandalone
153-
? {
154-
transform: 'scale(1)',
155-
boxShadow: baseStyle.boxShadow,
156-
}
157-
: {
158-
transform:
159-
'perspective(1500px) rotateX(4deg) rotateY(-8deg) rotateZ(1deg) scale(1)',
160-
boxShadow: baseStyle.boxShadow,
161-
};
209+
const onMouseOutStyle = isMinimized
210+
? {}
211+
: isStandalone
212+
? {
213+
transform: 'scale(1)',
214+
boxShadow: baseStyle.boxShadow,
215+
}
216+
: {
217+
transform:
218+
'perspective(1500px) rotateX(4deg) rotateY(-8deg) rotateZ(1deg) scale(1)',
219+
boxShadow: baseStyle.boxShadow,
220+
};
221+
222+
// Adjust height based on maximized state
223+
const heightClass = isMaximized ? "h-screen" : "h-[375px]";
162224

163225
return (
164226
<div
165-
className="w-full h-[375px] bg-black rounded-lg overflow-hidden shadow-lg transition-all duration-300 ease-in-out"
227+
ref={containerRef}
228+
className={`${isMaximized ? '' : 'w-full'} ${heightClass} bg-black rounded-lg overflow-hidden shadow-lg transition-all duration-300 ease-in-out`}
166229
style={perspectiveStyle}
167230
onMouseOver={(e) => {
168-
Object.assign(e.currentTarget.style, onMouseOverStyle);
231+
if (!isMinimized && !isMaximized) {
232+
Object.assign(e.currentTarget.style, onMouseOverStyle);
233+
}
169234
}}
170235
onMouseOut={(e) => {
171-
Object.assign(e.currentTarget.style, onMouseOutStyle);
236+
if (!isMinimized && !isMaximized) {
237+
Object.assign(e.currentTarget.style, onMouseOutStyle);
238+
}
239+
}}
240+
onMouseEnter={() => {
241+
if (!isMaximized) {
242+
setIsPaused(true);
243+
}
172244
}}
173-
onMouseEnter={() => setIsPaused(true)}
174245
onMouseLeave={() => {
175-
setIsPaused(false);
176-
// Add a small delay before resuming scrolling
177-
setTimeout(() => {
178-
if (scrollerRef.current) {
179-
scrollerRef.current.scrollTop = scrollerRef.current.scrollHeight;
180-
}
181-
}, 100);
246+
if (!isMaximized) {
247+
setIsPaused(false);
248+
// Add a small delay before resuming scrolling
249+
setTimeout(() => {
250+
if (scrollerRef.current) {
251+
scrollerRef.current.scrollTop = scrollerRef.current.scrollHeight;
252+
}
253+
}, 100);
254+
}
255+
}}
256+
onClick={() => {
257+
// Clicking on the minimized window restores it
258+
if (isMinimized) {
259+
handleRestore();
260+
}
182261
}}
183262
>
184263
<div
@@ -192,18 +271,29 @@ export function LogScroller() {
192271
<div
193272
className="w-3 h-3 rounded-full bg-red-500 cursor-pointer hover:bg-red-400 transition-colors"
194273
style={{ boxShadow: '0 1px 1px rgba(0, 0, 0, 0.2)' }}
195-
onClick={() => setIsVisible(false)}
274+
onClick={(e) => {
275+
e.stopPropagation();
276+
setIsVisible(false);
277+
}}
196278
title="Click to close"
197279
></div>
198280
<div
199281
className="w-3 h-3 rounded-full bg-yellow-500 cursor-pointer hover:bg-yellow-400 transition-colors"
200282
style={{ boxShadow: '0 1px 1px rgba(0, 0, 0, 0.2)' }}
201-
onClick={() => setIsVisible(false)}
283+
onClick={(e) => {
284+
e.stopPropagation();
285+
handleMinimize();
286+
}}
202287
title="Click to minimize"
203288
></div>
204289
<div
205-
className="w-3 h-3 rounded-full bg-green-500"
290+
className="w-3 h-3 rounded-full bg-green-500 cursor-pointer hover:bg-green-400 transition-colors"
206291
style={{ boxShadow: '0 1px 1px rgba(0, 0, 0, 0.2)' }}
292+
onClick={(e) => {
293+
e.stopPropagation();
294+
isMaximized ? handleRestore() : handleMaximize();
295+
}}
296+
title={isMaximized ? "Click to restore" : "Click to maximize"}
207297
></div>
208298
</div>
209299
<div
@@ -218,7 +308,7 @@ export function LogScroller() {
218308
</div>
219309

220310
{/* Container with relative positioning for the scrollable content and overlay */}
221-
<div className="relative h-[333px]">
311+
<div className={`relative ${isMaximized ? "h-[calc(100vh-30px)]" : "h-[333px]"}`}>
222312
{/* Scrollable content */}
223313
<div
224314
ref={scrollerRef}
@@ -244,15 +334,15 @@ export function LogScroller() {
244334
backgroundColor: 'transparent',
245335
padding: '12px',
246336
borderRadius: '0px',
247-
minHeight: '300px',
337+
minHeight: isMaximized ? 'calc(100vh - 100px)' : '300px',
248338
textShadow: '0 1px 0 rgba(0, 0, 0, 0.7)',
249339
letterSpacing: '0.2px',
250340
}}
251341
>
252342
{logs.join('\n\n')}
253343
</SyntaxHighlighter>
254344
) : (
255-
<div className="w-full h-[300px]"></div>
345+
<div className={`w-full ${isMaximized ? 'h-[calc(100vh-100px)]' : 'h-[300px]'}`}></div>
256346
)}
257347
</div>
258348
</div>

0 commit comments

Comments
 (0)