diff --git a/client/app/page.tsx b/client/app/page.tsx index 65fb4bc..a8b2aaa 100644 --- a/client/app/page.tsx +++ b/client/app/page.tsx @@ -104,67 +104,69 @@ const Home = () => { const currentTheme = VSCODE_THEMES[currentThemeIndex]; return ( -
- -
-

- Osborne -

-
- - {/* Theme Switcher - Pill Button */} -
- -
- - - setNewRoomCode(value.toUpperCase())} - maxLength={6} - pattern="[A-Z0-9]*" - inputMode="text" - > - - {[...Array(6)].map((_, index) => ( - - ))} - - - - or - - - - {/* Attribution */} -
-

- made with {" "} - by{" "} - - WebArk - -

+
+
+ +
+

+ Osborne +

- -
+ + {/* Theme Switcher - Pill Button */} +
+ +
+ + + setNewRoomCode(value.toUpperCase())} + maxLength={6} + pattern="[A-Z0-9]*" + inputMode="text" + > + + {[...Array(6)].map((_, index) => ( + + ))} + + + + or + + + + {/* Attribution */} +
+

+ made with {" "} + by{" "} + + WebArk + +

+
+
+ +
setIsDisclaimerOpen(true)} onDMCAOpen={() => setIsDMCAOpen(true)} diff --git a/client/app/room/page.tsx b/client/app/room/page.tsx index 46d1b80..b721a4c 100644 --- a/client/app/room/page.tsx +++ b/client/app/room/page.tsx @@ -11,13 +11,16 @@ import { import { useRouter, useSearchParams } from "next/navigation"; import { Button } from "@/components/ui/button"; import { - HoverCard, - HoverCardContent, - HoverCardTrigger, -} from "@/components/ui/hover-card"; + Card, + CardContent, + CardHeader, + CardTitle, + CardFooter, +} from "@/components/ui/card"; import { WifiOff, RefreshCw, + TriangleAlert, } from "lucide-react"; import { Skeleton } from "@/components/ui/skeleton"; import { CommentsPanel } from "@/components/RightPanel"; @@ -35,6 +38,7 @@ import dotenv from "dotenv"; import { JetBrains_Mono } from "next/font/google"; import { ThemeProvider } from "next-themes"; import { ContentWarningModal } from "@/components/ContentWarningModal"; +import { BetterHoverCard, HoverCardProvider } from "@/components/ui/BetterHoverCard"; dotenv.config(); @@ -210,7 +214,7 @@ const Room = () => { const [error, setError] = useState(""); const [isModalOpen, setIsModalOpen] = useState(false); const [isPurgeModalOpen, setIsPurgeModalOpen] = useState(false); - const [showDisconnectToast, setShowDisconnectToast] = useState(false); + const [showReconnectOverlay, setShowReconnectOverlay] = useState(false); const [currentThemeId, setCurrentThemeId] = useState("one-dark"); const [selectedLineStart, setSelectedLineStart] = useState(); const [selectedLineEnd, setSelectedLineEnd] = useState(); @@ -223,6 +227,8 @@ const Room = () => { const [rightPanelForced, setRightPanelForced] = useState(false); const [popupMessage, setPopupMessage] = useState<{text: string; type?: 'default' | 'warning'} | null>(null); const [isMobile, setIsMobile] = useState(false); + const [fileSizeError, setFileSizeError] = useState(null); + const [purgeError, setPurgeError] = useState(null); // Detect mobile screen size useEffect(() => { @@ -380,25 +386,19 @@ const Room = () => { } }, [currentThemeId]); - // Show disconnect toast only if still disconnected after a delay + // Show reconnect overlay only if still disconnected after a delay useEffect(() => { let showTimer: NodeJS.Timeout | null = null; - let hideTimer: NodeJS.Timeout | null = null; if (status === "Disconnected") { - // Wait 800ms before showing toast + // Wait 800ms before showing overlay showTimer = setTimeout(() => { - setShowDisconnectToast(true); - // Auto-hide after 10 seconds - hideTimer = setTimeout(() => { - setShowDisconnectToast(false); - }, 10000); + setShowReconnectOverlay(true); }, 800); } else { - setShowDisconnectToast(false); + setShowReconnectOverlay(false); } return () => { if (showTimer) clearTimeout(showTimer); - if (hideTimer) clearTimeout(hideTimer); }; }, [status]); @@ -707,7 +707,7 @@ const Room = () => { router.push("/"); } catch (error) { console.error("Error purging room:", error); - showPopup("Failed to purge room", "warning"); + setPurgeError("Failed to purge room"); } setIsPurgeModalOpen(false); @@ -725,7 +725,7 @@ const Room = () => { // Check file size limit if (file.size > maxFileSize) { const fileSizeInMB = (file.size / (1024 * 1024)).toFixed(2); - showPopup(`File "${file.name}" (${fileSizeInMB}MB) exceeds 10MB limit`, 'warning'); + setFileSizeError(`File "${file.name}" (${fileSizeInMB}MB) exceeds 10MB limit`); continue; // Skip this file and continue with others } @@ -795,7 +795,8 @@ const Room = () => { } return ( -
+ +
{ >
- - + { > share - - - copy link to this page - - - - + } + contentClassName="py-1 px-2 w-auto text-popover-foreground bg-popover text-xs border-foreground" + > + copy link to clipboard + + { > purge - - - permanently delete this room and all its contents - - - - + } + contentClassName="py-1 px-2 w-auto text-popover-foreground bg-popover text-xs border-foreground" + > + permanently delete this room + + { > exit - - - return to home - - + } + contentClassName="py-1 px-2 w-auto text-popover-foreground bg-popover text-xs border-foreground" + > + return to home +
- - + { @@ -868,13 +869,13 @@ const Room = () => { > upload - - - upload files - - - - + } + contentClassName="py-1 px-2 w-auto text-xs border-foreground" + > + upload files + + { @@ -886,41 +887,41 @@ const Room = () => { > theme - - - {getThemeById(currentThemeId)?.name || "Switch theme"} - - + } + contentClassName="py-1 px-2 w-auto text-xs border-foreground" + > + {`switch to ${getThemeById(getNextTheme(currentThemeId)?.id)?.name}`} + {/* Panel Controls for mobile and when panels are hidden due to width */} {(isMobile || !showSidePanels) && ( <> - - + setLeftPanelForced(!leftPanelForced)} > media - - - toggle users & media panel - - - - + } + contentClassName="py-1 px-2 w-auto text-xs border-foreground z-[999]" + > + show media + + setRightPanelForced(!rightPanelForced)} > notes - - - toggle comments panel - - + } + contentClassName="py-1 px-2 w-auto text-xs border-foreground" + > + show comments + )}
@@ -935,8 +936,8 @@ const Room = () => {