@tscircuit/fake-snippets 0.0.99 → 0.0.101
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 +302 -808
- package/dist/bundle.js +466 -414
- package/dist/index.d.ts +4 -2
- package/dist/index.js +25 -0
- package/fake-snippets-api/lib/db/db-client.ts +32 -0
- package/fake-snippets-api/routes/api/accounts/search.ts +20 -0
- package/fake-snippets-api/routes/api/packages/create.ts +14 -3
- package/package.json +7 -5
- package/src/App.tsx +58 -2
- package/src/components/CircuitJsonImportDialog.tsx +10 -5
- package/src/components/CmdKMenu.tsx +154 -19
- package/src/components/Header2.tsx +106 -25
- package/src/components/PackageBuildsPage/package-build-header.tsx +19 -15
- package/src/components/ViewPackagePage/components/important-files-view.tsx +304 -172
- package/src/components/ViewPackagePage/components/main-content-header.tsx +2 -2
- package/src/components/ViewPackagePage/components/repo-page-content.tsx +9 -0
- package/src/components/ViewPackagePage/components/sidebar-about-section.tsx +10 -3
- package/src/components/ViewPackagePage/components/sidebar.tsx +3 -1
- package/src/components/dialogs/edit-package-details-dialog.tsx +3 -2
- package/src/components/package-port/CodeAndPreview.tsx +1 -1
- package/src/components/package-port/CodeEditor.tsx +2 -2
- package/src/components/package-port/CodeEditorHeader.tsx +20 -16
- package/src/hooks/use-create-package-mutation.ts +1 -1
- package/src/hooks/useFileManagement.ts +1 -5
- package/src/lib/utils/package-utils.ts +0 -3
- package/src/pages/landing.tsx +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -1073,7 +1073,7 @@ declare const createDatabase: ({ seed }?: {
|
|
|
1073
1073
|
datasheet_pdf_urls: string[] | null;
|
|
1074
1074
|
ai_description: string | null;
|
|
1075
1075
|
}[];
|
|
1076
|
-
}, "addOrder" | "getOrderById" | "getOrderFilesByOrderId" | "addOrderQuote" | "getOrderQuoteById" | "getJlcpcbOrderStatesByOrderId" | "getJlcpcbOrderStepRunsByJlcpcbOrderStateId" | "updateOrder" | "addJlcpcbOrderState" | "updateJlcpcbOrderState" | "addOrderFile" | "getOrderFileById" | "addAccount" | "addAccountPackage" | "getAccountPackageById" | "updateAccountPackage" | "deleteAccountPackage" | "addSnippet" | "getLatestSnippets" | "getTrendingSnippets" | "getPackagesByAuthor" | "getSnippetByAuthorAndName" | "updateSnippet" | "getSnippetById" | "searchSnippets" | "searchPackages" | "deleteSnippet" | "addSession" | "getSessions" | "createLoginPage" | "getLoginPage" | "updateLoginPage" | "getAccount" | "updateAccount" | "createSession" | "addStar" | "removeStar" | "hasStarred" | "addPackage" | "updatePackage" | "getPackageById" | "getPackageReleaseById" | "addPackageRelease" | "updatePackageRelease" | "deletePackageFile" | "addPackageFile" | "updatePackageFile" | "getStarCount" | "getPackageFilesByReleaseId" | "updatePackageReleaseFsSha" | "addAiReview" | "updateAiReview" | "getAiReviewById" | "listAiReviews" | "addDatasheet" | "getDatasheetById" | "getDatasheetByChipName" | "listDatasheets" | "updateDatasheet"> & {
|
|
1076
|
+
}, "addOrder" | "getOrderById" | "getOrderFilesByOrderId" | "addOrderQuote" | "getOrderQuoteById" | "getJlcpcbOrderStatesByOrderId" | "getJlcpcbOrderStepRunsByJlcpcbOrderStateId" | "updateOrder" | "addJlcpcbOrderState" | "updateJlcpcbOrderState" | "addOrderFile" | "getOrderFileById" | "addAccount" | "addAccountPackage" | "getAccountPackageById" | "updateAccountPackage" | "deleteAccountPackage" | "addSnippet" | "getLatestSnippets" | "getTrendingSnippets" | "getPackagesByAuthor" | "getSnippetByAuthorAndName" | "updateSnippet" | "getSnippetById" | "searchSnippets" | "searchPackages" | "searchAccounts" | "deleteSnippet" | "addSession" | "getSessions" | "createLoginPage" | "getLoginPage" | "updateLoginPage" | "getAccount" | "updateAccount" | "createSession" | "addStar" | "removeStar" | "hasStarred" | "addPackage" | "updatePackage" | "getPackageById" | "getPackageReleaseById" | "addPackageRelease" | "updatePackageRelease" | "deletePackageFile" | "addPackageFile" | "updatePackageFile" | "getStarCount" | "getPackageFilesByReleaseId" | "updatePackageReleaseFsSha" | "addAiReview" | "updateAiReview" | "getAiReviewById" | "listAiReviews" | "addDatasheet" | "getDatasheetById" | "getDatasheetByChipName" | "listDatasheets" | "updateDatasheet"> & {
|
|
1077
1077
|
addOrder: (order: Omit<Order, "order_id">) => Order;
|
|
1078
1078
|
getOrderById: (orderId: string) => Order | undefined;
|
|
1079
1079
|
getOrderFilesByOrderId: (orderId: string) => OrderFile[];
|
|
@@ -1121,6 +1121,7 @@ declare const createDatabase: ({ seed }?: {
|
|
|
1121
1121
|
}) => Snippet | undefined;
|
|
1122
1122
|
searchSnippets: (query: string) => Snippet[];
|
|
1123
1123
|
searchPackages: (query: string) => Package[];
|
|
1124
|
+
searchAccounts: (query: string, limit?: number) => Account[];
|
|
1124
1125
|
deleteSnippet: (snippetId: string) => boolean;
|
|
1125
1126
|
addSession: (session: Omit<Session, "session_id">) => Session;
|
|
1126
1127
|
getSessions: ({ account_id, is_cli_session, }: {
|
|
@@ -1426,7 +1427,7 @@ declare const createDatabase: ({ seed }?: {
|
|
|
1426
1427
|
datasheet_pdf_urls: string[] | null;
|
|
1427
1428
|
ai_description: string | null;
|
|
1428
1429
|
}[];
|
|
1429
|
-
}, "addOrder" | "getOrderById" | "getOrderFilesByOrderId" | "addOrderQuote" | "getOrderQuoteById" | "getJlcpcbOrderStatesByOrderId" | "getJlcpcbOrderStepRunsByJlcpcbOrderStateId" | "updateOrder" | "addJlcpcbOrderState" | "updateJlcpcbOrderState" | "addOrderFile" | "getOrderFileById" | "addAccount" | "addAccountPackage" | "getAccountPackageById" | "updateAccountPackage" | "deleteAccountPackage" | "addSnippet" | "getLatestSnippets" | "getTrendingSnippets" | "getPackagesByAuthor" | "getSnippetByAuthorAndName" | "updateSnippet" | "getSnippetById" | "searchSnippets" | "searchPackages" | "deleteSnippet" | "addSession" | "getSessions" | "createLoginPage" | "getLoginPage" | "updateLoginPage" | "getAccount" | "updateAccount" | "createSession" | "addStar" | "removeStar" | "hasStarred" | "addPackage" | "updatePackage" | "getPackageById" | "getPackageReleaseById" | "addPackageRelease" | "updatePackageRelease" | "deletePackageFile" | "addPackageFile" | "updatePackageFile" | "getStarCount" | "getPackageFilesByReleaseId" | "updatePackageReleaseFsSha" | "addAiReview" | "updateAiReview" | "getAiReviewById" | "listAiReviews" | "addDatasheet" | "getDatasheetById" | "getDatasheetByChipName" | "listDatasheets" | "updateDatasheet"> & {
|
|
1430
|
+
}, "addOrder" | "getOrderById" | "getOrderFilesByOrderId" | "addOrderQuote" | "getOrderQuoteById" | "getJlcpcbOrderStatesByOrderId" | "getJlcpcbOrderStepRunsByJlcpcbOrderStateId" | "updateOrder" | "addJlcpcbOrderState" | "updateJlcpcbOrderState" | "addOrderFile" | "getOrderFileById" | "addAccount" | "addAccountPackage" | "getAccountPackageById" | "updateAccountPackage" | "deleteAccountPackage" | "addSnippet" | "getLatestSnippets" | "getTrendingSnippets" | "getPackagesByAuthor" | "getSnippetByAuthorAndName" | "updateSnippet" | "getSnippetById" | "searchSnippets" | "searchPackages" | "searchAccounts" | "deleteSnippet" | "addSession" | "getSessions" | "createLoginPage" | "getLoginPage" | "updateLoginPage" | "getAccount" | "updateAccount" | "createSession" | "addStar" | "removeStar" | "hasStarred" | "addPackage" | "updatePackage" | "getPackageById" | "getPackageReleaseById" | "addPackageRelease" | "updatePackageRelease" | "deletePackageFile" | "addPackageFile" | "updatePackageFile" | "getStarCount" | "getPackageFilesByReleaseId" | "updatePackageReleaseFsSha" | "addAiReview" | "updateAiReview" | "getAiReviewById" | "listAiReviews" | "addDatasheet" | "getDatasheetById" | "getDatasheetByChipName" | "listDatasheets" | "updateDatasheet"> & {
|
|
1430
1431
|
addOrder: (order: Omit<Order, "order_id">) => Order;
|
|
1431
1432
|
getOrderById: (orderId: string) => Order | undefined;
|
|
1432
1433
|
getOrderFilesByOrderId: (orderId: string) => OrderFile[];
|
|
@@ -1474,6 +1475,7 @@ declare const createDatabase: ({ seed }?: {
|
|
|
1474
1475
|
}) => Snippet | undefined;
|
|
1475
1476
|
searchSnippets: (query: string) => Snippet[];
|
|
1476
1477
|
searchPackages: (query: string) => Package[];
|
|
1478
|
+
searchAccounts: (query: string, limit?: number) => Account[];
|
|
1477
1479
|
deleteSnippet: (snippetId: string) => boolean;
|
|
1478
1480
|
addSession: (session: Omit<Session, "session_id">) => Session;
|
|
1479
1481
|
getSessions: ({ account_id, is_cli_session, }: {
|
package/dist/index.js
CHANGED
|
@@ -2798,6 +2798,31 @@ var initializer = combine(databaseSchema.parse({}), (set, get) => ({
|
|
|
2798
2798
|
];
|
|
2799
2799
|
return matchingPackages;
|
|
2800
2800
|
},
|
|
2801
|
+
searchAccounts: (query, limit) => {
|
|
2802
|
+
const state = get();
|
|
2803
|
+
const lowercaseQuery = query.toLowerCase();
|
|
2804
|
+
const accountsWithPublicPackages = /* @__PURE__ */ new Set();
|
|
2805
|
+
state.packages.filter((pkg) => pkg.is_public === true).forEach((pkg) => {
|
|
2806
|
+
if (pkg.creator_account_id) {
|
|
2807
|
+
accountsWithPublicPackages.add(pkg.creator_account_id);
|
|
2808
|
+
}
|
|
2809
|
+
if (pkg.owner_github_username) {
|
|
2810
|
+
const account = state.accounts.find(
|
|
2811
|
+
(acc) => acc.github_username === pkg.owner_github_username
|
|
2812
|
+
);
|
|
2813
|
+
if (account) {
|
|
2814
|
+
accountsWithPublicPackages.add(account.account_id);
|
|
2815
|
+
}
|
|
2816
|
+
}
|
|
2817
|
+
});
|
|
2818
|
+
const matchingAccounts = state.accounts.filter((account) => {
|
|
2819
|
+
if (!accountsWithPublicPackages.has(account.account_id)) {
|
|
2820
|
+
return false;
|
|
2821
|
+
}
|
|
2822
|
+
return account.github_username.toLowerCase().includes(lowercaseQuery);
|
|
2823
|
+
}).slice(0, limit || 50);
|
|
2824
|
+
return matchingAccounts;
|
|
2825
|
+
},
|
|
2801
2826
|
deleteSnippet: (snippetId) => {
|
|
2802
2827
|
let deleted = false;
|
|
2803
2828
|
set((state) => {
|
|
@@ -1019,6 +1019,38 @@ const initializer = combine(databaseSchema.parse({}), (set, get) => ({
|
|
|
1019
1019
|
|
|
1020
1020
|
return matchingPackages
|
|
1021
1021
|
},
|
|
1022
|
+
searchAccounts: (query: string, limit?: number): Account[] => {
|
|
1023
|
+
const state = get()
|
|
1024
|
+
const lowercaseQuery = query.toLowerCase()
|
|
1025
|
+
|
|
1026
|
+
const accountsWithPublicPackages = new Set<string>()
|
|
1027
|
+
state.packages
|
|
1028
|
+
.filter((pkg) => pkg.is_public === true)
|
|
1029
|
+
.forEach((pkg) => {
|
|
1030
|
+
if (pkg.creator_account_id) {
|
|
1031
|
+
accountsWithPublicPackages.add(pkg.creator_account_id)
|
|
1032
|
+
}
|
|
1033
|
+
if (pkg.owner_github_username) {
|
|
1034
|
+
const account = state.accounts.find(
|
|
1035
|
+
(acc) => acc.github_username === pkg.owner_github_username,
|
|
1036
|
+
)
|
|
1037
|
+
if (account) {
|
|
1038
|
+
accountsWithPublicPackages.add(account.account_id)
|
|
1039
|
+
}
|
|
1040
|
+
}
|
|
1041
|
+
})
|
|
1042
|
+
|
|
1043
|
+
const matchingAccounts = state.accounts
|
|
1044
|
+
.filter((account) => {
|
|
1045
|
+
if (!accountsWithPublicPackages.has(account.account_id)) {
|
|
1046
|
+
return false
|
|
1047
|
+
}
|
|
1048
|
+
return account.github_username.toLowerCase().includes(lowercaseQuery)
|
|
1049
|
+
})
|
|
1050
|
+
.slice(0, limit || 50)
|
|
1051
|
+
|
|
1052
|
+
return matchingAccounts
|
|
1053
|
+
},
|
|
1022
1054
|
deleteSnippet: (snippetId: string): boolean => {
|
|
1023
1055
|
let deleted = false
|
|
1024
1056
|
set((state) => {
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { withRouteSpec } from "fake-snippets-api/lib/middleware/with-winter-spec"
|
|
2
|
+
import { z } from "zod"
|
|
3
|
+
import { accountSchema } from "fake-snippets-api/lib/db/schema"
|
|
4
|
+
|
|
5
|
+
export default withRouteSpec({
|
|
6
|
+
methods: ["POST"],
|
|
7
|
+
auth: "session",
|
|
8
|
+
jsonBody: z.object({
|
|
9
|
+
query: z.string(),
|
|
10
|
+
limit: z.number().optional().default(50),
|
|
11
|
+
}),
|
|
12
|
+
jsonResponse: z.object({
|
|
13
|
+
ok: z.boolean(),
|
|
14
|
+
accounts: z.array(accountSchema),
|
|
15
|
+
}),
|
|
16
|
+
})(async (req, ctx) => {
|
|
17
|
+
const { query, limit } = req.jsonBody
|
|
18
|
+
const accounts = ctx.db.searchAccounts(query, limit)
|
|
19
|
+
return ctx.json({ accounts, ok: true })
|
|
20
|
+
})
|
|
@@ -13,7 +13,8 @@ export default withRouteSpec({
|
|
|
13
13
|
/^[@a-zA-Z0-9-_\/]+$/,
|
|
14
14
|
"Package name can only contain letters, numbers, hyphens, underscores, and forward slashes",
|
|
15
15
|
)
|
|
16
|
-
.transform((name) => name.replace(/^@/, ""))
|
|
16
|
+
.transform((name) => name.replace(/^@/, ""))
|
|
17
|
+
.optional(),
|
|
17
18
|
description: z.string().optional(),
|
|
18
19
|
is_private: z.boolean().optional().default(false),
|
|
19
20
|
is_unlisted: z.boolean().optional().default(false),
|
|
@@ -33,10 +34,20 @@ export default withRouteSpec({
|
|
|
33
34
|
})
|
|
34
35
|
}
|
|
35
36
|
|
|
36
|
-
|
|
37
|
+
let unscoped_name = name?.includes("/") ? name?.split("/")[1] : name
|
|
38
|
+
if (!unscoped_name) {
|
|
39
|
+
const state = ctx.db.getState()
|
|
40
|
+
const count = state.packages.filter(
|
|
41
|
+
(pkg) => pkg.creator_account_id === ctx.auth.account_id,
|
|
42
|
+
).length
|
|
43
|
+
|
|
44
|
+
unscoped_name = `untitled-package-${count}`
|
|
45
|
+
}
|
|
37
46
|
|
|
38
47
|
const newPackage = ctx.db.addPackage({
|
|
39
|
-
name
|
|
48
|
+
name: name?.includes("/")
|
|
49
|
+
? name
|
|
50
|
+
: `${ctx.auth.github_username}/${String(unscoped_name)}`,
|
|
40
51
|
description: description ?? null,
|
|
41
52
|
creator_account_id: ctx.auth.account_id,
|
|
42
53
|
owner_org_id: ctx.auth.personal_org_id,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tscircuit/fake-snippets",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.101",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -83,7 +83,7 @@
|
|
|
83
83
|
"@tscircuit/mm": "^0.0.8",
|
|
84
84
|
"@tscircuit/pcb-viewer": "^1.11.194",
|
|
85
85
|
"@tscircuit/prompt-benchmarks": "^0.0.28",
|
|
86
|
-
"@tscircuit/runframe": "0.0.
|
|
86
|
+
"@tscircuit/runframe": "0.0.736",
|
|
87
87
|
"@tscircuit/schematic-viewer": "^2.0.21",
|
|
88
88
|
"@types/babel__standalone": "^7.1.7",
|
|
89
89
|
"@types/bun": "^1.1.10",
|
|
@@ -105,9 +105,10 @@
|
|
|
105
105
|
"autoprefixer": "^10.4.20",
|
|
106
106
|
"change-case": "^5.4.4",
|
|
107
107
|
"circuit-json-to-bom-csv": "^0.0.7",
|
|
108
|
-
"circuit-json-to-gerber": "^0.0.
|
|
108
|
+
"circuit-json-to-gerber": "^0.0.29",
|
|
109
109
|
"circuit-json-to-pnp-csv": "^0.0.7",
|
|
110
110
|
"circuit-json-to-readable-netlist": "^0.0.13",
|
|
111
|
+
"circuit-json-to-spice": "^0.0.6",
|
|
111
112
|
"circuit-json-to-tscircuit": "^0.0.4",
|
|
112
113
|
"circuit-to-svg": "^0.0.167",
|
|
113
114
|
"class-variance-authority": "^0.7.1",
|
|
@@ -138,6 +139,7 @@
|
|
|
138
139
|
"ky": "^1.7.5",
|
|
139
140
|
"lucide-react": "^0.488.0",
|
|
140
141
|
"lz-string": "^1.5.0",
|
|
142
|
+
"marked": "^16.1.1",
|
|
141
143
|
"md5": "^2.3.0",
|
|
142
144
|
"ms": "^2.1.3",
|
|
143
145
|
"next-themes": "^0.3.0",
|
|
@@ -150,6 +152,7 @@
|
|
|
150
152
|
"react-cookie-consent": "^9.0.0",
|
|
151
153
|
"react-day-picker": "8.10.1",
|
|
152
154
|
"react-dom": "^18.3.1",
|
|
155
|
+
"react-error-boundary": "^6.0.0",
|
|
153
156
|
"react-helmet": "^6.1.0",
|
|
154
157
|
"react-helmet-async": "^2.0.5",
|
|
155
158
|
"react-hook-form": "^7.53.0",
|
|
@@ -187,7 +190,6 @@
|
|
|
187
190
|
"wouter": "^3.3.5",
|
|
188
191
|
"zod": "^3.23.8",
|
|
189
192
|
"zustand": "^4.5.5",
|
|
190
|
-
"zustand-hoist": "^2.0.1"
|
|
191
|
-
"circuit-json-to-spice": "^0.0.6"
|
|
193
|
+
"zustand-hoist": "^2.0.1"
|
|
192
194
|
}
|
|
193
195
|
}
|
package/src/App.tsx
CHANGED
|
@@ -3,6 +3,8 @@ import { Route, Switch } from "wouter"
|
|
|
3
3
|
import "./components/CmdKMenu"
|
|
4
4
|
import { ContextProviders } from "./ContextProviders"
|
|
5
5
|
import React from "react"
|
|
6
|
+
import { ReloadIcon } from "@radix-ui/react-icons"
|
|
7
|
+
import { Loader2 } from "lucide-react"
|
|
6
8
|
|
|
7
9
|
const FullPageLoader = () => (
|
|
8
10
|
<div className="fixed inset-0 flex items-center justify-center bg-white z-50">
|
|
@@ -163,10 +165,64 @@ class ErrorBoundary extends React.Component<
|
|
|
163
165
|
|
|
164
166
|
render() {
|
|
165
167
|
if (this.state.reloading) {
|
|
166
|
-
return
|
|
168
|
+
return (
|
|
169
|
+
<div className="min-h-screen flex items-center justify-center bg-gray-50 dark:bg-gray-900 px-4">
|
|
170
|
+
<div className="max-w-md w-full text-center">
|
|
171
|
+
<div className="mb-6">
|
|
172
|
+
<div className="inline-flex items-center justify-center w-16 h-16 bg-blue-100 dark:bg-blue-900 rounded-full mb-4">
|
|
173
|
+
<Loader2 className="w-8 h-8 text-blue-600 dark:text-blue-400 animate-spin" />
|
|
174
|
+
</div>
|
|
175
|
+
<h2 className="text-xl font-semibold text-gray-900 dark:text-white mb-2">
|
|
176
|
+
Reloading Page
|
|
177
|
+
</h2>
|
|
178
|
+
<p className="text-gray-600 dark:text-gray-400">
|
|
179
|
+
We encountered an issue and are refreshing the page for you.
|
|
180
|
+
</p>
|
|
181
|
+
</div>
|
|
182
|
+
</div>
|
|
183
|
+
</div>
|
|
184
|
+
)
|
|
167
185
|
}
|
|
168
186
|
if (this.state.hasError) {
|
|
169
|
-
return
|
|
187
|
+
return (
|
|
188
|
+
<div className="min-h-screen flex items-center justify-center bg-gray-50 dark:bg-gray-900 px-4">
|
|
189
|
+
<div className="max-w-lg w-full text-center">
|
|
190
|
+
<div className="mb-8">
|
|
191
|
+
<div className="inline-flex items-center justify-center w-20 h-20 bg-red-100 dark:bg-red-900 rounded-full mb-6">
|
|
192
|
+
<svg
|
|
193
|
+
className="w-10 h-10 text-red-600 dark:text-red-400"
|
|
194
|
+
fill="none"
|
|
195
|
+
stroke="currentColor"
|
|
196
|
+
viewBox="0 0 24 24"
|
|
197
|
+
>
|
|
198
|
+
<path
|
|
199
|
+
strokeLinecap="round"
|
|
200
|
+
strokeLinejoin="round"
|
|
201
|
+
strokeWidth={2}
|
|
202
|
+
d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-2.5L13.732 4c-.77-.833-1.964-.833-2.732 0L3.732 16.5c-.77.833.192 2.5 1.732 2.5z"
|
|
203
|
+
/>
|
|
204
|
+
</svg>
|
|
205
|
+
</div>
|
|
206
|
+
<h1 className="text-2xl font-bold text-gray-900 dark:text-white mb-3">
|
|
207
|
+
Oops! Something went wrong
|
|
208
|
+
</h1>
|
|
209
|
+
<p className="text-gray-600 dark:text-gray-400 mb-6">
|
|
210
|
+
We're experiencing technical difficulties. The page will
|
|
211
|
+
automatically reload when you return to this tab.
|
|
212
|
+
</p>
|
|
213
|
+
</div>
|
|
214
|
+
<div className="space-y-3">
|
|
215
|
+
<button
|
|
216
|
+
onClick={this.performReload}
|
|
217
|
+
className="w-full sm:w-auto inline-flex items-center justify-center px-6 py-2 border border-transparent text-base font-medium rounded-lg text-white bg-red-600 hover:bg-red-700 dark:bg-red-500 dark:hover:bg-red-600 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-red-500 transition-colors duration-200"
|
|
218
|
+
>
|
|
219
|
+
<ReloadIcon className="w-4 h-4 mr-2" />
|
|
220
|
+
Reload Now
|
|
221
|
+
</button>
|
|
222
|
+
</div>
|
|
223
|
+
</div>
|
|
224
|
+
</div>
|
|
225
|
+
)
|
|
170
226
|
}
|
|
171
227
|
return this.props.children
|
|
172
228
|
}
|
|
@@ -15,7 +15,6 @@ import { useLocation } from "wouter"
|
|
|
15
15
|
import { useGlobalStore } from "@/hooks/use-global-store"
|
|
16
16
|
import { convertCircuitJsonToTscircuit } from "circuit-json-to-tscircuit"
|
|
17
17
|
import { useCreatePackageMutation } from "@/hooks/use-create-package-mutation"
|
|
18
|
-
import { generateRandomPackageName } from "@/lib/utils/package-utils"
|
|
19
18
|
import { useCreatePackageReleaseMutation } from "@/hooks/use-create-package-release-mutation"
|
|
20
19
|
import { useCreatePackageFilesMutation } from "@/hooks/use-create-package-files-mutation"
|
|
21
20
|
|
|
@@ -67,10 +66,17 @@ export function CircuitJsonImportDialog({
|
|
|
67
66
|
|
|
68
67
|
const handleFileChange = async (e: React.ChangeEvent<HTMLInputElement>) => {
|
|
69
68
|
const selectedFile = e.target.files?.[0]
|
|
70
|
-
if (selectedFile
|
|
71
|
-
|
|
69
|
+
if (selectedFile) {
|
|
70
|
+
try {
|
|
71
|
+
const fileText = await selectedFile.text()
|
|
72
|
+
JSON.parse(fileText)
|
|
73
|
+
setFile(selectedFile)
|
|
74
|
+
setError(null)
|
|
75
|
+
} catch (e) {
|
|
76
|
+
setError("Please select a valid JSON file that can be parsed.")
|
|
77
|
+
}
|
|
72
78
|
} else {
|
|
73
|
-
setError("Please select a
|
|
79
|
+
setError("Please select a file.")
|
|
74
80
|
}
|
|
75
81
|
}
|
|
76
82
|
|
|
@@ -124,7 +130,6 @@ export function CircuitJsonImportDialog({
|
|
|
124
130
|
|
|
125
131
|
await createPackageMutation.mutateAsync(
|
|
126
132
|
{
|
|
127
|
-
name: `${loggedInUser?.github_username}/${generateRandomPackageName()}`,
|
|
128
133
|
description: "Imported from Circuit JSON",
|
|
129
134
|
},
|
|
130
135
|
{
|
|
@@ -5,7 +5,7 @@ import { useHotkeyCombo } from "@/hooks/use-hotkey"
|
|
|
5
5
|
import { useNotImplementedToast } from "@/hooks/use-toast"
|
|
6
6
|
import { fuzzyMatch } from "@/components/ViewPackagePage/utils/fuzz-search"
|
|
7
7
|
import { Command } from "cmdk"
|
|
8
|
-
import { Package } from "fake-snippets-api/lib/db/schema"
|
|
8
|
+
import { Package, Account } from "fake-snippets-api/lib/db/schema"
|
|
9
9
|
import React, { useCallback, useEffect, useMemo, useRef } from "react"
|
|
10
10
|
import { useQuery } from "react-query"
|
|
11
11
|
import {
|
|
@@ -16,6 +16,8 @@ import {
|
|
|
16
16
|
Sparkles,
|
|
17
17
|
Clock,
|
|
18
18
|
ArrowRight,
|
|
19
|
+
Star,
|
|
20
|
+
User,
|
|
19
21
|
} from "lucide-react"
|
|
20
22
|
import { DialogTitle, DialogDescription } from "@/components/ui/dialog"
|
|
21
23
|
|
|
@@ -40,6 +42,11 @@ interface ScoredPackage extends Package {
|
|
|
40
42
|
matches: number[]
|
|
41
43
|
}
|
|
42
44
|
|
|
45
|
+
interface ScoredAccount extends Account {
|
|
46
|
+
score: number
|
|
47
|
+
matches: number[]
|
|
48
|
+
}
|
|
49
|
+
|
|
43
50
|
const CmdKMenu = () => {
|
|
44
51
|
const [open, setOpen] = React.useState(false)
|
|
45
52
|
const [searchQuery, setSearchQuery] = React.useState("")
|
|
@@ -113,13 +120,42 @@ const CmdKMenu = () => {
|
|
|
113
120
|
["packageSearch", searchQuery],
|
|
114
121
|
async () => {
|
|
115
122
|
if (!searchQuery) return []
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
123
|
+
try {
|
|
124
|
+
const { data } = await axios.post("/packages/search", {
|
|
125
|
+
query: searchQuery,
|
|
126
|
+
})
|
|
127
|
+
return data.packages || []
|
|
128
|
+
} catch (error) {
|
|
129
|
+
console.warn("Failed to fetch packages:", error)
|
|
130
|
+
return []
|
|
131
|
+
}
|
|
120
132
|
},
|
|
121
133
|
{
|
|
122
134
|
enabled: Boolean(searchQuery),
|
|
135
|
+
retry: false,
|
|
136
|
+
refetchOnWindowFocus: false,
|
|
137
|
+
},
|
|
138
|
+
)
|
|
139
|
+
|
|
140
|
+
const { data: allAccounts = [], isLoading: isSearchingAccounts } = useQuery(
|
|
141
|
+
["accountSearch", searchQuery],
|
|
142
|
+
async () => {
|
|
143
|
+
if (!searchQuery) return []
|
|
144
|
+
try {
|
|
145
|
+
const { data } = await axios.post("/accounts/search", {
|
|
146
|
+
query: searchQuery,
|
|
147
|
+
limit: 5,
|
|
148
|
+
})
|
|
149
|
+
return data.accounts || []
|
|
150
|
+
} catch (error) {
|
|
151
|
+
console.warn("Failed to fetch accounts:", error)
|
|
152
|
+
return []
|
|
153
|
+
}
|
|
154
|
+
},
|
|
155
|
+
{
|
|
156
|
+
enabled: Boolean(searchQuery) && Boolean(currentUser),
|
|
157
|
+
retry: false,
|
|
158
|
+
refetchOnWindowFocus: false,
|
|
123
159
|
},
|
|
124
160
|
)
|
|
125
161
|
|
|
@@ -133,20 +169,43 @@ const CmdKMenu = () => {
|
|
|
133
169
|
})
|
|
134
170
|
.filter((pkg: ScoredPackage) => pkg.score >= 0)
|
|
135
171
|
.sort((a: ScoredPackage, b: ScoredPackage) => b.score - a.score)
|
|
136
|
-
.slice(0,
|
|
172
|
+
.slice(0, 6)
|
|
137
173
|
}, [allPackages, searchQuery])
|
|
138
174
|
|
|
175
|
+
const accountSearchResults = useMemo((): ScoredAccount[] => {
|
|
176
|
+
if (!searchQuery || !allAccounts.length) return []
|
|
177
|
+
|
|
178
|
+
return allAccounts
|
|
179
|
+
.map((account: Account) => {
|
|
180
|
+
const { score, matches } = fuzzyMatch(
|
|
181
|
+
searchQuery,
|
|
182
|
+
account.github_username,
|
|
183
|
+
)
|
|
184
|
+
return { ...account, score, matches }
|
|
185
|
+
})
|
|
186
|
+
.filter((account: ScoredAccount) => account.score >= 0)
|
|
187
|
+
.sort((a: ScoredAccount, b: ScoredAccount) => b.score - a.score)
|
|
188
|
+
.slice(0, 5)
|
|
189
|
+
}, [allAccounts, searchQuery])
|
|
190
|
+
|
|
139
191
|
const { data: recentPackages = [] } = useQuery<Package[]>(
|
|
140
192
|
["userPackages", currentUser],
|
|
141
193
|
async () => {
|
|
142
194
|
if (!currentUser) return []
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
195
|
+
try {
|
|
196
|
+
const response = await axios.post(`/packages/list`, {
|
|
197
|
+
owner_github_username: currentUser,
|
|
198
|
+
})
|
|
199
|
+
return response.data.packages || []
|
|
200
|
+
} catch (error) {
|
|
201
|
+
console.warn("Failed to fetch recent packages:", error)
|
|
202
|
+
return []
|
|
203
|
+
}
|
|
147
204
|
},
|
|
148
205
|
{
|
|
149
206
|
enabled: !!currentUser && !searchQuery,
|
|
207
|
+
retry: false,
|
|
208
|
+
refetchOnWindowFocus: false,
|
|
150
209
|
},
|
|
151
210
|
)
|
|
152
211
|
|
|
@@ -195,7 +254,7 @@ const CmdKMenu = () => {
|
|
|
195
254
|
|
|
196
255
|
const allItems = useMemo(() => {
|
|
197
256
|
const items: Array<{
|
|
198
|
-
type: "package" | "recent" | "template" | "blank" | "import"
|
|
257
|
+
type: "package" | "account" | "recent" | "template" | "blank" | "import"
|
|
199
258
|
item: any
|
|
200
259
|
disabled?: boolean
|
|
201
260
|
}> = []
|
|
@@ -206,6 +265,12 @@ const CmdKMenu = () => {
|
|
|
206
265
|
})
|
|
207
266
|
}
|
|
208
267
|
|
|
268
|
+
if (searchQuery && accountSearchResults.length > 0) {
|
|
269
|
+
accountSearchResults.forEach((account) => {
|
|
270
|
+
items.push({ type: "account", item: account })
|
|
271
|
+
})
|
|
272
|
+
}
|
|
273
|
+
|
|
209
274
|
if (!searchQuery && recentPackages.length > 0) {
|
|
210
275
|
recentPackages.slice(0, 6).forEach((pkg) => {
|
|
211
276
|
items.push({ type: "recent", item: pkg })
|
|
@@ -225,7 +290,13 @@ const CmdKMenu = () => {
|
|
|
225
290
|
})
|
|
226
291
|
|
|
227
292
|
return items
|
|
228
|
-
}, [
|
|
293
|
+
}, [
|
|
294
|
+
searchQuery,
|
|
295
|
+
searchResults,
|
|
296
|
+
accountSearchResults,
|
|
297
|
+
recentPackages,
|
|
298
|
+
filteredStaticOptions,
|
|
299
|
+
])
|
|
229
300
|
|
|
230
301
|
useHotkeyCombo("cmd+k", () => {
|
|
231
302
|
setOpen((prev) => !prev)
|
|
@@ -285,6 +356,10 @@ const CmdKMenu = () => {
|
|
|
285
356
|
window.location.href = `/${item.owner_github_username}/${item.unscoped_name}`
|
|
286
357
|
setOpen(false)
|
|
287
358
|
break
|
|
359
|
+
case "account":
|
|
360
|
+
window.location.href = `/${item.github_username}`
|
|
361
|
+
setOpen(false)
|
|
362
|
+
break
|
|
288
363
|
case "blank":
|
|
289
364
|
case "template":
|
|
290
365
|
if (!item.disabled) {
|
|
@@ -362,7 +437,11 @@ const CmdKMenu = () => {
|
|
|
362
437
|
)}
|
|
363
438
|
</div>
|
|
364
439
|
</div>
|
|
365
|
-
<div className="flex items-center gap-
|
|
440
|
+
<div className="flex items-center gap-2 flex-shrink-0">
|
|
441
|
+
<div className="flex items-center gap-1 text-gray-500">
|
|
442
|
+
<Star className="w-3 h-3 fill-yellow-400 text-yellow-400" />
|
|
443
|
+
<span className="text-xs">{data.star_count ?? 0}</span>
|
|
444
|
+
</div>
|
|
366
445
|
<span className="text-xs text-gray-500 bg-gray-100 px-1.5 py-0.5 rounded">
|
|
367
446
|
package
|
|
368
447
|
</span>
|
|
@@ -371,6 +450,41 @@ const CmdKMenu = () => {
|
|
|
371
450
|
</div>
|
|
372
451
|
)
|
|
373
452
|
|
|
453
|
+
case "account":
|
|
454
|
+
return (
|
|
455
|
+
<div
|
|
456
|
+
key={`account-${data.account_id}`}
|
|
457
|
+
ref={isSelected ? selectedItemRef : null}
|
|
458
|
+
className={baseClasses}
|
|
459
|
+
onClick={() => !disabled && handleItemSelect(item)}
|
|
460
|
+
>
|
|
461
|
+
<div className="flex items-center gap-2 min-w-0">
|
|
462
|
+
<img
|
|
463
|
+
src={`https://github.com/${data.github_username}.png`}
|
|
464
|
+
alt={`${data.github_username} avatar`}
|
|
465
|
+
className="w-6 h-6 rounded-full flex-shrink-0"
|
|
466
|
+
onError={(e) => {
|
|
467
|
+
const target = e.target as HTMLImageElement
|
|
468
|
+
target.style.display = "none"
|
|
469
|
+
target.nextElementSibling?.classList.remove("hidden")
|
|
470
|
+
}}
|
|
471
|
+
/>
|
|
472
|
+
<User className="w-6 h-6 text-gray-400 flex-shrink-0 hidden" />
|
|
473
|
+
<div className="flex flex-col min-w-0">
|
|
474
|
+
<span className="font-medium text-gray-900 truncate">
|
|
475
|
+
{renderHighlighted(data, data.github_username)}
|
|
476
|
+
</span>
|
|
477
|
+
</div>
|
|
478
|
+
</div>
|
|
479
|
+
<div className="flex items-center gap-1 flex-shrink-0">
|
|
480
|
+
<span className="text-xs text-gray-500 bg-gray-100 px-1.5 py-0.5 rounded">
|
|
481
|
+
user
|
|
482
|
+
</span>
|
|
483
|
+
{isSelected && <ArrowRight className="w-3 h-3 text-gray-400" />}
|
|
484
|
+
</div>
|
|
485
|
+
</div>
|
|
486
|
+
)
|
|
487
|
+
|
|
374
488
|
case "blank":
|
|
375
489
|
case "template":
|
|
376
490
|
return (
|
|
@@ -464,7 +578,7 @@ const CmdKMenu = () => {
|
|
|
464
578
|
</div>
|
|
465
579
|
|
|
466
580
|
<Command.List className="max-h-80 overflow-y-auto p-2 space-y-4">
|
|
467
|
-
{isSearching ? (
|
|
581
|
+
{isSearching || isSearchingAccounts ? (
|
|
468
582
|
<Command.Loading className="p-6 text-center text-gray-500">
|
|
469
583
|
<div className="flex items-center justify-center gap-2">
|
|
470
584
|
<div className="w-3 h-3 border-2 border-gray-300 border-t-gray-600 rounded-full animate-spin"></div>
|
|
@@ -476,7 +590,7 @@ const CmdKMenu = () => {
|
|
|
476
590
|
{searchQuery && searchResults.length > 0 && (
|
|
477
591
|
<div>
|
|
478
592
|
<h3 className="text-xs font-semibold text-gray-500 uppercase tracking-wide mb-2 px-2">
|
|
479
|
-
|
|
593
|
+
Packages
|
|
480
594
|
</h3>
|
|
481
595
|
<div className="space-y-1">
|
|
482
596
|
{searchResults.slice(0, 8).map((pkg, localIndex) => {
|
|
@@ -490,6 +604,25 @@ const CmdKMenu = () => {
|
|
|
490
604
|
</div>
|
|
491
605
|
)}
|
|
492
606
|
|
|
607
|
+
{searchQuery && accountSearchResults.length > 0 && (
|
|
608
|
+
<div>
|
|
609
|
+
<h3 className="text-xs font-semibold text-gray-500 uppercase tracking-wide mb-2 px-2">
|
|
610
|
+
Users
|
|
611
|
+
</h3>
|
|
612
|
+
<div className="space-y-1">
|
|
613
|
+
{accountSearchResults
|
|
614
|
+
.slice(0, 5)
|
|
615
|
+
.map((account, localIndex) => {
|
|
616
|
+
const globalIndex = searchResults.length + localIndex
|
|
617
|
+
return renderItem(
|
|
618
|
+
{ type: "account", item: account },
|
|
619
|
+
globalIndex,
|
|
620
|
+
)
|
|
621
|
+
})}
|
|
622
|
+
</div>
|
|
623
|
+
</div>
|
|
624
|
+
)}
|
|
625
|
+
|
|
493
626
|
{!searchQuery && recentPackages.length > 0 && (
|
|
494
627
|
<div>
|
|
495
628
|
<h3 className="text-xs font-semibold text-gray-500 uppercase tracking-wide mb-2 px-2 flex items-center gap-1">
|
|
@@ -518,7 +651,7 @@ const CmdKMenu = () => {
|
|
|
518
651
|
(template, localIndex) => {
|
|
519
652
|
const globalIndex =
|
|
520
653
|
(searchQuery
|
|
521
|
-
? searchResults.length
|
|
654
|
+
? searchResults.length + accountSearchResults.length
|
|
522
655
|
: recentPackages.length) + localIndex
|
|
523
656
|
return renderItem(
|
|
524
657
|
{
|
|
@@ -544,7 +677,7 @@ const CmdKMenu = () => {
|
|
|
544
677
|
(template, localIndex) => {
|
|
545
678
|
const globalIndex =
|
|
546
679
|
(searchQuery
|
|
547
|
-
? searchResults.length
|
|
680
|
+
? searchResults.length + accountSearchResults.length
|
|
548
681
|
: recentPackages.length) +
|
|
549
682
|
filteredStaticOptions.blankTemplates.length +
|
|
550
683
|
localIndex
|
|
@@ -568,7 +701,7 @@ const CmdKMenu = () => {
|
|
|
568
701
|
(option, localIndex) => {
|
|
569
702
|
const globalIndex =
|
|
570
703
|
(searchQuery
|
|
571
|
-
? searchResults.length
|
|
704
|
+
? searchResults.length + accountSearchResults.length
|
|
572
705
|
: recentPackages.length) +
|
|
573
706
|
filteredStaticOptions.blankTemplates.length +
|
|
574
707
|
filteredStaticOptions.templates.length +
|
|
@@ -585,10 +718,12 @@ const CmdKMenu = () => {
|
|
|
585
718
|
|
|
586
719
|
{searchQuery &&
|
|
587
720
|
!searchResults.length &&
|
|
721
|
+
!accountSearchResults.length &&
|
|
588
722
|
!filteredStaticOptions.blankTemplates.length &&
|
|
589
723
|
!filteredStaticOptions.templates.length &&
|
|
590
724
|
!filteredStaticOptions.importOptions.length &&
|
|
591
|
-
!isSearching &&
|
|
725
|
+
!isSearching &&
|
|
726
|
+
!isSearchingAccounts && (
|
|
592
727
|
<Command.Empty className="py-8 text-center">
|
|
593
728
|
<div className="text-gray-400 mb-1">No results found</div>
|
|
594
729
|
<div className="text-gray-500 text-xs">
|