📄 Add Commercial License for ee folder (#1532)
This commit is contained in:
@ -0,0 +1,64 @@
|
||||
import { Flex, Stack, Heading, Box, Text, Button } from '@chakra-ui/react'
|
||||
import React from 'react'
|
||||
import Image from 'next/image'
|
||||
import builderDndSrc from 'public/images/builder-dnd.png'
|
||||
import { ArrowRight } from 'assets/icons/ArrowRight'
|
||||
import { Flare } from 'assets/illustrations/Flare'
|
||||
import Link from 'next/link'
|
||||
|
||||
export const EasyBuildingExperience = () => {
|
||||
return (
|
||||
<Flex as="section" justify="center" pos="relative">
|
||||
<Flare
|
||||
color="blue"
|
||||
pos="absolute"
|
||||
left="-200px"
|
||||
top="-50px"
|
||||
data-aos="fade"
|
||||
data-aos-delay="500"
|
||||
/>
|
||||
<Stack
|
||||
style={{ maxWidth: '1000px' }}
|
||||
pt={'52'}
|
||||
w="full"
|
||||
px="4"
|
||||
spacing={12}
|
||||
direction={['column', 'row-reverse']}
|
||||
justifyContent="space-between"
|
||||
alignItems="center"
|
||||
>
|
||||
<Stack spacing="6" maxW="300px" minW={[0, '300px']}>
|
||||
<Heading as="h1" data-aos="fade">
|
||||
Easy building experience
|
||||
</Heading>
|
||||
<Text
|
||||
color="gray.400"
|
||||
fontSize={{ base: 'lg', xl: 'xl' }}
|
||||
data-aos="fade"
|
||||
>
|
||||
All you have to do is drag and drop blocks to create your app. Even
|
||||
if you have custom needs, you can always add custom code.
|
||||
</Text>
|
||||
<Flex>
|
||||
<Button
|
||||
as={Link}
|
||||
rightIcon={<ArrowRight />}
|
||||
href={`https://app.typebot.io/register`}
|
||||
variant="ghost"
|
||||
data-aos="fade"
|
||||
>
|
||||
Try it now
|
||||
</Button>
|
||||
</Flex>
|
||||
</Stack>
|
||||
<Box rounded="md" data-aos="fade">
|
||||
<Image
|
||||
src={builderDndSrc}
|
||||
alt="incomplete results illustration"
|
||||
placeholder="blur"
|
||||
/>
|
||||
</Box>
|
||||
</Stack>
|
||||
</Flex>
|
||||
)
|
||||
}
|
65
ee/apps/landing-page/components/Homepage/EasyEmbed.tsx
Normal file
65
ee/apps/landing-page/components/Homepage/EasyEmbed.tsx
Normal file
@ -0,0 +1,65 @@
|
||||
import { Flex, Stack, Heading, Box, Text, Button } from '@chakra-ui/react'
|
||||
import React from 'react'
|
||||
import Image from 'next/image'
|
||||
import nativeFeelingSrc from 'public/images/native-feeling.png'
|
||||
import { ArrowRight } from 'assets/icons/ArrowRight'
|
||||
import { Flare } from 'assets/illustrations/Flare'
|
||||
import Link from 'next/link'
|
||||
|
||||
export const EasyEmbed = () => {
|
||||
return (
|
||||
<Flex as="section" justify="center" pos="relative">
|
||||
<Flare
|
||||
color="orange"
|
||||
pos="absolute"
|
||||
right="-200px"
|
||||
top="100px"
|
||||
data-aos="fade"
|
||||
data-aos-delay="500"
|
||||
/>
|
||||
<Stack
|
||||
style={{ maxWidth: '1000px' }}
|
||||
pt={32}
|
||||
w="full"
|
||||
px="4"
|
||||
spacing={12}
|
||||
direction={['column', 'row']}
|
||||
justifyContent="space-between"
|
||||
alignItems="center"
|
||||
>
|
||||
<Stack spacing="6" maxW="300px" minW={[0, '300px']}>
|
||||
<Heading as="h1" data-aos="fade">
|
||||
Embed it in a click
|
||||
</Heading>
|
||||
<Text
|
||||
color="gray.400"
|
||||
fontSize={{ base: 'lg', xl: 'xl' }}
|
||||
data-aos="fade"
|
||||
>
|
||||
Embedding your typebot in your applications is a walk in the park.
|
||||
Typebot gives you several step-by-step platform-specific
|
||||
instructions. Your typebot will always feel "native".
|
||||
</Text>
|
||||
<Flex data-aos="fade">
|
||||
<Button
|
||||
as={Link}
|
||||
rightIcon={<ArrowRight />}
|
||||
href={`https://app.typebot.io/register`}
|
||||
variant="ghost"
|
||||
colorScheme="orange"
|
||||
>
|
||||
Try it now
|
||||
</Button>
|
||||
</Flex>
|
||||
</Stack>
|
||||
<Box rounded="md" data-aos="fade">
|
||||
<Image
|
||||
src={nativeFeelingSrc}
|
||||
alt="incomplete results illustration"
|
||||
placeholder="blur"
|
||||
/>
|
||||
</Box>
|
||||
</Stack>
|
||||
</Flex>
|
||||
)
|
||||
}
|
69
ee/apps/landing-page/components/Homepage/EndCta.tsx
Normal file
69
ee/apps/landing-page/components/Homepage/EndCta.tsx
Normal file
@ -0,0 +1,69 @@
|
||||
'use client'
|
||||
|
||||
import {
|
||||
Heading,
|
||||
Button,
|
||||
Text,
|
||||
Flex,
|
||||
VStack,
|
||||
StackProps,
|
||||
} from '@chakra-ui/react'
|
||||
import Link from 'next/link'
|
||||
import React from 'react'
|
||||
import { BackgroundPolygons } from './Hero/BackgroundPolygons'
|
||||
|
||||
type Props = {
|
||||
heading?: string
|
||||
polygonsBaseTop?: string
|
||||
} & StackProps
|
||||
|
||||
export const EndCta = ({ heading, polygonsBaseTop, ...props }: Props) => {
|
||||
return (
|
||||
<VStack
|
||||
as="section"
|
||||
py={32}
|
||||
pos="relative"
|
||||
bgGradient="linear(to-b, gray.900, gray.800)"
|
||||
height="100vh"
|
||||
justifyContent="center"
|
||||
{...props}
|
||||
>
|
||||
<BackgroundPolygons baseTop={polygonsBaseTop} />
|
||||
<VStack
|
||||
spacing="6"
|
||||
maxW="3xl"
|
||||
mx="auto"
|
||||
px={{ base: '6', lg: '8' }}
|
||||
py={{ base: '16', sm: '20' }}
|
||||
textAlign="center"
|
||||
>
|
||||
{heading ? (
|
||||
<Heading
|
||||
fontWeight="extrabold"
|
||||
letterSpacing="tight"
|
||||
data-aos="fade-up"
|
||||
>
|
||||
{heading}
|
||||
</Heading>
|
||||
) : null}
|
||||
<Flex>
|
||||
<Button
|
||||
as={Link}
|
||||
href="https://app.typebot.io/register"
|
||||
size="lg"
|
||||
colorScheme="orange"
|
||||
height="4rem"
|
||||
data-aos="fade-up"
|
||||
data-aos-delay="300"
|
||||
>
|
||||
Create a typebot
|
||||
</Button>
|
||||
</Flex>
|
||||
|
||||
<Text color="gray.400" data-aos="fade-up" data-aos-delay="400">
|
||||
No trial. Generous <strong>free</strong> plan.
|
||||
</Text>
|
||||
</VStack>
|
||||
</VStack>
|
||||
)
|
||||
}
|
@ -0,0 +1,46 @@
|
||||
import { IconProps, Text, Flex, VStack } from '@chakra-ui/react'
|
||||
import React, { useState } from 'react'
|
||||
|
||||
type FeatureCardProps = {
|
||||
Icon: (props: IconProps) => JSX.Element
|
||||
title: string
|
||||
content: string
|
||||
}
|
||||
|
||||
export const FeatureCard = ({ Icon, title, content }: FeatureCardProps) => {
|
||||
const [isHovered, setIsHovered] = useState(false)
|
||||
|
||||
return (
|
||||
<VStack
|
||||
p="6"
|
||||
bgColor="gray.800"
|
||||
pos="relative"
|
||||
rounded="lg"
|
||||
spacing="4"
|
||||
onMouseEnter={() => setIsHovered(true)}
|
||||
onMouseLeave={() => setIsHovered(false)}
|
||||
>
|
||||
<Flex
|
||||
boxSize="50px"
|
||||
bgColor="blue.500"
|
||||
rounded="lg"
|
||||
color="white"
|
||||
justify="center"
|
||||
align="center"
|
||||
pos="absolute"
|
||||
top="-25px"
|
||||
shadow="lg"
|
||||
transform={isHovered ? 'translateY(-5px)' : 'translateY(0px)'}
|
||||
transition="transform 300ms ease-out"
|
||||
>
|
||||
<Icon boxSize="25px" />
|
||||
</Flex>
|
||||
<Text textAlign="center" fontWeight="semibold" fontSize="lg">
|
||||
{title}
|
||||
</Text>
|
||||
<Text textAlign="center" color="gray.500">
|
||||
{content}
|
||||
</Text>
|
||||
</VStack>
|
||||
)
|
||||
}
|
@ -0,0 +1,84 @@
|
||||
import React from 'react'
|
||||
import {
|
||||
Flex,
|
||||
Heading,
|
||||
SimpleGrid,
|
||||
Stack,
|
||||
Text,
|
||||
VStack,
|
||||
} from '@chakra-ui/react'
|
||||
import { FeatureCard } from './FeatureCard'
|
||||
import { FolderIcon } from 'assets/icons/FolderIcon'
|
||||
import { AccessibilityIcon } from 'assets/icons/AccessibilityIcon'
|
||||
import { CalculatorIcon } from 'assets/icons/CaluclatorIcon'
|
||||
import { ConditionIcon } from 'assets/icons/ConditionIcon'
|
||||
import { PersonAddIcon } from 'assets/icons/PersonAddIcon'
|
||||
import { ShareIcon } from 'assets/icons/ShareIcon'
|
||||
|
||||
const features = [
|
||||
{
|
||||
Icon: AccessibilityIcon,
|
||||
title: 'Hidden fields',
|
||||
content:
|
||||
'Include data in your form URL to segment your user and use its data directly in your form.',
|
||||
},
|
||||
{
|
||||
Icon: PersonAddIcon,
|
||||
title: 'Team collaboration',
|
||||
content: 'Invite your teammates to work on your typebots with you',
|
||||
},
|
||||
{
|
||||
Icon: ConditionIcon,
|
||||
title: 'Link to sub typebots',
|
||||
content: 'Reuse your typebots in different parent bots.',
|
||||
},
|
||||
{
|
||||
Icon: CalculatorIcon,
|
||||
title: 'Custom code',
|
||||
content: 'Customize everything with your own Javascript & CSS code',
|
||||
},
|
||||
{
|
||||
Icon: ShareIcon,
|
||||
title: 'Custom domain',
|
||||
content: 'Connect your typebot to the custom URL of your choice',
|
||||
},
|
||||
{
|
||||
Icon: FolderIcon,
|
||||
title: 'Folder management',
|
||||
content:
|
||||
'Organize your typebots in specific folders to keep it clean and work with multiple clients',
|
||||
},
|
||||
]
|
||||
|
||||
export const Features = () => {
|
||||
return (
|
||||
<Flex justifyContent="center">
|
||||
<Stack
|
||||
style={{ maxWidth: '1200px' }}
|
||||
pt={'52'}
|
||||
w="full"
|
||||
px="4"
|
||||
spacing={12}
|
||||
>
|
||||
<VStack>
|
||||
<Heading as="h1" textAlign="center" data-aos="fade">
|
||||
And many more features
|
||||
</Heading>
|
||||
<Text
|
||||
color="gray.500"
|
||||
fontSize={['lg', 'xl']}
|
||||
textAlign="center"
|
||||
data-aos="fade"
|
||||
>
|
||||
Typebot makes form building easy and comes with powerful features
|
||||
</Text>
|
||||
</VStack>
|
||||
<SimpleGrid columns={[1, 3]} spacing="10" pt="10" data-aos="fade">
|
||||
{features.map((feature, idx) => (
|
||||
<FeatureCard key={idx} {...feature} />
|
||||
))}
|
||||
</SimpleGrid>
|
||||
</Stack>
|
||||
</Flex>
|
||||
)
|
||||
}
|
@ -0,0 +1 @@
|
||||
export { Features } from './Features'
|
File diff suppressed because one or more lines are too long
888
ee/apps/landing-page/components/Homepage/Hero/Brands.tsx
Executable file
888
ee/apps/landing-page/components/Homepage/Hero/Brands.tsx
Executable file
File diff suppressed because one or more lines are too long
133
ee/apps/landing-page/components/Homepage/Hero/Hero.tsx
Executable file
133
ee/apps/landing-page/components/Homepage/Hero/Hero.tsx
Executable file
@ -0,0 +1,133 @@
|
||||
import {
|
||||
Box,
|
||||
Button,
|
||||
Flex,
|
||||
Heading,
|
||||
SimpleGrid,
|
||||
Stack,
|
||||
Text,
|
||||
VStack,
|
||||
} from '@chakra-ui/react'
|
||||
import * as React from 'react'
|
||||
import { Header } from '../../common/Header/Header'
|
||||
import { BackgroundPolygons } from './BackgroundPolygons'
|
||||
import * as Logos from './Brands'
|
||||
import Link from 'next/link'
|
||||
import Image from 'next/image'
|
||||
import builderScreenshotSrc from 'public/images/builder-screenshot.png'
|
||||
|
||||
export const Hero = () => {
|
||||
return (
|
||||
<Box as="section" overflow="hidden">
|
||||
<Header />
|
||||
<Stack mx="auto" py="10" pos="relative" pb="32" px={[4, 0]}>
|
||||
<BackgroundPolygons />
|
||||
<VStack mb="20" spacing={20} alignItems="center">
|
||||
<VStack pt={['10', '20']} spacing="6" w="full">
|
||||
<Heading
|
||||
as="h1"
|
||||
fontSize={['4xl', '4xl', '5xl', '7xl']}
|
||||
textAlign="center"
|
||||
maxW="1000px"
|
||||
bgGradient="linear(to-r, blue.300, purple.300)"
|
||||
bgClip="text"
|
||||
data-aos="fade-up"
|
||||
>
|
||||
Build advanced chatbots visually
|
||||
</Heading>
|
||||
<Text
|
||||
fontSize={['lg', 'xl']}
|
||||
maxW="800px"
|
||||
textAlign="center"
|
||||
data-aos="fade-up"
|
||||
data-aos-delay="100"
|
||||
>
|
||||
Typebot gives you powerful blocks to create unique chat
|
||||
experiences. Embed them anywhere on your web/mobile apps and start
|
||||
collecting results like magic.
|
||||
</Text>
|
||||
<Stack
|
||||
direction={['column-reverse', 'row']}
|
||||
data-aos="fade-up"
|
||||
data-aos-delay="200"
|
||||
>
|
||||
<Button
|
||||
as={Link}
|
||||
href="https://app.typebot.io/register"
|
||||
colorScheme="orange"
|
||||
size="lg"
|
||||
height="4rem"
|
||||
px="2rem"
|
||||
>
|
||||
Create a typebot for free
|
||||
</Button>
|
||||
</Stack>
|
||||
</VStack>
|
||||
<Box maxW="1200px" pos="relative">
|
||||
<Box
|
||||
pos="absolute"
|
||||
left="-40px"
|
||||
bgColor="orange.500"
|
||||
boxSize={['150px', '150px', '300px', '600px']}
|
||||
rounded="full"
|
||||
filter="blur(40px)"
|
||||
opacity="0.7"
|
||||
className="animated-blob"
|
||||
data-aos="fade"
|
||||
data-aos-delay="1200"
|
||||
/>
|
||||
<Box
|
||||
pos="absolute"
|
||||
right="-40px"
|
||||
bgColor="blue.500"
|
||||
boxSize={['150px', '150px', '300px', '600px']}
|
||||
rounded="full"
|
||||
filter="blur(40px)"
|
||||
opacity="0.7"
|
||||
className="animated-blob animation-delay-5000"
|
||||
data-aos="fade"
|
||||
data-aos-delay="1200"
|
||||
/>
|
||||
<Box
|
||||
as="figure"
|
||||
shadow="lg"
|
||||
data-aos="zoom-out-up"
|
||||
data-aos-delay="800"
|
||||
>
|
||||
<Image
|
||||
src={builderScreenshotSrc}
|
||||
alt="Builder screenshot"
|
||||
placeholder="blur"
|
||||
style={{ borderRadius: '10px' }}
|
||||
/>
|
||||
</Box>
|
||||
</Box>
|
||||
</VStack>
|
||||
</Stack>
|
||||
<Flex justify="center" bgGradient="linear(to-b, gray.900, gray.800)">
|
||||
<VStack spacing="12" pb="32" maxW="7xl" px={4}>
|
||||
<Heading fontSize="25px" fontWeight="semibold" data-aos="fade">
|
||||
Loved by teams and creators from all around the world
|
||||
</Heading>
|
||||
<SimpleGrid
|
||||
columns={{ base: 2, md: 4 }}
|
||||
color="gray.400"
|
||||
alignItems="center"
|
||||
spacing={12}
|
||||
fontSize="4xl"
|
||||
data-aos="fade"
|
||||
>
|
||||
<Logos.IbanFirst />
|
||||
<Logos.Lemlist />
|
||||
<Logos.MakerLead />
|
||||
<Logos.Webisharp />
|
||||
<Logos.SocialHackrs />
|
||||
<Logos.PinpointInteractive />
|
||||
<Logos.Obole />
|
||||
<Logos.Awwwsome />
|
||||
</SimpleGrid>
|
||||
</VStack>
|
||||
</Flex>
|
||||
</Box>
|
||||
)
|
||||
}
|
1
ee/apps/landing-page/components/Homepage/Hero/index.tsx
Normal file
1
ee/apps/landing-page/components/Homepage/Hero/index.tsx
Normal file
@ -0,0 +1 @@
|
||||
export { Hero } from './Hero'
|
121
ee/apps/landing-page/components/Homepage/Integrations.tsx
Normal file
121
ee/apps/landing-page/components/Homepage/Integrations.tsx
Normal file
@ -0,0 +1,121 @@
|
||||
import { Flex, Heading, HStack, Stack, Text } from '@chakra-ui/react'
|
||||
import {
|
||||
GmailLogo,
|
||||
MailChimpLogo,
|
||||
NotionLogo,
|
||||
WebflowLogo,
|
||||
WordpressLogo,
|
||||
SlackLogo,
|
||||
AirtableLogo,
|
||||
GoogleSheetLogo,
|
||||
ZapierLogo,
|
||||
SalesforceLogo,
|
||||
CalendlyLogo,
|
||||
GoogleCalendarLogo,
|
||||
ShopifyLogo,
|
||||
GoogleDriveLogo,
|
||||
N8nLogo,
|
||||
} from 'assets/logos'
|
||||
import React from 'react'
|
||||
|
||||
const firstRowIcons = [
|
||||
GmailLogo,
|
||||
MailChimpLogo,
|
||||
NotionLogo,
|
||||
WebflowLogo,
|
||||
WordpressLogo,
|
||||
GoogleCalendarLogo,
|
||||
N8nLogo,
|
||||
GoogleDriveLogo,
|
||||
]
|
||||
const secondRowIcons = [
|
||||
SlackLogo,
|
||||
ShopifyLogo,
|
||||
AirtableLogo,
|
||||
GoogleSheetLogo,
|
||||
ZapierLogo,
|
||||
CalendlyLogo,
|
||||
SalesforceLogo,
|
||||
]
|
||||
|
||||
export const Integrations = () => (
|
||||
<Flex as="section" justify="center">
|
||||
<Stack w="full" align="center" spacing={12} pt={'52'}>
|
||||
<Stack pos="relative" width="1400px" spacing={[4, 12]}>
|
||||
<Flex
|
||||
pos="absolute"
|
||||
left="0"
|
||||
w="33%"
|
||||
h="full"
|
||||
bgGradient="linear(to-r, rgba(23,25,35,1), rgba(23,25,35,0))"
|
||||
pointerEvents="none"
|
||||
zIndex={100}
|
||||
/>
|
||||
<Flex
|
||||
pos="absolute"
|
||||
right="0"
|
||||
w="33%"
|
||||
h="full"
|
||||
bgGradient="linear(to-l, rgba(23,25,35,1), rgba(23,25,35,0))"
|
||||
pointerEvents="none"
|
||||
zIndex={100}
|
||||
/>
|
||||
<HStack w="full" spacing={[4, 16]}>
|
||||
{firstRowIcons.map((Icon, idx) => (
|
||||
<Flex
|
||||
_hover={{ borderColor: 'gray.500' }}
|
||||
transition="border 1s ease"
|
||||
key={idx}
|
||||
rounded="md"
|
||||
p="8"
|
||||
bgColor="gray.800"
|
||||
boxSize="120px"
|
||||
justifyContent="center"
|
||||
align="center"
|
||||
borderWidth="1px"
|
||||
data-aos="fade"
|
||||
data-aos-delay={idx * 200}
|
||||
>
|
||||
<Icon w="full" h="full" />
|
||||
</Flex>
|
||||
))}
|
||||
</HStack>
|
||||
<HStack w="full" spacing={[4, 16]} pl={['10', '20']}>
|
||||
{secondRowIcons.map((Icon, idx) => (
|
||||
<Flex
|
||||
key={idx}
|
||||
_hover={{ borderColor: 'gray.500' }}
|
||||
transition="border 1s ease"
|
||||
rounded="md"
|
||||
p="8"
|
||||
bgColor="gray.800"
|
||||
boxSize="120px"
|
||||
justifyContent="center"
|
||||
align="center"
|
||||
borderWidth="1px"
|
||||
data-aos="fade"
|
||||
data-aos-delay={(secondRowIcons.length - idx) * 200}
|
||||
>
|
||||
<Icon w="full" h="full" />
|
||||
</Flex>
|
||||
))}
|
||||
</HStack>
|
||||
</Stack>
|
||||
|
||||
<Stack w="full" maxWidth="1200px" px="4">
|
||||
<Heading fontSize={['3xl', '4xl']} data-aos="fade-up">
|
||||
Integrate with any platform
|
||||
</Heading>
|
||||
<Text
|
||||
color="gray.400"
|
||||
maxW="700px"
|
||||
fontSize={['lg', 'xl']}
|
||||
data-aos="fade-up"
|
||||
>
|
||||
Typebot offers several native integrations blocks as well as
|
||||
instructions on how to embed typebot on particular platforms
|
||||
</Text>
|
||||
</Stack>
|
||||
</Stack>
|
||||
</Flex>
|
||||
)
|
143
ee/apps/landing-page/components/Homepage/IntroducingChatApps.tsx
Normal file
143
ee/apps/landing-page/components/Homepage/IntroducingChatApps.tsx
Normal file
@ -0,0 +1,143 @@
|
||||
import {
|
||||
Button,
|
||||
Flex,
|
||||
Heading,
|
||||
Stack,
|
||||
Text,
|
||||
FormControl,
|
||||
FormLabel,
|
||||
Input,
|
||||
Checkbox,
|
||||
Textarea,
|
||||
} from '@chakra-ui/react'
|
||||
import React, { useEffect, useState } from 'react'
|
||||
import { PublicTypebot } from '@typebot.io/schemas'
|
||||
import { sendRequest } from '@typebot.io/lib'
|
||||
import { DontIcon } from 'assets/icons/DontIcon'
|
||||
import { DoIcon } from 'assets/icons/DoIcon'
|
||||
import { HandDrawnArrow } from 'assets/illustrations/HandDrawnArrow'
|
||||
import { Standard } from '@typebot.io/nextjs'
|
||||
|
||||
export const IntroducingChatApps = () => {
|
||||
const [typebot, setTypebot] = useState<PublicTypebot>()
|
||||
|
||||
useEffect(() => {
|
||||
fetchTemplate()
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [])
|
||||
|
||||
const fetchTemplate = async () => {
|
||||
const { data, error } = await sendRequest(`/typebots/lead-gen-lp.json`)
|
||||
if (error) return
|
||||
setTypebot(data as PublicTypebot)
|
||||
}
|
||||
|
||||
return (
|
||||
<Flex as="section" justify="center">
|
||||
<Stack
|
||||
style={{ maxWidth: '1200px' }}
|
||||
pt={32}
|
||||
w="full"
|
||||
px="4"
|
||||
spacing={16}
|
||||
justifyContent="space-between"
|
||||
alignItems="center"
|
||||
>
|
||||
<Stack spacing={6} w="full">
|
||||
<Heading
|
||||
fontSize={{ base: '3xl', lg: '5xl', xl: '6xl' }}
|
||||
textAlign="center"
|
||||
data-aos="fade"
|
||||
>
|
||||
Replace your old school forms with chatbots
|
||||
</Heading>
|
||||
<Text
|
||||
textAlign="center"
|
||||
fontSize={{ base: 'lg', xl: 'xl' }}
|
||||
color="gray.400"
|
||||
data-aos="fade"
|
||||
>
|
||||
Typebot is a better way to ask for information. It leads to an
|
||||
increase in customer satisfaction and retention and multiply by 3
|
||||
your conversion rate compared to classical forms.
|
||||
</Text>
|
||||
</Stack>
|
||||
|
||||
<Stack
|
||||
direction={['column', 'row']}
|
||||
w="full"
|
||||
spacing="6"
|
||||
data-aos="fade"
|
||||
>
|
||||
<Stack spacing={6} flex="1" align={['flex-start', 'center']}>
|
||||
<DontIcon />
|
||||
<FakeLeadGenForm />
|
||||
</Stack>
|
||||
|
||||
<Stack
|
||||
spacing={6}
|
||||
flex="1"
|
||||
h="full"
|
||||
pos="relative"
|
||||
align={['flex-start', 'center']}
|
||||
>
|
||||
<DoIcon />
|
||||
{typebot && (
|
||||
<Standard
|
||||
typebot={typebot}
|
||||
style={{
|
||||
borderRadius: '0.375rem',
|
||||
borderWidth: '1px',
|
||||
height: '562px',
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
<Flex top="-20px" right="40px" pos="absolute">
|
||||
<Text fontFamily="'Indie Flower'" fontSize="2xl">
|
||||
Try it out!
|
||||
</Text>
|
||||
<HandDrawnArrow
|
||||
transform="rotate(30deg)"
|
||||
boxSize="100px"
|
||||
top="15px"
|
||||
right="-60px"
|
||||
pos="absolute"
|
||||
/>
|
||||
</Flex>
|
||||
</Stack>
|
||||
</Stack>
|
||||
</Stack>
|
||||
</Flex>
|
||||
)
|
||||
}
|
||||
|
||||
const FakeLeadGenForm = () => (
|
||||
<Stack borderWidth="1px" spacing="4" padding="6" rounded="md" w="full">
|
||||
<FormControl isRequired>
|
||||
<FormLabel htmlFor="full-name">Full name</FormLabel>
|
||||
<Input id="full-name" placeholder="Full name" />
|
||||
</FormControl>
|
||||
<FormControl isRequired>
|
||||
<FormLabel htmlFor="email">Email</FormLabel>
|
||||
<Input id="email" placeholder="Email" />
|
||||
</FormControl>
|
||||
<FormControl isRequired>
|
||||
<FormLabel htmlFor="services">
|
||||
What services are you interested in?
|
||||
</FormLabel>
|
||||
<Stack>
|
||||
<Checkbox>Website Dev</Checkbox>
|
||||
<Checkbox>Content Marketing</Checkbox>
|
||||
<Checkbox>Social Media</Checkbox>
|
||||
<Checkbox>UX/UI Design</Checkbox>
|
||||
</Stack>
|
||||
</FormControl>
|
||||
<FormControl isRequired>
|
||||
<FormLabel htmlFor="info">Additional Information</FormLabel>
|
||||
<Textarea id="info" placeholder="Additional Information" />
|
||||
</FormControl>
|
||||
<Flex>
|
||||
<Button>Submit</Button>
|
||||
</Flex>
|
||||
</Stack>
|
||||
)
|
134
ee/apps/landing-page/components/Homepage/RealTimeResults.tsx
Normal file
134
ee/apps/landing-page/components/Homepage/RealTimeResults.tsx
Normal file
@ -0,0 +1,134 @@
|
||||
import { Flex, Stack, Heading, Text, Button, VStack } from '@chakra-ui/react'
|
||||
import { Standard } from '@typebot.io/nextjs'
|
||||
import { ArrowRight } from 'assets/icons/ArrowRight'
|
||||
import { HandDrawnArrow } from 'assets/illustrations/HandDrawnArrow'
|
||||
import { PublicTypebot, Typebot } from '@typebot.io/schemas'
|
||||
import Link from 'next/link'
|
||||
import React, { useEffect, useRef, useState } from 'react'
|
||||
import { sendRequest } from '@typebot.io/lib'
|
||||
|
||||
const nameBlockId = 'shuUtMDMw9P4iAHbz7B5SqJ'
|
||||
const messageBlockId = 'sqvXpT1YXE3Htp6BCPvVGv3'
|
||||
|
||||
export const RealTimeResults = () => {
|
||||
const iframeRef = useRef<HTMLIFrameElement | null>(null)
|
||||
const [typebot, setTypebot] = useState<PublicTypebot>()
|
||||
|
||||
const fetchTemplate = async () => {
|
||||
const { data, error } = await sendRequest(
|
||||
`/typebots/realtime-airtable.json`
|
||||
)
|
||||
if (error) return
|
||||
const typebot = data as Typebot
|
||||
setTypebot({ ...typebot, typebotId: typebot.id } as PublicTypebot)
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
fetchTemplate()
|
||||
}, [])
|
||||
|
||||
const refreshIframeContent = () => {
|
||||
if (!iframeRef.current) return
|
||||
iframeRef.current.src += ''
|
||||
}
|
||||
|
||||
const handleAnswer = ({ blockId }: { blockId: string }) => {
|
||||
if ([nameBlockId, messageBlockId].includes(blockId))
|
||||
setTimeout(refreshIframeContent, 1000)
|
||||
}
|
||||
|
||||
return (
|
||||
<Flex as="section" justify="center">
|
||||
<Stack
|
||||
style={{ maxWidth: '1200px' }}
|
||||
pt={'52'}
|
||||
w="full"
|
||||
px="4"
|
||||
spacing={16}
|
||||
justifyContent="space-between"
|
||||
alignItems="center"
|
||||
>
|
||||
<VStack spacing={6}>
|
||||
<Heading
|
||||
fontSize={{ base: '4xl', xl: '6xl' }}
|
||||
textAlign="center"
|
||||
data-aos="fade"
|
||||
>
|
||||
Collect results in real-time
|
||||
</Heading>
|
||||
<Text
|
||||
textAlign="center"
|
||||
color="gray.400"
|
||||
maxW="1000px"
|
||||
fontSize={{ base: 'lg', xl: 'xl' }}
|
||||
data-aos="fade"
|
||||
>
|
||||
One of the main advantage of a chat application is that you collect
|
||||
the user's responses on each question.{' '}
|
||||
<strong>You won't lose any valuable data.</strong>
|
||||
</Text>
|
||||
<Flex>
|
||||
<Button
|
||||
as={Link}
|
||||
rightIcon={<ArrowRight />}
|
||||
href={`https://app.typebot.io/register`}
|
||||
variant="ghost"
|
||||
colorScheme="blue"
|
||||
data-aos="fade"
|
||||
>
|
||||
Try it now
|
||||
</Button>
|
||||
</Flex>
|
||||
</VStack>
|
||||
|
||||
<Stack
|
||||
w="full"
|
||||
direction={['column', 'row']}
|
||||
spacing="4"
|
||||
pos="relative"
|
||||
data-aos="fade"
|
||||
>
|
||||
{typebot && (
|
||||
<Standard
|
||||
typebot="airtable-real-time"
|
||||
onAnswer={handleAnswer}
|
||||
style={{
|
||||
borderRadius: '0.375rem',
|
||||
borderWidth: '1px',
|
||||
height: '533px',
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
<iframe
|
||||
ref={iframeRef}
|
||||
src="https://airtable.com/embed/shr8nkV6DVN88LVIv?backgroundColor=blue"
|
||||
width="100%"
|
||||
height="533"
|
||||
style={{
|
||||
borderRadius: '0.5rem',
|
||||
border: 'none',
|
||||
backgroundColor: 'white',
|
||||
}}
|
||||
/>
|
||||
<Flex
|
||||
top="-60px"
|
||||
right="-30px"
|
||||
pos="absolute"
|
||||
display={{ base: 'none', xl: 'flex' }}
|
||||
>
|
||||
<Text fontFamily="'Indie Flower'" fontSize="2xl">
|
||||
It's a real Airtable view!
|
||||
</Text>
|
||||
<HandDrawnArrow
|
||||
transform="rotate(30deg)"
|
||||
boxSize="100px"
|
||||
top="15px"
|
||||
right="-60px"
|
||||
pos="absolute"
|
||||
/>
|
||||
</Flex>
|
||||
</Stack>
|
||||
</Stack>
|
||||
</Flex>
|
||||
)
|
||||
}
|
80
ee/apps/landing-page/components/Homepage/Testimonials/Testimonial.tsx
Executable file
80
ee/apps/landing-page/components/Homepage/Testimonials/Testimonial.tsx
Executable file
@ -0,0 +1,80 @@
|
||||
import { Avatar, Flex, HStack, Stack, Text } from '@chakra-ui/react'
|
||||
import * as React from 'react'
|
||||
import Image from 'next/image'
|
||||
import { TestimonialData } from './Testimonials'
|
||||
import {
|
||||
CapterraIcon,
|
||||
EmailIcon,
|
||||
ProductHuntIcon,
|
||||
RedditIcon,
|
||||
} from 'assets/icons'
|
||||
|
||||
export const Testimonial = ({
|
||||
avatarSrc,
|
||||
content,
|
||||
name,
|
||||
role,
|
||||
provider,
|
||||
}: TestimonialData) => (
|
||||
<Stack
|
||||
p="6"
|
||||
rounded="lg"
|
||||
bgColor="gray.800"
|
||||
color="white"
|
||||
shadow="lg"
|
||||
spacing="4"
|
||||
data-aos="fade"
|
||||
>
|
||||
<Flex justifyContent="space-between">
|
||||
<HStack spacing="4">
|
||||
{avatarSrc ? (
|
||||
<Image
|
||||
src={avatarSrc}
|
||||
alt={name}
|
||||
placeholder="blur"
|
||||
width={40}
|
||||
height={40}
|
||||
className="rounded-full"
|
||||
/>
|
||||
) : (
|
||||
<Avatar name={name} />
|
||||
)}
|
||||
<Stack spacing={1}>
|
||||
<Text
|
||||
as="cite"
|
||||
fontStyle="normal"
|
||||
fontWeight="extrabold"
|
||||
color="white"
|
||||
>
|
||||
{name}
|
||||
</Text>
|
||||
<Text fontSize="sm" color={'gray.100'}>
|
||||
{role}
|
||||
</Text>
|
||||
</Stack>
|
||||
</HStack>
|
||||
<ProviderIcon provider={provider} />
|
||||
</Flex>
|
||||
|
||||
<Text mt="3" maxW="38rem" color="gray.400">
|
||||
{content}
|
||||
</Text>
|
||||
</Stack>
|
||||
)
|
||||
|
||||
const ProviderIcon = ({
|
||||
provider,
|
||||
}: {
|
||||
provider: TestimonialData['provider']
|
||||
}): JSX.Element => {
|
||||
switch (provider) {
|
||||
case 'email':
|
||||
return <EmailIcon fontSize="20px" />
|
||||
case 'productHunt':
|
||||
return <ProductHuntIcon fontSize="20px" />
|
||||
case 'capterra':
|
||||
return <CapterraIcon fontSize="20px" />
|
||||
case 'reddit':
|
||||
return <RedditIcon fontSize="20px" />
|
||||
}
|
||||
}
|
222
ee/apps/landing-page/components/Homepage/Testimonials/Testimonials.tsx
Executable file
222
ee/apps/landing-page/components/Homepage/Testimonials/Testimonials.tsx
Executable file
@ -0,0 +1,222 @@
|
||||
import { Flex, Heading, SimpleGrid, Stack, VStack } from '@chakra-ui/react'
|
||||
import * as React from 'react'
|
||||
import joshuaPictureSrc from 'public/images/joshua.jpg'
|
||||
import julienPictureSrc from 'public/images/julien.jpeg'
|
||||
import nicolaiPictureSrc from 'public/images/nicolai.jpg'
|
||||
import annaFilouPictureSrc from 'public/images/annaFilou.jpeg'
|
||||
import theoPictureSrc from 'public/images/theo.jpeg'
|
||||
import abhayPictureSrc from 'public/images/abhay.jpeg'
|
||||
import lucasPictureSrc from 'public/images/lucas.png'
|
||||
import oscarPictureSrc from 'public/images/oscar.jpeg'
|
||||
import invictuzPictureSrc from 'public/images/invictuz.png'
|
||||
import laszloPictureSrc from 'public/images/laszlo.jpeg'
|
||||
import kurniaPictureSrc from 'public/images/kurnia.jpeg'
|
||||
import stevePictureSrc from 'public/images/steve.jpg'
|
||||
import { Testimonial } from './Testimonial'
|
||||
import { StaticImageData } from 'next/image'
|
||||
|
||||
export type TestimonialData = {
|
||||
name: string
|
||||
avatarSrc?: StaticImageData
|
||||
provider: 'email' | 'productHunt' | 'capterra' | 'reddit'
|
||||
role?: string
|
||||
content: string | React.ReactNode
|
||||
}
|
||||
|
||||
const testimonials: TestimonialData[][] = [
|
||||
[
|
||||
{
|
||||
name: 'Joshua Lim',
|
||||
role: 'Growth Strategist @ Socialhackrs Media',
|
||||
avatarSrc: joshuaPictureSrc,
|
||||
provider: 'email',
|
||||
content:
|
||||
'I upgraded my typeforms to typebots and saw a conversion rate increase from 14% to 43% on my marketing campaigns. I noticed the improvement on day one. That was a game-changer.',
|
||||
},
|
||||
{
|
||||
name: 'Laszlo Csömör',
|
||||
role: 'Digital Marketing Expert',
|
||||
provider: 'email',
|
||||
avatarSrc: laszloPictureSrc,
|
||||
content: (
|
||||
<>
|
||||
Typebot is one of the best chatbot builders with its intelligent
|
||||
features and drag-and-drop simplicity. Its UI/UX is an earthly
|
||||
paradise...
|
||||
<br />
|
||||
What's even more important is the person who stands behind it. He
|
||||
guarantees that the platform will work and progress for a long time.
|
||||
</>
|
||||
),
|
||||
},
|
||||
{
|
||||
name: 'Mario Barretta',
|
||||
role: 'Customer Care Manager',
|
||||
provider: 'email',
|
||||
content: (
|
||||
<>
|
||||
Thanks to typebot I can finally make site forms much more modern and I
|
||||
can collect information that I would have missed before. Also ,thanks
|
||||
to Baptiste, the service is always evolving and has excellent
|
||||
assistance not only in solving but also in listening to suggestions
|
||||
and putting it into action.
|
||||
<br />
|
||||
<br />
|
||||
Thank you thank you and thank you again .
|
||||
</>
|
||||
),
|
||||
},
|
||||
{
|
||||
name: 'Lucas Barp',
|
||||
provider: 'email',
|
||||
avatarSrc: lucasPictureSrc,
|
||||
role: 'Founder at Barp Digital',
|
||||
content:
|
||||
'The result of your work is incredible and can make life easier for many people.',
|
||||
},
|
||||
{
|
||||
name: 'Igor T.',
|
||||
role: 'CTO',
|
||||
provider: 'capterra',
|
||||
content:
|
||||
'Nice work. The developer promptly makes changes, which is quite rare. There was a suggestion for improvement and improvement, in 2 days it was implemented. Amazing! Good luck and thanks a lot',
|
||||
},
|
||||
],
|
||||
[
|
||||
{
|
||||
name: 'Oscar',
|
||||
role: 'CEO',
|
||||
provider: 'capterra',
|
||||
avatarSrc: oscarPictureSrc,
|
||||
content:
|
||||
'Within 5 minutes of signing up you can already have your bot running thanks to the templates it comes with. I have used many tools to make bots but none as simple, easy and powerful as Typebot.',
|
||||
},
|
||||
{
|
||||
name: 'Julien Muratot',
|
||||
role: 'Growth Manager @ Hornetwork',
|
||||
avatarSrc: julienPictureSrc,
|
||||
provider: 'email',
|
||||
content:
|
||||
'I run Google ads all year long on our landing page that contains a typebot. I saw a 2x increase on our conversation rate compared to our old WordPress form.',
|
||||
},
|
||||
{
|
||||
name: '_Invictuz',
|
||||
provider: 'reddit',
|
||||
avatarSrc: invictuzPictureSrc,
|
||||
content:
|
||||
"This is the sickest open-source project I've ever seen and demoed. The use case is so cool and modern and I can't believe how easy this is to get started using. The feature richness and polish in this project is incredible, it feel like a mature product. Unbelievable that this was built by one person. This is better than the demos of chatbot builders I've seen from full-fledged companies. I'm going to learn Typescript so that I can contribute to this someday. Mind-blowing stuff...",
|
||||
},
|
||||
{
|
||||
name: 'Theo Marechal',
|
||||
provider: 'productHunt',
|
||||
avatarSrc: theoPictureSrc,
|
||||
role: 'Nocode expert and content creator',
|
||||
content: (
|
||||
<>
|
||||
Amazing product! I'm using Typebot for everything when it's
|
||||
about talking with customers.
|
||||
<br />
|
||||
<br />
|
||||
What's amazing with Typebot is that it makes a "chat
|
||||
interface effect" without the hassle of being behind my computer
|
||||
all day responding to customers. Highly recommend !
|
||||
</>
|
||||
),
|
||||
},
|
||||
{
|
||||
name: 'Abhay Kulkarni',
|
||||
provider: 'productHunt',
|
||||
avatarSrc: abhayPictureSrc,
|
||||
role: 'Founder at Webisharp',
|
||||
content:
|
||||
'Using this tool for the last 2 hours & built a full lead capture bot. Pretty good experience till now. @baptiste_arnaud All the best for future :)',
|
||||
},
|
||||
],
|
||||
[
|
||||
{
|
||||
name: 'Steve de Jong',
|
||||
provider: 'email',
|
||||
avatarSrc: stevePictureSrc,
|
||||
role: 'CEO at Stillio',
|
||||
content: (
|
||||
<>
|
||||
We built our own onboarding template last December for all signups for
|
||||
Stillio and it works fantastic and reliably.
|
||||
<br />
|
||||
<br />
|
||||
We send the collected data to a Make-com webhook and from there,
|
||||
post-process and send to Encharge (email drip campaigns) and Pipedrive
|
||||
(CRM).
|
||||
<br />
|
||||
We are now working on personalizing the email templates based on the
|
||||
answers (user industry and role) given in the typebot. We are big fan!
|
||||
</>
|
||||
),
|
||||
},
|
||||
{
|
||||
name: 'Goran Milic',
|
||||
role: 'General Manager, Beefii',
|
||||
provider: 'email',
|
||||
content: (
|
||||
<>
|
||||
I used Typebot at my company and was impressed with how it cut our
|
||||
customer service workload in half. I was able to create a fully
|
||||
functional chatbot in minutes. <br /> You can create a bot to answer
|
||||
frequently asked questions about your business or create a bot that
|
||||
helps promote your business on social media or any other platform.,
|
||||
</>
|
||||
),
|
||||
},
|
||||
{
|
||||
name: 'Kurnia Kwik',
|
||||
role: 'Founder at DigitalPointer.ID',
|
||||
provider: 'email',
|
||||
avatarSrc: kurniaPictureSrc,
|
||||
content: (
|
||||
<>
|
||||
I have several chatbot builders, but Typebot is the one I use the
|
||||
most. It is simple to construct and very intuitive. <br />
|
||||
Integration with third-party applications is simple, and you can
|
||||
create the most sophisticated bots with its simplicity.
|
||||
</>
|
||||
),
|
||||
},
|
||||
{
|
||||
name: 'Nicolai Grut',
|
||||
role: 'CEO @ EcommerceNotebook.com',
|
||||
avatarSrc: nicolaiPictureSrc,
|
||||
provider: 'email',
|
||||
content:
|
||||
'I am really loving using Typebot! So good. I have used all the top bots and yours is definitely the most user friendly, and yet still so powerful.',
|
||||
},
|
||||
{
|
||||
name: 'Anna Filou',
|
||||
provider: 'productHunt',
|
||||
avatarSrc: annaFilouPictureSrc,
|
||||
role: 'Geek, Designer, Illustrator, Web Dev',
|
||||
content:
|
||||
"Seems like the product I've been waiting for Typeform to make! 😝",
|
||||
},
|
||||
],
|
||||
]
|
||||
|
||||
export const Testimonials = () => {
|
||||
return (
|
||||
<Flex as="section" justify="center">
|
||||
<VStack spacing={12} pt={'52'} px="4" maxW="1400px">
|
||||
<Heading textAlign={'center'} data-aos="fade">
|
||||
They've tried, they never looked back. 💙
|
||||
</Heading>
|
||||
<SimpleGrid columns={[1, 2, 3]} spacing="6">
|
||||
{testimonials.map((testimonialGroup, index) => (
|
||||
<Stack key={index} spacing="6">
|
||||
{testimonialGroup.map((testimonial, index) => (
|
||||
<Testimonial key={index} {...testimonial} />
|
||||
))}
|
||||
</Stack>
|
||||
))}
|
||||
</SimpleGrid>
|
||||
</VStack>
|
||||
</Flex>
|
||||
)
|
||||
}
|
@ -0,0 +1 @@
|
||||
export { Testimonials } from './Testimonials'
|
@ -0,0 +1,87 @@
|
||||
import {
|
||||
Modal,
|
||||
ModalOverlay,
|
||||
ModalContent,
|
||||
ModalHeader,
|
||||
ModalCloseButton,
|
||||
ModalBody,
|
||||
Stack,
|
||||
ModalFooter,
|
||||
Heading,
|
||||
Table,
|
||||
TableContainer,
|
||||
Tbody,
|
||||
Td,
|
||||
Th,
|
||||
Thead,
|
||||
Tr,
|
||||
} from '@chakra-ui/react'
|
||||
import { proChatTiers } from '@typebot.io/billing/constants'
|
||||
import { formatPrice } from '@typebot.io/billing/helpers/formatPrice'
|
||||
|
||||
type Props = {
|
||||
isOpen: boolean
|
||||
onClose: () => void
|
||||
}
|
||||
|
||||
export const ChatsProTiersModal = ({ isOpen, onClose }: Props) => {
|
||||
return (
|
||||
<Modal isOpen={isOpen} onClose={onClose} size="xl">
|
||||
<ModalOverlay />
|
||||
<ModalContent>
|
||||
<ModalHeader>
|
||||
<Heading size="lg">Chats pricing table</Heading>
|
||||
</ModalHeader>
|
||||
<ModalCloseButton />
|
||||
<ModalBody as={Stack} spacing="6">
|
||||
<TableContainer>
|
||||
<Table variant="simple">
|
||||
<Thead>
|
||||
<Tr>
|
||||
<Th isNumeric>Max chats</Th>
|
||||
<Th isNumeric>Price per month</Th>
|
||||
<Th isNumeric>Price per 1k chats</Th>
|
||||
</Tr>
|
||||
</Thead>
|
||||
<Tbody>
|
||||
{proChatTiers.map((tier, index) => {
|
||||
const pricePerMonth =
|
||||
(tier.flat_amount ??
|
||||
proChatTiers.at(-2)?.flat_amount ??
|
||||
0) / 100
|
||||
return (
|
||||
<Tr key={tier.up_to}>
|
||||
<Td isNumeric>
|
||||
{tier.up_to === 'inf'
|
||||
? '2,000,000+'
|
||||
: tier.up_to.toLocaleString()}
|
||||
</Td>
|
||||
<Td isNumeric>
|
||||
{index === 0 ? 'included' : formatPrice(pricePerMonth)}
|
||||
</Td>
|
||||
<Td isNumeric>
|
||||
{index === proChatTiers.length - 1
|
||||
? formatPrice(4.42, { maxFractionDigits: 2 })
|
||||
: index === 0
|
||||
? 'included'
|
||||
: formatPrice(
|
||||
(((pricePerMonth * 100) /
|
||||
((tier.up_to as number) -
|
||||
(proChatTiers.at(0)?.up_to as number))) *
|
||||
1000) /
|
||||
100,
|
||||
{ maxFractionDigits: 2 }
|
||||
)}
|
||||
</Td>
|
||||
</Tr>
|
||||
)
|
||||
})}
|
||||
</Tbody>
|
||||
</Table>
|
||||
</TableContainer>
|
||||
</ModalBody>
|
||||
<ModalFooter />
|
||||
</ModalContent>
|
||||
</Modal>
|
||||
)
|
||||
}
|
@ -0,0 +1,57 @@
|
||||
import {
|
||||
Stack,
|
||||
Heading,
|
||||
Button,
|
||||
List,
|
||||
ListItem,
|
||||
ListIcon,
|
||||
Text,
|
||||
Link,
|
||||
} from '@chakra-ui/react'
|
||||
import { CheckCircleIcon } from 'assets/icons'
|
||||
|
||||
export const EnterprisePlanCard = () => (
|
||||
<Stack
|
||||
direction={['column', 'row']}
|
||||
align="center"
|
||||
p="10"
|
||||
rounded="lg"
|
||||
bgColor="gray.800"
|
||||
borderWidth="2px"
|
||||
spacing={10}
|
||||
>
|
||||
<Stack maxW="300px" spacing={4}>
|
||||
<Heading fontSize="xl">Enterprise</Heading>
|
||||
<Text>
|
||||
Ideal for large companies looking to generate leads and automate
|
||||
customer support at scale
|
||||
</Text>
|
||||
<Text fontSize="lg">
|
||||
<Button
|
||||
as={Link}
|
||||
href="https://typebot.io/enterprise-lead-form"
|
||||
isExternal
|
||||
variant="outline"
|
||||
>
|
||||
Get a quote
|
||||
</Button>
|
||||
</Text>
|
||||
</Stack>
|
||||
<Stack flex="1">
|
||||
<List spacing="4">
|
||||
<ListItem fontWeight="medium" display="flex" alignItems="center">
|
||||
<ListIcon fontSize="xl" as={CheckCircleIcon} marginEnd={2} />
|
||||
Custom chats limits & seats for all your team
|
||||
</ListItem>
|
||||
<ListItem fontWeight="medium" display="flex" alignItems="center">
|
||||
<ListIcon fontSize="xl" as={CheckCircleIcon} marginEnd={2} />
|
||||
SSO & Granular access rights
|
||||
</ListItem>
|
||||
<ListItem fontWeight="medium" display="flex" alignItems="center">
|
||||
<ListIcon fontSize="xl" as={CheckCircleIcon} marginEnd={2} />
|
||||
Yearly contract with dedicated support representative
|
||||
</ListItem>
|
||||
</List>
|
||||
</Stack>
|
||||
</Stack>
|
||||
)
|
74
ee/apps/landing-page/components/PricingPage/Faq.tsx
Normal file
74
ee/apps/landing-page/components/PricingPage/Faq.tsx
Normal file
@ -0,0 +1,74 @@
|
||||
import { Heading, VStack, Stack, Text, Wrap, WrapItem } from '@chakra-ui/react'
|
||||
|
||||
export const Faq = () => (
|
||||
<VStack w="full" spacing="10">
|
||||
<Heading textAlign="center">Frequently asked questions</Heading>
|
||||
<Wrap spacing={10}>
|
||||
<WrapItem maxW="500px">
|
||||
<Stack borderWidth={1} p="8" rounded="lg" spacing={4}>
|
||||
<Heading as="h2" fontSize="2xl">
|
||||
What is considered a monthly chat?
|
||||
</Heading>
|
||||
<Text>
|
||||
A chat is counted whenever a user starts a discussion. It is
|
||||
independant of the number of messages he sends and receives. For
|
||||
example if a user starts a discussion and sends 10 messages to the
|
||||
bot, it will count as 1 chat. If the user chats again later and its
|
||||
session is remembered, it will not be counted as a new chat. <br />
|
||||
<br />
|
||||
An easy way to think about it: 1 chat equals to a row in your
|
||||
Results table
|
||||
</Text>
|
||||
</Stack>
|
||||
</WrapItem>
|
||||
|
||||
<WrapItem maxW="500px">
|
||||
<Stack borderWidth={1} p="8" rounded="lg" spacing={4}>
|
||||
<Heading as="h2" fontSize="2xl">
|
||||
What happens once I reach the included chats limit?
|
||||
</Heading>
|
||||
<Text>
|
||||
That's amazing, your bots are working full speed. 🚀
|
||||
<br />
|
||||
<br />
|
||||
You will first receive a heads up email when you reach 80% of your
|
||||
included limit. Once you have reached 100%, you will receive another
|
||||
email notification.
|
||||
<br />
|
||||
<br />
|
||||
After that, your chat limit be automatically upgraded to the next
|
||||
tier.
|
||||
</Text>
|
||||
</Stack>
|
||||
</WrapItem>
|
||||
|
||||
<WrapItem maxW="500px">
|
||||
<Stack borderWidth={1} p="8" rounded="lg" spacing={4}>
|
||||
<Heading as="h2" fontSize="2xl">
|
||||
Can I cancel or change my subscription any time?
|
||||
</Heading>
|
||||
<Text>
|
||||
Yes, you can cancel, upgrade or downgrade your subscription at any
|
||||
time. There is no minimum time commitment or lock-in.
|
||||
<br />
|
||||
<br />
|
||||
When you upgrade or downgrade your subscription, you'll get
|
||||
access to the new options right away. Your next invoice will have a
|
||||
prorated amount.
|
||||
</Text>
|
||||
</Stack>
|
||||
</WrapItem>
|
||||
<WrapItem maxW="500px">
|
||||
<Stack borderWidth={1} p="8" rounded="lg" spacing={4}>
|
||||
<Heading as="h2" fontSize="2xl">
|
||||
Do you offer annual payments?
|
||||
</Heading>
|
||||
<Text>
|
||||
No, because subscriptions pricing is based on chats usage, we can
|
||||
only offer monthly plans.
|
||||
</Text>
|
||||
</Stack>
|
||||
</WrapItem>
|
||||
</Wrap>
|
||||
</VStack>
|
||||
)
|
53
ee/apps/landing-page/components/PricingPage/FreePlanCard.tsx
Normal file
53
ee/apps/landing-page/components/PricingPage/FreePlanCard.tsx
Normal file
@ -0,0 +1,53 @@
|
||||
import { chakra, Tooltip, Text, Button } from '@chakra-ui/react'
|
||||
import { HelpCircleIcon } from 'assets/icons/HelpCircleIcon'
|
||||
import Link from 'next/link'
|
||||
import React from 'react'
|
||||
import { PricingCard } from './PricingCard'
|
||||
import { chatsLimits } from '@typebot.io/billing/constants'
|
||||
|
||||
export const FreePlanCard = () => (
|
||||
<PricingCard
|
||||
data={{
|
||||
price: 'Free',
|
||||
name: 'Personal',
|
||||
features: [
|
||||
'Unlimited typebots',
|
||||
<>
|
||||
<Text>
|
||||
<chakra.span fontWeight="bold">{chatsLimits.FREE}</chakra.span>{' '}
|
||||
chats/month
|
||||
</Text>
|
||||
|
||||
<Tooltip
|
||||
hasArrow
|
||||
placement="top"
|
||||
label="A chat is counted whenever a user starts a discussion. It is
|
||||
independant of the number of messages he sends and receives."
|
||||
>
|
||||
<chakra.span cursor="pointer" h="7">
|
||||
<HelpCircleIcon />
|
||||
</chakra.span>
|
||||
</Tooltip>
|
||||
</>,
|
||||
'Native integrations',
|
||||
'Webhooks',
|
||||
'Custom Javascript & CSS',
|
||||
'Community support & Docs',
|
||||
],
|
||||
}}
|
||||
button={
|
||||
<Button
|
||||
as={Link}
|
||||
href="https://app.typebot.io/register"
|
||||
variant="outline"
|
||||
colorScheme="gray"
|
||||
size="lg"
|
||||
w="full"
|
||||
fontWeight="extrabold"
|
||||
py={{ md: '8' }}
|
||||
>
|
||||
Get started
|
||||
</Button>
|
||||
}
|
||||
/>
|
||||
)
|
@ -0,0 +1,418 @@
|
||||
import {
|
||||
TableContainer,
|
||||
Table,
|
||||
Thead,
|
||||
Tr,
|
||||
Th,
|
||||
Tbody,
|
||||
Td,
|
||||
Text,
|
||||
Stack,
|
||||
HStack,
|
||||
Tooltip,
|
||||
chakra,
|
||||
Button,
|
||||
Heading,
|
||||
} from '@chakra-ui/react'
|
||||
import { CheckIcon } from 'assets/icons/CheckIcon'
|
||||
import { HelpCircleIcon } from 'assets/icons/HelpCircleIcon'
|
||||
import { Plan } from '@typebot.io/prisma'
|
||||
import Link from 'next/link'
|
||||
import React from 'react'
|
||||
import { parseNumberWithCommas } from '@typebot.io/lib'
|
||||
import { chatsLimits, prices, seatsLimits } from '@typebot.io/billing/constants'
|
||||
import { formatPrice } from '@typebot.io/billing/helpers/formatPrice'
|
||||
|
||||
type Props = {
|
||||
onChatsTiersClick: () => void
|
||||
}
|
||||
|
||||
export const PlanComparisonTables = ({ onChatsTiersClick }: Props) => (
|
||||
<Stack spacing="12">
|
||||
<TableContainer>
|
||||
<Table>
|
||||
<Thead>
|
||||
<Tr>
|
||||
<Th fontWeight="bold" color="white" w="400px">
|
||||
Usage
|
||||
</Th>
|
||||
<Th>Free</Th>
|
||||
<Th color="orange.200">Starter</Th>
|
||||
<Th color="blue.200">Pro</Th>
|
||||
</Tr>
|
||||
</Thead>
|
||||
<Tbody>
|
||||
<Tr>
|
||||
<Td>Total bots</Td>
|
||||
<Td>Unlimited</Td>
|
||||
<Td>Unlimited</Td>
|
||||
<Td>Unlimited</Td>
|
||||
</Tr>
|
||||
<Tr>
|
||||
<Td>Chats</Td>
|
||||
<Td>{chatsLimits.FREE} / month</Td>
|
||||
<Td>{parseNumberWithCommas(chatsLimits.STARTER)} / month</Td>
|
||||
<Td>{parseNumberWithCommas(chatsLimits.PRO)} / month</Td>
|
||||
</Tr>
|
||||
<Tr>
|
||||
<Td>Additional Chats</Td>
|
||||
<Td />
|
||||
<Td>{formatPrice(10)} per 500 chats</Td>
|
||||
<Td>
|
||||
<Button
|
||||
variant="outline"
|
||||
size="xs"
|
||||
onClick={onChatsTiersClick}
|
||||
colorScheme="gray"
|
||||
>
|
||||
See tiers
|
||||
</Button>
|
||||
</Td>
|
||||
</Tr>
|
||||
<Tr>
|
||||
<Td>Storage</Td>
|
||||
<Td />
|
||||
<Td>2 GB</Td>
|
||||
<Td>10 GB</Td>
|
||||
</Tr>
|
||||
<Tr>
|
||||
<Td>Members</Td>
|
||||
<Td>Just you</Td>
|
||||
<Td>{seatsLimits.STARTER} seats</Td>
|
||||
<Td>{seatsLimits.PRO} seats</Td>
|
||||
</Tr>
|
||||
<Tr>
|
||||
<Td>Guests</Td>
|
||||
<Td>Unlimited</Td>
|
||||
<Td>Unlimited</Td>
|
||||
<Td>Unlimited</Td>
|
||||
</Tr>
|
||||
</Tbody>
|
||||
</Table>
|
||||
</TableContainer>
|
||||
<TableContainer>
|
||||
<Table>
|
||||
<Thead>
|
||||
<Tr>
|
||||
<Th fontWeight="bold" color="white" w="400px">
|
||||
Features
|
||||
</Th>
|
||||
<Th>Free</Th>
|
||||
<Th color="orange.200">Starter</Th>
|
||||
<Th color="blue.200">Pro</Th>
|
||||
</Tr>
|
||||
</Thead>
|
||||
<Tbody>
|
||||
<Tr>
|
||||
<TdWithTooltip
|
||||
text="20+ blocks"
|
||||
tooltip="Includes display bubbles (text, image, video, embed), question inputs (email, url, phone number...) and logic blocks (conditions, set variables...)"
|
||||
/>
|
||||
<Td>
|
||||
<CheckIcon />
|
||||
</Td>
|
||||
<Td>
|
||||
<CheckIcon />
|
||||
</Td>
|
||||
<Td>
|
||||
<CheckIcon />
|
||||
</Td>
|
||||
</Tr>
|
||||
<Tr>
|
||||
<Td>Starter templates</Td>
|
||||
<Td>
|
||||
<CheckIcon />
|
||||
</Td>
|
||||
<Td>
|
||||
<CheckIcon />
|
||||
</Td>
|
||||
<Td>
|
||||
<CheckIcon />
|
||||
</Td>
|
||||
</Tr>
|
||||
<Tr>
|
||||
<Td>Webhooks</Td>
|
||||
<Td>
|
||||
<CheckIcon />
|
||||
</Td>
|
||||
<Td>
|
||||
<CheckIcon />
|
||||
</Td>
|
||||
<Td>
|
||||
<CheckIcon />
|
||||
</Td>
|
||||
</Tr>
|
||||
<Tr>
|
||||
<Td>Google Sheets</Td>
|
||||
<Td>
|
||||
<CheckIcon />
|
||||
</Td>
|
||||
<Td>
|
||||
<CheckIcon />
|
||||
</Td>
|
||||
<Td>
|
||||
<CheckIcon />
|
||||
</Td>
|
||||
</Tr>
|
||||
<Tr>
|
||||
<Td>Google Analytics</Td>
|
||||
<Td>
|
||||
<CheckIcon />
|
||||
</Td>
|
||||
<Td>
|
||||
<CheckIcon />
|
||||
</Td>
|
||||
<Td>
|
||||
<CheckIcon />
|
||||
</Td>
|
||||
</Tr>
|
||||
<Tr>
|
||||
<Td>Send emails</Td>
|
||||
<Td>
|
||||
<CheckIcon />
|
||||
</Td>
|
||||
<Td>
|
||||
<CheckIcon />
|
||||
</Td>
|
||||
<Td>
|
||||
<CheckIcon />
|
||||
</Td>
|
||||
</Tr>
|
||||
<Tr>
|
||||
<Td>Zapier</Td>
|
||||
<Td>
|
||||
<CheckIcon />
|
||||
</Td>
|
||||
<Td>
|
||||
<CheckIcon />
|
||||
</Td>
|
||||
<Td>
|
||||
<CheckIcon />
|
||||
</Td>
|
||||
</Tr>
|
||||
<Tr>
|
||||
<Td>Pabbly Connect</Td>
|
||||
<Td>
|
||||
<CheckIcon />
|
||||
</Td>
|
||||
<Td>
|
||||
<CheckIcon />
|
||||
</Td>
|
||||
<Td>
|
||||
<CheckIcon />
|
||||
</Td>
|
||||
</Tr>
|
||||
<Tr>
|
||||
<Td>Make.com</Td>
|
||||
<Td>
|
||||
<CheckIcon />
|
||||
</Td>
|
||||
<Td>
|
||||
<CheckIcon />
|
||||
</Td>
|
||||
<Td>
|
||||
<CheckIcon />
|
||||
</Td>
|
||||
</Tr>
|
||||
<Tr>
|
||||
<Td>Custom Javascript & CSS</Td>
|
||||
<Td>
|
||||
<CheckIcon />
|
||||
</Td>
|
||||
<Td>
|
||||
<CheckIcon />
|
||||
</Td>
|
||||
<Td>
|
||||
<CheckIcon />
|
||||
</Td>
|
||||
</Tr>
|
||||
<Tr>
|
||||
<Td>Export CSV</Td>
|
||||
<Td>
|
||||
<CheckIcon />
|
||||
</Td>
|
||||
<Td>
|
||||
<CheckIcon />
|
||||
</Td>
|
||||
<Td>
|
||||
<CheckIcon />
|
||||
</Td>
|
||||
</Tr>
|
||||
<Tr>
|
||||
<Td>File upload inputs</Td>
|
||||
<Td />
|
||||
<Td>
|
||||
<CheckIcon />
|
||||
</Td>
|
||||
<Td>
|
||||
<CheckIcon />
|
||||
</Td>
|
||||
</Tr>
|
||||
<Tr>
|
||||
<TdWithTooltip
|
||||
text="Folders"
|
||||
tooltip="Organize your typebots into folders"
|
||||
/>
|
||||
<Td />
|
||||
<Td>Unlimited</Td>
|
||||
<Td>Unlimited</Td>
|
||||
</Tr>
|
||||
<Tr>
|
||||
<Td>Remove branding</Td>
|
||||
<Td />
|
||||
<Td>
|
||||
<CheckIcon />
|
||||
</Td>
|
||||
<Td>
|
||||
<CheckIcon />
|
||||
</Td>
|
||||
</Tr>
|
||||
<Tr>
|
||||
<Td>WhatsApp integration</Td>
|
||||
<Td />
|
||||
<Td />
|
||||
<Td>
|
||||
<CheckIcon />
|
||||
</Td>
|
||||
</Tr>
|
||||
<Tr>
|
||||
<Td>Custom domains</Td>
|
||||
<Td />
|
||||
<Td />
|
||||
<Td>Unlimited</Td>
|
||||
</Tr>
|
||||
<Tr>
|
||||
<TdWithTooltip
|
||||
text="In-depth analytics"
|
||||
tooltip="Analytics graph that shows your form drop-off rate, submission rate, and more."
|
||||
/>
|
||||
<Td />
|
||||
<Td />
|
||||
<Td>
|
||||
<CheckIcon />
|
||||
</Td>
|
||||
</Tr>
|
||||
</Tbody>
|
||||
</Table>
|
||||
</TableContainer>
|
||||
<TableContainer>
|
||||
<Table>
|
||||
<Thead>
|
||||
<Tr>
|
||||
<Th fontWeight="bold" color="white" w="400px">
|
||||
Support
|
||||
</Th>
|
||||
<Th>Free</Th>
|
||||
<Th color="orange.200">Starter</Th>
|
||||
<Th color="blue.200">Pro</Th>
|
||||
</Tr>
|
||||
</Thead>
|
||||
<Tbody>
|
||||
<Tr>
|
||||
<Td>Community support</Td>
|
||||
<Td>
|
||||
<CheckIcon />
|
||||
</Td>
|
||||
<Td>
|
||||
<CheckIcon />
|
||||
</Td>
|
||||
<Td>
|
||||
<CheckIcon />
|
||||
</Td>
|
||||
</Tr>
|
||||
<Tr>
|
||||
<Td>Direct support channel</Td>
|
||||
<Td />
|
||||
<Td>
|
||||
<CheckIcon />
|
||||
</Td>
|
||||
<Td>
|
||||
<CheckIcon />
|
||||
</Td>
|
||||
</Tr>
|
||||
<Tr>
|
||||
<Td>Priority support</Td>
|
||||
<Td />
|
||||
<Td />
|
||||
<Td>
|
||||
<CheckIcon />
|
||||
</Td>
|
||||
</Tr>
|
||||
<Tr>
|
||||
<Td>Feature request priority</Td>
|
||||
<Td />
|
||||
<Td />
|
||||
<Td>
|
||||
<CheckIcon />
|
||||
</Td>
|
||||
</Tr>
|
||||
</Tbody>
|
||||
</Table>
|
||||
</TableContainer>
|
||||
<Stack
|
||||
direction={['column', 'row']}
|
||||
spacing={4}
|
||||
w="full"
|
||||
justify="space-around"
|
||||
>
|
||||
<Stack spacing={4}>
|
||||
<Heading as="h3" size="md">
|
||||
Personal
|
||||
</Heading>
|
||||
<Heading as="h3">Free</Heading>
|
||||
<Link href="https://app.typebot.io/register">
|
||||
<Button variant="outline" colorScheme="gray">
|
||||
Get started
|
||||
</Button>
|
||||
</Link>
|
||||
</Stack>
|
||||
<Stack spacing={4}>
|
||||
<Heading as="h3" size="md" color="orange.200">
|
||||
Starter
|
||||
</Heading>
|
||||
<Heading as="h3">
|
||||
{formatPrice(prices.STARTER)}{' '}
|
||||
<chakra.span fontSize="lg">/ month</chakra.span>
|
||||
</Heading>
|
||||
<Link
|
||||
href={`https://app.typebot.io/register?subscribePlan=${Plan.STARTER}`}
|
||||
>
|
||||
<Button variant="outline" colorScheme="orange">
|
||||
Subscribe
|
||||
</Button>
|
||||
</Link>
|
||||
</Stack>
|
||||
<Stack spacing={4}>
|
||||
<Heading as="h3" size="md" color="blue.200">
|
||||
Pro
|
||||
</Heading>
|
||||
<Heading as="h3">
|
||||
{formatPrice(prices.PRO)}{' '}
|
||||
<chakra.span fontSize="lg">/ month</chakra.span>
|
||||
</Heading>
|
||||
<Link
|
||||
href={`https://app.typebot.io/register?subscribePlan=${Plan.PRO}`}
|
||||
>
|
||||
<Button>Subscribe</Button>
|
||||
</Link>
|
||||
</Stack>
|
||||
</Stack>
|
||||
</Stack>
|
||||
)
|
||||
|
||||
const TdWithTooltip = ({
|
||||
text,
|
||||
tooltip,
|
||||
}: {
|
||||
text: string
|
||||
tooltip: string
|
||||
}) => (
|
||||
<HStack as={Td}>
|
||||
<Text>{text}</Text>
|
||||
<Tooltip hasArrow placement="top" label={tooltip}>
|
||||
<chakra.span cursor="pointer">
|
||||
<HelpCircleIcon />
|
||||
</chakra.span>
|
||||
</Tooltip>
|
||||
</HStack>
|
||||
)
|
@ -0,0 +1,27 @@
|
||||
import { Box, BoxProps, useColorModeValue } from '@chakra-ui/react'
|
||||
import * as React from 'react'
|
||||
import { CardBadge } from './CardBadge'
|
||||
|
||||
export interface CardProps extends BoxProps {
|
||||
isPopular?: boolean
|
||||
}
|
||||
|
||||
export const Card = (props: CardProps) => {
|
||||
const { children, isPopular, ...rest } = props
|
||||
return (
|
||||
<Box
|
||||
bg={useColorModeValue('white', 'gray.700')}
|
||||
position="relative"
|
||||
px="6"
|
||||
py="6"
|
||||
overflow="hidden"
|
||||
shadow="lg"
|
||||
maxW="md"
|
||||
width="100%"
|
||||
{...rest}
|
||||
>
|
||||
{isPopular && <CardBadge>Popular</CardBadge>}
|
||||
{children}
|
||||
</Box>
|
||||
)
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
import { Flex, FlexProps, Text, useColorModeValue } from '@chakra-ui/react'
|
||||
import * as React from 'react'
|
||||
|
||||
export const CardBadge = (props: FlexProps) => {
|
||||
const { children, ...flexProps } = props
|
||||
return (
|
||||
<Flex
|
||||
bg={useColorModeValue('green.500', 'green.200')}
|
||||
position="absolute"
|
||||
right={-20}
|
||||
top={6}
|
||||
width="240px"
|
||||
transform="rotate(45deg)"
|
||||
py={2}
|
||||
justifyContent="center"
|
||||
alignItems="center"
|
||||
{...flexProps}
|
||||
>
|
||||
<Text
|
||||
fontSize="xs"
|
||||
textTransform="uppercase"
|
||||
fontWeight="bold"
|
||||
letterSpacing="wider"
|
||||
color={useColorModeValue('white', 'gray.800')}
|
||||
>
|
||||
{children}
|
||||
</Text>
|
||||
</Flex>
|
||||
)
|
||||
}
|
@ -0,0 +1,94 @@
|
||||
import {
|
||||
Flex,
|
||||
Heading,
|
||||
List,
|
||||
ListIcon,
|
||||
ListItem,
|
||||
Text,
|
||||
useColorModeValue,
|
||||
VStack,
|
||||
} from '@chakra-ui/react'
|
||||
import * as React from 'react'
|
||||
import { CheckCircleIcon } from '../../../assets/icons/CheckCircleIcon'
|
||||
import { Card, CardProps } from './Card'
|
||||
import { formatPrice } from '@typebot.io/billing/helpers/formatPrice'
|
||||
|
||||
export interface PricingCardData {
|
||||
features: React.ReactNode[]
|
||||
name: string
|
||||
price: number | string
|
||||
featureLabel?: string
|
||||
}
|
||||
|
||||
interface PricingCardProps extends CardProps {
|
||||
data: PricingCardData
|
||||
icon?: JSX.Element
|
||||
button: React.ReactElement
|
||||
}
|
||||
|
||||
export const PricingCard = ({
|
||||
data,
|
||||
icon,
|
||||
button,
|
||||
...rest
|
||||
}: PricingCardProps) => {
|
||||
const { features, price, name } = data
|
||||
const accentColor = useColorModeValue('blue.500', 'white')
|
||||
const formattedPrice = typeof price === 'number' ? formatPrice(price) : price
|
||||
|
||||
return (
|
||||
<Card rounded="xl" bgColor="gray.800" {...rest}>
|
||||
<Flex justifyContent="space-between" flexDir="column" h="full">
|
||||
<Flex flexDir="column">
|
||||
<VStack spacing={6}>
|
||||
{icon}
|
||||
<Heading size="md" fontWeight="extrabold" color={rest.borderColor}>
|
||||
{name}
|
||||
</Heading>
|
||||
</VStack>
|
||||
<Flex
|
||||
align="flex-end"
|
||||
justify="center"
|
||||
fontWeight="extrabold"
|
||||
color={accentColor}
|
||||
my="8"
|
||||
>
|
||||
<Heading size="2xl" fontWeight="inherit" lineHeight="0.9em">
|
||||
{formattedPrice}
|
||||
</Heading>
|
||||
{typeof price === 'number' && (
|
||||
<Text fontWeight="inherit" fontSize="xl">
|
||||
/ month
|
||||
</Text>
|
||||
)}
|
||||
</Flex>
|
||||
|
||||
<List spacing="4" mb="8" maxW="30ch" mx="auto">
|
||||
{data.featureLabel && (
|
||||
<Text fontWeight="bold">{data.featureLabel}</Text>
|
||||
)}
|
||||
{features.map((feature, index) => (
|
||||
<ListItem
|
||||
fontWeight="medium"
|
||||
key={index}
|
||||
display="flex"
|
||||
alignItems="center"
|
||||
>
|
||||
<ListIcon
|
||||
fontSize="xl"
|
||||
as={CheckCircleIcon}
|
||||
marginEnd={2}
|
||||
color={accentColor}
|
||||
fill={rest.borderColor}
|
||||
/>
|
||||
{feature}
|
||||
</ListItem>
|
||||
))}
|
||||
</List>
|
||||
</Flex>
|
||||
|
||||
{button}
|
||||
</Flex>
|
||||
</Card>
|
||||
)
|
||||
}
|
78
ee/apps/landing-page/components/PricingPage/ProPlanCard.tsx
Normal file
78
ee/apps/landing-page/components/PricingPage/ProPlanCard.tsx
Normal file
@ -0,0 +1,78 @@
|
||||
import {
|
||||
chakra,
|
||||
Tooltip,
|
||||
Text,
|
||||
Button,
|
||||
HStack,
|
||||
Stack,
|
||||
Link,
|
||||
} from '@chakra-ui/react'
|
||||
import { HelpCircleIcon } from 'assets/icons/HelpCircleIcon'
|
||||
import { Plan } from '@typebot.io/prisma'
|
||||
import React from 'react'
|
||||
import { PricingCard } from './PricingCard'
|
||||
import { prices, seatsLimits } from '@typebot.io/billing/constants'
|
||||
|
||||
type Props = {
|
||||
onChatsTiersClick: () => void
|
||||
}
|
||||
|
||||
export const ProPlanCard = ({ onChatsTiersClick }: Props) => (
|
||||
<PricingCard
|
||||
data={{
|
||||
price: prices.PRO,
|
||||
name: 'Pro',
|
||||
featureLabel: 'Everything in Personal, plus:',
|
||||
features: [
|
||||
<Text key="seats">
|
||||
<chakra.span fontWeight="bold">{seatsLimits.PRO} seats</chakra.span>{' '}
|
||||
included
|
||||
</Text>,
|
||||
<Stack key="chats" spacing={0}>
|
||||
<HStack spacing={1.5}>
|
||||
<Text>10,000 chats/mo</Text>
|
||||
<Tooltip
|
||||
hasArrow
|
||||
placement="top"
|
||||
label="A chat is counted whenever a user starts a discussion. It is
|
||||
independant of the number of messages he sends and receives."
|
||||
>
|
||||
<chakra.span cursor="pointer" h="7">
|
||||
<HelpCircleIcon />
|
||||
</chakra.span>
|
||||
</Tooltip>
|
||||
</HStack>
|
||||
<Text fontSize="sm" color="gray.400">
|
||||
Extra chats:{' '}
|
||||
<Button
|
||||
variant="outline"
|
||||
size="xs"
|
||||
colorScheme="gray"
|
||||
onClick={onChatsTiersClick}
|
||||
>
|
||||
See tiers
|
||||
</Button>
|
||||
</Text>
|
||||
</Stack>,
|
||||
'WhatsApp integration',
|
||||
'Custom domains',
|
||||
'In-depth analytics',
|
||||
],
|
||||
}}
|
||||
borderWidth="3px"
|
||||
borderColor="blue.200"
|
||||
button={
|
||||
<Button
|
||||
as={Link}
|
||||
href={`https://app.typebot.io/register?subscribePlan=${Plan.PRO}`}
|
||||
colorScheme="blue"
|
||||
size="lg"
|
||||
w="full"
|
||||
fontWeight="extrabold"
|
||||
py={{ md: '8' }}
|
||||
>
|
||||
Subscribe now
|
||||
</Button>
|
||||
}
|
||||
/>
|
||||
)
|
@ -0,0 +1,65 @@
|
||||
import { chakra, Tooltip, Text, HStack, Button, Stack } from '@chakra-ui/react'
|
||||
import { HelpCircleIcon } from 'assets/icons/HelpCircleIcon'
|
||||
import { Plan } from '@typebot.io/prisma'
|
||||
import Link from 'next/link'
|
||||
import React from 'react'
|
||||
import { PricingCard } from './PricingCard'
|
||||
import { prices, seatsLimits } from '@typebot.io/billing/constants'
|
||||
|
||||
export const StarterPlanCard = () => {
|
||||
return (
|
||||
<PricingCard
|
||||
data={{
|
||||
price: prices.STARTER,
|
||||
name: 'Starter',
|
||||
featureLabel: 'Everything in Personal, plus:',
|
||||
features: [
|
||||
<Text key="seats">
|
||||
<chakra.span fontWeight="bold">
|
||||
{seatsLimits.STARTER} seats
|
||||
</chakra.span>{' '}
|
||||
included
|
||||
</Text>,
|
||||
<Stack key="chats" spacing={0}>
|
||||
<HStack spacing={1.5}>
|
||||
<Text>2,000 chats/mo</Text>
|
||||
<Tooltip
|
||||
hasArrow
|
||||
placement="top"
|
||||
label="A chat is counted whenever a user starts a discussion. It is
|
||||
independant of the number of messages he sends and receives."
|
||||
>
|
||||
<chakra.span cursor="pointer" h="7">
|
||||
<HelpCircleIcon />
|
||||
</chakra.span>
|
||||
</Tooltip>
|
||||
</HStack>
|
||||
<Text fontSize="sm" color="gray.400">
|
||||
Extra chats: $10 per 500
|
||||
</Text>
|
||||
</Stack>,
|
||||
'Branding removed',
|
||||
'Collect files from users',
|
||||
'Create folders',
|
||||
'Direct priority support',
|
||||
],
|
||||
}}
|
||||
borderWidth="1px"
|
||||
borderColor="orange.200"
|
||||
button={
|
||||
<Button
|
||||
as={Link}
|
||||
href={`https://app.typebot.io/register?subscribePlan=${Plan.STARTER}`}
|
||||
colorScheme="orange"
|
||||
size="lg"
|
||||
w="full"
|
||||
fontWeight="extrabold"
|
||||
py={{ md: '8' }}
|
||||
variant="outline"
|
||||
>
|
||||
Subscribe now
|
||||
</Button>
|
||||
}
|
||||
/>
|
||||
)
|
||||
}
|
21
ee/apps/landing-page/components/common/ArticleCta.tsx
Normal file
21
ee/apps/landing-page/components/common/ArticleCta.tsx
Normal file
@ -0,0 +1,21 @@
|
||||
import { VStack, Heading, Button, Text } from '@chakra-ui/react'
|
||||
import React from 'react'
|
||||
|
||||
export const ArticleCallToAction = () => (
|
||||
<VStack spacing={6}>
|
||||
<Heading fontSize="xx-large">
|
||||
Collect up to 4x more responses without 4x the work.
|
||||
</Heading>
|
||||
<Button
|
||||
size="lg"
|
||||
colorScheme="orange"
|
||||
as="a"
|
||||
href="https://app.typebot.io/register"
|
||||
>
|
||||
Create a typebot
|
||||
</Button>
|
||||
<Text fontSize="sm" fontStyle="italic" color="gray.600">
|
||||
It's free!
|
||||
</Text>
|
||||
</VStack>
|
||||
)
|
92
ee/apps/landing-page/components/common/Footer.tsx
Normal file
92
ee/apps/landing-page/components/common/Footer.tsx
Normal file
@ -0,0 +1,92 @@
|
||||
'use client'
|
||||
|
||||
import React, { ReactNode } from 'react'
|
||||
|
||||
import {
|
||||
Box,
|
||||
Container,
|
||||
Heading,
|
||||
HStack,
|
||||
SimpleGrid,
|
||||
Stack,
|
||||
Text,
|
||||
} from '@chakra-ui/react'
|
||||
import { Logo } from 'assets/icons/Logo'
|
||||
import { TextLink } from './TextLink'
|
||||
|
||||
const discordServerUrl = 'https://typebot.io/discord'
|
||||
const typebotLinkedInUrl = 'https://www.linkedin.com/company/typebot'
|
||||
const typebotTwitterUrl = 'https://twitter.com/Typebot_io'
|
||||
const baptisteTwitterUrl = 'https://twitter.com/baptisteArno'
|
||||
const statusPageUrl = 'https://status.typebot.io'
|
||||
export const contactUrl = 'https://bot.typebot.io/landing-page-bubble-en'
|
||||
export const roadmapLink = 'https://app.typebot.io/feedback'
|
||||
export const documentationLink = 'https://docs.typebot.io'
|
||||
export const githubRepoLink = 'https://github.com/baptisteArno/typebot.io'
|
||||
|
||||
export const Footer = () => {
|
||||
return (
|
||||
<Box w="full">
|
||||
<Container as={Stack} maxW={'1000px'} py={10}>
|
||||
<SimpleGrid columns={[1, 2, 4]} spacing={8} px={2}>
|
||||
<Stack spacing={6}>
|
||||
<HStack>
|
||||
<Logo boxSize="30px" />
|
||||
<Heading as="p" fontSize="lg">
|
||||
Typebot
|
||||
</Heading>
|
||||
</HStack>
|
||||
<Text>
|
||||
Made with ❤️ by{' '}
|
||||
<TextLink href={baptisteTwitterUrl}>@baptisteArno</TextLink>
|
||||
</Text>
|
||||
</Stack>
|
||||
<Stack align={'flex-start'}>
|
||||
<ListHeader>Product</ListHeader>
|
||||
<TextLink href={statusPageUrl} isExternal>
|
||||
Status
|
||||
</TextLink>
|
||||
<TextLink href={documentationLink} isExternal>
|
||||
Documentation
|
||||
</TextLink>
|
||||
<TextLink href={roadmapLink} isExternal>
|
||||
Roadmap
|
||||
</TextLink>
|
||||
<TextLink href={'/pricing'}>Pricing</TextLink>
|
||||
</Stack>
|
||||
<Stack align={'flex-start'}>
|
||||
<ListHeader>Community</ListHeader>
|
||||
<TextLink href={discordServerUrl} isExternal>
|
||||
Discord
|
||||
</TextLink>
|
||||
<TextLink href={githubRepoLink} isExternal>
|
||||
GitHub repository
|
||||
</TextLink>
|
||||
<TextLink href={typebotTwitterUrl} isExternal>
|
||||
Twitter
|
||||
</TextLink>
|
||||
<TextLink href={typebotLinkedInUrl} isExternal>
|
||||
LinkedIn
|
||||
</TextLink>
|
||||
<TextLink href="/oss-friends">OSS Friends</TextLink>
|
||||
</Stack>
|
||||
<Stack align={'flex-start'}>
|
||||
<ListHeader>Company</ListHeader>
|
||||
<TextLink href="/about">About</TextLink>
|
||||
<TextLink href="mailto:support@typebot.io">Contact</TextLink>
|
||||
<TextLink href={'/terms-of-service'}>Terms of Service</TextLink>
|
||||
<TextLink href={'/privacy-policies'}>Privacy Policy</TextLink>
|
||||
</Stack>
|
||||
</SimpleGrid>
|
||||
</Container>
|
||||
</Box>
|
||||
)
|
||||
}
|
||||
|
||||
const ListHeader = ({ children }: { children: ReactNode }) => {
|
||||
return (
|
||||
<Heading fontWeight={'500'} fontSize={'lg'} mb={2}>
|
||||
{children}
|
||||
</Heading>
|
||||
)
|
||||
}
|
111
ee/apps/landing-page/components/common/Header/Header.tsx
Executable file
111
ee/apps/landing-page/components/common/Header/Header.tsx
Executable file
@ -0,0 +1,111 @@
|
||||
'use client'
|
||||
|
||||
import {
|
||||
Button,
|
||||
Flex,
|
||||
Heading,
|
||||
HStack,
|
||||
IconButton,
|
||||
useColorModeValue as mode,
|
||||
useDisclosure,
|
||||
Box,
|
||||
Link,
|
||||
} from '@chakra-ui/react'
|
||||
import { HamburgerIcon } from 'assets/icons'
|
||||
import { ChevronDownIcon } from 'assets/icons/ChevronDownIcon'
|
||||
import { CloseIcon } from 'assets/icons/CloseIcon'
|
||||
import { Logo } from 'assets/icons/Logo'
|
||||
import * as React from 'react'
|
||||
import { MobileMenu } from './MobileMenu'
|
||||
import { ResourcesMenu } from './ResourcesMenu'
|
||||
|
||||
export const Header = () => {
|
||||
const { isOpen, onToggle } = useDisclosure()
|
||||
const { isOpen: isMobileMenuOpen, onToggle: onMobileMenuToggle } =
|
||||
useDisclosure()
|
||||
|
||||
return (
|
||||
<Flex pos="relative" zIndex={10} w="full">
|
||||
<HStack
|
||||
as="header"
|
||||
aria-label="Main navigation"
|
||||
maxW="7xl"
|
||||
w="full"
|
||||
mx="auto"
|
||||
px={{ base: '6', md: '8' }}
|
||||
py="4"
|
||||
justify="space-between"
|
||||
>
|
||||
<Flex
|
||||
align="center"
|
||||
justify="space-between"
|
||||
className="nav-content__mobile"
|
||||
color={mode('white', 'white')}
|
||||
>
|
||||
<HStack as={Link} href="/" rel="home" ml="2">
|
||||
<Logo boxSize="35px" />
|
||||
<Heading as="p" fontSize="lg">
|
||||
Typebot
|
||||
</Heading>
|
||||
</HStack>
|
||||
</Flex>
|
||||
<Box display={['block', 'block', 'none']}>
|
||||
<IconButton
|
||||
aria-label={'Open menu'}
|
||||
icon={
|
||||
isMobileMenuOpen ? (
|
||||
<CloseIcon boxSize="20px" />
|
||||
) : (
|
||||
<HamburgerIcon boxSize="20px" />
|
||||
)
|
||||
}
|
||||
variant="ghost"
|
||||
colorScheme="gray"
|
||||
onClick={onMobileMenuToggle}
|
||||
/>
|
||||
<MobileMenu isOpen={isMobileMenuOpen} />
|
||||
</Box>
|
||||
<HStack as="nav" spacing={4} display={['none', 'none', 'flex']}>
|
||||
<Flex>
|
||||
<Button
|
||||
rightIcon={<ChevronDownIcon />}
|
||||
onClick={onToggle}
|
||||
variant="ghost"
|
||||
colorScheme="gray"
|
||||
fontWeight={700}
|
||||
>
|
||||
Resources
|
||||
</Button>
|
||||
<ResourcesMenu isOpen={isOpen} />
|
||||
</Flex>
|
||||
<Button
|
||||
as={Link}
|
||||
href="/pricing"
|
||||
variant="ghost"
|
||||
colorScheme="gray"
|
||||
fontWeight={700}
|
||||
>
|
||||
Pricing
|
||||
</Button>
|
||||
<Button
|
||||
as={Link}
|
||||
href="https://app.typebot.io/signin"
|
||||
colorScheme="blue"
|
||||
variant="outline"
|
||||
fontWeight={700}
|
||||
>
|
||||
Sign in
|
||||
</Button>
|
||||
<Button
|
||||
as={Link}
|
||||
href="https://app.typebot.io/register"
|
||||
colorScheme="orange"
|
||||
fontWeight={700}
|
||||
>
|
||||
Create a typebot
|
||||
</Button>
|
||||
</HStack>
|
||||
</HStack>
|
||||
</Flex>
|
||||
)
|
||||
}
|
59
ee/apps/landing-page/components/common/Header/MobileMenu.tsx
Normal file
59
ee/apps/landing-page/components/common/Header/MobileMenu.tsx
Normal file
@ -0,0 +1,59 @@
|
||||
import { Collapse, Stack, Button, Text } from '@chakra-ui/react'
|
||||
import Link from 'next/link'
|
||||
import { links } from './_data'
|
||||
|
||||
type Props = { isOpen: boolean }
|
||||
|
||||
export const MobileMenu = ({ isOpen }: Props) => (
|
||||
<Collapse in={isOpen}>
|
||||
<Stack
|
||||
pos="absolute"
|
||||
insetX={0}
|
||||
bgGradient="linear(to-b, gray.900, gray.800)"
|
||||
px="6"
|
||||
py="10"
|
||||
spacing={4}
|
||||
>
|
||||
<Button
|
||||
as={Link}
|
||||
href="https://app.typebot.io/signin"
|
||||
colorScheme="blue"
|
||||
variant="outline"
|
||||
fontWeight={700}
|
||||
>
|
||||
Sign in
|
||||
</Button>
|
||||
<Button
|
||||
as={Link}
|
||||
href="https://app.typebot.io/register"
|
||||
colorScheme="orange"
|
||||
fontWeight={700}
|
||||
>
|
||||
Create a typebot
|
||||
</Button>
|
||||
<Button
|
||||
as={Link}
|
||||
href="/pricing"
|
||||
variant="outline"
|
||||
colorScheme="gray"
|
||||
fontWeight={700}
|
||||
>
|
||||
Pricing
|
||||
</Button>
|
||||
<Text fontWeight="700">Resources:</Text>
|
||||
{links[0].children?.map((link, idx) => (
|
||||
<Button
|
||||
as={Link}
|
||||
href={link.href}
|
||||
key={idx}
|
||||
variant="outline"
|
||||
colorScheme="gray"
|
||||
fontWeight={700}
|
||||
py="6"
|
||||
>
|
||||
{link.label}
|
||||
</Button>
|
||||
))}
|
||||
</Stack>
|
||||
</Collapse>
|
||||
)
|
92
ee/apps/landing-page/components/common/Header/ResourcesMenu.tsx
Executable file
92
ee/apps/landing-page/components/common/Header/ResourcesMenu.tsx
Executable file
@ -0,0 +1,92 @@
|
||||
import {
|
||||
Box,
|
||||
Center,
|
||||
Collapse,
|
||||
HStack,
|
||||
SimpleGrid,
|
||||
Text,
|
||||
useColorModeValue as mode,
|
||||
} from '@chakra-ui/react'
|
||||
import { ChevronRightIcon } from 'assets/icons/ChevronRightIcon'
|
||||
import Link from 'next/link'
|
||||
import * as React from 'react'
|
||||
import { links } from './_data'
|
||||
|
||||
type Props = { isOpen: boolean }
|
||||
|
||||
export const ResourcesMenu = ({ isOpen }: Props) => (
|
||||
<Collapse in={isOpen} animateOpacity unmountOnExit={false}>
|
||||
<Box
|
||||
w="full"
|
||||
shadow="lg"
|
||||
pos="absolute"
|
||||
insetX={0}
|
||||
top="16"
|
||||
py="12"
|
||||
px="4"
|
||||
bgGradient="linear(to-b, gray.900, gray.800)"
|
||||
>
|
||||
<Box maxW="7xl" mx="auto" px="8">
|
||||
<SimpleGrid spacing="10" columns={2}>
|
||||
{links[0].children?.map((item, idx) => (
|
||||
<Box
|
||||
as={Link}
|
||||
key={idx}
|
||||
className="group"
|
||||
href={item.href}
|
||||
m="-3"
|
||||
p="3"
|
||||
display="flex"
|
||||
alignItems="flex-start"
|
||||
transition="all 0.2s"
|
||||
rounded="lg"
|
||||
_hover={{ bg: mode('gray.50', 'gray.600') }}
|
||||
_focus={{ shadow: 'outline' }}
|
||||
target={
|
||||
item.href.startsWith('https') &&
|
||||
!item.href.includes('app.typebot.io')
|
||||
? '_blank'
|
||||
: undefined
|
||||
}
|
||||
>
|
||||
<Center
|
||||
aria-hidden
|
||||
as="span"
|
||||
flexShrink={0}
|
||||
w="10"
|
||||
h="10"
|
||||
fontSize="3xl"
|
||||
color={'blue.300'}
|
||||
>
|
||||
{item.icon}
|
||||
</Center>
|
||||
<Box marginStart="3" as="dl">
|
||||
<HStack as="dt">
|
||||
<Text
|
||||
fontWeight="semibold"
|
||||
color={mode('gray.900', 'white')}
|
||||
_groupHover={{ color: mode('blue.600', 'inherit') }}
|
||||
>
|
||||
{item.label}
|
||||
</Text>
|
||||
<Box
|
||||
fontSize="xs"
|
||||
as={ChevronRightIcon}
|
||||
transition="all 0.2s"
|
||||
_groupHover={{
|
||||
color: mode('blue.600', 'inherit'),
|
||||
transform: 'translateX(2px)',
|
||||
}}
|
||||
/>
|
||||
</HStack>
|
||||
<Text as="dd" color={mode('gray.500', 'gray.400')}>
|
||||
{item.description}
|
||||
</Text>
|
||||
</Box>
|
||||
</Box>
|
||||
))}
|
||||
</SimpleGrid>
|
||||
</Box>
|
||||
</Box>
|
||||
</Collapse>
|
||||
)
|
41
ee/apps/landing-page/components/common/Header/_data.tsx
Executable file
41
ee/apps/landing-page/components/common/Header/_data.tsx
Executable file
@ -0,0 +1,41 @@
|
||||
import { GitHubIcon } from 'assets/icons'
|
||||
import { DocIcon } from 'assets/icons/DocIcon'
|
||||
import { MapIcon } from 'assets/icons/MapIcon'
|
||||
import { PeopleCircleIcon } from 'assets/icons/PeopleCircleIcon'
|
||||
import * as React from 'react'
|
||||
|
||||
export const links = [
|
||||
{
|
||||
label: 'Resources',
|
||||
children: [
|
||||
{
|
||||
label: 'GitHub repository',
|
||||
description: 'Check out the entire source code of the project',
|
||||
href: 'https://github.com/baptisteArno/typebot.io',
|
||||
icon: <GitHubIcon fill="blue.300" />,
|
||||
},
|
||||
{
|
||||
label: 'Documentation',
|
||||
description:
|
||||
"Everything you need to know about how to use Typebot's builder",
|
||||
href: 'https://docs.typebot.io',
|
||||
icon: <DocIcon />,
|
||||
},
|
||||
{
|
||||
label: 'Roadmap',
|
||||
description:
|
||||
"Follow the development and make suggestions for which features you'd like to see",
|
||||
href: 'https://feedback.typebot.io/roadmap',
|
||||
icon: <MapIcon />,
|
||||
},
|
||||
{
|
||||
label: 'Community',
|
||||
description:
|
||||
'Join the Discord server and learn about chatbots best practices and get help from the community',
|
||||
href: '/discord',
|
||||
icon: <PeopleCircleIcon />,
|
||||
},
|
||||
],
|
||||
},
|
||||
{ label: 'Pricing', href: '/pricing' },
|
||||
]
|
36
ee/apps/landing-page/components/common/SocialMetaTags.tsx
Normal file
36
ee/apps/landing-page/components/common/SocialMetaTags.tsx
Normal file
@ -0,0 +1,36 @@
|
||||
import Head from 'next/head'
|
||||
import React from 'react'
|
||||
|
||||
export const SocialMetaTags = ({
|
||||
title = 'Typebot - Open-source conversational apps builder',
|
||||
description = 'Powerful blocks to create unique chat experiences. Embed them anywhere on your apps and start collecting results like magic.',
|
||||
currentUrl,
|
||||
imagePreviewUrl = 'https://home.typebot.io/images/preview.png',
|
||||
}: {
|
||||
title?: string
|
||||
description?: string
|
||||
currentUrl: string
|
||||
imagePreviewUrl?: string
|
||||
}) => (
|
||||
<Head>
|
||||
<title>{title}</title>
|
||||
<meta name="title" content={title} />
|
||||
<meta property="og:title" content={title} />
|
||||
<meta property="twitter:title" content={title} />
|
||||
|
||||
<meta property="twitter:url" content={currentUrl} />
|
||||
<meta property="og:url" content={currentUrl} />
|
||||
|
||||
<meta name="description" content={description} />
|
||||
<meta property="twitter:description" content={description} />
|
||||
<meta property="og:description" content={description} />
|
||||
|
||||
<meta property="og:image" content={imagePreviewUrl} />
|
||||
<meta property="twitter:image" content={imagePreviewUrl} />
|
||||
|
||||
<meta property="og:type" content="website" />
|
||||
<meta property="twitter:card" content="summary_large_image" />
|
||||
|
||||
<meta property="fb:app_id" content="2919783058077552" />
|
||||
</Head>
|
||||
)
|
26
ee/apps/landing-page/components/common/TableCells.tsx
Normal file
26
ee/apps/landing-page/components/common/TableCells.tsx
Normal file
@ -0,0 +1,26 @@
|
||||
import { CheckCircleIcon } from 'assets/icons/CheckCircleIcon'
|
||||
import { CloseIcon } from 'assets/icons/CloseIcon'
|
||||
import { Td, Text } from '@chakra-ui/react'
|
||||
import React, { ReactNode } from 'react'
|
||||
|
||||
export const Yes = (props: { children?: ReactNode }) => (
|
||||
<Td display={props.children ? 'flex' : ''}>
|
||||
<CheckCircleIcon fill="#0042da" width="25px" />
|
||||
{props.children && (
|
||||
<Text ml={1} fontSize="sm">
|
||||
{props.children}
|
||||
</Text>
|
||||
)}
|
||||
</Td>
|
||||
)
|
||||
|
||||
export const No = (props: { children?: ReactNode }) => (
|
||||
<Td display={props.children ? 'flex' : ''}>
|
||||
<CloseIcon width="25px" />
|
||||
{props.children && (
|
||||
<Text ml={1} fontSize="sm">
|
||||
{props.children}
|
||||
</Text>
|
||||
)}
|
||||
</Td>
|
||||
)
|
37
ee/apps/landing-page/components/common/TextLink.tsx
Normal file
37
ee/apps/landing-page/components/common/TextLink.tsx
Normal file
@ -0,0 +1,37 @@
|
||||
import Link, { LinkProps } from 'next/link'
|
||||
import React from 'react'
|
||||
import { chakra, HStack, TextProps } from '@chakra-ui/react'
|
||||
import { ExternalLinkIcon } from 'assets/icons/ExternalLinkIcon'
|
||||
|
||||
type TextLinkProps = LinkProps & TextProps & { isExternal?: boolean }
|
||||
|
||||
export const TextLink = ({
|
||||
children,
|
||||
href,
|
||||
shallow,
|
||||
replace,
|
||||
scroll,
|
||||
prefetch,
|
||||
isExternal,
|
||||
...textProps
|
||||
}: TextLinkProps) => (
|
||||
<Link
|
||||
href={href}
|
||||
shallow={shallow}
|
||||
replace={replace}
|
||||
scroll={scroll}
|
||||
prefetch={prefetch}
|
||||
target={isExternal ? '_blank' : undefined}
|
||||
>
|
||||
<chakra.span textDecor="underline" display="inline-block" {...textProps}>
|
||||
{isExternal ? (
|
||||
<HStack as="span" spacing={1}>
|
||||
<chakra.span>{children}</chakra.span>
|
||||
<ExternalLinkIcon />
|
||||
</HStack>
|
||||
) : (
|
||||
children
|
||||
)}
|
||||
</chakra.span>
|
||||
</Link>
|
||||
)
|
Reference in New Issue
Block a user