@tscircuit/cli 0.0.2
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/.prettierrc +1 -0
- package/README.md +50 -0
- package/build-cli.ts +14 -0
- package/bun.lockb +0 -0
- package/cli.ts +12 -0
- package/dev-server-api/README.md +3 -0
- package/dev-server-api/bun.lockb +0 -0
- package/dev-server-api/edgespec.config.ts +4 -0
- package/dev-server-api/index.ts +1 -0
- package/dev-server-api/package-lock.json +1201 -0
- package/dev-server-api/package.json +24 -0
- package/dev-server-api/routes/api/dev_package_examples/create.ts +43 -0
- package/dev-server-api/routes/api/dev_package_examples/get.ts +37 -0
- package/dev-server-api/routes/api/dev_package_examples/list.ts +29 -0
- package/dev-server-api/routes/api/dev_package_examples/update.ts +31 -0
- package/dev-server-api/routes/api/health.ts +11 -0
- package/dev-server-api/src/db/create-schema.ts +14 -0
- package/dev-server-api/src/db/get-db.ts +78 -0
- package/dev-server-api/src/middlewares/with-db.ts +14 -0
- package/dev-server-api/src/middlewares/with-error-response.ts +24 -0
- package/dev-server-api/src/with-edge-spec.ts +8 -0
- package/dev-server-api/tsconfig.json +28 -0
- package/dev-server-frontend/.eslintrc.cjs +20 -0
- package/dev-server-frontend/README.md +3 -0
- package/dev-server-frontend/bun.lockb +0 -0
- package/dev-server-frontend/components.json +17 -0
- package/dev-server-frontend/index.html +13 -0
- package/dev-server-frontend/package.json +62 -0
- package/dev-server-frontend/postcss.config.js +6 -0
- package/dev-server-frontend/src/App.tsx +22 -0
- package/dev-server-frontend/src/ExampleContentView.tsx +60 -0
- package/dev-server-frontend/src/Header.tsx +53 -0
- package/dev-server-frontend/src/HeaderMenu.tsx +188 -0
- package/dev-server-frontend/src/components/command-k.tsx +62 -0
- package/dev-server-frontend/src/components/global-context-providers.tsx +11 -0
- package/dev-server-frontend/src/components/select-example-search.tsx +137 -0
- package/dev-server-frontend/src/components/ui/alert-dialog.tsx +139 -0
- package/dev-server-frontend/src/components/ui/alert.tsx +59 -0
- package/dev-server-frontend/src/components/ui/breadcrumb.tsx +115 -0
- package/dev-server-frontend/src/components/ui/button.tsx +57 -0
- package/dev-server-frontend/src/components/ui/card.tsx +76 -0
- package/dev-server-frontend/src/components/ui/command.tsx +153 -0
- package/dev-server-frontend/src/components/ui/context-menu.tsx +202 -0
- package/dev-server-frontend/src/components/ui/dialog.tsx +120 -0
- package/dev-server-frontend/src/components/ui/menubar.tsx +238 -0
- package/dev-server-frontend/src/components/ui/navigation-menu.tsx +128 -0
- package/dev-server-frontend/src/components/ui/popover.tsx +31 -0
- package/dev-server-frontend/src/components/ui/select.tsx +162 -0
- package/dev-server-frontend/src/components/ui/tabs.tsx +53 -0
- package/dev-server-frontend/src/components/ui/toggle-group.tsx +59 -0
- package/dev-server-frontend/src/components/ui/toggle.tsx +43 -0
- package/dev-server-frontend/src/components/ui/tooltip.tsx +28 -0
- package/dev-server-frontend/src/hooks/toast-if-api-not-connected.ts +23 -0
- package/dev-server-frontend/src/hooks/use-global-store.ts +42 -0
- package/dev-server-frontend/src/index.css +76 -0
- package/dev-server-frontend/src/lib/utils.ts +6 -0
- package/dev-server-frontend/src/main.tsx +13 -0
- package/dev-server-frontend/src/vite-env.d.ts +1 -0
- package/dev-server-frontend/tailwind.config.js +77 -0
- package/dev-server-frontend/tsconfig.json +26 -0
- package/dev-server-frontend/tsconfig.node.json +13 -0
- package/dev-server-frontend/vite.config.ts +23 -0
- package/dist/cli.js +1326 -0
- package/lib/cmd-fns/auth-login.ts +59 -0
- package/lib/cmd-fns/auth-logout.ts +3 -0
- package/lib/cmd-fns/auth-sessions-create.ts +3 -0
- package/lib/cmd-fns/auth-sessions-get.ts +3 -0
- package/lib/cmd-fns/auth-sessions-list.ts +5 -0
- package/lib/cmd-fns/config-print-config.ts +6 -0
- package/lib/cmd-fns/config-reveal-location.ts +5 -0
- package/lib/cmd-fns/config-set-log-requests.ts +7 -0
- package/lib/cmd-fns/config-set-registry.ts +7 -0
- package/lib/cmd-fns/config-set-session.ts +7 -0
- package/lib/cmd-fns/dev.ts +217 -0
- package/lib/cmd-fns/index.ts +27 -0
- package/lib/cmd-fns/package-examples-create.ts +33 -0
- package/lib/cmd-fns/package-examples-get.ts +20 -0
- package/lib/cmd-fns/package-examples-list.ts +18 -0
- package/lib/cmd-fns/package-files-create.ts +31 -0
- package/lib/cmd-fns/package-files-download.ts +29 -0
- package/lib/cmd-fns/package-files-get.ts +3 -0
- package/lib/cmd-fns/package-files-list.ts +28 -0
- package/lib/cmd-fns/package-files-upload-directory.ts +6 -0
- package/lib/cmd-fns/package-releases-create.ts +35 -0
- package/lib/cmd-fns/package-releases-get.ts +3 -0
- package/lib/cmd-fns/package-releases-list.ts +32 -0
- package/lib/cmd-fns/packages-create.ts +16 -0
- package/lib/cmd-fns/packages-get.ts +16 -0
- package/lib/cmd-fns/packages-list.ts +16 -0
- package/lib/cmd-fns/publish.ts +3 -0
- package/lib/cmd-fns/soupify.ts +27 -0
- package/lib/get-program.ts +191 -0
- package/lib/param-handlers/index.ts +16 -0
- package/lib/param-handlers/interact-for-local-directory.ts +58 -0
- package/lib/param-handlers/interact-for-local-file.ts +59 -0
- package/lib/param-handlers/interact-for-package-example-id.ts +25 -0
- package/lib/param-handlers/interact-for-package-name-with-version.ts +63 -0
- package/lib/param-handlers/interact-for-package-name.ts +45 -0
- package/lib/param-handlers/interact-for-package-release-id.ts +16 -0
- package/lib/param-handlers/param-handler-type.ts +7 -0
- package/lib/soupify.ts +71 -0
- package/lib/util/app-context.ts +14 -0
- package/lib/util/create-context-and-run-program.ts +116 -0
- package/package.json +62 -0
- package/tests/assets/example-project/examples/basic-capacitor.tsx +1 -0
- package/tests/assets/example-project/examples/basic-resistor.tsx +3 -0
- package/tests/assets/example-project/package.json +8 -0
- package/tests/assets/example-project/src/MyCircuit.tsx +3 -0
- package/tests/soupify.test.ts +9 -0
- package/tsconfig.json +109 -0
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@tscircuit/dev-server-api",
|
|
3
|
+
"main": "dist/bundle.ts",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"scripts": {
|
|
6
|
+
"start": "edgespec dev --port 3021",
|
|
7
|
+
"build": "edgespec bundle -o dist/bundle.ts"
|
|
8
|
+
},
|
|
9
|
+
"devDependencies": {
|
|
10
|
+
"@types/better-sqlite3": "^7.6.9",
|
|
11
|
+
"@types/bun": "latest",
|
|
12
|
+
"@types/sql.js": "^1.4.9"
|
|
13
|
+
},
|
|
14
|
+
"peerDependencies": {
|
|
15
|
+
"typescript": "^5.0.0"
|
|
16
|
+
},
|
|
17
|
+
"dependencies": {
|
|
18
|
+
"better-sqlite3": "^9.4.3",
|
|
19
|
+
"edgespec": "^0.0.69",
|
|
20
|
+
"kysely": "^0.27.3",
|
|
21
|
+
"kysely-bun-sqlite": "^0.3.2",
|
|
22
|
+
"zod": "^3.22.4"
|
|
23
|
+
}
|
|
24
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { withEdgeSpec } from "src/with-edge-spec"
|
|
2
|
+
import { NotFoundError } from "edgespec/middleware"
|
|
3
|
+
import { z } from "zod"
|
|
4
|
+
|
|
5
|
+
export default withEdgeSpec({
|
|
6
|
+
methods: ["POST"],
|
|
7
|
+
jsonBody: z.object({
|
|
8
|
+
file_path: z.string(),
|
|
9
|
+
export_name: z.string().default("default"),
|
|
10
|
+
tscircuit_soup: z.any(),
|
|
11
|
+
}),
|
|
12
|
+
jsonResponse: z.object({
|
|
13
|
+
dev_package_example: z.object({
|
|
14
|
+
dev_package_example_id: z.coerce.number(),
|
|
15
|
+
file_path: z.string(),
|
|
16
|
+
tscircuit_soup: z.any(),
|
|
17
|
+
last_updated_at: z.string().datetime(),
|
|
18
|
+
}),
|
|
19
|
+
}),
|
|
20
|
+
auth: "none",
|
|
21
|
+
})(async (req, ctx) => {
|
|
22
|
+
const dev_package_example = await ctx.db
|
|
23
|
+
.insertInto("dev_package_example")
|
|
24
|
+
.values({
|
|
25
|
+
file_path: req.jsonBody.file_path,
|
|
26
|
+
export_name: req.jsonBody.export_name,
|
|
27
|
+
tscircuit_soup: JSON.stringify(req.jsonBody.tscircuit_soup),
|
|
28
|
+
last_updated_at: new Date().toISOString(),
|
|
29
|
+
})
|
|
30
|
+
.onConflict((oc) =>
|
|
31
|
+
oc.columns(["file_path"]).doUpdateSet({
|
|
32
|
+
export_name: req.jsonBody.export_name,
|
|
33
|
+
tscircuit_soup: JSON.stringify(req.jsonBody.tscircuit_soup),
|
|
34
|
+
last_updated_at: new Date().toISOString(),
|
|
35
|
+
})
|
|
36
|
+
)
|
|
37
|
+
.returningAll()
|
|
38
|
+
.executeTakeFirstOrThrow()
|
|
39
|
+
|
|
40
|
+
return ctx.json({
|
|
41
|
+
dev_package_example,
|
|
42
|
+
})
|
|
43
|
+
})
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { withEdgeSpec } from "src/with-edge-spec"
|
|
2
|
+
import { NotFoundError } from "edgespec/middleware"
|
|
3
|
+
import { z } from "zod"
|
|
4
|
+
|
|
5
|
+
export default withEdgeSpec({
|
|
6
|
+
methods: ["GET", "POST"],
|
|
7
|
+
commonParams: z.object({
|
|
8
|
+
dev_package_example_id: z.coerce.number(),
|
|
9
|
+
}),
|
|
10
|
+
jsonResponse: z.object({
|
|
11
|
+
dev_package_example: z.object({
|
|
12
|
+
dev_package_example_id: z.coerce.number(),
|
|
13
|
+
file_path: z.string(),
|
|
14
|
+
tscircuit_soup: z.any(),
|
|
15
|
+
last_updated_at: z.string().datetime(),
|
|
16
|
+
}),
|
|
17
|
+
}),
|
|
18
|
+
auth: "none",
|
|
19
|
+
})(async (req, ctx) => {
|
|
20
|
+
return ctx.json({
|
|
21
|
+
dev_package_example: await ctx.db
|
|
22
|
+
.selectFrom("dev_package_example")
|
|
23
|
+
.selectAll()
|
|
24
|
+
.where(
|
|
25
|
+
"dev_package_example_id",
|
|
26
|
+
"=",
|
|
27
|
+
req.commonParams.dev_package_example_id
|
|
28
|
+
)
|
|
29
|
+
.executeTakeFirstOrThrow((e) => {
|
|
30
|
+
throw new NotFoundError("Package not found")
|
|
31
|
+
})
|
|
32
|
+
.then((r) => ({
|
|
33
|
+
...r,
|
|
34
|
+
tscircuit_soup: JSON.parse(r.tscircuit_soup),
|
|
35
|
+
})),
|
|
36
|
+
})
|
|
37
|
+
})
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { withEdgeSpec } from "src/with-edge-spec"
|
|
2
|
+
import { z } from "zod"
|
|
3
|
+
|
|
4
|
+
export default withEdgeSpec({
|
|
5
|
+
methods: ["GET", "POST"],
|
|
6
|
+
jsonResponse: z.object({
|
|
7
|
+
dev_package_examples: z.array(
|
|
8
|
+
z.object({
|
|
9
|
+
dev_package_example_id: z.coerce.number(),
|
|
10
|
+
file_path: z.string(),
|
|
11
|
+
export_name: z.string(),
|
|
12
|
+
last_updated_at: z.string().datetime(),
|
|
13
|
+
})
|
|
14
|
+
),
|
|
15
|
+
}),
|
|
16
|
+
auth: "none",
|
|
17
|
+
})(async (req, ctx) => {
|
|
18
|
+
return ctx.json({
|
|
19
|
+
dev_package_examples: await ctx.db
|
|
20
|
+
.selectFrom("dev_package_example")
|
|
21
|
+
.select([
|
|
22
|
+
"dev_package_example_id",
|
|
23
|
+
"file_path",
|
|
24
|
+
"export_name",
|
|
25
|
+
"last_updated_at",
|
|
26
|
+
])
|
|
27
|
+
.execute(),
|
|
28
|
+
})
|
|
29
|
+
})
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { withEdgeSpec } from "src/with-edge-spec"
|
|
2
|
+
import { NotFoundError } from "edgespec/middleware"
|
|
3
|
+
import { z } from "zod"
|
|
4
|
+
|
|
5
|
+
export default withEdgeSpec({
|
|
6
|
+
methods: ["POST"],
|
|
7
|
+
jsonBody: z.object({
|
|
8
|
+
dev_package_example_id: z.coerce.number(),
|
|
9
|
+
tscircuit_soup: z.any(),
|
|
10
|
+
}),
|
|
11
|
+
jsonResponse: z.object({
|
|
12
|
+
dev_package_example: z.object({
|
|
13
|
+
dev_package_example_id: z.coerce.number(),
|
|
14
|
+
tscircuit_soup: z.any(),
|
|
15
|
+
last_updated_at: z.string().datetime(),
|
|
16
|
+
}),
|
|
17
|
+
}),
|
|
18
|
+
auth: "none",
|
|
19
|
+
})(async (req, ctx) => {
|
|
20
|
+
return ctx.json({
|
|
21
|
+
dev_package_example: await ctx.db
|
|
22
|
+
.updateTable("dev_package_example")
|
|
23
|
+
.set({
|
|
24
|
+
tscircuit_soup: req.jsonBody.tscircuit_soup,
|
|
25
|
+
last_updated_at: new Date().toISOString(),
|
|
26
|
+
})
|
|
27
|
+
.returningAll()
|
|
28
|
+
.where("dev_package_example_id", "=", req.jsonBody.dev_package_example_id)
|
|
29
|
+
.executeTakeFirstOrThrow(),
|
|
30
|
+
})
|
|
31
|
+
})
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { withEdgeSpec } from "../../src/with-edge-spec"
|
|
2
|
+
import { z } from "zod"
|
|
3
|
+
|
|
4
|
+
export default withEdgeSpec({
|
|
5
|
+
methods: ["GET", "POST"],
|
|
6
|
+
jsonResponse: z.object({
|
|
7
|
+
ok: z.boolean(),
|
|
8
|
+
}),
|
|
9
|
+
})(async (req, ctx) => {
|
|
10
|
+
return ctx.json({ ok: true })
|
|
11
|
+
})
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { DbClient } from "./get-db"
|
|
2
|
+
|
|
3
|
+
export const createSchema = async (db: DbClient) => {
|
|
4
|
+
await db.schema
|
|
5
|
+
.createTable("dev_package_example")
|
|
6
|
+
.addColumn("dev_package_example_id", "integer", (col) =>
|
|
7
|
+
col.primaryKey().autoIncrement()
|
|
8
|
+
)
|
|
9
|
+
.addColumn("file_path", "text", (col) => col.unique())
|
|
10
|
+
.addColumn("export_name", "text")
|
|
11
|
+
.addColumn("tscircuit_soup", "json")
|
|
12
|
+
.addColumn("last_updated_at", "text")
|
|
13
|
+
.execute()
|
|
14
|
+
}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { Kysely, sql, type Generated, SqliteDialect } from "kysely"
|
|
2
|
+
import { createSchema } from "./create-schema"
|
|
3
|
+
import { mkdirSync } from "fs"
|
|
4
|
+
import * as Path from "path"
|
|
5
|
+
|
|
6
|
+
interface DevPackageExample {
|
|
7
|
+
dev_package_example_id: Generated<number>
|
|
8
|
+
tscircuit_soup: any
|
|
9
|
+
file_path: string
|
|
10
|
+
export_name: string
|
|
11
|
+
last_updated_at: string
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
interface KyselyDatabaseSchema {
|
|
15
|
+
dev_package_example: DevPackageExample
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export type DbClient = Kysely<KyselyDatabaseSchema>
|
|
19
|
+
|
|
20
|
+
// let globalDb: Database | undefined
|
|
21
|
+
|
|
22
|
+
let globalDb: Kysely<KyselyDatabaseSchema> | undefined
|
|
23
|
+
|
|
24
|
+
export const getDb = async (): Promise<Kysely<KyselyDatabaseSchema>> => {
|
|
25
|
+
if (globalDb) return globalDb
|
|
26
|
+
|
|
27
|
+
const devServerDbPath =
|
|
28
|
+
process.env.TSCI_DEV_SERVER_DB ?? "./.tscircuit/dev-server.db"
|
|
29
|
+
|
|
30
|
+
mkdirSync(Path.dirname(devServerDbPath), { recursive: true })
|
|
31
|
+
|
|
32
|
+
// better-sqlite3 doesn't work in bun, so if we see we can use the bun
|
|
33
|
+
// alternative, attempt to use that instead
|
|
34
|
+
let dialect: any
|
|
35
|
+
|
|
36
|
+
if (typeof Bun !== "undefined") {
|
|
37
|
+
// console.log("Attempting to use bun-sqlite")
|
|
38
|
+
try {
|
|
39
|
+
const { BunSqliteDialect } = await import("kysely-bun-sqlite")
|
|
40
|
+
const { Database } = await import("bun:sqlite")
|
|
41
|
+
dialect = new BunSqliteDialect({
|
|
42
|
+
database: new Database(devServerDbPath, {
|
|
43
|
+
create: true,
|
|
44
|
+
}),
|
|
45
|
+
})
|
|
46
|
+
} catch (e) {}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
if (!dialect) {
|
|
50
|
+
// console.log("Attempting to use better-sqlite3")
|
|
51
|
+
try {
|
|
52
|
+
const BetterSqlite3 = await import("better-sqlite3")
|
|
53
|
+
dialect = new SqliteDialect({
|
|
54
|
+
database: new BetterSqlite3.default(devServerDbPath),
|
|
55
|
+
})
|
|
56
|
+
} catch (e) {}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
if (!dialect) {
|
|
60
|
+
throw new Error("Was not able to load sqlite dialect")
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const db = new Kysely<KyselyDatabaseSchema>({
|
|
64
|
+
dialect,
|
|
65
|
+
})
|
|
66
|
+
|
|
67
|
+
const schemaExistsResult = await sql`
|
|
68
|
+
SELECT name
|
|
69
|
+
FROM sqlite_master
|
|
70
|
+
WHERE type='table' AND name='dev_package_example'
|
|
71
|
+
`.execute(db)
|
|
72
|
+
|
|
73
|
+
if (schemaExistsResult.rows.length === 0) {
|
|
74
|
+
await createSchema(db)
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
return db
|
|
78
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { Middleware } from "edgespec"
|
|
2
|
+
import { getDb, type DbClient } from "../db/get-db"
|
|
3
|
+
|
|
4
|
+
export const withDb: Middleware<
|
|
5
|
+
{},
|
|
6
|
+
{
|
|
7
|
+
db: DbClient
|
|
8
|
+
}
|
|
9
|
+
> = async (req, ctx, next) => {
|
|
10
|
+
if (!ctx.db) {
|
|
11
|
+
ctx.db = await getDb()
|
|
12
|
+
}
|
|
13
|
+
return next(req, ctx)
|
|
14
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { Middleware } from "edgespec/middleware"
|
|
2
|
+
import kleur from "kleur"
|
|
3
|
+
|
|
4
|
+
export const withErrorResponse: Middleware<{}, {}> = async (req, ctx, next) => {
|
|
5
|
+
try {
|
|
6
|
+
return await next(req, ctx)
|
|
7
|
+
} catch (error: any) {
|
|
8
|
+
console.error(kleur.red("Intercepted error:"), error)
|
|
9
|
+
// If error is a Response, return it
|
|
10
|
+
if (error instanceof Response) {
|
|
11
|
+
return error
|
|
12
|
+
}
|
|
13
|
+
return (ctx as any).json(
|
|
14
|
+
{
|
|
15
|
+
ok: false,
|
|
16
|
+
error: {
|
|
17
|
+
message: error?.message,
|
|
18
|
+
error_code: error?.error_code ?? "internal_server_error",
|
|
19
|
+
},
|
|
20
|
+
},
|
|
21
|
+
{ status: error?.status || 500 }
|
|
22
|
+
)
|
|
23
|
+
}
|
|
24
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { createWithEdgeSpec } from "edgespec"
|
|
2
|
+
import { withDb } from "./middlewares/with-db"
|
|
3
|
+
import { withErrorResponse } from "./middlewares/with-error-response"
|
|
4
|
+
|
|
5
|
+
export const withEdgeSpec = createWithEdgeSpec({
|
|
6
|
+
authMiddleware: {},
|
|
7
|
+
beforeAuthMiddleware: [withErrorResponse, withDb],
|
|
8
|
+
})
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
// Enable latest features
|
|
4
|
+
"lib": ["ESNext"],
|
|
5
|
+
"target": "ESNext",
|
|
6
|
+
"module": "ESNext",
|
|
7
|
+
"moduleDetection": "force",
|
|
8
|
+
"jsx": "react-jsx",
|
|
9
|
+
"allowJs": true,
|
|
10
|
+
"baseUrl": ".",
|
|
11
|
+
|
|
12
|
+
// Bundler mode
|
|
13
|
+
"moduleResolution": "bundler",
|
|
14
|
+
"allowImportingTsExtensions": true,
|
|
15
|
+
"verbatimModuleSyntax": true,
|
|
16
|
+
"noEmit": true,
|
|
17
|
+
|
|
18
|
+
// Best practices
|
|
19
|
+
"strict": true,
|
|
20
|
+
"skipLibCheck": true,
|
|
21
|
+
"noFallthroughCasesInSwitch": true,
|
|
22
|
+
|
|
23
|
+
// Some stricter flags (disabled by default)
|
|
24
|
+
"noUnusedLocals": false,
|
|
25
|
+
"noUnusedParameters": false,
|
|
26
|
+
"noPropertyAccessFromIndexSignature": false
|
|
27
|
+
}
|
|
28
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
module.exports = {
|
|
2
|
+
root: true,
|
|
3
|
+
env: { browser: true, es2020: true },
|
|
4
|
+
extends: [
|
|
5
|
+
'eslint:recommended',
|
|
6
|
+
'plugin:@typescript-eslint/recommended',
|
|
7
|
+
'plugin:react-hooks/recommended',
|
|
8
|
+
],
|
|
9
|
+
ignorePatterns: ['dist', '.eslintrc.cjs'],
|
|
10
|
+
parser: '@typescript-eslint/parser',
|
|
11
|
+
plugins: ['react-refresh'],
|
|
12
|
+
rules: {
|
|
13
|
+
'react-refresh/only-export-components': [
|
|
14
|
+
'warn',
|
|
15
|
+
{ allowConstantExport: true },
|
|
16
|
+
],
|
|
17
|
+
'@typescript-eslint/no-unused-vars': 'off',
|
|
18
|
+
"@typescript-eslint/no-explicit-any": "off"
|
|
19
|
+
},
|
|
20
|
+
}
|
|
Binary file
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://ui.shadcn.com/schema.json",
|
|
3
|
+
"style": "new-york",
|
|
4
|
+
"rsc": false,
|
|
5
|
+
"tsx": true,
|
|
6
|
+
"tailwind": {
|
|
7
|
+
"config": "tailwind.config.js",
|
|
8
|
+
"css": "src/index.css",
|
|
9
|
+
"baseColor": "gray",
|
|
10
|
+
"cssVariables": true,
|
|
11
|
+
"prefix": ""
|
|
12
|
+
},
|
|
13
|
+
"aliases": {
|
|
14
|
+
"components": "src/components",
|
|
15
|
+
"utils": "src/lib/utils"
|
|
16
|
+
}
|
|
17
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8" />
|
|
5
|
+
<!-- <link rel="icon" type="image/svg+xml" href="/vite.svg" /> -->
|
|
6
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
7
|
+
<title>[dev] tscircuit</title>
|
|
8
|
+
</head>
|
|
9
|
+
<body>
|
|
10
|
+
<div id="root"></div>
|
|
11
|
+
<script type="module" src="/src/main.tsx"></script>
|
|
12
|
+
</body>
|
|
13
|
+
</html>
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@tscircuit/dev-server-frontend",
|
|
3
|
+
"private": true,
|
|
4
|
+
"version": "0.0.0",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/bundle.ts",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": "./dist/bundle.ts"
|
|
9
|
+
},
|
|
10
|
+
"scripts": {
|
|
11
|
+
"dev": "vite",
|
|
12
|
+
"start": "npm run dev",
|
|
13
|
+
"build": "tsc && vite build --base /preview && rm -f dist/bundle* && make-vfs --dir dist --outfile ./dist/bundle.ts",
|
|
14
|
+
"lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 10",
|
|
15
|
+
"preview": "vite preview"
|
|
16
|
+
},
|
|
17
|
+
"dependencies": {
|
|
18
|
+
"@radix-ui/react-alert-dialog": "^1.0.5",
|
|
19
|
+
"@radix-ui/react-context-menu": "^2.1.5",
|
|
20
|
+
"@radix-ui/react-dialog": "^1.0.5",
|
|
21
|
+
"@radix-ui/react-icons": "^1.3.0",
|
|
22
|
+
"@radix-ui/react-menubar": "^1.0.4",
|
|
23
|
+
"@radix-ui/react-navigation-menu": "^1.1.4",
|
|
24
|
+
"@radix-ui/react-popover": "^1.0.7",
|
|
25
|
+
"@radix-ui/react-select": "^2.0.0",
|
|
26
|
+
"@radix-ui/react-slot": "^1.0.2",
|
|
27
|
+
"@radix-ui/react-tabs": "^1.0.4",
|
|
28
|
+
"@radix-ui/react-toggle": "^1.0.3",
|
|
29
|
+
"@radix-ui/react-toggle-group": "^1.0.4",
|
|
30
|
+
"@radix-ui/react-tooltip": "^1.0.7",
|
|
31
|
+
"@tscircuit/pcb-viewer": "^1.2.12",
|
|
32
|
+
"@tscircuit/schematic-viewer": "^1.1.5",
|
|
33
|
+
"axios": "^1.6.7",
|
|
34
|
+
"class-variance-authority": "^0.7.0",
|
|
35
|
+
"clsx": "^2.1.0",
|
|
36
|
+
"cmdk": "^1.0.0",
|
|
37
|
+
"react": "^18.2.0",
|
|
38
|
+
"react-dom": "^18.2.0",
|
|
39
|
+
"react-hot-toast": "^2.4.1",
|
|
40
|
+
"react-query": "^3.39.3",
|
|
41
|
+
"tailwind-merge": "^2.2.1",
|
|
42
|
+
"tailwindcss-animate": "^1.0.7",
|
|
43
|
+
"zod": "^3.22.4",
|
|
44
|
+
"zustand": "^4.5.2"
|
|
45
|
+
},
|
|
46
|
+
"devDependencies": {
|
|
47
|
+
"@types/react": "^18.2.64",
|
|
48
|
+
"@types/react-dom": "^18.2.21",
|
|
49
|
+
"@typescript-eslint/eslint-plugin": "^7.1.1",
|
|
50
|
+
"@typescript-eslint/parser": "^7.1.1",
|
|
51
|
+
"@vitejs/plugin-react": "^4.2.1",
|
|
52
|
+
"autoprefixer": "^10.4.18",
|
|
53
|
+
"eslint": "^8.57.0",
|
|
54
|
+
"eslint-plugin-react-hooks": "^4.6.0",
|
|
55
|
+
"eslint-plugin-react-refresh": "^0.4.5",
|
|
56
|
+
"make-vfs": "1.0.10",
|
|
57
|
+
"postcss": "^8.4.35",
|
|
58
|
+
"tailwindcss": "^3.4.1",
|
|
59
|
+
"typescript": "^5.2.2",
|
|
60
|
+
"vite": "^5.1.6"
|
|
61
|
+
}
|
|
62
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { TabsContent } from "./components/ui/tabs"
|
|
2
|
+
import { MenubarShortcut } from "src/components/ui/menubar"
|
|
3
|
+
import { CommandK } from "./components/command-k"
|
|
4
|
+
import { useToastIfApiNotConnected } from "./hooks/toast-if-api-not-connected"
|
|
5
|
+
import { Header } from "./Header"
|
|
6
|
+
import { ExampleContentView } from "./ExampleContentView"
|
|
7
|
+
|
|
8
|
+
function App() {
|
|
9
|
+
useToastIfApiNotConnected()
|
|
10
|
+
|
|
11
|
+
return (
|
|
12
|
+
<div className="">
|
|
13
|
+
<Header />
|
|
14
|
+
<div className="">
|
|
15
|
+
<ExampleContentView />
|
|
16
|
+
</div>
|
|
17
|
+
<CommandK />
|
|
18
|
+
</div>
|
|
19
|
+
)
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export default App
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { useQuery } from "react-query"
|
|
2
|
+
import { useGlobalStore } from "./hooks/use-global-store"
|
|
3
|
+
import axios from "axios"
|
|
4
|
+
import { Schematic } from "@tscircuit/schematic-viewer"
|
|
5
|
+
import { PCBViewer } from "@tscircuit/pcb-viewer"
|
|
6
|
+
import { cn } from "./lib/utils"
|
|
7
|
+
|
|
8
|
+
export const ExampleContentView = () => {
|
|
9
|
+
const devExamplePackageId = useGlobalStore(
|
|
10
|
+
(s) => s.active_dev_example_package_id
|
|
11
|
+
)
|
|
12
|
+
|
|
13
|
+
const { data: pkg } = useQuery(
|
|
14
|
+
["dev_package_example", devExamplePackageId],
|
|
15
|
+
async () =>
|
|
16
|
+
axios
|
|
17
|
+
.post(`/api/dev_package_examples/get`, {
|
|
18
|
+
dev_package_example_id: devExamplePackageId,
|
|
19
|
+
})
|
|
20
|
+
.then((r) => r.data.dev_package_example)
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
const viewMode = useGlobalStore((s) => s.view_mode)
|
|
24
|
+
const splitMode = useGlobalStore((s) => s.split_mode)
|
|
25
|
+
|
|
26
|
+
const editorHeight = window.innerHeight - 52
|
|
27
|
+
const halfHeight = Math.floor(editorHeight / 2)
|
|
28
|
+
|
|
29
|
+
const itemHeight =
|
|
30
|
+
viewMode === "split" && splitMode === "vertical" ? halfHeight : editorHeight
|
|
31
|
+
|
|
32
|
+
return (
|
|
33
|
+
<div
|
|
34
|
+
key={pkg?.last_updated_at}
|
|
35
|
+
className={cn(
|
|
36
|
+
`h-[${editorHeight}px]`,
|
|
37
|
+
viewMode === "split" &&
|
|
38
|
+
splitMode === "horizontal" &&
|
|
39
|
+
"grid grid-cols-2",
|
|
40
|
+
viewMode === "split" && splitMode === "vertical" && "grid grid-rows-2"
|
|
41
|
+
)}
|
|
42
|
+
>
|
|
43
|
+
{pkg && (viewMode === "schematic" || viewMode === "split") && (
|
|
44
|
+
<Schematic
|
|
45
|
+
key={pkg?.last_updated_at}
|
|
46
|
+
style={{ height: itemHeight }}
|
|
47
|
+
soup={pkg.tscircuit_soup}
|
|
48
|
+
showTable={false}
|
|
49
|
+
/>
|
|
50
|
+
)}
|
|
51
|
+
{pkg && (viewMode === "pcb" || viewMode === "split") && (
|
|
52
|
+
<PCBViewer
|
|
53
|
+
key={pkg?.last_updated_at}
|
|
54
|
+
height={itemHeight}
|
|
55
|
+
soup={pkg.tscircuit_soup}
|
|
56
|
+
/>
|
|
57
|
+
)}
|
|
58
|
+
</div>
|
|
59
|
+
)
|
|
60
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { useState } from "react"
|
|
2
|
+
import { SelectExampleSearch } from "./components/select-example-search"
|
|
3
|
+
import { Button } from "./components/ui/button"
|
|
4
|
+
import { Tabs, TabsList, TabsTrigger } from "./components/ui/tabs"
|
|
5
|
+
import { RotateCounterClockwiseIcon } from "@radix-ui/react-icons"
|
|
6
|
+
import { useGlobalStore } from "./hooks/use-global-store"
|
|
7
|
+
import { HeaderMenu } from "./HeaderMenu"
|
|
8
|
+
import { CommandShortcut } from "./components/ui/command"
|
|
9
|
+
|
|
10
|
+
export const Header = () => {
|
|
11
|
+
const [viewMode, setViewMode] = useGlobalStore((s) => [
|
|
12
|
+
s.view_mode,
|
|
13
|
+
s.setViewMode,
|
|
14
|
+
])
|
|
15
|
+
const [splitMode, setSplitMode] = useGlobalStore((s) => [
|
|
16
|
+
s.split_mode,
|
|
17
|
+
s.setSplitMode,
|
|
18
|
+
])
|
|
19
|
+
const [inDebugMode, setInDebugMode] = useState(false)
|
|
20
|
+
|
|
21
|
+
return (
|
|
22
|
+
<div className="p-2 border-b border-b-gray-200 shadow-sm grid grid-cols-3">
|
|
23
|
+
<div className="flex">
|
|
24
|
+
<div className="inline-flex">
|
|
25
|
+
<HeaderMenu />
|
|
26
|
+
</div>
|
|
27
|
+
</div>
|
|
28
|
+
<div className="justify-center flex">
|
|
29
|
+
<SelectExampleSearch />
|
|
30
|
+
</div>
|
|
31
|
+
<div className="flex justify-end">
|
|
32
|
+
{/* Tabs from shadcn with "Tab One" and "Tab Two" */}
|
|
33
|
+
<Tabs onValueChange={(v) => setViewMode(v as any)} value={viewMode}>
|
|
34
|
+
<TabsList>
|
|
35
|
+
<TabsTrigger value="schematic">Schematic</TabsTrigger>
|
|
36
|
+
<TabsTrigger value="pcb">PCB</TabsTrigger>
|
|
37
|
+
<TabsTrigger value="split">Split</TabsTrigger>
|
|
38
|
+
</TabsList>
|
|
39
|
+
</Tabs>
|
|
40
|
+
<Button
|
|
41
|
+
variant="outline"
|
|
42
|
+
disabled={viewMode !== "split"}
|
|
43
|
+
className="ml-1 group"
|
|
44
|
+
onClick={() => {
|
|
45
|
+
setSplitMode(splitMode === "horizontal" ? "vertical" : "horizontal")
|
|
46
|
+
}}
|
|
47
|
+
>
|
|
48
|
+
<RotateCounterClockwiseIcon className="scale-x-[-1] group-hover:rotate-[30deg] transition-transform" />
|
|
49
|
+
</Button>
|
|
50
|
+
</div>
|
|
51
|
+
</div>
|
|
52
|
+
)
|
|
53
|
+
}
|