Skip to content

Commit fc892c5

Browse files
committed
feat: Introduce email generation panel, update codegen options, and upgrade various dependencies.
1 parent d412266 commit fc892c5

File tree

12 files changed

+1794
-1621
lines changed

12 files changed

+1794
-1621
lines changed

apps/debug/next-env.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
/// <reference types="next" />
22
/// <reference types="next/image-types/global" />
3+
/// <reference path="./.next/types/routes.d.ts" />
34

45
// NOTE: This file should not be edited
56
// see https://nextjs.org/docs/app/api-reference/config/typescript for more information.

apps/debug/package.json

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,21 +11,21 @@
1111
},
1212
"dependencies": {
1313
"backend": "workspace:*",
14-
"next": "^15.3.4",
14+
"next": "^15.5.7",
1515
"plugin-ui": "workspace:*",
16-
"react": "^19.1.0",
17-
"react-dom": "^19.1.0"
16+
"react": "^19.2.1",
17+
"react-dom": "^19.2.1"
1818
},
1919
"devDependencies": {
20-
"@tailwindcss/postcss": "^4.1.11",
21-
"@types/node": "^24.0.4",
22-
"@types/react": "^19.1.8",
23-
"@types/react-dom": "^19.1.6",
20+
"@tailwindcss/postcss": "^4.1.17",
21+
"@types/node": "^24.10.2",
22+
"@types/react": "^19.2.7",
23+
"@types/react-dom": "^19.2.3",
2424
"eslint-config-custom": "workspace:*",
2525
"postcss": "^8.5.6",
2626
"tailwindcss": "4.0.14",
2727
"tsconfig": "workspace:*",
2828
"types": "workspace:*",
29-
"typescript": "^5.8.3"
29+
"typescript": "^5.9.3"
3030
}
3131
}

apps/plugin/package.json

Lines changed: 20 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -10,38 +10,38 @@
1010
"dev": "pnpm build:watch"
1111
},
1212
"dependencies": {
13-
"@figma/plugin-typings": "^1.114.0",
13+
"@figma/plugin-typings": "^1.121.0",
1414
"backend": "workspace:*",
1515
"clsx": "^2.1.1",
1616
"copy-to-clipboard": "^3.3.3",
1717
"lucide-react": "^0.483.0",
18-
"motion": "^12.19.1",
19-
"nanoid": "^5.1.5",
18+
"motion": "^12.23.25",
19+
"nanoid": "^5.1.6",
2020
"plugin-ui": "workspace:*",
21-
"react": "^19.1.0",
22-
"react-dom": "^19.1.0",
23-
"tailwind-merge": "^3.3.1"
21+
"react": "^19.2.1",
22+
"react-dom": "^19.2.1",
23+
"tailwind-merge": "^3.4.0"
2424
},
2525
"devDependencies": {
26-
"@tailwindcss/postcss": "^4.1.11",
27-
"@types/node": "^24.0.4",
28-
"@types/react": "^19.1.8",
29-
"@types/react-dom": "^19.1.6",
30-
"@typescript-eslint/eslint-plugin": "^8.35.0",
31-
"@typescript-eslint/parser": "^8.35.0",
32-
"@vitejs/plugin-react": "^4.6.0",
33-
"@vitejs/plugin-react-swc": "^3.10.2",
34-
"concurrently": "^9.2.0",
35-
"esbuild": "^0.25.5",
26+
"@tailwindcss/postcss": "^4.1.17",
27+
"@types/node": "^24.10.2",
28+
"@types/react": "^19.2.7",
29+
"@types/react-dom": "^19.2.3",
30+
"@typescript-eslint/eslint-plugin": "^8.49.0",
31+
"@typescript-eslint/parser": "^8.49.0",
32+
"@vitejs/plugin-react": "^4.7.0",
33+
"@vitejs/plugin-react-swc": "^3.11.0",
34+
"concurrently": "^9.2.1",
35+
"esbuild": "^0.25.12",
3636
"eslint-config-custom": "workspace:*",
3737
"eslint-plugin-react-hooks": "^5.2.0",
38-
"eslint-plugin-react-refresh": "^0.4.20",
38+
"eslint-plugin-react-refresh": "^0.4.24",
3939
"postcss": "^8.5.6",
4040
"tailwindcss": "4.0.14",
4141
"tsconfig": "workspace:*",
4242
"types": "workspace:*",
43-
"typescript": "^5.8.3",
44-
"vite": "^5.4.19",
45-
"vite-plugin-singlefile": "^2.2.0"
43+
"typescript": "^5.9.3",
44+
"vite": "^5.4.21",
45+
"vite-plugin-singlefile": "^2.3.0"
4646
}
4747
}

