mirror of
https://github.com/formbricks/formbricks.git
synced 2026-04-25 23:18:54 -05:00
Add new landingpage with waitlist, update Formbricks App to handle custom waitlist survey (#185)
* add new landingpage for user research surveys * update Formbricks App to support custom surveys Co-authored-by: knugget <johannes@knugget.de>
This commit is contained in:
@@ -65,7 +65,7 @@ function Header({ navigation }: any) {
|
||||
onClick={() => router.push("https://github.com/formbricks/formbricks")}>
|
||||
View on Github
|
||||
</Button>
|
||||
<Button variant="highlight" className="ml-2" onClick={() => router.push("/get-started")}>
|
||||
<Button variant="highlight" className="ml-2" onClick={() => router.push("/waitlist")}>
|
||||
Get started
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
import { SurveyElement } from "./engineTypes";
|
||||
|
||||
interface FeatureSelectionProps {
|
||||
element: SurveyElement;
|
||||
field: any;
|
||||
register: any;
|
||||
control: any;
|
||||
onSubmit: () => void;
|
||||
disabled: boolean;
|
||||
}
|
||||
|
||||
export default function FeatureSelection({ element, field, register }: FeatureSelectionProps) {
|
||||
return (
|
||||
<div className="flex flex-col justify-center">
|
||||
<label
|
||||
htmlFor={element.id}
|
||||
className="pb-6 text-center text-lg font-bold text-slate-600 dark:text-slate-300 sm:text-xl md:text-2xl">
|
||||
{element.label}
|
||||
</label>
|
||||
<fieldset className="space-y-5">
|
||||
<legend className="sr-only">{element.label}</legend>
|
||||
<div className=" mx-auto grid max-w-5xl grid-cols-1 gap-6 px-2 sm:grid-cols-2">
|
||||
{element.options &&
|
||||
element.options.map((option) => (
|
||||
<label htmlFor={`${element.id}-${option.value}`} key={`${element.id}-${option.value}`}>
|
||||
<div className="drop-shadow-card duration-120 relative cursor-default rounded-lg border border-gray-200 bg-white p-6 transition-all ease-in-out hover:scale-105 dark:border-slate-700 dark:bg-slate-700">
|
||||
<div className="absolute right-10">
|
||||
<input
|
||||
id={`${element.id}-${option.value}`}
|
||||
aria-describedby={`${element.id}-${option.value}-description`}
|
||||
type="checkbox"
|
||||
value={option.value}
|
||||
className="text-brand focus:ring-brand border-brand h-5 w-5 rounded border-2 bg-slate-50"
|
||||
{...register(element.name!)}
|
||||
/>
|
||||
</div>
|
||||
<div className="h-12 w-12">
|
||||
{option.frontend?.icon && <option.frontend.icon className="text-brand h-10 w-10" />}
|
||||
</div>
|
||||
<span className="text-md mt-3 mb-1 font-bold text-slate-700 dark:text-slate-200">
|
||||
{option.label}
|
||||
</span>
|
||||
<p
|
||||
id={`${element.id}-${option.value}-description`}
|
||||
className="mt-1 text-xs text-slate-600 dark:text-slate-400">
|
||||
{option.frontend.description}
|
||||
</p>
|
||||
</div>
|
||||
</label>
|
||||
))}
|
||||
</div>
|
||||
</fieldset>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
import { RadioGroup } from "@headlessui/react";
|
||||
import { CheckCircleIcon } from "@heroicons/react/20/solid";
|
||||
import clsx from "clsx";
|
||||
import { useEffect, useState } from "react";
|
||||
import { Controller, useForm, useWatch } from "react-hook-form";
|
||||
import { SurveyElement } from "./engineTypes";
|
||||
|
||||
interface IconRadioProps {
|
||||
element: SurveyElement;
|
||||
field: any;
|
||||
control: any;
|
||||
onSubmit: () => void;
|
||||
disabled: boolean;
|
||||
}
|
||||
|
||||
export default function IconRadio({ element, control, onSubmit, disabled }: IconRadioProps) {
|
||||
const value = useWatch({
|
||||
control,
|
||||
name: element.name!!,
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
if (value && !disabled) {
|
||||
onSubmit();
|
||||
}
|
||||
}, [value, onSubmit, disabled]);
|
||||
|
||||
return (
|
||||
<Controller
|
||||
name={element.name!}
|
||||
control={control}
|
||||
rules={{ required: true }}
|
||||
render={({ field }: { field: any }) => (
|
||||
<RadioGroup className="flex flex-col justify-center" {...field}>
|
||||
<RadioGroup.Label className="pb-6 text-center text-lg font-bold text-slate-600 dark:text-slate-300 sm:text-xl md:text-2xl">
|
||||
{element.label}
|
||||
</RadioGroup.Label>
|
||||
|
||||
<div
|
||||
className={clsx(
|
||||
element.options && element.options.length >= 4
|
||||
? "lg:grid-cols-4"
|
||||
: element.options?.length === 3
|
||||
? "lg:grid-cols-3"
|
||||
: element.options?.length === 2
|
||||
? "lg:grid-cols-2"
|
||||
: "lg:grid-cols-1",
|
||||
"mt-4 grid w-full gap-y-6 sm:gap-x-4"
|
||||
)}>
|
||||
{element.options &&
|
||||
element.options.map((option) => (
|
||||
<RadioGroup.Option
|
||||
key={option.value}
|
||||
value={option.value}
|
||||
className={({ checked, active }) =>
|
||||
clsx(
|
||||
checked ? "border-transparent" : "border-slate-200 dark:border-slate-700",
|
||||
active ? "border-brand ring-brand ring-2" : "",
|
||||
"relative flex cursor-pointer rounded-lg border bg-white py-8 shadow-sm transition-all ease-in-out hover:scale-105 focus:outline-none dark:bg-slate-700"
|
||||
)
|
||||
}>
|
||||
{({ checked, active }) => (
|
||||
<>
|
||||
<div className="flex flex-1 flex-col justify-center text-slate-500 hover:text-slate-700 dark:text-slate-400 hover:dark:text-slate-200">
|
||||
{option.frontend?.icon && (
|
||||
<option.frontend.icon
|
||||
className="text-brand mx-auto mb-3 h-8 w-8"
|
||||
aria-hidden="true"
|
||||
/>
|
||||
)}
|
||||
<RadioGroup.Label as="span" className="mx-auto text-sm font-medium ">
|
||||
{option.label}
|
||||
</RadioGroup.Label>
|
||||
</div>
|
||||
|
||||
<CheckCircleIcon
|
||||
className={clsx(
|
||||
!checked ? "invisible" : "",
|
||||
"text-brand absolute -right-2 -top-2 z-10 h-5 w-5 rounded-full bg-white"
|
||||
)}
|
||||
aria-hidden="true"
|
||||
/>
|
||||
<span
|
||||
className={clsx(
|
||||
active ? "border" : "border-2",
|
||||
checked ? "border-brand" : "border-transparent",
|
||||
"pointer-events-none absolute -inset-px rounded-lg"
|
||||
)}
|
||||
aria-hidden="true"
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
</RadioGroup.Option>
|
||||
))}
|
||||
</div>
|
||||
</RadioGroup>
|
||||
)}
|
||||
/>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
import { SurveyElement } from "./engineTypes";
|
||||
|
||||
interface TextareaProps {
|
||||
element: SurveyElement;
|
||||
field: any;
|
||||
register: any;
|
||||
disabled: boolean;
|
||||
onSubmit: () => void;
|
||||
}
|
||||
|
||||
export default function Input({ element, field, register, disabled, onSubmit }: TextareaProps) {
|
||||
return (
|
||||
<div className="flex flex-col justify-center">
|
||||
<label
|
||||
htmlFor={element.id}
|
||||
className="pb-6 text-center text-lg font-bold text-slate-600 dark:text-slate-300 sm:text-xl md:text-2xl">
|
||||
{element.label}
|
||||
</label>
|
||||
<input
|
||||
type={element.frontend?.type || "text"}
|
||||
onBlur=""
|
||||
className="focus:border-brand focus:ring-brand mx-auto mt-4 block w-full max-w-xl rounded-md border-gray-300 shadow-sm sm:text-sm"
|
||||
placeholder={element.frontend?.placeholder || ""}
|
||||
required={!!element.frontend?.required}
|
||||
{...register(element.name!)}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
export default function Progressbar({ progress }: { progress: number }) {
|
||||
return (
|
||||
<div className="h-1.5 w-full rounded-full bg-gray-200 dark:bg-gray-700">
|
||||
<div
|
||||
className="h-1.5 rounded-full bg-slate-700 dark:bg-slate-300"
|
||||
style={{ width: `${Math.floor(progress * 100)}%` }}></div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
import { RadioGroup } from "@headlessui/react";
|
||||
import { CheckCircleIcon } from "@heroicons/react/20/solid";
|
||||
import clsx from "clsx";
|
||||
import { useEffect, useState } from "react";
|
||||
import { Controller, useForm, useWatch } from "react-hook-form";
|
||||
import { SurveyElement } from "./engineTypes";
|
||||
|
||||
interface IconRadioProps {
|
||||
element: SurveyElement;
|
||||
field: any;
|
||||
control: any;
|
||||
onSubmit: () => void;
|
||||
disabled: boolean;
|
||||
}
|
||||
|
||||
export default function Scale({ element, control, onSubmit, disabled }: IconRadioProps) {
|
||||
const value = useWatch({
|
||||
control,
|
||||
name: element.name!!,
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
if (value && !disabled) {
|
||||
onSubmit();
|
||||
}
|
||||
}, [value, onSubmit, disabled]);
|
||||
return (
|
||||
<Controller
|
||||
name={element.name!}
|
||||
control={control}
|
||||
rules={{ required: true }}
|
||||
render={({ field }: { field: any }) => (
|
||||
<RadioGroup className="flex flex-col justify-center" {...field}>
|
||||
<RadioGroup.Label className="pb-6 text-center text-lg font-bold text-slate-600 dark:text-slate-300 sm:text-xl md:text-2xl">
|
||||
{element.label}
|
||||
</RadioGroup.Label>
|
||||
<div
|
||||
className={clsx(
|
||||
element.frontend.max &&
|
||||
element.frontend.min &&
|
||||
element.frontend.max - element.frontend.min + 1 >= 11
|
||||
? "lg:grid-cols-11"
|
||||
: element.frontend.max - element.frontend.min + 1 === 10
|
||||
? "lg:grid-cols-10"
|
||||
: element.frontend.max - element.frontend.min + 1 === 9
|
||||
? "lg:grid-cols-9"
|
||||
: element.frontend.max - element.frontend.min + 1 === 8
|
||||
? "lg:grid-cols-8"
|
||||
: element.frontend.max - element.frontend.min + 1 === 7
|
||||
? "lg:grid-cols-7"
|
||||
: element.frontend.max - element.frontend.min + 1 === 6
|
||||
? "lg:grid-cols-6"
|
||||
: element.frontend.max - element.frontend.min + 1 === 5
|
||||
? "lg:grid-cols-5"
|
||||
: element.frontend.max - element.frontend.min + 1 === 4
|
||||
? "lg:grid-cols-4"
|
||||
: element.frontend.max - element.frontend.min + 1 === 3
|
||||
? "lg:grid-cols-3"
|
||||
: element.frontend.max - element.frontend.min + 1 === 2
|
||||
? "lg:grid-cols-2"
|
||||
: "lg:grid-cols-1",
|
||||
"mt-4 grid w-full gap-y-6 sm:gap-x-2"
|
||||
)}>
|
||||
{Array.from(
|
||||
{ length: element.frontend.max - element.frontend.min + 1 },
|
||||
(_, i) => i + element.frontend.min
|
||||
).map((num) => (
|
||||
<RadioGroup.Option
|
||||
key={num}
|
||||
value={num}
|
||||
className={({ checked, active }) =>
|
||||
clsx(
|
||||
checked ? "border-transparent" : "border-gray-200 dark:border-slate-700",
|
||||
active ? "border-brand ring-brand ring-2" : "",
|
||||
"relative flex cursor-pointer rounded-lg border bg-white p-4 shadow-sm transition-all ease-in-out hover:scale-105 focus:outline-none dark:bg-slate-700"
|
||||
)
|
||||
}>
|
||||
{({ checked, active }) => (
|
||||
<>
|
||||
<div className="flex flex-1 flex-col justify-center">
|
||||
<RadioGroup.Label
|
||||
as="span"
|
||||
className="mx-auto text-sm font-medium text-gray-900 dark:text-gray-200">
|
||||
{num}
|
||||
</RadioGroup.Label>
|
||||
</div>
|
||||
|
||||
<CheckCircleIcon
|
||||
className={clsx(
|
||||
!checked ? "invisible" : "",
|
||||
"text-brand absolute -right-2 -top-2 z-10 h-5 w-5 rounded-full bg-white"
|
||||
)}
|
||||
aria-hidden="true"
|
||||
/>
|
||||
<span
|
||||
className={clsx(
|
||||
active ? "border" : "border-2",
|
||||
checked ? "border-brand" : "border-transparent",
|
||||
"pointer-events-none absolute -inset-px rounded-lg"
|
||||
)}
|
||||
aria-hidden="true"
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
</RadioGroup.Option>
|
||||
))}
|
||||
</div>
|
||||
<div className="mt-2 flex justify-between text-sm text-gray-800">
|
||||
<p>{element.frontend.minLabel}</p>
|
||||
<p>{element.frontend.maxLabel}</p>
|
||||
</div>
|
||||
</RadioGroup>
|
||||
)}
|
||||
/>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
import { useEffect, useMemo, useState } from "react";
|
||||
import { Survey } from "./engineTypes";
|
||||
import Progressbar from "./Progressbar";
|
||||
import { SurveyPage } from "./SurveyPage";
|
||||
|
||||
interface SurveyProps {
|
||||
survey: Survey;
|
||||
formbricksUrl: string;
|
||||
formId: string;
|
||||
}
|
||||
|
||||
export function Survey({ survey, formbricksUrl, formId }: SurveyProps) {
|
||||
const [currentPage, setCurrentPage] = useState(survey.pages[0]);
|
||||
const [progress, setProgress] = useState(0);
|
||||
const [submission, setSubmission] = useState<any>({});
|
||||
const [finished, setFinished] = useState(false);
|
||||
|
||||
const schema = useMemo(() => generateSchema(survey), [survey]);
|
||||
|
||||
const onPageSubmit = (updatedSubmission: any) => {
|
||||
const nextPage = calculateNextPage(survey, updatedSubmission);
|
||||
setCurrentPage(nextPage);
|
||||
if (nextPage.endScreen) {
|
||||
setFinished(true);
|
||||
setProgress(1);
|
||||
} else {
|
||||
const nextPageIdx = survey.pages.findIndex((p) => p.id === nextPage.id);
|
||||
setProgress(nextPageIdx / survey.pages.length);
|
||||
}
|
||||
};
|
||||
|
||||
const calculateNextPage = (survey: Survey, submission: any) => {
|
||||
if (currentPage.branchingRules) {
|
||||
for (const rule of currentPage.branchingRules) {
|
||||
if (rule.type === "value") {
|
||||
if (rule.value === submission[rule.name]) {
|
||||
const nextPage = survey.pages.find((p) => p.id === rule.nextPageId);
|
||||
if (!nextPage) {
|
||||
throw new Error(`Next page ${rule.nextPageId} not found`);
|
||||
}
|
||||
return nextPage;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
const currentPageIdx = survey.pages.findIndex((p) => p.id === currentPage.id);
|
||||
return survey.pages[currentPageIdx + 1];
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="flex h-full w-full flex-col">
|
||||
{!(survey.config?.progressBar === false) && (
|
||||
<div className="mb-8 h-3">
|
||||
<Progressbar progress={progress} />
|
||||
</div>
|
||||
)}
|
||||
|
||||
<SurveyPage
|
||||
page={currentPage}
|
||||
onSubmit={onPageSubmit}
|
||||
submission={submission}
|
||||
setSubmission={setSubmission}
|
||||
finished={finished}
|
||||
formbricksUrl={formbricksUrl}
|
||||
formId={formId}
|
||||
schema={schema}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function generateSchema(survey: Survey) {
|
||||
const schema: any = JSON.parse(JSON.stringify(survey));
|
||||
deleteProps(schema, "frontend");
|
||||
return schema;
|
||||
}
|
||||
|
||||
function deleteProps(obj: any, propName: string) {
|
||||
if (Array.isArray(obj)) {
|
||||
for (let v of obj) {
|
||||
if (v instanceof Object) {
|
||||
deleteProps(v, propName);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
delete obj[propName];
|
||||
for (let v of Object.values(obj)) {
|
||||
if (v instanceof Object) {
|
||||
deleteProps(v, propName);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,123 @@
|
||||
import clsx from "clsx";
|
||||
import { useEffect, useRef, useState } from "react";
|
||||
import { Controller, useForm } from "react-hook-form";
|
||||
import Button from "../shared/Button";
|
||||
import { SurveyPage } from "./engineTypes";
|
||||
|
||||
interface SurveyProps {
|
||||
page: SurveyPage;
|
||||
onSubmit: (submission: any) => void;
|
||||
submission: any;
|
||||
setSubmission: (v: any) => void;
|
||||
finished: boolean;
|
||||
formbricksUrl: string;
|
||||
formId: string;
|
||||
schema: any;
|
||||
}
|
||||
|
||||
export function SurveyPage({
|
||||
page,
|
||||
onSubmit,
|
||||
submission,
|
||||
setSubmission,
|
||||
finished,
|
||||
formbricksUrl,
|
||||
formId,
|
||||
schema,
|
||||
}: SurveyProps) {
|
||||
const [submissionId, setSubmissionId] = useState<string>();
|
||||
const {
|
||||
handleSubmit,
|
||||
control,
|
||||
register,
|
||||
reset,
|
||||
formState: { errors },
|
||||
} = useForm();
|
||||
const [submittingPage, setSubmittingPage] = useState(false);
|
||||
const formRef = useRef<HTMLFormElement>(null);
|
||||
|
||||
useEffect(() => {
|
||||
reset();
|
||||
}, [page, reset]);
|
||||
|
||||
const sendToFormbricks = async (partialSubmission: any) => {
|
||||
if (!submissionId) {
|
||||
const res = await Promise.all([
|
||||
await fetch(`${formbricksUrl}/api/capture/forms/${formId}/submissions`, {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({ data: partialSubmission }),
|
||||
}),
|
||||
await fetch(`${formbricksUrl}/api/capture/forms/${formId}/schema`, {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify(schema),
|
||||
}),
|
||||
]);
|
||||
const submission = await res[0].json();
|
||||
setSubmissionId(submission.id);
|
||||
} else {
|
||||
await fetch(`${formbricksUrl}/api/capture/forms/${formId}/submissions/${submissionId}`, {
|
||||
method: "PUT",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({ data: partialSubmission }),
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const submitPage = async (data: any) => {
|
||||
setSubmittingPage(true);
|
||||
const updatedSubmission = { ...submission, ...data };
|
||||
setSubmission(updatedSubmission);
|
||||
try {
|
||||
await sendToFormbricks(data);
|
||||
setSubmittingPage(false);
|
||||
onSubmit(updatedSubmission);
|
||||
} catch (e) {
|
||||
alert("There was an error sending this form. Please try again later.");
|
||||
}
|
||||
};
|
||||
|
||||
const handleSubmitElement = () => {
|
||||
if (page.config?.autoSubmit && page.elements.length == 1) {
|
||||
formRef.current?.requestSubmit();
|
||||
setSubmittingPage(true);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<form onSubmit={handleSubmit(submitPage)} ref={formRef}>
|
||||
<div className="grid grid-cols-1 gap-8">
|
||||
{page.elements.map((element) => {
|
||||
const ElementComponent = element.component;
|
||||
return (
|
||||
<div key={element.id} className={clsx(submittingPage && "animate-pulse")}>
|
||||
{element.name ? (
|
||||
<ElementComponent
|
||||
element={element}
|
||||
control={control}
|
||||
register={register}
|
||||
onSubmit={() => handleSubmitElement()}
|
||||
disabled={submittingPage}
|
||||
/>
|
||||
) : (
|
||||
<ElementComponent element={element} />
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
{!finished && !(page.config?.autoSubmit && page.elements.length == 1) && (
|
||||
<div className="mx-auto mt-8 flex w-full max-w-xl justify-end">
|
||||
<Button
|
||||
variant="primary"
|
||||
type="submit"
|
||||
onClick={() => window.scrollTo(0, 0)}
|
||||
className="transition-all ease-in-out hover:scale-105">
|
||||
Next
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
</form>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
import { useEffect, useState } from "react";
|
||||
import { SurveyElement } from "./engineTypes";
|
||||
|
||||
interface TextareaProps {
|
||||
element: SurveyElement;
|
||||
register: any;
|
||||
onSubmit: () => void;
|
||||
}
|
||||
|
||||
export default function Textarea({ element, register, onSubmit }: TextareaProps) {
|
||||
return (
|
||||
<div className="flex flex-col justify-center">
|
||||
<label
|
||||
htmlFor={element.id}
|
||||
className="pb-6 text-center text-lg font-bold text-slate-600 dark:text-slate-300 sm:text-xl md:text-2xl">
|
||||
{element.label}
|
||||
</label>
|
||||
<textarea
|
||||
rows={element.frontend?.rows || 4}
|
||||
className="focus:border-brand focus:ring-brand mx-auto mt-4 block w-full max-w-xl rounded-md border-gray-300 shadow-sm sm:text-sm"
|
||||
placeholder={element.frontend?.placeholder || ""}
|
||||
required={!!element.frontend?.required}
|
||||
{...register(element.name!)}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
import { SurveyElement } from "./engineTypes";
|
||||
|
||||
export default function ThankYouHeading({ element }: { element: SurveyElement }) {
|
||||
return (
|
||||
<div className="text-center">
|
||||
<h2 className="mt-3 text-xl font-bold text-slate-700 dark:text-slate-100 sm:text-2xl md:text-3xl">
|
||||
We’re onboarding new users <span className="text-brand">regularly!</span>
|
||||
</h2>
|
||||
<p className="mt-4 text-slate-500 dark:text-slate-300">
|
||||
Thank you for signing up. We will be in touch shortly.
|
||||
</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
import Button from "../shared/Button";
|
||||
import { SurveyElement } from "./engineTypes";
|
||||
import { useRouter } from "next/router";
|
||||
|
||||
export default function ThankYouPlans({ element }: { element: SurveyElement }) {
|
||||
const router = useRouter();
|
||||
return (
|
||||
<div className="mx-auto grid max-w-3xl grid-cols-1 gap-4 xl:grid-cols-2">
|
||||
<div className="rounded-lg p-6">
|
||||
<div className="flex justify-between text-xl sm:text-2xl">
|
||||
<h3 className="font-bold text-slate-500 dark:text-slate-100">Free Plan</h3>
|
||||
<p className="text-slate-700 dark:text-slate-100">$0</p>
|
||||
</div>
|
||||
<ul className="mt-4 list-inside list-disc text-xs text-slate-500 dark:text-slate-300">
|
||||
<li>100 submissions / month</li>
|
||||
<li>Community support</li>
|
||||
<li>Waitlist</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div className="rounded-lg bg-slate-50 p-6 dark:bg-slate-700">
|
||||
<div className="flex justify-between text-xl sm:text-2xl">
|
||||
<h3 className="font-bold text-slate-500 dark:text-slate-100">Early Bird Plan</h3>
|
||||
<p className="text-slate-700 dark:text-slate-100">
|
||||
$49 <span className="line-through">$99</span>
|
||||
</p>
|
||||
</div>
|
||||
<p className="flex justify-end text-xs text-slate-500 dark:text-slate-300">/ Month</p>
|
||||
<ul className="mt-4 list-inside list-disc text-xs text-slate-500 dark:text-slate-300">
|
||||
<li>Unlimited submissions</li>
|
||||
<li>Founder onboarding</li>
|
||||
<li>Own support channel</li>
|
||||
<li className="font-bold">Skip waitlist</li>
|
||||
</ul>
|
||||
<div className="mt-5 flex flex-row justify-end">
|
||||
<Button
|
||||
type="button"
|
||||
target="_blank"
|
||||
onClick={() => router.push("https://buy.stripe.com/28o00R4GDf9qdfa5kp")}>
|
||||
Become Early Bird
|
||||
</Button>
|
||||
</div>
|
||||
<div className="mt-2 flex flex-row justify-end">
|
||||
<p className="text-xs text-slate-400 dark:text-slate-300">Cancel anytime</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
export interface SurveyOption {
|
||||
label: string;
|
||||
value: string;
|
||||
frontend?: any;
|
||||
}
|
||||
|
||||
export interface SurveyPage {
|
||||
id: string;
|
||||
endScreen?: boolean;
|
||||
elements: SurveyElement[];
|
||||
config?: {
|
||||
autoSubmit: boolean;
|
||||
};
|
||||
branchingRules?: {
|
||||
type: "value";
|
||||
name: string;
|
||||
value: string;
|
||||
nextPageId: string;
|
||||
}[];
|
||||
}
|
||||
|
||||
export interface SurveyElement {
|
||||
id: string;
|
||||
name?: string;
|
||||
label?: string;
|
||||
type: "radio" | "text" | "checkbox" | "html";
|
||||
options?: SurveyOption[];
|
||||
component: React.FC<any>;
|
||||
frontend?: any;
|
||||
}
|
||||
|
||||
export interface Survey {
|
||||
pages: SurveyPage[];
|
||||
config?: {
|
||||
progressBar?: boolean;
|
||||
};
|
||||
}
|
||||
@@ -1,54 +1,26 @@
|
||||
import {
|
||||
PlusIcon,
|
||||
SquaresPlusIcon,
|
||||
ChartBarIcon,
|
||||
ArrowTrendingUpIcon,
|
||||
DocumentPlusIcon,
|
||||
RectangleGroupIcon,
|
||||
} from "@heroicons/react/24/outline";
|
||||
import { PlusIcon, SquaresPlusIcon, ChartBarIcon } from "@heroicons/react/24/outline";
|
||||
import clsx from "clsx";
|
||||
import HeadingCentered from "../shared/HeadingCentered";
|
||||
|
||||
const features = [
|
||||
{
|
||||
id: "formCreation",
|
||||
name: "Fast Survey Creation",
|
||||
description: "Build complex forms with our React Lib. Use templates to assure consistent data.",
|
||||
id: "devAttention",
|
||||
name: "Minimal Dev Attention",
|
||||
description: "All you want is building your product. Set it up once, keep insights flowing in..",
|
||||
icon: PlusIcon,
|
||||
},
|
||||
{
|
||||
id: "dataPipelines",
|
||||
name: "Data Pipelines",
|
||||
description: "Save your data where you need it. Use webhooks or pre-built integrations.",
|
||||
id: "nativeLookFeel",
|
||||
name: "Native Look & Feel",
|
||||
description: "No more UX clutter. Use headless forms or highly customizabale UI components.",
|
||||
icon: SquaresPlusIcon,
|
||||
},
|
||||
{
|
||||
id: "dataInsights",
|
||||
name: "Powerful Data Insights",
|
||||
description: "View and manage your results quicker. Handle submissions in our dahsboard.",
|
||||
id: "openSourcer",
|
||||
name: "Open Source",
|
||||
description: "Own your data. Run Formbricks on your servers and comply with all regulation.",
|
||||
icon: ChartBarIcon,
|
||||
},
|
||||
{
|
||||
id: "nocodeBuilder",
|
||||
name: "100% customizable",
|
||||
description: "Delight your users and get more responses with a native look & feel.",
|
||||
icon: RectangleGroupIcon,
|
||||
comingSoon: true,
|
||||
},
|
||||
{
|
||||
id: "analytics",
|
||||
name: "Built-in Analytics",
|
||||
description: "Opening rate, drop-offs, conversions. Use privacy-first analytics out of the box.",
|
||||
icon: ArrowTrendingUpIcon,
|
||||
comingSoon: true,
|
||||
},
|
||||
{
|
||||
id: "templates",
|
||||
name: "Survey Templates",
|
||||
description: "NPS, CSAT, Employee Surveys. Name your business objective, we have the questions.",
|
||||
icon: DocumentPlusIcon,
|
||||
comingSoon: true,
|
||||
},
|
||||
];
|
||||
export default function Features() {
|
||||
return (
|
||||
@@ -59,30 +31,19 @@ export default function Features() {
|
||||
<div className="relative mx-auto max-w-7xl">
|
||||
<HeadingCentered
|
||||
closer
|
||||
teaser="the Swiss army knife for forms & surveys"
|
||||
heading="Build native surveys in minutes"
|
||||
subheading="Build a 'home-cooked' solution in a fraction of the time. We do the heavy lifting, you customize
|
||||
to your needs."
|
||||
teaser="Built for Product-minded founders"
|
||||
heading="Hack you way to Product-Market Fit"
|
||||
subheading="We redesigned experience management for SaaS founding teams:
|
||||
Developer-first, native look & feel, private at heart."
|
||||
/>
|
||||
|
||||
<ul role="list" className="grid grid-cols-1 gap-6 pt-8 sm:grid-cols-2 md:grid-cols-3">
|
||||
<ul role="list" className="grid grid-cols-1 gap-4 pt-8 sm:grid-cols-2 md:grid-cols-3 lg:gap-10">
|
||||
{features.map((feature) => (
|
||||
<li
|
||||
key={feature.id}
|
||||
className={clsx(
|
||||
feature.comingSoon
|
||||
? "bg-gradient-to-b from-slate-200 to-slate-100 dark:from-slate-800 dark:to-slate-900"
|
||||
: "bg-slate-200 drop-shadow-sm dark:bg-slate-800 ",
|
||||
"relative col-span-1 mt-16 flex flex-col rounded-xl text-center"
|
||||
)}>
|
||||
className="relative col-span-1 mt-16 flex flex-col rounded-xl bg-slate-100 text-center dark:bg-slate-700">
|
||||
<div className="absolute -mt-12 w-full">
|
||||
<div
|
||||
className={clsx(
|
||||
feature.comingSoon
|
||||
? "from-slate-100 via-slate-200 to-slate-200 dark:from-slate-800 dark:to-slate-900"
|
||||
: "from-slate-200 via-slate-100 to-slate-100 dark:from-slate-900 dark:to-slate-700 ",
|
||||
"mx-auto flex h-20 w-20 items-center justify-center rounded-full bg-gradient-to-br shadow"
|
||||
)}>
|
||||
<div className="mx-auto flex h-20 w-20 items-center justify-center rounded-3xl bg-slate-200 shadow dark:bg-slate-800">
|
||||
<feature.icon className="text-brand-dark dark:text-brand-light mx-auto h-10 w-10 flex-shrink-0" />
|
||||
</div>
|
||||
</div>
|
||||
@@ -93,13 +54,6 @@ export default function Features() {
|
||||
<dl className="mt-1 flex flex-grow flex-col justify-between">
|
||||
<dt className="sr-only">Description</dt>
|
||||
<dd className="text-sm text-gray-600 dark:text-slate-400">{feature.description}</dd>
|
||||
{feature.comingSoon && (
|
||||
<dd className="mt-4">
|
||||
<span className="rounded-full bg-slate-200 px-3 py-1 text-xs font-medium text-slate-500 dark:bg-slate-700 dark:text-slate-300">
|
||||
coming soon
|
||||
</span>
|
||||
</dd>
|
||||
)}
|
||||
</dl>
|
||||
</div>
|
||||
</li>
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import Button from "../shared/Button";
|
||||
import HeroAnimation from "../shared/HeroAnimation";
|
||||
import HeroTitle from "../shared/HeroTitle";
|
||||
import { useRouter } from "next/router";
|
||||
|
||||
interface Props {}
|
||||
@@ -9,19 +8,33 @@ export default function Hero({}: Props) {
|
||||
const router = useRouter();
|
||||
return (
|
||||
<div className="relative">
|
||||
<HeroTitle
|
||||
headingPt1="The"
|
||||
headingTeal="Open Source"
|
||||
headingPt2="Form & Survey Toolbox"
|
||||
subheading="Bring all qualitative user data on one open source platform. Modular, customizable,
|
||||
extendable.">
|
||||
<Button variant="secondary" onClick={() => router.push("/docs")}>
|
||||
Read docs
|
||||
</Button>
|
||||
<Button variant="primary" className="ml-3" onClick={() => router.push("/get-started")}>
|
||||
Get started
|
||||
</Button>
|
||||
</HeroTitle>
|
||||
<div className="px-4 py-20 text-center sm:px-6 lg:px-8 lg:py-28">
|
||||
<h1 className="text-3xl font-bold tracking-tight text-slate-800 dark:text-slate-200 sm:text-4xl md:text-5xl">
|
||||
<span className="xl:inline">Build</span>{" "}
|
||||
<span className="from-brand-light to-brand-dark bg-gradient-to-b bg-clip-text text-transparent xl:inline">
|
||||
user research
|
||||
</span>{" "}
|
||||
<span className="inline ">into your product</span>
|
||||
</h1>
|
||||
|
||||
<p className="xs:max-w-none mx-auto mt-3 max-w-xs text-base text-slate-500 dark:text-slate-300 sm:text-lg md:mt-5 md:text-xl">
|
||||
Natively embed qualitative user research into your B2B SaaS.
|
||||
<br />
|
||||
<span className="hidden md:block">
|
||||
Leverage Best Practices for user discovery to increase Product-Market Fit.
|
||||
</span>
|
||||
</p>
|
||||
|
||||
<div className="mx-auto mt-5 max-w-md sm:flex sm:justify-center md:mt-8">
|
||||
<Button variant="secondary" onClick={() => router.push("#best-practices")}>
|
||||
Best practices
|
||||
</Button>
|
||||
<Button variant="primary" className="ml-3" onClick={() => router.push("/waitlist")}>
|
||||
Get Access
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<HeroAnimation />
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -1,62 +1,103 @@
|
||||
import Image from "next/image";
|
||||
import ImageReactLib from "@/images/react-lib.png";
|
||||
import ImageDataPipelines from "@/images/data-pipelines.png";
|
||||
import Link from "next/link";
|
||||
import Button from "../shared/Button";
|
||||
import { useRouter } from "next/router";
|
||||
import ImageAnalytics from "@/images/connect-analytics.png";
|
||||
import ImageInsights from "@/images/insights.png";
|
||||
import ImageDarkAnalytics from "@/images/dark-connect-analytics.png";
|
||||
import ImageDarkInsights from "@/images/dark-insights.png";
|
||||
|
||||
const userBase = [
|
||||
{
|
||||
email: "anna@open.com",
|
||||
status: "Signed Up",
|
||||
},
|
||||
{
|
||||
email: "tim@yama.com",
|
||||
status: "Activated",
|
||||
},
|
||||
{
|
||||
email: "beth@lehem.com",
|
||||
status: "Customer",
|
||||
},
|
||||
{
|
||||
email: "pied@piper.com",
|
||||
status: "Customer",
|
||||
},
|
||||
{
|
||||
email: "janice@late.com",
|
||||
status: "Churned",
|
||||
},
|
||||
];
|
||||
|
||||
export default function Highlights({}) {
|
||||
const router = useRouter();
|
||||
return (
|
||||
<>
|
||||
<div className="mt-8 md:mt-32">
|
||||
<div className="mx-auto max-w-md px-4 sm:max-w-3xl sm:px-6 lg:max-w-7xl lg:px-8">
|
||||
<div className="grid lg:grid-cols-2 lg:items-center lg:gap-24">
|
||||
<div className="order-last lg:order-first">
|
||||
<h2 className="text-2xl font-bold tracking-tight text-slate-800 dark:text-slate-200 sm:text-3xl">
|
||||
Build forms in minutes with our{" "}
|
||||
<span className="text-brand-dark dark:text-brand-light font-light">lightweight</span> React
|
||||
Form Builder.
|
||||
<div className="mx-auto mt-8 mb-12 max-w-lg md:mt-32 md:mb-0 md:max-w-none">
|
||||
<div className="px-4 sm:max-w-4xl sm:px-6 lg:max-w-7xl lg:px-8">
|
||||
<div className="grid md:grid-cols-2 md:items-center md:gap-16">
|
||||
<div className="pb-8 md:pb-0">
|
||||
<h2 className="xs:text-3xl text-2xl font-bold tracking-tight text-slate-800 dark:text-slate-200">
|
||||
Connect product analytics,
|
||||
<br />
|
||||
<span className="font-light">ask specific user cohorts.</span>
|
||||
</h2>
|
||||
<p className="text-md mt-6 max-w-3xl leading-7 text-slate-500 dark:text-slate-400">
|
||||
Loads of question types, validation, multi-page forms, logic jumps, i18n, custom styles - all
|
||||
the good stuff you want, but don't want to build yourself.
|
||||
<br />
|
||||
<br />
|
||||
Build <span className="font-semibold">exactly</span> the form you want in a fraction of the
|
||||
time.
|
||||
Email is spammy and ineffective. Create cohorts based on usage data and reach out to specific
|
||||
cohorts in-app.
|
||||
</p>
|
||||
<div className="my-6">
|
||||
<Button variant="minimal" size="sm" onClick={() => router.push("/react-form-library")}>
|
||||
Read more
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
<Image src={ImageReactLib} alt="react library" className="mb-8 rounded-lg lg:mb-0" />
|
||||
<div className="rounded-lg bg-slate-100 p-4 dark:bg-slate-800 sm:p-8">
|
||||
<Image src={ImageAnalytics} alt="react library" className="block rounded-lg dark:hidden" />
|
||||
<Image src={ImageDarkAnalytics} alt="react library" className="hidden rounded-lg dark:block" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="mt-16 md:mt-32">
|
||||
<div className="mx-auto max-w-md px-4 sm:max-w-3xl sm:px-6 lg:max-w-7xl lg:px-8">
|
||||
<div className="lg:grid lg:grid-cols-2 lg:items-center lg:gap-24">
|
||||
<Image src={ImageDataPipelines} alt="react library" className="mb-8 rounded-lg lg:mb-0" />
|
||||
<div>
|
||||
<h2 className="text-2xl font-bold tracking-tight text-slate-800 dark:text-slate-100 sm:text-3xl">
|
||||
<span className="text-brand-dark dark:text-brand-light ">API</span> all the way
|
||||
<div className="mx-auto mt-8 mb-12 max-w-lg md:mt-32 md:mb-0 md:max-w-none">
|
||||
<div className="px-4 sm:max-w-4xl sm:px-6 lg:max-w-7xl lg:px-8">
|
||||
<div className="grid md:grid-cols-2 md:items-center md:gap-16">
|
||||
<div className="order-last rounded-lg bg-slate-100 p-4 dark:bg-slate-800 sm:p-8 md:order-first">
|
||||
<Image src={ImageInsights} alt="react library" className="block rounded-lg dark:hidden" />
|
||||
<Image src={ImageDarkInsights} alt="react library" className="hidden rounded-lg dark:block" />
|
||||
</div>
|
||||
<div className="pb-8 md:pb-0">
|
||||
<h2 className="xs:text-3xl text-2xl font-bold tracking-tight text-slate-800 dark:text-slate-100 sm:text-3xl">
|
||||
Fill the gaps between
|
||||
<br />
|
||||
<span className="font-light">analytics and interviews.</span>
|
||||
</h2>
|
||||
<p className="text-md mt-6 max-w-3xl leading-7 text-slate-500 dark:text-slate-400">
|
||||
Your form looks perfect? Time to build integrations...
|
||||
<br />
|
||||
<br />
|
||||
<span className="font-semibold">Or use our prebuilt data pipelines.</span> Pipe submissions
|
||||
right into your database. Set up webhooks, email notifications and 3rd party integrations in
|
||||
our webUI.
|
||||
Product analytics don’t tell a story, people do. Complement user interviews with a constant
|
||||
flow of qualitative user insights.
|
||||
</p>
|
||||
<div className="mt-6">
|
||||
<Button variant="minimal" size="sm" onClick={() => router.push("/core-api")}>
|
||||
Read more
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="mx-auto mt-8 mb-12 max-w-lg md:mt-32 md:mb-0 md:max-w-none">
|
||||
<div className="px-4 sm:max-w-4xl sm:px-6 lg:max-w-7xl lg:px-8">
|
||||
<div className="grid md:grid-cols-2 md:items-center md:gap-16">
|
||||
<div className="pb-8 md:pb-0">
|
||||
<h2 className="xs:text-3xl text-2xl font-bold tracking-tight text-slate-800 dark:text-slate-200 sm:text-3xl">
|
||||
From sign up to paid plan:
|
||||
<br />
|
||||
<span className="font-light">Never ask something twice.</span>
|
||||
</h2>
|
||||
<p className="text-md mt-6 max-w-3xl leading-7 text-slate-500 dark:text-slate-400">
|
||||
With Formbricks you build a database of everyone who signs up to your product. Enrich their
|
||||
profile at key moments in the user journey.
|
||||
</p>
|
||||
</div>
|
||||
<div className="w-full rounded-lg bg-slate-100 p-8 dark:bg-slate-800">
|
||||
{userBase.map((user) => (
|
||||
<div className="my-2 flex w-full justify-between rounded-lg bg-slate-50 py-2 px-4 text-slate-700 transition-all duration-75 ease-in-out hover:scale-105 dark:bg-slate-700 dark:text-slate-300">
|
||||
{user.email}
|
||||
<p className="xs:max-md:block hidden rounded-full bg-slate-200 px-3 text-sm dark:bg-slate-600 lg:block ">
|
||||
{user.status}
|
||||
</p>
|
||||
<a href={"mailto:" + user.email} className="text-brand font-semibold">
|
||||
Reach Out
|
||||
</a>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -20,7 +20,7 @@ export default function CTA() {
|
||||
<div className="rounded-xl bg-gradient-to-br from-slate-400 to-slate-300 py-24 text-center text-gray-800 dark:from-slate-800 dark:to-slate-700 dark:text-gray-100">
|
||||
<h3 className="text-3xl font-bold">Cloud</h3>
|
||||
<p className="mt-2 mb-4">Use our free managed service.</p>
|
||||
<Button variant="secondary" onClick={() => router.push("/get-started")} className="mt-3" disabled>
|
||||
<Button variant="secondary" onClick={() => router.push("/waitlist")} className="mt-3" disabled>
|
||||
Coming soon
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
@@ -3,7 +3,7 @@ import clsx from "clsx";
|
||||
import { FooterLogo } from "./Logo";
|
||||
|
||||
const navigation = {
|
||||
creation: [
|
||||
/* creation: [
|
||||
{ name: "React Form Builder", href: "/react-form-library", status: true },
|
||||
{ name: "No Code Builder", href: "/visual-builder", status: false },
|
||||
{ name: "Templates", href: "#", status: false },
|
||||
@@ -17,10 +17,9 @@ const navigation = {
|
||||
insights: [
|
||||
{ name: "Formbricks HQ", href: "/formbricks-hq", status: true },
|
||||
{ name: "Reports", href: "#", status: false },
|
||||
],
|
||||
], */
|
||||
other: [
|
||||
{ name: "Community", href: "/community", status: true },
|
||||
{ name: "Docs", href: "/docs", status: true },
|
||||
{ name: "Blog", href: "/blog", status: true },
|
||||
{ name: "GDPR FAQ", href: "/gdpr", status: true },
|
||||
{ name: "GDPR Guide", href: "/gdpr-guide", status: true },
|
||||
@@ -54,120 +53,30 @@ const navigation = {
|
||||
export default function Footer() {
|
||||
return (
|
||||
<footer
|
||||
className="bg-gradient-to-b from-slate-100 to-slate-300 dark:from-slate-900 dark:to-slate-800"
|
||||
className="mt-32 bg-gradient-to-b from-slate-50 to-slate-200 dark:from-slate-900 dark:to-slate-800"
|
||||
aria-labelledby="footer-heading">
|
||||
<h2 id="footer-heading" className="sr-only">
|
||||
Footer
|
||||
</h2>
|
||||
<div className="mx-auto max-w-7xl px-4 py-12 sm:px-6 lg:py-16 lg:px-8">
|
||||
<div className="xl:grid xl:grid-cols-3 xl:gap-8">
|
||||
<div className="space-y-8 xl:col-span-1">
|
||||
<FooterLogo className="h-8 w-auto sm:h-10" />
|
||||
<p className="text-base text-slate-500 dark:text-slate-400">The Open Source Survey Toolbox</p>
|
||||
<div className="flex space-x-6">
|
||||
{navigation.social.map((item) => (
|
||||
<Link key={item.name} href={item.href} className="text-slate-400 hover:text-gray-500">
|
||||
<span className="sr-only">{item.name}</span>
|
||||
<item.icon className="h-6 w-6" aria-hidden="true" />
|
||||
</Link>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
<div className="mt-12 grid grid-cols-2 gap-8 xl:col-span-2 xl:mt-0">
|
||||
<div className="md:grid md:grid-cols-2 md:gap-8">
|
||||
<div>
|
||||
<h3 className="text-sm font-bold text-slate-700 dark:text-slate-300">Survey Creation</h3>
|
||||
<ul role="list" className="mt-4 space-y-4">
|
||||
{navigation.creation.map((item) => (
|
||||
<li key={item.name}>
|
||||
<Link
|
||||
href={item.href}
|
||||
scroll={item.status}
|
||||
className={clsx(
|
||||
item.status
|
||||
? "cursor-pointer text-slate-600 hover:text-slate-500 dark:text-slate-400 dark:hover:text-slate-300"
|
||||
: "cursor-default text-slate-400 dark:text-slate-600",
|
||||
"text-base"
|
||||
)}>
|
||||
{item.name}
|
||||
</Link>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
<div className="mt-12 md:mt-0">
|
||||
<h3 className="text-sm font-bold text-slate-700 dark:text-slate-300">Data Pipelines</h3>
|
||||
<ul role="list" className="mt-4 space-y-4">
|
||||
{navigation.pipelines.map((item) => (
|
||||
<li key={item.name}>
|
||||
<Link
|
||||
href={item.href}
|
||||
scroll={item.status}
|
||||
className={clsx(
|
||||
item.status
|
||||
? "cursor-pointer text-slate-600 hover:text-slate-500 dark:text-slate-400 dark:hover:text-slate-300"
|
||||
: "cursor-default text-slate-400 dark:text-slate-600",
|
||||
"text-base"
|
||||
)}>
|
||||
{item.name}
|
||||
</Link>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div className="md:grid md:grid-cols-2 md:gap-8">
|
||||
<div>
|
||||
<h3 className="text-sm font-bold text-slate-700 dark:text-slate-300">Data Insights</h3>
|
||||
<ul role="list" className="mt-4 space-y-4">
|
||||
{navigation.insights.map((item) => (
|
||||
<li key={item.name}>
|
||||
<Link
|
||||
href={item.href}
|
||||
scroll={item.status}
|
||||
className={clsx(
|
||||
item.status
|
||||
? "cursor-pointer text-slate-600 hover:text-slate-500 dark:text-slate-400 dark:hover:text-slate-300"
|
||||
: "cursor-default text-slate-400 dark:text-slate-600",
|
||||
"text-base"
|
||||
)}>
|
||||
{item.name}
|
||||
</Link>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
<div className="mt-12 md:mt-0">
|
||||
<h3 className="text-sm font-bold text-slate-700 dark:text-slate-300">Other</h3>
|
||||
<ul role="list" className="mt-4 space-y-4">
|
||||
{navigation.other.map((item) => (
|
||||
<li key={item.name}>
|
||||
<Link
|
||||
href={item.href}
|
||||
scroll={item.status}
|
||||
className={clsx(
|
||||
item.status
|
||||
? "cursor-pointer text-slate-600 hover:text-slate-500 dark:text-slate-400 dark:hover:text-slate-300"
|
||||
: "cursor-default text-slate-400 dark:text-slate-600",
|
||||
"text-base"
|
||||
)}>
|
||||
{item.name}
|
||||
</Link>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="mt-12 border-gray-500 pt-8">
|
||||
<p className="text-sm text-slate-400 dark:text-gray-500 xl:text-center">
|
||||
<div className="mx-auto flex max-w-7xl flex-col space-y-6 px-4 py-12 text-center sm:px-6 lg:py-16 lg:px-8">
|
||||
<FooterLogo className="mx-auto h-8 w-auto sm:h-10" />
|
||||
<p className="text-base text-slate-500 dark:text-slate-400">Experience Management for B2B SaaS</p>
|
||||
<div className="border-gray-500">
|
||||
<p className="text-sm text-slate-400 dark:text-gray-500">
|
||||
© 2022. All rights reserved.
|
||||
<br />
|
||||
<Link href="/imprint">Imprint</Link> | <Link href="/privacy">Privacy Policy</Link> |{" "}
|
||||
<Link href="/terms">Terms</Link>
|
||||
</p>
|
||||
</div>
|
||||
<div className="flex justify-center space-x-6">
|
||||
{navigation.social.map((item) => (
|
||||
<Link key={item.name} href={item.href} className="text-slate-400 hover:text-gray-500">
|
||||
<span className="sr-only">{item.name}</span>
|
||||
<item.icon className="h-6 w-6" aria-hidden="true" />
|
||||
</Link>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
);
|
||||
|
||||
@@ -1,19 +1,5 @@
|
||||
import { Popover, Transition } from "@headlessui/react";
|
||||
import { ChevronDownIcon } from "@heroicons/react/20/solid";
|
||||
import {
|
||||
Bars3Icon,
|
||||
BoltIcon,
|
||||
ClipboardDocumentListIcon,
|
||||
CodeBracketSquareIcon,
|
||||
CpuChipIcon,
|
||||
CursorArrowRaysIcon,
|
||||
CursorArrowRippleIcon,
|
||||
DocumentChartBarIcon,
|
||||
EnvelopeIcon,
|
||||
SquaresPlusIcon,
|
||||
XMarkIcon,
|
||||
} from "@heroicons/react/24/outline";
|
||||
import clsx from "clsx";
|
||||
import { Bars3Icon, XMarkIcon } from "@heroicons/react/24/outline";
|
||||
import Link from "next/link";
|
||||
import { useRouter } from "next/router";
|
||||
import { Fragment } from "react";
|
||||
@@ -21,86 +7,12 @@ import Button from "./Button";
|
||||
import { FooterLogo } from "./Logo";
|
||||
import { ThemeSelector } from "./ThemeSelector";
|
||||
|
||||
const creation = [
|
||||
{
|
||||
name: "React Library",
|
||||
description: "Build surveys with React.js",
|
||||
href: "/react-form-library",
|
||||
icon: CodeBracketSquareIcon,
|
||||
status: true,
|
||||
},
|
||||
{
|
||||
name: "No Code Builder",
|
||||
description: "Notion-like visual builder",
|
||||
href: "/visual-builder",
|
||||
icon: CursorArrowRaysIcon,
|
||||
status: false,
|
||||
},
|
||||
{
|
||||
name: "Templates",
|
||||
description: "CSAT, PMF survey, etc.",
|
||||
href: "#",
|
||||
icon: ClipboardDocumentListIcon,
|
||||
status: false,
|
||||
},
|
||||
];
|
||||
|
||||
const pipes = [
|
||||
{
|
||||
name: "Core API",
|
||||
description: "The OS survey engine",
|
||||
href: "/core-api",
|
||||
icon: CpuChipIcon,
|
||||
status: true,
|
||||
},
|
||||
{
|
||||
name: "Webhooks",
|
||||
description: "Send JSON anywhere",
|
||||
href: "/webhooks",
|
||||
icon: BoltIcon,
|
||||
status: true,
|
||||
},
|
||||
{
|
||||
name: "Email",
|
||||
description: "Send data and notifications",
|
||||
href: "/email",
|
||||
icon: EnvelopeIcon,
|
||||
status: true,
|
||||
},
|
||||
{
|
||||
name: "Integrations",
|
||||
description: "Connect with 100+ apps",
|
||||
href: "/integrations",
|
||||
icon: SquaresPlusIcon,
|
||||
status: false,
|
||||
},
|
||||
];
|
||||
|
||||
const insights = [
|
||||
{
|
||||
name: "Formbricks HQ",
|
||||
description: "Manage submissions easily",
|
||||
href: "/formbricks-hq",
|
||||
icon: CursorArrowRippleIcon,
|
||||
cat: "insights",
|
||||
status: true,
|
||||
},
|
||||
{
|
||||
name: "Reports",
|
||||
description: "Based on Templates",
|
||||
href: "#",
|
||||
icon: DocumentChartBarIcon,
|
||||
cat: "insights",
|
||||
status: false,
|
||||
},
|
||||
];
|
||||
|
||||
export default function Header() {
|
||||
const router = useRouter();
|
||||
return (
|
||||
<Popover className="relative" as="header">
|
||||
<div className="flex items-center justify-between px-4 py-6 sm:px-6 md:justify-start md:space-x-10">
|
||||
<div className="flex justify-start lg:w-0 lg:flex-1">
|
||||
<div className="flex items-center justify-between px-4 py-6 sm:px-6 md:justify-start ">
|
||||
<div className="flex w-0 flex-1 justify-start">
|
||||
<Link href="/">
|
||||
<span className="sr-only">Formbricks</span>
|
||||
<FooterLogo className="h-8 w-auto sm:h-10" />
|
||||
@@ -113,145 +25,6 @@ export default function Header() {
|
||||
</Popover.Button>
|
||||
</div>
|
||||
<Popover.Group as="nav" className="hidden space-x-10 md:flex">
|
||||
<Popover className="relative">
|
||||
{({ open }) => (
|
||||
<>
|
||||
<Popover.Button
|
||||
className={clsx(
|
||||
open ? "text-slate-700" : "text-slate-400",
|
||||
"group inline-flex items-center rounded-md text-base font-medium hover:text-slate-700 focus:outline-none focus:ring-2 focus:ring-teal-500 focus:ring-offset-2 dark:hover:text-slate-300"
|
||||
)}>
|
||||
<span>Bricks</span>
|
||||
<ChevronDownIcon className="ml-2 h-5 w-5" aria-hidden="true" />
|
||||
</Popover.Button>
|
||||
|
||||
<Transition
|
||||
as={Fragment}
|
||||
enter="transition ease-out duration-200"
|
||||
enterFrom="opacity-0 translate-y-1"
|
||||
enterTo="opacity-100 translate-y-0"
|
||||
leave="transition ease-in duration-150"
|
||||
leaveFrom="opacity-100 translate-y-0"
|
||||
leaveTo="opacity-0 translate-y-1">
|
||||
<Popover.Panel className="absolute z-10 mt-3 -ml-4 w-screen max-w-lg transform lg:left-1/2 lg:ml-0 lg:max-w-4xl lg:-translate-x-1/2">
|
||||
<div className="overflow-hidden rounded-lg shadow-lg ring-1 ring-black ring-opacity-5">
|
||||
<div className="relative grid gap-6 bg-slate-50 px-5 py-6 dark:bg-slate-700 sm:gap-6 sm:p-8 lg:grid-cols-3">
|
||||
<div>
|
||||
<h4 className="mb-6 ml-16 text-sm text-slate-400">Survey Creation</h4>
|
||||
{creation.map((brick) => (
|
||||
<Link
|
||||
key={brick.name}
|
||||
href={brick.href}
|
||||
className={clsx(
|
||||
brick.status
|
||||
? "cursor-pointer hover:bg-slate-100 dark:hover:bg-slate-600 dark:hover:bg-opacity-50"
|
||||
: "cursor-default",
|
||||
"-m-3 flex items-start rounded-lg p-3 py-4"
|
||||
)}>
|
||||
<div
|
||||
className={clsx(
|
||||
brick.status ? "text-brand-dark dark:text-brand-light" : "text-slate-500",
|
||||
"flex h-10 w-10 flex-shrink-0 items-center justify-center rounded-md sm:h-12 sm:w-12"
|
||||
)}>
|
||||
<brick.icon className="h-6 w-6" aria-hidden="true" />
|
||||
</div>
|
||||
<div className="ml-4">
|
||||
<p
|
||||
className={clsx(
|
||||
brick.status
|
||||
? "text-slate-800 dark:text-slate-50"
|
||||
: "text-slate-500 dark:text-slate-400",
|
||||
"text-lg font-semibold"
|
||||
)}>
|
||||
{brick.name}
|
||||
</p>
|
||||
<p className="text-sm text-slate-400 dark:text-slate-500">
|
||||
{brick.description}
|
||||
</p>
|
||||
</div>
|
||||
</Link>
|
||||
))}
|
||||
</div>
|
||||
<div>
|
||||
<h4 className="mb-6 ml-16 text-sm text-slate-400">Data Pipelines</h4>
|
||||
{pipes.map((brick) => (
|
||||
<Link
|
||||
key={brick.name}
|
||||
href={brick.href}
|
||||
className={clsx(
|
||||
brick.status
|
||||
? "cursor-pointer hover:bg-slate-100 dark:hover:bg-slate-600 dark:hover:bg-opacity-50"
|
||||
: "cursor-default",
|
||||
"-m-3 flex items-start rounded-lg p-3 py-4"
|
||||
)}>
|
||||
<div
|
||||
className={clsx(
|
||||
brick.status ? "text-brand-dark dark:text-brand-light" : "text-slate-500",
|
||||
"flex h-10 w-10 flex-shrink-0 items-center justify-center rounded-md sm:h-12 sm:w-12"
|
||||
)}>
|
||||
<brick.icon className="h-6 w-6" aria-hidden="true" />
|
||||
</div>
|
||||
<div className="ml-4">
|
||||
<p
|
||||
className={clsx(
|
||||
brick.status
|
||||
? "text-slate-800 dark:text-slate-50"
|
||||
: "text-slate-500 dark:text-slate-400",
|
||||
"text-lg font-semibold"
|
||||
)}>
|
||||
{brick.name}
|
||||
</p>
|
||||
<p className="text-sm text-slate-400 dark:text-slate-500">
|
||||
{brick.description}
|
||||
</p>
|
||||
</div>
|
||||
</Link>
|
||||
))}
|
||||
</div>
|
||||
<div>
|
||||
<h4 className="mb-6 ml-16 text-sm text-slate-400">Data Insights</h4>
|
||||
{insights.map((brick) => (
|
||||
<Link
|
||||
key={brick.name}
|
||||
href={brick.href}
|
||||
className={clsx(
|
||||
brick.status
|
||||
? "cursor-pointer hover:bg-slate-100 dark:hover:bg-slate-600 dark:hover:bg-opacity-50"
|
||||
: "cursor-default",
|
||||
"-m-3 flex items-start rounded-lg p-3 py-4"
|
||||
)}>
|
||||
<div
|
||||
className={clsx(
|
||||
brick.status ? "text-brand-dark dark:text-brand-light" : "text-slate-500",
|
||||
"flex h-10 w-10 flex-shrink-0 items-center justify-center rounded-md sm:h-12 sm:w-12"
|
||||
)}>
|
||||
<brick.icon className="h-6 w-6" aria-hidden="true" />
|
||||
</div>
|
||||
<div className="ml-4">
|
||||
<p
|
||||
className={clsx(
|
||||
brick.status
|
||||
? "text-slate-800 dark:text-slate-50"
|
||||
: "text-slate-500 dark:text-slate-400",
|
||||
"text-lg font-semibold"
|
||||
)}>
|
||||
{brick.name}
|
||||
</p>
|
||||
<p className="text-sm text-slate-400 dark:text-slate-500">
|
||||
{brick.description}
|
||||
</p>
|
||||
</div>
|
||||
</Link>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Popover.Panel>
|
||||
</Transition>
|
||||
</>
|
||||
)}
|
||||
</Popover>
|
||||
|
||||
<Link
|
||||
href="/community"
|
||||
className="text-base font-medium text-slate-400 hover:text-slate-700 dark:hover:text-slate-300">
|
||||
@@ -262,23 +35,11 @@ export default function Header() {
|
||||
className="text-base font-medium text-slate-400 hover:text-slate-700 dark:hover:text-slate-300">
|
||||
Blog <p className="bg-brand inline rounded-full px-2 text-xs text-white">1</p>
|
||||
</Link>
|
||||
<Link
|
||||
href="/docs"
|
||||
className="text-base font-medium text-slate-400 hover:text-slate-700 dark:hover:text-slate-300">
|
||||
Docs
|
||||
</Link>
|
||||
</Popover.Group>
|
||||
<div className="hidden items-center justify-end md:flex md:flex-1 lg:w-0">
|
||||
<div className="hidden flex-1 items-center justify-end md:flex">
|
||||
<ThemeSelector className="relative z-10 mr-5" />
|
||||
<Button
|
||||
variant="secondary"
|
||||
EndIcon={GitHubIcon}
|
||||
endIconClassName="fill-slate-800 dark:fill-slate-200"
|
||||
onClick={() => router.push("https://github.com/formbricks/formbricks")}>
|
||||
View on Github
|
||||
</Button>
|
||||
<Button variant="highlight" className="ml-2" onClick={() => router.push("/get-started")}>
|
||||
Get started
|
||||
<Button variant="highlight" className="ml-2" onClick={() => router.push("/waitlist")}>
|
||||
Get Access
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -307,139 +68,11 @@ export default function Header() {
|
||||
</Popover.Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<nav className="relative bg-gray-200 px-5 py-6 dark:bg-slate-800">
|
||||
<div>
|
||||
<h4 className="mb-3 text-sm text-gray-900 dark:text-gray-300">Survey Creation</h4>
|
||||
{creation.map((brick) => (
|
||||
<Link
|
||||
key={brick.name}
|
||||
href={brick.href}
|
||||
className={clsx(
|
||||
brick.status ? "cursor-pointer" : "cursor-default",
|
||||
"-m-3 flex items-start rounded-lg p-3 py-3"
|
||||
)}>
|
||||
<div
|
||||
className={clsx(
|
||||
brick.status ? "text-brand-dark dark:text-brand-light" : "text-slate-500",
|
||||
"flex h-10 w-10 flex-shrink-0 items-center justify-center rounded-md sm:h-12 sm:w-12"
|
||||
)}>
|
||||
<brick.icon className="h-6 w-6" aria-hidden="true" />
|
||||
</div>
|
||||
<div className="ml-4">
|
||||
<p
|
||||
className={clsx(
|
||||
brick.status
|
||||
? "text-gray-900 dark:text-gray-200"
|
||||
: "text-gray-400 dark:text-gray-500",
|
||||
"text-lg font-semibold"
|
||||
)}>
|
||||
{brick.name}
|
||||
</p>
|
||||
<p
|
||||
className={clsx(
|
||||
brick.status
|
||||
? "text-gray-900 dark:text-gray-400"
|
||||
: "text-gray-400 dark:text-gray-600",
|
||||
"text-sm"
|
||||
)}>
|
||||
{brick.description}
|
||||
</p>
|
||||
</div>
|
||||
</Link>
|
||||
))}
|
||||
</div>
|
||||
<div>
|
||||
<h4 className="mt-8 mb-3 text-sm text-gray-900 dark:text-gray-300">Data Pipelines</h4>
|
||||
{pipes.map((brick) => (
|
||||
<Link
|
||||
key={brick.name}
|
||||
href={brick.href}
|
||||
className={clsx(
|
||||
brick.status ? "cursor-pointer" : "cursor-default",
|
||||
"-m-3 flex items-start rounded-lg p-3 py-3"
|
||||
)}>
|
||||
<div
|
||||
className={clsx(
|
||||
brick.status ? "text-brand-dark dark:text-brand-light" : "text-slate-500",
|
||||
"flex h-10 w-10 flex-shrink-0 items-center justify-center rounded-md sm:h-12 sm:w-12"
|
||||
)}>
|
||||
<brick.icon className="h-6 w-6" aria-hidden="true" />
|
||||
</div>
|
||||
<div className="ml-4">
|
||||
<p
|
||||
className={clsx(
|
||||
brick.status
|
||||
? "text-gray-900 dark:text-gray-200"
|
||||
: "text-gray-400 dark:text-gray-500",
|
||||
"text-lg font-semibold"
|
||||
)}>
|
||||
{brick.name}
|
||||
</p>
|
||||
<p
|
||||
className={clsx(
|
||||
brick.status
|
||||
? "text-gray-900 dark:text-gray-400"
|
||||
: "text-gray-400 dark:text-gray-600",
|
||||
"text-sm"
|
||||
)}>
|
||||
{brick.description}
|
||||
</p>
|
||||
</div>
|
||||
</Link>
|
||||
))}
|
||||
</div>
|
||||
<div>
|
||||
<h4 className="mt-8 mb-3 text-sm text-gray-900 dark:text-gray-300">Data Insights</h4>
|
||||
{insights.map((brick) => (
|
||||
<Link
|
||||
key={brick.name}
|
||||
href={brick.href}
|
||||
className={clsx(
|
||||
brick.status ? "cursor-pointer" : "cursor-default",
|
||||
"-m-3 flex items-start rounded-lg p-3 py-3"
|
||||
)}>
|
||||
<div
|
||||
className={clsx(
|
||||
brick.status ? "text-brand-dark dark:text-brand-light" : "text-slate-500",
|
||||
"flex h-10 w-10 flex-shrink-0 items-center justify-center rounded-md sm:h-12 sm:w-12"
|
||||
)}>
|
||||
<brick.icon className="h-6 w-6" aria-hidden="true" />
|
||||
</div>
|
||||
<div className="ml-4">
|
||||
<p
|
||||
className={clsx(
|
||||
brick.status
|
||||
? "text-gray-900 dark:text-gray-200"
|
||||
: "text-gray-400 dark:text-gray-500",
|
||||
"text-lg font-semibold"
|
||||
)}>
|
||||
{brick.name}
|
||||
</p>
|
||||
<p
|
||||
className={clsx(
|
||||
brick.status
|
||||
? "text-gray-900 dark:text-gray-400"
|
||||
: "text-gray-400 dark:text-gray-600",
|
||||
"text-sm"
|
||||
)}>
|
||||
{brick.description}
|
||||
</p>
|
||||
</div>
|
||||
</Link>
|
||||
))}
|
||||
</div>
|
||||
</nav>
|
||||
</div>
|
||||
<div className="px-5 py-6">
|
||||
<div className="grid grid-cols-3 text-center text-sm font-medium text-gray-900 hover:text-gray-700 dark:text-slate-200 sm:text-base">
|
||||
<div className="flex flex-col space-y-5 text-center text-sm dark:text-slate-300">
|
||||
<Link href="/community">Community</Link>
|
||||
|
||||
<Link href="/blog">Blog</Link>
|
||||
|
||||
<Link href="/docs">Documentation</Link>
|
||||
</div>
|
||||
<div className="mt-6">
|
||||
<Button
|
||||
variant="secondary"
|
||||
EndIcon={GitHubIcon}
|
||||
@@ -449,9 +82,9 @@ export default function Header() {
|
||||
</Button>
|
||||
<Button
|
||||
variant="primary"
|
||||
onClick={() => router.push("/get-started")}
|
||||
className="mt-3 flex w-full justify-center">
|
||||
Get started
|
||||
onClick={() => router.push("/waitlist")}
|
||||
className="flex w-full justify-center">
|
||||
Get access
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -0,0 +1,471 @@
|
||||
import { Popover, Transition } from "@headlessui/react";
|
||||
import { ChevronDownIcon } from "@heroicons/react/20/solid";
|
||||
import {
|
||||
Bars3Icon,
|
||||
BoltIcon,
|
||||
ClipboardDocumentListIcon,
|
||||
CodeBracketSquareIcon,
|
||||
CpuChipIcon,
|
||||
CursorArrowRaysIcon,
|
||||
CursorArrowRippleIcon,
|
||||
DocumentChartBarIcon,
|
||||
EnvelopeIcon,
|
||||
SquaresPlusIcon,
|
||||
XMarkIcon,
|
||||
} from "@heroicons/react/24/outline";
|
||||
import clsx from "clsx";
|
||||
import Link from "next/link";
|
||||
import { useRouter } from "next/router";
|
||||
import { Fragment } from "react";
|
||||
import Button from "./Button";
|
||||
import { FooterLogo } from "./Logo";
|
||||
import { ThemeSelector } from "./ThemeSelector";
|
||||
|
||||
const creation = [
|
||||
{
|
||||
name: "React Library",
|
||||
description: "Build surveys with React.js",
|
||||
href: "/react-form-library",
|
||||
icon: CodeBracketSquareIcon,
|
||||
status: true,
|
||||
},
|
||||
{
|
||||
name: "No Code Builder",
|
||||
description: "Notion-like visual builder",
|
||||
href: "/visual-builder",
|
||||
icon: CursorArrowRaysIcon,
|
||||
status: false,
|
||||
},
|
||||
{
|
||||
name: "Templates",
|
||||
description: "CSAT, PMF survey, etc.",
|
||||
href: "#",
|
||||
icon: ClipboardDocumentListIcon,
|
||||
status: false,
|
||||
},
|
||||
];
|
||||
|
||||
const pipes = [
|
||||
{
|
||||
name: "Core API",
|
||||
description: "The OS survey engine",
|
||||
href: "/core-api",
|
||||
icon: CpuChipIcon,
|
||||
status: true,
|
||||
},
|
||||
{
|
||||
name: "Webhooks",
|
||||
description: "Send JSON anywhere",
|
||||
href: "/webhooks",
|
||||
icon: BoltIcon,
|
||||
status: true,
|
||||
},
|
||||
{
|
||||
name: "Email",
|
||||
description: "Send data and notifications",
|
||||
href: "/email",
|
||||
icon: EnvelopeIcon,
|
||||
status: true,
|
||||
},
|
||||
{
|
||||
name: "Integrations",
|
||||
description: "Connect with 100+ apps",
|
||||
href: "/integrations",
|
||||
icon: SquaresPlusIcon,
|
||||
status: false,
|
||||
},
|
||||
];
|
||||
|
||||
const insights = [
|
||||
{
|
||||
name: "Formbricks HQ",
|
||||
description: "Manage submissions easily",
|
||||
href: "/formbricks-hq",
|
||||
icon: CursorArrowRippleIcon,
|
||||
cat: "insights",
|
||||
status: true,
|
||||
},
|
||||
{
|
||||
name: "Reports",
|
||||
description: "Based on Templates",
|
||||
href: "#",
|
||||
icon: DocumentChartBarIcon,
|
||||
cat: "insights",
|
||||
status: false,
|
||||
},
|
||||
];
|
||||
|
||||
export default function Header() {
|
||||
const router = useRouter();
|
||||
return (
|
||||
<Popover className="relative" as="header">
|
||||
<div className="flex items-center justify-between px-4 py-6 sm:px-6 md:justify-start md:space-x-10">
|
||||
<div className="flex justify-start lg:w-0 lg:flex-1">
|
||||
<Link href="/">
|
||||
<span className="sr-only">Formbricks</span>
|
||||
<FooterLogo className="h-8 w-auto sm:h-10" />
|
||||
</Link>
|
||||
</div>
|
||||
<div className="-my-2 -mr-2 md:hidden">
|
||||
<Popover.Button className="inline-flex items-center justify-center rounded-md bg-gray-100 p-2 text-gray-400 hover:bg-gray-100 hover:text-gray-500 focus:outline-none focus:ring-2 focus:ring-inset focus:ring-teal-500 dark:bg-slate-700 dark:text-slate-200">
|
||||
<span className="sr-only">Open menu</span>
|
||||
<Bars3Icon className="h-6 w-6" aria-hidden="true" />
|
||||
</Popover.Button>
|
||||
</div>
|
||||
<Popover.Group as="nav" className="hidden space-x-10 md:flex">
|
||||
<Popover className="relative">
|
||||
{({ open }) => (
|
||||
<>
|
||||
<Popover.Button
|
||||
className={clsx(
|
||||
open ? "text-slate-700" : "text-slate-400",
|
||||
"group inline-flex items-center rounded-md text-base font-medium hover:text-slate-700 focus:outline-none focus:ring-2 focus:ring-teal-500 focus:ring-offset-2 dark:hover:text-slate-300"
|
||||
)}>
|
||||
<span>Bricks</span>
|
||||
<ChevronDownIcon className="ml-2 h-5 w-5" aria-hidden="true" />
|
||||
</Popover.Button>
|
||||
|
||||
<Transition
|
||||
as={Fragment}
|
||||
enter="transition ease-out duration-200"
|
||||
enterFrom="opacity-0 translate-y-1"
|
||||
enterTo="opacity-100 translate-y-0"
|
||||
leave="transition ease-in duration-150"
|
||||
leaveFrom="opacity-100 translate-y-0"
|
||||
leaveTo="opacity-0 translate-y-1">
|
||||
<Popover.Panel className="absolute z-10 mt-3 -ml-4 w-screen max-w-lg transform lg:left-1/2 lg:ml-0 lg:max-w-4xl lg:-translate-x-1/2">
|
||||
<div className="overflow-hidden rounded-lg shadow-lg ring-1 ring-black ring-opacity-5">
|
||||
<div className="relative grid gap-6 bg-slate-50 px-5 py-6 dark:bg-slate-700 sm:gap-6 sm:p-8 lg:grid-cols-3">
|
||||
<div>
|
||||
<h4 className="mb-6 ml-16 text-sm text-slate-400">Survey Creation</h4>
|
||||
{creation.map((brick) => (
|
||||
<Link
|
||||
key={brick.name}
|
||||
href={brick.href}
|
||||
className={clsx(
|
||||
brick.status
|
||||
? "cursor-pointer hover:bg-slate-100 dark:hover:bg-slate-600 dark:hover:bg-opacity-50"
|
||||
: "cursor-default",
|
||||
"-m-3 flex items-start rounded-lg p-3 py-4"
|
||||
)}>
|
||||
<div
|
||||
className={clsx(
|
||||
brick.status ? "text-brand-dark dark:text-brand-light" : "text-slate-500",
|
||||
"flex h-10 w-10 flex-shrink-0 items-center justify-center rounded-md sm:h-12 sm:w-12"
|
||||
)}>
|
||||
<brick.icon className="h-6 w-6" aria-hidden="true" />
|
||||
</div>
|
||||
<div className="ml-4">
|
||||
<p
|
||||
className={clsx(
|
||||
brick.status
|
||||
? "text-slate-800 dark:text-slate-50"
|
||||
: "text-slate-500 dark:text-slate-400",
|
||||
"text-lg font-semibold"
|
||||
)}>
|
||||
{brick.name}
|
||||
</p>
|
||||
<p className="text-sm text-slate-400 dark:text-slate-500">
|
||||
{brick.description}
|
||||
</p>
|
||||
</div>
|
||||
</Link>
|
||||
))}
|
||||
</div>
|
||||
<div>
|
||||
<h4 className="mb-6 ml-16 text-sm text-slate-400">Data Pipelines</h4>
|
||||
{pipes.map((brick) => (
|
||||
<Link
|
||||
key={brick.name}
|
||||
href={brick.href}
|
||||
className={clsx(
|
||||
brick.status
|
||||
? "cursor-pointer hover:bg-slate-100 dark:hover:bg-slate-600 dark:hover:bg-opacity-50"
|
||||
: "cursor-default",
|
||||
"-m-3 flex items-start rounded-lg p-3 py-4"
|
||||
)}>
|
||||
<div
|
||||
className={clsx(
|
||||
brick.status ? "text-brand-dark dark:text-brand-light" : "text-slate-500",
|
||||
"flex h-10 w-10 flex-shrink-0 items-center justify-center rounded-md sm:h-12 sm:w-12"
|
||||
)}>
|
||||
<brick.icon className="h-6 w-6" aria-hidden="true" />
|
||||
</div>
|
||||
<div className="ml-4">
|
||||
<p
|
||||
className={clsx(
|
||||
brick.status
|
||||
? "text-slate-800 dark:text-slate-50"
|
||||
: "text-slate-500 dark:text-slate-400",
|
||||
"text-lg font-semibold"
|
||||
)}>
|
||||
{brick.name}
|
||||
</p>
|
||||
<p className="text-sm text-slate-400 dark:text-slate-500">
|
||||
{brick.description}
|
||||
</p>
|
||||
</div>
|
||||
</Link>
|
||||
))}
|
||||
</div>
|
||||
<div>
|
||||
<h4 className="mb-6 ml-16 text-sm text-slate-400">Data Insights</h4>
|
||||
{insights.map((brick) => (
|
||||
<Link
|
||||
key={brick.name}
|
||||
href={brick.href}
|
||||
className={clsx(
|
||||
brick.status
|
||||
? "cursor-pointer hover:bg-slate-100 dark:hover:bg-slate-600 dark:hover:bg-opacity-50"
|
||||
: "cursor-default",
|
||||
"-m-3 flex items-start rounded-lg p-3 py-4"
|
||||
)}>
|
||||
<div
|
||||
className={clsx(
|
||||
brick.status ? "text-brand-dark dark:text-brand-light" : "text-slate-500",
|
||||
"flex h-10 w-10 flex-shrink-0 items-center justify-center rounded-md sm:h-12 sm:w-12"
|
||||
)}>
|
||||
<brick.icon className="h-6 w-6" aria-hidden="true" />
|
||||
</div>
|
||||
<div className="ml-4">
|
||||
<p
|
||||
className={clsx(
|
||||
brick.status
|
||||
? "text-slate-800 dark:text-slate-50"
|
||||
: "text-slate-500 dark:text-slate-400",
|
||||
"text-lg font-semibold"
|
||||
)}>
|
||||
{brick.name}
|
||||
</p>
|
||||
<p className="text-sm text-slate-400 dark:text-slate-500">
|
||||
{brick.description}
|
||||
</p>
|
||||
</div>
|
||||
</Link>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Popover.Panel>
|
||||
</Transition>
|
||||
</>
|
||||
)}
|
||||
</Popover>
|
||||
|
||||
<Link
|
||||
href="/community"
|
||||
className="text-base font-medium text-slate-400 hover:text-slate-700 dark:hover:text-slate-300">
|
||||
Community
|
||||
</Link>
|
||||
<Link
|
||||
href="/blog"
|
||||
className="text-base font-medium text-slate-400 hover:text-slate-700 dark:hover:text-slate-300">
|
||||
Blog <p className="bg-brand inline rounded-full px-2 text-xs text-white">1</p>
|
||||
</Link>
|
||||
<Link
|
||||
href="/docs"
|
||||
className="text-base font-medium text-slate-400 hover:text-slate-700 dark:hover:text-slate-300">
|
||||
Docs
|
||||
</Link>
|
||||
</Popover.Group>
|
||||
<div className="hidden items-center justify-end md:flex md:flex-1 lg:w-0">
|
||||
<ThemeSelector className="relative z-10 mr-5" />
|
||||
<Button
|
||||
variant="secondary"
|
||||
EndIcon={GitHubIcon}
|
||||
endIconClassName="fill-slate-800 dark:fill-slate-200"
|
||||
onClick={() => router.push("https://github.com/formbricks/formbricks")}>
|
||||
View on Github
|
||||
</Button>
|
||||
<Button variant="highlight" className="ml-2" onClick={() => router.push("/get-started")}>
|
||||
Get started
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Transition
|
||||
as={Fragment}
|
||||
enter="duration-200 ease-out"
|
||||
enterFrom="opacity-0 scale-95"
|
||||
enterTo="opacity-100 scale-100"
|
||||
leave="duration-100 ease-in"
|
||||
leaveFrom="opacity-100 scale-100"
|
||||
leaveTo="opacity-0 scale-95">
|
||||
<Popover.Panel
|
||||
focus
|
||||
className="absolute inset-x-0 top-0 z-20 origin-top-right transform p-2 transition md:hidden">
|
||||
<div className="dark:divide-slate divide-y-2 divide-gray-100 rounded-lg bg-gray-200 shadow-lg ring-1 ring-black ring-opacity-5 dark:divide-gray-700 dark:bg-slate-800">
|
||||
<div className="px-5 pt-5 pb-6">
|
||||
<div className="flex items-center justify-between">
|
||||
<div>
|
||||
<FooterLogo className="h-8 w-auto" />
|
||||
</div>
|
||||
<div className="-mr-2">
|
||||
<Popover.Button className="inline-flex items-center justify-center rounded-md bg-white p-2 text-gray-400 hover:bg-gray-100 hover:text-gray-500 focus:outline-none focus:ring-2 focus:ring-inset focus:ring-teal-500 dark:bg-slate-700 dark:text-slate-200">
|
||||
<span className="sr-only">Close menu</span>
|
||||
<XMarkIcon className="h-6 w-6" aria-hidden="true" />
|
||||
</Popover.Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<nav className="relative bg-gray-200 px-5 py-6 dark:bg-slate-800">
|
||||
<div>
|
||||
<h4 className="mb-3 text-sm text-gray-900 dark:text-gray-300">Survey Creation</h4>
|
||||
{creation.map((brick) => (
|
||||
<Link
|
||||
key={brick.name}
|
||||
href={brick.href}
|
||||
className={clsx(
|
||||
brick.status ? "cursor-pointer" : "cursor-default",
|
||||
"-m-3 flex items-start rounded-lg p-3 py-3"
|
||||
)}>
|
||||
<div
|
||||
className={clsx(
|
||||
brick.status ? "text-brand-dark dark:text-brand-light" : "text-slate-500",
|
||||
"flex h-10 w-10 flex-shrink-0 items-center justify-center rounded-md sm:h-12 sm:w-12"
|
||||
)}>
|
||||
<brick.icon className="h-6 w-6" aria-hidden="true" />
|
||||
</div>
|
||||
<div className="ml-4">
|
||||
<p
|
||||
className={clsx(
|
||||
brick.status
|
||||
? "text-gray-900 dark:text-gray-200"
|
||||
: "text-gray-400 dark:text-gray-500",
|
||||
"text-lg font-semibold"
|
||||
)}>
|
||||
{brick.name}
|
||||
</p>
|
||||
<p
|
||||
className={clsx(
|
||||
brick.status
|
||||
? "text-gray-900 dark:text-gray-400"
|
||||
: "text-gray-400 dark:text-gray-600",
|
||||
"text-sm"
|
||||
)}>
|
||||
{brick.description}
|
||||
</p>
|
||||
</div>
|
||||
</Link>
|
||||
))}
|
||||
</div>
|
||||
<div>
|
||||
<h4 className="mt-8 mb-3 text-sm text-gray-900 dark:text-gray-300">Data Pipelines</h4>
|
||||
{pipes.map((brick) => (
|
||||
<Link
|
||||
key={brick.name}
|
||||
href={brick.href}
|
||||
className={clsx(
|
||||
brick.status ? "cursor-pointer" : "cursor-default",
|
||||
"-m-3 flex items-start rounded-lg p-3 py-3"
|
||||
)}>
|
||||
<div
|
||||
className={clsx(
|
||||
brick.status ? "text-brand-dark dark:text-brand-light" : "text-slate-500",
|
||||
"flex h-10 w-10 flex-shrink-0 items-center justify-center rounded-md sm:h-12 sm:w-12"
|
||||
)}>
|
||||
<brick.icon className="h-6 w-6" aria-hidden="true" />
|
||||
</div>
|
||||
<div className="ml-4">
|
||||
<p
|
||||
className={clsx(
|
||||
brick.status
|
||||
? "text-gray-900 dark:text-gray-200"
|
||||
: "text-gray-400 dark:text-gray-500",
|
||||
"text-lg font-semibold"
|
||||
)}>
|
||||
{brick.name}
|
||||
</p>
|
||||
<p
|
||||
className={clsx(
|
||||
brick.status
|
||||
? "text-gray-900 dark:text-gray-400"
|
||||
: "text-gray-400 dark:text-gray-600",
|
||||
"text-sm"
|
||||
)}>
|
||||
{brick.description}
|
||||
</p>
|
||||
</div>
|
||||
</Link>
|
||||
))}
|
||||
</div>
|
||||
<div>
|
||||
<h4 className="mt-8 mb-3 text-sm text-gray-900 dark:text-gray-300">Data Insights</h4>
|
||||
{insights.map((brick) => (
|
||||
<Link
|
||||
key={brick.name}
|
||||
href={brick.href}
|
||||
className={clsx(
|
||||
brick.status ? "cursor-pointer" : "cursor-default",
|
||||
"-m-3 flex items-start rounded-lg p-3 py-3"
|
||||
)}>
|
||||
<div
|
||||
className={clsx(
|
||||
brick.status ? "text-brand-dark dark:text-brand-light" : "text-slate-500",
|
||||
"flex h-10 w-10 flex-shrink-0 items-center justify-center rounded-md sm:h-12 sm:w-12"
|
||||
)}>
|
||||
<brick.icon className="h-6 w-6" aria-hidden="true" />
|
||||
</div>
|
||||
<div className="ml-4">
|
||||
<p
|
||||
className={clsx(
|
||||
brick.status
|
||||
? "text-gray-900 dark:text-gray-200"
|
||||
: "text-gray-400 dark:text-gray-500",
|
||||
"text-lg font-semibold"
|
||||
)}>
|
||||
{brick.name}
|
||||
</p>
|
||||
<p
|
||||
className={clsx(
|
||||
brick.status
|
||||
? "text-gray-900 dark:text-gray-400"
|
||||
: "text-gray-400 dark:text-gray-600",
|
||||
"text-sm"
|
||||
)}>
|
||||
{brick.description}
|
||||
</p>
|
||||
</div>
|
||||
</Link>
|
||||
))}
|
||||
</div>
|
||||
</nav>
|
||||
</div>
|
||||
<div className="px-5 py-6">
|
||||
<div className="grid grid-cols-3 text-center text-sm font-medium text-gray-900 hover:text-gray-700 dark:text-slate-200 sm:text-base">
|
||||
<Link href="/community">Community</Link>
|
||||
|
||||
<Link href="/blog">Blog</Link>
|
||||
|
||||
<Link href="/docs">Documentation</Link>
|
||||
</div>
|
||||
<div className="mt-6">
|
||||
<Button
|
||||
variant="secondary"
|
||||
EndIcon={GitHubIcon}
|
||||
onClick={() => router.push("https://github.com/formbricks/formbricks")}
|
||||
className="flex w-full justify-center fill-slate-800 dark:fill-slate-200">
|
||||
View on Github
|
||||
</Button>
|
||||
<Button
|
||||
variant="primary"
|
||||
onClick={() => router.push("/get-started")}
|
||||
className="mt-3 flex w-full justify-center">
|
||||
Get started
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Popover.Panel>
|
||||
</Transition>
|
||||
</Popover>
|
||||
);
|
||||
}
|
||||
|
||||
function GitHubIcon(props: any) {
|
||||
return (
|
||||
<svg aria-hidden="true" viewBox="0 0 16 16" {...props}>
|
||||
<path d="M8 0C3.58 0 0 3.58 0 8C0 11.54 2.29 14.53 5.47 15.59C5.87 15.66 6.02 15.42 6.02 15.21C6.02 15.02 6.01 14.39 6.01 13.72C4 14.09 3.48 13.23 3.32 12.78C3.23 12.55 2.84 11.84 2.5 11.65C2.22 11.5 1.82 11.13 2.49 11.12C3.12 11.11 3.57 11.7 3.72 11.94C4.44 13.15 5.59 12.81 6.05 12.6C6.12 12.08 6.33 11.73 6.56 11.53C4.78 11.33 2.92 10.64 2.92 7.58C2.92 6.71 3.23 5.99 3.74 5.43C3.66 5.23 3.38 4.41 3.82 3.31C3.82 3.31 4.49 3.1 6.02 4.13C6.66 3.95 7.34 3.86 8.02 3.86C8.7 3.86 9.38 3.95 10.02 4.13C11.55 3.09 12.22 3.31 12.22 3.31C12.66 4.41 12.38 5.23 12.3 5.43C12.81 5.99 13.12 6.7 13.12 7.58C13.12 10.65 11.25 11.33 9.47 11.53C9.76 11.78 10.01 12.26 10.01 13.01C10.01 14.08 10 14.94 10 15.21C10 15.42 10.15 15.67 10.55 15.59C13.71 14.53 16 11.53 16 8C16 3.58 12.42 0 8 0Z" />
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
@@ -17,7 +17,7 @@ export default function HeroAnimation(props: any) {
|
||||
loop: true,
|
||||
autoplay: true,
|
||||
// path to your animation file, place it inside public folder
|
||||
path: "/animations/hero-v2.json",
|
||||
path: "/animations/xm-hero-v1.json",
|
||||
});
|
||||
|
||||
return () => animation.destroy();
|
||||
|
||||
@@ -0,0 +1,126 @@
|
||||
import clsx from "clsx";
|
||||
import {
|
||||
OnboardingIcon,
|
||||
PMFIcon,
|
||||
DogChaserIcon,
|
||||
CancelSubscriptionIcon,
|
||||
InterviewPromptIcon,
|
||||
DoorIcon,
|
||||
FeedbackIcon,
|
||||
BugBlueIcon,
|
||||
AngryBirdRageIcon,
|
||||
FeatureRequestIcon,
|
||||
} from "@formbricks/ui";
|
||||
|
||||
const BestPractices = [
|
||||
{
|
||||
title: "Onboarding Segmentation",
|
||||
description:
|
||||
"Get to know your users right from the start. Ask a few questions early, let us enrich the profile.",
|
||||
category: "In-Moment",
|
||||
icon: OnboardingIcon,
|
||||
},
|
||||
{
|
||||
title: "Superhuman PMF Engine",
|
||||
description: "Find out how disappointed people would be if they could not use your service any more.",
|
||||
category: "In-Moment",
|
||||
icon: PMFIcon,
|
||||
},
|
||||
{
|
||||
title: "Feature Chaser",
|
||||
description: "Show a survey about a new feature shown only to people who used it.",
|
||||
category: "In-Moment",
|
||||
icon: DogChaserIcon,
|
||||
},
|
||||
{
|
||||
title: "Cancel Subscription Flow",
|
||||
description: "Request users going through a cancel subscription flow before cancelling.",
|
||||
category: "In-Moment",
|
||||
icon: CancelSubscriptionIcon,
|
||||
},
|
||||
{
|
||||
title: "Interview Prompt",
|
||||
description: "Ask high-interest users to book a time in your calendar to get all the juicy details.",
|
||||
category: "Exploration",
|
||||
icon: InterviewPromptIcon,
|
||||
},
|
||||
{
|
||||
title: "Fake Door Follow-Up",
|
||||
description: "Running a fake door experiment? Catch users right when they are full of expectations.",
|
||||
category: "Exploration",
|
||||
icon: DoorIcon,
|
||||
},
|
||||
{
|
||||
title: "Feedback Box",
|
||||
description: "Give users the chance to share feedback in a single click.",
|
||||
category: "Retain Users",
|
||||
icon: FeedbackIcon,
|
||||
},
|
||||
{
|
||||
title: "Bug Report Form",
|
||||
description: "Catch all bugs in your SaaS with easy and accessible bug reports.",
|
||||
category: "Retain Users",
|
||||
icon: BugBlueIcon,
|
||||
},
|
||||
{
|
||||
title: "Rage Click Survey",
|
||||
description: "Sometimes things don’t work. Trigger this rage click survey to catch users in rage.",
|
||||
category: "Retain Users",
|
||||
icon: AngryBirdRageIcon,
|
||||
},
|
||||
{
|
||||
title: "Feature Request Widget",
|
||||
description: "Allow users to request features and pipe it to GitHub projects or Linear.",
|
||||
category: "Retain Users",
|
||||
icon: FeatureRequestIcon,
|
||||
},
|
||||
];
|
||||
|
||||
export default function InsightOppos() {
|
||||
return (
|
||||
<div className="pt-12 pb-10 md:pt-40">
|
||||
<div className="px-4 py-20 text-center sm:px-6 lg:px-8" id="best-practices">
|
||||
<h1 className="text-3xl font-bold tracking-tight text-slate-800 dark:text-slate-200 sm:text-4xl md:text-5xl">
|
||||
Insight{" "}
|
||||
<span className="from-brand-light to-brand-dark bg-gradient-to-b bg-clip-text text-transparent xl:inline">
|
||||
Opportunities
|
||||
</span>
|
||||
</h1>
|
||||
<p className="mx-auto mt-3 max-w-md text-base text-slate-500 dark:text-slate-300 sm:text-lg md:mt-5 md:max-w-3xl md:text-xl">
|
||||
All Best Practices for qualitative user research in one product.
|
||||
</p>
|
||||
</div>
|
||||
<div>
|
||||
<div className=" mx-auto grid max-w-5xl grid-cols-1 gap-6 px-2 sm:grid-cols-2">
|
||||
{BestPractices.map((bestPractice) => (
|
||||
<div
|
||||
key={bestPractice.title}
|
||||
className="drop-shadow-card duration-120 relative cursor-default rounded-lg bg-slate-100 p-8 transition-all ease-in-out hover:scale-105 dark:bg-slate-800">
|
||||
<div
|
||||
className={clsx(
|
||||
// base styles independent what type of button it is
|
||||
"absolute right-10 rounded-full py-1 px-3",
|
||||
// different styles depending on size
|
||||
bestPractice.category === "In-Moment" &&
|
||||
"bg-pink-100 text-pink-500 dark:bg-pink-800 dark:text-pink-200",
|
||||
bestPractice.category === "Exploration" &&
|
||||
"bg-blue-100 text-blue-500 dark:bg-blue-800 dark:text-blue-200",
|
||||
bestPractice.category === "Retain Users" &&
|
||||
"bg-orange-100 text-orange-500 dark:bg-orange-800 dark:text-orange-200"
|
||||
)}>
|
||||
{bestPractice.category}
|
||||
</div>
|
||||
<div className="h-12 w-12">
|
||||
<bestPractice.icon className="h-12 w-12 " />
|
||||
</div>
|
||||
<h3 className="mt-3 mb-1 text-xl font-bold text-slate-700 dark:text-slate-200">
|
||||
{bestPractice.title}
|
||||
</h3>
|
||||
<p className="text-sm text-slate-600 dark:text-slate-400">{bestPractice.description}</p>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
import Button from "./Button";
|
||||
import { useRouter } from "next/router";
|
||||
import clsx from "clsx";
|
||||
|
||||
interface Props {
|
||||
inverted?: boolean;
|
||||
}
|
||||
|
||||
export default function JoinWaitlist({ inverted = false }: Props) {
|
||||
const router = useRouter();
|
||||
return (
|
||||
<div
|
||||
className={clsx(
|
||||
inverted
|
||||
? "from-slate-800 via-slate-800 to-slate-700 dark:from-slate-200 dark:to-slate-300"
|
||||
: "from-slate-200 to-slate-300 dark:from-slate-800 dark:via-slate-800 dark:to-slate-700",
|
||||
"mx-auto mb-12 w-full max-w-5xl bg-gradient-to-br sm:rounded-xl md:mb-0 "
|
||||
)}>
|
||||
<div className="relative px-4 py-8 sm:px-6 sm:pt-8 sm:pb-12 lg:px-8 lg:pt-12">
|
||||
<div className="absolute right-10 md:top-1/2 md:-translate-y-1/2">
|
||||
<Button variant="highlight" onClick={() => router.push("/waitlist")}>
|
||||
Get Access
|
||||
</Button>
|
||||
</div>
|
||||
<p className="lg:text-md dark:text-brand-dark text-brand-light text-sm font-semibold uppercase">
|
||||
Curious?
|
||||
</p>
|
||||
<h2
|
||||
className={clsx(
|
||||
inverted ? "text-slate-200 dark:text-slate-800" : "text-slate-800 dark:text-slate-200",
|
||||
"mt-4 text-2xl font-bold tracking-tight lg:text-3xl "
|
||||
)}>
|
||||
Get access now!
|
||||
</h2>
|
||||
<p
|
||||
className={clsx(
|
||||
inverted ? "text-slate-300 dark:text-slate-500" : "text-slate-500 dark:text-slate-300",
|
||||
"text-md mt-4 max-w-3xl lg:text-lg"
|
||||
)}>
|
||||
We’re onboarding design partners regularly. Sign up to get early access.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -15,9 +15,11 @@ export default function Layout({ title, description, children }: LayoutProps) {
|
||||
<MetaInformation title={title} description={description} />
|
||||
<Header />
|
||||
<FeedbackButton />
|
||||
<main className="max-w-8xl relative mx-auto mb-auto flex flex-col justify-center sm:px-2 lg:px-8 xl:px-12">
|
||||
{children}
|
||||
</main>
|
||||
{
|
||||
<main className="max-w-8xl relative mx-auto mb-auto flex w-full flex-col justify-center sm:px-2 lg:px-8 xl:px-12">
|
||||
{children}
|
||||
</main>
|
||||
}
|
||||
<Footer />
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
import Footer from "./Footer";
|
||||
import MetaInformation from "./MetaInformation";
|
||||
|
||||
interface LayoutProps {
|
||||
children: React.ReactNode;
|
||||
title: string;
|
||||
description: string;
|
||||
}
|
||||
|
||||
export default function Layout({ title, description, children }: LayoutProps) {
|
||||
return (
|
||||
<div className="flex h-screen flex-col justify-between">
|
||||
<MetaInformation title={title} description={description} />
|
||||
{
|
||||
<main className="max-w-8xl relative mx-auto mb-auto flex w-full flex-col justify-center sm:px-2 lg:px-8 xl:px-12">
|
||||
{children}
|
||||
</main>
|
||||
}
|
||||
<Footer />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -24,7 +24,7 @@ export default function CTA() {
|
||||
<div className="rounded-xl bg-gradient-to-br from-slate-400 to-slate-300 pb-10 text-center text-gray-800 dark:from-slate-800 dark:to-slate-700 dark:text-slate-200">
|
||||
<h3 className="text-3xl font-bold">Cloud</h3>
|
||||
<p className="mt-2 mb-4 dark:text-slate-400">Use our free managed service.</p>
|
||||
<Button variant="secondary" onClick={() => router.push("/get-started")} className="mt-3">
|
||||
<Button variant="secondary" onClick={() => router.push("/waitlist")} className="mt-3">
|
||||
Get started
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
@@ -19,7 +19,7 @@ export default function HeadingCentered() {
|
||||
<Button variant="secondary" onClick={() => router.push("/discord")}>
|
||||
Join Discord
|
||||
</Button>
|
||||
<Button variant="primary" className="ml-3" onClick={() => router.push("/get-started")}>
|
||||
<Button variant="primary" className="ml-3" onClick={() => router.push("/waitlist")}>
|
||||
Get started
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
@@ -21,7 +21,7 @@ export default function HeadingCentered() {
|
||||
<Button variant="secondary" onClick={() => router.push("/docs")}>
|
||||
Read docs
|
||||
</Button>
|
||||
<Button variant="primary" className="ml-3" onClick={() => router.push("/get-started")}>
|
||||
<Button variant="primary" className="ml-3" onClick={() => router.push("/waitlist")}>
|
||||
Get started
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 55 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 48 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 48 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 45 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 43 KiB |
@@ -10,6 +10,7 @@
|
||||
"lint": "next lint"
|
||||
},
|
||||
"dependencies": {
|
||||
"@formbricks/ui": "workspace:*",
|
||||
"@docsearch/react": "^3.3.0",
|
||||
"@formbricks/react": "workspace:*",
|
||||
"@headlessui/react": "^1.7.3",
|
||||
@@ -27,6 +28,7 @@
|
||||
"prism-react-renderer": "^1.3.5",
|
||||
"react": "18.2.0",
|
||||
"react-dom": "18.2.0",
|
||||
"react-hook-form": "^7.39.1",
|
||||
"react-responsive-embed": "^2.1.0",
|
||||
"remark-gfm": "^3.0.1"
|
||||
},
|
||||
|
||||
@@ -54,7 +54,7 @@ export default function Document() {
|
||||
<meta name="msapplication-config" content="/favicon/browserconfig.xml" />
|
||||
<meta name="theme-color" content="#ffffff" />
|
||||
</Head>
|
||||
<body className="bg-slate-100 dark:bg-slate-900">
|
||||
<body className="bg-slate-50 dark:bg-slate-900">
|
||||
<Main />
|
||||
<NextScript />
|
||||
</body>
|
||||
|
||||
@@ -38,7 +38,7 @@ const EmailPage = () => (
|
||||
img={<Image src={ImageEmail} alt="react library" className="rounded-lg" />}
|
||||
isImgLeft
|
||||
cta="Get started"
|
||||
href="/get-started"
|
||||
href="/waitlist"
|
||||
/>
|
||||
<ul role="list" className="grid grid-cols-1 gap-6 px-12 pt-2 pb-16 sm:grid-cols-2 md:grid-cols-3">
|
||||
{features.map((feature) => (
|
||||
|
||||
@@ -2,18 +2,19 @@ import Layout from "@/components/shared/Layout";
|
||||
import Hero from "@/components/home/Hero";
|
||||
import Features from "@/components/home/Features";
|
||||
import Highlights from "@/components/home/Highlights";
|
||||
import WhyFormbricks from "../components/shared/WhyFormbricks";
|
||||
import CTA from "@/components/shared/CTA";
|
||||
import InsightOppos from "@/components/shared/InsightOppos";
|
||||
import JoinWaitlist from "@/components/shared/JoinWaitlist";
|
||||
|
||||
const IndexPage = () => (
|
||||
<Layout
|
||||
title="Formbricks | Open Source Forms & Survey Toolbox"
|
||||
description="Modular, customizable and extendable form infrastructure. Build exactly the form or survey solution you need in a fraction of the time. 100% data ownership.">
|
||||
title="Formbricks | Natively embedded user research for B2B SaaS"
|
||||
description="Build qualitative user research into your product. Leverage Best practices to increase Product-Market Fit.">
|
||||
<Hero />
|
||||
<Features />
|
||||
<JoinWaitlist />
|
||||
<Highlights />
|
||||
<WhyFormbricks />
|
||||
<CTA />
|
||||
<InsightOppos />
|
||||
<JoinWaitlist inverted />
|
||||
</Layout>
|
||||
);
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ If you want to build highly customized forms optimized to the last milisecond, t
|
||||
|
||||
### What is **Formbricks React** good for?
|
||||
|
||||
If you need more than what a basic HTML form has to offer, Formbricks React is very likely the right choice for you. You won’t find yourself rewriting common form functionality over again. It’s native integration into the (also self-hostable) [formbricks.com](https://formbricks.com/get-started) cloud speeds up working with qualitative data overall.
|
||||
If you need more than what a basic HTML form has to offer, Formbricks React is very likely the right choice for you. You won’t find yourself rewriting common form functionality over again. It’s native integration into the (also self-hostable) [formbricks.com](https://formbricks.com/waitlist) cloud speeds up working with qualitative data overall.
|
||||
|
||||
<Callout title="Always uptodate" type="note">
|
||||
At this early stage, the React Library develops rapidly. We keep this page updated as we keep shipping.
|
||||
|
||||
@@ -0,0 +1,486 @@
|
||||
import FeatureSelection from "@/components/engine/FeatureSelection";
|
||||
import IconRadio from "@/components/engine/IconRadio";
|
||||
import Input from "@/components/engine/Input";
|
||||
import Scale from "@/components/engine/Scale";
|
||||
import { Survey } from "@/components/engine/Survey";
|
||||
import Textarea from "@/components/engine/Textarea";
|
||||
import ThankYouHeading from "@/components/engine/ThankYouHeading";
|
||||
import ThankYouPlans from "@/components/engine/ThankYouPlans";
|
||||
import LayoutWaitlist from "@/components/shared/LayoutWaitlist";
|
||||
import { NoSymbolIcon, UserIcon } from "@heroicons/react/24/outline";
|
||||
import {
|
||||
OnboardingIcon,
|
||||
PMFIcon,
|
||||
DogChaserIcon,
|
||||
CancelSubscriptionIcon,
|
||||
InterviewPromptIcon,
|
||||
DoorIcon,
|
||||
FeedbackIcon,
|
||||
BugBlueIcon,
|
||||
AngryBirdRageIcon,
|
||||
FeatureRequestIcon,
|
||||
FounderIcon,
|
||||
EngineerIcon,
|
||||
LaptopWorkerIcon,
|
||||
UserCommentIcon,
|
||||
UserGroupIcon,
|
||||
BellIcon,
|
||||
SkyscraperIcon,
|
||||
CheckMarkIcon,
|
||||
CrossMarkIcon,
|
||||
UserCoupleIcon,
|
||||
} from "@formbricks/ui";
|
||||
|
||||
const WaitlistPage = () => (
|
||||
<LayoutWaitlist title="Waitlist" description="Join our Waitlist today">
|
||||
<div className="mx-auto w-full max-w-5xl px-6 md:w-3/4">
|
||||
<div className="px-4 pt-20 pb-4">
|
||||
<h1 className="text-3xl font-bold tracking-tight text-slate-800 dark:text-slate-200 sm:text-4xl md:text-5xl">
|
||||
<span className="xl:inline">Get</span>{" "}
|
||||
<span className="from-brand-light to-brand-dark bg-gradient-to-b bg-clip-text text-transparent xl:inline">
|
||||
early
|
||||
</span>{" "}
|
||||
<span className="inline ">access</span>
|
||||
</h1>
|
||||
<p className="mt-3 text-sm text-slate-400 dark:text-slate-300 md:text-base">
|
||||
We are onboarding users continuously. Tell us more about you!
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="mx-auto my-6 w-full max-w-5xl rounded-xl bg-slate-100 px-8 py-10 md:my-12 md:px-16 md:py-20">
|
||||
<Survey
|
||||
formbricksUrl="http://localhost:3000"
|
||||
formId="cld2xwo2r000cu0mdkju2nj96"
|
||||
survey={{
|
||||
config: {
|
||||
progressBar: false,
|
||||
},
|
||||
pages: [
|
||||
{
|
||||
id: "rolePage",
|
||||
config: {
|
||||
autoSubmit: true,
|
||||
},
|
||||
elements: [
|
||||
{
|
||||
id: "role",
|
||||
type: "radio",
|
||||
label: "How would you describe your role?",
|
||||
name: "role",
|
||||
options: [
|
||||
{ label: "Founder", value: "founder", frontend: { icon: FounderIcon } },
|
||||
{
|
||||
label: "Product Manager",
|
||||
value: "productManager",
|
||||
frontend: { icon: LaptopWorkerIcon },
|
||||
},
|
||||
{ label: "Engineer", value: "engineer", frontend: { icon: EngineerIcon } },
|
||||
],
|
||||
component: IconRadio,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: "targetGroupPage",
|
||||
config: {
|
||||
autoSubmit: true,
|
||||
},
|
||||
elements: [
|
||||
{
|
||||
id: "targetGroup",
|
||||
type: "radio",
|
||||
label: "Who are you serving?",
|
||||
name: "targetGroup",
|
||||
options: [
|
||||
{ label: "Companies", value: "companies", frontend: { icon: SkyscraperIcon } },
|
||||
{ label: "Consumers", value: "consumers", frontend: { icon: UserGroupIcon } },
|
||||
],
|
||||
component: IconRadio,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: "featureSelectionPage",
|
||||
elements: [
|
||||
{
|
||||
id: "featureSelection",
|
||||
type: "radio",
|
||||
label: "Pick 2 to get started",
|
||||
name: "featureSelection",
|
||||
options: [
|
||||
{
|
||||
label: "Onboarding Segmentation",
|
||||
value: "onboardingSegmentation",
|
||||
frontend: {
|
||||
icon: OnboardingIcon,
|
||||
description:
|
||||
"Get to know your users right from the start. Ask a few questions early, let us enrich the profile.",
|
||||
},
|
||||
},
|
||||
{
|
||||
label: "Superhuman PMF Engine",
|
||||
value: "pmf",
|
||||
frontend: {
|
||||
icon: PMFIcon,
|
||||
description:
|
||||
"Find out how disappointed people would be if they could not use your service any more.",
|
||||
},
|
||||
},
|
||||
{
|
||||
label: "Feature Chaser",
|
||||
value: "featureChaser",
|
||||
frontend: {
|
||||
icon: DogChaserIcon,
|
||||
description: "Show a survey about a new feature shown only to people who used it.",
|
||||
},
|
||||
},
|
||||
{
|
||||
label: "Cancel Subscription Flow",
|
||||
value: "cancelSubscriptionFlow",
|
||||
frontend: {
|
||||
icon: CancelSubscriptionIcon,
|
||||
description:
|
||||
"Request users going through a cancel subscription flow before cancelling.",
|
||||
},
|
||||
},
|
||||
{
|
||||
label: "Interview Prompt",
|
||||
value: "interviewPrompt",
|
||||
frontend: {
|
||||
icon: InterviewPromptIcon,
|
||||
description:
|
||||
"Ask high-interest users to book a time in your calendar to get all the juicy details.",
|
||||
},
|
||||
},
|
||||
{
|
||||
label: "Fake Door Follow-Up",
|
||||
value: "fakeDoorFollowUp",
|
||||
frontend: {
|
||||
icon: DoorIcon,
|
||||
description:
|
||||
"Running a fake door experiment? Catch users right when they are full of expectations.",
|
||||
},
|
||||
},
|
||||
{
|
||||
label: "FeedbackBox",
|
||||
value: "feedbackBox",
|
||||
frontend: {
|
||||
icon: FeedbackIcon,
|
||||
description: "Give users the chance to share feedback in a single click.",
|
||||
},
|
||||
},
|
||||
{
|
||||
label: "Bug Report Form",
|
||||
value: "bugReportForm",
|
||||
frontend: {
|
||||
icon: BugBlueIcon,
|
||||
description: "Catch all bugs in your SaaS with easy and accessible bug reports.",
|
||||
},
|
||||
},
|
||||
{
|
||||
label: "Rage Click Survey",
|
||||
value: "rageClickSurvey",
|
||||
frontend: {
|
||||
icon: AngryBirdRageIcon,
|
||||
description:
|
||||
"Sometimes things don’t work. Trigger this rage click survey to catch users in rage.",
|
||||
},
|
||||
},
|
||||
{
|
||||
label: "Feature Request Widget",
|
||||
value: "featureRequestWidget",
|
||||
frontend: {
|
||||
icon: FeatureRequestIcon,
|
||||
description:
|
||||
"Allow users to request features and pipe it to GitHub projects or Linear.",
|
||||
},
|
||||
},
|
||||
],
|
||||
component: FeatureSelection,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: "emailPage",
|
||||
elements: [
|
||||
{
|
||||
id: "email",
|
||||
type: "text",
|
||||
label: "What's your email?",
|
||||
name: "email",
|
||||
frontend: {
|
||||
required: true,
|
||||
type: "email",
|
||||
placeholder: "email@example.com",
|
||||
},
|
||||
component: Input,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: "wauPage",
|
||||
config: {
|
||||
autoSubmit: true,
|
||||
},
|
||||
elements: [
|
||||
{
|
||||
id: "wau",
|
||||
type: "radio",
|
||||
label: "How many weekly active users do you have?",
|
||||
name: "wau",
|
||||
options: [
|
||||
{ label: "Not launched", value: "notLaunched", frontend: { icon: CrossMarkIcon } },
|
||||
{ label: "10-100", value: "10-100", frontend: { icon: UserCoupleIcon } },
|
||||
{ label: "100-1.000", value: "100-1000", frontend: { icon: UserGroupIcon } },
|
||||
{ label: "1.000+", value: "10000+", frontend: { icon: UserGroupIcon } },
|
||||
],
|
||||
component: IconRadio,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: "goalPage",
|
||||
config: {
|
||||
autoSubmit: true,
|
||||
},
|
||||
elements: [
|
||||
{
|
||||
id: "goal",
|
||||
type: "radio",
|
||||
label: "What are you here for?",
|
||||
name: "goal",
|
||||
options: [
|
||||
{
|
||||
label: "Just notify me on launch",
|
||||
value: "justNotify",
|
||||
frontend: { icon: BellIcon },
|
||||
},
|
||||
{
|
||||
label: "Become a beta user",
|
||||
value: "becomeBetaUser",
|
||||
frontend: { icon: UserCommentIcon },
|
||||
},
|
||||
],
|
||||
component: IconRadio,
|
||||
},
|
||||
],
|
||||
branchingRules: [
|
||||
{
|
||||
type: "value",
|
||||
name: "goal",
|
||||
value: "justNotify",
|
||||
nextPageId: "thankYouPageNotify",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: "namePage",
|
||||
elements: [
|
||||
{
|
||||
id: "name",
|
||||
type: "text",
|
||||
label: "First of all, what’s your name?",
|
||||
name: "name",
|
||||
frontend: { placeholder: "First name" },
|
||||
component: Input,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: "urgencyPage",
|
||||
config: {
|
||||
autoSubmit: true,
|
||||
},
|
||||
elements: [
|
||||
{
|
||||
id: "urgency",
|
||||
type: "radio",
|
||||
label: "How urgently do you need this?",
|
||||
name: "urgency",
|
||||
options: [
|
||||
{ label: "1", value: "1" },
|
||||
{ label: "2", value: "2" },
|
||||
{ label: "3", value: "3" },
|
||||
{ label: "4", value: "4" },
|
||||
{ label: "5", value: "5" },
|
||||
{ label: "6", value: "6" },
|
||||
{ label: "7", value: "7" },
|
||||
{ label: "8", value: "8" },
|
||||
{ label: "9", value: "9" },
|
||||
{ label: "10", value: "10" },
|
||||
],
|
||||
frontend: {
|
||||
min: 1,
|
||||
max: 10,
|
||||
minLabel: "I’m just curious",
|
||||
maxLabel: "As soon as possible",
|
||||
},
|
||||
component: Scale,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: "pmfPage",
|
||||
config: {
|
||||
autoSubmit: true,
|
||||
},
|
||||
elements: [
|
||||
{
|
||||
id: "pmf",
|
||||
type: "radio",
|
||||
label: "Have you found Product-Market-Fit?",
|
||||
name: "pmf",
|
||||
options: [
|
||||
{
|
||||
label: "Yes",
|
||||
value: "yes",
|
||||
frontend: { icon: CheckMarkIcon },
|
||||
},
|
||||
{
|
||||
label: "No",
|
||||
value: "no",
|
||||
frontend: { icon: CrossMarkIcon },
|
||||
},
|
||||
],
|
||||
component: IconRadio,
|
||||
},
|
||||
],
|
||||
branchingRules: [
|
||||
{
|
||||
type: "value",
|
||||
name: "pmf",
|
||||
value: "no",
|
||||
nextPageId: "pmfApproachPage",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: "scalingResearchPage",
|
||||
elements: [
|
||||
{
|
||||
id: "scalingResearch",
|
||||
type: "text",
|
||||
label: "The hardest part about scaling user research is...",
|
||||
name: "scalingResearch",
|
||||
frontend: { placeholder: "Please complete the sentence." },
|
||||
component: Textarea,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: "triedSolveItPage",
|
||||
elements: [
|
||||
{
|
||||
id: "triedSolveIt",
|
||||
type: "text",
|
||||
label: "We have tried to solve it by...",
|
||||
name: "triedSolveIt",
|
||||
frontend: { placeholder: "Please complete the sentence." },
|
||||
component: Textarea,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: "toolsMaintainPmfPage",
|
||||
elements: [
|
||||
{
|
||||
id: "toolsMaintainPmf",
|
||||
type: "text",
|
||||
label: "What tools help you maintain Product-Market Fit?",
|
||||
name: "toolsMaintainPmf",
|
||||
frontend: { placehodler: "Mixpanel, Segment, Intercom..." },
|
||||
component: Textarea,
|
||||
},
|
||||
],
|
||||
branchingRules: [
|
||||
{
|
||||
type: "value",
|
||||
name: "pmf",
|
||||
value: "yes",
|
||||
nextPageId: "thankYouPageBetaUser",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: "pmfApproachPage",
|
||||
elements: [
|
||||
{
|
||||
id: "pmfApproach",
|
||||
type: "text",
|
||||
label: "What is your approach for finding Product-Market Fit?",
|
||||
name: "pmfApproach",
|
||||
frontend: { placeholder: "Last time, I..." },
|
||||
component: Textarea,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: "pmfHardestPartPage",
|
||||
elements: [
|
||||
{
|
||||
id: "pmfHardestPart",
|
||||
type: "text",
|
||||
label: "What is the hardest part about it?",
|
||||
name: "pmfHardestPart",
|
||||
frontend: { placeholder: "Please complete the sentence." },
|
||||
component: Textarea,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: "pmfFindingToolsPage",
|
||||
elements: [
|
||||
{
|
||||
id: "pmfFindingTools",
|
||||
type: "text",
|
||||
label: "What tools help you finding Product-Market Fit?",
|
||||
name: "pmfFindingTools",
|
||||
frontend: { placeholder: "Mixpanel, Segment, Intercom..." },
|
||||
component: Textarea,
|
||||
},
|
||||
],
|
||||
branchingRules: [
|
||||
{
|
||||
type: "value",
|
||||
name: "pmf",
|
||||
value: "no",
|
||||
nextPageId: "thankYouPageBetaUser",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: "thankYouPageNotify",
|
||||
endScreen: true,
|
||||
elements: [
|
||||
{
|
||||
id: "thankYouNotify",
|
||||
type: "html",
|
||||
component: ThankYouHeading,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: "thankYouPageBetaUser",
|
||||
endScreen: true,
|
||||
elements: [
|
||||
{
|
||||
id: "thankYouBetaUser",
|
||||
type: "html",
|
||||
component: ThankYouHeading,
|
||||
},
|
||||
{
|
||||
id: "thankYouBetaUser",
|
||||
type: "html",
|
||||
component: ThankYouPlans,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</LayoutWaitlist>
|
||||
);
|
||||
|
||||
export default WaitlistPage;
|
||||
File diff suppressed because one or more lines are too long
@@ -24,8 +24,8 @@ module.exports = {
|
||||
extend: {
|
||||
colors: {
|
||||
brand: {
|
||||
DEFAULT: "#00E6CA",
|
||||
light: "#00E6CA",
|
||||
DEFAULT: "#00C4B8",
|
||||
light: "#00C4B8",
|
||||
dark: "#00C4B8",
|
||||
},
|
||||
|
||||
@@ -44,6 +44,9 @@ module.exports = {
|
||||
screens: {
|
||||
xs: "430px",
|
||||
},
|
||||
dropShadow: {
|
||||
card: "0px 4px 12px rgba(0, 0, 0, 0.5);",
|
||||
},
|
||||
},
|
||||
},
|
||||
plugins: [require("@tailwindcss/typography"), require("@tailwindcss/forms")],
|
||||
|
||||
@@ -40,7 +40,7 @@ export default function FormsList({ workspaceId }) {
|
||||
onClick={() => newForm()}
|
||||
alertText="You don't have any forms yet."
|
||||
hintText="Start by creating a form."
|
||||
buttonText="create feedback form"
|
||||
buttonText="create form"
|
||||
borderStyles="border-4 border-dotted border-red"
|
||||
hasButton={true}>
|
||||
<DocumentPlusIcon className="stroke-thin mx-auto h-24 w-24 text-slate-300" />
|
||||
|
||||
@@ -2,8 +2,10 @@
|
||||
|
||||
import { createForm } from "@/lib/forms";
|
||||
import { Button } from "@formbricks/ui";
|
||||
import { Dialog, Transition } from "@headlessui/react";
|
||||
import { Dialog, RadioGroup, Transition } from "@headlessui/react";
|
||||
import { UserIcon } from "@heroicons/react/24/outline";
|
||||
import { XMarkIcon } from "@heroicons/react/24/solid";
|
||||
import clsx from "clsx";
|
||||
import { useRouter } from "next/navigation";
|
||||
import { Fragment, useState } from "react";
|
||||
import { BsPlus } from "react-icons/bs";
|
||||
@@ -14,34 +16,75 @@ type FormOnboardingModalProps = {
|
||||
workspaceId: string;
|
||||
};
|
||||
|
||||
const formTypes = [
|
||||
{
|
||||
id: "feedback",
|
||||
name: "Feedback Box",
|
||||
description: "A direct channel to feel the pulse of your users.",
|
||||
icon: UserIcon,
|
||||
},
|
||||
{
|
||||
id: "custom",
|
||||
name: "Custom Form",
|
||||
description: "Send and analyze your custom form.",
|
||||
icon: UserIcon,
|
||||
},
|
||||
];
|
||||
|
||||
export default function NewFormModal({ open, setOpen, workspaceId }: FormOnboardingModalProps) {
|
||||
const router = useRouter();
|
||||
const [label, setLabel] = useState("");
|
||||
const [formType, setFormType] = useState(formTypes[0].id);
|
||||
|
||||
const createFormAction = async (e) => {
|
||||
e.preventDefault();
|
||||
const form = await createForm(workspaceId, {
|
||||
label,
|
||||
type: "feedback",
|
||||
schema: {
|
||||
type: "form",
|
||||
config: {},
|
||||
children: [
|
||||
{
|
||||
type: "radio",
|
||||
name: "feedbackType",
|
||||
label: "What's on your mind?",
|
||||
options: ["idea", "compliment", "bug"],
|
||||
},
|
||||
{
|
||||
type: "textarea",
|
||||
name: "message",
|
||||
label: "What's your feedback?",
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
router.push(`/workspaces/${workspaceId}/forms/${form.id}/feedback/`);
|
||||
let formTemplate;
|
||||
if (formType === "feedback") {
|
||||
formTemplate = {
|
||||
label,
|
||||
type: "feedback",
|
||||
schema: {
|
||||
type: "form",
|
||||
config: {},
|
||||
pages: [
|
||||
{
|
||||
id: "feedbackTypePage",
|
||||
elements: [
|
||||
{
|
||||
type: "radio",
|
||||
name: "feedbackType",
|
||||
label: "What's on your mind?",
|
||||
options: [
|
||||
{ label: "Idea", value: "idea" },
|
||||
{ label: "Compliment", value: "compliment" },
|
||||
{ label: "Bug", value: "bug" },
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: "messagePage",
|
||||
elements: [
|
||||
{
|
||||
type: "textarea",
|
||||
name: "message",
|
||||
label: "What's your feedback?",
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
} else if (formType === "custom") {
|
||||
formTemplate = {
|
||||
label,
|
||||
type: "custom",
|
||||
};
|
||||
} else {
|
||||
throw new Error("Unknown form type");
|
||||
}
|
||||
const form = await createForm(workspaceId, formTemplate);
|
||||
router.push(`/workspaces/${workspaceId}/forms/${form.id}/${form.type}/`);
|
||||
};
|
||||
|
||||
return (
|
||||
@@ -101,10 +144,59 @@ export default function NewFormModal({ open, setOpen, workspaceId }: FormOnboard
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<hr className="my-6 text-gray-600" />
|
||||
<RadioGroup value={formType} onChange={setFormType}>
|
||||
<RadioGroup.Label className="text-sm font-light text-slate-800">
|
||||
Choose your form type
|
||||
</RadioGroup.Label>
|
||||
<div className="mt-3 space-y-4">
|
||||
{formTypes.map((formType) => (
|
||||
<RadioGroup.Option
|
||||
key={formType.name}
|
||||
value={formType.id}
|
||||
className={({ checked, active }) =>
|
||||
clsx(
|
||||
checked ? "border-transparent" : "border-gray-300",
|
||||
active ? "border-brand ring-brand ring-2" : "",
|
||||
"relative block cursor-pointer rounded-lg border bg-white px-6 py-4 shadow-sm focus:outline-none sm:flex"
|
||||
)
|
||||
}>
|
||||
{({ active, checked }) => (
|
||||
<>
|
||||
<RadioGroup.Description
|
||||
as="span"
|
||||
className="mt-2 mr-3 flex text-sm sm:mt-0 sm:flex-col sm:text-right">
|
||||
<formType.icon className="h-6 w-6" />
|
||||
</RadioGroup.Description>
|
||||
<span className="flex items-center">
|
||||
<span className="flex flex-col text-sm">
|
||||
<RadioGroup.Label as="span" className="font-medium text-gray-900">
|
||||
{formType.name}
|
||||
</RadioGroup.Label>
|
||||
<RadioGroup.Description as="span" className="text-gray-500">
|
||||
{formType.description}
|
||||
</RadioGroup.Description>
|
||||
</span>
|
||||
</span>
|
||||
|
||||
<span
|
||||
className={clsx(
|
||||
active ? "border" : "border-2",
|
||||
checked ? "border-brand" : "border-transparent",
|
||||
"pointer-events-none absolute -inset-px rounded-lg"
|
||||
)}
|
||||
aria-hidden="true"
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
</RadioGroup.Option>
|
||||
))}
|
||||
</div>
|
||||
</RadioGroup>
|
||||
|
||||
<div className="mt-5 sm:mt-6">
|
||||
<Button type="submit" className="w-full justify-center">
|
||||
create feedback form
|
||||
create form
|
||||
<BsPlus className="ml-1 h-6 w-6"></BsPlus>
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
+9
-210
@@ -9,7 +9,7 @@ import clsx from "clsx";
|
||||
import Link from "next/link";
|
||||
import { useRouter } from "next/router";
|
||||
import Prism from "prismjs";
|
||||
import { useEffect, useState } from "react";
|
||||
import { useEffect, useMemo, useState } from "react";
|
||||
import { AiFillApi } from "react-icons/ai";
|
||||
import { FaReact, FaVuejs } from "react-icons/fa";
|
||||
import { toast } from "react-toastify";
|
||||
@@ -19,8 +19,6 @@ require("prismjs/components/prism-javascript");
|
||||
const tabs = [
|
||||
{ id: "overview", name: "Overview", icon: UserIcon },
|
||||
{ id: "api", name: "API", icon: AiFillApi },
|
||||
{ id: "react", name: "React", icon: FaReact },
|
||||
{ id: "vue", name: "Vue", icon: FaVuejs },
|
||||
];
|
||||
|
||||
export default function FormOverviewPage() {
|
||||
@@ -34,6 +32,12 @@ export default function FormOverviewPage() {
|
||||
);
|
||||
const [activeTab, setActiveTab] = useState(tabs[0]);
|
||||
|
||||
const capturePostUrl = useMemo(() => {
|
||||
if (form) {
|
||||
return `${window.location.protocol}//${window.location.host}/api/capture/forms/${form.id}/submissions`;
|
||||
}
|
||||
}, [form]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!isLoadingForm) {
|
||||
Prism.highlightAll();
|
||||
@@ -151,7 +155,7 @@ export default function FormOverviewPage() {
|
||||
id="captureUrl"
|
||||
type="text"
|
||||
className="focus:border-brand focus:ring-brand block w-full rounded-r-md border-gray-300 bg-gray-100 shadow-sm sm:text-sm"
|
||||
value={`${window.location.protocol}//${window.location.host}/api/capture/forms/${form.id}/submissions`}
|
||||
value={capturePostUrl}
|
||||
disabled
|
||||
/>
|
||||
</div>
|
||||
@@ -160,7 +164,7 @@ export default function FormOverviewPage() {
|
||||
variant="secondary"
|
||||
className="mt-2 w-full justify-center"
|
||||
onClick={() => {
|
||||
navigator.clipboard.writeText(form.id);
|
||||
navigator.clipboard.writeText(capturePostUrl);
|
||||
toast("Copied form url to clipboard");
|
||||
}}>
|
||||
copy
|
||||
@@ -268,212 +272,7 @@ export default function FormOverviewPage() {
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
) : activeTab.id === "react" ? (
|
||||
<div>
|
||||
<div className="mt-5 grid grid-cols-5 gap-8">
|
||||
<div className="col-span-3 rounded-md bg-black p-4 text-sm font-light text-gray-200">
|
||||
<pre>
|
||||
<code className="language-js whitespace-pre-wrap">
|
||||
{`import { Form, Text, Email, Checkbox, Submit, sendToHq } from "@formbricks/react";
|
||||
import "@formbricks/react/styles.css";
|
||||
|
||||
export default function WaitlistForm() {
|
||||
return (
|
||||
<Form formId="${form.id}" hqUrl="${window.location.protocol}//${window.location.host}" onSubmit={sendToHq}>
|
||||
<Text name="name" label="What's your name?" validation="required" />
|
||||
<Email
|
||||
name="email"
|
||||
label="What's your email address?"
|
||||
placeholder="you@example.com"
|
||||
validation="required|email"
|
||||
/>
|
||||
<Checkbox
|
||||
name="terms"
|
||||
label="Terms & Conditions"
|
||||
help="To use our service, please accept."
|
||||
validation="accepted"
|
||||
/>
|
||||
<Submit label="Let's go!" />
|
||||
</Form>
|
||||
);
|
||||
}`}
|
||||
</code>
|
||||
</pre>
|
||||
</div>
|
||||
<div className="col-span-2">
|
||||
<h3 className="block text-lg font-semibold text-slate-800">Formbricks React</h3>
|
||||
<p className="my-3 text-sm text-gray-600">
|
||||
The best way to send submissions to Formbricks HQ in React is{" "}
|
||||
<Link
|
||||
target="_blank"
|
||||
className="underline"
|
||||
href="https://www.npmjs.com/package/@formbricks/react">
|
||||
Formbricks React.
|
||||
</Link>{" "}
|
||||
It makes form creation easy and automatically creates a schema to get a full picture of your
|
||||
data in the Summary tab.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="mt-5 grid grid-cols-5 gap-8">
|
||||
<div className="col-span-3 rounded-md bg-black p-4 text-sm font-light text-gray-200">
|
||||
<pre>
|
||||
<code className="language-js whitespace-pre-wrap">
|
||||
{`
|
||||
<form
|
||||
onSubmit={(e) => {
|
||||
e.preventDefault();
|
||||
fetch(
|
||||
"${window.location.protocol}//${window.location.host}/api/capture/forms/${form.id}/submissions",
|
||||
{
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
data: {
|
||||
firstname: e.target.firstname.value,
|
||||
email: e.target.email.value,
|
||||
},
|
||||
}),
|
||||
}
|
||||
);
|
||||
console.log("submission sent!");
|
||||
e.target.reset();
|
||||
}}
|
||||
>
|
||||
<label htmlFor="firstname">First name</label>
|
||||
<input type="text" name="firstname" id="firstname" />
|
||||
<label htmlFor="email">Email</label>
|
||||
<input type="email" name="email" id="email" placeholder="you@example.com" />
|
||||
|
||||
<button type="submit">Submit</button>
|
||||
</form>`}
|
||||
</code>
|
||||
</pre>
|
||||
</div>
|
||||
<div className="col-span-2">
|
||||
<h3 className="block text-lg font-semibold text-slate-800">Standard React Forms</h3>
|
||||
<p className="my-3 text-sm text-gray-600">
|
||||
You can also use the default React Form functionality (or another form library) to send the
|
||||
submissions to Formbricks HQ.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
) : activeTab.id === "vue" ? (
|
||||
<div>
|
||||
<div className="mt-5 grid grid-cols-5 gap-8">
|
||||
<div className="col-span-3 rounded-md bg-black p-4 text-sm font-light text-gray-200">
|
||||
<pre>
|
||||
<code className="language-js whitespace-pre-wrap">
|
||||
{`<template>
|
||||
<form @submit.prevent="submitForm">
|
||||
<label>
|
||||
<span>Email</span>
|
||||
<input type="email" name="email" v-model="email" />
|
||||
</label>
|
||||
<label>
|
||||
<span>Message</span>
|
||||
<textarea name="message" v-model="message"></textarea>
|
||||
</label>
|
||||
<button type="submit">Submit</button>
|
||||
</form>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
email: '',
|
||||
message: '',
|
||||
endpoint: '${window.location.protocol}//${window.location.host}/capture/forms/${form.id}/submissions',
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async submitForm() {
|
||||
const data = {
|
||||
email: this.email,
|
||||
message: this.message,
|
||||
}
|
||||
const response = await this.$axios.post(this.endpoint, {data})
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>`}
|
||||
</code>
|
||||
</pre>
|
||||
</div>
|
||||
<div className="col-span-2">
|
||||
<h3 className="block text-lg font-semibold text-slate-800">Standard Vue Forms</h3>
|
||||
<p className="my-3 text-sm text-gray-600">
|
||||
You can also use the default Vue form functionality to send submissions to Formbricks HQ.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
) : null}
|
||||
|
||||
{/* <div className="mt-16">
|
||||
<h2 className="text-xl font-bold text-slate-800">Code your form</h2>
|
||||
<div className="">
|
||||
<p className="text-slate-800">
|
||||
Build your form with the code library of your choice. Manage your data in this dashboard.
|
||||
</p>
|
||||
</div>
|
||||
<ul role="list" className="mt-3 grid grid-cols-1 gap-5 sm:grid-cols-2 sm:gap-6">
|
||||
{libs.map((lib) => (
|
||||
<Link
|
||||
key={lib.id}
|
||||
href={lib.href}
|
||||
className={clsx(
|
||||
"col-span-1 flex rounded-md shadow-sm",
|
||||
lib.disabled && "pointer-events-none"
|
||||
)}
|
||||
target={lib.target || ""}
|
||||
rel="noreferrer">
|
||||
<li
|
||||
className={clsx(
|
||||
lib.comingSoon ? "text-slate-500" : "text-slate-800 shadow-sm hover:text-black",
|
||||
"col-span-1 flex w-full rounded-md"
|
||||
)}>
|
||||
<div
|
||||
className={clsx(
|
||||
lib.bgColor || "bg-slate-300",
|
||||
"flex w-20 flex-shrink-0 items-center justify-center rounded-l-md text-sm font-medium text-white"
|
||||
)}>
|
||||
<lib.icon
|
||||
className={clsx(lib.comingSoon ? "text-slate-100" : "stroke-1 text-white", "h-10 w-10")}
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
className={clsx(
|
||||
lib.comingSoon ? "border-dashed" : "",
|
||||
"flex flex-1 items-center justify-between truncate rounded-r-md bg-white"
|
||||
)}>
|
||||
<div className="inline-flex truncate px-4 py-6 text-lg">
|
||||
<p className="font-light">{lib.name}</p>
|
||||
{lib.comingSoon && (
|
||||
<div className="ml-3 rounded bg-teal-100 p-1 px-3">
|
||||
<p className="text-xs text-black">coming soon</p>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
</Link>
|
||||
))}
|
||||
</ul>
|
||||
|
||||
<div className="my-12 text-center font-light text-slate-500">
|
||||
<p>
|
||||
Your form is running? Go to{" "}
|
||||
<Link href={`/forms/${form.id}/preview`} className="text-red underline">
|
||||
Pipelines
|
||||
</Link>
|
||||
</p>
|
||||
</div>
|
||||
</div> */}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
@@ -10,7 +10,6 @@ export default function SubmissionDisplay({ schema, submission }) {
|
||||
{Object.entries(MergeWithSchema(submission.data, schema)).map(([key, value]) => (
|
||||
<li key={key} className="py-5">
|
||||
<p className="text-sm font-semibold text-gray-800">{key}</p>
|
||||
|
||||
<p
|
||||
className={clsx(
|
||||
value ? "text-gray-600" : "text-gray-400",
|
||||
|
||||
@@ -1,18 +1,17 @@
|
||||
"use client";
|
||||
|
||||
import SubmissionDisplay from "@/components/forms/submissions/SubmissionDisplay";
|
||||
import LoadingSpinner from "@/components/LoadingSpinner";
|
||||
import { useForm } from "@/lib/forms";
|
||||
import { deleteSubmission, useSubmissions } from "@/lib/submissions";
|
||||
import { convertDateTimeString } from "@/lib/utils";
|
||||
import { RadioGroup } from "@headlessui/react";
|
||||
import { TrashIcon } from "@heroicons/react/24/outline";
|
||||
import { useEffect, useState } from "react";
|
||||
import { toast } from "react-toastify";
|
||||
import { convertDateTimeString } from "@/lib/utils";
|
||||
import LoadingSpinner from "@/components/LoadingSpinner";
|
||||
import type { Submission } from "@prisma/client";
|
||||
import clsx from "clsx";
|
||||
import SubmissionDisplay from "@/components/forms/submissions/SubmissionDisplay";
|
||||
import { format } from "path";
|
||||
import { useForm } from "@/lib/forms";
|
||||
import { useRouter } from "next/router";
|
||||
import { useEffect, useState } from "react";
|
||||
import { toast } from "react-toastify";
|
||||
|
||||
export default function SubmissionsPage() {
|
||||
const router = useRouter();
|
||||
|
||||
@@ -4,6 +4,7 @@ import AnalyticsCard from "@/components/AnalyticsCard";
|
||||
import LoadingSpinner from "@/components/LoadingSpinner";
|
||||
import { useForm } from "@/lib/forms";
|
||||
import { useSubmissions } from "@/lib/submissions";
|
||||
import { capitalizeFirstLetter } from "@/lib/utils";
|
||||
import { useWorkspace } from "@/lib/workspaces";
|
||||
import { Bar, Nps, Table } from "@formbricks/charts";
|
||||
import { ExclamationTriangleIcon } from "@heroicons/react/20/solid";
|
||||
@@ -35,6 +36,10 @@ export default function SummaryPage() {
|
||||
if (isErrorForm || isErrorWorkspace) {
|
||||
return <div>Error loading ressources. Maybe you don‘t have enough access rights</div>;
|
||||
}
|
||||
|
||||
{
|
||||
console.log(JSON.stringify(submissions, null, 2));
|
||||
}
|
||||
return (
|
||||
<div className="mx-auto py-8 sm:px-6 lg:px-8">
|
||||
<header className="mb-8">
|
||||
@@ -53,7 +58,7 @@ export default function SummaryPage() {
|
||||
<div className="w-full border-t border-gray-300" />
|
||||
</div>
|
||||
<div className="relative flex justify-center">
|
||||
<span className="bg-white px-3 text-lg font-medium text-gray-900">Questions & Answers</span>
|
||||
<span className="bg-gray-50 px-3 text-lg font-medium text-gray-900">Questions & Answers</span>
|
||||
</div>
|
||||
</div>
|
||||
{Object.keys(form.schema).length === 0 ? (
|
||||
@@ -82,43 +87,59 @@ export default function SummaryPage() {
|
||||
</div>
|
||||
) : (
|
||||
<div className="grid grid-cols-1 divide-y">
|
||||
{form.schema.children
|
||||
.filter((e) => e.type !== "submit")
|
||||
.map((elem) => (
|
||||
<div className="py-12">
|
||||
{["email", "number", "phone", "search", "text", "textarea", "url"].includes(elem.type) ? (
|
||||
<div>
|
||||
<h2 className="mb-6 text-xl font-bold leading-tight tracking-tight text-gray-900">
|
||||
{elem.label}
|
||||
<span className="text-brand-dark ml-4 inline-flex items-center rounded-md border border-teal-100 bg-teal-50 px-2.5 py-0.5 text-sm font-medium">
|
||||
Checkbox
|
||||
</span>
|
||||
</h2>
|
||||
<Table submissions={submissions} schema={form.schema} fieldName={elem.name} />
|
||||
</div>
|
||||
) : ["checkbox", "radio"].includes(elem.type) ? (
|
||||
<div>
|
||||
<h2 className="mb-6 text-xl font-bold leading-tight tracking-tight text-gray-900">
|
||||
{elem.label}
|
||||
<span className="text-brand-dark ml-4 inline-flex items-center rounded-md border border-teal-100 bg-teal-50 px-2.5 py-0.5 text-sm font-medium">
|
||||
{elem.type}
|
||||
</span>
|
||||
</h2>
|
||||
<Bar submissions={submissions} schema={form.schema} fieldName={elem.name} />
|
||||
</div>
|
||||
) : ["nps"].includes(elem.type) ? (
|
||||
<div>
|
||||
<h2 className="mb-6 text-xl font-bold leading-tight tracking-tight text-gray-900">
|
||||
{elem.label}
|
||||
<span className="text-brand-dark ml-4 inline-flex items-center rounded-md border border-teal-100 bg-teal-50 px-2.5 py-0.5 text-sm font-medium">
|
||||
{elem.type}
|
||||
</span>
|
||||
</h2>
|
||||
<Nps submissions={submissions} schema={form.schema} fieldName={elem.name} />
|
||||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
))}
|
||||
{form.schema.pages.map((page) =>
|
||||
page.elements
|
||||
.filter((e) =>
|
||||
[
|
||||
"checkbox",
|
||||
"email",
|
||||
"number",
|
||||
"nps",
|
||||
"phone",
|
||||
"radio",
|
||||
"search",
|
||||
"text",
|
||||
"textarea",
|
||||
"url",
|
||||
].includes(e.type)
|
||||
)
|
||||
.map((elem) => (
|
||||
<div className="py-12">
|
||||
{["email", "number", "phone", "search", "text", "textarea", "url"].includes(elem.type) ? (
|
||||
<div>
|
||||
<h2 className="mb-6 text-xl font-bold leading-tight tracking-tight text-gray-900">
|
||||
{elem.label}
|
||||
<span className="text-brand-dark ml-4 inline-flex items-center rounded-md border border-teal-100 bg-teal-50 px-2.5 py-0.5 text-sm font-medium">
|
||||
{capitalizeFirstLetter(elem.type)}
|
||||
</span>
|
||||
</h2>
|
||||
<Table submissions={submissions} schema={form.schema} fieldName={elem.name} />
|
||||
</div>
|
||||
) : ["checkbox", "radio"].includes(elem.type) ? (
|
||||
<div>
|
||||
<h2 className="mb-6 text-xl font-bold leading-tight tracking-tight text-gray-900">
|
||||
{elem.label}
|
||||
<span className="text-brand-dark ml-4 inline-flex items-center rounded-md border border-teal-100 bg-teal-50 px-2.5 py-0.5 text-sm font-medium">
|
||||
{capitalizeFirstLetter(elem.type)}
|
||||
</span>
|
||||
</h2>
|
||||
<Bar submissions={submissions} schema={form.schema} fieldName={elem.name} />
|
||||
</div>
|
||||
) : ["nps"].includes(elem.type) ? (
|
||||
<div>
|
||||
<h2 className="mb-6 text-xl font-bold leading-tight tracking-tight text-gray-900">
|
||||
{elem.label}
|
||||
<span className="text-brand-dark ml-4 inline-flex items-center rounded-md border border-teal-100 bg-teal-50 px-2.5 py-0.5 text-sm font-medium">
|
||||
{capitalizeFirstLetter(elem.type)}
|
||||
</span>
|
||||
</h2>
|
||||
<Nps submissions={submissions} schema={form.schema} fieldName={elem.name} />
|
||||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
))
|
||||
)}
|
||||
{}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@@ -12,6 +12,7 @@ import { Fragment } from "react";
|
||||
import { ToastContainer } from "react-toastify";
|
||||
import LoadingSpinner from "@/components/LoadingSpinner";
|
||||
import { Logo } from "../Logo";
|
||||
import Head from "next/head";
|
||||
|
||||
export default function LayoutApp({ children }) {
|
||||
const userNavigation = [
|
||||
@@ -36,13 +37,16 @@ export default function LayoutApp({ children }) {
|
||||
}
|
||||
|
||||
if (!session) {
|
||||
console.log("no sessions");
|
||||
router.push(`/auth/signin?callbackUrl=${encodeURIComponent(window.location.href)}`);
|
||||
return <div></div>;
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<Head>
|
||||
<title>Formbricks</title>
|
||||
<meta name="description" content="Build user research into your product" />
|
||||
</Head>
|
||||
<div className="h-screen">
|
||||
<Disclosure as="nav" className="border-b border-gray-200 bg-white">
|
||||
{({ open }) => (
|
||||
|
||||
+6
-6
@@ -7,29 +7,29 @@ import { usePathname } from "next/navigation";
|
||||
import { useRouter } from "next/router";
|
||||
import { useMemo } from "react";
|
||||
|
||||
export default function LayoutWrapperForm({ children }) {
|
||||
export default function LayoutWrapperCustomForm({ children }) {
|
||||
const router = useRouter();
|
||||
const pathname = usePathname();
|
||||
const navigation = useMemo(
|
||||
() => [
|
||||
{
|
||||
name: "Form",
|
||||
href: `/workspaces/${router.query.workspaceId}/forms/${router.query.formId}/`,
|
||||
current: pathname.endsWith(router.query.formId?.toString()),
|
||||
href: `/workspaces/${router.query.workspaceId}/forms/${router.query.formId}/custom/`,
|
||||
current: pathname.endsWith("custom") || pathname.endsWith("custom/"),
|
||||
},
|
||||
{
|
||||
name: "Pipelines",
|
||||
href: `/workspaces/${router.query.workspaceId}/forms/${router.query.formId}/pipelines/`,
|
||||
href: `/workspaces/${router.query.workspaceId}/forms/${router.query.formId}/custom/pipelines/`,
|
||||
current: pathname.includes("pipelines"),
|
||||
},
|
||||
{
|
||||
name: "Summary",
|
||||
href: `/workspaces/${router.query.workspaceId}/forms/${router.query.formId}/summary/`,
|
||||
href: `/workspaces/${router.query.workspaceId}/forms/${router.query.formId}/custom/summary/`,
|
||||
current: pathname.includes("summary"),
|
||||
},
|
||||
{
|
||||
name: "Submissions",
|
||||
href: `/workspaces/${router.query.workspaceId}/forms/${router.query.formId}/submissions/`,
|
||||
href: `/workspaces/${router.query.workspaceId}/forms/${router.query.formId}/custom/submissions/`,
|
||||
current: pathname.includes("submissions"),
|
||||
},
|
||||
],
|
||||
@@ -44,15 +44,54 @@ export const MergeWithSchema = (submissionData, schema) => {
|
||||
return submissionData;
|
||||
}
|
||||
const mergedData = {};
|
||||
for (const elem of schema.children) {
|
||||
if (["submit"].includes(elem.type)) {
|
||||
continue;
|
||||
}
|
||||
if (elem.name in submissionData) {
|
||||
mergedData[elem.label] = submissionData[elem.name];
|
||||
} else {
|
||||
mergedData[elem.label] = "not provided";
|
||||
const optionLabelMap = getOptionLabelMap(schema);
|
||||
for (const page of schema.pages) {
|
||||
for (const elem of page.elements) {
|
||||
if (
|
||||
![
|
||||
"checkbox",
|
||||
"email",
|
||||
"number",
|
||||
"nps",
|
||||
"phone",
|
||||
"radio",
|
||||
"search",
|
||||
"text",
|
||||
"textarea",
|
||||
"url",
|
||||
"scale",
|
||||
].includes(elem.type)
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
if (elem.name in submissionData) {
|
||||
if (["checkbox", "radio"].includes(elem.type)) {
|
||||
if (Array.isArray(submissionData[elem.name])) {
|
||||
mergedData[elem.label] = submissionData[elem.name].map((value) => optionLabelMap[value] || value);
|
||||
} else {
|
||||
mergedData[elem.label] = optionLabelMap[submissionData[elem.name]] || submissionData[elem.name];
|
||||
}
|
||||
} else {
|
||||
mergedData[elem.label] = submissionData[elem.name];
|
||||
}
|
||||
} else {
|
||||
mergedData[elem.label] = "not provided";
|
||||
}
|
||||
}
|
||||
}
|
||||
return mergedData;
|
||||
};
|
||||
|
||||
const getOptionLabelMap = (schema) => {
|
||||
const optionLabelMap = {};
|
||||
for (const page of schema.pages) {
|
||||
for (const elem of page.elements) {
|
||||
if (elem.options && elem.options.length > 0) {
|
||||
for (const option of elem.options) {
|
||||
optionLabelMap[option.value] = option.label;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return optionLabelMap;
|
||||
};
|
||||
|
||||
@@ -92,3 +92,7 @@ export const parseUserAgent = (userAgent: string) => {
|
||||
const info = platform.parse(userAgent);
|
||||
return info.description;
|
||||
};
|
||||
|
||||
export const capitalizeFirstLetter = (string) => {
|
||||
return string.charAt(0).toUpperCase() + string.slice(1);
|
||||
};
|
||||
|
||||
@@ -0,0 +1,88 @@
|
||||
import { runPipelines } from "@/lib/pipelinesHandler";
|
||||
import { capturePosthogEvent } from "@/lib/posthog";
|
||||
import { captureTelemetry } from "@/lib/telemetry";
|
||||
import { prisma } from "@formbricks/database";
|
||||
import type { NextApiRequest, NextApiResponse } from "next";
|
||||
import NextCors from "nextjs-cors";
|
||||
|
||||
export default async function handle(req: NextApiRequest, res: NextApiResponse) {
|
||||
await NextCors(req, res, {
|
||||
// Options
|
||||
methods: ["GET", "HEAD", "PUT", "PATCH", "POST", "DELETE"],
|
||||
origin: "*",
|
||||
optionsSuccessStatus: 200, // some legacy browsers (IE11, various SmartTVs) choke on 204
|
||||
});
|
||||
|
||||
const formId = req.query.formId.toString();
|
||||
const submissionId = req.query.submissionId.toString();
|
||||
|
||||
// PUT /capture/forms/[formId]/submissions/[submissionId]
|
||||
// Extend an existing form submission
|
||||
// Required fields in body: -
|
||||
// Optional fields in body: customerId, data
|
||||
if (req.method === "PUT") {
|
||||
const submission = req.body;
|
||||
|
||||
// get form
|
||||
const form = await prisma.form.findUnique({
|
||||
where: { id: formId },
|
||||
});
|
||||
|
||||
const prevSubmission = await prisma.submission.findUnique({
|
||||
where: { id: submissionId },
|
||||
});
|
||||
|
||||
if (prevSubmission === null) {
|
||||
return res.status(404).json({ message: "Submission not found" });
|
||||
}
|
||||
|
||||
if (typeof prevSubmission.data !== "object") {
|
||||
prevSubmission.data = {};
|
||||
}
|
||||
|
||||
const event: any = {
|
||||
where: { id: submissionId },
|
||||
data: {
|
||||
data: { ...prevSubmission.data, ...submission.data },
|
||||
meta: { userAgent: req.headers["user-agent"] },
|
||||
},
|
||||
};
|
||||
|
||||
if (submission.customer && "email" in submission.customer) {
|
||||
const customerEmail = submission.customer.email;
|
||||
const customerData = { ...submission.customer };
|
||||
delete customerData.email;
|
||||
// create or link customer
|
||||
event.data.customer = {
|
||||
connectOrCreate: {
|
||||
where: {
|
||||
email_workspaceId: {
|
||||
email: submission.customer.email,
|
||||
workspaceId: form.workspaceId,
|
||||
},
|
||||
},
|
||||
create: {
|
||||
email: customerEmail,
|
||||
workspace: { connect: { id: form.workspaceId } },
|
||||
data: customerData,
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
// create form in db
|
||||
const submissionResult = await prisma.submission.update(event);
|
||||
await runPipelines(form, submission);
|
||||
// tracking
|
||||
capturePosthogEvent(form.workspaceId, "submission received", {
|
||||
formId,
|
||||
});
|
||||
captureTelemetry("submission received");
|
||||
res.json(submissionResult);
|
||||
}
|
||||
|
||||
// Unknown HTTP Method
|
||||
else {
|
||||
throw new Error(`The HTTP ${req.method} method is not supported by this route.`);
|
||||
}
|
||||
}
|
||||
@@ -35,21 +35,21 @@ export default async function handle(req: NextApiRequest, res: NextApiResponse)
|
||||
},
|
||||
};
|
||||
|
||||
if (submission.customer && "id" in submission.customer) {
|
||||
const customerId = submission.customer.id;
|
||||
if (submission.customer && "email" in submission.customer) {
|
||||
const customerEmail = submission.customer.email;
|
||||
const customerData = { ...submission.customer };
|
||||
delete customerData.id;
|
||||
delete customerData.email;
|
||||
// create or link customer
|
||||
event.data.customer = {
|
||||
connectOrCreate: {
|
||||
where: {
|
||||
id_workspaceId: {
|
||||
id: submission.customer.id,
|
||||
email_workspaceId: {
|
||||
email: submission.customer.email,
|
||||
workspaceId: form.workspaceId,
|
||||
},
|
||||
},
|
||||
create: {
|
||||
id: customerId,
|
||||
email: customerEmail,
|
||||
workspace: { connect: { id: form.workspaceId } },
|
||||
data: customerData,
|
||||
},
|
||||
|
||||
+10
-10
@@ -11,7 +11,7 @@ export default async function handle(req: NextApiRequest, res: NextApiResponse)
|
||||
|
||||
const workspaceId = req.query.workspaceId.toString();
|
||||
|
||||
const customerId = req.query.customerId.toString();
|
||||
const customerEmail = req.query.customerEmail.toString();
|
||||
|
||||
// check workspace permission
|
||||
const membership = await prisma.membership.findUnique({
|
||||
@@ -28,13 +28,13 @@ export default async function handle(req: NextApiRequest, res: NextApiResponse)
|
||||
.json({ message: "You don't have access to this workspace or this workspace doesn't exist" });
|
||||
}
|
||||
|
||||
// GET /api/workspaces[workspaceId]/customers/[customerId]
|
||||
// GET /api/workspaces[workspaceId]/customers/[customerEmail]
|
||||
// Get a specific workspace
|
||||
if (req.method === "GET") {
|
||||
const customer = await prisma.customer.findUnique({
|
||||
where: {
|
||||
id_workspaceId: {
|
||||
id: customerId,
|
||||
email_workspaceId: {
|
||||
email: customerEmail,
|
||||
workspaceId,
|
||||
},
|
||||
},
|
||||
@@ -46,14 +46,14 @@ export default async function handle(req: NextApiRequest, res: NextApiResponse)
|
||||
return res.json(customer);
|
||||
}
|
||||
|
||||
// POST /api/workspaces[workspaceId]/customer/[customerId]
|
||||
// POST /api/workspaces[workspaceId]/customer/[customerEmail]
|
||||
// Replace a specific customer
|
||||
else if (req.method === "POST") {
|
||||
const data = { ...req.body, updatedAt: new Date() };
|
||||
const prismaRes = await prisma.customer.update({
|
||||
where: {
|
||||
id_workspaceId: {
|
||||
id: customerId,
|
||||
email_workspaceId: {
|
||||
email: customerEmail,
|
||||
workspaceId,
|
||||
},
|
||||
},
|
||||
@@ -62,13 +62,13 @@ export default async function handle(req: NextApiRequest, res: NextApiResponse)
|
||||
return res.json(prismaRes);
|
||||
}
|
||||
|
||||
// Delete /api/workspaces[workspaceId]/customer/[customerId]
|
||||
// Delete /api/workspaces[workspaceId]/customer/[customerEmail]
|
||||
// Deletes a single customer
|
||||
else if (req.method === "DELETE") {
|
||||
const prismaRes = await prisma.customer.delete({
|
||||
where: {
|
||||
id_workspaceId: {
|
||||
id: customerId,
|
||||
email_workspaceId: {
|
||||
email: customerEmail,
|
||||
workspaceId: workspaceId,
|
||||
},
|
||||
},
|
||||
+4
-4
@@ -1,14 +1,14 @@
|
||||
import PipelinesPage from "@/components/forms/pipelines/PipelinesOverview";
|
||||
import FormOverviewPage from "@/components/forms/custom/FormOverviewPage";
|
||||
import LayoutApp from "@/components/layout/LayoutApp";
|
||||
import LayoutWrapperForm from "@/components/layout/LayoutWrapperForm";
|
||||
import LayoutWrapperForm from "@/components/layout/LayoutWrapperCustomForm";
|
||||
import LayoutWrapperWorkspace from "@/components/layout/LayoutWrapperWorkspace";
|
||||
|
||||
export default function Pipeline({}) {
|
||||
export default function FormOverview({}) {
|
||||
return (
|
||||
<LayoutApp>
|
||||
<LayoutWrapperWorkspace>
|
||||
<LayoutWrapperForm>
|
||||
<PipelinesPage />
|
||||
<FormOverviewPage />
|
||||
</LayoutWrapperForm>
|
||||
</LayoutWrapperWorkspace>
|
||||
</LayoutApp>
|
||||
@@ -0,0 +1,18 @@
|
||||
import PipelinesPage from "@/components/forms/pipelines/PipelinesOverview";
|
||||
import LayoutApp from "@/components/layout/LayoutApp";
|
||||
import LayoutWrapperCustomForm from "@/components/layout/LayoutWrapperCustomForm";
|
||||
import LayoutWrapperWorkspace from "@/components/layout/LayoutWrapperWorkspace";
|
||||
|
||||
export default function Pipeline({}) {
|
||||
return (
|
||||
<LayoutApp>
|
||||
<LayoutWrapperWorkspace>
|
||||
<LayoutWrapperCustomForm>
|
||||
<div className="p-5">
|
||||
<PipelinesPage />
|
||||
</div>
|
||||
</LayoutWrapperCustomForm>
|
||||
</LayoutWrapperWorkspace>
|
||||
</LayoutApp>
|
||||
);
|
||||
}
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
import SubmissionsPage from "@/components/forms/submissions/SubmissionsPage";
|
||||
import LayoutApp from "@/components/layout/LayoutApp";
|
||||
import LayoutWrapperForm from "@/components/layout/LayoutWrapperForm";
|
||||
import LayoutWrapperForm from "@/components/layout/LayoutWrapperCustomForm";
|
||||
import LayoutWrapperWorkspace from "@/components/layout/LayoutWrapperWorkspace";
|
||||
|
||||
export default function Submissions({}) {
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
import SummaryPage from "@/components/forms/summary/SummaryPage";
|
||||
import LayoutApp from "@/components/layout/LayoutApp";
|
||||
import LayoutWrapperForm from "@/components/layout/LayoutWrapperForm";
|
||||
import LayoutWrapperForm from "@/components/layout/LayoutWrapperCustomForm";
|
||||
import LayoutWrapperWorkspace from "@/components/layout/LayoutWrapperWorkspace";
|
||||
|
||||
export default function Submissions({}) {
|
||||
@@ -1,6 +1,6 @@
|
||||
import FormOverviewPage from "@/components/forms/FormOverviewPage";
|
||||
import FormOverviewPage from "@/components/forms/custom/FormOverviewPage";
|
||||
import LayoutApp from "@/components/layout/LayoutApp";
|
||||
import LayoutWrapperForm from "@/components/layout/LayoutWrapperForm";
|
||||
import LayoutWrapperForm from "@/components/layout/LayoutWrapperCustomForm";
|
||||
import LayoutWrapperWorkspace from "@/components/layout/LayoutWrapperWorkspace";
|
||||
|
||||
export default function FormOverview({}) {
|
||||
|
||||
@@ -18,10 +18,22 @@ export function FbBar({ color, submissions, schema, fieldName }: Props) {
|
||||
}
|
||||
// build data object by finding schema definition of field and scanning submissions for this key
|
||||
const dataDict: any = {};
|
||||
const schemaElem = schema.children.find((e: any) => e.name === fieldName);
|
||||
let schemaElem;
|
||||
for (const pages of schema.pages) {
|
||||
for (const elem of pages.elements) {
|
||||
if (elem.name === fieldName) {
|
||||
schemaElem = elem;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (typeof schemaElem === "undefined") {
|
||||
throw Error("key not found in schema");
|
||||
}
|
||||
console.log(schemaElem);
|
||||
if (!("options" in schemaElem)) {
|
||||
throw Error(`No options found for element "${schemaElem.name}"`);
|
||||
}
|
||||
for (const option of schemaElem.options) {
|
||||
dataDict[option.value] = { name: option.label, value: 0 };
|
||||
}
|
||||
|
||||
@@ -18,7 +18,15 @@ export function Nps({ color, submissions, schema, fieldName }: Props) {
|
||||
}
|
||||
// build data object by finding schema definition of field and scanning submissions for this key
|
||||
const dataDict: any = {};
|
||||
const schemaElem = schema.children.find((e: any) => e.name === fieldName);
|
||||
let schemaElem;
|
||||
for (const pages of schema.pages) {
|
||||
for (const elem of pages.elements) {
|
||||
if (elem.name === fieldName) {
|
||||
schemaElem = elem;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (typeof schemaElem === "undefined") {
|
||||
throw Error("key not found in schema");
|
||||
}
|
||||
|
||||
@@ -12,7 +12,15 @@ export function Table({ submissions, schema, fieldName }: Props) {
|
||||
return [];
|
||||
}
|
||||
// check if fieldName in schema
|
||||
const schemaElem = schema.children.find((e: any) => e.name === fieldName);
|
||||
let schemaElem;
|
||||
for (const pages of schema.pages) {
|
||||
for (const elem of pages.elements) {
|
||||
if (elem.name === fieldName) {
|
||||
schemaElem = elem;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (typeof schemaElem === "undefined") {
|
||||
throw Error("key not found in schema");
|
||||
}
|
||||
|
||||
+5
-5
@@ -5,7 +5,7 @@ CREATE TYPE "PipelineType" AS ENUM ('webhook', 'emailNotification', 'slackNotifi
|
||||
CREATE TYPE "PipelineEvent" AS ENUM ('submissionCreated');
|
||||
|
||||
-- CreateEnum
|
||||
CREATE TYPE "FormType" AS ENUM ('feedback');
|
||||
CREATE TYPE "FormType" AS ENUM ('custom', 'feedback');
|
||||
|
||||
-- CreateEnum
|
||||
CREATE TYPE "MembershipRole" AS ENUM ('member', 'admin', 'owner');
|
||||
@@ -30,13 +30,13 @@ CREATE TABLE "Pipeline" (
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "Customer" (
|
||||
"id" TEXT NOT NULL,
|
||||
"email" TEXT NOT NULL,
|
||||
"created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updated_at" TIMESTAMP(3) NOT NULL,
|
||||
"workspaceId" TEXT NOT NULL,
|
||||
"data" JSONB NOT NULL DEFAULT '{}',
|
||||
|
||||
CONSTRAINT "Customer_pkey" PRIMARY KEY ("id","workspaceId")
|
||||
CONSTRAINT "Customer_pkey" PRIMARY KEY ("email","workspaceId")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
@@ -59,7 +59,7 @@ CREATE TABLE "Submission" (
|
||||
"updated_at" TIMESTAMP(3) NOT NULL,
|
||||
"archived" BOOLEAN NOT NULL DEFAULT false,
|
||||
"formId" TEXT NOT NULL,
|
||||
"customerId" TEXT,
|
||||
"customerEmail" TEXT,
|
||||
"customerWorkspaceId" TEXT,
|
||||
"data" JSONB NOT NULL DEFAULT '{}',
|
||||
"meta" JSONB NOT NULL DEFAULT '{}',
|
||||
@@ -159,7 +159,7 @@ ALTER TABLE "Form" ADD CONSTRAINT "Form_workspaceId_fkey" FOREIGN KEY ("workspac
|
||||
ALTER TABLE "Submission" ADD CONSTRAINT "Submission_formId_fkey" FOREIGN KEY ("formId") REFERENCES "Form"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "Submission" ADD CONSTRAINT "Submission_customerId_customerWorkspaceId_fkey" FOREIGN KEY ("customerId", "customerWorkspaceId") REFERENCES "Customer"("id", "workspaceId") ON DELETE SET NULL ON UPDATE CASCADE;
|
||||
ALTER TABLE "Submission" ADD CONSTRAINT "Submission_customerEmail_customerWorkspaceId_fkey" FOREIGN KEY ("customerEmail", "customerWorkspaceId") REFERENCES "Customer"("email", "workspaceId") ON DELETE SET NULL ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "Membership" ADD CONSTRAINT "Membership_workspaceId_fkey" FOREIGN KEY ("workspaceId") REFERENCES "Workspace"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
@@ -35,7 +35,7 @@ model Pipeline {
|
||||
}
|
||||
|
||||
model Customer {
|
||||
id String
|
||||
email String
|
||||
createdAt DateTime @default(now()) @map(name: "created_at")
|
||||
updatedAt DateTime @updatedAt @map(name: "updated_at")
|
||||
workspace Workspace @relation(fields: [workspaceId], references: [id], onDelete: Cascade)
|
||||
@@ -43,10 +43,11 @@ model Customer {
|
||||
submissions Submission[]
|
||||
data Json @default("{}")
|
||||
|
||||
@@id([id, workspaceId])
|
||||
@@id([email, workspaceId])
|
||||
}
|
||||
|
||||
enum FormType {
|
||||
custom
|
||||
feedback
|
||||
}
|
||||
|
||||
@@ -70,8 +71,8 @@ model Submission {
|
||||
archived Boolean @default(false)
|
||||
form Form @relation(fields: [formId], references: [id], onDelete: Cascade)
|
||||
formId String
|
||||
customer Customer? @relation(fields: [customerId, customerWorkspaceId], references: [id, workspaceId])
|
||||
customerId String?
|
||||
customer Customer? @relation(fields: [customerEmail, customerWorkspaceId], references: [email, workspaceId])
|
||||
customerEmail String?
|
||||
customerWorkspaceId String?
|
||||
data Json @default("{}")
|
||||
meta Json @default("{}")
|
||||
|
||||
@@ -0,0 +1,146 @@
|
||||
export function AngryBirdRage2Icon(props: any) {
|
||||
return (
|
||||
<svg width="79" height="75" viewBox="0 0 79 75" fill="none" xmlns="http://www.w3.org/2000/svg" {...props}>
|
||||
<path
|
||||
d="M70.1683 50C70.1683 66.4 56.4144 73.4375 39.4459 73.4375C22.4774 73.4375 8.72339 66.4 8.72339 50C8.72339 33.6 22.4806 10.9375 39.4459 10.9375C56.4111 10.9375 70.1683 33.6062 70.1683 50Z"
|
||||
fill="#00E6CA"
|
||||
/>
|
||||
<path
|
||||
d="M39.4457 23.4375C54.2216 23.4375 66.5591 40.625 69.502 55.8906C69.9564 53.9582 70.1799 51.9817 70.1682 50C70.1682 33.6063 56.4142 10.9375 39.4457 10.9375C22.4772 10.9375 8.72323 33.6063 8.72323 50C8.7131 51.9816 8.9366 53.9579 9.38942 55.8906C12.3355 40.625 24.673 23.4375 39.4457 23.4375Z"
|
||||
fill="#C4F0EB"
|
||||
/>
|
||||
<path
|
||||
d="M70.1683 50C70.1683 66.4 56.4144 73.4375 39.4459 73.4375C22.4774 73.4375 8.72339 66.4 8.72339 50C8.72339 33.6 22.4806 10.9375 39.4459 10.9375C56.4111 10.9375 70.1683 33.6062 70.1683 50Z"
|
||||
stroke="#00303E"
|
||||
stroke-width="1.66667"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
/>
|
||||
<path
|
||||
d="M29.5239 56L38.2168 65.8031C38.3686 65.9747 38.557 66.1124 38.7692 66.2068C38.9813 66.3012 39.2121 66.3501 39.4457 66.3501C39.6792 66.3501 39.91 66.3012 40.1222 66.2068C40.3343 66.1124 40.5228 65.9747 40.6746 65.8031L49.3674 56"
|
||||
fill="#00E6CA"
|
||||
/>
|
||||
<path
|
||||
d="M29.5239 56L38.2168 65.8031C38.3686 65.9747 38.557 66.1124 38.7692 66.2068C38.9813 66.3012 39.2121 66.3501 39.4457 66.3501C39.6792 66.3501 39.91 66.3012 40.1222 66.2068C40.3343 66.1124 40.5228 65.9747 40.6746 65.8031L49.3674 56"
|
||||
stroke="#00303E"
|
||||
stroke-width="1.66667"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
/>
|
||||
<path
|
||||
d="M30.9826 28.2407C29.6749 27.9941 28.3204 28.1438 27.104 28.6693C25.8877 29.1948 24.8691 30.0705 24.1872 31.1766C23.5054 32.2827 23.1937 33.5653 23.2948 34.849C23.3958 36.1328 23.9047 37.3551 24.7518 38.3488C25.5989 39.3425 26.7429 40.0592 28.0275 40.4009C29.312 40.7426 30.6745 40.6926 31.9285 40.2577C33.1826 39.8229 34.2671 39.0244 35.0337 37.9715C35.8004 36.9186 36.2119 35.6625 36.2119 34.3751C36.213 33.3778 35.9657 32.3949 35.4907 31.5094"
|
||||
fill="white"
|
||||
/>
|
||||
<path
|
||||
d="M30.9826 28.2407C29.6749 27.9941 28.3204 28.1438 27.104 28.6693C25.8877 29.1948 24.8691 30.0705 24.1872 31.1766C23.5054 32.2827 23.1937 33.5653 23.2948 34.849C23.3958 36.1328 23.9047 37.3551 24.7518 38.3488C25.5989 39.3425 26.7429 40.0592 28.0275 40.4009C29.312 40.7426 30.6745 40.6926 31.9285 40.2577C33.1826 39.8229 34.2671 39.0244 35.0337 37.9715C35.8004 36.9186 36.2119 35.6625 36.2119 34.3751C36.213 33.3778 35.9657 32.3949 35.4907 31.5094"
|
||||
stroke="#00303E"
|
||||
stroke-width="1.66667"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
/>
|
||||
<path
|
||||
d="M47.909 28.2407C49.2167 27.9941 50.5712 28.1438 51.7875 28.6693C53.0039 29.1948 54.0225 30.0705 54.7044 31.1766C55.3862 32.2827 55.6979 33.5653 55.5968 34.849C55.4958 36.1328 54.9869 37.3551 54.1398 38.3488C53.2927 39.3425 52.1487 40.0592 50.8641 40.4009C49.5796 40.7426 48.2171 40.6926 46.9631 40.2577C45.709 39.8229 44.6245 39.0244 43.8579 37.9715C43.0912 36.9186 42.6797 35.6625 42.6797 34.3751C42.6786 33.3778 42.9259 32.3949 43.4009 31.5094"
|
||||
fill="white"
|
||||
/>
|
||||
<path
|
||||
d="M47.909 28.2407C49.2167 27.9941 50.5712 28.1438 51.7875 28.6693C53.0039 29.1948 54.0225 30.0705 54.7044 31.1766C55.3862 32.2827 55.6979 33.5653 55.5968 34.849C55.4958 36.1328 54.9869 37.3551 54.1398 38.3488C53.2927 39.3425 52.1487 40.0592 50.8641 40.4009C49.5796 40.7426 48.2171 40.6926 46.9631 40.2577C45.709 39.8229 44.6245 39.0244 43.8579 37.9715C43.0912 36.9186 42.6797 35.6625 42.6797 34.3751C42.6786 33.3778 42.9259 32.3949 43.4009 31.5094"
|
||||
stroke="#00303E"
|
||||
stroke-width="1.66667"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
/>
|
||||
<path
|
||||
d="M25.5722 54.2156C25.3243 54.1002 25.111 53.9255 24.9525 53.7082C24.794 53.4908 24.6955 53.238 24.6663 52.9736C24.6372 52.7092 24.6783 52.4419 24.7859 52.1972C24.8935 51.9525 25.0639 51.7383 25.2811 51.575C28.819 48.9125 36.1083 43.75 39.4458 43.75C42.7832 43.75 50.0725 48.9125 53.6105 51.5625C53.8276 51.7258 53.998 51.94 54.1056 52.1847C54.2132 52.4294 54.2544 52.6967 54.2252 52.9611C54.1961 53.2255 54.0976 53.4783 53.9391 53.6957C53.7806 53.913 53.5673 54.0877 53.3194 54.2031C48.9386 56.4845 44.2772 58.2223 39.4458 59.375C34.615 58.2262 29.9536 56.4927 25.5722 54.2156Z"
|
||||
fill="#00E6CA"
|
||||
/>
|
||||
<path
|
||||
d="M39.4458 59.375C34.615 58.2262 29.9536 56.4927 25.5722 54.2156C25.3243 54.1002 25.111 53.9255 24.9525 53.7082C24.794 53.4908 24.6955 53.238 24.6663 52.9736C24.6372 52.7092 24.6783 52.4419 24.7859 52.1972C24.8935 51.9525 25.0639 51.7383 25.2811 51.575C28.819 48.9125 36.1083 43.75 39.4458 43.75V59.375Z"
|
||||
fill="#C4F0EB"
|
||||
/>
|
||||
<path
|
||||
d="M25.5722 54.2156C25.3243 54.1002 25.111 53.9255 24.9525 53.7082C24.794 53.4908 24.6955 53.238 24.6663 52.9736C24.6372 52.7092 24.6783 52.4419 24.7859 52.1972C24.8935 51.9525 25.0639 51.7383 25.2811 51.575C28.819 48.9125 36.1083 43.75 39.4458 43.75C42.7832 43.75 50.0725 48.9125 53.6105 51.5625C53.8276 51.7258 53.998 51.94 54.1056 52.1847C54.2132 52.4294 54.2544 52.6967 54.2252 52.9611C54.1961 53.2255 54.0976 53.4783 53.9391 53.6957C53.7806 53.913 53.5673 54.0877 53.3194 54.2031C48.9386 56.4845 44.2772 58.2223 39.4458 59.375C34.615 58.2262 29.9536 56.4927 25.5722 54.2156V54.2156Z"
|
||||
stroke="#00303E"
|
||||
stroke-width="1.66667"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
/>
|
||||
<path
|
||||
d="M30.9275 12.8469L20.042 7.8125"
|
||||
stroke="#00303E"
|
||||
stroke-width="1.66667"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
/>
|
||||
<path
|
||||
d="M33.8349 11.7687L26.51 1.5625"
|
||||
stroke="#00303E"
|
||||
stroke-width="1.66667"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
/>
|
||||
<path
|
||||
d="M26.51 25L39.4458 34.375L52.3816 25"
|
||||
stroke="#00303E"
|
||||
stroke-width="1.66667"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
/>
|
||||
<path
|
||||
d="M29.7439 33.5938C29.9583 33.5938 30.164 33.6761 30.3156 33.8226C30.4672 33.9691 30.5524 34.1678 30.5524 34.375"
|
||||
stroke="#00303E"
|
||||
stroke-width="1.66667"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
/>
|
||||
<path
|
||||
d="M28.9355 34.375C28.9355 34.1678 29.0207 33.9691 29.1723 33.8226C29.324 33.6761 29.5296 33.5938 29.744 33.5938"
|
||||
stroke="#00303E"
|
||||
stroke-width="1.66667"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
/>
|
||||
<path
|
||||
d="M29.744 35.1562C29.5296 35.1562 29.324 35.0739 29.1723 34.9274C29.0207 34.7809 28.9355 34.5822 28.9355 34.375"
|
||||
stroke="#00303E"
|
||||
stroke-width="1.66667"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
/>
|
||||
<path
|
||||
d="M30.5524 34.375C30.5524 34.5822 30.4672 34.7809 30.3156 34.9274C30.164 35.0739 29.9583 35.1562 29.7439 35.1562"
|
||||
stroke="#00303E"
|
||||
stroke-width="1.66667"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
/>
|
||||
<path
|
||||
d="M49.1476 33.5938C48.9332 33.5938 48.7275 33.6761 48.5759 33.8226C48.4243 33.9691 48.3391 34.1678 48.3391 34.375"
|
||||
stroke="#00303E"
|
||||
stroke-width="1.66667"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
/>
|
||||
<path
|
||||
d="M49.9562 34.375C49.9562 34.1678 49.871 33.9691 49.7194 33.8226C49.5678 33.6761 49.3621 33.5938 49.1477 33.5938"
|
||||
stroke="#00303E"
|
||||
stroke-width="1.66667"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
/>
|
||||
<path
|
||||
d="M49.1477 35.1562C49.3621 35.1562 49.5678 35.0739 49.7194 34.9274C49.871 34.7809 49.9562 34.5822 49.9562 34.375"
|
||||
stroke="#00303E"
|
||||
stroke-width="1.66667"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
/>
|
||||
<path
|
||||
d="M48.3391 34.375C48.3391 34.5822 48.4243 34.7809 48.5759 34.9274C48.7275 35.0739 48.9332 35.1562 49.1476 35.1562"
|
||||
stroke="#00303E"
|
||||
stroke-width="1.66667"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,142 @@
|
||||
export function AngryBirdRageIcon(props: any) {
|
||||
return (
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" {...props}>
|
||||
<defs />
|
||||
<title>{"video-game-angry-birds"}</title>
|
||||
<path
|
||||
d="M21.5,16c0,5.248-4.253,7.5-9.5,7.5S2.5,21.248,2.5,16,6.754,3.5,12,3.5,21.5,10.754,21.5,16Z"
|
||||
fill="#00e6ca"
|
||||
/>
|
||||
<path
|
||||
d="M12,7.5c4.569,0,8.384,5.5,9.294,10.385A8.293,8.293,0,0,0,21.5,16c0-5.246-4.253-12.5-9.5-12.5S2.5,10.754,2.5,16a8.35,8.35,0,0,0,.206,1.885C3.617,13,7.432,7.5,12,7.5Z"
|
||||
fill="#c4f0eb"
|
||||
/>
|
||||
<path
|
||||
d="M21.5,16c0,5.248-4.253,7.5-9.5,7.5S2.5,21.248,2.5,16,6.754,3.5,12,3.5,21.5,10.754,21.5,16Z"
|
||||
stroke="#0f172a"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
fill="none"
|
||||
/>
|
||||
<path
|
||||
d="M8.932,17.92l2.688,3.137a.5.5,0,0,0,.76,0l2.688-3.137"
|
||||
fill="#00e6ca"
|
||||
stroke="#0f172a"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
<path
|
||||
d="M9.383,9.037A2,2,0,1,0,11,11a1.988,1.988,0,0,0-.223-.917"
|
||||
fill="#f8fafc"
|
||||
stroke="#0f172a"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
<path
|
||||
d="M14.617,9.037A2,2,0,1,1,13,11a1.988,1.988,0,0,1,.223-.917"
|
||||
fill="#f8fafc"
|
||||
stroke="#0f172a"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
<path
|
||||
d="M7.71,17.349a.5.5,0,0,1-.09-.845C8.714,15.652,10.968,14,12,14s3.286,1.652,4.38,2.5a.5.5,0,0,1-.09.845A18.278,18.278,0,0,1,12,19,18.278,18.278,0,0,1,7.71,17.349Z"
|
||||
fill="#00e6ca"
|
||||
/>
|
||||
<path
|
||||
d="M12,19a18.278,18.278,0,0,1-4.29-1.651.5.5,0,0,1-.09-.845C8.714,15.652,10.968,14,12,14Z"
|
||||
fill="#c4f0eb"
|
||||
/>
|
||||
<path
|
||||
d="M7.71,17.349a.5.5,0,0,1-.09-.845C8.714,15.652,10.968,14,12,14s3.286,1.652,4.38,2.5a.5.5,0,0,1-.09.845A18.278,18.278,0,0,1,12,19,18.278,18.278,0,0,1,7.71,17.349Z"
|
||||
stroke="#0f172a"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
fill="none"
|
||||
/>
|
||||
<line
|
||||
x1={9.366}
|
||||
y1={4.111}
|
||||
x2={6}
|
||||
y2={2.5}
|
||||
stroke="#0f172a"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
fill="none"
|
||||
/>
|
||||
<line
|
||||
x1={10.265}
|
||||
y1={3.766}
|
||||
x2={8}
|
||||
y2={0.5}
|
||||
stroke="#0f172a"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
fill="none"
|
||||
/>
|
||||
<polyline
|
||||
points="8 8 12 11 16 8"
|
||||
stroke="#0f172a"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
fill="none"
|
||||
/>
|
||||
<path
|
||||
d="M9,10.75a.25.25,0,0,1,.25.25"
|
||||
stroke="#0f172a"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
fill="none"
|
||||
/>
|
||||
<path
|
||||
d="M8.75,11A.25.25,0,0,1,9,10.75"
|
||||
stroke="#0f172a"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
fill="none"
|
||||
/>
|
||||
<path
|
||||
d="M9,11.25A.25.25,0,0,1,8.75,11"
|
||||
stroke="#0f172a"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
fill="none"
|
||||
/>
|
||||
<path
|
||||
d="M9.25,11a.25.25,0,0,1-.25.25"
|
||||
stroke="#0f172a"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
fill="none"
|
||||
/>
|
||||
<path
|
||||
d="M15,10.75a.25.25,0,0,0-.25.25"
|
||||
stroke="#0f172a"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
fill="none"
|
||||
/>
|
||||
<path
|
||||
d="M15.25,11a.25.25,0,0,0-.25-.25"
|
||||
stroke="#0f172a"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
fill="none"
|
||||
/>
|
||||
<path
|
||||
d="M15,11.25a.25.25,0,0,0,.25-.25"
|
||||
stroke="#0f172a"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
fill="none"
|
||||
/>
|
||||
<path
|
||||
d="M14.75,11a.25.25,0,0,0,.25.25"
|
||||
stroke="#0f172a"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
fill="none"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
export function BellIcon(props: any) {
|
||||
return (
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" {...props}>
|
||||
<defs />
|
||||
<path
|
||||
d="M15,20.5a3,3,0,1,1-6,0Z"
|
||||
stroke="#0f172a"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
fill="#00e6ca"
|
||||
/>
|
||||
<path
|
||||
d="M20.5,17.5V11a8.5,8.5,0,0,0-5.541-7.959,3,3,0,0,0-5.922,0A8.493,8.493,0,0,0,3.5,11v6.5a3,3,0,0,1-3,3h23A3,3,0,0,1,20.5,17.5Z"
|
||||
fill="#00e6ca"
|
||||
/>
|
||||
<path d="M12,.5A3,3,0,0,0,9.037,3.044,8.5,8.5,0,0,0,3.5,11v6.5a3,3,0,0,1-3,3H12Z" fill="#c4f0eb" />
|
||||
<path
|
||||
d="M20.5,17.5V11a8.5,8.5,0,0,0-5.541-7.959,3,3,0,0,0-5.922,0A8.493,8.493,0,0,0,3.5,11v6.5a3,3,0,0,1-3,3h23A3,3,0,0,1,20.5,17.5Z"
|
||||
fill="none"
|
||||
stroke="#0f172a"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,222 @@
|
||||
export function BugBlueIcon(props: any) {
|
||||
return (
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" {...props}>
|
||||
<defs />
|
||||
<title>{"flying-insect-ladybug"}</title>
|
||||
<path d="M16,6.436V4.5a4,4,0,0,0-8,0V6.436" fill="#00e6ca" />
|
||||
<path
|
||||
d="M12,.5a4,4,0,0,0-4,4V6.436h.04a3.977,3.977,0,0,1,7.92,0H16V4.5A4,4,0,0,0,12,.5Z"
|
||||
fill="#00e6ca"
|
||||
/>
|
||||
<path
|
||||
d="M16,6.436V4.5a4,4,0,0,0-8,0V6.436"
|
||||
stroke="#0f172a"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
fill="none"
|
||||
/>
|
||||
<circle cx={12} cy={14.5} r={9} fill="#c4f0eb" />
|
||||
<path d="M12,19.115a9,9,0,0,1-8.72-6.808,9,9,0,1,0,17.44,0A9,9,0,0,1,12,19.115Z" fill="#00e6ca" />
|
||||
<line
|
||||
x1={9.115}
|
||||
y1={1.73}
|
||||
x2={8.5}
|
||||
y2={0.5}
|
||||
stroke="#0f172a"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
fill="none"
|
||||
/>
|
||||
<line
|
||||
x1={14.885}
|
||||
y1={1.73}
|
||||
x2={15.5}
|
||||
y2={0.5}
|
||||
stroke="#0f172a"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
fill="none"
|
||||
/>
|
||||
<circle
|
||||
cx={12}
|
||||
cy={14.5}
|
||||
r={3.5}
|
||||
stroke="#0f172a"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
fill="#00e6ca"
|
||||
/>
|
||||
<path
|
||||
d="M17.319,21.75a2.5,2.5,0,0,1,3-3.793"
|
||||
fill="#00e6ca"
|
||||
stroke="#0f172a"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
<path
|
||||
d="M20.286,10.98a2.679,2.679,0,0,1-1.036.228,2.5,2.5,0,0,1-2-4"
|
||||
stroke="#0f172a"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
fill="#00e6ca"
|
||||
/>
|
||||
<path
|
||||
d="M6.719,21.789a2.629,2.629,0,0,0,.532-1.541,2.5,2.5,0,0,0-2.5-2.5A2.763,2.763,0,0,0,3.7,17.98"
|
||||
fill="#00e6ca"
|
||||
stroke="#0f172a"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
<path
|
||||
d="M3.713,10.983a2.677,2.677,0,0,0,1.037.225,2.5,2.5,0,0,0,2-4"
|
||||
stroke="#0f172a"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
fill="#00e6ca"
|
||||
/>
|
||||
<polyline
|
||||
points="18.383 8.156 20 6 21.5 6"
|
||||
stroke="#0f172a"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
fill="none"
|
||||
/>
|
||||
<polyline
|
||||
points="18.391 20.837 19.5 22.5 21 22.5"
|
||||
stroke="#0f172a"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
fill="none"
|
||||
/>
|
||||
<polyline
|
||||
points="5.617 8.156 4 6 2.5 6"
|
||||
stroke="#0f172a"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
fill="none"
|
||||
/>
|
||||
<polyline
|
||||
points="5.609 20.837 4.5 22.5 3 22.5"
|
||||
stroke="#0f172a"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
fill="none"
|
||||
/>
|
||||
<line
|
||||
x1={20.678}
|
||||
y1={12.107}
|
||||
x2={22.5}
|
||||
y2={11.5}
|
||||
stroke="#0f172a"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
fill="none"
|
||||
/>
|
||||
<line
|
||||
x1={20.792}
|
||||
y1={16.431}
|
||||
x2={22.5}
|
||||
y2={17}
|
||||
stroke="#0f172a"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
fill="none"
|
||||
/>
|
||||
<line
|
||||
x1={3.322}
|
||||
y1={12.107}
|
||||
x2={1.5}
|
||||
y2={11.5}
|
||||
stroke="#0f172a"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
fill="none"
|
||||
/>
|
||||
<line
|
||||
x1={3.208}
|
||||
y1={16.431}
|
||||
x2={1.5}
|
||||
y2={17}
|
||||
stroke="#0f172a"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
fill="none"
|
||||
/>
|
||||
<path
|
||||
d="M10.25,3a.25.25,0,0,1,.25.25"
|
||||
stroke="#0f172a"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
fill="none"
|
||||
/>
|
||||
<path
|
||||
d="M10,3.25A.25.25,0,0,1,10.25,3"
|
||||
stroke="#0f172a"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
fill="none"
|
||||
/>
|
||||
<path
|
||||
d="M10.25,3.5A.25.25,0,0,1,10,3.25"
|
||||
stroke="#0f172a"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
fill="none"
|
||||
/>
|
||||
<path
|
||||
d="M10.5,3.25a.25.25,0,0,1-.25.25"
|
||||
stroke="#0f172a"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
fill="none"
|
||||
/>
|
||||
<path
|
||||
d="M13.75,3a.25.25,0,0,1,.25.25"
|
||||
stroke="#0f172a"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
fill="none"
|
||||
/>
|
||||
<path
|
||||
d="M13.5,3.25A.25.25,0,0,1,13.75,3"
|
||||
stroke="#0f172a"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
fill="none"
|
||||
/>
|
||||
<path
|
||||
d="M13.75,3.5a.25.25,0,0,1-.25-.25"
|
||||
stroke="#0f172a"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
fill="none"
|
||||
/>
|
||||
<path
|
||||
d="M14,3.25a.25.25,0,0,1-.25.25"
|
||||
stroke="#0f172a"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
fill="none"
|
||||
/>
|
||||
<circle
|
||||
cx={12}
|
||||
cy={14.5}
|
||||
r={9}
|
||||
stroke="#0f172a"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
fill="none"
|
||||
/>
|
||||
<line
|
||||
x1={12}
|
||||
y1={5.5}
|
||||
x2={12}
|
||||
y2={23.5}
|
||||
stroke="#0f172a"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
fill="none"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
export function CancelSubscriptionIcon(props: any) {
|
||||
return (
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" {...props}>
|
||||
<defs />
|
||||
<path
|
||||
d="M21.566,17.945a1,1,0,0,0,0-.894l-.516-1.034a1,1,0,0,1,.062-1l.308-.462a1,1,0,0,0,0-1.11L20.79,12.5H12.605l-.631-4.12-1.138.758a2.994,2.994,0,0,0-.888.922l-3.3,5.361a1.989,1.989,0,0,1-1,.821L2.29,17.5v5a1,1,0,0,0,1,1h6l1.967-.786a3,3,0,0,1,1.111-.214H19.79l1.062-1.065a1,1,0,0,0,.243-1.023l-.175-.521a1,1,0,0,1,.055-.763Z"
|
||||
fill="#c4f0eb"
|
||||
/>
|
||||
<path
|
||||
d="M20.921,19.891a.807.807,0,0,1-.014-.11c-8.23.8-14.712-.906-9.72-10.877l-.351.235a2.979,2.979,0,0,0-.888.921l-3.3,5.361a2,2,0,0,1-1,.821L2.29,17.5v5a1,1,0,0,0,1,1h6l1.967-.786a3,3,0,0,1,1.111-.214H19.79l1.063-1.065a1,1,0,0,0,.242-1.023Z"
|
||||
fill="#c4f0eb"
|
||||
/>
|
||||
<path
|
||||
d="M12.59,12.5,10.873,1.16a.6.6,0,0,1,.6-.66h8.24a.6.6,0,0,1,.593.689L18.607,12.5Z"
|
||||
fill="#c4f0eb"
|
||||
/>
|
||||
<path
|
||||
d="M12.289,10.5,10.875,1.074A.5.5,0,0,1,11.37.5h6.919"
|
||||
stroke="#0f172a"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
fill="none"
|
||||
/>
|
||||
<path
|
||||
d="M14.789,12.5l-.945-9.45a.5.5,0,0,1,.5-.55h6.867a.5.5,0,0,1,.494.574L20.289,12.5"
|
||||
fill="#00e6ca"
|
||||
/>
|
||||
<path
|
||||
d="M12.29,12.5h8.5l.63.945a1,1,0,0,1,0,1.11l-.308.462a1,1,0,0,0-.062,1l.517,1.034a1,1,0,0,1,0,.894l-.592,1.183a1,1,0,0,0-.054.763l.174.521a1,1,0,0,1-.242,1.023L19.79,22.5H12.368a2.992,2.992,0,0,0-1.114.215L9.29,23.5"
|
||||
stroke="#0f172a"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
fill="none"
|
||||
/>
|
||||
<path
|
||||
d="M2.29,17.5l3.358-1.259a2,2,0,0,0,1-.825l3.3-5.357a3.007,3.007,0,0,1,.891-.923l1.135-.757"
|
||||
stroke="#0f172a"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
fill="none"
|
||||
/>
|
||||
<path
|
||||
d="M21.211,2.5H14.344a.5.5,0,0,0-.5.55l.666,6.659,7.054-7.054A.5.5,0,0,0,21.211,2.5Z"
|
||||
fill="#c4f0eb"
|
||||
/>
|
||||
<path
|
||||
d="M14.789,12.5l-.945-9.45a.5.5,0,0,1,.5-.55h6.867a.5.5,0,0,1,.494.574L20.289,12.5"
|
||||
stroke="#0f172a"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
fill="none"
|
||||
/>
|
||||
<path
|
||||
d="M17.54,9a1.25,1.25,0,1,0-1.25-1.25A1.25,1.25,0,0,0,17.54,9Z"
|
||||
fill="#f8fafc"
|
||||
stroke="#0f172a"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
export function CheckMarkIcon(props: any) {
|
||||
return (
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" {...props}>
|
||||
<defs />
|
||||
<circle cx={12} cy={12} r={12} fill="#c4f0eb" />
|
||||
<polyline
|
||||
points="23.5 0.499 7 23.499 0.5 16.999"
|
||||
fill="none"
|
||||
stroke="#0f172a"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
export function CrossMarkIcon(props: any) {
|
||||
return (
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" {...props}>
|
||||
<defs />
|
||||
<circle cx={12} cy={12} r={11} fill="#c4f0eb" />
|
||||
<line
|
||||
x1={23.5}
|
||||
y1={0.5}
|
||||
x2={0.5}
|
||||
y2={23.5}
|
||||
fill="none"
|
||||
stroke="#0f172a"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
<line
|
||||
x1={23.5}
|
||||
y1={23.5}
|
||||
x2={0.5}
|
||||
y2={0.5}
|
||||
fill="none"
|
||||
stroke="#0f172a"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
export function DogChaserIcon(props: any) {
|
||||
return (
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" {...props}>
|
||||
<defs />
|
||||
<title>{"dog-jump"}</title>
|
||||
<path
|
||||
d="M1.8,9.118C3.3,8.618,8.187,7.5,10.687,6.5a40.6,40.6,0,0,0,5-2.5l1.5-2a5.473,5.473,0,0,1,1,2c1.5,0,2,2,2,2l1.321.264a1,1,0,0,1,.733,1.352l-.252.63a.994.994,0,0,1-1.051.621A8.937,8.937,0,0,0,17.687,9a6.813,6.813,0,0,0-3,1.5s3.5-.5,4.5,1c.785,1.177,1,2,0,2.5-1.612.806-3-1-3-1s-3.514,1.172-4.677-.627h0S7.187,13,5.687,14A2.8,2.8,0,0,1,4.68,17.541L2.492,19.157A32.313,32.313,0,0,1,1.8,9.118Z"
|
||||
fill="#00e6ca"
|
||||
/>
|
||||
<path
|
||||
d="M19.74,4.987A1.858,1.858,0,0,0,18.187,4a5.473,5.473,0,0,0-1-2l-1.5,2a40.6,40.6,0,0,1-5,2.5C8.187,7.5,3.3,8.618,1.8,9.118c-.089.891-.123,1.8-.124,2.719C12.4,9.229,16.365,5.166,19.74,4.987Z"
|
||||
fill="#c4f0eb"
|
||||
/>
|
||||
<path
|
||||
d="M11.51,12.373a2.284,2.284,0,0,1-.323-.873"
|
||||
fill="none"
|
||||
stroke="#0f172a"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
<path
|
||||
d="M1.8,9.118C3.3,8.618,8.187,7.5,10.687,6.5a40.6,40.6,0,0,0,5-2.5l1.5-2a5.473,5.473,0,0,1,1,2c1.5,0,2,2,2,2l1.321.264a1,1,0,0,1,.733,1.352l-.252.63a.994.994,0,0,1-1.051.621A8.937,8.937,0,0,0,17.687,9a6.813,6.813,0,0,0-3,1.5s3.5-.5,4.5,1c.785,1.177,1,2,0,2.5-1.612.806-3-1-3-1s-3.514,1.172-4.677-.627h0S7.187,13,5.687,14A2.8,2.8,0,0,1,4.68,17.541"
|
||||
fill="none"
|
||||
stroke="#0f172a"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
<path
|
||||
d="M7.044,5.5c-.55-2.436-1.4-4-2.357-4-1.657,0-3,4.7-3,10.5s1.343,10.5,3,10.5c1.359,0,2.631-2.663,3-7"
|
||||
fill="none"
|
||||
stroke="#0f172a"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
<path
|
||||
d="M17.937,5.5a.25.25,0,0,0-.25.25"
|
||||
fill="none"
|
||||
stroke="#0f172a"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
<path
|
||||
d="M18.187,5.75a.25.25,0,0,0-.25-.25"
|
||||
fill="none"
|
||||
stroke="#0f172a"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
<path
|
||||
d="M17.937,6a.25.25,0,0,0,.25-.25"
|
||||
fill="none"
|
||||
stroke="#0f172a"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
<path
|
||||
d="M17.687,5.75a.25.25,0,0,0,.25.25"
|
||||
fill="none"
|
||||
stroke="#0f172a"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
export function DoorIcon(props: any) {
|
||||
return (
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" {...props}>
|
||||
<defs />
|
||||
<title>{"architecture-door"}</title>
|
||||
<path d="M5,20.5V1.5a1,1,0,0,1,1-1H18a1,1,0,0,1,1,1v19Z" fill="#00e6ca" />
|
||||
<path d="M18,.5H6a1,1,0,0,0-1,1v3a1,1,0,0,1,1-1H18a1,1,0,0,1,1,1v-3A1,1,0,0,0,18,.5Z" fill="#00e6ca" />
|
||||
<circle
|
||||
cx={15.501}
|
||||
cy={11}
|
||||
r={1.5}
|
||||
stroke="#0f172a"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
fill="#00e6ca"
|
||||
/>
|
||||
<path
|
||||
d="M5,20.5V1.5a1,1,0,0,1,1-1H18a1,1,0,0,1,1,1v19"
|
||||
fill="none"
|
||||
stroke="#0f172a"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
<path
|
||||
d="M21,21.5a1,1,0,0,0-1-1H4a1,1,0,0,0-1,1V23a.5.5,0,0,0,.5.5h17A.5.5,0,0,0,21,23Z"
|
||||
stroke="#0f172a"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
fill="#00e6ca"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,143 @@
|
||||
export function EngineerIcon(props: any) {
|
||||
return (
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" {...props}>
|
||||
<defs />
|
||||
<title>{"study-maths-brain"}</title>
|
||||
<path
|
||||
d="M6.851,23.5V21.023H5.932a2.477,2.477,0,0,1-2.478-2.478V16.067H1.343a.5.5,0,0,1-.474-.653c1.1-3.414,2-6.989,4.286-9.081,0,0,2.582-2.559,7.8-1.516s5.46,7.739,5.46,7.739a8.036,8.036,0,0,1-3.3,6.494V23.5Z"
|
||||
fill="#c4f0eb"
|
||||
/>
|
||||
<path
|
||||
d="M10.406,7.61a12.3,12.3,0,0,1,7.62,2.639c-.551-2.042-1.877-4.793-5.07-5.432-5.219-1.043-7.8,1.516-7.8,1.516a11.057,11.057,0,0,0-2.61,4.1A12.318,12.318,0,0,1,10.406,7.61Z"
|
||||
fill="#c4f0eb"
|
||||
/>
|
||||
<line
|
||||
x1={17.656}
|
||||
y1={0.501}
|
||||
x2={17.656}
|
||||
y2={4.501}
|
||||
fill="none"
|
||||
stroke="#0f172a"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
<line
|
||||
x1={19.656}
|
||||
y1={2.501}
|
||||
x2={15.656}
|
||||
y2={2.501}
|
||||
fill="none"
|
||||
stroke="#0f172a"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
<line
|
||||
x1={20.327}
|
||||
y1={6.001}
|
||||
x2={23.156}
|
||||
y2={8.83}
|
||||
fill="none"
|
||||
stroke="#0f172a"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
<line
|
||||
x1={23.156}
|
||||
y1={6.001}
|
||||
x2={20.327}
|
||||
y2={8.83}
|
||||
fill="none"
|
||||
stroke="#0f172a"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
<line
|
||||
x1={15.156}
|
||||
y1={8.497}
|
||||
x2={11.156}
|
||||
y2={8.497}
|
||||
fill="none"
|
||||
stroke="#0f172a"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
<path
|
||||
d="M13.156,6.247a.25.25,0,0,0-.25.25"
|
||||
fill="none"
|
||||
stroke="#0f172a"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
<path
|
||||
d="M13.406,6.5a.25.25,0,0,0-.25-.25"
|
||||
fill="none"
|
||||
stroke="#0f172a"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
<path
|
||||
d="M13.156,6.747a.25.25,0,0,0,.25-.25"
|
||||
fill="none"
|
||||
stroke="#0f172a"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
<path
|
||||
d="M12.906,6.5a.25.25,0,0,0,.25.25"
|
||||
fill="none"
|
||||
stroke="#0f172a"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
<path
|
||||
d="M13.156,10.247a.25.25,0,0,0-.25.25"
|
||||
fill="none"
|
||||
stroke="#0f172a"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
<path
|
||||
d="M13.406,10.5a.25.25,0,0,0-.25-.25"
|
||||
fill="none"
|
||||
stroke="#0f172a"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
<path
|
||||
d="M13.156,10.747a.25.25,0,0,0,.25-.25"
|
||||
fill="none"
|
||||
stroke="#0f172a"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
<path
|
||||
d="M12.906,10.5a.25.25,0,0,0,.25.25"
|
||||
fill="none"
|
||||
stroke="#0f172a"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
<polyline
|
||||
points="7.656 2.001 8.656 3.501 9.656 0.501 13.156 0.501"
|
||||
fill="none"
|
||||
stroke="#0f172a"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
<path
|
||||
d="M6.851,23.5V21.023H5.932a2.477,2.477,0,0,1-2.478-2.478V16.067H1.343a.5.5,0,0,1-.474-.653c1.1-3.414,2-6.989,4.286-9.081"
|
||||
fill="none"
|
||||
stroke="#0f172a"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
<path
|
||||
d="M18.416,12.556a8.036,8.036,0,0,1-3.3,6.494V23.5"
|
||||
fill="none"
|
||||
stroke="#0f172a"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
export function FeatureRequestIcon(props: any) {
|
||||
return (
|
||||
<svg width="75" height="75" viewBox="0 0 75 75" fill="none" xmlns="http://www.w3.org/2000/svg" {...props}>
|
||||
<path
|
||||
d="M23.4375 73.4375L25 54.6875H32.8125V43.75C32.8125 39.606 31.1663 35.6317 28.236 32.7015C25.3058 29.7712 21.3315 28.125 17.1875 28.125C13.0435 28.125 9.06921 29.7712 6.13896 32.7015C3.2087 35.6317 1.5625 39.606 1.5625 43.75V54.6875H9.375L10.9375 73.4375H23.4375Z"
|
||||
fill="#C4F0EB"
|
||||
/>
|
||||
<path
|
||||
d="M17.1875 23.4375C23.2281 23.4375 28.125 18.5406 28.125 12.5C28.125 6.45938 23.2281 1.5625 17.1875 1.5625C11.1469 1.5625 6.25 6.45938 6.25 12.5C6.25 18.5406 11.1469 23.4375 17.1875 23.4375Z"
|
||||
fill="#C4F0EB"
|
||||
/>
|
||||
<path
|
||||
d="M32.8125 43.75V50C32.8125 45.856 31.1663 41.8817 28.236 38.9515C25.3058 36.0212 21.3315 34.375 17.1875 34.375C13.0435 34.375 9.06921 36.0212 6.13896 38.9515C3.2087 41.8817 1.5625 45.856 1.5625 50V43.75C1.5625 39.606 3.2087 35.6317 6.13896 32.7015C9.06921 29.7712 13.0435 28.125 17.1875 28.125C21.3315 28.125 25.3058 29.7712 28.236 32.7015C31.1663 35.6317 32.8125 39.606 32.8125 43.75V43.75Z"
|
||||
fill="white"
|
||||
/>
|
||||
<path
|
||||
d="M28.1251 12.5C28.1295 13.5595 27.9714 14.6134 27.6563 15.625C26.9874 13.3676 25.6066 11.3869 23.72 9.97825C21.8334 8.56963 19.542 7.80857 17.1876 7.80857C14.8331 7.80857 12.5417 8.56963 10.6551 9.97825C8.76854 11.3869 7.38781 13.3676 6.71884 15.625C6.4038 14.6134 6.24571 13.5595 6.25009 12.5C6.25009 9.59919 7.40243 6.8172 9.45361 4.76602C11.5048 2.71484 14.2868 1.5625 17.1876 1.5625C20.0884 1.5625 22.8704 2.71484 24.9216 4.76602C26.9727 6.8172 28.1251 9.59919 28.1251 12.5Z"
|
||||
fill="white"
|
||||
/>
|
||||
<path
|
||||
d="M31.975 38.6934C30.7795 35.1905 28.3792 32.2256 25.2018 30.3272C22.0244 28.4287 18.2762 27.7198 14.6249 28.3268C10.9737 28.9339 7.65647 30.8174 5.26428 33.6419C2.87209 36.4663 1.56027 40.0483 1.5625 43.7497V54.6872H9.375L10.9375 73.4372H23.4375L25 54.6872H28.125"
|
||||
stroke="black"
|
||||
stroke-width="3.2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
/>
|
||||
<path
|
||||
d="M17.1875 23.4375C23.2281 23.4375 28.125 18.5406 28.125 12.5C28.125 6.45938 23.2281 1.5625 17.1875 1.5625C11.1469 1.5625 6.25 6.45938 6.25 12.5C6.25 18.5406 11.1469 23.4375 17.1875 23.4375Z"
|
||||
stroke="black"
|
||||
stroke-width="3.2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
/>
|
||||
<path
|
||||
d="M54.6875 73.4375C58.3959 73.4375 62.021 72.3378 65.1044 70.2776C68.1879 68.2173 70.5911 65.2889 72.0102 61.8628C73.4294 58.4367 73.8007 54.6667 73.0772 51.0296C72.3538 47.3924 70.568 44.0515 67.9458 41.4293C65.3235 38.807 61.9826 37.0213 58.3454 36.2978C54.7083 35.5743 50.9383 35.9456 47.5122 37.3648C44.0861 38.7839 41.1577 41.1871 39.0974 44.2706C37.0372 47.354 35.9375 50.9791 35.9375 54.6875C35.9375 59.6603 37.9129 64.4295 41.4292 67.9458C44.9456 71.4621 49.7147 73.4375 54.6875 73.4375Z"
|
||||
fill="#00E6CA"
|
||||
/>
|
||||
<path
|
||||
d="M54.6873 35.9375C50.8711 35.9345 47.1449 37.0969 44.0074 39.2694C40.8699 41.4419 38.4707 44.5207 37.1308 48.094C35.7908 51.6672 35.5741 55.5645 36.5096 59.2643C37.4451 62.9641 39.4881 66.2899 42.3654 68.7969L68.7967 42.3656C67.042 40.3467 64.8744 38.7279 62.4402 37.619C60.0061 36.51 57.3622 35.9366 54.6873 35.9375V35.9375Z"
|
||||
fill="#C4F0EB"
|
||||
/>
|
||||
<path
|
||||
d="M54.6875 73.4375C58.3959 73.4375 62.021 72.3378 65.1044 70.2776C68.1879 68.2173 70.5911 65.2889 72.0102 61.8628C73.4294 58.4367 73.8007 54.6667 73.0772 51.0296C72.3538 47.3924 70.568 44.0515 67.9458 41.4293C65.3235 38.807 61.9826 37.0213 58.3454 36.2978C54.7083 35.5743 50.9383 35.9456 47.5122 37.3648C44.0861 38.7839 41.1577 41.1871 39.0974 44.2706C37.0372 47.354 35.9375 50.9791 35.9375 54.6875C35.9375 59.6603 37.9129 64.4295 41.4292 67.9458C44.9456 71.4621 49.7147 73.4375 54.6875 73.4375Z"
|
||||
stroke="black"
|
||||
stroke-width="3.2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
/>
|
||||
<path
|
||||
d="M54.6875 45.3125V64.0625"
|
||||
stroke="black"
|
||||
stroke-width="3.2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
/>
|
||||
<path
|
||||
d="M64.0625 54.6875H45.3125"
|
||||
stroke="black"
|
||||
stroke-width="3.2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
export function FeedbackIcon(props: any) {
|
||||
return (
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" {...props}>
|
||||
<defs />
|
||||
<path
|
||||
d="M23.5,6.5c0-3.313-3.358-6-7.5-6s-7.5,2.687-7.5,6c0,3.179,3.092,5.773,7,5.981V16l4.365-4.365A5.88,5.88,0,0,0,23.5,6.5Z"
|
||||
fill="#00e6ca"
|
||||
/>
|
||||
<path
|
||||
d="M16,2.5c3.716,0,6.8,2.163,7.4,5a4.807,4.807,0,0,0,.1-1c0-3.313-3.358-6-7.5-6s-7.5,2.687-7.5,6a4.892,4.892,0,0,0,.1,1C9.2,4.663,12.285,2.5,16,2.5Z"
|
||||
fill="#c4f0eb"
|
||||
/>
|
||||
<path
|
||||
d="M23.5,6.5c0-3.313-3.358-6-7.5-6s-7.5,2.687-7.5,6c0,3.179,3.092,5.773,7,5.981V16l4.365-4.365A5.88,5.88,0,0,0,23.5,6.5Z"
|
||||
stroke="#0f172a"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
fill="none"
|
||||
/>
|
||||
<line
|
||||
x1={12.501}
|
||||
y1={4.5}
|
||||
x2={19.501}
|
||||
y2={4.5}
|
||||
stroke="#0f172a"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
fill="none"
|
||||
/>
|
||||
<line
|
||||
x1={12.501}
|
||||
y1={7.5}
|
||||
x2={17.501}
|
||||
y2={7.5}
|
||||
stroke="#0f172a"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
fill="none"
|
||||
/>
|
||||
<circle
|
||||
cx={3.5}
|
||||
cy={10.25}
|
||||
r={2.25}
|
||||
fill="#c4f0eb"
|
||||
stroke="#0f172a"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
<path
|
||||
d="M3.5,13.5a3,3,0,0,0-3,3v2H2l.5,5h2l.5-5H6.5v-2A3,3,0,0,0,3.5,13.5Z"
|
||||
fill="#c4f0eb"
|
||||
stroke="#0f172a"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
export function FounderIcon(props: any) {
|
||||
return (
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" {...props}>
|
||||
<defs />
|
||||
<title>{"swimming-jump"}</title>
|
||||
<path
|
||||
d="M23.5,23.5h-13l0-.043c1.492.318,2.712-1.229,2.712-1.229h0a2.805,2.805,0,0,0,2.2,1.251,3.216,3.216,0,0,0,2.387-1.251h0a2.327,2.327,0,0,0,2.017,1.251,2.682,2.682,0,0,0,2.2-1.251h0a2.983,2.983,0,0,0,1.47,1.159Z"
|
||||
fill="#00e6ca"
|
||||
/>
|
||||
<path d="M.5,19.5H10a.5.5,0,0,1,.5.5v3.5H.5Z" fill="#c4f0eb" />
|
||||
<circle
|
||||
cx={18}
|
||||
cy={6.15}
|
||||
r={2.5}
|
||||
stroke="#0f172a"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
fill="#c4f0eb"
|
||||
/>
|
||||
<path
|
||||
d="M23.5,23.387a2.983,2.983,0,0,1-1.47-1.159h0a2.682,2.682,0,0,1-2.2,1.251,2.327,2.327,0,0,1-2.017-1.251h0a3.216,3.216,0,0,1-2.387,1.251,2.805,2.805,0,0,1-2.2-1.251h0S12,23.775,10.5,23.457"
|
||||
fill="none"
|
||||
stroke="#0f172a"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
<path
|
||||
d="M.5,19.5H10a.5.5,0,0,1,.5.5v3.5"
|
||||
fill="none"
|
||||
stroke="#0f172a"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
<path
|
||||
d="M5.251,17.5l2.364-3.676L3.062,10.169A1.5,1.5,0,0,1,4,7.5H9.753L6.738,2.811A1.5,1.5,0,1,1,9.26,1.188l4.5,7A1.5,1.5,0,0,1,12.5,10.5H8.266l2.28,1.83a1.5,1.5,0,0,1,.323,1.981L8.818,17.5Z"
|
||||
fill="#00e6ca"
|
||||
/>
|
||||
<path
|
||||
d="M13.4,10.2a1.5,1.5,0,0,0,.365-2.013l-4.5-7A1.5,1.5,0,0,0,7.188.738a1.433,1.433,0,0,0-.126.09Z"
|
||||
fill="#c4f0eb"
|
||||
/>
|
||||
<path
|
||||
d="M5.251,17.5l2.364-3.676L3.062,10.169A1.5,1.5,0,0,1,4,7.5H9.753L6.738,2.811A1.5,1.5,0,1,1,9.26,1.188l4.5,7A1.5,1.5,0,0,1,12.5,10.5H8.266l2.28,1.83a1.5,1.5,0,0,1,.323,1.981L8.818,17.5"
|
||||
fill="none"
|
||||
stroke="#0f172a"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
export function InterviewPromptIcon(props: any) {
|
||||
return (
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" {...props}>
|
||||
<defs />
|
||||
<path d="M1.5,21.5V9A1.5,1.5,0,0,1,3,7.5H19A1.5,1.5,0,0,1,20.5,9V21.5Z" fill="#00e6ca" />
|
||||
<path d="M14.438,7.5H3A1.5,1.5,0,0,0,1.5,9V20.438Z" fill="#c4f0eb" />
|
||||
<path
|
||||
d="M1.5,20.5V9A1.5,1.5,0,0,1,3,7.5h8.5"
|
||||
stroke="#0f172a"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
fill="none"
|
||||
/>
|
||||
<path d="M20.5,9.5v11" stroke="#0f172a" strokeLinecap="round" strokeLinejoin="round" fill="none" />
|
||||
<path
|
||||
d="M13.5,20.5v1h-5v-1H.5v2a1,1,0,0,0,1,1h19a1,1,0,0,0,1-1v-2Z"
|
||||
fill="#c4f0eb"
|
||||
stroke="#0f172a"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
<path
|
||||
d="M16,18.5c-.408-.63-1.761-1.088-3.455-1.715-.479-.178-.4-1.426-.188-1.659a3.532,3.532,0,0,0,.918-2.734A2.188,2.188,0,0,0,11.036,10,2.188,2.188,0,0,0,8.8,12.392a3.526,3.526,0,0,0,.919,2.734c.211.233.29,1.481-.188,1.659-1.7.627-3.048,1.085-3.455,1.715"
|
||||
fill="#f8fafc"
|
||||
stroke="#0f172a"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
<path
|
||||
d="M23.5,1.5l-2,.583V1.5a1,1,0,0,0-1-1h-6a1,1,0,0,0-1,1v5a1,1,0,0,0,1,1h6a1,1,0,0,0,1-1V5.833l2,.667Z"
|
||||
fill="#00e6ca"
|
||||
/>
|
||||
<path d="M14.5.5a1,1,0,0,0-1,1v5a.983.983,0,0,0,.234.62L20.353.5Z" fill="#c4f0eb" />
|
||||
<path
|
||||
d="M23.5,1.5l-2,.583V1.5a1,1,0,0,0-1-1h-6a1,1,0,0,0-1,1v5a1,1,0,0,0,1,1h6a1,1,0,0,0,1-1V5.833l2,.667Z"
|
||||
stroke="#0f172a"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
fill="none"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
export function LaptopWorkerIcon(props: any) {
|
||||
return (
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" {...props}>
|
||||
<defs />
|
||||
<path
|
||||
d="M12,8A3.5,3.5,0,1,0,8.5,4.5,3.5,3.5,0,0,0,12,8Z"
|
||||
stroke="#0f172a"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
fill="#c4f0eb"
|
||||
/>
|
||||
<path
|
||||
d="M16.745,13a4.966,4.966,0,0,0-9.49,0"
|
||||
fill="#00e6ca"
|
||||
stroke="#0f172a"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
<path d="M18.5,23H5.5L3.811,16.243A1,1,0,0,1,4.781,15H19.219a1,1,0,0,1,.97,1.242Z" fill="#c4f0eb" />
|
||||
<path d="M4.781,15a1,1,0,0,0-.97,1.242L5.5,23H7.723l8-8Z" fill="#f8fafc" />
|
||||
<path
|
||||
d="M18.5,23H5.5L3.811,16.243A1,1,0,0,1,4.781,15H19.219a1,1,0,0,1,.97,1.242Z"
|
||||
fill="none"
|
||||
stroke="#0f172a"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
<path d="M1,23H23" fill="none" stroke="#0f172a" strokeLinecap="round" strokeLinejoin="round" />
|
||||
<path d="M12,12v1.5" fill="none" stroke="#0f172a" strokeLinecap="round" strokeLinejoin="round" />
|
||||
<path
|
||||
d="M13.167,4.5a5.831,5.831,0,0,0,2.286-.467,3.478,3.478,0,0,0-6.459-1.3A5.812,5.812,0,0,0,13.167,4.5Z"
|
||||
fill="#00e6ca"
|
||||
stroke="#0f172a"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
<path
|
||||
d="M12,20a1.25,1.25,0,1,0-1.25-1.25A1.25,1.25,0,0,0,12,20Z"
|
||||
fill="#00e6ca"
|
||||
stroke="#0f172a"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
export function OnboardingIcon(props: any) {
|
||||
return (
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" {...props}>
|
||||
<defs />
|
||||
<path
|
||||
d="M9,7.5H7.059A6.059,6.059,0,0,0,1,13.558v4.988c0,1.5.662,2.218,1.97,2.937a.059.059,0,0,1,.03.051V23.5H9Z"
|
||||
fill="#c4f0eb"
|
||||
/>
|
||||
<path
|
||||
d="M8,7.5H7.059A6.059,6.059,0,0,0,1,13.558v4.988c0,1.5.662,2.218,1.97,2.937a.059.059,0,0,1,.03.051V23.5"
|
||||
stroke="#0f172a"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
fill="none"
|
||||
/>
|
||||
<path
|
||||
d="M8,18.824V22.5a1,1,0,0,0,1,1H22a1,1,0,0,0,1-1V1.5a1,1,0,0,0-1-1H17.95a.5.5,0,0,0-.49.4,2,2,0,0,1-3.92,0,.5.5,0,0,0-.49-.4H9a1,1,0,0,0-1,1V18.824Z"
|
||||
fill="#00e6ca"
|
||||
/>
|
||||
<path
|
||||
d="M15.5,2.5A2,2,0,0,1,13.54.9a.5.5,0,0,0-.49-.4H9a1,1,0,0,0-1,1v21a1,1,0,0,0,1,1h6.5Z"
|
||||
fill="#c4f0eb"
|
||||
/>
|
||||
<path
|
||||
d="M13.782,15.4l3.259,1.214,2-1.364a1.109,1.109,0,0,1,.876-.168,1.189,1.189,0,0,1,.852.766,1.106,1.106,0,0,1,.066.378,1.175,1.175,0,0,1-.548,1.018l-6.762,4.2a.415.415,0,0,1-.458-.013l-2.479-1.74a.229.229,0,0,1-.035-.322.234.234,0,0,1,.039-.038l1.04-.918a.231.231,0,0,1,.222-.038l1.3.777,1.653-1.154L12.4,16.5"
|
||||
fill="#f8fafc"
|
||||
stroke="#0f172a"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
<path
|
||||
d="M8,18.824V22.5a1,1,0,0,0,1,1H22a1,1,0,0,0,1-1V1.5a1,1,0,0,0-1-1H17.95a.5.5,0,0,0-.49.4,2,2,0,0,1-3.92,0,.5.5,0,0,0-.49-.4H9a1,1,0,0,0-1,1v11"
|
||||
stroke="#0f172a"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
fill="none"
|
||||
/>
|
||||
<path
|
||||
d="M10.25,7a.25.25,0,1,1-.25.25A.25.25,0,0,1,10.25,7"
|
||||
stroke="#0f172a"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
fill="none"
|
||||
/>
|
||||
<path
|
||||
d="M12.75,7a.25.25,0,1,1-.25.25A.25.25,0,0,1,12.75,7"
|
||||
stroke="#0f172a"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
fill="none"
|
||||
/>
|
||||
<path
|
||||
d="M15.25,7a.25.25,0,1,1-.25.25A.25.25,0,0,1,15.25,7"
|
||||
stroke="#0f172a"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
fill="none"
|
||||
/>
|
||||
<path
|
||||
d="M17.75,7a.25.25,0,1,1-.25.25A.25.25,0,0,1,17.75,7"
|
||||
stroke="#0f172a"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
fill="none"
|
||||
/>
|
||||
<path
|
||||
d="M20.25,7a.25.25,0,1,1-.25.25A.25.25,0,0,1,20.25,7"
|
||||
stroke="#0f172a"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
fill="none"
|
||||
/>
|
||||
<path
|
||||
d="M7,19.467A3.2,3.2,0,0,0,9,16.5h2.847a2.108,2.108,0,0,0,2.133-1.709A2,2,0,0,0,12,12.5H6.5"
|
||||
stroke="#0f172a"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
fill="#c4f0eb"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
export function PMFIcon(props: any) {
|
||||
return (
|
||||
<svg width="59" height="77" viewBox="0 0 59 77" fill="none" xmlns="http://www.w3.org/2000/svg" {...props}>
|
||||
<path
|
||||
d="M50.354 1.60449H8.64567C5.10184 1.60449 2.229 4.47733 2.229 8.02116V68.9795C2.229 72.5233 5.10184 75.3962 8.64567 75.3962H50.354C53.8978 75.3962 56.7707 72.5233 56.7707 68.9795V8.02116C56.7707 4.47733 53.8978 1.60449 50.354 1.60449Z"
|
||||
fill="#C4F0EB"
|
||||
/>
|
||||
<path
|
||||
d="M50.354 67.0544H8.64567C6.94386 67.0544 5.31176 66.3783 4.1084 65.175C2.90504 63.9716 2.229 62.3395 2.229 60.6377V68.9794C2.229 70.6812 2.90504 72.3133 4.1084 73.5166C5.31176 74.72 6.94386 75.396 8.64567 75.396H50.354C52.0558 75.396 53.6879 74.72 54.8913 73.5166C56.0946 72.3133 56.7707 70.6812 56.7707 68.9794V60.6377C56.7707 62.3395 56.0946 63.9716 54.8913 65.175C53.6879 66.3783 52.0558 67.0544 50.354 67.0544Z"
|
||||
fill="#00E6CA"
|
||||
/>
|
||||
<path
|
||||
d="M50.354 1.60449H8.64567C5.10184 1.60449 2.229 4.47733 2.229 8.02116V68.9795C2.229 72.5233 5.10184 75.3962 8.64567 75.3962H50.354C53.8978 75.3962 56.7707 72.5233 56.7707 68.9795V8.02116C56.7707 4.47733 53.8978 1.60449 50.354 1.60449Z"
|
||||
stroke="black"
|
||||
stroke-width="3"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
/>
|
||||
<path
|
||||
d="M45.5415 8.02051H13.4582C12.5722 8.02051 11.854 8.73872 11.854 9.62467V35.2913C11.854 36.1773 12.5722 36.8955 13.4582 36.8955H45.5415C46.4275 36.8955 47.1457 36.1773 47.1457 35.2913V9.62467C47.1457 8.73872 46.4275 8.02051 45.5415 8.02051Z"
|
||||
fill="#00E6CA"
|
||||
/>
|
||||
<path
|
||||
d="M13.4582 8.02051C13.0327 8.02051 12.6247 8.18952 12.3239 8.49036C12.023 8.7912 11.854 9.19922 11.854 9.62467V35.2913C11.854 35.7168 12.023 36.1248 12.3239 36.4257C12.6247 36.7265 13.0327 36.8955 13.4582 36.8955H13.5865L42.4615 8.02051H13.4582Z"
|
||||
fill="#C4F0EB"
|
||||
/>
|
||||
<path
|
||||
d="M45.5415 8.02051H13.4582C12.5722 8.02051 11.854 8.73872 11.854 9.62467V35.2913C11.854 36.1773 12.5722 36.8955 13.4582 36.8955H45.5415C46.4275 36.8955 47.1457 36.1773 47.1457 35.2913V9.62467C47.1457 8.73872 46.4275 8.02051 45.5415 8.02051Z"
|
||||
stroke="black"
|
||||
stroke-width="3"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
/>
|
||||
<path
|
||||
d="M45.5418 54.5417C47.3137 54.5417 48.7502 53.1052 48.7502 51.3333C48.7502 49.5614 47.3137 48.125 45.5418 48.125C43.7699 48.125 42.3335 49.5614 42.3335 51.3333C42.3335 53.1052 43.7699 54.5417 45.5418 54.5417Z"
|
||||
fill="white"
|
||||
stroke="black"
|
||||
stroke-width="3"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
/>
|
||||
<path
|
||||
d="M45.5418 67.3747C47.3137 67.3747 48.7502 65.9383 48.7502 64.1663C48.7502 62.3944 47.3137 60.958 45.5418 60.958C43.7699 60.958 42.3335 62.3944 42.3335 64.1663C42.3335 65.9383 43.7699 67.3747 45.5418 67.3747Z"
|
||||
fill="white"
|
||||
stroke="black"
|
||||
stroke-width="3"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
/>
|
||||
<path
|
||||
d="M21.479 65.7705C26.7947 65.7705 31.104 61.4612 31.104 56.1455C31.104 50.8298 26.7947 46.5205 21.479 46.5205C16.1633 46.5205 11.854 50.8298 11.854 56.1455C11.854 61.4612 16.1633 65.7705 21.479 65.7705Z"
|
||||
fill="#00E6CA"
|
||||
stroke="black"
|
||||
stroke-width="3"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
/>
|
||||
<path
|
||||
d="M27.9857 30.6588L19.875 14.4375"
|
||||
stroke="black"
|
||||
stroke-width="3"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
/>
|
||||
<path
|
||||
d="M23.0835 36.8962C23.0835 35.1944 23.7595 33.5622 24.9629 32.3589C26.1663 31.1555 27.7984 30.4795 29.5002 30.4795C31.202 30.4795 32.8341 31.1555 34.0374 32.3589C35.2408 33.5622 35.9168 35.1944 35.9168 36.8962H23.0835Z"
|
||||
fill="#00E6CA"
|
||||
stroke="black"
|
||||
stroke-width="3"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
/>
|
||||
<path
|
||||
d="M21.479 43.4629V68.9788"
|
||||
stroke="black"
|
||||
stroke-width="3"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
export function SkyscraperIcon(props: any) {
|
||||
return (
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" {...props}>
|
||||
<defs />
|
||||
<title>{"building-modern"}</title>
|
||||
<path d="M11,23.5V1.5a1,1,0,0,1,1-1h8a1,1,0,0,1,1,1V23a.5.5,0,0,1-.5.5Z" fill="#00e6ca" />
|
||||
<path d="M21,6.167V1.5a1,1,0,0,0-1-1H12a1,1,0,0,0-1,1V16.167Z" fill="#c4f0eb" />
|
||||
<path d="M13,23.5H3.5A.5.5,0,0,1,3,23V9.5a1,1,0,0,1,1-1h8a1,1,0,0,1,1,1Z" fill="#00e6ca" />
|
||||
<path d="M13,10.2V9.5a1,1,0,0,0-1-1H4a1,1,0,0,0-1,1V20.2Z" fill="#c4f0eb" />
|
||||
<path
|
||||
d="M13,23.5H3.5A.5.5,0,0,1,3,23V9.5a1,1,0,0,1,1-1h8a1,1,0,0,1,1,1Z"
|
||||
stroke="#0f172a"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
fill="none"
|
||||
/>
|
||||
<path
|
||||
d="M11,8.5v-7a1,1,0,0,1,1-1h8a1,1,0,0,1,1,1V23a.5.5,0,0,1-.5.5H13"
|
||||
stroke="#0f172a"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
fill="none"
|
||||
/>
|
||||
<path
|
||||
d="M19,23.5V21a.5.5,0,0,0-.5-.5h-2a.5.5,0,0,0-.5.5v2.5Z"
|
||||
fill="#f8fafc"
|
||||
stroke="#0f172a"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
<path
|
||||
d="M8,23.5V21a.5.5,0,0,0-.5-.5h-2A.5.5,0,0,0,5,21v2.5Z"
|
||||
fill="#f8fafc"
|
||||
stroke="#0f172a"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
<line
|
||||
x1={3}
|
||||
y1={11.5}
|
||||
x2={7}
|
||||
y2={11.5}
|
||||
stroke="#0f172a"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
fill="none"
|
||||
/>
|
||||
<line
|
||||
x1={11}
|
||||
y1={6.5}
|
||||
x2={15}
|
||||
y2={6.5}
|
||||
stroke="#0f172a"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
fill="none"
|
||||
/>
|
||||
<line
|
||||
x1={11}
|
||||
y1={3.5}
|
||||
x2={17}
|
||||
y2={3.5}
|
||||
stroke="#0f172a"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
fill="none"
|
||||
/>
|
||||
<line
|
||||
x1={3}
|
||||
y1={14.5}
|
||||
x2={5}
|
||||
y2={14.5}
|
||||
stroke="#0f172a"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
fill="none"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
export function UserCommentIcon(props: any) {
|
||||
return (
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" {...props}>
|
||||
<defs />
|
||||
<path
|
||||
d="M12.582,11.3A6.838,6.838,0,0,0,15.5,12.43c0,.57,0,2.57,0,3.07.5-.5,3.5-3,4-3.461a6.015,6.015,0,0,0,4-5.539A6.265,6.265,0,0,0,17,.5c-5.25,0-9.027,5.751-4.417,10.8Z"
|
||||
fill="#00e6ca"
|
||||
/>
|
||||
<path
|
||||
d="M17,2.5a6.373,6.373,0,0,1,6.41,5,5.613,5.613,0,0,0,.09-1A6.265,6.265,0,0,0,17,.5c-3.949,0-7.064,3.253-6.4,7.012A6.365,6.365,0,0,1,17,2.5Z"
|
||||
fill="#c4f0eb"
|
||||
/>
|
||||
<path d="M15.5,14.43h0v.182C15.5,14.541,15.5,14.48,15.5,14.43Z" fill="#c4f0eb" />
|
||||
<path
|
||||
d="M.5,23.5a8.719,8.719,0,0,1,.7-3.322c.49-.981,2.539-1.661,5.111-2.613.695-.258.581-2.074.273-2.413a5.127,5.127,0,0,1-1.336-3.978A3.354,3.354,0,0,1,8.5,7.5a3.354,3.354,0,0,1,3.256,3.674,5.127,5.127,0,0,1-1.336,3.978c-.308.339-.422,2.155.273,2.413,2.572.952,4.621,1.632,5.111,2.613a8.719,8.719,0,0,1,.7,3.322Z"
|
||||
fill="#c4f0eb"
|
||||
/>
|
||||
<path
|
||||
d="M8.5,7.5a3.354,3.354,0,0,0-3.256,3.674A5.127,5.127,0,0,0,6.58,15.152c.308.339.422,2.155-.273,2.413C3.734,18.517,1.686,19.2,1.2,20.178A8.719,8.719,0,0,0,.5,23.5h8Z"
|
||||
fill="#f8fafc"
|
||||
/>
|
||||
<path
|
||||
d="M.5,23.5a8.719,8.719,0,0,1,.7-3.322c.49-.981,2.539-1.661,5.111-2.613.695-.258.581-2.074.273-2.413a5.127,5.127,0,0,1-1.336-3.978A3.354,3.354,0,0,1,8.5,7.5a3.354,3.354,0,0,1,3.256,3.674,5.127,5.127,0,0,1-1.336,3.978c-.308.339-.422,2.155.273,2.413,2.572.952,4.621,1.632,5.111,2.613a8.719,8.719,0,0,1,.7,3.322Z"
|
||||
fill="none"
|
||||
stroke="#0f172a"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
<path
|
||||
d="M13.979,12.034a6.828,6.828,0,0,0,1.521.4c0,.57,0,2.57,0,3.07.5-.5,3.5-3,4-3.461a6.015,6.015,0,0,0,4-5.539A6.265,6.265,0,0,0,17,.5a6.329,6.329,0,0,0-6.467,5.393"
|
||||
fill="none"
|
||||
stroke="#0f172a"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
<path
|
||||
d="M14.25,6.25a.249.249,0,0,1,.25.25h0a.249.249,0,0,1-.25.25h0A.25.25,0,0,1,14,6.5h0a.25.25,0,0,1,.25-.25"
|
||||
fill="none"
|
||||
stroke="#0f172a"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
<line
|
||||
x1={14.25}
|
||||
y1={6.25}
|
||||
x2={14.25}
|
||||
y2={6.25}
|
||||
fill="none"
|
||||
stroke="#0f172a"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
<path
|
||||
d="M17,6.25a.25.25,0,0,1,.25.25h0a.25.25,0,0,1-.25.25h0a.25.25,0,0,1-.25-.25h0A.25.25,0,0,1,17,6.25"
|
||||
fill="none"
|
||||
stroke="#0f172a"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
<line
|
||||
x1={17}
|
||||
y1={6.25}
|
||||
x2={17}
|
||||
y2={6.25}
|
||||
fill="none"
|
||||
stroke="#0f172a"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
<path
|
||||
d="M19.75,6.25A.25.25,0,0,1,20,6.5h0a.25.25,0,0,1-.25.25h0a.25.25,0,0,1-.25-.25h0a.25.25,0,0,1,.25-.25"
|
||||
fill="none"
|
||||
stroke="#0f172a"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
<line
|
||||
x1={19.75}
|
||||
y1={6.25}
|
||||
x2={19.75}
|
||||
y2={6.25}
|
||||
fill="none"
|
||||
stroke="#0f172a"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
export function UserCoupleIcon(props: any) {
|
||||
return (
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" {...props}>
|
||||
<defs />
|
||||
<path d="M14.407,19.385,14.75,23.5h4l.5-6h2.5V14a5,5,0,0,0-8-4" fill="#c4f0eb" />
|
||||
<path
|
||||
d="M16.75,9a4.978,4.978,0,0,0-3,1l.138,1.976a4.986,4.986,0,0,1,7.862,4.087V14A5,5,0,0,0,16.75,9Z"
|
||||
fill="#ffffff"
|
||||
/>
|
||||
<path
|
||||
d="M14.407,19.385,14.75,23.5h4l.5-6h2.5V14a5,5,0,0,0-8-4"
|
||||
fill="none"
|
||||
stroke="#00303e"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
<circle cx={16.75} cy={4} r={3.5} fill="#c4f0eb" />
|
||||
<path d="M9.75,23.5l.5-6h2.5V14a5,5,0,0,0-10,0v3.5h2.5l.5,6Z" fill="#c4f0eb" />
|
||||
<circle cx={7.75} cy={4} r={3.5} fill="#c4f0eb" />
|
||||
<path
|
||||
d="M11.25,4a3.383,3.383,0,0,1-.15,1.01,3.5,3.5,0,0,0-6.7,0A3.383,3.383,0,0,1,4.25,4a3.5,3.5,0,0,1,7,0Z"
|
||||
fill="#ffffff"
|
||||
/>
|
||||
<path d="M7.75,9a5,5,0,0,0-5,5v2.019a5,5,0,0,1,10,0V14A5,5,0,0,0,7.75,9Z" fill="#ffffff" />
|
||||
<path
|
||||
d="M9.75,23.5l.5-6h2.5V14a5,5,0,0,0-10,0v3.5h2.5l.5,6Z"
|
||||
fill="none"
|
||||
stroke="#00303e"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
<circle
|
||||
cx={7.75}
|
||||
cy={4}
|
||||
r={3.5}
|
||||
fill="none"
|
||||
stroke="#00303e"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
<path
|
||||
d="M20.25,4a3.383,3.383,0,0,1-.15,1.01,3.5,3.5,0,0,0-6.7,0A3.383,3.383,0,0,1,13.25,4a3.5,3.5,0,0,1,7,0Z"
|
||||
fill="#ffffff"
|
||||
/>
|
||||
<circle
|
||||
cx={16.75}
|
||||
cy={4}
|
||||
r={3.5}
|
||||
fill="none"
|
||||
stroke="#00303e"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
export function UserGroupIcon(props: any) {
|
||||
return (
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" {...props}>
|
||||
<defs />
|
||||
<circle cx={20} cy={8.25} r={2.75} fill="#c4f0eb" />
|
||||
<path d="M23.5,15.5a3.5,3.5,0,0,0-7,0v3h1.583l.417,5h3l.417-5H23.5Z" fill="#c4f0eb" />
|
||||
<path
|
||||
d="M20,7.736a2.748,2.748,0,0,1,2.508,1.632,2.75,2.75,0,1,0-5.016,0A2.748,2.748,0,0,1,20,7.736Z"
|
||||
fill="#ffffff"
|
||||
/>
|
||||
<path
|
||||
d="M20,12a3.5,3.5,0,0,0-3.5,3.5v2.236a3.5,3.5,0,0,1,7,0V15.5A3.5,3.5,0,0,0,20,12Z"
|
||||
fill="#ffffff"
|
||||
/>
|
||||
<circle
|
||||
cx={20}
|
||||
cy={8.25}
|
||||
r={2.75}
|
||||
fill="none"
|
||||
stroke="#00303e"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
<path
|
||||
d="M23.5,15.5a3.5,3.5,0,0,0-7,0v3h1.583l.417,5h3l.417-5H23.5Z"
|
||||
fill="none"
|
||||
stroke="#00303e"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
<circle cx={12} cy={2.75} r={2.25} fill="#c4f0eb" />
|
||||
<path d="M12,6A3,3,0,0,0,9,9v2.5h1.5L11,16h2l.5-4.5H15V9A3,3,0,0,0,12,6Z" fill="#c4f0eb" />
|
||||
<path
|
||||
d="M12,2.736a2.239,2.239,0,0,1,1.941,1.132A2.224,2.224,0,0,0,14.25,2.75a2.25,2.25,0,0,0-4.5,0,2.224,2.224,0,0,0,.309,1.118A2.239,2.239,0,0,1,12,2.736Z"
|
||||
fill="#ffffff"
|
||||
/>
|
||||
<path d="M12,6A3,3,0,0,0,9,9v2.236a3,3,0,0,1,6,0V9A3,3,0,0,0,12,6Z" fill="#ffffff" />
|
||||
<circle
|
||||
cx={12}
|
||||
cy={2.75}
|
||||
r={2.25}
|
||||
fill="none"
|
||||
stroke="#00303e"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
<path
|
||||
d="M12,6A3,3,0,0,0,9,9v2.5h1.5L11,16h2l.5-4.5H15V9A3,3,0,0,0,12,6Z"
|
||||
fill="none"
|
||||
stroke="#00303e"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
<circle cx={4} cy={8.25} r={2.75} fill="#c4f0eb" />
|
||||
<path d="M7.5,15.5a3.5,3.5,0,0,0-7,0v3H2.083l.417,5h3l.417-5H7.5Z" fill="#c4f0eb" />
|
||||
<path
|
||||
d="M4,7.736A2.748,2.748,0,0,1,6.508,9.368,2.748,2.748,0,1,0,1.25,8.25a2.729,2.729,0,0,0,.242,1.118A2.748,2.748,0,0,1,4,7.736Z"
|
||||
fill="#ffffff"
|
||||
/>
|
||||
<path d="M4,12A3.5,3.5,0,0,0,.5,15.5v2.236a3.5,3.5,0,0,1,7,0V15.5A3.5,3.5,0,0,0,4,12Z" fill="#ffffff" />
|
||||
<circle
|
||||
cx={4}
|
||||
cy={8.25}
|
||||
r={2.75}
|
||||
fill="none"
|
||||
stroke="#00303e"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
<path
|
||||
d="M7.5,15.5a3.5,3.5,0,0,0-7,0v3H2.083l.417,5h3l.417-5H7.5Z"
|
||||
fill="none"
|
||||
stroke="#00303e"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
@@ -1,9 +1,31 @@
|
||||
export * from "./Button";
|
||||
|
||||
/* Icons */
|
||||
export * from "./icons/Back";
|
||||
export * from "./icons/Bug";
|
||||
export * from "./icons/Compliment";
|
||||
export * from "./icons/Customers";
|
||||
export * from "./icons/Form";
|
||||
export * from "./icons/Idea";
|
||||
export * from "./icons/BackIcon";
|
||||
export * from "./icons/BugIcon";
|
||||
export * from "./icons/BugBlueIcon";
|
||||
export * from "./icons/ComplimentIcon";
|
||||
export * from "./icons/CustomersIcon";
|
||||
export * from "./icons/FormIcon";
|
||||
export * from "./icons/PMFIcon";
|
||||
export * from "./icons/IdeaIcon";
|
||||
export * from "./icons/AngryBirdRageIcon";
|
||||
export * from "./icons/AngryBirdRage2Icon";
|
||||
export * from "./icons/CancelSubscriptionIcon";
|
||||
export * from "./icons/DogChaserIcon";
|
||||
export * from "./icons/DoorIcon";
|
||||
export * from "./icons/FeatureRequestIcon";
|
||||
export * from "./icons/FeedbackIcon";
|
||||
export * from "./icons/InterviewPromptIcon";
|
||||
export * from "./icons/OnboardingIcon";
|
||||
export * from "./icons/FounderIcon";
|
||||
export * from "./icons/EngineerIcon";
|
||||
export * from "./icons/LaptopWorkerIcon";
|
||||
export * from "./icons/UserGroupIcon";
|
||||
export * from "./icons/UserCoupleIcon";
|
||||
export * from "./icons/UserCommentIcon";
|
||||
export * from "./icons/LaptopWorkerIcon";
|
||||
export * from "./icons/CrossMarkIcon";
|
||||
export * from "./icons/CheckMarkIcon";
|
||||
export * from "./icons/BellIcon";
|
||||
export * from "./icons/SkyscraperIcon";
|
||||
|
||||
Generated
+297
-111
@@ -10,9 +10,9 @@ importers:
|
||||
turbo: latest
|
||||
devDependencies:
|
||||
'@changesets/cli': 2.25.0
|
||||
prettier: 2.8.1
|
||||
prettier: 2.8.3
|
||||
tsx: 3.9.0
|
||||
turbo: 1.6.3
|
||||
turbo: 1.7.0
|
||||
|
||||
apps/demo:
|
||||
specifiers:
|
||||
@@ -43,7 +43,7 @@ importers:
|
||||
'@heroicons/react': 2.0.13_react@18.2.0
|
||||
'@tailwindcss/forms': 0.5.3_tailwindcss@3.2.4
|
||||
clsx: 1.2.1
|
||||
next: 13.0.7_biqbaboplfbrettd7655fr4n2y
|
||||
next: 13.1.2_biqbaboplfbrettd7655fr4n2y
|
||||
react: 18.2.0
|
||||
react-dom: 18.2.0_react@18.2.0
|
||||
react-toastify: 9.1.1_biqbaboplfbrettd7655fr4n2y
|
||||
@@ -63,6 +63,7 @@ importers:
|
||||
specifiers:
|
||||
'@docsearch/react': ^3.3.0
|
||||
'@formbricks/react': workspace:*
|
||||
'@formbricks/ui': workspace:*
|
||||
'@headlessui/react': ^1.7.3
|
||||
'@heroicons/react': ^2.0.13
|
||||
'@mapbox/rehype-prism': ^0.8.0
|
||||
@@ -87,6 +88,7 @@ importers:
|
||||
prism-react-renderer: ^1.3.5
|
||||
react: 18.2.0
|
||||
react-dom: 18.2.0
|
||||
react-hook-form: ^7.39.1
|
||||
react-responsive-embed: ^2.1.0
|
||||
remark-gfm: ^3.0.1
|
||||
tailwindcss: ^3.2.1
|
||||
@@ -94,6 +96,7 @@ importers:
|
||||
dependencies:
|
||||
'@docsearch/react': 3.3.0_4mdvn5gl4vbbvabne2xxb7fpaa
|
||||
'@formbricks/react': link:../../packages/react
|
||||
'@formbricks/ui': link:../../packages/ui
|
||||
'@headlessui/react': 1.7.4_biqbaboplfbrettd7655fr4n2y
|
||||
'@heroicons/react': 2.0.13_react@18.2.0
|
||||
'@mapbox/rehype-prism': 0.8.0
|
||||
@@ -105,10 +108,11 @@ importers:
|
||||
lottie-web: 5.10.0
|
||||
next: 13.0.0_biqbaboplfbrettd7655fr4n2y
|
||||
next-plausible: 3.6.4_r5sq4deac3rmm2d5onhwvomqve
|
||||
next-sitemap: 3.1.32_o6lqsnjzhz2zhif2mulkhpnbxy
|
||||
next-sitemap: 3.1.32_yinmfuacmj4u57glipxrgw6l3m
|
||||
prism-react-renderer: 1.3.5_react@18.2.0
|
||||
react: 18.2.0
|
||||
react-dom: 18.2.0_react@18.2.0
|
||||
react-hook-form: 7.40.0_react@18.2.0
|
||||
react-responsive-embed: 2.1.0_sh5qlbywuemxd2y3xkrw2y2kr4
|
||||
remark-gfm: 3.0.1
|
||||
devDependencies:
|
||||
@@ -124,79 +128,6 @@ importers:
|
||||
tailwindcss: 3.2.4_postcss@8.4.19
|
||||
typescript: 4.8.4
|
||||
|
||||
apps/hq:
|
||||
specifiers:
|
||||
'@formbricks/charts': workspace:*
|
||||
'@formbricks/database': workspace:*
|
||||
'@formbricks/react': workspace:*
|
||||
'@formbricks/tailwind-config': workspace:*
|
||||
'@formbricks/tsconfig': workspace:*
|
||||
'@formbricks/ui': workspace:*
|
||||
'@headlessui/react': ^1.7.4
|
||||
'@heroicons/react': ^2.0.13
|
||||
'@sentry/nextjs': ^7.24.2
|
||||
'@types/node': ^18.11.9
|
||||
'@types/react': ^18.0.25
|
||||
'@types/react-dom': ^18.0.9
|
||||
'@vercel/analytics': ^0.1.5
|
||||
autoprefixer: ^10.4.13
|
||||
bcryptjs: ^2.4.3
|
||||
clsx: ^1.2.1
|
||||
date-fns: ^2.29.3
|
||||
eslint: ^8.28.0
|
||||
eslint-config-formbricks: workspace:*
|
||||
jsonwebtoken: ^8.5.1
|
||||
next: ^13.0.5
|
||||
next-auth: ^4.17.0
|
||||
nextjs-cors: ^2.1.2
|
||||
nodemailer: ^6.8.0
|
||||
platform: ^1.3.6
|
||||
postcss: ^8.4.19
|
||||
prismjs: ^1.29.0
|
||||
react: ^18.2.0
|
||||
react-dom: ^18.2.0
|
||||
react-icons: ^4.6.0
|
||||
react-loader-spinner: ^5.3.4
|
||||
react-toastify: ^9.1.1
|
||||
swr: ^1.3.0
|
||||
typescript: ^4.9.3
|
||||
dependencies:
|
||||
'@formbricks/charts': link:../../packages/charts
|
||||
'@formbricks/react': link:../../packages/react
|
||||
'@formbricks/ui': link:../../packages/ui
|
||||
'@headlessui/react': 1.7.4_biqbaboplfbrettd7655fr4n2y
|
||||
'@heroicons/react': 2.0.13_react@18.2.0
|
||||
'@sentry/nextjs': 7.24.2_next@13.0.5+react@18.2.0
|
||||
'@vercel/analytics': 0.1.5_react@18.2.0
|
||||
bcryptjs: 2.4.3
|
||||
clsx: 1.2.1
|
||||
date-fns: 2.29.3
|
||||
jsonwebtoken: 8.5.1
|
||||
next: 13.0.5_biqbaboplfbrettd7655fr4n2y
|
||||
next-auth: 4.17.0_2xoejpawkzgot77rbv5mbik6ve
|
||||
nextjs-cors: 2.1.2_next@13.0.5
|
||||
nodemailer: 6.8.0
|
||||
platform: 1.3.6
|
||||
prismjs: 1.29.0
|
||||
react: 18.2.0
|
||||
react-dom: 18.2.0_react@18.2.0
|
||||
react-icons: 4.7.1_react@18.2.0
|
||||
react-loader-spinner: 5.3.4_biqbaboplfbrettd7655fr4n2y
|
||||
react-toastify: 9.1.1_biqbaboplfbrettd7655fr4n2y
|
||||
swr: 1.3.0_react@18.2.0
|
||||
devDependencies:
|
||||
'@formbricks/database': link:../../packages/database
|
||||
'@formbricks/tailwind-config': link:../../packages/tailwind-config
|
||||
'@formbricks/tsconfig': link:../../packages/tsconfig
|
||||
'@types/node': 18.11.10
|
||||
'@types/react': 18.0.25
|
||||
'@types/react-dom': 18.0.9
|
||||
autoprefixer: 10.4.13_postcss@8.4.19
|
||||
eslint: 8.28.0
|
||||
eslint-config-formbricks: link:../../packages/eslint-config-formbricks
|
||||
postcss: 8.4.19
|
||||
typescript: 4.9.3
|
||||
|
||||
apps/storybook:
|
||||
specifiers:
|
||||
'@formbricks/tailwind-config': workspace:*
|
||||
@@ -242,6 +173,79 @@ importers:
|
||||
typescript: 4.9.3
|
||||
vite: 3.2.4
|
||||
|
||||
apps/web:
|
||||
specifiers:
|
||||
'@formbricks/charts': workspace:*
|
||||
'@formbricks/database': workspace:*
|
||||
'@formbricks/react': workspace:*
|
||||
'@formbricks/tailwind-config': workspace:*
|
||||
'@formbricks/tsconfig': workspace:*
|
||||
'@formbricks/ui': workspace:*
|
||||
'@headlessui/react': ^1.7.4
|
||||
'@heroicons/react': ^2.0.13
|
||||
'@sentry/nextjs': ^7.24.2
|
||||
'@types/node': ^18.11.9
|
||||
'@types/react': ^18.0.25
|
||||
'@types/react-dom': ^18.0.9
|
||||
'@vercel/analytics': ^0.1.5
|
||||
autoprefixer: ^10.4.13
|
||||
bcryptjs: ^2.4.3
|
||||
clsx: ^1.2.1
|
||||
date-fns: ^2.29.3
|
||||
eslint: ^8.28.0
|
||||
eslint-config-formbricks: workspace:*
|
||||
jsonwebtoken: ^8.5.1
|
||||
next: ^13.0.5
|
||||
next-auth: ^4.17.0
|
||||
nextjs-cors: ^2.1.2
|
||||
nodemailer: ^6.8.0
|
||||
platform: ^1.3.6
|
||||
postcss: ^8.4.19
|
||||
prismjs: ^1.29.0
|
||||
react: ^18.2.0
|
||||
react-dom: ^18.2.0
|
||||
react-icons: ^4.6.0
|
||||
react-loader-spinner: ^5.3.4
|
||||
react-toastify: ^9.1.1
|
||||
swr: ^1.3.0
|
||||
typescript: ^4.9.3
|
||||
dependencies:
|
||||
'@formbricks/charts': link:../../packages/charts
|
||||
'@formbricks/react': link:../../packages/react
|
||||
'@formbricks/ui': link:../../packages/ui
|
||||
'@headlessui/react': 1.7.4_biqbaboplfbrettd7655fr4n2y
|
||||
'@heroicons/react': 2.0.13_react@18.2.0
|
||||
'@sentry/nextjs': 7.24.2_next@13.0.7+react@18.2.0
|
||||
'@vercel/analytics': 0.1.5_react@18.2.0
|
||||
bcryptjs: 2.4.3
|
||||
clsx: 1.2.1
|
||||
date-fns: 2.29.3
|
||||
jsonwebtoken: 8.5.1
|
||||
next: 13.0.7_biqbaboplfbrettd7655fr4n2y
|
||||
next-auth: 4.17.0_gxrb4puqhmlxj5cjmftw47fgty
|
||||
nextjs-cors: 2.1.2_next@13.0.7
|
||||
nodemailer: 6.8.0
|
||||
platform: 1.3.6
|
||||
prismjs: 1.29.0
|
||||
react: 18.2.0
|
||||
react-dom: 18.2.0_react@18.2.0
|
||||
react-icons: 4.7.1_react@18.2.0
|
||||
react-loader-spinner: 5.3.4_biqbaboplfbrettd7655fr4n2y
|
||||
react-toastify: 9.1.1_biqbaboplfbrettd7655fr4n2y
|
||||
swr: 1.3.0_react@18.2.0
|
||||
devDependencies:
|
||||
'@formbricks/database': link:../../packages/database
|
||||
'@formbricks/tailwind-config': link:../../packages/tailwind-config
|
||||
'@formbricks/tsconfig': link:../../packages/tsconfig
|
||||
'@types/node': 18.11.10
|
||||
'@types/react': 18.0.25
|
||||
'@types/react-dom': 18.0.9
|
||||
autoprefixer: 10.4.13_postcss@8.4.19
|
||||
eslint: 8.28.0
|
||||
eslint-config-formbricks: link:../../packages/eslint-config-formbricks
|
||||
postcss: 8.4.19
|
||||
typescript: 4.9.3
|
||||
|
||||
packages/charts:
|
||||
specifiers:
|
||||
'@formbricks/tsconfig': workspace:*
|
||||
@@ -2024,7 +2028,7 @@ packages:
|
||||
/@changesets/apply-release-plan/6.1.1:
|
||||
resolution: {integrity: sha512-LaQiP/Wf0zMVR0HNrLQAjz3rsNsr0d/RlnP6Ef4oi8VafOwnY1EoWdK4kssuUJGgNgDyHpomS50dm8CU3D7k7g==}
|
||||
dependencies:
|
||||
'@babel/runtime': 7.19.4
|
||||
'@babel/runtime': 7.20.6
|
||||
'@changesets/config': 2.2.0
|
||||
'@changesets/get-version-range-type': 0.3.2
|
||||
'@changesets/git': 1.5.0
|
||||
@@ -2034,7 +2038,7 @@ packages:
|
||||
fs-extra: 7.0.1
|
||||
lodash.startcase: 4.4.0
|
||||
outdent: 0.5.0
|
||||
prettier: 2.8.1
|
||||
prettier: 2.8.3
|
||||
resolve-from: 5.0.0
|
||||
semver: 5.7.1
|
||||
dev: true
|
||||
@@ -2197,11 +2201,11 @@ packages:
|
||||
/@changesets/write/0.2.1:
|
||||
resolution: {integrity: sha512-KUd49nt2fnYdGixIqTi1yVE1nAoZYUMdtB3jBfp77IMqjZ65hrmZE5HdccDlTeClZN0420ffpnfET3zzeY8pdw==}
|
||||
dependencies:
|
||||
'@babel/runtime': 7.19.4
|
||||
'@babel/runtime': 7.20.6
|
||||
'@changesets/types': 5.2.0
|
||||
fs-extra: 7.0.1
|
||||
human-id: 1.0.2
|
||||
prettier: 2.8.1
|
||||
prettier: 2.8.3
|
||||
dev: true
|
||||
|
||||
/@cnakazawa/watch/1.0.4:
|
||||
@@ -2663,6 +2667,10 @@ packages:
|
||||
resolution: {integrity: sha512-ZBclBRB7DbkSswXgbJ+muF5RxfgmAuQKAWL8tcm86aZmoiL1ZainxQK0hMcMYdh+IYG8UObAKV2wKB5O+6P4ng==}
|
||||
dev: false
|
||||
|
||||
/@next/env/13.1.2:
|
||||
resolution: {integrity: sha512-PpT4UZIX66VMTqXt4HKEJ+/PwbS+tWmmhZlazaws1a+dbUA5pPdjntQ46Jvj616i3ZKN9doS9LHx3y50RLjAWg==}
|
||||
dev: false
|
||||
|
||||
/@next/eslint-plugin-next/13.0.5:
|
||||
resolution: {integrity: sha512-H9U9B1dFnCDmylDZ6/dYt95Ie1Iu+SLBMcO6rkIGIDcj5UK+DNyMiWm83xWBZ1gREM8cfp5Srv1g6wqf8pM4lw==}
|
||||
dependencies:
|
||||
@@ -2707,6 +2715,15 @@ packages:
|
||||
dev: false
|
||||
optional: true
|
||||
|
||||
/@next/swc-android-arm-eabi/13.1.2:
|
||||
resolution: {integrity: sha512-7mRz1owoGsbfIcdOJA3kk7KEwPZ+OvVT1z9DkR/yru4QdVLF69h/1SHy0vlUNQMxDRllabhxCfkoZCB34GOGAg==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [arm]
|
||||
os: [android]
|
||||
requiresBuild: true
|
||||
dev: false
|
||||
optional: true
|
||||
|
||||
/@next/swc-android-arm64/13.0.0:
|
||||
resolution: {integrity: sha512-RW9Uy3bMSc0zVGCa11klFuwfP/jdcdkhdruqnrJ7v+7XHm6OFKkSRzX6ee7yGR1rdDZvTnP4GZSRSpzjLv/N0g==}
|
||||
engines: {node: '>= 10'}
|
||||
@@ -2734,6 +2751,15 @@ packages:
|
||||
dev: false
|
||||
optional: true
|
||||
|
||||
/@next/swc-android-arm64/13.1.2:
|
||||
resolution: {integrity: sha512-mgjZ2eJSayovQm1LcE54BLSI4jjnnnLtq5GY5g+DdPuUiCT644gKtjZ/w2BQvuIecCqqBO+Ph9yzo/wUTq7NLg==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [arm64]
|
||||
os: [android]
|
||||
requiresBuild: true
|
||||
dev: false
|
||||
optional: true
|
||||
|
||||
/@next/swc-darwin-arm64/13.0.0:
|
||||
resolution: {integrity: sha512-APA26nps1j4qyhOIzkclW/OmgotVHj1jBxebSpMCPw2rXfiNvKNY9FA0TcuwPmUCNqaTnm703h6oW4dvp73A4Q==}
|
||||
engines: {node: '>= 10'}
|
||||
@@ -2761,6 +2787,15 @@ packages:
|
||||
dev: false
|
||||
optional: true
|
||||
|
||||
/@next/swc-darwin-arm64/13.1.2:
|
||||
resolution: {integrity: sha512-RikoQqy109r2222UJlyGs4dZw2BibkfPqpeFdW5JEGv+L2PStlHID8DwyVYbmHfQ0VIBGvbf/NAUtFakAWlhwg==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [arm64]
|
||||
os: [darwin]
|
||||
requiresBuild: true
|
||||
dev: false
|
||||
optional: true
|
||||
|
||||
/@next/swc-darwin-x64/13.0.0:
|
||||
resolution: {integrity: sha512-qsUhUdoFuRJiaJ7LnvTQ6GZv1QnMDcRXCIjxaN0FNVXwrjkq++U7KjBUaxXkRzLV4C7u0NHLNOp0iZwNNE7ypw==}
|
||||
engines: {node: '>= 10'}
|
||||
@@ -2788,6 +2823,15 @@ packages:
|
||||
dev: false
|
||||
optional: true
|
||||
|
||||
/@next/swc-darwin-x64/13.1.2:
|
||||
resolution: {integrity: sha512-JbDZjaTvL8gyPC5TAH6OnD4jmXPkyUxRYPvu08ZmhT/XAFBb/Cso0BdXyDax/BPCG70mimP9d3hXNKNq+A0VtQ==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [x64]
|
||||
os: [darwin]
|
||||
requiresBuild: true
|
||||
dev: false
|
||||
optional: true
|
||||
|
||||
/@next/swc-freebsd-x64/13.0.0:
|
||||
resolution: {integrity: sha512-sCdyCbboS7CwdnevKH9J6hkJI76LUw1jVWt4eV7kISuLiPba3JmehZSWm80oa4ADChRVAwzhLAo2zJaYRrInbg==}
|
||||
engines: {node: '>= 10'}
|
||||
@@ -2815,6 +2859,15 @@ packages:
|
||||
dev: false
|
||||
optional: true
|
||||
|
||||
/@next/swc-freebsd-x64/13.1.2:
|
||||
resolution: {integrity: sha512-ax4j8VrdFQ/xc3W7Om0u1vnDxVApQHKsChBbAMynCrnycZmpbqK4MZu4ZkycT+mx2eccCiqZROpbzDbEdPosEw==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [x64]
|
||||
os: [freebsd]
|
||||
requiresBuild: true
|
||||
dev: false
|
||||
optional: true
|
||||
|
||||
/@next/swc-linux-arm-gnueabihf/13.0.0:
|
||||
resolution: {integrity: sha512-/X/VxfFA41C9jrEv+sUsPLQ5vbDPVIgG0CJrzKvrcc+b+4zIgPgtfsaWq9ockjHFQi3ycvlZK4TALOXO8ovQ6Q==}
|
||||
engines: {node: '>= 10'}
|
||||
@@ -2842,6 +2895,15 @@ packages:
|
||||
dev: false
|
||||
optional: true
|
||||
|
||||
/@next/swc-linux-arm-gnueabihf/13.1.2:
|
||||
resolution: {integrity: sha512-NcRHTesnCxnUvSJa637PQJffBBkmqi5XS/xVWGY7dI6nyJ+pC96Oj7kd+mcjnFUQI5lHKbg39qBWKtOzbezc4w==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [arm]
|
||||
os: [linux]
|
||||
requiresBuild: true
|
||||
dev: false
|
||||
optional: true
|
||||
|
||||
/@next/swc-linux-arm64-gnu/13.0.0:
|
||||
resolution: {integrity: sha512-x6Oxr1GIi0ZtNiT6jbw+JVcbEi3UQgF7mMmkrgfL4mfchOwXtWSHKTSSPnwoJWJfXYa0Vy1n8NElWNTGAqoWFw==}
|
||||
engines: {node: '>= 10'}
|
||||
@@ -2869,6 +2931,15 @@ packages:
|
||||
dev: false
|
||||
optional: true
|
||||
|
||||
/@next/swc-linux-arm64-gnu/13.1.2:
|
||||
resolution: {integrity: sha512-AxJdjocLtPrsBY4P2COSBIc3crT5bpjgGenNuINoensOlXhBkYM0aRDYZdydwXOhG+kN2ngUvfgitop9pa204w==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
requiresBuild: true
|
||||
dev: false
|
||||
optional: true
|
||||
|
||||
/@next/swc-linux-arm64-musl/13.0.0:
|
||||
resolution: {integrity: sha512-SnMH9ngI+ipGh3kqQ8+mDtWunirwmhQnQeZkEq9e/9Xsgjf04OetqrqRHKM1HmJtG2qMUJbyXFJ0F81TPuT+3g==}
|
||||
engines: {node: '>= 10'}
|
||||
@@ -2896,6 +2967,15 @@ packages:
|
||||
dev: false
|
||||
optional: true
|
||||
|
||||
/@next/swc-linux-arm64-musl/13.1.2:
|
||||
resolution: {integrity: sha512-JmNimDkcCRq7P5zpkdqeaSZ69qKDntEPtyIaMNWqy5M0WUJxGim0Fs6Qzxayiyvuuh9Guxks4woQ/j/ZvX/c8Q==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
requiresBuild: true
|
||||
dev: false
|
||||
optional: true
|
||||
|
||||
/@next/swc-linux-x64-gnu/13.0.0:
|
||||
resolution: {integrity: sha512-VSQwTX9EmdbotArtA1J67X8964oQfe0xHb32x4tu+JqTR+wOHyG6wGzPMdXH2oKAp6rdd7BzqxUXXf0J+ypHlw==}
|
||||
engines: {node: '>= 10'}
|
||||
@@ -2923,6 +3003,15 @@ packages:
|
||||
dev: false
|
||||
optional: true
|
||||
|
||||
/@next/swc-linux-x64-gnu/13.1.2:
|
||||
resolution: {integrity: sha512-TsLsjZwUlgmvI42neTuIoD6K9RlXCUzqPtvIClgXxVO0um0DiZwK+M+0zX/uVXhMVphfPY2c5YeR1zFSIONY4A==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
requiresBuild: true
|
||||
dev: false
|
||||
optional: true
|
||||
|
||||
/@next/swc-linux-x64-musl/13.0.0:
|
||||
resolution: {integrity: sha512-xBCP0nnpO0q4tsytXkvIwWFINtbFRyVY5gxa1zB0vlFtqYR9lNhrOwH3CBrks3kkeaePOXd611+8sjdUtrLnXA==}
|
||||
engines: {node: '>= 10'}
|
||||
@@ -2950,6 +3039,15 @@ packages:
|
||||
dev: false
|
||||
optional: true
|
||||
|
||||
/@next/swc-linux-x64-musl/13.1.2:
|
||||
resolution: {integrity: sha512-eSkyXgCXydEFPTkcncQOGepafedPte6JT/OofB9uvruucrrMVBagCASOuPxodWEMrlfEKSXVnExMKIlfmQMD7A==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
requiresBuild: true
|
||||
dev: false
|
||||
optional: true
|
||||
|
||||
/@next/swc-win32-arm64-msvc/13.0.0:
|
||||
resolution: {integrity: sha512-NutwDafqhGxqPj/eiUixJq9ImS/0sgx6gqlD7jRndCvQ2Q8AvDdu1+xKcGWGNnhcDsNM/n1avf1e62OG1GaqJg==}
|
||||
engines: {node: '>= 10'}
|
||||
@@ -2977,6 +3075,15 @@ packages:
|
||||
dev: false
|
||||
optional: true
|
||||
|
||||
/@next/swc-win32-arm64-msvc/13.1.2:
|
||||
resolution: {integrity: sha512-DmXFaRTgt2KrV9dmRLifDJE+cYiutHVFIw5/C9BtnwXH39uf3YbPxeD98vNrtqqqZVVLXY/1ySaSIwzYnqeY9g==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [arm64]
|
||||
os: [win32]
|
||||
requiresBuild: true
|
||||
dev: false
|
||||
optional: true
|
||||
|
||||
/@next/swc-win32-ia32-msvc/13.0.0:
|
||||
resolution: {integrity: sha512-zNaxaO+Kl/xNz02E9QlcVz0pT4MjkXGDLb25qxtAzyJL15aU0+VjjbIZAYWctG59dvggNIUNDWgoBeVTKB9xLg==}
|
||||
engines: {node: '>= 10'}
|
||||
@@ -3004,6 +3111,15 @@ packages:
|
||||
dev: false
|
||||
optional: true
|
||||
|
||||
/@next/swc-win32-ia32-msvc/13.1.2:
|
||||
resolution: {integrity: sha512-3+nBkuFs/wT+lmRVQNH5SyDT7I4vUlNPntosEaEP63FuYQdPLaxz0GvcR66MdFSFh2fsvazpe4wciOwVS4FItQ==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [ia32]
|
||||
os: [win32]
|
||||
requiresBuild: true
|
||||
dev: false
|
||||
optional: true
|
||||
|
||||
/@next/swc-win32-x64-msvc/13.0.0:
|
||||
resolution: {integrity: sha512-FFOGGWwTCRMu9W7MF496Urefxtuo2lttxF1vwS+1rIRsKvuLrWhVaVTj3T8sf2EBL6gtJbmh4TYlizS+obnGKA==}
|
||||
engines: {node: '>= 10'}
|
||||
@@ -3031,6 +3147,15 @@ packages:
|
||||
dev: false
|
||||
optional: true
|
||||
|
||||
/@next/swc-win32-x64-msvc/13.1.2:
|
||||
resolution: {integrity: sha512-avsyveEvcvH42PvKjR4Pb8JlLttuGURr2H3ZhS2b85pHOiZ7yjH3rMUoGnNzuLMApyxYaCvd4MedPrLhnNhkog==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [x64]
|
||||
os: [win32]
|
||||
requiresBuild: true
|
||||
dev: false
|
||||
optional: true
|
||||
|
||||
/@nodelib/fs.scandir/2.1.5:
|
||||
resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==}
|
||||
engines: {node: '>= 8'}
|
||||
@@ -3486,7 +3611,7 @@ packages:
|
||||
tslib: 1.14.1
|
||||
dev: false
|
||||
|
||||
/@sentry/nextjs/7.24.2_next@13.0.5+react@18.2.0:
|
||||
/@sentry/nextjs/7.24.2_next@13.0.7+react@18.2.0:
|
||||
resolution: {integrity: sha512-sow61sNU7DUwWdbf+wwd2dEbM/9NGfkSjaDE/oEesUjWhH/3bLgvn0HjgVU7UNnrpm+Wl2p6npfEP3sZ8nMRvg==}
|
||||
engines: {node: '>=8'}
|
||||
peerDependencies:
|
||||
@@ -3508,7 +3633,7 @@ packages:
|
||||
'@sentry/utils': 7.24.2
|
||||
'@sentry/webpack-plugin': 1.20.0
|
||||
chalk: 3.0.0
|
||||
next: 13.0.5_biqbaboplfbrettd7655fr4n2y
|
||||
next: 13.0.7_biqbaboplfbrettd7655fr4n2y
|
||||
react: 18.2.0
|
||||
rollup: 2.78.0
|
||||
tslib: 1.14.1
|
||||
@@ -12969,7 +13094,7 @@ packages:
|
||||
engines: {node: '>=10'}
|
||||
dev: true
|
||||
|
||||
/next-auth/4.17.0_2xoejpawkzgot77rbv5mbik6ve:
|
||||
/next-auth/4.17.0_gxrb4puqhmlxj5cjmftw47fgty:
|
||||
resolution: {integrity: sha512-aN2tdnjS0MDeUpB2tBDOaWnegkgeMWrsccujbXRGMJ607b+EwRcy63MFGSr0OAboDJEe0902piXQkt94GqF8Qw==}
|
||||
engines: {node: ^12.19.0 || ^14.15.0 || ^16.13.0 || ^18.12.0}
|
||||
peerDependencies:
|
||||
@@ -12985,7 +13110,7 @@ packages:
|
||||
'@panva/hkdf': 1.0.2
|
||||
cookie: 0.5.0
|
||||
jose: 4.11.1
|
||||
next: 13.0.5_biqbaboplfbrettd7655fr4n2y
|
||||
next: 13.0.7_biqbaboplfbrettd7655fr4n2y
|
||||
nodemailer: 6.8.0
|
||||
oauth: 0.9.15
|
||||
openid-client: 5.3.1
|
||||
@@ -13008,7 +13133,7 @@ packages:
|
||||
react-dom: 18.2.0_react@18.2.0
|
||||
dev: false
|
||||
|
||||
/next-sitemap/3.1.32_o6lqsnjzhz2zhif2mulkhpnbxy:
|
||||
/next-sitemap/3.1.32_yinmfuacmj4u57glipxrgw6l3m:
|
||||
resolution: {integrity: sha512-jkIKpwLXpWWTPfmDO46+6nu4+qpar4CjvUwCR9rYZHWtzE/wFfaCVFKpGtFMl6MFjpu8GjiE6kWFEa7uF3bzzg==}
|
||||
engines: {node: '>=14.18'}
|
||||
hasBin: true
|
||||
@@ -13017,7 +13142,7 @@ packages:
|
||||
next: '*'
|
||||
dependencies:
|
||||
'@corex/deepmerge': 4.0.29
|
||||
'@next/env': 13.0.7
|
||||
'@next/env': 13.1.2
|
||||
minimist: 1.2.7
|
||||
next: 13.0.0_biqbaboplfbrettd7655fr4n2y
|
||||
dev: false
|
||||
@@ -13199,13 +13324,57 @@ packages:
|
||||
- babel-plugin-macros
|
||||
dev: false
|
||||
|
||||
/nextjs-cors/2.1.2_next@13.0.5:
|
||||
/next/13.1.2_biqbaboplfbrettd7655fr4n2y:
|
||||
resolution: {integrity: sha512-Rdnnb2YH///w78FEOR/IQ6TXga+qpth4OqFSem48ng1PYYKr6XBsIk1XVaRcIGM3o6iiHnun0nJvkJHDf+ICyQ==}
|
||||
engines: {node: '>=14.6.0'}
|
||||
hasBin: true
|
||||
peerDependencies:
|
||||
fibers: '>= 3.1.0'
|
||||
node-sass: ^6.0.0 || ^7.0.0
|
||||
react: ^18.2.0
|
||||
react-dom: ^18.2.0
|
||||
sass: ^1.3.0
|
||||
peerDependenciesMeta:
|
||||
fibers:
|
||||
optional: true
|
||||
node-sass:
|
||||
optional: true
|
||||
sass:
|
||||
optional: true
|
||||
dependencies:
|
||||
'@next/env': 13.1.2
|
||||
'@swc/helpers': 0.4.14
|
||||
caniuse-lite: 1.0.30001435
|
||||
postcss: 8.4.14
|
||||
react: 18.2.0
|
||||
react-dom: 18.2.0_react@18.2.0
|
||||
styled-jsx: 5.1.1_react@18.2.0
|
||||
optionalDependencies:
|
||||
'@next/swc-android-arm-eabi': 13.1.2
|
||||
'@next/swc-android-arm64': 13.1.2
|
||||
'@next/swc-darwin-arm64': 13.1.2
|
||||
'@next/swc-darwin-x64': 13.1.2
|
||||
'@next/swc-freebsd-x64': 13.1.2
|
||||
'@next/swc-linux-arm-gnueabihf': 13.1.2
|
||||
'@next/swc-linux-arm64-gnu': 13.1.2
|
||||
'@next/swc-linux-arm64-musl': 13.1.2
|
||||
'@next/swc-linux-x64-gnu': 13.1.2
|
||||
'@next/swc-linux-x64-musl': 13.1.2
|
||||
'@next/swc-win32-arm64-msvc': 13.1.2
|
||||
'@next/swc-win32-ia32-msvc': 13.1.2
|
||||
'@next/swc-win32-x64-msvc': 13.1.2
|
||||
transitivePeerDependencies:
|
||||
- '@babel/core'
|
||||
- babel-plugin-macros
|
||||
dev: false
|
||||
|
||||
/nextjs-cors/2.1.2_next@13.0.7:
|
||||
resolution: {integrity: sha512-2yOVivaaf2ILe4f/qY32hnj3oC77VCOsUQJQfhVMGsXE/YMEWUY2zy78sH9FKUCM7eG42/l3pDofIzMD781XGA==}
|
||||
peerDependencies:
|
||||
next: ^8.1.1-canary.54 || ^9.0.0 || ^10.0.0-0 || ^11.0.0 || ^12.0.0 || ^13.0.0
|
||||
dependencies:
|
||||
cors: 2.8.5
|
||||
next: 13.0.5_biqbaboplfbrettd7655fr4n2y
|
||||
next: 13.0.7_biqbaboplfbrettd7655fr4n2y
|
||||
dev: false
|
||||
|
||||
/nice-try/1.0.5:
|
||||
@@ -14583,8 +14752,8 @@ packages:
|
||||
hasBin: true
|
||||
dev: true
|
||||
|
||||
/prettier/2.8.1:
|
||||
resolution: {integrity: sha512-lqGoSJBQNJidqCHE80vqZJHWHRFoNYsSpP9AjFhlhi9ODCJA541svILes/+/1GM3VaL/abZi7cpFzOpdR9UPKg==}
|
||||
/prettier/2.8.3:
|
||||
resolution: {integrity: sha512-tJ/oJ4amDihPoufT5sM0Z1SKEuKay8LfVAMlbbhnnkvt6BUserZylqo2PN+p9KeljLr0OHa2rXHU1T8reeoTrw==}
|
||||
engines: {node: '>=10.13.0'}
|
||||
hasBin: true
|
||||
dev: true
|
||||
@@ -16569,6 +16738,23 @@ packages:
|
||||
react: 18.2.0
|
||||
dev: false
|
||||
|
||||
/styled-jsx/5.1.1_react@18.2.0:
|
||||
resolution: {integrity: sha512-pW7uC1l4mBZ8ugbiZrcIsiIvVx1UmTfw7UkC3Um2tmfUq9Bhk8IiyEIPl6F8agHgjzku6j0xQEZbfA5uSgSaCw==}
|
||||
engines: {node: '>= 12.0.0'}
|
||||
peerDependencies:
|
||||
'@babel/core': '*'
|
||||
babel-plugin-macros: '*'
|
||||
react: '>= 16.8.0 || 17.x.x || ^18.0.0-0'
|
||||
peerDependenciesMeta:
|
||||
'@babel/core':
|
||||
optional: true
|
||||
babel-plugin-macros:
|
||||
optional: true
|
||||
dependencies:
|
||||
client-only: 0.0.1
|
||||
react: 18.2.0
|
||||
dev: false
|
||||
|
||||
/styled-tools/1.7.2:
|
||||
resolution: {integrity: sha512-IjLxzM20RMwAsx8M1QoRlCG/Kmq8lKzCGyospjtSXt/BTIIcvgTonaxQAsKnBrsZNwhpHzO9ADx5te0h76ILVg==}
|
||||
dev: false
|
||||
@@ -17267,65 +17453,65 @@ packages:
|
||||
yargs: 17.6.2
|
||||
dev: true
|
||||
|
||||
/turbo-darwin-64/1.6.3:
|
||||
resolution: {integrity: sha512-QmDIX0Yh1wYQl0bUS0gGWwNxpJwrzZU2GIAYt3aOKoirWA2ecnyb3R6ludcS1znfNV2MfunP+l8E3ncxUHwtjA==}
|
||||
/turbo-darwin-64/1.7.0:
|
||||
resolution: {integrity: sha512-hSGAueSf5Ko8J67mpqjpt9FsP6ePn1nMcl7IVPoJq5dHsgX3anCP/BPlexJ502bNK+87DDyhQhJ/LPSJXKrSYQ==}
|
||||
cpu: [x64]
|
||||
os: [darwin]
|
||||
requiresBuild: true
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/turbo-darwin-arm64/1.6.3:
|
||||
resolution: {integrity: sha512-75DXhFpwE7CinBbtxTxH08EcWrxYSPFow3NaeFwsG8aymkWXF+U2aukYHJA6I12n9/dGqf7yRXzkF0S/9UtdyQ==}
|
||||
/turbo-darwin-arm64/1.7.0:
|
||||
resolution: {integrity: sha512-BLLOW5W6VZxk5+0ZOj5AO1qjM0P5isIgjbEuyAl8lHZ4s9antUbY4CtFrspT32XxPTYoDl4UjviPMcSsbcl3WQ==}
|
||||
cpu: [arm64]
|
||||
os: [darwin]
|
||||
requiresBuild: true
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/turbo-linux-64/1.6.3:
|
||||
resolution: {integrity: sha512-O9uc6J0yoRPWdPg9THRQi69K6E2iZ98cRHNvus05lZbcPzZTxJYkYGb5iagCmCW/pq6fL4T4oLWAd6evg2LGQA==}
|
||||
/turbo-linux-64/1.7.0:
|
||||
resolution: {integrity: sha512-aw2qxmfZa+kT87SB3GNUoFimqEPzTlzlRqhPgHuAAT6Uf0JHnmebPt4K+ZPtDNl5yfVmtB05bhHPqw+5QV97Yg==}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
requiresBuild: true
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/turbo-linux-arm64/1.6.3:
|
||||
resolution: {integrity: sha512-dCy667qqEtZIhulsRTe8hhWQNCJO0i20uHXv7KjLHuFZGCeMbWxB8rsneRoY+blf8+QNqGuXQJxak7ayjHLxiA==}
|
||||
/turbo-linux-arm64/1.7.0:
|
||||
resolution: {integrity: sha512-AJEx2jX+zO5fQtJpO3r6uhTabj4oSA5ZhB7zTs/rwu/XqoydsvStA4X8NDW4poTbOjF7DcSHizqwi04tSMzpJw==}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
requiresBuild: true
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/turbo-windows-64/1.6.3:
|
||||
resolution: {integrity: sha512-lKRqwL3mrVF09b9KySSaOwetehmGknV9EcQTF7d2dxngGYYX1WXoQLjFP9YYH8ZV07oPm+RUOAKSCQuDuMNhiA==}
|
||||
/turbo-windows-64/1.7.0:
|
||||
resolution: {integrity: sha512-ewj7PPv2uxqv0r31hgnBa3E5qwUu7eyVRP5M1gB/TJXfSHduU79gbxpKCyxIZv2fL/N2/3U7EPOQPSZxBAoljA==}
|
||||
cpu: [x64]
|
||||
os: [win32]
|
||||
requiresBuild: true
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/turbo-windows-arm64/1.6.3:
|
||||
resolution: {integrity: sha512-BXY1sDPEA1DgPwuENvDCD8B7Hb0toscjus941WpL8CVd10hg9pk/MWn9CNgwDO5Q9ks0mw+liDv2EMnleEjeNA==}
|
||||
/turbo-windows-arm64/1.7.0:
|
||||
resolution: {integrity: sha512-LzjOUzveWkvTD0jP8DBMYiAnYemmydsvqxdSmsUapHHJkl6wKZIOQNSO7pxsy+9XM/1/+0f9Y9F9ZNl5lePTEA==}
|
||||
cpu: [arm64]
|
||||
os: [win32]
|
||||
requiresBuild: true
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/turbo/1.6.3:
|
||||
resolution: {integrity: sha512-FtfhJLmEEtHveGxW4Ye/QuY85AnZ2ZNVgkTBswoap7UMHB1+oI4diHPNyqrQLG4K1UFtCkjOlVoLsllUh/9QRw==}
|
||||
/turbo/1.7.0:
|
||||
resolution: {integrity: sha512-cwympNwQNnQZ/TffBd8yT0i0O10Cf/hlxccCYgUcwhcGEb9rDjE5thDbHoHw1hlJQUF/5ua7ERJe7Zr0lNE/ww==}
|
||||
hasBin: true
|
||||
requiresBuild: true
|
||||
optionalDependencies:
|
||||
turbo-darwin-64: 1.6.3
|
||||
turbo-darwin-arm64: 1.6.3
|
||||
turbo-linux-64: 1.6.3
|
||||
turbo-linux-arm64: 1.6.3
|
||||
turbo-windows-64: 1.6.3
|
||||
turbo-windows-arm64: 1.6.3
|
||||
turbo-darwin-64: 1.7.0
|
||||
turbo-darwin-arm64: 1.7.0
|
||||
turbo-linux-64: 1.7.0
|
||||
turbo-linux-arm64: 1.7.0
|
||||
turbo-windows-64: 1.7.0
|
||||
turbo-windows-arm64: 1.7.0
|
||||
dev: true
|
||||
|
||||
/type-check/0.3.2:
|
||||
|
||||
Reference in New Issue
Block a user