@tscircuit/fake-snippets 0.0.90 → 0.0.91

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -118,6 +118,7 @@ export default withRouteSpec({
118
118
  prediction: z.string(),
119
119
  }),
120
120
  })(async (req, ctx) => {
121
+ return ctx.json({ prediction: "mock" })
121
122
  const openai = getOpenAIClient()
122
123
  const { prefix, suffix, model, language } = req.jsonBody
123
124
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tscircuit/fake-snippets",
3
- "version": "0.0.90",
3
+ "version": "0.0.91",
4
4
  "type": "module",
5
5
  "repository": {
6
6
  "type": "git",
@@ -77,16 +77,12 @@
77
77
  "@tailwindcss/typography": "^0.5.16",
78
78
  "@tscircuit/3d-viewer": "^0.0.279",
79
79
  "@tscircuit/assembly-viewer": "^0.0.1",
80
- "@tscircuit/core": "^0.0.536",
81
80
  "@tscircuit/create-snippet-url": "^0.0.8",
82
81
  "@tscircuit/eval": "^0.0.244",
83
- "@tscircuit/footprinter": "^0.0.186",
84
82
  "@tscircuit/layout": "^0.0.29",
85
- "@tscircuit/math-utils": "^0.0.10",
86
83
  "@tscircuit/mm": "^0.0.8",
87
84
  "@tscircuit/pcb-viewer": "^1.11.194",
88
85
  "@tscircuit/prompt-benchmarks": "^0.0.28",
89
- "@tscircuit/props": "^0.0.246",
90
86
  "@tscircuit/runframe": "^0.0.669",
91
87
  "@tscircuit/schematic-viewer": "^2.0.21",
92
88
  "@types/babel__standalone": "^7.1.7",
@@ -108,7 +104,6 @@
108
104
  "@vitejs/plugin-react": "^4.3.1",
109
105
  "autoprefixer": "^10.4.20",
110
106
  "change-case": "^5.4.4",
111
- "circuit-json": "^0.0.190",
112
107
  "circuit-json-to-bom-csv": "^0.0.7",
113
108
  "circuit-json-to-gerber": "^0.0.25",
114
109
  "circuit-json-to-pnp-csv": "^0.0.7",
@@ -124,7 +119,7 @@
124
119
  "date-fns": "^4.1.0",
125
120
  "dotenv": "^16.5.0",
126
121
  "dsn-converter": "^0.0.60",
127
- "easyeda": "^0.0.195",
122
+ "easyeda": "^0.0.203",
128
123
  "embla-carousel-react": "^8.3.0",
129
124
  "extract-codefence": "^0.0.4",
130
125
  "fflate": "^0.8.2",
@@ -139,7 +134,7 @@
139
134
  "jose": "^5.9.3",
140
135
  "jscad-electronics": "^0.0.25",
141
136
  "jszip": "^3.10.1",
142
- "kicad-converter": "^0.0.16",
137
+ "kicad-converter": "^0.0.17",
143
138
  "ky": "^1.7.5",
144
139
  "lucide-react": "^0.488.0",
145
140
  "lz-string": "^1.5.0",
@@ -179,6 +174,7 @@
179
174
  "terser": "^5.27.0",
180
175
  "three": "^0.177.0",
181
176
  "three-stdlib": "^2.36.0",
177
+ "tscircuit": "^0.0.522",
182
178
  "tsup": "^8.5.0",
183
179
  "typescript": "^5.6.3",
184
180
  "use-async-memo": "^1.2.5",
@@ -4,7 +4,6 @@ import { useEffect } from "react"
4
4
  import { useGlobalStore } from "./hooks/use-global-store"
5
5
  import { posthog } from "./lib/posthog"
6
6
  import { Toaster } from "react-hot-toast"
7
- import { Toaster as SonnerToaster } from "@/components/ui/sonner"
8
7
  import { populateQueryCacheWithSSRData } from "./lib/populate-query-cache-with-ssr-data"
9
8
 
10
9
  const staffGithubUsernames = [
@@ -66,7 +65,6 @@ export const ContextProviders = ({ children }: any) => {
66
65
  <PostHogIdentifier />
67
66
  {children}
68
67
  <Toaster position="bottom-right" />
69
- <SonnerToaster position="bottom-left" />
70
68
  </HelmetProvider>
71
69
  </QueryClientProvider>
72
70
  )
@@ -3,7 +3,7 @@ import { useAxios } from "@/hooks/use-axios"
3
3
  import { useLocation } from "wouter"
4
4
  import React, { useState } from "react"
5
5
  import { useQuery } from "react-query"
6
- import { useSnippetsBaseApiUrl } from "@/hooks/use-snippets-base-api-url"
6
+ import { usePackagesBaseApiUrl } from "@/hooks/use-packages-base-api-url"
7
7
  import { Search } from "lucide-react"
8
8
  import { Button } from "./ui/button"
9
9
  import { PackageCardSkeleton } from "./PackageCardSkeleton"
@@ -20,7 +20,7 @@ const PageSearchComponent: React.FC<PageSearchComponentProps> = ({
20
20
  }) => {
21
21
  const [location, setLocation] = useLocation()
22
22
  const axios = useAxios()
23
- const snippetsBaseApiUrl = useSnippetsBaseApiUrl()
23
+ const snippetsBaseApiUrl = usePackagesBaseApiUrl()
24
24
 
25
25
  // Initialize search query directly from URL
26
26
  const [searchQuery, setSearchQuery] = useState(
@@ -4,7 +4,7 @@ import { useLocation } from "wouter"
4
4
  import React, { useEffect, useRef, useState } from "react"
5
5
  import { useQuery } from "react-query"
6
6
  import { Alert } from "./ui/alert"
7
- import { useSnippetsBaseApiUrl } from "@/hooks/use-snippets-base-api-url"
7
+ import { usePackagesBaseApiUrl } from "@/hooks/use-packages-base-api-url"
8
8
  import { PrefetchPageLink } from "./PrefetchPageLink"
9
9
  import { CircuitBoard } from "lucide-react"
10
10
  import { cn } from "@/lib/utils"
@@ -60,7 +60,7 @@ const SearchComponent: React.FC<SearchComponentProps> = ({
60
60
  const resultsRef = useRef<HTMLDivElement>(null)
61
61
  const inputRef = useRef<HTMLInputElement>(null)
62
62
  const [location, setLocation] = useLocation()
63
- const snippetsBaseApiUrl = useSnippetsBaseApiUrl()
63
+ const snippetsBaseApiUrl = usePackagesBaseApiUrl()
64
64
 
65
65
  const { data: searchResults, isLoading } = useQuery(
66
66
  ["packageSearch", searchQuery],
@@ -4,7 +4,7 @@ import { StarFilledIcon } from "@radix-ui/react-icons"
4
4
  import { Link } from "wouter"
5
5
  import { Package } from "fake-snippets-api/lib/db/schema"
6
6
  import { useRef, useState } from "react"
7
- import { useSnippetsBaseApiUrl } from "@/hooks/use-snippets-base-api-url"
7
+ import { usePackagesBaseApiUrl } from "@/hooks/use-packages-base-api-url"
8
8
 
9
9
  const CarouselItem = ({
10
10
  pkg,
@@ -36,7 +36,7 @@ export const TrendingPackagesCarousel = () => {
36
36
  const axios = useAxios()
37
37
  const scrollRef = useRef<HTMLDivElement>(null)
38
38
  const [isHovered, setIsHovered] = useState(false)
39
- const apiBaseUrl = useSnippetsBaseApiUrl()
39
+ const apiBaseUrl = usePackagesBaseApiUrl()
40
40
 
41
41
  const { data: trendingPackages } = useQuery<Package[]>(
42
42
  "trendingPackages",
@@ -0,0 +1,25 @@
1
+ import { createUseDialog } from "./create-use-dialog"
2
+ import {
3
+ ComponentSearchResult,
4
+ ImportComponentDialog as RunframeImportComponentDialog,
5
+ } from "@tscircuit/runframe/runner"
6
+
7
+ export const ImportComponentDialog = ({
8
+ open,
9
+ onOpenChange,
10
+ onComponentSelected,
11
+ }: {
12
+ open: boolean
13
+ onOpenChange: (open: boolean) => any
14
+ onComponentSelected: (pkg: ComponentSearchResult) => any
15
+ }) => {
16
+ return (
17
+ <RunframeImportComponentDialog
18
+ isOpen={open}
19
+ onClose={() => onOpenChange(false)}
20
+ onImport={(data) => onComponentSelected(data)}
21
+ />
22
+ )
23
+ }
24
+
25
+ export const useImportComponentDialog = createUseDialog(ImportComponentDialog)
@@ -1,4 +1,4 @@
1
- import { useSnippetsBaseApiUrl } from "@/hooks/use-snippets-base-api-url"
1
+ import { usePackagesBaseApiUrl } from "@/hooks/use-packages-base-api-url"
2
2
  import { useHotkeyCombo } from "@/hooks/use-hotkey"
3
3
  import { basicSetup } from "@/lib/codemirror/basic-setup"
4
4
  import {
@@ -82,7 +82,7 @@ export const CodeEditor = ({
82
82
  const viewRef = useRef<EditorView | null>(null)
83
83
  const ataRef = useRef<ReturnType<typeof setupTypeAcquisition> | null>(null)
84
84
  const lastReceivedTsFileTimeRef = useRef<number>(0)
85
- const apiUrl = useSnippetsBaseApiUrl()
85
+ const apiUrl = usePackagesBaseApiUrl()
86
86
  const codeCompletionApi = useCodeCompletionApi()
87
87
  const [cursorPosition, setCursorPosition] = useState<number | null>(null)
88
88
  const [code, setCode] = useState(files[0]?.content || "")
@@ -329,17 +329,20 @@ export const CodeEditor = ({
329
329
  if (aiAutocompleteEnabled) {
330
330
  baseExtensions.push(
331
331
  inlineCopilot(async (prefix, suffix) => {
332
- const res = await fetch("/api/autocomplete/create_autocomplete", {
333
- method: "POST",
334
- headers: {
335
- "Content-Type": "application/json",
332
+ const res = await fetch(
333
+ `${apiUrl}/autocomplete/create_autocomplete`,
334
+ {
335
+ method: "POST",
336
+ headers: {
337
+ "Content-Type": "application/json",
338
+ },
339
+ body: JSON.stringify({
340
+ prefix,
341
+ suffix,
342
+ language: "typescript",
343
+ }),
336
344
  },
337
- body: JSON.stringify({
338
- prefix,
339
- suffix,
340
- language: "typescript",
341
- }),
342
- })
345
+ )
343
346
 
344
347
  const { prediction } = await res.json()
345
348
  return prediction
@@ -661,6 +664,10 @@ export const CodeEditor = ({
661
664
  {showImportAndFormatButtons && (
662
665
  <CodeEditorHeader
663
666
  entrypointFileName={entryPointFileName}
667
+ appendNewFile={(path: string, content: string) => {
668
+ onFileContentChanged?.(path, content)
669
+ }}
670
+ createFile={handleCreateFile}
664
671
  fileSidebarState={
665
672
  [sidebarOpen, setSidebarOpen] as ReturnType<
666
673
  typeof useState<boolean>
@@ -1,7 +1,7 @@
1
1
  import React, { useState, useCallback } from "react"
2
2
  import { Button } from "@/components/ui/button"
3
3
  import { handleManualEditsImportWithSupportForMultipleFiles } from "@/lib/handleManualEditsImportWithSupportForMultipleFiles"
4
- import { useImportPackageDialog } from "@/components/dialogs/import-package-dialog"
4
+ import { useImportComponentDialog } from "@/components/dialogs/import-component-dialog"
5
5
  import { useToast } from "@/hooks/use-toast"
6
6
  import {
7
7
  DropdownMenu,
@@ -19,14 +19,16 @@ import {
19
19
  SelectValue,
20
20
  } from "../ui/select"
21
21
  import { isHiddenFile } from "../ViewPackagePage/utils/is-hidden-file"
22
- import { Package } from "fake-snippets-api/lib/db/schema"
23
22
  import {
24
23
  Tooltip,
25
24
  TooltipContent,
26
25
  TooltipProvider,
27
26
  TooltipTrigger,
28
27
  } from "@/components/ui/tooltip"
29
- import ai from "fake-snippets-api/routes/api/ai"
28
+ import { convertRawEasyToTsx, fetchEasyEDAComponent } from "easyeda/browser"
29
+ import { ComponentSearchResult } from "@tscircuit/runframe/runner"
30
+ import { usePackagesBaseApiUrl } from "@/hooks/use-packages-base-api-url"
31
+ import { ICreateFileProps, ICreateFileResult } from "@/hooks/useFileManagement"
30
32
 
31
33
  export type FileName = string
32
34
 
@@ -37,6 +39,8 @@ interface CodeEditorHeaderProps {
37
39
  fileSidebarState: ReturnType<typeof useState<boolean>>
38
40
  handleFileChange: (filename: FileName) => void
39
41
  entrypointFileName?: string
42
+ appendNewFile: (path: string, content: string) => void
43
+ createFile: (props: ICreateFileProps) => ICreateFileResult
40
44
  aiAutocompleteState: [boolean, React.Dispatch<React.SetStateAction<boolean>>]
41
45
  }
42
46
 
@@ -44,15 +48,18 @@ export const CodeEditorHeader: React.FC<CodeEditorHeaderProps> = ({
44
48
  currentFile,
45
49
  files,
46
50
  updateFileContent,
51
+ appendNewFile,
47
52
  fileSidebarState,
48
53
  handleFileChange,
49
54
  entrypointFileName = "index.tsx",
55
+ createFile,
50
56
  aiAutocompleteState,
51
57
  }) => {
52
- const { Dialog: ImportPackageDialog, openDialog: openImportDialog } =
53
- useImportPackageDialog()
54
- const { toast } = useToast()
58
+ const { Dialog: ImportComponentDialog, openDialog: openImportDialog } =
59
+ useImportComponentDialog()
60
+ const { toast, toastLibrary } = useToast()
55
61
  const [sidebarOpen, setSidebarOpen] = fileSidebarState
62
+ const API_BASE = usePackagesBaseApiUrl()
56
63
  const [aiAutocompleteEnabled, setAiAutocompleteEnabled] = aiAutocompleteState
57
64
 
58
65
  const handleFormatFile = useCallback(() => {
@@ -144,6 +151,49 @@ export const CodeEditorHeader: React.FC<CodeEditorHeaderProps> = ({
144
151
  }
145
152
  }, [currentFile, files, toast, updateFileContent])
146
153
 
154
+ const handleComponentImport = async (component: ComponentSearchResult) => {
155
+ if (component.source == "tscircuit.com") {
156
+ const newContent = `import {} from "@tsci/${component.owner}.${component.name}"\n${files[currentFile || ""]}`
157
+ updateFileContent(currentFile, newContent)
158
+ }
159
+ if (component.source == "jlcpcb") {
160
+ const jlcpcbComponent = await fetchEasyEDAComponent("C1", {
161
+ fetch: ((url, options: any) => {
162
+ return fetch(`${API_BASE}/proxy`, {
163
+ ...options,
164
+ headers: {
165
+ ...options?.headers,
166
+ "X-Target-Url": url.toString(),
167
+ "X-Sender-Origin": options?.headers?.origin ?? "",
168
+ "X-Sender-Host": options?.headers?.host ?? "https://easyeda.com",
169
+ "X-Sender-Referer": options?.headers?.referer ?? "",
170
+ "X-Sender-User-Agent": options?.headers?.userAgent ?? "",
171
+ "X-Sender-Cookie": options?.headers?.cookie ?? "",
172
+ },
173
+ })
174
+ }) as typeof fetch,
175
+ })
176
+ const tsxComponent = await convertRawEasyToTsx(jlcpcbComponent)
177
+ let componentName = component.name.replace(/ /g, "-")
178
+ if (files[`${componentName}.tsx`] || files[`./${componentName}.tsx`]) {
179
+ componentName = `${componentName}-1`
180
+ }
181
+ const createFileResult = createFile({
182
+ newFileName: `${componentName}.tsx`,
183
+ content: tsxComponent,
184
+ onError: (error) => {
185
+ throw error
186
+ },
187
+ openFile: false,
188
+ })
189
+ if (!createFileResult.newFileCreated) {
190
+ throw new Error("Failed to create file")
191
+ }
192
+ const newContent = `import ${componentName.replace(/-/g, "")} from "./${componentName}.tsx"\n${files[currentFile || ""]}`
193
+ updateFileContent(currentFile, newContent)
194
+ }
195
+ }
196
+
147
197
  return (
148
198
  <>
149
199
  <div className="flex items-center gap-2 px-2 border-b border-gray-200">
@@ -275,10 +325,17 @@ export const CodeEditorHeader: React.FC<CodeEditorHeaderProps> = ({
275
325
  Format
276
326
  </Button>
277
327
  </div>
278
- <ImportPackageDialog
279
- onPackageSelected={(pkg: Package) => {
280
- const newContent = `import {} from "@tsci/${pkg.owner_github_username}.${pkg.unscoped_name}"\n${files[currentFile || ""]}`
281
- updateFileContent(currentFile, newContent)
328
+ <ImportComponentDialog
329
+ onComponentSelected={async (component) => {
330
+ toastLibrary.promise(handleComponentImport(component), {
331
+ loading: "Importing component...",
332
+ success: <p>Component imported successfully!</p>,
333
+ error: (error) => (
334
+ <p>
335
+ Error importing component: {error.message || String(error)}
336
+ </p>
337
+ ),
338
+ })
282
339
  }}
283
340
  />
284
341
  </div>
@@ -385,60 +385,66 @@ export default function EditorNav({
385
385
  <File className="mr-2 h-3 w-3" />
386
386
  View Files
387
387
  </DropdownMenuItem>
388
- <DropdownMenuSub>
389
- <DropdownMenuSubTrigger
390
- className="text-xs"
391
- disabled={isChangingType || hasUnsavedChanges}
392
- >
393
- <Edit2 className="mr-2 h-3 w-3" />
394
- {isChangingType ? "Changing..." : "Change Type"}
395
- </DropdownMenuSubTrigger>
396
- <DropdownMenuSubContent>
388
+ {session?.github_username === pkg.owner_github_username && (
389
+ <>
390
+ <DropdownMenuSub>
391
+ <DropdownMenuSubTrigger
392
+ className="text-xs"
393
+ disabled={isChangingType || hasUnsavedChanges}
394
+ >
395
+ <Edit2 className="mr-2 h-3 w-3" />
396
+ {isChangingType ? "Changing..." : "Change Type"}
397
+ </DropdownMenuSubTrigger>
398
+ <DropdownMenuSubContent>
399
+ <DropdownMenuItem
400
+ className="text-xs"
401
+ disabled={currentType === "board" || isChangingType}
402
+ onClick={() => handleTypeChange("board")}
403
+ >
404
+ Board {currentType === "board" && "✓"}
405
+ </DropdownMenuItem>
406
+ <DropdownMenuItem
407
+ className="text-xs"
408
+ disabled={currentType === "package" || isChangingType}
409
+ onClick={() => handleTypeChange("package")}
410
+ >
411
+ Module {currentType === "package" && "✓"}
412
+ </DropdownMenuItem>
413
+ </DropdownMenuSubContent>
414
+ </DropdownMenuSub>
415
+ <DropdownMenuSub>
416
+ <DropdownMenuSubTrigger className="text-xs">
417
+ <Edit2 className="mr-2 h-3 w-3" />
418
+ Change Package Visibility
419
+ </DropdownMenuSubTrigger>
420
+ <DropdownMenuSubContent>
421
+ <DropdownMenuItem
422
+ className="text-xs"
423
+ disabled={isPrivate}
424
+ onClick={() => updatePackageVisibilityToPrivate(true)}
425
+ >
426
+ Private {isPrivate && "✓"}
427
+ </DropdownMenuItem>
428
+ <DropdownMenuItem
429
+ className="text-xs"
430
+ disabled={!isPrivate}
431
+ onClick={() =>
432
+ updatePackageVisibilityToPrivate(false)
433
+ }
434
+ >
435
+ Public {!isPrivate && "✓"}
436
+ </DropdownMenuItem>
437
+ </DropdownMenuSubContent>
438
+ </DropdownMenuSub>
397
439
  <DropdownMenuItem
398
- className="text-xs"
399
- disabled={currentType === "board" || isChangingType}
400
- onClick={() => handleTypeChange("board")}
440
+ className="text-xs text-red-600"
441
+ onClick={() => openDeleteDialog()}
401
442
  >
402
- Board {currentType === "board" && "✓"}
443
+ <Trash2 className="mr-2 h-3 w-3" />
444
+ Delete Package
403
445
  </DropdownMenuItem>
404
- <DropdownMenuItem
405
- className="text-xs"
406
- disabled={currentType === "package" || isChangingType}
407
- onClick={() => handleTypeChange("package")}
408
- >
409
- Module {currentType === "package" && "✓"}
410
- </DropdownMenuItem>
411
- </DropdownMenuSubContent>
412
- </DropdownMenuSub>
413
- <DropdownMenuSub>
414
- <DropdownMenuSubTrigger className="text-xs">
415
- <Edit2 className="mr-2 h-3 w-3" />
416
- Change Package Visibility
417
- </DropdownMenuSubTrigger>
418
- <DropdownMenuSubContent>
419
- <DropdownMenuItem
420
- className="text-xs"
421
- disabled={isPrivate}
422
- onClick={() => updatePackageVisibilityToPrivate(true)}
423
- >
424
- Private {isPrivate && "✓"}
425
- </DropdownMenuItem>
426
- <DropdownMenuItem
427
- className="text-xs"
428
- disabled={!isPrivate}
429
- onClick={() => updatePackageVisibilityToPrivate(false)}
430
- >
431
- Public {!isPrivate && "✓"}
432
- </DropdownMenuItem>
433
- </DropdownMenuSubContent>
434
- </DropdownMenuSub>
435
- <DropdownMenuItem
436
- className="text-xs text-red-600"
437
- onClick={() => openDeleteDialog()}
438
- >
439
- <Trash2 className="mr-2 h-3 w-3" />
440
- Delete Package
441
- </DropdownMenuItem>
446
+ </>
447
+ )}
442
448
  <DropdownMenuItem className="text-xs text-gray-500" disabled>
443
449
  @tscircuit/core@{tscircuitCorePkg.version}
444
450
  </DropdownMenuItem>
@@ -1,10 +1,10 @@
1
1
  import axios from "redaxios"
2
2
  import { useMemo } from "react"
3
- import { useSnippetsBaseApiUrl } from "./use-snippets-base-api-url"
4
3
  import { useGlobalStore } from "./use-global-store"
4
+ import { usePackagesBaseApiUrl } from "./use-packages-base-api-url"
5
5
 
6
6
  export const useAxios = () => {
7
- const snippetsBaseApiUrl = useSnippetsBaseApiUrl()
7
+ const snippetsBaseApiUrl = usePackagesBaseApiUrl()
8
8
  const session = useGlobalStore((s) => s.session)
9
9
  return useMemo(() => {
10
10
  const instance = axios.create({
@@ -0,0 +1,3 @@
1
+ export const usePackagesBaseApiUrl = () => {
2
+ return import.meta.env.VITE_SNIPPETS_API_URL ?? "/api"
3
+ }
@@ -34,7 +34,7 @@ export const useRequestAiReviewMutation = ({
34
34
  onSuccess: ({ package_release, ai_review }) => {
35
35
  toast({
36
36
  title: "AI review requested",
37
- description: "An AI review has been generated.",
37
+ description: "An AI review has been requested.",
38
38
  })
39
39
  queryClient.invalidateQueries(["packageRelease"])
40
40
  onSuccess?.(package_release, ai_review)
@@ -1,9 +1,9 @@
1
1
  import { useGlobalStore } from "./use-global-store"
2
2
  import { useIsUsingFakeApi } from "./use-is-using-fake-api"
3
- import { useSnippetsBaseApiUrl } from "./use-snippets-base-api-url"
3
+ import { usePackagesBaseApiUrl } from "./use-packages-base-api-url"
4
4
 
5
5
  export const useSignIn = () => {
6
- const snippetsBaseApiUrl = useSnippetsBaseApiUrl()
6
+ const snippetsBaseApiUrl = usePackagesBaseApiUrl()
7
7
  const isUsingFakeApi = useIsUsingFakeApi()
8
8
  const setSession = useGlobalStore((s) => s.setSession)
9
9
  return () => {
@@ -63,6 +63,7 @@ function useToast() {
63
63
  return {
64
64
  toast,
65
65
  dismiss: toastLibrary.dismiss,
66
+ toastLibrary,
66
67
  }
67
68
  }
68
69
 
@@ -20,7 +20,9 @@ import { encodeFsMapToUrlHash } from "@/lib/encodeFsMapToUrlHash"
20
20
 
21
21
  export interface ICreateFileProps {
22
22
  newFileName: string
23
+ content?: string
23
24
  onError: (error: Error) => void
25
+ openFile?: boolean
24
26
  }
25
27
  export interface ICreateFileResult {
26
28
  newFileCreated: boolean
@@ -182,6 +184,8 @@ export function useFileManagement({
182
184
  const createFile = ({
183
185
  newFileName,
184
186
  onError,
187
+ content,
188
+ openFile = true,
185
189
  }: ICreateFileProps): ICreateFileResult => {
186
190
  newFileName = newFileName.trim()
187
191
  if (!newFileName) {
@@ -206,11 +210,12 @@ export function useFileManagement({
206
210
  }
207
211
  const updatedFiles = [
208
212
  ...(localFiles || []),
209
- { path: newFileName, content: "" },
213
+ { path: newFileName, content: content || "" },
210
214
  ]
211
215
  setLocalFiles(updatedFiles)
212
- // immediately select the newly created file
213
- setCurrentFile(newFileName)
216
+ if (openFile) {
217
+ setCurrentFile(newFileName)
218
+ }
214
219
  return {
215
220
  newFileCreated: true,
216
221
  }
package/src/main.tsx CHANGED
@@ -6,9 +6,6 @@ if (typeof window !== "undefined" && !window.__APP_LOADED_AT) {
6
6
  window.__APP_LOADED_AT = Date.now()
7
7
  }
8
8
  import "./index.css"
9
- import { setupBuildWatcher } from "./build-watcher"
10
-
11
- setupBuildWatcher()
12
9
 
13
10
  createRoot(document.getElementById("root")!).render(
14
11
  <StrictMode>
@@ -12,7 +12,7 @@ import { PrefetchPageLink } from "@/components/PrefetchPageLink"
12
12
  import { PackagesList } from "@/components/PackagesList"
13
13
  import { Helmet } from "react-helmet-async"
14
14
  import { useSignIn } from "@/hooks/use-sign-in"
15
- import { useSnippetsBaseApiUrl } from "@/hooks/use-snippets-base-api-url"
15
+ import { usePackagesBaseApiUrl } from "@/hooks/use-packages-base-api-url"
16
16
  import { useConfirmDeletePackageDialog } from "@/components/dialogs/confirm-delete-package-dialog"
17
17
  import { PackageCardSkeleton } from "@/components/PackageCardSkeleton"
18
18
  import { PackageCard } from "@/components/PackageCard"
@@ -81,7 +81,7 @@ export const DashboardPage = () => {
81
81
  },
82
82
  )
83
83
 
84
- const baseUrl = useSnippetsBaseApiUrl()
84
+ const baseUrl = usePackagesBaseApiUrl()
85
85
 
86
86
  const handleDeleteClick = (e: React.MouseEvent, pkg: Package) => {
87
87
  e.preventDefault() // Prevent navigation
@@ -1,10 +1,10 @@
1
1
  import { useGlobalStore } from "@/hooks/use-global-store"
2
- import { useSnippetsBaseApiUrl } from "@/hooks/use-snippets-base-api-url"
2
+ import { usePackagesBaseApiUrl } from "@/hooks/use-packages-base-api-url"
3
3
  import { useState } from "react"
4
4
  import { useLocation } from "wouter"
5
5
 
6
6
  export const DevLoginPage = () => {
7
- const snippetsBaseApiUrl = useSnippetsBaseApiUrl()
7
+ const snippetsBaseApiUrl = usePackagesBaseApiUrl()
8
8
  const [username, setUsername] = useState("")
9
9
  const setSession = useGlobalStore((s) => s.setSession)
10
10
  const [, setLocation] = useLocation()
@@ -6,7 +6,7 @@ import Header from "@/components/Header"
6
6
  import Footer from "@/components/Footer"
7
7
  import { Search, Keyboard, Cpu, Layers, LucideBellElectric } from "lucide-react"
8
8
  import { Input } from "@/components/ui/input"
9
- import { useSnippetsBaseApiUrl } from "@/hooks/use-snippets-base-api-url"
9
+ import { usePackagesBaseApiUrl } from "@/hooks/use-packages-base-api-url"
10
10
  import {
11
11
  Select,
12
12
  SelectContent,
@@ -18,7 +18,7 @@ import PackageSearchResults from "@/components/PackageSearchResults"
18
18
 
19
19
  const LatestPage: React.FC = () => {
20
20
  const axios = useAxios()
21
- const apiBaseUrl = useSnippetsBaseApiUrl()
21
+ const apiBaseUrl = usePackagesBaseApiUrl()
22
22
  const [searchQuery, setSearchQuery] = useState("")
23
23
  const [category, setCategory] = useState("all")
24
24
 
@@ -7,7 +7,7 @@ import Footer from "@/components/Footer"
7
7
  import { Input } from "@/components/ui/input"
8
8
  import { Search } from "lucide-react"
9
9
  import PackageSearchResults from "@/components/PackageSearchResults"
10
- import { useSnippetsBaseApiUrl } from "@/hooks/use-snippets-base-api-url"
10
+ import { usePackagesBaseApiUrl } from "@/hooks/use-packages-base-api-url"
11
11
  import {
12
12
  Select,
13
13
  SelectContent,
@@ -19,7 +19,7 @@ import { Package } from "fake-snippets-api/lib/db/schema"
19
19
 
20
20
  export const SearchPage = () => {
21
21
  const axios = useAxios()
22
- const apiBaseUrl = useSnippetsBaseApiUrl()
22
+ const apiBaseUrl = usePackagesBaseApiUrl()
23
23
  const [searchParams, setSearchParams] = useSearchParams()
24
24
 
25
25
  const [searchQuery, setSearchQuery] = useState(searchParams.get("q") || "")
@@ -4,7 +4,7 @@ import { useAxios } from "@/hooks/use-axios"
4
4
  import Header from "@/components/Header"
5
5
  import Footer from "@/components/Footer"
6
6
  import { useSearchParams } from "wouter"
7
- import { useSnippetsBaseApiUrl } from "@/hooks/use-snippets-base-api-url"
7
+ import { usePackagesBaseApiUrl } from "@/hooks/use-packages-base-api-url"
8
8
  import { Search, Keyboard, Cpu, Layers, LucideBellElectric } from "lucide-react"
9
9
  import { Input } from "@/components/ui/input"
10
10
  import {
@@ -19,7 +19,7 @@ import PackageSearchResults from "@/components/PackageSearchResults"
19
19
 
20
20
  const TrendingPage: React.FC = () => {
21
21
  const axios = useAxios()
22
- const apiBaseUrl = useSnippetsBaseApiUrl()
22
+ const apiBaseUrl = usePackagesBaseApiUrl()
23
23
  const [searchParams, setSearchParams] = useSearchParams()
24
24
 
25
25
  const [searchQuery, setSearchQuery] = useState(searchParams.get("q") || "")