From 8bed8fa3ac2f310125915138ce4971887c0ce278 Mon Sep 17 00:00:00 2001 From: Vince Date: Tue, 9 Feb 2021 15:31:56 +1100 Subject: [PATCH] Side menu logic with blog title --- components/layout/index.tsx | 23 ++------------------ components/navigation/DesktopHeader.tsx | 7 +++--- components/navigation/Header.tsx | 4 ++-- components/navigation/SideMenu.tsx | 17 +++++++++------ components/navigation/SideMenuInner.tsx | 4 ++-- components/navigation/SideMenuSideBar.tsx | 25 ++++++++++++---------- constants/navigation.ts | 8 ++----- pages/_app.tsx | 26 ++++++++++++++++------- pages/blog/[slug].tsx | 23 +++++++++++--------- pages/blog/index.tsx | 19 ++++------------- state/navigation.ts | 9 ++++++++ state/reducers/navigation.ts | 3 +++ 12 files changed, 83 insertions(+), 85 deletions(-) diff --git a/components/layout/index.tsx b/components/layout/index.tsx index 449b777..92b56e0 100644 --- a/components/layout/index.tsx +++ b/components/layout/index.tsx @@ -1,9 +1,5 @@ -import React, { ReactNode, useContext } from 'react'; -import { useSelector } from 'react-redux'; +import React, { ReactNode } from 'react'; import { UI } from '../../constants'; -import { ScreenContext } from '../../contexts/screen'; -import { PageType } from '../../state/navigation'; -import { IState } from '../../state/reducers'; import { Header } from '../navigation/Header'; import { SideMenu } from '../navigation/SideMenu'; @@ -12,16 +8,6 @@ interface Props { } export default function Layout({ children }: Props) { - const { isTablet, isDesktop } = useContext(ScreenContext); - const { pageType, sideMenuExpanded } = useSelector( - (state: IState) => state.navigation, - ); - - const marginLeft = - (pageType !== PageType.NORMAL && isDesktop) || isTablet - ? UI.SIDE_MENU_SIDE_BAR_WIDTH_PX - : 0; - return (
-
+
{children}
diff --git a/components/navigation/DesktopHeader.tsx b/components/navigation/DesktopHeader.tsx index 3e3b5b1..80ddf23 100644 --- a/components/navigation/DesktopHeader.tsx +++ b/components/navigation/DesktopHeader.tsx @@ -1,6 +1,7 @@ import classNames from 'classnames'; import Link from 'next/link'; import React, { useRef } from 'react'; +import { v4 as uuid } from 'uuid'; import OxenLogoSVG from '../../assets/svgs/brand.svg'; import { NAVIGATION, UI } from '../../constants'; @@ -45,15 +46,15 @@ export function DesktopHeader() { ); return ( - <> +
{item.external ? ( link ) : ( - + {link} )} - +
); })}
diff --git a/components/navigation/Header.tsx b/components/navigation/Header.tsx index c5f593b..03b8a71 100644 --- a/components/navigation/Header.tsx +++ b/components/navigation/Header.tsx @@ -4,6 +4,6 @@ import { DesktopHeader } from './DesktopHeader'; import { MobileHeader } from './MobileHeader'; export function Header() { - const { isDesktop } = useContext(ScreenContext); - return <>{isDesktop ? : }; + const { isHuge } = useContext(ScreenContext); + return <>{isHuge ? : }; } diff --git a/components/navigation/SideMenu.tsx b/components/navigation/SideMenu.tsx index 9e394b5..f62acf3 100644 --- a/components/navigation/SideMenu.tsx +++ b/components/navigation/SideMenu.tsx @@ -1,7 +1,9 @@ import React, { useContext } from 'react'; +import { useSelector } from 'react-redux'; import { ScreenContext } from '../../contexts/screen'; +import { PageType } from '../../state/navigation'; +import { IState } from '../../state/reducers'; import { SideMenuFullscreen } from './SideMenuFullscreen'; -import { SideMenuInner } from './SideMenuInner'; import { SideMenuSplit } from './SideMenuSplit'; export interface ISideMenuItem { @@ -12,7 +14,9 @@ export interface ISideMenuItem { export function SideMenu() { const { isMobile, isTablet } = useContext(ScreenContext); - const overlay = false; + const { sideMenuExpanded: expanded, pageType, postTitle } = useSelector( + (state: IState) => state.navigation, + ); // ON MOBILE: overlay with no sidebar // ON TABLET: overlay with sidebar @@ -23,12 +27,11 @@ export function SideMenu() { // Split screen overlay with sidebar: ONLY ON DESKTOP && /blog // Just sidebar: /blog - return isMobile || isTablet ? ( + const isBlog = pageType === PageType.BLOG; + const isPost = pageType === PageType.POST; + + return (isMobile || isTablet) && !isBlog && !isPost ? ( - ) : overlay ? ( -
- -
) : ( ); diff --git a/components/navigation/SideMenuInner.tsx b/components/navigation/SideMenuInner.tsx index 58213fa..2728b36 100644 --- a/components/navigation/SideMenuInner.tsx +++ b/components/navigation/SideMenuInner.tsx @@ -40,7 +40,7 @@ export function SideMenuInner() {
- {!isDesktop && ( + {!isHuge && (
)} -
+
state.navigation, ); - const isCollapsible = isTablet || isMobile; - const router = useRouter(); const dispatch = useDispatch(); @@ -32,8 +34,10 @@ export function SideMenuSideBar({ mode }: Props) { item => item.href === router.asPath, )?.label; - const isBlog = !sideMenuSplit; - const label = isBlog ? 'Blog' : selectedSideMenuItem; + const isBlog = pageType === PageType.BLOG; + const isPost = pageType === PageType.POST; + const label = isPost ? postTitle : isBlog ? 'Blog' : selectedSideMenuItem; + const isCollapsible = (isTablet || isMobile) && !isPost && !isBlog; const toggleSideMenu = () => dispatch(expanded ? collapseSideMenu() : expandSideMenu()); @@ -49,21 +53,20 @@ export function SideMenuSideBar({ mode }: Props) { mode === SideBarMode.LABEL && 'border-r border-b', mode === SideBarMode.MENU && !expanded && 'border-r', )} - onClick={() => isCollapsible && toggleSideMenu()} >
{isCollapsible && ( isCollapsible && toggleSideMenu()} className={classNames( 'h-4 transform outline-none duration-300 cursor-pointer', expanded ? 'rotate-180' : '-rotate-60', )} /> )} - {isBlog && !isCollapsible && ( - + {(isBlog || isPost) && !isCollapsible && ( + router.push('/blog', '/blog')} className={classNames( 'h-4 transform outline-none duration-300 rotate-180 cursor-pointer', )} diff --git a/constants/navigation.ts b/constants/navigation.ts index 45e7a6a..6292edd 100644 --- a/constants/navigation.ts +++ b/constants/navigation.ts @@ -98,15 +98,11 @@ const SIDE_MENU_ITEMS = { }, } as { [name: string]: ISideMenuItem }; -// Pages in which the sidebar breaks out of the split view -const SIDEBAR_OVERLAY_PAGES = ['blog']; - const NAVIGATION = { MENU_ITEMS, SIDE_MENU_ITEMS, - OVERLAY_PAGE_REGEX: new RegExp( - `^/(${SIDEBAR_OVERLAY_PAGES.map(i => `(${i})`).join('|')})[/]?`, - ), + BLOG_REGEX: /^\/(blog)[/]?$/, + POST_REGEX: /^\/(blog\/\[slug\])[/]?$/, }; export default NAVIGATION; diff --git a/pages/_app.tsx b/pages/_app.tsx index b3686fa..8ad536f 100644 --- a/pages/_app.tsx +++ b/pages/_app.tsx @@ -11,7 +11,8 @@ import ScreenProvider from '../contexts/screen'; import { CmsApi } from '../services/cms'; import { collapseSideMenu, - setSideMenuSplit, + PageType, + setPageType, setSplitPagesContent, } from '../state/navigation'; import { rootReducer } from '../state/reducers'; @@ -24,14 +25,20 @@ function App({ Component, pageProps }: AppProps) { const handleLocationChange = url => { // Break out of split view - const split = !NAVIGATION.OVERLAY_PAGE_REGEX.test(url); + const onBlog = NAVIGATION.BLOG_REGEX.test(url); + const onPost = NAVIGATION.POST_REGEX.test(url); - console.log( - '_app ➡️ NAVIGATION.OVERLAY_PAGE_REGEX.test(url);:', - NAVIGATION.OVERLAY_PAGE_REGEX.test(url), - ); + console.log('_app ➡️ url:', url); + console.log('_app ➡️ onBlog:', onBlog); + console.log('_app ➡️ NAVIGATION.BLOG_REGEX:', NAVIGATION.BLOG_REGEX); - store.dispatch(setSideMenuSplit(split)); + const pageType = onBlog + ? PageType.BLOG + : onPost + ? PageType.POST + : PageType.NORMAL; + + store.dispatch(setPageType(pageType)); store.dispatch(collapseSideMenu()); }; @@ -41,7 +48,10 @@ function App({ Component, pageProps }: AppProps) { store.dispatch(collapseSideMenu()); handleLocationChange(router.pathname); - console.log('NAVIGATION.OVERLAY_PAGE_REGEX', NAVIGATION.OVERLAY_PAGE_REGEX); + console.log( + '_app ➡️ store.getState().navigation.pageType:', + store.getState().navigation.pageType, + ); }, []); // Close side menu on page changed diff --git a/pages/blog/[slug].tsx b/pages/blog/[slug].tsx index 43209f8..ba27628 100644 --- a/pages/blog/[slug].tsx +++ b/pages/blog/[slug].tsx @@ -1,12 +1,15 @@ // [slug].js import Head from 'next/head'; import React, { useEffect } from 'react'; +import { useDispatch, useSelector } from 'react-redux'; import { Article } from '../../components/article/Article'; import { CmsApi } from '../../services/cms'; +import { setPostTitle } from '../../state/navigation'; +import { IState } from '../../state/reducers'; import { IPost } from '../../types/cms'; import { generateTitle } from '../../utils/metadata'; -export async function getStaticProps({ params }) { +export async function getServerSideProps({ params }) { const api = new CmsApi(); const post = await api.fetchBlogBySlug(String(params.slug) ?? ''); @@ -17,18 +20,18 @@ export async function getStaticProps({ params }) { }; } - return { props: post, revalidate: 60 }; + return { props: { post } }; } -function Post(post: IPost) { - // Scroll to top on load - useEffect(() => { - if (typeof window !== 'undefined') { - window.scrollTo(0, 0); - } - }, []); +function Post({ post }: { post: IPost }) { + const { pageType, postTitle } = useSelector( + (state: IState) => state.navigation, + ); + const dispatch = useDispatch(); - console.log('[slug] ➡️ posts:', post); + useEffect(() => { + dispatch(setPostTitle(postTitle)); + }, []); return ( <> diff --git a/pages/blog/index.tsx b/pages/blog/index.tsx index 4a68fa0..f79c65e 100644 --- a/pages/blog/index.tsx +++ b/pages/blog/index.tsx @@ -1,7 +1,6 @@ import { InferGetServerSidePropsType } from 'next'; import Head from 'next/head'; -import { useRouter } from 'next/router'; -import React, { useEffect } from 'react'; +import React from 'react'; import { ArticleCard } from '../../components/cards/ArticleCard'; import { ArticleCardFeature } from '../../components/cards/ArticleCardFeature'; import { CardGrid } from '../../components/cards/CardGrid'; @@ -17,19 +16,9 @@ export async function getServerSideProps(context) { return { props: { posts } }; } -const Blog = ( - props: InferGetServerSidePropsType, -) => { - const { posts } = props; - - console.log('index ➡️ posts:', posts); - - const router = useRouter(); - - useEffect(() => { - console.log('index ➡️ router.query;:', router.query); - }, []); - +const Blog = ({ + posts, +}: InferGetServerSidePropsType) => { return (
diff --git a/state/navigation.ts b/state/navigation.ts index e1aabe9..8741d9d 100644 --- a/state/navigation.ts +++ b/state/navigation.ts @@ -19,6 +19,7 @@ export interface INavigation { headerCollapsed: boolean; sideMenuExpanded: boolean; pageType: PageType; + postTitle?: string; pages?: TPages; } @@ -32,6 +33,7 @@ export const initialNavigationState: INavigation = { // Side menu expanded only toggles for mobile. // On desktop it's always open (if it fits). pageType: PageType.NORMAL, + postTitle: undefined, headerCollapsed: true, sideMenuExpanded: false, }; @@ -39,6 +41,7 @@ export const initialNavigationState: INavigation = { export enum NavigationActions { SET_HEADER_COLLAPSED = 'SET_HEADER_COLLAPSED', SET_PAGE_TYPE = 'SET_PAGE_TYPE', + SET_POST_TITLE = 'SET_POST_TITLE', EXPAND_SIDE_MENU = 'EXPAND_SIDE_MENU', COLLAPSE_SIDE_MENU = 'COLLAPSE_SIDE_MENU', SET_SPLIT_PAGES_CONTENT = 'SET_SPLIT_PAGES_CONTENT', @@ -57,6 +60,12 @@ export const setPageType = (type: PageType) => ({ payload: type, }); +// For sidebar title +export const setPostTitle = (title: string) => ({ + type: NavigationActions.SET_POST_TITLE, + payload: title, +}); + export const expandSideMenu = () => ({ type: NavigationActions.EXPAND_SIDE_MENU, }); diff --git a/state/reducers/navigation.ts b/state/reducers/navigation.ts index cad50ad..f101018 100644 --- a/state/reducers/navigation.ts +++ b/state/reducers/navigation.ts @@ -20,6 +20,9 @@ export const navigationReducer = ( case NavigationActions.SET_PAGE_TYPE: { return { ...state, pageType: action.payload }; } + case NavigationActions.SET_POST_TITLE: { + return { ...state, postTitle: action.payload }; + } case NavigationActions.EXPAND_SIDE_MENU: { return { ...state, sideMenuExpanded: true }; }