Skip to content

Commit

Permalink
feat: preserve sidebar state across route changes for global music pl…
Browse files Browse the repository at this point in the history
…ayer
  • Loading branch information
nounspaceryan committed Jul 15, 2024
1 parent d6f65b1 commit c0e8723
Show file tree
Hide file tree
Showing 7 changed files with 93 additions and 67 deletions.
19 changes: 6 additions & 13 deletions src/common/components/organisms/Navigation.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import React, { useCallback, useEffect, useMemo, useState } from "react";
import { useRouter } from "next/router";
import { mergeClasses } from "@/common/lib/utils/mergeClasses";
import BrandHeader from "../molecules/BrandHeader";
import Player from "@/common/components/organisms/Player";
Expand All @@ -15,6 +16,7 @@ import { Button } from "../atoms/button";
import { FaPaintbrush, FaDiscord } from "react-icons/fa6";
import { NOUNISH_LOWFI_URL } from "@/constants/nounishLowfi";
import { UserTheme } from "@/common/lib/theme";
import { useUserTheme } from "@/common/lib/theme/UserThemeProvider";
import {
AnalyticsEvent,
analytics,
Expand All @@ -33,21 +35,17 @@ type NavItemProps = {
type NavProps = {
isEditable: boolean;
enterEditMode: () => void;
theme?: UserTheme;
};

const Navigation: React.FC<NavProps> = ({
isEditable,
enterEditMode,
theme: userTheme,
}) => {
const Navigation: React.FC<NavProps> = ({ isEditable, enterEditMode }) => {
const { setModalOpen, getIsLoggedIn, getIsInitializing } = useAppStore(
(state) => ({
setModalOpen: state.setup.setModalOpen,
getIsLoggedIn: state.getIsAccountReady,
getIsInitializing: state.getIsInitializing,
}),
);
const userTheme: UserTheme = useUserTheme();
const logout = useLogout();

function turnOnEditMode() {
Expand Down Expand Up @@ -79,12 +77,7 @@ const Navigation: React.FC<NavProps> = ({
[user],
);

const [currentUrl, setCurrentUrl] = useState("");

useEffect(() => {
// Get the current URL
setCurrentUrl(window.location.pathname);
}, []);
const router = useRouter();

const NavItem: React.FC<NavItemProps> = ({
label,
Expand All @@ -100,7 +93,7 @@ const Navigation: React.FC<NavProps> = ({
href={disable ? "#" : href}
className={mergeClasses(
"flex items-center p-2 text-gray-900 rounded-lg dark:text-white hover:bg-gray-100 dark:hover:bg-gray-700 group w-full",
href === currentUrl ? "bg-gray-100" : "",
href === router.asPath ? "bg-gray-100" : "",
)}
onClick={onClick}
rel={openInNewTab ? "noopener noreferrer" : undefined}
Expand Down
72 changes: 56 additions & 16 deletions src/common/components/organisms/Sidebar.tsx
Original file line number Diff line number Diff line change
@@ -1,30 +1,70 @@
import React from "react";
import React, {
createContext,
useContext,
useState,
useRef,
useMemo,
} from "react";
import Navigation from "./Navigation";
import { UserTheme } from "@/common/lib/theme";

export interface SidebarProps {
export interface SidebarProps {}

export type SidebarContextProviderProps = { children: React.ReactNode };

export type SidebarContextValue = {
editMode: boolean;
enterEditMode: () => void;
theme?: UserTheme;
isEditable: boolean;
setEditMode: (value: boolean) => void;
sidebarEditable: boolean;
setSidebarEditable: (value: boolean) => void;
portalRef: React.RefObject<HTMLDivElement>;
}

export const Sidebar: React.FC<SidebarProps> = ({
editMode,
enterEditMode,
isEditable,
portalRef,
theme,
};

export const SidebarContext = createContext<SidebarContextValue>(
{} as SidebarContextValue,
);

export const SidebarContextProvider: React.FC<SidebarContextProviderProps> = ({
children,
}) => {
const [editMode, setEditMode] = useState(false);
const [sidebarEditable, setSidebarEditable] = useState(false);
const portalRef = useRef<HTMLDivElement>(null);

const value = useMemo(
() => ({
editMode,
setEditMode,
sidebarEditable,
setSidebarEditable,
portalRef,
}),
[editMode, sidebarEditable, portalRef],
);

return (
<SidebarContext.Provider value={value}>{children}</SidebarContext.Provider>
);
};

export const useSidebarContext = (): SidebarContextValue => {
return useContext(SidebarContext);
};

export const Sidebar: React.FC<SidebarProps> = () => {
const { editMode, setEditMode, sidebarEditable, portalRef } =
useSidebarContext();

function enterEditMode() {
setEditMode(true);
}

return (
<>
<div ref={portalRef} className={editMode ? "w-full" : ""}></div>
<div className={editMode ? "hidden" : "flex mx-auto"}>
<Navigation
isEditable={isEditable}
isEditable={sidebarEditable}
enterEditMode={enterEditMode}
theme={theme}
/>
</div>
</>
Expand Down
31 changes: 7 additions & 24 deletions src/common/components/pages/SpacePage.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import React, { ReactNode, useRef, useState } from "react";
import Sidebar from "../organisms/Sidebar";
import React, { ReactNode } from "react";
import Space, { SpaceConfig, SpaceConfigSaveDetails } from "../templates/Space";
import { isUndefined } from "lodash";
import SpaceLoading from "../templates/SpaceLoading";
import SpaceLoading from "@/common/components/templates/SpaceLoading";
import { useSidebarContext } from "@/common/components/organisms/Sidebar";

type SpacePageArgs = {
config?: SpaceConfig;
Expand All @@ -21,28 +21,11 @@ export default function SpacePage({
profile,
loading,
}: SpacePageArgs) {
const [editMode, setEditMode] = useState(false);
const [sidebarEditable, setSidebarEditable] = useState(false);
const portalRef = useRef<HTMLDivElement>(null);

function enterEditMode() {
setEditMode(true);
}
const { editMode, setEditMode, setSidebarEditable, portalRef } =
useSidebarContext();

return (
<div
className="flex w-full h-full"
style={{ background: "var(--user-theme-background)" }}
>
<div className="flex mx-auto transition-all duration-100 ease-out z-10">
<Sidebar
editMode={editMode}
enterEditMode={enterEditMode}
isEditable={sidebarEditable}
portalRef={portalRef}
theme={config?.theme}
/>
</div>
<>
{isUndefined(config) ||
isUndefined(saveConfig) ||
isUndefined(commitConfig) ||
Expand All @@ -62,6 +45,6 @@ export default function SpacePage({
portalRef={portalRef}
/>
)}
</div>
</>
);
}
5 changes: 4 additions & 1 deletion src/common/providers/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import UserThemeProvider from "@/common/lib/theme/UserThemeProvider";
import LoggedInStateProvider from "./LoggedInStateProvider";
import AnalyticsProvider from "./AnalyticsProvider";
import VersionCheckProivder from "./VersionCheckProvider";
import { SidebarContextProvider } from "@/common/components/organisms/Sidebar";

export default function Providers({ children }: { children: React.ReactNode }) {
return (
Expand All @@ -22,7 +23,9 @@ export default function Providers({ children }: { children: React.ReactNode }) {
<UserThemeProvider>
<AuthenticatorProvider>
<LoggedInStateProvider>
<AnalyticsProvider>{children}</AnalyticsProvider>
<SidebarContextProvider>
<AnalyticsProvider>{children}</AnalyticsProvider>
</SidebarContextProvider>
</LoggedInStateProvider>
</AuthenticatorProvider>
</UserThemeProvider>
Expand Down
21 changes: 20 additions & 1 deletion src/pages/_app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import type { AppProps } from "next/app";
import type { NextPage } from "next";
import Head from "next/head";
import Providers from "@/common/providers";
import Sidebar from "@/common/components/organisms/Sidebar";

export type NextPageWithLayout<P = any, IP = P> = NextPage<P, IP> & {
getLayout?: (page: React.ReactElement) => React.ReactNode;
Expand All @@ -14,9 +15,27 @@ type AppPropsWithLayout = AppProps & {
Component: NextPageWithLayout;
};

const sidebarLayout = (page: React.ReactElement) => {
return (
<>
<div className="min-h-screen max-w-screen h-screen w-screen">
<div
className="flex w-full h-full"
style={{ background: "var(--user-theme-background)" }}
>
<div className="flex mx-auto transition-all duration-100 ease-out z-10">
<Sidebar />
</div>
{page}
</div>
</div>
</>
);
};

export default function MyApp({ Component, pageProps }: AppPropsWithLayout) {
// Use the layout defined at the page level, if available
const getLayout = Component.getLayout ?? ((page) => page);
const getLayout = Component.getLayout ?? sidebarLayout;

return (
<>
Expand Down
6 changes: 0 additions & 6 deletions src/pages/homebase/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -57,10 +57,4 @@ const Homebase: NextPageWithLayout = () => {
return <SpacePage {...args} />;
};

Homebase.getLayout = function getLayout(page: React.ReactElement) {
return (
<div className="min-h-screen max-w-screen h-screen w-screen">{page}</div>
);
};

export default Homebase;
6 changes: 0 additions & 6 deletions src/pages/s/[handle].tsx
Original file line number Diff line number Diff line change
Expand Up @@ -94,10 +94,4 @@ const UserPrimarySpace: NextPageWithLayout = ({
return <SpaceNotFound />;
};

UserPrimarySpace.getLayout = (page: React.ReactElement) => {
return (
<div className="min-h-screen max-w-screen h-screen w-screen">{page}</div>
);
};

export default UserPrimarySpace;

0 comments on commit c0e8723

Please sign in to comment.