From c23961fa817598b0b676b9df7d4bf9fa3efb21d4 Mon Sep 17 00:00:00 2001 From: Abdul Rahman <81605929+abdulrahmancodes@users.noreply.github.com> Date: Tue, 31 Mar 2026 22:21:01 +0530 Subject: [PATCH 01/20] Fix navbar object color not updating immediately when changed in edit mode (#19075) https://github.com/user-attachments/assets/f2a8f2af-b92f-4d2e-9570-fe66f0a3eca0 --- .../utils/isValidObjectNavigationMenuItem.ts | 19 +++++++++++++++++++ .../hooks/useSaveNavigationMenuItemsDraft.ts | 5 +---- .../components/SidePanelEditColorOption.tsx | 19 ++++++++++++++++++- .../SidePanelEditObjectViewBase.tsx | 8 ++++---- .../utils/getObjectMetadataColorUpdates.ts | 16 ++++------------ 5 files changed, 46 insertions(+), 21 deletions(-) create mode 100644 packages/twenty-front/src/modules/navigation-menu-item/common/utils/isValidObjectNavigationMenuItem.ts diff --git a/packages/twenty-front/src/modules/navigation-menu-item/common/utils/isValidObjectNavigationMenuItem.ts b/packages/twenty-front/src/modules/navigation-menu-item/common/utils/isValidObjectNavigationMenuItem.ts new file mode 100644 index 00000000000..a7ae4775851 --- /dev/null +++ b/packages/twenty-front/src/modules/navigation-menu-item/common/utils/isValidObjectNavigationMenuItem.ts @@ -0,0 +1,19 @@ +import { isNonEmptyString } from '@sniptt/guards'; +import { type NavigationMenuItem } from '~/generated-metadata/graphql'; + +import { isNavigationMenuItemObject } from '@/navigation-menu-item/common/utils/isNavigationMenuItemObject'; +import { isDefined } from 'twenty-shared/utils'; + +type ObjectNavigationMenuItem = Omit< + NavigationMenuItem, + 'targetObjectMetadataId' +> & { + targetObjectMetadataId: string; +}; + +export const isValidObjectNavigationMenuItem = ( + item?: NavigationMenuItem, +): item is ObjectNavigationMenuItem => + isDefined(item) && + isNavigationMenuItemObject(item) && + isNonEmptyString(item.targetObjectMetadataId); diff --git a/packages/twenty-front/src/modules/navigation-menu-item/edit/hooks/useSaveNavigationMenuItemsDraft.ts b/packages/twenty-front/src/modules/navigation-menu-item/edit/hooks/useSaveNavigationMenuItemsDraft.ts index d272218a955..e0c60c73576 100644 --- a/packages/twenty-front/src/modules/navigation-menu-item/edit/hooks/useSaveNavigationMenuItemsDraft.ts +++ b/packages/twenty-front/src/modules/navigation-menu-item/edit/hooks/useSaveNavigationMenuItemsDraft.ts @@ -10,7 +10,6 @@ import { filterWorkspaceNavigationMenuItems } from '@/navigation-menu-item/commo import { buildUpdateInputsFromDraft } from '@/navigation-menu-item/edit/utils/buildUpdateInputsFromDraft'; import { getObjectMetadataColorUpdates } from '@/navigation-menu-item/edit/utils/getObjectMetadataColorUpdates'; import { useUpdateOneObjectMetadataItem } from '@/object-metadata/hooks/useUpdateOneObjectMetadataItem'; -import { objectMetadataItemsSelector } from '@/object-metadata/states/objectMetadataItemsSelector'; import { useStore } from 'jotai'; export const useSaveNavigationMenuItemsDraft = () => { @@ -29,11 +28,9 @@ export const useSaveNavigationMenuItemsDraft = () => { return; } - const objectMetadataItems = store.get(objectMetadataItemsSelector.atom); - const colorUpdates = getObjectMetadataColorUpdates({ draft, - objectMetadataItems, + currentItems, }); for (const { idToUpdate, color } of colorUpdates) { diff --git a/packages/twenty-front/src/modules/navigation-menu-item/edit/side-panel/components/SidePanelEditColorOption.tsx b/packages/twenty-front/src/modules/navigation-menu-item/edit/side-panel/components/SidePanelEditColorOption.tsx index f659af88b3b..2389abdecde 100644 --- a/packages/twenty-front/src/modules/navigation-menu-item/edit/side-panel/components/SidePanelEditColorOption.tsx +++ b/packages/twenty-front/src/modules/navigation-menu-item/edit/side-panel/components/SidePanelEditColorOption.tsx @@ -1,4 +1,8 @@ import { CommandMenuItemDropdown } from '@/command-menu/components/CommandMenuItemDropdown'; +import { useUpdateMetadataStoreDraft } from '@/metadata-store/hooks/useUpdateMetadataStoreDraft'; +import { type FlatObjectMetadataItem } from '@/metadata-store/types/FlatObjectMetadataItem'; +import { isValidObjectNavigationMenuItem } from '@/navigation-menu-item/common/utils/isValidObjectNavigationMenuItem'; +import { useSelectedNavigationMenuItemEditItem } from '@/navigation-menu-item/edit/hooks/useSelectedNavigationMenuItemEditItem'; import { useUpdateNavigationMenuItemInDraft } from '@/navigation-menu-item/edit/hooks/useUpdateNavigationMenuItemInDraft'; import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent'; import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer'; @@ -15,8 +19,8 @@ import { DEFAULT_COLOR_LABELS, MenuItemSelectColor, } from 'twenty-ui/navigation'; -import { themeCssVariables } from 'twenty-ui/theme-constants'; import { type ThemeColor, MAIN_COLOR_NAMES } from 'twenty-ui/theme'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; const NAVIGATION_MENU_ITEM_COLOR_DROPDOWN_ID = 'navigation-menu-item-color'; const StyledMenuStyleText = styled.span` @@ -37,6 +41,8 @@ export const SidePanelEditColorOption = ({ const { updateNavigationMenuItemInDraft } = useUpdateNavigationMenuItemInDraft(); const { closeDropdown } = useCloseDropdown(); + const { updateInDraft, applyChanges } = useUpdateMetadataStoreDraft(); + const { selectedItem } = useSelectedNavigationMenuItemEditItem(); const [searchValue, setSearchValue] = useState(''); const themeColor = color ?? 'gray'; @@ -56,6 +62,17 @@ export const SidePanelEditColorOption = ({ updateNavigationMenuItemInDraft(navigationMenuItemId, { color: selectedColor, }); + + if (isValidObjectNavigationMenuItem(selectedItem)) { + updateInDraft('objectMetadataItems', [ + { + id: selectedItem.targetObjectMetadataId, + color: selectedColor, + } as FlatObjectMetadataItem, + ]); + applyChanges(); + } + closeDropdown(NAVIGATION_MENU_ITEM_COLOR_DROPDOWN_ID); }; diff --git a/packages/twenty-front/src/modules/navigation-menu-item/edit/side-panel/components/SidePanelEditObjectViewBase.tsx b/packages/twenty-front/src/modules/navigation-menu-item/edit/side-panel/components/SidePanelEditObjectViewBase.tsx index 4ce668ce4e5..631a122a102 100644 --- a/packages/twenty-front/src/modules/navigation-menu-item/edit/side-panel/components/SidePanelEditObjectViewBase.tsx +++ b/packages/twenty-front/src/modules/navigation-menu-item/edit/side-panel/components/SidePanelEditObjectViewBase.tsx @@ -1,16 +1,16 @@ import { navigationMenuItemsSelector } from '@/navigation-menu-item/common/states/navigationMenuItemsSelector'; import { getNavigationMenuItemColor } from '@/navigation-menu-item/common/utils/getNavigationMenuItemColor'; -import { getNavigationMenuItemObjectNameSingular } from '@/navigation-menu-item/display/object/utils/getNavigationMenuItemObjectNameSingular'; import { parseThemeColor } from '@/navigation-menu-item/common/utils/parseThemeColor'; -import { objectMetadataItemsSelector } from '@/object-metadata/states/objectMetadataItemsSelector'; -import { SidePanelGroup } from '@/side-panel/components/SidePanelGroup'; -import { SidePanelList } from '@/side-panel/components/SidePanelList'; +import { getNavigationMenuItemObjectNameSingular } from '@/navigation-menu-item/display/object/utils/getNavigationMenuItemObjectNameSingular'; import { SidePanelEditColorOption } from '@/navigation-menu-item/edit/side-panel/components/SidePanelEditColorOption'; import { type OrganizeActionsProps, SidePanelEditOrganizeActions, } from '@/navigation-menu-item/edit/side-panel/components/SidePanelEditOrganizeActions'; import { getOrganizeActionsSelectableItemIds } from '@/navigation-menu-item/edit/side-panel/utils/getOrganizeActionsSelectableItemIds'; +import { objectMetadataItemsSelector } from '@/object-metadata/states/objectMetadataItemsSelector'; +import { SidePanelGroup } from '@/side-panel/components/SidePanelGroup'; +import { SidePanelList } from '@/side-panel/components/SidePanelList'; import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue'; import { viewsSelector } from '@/views/states/selectors/viewsSelector'; import { useLingui } from '@lingui/react/macro'; diff --git a/packages/twenty-front/src/modules/navigation-menu-item/edit/utils/getObjectMetadataColorUpdates.ts b/packages/twenty-front/src/modules/navigation-menu-item/edit/utils/getObjectMetadataColorUpdates.ts index a9ad074b419..c1de85fc386 100644 --- a/packages/twenty-front/src/modules/navigation-menu-item/edit/utils/getObjectMetadataColorUpdates.ts +++ b/packages/twenty-front/src/modules/navigation-menu-item/edit/utils/getObjectMetadataColorUpdates.ts @@ -3,8 +3,6 @@ import { isDefined } from 'twenty-shared/utils'; import { type NavigationMenuItem } from '~/generated-metadata/graphql'; -import { type EnrichedObjectMetadataItem } from '@/object-metadata/types/EnrichedObjectMetadataItem'; - type ObjectMetadataColorUpdate = { idToUpdate: string; color: string; @@ -12,10 +10,10 @@ type ObjectMetadataColorUpdate = { export const getObjectMetadataColorUpdates = ({ draft, - objectMetadataItems, + currentItems, }: { draft: NavigationMenuItem[]; - objectMetadataItems: EnrichedObjectMetadataItem[]; + currentItems: NavigationMenuItem[]; }): ObjectMetadataColorUpdate[] => { const updates: ObjectMetadataColorUpdate[] = []; @@ -30,15 +28,9 @@ export const getObjectMetadataColorUpdates = ({ continue; } - const objectMetadataItem = objectMetadataItems.find( - (item) => item.id === draftItem.targetObjectMetadataId, - ); + const currentItem = currentItems.find((item) => item.id === draftItem.id); - if (!isDefined(objectMetadataItem)) { - continue; - } - - if (objectMetadataItem.color === draftItem.color) { + if (currentItem?.color === draftItem.color) { continue; } From 94e019f012bf1ab63d05cf81987237be489f0dc6 Mon Sep 17 00:00:00 2001 From: "Abdullah." <125115953+mabdullahabaid@users.noreply.github.com> Date: Tue, 31 Mar 2026 22:19:50 +0500 Subject: [PATCH 02/20] Complete the structure for homepage in new website. (#19162) This PR completes the sections we need for the Homepage. Assets, such as images, are still placeholder, and will be replaced as they become available. We're still waiting on Lottie and 3d asset files from the design team. --- .../images/home/testimonials/avatar-one.png | Bin 0 -> 11047 bytes .../images/home/testimonials/avatar-three.png | Bin 0 -> 11047 bytes .../images/home/testimonials/avatar-two.png | Bin 0 -> 11047 bytes .../partner/testimonials/avatar-five.png | Bin 0 -> 11047 bytes .../partner/testimonials/avatar-four.png | Bin 0 -> 11047 bytes .../partner/testimonials/avatar-one.png | Bin 0 -> 11047 bytes .../partner/testimonials/avatar-three.png | Bin 0 -> 11047 bytes .../partner/testimonials/avatar-two.png | Bin 0 -> 11047 bytes .../src/app/(home)/constants/helped.ts | 56 ++++ .../src/app/(home)/constants/home-stepper.ts | 51 +++ .../src/app/(home)/constants/stepper.ts | 101 ------ .../src/app/(home)/constants/testimonials.ts | 58 ++++ .../src/app/(home)/page.tsx | 29 +- .../src/app/partner/constants/testimonials.ts | 58 ++++ .../src/app/partner/page.tsx | 13 + .../src/app/why-twenty/constants/quote.ts | 12 + .../app/why-twenty/constants/statement-one.ts | 8 + .../app/why-twenty/constants/statement-two.ts | 8 + .../src/app/why-twenty/page.tsx | 24 ++ .../src/icons/clients/Beagle.tsx | 30 ++ .../src/icons/clients/Evergreen.tsx | 26 ++ .../src/icons/clients/Realytics.tsx | 26 ++ .../src/icons/clients/index.ts | 21 +- .../src/sections/Helped/HelpedCardShape.tsx | 47 +++ .../sections/Helped/components/Card/Card.tsx | 139 ++++++++ .../sections/Helped/components/Root/Root.tsx | 15 + .../Helped/components/Scene/Scene.tsx | 104 ++++++ .../src/sections/Helped/components/index.ts | 4 + .../HelpedSceneScrollLayoutEffect.tsx | 57 ++++ .../src/sections/Helped/types/HeadingCard.ts | 10 + .../src/sections/Helped/types/HelpedData.ts | 9 + .../src/sections/Helped/types/index.ts | 0 .../Helped/utils/helped-scene-layout.ts | 139 ++++++++ .../components/Content/Content.tsx | 217 ------------- .../HeroStepper/components/Flow/Flow.tsx | 45 --- .../HeroStepper/components/Visual/Visual.tsx | 61 ---- .../sections/HeroStepper/components/index.ts | 11 - .../types/HeroStepperContentProps.ts | 8 - .../HeroStepper/types/HeroStepperData.ts | 5 - .../types/HeroStepperVisualProps.ts | 6 - .../src/sections/HeroStepper/types/index.ts | 4 - .../HomeStepper/components/Flow/Flow.tsx | 36 ++ .../components/LeftColumn/LeftColumn.tsx | 95 ++++++ .../components/ProgressBar/ProgressBar.tsx | 125 +++++++ .../components/RightColumn/RightColumn.tsx | 22 ++ .../components/Root/Root.tsx | 17 +- .../ScrollSection/ScrollSection.tsx | 20 ++ .../StepperVisualFrame/StepperVisualFrame.tsx | 2 +- .../HomeStepper/components/Visual/Visual.tsx | 15 + .../sections/HomeStepper/components/index.ts | 15 + ...bserveActiveStepFromIntersectionEffect.tsx | 55 ++++ .../SyncScrollProgressFromContainerEffect.tsx | 41 +++ .../HomeStepper/types/HomeStepperData.ts | 5 + .../types/HomeStepperStep.ts} | 4 +- .../src/sections/HomeStepper/types/index.ts | 2 + .../Quote/components/Heading/Heading.tsx | 28 ++ .../sections/Quote/components/Root/Root.tsx | 46 +++ .../Quote/components/Visual/Visual.tsx | 56 ++++ .../src/sections/Quote/components/index.ts | 5 + .../src/sections/Quote/types/QuoteData.ts | 7 + .../src/sections/Quote/types/index.ts | 1 + .../components/Decoration/Decoration.tsx | 28 ++ .../Statement/components/Heading/Heading.tsx | 45 +++ .../Statement/components/Root/Root.tsx | 52 +++ .../sections/Statement/components/index.ts | 4 + .../sections/Statement/types/StatementData.ts | 5 + .../src/sections/Statement/types/index.ts | 1 + .../Testimonials/TestimonialsShape.tsx | 46 +++ .../components/Carousel/Carousel.tsx | 307 ++++++++++++++++++ .../Testimonials/components/Embed/Embed.tsx | 56 ++++ .../Testimonials/components/Root/Root.tsx | 47 +++ .../components/Separator/Separator.tsx | 61 ++++ .../sections/Testimonials/components/index.ts | 11 + .../Testimonials/types/TestimonialAuthor.ts | 9 + .../Testimonials/types/TestimonialCard.ts | 7 + .../Testimonials/types/TestimonialsData.ts | 9 + .../src/sections/Testimonials/types/index.ts | 1 + 77 files changed, 2209 insertions(+), 479 deletions(-) create mode 100644 packages/twenty-website-new/public/images/home/testimonials/avatar-one.png create mode 100644 packages/twenty-website-new/public/images/home/testimonials/avatar-three.png create mode 100644 packages/twenty-website-new/public/images/home/testimonials/avatar-two.png create mode 100644 packages/twenty-website-new/public/images/partner/testimonials/avatar-five.png create mode 100644 packages/twenty-website-new/public/images/partner/testimonials/avatar-four.png create mode 100644 packages/twenty-website-new/public/images/partner/testimonials/avatar-one.png create mode 100644 packages/twenty-website-new/public/images/partner/testimonials/avatar-three.png create mode 100644 packages/twenty-website-new/public/images/partner/testimonials/avatar-two.png create mode 100644 packages/twenty-website-new/src/app/(home)/constants/helped.ts create mode 100644 packages/twenty-website-new/src/app/(home)/constants/home-stepper.ts delete mode 100644 packages/twenty-website-new/src/app/(home)/constants/stepper.ts create mode 100644 packages/twenty-website-new/src/app/(home)/constants/testimonials.ts create mode 100644 packages/twenty-website-new/src/app/partner/constants/testimonials.ts create mode 100644 packages/twenty-website-new/src/app/why-twenty/constants/quote.ts create mode 100644 packages/twenty-website-new/src/app/why-twenty/constants/statement-one.ts create mode 100644 packages/twenty-website-new/src/app/why-twenty/constants/statement-two.ts create mode 100644 packages/twenty-website-new/src/icons/clients/Beagle.tsx create mode 100644 packages/twenty-website-new/src/icons/clients/Evergreen.tsx create mode 100644 packages/twenty-website-new/src/icons/clients/Realytics.tsx create mode 100644 packages/twenty-website-new/src/sections/Helped/HelpedCardShape.tsx create mode 100644 packages/twenty-website-new/src/sections/Helped/components/Card/Card.tsx create mode 100644 packages/twenty-website-new/src/sections/Helped/components/Root/Root.tsx create mode 100644 packages/twenty-website-new/src/sections/Helped/components/Scene/Scene.tsx create mode 100644 packages/twenty-website-new/src/sections/Helped/components/index.ts create mode 100644 packages/twenty-website-new/src/sections/Helped/effect-components/HelpedSceneScrollLayoutEffect.tsx create mode 100644 packages/twenty-website-new/src/sections/Helped/types/HeadingCard.ts create mode 100644 packages/twenty-website-new/src/sections/Helped/types/HelpedData.ts create mode 100644 packages/twenty-website-new/src/sections/Helped/types/index.ts create mode 100644 packages/twenty-website-new/src/sections/Helped/utils/helped-scene-layout.ts delete mode 100644 packages/twenty-website-new/src/sections/HeroStepper/components/Content/Content.tsx delete mode 100644 packages/twenty-website-new/src/sections/HeroStepper/components/Flow/Flow.tsx delete mode 100644 packages/twenty-website-new/src/sections/HeroStepper/components/Visual/Visual.tsx delete mode 100644 packages/twenty-website-new/src/sections/HeroStepper/components/index.ts delete mode 100644 packages/twenty-website-new/src/sections/HeroStepper/types/HeroStepperContentProps.ts delete mode 100644 packages/twenty-website-new/src/sections/HeroStepper/types/HeroStepperData.ts delete mode 100644 packages/twenty-website-new/src/sections/HeroStepper/types/HeroStepperVisualProps.ts delete mode 100644 packages/twenty-website-new/src/sections/HeroStepper/types/index.ts create mode 100644 packages/twenty-website-new/src/sections/HomeStepper/components/Flow/Flow.tsx create mode 100644 packages/twenty-website-new/src/sections/HomeStepper/components/LeftColumn/LeftColumn.tsx create mode 100644 packages/twenty-website-new/src/sections/HomeStepper/components/ProgressBar/ProgressBar.tsx create mode 100644 packages/twenty-website-new/src/sections/HomeStepper/components/RightColumn/RightColumn.tsx rename packages/twenty-website-new/src/sections/{HeroStepper => HomeStepper}/components/Root/Root.tsx (71%) create mode 100644 packages/twenty-website-new/src/sections/HomeStepper/components/ScrollSection/ScrollSection.tsx rename packages/twenty-website-new/src/sections/{HeroStepper => HomeStepper}/components/StepperVisualFrame/StepperVisualFrame.tsx (98%) create mode 100644 packages/twenty-website-new/src/sections/HomeStepper/components/Visual/Visual.tsx create mode 100644 packages/twenty-website-new/src/sections/HomeStepper/components/index.ts create mode 100644 packages/twenty-website-new/src/sections/HomeStepper/effect-components/ObserveActiveStepFromIntersectionEffect.tsx create mode 100644 packages/twenty-website-new/src/sections/HomeStepper/effect-components/SyncScrollProgressFromContainerEffect.tsx create mode 100644 packages/twenty-website-new/src/sections/HomeStepper/types/HomeStepperData.ts rename packages/twenty-website-new/src/sections/{HeroStepper/types/HeroStepperStep.ts => HomeStepper/types/HomeStepperStep.ts} (60%) create mode 100644 packages/twenty-website-new/src/sections/HomeStepper/types/index.ts create mode 100644 packages/twenty-website-new/src/sections/Quote/components/Heading/Heading.tsx create mode 100644 packages/twenty-website-new/src/sections/Quote/components/Root/Root.tsx create mode 100644 packages/twenty-website-new/src/sections/Quote/components/Visual/Visual.tsx create mode 100644 packages/twenty-website-new/src/sections/Quote/components/index.ts create mode 100644 packages/twenty-website-new/src/sections/Quote/types/QuoteData.ts create mode 100644 packages/twenty-website-new/src/sections/Quote/types/index.ts create mode 100644 packages/twenty-website-new/src/sections/Statement/components/Decoration/Decoration.tsx create mode 100644 packages/twenty-website-new/src/sections/Statement/components/Heading/Heading.tsx create mode 100644 packages/twenty-website-new/src/sections/Statement/components/Root/Root.tsx create mode 100644 packages/twenty-website-new/src/sections/Statement/components/index.ts create mode 100644 packages/twenty-website-new/src/sections/Statement/types/StatementData.ts create mode 100644 packages/twenty-website-new/src/sections/Statement/types/index.ts create mode 100644 packages/twenty-website-new/src/sections/Testimonials/TestimonialsShape.tsx create mode 100644 packages/twenty-website-new/src/sections/Testimonials/components/Carousel/Carousel.tsx create mode 100644 packages/twenty-website-new/src/sections/Testimonials/components/Embed/Embed.tsx create mode 100644 packages/twenty-website-new/src/sections/Testimonials/components/Root/Root.tsx create mode 100644 packages/twenty-website-new/src/sections/Testimonials/components/Separator/Separator.tsx create mode 100644 packages/twenty-website-new/src/sections/Testimonials/components/index.ts create mode 100644 packages/twenty-website-new/src/sections/Testimonials/types/TestimonialAuthor.ts create mode 100644 packages/twenty-website-new/src/sections/Testimonials/types/TestimonialCard.ts create mode 100644 packages/twenty-website-new/src/sections/Testimonials/types/TestimonialsData.ts create mode 100644 packages/twenty-website-new/src/sections/Testimonials/types/index.ts diff --git a/packages/twenty-website-new/public/images/home/testimonials/avatar-one.png b/packages/twenty-website-new/public/images/home/testimonials/avatar-one.png new file mode 100644 index 0000000000000000000000000000000000000000..a99a99976907e24c960692f643d0b9fc14614597 GIT binary patch literal 11047 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 literal 0 HcmV?d00001 diff --git a/packages/twenty-website-new/public/images/home/testimonials/avatar-three.png b/packages/twenty-website-new/public/images/home/testimonials/avatar-three.png new file mode 100644 index 0000000000000000000000000000000000000000..a99a99976907e24c960692f643d0b9fc14614597 GIT binary patch literal 11047 zcmV+?E7;VDP)>Mp5mHGc1rlfk2`T{&4`aXr9B3pS z2F4hG28#iN-ITzlYdjnT{RcqLm?gj%vv6iS@Ct*6FwlTVqyda75+nwxpgO;+{@woN zSF!fl=iHl+4H?q8cRymqiWMtXM66hA?|uE+zrhnvJn{JJUiZ3xeC)Bu-hXy>_WoP9 zZe7do&Ye5g?%ut7j`N`pedzr7M?d<}`T5)4_O|=(^Z)kk+vnHwKRDm{&UY@(13891 zWpZp99H&hF=Lb#$_u!W@fN66NJj$%_nzs2ip36_|b6p(!USyi{cfb4H7qnmb%2!@{ z@x>P}@FL6L1?TN=fBQuphX8t808a<#egEF?pRZrP{y(^ImOuBHeBx7|`qcma^{;>Z zgbB2OP@I*3EmZI(1?z@cn7%ia;o3^!`hU~@-S2*P-~Hx+c1=n{ovwSOT=~yHqRhmf z|9iliFKF{W{Sf84N`N+sw1EG7@AogyJ@?!{J^uLP|8P%{es(=q-}uHi{@;85p1Af1 z9(q7YV}Q+xiDL^Zp_MBO>S#d zk4JO!!}%ND@P_-`$I8_i50?Y&bTTq&_icW0^R{4?7j+Ucq@Eo6{;AM%IYuG>{O3Ra z_p^J<{3C>{IB7Tx(^!NN`0a0hdr{ddUh#_ad-+XFOs-_laW}B>+TCu|(@Hae6*uj3 zENA!S>uEdnaNP0Fsx2twikEhKR;sH|9@k^J96|ei*WdAucf2??))j1ZaO1j+gUY`b za7V0^XqrImk-y~{>vmO21Q3`XL-&lCl7rnqj&q%3M(^Flj00%%oa4B?Lo=^KF6{0Q ztWWO9d`!H0Hnf^BY|(Ca*>2E*^E88O+Ah=eSpJih$oXZ1=~!A^@!t5ya0Y_`TaYv; zKa>lmx$dbaBLZO=TDhoiVzg%^6LcM`5x$CtOk>N{Oo|G$91N{oRxDrdK{nOXG&uh7 zhd+GKQkd4%FAb+!v+M7D?|WbD=_Zx7l|iv41+aPbh+^8gQkt%7>v*bbtIQtSTh=as zg+{=s9SfWK11xwcO5bx2+Fx*Hu8Q&|Ba7)^k_37tU}`)2QC+K;w3> zcgT{g=yv^w?l)d5=$6tNXJw6S(%k$&-u zUu-HjuBst>D{aby{I{p(+Ufgc)^ z%exGmLhsBLgP5oNC&b&@_&7?^_n`?c^tvSz+8CYD9V-oMhS@p$~uw2DF4aWrAR@|*XAK9L* z3V4diIUUeuwi{15TQMu7%eJLkxwy%#O;+wuJ@Ce?>#E@xR~J{70XYT34w$V_xt@6K zn3>XL`ED@3=L$q%7jPoW7Knm?r({TJyOY4y z2;Jk-Oy3X!p^9RF8~+O{(!)0Da8) z6mxYQ6SS3^?i+794v>W7__BaSo7_x8Iz4s9`eoU`d<9x|lLCWtmCG1i_g=VIjra62 z;P`_^7%xJ|XmV@=ZZE)^9@A92#%{!x1v;ceK=b2Fd$Q(#DcEuipZ)A-&)reh&y3$Y z7l?DBFevJtrIoAVa|_PwU+><%e*v%+3S7rI4vgt6gYh}%zZIotamMNE98Ye~O6IAt z+nK5KG_qGh+~dZ!pk-_sOw;xrAQ`BEC=e5pzh)-dJfCNxyYt%mOhK#fO>VF0JxuVG zuYBb`rFalI73lT=YDf^B1mhInwQFmudh6EVOmvn|_Q0tz(1i=@SqcneQdgrKchqr4 z2bPYnCSl%w&*6iy+WOono>b+D`N`d3>o^`OqPJ6A-soC|t zaAtGW=AZuvKg=gnopV1P!)mb=&n}RqjLAGtz)}ijEQB6$J;m)AmlZoWi8-8WYBO^9I_8vp~j6Faw+B2q(j}GCn znooxkCmn)zZGCPb-aRl|Yq!V!xUY=ds|MF~iWPGbc9JVIuFS$5F8n3qwH1ty^>imq zqhr;XfUUx`Jz=8favUFOaF^*e*fM$jYoe8(XDtp?AB1}gf60b_;~U?&PbNK^?TLZo z%d4EqpEL_ILsRFqJMi%o&^F%6dQG%eia@z7g)#j}(EQl0Vqi%DmkeMP*eASlX((uB zj<}fB9%KU(k=wU#kIO}?cKZ6>Y5F0EB8G>^=crBfOygP9V>%t^jXQQtY zPKm4Ti-9ILaqHGgSJMyS_3>Y88jmGP;M{wi4e7*mJeJq1+&o=^3uE830ZZa`ng(vL z2T`8d;H3&%gJ)_N*6^w<5DUzEmNE=yFybw&?sQMr+3U>A&F;w72|y6Ilb)5CcJpBC z1g*&$we@ow$ocfH!v^XLUw*zSi=6pyw+4O#Wq1=wfPKrjo2g!MQ~g*K?TA%`C&yqN z;2%=DJurERLvZHou`LZ#^6nriawfVJiJ4cx52{fHdLFU4M;#HG8`X_GbPv7~*RgET zR&d(4V-rq$5_fdm1~~90Xhzx0OMc;{Er#72|2vlzx8(;NVkz@;Cc3llr-Bu6FFcUP zdL9-)A+njBjqCwW<#Rus9|gt@SuxV-8SN>LGEzSHQ4H@Y%rQ#l!5L^v7HdWMy+HYC zPxNJhCsU4kE-cT+xBCbyC2_cS4BtpxRZ}77uMi=+4qABvrC+&~FVl*m#d6?oCKr)*@;p5_tH}jRFssGXl?&>&O|VK)9D?&aP`eo~WTS8rpZg)l>2R{DskKcEl!IIJ4aSHLI z<>h0Zy`xO-MK-I&)IEx_f|kh?hfdf3rd?QE4%z3pAcTENhPk(=1mgN^DQ%JHTm}O< z9LGK3Daw%9*dCY`Qw^tB5G(a5xur8+)@TdkQA#C@fZiL_cs+}Qw(-1&$TJq>O|OJG z76Jg}MB(0-JUmOxF)V4^-!YkTLuL zSh0t8F_pprcL3L?_QED7Isfw zOtnvEnmAP$JilOSGIt#-1^kGQN9?4GO=m0S=}|f<7q3(yBaK_WiYHP-e~+NI7FhFi zNO&g`-PWz$7~6?Mho@7IwHQ|o7cbfD>1d!kY_bZImGMHK&GzIbCj~N0iqi4ZR@u}~ zqK_9dc}BI`-hpMp0&VTP=>^qkyDT`+&U8QjTGg zUEQ0OK!7cJlW>4TX7*IDU~Gw6SS*SLxDW3r6fu+sNCRziXh7SdFtIjKpsmH!)u6JK zdZ-pt8LggP+Z{PW%ysZQ^@rZHI7{O@2C_o-F*uzrK$uf`*W=DSv?m&z)jfA!yC(DA z?!8?%sRdl1(*is^Xj-Oi8dDf?890UB*og3FrJO1auqVUdHEOt&Wj{)QLht}K?9WNN{w#=JdF01R)sAU$)Qzcu0b6mNt z1?z6mF-?H&tIj4*^0EtK{fl6pL?WGhSvO`G+4b**GY;A{Awc%S=J=@6Wv zj2E*opani1ADTsN`O+G1s4TALm+hIMh9NSEM zHnhb>_Tl|1Uod4Wy%)}`#U1JMzb%T*UC%I9mdDC9Ef(6nwcBgUXkLwH^LzXD`eP<` zzqm|ByYoWH*{q=Dwxxhf3e1ybWo4QMpZjI1-_OurCJ%Iy3&SnO<6XI}X~aUWM~Z2zTrIr&Eom9G>BKhOWR1HX5|IS9 z1_l@#?AeVFI{w{{3|6Ac`ShYVAPokDN2 zhA!W5$cniG+A=vqJ?-Nmb8NTEOl}3~lqesY*c|_~e5l*A$3t?#4Yx(UtP3;E$=Xk@ z`V67=l$sIhhW9y(fX-HfM~89j1RM3Fyk{kM78|KLUf7CrT&8n6xUeiE|TtpdG_7Y{jEoHfVh>kmFMH>WZbtqi}ta1+in>}BuM57 z7`r;!u?P0zt-Qw;oY@UP#8YOw9^-lH36q>N-JC|xY9v^|Y@FH?h(psnb_@hg-pia% zJ9W8qN-R=-DHCgv!Gc1eKrE_u8+fjZy7-6-Jn(5s%CS@uVBonte5Y<+8N&vCEa9XS zE9E|<3|(%o!UgVo&F`UEl&wVL^{k=;KQp_c*SJ>=30!$YnT5(zsZ5WL<-v*@#lr$) zeNtD`b!<7+Hw{{!lTE+Mx7DAtm}IL<2kUyEnJfzdJ5a-dJ2dG)555g zeNz0%h1qSA6?UB97kN8|alJhY>UzQHH=yH(fbIo9!vEI;-`Z_TbUt;enK(cDP}mJzRy=`;Xa zHeALsnqoQHdU**?&0+;%3{FeEr z0i922_vCVYJY6%rK5l5sWZ`xllj3o`6(ut!FQx{(e9}bF?_A|MNe@`%gA`CpNzL-#)(&CNp`>EPRfIan@!Ah=mlDP;S?8m)+2!w z`fAiUz+Sm0TY{A}XmA-@qp1!D{GIKFMq4PC`QjJ9c>dICgum+iEtnQp`yLhu_vjsj z%_}q<`?yWr4wp@w#+n-j;8Z|KALw`EEr30y&i?&j0+M`Q3v1X~$=-4uQJSp8PYUs% z0Bh=O`mxG%^4EH(FyJ5-ZS1E}Jq`5}m5jCosa`O(JDP%WTPaL8BhDFS8tHqu+nz~6 z8`lhNGUMTiV6;cIX`BM#$sdwq2FN2j&8w}c@ut1u{O{0!_9bYaEbCr4){Wh~$M92h z*l&LGn`=+01~*yf(0%P|Uwgq{EBXYTKZD;dfBDPj zG@pI;*$aB$gVVgiABtgKb8NiG9J(IVE)&Jd@=OMP_{g=i?+}=ey>QTlwF_E}))lxT zeePr5KSb|AfK4}3{9}N%wD7*?yC8euD&>Kt?eq%tQQWPEE?02h2j@IP;Jn{gXgAi1 z)eECA-zM0!J)<%n?q@XIS-RaO;1oWSZ0u#LB+RFm5~25)N9AvZc5Z{2G=!*p-5xE${-Gg&kL zZ#=e+kTC2$PQjfX*WQ8~?Or(Uk?KzCn5N5jgQt;iXknS=mc^Pz|JEq#0Ycdp`Uf09$T)qBrD6(F53&XEwe4_**rEN-uIxt-YvX#Go4|^By()nW_sv36p6#tkH+-5n@vx8oT zv2yj)+Q9^`krb}v#UHt^!d+!e%UGRY-F`++lqJB-)nJ> z2e(|IZ8J1N}CPSU2Zv z01q^_(p-fcx?lQUa#hI>9p%E@U^m2OxYvCeH_&)ya@85_77*Sv_3wJy3?Hhe`EMn0 zn^)%(xZbHf4#@3pa-3xY6014qr3&uAmgP#`zP{ppWqHl7Y3zaf_CyE#se`V_9otVy z+N7^Kvl+G@haSgtM0b#rmrne(a7-IOIn9gtoI1tz_P%P5=E=GR_}EKkJb96W<>5Fb zTSD9>^JMvVd)vJ>ZMU`ikA8NRo2PR3!kJ@`wmJ~CkYLnnDZXw&wux^V&bRPnD6~C# zOuNgkEQD!y9%^Nc+UiX_G;CR|{Lfc{COp$Me#fNd)otor)x>98*_NO2E&ILG_`ty! zs1@Q^zuUs?hIM^izDM;`&tx%HJp8qw`SbBHZR(jM_osTge$#FX3gmjG^x5_?S=5I6 zK6PMo-Fuw_$7DRQYR=BOObf3w!Yje;&A=M3zjto|uPmemj9{nC_S6xUBi7<7+T@?h zz&rfpxZjxHGVTk2BdUW%ul*x=6R`s^PjpzF42*CBOcwMbYPO!4jlN_6Obd~W4vkNFuCWcX1?Ov%+v>Ku%p`}&1vl+>uY23Hw>-s79$w>NzCbJn5Apf>3eOJ-<`|3B56*!HY=r9{@BzuGf6Kebh7I znIH3wFmv8nTjMo<0m_)yEgl+=bIZYH{Jg-_wzo^cQf0!Zy=h zP_yvxkNItVud20mGMT1rSdFTQ?#i7QuLZ>>sx8_R@9f^2M&hbXExWC@!7K9R6?Vj^ z6VK4@uwvDwExuQ6Nd3IgmRQigv-a-+KMUVE0S9jFe)_nXn%qLW0pqu8TM53Q{k;X^ z40CnvmB z478#LPM~Lk$MA4$oU?~s&p@~69mDG(youK-6K#2~=&yL)%XhNV89*ISpT|ICKjQ;) z{LXj2^Wykc#WQ)i0r3iWoHrws3D61sQh)$7;N6W={v^8xAo?{cg0K)N$6^H={Z7WH??7=eQ zzU2z9c{xM++b=lJ?}oLr^Al#m8atUwGXz)(f;;VDhK8R8I~=rx%%MXI8N?olT7e@kh^c&wG%a#6tW1lBE7F`s9Z@4ss@&K(6;_JG;Be+P3d^ z89%k^wLb6ynT7Ehm(|-a+Jg7u<%$OuMh~^gF_3xVgLahfSgGUDfcwRD2FSEGKmN!d zZM*@&Hgz^>2!Y*mzTW2Cv~u5DHeq-Q+yFD@KyGpuuI~`73D+h*Kff}!X`(z<#))pb zzAb)D>kyw!+wP3FwHkL-A2{xp$<<9Xg6Ge3~3dtSDEO&^q9SX2eZ(C z;Z+9Kv#71?ZsWP0#-mQ~oE@f|XN4(fjKekON1@#%BR z>=a&2e=2t>v$ZD+sf7(M{US_c5?ZDQ57a|B7zisFdZM?Pss}bmWR_&Yk zab3*|U~9XleNChJo_O7AQL{(%>NrUi-%lOPg6T%+{C92n;5>e z;nF5yG(UUY!V0hHwrg_Top5uTe7;Ecz4qo2+mhH z$?!jZXY2snBL=)d`o8{(uy-&+BY-Q{F=G%C9s`JHEK26Y5 zN2Yo`b!2Lr%w+C)TALqlwD)2v*8!VXrt}V8Vcx+WJWMG8o7~ZyMK(+{r`Kk&VWS5N7!09$Rf0;Rm)(r?+iU%Gvs(zo>lFAJ-AcI;vnX2DGzgL`ww zqOs1~SP3ZOhIZPXSNAhpvz7x0jWQia<=A}t*k$3{uk<%ww~um^p&gWQ0PA|;pFv^8 zbw_k3O}tvc8O$C~`S0BZRv@l1Na4eLTaJ`P4t!n$I-bqO;G`cPEv7z#OTqce6|zx? zSDksmv%kfj^fh0g@#i9K6%0A|H`1qXyHlp$ap-{0ulY6fLT!K92A(D!njiD9q74tc z2;xxt`~r&0@@kn*vU3@}A7?Xe*d7+E@+a`?c3|eZ6+n0pa-JMcOUth%LD#GK*z09|GD0-i!z(vjdy2tBk4dt z1K+N$EklopmB8AX(C7)TJ7^l==7)QGET_R`{ARRni?409^$^}9uj#mznX;3M?Y=lv zPk!E=*mBM9A`|UZcCRQqN94?F3X@fJRvGYhpF5K~!L%AY(IYPcKk&Vki8d|s;6z*3 z175eyIVRIHp3f&djwd|xX1u9i;L}#R^Ffy3s$ZJ#-l1SQf`7iD%#Y{z$xSv7(J=6G z+{rbPPq`L6Iy1O*HW_EM-buH~@4AD~c$e`;FDD3j^r-nxxmXYQ?&KqQfzSZ2H@>wT z=oHG3fSWelr3`pj@kz!jUbp(i{WmEQS^QN7oqqA7McFt8z_*j8H_%uJ^w)Z<-E>@U z(l&m_FKuF1CcWLphu(=#pF>bRrtxf44MndI&MbBx*Y zm|$|B{3pHAvIFN)Ci)Rv3hsNsR8OG;evHPCsdOgOfn^>HBxBiGQZl{P;{4yrM1$Yu zJgRzHN`P-Xx6i?&*XF3VAA1QNPb6gVxj+0nO}o2&tBiGj8e*d7HhE%TnRxY}tzKKY z6+hk2{k{8c-;K!(``j^#@B0xL3oGDkHVQ+Tp88MqwmaJklY5!mTH_jT%0wG~axE(! z{1~w1Wtjw@y;T1BKApL8HEx45$Kcr2P5tc*^X*zunEKg@_Q-{u09Tcf|671Fk0@*B zDhnK#@cMI+4(@D*+XaDVS70;l0Gu+=cd**QI_BOp440YQ!iqNM?Q$BAHkjUo*D?VP z;aSG;?RqUI?{)-C@6=4RX$J2`cVtKV9m#j&%$UvK%3Tbka8#ex4w@@@H@VGhy8DO1Z-l<8}J zex-hAD4Fsa&skv@@XM^ojFL_5Z@_mP0d2}R^h=;7UQG+Wp|>^7b>^5htu~(ZG=9qV zyM5-P(Dt*F8OanP)RzL$hOYyVX-bL5D7-_JlkS`zJdE=Q6g6r88 zGaAl4oA9i{!s=a!(CD;1ZSw4h*(m0l&0J0~AO}(t7QA_I8vs%phMu~kP|rU5?D@H$ z1n$R|JzMlltY^c>wx6iwX<-!HPZ=Ylf0NJmDJKZ<8lsg{Cu#aS_wA+TK&^Yi7(zMq8aeZVMFPJ|oQMSPYLsXc!+l-9D~Qcvy*k zZl2?b9&I%bod@EWGRUlXpd&4hmN8)2A&1`L+Wj^4pF;s;8F=A^7k>7WpZw(0H=lq0 z`Tu_p`G39o)vx|9fB3^69!DtN^NW&To^vl>l0i`5xl+5Meqp8s4?P;|hPC1Wt_wx! z7fo8R?B05S&^~95or$(WS@Eeqcy^mkfI7>ay~UQtG)QwyCfZqZ1_g3~?@0k$j_uz3 z77hU|$ z*~?z`pB%sVNdOD0t%75R9);jIK3c^Hj$y214Suu67C(+v%mddQ8+0bx%IEgE9LLb^ z__3AU^5I^;Khbfa+hqAqPiP<$Vpg{urHPV8NeHyTr;Qw=xbXI?U;XO;{NM*a_@DRg hefsIApZ#P5CxPWVcBudW002ovPDHLkV1inah?oEX literal 0 HcmV?d00001 diff --git a/packages/twenty-website-new/public/images/home/testimonials/avatar-two.png b/packages/twenty-website-new/public/images/home/testimonials/avatar-two.png new file mode 100644 index 0000000000000000000000000000000000000000..a99a99976907e24c960692f643d0b9fc14614597 GIT binary patch literal 11047 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 literal 0 HcmV?d00001 diff --git a/packages/twenty-website-new/public/images/partner/testimonials/avatar-five.png b/packages/twenty-website-new/public/images/partner/testimonials/avatar-five.png new file mode 100644 index 0000000000000000000000000000000000000000..a99a99976907e24c960692f643d0b9fc14614597 GIT binary patch literal 11047 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 literal 0 HcmV?d00001 diff --git a/packages/twenty-website-new/public/images/partner/testimonials/avatar-four.png b/packages/twenty-website-new/public/images/partner/testimonials/avatar-four.png new file mode 100644 index 0000000000000000000000000000000000000000..a99a99976907e24c960692f643d0b9fc14614597 GIT binary patch literal 11047 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 literal 0 HcmV?d00001 diff --git a/packages/twenty-website-new/public/images/partner/testimonials/avatar-one.png b/packages/twenty-website-new/public/images/partner/testimonials/avatar-one.png new file mode 100644 index 0000000000000000000000000000000000000000..a99a99976907e24c960692f643d0b9fc14614597 GIT binary patch literal 11047 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 literal 0 HcmV?d00001 diff --git a/packages/twenty-website-new/public/images/partner/testimonials/avatar-three.png b/packages/twenty-website-new/public/images/partner/testimonials/avatar-three.png new file mode 100644 index 0000000000000000000000000000000000000000..a99a99976907e24c960692f643d0b9fc14614597 GIT binary patch literal 11047 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 literal 0 HcmV?d00001 diff --git a/packages/twenty-website-new/public/images/partner/testimonials/avatar-two.png b/packages/twenty-website-new/public/images/partner/testimonials/avatar-two.png new file mode 100644 index 0000000000000000000000000000000000000000..a99a99976907e24c960692f643d0b9fc14614597 GIT binary patch literal 11047 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 literal 0 HcmV?d00001 diff --git a/packages/twenty-website-new/src/app/(home)/constants/helped.ts b/packages/twenty-website-new/src/app/(home)/constants/helped.ts new file mode 100644 index 00000000000..43757b07376 --- /dev/null +++ b/packages/twenty-website-new/src/app/(home)/constants/helped.ts @@ -0,0 +1,56 @@ +import type { HelpedDataType } from '@/sections/Helped/types/HelpedData'; + +export const HELPED_DATA: HelpedDataType = { + eyebrow: { + heading: { + text: 'Twenty helped them', + fontFamily: 'sans', + }, + }, + heading: [ + { + text: 'Make your GTM team happy with a', + fontFamily: 'serif', + }, + { + text: " CRM they'll love", + fontFamily: 'sans', + }, + ], + cards: [ + { + icon: 'realytics', + heading: { text: 'Increase lead qualification', fontFamily: 'sans' }, + body: { + text: 'Realytics built lead scoring into their CRM and increased qualified outbound by 40%.', + }, + illustration: { + src: 'https://app.endlesstools.io/embed/54cb2a73-baef-4eff-9957-17d262b5bbaf', + title: '', + }, + }, + { + icon: 'beagle', + heading: { text: 'Build performing onboarding', fontFamily: 'sans' }, + body: { + text: 'Beagle launched a custom onboarding pipeline and shortened their sales cycle by 30%.', + }, + illustration: { + src: 'https://app.endlesstools.io/embed/0988b17d-7648-4b95-bd6b-8fab1e798da9', + title: '', + }, + }, + + { + icon: 'evergreen', + heading: { text: 'Unify workflow', fontFamily: 'sans' }, + body: { + text: 'Evergreen unified sales and CS workflows, boosting expansion revenue by 25%.', + }, + illustration: { + src: 'https://app.endlesstools.io/embed/18fc3259-eb0d-4254-961c-0fc26aa7b205', + title: '', + }, + }, + ], +}; diff --git a/packages/twenty-website-new/src/app/(home)/constants/home-stepper.ts b/packages/twenty-website-new/src/app/(home)/constants/home-stepper.ts new file mode 100644 index 00000000000..21991c9d05f --- /dev/null +++ b/packages/twenty-website-new/src/app/(home)/constants/home-stepper.ts @@ -0,0 +1,51 @@ +import type { HomeStepperDataType } from '@/sections/HomeStepper/types'; + +export const HOME_STEPPER_DATA: HomeStepperDataType = { + steps: [ + { + heading: [ + { + text: 'Begin with production-grade', + fontFamily: 'serif', + }, + { + text: ' building blocks', + fontFamily: 'sans', + }, + ], + body: { + text: 'Compose your CRM and internal apps with a single extensibility toolkit. Data model, layout, and automation.', + }, + }, + { + heading: [ + { + text: 'Continue iteration', + fontFamily: 'serif', + }, + { + text: ' without friction', + fontFamily: 'sans', + }, + ], + body: { + text: 'Enjoy unlimited customization using the AI coding tools you already love. Adapt your CRM to fit the way your business grows and wins.', + }, + }, + { + heading: [ + { + text: 'Stay in control with our', + fontFamily: 'serif', + }, + { + text: ' open-source software', + fontFamily: 'sans', + }, + ], + body: { + text: "Don't get locked into someone else's ecosystem. Twenty's developer experience looks like normal software, with local setup, real data, live testing, and no proprietary tooling.", + }, + }, + ], +}; diff --git a/packages/twenty-website-new/src/app/(home)/constants/stepper.ts b/packages/twenty-website-new/src/app/(home)/constants/stepper.ts deleted file mode 100644 index fa8710cf613..00000000000 --- a/packages/twenty-website-new/src/app/(home)/constants/stepper.ts +++ /dev/null @@ -1,101 +0,0 @@ -import type { HeroStepperDataType } from '@/sections/HeroStepper/types'; - -export const STEPPER_DATA: HeroStepperDataType = { - steps: [ - { - heading: [ - { - text: 'Begin with production-grade', - fontFamily: 'serif', - }, - { - text: ' building blocks', - fontFamily: 'sans', - }, - ], - body: { - text: 'Compose your CRM and internal apps with a single extensibility toolkit. Data model, layout, and automation.', - }, - images: [ - { - src: '/images/home/stepper/step-one-one.png', - alt: 'Twenty modules for logic, data model, and layout', - }, - { - src: '/images/home/stepper/step-one-two.png', - alt: 'Twenty data model and layout building blocks', - }, - { - src: '/images/home/stepper/step-one-three.png', - alt: 'Twenty automation and extensibility toolkit', - }, - ], - }, - { - heading: [ - { - text: 'Continue iteration', - fontFamily: 'serif', - }, - { - text: ' without friction', - fontFamily: 'sans', - }, - ], - body: { - text: 'Enjoy unlimited customization using the AI coding tools you already love. Adapt your CRM to fit the way your business grows and wins.', - }, - images: [ - { - src: '/images/home/stepper/step-two-one.png', - alt: 'Twenty CRM adapted with familiar development tools', - }, - { - src: '/images/home/stepper/step-two-two.png', - alt: 'Customizing Twenty with AI-assisted coding workflows', - }, - { - src: '/images/home/stepper/step-two-three.png', - alt: 'Iterating on Twenty as your business grows', - }, - { - src: '/images/home/stepper/step-two-four.png', - alt: 'Twenty workspace tailored to your team', - }, - ], - }, - { - heading: [ - { - text: 'Stay in control with our', - fontFamily: 'serif', - }, - { - text: ' open-source software', - fontFamily: 'sans', - }, - ], - body: { - text: "Don't get locked into someone else's ecosystem. Twenty's developer experience looks like normal software, with local setup, real data, live testing, and no proprietary tooling.", - }, - images: [ - { - src: '/images/home/stepper/step-three-one.png', - alt: 'Twenty open-source CRM in a normal local development setup', - }, - { - src: '/images/home/stepper/step-three-two.png', - alt: 'Twenty developer experience with real data and live testing', - }, - { - src: '/images/home/stepper/step-three-three.png', - alt: 'Twenty without proprietary vendor lock-in', - }, - { - src: '/images/home/stepper/step-three-four.png', - alt: 'Twenty as transparent, self-hosted software', - }, - ], - }, - ], -}; diff --git a/packages/twenty-website-new/src/app/(home)/constants/testimonials.ts b/packages/twenty-website-new/src/app/(home)/constants/testimonials.ts new file mode 100644 index 00000000000..c5bdf4fba08 --- /dev/null +++ b/packages/twenty-website-new/src/app/(home)/constants/testimonials.ts @@ -0,0 +1,58 @@ +import type { TestimonialsDataType } from '@/sections/Testimonials/types'; + +export const TESTIMONIALS_DATA: TestimonialsDataType = { + eyebrow: { + heading: { text: 'They are the real sales', fontFamily: 'sans' }, + }, + testimonials: [ + { + heading: { + text: "YES @twentycrm has json object fields. Such a simple feature and yet so many CRMs don't. It allows me to add data without caring too much about the data model, and eventually make it cleaner if the model gets stable.", + fontFamily: 'sans', + }, + author: { + avatar: { + src: '/images/home/testimonials/avatar-one.png', + alt: '', + }, + name: { text: 'Wayne Hamadi' }, + handle: { text: '@wayne_hamadi' }, + date: new Date('2024-05-23'), + }, + }, + { + heading: { + text: 'We switched from a rigid CRM where every custom field felt like a ticket. Twenty lets our team model how we actually sell without waiting on consultants.', + fontFamily: 'sans', + }, + author: { + avatar: { + src: '/images/home/testimonials/avatar-two.png', + alt: '', + }, + name: { text: 'Priya Nandakumar' }, + handle: { text: '@priya_builds' }, + date: new Date('2024-07-11'), + }, + }, + { + heading: { + text: 'Open source was the hook; the product is what kept us. Pipelines, people, and reporting finally live in one place our engineers are happy to extend.', + fontFamily: 'sans', + }, + author: { + avatar: { + src: '/images/home/testimonials/avatar-three.png', + alt: '', + }, + name: { text: 'Marcus Chen' }, + handle: { text: '@marcus_ops' }, + date: new Date('2024-09-02'), + }, + }, + ], + illustration: { + src: 'https://app.endlesstools.io/embed/61c7255f-cf10-46f6-ac99-91047fd76d75', + title: 'Endless Tools Editor', + }, +}; diff --git a/packages/twenty-website-new/src/app/(home)/page.tsx b/packages/twenty-website-new/src/app/(home)/page.tsx index f8176a01cbd..48e3d897dd9 100644 --- a/packages/twenty-website-new/src/app/(home)/page.tsx +++ b/packages/twenty-website-new/src/app/(home)/page.tsx @@ -1,16 +1,22 @@ import { FAQ_DATA } from '@/app/(home)/constants/faq'; +import { HELPED_DATA } from '@/app/(home)/constants/helped'; import { HERO_DATA } from '@/app/(home)/constants/hero'; +import { HOME_STEPPER_DATA } from '@/app/(home)/constants/home-stepper'; import { MENU_DATA } from '@/app/(home)/constants/menu'; import { PROBLEM_DATA } from '@/app/(home)/constants/problem'; +import { TESTIMONIALS_DATA } from '@/app/(home)/constants/testimonials'; import { THREE_CARDS_FEATURE_DATA } from '@/app/(home)/constants/three-cards-feature'; import { THREE_CARDS_ILLUSTRATION_DATA } from '@/app/(home)/constants/three-cards-illustration'; import { TRUSTED_BY_DATA } from '@/app/(home)/constants/trusted-by'; import { Body, Eyebrow, Heading, LinkButton } from '@/design-system/components'; import { Pages } from '@/enums/pages'; import { Faq } from '@/sections/Faq/components'; +import { Helped } from '@/sections/Helped/components'; import { Hero } from '@/sections/Hero/components'; +import { HomeStepper } from '@/sections/HomeStepper/components'; import { Menu } from '@/sections/Menu/components'; import { Problem } from '@/sections/Problem/components'; +import { Testimonials } from '@/sections/Testimonials/components'; import { ThreeCards } from '@/sections/ThreeCards/components'; import { TrustedBy } from '@/sections/TrustedBy/components'; import { theme } from '@/theme'; @@ -86,7 +92,7 @@ export default function HomePage() { /> - {/* */} + @@ -105,12 +111,25 @@ export default function HomePage() { /> + + + + + + + + - + + + + + diff --git a/packages/twenty-website-new/src/app/why-twenty/constants/quote.ts b/packages/twenty-website-new/src/app/why-twenty/constants/quote.ts new file mode 100644 index 00000000000..de79da3d30f --- /dev/null +++ b/packages/twenty-website-new/src/app/why-twenty/constants/quote.ts @@ -0,0 +1,12 @@ +import type { QuoteDataType } from '@/sections/Quote/types/QuoteData'; + +export const QUOTE_DATA: QuoteDataType = { + illustration: { + src: 'https://app.endlesstools.io/embed/48586814-c307-4abd-8eec-0270ef3e91ce', + title: 'Endless Tools Editor', + }, + heading: [ + { text: '“In the AI age,\n', fontFamily: 'serif' }, + { text: ' convergence accelerates”', fontFamily: 'sans' }, + ], +}; diff --git a/packages/twenty-website-new/src/app/why-twenty/constants/statement-one.ts b/packages/twenty-website-new/src/app/why-twenty/constants/statement-one.ts new file mode 100644 index 00000000000..3d504694dbe --- /dev/null +++ b/packages/twenty-website-new/src/app/why-twenty/constants/statement-one.ts @@ -0,0 +1,8 @@ +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.', + fontFamily: 'serif', + }, +}; diff --git a/packages/twenty-website-new/src/app/why-twenty/constants/statement-two.ts b/packages/twenty-website-new/src/app/why-twenty/constants/statement-two.ts new file mode 100644 index 00000000000..0a3925723a8 --- /dev/null +++ b/packages/twenty-website-new/src/app/why-twenty/constants/statement-two.ts @@ -0,0 +1,8 @@ +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.', + fontFamily: 'serif', + }, +}; diff --git a/packages/twenty-website-new/src/app/why-twenty/page.tsx b/packages/twenty-website-new/src/app/why-twenty/page.tsx index 6fb441d33c1..72c61be2700 100644 --- a/packages/twenty-website-new/src/app/why-twenty/page.tsx +++ b/packages/twenty-website-new/src/app/why-twenty/page.tsx @@ -1,8 +1,13 @@ import { MENU_DATA } from '@/app/(home)/constants/menu'; import { HERO_DATA } from '@/app/why-twenty/constants/hero'; +import { QUOTE_DATA } from '@/app/why-twenty/constants/quote'; +import { STATEMENT_ONE } from '@/app/why-twenty/constants/statement-one'; +import { STATEMENT_TWO } from '@/app/why-twenty/constants/statement-two'; import { Pages } from '@/enums/pages'; import { Hero } from '@/sections/Hero/components'; import { Menu } from '@/sections/Menu/components'; +import { Quote } from '@/sections/Quote/components'; +import { Statement } from '@/sections/Statement/components'; import { theme } from '@/theme'; export default function WhyTwentyPage() { @@ -32,6 +37,25 @@ export default function WhyTwentyPage() { illustration={HERO_DATA.illustration} /> + + + + + + + + + + + + + ); } diff --git a/packages/twenty-website-new/src/icons/clients/Beagle.tsx b/packages/twenty-website-new/src/icons/clients/Beagle.tsx new file mode 100644 index 00000000000..f41ff2d0637 --- /dev/null +++ b/packages/twenty-website-new/src/icons/clients/Beagle.tsx @@ -0,0 +1,30 @@ +const BEAGLE_VIEWBOX_WIDTH = 104; +const BEAGLE_VIEWBOX_HEIGHT = 25; + +const BEAGLE_PATH_1 = + 'M9.812 24.614h-.649l-1.43-1.982 1.394-4.23c-.184-.802-.777-1.859-1.548-2.844L6.056 22 0 22.19V0h19.257c1.34-.006 2.612.116 3.774.31l-.08 21.751-3.645-.054-1.946-6.218c-1.376.243-2.196-.018-3.4-.395-1.09.56-2.576 1.842-3.549 2.826l1.004 4.565-1.61 1.817zm.183-8.618c1.395-.255 2.557-.802 3.506-1.3-1.322-4.735 1.43-4.145.159-8.892 3.12 1.222-1.75 7.834 1.602 9.165.459.182 1.615.097 2.098-.17 1.958-1.088 2.148-3.44 1.56-5.488-1.278-4.473-5.303-6.99-9.928-5.567-1.59.486-3.138 1.89-2.832 3.55l.801-.736c.147-.134.747.012.74.212l-.018.645-3.756.923c.863.34 1.56.584 2.062 1.046l-1.652 1.319c-.067 1.209 1.205 2.218 2.239 2.522 1.162.34 2.808.23 3.432-.687.012-.292-.172-1.185.08-1.124l1.296.328c-.801 1.5-2.11 1.969-3.835 2.735.489.522 1.761 1.653 2.44 1.531zM4.84 13.03 3.383 9.967c-.44.644-.44 1.41-.147 2.09.19.444.911.864 1.597.973zm79.937-9.34L88.711 2c.165-.073.728-.025.85.073.16.127.416.59.416.88v12.569c0 1.604 1.395 1.629 1.199 2.443-.055.219-.68.492-.96.492l-5.01.019c-.019 5.7-13.55 5.038-14.033 1.653-.16-1.1.997-1.18 1.321-2.249.57-1.872-3.542 2.838-6.356-.486-2.697 1.677-6.404 2.212-8.13-1.124-2.33 2.364-5.737 3.214-8.826 1.963-2.08-.845-3.04-2.632-3.444-4.978-.483 2.474-1.72 4.394-4.148 5.202-1.92.645-4.025.31-5.945-.486-.887-.37-1.573.772-2.882.614-.25-.03-.501-.669-.501-.954l.012-10.994c0-1.653-1.334-1.155-1.566-2.2-.043-.195.343-.748.55-.839l3.72-1.556c.195-.079.862-.073 1.04.037.226.14.397.686.403.978l.104 5.956c1.946-1.635 3.677-2.157 5.744-1.568 2.068.59 2.973 2.425 3.512 4.88.862-3.786 4.367-5.725 8.062-4.935 2.355.505 4.172 2.407 3.762 4.923l-6.533 2.079c1.095 1.98 3.487 2.23 5.426 1.045.349-.213 1.034-.462 1.554-.68.948-3.216 3.798-3.125 6.85-2.936.209-1.216-1.063-2.437-2.477-2.115-1.712.395-3.034 1.234-3.364.535-.703-1.459 2.508-3.367 6.472-2.942 1.853.2 3.315 1.404 3.578 3.27l.606 4.224c.08.559 1.438 1.5 1.756 1.063l1.553-2.17c-.88-.875-1.535-1.604-1.553-2.594-.05-3.282 4.66-3.805 7.12-4.103.6-1.215.936-3.166 2.539-3.561 1.174-.292 2.104.54 3.125 1.495l.52-1.24zM74.672 14.561c3.548 1.841 6.551-.499 10.112 2.4.232.195.984-.522.984-.93l-.036-9.942c0-.42-.985-1.355-1.09-1.082-.079.213-.378 1.015-.61 1.07l-3.683.82c.287 1.203 3.321.796 3.413 3.586.043 1.282-.795 2.291-1.988 2.953-2.208 1.234-4.533.547-7.102 1.125m4.967-3.786a2.017 2.017 0 0 0-2.025-2.012c-1.12 0-2.025.9-2.025 2.011 0 1.113.906 2.012 2.025 2.012 1.12 0 2.025-.9 2.025-2.012m-26.236.589c.287-.42-.227-1.489-.618-1.811-.343-.28-1.517-.383-1.866-.073-.838.73-1.107 2.291-.544 3.075.984-.146 2.422-.601 3.028-1.191m-16.199 4.364c.508.79 1.597 1.209 2.362 1.033 1.86-.426 2.208-4.157.428-6.078-.373-.4-1.322-.753-1.774-.632-2 .541-2.245 3.75-1.016 5.677m28.36-.809a1.56 1.56 0 0 0-1.566-1.556c-.863 0-1.566.7-1.566 1.556s.703 1.556 1.566 1.556c.862 0 1.566-.699 1.566-1.556m15.53 5.039c-.146-.11-.647-.493-.862-.517l-5.254-.602c-.325-.036-.863.766-.716 1.033 1.224 2.213 8.044 1.01 6.827.085zm15.576-5.59c.88 2.243 3.773 2.146 5.468.936.269-.188.948-.273 1.211-.23.263.042.196.947.006 1.172-2.159 2.595-6.386 3.403-9.402 1.61-2.123-1.257-2.881-3.603-2.477-5.864s2.183-4.023 4.606-4.576c2.006-.462 4.117-.183 5.67 1.19 1.083.961 1.683 2.353 1.267 3.739l-6.35 2.03zm2.415-2.814c-.152-.93-.501-1.786-.899-2.048-.434-.285-1.584-.291-1.908.08a2.82 2.82 0 0 0-.416 3.05l3.223-1.075z'; + +const BEAGLE_PATH_2 = + 'm11.977 8.187-.868-.62c-.19-.134-.618.048-1.187.152 0-.134.202-.766.373-1.015.202-.286 1.18-.22 1.389.066.208.286.312.96.293 1.417'; + +type BeagleIconProps = { + fillColor: string; + size: number; +}; + +export function BeagleIcon({ fillColor, size }: BeagleIconProps) { + const height = size * (BEAGLE_VIEWBOX_HEIGHT / BEAGLE_VIEWBOX_WIDTH); + + return ( + + + + + ); +} diff --git a/packages/twenty-website-new/src/icons/clients/Evergreen.tsx b/packages/twenty-website-new/src/icons/clients/Evergreen.tsx new file mode 100644 index 00000000000..08f3d70c6a1 --- /dev/null +++ b/packages/twenty-website-new/src/icons/clients/Evergreen.tsx @@ -0,0 +1,26 @@ +const EVERGREEN_VIEWBOX_WIDTH = 134; +const EVERGREEN_VIEWBOX_HEIGHT = 16; + +const EVERGREEN_PATH = + 'M75.483.012v15.632h4.756V10.21h2.598c.688 0 1.305.561 1.305 1.276v4.157h4.76V9.647c0-.946-.498-1.166-.874-1.196.376-.006.874-.272.874-1.227V2.253c0-1.83-.798-2.242-2.041-2.242zM80.24 3.88h3.183c.481 0 .72.294.72.794v1.29c0 .498-.24.73-.72.73H80.24zM105.135.012h13.081v3.867h-8.324v2.11h8.324v3.483h-8.324v2.322h8.324v3.85h-13.081zm-14.601 0h13.08v3.867h-8.323v2.11h8.323v3.483h-8.323v2.322h8.323v3.85h-13.08zM0 .012h13.08v3.867H4.757v2.11h8.323v3.483H4.757v2.322h8.323v3.85H0zm119.687 0h4.9l4.438 8.352V.012h4.931v15.632h-4.931l-4.438-8.51v8.51h-4.9zM61.176 15.36c-.32-.172-.74-.535-.934-.808-.34-.48-.352-.703-.352-6.716 0-8.465-.568-7.825 6.965-7.825 4.514 0 5.163.033 5.685.306.96.502 1.276 1.274 1.278 3.122l.002 1.583-4.725.02V4.55c0-.327-.374-.67-.69-.67h-2.987c-.344 0-.74.39-.74.747V11c0 .368.387.793.742.793h2.972c.347 0 .703-.439.703-.8V9.86h-2.548V6.62l7.273-.014v3.605c0 3.936-.071 4.293-.99 4.998-.458.351-.707.39-5.775.435-4.79.043-5.352-.002-5.879-.284M44.857.012v15.632h4.756V10.21h2.598c.688 0 1.305.561 1.305 1.276v4.157h4.76V9.647c0-.946-.498-1.166-.874-1.196.376-.006.874-.272.874-1.227V2.253c0-1.83-.798-2.242-2.041-2.242zm4.757 3.868h3.183c.481 0 .72.294.72.794v1.29c0 .498-.24.73-.72.73h-3.183zM30.248.012h13.08v3.867h-8.324v2.11h8.324v3.483h-8.324v2.322h8.324v3.85h-13.08zm-16.344 0h5.08l2.574 10.023L24.144.012h5.1l-5.006 15.632h-5.361z'; + +type EvergreenIconProps = { + fillColor: string; + size: number; +}; + +export function EvergreenIcon({ fillColor, size }: EvergreenIconProps) { + const height = size * (EVERGREEN_VIEWBOX_HEIGHT / EVERGREEN_VIEWBOX_WIDTH); + + return ( + + + + ); +} diff --git a/packages/twenty-website-new/src/icons/clients/Realytics.tsx b/packages/twenty-website-new/src/icons/clients/Realytics.tsx new file mode 100644 index 00000000000..14f1cadac53 --- /dev/null +++ b/packages/twenty-website-new/src/icons/clients/Realytics.tsx @@ -0,0 +1,26 @@ +const REALYTICS_VIEWBOX_WIDTH = 115; +const REALYTICS_VIEWBOX_HEIGHT = 27; + +const REALYTICS_PATH = + 'm50.998 21.111-2.184-4.264h-1.32v4.264H44.17V8.397h4.803c2.731 0 5.074.939 5.074 4.106a3.91 3.91 0 0 1-2.052 3.676l2.75 4.926zm-3.47-6.922h1.207c1.32 0 2.032-.589 2.032-1.68s-.7-1.447-2.032-1.447h-1.208zm12.29-3.009c2.751 0 4.117 1.984 4.117 4.629a5.7 5.7 0 0 1-.099 1.243h-5.792a2.34 2.34 0 0 0 2.52 2.116 3.9 3.9 0 0 0 2.091-.662l.957 1.74a6.3 6.3 0 0 1-3.437 1.097c-2.771 0-4.896-1.878-4.896-5.085s2.237-5.077 4.54-5.077m1.676 4.087c0-1.118-.468-1.898-1.616-1.898-.898 0-1.676.608-1.874 1.898zm8.846-.391a1.325 1.325 0 0 0-.934-1.369 1.3 1.3 0 0 0-.59-.04c-.92.06-1.808.363-2.573.88l-1.016-1.924a8 8 0 0 1 4.137-1.27c2.48 0 3.846 1.408 3.846 4.384v5.554h-2.342l-.218-.999h-.06a4.25 4.25 0 0 1-2.856 1.256 2.78 2.78 0 0 1-2.078-.836 2.8 2.8 0 0 1-.792-2.1c.027-2.022 1.65-3.146 5.476-3.536m-1.603 4.244a2.15 2.15 0 0 0 1.603-.82v-1.699c-2.052.271-2.711.86-2.711 1.6-.007.628.422.92 1.108.92m6.307-11.618h3.358v10.288c0 .661.31.86.548.86q.177.005.35-.04l.389 2.466a4.1 4.1 0 0 1-1.637.271c-2.263 0-3.001-1.487-3.001-3.676zm5.885 16.371c1.075 0 1.755-.86 2.144-2.036l.218-.701-3.807-9.528h1.656l1.933 5.29c.29.82.627 1.798.917 2.678h.08c.27-.86.547-1.839.797-2.678l1.703-5.29h1.563l-3.576 10.288c-.66 1.878-1.642 3.306-3.549 3.306a3.1 3.1 0 0 1-1.115-.198l.31-1.27q.354.118.726.14m8.807-10.95h-1.405v-1.21l1.485-.1.197-2.644h1.32v2.645h2.553v1.322h-2.533v5.29c0 1.177.37 1.838 1.464 1.838a3.4 3.4 0 0 0 1.076-.252l.31 1.21a5.8 5.8 0 0 1-1.755.35c-2.032 0-2.712-1.322-2.712-3.166zm5.543-4.304a1.12 1.12 0 0 1 1.11-1.032 1.114 1.114 0 0 1 1.112 1.032 1.12 1.12 0 0 1-1.111 1.031 1.114 1.114 0 0 1-1.112-1.031m.29 2.995h1.603v9.508h-1.604zm8.181-.231a3.9 3.9 0 0 1 2.771 1.137l-.798 1.038a2.87 2.87 0 0 0-1.913-.84c-1.716 0-2.969 1.488-2.969 3.676s1.187 3.637 2.929 3.637a3.38 3.38 0 0 0 2.23-.966l.719 1.058a4.7 4.7 0 0 1-3.081 1.23c-2.52 0-4.447-1.818-4.447-4.965 0-3.148 2.118-5.005 4.559-5.005m4.288 7.59a4.26 4.26 0 0 0 2.791 1.137c1.247 0 1.874-.661 1.874-1.488 0-.978-1.135-1.408-2.164-1.798-1.32-.49-2.83-1.137-2.83-2.737s1.207-2.698 3.259-2.698a4.73 4.73 0 0 1 2.949 1.071l-.759 1.018a3.52 3.52 0 0 0-2.164-.84c-1.187 0-1.735.662-1.735 1.37 0 .879 1.036 1.23 2.105 1.646 1.365.509 2.889 1.077 2.889 2.876 0 1.547-1.227 2.836-3.477 2.836a5.7 5.7 0 0 1-3.529-1.322zM9.401 12.562H.33a.33.33 0 0 0-.33.331v13.085c0 .182.148.33.33.33H9.4a.33.33 0 0 0 .33-.33V12.893a.33.33 0 0 0-.33-.33m11.824 5.758h-9.019a.33.33 0 0 0-.33.33v7.327c0 .182.148.33.33.33h9.019a.33.33 0 0 0 .33-.33v-7.326a.33.33 0 0 0-.33-.33M33.211 0h-9.21a.33.33 0 0 0-.33.33v25.648c0 .182.148.33.33.33h9.21a.33.33 0 0 0 .33-.33V.33a.33.33 0 0 0-.33-.331'; + +type RealyticsIconProps = { + fillColor: string; + size: number; +}; + +export function RealyticsIcon({ fillColor, size }: RealyticsIconProps) { + const height = size * (REALYTICS_VIEWBOX_HEIGHT / REALYTICS_VIEWBOX_WIDTH); + + return ( + + + + ); +} diff --git a/packages/twenty-website-new/src/icons/clients/index.ts b/packages/twenty-website-new/src/icons/clients/index.ts index 59c58fb04c9..7dc3328a764 100644 --- a/packages/twenty-website-new/src/icons/clients/index.ts +++ b/packages/twenty-website-new/src/icons/clients/index.ts @@ -1,13 +1,22 @@ -import type { ComponentType } from "react"; -import { FlexportIcon } from "./Flexport"; -import { ZapierIcon } from "./Zapier"; +import type { ComponentType } from 'react'; +import { BeagleIcon } from './Beagle'; +import { EvergreenIcon } from './Evergreen'; +import { FlexportIcon } from './Flexport'; +import { RealyticsIcon } from './Realytics'; +import { ZapierIcon } from './Zapier'; -export { FlexportIcon } from "./Flexport"; -export { ZapierIcon } from "./Zapier"; +export { BeagleIcon } from './Beagle'; +export { EvergreenIcon } from './Evergreen'; +export { FlexportIcon } from './Flexport'; +export { RealyticsIcon } from './Realytics'; +export { ZapierIcon } from './Zapier'; -export type ClientIconProps = { size: number; fillColor: string }; +export type ClientIconProps = { fillColor: string; size: number }; export const CLIENT_ICONS: Record> = { + beagle: BeagleIcon, + evergreen: EvergreenIcon, flexport: FlexportIcon, + realytics: RealyticsIcon, zapier: ZapierIcon, }; diff --git a/packages/twenty-website-new/src/sections/Helped/HelpedCardShape.tsx b/packages/twenty-website-new/src/sections/Helped/HelpedCardShape.tsx new file mode 100644 index 00000000000..bbcc2d775ba --- /dev/null +++ b/packages/twenty-website-new/src/sections/Helped/HelpedCardShape.tsx @@ -0,0 +1,47 @@ +const HELPED_CARD_SHAPE_FILL_PATH = + 'M0 490V4a4 4 0 0 1 4-4h288.23c.932 0 1.856.163 2.731.48l60.814 22.09c.875.318 1.8.48 2.731.48H439a4 4 0 0 1 4 4V490a4 4 0 0 1-4 4H4a4 4 0 0 1-4-4'; + +const HELPED_CARD_SHAPE_STROKE_PATH = + 'M4 .5h288.23c.874 0 1.74.152 2.561.45l60.813 22.09c.931.338 1.912.51 2.902.51H439a3.5 3.5 0 0 1 3.5 3.5V490a3.5 3.5 0 0 1-3.5 3.5H4A3.5 3.5 0 0 1 .5 490V4A3.5 3.5 0 0 1 4 .5Z'; + +type HelpedCardShapeProps = { + fillColor: string; + strokeColor: string; +}; + +export function HelpedCardShape({ + fillColor, + strokeColor, +}: HelpedCardShapeProps) { + return ( +
+ + + + +
+ ); +} diff --git a/packages/twenty-website-new/src/sections/Helped/components/Card/Card.tsx b/packages/twenty-website-new/src/sections/Helped/components/Card/Card.tsx new file mode 100644 index 00000000000..c244e77efc6 --- /dev/null +++ b/packages/twenty-website-new/src/sections/Helped/components/Card/Card.tsx @@ -0,0 +1,139 @@ +import { Body, Heading, LinkButton } from '@/design-system/components'; +import { CLIENT_ICONS } from '@/icons'; +import { HelpedCardShape } from '@/sections/Helped/HelpedCardShape'; +import type { HeadingCardType } from '@/sections/Helped/types/HeadingCard'; +import { theme } from '@/theme'; +import { styled } from '@linaria/react'; + +const CardRoot = styled.article` + display: grid; + grid-template-columns: 1fr; + isolation: isolate; + max-width: 443px; + min-height: 0; + min-width: 0; + padding-bottom: ${theme.spacing(4)}; + padding-left: ${theme.spacing(4)}; + padding-right: ${theme.spacing(4)}; + padding-top: ${theme.spacing(2.5)}; + position: relative; + row-gap: ${theme.spacing(2.5)}; + width: 100%; +`; + +const LogoRow = styled.div` + align-items: center; + display: grid; + grid-template-columns: 1fr; + min-height: ${theme.spacing(8)}; +`; + +const Rule = styled.div` + background-color: ${theme.colors.secondary.border[40]}; + height: 1px; + width: 100%; +`; + +const VisualShell = styled.div` + background-color: ${theme.colors.secondary.background[100]}; + border-radius: ${theme.radius(2)}; + height: 240px; + overflow: hidden; + position: relative; + width: 100%; +`; + +const StyledIframe = styled.iframe` + border: none; + height: 200%; + left: 51.5%; + mix-blend-mode: lighten; + pointer-events: none; + position: absolute; + top: 50%; + transform: translate(-50%, -50%); + width: 200%; +`; + +const HueOverlay = styled.div` + background-color: ${theme.colors.highlight[100]}; + inset: 0; + mix-blend-mode: hue; + pointer-events: none; + position: absolute; +`; + +const CopyBlock = styled.div` + display: grid; + grid-template-columns: 1fr; + row-gap: ${theme.spacing(2)}; +`; + +const CardTitleWrap = styled.div` + color: ${theme.colors.secondary.text[100]}; +`; + +const CardBodyWrap = styled.div` + color: ${theme.colors.secondary.text[80]}; +`; + +const CtaRow = styled.div` + display: grid; + grid-template-columns: max-content; + justify-items: start; + padding-top: ${theme.spacing(1)}; +`; + +const LOGO_FILL = theme.colors.secondary.text[100]; + +type CardProps = { + card: HeadingCardType; +}; + +export function Card({ card }: CardProps) { + const IconComponent = CLIENT_ICONS[card.icon]; + const logoWidth = card.icon === 'evergreen' ? 96 : 104; + + return ( + + + + {IconComponent ? ( + + ) : null} + + + ); +} diff --git a/packages/twenty-website-new/src/sections/Helped/components/Root/Root.tsx b/packages/twenty-website-new/src/sections/Helped/components/Root/Root.tsx new file mode 100644 index 00000000000..ca74c9b9148 --- /dev/null +++ b/packages/twenty-website-new/src/sections/Helped/components/Root/Root.tsx @@ -0,0 +1,15 @@ +import { styled } from '@linaria/react'; +import type { ReactNode } from 'react'; + +const StyledSection = styled.section` + width: 100%; +`; + +type RootProps = { + backgroundColor: string; + children: ReactNode; +}; + +export function Root({ backgroundColor, children }: RootProps) { + return {children}; +} diff --git a/packages/twenty-website-new/src/sections/Helped/components/Scene/Scene.tsx b/packages/twenty-website-new/src/sections/Helped/components/Scene/Scene.tsx new file mode 100644 index 00000000000..5172198edd5 --- /dev/null +++ b/packages/twenty-website-new/src/sections/Helped/components/Scene/Scene.tsx @@ -0,0 +1,104 @@ +'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 { Card } from '../Card/Card'; + +const SCROLL_HEIGHT_VH = 420; + +const ScrollStage = styled.section` + position: relative; + width: 100%; +`; + +const StickyInner = styled.div` + align-items: center; + display: grid; + grid-template-columns: 1fr; + grid-template-rows: 1fr; + justify-items: center; + min-height: 100vh; + overflow: hidden; + position: sticky; + top: 0; +`; + +const HeadlineBlock = styled.div` + display: grid; + grid-template-columns: 1fr; + justify-items: center; + max-width: 688px; + padding-left: ${theme.spacing(4)}; + padding-right: ${theme.spacing(4)}; + row-gap: ${theme.spacing(6)}; + text-align: center; + width: 100%; + z-index: 1; +`; + +const CardsLayer = styled.div` + inset: 0; + pointer-events: none; + position: absolute; + z-index: 2; + + & article { + pointer-events: auto; + } +`; + +const CardPositioner = styled.div` + position: absolute; + width: min(${CARD_WIDTH_DESKTOP}px, calc(100% - ${theme.spacing(8)})); + will-change: transform, opacity; +`; + +type SceneProps = { + data: HelpedDataType; +}; + +export function Scene({ data }: SceneProps) { + const sectionRef = useRef(null); + const innerRef = useRef(null); + const headlineRef = useRef(null); + const cardRefs = useRef<(HTMLDivElement | null)[]>([]); + + return ( + + + + + + + + + {data.cards.map((card, index) => ( + { + cardRefs.current[index] = element; + }} + > + + + ))} + + + + ); +} diff --git a/packages/twenty-website-new/src/sections/Helped/components/index.ts b/packages/twenty-website-new/src/sections/Helped/components/index.ts new file mode 100644 index 00000000000..e76bec07900 --- /dev/null +++ b/packages/twenty-website-new/src/sections/Helped/components/index.ts @@ -0,0 +1,4 @@ +import { Root } from './Root/Root'; +import { Scene } from './Scene/Scene'; + +export const Helped = { Root, Scene }; diff --git a/packages/twenty-website-new/src/sections/Helped/effect-components/HelpedSceneScrollLayoutEffect.tsx b/packages/twenty-website-new/src/sections/Helped/effect-components/HelpedSceneScrollLayoutEffect.tsx new file mode 100644 index 00000000000..d831887ec64 --- /dev/null +++ b/packages/twenty-website-new/src/sections/Helped/effect-components/HelpedSceneScrollLayoutEffect.tsx @@ -0,0 +1,57 @@ +'use client'; + +import { useEffect } from 'react'; + +import type { HeadingCardType } from '@/sections/Helped/types/HeadingCard'; +import { + applyHelpedSceneLayout, + type HelpedSceneLayoutRefs, +} from '@/sections/Helped/utils/helped-scene-layout'; + +type HelpedSceneScrollLayoutEffectProps = HelpedSceneLayoutRefs & { + cards: HeadingCardType[]; +}; + +export function HelpedSceneScrollLayoutEffect({ + cardRefs, + cards, + headlineRef, + innerRef, + sectionRef, +}: HelpedSceneScrollLayoutEffectProps) { + useEffect(() => { + const refs: HelpedSceneLayoutRefs = { + cardRefs, + headlineRef, + innerRef, + sectionRef, + }; + + let rafId: number | null = null; + + const flushLayout = () => { + rafId = null; + applyHelpedSceneLayout(refs, cards); + }; + + const scheduleLayout = () => { + if (rafId !== null) { + return; + } + rafId = window.requestAnimationFrame(flushLayout); + }; + + applyHelpedSceneLayout(refs, cards); + window.addEventListener('scroll', scheduleLayout, { passive: true }); + window.addEventListener('resize', scheduleLayout); + return () => { + window.removeEventListener('scroll', scheduleLayout); + window.removeEventListener('resize', scheduleLayout); + if (rafId !== null) { + window.cancelAnimationFrame(rafId); + } + }; + }, [cardRefs, cards, headlineRef, innerRef, sectionRef]); + + return null; +} diff --git a/packages/twenty-website-new/src/sections/Helped/types/HeadingCard.ts b/packages/twenty-website-new/src/sections/Helped/types/HeadingCard.ts new file mode 100644 index 00000000000..8e1b0629038 --- /dev/null +++ b/packages/twenty-website-new/src/sections/Helped/types/HeadingCard.ts @@ -0,0 +1,10 @@ +import type { BodyType } from '@/design-system/components/Body/types/Body'; +import type { HeadingType } from '@/design-system/components/Heading/types/Heading'; +import type { IllustrationType } from '@/design-system/components/Illustration/types/Illustration'; + +export type HeadingCardType = { + icon: string; + illustration: IllustrationType; + heading: HeadingType; + body: BodyType; +}; diff --git a/packages/twenty-website-new/src/sections/Helped/types/HelpedData.ts b/packages/twenty-website-new/src/sections/Helped/types/HelpedData.ts new file mode 100644 index 00000000000..d9cc2f4658c --- /dev/null +++ b/packages/twenty-website-new/src/sections/Helped/types/HelpedData.ts @@ -0,0 +1,9 @@ +import type { EyebrowType } from '@/design-system/components/Eyebrow/types/Eyebrow'; +import type { HeadingType } from '@/design-system/components/Heading/types/Heading'; +import type { HeadingCardType } from '@/sections/Helped/types/HeadingCard'; + +export type HelpedDataType = { + eyebrow: EyebrowType; + heading: HeadingType[]; + cards: HeadingCardType[]; +}; diff --git a/packages/twenty-website-new/src/sections/Helped/types/index.ts b/packages/twenty-website-new/src/sections/Helped/types/index.ts new file mode 100644 index 00000000000..e69de29bb2d diff --git a/packages/twenty-website-new/src/sections/Helped/utils/helped-scene-layout.ts b/packages/twenty-website-new/src/sections/Helped/utils/helped-scene-layout.ts new file mode 100644 index 00000000000..eb5aaa5f051 --- /dev/null +++ b/packages/twenty-website-new/src/sections/Helped/utils/helped-scene-layout.ts @@ -0,0 +1,139 @@ +import type { RefObject } from 'react'; + +import type { HeadingCardType } from '@/sections/Helped/types/HeadingCard'; +import { theme } from '@/theme'; + +export const CARD_WIDTH_DESKTOP = 443; +const CARD_WIDTH_MOBILE_MAX = 360; +const HORIZONTAL_PAD = 32; + +// Scroll progress 0..1 through the tall section +const HEADLINE_FADE_START = 0.76; +const HEADLINE_FADE_END = 0.92; +const HEADLINE_LIFT_PX = 48; + +// Each card fades/slides in over the same window, shifted along the scroll +const CARD_WINDOW = 0.2; +const CARD_STAGGER = 0.12; +const CARD_FIRST_START = 0.06; +const ENTER_OFFSET_Y_RATIO = 0.34; + +function clamp01(value: number) { + return Math.min(1, Math.max(0, value)); +} + +function cardRestPosition( + index: number, + innerWidth: number, + innerHeight: number, + cardWidth: number, + isDesktop: boolean, +): { left: number; top: number } { + if (isDesktop) { + if (index === 0) { + return { + left: innerWidth - cardWidth - innerWidth * 0.035, + top: innerHeight * 0.08, + }; + } + if (index === 1) { + return { + left: innerWidth * 0.03, + top: innerHeight * 0.3, + }; + } + return { + left: (innerWidth - cardWidth) / 2, + top: innerHeight * 0.52, + }; + } + + return { + left: (innerWidth - cardWidth) / 2, + top: innerHeight * 0.36 + index * 0.06 * innerHeight, + }; +} + +export type HelpedSceneLayoutRefs = { + cardRefs: RefObject<(HTMLDivElement | null)[]>; + headlineRef: RefObject; + innerRef: RefObject; + sectionRef: RefObject; +}; + +export function applyHelpedSceneLayout( + refs: HelpedSceneLayoutRefs, + cards: readonly HeadingCardType[], +): void { + const { sectionRef, innerRef, headlineRef, cardRefs } = refs; + const section = sectionRef.current; + const inner = innerRef.current; + if (!section || !inner) { + return; + } + + const reducedMotion = window.matchMedia( + '(prefers-reduced-motion: reduce)', + ).matches; + const isDesktop = window.matchMedia( + `(min-width: ${theme.breakpoints.md}px)`, + ).matches; + + const rect = section.getBoundingClientRect(); + const scrollRange = Math.max(1, section.offsetHeight - window.innerHeight); + const progress = clamp01(-rect.top / scrollRange); + + const innerWidth = inner.offsetWidth; + const innerHeight = inner.offsetHeight; + const cardWidth = Math.min( + isDesktop ? CARD_WIDTH_DESKTOP : CARD_WIDTH_MOBILE_MAX, + innerWidth - HORIZONTAL_PAD * 2, + ); + + if (headlineRef.current) { + const headlineT = clamp01( + (progress - HEADLINE_FADE_START) / + (HEADLINE_FADE_END - HEADLINE_FADE_START), + ); + headlineRef.current.style.opacity = String(1 - headlineT); + headlineRef.current.style.transform = `translate3d(0, ${-headlineT * HEADLINE_LIFT_PX}px, 0)`; + } + + const enterOffsetY = innerHeight * ENTER_OFFSET_Y_RATIO; + + cards.forEach((_, index) => { + const node = cardRefs.current[index]; + if (!node) { + return; + } + + const { left: restLeft, top: restTop } = cardRestPosition( + index, + innerWidth, + innerHeight, + cardWidth, + isDesktop, + ); + + node.style.width = `${cardWidth}px`; + node.style.zIndex = String(10 + index); + + if (reducedMotion) { + node.style.opacity = '1'; + node.style.transform = 'none'; + node.style.left = `${restLeft}px`; + node.style.top = `${restTop}px`; + return; + } + + const windowStart = CARD_FIRST_START + index * CARD_STAGGER; + const windowEnd = windowStart + CARD_WINDOW; + const cardT = clamp01( + (progress - windowStart) / (windowEnd - windowStart), + ); + + node.style.left = `${restLeft}px`; + node.style.top = `${restTop + enterOffsetY * (1 - cardT)}px`; + node.style.opacity = String(cardT); + }); +} diff --git a/packages/twenty-website-new/src/sections/HeroStepper/components/Content/Content.tsx b/packages/twenty-website-new/src/sections/HeroStepper/components/Content/Content.tsx deleted file mode 100644 index 0574a9a8a4e..00000000000 --- a/packages/twenty-website-new/src/sections/HeroStepper/components/Content/Content.tsx +++ /dev/null @@ -1,217 +0,0 @@ -'use client'; - -import { Body, Heading } from '@/design-system/components'; -import type { HeroStepperContentProps } from '@/sections/HeroStepper/types'; -import { theme } from '@/theme'; -import { styled } from '@linaria/react'; -import { useEffect, useRef, type ReactNode } from 'react'; - -const ContentRoot = styled.div` - display: grid; - grid-template-columns: auto 1fr; - gap: ${theme.spacing(6)}; - min-width: 0; - - @media (min-width: ${theme.breakpoints.md}px) { - gap: ${theme.spacing(10)}; - } -`; - -const ProgressRail = styled.div` - display: none; - - @media (min-width: ${theme.breakpoints.md}px) { - display: flex; - flex-direction: column; - align-items: center; - gap: ${theme.spacing(2)}; - position: sticky; - top: calc(50vh - ${theme.spacing(10)}); - height: max-content; - } -`; - -const StepIndicatorRow = styled.div` - display: flex; - align-items: flex-start; - gap: ${theme.spacing(4)}; -`; - -const PillBackground = styled.div` - background-color: ${theme.colors.primary.border[80]}; - border-radius: ${theme.radius(8)}; - display: flex; - height: ${theme.spacing(20)}; - overflow: hidden; - width: ${theme.spacing(1)}; -`; - -const PillFill = styled.div` - background-color: ${theme.colors.highlight[100]}; - border-radius: ${theme.radius(10)}; - transition: height 0.4s ease; - width: 100%; -`; - -const ActiveLabel = styled.p` - color: ${theme.colors.highlight[100]}; - font-family: ${theme.font.family.mono}; - font-size: ${theme.font.size(3)}; - font-weight: ${theme.font.weight.medium}; - margin: 0; - text-transform: uppercase; - line-height: ${theme.spacing(4)}; -`; - -const InactiveDotWrapper = styled.div` - display: flex; - align-items: center; - gap: ${theme.spacing(4)}; -`; - -const InactiveDot = styled.div` - background-color: ${theme.colors.primary.border[80]}; - border-radius: 50%; - height: ${theme.spacing(1)}; - width: ${theme.spacing(1)}; -`; - -const StepsColumn = styled.div` - display: grid; - grid-template-columns: 1fr; - min-width: 0; - - @media (min-width: ${theme.breakpoints.md}px) { - max-width: 454px; - } -`; - -const StepBlock = styled.div` - align-content: center; - display: grid; - grid-template-columns: 1fr; - min-height: 80vh; - opacity: 0.3; - row-gap: ${theme.spacing(4)}; - transition: opacity 0.4s ease; - - @media (min-width: ${theme.breakpoints.md}px) { - min-height: 100vh; - row-gap: ${theme.spacing(6)}; - } - - &[data-active='true'] { - opacity: 1; - } -`; - -type ProgressRailProps = { - activeImageIndex: number; - activeStepIndex: number; - steps: HeroStepperContentProps['steps']; -}; - -function HeroProgressRail({ - activeImageIndex, - activeStepIndex, - steps, -}: ProgressRailProps) { - const nodes: ReactNode[] = []; - const stepCount = steps.length; - - for (let index = 0; index < stepCount; index += 1) { - if (index === activeStepIndex) { - const stepImagesCount = steps[index]?.images.length || 1; - const fillPercentage = ((activeImageIndex + 1) / stepImagesCount) * 100; - - nodes.push( - - - - - {String(index + 1).padStart(2, '0')} - , - ); - } else { - nodes.push( - - - , - ); - } - } - - return {nodes}; -} - -export function Content({ - activeImageIndex, - activeStepIndex, - onActiveStepChange, - steps, -}: HeroStepperContentProps) { - const stepRefs = useRef<(HTMLDivElement | null)[]>([]); - - useEffect(() => { - stepRefs.current = stepRefs.current.slice(0, steps.length); - }, [steps.length]); - - useEffect(() => { - const elements = stepRefs.current.filter(Boolean) as HTMLDivElement[]; - if (elements.length === 0) { - return; - } - - const observer = new IntersectionObserver( - (entries) => { - const candidates = entries.filter( - (entry) => entry.isIntersecting && entry.intersectionRatio > 0.15, - ); - if (candidates.length === 0) { - return; - } - - const best = candidates.reduce((previous, current) => - current.intersectionRatio > previous.intersectionRatio - ? current - : previous, - ); - const indexAttribute = best.target.getAttribute('data-step-index'); - const index = indexAttribute === null ? NaN : Number(indexAttribute); - if (!Number.isNaN(index)) { - onActiveStepChange(index); - } - }, - { root: null, threshold: [0, 0.15, 0.3, 0.5, 0.75, 1] }, - ); - - elements.forEach((element) => observer.observe(element)); - - return () => observer.disconnect(); - }, [onActiveStepChange, steps]); - - return ( - - - - {steps.map((step, index) => ( - { - stepRefs.current[index] = element; - }} - > - - - - ))} - - - ); -} diff --git a/packages/twenty-website-new/src/sections/HeroStepper/components/Flow/Flow.tsx b/packages/twenty-website-new/src/sections/HeroStepper/components/Flow/Flow.tsx deleted file mode 100644 index 96a535026d8..00000000000 --- a/packages/twenty-website-new/src/sections/HeroStepper/components/Flow/Flow.tsx +++ /dev/null @@ -1,45 +0,0 @@ -'use client'; - -import type { HeroStepperStepType } from '@/sections/HeroStepper/types/HeroStepperStep'; -import { useEffect, useState } from 'react'; -import { Content } from '../Content/Content'; -import { Root } from '../Root/Root'; -import { Visual } from '../Visual/Visual'; - -type FlowProps = { - steps: HeroStepperStepType[]; -}; - -export function Flow({ steps }: FlowProps) { - const [activeStepIndex, setActiveStepIndex] = useState(0); - const [activeImageIndex, setActiveImageIndex] = useState(0); - - useEffect(() => { - setActiveImageIndex(0); - }, [activeStepIndex]); - - useEffect(() => { - const imageList = steps[activeStepIndex]?.images ?? []; - if (imageList.length <= 1) { - return; - } - const timerId = window.setInterval(() => { - setActiveImageIndex((previous) => (previous + 1) % imageList.length); - }, 5000); - return () => window.clearInterval(timerId); - }, [activeStepIndex, steps]); - - const images = steps[activeStepIndex]?.images ?? []; - - return ( - - - - - ); -} diff --git a/packages/twenty-website-new/src/sections/HeroStepper/components/Visual/Visual.tsx b/packages/twenty-website-new/src/sections/HeroStepper/components/Visual/Visual.tsx deleted file mode 100644 index 7c31e9d3c80..00000000000 --- a/packages/twenty-website-new/src/sections/HeroStepper/components/Visual/Visual.tsx +++ /dev/null @@ -1,61 +0,0 @@ -import type { HeroStepperVisualProps } from '@/sections/HeroStepper/types'; -import { theme } from '@/theme'; -import { css } from '@linaria/core'; -import { styled } from '@linaria/react'; -import NextImage from 'next/image'; -import { StepperVisualFrame } from '../StepperVisualFrame/StepperVisualFrame'; - -const HOME_STEPPER_BACKGROUND = '/images/home/stepper/background.png'; -const HOME_STEPPER_SHAPE = '/images/home/stepper/background-shape.png'; - -const VisualColumn = styled.div` - min-width: 0; - width: 100%; - - @media (min-width: ${theme.breakpoints.md}px) { - max-width: 672px; - position: sticky; - top: ${theme.spacing(10)}; - } -`; - -const slideImageClassName = css` - object-fit: contain; - object-position: center; - opacity: 0; - transition: opacity 0.4s ease; - - &[data-active='true'] { - opacity: 1; - } -`; - -export function Visual({ - activeImageIndex = 0, - images, -}: HeroStepperVisualProps) { - if (!images || images.length === 0) { - return null; - } - - return ( - - - {images.map((image, index) => ( - - ))} - - - ); -} diff --git a/packages/twenty-website-new/src/sections/HeroStepper/components/index.ts b/packages/twenty-website-new/src/sections/HeroStepper/components/index.ts deleted file mode 100644 index 37969298804..00000000000 --- a/packages/twenty-website-new/src/sections/HeroStepper/components/index.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { Content } from './Content/Content'; -import { Flow } from './Flow/Flow'; -import { Root } from './Root/Root'; -import { Visual } from './Visual/Visual'; - -export const HeroStepper = { - Content, - Flow, - Root, - Visual, -}; diff --git a/packages/twenty-website-new/src/sections/HeroStepper/types/HeroStepperContentProps.ts b/packages/twenty-website-new/src/sections/HeroStepper/types/HeroStepperContentProps.ts deleted file mode 100644 index 3b3de16e86b..00000000000 --- a/packages/twenty-website-new/src/sections/HeroStepper/types/HeroStepperContentProps.ts +++ /dev/null @@ -1,8 +0,0 @@ -import type { HeroStepperStepType } from '@/sections/HeroStepper/types/HeroStepperStep'; - -export type HeroStepperContentProps = { - activeImageIndex: number; - activeStepIndex: number; - onActiveStepChange: (index: number) => void; - steps: HeroStepperStepType[]; -}; diff --git a/packages/twenty-website-new/src/sections/HeroStepper/types/HeroStepperData.ts b/packages/twenty-website-new/src/sections/HeroStepper/types/HeroStepperData.ts deleted file mode 100644 index 16258eb93da..00000000000 --- a/packages/twenty-website-new/src/sections/HeroStepper/types/HeroStepperData.ts +++ /dev/null @@ -1,5 +0,0 @@ -import type { HeroStepperStepType } from '@/sections/HeroStepper/types/HeroStepperStep'; - -export type HeroStepperDataType = { - steps: HeroStepperStepType[]; -}; diff --git a/packages/twenty-website-new/src/sections/HeroStepper/types/HeroStepperVisualProps.ts b/packages/twenty-website-new/src/sections/HeroStepper/types/HeroStepperVisualProps.ts deleted file mode 100644 index d6318208162..00000000000 --- a/packages/twenty-website-new/src/sections/HeroStepper/types/HeroStepperVisualProps.ts +++ /dev/null @@ -1,6 +0,0 @@ -import type { ImageType } from '@/design-system/components/Image/types/Image'; - -export type HeroStepperVisualProps = { - activeImageIndex?: number; - images: ImageType[]; -}; diff --git a/packages/twenty-website-new/src/sections/HeroStepper/types/index.ts b/packages/twenty-website-new/src/sections/HeroStepper/types/index.ts deleted file mode 100644 index 2069f4d6d26..00000000000 --- a/packages/twenty-website-new/src/sections/HeroStepper/types/index.ts +++ /dev/null @@ -1,4 +0,0 @@ -export type { HeroStepperContentProps } from './HeroStepperContentProps'; -export type { HeroStepperDataType } from './HeroStepperData'; -export type { HeroStepperStepType } from './HeroStepperStep'; -export type { HeroStepperVisualProps } from './HeroStepperVisualProps'; diff --git a/packages/twenty-website-new/src/sections/HomeStepper/components/Flow/Flow.tsx b/packages/twenty-website-new/src/sections/HomeStepper/components/Flow/Flow.tsx new file mode 100644 index 00000000000..f4fb37ffb0b --- /dev/null +++ b/packages/twenty-website-new/src/sections/HomeStepper/components/Flow/Flow.tsx @@ -0,0 +1,36 @@ +'use client'; + +import type { HomeStepperStepType } from '@/sections/HomeStepper/types/HomeStepperStep'; +import { useState, type RefObject } from 'react'; +import { SyncScrollProgressFromContainerEffect } from '../../effect-components/SyncScrollProgressFromContainerEffect'; +import { LeftColumn } from '../LeftColumn/LeftColumn'; +import { RightColumn } from '../RightColumn/RightColumn'; +import { Visual } from '../Visual/Visual'; + +type FlowProps = { + scrollContainerRef: RefObject; + steps: HomeStepperStepType[]; +}; + +export function Flow({ scrollContainerRef, steps }: FlowProps) { + const [activeStepIndex, setActiveStepIndex] = useState(0); + const [scrollProgress, setScrollProgress] = useState(0); + + return ( + <> + + + + + + + ); +} diff --git a/packages/twenty-website-new/src/sections/HomeStepper/components/LeftColumn/LeftColumn.tsx b/packages/twenty-website-new/src/sections/HomeStepper/components/LeftColumn/LeftColumn.tsx new file mode 100644 index 00000000000..f85f83e83bf --- /dev/null +++ b/packages/twenty-website-new/src/sections/HomeStepper/components/LeftColumn/LeftColumn.tsx @@ -0,0 +1,95 @@ +'use client'; + +import { Body, Heading } from '@/design-system/components'; +import { theme } from '@/theme'; +import { styled } from '@linaria/react'; +import { useRef } from 'react'; +import { ObserveActiveStepFromIntersectionEffect } from '../../effect-components/ObserveActiveStepFromIntersectionEffect'; +import type { HomeStepperStepType } from '../../types/HomeStepperStep'; +import { ProgressBar } from '../ProgressBar/ProgressBar'; + +const LeftColumnRoot = styled.div` + display: grid; + grid-template-columns: auto 1fr; + gap: ${theme.spacing(6)}; + min-width: 0; + + @media (min-width: ${theme.breakpoints.md}px) { + gap: ${theme.spacing(10)}; + } +`; + +const StepsColumn = styled.div` + display: grid; + grid-template-columns: 1fr; + min-width: 0; + + @media (min-width: ${theme.breakpoints.md}px) { + max-width: 454px; + } +`; + +const StepBlock = styled.div` + align-content: center; + display: grid; + grid-template-columns: 1fr; + min-height: 80vh; + opacity: 0.3; + row-gap: ${theme.spacing(4)}; + transition: opacity 0.4s ease; + + @media (min-width: ${theme.breakpoints.md}px) { + min-height: 100vh; + row-gap: ${theme.spacing(6)}; + } + + &[data-active='true'] { + opacity: 1; + } +`; + +export type HomeStepperLeftColumnProps = { + activeStepIndex: number; + onActiveStepChange: (index: number) => void; + scrollProgress: number; + steps: HomeStepperStepType[]; +}; + +export function LeftColumn({ + activeStepIndex, + onActiveStepChange, + scrollProgress, + steps, +}: HomeStepperLeftColumnProps) { + const stepRefs = useRef<(HTMLDivElement | null)[]>([]); + + return ( + + + + + {steps.map((step, index) => ( + { + stepRefs.current[index] = element; + }} + > + + + + ))} + + + ); +} diff --git a/packages/twenty-website-new/src/sections/HomeStepper/components/ProgressBar/ProgressBar.tsx b/packages/twenty-website-new/src/sections/HomeStepper/components/ProgressBar/ProgressBar.tsx new file mode 100644 index 00000000000..d116883650a --- /dev/null +++ b/packages/twenty-website-new/src/sections/HomeStepper/components/ProgressBar/ProgressBar.tsx @@ -0,0 +1,125 @@ +import { theme } from '@/theme'; +import { styled } from '@linaria/react'; +import type { HomeStepperStepType } from '../../types/HomeStepperStep'; + +const ProgressBarContainer = styled.div` + display: none; + + @media (min-width: ${theme.breakpoints.md}px) { + align-items: flex-start; + align-self: stretch; + display: flex; + flex-direction: column; + min-height: 0; + } +`; + +const StickyViewportCenter = styled.div` + align-items: center; + display: flex; + flex-shrink: 0; + height: 100vh; + justify-content: flex-start; + max-height: 100vh; + position: sticky; + top: 0; +`; + +const ProgressRail = styled.div` + align-items: flex-start; + display: flex; + flex-direction: column; + gap: ${theme.spacing(1)}; +`; + +const StepIndicatorRow = styled.div` + align-items: flex-start; + display: flex; + gap: ${theme.spacing(3)}; + height: 80px; +`; + +const PillBackground = styled.div` + background-color: ${theme.colors.primary.border[20]}; + border-radius: ${theme.radius(8)}; + display: flex; + height: 100%; + overflow: hidden; + width: ${theme.spacing(1)}; +`; + +const PillFill = styled.div` + background-color: ${theme.colors.highlight[100]}; + border-radius: ${theme.radius(8)}; + transition: height 0.4s ease; + width: 100%; +`; + +const ActiveLabel = styled.p` + color: ${theme.colors.highlight[100]}; + font-family: ${theme.font.family.mono}; + font-size: ${theme.font.size(3)}; + font-weight: ${theme.font.weight.medium}; + line-height: 16px; + margin: 0; + margin-top: -2px; + text-transform: uppercase; +`; + +const InactiveDotWrapper = styled.div` + align-items: center; + display: flex; + height: 16px; + justify-content: center; + width: ${theme.spacing(1)}; +`; + +const InactiveDot = styled.div` + background-color: ${theme.colors.primary.border[20]}; + border-radius: 50%; + height: ${theme.spacing(1)}; + width: ${theme.spacing(1)}; +`; + +type ProgressBarProps = { + activeStepIndex: number; + scrollProgress: number; + steps: HomeStepperStepType[]; +}; + +export function ProgressBar({ + activeStepIndex, + scrollProgress, + steps, +}: ProgressBarProps) { + const stepCount = steps.length; + + const localProgress = Math.min( + 1, + Math.max(0, scrollProgress * stepCount - activeStepIndex), + ); + const fillPercentage = localProgress * 100; + + return ( + + + + {steps.map((_, index) => + index === activeStepIndex ? ( + + + + + {String(index + 1).padStart(2, '0')} + + ) : ( + + + + ), + )} + + + + ); +} diff --git a/packages/twenty-website-new/src/sections/HomeStepper/components/RightColumn/RightColumn.tsx b/packages/twenty-website-new/src/sections/HomeStepper/components/RightColumn/RightColumn.tsx new file mode 100644 index 00000000000..3800e8e3960 --- /dev/null +++ b/packages/twenty-website-new/src/sections/HomeStepper/components/RightColumn/RightColumn.tsx @@ -0,0 +1,22 @@ +import { theme } from '@/theme'; +import { styled } from '@linaria/react'; +import type { ReactNode } from 'react'; + +const StyledRightColumn = styled.div` + min-width: 0; + width: 100%; + + @media (min-width: ${theme.breakpoints.md}px) { + max-width: 672px; + position: sticky; + top: ${theme.spacing(10)}; + } +`; + +type RightColumnProps = { + children: ReactNode; +}; + +export function RightColumn({ children }: RightColumnProps) { + return {children}; +} diff --git a/packages/twenty-website-new/src/sections/HeroStepper/components/Root/Root.tsx b/packages/twenty-website-new/src/sections/HomeStepper/components/Root/Root.tsx similarity index 71% rename from packages/twenty-website-new/src/sections/HeroStepper/components/Root/Root.tsx rename to packages/twenty-website-new/src/sections/HomeStepper/components/Root/Root.tsx index 462f41a4e20..4067dca83fa 100644 --- a/packages/twenty-website-new/src/sections/HeroStepper/components/Root/Root.tsx +++ b/packages/twenty-website-new/src/sections/HomeStepper/components/Root/Root.tsx @@ -1,14 +1,16 @@ +'use client'; + import { Container } from '@/design-system/components'; import { theme } from '@/theme'; import { styled } from '@linaria/react'; -import type { ReactNode } from 'react'; +import type { ReactNode, RefObject } from 'react'; const StyledSection = styled.section` background-color: ${theme.colors.primary.text[5]}; width: 100%; `; -const Grid = styled(Container)` +const StyledContainer = styled(Container)` display: grid; grid-template-columns: 1fr; min-width: 0; @@ -31,12 +33,15 @@ const Grid = styled(Container)` } `; -type RootProps = { children: ReactNode }; +type RootProps = { + children: ReactNode; + scrollContainerRef?: RefObject; +}; -export function Root({ children }: RootProps) { +export function Root({ children, scrollContainerRef }: RootProps) { return ( - - {children} + + {children} ); } diff --git a/packages/twenty-website-new/src/sections/HomeStepper/components/ScrollSection/ScrollSection.tsx b/packages/twenty-website-new/src/sections/HomeStepper/components/ScrollSection/ScrollSection.tsx new file mode 100644 index 00000000000..68cdee8425e --- /dev/null +++ b/packages/twenty-website-new/src/sections/HomeStepper/components/ScrollSection/ScrollSection.tsx @@ -0,0 +1,20 @@ +'use client'; + +import type { HomeStepperStepType } from '@/sections/HomeStepper/types/HomeStepperStep'; +import { useRef } from 'react'; +import { Flow } from '../Flow/Flow'; +import { Root } from '../Root/Root'; + +type ScrollSectionProps = { + steps: HomeStepperStepType[]; +}; + +export function ScrollSection({ steps }: ScrollSectionProps) { + const scrollContainerRef = useRef(null); + + return ( + + + + ); +} diff --git a/packages/twenty-website-new/src/sections/HeroStepper/components/StepperVisualFrame/StepperVisualFrame.tsx b/packages/twenty-website-new/src/sections/HomeStepper/components/StepperVisualFrame/StepperVisualFrame.tsx similarity index 98% rename from packages/twenty-website-new/src/sections/HeroStepper/components/StepperVisualFrame/StepperVisualFrame.tsx rename to packages/twenty-website-new/src/sections/HomeStepper/components/StepperVisualFrame/StepperVisualFrame.tsx index 8d8481a9428..ae0214e4ab6 100644 --- a/packages/twenty-website-new/src/sections/HeroStepper/components/StepperVisualFrame/StepperVisualFrame.tsx +++ b/packages/twenty-website-new/src/sections/HomeStepper/components/StepperVisualFrame/StepperVisualFrame.tsx @@ -44,7 +44,7 @@ const shapeImageClassName = css` type StepperVisualFrameProps = { backgroundSrc: string; - children: ReactNode; + children?: ReactNode; shapeSrc: string; }; diff --git a/packages/twenty-website-new/src/sections/HomeStepper/components/Visual/Visual.tsx b/packages/twenty-website-new/src/sections/HomeStepper/components/Visual/Visual.tsx new file mode 100644 index 00000000000..3484954c9fa --- /dev/null +++ b/packages/twenty-website-new/src/sections/HomeStepper/components/Visual/Visual.tsx @@ -0,0 +1,15 @@ +'use client'; + +import { StepperVisualFrame } from '../StepperVisualFrame/StepperVisualFrame'; + +const HOME_STEPPER_BACKGROUND = '/images/home/stepper/background.png'; +const HOME_STEPPER_SHAPE = '/images/home/stepper/background-shape.png'; + +export function Visual() { + return ( + + ); +} diff --git a/packages/twenty-website-new/src/sections/HomeStepper/components/index.ts b/packages/twenty-website-new/src/sections/HomeStepper/components/index.ts new file mode 100644 index 00000000000..fb980ecba40 --- /dev/null +++ b/packages/twenty-website-new/src/sections/HomeStepper/components/index.ts @@ -0,0 +1,15 @@ +import { Flow } from './Flow/Flow'; +import { LeftColumn } from './LeftColumn/LeftColumn'; +import { RightColumn } from './RightColumn/RightColumn'; +import { Root } from './Root/Root'; +import { ScrollSection } from './ScrollSection/ScrollSection'; +import { Visual } from './Visual/Visual'; + +export const HomeStepper = { + Flow, + LeftColumn, + RightColumn, + Root, + ScrollSection, + Visual, +}; diff --git a/packages/twenty-website-new/src/sections/HomeStepper/effect-components/ObserveActiveStepFromIntersectionEffect.tsx b/packages/twenty-website-new/src/sections/HomeStepper/effect-components/ObserveActiveStepFromIntersectionEffect.tsx new file mode 100644 index 00000000000..6320c58dff5 --- /dev/null +++ b/packages/twenty-website-new/src/sections/HomeStepper/effect-components/ObserveActiveStepFromIntersectionEffect.tsx @@ -0,0 +1,55 @@ +'use client'; + +import { useEffect, type RefObject } from 'react'; + +type ObserveActiveStepFromIntersectionEffectProps = { + onActiveStepChange: (index: number) => void; + stepRefs: RefObject<(HTMLDivElement | null)[]>; + stepsLength: number; +}; + +export function ObserveActiveStepFromIntersectionEffect({ + onActiveStepChange, + stepRefs, + stepsLength, +}: ObserveActiveStepFromIntersectionEffectProps) { + useEffect(() => { + stepRefs.current = stepRefs.current.slice(0, stepsLength); + + const elements = stepRefs.current.filter( + (element): element is HTMLDivElement => element !== null, + ); + if (elements.length === 0) { + return; + } + + const observer = new IntersectionObserver( + (entries) => { + const candidates = entries.filter( + (entry) => entry.isIntersecting && entry.intersectionRatio > 0.15, + ); + if (candidates.length === 0) { + return; + } + + const best = candidates.reduce((previous, current) => + current.intersectionRatio > previous.intersectionRatio + ? current + : previous, + ); + const indexAttribute = best.target.getAttribute('data-step-index'); + const index = indexAttribute === null ? NaN : Number(indexAttribute); + if (!Number.isNaN(index)) { + onActiveStepChange(index); + } + }, + { root: null, threshold: [0, 0.15, 0.3, 0.5, 0.75, 1] }, + ); + + elements.forEach((element) => observer.observe(element)); + + return () => observer.disconnect(); + }, [onActiveStepChange, stepRefs, stepsLength]); + + return null; +} diff --git a/packages/twenty-website-new/src/sections/HomeStepper/effect-components/SyncScrollProgressFromContainerEffect.tsx b/packages/twenty-website-new/src/sections/HomeStepper/effect-components/SyncScrollProgressFromContainerEffect.tsx new file mode 100644 index 00000000000..4dc81b6b422 --- /dev/null +++ b/packages/twenty-website-new/src/sections/HomeStepper/effect-components/SyncScrollProgressFromContainerEffect.tsx @@ -0,0 +1,41 @@ +'use client'; + +import { useEffect, type RefObject } from 'react'; + +type SyncScrollProgressFromContainerEffectProps = { + onScrollProgress: (progress: number) => void; + scrollContainerRef: RefObject; +}; + +export function SyncScrollProgressFromContainerEffect({ + onScrollProgress, + scrollContainerRef, +}: SyncScrollProgressFromContainerEffectProps) { + useEffect(() => { + const handleScroll = () => { + const element = scrollContainerRef.current; + if (!element) { + return; + } + const rect = element.getBoundingClientRect(); + const windowHeight = window.innerHeight; + const scrollableDistance = rect.height - windowHeight; + if (scrollableDistance <= 0) { + return; + } + + const progress = Math.max(0, Math.min(1, -rect.top / scrollableDistance)); + onScrollProgress(progress); + }; + + handleScroll(); + window.addEventListener('scroll', handleScroll, { passive: true }); + window.addEventListener('resize', handleScroll); + return () => { + window.removeEventListener('scroll', handleScroll); + window.removeEventListener('resize', handleScroll); + }; + }, [onScrollProgress, scrollContainerRef]); + + return null; +} diff --git a/packages/twenty-website-new/src/sections/HomeStepper/types/HomeStepperData.ts b/packages/twenty-website-new/src/sections/HomeStepper/types/HomeStepperData.ts new file mode 100644 index 00000000000..7986a031a7f --- /dev/null +++ b/packages/twenty-website-new/src/sections/HomeStepper/types/HomeStepperData.ts @@ -0,0 +1,5 @@ +import type { HomeStepperStepType } from '@/sections/HomeStepper/types/HomeStepperStep'; + +export type HomeStepperDataType = { + steps: HomeStepperStepType[]; +}; diff --git a/packages/twenty-website-new/src/sections/HeroStepper/types/HeroStepperStep.ts b/packages/twenty-website-new/src/sections/HomeStepper/types/HomeStepperStep.ts similarity index 60% rename from packages/twenty-website-new/src/sections/HeroStepper/types/HeroStepperStep.ts rename to packages/twenty-website-new/src/sections/HomeStepper/types/HomeStepperStep.ts index cd2c64d6cb5..8c590dc3d4e 100644 --- a/packages/twenty-website-new/src/sections/HeroStepper/types/HeroStepperStep.ts +++ b/packages/twenty-website-new/src/sections/HomeStepper/types/HomeStepperStep.ts @@ -1,9 +1,7 @@ import type { BodyType } from '@/design-system/components/Body/types/Body'; import type { HeadingType } from '@/design-system/components/Heading/types/Heading'; -import type { ImageType } from '@/design-system/components/Image/types/Image'; -export type HeroStepperStepType = { +export type HomeStepperStepType = { body: BodyType; heading: HeadingType[]; - images: ImageType[]; }; diff --git a/packages/twenty-website-new/src/sections/HomeStepper/types/index.ts b/packages/twenty-website-new/src/sections/HomeStepper/types/index.ts new file mode 100644 index 00000000000..7a81adbfe2b --- /dev/null +++ b/packages/twenty-website-new/src/sections/HomeStepper/types/index.ts @@ -0,0 +1,2 @@ +export type { HomeStepperDataType } from './HomeStepperData'; +export type { HomeStepperStepType } from './HomeStepperStep'; diff --git a/packages/twenty-website-new/src/sections/Quote/components/Heading/Heading.tsx b/packages/twenty-website-new/src/sections/Quote/components/Heading/Heading.tsx new file mode 100644 index 00000000000..39619d6ead5 --- /dev/null +++ b/packages/twenty-website-new/src/sections/Quote/components/Heading/Heading.tsx @@ -0,0 +1,28 @@ +import { Heading as BaseHeading } from '@/design-system/components/Heading/Heading'; +import type { HeadingType } from '@/design-system/components/Heading/types/Heading'; +import { theme } from '@/theme'; +import { styled } from '@linaria/react'; + +const HeadingWrapper = styled.div` + color: ${theme.colors.secondary.text[100]}; + max-width: 100%; + min-width: 0; + white-space: pre-line; + width: 100%; + + @media (min-width: ${theme.breakpoints.md}px) { + max-width: 517px; + } +`; + +type QuoteHeadingProps = { + segments: HeadingType[]; +}; + +export function Heading({ segments }: QuoteHeadingProps) { + return ( + + + + ); +} diff --git a/packages/twenty-website-new/src/sections/Quote/components/Root/Root.tsx b/packages/twenty-website-new/src/sections/Quote/components/Root/Root.tsx new file mode 100644 index 00000000000..8d499464565 --- /dev/null +++ b/packages/twenty-website-new/src/sections/Quote/components/Root/Root.tsx @@ -0,0 +1,46 @@ +import { Container } from '@/design-system/components'; +import { theme } from '@/theme'; +import { styled } from '@linaria/react'; +import type { ReactNode } from 'react'; + +const StyledSection = styled.section` + min-width: 0; + width: 100%; +`; + +const StyledContainer = styled(Container)` + column-gap: ${theme.spacing(6)}; + display: grid; + grid-template-columns: minmax(0, 1fr); + justify-items: stretch; + padding-bottom: ${theme.spacing(12)}; + padding-left: ${theme.spacing(4)}; + padding-right: ${theme.spacing(4)}; + padding-top: ${theme.spacing(12)}; + row-gap: ${theme.spacing(10)}; + + @media (min-width: ${theme.breakpoints.md}px) { + align-items: center; + column-gap: ${theme.spacing(8)}; + grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); + justify-items: start; + padding-bottom: ${theme.spacing(14)}; + padding-left: ${theme.spacing(10)}; + padding-right: ${theme.spacing(10)}; + padding-top: ${theme.spacing(14)}; + row-gap: ${theme.spacing(8)}; + } +`; + +type RootProps = { + backgroundColor: string; + children: ReactNode; +}; + +export function Root({ backgroundColor, children }: RootProps) { + return ( + + {children} + + ); +} diff --git a/packages/twenty-website-new/src/sections/Quote/components/Visual/Visual.tsx b/packages/twenty-website-new/src/sections/Quote/components/Visual/Visual.tsx new file mode 100644 index 00000000000..3fb5bf9b8e3 --- /dev/null +++ b/packages/twenty-website-new/src/sections/Quote/components/Visual/Visual.tsx @@ -0,0 +1,56 @@ +import type { IllustrationType } from '@/design-system/components/Illustration/types/Illustration'; +import { theme } from '@/theme'; +import { styled } from '@linaria/react'; + +const VisualContainer = styled.div` + background-color: ${theme.colors.secondary.background[100]}; + border-radius: ${theme.radius(1)}; + height: min(544px, 70vw); + min-height: ${theme.spacing(80)}; + overflow: hidden; + position: relative; + width: 100%; + + @media (min-width: ${theme.breakpoints.md}px) { + height: 544px; + max-width: 646px; + } +`; + +const StyledIframe = styled.iframe` + border: none; + height: 200%; + left: 51.5%; + mix-blend-mode: lighten; + position: absolute; + top: 50%; + transform: translate(-50%, -50%); + width: 200%; +`; + +const HueOverlay = styled.div` + background-color: ${theme.colors.highlight[100]}; + inset: 0; + mix-blend-mode: hue; + pointer-events: none; + position: absolute; +`; + +type VisualProps = { + illustration: IllustrationType; +}; + +export function Visual({ illustration }: VisualProps) { + return ( + + + + ); +} diff --git a/packages/twenty-website-new/src/sections/Quote/components/index.ts b/packages/twenty-website-new/src/sections/Quote/components/index.ts new file mode 100644 index 00000000000..9873d3110af --- /dev/null +++ b/packages/twenty-website-new/src/sections/Quote/components/index.ts @@ -0,0 +1,5 @@ +import { Heading } from './Heading/Heading'; +import { Root } from './Root/Root'; +import { Visual } from './Visual/Visual'; + +export const Quote = { Heading, Root, Visual }; diff --git a/packages/twenty-website-new/src/sections/Quote/types/QuoteData.ts b/packages/twenty-website-new/src/sections/Quote/types/QuoteData.ts new file mode 100644 index 00000000000..16b4bb7bb13 --- /dev/null +++ b/packages/twenty-website-new/src/sections/Quote/types/QuoteData.ts @@ -0,0 +1,7 @@ +import type { HeadingType } from '@/design-system/components/Heading/types/Heading'; +import type { IllustrationType } from '@/design-system/components/Illustration/types/Illustration'; + +export type QuoteDataType = { + illustration: IllustrationType; + heading: HeadingType[]; +}; diff --git a/packages/twenty-website-new/src/sections/Quote/types/index.ts b/packages/twenty-website-new/src/sections/Quote/types/index.ts new file mode 100644 index 00000000000..cbcfc4af84f --- /dev/null +++ b/packages/twenty-website-new/src/sections/Quote/types/index.ts @@ -0,0 +1 @@ +export type { QuoteDataType } from './QuoteData'; diff --git a/packages/twenty-website-new/src/sections/Statement/components/Decoration/Decoration.tsx b/packages/twenty-website-new/src/sections/Statement/components/Decoration/Decoration.tsx new file mode 100644 index 00000000000..980bbdcfda5 --- /dev/null +++ b/packages/twenty-website-new/src/sections/Statement/components/Decoration/Decoration.tsx @@ -0,0 +1,28 @@ +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