diff --git a/apps/builder/src/assets/styles/globals.css b/apps/builder/src/assets/styles/globals.css index 9ce0c84c4..3d9ab3d4d 100644 --- a/apps/builder/src/assets/styles/globals.css +++ b/apps/builder/src/assets/styles/globals.css @@ -4,6 +4,10 @@ @tailwind components; @tailwind utilities; +:root { + --spacing: 0.25rem; +} + h1 { @apply text-4xl md:text-6xl; } diff --git a/apps/builder/src/components/AlertInfo.tsx b/apps/builder/src/components/AlertInfo.tsx deleted file mode 100644 index a4dfba102..000000000 --- a/apps/builder/src/components/AlertInfo.tsx +++ /dev/null @@ -1,8 +0,0 @@ -import { Alert, AlertIcon, type AlertProps } from "@chakra-ui/react"; - -export const AlertInfo = (props: AlertProps) => ( - - - {props.children} - -); diff --git a/apps/builder/src/components/ImageUploadContent/UnsplashPicker.tsx b/apps/builder/src/components/ImageUploadContent/UnsplashPicker.tsx index f77972b2e..b801cea37 100644 --- a/apps/builder/src/components/ImageUploadContent/UnsplashPicker.tsx +++ b/apps/builder/src/components/ImageUploadContent/UnsplashPicker.tsx @@ -1,6 +1,4 @@ import { - Alert, - AlertIcon, Box, Flex, Grid, @@ -15,6 +13,8 @@ import { } from "@chakra-ui/react"; import { env } from "@typebot.io/env"; import { isDefined } from "@typebot.io/lib/utils"; +import { Alert } from "@typebot.io/ui/components/Alert"; +import { TriangleAlertIcon } from "@typebot.io/ui/icons/TriangleAlertIcon"; import { useCallback, useEffect, useRef, useState } from "react"; import { createApi } from "unsplash-js"; import type { Basic as UnsplashPhoto } from "unsplash-js/dist/methods/photos/types"; @@ -153,10 +153,10 @@ export const UnsplashPicker = ({ imageSize, onImageSelect }: Props) => { {isDefined(error) && ( - - - {error} - + + + {error} + )} {images.length > 0 && ( diff --git a/apps/builder/src/components/UnlockPlanAlertInfo.tsx b/apps/builder/src/components/UnlockPlanAlertInfo.tsx deleted file mode 100644 index 2db0c48e7..000000000 --- a/apps/builder/src/components/UnlockPlanAlertInfo.tsx +++ /dev/null @@ -1,40 +0,0 @@ -import { - Alert, - AlertIcon, - type AlertProps, - HStack, - Text, - useDisclosure, -} from "@chakra-ui/react"; -import type { ChangePlanDialogProps } from "@/features/billing/components/ChangePlanDialog"; -import { ChangePlanDialog } from "@/features/billing/components/ChangePlanDialog"; - -type Props = AlertProps & Pick; - -export const UnlockPlanAlertInfo = ({ - type, - excludedPlans, - ...props -}: Props) => { - const { isOpen, onClose } = useDisclosure(); - return ( - - - - {props.children} - - - - ); -}; diff --git a/apps/builder/src/components/VideoUploadContent/PexelsPicker.tsx b/apps/builder/src/components/VideoUploadContent/PexelsPicker.tsx index a048795d4..c999a7cfc 100644 --- a/apps/builder/src/components/VideoUploadContent/PexelsPicker.tsx +++ b/apps/builder/src/components/VideoUploadContent/PexelsPicker.tsx @@ -1,6 +1,4 @@ import { - Alert, - AlertIcon, Box, Flex, Grid, @@ -14,6 +12,8 @@ import { } from "@chakra-ui/react"; import { env } from "@typebot.io/env"; import { isDefined } from "@typebot.io/lib/utils"; +import { Alert } from "@typebot.io/ui/components/Alert"; +import { TriangleAlertIcon } from "@typebot.io/ui/icons/TriangleAlertIcon"; import { createClient, type ErrorResponse, @@ -171,10 +171,10 @@ export const PexelsPicker = ({ onVideoSelect }: Props) => { {isDefined(error) && ( - - - {error} - + + + {error} + )} {videos.length > 0 && ( diff --git a/apps/builder/src/features/auth/components/SignInError.tsx b/apps/builder/src/features/auth/components/SignInError.tsx index 8ce429129..19b780473 100644 --- a/apps/builder/src/features/auth/components/SignInError.tsx +++ b/apps/builder/src/features/auth/components/SignInError.tsx @@ -1,5 +1,6 @@ -import { Alert } from "@chakra-ui/react"; import { useTranslate } from "@tolgee/react"; +import { Alert } from "@typebot.io/ui/components/Alert"; +import { TriangleAlertIcon } from "@typebot.io/ui/icons/TriangleAlertIcon"; type Props = { error: string; @@ -22,8 +23,9 @@ export const SignInError = ({ error }: Props) => { if (!errors[error]) return null; return ( - - {errors[error]} - + + + {errors[error]} + ); }; diff --git a/apps/builder/src/features/auth/components/SignInForm.tsx b/apps/builder/src/features/auth/components/SignInForm.tsx index 3ea774d98..29f178fc3 100644 --- a/apps/builder/src/features/auth/components/SignInForm.tsx +++ b/apps/builder/src/features/auth/components/SignInForm.tsx @@ -1,7 +1,5 @@ import { sanitizeUrl } from "@braintree/sanitize-url"; import { - Alert, - AlertIcon, FormControl, FormLabel, HStack, @@ -16,7 +14,9 @@ import { VStack, } from "@chakra-ui/react"; import { useTranslate } from "@tolgee/react"; +import { Alert } from "@typebot.io/ui/components/Alert"; import { Button } from "@typebot.io/ui/components/Button"; +import { CheckmarkSquare02Icon } from "@typebot.io/ui/icons/CheckmarkSquare02Icon"; import { useRouter } from "next/navigation"; import { getProviders, signIn, useSession } from "next-auth/react"; import { useQueryState } from "nuqs"; @@ -174,15 +174,15 @@ export const SignInForm = ({ )} - - - - - {t("auth.magicLink.title")} - {t("auth.magicLink.description")} - - - + + +
+ {t("auth.magicLink.title")} + + {t("auth.magicLink.description")} + +
+
Login code: diff --git a/apps/builder/src/features/billing/components/ChangePlanDialog.tsx b/apps/builder/src/features/billing/components/ChangePlanDialog.tsx index cfdd7d423..9d3a066a8 100644 --- a/apps/builder/src/features/billing/components/ChangePlanDialog.tsx +++ b/apps/builder/src/features/billing/components/ChangePlanDialog.tsx @@ -1,9 +1,10 @@ import { HStack } from "@chakra-ui/react"; import { useTranslate } from "@tolgee/react"; +import { Alert } from "@typebot.io/ui/components/Alert"; import { Button } from "@typebot.io/ui/components/Button"; import { Dialog } from "@typebot.io/ui/components/Dialog"; +import { InformationSquareIcon } from "@typebot.io/ui/icons/InformationSquareIcon"; import { cx } from "@typebot.io/ui/lib/cva"; -import { AlertInfo } from "@/components/AlertInfo"; import { useWorkspace } from "@/features/workspace/WorkspaceProvider"; import { ChangePlanForm } from "./ChangePlanForm"; @@ -32,9 +33,12 @@ export const ChangePlanDialog = ({ {type && ( - - {t("billing.upgradeLimitLabel", { type: type })} - + + + + {t("billing.upgradeLimitLabel", { type: type })} + + )} {workspace && ( { )} {data?.subscription?.status === "past_due" && ( - - - {t("billing.currentSubscription.pastDueAlert")} - + + + + {t("billing.currentSubscription.pastDueAlert")} + + )} {isSubscribed && ( diff --git a/apps/builder/src/features/blocks/integrations/googleSheets/components/GoogleSheetsConnectDialog.tsx b/apps/builder/src/features/blocks/integrations/googleSheets/components/GoogleSheetsConnectDialog.tsx index 016b00e80..284880fa3 100644 --- a/apps/builder/src/features/blocks/integrations/googleSheets/components/GoogleSheetsConnectDialog.tsx +++ b/apps/builder/src/features/blocks/integrations/googleSheets/components/GoogleSheetsConnectDialog.tsx @@ -1,6 +1,5 @@ import { Image, Text } from "@chakra-ui/react"; import { Dialog } from "@typebot.io/ui/components/Dialog"; -import { AlertInfo } from "@/components/AlertInfo"; import { ButtonLink } from "@/components/ButtonLink"; import { GoogleLogo } from "@/components/GoogleLogo"; import { useWorkspace } from "@/features/workspace/WorkspaceProvider"; @@ -47,11 +46,6 @@ export const GoogleSheetConnectDialogBody = ({ alt="Google Spreadsheets checkboxes" rounded="md" /> - - Google does not provide more granular permissions than "read" - or "write" access. That's why it states that Typebot can - also delete your spreadsheets which it won't. - {workspace?.id && ( - - - {url ? ( - "Your scenario is correctly configured 🚀" - ) : ( - - Head up to Make.com to configure this block: + {url ? ( + + + + Your scenario is correctly configured 🚀 + + + ) : ( + + + + Head up to Make.com to configure this block + + Make.com - - )} - + + + )} - - - Make sure to add a payment method to your OpenAI account. Otherwise, - it will not work after a few messages. - + + + + Make sure to add a payment method to your OpenAI account. Otherwise, + it will not work after a few messages. + + + + + )} {!isPublished && phoneNumberData && ( - You have modifications that can be published. + + + + You have modifications that can be published. + + )} diff --git a/apps/builder/src/features/results/components/table/ExportAllResultsDialog.tsx b/apps/builder/src/features/results/components/table/ExportAllResultsDialog.tsx index 3aef26d1a..4565e17f1 100644 --- a/apps/builder/src/features/results/components/table/ExportAllResultsDialog.tsx +++ b/apps/builder/src/features/results/components/table/ExportAllResultsDialog.tsx @@ -8,14 +8,15 @@ import { parseBlockIdVariableIdMap } from "@typebot.io/results/parseBlockIdVaria import { parseColumnsOrder } from "@typebot.io/results/parseColumnsOrder"; import { parseResultHeader } from "@typebot.io/results/parseResultHeader"; import type { Typebot } from "@typebot.io/typebot/schemas/typebot"; +import { Alert } from "@typebot.io/ui/components/Alert"; import { Button } from "@typebot.io/ui/components/Button"; import { Dialog } from "@typebot.io/ui/components/Dialog"; import { Field } from "@typebot.io/ui/components/Field"; import { MoreInfoTooltip } from "@typebot.io/ui/components/MoreInfoTooltip"; import { Switch } from "@typebot.io/ui/components/Switch"; +import { InformationSquareIcon } from "@typebot.io/ui/icons/InformationSquareIcon"; import { unparse } from "papaparse"; import { useState } from "react"; -import { AlertInfo } from "@/components/AlertInfo"; import { DownloadIcon } from "@/components/icons"; import { useTypebot } from "@/features/editor/providers/TypebotProvider"; import { trpc, trpcClient } from "@/lib/queryClient"; @@ -165,11 +166,14 @@ export const ExportAllResultsDialog = ({ isOpen, onClose }: Props) => { - {totalResults > 2000 ? ( - The export may take a while. - ) : ( - The export may take up to 1 minute. - )} + + + + {totalResults > 2000 + ? "The export may take a while." + : "The export may take up to 1 minute."} + + {isExportLoading && ( Fetching all results... diff --git a/apps/builder/src/features/workspace/components/MembersList.tsx b/apps/builder/src/features/workspace/components/MembersList.tsx index 85b27370b..59f901f62 100644 --- a/apps/builder/src/features/workspace/components/MembersList.tsx +++ b/apps/builder/src/features/workspace/components/MembersList.tsx @@ -10,7 +10,11 @@ import { getSeatsLimit } from "@typebot.io/billing/helpers/getSeatsLimit"; import { isDefined } from "@typebot.io/lib/utils"; import { WorkspaceRole } from "@typebot.io/prisma/enum"; import type { Prisma } from "@typebot.io/prisma/types"; -import { UnlockPlanAlertInfo } from "@/components/UnlockPlanAlertInfo"; +import { Alert } from "@typebot.io/ui/components/Alert"; +import { Button } from "@typebot.io/ui/components/Button"; +import { useOpenControls } from "@typebot.io/ui/hooks/useOpenControls"; +import { InformationSquareIcon } from "@typebot.io/ui/icons/InformationSquareIcon"; +import { ChangePlanDialog } from "@/features/billing/components/ChangePlanDialog"; import { useUser } from "@/features/user/hooks/useUser"; import { useMembers } from "../hooks/useMembers"; import { deleteInvitationQuery } from "../queries/deleteInvitationQuery"; @@ -30,6 +34,12 @@ export const MembersList = () => { workspaceId: workspace?.id, }); + const { + isOpen: isChangePlanDialogOpen, + onOpen: onChangePlanDialogOpen, + onClose: onChangePlanDialogClose, + } = useOpenControls(); + const handleDeleteMemberClick = (memberId: string) => async () => { if (!workspace) return; await deleteMemberQuery(workspace.id, memberId); @@ -102,9 +112,26 @@ export const MembersList = () => { return ( {!canInviteNewMember && ( - - {t("workspace.membersList.unlockBanner.label")} - + + + Unlock more members + + {t("workspace.membersList.unlockBanner.label")} + + + + + + )} {isDefined(seatsLimit) && ( diff --git a/packages/ui/src/components/Alert.tsx b/packages/ui/src/components/Alert.tsx new file mode 100644 index 000000000..643a7603b --- /dev/null +++ b/packages/ui/src/components/Alert.tsx @@ -0,0 +1,73 @@ +import { cva, type VariantProps } from "class-variance-authority"; +import type * as React from "react"; +import { cn } from "../lib/cn"; + +const alertVariants = cva( + "relative grid w-full items-start gap-x-2 rounded-xl border bg-card px-3 py-2.5 text-sm text-card-foreground has-data-[slot=alert-action]:grid-cols-[1fr_auto] has-[>svg]:grid-cols-[calc(var(--spacing)*5)_1fr] has-[>svg]:gap-x-2 has-[>svg]:has-data-[slot=alert-action]:grid-cols-[calc(var(--spacing)*4)_1fr_auto] [&>svg]:size-4 [&>svg]:mt-0.5", + { + variants: { + variant: { + info: "border-blue-6 bg-blue-2 [&>svg]:text-blue-10", + success: "border-green-6 bg-green-2 [&>svg]:text-green-10", + warning: "border-orange-6 bg-orange-2 [&>svg]:text-orange-10", + error: "border-red-6 bg-red-2 [&>svg]:text-red-10", + }, + }, + defaultVariants: { + variant: "info", + }, + }, +); + +function Root({ + className, + variant, + ...props +}: React.ComponentProps<"div"> & VariantProps) { + return ( +
+ ); +} + +function Title({ className, ...props }: React.ComponentProps<"div">) { + return ( +
+ ); +} + +function Description({ className, ...props }: React.ComponentProps<"div">) { + return ( + + ); +} + +function Action({ className, ...props }: React.ComponentProps<"div">) { + return ( +
+ ); +} + +export const Alert = { Root, Title, Description, Action }; diff --git a/packages/ui/src/components/Button.tsx b/packages/ui/src/components/Button.tsx index ab96a8e04..78879ad26 100644 --- a/packages/ui/src/components/Button.tsx +++ b/packages/ui/src/components/Button.tsx @@ -40,6 +40,13 @@ const buttonVariants = cva( size: "default", iconStyle: "auto", }, + compoundVariants: [ + { + size: "xs", + iconStyle: "auto", + class: "[&_svg]:size-3", + }, + ], }, );