feat: make terminal resizable with drag handle
Build & Push Portfolio Image / build-push (push) Successful in 2m44s

This commit is contained in:
Story Crater Bot
2026-09-01 10:33:14 -07:00
parent 989109352b
commit db574ca04f
+48 -1
View File
@@ -67,9 +67,13 @@ export function InteractiveTerminal() {
const [isLoading, setIsLoading] = useState(false)
const { isOpen, setIsOpen } = useTerminal()
const [isMac, setIsMac] = useState(true)
const [width, setWidth] = useState(448) // 28rem = 448px
const [height, setHeight] = useState(512) // 32rem = 512px
const [isResizing, setIsResizing] = useState(false)
const terminalRef = useRef<HTMLDivElement>(null)
const containerRef = useRef<HTMLDivElement>(null)
const inputRef = useRef<HTMLInputElement>(null)
const resizeHandleRef = useRef<HTMLDivElement>(null)
const isDark = useTheme()
// Close on click outside
@@ -108,6 +112,35 @@ export function InteractiveTerminal() {
if (isOpen) inputRef.current?.focus()
}, [isOpen])
// Handle terminal resize
useEffect(() => {
const handleMouseMove = (e: MouseEvent) => {
if (!isResizing) return
const container = containerRef.current
if (!container) return
const rect = container.getBoundingClientRect()
const newWidth = Math.max(320, e.clientX - rect.left)
const newHeight = Math.max(300, e.clientY - rect.top)
setWidth(newWidth)
setHeight(newHeight)
}
const handleMouseUp = () => {
setIsResizing(false)
}
if (isResizing) {
document.addEventListener('mousemove', handleMouseMove)
document.addEventListener('mouseup', handleMouseUp)
return () => {
document.removeEventListener('mousemove', handleMouseMove)
document.removeEventListener('mouseup', handleMouseUp)
}
}
}, [isResizing])
const handleCommand = async (cmd: string) => {
const trimmed = cmd.trim()
if (!trimmed) return
@@ -216,7 +249,8 @@ export function InteractiveTerminal() {
ref={containerRef}
initial={{ opacity: 0, y: 10 }}
animate={{ opacity: 1, y: 0 }}
className={`rounded-lg shadow-2xl w-[28rem] h-[32rem] flex flex-col border ${
style={{ width: `${width}px`, height: `${height}px` }}
className={`rounded-lg shadow-2xl flex flex-col border relative ${
isDark
? 'bg-gray-950 border-gray-700'
: 'bg-white border-gray-300'
@@ -303,6 +337,19 @@ export function InteractiveTerminal() {
/>
</div>
</div>
{/* Resize handle */}
<div
ref={resizeHandleRef}
onMouseDown={() => setIsResizing(true)}
className={`absolute bottom-0 right-0 w-4 h-4 cursor-se-resize ${
isDark ? 'bg-gray-700 hover:bg-gray-600' : 'bg-gray-300 hover:bg-gray-400'
} transition-colors`}
style={{
borderBottomRightRadius: 'inherit',
opacity: isResizing ? 1 : 0.5,
}}
/>
</motion.div>
)}
</motion.div>