diff --git a/.github/workflows/docsearch-scrap.yml b/.github/workflows/docsearch-scrap.yml new file mode 100644 index 000000000..842a4da4b --- /dev/null +++ b/.github/workflows/docsearch-scrap.yml @@ -0,0 +1,17 @@ +name: Docsearch Scrap + +on: + schedule: + - cron: '0 8 * * *' + +jobs: + scrap: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + - uses: darrenjennings/algolia-docsearch-action@master + with: + algolia_application_id: 'DXYNLHZTGJ' + algolia_api_key: ${{secrets.DOCSEARCH_API_KEY}} + file: 'apps/docs/docsearch-scrapper-config.json' diff --git a/.gitignore b/.gitignore index 7aeb7f11a..1d1762b48 100644 --- a/.gitignore +++ b/.gitignore @@ -12,3 +12,6 @@ dist test-results **/api/scripts .sentryclirc +.docusaurus +.cache-loader +build diff --git a/apps/builder/.env.local.example b/apps/builder/.env.local.example index 16e54e174..6971e98ef 100644 --- a/apps/builder/.env.local.example +++ b/apps/builder/.env.local.example @@ -38,6 +38,8 @@ FACEBOOK_CLIENT_SECRET= # (Optional) Subscription Payment NEXT_PUBLIC_STRIPE_PUBLIC_KEY= STRIPE_SECRET_KEY= +STRIPE_PRICE_USD_ID= +STRIPE_PRICE_EUR_ID= STRIPE_WEBHOOK_SECRET= # (Optional) Used for GIF search diff --git a/apps/builder/components/account/BillingSection.tsx b/apps/builder/components/account/BillingSection.tsx index 1d14bdea5..2d5f984c2 100644 --- a/apps/builder/components/account/BillingSection.tsx +++ b/apps/builder/components/account/BillingSection.tsx @@ -8,6 +8,7 @@ import { useToast, } from '@chakra-ui/react' import { NextChakraLink } from 'components/nextChakra/NextChakraLink' +import { UpgradeButton } from 'components/shared/buttons/UpgradeButton' import { useUser } from 'contexts/UserContext' import { Plan } from 'db' import { useRouter } from 'next/router' @@ -54,9 +55,7 @@ export const BillingSection = () => { Manage my subscription )} - {user?.plan === Plan.FREE && ( - - )} + {user?.plan === Plan.FREE && } {user?.plan === Plan.FREE && ( diff --git a/apps/builder/components/auth/SignInForm.tsx b/apps/builder/components/auth/SignInForm.tsx index e89e55e94..fe74157b2 100644 --- a/apps/builder/components/auth/SignInForm.tsx +++ b/apps/builder/components/auth/SignInForm.tsx @@ -28,7 +28,8 @@ export const SignInForm = ({ }) useEffect(() => { - if (status === 'authenticated') router.replace('/typebots') + if (status === 'authenticated') + router.replace({ pathname: '/typebots', query: router.query }) }, [status, router]) const handleEmailChange = (e: ChangeEvent) => diff --git a/apps/builder/components/auth/SocialLoginButtons.tsx b/apps/builder/components/auth/SocialLoginButtons.tsx index 760619d57..c95c1a42f 100644 --- a/apps/builder/components/auth/SocialLoginButtons.tsx +++ b/apps/builder/components/auth/SocialLoginButtons.tsx @@ -1,16 +1,28 @@ import { Stack, Button } from '@chakra-ui/react' import { FacebookIcon, GithubIcon, GoogleIcon } from 'assets/icons' import { signIn, useSession } from 'next-auth/react' +import { useRouter } from 'next/router' import React from 'react' +import { stringify } from 'qs' export const SocialLoginButtons = () => { + const { query } = useRouter() const { status } = useSession() - const handleGitHubClick = async () => signIn('github') + const handleGitHubClick = async () => + signIn('github', { + callbackUrl: `/typebots?${stringify(query)}`, + }) - const handleGoogleClick = async () => signIn('google') + const handleGoogleClick = async () => + signIn('google', { + callbackUrl: `/typebots?${stringify(query)}`, + }) - const handleFacebookClick = async () => signIn('facebook') + const handleFacebookClick = async () => + signIn('facebook', { + callbackUrl: `/typebots?${stringify(query)}`, + }) return ( diff --git a/apps/builder/components/shared/buttons/UpgradeButton.tsx b/apps/builder/components/shared/buttons/UpgradeButton.tsx new file mode 100644 index 000000000..0307b08f8 --- /dev/null +++ b/apps/builder/components/shared/buttons/UpgradeButton.tsx @@ -0,0 +1,16 @@ +import { Button, ButtonProps, useDisclosure } from '@chakra-ui/react' +import React from 'react' +import { UpgradeModal } from '../modals/UpgradeModal.' +import { LimitReached } from '../modals/UpgradeModal./UpgradeModal' + +type Props = { type?: LimitReached } & ButtonProps + +export const UpgradeButton = ({ type, ...props }: Props) => { + const { isOpen, onOpen, onClose } = useDisclosure() + return ( + + ) +} diff --git a/apps/builder/components/shared/modals/UpgradeModal./UpgradeModal.tsx b/apps/builder/components/shared/modals/UpgradeModal./UpgradeModal.tsx index 3e8e64f12..007324b96 100644 --- a/apps/builder/components/shared/modals/UpgradeModal./UpgradeModal.tsx +++ b/apps/builder/components/shared/modals/UpgradeModal./UpgradeModal.tsx @@ -31,10 +31,12 @@ type UpgradeModalProps = { export const UpgradeModal = ({ type, onClose, isOpen }: UpgradeModalProps) => { const { user } = useUser() const [payLoading, setPayLoading] = useState(false) - const [userLanguage, setUserLanguage] = useState('en') + const [currency, setCurrency] = useState<'usd' | 'eur'>('usd') useEffect(() => { - setUserLanguage(navigator.language.toLowerCase()) + setCurrency( + navigator.languages.find((l) => l.includes('fr')) ? 'eur' : 'usd' + ) }, []) let limitLabel @@ -55,7 +57,7 @@ export const UpgradeModal = ({ type, onClose, isOpen }: UpgradeModalProps) => { const handlePayClick = async () => { if (!user) return setPayLoading(true) - await pay(user) + await pay(user, currency) } return ( @@ -73,7 +75,7 @@ export const UpgradeModal = ({ type, onClose, isOpen }: UpgradeModalProps) => { )} { + const mailgun = new Mailgun(formData) + return mailgun.client({ + username: 'api', + key: '0b024a6aac02d3f52d30999674bcde30-53c13666-e8653f58', + url: 'https://api.eu.mailgun.net', + }) +} diff --git a/apps/builder/package.json b/apps/builder/package.json index 22b311855..00bcf1dfd 100644 --- a/apps/builder/package.json +++ b/apps/builder/package.json @@ -44,6 +44,7 @@ "deep-object-diff": "^1.1.7", "fast-equals": "^2.0.4", "focus-visible": "^5.2.0", + "form-data": "^4.0.0", "framer-motion": "^4", "google-auth-library": "^7.11.0", "google-spreadsheet": "^3.2.0", @@ -52,6 +53,7 @@ "immer": "^9.0.12", "js-video-url-parser": "^0.5.1", "kbar": "^0.1.0-beta.24", + "mailgun.js": "^4.2.1", "micro": "^9.3.4", "micro-cors": "^0.1.1", "models": "*", diff --git a/apps/builder/pages/api/auth/[...nextauth].ts b/apps/builder/pages/api/auth/[...nextauth].ts index 665a702d0..27b5e35d1 100644 --- a/apps/builder/pages/api/auth/[...nextauth].ts +++ b/apps/builder/pages/api/auth/[...nextauth].ts @@ -19,6 +19,13 @@ const providers: Provider[] = [ }, }, from: `"${process.env.AUTH_EMAIL_FROM_NAME}" <${process.env.AUTH_EMAIL_FROM_EMAIL}>`, + // sendVerificationRequest({ + // identifier: email, + // url, + // provider: { server, from }, + // }) { + // console.log(url) + // }, }), ] diff --git a/apps/builder/pages/api/stripe/checkout.ts b/apps/builder/pages/api/stripe/checkout.ts index 8ccdd079a..22fd9e49c 100644 --- a/apps/builder/pages/api/stripe/checkout.ts +++ b/apps/builder/pages/api/stripe/checkout.ts @@ -3,7 +3,6 @@ import { methodNotAllowed } from 'utils' import Stripe from 'stripe' import { withSentry } from '@sentry/nextjs' -const usdPriceIdTest = 'price_1Jc4TQKexUFvKTWyGvsH4Ff5' const handler = async (req: NextApiRequest, res: NextApiResponse) => { if (req.method === 'POST') { if (!process.env.STRIPE_SECRET_KEY) @@ -11,21 +10,25 @@ const handler = async (req: NextApiRequest, res: NextApiResponse) => { const stripe = new Stripe(process.env.STRIPE_SECRET_KEY, { apiVersion: '2020-08-27', }) - const { email } = req.body + const { email, currency } = JSON.parse(req.body) const session = await stripe.checkout.sessions.create({ success_url: `${req.headers.origin}/typebots?stripe=success`, cancel_url: `${req.headers.origin}/typebots?stripe=cancel`, automatic_tax: { enabled: true }, allow_promotion_codes: true, customer_email: email, + mode: 'subscription', line_items: [ { - price: usdPriceIdTest, + price: + currency === 'eur' + ? process.env.STRIPE_PRICE_EUR_ID + : process.env.STRIPE_PRICE_USD_ID, quantity: 1, }, ], }) - res.status(201).send({ sessionId: session.id }) + return res.status(201).send({ sessionId: session.id }) } return methodNotAllowed(res) } diff --git a/apps/builder/pages/api/stripe/customer-portal.ts b/apps/builder/pages/api/stripe/customer-portal.ts index f9be04567..e50a174bb 100644 --- a/apps/builder/pages/api/stripe/customer-portal.ts +++ b/apps/builder/pages/api/stripe/customer-portal.ts @@ -20,9 +20,10 @@ const handler = async (req: NextApiRequest, res: NextApiResponse) => { }) const session = await stripe.billingPortal.sessions.create({ customer: user.stripeId, - return_url: `${req.headers.origin}/account`, + return_url: req.headers.referer, }) - res.status(201).redirect(session.url) + res.redirect(session.url) + return } return methodNotAllowed(res) } diff --git a/apps/builder/pages/api/stripe/webhook.ts b/apps/builder/pages/api/stripe/webhook.ts index 5dc101ae9..606d05605 100644 --- a/apps/builder/pages/api/stripe/webhook.ts +++ b/apps/builder/pages/api/stripe/webhook.ts @@ -47,6 +47,7 @@ const webhookHandler = async (req: NextApiRequest, res: NextApiResponse) => { where: { email: customer_email }, data: { plan: Plan.PRO, stripeId: session.customer as string }, }) + return res.status(200).send({ message: 'user upgraded in DB' }) } case 'customer.subscription.deleted': { const subscription = event.data.object as Stripe.Subscription @@ -58,6 +59,10 @@ const webhookHandler = async (req: NextApiRequest, res: NextApiResponse) => { plan: Plan.FREE, }, }) + return res.status(200).send({ message: 'user downgraded in DB' }) + } + default: { + return res.status(304).send({ message: 'event not handled' }) } } } catch (err) { diff --git a/apps/builder/pages/typebots.tsx b/apps/builder/pages/typebots.tsx index ec10e4752..abbd013b5 100644 --- a/apps/builder/pages/typebots.tsx +++ b/apps/builder/pages/typebots.tsx @@ -1,17 +1,65 @@ -import React from 'react' -import { Stack } from '@chakra-ui/layout' +import React, { useEffect, useState } from 'react' +import { Flex, Stack } from '@chakra-ui/layout' import { DashboardHeader } from 'components/dashboard/DashboardHeader' import { Seo } from 'components/Seo' import { FolderContent } from 'components/dashboard/FolderContent' import { TypebotDndContext } from 'contexts/TypebotDndContext' +import { useRouter } from 'next/router' +import { redeemCoupon } from 'services/coupons' +import { Spinner, useToast } from '@chakra-ui/react' +import { pay } from 'services/stripe' +import { useUser } from 'contexts/UserContext' const DashboardPage = () => { + const [isLoading, setIsLoading] = useState(false) + const { query, isReady } = useRouter() + const { user } = useUser() + const toast = useToast({ + position: 'top-right', + status: 'success', + }) + + useEffect(() => { + const subscribe = query.subscribe?.toString() + if (subscribe && user && user.plan === 'FREE') { + setIsLoading(true) + pay( + user, + navigator.languages.find((l) => l.includes('fr')) ? 'eur' : 'usd' + ) + } + }, [query.subscribe, user]) + + useEffect(() => { + if (!isReady) return + const couponCode = query.coupon?.toString() + const stripeStatus = query.stripe?.toString() + + if (stripeStatus === 'success') + toast({ + title: 'Typebot Pro', + description: "You've successfully subscribed 🎉", + }) + if (!couponCode) return + setIsLoading(true) + redeemCoupon(couponCode).then(() => { + location.href = '/typebots' + }) + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [isReady]) + return ( - + {isLoading ? ( + + + + ) : ( + + )} ) diff --git a/apps/builder/services/stripe.ts b/apps/builder/services/stripe.ts index 2112c6d26..87a916b7f 100644 --- a/apps/builder/services/stripe.ts +++ b/apps/builder/services/stripe.ts @@ -2,14 +2,14 @@ import { User } from 'db' import { loadStripe } from '@stripe/stripe-js' import { sendRequest } from 'utils' -export const pay = async (user: User) => { +export const pay = async (user: User, currency: 'usd' | 'eur') => { if (!process.env.NEXT_PUBLIC_STRIPE_PUBLIC_KEY) throw new Error('NEXT_PUBLIC_STRIPE_PUBLIC_KEY is missing in env') const stripe = await loadStripe(process.env.NEXT_PUBLIC_STRIPE_PUBLIC_KEY) const { data, error } = await sendRequest<{ sessionId: string }>({ method: 'POST', url: '/api/stripe/checkout', - body: { email: user.email }, + body: { email: user.email, currency }, }) if (error || !data) return return stripe?.redirectToCheckout({ diff --git a/apps/docs/README.md b/apps/docs/README.md new file mode 100644 index 000000000..2de7dfa32 --- /dev/null +++ b/apps/docs/README.md @@ -0,0 +1,33 @@ +# Typebot docs + +This is the source code of Typebot's documentation located at https://docs.typebot.io + +# Contribute + +If you're not technical or not familiar with how GitHub works, you can send your written documents directly to [baptiste@typebot.io](mailto:baptiste@typebot.io). You will be mentioned as a contributor 🥰 + +# Website + +This website is built using [Docusaurus 2](https://docusaurus.io/), a modern static website generator. + +## Installation + +```console +yarn install +``` + +## Local Development + +```console +yarn start +``` + +This command starts a local development server and opens up a browser window. Most changes are reflected live without having to restart the server. + +## Build + +```console +yarn build +``` + +This command generates static content into the `build` directory and can be served using any static contents hosting service. diff --git a/apps/docs/babel.config.js b/apps/docs/babel.config.js new file mode 100644 index 000000000..e00595dae --- /dev/null +++ b/apps/docs/babel.config.js @@ -0,0 +1,3 @@ +module.exports = { + presets: [require.resolve('@docusaurus/core/lib/babel/preset')], +}; diff --git a/apps/docs/docs/embed/_category_.json b/apps/docs/docs/embed/_category_.json new file mode 100644 index 000000000..dc640b098 --- /dev/null +++ b/apps/docs/docs/embed/_category_.json @@ -0,0 +1,4 @@ +{ + "label": "Embed", + "position": 5 +} diff --git a/apps/docs/docs/embed/iframe.md b/apps/docs/docs/embed/iframe.md new file mode 100644 index 000000000..9d27927a1 --- /dev/null +++ b/apps/docs/docs/embed/iframe.md @@ -0,0 +1,11 @@ +--- +sidebar_position: 3 +--- + +# Iframe + +You can easily get your typebot iframe code by clicking on the "Iframe" button in the "Share" tab of your typebot. + +Iframe preview + +Here, you can set up its width and height. A good default is a `width` of `100%` and a `height` of `600px`. diff --git a/apps/docs/docs/embed/javascript-commands.md b/apps/docs/docs/embed/javascript-commands.md new file mode 100644 index 000000000..fb099b0f6 --- /dev/null +++ b/apps/docs/docs/embed/javascript-commands.md @@ -0,0 +1,65 @@ +--- +sidebar_position: 4 +--- + +# Javascript library + +Typebot Javascript library is open-source ([check out the repository](https://github.com/typebot-io/typebot-js)). Feel free to contribute if you're a developer and wish to improve its features. + +Whenever a typebot is embedded on your website, you have access to commands to automatically trigger actions on your embedding depending on its type. + +## Popup + +### Open or Close a popup + +You can use these commands: + +```js +Typebot.getPopupActions().open(); +``` + +```js +Typebot.getPopupActions().close(); +``` + +You can bind these commands on a button element, for example: + +```html + +``` + +## Bubble + +### Open or close the proactive message + +You can use this command: + +```js +Typebot.getBubbleActions().openProactiveMessage(); +``` + +You can bind this command on a button element, for example: + +```html + +``` + +### Open or close the typebot + +You can use these commands: + +```js +Typebot.getBubbleActions().open(); +``` + +```js +Typebot.getBubbleActions().close(); +``` + +You can bind these commands on a button element, for example: + +```html + +``` diff --git a/apps/docs/docs/embed/overview.md b/apps/docs/docs/embed/overview.md new file mode 100644 index 000000000..2427d0987 --- /dev/null +++ b/apps/docs/docs/embed/overview.md @@ -0,0 +1,28 @@ +--- +sidebar_position: 1 +--- + +# Overview + +You can choose to embed your typebot in 3 different ways. + +## Standard + +Embeds the typebot in a box with the size of your choice. This type is used at the top of [Typebot's homepage](https://www.typebot.io/) + +Standard + +You can also set the width to `100%` and the height to `100vh` to make it take the entire page dimensions + +## Popup + +Embeds the typebot in a Popup that overlays your website. It can be triggered after a delay or with a click of a button for example + +Popup + +## Bubble + +Embeds the typebot as a "chat bubble" at the bottom right corner of your site. Can be triggered automatically or with a click. It can also come with a "proactive message". An example can be found in [Typebot's pricing page](https://www.typebot.io/pricing) + +Bubble 1 +Bubble 2 diff --git a/apps/docs/docs/embed/wordpress.md b/apps/docs/docs/embed/wordpress.md new file mode 100644 index 000000000..21425d7e8 --- /dev/null +++ b/apps/docs/docs/embed/wordpress.md @@ -0,0 +1,103 @@ +--- +sidebar_position: 2 +--- + +# WordPress + +Typebot has a native [WordPress plug-in](https://wordpress.org/plugins/typebot/) that helps you embed typebots in your WordPress site. + +Of course, before using it, you need to create and publish your first typebot. + +WP plugin preview + +You can either choose to configurate an "easy setup" or "advanced setup". + +## Easy setup + +### Container + +When choosing "container" and click on "Save" you can then use a typebot shortcode in your page builder. [Here is a complete tutorial on how to insert a shortcode](https://www.wpbeginner.com/wp-tutorials/how-to-add-a-shortcode-in-wordpress/). + +Here is how it looks like: + +```text +[typebot width="100%" height="500px" background-color="#F7F8FF"] +``` + +`width`, `height`, `background-color` and `url` are optionnal. + +You should use `url` parameter only if you need to embed different typebots as containers on your website. + +If your typebot appears to have a small height like this: +WP plugin preview + +you need to set a fixed `height` in pixel (`500px` or `600px` is usually a great number). + +### Popup & Bubble + +Fields are self explanatory. + +#### Pages to include separated by a comma + +With this field, you can tell the plugin to include the typebot only on specific pages. + +Example: + +- `/my-page,/other-page/*`: the typebot will appear on these pages: `/my-page`, `/other-page`, `/other-page/sub/path`, `/other-page/other/path` + +## Advanced setup + +This config allows you to directly paste the code from "HTML & Javascript" instructions in the Share page. So that you can set your own logic if needed. + +Here is an example for a bubble config: + +```html + + + +``` + +## Personalize user experience (Hidden variables) + +You can leverage the hidden variables and inject your user information directly into your typebot so that the experience is entirely customized to your user. Here are the available variables from WordPress: + +WP predefined variables + +Then you can use these variables anywhere on your typebot. For more informations, check out the [Hidden variables doc](https://docs.typebot.io/editor/variables/hidden-variables) + +## Your typebot isn't showing? + +### You have a cache plugin + +Plugins like WP Rocket prevent Typebot to work. + +For WP Rocket: + +1. Go to Settings > WP Rocket > Excluded Inline Javascript: + +WP plugin preview + +2. Type "typebot" +3. Save + +### You have plugin that adds `defer` attribute to external scripts + +You need to add an exception for Typebot in the corresponding plugin config. + +### Still not working + +Contact me on the application using the typebot at the bottom right corner diff --git a/apps/docs/docs/get-started/_category_.json b/apps/docs/docs/get-started/_category_.json new file mode 100644 index 000000000..1bf165d40 --- /dev/null +++ b/apps/docs/docs/get-started/_category_.json @@ -0,0 +1,4 @@ +{ + "label": "Get Started", + "position": 1 +} diff --git a/apps/docs/docs/get-started/overview.md b/apps/docs/docs/get-started/overview.md new file mode 100644 index 000000000..2e7a8d2a2 --- /dev/null +++ b/apps/docs/docs/get-started/overview.md @@ -0,0 +1,9 @@ +--- +sidebar_position: 2 +--- + +# Overview + +The best way for me to show you Typebot's simplicity is through a product tour video: + + diff --git a/apps/docs/docs/get-started/welcome.md b/apps/docs/docs/get-started/welcome.md new file mode 100644 index 000000000..cabe9433c --- /dev/null +++ b/apps/docs/docs/get-started/welcome.md @@ -0,0 +1,14 @@ +--- +sidebar_position: 1 +slug: / +--- + +# Welcome + +[Typebot](https://www.typebot.io) is a conversational form builder that helps you collect more responses compared to other form builders (Typeform, Google Forms, Tally...). + +This is the Typebot documentation. It's a great place to find most answers. Please use the search box in the top right or the navigation menu (soon available) on the left-hand side to find the answers you're looking for. + +This documentation is a work in progress. + +If you can't find what you're looking for, don't hesitate to contact me directly on the web app or at baptiste@typebot.io. diff --git a/apps/docs/docsearch-scrapper-config.json b/apps/docs/docsearch-scrapper-config.json new file mode 100644 index 000000000..26bb4805a --- /dev/null +++ b/apps/docs/docsearch-scrapper-config.json @@ -0,0 +1,19 @@ +{ + "index_name": "typebot", + "start_urls": ["https://docs.typebot.io/"], + "stop_urls": ["open-typebot=true$"], + "selectors": { + "lvl0": { + "selector": ".menu__link--sublist.menu__link--active", + "global": true, + "default_value": "Documentation" + }, + "lvl1": "[class^='docItemContainer_'] h1", + "lvl2": "[class^='docItemContainer_'] h2", + "lvl3": "[class^='docItemContainer_'] h3", + "lvl4": "[class^='docItemContainer_'] h4", + "lvl5": "[class^='docItemContainer_'] h5", + "text": "[class^='docItemContainer_'] p, [class^='docItemContainer_'] li" + }, + "selectors_exclude": [".hash-link"] +} diff --git a/apps/docs/docusaurus.config.js b/apps/docs/docusaurus.config.js new file mode 100644 index 000000000..5e4e3ce69 --- /dev/null +++ b/apps/docs/docusaurus.config.js @@ -0,0 +1,101 @@ +/** @type {import('@docusaurus/types').DocusaurusConfig} */ +module.exports = { + title: "Typebot docs", + tagline: "Get to Typebot next level with its documentation", + url: "https://docs.typebot.io", + baseUrl: "/", + onBrokenLinks: "warn", + onBrokenMarkdownLinks: "warn", + favicon: "img/favicon.png", + organizationName: "Typebot_io", // Usually your GitHub org/user name. + themeConfig: { + navbar: { + title: "Typebot", + logo: { + alt: "Typebot Logo", + src: "img/logo.svg", + }, + items: [ + { + href: "https://github.com/typebot-io/docs", + label: "Contribute", + position: "right", + }, + ], + }, + algolia: { + apiKey: "d2e121d4ad4e5346ac2c3329424981a1", + indexName: "typebot", + appId: "DXYNLHZTGJ", + }, + footer: { + links: [ + { + title: "Product", + items: [ + { + label: "Homepage", + to: "https://www.typebot.io", + }, + { + label: "Roadmap", + to: "https://feedback.typebot.io", + }, + { + label: "Blog", + to: "https://www.typebot.io/blog", + }, + ], + }, + { + title: "Community", + items: [ + { + label: "Facebook Group", + href: "https://www.facebook.com/groups/typebot", + }, + { + label: "Twitter", + href: "https://twitter.com/Typebot_io", + }, + ], + }, + { + title: "Company", + items: [ + { + label: "About", + to: "https://www.typebot.io/about", + }, + { + label: "Terms of Service", + href: "https://www.typebot.io/terms-of-service", + }, + { + label: "Privacy Policy", + href: "https://www.typebot.io/privacy-policies", + }, + ], + }, + ], + }, + colorMode: { + disableSwitch: true, + }, + }, + presets: [ + [ + "@docusaurus/preset-classic", + { + docs: { + sidebarPath: require.resolve("./sidebars.js"), + routeBasePath: "/", + }, + theme: { + customCss: require.resolve("./src/css/custom.css"), + }, + }, + ], + ], + scripts: ["https://unpkg.com/typebot-js", "/scripts/typebot.js"], +}; diff --git a/apps/docs/package.json b/apps/docs/package.json new file mode 100644 index 000000000..d5ac4d6f0 --- /dev/null +++ b/apps/docs/package.json @@ -0,0 +1,42 @@ +{ + "name": "documentation", + "version": "0.0.0", + "private": true, + "scripts": { + "docusaurus": "docusaurus", + "start": "docusaurus start --no-open --port 3004", + "build": "docusaurus build", + "swizzle": "docusaurus swizzle", + "deploy": "docusaurus deploy", + "clear": "docusaurus clear", + "serve": "docusaurus serve", + "write-translations": "docusaurus write-translations", + "write-heading-ids": "docusaurus write-heading-ids", + "update-search": "docker run -it --rm --env-file=.env -e \"CONFIG=$(cat /Users/baptistearnaud/Dev/typebot-io/docs/docsearch-scrapper-config.json | jq -r tostring)\" algolia/docsearch-scraper" + }, + "dependencies": { + "@docusaurus/core": "2.0.0-beta.15", + "@docusaurus/preset-classic": "2.0.0-beta.15", + "@docusaurus/theme-search-algolia": "^2.0.0-beta.15", + "@mdx-js/react": "^1.6.21", + "@svgr/webpack": "^5.5.0", + "clsx": "^1.1.1", + "file-loader": "^6.2.0", + "prism-react-renderer": "^1.3.1", + "react": "^17.0.2", + "react-dom": "^17.0.2", + "url-loader": "^4.1.1" + }, + "browserslist": { + "production": [ + ">0.5%", + "not dead", + "not op_mini all" + ], + "development": [ + "last 1 chrome version", + "last 1 firefox version", + "last 1 safari version" + ] + } +} diff --git a/apps/docs/sidebars.js b/apps/docs/sidebars.js new file mode 100644 index 000000000..981a73cd7 --- /dev/null +++ b/apps/docs/sidebars.js @@ -0,0 +1,26 @@ +/** + * Creating a sidebar enables you to: + - create an ordered group of docs + - render a sidebar for each doc of that group + - provide next/previous navigation + + The sidebars can be generated from the filesystem, or explicitly defined here. + + Create as many sidebars as you want. + */ + +module.exports = { + // By default, Docusaurus generates a sidebar from the docs folder structure + tutorialSidebar: [{type: 'autogenerated', dirName: '.'}], + + // But you can create a sidebar manually + /* + tutorialSidebar: [ + { + type: 'category', + label: 'Tutorial', + items: ['hello'], + }, + ], + */ +}; diff --git a/apps/docs/src/css/custom.css b/apps/docs/src/css/custom.css new file mode 100644 index 000000000..120d03c44 --- /dev/null +++ b/apps/docs/src/css/custom.css @@ -0,0 +1,45 @@ +/* stylelint-disable docusaurus/copyright-header */ +/** + * Any CSS included here will be global. The classic template + * bundles Infima by default. Infima is a CSS framework designed to + * work well for content-centric websites. + */ + +@import url("https://fonts.googleapis.com/css2?family=Epilogue:wght@300;400;500;600;700;800&family=Open+Sans:wght@300;400;600;700&display=swap"); + +body { + font-family: "Open Sans", sans-serif; +} + +h1, +h2, +h3, +h4 { + font-family: "Epilogue", sans-serif; +} + +img { + border-radius: 0.5rem; +} +/* You can override the default Infima variables here. */ +:root { + --ifm-color-primary: #0042da; + --ifm-color-primary-dark: #003bc4; + --ifm-color-primary-darker: #0038b9; + --ifm-color-primary-darkest: #002e99; + --ifm-color-primary-light: #0049f0; + --ifm-color-primary-lighter: #004cfb; + --ifm-color-primary-lightest: #1c61ff; + --ifm-code-font-size: 95%; +} + +.docusaurus-highlight-code-line { + background-color: rgba(0, 0, 0, 0.1); + display: block; + margin: 0 calc(-1 * var(--ifm-pre-padding)); + padding: 0 var(--ifm-pre-padding); +} + +html[data-theme="dark"] .docusaurus-highlight-code-line { + background-color: rgba(0, 0, 0, 0.3); +} diff --git a/apps/docs/static/.nojekyll b/apps/docs/static/.nojekyll new file mode 100644 index 000000000..e69de29bb diff --git a/apps/docs/static/img/docusaurus.png b/apps/docs/static/img/docusaurus.png new file mode 100644 index 000000000..f458149e3 Binary files /dev/null and b/apps/docs/static/img/docusaurus.png differ diff --git a/apps/docs/static/img/embeddings/bubble1.png b/apps/docs/static/img/embeddings/bubble1.png new file mode 100644 index 000000000..8cd280046 Binary files /dev/null and b/apps/docs/static/img/embeddings/bubble1.png differ diff --git a/apps/docs/static/img/embeddings/bubble2.png b/apps/docs/static/img/embeddings/bubble2.png new file mode 100644 index 000000000..f2c52edbd Binary files /dev/null and b/apps/docs/static/img/embeddings/bubble2.png differ diff --git a/apps/docs/static/img/embeddings/iframe/iframe-preview.png b/apps/docs/static/img/embeddings/iframe/iframe-preview.png new file mode 100644 index 000000000..9ffdaa620 Binary files /dev/null and b/apps/docs/static/img/embeddings/iframe/iframe-preview.png differ diff --git a/apps/docs/static/img/embeddings/popup.png b/apps/docs/static/img/embeddings/popup.png new file mode 100644 index 000000000..8effd0caf Binary files /dev/null and b/apps/docs/static/img/embeddings/popup.png differ diff --git a/apps/docs/static/img/embeddings/standard.png b/apps/docs/static/img/embeddings/standard.png new file mode 100644 index 000000000..47f15b03f Binary files /dev/null and b/apps/docs/static/img/embeddings/standard.png differ diff --git a/apps/docs/static/img/embeddings/wordpress-preview.png b/apps/docs/static/img/embeddings/wordpress-preview.png new file mode 100644 index 000000000..f40baa6e1 Binary files /dev/null and b/apps/docs/static/img/embeddings/wordpress-preview.png differ diff --git a/apps/docs/static/img/embeddings/wp-rocket.png b/apps/docs/static/img/embeddings/wp-rocket.png new file mode 100644 index 000000000..80b05054e Binary files /dev/null and b/apps/docs/static/img/embeddings/wp-rocket.png differ diff --git a/apps/docs/static/img/embeddings/wp-small-container.png b/apps/docs/static/img/embeddings/wp-small-container.png new file mode 100644 index 000000000..e65304f21 Binary files /dev/null and b/apps/docs/static/img/embeddings/wp-small-container.png differ diff --git a/apps/docs/static/img/embeddings/wp-variables.png b/apps/docs/static/img/embeddings/wp-variables.png new file mode 100644 index 000000000..c31020f25 Binary files /dev/null and b/apps/docs/static/img/embeddings/wp-variables.png differ diff --git a/apps/docs/static/img/favicon.png b/apps/docs/static/img/favicon.png new file mode 100644 index 000000000..7512abc2a Binary files /dev/null and b/apps/docs/static/img/favicon.png differ diff --git a/apps/docs/static/img/logo.svg b/apps/docs/static/img/logo.svg new file mode 100644 index 000000000..4c9d1bc6b --- /dev/null +++ b/apps/docs/static/img/logo.svg @@ -0,0 +1,42 @@ + + + + + + + \ No newline at end of file diff --git a/apps/landing-page/components/Homepage/EndCta.tsx b/apps/landing-page/components/Homepage/EndCta.tsx index 12a06776f..2264e7811 100644 --- a/apps/landing-page/components/Homepage/EndCta.tsx +++ b/apps/landing-page/components/Homepage/EndCta.tsx @@ -21,7 +21,7 @@ export const EndCta = () => { diff --git a/apps/landing-page/components/common/Navbar/NavContent.tsx b/apps/landing-page/components/common/Navbar/NavContent.tsx index 48bec0ee3..3d95c2332 100755 --- a/apps/landing-page/components/common/Navbar/NavContent.tsx +++ b/apps/landing-page/components/common/Navbar/NavContent.tsx @@ -64,7 +64,7 @@ const MobileNavContext = ({