From a3c37e31ac0bc904b640e31790249b51171d19af Mon Sep 17 00:00:00 2001 From: "Rodrigo Rodriguez (Pragmatismo)" Date: Sun, 29 Jun 2025 21:33:12 -0300 Subject: [PATCH] feat: Add mobile chat interface and command input to footer component --- app/client-nav.tsx | 100 ++++++++- app/footer.tsx | 549 +++++++++++++++++++++++++++------------------ app/layout.tsx | 2 +- app/prompt.txt | 8 +- public/output.css | 151 ++++++++++++- 5 files changed, 575 insertions(+), 235 deletions(-) diff --git a/app/client-nav.tsx b/app/client-nav.tsx index b01efda..cc6dd47 100644 --- a/app/client-nav.tsx +++ b/app/client-nav.tsx @@ -4,6 +4,7 @@ import { usePathname, useRouter } from 'next/navigation'; import Image from 'next/image'; import { useRef, useEffect, useState } from 'react'; import { useTheme } from './theme-provider'; +import { ChevronLeft, ChevronRight, HardDrive, Terminal } from 'lucide-react'; import './client-nav.css'; // Ensure you have the CSS file for styles const examples = [ @@ -21,7 +22,7 @@ const examples = [ { name: "Settings", href: "/settings", color: "#6B7280" }, // Gray ]; -export function Nav() { +export const Nav = ()=> { const pathname = usePathname(); const router = useRouter(); const scrollContainerRef = useRef(null); @@ -32,8 +33,35 @@ export function Nav() { const loginMenuRef = useRef(null); const [showThemeMenu, setShowThemeMenu] = useState(false); const themeMenuRef = useRef(null); + const [currentTime, setCurrentTime] = useState(new Date()); const { theme, setTheme, themes } = useTheme(); + // Update time every second + useEffect(() => { + const timer = setInterval(() => { + setCurrentTime(new Date()); + }, 1000); + + return () => clearInterval(timer); + }, []); + + const formatTime = (date) => { + return date.toLocaleTimeString('en-US', { + hour12: false, + hour: '2-digit', + minute: '2-digit', + second: '2-digit' + }); + }; + + const formatDate = (date) => { + return date.toLocaleDateString('en-US', { + year: 'numeric', + month: '2-digit', + day: '2-digit' + }); + }; + const isActive = (href: string) => { if (href === '/') return pathname === href; return pathname.startsWith(href); @@ -153,7 +181,36 @@ export function Nav() { return ( <> -
+ {/* Retro System Status Bar */} +
+
+
+
+ + RETRO NAVIGATOR v4.0 +
+
+
+ READY +
+
+ THEME: + {theme.label} +
+
+
+ {formatDate(currentTime)} + {formatTime(currentTime)} +
+ + SYS +
+
+
+
+ + {/* Main Navigation */} +
@@ -166,8 +223,12 @@ export function Nav() {
{showScrollButtons && ( - )} @@ -182,6 +243,20 @@ export function Nav() { onClick={() => router.push(example.href)} className={`nav-item ${active ? 'active' : ''}`} style={{'--neon-color': example.color} as React.CSSProperties} + onMouseEnter={(e) => { + e.target.style.boxShadow = `0 0 15px ${example.color}60`; + e.target.style.borderColor = example.color; + e.target.style.color = example.color; + e.target.style.textShadow = `0 0 8px ${example.color}80`; + }} + onMouseLeave={(e) => { + if (!active) { + e.target.style.boxShadow = 'none'; + e.target.style.borderColor = ''; + e.target.style.color = ''; + e.target.style.textShadow = 'none'; + } + }} > {example.name}
@@ -192,8 +267,12 @@ export function Nav() {
{showScrollButtons && ( - )} @@ -255,8 +334,13 @@ export function Nav() {
-
+
); -} \ No newline at end of file +} + + + + +export default Nav; \ No newline at end of file diff --git a/app/footer.tsx b/app/footer.tsx index ab70ff7..01b4f97 100644 --- a/app/footer.tsx +++ b/app/footer.tsx @@ -1,7 +1,7 @@ "use client"; import React, { useState, useEffect } from 'react'; -import { MessageCircle, Send, X, Minimize2, Maximize2, Monitor, Terminal, Cpu, HardDrive } from 'lucide-react'; +import { MessageCircle, Send, X, Minimize2, Maximize2, Monitor, Terminal, Cpu, HardDrive, ChevronUp, ChevronDown } from 'lucide-react'; import { ResizableHandle, ResizablePanel, @@ -13,6 +13,8 @@ const Footer = ({ className = "", shortcuts }) => { const [inputValue, setInputValue] = useState(''); const [isMobile, setIsMobile] = useState(false); const [currentTime, setCurrentTime] = useState(new Date()); + const [isMaximized, setIsMaximized] = useState(false); + const [isMinimized, setIsMinimized] = useState(false); useEffect(() => { const checkMobile = () => { @@ -89,6 +91,20 @@ const Footer = ({ className = "", shortcuts }) => { } }; + const toggleMaximize = () => { + if (isMinimized) { + setIsMinimized(false); + } + setIsMaximized(!isMaximized); + }; + + const toggleMinimize = () => { + setIsMinimized(!isMinimized); + if (isMaximized) { + setIsMaximized(false); + } + }; + const formatTime = (date) => { return date.toLocaleTimeString('en-US', { hour12: false, @@ -108,248 +124,349 @@ const Footer = ({ className = "", shortcuts }) => { }); }; + const getContainerHeight = () => { + if (isMinimized) return 'h-4'; + if (isMaximized) return 'h-screen fixed inset-0 z-50 bg-background'; + return isMobile ? 'h-64' : 'h-32'; + }; + + const scrollbarStyles = ` + /* Webkit browsers */ + ::-webkit-scrollbar { + width: 8px; + height: 8px; + } + + ::-webkit-scrollbar-track { + background: rgba(0, 0, 0, 0.1); + border-radius: 4px; + } + + ::-webkit-scrollbar-thumb { + background: rgba(128, 128, 128, 0.3); + border-radius: 4px; + border: 1px solid rgba(255, 255, 255, 0.1); + } + + ::-webkit-scrollbar-thumb:hover { + background: rgba(128, 128, 128, 0.5); + } + + /* Firefox */ + * { + scrollbar-width: thin; + scrollbar-color: rgba(128, 128, 128, 0.3) rgba(0, 0, 0, 0.1); + } + `; + if (isMobile) { return ( -
- - -
-
-
- - MOBILE TERMINAL -
-
- {formatTime(currentTime)} -
+ <> +