Remove hover and scroll transitions from website. (#19369)

This PR removes hover and scroll transitions from the website. 

Per the conversation with Thomas, we should introduce them one by one
for each section.
This commit is contained in:
Abdullah.
2026-04-07 12:58:40 +05:00
committed by GitHub
parent f33ad53e72
commit 2d552fc9fd
32 changed files with 544 additions and 993 deletions
@@ -8,11 +8,10 @@ import {
THREE_CARDS_ILLUSTRATION_DATA,
} from '@/app/(home)/_constants';
import { FAQ_DATA, MENU_DATA, TRUSTED_BY_DATA } from '@/app/_constants';
import { fetchCommunityStats } from '@/lib/community/fetch-community-stats';
import { mergeSocialLinkLabels } from '@/lib/community/merge-social-link-labels';
import { Body, Eyebrow, Heading, LinkButton } from '@/design-system/components';
import { Pages } from '@/enums/pages';
import { ScrollReveal } from '@/motion/ScrollReveal';
import { fetchCommunityStats } from '@/lib/community/fetch-community-stats';
import { mergeSocialLinkLabels } from '@/lib/community/merge-social-link-labels';
import { Faq } from '@/sections/Faq/components';
import { Helped } from '@/sections/Helped/components';
import { Hero } from '@/sections/Hero/components';
@@ -32,10 +31,7 @@ export const metadata: Metadata = {
export default async function HomePage() {
const stats = await fetchCommunityStats();
const menuSocialLinks = mergeSocialLinkLabels(
MENU_DATA.socialLinks,
stats,
);
const menuSocialLinks = mergeSocialLinkLabels(MENU_DATA.socialLinks, stats);
return (
<>
@@ -51,136 +47,117 @@ export default async function HomePage() {
<Menu.Cta scheme="primary" />
</Menu.Root>
<ScrollReveal>
<Hero.Root backgroundColor={theme.colors.primary.background[100]}>
<Hero.Heading page={Pages.Home} segments={HERO_DATA.heading} />
<Hero.Body page={Pages.Home} body={HERO_DATA.body} size="sm" />
<Hero.Cta>
<Hero.Root backgroundColor={theme.colors.primary.background[100]}>
<Hero.Heading page={Pages.Home} segments={HERO_DATA.heading} />
<Hero.Body page={Pages.Home} body={HERO_DATA.body} size="sm" />
<Hero.Cta>
<LinkButton
color="secondary"
href="https://app.twenty.com/welcome"
label="Get started"
type="anchor"
variant="contained"
/>
</Hero.Cta>
<Hero.HomeVisual visual={HERO_DATA.visual} />
</Hero.Root>
<TrustedBy.Root>
<TrustedBy.Separator separator={TRUSTED_BY_DATA.separator} />
<TrustedBy.Logos
clientCountLabel={TRUSTED_BY_DATA.clientCountLabel}
logos={TRUSTED_BY_DATA.logos}
/>
</TrustedBy.Root>
<Problem.Root>
<Problem.Visual />
<Problem.Content>
<Eyebrow
colorScheme="primary"
heading={PROBLEM_DATA.eyebrow.heading}
/>
<Problem.Heading segments={PROBLEM_DATA.heading} />
<Problem.Points points={PROBLEM_DATA.points} />
</Problem.Content>
</Problem.Root>
<ThreeCards.Root backgroundColor={theme.colors.primary.background[100]}>
<ThreeCards.Intro page={Pages.Home} align="left">
<Eyebrow
colorScheme="primary"
heading={THREE_CARDS_ILLUSTRATION_DATA.eyebrow.heading}
/>
<Heading
segments={THREE_CARDS_ILLUSTRATION_DATA.heading}
size="lg"
weight="light"
/>
<Body body={THREE_CARDS_ILLUSTRATION_DATA.body} size="sm" />
</ThreeCards.Intro>
<ThreeCards.IllustrationCards
illustrationCards={THREE_CARDS_ILLUSTRATION_DATA.illustrationCards}
/>
</ThreeCards.Root>
<HomeStepper.ScrollSection steps={HOME_STEPPER_DATA.steps} />
<ThreeCards.Root backgroundColor={theme.colors.primary.background[100]}>
<ThreeCards.Intro page={Pages.Home} align="center">
<Eyebrow
colorScheme="primary"
heading={THREE_CARDS_FEATURE_DATA.eyebrow.heading}
/>
<Heading
segments={THREE_CARDS_FEATURE_DATA.heading}
size="lg"
weight="light"
/>
</ThreeCards.Intro>
<ThreeCards.FeatureCards
featureCards={THREE_CARDS_FEATURE_DATA.featureCards}
/>
</ThreeCards.Root>
<Helped.Root backgroundColor={theme.colors.secondary.background[5]}>
<Helped.Scene data={HELPED_DATA} />
</Helped.Root>
<Testimonials.Root
backgroundColor={theme.colors.secondary.background[5]}
color={theme.colors.primary.text[100]}
shapeFillColor={theme.colors.primary.background[100]}
>
<Testimonials.Carousel
eyebrow={TESTIMONIALS_DATA.eyebrow}
illustration={TESTIMONIALS_DATA.illustration}
testimonials={TESTIMONIALS_DATA.testimonials}
/>
</Testimonials.Root>
<Faq.Root illustration={FAQ_DATA.illustration}>
<Faq.Intro>
<Eyebrow colorScheme="secondary" heading={FAQ_DATA.eyebrow.heading} />
<Faq.Heading segments={FAQ_DATA.heading} />
<Faq.Cta>
<LinkButton
color="secondary"
color="primary"
href="https://app.twenty.com/welcome"
label="Get started"
type="anchor"
variant="contained"
/>
</Hero.Cta>
<Hero.HomeVisual visual={HERO_DATA.visual} />
</Hero.Root>
</ScrollReveal>
<ScrollReveal>
<TrustedBy.Root>
<TrustedBy.Separator separator={TRUSTED_BY_DATA.separator} />
<TrustedBy.Logos
clientCountLabel={TRUSTED_BY_DATA.clientCountLabel}
logos={TRUSTED_BY_DATA.logos}
/>
</TrustedBy.Root>
</ScrollReveal>
<ScrollReveal>
<Problem.Root>
<Problem.Visual />
<Problem.Content>
<Eyebrow
colorScheme="primary"
heading={PROBLEM_DATA.eyebrow.heading}
<LinkButton
color="primary"
href="https://twenty.com/contact"
label="Talk to us"
type="anchor"
variant="outlined"
/>
<Problem.Heading segments={PROBLEM_DATA.heading} />
<Problem.Points points={PROBLEM_DATA.points} />
</Problem.Content>
</Problem.Root>
</ScrollReveal>
<ScrollReveal>
<ThreeCards.Root backgroundColor={theme.colors.primary.background[100]}>
<ThreeCards.Intro page={Pages.Home} align="left">
<Eyebrow
colorScheme="primary"
heading={THREE_CARDS_ILLUSTRATION_DATA.eyebrow.heading}
/>
<Heading
segments={THREE_CARDS_ILLUSTRATION_DATA.heading}
size="lg"
weight="light"
/>
<Body body={THREE_CARDS_ILLUSTRATION_DATA.body} size="sm" />
</ThreeCards.Intro>
<ThreeCards.IllustrationCards
illustrationCards={THREE_CARDS_ILLUSTRATION_DATA.illustrationCards}
/>
</ThreeCards.Root>
</ScrollReveal>
<HomeStepper.ScrollSection steps={HOME_STEPPER_DATA.steps} />
<ScrollReveal>
<ThreeCards.Root backgroundColor={theme.colors.primary.background[100]}>
<ThreeCards.Intro page={Pages.Home} align="center">
<Eyebrow
colorScheme="primary"
heading={THREE_CARDS_FEATURE_DATA.eyebrow.heading}
/>
<Heading
segments={THREE_CARDS_FEATURE_DATA.heading}
size="lg"
weight="light"
/>
</ThreeCards.Intro>
<ThreeCards.FeatureCards
featureCards={THREE_CARDS_FEATURE_DATA.featureCards}
/>
</ThreeCards.Root>
</ScrollReveal>
<ScrollReveal>
<Helped.Root backgroundColor={theme.colors.secondary.background[5]}>
<Helped.Scene data={HELPED_DATA} />
</Helped.Root>
</ScrollReveal>
<ScrollReveal>
<Testimonials.Root
backgroundColor={theme.colors.secondary.background[5]}
color={theme.colors.primary.text[100]}
shapeFillColor={theme.colors.primary.background[100]}
>
<Testimonials.Carousel
eyebrow={TESTIMONIALS_DATA.eyebrow}
illustration={TESTIMONIALS_DATA.illustration}
testimonials={TESTIMONIALS_DATA.testimonials}
/>
</Testimonials.Root>
</ScrollReveal>
<ScrollReveal>
<Faq.Root illustration={FAQ_DATA.illustration}>
<Faq.Intro>
<Eyebrow
colorScheme="secondary"
heading={FAQ_DATA.eyebrow.heading}
/>
<Faq.Heading segments={FAQ_DATA.heading} />
<Faq.Cta>
<LinkButton
color="primary"
href="https://app.twenty.com/welcome"
label="Get started"
type="anchor"
variant="contained"
/>
<LinkButton
color="primary"
href="https://twenty.com/contact"
label="Talk to us"
type="anchor"
variant="outlined"
/>
</Faq.Cta>
</Faq.Intro>
<Faq.Items questions={FAQ_DATA.questions} />
</Faq.Root>
</ScrollReveal>
</Faq.Cta>
</Faq.Intro>
<Faq.Items questions={FAQ_DATA.questions} />
</Faq.Root>
</>
);
}
@@ -9,7 +9,6 @@ import { css } from '@linaria/core';
import { styled } from '@linaria/react';
import type { Metadata } from 'next';
import { Aleo, Azeret_Mono, Host_Grotesk, VT323 } from 'next/font/google';
import '../../../twenty-ui/dist/theme-light.css';
const hostGrotesk = Host_Grotesk({
subsets: ['latin'],
@@ -1,6 +1,4 @@
import { FAQ_DATA, MENU_DATA, TRUSTED_BY_DATA } from '@/app/_constants';
import { fetchCommunityStats } from '@/lib/community/fetch-community-stats';
import { mergeSocialLinkLabels } from '@/lib/community/merge-social-link-labels';
import {
ENGAGEMENT_BAND_DATA,
HERO_DATA,
@@ -10,7 +8,8 @@ import {
} from '@/app/partner/_constants';
import { Body, Eyebrow, Heading, LinkButton } from '@/design-system/components';
import { Pages } from '@/enums/pages';
import { ScrollReveal } from '@/motion/ScrollReveal';
import { fetchCommunityStats } from '@/lib/community/fetch-community-stats';
import { mergeSocialLinkLabels } from '@/lib/community/merge-social-link-labels';
import { EngagementBand } from '@/sections/EngagementBand/components';
import { Faq } from '@/sections/Faq/components';
import { Hero } from '@/sections/Hero/components';
@@ -30,10 +29,7 @@ export const metadata: Metadata = {
export default async function PartnerPage() {
const stats = await fetchCommunityStats();
const menuSocialLinks = mergeSocialLinkLabels(
MENU_DATA.socialLinks,
stats,
);
const menuSocialLinks = mergeSocialLinkLabels(MENU_DATA.socialLinks, stats);
return (
<>
@@ -49,156 +45,139 @@ export default async function PartnerPage() {
<Menu.Cta scheme="primary" />
</Menu.Root>
<ScrollReveal>
<Hero.Root backgroundColor={theme.colors.primary.background[100]}>
<Hero.Heading page={Pages.Partner} segments={HERO_DATA.heading} />
<Hero.Body page={Pages.Partner} body={HERO_DATA.body} />
<Hero.Cta>
<Hero.Root backgroundColor={theme.colors.primary.background[100]}>
<Hero.Heading page={Pages.Partner} segments={HERO_DATA.heading} />
<Hero.Body page={Pages.Partner} body={HERO_DATA.body} />
<Hero.Cta>
<LinkButton
color="secondary"
href="https://app.twenty.com/welcome"
label="Become a partner"
type="anchor"
variant="outlined"
/>
<LinkButton
color="secondary"
href="https://app.twenty.com/welcome"
label="Find a partner"
type="anchor"
variant="contained"
/>
</Hero.Cta>
<Hero.Illustration
illustration={HERO_DATA.illustration}
backgroundColor={theme.colors.secondary.background[100]}
/>
</Hero.Root>
<TrustedBy.Root>
<TrustedBy.Separator separator={TRUSTED_BY_DATA.separator} />
<TrustedBy.Logos
clientCountLabel={TRUSTED_BY_DATA.clientCountLabel}
logos={TRUSTED_BY_DATA.logos}
/>
</TrustedBy.Root>
<EngagementBand.Root
backgroundColor={theme.colors.primary.background[100]}
>
<EngagementBand.Strip
fillColor={theme.colors.secondary.background[100]}
variant="secondary"
>
<EngagementBand.Copy>
<EngagementBand.Heading segments={ENGAGEMENT_BAND_DATA.heading} />
<EngagementBand.Body body={ENGAGEMENT_BAND_DATA.body} />
</EngagementBand.Copy>
<EngagementBand.Actions>
<LinkButton
color="secondary"
color="primary"
href="https://app.twenty.com/welcome"
label="Become a partner"
type="anchor"
variant="outlined"
/>
<LinkButton
color="secondary"
href="https://app.twenty.com/welcome"
label="Find a partner"
label="Read our case studies"
type="anchor"
variant="contained"
/>
</Hero.Cta>
<Hero.Illustration
illustration={HERO_DATA.illustration}
backgroundColor={theme.colors.secondary.background[100]}
</EngagementBand.Actions>
</EngagementBand.Strip>
</EngagementBand.Root>
<ThreeCards.Root backgroundColor={theme.colors.secondary.background[5]}>
<ThreeCards.Intro page={Pages.Partner} align="left">
<Eyebrow
colorScheme="primary"
heading={THREE_CARDS_ILLUSTRATION_DATA.eyebrow.heading}
/>
</Hero.Root>
</ScrollReveal>
<ScrollReveal>
<TrustedBy.Root>
<TrustedBy.Separator separator={TRUSTED_BY_DATA.separator} />
<TrustedBy.Logos
clientCountLabel={TRUSTED_BY_DATA.clientCountLabel}
logos={TRUSTED_BY_DATA.logos}
<Heading
segments={THREE_CARDS_ILLUSTRATION_DATA.heading}
size="lg"
weight="light"
/>
</TrustedBy.Root>
</ScrollReveal>
<Body body={THREE_CARDS_ILLUSTRATION_DATA.body} size="sm" />
</ThreeCards.Intro>
<ThreeCards.IllustrationCards
illustrationCards={THREE_CARDS_ILLUSTRATION_DATA.illustrationCards}
variant="simple"
/>
</ThreeCards.Root>
<ScrollReveal>
<EngagementBand.Root
backgroundColor={theme.colors.primary.background[100]}
>
<EngagementBand.Strip
fillColor={theme.colors.secondary.background[100]}
variant="secondary"
>
<EngagementBand.Copy>
<EngagementBand.Heading segments={ENGAGEMENT_BAND_DATA.heading} />
<EngagementBand.Body body={ENGAGEMENT_BAND_DATA.body} />
</EngagementBand.Copy>
<EngagementBand.Actions>
<LinkButton
color="primary"
href="https://app.twenty.com/welcome"
label="Read our case studies"
type="anchor"
variant="contained"
/>
</EngagementBand.Actions>
</EngagementBand.Strip>
</EngagementBand.Root>
</ScrollReveal>
<Testimonials.Root
backgroundColor={theme.colors.secondary.background[5]}
color={theme.colors.primary.text[100]}
>
<Testimonials.Carousel
eyebrow={TESTIMONIALS_DATA.eyebrow}
illustration={TESTIMONIALS_DATA.illustration}
testimonials={TESTIMONIALS_DATA.testimonials}
/>
</Testimonials.Root>
<ScrollReveal>
<ThreeCards.Root backgroundColor={theme.colors.secondary.background[5]}>
<ThreeCards.Intro page={Pages.Partner} align="left">
<Eyebrow
colorScheme="primary"
heading={THREE_CARDS_ILLUSTRATION_DATA.eyebrow.heading}
/>
<Heading
segments={THREE_CARDS_ILLUSTRATION_DATA.heading}
size="lg"
weight="light"
/>
<Body body={THREE_CARDS_ILLUSTRATION_DATA.body} size="sm" />
</ThreeCards.Intro>
<ThreeCards.IllustrationCards
illustrationCards={THREE_CARDS_ILLUSTRATION_DATA.illustrationCards}
variant="simple"
<Signoff.Root
backgroundColor={theme.colors.primary.background[100]}
color={theme.colors.primary.text[100]}
>
<Signoff.Heading segments={SIGNOFF_DATA.heading} />
<Signoff.Body body={SIGNOFF_DATA.body} />
<Signoff.Cta>
<LinkButton
color="secondary"
href="https://app.twenty.com/welcome"
label="Become a partner"
type="anchor"
variant="outlined"
/>
</ThreeCards.Root>
</ScrollReveal>
<ScrollReveal>
<Testimonials.Root
backgroundColor={theme.colors.secondary.background[5]}
color={theme.colors.primary.text[100]}
>
<Testimonials.Carousel
eyebrow={TESTIMONIALS_DATA.eyebrow}
illustration={TESTIMONIALS_DATA.illustration}
testimonials={TESTIMONIALS_DATA.testimonials}
<LinkButton
color="secondary"
href="https://twenty.com/contact"
label="Talk to us"
type="anchor"
variant="contained"
/>
</Testimonials.Root>
</ScrollReveal>
</Signoff.Cta>
</Signoff.Root>
<ScrollReveal>
<Signoff.Root
backgroundColor={theme.colors.primary.background[100]}
color={theme.colors.primary.text[100]}
>
<Signoff.Heading segments={SIGNOFF_DATA.heading} />
<Signoff.Body body={SIGNOFF_DATA.body} />
<Signoff.Cta>
<Faq.Root illustration={FAQ_DATA.illustration}>
<Faq.Intro>
<Eyebrow colorScheme="secondary" heading={FAQ_DATA.eyebrow.heading} />
<Faq.Heading segments={FAQ_DATA.heading} />
<Faq.Cta>
<LinkButton
color="secondary"
color="primary"
href="https://app.twenty.com/welcome"
label="Become a partner"
label="Get started"
type="anchor"
variant="outlined"
variant="contained"
/>
<LinkButton
color="secondary"
color="primary"
href="https://twenty.com/contact"
label="Talk to us"
type="anchor"
variant="contained"
variant="outlined"
/>
</Signoff.Cta>
</Signoff.Root>
</ScrollReveal>
<ScrollReveal>
<Faq.Root illustration={FAQ_DATA.illustration}>
<Faq.Intro>
<Eyebrow
colorScheme="secondary"
heading={FAQ_DATA.eyebrow.heading}
/>
<Faq.Heading segments={FAQ_DATA.heading} />
<Faq.Cta>
<LinkButton
color="primary"
href="https://app.twenty.com/welcome"
label="Get started"
type="anchor"
variant="contained"
/>
<LinkButton
color="primary"
href="https://twenty.com/contact"
label="Talk to us"
type="anchor"
variant="outlined"
/>
</Faq.Cta>
</Faq.Intro>
<Faq.Items questions={FAQ_DATA.questions} />
</Faq.Root>
</ScrollReveal>
</Faq.Cta>
</Faq.Intro>
<Faq.Items questions={FAQ_DATA.questions} />
</Faq.Root>
</>
);
}
@@ -1,6 +1,4 @@
import { FAQ_DATA, MENU_DATA } from '@/app/_constants';
import { fetchCommunityStats } from '@/lib/community/fetch-community-stats';
import { mergeSocialLinkLabels } from '@/lib/community/merge-social-link-labels';
import {
ENGAGEMENT_BAND_DATA,
HERO_DATA,
@@ -9,7 +7,8 @@ import {
} from '@/app/pricing/_constants';
import { Eyebrow, LinkButton } from '@/design-system/components';
import { Pages } from '@/enums/pages';
import { ScrollReveal } from '@/motion/ScrollReveal';
import { fetchCommunityStats } from '@/lib/community/fetch-community-stats';
import { mergeSocialLinkLabels } from '@/lib/community/merge-social-link-labels';
import { EngagementBand } from '@/sections/EngagementBand/components';
import { Faq } from '@/sections/Faq/components';
import { Hero } from '@/sections/Hero/components';
@@ -28,10 +27,7 @@ export const metadata: Metadata = {
export default async function PricingPage() {
const stats = await fetchCommunityStats();
const menuSocialLinks = mergeSocialLinkLabels(
MENU_DATA.socialLinks,
stats,
);
const menuSocialLinks = mergeSocialLinkLabels(MENU_DATA.socialLinks, stats);
return (
<>
@@ -47,51 +43,41 @@ export default async function PricingPage() {
<Menu.Cta scheme="primary" />
</Menu.Root>
<ScrollReveal>
<Hero.Root backgroundColor={theme.colors.secondary.background[5]}>
<Hero.Heading page={Pages.Pricing} segments={HERO_DATA.heading} />
<Hero.Body page={Pages.Pricing} body={HERO_DATA.body} />
</Hero.Root>
</ScrollReveal>
<Hero.Root backgroundColor={theme.colors.secondary.background[5]}>
<Hero.Heading page={Pages.Pricing} segments={HERO_DATA.heading} />
<Hero.Body page={Pages.Pricing} body={HERO_DATA.body} />
</Hero.Root>
<ScrollReveal>
<Plans.Root backgroundColor={theme.colors.secondary.background[5]}>
<Plans.Content />
</Plans.Root>
</ScrollReveal>
<Plans.Root backgroundColor={theme.colors.secondary.background[5]}>
<Plans.Content />
</Plans.Root>
<ScrollReveal>
<EngagementBand.Root
backgroundColor={theme.colors.secondary.background[5]}
<EngagementBand.Root
backgroundColor={theme.colors.secondary.background[5]}
>
<EngagementBand.Strip
fillColor={theme.colors.primary.background[100]}
variant="primary"
>
<EngagementBand.Strip
fillColor={theme.colors.primary.background[100]}
variant="primary"
>
<EngagementBand.Copy>
<EngagementBand.Heading segments={ENGAGEMENT_BAND_DATA.heading} />
<EngagementBand.Body body={ENGAGEMENT_BAND_DATA.body} />
</EngagementBand.Copy>
<EngagementBand.Actions>
<LinkButton
color="secondary"
href="https://app.twenty.com/welcome"
label="Read our case studies"
type="anchor"
variant="contained"
/>
</EngagementBand.Actions>
</EngagementBand.Strip>
</EngagementBand.Root>
</ScrollReveal>
<EngagementBand.Copy>
<EngagementBand.Heading segments={ENGAGEMENT_BAND_DATA.heading} />
<EngagementBand.Body body={ENGAGEMENT_BAND_DATA.body} />
</EngagementBand.Copy>
<EngagementBand.Actions>
<LinkButton
color="secondary"
href="https://app.twenty.com/welcome"
label="Read our case studies"
type="anchor"
variant="contained"
/>
</EngagementBand.Actions>
</EngagementBand.Strip>
</EngagementBand.Root>
<ScrollReveal>
<PlanTable.Root
backgroundColor={theme.colors.secondary.background[100]}
>
<PlanTable.Content data={PLAN_TABLE_DATA} />
</PlanTable.Root>
</ScrollReveal>
<PlanTable.Root backgroundColor={theme.colors.secondary.background[100]}>
<PlanTable.Content data={PLAN_TABLE_DATA} />
</PlanTable.Root>
<Salesforce.Flow
backgroundColor={theme.colors.secondary.background[5]}
@@ -100,34 +86,29 @@ export default async function PricingPage() {
pricing={SALESFORCE_DATA.pricing}
/>
<ScrollReveal>
<Faq.Root illustration={FAQ_DATA.illustration}>
<Faq.Intro>
<Eyebrow
colorScheme="secondary"
heading={FAQ_DATA.eyebrow.heading}
<Faq.Root illustration={FAQ_DATA.illustration}>
<Faq.Intro>
<Eyebrow colorScheme="secondary" heading={FAQ_DATA.eyebrow.heading} />
<Faq.Heading segments={FAQ_DATA.heading} />
<Faq.Cta>
<LinkButton
color="primary"
href="https://app.twenty.com/welcome"
label="Get started"
type="anchor"
variant="contained"
/>
<Faq.Heading segments={FAQ_DATA.heading} />
<Faq.Cta>
<LinkButton
color="primary"
href="https://app.twenty.com/welcome"
label="Get started"
type="anchor"
variant="contained"
/>
<LinkButton
color="primary"
href="https://twenty.com/contact"
label="Talk to us"
type="anchor"
variant="outlined"
/>
</Faq.Cta>
</Faq.Intro>
<Faq.Items questions={FAQ_DATA.questions} />
</Faq.Root>
</ScrollReveal>
<LinkButton
color="primary"
href="https://twenty.com/contact"
label="Talk to us"
type="anchor"
variant="outlined"
/>
</Faq.Cta>
</Faq.Intro>
<Faq.Items questions={FAQ_DATA.questions} />
</Faq.Root>
</>
);
}
@@ -1,6 +1,4 @@
import { FAQ_DATA, MENU_DATA, TRUSTED_BY_DATA } from '@/app/_constants';
import { fetchCommunityStats } from '@/lib/community/fetch-community-stats';
import { mergeSocialLinkLabels } from '@/lib/community/merge-social-link-labels';
import {
DEMO_DATA,
FEATURE_DATA,
@@ -11,7 +9,8 @@ import {
} from '@/app/product/_constants';
import { Body, Eyebrow, Heading, LinkButton } from '@/design-system/components';
import { Pages } from '@/enums/pages';
import { ScrollReveal } from '@/motion/ScrollReveal';
import { fetchCommunityStats } from '@/lib/community/fetch-community-stats';
import { mergeSocialLinkLabels } from '@/lib/community/merge-social-link-labels';
import { Demo } from '@/sections/Demo/components';
import { Faq } from '@/sections/Faq/components';
import { Feature } from '@/sections/Feature/components';
@@ -32,10 +31,7 @@ export const metadata: Metadata = {
export default async function ProductPage() {
const stats = await fetchCommunityStats();
const menuSocialLinks = mergeSocialLinkLabels(
MENU_DATA.socialLinks,
stats,
);
const menuSocialLinks = mergeSocialLinkLabels(MENU_DATA.socialLinks, stats);
return (
<>
@@ -51,80 +47,67 @@ export default async function ProductPage() {
<Menu.Cta scheme="primary" />
</Menu.Root>
<ScrollReveal>
<Hero.Root backgroundColor={theme.colors.primary.background[100]}>
<Hero.Heading page={Pages.Product} segments={HERO_DATA.heading} />
<Hero.Body page={Pages.Product} body={HERO_DATA.body} />
<Hero.Cta>
<LinkButton
color="secondary"
href="https://app.twenty.com/welcome"
label="Get started"
type="anchor"
variant="contained"
/>
</Hero.Cta>
<Hero.Illustration
illustration={HERO_DATA.illustration}
backgroundColor={theme.colors.secondary.background[5]}
<Hero.Root backgroundColor={theme.colors.primary.background[100]}>
<Hero.Heading page={Pages.Product} segments={HERO_DATA.heading} />
<Hero.Body page={Pages.Product} body={HERO_DATA.body} />
<Hero.Cta>
<LinkButton
color="secondary"
href="https://app.twenty.com/welcome"
label="Get started"
type="anchor"
variant="contained"
/>
</Hero.Root>
</ScrollReveal>
</Hero.Cta>
<Hero.Illustration
illustration={HERO_DATA.illustration}
backgroundColor={theme.colors.secondary.background[5]}
/>
</Hero.Root>
<ScrollReveal>
<TrustedBy.Root>
<TrustedBy.Separator separator={TRUSTED_BY_DATA.separator} />
<TrustedBy.Logos
clientCountLabel={TRUSTED_BY_DATA.clientCountLabel}
logos={TRUSTED_BY_DATA.logos}
/>
</TrustedBy.Root>
</ScrollReveal>
<TrustedBy.Root>
<TrustedBy.Separator separator={TRUSTED_BY_DATA.separator} />
<TrustedBy.Logos
clientCountLabel={TRUSTED_BY_DATA.clientCountLabel}
logos={TRUSTED_BY_DATA.logos}
/>
</TrustedBy.Root>
<ScrollReveal>
<Tabs.Root>
<Tabs.Root>
<Eyebrow colorScheme="secondary" heading={TABS_DATA.eyebrow.heading} />
<Tabs.Heading segments={TABS_DATA.heading} />
<Tabs.Body body={TABS_DATA.body} />
<Tabs.TabGroup tabs={TABS_DATA.tabs} />
</Tabs.Root>
<Feature.Root backgroundColor={theme.colors.primary.background[100]}>
<Feature.Intro align="center" page={Pages.Product}>
<Eyebrow
colorScheme="secondary"
heading={TABS_DATA.eyebrow.heading}
colorScheme="primary"
heading={FEATURE_DATA.eyebrow.heading}
/>
<Tabs.Heading segments={TABS_DATA.heading} />
<Tabs.Body body={TABS_DATA.body} />
<Tabs.TabGroup tabs={TABS_DATA.tabs} />
</Tabs.Root>
</ScrollReveal>
<Heading segments={FEATURE_DATA.heading} size="lg" weight="light" />
</Feature.Intro>
<Feature.Tiles mask={FEATURE_DATA.mask} tiles={FEATURE_DATA.tiles} />
</Feature.Root>
<ScrollReveal>
<Feature.Root backgroundColor={theme.colors.primary.background[100]}>
<Feature.Intro align="center" page={Pages.Product}>
<Eyebrow
colorScheme="primary"
heading={FEATURE_DATA.eyebrow.heading}
/>
<Heading segments={FEATURE_DATA.heading} size="lg" weight="light" />
</Feature.Intro>
<Feature.Tiles mask={FEATURE_DATA.mask} tiles={FEATURE_DATA.tiles} />
</Feature.Root>
</ScrollReveal>
<ScrollReveal>
<ThreeCards.Root backgroundColor={theme.colors.primary.background[100]}>
<ThreeCards.Intro page={Pages.Product} align="left">
<Eyebrow
colorScheme="primary"
heading={THREE_CARDS_ILLUSTRATION_DATA.eyebrow.heading}
/>
<Heading
segments={THREE_CARDS_ILLUSTRATION_DATA.heading}
size="lg"
weight="light"
/>
<Body body={THREE_CARDS_ILLUSTRATION_DATA.body} size="sm" />
</ThreeCards.Intro>
<ThreeCards.IllustrationCards
illustrationCards={THREE_CARDS_ILLUSTRATION_DATA.illustrationCards}
<ThreeCards.Root backgroundColor={theme.colors.primary.background[100]}>
<ThreeCards.Intro page={Pages.Product} align="left">
<Eyebrow
colorScheme="primary"
heading={THREE_CARDS_ILLUSTRATION_DATA.eyebrow.heading}
/>
</ThreeCards.Root>
</ScrollReveal>
<Heading
segments={THREE_CARDS_ILLUSTRATION_DATA.heading}
size="lg"
weight="light"
/>
<Body body={THREE_CARDS_ILLUSTRATION_DATA.body} size="sm" />
</ThreeCards.Intro>
<ThreeCards.IllustrationCards
illustrationCards={THREE_CARDS_ILLUSTRATION_DATA.illustrationCards}
/>
</ThreeCards.Root>
<ProductStepper.Flow
body={STEPPER_DATA.body}
@@ -133,51 +116,44 @@ export default async function ProductPage() {
steps={STEPPER_DATA.steps}
/>
<ScrollReveal>
<Demo.Root>
<Eyebrow colorScheme="primary" heading={DEMO_DATA.eyebrow.heading} />
<Demo.Heading segments={DEMO_DATA.heading} />
<Demo.Cta>
<Demo.Root>
<Eyebrow colorScheme="primary" heading={DEMO_DATA.eyebrow.heading} />
<Demo.Heading segments={DEMO_DATA.heading} />
<Demo.Cta>
<LinkButton
color="secondary"
href="https://app.twenty.com/welcome"
label="Try twenty cloud"
type="anchor"
variant="contained"
/>
</Demo.Cta>
<Demo.Screenshot image={DEMO_DATA.image} />
</Demo.Root>
<Faq.Root illustration={FAQ_DATA.illustration}>
<Faq.Intro>
<Eyebrow colorScheme="secondary" heading={FAQ_DATA.eyebrow.heading} />
<Faq.Heading segments={FAQ_DATA.heading} />
<Faq.Cta>
<LinkButton
color="secondary"
color="primary"
href="https://app.twenty.com/welcome"
label="Try twenty cloud"
label="Get started"
type="anchor"
variant="contained"
/>
</Demo.Cta>
<Demo.Screenshot image={DEMO_DATA.image} />
</Demo.Root>
</ScrollReveal>
<ScrollReveal>
<Faq.Root illustration={FAQ_DATA.illustration}>
<Faq.Intro>
<Eyebrow
colorScheme="secondary"
heading={FAQ_DATA.eyebrow.heading}
<LinkButton
color="primary"
href="https://twenty.com/contact"
label="Talk to us"
type="anchor"
variant="outlined"
/>
<Faq.Heading segments={FAQ_DATA.heading} />
<Faq.Cta>
<LinkButton
color="primary"
href="https://app.twenty.com/welcome"
label="Get started"
type="anchor"
variant="contained"
/>
<LinkButton
color="primary"
href="https://twenty.com/contact"
label="Talk to us"
type="anchor"
variant="outlined"
/>
</Faq.Cta>
</Faq.Intro>
<Faq.Items questions={FAQ_DATA.questions} />
</Faq.Root>
</ScrollReveal>
</Faq.Cta>
</Faq.Intro>
<Faq.Items questions={FAQ_DATA.questions} />
</Faq.Root>
</>
);
}
@@ -10,7 +10,6 @@ import { mergeSocialLinkLabels } from '@/lib/community/merge-social-link-labels'
import { fetchLatestGithubReleaseTag } from '@/lib/github/fetch-latest-release-tag';
import { getVisibleReleaseNotes } from '@/lib/releases/get-visible-releases';
import { loadLocalReleaseNotes } from '@/lib/releases/load-local-release-notes';
import { ScrollReveal } from '@/motion/ScrollReveal';
import { Hero } from '@/sections/Hero/components';
import { Menu } from '@/sections/Menu/components';
import { ReleaseNotes } from '@/sections/ReleaseNotes/components';
@@ -50,30 +49,28 @@ export default async function ReleaseNotesPage() {
<Menu.Cta scheme="primary" />
</Menu.Root>
<ScrollReveal>
<Hero.Root backgroundColor={theme.colors.primary.background[100]}>
<Hero.Heading
page={Pages.ReleaseNotes}
segments={RELEASE_NOTES_HERO_HEADING}
size="lg"
weight="light"
<Hero.Root backgroundColor={theme.colors.primary.background[100]}>
<Hero.Heading
page={Pages.ReleaseNotes}
segments={RELEASE_NOTES_HERO_HEADING}
size="lg"
weight="light"
/>
<Hero.Body
page={Pages.ReleaseNotes}
body={RELEASE_NOTES_HERO_BODY}
size="sm"
/>
<Hero.Cta>
<LinkButton
color="secondary"
href="https://github.com/twentyhq/twenty/releases"
label="GitHub releases"
type="anchor"
variant="outlined"
/>
<Hero.Body
page={Pages.ReleaseNotes}
body={RELEASE_NOTES_HERO_BODY}
size="sm"
/>
<Hero.Cta>
<LinkButton
color="secondary"
href="https://github.com/twentyhq/twenty/releases"
label="GitHub releases"
type="anchor"
variant="outlined"
/>
</Hero.Cta>
</Hero.Root>
</ScrollReveal>
</Hero.Cta>
</Hero.Root>
<ReleaseNotes.Root>
{allNotes.length === 0 ? (
@@ -16,7 +16,6 @@ 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';
import { ScrollReveal } from '@/motion/ScrollReveal';
import { Editorial } from '@/sections/Editorial/components';
import { Hero } from '@/sections/Hero/components';
import { Marquee } from '@/sections/Marquee/components';
@@ -52,114 +51,96 @@ export default async function WhyTwentyPage() {
<Menu.Cta scheme="secondary" />
</Menu.Root>
<ScrollReveal>
<Hero.Root backgroundColor={theme.colors.secondary.background[100]}>
<Hero.Heading
page={Pages.WhyTwenty}
segments={HERO_DATA.heading}
size="xl"
/>
<Hero.Body page={Pages.WhyTwenty} body={HERO_DATA.body} />
<Hero.WhyTwentyVisual
image={HERO_DATA.image}
illustration={HERO_DATA.illustration}
/>
</Hero.Root>
</ScrollReveal>
<ScrollReveal>
<Editorial.Root
backgroundColor={theme.colors.secondary.background[100]}
color={theme.colors.secondary.text[100]}
mutedColor={theme.colors.secondary.text[60]}
>
<Editorial.Intro>
<Editorial.Eyebrow
colorScheme="secondary"
eyebrow={EDITORIAL_ONE.eyebrow!}
/>
<Editorial.Heading segments={EDITORIAL_ONE.heading!} />
</Editorial.Intro>
<Editorial.Body body={EDITORIAL_ONE.body} layout="two-column" />
</Editorial.Root>
</ScrollReveal>
<ScrollReveal>
<Quote.Root backgroundColor={theme.colors.secondary.background[100]}>
<Quote.Visual illustration={QUOTE_DATA.illustration} />
<Quote.Heading segments={QUOTE_DATA.heading} />
</Quote.Root>
</ScrollReveal>
<ScrollReveal>
<Editorial.Root
backgroundColor={theme.colors.secondary.background[100]}
color={theme.colors.secondary.text[100]}
mutedColor={theme.colors.secondary.text[60]}
>
<Editorial.Body body={EDITORIAL_TWO.body} layout="centered" />
</Editorial.Root>
</ScrollReveal>
<ScrollReveal>
<Marquee.Root
backgroundColor={theme.colors.secondary.background[100]}
color={theme.colors.secondary.text[100]}
heading={MARQUEE_DATA.heading}
<Hero.Root backgroundColor={theme.colors.secondary.background[100]}>
<Hero.Heading
page={Pages.WhyTwenty}
segments={HERO_DATA.heading}
size="xl"
/>
</ScrollReveal>
<Hero.Body page={Pages.WhyTwenty} body={HERO_DATA.body} />
<Hero.WhyTwentyVisual
image={HERO_DATA.image}
illustration={HERO_DATA.illustration}
/>
</Hero.Root>
<ScrollReveal>
<Editorial.Root
backgroundColor={theme.colors.secondary.background[100]}
color={theme.colors.secondary.text[100]}
mutedColor={theme.colors.secondary.text[60]}
>
<Editorial.Intro>
<Editorial.Eyebrow
colorScheme="secondary"
eyebrow={EDITORIAL_THREE.eyebrow!}
/>
<Editorial.Heading segments={EDITORIAL_THREE.heading!} />
</Editorial.Intro>
<Editorial.Body body={EDITORIAL_THREE.body} layout="indented" />
</Editorial.Root>
</ScrollReveal>
<Editorial.Root
backgroundColor={theme.colors.secondary.background[100]}
color={theme.colors.secondary.text[100]}
mutedColor={theme.colors.secondary.text[60]}
>
<Editorial.Intro>
<Editorial.Eyebrow
colorScheme="secondary"
eyebrow={EDITORIAL_ONE.eyebrow!}
/>
<Editorial.Heading segments={EDITORIAL_ONE.heading!} />
</Editorial.Intro>
<Editorial.Body body={EDITORIAL_ONE.body} layout="two-column" />
</Editorial.Root>
<ScrollReveal>
<Statement.Root
backgroundColor={theme.colors.secondary.background[100]}
color={theme.colors.secondary.text[100]}
>
<Statement.Heading segments={STATEMENT_ONE.heading} />
</Statement.Root>
</ScrollReveal>
<Quote.Root backgroundColor={theme.colors.secondary.background[100]}>
<Quote.Visual illustration={QUOTE_DATA.illustration} />
<Quote.Heading segments={QUOTE_DATA.heading} />
</Quote.Root>
<ScrollReveal>
<Statement.Root
backgroundColor={theme.colors.primary.background[100]}
color={theme.colors.primary.text[100]}
>
<Statement.Heading segments={STATEMENT_TWO.heading} />
</Statement.Root>
</ScrollReveal>
<Editorial.Root
backgroundColor={theme.colors.secondary.background[100]}
color={theme.colors.secondary.text[100]}
mutedColor={theme.colors.secondary.text[60]}
>
<Editorial.Body body={EDITORIAL_TWO.body} layout="centered" />
</Editorial.Root>
<ScrollReveal>
<Editorial.Root
backgroundColor={theme.colors.primary.background[100]}
color={theme.colors.primary.text[100]}
mutedColor={theme.colors.primary.text[60]}
>
<Editorial.Intro>
<Editorial.Eyebrow
colorScheme="primary"
eyebrow={EDITORIAL_FOUR.eyebrow!}
/>
<Editorial.Heading segments={EDITORIAL_FOUR.heading!} />
</Editorial.Intro>
<Editorial.Body body={EDITORIAL_FOUR.body} layout="two-column" />
</Editorial.Root>
</ScrollReveal>
<Marquee.Root
backgroundColor={theme.colors.secondary.background[100]}
color={theme.colors.secondary.text[100]}
heading={MARQUEE_DATA.heading}
/>
<Editorial.Root
backgroundColor={theme.colors.secondary.background[100]}
color={theme.colors.secondary.text[100]}
mutedColor={theme.colors.secondary.text[60]}
>
<Editorial.Intro>
<Editorial.Eyebrow
colorScheme="secondary"
eyebrow={EDITORIAL_THREE.eyebrow!}
/>
<Editorial.Heading segments={EDITORIAL_THREE.heading!} />
</Editorial.Intro>
<Editorial.Body body={EDITORIAL_THREE.body} layout="indented" />
</Editorial.Root>
<Statement.Root
backgroundColor={theme.colors.secondary.background[100]}
color={theme.colors.secondary.text[100]}
>
<Statement.Heading segments={STATEMENT_ONE.heading} />
</Statement.Root>
<Statement.Root
backgroundColor={theme.colors.primary.background[100]}
color={theme.colors.primary.text[100]}
>
<Statement.Heading segments={STATEMENT_TWO.heading} />
</Statement.Root>
<Editorial.Root
backgroundColor={theme.colors.primary.background[100]}
color={theme.colors.primary.text[100]}
mutedColor={theme.colors.primary.text[60]}
>
<Editorial.Intro>
<Editorial.Eyebrow
colorScheme="primary"
eyebrow={EDITORIAL_FOUR.eyebrow!}
/>
<Editorial.Heading segments={EDITORIAL_FOUR.heading!} />
</Editorial.Intro>
<Editorial.Body body={EDITORIAL_FOUR.body} layout="two-column" />
</Editorial.Root>
<WhyTwentyStepper.Flow
body={STEPPER_DATA.body}
@@ -167,26 +148,24 @@ export default async function WhyTwentyPage() {
illustration={STEPPER_DATA.illustration}
/>
<ScrollReveal>
<Signoff.Root
backgroundColor={theme.colors.primary.text[10]}
color={theme.colors.secondary.text[100]}
variant="shaped"
shapeFillColor={theme.colors.secondary.background[100]}
>
<Signoff.Heading segments={SIGNOFF_DATA.heading} />
<Signoff.Body body={SIGNOFF_DATA.body} />
<Signoff.Cta>
<LinkButton
color="primary"
href="https://app.twenty.com/welcome"
label="Get started"
type="anchor"
variant="contained"
/>
</Signoff.Cta>
</Signoff.Root>
</ScrollReveal>
<Signoff.Root
backgroundColor={theme.colors.primary.text[10]}
color={theme.colors.secondary.text[100]}
variant="shaped"
shapeFillColor={theme.colors.secondary.background[100]}
>
<Signoff.Heading segments={SIGNOFF_DATA.heading} />
<Signoff.Body body={SIGNOFF_DATA.body} />
<Signoff.Cta>
<LinkButton
color="primary"
href="https://app.twenty.com/welcome"
label="Get started"
type="anchor"
variant="contained"
/>
</Signoff.Cta>
</Signoff.Root>
</>
);
}
@@ -24,16 +24,6 @@ export const buttonBaseStyles = `
outline: 1px solid ${theme.colors.highlight[100]};
outline-offset: 1px;
}
transition: transform 0.2s cubic-bezier(0.2, 0.8, 0.2, 1);
&:hover {
transform: scale(1.04);
}
&:active {
transform: scale(0.96);
}
`;
const Label = styled.span`
@@ -5,11 +5,6 @@ import { styled } from '@linaria/react';
const StyledHeading = styled(BaseHeading)`
max-width: 360px;
transition: transform 0.6s cubic-bezier(0.16, 1, 0.3, 1);
&:hover {
transform: translateY(-4px);
}
@media (min-width: ${theme.breakpoints.md}px) {
max-width: 672px;
@@ -6,7 +6,6 @@ import { styled } from '@linaria/react';
const BodyParagraph = styled.div`
color: var(--editorial-body-color);
min-width: 0;
transition: color 0.4s ease, opacity 0.4s ease;
`;
const TwoColumnGrid = styled.div`
@@ -19,27 +18,16 @@ const TwoColumnGrid = styled.div`
row-gap: ${theme.spacing(6)};
width: 100%;
/* When hovering a paragraph, dim the others */
&:has(${BodyParagraph}:hover) ${BodyParagraph}:not(:hover) {
opacity: 0.4;
}
@media (min-width: ${theme.breakpoints.md}px) {
grid-template-columns: repeat(2, minmax(0, 1fr));
}
`;
// 1440 artboard: 384 + 556 + 500 — only two-column uses horizontal centering.
const SingleColumnBody = styled.div`
max-width: 556px;
min-width: 0;
width: 100%;
/* When hovering a paragraph, dim the others */
&:has(${BodyParagraph}:hover) ${BodyParagraph}:not(:hover) {
opacity: 0.4;
}
@media (min-width: ${theme.breakpoints.md}px) {
margin-left: 384px;
margin-right: 500px;
@@ -6,11 +6,6 @@ const HeadingWrap = styled.div`
max-width: 617px;
min-width: 0;
width: 100%;
transition: transform 0.5s cubic-bezier(0.16, 1, 0.3, 1);
&:hover {
transform: translateX(8px);
}
`;
type EditorialHeadingProps = {
@@ -14,23 +14,6 @@ const Inner = styled.div`
flex-direction: column;
gap: ${theme.spacing(10)};
width: 100%;
/* Smooth transition for the children elements */
& > * {
transition: opacity 0.6s cubic-bezier(0.16, 1, 0.3, 1), transform 0.6s cubic-bezier(0.16, 1, 0.3, 1);
}
/* When hovering over any direct child, aggressively shrink and dim the other */
&:has(> div:hover) > div:not(:hover) {
opacity: 0.1;
transform: scale(0.95) translateY(12px);
}
/* Expand the hovered element */
&:has(> div:hover) > div:hover {
transform: scale(1.02);
z-index: 2;
}
`;
const StyledContainer = styled(Container)`
@@ -5,12 +5,6 @@ import { styled } from '@linaria/react';
const StyledHeading = styled(BaseHeading)`
white-space: pre-line;
transition: opacity 0.4s ease, transform 0.4s cubic-bezier(0.16, 1, 0.3, 1);
&:hover {
opacity: 0.8;
transform: translateY(-4px);
}
@media (min-width: ${theme.breakpoints.md}px) {
max-width: 668px;
@@ -2,7 +2,6 @@ import { Heading as BaseHeading } from '@/design-system/components';
import type { HeadingType } from '@/design-system/components/Heading/types/Heading';
import { theme } from '@/theme';
import { css } from '@linaria/core';
import { styled } from '@linaria/react';
const faqHeadingClassName = css`
white-space: pre-line;
@@ -12,31 +11,18 @@ const faqHeadingClassName = css`
}
`;
const HeadingWrapper = styled.div`
transition:
transform 0.4s cubic-bezier(0.16, 1, 0.3, 1),
opacity 0.4s ease;
&:hover {
transform: translateX(4px);
opacity: 0.8;
}
`;
type HeadingProps = {
segments: HeadingType[];
};
export function Heading({ segments }: HeadingProps) {
return (
<HeadingWrapper>
<BaseHeading
as="h2"
className={faqHeadingClassName}
segments={segments}
size="lg"
weight="light"
/>
</HeadingWrapper>
<BaseHeading
as="h2"
className={faqHeadingClassName}
segments={segments}
size="lg"
weight="light"
/>
);
}
@@ -1,4 +1,9 @@
import { Body, Heading, LazyEmbed, LinkButton } from '@/design-system/components';
import {
Body,
Heading,
LazyEmbed,
LinkButton,
} from '@/design-system/components';
import { CLIENT_ICONS } from '@/icons';
import { HelpedCardShape } from '@/sections/Helped/HelpedCardShape';
import type { HeadingCardType } from '@/sections/Helped/types/HeadingCard';
@@ -19,32 +24,11 @@ const CardRoot = styled.article`
position: relative;
row-gap: ${theme.spacing(2.5)};
width: 100%;
transition: transform 0.6s cubic-bezier(0.16, 1, 0.3, 1), filter 0.6s ease;
transition:
transform 0.6s cubic-bezier(0.16, 1, 0.3, 1),
filter 0.6s ease;
transform-style: preserve-3d;
perspective: 1200px;
/* Group hover context to dim other cards */
&:hover {
transform: translateY(-16px) scale(1.02) rotateX(2deg) rotateY(-2deg);
z-index: 10;
}
/* Complex hover shadow */
&::before {
content: '';
position: absolute;
inset: 0;
border-radius: ${theme.radius(4)};
box-shadow: 0 40px 80px -20px rgba(0,0,0,0.4);
opacity: 0;
transition: opacity 0.6s ease;
z-index: -1;
pointer-events: none;
}
&:hover::before {
opacity: 1;
}
`;
const LogoRow = styled.div`
@@ -67,12 +51,6 @@ const VisualShell = styled.div`
overflow: hidden;
position: relative;
width: 100%;
transition: transform 0.6s cubic-bezier(0.16, 1, 0.3, 1);
transform-style: preserve-3d;
${CardRoot}:hover & {
transform: translateZ(30px) scale(1.02);
}
`;
const StyledIframe = styled(LazyEmbed)`
@@ -1,12 +1,12 @@
'use client';
import { styled } from '@linaria/react';
import { useRef } from 'react';
import { Eyebrow, Heading } from '@/design-system/components';
import { HelpedSceneScrollLayoutEffect } from '@/sections/Helped/effect-components/HelpedSceneScrollLayoutEffect';
import type { HelpedDataType } from '@/sections/Helped/types/HelpedData';
import { CARD_WIDTH_DESKTOP } from '@/sections/Helped/utils/helped-scene-layout';
import { theme } from '@/theme';
import { styled } from '@linaria/react';
import { useRef } from 'react';
import { Card } from '../Card/Card';
const SCROLL_HEIGHT_VH = 420;
@@ -39,16 +39,6 @@ const HeadlineBlock = styled.div`
text-align: center;
width: 100%;
z-index: 1;
span {
transition: opacity 0.4s ease;
}
h1:has(span:hover) span:not(:hover),
h2:has(span:hover) span:not(:hover),
h3:has(span:hover) span:not(:hover) {
opacity: 0.2;
}
`;
const CardsLayer = styled.div`
@@ -11,18 +11,9 @@ const BodyContainer = styled.div`
margin-top: calc(${theme.spacing(2)} - ${theme.spacing(6)});
max-width: 360px;
width: 100%;
transition: color 0.4s ease;
&:hover {
color: ${theme.colors.primary.text[100]};
}
&[data-page=${Pages.WhyTwenty}] {
color: ${theme.colors.secondary.text[60]};
&:hover {
color: ${theme.colors.secondary.text[100]};
}
}
@media (min-width: ${theme.breakpoints.md}px) {
@@ -11,18 +11,6 @@ const HeadingContainer = styled.div`
width: 100%;
word-wrap: break-word;
/* Target the spans rendered by BaseHeading */
span {
transition: opacity 0.4s ease;
}
/* When hovering over the heading, dim un-hovered spans */
h1:has(span:hover) span:not(:hover),
h2:has(span:hover) span:not(:hover),
h3:has(span:hover) span:not(:hover) {
opacity: 0.2;
}
&[data-page=${Pages.WhyTwenty}] {
color: ${theme.colors.secondary.text[100]};
}
@@ -35,17 +35,6 @@ const StepBlock = styled.div`
min-height: 80vh;
opacity: 0.3;
row-gap: ${theme.spacing(4)};
transition: opacity 0.4s ease;
span {
transition: opacity 0.4s ease;
}
h1:has(span:hover) span:not(:hover),
h2:has(span:hover) span:not(:hover),
h3:has(span:hover) span:not(:hover) {
opacity: 0.2;
}
@media (min-width: ${theme.breakpoints.md}px) {
min-height: 100vh;
@@ -88,4 +77,4 @@ export function LeftColumn({
</StepsColumn>
</LeftColumnRoot>
);
}
}
@@ -8,11 +8,6 @@ const PhraseGroup = styled.div`
column-gap: ${theme.spacing(3)};
display: flex;
flex-shrink: 0;
&:hover > span {
opacity: 0.2;
transform: scale(0.95);
}
`;
const Segment = styled.span`
@@ -20,16 +15,6 @@ const Segment = styled.span`
font-weight: ${theme.font.weight.light};
line-height: 1;
white-space: nowrap;
transition:
opacity 0.4s ease,
transform 0.4s cubic-bezier(0.16, 1, 0.3, 1),
color 0.4s ease;
&:hover {
opacity: 1 !important;
transform: scale(1) !important;
color: ${theme.colors.highlight[100]} !important;
}
&[data-segment-index='0'] {
color: inherit;
@@ -1,4 +1,9 @@
import { Body, Heading, LazyEmbed, LinkButton } from '@/design-system/components';
import {
Body,
Heading,
LazyEmbed,
LinkButton,
} from '@/design-system/components';
import { CheckIcon } from '@/icons/informative/Check';
import type { PlanCardType } from '@/sections/Plans/types';
import { theme } from '@/theme';
@@ -19,19 +24,8 @@ const StyledCard = styled.div`
padding-right: ${theme.spacing(4)};
padding-top: ${theme.spacing(4)};
row-gap: ${theme.spacing(4)};
transition:
transform 0.6s cubic-bezier(0.16, 1, 0.3, 1),
box-shadow 0.6s cubic-bezier(0.16, 1, 0.3, 1),
border-color 0.6s cubic-bezier(0.16, 1, 0.3, 1);
position: relative;
z-index: 1;
&:hover {
border-color: ${theme.colors.highlight[100]};
transform: translateY(-12px) scale(1.02);
box-shadow: 0 24px 48px rgba(0, 0, 0, 0.12);
z-index: 10;
}
`;
const CardHeader = styled.div`
@@ -111,12 +105,7 @@ export function Card({ card, highlighted = false, maxBullets }: CardProps) {
<StyledCard style={{ gridRow: `span ${totalRows}` }}>
<CardHeader>
<CardHeaderInfo>
<Heading
as="h3"
segments={card.heading}
size="md"
weight="light"
/>
<Heading as="h3" segments={card.heading} size="md" weight="light" />
<PriceLine>
<Heading
as="h4"
@@ -124,11 +113,7 @@ export function Card({ card, highlighted = false, maxBullets }: CardProps) {
size="sm"
weight="regular"
/>
<Body
as="span"
body={card.price.body}
size="sm"
/>
<Body as="span" body={card.price.body} size="sm" />
</PriceLine>
</CardHeaderInfo>
<CardIllustration
@@ -1,10 +1,9 @@
import {
Heading as BaseHeading,
type HeadingProps,
} from "@/design-system/components/Heading/Heading";
import { theme } from "@/theme";
import { css } from "@linaria/core";
import { styled } from "@linaria/react";
} from '@/design-system/components/Heading/Heading';
import { theme } from '@/theme';
import { css } from '@linaria/core';
const problemHeadingClassName = css`
margin-top: calc(${theme.spacing(2)} - ${theme.spacing(10)});
@@ -14,29 +13,19 @@ const problemHeadingClassName = css`
}
`;
const HeadingWrapper = styled.div`
transition: transform 0.5s cubic-bezier(0.16, 1, 0.3, 1);
&:hover {
transform: scale(1.02);
}
`;
export function Heading({
as = "h2",
size = "md",
weight = "light",
as = 'h2',
size = 'md',
weight = 'light',
...props
}: HeadingProps) {
return (
<HeadingWrapper>
<BaseHeading
className={problemHeadingClassName}
as={as}
size={size}
weight={weight}
{...props}
/>
</HeadingWrapper>
<BaseHeading
className={problemHeadingClassName}
as={as}
size={size}
weight={weight}
{...props}
/>
);
}
@@ -16,23 +16,6 @@ const StyledContainer = styled(Container)`
padding-right: ${theme.spacing(4)};
padding-top: ${theme.spacing(12)};
/* Smooth transition for the children elements */
& > * {
transition: opacity 0.6s cubic-bezier(0.16, 1, 0.3, 1), transform 0.6s cubic-bezier(0.16, 1, 0.3, 1);
}
/* When hovering one column, aggressively push the other one down and fade it out */
&:has(> div:hover) > div:not(:hover) {
opacity: 0.1;
transform: translateY(24px) scale(0.95);
}
/* Scale up the hovered column slightly */
&:has(> div:hover) > div:hover {
transform: scale(1.02);
z-index: 2;
}
@media (min-width: ${theme.breakpoints.md}px) {
column-gap: ${theme.spacing(4)};
grid-template-columns: 1fr 1fr;
@@ -11,11 +11,6 @@ const HeadingWrap = styled.div`
max-width: 921px;
min-width: 0;
width: 100%;
transition: transform 0.6s cubic-bezier(0.16, 1, 0.3, 1);
&:hover {
transform: translateY(-8px) scale(1.02);
}
`;
type HeadingProps = {
@@ -27,35 +27,6 @@ const StyledContainer = styled(Container)`
text-align: center;
position: relative;
z-index: 10;
transition: transform 0.6s cubic-bezier(0.16, 1, 0.3, 1);
/* Whole container pushes forward on hover */
&:hover {
transform: scale(1.05);
}
/* Smooth transition for the children elements */
& > * {
transition: opacity 0.6s ease, transform 0.6s cubic-bezier(0.16, 1, 0.3, 1);
}
/* When hovering over the heading, push it up and dim the rest */
&:has(h2:hover) > div:not(:first-child) {
opacity: 0.2;
transform: translateY(16px);
}
/* When hovering over the body text, push it left/right and dim the rest */
&:has(div > p:hover) > div:not(:nth-child(2)) {
opacity: 0.2;
transform: scale(0.95);
}
/* When hovering over CTA, push it up hugely and dim text */
&:has(a:hover) > div:not(:last-child) {
opacity: 0.1;
transform: translateY(-24px) scale(0.9);
}
@media (min-width: ${theme.breakpoints.md}px) {
padding-bottom: ${theme.spacing(28)};
@@ -1,28 +0,0 @@
import { theme } from '@/theme';
import { styled } from '@linaria/react';
const Line = styled.div`
background: repeating-linear-gradient(
to bottom,
var(--statement-line) 0,
var(--statement-line) 4px,
transparent 4px,
transparent 8px
);
height: 85%;
max-height: 938px;
pointer-events: none;
position: absolute;
right: ${theme.spacing(6)};
top: 50%;
transform: translateY(-50%);
width: 1px;
@media (max-width: ${theme.breakpoints.md - 1}px) {
display: none;
}
`;
export function Decoration() {
return <Line aria-hidden="true" />;
}
@@ -24,12 +24,6 @@ const HeadingWrapper = styled.div`
max-width: 901px;
min-width: 0;
width: 100%;
transition: letter-spacing 0.8s cubic-bezier(0.16, 1, 0.3, 1), transform 0.8s cubic-bezier(0.16, 1, 0.3, 1);
&:hover {
letter-spacing: -0.01em;
transform: scale(1.02);
}
`;
type StatementHeadingProps = {
@@ -2,7 +2,6 @@ import { Container } from '@/design-system/components';
import { theme } from '@/theme';
import { styled } from '@linaria/react';
import type { CSSProperties, ReactNode } from 'react';
import { Decoration } from '../Decoration/Decoration';
const StyledSection = styled.section`
min-width: 0;
@@ -22,17 +21,6 @@ const StyledContainer = styled(Container)`
padding-top: ${theme.spacing(28)};
position: relative;
/* Smooth transition for the children elements */
& > * {
transition: opacity 0.8s cubic-bezier(0.16, 1, 0.3, 1), transform 0.8s cubic-bezier(0.16, 1, 0.3, 1);
}
/* When hovering over the heading, massively spin the decoration and push it up */
&:has(div:hover) > div:not(:hover) {
opacity: 0.1;
transform: scale(1.5) rotate(90deg) translateY(-20px);
}
@media (min-width: ${theme.breakpoints.md}px) {
padding-left: ${theme.spacing(10)};
padding-right: ${theme.spacing(10)};
@@ -54,10 +42,7 @@ export function Root({ backgroundColor, children, color }: RootProps) {
return (
<StyledSection style={{ ...cssVariables, backgroundColor, color }}>
<StyledContainer>
<Decoration />
{children}
</StyledContainer>
<StyledContainer>{children}</StyledContainer>
</StyledSection>
);
}
@@ -8,21 +8,6 @@ const StyledHeading = styled(BaseHeading)`
position: relative;
display: inline-block;
&::after {
content: '';
position: absolute;
width: 0;
height: 1px;
bottom: -4px;
left: 0;
background-color: currentColor;
transition: width 0.6s cubic-bezier(0.16, 1, 0.3, 1);
}
&:hover::after {
width: 100%;
}
@media (min-width: ${theme.breakpoints.md}px) {
max-width: 672px;
}
@@ -15,12 +15,6 @@ const FeatureCardContainer = styled.div`
overflow: hidden;
min-width: 0;
height: 100%;
transition: transform 0.4s cubic-bezier(0.16, 1, 0.3, 1), box-shadow 0.4s cubic-bezier(0.16, 1, 0.3, 1);
&:hover {
transform: translateY(-4px);
box-shadow: 0 12px 32px rgba(0, 0, 0, 0.08);
}
`;
const CardImage = styled.div`
@@ -29,14 +23,6 @@ const CardImage = styled.div`
background-color: ${theme.colors.primary.border[10]};
position: relative;
overflow: hidden;
img {
transition: transform 0.6s cubic-bezier(0.16, 1, 0.3, 1);
}
${FeatureCardContainer}:hover img {
transform: scale(1.05);
}
`;
const CardContent = styled.div`
@@ -60,20 +46,6 @@ const CardIcon = styled.div`
height: 22px;
`;
const HeadingWrap = styled.div`
min-width: 0;
span {
transition: opacity 0.4s ease;
}
h1:has(span:hover) span:not(:hover),
h2:has(span:hover) span:not(:hover),
h3:has(span:hover) span:not(:hover) {
opacity: 0.2;
}
`;
type FeatureCardProps = { featureCard: ThreeCardsFeatureCardType };
export function FeatureCard({ featureCard }: FeatureCardProps) {
@@ -95,14 +67,12 @@ export function FeatureCard({ featureCard }: FeatureCardProps) {
fillColor={theme.colors.highlight[100]}
/>
</CardIcon>
<HeadingWrap>
<Heading
as="h3"
segments={featureCard.heading}
size="xs"
weight="medium"
/>
</HeadingWrap>
<Heading
as="h3"
segments={featureCard.heading}
size="xs"
weight="medium"
/>
</CardTitleRow>
<Body body={featureCard.body} size="sm" weight="regular" />
</CardContent>
@@ -1,4 +1,9 @@
import { Body, Heading, IconButton, LazyEmbed } from '@/design-system/components';
import {
Body,
Heading,
IconButton,
LazyEmbed,
} from '@/design-system/components';
import { ArrowRightIcon } from '@/icons';
import type { ThreeCardsIllustrationCardType } from '@/sections/ThreeCards/types';
import { theme } from '@/theme';
@@ -19,22 +24,6 @@ const IllustrationCardContainer = styled.div`
min-width: 0;
min-height: 0;
height: 100%;
transition: transform 0.4s cubic-bezier(0.16, 1, 0.3, 1), box-shadow 0.4s cubic-bezier(0.16, 1, 0.3, 1);
span {
transition: opacity 0.4s ease;
}
h1:has(span:hover) span:not(:hover),
h2:has(span:hover) span:not(:hover),
h3:has(span:hover) span:not(:hover) {
opacity: 0.2;
}
&:hover {
transform: translateY(-4px) scale(1.02);
box-shadow: 0 12px 32px rgba(0, 0, 0, 0.08);
}
`;
const CardRule = styled.div`
@@ -9,13 +9,6 @@ const StyledLogo = styled.div`
flex-shrink: 0;
position: relative;
width: 64px;
transition:
transform 0.4s cubic-bezier(0.16, 1, 0.3, 1),
filter 0.4s ease;
&:hover {
transform: scale(1.05) translateY(-2px);
}
@media (min-width: ${theme.breakpoints.md}px) {
height: 40px;