diff --git a/bun.lockb b/bun.lockb old mode 100644 new mode 100755 index 34b171d5..ddcf9900 Binary files a/bun.lockb and b/bun.lockb differ diff --git a/src/components/AiChatInterface.tsx b/src/components/AiChatInterface.tsx index 4a5d88ae..98032eed 100644 --- a/src/components/AiChatInterface.tsx +++ b/src/components/AiChatInterface.tsx @@ -10,6 +10,8 @@ import { Link, useLocation } from "wouter" import { useSnippet } from "@/hooks/use-snippet" import { Edit2 } from "lucide-react" import { SnippetLink } from "./SnippetLink" +import { useGlobalStore } from "@/hooks/use-global-store" +import { useSignIn } from "@/hooks/use-sign-in" export default function AIChatInterface({ code, @@ -19,8 +21,10 @@ export default function AIChatInterface({ onStartStreaming, onStopStreaming, errorMessage, + disabled, }: { code: string + disabled?: boolean hasUnsavedChanges: boolean snippetId?: string | null onCodeChange: (code: string) => void @@ -36,6 +40,8 @@ export default function AIChatInterface({ const [currentCodeBlock, setCurrentCodeBlock] = useState(null) const [location, navigate] = useLocation() const isStreamingRef = useRef(false) + const isLoggedIn = useGlobalStore((s) => Boolean(s.session)) + const signIn = useSignIn() useEffect(() => { messagesEndRef.current?.scrollIntoView({ behavior: "smooth" }) @@ -159,12 +165,28 @@ export default function AIChatInterface({ )} - {messages.length === 0 && ( + {messages.length === 0 && isLoggedIn && (
Submit a prompt to {snippet ? "edit!" : "get started!"}
)} + {!isLoggedIn && ( +
+
+ Sign in use the AI chat or{" "} + + use the regular editor + +
+
+ + +
+
+ )} {messages.map((message, index) => ( ))} @@ -176,6 +198,7 @@ export default function AIChatInterface({ onClick={() => { addMessage(`Fix this error: ${errorMessage}`) }} + disabled={!isLoggedIn} className="mb-2 bg-green-50 hover:bg-green-100" variant="outline" > @@ -191,7 +214,7 @@ export default function AIChatInterface({ onSubmit={async (message: string) => { addMessage(message) }} - disabled={isStreaming} + disabled={isStreaming || !isLoggedIn} /> ) diff --git a/src/components/ChatInput.tsx b/src/components/ChatInput.tsx index 7be92ae6..775627d5 100644 --- a/src/components/ChatInput.tsx +++ b/src/components/ChatInput.tsx @@ -44,6 +44,7 @@ export default function ChatInput({ onSubmit, disabled }: ChatInputProps) { type="submit" size="icon" className="absolute right-2 top-1/2 transform -translate-y-1/2 bg-blue-500 hover:bg-blue-600 text-white rounded-full" + disabled={disabled} > diff --git a/src/components/CodeAndPreview.tsx b/src/components/CodeAndPreview.tsx index 3c7b9ff6..787484ba 100644 --- a/src/components/CodeAndPreview.tsx +++ b/src/components/CodeAndPreview.tsx @@ -21,6 +21,9 @@ import { ErrorBoundary } from "react-error-boundary" import { ErrorTabContent } from "./ErrorTabContent" import { cn } from "@/lib/utils" import { PreviewContent } from "./PreviewContent" +import { useGlobalStore } from "@/hooks/use-global-store" +import { useUrlParams } from "@/hooks/use-url-params" +import { getSnippetTemplate } from "@/lib/get-snippet-template" interface Props { snippet?: Snippet | null @@ -28,18 +31,31 @@ interface Props { export function CodeAndPreview({ snippet }: Props) { const axios = useAxios() + const isLoggedIn = useGlobalStore((s) => Boolean(s.session)) + const urlParams = useUrlParams() + const templateFromUrl = useMemo( + () => getSnippetTemplate(urlParams.template), + [], + ) const defaultCode = useMemo(() => { - return decodeUrlHashToText(window.location.toString()) ?? snippet?.code + return ( + decodeUrlHashToText(window.location.toString()) ?? + snippet?.code ?? + templateFromUrl.code + ) }, []) const [code, setCode] = useState(defaultCode ?? "") const [dts, setDts] = useState("") const [showPreview, setShowPreview] = useState(true) + const snippetType: "board" | "package" | "model" | "footprint" = + snippet?.snippet_type ?? (templateFromUrl.type as any) useEffect(() => { - if (snippet?.code && !defaultCode) { + if (snippet?.code) { setCode(snippet.code) } - }, [snippet?.code]) + }, [Boolean(snippet)]) + const { toast } = useToast() const { @@ -50,7 +66,7 @@ export function CodeAndPreview({ snippet }: Props) { tsxRunTriggerCount, } = useRunTsx({ code, - type: snippet?.snippet_type, + type: snippetType, }) const qc = useQueryClient() @@ -91,7 +107,7 @@ export function CodeAndPreview({ snippet }: Props) { const hasUnsavedChanges = snippet?.code !== code - if (!snippet) { + if (!snippet && isLoggedIn) { return
Loading...
} @@ -100,6 +116,7 @@ export function CodeAndPreview({ snippet }: Props) { void @@ -54,19 +57,30 @@ export default function EditorNav({ onSave: () => void }) { const [, navigate] = useLocation() + const isLoggedIn = useGlobalStore((s) => Boolean(s.session)) return ( @@ -127,6 +131,7 @@ export default function Header() { Editor diff --git a/src/components/HeaderLogin.tsx b/src/components/HeaderLogin.tsx index 29984f3c..57813f7a 100644 --- a/src/components/HeaderLogin.tsx +++ b/src/components/HeaderLogin.tsx @@ -13,6 +13,7 @@ import { useSnippetsBaseApiUrl } from "@/hooks/use-snippets-base-api-url" import { useGlobalStore } from "@/hooks/use-global-store" import { useAccountBalance } from "@/hooks/use-account-balance" import { useIsUsingFakeApi } from "@/hooks/use-is-using-fake-api" +import { useSignIn } from "@/hooks/use-sign-in" interface HeaderLoginProps {} @@ -23,6 +24,7 @@ export const HeaderLogin: React.FC = () => { const setSession = useGlobalStore((s) => s.setSession) const snippetsBaseApiUrl = useSnippetsBaseApiUrl() const isUsingFakeApi = useIsUsingFakeApi() + const signIn = useSignIn() const { data: accountBalance } = useAccountBalance() if (!isLoggedIn) { @@ -45,21 +47,10 @@ export const HeaderLogin: React.FC = () => { ) : ( <> - - diff --git a/src/components/PreviewContent.tsx b/src/components/PreviewContent.tsx index 0942ebec..0fcd8488 100644 --- a/src/components/PreviewContent.tsx +++ b/src/components/PreviewContent.tsx @@ -51,7 +51,7 @@ export type PreviewContentProps = const PreviewEmptyState = ({ triggerRunTsx, }: { triggerRunTsx: () => void }) => ( -
+
No circuit json loaded