@tscircuit/fake-snippets 0.0.41 → 0.0.43

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/dist/index.d.ts CHANGED
@@ -258,6 +258,126 @@ declare const orderFileSchema: z.ZodObject<{
258
258
  content_bytes: Uint8Array<ArrayBuffer> | null;
259
259
  }>;
260
260
  type OrderFile = z.infer<typeof orderFileSchema>;
261
+ declare const orderQuoteSchema: z.ZodObject<{
262
+ order_quote_id: z.ZodString;
263
+ account_id: z.ZodNullable<z.ZodString>;
264
+ package_release_id: z.ZodNullable<z.ZodString>;
265
+ is_completed: z.ZodDefault<z.ZodBoolean>;
266
+ is_processing: z.ZodDefault<z.ZodBoolean>;
267
+ vendor_name: z.ZodString;
268
+ error: z.ZodNullable<z.ZodObject<{
269
+ error_code: z.ZodString;
270
+ message: z.ZodString;
271
+ }, "passthrough", z.ZodTypeAny, z.objectOutputType<{
272
+ error_code: z.ZodString;
273
+ message: z.ZodString;
274
+ }, z.ZodTypeAny, "passthrough">, z.objectInputType<{
275
+ error_code: z.ZodString;
276
+ message: z.ZodString;
277
+ }, z.ZodTypeAny, "passthrough">>>;
278
+ has_error: z.ZodDefault<z.ZodBoolean>;
279
+ created_at: z.ZodString;
280
+ updated_at: z.ZodString;
281
+ completed_at: z.ZodNullable<z.ZodString>;
282
+ quoted_components: z.ZodNullable<z.ZodArray<z.ZodObject<{
283
+ manufacturer_part_number: z.ZodNullable<z.ZodString>;
284
+ supplier_part_number: z.ZodNullable<z.ZodString>;
285
+ quantity: z.ZodDefault<z.ZodNumber>;
286
+ unit_price: z.ZodDefault<z.ZodNumber>;
287
+ total_price: z.ZodDefault<z.ZodNumber>;
288
+ available: z.ZodDefault<z.ZodBoolean>;
289
+ }, "strip", z.ZodTypeAny, {
290
+ manufacturer_part_number: string | null;
291
+ supplier_part_number: string | null;
292
+ quantity: number;
293
+ unit_price: number;
294
+ total_price: number;
295
+ available: boolean;
296
+ }, {
297
+ manufacturer_part_number: string | null;
298
+ supplier_part_number: string | null;
299
+ quantity?: number | undefined;
300
+ unit_price?: number | undefined;
301
+ total_price?: number | undefined;
302
+ available?: boolean | undefined;
303
+ }>, "many">>;
304
+ bare_pcb_cost: z.ZodDefault<z.ZodNumber>;
305
+ shipping_options: z.ZodArray<z.ZodObject<{
306
+ carrier: z.ZodString;
307
+ service: z.ZodString;
308
+ cost: z.ZodNumber;
309
+ }, "strip", z.ZodTypeAny, {
310
+ carrier: string;
311
+ service: string;
312
+ cost: number;
313
+ }, {
314
+ carrier: string;
315
+ service: string;
316
+ cost: number;
317
+ }>, "many">;
318
+ total_cost: z.ZodDefault<z.ZodNumber>;
319
+ }, "strip", z.ZodTypeAny, {
320
+ error: z.objectOutputType<{
321
+ error_code: z.ZodString;
322
+ message: z.ZodString;
323
+ }, z.ZodTypeAny, "passthrough"> | null;
324
+ package_release_id: string | null;
325
+ created_at: string;
326
+ updated_at: string;
327
+ account_id: string | null;
328
+ has_error: boolean;
329
+ completed_at: string | null;
330
+ order_quote_id: string;
331
+ is_completed: boolean;
332
+ is_processing: boolean;
333
+ vendor_name: string;
334
+ quoted_components: {
335
+ manufacturer_part_number: string | null;
336
+ supplier_part_number: string | null;
337
+ quantity: number;
338
+ unit_price: number;
339
+ total_price: number;
340
+ available: boolean;
341
+ }[] | null;
342
+ bare_pcb_cost: number;
343
+ shipping_options: {
344
+ carrier: string;
345
+ service: string;
346
+ cost: number;
347
+ }[];
348
+ total_cost: number;
349
+ }, {
350
+ error: z.objectInputType<{
351
+ error_code: z.ZodString;
352
+ message: z.ZodString;
353
+ }, z.ZodTypeAny, "passthrough"> | null;
354
+ package_release_id: string | null;
355
+ created_at: string;
356
+ updated_at: string;
357
+ account_id: string | null;
358
+ completed_at: string | null;
359
+ order_quote_id: string;
360
+ vendor_name: string;
361
+ quoted_components: {
362
+ manufacturer_part_number: string | null;
363
+ supplier_part_number: string | null;
364
+ quantity?: number | undefined;
365
+ unit_price?: number | undefined;
366
+ total_price?: number | undefined;
367
+ available?: boolean | undefined;
368
+ }[] | null;
369
+ shipping_options: {
370
+ carrier: string;
371
+ service: string;
372
+ cost: number;
373
+ }[];
374
+ has_error?: boolean | undefined;
375
+ is_completed?: boolean | undefined;
376
+ is_processing?: boolean | undefined;
377
+ bare_pcb_cost?: number | undefined;
378
+ total_cost?: number | undefined;
379
+ }>;
380
+ type OrderQuote = z.infer<typeof orderQuoteSchema>;
261
381
  declare const accountPackageSchema: z.ZodObject<{
262
382
  account_package_id: z.ZodString;
263
383
  account_id: z.ZodString;
@@ -737,10 +857,16 @@ declare const createDatabase: ({ seed }?: {
737
857
  }[];
738
858
  total_cost: number;
739
859
  }[];
740
- }, "addOrder" | "getOrderById" | "getOrderFilesByOrderId" | "getJlcpcbOrderStatesByOrderId" | "getJlcpcbOrderStepRunsByJlcpcbOrderStateId" | "updateOrder" | "addJlcpcbOrderState" | "updateJlcpcbOrderState" | "addOrderFile" | "getOrderFileById" | "addAccount" | "addAccountPackage" | "getAccountPackageById" | "updateAccountPackage" | "deleteAccountPackage" | "addSnippet" | "getLatestSnippets" | "getTrendingSnippets" | "getPackagesByAuthor" | "getSnippetByAuthorAndName" | "updateSnippet" | "getSnippetById" | "searchSnippets" | "deleteSnippet" | "addSession" | "getSessions" | "createLoginPage" | "getLoginPage" | "updateLoginPage" | "getAccount" | "updateAccount" | "createSession" | "addStar" | "removeStar" | "hasStarred" | "addPackage" | "updatePackage" | "getPackageById" | "getPackageReleaseById" | "addPackageRelease" | "updatePackageRelease" | "deletePackageFile" | "addPackageFile" | "updatePackageFile" | "getStarCount" | "getPackageFilesByReleaseId"> & {
860
+ }, "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" | "deleteSnippet" | "addSession" | "getSessions" | "createLoginPage" | "getLoginPage" | "updateLoginPage" | "getAccount" | "updateAccount" | "createSession" | "addStar" | "removeStar" | "hasStarred" | "addPackage" | "updatePackage" | "getPackageById" | "getPackageReleaseById" | "addPackageRelease" | "updatePackageRelease" | "deletePackageFile" | "addPackageFile" | "updatePackageFile" | "getStarCount" | "getPackageFilesByReleaseId"> & {
741
861
  addOrder: (order: Omit<Order, "order_id">) => Order;
742
862
  getOrderById: (orderId: string) => Order | undefined;
743
863
  getOrderFilesByOrderId: (orderId: string) => OrderFile[];
864
+ addOrderQuote: ({ account_id, package_release_id, vendor_name, }: {
865
+ account_id: string;
866
+ package_release_id: string;
867
+ vendor_name: string;
868
+ }) => string;
869
+ getOrderQuoteById: (orderQuoteId: string) => OrderQuote | undefined;
744
870
  getJlcpcbOrderStatesByOrderId: (orderId: string) => JlcpcbOrderState | undefined;
745
871
  getJlcpcbOrderStepRunsByJlcpcbOrderStateId: (jlcpcbOrderStateId: string) => JlcpcbOrderStepRun[];
746
872
  updateOrder: (orderId: string, updates: Partial<Order>) => void;
@@ -1013,10 +1139,16 @@ declare const createDatabase: ({ seed }?: {
1013
1139
  }[];
1014
1140
  total_cost: number;
1015
1141
  }[];
1016
- }, "addOrder" | "getOrderById" | "getOrderFilesByOrderId" | "getJlcpcbOrderStatesByOrderId" | "getJlcpcbOrderStepRunsByJlcpcbOrderStateId" | "updateOrder" | "addJlcpcbOrderState" | "updateJlcpcbOrderState" | "addOrderFile" | "getOrderFileById" | "addAccount" | "addAccountPackage" | "getAccountPackageById" | "updateAccountPackage" | "deleteAccountPackage" | "addSnippet" | "getLatestSnippets" | "getTrendingSnippets" | "getPackagesByAuthor" | "getSnippetByAuthorAndName" | "updateSnippet" | "getSnippetById" | "searchSnippets" | "deleteSnippet" | "addSession" | "getSessions" | "createLoginPage" | "getLoginPage" | "updateLoginPage" | "getAccount" | "updateAccount" | "createSession" | "addStar" | "removeStar" | "hasStarred" | "addPackage" | "updatePackage" | "getPackageById" | "getPackageReleaseById" | "addPackageRelease" | "updatePackageRelease" | "deletePackageFile" | "addPackageFile" | "updatePackageFile" | "getStarCount" | "getPackageFilesByReleaseId"> & {
1142
+ }, "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" | "deleteSnippet" | "addSession" | "getSessions" | "createLoginPage" | "getLoginPage" | "updateLoginPage" | "getAccount" | "updateAccount" | "createSession" | "addStar" | "removeStar" | "hasStarred" | "addPackage" | "updatePackage" | "getPackageById" | "getPackageReleaseById" | "addPackageRelease" | "updatePackageRelease" | "deletePackageFile" | "addPackageFile" | "updatePackageFile" | "getStarCount" | "getPackageFilesByReleaseId"> & {
1017
1143
  addOrder: (order: Omit<Order, "order_id">) => Order;
1018
1144
  getOrderById: (orderId: string) => Order | undefined;
1019
1145
  getOrderFilesByOrderId: (orderId: string) => OrderFile[];
1146
+ addOrderQuote: ({ account_id, package_release_id, vendor_name, }: {
1147
+ account_id: string;
1148
+ package_release_id: string;
1149
+ vendor_name: string;
1150
+ }) => string;
1151
+ getOrderQuoteById: (orderQuoteId: string) => OrderQuote | undefined;
1020
1152
  getJlcpcbOrderStatesByOrderId: (orderId: string) => JlcpcbOrderState | undefined;
1021
1153
  getJlcpcbOrderStepRunsByJlcpcbOrderStateId: (jlcpcbOrderStateId: string) => JlcpcbOrderStepRun[];
1022
1154
  updateOrder: (orderId: string, updates: Partial<Order>) => void;
package/dist/index.js CHANGED
@@ -2020,6 +2020,42 @@ var initializer = combine(databaseSchema.parse({}), (set, get) => ({
2020
2020
  const state = get();
2021
2021
  return state.orderFiles.filter((file) => file.order_id === orderId);
2022
2022
  },
2023
+ addOrderQuote: ({
2024
+ account_id,
2025
+ package_release_id,
2026
+ vendor_name
2027
+ }) => {
2028
+ const newOrderQuote = {
2029
+ order_quote_id: `order_quote_${get().idCounter + 1}`,
2030
+ account_id,
2031
+ package_release_id,
2032
+ created_at: (/* @__PURE__ */ new Date()).toISOString(),
2033
+ updated_at: (/* @__PURE__ */ new Date()).toISOString(),
2034
+ completed_at: null,
2035
+ error: null,
2036
+ has_error: false,
2037
+ is_completed: false,
2038
+ is_processing: true,
2039
+ vendor_name,
2040
+ quoted_components: [],
2041
+ bare_pcb_cost: 0,
2042
+ shipping_options: [],
2043
+ total_cost: 0
2044
+ };
2045
+ set((state) => {
2046
+ return {
2047
+ orderQuotes: [...state.orderQuotes, newOrderQuote],
2048
+ idCounter: state.idCounter + 1
2049
+ };
2050
+ });
2051
+ return newOrderQuote.order_quote_id;
2052
+ },
2053
+ getOrderQuoteById: (orderQuoteId) => {
2054
+ const state = get();
2055
+ return state.orderQuotes.find(
2056
+ (quote) => quote.order_quote_id === orderQuoteId
2057
+ );
2058
+ },
2023
2059
  getJlcpcbOrderStatesByOrderId: (orderId) => {
2024
2060
  const state = get();
2025
2061
  return state.jlcpcbOrderState.find((state2) => state2.order_id === orderId);
@@ -6,11 +6,12 @@ import { combine } from "zustand/middleware"
6
6
  import {
7
7
  type Account,
8
8
  type AccountPackage,
9
- JlcpcbOrderState,
10
- JlcpcbOrderStepRun,
9
+ type JlcpcbOrderState,
10
+ type JlcpcbOrderStepRun,
11
11
  type LoginPage,
12
12
  type Order,
13
13
  type OrderFile,
14
+ OrderQuote,
14
15
  type Package,
15
16
  type PackageFile,
16
17
  type PackageRelease,
@@ -51,6 +52,47 @@ const initializer = combine(databaseSchema.parse({}), (set, get) => ({
51
52
  const state = get()
52
53
  return state.orderFiles.filter((file) => file.order_id === orderId)
53
54
  },
55
+ addOrderQuote: ({
56
+ account_id,
57
+ package_release_id,
58
+ vendor_name,
59
+ }: {
60
+ account_id: string
61
+ package_release_id: string
62
+ vendor_name: string
63
+ }): string => {
64
+ // Details for the order quote will be updated by the job with the cost
65
+ const newOrderQuote = {
66
+ order_quote_id: `order_quote_${get().idCounter + 1}`,
67
+ account_id,
68
+ package_release_id,
69
+ created_at: new Date().toISOString(),
70
+ updated_at: new Date().toISOString(),
71
+ completed_at: null,
72
+ error: null,
73
+ has_error: false,
74
+ is_completed: false,
75
+ is_processing: true,
76
+ vendor_name,
77
+ quoted_components: [],
78
+ bare_pcb_cost: 0,
79
+ shipping_options: [],
80
+ total_cost: 0,
81
+ }
82
+ set((state) => {
83
+ return {
84
+ orderQuotes: [...state.orderQuotes, newOrderQuote],
85
+ idCounter: state.idCounter + 1,
86
+ }
87
+ })
88
+ return newOrderQuote.order_quote_id
89
+ },
90
+ getOrderQuoteById: (orderQuoteId: string): OrderQuote | undefined => {
91
+ const state = get()
92
+ return state.orderQuotes.find(
93
+ (quote) => quote.order_quote_id === orderQuoteId,
94
+ )
95
+ },
54
96
  getJlcpcbOrderStatesByOrderId: (
55
97
  orderId: string,
56
98
  ): JlcpcbOrderState | undefined => {
@@ -0,0 +1,26 @@
1
+ import { withRouteSpec } from "fake-snippets-api/lib/middleware/with-winter-spec"
2
+ import { z } from "zod"
3
+
4
+ export default withRouteSpec({
5
+ methods: ["POST"],
6
+ auth: "session",
7
+ jsonBody: z.object({
8
+ package_release_id: z.string(),
9
+ vendor_name: z.string(),
10
+ }),
11
+ jsonResponse: z.object({
12
+ order_quote_id: z.string(),
13
+ }),
14
+ })(async (req, ctx) => {
15
+ const { package_release_id, vendor_name } = req.jsonBody
16
+
17
+ const orderQuoteId = ctx.db.addOrderQuote({
18
+ account_id: ctx.auth.account_id,
19
+ package_release_id,
20
+ vendor_name,
21
+ })
22
+
23
+ return ctx.json({
24
+ order_quote_id: orderQuoteId,
25
+ })
26
+ })
@@ -0,0 +1,30 @@
1
+ import { withRouteSpec } from "fake-snippets-api/lib/middleware/with-winter-spec"
2
+ import { z } from "zod"
3
+
4
+ export default withRouteSpec({
5
+ methods: ["POST"],
6
+ auth: "session",
7
+ jsonBody: z.object({
8
+ package_release_id: z.string(),
9
+ }),
10
+ jsonResponse: z.object({
11
+ order_quote_ids: z.array(z.string()),
12
+ }),
13
+ })(async (req, ctx) => {
14
+ const { package_release_id } = req.jsonBody
15
+ const vendorNames = ["JLCPCB", "MacroFab"]
16
+
17
+ let orderQuoteIds = []
18
+ for (const vendorName of vendorNames) {
19
+ const orderQuoteId = ctx.db.addOrderQuote({
20
+ account_id: ctx.auth.account_id,
21
+ package_release_id,
22
+ vendor_name: vendorName,
23
+ })
24
+ orderQuoteIds.push(orderQuoteId)
25
+ }
26
+
27
+ return ctx.json({
28
+ order_quote_ids: orderQuoteIds,
29
+ })
30
+ })
@@ -0,0 +1,32 @@
1
+ import { withRouteSpec } from "fake-snippets-api/lib/middleware/with-winter-spec"
2
+ import { z } from "zod"
3
+ import { orderQuoteSchema } from "fake-snippets-api/lib/db/schema"
4
+
5
+ export default withRouteSpec({
6
+ methods: ["POST"],
7
+ auth: "session",
8
+ jsonBody: z.object({
9
+ order_quote_id: z.string(),
10
+ }),
11
+ jsonResponse: z.object({
12
+ order_quote: orderQuoteSchema.optional(),
13
+ error: z.string().optional(),
14
+ }),
15
+ })(async (req, ctx) => {
16
+ const { order_quote_id } = req.jsonBody
17
+
18
+ const orderQuote = ctx.db.getOrderQuoteById(order_quote_id)
19
+
20
+ if (!orderQuote) {
21
+ return ctx.json(
22
+ {
23
+ error: "Order quote not found",
24
+ },
25
+ { status: 404 },
26
+ )
27
+ }
28
+
29
+ return ctx.json({
30
+ order_quote: orderQuote,
31
+ })
32
+ })
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tscircuit/fake-snippets",
3
- "version": "0.0.41",
3
+ "version": "0.0.43",
4
4
  "type": "module",
5
5
  "repository": {
6
6
  "type": "git",
@@ -134,9 +134,9 @@
134
134
  "@babel/standalone": "^7.26.2",
135
135
  "@biomejs/biome": "^1.9.2",
136
136
  "@playwright/test": "^1.48.0",
137
- "@tscircuit/core": "^0.0.365",
137
+ "@tscircuit/core": "^0.0.370",
138
138
  "@tscircuit/prompt-benchmarks": "^0.0.28",
139
- "@tscircuit/runframe": "^0.0.316",
139
+ "@tscircuit/runframe": "^0.0.330",
140
140
  "@types/babel__standalone": "^7.1.7",
141
141
  "@types/bun": "^1.1.10",
142
142
  "@types/country-list": "^2.1.4",
@@ -336,13 +336,16 @@ export default function EditorNav({
336
336
  <File className="mr-2 h-3 w-3" />
337
337
  View Files
338
338
  </DropdownMenuItem>
339
- <DropdownMenuItem
340
- className="text-xs"
341
- onClick={() => openupdateDescriptionDialog()}
342
- >
343
- <FilePenLine className="mr-2 h-3 w-3" />
344
- Edit Description
345
- </DropdownMenuItem>
339
+ {snippet?.owner_name === session?.github_username && (
340
+ <DropdownMenuItem
341
+ className="text-xs"
342
+ onClick={() => openupdateDescriptionDialog()}
343
+ >
344
+ <FilePenLine className="mr-2 h-3 w-3" />
345
+ Edit Description
346
+ </DropdownMenuItem>
347
+ )}
348
+
346
349
  <DropdownMenuItem
347
350
  className="text-xs"
348
351
  onClick={() => openViewTsFilesDialog()}
@@ -350,60 +353,67 @@ export default function EditorNav({
350
353
  <File className="mr-2 h-3 w-3" />
351
354
  [Debug] View TS Files
352
355
  </DropdownMenuItem>
353
- <DropdownMenuSub>
354
- <DropdownMenuSubTrigger
355
- className="text-xs"
356
- disabled={isChangingType || hasUnsavedChanges}
357
- >
358
- <Edit2 className="mr-2 h-3 w-3" />
359
- {isChangingType ? "Changing..." : "Change Type"}
360
- </DropdownMenuSubTrigger>
361
- <DropdownMenuSubContent>
362
- <DropdownMenuItem
363
- className="text-xs"
364
- disabled={currentType === "board" || isChangingType}
365
- onClick={() => handleTypeChange("board")}
366
- >
367
- Board {currentType === "board" && "✓"}
368
- </DropdownMenuItem>
369
- <DropdownMenuItem
370
- className="text-xs"
371
- disabled={currentType === "package" || isChangingType}
372
- onClick={() => handleTypeChange("package")}
373
- >
374
- Module {currentType === "package" && "✓"}
375
- </DropdownMenuItem>
376
- </DropdownMenuSubContent>
377
- </DropdownMenuSub>
378
- <DropdownMenuSub>
379
- <DropdownMenuSubTrigger className="text-xs">
380
- <Edit2 className="mr-2 h-3 w-3" />
381
- Change Package Visibility
382
- </DropdownMenuSubTrigger>
383
- <DropdownMenuSubContent>
356
+ {snippet?.owner_name === session?.github_username && (
357
+ <>
358
+ <DropdownMenuSub>
359
+ <DropdownMenuSubTrigger
360
+ className="text-xs"
361
+ disabled={isChangingType || hasUnsavedChanges}
362
+ >
363
+ <Edit2 className="mr-2 h-3 w-3" />
364
+ {isChangingType ? "Changing..." : "Change Type"}
365
+ </DropdownMenuSubTrigger>
366
+ <DropdownMenuSubContent>
367
+ <DropdownMenuItem
368
+ className="text-xs"
369
+ disabled={currentType === "board" || isChangingType}
370
+ onClick={() => handleTypeChange("board")}
371
+ >
372
+ Board {currentType === "board" && "✓"}
373
+ </DropdownMenuItem>
374
+ <DropdownMenuItem
375
+ className="text-xs"
376
+ disabled={currentType === "package" || isChangingType}
377
+ onClick={() => handleTypeChange("package")}
378
+ >
379
+ Module {currentType === "package" && "✓"}
380
+ </DropdownMenuItem>
381
+ </DropdownMenuSubContent>
382
+ </DropdownMenuSub>
383
+ <DropdownMenuSub>
384
+ <DropdownMenuSubTrigger className="text-xs">
385
+ <Edit2 className="mr-2 h-3 w-3" />
386
+ Change Package Visibility
387
+ </DropdownMenuSubTrigger>
388
+ <DropdownMenuSubContent>
389
+ <DropdownMenuItem
390
+ className="text-xs"
391
+ disabled={isPrivate}
392
+ onClick={() => updatePackageVisibilityToPrivate(true)}
393
+ >
394
+ Private {isPrivate && "✓"}
395
+ </DropdownMenuItem>
396
+ <DropdownMenuItem
397
+ className="text-xs"
398
+ disabled={!isPrivate}
399
+ onClick={() =>
400
+ updatePackageVisibilityToPrivate(false)
401
+ }
402
+ >
403
+ Public {!isPrivate && "✓"}
404
+ </DropdownMenuItem>
405
+ </DropdownMenuSubContent>
406
+ </DropdownMenuSub>
384
407
  <DropdownMenuItem
385
- className="text-xs"
386
- disabled={isPrivate}
387
- onClick={() => updatePackageVisibilityToPrivate(true)}
408
+ className="text-xs text-red-600"
409
+ onClick={() => openDeleteDialog()}
388
410
  >
389
- Private {isPrivate && "✓"}
411
+ <Trash2 className="mr-2 h-3 w-3" />
412
+ Delete Snippet
390
413
  </DropdownMenuItem>
391
- <DropdownMenuItem
392
- className="text-xs"
393
- disabled={!isPrivate}
394
- onClick={() => updatePackageVisibilityToPrivate(false)}
395
- >
396
- Public {!isPrivate && "✓"}
397
- </DropdownMenuItem>
398
- </DropdownMenuSubContent>
399
- </DropdownMenuSub>
400
- <DropdownMenuItem
401
- className="text-xs text-red-600"
402
- onClick={() => openDeleteDialog()}
403
- >
404
- <Trash2 className="mr-2 h-3 w-3" />
405
- Delete Snippet
406
- </DropdownMenuItem>
414
+ </>
415
+ )}
416
+
407
417
  <DropdownMenuItem className="text-xs text-gray-500" disabled>
408
418
  @tscircuit/core@{tscircuitCorePkg.version}
409
419
  </DropdownMenuItem>
@@ -222,7 +222,12 @@ export default function ImportantFilesView({
222
222
  activeFilePath.endsWith(".jsx") ||
223
223
  activeFilePath.endsWith(".ts") ||
224
224
  activeFilePath.endsWith(".tsx")) ? (
225
- <ShikiCodeViewer code={activeFileContent} filePath={activeFilePath} />
225
+ <div className="overflow-x-auto">
226
+ <ShikiCodeViewer
227
+ code={activeFileContent}
228
+ filePath={activeFilePath}
229
+ />
230
+ </div>
226
231
  ) : (
227
232
  <pre className="whitespace-pre-wrap">{activeFileContent}</pre>
228
233
  )}
@@ -69,17 +69,20 @@ export default function PackageHeader({
69
69
  return (
70
70
  <header className="bg-white border-b border-gray-200 py-4">
71
71
  <div className="max-w-[1200px] mx-auto px-4">
72
- <div className="flex items-center justify-between">
73
- <div className="flex items-center">
72
+ <div className="flex items-center justify-between flex-wrap gap-y-2">
73
+ <div className="flex items-center min-w-0 flex-wrap">
74
74
  {author && packageName ? (
75
75
  <>
76
- <h1 className="text-xl font-bold mr-2">
77
- <Link href={`/${author}`} className="text-blue-600">
76
+ <h1 className="text-lg md:text-xl font-bold mr-2 break-words">
77
+ <Link
78
+ href={`/${author}`}
79
+ className="text-blue-600 hover:underline"
80
+ >
78
81
  {author}
79
82
  </Link>
80
83
  <span className="px-1 text-gray-500">/</span>
81
84
  <Link
82
- className="text-blue-600"
85
+ className="text-blue-600 hover:underline"
83
86
  href={`/${author}/${packageName}`}
84
87
  >
85
88
  {packageName}
@@ -117,6 +120,37 @@ export default function PackageHeader({
117
120
  )}
118
121
  </Button>
119
122
 
123
+ <Button
124
+ variant="outline"
125
+ size="sm"
126
+ onClick={handleForkClick}
127
+ disabled={
128
+ isCurrentUserAuthor || isForkLoading || !packageInfo?.package_id
129
+ }
130
+ >
131
+ <GitFork className="w-4 h-4 mr-2" />
132
+ Fork
133
+ </Button>
134
+ </div>
135
+ {/* Mobile buttons - shown below md breakpoint */}
136
+ <div className="flex items-center space-x-2 md:hidden w-full justify-end pt-2">
137
+ <Button
138
+ variant="outline"
139
+ size="sm"
140
+ onClick={handleStarClick}
141
+ disabled={isStarLoading || !packageInfo?.name}
142
+ >
143
+ <Star
144
+ className={`w-4 h-4 mr-2 ${starData?.is_starred ? "fill-yellow-500 text-yellow-500" : ""}`}
145
+ />
146
+ {starData?.is_starred ? "Starred" : "Star"}
147
+ {(starData?.star_count ?? 0) > 0 && (
148
+ <span className="ml-1.5 bg-gray-100 text-gray-700 rounded-full px-1.5 py-0.5 text-xs font-medium">
149
+ {starData?.star_count}
150
+ </span>
151
+ )}
152
+ </Button>
153
+
120
154
  <Button
121
155
  variant="outline"
122
156
  size="sm"
@@ -201,6 +201,7 @@ export default function RepoPageContent({
201
201
  {/* Sidebar - Hidden on mobile, shown on md and up */}
202
202
  <div className="hidden md:block md:w-[296px] flex-shrink-0">
203
203
  <Sidebar
204
+ packageInfo={packageInfo}
204
205
  isLoading={!packageInfo}
205
206
  onViewChange={(view) => {
206
207
  setActiveView(view)