[dyad] Improved form UX - wrote 1 file(s)

This commit is contained in:
[dyad]
2026-01-20 13:22:27 +01:00
parent d70dd611e0
commit 6c738cd9d1

View File

@@ -5,7 +5,7 @@ import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input"; import { Input } from "@/components/ui/input";
import { Textarea } from "@/components/ui/textarea"; import { Textarea } from "@/components/ui/textarea";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import { Globe, Edit, Check } from "lucide-react"; import { Globe, Edit, Check, Loader2, X, ImageOff } from "lucide-react";
import { extractMetaData } from "@/app/actions"; import { extractMetaData } from "@/app/actions";
import { LengthIndicator } from "./length-indicator"; import { LengthIndicator } from "./length-indicator";
import { CopyButton } from "./copy-button"; import { CopyButton } from "./copy-button";
@@ -17,6 +17,7 @@ interface MetaData {
} }
export function MetaForm() { export function MetaForm() {
const [url, setUrl] = useState("");
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false);
const [error, setError] = useState<string | null>(null); const [error, setError] = useState<string | null>(null);
const [metaData, setMetaData] = useState<MetaData | null>(null); const [metaData, setMetaData] = useState<MetaData | null>(null);
@@ -26,11 +27,13 @@ export function MetaForm() {
const [editableTitle, setEditableTitle] = useState(""); const [editableTitle, setEditableTitle] = useState("");
const [editableDescription, setEditableDescription] = useState(""); const [editableDescription, setEditableDescription] = useState("");
const [imageError, setImageError] = useState(false);
useEffect(() => { useEffect(() => {
if (metaData) { if (metaData) {
setEditableTitle(metaData.title); setEditableTitle(metaData.title);
setEditableDescription(metaData.description); setEditableDescription(metaData.description);
setImageError(false);
} }
}, [metaData]); }, [metaData]);
@@ -41,9 +44,7 @@ export function MetaForm() {
setMetaData(null); setMetaData(null);
setIsEditingTitle(false); setIsEditingTitle(false);
setIsEditingDescription(false); setIsEditingDescription(false);
setImageError(false);
const formData = new FormData(event.currentTarget);
const url = formData.get("url") as string;
const result = await extractMetaData(url); const result = await extractMetaData(url);
@@ -56,6 +57,13 @@ export function MetaForm() {
setLoading(false); setLoading(false);
}; };
const handleClear = () => {
setUrl("");
setLoading(false);
setError(null);
setMetaData(null);
};
return ( return (
<div className="w-full space-y-6"> <div className="w-full space-y-6">
<form <form
@@ -70,15 +78,30 @@ export function MetaForm() {
placeholder="https://example.com" placeholder="https://example.com"
required required
className="pl-10 h-12 text-base rounded-lg shadow-sm" className="pl-10 h-12 text-base rounded-lg shadow-sm"
value={url}
onChange={(e) => setUrl(e.target.value)}
/> />
</div> </div>
<Button <Button
type="submit" type="submit"
disabled={loading} disabled={loading}
className="w-full sm:w-auto h-12 px-8 rounded-lg font-semibold transition-all" className="w-full sm:w-auto h-12 px-8 rounded-lg font-semibold transition-all flex items-center gap-2"
> >
{loading && <Loader2 className="h-5 w-5 animate-spin" />}
{loading ? "Extracting..." : "Extract"} {loading ? "Extracting..." : "Extract"}
</Button> </Button>
{(url || metaData || error) && (
<Button
type="button"
variant="ghost"
size="icon"
onClick={handleClear}
className="h-12 w-12"
>
<X className="h-5 w-5" />
<span className="sr-only">Clear</span>
</Button>
)}
</form> </form>
{error && ( {error && (
@@ -102,12 +125,20 @@ export function MetaForm() {
<h3 className="font-semibold text-card-foreground mb-2"> <h3 className="font-semibold text-card-foreground mb-2">
Preview Image Preview Image
</h3> </h3>
<div className="aspect-video bg-muted rounded-md overflow-hidden relative"> <div className="aspect-video bg-muted rounded-md overflow-hidden relative flex items-center justify-center">
<img {!imageError ? (
src={metaData.image} <img
alt="Meta preview image" src={metaData.image}
className="w-full h-full object-cover" alt="Meta preview image"
/> className="w-full h-full object-cover"
onError={() => setImageError(true)}
/>
) : (
<div className="flex flex-col items-center gap-2 text-muted-foreground">
<ImageOff className="h-8 w-8" />
<span>Image not available</span>
</div>
)}
</div> </div>
</div> </div>
)} )}