Spaces:
Running
Running
File size: 5,475 Bytes
1a9c884 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 |
import { useState, useRef, useEffect } from "react";
import { PROMPTS } from "../constants";
import GlassContainer from "./GlassContainer";
interface PromptInputProps {
onPromptChange: (prompt: string) => void;
defaultPrompt?: string;
}
export default function PromptInput({ onPromptChange, defaultPrompt = PROMPTS.default }: PromptInputProps) {
const [prompt, setPrompt] = useState(defaultPrompt);
const [showSuggestions, setShowSuggestions] = useState(false);
const inputRef = useRef<HTMLTextAreaElement>(null);
const containerRef = useRef<HTMLDivElement>(null);
const resizeTextarea = () => {
if (inputRef.current) {
inputRef.current.style.height = "auto";
const newHeight = Math.min(inputRef.current.scrollHeight, 200);
inputRef.current.style.height = `${newHeight}px`;
}
};
useEffect(() => {
onPromptChange(prompt);
resizeTextarea();
}, [prompt, onPromptChange]);
const handleInputFocus = () => {
setShowSuggestions(true);
};
const handleInputClick = () => {
setShowSuggestions(true);
};
const handleInputBlur = (e: React.FocusEvent) => {
if (!e.relatedTarget || !containerRef.current?.contains(e.relatedTarget as Node)) {
setShowSuggestions(false);
}
};
const handleSuggestionClick = (suggestion: string) => {
setPrompt(suggestion);
setShowSuggestions(false);
inputRef.current?.focus();
};
const clearInput = () => {
setPrompt("");
inputRef.current?.focus();
};
const handleInputChange = (e: React.ChangeEvent<HTMLTextAreaElement>) => {
setPrompt(e.target.value);
};
return (
<div
ref={containerRef}
className="w-[420px] relative"
style={
{
"--input-bg": "rgba(0, 0, 0, 0.2)",
"--input-border": "rgba(255, 255, 255, 0.1)",
} as React.CSSProperties
}
>
{/* Suggestions Panel */}
<div
className={`absolute bottom-full left-0 right-0 mb-2 ${
showSuggestions ? "opacity-100 pointer-events-auto" : "opacity-0 pointer-events-none"
}`}
>
<GlassContainer className="rounded-2xl shadow-2xl">
<div
className={`p-5 text-white transition-opacity duration-100 ${
showSuggestions ? "opacity-100" : "opacity-0"
}`}
>
<div className="suggestion-group">
<h4 className="text-sm mb-3 opacity-70 font-medium">Suggested Prompts</h4>
<ul className="space-y-1">
{PROMPTS.suggestions.map((suggestion, index) => (
<li
key={index}
tabIndex={0}
onMouseDown={(e) => {
e.preventDefault();
}}
onClick={() => handleSuggestionClick(suggestion)}
onKeyDown={(e) => {
if (e.key === "Enter" || e.key === " ") {
e.preventDefault();
handleSuggestionClick(suggestion);
}
}}
className="py-2 px-3 rounded-lg cursor-pointer flex items-center gap-3 transition-all duration-200 hover:bg-white/20 hover:translate-x-1 hover:shadow-sm focus:bg-white/20 focus:translate-x-1 focus:outline-none"
>
<span className="opacity-70 text-sm transition-all duration-200 hover:opacity-100">→</span>
<span className="text-sm transition-all duration-200 hover:text-white/90">{suggestion}</span>
</li>
))}
</ul>
</div>
</div>
</GlassContainer>
</div>
{/* Input Container */}
<GlassContainer className="rounded-2xl shadow-2xl">
<div className="text-white">
<div className="search-container relative p-5 flex items-center transition-all duration-400">
<div className="relative w-full">
<textarea
ref={inputRef}
value={prompt}
onChange={handleInputChange}
onFocus={handleInputFocus}
onBlur={handleInputBlur}
onClick={handleInputClick}
className="search-input w-full py-3 pl-4 pr-8 rounded-xl text-white text-base transition-all duration-400 border resize-none focus:outline-none focus:-translate-y-0.5 focus:shadow-lg"
style={{
background: "var(--input-bg)",
borderColor: "var(--input-border)",
color: "#ffffff",
minHeight: "48px",
maxHeight: "200px",
height: "auto",
overflowY: "hidden",
}}
placeholder={PROMPTS.placeholder}
rows={1}
/>
{prompt && (
<button
type="button"
onClick={clearInput}
className="search-clear absolute right-3 top-2 text-white opacity-70 hover:opacity-100 hover:bg-white/10 rounded-full p-1 transition-all duration-300"
>
×
</button>
)}
</div>
</div>
</div>
</GlassContainer>
</div>
);
}
|