From 5792de1a652d2ce45cdfec25e6023caa87ad5484 Mon Sep 17 00:00:00 2001 From: Hossein Mehrabi Date: Thu, 24 Aug 2023 08:30:51 +0330 Subject: [PATCH 01/16] refactor: refactor PostCard component --- .../PostCard/PostCard.ShowDetails.tsx | 167 +++++++-- src/components/PostCard/PostCard.tsx | 324 ++++++++++-------- 2 files changed, 312 insertions(+), 179 deletions(-) diff --git a/src/components/PostCard/PostCard.ShowDetails.tsx b/src/components/PostCard/PostCard.ShowDetails.tsx index ee9b2c2..c68ba40 100644 --- a/src/components/PostCard/PostCard.ShowDetails.tsx +++ b/src/components/PostCard/PostCard.ShowDetails.tsx @@ -1,20 +1,21 @@ import { LPE } from '@/types/lpe.types' -import { Typography } from '@acid-info/lsd-react' +import { Theme, Typography } from '@acid-info/lsd-react' import { css } from '@emotion/react' import styled from '@emotion/styled' +import clsx from 'clsx' import Image from 'next/image' import Link from 'next/link' -export type PostCardShowDetailsProps = Partial< - React.ComponentProps -> & { - title: string - slug: string - episodeNumber: number - logo?: LPE.Image.Document - podcast: LPE.Podcast.Show - size?: 'small' | 'medium' -} +type Size = 'small' | 'medium' | 'large' + +export type PostCardShowDetailsProps = React.HTMLAttributes & + Partial & { + title: string + slug: string + episodeNumber: number + logo?: LPE.Image.Document + podcast: LPE.Podcast.Show + } // TODO export const PostCardShowDetails = ({ @@ -25,45 +26,137 @@ export const PostCardShowDetails = ({ ...props }: PostCardShowDetailsProps) => { return ( - - + +
{podcast && ( <> - - - {podcast.title} - {size !== 'small' && ( - {episodeNumber} EP - )} - +
+ + {podcast.title} + + + {episodeNumber} EP + +
)} - +
) } -const Container = styled.div` - display: flex; - gap: 8px; - align-items: center; -` +PostCardShowDetails.styles = { + small: (theme: Theme) => css` + .show-details__title { + font-size: 12px !important; + font-weight: 400 !important; + line-height: 16px !important; + } -const PodcastInfo = styled.div` - display: flex; - flex-direction: column; - gap: 2px; -` + .show-details__episodes { + display: none; + } -const CustomLink = styled(Link)` + .show-details__logo { + width: 24px; + height: 24px; + } + `, + + medium: (theme: Theme) => css` + .show-details__episodes { + display: none; + } + + .show-details__logo { + width: 28px; + height: 28px; + } + `, + + large: (theme: Theme) => css` + .show-details__episodes { + display: block !important; + } + + .show-details__logo { + width: 38px; + height: 38px; + } + `, +} + +type CustomLinkProps = { + size?: Size + xsSize?: Size + smSize?: Size + mdSize?: Size + lgSize?: Size +} + +const CustomLink = styled(Link)` text-decoration: none; -` -const Logo = styled(Image)` - border-radius: 100%; + .show-details { + &__container { + display: flex; + gap: 8px; + align-items: center; + } + + &__info { + display: flex; + flex-direction: column; + gap: 2px; + } + + &__logo { + border-radius: 100%; + } + } + + &.show-details--small { + ${(props) => PostCardShowDetails.styles.small(props.theme)} + } + + &.show-details--medium { + ${(props) => PostCardShowDetails.styles.medium(props.theme)} + } + + &.show-details--large { + ${(props) => PostCardShowDetails.styles.large(props.theme)} + } + + &.show-details { + @media (max-width: ${({ theme }) => theme.breakpoints.sm.width - 1}px) { + ${(props) => + props.xsSize && PostCardShowDetails.styles[props.xsSize](props.theme)} + } + + @media (min-width: ${({ theme }) => theme.breakpoints.sm.width}px) { + ${(props) => + props.smSize && PostCardShowDetails.styles[props.smSize](props.theme)} + } + + @media (min-width: ${({ theme }) => theme.breakpoints.md.width}px) { + ${(props) => + props.mdSize && PostCardShowDetails.styles[props.mdSize](props.theme)} + } + + @media (min-width: ${({ theme }) => theme.breakpoints.lg.width}px) { + ${(props) => + props.lgSize && PostCardShowDetails.styles[props.lgSize](props.theme)} + } + } ` diff --git a/src/components/PostCard/PostCard.tsx b/src/components/PostCard/PostCard.tsx index e5f36a1..3e42fd0 100644 --- a/src/components/PostCard/PostCard.tsx +++ b/src/components/PostCard/PostCard.tsx @@ -1,21 +1,21 @@ -import { Tags } from '@/components/Tags' -import { Typography } from '@acid-info/lsd-react' -import { CommonProps } from '@acid-info/lsd-react/dist/utils/useCommonProps' -import styled from '@emotion/styled' -import Link from 'next/link' -import React from 'react' -import { LPE } from '../../types/lpe.types' -import { Authors } from '../Authors' -import { AuthorsDirection } from '../Authors/Authors' - -import { ResponsiveImageProps } from '../ResponsiveImage/ResponsiveImage' - import { PostCardCover } from '@/components/PostCard/PostCard.Cover' import { PostCardShowDetails, PostCardShowDetailsProps, } from '@/components/PostCard/PostCard.ShowDetails' +import { Tags } from '@/components/Tags' +import { Theme, Typography } from '@acid-info/lsd-react' +import { CommonProps } from '@acid-info/lsd-react/dist/utils/useCommonProps' import { css } from '@emotion/react' +import styled from '@emotion/styled' +import clsx from 'clsx' +import Link from 'next/link' +import React from 'react' +import { LPE } from '../../types/lpe.types' +import { lsdUtils } from '../../utils/lsd.utils' +import { Authors } from '../Authors' +import { AuthorsDirection } from '../Authors/Authors' +import { ResponsiveImageProps } from '../ResponsiveImage/ResponsiveImage' import { PostCardLabel } from './PostCard.Label' export type PostAppearanceProps = { @@ -39,6 +39,7 @@ export type PostCardProps = CommonProps & data: PostDataProps contentType: LPE.PostType size?: 'xxsmall' | 'xsmall' | 'small' | 'medium' | 'large' + applySizeStyles?: boolean displayPodcastShow?: boolean } @@ -57,6 +58,7 @@ export const PostCard = (_props: PostCardProps) => { }, size = 'small', contentType, + applySizeStyles = true, displayPodcastShow = true, ...props } = _props @@ -68,7 +70,7 @@ export const PostCard = (_props: PostCardProps) => { const coverImageElement = coverImage && ( { ) const labelElement = ( - + ) const titleElement = ( - + {title} @@ -102,7 +100,7 @@ export const PostCard = (_props: PostCardProps) => { const subtitleElement = subtitle && ( @@ -112,7 +110,7 @@ export const PostCard = (_props: PostCardProps) => { const authorsElement = authors && authors.length > 0 && ( { const showElement = displayPodcastShow && podcastShowDetails && ( ) - const tagsElement = tags.length > 0 && + const tagsElement = tags.length > 0 && ( + + ) return ( - - {size === 'large' ? ( - <> -
- {labelElement} - {titleElement} - {subtitleElement} - {authorsElement} - {showElement} - {tagsElement} -
-
{coverImageElement}
- - ) : ( - <> - {coverImageElement} - {labelElement} - {titleElement} - {subtitleElement} - {authorsElement} - {showElement} - {tagsElement} - + + {labelElement} + {coverImageElement} + {titleElement} + {subtitleElement} + {showElement} + {authorsElement} + {tagsElement} ) } @@ -193,115 +182,166 @@ PostCard.toData = (post: LPE.Post.Document, shows: LPE.Podcast.Show[] = []) => { } } +PostCard.styles = { + xxsmall: (theme: Theme) => css` + height: 100%; + + .post-card__title-text { + display: -webkit-box; + -webkit-line-clamp: 2; + -webkit-box-orient: vertical; + max-height: calc(2 * var(--lsd-h6-lineHeight)); + + ${lsdUtils.typography('h6')} + } + + .post-card__subtitle { + display: none; + } + + .post-card__cover-image { + display: none; + } + + .post-card__tags { + display: none; + } + + .post-card__authors, + .post-card__show-details { + flex-grow: 1; + display: flex; + } + + @media (max-width: ${theme.breakpoints.lg.width - 1}px) { + .post-card__title-text { + ${lsdUtils.typography('subtitle1', true)} + max-height: calc(2 * var(--lsd-subtitle1-lineHeight)); + } + } + `, + xsmall: (theme: Theme) => css` + .post-card__title-text { + ${lsdUtils.typography('h6')} + } + `, + small: (theme: Theme) => css` + .post-card__title-text { + ${lsdUtils.typography('h4')} + } + + .post-card__subtitle { + ${lsdUtils.typography('subtitle2')} + } + + .post-card__show-details { + ${PostCardShowDetails.styles.large(theme)} + } + `, + medium: (theme: Theme) => css` + .post-card__title-text { + ${lsdUtils.typography('h2')} + } + + .post-card__subtitle { + ${lsdUtils.typography('subtitle2')} + } + + .post-card__show-details { + ${PostCardShowDetails.styles.large(theme)} + } + `, + large: (theme: Theme) => css` + display: grid; + grid-template-columns: repeat(2, 1fr); + grid-template-areas: + 'info image' + 'info image' + 'info image' + 'info image' + 'info image' + 'info image' + '. image'; + gap: 16px 105px; + + .post-card__title-text { + ${lsdUtils.typography('h2')} + } + + .postcard__subtitle { + ${lsdUtils.typography('subtitle2')} + } + + .post-card__cover-image { + grid-area: image; + } + + .post-card__label { + grid-area: info; + grid-row: auto; + } + + .post-card__title { + grid-area: info; + grid-row: auto; + } + + .post-card__authors, + .post-card__show-details { + grid-area: info; + grid-row: auto; + } + + .post-card__tags { + grid-area: info; + grid-row: auto; + } + + .post-card__show-details { + ${PostCardShowDetails.styles.large(theme)} + } + `, +} + const Container = styled.div>` display: flex; flex-direction: column; position: 'relative'; - gap: 16px; + gap: 16px 0; - .label { + .post-card__label { margin-bottom: -8px; } - .titleLink { + .post-card__title { text-decoration: none; width: fit-content; } - .title, - .subtitle { + .post-card__title-text, + .post-card__subtitle { text-overflow: ellipsis; overflow: hidden; word-break: break-word; } - .title { - @media (max-width: 768px) { - font-size: 28px; - line-height: 36px; - } + &.post-card--xxsmall { + ${({ theme }) => PostCard.styles.xxsmall(theme)} } - .subtitle { - @media (max-width: 768px) { - font-size: 14px; - line-height: 20px; - } + &.post-card--xsmall { + ${({ theme }) => PostCard.styles.xsmall(theme)} } - ${({ size }) => - size === 'xxsmall' && - css` - .label { - } + &.post-card--small { + ${({ theme }) => PostCard.styles.small(theme)} + } - .title { - display: -webkit-box; - -webkit-line-clamp: 2; - -webkit-box-orient: vertical; - max-height: calc(2 * var(--lsd-h6-lineHeight)); - } + &.post-card--medium { + ${({ theme }) => PostCard.styles.medium(theme)} + } - .subtitle { - display: none; - } - - .coverImage { - display: none; - } - - .tags { - display: none; - } - - .authors, - .showDetails { - flex-grow: 1; - display: flex; - } - `} - - ${({ size }) => - size === 'xsmall' && - css` - .label { - margin-bottom: -px; - } - - .title { - } - - .subtitle { - display: none; - } - - .coverImage { - } - - .tags { - margin-top: 8px; - } - - .authors, - .showDetails { - } - `} - - ${({ size }) => size === 'small' && css``} - - ${({ size }) => size === 'medium' && css``} - - ${({ size }) => - size === 'large' && - css` - display: grid; - grid-template-columns: repeat(2, 1fr); - - > * { - display: flex; - flex-direction: column; - position: 'relative'; - gap: 16px; - } - `} + &.post-card--large { + ${({ theme }) => PostCard.styles.large(theme)} + } ` From 38421bef71ce2fd18c81668a3f473bb211f2ce44 Mon Sep 17 00:00:00 2001 From: Hossein Mehrabi Date: Thu, 24 Aug 2023 08:31:44 +0330 Subject: [PATCH 02/16] fix: fix lsd xl breakpoint width --- src/containers/LSDThemeProvider/themes.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/containers/LSDThemeProvider/themes.ts b/src/containers/LSDThemeProvider/themes.ts index e050ea8..7459091 100644 --- a/src/containers/LSDThemeProvider/themes.ts +++ b/src/containers/LSDThemeProvider/themes.ts @@ -47,6 +47,9 @@ export const useLSDTheme = () => { lg: { width: 1280, }, + xl: { + width: 1440, + }, }, palette: {}, typography: {}, From dbc7cd476dd601e65b3daaf99f4e970ecc629008 Mon Sep 17 00:00:00 2001 From: Hossein Mehrabi Date: Thu, 24 Aug 2023 08:32:25 +0330 Subject: [PATCH 03/16] fix: fix chunkArray infinite loop issue --- src/utils/array.utils.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/utils/array.utils.ts b/src/utils/array.utils.ts index 1491f6c..99e347c 100644 --- a/src/utils/array.utils.ts +++ b/src/utils/array.utils.ts @@ -4,6 +4,8 @@ export const chunkArray = (arr: T[], ...pattern: number[]): T[][] => { let index = 0 let iteration = 0 + if (pattern.length === 0) return [arr] + while (index < arr.length) { const take = pattern[iteration % pattern.length] const elements = arr.slice(index, index + take) From debcfc103b6a67a57eeb7eb6be26a7b73f8a6e9f Mon Sep 17 00:00:00 2001 From: Hossein Mehrabi Date: Thu, 24 Aug 2023 08:32:50 +0330 Subject: [PATCH 04/16] feat: implement LSD typography and breakpoint utils --- src/utils/lsd.utils.ts | 58 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100644 src/utils/lsd.utils.ts diff --git a/src/utils/lsd.utils.ts b/src/utils/lsd.utils.ts new file mode 100644 index 0000000..60dfb6a --- /dev/null +++ b/src/utils/lsd.utils.ts @@ -0,0 +1,58 @@ +import { + Breakpoints, + Theme, + TypographyVariants, + THEME_BREAKPOINTS, +} from '@acid-info/lsd-react' +import { css } from '@emotion/react' + +export class LsdUtils { + breakpoints = (exclude: Breakpoints[] = []) => + THEME_BREAKPOINTS.filter((b) => !exclude.find((b2) => b2 === b)) + + typography = (variant: TypographyVariants | 'subtitle3', important = false) => + variant === 'subtitle3' + ? ` + font-size: 12px !important; + font-weight: 400 !important; + line-height: 16px !important; + ` + : ` + font-size: var(--lsd-${variant}-fontSize)${important ? '!important' : ''}; + font-weight: var(--lsd-${variant}-fontWeight)${ + important ? '!important' : '' + }; + line-height: var(--lsd-${variant}-lineHeight)${ + important ? '!important' : '' + }; + ` + + breakpoint = ( + theme: Theme, + breakpoint: Breakpoints, + func: 'exact' | 'up' | 'down' = 'up', + ) => { + const width = theme.breakpoints[breakpoint].width + const idx = THEME_BREAKPOINTS.findIndex((b) => b === breakpoint) + const next = theme.breakpoints[THEME_BREAKPOINTS[idx + 1]] + const min = width + const max = next?.width ? next.width - 1 : Number.MAX_SAFE_INTEGER + + let media = `@media ` + + if (func === 'up') { + media += `(min-width: ${min}px)` + } else if (func === 'down') media += `(max-width: ${max}px)` + else media += `(min-width: ${min}px) and (max-width: ${max}px)` + + return (styles: any) => { + return css` + ${media} { + ${styles} + } + ` + } + } +} + +export const lsdUtils = new LsdUtils() From f30f2d1b9e7c42d3272c8eb453811d8fdd4bf84d Mon Sep 17 00:00:00 2001 From: Hossein Mehrabi Date: Thu, 24 Aug 2023 08:33:41 +0330 Subject: [PATCH 05/16] feat: make PostGrid component responsive --- src/components/Podcasts/Episodes.List.tsx | 6 +- src/components/PostsGrid/PostsGrid.tsx | 300 +++++++++++++----- src/containers/HomePage/HomePage.tsx | 82 ++++- .../PodcastShowsPreview.tsx | 55 +++- src/utils/math.utils.ts | 3 + 5 files changed, 346 insertions(+), 100 deletions(-) create mode 100644 src/utils/math.utils.ts diff --git a/src/components/Podcasts/Episodes.List.tsx b/src/components/Podcasts/Episodes.List.tsx index b758262..36eab05 100644 --- a/src/components/Podcasts/Episodes.List.tsx +++ b/src/components/Podcasts/Episodes.List.tsx @@ -7,7 +7,7 @@ interface Props { episodes: LPE.Podcast.Document[] shows?: LPE.Podcast.Show[] bordered?: boolean - size?: PostsGridProps['size'] + size?: string cols?: number displayShow?: boolean } @@ -24,14 +24,14 @@ export default function EpisodesList({ return ( {header} - + /> */} ) } diff --git a/src/components/PostsGrid/PostsGrid.tsx b/src/components/PostsGrid/PostsGrid.tsx index 009faf7..07783ce 100644 --- a/src/components/PostsGrid/PostsGrid.tsx +++ b/src/components/PostsGrid/PostsGrid.tsx @@ -1,8 +1,12 @@ -import { css } from '@emotion/react' +/** @jsxImportSource @emotion/react */ +import { Breakpoints, Theme, useTheme } from '@acid-info/lsd-react' +import { css, SerializedStyles } from '@emotion/react' import styled from '@emotion/styled' import React, { useMemo } from 'react' import { LPE } from '../../types/lpe.types' import { chunkArray } from '../../utils/array.utils' +import { lsdUtils } from '../../utils/lsd.utils' +import { lcm } from '../../utils/math.utils' import { PostCard, PostCardProps } from '../PostCard' export type PostsGridProps = Partial> & { @@ -12,41 +16,134 @@ export type PostsGridProps = Partial> & { } export const PostsGrid: React.FC = ({ - cols = 4, - size = 'small', posts = [], shows = [], + pattern = [], + breakpoints = [], bordered = false, displayPodcastShow = true, ...props }) => { - const groups = useMemo(() => chunkArray(posts, cols), [posts, cols]) + const theme = useTheme() + + const items = useMemo(() => { + const cols = pattern.map((p) => p.cols) + const chunked = chunkArray(posts, ...cols) + + return chunked + .map((posts, i) => + posts.map((post) => ({ + post, + size: pattern[i % pattern.length]?.size, + })), + ) + .flat() + }, [pattern, posts]) + + const postCardStyles = useMemo( + () => ({ + xxsmall: PostCard.styles.xxsmall(theme), + xsmall: PostCard.styles.xsmall(theme), + small: PostCard.styles.small(theme), + medium: PostCard.styles.medium(theme), + large: PostCard.styles.large(theme), + }), + [theme], + ) return ( - - {groups.map((group, index) => ( -
- {group.map((post) => ( -
- -
- ))} -
- ))} + +
+ {items.map(({ post, size }) => ( +
+ +
+ ))} +
) } -const Container = styled.div<{ +type Pattern = { cols: number - bordered: boolean size: PostCardProps['size'] +} +type Breakpoint = { + pattern: Pattern[] + breakpoint: Breakpoints +} + +const createGridStyles = ({ + theme, + pattern = [], + postCardStyles, + breakpoint = false, +}: { + theme: Theme + postCardStyles: { + [name: string]: SerializedStyles + } + pattern: Pick[] + breakpoint?: boolean +}) => { + const cm = pattern.map((p) => p.cols).reduce(lcm, 1) + const sum = Math.max( + 1, + pattern.reduce((p, c) => p + c.cols, 0), + ) + + let selectorNumber = 0 + const selectors = pattern.map((p) => { + const start = selectorNumber + 1 + selectorNumber += p.cols + + return new Array(p.cols) + .fill(null) + .map((i, index) => `${sum}n + ${start + index}`) + }) + + return css` + > .row { + display: grid; + grid-template-columns: repeat(${cm}, 1fr); + + & > div { + ${pattern.map( + (p, i) => ` + ${selectors[i].map((s) => `&:nth-child(${s})`).join(', ')} { + grid-column: span ${cm / p.cols}; + + .post-card { + ${postCardStyles[p.size as string].styles} + } + } + `, + )} + } + } + ` +} + +const Container = styled.div<{ + bordered: boolean + pattern: Pattern[] + breakpoints: Breakpoint[] + postCardStyles: { + [name: string]: SerializedStyles + } }>` display: grid; gap: 16px 0; @@ -54,7 +151,6 @@ const Container = styled.div<{ ${(props) => css` > .row { display: grid; - grid-template-columns: repeat(${props.cols}, 1fr); gap: 0 16px; & > div { @@ -63,55 +159,115 @@ const Container = styled.div<{ rgb(var(--lsd-border-primary)); } } + + ${lsdUtils + .breakpoints(props.breakpoints.map((b) => b.breakpoint)) + .map((breakpoint) => + lsdUtils.breakpoint( + props.theme, + breakpoint, + 'exact', + )(css` + ${createGridStyles({ + theme: props.theme, + pattern: props.pattern, + postCardStyles: props.postCardStyles, + breakpoint: true, + })} + `), + )} `} - ${(props) => - props.size === 'xxsmall' && - css` - > .row { - padding: 24px 0; - gap: 0 32px; - - & > div { - border-top: 0; - padding: 0; - position: relative; - } - - & > div:not(:last-child)::after { - content: ' '; - height: 100%; - width: 1px; - background: rgb(var(--lsd-border-primary)); - position: absolute; - top: 0; - right: -16px; - display: ${props.bordered ? 'block' : 'none'}; - } - } - `} - - ${(props) => - props.size === 'xsmall' && - css` - > .row { - gap: 0 16px; - - & > div { - box-sizing: border-box; - border-top: 0; - } - - & > div:last-child { - } - & > div:not(:last-child) { - } - } - `} - - ${(props) => props.size === 'small' && css``} - - ${(props) => props.size === 'medium' && css``} - - ${(props) => props.size === 'large' && css``} + ${({ breakpoints = [], theme, postCardStyles }) => { + return breakpoints.map((b) => + lsdUtils.breakpoint( + theme, + b.breakpoint, + 'exact', + )(css` + ${createGridStyles({ + theme, + pattern: b.pattern, + postCardStyles, + breakpoint: true, + })} + `), + ) + }} ` +// ${b.size.map( +// ([originalSize, targetSize]) => ` +// .post-card--${originalSize} { +// ${postCardStyles[targetSize as string]?.styles} +// } +// `, +// )} + +// @media (max-width: ${props.theme.breakpoints.sm.width - 1}px) { +// } + +// @media (min-width: ${props.theme.breakpoints.sm.width}px) { +// ${props.pattern.sm && createGridStyles({ pattern: props.pattern.sm })} +// } + +// @media (min-width: ${props.theme.breakpoints.md.width}px) { +// ${props.pattern.md && createGridStyles({ pattern: props.pattern.md })} +// } + +// @media (min-width: ${props.theme.breakpoints.lg.width}px) { +// ${props.pattern.lg && createGridStyles({ pattern: props.pattern.lg })} +// } + +// styled.div` +// ${(props) => +// props.size === 'xxsmall' && +// css` +// > .row { +// padding: 24px 0; +// gap: 0 32px; + +// & > div { +// border-top: 0; +// padding: 0; +// position: relative; +// } + +// & > div:not(:last-child)::after { +// content: ' '; +// height: 100%; +// width: 1px; +// background: rgb(var(--lsd-border-primary)); +// position: absolute; +// top: 0; +// right: -16px; +// display: ${props.bordered ? 'block' : 'none'}; +// } +// } +// `} + +// ${(props) => +// props.size === 'xsmall' && +// css` +// > .row { +// gap: 0 16px; + +// & > div { +// box-sizing: border-box; +// border-top: 0; +// } + +// & > div:last-child { +// } +// & > div:not(:last-child) { +// } +// } +// `} + +// ${(props) => props.size === 'small' && css``} + +// ${(props) => props.size === 'medium' && css``} + +// ${(props) => props.size === 'large' && css``} // @media (max-width: ${( +// props, +// ) => props.theme.breakpoints.sm.width}) +// ` diff --git a/src/containers/HomePage/HomePage.tsx b/src/containers/HomePage/HomePage.tsx index 7485453..c2ba433 100644 --- a/src/containers/HomePage/HomePage.tsx +++ b/src/containers/HomePage/HomePage.tsx @@ -5,7 +5,6 @@ import { Hero } from '../../components/Hero' import { PostsGrid } from '../../components/PostsGrid' import { useRecentPosts } from '../../queries/useRecentPosts.query' import { LPE } from '../../types/lpe.types' -import { chunkArray } from '../../utils/array.utils' import { PodcastShowsPreview } from '../PodcastShowsPreview' export type HomePageProps = React.DetailedHTMLProps< @@ -28,29 +27,82 @@ export const HomePage: React.FC = ({ const query = useRecentPosts({ initialData: latest, limit: 10 }) const [group1, group2] = useMemo( - () => [[query.posts.slice(0, 5)], chunkArray(query.posts.slice(5), 4, 2)], + () => [query.posts.slice(0, 5), query.posts.slice(5)], [query.posts], ) return ( - + - {group2.map((group, index) => ( - - ))} + + {query.hasNextPage && (
@@ -176,4 +181,34 @@ const Root = styled('div')` } } } + + ${(props) => + lsdUtils.breakpoint( + props.theme, + 'xs', + 'exact', + )(css` + .podcasts__shows { + padding-top: 0; + grid-template-columns: repeat(1, 1fr); + } + + .podcasts__show { + border-right: none !important; + padding: 0 !important; + + &:not(:first-child) { + border-top: 1px solid rgb(var(--lsd-border-primary)); + } + } + + .podcasts__show-card { + margin-top: 0; + padding: 24px 0px 16px 0px; + } + + .podcasts__show-hosts { + margin-top: 80px; + } + `)} ` diff --git a/src/utils/math.utils.ts b/src/utils/math.utils.ts new file mode 100644 index 0000000..0dcb216 --- /dev/null +++ b/src/utils/math.utils.ts @@ -0,0 +1,3 @@ +export const gcd = (a: number, b: number): number => (a ? gcd(b % a, a) : b) + +export const lcm = (a: number, b: number): number => (a * b) / gcd(a, b) From c409b2e64323369e2b1715d50e936d570d43b137 Mon Sep 17 00:00:00 2001 From: Hossein Mehrabi Date: Thu, 24 Aug 2023 19:56:43 +0330 Subject: [PATCH 06/16] feat: responsive PostCard --- .../PostCard/PostCard.ShowDetails.tsx | 30 +++++-- src/components/PostCard/PostCard.tsx | 77 +++++++++++++++++- src/components/PostsGrid/PostsGrid.tsx | 81 +------------------ src/utils/lsd.utils.ts | 23 ++++-- 4 files changed, 115 insertions(+), 96 deletions(-) diff --git a/src/components/PostCard/PostCard.ShowDetails.tsx b/src/components/PostCard/PostCard.ShowDetails.tsx index c68ba40..c39b336 100644 --- a/src/components/PostCard/PostCard.ShowDetails.tsx +++ b/src/components/PostCard/PostCard.ShowDetails.tsx @@ -23,12 +23,14 @@ export const PostCardShowDetails = ({ episodeNumber, podcast, size = 'medium', + applySizeStyles = true, ...props }: PostCardShowDetailsProps) => { return (
@@ -65,7 +67,7 @@ PostCardShowDetails.styles = { } .show-details__episodes { - display: none; + display: none !important; } .show-details__logo { @@ -103,6 +105,7 @@ type CustomLinkProps = { smSize?: Size mdSize?: Size lgSize?: Size + applySizeStyles?: boolean } const CustomLink = styled(Link)` @@ -127,36 +130,47 @@ const CustomLink = styled(Link)` } &.show-details--small { - ${(props) => PostCardShowDetails.styles.small(props.theme)} + ${(props) => + props.applySizeStyles && PostCardShowDetails.styles.small(props.theme)} } &.show-details--medium { - ${(props) => PostCardShowDetails.styles.medium(props.theme)} + ${(props) => + props.applySizeStyles && PostCardShowDetails.styles.medium(props.theme)} } &.show-details--large { - ${(props) => PostCardShowDetails.styles.large(props.theme)} + ${(props) => + props.applySizeStyles && PostCardShowDetails.styles.large(props.theme)} } &.show-details { @media (max-width: ${({ theme }) => theme.breakpoints.sm.width - 1}px) { ${(props) => - props.xsSize && PostCardShowDetails.styles[props.xsSize](props.theme)} + props.xsSize && + props.applySizeStyles && + PostCardShowDetails.styles[props.xsSize](props.theme)} } @media (min-width: ${({ theme }) => theme.breakpoints.sm.width}px) { ${(props) => - props.smSize && PostCardShowDetails.styles[props.smSize](props.theme)} + props.smSize && + props.applySizeStyles && + PostCardShowDetails.styles[props.smSize](props.theme)} } @media (min-width: ${({ theme }) => theme.breakpoints.md.width}px) { ${(props) => - props.mdSize && PostCardShowDetails.styles[props.mdSize](props.theme)} + props.mdSize && + props.applySizeStyles && + PostCardShowDetails.styles[props.mdSize](props.theme)} } @media (min-width: ${({ theme }) => theme.breakpoints.lg.width}px) { ${(props) => - props.lgSize && PostCardShowDetails.styles[props.lgSize](props.theme)} + props.lgSize && + props.applySizeStyles && + PostCardShowDetails.styles[props.lgSize](props.theme)} } } ` diff --git a/src/components/PostCard/PostCard.tsx b/src/components/PostCard/PostCard.tsx index 3e42fd0..6e8b546 100644 --- a/src/components/PostCard/PostCard.tsx +++ b/src/components/PostCard/PostCard.tsx @@ -122,6 +122,7 @@ export const PostCard = (_props: PostCardProps) => { ) @@ -137,8 +138,8 @@ export const PostCard = (_props: PostCardProps) => { applySizeStyles && applySizeStyles && `post-card--${size}`, )} > - {labelElement} {coverImageElement} + {labelElement} {titleElement} {subtitleElement} {showElement} @@ -213,7 +214,26 @@ PostCard.styles = { display: flex; } - @media (max-width: ${theme.breakpoints.lg.width - 1}px) { + .post-card__show-details { + ${PostCardShowDetails.styles.small(theme)} + } + + ${lsdUtils.breakpoint(theme, 'sm', 'exact')} { + .post-card__authors { + display: flex; + flex-direction: column; + align-items: flex-start; + gap: 6px 0; + + > div { + > span { + display: none; + } + } + } + } + + ${lsdUtils.breakpoint(theme, 'md', 'down')} { .post-card__title-text { ${lsdUtils.typography('subtitle1', true)} max-height: calc(2 * var(--lsd-subtitle1-lineHeight)); @@ -237,6 +257,23 @@ PostCard.styles = { .post-card__show-details { ${PostCardShowDetails.styles.large(theme)} } + + ${lsdUtils.breakpoint(theme, 'md', 'down')} { + .post-card__title-text { + ${lsdUtils.typography('h5')} + + display: -webkit-box; + -webkit-line-clamp: 3; + -webkit-box-orient: vertical; + max-height: calc(3 * var(--lsd-h5-lineHeight)); + } + } + + ${lsdUtils.breakpoint(theme, 'xs', 'exact')} { + .post-card__show-details { + ${PostCardShowDetails.styles.small(theme)} + } + } `, medium: (theme: Theme) => css` .post-card__title-text { @@ -250,6 +287,17 @@ PostCard.styles = { .post-card__show-details { ${PostCardShowDetails.styles.large(theme)} } + + ${lsdUtils.breakpoint(theme, 'md', 'down')} { + .post-card__title-text { + ${lsdUtils.typography('h3')} + + display: -webkit-box; + -webkit-line-clamp: 3; + -webkit-box-orient: vertical; + max-height: calc(3 * var(--lsd-h3-lineHeight)); + } + } `, large: (theme: Theme) => css` display: grid; @@ -300,6 +348,31 @@ PostCard.styles = { .post-card__show-details { ${PostCardShowDetails.styles.large(theme)} } + + ${lsdUtils.breakpoint(theme, 'sm', 'exact')} { + gap: 16px 16px; + } + + ${lsdUtils.breakpoint(theme, 'md', 'exact')} { + gap: 16px 100px; + } + + ${lsdUtils.breakpoint(theme, 'md', 'down')} { + .post-card__title-text { + ${lsdUtils.typography('h3')} + + display: -webkit-box; + -webkit-line-clamp: 3; + -webkit-box-orient: vertical; + max-height: calc(3 * var(--lsd-h3-lineHeight)); + } + } + + ${lsdUtils.breakpoint(theme, 'xs', 'exact')} { + .post-card__title-text { + ${lsdUtils.typography('h5')} + } + } `, } diff --git a/src/components/PostsGrid/PostsGrid.tsx b/src/components/PostsGrid/PostsGrid.tsx index 07783ce..f903858 100644 --- a/src/components/PostsGrid/PostsGrid.tsx +++ b/src/components/PostsGrid/PostsGrid.tsx @@ -127,6 +127,7 @@ const createGridStyles = ({ grid-column: span ${cm / p.cols}; .post-card { + --post-card-size: ${p.size}; ${postCardStyles[p.size as string].styles} } } @@ -163,7 +164,7 @@ const Container = styled.div<{ ${lsdUtils .breakpoints(props.breakpoints.map((b) => b.breakpoint)) .map((breakpoint) => - lsdUtils.breakpoint( + lsdUtils.responsive( props.theme, breakpoint, 'exact', @@ -180,7 +181,7 @@ const Container = styled.div<{ ${({ breakpoints = [], theme, postCardStyles }) => { return breakpoints.map((b) => - lsdUtils.breakpoint( + lsdUtils.responsive( theme, b.breakpoint, 'exact', @@ -195,79 +196,3 @@ const Container = styled.div<{ ) }} ` -// ${b.size.map( -// ([originalSize, targetSize]) => ` -// .post-card--${originalSize} { -// ${postCardStyles[targetSize as string]?.styles} -// } -// `, -// )} - -// @media (max-width: ${props.theme.breakpoints.sm.width - 1}px) { -// } - -// @media (min-width: ${props.theme.breakpoints.sm.width}px) { -// ${props.pattern.sm && createGridStyles({ pattern: props.pattern.sm })} -// } - -// @media (min-width: ${props.theme.breakpoints.md.width}px) { -// ${props.pattern.md && createGridStyles({ pattern: props.pattern.md })} -// } - -// @media (min-width: ${props.theme.breakpoints.lg.width}px) { -// ${props.pattern.lg && createGridStyles({ pattern: props.pattern.lg })} -// } - -// styled.div` -// ${(props) => -// props.size === 'xxsmall' && -// css` -// > .row { -// padding: 24px 0; -// gap: 0 32px; - -// & > div { -// border-top: 0; -// padding: 0; -// position: relative; -// } - -// & > div:not(:last-child)::after { -// content: ' '; -// height: 100%; -// width: 1px; -// background: rgb(var(--lsd-border-primary)); -// position: absolute; -// top: 0; -// right: -16px; -// display: ${props.bordered ? 'block' : 'none'}; -// } -// } -// `} - -// ${(props) => -// props.size === 'xsmall' && -// css` -// > .row { -// gap: 0 16px; - -// & > div { -// box-sizing: border-box; -// border-top: 0; -// } - -// & > div:last-child { -// } -// & > div:not(:last-child) { -// } -// } -// `} - -// ${(props) => props.size === 'small' && css``} - -// ${(props) => props.size === 'medium' && css``} - -// ${(props) => props.size === 'large' && css``} // @media (max-width: ${( -// props, -// ) => props.theme.breakpoints.sm.width}) -// ` diff --git a/src/utils/lsd.utils.ts b/src/utils/lsd.utils.ts index 60dfb6a..9bcefed 100644 --- a/src/utils/lsd.utils.ts +++ b/src/utils/lsd.utils.ts @@ -4,7 +4,7 @@ import { TypographyVariants, THEME_BREAKPOINTS, } from '@acid-info/lsd-react' -import { css } from '@emotion/react' +import { css, SerializedStyles } from '@emotion/react' export class LsdUtils { breakpoints = (exclude: Breakpoints[] = []) => @@ -45,13 +45,20 @@ export class LsdUtils { } else if (func === 'down') media += `(max-width: ${max}px)` else media += `(min-width: ${min}px) and (max-width: ${max}px)` - return (styles: any) => { - return css` - ${media} { - ${styles} - } - ` - } + return `${media}` + } + + responsive = ( + theme: Theme, + breakpoint: Breakpoints, + func: 'exact' | 'up' | 'down' = 'up', + ) => { + const media = lsdUtils.breakpoint(theme, breakpoint, func) + return (styles: SerializedStyles) => css` + ${media} { + ${styles} + } + ` } } From c3db5e687317e62e71ca33ce095dc87fc5c1bbfa Mon Sep 17 00:00:00 2001 From: Hossein Mehrabi Date: Thu, 24 Aug 2023 19:57:01 +0330 Subject: [PATCH 07/16] fix: landing page grid settings --- src/containers/HomePage/HomePage.tsx | 8 -------- .../PodcastShowsPreview/PodcastShowsPreview.tsx | 10 +++++++++- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/containers/HomePage/HomePage.tsx b/src/containers/HomePage/HomePage.tsx index c2ba433..800acdd 100644 --- a/src/containers/HomePage/HomePage.tsx +++ b/src/containers/HomePage/HomePage.tsx @@ -53,14 +53,6 @@ export const HomePage: React.FC = ({ cols: 2, size: 'medium', }, - { - cols: 3, - size: 'small', - }, - { - cols: 5, - size: 'medium', - }, ]} breakpoints={[ { diff --git a/src/containers/PodcastShowsPreview/PodcastShowsPreview.tsx b/src/containers/PodcastShowsPreview/PodcastShowsPreview.tsx index 67f5926..0713444 100644 --- a/src/containers/PodcastShowsPreview/PodcastShowsPreview.tsx +++ b/src/containers/PodcastShowsPreview/PodcastShowsPreview.tsx @@ -97,6 +97,14 @@ export const PodcastShowsPreview: React.FC = ({ breakpoint: 'xs', pattern: [{ cols: 1, size: 'small' }], }, + { + breakpoint: 'sm', + pattern: [{ cols: 2, size: 'small' }], + }, + { + breakpoint: 'md', + pattern: [{ cols: 2, size: 'small' }], + }, ]} />
@@ -183,7 +191,7 @@ const Root = styled('div')` } ${(props) => - lsdUtils.breakpoint( + lsdUtils.responsive( props.theme, 'xs', 'exact', From 49df825cd488ea36cb16d671136bf156136a94e2 Mon Sep 17 00:00:00 2001 From: Hossein Mehrabi Date: Thu, 24 Aug 2023 20:49:20 +0330 Subject: [PATCH 08/16] fix: make show details stick to the bottom of the xxsmall PostCard --- src/components/PostCard/PostCard.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/components/PostCard/PostCard.tsx b/src/components/PostCard/PostCard.tsx index 6e8b546..7ac509a 100644 --- a/src/components/PostCard/PostCard.tsx +++ b/src/components/PostCard/PostCard.tsx @@ -212,6 +212,7 @@ PostCard.styles = { .post-card__show-details { flex-grow: 1; display: flex; + align-items: flex-end; } .post-card__show-details { From 1315d9c7f1411df87f0c5b2907eaebc0ab02538a Mon Sep 17 00:00:00 2001 From: Hossein Mehrabi Date: Thu, 24 Aug 2023 20:49:55 +0330 Subject: [PATCH 09/16] feat: add support for horizontal scroll in the PostsGrid component --- src/components/PostsGrid/PostsGrid.tsx | 120 ++++++++++++++++++------- 1 file changed, 87 insertions(+), 33 deletions(-) diff --git a/src/components/PostsGrid/PostsGrid.tsx b/src/components/PostsGrid/PostsGrid.tsx index f903858..1b43732 100644 --- a/src/components/PostsGrid/PostsGrid.tsx +++ b/src/components/PostsGrid/PostsGrid.tsx @@ -21,6 +21,7 @@ export const PostsGrid: React.FC = ({ pattern = [], breakpoints = [], bordered = false, + horizontal = false, displayPodcastShow = true, ...props }) => { @@ -57,6 +58,7 @@ export const PostsGrid: React.FC = ({ pattern={pattern} breakpoints={breakpoints} bordered={bordered} + horizontal={horizontal} postCardStyles={postCardStyles} >
@@ -79,6 +81,7 @@ export const PostsGrid: React.FC = ({ type Pattern = { cols: number + maxWidth?: string size: PostCardProps['size'] } type Breakpoint = { @@ -91,55 +94,104 @@ const createGridStyles = ({ pattern = [], postCardStyles, breakpoint = false, + horizontal = false, }: { theme: Theme postCardStyles: { [name: string]: SerializedStyles } - pattern: Pick[] + pattern: Pick[] breakpoint?: boolean + horizontal?: boolean }) => { - const cm = pattern.map((p) => p.cols).reduce(lcm, 1) - const sum = Math.max( - 1, - pattern.reduce((p, c) => p + c.cols, 0), - ) + const grid = !horizontal - let selectorNumber = 0 - const selectors = pattern.map((p) => { - const start = selectorNumber + 1 - selectorNumber += p.cols + if (grid) { + const cm = pattern.map((p) => p.cols).reduce(lcm, 1) + const sum = Math.max( + 1, + pattern.reduce((p, c) => p + c.cols, 0), + ) - return new Array(p.cols) - .fill(null) - .map((i, index) => `${sum}n + ${start + index}`) - }) + let selectorNumber = 0 + const selectors = pattern.map((p) => { + const start = selectorNumber + 1 + selectorNumber += p.cols - return css` - > .row { - display: grid; - grid-template-columns: repeat(${cm}, 1fr); + return new Array(p.cols) + .fill(null) + .map((i, index) => `${sum}n + ${start + index}`) + }) - & > div { - ${pattern.map( - (p, i) => ` - ${selectors[i].map((s) => `&:nth-child(${s})`).join(', ')} { - grid-column: span ${cm / p.cols}; + return css` + > .row { + display: grid; + grid-template-columns: repeat(${cm}, 1fr); - .post-card { - --post-card-size: ${p.size}; - ${postCardStyles[p.size as string].styles} - } - } - `, - )} + & > div { + ${pattern.map( + (p, i) => css` + ${selectors[i].map((s) => `&:nth-child(${s})`).join(', ')} { + grid-column: span ${cm / p.cols}; + + .post-card { + --post-card-size: ${p.size}; + ${postCardStyles[p.size as string].styles} + } + } + `, + )} + } } - } - ` + ` + } else { + return css` + overflow: hidden; + + > .row { + display: flex; + flex-direction: row; + flex-wrap: unwrap; + justify-content: flex-start; + width: 100%; + overflow: scroll; + scroll-snap-type: x mandatory; + + /* Chrome, Safari and Opera */ + &::-webkit-scrollbar { + width: 0; + display: none; + } + + /* Firefox, Edge and IE */ + -ms-overflow-style: none; + scrollbar-width: none; + + & > div { + ${pattern.map( + (p, i) => css` + max-width: ${p.maxWidth ? p.maxWidth : 'unset'}; + flex-grow: 1 auto; + flex-shrink: 0; + width: calc((100% - (${p.cols - 1} * 16px)) / ${p.cols}); + flex-basis: calc((100% - (${p.cols - 1} * 16px)) / ${p.cols}); + scroll-snap-align: start !important; + + .post-card { + --post-card-size: ${p.size}; + ${postCardStyles[p.size as string].styles} + } + `, + )} + } + } + ` + } } const Container = styled.div<{ bordered: boolean + horizontal?: boolean pattern: Pattern[] breakpoints: Breakpoint[] postCardStyles: { @@ -171,6 +223,7 @@ const Container = styled.div<{ )(css` ${createGridStyles({ theme: props.theme, + horizontal: props.horizontal, pattern: props.pattern, postCardStyles: props.postCardStyles, breakpoint: true, @@ -179,7 +232,7 @@ const Container = styled.div<{ )} `} - ${({ breakpoints = [], theme, postCardStyles }) => { + ${({ breakpoints = [], theme, postCardStyles, horizontal }) => { return breakpoints.map((b) => lsdUtils.responsive( theme, @@ -188,6 +241,7 @@ const Container = styled.div<{ )(css` ${createGridStyles({ theme, + horizontal, pattern: b.pattern, postCardStyles, breakpoint: true, From 187c6de312ae72138ce05d1014b4cc920e2210aa Mon Sep 17 00:00:00 2001 From: Hossein Mehrabi Date: Thu, 24 Aug 2023 20:51:26 +0330 Subject: [PATCH 10/16] feat: enable horizontal scroll for the five most recent posts on the landing page --- src/containers/HomePage/HomePage.tsx | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/src/containers/HomePage/HomePage.tsx b/src/containers/HomePage/HomePage.tsx index 800acdd..08920a3 100644 --- a/src/containers/HomePage/HomePage.tsx +++ b/src/containers/HomePage/HomePage.tsx @@ -34,7 +34,25 @@ export const HomePage: React.FC = ({ return ( - + Date: Thu, 24 Aug 2023 20:55:50 +0330 Subject: [PATCH 11/16] fix: hide the year of most recent posts on the landing page --- src/components/PostCard/PostCard.Label.tsx | 14 ++++++++++++-- src/components/PostCard/PostCard.tsx | 3 +++ src/components/PostsGrid/PostsGrid.tsx | 3 +++ src/containers/HomePage/HomePage.tsx | 1 + 4 files changed, 19 insertions(+), 2 deletions(-) diff --git a/src/components/PostCard/PostCard.Label.tsx b/src/components/PostCard/PostCard.Label.tsx index f614260..d801842 100644 --- a/src/components/PostCard/PostCard.Label.tsx +++ b/src/components/PostCard/PostCard.Label.tsx @@ -7,9 +7,15 @@ import PostType = LPE.PostType export type Props = React.ComponentProps & { contentType: PostType date: Date | null + displayYear?: boolean } -export const PostCardLabel: FC = ({ contentType, date, ...props }) => { +export const PostCardLabel: FC = ({ + displayYear = true, + contentType, + date, + ...props +}) => { return ( @@ -23,7 +29,11 @@ export const PostCardLabel: FC = ({ contentType, date, ...props }) => { date.toLocaleString('en-GB', { day: 'numeric', month: 'long', // TODO: Should be uppercase - year: 'numeric', + ...(displayYear + ? { + year: 'numeric', + } + : {}), })} diff --git a/src/components/PostCard/PostCard.tsx b/src/components/PostCard/PostCard.tsx index 7ac509a..7d66e7d 100644 --- a/src/components/PostCard/PostCard.tsx +++ b/src/components/PostCard/PostCard.tsx @@ -41,6 +41,7 @@ export type PostCardProps = CommonProps & size?: 'xxsmall' | 'xsmall' | 'small' | 'medium' | 'large' applySizeStyles?: boolean displayPodcastShow?: boolean + displayYear?: boolean } export const PostCard = (_props: PostCardProps) => { @@ -60,6 +61,7 @@ export const PostCard = (_props: PostCardProps) => { contentType, applySizeStyles = true, displayPodcastShow = true, + displayYear = true, ...props } = _props @@ -81,6 +83,7 @@ export const PostCard = (_props: PostCardProps) => { ) diff --git a/src/components/PostsGrid/PostsGrid.tsx b/src/components/PostsGrid/PostsGrid.tsx index 1b43732..aa52cfc 100644 --- a/src/components/PostsGrid/PostsGrid.tsx +++ b/src/components/PostsGrid/PostsGrid.tsx @@ -13,6 +13,7 @@ export type PostsGridProps = Partial> & { shows?: LPE.Podcast.Show[] posts?: LPE.Post.Document[] displayPodcastShow?: boolean + displayYear?: boolean } export const PostsGrid: React.FC = ({ @@ -23,6 +24,7 @@ export const PostsGrid: React.FC = ({ bordered = false, horizontal = false, displayPodcastShow = true, + displayYear = true, ...props }) => { const theme = useTheme() @@ -69,6 +71,7 @@ export const PostsGrid: React.FC = ({ applySizeStyles={false} className="post-card" contentType={post.type} + displayYear={displayYear} displayPodcastShow={displayPodcastShow} data={PostCard.toData(post, shows)} /> diff --git a/src/containers/HomePage/HomePage.tsx b/src/containers/HomePage/HomePage.tsx index 08920a3..59fe67a 100644 --- a/src/containers/HomePage/HomePage.tsx +++ b/src/containers/HomePage/HomePage.tsx @@ -37,6 +37,7 @@ export const HomePage: React.FC = ({ Date: Thu, 24 Aug 2023 21:45:43 +0330 Subject: [PATCH 12/16] fix: fix spacing and border style of most recent posts --- src/components/PostsGrid/PostsGrid.tsx | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/src/components/PostsGrid/PostsGrid.tsx b/src/components/PostsGrid/PostsGrid.tsx index aa52cfc..f8f774b 100644 --- a/src/components/PostsGrid/PostsGrid.tsx +++ b/src/components/PostsGrid/PostsGrid.tsx @@ -159,6 +159,7 @@ const createGridStyles = ({ width: 100%; overflow: scroll; scroll-snap-type: x mandatory; + gap: 0 32px; /* Chrome, Safari and Opera */ &::-webkit-scrollbar { @@ -176,14 +177,27 @@ const createGridStyles = ({ max-width: ${p.maxWidth ? p.maxWidth : 'unset'}; flex-grow: 1 auto; flex-shrink: 0; - width: calc((100% - (${p.cols - 1} * 16px)) / ${p.cols}); - flex-basis: calc((100% - (${p.cols - 1} * 16px)) / ${p.cols}); + width: calc((100% - (${p.cols - 1} * 32px)) / ${p.cols}); + flex-basis: calc((100% - (${p.cols - 1} * 32px)) / ${p.cols}); scroll-snap-align: start !important; + position: relative; .post-card { --post-card-size: ${p.size}; ${postCardStyles[p.size as string].styles} } + + &:not(:last-child) { + &::after { + width: 1px; + height: calc(100% - 48px); + content: ' '; + right: -16px; + top: 24px; + background: rgb(var(--lsd-border-primary)); + position: absolute; + } + } `, )} } From 6ecdc38d521dad413721de5820ce00b67d873cfb Mon Sep 17 00:00:00 2001 From: Hossein Mehrabi Date: Thu, 24 Aug 2023 21:51:25 +0330 Subject: [PATCH 13/16] fix: fix load more posts button size --- src/containers/HomePage/HomePage.tsx | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/containers/HomePage/HomePage.tsx b/src/containers/HomePage/HomePage.tsx index 59fe67a..96def0b 100644 --- a/src/containers/HomePage/HomePage.tsx +++ b/src/containers/HomePage/HomePage.tsx @@ -5,6 +5,7 @@ import { Hero } from '../../components/Hero' import { PostsGrid } from '../../components/PostsGrid' import { useRecentPosts } from '../../queries/useRecentPosts.query' import { LPE } from '../../types/lpe.types' +import { lsdUtils } from '../../utils/lsd.utils' import { PodcastShowsPreview } from '../PodcastShowsPreview' export type HomePageProps = React.DetailedHTMLProps< @@ -145,6 +146,18 @@ const Root = styled('div')` button { width: 340px; } + + ${(props) => lsdUtils.breakpoint(props.theme, 'md', 'down')} { + button { + width: 236px; + } + } + + ${(props) => lsdUtils.breakpoint(props.theme, 'xs', 'exact')} { + button { + width: 100%; + } + } } .podcasts { From 1583ca83bed59747e006dd46c7c9e9655c18fd22 Mon Sep 17 00:00:00 2001 From: Hossein Mehrabi Date: Thu, 24 Aug 2023 22:05:44 +0330 Subject: [PATCH 14/16] fix: restore show episodes border style --- src/components/PostsGrid/PostsGrid.tsx | 18 +++++++++++++++++- .../PodcastShowsPreview.tsx | 17 ++++++++++++++--- 2 files changed, 31 insertions(+), 4 deletions(-) diff --git a/src/components/PostsGrid/PostsGrid.tsx b/src/components/PostsGrid/PostsGrid.tsx index f8f774b..2267a87 100644 --- a/src/components/PostsGrid/PostsGrid.tsx +++ b/src/components/PostsGrid/PostsGrid.tsx @@ -86,6 +86,7 @@ type Pattern = { cols: number maxWidth?: string size: PostCardProps['size'] + rowBorder?: boolean } type Breakpoint = { pattern: Pattern[] @@ -103,7 +104,7 @@ const createGridStyles = ({ postCardStyles: { [name: string]: SerializedStyles } - pattern: Pick[] + pattern: Pick[] breakpoint?: boolean horizontal?: boolean }) => { @@ -130,12 +131,27 @@ const createGridStyles = ({ > .row { display: grid; grid-template-columns: repeat(${cm}, 1fr); + overflow: hidden; & > div { ${pattern.map( (p, i) => css` ${selectors[i].map((s) => `&:nth-child(${s})`).join(', ')} { grid-column: span ${cm / p.cols}; + position: relative; + + ${p.rowBorder && + css` + &::before { + width: calc(100% + 16px); + height: 1px; + content: ' '; + top: 0; + left: 0px; + position: absolute; + background: rgb(var(--lsd-border-primary)); + } + `} .post-card { --post-card-size: ${p.size}; diff --git a/src/containers/PodcastShowsPreview/PodcastShowsPreview.tsx b/src/containers/PodcastShowsPreview/PodcastShowsPreview.tsx index 0713444..ad6d8bc 100644 --- a/src/containers/PodcastShowsPreview/PodcastShowsPreview.tsx +++ b/src/containers/PodcastShowsPreview/PodcastShowsPreview.tsx @@ -91,19 +91,30 @@ export const PodcastShowsPreview: React.FC = ({ cols: 2, size: 'xsmall', }, + { + cols: 2, + size: 'xsmall', + rowBorder: true, + }, ]} breakpoints={[ { breakpoint: 'xs', - pattern: [{ cols: 1, size: 'small' }], + pattern: [{ cols: 1, size: 'small', rowBorder: true }], }, { breakpoint: 'sm', - pattern: [{ cols: 2, size: 'small' }], + pattern: [ + { cols: 2, size: 'small' }, + { cols: 2, size: 'small', rowBorder: true }, + ], }, { breakpoint: 'md', - pattern: [{ cols: 2, size: 'small' }], + pattern: [ + { cols: 2, size: 'small' }, + { cols: 2, size: 'small', rowBorder: true }, + ], }, ]} /> From 8664c5e288ea4d9340dffcc681713b68fe277f6b Mon Sep 17 00:00:00 2001 From: Hossein Mehrabi Date: Thu, 24 Aug 2023 23:48:47 +0330 Subject: [PATCH 15/16] feat: enhance PostsGrid's border styling options --- src/components/PostsGrid/PostsGrid.tsx | 86 ++++++++++++++++++++------ 1 file changed, 67 insertions(+), 19 deletions(-) diff --git a/src/components/PostsGrid/PostsGrid.tsx b/src/components/PostsGrid/PostsGrid.tsx index 2267a87..c93e63a 100644 --- a/src/components/PostsGrid/PostsGrid.tsx +++ b/src/components/PostsGrid/PostsGrid.tsx @@ -86,7 +86,7 @@ type Pattern = { cols: number maxWidth?: string size: PostCardProps['size'] - rowBorder?: boolean + rowBorder?: boolean | 'except-first-row' } type Breakpoint = { pattern: Pattern[] @@ -99,6 +99,7 @@ const createGridStyles = ({ postCardStyles, breakpoint = false, horizontal = false, + bordered = false, }: { theme: Theme postCardStyles: { @@ -107,6 +108,7 @@ const createGridStyles = ({ pattern: Pick[] breakpoint?: boolean horizontal?: boolean + bordered: boolean | 'except-first-row' }) => { const grid = !horizontal @@ -127,6 +129,12 @@ const createGridStyles = ({ .map((i, index) => `${sum}n + ${start + index}`) }) + const firstRow = new Array(pattern?.[0]?.cols ?? 0) + .fill(null) + .map((v, i) => i + 1) + .map((i) => `&:nth-child(${i})`) + .join(', ') + return css` > .row { display: grid; @@ -134,32 +142,72 @@ const createGridStyles = ({ overflow: hidden; & > div { - ${pattern.map( - (p, i) => css` - ${selectors[i].map((s) => `&:nth-child(${s})`).join(', ')} { + ${bordered && + css` + border-top: 1px solid rgb(var(--lsd-border-primary)); + `} + + ${bordered === 'except-first-row' && + css` + ${firstRow} { + border-top: none; + } + `} + + ${pattern.map((p, i) => { + const firstRow = new Array(p.cols) + .fill(null) + .map((v, i) => i + 1) + .map((i) => `&:nth-child(${i})`) + .join(', ') + + const rowSelectors = selectors[i].map((s) => `&:nth-child(${s})`) + const firstSelector = rowSelectors[0] + const lastSelector = rowSelectors[rowSelectors.length - 1] + + return css` + ${rowSelectors.join(', ')} { grid-column: span ${cm / p.cols}; position: relative; ${p.rowBorder && + bordered && css` - &::before { - width: calc(100% + 16px); - height: 1px; - content: ' '; - top: 0; - left: 0px; - position: absolute; - background: rgb(var(--lsd-border-primary)); - } + border-top: none; `} + ${p.rowBorder && + css` + ${firstSelector} { + &::before { + width: calc(100% * ${p.cols} + 16px); + height: 1px; + content: ' '; + top: 0; + left: 0px; + position: absolute; + display: block; + background: rgb(var(--lsd-border-primary)); + } + } + `} + + ${p.rowBorder === 'except-first-row' && + css` + ${firstRow} { + &::before { + display: none !important; + } + } + `} + .post-card { --post-card-size: ${p.size}; ${postCardStyles[p.size as string].styles} } } - `, - )} + ` + })} } } ` @@ -223,7 +271,7 @@ const createGridStyles = ({ } const Container = styled.div<{ - bordered: boolean + bordered: boolean | 'except-first-row' horizontal?: boolean pattern: Pattern[] breakpoints: Breakpoint[] @@ -241,8 +289,6 @@ const Container = styled.div<{ & > div { padding: 24px 0; - border-top: ${props.bordered ? '1px' : '0'} solid - rgb(var(--lsd-border-primary)); } } @@ -260,12 +306,13 @@ const Container = styled.div<{ pattern: props.pattern, postCardStyles: props.postCardStyles, breakpoint: true, + bordered: props.bordered, })} `), )} `} - ${({ breakpoints = [], theme, postCardStyles, horizontal }) => { + ${({ breakpoints = [], theme, postCardStyles, horizontal, bordered }) => { return breakpoints.map((b) => lsdUtils.responsive( theme, @@ -278,6 +325,7 @@ const Container = styled.div<{ pattern: b.pattern, postCardStyles, breakpoint: true, + bordered, })} `), ) From 8f98901eed5b2c3ad1e4646c5881567e2a4cbe0d Mon Sep 17 00:00:00 2001 From: Hossein Mehrabi Date: Thu, 24 Aug 2023 23:49:44 +0330 Subject: [PATCH 16/16] fix: restore broken episode list component --- src/components/Podcasts/Episodes.List.tsx | 32 +++++++------- src/containers/PodcastShowContainer.tsx | 47 ++++++++++++++++++--- src/containers/PodcastsContainer.tsx | 51 ++++++++++++++++++++--- 3 files changed, 105 insertions(+), 25 deletions(-) diff --git a/src/components/Podcasts/Episodes.List.tsx b/src/components/Podcasts/Episodes.List.tsx index 36eab05..f9bdfce 100644 --- a/src/components/Podcasts/Episodes.List.tsx +++ b/src/components/Podcasts/Episodes.List.tsx @@ -2,36 +2,38 @@ import styled from '@emotion/styled' import { LPE } from '../../types/lpe.types' import { PostsGrid, PostsGridProps } from '../PostsGrid' -interface Props { +interface Props {} + +export type EpisodesListProps = Partial< + React.ComponentProps +> & { header?: React.ReactNode episodes: LPE.Podcast.Document[] shows?: LPE.Podcast.Show[] - bordered?: boolean - size?: string - cols?: number displayShow?: boolean -} +} & Pick export default function EpisodesList({ shows = [], + episodes = [], + pattern, + breakpoints, + bordered, header, - episodes, - bordered = false, - cols = 4, - size = 'small', displayShow = true, -}: Props) { + ...props +}: EpisodesListProps) { return ( - + {header} - {/* */} + /> ) } diff --git a/src/containers/PodcastShowContainer.tsx b/src/containers/PodcastShowContainer.tsx index 99cfad2..4192010 100644 --- a/src/containers/PodcastShowContainer.tsx +++ b/src/containers/PodcastShowContainer.tsx @@ -29,21 +29,58 @@ const PodcastShowContainer = (props: Props) => { All episodes} + bordered="except-first-row" + pattern={[ + { + cols: 2, + size: 'medium', + }, + ]} + breakpoints={[ + { + breakpoint: 'xs', + pattern: [ + { + cols: 1, + size: 'small', + rowBorder: 'except-first-row', + }, + ], + }, + ]} /> 0 ? true : 'except-first-row' + } + pattern={[ + { + cols: 4, + size: 'small', + }, + ]} + breakpoints={[ + { + breakpoint: 'xs', + pattern: [{ cols: 1, size: 'small' }], + }, + { + breakpoint: 'sm', + pattern: [{ cols: 4, size: 'xsmall' }], + }, + { + breakpoint: 'md', + pattern: [{ cols: 4, size: 'xsmall' }], + }, + ]} /> diff --git a/src/containers/PodcastsContainer.tsx b/src/containers/PodcastsContainer.tsx index 707bd44..bbd07de 100644 --- a/src/containers/PodcastsContainer.tsx +++ b/src/containers/PodcastsContainer.tsx @@ -23,16 +23,45 @@ const PodcastsContainer = (props: Props) => { Latest Episodes} + pattern={[{ cols: 2, size: 'medium' }]} + breakpoints={[ + { + breakpoint: 'xs', + pattern: [ + { cols: 1, size: 'small', rowBorder: 'except-first-row' }, + ], + }, + { + breakpoint: 'sm', + pattern: [{ cols: 2, size: 'small' }], + }, + { + breakpoint: 'md', + pattern: [{ cols: 2, size: 'small' }], + }, + ]} /> @@ -56,8 +85,20 @@ const PodcastsContainer = (props: Props) => { } shows={[show]} + bordered="except-first-row" displayShow={false} - episodes={show.episodes as LPE.Podcast.Document[]} + episodes={(show.episodes as LPE.Podcast.Document[]).slice(0, 4)} + pattern={[{ cols: 4, size: 'small' }]} + breakpoints={[ + { + breakpoint: 'xs', + pattern: [{ cols: 1, size: 'small' }], + }, + { + breakpoint: 'sm', + pattern: [{ cols: 2, size: 'small' }], + }, + ]} /> ))}