diff --git a/packages/web/src/components/apps/markdown.tsx b/packages/web/src/components/apps/markdown.tsx index b5df654c..1f29744a 100644 --- a/packages/web/src/components/apps/markdown.tsx +++ b/packages/web/src/components/apps/markdown.tsx @@ -1,10 +1,11 @@ -import MarkdownReact from 'marked-react'; -import { cn } from '@srcbook/components'; +import { marked } from 'marked'; +import { cn } from '@/lib/utils'; export default function Markdown(props: { source: string; className?: string }) { return ( -
- {props.source} -
+
); } diff --git a/packages/web/src/components/onboarding-modal.tsx b/packages/web/src/components/onboarding-modal.tsx index 2ce9df2b..4aa7061a 100644 --- a/packages/web/src/components/onboarding-modal.tsx +++ b/packages/web/src/components/onboarding-modal.tsx @@ -1,35 +1,38 @@ import React, { useState, useEffect } from 'react'; import { LayoutGrid, FileText, Loader2, CircleCheck, CircleX } from 'lucide-react'; -import { Button } from '../../../components/src/components/ui/button'; -import { Input } from '../../../components/src/components/ui/input'; +import { Button } from '@srcbook/components/src/components/ui/button'; +import { Input } from '@srcbook/components/src/components/ui/input'; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, -} from '../../../components/src/components/ui/select'; +} from '@srcbook/components/src/components/ui/select'; import { AiProviderType, getDefaultModel } from '@srcbook/shared'; import { aiHealthcheck } from '@/lib/server'; +import { useSettings } from '@/components/use-settings'; interface OnboardingModalProps { onComplete: (apiKey: string) => void; } const OnboardingModal: React.FC = ({ onComplete }) => { - const [aiProvider, setAiProvider] = useState('anthropic'); + const { aiProvider, aiModel, updateConfig } = useSettings(); const [apiKey, setApiKey] = useState(''); - const [model, setModel] = useState(getDefaultModel('anthropic')); const handleContinue = () => { if (apiKey.trim()) { + updateConfig({ + [aiProvider === 'openai' ? 'openaiKey' : 'anthropicKey']: apiKey + }); onComplete(apiKey); } }; const handleAiProviderChange = (provider: AiProviderType) => { - setAiProvider(provider); - setModel(getDefaultModel(provider)); + const newModel = getDefaultModel(provider); + updateConfig({ aiProvider: provider, aiModel: newModel }); }; return ( @@ -82,8 +85,8 @@ const OnboardingModal: React.FC = ({ onComplete }) => { name="aiModel" className="w-[200px]" placeholder="AI model" - value={model} - onChange={(e) => setModel(e.target.value)} + value={aiModel} + onChange={(e) => updateConfig({ aiModel: e.target.value })} />
@@ -95,7 +98,7 @@ const OnboardingModal: React.FC = ({ onComplete }) => { className="flex-1" placeholder={`${aiProvider} API Key`} /> - +
@@ -135,6 +138,7 @@ const TestAiButton: React.FC<{ apiKey: string; aiProvider: AiProviderType; model aiProvider, model, }) => { + const { updateConfig } = useSettings(); const [state, setState] = useState<'idle' | 'loading' | 'success' | 'error'>('idle'); const TIMEOUT = 2500; @@ -147,7 +151,14 @@ const TestAiButton: React.FC<{ apiKey: string; aiProvider: AiProviderType; model const check = () => { setState('loading'); - aiHealthcheck(apiKey, aiProvider, model) + // Update the global configuration before running the healthcheck + updateConfig({ + aiProvider, + aiModel: model, + [aiProvider === 'openai' ? 'openaiKey' : 'anthropicKey']: apiKey + }); + + aiHealthcheck() .then((res) => { setState(res.error ? 'error' : 'success'); }) diff --git a/packages/web/src/routes/home.tsx b/packages/web/src/routes/home.tsx index 58a22de0..991a9c3f 100644 --- a/packages/web/src/routes/home.tsx +++ b/packages/web/src/routes/home.tsx @@ -68,24 +68,27 @@ export default function Home() { const [appToDelete, setAppToDelete] = useState(null); const [showCreateAppModal, setShowCreateAppModal] = useState(false); - const { openaiKey, anthropicKey, aiBaseUrl } = useSettings(); + const { aiProvider, openaiKey, anthropicKey } = useSettings(); const [showOnboarding, setShowOnboarding] = useState(false); + const [isLoading, setIsLoading] = useState(true); useEffect(() => { - const hasSeenOnboarding = localStorage.getItem('hasSeenOnboarding'); - const hasApiKey = openaiKey || anthropicKey || aiBaseUrl; + const checkApiKey = () => { + const hasSeenOnboarding = localStorage.getItem('hasSeenOnboarding') === 'true'; + const hasApiKey = aiProvider === 'openai' ? !!openaiKey : !!anthropicKey; - if (!hasSeenOnboarding && !hasApiKey) { - setShowOnboarding(true); - } - }, [openaiKey, anthropicKey, aiBaseUrl]); + if (!hasSeenOnboarding || !hasApiKey) { + setShowOnboarding(true); + } + setIsLoading(false); + }; - const handleOnboardingComplete = (apiKey: string) => { + checkApiKey(); + }, [aiProvider, openaiKey, anthropicKey]); + + const handleOnboardingComplete = () => { setShowOnboarding(false); localStorage.setItem('hasSeenOnboarding', 'true'); - // Here you should update the API key in your settings - // This depends on how your settings are managed, but it might look like: - // updateConfigContext({ openaiKey: apiKey }); // or anthropicKey, depending on the provider }; function onDeleteSrcbook(srcbook: SessionType) { @@ -113,6 +116,10 @@ export default function Home() { openSrcbook(result.dir); } + if (isLoading) { + return
Loading...
; + } + if (showOnboarding) { return ; }