viktor-hu commited on
Commit
11ef531
·
verified ·
1 Parent(s): 25c879d

update ui (#9)

Browse files

- feat. update ui (981c920d03c0f4a2eb177778206aa39c0964b09f)
- feat. update default template (a25d574e5d9688831346c10ef1d2fabbdd7ab891)

src/app/globals.css CHANGED
@@ -66,3 +66,42 @@
66
  .code-area pre {
67
  font-family: "Menlo", "Monaco", "Courier New", monospace;
68
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
66
  .code-area pre {
67
  font-family: "Menlo", "Monaco", "Courier New", monospace;
68
  }
69
+
70
+ /* Custom rainbow border animation */
71
+ @keyframes rainbow-border-glow {
72
+ 0% {
73
+ border-color: #8b5cf6;
74
+ box-shadow: 0 0 30px rgba(139, 92, 246, 0.5), 0 0 20px rgba(139, 92, 246, 0.3);
75
+ }
76
+ 16.66% {
77
+ border-color: #ec4899;
78
+ box-shadow: 0 0 30px rgba(236, 72, 153, 0.5), 0 0 20px rgba(236, 72, 153, 0.3);
79
+ }
80
+ 33.33% {
81
+ border-color: #f87171;
82
+ box-shadow: 0 0 30px rgba(248, 113, 113, 0.5), 0 0 20px rgba(248, 113, 113, 0.3);
83
+ }
84
+ 50% {
85
+ border-color: #fb923c;
86
+ box-shadow: 0 0 30px rgba(251, 146, 60, 0.5), 0 0 20px rgba(251, 146, 60, 0.3);
87
+ }
88
+ 66.66% {
89
+ border-color: #fbbf24;
90
+ box-shadow: 0 0 30px rgba(251, 191, 36, 0.5), 0 0 20px rgba(251, 191, 36, 0.3);
91
+ }
92
+ 83.33% {
93
+ border-color: #4ade80;
94
+ box-shadow: 0 0 30px rgba(74, 222, 128, 0.5), 0 0 20px rgba(74, 222, 128, 0.3);
95
+ }
96
+ 100% {
97
+ border-color: #8b5cf6;
98
+ box-shadow: 0 0 30px rgba(139, 92, 246, 0.5), 0 0 20px rgba(139, 92, 246, 0.3);
99
+ }
100
+ }
101
+
102
+ .rainbow-border-animate {
103
+ animation: rainbow-border-glow 4s ease-in-out infinite;
104
+ /* Ensure smooth transition when animation stops */
105
+ border-color: #8b5cf6;
106
+ box-shadow: 0 0 10px rgba(139, 92, 246, 0.5), 0 0 20px rgba(139, 92, 246, 0.3);
107
+ }
src/components/prompt-input.tsx CHANGED
@@ -37,6 +37,7 @@ export function PromptInput({
37
  const [selectedColors, setSelectedColors] = useState<string[]>([]);
38
  const [improveError, setImproveError] = useState<string | null>(null);
39
  const [showAuthError, setShowAuthError] = useState(false);
 
40
 
41
  // Update prompt when initialPrompt changes
42
  useEffect(() => {
@@ -188,21 +189,33 @@ export function PromptInput({
188
  onClick={toggleFullScreen}
189
  />
190
  </div>
191
- <form onSubmit={handleSubmit} className="flex flex-col gap-4 h-full">
192
  <div className={`relative ${isFullScreen ? "h-full" : ""}`}>
193
  <ColorPanel onColorsChange={handleColorsChange} />
194
- <Textarea
195
- value={prompt}
196
- onChange={(e) => {
197
- setPrompt(e.target.value);
198
- // Clear error when user types
199
- if (improveError) setImproveError(null);
200
- }}
201
- placeholder="Describe what site you want to build. E.g., Build a snake game"
202
- className={`min-h-24 pr-20 pt-12 bg-novita-gray/20 border-novita-gray/30 text-white placeholder:text-novita-gray/70 resize-none ${isFullScreen ? "h-full" : ""}`}
203
- disabled={isLoading || isImprovingPrompt}
204
- />
205
- <div className="absolute bottom-3 right-3 flex gap-2">
 
 
 
 
 
 
 
 
 
 
 
 
206
  <TooltipProvider>
207
  <Tooltip>
208
  <TooltipTrigger asChild>
 
37
  const [selectedColors, setSelectedColors] = useState<string[]>([]);
38
  const [improveError, setImproveError] = useState<string | null>(null);
39
  const [showAuthError, setShowAuthError] = useState(false);
40
+ const [isAnimationActive, setIsAnimationActive] = useState(true);
41
 
42
  // Update prompt when initialPrompt changes
43
  useEffect(() => {
 
189
  onClick={toggleFullScreen}
190
  />
191
  </div>
192
+ <form onSubmit={handleSubmit} className="flex flex-col gap-4 h-full relative z-[1]">
193
  <div className={`relative ${isFullScreen ? "h-full" : ""}`}>
194
  <ColorPanel onColorsChange={handleColorsChange} />
195
+
196
+ {/* Textarea with animated glowing border */}
197
+ <div className={`relative ${isFullScreen ? "h-full" : ""}`}>
198
+ <Textarea
199
+ value={prompt}
200
+ onChange={(e) => {
201
+ setPrompt(e.target.value);
202
+ // Clear error when user types
203
+ if (improveError) setImproveError(null);
204
+ }}
205
+ onBlur={() => setIsAnimationActive(true)}
206
+ onFocus={() => setIsAnimationActive(false)}
207
+ placeholder="Describe what site you want to build. E.g., Build a snake game"
208
+ className={`min-h-24 pr-20 pt-12 bg-novita-gray/20 text-white placeholder:text-white/40 resize-none relative z-[1] rounded-lg transition-colors duration-300 focus:outline-none focus:ring-0 focus:ring-offset-0 focus-visible:outline-none focus-visible:ring-0 focus-visible:ring-offset-0 focus:border-novita-green ${
209
+ isFullScreen ? "h-full" : ""
210
+ } ${
211
+ isAnimationActive
212
+ ? "border-2 rainbow-border-animate"
213
+ : "border-2 border-novita-gray/30"
214
+ }`}
215
+ disabled={isLoading || isImprovingPrompt}
216
+ />
217
+ </div>
218
+ <div className="absolute bottom-3 right-3 flex gap-2 z-10">
219
  <TooltipProvider>
220
  <Tooltip>
221
  <TooltipTrigger asChild>
src/lib/constants.dev.ts CHANGED
@@ -104,6 +104,57 @@ export const DEFAULT_HTML = `<!DOCTYPE html>
104
  .text-huge {
105
  font-size: clamp(6rem, 20vw, 15rem);
106
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
107
  </style>
108
  </head>
109
  <body class="pixel-grid scanlines">
@@ -144,6 +195,11 @@ export const DEFAULT_HTML = `<!DOCTYPE html>
144
  </div>
145
  </div>
146
 
 
 
 
 
 
147
  <script>
148
  document.addEventListener('DOMContentLoaded', function() {
149
  // Brutalist press-down interactivity
 
104
  .text-huge {
105
  font-size: clamp(6rem, 20vw, 15rem);
106
  }
107
+
108
+ /* Arrow animation styles */
109
+ .arrow-container {
110
+ position: fixed;
111
+ bottom: 0px;
112
+ left: 0px;
113
+ z-index: 50;
114
+ pointer-events: none;
115
+ }
116
+
117
+ .arrow {
118
+ font-size: 6rem;
119
+ color: #fff;
120
+ animation: moveLeftRight 3s ease-in-out infinite;
121
+ text-shadow:
122
+ 0 0 20px rgba(255, 255, 255, 0.8),
123
+ 0 0 40px rgba(255, 255, 255, 0.6),
124
+ 0 0 60px rgba(255, 255, 255, 0.4),
125
+ 4px 4px 8px rgba(0, 0, 0, 0.5);
126
+ filter: drop-shadow(0 0 15px rgba(255, 255, 255, 0.7));
127
+ opacity: 0.9;
128
+ font-weight: bold;
129
+ transition: all 0.3s ease;
130
+ }
131
+
132
+ .arrow:hover {
133
+ opacity: 1;
134
+ transform: scale(1.1);
135
+ text-shadow:
136
+ 0 0 30px rgba(255, 255, 255, 1),
137
+ 0 0 50px rgba(255, 255, 255, 0.8),
138
+ 0 0 80px rgba(255, 255, 255, 0.6),
139
+ 4px 4px 12px rgba(0, 0, 0, 0.7);
140
+ }
141
+
142
+ @keyframes moveLeftRight {
143
+ 0%, 100% {
144
+ transform: translateX(0);
145
+ opacity: 0.9;
146
+ }
147
+ 25% {
148
+ opacity: 1;
149
+ }
150
+ 50% {
151
+ transform: translateX(60px);
152
+ opacity: 0.95;
153
+ }
154
+ 75% {
155
+ opacity: 1;
156
+ }
157
+ }
158
  </style>
159
  </head>
160
  <body class="pixel-grid scanlines">
 
195
  </div>
196
  </div>
197
 
198
+ <!-- Animated arrow in bottom left corner -->
199
+ <div class="arrow-container">
200
+ <div class="arrow">←</div>
201
+ </div>
202
+
203
  <script>
204
  document.addEventListener('DOMContentLoaded', function() {
205
  // Brutalist press-down interactivity
src/lib/constants.prod.ts CHANGED
@@ -104,6 +104,57 @@ export const DEFAULT_HTML = `<!DOCTYPE html>
104
  .text-huge {
105
  font-size: clamp(6rem, 20vw, 15rem);
106
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
107
  </style>
108
  </head>
109
  <body class="pixel-grid scanlines">
@@ -144,6 +195,11 @@ export const DEFAULT_HTML = `<!DOCTYPE html>
144
  </div>
145
  </div>
146
 
 
 
 
 
 
147
  <script>
148
  document.addEventListener('DOMContentLoaded', function() {
149
  // Brutalist press-down interactivity
 
104
  .text-huge {
105
  font-size: clamp(6rem, 20vw, 15rem);
106
  }
107
+
108
+ /* Arrow animation styles */
109
+ .arrow-container {
110
+ position: fixed;
111
+ bottom: 0px;
112
+ left: 0px;
113
+ z-index: 50;
114
+ pointer-events: none;
115
+ }
116
+
117
+ .arrow {
118
+ font-size: 6rem;
119
+ color: #fff;
120
+ animation: moveLeftRight 3s ease-in-out infinite;
121
+ text-shadow:
122
+ 0 0 20px rgba(255, 255, 255, 0.8),
123
+ 0 0 40px rgba(255, 255, 255, 0.6),
124
+ 0 0 60px rgba(255, 255, 255, 0.4),
125
+ 4px 4px 8px rgba(0, 0, 0, 0.5);
126
+ filter: drop-shadow(0 0 15px rgba(255, 255, 255, 0.7));
127
+ opacity: 0.9;
128
+ font-weight: bold;
129
+ transition: all 0.3s ease;
130
+ }
131
+
132
+ .arrow:hover {
133
+ opacity: 1;
134
+ transform: scale(1.1);
135
+ text-shadow:
136
+ 0 0 30px rgba(255, 255, 255, 1),
137
+ 0 0 50px rgba(255, 255, 255, 0.8),
138
+ 0 0 80px rgba(255, 255, 255, 0.6),
139
+ 4px 4px 12px rgba(0, 0, 0, 0.7);
140
+ }
141
+
142
+ @keyframes moveLeftRight {
143
+ 0%, 100% {
144
+ transform: translateX(0);
145
+ opacity: 0.9;
146
+ }
147
+ 25% {
148
+ opacity: 1;
149
+ }
150
+ 50% {
151
+ transform: translateX(60px);
152
+ opacity: 0.95;
153
+ }
154
+ 75% {
155
+ opacity: 1;
156
+ }
157
+ }
158
  </style>
159
  </head>
160
  <body class="pixel-grid scanlines">
 
195
  </div>
196
  </div>
197
 
198
+ <!-- Animated arrow in bottom left corner -->
199
+ <div class="arrow-container">
200
+ <div class="arrow">←</div>
201
+ </div>
202
+
203
  <script>
204
  document.addEventListener('DOMContentLoaded', function() {
205
  // Brutalist press-down interactivity
tailwind.config.ts CHANGED
@@ -74,10 +74,68 @@ const config = {
74
  from: { height: "var(--radix-accordion-content-height)" },
75
  to: { height: "0" },
76
  },
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
77
  },
78
  animation: {
79
  "accordion-down": "accordion-down 0.2s ease-out",
80
  "accordion-up": "accordion-up 0.2s ease-out",
 
 
 
 
 
 
81
  },
82
  },
83
  },
 
74
  from: { height: "var(--radix-accordion-content-height)" },
75
  to: { height: "0" },
76
  },
77
+ "rainbow-border": {
78
+ "0%": {
79
+ borderColor: "#8b5cf6", // purple-400
80
+ boxShadow: "0 0 20px rgba(139, 92, 246, 0.5), 0 0 40px rgba(139, 92, 246, 0.3)",
81
+ },
82
+ "16.66%": {
83
+ borderColor: "#ec4899", // pink-400
84
+ boxShadow: "0 0 20px rgba(236, 72, 153, 0.5), 0 0 40px rgba(236, 72, 153, 0.3)",
85
+ },
86
+ "33.33%": {
87
+ borderColor: "#f87171", // red-400
88
+ boxShadow: "0 0 20px rgba(248, 113, 113, 0.5), 0 0 40px rgba(248, 113, 113, 0.3)",
89
+ },
90
+ "50%": {
91
+ borderColor: "#fb923c", // orange-400
92
+ boxShadow: "0 0 20px rgba(251, 146, 60, 0.5), 0 0 40px rgba(251, 146, 60, 0.3)",
93
+ },
94
+ "66.66%": {
95
+ borderColor: "#fbbf24", // yellow-400
96
+ boxShadow: "0 0 20px rgba(251, 191, 36, 0.5), 0 0 40px rgba(251, 191, 36, 0.3)",
97
+ },
98
+ "83.33%": {
99
+ borderColor: "#4ade80", // green-400
100
+ boxShadow: "0 0 20px rgba(74, 222, 128, 0.5), 0 0 40px rgba(74, 222, 128, 0.3)",
101
+ },
102
+ "100%": {
103
+ borderColor: "#8b5cf6", // purple-400
104
+ boxShadow: "0 0 20px rgba(139, 92, 246, 0.5), 0 0 40px rgba(139, 92, 246, 0.3)",
105
+ },
106
+ },
107
+ "color-shift": {
108
+ "0%, 100%": {
109
+ "background-position": "0% 50%",
110
+ },
111
+ "50%": {
112
+ "background-position": "100% 50%",
113
+ },
114
+ },
115
+ "border-glow": {
116
+ "0%": {
117
+ opacity: "0.1",
118
+ transform: "scale(1)",
119
+ },
120
+ "50%": {
121
+ opacity: "0.3",
122
+ transform: "scale(1.02)",
123
+ },
124
+ "100%": {
125
+ opacity: "0.1",
126
+ transform: "scale(1)",
127
+ },
128
+ },
129
  },
130
  animation: {
131
  "accordion-down": "accordion-down 0.2s ease-out",
132
  "accordion-up": "accordion-up 0.2s ease-out",
133
+ "rainbow-border": "rainbow-border 4s ease-in-out infinite",
134
+ "color-shift": "color-shift 3s ease-in-out infinite",
135
+ "border-glow": "border-glow 4s ease-in-out infinite",
136
+ },
137
+ boxShadow: {
138
+ "rainbow-glow": "0 0 20px rgba(139, 92, 246, 0.5), 0 0 40px rgba(139, 92, 246, 0.3), 0 0 60px rgba(139, 92, 246, 0.1)",
139
  },
140
  },
141
  },