mirror of
https://github.com/oxen-io/oxen-website.git
synced 2023-12-13 21:00:18 +01:00
Side menu logic with blog title
This commit is contained in:
parent
b1dd5b5070
commit
8bed8fa3ac
|
@ -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 (
|
||||
<div
|
||||
style={{ height: '100vh', width: '100%' }}
|
||||
|
@ -36,12 +22,7 @@ export default function Layout({ children }: Props) {
|
|||
className="flex w-full h-full"
|
||||
>
|
||||
<SideMenu />
|
||||
<div
|
||||
style={{
|
||||
marginLeft: `${marginLeft}px`,
|
||||
}}
|
||||
className="w-full py-6 overflow-y-auto duration-300 bg-alt"
|
||||
>
|
||||
<div className="w-full py-6 overflow-y-auto duration-300 bg-alt">
|
||||
{children}
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -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 (
|
||||
<>
|
||||
<div key={uuid()}>
|
||||
{item.external ? (
|
||||
link
|
||||
) : (
|
||||
<Link key={item.label} href={item.href} as={item.href}>
|
||||
<Link href={item.href} as={item.href}>
|
||||
{link}
|
||||
</Link>
|
||||
)}
|
||||
</>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
|
|
|
@ -4,6 +4,6 @@ import { DesktopHeader } from './DesktopHeader';
|
|||
import { MobileHeader } from './MobileHeader';
|
||||
|
||||
export function Header() {
|
||||
const { isDesktop } = useContext(ScreenContext);
|
||||
return <>{isDesktop ? <DesktopHeader /> : <MobileHeader />}</>;
|
||||
const { isHuge } = useContext(ScreenContext);
|
||||
return <>{isHuge ? <DesktopHeader /> : <MobileHeader />}</>;
|
||||
}
|
||||
|
|
|
@ -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 ? (
|
||||
<SideMenuFullscreen withSideBar={isTablet} />
|
||||
) : overlay ? (
|
||||
<div className="fixed inset-0">
|
||||
<SideMenuInner />
|
||||
</div>
|
||||
) : (
|
||||
<SideMenuSplit />
|
||||
);
|
||||
|
|
|
@ -40,7 +40,7 @@ export function SideMenuInner() {
|
|||
|
||||
<Contained>
|
||||
<div className="flex flex-col w-full space-y-4">
|
||||
{!isDesktop && (
|
||||
{!isHuge && (
|
||||
<div
|
||||
className={classNames(
|
||||
'flex flex-col pt-8 pb-2 font-medium uppercase font-prompt',
|
||||
|
@ -59,7 +59,7 @@ export function SideMenuInner() {
|
|||
</div>
|
||||
)}
|
||||
|
||||
<div className="flex pb-6 -mx-6 space-x-3">
|
||||
<div className="flex pb-6 space-x-3 mobile:-mx-6">
|
||||
<a
|
||||
href="https://t.me/Oxen_Community"
|
||||
target="_blank"
|
||||
|
|
|
@ -5,7 +5,11 @@ import { useDispatch, useSelector } from 'react-redux';
|
|||
import TriangleSVG from '../../assets/svgs/triangle.svg';
|
||||
import { NAVIGATION, UI } from '../../constants';
|
||||
import { ScreenContext } from '../../contexts/screen';
|
||||
import { collapseSideMenu, expandSideMenu } from '../../state/navigation';
|
||||
import {
|
||||
collapseSideMenu,
|
||||
expandSideMenu,
|
||||
PageType,
|
||||
} from '../../state/navigation';
|
||||
import { IState } from '../../state/reducers';
|
||||
|
||||
export enum SideBarMode {
|
||||
|
@ -18,13 +22,11 @@ interface Props {
|
|||
}
|
||||
|
||||
export function SideMenuSideBar({ mode }: Props) {
|
||||
const { isMobile, isTablet, isDesktop, isHuge } = useContext(ScreenContext);
|
||||
const { sideMenuExpanded: expanded, sideMenuSplit } = useSelector(
|
||||
const { isMobile, isTablet, isHuge } = useContext(ScreenContext);
|
||||
const { sideMenuExpanded: expanded, pageType, postTitle } = useSelector(
|
||||
(state: IState) => 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()}
|
||||
>
|
||||
<div>
|
||||
{isCollapsible && (
|
||||
<TriangleSVG
|
||||
onClick={() => isCollapsible && toggleSideMenu()}
|
||||
className={classNames(
|
||||
'h-4 transform outline-none duration-300 cursor-pointer',
|
||||
expanded ? 'rotate-180' : '-rotate-60',
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
{isBlog && !isCollapsible && (
|
||||
<a href="/blog">
|
||||
{(isBlog || isPost) && !isCollapsible && (
|
||||
<a href={isPost ? '/blog' : '/'}>
|
||||
<TriangleSVG
|
||||
// onClick={() => router.push('/blog', '/blog')}
|
||||
className={classNames(
|
||||
'h-4 transform outline-none duration-300 rotate-180 cursor-pointer',
|
||||
)}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 (
|
||||
<>
|
||||
|
|
|
@ -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<typeof getServerSideProps>,
|
||||
) => {
|
||||
const { posts } = props;
|
||||
|
||||
console.log('index ➡️ posts:', posts);
|
||||
|
||||
const router = useRouter();
|
||||
|
||||
useEffect(() => {
|
||||
console.log('index ➡️ router.query;:', router.query);
|
||||
}, []);
|
||||
|
||||
const Blog = ({
|
||||
posts,
|
||||
}: InferGetServerSidePropsType<typeof getServerSideProps>) => {
|
||||
return (
|
||||
<div>
|
||||
<Head>
|
||||
|
|
|
@ -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,
|
||||
});
|
||||
|
|
|
@ -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 };
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue