Repository navigation
Show mini nav #17075
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
Merged
Merged
Show mini nav #17075
Changes from all commits
Commits
Show all changes
37 commits
Select commit
Hold shift + click to select a range
3493543
Render mini nav data
OlwenPearce fc381ec
Reduce top bar padding
OlwenPearce f17e526
Scroll with title
OlwenPearce b754a47
Add case to show image not rendered
OlwenPearce b97830d
Only display mini nav when flex gen boost and above
OlwenPearce fe81fe1
Remove not rendered storybook
OlwenPearce 26db67b
Extract test fixture
OlwenPearce b4dac1a
Reduce re-ordering
OlwenPearce 5ede409
Post rebase fix
OlwenPearce 8989900
Adjust to use cards kicker colour
OlwenPearce 5be29bf
Use standard new card in stories
OlwenPearce 9352018
Fix underlines / hovering
OlwenPearce ecbe166
Make card size larger
OlwenPearce ac23a89
Merge branch 'main' into show-mini-nav
OlwenPearce a6f187b
Use the same padding without a dividing line as with
OlwenPearce 53aa841
Pad ever so slightly
OlwenPearce 6875ab9
Try to make things cleaner / more readable
OlwenPearce 1161860
Merge branch 'main' into show-mini-nav
OlwenPearce 5eaf655
Post rebase issues
OlwenPearce c050538
Fix padding reversion
OlwenPearce f2b0a18
Slight padding
OlwenPearce a31ced5
Merge branch 'main' into show-mini-nav
OlwenPearce 2dc143f
Merge branch 'show-mini-nav' of github.com:guardian/dotcom-rendering …
OlwenPearce f024f86
Generate new schemas
OlwenPearce 1bd5664
Rebase fix: make pageId optional
OlwenPearce 71179f8
Rebase fix: remove unused var
OlwenPearce 6ec5fd5
Rebase fix: remove unused var
OlwenPearce a411dc2
Separate out mini nav somewhat
OlwenPearce 7c48c30
Create separate mini nav component
OlwenPearce 16d56ad
Remove fallback that got dropped
OlwenPearce 7e5fd84
Revert slight pad
OlwenPearce 42be00f
Post rebase fix
OlwenPearce deac4bc
Make padding split clearer (I think)
OlwenPearce 25bc226
Fix padding on no header case
OlwenPearce 0296e73
Tweaks
OlwenPearce 8893e9f
Tweaks
OlwenPearce 6f4b03a
Clearer split of styles
OlwenPearce File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,26 @@ | ||
| import type { CustomSubnav } from '../../src/types/customSubnav'; | ||
|
|
||
| export const customSubnav: CustomSubnav = { | ||
| id: 'us-politics', | ||
| header: { | ||
| headerText: 'US politics', | ||
| copy: '', | ||
| dotcomPath: '/us-news/us-politics', | ||
| showHeaderText: true, | ||
| }, | ||
| format: 'large', | ||
| links: [ | ||
| { | ||
| linkText: 'Trump administration', | ||
| dotcomPath: '/us-news/trump-administration', | ||
| }, | ||
| { linkText: 'US Congress', dotcomPath: '/us-news/us-congress' }, | ||
| { linkText: 'US supreme court', dotcomPath: '/law/us-supreme-court' }, | ||
| { | ||
| linkText: 'US elections 2024', | ||
| dotcomPath: '/us-news/us-elections-2024', | ||
| }, | ||
| { linkText: 'US immigration', dotcomPath: '/us-news/usimmigration' }, | ||
| ], | ||
| pages: [], | ||
| }; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,35 @@ | ||
| import { css } from '@emotion/react'; | ||
| import { getZIndex } from '../lib/getZIndex'; | ||
| import { palette } from '../palette'; | ||
| import type { DCRFrontCard } from '../types/front'; | ||
| import { CustomSubNav } from './Masthead/Titlepiece/CustomSubNav'; | ||
|
|
||
| type Props = { | ||
| miniNavData: DCRFrontCard['miniNavData']; | ||
| }; | ||
|
|
||
| export const CardMiniNav = ({ miniNavData }: Props) => { | ||
| if (!miniNavData) { | ||
| return null; | ||
| } | ||
|
|
||
| return ( | ||
| <div | ||
| className="mini-nav" | ||
| css={css` | ||
| position: relative; | ||
| z-index: ${getZIndex('card-nested-link')}; | ||
| min-width: 0; | ||
| --custom-subnav-header-text: ${palette( | ||
| miniNavData.header.dotcomPath | ||
| ? '--card-kicker-text' | ||
| : '--card-headline', | ||
| )}; | ||
| --masthead-nav-link-text: ${palette('--card-headline')}; | ||
| --masthead-nav-link-text-hover: ${palette('--card-headline')}; | ||
| `} | ||
| > | ||
| <CustomSubNav customSubNav={miniNavData} renderingPage="card" /> | ||
| </div> | ||
| ); | ||
| }; |
201 changes: 201 additions & 0 deletions
201
dotcom-rendering/src/components/FrontCard.miniNav.test.tsx
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,201 @@ | ||
| import { render, screen } from '@testing-library/react'; | ||
| import { customSubnav } from '../../fixtures/manual/customSubnav'; | ||
| import { trails } from '../../fixtures/manual/trails'; | ||
| import type { CustomSubnav } from '../types/customSubnav'; | ||
| import type { DCRContainerType, DCRFrontCard } from '../types/front'; | ||
| import { ConfigProvider } from './ConfigContext'; | ||
| import { FrontCard } from './FrontCard'; | ||
|
|
||
| const miniNavData = { | ||
| ...customSubnav, | ||
| id: 'football-mini-nav', | ||
| header: { | ||
| ...customSubnav.header, | ||
| headerText: 'Football', | ||
| dotcomPath: '/football', | ||
| copy: 'Football navigation', | ||
| }, | ||
| format: 'compact', | ||
| links: [{ linkText: 'More Football', dotcomPath: '/football' }], | ||
| } satisfies CustomSubnav; | ||
|
|
||
| const defaultTrail = { | ||
| ...trails[0], | ||
| boostLevel: 'boost', | ||
| showMiniNav: true, | ||
| miniNavData, | ||
| } satisfies DCRFrontCard; | ||
|
|
||
| const renderCard = ({ | ||
| trail = defaultTrail, | ||
| ...props | ||
| }: { | ||
| trail?: DCRFrontCard; | ||
| containerType?: DCRContainerType; | ||
| } = {}) => | ||
| render( | ||
| <ConfigProvider | ||
| value={{ | ||
| renderingTarget: 'Web', | ||
| darkModeAvailable: false, | ||
| assetOrigin: '/', | ||
| editionId: 'UK', | ||
| }} | ||
| > | ||
| <FrontCard | ||
| trail={trail} | ||
| containerType="flexible/general" | ||
| imageLoading="eager" | ||
| serverTime={1793031866891} | ||
| {...props} | ||
| /> | ||
| </ConfigProvider>, | ||
| ); | ||
|
|
||
| const expectMiniNavAbsent = () => { | ||
| expect(screen.queryByText('Football')).not.toBeInTheDocument(); | ||
| expect( | ||
| screen.queryByRole('link', { name: 'More Football' }), | ||
| ).not.toBeInTheDocument(); | ||
| expect(screen.getByText(defaultTrail.headline)).toBeInTheDocument(); | ||
| }; | ||
|
|
||
| describe('FrontCard mini navigation', () => { | ||
| it.each(['boost', 'megaboost', 'gigaboost'] as const)( | ||
| 'renders mini navigation for a %s card', | ||
| (boostLevel) => { | ||
| renderCard({ trail: { ...defaultTrail, boostLevel } }); | ||
|
|
||
| expect( | ||
| screen.getByRole('link', { name: 'More Football' }), | ||
| ).toHaveAttribute('href', '/football'); | ||
| expect(screen.getByText(defaultTrail.headline)).toBeInTheDocument(); | ||
| }, | ||
| ); | ||
|
|
||
| it.each([undefined, 'default'] as const)( | ||
| 'does not render mini navigation with boost level %s', | ||
| (boostLevel) => { | ||
| renderCard({ trail: { ...defaultTrail, boostLevel } }); | ||
|
|
||
| expectMiniNavAbsent(); | ||
| }, | ||
| ); | ||
|
|
||
| it.each([undefined, 'static/medium/4', 'flexible/special'] as const)( | ||
| 'does not render mini navigation in container %s', | ||
| (containerType) => { | ||
| renderCard({ containerType }); | ||
|
|
||
| expectMiniNavAbsent(); | ||
| }, | ||
| ); | ||
|
|
||
| it('does not render mini navigation when disabled', () => { | ||
| renderCard({ trail: { ...defaultTrail, showMiniNav: false } }); | ||
|
|
||
| expectMiniNavAbsent(); | ||
| }); | ||
|
|
||
| it('does not render mini navigation when configuration is missing', () => { | ||
| renderCard({ trail: { ...defaultTrail, miniNavData: undefined } }); | ||
|
|
||
| expectMiniNavAbsent(); | ||
| }); | ||
|
|
||
| it('renders a header link without an underline when header text is enabled', () => { | ||
| renderCard(); | ||
|
|
||
| const header = screen.getByRole('link', { name: 'Football' }); | ||
| expect(header).toHaveAttribute('href', '/football'); | ||
| expect(header).toHaveStyle('text-decoration: none'); | ||
| }); | ||
|
|
||
| it('renders header text without a link when the header has no path', () => { | ||
| renderCard({ | ||
| trail: { | ||
| ...defaultTrail, | ||
| miniNavData: { | ||
| ...miniNavData, | ||
| header: { ...miniNavData.header, dotcomPath: undefined }, | ||
| }, | ||
| }, | ||
| }); | ||
|
|
||
| expect(screen.getByText('Football')).toBeInTheDocument(); | ||
| expect(screen.getByText('Football').closest('a')).toBeNull(); | ||
| expect(screen.getByText('Football').closest('.mini-nav')).toHaveStyle({ | ||
| '--custom-subnav-header-text': 'var(--card-headline)', | ||
| }); | ||
| expect( | ||
| screen.getByRole('link', { name: 'More Football' }), | ||
| ).toHaveAttribute('href', '/football'); | ||
| }); | ||
|
|
||
| it('hides the header without hiding navigation links when header text is disabled', () => { | ||
| renderCard({ | ||
| trail: { | ||
| ...defaultTrail, | ||
| miniNavData: { | ||
| ...miniNavData, | ||
| header: { ...miniNavData.header, showHeaderText: false }, | ||
| }, | ||
| }, | ||
| }); | ||
|
|
||
| expect(screen.queryByText('Football')).not.toBeInTheDocument(); | ||
| expect( | ||
| screen.getByRole('link', { name: 'More Football' }), | ||
| ).toHaveAttribute('href', '/football'); | ||
| expect(screen.getByText(defaultTrail.headline)).toBeInTheDocument(); | ||
| }); | ||
|
|
||
| it('places mini navigation before the card content in a full-width column', () => { | ||
| renderCard(); | ||
|
|
||
| const miniNav = screen | ||
| .getByRole('link', { name: 'More Football' }) | ||
| .closest('[data-component-id]'); | ||
| const navWrapper = miniNav?.parentElement; | ||
| const cardWrapper = navWrapper?.parentElement; | ||
|
|
||
| expect(cardWrapper).toHaveStyle({ | ||
| display: 'flex', | ||
| flexDirection: 'column', | ||
| width: '100%', | ||
| }); | ||
| expect(cardWrapper?.firstElementChild).toBe(navWrapper); | ||
| expect(cardWrapper).toContainElement( | ||
| screen.getByText(defaultTrail.headline), | ||
| ); | ||
| }); | ||
|
|
||
| it('uses card styling rather than article subnav styling', () => { | ||
| renderCard(); | ||
|
|
||
| const miniNav = screen | ||
| .getByRole('link', { name: 'More Football' }) | ||
| .closest('[data-component-id]'); | ||
| const list = screen.getByRole('list'); | ||
|
|
||
| expect(miniNav).toHaveAttribute('data-rendering-page', 'card'); | ||
| // Article subnavs have a divider (with an 8px gap) and fixed row heights; card mini-navs must not. | ||
| // (jsdom drops the `border-left` shorthand as it contains a CSS var, so assert on the divider's padding.) | ||
| expect(list).not.toHaveStyle({ paddingLeft: '8px' }); | ||
| expect(miniNav).not.toHaveStyle({ minHeight: '36px' }); | ||
| }); | ||
|
|
||
| it('uses the card kicker colour for the header and headline colour for links', () => { | ||
| renderCard(); | ||
|
|
||
| const miniNav = screen | ||
| .getByRole('link', { name: 'More Football' }) | ||
| .closest('[data-component-id]'); | ||
|
|
||
| expect(miniNav?.parentElement).toHaveStyle({ | ||
| '--custom-subnav-header-text': 'var(--card-kicker-text)', | ||
| '--masthead-nav-link-text': 'var(--card-headline)', | ||
| '--masthead-nav-link-text-hover': 'var(--card-headline)', | ||
| }); | ||
| }); | ||
| }); |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.