161 lines
6.3 KiB
TypeScript
161 lines
6.3 KiB
TypeScript
"use client";
|
|
|
|
import { useState } from "react";
|
|
import Globe from "@/components/app/(home)/sections/hero-input/_svg/Globe";
|
|
import HeroInputSubmitButton from "@/components/app/(home)/sections/hero-input/Button/Button";
|
|
|
|
interface SidebarInputProps {
|
|
onSubmit: (url: string, style: string, model: string, instructions?: string) => void;
|
|
disabled?: boolean;
|
|
}
|
|
|
|
export default function SidebarInput({ onSubmit, disabled = false }: SidebarInputProps) {
|
|
const [url, setUrl] = useState<string>("");
|
|
const [selectedStyle, setSelectedStyle] = useState<string>("1");
|
|
const [selectedModel, setSelectedModel] = useState<string>("moonshotai/kimi-k2-instruct-0905");
|
|
const [additionalInstructions, setAdditionalInstructions] = useState<string>("");
|
|
const [isValidUrl, setIsValidUrl] = useState<boolean>(false);
|
|
|
|
// Simple URL validation
|
|
const validateUrl = (urlString: string) => {
|
|
if (!urlString) return false;
|
|
const urlPattern = /^(https?:\/\/)?([\da-z\.-]+)\.([a-z\.]{2,6})([\/\w \.-]*)*\/?$/;
|
|
return urlPattern.test(urlString.toLowerCase());
|
|
};
|
|
|
|
const styles = [
|
|
{ id: "1", name: "Glassmorphism", description: "Frosted glass effect" },
|
|
{ id: "2", name: "Neumorphism", description: "Soft 3D shadows" },
|
|
{ id: "3", name: "Brutalism", description: "Bold and raw" },
|
|
{ id: "4", name: "Minimalist", description: "Clean and simple" },
|
|
{ id: "5", name: "Dark Mode", description: "Dark theme design" },
|
|
{ id: "6", name: "Gradient Rich", description: "Vibrant gradients" },
|
|
{ id: "7", name: "3D Depth", description: "Dimensional layers" },
|
|
{ id: "8", name: "Retro Wave", description: "80s inspired" },
|
|
];
|
|
|
|
const models = [
|
|
{ id: "moonshotai/kimi-k2-instruct-0905", name: "Kimi K2 0905 on Groq" },
|
|
{ id: "openai/gpt-5", name: "GPT-5" },
|
|
{ id: "anthropic/claude-sonnet-4-20250514", name: "Sonnet 4" },
|
|
{ id: "google/gemini-2.0-flash-exp", name: "Gemini 2.0" },
|
|
];
|
|
|
|
const handleSubmit = (e?: React.FormEvent) => {
|
|
if (e) e.preventDefault();
|
|
if (!url.trim() || disabled) return;
|
|
|
|
onSubmit(url.trim(), selectedStyle, selectedModel, additionalInstructions || undefined);
|
|
|
|
// Reset form
|
|
setUrl("");
|
|
setAdditionalInstructions("");
|
|
setIsValidUrl(false);
|
|
};
|
|
|
|
return (
|
|
<div className="w-full">
|
|
<div >
|
|
<div className="p-4 border-b border-gray-100">
|
|
{/* URL Input */}
|
|
<div className="flex gap-3 items-center">
|
|
<Globe />
|
|
<input
|
|
className="flex-1 bg-transparent text-sm text-gray-900 placeholder:text-gray-400 focus:outline-none"
|
|
placeholder="example.com"
|
|
type="text"
|
|
value={url}
|
|
disabled={disabled}
|
|
onChange={(e) => {
|
|
setUrl(e.target.value);
|
|
setIsValidUrl(validateUrl(e.target.value));
|
|
}}
|
|
onKeyDown={(e) => {
|
|
if (e.key === "Enter") {
|
|
e.preventDefault();
|
|
handleSubmit();
|
|
}
|
|
}}
|
|
/>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Options Section - Show when valid URL */}
|
|
{isValidUrl && (
|
|
<div className="p-4 space-y-4">
|
|
{/* Style Selector */}
|
|
<div>
|
|
<label className="block text-xs font-medium text-gray-700 mb-2">Style</label>
|
|
<div className="grid grid-cols-2 gap-1.5">
|
|
{styles.map((style) => (
|
|
<button
|
|
key={style.id}
|
|
onClick={() => setSelectedStyle(style.id)}
|
|
disabled={disabled}
|
|
className={`
|
|
py-2 px-2 rounded text-xs font-medium border transition-all text-center
|
|
${selectedStyle === style.id
|
|
? 'border-orange-500 bg-orange-50 text-orange-900'
|
|
: 'border-gray-200 hover:border-gray-300 bg-white text-gray-700'
|
|
}
|
|
${disabled ? 'opacity-50 cursor-not-allowed' : ''}
|
|
`}
|
|
>
|
|
{style.name}
|
|
</button>
|
|
))}
|
|
</div>
|
|
</div>
|
|
|
|
{/* Model Selector */}
|
|
<div>
|
|
<label className="block text-xs font-medium text-gray-700 mb-2">AI Model</label>
|
|
<select
|
|
value={selectedModel}
|
|
onChange={(e) => setSelectedModel(e.target.value)}
|
|
disabled={disabled}
|
|
className="w-full px-3 py-2 text-xs font-medium text-gray-700 bg-white rounded border border-gray-200 focus:border-orange-500 focus:outline-none focus:ring-1 focus:ring-orange-500"
|
|
>
|
|
{models.map((model) => (
|
|
<option key={model.id} value={model.id}>
|
|
{model.name}
|
|
</option>
|
|
))}
|
|
</select>
|
|
</div>
|
|
|
|
{/* Additional Instructions */}
|
|
<div>
|
|
<label className="block text-xs font-medium text-gray-700 mb-2">Additional Instructions (optional)</label>
|
|
<input
|
|
type="text"
|
|
value={additionalInstructions}
|
|
onChange={(e) => setAdditionalInstructions(e.target.value)}
|
|
disabled={disabled}
|
|
className="w-full px-3 py-2 text-xs text-gray-700 bg-gray-50 rounded border border-gray-200 focus:border-orange-500 focus:outline-none focus:ring-1 focus:ring-orange-500 placeholder:text-gray-400"
|
|
placeholder="e.g., make it more colorful, add animations..."
|
|
/>
|
|
</div>
|
|
|
|
{/* Submit Button */}
|
|
<div className="pt-2">
|
|
<button
|
|
onClick={handleSubmit}
|
|
disabled={!isValidUrl || disabled}
|
|
className={`
|
|
w-full py-2.5 px-4 rounded-lg text-sm font-medium transition-all
|
|
${isValidUrl && !disabled
|
|
? 'bg-orange-500 hover:bg-orange-600 text-white'
|
|
: 'bg-gray-200 text-gray-400 cursor-not-allowed'
|
|
}
|
|
`}
|
|
>
|
|
{disabled ? 'Generating...' : 'Generate Website'}
|
|
</button>
|
|
</div>
|
|
</div>
|
|
)}
|
|
</div>
|
|
</div>
|
|
);
|
|
} |