11import { useEffect , useState } from 'react' ;
2+ import { toast } from 'sonner' ;
23import { CircleCheck , Loader2 , CircleX , EyeIcon , EyeOffIcon } from 'lucide-react' ;
34import { Link } from 'react-router-dom' ;
45import { aiHealthcheck , subscribeToMailingList } from '@/lib/server' ;
@@ -15,7 +16,7 @@ import { Input } from '@srcbook/components/src/components/ui/input';
1516import useTheme from '@srcbook/components/src/components/use-theme' ;
1617import { Switch } from '@srcbook/components/src/components/ui/switch' ;
1718import { Button } from '@srcbook/components/src/components/ui/button' ;
18- import { toast } from 'sonner ' ;
19+ import { cn } from '@/lib/utils ' ;
1920
2021function Settings ( ) {
2122 const {
@@ -37,6 +38,8 @@ function Settings() {
3738 const [ model , setModel ] = useState < string > ( aiModel ) ;
3839 const [ baseUrl , setBaseUrl ] = useState < string > ( aiBaseUrl || '' ) ;
3940 const [ email , setEmail ] = useState < string > ( isSubscribed ? subscriptionEmail : '' ) ;
41+
42+ const [ codeiumApiKeyHovering , setCodeiumApiKeyHovering ] = useState ( false ) ;
4043 const [ codeiumApiKeyVisible , setCodeiumApiKeyVisible ] = useState ( false ) ;
4144
4245 const updateDefaultLanguage = ( value : CodeLanguageType ) => {
@@ -121,7 +124,7 @@ function Settings() {
121124
122125 < div >
123126 < h2 className = "text-xl pb-2" > AI</ h2 >
124- < div className = "flex flex-col" >
127+ < div className = "flex flex-col pb-4 " >
125128 < label className = "opacity-70 text-sm pb-4" htmlFor = "ai-provider-selector" >
126129 Select your preferred LLM and enter your credentials to use Srcbook's AI features.
127130 </ label >
@@ -210,51 +213,75 @@ function Settings() {
210213 </ div >
211214 ) }
212215 </ div >
213- </ div >
214- < div >
215- < h2 className = "text-xl pb-2" > AI Autocomplete</ h2 >
216+
217+ < h3 className = "text-md pb-2" > Codeium AI Autocomplete</ h3 >
216218 < div className = "flex flex-col" >
219+ < div className = "opacity-70 text-sm pb-1" >
220+ By default, Codeium uses a public api token with limited capabilities. Optionally,
221+ sign in to remove rate limits:
222+ </ div >
223+
217224 { codeiumApiKey ? (
218- < div >
219- < div className = "opacity-70 text-sm pb-2" > Codeium API Key:</ div >
225+ < div
226+ className = "flex flex-col p-3 border rounded-sm"
227+ onMouseEnter = { ( ) => setCodeiumApiKeyHovering ( true ) }
228+ onMouseLeave = { ( ) => setCodeiumApiKeyHovering ( false ) }
229+ >
230+ < div className = "opacity-70 text-sm pb-2" > Signed in! Codeium API Key:</ div >
220231 < div className = "flex justify-between items-center gap-2" >
221- < Input
222- name = "codeiumApiKey"
223- type = { codeiumApiKeyVisible ? 'text' : 'password' }
224- value = { codeiumApiKey }
225- readOnly
226- />
227- < Button
228- size = "icon"
229- variant = "secondary"
230- onClick = { ( ) => setCodeiumApiKeyVisible ( ( n ) => ! n ) }
231- >
232- { codeiumApiKeyVisible ? < EyeIcon size = { 16 } /> : < EyeOffIcon size = { 16 } /> }
233- </ Button >
232+ < div className = "text-left align-middle relative w-full" >
233+ < Input
234+ name = "codeiumApiKey"
235+ type = { codeiumApiKeyVisible ? 'text' : 'password' }
236+ value = { codeiumApiKey }
237+ disabled
238+ className = "disabled:opacity-100 disabled:cursor-text group-hover:border-border group-focus-within:border-border pr-8"
239+ />
240+ { codeiumApiKeyVisible ? (
241+ < EyeOffIcon
242+ size = { 14 }
243+ className = { cn (
244+ 'absolute right-3 top-2.5 cursor-pointer opacity-80 bg-background' ,
245+ ! codeiumApiKeyHovering && 'hidden' ,
246+ ) }
247+ onClick = { ( ) => setCodeiumApiKeyVisible ( false ) }
248+ />
249+ ) : (
250+ < EyeIcon
251+ size = { 14 }
252+ className = { cn (
253+ 'absolute right-3 top-2.5 cursor-pointer opacity-80 bg-background' ,
254+ ! codeiumApiKeyHovering && 'hidden' ,
255+ ) }
256+ onClick = { ( ) => setCodeiumApiKeyVisible ( true ) }
257+ />
258+ ) }
259+ </ div >
260+
234261 < Button
235262 variant = "secondary"
236263 onClick = { ( ) => {
237264 updateConfigContext ( { codeiumApiKey : null } )
238265 . then ( ( ) => {
239- toast . success ( 'Removed Codeium api key.' ) ;
266+ toast . success ( 'Detached Codeium API key.' ) ;
240267 } )
241268 . catch ( ( err ) => {
242- console . error ( 'Error removing Codeium api key:' , err ) ;
243- toast . error ( 'Error removing Codeium key!' ) ;
269+ console . error ( 'Error detaching Codeium API key:' , err ) ;
270+ toast . error ( 'Error detaching Codeium API key!' ) ;
244271 } ) ;
245272 } }
246273 >
247- Remove
274+ Detach
248275 </ Button >
249276 </ div >
250277 </ div >
251278 ) : (
252- < div >
253- < Button asChild >
279+ < div className = "flex justify-center items-center p-3 h-[64px] border rounded-sm" >
280+ < Button asChild variant = "secondary" >
254281 < Link
255282 to = { `https://www.codeium.com/profile?response_type=token&redirect_uri=${ codeiumCallbackUrl } &state=a&scope=openid%20profile%20email&redirect_parameters_type=query` }
256283 >
257- Start Codeium OAuth
284+ Authenticate with Codeium
258285 </ Link >
259286 </ Button >
260287 </ div >
0 commit comments