diff --git a/apps/formbricks-com-old/pages/docs/actions/code/index.mdx b/apps/formbricks-com-old/pages/docs/actions/code/index.mdx deleted file mode 100644 index 78166145d2..0000000000 --- a/apps/formbricks-com-old/pages/docs/actions/code/index.mdx +++ /dev/null @@ -1,25 +0,0 @@ -import { Layout } from "@/components/docs/Layout"; - -export const meta = { - title: "Code Actions", - description: - "Integrate code actions in Formbricks using formbricks.track() to trigger surveys based on user actions, like button clicks, for precise insights. All open-source.", -}; - -Actions can also be set in the code base. You can fire an action using `formbricks.track()` - -```javascript -formbricks.track("Action Name"); -``` - -Here is an example of how to fire an action when a user clicks a button: - -```javascript -const handleClick = () => { - formbricks.track("Button Clicked"); -}; - -return ; -``` - -export default ({ children }) => {children}; diff --git a/apps/formbricks-com-old/pages/docs/actions/no-code/index.mdx b/apps/formbricks-com-old/pages/docs/actions/no-code/index.mdx deleted file mode 100644 index 5aad65cd59..0000000000 --- a/apps/formbricks-com-old/pages/docs/actions/no-code/index.mdx +++ /dev/null @@ -1,30 +0,0 @@ -import { Layout } from "@/components/docs/Layout"; - -export const meta = { - title: "No-Code Actions", - description: - "Utilize Formbricks' No-Code Actions like Page URL, innerText, and CSS Selector for easy survey triggers and enhanced user insights.", -}; - -No-Code actions can be set up within Formbricks with just a few clicks. There are three types of No-Code actions: - -## Page URL Action - -The page URL action is triggered, when a user visits a specific page in your application. There are several match conditions: - -- `exactMatch`: The URL should exactly match the provided string. -- `contains`: The URL should contain the specified string as a substring. -- `startsWith`: The URL should start with the specified string. -- `endsWith`: The URL should end with the specified string. -- `notMatch`: The URL should not match the specified condition. -- `notContains`: The URL should not contain the specified string as a substring. - -## innerText Action - -The innerText action checks if the `innerText` of a clicked HTML element matches a specific text, e.g. the label of a button. Display a survey on any button click! - -## CSS Selector Action - -The CSS Selector action checks if the provided CSS selector matches the selector of a clicked HTML element. The CSS selector can be a class, id or any other CSS selector within your website. Display a survey on any element click! - -export default ({ children }) => {children}; diff --git a/apps/formbricks-com-old/pages/docs/actions/why/index.mdx b/apps/formbricks-com-old/pages/docs/actions/why/index.mdx deleted file mode 100644 index 580afca3a3..0000000000 --- a/apps/formbricks-com-old/pages/docs/actions/why/index.mdx +++ /dev/null @@ -1,23 +0,0 @@ -import { Layout } from "@/components/docs/Layout"; - -export const meta = { - title: "What are actions and why are they useful?", - description: - "Actions in Formbricks enable targeted survey displays during specific user journey moments. Enhance user segmentation by tracking actions for granular surveying.", -}; - -You want to understand what your users think and feel during specific moments in the user journey. To be able to ask at exactly the right point in time, you need actions. - -## What are actions? - -Actions are a little notification sent from your application to Formbricks. You decide which actions are sent either in your [Code](/docs/actions/code) or by setting up a [No-Code](/docs/actions/no-code) action within Formbricks. - -## How do actions work? - -When a predefined action happens in your app, the Formbricks widget notices. This action can then trigger a survey to be shown to the user and is stored in the database. - -## Why are actions useful? - -Actions help you to display your surveys at the right time. Later on, you will be able to segment your users based on the actions they have triggered in the past. This way, you can create much more granular user segments, e.g. only target users that already have used a specific feature. - -export default ({ children }) => {children}; diff --git a/apps/formbricks-com-old/pages/docs/api/api-key-setup/add-api-key.png b/apps/formbricks-com-old/pages/docs/api/api-key-setup/add-api-key.png deleted file mode 100644 index 8ea4a144a1..0000000000 Binary files a/apps/formbricks-com-old/pages/docs/api/api-key-setup/add-api-key.png and /dev/null differ diff --git a/apps/formbricks-com-old/pages/docs/api/api-key-setup/api-key-secret.png b/apps/formbricks-com-old/pages/docs/api/api-key-setup/api-key-secret.png deleted file mode 100644 index c30d79529a..0000000000 Binary files a/apps/formbricks-com-old/pages/docs/api/api-key-setup/api-key-secret.png and /dev/null differ diff --git a/apps/formbricks-com-old/pages/docs/api/api-key-setup/index.mdx b/apps/formbricks-com-old/pages/docs/api/api-key-setup/index.mdx deleted file mode 100644 index e19805ccf6..0000000000 --- a/apps/formbricks-com-old/pages/docs/api/api-key-setup/index.mdx +++ /dev/null @@ -1,41 +0,0 @@ -import { Layout } from "@/components/docs/Layout"; -import { Fence } from "@/components/shared/Fence"; -import { APILayout } from "@/components/shared/APILayout.tsx"; -import { Callout } from "@/components/shared/Callout"; -import Image from "next/image"; - -import AddApiKey from "./add-api-key.png"; -import ApiKeySecret from "./api-key-secret.png"; - -export const meta = { - title: "API Key Setup", - description: - "Generate, store, and delete personal API keys for secure Formbricks access. Ensure safekeeping to prevent unauthorized account control.", -}; - -## Auth: Personal API key - -The API requests are authorized with a personal API key. This API key gives you the same rights as if you were logged in at formbricks.com - **don't share it around!** - -### How to generate an API key - -1. Go to your settings on [app.formbricks.com](https://app.formbricks.com). -2. Go to page “API keys” - Add API Key -3. Create a key for the development or production environment. -4. Copy the key immediately. You won’t be able to see it again. - API Key Secret - - - Anyone who has your API key has full control over your account. For security reasons, you cannot view the - API key again. - - -### Delete a personal API key - -1. Go to settings on [app.formbricks.com](https://app.formbricks.com/). -2. Go to page “API keys”. -3. Find the key you wish to revoke and select “Delete”. -4. Your API key will stop working immediately. - -export default ({ children }) => {children}; diff --git a/apps/formbricks-com-old/pages/docs/api/overview/index.mdx b/apps/formbricks-com-old/pages/docs/api/overview/index.mdx deleted file mode 100644 index a42df0b989..0000000000 --- a/apps/formbricks-com-old/pages/docs/api/overview/index.mdx +++ /dev/null @@ -1,29 +0,0 @@ -import { Layout } from "@/components/docs/Layout"; -import { Fence } from "@/components/shared/Fence"; -import { APILayout } from "@/components/shared/APILayout.tsx"; - -export const meta = { - title: "API Overview", - description: - "Explore Formbricks' APIs: Public Client API for client-side tasks, and User API for account management with secure API Key authentication.", -}; - -Formbricks offers two types of APIs: the Public Client API and the User API. Each API serves a different purpose, has different authentication requirements, and provides access to different data and settings. - -## Public Client API - -The Public Client API is designed for the JavaScript SDK and does not require authentication. It's primarily used for creating persons, sessions, and responses within the Formbricks platform. This API is ideal for client-side interactions, as it doesn't expose sensitive information. - -## User API - -The User API provides access to all data and settings that are visible in the Formbricks App. This API requires a personal API Key for authentication, which can be generated in the Settings section of the Formbricks App. With the User API, you can manage your Formbricks account programmatically, accessing and modifying data and settings as needed. - -**Auth:** Personal API Key - -API requests made to the User API are authorized using a personal API key. This key grants the same rights and access as if you were logged in at formbricks.com. It's essential to keep your API key secure and not share it with others. - -To generate, store, or delete an API key, follow the instructions provided on the following page [API Key](/docs/api/api-key-setup). - -By understanding the differences between these two APIs, you can choose the appropriate one for your needs, ensuring a secure and efficient integration with the Formbricks platform. - -export default ({ children }) => {children}; diff --git a/apps/formbricks-com-old/pages/docs/attributes/custom-attributes/index.mdx b/apps/formbricks-com-old/pages/docs/attributes/custom-attributes/index.mdx deleted file mode 100644 index 4605b0d876..0000000000 --- a/apps/formbricks-com-old/pages/docs/attributes/custom-attributes/index.mdx +++ /dev/null @@ -1,27 +0,0 @@ -import { Layout } from "@/components/docs/Layout"; - -export const meta = { - title: "Setting attributes with code", - description: - "Set attributes in code using setAttribute function. Enhance user segmentation, target surveys effectively, and gather valuable insights for better decisions. All open-source.", -}; - -One way to send attributes to Formbricks is in your code. In Formbricks, there are two special attributes for [user identification](/docs/attributes/identify-users)(user ID & email) and custom attributes. An example: - -### Setting Custom User Attributes - -You can use the setAttribute function to set any custom attribute for the user (e.g. name, plan, etc.): - -```javascript -formbricks.setAttribute("Plan", "Pro"); -``` - -Generally speaking, the setAttribute function works like this: - -```javascript -formbricks.setAttribute("attribute_key", "attribute_value"); -``` - -Where `attributeName` is the name of the attribute you want to set, and `attributeValue` is the value of the attribute you want to set. - -export default ({ children }) => {children}; diff --git a/apps/formbricks-com-old/pages/docs/attributes/identify-users/index.mdx b/apps/formbricks-com-old/pages/docs/attributes/identify-users/index.mdx deleted file mode 100644 index 79d20aec3d..0000000000 --- a/apps/formbricks-com-old/pages/docs/attributes/identify-users/index.mdx +++ /dev/null @@ -1,45 +0,0 @@ -import { Layout } from "@/components/docs/Layout"; - -export const meta = { - title: "Identifying Users", - description: - "Identify users with Formbricks by setting User ID, email, and custom attributes. Enhance survey targeting and recontacting while maintaining user privacy.", -}; - -At Formbricks, we value user privacy. By default, Formbricks doesn't collect or store any personal information from your users. However, we understand that it can be helpful for you to know which user submitted the feedback and also functionality like recontacting users and controlling the waiting period between surveys requires identifying the users. That's why we provide a way for you to share existing user data from your app, so you can view it in our dashboard. - -Once the Formbricks widget is loaded on your web app, our SDK exposes methods for identifying user attributes. Let's set it up! - -## Setting User ID - -You can use the `setUserId` function to identify a user with any string. It's best to use the default identifier you use in your app (e.g. unique id from database) but you can also anonymize these as long as they are unique for every user. This function can be called multiple times with the same value safely and stores the identifier in local storage. We recommend you set the User ID whenever the user logs in to your website, as well as after the installation snippet (if the user is already logged in). - -```javascript -formbricks.setUserId("USER_ID"); -``` - -## Setting User Email - -You can use the setEmail function to set the user's email: - -```javascript -formbricks.setEmail("user@example.com"); -``` - -### Setting Custom User Attributes - -You can use the setAttribute function to set any custom attribute for the user (e.g. name, plan, etc.): - -```javascript -formbricks.setAttribute("attribute_key", "attribute_value"); -``` - -### Logging Out Users - -When a user logs out of your webpage, make sure to log them out of Formbricks as well. This will prevent new activity from being associated with an incorrect user. Use the logout function: - -```javascript -formbricks.logout(); -``` - -export default ({ children }) => {children}; diff --git a/apps/formbricks-com-old/pages/docs/attributes/why/index.mdx b/apps/formbricks-com-old/pages/docs/attributes/why/index.mdx deleted file mode 100644 index 4b09cbb01c..0000000000 --- a/apps/formbricks-com-old/pages/docs/attributes/why/index.mdx +++ /dev/null @@ -1,23 +0,0 @@ -import { Layout } from "@/components/docs/Layout"; - -export const meta = { - title: "What are attributes and why are they useful?", - description: - "How to use attributes for user segmentation, enhancing survey targeting & results. Improve feedback quality and make data-driven decisions.", -}; - -Surveying your user base without segmentation leads to weak results and survey fatigue. Attributes help you segment your users into groups. - -## What are attributes? - -Attributes are key-value pairs that you can set for each person individually. For example, the attribute "Plan" can be set to "Free" or "Paid". - -## How do attributes work? - -Attributes are sent from your application to Formbricks and are associated with the current user. We store it in our database and allow you to use it the next time you create a survey. - -## Why are attributes useful? - -Attributes help show surveys to the right group of people. For example, you can show a survey to all users who have a "Plan" attribute set to "Paid". - -export default ({ children }) => {children}; diff --git a/apps/formbricks-com-old/pages/docs/best-practices/cancel-subscription/change-text.png b/apps/formbricks-com-old/pages/docs/best-practices/cancel-subscription/change-text.png deleted file mode 100644 index 1908b5f5be..0000000000 Binary files a/apps/formbricks-com-old/pages/docs/best-practices/cancel-subscription/change-text.png and /dev/null differ diff --git a/apps/formbricks-com-old/pages/docs/best-practices/cancel-subscription/create-cancel-flow.png b/apps/formbricks-com-old/pages/docs/best-practices/cancel-subscription/create-cancel-flow.png deleted file mode 100644 index 7526a42b9a..0000000000 Binary files a/apps/formbricks-com-old/pages/docs/best-practices/cancel-subscription/create-cancel-flow.png and /dev/null differ diff --git a/apps/formbricks-com-old/pages/docs/best-practices/cancel-subscription/index.mdx b/apps/formbricks-com-old/pages/docs/best-practices/cancel-subscription/index.mdx deleted file mode 100644 index 06612d8cec..0000000000 --- a/apps/formbricks-com-old/pages/docs/best-practices/cancel-subscription/index.mdx +++ /dev/null @@ -1,125 +0,0 @@ -import { Layout } from "@/components/docs/Layout"; -import { Fence } from "@/components/shared/Fence"; -import { Callout } from "@/components/shared/Callout"; -import Image from "next/image"; -import DemoPreview from "@/components/dummyUI/DemoPreview"; - -import CreateChurnFlow from "./create-cancel-flow.png"; -import ChangeText from "./change-text.png"; -import TriggerInnerText from "./trigger-inner-text.png"; -import TriggerCSS from "./trigger-css-selector.png"; -import TriggerPageUrl from "./trigger-page-url.png"; -import RecontactOptions from "./recontact-options.png"; -import PublishSurvey from "./publish-survey.png"; -import SelectAction from "./select-action.png"; - -export const meta = { - title: "Learn from Churn", - description: "To know how to decrease churn, you have to understand it. Use a micro-survey.", -}; - -Churn is hard, but can teach you a lot. Whenever a user decides that your product isn’t worth it anymore, you have a unique opportunity to get deep insights. These insights are pure gold to reduce churn. - -## Purpose - -The Churn Survey is among the most effective ways to identify weaknesses in you offering. People were willing to pay but now are not anymore: What changed? Let’s find out! - -## Preview - - - -## Formbricks Approach - -- Ask at exactly the right point in time -- Follow-up to prevent bad reviews -- Coming soon: Make survey mandatory - -## Overview - -To run the Churn Survey in your app you want to proceed as follows: - -1. Create new Churn Survey at [app.formbricks.com](http://app.formbricks.com/) -2. Set up the user action to display survey at right point in time -3. Choose correct recontact options to never miss a feedback -4. Prevent that churn! - - - We assume that you have already installed the Formbricks Widget in your web app. It’s required to display - messages and surveys in your app. If not, please follow the [Quick Start Guide (takes 15mins - max.)](/docs/getting-started/quickstart) - - -### 1. Create new Churn Survey - -If you don't have an account yet, create one at [app.formbricks.com](https://app.formbricks.com/auth/signup) - -Click on "Create Survey" and choose the template “Churn Survey”: - -Create churn survey by template - -### 2. Update questions (if you like) - -You’re free to update the question and answer options. However, based on our experience, we suggest giving the provided template a go 😊 - -Change text content - -_Want to change the button color? You can do so in the product settings._ - -Save, and move over to the “Audience” tab. - -### 3. Pre-segment your audience - -In this case, you don’t really need to pre-segment your audience. You likely want to ask everyone who hits the “Cancel subscription” button. - -### 4. Set up a trigger - -To create the trigger for your Churn Survey, you have two options to choose from: - -1. **Trigger by innerText:** You likely have a “Cancel Subscription” button in your app. You can setup a user Action with the according `innerText` to trigger the survey, like so: - -Set the trigger by inner Text - -2. **Trigger by CSS Selector:** In case you have more than one button saying “Cancel Subscription” in your app and only want to display the survey when one of them is clicked, you want to be more specific. The best way to do that is to give this button the HTML `id=“cancel-subscription”` and set your user action up like so: - -Set the trigger by CSS Selector - -3. **Trigger by pageURL:** Lastly, you could also display your survey on a subpage “/subscription-cancelled” where you forward users once they cancelled the trial subscription. You can then create a user Action with the type `pageURL` with the following settings: - -Set the trigger by page URL - -Whenever a user visits this page, matches the filter conditions above and the recontact options (below) the survey will be displayed ✅ - -Here is our complete [Actions manual](/docs/actions/why) covering [Code](/docs/actions/code) and [No-Code](/docs/actions/no-code) Actions. - - - -We’re currently building full-screen survey pop-ups. You’ll be able to prevent users from closing the survey unless they respond to it. It’s certainly debatable if you want that but you could force them to click through the survey before letting them cancel 🤷 - - - -### 5. Select Action in the “When to ask” card - -Select feedback button action - -### 6. Last step: Set Recontact Options correctly - -Lastly, scroll down to “Recontact Options”. Here you have to choose the correct settings to make sure you milk these super valuable insights. You want to make sure that this survey is always displayed, no matter if the user has already seen a survey in the past days: - -Set recontact options - -These settings make sure the survey is always displayed, when a user wants to Cancel their subscription. - -### 7. Congrats! You’re ready to publish your survey 💃 - -Publish survey - - - You need to have the Formbricks Widget installed to display the Churn Survey in your app. Please follow - [this tutorial (Step 4 onwards)](/docs/getting-started/quickstart) to install the widget. - - -### - -# Get those insights! 🎉 - -export default ({ children }) => {children}; diff --git a/apps/formbricks-com-old/pages/docs/best-practices/cancel-subscription/publish-survey.png b/apps/formbricks-com-old/pages/docs/best-practices/cancel-subscription/publish-survey.png deleted file mode 100644 index 5d21ed596f..0000000000 Binary files a/apps/formbricks-com-old/pages/docs/best-practices/cancel-subscription/publish-survey.png and /dev/null differ diff --git a/apps/formbricks-com-old/pages/docs/best-practices/cancel-subscription/recontact-options.png b/apps/formbricks-com-old/pages/docs/best-practices/cancel-subscription/recontact-options.png deleted file mode 100644 index 5995f97fdd..0000000000 Binary files a/apps/formbricks-com-old/pages/docs/best-practices/cancel-subscription/recontact-options.png and /dev/null differ diff --git a/apps/formbricks-com-old/pages/docs/best-practices/cancel-subscription/select-action.png b/apps/formbricks-com-old/pages/docs/best-practices/cancel-subscription/select-action.png deleted file mode 100644 index 94cc8eb004..0000000000 Binary files a/apps/formbricks-com-old/pages/docs/best-practices/cancel-subscription/select-action.png and /dev/null differ diff --git a/apps/formbricks-com-old/pages/docs/best-practices/cancel-subscription/trigger-css-selector.png b/apps/formbricks-com-old/pages/docs/best-practices/cancel-subscription/trigger-css-selector.png deleted file mode 100644 index 806170f0d3..0000000000 Binary files a/apps/formbricks-com-old/pages/docs/best-practices/cancel-subscription/trigger-css-selector.png and /dev/null differ diff --git a/apps/formbricks-com-old/pages/docs/best-practices/cancel-subscription/trigger-inner-text.png b/apps/formbricks-com-old/pages/docs/best-practices/cancel-subscription/trigger-inner-text.png deleted file mode 100644 index 103d0764fc..0000000000 Binary files a/apps/formbricks-com-old/pages/docs/best-practices/cancel-subscription/trigger-inner-text.png and /dev/null differ diff --git a/apps/formbricks-com-old/pages/docs/best-practices/cancel-subscription/trigger-page-url.png b/apps/formbricks-com-old/pages/docs/best-practices/cancel-subscription/trigger-page-url.png deleted file mode 100644 index c66b870928..0000000000 Binary files a/apps/formbricks-com-old/pages/docs/best-practices/cancel-subscription/trigger-page-url.png and /dev/null differ diff --git a/apps/formbricks-com-old/pages/docs/best-practices/docs-feedback/add-action.png b/apps/formbricks-com-old/pages/docs/best-practices/docs-feedback/add-action.png deleted file mode 100644 index 7ebb5853f7..0000000000 Binary files a/apps/formbricks-com-old/pages/docs/best-practices/docs-feedback/add-action.png and /dev/null differ diff --git a/apps/formbricks-com-old/pages/docs/best-practices/docs-feedback/change-id.png b/apps/formbricks-com-old/pages/docs/best-practices/docs-feedback/change-id.png deleted file mode 100644 index fc83c4ef02..0000000000 Binary files a/apps/formbricks-com-old/pages/docs/best-practices/docs-feedback/change-id.png and /dev/null differ diff --git a/apps/formbricks-com-old/pages/docs/best-practices/docs-feedback/copy-ids.png b/apps/formbricks-com-old/pages/docs/best-practices/docs-feedback/copy-ids.png deleted file mode 100644 index f2e8481112..0000000000 Binary files a/apps/formbricks-com-old/pages/docs/best-practices/docs-feedback/copy-ids.png and /dev/null differ diff --git a/apps/formbricks-com-old/pages/docs/best-practices/docs-feedback/docs-navi.png b/apps/formbricks-com-old/pages/docs/best-practices/docs-feedback/docs-navi.png deleted file mode 100644 index df5b0a319f..0000000000 Binary files a/apps/formbricks-com-old/pages/docs/best-practices/docs-feedback/docs-navi.png and /dev/null differ diff --git a/apps/formbricks-com-old/pages/docs/best-practices/docs-feedback/docs-template.png b/apps/formbricks-com-old/pages/docs/best-practices/docs-feedback/docs-template.png deleted file mode 100644 index c689d8f440..0000000000 Binary files a/apps/formbricks-com-old/pages/docs/best-practices/docs-feedback/docs-template.png and /dev/null differ diff --git a/apps/formbricks-com-old/pages/docs/best-practices/docs-feedback/index.mdx b/apps/formbricks-com-old/pages/docs/best-practices/docs-feedback/index.mdx deleted file mode 100644 index 30e4316ada..0000000000 --- a/apps/formbricks-com-old/pages/docs/best-practices/docs-feedback/index.mdx +++ /dev/null @@ -1,385 +0,0 @@ -import { Layout } from "@/components/docs/Layout"; -import { Fence } from "@/components/shared/Fence"; -import { Callout } from "@/components/shared/Callout"; -import Image from "next/image"; - -import DocsFeedback from "@/components/docs/DocsFeedback"; -import AddAction from "./add-action.png"; -import ChangeId from "./change-id.png"; -import DocsNavi from "./docs-navi.png"; -import DocsTemplate from "./docs-template.png"; -import SelectNonevent from "./select-nonevent.png"; -import SwitchToDev from "./switch-to-dev.png"; -import WhenToAsk from "./when-to-ask.png"; -import CopyIds from "./copy-ids.png"; - -export const meta = { - title: "Docs Feedback", - description: "Docs Feedback allows you to measure how clear your documentation is.", -}; - -Docs Feedback allows you to measure how clear your documentation is. - -## Purpose - -Unlike yourself, your users don't spend 5-7 days per week thinking about your product. To fight the "Curse of Knowledge" you have to measure how clear your docs are. - -## Preview - - - -## Installation - -To get this running, you'll need a bit of time. Here are the steps we're going through: - -1. Set up Formbricks Cloud -2. Build the frontend -3. Connect to API -4. Test - -### 1. Setting up Formbricks Cloud - -1. To get started, create an account for the [Formbricks Cloud](https://app.formbricks.com/auth/signup). - -2. In the Menu (top right) you see that you can switch between a “Development” and a “Production” environment. These are two separate environments so your test data doesn’t mess up the insights from prod. Switch to “Development”: - -switch to dev environment - -3. Then, create a survey using the template “Docs Feedback”: - -select docs template - -4. Change the Internal Question ID of the first question to **“isHelpful”** to make your life easier 😉 - -switch to dev environment - -5. In the same way, you can change the Internal Question ID of the _Please elaborate_ question to **“additionalFeedback”** and the one of the _Page URL_ question to **“pageUrl”**. - - - If you want different answers than “Yes 👍” and “No 👎” you need update the choices accordingly. They have - to be identical to the frontend we're building in the next step. - - -6. Click on “Continue to Settings or select the audience tab manually. Scroll down to “When to ask” and create a new Action: - -set up when to ask card - -7. Our goal is to create an event that never fires. This is a bit nonsensical because it is a workaround. Stick with me 😃 Fill the action out like on the screenshot: - -add action - -8. Select the Non-Event in the dropdown. Now you see that the “Publish survey” button is active. Publish your survey 🤝 - -select nonevent - -**You’re all setup in Formbricks Cloud for now 👍** - -### 2. Build the frontend - - - Your frontend likely looks and works differently. This is an example specific to our tech stack. We want to - illustrate what you should consider building yours 😊 - - -Before we start, lets talk about the widget. It works like this: - -- Once the user selects yes/no, a partial response is sent to the Formbricks API. It includes the feedback and the current page url. -- Then the user is presented with an additional open text field to further explain their choice. Once it's submitted, the previous response is updated with the additional feedback. - -This allows us to capture and analyze partial feedback where the user is not willing to provide additional information. - -**Let's do this 👇** - -1. Open the code editor where you handle your docs page. - -2. Likely, you have a template file or similar which renders the navigation at the bottom of the page: - -doc navigation - -Locate that file. We are using the [Tailwind Template “Syntax”](https://tailwindui.com/templates/syntax) for our docs. Here is our [Layout.tsx](https://github.com/formbricks/formbricks/blob/main/apps/formbricks-com/components/docs/Layout.tsx) file. - -3. Write the frontend code for the widget. Here is the full component (we break it down right below): - -```tsx -import { useState } from "react"; -import { handleFeedbackSubmit, updateFeedback } from "../../lib/handleFeedbackSubmit"; -import { Popover, PopoverTrigger, PopoverContent, Button } from "@formbricks/ui"; -import { useRouter } from "next/router"; - -export default function DocsFeedback() { - const router = useRouter(); - const [isOpen, setIsOpen] = useState(false); - const [sharedFeedback, setSharedFeedback] = useState(false); - const [responseId, setResponseId] = useState(null); - const [freeText, setFreeText] = useState(""); - - if ( - !process.env.NEXT_PUBLIC_FORMBRICKS_COM_DOCS_FEEDBACK_SURVEY_ID || - !process.env.NEXT_PUBLIC_FORMBRICKS_COM_API_HOST || - !process.env.NEXT_PUBLIC_FORMBRICKS_COM_ENVIRONMENT_ID - ) { - return null; - } - - return ( -
- {!sharedFeedback ? ( -
- Was this page helpful? - -
- {["Yes 👍", " No 👎"].map((option) => ( - { - const id = await handleFeedbackSubmit(option, router.asPath); - setResponseId(id); - }}> - {option} - - ))} -
- -
- +
+
+
+ +
+ + ); +} diff --git a/apps/formbricks-com/src/components/dummyUI/PreviewModal.tsx b/apps/formbricks-com/src/components/dummyUI/PreviewModal.tsx new file mode 100644 index 0000000000..0bdcf5e568 --- /dev/null +++ b/apps/formbricks-com/src/components/dummyUI/PreviewModal.tsx @@ -0,0 +1,27 @@ +import clsx from "clsx"; +import { ReactNode, useEffect, useState } from "react"; + +export const Modal: React.FC<{ children: ReactNode; isOpen: boolean }> = ({ children, isOpen }) => { + const [show, setShow] = useState(false); + + useEffect(() => { + setShow(isOpen); + }, [isOpen]); + return ( +
+
+
+ {children} +
+
+
+ ); +}; + +export default Modal; diff --git a/apps/formbricks-com/src/components/dummyUI/PreviewSurvey.tsx b/apps/formbricks-com/src/components/dummyUI/PreviewSurvey.tsx new file mode 100644 index 0000000000..7fba2a5986 --- /dev/null +++ b/apps/formbricks-com/src/components/dummyUI/PreviewSurvey.tsx @@ -0,0 +1,89 @@ +import { useState } from "react"; +import Modal from "./Modal"; +import QuestionConditional from "./QuestionConditional"; +import type { Question } from "@formbricks/types/questions"; +import { Survey } from "@formbricks/types/surveys"; +import ThankYouCard from "./ThankYouCard"; + +interface PreviewSurveyProps { + localSurvey?: Survey; + setActiveQuestionId: (id: string | null) => void; + activeQuestionId?: string | null; + questions: Question[]; + brandColor: string; +} + +export default function PreviewSurvey({ + localSurvey, + setActiveQuestionId, + activeQuestionId, + questions, + brandColor, +}: PreviewSurveyProps) { + const [isModalOpen, setIsModalOpen] = useState(true); + + const gotoNextQuestion = () => { + const currentIndex = questions.findIndex((q) => q.id === activeQuestionId); + if (currentIndex < questions.length - 1) { + setActiveQuestionId(questions[currentIndex + 1].id); + } else { + if (localSurvey?.thankYouCard?.enabled) { + setActiveQuestionId("thank-you-card"); + } else { + setIsModalOpen(false); + setTimeout(() => { + setActiveQuestionId(questions[0].id); + setIsModalOpen(true); + }, 500); + if (localSurvey?.thankYouCard?.enabled) { + setActiveQuestionId("thank-you-card"); + } else { + setIsModalOpen(false); + setTimeout(() => { + setActiveQuestionId(questions[0].id); + setIsModalOpen(true); + }, 500); + } + } + } + }; + + const resetPreview = () => { + setIsModalOpen(false); + setTimeout(() => { + setActiveQuestionId(questions[0].id); + setIsModalOpen(true); + }, 500); + }; + + if (!activeQuestionId) { + return null; + } + + return ( + <> + + {activeQuestionId == "thank-you-card" ? ( + + ) : ( + questions.map( + (question, idx) => + activeQuestionId === question.id && ( + + ) + ) + )} + + + ); +} diff --git a/apps/formbricks-com/src/components/dummyUI/Progress.tsx b/apps/formbricks-com/src/components/dummyUI/Progress.tsx new file mode 100644 index 0000000000..16f75f378f --- /dev/null +++ b/apps/formbricks-com/src/components/dummyUI/Progress.tsx @@ -0,0 +1,11 @@ +export const Progress: React.FC<{ progress: number; brandColor: string }> = ({ progress, brandColor }) => { + return ( +
+
+
+ ); +}; + +export default Progress; diff --git a/apps/formbricks-com/src/components/dummyUI/QuestionConditional.tsx b/apps/formbricks-com/src/components/dummyUI/QuestionConditional.tsx new file mode 100644 index 0000000000..207421dbc4 --- /dev/null +++ b/apps/formbricks-com/src/components/dummyUI/QuestionConditional.tsx @@ -0,0 +1,65 @@ +import { QuestionType, type Question } from "@formbricks/types/questions"; +import OpenTextQuestion from "./OpenTextQuestion"; +import MultipleChoiceSingleQuestion from "./MultipleChoiceSingleQuestion"; +import MultipleChoiceMultiQuestion from "./MultipleChoiceMultiQuestion"; +import NPSQuestion from "./NPSQuestion"; +import CTAQuestion from "./CTAQuestion"; +import RatingQuestion from "./RatingQuestion"; + +interface QuestionConditionalProps { + question: Question; + onSubmit: (data: { [x: string]: any }) => void; + lastQuestion: boolean; + brandColor: string; +} + +export default function QuestionConditional({ + question, + onSubmit, + lastQuestion, + brandColor, +}: QuestionConditionalProps) { + return question.type === QuestionType.OpenText ? ( + + ) : question.type === QuestionType.MultipleChoiceSingle ? ( + + ) : question.type === QuestionType.MultipleChoiceMulti ? ( + + ) : question.type === QuestionType.NPS ? ( + + ) : question.type === QuestionType.CTA ? ( + + ) : question.type === QuestionType.Rating ? ( + + ) : null; +} diff --git a/apps/formbricks-com/src/components/dummyUI/RatingQuestion.tsx b/apps/formbricks-com/src/components/dummyUI/RatingQuestion.tsx new file mode 100644 index 0000000000..ddbccfd1e8 --- /dev/null +++ b/apps/formbricks-com/src/components/dummyUI/RatingQuestion.tsx @@ -0,0 +1,91 @@ +import type { RatingQuestion } from "@formbricks/types/questions"; +import { useState } from "react"; +import { cn } from "@formbricks/lib/cn"; +import Headline from "./Headline"; +import Subheader from "./Subheader"; + +interface RatingQuestionProps { + question: RatingQuestion; + onSubmit: (data: { [x: string]: any }) => void; + lastQuestion: boolean; + brandColor: string; +} + +export default function RatingQuestion({ + question, + onSubmit, + lastQuestion, + brandColor, +}: RatingQuestionProps) { + const [selectedChoice, setSelectedChoice] = useState(null); + + const handleSelect = (number: number) => { + setSelectedChoice(number); + if (question.required) { + onSubmit({ + [question.id]: number, + }); + setSelectedChoice(null); // reset choice + } + }; + + return ( +
{ + e.preventDefault(); + + const data = { + [question.id]: selectedChoice, + }; + + setSelectedChoice(null); // reset choice + + onSubmit(data); + }}> + + +
+
+ Options +
+ {Array.from({ length: question.range }, (_, i) => i + 1).map((number) => ( + + ))} +
+
+

{question.lowerLabel}

+

{question.upperLabel}

+
+
+
+ {!question.required && ( +
+
+ +
+ )} + + ); +} diff --git a/apps/formbricks-com/src/components/dummyUI/Subheader.tsx b/apps/formbricks-com/src/components/dummyUI/Subheader.tsx new file mode 100644 index 0000000000..2fa4c32353 --- /dev/null +++ b/apps/formbricks-com/src/components/dummyUI/Subheader.tsx @@ -0,0 +1,14 @@ +export const Subheader: React.FC<{ subheader?: string; questionId: string }> = ({ + subheader, + questionId, +}) => { + return ( + + ); +}; + +export default Subheader; diff --git a/apps/formbricks-com/src/components/dummyUI/TemplateList.tsx b/apps/formbricks-com/src/components/dummyUI/TemplateList.tsx new file mode 100644 index 0000000000..9e96545f0d --- /dev/null +++ b/apps/formbricks-com/src/components/dummyUI/TemplateList.tsx @@ -0,0 +1,77 @@ +import type { Template } from "@formbricks/types/templates"; +import { useEffect, useState } from "react"; +import { cn } from "@formbricks/lib/cn"; +import { templates } from "./templates"; + +type TemplateList = { + onTemplateClick: (template: Template) => void; + activeTemplate: Template | null; +}; + +const ALL_CATEGORY_NAME = "All"; + +export default function TemplateList({ onTemplateClick, activeTemplate }: TemplateList) { + const [selectedFilter, setSelectedFilter] = useState(ALL_CATEGORY_NAME); + + const [categories, setCategories] = useState>([]); + + useEffect(() => { + const defaultCategories = [ + /* ALL_CATEGORY_NAME, */ + ...(Array.from(new Set(templates.map((template) => template.category))) as string[]), + ]; + + const fullCategories = [ALL_CATEGORY_NAME, ...defaultCategories]; + + setCategories(fullCategories); + + const activeFilter = ALL_CATEGORY_NAME; + setSelectedFilter(activeFilter); + }, []); + + return ( +
+
+ {categories.map((category) => ( + + ))} +
+
+ {templates + .filter((template) => selectedFilter === ALL_CATEGORY_NAME || template.category === selectedFilter) + .map((template: Template) => ( + + ))} +
+
+ ); +} diff --git a/apps/formbricks-com/src/components/dummyUI/ThankYouCard.tsx b/apps/formbricks-com/src/components/dummyUI/ThankYouCard.tsx new file mode 100644 index 0000000000..9d34466083 --- /dev/null +++ b/apps/formbricks-com/src/components/dummyUI/ThankYouCard.tsx @@ -0,0 +1,52 @@ +import Headline from "./Headline"; +import Subheader from "./Subheader"; + +interface ThankYouCardProps { + headline: string; + subheader: string; + brandColor: string; +} + +export default function ThankYouCard({ headline, subheader, brandColor }: ThankYouCardProps) { + return ( +
+
+ + + +
+ + + +
+ + +
+ + {/* + +
+

+ Powered by{" "} + + + Formbricks + + +

+
*/} +
+ ); +} diff --git a/apps/formbricks-com/src/components/dummyUI/templates.ts b/apps/formbricks-com/src/components/dummyUI/templates.ts new file mode 100644 index 0000000000..91822c2409 --- /dev/null +++ b/apps/formbricks-com/src/components/dummyUI/templates.ts @@ -0,0 +1,1102 @@ +import { + AppPieChartIcon, + ArrowRightCircleIcon, + ArrowUpRightIcon, + BaseballIcon, + CancelSubscriptionIcon, + CashCalculatorIcon, + CheckMarkIcon, + CodeBookIcon, + DashboardIcon, + DogChaserIcon, + DoorIcon, + FeedbackIcon, + GaugeSpeedFastIcon, + HeartCommentIcon, + InterviewPromptIcon, + LoadingBarIcon, + OnboardingIcon, + PMFIcon, + TaskListSearchIcon, + UserSearchGlasIcon, + VideoTabletAdjustIcon, +} from "@formbricks/ui"; + +import { createId } from "@paralleldrive/cuid2"; +import type { Template } from "@formbricks/types/templates"; +import { QuestionType } from "@formbricks/types/questions"; + +const thankYouCardDefault = { + enabled: true, + headline: "Thank you!", + subheader: "We appreciate your feedback.", +}; + +export const customSurvey: Template = { + name: "Start from scratch", + description: "Create a survey without template.", + icon: null, + preset: { + name: "New Survey", + questions: [ + { + id: createId(), + type: QuestionType.OpenText, + headline: "Custom Survey", + subheader: "This is an example survey.", + placeholder: "Type your answer here...", + longAnswer: true, + required: true, + }, + ], + thankYouCard: thankYouCardDefault, + }, +}; + +export const templates: Template[] = [ + { + name: "Product Market Fit (Superhuman)", + icon: PMFIcon, + category: "Product Experience", + + description: "Measure PMF by assessing how disappointed users would be if your product disappeared.", + preset: { + name: "Product Market Fit (Superhuman)", + questions: [ + { + id: createId(), + type: QuestionType.MultipleChoiceSingle, + headline: "How disappointed would you be if you could no longer use Formbricks?", + subheader: "Please select one of the following options:", + required: true, + shuffleOption: "none", + choices: [ + { + id: createId(), + label: "Not at all disappointed", + }, + { + id: createId(), + label: "Somewhat disappointed", + }, + { + id: createId(), + label: "Very disappointed", + }, + ], + }, + { + id: createId(), + type: QuestionType.MultipleChoiceSingle, + headline: "What is your role?", + subheader: "Please select one of the following options:", + required: true, + shuffleOption: "none", + choices: [ + { + id: createId(), + label: "Founder", + }, + { + id: createId(), + label: "Executive", + }, + { + id: createId(), + label: "Product Manager", + }, + { + id: createId(), + label: "Product Owner", + }, + { + id: createId(), + label: "Software Engineer", + }, + ], + }, + { + id: createId(), + type: QuestionType.OpenText, + headline: "What type of people do you think would most benefit from Formbricks?", + longAnswer: true, + required: true, + }, + { + id: createId(), + type: QuestionType.OpenText, + headline: "What is the main benefit your receive from Formbricks?", + longAnswer: true, + required: true, + }, + { + id: createId(), + type: QuestionType.OpenText, + headline: "How can we improve our service for you?", + subheader: "Please be as specific as possible.", + longAnswer: true, + required: true, + }, + ], + thankYouCard: thankYouCardDefault, + }, + }, + + { + name: "Onboarding Segmentation", + icon: OnboardingIcon, + category: "Product Experience", + description: "Learn more about who signed up to your product and why.", + preset: { + name: "Onboarding Segmentation", + questions: [ + { + id: createId(), + type: QuestionType.MultipleChoiceSingle, + headline: "What is your role?", + subheader: "Please select one of the following options:", + required: true, + shuffleOption: "none", + choices: [ + { + id: createId(), + label: "Founder", + }, + { + id: createId(), + label: "Executive", + }, + { + id: createId(), + label: "Product Manager", + }, + { + id: createId(), + label: "Product Owner", + }, + { + id: createId(), + label: "Software Engineer", + }, + ], + }, + { + id: createId(), + type: QuestionType.MultipleChoiceSingle, + headline: "What's your company size?", + subheader: "Please select one of the following options:", + required: true, + shuffleOption: "none", + choices: [ + { + id: createId(), + label: "only me", + }, + { + id: createId(), + label: "1-5 employees", + }, + { + id: createId(), + label: "6-10 employees", + }, + { + id: createId(), + label: "11-100 employees", + }, + { + id: createId(), + label: "over 100 employees", + }, + ], + }, + { + id: createId(), + type: QuestionType.MultipleChoiceSingle, + headline: "How did you hear about us first?", + subheader: "Please select one of the following options:", + required: true, + shuffleOption: "none", + choices: [ + { + id: createId(), + label: "Recommendation", + }, + { + id: createId(), + label: "Social Media", + }, + { + id: createId(), + label: "Ads", + }, + { + id: createId(), + label: "Google Search", + }, + { + id: createId(), + label: "In a Podcast", + }, + ], + }, + ], + thankYouCard: thankYouCardDefault, + }, + }, + { + name: "Uncover Strengths & Weaknesses", + icon: TaskListSearchIcon, + category: "Growth", + description: "Find out what users like and don't like about your product or offering.", + preset: { + name: "Uncover Strengths & Weaknesses", + questions: [ + { + id: createId(), + type: QuestionType.MultipleChoiceSingle, + headline: "What do you value most about our service?", + subheader: "Please select one of the following options:", + required: true, + shuffleOption: "none", + choices: [ + { + id: createId(), + label: "Ease of use", + }, + { + id: createId(), + label: "Good value for money", + }, + { + id: createId(), + label: "It's open-source", + }, + { + id: createId(), + label: "The founders are pretty", + }, + ], + }, + { + id: createId(), + type: QuestionType.MultipleChoiceSingle, + headline: "What should we improve on?", + subheader: "Please select one of the following options:", + required: true, + shuffleOption: "none", + choices: [ + { + id: createId(), + label: "Documentation", + }, + { + id: createId(), + label: "Customizability", + }, + { + id: createId(), + label: "Pricing", + }, + { + id: createId(), + label: "Humbleness of founders", + }, + ], + }, + { + id: createId(), + type: QuestionType.OpenText, + headline: "Would you like to add something?", + subheader: "Feel free to speak your mind, we do too.", + longAnswer: true, + required: false, + }, + ], + thankYouCard: thankYouCardDefault, + }, + }, + { + name: "Marketing Attribution", + icon: AppPieChartIcon, + category: "Growth", + description: "How did you first hear about us?", + preset: { + name: "Marketing Attribution", + questions: [ + { + id: createId(), + type: QuestionType.MultipleChoiceSingle, + headline: "How did you hear about us first?", + subheader: "Please select one of the following options:", + required: true, + shuffleOption: "none", + choices: [ + { + id: createId(), + label: "Recommendation", + }, + { + id: createId(), + label: "Social Media", + }, + { + id: createId(), + label: "Ads", + }, + { + id: createId(), + label: "Google Search", + }, + { + id: createId(), + label: "In a Podcast", + }, + ], + }, + ], + thankYouCard: thankYouCardDefault, + }, + }, + { + name: "Churn Survey", + icon: CancelSubscriptionIcon, + category: "Increase Revenue", + description: "Find out why people cancel their subscriptions. These insights are pure gold!", + preset: { + name: "Churn Survey", + questions: [ + { + id: createId(), + type: QuestionType.MultipleChoiceSingle, + headline: "Why did you cancel your subscription?", + subheader: "We're sorry to see you leave. Please help us do better:", + required: true, + shuffleOption: "none", + choices: [ + { + id: createId(), + label: "I didn't get much value out of it", + }, + { + id: createId(), + label: "It's too expensive", + }, + { + id: createId(), + label: "I am missing a feature", + }, + { + id: createId(), + label: "Poor customer service", + }, + { + id: createId(), + label: "I just didn't need it anymore", + }, + ], + }, + { + id: createId(), + type: QuestionType.OpenText, + headline: "How can we win you back?", + subheader: "Feel free to speak your mind, we do too.", + longAnswer: true, + required: false, + }, + ], + thankYouCard: thankYouCardDefault, + }, + }, + { + name: "Improve Trial Conversion", + icon: BaseballIcon, + category: "Increase Revenue", + description: "Find out why people stopped their trial. These insights help you improve your funnel.", + preset: { + name: "Improve Trial Conversion", + questions: [ + { + id: createId(), + type: QuestionType.MultipleChoiceSingle, + headline: "Why did you stop your trial?", + subheader: "Help us understand you better:", + required: true, + shuffleOption: "none", + choices: [ + { + id: createId(), + label: "I didn't get much value out of it", + }, + { + id: createId(), + label: "I expected something else", + }, + { + id: createId(), + label: "It's too expensive for what it does", + }, + { + id: createId(), + label: "I am missing a feature", + }, + { + id: createId(), + label: "I was just looking around", + }, + ], + }, + { + id: createId(), + type: QuestionType.OpenText, + headline: "Any details to share?", + longAnswer: true, + required: false, + }, + { + id: createId(), + type: QuestionType.OpenText, + headline: "How are you solving your problem instead?", + subheader: "Please name alternative tools:", + longAnswer: true, + required: false, + }, + ], + thankYouCard: thankYouCardDefault, + }, + }, + { + name: "Changing subscription experience", + icon: CashCalculatorIcon, + category: "Increase Revenue", + description: "Find out what goes through peoples minds when changing their subscriptions.", + preset: { + name: "Changing subscription experience", + questions: [ + { + id: createId(), + type: QuestionType.MultipleChoiceSingle, + headline: "How easy was it to change your plan?", + required: true, + shuffleOption: "none", + choices: [ + { + id: createId(), + label: "Extremely difficult", + }, + { + id: createId(), + label: "It took a while, but I got it", + }, + { + id: createId(), + label: "It was alright", + }, + { + id: createId(), + label: "Quite easy", + }, + { + id: createId(), + label: "Very easy, love it!", + }, + ], + }, + { + id: createId(), + type: QuestionType.MultipleChoiceSingle, + headline: "Is the pricing information easy to understand?", + required: true, + shuffleOption: "none", + choices: [ + { + id: createId(), + label: "Yes, very clear.", + }, + { + id: createId(), + label: "I was confused at first, but found what I needed.", + }, + { + id: createId(), + label: "Quite complicated.", + }, + ], + }, + ], + thankYouCard: thankYouCardDefault, + }, + }, + { + name: "Measure Task Accomplishment", + icon: CheckMarkIcon, + category: "Product Experience", + description: "See if people get their 'Job To Be Done' done. Successful people are better customers.", + preset: { + name: "Measure Task Accomplishment", + questions: [ + { + id: createId(), + type: QuestionType.MultipleChoiceSingle, + headline: "Were you able to accomplish what you came here to do today?", + required: true, + shuffleOption: "none", + choices: [ + { + id: createId(), + label: "Yes", + }, + { + id: createId(), + label: "Working on it, boss", + }, + { + id: createId(), + label: "No", + }, + ], + }, + { + id: createId(), + type: QuestionType.Rating, + headline: "How easy was it to achieve your goal?", + required: true, + lowerLabel: "Very difficult", + upperLabel: "Very easy", + range: 5, + scale: "number", + }, + { + id: createId(), + type: QuestionType.OpenText, + headline: "What did you come here to do today?", + longAnswer: true, + required: false, + }, + ], + thankYouCard: thankYouCardDefault, + }, + }, + { + name: "Identify Customer Goals", + icon: ArrowRightCircleIcon, + category: "Product Experience", + description: + "Better understand if your messaging creates the right expectations of the value your product provides.", + preset: { + name: "Identify Customer Goals", + questions: [ + { + id: createId(), + type: QuestionType.MultipleChoiceSingle, + headline: "What's your primary goal for using Formbricks?", + required: true, + shuffleOption: "none", + choices: [ + { + id: createId(), + label: "Understand my user base deeply", + }, + { + id: createId(), + label: "Identify upselling opportunities", + }, + { + id: createId(), + label: "Build the best possible product", + }, + { + id: createId(), + label: "Rule the world to make everyone breakfast brussels sprouts.", + }, + ], + }, + ], + thankYouCard: thankYouCardDefault, + }, + }, + { + name: "Feature Chaser", + icon: DogChaserIcon, + category: "Product Experience", + description: "Follow up with users who just used a specific feature.", + preset: { + name: "Feature Chaser", + questions: [ + { + id: createId(), + type: QuestionType.Rating, + headline: "How easy was it to achieve your goal?", + required: true, + lowerLabel: "Very difficult", + upperLabel: "Very easy", + range: 5, + scale: "number", + }, + { + id: createId(), + type: QuestionType.OpenText, + headline: "Wanna add something?", + subheader: "This really helps us do better!", + longAnswer: true, + required: false, + }, + ], + thankYouCard: thankYouCardDefault, + }, + }, + { + name: "Fake Door Follow-Up", + icon: DoorIcon, + category: "Exploration", + description: "Follow up with users who ran into one of your Fake Door experiments.", + preset: { + name: "Fake Door Follow-Up", + questions: [ + { + id: createId(), + type: QuestionType.Rating, + headline: "How important is this feature for you?", + required: true, + lowerLabel: "Not important", + upperLabel: "Very important", + range: 5, + scale: "number", + }, + ], + thankYouCard: thankYouCardDefault, + }, + }, + { + name: "Product Market Fit Survey (short)", + icon: PMFIcon, + category: "Product Experience", + + description: "Measure PMF by assessing how disappointed users would be if your product disappeared.", + preset: { + name: "Product Market Fit Survey (short)", + questions: [ + { + id: createId(), + type: QuestionType.MultipleChoiceSingle, + headline: "How disappointed would you be if you could no longer use Formbricks?", + subheader: "Please select one of the following options:", + required: true, + shuffleOption: "none", + choices: [ + { + id: createId(), + label: "Not at all disappointed", + }, + { + id: createId(), + label: "Somewhat disappointed", + }, + { + id: createId(), + label: "Very disappointed", + }, + ], + }, + { + id: createId(), + type: QuestionType.OpenText, + headline: "How can we improve our service for you?", + subheader: "Please be as specific as possible.", + longAnswer: true, + required: true, + }, + ], + thankYouCard: thankYouCardDefault, + }, + }, + { + name: "Feedback Box", + icon: FeedbackIcon, + category: "Product Experience", + description: "Give your users the chance to seamlessly share what's on their minds.", + preset: { + name: "Feedback Box", + questions: [ + { + id: createId(), + type: QuestionType.MultipleChoiceSingle, + headline: "What's on your mind, boss?", + subheader: "Thanks for sharing. We'll get back to you asap.", + required: true, + shuffleOption: "none", + choices: [ + { + id: createId(), + label: "Bug report 🐞", + }, + { + id: createId(), + label: "Feature Request 💡", + }, + ], + }, + { + id: createId(), + type: QuestionType.OpenText, + headline: "Give us the juicy details:", + longAnswer: true, + required: true, + }, + ], + thankYouCard: thankYouCardDefault, + }, + }, + { + name: "Integration usage survey", + icon: DashboardIcon, + category: "Product Experience", + description: "Evaluate how easily users can add integrations to your product. Find blind spots.", + preset: { + name: "Integration Usage Survey", + questions: [ + { + id: createId(), + type: QuestionType.MultipleChoiceSingle, + headline: "How easy was it to set this integration up?", + required: true, + shuffleOption: "none", + choices: [ + { + id: createId(), + label: "Extremely difficult", + }, + { + id: createId(), + label: "It took a while, but I got it", + }, + { + id: createId(), + label: "It was alright", + }, + { + id: createId(), + label: "Quite easy", + }, + { + id: createId(), + label: "Very easy, love it!", + }, + ], + }, + { + id: createId(), + type: QuestionType.OpenText, + headline: "Which product would you like to integrate next?", + subheader: "We keep building integrations. Yours can be next:", + longAnswer: true, + required: false, + }, + ], + thankYouCard: thankYouCardDefault, + }, + }, + { + name: "New integration survey", + icon: DashboardIcon, + category: "Exploration", + description: "Find out which integrations your users would like to see next.", + preset: { + name: "New integration survey", + questions: [ + { + id: createId(), + type: QuestionType.MultipleChoiceSingle, + headline: "Which other tools are you using?", + required: true, + shuffleOption: "none", + choices: [ + { + id: createId(), + label: "PostHog", + }, + { + id: createId(), + label: "Segment", + }, + { + id: createId(), + label: "Hubspot", + }, + { + id: createId(), + label: "Twilio", + }, + { + id: createId(), + label: "Other", + }, + ], + }, + { + id: createId(), + type: QuestionType.OpenText, + headline: "If you chose other, please clarify:", + longAnswer: true, + required: false, + }, + ], + thankYouCard: thankYouCardDefault, + }, + }, + { + name: "Docs Feedback", + icon: CodeBookIcon, + category: "Product Experience", + description: "Measure how clear each page of your developer documentation is.", + preset: { + name: "Formbricks Docs Feedback", + questions: [ + { + id: createId(), + type: QuestionType.MultipleChoiceSingle, + headline: "Was this page helpful?", + required: true, + shuffleOption: "none", + choices: [ + { + id: createId(), + label: "Yes 👍", + }, + { + id: createId(), + label: "No 👎", + }, + ], + }, + { + id: createId(), + type: QuestionType.OpenText, + headline: "Please elaborate:", + longAnswer: true, + required: false, + }, + { + id: createId(), + type: QuestionType.OpenText, + headline: "Page URL", + longAnswer: true, + required: false, + }, + ], + thankYouCard: thankYouCardDefault, + }, + }, + { + name: "Interview Prompt", + icon: InterviewPromptIcon, + category: "Exploration", + description: "Invite a specific subset of your users to schedule an interview with your product team.", + preset: { + name: "Interview Prompt", + questions: [ + { + id: createId(), + type: QuestionType.CTA, + headline: "Do you have 15 min to talk to us? 🙏", + html: "You're one of our power users. We would love to interview you briefly!", + buttonLabel: "Book interview", + buttonUrl: "https://cal.com/johannes/onboarding?duration=25", + buttonExternal: true, + required: false, + dismissButtonLabel: "Maybe later", + }, + ], + thankYouCard: thankYouCardDefault, + }, + }, + { + name: "Review Prompt", + icon: HeartCommentIcon, + category: "Growth", + description: "Invite users who love your product to review it publicly.", + preset: { + name: "Review Prompt", + questions: [ + { + id: createId(), + type: QuestionType.CTA, + headline: "You're one of our most valued customers! Please write a review for us.", + buttonLabel: "Write review", + buttonUrl: "https://formbricks.com/github", + buttonExternal: true, + required: false, + }, + ], + thankYouCard: thankYouCardDefault, + }, + }, + { + name: "Net Promoter Score (NPS)", + icon: GaugeSpeedFastIcon, + category: "Customer Success", + description: "Measure the Net Promoter Score of your product.", + preset: { + name: "Formbricks NPS", + questions: [ + { + id: createId(), + type: QuestionType.NPS, + headline: "How likely are you to recommend Formbricks to a friend or colleague?", + required: false, + lowerLabel: "Not likely", + upperLabel: "Very likely", + }, + ], + thankYouCard: thankYouCardDefault, + }, + }, + { + name: "Identify upsell opportunities", + icon: ArrowUpRightIcon, + category: "Increase Revenue", + description: "Find out how much time your product saves your user. Use it to upsell.", + preset: { + name: "Identify upsell opportunities", + questions: [ + { + id: createId(), + type: QuestionType.MultipleChoiceSingle, + headline: "How many hours does your team save per week by using Formbricks?", + required: true, + shuffleOption: "none", + choices: [ + { + id: createId(), + label: "Less than 1 hour", + }, + { + id: createId(), + label: "1 to 2 hours", + }, + { + id: createId(), + label: "3 to 5 hours", + }, + { + id: createId(), + label: "5+ hours", + }, + ], + }, + ], + thankYouCard: thankYouCardDefault, + }, + }, + { + name: "Build Product Roadmap", + icon: LoadingBarIcon, + category: "Product Experience", + description: "Ask how users rate your product. Identify blind spots to build your roadmap.", + preset: { + name: "Build Product Roadmap", + questions: [ + { + id: createId(), + type: QuestionType.Rating, + headline: "How satisfied are you with the features of Formbricks?", + required: true, + lowerLabel: "Not satisfied", + upperLabel: "Very satisfied", + scale: "number", + range: 5, + }, + { + id: createId(), + type: QuestionType.OpenText, + headline: "What's the #1 thing you'd like to change in Formbricks?", + longAnswer: true, + required: false, + }, + ], + thankYouCard: thankYouCardDefault, + }, + }, + { + name: "Gauge Feature Satisfaction", + icon: UserSearchGlasIcon, + category: "Product Experience", + description: "Evaluate the satisfaction of specific features of your product.", + preset: { + name: "Gauge Feature Satisfaction", + questions: [ + { + id: createId(), + type: QuestionType.Rating, + headline: "How easy was it to achieve ... ?", + required: true, + lowerLabel: "Not easy", + upperLabel: "Very easy", + scale: "number", + range: 5, + }, + { + id: createId(), + type: QuestionType.OpenText, + headline: "What is one thing we could do better?", + longAnswer: true, + required: false, + }, + ], + thankYouCard: thankYouCardDefault, + }, + }, + { + name: "Marketing Site Clarity", + icon: VideoTabletAdjustIcon, + category: "Growth", + description: "Identify users dropping off your marketing site. Improve your messaging.", + preset: { + name: "Marketing Site Clarity", + questions: [ + { + id: createId(), + type: QuestionType.MultipleChoiceSingle, + headline: "Do you have all the info you need to give Formbricks a try?", + required: true, + shuffleOption: "none", + choices: [ + { + id: createId(), + label: "Yes, totally", + }, + { + id: createId(), + label: "Kind of...", + }, + { + id: createId(), + label: "No, not at all", + }, + ], + }, + { + id: createId(), + type: QuestionType.OpenText, + headline: "What’s missing or unclear to you about Formbricks?", + longAnswer: true, + required: false, + }, + { + id: createId(), + type: QuestionType.CTA, + headline: "Thanks for your answer! Get 25% off your first 6 months:", + required: false, + buttonLabel: "Get discount", + buttonUrl: "https://app.formbricks.com/auth/signup", + buttonExternal: true, + }, + ], + thankYouCard: thankYouCardDefault, + }, + }, +]; + +export const findTemplateByName = (name: string): Template | undefined => { + return templates.find((template) => template.name === name); +}; diff --git a/apps/formbricks-com/src/components/home/Features.tsx b/apps/formbricks-com/src/components/home/Features.tsx new file mode 100644 index 0000000000..6ef45f9657 --- /dev/null +++ b/apps/formbricks-com/src/components/home/Features.tsx @@ -0,0 +1,66 @@ +import { CodeFileIcon, EyeIcon, HandPuzzleIcon } from "@formbricks/ui"; +import HeadingCentered from "../shared/HeadingCentered"; + +const features = [ + { + id: "compliance", + name: "Smoothly Compliant", + description: "Use our GDPR-compliant Cloud or self-host the entire solution.", + icon: EyeIcon, + }, + { + id: "customizable", + name: "Fully Customizable", + description: "Full customizability and extendability. Integrate with your stack easily.", + icon: HandPuzzleIcon, + }, + { + id: "independent", + name: "Stay independent", + description: "The code is open-source. Do with it what your organization needs.", + icon: CodeFileIcon, + }, +]; +export const Features: React.FC = () => { + return ( +
+
+ + +
    + {features.map((feature) => { + const IconComponent: React.ElementType = feature.icon; + + return ( +
  • +
    +
    + +
    +
    +
    +

    + {feature.name} +

    +
    +
    Description
    +
    {feature.description}
    +
    +
    +
  • + ); + })} +
+
+
+ ); +}; + +export default Features; diff --git a/apps/formbricks-com/src/components/home/GitHubSponsorship.tsx b/apps/formbricks-com/src/components/home/GitHubSponsorship.tsx new file mode 100644 index 0000000000..a089c5b7dd --- /dev/null +++ b/apps/formbricks-com/src/components/home/GitHubSponsorship.tsx @@ -0,0 +1,45 @@ +import GitHubMarkWhite from "@/images/github-mark-white.svg"; +import GitHubMarkDark from "@/images/github-mark.svg"; +import Image from "next/image"; +import Link from "next/link"; + +export const GitHubSponsorship: React.FC = () => { + return ( +
+ +
+ GitHub Sponsors Formbricks badge + GitHub Sponsors Formbricks badge +
+

+ Proudly Open-Source 🤍 +

+

+ We're proud to to be supported by GitHubs Open-Source Program!{" "} + + + Read more. + + +

+
+ ); +}; + +export default GitHubSponsorship; diff --git a/apps/formbricks-com/src/components/home/Hero.tsx b/apps/formbricks-com/src/components/home/Hero.tsx new file mode 100644 index 0000000000..2b06350668 --- /dev/null +++ b/apps/formbricks-com/src/components/home/Hero.tsx @@ -0,0 +1,119 @@ +import CalLogoDark from "@/images/clients/cal-logo-dark.svg"; +import CalLogoLight from "@/images/clients/cal-logo-light.svg"; +import ClovyrLogo from "@/images/clients/clovyr-logo.svg"; +import CrowdLogoDark from "@/images/clients/crowd-logo-dark.svg"; +import CrowdLogoLight from "@/images/clients/crowd-logo-light.svg"; +import NILogoDark from "@/images/clients/niLogoDark.svg"; +import NILogoLight from "@/images/clients/niLogoWhite.svg"; +import AnimationFallback from "@/public/animations/opensource-xm-platform-formbricks-fallback.png"; +import { Button } from "@formbricks/ui"; +import { ChevronRightIcon } from "@heroicons/react/24/outline"; +import { usePlausible } from "next-plausible"; +import Image from "next/image"; +import { useRouter } from "next/router"; +import HeroAnimation from "./HeroAnimation"; + +export const Hero: React.FC = ({}) => { + const plausible = usePlausible(); + const router = useRouter(); + return ( +
+
+ + We're Open-Source | Star us on GitHub{" "} + + +

+ Open-source Experience Management +

+ +

+ Understand what customers think & feel about your product. +
+ + Natively integrate user research with minimal dev attention,{" "} + privacy-first. + +

+ +
+

+ Trusted by +

+
+ Cal Logo + Cal Logo + Crowd.dev Logo + Crowd.dev Logo + Clovyr Logo + Neverinstall Logo + Neverinstall Logo +
+
+
+ + +
+
+
+ +
+
+ ); +}; + +export default Hero; diff --git a/apps/formbricks-com/src/components/home/HeroAnimation.tsx b/apps/formbricks-com/src/components/home/HeroAnimation.tsx new file mode 100644 index 0000000000..163cf9a29b --- /dev/null +++ b/apps/formbricks-com/src/components/home/HeroAnimation.tsx @@ -0,0 +1,53 @@ +import { useEffect, useRef, useState } from "react"; +import type { LottiePlayer } from "lottie-web"; +import Image from "next/image"; + +export const HeroAnimation: React.FC = ({ fallbackImage, ...props }) => { + const [loaded, setLoaded] = useState(false); + const ref = useRef(null); + const [lottie, setLottie] = useState(null); + + useEffect(() => { + import("lottie-web").then((Lottie) => setLottie(Lottie.default)); + }, []); + + useEffect(() => { + if (lottie && ref.current) { + const animation = lottie.loadAnimation({ + container: ref.current, + renderer: "svg", + loop: true, + autoplay: true, + // path to your animation file, place it inside public folder + path: "/animations/opensource-xm-platform-formbricks.json", + }); + + animation.addEventListener("DOMLoaded", () => { + setLoaded(true); + }); + + return () => animation.destroy(); + } + }, [lottie]); + + return ( +
+
+ {!loaded && ( +
+ Fallback Image +
+ )} +
+ ); +}; + +export default HeroAnimation; diff --git a/apps/formbricks-com/src/components/home/Highlights.tsx b/apps/formbricks-com/src/components/home/Highlights.tsx new file mode 100644 index 0000000000..cea8820ad1 --- /dev/null +++ b/apps/formbricks-com/src/components/home/Highlights.tsx @@ -0,0 +1,68 @@ +import ImageAttributesDark from "@/images/attributes-dark.svg"; +import ImageAttributesLight from "@/images/attributes-light.svg"; +import ImageEventTriggerDark from "@/images/event-trigger-dark.svg"; +import ImageEventTriggerLight from "@/images/event-trigger-light.svg"; +import Image from "next/image"; + +export const Highlights: React.FC = ({}) => { + return ( + <> +
+
+
+
+

+ Ask at the right moment, +
+ get the data you need. +

+

+ Follow up emails are so 2010. Ask users as they experience your product - and leverage a + significantly higher conversion rate. +

+
+
+ react library + react library +
+
+
+
+
+
+
+
+ react library + react library +
+
+

+ Dont' ‘Spray and pray’. +
+ Pre-segment granularly. +

+

+ Pre-segment who sees your survey based on custom attributes. Keep the signal, cancel out the + noise. +

+
+
+
+
+ + ); +}; + +export default Highlights; diff --git a/apps/formbricks-com/src/components/home/SetupTabs.tsx b/apps/formbricks-com/src/components/home/SetupTabs.tsx new file mode 100644 index 0000000000..c753ae245a --- /dev/null +++ b/apps/formbricks-com/src/components/home/SetupTabs.tsx @@ -0,0 +1,71 @@ +import clsx from "clsx"; +import { useState } from "react"; +import { IoLogoHtml5, IoLogoNpm } from "react-icons/io5"; +import CodeBlock from "../shared/CodeBlock"; + +interface SecondNavbarProps { + tabs: { id: string; label: string; icon?: React.ReactNode }[]; + activeId: string; + setActiveId: (id: string) => void; +} + +export const TabBar: React.FC = ({ tabs, activeId, setActiveId }) => { + return ( +
+ +
+ ); +}; + +const tabs = [ + { id: "npm", label: "NPM", icon: }, + { id: "html", label: "HTML", icon: }, +]; + +export const SetupInstructions: React.FC = ({}) => { + const [activeTab, setActiveTab] = useState(tabs[0].id); + + return ( +
+ +
+ {activeTab === "npm" ? ( + <> + npm install @formbricks/js + + {`import formbricks from "@formbricks/js"; + +if (typeof window !== "undefined") { + formbricks.init({ + environmentId: "claV2as2kKAqF28fJ8", + apiHost: "https://app.formbricks.com", + }); +}`} + + ) : activeTab === "html" ? ( + {``} + ) : null} +
+
+ ); +}; + +export default SetupInstructions; diff --git a/apps/formbricks-com/src/components/home/Steps.tsx b/apps/formbricks-com/src/components/home/Steps.tsx new file mode 100644 index 0000000000..93ee57a091 --- /dev/null +++ b/apps/formbricks-com/src/components/home/Steps.tsx @@ -0,0 +1,148 @@ +import DemoPreview from "@/components/dummyUI/DemoPreview"; +import DashboardMockupDark from "@/images/dashboard-mockup-dark.png"; +import DashboardMockup from "@/images/dashboard-mockup.png"; +import { Button } from "@formbricks/ui"; +import { CursorArrowRaysIcon } from "@heroicons/react/24/solid"; +import Image from "next/image"; +import { useState } from "react"; +import AddEventDummy from "../dummyUI/AddEventDummy"; +import AddNoCodeEventModalDummy from "../dummyUI/AddNoCodeEventModalDummy"; +import HeadingCentered from "../shared/HeadingCentered"; +import SetupTabs from "./SetupTabs"; + +export const Steps: React.FC = () => { + const [isAddEventModalOpen, setAddEventModalOpen] = useState(false); + + return ( + <> + +
+
+
+
+

Step 1

+

+ Copy + Paste +

+

+ Simply copy a <script> tag to your HTML head - that’s about it. Or use NPM to install + Formbricks for React, Vue, Svelte, etc. +

+
+
+ +
+
+
+
+
+
+
+
+
+ +
+
+
+

Step 2

+

+ No-Code: Track User Actions +

+

+ Set up user actions which can trigger your survey without writing a single line of code. + Surveys can be triggered on specific pages or after an element is clicked. +

+
+
+
+
+
+
+
+
+

Step 3

+

+ Create your survey +

+

+ Start from a template - or from scratch. Ask what you want, in any language. You can also + adjust the look and feel of your survey. +

+
+
+ +
+
+
+
+
+
+
+
+
+ +
+
+
+

Step 4

+

+ Set segment and trigger +

+

+ Create a custom segment for each survey. Use attributes and past user actions to only survey + the people who have answers. Trigger your survey on any user action in your app. +

+
+
+
+
+
+
+
+
+

Step 5

+

+ Make better decisions +

+

+ Gather all insights you can - including partial submissions. Build conviction for the next + product decision. Better data, better business. +

+
+
+ Data Pipelines + Data Pipelines +
+
+
+
+ + + + ); +}; + +export default Steps; diff --git a/apps/formbricks-com/src/components/home/VideoWalkThrough.tsx b/apps/formbricks-com/src/components/home/VideoWalkThrough.tsx new file mode 100644 index 0000000000..10259215e3 --- /dev/null +++ b/apps/formbricks-com/src/components/home/VideoWalkThrough.tsx @@ -0,0 +1,17 @@ +import { ResponsiveVideo } from "@formbricks/ui"; +import Modal from "../shared/Modal"; + +interface VideoWalkThroughProps { + open: boolean; + setOpen: (v: boolean) => void; +} + +export const VideoWalkThrough: React.FC = ({ open, setOpen }) => { + return ( + +
+ +
+
+ ); +}; diff --git a/apps/formbricks-com/src/components/icons/BellIcon.tsx b/apps/formbricks-com/src/components/icons/BellIcon.tsx deleted file mode 100644 index 1c0c2291cd..0000000000 --- a/apps/formbricks-com/src/components/icons/BellIcon.tsx +++ /dev/null @@ -1,17 +0,0 @@ -export function BellIcon(props: React.ComponentPropsWithoutRef<'svg'>) { - return ( - - ) -} diff --git a/apps/formbricks-com/src/components/icons/BoltIcon.tsx b/apps/formbricks-com/src/components/icons/BoltIcon.tsx deleted file mode 100644 index 308d997cc0..0000000000 --- a/apps/formbricks-com/src/components/icons/BoltIcon.tsx +++ /dev/null @@ -1,11 +0,0 @@ -export function BoltIcon(props: React.ComponentPropsWithoutRef<'svg'>) { - return ( - - ) -} diff --git a/apps/formbricks-com/src/components/icons/BookIcon.tsx b/apps/formbricks-com/src/components/icons/BookIcon.tsx deleted file mode 100644 index 9f7709bc3c..0000000000 --- a/apps/formbricks-com/src/components/icons/BookIcon.tsx +++ /dev/null @@ -1,17 +0,0 @@ -export function BookIcon(props: React.ComponentPropsWithoutRef<'svg'>) { - return ( - - ) -} diff --git a/apps/formbricks-com/src/components/icons/CalendarIcon.tsx b/apps/formbricks-com/src/components/icons/CalendarIcon.tsx deleted file mode 100644 index e9d374867d..0000000000 --- a/apps/formbricks-com/src/components/icons/CalendarIcon.tsx +++ /dev/null @@ -1,23 +0,0 @@ -export function CalendarIcon(props: React.ComponentPropsWithoutRef<'svg'>) { - return ( - - ) -} diff --git a/apps/formbricks-com/src/components/icons/CartIcon.tsx b/apps/formbricks-com/src/components/icons/CartIcon.tsx deleted file mode 100644 index 30c9438f7f..0000000000 --- a/apps/formbricks-com/src/components/icons/CartIcon.tsx +++ /dev/null @@ -1,15 +0,0 @@ -export function CartIcon(props: React.ComponentPropsWithoutRef<'svg'>) { - return ( - - ) -} diff --git a/apps/formbricks-com/src/components/icons/ChatBubbleIcon.tsx b/apps/formbricks-com/src/components/icons/ChatBubbleIcon.tsx deleted file mode 100644 index 418427b05d..0000000000 --- a/apps/formbricks-com/src/components/icons/ChatBubbleIcon.tsx +++ /dev/null @@ -1,17 +0,0 @@ -export function ChatBubbleIcon(props: React.ComponentPropsWithoutRef<'svg'>) { - return ( - - ) -} diff --git a/apps/formbricks-com/src/components/icons/CheckIcon.tsx b/apps/formbricks-com/src/components/icons/CheckIcon.tsx deleted file mode 100644 index b9433644d1..0000000000 --- a/apps/formbricks-com/src/components/icons/CheckIcon.tsx +++ /dev/null @@ -1,17 +0,0 @@ -export function CheckIcon(props: React.ComponentPropsWithoutRef<'svg'>) { - return ( - - ) -} diff --git a/apps/formbricks-com/src/components/icons/ChevronRightLeftIcon.tsx b/apps/formbricks-com/src/components/icons/ChevronRightLeftIcon.tsx deleted file mode 100644 index 281c9de529..0000000000 --- a/apps/formbricks-com/src/components/icons/ChevronRightLeftIcon.tsx +++ /dev/null @@ -1,19 +0,0 @@ -export function ChevronRightLeftIcon( - props: React.ComponentPropsWithoutRef<'svg'>, -) { - return ( - - ) -} diff --git a/apps/formbricks-com/src/components/icons/ClipboardIcon.tsx b/apps/formbricks-com/src/components/icons/ClipboardIcon.tsx deleted file mode 100644 index 33d997b5b3..0000000000 --- a/apps/formbricks-com/src/components/icons/ClipboardIcon.tsx +++ /dev/null @@ -1,17 +0,0 @@ -export function ClipboardIcon(props: React.ComponentPropsWithoutRef<'svg'>) { - return ( - - ) -} diff --git a/apps/formbricks-com/src/components/icons/CogIcon.tsx b/apps/formbricks-com/src/components/icons/CogIcon.tsx deleted file mode 100644 index cedecf5420..0000000000 --- a/apps/formbricks-com/src/components/icons/CogIcon.tsx +++ /dev/null @@ -1,19 +0,0 @@ -export function CogIcon(props: React.ComponentPropsWithoutRef<'svg'>) { - return ( - - ) -} diff --git a/apps/formbricks-com/src/components/icons/CopyIcon.tsx b/apps/formbricks-com/src/components/icons/CopyIcon.tsx deleted file mode 100644 index 0eedaaa4cb..0000000000 --- a/apps/formbricks-com/src/components/icons/CopyIcon.tsx +++ /dev/null @@ -1,17 +0,0 @@ -export function CopyIcon(props: React.ComponentPropsWithoutRef<'svg'>) { - return ( - - ) -} diff --git a/apps/formbricks-com/src/components/icons/DocumentIcon.tsx b/apps/formbricks-com/src/components/icons/DocumentIcon.tsx deleted file mode 100644 index 8f83d2094f..0000000000 --- a/apps/formbricks-com/src/components/icons/DocumentIcon.tsx +++ /dev/null @@ -1,17 +0,0 @@ -export function DocumentIcon(props: React.ComponentPropsWithoutRef<'svg'>) { - return ( - - ) -} diff --git a/apps/formbricks-com/src/components/icons/EnvelopeIcon.tsx b/apps/formbricks-com/src/components/icons/EnvelopeIcon.tsx deleted file mode 100644 index de57e4c475..0000000000 --- a/apps/formbricks-com/src/components/icons/EnvelopeIcon.tsx +++ /dev/null @@ -1,17 +0,0 @@ -export function EnvelopeIcon(props: React.ComponentPropsWithoutRef<'svg'>) { - return ( - - ) -} diff --git a/apps/formbricks-com/src/components/icons/FaceSmileIcon.tsx b/apps/formbricks-com/src/components/icons/FaceSmileIcon.tsx deleted file mode 100644 index 7c855a63ea..0000000000 --- a/apps/formbricks-com/src/components/icons/FaceSmileIcon.tsx +++ /dev/null @@ -1,17 +0,0 @@ -export function FaceSmileIcon(props: React.ComponentPropsWithoutRef<'svg'>) { - return ( - - ) -} diff --git a/apps/formbricks-com/src/components/icons/FolderIcon.tsx b/apps/formbricks-com/src/components/icons/FolderIcon.tsx deleted file mode 100644 index 050c77bb75..0000000000 --- a/apps/formbricks-com/src/components/icons/FolderIcon.tsx +++ /dev/null @@ -1,22 +0,0 @@ -export function FolderIcon(props: React.ComponentPropsWithoutRef<'svg'>) { - return ( - - ) -} diff --git a/apps/formbricks-com/src/components/icons/LinkIcon.tsx b/apps/formbricks-com/src/components/icons/LinkIcon.tsx deleted file mode 100644 index f77d6184ab..0000000000 --- a/apps/formbricks-com/src/components/icons/LinkIcon.tsx +++ /dev/null @@ -1,12 +0,0 @@ -export function LinkIcon(props: React.ComponentPropsWithoutRef<'svg'>) { - return ( - - ) -} diff --git a/apps/formbricks-com/src/components/icons/ListIcon.tsx b/apps/formbricks-com/src/components/icons/ListIcon.tsx deleted file mode 100644 index 69354ec067..0000000000 --- a/apps/formbricks-com/src/components/icons/ListIcon.tsx +++ /dev/null @@ -1,17 +0,0 @@ -export function ListIcon(props: React.ComponentPropsWithoutRef<'svg'>) { - return ( - - ) -} diff --git a/apps/formbricks-com/src/components/icons/MagnifyingGlassIcon.tsx b/apps/formbricks-com/src/components/icons/MagnifyingGlassIcon.tsx deleted file mode 100644 index 5e219f6340..0000000000 --- a/apps/formbricks-com/src/components/icons/MagnifyingGlassIcon.tsx +++ /dev/null @@ -1,15 +0,0 @@ -export function MagnifyingGlassIcon( - props: React.ComponentPropsWithoutRef<'svg'>, -) { - return ( - - ) -} diff --git a/apps/formbricks-com/src/components/icons/MapPinIcon.tsx b/apps/formbricks-com/src/components/icons/MapPinIcon.tsx deleted file mode 100644 index 6070adb133..0000000000 --- a/apps/formbricks-com/src/components/icons/MapPinIcon.tsx +++ /dev/null @@ -1,19 +0,0 @@ -export function MapPinIcon(props: React.ComponentPropsWithoutRef<'svg'>) { - return ( - - ) -} diff --git a/apps/formbricks-com/src/components/icons/PackageIcon.tsx b/apps/formbricks-com/src/components/icons/PackageIcon.tsx deleted file mode 100644 index 6bd9225f5f..0000000000 --- a/apps/formbricks-com/src/components/icons/PackageIcon.tsx +++ /dev/null @@ -1,16 +0,0 @@ -export function PackageIcon(props: React.ComponentPropsWithoutRef<'svg'>) { - return ( - - ) -} diff --git a/apps/formbricks-com/src/components/icons/PaperAirplaneIcon.tsx b/apps/formbricks-com/src/components/icons/PaperAirplaneIcon.tsx deleted file mode 100644 index 12c29b9150..0000000000 --- a/apps/formbricks-com/src/components/icons/PaperAirplaneIcon.tsx +++ /dev/null @@ -1,19 +0,0 @@ -export function PaperAirplaneIcon( - props: React.ComponentPropsWithoutRef<'svg'>, -) { - return ( - - ) -} diff --git a/apps/formbricks-com/src/components/icons/PaperClipIcon.tsx b/apps/formbricks-com/src/components/icons/PaperClipIcon.tsx deleted file mode 100644 index db51c7f708..0000000000 --- a/apps/formbricks-com/src/components/icons/PaperClipIcon.tsx +++ /dev/null @@ -1,12 +0,0 @@ -export function PaperClipIcon(props: React.ComponentPropsWithoutRef<'svg'>) { - return ( - - ) -} diff --git a/apps/formbricks-com/src/components/icons/ShapesIcon.tsx b/apps/formbricks-com/src/components/icons/ShapesIcon.tsx deleted file mode 100644 index ac57a52ca2..0000000000 --- a/apps/formbricks-com/src/components/icons/ShapesIcon.tsx +++ /dev/null @@ -1,17 +0,0 @@ -export function ShapesIcon(props: React.ComponentPropsWithoutRef<'svg'>) { - return ( - - ) -} diff --git a/apps/formbricks-com/src/components/icons/ShirtIcon.tsx b/apps/formbricks-com/src/components/icons/ShirtIcon.tsx deleted file mode 100644 index f8cdfd5086..0000000000 --- a/apps/formbricks-com/src/components/icons/ShirtIcon.tsx +++ /dev/null @@ -1,11 +0,0 @@ -export function ShirtIcon(props: React.ComponentPropsWithoutRef<'svg'>) { - return ( - - ) -} diff --git a/apps/formbricks-com/src/components/icons/SquaresPlusIcon.tsx b/apps/formbricks-com/src/components/icons/SquaresPlusIcon.tsx deleted file mode 100644 index 0005f59d57..0000000000 --- a/apps/formbricks-com/src/components/icons/SquaresPlusIcon.tsx +++ /dev/null @@ -1,17 +0,0 @@ -export function SquaresPlusIcon(props: React.ComponentPropsWithoutRef<'svg'>) { - return ( - - ) -} diff --git a/apps/formbricks-com/src/components/icons/TagIcon.tsx b/apps/formbricks-com/src/components/icons/TagIcon.tsx deleted file mode 100644 index f360241439..0000000000 --- a/apps/formbricks-com/src/components/icons/TagIcon.tsx +++ /dev/null @@ -1,19 +0,0 @@ -export function TagIcon(props: React.ComponentPropsWithoutRef<'svg'>) { - return ( - - ) -} diff --git a/apps/formbricks-com/src/components/icons/UserIcon.tsx b/apps/formbricks-com/src/components/icons/UserIcon.tsx deleted file mode 100644 index 78bb8f6174..0000000000 --- a/apps/formbricks-com/src/components/icons/UserIcon.tsx +++ /dev/null @@ -1,24 +0,0 @@ -export function UserIcon(props: React.ComponentPropsWithoutRef<'svg'>) { - return ( - - ) -} diff --git a/apps/formbricks-com/src/components/icons/UsersIcon.tsx b/apps/formbricks-com/src/components/icons/UsersIcon.tsx deleted file mode 100644 index aa7d13b3d1..0000000000 --- a/apps/formbricks-com/src/components/icons/UsersIcon.tsx +++ /dev/null @@ -1,28 +0,0 @@ -export function UsersIcon(props: React.ComponentPropsWithoutRef<'svg'>) { - return ( - - ) -} diff --git a/apps/formbricks-com/src/components/mdx.tsx b/apps/formbricks-com/src/components/mdx.tsx deleted file mode 100644 index 10b9823416..0000000000 --- a/apps/formbricks-com/src/components/mdx.tsx +++ /dev/null @@ -1,131 +0,0 @@ -import Link from 'next/link' -import clsx from 'clsx' - -import { Feedback } from '@/app/docs/_components/Feedback' -import { Heading } from '@/app/docs/_components/Heading' -import { Prose } from '@/app/docs/_components/Prose' - -export const a = Link -export { Button } from '@/app/docs/_components/Button' -export { - CodeGroup, - Code as code, - Pre as pre, -} from '@/app/docs/_components/Code' - -export function wrapper({ children }: { children: React.ReactNode }) { - return ( -
- {children} -
- -
-
- ) -} - -export const h2 = function H2( - props: Omit, 'level'> -) { - return -} - -function InfoIcon(props: React.ComponentPropsWithoutRef<'svg'>) { - return ( - - ) -} - -export function Note({ children }: { children: React.ReactNode }) { - return ( -
- -
- {children} -
-
- ) -} - -export function Row({ children }: { children: React.ReactNode }) { - return ( -
- {children} -
- ) -} - -export function Col({ - children, - sticky = false, -}: { - children: React.ReactNode - sticky?: boolean -}) { - return ( -
:first-child]:mt-0 [&>:last-child]:mb-0', - sticky && 'xl:sticky xl:top-24' - )} - > - {children} -
- ) -} - -export function Properties({ children }: { children: React.ReactNode }) { - return ( -
-
    - {children} -
-
- ) -} - -export function Property({ - name, - children, - type, -}: { - name: string - children: React.ReactNode - type?: string -}) { - return ( -
  • -
    -
    Name
    -
    - {name} -
    - {type && ( - <> -
    Type
    -
    - {type} -
    - - )} -
    Description
    -
    - {children} -
    -
    -
  • - ) -} diff --git a/apps/formbricks-com/src/components/shared/APILayout.tsx b/apps/formbricks-com/src/components/shared/APILayout.tsx new file mode 100644 index 0000000000..d910c67f88 --- /dev/null +++ b/apps/formbricks-com/src/components/shared/APILayout.tsx @@ -0,0 +1,214 @@ +import { ChevronDownIcon, ChevronLeftIcon, ChevronRightIcon } from "@heroicons/react/24/solid"; +import clsx from "clsx"; +import { useState } from "react"; + +interface APICallProps { + method: "GET" | "POST"; + url: string; + description: string; + headers: { + label: string; + type: string; + description: string; + required?: boolean; + }[]; + bodies: { + label: string; + type: string; + description: string; + required?: boolean; + }[]; + responses: { + color: string; + statusCode: string; + description: string; + example?: string; + }[]; + example?: string; +} + +export function APILayout({ method, url, description, headers, bodies, responses, example }: APICallProps) { + const [switchState, setSwitchState] = useState(true); + function handleOnChange() { + setSwitchState(!switchState); + } + + return ( +
    + {switchState ? ( +
    + ); +} + +interface ParaProps { + label: string; + type: string; + description: string; + required?: boolean; +} + +function Parameter({ label, type, description, required }: ParaProps) { + return ( + <> +
    +
    + {label} + {required &&

    *

    } +
    +
    {type}
    +
    {description}
    +
    + + ); +} + +interface RespProps { + color: string; + statusCode: string; + description: string; + example?: string; +} + +function Response({ color, statusCode, description, example }: RespProps) { + const [toggleExample, setSwitchState] = useState(false); + function handleOnChange() { + setSwitchState(!toggleExample); + } + return ( +
    +
    +
    +   +
    +
    {statusCode}
    +
    +
    +
    {description}
    +
    + {example && + (toggleExample ? ( +
    +
    + {example && toggleExample && ( +
    + {example} +
    + )} +
    + ); +} diff --git a/apps/formbricks-com/src/components/shared/AuthorBox.tsx b/apps/formbricks-com/src/components/shared/AuthorBox.tsx new file mode 100644 index 0000000000..f818fe9159 --- /dev/null +++ b/apps/formbricks-com/src/components/shared/AuthorBox.tsx @@ -0,0 +1,36 @@ +import Image from "next/image"; +import AuthorJohannes from "@/images/blog/johannes-co-founder-formbricks-small.jpg"; + +interface AuthorBoxProps { + name: string; + title: string; + date: string; + duration: string; +} + +export default function AuthorBox({ name, title, date, duration }: AuthorBoxProps) { + return ( +
    + {name} +
    +
    +

    {name}

    +

    {title}

    +
    +
    +

    {duration} Minutes

    +

    {date}

    +
    +
    +
    + ); +} diff --git a/apps/formbricks-com/src/components/shared/BestPracticeNavigation.tsx b/apps/formbricks-com/src/components/shared/BestPracticeNavigation.tsx new file mode 100644 index 0000000000..054cbebdbd --- /dev/null +++ b/apps/formbricks-com/src/components/shared/BestPracticeNavigation.tsx @@ -0,0 +1,114 @@ +import { + CancelSubscriptionIcon, + DogChaserIcon, + FeedbackIcon, + InterviewPromptIcon, + OnboardingIcon, + PMFIcon, + BaseballIcon, + CodeBookIcon, +} from "@formbricks/ui"; +import clsx from "clsx"; +import Link from "next/link"; + +export default function BestPracticeNavigation() { + const BestPractices = [ + { + name: "Interview Prompt", + href: "/interview-prompt", + status: true, + icon: InterviewPromptIcon, + description: "Ask only power users users to book a time in your calendar. Get those juicy details.", + category: "Understand Users", + }, + { + name: "Product-Market Fit Survey", + href: "/measure-product-market-fit", + status: true, + icon: PMFIcon, + description: "Find out how disappointed people would be if they could not use your service any more.", + category: "Understand Users", + }, + { + name: "Onboarding Segments", + href: "/onboarding-segmentation", + status: false, + icon: OnboardingIcon, + description: + "Get to know your users right from the start. Ask a few questions early, let us enrich the profile.", + category: "Understand Users", + }, + { + name: "Learn from Churn", + href: "/learn-from-churn", + status: true, + icon: CancelSubscriptionIcon, + description: "Churn is hard, but insightful. Learn from users who changed their mind.", + category: "Increase Revenue", + }, + { + name: "Improve Trial CR", + href: "/improve-trial-conversion", + status: true, + icon: BaseballIcon, + description: "Take guessing out, convert more trials to paid users with insights.", + category: "Increase Revenue", + }, + { + name: "Docs Feedback", + href: "/docs-feedback", + status: true, + icon: CodeBookIcon, + description: "Clear docs lead to more adoption. Understand granularly what's confusing.", + category: "Boost Retention", + }, + { + name: "Feature Chaser", + href: "/feature-chaser", + status: true, + icon: DogChaserIcon, + description: "Show a survey about a new feature shown only to people who used it.", + category: "Boost Retention", + }, + { + name: "Feedback Box", + href: "/feedback-box", + status: true, + icon: FeedbackIcon, + description: "Give users the chance to share feedback in a single click.", + category: "Boost Retention", + }, + ]; + + return ( +
    + {BestPractices.map((bestPractice) => ( + +
    +
    + {bestPractice.category} +
    +
    + +
    +

    + {bestPractice.name} +

    +

    {bestPractice.description}

    +
    + + ))} +
    + ); +} diff --git a/apps/formbricks-com/src/components/shared/BestPractices.tsx b/apps/formbricks-com/src/components/shared/BestPractices.tsx new file mode 100644 index 0000000000..5d33601f7c --- /dev/null +++ b/apps/formbricks-com/src/components/shared/BestPractices.tsx @@ -0,0 +1,37 @@ +import { Button } from "@formbricks/ui"; +import { usePlausible } from "next-plausible"; +import { useRouter } from "next/router"; +import BestPracticeNavigation from "./BestPracticeNavigation"; + +export default function InsightOppos() { + const plausible = usePlausible(); + const router = useRouter(); + return ( +
    +
    +

    + Get started with{" "} + + Best Practices + +

    +

    + Run battle-tested approaches for qualitative user research in minutes. +

    +
    + + + +
    + +
    +
    + ); +} diff --git a/apps/formbricks-com/src/components/shared/BreakerCTA.tsx b/apps/formbricks-com/src/components/shared/BreakerCTA.tsx new file mode 100644 index 0000000000..c518b7e69a --- /dev/null +++ b/apps/formbricks-com/src/components/shared/BreakerCTA.tsx @@ -0,0 +1,62 @@ +import { Button } from "@formbricks/ui"; +import clsx from "clsx"; +import { usePlausible } from "next-plausible"; +import { useRouter } from "next/router"; + +interface Props { + teaser: string; + headline: string; + subheadline: string; + cta: string; + href: string; + inverted?: boolean; +} + +export default function BreakerCTA({ inverted = false, teaser, headline, subheadline, cta, href }: Props) { + const router = useRouter(); + const plausible = usePlausible(); + return ( +
    +
    +
    + +
    +

    + {teaser} +

    +

    + {headline} +

    +

    + {subheadline} +

    +
    + +
    +
    +
    + ); +} diff --git a/apps/formbricks-com/src/components/shared/CTA.tsx b/apps/formbricks-com/src/components/shared/CTA.tsx new file mode 100644 index 0000000000..64029e23b0 --- /dev/null +++ b/apps/formbricks-com/src/components/shared/CTA.tsx @@ -0,0 +1,31 @@ +import { Button } from "@formbricks/ui"; +import { useRouter } from "next/router"; +import HeadingCentered from "./HeadingCentered"; + +export default function CTA() { + const router = useRouter(); + return ( + <> +
    + + +
    +
    +

    Self-hosted

    +

    Run locally e.g. with docker-compose.

    + +
    +
    +

    Cloud

    +

    Use our free managed service.

    + +
    +
    +
    + + ); +} diff --git a/apps/formbricks-com/src/components/shared/Callout.tsx b/apps/formbricks-com/src/components/shared/Callout.tsx new file mode 100644 index 0000000000..99be002ec5 --- /dev/null +++ b/apps/formbricks-com/src/components/shared/Callout.tsx @@ -0,0 +1,40 @@ +import clsx from "clsx"; +import { Icon } from "@/components/shared/Icon"; + +const styles = { + note: { + container: "bg-slate-100 dark:bg-slate-800/60 dark:ring-1 dark:ring-slate-300/10", + title: "text-slate-900 dark:text-slate-400", + body: "text-slate-800 [--tw-prose-background:theme(colors.slate.50)] prose-a:text-slate-900 prose-code:text-slate-900 dark:text-slate-300 dark:prose-code:text-slate-300", + }, + warning: { + container: "bg-amber-50 dark:bg-slate-800/60 dark:ring-1 dark:ring-slate-300/10", + title: "text-amber-900 dark:text-amber-500", + body: "text-amber-800 [--tw-prose-underline:theme(colors.amber.400)] [--tw-prose-background:theme(colors.amber.50)] prose-a:text-amber-900 prose-code:text-amber-900 dark:text-slate-300 dark:[--tw-prose-underline:theme(colors.slate.700)] dark:prose-code:text-slate-300", + }, +}; + +const icons = { + note: (props: any) => , + warning: (props: any) => , +}; + +interface CalloutProps { + type: "note" | "warning"; + title: string; + children: React.ReactNode; +} + +export function Callout({ type = "note", title, children }: CalloutProps) { + let IconComponent = icons[type]; + + return ( +
    + +
    +

    {title}

    +
    {children}
    +
    +
    + ); +} diff --git a/apps/formbricks-com/src/components/shared/Card.jsx b/apps/formbricks-com/src/components/shared/Card.jsx new file mode 100644 index 0000000000..46daeb69d7 --- /dev/null +++ b/apps/formbricks-com/src/components/shared/Card.jsx @@ -0,0 +1,76 @@ +import Link from "next/link"; +import clsx from "clsx"; + +function ChevronRightIcon(props) { + return ( + + ); +} + +export function Card({ as: Component = "div", className, children }) { + return ( + {children} + ); +} + +Card.Link = function CardLink({ children, ...props }) { + return ( + <> +
    + + + {children} + + + ); +}; + +Card.Title = function CardTitle({ as: Component = "h2", href, children }) { + return ( + + {href ? {children} : children} + + ); +}; + +Card.Description = function CardDescription({ children }) { + return

    {children}

    ; +}; + +Card.Cta = function CardCta({ children }) { + return ( + + ); +}; + +Card.Eyebrow = function CardEyebrow({ + as: Component = "p", + decorate = false, + className, + children, + ...props +}) { + return ( + + {decorate && ( + + ); +}; diff --git a/apps/formbricks-com/src/components/shared/CodeBlock.tsx b/apps/formbricks-com/src/components/shared/CodeBlock.tsx new file mode 100644 index 0000000000..d64b394a25 --- /dev/null +++ b/apps/formbricks-com/src/components/shared/CodeBlock.tsx @@ -0,0 +1,24 @@ +// components/ui/CodeBlock.tsx +import Prism from "prismjs"; +import "prismjs/themes/prism.css"; +import React, { useEffect } from "react"; + +interface CodeBlockProps { + children: React.ReactNode; +} + +const CodeBlock: React.FC = ({ children }) => { + useEffect(() => { + Prism.highlightAll(); + }, [children]); + + return ( +
    +
    +        {children}
    +      
    +
    + ); +}; + +export default CodeBlock; diff --git a/apps/formbricks-com/src/components/shared/EarlyBirdDeal.tsx b/apps/formbricks-com/src/components/shared/EarlyBirdDeal.tsx new file mode 100644 index 0000000000..b3916c5eee --- /dev/null +++ b/apps/formbricks-com/src/components/shared/EarlyBirdDeal.tsx @@ -0,0 +1,41 @@ +import EarlyBird from "@/images/early bird deal for open source jotform alternative typeform and surveymonkey_v2.svg"; +import { Button } from "@formbricks/ui"; +import { usePlausible } from "next-plausible"; +import Image from "next/image"; + +export default function EarlyBirdDeal() { + const plausible = usePlausible(); + return ( +
    +
    +

    + 50% off for Early Birds. +

    +

    + Limited deal: Only{" "} + 14 left. +

    + +
    + +
    +

    + This saves you $588 every year. +

    +
    + formbricks favicon open source forms typeform alternative +
    +
    +
    + ); +} diff --git a/apps/formbricks-com/src/components/shared/FeatureHighlight.tsx b/apps/formbricks-com/src/components/shared/FeatureHighlight.tsx new file mode 100644 index 0000000000..f5c3d99f61 --- /dev/null +++ b/apps/formbricks-com/src/components/shared/FeatureHighlight.tsx @@ -0,0 +1,55 @@ +import { Button } from "@formbricks/ui"; +import { useRouter } from "next/router"; +import clsx from "clsx"; + +interface Props { + featureTitle: string; + text: string; + img: React.ReactNode; + isImgLeft?: boolean; + cta?: string; + href?: string; + disabled?: boolean; +} + +export default function FeatureHighlights({ + featureTitle, + text, + img, + isImgLeft, + cta, + href, + disabled, +}: Props) { + const router = useRouter(); + + return ( +
    +
    +
    +
    +

    + {featureTitle} +

    +
    + {text} +
    +
    + {cta && href && ( + + )} +
    +
    + {img} +
    +
    +
    + ); +} diff --git a/apps/formbricks-com/src/components/shared/Fence.jsx b/apps/formbricks-com/src/components/shared/Fence.jsx new file mode 100644 index 0000000000..dab11c6b8e --- /dev/null +++ b/apps/formbricks-com/src/components/shared/Fence.jsx @@ -0,0 +1,25 @@ +import { Fragment } from "react"; +import { Highlight } from "prism-react-renderer"; + +export function Fence({ children, language }) { + return ( + + {({ className, style, tokens, getTokenProps }) => ( +
    +          
    +            {tokens.map((line, lineIndex) => (
    +              
    +                {line
    +                  .filter((token) => !token.empty)
    +                  .map((token, tokenIndex) => (
    +                    
    +                  ))}
    +                {"\n"}
    +              
    +            ))}
    +          
    +        
    + )} +
    + ); +} diff --git a/apps/formbricks-com/src/components/shared/Footer.tsx b/apps/formbricks-com/src/components/shared/Footer.tsx new file mode 100644 index 0000000000..34c49e030c --- /dev/null +++ b/apps/formbricks-com/src/components/shared/Footer.tsx @@ -0,0 +1,71 @@ +import Link from "next/link"; +import { FooterLogo } from "./Logo"; + +const navigation = { + other: [ + { name: "Community", href: "/community", status: true }, + { name: "Blog", href: "/blog", status: true }, + { name: "OSS Friends", href: "/oss-friends", status: true }, + { name: "GDPR FAQ", href: "/gdpr", status: true }, + { name: "GDPR Guide", href: "/gdpr-guide", status: true }, + ], + social: [ + { + name: "Twitter", + href: "https://twitter.com/formbricks", + icon: (props: any) => ( + + + + ), + }, + { + name: "GitHub", + href: "https://github.com/formbricks/formbricks", + icon: (props: any) => ( + + + + ), + }, + ], +}; + +export default function Footer() { + return ( +
    + +
    + + Formbricks + + +

    Privacy-first Experience Management

    +
    +

    + Formbricks GmbH © 2022. All rights reserved. +
    + Imprint | Privacy Policy |{" "} + Terms | OSS Friends +

    +
    +
    + {navigation.social.map((item) => ( + + {item.name} +
    +
    +
    + ); +} diff --git a/apps/formbricks-com/src/components/shared/Header.tsx b/apps/formbricks-com/src/components/shared/Header.tsx new file mode 100644 index 0000000000..000b1e84fb --- /dev/null +++ b/apps/formbricks-com/src/components/shared/Header.tsx @@ -0,0 +1,396 @@ +import GitHubMarkWhite from "@/images/github-mark-white.svg"; +import GitHubMarkDark from "@/images/github-mark.svg"; +import { + BaseballIcon, + Button, + CancelSubscriptionIcon, + CodeBookIcon, + DogChaserIcon, + FeedbackIcon, + InterviewPromptIcon, + OnboardingIcon, + PMFIcon, +} from "@formbricks/ui"; +import { Popover, Transition } from "@headlessui/react"; +import { Bars3Icon, ChevronDownIcon, ChevronRightIcon, XMarkIcon } from "@heroicons/react/24/outline"; +import clsx from "clsx"; +import { usePlausible } from "next-plausible"; +import Image from "next/image"; +import Link from "next/link"; +import { useRouter } from "next/router"; +import { Fragment, useState } from "react"; +import { FooterLogo } from "./Logo"; +import { ThemeSelector } from "./ThemeSelector"; + +function GitHubIcon(props: any) { + return ( + + ); +} + +const UnderstandUsers = [ + { + name: "Interview Prompt", + href: "/interview-prompt", + status: true, + icon: InterviewPromptIcon, + description: "Interview invites on auto-pilot", + }, + { + name: "Measure PMF", + href: "/measure-product-market-fit", + status: true, + icon: PMFIcon, + description: "Improve Product-Market Fit", + }, + { + name: "Onboarding Segments", + href: "/onboarding-segmentation", + status: true, + icon: OnboardingIcon, + description: "Get it right from the start", + }, +]; + +const IncreaseRevenue = [ + { + name: "Learn from Churn", + href: "/learn-from-churn", + status: true, + icon: CancelSubscriptionIcon, + description: "Churn is hard, but insightful", + }, + { + name: "Improve Trial CR", + href: "/improve-trial-conversion", + status: true, + icon: BaseballIcon, + description: "Take guessing out, hit it right", + }, +]; + +const BoostRetention = [ + { + name: "Feedback Box", + href: "/feedback-box", + status: true, + icon: FeedbackIcon, + description: "Always keep an ear open", + }, + { + name: "Docs Feedback", + href: "/docs-feedback", + status: true, + icon: CodeBookIcon, + description: "Clear docs, more adoption", + }, + { + name: "Feature Chaser", + href: "/feature-chaser", + status: true, + icon: DogChaserIcon, + description: "Follow up, improve", + }, +]; + +export default function Header() { + const [mobileSubOpen, setMobileSubOpen] = useState(false); + const plausible = usePlausible(); + const router = useRouter(); + return ( + +
    +
    + + Formbricks + + +
    +
    + + Open menu + +
    + + + {({ open }) => ( + <> + + Best Practices + + + + +
    +
    +
    +

    + Understand Users +

    + {UnderstandUsers.map((brick) => ( + +
    +
    +
    +

    + {brick.name} +

    +

    {brick.description}

    +
    + + ))} +
    +
    +

    + Increase Revenue +

    + {IncreaseRevenue.map((brick) => ( + +
    +
    +
    +

    + {brick.name} +

    +

    {brick.description}

    +
    + + ))} +
    +
    +

    + Boost Retention +

    + {BoostRetention.map((brick) => ( + +
    +
    +
    +

    + {brick.name} +

    +

    {brick.description}

    +
    + + ))} +
    +
    +
    +
    +
    + + )} +
    + {/* + Community + + */} + + Pricing + + + Docs + + + Blog {/*

    1

    */} + + {/* + Careers

    2

    + */} + + + Concierge + +
    +
    + + + {/* */} + + +
    +
    + + + +
    +
    +
    +
    + +
    +
    + + Close menu + +
    +
    +
    +
    +
    +
    + {mobileSubOpen ? ( + + ) : ( + + )} + +
    + {mobileSubOpen && ( +
    + {UnderstandUsers.map((brick) => ( + + {brick.name} + + ))} + {IncreaseRevenue.map((brick) => ( + + {brick.name} + + ))} + {BoostRetention.map((brick) => ( + + {brick.name} + + ))} +
    +
    + )} + Concierge + Pricing + Docs + Blog + {/* Careers */} + + +
    +
    +
    +
    +
    +
    + ); +} diff --git a/apps/formbricks-com/src/components/shared/HeaderLight.tsx b/apps/formbricks-com/src/components/shared/HeaderLight.tsx new file mode 100644 index 0000000000..cffc8b27e0 --- /dev/null +++ b/apps/formbricks-com/src/components/shared/HeaderLight.tsx @@ -0,0 +1,43 @@ +import { Button } from "@formbricks/ui"; +import { Popover } from "@headlessui/react"; +import { usePlausible } from "next-plausible"; +import Link from "next/link"; +import { useRouter } from "next/router"; +import { FooterLogo } from "./Logo"; + +export default function HeaderLight() { + const plausible = usePlausible(); + const router = useRouter(); + return ( + +
    +
    + + Formbricks + + +
    + +
    + + +
    +
    +
    + ); +} diff --git a/apps/formbricks-com/src/components/shared/HeadingCentered.tsx b/apps/formbricks-com/src/components/shared/HeadingCentered.tsx new file mode 100644 index 0000000000..d7c74aef8e --- /dev/null +++ b/apps/formbricks-com/src/components/shared/HeadingCentered.tsx @@ -0,0 +1,24 @@ +import clsx from "clsx"; + +interface Props { + teaser?: string; + heading: string; + subheading?: string; + closer?: boolean; +} + +export default function HeadingCentered({ teaser, heading, subheading, closer }: Props) { + return ( +
    +

    + {teaser} +

    +

    + {heading} +

    +

    + {subheading} +

    +
    + ); +} diff --git a/apps/formbricks-com/src/components/shared/HeroAnimation.tsx b/apps/formbricks-com/src/components/shared/HeroAnimation.tsx new file mode 100644 index 0000000000..8556664838 --- /dev/null +++ b/apps/formbricks-com/src/components/shared/HeroAnimation.tsx @@ -0,0 +1,28 @@ +import { useEffect, useRef, useState } from "react"; +import type { LottiePlayer } from "lottie-web"; + +export default function HeroAnimation(props: any) { + const ref = useRef(null); + const [lottie, setLottie] = useState(null); + + useEffect(() => { + import("lottie-web").then((Lottie) => setLottie(Lottie.default)); + }, []); + + useEffect(() => { + if (lottie && ref.current) { + const animation = lottie.loadAnimation({ + container: ref.current, + renderer: "svg", + loop: true, + autoplay: true, + // path to your animation file, place it inside public folder + path: "/animations/xm-hero-v1.json", + }); + + return () => animation.destroy(); + } + }, [lottie]); + + return
    ; +} diff --git a/apps/formbricks-com/src/components/shared/HeroTitle.tsx b/apps/formbricks-com/src/components/shared/HeroTitle.tsx new file mode 100644 index 0000000000..6f6c26177f --- /dev/null +++ b/apps/formbricks-com/src/components/shared/HeroTitle.tsx @@ -0,0 +1,25 @@ +interface Props { + headingPt1: string; + headingTeal?: string; + headingPt2?: string; + subheading?: string; + children?: React.ReactNode; +} + +export default function HeroTitle({ headingPt1, headingTeal, headingPt2, subheading, children }: Props) { + return ( +
    +

    + {headingPt1}{" "} + + {headingTeal} + {" "} + {headingPt2} +

    +

    + {subheading} +

    +
    {children}
    +
    + ); +} diff --git a/apps/formbricks-com/src/components/shared/Icon.jsx b/apps/formbricks-com/src/components/shared/Icon.jsx new file mode 100644 index 0000000000..acde8da647 --- /dev/null +++ b/apps/formbricks-com/src/components/shared/Icon.jsx @@ -0,0 +1,69 @@ +import { useId } from "react"; +import clsx from "clsx"; + +import { InstallationIcon } from "@/components/shared/icons/InstallationIcon"; +import { LightbulbIcon } from "@/components/shared/icons/LightbulbIcon"; +import { PluginsIcon } from "@/components/shared/icons/PluginsIcon"; +import { PresetsIcon } from "@/components/shared/icons/PresetsIcon"; +import { ThemingIcon } from "@/components/shared/icons/ThemingIcon"; +import { WarningIcon } from "@/components/shared/icons/WarningIcon"; + +const icons = { + installation: InstallationIcon, + presets: PresetsIcon, + plugins: PluginsIcon, + theming: ThemingIcon, + lightbulb: LightbulbIcon, + warning: WarningIcon, +}; + +const iconStyles = { + slate: "[--icon-foreground:theme(colors.slate.900)] [--icon-background:theme(colors.white)]", + amber: "[--icon-foreground:theme(colors.amber.900)] [--icon-background:theme(colors.amber.100)]", +}; + +export function Icon({ color = "slate", icon, className, ...props }) { + let id = useId(); + let IconComponent = icons[icon]; + + return ( + + ); +} + +const gradients = { + slate: [ + { stopColor: "#0EA5E9" }, + { stopColor: "#22D3EE", offset: ".527" }, + { stopColor: "#818CF8", offset: 1 }, + ], + amber: [ + { stopColor: "#FDE68A", offset: ".08" }, + { stopColor: "#F59E0B", offset: ".837" }, + ], +}; + +export function Gradient({ color = "slate", ...props }) { + return ( + + {gradients[color].map((stop, stopIndex) => ( + + ))} + + ); +} + +export function LightMode({ className, ...props }) { + return ; +} + +export function DarkMode({ className, ...props }) { + return ; +} diff --git a/apps/formbricks-com/src/components/shared/Layout.tsx b/apps/formbricks-com/src/components/shared/Layout.tsx new file mode 100644 index 0000000000..9a039fadc5 --- /dev/null +++ b/apps/formbricks-com/src/components/shared/Layout.tsx @@ -0,0 +1,24 @@ +import Footer from "./Footer"; +import Header from "./Header"; +import MetaInformation from "./MetaInformation"; + +interface LayoutProps { + children: React.ReactNode; + title: string; + description: string; +} + +export default function Layout({ title, description, children }: LayoutProps) { + return ( +
    + +
    + { +
    + {children} +
    + } +
    +
    + ); +} diff --git a/apps/formbricks-com/src/components/shared/LayoutLight.tsx b/apps/formbricks-com/src/components/shared/LayoutLight.tsx new file mode 100644 index 0000000000..252544cbd4 --- /dev/null +++ b/apps/formbricks-com/src/components/shared/LayoutLight.tsx @@ -0,0 +1,24 @@ +import Footer from "./Footer"; +import MetaInformation from "./MetaInformation"; +import HeaderLight from "./HeaderLight"; + +interface LayoutProps { + children: React.ReactNode; + title: string; + description: string; +} + +export default function Layout({ title, description, children }: LayoutProps) { + return ( +
    + + + { +
    + {children} +
    + } +
    +
    + ); +} diff --git a/apps/formbricks-com/src/components/shared/LayoutMdx.tsx b/apps/formbricks-com/src/components/shared/LayoutMdx.tsx new file mode 100644 index 0000000000..585f9d2107 --- /dev/null +++ b/apps/formbricks-com/src/components/shared/LayoutMdx.tsx @@ -0,0 +1,67 @@ +import { useEffect } from "react"; +import Footer from "./Footer"; +import Header from "./Header"; +import MetaInformation from "./MetaInformation"; +import { Prose } from "./Prose"; + +const useExternalLinks = (selector: string) => { + useEffect(() => { + const links = document.querySelectorAll(selector); + + links.forEach((link) => { + link.setAttribute("target", "_blank"); + link.setAttribute("rel", "noopener noreferrer"); + }); + + return () => { + links.forEach((link) => { + link.removeAttribute("target"); + link.removeAttribute("rel"); + }); + }; + }, [selector]); +}; + +interface Props { + meta: { + title: string; + description: string; + publishedTime: string; + authors: string[]; + section: string; + tags: string[]; + }; + children: JSX.Element; +} + +export default function LayoutMdx({ meta, children }: Props) { + useExternalLinks(".prose a"); + return ( +
    + +
    +
    +
    + {meta.title && ( +
    + {meta.title && ( +

    + {meta.title} +

    + )} +
    + )} + {children} +
    +
    +
    +
    + ); +} diff --git a/apps/formbricks-com/src/components/shared/Logo.tsx b/apps/formbricks-com/src/components/shared/Logo.tsx new file mode 100644 index 0000000000..3f45009ea6 --- /dev/null +++ b/apps/formbricks-com/src/components/shared/Logo.tsx @@ -0,0 +1,36 @@ +import Image from "next/image"; +import logomark from "@/images/logo/logomark.svg"; +import logo from "@/images/logo/logo.svg"; +import logoDark from "@/images/logo/logo_dark.svg"; +import footerLogo from "@/images/logo/footerlogo.svg"; +import footerLogoDark from "@/images/logo/footerlogo-dark.svg"; + +export function Logomark(props: any) { + return Formbricks Open source Forms & Surveys Logomark; +} + +export function Logo(props: any) { + return ( +
    +
    + Formbricks Open source Forms & Surveys Logo +
    +
    + Formbricks Open source Forms & Surveys Logo +
    +
    + ); +} + +export function FooterLogo(props: any) { + return ( +
    +
    + Formbricks Open source Forms & Surveys Logo +
    +
    + Formbricks Open source Forms & Surveys Logo +
    +
    + ); +} diff --git a/apps/formbricks-com/src/components/shared/MdxCTA.tsx b/apps/formbricks-com/src/components/shared/MdxCTA.tsx new file mode 100644 index 0000000000..f189dd66a0 --- /dev/null +++ b/apps/formbricks-com/src/components/shared/MdxCTA.tsx @@ -0,0 +1,34 @@ +import { Button } from "@formbricks/ui"; +import { useRouter } from "next/router"; + +export default function CTA() { + const router = useRouter(); + return ( + <> +
    +

    + It's free & open-source +

    +

    + Try Formbricks right now! +

    +
    +
    +

    Self-hosted

    +

    Run locally with docker-compose.

    + +
    +
    +

    Cloud

    +

    Use our free managed service.

    + +
    +
    +
    + + ); +} diff --git a/apps/formbricks-com/src/components/shared/MdxTryItCTA.tsx b/apps/formbricks-com/src/components/shared/MdxTryItCTA.tsx new file mode 100644 index 0000000000..786c29fe8d --- /dev/null +++ b/apps/formbricks-com/src/components/shared/MdxTryItCTA.tsx @@ -0,0 +1,36 @@ +import { Button } from "@formbricks/ui"; +import { DocumentDuplicateIcon } from "@heroicons/react/24/outline"; +import { useRouter } from "next/router"; + +export default function HeadingCentered() { + const router = useRouter(); + return ( +
    +
    +

    + What are you waiting for? +

    +

    + Try it right now! +

    +

    + Dive right in or browse docs for examples. Questions? Join our Discord, we’re happy to help +

    + + +
    +
    +
    +

    npm install @formbricks/react

    + +
    +
    +
    + ); +} diff --git a/apps/formbricks-com/src/components/shared/MetaInformation.tsx b/apps/formbricks-com/src/components/shared/MetaInformation.tsx new file mode 100644 index 0000000000..39961f3c52 --- /dev/null +++ b/apps/formbricks-com/src/components/shared/MetaInformation.tsx @@ -0,0 +1,49 @@ +import Head from "next/head"; + +interface Props { + title: string; + description: string; + publishedTime?: string; + updatedTime?: string; + authors?: string[]; + section?: string; + tags?: string[]; +} + +export default function MetaInformation({ + title, + description, + publishedTime, + updatedTime, + authors, + section, + tags, +}: Props) { + const pageTitle = `${title} | Open-Source Experience Management, Privacy-first`; + return ( + + {pageTitle} + + + + + + + + + + + + + {publishedTime && } + {updatedTime && } + {authors && } + {section && } + {tags && } + + + + + + ); +} diff --git a/apps/formbricks-com/src/components/shared/MobileNavigation.jsx b/apps/formbricks-com/src/components/shared/MobileNavigation.jsx new file mode 100644 index 0000000000..a5d8766116 --- /dev/null +++ b/apps/formbricks-com/src/components/shared/MobileNavigation.jsx @@ -0,0 +1,69 @@ +import { useEffect, useState } from "react"; +import Link from "next/link"; +import { useRouter } from "next/router"; +import { Dialog } from "@headlessui/react"; + +import { Logomark } from "@/components/shared/Logo"; +import { Navigation } from "@/components/shared/Navigation"; + +function MenuIcon(props) { + return ( + + ); +} + +function CloseIcon(props) { + return ( + + ); +} + +export function MobileNavigation({ navigation }) { + let router = useRouter(); + let [isOpen, setIsOpen] = useState(false); + + useEffect(() => { + if (!isOpen) return; + + function onRouteChange() { + setIsOpen(false); + } + + router.events.on("routeChangeComplete", onRouteChange); + router.events.on("routeChangeError", onRouteChange); + + return () => { + router.events.off("routeChangeComplete", onRouteChange); + router.events.off("routeChangeError", onRouteChange); + }; + }, [router, isOpen]); + + return ( + <> + + + +
    + + + + +
    + +
    +
    + + ); +} diff --git a/apps/formbricks-com/src/components/shared/Modal.tsx b/apps/formbricks-com/src/components/shared/Modal.tsx new file mode 100644 index 0000000000..2e565bd7f6 --- /dev/null +++ b/apps/formbricks-com/src/components/shared/Modal.tsx @@ -0,0 +1,75 @@ +import { Dialog, Transition } from "@headlessui/react"; +import { XMarkIcon } from "@heroicons/react/24/solid"; +import { Fragment } from "react"; +import clsx from "clsx"; + +type Modal = { + open: boolean; + setOpen: (v: boolean) => void; + children: React.ReactNode; + title?: string; + noPadding?: boolean; + closeOnOutsideClick?: boolean; +}; + +const Modal: React.FC = ({ + open, + setOpen, + children, + title, + noPadding, + closeOnOutsideClick = true, +}) => { + return ( + <> + + closeOnOutsideClick && setOpen(false)}> + +
    + + +
    +
    + + +
    + +
    + {title &&

    {title}

    } + + {children} +
    +
    +
    +
    +
    +
    + + ); +}; + +export default Modal; diff --git a/apps/formbricks-com/src/components/shared/Navigation.tsx b/apps/formbricks-com/src/components/shared/Navigation.tsx new file mode 100644 index 0000000000..0befd0b566 --- /dev/null +++ b/apps/formbricks-com/src/components/shared/Navigation.tsx @@ -0,0 +1,51 @@ +import Link from "next/link"; +import { useRouter } from "next/router"; +import clsx from "clsx"; + +interface NavigationProps { + navigation: { + title: string; + links: { + title: string; + href: string; + }[]; + }[]; + className: string; + preserveScroll: () => void; + linkRef: React.RefObject; +} + +export function Navigation({ navigation, className, preserveScroll, linkRef }: NavigationProps) { + let router = useRouter(); + + return ( + + ); +} diff --git a/apps/formbricks-com/src/components/shared/NewsletterSignup.tsx b/apps/formbricks-com/src/components/shared/NewsletterSignup.tsx new file mode 100644 index 0000000000..49ed550042 --- /dev/null +++ b/apps/formbricks-com/src/components/shared/NewsletterSignup.tsx @@ -0,0 +1,61 @@ +import Friends from "@/images/newsletter-signup-gif.gif"; +import { Button } from "@formbricks/ui"; +import Image from "next/image"; + +export default function WaitlistForm() { + return ( +
    +

    Build in public

    + Get all the juicy details of our journey building Formbricks in public 👇 +
    +
    +
    +
    + +
    +
    + + +
    +
    + + +
    +
    + + +
    + +
    +
    + + Sign up to newsletter +
    +
    + ); +} diff --git a/apps/formbricks-com/src/components/shared/Pricing.tsx b/apps/formbricks-com/src/components/shared/Pricing.tsx new file mode 100644 index 0000000000..dacb32dd4b --- /dev/null +++ b/apps/formbricks-com/src/components/shared/Pricing.tsx @@ -0,0 +1,162 @@ +import { Button } from "@formbricks/ui"; +import clsx from "clsx"; +import HeadingCentered from "./HeadingCentered"; +import { CheckIcon } from "@heroicons/react/24/outline"; +import { usePlausible } from "next-plausible"; +import { useRouter } from "next/router"; + +const tiers = [ + { + name: "Self-hosting", + priceMonthly: "free", + paymentRythm: "/always", + button: "secondary", + discounted: false, + highlight: false, + description: "Host Formbricks on your own server.", + features: [ + "All Free features", + "Easy self-hosting (Docker)", + "Unlimited surveys", + "Unlimited responses", + "Unlimited team members", + ], + ctaName: "Read docs", + plausibleGoal: "Pricing_CTA_SelfHosting", + href: "/docs/self-hosting/deployment", + }, + { + name: "Cloud", + href: "https://app.formbricks.com/auth/signup", + priceMonthly: "$0", + paymentRythm: "/month", + button: "highlight", + discounted: false, + highlight: true, + description: "Start with the 'Free forever' plan.", + features: [ + "Unlimited surveys", + "In-product surveys", + "Link surveys", + "Remove branding", + "Granular targeting", + "30+ templates", + "API access", + "Integrations (Zapier, Make, ...)", + "Unlimited team members", + "100 responses per survey", + ], + ctaName: "Get started", + plausibleGoal: "Pricing_CTA_FreePlan", + }, + { + name: "Cloud Pro", + href: "https://app.formbricks.com/auth/signup", + priceMonthly: "$99", + paymentRythm: "/month", + button: "secondary", + discounted: false, + highlight: false, + description: "All features, unlimited usage.", + features: ["Everything in 'Cloud'", "Unlimited responses per survey"], + ctaName: "Start for free", + plausibleGoal: "Pricing_CTA_ProPlan", + }, +]; + +export default function Pricing() { + const plausible = usePlausible(); + const router = useRouter(); + + return ( +
    +
    + + +
    + {tiers.map((tier) => ( +
    +
    +

    + {tier.name} +

    +

    + {tier.description} +

    +
      + {tier.features.map((feature, index) => ( +
    • +
      + +
      + {feature} +
    • + ))} +
    +

    + + {tier.priceMonthly} + {" "} + + {tier.discounted && "$49"} + + + {tier.paymentRythm} + +

    + + + + {tier.name == "Cloud Pro" && ( +

    No Creditcard required.

    + )} + {tier.name == "Cloud" && ( +

    Free forever 🤍

    + )} +
    +
    + ))} +
    +
    +
    + ); +} diff --git a/apps/formbricks-com/src/components/shared/Prose.jsx b/apps/formbricks-com/src/components/shared/Prose.jsx new file mode 100644 index 0000000000..6a816f2419 --- /dev/null +++ b/apps/formbricks-com/src/components/shared/Prose.jsx @@ -0,0 +1,25 @@ +import clsx from "clsx"; + +export function Prose({ as: Component = "div", className, ...props }) { + return ( + + ); +} diff --git a/apps/formbricks-com/src/components/shared/Search.tsx b/apps/formbricks-com/src/components/shared/Search.tsx new file mode 100644 index 0000000000..679185b068 --- /dev/null +++ b/apps/formbricks-com/src/components/shared/Search.tsx @@ -0,0 +1,82 @@ +import { useCallback, useEffect, useState } from "react"; +import { createPortal } from "react-dom"; +import Link from "next/link"; +import Router from "next/router"; +import { DocSearchModal, useDocSearchKeyboardEvents } from "@docsearch/react"; + +const docSearchConfig = { + appId: process.env.NEXT_PUBLIC_DOCSEARCH_APP_ID || "", + apiKey: process.env.NEXT_PUBLIC_DOCSEARCH_API_KEY || "", + indexName: process.env.NEXT_PUBLIC_DOCSEARCH_INDEX_NAME || "", +}; + +interface HitProps { + hit: { url: string }; + children: React.ReactNode; +} + +function Hit({ hit, children }: HitProps) { + return {children}; +} + +function SearchIcon(props: any) { + return ( + + ); +} + +export function Search() { + let [isOpen, setIsOpen] = useState(false); + let [modifierKey, setModifierKey] = useState(); + + const onOpen = useCallback(() => { + setIsOpen(true); + }, [setIsOpen]); + + const onClose = useCallback(() => { + setIsOpen(false); + }, [setIsOpen]); + + useDocSearchKeyboardEvents({ isOpen, onOpen, onClose }); + + useEffect(() => { + setModifierKey(/(Mac|iPhone|iPod|iPad)/i.test(navigator.platform) ? "⌘" : "Ctrl "); + }, []); + + return ( + <> + + {isOpen && + createPortal( + , + document.body + )} + + ); +} diff --git a/apps/formbricks-com/src/components/shared/ThemeSelector.jsx b/apps/formbricks-com/src/components/shared/ThemeSelector.jsx new file mode 100644 index 0000000000..5506c70bf5 --- /dev/null +++ b/apps/formbricks-com/src/components/shared/ThemeSelector.jsx @@ -0,0 +1,111 @@ +import { useEffect, useState } from "react"; +import { Listbox } from "@headlessui/react"; +import clsx from "clsx"; + +const themes = [ + { name: "Light", value: "light", icon: LightIcon }, + { name: "Dark", value: "dark", icon: DarkIcon }, + { name: "System", value: "system", icon: SystemIcon }, +]; + +function LightIcon(props) { + return ( + + ); +} + +function DarkIcon(props) { + return ( + + ); +} + +function SystemIcon(props) { + return ( + + ); +} + +export function ThemeSelector(props) { + let [selectedTheme, setSelectedTheme] = useState(); + + useEffect(() => { + if (selectedTheme) { + document.documentElement.setAttribute("data-theme", selectedTheme.value); + } else { + setSelectedTheme( + themes.find((theme) => theme.value === document.documentElement.getAttribute("data-theme")) + ); + } + }, [selectedTheme]); + + useEffect(() => { + let handler = () => + setSelectedTheme(themes.find((theme) => theme.value === (window.localStorage.theme ?? "system"))); + + window.addEventListener("storage", handler); + + return () => window.removeEventListener("storage", handler); + }, []); + + return ( + + Theme + + + + + + + + {themes.map((theme) => ( + + clsx("flex cursor-pointer select-none items-center rounded-[0.625rem] p-1", { + "text-brand-dark dark:text-brand-light": selected, + "text-slate-800 dark:text-slate-100": active && !selected, + "text-slate-700 dark:text-slate-400": !active && !selected, + "bg-slate-100 dark:bg-slate-900/40": active, + }) + }> + {({ selected }) => ( + <> +
    + +
    +
    {theme.name}
    + + )} +
    + ))} +
    +
    + ); +} diff --git a/apps/formbricks-com/src/components/shared/TryItCTA.tsx b/apps/formbricks-com/src/components/shared/TryItCTA.tsx new file mode 100644 index 0000000000..21dda175e7 --- /dev/null +++ b/apps/formbricks-com/src/components/shared/TryItCTA.tsx @@ -0,0 +1,38 @@ +import { Button } from "@formbricks/ui"; +import { DocumentDuplicateIcon } from "@heroicons/react/24/outline"; +import { useRouter } from "next/router"; + +export default function HeadingCentered() { + const router = useRouter(); + return ( +
    +
    +

    + What are you waiting for? +

    +

    + Try it right now! +

    +

    + Dive right in or browse docs for examples. +
    + Questions? Join our Discord, we’re happy to help! +

    + + +
    +
    +
    +

    npm install @formbricks/react

    + +
    +
    +
    + ); +} diff --git a/apps/formbricks-com/src/components/shared/UseCaseCTA.tsx b/apps/formbricks-com/src/components/shared/UseCaseCTA.tsx new file mode 100644 index 0000000000..e753afddcf --- /dev/null +++ b/apps/formbricks-com/src/components/shared/UseCaseCTA.tsx @@ -0,0 +1,29 @@ +import { Button } from "@formbricks/ui"; +import { useRouter } from "next/router"; + +interface UseCaseCTAProps { + href: string; +} + +export default function UseCaseHeader({ href }: UseCaseCTAProps) { + /* const plausible = usePlausible(); */ + const router = useRouter(); + return ( +
    + +
    + +

    It's free

    +
    +
    + ); +} diff --git a/apps/formbricks-com/src/components/shared/UseCaseHeader.tsx b/apps/formbricks-com/src/components/shared/UseCaseHeader.tsx new file mode 100644 index 0000000000..8fe2c14c2e --- /dev/null +++ b/apps/formbricks-com/src/components/shared/UseCaseHeader.tsx @@ -0,0 +1,26 @@ +interface UseCaseHeaderProps { + title: string; + + difficulty: string; + setupMinutes: string; +} + +export default function UseCaseHeader({ title, difficulty, setupMinutes }: UseCaseHeaderProps) { + return ( +
    +
    +

    + {title} +

    +
    +
    + {difficulty} +
    +
    + {setupMinutes} minutes +
    +
    +
    +
    + ); +} diff --git a/apps/formbricks-com/src/components/shared/WhyFormbricks.tsx b/apps/formbricks-com/src/components/shared/WhyFormbricks.tsx new file mode 100644 index 0000000000..78d29c8d65 --- /dev/null +++ b/apps/formbricks-com/src/components/shared/WhyFormbricks.tsx @@ -0,0 +1,80 @@ +import { + UsersIcon, + CubeTransparentIcon, + UserGroupIcon, + CommandLineIcon, + SwatchIcon, + SquaresPlusIcon, +} from "@heroicons/react/24/outline"; + +const features = [ + { + name: "Futureproof", + description: "Form needs change. With Formbricks you’ll avoid island solutions right from the start.", + icon: CubeTransparentIcon, + }, + { + name: "Privacy by design", + description: "Self-host the entire product and fly through privacy compliance reviews.", + icon: UsersIcon, + }, + { + name: "Community driven", + description: "We're building for you. If you need something specific, we’re happy to build it!", + icon: UserGroupIcon, + }, + { + name: "Great DX", + description: "We love a solid developer experience. We felt your pain and do our best to avoid it.", + icon: CommandLineIcon, + }, + { + name: "Customizable", + description: "We have to build opinionated. If it doesn't suit your need, just change it up.", + icon: SwatchIcon, + }, + { + name: "Extendable", + description: "Even though we try, we cannot build every single integration. With Formbricks, you can.", + icon: SquaresPlusIcon, + }, +]; + +export default function FeatureTable({}) { + return ( +
    +
    +

    + Why Formbricks? +

    +

    + The only complete open source option. +

    +

    + We experienced how form needs develop as companies grow. We could'nt find a solution which ticked + all of the boxes. Now we're building it. +

    +
    + {features.map((feature) => ( +
    +
    + + +
    +
    +

    {feature.name}

    +

    + {feature.description} +

    +
    +
    + ))} +
    +
    +
    + ); +} diff --git a/apps/formbricks-com/src/components/shared/icons/InstallationIcon.jsx b/apps/formbricks-com/src/components/shared/icons/InstallationIcon.jsx new file mode 100644 index 0000000000..b36601e0d3 --- /dev/null +++ b/apps/formbricks-com/src/components/shared/icons/InstallationIcon.jsx @@ -0,0 +1,33 @@ +import { DarkMode, Gradient, LightMode } from "@/components/shared/Icon"; + +export function InstallationIcon({ id, color }) { + return ( + <> + + + + + + + + + + + + + ); +} diff --git a/apps/formbricks-com/src/components/shared/icons/LightbulbIcon.jsx b/apps/formbricks-com/src/components/shared/icons/LightbulbIcon.jsx new file mode 100644 index 0000000000..1f6ab70d23 --- /dev/null +++ b/apps/formbricks-com/src/components/shared/icons/LightbulbIcon.jsx @@ -0,0 +1,42 @@ +import { DarkMode, Gradient, LightMode } from "@/components/shared/Icon"; + +export function LightbulbIcon({ id, color }) { + return ( + <> + + + + + + + + + + + + + + + ); +} diff --git a/apps/formbricks-com/src/components/shared/icons/PluginsIcon.jsx b/apps/formbricks-com/src/components/shared/icons/PluginsIcon.jsx new file mode 100644 index 0000000000..ae8f05e78c --- /dev/null +++ b/apps/formbricks-com/src/components/shared/icons/PluginsIcon.jsx @@ -0,0 +1,49 @@ +import { DarkMode, Gradient, LightMode } from "@/components/shared/Icon"; + +export function PluginsIcon({ id, color }) { + return ( + <> + + + + + + + + + + + + + + + + + + + + + + + ); +} diff --git a/apps/formbricks-com/src/components/shared/icons/PresetsIcon.jsx b/apps/formbricks-com/src/components/shared/icons/PresetsIcon.jsx new file mode 100644 index 0000000000..2464ddc913 --- /dev/null +++ b/apps/formbricks-com/src/components/shared/icons/PresetsIcon.jsx @@ -0,0 +1,38 @@ +import { DarkMode, Gradient, LightMode } from "@/components/shared/Icon"; + +export function PresetsIcon({ id, color }) { + return ( + <> + + + + + + + + + + + + + + + + + + + ); +} diff --git a/apps/formbricks-com/src/components/shared/icons/ThemingIcon.jsx b/apps/formbricks-com/src/components/shared/icons/ThemingIcon.jsx new file mode 100644 index 0000000000..476c9f022b --- /dev/null +++ b/apps/formbricks-com/src/components/shared/icons/ThemingIcon.jsx @@ -0,0 +1,55 @@ +import { DarkMode, Gradient, LightMode } from "@/components/shared/Icon"; + +export function ThemingIcon({ id, color }) { + return ( + <> + + + + + + + + + + + + + + + + ); +} diff --git a/apps/formbricks-com/src/components/shared/icons/WarningIcon.jsx b/apps/formbricks-com/src/components/shared/icons/WarningIcon.jsx new file mode 100644 index 0000000000..aa5108664a --- /dev/null +++ b/apps/formbricks-com/src/components/shared/icons/WarningIcon.jsx @@ -0,0 +1,55 @@ +import { DarkMode, Gradient, LightMode } from "@/components/shared/Icon"; + +export function WarningIcon({ id, color }) { + return ( + <> + + + + + + + + + + + + + + + ); +} diff --git a/apps/formbricks-com-old/images/SEO/Best React Form Library and Builder 2023 to create and build forms surveys easy and fast.png b/apps/formbricks-com/src/images/SEO/Best React Form Library and Builder 2023 to create and build forms surveys easy and fast.png similarity index 100% rename from apps/formbricks-com-old/images/SEO/Best React Form Library and Builder 2023 to create and build forms surveys easy and fast.png rename to apps/formbricks-com/src/images/SEO/Best React Form Library and Builder 2023 to create and build forms surveys easy and fast.png diff --git a/apps/formbricks-com-old/images/SEO/Data Controller vs Data Processor Overview for open source forms and surveys.png b/apps/formbricks-com/src/images/SEO/Data Controller vs Data Processor Overview for open source forms and surveys.png similarity index 100% rename from apps/formbricks-com-old/images/SEO/Data Controller vs Data Processor Overview for open source forms and surveys.png rename to apps/formbricks-com/src/images/SEO/Data Controller vs Data Processor Overview for open source forms and surveys.png diff --git a/apps/formbricks-com-old/images/SEO/Formbricks React Form Library vs React Hook Form comparison post to build forms fast in reactjs smaller.png b/apps/formbricks-com/src/images/SEO/Formbricks React Form Library vs React Hook Form comparison post to build forms fast in reactjs smaller.png similarity index 100% rename from apps/formbricks-com-old/images/SEO/Formbricks React Form Library vs React Hook Form comparison post to build forms fast in reactjs smaller.png rename to apps/formbricks-com/src/images/SEO/Formbricks React Form Library vs React Hook Form comparison post to build forms fast in reactjs smaller.png diff --git a/apps/formbricks-com-old/images/SEO/Formspree open source alternative vs Formbricks FormHQ comparison post for form backend as a service.png b/apps/formbricks-com/src/images/SEO/Formspree open source alternative vs Formbricks FormHQ comparison post for form backend as a service.png similarity index 100% rename from apps/formbricks-com-old/images/SEO/Formspree open source alternative vs Formbricks FormHQ comparison post for form backend as a service.png rename to apps/formbricks-com/src/images/SEO/Formspree open source alternative vs Formbricks FormHQ comparison post for form backend as a service.png diff --git a/apps/formbricks-com-old/images/SEO/Google Form Example Customize and make it comply with GDPR CCPA HIPAA open source alternative.png b/apps/formbricks-com/src/images/SEO/Google Form Example Customize and make it comply with GDPR CCPA HIPAA open source alternative.png similarity index 100% rename from apps/formbricks-com-old/images/SEO/Google Form Example Customize and make it comply with GDPR CCPA HIPAA open source alternative.png rename to apps/formbricks-com/src/images/SEO/Google Form Example Customize and make it comply with GDPR CCPA HIPAA open source alternative.png diff --git a/apps/formbricks-com-old/images/SEO/Google Forms Open Source Alternative Comparison with Formbricks Open-source Online Form Builder.png b/apps/formbricks-com/src/images/SEO/Google Forms Open Source Alternative Comparison with Formbricks Open-source Online Form Builder.png similarity index 100% rename from apps/formbricks-com-old/images/SEO/Google Forms Open Source Alternative Comparison with Formbricks Open-source Online Form Builder.png rename to apps/formbricks-com/src/images/SEO/Google Forms Open Source Alternative Comparison with Formbricks Open-source Online Form Builder.png diff --git a/apps/formbricks-com-old/images/SEO/GoogleForms GDPR compliant for EU company open source self-hosting alternative.png b/apps/formbricks-com/src/images/SEO/GoogleForms GDPR compliant for EU company open source self-hosting alternative.png similarity index 100% rename from apps/formbricks-com-old/images/SEO/GoogleForms GDPR compliant for EU company open source self-hosting alternative.png rename to apps/formbricks-com/src/images/SEO/GoogleForms GDPR compliant for EU company open source self-hosting alternative.png diff --git a/apps/formbricks-com-old/images/SEO/OhMyForm Typeform Alternative comparison Formbricks open source forms and survey library builder.png b/apps/formbricks-com/src/images/SEO/OhMyForm Typeform Alternative comparison Formbricks open source forms and survey library builder.png similarity index 100% rename from apps/formbricks-com-old/images/SEO/OhMyForm Typeform Alternative comparison Formbricks open source forms and survey library builder.png rename to apps/formbricks-com/src/images/SEO/OhMyForm Typeform Alternative comparison Formbricks open source forms and survey library builder.png diff --git a/apps/formbricks-com-old/images/SEO/Stars - best open source react survey builder 2023 comparison of github repository stars for form builder library.png b/apps/formbricks-com/src/images/SEO/Stars - best open source react survey builder 2023 comparison of github repository stars for form builder library.png similarity index 100% rename from apps/formbricks-com-old/images/SEO/Stars - best open source react survey builder 2023 comparison of github repository stars for form builder library.png rename to apps/formbricks-com/src/images/SEO/Stars - best open source react survey builder 2023 comparison of github repository stars for form builder library.png diff --git a/apps/formbricks-com-old/images/SEO/Winner comparison best React survey Library and Builder 2023 2022.png b/apps/formbricks-com/src/images/SEO/Winner comparison best React survey Library and Builder 2023 2022.png similarity index 100% rename from apps/formbricks-com-old/images/SEO/Winner comparison best React survey Library and Builder 2023 2022.png rename to apps/formbricks-com/src/images/SEO/Winner comparison best React survey Library and Builder 2023 2022.png diff --git a/apps/formbricks-com-old/images/SEO/example-lemonade-radio-field-with-image-in-react-library-Oopen-source.png b/apps/formbricks-com/src/images/SEO/example-lemonade-radio-field-with-image-in-react-library-Oopen-source.png similarity index 100% rename from apps/formbricks-com-old/images/SEO/example-lemonade-radio-field-with-image-in-react-library-Oopen-source.png rename to apps/formbricks-com/src/images/SEO/example-lemonade-radio-field-with-image-in-react-library-Oopen-source.png diff --git a/apps/formbricks-com-old/images/SEO/who gets the crown of open source forms.gif b/apps/formbricks-com/src/images/SEO/who gets the crown of open source forms.gif similarity index 100% rename from apps/formbricks-com-old/images/SEO/who gets the crown of open source forms.gif rename to apps/formbricks-com/src/images/SEO/who gets the crown of open source forms.gif diff --git a/apps/formbricks-com-old/images/ask-nothing-twice.png b/apps/formbricks-com/src/images/ask-nothing-twice.png similarity index 100% rename from apps/formbricks-com-old/images/ask-nothing-twice.png rename to apps/formbricks-com/src/images/ask-nothing-twice.png diff --git a/apps/formbricks-com-old/images/attributes-dark.png b/apps/formbricks-com/src/images/attributes-dark.png similarity index 100% rename from apps/formbricks-com-old/images/attributes-dark.png rename to apps/formbricks-com/src/images/attributes-dark.png diff --git a/apps/formbricks-com-old/images/attributes-dark.svg b/apps/formbricks-com/src/images/attributes-dark.svg similarity index 100% rename from apps/formbricks-com-old/images/attributes-dark.svg rename to apps/formbricks-com/src/images/attributes-dark.svg diff --git a/apps/formbricks-com-old/images/attributes-light.png b/apps/formbricks-com/src/images/attributes-light.png similarity index 100% rename from apps/formbricks-com-old/images/attributes-light.png rename to apps/formbricks-com/src/images/attributes-light.png diff --git a/apps/formbricks-com-old/images/attributes-light.svg b/apps/formbricks-com/src/images/attributes-light.svg similarity index 100% rename from apps/formbricks-com-old/images/attributes-light.svg rename to apps/formbricks-com/src/images/attributes-light.svg diff --git a/apps/formbricks-com/src/images/blog/SEO/Best React Form Library and Builder 2023 to create and build forms surveys easy and fast.png b/apps/formbricks-com/src/images/blog/SEO/Best React Form Library and Builder 2023 to create and build forms surveys easy and fast.png new file mode 100644 index 0000000000..397c61b314 Binary files /dev/null and b/apps/formbricks-com/src/images/blog/SEO/Best React Form Library and Builder 2023 to create and build forms surveys easy and fast.png differ diff --git a/apps/formbricks-com/src/images/blog/SEO/Data Controller vs Data Processor Overview for open source forms and surveys.png b/apps/formbricks-com/src/images/blog/SEO/Data Controller vs Data Processor Overview for open source forms and surveys.png new file mode 100644 index 0000000000..d5b1e04bba Binary files /dev/null and b/apps/formbricks-com/src/images/blog/SEO/Data Controller vs Data Processor Overview for open source forms and surveys.png differ diff --git a/apps/formbricks-com/src/images/blog/SEO/Formbricks React Form Library vs React Hook Form comparison post to build forms fast in reactjs smaller.png b/apps/formbricks-com/src/images/blog/SEO/Formbricks React Form Library vs React Hook Form comparison post to build forms fast in reactjs smaller.png new file mode 100644 index 0000000000..9db63c89e5 Binary files /dev/null and b/apps/formbricks-com/src/images/blog/SEO/Formbricks React Form Library vs React Hook Form comparison post to build forms fast in reactjs smaller.png differ diff --git a/apps/formbricks-com/src/images/blog/SEO/Formspree open source alternative vs Formbricks FormHQ comparison post for form backend as a service.png b/apps/formbricks-com/src/images/blog/SEO/Formspree open source alternative vs Formbricks FormHQ comparison post for form backend as a service.png new file mode 100644 index 0000000000..a31075a0fd Binary files /dev/null and b/apps/formbricks-com/src/images/blog/SEO/Formspree open source alternative vs Formbricks FormHQ comparison post for form backend as a service.png differ diff --git a/apps/formbricks-com/src/images/blog/SEO/Google Form Example Customize and make it comply with GDPR CCPA HIPAA open source alternative.png b/apps/formbricks-com/src/images/blog/SEO/Google Form Example Customize and make it comply with GDPR CCPA HIPAA open source alternative.png new file mode 100644 index 0000000000..bcb740041d Binary files /dev/null and b/apps/formbricks-com/src/images/blog/SEO/Google Form Example Customize and make it comply with GDPR CCPA HIPAA open source alternative.png differ diff --git a/apps/formbricks-com/src/images/blog/SEO/Google Forms Open Source Alternative Comparison with Formbricks Open-source Online Form Builder.png b/apps/formbricks-com/src/images/blog/SEO/Google Forms Open Source Alternative Comparison with Formbricks Open-source Online Form Builder.png new file mode 100644 index 0000000000..e65289b7d8 Binary files /dev/null and b/apps/formbricks-com/src/images/blog/SEO/Google Forms Open Source Alternative Comparison with Formbricks Open-source Online Form Builder.png differ diff --git a/apps/formbricks-com/src/images/blog/SEO/GoogleForms GDPR compliant for EU company open source self-hosting alternative.png b/apps/formbricks-com/src/images/blog/SEO/GoogleForms GDPR compliant for EU company open source self-hosting alternative.png new file mode 100644 index 0000000000..e3594fc1a2 Binary files /dev/null and b/apps/formbricks-com/src/images/blog/SEO/GoogleForms GDPR compliant for EU company open source self-hosting alternative.png differ diff --git a/apps/formbricks-com/src/images/blog/SEO/OhMyForm Typeform Alternative comparison Formbricks open source forms and survey library builder.png b/apps/formbricks-com/src/images/blog/SEO/OhMyForm Typeform Alternative comparison Formbricks open source forms and survey library builder.png new file mode 100644 index 0000000000..f1251113d8 Binary files /dev/null and b/apps/formbricks-com/src/images/blog/SEO/OhMyForm Typeform Alternative comparison Formbricks open source forms and survey library builder.png differ diff --git a/apps/formbricks-com/src/images/blog/SEO/Stars - best open source react survey builder 2023 comparison of github repository stars for form builder library.png b/apps/formbricks-com/src/images/blog/SEO/Stars - best open source react survey builder 2023 comparison of github repository stars for form builder library.png new file mode 100644 index 0000000000..db6d997a2c Binary files /dev/null and b/apps/formbricks-com/src/images/blog/SEO/Stars - best open source react survey builder 2023 comparison of github repository stars for form builder library.png differ diff --git a/apps/formbricks-com/src/images/blog/SEO/Winner comparison best React survey Library and Builder 2023 2022.png b/apps/formbricks-com/src/images/blog/SEO/Winner comparison best React survey Library and Builder 2023 2022.png new file mode 100644 index 0000000000..96f7db1acf Binary files /dev/null and b/apps/formbricks-com/src/images/blog/SEO/Winner comparison best React survey Library and Builder 2023 2022.png differ diff --git a/apps/formbricks-com/src/images/blog/SEO/example-lemonade-radio-field-with-image-in-react-library-Oopen-source.png b/apps/formbricks-com/src/images/blog/SEO/example-lemonade-radio-field-with-image-in-react-library-Oopen-source.png new file mode 100644 index 0000000000..cea047504a Binary files /dev/null and b/apps/formbricks-com/src/images/blog/SEO/example-lemonade-radio-field-with-image-in-react-library-Oopen-source.png differ diff --git a/apps/formbricks-com/src/images/blog/SEO/who gets the crown of open source forms.gif b/apps/formbricks-com/src/images/blog/SEO/who gets the crown of open source forms.gif new file mode 100644 index 0000000000..93ed405bfd Binary files /dev/null and b/apps/formbricks-com/src/images/blog/SEO/who gets the crown of open source forms.gif differ diff --git a/apps/formbricks-com/src/images/blog/ask-nothing-twice.png b/apps/formbricks-com/src/images/blog/ask-nothing-twice.png new file mode 100644 index 0000000000..a66a2356ac Binary files /dev/null and b/apps/formbricks-com/src/images/blog/ask-nothing-twice.png differ diff --git a/apps/formbricks-com/src/images/blog/attributes-dark.png b/apps/formbricks-com/src/images/blog/attributes-dark.png new file mode 100644 index 0000000000..2637ab16be Binary files /dev/null and b/apps/formbricks-com/src/images/blog/attributes-dark.png differ diff --git a/apps/formbricks-com/src/images/blog/attributes-dark.svg b/apps/formbricks-com/src/images/blog/attributes-dark.svg new file mode 100644 index 0000000000..6148dbf453 --- /dev/null +++ b/apps/formbricks-com/src/images/blog/attributes-dark.svg @@ -0,0 +1,129 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/apps/formbricks-com/src/images/blog/attributes-light.png b/apps/formbricks-com/src/images/blog/attributes-light.png new file mode 100644 index 0000000000..1813075ecc Binary files /dev/null and b/apps/formbricks-com/src/images/blog/attributes-light.png differ diff --git a/apps/formbricks-com/src/images/blog/attributes-light.svg b/apps/formbricks-com/src/images/blog/attributes-light.svg new file mode 100644 index 0000000000..f2534159bf --- /dev/null +++ b/apps/formbricks-com/src/images/blog/attributes-light.svg @@ -0,0 +1,129 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/apps/formbricks-com-old/images/blur-cyan.png b/apps/formbricks-com/src/images/blog/blur-cyan.png similarity index 100% rename from apps/formbricks-com-old/images/blur-cyan.png rename to apps/formbricks-com/src/images/blog/blur-cyan.png diff --git a/apps/formbricks-com-old/images/blur-indigo.png b/apps/formbricks-com/src/images/blog/blur-indigo.png similarity index 100% rename from apps/formbricks-com-old/images/blur-indigo.png rename to apps/formbricks-com/src/images/blog/blur-indigo.png diff --git a/apps/formbricks-com-old/images/clients/cal-logo-dark.svg b/apps/formbricks-com/src/images/blog/clients/cal-logo-dark.svg similarity index 100% rename from apps/formbricks-com-old/images/clients/cal-logo-dark.svg rename to apps/formbricks-com/src/images/blog/clients/cal-logo-dark.svg diff --git a/apps/formbricks-com-old/images/clients/cal-logo-light.svg b/apps/formbricks-com/src/images/blog/clients/cal-logo-light.svg similarity index 100% rename from apps/formbricks-com-old/images/clients/cal-logo-light.svg rename to apps/formbricks-com/src/images/blog/clients/cal-logo-light.svg diff --git a/apps/formbricks-com-old/images/clients/clovyr-logo.svg b/apps/formbricks-com/src/images/blog/clients/clovyr-logo.svg similarity index 100% rename from apps/formbricks-com-old/images/clients/clovyr-logo.svg rename to apps/formbricks-com/src/images/blog/clients/clovyr-logo.svg diff --git a/apps/formbricks-com-old/images/clients/crowd-logo-dark.svg b/apps/formbricks-com/src/images/blog/clients/crowd-logo-dark.svg similarity index 100% rename from apps/formbricks-com-old/images/clients/crowd-logo-dark.svg rename to apps/formbricks-com/src/images/blog/clients/crowd-logo-dark.svg diff --git a/apps/formbricks-com-old/images/clients/crowd-logo-light.svg b/apps/formbricks-com/src/images/blog/clients/crowd-logo-light.svg similarity index 100% rename from apps/formbricks-com-old/images/clients/crowd-logo-light.svg rename to apps/formbricks-com/src/images/blog/clients/crowd-logo-light.svg diff --git a/apps/formbricks-com-old/images/clients/niLogoDark.svg b/apps/formbricks-com/src/images/blog/clients/niLogoDark.svg similarity index 100% rename from apps/formbricks-com-old/images/clients/niLogoDark.svg rename to apps/formbricks-com/src/images/blog/clients/niLogoDark.svg diff --git a/apps/formbricks-com-old/images/clients/niLogoWhite.svg b/apps/formbricks-com/src/images/blog/clients/niLogoWhite.svg similarity index 100% rename from apps/formbricks-com-old/images/clients/niLogoWhite.svg rename to apps/formbricks-com/src/images/blog/clients/niLogoWhite.svg diff --git a/apps/formbricks-com-old/images/connect-analytics.png b/apps/formbricks-com/src/images/blog/connect-analytics.png similarity index 100% rename from apps/formbricks-com-old/images/connect-analytics.png rename to apps/formbricks-com/src/images/blog/connect-analytics.png diff --git a/apps/formbricks-com-old/images/core-api.svg b/apps/formbricks-com/src/images/blog/core-api.svg similarity index 100% rename from apps/formbricks-com-old/images/core-api.svg rename to apps/formbricks-com/src/images/blog/core-api.svg diff --git a/apps/formbricks-com-old/images/dark-connect-analytics.png b/apps/formbricks-com/src/images/blog/dark-connect-analytics.png similarity index 100% rename from apps/formbricks-com-old/images/dark-connect-analytics.png rename to apps/formbricks-com/src/images/blog/dark-connect-analytics.png diff --git a/apps/formbricks-com-old/images/dark-insights.png b/apps/formbricks-com/src/images/blog/dark-insights.png similarity index 100% rename from apps/formbricks-com-old/images/dark-insights.png rename to apps/formbricks-com/src/images/blog/dark-insights.png diff --git a/apps/formbricks-com-old/images/dashboard-mockup-dark.png b/apps/formbricks-com/src/images/blog/dashboard-mockup-dark.png similarity index 100% rename from apps/formbricks-com-old/images/dashboard-mockup-dark.png rename to apps/formbricks-com/src/images/blog/dashboard-mockup-dark.png diff --git a/apps/formbricks-com-old/images/dashboard-mockup.png b/apps/formbricks-com/src/images/blog/dashboard-mockup.png similarity index 100% rename from apps/formbricks-com-old/images/dashboard-mockup.png rename to apps/formbricks-com/src/images/blog/dashboard-mockup.png diff --git a/apps/formbricks-com-old/images/data-pipelines.png b/apps/formbricks-com/src/images/blog/data-pipelines.png similarity index 100% rename from apps/formbricks-com-old/images/data-pipelines.png rename to apps/formbricks-com/src/images/blog/data-pipelines.png diff --git a/apps/formbricks-com-old/images/docs/copy-id.png b/apps/formbricks-com/src/images/blog/docs/copy-id.png similarity index 100% rename from apps/formbricks-com-old/images/docs/copy-id.png rename to apps/formbricks-com/src/images/blog/docs/copy-id.png diff --git a/apps/formbricks-com-old/images/docs/create-feedback-box.png b/apps/formbricks-com/src/images/blog/docs/create-feedback-box.png similarity index 100% rename from apps/formbricks-com-old/images/docs/create-feedback-box.png rename to apps/formbricks-com/src/images/blog/docs/create-feedback-box.png diff --git a/apps/formbricks-com-old/images/docs/fb-id.png b/apps/formbricks-com/src/images/blog/docs/fb-id.png similarity index 100% rename from apps/formbricks-com-old/images/docs/fb-id.png rename to apps/formbricks-com/src/images/blog/docs/fb-id.png diff --git a/apps/formbricks-com-old/images/docs/new-pmf.png b/apps/formbricks-com/src/images/blog/docs/new-pmf.png similarity index 100% rename from apps/formbricks-com-old/images/docs/new-pmf.png rename to apps/formbricks-com/src/images/blog/docs/new-pmf.png diff --git a/apps/formbricks-com-old/images/early bird deal for open source jotform alternative typeform and surveymonkey_v2.svg b/apps/formbricks-com/src/images/blog/early bird deal for open source jotform alternative typeform and surveymonkey_v2.svg similarity index 100% rename from apps/formbricks-com-old/images/early bird deal for open source jotform alternative typeform and surveymonkey_v2.svg rename to apps/formbricks-com/src/images/blog/early bird deal for open source jotform alternative typeform and surveymonkey_v2.svg diff --git a/apps/formbricks-com-old/images/email.svg b/apps/formbricks-com/src/images/blog/email.svg similarity index 100% rename from apps/formbricks-com-old/images/email.svg rename to apps/formbricks-com/src/images/blog/email.svg diff --git a/apps/formbricks-com-old/images/event-trigger-dark.png b/apps/formbricks-com/src/images/blog/event-trigger-dark.png similarity index 100% rename from apps/formbricks-com-old/images/event-trigger-dark.png rename to apps/formbricks-com/src/images/blog/event-trigger-dark.png diff --git a/apps/formbricks-com-old/images/event-trigger-dark.svg b/apps/formbricks-com/src/images/blog/event-trigger-dark.svg similarity index 100% rename from apps/formbricks-com-old/images/event-trigger-dark.svg rename to apps/formbricks-com/src/images/blog/event-trigger-dark.svg diff --git a/apps/formbricks-com-old/images/event-trigger-light.png b/apps/formbricks-com/src/images/blog/event-trigger-light.png similarity index 100% rename from apps/formbricks-com-old/images/event-trigger-light.png rename to apps/formbricks-com/src/images/blog/event-trigger-light.png diff --git a/apps/formbricks-com-old/images/event-trigger-light.svg b/apps/formbricks-com/src/images/blog/event-trigger-light.svg similarity index 100% rename from apps/formbricks-com-old/images/event-trigger-light.svg rename to apps/formbricks-com/src/images/blog/event-trigger-light.svg diff --git a/apps/formbricks-com-old/images/form-hq.png b/apps/formbricks-com/src/images/blog/form-hq.png similarity index 100% rename from apps/formbricks-com-old/images/form-hq.png rename to apps/formbricks-com/src/images/blog/form-hq.png diff --git a/apps/formbricks-com-old/images/github-mark-white.svg b/apps/formbricks-com/src/images/blog/github-mark-white.svg similarity index 100% rename from apps/formbricks-com-old/images/github-mark-white.svg rename to apps/formbricks-com/src/images/blog/github-mark-white.svg diff --git a/apps/formbricks-com-old/images/github-mark.svg b/apps/formbricks-com/src/images/blog/github-mark.svg similarity index 100% rename from apps/formbricks-com-old/images/github-mark.svg rename to apps/formbricks-com/src/images/blog/github-mark.svg diff --git a/apps/formbricks-com-old/images/insights.png b/apps/formbricks-com/src/images/blog/insights.png similarity index 100% rename from apps/formbricks-com-old/images/insights.png rename to apps/formbricks-com/src/images/blog/insights.png diff --git a/apps/formbricks-com-old/images/blog/johannes-co-founder-formbricks-small.jpg b/apps/formbricks-com/src/images/blog/johannes-co-founder-formbricks-small.jpg similarity index 100% rename from apps/formbricks-com-old/images/blog/johannes-co-founder-formbricks-small.jpg rename to apps/formbricks-com/src/images/blog/johannes-co-founder-formbricks-small.jpg diff --git a/apps/formbricks-com-old/images/logo/footerlogo-dark.svg b/apps/formbricks-com/src/images/blog/logo/footerlogo-dark.svg similarity index 100% rename from apps/formbricks-com-old/images/logo/footerlogo-dark.svg rename to apps/formbricks-com/src/images/blog/logo/footerlogo-dark.svg diff --git a/apps/formbricks-com-old/images/logo/footerlogo.svg b/apps/formbricks-com/src/images/blog/logo/footerlogo.svg similarity index 100% rename from apps/formbricks-com-old/images/logo/footerlogo.svg rename to apps/formbricks-com/src/images/blog/logo/footerlogo.svg diff --git a/apps/formbricks-com-old/images/logo/logo.svg b/apps/formbricks-com/src/images/blog/logo/logo.svg similarity index 100% rename from apps/formbricks-com-old/images/logo/logo.svg rename to apps/formbricks-com/src/images/blog/logo/logo.svg diff --git a/apps/formbricks-com-old/images/logo/logo_dark.svg b/apps/formbricks-com/src/images/blog/logo/logo_dark.svg similarity index 100% rename from apps/formbricks-com-old/images/logo/logo_dark.svg rename to apps/formbricks-com/src/images/blog/logo/logo_dark.svg diff --git a/apps/formbricks-com-old/images/logo/logomark.svg b/apps/formbricks-com/src/images/blog/logo/logomark.svg similarity index 100% rename from apps/formbricks-com-old/images/logo/logomark.svg rename to apps/formbricks-com/src/images/blog/logo/logomark.svg diff --git a/apps/formbricks-com-old/images/newsletter-signup-gif.gif b/apps/formbricks-com/src/images/blog/newsletter-signup-gif.gif similarity index 100% rename from apps/formbricks-com-old/images/newsletter-signup-gif.gif rename to apps/formbricks-com/src/images/blog/newsletter-signup-gif.gif diff --git a/apps/formbricks-com-old/images/pipelines-dark.png b/apps/formbricks-com/src/images/blog/pipelines-dark.png similarity index 100% rename from apps/formbricks-com-old/images/pipelines-dark.png rename to apps/formbricks-com/src/images/blog/pipelines-dark.png diff --git a/apps/formbricks-com-old/images/pipelines.png b/apps/formbricks-com/src/images/blog/pipelines.png similarity index 100% rename from apps/formbricks-com-old/images/pipelines.png rename to apps/formbricks-com/src/images/blog/pipelines.png diff --git a/apps/formbricks-com-old/images/pre-segmentation-dark.png b/apps/formbricks-com/src/images/blog/pre-segmentation-dark.png similarity index 100% rename from apps/formbricks-com-old/images/pre-segmentation-dark.png rename to apps/formbricks-com/src/images/blog/pre-segmentation-dark.png diff --git a/apps/formbricks-com-old/images/pre-segmentation.png b/apps/formbricks-com/src/images/blog/pre-segmentation.png similarity index 100% rename from apps/formbricks-com-old/images/pre-segmentation.png rename to apps/formbricks-com/src/images/blog/pre-segmentation.png diff --git a/apps/formbricks-com-old/images/pre-segmentation.svg b/apps/formbricks-com/src/images/blog/pre-segmentation.svg similarity index 100% rename from apps/formbricks-com-old/images/pre-segmentation.svg rename to apps/formbricks-com/src/images/blog/pre-segmentation.svg diff --git a/apps/formbricks-com-old/images/react-lib.png b/apps/formbricks-com/src/images/blog/react-lib.png similarity index 100% rename from apps/formbricks-com-old/images/react-lib.png rename to apps/formbricks-com/src/images/blog/react-lib.png diff --git a/apps/formbricks-com-old/images/schema-generation-svg.svg b/apps/formbricks-com/src/images/blog/schema-generation-svg.svg similarity index 100% rename from apps/formbricks-com-old/images/schema-generation-svg.svg rename to apps/formbricks-com/src/images/blog/schema-generation-svg.svg diff --git a/apps/formbricks-com-old/images/schema-generation.png b/apps/formbricks-com/src/images/blog/schema-generation.png similarity index 100% rename from apps/formbricks-com-old/images/schema-generation.png rename to apps/formbricks-com/src/images/blog/schema-generation.png diff --git a/apps/formbricks-com-old/images/webhook-png.png b/apps/formbricks-com/src/images/blog/webhook-png.png similarity index 100% rename from apps/formbricks-com-old/images/webhook-png.png rename to apps/formbricks-com/src/images/blog/webhook-png.png diff --git a/apps/formbricks-com/src/images/blur-cyan.png b/apps/formbricks-com/src/images/blur-cyan.png new file mode 100644 index 0000000000..e98d7b90e6 Binary files /dev/null and b/apps/formbricks-com/src/images/blur-cyan.png differ diff --git a/apps/formbricks-com/src/images/blur-indigo.png b/apps/formbricks-com/src/images/blur-indigo.png new file mode 100644 index 0000000000..3fc10f984e Binary files /dev/null and b/apps/formbricks-com/src/images/blur-indigo.png differ diff --git a/apps/formbricks-com/src/images/clients/cal-logo-dark.svg b/apps/formbricks-com/src/images/clients/cal-logo-dark.svg new file mode 100644 index 0000000000..e12d2875c3 --- /dev/null +++ b/apps/formbricks-com/src/images/clients/cal-logo-dark.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/apps/formbricks-com/src/images/clients/cal-logo-light.svg b/apps/formbricks-com/src/images/clients/cal-logo-light.svg new file mode 100644 index 0000000000..bccfe813ef --- /dev/null +++ b/apps/formbricks-com/src/images/clients/cal-logo-light.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/apps/formbricks-com/src/images/clients/clovyr-logo.svg b/apps/formbricks-com/src/images/clients/clovyr-logo.svg new file mode 100644 index 0000000000..83ea8bb6ee --- /dev/null +++ b/apps/formbricks-com/src/images/clients/clovyr-logo.svg @@ -0,0 +1 @@ +clovyr-logo \ No newline at end of file diff --git a/apps/formbricks-com/src/images/clients/crowd-logo-dark.svg b/apps/formbricks-com/src/images/clients/crowd-logo-dark.svg new file mode 100644 index 0000000000..3b88ad8e08 --- /dev/null +++ b/apps/formbricks-com/src/images/clients/crowd-logo-dark.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/apps/formbricks-com/src/images/clients/crowd-logo-light.svg b/apps/formbricks-com/src/images/clients/crowd-logo-light.svg new file mode 100644 index 0000000000..0ba87c1306 --- /dev/null +++ b/apps/formbricks-com/src/images/clients/crowd-logo-light.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/apps/formbricks-com/src/images/clients/niLogoDark.svg b/apps/formbricks-com/src/images/clients/niLogoDark.svg new file mode 100644 index 0000000000..e6f95c4145 --- /dev/null +++ b/apps/formbricks-com/src/images/clients/niLogoDark.svg @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/apps/formbricks-com/src/images/clients/niLogoWhite.svg b/apps/formbricks-com/src/images/clients/niLogoWhite.svg new file mode 100644 index 0000000000..01937410d2 --- /dev/null +++ b/apps/formbricks-com/src/images/clients/niLogoWhite.svg @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/apps/formbricks-com/src/images/connect-analytics.png b/apps/formbricks-com/src/images/connect-analytics.png new file mode 100644 index 0000000000..e7bf48753a Binary files /dev/null and b/apps/formbricks-com/src/images/connect-analytics.png differ diff --git a/apps/formbricks-com/src/images/core-api.svg b/apps/formbricks-com/src/images/core-api.svg new file mode 100644 index 0000000000..c27abc51f4 --- /dev/null +++ b/apps/formbricks-com/src/images/core-api.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/apps/formbricks-com/src/images/dark-connect-analytics.png b/apps/formbricks-com/src/images/dark-connect-analytics.png new file mode 100644 index 0000000000..dcaba31ec3 Binary files /dev/null and b/apps/formbricks-com/src/images/dark-connect-analytics.png differ diff --git a/apps/formbricks-com/src/images/dark-insights.png b/apps/formbricks-com/src/images/dark-insights.png new file mode 100644 index 0000000000..e2670ad29f Binary files /dev/null and b/apps/formbricks-com/src/images/dark-insights.png differ diff --git a/apps/formbricks-com/src/images/dashboard-mockup-dark.png b/apps/formbricks-com/src/images/dashboard-mockup-dark.png new file mode 100644 index 0000000000..cae532da64 Binary files /dev/null and b/apps/formbricks-com/src/images/dashboard-mockup-dark.png differ diff --git a/apps/formbricks-com/src/images/dashboard-mockup.png b/apps/formbricks-com/src/images/dashboard-mockup.png new file mode 100644 index 0000000000..dfb5590108 Binary files /dev/null and b/apps/formbricks-com/src/images/dashboard-mockup.png differ diff --git a/apps/formbricks-com/src/images/data-pipelines.png b/apps/formbricks-com/src/images/data-pipelines.png new file mode 100644 index 0000000000..344bf92d41 Binary files /dev/null and b/apps/formbricks-com/src/images/data-pipelines.png differ diff --git a/apps/formbricks-com/src/images/docs/copy-id.png b/apps/formbricks-com/src/images/docs/copy-id.png new file mode 100644 index 0000000000..5655116285 Binary files /dev/null and b/apps/formbricks-com/src/images/docs/copy-id.png differ diff --git a/apps/formbricks-com/src/images/docs/create-feedback-box.png b/apps/formbricks-com/src/images/docs/create-feedback-box.png new file mode 100644 index 0000000000..5602fe02f7 Binary files /dev/null and b/apps/formbricks-com/src/images/docs/create-feedback-box.png differ diff --git a/apps/formbricks-com/src/images/docs/fb-id.png b/apps/formbricks-com/src/images/docs/fb-id.png new file mode 100644 index 0000000000..15f69748f5 Binary files /dev/null and b/apps/formbricks-com/src/images/docs/fb-id.png differ diff --git a/apps/formbricks-com/src/images/docs/new-pmf.png b/apps/formbricks-com/src/images/docs/new-pmf.png new file mode 100644 index 0000000000..ff187e7cc1 Binary files /dev/null and b/apps/formbricks-com/src/images/docs/new-pmf.png differ diff --git a/apps/formbricks-com/src/images/early bird deal for open source jotform alternative typeform and surveymonkey_v2.svg b/apps/formbricks-com/src/images/early bird deal for open source jotform alternative typeform and surveymonkey_v2.svg new file mode 100644 index 0000000000..3740e2367c --- /dev/null +++ b/apps/formbricks-com/src/images/early bird deal for open source jotform alternative typeform and surveymonkey_v2.svg @@ -0,0 +1,276 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/apps/formbricks-com/src/images/email.svg b/apps/formbricks-com/src/images/email.svg new file mode 100644 index 0000000000..29b5506261 --- /dev/null +++ b/apps/formbricks-com/src/images/email.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/apps/formbricks-com/src/images/event-trigger-dark.png b/apps/formbricks-com/src/images/event-trigger-dark.png new file mode 100644 index 0000000000..60ee18115f Binary files /dev/null and b/apps/formbricks-com/src/images/event-trigger-dark.png differ diff --git a/apps/formbricks-com/src/images/event-trigger-dark.svg b/apps/formbricks-com/src/images/event-trigger-dark.svg new file mode 100644 index 0000000000..08315ff1f7 --- /dev/null +++ b/apps/formbricks-com/src/images/event-trigger-dark.svg @@ -0,0 +1,50 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/apps/formbricks-com/src/images/event-trigger-light.png b/apps/formbricks-com/src/images/event-trigger-light.png new file mode 100644 index 0000000000..e938e17864 Binary files /dev/null and b/apps/formbricks-com/src/images/event-trigger-light.png differ diff --git a/apps/formbricks-com/src/images/event-trigger-light.svg b/apps/formbricks-com/src/images/event-trigger-light.svg new file mode 100644 index 0000000000..f8360722c4 --- /dev/null +++ b/apps/formbricks-com/src/images/event-trigger-light.svg @@ -0,0 +1,50 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/apps/formbricks-com/src/images/form-hq.png b/apps/formbricks-com/src/images/form-hq.png new file mode 100644 index 0000000000..f337588428 Binary files /dev/null and b/apps/formbricks-com/src/images/form-hq.png differ diff --git a/apps/formbricks-com/src/images/github-mark-white.svg b/apps/formbricks-com/src/images/github-mark-white.svg new file mode 100644 index 0000000000..d5e6491854 --- /dev/null +++ b/apps/formbricks-com/src/images/github-mark-white.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/apps/formbricks-com/src/images/github-mark.svg b/apps/formbricks-com/src/images/github-mark.svg new file mode 100644 index 0000000000..37fa923df3 --- /dev/null +++ b/apps/formbricks-com/src/images/github-mark.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/apps/formbricks-com/src/images/insights.png b/apps/formbricks-com/src/images/insights.png new file mode 100644 index 0000000000..6aa863c3a5 Binary files /dev/null and b/apps/formbricks-com/src/images/insights.png differ diff --git a/apps/formbricks-com/src/images/logo/footerlogo-dark.svg b/apps/formbricks-com/src/images/logo/footerlogo-dark.svg new file mode 100644 index 0000000000..7f0568ab1a --- /dev/null +++ b/apps/formbricks-com/src/images/logo/footerlogo-dark.svg @@ -0,0 +1,76 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/apps/formbricks-com/src/images/logo/footerlogo.svg b/apps/formbricks-com/src/images/logo/footerlogo.svg new file mode 100644 index 0000000000..659385db41 --- /dev/null +++ b/apps/formbricks-com/src/images/logo/footerlogo.svg @@ -0,0 +1,76 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/apps/formbricks-com/src/images/logo/logo.svg b/apps/formbricks-com/src/images/logo/logo.svg new file mode 100644 index 0000000000..876b76df16 --- /dev/null +++ b/apps/formbricks-com/src/images/logo/logo.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/apps/formbricks-com/src/images/logo/logo_dark.svg b/apps/formbricks-com/src/images/logo/logo_dark.svg new file mode 100644 index 0000000000..73058e0901 --- /dev/null +++ b/apps/formbricks-com/src/images/logo/logo_dark.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/apps/formbricks-com/src/images/logo/logomark.svg b/apps/formbricks-com/src/images/logo/logomark.svg new file mode 100644 index 0000000000..8a45b869b1 --- /dev/null +++ b/apps/formbricks-com/src/images/logo/logomark.svg @@ -0,0 +1,79 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/apps/formbricks-com/src/images/newsletter-signup-gif.gif b/apps/formbricks-com/src/images/newsletter-signup-gif.gif new file mode 100644 index 0000000000..2587878b5f Binary files /dev/null and b/apps/formbricks-com/src/images/newsletter-signup-gif.gif differ diff --git a/apps/formbricks-com/src/images/pipelines-dark.png b/apps/formbricks-com/src/images/pipelines-dark.png new file mode 100644 index 0000000000..1f2192a4d4 Binary files /dev/null and b/apps/formbricks-com/src/images/pipelines-dark.png differ diff --git a/apps/formbricks-com/src/images/pipelines.png b/apps/formbricks-com/src/images/pipelines.png new file mode 100644 index 0000000000..250a599fec Binary files /dev/null and b/apps/formbricks-com/src/images/pipelines.png differ diff --git a/apps/formbricks-com/src/images/pre-segmentation-dark.png b/apps/formbricks-com/src/images/pre-segmentation-dark.png new file mode 100644 index 0000000000..1f57383cf8 Binary files /dev/null and b/apps/formbricks-com/src/images/pre-segmentation-dark.png differ diff --git a/apps/formbricks-com/src/images/pre-segmentation.png b/apps/formbricks-com/src/images/pre-segmentation.png new file mode 100644 index 0000000000..838d3f81f3 Binary files /dev/null and b/apps/formbricks-com/src/images/pre-segmentation.png differ diff --git a/apps/formbricks-com/src/images/pre-segmentation.svg b/apps/formbricks-com/src/images/pre-segmentation.svg new file mode 100644 index 0000000000..a0d3e41301 --- /dev/null +++ b/apps/formbricks-com/src/images/pre-segmentation.svg @@ -0,0 +1,89 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/apps/formbricks-com/src/images/react-lib.png b/apps/formbricks-com/src/images/react-lib.png new file mode 100644 index 0000000000..280207cf87 Binary files /dev/null and b/apps/formbricks-com/src/images/react-lib.png differ diff --git a/apps/formbricks-com/src/images/schema-generation-svg.svg b/apps/formbricks-com/src/images/schema-generation-svg.svg new file mode 100644 index 0000000000..f21ebf84aa --- /dev/null +++ b/apps/formbricks-com/src/images/schema-generation-svg.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/apps/formbricks-com/src/images/schema-generation.png b/apps/formbricks-com/src/images/schema-generation.png new file mode 100644 index 0000000000..3c0dffa8ed Binary files /dev/null and b/apps/formbricks-com/src/images/schema-generation.png differ diff --git a/apps/formbricks-com/src/images/webhook-png.png b/apps/formbricks-com/src/images/webhook-png.png new file mode 100644 index 0000000000..b5f3061736 Binary files /dev/null and b/apps/formbricks-com/src/images/webhook-png.png differ diff --git a/apps/formbricks-com/src/pages/404.tsx b/apps/formbricks-com/src/pages/404.tsx new file mode 100644 index 0000000000..d875bcd6c7 --- /dev/null +++ b/apps/formbricks-com/src/pages/404.tsx @@ -0,0 +1,14 @@ +// 404.js +import { Button } from "@formbricks/ui"; + +export default function FourOhFour() { + return ( +
    +

    404

    +

    Page Not Found

    + +
    + ); +} diff --git a/apps/formbricks-com/src/pages/_app.tsx b/apps/formbricks-com/src/pages/_app.tsx new file mode 100644 index 0000000000..1e5bd76a62 --- /dev/null +++ b/apps/formbricks-com/src/pages/_app.tsx @@ -0,0 +1,11 @@ +import PlausibleProvider from 'next-plausible' +import type { AppProps } from 'next/app' +import '../styles/tailwind.css' + +export default function App({ Component, pageProps }: AppProps) { + return ( + + + + ) +} diff --git a/apps/formbricks-com/src/pages/_document.tsx b/apps/formbricks-com/src/pages/_document.tsx new file mode 100644 index 0000000000..d31dd04b8b --- /dev/null +++ b/apps/formbricks-com/src/pages/_document.tsx @@ -0,0 +1,63 @@ +import { Head, Html, Main, NextScript } from "next/document"; + +const themeScript = ` + let isDarkMode = window.matchMedia('(prefers-color-scheme: dark)') + + function updateTheme(theme) { + theme = theme ?? window.localStorage.theme ?? 'system' + + if (theme === 'dark' || (theme === 'system' && isDarkMode.matches)) { + document.documentElement.classList.add('dark') + } else if (theme === 'light' || (theme === 'system' && !isDarkMode.matches)) { + document.documentElement.classList.remove('dark') + } + + return theme + } + + function updateThemeWithoutTransitions(theme) { + updateTheme(theme) + document.documentElement.classList.add('[&_*]:!transition-none') + window.setTimeout(() => { + document.documentElement.classList.remove('[&_*]:!transition-none') + }, 0) + } + + document.documentElement.setAttribute('data-theme', updateTheme()) + + new MutationObserver(([{ oldValue }]) => { + let newValue = document.documentElement.getAttribute('data-theme') + if (newValue !== oldValue) { + try { + window.localStorage.setItem('theme', newValue) + } catch {} + updateThemeWithoutTransitions(newValue) + } + }).observe(document.documentElement, { attributeFilter: ['data-theme'], attributeOldValue: true }) + + isDarkMode.addEventListener('change', () => updateThemeWithoutTransitions()) +`; + +export default function Document() { + return ( + + +