mirror of
https://github.com/acid-info/logos-press-engine.git
synced 2025-02-23 14:48:08 +00:00
last detailing
This commit is contained in:
parent
4d27bc6a96
commit
3eea66a23b
@ -12,19 +12,19 @@ import { useScrollDirection } from '@/utils/ui.utils'
|
|||||||
import { useRouter } from 'next/router'
|
import { useRouter } from 'next/router'
|
||||||
import { useSearchBarContext } from '@/context/searchbar.context'
|
import { useSearchBarContext } from '@/context/searchbar.context'
|
||||||
|
|
||||||
interface NavbarProps {
|
interface AppBarProps {
|
||||||
isDark: boolean
|
isDark: boolean
|
||||||
toggle: () => void
|
toggle: () => void
|
||||||
onSearch?: (query: string, tags: string[]) => void
|
onSearch?: (query: string, tags: string[]) => void
|
||||||
onReset?: () => void
|
onReset?: () => void
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function Navbar({
|
export default function AppBar({
|
||||||
isDark,
|
isDark,
|
||||||
toggle,
|
toggle,
|
||||||
onReset,
|
onReset,
|
||||||
onSearch,
|
onSearch,
|
||||||
}: NavbarProps) {
|
}: AppBarProps) {
|
||||||
const { resultsNumber } = useSearchBarContext()
|
const { resultsNumber } = useSearchBarContext()
|
||||||
const { pathname } = useRouter()
|
const { pathname } = useRouter()
|
||||||
const isSearchPage = pathname === '/search'
|
const isSearchPage = pathname === '/search'
|
||||||
@ -52,7 +52,7 @@ export default function Navbar({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Container className={`${hide ? 'hide' : ''} ${className}`}>
|
<Container className={`${hide ? 'hide' : ''} ${className}`}>
|
||||||
<AppBar>
|
<NavBar>
|
||||||
<LogosIconContainer href={'/'}>
|
<LogosIconContainer href={'/'}>
|
||||||
<LogosIcon color="primary" />
|
<LogosIcon color="primary" />
|
||||||
</LogosIconContainer>
|
</LogosIconContainer>
|
||||||
@ -69,10 +69,10 @@ export default function Navbar({
|
|||||||
size="small"
|
size="small"
|
||||||
onClick={() => onSearchIconClick()}
|
onClick={() => onSearchIconClick()}
|
||||||
>
|
>
|
||||||
<SearchIcon />
|
<SearchIcon color="primary" />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
</Icons>
|
</Icons>
|
||||||
</AppBar>
|
</NavBar>
|
||||||
<MobileSearchContainer
|
<MobileSearchContainer
|
||||||
className={`searchBar ${hideSearch ? 'hide' : ''}`}
|
className={`searchBar ${hideSearch ? 'hide' : ''}`}
|
||||||
>
|
>
|
||||||
@ -92,8 +92,8 @@ const Container = styled.div`
|
|||||||
transition: top 0.2s;
|
transition: top 0.2s;
|
||||||
position: fixed;
|
position: fixed;
|
||||||
top: 0;
|
top: 0;
|
||||||
left: 0;
|
|
||||||
z-index: 101;
|
z-index: 101;
|
||||||
|
left: calc(calc(100% - ${uiConfigs.maxContainerWidth}px) / 2);
|
||||||
|
|
||||||
&._page {
|
&._page {
|
||||||
@media (min-width: 768px) {
|
@media (min-width: 768px) {
|
||||||
@ -110,7 +110,14 @@ const Container = styled.div`
|
|||||||
&.search_page {
|
&.search_page {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@media (max-width: ${uiConfigs.maxContainerWidth}px) {
|
||||||
|
left: 16px;
|
||||||
|
width: calc(100% - 32px);
|
||||||
|
}
|
||||||
|
|
||||||
@media (max-width: 768px) {
|
@media (max-width: 768px) {
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
&.hide {
|
&.hide {
|
||||||
top: -44px;
|
top: -44px;
|
||||||
}
|
}
|
||||||
@ -137,7 +144,7 @@ const MobileSearchContainer = styled.div`
|
|||||||
}
|
}
|
||||||
`
|
`
|
||||||
|
|
||||||
const AppBar = styled.nav`
|
const NavBar = styled.nav`
|
||||||
display: flex;
|
display: flex;
|
||||||
padding: 8px 0;
|
padding: 8px 0;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
@ -204,7 +211,3 @@ const Icons = styled.div`
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
|
|
||||||
const Selector = styled(IconButton)`
|
|
||||||
border-left: none;
|
|
||||||
`
|
|
1
src/components/AppBar/index.ts
Normal file
1
src/components/AppBar/index.ts
Normal file
@ -0,0 +1 @@
|
|||||||
|
export { default as AppBar } from './AppBar'
|
@ -43,13 +43,7 @@ const ArticleContainer = styled.article`
|
|||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: 16px;
|
gap: 16px;
|
||||||
max-width: 700px;
|
max-width: 700px;
|
||||||
margin-inline: 5%;
|
|
||||||
padding-bottom: 80px;
|
padding-bottom: 80px;
|
||||||
|
|
||||||
// temporary breakpoint
|
|
||||||
@media (max-width: 1024px) {
|
|
||||||
margin-inline: 16px;
|
|
||||||
}
|
|
||||||
`
|
`
|
||||||
|
|
||||||
const TextContainer = styled.div`
|
const TextContainer = styled.div`
|
||||||
|
@ -18,6 +18,7 @@ export const ArticleHeading = ({
|
|||||||
block,
|
block,
|
||||||
headingElementsRef,
|
headingElementsRef,
|
||||||
typographyProps,
|
typographyProps,
|
||||||
|
...props
|
||||||
}: Props) => {
|
}: Props) => {
|
||||||
const id =
|
const id =
|
||||||
extractIdFromFirstTag(block.html) || `${block.tagName}-${block.order}`
|
extractIdFromFirstTag(block.html) || `${block.tagName}-${block.order}`
|
||||||
@ -37,6 +38,7 @@ export const ArticleHeading = ({
|
|||||||
className={extractClassFromFirstTag(block.html) || ''}
|
className={extractClassFromFirstTag(block.html) || ''}
|
||||||
dangerouslySetInnerHTML={{ __html: `${extractInnerHtml(block.html)}` }}
|
dangerouslySetInnerHTML={{ __html: `${extractInnerHtml(block.html)}` }}
|
||||||
{...(typographyProps || {})}
|
{...(typographyProps || {})}
|
||||||
|
{...props}
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
@ -48,7 +50,7 @@ const Headline = styled(Typography)`
|
|||||||
|
|
||||||
@media (max-width: 768px) {
|
@media (max-width: 768px) {
|
||||||
&.title {
|
&.title {
|
||||||
font-size: var(--lsd-h3-fontSize);
|
font-size: var(--lsd-h4-fontSize);
|
||||||
line-height: var(--lsd-h4-lineHeight);
|
line-height: var(--lsd-h4-lineHeight);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,7 +6,7 @@ import { PostImageRatio } from '../../Post/Post'
|
|||||||
import ArticleStats from '../Article.Stats'
|
import ArticleStats from '../Article.Stats'
|
||||||
import { Typography } from '@acid-info/lsd-react'
|
import { Typography } from '@acid-info/lsd-react'
|
||||||
import styled from '@emotion/styled'
|
import styled from '@emotion/styled'
|
||||||
import ArticleSummary, { MobileSummary } from './Article.Summary'
|
import ArticleSummary from './Article.Summary'
|
||||||
import { calcReadingTime } from '@/utils/string.utils'
|
import { calcReadingTime } from '@/utils/string.utils'
|
||||||
import { Authors } from '@/components/Authors'
|
import { Authors } from '@/components/Authors'
|
||||||
import { Tags } from '@/components/Tags'
|
import { Tags } from '@/components/Tags'
|
||||||
@ -14,12 +14,8 @@ import { UnbodyGraphQl } from '@/lib/unbody/unbody-content.types'
|
|||||||
import { ArticleHeading } from '@/components/Article/Article.Heading'
|
import { ArticleHeading } from '@/components/Article/Article.Heading'
|
||||||
import { useArticleContainerContext } from '@/containers/ArticleContainer.Context'
|
import { useArticleContainerContext } from '@/containers/ArticleContainer.Context'
|
||||||
import { useIntersectionObserver } from '@/utils/ui.utils'
|
import { useIntersectionObserver } from '@/utils/ui.utils'
|
||||||
import { MobileToc } from '@/components/Article/Article.MobileToc'
|
|
||||||
import { useSearchBarContext } from '@/context/searchbar.context'
|
|
||||||
|
|
||||||
const ArticleHeader = ({
|
const ArticleHeader = ({
|
||||||
title,
|
|
||||||
toc,
|
|
||||||
summary,
|
summary,
|
||||||
subtitle,
|
subtitle,
|
||||||
mentions,
|
mentions,
|
||||||
@ -27,9 +23,8 @@ const ArticleHeader = ({
|
|||||||
modifiedAt,
|
modifiedAt,
|
||||||
blocks,
|
blocks,
|
||||||
}: GoogleDocEnhanced) => {
|
}: GoogleDocEnhanced) => {
|
||||||
const { setTocId, tocId } = useArticleContainerContext()
|
const { setTocId } = useArticleContainerContext()
|
||||||
const headingElementsRef = useIntersectionObserver(setTocId)
|
const headingElementsRef = useIntersectionObserver(setTocId)
|
||||||
const { resultsNumber } = useSearchBarContext()
|
|
||||||
|
|
||||||
const _thumbnail = useMemo(() => {
|
const _thumbnail = useMemo(() => {
|
||||||
const coverImage = getArticleCover(blocks)
|
const coverImage = getArticleCover(blocks)
|
||||||
@ -58,15 +53,14 @@ const ArticleHeader = ({
|
|||||||
}, [blocks])
|
}, [blocks])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<header>
|
<ArticleHeaderContainer>
|
||||||
<ArticleStats dateStr={modifiedAt} readingLength={readingTime} />
|
<ArticleStats dateStr={modifiedAt} readingLength={readingTime} />
|
||||||
<ArticleHeading
|
<ArticleTitle
|
||||||
block={blocks[0] as any}
|
block={blocks[0] as any}
|
||||||
typographyProps={{
|
typographyProps={{
|
||||||
variant: 'h1',
|
variant: 'h1',
|
||||||
genericFontFamily: 'serif',
|
genericFontFamily: 'serif',
|
||||||
component: 'h1',
|
component: 'h1',
|
||||||
style: { marginBottom: '16px' },
|
|
||||||
}}
|
}}
|
||||||
headingElementsRef={headingElementsRef}
|
headingElementsRef={headingElementsRef}
|
||||||
/>
|
/>
|
||||||
@ -79,22 +73,60 @@ const ArticleHeader = ({
|
|||||||
{subtitle}
|
{subtitle}
|
||||||
</ArticleSubtitle>
|
</ArticleSubtitle>
|
||||||
)}
|
)}
|
||||||
<Tags tags={tags} />
|
<Tags tags={tags} className={'articleTags'} />
|
||||||
<AuthorsContainer>
|
<AuthorsContainer>
|
||||||
<Authors mentions={mentions} email={true} gap={12} />
|
<Authors mentions={mentions} email={true} gap={12} />
|
||||||
</AuthorsContainer>
|
</AuthorsContainer>
|
||||||
<MobileCollapseContainer>
|
{/*<MobileCollapseContainer>*/}
|
||||||
{resultsNumber === null && <MobileToc toc={toc} />}
|
{/* {resultsNumber === null && <MobileToc toc={toc} />}*/}
|
||||||
{resultsNumber === null && <MobileSummary summary={summary} />}
|
{/* {resultsNumber === null && <MobileSummary summary={summary} />}*/}
|
||||||
</MobileCollapseContainer>
|
{/*</MobileCollapseContainer>*/}
|
||||||
|
<ArticleSummary
|
||||||
|
summary={summary}
|
||||||
|
className={'mobileSummary'}
|
||||||
|
showLabel={false}
|
||||||
|
/>
|
||||||
{_thumbnail}
|
{_thumbnail}
|
||||||
<ArticleSummary summary={summary} />
|
<ArticleSummary
|
||||||
</header>
|
summary={summary}
|
||||||
|
className={'desktopSummary'}
|
||||||
|
showLabel={true}
|
||||||
|
/>
|
||||||
|
</ArticleHeaderContainer>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
const MobileCollapseContainer = styled.div`
|
const ArticleHeaderContainer = styled.header`
|
||||||
margin-bottom: 32px;
|
.mobileSummary {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.desktopSummary {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
.mobileSummary {
|
||||||
|
color: red;
|
||||||
|
display: block;
|
||||||
|
p {
|
||||||
|
font-size: var(--lsd-body3-fontSize);
|
||||||
|
line-height: var(--lsd-body3-lineHeight);
|
||||||
|
margin-bottom: 24px;
|
||||||
|
}
|
||||||
|
hr {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.desktopSummary {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.articleTags {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
`
|
`
|
||||||
|
|
||||||
const CustomTypography = styled(Typography)`
|
const CustomTypography = styled(Typography)`
|
||||||
@ -103,18 +135,34 @@ const CustomTypography = styled(Typography)`
|
|||||||
white-space: pre-wrap;
|
white-space: pre-wrap;
|
||||||
`
|
`
|
||||||
|
|
||||||
const ArticleTitle = styled(CustomTypography)`
|
const ArticleTitle = styled(ArticleHeading)`
|
||||||
margin-bottom: 24px;
|
margin-bottom: 16px;
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
margin-bottom: 8px;
|
||||||
|
}
|
||||||
`
|
`
|
||||||
|
|
||||||
const ArticleSubtitle = styled(CustomTypography)`
|
const ArticleSubtitle = styled(CustomTypography)`
|
||||||
margin-bottom: 16px;
|
margin-bottom: 16px;
|
||||||
|
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
font-size: var(--lsd-subtitle1-fontSize);
|
||||||
|
}
|
||||||
`
|
`
|
||||||
|
|
||||||
const AuthorsContainer = styled.div`
|
const AuthorsContainer = styled.div`
|
||||||
//margin-block: 24px;
|
//margin-block: 24px;
|
||||||
margin-top: 24px;
|
margin-top: 24px;
|
||||||
margin-bottom: 32px;
|
margin-bottom: 32px;
|
||||||
|
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
margin-top: 16px;
|
||||||
|
margin-bottom: 24px;
|
||||||
|
|
||||||
|
a[href^='mailto:'] {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
`
|
`
|
||||||
|
|
||||||
export default ArticleHeader
|
export default ArticleHeader
|
||||||
|
@ -4,24 +4,14 @@ import React from 'react'
|
|||||||
import { Collapse } from '@/components/Collapse'
|
import { Collapse } from '@/components/Collapse'
|
||||||
import useIsDarkState from '@/states/isDarkState/isDarkState'
|
import useIsDarkState from '@/states/isDarkState/isDarkState'
|
||||||
|
|
||||||
export const MobileSummary = ({ summary }: { summary: string }) => {
|
type Props = {
|
||||||
const isDark = useIsDarkState().get()
|
summary: string
|
||||||
return (
|
className?: string
|
||||||
<SummaryContainerMobile
|
showLabel?: boolean
|
||||||
label={'Summary'}
|
|
||||||
initOpen={false}
|
|
||||||
style={{ background: isDark ? 'black' : 'white' }}
|
|
||||||
>
|
|
||||||
<SummaryParagraph variant="h6" component={'p'}>
|
|
||||||
{summary}
|
|
||||||
</SummaryParagraph>
|
|
||||||
</SummaryContainerMobile>
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
const ArticleSummary = ({ summary, className, showLabel }: Props) => (
|
||||||
const ArticleSummary = ({ summary }: { summary: string }) => (
|
<ArticleSummaryContainer className={className}>
|
||||||
<ArticleSummaryContainer>
|
{showLabel && <Typography variant="body3">summary</Typography>}
|
||||||
<Typography variant="body3">summary</Typography>
|
|
||||||
<SummaryParagraph variant="h6" component={'p'}>
|
<SummaryParagraph variant="h6" component={'p'}>
|
||||||
{summary}
|
{summary}
|
||||||
</SummaryParagraph>
|
</SummaryParagraph>
|
||||||
@ -35,6 +25,7 @@ const ArticleSummaryContainer = styled('div')`
|
|||||||
@media (max-width: 770px) {
|
@media (max-width: 770px) {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
> span {
|
> span {
|
||||||
margin-bottom: 16px;
|
margin-bottom: 16px;
|
||||||
display: block;
|
display: block;
|
||||||
@ -46,17 +37,4 @@ const SummaryParagraph = styled(Typography)`
|
|||||||
display: block;
|
display: block;
|
||||||
`
|
`
|
||||||
|
|
||||||
const SummaryContainerMobile = styled(Collapse)`
|
|
||||||
display: none;
|
|
||||||
@media (max-width: 770px) {
|
|
||||||
display: block;
|
|
||||||
p {
|
|
||||||
padding: 12px 14px;
|
|
||||||
margin-bottom: 0;
|
|
||||||
font-size: var(--lsd-font-size-body2);
|
|
||||||
line-height: var(--lsd-line-height-body2);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`
|
|
||||||
|
|
||||||
export default ArticleSummary
|
export default ArticleSummary
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { Typography } from '@acid-info/lsd-react'
|
import { Typography } from '@acid-info/lsd-react'
|
||||||
import styled from '@emotion/styled'
|
import styled from '@emotion/styled'
|
||||||
import { uiConfigs } from '@/configs/ui.configs'
|
import { uiConfigs } from '@/configs/ui.configs'
|
||||||
import { NavbarFiller } from '@/components/Navbar/NavbarFiller'
|
import { NavbarFiller } from '@/components/AppBar/NavbarFiller'
|
||||||
import { Searchbar } from '@/components/Searchbar'
|
import { Searchbar } from '@/components/Searchbar'
|
||||||
|
|
||||||
export default function Hero() {
|
export default function Hero() {
|
||||||
@ -18,7 +18,6 @@ export default function Hero() {
|
|||||||
</Description>
|
</Description>
|
||||||
</HeroText>
|
</HeroText>
|
||||||
<NavbarFiller />
|
<NavbarFiller />
|
||||||
<Searchbar className={'desktop'} />
|
|
||||||
</Container>
|
</Container>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -2,8 +2,8 @@ import styled from '@emotion/styled'
|
|||||||
import { uiConfigs } from '@/configs/ui.configs'
|
import { uiConfigs } from '@/configs/ui.configs'
|
||||||
import { PropsWithChildren } from 'react'
|
import { PropsWithChildren } from 'react'
|
||||||
|
|
||||||
const Main = ({ children }: PropsWithChildren) => {
|
const Main = ({ children, ...props }: PropsWithChildren<any>) => {
|
||||||
return <Container>{children}</Container>
|
return <Container {...props}>{children}</Container>
|
||||||
}
|
}
|
||||||
|
|
||||||
const Container = styled.main`
|
const Container = styled.main`
|
||||||
@ -11,6 +11,10 @@ const Container = styled.main`
|
|||||||
margin-left: auto;
|
margin-left: auto;
|
||||||
margin-right: auto;
|
margin-right: auto;
|
||||||
|
|
||||||
|
@media (max-width: ${uiConfigs.maxContainerWidth}px) {
|
||||||
|
padding: 0 16px;
|
||||||
|
}
|
||||||
|
|
||||||
@media (max-width: 768px) {
|
@media (max-width: 768px) {
|
||||||
margin-top: ${uiConfigs.postSectionMobileMargin}px;
|
margin-top: ${uiConfigs.postSectionMobileMargin}px;
|
||||||
}
|
}
|
||||||
|
@ -1 +0,0 @@
|
|||||||
export { default as Navbar } from './Navbar';
|
|
@ -137,13 +137,20 @@ export default function Post({
|
|||||||
|
|
||||||
const _thumbnail = useMemo(() => {
|
const _thumbnail = useMemo(() => {
|
||||||
if (!showImage || !coverImage) return null
|
if (!showImage || !coverImage) return null
|
||||||
|
let allImageProps = [
|
||||||
|
...imagePropsArray,
|
||||||
|
...(imageProps ? [imageProps] : []),
|
||||||
|
]
|
||||||
|
|
||||||
if (postType === PostType.BODY) {
|
if (postType === PostType.BODY) {
|
||||||
return (
|
return (
|
||||||
<Link href={`/article/${slug}`}>
|
<Link href={`/article/${slug}`}>
|
||||||
{[...imagePropsArray, ...(imageProps ? [imageProps] : [])].map(
|
{allImageProps.length > 0 ? (
|
||||||
(imageProps, index) => (
|
allImageProps.map((_imageProps, index) => (
|
||||||
<ResponsiveImage key={index} {...imageProps} data={coverImage} />
|
<ResponsiveImage key={index} {..._imageProps} data={coverImage} />
|
||||||
),
|
))
|
||||||
|
) : (
|
||||||
|
<ResponsiveImage {...imageProps} data={coverImage} />
|
||||||
)}
|
)}
|
||||||
</Link>
|
</Link>
|
||||||
)
|
)
|
||||||
@ -151,14 +158,16 @@ export default function Post({
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Link href={`/article/${slug}`}>
|
<Link href={`/article/${slug}`}>
|
||||||
{[...imagePropsArray, ...(imageProps ? [imageProps] : [])].map(
|
{allImageProps.length > 0 ? (
|
||||||
(imageProps, index) => (
|
allImageProps.map((_imageProps, index) => (
|
||||||
<ResponsiveImage
|
<ResponsiveImage
|
||||||
key={index}
|
key={index}
|
||||||
{...imageProps}
|
{..._imageProps}
|
||||||
data={coverImage}
|
data={coverImage}
|
||||||
/>
|
/>
|
||||||
),
|
))
|
||||||
|
) : (
|
||||||
|
<ResponsiveImage {...imageProps} data={coverImage} />
|
||||||
)}
|
)}
|
||||||
</Link>
|
</Link>
|
||||||
{_title}
|
{_title}
|
||||||
|
@ -79,6 +79,7 @@ const CustomGrid = styled(Grid)`
|
|||||||
min-height: 500px;
|
min-height: 500px;
|
||||||
@media (max-width: 768px) {
|
@media (max-width: 768px) {
|
||||||
gap: 8px;
|
gap: 8px;
|
||||||
|
min-height: auto;
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
|
|
||||||
|
@ -29,7 +29,9 @@ export default function RelatedArticles({ data }: Props) {
|
|||||||
tags: article.doc.tags,
|
tags: article.doc.tags,
|
||||||
coverImage: getArticleCover(article.doc.blocks),
|
coverImage: getArticleCover(article.doc.blocks),
|
||||||
}))}
|
}))}
|
||||||
pageSize={4}
|
pageSize={
|
||||||
|
typeof window !== 'undefined' && window.innerWidth < 768 ? 2 : 4
|
||||||
|
}
|
||||||
loading={data.loading}
|
loading={data.loading}
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
|
@ -103,7 +103,6 @@ export default function Searchbar(props: SearchbarProps) {
|
|||||||
performSearch('', [])
|
performSearch('', [])
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
setQuery('')
|
setQuery('')
|
||||||
setFilterTags([])
|
setFilterTags([])
|
||||||
setActive(false)
|
setActive(false)
|
||||||
@ -126,7 +125,8 @@ export default function Searchbar(props: SearchbarProps) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const isCollapsed = isValidSearchInput(filterTags) && !active
|
const withValue = isValidSearchInput(filterTags) || resultsNumber !== null
|
||||||
|
const isCollapsed = withValue && !active
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (active && query.length > 0) {
|
if (active && query.length > 0) {
|
||||||
@ -203,11 +203,13 @@ export default function Searchbar(props: SearchbarProps) {
|
|||||||
<div>
|
<div>
|
||||||
<IconButton
|
<IconButton
|
||||||
className={styles.searchButton}
|
className={styles.searchButton}
|
||||||
onClick={() =>
|
onClick={() => (withValue ? performClear() : performSearch())}
|
||||||
isValidSearchInput() ? performClear() : performSearch()
|
|
||||||
}
|
|
||||||
>
|
>
|
||||||
{isValidSearchInput() ? <CloseIcon /> : <SearchIcon />}
|
{withValue ? (
|
||||||
|
<CloseIcon color="primary" />
|
||||||
|
) : (
|
||||||
|
<SearchIcon color="primary" />
|
||||||
|
)}
|
||||||
</IconButton>
|
</IconButton>
|
||||||
</div>
|
</div>
|
||||||
</SearchBox>
|
</SearchBox>
|
||||||
@ -231,8 +233,10 @@ export default function Searchbar(props: SearchbarProps) {
|
|||||||
variant={'subtitle2'}
|
variant={'subtitle2'}
|
||||||
dangerouslySetInnerHTML={{
|
dangerouslySetInnerHTML={{
|
||||||
__html: [
|
__html: [
|
||||||
`${resultsNumber} matches`,
|
...(resultsNumber !== null ? [`${resultsNumber} matches`] : []),
|
||||||
`<span class="helper">${resultsHelperText}<span>`,
|
...(resultsHelperText !== null
|
||||||
|
? [`<span class="helper">${resultsHelperText}<span>`]
|
||||||
|
: []),
|
||||||
].join('<span class="dot">.</span>'),
|
].join('<span class="dot">.</span>'),
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
@ -249,6 +253,7 @@ const TagsWrapper = styled.div`
|
|||||||
margin-top: 19px;
|
margin-top: 19px;
|
||||||
height: 24px;
|
height: 24px;
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width: 768px) {
|
@media (max-width: 768px) {
|
||||||
&.active {
|
&.active {
|
||||||
margin-top: 10px;
|
margin-top: 10px;
|
||||||
|
@ -20,10 +20,6 @@ export function SearchbarContainer({
|
|||||||
className,
|
className,
|
||||||
beSticky = false,
|
beSticky = false,
|
||||||
}: Props) {
|
}: Props) {
|
||||||
const { pathname } = useRouter()
|
|
||||||
const isSearchPage = pathname === '/search'
|
|
||||||
const isArticlePage = pathname === '/article/[slug]'
|
|
||||||
|
|
||||||
const { sticky, stickyRef, height } = useSticky<HTMLDivElement>(
|
const { sticky, stickyRef, height } = useSticky<HTMLDivElement>(
|
||||||
uiConfigs.navbarRenderedHeight,
|
uiConfigs.navbarRenderedHeight,
|
||||||
)
|
)
|
||||||
@ -74,9 +70,25 @@ const SearchBarWrapper = styled.div<Props>`
|
|||||||
|
|
||||||
&.sticky {
|
&.sticky {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
|
|
||||||
top: ${uiConfigs.navbarRenderedHeight - 1}px;
|
top: ${uiConfigs.navbarRenderedHeight - 1}px;
|
||||||
z-index: 100;
|
z-index: 100;
|
||||||
max-width: ${uiConfigs.maxContainerWidth}px;
|
max-width: ${uiConfigs.maxContainerWidth}px;
|
||||||
border-top: none;
|
border-top: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@media (max-width: ${uiConfigs.maxContainerWidth}px) {
|
||||||
|
&.sticky {
|
||||||
|
width: calc(100% - 32px);
|
||||||
|
left: 16px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
&.sticky {
|
||||||
|
width: 100%;
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
`
|
`
|
||||||
|
@ -35,10 +35,6 @@ export const Section = ({ title, subtitle, children, ...props }: Props) => {
|
|||||||
const SectionContainer = styled.section`
|
const SectionContainer = styled.section`
|
||||||
width: 100%;
|
width: 100%;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
|
|
||||||
@media (max-width: 1440px) {
|
|
||||||
padding-inline: 16px;
|
|
||||||
}
|
|
||||||
`
|
`
|
||||||
|
|
||||||
const Container = styled.div`
|
const Container = styled.div`
|
||||||
|
@ -4,13 +4,13 @@ import styled from '@emotion/styled'
|
|||||||
import Link from 'next/link'
|
import Link from 'next/link'
|
||||||
import { useRouter } from 'next/router'
|
import { useRouter } from 'next/router'
|
||||||
|
|
||||||
const Tags = ({ tags }: { tags: string[] }) => {
|
const Tags = ({ tags, className }: { tags: string[]; className?: string }) => {
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const { query } = router
|
const { query } = router
|
||||||
const { topics } = query
|
const { topics } = query
|
||||||
|
|
||||||
return tags.length > 0 ? (
|
return tags.length > 0 ? (
|
||||||
<TagsContainer>
|
<TagsContainer className={className}>
|
||||||
{tags.map((tag, idx) => (
|
{tags.map((tag, idx) => (
|
||||||
<Link key={`tag-${idx}`} href={`/search?topics=${tag}`}>
|
<Link key={`tag-${idx}`} href={`/search?topics=${tag}`}>
|
||||||
<Tag
|
<Tag
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
export const uiConfigs = {
|
export const uiConfigs = {
|
||||||
navbarRenderedHeight: 45,
|
navbarRenderedHeight: 45,
|
||||||
postSectionMargin: 108,
|
postSectionMargin: 101,
|
||||||
postSectionMobileMargin: 48,
|
postSectionMobileMargin: 48,
|
||||||
articleSectionMargin: 40,
|
articleSectionMargin: 40,
|
||||||
maxContainerWidth: 1440,
|
maxContainerWidth: 1440,
|
||||||
|
@ -1,13 +1,10 @@
|
|||||||
import { Navbar } from '@/components/Navbar'
|
|
||||||
import useIsDarkState from '@/states/isDarkState/isDarkState'
|
import useIsDarkState from '@/states/isDarkState/isDarkState'
|
||||||
import { PropsWithChildren } from 'react'
|
import { PropsWithChildren } from 'react'
|
||||||
import { NavbarFiller } from '@/components/Navbar/NavbarFiller'
|
|
||||||
import { Searchbar } from '@/components/Searchbar'
|
|
||||||
import { ESearchScope } from '@/types/ui.types'
|
|
||||||
import styles from './Article.layout.module.css'
|
import styles from './Article.layout.module.css'
|
||||||
import { Footer } from '@/components/Footer'
|
import { Footer } from '@/components/Footer'
|
||||||
import { Main } from '@/components/Main'
|
import { Main } from '@/components/Main'
|
||||||
import { useArticleContext } from '@/context/article.context'
|
import { useArticleContext } from '@/context/article.context'
|
||||||
|
import { AppBar } from '@/components/AppBar'
|
||||||
|
|
||||||
type Props = PropsWithChildren<{
|
type Props = PropsWithChildren<{
|
||||||
// onSearch: (query: string, filters: string[]) => void
|
// onSearch: (query: string, filters: string[]) => void
|
||||||
@ -19,7 +16,7 @@ export default function ArticleLayout({ children }: Props) {
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<header className={styles.header}>
|
<header className={styles.header}>
|
||||||
<Navbar
|
<AppBar
|
||||||
isDark={isDarkState.get()}
|
isDark={isDarkState.get()}
|
||||||
toggle={isDarkState.toggle}
|
toggle={isDarkState.toggle}
|
||||||
onSearch={onSearch}
|
onSearch={onSearch}
|
||||||
|
@ -1,42 +1,41 @@
|
|||||||
import { Navbar } from '@/components/Navbar'
|
import { AppBar } from '../../components/AppBar'
|
||||||
import useIsDarkState from '@/states/isDarkState/isDarkState'
|
import useIsDarkState from '@/states/isDarkState/isDarkState'
|
||||||
import { PropsWithChildren } from 'react'
|
import { PropsWithChildren } from 'react'
|
||||||
import { Hero } from '@/components/Hero'
|
import { Hero } from '@/components/Hero'
|
||||||
import { NavbarFiller } from '@/components/Navbar/NavbarFiller'
|
import { NavbarFiller } from '@/components/AppBar/NavbarFiller'
|
||||||
import { Searchbar } from '@/components/Searchbar'
|
import { Searchbar } from '@/components/Searchbar'
|
||||||
import { Footer } from '@/components/Footer'
|
import { Footer } from '@/components/Footer'
|
||||||
import { Main } from '@/components/Main'
|
import { Main } from '@/components/Main'
|
||||||
import { uiConfigs } from '@/configs/ui.configs'
|
import { uiConfigs } from '@/configs/ui.configs'
|
||||||
import { useRouter } from 'next/router'
|
import { useRouter } from 'next/router'
|
||||||
import { defaultThemes } from '@acid-info/lsd-react'
|
import { defaultThemes } from '@acid-info/lsd-react'
|
||||||
|
import styled from '@emotion/styled'
|
||||||
|
|
||||||
export default function DefaultLayout(props: PropsWithChildren<any>) {
|
export default function DefaultLayout(props: PropsWithChildren<any>) {
|
||||||
const isDarkState = useIsDarkState()
|
const isDarkState = useIsDarkState()
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<header
|
<HeaderContainer
|
||||||
style={{
|
style={{
|
||||||
textAlign: 'center',
|
textAlign: 'center',
|
||||||
marginBlock: `${uiConfigs.navbarRenderedHeight}px`,
|
marginBlock: `${uiConfigs.navbarRenderedHeight}px`,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div
|
<div>
|
||||||
// style={{
|
<AppBar isDark={isDarkState.get()} toggle={isDarkState.toggle} />
|
||||||
// borderBottom: `1px solid rgb(${
|
|
||||||
// isDarkState.get()
|
|
||||||
// ? defaultThemes.dark.palette.border.primary
|
|
||||||
// : defaultThemes.light.palette.border.primary
|
|
||||||
// })`,
|
|
||||||
// }}
|
|
||||||
>
|
|
||||||
<Navbar isDark={isDarkState.get()} toggle={isDarkState.toggle} />
|
|
||||||
<Hero />
|
<Hero />
|
||||||
</div>
|
</div>
|
||||||
<Searchbar withFilterTags={false} />
|
<Searchbar withFilterTags={false} beSticky={true} />
|
||||||
</header>
|
</HeaderContainer>
|
||||||
<Main>{props.children}</Main>
|
<Main>{props.children}</Main>
|
||||||
<Footer />
|
<Footer />
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const HeaderContainer = styled.header`
|
||||||
|
@media (min-width: 776px) and (max-width: ${uiConfigs.maxContainerWidth}px) {
|
||||||
|
padding: 0 16px;
|
||||||
|
}
|
||||||
|
`
|
||||||
|
@ -1,12 +1,10 @@
|
|||||||
import { Navbar } from '@/components/Navbar'
|
|
||||||
import useIsDarkState from '@/states/isDarkState/isDarkState'
|
import useIsDarkState from '@/states/isDarkState/isDarkState'
|
||||||
import { PropsWithChildren } from 'react'
|
import { PropsWithChildren } from 'react'
|
||||||
import { NavbarFiller } from '@/components/Navbar/NavbarFiller'
|
|
||||||
import { Searchbar } from '@/components/Searchbar'
|
|
||||||
import { ESearchScope } from '@/types/ui.types'
|
|
||||||
import styles from './Search.layout.module.css'
|
import styles from './Search.layout.module.css'
|
||||||
import { Footer } from '@/components/Footer'
|
import { Footer } from '@/components/Footer'
|
||||||
import { Main } from '@/components/Main'
|
import { Main } from '@/components/Main'
|
||||||
|
import { AppBar } from '@/components/AppBar'
|
||||||
|
import styled from '@emotion/styled'
|
||||||
import { uiConfigs } from '@/configs/ui.configs'
|
import { uiConfigs } from '@/configs/ui.configs'
|
||||||
|
|
||||||
export default function SearchLayout(props: PropsWithChildren<any>) {
|
export default function SearchLayout(props: PropsWithChildren<any>) {
|
||||||
@ -14,10 +12,22 @@ export default function SearchLayout(props: PropsWithChildren<any>) {
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<header className={styles.header}>
|
<header className={styles.header}>
|
||||||
<Navbar isDark={isDarkState.get()} toggle={isDarkState.toggle} />
|
<AppBar isDark={isDarkState.get()} toggle={isDarkState.toggle} />
|
||||||
</header>
|
</header>
|
||||||
<Main>{props.children}</Main>
|
<MainContainer className={'search_page'}>{props.children}</MainContainer>
|
||||||
<Footer />
|
<Footer />
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const MainContainer = styled(Main)`
|
||||||
|
&.search_page {
|
||||||
|
margin-top: ${uiConfigs.postSectionMargin * 1.7}px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
&.search_page {
|
||||||
|
margin-top: ${uiConfigs.postSectionMobileMargin * 3}px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`
|
||||||
|
@ -42,7 +42,6 @@ export async function getStaticPaths() {
|
|||||||
|
|
||||||
export const getStaticProps = async ({ params }: GetStaticPropsContext) => {
|
export const getStaticProps = async ({ params }: GetStaticPropsContext) => {
|
||||||
const { slug } = params!
|
const { slug } = params!
|
||||||
console.log('rendering', slug)
|
|
||||||
|
|
||||||
if (!slug) {
|
if (!slug) {
|
||||||
return {
|
return {
|
||||||
|
@ -84,7 +84,12 @@ export default function SearchPage({
|
|||||||
}, [mounted, router.query])
|
}, [mounted, router.query])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setResultsNumber(articles.data.length + blocks.data.length)
|
if (
|
||||||
|
articles.data.length + blocks.data.length <
|
||||||
|
initialArticles.length + initialBlocks.length
|
||||||
|
) {
|
||||||
|
setResultsNumber(articles.data.length + blocks.data.length)
|
||||||
|
}
|
||||||
const tags = extractTopicsFromQuery(router.query)
|
const tags = extractTopicsFromQuery(router.query)
|
||||||
setResultsHelperText(
|
setResultsHelperText(
|
||||||
[
|
[
|
||||||
|
@ -5,10 +5,6 @@ class SearchService {
|
|||||||
constructor() {}
|
constructor() {}
|
||||||
|
|
||||||
search = (query: string, tags: string[], postType: PostTypes) => {
|
search = (query: string, tags: string[], postType: PostTypes) => {
|
||||||
console.log(
|
|
||||||
`/api/search/general/${postType}?q=${query}&tags=${tags.join(',')}`,
|
|
||||||
)
|
|
||||||
|
|
||||||
return fetch(
|
return fetch(
|
||||||
`/api/search/general/${postType}?q=${query}&tags=${tags.join(',')}`,
|
`/api/search/general/${postType}?q=${query}&tags=${tags.join(',')}`,
|
||||||
)
|
)
|
||||||
|
@ -83,6 +83,7 @@ export function useIntersectionObserver(
|
|||||||
headings.forEach((heading) => {
|
headings.forEach((heading) => {
|
||||||
if (heading.isIntersecting && heading.target instanceof HTMLElement) {
|
if (heading.isIntersecting && heading.target instanceof HTMLElement) {
|
||||||
const targetId = heading.target.getAttribute('id')
|
const targetId = heading.target.getAttribute('id')
|
||||||
|
console.log(targetId)
|
||||||
if (targetId) setActiveId(targetId)
|
if (targetId) setActiveId(targetId)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
Loading…
x
Reference in New Issue
Block a user