diff --git a/frontend/package.json b/frontend/package.json index ef840e7..40fed34 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -11,6 +11,8 @@ }, "dependencies": { "@codemirror/lang-html": "^6.4.6", + "@radix-ui/react-alert-dialog": "^1.0.5", + "@radix-ui/react-checkbox": "^1.0.4", "@radix-ui/react-dialog": "^1.0.5", "@radix-ui/react-icons": "^1.3.0", "@radix-ui/react-label": "^2.0.2", @@ -22,8 +24,8 @@ "classnames": "^2.3.2", "clsx": "^2.0.0", "codemirror": "^6.0.1", - "html2canvas": "^1.4.1", "copy-to-clipboard": "^3.3.3", + "html2canvas": "^1.4.1", "react": "^18.2.0", "react-dom": "^18.2.0", "react-dropzone": "^14.2.3", diff --git a/frontend/src/components/ImageUpload.tsx b/frontend/src/components/ImageUpload.tsx index 1942f29..d1b7f03 100644 --- a/frontend/src/components/ImageUpload.tsx +++ b/frontend/src/components/ImageUpload.tsx @@ -128,7 +128,9 @@ const [colors, setColors] = useState([]); // Convert images to data URLs and set the prompt images state Promise.all(files.map((file) => fileToDataURL(file))) .then((dataUrls) => { - setReferenceImages(dataUrls.map((dataUrl) => dataUrl as string)); + if(dataUrls.length > 0) { + setReferenceImages(dataUrls.map((dataUrl) => dataUrl as string)); + } }) .catch((error) => { // TODO: Display error to user @@ -162,7 +164,10 @@ const [colors, setColors] = useState([]); {/* eslint-disable-next-line @typescript-eslint/no-explicit-any */}
-

Drop a screenshot here, paste from clipboard, or click to select

+

+ Drag & drop a screenshot here, or paste from clipboard, or click to + upload +

); diff --git a/frontend/src/components/TermsOfServiceDialog.tsx b/frontend/src/components/TermsOfServiceDialog.tsx index 2bd3178..b812d26 100644 --- a/frontend/src/components/TermsOfServiceDialog.tsx +++ b/frontend/src/components/TermsOfServiceDialog.tsx @@ -1,26 +1,54 @@ +import React from "react"; import { - Dialog, - DialogClose, - DialogContent, - DialogFooter, - DialogHeader, - DialogTitle, -} from "@/components/ui/dialog"; + AlertDialog, + AlertDialogAction, + AlertDialogContent, + AlertDialogFooter, + AlertDialogHeader, + AlertDialogTitle, +} from "./ui/alert-dialog"; +import { Input } from "./ui/input"; +import toast from "react-hot-toast"; +import { PICO_BACKEND_FORM_SECRET } from "../config"; const TermsOfServiceDialog: React.FC<{ open: boolean; onOpenChange: (open: boolean) => void; }> = ({ open, onOpenChange }) => { + const [email, setEmail] = React.useState(""); + + const onSubscribe = async () => { + await fetch("https://backend.buildpicoapps.com/form", { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ email, secret: PICO_BACKEND_FORM_SECRET }), + }); + }; return ( - - - - Terms of Service - + + + + + Enter your email to get started + + + +
+ { + setEmail(e.target.value); + }} + /> +
- By using this website, you agree to the{" "} + By providing your email, you consent to receiving occasional product + updates, and you accept the{" "} terms of service - . This project is MIT licensed.{" "} + .
+
+ Prefer to run it yourself locally? This project is open source.{" "} - You can run this app locally by downloading the source code from - Github. + Download the code and get started on Github.
- - Agree - -
-
+ + { + if (!email.trim() || !email.trim().includes("@")) { + e.preventDefault(); + toast.error("Please enter your email"); + } else { + onSubscribe(); + } + }} + > + Agree + + + + ); }; diff --git a/frontend/src/components/ui/alert-dialog.tsx b/frontend/src/components/ui/alert-dialog.tsx new file mode 100644 index 0000000..cc49f39 --- /dev/null +++ b/frontend/src/components/ui/alert-dialog.tsx @@ -0,0 +1,139 @@ +import * as React from "react" +import * as AlertDialogPrimitive from "@radix-ui/react-alert-dialog" + +import { cn } from "@/lib/utils" +import { buttonVariants } from "@/components/ui/button" + +const AlertDialog = AlertDialogPrimitive.Root + +const AlertDialogTrigger = AlertDialogPrimitive.Trigger + +const AlertDialogPortal = AlertDialogPrimitive.Portal + +const AlertDialogOverlay = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)) +AlertDialogOverlay.displayName = AlertDialogPrimitive.Overlay.displayName + +const AlertDialogContent = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + + + + +)) +AlertDialogContent.displayName = AlertDialogPrimitive.Content.displayName + +const AlertDialogHeader = ({ + className, + ...props +}: React.HTMLAttributes) => ( +
+) +AlertDialogHeader.displayName = "AlertDialogHeader" + +const AlertDialogFooter = ({ + className, + ...props +}: React.HTMLAttributes) => ( +
+) +AlertDialogFooter.displayName = "AlertDialogFooter" + +const AlertDialogTitle = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)) +AlertDialogTitle.displayName = AlertDialogPrimitive.Title.displayName + +const AlertDialogDescription = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)) +AlertDialogDescription.displayName = + AlertDialogPrimitive.Description.displayName + +const AlertDialogAction = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)) +AlertDialogAction.displayName = AlertDialogPrimitive.Action.displayName + +const AlertDialogCancel = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)) +AlertDialogCancel.displayName = AlertDialogPrimitive.Cancel.displayName + +export { + AlertDialog, + AlertDialogPortal, + AlertDialogOverlay, + AlertDialogTrigger, + AlertDialogContent, + AlertDialogHeader, + AlertDialogFooter, + AlertDialogTitle, + AlertDialogDescription, + AlertDialogAction, + AlertDialogCancel, +} diff --git a/frontend/src/components/ui/checkbox.tsx b/frontend/src/components/ui/checkbox.tsx new file mode 100644 index 0000000..f831532 --- /dev/null +++ b/frontend/src/components/ui/checkbox.tsx @@ -0,0 +1,28 @@ +import * as React from "react" +import * as CheckboxPrimitive from "@radix-ui/react-checkbox" +import { CheckIcon } from "@radix-ui/react-icons" + +import { cn } from "@/lib/utils" + +const Checkbox = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + + + + + +)) +Checkbox.displayName = CheckboxPrimitive.Root.displayName + +export { Checkbox } diff --git a/frontend/src/config.ts b/frontend/src/config.ts index 7a6251c..4f0de2f 100644 --- a/frontend/src/config.ts +++ b/frontend/src/config.ts @@ -7,3 +7,6 @@ export const WS_BACKEND_URL = export const HTTP_BACKEND_URL = import.meta.env.VITE_HTTP_BACKEND_URL || "http://127.0.0.1:7001"; + +export const PICO_BACKEND_FORM_SECRET = + import.meta.env.VITE_PICO_BACKEND_FORM_SECRET || null; diff --git a/frontend/yarn.lock b/frontend/yarn.lock index 1230589..21ea63f 100644 --- a/frontend/yarn.lock +++ b/frontend/yarn.lock @@ -593,6 +593,34 @@ dependencies: "@babel/runtime" "^7.13.10" +"@radix-ui/react-alert-dialog@^1.0.5": + version "1.0.5" + resolved "https://registry.yarnpkg.com/@radix-ui/react-alert-dialog/-/react-alert-dialog-1.0.5.tgz#70dd529cbf1e4bff386814d3776901fcaa131b8c" + integrity sha512-OrVIOcZL0tl6xibeuGt5/+UxoT2N27KCFOPjFyfXMnchxSHZ/OW7cCX2nGlIYJrbHK/fczPcFzAwvNBB6XBNMA== + dependencies: + "@babel/runtime" "^7.13.10" + "@radix-ui/primitive" "1.0.1" + "@radix-ui/react-compose-refs" "1.0.1" + "@radix-ui/react-context" "1.0.1" + "@radix-ui/react-dialog" "1.0.5" + "@radix-ui/react-primitive" "1.0.3" + "@radix-ui/react-slot" "1.0.2" + +"@radix-ui/react-checkbox@^1.0.4": + version "1.0.4" + resolved "https://registry.yarnpkg.com/@radix-ui/react-checkbox/-/react-checkbox-1.0.4.tgz#98f22c38d5010dd6df4c5744cac74087e3275f4b" + integrity sha512-CBuGQa52aAYnADZVt/KBQzXrwx6TqnlwtcIPGtVt5JkkzQwMOLJjPukimhfKEr4GQNd43C+djUh5Ikopj8pSLg== + dependencies: + "@babel/runtime" "^7.13.10" + "@radix-ui/primitive" "1.0.1" + "@radix-ui/react-compose-refs" "1.0.1" + "@radix-ui/react-context" "1.0.1" + "@radix-ui/react-presence" "1.0.1" + "@radix-ui/react-primitive" "1.0.3" + "@radix-ui/react-use-controllable-state" "1.0.1" + "@radix-ui/react-use-previous" "1.0.1" + "@radix-ui/react-use-size" "1.0.1" + "@radix-ui/react-collection@1.0.3": version "1.0.3" resolved "https://registry.yarnpkg.com/@radix-ui/react-collection/-/react-collection-1.0.3.tgz#9595a66e09026187524a36c6e7e9c7d286469159" @@ -618,7 +646,7 @@ dependencies: "@babel/runtime" "^7.13.10" -"@radix-ui/react-dialog@^1.0.5": +"@radix-ui/react-dialog@1.0.5", "@radix-ui/react-dialog@^1.0.5": version "1.0.5" resolved "https://registry.yarnpkg.com/@radix-ui/react-dialog/-/react-dialog-1.0.5.tgz#71657b1b116de6c7a0b03242d7d43e01062c7300" integrity sha512-GjWJX/AUpB703eEBanuBnIWdIXg6NvJFCXcNlSZk4xdszCdhrJgBoUd1cGk67vFO+WdA2pfI/plOpqz/5GUP6Q==