Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 12 additions & 25 deletions packages/shared/src/components/cards/Freeform/FreeformGrid.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import type { ReactElement, Ref } from 'react';
import React, { forwardRef, useRef } from 'react';
import classNames from 'classnames';
import type { PostCardProps } from '../common/common';
import { Container, generateTitleClamp } from '../common/common';
import { Container } from '../common/common';
import { usePostImage } from '../../../hooks/post/usePostImage';
import FeedItemContainer from '../common/FeedItemContainer';
import {
Expand All @@ -21,6 +20,7 @@ import {
glassCoverImageClassName,
} from '../common/FeedCardGlassActions';
import { ClickbaitShield } from '../common/ClickbaitShield';
import PostTags from '../common/PostTags';
import { useSmartTitle } from '../../../hooks/post/useSmartTitle';
import { useFeedCardGlassActions } from '../../../hooks/useFeedCardGlassActions';
import { useHiddenFeedbackPanel } from '../../../hooks/post/useHiddenFeedbackPanel';
Expand Down Expand Up @@ -90,36 +90,22 @@ export const FreeformGrid = forwardRef(function SharePostCard(
post={post}
enableSourceHeader={enableSourceHeader}
/>
<FreeformCardTitle
className={classNames(
generateTitleClamp({
hasImage: !!image,
hasHtmlContent: !!post.contentHtml,
}),
)}
>
{title}
</FreeformCardTitle>
<FreeformCardTitle className="line-clamp-3">{title}</FreeformCardTitle>
</CardTextContainer>
<>
{image && <CardSpace />}
<div
className={classNames(
'mx-4 mb-2 flex items-center',
!image && 'mt-1',
)}
>
{/* Match the collection card: push the tags + date to the bottom of the
text area, just above the footer (cover image or text preview). */}
<Container>
<CardSpace />
<div className="mx-4 flex items-center">
{post.clickbaitTitleDetected && <ClickbaitShield post={post} />}
<PostTags post={post} />
</div>
<PostMetadata
className={classNames(
'mx-4 line-clamp-1 break-words',
image ? 'mt-0' : 'mt-1',
)}
className="mx-4"
createdAt={post.createdAt}
readTime={post.readTime}
/>
</>
</Container>
<Container
ref={containerRef}
className={useGlass && image ? 'flex-none' : undefined}
Expand All @@ -132,6 +118,7 @@ export const FreeformGrid = forwardRef(function SharePostCard(
imageClassName={
useGlass && image ? glassCoverImageClassName : undefined
}
contentClassName="min-h-[10.5rem]"
/>
{useGlass ? (
<FeedCardGlassActions
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import FeedItemContainer from '../common/list/FeedItemContainer';
import { CardContainer, CardContent, CardTitle } from '../common/list/ListCard';
import { PostCardHeader } from '../common/list/PostCardHeader';
import { CardCoverList } from '../common/list/CardCover';
import PostTags from '../common/PostTags';
import ActionButtons from '../common/ActionButtons';
import { HIGH_PRIORITY_IMAGE_PROPS } from '../../image/Image';
import { ClickbaitShield } from '../common/ClickbaitShield';
Expand Down Expand Up @@ -167,6 +168,8 @@ export const FreeformList = forwardRef(function SharePostCard(
</CardTitle>

{post.clickbaitTitleDetected && <ClickbaitShield post={post} />}
<div className="flex flex-1 tablet:hidden" />
<PostTags post={post} />
<div className="hidden flex-1 tablet:flex" />
{!isMobile && actionButtons}
</div>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import type { ReactElement } from 'react';
import React from 'react';
import classNames from 'classnames';
import { CollectionPillSources } from '../../post/collection/CollectionPillSources';
import { getCollectionPillLabel } from '../../post/collection/common';
import { CollectionSourceStack } from '../../post/collection/CollectionSourceStack';
import {
BookmakProviderHeader,
headerHiddenClassName,
Expand Down Expand Up @@ -31,23 +30,24 @@ export const CollectionCardHeader = ({
return (
<>
{highlightBookmarkedPost && <BookmakProviderHeader />}
<CollectionPillSources
className={{
main: classNames(
'mb-1 mt-3',
highlightBookmarkedPost && headerHiddenClassName,
),
}}
sources={sources ?? []}
totalSources={totalSources ?? 0}
label={getCollectionPillLabel(post)}
<div
className={classNames(
// mt-4 matches the article card's CardHeader top margin so the title
// (and the tags/date below it) start on the same row.
'mb-1 mt-4 flex flex-row items-center',
highlightBookmarkedPost && headerHiddenClassName,
)}
>
<CollectionSourceStack
sources={sources ?? []}
totalSources={totalSources ?? 0}
/>
<div className="flex-1" />
<PostOptionButton
post={post}
triggerClassName="laptop:mouse:invisible laptop:mouse:group-hover:visible"
/>
</CollectionPillSources>
</div>
</>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,6 @@ export const CollectionFeaturedWideGridCard = forwardRef(
wasUpdated ? TimeFormatType.PostUpdated : TimeFormatType.Post
}
readTime={post.readTime}
numSources={post.numCollectionSources}
className="mt-1"
/>
{!!post.summary && (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -107,20 +107,31 @@ it('should hide read time when not available', async () => {
expect(screen.queryByTestId('readTime')).not.toBeInTheDocument();
});

it('should display the `collection` pill in the header', async () => {
renderComponent();
await screen.findByText('Collection');
});

it('should display the `Trend` pill when the post source is trends', async () => {
it('should display the collection source stack in the header', async () => {
renderComponent({
post: {
...post,
source: { ...post.source, id: 'trends' } as Post['source'],
},
collectionSources: [
{
id: 'src1',
handle: 'src1',
name: 'Source One',
image: 'https://daily.dev/src1.png',
permalink: 'https://daily.dev/sources/src1',
},
{
id: 'src2',
handle: 'src2',
name: 'Source Two',
image: 'https://daily.dev/src2.png',
permalink: 'https://daily.dev/sources/src2',
},
],
numCollectionSources: 2,
} as Post,
});
await screen.findByText('Trend');
expect(screen.queryByText('Collection')).not.toBeInTheDocument();
await screen.findByAltText('Avatar of src1');
await screen.findByAltText('Avatar of src2');
});

it('should show options button on hover when in laptop size', async () => {
Expand Down
45 changes: 29 additions & 16 deletions packages/shared/src/components/cards/collection/CollectionGrid.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,14 @@ import type { Ref } from 'react';
import React, { forwardRef } from 'react';
import classNames from 'classnames';
import type { PostCardProps } from '../common/common';
import { Container, generateTitleClamp } from '../common/common';
import { Container } from '../common/common';
import FeedItemContainer from '../common/FeedItemContainer';
import { CollectionCardHeader } from './CollectionCardHeader';
import {
getPostClassNames,
FreeformCardTitle,
CardTextContainer,
CardSpace,
} from '../common/Card';
import { WelcomePostCardFooter } from '../common/WelcomePostCardFooter';
import ActionButtons from '../common/ActionButtons';
Expand Down Expand Up @@ -69,6 +70,16 @@ export const CollectionGrid = forwardRef(function CollectionCard(
);
}

const postMetadata = (
<PostMetadata
createdAt={wasUpdated ? post.updatedAt : post.createdAt}
dateLabel={wasUpdated ? 'Updated' : undefined}
dateType={wasUpdated ? TimeFormatType.PostUpdated : TimeFormatType.Post}
readTime={post.readTime}
className="mx-4"
/>
);

return (
<FeedItemContainer
domProps={{
Expand All @@ -88,30 +99,27 @@ export const CollectionGrid = forwardRef(function CollectionCard(
onPostCardClick={onPostCardClick}
onPostCardAuxClick={onPostCardAuxClick}
/>
<CardTextContainer className="mx-4 flex-1">
<CardTextContainer className="mx-4">
<CollectionCardHeader post={post} />
<FreeformCardTitle
className={classNames(
generateTitleClamp({
hasImage: !!image,
hasHtmlContent: !!post.contentHtml,
}),
// Match the default article card's title guideline: clamp to 3 lines
// at natural height (no fixed reserve).
'line-clamp-3',
'font-bold text-text-primary typo-title3',
)}
>
{post.title}
</FreeformCardTitle>

<PostTags post={post} className="!items-end" />
</CardTextContainer>
<PostMetadata
createdAt={wasUpdated ? post.updatedAt : post.createdAt}
dateLabel={wasUpdated ? 'Updated' : undefined}
dateType={wasUpdated ? TimeFormatType.PostUpdated : TimeFormatType.Post}
readTime={post.readTime}
numSources={post.numCollectionSources}
className={classNames('mx-4', post.image ? 'my-0' : 'mb-4 mt-2')}
/>
{/* Push the tags + date to the bottom of the text area, just above the
footer (cover image or freeform text preview), matching the default
article card so they align regardless of title length. */}
<Container>
<CardSpace />
<PostTags post={post} className="mx-4" />
{postMetadata}
</Container>
<Container className={useGlass && image ? 'flex-none' : undefined}>
<WelcomePostCardFooter
image={image}
Expand All @@ -122,6 +130,11 @@ export const CollectionGrid = forwardRef(function CollectionCard(
imageClassName={
useGlass && image ? glassCoverImageClassName : undefined
}
// Give the freeform text preview the same footer height as the cover
// image slot (h-40 image + its mt-2/mb-1 margins = 10.5rem) so the
// tags/date bottom-anchor to the same row as the image cards and the
// default article card.
contentClassName="min-h-[10.5rem]"
/>
{useGlass ? (
<FeedCardGlassActions
Expand Down
17 changes: 7 additions & 10 deletions packages/shared/src/components/cards/collection/CollectionList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,7 @@ import {
import ActionButtons from '../common/ActionButtons';
import { usePostImage } from '../../../hooks/post/usePostImage';
import { PostCardHeader } from '../common/list/PostCardHeader';
import { CollectionPillSources } from '../../post/collection/CollectionPillSources';
import { getCollectionPillLabel } from '../../post/collection/common';
import { CollectionSourceStack } from '../../post/collection/CollectionSourceStack';
import { useTruncatedSummary, useViewSize, ViewSize } from '../../../hooks';
import PostTags from '../common/PostTags';
import { CardCoverList } from '../common/list/CardCover';
Expand Down Expand Up @@ -108,18 +107,16 @@ export const CollectionList = forwardRef(function CollectionCard(
dateType: wasUpdated
? TimeFormatType.PostUpdated
: TimeFormatType.Post,
numSources: post.numCollectionSources,
}}
>
<CollectionPillSources
className={{
main: classNames(!!post.collectionSources?.length && '-my-0.5'),
avatar: 'group-hover:border-background-subtle',
}}
<CollectionSourceStack
className={classNames(
!!post.collectionSources?.length && '-my-0.5',
)}
sources={post.collectionSources ?? []}
totalSources={post.numCollectionSources ?? 0}
alwaysShowSources
label={getCollectionPillLabel(post)}
alwaysExpanded
enableHoverCard={false}
/>
</PostCardHeader>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ interface WelcomePostCardFooterProps {
contentHtml?: string;
onShare?: (post: Post) => void;
imageClassName?: string;
contentClassName?: string;
glassActions?: boolean;
}

Expand All @@ -22,6 +23,7 @@ export const WelcomePostCardFooter = ({
onShare,
contentHtml,
imageClassName,
contentClassName,
glassActions = false,
}: WelcomePostCardFooterProps): ReactElement | null => {
const { overlay } = useCardCover({
Expand Down Expand Up @@ -74,6 +76,7 @@ export const WelcomePostCardFooter = ({
// The glass action bar floats over the card bottom. Clamp one line
// tighter and reserve its height (pb-12) so text never sits under it.
glassActions ? 'line-clamp-5 pb-12' : 'line-clamp-6',
contentClassName,
)}
>
{decodedText}
Expand Down
Loading
Loading