Add unsend campaign feature (#45)

* Add unsend email editor

Add email editor

Add more email editor

Add renderer partial

Add more marketing email features

* Add more campaign feature

* Add variables

* Getting there

* campaign is there mfs

* Add migration
This commit is contained in:
KM Koushik
2024-08-10 10:09:10 +10:00
committed by GitHub
parent 0c072579b9
commit 5ddc0a7bb9
92 changed files with 11766 additions and 338 deletions

View File

@@ -33,11 +33,13 @@
"@radix-ui/react-dialog": "^1.0.5",
"@radix-ui/react-dropdown-menu": "^2.0.6",
"@radix-ui/react-label": "^2.0.2",
"@radix-ui/react-popover": "^1.1.1",
"@radix-ui/react-select": "^2.0.0",
"@radix-ui/react-separator": "^1.0.3",
"@radix-ui/react-slot": "^1.0.2",
"@radix-ui/react-switch": "^1.0.3",
"@radix-ui/react-tabs": "^1.0.4",
"@radix-ui/react-tooltip": "^1.1.2",
"add": "^2.0.6",
"class-variance-authority": "^0.7.0",
"clsx": "^2.1.0",

View File

@@ -19,6 +19,7 @@ const buttonVariants = cva(
ghost: "hover:bg-accent hover:text-accent-foreground",
icon: "bg-transparent hover:bg-transparent hover:bg-accent hover:text-accent-foreground",
link: "text-primary underline-offset-4 hover:underline",
silent: "bg-transparent hover:bg-accent/10 p-1",
},
size: {
default: "h-9 px-4 ",

View File

@@ -0,0 +1,31 @@
"use client";
import * as React from "react";
import * as PopoverPrimitive from "@radix-ui/react-popover";
import { cn } from "../lib/utils";
const Popover = PopoverPrimitive.Root;
const PopoverTrigger = PopoverPrimitive.Trigger;
const PopoverContent = React.forwardRef<
React.ElementRef<typeof PopoverPrimitive.Content>,
React.ComponentPropsWithoutRef<typeof PopoverPrimitive.Content>
>(({ className, align = "center", sideOffset = 4, ...props }, ref) => (
<PopoverPrimitive.Portal>
<PopoverPrimitive.Content
ref={ref}
align={align}
sideOffset={sideOffset}
className={cn(
"z-50 w-72 rounded-md border bg-popover p-4 text-popover-foreground shadow-md outline-none 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-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
className
)}
{...props}
/>
</PopoverPrimitive.Portal>
));
PopoverContent.displayName = PopoverPrimitive.Content.displayName;
export { Popover, PopoverTrigger, PopoverContent };

View File

@@ -18,7 +18,7 @@ const Separator = React.forwardRef<
decorative={decorative}
orientation={orientation}
className={cn(
"shrink-0 bg-border",
"shrink-0 bg-border ",
orientation === "horizontal" ? "h-[1px] w-full" : "h-full w-[1px]",
className
)}

View File

@@ -6,7 +6,7 @@ const Table = React.forwardRef<
HTMLTableElement,
React.HTMLAttributes<HTMLTableElement>
>(({ className, ...props }, ref) => (
<div className="relative w-full overflow-auto">
<div className="relative w-full overflow-auto ">
<table
ref={ref}
className={cn("w-full caption-bottom text-sm", className)}

View File

@@ -6,7 +6,8 @@ import { CheckIcon, ClipboardCopy } from "lucide-react";
export const TextWithCopyButton: React.FC<{
value: string;
className?: string;
}> = ({ value, className }) => {
alwaysShowCopy?: boolean;
}> = ({ value, className, alwaysShowCopy }) => {
const [isCopied, setIsCopied] = React.useState(false);
const copyToClipboard = async () => {
@@ -24,7 +25,9 @@ export const TextWithCopyButton: React.FC<{
<div className={className}>{value}</div>
<Button
variant="ghost"
className="hover:bg-transparent p-0 cursor-pointer text-muted-foreground opacity-0 group-hover:opacity-100"
className={`hover:bg-transparent p-0 cursor-pointer text-muted-foreground ${
alwaysShowCopy ? "opacity-100" : "opacity-0 group-hover:opacity-100"
}`}
onClick={copyToClipboard}
>
{isCopied ? (

View File

@@ -0,0 +1,24 @@
import * as React from "react";
import { cn } from "../lib/utils";
export interface TextareaProps
extends React.TextareaHTMLAttributes<HTMLTextAreaElement> {}
const Textarea = React.forwardRef<HTMLTextAreaElement, TextareaProps>(
({ className, ...props }, ref) => {
return (
<textarea
className={cn(
"flex min-h-[80px] w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
className
)}
ref={ref}
{...props}
/>
);
}
);
Textarea.displayName = "Textarea";
export { Textarea };

View File

@@ -0,0 +1,30 @@
"use client";
import * as React from "react";
import * as TooltipPrimitive from "@radix-ui/react-tooltip";
import { cn } from "../lib/utils";
const TooltipProvider = TooltipPrimitive.Provider;
const Tooltip = TooltipPrimitive.Root;
const TooltipTrigger = TooltipPrimitive.Trigger;
const TooltipContent = React.forwardRef<
React.ElementRef<typeof TooltipPrimitive.Content>,
React.ComponentPropsWithoutRef<typeof TooltipPrimitive.Content>
>(({ className, sideOffset = 4, ...props }, ref) => (
<TooltipPrimitive.Content
ref={ref}
sideOffset={sideOffset}
className={cn(
"z-50 overflow-hidden rounded-md border bg-popover px-3 py-1.5 text-sm text-popover-foreground shadow-md animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
className
)}
{...props}
/>
));
TooltipContent.displayName = TooltipPrimitive.Content.displayName;
export { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider };

View File

@@ -3,7 +3,8 @@
@tailwind utilities;
@layer base {
:root {
:root,
.light {
--background: 0 0% 100%;
--foreground: 222.2 84% 4.9%;
@@ -28,7 +29,7 @@
--destructive: 0 84.2% 60.2%;
--destructive-foreground: 210 40% 98%;
--border: 214.3 31.8% 91.4%;
--border: 214 1% 71%;
--input: 214.3 31.8% 91.4%;
--ring: 222.2 84% 4.9%;
@@ -77,3 +78,12 @@
@apply h-full;
}
}
/* .app,
::before,
::after {
@apply border-border;
box-sizing: border-box;
border-width: 0;
border-style: solid;
} */