From 0e18e1822cb2ab90935e686bd67e647d2bc94a62 Mon Sep 17 00:00:00 2001 From: Hossein Mehrabi Date: Tue, 22 Aug 2023 17:16:05 +0330 Subject: [PATCH] feat: implement new hero compoent --- package.json | 1 + src/components/FilterTags/FilterTags.tsx | 26 +++-- src/components/Hero/Hero.tsx | 102 +++++++++++-------- src/components/Hero/index.ts | 2 +- src/components/Main/Main.tsx | 29 ++++-- src/components/NavBar/NavBar.tsx | 18 +++- src/components/NavBar/NavbarFiller.tsx | 26 +++-- src/configs/copy.configs.ts | 3 + src/containers/HomePage/HomePage.tsx | 2 +- src/index.d.ts | 8 ++ src/layouts/DefaultLayout/Default.layout.tsx | 16 ++- src/pages/index.tsx | 16 ++- src/states/navbarState/index.ts | 1 + src/states/navbarState/navbar.state.ts | 39 +++++++ 14 files changed, 208 insertions(+), 81 deletions(-) create mode 100644 src/states/navbarState/index.ts create mode 100644 src/states/navbarState/navbar.state.ts diff --git a/package.json b/package.json index e80b6f3..a5972d7 100644 --- a/package.json +++ b/package.json @@ -52,6 +52,7 @@ "react-dom": "18.2.0", "react-imgix": "^9.7.0", "react-player": "^2.12.0", + "react-use": "^17.4.0", "typescript": "5.0.4" }, "devDependencies": { diff --git a/src/components/FilterTags/FilterTags.tsx b/src/components/FilterTags/FilterTags.tsx index fc7e44f..a4ff18e 100644 --- a/src/components/FilterTags/FilterTags.tsx +++ b/src/components/FilterTags/FilterTags.tsx @@ -1,22 +1,23 @@ -import { Tag } from '@acid-info/lsd-react' -import styled from '@emotion/styled' import { nope } from '@/utils/general.utils' +import { Tag, TagProps } from '@acid-info/lsd-react' +import styled from '@emotion/styled' type FilterTagsProps = { tags: string[] selectedTags: string[] + size?: TagProps['size'] onTagClick?: (tag: string) => void } export default function FilterTags(props: FilterTagsProps) { - const { tags = [], onTagClick = nope, selectedTags } = props + const { size = 'small', tags = [], onTagClick = nope, selectedTags } = props return ( {tags.map((tag, index) => ( onTagClick(tag)} @@ -39,6 +40,7 @@ const Tags = styled.div` gap: 8px; overflow-x: auto; padding-right: 14px; + flex-wrap: wrap; min-height: 24px; @@ -55,13 +57,17 @@ const Tags = styled.div` > * { white-space: nowrap; + overflow: hidden; + max-width: 200px; + + span { + width: 100%; + overflow: hidden; + text-overflow: ellipsis; + } } - @media (max-width: 768px) { - > *:first-child { - margin-left: 16px; - } - - padding-right: 16px; + @media (max-width: ${(props) => props.theme.breakpoints.md.width}px) { + justify-content: center; } ` diff --git a/src/components/Hero/Hero.tsx b/src/components/Hero/Hero.tsx index 988108d..91b0434 100644 --- a/src/components/Hero/Hero.tsx +++ b/src/components/Hero/Hero.tsx @@ -1,67 +1,83 @@ import { NavbarFiller } from '@/components/NavBar/NavbarFiller' import { Typography } from '@acid-info/lsd-react' import styled from '@emotion/styled' +import { useEffect, useRef } from 'react' +import { useWindowScroll } from 'react-use' +import { uiConfigs } from '../../configs/ui.configs' +import { useNavbarState } from '../../states/navbarState' + +export type HeroProps = Partial> & { + tags?: string[] +} + +export const Hero: React.FC = ({ tags = [], ...props }) => { + const ref = useRef(null) + const scroll = useWindowScroll() + const navbarState = useNavbarState() + + useEffect(() => { + const el = ref.current + if (!el) return + + const rect = el.getBoundingClientRect() + if (rect.bottom - uiConfigs.navbarRenderedHeight > 0) { + navbarState.showTitle.get() && navbarState.setShowTitle(false) + } else { + !navbarState.showTitle.get() && navbarState.setShowTitle(true) + } + }, [scroll.y, navbarState]) -export default function Hero() { return ( - - - - <span>LOGOS</span> - <span> → </span> - <span>PRESS ENGINE</span> - - - Blog with media written by Logos members - - - + + + <span>LOGOS</span> + <span> → </span> + <span ref={ref}>PRESS ENGINE</span> + + + Your Guide to Network States and the technology driving Sovereign + Communities + + ) } const Container = styled.div` - border-bottom: 1px solid rgb(var(--lsd-theme-primary)); - @media (max-width: 768px) { - .desktop { - display: none; - } - h1 { - min-height: 32px; - } - } - @media (min-width: 768px) { - h1 { - min-height: 98px; - } - } -` - -const HeroText = styled.div` display: flex; flex-direction: column; + gap: 8px 0; align-items: center; - padding: 16px 16px 8px 16px; - @media (max-width: 768px) { - gap: 6px; + padding: 24px 16px 40px 16px; + border-bottom: 1px solid rgb(var(--lsd-border-primary)); + + .navbar__filter { + margin-top: 24px; + } + + @media (max-width: ${(props) => props.theme.breakpoints.md.width}px) { + padding: 8px 16px 16px; } ` const Title = styled(Typography)` - @media (min-width: 1024px) { - font-size: var(--lsd-display1-fontSize); - line-height: var(--lsd-display1-lineHeight); - } - @media (max-width: 768px) { - font-size: var(--lsd-h4-fontSize); - line-height: var(--lsd-h4-lineHeight); + text-align: center; + + @media (max-width: ${(props) => props.theme.breakpoints.md.width}px) { + font-size: var(--lsd-h4-fontSize) !important; + font-weight: var(--lsd-h4-fontWeight) !important; + line-height: var(--lsd-h4-lineHeight) !important; } ` const Description = styled(Typography)` - @media (max-width: 768px) { - font-size: 12px; - line-height: 16px; + text-align: center; + max-width: 407px; + + @media (max-width: ${(props) => props.theme.breakpoints.md.width}px) { + font-size: 12px !important; + font-weight: 400 !important; + line-height: 16px !important; } ` diff --git a/src/components/Hero/index.ts b/src/components/Hero/index.ts index a3465b7..7b8bc32 100644 --- a/src/components/Hero/index.ts +++ b/src/components/Hero/index.ts @@ -1 +1 @@ -export { default as Hero } from './Hero' +export * from './Hero' diff --git a/src/components/Main/Main.tsx b/src/components/Main/Main.tsx index 5af0e35..fd4a210 100644 --- a/src/components/Main/Main.tsx +++ b/src/components/Main/Main.tsx @@ -1,13 +1,25 @@ -import styled from '@emotion/styled' import { uiConfigs } from '@/configs/ui.configs' -import { PropsWithChildren } from 'react' +import styled from '@emotion/styled' -const Main = ({ children, ...props }: PropsWithChildren) => { - return {children} +export type MainProps = Partial> & {} + +export const Main = ({ + spacing = 'default', + children, + ...props +}: MainProps) => { + return ( + + {children} + + ) } -const Container = styled.main` - margin-top: ${uiConfigs.postSectionMargin}px; +const Container = styled.main<{ + spacing: 'default' | false +}>` + margin-top: ${({ spacing }) => + spacing ? uiConfigs.postSectionMargin : uiConfigs.navbarRenderedHeight}px; margin-left: auto; margin-right: auto; @@ -16,7 +28,10 @@ const Container = styled.main` } @media (max-width: 768px) { - margin-top: ${uiConfigs.postSectionMobileMargin}px; + margin-top: ${({ spacing }) => + spacing + ? uiConfigs.postSectionMobileMargin + : uiConfigs.navbarRenderedHeight}px; } ` diff --git a/src/components/NavBar/NavBar.tsx b/src/components/NavBar/NavBar.tsx index 17bc546..7b6a3ba 100644 --- a/src/components/NavBar/NavBar.tsx +++ b/src/components/NavBar/NavBar.tsx @@ -9,14 +9,18 @@ import { IconButton, MenuIcon, Typography } from '@acid-info/lsd-react' import styled from '@emotion/styled' import Link from 'next/link' import { useRouter } from 'next/router' -import { useState } from 'react' +import { useEffect, useState } from 'react' +import { NavbarState, useNavbarState } from '../../states/navbarState' import { LogosIcon } from '../Icons/LogosIcon' export interface NavBarProps { - showLogoType?: boolean + defaultState?: Partial } -export default function NavBar({ showLogoType = true }: NavBarProps) { +export default function NavBar({ + defaultState = { showTitle: true }, +}: NavBarProps) { + const state = useNavbarState(defaultState) const themeState = useThemeState() const { pathname } = useRouter() const isSearchPage = pathname === '/search' @@ -32,14 +36,18 @@ export default function NavBar({ showLogoType = true }: NavBarProps) { setShowMobileMenu(!showMobileMenu) } + useEffect(() => { + defaultState && state.state.set((value) => ({ ...value, ...defaultState })) + }, [defaultState]) + return ( - {showLogoType && ( + {state.showTitle.get() && ( - Press Engine + {state.title.get()} )} diff --git a/src/components/NavBar/NavbarFiller.tsx b/src/components/NavBar/NavbarFiller.tsx index 9cdee18..6f5433b 100644 --- a/src/components/NavBar/NavbarFiller.tsx +++ b/src/components/NavBar/NavbarFiller.tsx @@ -1,19 +1,32 @@ -import styled from '@emotion/styled' import { FilterTags } from '@/components/FilterTags' -import { useSearchBarContext } from '@/context/searchbar.context' +import styled from '@emotion/styled' import { useRouter } from 'next/router' +import React from 'react' -export const NavbarFiller = () => { +export type NavbarFilter = Partial< + React.ComponentProps +> & { + tags?: string[] +} + +export const NavbarFiller: React.FC = ({ + tags = [], + ...props +}) => { const router = useRouter() - const { tags } = useSearchBarContext() const onTagClick = (tag: string) => { router.push(`/search?topics=${tag}`) } return ( - - + + ) } @@ -24,7 +37,6 @@ export const NavbarFillerContainer = styled.div` text-align: center; display: flex; justify-content: center; - margin-block: 24px; @media (max-width: 768px) { margin-block: 16px; diff --git a/src/configs/copy.configs.ts b/src/configs/copy.configs.ts index 800814b..bf5c916 100644 --- a/src/configs/copy.configs.ts +++ b/src/configs/copy.configs.ts @@ -1,4 +1,7 @@ export const copyConfigs = { + navbar: { + title: 'Press Engine', + }, search: { searchbarPlaceholders: { global: () => 'Search through the LPE posts...', diff --git a/src/containers/HomePage/HomePage.tsx b/src/containers/HomePage/HomePage.tsx index 69f799e..7485453 100644 --- a/src/containers/HomePage/HomePage.tsx +++ b/src/containers/HomePage/HomePage.tsx @@ -34,7 +34,7 @@ export const HomePage: React.FC = ({ return ( - + = NextPage & { + getLayout?: (page: React.ReactNode) => any + } +} diff --git a/src/layouts/DefaultLayout/Default.layout.tsx b/src/layouts/DefaultLayout/Default.layout.tsx index de1e9e1..172c11d 100644 --- a/src/layouts/DefaultLayout/Default.layout.tsx +++ b/src/layouts/DefaultLayout/Default.layout.tsx @@ -1,19 +1,25 @@ import { Footer } from '@/components/Footer' import { Main } from '@/components/Main' -import { PropsWithChildren } from 'react' -import { AppBar } from '../../components/NavBar' import { NavBarProps } from '@/components/NavBar/NavBar' +import { PropsWithChildren } from 'react' +import { MainProps } from '../../components/Main/Main' +import { AppBar } from '../../components/NavBar' interface Props { navbarProps?: NavBarProps + mainProps?: Partial } export default function DefaultLayout(props: PropsWithChildren) { - const { navbarProps = {} } = props + const { mainProps = {}, navbarProps = {} } = props + return ( <> - -
{props.children}
+ +
{props.children}