mirror of
https://github.com/formbricks/formbricks.git
synced 2026-01-05 00:49:57 -06:00
Update Docs, add Walkthrough Video to App & LP (#212)
* update LP with walk through * update docs with attributes and events * update team UI + form validation * add walk through to app * small fixes --------- Co-authored-by: Matthias Nannt <mail@matthiasnannt.com>
This commit is contained in:
@@ -64,9 +64,9 @@ 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("/waitlist")}>
|
||||
{/* <Button variant="highlight" className="ml-2" onClick={() => router.push("/waitlist")}>
|
||||
Get started
|
||||
</Button>
|
||||
</Button> */}
|
||||
</div>
|
||||
</header>
|
||||
);
|
||||
@@ -124,15 +124,6 @@ export function Layout({ children, meta }: LayoutProps) {
|
||||
</header>
|
||||
)}
|
||||
<Prose className="">{children}</Prose>
|
||||
<div className="mt-16 rounded-xl border-2 border-slate-200 bg-slate-300 p-8 dark:border-slate-700/50 dark:bg-slate-800">
|
||||
<h4 className="text-3xl font-semibold text-slate-500 dark:text-slate-50">Need help?</h4>
|
||||
<p className="my-4 text-slate-500 dark:text-slate-400">
|
||||
Join our Discord and ask away. We're happy to help where we can!
|
||||
</p>
|
||||
<Button variant="highlight" href="/discord" target="_blank">
|
||||
Join Discord
|
||||
</Button>
|
||||
</div>
|
||||
</article>
|
||||
<dl className="mt-12 flex border-t border-slate-200 pt-6 dark:border-slate-800">
|
||||
{previousPage && (
|
||||
@@ -164,6 +155,15 @@ export function Layout({ children, meta }: LayoutProps) {
|
||||
</div>
|
||||
)}
|
||||
</dl>
|
||||
<div className="mt-16 rounded-xl border-2 border-slate-200 bg-slate-300 p-8 dark:border-slate-700/50 dark:bg-slate-800">
|
||||
<h4 className="text-3xl font-semibold text-slate-500 dark:text-slate-50">Need help?</h4>
|
||||
<p className="my-4 text-slate-500 dark:text-slate-400">
|
||||
Join our Discord and ask away. We're happy to help where we can!
|
||||
</p>
|
||||
<Button variant="highlight" href="/discord" target="_blank">
|
||||
Join Discord
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
|
||||
@@ -1,8 +1,16 @@
|
||||
import TemplateList from "../dummyUI/TemplateList";
|
||||
import { Button } from "@formbricks/ui";
|
||||
import { useState } from "react";
|
||||
import { useRouter } from "next/router";
|
||||
import VideoWalkThrough from "./VideoWalkThrough";
|
||||
import { PlayCircleIcon } from "@heroicons/react/24/solid";
|
||||
|
||||
interface Props {}
|
||||
|
||||
export default function Hero({}: Props) {
|
||||
const router = useRouter();
|
||||
const [videoModal, setVideoModal] = useState(false);
|
||||
|
||||
return (
|
||||
<div className="relative">
|
||||
<div className="px-4 py-20 text-center sm:px-6 lg:px-8 lg:py-28">
|
||||
@@ -21,18 +29,28 @@ export default function Hero({}: Props) {
|
||||
Continuously measure what your customers think and feel. All open-source.
|
||||
</span>
|
||||
</p>
|
||||
{/*
|
||||
|
||||
<div className="mx-auto mt-5 max-w-md sm:flex sm:justify-center md:mt-8">
|
||||
<Button variant="secondary" className="" onClick={() => router.push("#best-practices")}>
|
||||
Best practices
|
||||
<Button
|
||||
variant="highlight"
|
||||
className="mr-3 px-6"
|
||||
onClick={() => setVideoModal(true)}
|
||||
EndIcon={PlayCircleIcon}
|
||||
endIconClassName=" ml-2">
|
||||
Watch video
|
||||
</Button>
|
||||
<Button variant="highlight" className="ml-3 px-6" onClick={() => router.push("/waitlist")}>
|
||||
Get Access
|
||||
</Button>
|
||||
</div> */}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<TemplateList />
|
||||
<VideoWalkThrough open={videoModal} setOpen={() => setVideoModal(false)} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
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
apps/formbricks-com/components/home/VideoWalkThrough.tsx
Normal file
17
apps/formbricks-com/components/home/VideoWalkThrough.tsx
Normal file
@@ -0,0 +1,17 @@
|
||||
import { ResponsiveVideo } from "@formbricks/ui";
|
||||
import Modal from "../shared/Modal";
|
||||
|
||||
interface VideoWalkThroughProps {
|
||||
open: boolean;
|
||||
setOpen: (v: boolean) => void;
|
||||
}
|
||||
|
||||
export default function VideoWalkThrough({ open, setOpen }: VideoWalkThroughProps) {
|
||||
return (
|
||||
<Modal open={open} setOpen={setOpen}>
|
||||
<div className="mt-5">
|
||||
<ResponsiveVideo src="/videos/walkthrough-v1.mp4" />
|
||||
</div>
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
@@ -46,8 +46,9 @@ export default function Header() {
|
||||
<Button
|
||||
variant="secondary"
|
||||
EndIcon={GitHubIcon}
|
||||
endIconClassName="fill-slate-800 ml-2"
|
||||
onClick={() => router.push("https://github.com/formbricks/formbricks")}>
|
||||
endIconClassName="fill-slate-800 ml-2 dark:fill-slate-200"
|
||||
href="https://github.com/formbricks/formbricks"
|
||||
target="_blank">
|
||||
View on Github
|
||||
</Button>
|
||||
{/* <Button variant="highlight" className="ml-2" onClick={() => router.push("/waitlist")}>
|
||||
|
||||
@@ -52,7 +52,7 @@ export function Search() {
|
||||
className="group flex h-6 w-6 items-center justify-center sm:justify-start md:h-auto md:w-60 md:flex-none md:rounded-lg md:py-2.5 md:pl-4 md:pr-3.5 md:text-sm md:ring-1 md:ring-slate-200 md:hover:ring-slate-300 dark:md:bg-slate-800/75 dark:md:ring-inset dark:md:ring-white/5 dark:md:hover:bg-slate-700/40 dark:md:hover:ring-slate-500 xl:w-80"
|
||||
onClick={onOpen}>
|
||||
<SearchIcon className="h-5 w-5 flex-none fill-slate-400 group-hover:fill-slate-500 dark:fill-slate-500 md:group-hover:fill-slate-400" />
|
||||
<span className="sr-only md:not-sr-only md:ml-2 md:text-slate-500 md:dark:text-slate-400">
|
||||
<span className="sr-only md:not-sr-only md:pl-2 md:text-slate-500 md:dark:text-slate-400">
|
||||
Search docs
|
||||
</span>
|
||||
{modifierKey && (
|
||||
|
||||
@@ -13,7 +13,22 @@ const navigation = [
|
||||
{ title: "Quickstart", href: "/docs/getting-started/quickstart" },
|
||||
{ title: "Setup with Next.js", href: "/docs/getting-started/nextjs" },
|
||||
{ title: "Setup with Vue.js", href: "/docs/getting-started/vuejs" },
|
||||
{ title: "Identify users", href: "/docs/getting-started/identify-users" },
|
||||
],
|
||||
},
|
||||
{
|
||||
title: "Attributes",
|
||||
links: [
|
||||
{ title: "Why Attributes?", href: "/docs/attributes/why" },
|
||||
{ title: "Custom Attributes", href: "/docs/attributes/custom-attributes" },
|
||||
{ title: "Identify users", href: "/docs/attributes/identify-users" },
|
||||
],
|
||||
},
|
||||
{
|
||||
title: "Events",
|
||||
links: [
|
||||
{ title: "Why Events?", href: "/docs/events/why" },
|
||||
{ title: "No-Code Events", href: "/docs/events/no-code" },
|
||||
{ title: "Code Events", href: "/docs/events/code" },
|
||||
],
|
||||
},
|
||||
{
|
||||
|
||||
@@ -40,6 +40,7 @@
|
||||
"@types/prismjs": "^1.26.0",
|
||||
"@types/react": "18.0.28",
|
||||
"@types/react-dom": "18.0.11",
|
||||
"@types/react-responsive-embed": "^2.1.0",
|
||||
"autoprefixer": "^10.4.14",
|
||||
"eslint": "8.36.0",
|
||||
"eslint-config-formbricks": "workspace:*",
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 976 KiB |
@@ -0,0 +1,47 @@
|
||||
import Image from "next/image";
|
||||
import LayoutMdx from "@/components/shared/LayoutMdx";
|
||||
import FormbricksSneak from "./formbricks-sneak.png";
|
||||
import ResponsiveEmbed from "react-responsive-embed";
|
||||
|
||||
export const meta = {
|
||||
title: "Video: Walk-through of the new Formbricks",
|
||||
description: "The new, powerful Formbricks is almost ready!",
|
||||
date: "2023-03-30",
|
||||
};
|
||||
|
||||
_The new, powerful Formbricks is almost ready!_
|
||||
|
||||
<Image src={FormbricksSneak} alt="Sneakpeek into what the new Formbricks can do" className="rounded-lg" />
|
||||
|
||||
We've been working hard on getting a revamped Formbricks ready - we're almost there!
|
||||
|
||||
What you can do with it:
|
||||
|
||||
1. Design **any survey** you want
|
||||
2. Trigger at any point in your app both **No Code** (page view, element click) and **Code** (hook `formbricks.track` into your event)
|
||||
3. Pass custom user attributes to Formbricks to **segment your user base**
|
||||
|
||||
## Have a look:
|
||||
|
||||
<ResponsiveEmbed
|
||||
src="https://www.tella.tv/video/clfrymq2f00sk0fjqd9r6btf1/embed?b=0&title=0&a=1&loop=0&t=0&muted=0"
|
||||
allowFullScreen
|
||||
className="rounded-lg"
|
||||
/>
|
||||
|
||||
Formbricks is a lot more powerful than ever before! :mechanical_arm:
|
||||
|
||||
You can create:
|
||||
|
||||
- Onboarding surveys,
|
||||
- PMF surveys,
|
||||
- Churn surveys,
|
||||
- Feature chaser,
|
||||
- Feedback box,
|
||||
- Identify customer goals,
|
||||
- Measure task completion,
|
||||
- etc, etc.
|
||||
|
||||
## Stay tuned, Formbricks Cloud goes live soon!
|
||||
|
||||
export default ({ children }) => <LayoutMdx meta={meta}>{children}</LayoutMdx>;
|
||||
@@ -0,0 +1,25 @@
|
||||
import { Layout } from "@/components/docs/Layout";
|
||||
|
||||
export const meta = {
|
||||
title: "Setting attributes with code",
|
||||
};
|
||||
|
||||
One way to send attributes to Formbricks is in your code. In Formbricks, there are two special attributes for [user identification](/docs/attributes/identify-users)(user ID & email) and custom attributes. An example:
|
||||
|
||||
### Setting Custom User Attributes
|
||||
|
||||
You can use the setAttribute function to set any custom attribute for the user (e.g. name, plan, etc.):
|
||||
|
||||
```javascript
|
||||
formbricks.setAttribute("Plan", "Pro");
|
||||
```
|
||||
|
||||
Generally speaking, the setAttribute function works like this:
|
||||
|
||||
```javascript
|
||||
formbricks.setAttribute("attribute_key", "attribute_value");
|
||||
```
|
||||
|
||||
Where `attributeName` is the name of the attribute you want to set, and `attributeValue` is the value of the attribute you want to set.
|
||||
|
||||
export default ({ children }) => <Layout meta={meta}>{children}</Layout>;
|
||||
21
apps/formbricks-com/pages/docs/attributes/why/index.mdx
Normal file
21
apps/formbricks-com/pages/docs/attributes/why/index.mdx
Normal file
@@ -0,0 +1,21 @@
|
||||
import { Layout } from "@/components/docs/Layout";
|
||||
|
||||
export const meta = {
|
||||
title: "What are attributes and why are they useful?",
|
||||
};
|
||||
|
||||
Surveying your user base without segmentation leads to weak results and survey fatigue. Attributes help you segment your users into groups.
|
||||
|
||||
## What are attributes?
|
||||
|
||||
Attributes are key-value pairs that you can set for each person individually. For example, the attribute "Plan" can be set to "Free" or "Paid".
|
||||
|
||||
## How do attributes work?
|
||||
|
||||
Attributes are sent from your application to Formbricks and are associated with the current user. We store it in our database and allow you to use it the next time you create a survey.
|
||||
|
||||
## Why are attributes useful?
|
||||
|
||||
Attributes help show surveys to the right group of people. For example, you can show a survey to all users who have a "Plan" attribute set to "Paid".
|
||||
|
||||
export default ({ children }) => <Layout meta={meta}>{children}</Layout>;
|
||||
23
apps/formbricks-com/pages/docs/events/code/index.mdx
Normal file
23
apps/formbricks-com/pages/docs/events/code/index.mdx
Normal file
@@ -0,0 +1,23 @@
|
||||
import { Layout } from "@/components/docs/Layout";
|
||||
|
||||
export const meta = {
|
||||
title: "Code Events",
|
||||
};
|
||||
|
||||
Events can also be set in the code base. You can fire an event using `formbricks.track()`
|
||||
|
||||
```javascript
|
||||
formbricks.track("Event Name");
|
||||
```
|
||||
|
||||
Here is an example of how to fire an event when a user clicks a button:
|
||||
|
||||
```javascript
|
||||
const handleClick = () => {
|
||||
formbricks.track("Button Clicked");
|
||||
};
|
||||
|
||||
return <button onClick={handleClick}>Click Me</button>;
|
||||
```
|
||||
|
||||
export default ({ children }) => <Layout meta={meta}>{children}</Layout>;
|
||||
28
apps/formbricks-com/pages/docs/events/no-code/index.mdx
Normal file
28
apps/formbricks-com/pages/docs/events/no-code/index.mdx
Normal file
@@ -0,0 +1,28 @@
|
||||
import { Layout } from "@/components/docs/Layout";
|
||||
|
||||
export const meta = {
|
||||
title: "No-Code Events",
|
||||
};
|
||||
|
||||
No-Code events can be set up within Formbricks with just a few clicks. There are three types of No-Code events:
|
||||
|
||||
## Page URL Event
|
||||
|
||||
The page URL event is triggered, when a user visits a specific page in your application. There are several match conditions:
|
||||
|
||||
- `exactMatch`: The URL should exactly match the provided string.
|
||||
- `contains`: The URL should contain the specified string as a substring.
|
||||
- `startsWith`: The URL should start with the specified string.
|
||||
- `endsWith`: The URL should end with the specified string.
|
||||
- `notMatch`: The URL should not match the specified condition.
|
||||
- `notContains`: The URL should not contain the specified string as a substring.
|
||||
|
||||
## innerText Event (coming soon)
|
||||
|
||||
The innerText event checks if the `innerText` of a clicked HTML element matches a specific text, e.g. the label of a button.
|
||||
|
||||
## CSS Selector Event (coming soon)
|
||||
|
||||
The CSS Selector event checks if the provided CSS selector matches the selector of a clicked HTML element. The CSS selector can be a class, id or any other CSS selector within your website.
|
||||
|
||||
export default ({ children }) => <Layout meta={meta}>{children}</Layout>;
|
||||
21
apps/formbricks-com/pages/docs/events/why/index.mdx
Normal file
21
apps/formbricks-com/pages/docs/events/why/index.mdx
Normal file
@@ -0,0 +1,21 @@
|
||||
import { Layout } from "@/components/docs/Layout";
|
||||
|
||||
export const meta = {
|
||||
title: "What are events and why are they useful?",
|
||||
};
|
||||
|
||||
You want to understand what your users think and feel during specific moments in the user journey. To be able to ask at exactly the right point in time, you need events.
|
||||
|
||||
## What are events?
|
||||
|
||||
Events are a little notification sent from your application to Formbricks. You decide which events are sent either in your [Code](/docs/events/code) or by setting up a [No-Code](/docs/events/no-code) event within Formbricks.
|
||||
|
||||
## How do events work?
|
||||
|
||||
When a predefined event happens in your app, the Formbricks widget notices. This event can then trigger a survey to be shown to the user and is stored in the database.
|
||||
|
||||
## Why are events useful?
|
||||
|
||||
Events help you to display your surveys at the right time. Later on, you will be able to segment your users based on the events they have triggered in the past. This way, you can create much more granular user segments, e.g. only target users that already have used a specific feature.
|
||||
|
||||
export default ({ children }) => <Layout meta={meta}>{children}</Layout>;
|
||||
@@ -1,11 +1,9 @@
|
||||
import { Layout } from "@/components/docs/Layout";
|
||||
|
||||
export const meta = {
|
||||
title: "Quickstart",
|
||||
title: "Setting up Formbricks SDK with Next.js",
|
||||
};
|
||||
|
||||
# Setting up Formbricks SDK with Next.js
|
||||
|
||||
This guide will walk you through the process of integrating the Formbricks SDK into a Next.js application. As the Formbricks SDK only works on the client side, it's essential to ensure proper integration to avoid any issues.
|
||||
|
||||
## Introduction
|
||||
|
||||
@@ -80,8 +80,11 @@ For more detailed guides for different frameworks, check out our [Next.js](/docs
|
||||
|
||||
## Step 5: Verify your setup
|
||||
|
||||
After setting up the widget, head back to the Formbricks dashboard: 1. Navigate to **Settings** in the top menubar. 2. Check the **Setup Checklist** to ensure everything is working
|
||||
correctly. If all items in the checklist are marked as complete, congratulations! You've successfully set up
|
||||
Formbricks, and you're ready to start creating and customizing your in-product surveys.
|
||||
After setting up the widget, head back to the Formbricks dashboard:
|
||||
|
||||
1. Navigate to **Settings** in the top menubar.
|
||||
2. Check the **Setup Checklist** to ensure everything is working correctly.
|
||||
|
||||
If you see confetti and a green box saying "Receiving data" you've successfully set up Formbricks. You're ready to start creating and customizing your in-product surveys.
|
||||
|
||||
export default ({ children }) => <Layout meta={meta}>{children}</Layout>;
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
import { Layout } from "@/components/docs/Layout";
|
||||
|
||||
export const meta = {
|
||||
title: "Quickstart",
|
||||
title: "Setting up Formbricks SDK with Vue.js",
|
||||
};
|
||||
|
||||
# Setting up Formbricks SDK with Vue.js
|
||||
|
||||
In this guide, we will go through the steps to set up the Formbricks SDK in a Vue.js application. This will allow you to create and customize in-product micro-surveys to gather valuable feedback from your users and improve your product experience.
|
||||
|
||||
## Introduction
|
||||
|
||||
@@ -5,13 +5,11 @@ export const meta = {
|
||||
title: "How Formbricks works",
|
||||
};
|
||||
|
||||
Formbricks is a powerful platform designed to help you create and manage in-product micro-surveys for SaaS and digital products. In this section, we'll provide a high-level overview of the different components that make up the Formbricks platform.
|
||||
Formbricks is a powerful platform designed to help you create and manage in-product micro-surveys for SaaS and digital products. Here is an overview:
|
||||
|
||||
## Overview
|
||||
## Four components
|
||||
|
||||
The Formbricks platform consists of four main components:
|
||||
|
||||
1. **Form Builder**: Create and customize your survey forms with a user-friendly, no-code interface.
|
||||
1. **Form Builder**: Create and customize your surveys with a user-friendly, no-code interface.
|
||||
2. **Targeting & Triggers**: Define specific user segments and set event-based triggers to display your surveys to the right users at the right time.
|
||||
3. **Integration**: Seamlessly integrate Formbricks into your web or mobile application using the provided SDKs or the HTML snippet.
|
||||
4. **Analytics & Insights**: Analyze user responses and gain actionable insights to make informed product decisions.
|
||||
@@ -32,6 +30,4 @@ Integrating Formbricks into your web or mobile application is a breeze. With SDK
|
||||
|
||||
Formbricks provides powerful analytics and insights to help you understand user responses and make data-driven decisions. The platform aggregates survey results and presents them in an easy-to-understand format, enabling you to identify trends, spot issues, and uncover opportunities for improvement. With Formbricks, you're always one step ahead in understanding your users and optimizing your product experience.
|
||||
|
||||
By combining these components, Formbricks offers an end-to-end solution for creating, managing, and analyzing in-product micro-surveys. Get started with Formbricks today and unlock valuable insights to grow your digital product. 🚀
|
||||
|
||||
export default ({ children }) => <Layout meta={meta}>{children}</Layout>;
|
||||
|
||||
@@ -18,6 +18,6 @@ Formbricks outshines other survey tools by specializing in in-product micro-surv
|
||||
| Event-based triggers | ❌ | ✅ |
|
||||
| User segmentation | ❌ | ✅ |
|
||||
|
||||
With Formbricks, you're not just getting another survey tool, but an in-depth, data-driven solution tailor-made for digital products. Start experiencing the difference with Formbricks today! 🎉
|
||||
With Formbricks, you're not just getting another survey tool, but an in-depth, data-driven solution tailor-made for digital products 🎉
|
||||
|
||||
export default ({ children }) => <Layout meta={meta}>{children}</Layout>;
|
||||
|
||||
BIN
apps/formbricks-com/public/videos/walkthrough-v1.mp4
Normal file
BIN
apps/formbricks-com/public/videos/walkthrough-v1.mp4
Normal file
Binary file not shown.
@@ -34,3 +34,11 @@
|
||||
background-color: #cbd5e1;
|
||||
border: 3px solid #cbd5e1;
|
||||
}
|
||||
|
||||
.DocSearch-Input {
|
||||
@apply px-11 text-gray-900 bg-white;
|
||||
}
|
||||
|
||||
.dark .DocSearch-Input {
|
||||
@apply text-gray-200 bg-gray-800;
|
||||
}
|
||||
|
||||
@@ -33,6 +33,7 @@ import {
|
||||
PaintBrushIcon,
|
||||
PlusIcon,
|
||||
UserCircleIcon,
|
||||
UsersIcon,
|
||||
} from "@heroicons/react/24/solid";
|
||||
import clsx from "clsx";
|
||||
import type { Session } from "next-auth";
|
||||
@@ -122,8 +123,8 @@ export default function EnvironmentsNavbar({ environmentId, session }: Environme
|
||||
icon: UserCircleIcon,
|
||||
label: "Profile",
|
||||
href: `/environments/${environmentId}/settings/profile`,
|
||||
} /*
|
||||
{ icon: UsersIcon, label: "Team", href: `/environments/${environmentId}/settings/team` }, */,
|
||||
},
|
||||
{ icon: UsersIcon, label: "Team", href: `/environments/${environmentId}/settings/team` },
|
||||
{
|
||||
icon: CreditCardIcon,
|
||||
label: "Billing & Plan",
|
||||
|
||||
@@ -33,7 +33,10 @@ export default function AttributeClassesList({ environmentId }: { environmentId:
|
||||
return (
|
||||
<>
|
||||
<div className="mb-6 text-right">
|
||||
<Button variant="secondary" href="https://formbricks.com/docs" target="_blank">
|
||||
<Button
|
||||
variant="secondary"
|
||||
href="http://formbricks.com/docs/attributes/custom-attributes"
|
||||
target="_blank">
|
||||
<QuestionMarkCircleIcon className="mr-2 h-4 w-4" />
|
||||
How to add attributes
|
||||
</Button>
|
||||
|
||||
@@ -70,7 +70,10 @@ export default function AttributeSettingsTab({
|
||||
</div>
|
||||
<div className="flex justify-between border-t border-slate-200 pt-6">
|
||||
<div>
|
||||
<Button variant="secondary" href="https://formbricks.com/docs" target="_blank">
|
||||
<Button
|
||||
variant="secondary"
|
||||
href="https://formbricks.com/docs/getting-started/identify-users"
|
||||
target="_blank">
|
||||
Read Docs
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
@@ -41,7 +41,7 @@ export default function AddMemberModal({ open, setOpen, onSubmit }: MemberModalP
|
||||
</div>
|
||||
<div>
|
||||
<Label>Email Adress</Label>
|
||||
<Input placeholder="hans@wurst.com" {...register("email")} />
|
||||
<Input type="email" placeholder="hans@wurst.com" {...register("email", { required: true })} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -55,12 +55,7 @@ export default function AddMemberModal({ open, setOpen, onSubmit }: MemberModalP
|
||||
}}>
|
||||
Cancel
|
||||
</Button>
|
||||
<Button
|
||||
variant="primary"
|
||||
type="submit"
|
||||
onClick={() => {
|
||||
setOpen(false);
|
||||
}}>
|
||||
<Button variant="primary" type="submit">
|
||||
Send Invitation
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
@@ -14,6 +14,8 @@ import {
|
||||
import { PaperAirplaneIcon, TrashIcon } from "@heroicons/react/24/outline";
|
||||
import { useState } from "react";
|
||||
import AddMemberModal from "./AddMemberModal";
|
||||
import { Badge } from "@formbricks/ui";
|
||||
import toast from "react-hot-toast";
|
||||
|
||||
export function EditMemberships({ environmentId }) {
|
||||
const { team, isErrorTeam, isLoadingTeam, mutateTeam } = useTeam(environmentId);
|
||||
@@ -69,7 +71,7 @@ export function EditMemberships({ environmentId }) {
|
||||
</Button>
|
||||
</div>
|
||||
<div className="rounded-lg border border-slate-200">
|
||||
<div className="grid h-12 grid-cols-7 content-center rounded-lg bg-slate-100 text-left text-sm font-semibold text-slate-900">
|
||||
<div className="grid h-12 grid-cols-7 content-center rounded-t-lg bg-slate-100 text-left text-sm font-semibold text-slate-900">
|
||||
<div className="px-6"></div>
|
||||
<div className="col-span-2 ">Fullname</div>
|
||||
<div className="col-span-2">Email</div>
|
||||
@@ -78,7 +80,7 @@ export function EditMemberships({ environmentId }) {
|
||||
<div className="grid-cols-7">
|
||||
{[...team.members, ...team.invitees].map((member) => (
|
||||
<div
|
||||
className="grid h-12 w-full grid-cols-7 content-center rounded-lg py-2 text-left text-sm text-slate-900 hover:bg-slate-100"
|
||||
className="grid h-12 w-full grid-cols-7 content-center rounded-lg p-0.5 py-2 text-left text-sm text-slate-900"
|
||||
key={member.email}>
|
||||
<div className="h-58 px-6 ">
|
||||
<ProfileAvatar userId={member.userId} />
|
||||
@@ -88,22 +90,22 @@ export function EditMemberships({ environmentId }) {
|
||||
</div>
|
||||
<div className="col-span-2 flex flex-col justify-center">{member.email}</div>
|
||||
<div className="col-span-2 flex items-center justify-end gap-x-6 pr-6">
|
||||
{!member.accepted && (
|
||||
<p className="rounded-md border-2 border-amber-500 bg-amber-50 px-2 py-px text-xs text-amber-500">
|
||||
Pending
|
||||
</p>
|
||||
)}
|
||||
{!member.accepted && <Badge type="warning" text="Pending" size="tiny" />}
|
||||
{member.role !== "owner" && (
|
||||
<button onClick={(e) => handleOpenDeleteMemberModal(e, member)}>
|
||||
<TrashIcon className="h-5 w-5 text-black" />
|
||||
<TrashIcon className="h-5 w-5 text-slate-700 hover:text-slate-500" />
|
||||
</button>
|
||||
)}
|
||||
{!member.accepted && (
|
||||
<TooltipProvider>
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<button onClick={() => handleResendInvite(member.inviteId)}>
|
||||
<PaperAirplaneIcon className="h-5 w-5 text-black" />
|
||||
<button
|
||||
onClick={() => {
|
||||
handleResendInvite(member.inviteId);
|
||||
toast.success("Invitation sent once more.");
|
||||
}}>
|
||||
<PaperAirplaneIcon className="h-5 w-5 text-slate-700 hover:text-slate-500" />
|
||||
</button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent className="TooltipContent" sideOffset={5}>
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import SettingsCard from "../SettingsCard";
|
||||
import SettingsTitle from "../SettingsTitle";
|
||||
import { EditMemberships } from "./EditMemberships";
|
||||
import { EditTeamName } from "./EditTeamName";
|
||||
|
||||
export default function MembersSettingsPage({ params }) {
|
||||
return (
|
||||
@@ -10,9 +9,9 @@ export default function MembersSettingsPage({ params }) {
|
||||
<SettingsCard title="Manage members" description="Add or remove members in your team.">
|
||||
<EditMemberships environmentId={params.environmentId} />
|
||||
</SettingsCard>
|
||||
<SettingsCard title="Team Name" description="Change the name of your team. Just in case.">
|
||||
<EditTeamName />
|
||||
</SettingsCard>
|
||||
{/* <SettingsCard title="Team Name" description="Change the name of your team. Just in case.">
|
||||
<EditTeamName />
|
||||
</SettingsCard>*/}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -62,7 +62,10 @@ if (typeof window !== "undefined") {
|
||||
<span className="font-semibold">
|
||||
Need a more detailed setup guide for React, Next.js or Vue.js?
|
||||
</span>{" "}
|
||||
<Link className="decoration-brand-dark" href="https://formbricks.com/docs" target="_blank">
|
||||
<Link
|
||||
className="decoration-brand-dark"
|
||||
href="https://formbricks.com/docs/getting-started/quickstart"
|
||||
target="_blank">
|
||||
Check out the docs.
|
||||
</Link>
|
||||
</li>
|
||||
@@ -83,7 +86,10 @@ if (typeof window !== "undefined") {
|
||||
<span className="font-semibold">
|
||||
Want to learn how to add user attributes, custom events and more?
|
||||
</span>{" "}
|
||||
<Link className="decoration-brand-dark" href="https://formbricks.com/docs" target="_blank">
|
||||
<Link
|
||||
className="decoration-brand-dark"
|
||||
href="https://formbricks.com/docs/attributes/why"
|
||||
target="_blank">
|
||||
Dive into the docs.
|
||||
</Link>
|
||||
</li>
|
||||
@@ -96,7 +102,7 @@ if (typeof window !== "undefined") {
|
||||
Insert this code into the <code>{`<head>`}</code> tag of your website:
|
||||
</p>
|
||||
<CodeBlock language="js">{`<script type="text/javascript">
|
||||
!function(){var t=document.createElement("script");t.type="text/javascript",t.async=!0,t.src="./dist/index.umd.js";var e=document.getElementsByTagName("script")[0];e.parentNode.insertBefore(t,e),setTimeout(function(){window.formbricks.init("${environmentId}","${window.location.protocol}//${window.location.host}")},500)}();
|
||||
!function(){var t=document.createElement("script");t.type="text/javascript",t.async=!0,t.src="./dist/index.umd.js";var e=document.getElementsByTagName("script")[0];e.parentNode.insertBefore(t,e),setTimeout(function(){window.formbricks.init({environmentId: "${environmentId}", apiHost: "${window.location.protocol}//${window.location.host}"})},500)}();
|
||||
</script>`}</CodeBlock>
|
||||
<p className="text-lg font-semibold text-slate-800">You're done 🎉</p>
|
||||
<p>
|
||||
@@ -125,7 +131,10 @@ if (typeof window !== "undefined") {
|
||||
<span className="font-semibold">
|
||||
Want to learn how to add user attributes, custom events and more?
|
||||
</span>{" "}
|
||||
<Link className="decoration-brand-dark" href="https://formbricks.com/docs" target="_blank">
|
||||
<Link
|
||||
className="decoration-brand-dark"
|
||||
href="https://formbricks.com/docs/attributes/why"
|
||||
target="_blank">
|
||||
Dive into the docs.
|
||||
</Link>
|
||||
</li>
|
||||
|
||||
@@ -9,9 +9,10 @@ import {
|
||||
DropdownMenuTrigger,
|
||||
} from "@/components/shared/DropdownMenu";
|
||||
import LoadingSpinner from "@/components/shared/LoadingSpinner";
|
||||
import Modal from "@/components/shared/Modal";
|
||||
import SurveyStatusIndicator from "@/components/shared/SurveyStatusIndicator";
|
||||
import { ErrorComponent } from "@formbricks/ui";
|
||||
import { deleteSurvey, useSurveys } from "@/lib/surveys/surveys";
|
||||
import { Button, ErrorComponent, ResponsiveVideo } from "@formbricks/ui";
|
||||
import { PlusIcon } from "@heroicons/react/24/outline";
|
||||
import { EllipsisHorizontalIcon, PencilSquareIcon, TrashIcon } from "@heroicons/react/24/solid";
|
||||
import Link from "next/link";
|
||||
@@ -24,6 +25,7 @@ export default function SurveysList({ environmentId }) {
|
||||
const { surveys, mutateSurveys, isLoadingSurveys, isErrorSurveys } = useSurveys(environmentId);
|
||||
|
||||
const [isDeleteDialogOpen, setDeleteDialogOpen] = useState(false);
|
||||
const [isVideoDialogOpen, setVideoDialogOpen] = useState(false);
|
||||
|
||||
const [activeSurvey, setActiveSurvey] = useState("" as any);
|
||||
const [activeSurveyIdx, setActiveSurveyIdx] = useState("" as any);
|
||||
@@ -67,6 +69,25 @@ export default function SurveysList({ environmentId }) {
|
||||
</div>
|
||||
</li>
|
||||
</button>
|
||||
{surveys.length === 0 && (
|
||||
<div className="flex flex-col items-center justify-center space-y-4 rounded-lg border border-slate-200 bg-slate-100 p-2">
|
||||
<p className="text-center text-xs text-slate-500">Kinda lost?</p>
|
||||
<video width="100" height="120" loop autoPlay className="rounded">
|
||||
<source src="/video/lost-sw.mp4" type="video/mp4" />
|
||||
No GIF support
|
||||
</video>
|
||||
<Button
|
||||
variant="secondary"
|
||||
onClick={() => setVideoDialogOpen(true)}
|
||||
className="hover:bg-slate-300">
|
||||
Play video
|
||||
</Button>
|
||||
|
||||
<Modal open={isVideoDialogOpen} setOpen={setVideoDialogOpen}>
|
||||
<ResponsiveVideo src="/video/walkthrough-v1.mp4" />
|
||||
</Modal>
|
||||
</div>
|
||||
)}
|
||||
{surveys
|
||||
.sort((a, b) => b.updatedAt - a.updatedAt)
|
||||
.map((survey, surveyIdx) => (
|
||||
|
||||
@@ -73,6 +73,7 @@ export default function SurveyMenuBar({
|
||||
<Button
|
||||
disabled={localSurvey.triggers[0] === "" || localSurvey.triggers.length === 0}
|
||||
variant="highlight"
|
||||
loading={isMutatingSurvey}
|
||||
onClick={() => {
|
||||
triggerSurveyMutate({ ...localSurvey, status: "inProgress" });
|
||||
router.push(`/environments/${environmentId}/surveys/${localSurvey.id}/summary?success=true`);
|
||||
|
||||
@@ -4,6 +4,7 @@ import { Button } from "@formbricks/ui";
|
||||
import type { Template } from "@formbricks/types/templates";
|
||||
import { createSurvey } from "@/lib/surveys/surveys";
|
||||
import { useRouter } from "next/navigation";
|
||||
import { useState } from "react";
|
||||
|
||||
interface TemplateMenuBarProps {
|
||||
activeTemplate: Template | null;
|
||||
@@ -12,8 +13,9 @@ interface TemplateMenuBarProps {
|
||||
|
||||
export default function TemplateMenuBar({ activeTemplate, environmentId }: TemplateMenuBarProps) {
|
||||
const router = useRouter();
|
||||
|
||||
const [loading, setLoading] = useState(false);
|
||||
const addSurvey = async (activeTemplate) => {
|
||||
setLoading(true);
|
||||
const survey = await createSurvey(environmentId, activeTemplate.preset);
|
||||
router.push(`/environments/${environmentId}/surveys/${survey.id}/edit`);
|
||||
};
|
||||
@@ -28,6 +30,7 @@ export default function TemplateMenuBar({ activeTemplate, environmentId }: Templ
|
||||
<Button
|
||||
variant="highlight"
|
||||
disabled={activeTemplate === null}
|
||||
loading={loading}
|
||||
onClick={() => addSurvey(activeTemplate)}>
|
||||
Create Survey
|
||||
</Button>
|
||||
|
||||
@@ -17,7 +17,7 @@ const ContentLayout = ({ headline, description, children }) => {
|
||||
export const NotLoggedInContent = ({ email, token, redirectUrl }) => {
|
||||
email = encodeURIComponent(email);
|
||||
return (
|
||||
<ContentLayout headline="Happy to have you 🫶" description="Please create an account or login.">
|
||||
<ContentLayout headline="Happy to have you 🤗" description="Please create an account or login.">
|
||||
<Button variant="secondary" href={`/auth/signup?inviteToken=${token}&email=${email}`}>
|
||||
Create account
|
||||
</Button>
|
||||
|
||||
BIN
apps/web/public/video/lost-sw.mp4
Normal file
BIN
apps/web/public/video/lost-sw.mp4
Normal file
Binary file not shown.
BIN
apps/web/public/video/walkthrough-v1.mp4
Normal file
BIN
apps/web/public/video/walkthrough-v1.mp4
Normal file
Binary file not shown.
@@ -30,7 +30,7 @@ export function Badge({ text, type, size }: BadgeProps) {
|
||||
return (
|
||||
<span
|
||||
className={cn(
|
||||
"ml-2 inline-flex items-center rounded-full font-medium",
|
||||
"ml-2 inline-flex cursor-default items-center rounded-full font-medium",
|
||||
bgColor[type],
|
||||
textColor[type],
|
||||
padding[size],
|
||||
|
||||
@@ -87,7 +87,7 @@ export const Button: React.ForwardRefExoticComponent<
|
||||
variant === "secondary" &&
|
||||
(disabled
|
||||
? "text-slate-400 dark:text-slate-500 bg-slate-200 dark:bg-slate-800"
|
||||
: "text-slate-600 hover:text-slate-500 bg-slate-200 hover:bg-slate-100 focus:outline-none focus:ring-2 focus:ring-offset-1 focus:bg-slate-700 focus:ring-neutral-500"),
|
||||
: "text-slate-600 hover:text-slate-500 bg-slate-200 hover:bg-slate-100 dark:bg-slate-700 dark:text-slate-300 dark:hover:bg-slate-600 focus:outline-none focus:ring-2 focus:ring-offset-1 focus:bg-slate-700 focus:ring-neutral-500"),
|
||||
variant === "warn" &&
|
||||
(disabled
|
||||
? "text-slate-400 bg-transparent"
|
||||
|
||||
18
packages/ui/components/ResponsiveVideo.tsx
Normal file
18
packages/ui/components/ResponsiveVideo.tsx
Normal file
@@ -0,0 +1,18 @@
|
||||
interface ResponsiveVideoProps {
|
||||
src: string;
|
||||
title?: string;
|
||||
}
|
||||
|
||||
export function ResponsiveVideo({ src, title }: ResponsiveVideoProps) {
|
||||
return (
|
||||
<div className="relative" style={{ paddingTop: "56.25%" }}>
|
||||
<iframe
|
||||
className="absolute top-0 left-0 h-full w-full rounded"
|
||||
src={src}
|
||||
title={title}
|
||||
frameBorder="0"
|
||||
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
|
||||
allowFullScreen></iframe>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -30,6 +30,7 @@ export { PageTitle } from "./components/PageTitle";
|
||||
export { Popover, PopoverTrigger, PopoverContent } from "./components/Popover";
|
||||
export { ProgressBar } from "./components/ProgressBar";
|
||||
export { RadioGroup, RadioGroupItem } from "./components/RadioGroup";
|
||||
export { ResponsiveVideo } from "./components/ResponsiveVideo";
|
||||
export {
|
||||
Select,
|
||||
SelectGroup,
|
||||
|
||||
50
pnpm-lock.yaml
generated
50
pnpm-lock.yaml
generated
@@ -12,7 +12,7 @@ importers:
|
||||
'@changesets/cli': 2.25.0
|
||||
prettier: 2.8.7
|
||||
tsx: 3.9.0
|
||||
turbo: 1.8.6
|
||||
turbo: 1.8.8
|
||||
|
||||
apps/demo:
|
||||
specifiers:
|
||||
@@ -65,6 +65,7 @@ importers:
|
||||
'@types/prismjs': ^1.26.0
|
||||
'@types/react': 18.0.28
|
||||
'@types/react-dom': 18.0.11
|
||||
'@types/react-responsive-embed': ^2.1.0
|
||||
add: ^2.0.6
|
||||
autoprefixer: ^10.4.14
|
||||
clsx: ^1.2.1
|
||||
@@ -115,6 +116,7 @@ importers:
|
||||
'@types/prismjs': 1.26.0
|
||||
'@types/react': 18.0.28
|
||||
'@types/react-dom': 18.0.11
|
||||
'@types/react-responsive-embed': 2.1.0
|
||||
autoprefixer: 10.4.14_postcss@8.4.21
|
||||
eslint: 8.36.0
|
||||
eslint-config-formbricks: link:../../packages/eslint-config-formbricks
|
||||
@@ -4586,6 +4588,12 @@ packages:
|
||||
redux: 4.2.1
|
||||
dev: false
|
||||
|
||||
/@types/react-responsive-embed/2.1.0:
|
||||
resolution: {integrity: sha512-VZ921rT7Kf5Zq2GyUxaFXWXQd/YqSMwpwOO5BRJJyzcZoH34YbeX442Dk/nDwXL5QQkz1Zp7hmD80Ris1OHPCA==}
|
||||
dependencies:
|
||||
'@types/react': 18.0.31
|
||||
dev: true
|
||||
|
||||
/@types/react/18.0.27:
|
||||
resolution: {integrity: sha512-3vtRKHgVxu3Jp9t718R9BuzoD4NcQ8YJ5XRzsSKxNDiDonD2MXIT1TmSkenxuCycZJoQT5d2vE8LwWJxBC1gmA==}
|
||||
dependencies:
|
||||
@@ -18638,65 +18646,65 @@ packages:
|
||||
dependencies:
|
||||
safe-buffer: 5.2.1
|
||||
|
||||
/turbo-darwin-64/1.8.6:
|
||||
resolution: {integrity: sha512-VlXkQR0TEBAEyBRsvAXBax+fj1EdPKPliwBaCnRLiDUcA/8wYlKte/Kk6ubmj9E0n7U/B4keCxxHiJZqW/5Rqg==}
|
||||
/turbo-darwin-64/1.8.8:
|
||||
resolution: {integrity: sha512-18cSeIm7aeEvIxGyq7PVoFyEnPpWDM/0CpZvXKHpQ6qMTkfNt517qVqUTAwsIYqNS8xazcKAqkNbvU1V49n65Q==}
|
||||
cpu: [x64]
|
||||
os: [darwin]
|
||||
requiresBuild: true
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/turbo-darwin-arm64/1.8.6:
|
||||
resolution: {integrity: sha512-w4L2QLj90ex68UXxTPoqtZPl8mWzc6a1RtPjQhoxAWtZf9T2WXi813dCzYEbVUVC09/DOW/VxZRN7sb2r0KP9A==}
|
||||
/turbo-darwin-arm64/1.8.8:
|
||||
resolution: {integrity: sha512-ruGRI9nHxojIGLQv1TPgN7ud4HO4V8mFBwSgO6oDoZTNuk5ybWybItGR+yu6fni5vJoyMHXOYA2srnxvOc7hjQ==}
|
||||
cpu: [arm64]
|
||||
os: [darwin]
|
||||
requiresBuild: true
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/turbo-linux-64/1.8.6:
|
||||
resolution: {integrity: sha512-eV245jefIhMAZskqQKalFwreC5UEdQcuHcBiWcgUk0py76fbwB7+1HfH5cmeJlb3a1sB6f3H0HHmGPmb34feCA==}
|
||||
/turbo-linux-64/1.8.8:
|
||||
resolution: {integrity: sha512-N/GkHTHeIQogXB1/6ZWfxHx+ubYeb8Jlq3b/3jnU4zLucpZzTQ8XkXIAfJG/TL3Q7ON7xQ8yGOyGLhHL7MpFRg==}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
requiresBuild: true
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/turbo-linux-arm64/1.8.6:
|
||||
resolution: {integrity: sha512-Kiw3nyEvNU6Bpil4zE5FwhasPAOi59R4YdCmjJp0Sen6V9u+/Jij6SWwaoUdATORJLiYQBbhontWBH55B53VDw==}
|
||||
/turbo-linux-arm64/1.8.8:
|
||||
resolution: {integrity: sha512-hKqLbBHgUkYf2Ww8uBL9UYdBFQ5677a7QXdsFhONXoACbDUPvpK4BKlz3NN7G4NZ+g9dGju+OJJjQP0VXRHb5w==}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
requiresBuild: true
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/turbo-windows-64/1.8.6:
|
||||
resolution: {integrity: sha512-34BkAG9r4nE00xeMeVahaF82h8R6SO+IIOcD60fNr2p+Ch+YcQa+DbEWA/KUj3coUTIiNP5XnRCLRUYADdlxjQ==}
|
||||
/turbo-windows-64/1.8.8:
|
||||
resolution: {integrity: sha512-2ndjDJyzkNslXxLt+PQuU21AHJWc8f6MnLypXy3KsN4EyX/uKKGZS0QJWz27PeHg0JS75PVvhfFV+L9t9i+Yyg==}
|
||||
cpu: [x64]
|
||||
os: [win32]
|
||||
requiresBuild: true
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/turbo-windows-arm64/1.8.6:
|
||||
resolution: {integrity: sha512-4jWUaI7Lmonp2I3x81GruiCYd0aQsG/xDOYhuv9+j2yIgB/UHJFz/P8PWp/nziwPtGpRd/AheDlPzzyd9lWoqw==}
|
||||
/turbo-windows-arm64/1.8.8:
|
||||
resolution: {integrity: sha512-xCA3oxgmW9OMqpI34AAmKfOVsfDljhD5YBwgs0ZDsn5h3kCHhC4x9W5dDk1oyQ4F5EXSH3xVym5/xl1J6WRpUg==}
|
||||
cpu: [arm64]
|
||||
os: [win32]
|
||||
requiresBuild: true
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/turbo/1.8.6:
|
||||
resolution: {integrity: sha512-6IOOaa8ytgjnSCTnp3LKAd2uGBZ/Kmx8ZPlI/YMWuKMUqvkXKLbh+w76ApMgMm+faUqti+QujVWovCu2kY6KuQ==}
|
||||
/turbo/1.8.8:
|
||||
resolution: {integrity: sha512-qYJ5NjoTX+591/x09KgsDOPVDUJfU9GoS+6jszQQlLp1AHrf1wRFA3Yps8U+/HTG03q0M4qouOfOLtRQP4QypA==}
|
||||
hasBin: true
|
||||
requiresBuild: true
|
||||
optionalDependencies:
|
||||
turbo-darwin-64: 1.8.6
|
||||
turbo-darwin-arm64: 1.8.6
|
||||
turbo-linux-64: 1.8.6
|
||||
turbo-linux-arm64: 1.8.6
|
||||
turbo-windows-64: 1.8.6
|
||||
turbo-windows-arm64: 1.8.6
|
||||
turbo-darwin-64: 1.8.8
|
||||
turbo-darwin-arm64: 1.8.8
|
||||
turbo-linux-64: 1.8.8
|
||||
turbo-linux-arm64: 1.8.8
|
||||
turbo-windows-64: 1.8.8
|
||||
turbo-windows-arm64: 1.8.8
|
||||
dev: true
|
||||
|
||||
/tween-functions/1.2.0:
|
||||
|
||||
Reference in New Issue
Block a user