@tscircuit/fake-snippets 0.0.76 → 0.0.78

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.
@@ -18,7 +18,7 @@ function computeDuration(
18
18
  }
19
19
 
20
20
  export const PackageBuildDetailsPage = () => {
21
- const { packageRelease } = useCurrentPackageRelease()
21
+ const { packageRelease } = useCurrentPackageRelease({ include_logs: true })
22
22
  const [openSections, setOpenSections] = useState<Record<string, boolean>>({})
23
23
 
24
24
  const {
@@ -79,8 +79,8 @@ export const PackageBuildDetailsPage = () => {
79
79
  >
80
80
  <LogContent
81
81
  logs={
82
- packageRelease?.transpilation_logs ?? [
83
- { msg: "No transpilation logs available" },
82
+ transpilation_logs ?? [
83
+ { message: "No transpilation logs available" },
84
84
  ]
85
85
  }
86
86
  error={transpilation_error}
@@ -100,8 +100,8 @@ export const PackageBuildDetailsPage = () => {
100
100
  >
101
101
  <LogContent
102
102
  logs={
103
- packageRelease?.circuit_json_build_logs ?? [
104
- { msg: "No Circuit JSON logs available" },
103
+ circuit_json_build_logs ?? [
104
+ { message: "No Circuit JSON logs available" },
105
105
  ]
106
106
  }
107
107
  error={circuit_json_build_error!}
@@ -8,9 +8,9 @@ export const getColorForDisplayStatus = (
8
8
  return "bg-yellow-500"
9
9
  case "building":
10
10
  return "bg-blue-500"
11
- case "successful":
11
+ case "complete":
12
12
  return "bg-green-500"
13
- case "failed":
13
+ case "error":
14
14
  return "bg-red-500"
15
15
  }
16
16
  return "bg-gray-500"
@@ -1,5 +1,4 @@
1
1
  import { Globe, GitBranch, GitCommit, Clock } from "lucide-react"
2
- import { Badge } from "@/components/ui/badge"
3
2
  import { useCurrentPackageRelease } from "@/hooks/use-current-package-release"
4
3
  import { useParams } from "wouter"
5
4
  import { timeAgo } from "@/lib/utils/timeAgo"
@@ -17,9 +16,9 @@ function getColorFromDisplayStatus(
17
16
  return "bg-yellow-500"
18
17
  case "building":
19
18
  return "bg-blue-500"
20
- case "successful":
19
+ case "complete":
21
20
  return "bg-green-500"
22
- case "failed":
21
+ case "error":
23
22
  return "bg-red-500"
24
23
  }
25
24
  }
@@ -67,7 +66,7 @@ export function PackageBuildDetailsPanel() {
67
66
  </div>
68
67
  <span className="text-sm">{author}</span>
69
68
  <span className="text-sm text-gray-500">
70
- {timeAgo(packageRelease?.created_at, "")}
69
+ {timeAgo(created_at, "")}
71
70
  </span>
72
71
  </div>
73
72
  </div>
@@ -66,6 +66,11 @@ export const RenamePackageDialog = ({
66
66
  onChange={(e) => setNewName(e.target.value.replace(" ", "").trim())}
67
67
  placeholder="Enter new name"
68
68
  disabled={renamePackageMutation.isLoading}
69
+ onKeyDown={(e) => {
70
+ if (e.key === "Enter" && !renamePackageMutation.isLoading) {
71
+ renamePackageMutation.mutate()
72
+ }
73
+ }}
69
74
  />
70
75
  <Button
71
76
  disabled={renamePackageMutation.isLoading}
@@ -9,18 +9,15 @@ import { Decoration, hoverTooltip, keymap } from "@codemirror/view"
9
9
  import { getImportsFromCode } from "@tscircuit/prompt-benchmarks/code-runner-utils"
10
10
  import type { ATABootstrapConfig } from "@typescript/ata"
11
11
  import { setupTypeAcquisition } from "@typescript/ata"
12
+ import { linter } from "@codemirror/lint"
12
13
  import { TSCI_PACKAGE_PATTERN } from "@/lib/constants"
13
14
  import {
14
15
  createDefaultMapFromCDN,
15
16
  createSystem,
16
17
  createVirtualTypeScriptEnvironment,
17
18
  } from "@typescript/vfs"
18
- import {
19
- tsAutocomplete,
20
- tsFacet,
21
- tsLinter,
22
- tsSync,
23
- } from "@valtown/codemirror-ts"
19
+ import { tsAutocomplete, tsFacet, tsSync } from "@valtown/codemirror-ts"
20
+ import { getLints } from "@valtown/codemirror-ts"
24
21
  import { EditorView } from "codemirror"
25
22
  import { useEffect, useMemo, useRef, useState } from "react"
26
23
  import tsModule from "typescript"
@@ -75,6 +72,7 @@ export const CodeEditor = ({
75
72
  const editorRef = useRef<HTMLDivElement>(null)
76
73
  const viewRef = useRef<EditorView | null>(null)
77
74
  const ataRef = useRef<ReturnType<typeof setupTypeAcquisition> | null>(null)
75
+ const lastReceivedTsFileTimeRef = useRef<number>(0)
78
76
  const apiUrl = useSnippetsBaseApiUrl()
79
77
  const codeCompletionApi = useCodeCompletionApi()
80
78
  const [cursorPosition, setCursorPosition] = useState<number | null>(null)
@@ -218,16 +216,12 @@ export const CodeEditor = ({
218
216
  receivedFile: (code: string, path: string) => {
219
217
  fsMap.set(path, code)
220
218
  env.createFile(path, code)
221
- if (viewRef.current) {
222
- viewRef.current.dispatch({
223
- changes: {
224
- from: 0,
225
- to: viewRef.current.state.doc.length,
226
- insert: viewRef.current.state.doc.toString(),
227
- },
228
- selection: viewRef.current.state.selection,
229
- })
219
+ if (/\.tsx?$|\.d\.ts$/.test(path)) {
220
+ lastReceivedTsFileTimeRef.current = Date.now()
230
221
  }
222
+ // Avoid dispatching a view update when ATA downloads files. Dispatching
223
+ // here caused the editor to reset the user's selection, which made text
224
+ // selection impossible while dependencies were loading.
231
225
  },
232
226
  },
233
227
  }
@@ -292,7 +286,18 @@ export const CodeEditor = ({
292
286
  : currentFile,
293
287
  }),
294
288
  tsSync(),
295
- tsLinter(),
289
+ linter(async (view) => {
290
+ if (Date.now() - lastReceivedTsFileTimeRef.current < 3000) {
291
+ return []
292
+ }
293
+ const config = view.state.facet(tsFacet)
294
+ return config
295
+ ? getLints({
296
+ ...config,
297
+ diagnosticCodesToIgnore: [],
298
+ })
299
+ : []
300
+ }),
296
301
  autocompletion({ override: [tsAutocomplete()] }),
297
302
  hoverTooltip((view, pos) => {
298
303
  const line = view.state.doc.lineAt(pos)
@@ -386,6 +391,13 @@ export const CodeEditor = ({
386
391
  }
387
392
  return false
388
393
  },
394
+ keydown: (event) => {
395
+ if ((event.metaKey || event.ctrlKey) && event.key === "Enter") {
396
+ event.preventDefault()
397
+ return true
398
+ }
399
+ return false
400
+ },
389
401
  }),
390
402
  EditorView.theme({
391
403
  ".cm-tooltip-hover": {
@@ -3,7 +3,9 @@ import { useCurrentPackageId } from "./use-current-package-id"
3
3
  import { useUrlParams } from "./use-url-params"
4
4
  import { usePackageRelease } from "./use-package-release"
5
5
 
6
- export const useCurrentPackageRelease = () => {
6
+ export const useCurrentPackageRelease = (options?: {
7
+ include_logs: boolean
8
+ }) => {
7
9
  const { packageId } = useCurrentPackageId()
8
10
  const urlParams = useUrlParams()
9
11
  const { author, packageName } = useParams()
@@ -23,6 +25,8 @@ export const useCurrentPackageRelease = () => {
23
25
  query = { package_id: packageId, is_latest: true }
24
26
  }
25
27
 
26
- const { data: packageRelease, ...rest } = usePackageRelease(query)
28
+ const { data: packageRelease, ...rest } = usePackageRelease(query, {
29
+ include_logs: options?.include_logs ?? false,
30
+ })
27
31
  return { packageRelease, ...rest }
28
32
  }
@@ -18,15 +18,28 @@ type PackageReleaseQuery =
18
18
  is_latest: boolean
19
19
  }
20
20
 
21
- export const usePackageRelease = (query: PackageReleaseQuery | null) => {
21
+ export const usePackageRelease = (
22
+ query: PackageReleaseQuery | null,
23
+ options?: { include_logs: boolean },
24
+ ) => {
22
25
  const axios = useAxios()
23
26
 
24
27
  return useQuery<PackageRelease, Error & { status: number }>(
25
- ["packageRelease", query],
28
+ ["packageRelease", query, options?.include_logs],
26
29
  async () => {
27
30
  if (!query) return
28
31
 
29
- const { data } = await axios.post("/package_releases/get", query)
32
+ const { data } = await axios.post(
33
+ "/package_releases/get",
34
+ query,
35
+ options?.include_logs
36
+ ? {
37
+ params: {
38
+ include_logs: true,
39
+ },
40
+ }
41
+ : undefined,
42
+ )
30
43
 
31
44
  if (!data.package_release) {
32
45
  throw new Error("Package release not found")
@@ -4,17 +4,8 @@ import { useAxios } from "@/hooks/use-axios"
4
4
  import { Package } from "fake-snippets-api/lib/db/schema"
5
5
  import Header from "@/components/Header"
6
6
  import Footer from "@/components/Footer"
7
- import {
8
- Search,
9
- Tag,
10
- Calendar,
11
- Keyboard,
12
- Cpu,
13
- Layers,
14
- LucideBellElectric,
15
- } from "lucide-react"
7
+ import { Search, Keyboard, Cpu, Layers, LucideBellElectric } from "lucide-react"
16
8
  import { Input } from "@/components/ui/input"
17
- import { Badge } from "@/components/ui/badge"
18
9
  import { useSnippetsBaseApiUrl } from "@/hooks/use-snippets-base-api-url"
19
10
  import {
20
11
  Select,
@@ -23,8 +14,7 @@ import {
23
14
  SelectTrigger,
24
15
  SelectValue,
25
16
  } from "@/components/ui/select"
26
- import { PackageCardSkeleton } from "@/components/PackageCardSkeleton"
27
- import { PackageCard } from "@/components/PackageCard"
17
+ import PackageSearchResults from "@/components/PackageSearchResults"
28
18
 
29
19
  const LatestPage: React.FC = () => {
30
20
  const axios = useAxios()
@@ -48,22 +38,24 @@ const LatestPage: React.FC = () => {
48
38
  },
49
39
  )
50
40
 
51
- const filteredPackages = packages?.filter((pkg) => {
52
- if (!searchQuery) return true
41
+ const filteredPackages = packages
42
+ ?.filter((pkg) => {
43
+ if (!searchQuery) return true
53
44
 
54
- const query = searchQuery.toLowerCase().trim()
45
+ const query = searchQuery.toLowerCase().trim()
55
46
 
56
- const searchableFields = [
57
- pkg.unscoped_name.toLowerCase(),
58
- pkg.owner_github_username?.toLowerCase() ?? "",
59
- (pkg.description || "").toLowerCase(),
60
- ]
47
+ const searchableFields = [
48
+ pkg.unscoped_name.toLowerCase(),
49
+ pkg.owner_github_username?.toLowerCase() ?? "",
50
+ (pkg.description || "").toLowerCase(),
51
+ ]
61
52
 
62
- return searchableFields.some((field) => {
63
- const queryWords = query.split(/\s+/).filter((word) => word.length > 0)
64
- return queryWords.every((word) => field.includes(word))
53
+ return searchableFields.some((field) => {
54
+ const queryWords = query.split(/\s+/).filter((word) => word.length > 0)
55
+ return queryWords.every((word) => field.includes(word))
56
+ })
65
57
  })
66
- })
58
+ ?.sort((a, b) => b.created_at.localeCompare(a.created_at))
67
59
 
68
60
  return (
69
61
  <div className="min-h-screen flex flex-col bg-gray-50">
@@ -71,7 +63,6 @@ const LatestPage: React.FC = () => {
71
63
  <main className="flex-grow container mx-auto px-4 py-8">
72
64
  <div className="mb-8 max-w-3xl">
73
65
  <div className="flex items-center gap-2 mb-3">
74
- <Calendar className="w-6 h-6 text-blue-500" />
75
66
  <h1 className="text-4xl font-bold text-gray-900">
76
67
  Latest Packages
77
68
  </h1>
@@ -81,16 +72,6 @@ const LatestPage: React.FC = () => {
81
72
  additions showcase new ideas and innovative approaches to circuit
82
73
  design.
83
74
  </p>
84
- <div className="flex flex-wrap gap-3">
85
- <Badge variant="secondary" className="px-3 py-1">
86
- <Tag className="w-3.5 h-3.5 mr-1" />
87
- <span>Latest Uploads</span>
88
- </Badge>
89
- <Badge variant="secondary" className="px-3 py-1">
90
- <Calendar className="w-3.5 h-3.5 mr-1" />
91
- <span>Most Recent First</span>
92
- </Badge>
93
- </div>
94
75
  </div>
95
76
 
96
77
  <div className="mb-6">
@@ -139,58 +120,19 @@ const LatestPage: React.FC = () => {
139
120
  </Select>
140
121
  </div>
141
122
  </div>
142
-
143
- {isLoading ? (
144
- <div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4">
145
- {[...Array(6)].map((_, i) => (
146
- <PackageCardSkeleton key={i} />
147
- ))}
148
- </div>
149
- ) : error ? (
150
- <div className="bg-red-50 border border-red-200 text-red-700 p-6 rounded-xl shadow-sm max-w-2xl mx-auto">
151
- <div className="flex items-start">
152
- <div className="mr-4 bg-red-100 p-2 rounded-full">
153
- <Search className="w-6 h-6 text-red-600" />
154
- </div>
155
- <div>
156
- <h3 className="text-lg font-semibold mb-2">
157
- Error Loading Packages
158
- </h3>
159
- <p className="text-red-600">
160
- We couldn't load the latest packages. Please try again later.
161
- </p>
162
- </div>
163
- </div>
164
- </div>
165
- ) : filteredPackages?.length === 0 ? (
166
- <div className="text-center py-12 px-4">
167
- <div className="bg-slate-50 inline-flex rounded-full p-4 mb-4">
168
- <Search className="w-8 h-8 text-slate-400" />
169
- </div>
170
- <h3 className="text-xl font-medium text-slate-900 mb-2">
171
- No Matching Packages
172
- </h3>
173
- <p className="text-slate-500 max-w-md mx-auto mb-6">
174
- {searchQuery
175
- ? `No packages match your search for "${searchQuery}".`
176
- : category !== "all"
177
- ? `No ${category} packages found in the latest list.`
178
- : "There are no new packages at the moment."}
179
- </p>
180
- </div>
181
- ) : (
182
- <div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4">
183
- {filteredPackages
184
- ?.sort((a, b) => b.created_at.localeCompare(a.created_at))
185
- ?.map((pkg) => (
186
- <PackageCard
187
- key={pkg.package_id}
188
- pkg={pkg}
189
- baseUrl={apiBaseUrl}
190
- />
191
- ))}
192
- </div>
193
- )}
123
+ <PackageSearchResults
124
+ isLoading={isLoading}
125
+ error={error}
126
+ filteredPackages={filteredPackages}
127
+ apiBaseUrl={apiBaseUrl}
128
+ emptyStateMessage={
129
+ searchQuery
130
+ ? `No packages match your search for "${searchQuery}".`
131
+ : category !== "all"
132
+ ? `No ${category} packages found in the latest list.`
133
+ : "There are no new packages at the moment."
134
+ }
135
+ />
194
136
  </main>
195
137
  <Footer />
196
138
  </div>