| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141 |
- import React, { useState } from "react";
- import { generateImage } from "../services/gemini";
- import { GeneratedImage } from "../services/types";
- const ImageView: React.FC = () => {
- const [prompt, setPrompt] = useState("");
- const [loading, setLoading] = useState(false);
- const [history, setHistory] = useState<GeneratedImage[]>([]);
- const [aspectRatio, setAspectRatio] = useState<"1:1" | "16:9" | "9:16">(
- "1:1"
- );
- const handleGenerate = async () => {
- if (!prompt.trim() || loading) return;
- setLoading(true);
- try {
- const url = await generateImage(prompt, aspectRatio);
- setHistory((prev) => [{ url, prompt, timestamp: new Date() }, ...prev]);
- } catch (error) {
- console.error(error);
- alert("Asset generation failed. Please refine your parameters.");
- } finally {
- setLoading(false);
- }
- };
- return (
- <div className="flex flex-col h-full bg-slate-50">
- <div className="p-10 bg-white border-b border-slate-200 shadow-sm z-10">
- <div className="max-w-7xl mx-auto flex flex-col space-y-6">
- <div>
- <h2 className="text-3xl font-black text-slate-900 tracking-tight">
- Image Forge
- </h2>
- <p className="text-slate-500 font-medium">
- Generate high-fidelity visual assets for your brand and projects.
- </p>
- </div>
- <div className="flex flex-col lg:flex-row gap-4">
- <div className="flex-1 relative group">
- <input
- type="text"
- value={prompt}
- onChange={(e) => setPrompt(e.target.value)}
- placeholder="High-resolution architectural render of a modern workspace..."
- className="w-full bg-slate-50 text-slate-800 rounded-2xl px-6 py-4 focus:outline-none focus:ring-4 focus:ring-blue-500/10 border border-slate-200 text-lg transition-all"
- />
- </div>
- <div className="flex gap-4">
- <select
- value={aspectRatio}
- onChange={(e: any) => setAspectRatio(e.target.value)}
- className="bg-white text-slate-700 border border-slate-200 rounded-2xl px-6 py-4 outline-none focus:ring-2 focus:ring-[#004ea8] font-semibold text-sm shadow-sm cursor-pointer hover:bg-slate-50 transition-colors"
- >
- <option value="1:1">Standard (1:1)</option>
- <option value="16:9">Widescreen (16:9)</option>
- <option value="9:16">Mobile (9:16)</option>
- </select>
- <button
- onClick={handleGenerate}
- disabled={loading}
- className="bg-[#004ea8] hover:bg-[#003d82] disabled:opacity-50 text-white rounded-2xl px-10 py-4 font-bold transition-all shadow-xl active:scale-95 whitespace-nowrap"
- >
- {loading ? "Synthesizing..." : "Generate Assets"}
- </button>
- </div>
- </div>
- </div>
- </div>
- <div className="flex-1 overflow-y-auto p-10">
- <div className="max-w-7xl mx-auto">
- {history.length === 0 && !loading && (
- <div className="h-[50vh] flex flex-col items-center justify-center opacity-40">
- <div className="p-10 bg-white rounded-[40px] shadow-2xl border border-slate-100 mb-8">
- <svg
- className="w-24 h-24 text-slate-200"
- fill="none"
- stroke="currentColor"
- viewBox="0 0 24 24"
- >
- <path
- strokeLinecap="round"
- strokeLinejoin="round"
- strokeWidth={1}
- d="M4 16l4.586-4.586a2 2 0 012.828 0L16 16m-2-2l1.586-1.586a2 2 0 012.828 0L20 14m-6-6h.01M6 20h12a2 2 0 002-2V6a2 2 0 00-2-2H6a2 2 0 00-2 2v12a2 2 0 002 2z"
- />
- </svg>
- </div>
- <p className="text-2xl font-bold text-slate-400">
- Project Gallery Empty
- </p>
- <p className="text-slate-300 mt-2">
- Initialize generation to view results.
- </p>
- </div>
- )}
- <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-10">
- {loading && (
- <div className="aspect-square bg-white border border-slate-200 rounded-[32px] flex flex-col items-center justify-center shadow-xl animate-pulse">
- <div className="w-16 h-16 border-4 border-[#004ea8] border-t-transparent rounded-full animate-spin"></div>
- <p className="mt-6 text-slate-500 font-bold uppercase tracking-widest text-xs">
- Computing Vision...
- </p>
- </div>
- )}
- {history.map((img, i) => (
- <div
- key={i}
- className="group relative bg-white border border-slate-200 rounded-[32px] overflow-hidden shadow-lg hover:shadow-2xl transition-all hover:scale-[1.03]"
- >
- <img
- src={img.url}
- alt={img.prompt}
- className="w-full h-auto object-cover"
- />
- <div className="absolute inset-0 bg-gradient-to-t from-[#004ea8]/90 via-transparent to-transparent opacity-0 group-hover:opacity-100 transition-all p-8 flex flex-col justify-end">
- <div className="bg-white/10 backdrop-blur-xl p-4 rounded-2xl border border-white/20">
- <p className="text-sm text-white font-semibold line-clamp-2">
- "{img.prompt}"
- </p>
- <a
- href={img.url}
- download={`asset-${i}.png`}
- className="mt-4 block w-full bg-white text-[#004ea8] text-center py-3 rounded-xl text-xs font-black uppercase tracking-widest transition-colors hover:bg-slate-100"
- >
- Export Resolution
- </a>
- </div>
- </div>
- </div>
- ))}
- </div>
- </div>
- </div>
- </div>
- );
- };
- export default ImageView;
|