File size: 5,715 Bytes
02ce812
 
763be49
 
 
 
 
02ce812
763be49
 
 
 
02ce812
763be49
02ce812
763be49
 
 
 
 
 
02ce812
763be49
 
 
 
02ce812
763be49
02ce812
763be49
02ce812
 
 
 
 
 
 
 
763be49
02ce812
 
763be49
 
 
02ce812
763be49
 
 
 
02ce812
763be49
02ce812
763be49
 
 
 
02ce812
763be49
 
 
 
 
 
 
 
 
8769c74
763be49
 
 
 
 
02ce812
763be49
 
 
 
 
02ce812
8769c74
02ce812
763be49
 
 
 
 
 
 
 
 
 
 
02ce812
 
 
 
 
763be49
02ce812
 
 
 
 
 
 
 
 
 
 
 
 
 
763be49
 
 
02ce812
763be49
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
02ce812
 
 
 
 
 
 
 
 
 
763be49
 
 
 
 
 
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 React, { useEffect, useRef } from 'react';
import { MagicSparkleIcon, CloseIcon, QuestionMarkIcon } from './icons';

interface AiEditModalProps {
  isOpen: boolean;
  onClose: () => void;
  onGenerate: () => void;
  onAsk: () => void;
  imageUrl: string;
  prompt: string;
  onPromptChange: (newPrompt: string) => void;
  isLoading: boolean;
  isAsking: boolean;
  error: string | null;
  askUrl: string | null;
}

const AiEditModal: React.FC<AiEditModalProps> = ({
  isOpen,
  onClose,
  onGenerate,
  onAsk,
  imageUrl,
  prompt,
  onPromptChange,
  isLoading,
  isAsking,
  error,
  askUrl,
}) => {
  const iframeContainerRef = useRef<HTMLDivElement>(null);
  
  useEffect(() => {
    if (askUrl && iframeContainerRef.current) {
      iframeContainerRef.current.scrollIntoView({ behavior: 'smooth', block: 'start' });
    }
  }, [askUrl]);
  
  if (!isOpen) return null;
  
  const isAnyLoading = isLoading || isAsking;

  return (
    <div 
        className="fixed inset-0 bg-black bg-opacity-60 backdrop-blur-sm flex justify-center items-start z-[1000] p-4 pt-16"
        aria-modal="true"
        role="dialog"
        aria-labelledby="ai-edit-modal-title"
    >
      <div className="bg-white rounded-lg shadow-2xl p-6 w-full max-w-lg transform transition-all max-h-[calc(100vh-5rem)] overflow-y-auto">
        <div className="flex justify-between items-center mb-4">
          <h2 id="ai-edit-modal-title" className="text-xl font-semibold text-slate-700">Edit or Ask about Image with AI</h2>
          <button
            onClick={onClose}
            className="text-slate-400 hover:text-slate-600 transition-colors"
            aria-label="Close AI edit modal"
            disabled={isAnyLoading}
          >
            <CloseIcon className="w-6 h-6" />
          </button>
        </div>

        <div className="mb-4">
          <img 
            src={imageUrl} 
            alt="Uploaded image preview" 
            className="max-w-full w-auto h-32 rounded border border-slate-300 object-contain mx-auto" 
          />
        </div>

        <div className="mb-4">
          <label htmlFor="aiPrompt" className="block text-sm font-medium text-slate-700 mb-1">
            Describe what you want to change, or ask a question:
          </label>
          <textarea
            id="aiPrompt"
            value={prompt}
            onChange={(e) => onPromptChange(e.target.value)}
            placeholder="e.g., 'make the cat wear a party hat' or 'what is in this image?'"
            className="w-full p-2 border border-slate-300 rounded-md focus:ring-2 focus:ring-blue-500 focus:border-blue-500 transition-shadow text-xl h-[200px]"
            disabled={isAnyLoading}
            aria-describedby={error ? "ai-edit-error" : undefined}
          />
        </div>

        {error && (
          <div id="ai-edit-error" className="mb-4 p-3 bg-red-100 border border-red-300 text-red-700 rounded-md text-sm" role="alert">
            <p className="font-semibold">Error:</p>
            <p>{error}</p>
          </div>
        )}

        <div className="flex justify-between items-center gap-3">
           <button
            onClick={onAsk}
            disabled={isAnyLoading || !prompt.trim()}
            className="px-4 py-2 bg-sky-600 text-white rounded-md hover:bg-sky-700 focus:ring-2 focus:ring-sky-500 focus:ring-offset-2 transition-colors disabled:opacity-50 disabled:cursor-not-allowed text-sm font-medium flex items-center justify-center gap-2"
          >
            {isAsking ? (
              <>
                <svg className="animate-spin -ml-1 mr-2 h-4 w-4 text-white" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24">
                  <circle className="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" strokeWidth="4"></circle>
                  <path className="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
                </svg>
                Asking...
              </>
            ) : (
              <>
                <QuestionMarkIcon className="w-4 h-4 mr-1" />
                Ask
              </>
            )}
          </button>
          <button
            onClick={onGenerate}
            disabled={isAnyLoading || !prompt.trim()}
            className="px-4 py-2 bg-blue-600 text-white rounded-md hover:bg-blue-700 focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 transition-colors disabled:opacity-50 disabled:cursor-not-allowed text-sm font-medium flex items-center justify-center gap-2"
          >
            {isLoading ? (
              <>
                <svg className="animate-spin -ml-1 mr-2 h-4 w-4 text-white" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24">
                  <circle className="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" strokeWidth="4"></circle>
                  <path className="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
                </svg>
                Generating...
              </>
            ) : (
              <>
                <MagicSparkleIcon className="w-4 h-4 mr-1" />
                Generate Image
              </>
            )}
          </button>
        </div>

        {askUrl && (
          <div ref={iframeContainerRef} className="mt-4 pt-2">
            <iframe
              src={askUrl}
              title="AI Response"
              className="w-full h-[70vh] border-0 rounded-md bg-slate-50"
            />
          </div>
        )}
      </div>
    </div>
  );
};

export default AiEditModal;