From 646f722ce168ec98b33d69eee0646dd19dd1695a Mon Sep 17 00:00:00 2001 From: angel Date: Wed, 2 Jul 2025 16:33:14 +0000 Subject: [PATCH] feat: enhance Ihateserverside component with client-side hydration and sidebar functionality --- .env.local | 2 +- app/components/ihateserverside.tsx | 60 ++++++++++++++++++++++++---- app/components/menu.tsx | 63 +++++++++++++++++++----------- 3 files changed, 94 insertions(+), 31 deletions(-) diff --git a/.env.local b/.env.local index 079945a..093b263 100644 --- a/.env.local +++ b/.env.local @@ -1 +1 @@ -NEXT_PUBLIC_COMMIT_SHA=dd1a5b1 +NEXT_PUBLIC_COMMIT_SHA=1c60db5 diff --git a/app/components/ihateserverside.tsx b/app/components/ihateserverside.tsx index a44733f..073fd66 100644 --- a/app/components/ihateserverside.tsx +++ b/app/components/ihateserverside.tsx @@ -1,6 +1,6 @@ 'use client'; -import React, { useState } from 'react'; +import React, { useState, useEffect } from 'react'; import { Menu } from "@/app/components/menu"; import { Sidebar } from "@/app/components/sidebar"; import { useNavidrome } from "@/app/components/NavidromeContext"; @@ -15,14 +15,17 @@ const Ihateserverside: React.FC = ({ children }) => { const [isSidebarVisible, setIsSidebarVisible] = useState(true); const [isStatusBarVisible, setIsStatusBarVisible] = useState(true); const [isSidebarHidden, setIsSidebarHidden] = useState(false); - const [isSidebarCollapsed, setIsSidebarCollapsed] = useState(() => { - if (typeof window !== 'undefined') { - return localStorage.getItem('sidebar-collapsed') === 'true'; - } - return false; - }); + const [isSidebarCollapsed, setIsSidebarCollapsed] = useState(false); + const [isClient, setIsClient] = useState(false); const { playlists } = useNavidrome(); + // Handle client-side hydration + useEffect(() => { + setIsClient(true); + const savedCollapsed = localStorage.getItem('sidebar-collapsed') === 'true'; + setIsSidebarCollapsed(savedCollapsed); + }, []); + const toggleSidebarCollapse = () => { const newCollapsed = !isSidebarCollapsed; setIsSidebarCollapsed(newCollapsed); @@ -36,6 +39,49 @@ const Ihateserverside: React.FC = ({ children }) => { setIsSidebarHidden(true); // This will fully hide the sidebar after transition } }; + + if (!isClient) { + // Return a basic layout during SSR to match initial client render + return ( +
+ {/* Top Menu */} +
+ setIsSidebarVisible(!isSidebarVisible)} + isSidebarVisible={isSidebarVisible} + toggleStatusBar={() => setIsStatusBarVisible(!isStatusBarVisible)} + isStatusBarVisible={isStatusBarVisible} + /> +
+ + {/* Main Content Area */} +
+
+ +
+
+
{children}
+
+
+ + {/* Floating Audio Player */} + + +
+ ); + } return (
{/* Top Menu */} diff --git a/app/components/menu.tsx b/app/components/menu.tsx index 958d37a..d747fd1 100644 --- a/app/components/menu.tsx +++ b/app/components/menu.tsx @@ -44,6 +44,8 @@ export function Menu({ toggleSidebar, isSidebarVisible, toggleStatusBar, isStatu const router = useRouter(); const [open, setOpen] = useState(false); const { isConnected } = useNavidrome(); + const [isClient, setIsClient] = useState(false); + const [navidromeUrl, setNavidromeUrl] = useState(null); // For this demo, we'll show connection status instead of user auth const connectionStatus = isConnected ? "Connected to Navidrome" : "Not connected"; @@ -57,6 +59,29 @@ export function Menu({ toggleSidebar, isSidebarVisible, toggleStatusBar, isStatu setIsFullScreen(!isFullScreen) }, [isFullScreen]) + useEffect(() => { + setIsClient(true); + + // Get Navidrome URL from localStorage + const config = localStorage.getItem("navidrome-config"); + if (config) { + try { + const { serverUrl } = JSON.parse(config); + if (serverUrl) { + // Remove protocol (http:// or https://) and trailing slash + const prettyUrl = serverUrl.replace(/^https?:\/\//, "").replace(/\/$/, ""); + setNavidromeUrl(prettyUrl); + } else { + setNavidromeUrl(null); + } + } catch { + setNavidromeUrl(null); + } + } else { + setNavidromeUrl(null); + } + }, []); + useEffect(() => { const handleKeyDown = (event: KeyboardEvent) => { if ((event.metaKey || event.ctrlKey) && event.key === ',') { @@ -73,12 +98,16 @@ export function Menu({ toggleSidebar, isSidebarVisible, toggleStatusBar, isStatu } }; - window.addEventListener('keydown', handleKeyDown); + if (isClient) { + window.addEventListener('keydown', handleKeyDown); + } return () => { - window.removeEventListener('keydown', handleKeyDown); + if (isClient) { + window.removeEventListener('keydown', handleKeyDown); + } }; - }, [router, toggleSidebar, handleFullScreen]); + }, [router, toggleSidebar, handleFullScreen, isClient]); return ( <> @@ -100,7 +129,7 @@ export function Menu({ toggleSidebar, isSidebarVisible, toggleStatusBar, isStatu Preferences ⌘, - window.close()}> + isClient && window.close()}> Quit Music ⌘Q @@ -281,25 +310,13 @@ export function Menu({ toggleSidebar, isSidebarVisible, toggleStatusBar, isStatu
Navidrome URL - {typeof window !== "undefined" - ? (() => { - const config = localStorage.getItem("navidrome-config"); - if (config) { - try { - const { serverUrl } = JSON.parse(config); - if (serverUrl) { - // Remove protocol (http:// or https://) and trailing slash - const prettyUrl = serverUrl.replace(/^https?:\/\//, "").replace(/\/$/, ""); - return prettyUrl; - } - return Not set; - } catch { - return Invalid config; - } - } - return Not set; - })() - : Not available} + {!isClient ? ( + Loading... + ) : navidromeUrl ? ( + navidromeUrl + ) : ( + Not set + )}