@tscircuit/fake-snippets 0.0.87 → 0.0.88
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.
- package/bun.lock +4 -4
- package/dist/bundle.js +2 -2
- package/fake-snippets-api/routes/api/package_releases/create.ts +1 -1
- package/package.json +4 -6
- package/src/components/Header.tsx +5 -1
- package/src/components/HeaderLogin.tsx +1 -1
- package/src/components/PrefetchPageLink.tsx +66 -15
- package/src/components/ViewPackagePage/components/important-files-view.tsx +7 -5
- package/src/components/ViewPackagePage/components/main-content-header.tsx +1 -1
- package/src/components/ViewPackagePage/components/repo-page-content.tsx +14 -4
- package/src/components/ViewPackagePage/utils/is-package-file-important.ts +18 -5
- package/src/lib/populate-query-cache-with-ssr-data.ts +31 -37
- package/src/pages/user-profile.tsx +1 -1
|
@@ -28,7 +28,7 @@ export default withRouteSpec({
|
|
|
28
28
|
package_name_with_version,
|
|
29
29
|
} = req.jsonBody
|
|
30
30
|
|
|
31
|
-
if (package_name_with_version && !
|
|
31
|
+
if (package_name_with_version && !package_id) {
|
|
32
32
|
const [packageName, parsedVersion] = package_name_with_version.split("@")
|
|
33
33
|
const pkg = ctx.db.packages.find((p) => p.name === packageName)
|
|
34
34
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tscircuit/fake-snippets",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.88",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
"generate-images": "bun run scripts/generate-image-sizes.ts",
|
|
33
33
|
"generate-sitemap": "bun run scripts/generate-sitemap.ts"
|
|
34
34
|
},
|
|
35
|
-
"
|
|
35
|
+
"devDependencies": {
|
|
36
36
|
"@babel/preset-react": "^7.25.9",
|
|
37
37
|
"@babel/preset-typescript": "^7.26.0",
|
|
38
38
|
"@codemirror/autocomplete": "^6.18.1",
|
|
@@ -136,9 +136,7 @@
|
|
|
136
136
|
"use-mouse-matrix-transform": "^1.3.0",
|
|
137
137
|
"vaul": "^0.9.9",
|
|
138
138
|
"vite-plugin-vercel": "^9.0.4",
|
|
139
|
-
"wouter": "^3.3.5"
|
|
140
|
-
},
|
|
141
|
-
"devDependencies": {
|
|
139
|
+
"wouter": "^3.3.5",
|
|
142
140
|
"@anthropic-ai/sdk": "^0.27.3",
|
|
143
141
|
"@babel/standalone": "^7.26.2",
|
|
144
142
|
"@biomejs/biome": "^1.9.2",
|
|
@@ -147,7 +145,7 @@
|
|
|
147
145
|
"@tscircuit/core": "^0.0.433",
|
|
148
146
|
"@tscircuit/eval": "^0.0.227",
|
|
149
147
|
"@tscircuit/prompt-benchmarks": "^0.0.28",
|
|
150
|
-
"@tscircuit/runframe": "^0.0.
|
|
148
|
+
"@tscircuit/runframe": "^0.0.582",
|
|
151
149
|
"@types/babel__standalone": "^7.1.7",
|
|
152
150
|
"@types/bun": "^1.1.10",
|
|
153
151
|
"@types/country-list": "^2.1.4",
|
|
@@ -168,10 +168,14 @@ export default function Header() {
|
|
|
168
168
|
Docs
|
|
169
169
|
</HeaderButton>
|
|
170
170
|
</li>
|
|
171
|
+
<li>
|
|
172
|
+
<HeaderButton className="w-full justify-start" href="/search">
|
|
173
|
+
Search
|
|
174
|
+
</HeaderButton>
|
|
175
|
+
</li>
|
|
171
176
|
</ul>
|
|
172
177
|
</nav>
|
|
173
178
|
<div className="flex flex-col gap-4">
|
|
174
|
-
<SearchComponent />
|
|
175
179
|
<HeaderDropdown />
|
|
176
180
|
<HeaderLogin />
|
|
177
181
|
</div>
|
|
@@ -43,7 +43,7 @@ export const HeaderLogin = () => {
|
|
|
43
43
|
</AvatarFallback>
|
|
44
44
|
</Avatar>
|
|
45
45
|
</DropdownMenuTrigger>
|
|
46
|
-
<DropdownMenuContent>
|
|
46
|
+
<DropdownMenuContent className="ml-1 md:ml-0 md:mr-1">
|
|
47
47
|
<DropdownMenuItem asChild className="text-gray-500 text-xs" disabled>
|
|
48
48
|
<div>
|
|
49
49
|
AI Usage $
|
|
@@ -1,18 +1,34 @@
|
|
|
1
1
|
import { Link } from "wouter"
|
|
2
2
|
import { useEffect } from "react"
|
|
3
3
|
import { useInView } from "react-intersection-observer"
|
|
4
|
+
import { useQueryClient } from "react-query"
|
|
5
|
+
import { useAxios } from "@/hooks/use-axios"
|
|
4
6
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
7
|
+
// Whitelist of known pages that can be safely prefetched
|
|
8
|
+
const PREFETCHABLE_PAGES = new Set([
|
|
9
|
+
"landing",
|
|
10
|
+
"editor",
|
|
11
|
+
"search",
|
|
12
|
+
"trending",
|
|
13
|
+
"dashboard",
|
|
14
|
+
"latest",
|
|
15
|
+
"settings",
|
|
16
|
+
"quickstart",
|
|
17
|
+
])
|
|
18
|
+
|
|
19
|
+
// Helper to check if a path is a package path (e.g. /username/package-name)
|
|
20
|
+
const isPackagePath = (path: string) => {
|
|
21
|
+
const parts = path.split("/").filter(Boolean)
|
|
22
|
+
return parts.length === 2
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// Helper to check if a path is a user profile path
|
|
26
|
+
const isUserProfilePath = (path: string) => {
|
|
27
|
+
const parts = path.split("/").filter(Boolean)
|
|
28
|
+
return parts.length === 1 && !PREFETCHABLE_PAGES.has(parts[0])
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export const PrefetchPageLink = ({
|
|
16
32
|
href,
|
|
17
33
|
children,
|
|
18
34
|
className,
|
|
@@ -27,13 +43,48 @@ const PrefetchPageLink = ({
|
|
|
27
43
|
triggerOnce: true,
|
|
28
44
|
threshold: 0,
|
|
29
45
|
})
|
|
46
|
+
const queryClient = useQueryClient()
|
|
47
|
+
const axios = useAxios()
|
|
30
48
|
|
|
31
49
|
useEffect(() => {
|
|
32
|
-
if (inView)
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
50
|
+
if (!inView) return
|
|
51
|
+
|
|
52
|
+
const path = href === "/" ? "landing" : href.slice(1)
|
|
53
|
+
if (!path) return
|
|
54
|
+
|
|
55
|
+
// Handle user profile paths
|
|
56
|
+
if (isUserProfilePath(path)) {
|
|
57
|
+
const username = path.split("/")[0]
|
|
58
|
+
// Prefetch user profile data
|
|
59
|
+
queryClient.prefetchQuery(["account", username], async () => {
|
|
60
|
+
const { data } = await axios.post("/accounts/get", {
|
|
61
|
+
github_username: username,
|
|
62
|
+
})
|
|
63
|
+
return data.account
|
|
64
|
+
})
|
|
65
|
+
return
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// Handle package paths
|
|
69
|
+
if (isPackagePath(path)) {
|
|
70
|
+
const [owner, name] = path.split("/")
|
|
71
|
+
const packageName = name.split("#")[0]
|
|
72
|
+
// Prefetch package data
|
|
73
|
+
queryClient.prefetchQuery(
|
|
74
|
+
["package", `${owner}/${packageName}`],
|
|
75
|
+
async () => {
|
|
76
|
+
const { data } = await axios.get("/packages/get", {
|
|
77
|
+
params: { name: `${owner}/${packageName}` },
|
|
78
|
+
})
|
|
79
|
+
return data.package
|
|
80
|
+
},
|
|
81
|
+
)
|
|
82
|
+
return
|
|
83
|
+
}
|
|
36
84
|
|
|
85
|
+
// Handle regular pages
|
|
86
|
+
const pageName = path.split("?")[0]
|
|
87
|
+
if (PREFETCHABLE_PAGES.has(pageName)) {
|
|
37
88
|
import(`@/pages/${pageName}.tsx`).catch((error) => {
|
|
38
89
|
console.error(`Failed to prefetch page module ${pageName}:`, error)
|
|
39
90
|
})
|
|
@@ -213,11 +213,11 @@ export default function ImportantFilesView({
|
|
|
213
213
|
return (
|
|
214
214
|
<div className="mt-4 border border-gray-200 dark:border-[#30363d] rounded-md overflow-hidden">
|
|
215
215
|
<div className="flex items-center pl-2 pr-4 py-2 bg-gray-100 dark:bg-[#161b22] border-b border-gray-200 dark:border-[#30363d]">
|
|
216
|
-
<div className="flex items-center space-x-2 overflow-x-auto no-scrollbar">
|
|
216
|
+
<div className="flex items-center space-x-2 overflow-x-auto no-scrollbar flex-1 min-w-0">
|
|
217
217
|
{/* AI Description Tab */}
|
|
218
218
|
{hasAiContent && (
|
|
219
219
|
<button
|
|
220
|
-
className={`flex items-center px-3 py-1.5 rounded-md text-xs ${
|
|
220
|
+
className={`flex items-center px-3 py-1.5 rounded-md text-xs flex-shrink-0 whitespace-nowrap ${
|
|
221
221
|
activeTab === "ai"
|
|
222
222
|
? "bg-gray-200 dark:bg-[#30363d] font-medium"
|
|
223
223
|
: "text-gray-500 dark:text-[#8b949e] hover:bg-gray-200 dark:hover:bg-[#30363d]"
|
|
@@ -234,7 +234,7 @@ export default function ImportantFilesView({
|
|
|
234
234
|
|
|
235
235
|
{/* AI Review Tab */}
|
|
236
236
|
<button
|
|
237
|
-
className={`flex items-center px-3 py-1.5 rounded-md text-xs ${
|
|
237
|
+
className={`flex items-center px-3 py-1.5 rounded-md text-xs flex-shrink-0 whitespace-nowrap ${
|
|
238
238
|
activeTab === "ai-review"
|
|
239
239
|
? "bg-gray-200 dark:bg-[#30363d] font-medium"
|
|
240
240
|
: "text-gray-500 dark:text-[#8b949e] hover:bg-gray-200 dark:hover:bg-[#30363d]"
|
|
@@ -252,7 +252,7 @@ export default function ImportantFilesView({
|
|
|
252
252
|
{importantFiles.map((file) => (
|
|
253
253
|
<button
|
|
254
254
|
key={file.package_file_id}
|
|
255
|
-
className={`flex items-center px-3 py-1.5 rounded-md text-xs ${
|
|
255
|
+
className={`flex items-center px-3 py-1.5 rounded-md text-xs flex-shrink-0 whitespace-nowrap ${
|
|
256
256
|
activeTab === "file" && activeFilePath === file.file_path
|
|
257
257
|
? "bg-gray-200 dark:bg-[#30363d] font-medium"
|
|
258
258
|
: "text-gray-500 dark:text-[#8b949e] hover:bg-gray-200 dark:hover:bg-[#30363d]"
|
|
@@ -295,7 +295,9 @@ export default function ImportantFilesView({
|
|
|
295
295
|
renderAiContent()
|
|
296
296
|
) : activeTab === "ai-review" ? (
|
|
297
297
|
renderAiReviewContent()
|
|
298
|
-
) : activeFilePath &&
|
|
298
|
+
) : activeFilePath &&
|
|
299
|
+
(activeFilePath.endsWith(".md") ||
|
|
300
|
+
activeFilePath?.toLowerCase().endsWith("readme")) ? (
|
|
299
301
|
<MarkdownViewer markdownContent={activeFileContent} />
|
|
300
302
|
) : activeFilePath &&
|
|
301
303
|
(activeFilePath.endsWith(".js") ||
|
|
@@ -87,7 +87,7 @@ export default function MainContentHeader({
|
|
|
87
87
|
</Button>
|
|
88
88
|
</DropdownMenuTrigger>
|
|
89
89
|
<DropdownMenuContent align="end" className="w-72">
|
|
90
|
-
<DropdownMenuItem asChild>
|
|
90
|
+
<DropdownMenuItem disabled={!Boolean(packageInfo)} asChild>
|
|
91
91
|
<a
|
|
92
92
|
href={`/editor?package_id=${packageInfo?.package_id}`}
|
|
93
93
|
className="cursor-pointer p-2 py-4"
|
|
@@ -12,7 +12,10 @@ import ThreeDView from "./tab-views/3d-view"
|
|
|
12
12
|
import PCBView from "./tab-views/pcb-view"
|
|
13
13
|
import SchematicView from "./tab-views/schematic-view"
|
|
14
14
|
import BOMView from "./tab-views/bom-view"
|
|
15
|
-
import {
|
|
15
|
+
import {
|
|
16
|
+
isPackageFileImportant,
|
|
17
|
+
scorePackageFileImportance,
|
|
18
|
+
} from "../utils/is-package-file-important"
|
|
16
19
|
import Header from "@/components/Header"
|
|
17
20
|
import Footer from "@/components/Footer"
|
|
18
21
|
import PackageHeader from "./package-header"
|
|
@@ -90,9 +93,16 @@ export default function RepoPageContent({
|
|
|
90
93
|
const importantFiles = useMemo(() => {
|
|
91
94
|
if (!packageFiles || !importantFilePaths) return []
|
|
92
95
|
|
|
93
|
-
return packageFiles
|
|
94
|
-
|
|
95
|
-
|
|
96
|
+
return packageFiles
|
|
97
|
+
.filter((file) =>
|
|
98
|
+
importantFilePaths.some((path) => file.file_path.endsWith(path)),
|
|
99
|
+
)
|
|
100
|
+
.sort((a, b) => {
|
|
101
|
+
const aImportance = scorePackageFileImportance(a.file_path)
|
|
102
|
+
const bImportance = scorePackageFileImportance(b.file_path)
|
|
103
|
+
return aImportance - bImportance
|
|
104
|
+
})
|
|
105
|
+
.reverse()
|
|
96
106
|
}, [packageFiles, importantFilePaths])
|
|
97
107
|
|
|
98
108
|
// Generate package name with version for file lookups
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
const importanceMap = {
|
|
2
2
|
"readme.md": 200,
|
|
3
|
+
readme: 200,
|
|
3
4
|
license: 100,
|
|
4
5
|
"license.md": 100,
|
|
5
6
|
"index.ts": 90,
|
|
@@ -7,7 +8,23 @@ const importanceMap = {
|
|
|
7
8
|
"circuit.tsx": 90,
|
|
8
9
|
}
|
|
9
10
|
|
|
10
|
-
|
|
11
|
+
/**
|
|
12
|
+
* Determines if a file is considered "important" for display in the
|
|
13
|
+
* `ImportantFilesView` component.
|
|
14
|
+
*
|
|
15
|
+
* A file is deemed important if it resides in the root directory of the package
|
|
16
|
+
* and has a positive importance score. Nested paths are not considered important.
|
|
17
|
+
*/
|
|
18
|
+
export const isPackageFileImportant = (filePath: string): boolean => {
|
|
19
|
+
const normalized = filePath.replace(/^\.\/?/, "").toLowerCase()
|
|
20
|
+
if (normalized.split("/").length > 1) {
|
|
21
|
+
return false
|
|
22
|
+
}
|
|
23
|
+
return scorePackageFileImportance(filePath) > 0
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// Kept for backward compatibility with older imports
|
|
27
|
+
export const scorePackageFileImportance = (filePath: string): number => {
|
|
11
28
|
const lowerCaseFilePath = filePath.toLowerCase()
|
|
12
29
|
for (const [key, value] of Object.entries(importanceMap)) {
|
|
13
30
|
if (lowerCaseFilePath.endsWith(key)) {
|
|
@@ -16,7 +33,3 @@ export const scorePackageFileImportance = (filePath: string) => {
|
|
|
16
33
|
}
|
|
17
34
|
return 0
|
|
18
35
|
}
|
|
19
|
-
|
|
20
|
-
export const isPackageFileImportant = (filePath: string) => {
|
|
21
|
-
return scorePackageFileImportance(filePath) > 0
|
|
22
|
-
}
|
|
@@ -7,46 +7,40 @@ import type { QueryClient } from "react-query"
|
|
|
7
7
|
export function populateQueryCacheWithSSRData(queryClient: QueryClient) {
|
|
8
8
|
if (typeof window === "undefined") return
|
|
9
9
|
|
|
10
|
-
const
|
|
11
|
-
const
|
|
12
|
-
const
|
|
10
|
+
const windowAny = window as any
|
|
11
|
+
const ssrPackage = windowAny.SSR_PACKAGE
|
|
12
|
+
const ssrPackageRelease = windowAny.SSR_PACKAGE_RELEASE
|
|
13
|
+
const ssrPackageFiles = windowAny.SSR_PACKAGE_FILES
|
|
13
14
|
|
|
14
|
-
if (ssrPackage)
|
|
15
|
-
// Cache package data with all possible query keys
|
|
16
|
-
queryClient.setQueryData(["package", ssrPackage.package_id], ssrPackage)
|
|
17
|
-
queryClient.setQueryData(["package", ssrPackage.name], ssrPackage)
|
|
18
|
-
queryClient.setQueryData(["packages", ssrPackage.package_id], ssrPackage)
|
|
19
|
-
}
|
|
15
|
+
if (!ssrPackage || !ssrPackageRelease) return
|
|
20
16
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
17
|
+
queryClient.setQueryData(["package", ssrPackage.name], ssrPackage)
|
|
18
|
+
queryClient.setQueryData(["packages", ssrPackage.package_id], ssrPackage)
|
|
19
|
+
|
|
20
|
+
queryClient.setQueryData(
|
|
21
|
+
[
|
|
22
|
+
"packageRelease",
|
|
23
|
+
{
|
|
24
|
+
is_latest: true,
|
|
25
|
+
package_name: ssrPackage.name,
|
|
26
|
+
include_ai_review: true,
|
|
27
|
+
},
|
|
28
|
+
],
|
|
29
|
+
ssrPackageRelease,
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
queryClient.setQueryData(
|
|
33
|
+
[
|
|
34
|
+
"packageRelease",
|
|
35
|
+
{ package_release_id: ssrPackageRelease.package_release_id },
|
|
36
|
+
],
|
|
37
|
+
ssrPackageRelease,
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
if (ssrPackageFiles && ssrPackageRelease.package_release_id) {
|
|
30
41
|
queryClient.setQueryData(
|
|
31
|
-
["
|
|
32
|
-
|
|
42
|
+
["packageFiles", ssrPackageRelease.package_release_id],
|
|
43
|
+
ssrPackageFiles,
|
|
33
44
|
)
|
|
34
|
-
if (ssrPackageRelease.package_release_id) {
|
|
35
|
-
queryClient.setQueryData(
|
|
36
|
-
[
|
|
37
|
-
"packageRelease",
|
|
38
|
-
{ package_release_id: ssrPackageRelease.package_release_id },
|
|
39
|
-
],
|
|
40
|
-
ssrPackageRelease,
|
|
41
|
-
)
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
// Cache package files if available
|
|
45
|
-
if (ssrPackageFiles && ssrPackageRelease.package_release_id) {
|
|
46
|
-
queryClient.setQueryData(
|
|
47
|
-
["packageFiles", ssrPackageRelease.package_release_id],
|
|
48
|
-
ssrPackageFiles,
|
|
49
|
-
)
|
|
50
|
-
}
|
|
51
45
|
}
|
|
52
46
|
}
|
|
@@ -55,7 +55,7 @@ export const UserProfilePage = () => {
|
|
|
55
55
|
)
|
|
56
56
|
|
|
57
57
|
// use the username stored in the database so the correct case is displayed
|
|
58
|
-
const githubUsername = account?.account
|
|
58
|
+
const githubUsername = account?.account?.github_username || username
|
|
59
59
|
const isCurrentUserProfile = githubUsername === session?.github_username
|
|
60
60
|
|
|
61
61
|
const { Dialog: DeleteDialog, openDialog: openDeleteDialog } =
|