package.json

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,10 @@
1010
"format": "prettier --write \"**/*.{ts,tsx,css,md}\""
1111
},
1212
"devDependencies": {
13-
"eslint": "^9.29.0",
13+
"eslint": "^9.39.1",
1414
"eslint-config-custom": "workspace:*",
15-
"prettier": "^3.6.2",
16-
"turbo": "^2.5.4",
17-
"typescript": "^5.8.3"
15+
"prettier": "^3.7.4",
16+
"turbo": "^2.6.3",
17+
"typescript": "^5.9.3"
1818
}
1919
}

packages/backend/package.json

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -13,20 +13,20 @@
1313
"lint": "eslint \"src/**/*.ts*\""
1414
},
1515
"dependencies": {
16-
"@figma/plugin-typings": "^1.114.0",
17-
"js-base64": "^3.7.7",
18-
"nanoid": "^5.1.5",
16+
"@figma/plugin-typings": "^1.121.0",
17+
"js-base64": "^3.7.8",
18+
"nanoid": "^5.1.6",
1919
"react": "19.0.0",
2020
"react-dom": "19.0.0",
2121
"types": "workspace:*"
2222
},
2323
"devDependencies": {
24-
"@types/react": "^19.1.8",
25-
"@types/react-dom": "^19.1.6",
26-
"eslint": "^9.29.0",
24+
"@types/react": "^19.2.7",
25+
"@types/react-dom": "^19.2.3",
26+
"eslint": "^9.39.1",
2727
"eslint-config-custom": "workspace:*",
2828
"tsconfig": "workspace:*",
29-
"tsup": "^8.5.0",
30-
"typescript": "^5.8.3"
29+
"tsup": "^8.5.1",
30+
"typescript": "^5.9.3"
3131
}
3232
}

packages/eslint-config-custom/package.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@
44
"main": "index.js",
55
"license": "MIT",
66
"dependencies": {
7-
"eslint-config-next": "^15.3.4",
8-
"eslint-config-prettier": "^10.1.5",
9-
"eslint-config-turbo": "^2.5.4",
7+
"eslint-config-next": "^15.5.7",
8+
"eslint-config-prettier": "^10.1.8",
9+
"eslint-config-turbo": "^2.6.3",
1010
"eslint-plugin-react": "7.37.4"
1111
},
1212
"publishConfig": {

packages/plugin-ui/package.json

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,22 +10,22 @@
1010
"lint": "eslint \"src/**/*.ts*\""
1111
},
1212
"dependencies": {
13-
"@types/react": "^19.1.8",
14-
"@types/react-dom": "^19.1.6",
13+
"@types/react": "^19.2.7",
14+
"@types/react-dom": "^19.2.3",
1515
"@types/react-syntax-highlighter": "15.5.13",
1616
"clsx": "^2.1.1",
1717
"copy-to-clipboard": "^3.3.3",
1818
"lucide-react": "^0.483.0",
19-
"react": "^19.1.0",
20-
"react-syntax-highlighter": "^15.6.1",
21-
"tailwind-merge": "^3.3.1",
22-
"tailwindcss": "^4.1.11"
19+
"react": "^19.2.1",
20+
"react-syntax-highlighter": "^15.6.6",
21+
"tailwind-merge": "^3.4.0",
22+
"tailwindcss": "^4.1.17"
2323
},
2424
"devDependencies": {
25-
"eslint": "^9.29.0",
25+
"eslint": "^9.39.1",
2626
"eslint-config-custom": "workspace:*",
2727
"tsconfig": "workspace:*",
2828
"types": "workspace:*",
29-
"typescript": "^5.8.3"
29+
"typescript": "^5.9.3"
3030
}
3131
}

