From ad84b2a3555b644eff0967a3948efc9fb6466ba4 Mon Sep 17 00:00:00 2001 From: Nimrod Kramer <41470823+nimrodkra@users.noreply.github.com> Date: Sun, 26 Apr 2026 15:26:57 +0300 Subject: [PATCH 1/3] feat: add Happening Now sidebar widget on post pages Adds a compact, rotating "Happening Now" widget to article, squad and collection post sidebars (covers post pages and post modals). Gated behind the new `post_page_highlights` GrowthBook flag. Made-with: Cursor --- .../HighlightPostSidebarWidget.spec.tsx | 191 ++++++++++++++++ .../highlight/HighlightPostSidebarWidget.tsx | 210 ++++++++++++++++++ .../src/components/cards/highlight/common.tsx | 71 +++--- .../src/components/post/PostWidgets.tsx | 2 + .../src/components/post/SquadPostWidgets.tsx | 2 + .../post/collection/CollectionPostWidgets.tsx | 2 + packages/shared/src/lib/featureManagement.ts | 4 + packages/shared/src/lib/feed.ts | 4 +- 8 files changed, 459 insertions(+), 27 deletions(-) create mode 100644 packages/shared/src/components/cards/highlight/HighlightPostSidebarWidget.spec.tsx create mode 100644 packages/shared/src/components/cards/highlight/HighlightPostSidebarWidget.tsx diff --git a/packages/shared/src/components/cards/highlight/HighlightPostSidebarWidget.spec.tsx b/packages/shared/src/components/cards/highlight/HighlightPostSidebarWidget.spec.tsx new file mode 100644 index 0000000000..9af0e0d9c0 --- /dev/null +++ b/packages/shared/src/components/cards/highlight/HighlightPostSidebarWidget.spec.tsx @@ -0,0 +1,191 @@ +import React from 'react'; +import { act, render, screen, waitFor } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; +import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; +import { HighlightPostSidebarWidget } from './HighlightPostSidebarWidget'; +import { useAuthContext } from '../../../contexts/AuthContext'; +import { useConditionalFeature } from '../../../hooks/useConditionalFeature'; +import { useLogContext } from '../../../contexts/LogContext'; +import { gqlClient } from '../../../graphql/common'; + +jest.mock('../../../lib/constants', () => ({ + webappUrl: '/', + isDevelopment: false, +})); + +jest.mock('../../../contexts/AuthContext'); +jest.mock('../../../hooks/useConditionalFeature'); +jest.mock('../../../contexts/LogContext'); +jest.mock('../../../graphql/common', () => ({ + gqlClient: { + request: jest.fn(), + }, +})); + +const mockUseAuthContext = jest.mocked(useAuthContext); +const mockUseConditionalFeature = jest.mocked(useConditionalFeature); +const mockUseLogContext = jest.mocked(useLogContext); +const mockGqlRequest = jest.mocked(gqlClient.request); + +const buildHighlight = (id: string, headline: string) => ({ + id, + channel: 'agents', + headline, + highlightedAt: '2026-04-05T09:00:00.000Z', + post: { + id: `post-${id}`, + commentsPermalink: `/posts/post-${id}`, + }, +}); + +const buildResponse = (highlights: ReturnType[]) => ({ + majorHeadlines: { + edges: highlights.map((node) => ({ node, cursor: node.id })), + pageInfo: { hasNextPage: false, endCursor: null }, + }, +}); + +const renderWidget = () => { + const client = new QueryClient({ + defaultOptions: { queries: { retry: false, gcTime: 0 } }, + }); + return render( + + + , + ); +}; + +describe('HighlightPostSidebarWidget', () => { + const logEvent = jest.fn(); + + beforeEach(() => { + jest.clearAllMocks(); + mockGqlRequest.mockReset(); + mockUseAuthContext.mockReturnValue({ + user: { id: 'u1' }, + // eslint-disable-next-line @typescript-eslint/no-explicit-any + } as any); + mockUseConditionalFeature.mockReturnValue({ + value: true, + isLoading: false, + }); + mockUseLogContext.mockReturnValue({ + logEvent, + // eslint-disable-next-line @typescript-eslint/no-explicit-any + } as any); + }); + + afterEach(() => { + jest.useRealTimers(); + }); + + it('renders title and the first headline when query resolves', async () => { + mockGqlRequest.mockResolvedValue( + buildResponse([ + buildHighlight('h1', 'The first highlight'), + buildHighlight('h2', 'The second highlight'), + ]), + ); + + renderWidget(); + + expect(await screen.findByText('Happening Now')).toBeInTheDocument(); + expect(screen.getByText('The first highlight')).toBeInTheDocument(); + expect(screen.queryByText('The second highlight')).not.toBeInTheDocument(); + }); + + it('returns null when no highlights are returned', async () => { + mockGqlRequest.mockResolvedValue(buildResponse([])); + + renderWidget(); + + await waitFor(() => expect(mockGqlRequest).toHaveBeenCalled()); + expect(screen.queryByText('Happening Now')).not.toBeInTheDocument(); + expect( + screen.queryByTestId('postPageHighlightWidget'), + ).not.toBeInTheDocument(); + }); + + it('returns null when feature flag is off', () => { + mockUseConditionalFeature.mockReturnValue({ + value: false, + isLoading: false, + }); + mockGqlRequest.mockResolvedValue( + buildResponse([buildHighlight('h1', 'Hidden headline')]), + ); + + renderWidget(); + + expect(screen.queryByText('Happening Now')).not.toBeInTheDocument(); + expect( + screen.queryByTestId('postPageHighlightWidget'), + ).not.toBeInTheDocument(); + }); + + it('points "Read all" to /highlights with the first highlight id', async () => { + mockGqlRequest.mockResolvedValue( + buildResponse([buildHighlight('first', 'First headline')]), + ); + + renderWidget(); + + const readAll = await screen.findByLabelText('Read all highlights'); + expect(readAll).toHaveAttribute('href', '/highlights?highlight=first'); + }); + + it('rotates headlines after the interval', async () => { + jest.useFakeTimers({ doNotFake: ['queueMicrotask'] }); + mockGqlRequest.mockResolvedValue( + buildResponse([ + buildHighlight('h1', 'The first highlight'), + buildHighlight('h2', 'The second highlight'), + ]), + ); + + renderWidget(); + + await act(async () => { + await Promise.resolve(); + }); + + await waitFor(() => + expect(screen.getByText('The first highlight')).toBeInTheDocument(), + ); + + await act(async () => { + jest.advanceTimersByTime(6000); + }); + await act(async () => { + jest.advanceTimersByTime(500); + }); + + expect(screen.getByText('The second highlight')).toBeInTheDocument(); + expect(screen.queryByText('The first highlight')).not.toBeInTheDocument(); + }); + + it('pauses rotation while hovering', async () => { + mockGqlRequest.mockResolvedValue( + buildResponse([ + buildHighlight('h1', 'The first highlight'), + buildHighlight('h2', 'The second highlight'), + ]), + ); + + renderWidget(); + const article = await screen.findByTestId('postPageHighlightWidget'); + expect(screen.getByText('The first highlight')).toBeInTheDocument(); + + await userEvent.hover(article); + + jest.useFakeTimers(); + await act(async () => { + jest.advanceTimersByTime(6000); + jest.advanceTimersByTime(500); + }); + + expect(screen.getByText('The first highlight')).toBeInTheDocument(); + expect(screen.queryByText('The second highlight')).not.toBeInTheDocument(); + }); +}); diff --git a/packages/shared/src/components/cards/highlight/HighlightPostSidebarWidget.tsx b/packages/shared/src/components/cards/highlight/HighlightPostSidebarWidget.tsx new file mode 100644 index 0000000000..1e57370906 --- /dev/null +++ b/packages/shared/src/components/cards/highlight/HighlightPostSidebarWidget.tsx @@ -0,0 +1,210 @@ +import type { ReactElement } from 'react'; +import React, { + useCallback, + useEffect, + useRef, + useState, +} from 'react'; +import classNames from 'classnames'; +import { useQuery } from '@tanstack/react-query'; +import { WidgetContainer } from '../../widgets/common'; +import { + getHighlightsUrl, + highlightsTitleGradientClassName, +} from './common'; +import { + majorHeadlinesQueryOptions, + type PostHighlight, +} from '../../../graphql/highlights'; +import { RelativeTime } from '../../utilities/RelativeTime'; +import Link from '../../utilities/Link'; +import { useAuthContext } from '../../../contexts/AuthContext'; +import { useConditionalFeature } from '../../../hooks/useConditionalFeature'; +import { featurePostPageHighlights } from '../../../lib/featureManagement'; +import { useLogContext } from '../../../contexts/LogContext'; +import { LogEvent, Origin } from '../../../lib/log'; +import { feedHighlightsLogEvent } from '../../../lib/feed'; +import useLogEventOnce from '../../../hooks/log/useLogEventOnce'; + +const HIGHLIGHTS_LIMIT = 10; +const ROTATION_INTERVAL_MS = 6000; +const FADE_DURATION_MS = 500; +const FEED_NAME = 'post-page-highlights'; + +const prefersReducedMotion = (): boolean => { + if (typeof window === 'undefined' || !window.matchMedia) { + return false; + } + return window.matchMedia('(prefers-reduced-motion: reduce)').matches; +}; + +export const HighlightPostSidebarWidget = (): ReactElement | null => { + const { user } = useAuthContext(); + const { logEvent } = useLogContext(); + const { value: isEnabled } = useConditionalFeature({ + feature: featurePostPageHighlights, + shouldEvaluate: !!user, + }); + + const { data } = useQuery({ + ...majorHeadlinesQueryOptions({ first: HIGHLIGHTS_LIMIT }), + enabled: isEnabled && !!user, + }); + + const highlights: PostHighlight[] = + data?.majorHeadlines?.edges?.map((edge) => edge.node) ?? []; + + const [index, setIndex] = useState(0); + const [isVisible, setIsVisible] = useState(true); + const [isPaused, setIsPaused] = useState(false); + const fadeOutTimeoutRef = useRef | null>(null); + + const hasHighlights = highlights.length > 0; + const shouldRender = isEnabled && hasHighlights; + const canRotate = shouldRender && highlights.length > 1 && !isPaused; + + useLogEventOnce( + () => + feedHighlightsLogEvent(LogEvent.Impression, { + feedName: FEED_NAME, + action: 'impression', + count: highlights.length, + highlightIds: highlights.map((h) => h.id), + origin: Origin.ArticlePage, + }), + { condition: shouldRender }, + ); + + useEffect(() => { + if (index >= highlights.length && highlights.length > 0) { + setIndex(0); + } + }, [highlights.length, index]); + + useEffect(() => { + if (!canRotate) { + return undefined; + } + + const reducedMotion = prefersReducedMotion(); + const interval = setInterval(() => { + if (typeof document !== 'undefined' && document.hidden) { + return; + } + + if (reducedMotion) { + setIndex((prev) => (prev + 1) % highlights.length); + return; + } + + setIsVisible(false); + fadeOutTimeoutRef.current = setTimeout(() => { + setIndex((prev) => (prev + 1) % highlights.length); + setIsVisible(true); + }, FADE_DURATION_MS); + }, ROTATION_INTERVAL_MS); + + return () => { + clearInterval(interval); + if (fadeOutTimeoutRef.current) { + clearTimeout(fadeOutTimeoutRef.current); + fadeOutTimeoutRef.current = null; + } + }; + }, [canRotate, highlights.length]); + + const onPauseStart = useCallback(() => setIsPaused(true), []); + const onPauseEnd = useCallback(() => setIsPaused(false), []); + + if (!shouldRender) { + return null; + } + + const current = highlights[Math.min(index, highlights.length - 1)]; + const firstHighlight = highlights[0]; + + const onHighlightClick = () => { + logEvent( + feedHighlightsLogEvent(LogEvent.Click, { + feedName: FEED_NAME, + action: 'highlight_click', + position: index + 1, + count: highlights.length, + clickedHighlight: current, + highlightIds: highlights.map((h) => h.id), + origin: Origin.ArticlePage, + }), + ); + }; + + const onReadAllClick = () => { + logEvent( + feedHighlightsLogEvent(LogEvent.Click, { + feedName: FEED_NAME, + action: 'read_all_click', + count: highlights.length, + highlightIds: highlights.map((h) => h.id), + origin: Origin.ArticlePage, + }), + ); + }; + + const headlineHref = getHighlightsUrl(current.id); + + return ( + +

+ Happening Now +

+
+ + + + {current.headline} + + + + +
+ + + Read all + + → + + + +
+ ); +}; diff --git a/packages/shared/src/components/cards/highlight/common.tsx b/packages/shared/src/components/cards/highlight/common.tsx index 5560f76429..7444270d02 100644 --- a/packages/shared/src/components/cards/highlight/common.tsx +++ b/packages/shared/src/components/cards/highlight/common.tsx @@ -12,16 +12,53 @@ export interface HighlightCardProps { onReadAllClick?: () => void; } -const titleGradientClassName = 'feed-highlights-title-gradient'; +export const highlightsTitleGradientClassName = 'feed-highlights-title-gradient'; const HIGHLIGHTS_URL = `${webappUrl}highlights`; -const getHighlightsUrl = (highlightId?: string): string => +export const getHighlightsUrl = (highlightId?: string): string => highlightId ? `${HIGHLIGHTS_URL}?highlight=${highlightId}` : HIGHLIGHTS_URL; const getHighlightUrl = (highlight: PostHighlight): string => getHighlightsUrl(highlight.id); +export const ReadAllHighlightsFooter = ({ + highlightId, + onClick, + className, +}: { + highlightId?: string; + onClick?: () => void; + className?: string; +}): ReactElement => { + const href = getHighlightsUrl(highlightId); + return ( +
+ + onClick?.()} + > + + Read all + + + → + + + +
+ ); +}; + const HighlightRow = ({ highlight, index, @@ -73,7 +110,7 @@ export const HighlightCardContent = ({

@@ -90,29 +127,11 @@ export const HighlightCardContent = ({ /> ))} -
- - onReadAllClick?.()} - > - - Read all - - - → - - - -
+ ); }; diff --git a/packages/shared/src/components/post/PostWidgets.tsx b/packages/shared/src/components/post/PostWidgets.tsx index 9feb64a7ad..5f5ea16f10 100644 --- a/packages/shared/src/components/post/PostWidgets.tsx +++ b/packages/shared/src/components/post/PostWidgets.tsx @@ -16,6 +16,7 @@ import EntityCardSkeleton from '../cards/entity/EntityCardSkeleton'; import { PostSidebarAdWidget } from './PostSidebarAdWidget'; import { FeaturedArchives } from '../widgets/FeaturedArchives'; import { PostSignupWidget } from './PostSignupWidget'; +import { HighlightPostSidebarWidget } from '../cards/highlight/HighlightPostSidebarWidget'; const UserEntityCard = dynamic( /* webpackChunkName: "userEntityCard" */ () => @@ -102,6 +103,7 @@ export function PostWidgets({ link={post.commentsPermalink} onCopyPostLink={onCopyPostLink} /> + {tokenRefreshed && } diff --git a/packages/shared/src/components/post/SquadPostWidgets.tsx b/packages/shared/src/components/post/SquadPostWidgets.tsx index 483ecbcae0..d209c32c9b 100644 --- a/packages/shared/src/components/post/SquadPostWidgets.tsx +++ b/packages/shared/src/components/post/SquadPostWidgets.tsx @@ -17,6 +17,7 @@ import type { UserShortProfile } from '../../lib/user'; import { PostSidebarAdWidget } from './PostSidebarAdWidget'; import { FeaturedArchives } from '../widgets/FeaturedArchives'; import { PostSignupWidget } from './PostSignupWidget'; +import { HighlightPostSidebarWidget } from '../cards/highlight/HighlightPostSidebarWidget'; export function SquadPostWidgets({ onCopyPostLink, @@ -76,6 +77,7 @@ export function SquadPostWidgets({ /> )} + {tokenRefreshed && } diff --git a/packages/shared/src/components/post/collection/CollectionPostWidgets.tsx b/packages/shared/src/components/post/collection/CollectionPostWidgets.tsx index 9b42cca302..fe2605c75b 100644 --- a/packages/shared/src/components/post/collection/CollectionPostWidgets.tsx +++ b/packages/shared/src/components/post/collection/CollectionPostWidgets.tsx @@ -11,6 +11,7 @@ import { FooterLinks } from '../../footer'; import { PostSidebarAdWidget } from '../PostSidebarAdWidget'; import { FeaturedArchives } from '../../widgets/FeaturedArchives'; import { PostSignupWidget } from '../PostSignupWidget'; +import { HighlightPostSidebarWidget } from '../../cards/highlight/HighlightPostSidebarWidget'; export const CollectionPostWidgets = ({ onCopyPostLink, @@ -37,6 +38,7 @@ export const CollectionPostWidgets = ({ onCopyPostLink={onCopyPostLink} link={post.commentsPermalink} /> + diff --git a/packages/shared/src/lib/featureManagement.ts b/packages/shared/src/lib/featureManagement.ts index 08cb456228..2295000c61 100644 --- a/packages/shared/src/lib/featureManagement.ts +++ b/packages/shared/src/lib/featureManagement.ts @@ -33,6 +33,10 @@ export const discussedFeedVersion = new Feature('discussed_feed_version', 2); export const latestFeedVersion = new Feature('latest_feed_version', 2); export const customFeedVersion = new Feature('custom_feed_version', 2); export const featureFeedV2Highlights = new Feature('feed_v2_highlights', false); +export const featurePostPageHighlights = new Feature( + 'post_page_highlights', + false, +); // @ts-expect-error stale feature without default export const plusTakeoverContent = new Feature<{ diff --git a/packages/shared/src/lib/feed.ts b/packages/shared/src/lib/feed.ts index b4a97ae582..7e0b17853c 100644 --- a/packages/shared/src/lib/feed.ts +++ b/packages/shared/src/lib/feed.ts @@ -180,6 +180,7 @@ interface FeedHighlightsLogEventOptions extends FeedItemPosition { highlightIds?: string[]; feedMeta?: string | null; position?: number; + origin?: Origin; } export function feedHighlightsLogEvent( @@ -196,6 +197,7 @@ export function feedHighlightsLogEvent( highlightIds, feedMeta, position, + origin, }: FeedHighlightsLogEventOptions, ): FeedItemLogEvent { return { @@ -208,7 +210,7 @@ export function feedHighlightsLogEvent( feed_item_title: clickedHighlight?.headline, target_type: TargetType.HighlightsCard, extra: JSON.stringify({ - ...feedLogExtra(feedName, ranking).extra, + ...feedLogExtra(feedName, ranking, undefined, origin).extra, ...(action ? { action } : {}), ...(typeof count === 'number' ? { count } : {}), ...(typeof position === 'number' ? { position } : {}), From 5b0f3b4171d188936e88783e832d644ca129d942 Mon Sep 17 00:00:00 2001 From: Nimrod Kramer <41470823+nimrodkra@users.noreply.github.com> Date: Sun, 26 Apr 2026 15:33:39 +0300 Subject: [PATCH 2/3] test: strengthen hover-pause and add impression coverage - Restructure hover-pause test to fake-time before render so the rotation interval is live, then verify rotation actually pauses on hover and resumes on unhover (previously the test passed because the interval was never created during pause). - Add a test asserting the impression event fires when highlights load. Made-with: Cursor --- .../HighlightPostSidebarWidget.spec.tsx | 54 ++++++++++++++++--- 1 file changed, 47 insertions(+), 7 deletions(-) diff --git a/packages/shared/src/components/cards/highlight/HighlightPostSidebarWidget.spec.tsx b/packages/shared/src/components/cards/highlight/HighlightPostSidebarWidget.spec.tsx index 9af0e0d9c0..35644612ae 100644 --- a/packages/shared/src/components/cards/highlight/HighlightPostSidebarWidget.spec.tsx +++ b/packages/shared/src/components/cards/highlight/HighlightPostSidebarWidget.spec.tsx @@ -1,6 +1,5 @@ import React from 'react'; -import { act, render, screen, waitFor } from '@testing-library/react'; -import userEvent from '@testing-library/user-event'; +import { act, fireEvent, render, screen, waitFor } from '@testing-library/react'; import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; import { HighlightPostSidebarWidget } from './HighlightPostSidebarWidget'; import { useAuthContext } from '../../../contexts/AuthContext'; @@ -165,7 +164,8 @@ describe('HighlightPostSidebarWidget', () => { expect(screen.queryByText('The first highlight')).not.toBeInTheDocument(); }); - it('pauses rotation while hovering', async () => { + it('pauses rotation while hovering and resumes after unhover', async () => { + jest.useFakeTimers({ doNotFake: ['queueMicrotask'] }); mockGqlRequest.mockResolvedValue( buildResponse([ buildHighlight('h1', 'The first highlight'), @@ -174,18 +174,58 @@ describe('HighlightPostSidebarWidget', () => { ); renderWidget(); - const article = await screen.findByTestId('postPageHighlightWidget'); - expect(screen.getByText('The first highlight')).toBeInTheDocument(); - await userEvent.hover(article); + await act(async () => { + await Promise.resolve(); + }); + await waitFor(() => + expect(screen.getByText('The first highlight')).toBeInTheDocument(), + ); + + const widget = screen.getByTestId('postPageHighlightWidget'); + + await act(async () => { + fireEvent.mouseEnter(widget); + }); - jest.useFakeTimers(); await act(async () => { jest.advanceTimersByTime(6000); + }); + await act(async () => { jest.advanceTimersByTime(500); }); expect(screen.getByText('The first highlight')).toBeInTheDocument(); expect(screen.queryByText('The second highlight')).not.toBeInTheDocument(); + + await act(async () => { + fireEvent.mouseLeave(widget); + }); + + await act(async () => { + jest.advanceTimersByTime(6000); + }); + await act(async () => { + jest.advanceTimersByTime(500); + }); + + expect(screen.getByText('The second highlight')).toBeInTheDocument(); + expect(screen.queryByText('The first highlight')).not.toBeInTheDocument(); + }); + + it('logs an impression when highlights load', async () => { + mockGqlRequest.mockResolvedValue( + buildResponse([buildHighlight('h1', 'A headline')]), + ); + + renderWidget(); + + await screen.findByText('Happening Now'); + + await waitFor(() => + expect(logEvent).toHaveBeenCalledWith( + expect.objectContaining({ event_name: 'impression' }), + ), + ); }); }); From 56fdce92c4f55554bfbe4216c48cea52259e563a Mon Sep 17 00:00:00 2001 From: Nimrod Kramer <41470823+nimrodkra@users.noreply.github.com> Date: Sun, 26 Apr 2026 15:41:29 +0300 Subject: [PATCH 3/3] chore: prettier formatting Made-with: Cursor --- .../HighlightPostSidebarWidget.spec.tsx | 8 +++++++- .../highlight/HighlightPostSidebarWidget.tsx | 19 ++++--------------- .../src/components/cards/highlight/common.tsx | 3 ++- 3 files changed, 13 insertions(+), 17 deletions(-) diff --git a/packages/shared/src/components/cards/highlight/HighlightPostSidebarWidget.spec.tsx b/packages/shared/src/components/cards/highlight/HighlightPostSidebarWidget.spec.tsx index 35644612ae..84b0dd575b 100644 --- a/packages/shared/src/components/cards/highlight/HighlightPostSidebarWidget.spec.tsx +++ b/packages/shared/src/components/cards/highlight/HighlightPostSidebarWidget.spec.tsx @@ -1,5 +1,11 @@ import React from 'react'; -import { act, fireEvent, render, screen, waitFor } from '@testing-library/react'; +import { + act, + fireEvent, + render, + screen, + waitFor, +} from '@testing-library/react'; import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; import { HighlightPostSidebarWidget } from './HighlightPostSidebarWidget'; import { useAuthContext } from '../../../contexts/AuthContext'; diff --git a/packages/shared/src/components/cards/highlight/HighlightPostSidebarWidget.tsx b/packages/shared/src/components/cards/highlight/HighlightPostSidebarWidget.tsx index 1e57370906..dca3ee3cdc 100644 --- a/packages/shared/src/components/cards/highlight/HighlightPostSidebarWidget.tsx +++ b/packages/shared/src/components/cards/highlight/HighlightPostSidebarWidget.tsx @@ -1,17 +1,9 @@ import type { ReactElement } from 'react'; -import React, { - useCallback, - useEffect, - useRef, - useState, -} from 'react'; +import React, { useCallback, useEffect, useRef, useState } from 'react'; import classNames from 'classnames'; import { useQuery } from '@tanstack/react-query'; import { WidgetContainer } from '../../widgets/common'; -import { - getHighlightsUrl, - highlightsTitleGradientClassName, -} from './common'; +import { getHighlightsUrl, highlightsTitleGradientClassName } from './common'; import { majorHeadlinesQueryOptions, type PostHighlight, @@ -168,10 +160,7 @@ export const HighlightPostSidebarWidget = (): ReactElement | null => { > Happening Now

-
+
{ diff --git a/packages/shared/src/components/cards/highlight/common.tsx b/packages/shared/src/components/cards/highlight/common.tsx index 7444270d02..ca3ec83c1e 100644 --- a/packages/shared/src/components/cards/highlight/common.tsx +++ b/packages/shared/src/components/cards/highlight/common.tsx @@ -12,7 +12,8 @@ export interface HighlightCardProps { onReadAllClick?: () => void; } -export const highlightsTitleGradientClassName = 'feed-highlights-title-gradient'; +export const highlightsTitleGradientClassName = + 'feed-highlights-title-gradient'; const HIGHLIGHTS_URL = `${webappUrl}highlights`;