@@ -2,7 +2,7 @@ import React, { useState, useEffect, useCallback } from 'react';
22import {
33 FolderOpen , Plus , Clock , ChevronRight , ArrowRight ,
44 Download , CheckCircle , Loader2 , Zap , Code2 , Brain , Package ,
5- Cloud , LogOut , UserCircle ,
5+ Cloud , LogOut , UserCircle , Star ,
66} from 'lucide-react' ;
77import type { LicenseStatus } from '@/types/electron' ;
88
@@ -39,6 +39,10 @@ export const WelcomeScreen: React.FC<WelcomeScreenProps> = ({ onOpenFolder, onNe
3939 const [ licenseStatus , setLicenseStatus ] = useState < LicenseStatus | null > ( null ) ;
4040 const [ licenseLoading , setLicenseLoading ] = useState ( false ) ;
4141 const [ cloudAILoading , setCloudAILoading ] = useState ( false ) ;
42+ // Track which model is currently active (loaded)
43+ const [ activeModel , setActiveModel ] = useState < string | null > ( null ) ;
44+ // Track which model is set as default
45+ const [ defaultModelPath , setDefaultModelPath ] = useState < string | null > ( null ) ;
4246
4347 useEffect ( ( ) => {
4448 try {
@@ -68,6 +72,13 @@ export const WelcomeScreen: React.FC<WelcomeScreenProps> = ({ onOpenFolder, onNe
6872 // Load license status for sign-in strip
6973 useEffect ( ( ) => {
7074 window . electronAPI ?. licenseGetStatus ?.( ) . then ( s => { if ( s ) setLicenseStatus ( s ) ; } ) . catch ( ( ) => { } ) ;
75+ // Load default model path from settings
76+ window . electronAPI ?. getDefaultModelPath ?.( ) . then ( p => { if ( p ) setDefaultModelPath ( p ) ; } ) . catch ( ( ) => { } ) ;
77+ // Listen for auto-loaded model on startup
78+ const cleanup = window . electronAPI ?. onModelAutoLoaded ?.( ( data : { path : string ; name : string } ) => {
79+ setActiveModel ( data . path ) ;
80+ } ) ;
81+ return ( ) => { if ( typeof cleanup === 'function' ) cleanup ( ) ; } ;
7182 } , [ ] ) ;
7283
7384 const openRecent = ( path : string ) => {
@@ -88,11 +99,19 @@ export const WelcomeScreen: React.FC<WelcomeScreenProps> = ({ onOpenFolder, onNe
8899 await window . electronAPI ?. llmLoadModel ?.( modelPath ) ;
89100 // Switch app to local model — clear cloud provider preference so ChatPanel defaults to local
90101 try { localStorage . removeItem ( 'guide-cloud-provider' ) ; } catch { }
102+ setActiveModel ( modelPath ) ;
91103 } finally {
92104 setLoadingModel ( null ) ;
93105 }
94106 } ;
95107
108+ const setAsDefault = async ( modelPath : string ) => {
109+ try {
110+ await window . electronAPI ?. setDefaultModel ?.( modelPath ) ;
111+ setDefaultModelPath ( modelPath ) ;
112+ } catch { }
113+ } ;
114+
96115 const useCloudAI = ( ) => {
97116 setCloudAILoading ( true ) ;
98117 try {
@@ -309,25 +328,47 @@ export const WelcomeScreen: React.FC<WelcomeScreenProps> = ({ onOpenFolder, onNe
309328 < div className = "flex flex-col gap-1" >
310329 { installedModels . slice ( 0 , 4 ) . map ( ( model ) => {
311330 const label = ( model . name || ( model . path || '' ) . split ( / [ / \\ ] / ) . pop ( ) || 'Unknown' ) . replace ( / \. g g u f $ / i, '' ) ;
331+ const mp = model . path || model . name ;
332+ const isActive = activeModel === mp ;
333+ const isDefault = defaultModelPath === mp ;
334+ const isLoading = loadingModel === mp ;
312335 return (
313336 < div
314- key = { model . path || model . name }
337+ key = { mp }
315338 className = "flex items-center gap-2 px-3 py-1.5 rounded-lg"
316- style = { { backgroundColor : 'var(--theme-bg-secondary)' , border : '1px solid var(--theme-border)' } }
339+ style = { {
340+ backgroundColor : isActive ? 'color-mix(in srgb, var(--theme-accent) 10%, var(--theme-bg-secondary))' : 'var(--theme-bg-secondary)' ,
341+ border : isActive ? '1px solid var(--theme-accent)' : '1px solid var(--theme-border)' ,
342+ } }
317343 >
344+ { /* Set as default star */ }
345+ < button
346+ onClick = { ( ) => setAsDefault ( mp ) }
347+ className = "flex-shrink-0 transition-colors"
348+ style = { { color : isDefault ? 'var(--theme-accent)' : 'var(--theme-foreground-subtle)' , cursor : 'pointer' } }
349+ title = { isDefault ? 'Default model' : 'Set as default' }
350+ >
351+ < Star size = { 12 } fill = { isDefault ? 'currentColor' : 'none' } />
352+ </ button >
318353 < span className = "flex-1 min-w-0 text-[12px] truncate" style = { { color : 'var(--theme-foreground)' } } title = { label } >
319354 { label }
320355 </ span >
321356 < button
322- onClick = { ( ) => useModel ( model . path || model . name ) }
323- disabled = { loadingModel === ( model . path || model . name ) }
357+ onClick = { ( ) => ! isActive && useModel ( mp ) }
358+ disabled = { isLoading || isActive }
324359 className = "flex-shrink-0 text-[11px] px-2 py-0.5 rounded font-medium flex items-center justify-center gap-1 transition-opacity"
325- style = { { backgroundColor : 'var(--theme-accent)' , color : 'var(--theme-bg)' , minWidth : 36 , opacity : loadingModel === ( model . path || model . name ) ? 0.7 : 1 } }
326- onMouseEnter = { ( e ) => { if ( loadingModel !== ( model . path || model . name ) ) ( e . currentTarget as HTMLElement ) . style . opacity = '0.8' ; } }
327- onMouseLeave = { ( e ) => { if ( loadingModel !== ( model . path || model . name ) ) ( e . currentTarget as HTMLElement ) . style . opacity = '1' ; } }
328- title = { loadingModel === ( model . path || model . name ) ? 'Loading...' : `Load ${ label } ` }
360+ style = { {
361+ backgroundColor : isActive ? '#89d185' : 'var(--theme-accent)' ,
362+ color : 'var(--theme-bg)' ,
363+ minWidth : 46 ,
364+ opacity : isLoading ? 0.7 : 1 ,
365+ cursor : isActive ? 'default' : 'pointer' ,
366+ } }
367+ onMouseEnter = { ( e ) => { if ( ! isLoading && ! isActive ) ( e . currentTarget as HTMLElement ) . style . opacity = '0.8' ; } }
368+ onMouseLeave = { ( e ) => { if ( ! isLoading && ! isActive ) ( e . currentTarget as HTMLElement ) . style . opacity = '1' ; } }
369+ title = { isActive ? 'Model is active' : isLoading ? 'Loading...' : `Load ${ label } ` }
329370 >
330- { loadingModel === ( model . path || model . name ) ? < Loader2 size = { 10 } className = "animate-spin" /> : 'Use' }
371+ { isLoading ? < Loader2 size = { 10 } className = "animate-spin" /> : isActive ? 'Active' : 'Use' }
331372 </ button >
332373 </ div >
333374 ) ;
0 commit comments