packages/plugin-ui/src/PluginUI.tsx

Lines changed: 31 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import GradientsPanel from "./components/GradientsPanel";
44
import ColorsPanel from "./components/ColorsPanel";
55
import CodePanel from "./components/CodePanel";
66
import About from "./components/About";
7+
import EmailPanel from "./components/EmailPanel";
78
import WarningsPanel from "./components/WarningsPanel";
89
import {
910
Framework,
@@ -19,7 +20,7 @@ import {
1920
} from "./codegenPreferenceOptions";
2021
import Loading from "./components/Loading";
2122
import { useState } from "react";
22-
import { InfoIcon } from "lucide-react";
23+
import { InfoIcon, MailIcon } from "lucide-react";
2324
import React from "react";
2425

2526
type PluginUIProps = {
@@ -45,29 +46,34 @@ type FrameworkTabsProps = {
4546
selectedFramework: Framework;
4647
setSelectedFramework: (framework: Framework) => void;
4748
showAbout: boolean;
49+
showEmail: boolean;
4850
setShowAbout: (show: boolean) => void;
51+
setShowEmail: (show: boolean) => void;
4952
};
5053

5154
const FrameworkTabs = ({
5255
frameworks,
5356
selectedFramework,
5457
setSelectedFramework,
5558
showAbout,
59+
showEmail,
5660
setShowAbout,
61+
setShowEmail,
5762
}: FrameworkTabsProps) => {
5863
return (
5964
<div className="grid grid-cols-4 sm:grid-cols-2 md:grid-cols-4 gap-1 grow">
6065
{frameworks.map((tab) => (
6166
<button
6267
key={`tab ${tab}`}
63-
className={`w-full text-sm rounded-md transition-colors font-medium ${
64-
selectedFramework === tab && !showAbout
68+
className={`w-full h-8 flex items-center justify-center text-sm rounded-md transition-colors font-medium ${
69+
selectedFramework === tab && !showAbout && !showEmail
6570
? "bg-primary text-primary-foreground shadow-xs"
6671
: "bg-muted hover:bg-primary/90 hover:text-primary-foreground"
6772
}`}
6873
onClick={() => {
6974
setSelectedFramework(tab as Framework);
7075
setShowAbout(false);
76+
setShowEmail(false);
7177
}}
7278
>
7379
{tab}
@@ -79,6 +85,7 @@ const FrameworkTabs = ({
7985

8086
export const PluginUI = (props: PluginUIProps) => {
8187
const [showAbout, setShowAbout] = useState(false);
88+
const [showEmail, setShowEmail] = useState(false);
8289

8390
const [previewExpanded, setPreviewExpanded] = useState(false);
8491
const [previewViewMode, setPreviewViewMode] = useState<
@@ -102,15 +109,33 @@ export const PluginUI = (props: PluginUIProps) => {
102109
selectedFramework={props.selectedFramework}
103110
setSelectedFramework={props.setSelectedFramework}
104111
showAbout={showAbout}
112+
showEmail={showEmail}
105113
setShowAbout={setShowAbout}
114+
setShowEmail={setShowEmail}
106115
/>
116+
<button
117+
className={`px-3 h-8 flex items-center justify-center rounded-md text-sm font-medium transition-colors ${
118+
showEmail
119+
? "bg-primary text-primary-foreground shadow-xs"
120+
: "bg-muted hover:bg-primary/90 hover:text-primary-foreground"
121+
}`}
122+
onClick={() => {
123+
setShowEmail(!showEmail);
124+
setShowAbout(false);
125+
}}
126+
>
127+
Email
128+
</button>
107129
<button
108130
className={`w-8 h-8 flex items-center justify-center rounded-md text-sm font-medium ${
109131
showAbout
110132
? "bg-primary text-primary-foreground shadow-xs"
111133
: "bg-muted hover:bg-primary/90 hover:text-primary-foreground"
112134
}`}
113-
onClick={() => setShowAbout(!showAbout)}
135+
onClick={() => {
136+
setShowAbout(!showAbout);
137+
setShowEmail(false);
138+
}}
114139
aria-label="About"
115140
>
116141
<InfoIcon size={16} />
@@ -130,6 +155,8 @@ export const PluginUI = (props: PluginUIProps) => {
130155
useOldPluginVersion={props.settings?.useOldPluginVersion2025}
131156
onPreferenceChanged={props.onPreferenceChanged}
132157
/>
158+
) : showEmail ? (
159+
<EmailPanel />
133160
) : (
134161
<div className="flex flex-col items-center px-4 py-2 gap-2 dark:bg-transparent">
135162
{isEmpty === false && props.htmlPreview && (

packages/plugin-ui/src/codegenPreferenceOptions.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ export const selectPreferenceOptions: SelectPreferenceOptions[] = [
8383
options: [
8484
{ label: "HTML", value: "html" },
8585
{ label: "React (JSX)", value: "jsx" },
86-
{ label: "Twig (Experimental)", value: "twig" },
86+
{ label: "Twig", value: "twig" },
8787
],
8888
includedLanguages: ["Tailwind"],
8989
},
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
import React from "react";
2+
import {
3+
SparklesIcon,
4+
ExternalLinkIcon,
5+
BotIcon,
6+
ArrowRightIcon
7+
} from "lucide-react";
8+
9+
// Correct Figma Icon Path (Monochrome)
10+
const CustomFigmaIcon = ({ className }: { className?: string }) => (
11+
<svg xmlns="http://www.w3.org/2000/svg" className={className} fill="currentColor" viewBox="0 0 256 256"><path d="M192,96a40,40,0,0,0-24-72H96A40,40,0,0,0,72,96a40,40,0,0,0,1.37,65A44,44,0,1,0,144,196V160a40,40,0,1,0,48-64Zm0-32a24,24,0,0,1-24,24H144V40h24A24,24,0,0,1,192,64ZM72,64A24,24,0,0,1,96,40h32V88H96A24,24,0,0,1,72,64Zm24,88a24,24,0,0,1,0-48h32v48H96Zm32,44a28,28,0,1,1-28-28h28Zm40-44a24,24,0,1,1,24-24A24,24,0,0,1,168,152Z"></path></svg>
12+
);
13+
14+
const EmailPanel = () => {
15+
return (
16+
<div className="flex flex-col h-full overflow-y-auto px-5 py-8 bg-gradient-to-b from-white to-gray-50 dark:from-black dark:to-[#0a0a0a]">
17+
{/* Header */}
18+
<div className="text-center mb-10">
19+
<div className="inline-flex items-center justify-center p-3.5 mb-5 rounded-3xl bg-black dark:bg-white shadow-xl shadow-black/5 dark:shadow-white/5 ring-1 ring-black/5 dark:ring-white/10">
20+
<BotIcon className="w-8 h-8 text-white dark:text-black" />
21+
</div>
22+
<h1 className="text-4xl font-bold dark:text-white mb-3 tracking-tighter font-display">
23+
Kopi AI
24+
</h1>
25+
<p className="text-xs text-gray-500 dark:text-gray-400 mt-3 max-w-[260px] mx-auto leading-relaxed">
26+
AI email marketing design agent.
27+
</p>
28+
</div>
29+
30+
{/* Main Cards */}
31+
<div className="grid grid-col-1 gap-3 px-1">
32+
{/* Create with AI Card */}
33+
<div className="group relative overflow-hidden p-4 rounded-2xl bg-white dark:bg-zinc-900 border border-gray-100 dark:border-zinc-800 shadow-sm hover:shadow-md transition-all duration-300">
34+
<div className="absolute top-0 right-0 w-16 h-16 bg-gradient-to-br from-violet-100/50 to-transparent dark:from-violet-900/10 dark:to-transparent rounded-bl-3xl -mr-4 -mt-4 transition-transform group-hover:scale-110" />
35+
36+
<div className="relative flex items-center gap-4">
37+
<div className="w-10 h-10 rounded-xl bg-violet-50 dark:bg-violet-950/30 flex items-center justify-center shrink-0 border border-violet-100 dark:border-violet-900/50">
38+
<SparklesIcon className="w-5 h-5 text-violet-600 dark:text-violet-400" />
39+
</div>
40+
<div>
41+
<h3 className="text-sm font-bold text-gray-900 dark:text-gray-100">Create with AI</h3>
42+
<p className="text-[11px] text-gray-500 dark:text-gray-400 mt-0.5 leading-snug">
43+
Generate emails from scratch tailored to your brand
44+
</p>
45+
</div>
46+
</div>
47+
</div>
48+
49+
{/* Brand Loyal Card */}
50+
<div className="group relative overflow-hidden p-4 rounded-2xl bg-white dark:bg-zinc-900 border border-gray-100 dark:border-zinc-800 shadow-sm hover:shadow-md transition-all duration-300">
51+
<div className="absolute top-0 right-0 w-16 h-16 bg-gradient-to-br from-orange-100/50 to-transparent dark:from-orange-900/10 dark:to-transparent rounded-bl-3xl -mr-4 -mt-4 transition-transform group-hover:scale-110" />
52+
53+
<div className="relative flex items-center gap-4">
54+
<div className="w-10 h-10 rounded-xl bg-orange-50 dark:bg-orange-950/30 flex items-center justify-center shrink-0 border border-orange-100 dark:border-orange-900/50">
55+
<CustomFigmaIcon className="w-6 h-6 text-gray-900 dark:text-gray-100" />
56+
</div>
57+
<div>
58+
<h3 className="text-sm font-bold text-gray-900 dark:text-gray-100">Generate from Figma</h3>
59+
<p className="text-[11px] text-gray-500 dark:text-gray-400 mt-0.5 leading-snug">
60+
Generate emails from Figma designs
61+
</p>
62+
</div>
63+
</div>
64+
</div>
65+
</div>
66+
67+
{/* Subtext */}
68+
<div className="flex justify-center mt-6 mb-4">
69+
<p className="text-[11px] leading-relaxed text-gray-400 dark:text-gray-500 text-center max-w-[280px]">
70+
Clean, responsive, on-brand email HTML
71+
</p>
72+
</div>
73+
74+
{/* CTA */}
75+
<div className="mt-auto pt-4 text-center">
76+
<a
77+
href="https://docs.google.com/forms/d/e/1FAIpQLSe6F4CKOoj3FgEsualL2pUunTki2aMfO2WK0v5ExO7k_8HjmA/viewform?usp=sharing&ouid=115251107698498111547"
78+
target="_blank"
79+
rel="noopener noreferrer"
80+
className="group w-full inline-flex items-center justify-center gap-2 px-6 py-3.5 rounded-xl bg-gray-900 dark:bg-gray-100 text-white dark:text-black text-sm font-bold transition-all shadow-lg hover:shadow-gray-900/20 dark:hover:shadow-white/10 hover:scale-[1.02] active:scale-[0.98]"
81+
>
82+
Get Started
83+
<ArrowRightIcon className="w-4 h-4 opacity-50 group-hover:translate-x-1 transition-transform" />
84+
</a>
85+
</div>
86+
</div>
87+
);
88+
};
89+
90+
export default EmailPanel;

0 commit comments

Comments
 (0)