77 <div class =" mb-4 flex items-center justify-center" >
88 <div class =" rounded-xl bg-gray-900 p-3 dark:bg-gray-100" >
99 <svg class =" h-10 w-10 text-white dark:text-gray-900" fill =" none" stroke =" currentColor" viewBox =" 0 0 24 24" >
10- <path stroke-linecap =" round" stroke-linejoin =" round" stroke-width =" 2" d =" M8 12h.01M12 12h.01M16 12h.01M21 12c0 4.418-4.03 8-9 8a9.863 9.863 0 01-4.255-.949L3 20l1.395-3.72C3.512 15.042 3 13.574 3 12c0-4.418 4.03-8 9-8s9 3.582 9 8z" />
10+ <path
11+ stroke-linecap =" round"
12+ stroke-linejoin =" round"
13+ stroke-width =" 2"
14+ d =" M8 12h.01M12 12h.01M16 12h.01M21 12c0 4.418-4.03 8-9 8a9.863 9.863 0 01-4.255-.949L3 20l1.395-3.72C3.512 15.042 3 13.574 3 12c0-4.418 4.03-8 9-8s9 3.582 9 8z"
15+ />
1116 </svg >
1217 </div >
1318 </div >
1722
1823 <!-- Progress Indicator -->
1924 <div v-if =" showSteps" class =" mb-6 flex items-center justify-center space-x-2" >
20- <div v-for =" i in 2" :key =" i"
21- :class =" ['h-1.5 w-20 rounded-full transition-all duration-300',
22- i <= currentStep ? 'bg-gray-900 dark:bg-gray-100' : 'bg-gray-200 dark:bg-gray-700']" >
23- </div >
25+ <div
26+ v-for =" i in 2"
27+ :key =" i"
28+ :class =" [
29+ 'h-1.5 w-20 rounded-full transition-all duration-300',
30+ i <= currentStep ? 'bg-gray-900 dark:bg-gray-100' : 'bg-gray-200 dark:bg-gray-700',
31+ ]"
32+ ></div >
2433 </div >
2534
2635 <!-- Main Card -->
2938 <!-- Step 1: API Key -->
3039 <div v-if =" currentStep === 1" >
3140 <h2 class =" mb-6 text-xl font-medium text-gray-900 dark:text-white" >Setup OpenAI API</h2 >
32-
41+
3342 <div class =" space-y-4" >
3443 <div >
35- <label class =" mb-2 block text-sm font-medium text-gray-700 dark:text-gray-300" >
36- API Key
37- </label >
44+ <label class =" mb-2 block text-sm font-medium text-gray-700 dark:text-gray-300" > API Key </label >
3845 <div class =" relative" >
3946 <input
4047 v-model =" apiKey"
4148 :type =" showApiKey ? 'text' : 'password'"
4249 placeholder =" sk-..."
43- class =" w-full rounded-lg border border-gray-300 bg-white px-4 py-2.5 text-gray-900 placeholder-gray-400 focus:border-gray-400 focus:outline-none focus: ring-1 focus:ring-gray-400 dark:border-gray-600 dark:bg-gray-700 dark:text-white dark:placeholder-gray-500"
50+ class =" w-full rounded-lg border border-gray-300 bg-white px-4 py-2.5 text-gray-900 placeholder-gray-400 focus:border-gray-400 focus:ring-1 focus:ring-gray-400 focus:outline-none dark:border-gray-600 dark:bg-gray-700 dark:text-white dark:placeholder-gray-500"
4451 @input =" validateApiKey"
4552 />
4653 <button
4754 @click =" showApiKey = !showApiKey"
4855 type =" button"
49- class =" absolute right-3 top-1/2 -translate-y-1/2 text-gray-400 hover:text-gray-600 dark:hover:text-gray-300"
56+ class =" absolute top-1/2 right-3 -translate-y-1/2 text-gray-400 hover:text-gray-600 dark:hover:text-gray-300"
5057 >
5158 <svg v-if =" !showApiKey" class =" h-5 w-5" fill =" none" stroke =" currentColor" viewBox =" 0 0 24 24" >
52- <path stroke-linecap =" round" stroke-linejoin =" round" stroke-width =" 2" d =" M15 12a3 3 0 11-6 0 3 3 0 016 0z" />
53- <path stroke-linecap =" round" stroke-linejoin =" round" stroke-width =" 2" d =" M2.458 12C3.732 7.943 7.523 5 12 5c4.478 0 8.268 2.943 9.542 7-1.274 4.057-5.064 7-9.542 7-4.477 0-8.268-2.943-9.542-7z" />
59+ <path
60+ stroke-linecap =" round"
61+ stroke-linejoin =" round"
62+ stroke-width =" 2"
63+ d =" M15 12a3 3 0 11-6 0 3 3 0 016 0z"
64+ />
65+ <path
66+ stroke-linecap =" round"
67+ stroke-linejoin =" round"
68+ stroke-width =" 2"
69+ d =" M2.458 12C3.732 7.943 7.523 5 12 5c4.478 0 8.268 2.943 9.542 7-1.274 4.057-5.064 7-9.542 7-4.477 0-8.268-2.943-9.542-7z"
70+ />
5471 </svg >
5572 <svg v-else class =" h-5 w-5" fill =" none" stroke =" currentColor" viewBox =" 0 0 24 24" >
56- <path stroke-linecap =" round" stroke-linejoin =" round" stroke-width =" 2" d =" M13.875 18.825A10.05 10.05 0 0112 19c-4.478 0-8.268-2.943-9.543-7a9.97 9.97 0 011.563-3.029m5.858.908a3 3 0 114.243 4.243M9.878 9.878l4.242 4.242M9.88 9.88l-3.29-3.29m7.532 7.532l3.29 3.29M3 3l3.59 3.59m0 0A9.953 9.953 0 0112 5c4.478 0 8.268 2.943 9.543 7a10.025 10.025 0 01-4.132 5.411m0 0L21 21" />
73+ <path
74+ stroke-linecap =" round"
75+ stroke-linejoin =" round"
76+ stroke-width =" 2"
77+ d =" M13.875 18.825A10.05 10.05 0 0112 19c-4.478 0-8.268-2.943-9.543-7a9.97 9.97 0 011.563-3.029m5.858.908a3 3 0 114.243 4.243M9.878 9.878l4.242 4.242M9.88 9.88l-3.29-3.29m7.532 7.532l3.29 3.29M3 3l3.59 3.59m0 0A9.953 9.953 0 0112 5c4.478 0 8.268 2.943 9.543 7a10.025 10.025 0 01-4.132 5.411m0 0L21 21"
78+ />
5779 </svg >
5880 </button >
5981 </div >
7698
7799 <div class =" rounded-lg bg-gray-50 p-3 dark:bg-gray-900/50" >
78100 <p class =" text-sm text-gray-600 dark:text-gray-400" >
79- Need an API key?
80- <button @click =" openOpenAI" class =" font-medium text-gray-900 underline hover:text-gray-700 dark:text-gray-100 dark:hover:text-gray-300" >
101+ Need an API key?
102+ <button
103+ @click =" openOpenAI"
104+ class =" font-medium text-gray-900 underline hover:text-gray-700 dark:text-gray-100 dark:hover:text-gray-300"
105+ >
81106 Get one from OpenAI
82107 </button >
83108 </p >
88113 <button
89114 @click =" saveApiKey"
90115 :disabled =" !apiKeyValid || isValidating"
91- :class =" ['rounded-lg px-6 py-2.5 text-sm font-medium transition-all',
92- apiKeyValid && !isValidating
93- ? 'bg-gray-900 text-white hover:bg-gray-800 dark:bg-gray-100 dark:text-gray-900 dark:hover:bg-gray-200'
94- : 'bg-gray-100 text-gray-400 cursor-not-allowed dark:bg-gray-800 dark:text-gray-600']"
116+ :class =" [
117+ 'rounded-lg px-6 py-2.5 text-sm font-medium transition-all',
118+ apiKeyValid && !isValidating
119+ ? 'bg-gray-900 text-white hover:bg-gray-800 dark:bg-gray-100 dark:text-gray-900 dark:hover:bg-gray-200'
120+ : 'cursor-not-allowed bg-gray-100 text-gray-400 dark:bg-gray-800 dark:text-gray-600',
121+ ]"
95122 >
96123 <span v-if =" isValidating" class =" flex items-center" >
97124 <svg class =" mr-2 h-4 w-4 animate-spin" fill =" none" viewBox =" 0 0 24 24" >
98125 <circle class =" opacity-25" cx =" 12" cy =" 12" r =" 10" stroke =" currentColor" stroke-width =" 4" ></circle >
99- <path class =" 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 >
126+ <path
127+ class =" opacity-75"
128+ fill =" currentColor"
129+ 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"
130+ ></path >
100131 </svg >
101132 Validating...
102133 </span >
110141 <div class =" text-center" >
111142 <div class =" mb-4 inline-flex rounded-full bg-gray-100 p-3 dark:bg-gray-700" >
112143 <svg class =" h-8 w-8 text-gray-700 dark:text-gray-300" fill =" currentColor" viewBox =" 0 0 24 24" >
113- <path d =" M12 0c-6.626 0-12 5.373-12 12 0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23.957-.266 1.983-.399 3.003-.404 1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576 4.765-1.589 8.199-6.086 8.199-11.386 0-6.627-5.373-12-12-12z" />
144+ <path
145+ d =" M12 0c-6.626 0-12 5.373-12 12 0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23.957-.266 1.983-.399 3.003-.404 1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576 4.765-1.589 8.199-6.086 8.199-11.386 0-6.627-5.373-12-12-12z"
146+ />
114147 </svg >
115148 </div >
116149 <h2 class =" mb-2 text-xl font-medium text-gray-900 dark:text-white" >Support Clueless</h2 >
117150 <p class =" mb-6 text-sm text-gray-600 dark:text-gray-400" >
118- If you find Clueless helpful, please consider starring our repository on GitHub. It helps others discover the project!
151+ If you find Clueless helpful, please consider starring our repository on GitHub. It helps others discover the
152+ project!
119153 </p >
120-
154+
121155 <button
122156 @click =" openGitHub"
123157 class =" mb-4 inline-flex items-center rounded-lg bg-gray-900 px-4 py-2.5 text-sm font-medium text-white hover:bg-gray-800 dark:bg-gray-100 dark:text-gray-900 dark:hover:bg-gray-200"
124158 >
125159 <svg class =" mr-2 h-4 w-4" fill =" currentColor" viewBox =" 0 0 16 16" >
126- <path d =" M8 .25a.75.75 0 01.673.418l1.882 3.815 4.21.612a.75.75 0 01.416 1.279l-3.046 2.97.719 4.192a.75.75 0 01-1.088.791L8 12.347l-3.766 1.98a.75.75 0 01-1.088-.79l.72-4.194L.818 6.374a.75.75 0 01.416-1.28l4.21-.611L7.327.668A.75.75 0 018 .25z" />
160+ <path
161+ d =" M8 .25a.75.75 0 01.673.418l1.882 3.815 4.21.612a.75.75 0 01.416 1.279l-3.046 2.97.719 4.192a.75.75 0 01-1.088.791L8 12.347l-3.766 1.98a.75.75 0 01-1.088-.79l.72-4.194L.818 6.374a.75.75 0 01.416-1.28l4.21-.611L7.327.668A.75.75 0 018 .25z"
162+ />
127163 </svg >
128164 Star on GitHub
129165 </button >
133169 enter-from-class =" opacity-0 scale-95"
134170 enter-to-class =" opacity-100 scale-100"
135171 >
136- <p v-if =" hasStarred" class =" mb-4 text-sm text-green-600 dark:text-green-400" >
137- ✓ Thank you for your support!
138- </p >
172+ <p v-if =" hasStarred" class =" mb-4 text-sm text-green-600 dark:text-green-400" >✓ Thank you for your support!</p >
139173 </Transition >
140174 </div >
141175
162196</template >
163197
164198<script setup lang="ts">
165- import { ref , computed } from ' vue '
166- import { router } from ' @inertiajs/vue3 '
167- import axios from ' axios '
199+ import { router } from ' @inertiajs/vue3 ' ;
200+ import axios from ' axios ' ;
201+ import { computed , ref } from ' vue ' ;
168202
169- const currentStep = ref (1 )
170- const apiKey = ref (' ' )
171- const showApiKey = ref (false )
172- const apiKeyValid = ref (false )
173- const apiKeyError = ref (' ' )
174- const isValidating = ref (false )
175- const hasStarred = ref (false )
203+ const currentStep = ref (1 );
204+ const apiKey = ref (' ' );
205+ const showApiKey = ref (false );
206+ const apiKeyValid = ref (false );
207+ const apiKeyError = ref (' ' );
208+ const isValidating = ref (false );
209+ const hasStarred = ref (false );
176210
177- const showSteps = computed (() => currentStep .value > 0 )
211+ const showSteps = computed (() => currentStep .value > 0 );
178212
179213const validateApiKey = () => {
180- const key = apiKey .value .trim ()
181-
214+ const key = apiKey .value .trim ();
215+
182216 if (! key ) {
183- apiKeyValid .value = false
184- apiKeyError .value = ' '
185- return
217+ apiKeyValid .value = false ;
218+ apiKeyError .value = ' ' ;
219+ return ;
186220 }
187-
221+
188222 if (! key .startsWith (' sk-' )) {
189- apiKeyValid .value = false
190- apiKeyError .value = ' API key should start with "sk-"'
191- return
223+ apiKeyValid .value = false ;
224+ apiKeyError .value = ' API key should start with "sk-"' ;
225+ return ;
192226 }
193-
227+
194228 if (key .length < 20 ) {
195- apiKeyValid .value = false
196- apiKeyError .value = ' API key seems too short'
197- return
229+ apiKeyValid .value = false ;
230+ apiKeyError .value = ' API key seems too short' ;
231+ return ;
198232 }
199-
200- apiKeyValid .value = true
201- apiKeyError .value = ' '
202- }
233+
234+ apiKeyValid .value = true ;
235+ apiKeyError .value = ' ' ;
236+ };
203237
204238const saveApiKey = async () => {
205- if (! apiKeyValid .value || isValidating .value ) return
206-
207- isValidating .value = true
208-
239+ if (! apiKeyValid .value || isValidating .value ) return ;
240+
241+ isValidating .value = true ;
242+
209243 try {
210244 const response = await axios .post (' /api/openai/api-key' , {
211- api_key: apiKey .value
212- })
213-
245+ api_key: apiKey .value ,
246+ });
247+
214248 if (response .data .success ) {
215- currentStep .value = 2
249+ currentStep .value = 2 ;
216250 } else {
217- apiKeyError .value = ' Failed to save API key. Please try again.'
251+ apiKeyError .value = ' Failed to save API key. Please try again.' ;
218252 }
219- } catch ( error ) {
220- apiKeyError .value = ' Invalid API key or connection error. Please check and try again.'
253+ } catch {
254+ apiKeyError .value = ' Invalid API key or connection error. Please check and try again.' ;
221255 } finally {
222- isValidating .value = false
256+ isValidating .value = false ;
223257 }
224- }
258+ };
225259
226260const openGitHub = async () => {
227261 try {
228262 // Use NativePHP API endpoint to open in default browser
229263 await axios .post (' /api/open-external' , {
230- url: ' https://github.com/vijaythecoder/clueless'
231- })
232- hasStarred .value = true
264+ url: ' https://github.com/vijaythecoder/clueless' ,
265+ });
266+ hasStarred .value = true ;
233267 } catch (error ) {
234- console .error (' Failed to open GitHub:' , error )
268+ console .error (' Failed to open GitHub:' , error );
235269 // Fallback for web browser
236- window .open (' https://github.com/vijaythecoder/clueless' , ' _blank' )
237- hasStarred .value = true
270+ window .open (' https://github.com/vijaythecoder/clueless' , ' _blank' );
271+ hasStarred .value = true ;
238272 }
239- }
273+ };
240274
241275const openOpenAI = async () => {
242276 try {
243277 // Use NativePHP API endpoint to open in default browser
244278 await axios .post (' /api/open-external' , {
245- url: ' https://platform.openai.com/api-keys'
246- })
279+ url: ' https://platform.openai.com/api-keys' ,
280+ });
247281 } catch (error ) {
248- console .error (' Failed to open OpenAI:' , error )
282+ console .error (' Failed to open OpenAI:' , error );
249283 // Fallback for web browser
250- window .open (' https://platform.openai.com/api-keys' , ' _blank' )
284+ window .open (' https://platform.openai.com/api-keys' , ' _blank' );
251285 }
252- }
286+ };
253287
254288const completeOnboarding = () => {
255289 // Navigate to realtime agent
256- router .visit (' /realtime-agent' )
257- }
258- </script >
290+ router .visit (' /realtime-agent' );
291+ };
292+ </script >
0 commit comments