|
1 | | -"use client"; |
| 1 | +'use client'; |
2 | 2 |
|
3 | | -import React from "react"; |
| 3 | +import { RocketLaunchIcon } from '@phosphor-icons/react'; |
| 4 | +import { cn } from '@/lib/utils'; |
4 | 5 |
|
5 | | -type ExampleType = "saas" | "merch store"; |
| 6 | +const examples = ['saas', 'merch store'] as const; |
| 7 | +const prompts = { |
| 8 | + saas: 'Build me a trip planning tool', |
| 9 | + 'merch store': 'Build me a t-shirt store', |
| 10 | +} as const; |
6 | 11 |
|
7 | | -interface PromptMap { |
8 | | - [key: string]: string; |
9 | | -} |
| 12 | +export const LeapComponent = () => { |
| 13 | + const handleGenerate = () => { |
| 14 | + const input = document.querySelector( |
| 15 | + '.leap-prompt-input' |
| 16 | + ) as HTMLInputElement; |
| 17 | + const prompt = input?.value |
| 18 | + ? `${input.value} use Databuddy for analytics` |
| 19 | + : ''; |
| 20 | + window.location.href = `https://leap.new/?build=${encodeURIComponent(prompt)}`; |
| 21 | + }; |
10 | 22 |
|
11 | | -export const LeapComponent: React.FC = () => { |
12 | | - // Handle button click |
13 | | - const handleGenerateClick = (): void => { |
14 | | - if (typeof document !== "undefined" && typeof window !== "undefined") { |
15 | | - const input = document.querySelector( |
16 | | - ".leap-prompt-input", |
17 | | - ) as HTMLInputElement; |
18 | | - if (input && input.value) { |
19 | | - // Append "use Databuddy for analytics" to the user's prompt |
20 | | - const enhancedPrompt = `${input.value} use Databuddy for analytics`; |
21 | | - window.location.href = `https://leap.new/?build=${encodeURIComponent(enhancedPrompt)}`; |
22 | | - } else { |
23 | | - window.location.href = "https://leap.new/"; |
24 | | - } |
25 | | - } |
26 | | - }; |
| 23 | + const handleExample = (example: (typeof examples)[number]) => { |
| 24 | + const input = document.querySelector( |
| 25 | + '.leap-prompt-input' |
| 26 | + ) as HTMLInputElement; |
| 27 | + if (input) { |
| 28 | + input.value = prompts[example]; |
| 29 | + } |
| 30 | + }; |
27 | 31 |
|
28 | | - // Handle example click |
29 | | - const handleExampleClick = (exampleType: ExampleType): void => { |
30 | | - if (typeof document !== "undefined" && typeof window !== "undefined") { |
31 | | - const input = document.querySelector( |
32 | | - ".leap-prompt-input", |
33 | | - ) as HTMLInputElement; |
34 | | - if (input) { |
35 | | - // Set specific prompts based on the example type |
36 | | - const prompts: PromptMap = { |
37 | | - saas: "Build me a trip planning tool", |
38 | | - "merch store": "Build me a t-shirt store", |
39 | | - }; |
40 | | - input.value = prompts[exampleType] || exampleType; |
41 | | - } |
42 | | - } |
43 | | - }; |
| 32 | + return ( |
| 33 | + <div className="group relative my-2 w-full border border-border bg-card/50 backdrop-blur-sm transition-all duration-300 hover:bg-card/70"> |
| 34 | + <div className="p-3"> |
| 35 | + <div className="flex items-center gap-2"> |
| 36 | + <RocketLaunchIcon |
| 37 | + className="size-4 text-purple-500" |
| 38 | + weight="duotone" |
| 39 | + /> |
| 40 | + <h3 className="font-semibold text-foreground text-sm leading-none"> |
| 41 | + Try Databuddy with Leap |
| 42 | + </h3> |
| 43 | + </div> |
44 | 44 |
|
45 | | - const examples: ExampleType[] = ["saas", "merch store"]; |
| 45 | + <p className="items-center text-muted-foreground text-xs"> |
| 46 | + Let Leap generate a complete application that uses Databuddy for |
| 47 | + analytics. |
| 48 | + </p> |
46 | 49 |
|
47 | | - return ( |
48 | | - <div style={{ position: "relative", width: "100%" }}> |
49 | | - <div |
50 | | - style={{ |
51 | | - border: "1px solid #222", |
52 | | - borderRadius: "0px", |
53 | | - padding: "20px", |
54 | | - margin: "36px 0", |
55 | | - backgroundColor: "#ffffff", |
56 | | - boxShadow: "0 4px 12px rgba(0, 0, 0, 0.2)", |
57 | | - width: "100%", |
58 | | - maxWidth: "680px", |
59 | | - boxSizing: "border-box", |
60 | | - }} |
61 | | - > |
62 | | - <h3 |
63 | | - style={{ |
64 | | - margin: "0 0 12px 0", |
65 | | - color: "#000", |
66 | | - fontSize: "18px", |
67 | | - fontWeight: "600", |
68 | | - }} |
69 | | - > |
70 | | - Try Databuddy with Leap |
71 | | - </h3> |
72 | | - <div> |
73 | | - <p |
74 | | - style={{ |
75 | | - marginBottom: "16px", |
76 | | - color: "#666", |
77 | | - fontSize: "15px", |
78 | | - lineHeight: "1.5", |
79 | | - }} |
80 | | - > |
81 | | - Let Leap generate a complete application that uses Databuddy for |
82 | | - analytics. |
83 | | - </p> |
84 | | - <div |
85 | | - style={{ |
86 | | - display: "flex", |
87 | | - gap: "12px", |
88 | | - flexWrap: "nowrap", |
89 | | - alignItems: "center", |
90 | | - }} |
91 | | - > |
92 | | - <div style={{ flexGrow: 1, minWidth: 0 }}> |
93 | | - <input |
94 | | - type="text" |
95 | | - className="leap-prompt-input" |
96 | | - style={{ |
97 | | - width: "100%", |
98 | | - padding: "12px 16px", |
99 | | - border: "1px solid #333", |
100 | | - borderRadius: "0px", |
101 | | - fontSize: "14px", |
102 | | - backgroundColor: "#fff", |
103 | | - color: "#666", |
104 | | - boxSizing: "border-box", |
105 | | - }} |
106 | | - placeholder="What do you want to build with Databuddy analytics?" |
107 | | - /> |
108 | | - </div> |
109 | | - <div style={{ flexShrink: 0 }}> |
110 | | - <button |
111 | | - type="button" |
112 | | - style={{ |
113 | | - backgroundColor: "#fff", |
114 | | - color: "#000", |
115 | | - border: "1px solid #000", |
116 | | - borderRadius: "0px", |
117 | | - padding: "12px 20px", |
118 | | - cursor: "pointer", |
119 | | - fontWeight: "600", |
120 | | - fontSize: "14px", |
121 | | - transition: "all 0.2s ease", |
122 | | - whiteSpace: "nowrap", |
123 | | - }} |
124 | | - onClick={handleGenerateClick} |
125 | | - > |
126 | | - Generate |
127 | | - </button> |
128 | | - </div> |
129 | | - </div> |
130 | | - <div |
131 | | - style={{ |
132 | | - display: "flex", |
133 | | - gap: "12px", |
134 | | - flexWrap: "wrap", |
135 | | - marginTop: "8px", |
136 | | - fontSize: "12px", |
137 | | - }} |
138 | | - > |
139 | | - <span style={{ color: "#666", marginRight: "4px" }}>Examples:</span> |
140 | | - {examples.map((example: ExampleType, index: number) => ( |
141 | | - <div |
142 | | - key={index} |
143 | | - onClick={() => handleExampleClick(example)} |
144 | | - style={{ |
145 | | - color: "#999", |
146 | | - cursor: "pointer", |
147 | | - borderBottom: "1px dotted #555", |
148 | | - padding: "0 2px", |
149 | | - transition: "color 0.2s ease", |
150 | | - }} |
151 | | - className="hover:text-[#d5db04]" |
152 | | - role="button" |
153 | | - tabIndex={0} |
154 | | - onKeyDown={(e: React.KeyboardEvent) => { |
155 | | - if (e.key === "Enter" || e.key === " ") { |
156 | | - e.preventDefault(); |
157 | | - handleExampleClick(example); |
158 | | - } |
159 | | - }} |
160 | | - > |
161 | | - {example} |
162 | | - </div> |
163 | | - ))} |
164 | | - </div> |
165 | | - </div> |
166 | | - </div> |
167 | | - </div> |
168 | | - ); |
| 50 | + <div className="flex w-full gap-2"> |
| 51 | + <input |
| 52 | + className="leap-prompt-input flex-1 border border-input bg-background px-2 py-1.5 text-foreground text-sm transition-colors placeholder:text-muted-foreground focus:border-ring focus:outline-none focus:ring-1 focus:ring-ring" |
| 53 | + placeholder="What do you want to build with Databuddy analytics?" |
| 54 | + type="text" |
| 55 | + /> |
| 56 | + <button |
| 57 | + className={cn( |
| 58 | + 'inline-flex items-center justify-center whitespace-nowrap px-3 py-1.5 font-medium text-sm transition-all duration-200', |
| 59 | + 'bg-foreground/5 text-foreground backdrop-blur-[50px]', |
| 60 | + 'border border-border hover:animate-[borderGlitch_0.6s_ease-in-out]', |
| 61 | + 'focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring active:scale-[0.98]' |
| 62 | + )} |
| 63 | + onClick={handleGenerate} |
| 64 | + type="button" |
| 65 | + > |
| 66 | + Generate |
| 67 | + </button> |
| 68 | + </div> |
| 69 | + |
| 70 | + <div className="mt-2 flex flex-wrap items-center gap-1.5 text-xs"> |
| 71 | + <span className="text-muted-foreground">Examples:</span> |
| 72 | + {examples.map((example) => ( |
| 73 | + <button |
| 74 | + className="border-muted-foreground/50 border-b border-dotted px-1 text-muted-foreground transition-colors hover:border-purple-400 hover:text-purple-400 focus:border-purple-400 focus:text-purple-400 focus:outline-none" |
| 75 | + key={example} |
| 76 | + onClick={() => handleExample(example)} |
| 77 | + type="button" |
| 78 | + > |
| 79 | + {example} |
| 80 | + </button> |
| 81 | + ))} |
| 82 | + </div> |
| 83 | + </div> |
| 84 | + |
| 85 | + {/* Sci-fi corners */} |
| 86 | + <div className="pointer-events-none absolute inset-0"> |
| 87 | + {[ |
| 88 | + 'top-0 left-0', |
| 89 | + 'top-0 right-0 -scale-x-[1]', |
| 90 | + 'bottom-0 left-0 -scale-y-[1]', |
| 91 | + 'bottom-0 right-0 -scale-[1]', |
| 92 | + ].map((position) => ( |
| 93 | + <div |
| 94 | + className={`absolute h-2 w-2 group-hover:animate-[cornerGlitch_0.6s_ease-in-out] ${position}`} |
| 95 | + key={position} |
| 96 | + > |
| 97 | + <div className="absolute top-0 left-0.5 h-0.5 w-1.5 origin-left bg-foreground/20" /> |
| 98 | + <div className="absolute top-0 left-0 h-2 w-0.5 origin-top bg-foreground/20" /> |
| 99 | + </div> |
| 100 | + ))} |
| 101 | + </div> |
| 102 | + </div> |
| 103 | + ); |
169 | 104 | }; |
170 | 105 |
|
171 | 106 | export default LeapComponent; |
0 commit comments