Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/highlighted post preview #1004

Merged
merged 16 commits into from
Nov 2, 2023
53 changes: 47 additions & 6 deletions src/components/PostPreview/PostPreview.scss
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
@use '@eleven-labs/design-system/scss/abstracts' as *;
@use "@eleven-labs/design-system/scss/abstracts" as *;

$border-radius: 4px;

@mixin multi-line-ellipsis($line-height: 1.2em, $line-count: 1, $bg-color: var(--color-white)) {
overflow: hidden;
Expand All @@ -9,14 +11,14 @@
padding-right: 1em;

&::before {
content: '...';
content: "...";
position: absolute;
right: 0;
bottom: 0;
}

&::after {
content: '';
content: "";
position: absolute;
right: 0;
width: 1em;
Expand All @@ -26,24 +28,63 @@
}
}

@mixin post-preview-card {
box-shadow: 0 4px 4px rgb(0 0 0 / 20%);
border-radius: $border-radius;
}

.post-preview {
--max-height-post-preview-mask: 44px;

&--mask {
max-height: var(--max-height-post-preview-mask);

@include create-media-queries('md') {
@include create-media-queries("md") {
--max-height-post-preview-mask: 24px;
}

mask-image: linear-gradient(#000, transparent);
}

&--related {
@include post-preview-card;

padding: var(--spacing-s);
background-color: var(--color-white);
border-radius: 4px;
box-shadow: 0 4px 4px rgb(0 0 0 / 20%);
}

&--highlighted {
@include post-preview-card;

display: flex;
flex-direction: column;
position: relative;

article {
padding: var(--spacing-s);
}

.sparkle {
display: none;
}

@include create-media-queries("md") {
flex-direction: row;
align-items: center;
justify-content: center;
height: 100%;

.sparkle {
display: block;
top: 50%;
transform: translate(-50%, -50%);
left: calc(var(--spacing-xl) * -1);
width: 47px;
height: 108px;
position: absolute;
background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg"><line x1="33.1063" y1="3.06202" x2="44.1118" y2="14.4606" stroke="%23F3C93D" stroke-width="5" stroke-linecap="round"/><line x1="2.5" y1="-2.5" x2="18.3445" y2="-2.5" transform="matrix(0.694595 -0.719401 -0.719401 -0.694595 29.5713 105.469)" stroke="%23F3C93D" stroke-width="5" stroke-linecap="round"/><line x1="3" y1="50.8906" x2="41.0134" y2="50.8906" stroke="%23F3C93D" stroke-width="6" stroke-linecap="round"/></svg>');
}
}
}

&__excerpt {
Expand Down
10 changes: 10 additions & 0 deletions src/components/PostPreview/PostPreview.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,11 @@ export default {
} as Meta<typeof PostPreview>;

const Template: StoryFn<typeof PostPreview> = (args) => <PostPreview {...args} />;
const TemplateWithMargin: StoryFn<typeof PostPreview> = (args) => (
<div style={{ margin: '0 2.5em' }}>
<PostPreview {...args} />
</div>
);

export const Overview = Template.bind({});

Expand Down Expand Up @@ -52,3 +57,8 @@ PostPreviewIsRelated.parameters = {
PostPreviewIsRelated.args = {
isRelated: true,
};

export const PostPreviewIsHighlighted = TemplateWithMargin.bind({});
PostPreviewIsHighlighted.args = {
isHighlighted: true,
};
61 changes: 21 additions & 40 deletions src/components/PostPreview/PostPreview.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import './PostPreview.scss';

import { AsProps, Box, BoxProps, Flex, Heading, Link, Skeleton, Text } from '@eleven-labs/design-system';
import classNames from 'classnames';
import { AsProps, BoxProps } from '@eleven-labs/design-system';
import React from 'react';

import { ArticleMetadata, TutoTag } from '@/components';
import { ArticleMetadata } from '@/components';
import { ContentTypeEnum } from '@/constants';

import { PostPreviewCard } from './PostPreviewCard';
import { PostPreviewContent } from './PostPreviewContent';

export type PostPreviewOptions = {
contentType?: ContentTypeEnum.ARTICLE | ContentTypeEnum.TUTORIAL;
title?: React.ReactNode;
Expand All @@ -15,9 +15,11 @@ export type PostPreviewOptions = {
readingTime?: number;
authors?: { username: string; name: string }[];
link?: AsProps<'a'>;
image?: { source: string; alt: string };
hasMask?: boolean;
isRelated?: boolean;
isLoading?: boolean;
isHighlighted?: boolean;
};

export type PostPreviewProps = PostPreviewOptions & BoxProps;
Expand All @@ -33,39 +35,18 @@ export const PostPreview: React.FC<PostPreviewProps> = ({
hasMask,
isRelated,
isLoading = false,
isHighlighted = false,
...boxProps
}) => {
const titleBlock = hasMask ? (
(title as React.JSX.Element)
) : (
<Link {...link} data-internal-link={isRelated ? 'relatedPost' : 'post'}>
{title}
</Link>
);
return (
<Box
as="article"
className={classNames('post-preview', { 'post-preview--mask': hasMask }, { 'post-preview--related': isRelated })}
{...boxProps}
>
<Skeleton isLoading={isLoading}>
<Heading as="h2" color="amaranth" size="s">
{contentType === ContentTypeEnum.TUTORIAL ? (
<Flex gap="xxs">
<TutoTag />
{titleBlock}
</Flex>
) : (
titleBlock
)}
</Heading>
</Skeleton>
<Skeleton isLoading={isLoading} style={{ height: 75 }}>
<Text size="s" className="post-preview__excerpt">
{excerpt}
</Text>
</Skeleton>
<ArticleMetadata mt={{ xs: 'xs', md: 's' }} date={date} readingTime={readingTime} authors={authors} />
</Box>
);
};
}) => (
<PostPreviewCard isHighlighted={isHighlighted} hasMask={hasMask} isRelated={isRelated} {...boxProps}>
<PostPreviewContent
isLoading={isLoading}
isRelated={isRelated}
title={title}
link={link}
excerpt={excerpt}
hasMask={hasMask}
/>
<ArticleMetadata mt={{ xs: 'xs', md: 's' }} date={date} readingTime={readingTime} authors={authors} />
</PostPreviewCard>
);
46 changes: 46 additions & 0 deletions src/components/PostPreview/PostPreviewCard.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import './PostPreview.scss';

import { Box } from '@eleven-labs/design-system';
import classNames from 'classnames';
import React from 'react';

interface PostPreviewCardProps {
hasMask?: boolean;
isRelated?: boolean;
isLoading?: boolean;
isHighlighted?: boolean;
children: React.ReactNode;
}

export const PostPreviewCard: React.FC<PostPreviewCardProps> = ({
isHighlighted,
hasMask,
isRelated,
children,
...props
}) => {
const Container: React.FC<{ children: React.ReactNode }> = ({ children }) =>
isHighlighted ? (
<Box className={classNames({ 'post-preview--highlighted': isHighlighted })}>
<div className="sparkle" />
{children}
</Box>
) : (
<>{children}</>
);
return (
<Container>
<Box
as="article"
className={classNames(
'post-preview',
{ 'post-preview--mask': hasMask },
{ 'post-preview--related': isRelated }
)}
{...props}
>
{children}
</Box>
</Container>
);
};
44 changes: 44 additions & 0 deletions src/components/PostPreview/PostPreviewContent.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import './PostPreview.scss';

import { AsProps } from '@eleven-labs/design-system';
import { Heading, Link, Skeleton, Text } from '@eleven-labs/design-system';
import React from 'react';

interface PostPreviewContentProps {
title?: React.ReactNode;
excerpt?: React.ReactNode;
link?: AsProps<'a'>;
hasMask?: boolean;
isRelated?: boolean;
isLoading?: boolean;
}

export const PostPreviewContent: React.FC<PostPreviewContentProps> = ({
isLoading,
hasMask,
title,
link,
isRelated,
excerpt,
}) => {
return (
<>
<Skeleton isLoading={isLoading}>
<Heading as="h2" color="amaranth" size="s" mb={{ xs: 'xxs-3', md: 'xxs' }}>
{hasMask ? (
title
) : (
<Link {...link} data-internal-link={isRelated ? 'relatedPost' : 'post'}>
{title}
</Link>
)}
</Heading>
</Skeleton>
<Skeleton isLoading={isLoading} style={{ height: 75 }}>
<Text size="s" className="post-preview__excerpt">
{excerpt}
</Text>
</Skeleton>
</>
);
};
13 changes: 13 additions & 0 deletions src/pages/PostListPage/PostListPage.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import React from 'react';
import { PostPreviewList, PostPreviewListProps } from '@/components';
import NewsletterBlockStories from '@/components/NewsletterBlock/NewsletterBlock.stories';
import * as PostPreviewListStories from '@/components/PostPreviewList/PostPreviewList.stories';
import { ContentTypeEnum } from '@/constants';
import { PostListPage } from '@/pages';

export default {
Expand All @@ -26,6 +27,18 @@ export default {
{ label: 'Bonnes pratiques' },
],
},
highlightedPostTitle: 'Notre article du moment',
highlightedPost: {
contentType: ContentTypeEnum.ARTICLE,
title: `Highlighted article`,
date: '09 fév. 2021',
readingTime: 24,
authors: [{ username: 'jdoe', name: 'J. Doe' }],
excerpt:
'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed hendrerit vel tellus in molestie. Curabitur malesuada sodales consectetur. Aliquam convallis nec lacus in euismod. Vestibulum id eros vitae tellus sodales ultricies eget eu ipsum.',
isLoading: false,
isHighlighted: true,
},
title: 'Tous nos articles',
postPreviewList: React.createElement<PostPreviewListProps>(PostPreviewList, {
...PostPreviewListStories.default.args,
Expand Down
23 changes: 20 additions & 3 deletions src/pages/PostListPage/PostListPage.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Text } from '@eleven-labs/design-system';
import { Box, Text } from '@eleven-labs/design-system';
import React from 'react';

import { Container, NewsletterBlock, NewsletterBlockProps } from '@/components';
import { Container, NewsletterBlock, NewsletterBlockProps, PostPreview, PostPreviewProps } from '@/components';

import { SubHeader, SubHeaderProps } from './SubHeader';

Expand All @@ -10,13 +10,30 @@ export type PostListPageProps = {
title: React.ReactNode;
postPreviewList: React.ReactNode;
newsletterBlock: NewsletterBlockProps;
highlightedPost?: PostPreviewProps;
highlightedPostTitle?: string;
};

export const PostListPage: React.FC<PostListPageProps> = ({ subHeader, title, postPreviewList, newsletterBlock }) => (
export const PostListPage: React.FC<PostListPageProps> = ({
subHeader,
title,
postPreviewList,
newsletterBlock,
highlightedPost,
highlightedPostTitle,
}) => (
<>
<SubHeader {...subHeader} />
<Container variant="global" mt={{ xs: 'l', md: 'xl' }}>
<Container variant="content">
{highlightedPost && (
<Box mb="xl">
<Text size="m" my="s" fontWeight="medium">
{highlightedPostTitle}
</Text>
<PostPreview {...highlightedPost} isHighlighted />
</Box>
)}
<Text size="m" my="m" fontWeight="medium">
{title}
</Text>
Expand Down
Loading