mirror of
https://github.com/twentyhq/twenty
synced 2026-04-21 13:37:22 +00:00
Redesign why-twenty page with three-section narrative (#19882)
## Summary
- Restructures the why-twenty page into a clearer three-act story (the
shift / what this means / the opportunity), with new copy across hero
subtitle, all editorials, marquee, quote and signoff.
- Adds visual rhythm via left/right section anchoring (sections 1 and 3
left-aligned, section 2 right-aligned) and per-section `GuideCrosshair`
markers at the top edge of each editorial.
- Adds a CTA `Signoff` section ("Get started") at the end of the page.
- Bumps the 3D quotation marks (`Quotes` illustration) so the Quote can
serve as a visual section break.
## Changes
- **Editorial section**
([Editorial.Heading](packages/twenty-website-new/src/sections/Editorial/components/Heading/Heading.tsx),
[Editorial.Body](packages/twenty-website-new/src/sections/Editorial/components/Body/Body.tsx),
[Editorial.Root](packages/twenty-website-new/src/sections/Editorial/components/Root/Root.tsx)):
- Default heading size `xl` → `lg`
- New `two-column-left` and `two-column-right` body layouts via
`data-align` on `TwoColumnGrid`
- New optional `crosshair` prop on `Editorial.Root` that anchors a
`GuideCrosshair` to the section
- **Why-twenty constants** — fresh copy in `hero.ts`, `editorial-one`,
`editorial-three`, `editorial-four`, `marquee.ts`, `quote.ts`,
`signoff.ts`
- **Page layout**
([why-twenty/page.tsx](packages/twenty-website-new/src/app/why-twenty/page.tsx)):
- Section 1 → left content + crosshair on right
- Section 2 → right content + crosshair on left
- Section 3 → left content + crosshair on right
- Adds `Signoff` block with `LinkButton` "Get started" CTA
- **Quote 3D illustration** — `previewDistance` 6 → 4 and bigger
`StyledVisualMount` (added a one-line `oxlint-disable` for the
pre-existing `@ts-nocheck` that the diff surfaced)
- **Signoff** — keeps the GuideCrosshair behavior limited to Partners
(per-page config map remains in place)
Editorial is only consumed on the why-twenty page so the heading/body
changes don't affect any other page.
## Test plan
- [ ] Visit `/why-twenty` on desktop — verify the three editorials read
as left/right/left with crosshairs at section top edges
- [ ] Verify the Signoff CTA renders white "Get started" pill button on
dark background and links to `app.twenty.com/welcome`
- [ ] Verify mobile layout — crosshairs hidden, content left-aligned,
body stacks single column
- [ ] Lighthouse / no console errors
🤖 Generated with [Claude Code](https://claude.com/claude-code)
This commit is contained in:
parent
c959998111
commit
9f5688ab13
16 changed files with 462 additions and 219 deletions
|
|
@ -4,19 +4,25 @@ export const EDITORIAL_FOUR: EditorialDataType = {
|
|||
eyebrow: {
|
||||
heading: {
|
||||
fontFamily: 'sans',
|
||||
text: 'What must our CRM do that nobody else can?',
|
||||
text: 'What this means',
|
||||
},
|
||||
},
|
||||
heading: {
|
||||
fontFamily: 'serif',
|
||||
text: 'CRM becomes an execution system',
|
||||
},
|
||||
heading: [
|
||||
{
|
||||
fontFamily: 'serif',
|
||||
text: 'Differentiation now ',
|
||||
},
|
||||
{
|
||||
fontFamily: 'sans',
|
||||
text: 'lives in the code you own.',
|
||||
},
|
||||
],
|
||||
body: [
|
||||
{
|
||||
text: 'For years, CRM was treated like a ledger. A place to log what happened. AI flips that. When agents draft emails, qualify leads, propose next steps, update records, and trigger follow-ups, the CRM becomes where work begins.',
|
||||
text: "You don't buy your deployment pipeline off the shelf. You don't rent your data warehouse from a vendor who decides the schema. You build it, you own it, you iterate on it every week. CRM is going the same way. The teams that treat it as infrastructure they own will compound an advantage every quarter.",
|
||||
},
|
||||
{
|
||||
text: 'It becomes the interface between humans, agents, and reality. The customer system is the map that directs action. If the map is generic, the actions will be generic. If the map is wrong, the actions will be wrong at scale. If they matter, you must own them.',
|
||||
text: 'Tuesday your team learns that deals with a technical champion close 3x faster. Wednesday you add the field, wire up the scoring, adjust the workflow. By Thursday your agents are acting on it. That feedback loop is the edge. And it only works if the CRM is yours.',
|
||||
},
|
||||
],
|
||||
};
|
||||
|
|
|
|||
|
|
@ -4,19 +4,19 @@ export const EDITORIAL_ONE: EditorialDataType = {
|
|||
eyebrow: {
|
||||
heading: {
|
||||
fontFamily: 'sans',
|
||||
text: 'What must our CRM do that nobody else can?',
|
||||
text: 'The shift',
|
||||
},
|
||||
},
|
||||
heading: [
|
||||
{ fontFamily: 'serif', text: 'Packaged CRMs' },
|
||||
{ fontFamily: 'sans', text: ' optimize for sameness' },
|
||||
{ fontFamily: 'serif', text: 'CRM was a ledger.' },
|
||||
{ fontFamily: 'sans', text: ' AI turned it into an operating system.' },
|
||||
],
|
||||
body: [
|
||||
{
|
||||
text: 'Off-the-shelf CRMs are built for the median workflow. They standardize what an account is, what a pipeline looks like, what stages matter, and what "good" reporting means. They help you keep up with the market, this is beta. But when it is time to generate differentiated value, alpha, they fall short.',
|
||||
text: "For twenty years, CRM meant the same thing: a place to log calls, track deals, and pull reports on Friday. The real work happened in people's heads, in Slack threads, in hallway conversations. The CRM kept score. Nobody expected more from it.",
|
||||
},
|
||||
{
|
||||
text: 'When every company runs the same objects, the same lifecycle stages, the same routing logic, and the same prepackaged "AI insights," the CRM stops being an advantage. It becomes a cost of entry. You do not just buy software. You inherit assumptions, assumptions that over time become constraints.',
|
||||
text: 'AI agents are starting to draft outreach, score leads, research accounts, write follow-ups, update deal stages. Every one of these actions reads from and writes to the CRM. The scoreboard became the playbook. The database became the brain.',
|
||||
},
|
||||
],
|
||||
};
|
||||
|
|
|
|||
|
|
@ -2,13 +2,24 @@ import type { EditorialDataType } from '@/sections/Editorial/types/EditorialData
|
|||
|
||||
export const EDITORIAL_THREE: EditorialDataType = {
|
||||
eyebrow: {
|
||||
heading: { fontFamily: 'sans', text: 'Lorem ipsum dolor' },
|
||||
heading: { fontFamily: 'sans', text: 'The opportunity' },
|
||||
},
|
||||
heading: [
|
||||
{ fontFamily: 'serif', text: 'Lorem ipsum dolor sit amet,' },
|
||||
{ fontFamily: 'sans', text: ' consectetur' },
|
||||
{
|
||||
fontFamily: 'serif',
|
||||
text: 'Build it in an afternoon.',
|
||||
},
|
||||
{
|
||||
fontFamily: 'sans',
|
||||
text: ' AI made the gap that small.',
|
||||
},
|
||||
],
|
||||
body: [
|
||||
{
|
||||
text: 'A year ago, customizing your CRM meant hiring a Salesforce consultant, learning Apex, waiting months. The gap between "I want this" and "it\'s live" was measured in quarters and invoices. So people settled. They bent their process to fit the tool and called it adoption.',
|
||||
},
|
||||
{
|
||||
text: "Now a developer can describe what they want to Claude Code and have a working app in an afternoon. A custom object, a scoring workflow, a new view, an integration. The bottleneck isn't building anymore. It's whether your platform lets you.",
|
||||
},
|
||||
],
|
||||
body: {
|
||||
text: 'AI compresses the time between idea and implementation. Feature parity arrives faster. "Best practices" expire faster. Competitive imitation accelerates because everyone has access to the same models, the same libraries, and the same distribution channels. When the surface area of software becomes cheap, differentiation moves underneath it.',
|
||||
},
|
||||
};
|
||||
|
|
|
|||
|
|
@ -2,6 +2,6 @@ import type { EditorialDataType } from '@/sections/Editorial/types/EditorialData
|
|||
|
||||
export const EDITORIAL_TWO: EditorialDataType = {
|
||||
body: {
|
||||
text: 'AI compresses the time between idea and implementation. Feature parity arrives faster. "Best practices" expire faster. Competitive imitation accelerates because everyone has access to the same models, the same libraries, and the same distribution channels. When the surface area of software becomes cheap, differentiation moves underneath it.',
|
||||
text: 'Every company on Salesforce runs the same objects, the same lifecycle stages, the same routing logic. They bought "best practices." But best practices are just the average, packaged and sold back as wisdom. When your CRM is identical to your competitor\'s, your AI agents will make the same decisions as theirs. Same scoring, same timing, same emails. You automated yourself into mediocrity.',
|
||||
},
|
||||
};
|
||||
|
|
|
|||
|
|
@ -6,6 +6,9 @@ export const HERO_DATA: HeroWhyTwentyDataType = {
|
|||
{ text: ' not bought.', fontFamily: 'sans' },
|
||||
],
|
||||
body: {
|
||||
text: 'Most packaged software makes companies more similar. CRM is no exception. AI is turning software into a commodity. That does not make your go-to-market a commodity. It makes it the battleground.',
|
||||
text:
|
||||
'CRM was a database you filled on Fridays. ' +
|
||||
'AI turned it into the system that runs your go-to-market. ' +
|
||||
"To differentiate, you have to build what your competitors can't buy.",
|
||||
},
|
||||
};
|
||||
|
|
|
|||
|
|
@ -2,8 +2,8 @@ import type { MarqueeDataType } from '@/sections/Marquee/types';
|
|||
|
||||
export const MARQUEE_DATA: MarqueeDataType = {
|
||||
heading: [
|
||||
{ fontFamily: 'serif', text: 'AI raises' },
|
||||
{ fontFamily: 'sans', text: 'the cost of' },
|
||||
{ fontFamily: 'sans', text: 'being wrong' },
|
||||
{ fontFamily: 'serif', text: 'Same CRM' },
|
||||
{ fontFamily: 'sans', text: 'Same output' },
|
||||
{ fontFamily: 'serif', text: 'Same results' },
|
||||
],
|
||||
};
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import type { QuoteDataType } from '@/sections/Quote/types/QuoteData';
|
|||
export const QUOTE_DATA: QuoteDataType = {
|
||||
illustration: 'quoteQuotes',
|
||||
heading: [
|
||||
{ text: '“In the AI age,\n', fontFamily: 'serif' },
|
||||
{ text: ' convergence accelerates”', fontFamily: 'sans' },
|
||||
{ text: '“Best teams will run\n', fontFamily: 'serif' },
|
||||
{ text: ' systems nobody else has.”', fontFamily: 'sans' },
|
||||
],
|
||||
};
|
||||
|
|
|
|||
|
|
@ -2,10 +2,10 @@ import type { SignoffDataType } from '@/sections/Signoff/types';
|
|||
|
||||
export const SIGNOFF_DATA: SignoffDataType = {
|
||||
heading: [
|
||||
{ text: 'The future of CRM is built,', fontFamily: 'serif' },
|
||||
{ text: ' not bought.', fontFamily: 'sans' },
|
||||
{ text: 'Build a CRM your competitors ', fontFamily: 'serif' },
|
||||
{ text: "can't buy.", fontFamily: 'sans' },
|
||||
],
|
||||
body: {
|
||||
text: 'This is the world we are building toward at Twenty. ',
|
||||
text: 'Open-source, AI-ready, and yours to shape.',
|
||||
},
|
||||
};
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import type { StatementDataType } from '@/sections/Statement/types';
|
|||
|
||||
export const STATEMENT_ONE: StatementDataType = {
|
||||
heading: {
|
||||
text: 'Lorem ipsum dolor sit amet, consecteturLorem ipsum dolor sit amet, consectetur oremipsum dolor sit amet, conse.',
|
||||
text: 'The best go-to-market teams will run systems nobody else has.',
|
||||
fontFamily: 'serif',
|
||||
},
|
||||
};
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import type { StatementDataType } from '@/sections/Statement/types';
|
|||
|
||||
export const STATEMENT_TWO: StatementDataType = {
|
||||
heading: {
|
||||
text: 'Lorem ipsum dolor sit amet, consectetur. Lorem ipsum dolor sit amet, consectetur oremipsum dolor sit amet, conse.',
|
||||
text: "Not because they're bigger. Because they built exactly what they needed.",
|
||||
fontFamily: 'serif',
|
||||
},
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,11 +1,13 @@
|
|||
import { MENU_DATA } from '@/app/_constants';
|
||||
import {
|
||||
EDITORIAL_FOUR,
|
||||
EDITORIAL_ONE,
|
||||
EDITORIAL_TWO,
|
||||
EDITORIAL_THREE,
|
||||
HERO_DATA,
|
||||
MARQUEE_DATA,
|
||||
QUOTE_DATA,
|
||||
SIGNOFF_DATA,
|
||||
} from '@/app/why-twenty/_constants';
|
||||
import { LinkButton } from '@/design-system/components';
|
||||
import { Pages } from '@/enums/pages';
|
||||
import { fetchCommunityStats } from '@/lib/community/fetch-community-stats';
|
||||
import { mergeSocialLinkLabels } from '@/lib/community/merge-social-link-labels';
|
||||
|
|
@ -14,7 +16,7 @@ import { Editorial } from '@/sections/Editorial/components';
|
|||
import { Hero } from '@/sections/Hero/components';
|
||||
import { Marquee } from '@/sections/Marquee/components';
|
||||
import { Menu } from '@/sections/Menu/components';
|
||||
import { Quote } from '@/sections/Quote/components';
|
||||
import { Signoff } from '@/sections/Signoff/components';
|
||||
import { theme } from '@/theme';
|
||||
import { css } from '@linaria/core';
|
||||
import type { Metadata } from 'next';
|
||||
|
|
@ -29,6 +31,35 @@ const editorialOneIntroClass = css`
|
|||
}
|
||||
`;
|
||||
|
||||
const editorialRightIntroClass = css`
|
||||
margin-bottom: ${theme.spacing(4)};
|
||||
--editorial-heading-max-width: 760px;
|
||||
--editorial-intro-max-width: 760px;
|
||||
|
||||
@media (min-width: ${theme.breakpoints.md}px) {
|
||||
align-items: flex-end;
|
||||
margin-bottom: ${theme.spacing(8)};
|
||||
margin-left: auto;
|
||||
margin-right: 0;
|
||||
text-align: right;
|
||||
width: auto;
|
||||
}
|
||||
`;
|
||||
|
||||
const crosshairLineColor = theme.colors.secondary.border[10];
|
||||
|
||||
const sectionCrosshairLeft = {
|
||||
crossX: '120px',
|
||||
crossY: '0px',
|
||||
lineColor: crosshairLineColor,
|
||||
};
|
||||
|
||||
const sectionCrosshairRight = {
|
||||
crossX: 'calc(100% - 120px)',
|
||||
crossY: '0px',
|
||||
lineColor: crosshairLineColor,
|
||||
};
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: 'Why Twenty | Twenty',
|
||||
description:
|
||||
|
|
@ -70,6 +101,7 @@ export default async function WhyTwentyPage() {
|
|||
<Editorial.Root
|
||||
backgroundColor={theme.colors.secondary.background[100]}
|
||||
color={theme.colors.secondary.text[100]}
|
||||
crosshair={sectionCrosshairRight}
|
||||
mutedColor={theme.colors.secondary.text[60]}
|
||||
>
|
||||
<Editorial.Intro className={editorialOneIntroClass}>
|
||||
|
|
@ -79,14 +111,10 @@ export default async function WhyTwentyPage() {
|
|||
/>
|
||||
<Editorial.Heading segments={EDITORIAL_ONE.heading!} />
|
||||
</Editorial.Intro>
|
||||
<Editorial.Body body={EDITORIAL_ONE.body} layout="two-column" />
|
||||
<Editorial.Body body={EDITORIAL_ONE.body} layout="two-column-left" />
|
||||
</Editorial.Root>
|
||||
|
||||
<Quote.Root backgroundColor={theme.colors.secondary.background[100]}>
|
||||
<Quote.Visual illustration={QUOTE_DATA.illustration} />
|
||||
<Quote.Heading segments={QUOTE_DATA.heading} />
|
||||
</Quote.Root>
|
||||
|
||||
{/*
|
||||
<Editorial.Root
|
||||
backgroundColor={theme.colors.secondary.background[100]}
|
||||
color={theme.colors.secondary.text[100]}
|
||||
|
|
@ -94,12 +122,71 @@ export default async function WhyTwentyPage() {
|
|||
>
|
||||
<Editorial.Body body={EDITORIAL_TWO.body} layout="centered" />
|
||||
</Editorial.Root>
|
||||
*/}
|
||||
|
||||
<Editorial.Root
|
||||
backgroundColor={theme.colors.secondary.background[100]}
|
||||
color={theme.colors.secondary.text[100]}
|
||||
crosshair={sectionCrosshairLeft}
|
||||
mutedColor={theme.colors.secondary.text[60]}
|
||||
>
|
||||
<Editorial.Intro className={editorialRightIntroClass}>
|
||||
<Editorial.Eyebrow
|
||||
colorScheme="secondary"
|
||||
eyebrow={EDITORIAL_FOUR.eyebrow!}
|
||||
/>
|
||||
<Editorial.Heading segments={EDITORIAL_FOUR.heading!} />
|
||||
</Editorial.Intro>
|
||||
<Editorial.Body body={EDITORIAL_FOUR.body} layout="two-column-right" />
|
||||
</Editorial.Root>
|
||||
|
||||
{/* <Quote.Root backgroundColor={theme.colors.secondary.background[80]}>
|
||||
<Quote.Visual illustration={QUOTE_DATA.illustration} />
|
||||
<Quote.Heading segments={QUOTE_DATA.heading} />
|
||||
</Quote.Root>*/}
|
||||
|
||||
<Editorial.Root
|
||||
backgroundColor={theme.colors.secondary.background[100]}
|
||||
color={theme.colors.secondary.text[100]}
|
||||
crosshair={sectionCrosshairRight}
|
||||
mutedColor={theme.colors.secondary.text[60]}
|
||||
>
|
||||
<Editorial.Intro className={editorialOneIntroClass}>
|
||||
<Editorial.Eyebrow
|
||||
colorScheme="secondary"
|
||||
eyebrow={EDITORIAL_THREE.eyebrow!}
|
||||
/>
|
||||
<Editorial.Heading segments={EDITORIAL_THREE.heading!} />
|
||||
</Editorial.Intro>
|
||||
<Editorial.Body body={EDITORIAL_THREE.body} layout="two-column-left" />
|
||||
</Editorial.Root>
|
||||
|
||||
<Marquee.Root
|
||||
backgroundColor={theme.colors.secondary.background[100]}
|
||||
color={theme.colors.secondary.text[100]}
|
||||
heading={MARQUEE_DATA.heading}
|
||||
/>
|
||||
|
||||
<Signoff.Root
|
||||
backgroundColor={theme.colors.secondary.background[100]}
|
||||
color={theme.colors.secondary.text[100]}
|
||||
page={Pages.WhyTwenty}
|
||||
>
|
||||
<Signoff.Heading
|
||||
page={Pages.WhyTwenty}
|
||||
segments={SIGNOFF_DATA.heading}
|
||||
/>
|
||||
<Signoff.Body body={SIGNOFF_DATA.body} page={Pages.WhyTwenty} />
|
||||
<Signoff.Cta>
|
||||
<LinkButton
|
||||
color="primary"
|
||||
href="https://app.twenty.com/welcome"
|
||||
label="Get started"
|
||||
type="anchor"
|
||||
variant="contained"
|
||||
/>
|
||||
</Signoff.Cta>
|
||||
</Signoff.Root>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
|
|
@ -21,6 +21,14 @@ const TwoColumnGrid = styled.div`
|
|||
|
||||
@media (min-width: ${theme.breakpoints.md}px) {
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
|
||||
&[data-align='left'] {
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
&[data-align='right'] {
|
||||
margin-right: 0;
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
|
|
@ -37,7 +45,12 @@ const SingleColumnBody = styled.div`
|
|||
|
||||
type EditorialBodyProps = {
|
||||
body: BodyType | BodyType[];
|
||||
layout: 'centered' | 'indented' | 'two-column';
|
||||
layout:
|
||||
| 'centered'
|
||||
| 'indented'
|
||||
| 'two-column'
|
||||
| 'two-column-left'
|
||||
| 'two-column-right';
|
||||
};
|
||||
|
||||
export function Body({ body, layout }: EditorialBodyProps) {
|
||||
|
|
@ -67,8 +80,24 @@ export function Body({ body, layout }: EditorialBodyProps) {
|
|||
</BodyParagraph>
|
||||
);
|
||||
|
||||
if (layout === 'two-column') {
|
||||
return <TwoColumnGrid>{paragraphs}</TwoColumnGrid>;
|
||||
if (
|
||||
layout === 'two-column' ||
|
||||
layout === 'two-column-left' ||
|
||||
layout === 'two-column-right'
|
||||
) {
|
||||
return (
|
||||
<TwoColumnGrid
|
||||
data-align={
|
||||
layout === 'two-column-right'
|
||||
? 'right'
|
||||
: layout === 'two-column-left'
|
||||
? 'left'
|
||||
: undefined
|
||||
}
|
||||
>
|
||||
{paragraphs}
|
||||
</TwoColumnGrid>
|
||||
);
|
||||
}
|
||||
|
||||
return <SingleColumnBody>{paragraphs}</SingleColumnBody>;
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ type EditorialHeadingProps = {
|
|||
export function Heading({ segments }: EditorialHeadingProps) {
|
||||
return (
|
||||
<HeadingWrap>
|
||||
<BaseHeading as="h2" segments={segments} size="xl" weight="light" />
|
||||
<BaseHeading as="h2" segments={segments} size="lg" weight="light" />
|
||||
</HeadingWrap>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { Container } from '@/design-system/components';
|
||||
import { Container, GuideCrosshair } from '@/design-system/components';
|
||||
import { theme } from '@/theme';
|
||||
import { styled } from '@linaria/react';
|
||||
import type { CSSProperties, ReactNode } from 'react';
|
||||
|
|
@ -6,6 +6,10 @@ import type { CSSProperties, ReactNode } from 'react';
|
|||
const StyledSection = styled.section`
|
||||
min-width: 0;
|
||||
width: 100%;
|
||||
|
||||
&[data-has-crosshair] {
|
||||
position: relative;
|
||||
}
|
||||
`;
|
||||
|
||||
const Inner = styled.div`
|
||||
|
|
@ -28,10 +32,17 @@ const StyledContainer = styled(Container)`
|
|||
}
|
||||
`;
|
||||
|
||||
type EditorialCrosshair = {
|
||||
crossX: string;
|
||||
crossY: string;
|
||||
lineColor?: string;
|
||||
};
|
||||
|
||||
type RootProps = {
|
||||
backgroundColor: string;
|
||||
children: ReactNode;
|
||||
color: string;
|
||||
crosshair?: EditorialCrosshair;
|
||||
mutedColor: string;
|
||||
};
|
||||
|
||||
|
|
@ -39,6 +50,7 @@ export function Root({
|
|||
backgroundColor,
|
||||
children,
|
||||
color,
|
||||
crosshair,
|
||||
mutedColor,
|
||||
}: RootProps) {
|
||||
const cssVariables = {
|
||||
|
|
@ -47,12 +59,20 @@ export function Root({
|
|||
|
||||
return (
|
||||
<StyledSection
|
||||
data-has-crosshair={crosshair ? '' : undefined}
|
||||
style={{
|
||||
...cssVariables,
|
||||
backgroundColor,
|
||||
color,
|
||||
}}
|
||||
>
|
||||
{crosshair ? (
|
||||
<GuideCrosshair
|
||||
crossX={crosshair.crossX}
|
||||
crossY={crosshair.crossY}
|
||||
lineColor={crosshair.lineColor}
|
||||
/>
|
||||
) : null}
|
||||
<StyledContainer>
|
||||
<Inner>{children}</Inner>
|
||||
</StyledContainer>
|
||||
|
|
|
|||
|
|
@ -6,6 +6,12 @@ import { Pages } from '@/enums/pages';
|
|||
import { SignoffShape } from '@/sections/Signoff/SignoffShape';
|
||||
import { theme } from '@/theme';
|
||||
|
||||
const GUIDE_CROSSHAIR_BY_PAGE: Partial<
|
||||
Record<Pages, { crossX: string; crossY: string; lineColor?: string }>
|
||||
> = {
|
||||
[Pages.Partners]: { crossX: 'calc(50% + 334px)', crossY: '198px' },
|
||||
};
|
||||
|
||||
const StyledSection = styled.section`
|
||||
min-width: 0;
|
||||
width: 100%;
|
||||
|
|
@ -93,8 +99,12 @@ export function Root(props: RootProps) {
|
|||
{isShaped && shapeFillColor ? (
|
||||
<SignoffShape fillColor={shapeFillColor} />
|
||||
) : null}
|
||||
{page === Pages.Partners ? (
|
||||
<GuideCrosshair crossX="calc(50% + 334px)" crossY="198px" />
|
||||
{page && GUIDE_CROSSHAIR_BY_PAGE[page] ? (
|
||||
<GuideCrosshair
|
||||
crossX={GUIDE_CROSSHAIR_BY_PAGE[page]!.crossX}
|
||||
crossY={GUIDE_CROSSHAIR_BY_PAGE[page]!.crossY}
|
||||
lineColor={GUIDE_CROSSHAIR_BY_PAGE[page]!.lineColor}
|
||||
/>
|
||||
) : null}
|
||||
<StyledContainer>{children}</StyledContainer>
|
||||
</StyledSection>
|
||||
|
|
|
|||
Loading…
Reference in a new issue