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 ;
}