diff --git a/packages/web/components/templates/NavigationLayout.tsx b/packages/web/components/templates/NavigationLayout.tsx new file mode 100644 index 000000000..a52290ca2 --- /dev/null +++ b/packages/web/components/templates/NavigationLayout.tsx @@ -0,0 +1,199 @@ +import { PageMetaData, PageMetaDataProps } from '../patterns/PageMetaData' +import { Box, VStack } from '../elements/LayoutPrimitives' +import { ReactNode, useEffect, useState, useCallback } from 'react' +import { useGetViewerQuery } from '../../lib/networking/queries/useGetViewerQuery' +import { navigationCommands } from '../../lib/keyboardShortcuts/navigationShortcuts' +import { useKeyboardShortcuts } from '../../lib/keyboardShortcuts/useKeyboardShortcuts' +import { NextRouter, useRouter } from 'next/router' +import { ConfirmationModal } from '../patterns/ConfirmationModal' +import { KeyboardShortcutListModal } from './KeyboardShortcutListModal' +import { setupAnalytics } from '../../lib/analytics' +import { primaryCommands } from '../../lib/keyboardShortcuts/navigationShortcuts' +import { logout } from '../../lib/logout' +import { useApplyLocalTheme } from '../../lib/hooks/useApplyLocalTheme' +import { updateTheme } from '../../lib/themeUpdater' +import { Priority, useRegisterActions } from 'kbar' +import { ThemeId, theme } from '../tokens/stitches.config' +import { NavigationMenu } from './navMenu/NavigationMenu' +import { DEFAULT_HEADER_HEIGHT } from './homeFeed/HeaderSpacer' +import { Button } from '../elements/Button' +import { List } from 'phosphor-react' +import { usePersistedState } from '../../lib/hooks/usePersistedState' + +export type NavigationSection = + | 'justread' + | 'home' + | 'library' + | 'subscriptions' + | 'highlights' + +type NavigationLayoutProps = { + children: ReactNode + section: NavigationSection + pageMetaDataProps?: PageMetaDataProps +} + +export function NavigationLayout(props: NavigationLayoutProps): JSX.Element { + useApplyLocalTheme() + + const { viewerData } = useGetViewerQuery() + const router = useRouter() + const [showLogoutConfirmation, setShowLogoutConfirmation] = useState(false) + const [showKeyboardCommandsModal, setShowKeyboardCommandsModal] = + useState(false) + const [showLeftMenu, setShowLeftMenu] = usePersistedState({ + key: 'nav-show-menu', + isSessionStorage: false, + initialValue: true, + }) + + useKeyboardShortcuts(navigationCommands(router)) + + useKeyboardShortcuts( + primaryCommands((action) => { + switch (action) { + case 'toggleShortcutHelpModalDisplay': + setShowKeyboardCommandsModal(true) + break + } + }) + ) + + useRegisterActions( + [ + { + id: 'home', + section: 'Navigation', + name: 'Go to Home (Library) ', + shortcut: ['g h'], + keywords: 'go home', + perform: () => router?.push('/home'), + }, + { + id: 'lightTheme', + section: 'Preferences', + name: 'Change theme (light) ', + shortcut: ['v', 'l'], + keywords: 'light theme', + priority: Priority.LOW, + perform: () => updateTheme(ThemeId.Light), + }, + { + id: 'darkTheme', + section: 'Preferences', + name: 'Change theme (dark) ', + shortcut: ['v', 'd'], + keywords: 'dark theme', + priority: Priority.LOW, + perform: () => updateTheme(ThemeId.Dark), + }, + ], + [router] + ) + + // Attempt to identify the user if they are logged in. + useEffect(() => { + setupAnalytics(viewerData?.me) + }, [viewerData?.me]) + + const showLogout = useCallback(() => { + setShowLogoutConfirmation(true) + }, [setShowLogoutConfirmation]) + + useEffect(() => { + document.addEventListener('logout', showLogout) + + return () => { + document.removeEventListener('logout', showLogout) + } + }, [showLogout]) + + return ( + <> + {props.pageMetaDataProps ? ( + + ) : null} + +
{ + setShowLeftMenu(!showLeftMenu) + }} + /> + {showLeftMenu && ( + {}} + searchTerm={''} + // eslint-disable-next-line @typescript-eslint/no-empty-function + applySearchQuery={(searchQuery: string) => {}} + showFilterMenu={showLeftMenu} + setShowFilterMenu={(show) => { + setShowLeftMenu(show) + }} + /> + )} + {props.children} + {showLogoutConfirmation ? ( + setShowLogoutConfirmation(false)} + /> + ) : null} + {showKeyboardCommandsModal ? ( + setShowKeyboardCommandsModal(false)} + /> + ) : null} + + + ) +} + +type HeaderProps = { + toggleMenu: () => void +} + +const Header = (props: HeaderProps): JSX.Element => { + const small = false + + return ( + + + + + + ) +} diff --git a/packages/web/components/templates/navMenu/NavigationMenu.tsx b/packages/web/components/templates/navMenu/NavigationMenu.tsx index 47df7da78..72ab6d15a 100644 --- a/packages/web/components/templates/navMenu/NavigationMenu.tsx +++ b/packages/web/components/templates/navMenu/NavigationMenu.tsx @@ -32,10 +32,13 @@ import { Dropdown, DropdownOption } from '../../elements/DropdownElements' import { useRouter } from 'next/router' import { DiscoverIcon } from '../../elements/icons/DiscoverIcon' import { escapeQuotes } from '../../../utils/helper' +import { NavigationSection } from '../NavigationLayout' export const LIBRARY_LEFT_MENU_WIDTH = '275px' type LibraryFilterMenuProps = { + section: NavigationSection + setShowAddLinkModal: (show: boolean) => void searchTerm: string | undefined @@ -206,33 +209,31 @@ const LibraryNav = (props: LibraryFilterMenuProps): JSX.Element => { } /> } /> } /> } /> - } - /> ) } @@ -731,11 +732,8 @@ type NavButtonProps = { text: string icon: ReactNode - filterTerm: string - searchTerm: string | undefined - - applySearchQuery: (searchTerm: string) => void - setShowFilterMenu: (show: boolean) => void + isSelected: boolean + section: NavigationSection } type NavButtonRedirectProps = { @@ -803,15 +801,7 @@ function NavRedirectButton(props: NavButtonRedirectProps): JSX.Element { } function NavButton(props: NavButtonProps): JSX.Element { - const isInboxFilter = (filter: string) => { - return filter === '' || filter === 'in:inbox' - } - const selected = useMemo(() => { - if (isInboxFilter(props.filterTerm) && !props.searchTerm) { - return true - } - return props.searchTerm === props.filterTerm - }, [props.searchTerm, props.filterTerm]) + const router = useRouter() return ( { - props.applySearchQuery(props.filterTerm) - props.setShowFilterMenu(false) - e.preventDefault() + router.push(`/` + props.section) }} > {props.icon} diff --git a/packages/web/pages/highlights/index.tsx b/packages/web/pages/highlights/index.tsx new file mode 100644 index 000000000..f9e38bd1d --- /dev/null +++ b/packages/web/pages/highlights/index.tsx @@ -0,0 +1,29 @@ +import { NavigationLayout } from '../../components/templates/NavigationLayout' +import { PrimaryLayout } from '../../components/templates/PrimaryLayout' +import { HomeFeedContainer } from '../../components/templates/homeFeed/HomeFeedContainer' +import { VStack } from '../../components/elements/LayoutPrimitives' + +export default function Highlights(): JSX.Element { + return ( + + +
Highlights will go here
+
+
+ ) +} diff --git a/packages/web/pages/justread/index.tsx b/packages/web/pages/justread/index.tsx index ef491bf40..c5d6c41df 100644 --- a/packages/web/pages/justread/index.tsx +++ b/packages/web/pages/justread/index.tsx @@ -30,97 +30,77 @@ import { SpanBox, VStack, } from './../../components/elements/LayoutPrimitives' -import { List, ThumbsDown, ThumbsUp } from 'phosphor-react' -import { showErrorToast, showSuccessToast } from '../../lib/toastHelpers' import { Toaster } from 'react-hot-toast' -import { DEFAULT_HEADER_HEIGHT } from '../../components/templates/homeFeed/HeaderSpacer' -import { NavigationMenu } from '../../components/templates/navMenu/NavigationMenu' +import { NavigationLayout } from '../../components/templates/NavigationLayout' export default function Home(): JSX.Element { - const [showLeftMenu, setShowLeftMenu] = useState(false) const homeData = useGetHomeItems() useApplyLocalTheme() return ( - - -
{ - setShowLeftMenu(!showLeftMenu) - }} - /> - {showLeftMenu && ( - {}} - searchTerm={''} - // eslint-disable-next-line @typescript-eslint/no-empty-function - applySearchQuery={(searchQuery: string) => {}} - showFilterMenu={showLeftMenu} - setShowFilterMenu={(show) => { - setShowLeftMenu(show) - }} - /> - )} + - {homeData.sections?.map((homeSection, idx) => { - if (homeSection.items.length < 1) { - return <> - } - switch (homeSection.layout) { - case 'just_added': - return ( - - ) - case 'top_picks': - return ( - - ) - case 'quick_links': - return ( - - ) - case 'hidden': - return ( - - ) - default: + + + {homeData.sections?.map((homeSection, idx) => { + if (homeSection.items.length < 1) { return <> - } - })} + } + switch (homeSection.layout) { + case 'just_added': + return ( + + ) + case 'top_picks': + return ( + + ) + case 'quick_links': + return ( + + ) + case 'hidden': + return ( + + ) + default: + return <> + } + })} + - + ) } @@ -753,44 +733,3 @@ const SubscriptionSourceHoverContent = ( // // ) // } - -type HeaderProps = { - toggleMenu: () => void -} - -const Header = (props: HeaderProps): JSX.Element => { - const small = false - - return ( - - - - - - ) -} diff --git a/packages/web/pages/library/index.tsx b/packages/web/pages/library/index.tsx new file mode 100644 index 000000000..7d7eb06ad --- /dev/null +++ b/packages/web/pages/library/index.tsx @@ -0,0 +1,33 @@ +import { NavigationLayout } from '../../components/templates/NavigationLayout' +import { PrimaryLayout } from '../../components/templates/PrimaryLayout' +import { HomeFeedContainer } from '../../components/templates/homeFeed/HomeFeedContainer' +import { VStack } from '../../components/elements/LayoutPrimitives' + +export default function Home(): JSX.Element { + return +} + +function LoadedContent(): JSX.Element { + return ( + + + + + + ) +} diff --git a/packages/web/pages/subscriptions/index.tsx b/packages/web/pages/subscriptions/index.tsx new file mode 100644 index 000000000..0a68a24cf --- /dev/null +++ b/packages/web/pages/subscriptions/index.tsx @@ -0,0 +1,29 @@ +import { NavigationLayout } from '../../components/templates/NavigationLayout' +import { PrimaryLayout } from '../../components/templates/PrimaryLayout' +import { HomeFeedContainer } from '../../components/templates/homeFeed/HomeFeedContainer' +import { VStack } from '../../components/elements/LayoutPrimitives' + +export default function Subscriptions(): JSX.Element { + return ( + + +
Subscriptions will go here
+
+
+ ) +}