Merge main into sweep/color-thief-feature
This commit is contained in:
commit
8712c87ceb
@ -11,6 +11,8 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@codemirror/lang-html": "^6.4.6",
|
"@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-dialog": "^1.0.5",
|
||||||
"@radix-ui/react-icons": "^1.3.0",
|
"@radix-ui/react-icons": "^1.3.0",
|
||||||
"@radix-ui/react-label": "^2.0.2",
|
"@radix-ui/react-label": "^2.0.2",
|
||||||
@ -22,8 +24,8 @@
|
|||||||
"classnames": "^2.3.2",
|
"classnames": "^2.3.2",
|
||||||
"clsx": "^2.0.0",
|
"clsx": "^2.0.0",
|
||||||
"codemirror": "^6.0.1",
|
"codemirror": "^6.0.1",
|
||||||
"html2canvas": "^1.4.1",
|
|
||||||
"copy-to-clipboard": "^3.3.3",
|
"copy-to-clipboard": "^3.3.3",
|
||||||
|
"html2canvas": "^1.4.1",
|
||||||
"react": "^18.2.0",
|
"react": "^18.2.0",
|
||||||
"react-dom": "^18.2.0",
|
"react-dom": "^18.2.0",
|
||||||
"react-dropzone": "^14.2.3",
|
"react-dropzone": "^14.2.3",
|
||||||
|
|||||||
@ -128,7 +128,9 @@ const [colors, setColors] = useState<string[]>([]);
|
|||||||
// Convert images to data URLs and set the prompt images state
|
// Convert images to data URLs and set the prompt images state
|
||||||
Promise.all(files.map((file) => fileToDataURL(file)))
|
Promise.all(files.map((file) => fileToDataURL(file)))
|
||||||
.then((dataUrls) => {
|
.then((dataUrls) => {
|
||||||
setReferenceImages(dataUrls.map((dataUrl) => dataUrl as string));
|
if(dataUrls.length > 0) {
|
||||||
|
setReferenceImages(dataUrls.map((dataUrl) => dataUrl as string));
|
||||||
|
}
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
// TODO: Display error to user
|
// TODO: Display error to user
|
||||||
@ -162,7 +164,10 @@ const [colors, setColors] = useState<string[]>([]);
|
|||||||
{/* eslint-disable-next-line @typescript-eslint/no-explicit-any */}
|
{/* eslint-disable-next-line @typescript-eslint/no-explicit-any */}
|
||||||
<div {...getRootProps({ style: style as any })}>
|
<div {...getRootProps({ style: style as any })}>
|
||||||
<input {...getInputProps()} />
|
<input {...getInputProps()} />
|
||||||
<p>Drop a screenshot here, paste from clipboard, or click to select</p>
|
<p className="text-slate-700 font-bold">
|
||||||
|
Drag & drop a screenshot here, or paste from clipboard, or click to
|
||||||
|
upload
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -1,26 +1,54 @@
|
|||||||
|
import React from "react";
|
||||||
import {
|
import {
|
||||||
Dialog,
|
AlertDialog,
|
||||||
DialogClose,
|
AlertDialogAction,
|
||||||
DialogContent,
|
AlertDialogContent,
|
||||||
DialogFooter,
|
AlertDialogFooter,
|
||||||
DialogHeader,
|
AlertDialogHeader,
|
||||||
DialogTitle,
|
AlertDialogTitle,
|
||||||
} from "@/components/ui/dialog";
|
} 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<{
|
const TermsOfServiceDialog: React.FC<{
|
||||||
open: boolean;
|
open: boolean;
|
||||||
onOpenChange: (open: boolean) => void;
|
onOpenChange: (open: boolean) => void;
|
||||||
}> = ({ open, onOpenChange }) => {
|
}> = ({ 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 (
|
return (
|
||||||
<Dialog open={open} onOpenChange={onOpenChange}>
|
<AlertDialog open={open} onOpenChange={onOpenChange}>
|
||||||
<DialogContent>
|
<AlertDialogContent>
|
||||||
<DialogHeader>
|
<AlertDialogHeader>
|
||||||
<DialogTitle className="mb-4">Terms of Service</DialogTitle>
|
<AlertDialogTitle className="mb-2">
|
||||||
</DialogHeader>
|
Enter your email to get started
|
||||||
|
</AlertDialogTitle>
|
||||||
|
</AlertDialogHeader>
|
||||||
|
|
||||||
|
<div className="mb-2">
|
||||||
|
<Input
|
||||||
|
placeholder="Email"
|
||||||
|
value={email}
|
||||||
|
onChange={(e) => {
|
||||||
|
setEmail(e.target.value);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
<div className="flex items-center space-x-2">
|
<div className="flex items-center space-x-2">
|
||||||
<span>
|
<span>
|
||||||
By using this website, you agree to the{" "}
|
By providing your email, you consent to receiving occasional product
|
||||||
|
updates, and you accept the{" "}
|
||||||
<a
|
<a
|
||||||
href="https://a.picoapps.xyz/camera-write"
|
href="https://a.picoapps.xyz/camera-write"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
@ -28,23 +56,35 @@ const TermsOfServiceDialog: React.FC<{
|
|||||||
>
|
>
|
||||||
terms of service
|
terms of service
|
||||||
</a>
|
</a>
|
||||||
. This project is MIT licensed.{" "}
|
. <br />
|
||||||
|
<br />
|
||||||
|
Prefer to run it yourself locally? This project is open source.{" "}
|
||||||
<a
|
<a
|
||||||
href="https://github.com/abi/screenshot-to-code"
|
href="https://github.com/abi/screenshot-to-code"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
className="underline"
|
className="underline"
|
||||||
>
|
>
|
||||||
You can run this app locally by downloading the source code from
|
Download the code and get started on Github.
|
||||||
Github.
|
|
||||||
</a>
|
</a>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<DialogFooter>
|
<AlertDialogFooter>
|
||||||
<DialogClose>Agree</DialogClose>
|
<AlertDialogAction
|
||||||
</DialogFooter>
|
onClick={(e) => {
|
||||||
</DialogContent>
|
if (!email.trim() || !email.trim().includes("@")) {
|
||||||
</Dialog>
|
e.preventDefault();
|
||||||
|
toast.error("Please enter your email");
|
||||||
|
} else {
|
||||||
|
onSubscribe();
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Agree
|
||||||
|
</AlertDialogAction>
|
||||||
|
</AlertDialogFooter>
|
||||||
|
</AlertDialogContent>
|
||||||
|
</AlertDialog>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
139
frontend/src/components/ui/alert-dialog.tsx
Normal file
139
frontend/src/components/ui/alert-dialog.tsx
Normal file
@ -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<typeof AlertDialogPrimitive.Overlay>,
|
||||||
|
React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Overlay>
|
||||||
|
>(({ className, ...props }, ref) => (
|
||||||
|
<AlertDialogPrimitive.Overlay
|
||||||
|
className={cn(
|
||||||
|
"fixed inset-0 z-50 bg-background/80 backdrop-blur-sm data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
ref={ref}
|
||||||
|
/>
|
||||||
|
))
|
||||||
|
AlertDialogOverlay.displayName = AlertDialogPrimitive.Overlay.displayName
|
||||||
|
|
||||||
|
const AlertDialogContent = React.forwardRef<
|
||||||
|
React.ElementRef<typeof AlertDialogPrimitive.Content>,
|
||||||
|
React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Content>
|
||||||
|
>(({ className, ...props }, ref) => (
|
||||||
|
<AlertDialogPortal>
|
||||||
|
<AlertDialogOverlay />
|
||||||
|
<AlertDialogPrimitive.Content
|
||||||
|
ref={ref}
|
||||||
|
className={cn(
|
||||||
|
"fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
</AlertDialogPortal>
|
||||||
|
))
|
||||||
|
AlertDialogContent.displayName = AlertDialogPrimitive.Content.displayName
|
||||||
|
|
||||||
|
const AlertDialogHeader = ({
|
||||||
|
className,
|
||||||
|
...props
|
||||||
|
}: React.HTMLAttributes<HTMLDivElement>) => (
|
||||||
|
<div
|
||||||
|
className={cn(
|
||||||
|
"flex flex-col space-y-2 text-center sm:text-left",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
AlertDialogHeader.displayName = "AlertDialogHeader"
|
||||||
|
|
||||||
|
const AlertDialogFooter = ({
|
||||||
|
className,
|
||||||
|
...props
|
||||||
|
}: React.HTMLAttributes<HTMLDivElement>) => (
|
||||||
|
<div
|
||||||
|
className={cn(
|
||||||
|
"flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
AlertDialogFooter.displayName = "AlertDialogFooter"
|
||||||
|
|
||||||
|
const AlertDialogTitle = React.forwardRef<
|
||||||
|
React.ElementRef<typeof AlertDialogPrimitive.Title>,
|
||||||
|
React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Title>
|
||||||
|
>(({ className, ...props }, ref) => (
|
||||||
|
<AlertDialogPrimitive.Title
|
||||||
|
ref={ref}
|
||||||
|
className={cn("text-lg font-semibold", className)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
))
|
||||||
|
AlertDialogTitle.displayName = AlertDialogPrimitive.Title.displayName
|
||||||
|
|
||||||
|
const AlertDialogDescription = React.forwardRef<
|
||||||
|
React.ElementRef<typeof AlertDialogPrimitive.Description>,
|
||||||
|
React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Description>
|
||||||
|
>(({ className, ...props }, ref) => (
|
||||||
|
<AlertDialogPrimitive.Description
|
||||||
|
ref={ref}
|
||||||
|
className={cn("text-sm text-muted-foreground", className)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
))
|
||||||
|
AlertDialogDescription.displayName =
|
||||||
|
AlertDialogPrimitive.Description.displayName
|
||||||
|
|
||||||
|
const AlertDialogAction = React.forwardRef<
|
||||||
|
React.ElementRef<typeof AlertDialogPrimitive.Action>,
|
||||||
|
React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Action>
|
||||||
|
>(({ className, ...props }, ref) => (
|
||||||
|
<AlertDialogPrimitive.Action
|
||||||
|
ref={ref}
|
||||||
|
className={cn(buttonVariants(), className)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
))
|
||||||
|
AlertDialogAction.displayName = AlertDialogPrimitive.Action.displayName
|
||||||
|
|
||||||
|
const AlertDialogCancel = React.forwardRef<
|
||||||
|
React.ElementRef<typeof AlertDialogPrimitive.Cancel>,
|
||||||
|
React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Cancel>
|
||||||
|
>(({ className, ...props }, ref) => (
|
||||||
|
<AlertDialogPrimitive.Cancel
|
||||||
|
ref={ref}
|
||||||
|
className={cn(
|
||||||
|
buttonVariants({ variant: "outline" }),
|
||||||
|
"mt-2 sm:mt-0",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
))
|
||||||
|
AlertDialogCancel.displayName = AlertDialogPrimitive.Cancel.displayName
|
||||||
|
|
||||||
|
export {
|
||||||
|
AlertDialog,
|
||||||
|
AlertDialogPortal,
|
||||||
|
AlertDialogOverlay,
|
||||||
|
AlertDialogTrigger,
|
||||||
|
AlertDialogContent,
|
||||||
|
AlertDialogHeader,
|
||||||
|
AlertDialogFooter,
|
||||||
|
AlertDialogTitle,
|
||||||
|
AlertDialogDescription,
|
||||||
|
AlertDialogAction,
|
||||||
|
AlertDialogCancel,
|
||||||
|
}
|
||||||
28
frontend/src/components/ui/checkbox.tsx
Normal file
28
frontend/src/components/ui/checkbox.tsx
Normal file
@ -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<typeof CheckboxPrimitive.Root>,
|
||||||
|
React.ComponentPropsWithoutRef<typeof CheckboxPrimitive.Root>
|
||||||
|
>(({ className, ...props }, ref) => (
|
||||||
|
<CheckboxPrimitive.Root
|
||||||
|
ref={ref}
|
||||||
|
className={cn(
|
||||||
|
"peer h-4 w-4 shrink-0 rounded-sm border border-primary shadow focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
>
|
||||||
|
<CheckboxPrimitive.Indicator
|
||||||
|
className={cn("flex items-center justify-center text-current")}
|
||||||
|
>
|
||||||
|
<CheckIcon className="h-4 w-4" />
|
||||||
|
</CheckboxPrimitive.Indicator>
|
||||||
|
</CheckboxPrimitive.Root>
|
||||||
|
))
|
||||||
|
Checkbox.displayName = CheckboxPrimitive.Root.displayName
|
||||||
|
|
||||||
|
export { Checkbox }
|
||||||
@ -7,3 +7,6 @@ export const WS_BACKEND_URL =
|
|||||||
|
|
||||||
export const HTTP_BACKEND_URL =
|
export const HTTP_BACKEND_URL =
|
||||||
import.meta.env.VITE_HTTP_BACKEND_URL || "http://127.0.0.1:7001";
|
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;
|
||||||
|
|||||||
@ -593,6 +593,34 @@
|
|||||||
dependencies:
|
dependencies:
|
||||||
"@babel/runtime" "^7.13.10"
|
"@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":
|
"@radix-ui/react-collection@1.0.3":
|
||||||
version "1.0.3"
|
version "1.0.3"
|
||||||
resolved "https://registry.yarnpkg.com/@radix-ui/react-collection/-/react-collection-1.0.3.tgz#9595a66e09026187524a36c6e7e9c7d286469159"
|
resolved "https://registry.yarnpkg.com/@radix-ui/react-collection/-/react-collection-1.0.3.tgz#9595a66e09026187524a36c6e7e9c7d286469159"
|
||||||
@ -618,7 +646,7 @@
|
|||||||
dependencies:
|
dependencies:
|
||||||
"@babel/runtime" "^7.13.10"
|
"@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"
|
version "1.0.5"
|
||||||
resolved "https://registry.yarnpkg.com/@radix-ui/react-dialog/-/react-dialog-1.0.5.tgz#71657b1b116de6c7a0b03242d7d43e01062c7300"
|
resolved "https://registry.yarnpkg.com/@radix-ui/react-dialog/-/react-dialog-1.0.5.tgz#71657b1b116de6c7a0b03242d7d43e01062c7300"
|
||||||
integrity sha512-GjWJX/AUpB703eEBanuBnIWdIXg6NvJFCXcNlSZk4xdszCdhrJgBoUd1cGk67vFO+WdA2pfI/plOpqz/5GUP6Q==
|
integrity sha512-GjWJX/AUpB703eEBanuBnIWdIXg6NvJFCXcNlSZk4xdszCdhrJgBoUd1cGk67vFO+WdA2pfI/plOpqz/5GUP6Q==
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user