@tscircuit/fake-snippets 0.0.26 → 0.0.28

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.
Files changed (58) hide show
  1. package/bun-tests/fake-snippets-api/routes/package_files/create.test.ts +5 -6
  2. package/bun-tests/fake-snippets-api/routes/packages/list-1.test.ts +3 -0
  3. package/bun-tests/fake-snippets-api/routes/packages/list-2.test.ts +2 -0
  4. package/bun-tests/fake-snippets-api/routes/snippets/list_newest.test.ts +5 -3
  5. package/bun-tests/fake-snippets-api/routes/snippets/list_trending.test.ts +8 -5
  6. package/bun-tests/fake-snippets-api/routes/snippets/update.test.ts +1 -1
  7. package/bun.lock +110 -5
  8. package/dist/bundle.js +62 -11
  9. package/dist/index.d.ts +5 -0
  10. package/dist/index.js +4 -2
  11. package/fake-snippets-api/lib/db/autoload-snippets.json +4 -0
  12. package/fake-snippets-api/lib/db/db-client.ts +2 -1
  13. package/fake-snippets-api/lib/db/schema.ts +1 -0
  14. package/fake-snippets-api/lib/public-mapping/public-map-package.ts +1 -0
  15. package/fake-snippets-api/routes/api/package_files/list.ts +6 -3
  16. package/fake-snippets-api/routes/api/package_releases/get.ts +67 -1
  17. package/fake-snippets-api/routes/api/packages/create.ts +2 -1
  18. package/fake-snippets-api/routes/api/snippets/create.ts +1 -0
  19. package/package.json +2 -1
  20. package/public/placeholder-logo.png +0 -0
  21. package/public/placeholder-logo.svg +1 -0
  22. package/public/placeholder-user.jpg +0 -0
  23. package/public/placeholder.jpg +0 -0
  24. package/public/placeholder.svg +1 -0
  25. package/src/App.tsx +6 -0
  26. package/src/components/ViewPackagePage/components/ShikiCodeViewer.tsx +50 -0
  27. package/src/components/ViewPackagePage/components/file-explorer.tsx +118 -0
  28. package/src/components/ViewPackagePage/components/important-files-view.tsx +231 -0
  29. package/src/components/ViewPackagePage/components/main-content-header.tsx +172 -0
  30. package/src/components/ViewPackagePage/components/main-content-view-selector.tsx +106 -0
  31. package/src/components/ViewPackagePage/components/mobile-sidebar.tsx +130 -0
  32. package/src/components/ViewPackagePage/components/package-header.tsx +107 -0
  33. package/src/components/ViewPackagePage/components/preview-image-squares.tsx +63 -0
  34. package/src/components/ViewPackagePage/components/readme-view.tsx +58 -0
  35. package/src/components/ViewPackagePage/components/repo-header-button.tsx +36 -0
  36. package/src/components/ViewPackagePage/components/repo-header.tsx +4 -0
  37. package/src/components/ViewPackagePage/components/repo-page-content.tsx +213 -0
  38. package/src/components/ViewPackagePage/components/repo-tab-header.tsx +12 -0
  39. package/src/components/ViewPackagePage/components/sidebar-about-section.tsx +103 -0
  40. package/src/components/ViewPackagePage/components/sidebar-contributors-section.tsx +31 -0
  41. package/src/components/ViewPackagePage/components/sidebar-packages-section.tsx +16 -0
  42. package/src/components/ViewPackagePage/components/sidebar-releases-section.tsx +44 -0
  43. package/src/components/ViewPackagePage/components/sidebar.tsx +40 -0
  44. package/src/components/ViewPackagePage/components/tab-views/3d-view.tsx +9 -0
  45. package/src/components/ViewPackagePage/components/tab-views/bom-view.tsx +9 -0
  46. package/src/components/ViewPackagePage/components/tab-views/files-view.tsx +166 -0
  47. package/src/components/ViewPackagePage/components/tab-views/pcb-view.tsx +9 -0
  48. package/src/components/ViewPackagePage/components/tab-views/schematic-view.tsx +9 -0
  49. package/src/components/ViewPackagePage/components/theme-toggle.tsx +42 -0
  50. package/src/components/ViewPackagePage/hooks/use-mobile.tsx +19 -0
  51. package/src/components/ViewPackagePage/hooks/use-toast.ts +191 -0
  52. package/src/components/ViewPackagePage/simulate-page.tsx +120 -0
  53. package/src/components/ViewPackagePage/utils/is-package-file-important.ts +21 -0
  54. package/src/hooks/use-package-files.ts +29 -0
  55. package/src/hooks/use-package-release.ts +22 -0
  56. package/src/index.css +15 -0
  57. package/src/pages/beta.tsx +282 -99
  58. package/src/pages/view-package.tsx +38 -0
package/dist/index.d.ts CHANGED
@@ -355,6 +355,7 @@ declare const packageSchema: z.ZodObject<{
355
355
  license: z.ZodNullable<z.ZodString>;
356
356
  star_count: z.ZodDefault<z.ZodNumber>;
357
357
  ai_description: z.ZodNullable<z.ZodString>;
358
+ ai_usage_instructions: z.ZodNullable<z.ZodString>;
358
359
  }, "strip", z.ZodTypeAny, {
359
360
  name: string;
360
361
  unscoped_name: string;
@@ -379,6 +380,7 @@ declare const packageSchema: z.ZodObject<{
379
380
  latest_package_release_id: string | null;
380
381
  latest_version: string | null;
381
382
  ai_description: string | null;
383
+ ai_usage_instructions: string | null;
382
384
  snippet_type?: "board" | "package" | "model" | "footprint" | undefined;
383
385
  }, {
384
386
  name: string;
@@ -394,6 +396,7 @@ declare const packageSchema: z.ZodObject<{
394
396
  latest_package_release_id: string | null;
395
397
  latest_version: string | null;
396
398
  ai_description: string | null;
399
+ ai_usage_instructions: string | null;
397
400
  snippet_type?: "board" | "package" | "model" | "footprint" | undefined;
398
401
  star_count?: number | undefined;
399
402
  is_private?: boolean | null | undefined;
@@ -605,6 +608,7 @@ declare const createDatabase: ({ seed }?: {
605
608
  latest_package_release_id: string | null;
606
609
  latest_version: string | null;
607
610
  ai_description: string | null;
611
+ ai_usage_instructions: string | null;
608
612
  snippet_type?: "board" | "package" | "model" | "footprint" | undefined;
609
613
  }[];
610
614
  orders: {
@@ -842,6 +846,7 @@ declare const createDatabase: ({ seed }?: {
842
846
  latest_package_release_id: string | null;
843
847
  latest_version: string | null;
844
848
  ai_description: string | null;
849
+ ai_usage_instructions: string | null;
845
850
  snippet_type?: "board" | "package" | "model" | "footprint" | undefined;
846
851
  }[];
847
852
  orders: {
package/dist/index.js CHANGED
@@ -144,7 +144,8 @@ var packageSchema = z.object({
144
144
  latest_version: z.string().nullable(),
145
145
  license: z.string().nullable(),
146
146
  star_count: z.number().default(0),
147
- ai_description: z.string().nullable()
147
+ ai_description: z.string().nullable(),
148
+ ai_usage_instructions: z.string().nullable()
148
149
  });
149
150
  var jlcpcbOrderStateSchema = z.object({
150
151
  jlcpcb_order_state_id: z.string(),
@@ -2016,7 +2017,8 @@ var initializer = combine(databaseSchema.parse({}), (set, get) => ({
2016
2017
  star_count: 0,
2017
2018
  created_at: currentTime,
2018
2019
  updated_at: currentTime,
2019
- ai_description: null,
2020
+ ai_description: "placeholder ai description",
2021
+ ai_usage_instructions: "placeholder ai usage instructions",
2020
2022
  is_snippet: true,
2021
2023
  is_board: snippet.snippet_type === "board",
2022
2024
  is_package: snippet.snippet_type === "package",
@@ -16,6 +16,10 @@
16
16
  "owner": "seveibar",
17
17
  "name": "usb-c-flashlight"
18
18
  },
19
+ {
20
+ "owner": "seveibar",
21
+ "name": "nine-key-keyboard"
22
+ },
19
23
  {
20
24
  "owner": "AnasSarkiz",
21
25
  "name": "grid-of-LEDs-with-an-ESP32"
@@ -216,7 +216,8 @@ const initializer = combine(databaseSchema.parse({}), (set, get) => ({
216
216
  star_count: 0,
217
217
  created_at: currentTime,
218
218
  updated_at: currentTime,
219
- ai_description: null,
219
+ ai_description: "placeholder ai description",
220
+ ai_usage_instructions: "placeholder ai usage instructions",
220
221
  is_snippet: true,
221
222
  is_board: snippet.snippet_type === "board",
222
223
  is_package: snippet.snippet_type === "package",
@@ -166,6 +166,7 @@ export const packageSchema = z.object({
166
166
  license: z.string().nullable(),
167
167
  star_count: z.number().default(0),
168
168
  ai_description: z.string().nullable(),
169
+ ai_usage_instructions: z.string().nullable(),
169
170
  })
170
171
  export type Package = z.infer<typeof packageSchema>
171
172
 
@@ -16,6 +16,7 @@ export const publicMapPackage = (internalPackage: {
16
16
  updated_at: string
17
17
  created_at: string
18
18
  ai_description: string | null
19
+ ai_usage_instructions: string | null
19
20
  is_snippet: boolean
20
21
  is_board: boolean
21
22
  is_package: boolean
@@ -37,9 +37,12 @@ export default withRouteSpec(routeSpec)(async (req, ctx) => {
37
37
  })
38
38
  }
39
39
 
40
- const packageFiles = ctx.db.packageFiles.filter(
41
- (file) => file.package_release_id === packageReleaseId,
42
- )
40
+ const packageFiles = ctx.db.packageFiles
41
+ .filter((file) => file.package_release_id === packageReleaseId)
42
+ .map((file) => ({
43
+ ...file,
44
+ content_text: undefined,
45
+ }))
43
46
 
44
47
  return ctx.json({
45
48
  ok: true,
@@ -9,13 +9,79 @@ export default withRouteSpec({
9
9
  jsonBody: z.object({
10
10
  package_release_id: z.string().optional(),
11
11
  package_name_with_version: z.string().optional(),
12
+ package_name: z.string().optional(),
13
+ package_id: z.string().optional(),
14
+ is_latest: z.boolean().optional(),
12
15
  }),
13
16
  jsonResponse: z.object({
14
17
  ok: z.boolean(),
15
18
  package_release: zt.packageReleaseSchema,
16
19
  }),
17
20
  })(async (req, ctx) => {
18
- const { package_release_id, package_name_with_version } = req.jsonBody
21
+ const {
22
+ package_release_id,
23
+ package_name_with_version,
24
+ package_name,
25
+ package_id,
26
+ is_latest,
27
+ } = req.jsonBody
28
+
29
+ // Handle package_name with is_latest
30
+ if (package_name && is_latest === true) {
31
+ const pkg = ctx.db.packages.find((x) => x.name === package_name)
32
+
33
+ if (!pkg) {
34
+ return ctx.error(404, {
35
+ error_code: "package_not_found",
36
+ message: "Package not found",
37
+ })
38
+ }
39
+
40
+ // Sort releases by version to find the latest one
41
+ const packageReleases = ctx.db.packageReleases
42
+ .filter((x) => x.package_id === pkg.package_id)
43
+ .sort((a, b) => {
44
+ return (
45
+ new Date(b.created_at).getTime() - new Date(a.created_at).getTime()
46
+ )
47
+ })
48
+
49
+ if (packageReleases.length === 0) {
50
+ return ctx.error(404, {
51
+ error_code: "package_release_not_found",
52
+ message: "No releases found for this package",
53
+ })
54
+ }
55
+
56
+ return ctx.json({
57
+ ok: true,
58
+ package_release: publicMapPackageRelease(packageReleases[0]),
59
+ })
60
+ }
61
+
62
+ // Handle package_id with is_latest
63
+ if (package_id && is_latest === true) {
64
+ // Sort releases by version to find the latest one
65
+ const packageReleases = ctx.db.packageReleases
66
+ .filter((x) => x.package_id === package_id)
67
+ .sort((a, b) => {
68
+ return (
69
+ new Date(b.created_at).getTime() - new Date(a.created_at).getTime()
70
+ )
71
+ })
72
+
73
+ if (packageReleases.length === 0) {
74
+ return ctx.error(404, {
75
+ error_code: "package_release_not_found",
76
+ message: "No releases found for this package",
77
+ })
78
+ }
79
+
80
+ return ctx.json({
81
+ ok: true,
82
+ package_release: publicMapPackageRelease(packageReleases[0]),
83
+ })
84
+ }
19
85
 
20
86
  if (package_name_with_version && !package_release_id) {
21
87
  const [packageName, parsedVersion] = package_name_with_version.split("@")
@@ -47,10 +47,11 @@ export default withRouteSpec({
47
47
  updated_at: new Date().toISOString(),
48
48
  unscoped_name: name,
49
49
  star_count: 0,
50
- ai_description: name,
50
+ ai_description: "placeholder ai description",
51
51
  is_private: is_private ?? false,
52
52
  is_public: is_private === true ? false : true,
53
53
  is_unlisted: is_private === true ? true : (is_unlisted ?? false),
54
+ ai_usage_instructions: "placeholder ai usage instructions",
54
55
  })
55
56
 
56
57
  if (!newPackage) {
@@ -92,6 +92,7 @@ export default withRouteSpec({
92
92
  is_public: is_public || true,
93
93
  is_unlisted: is_unlisted || false,
94
94
  latest_package_release_id: `package_release_${timestamp}`,
95
+ ai_usage_instructions: "placeholder ai usage instructions",
95
96
  }
96
97
 
97
98
  ctx.db.addPackage(newPackage)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tscircuit/fake-snippets",
3
- "version": "0.0.26",
3
+ "version": "0.0.28",
4
4
  "type": "module",
5
5
  "repository": {
6
6
  "type": "git",
@@ -159,6 +159,7 @@
159
159
  "react": "^18.3.1",
160
160
  "redaxios": "^0.5.1",
161
161
  "sharp": "^0.33.5",
162
+ "shiki": "^3.2.1",
162
163
  "tailwindcss": "^3.4.13",
163
164
  "terser": "^5.27.0",
164
165
  "tsup": "^8.3.5",
Binary file
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="215" height="48" fill="none"><path fill="#000" d="M57.588 9.6h6L73.828 38h-5.2l-2.36-6.88h-11.36L52.548 38h-5.2l10.24-28.4Zm7.16 17.16-4.16-12.16-4.16 12.16h8.32Zm23.694-2.24c-.186-1.307-.706-2.32-1.56-3.04-.853-.72-1.866-1.08-3.04-1.08-1.68 0-2.986.613-3.92 1.84-.906 1.227-1.36 2.947-1.36 5.16s.454 3.933 1.36 5.16c.934 1.227 2.24 1.84 3.92 1.84 1.254 0 2.307-.373 3.16-1.12.854-.773 1.387-1.867 1.6-3.28l5.12.24c-.186 1.68-.733 3.147-1.64 4.4-.906 1.227-2.08 2.173-3.52 2.84-1.413.667-2.986 1-4.72 1-2.08 0-3.906-.453-5.48-1.36-1.546-.907-2.76-2.2-3.64-3.88-.853-1.68-1.28-3.627-1.28-5.84 0-2.24.427-4.187 1.28-5.84.88-1.68 2.094-2.973 3.64-3.88 1.574-.907 3.4-1.36 5.48-1.36 1.68 0 3.227.32 4.64.96 1.414.64 2.56 1.56 3.44 2.76.907 1.2 1.454 2.6 1.64 4.2l-5.12.28Zm11.486-7.72.12 3.4c.534-1.227 1.307-2.173 2.32-2.84 1.04-.693 2.267-1.04 3.68-1.04 1.494 0 2.76.387 3.8 1.16 1.067.747 1.827 1.813 2.28 3.2.507-1.44 1.294-2.52 2.36-3.24 1.094-.747 2.414-1.12 3.96-1.12 1.414 0 2.64.307 3.68.92s1.84 1.52 2.4 2.72c.56 1.2.84 2.667.84 4.4V38h-4.96V25.92c0-1.813-.293-3.187-.88-4.12-.56-.96-1.413-1.44-2.56-1.44-.906 0-1.68.213-2.32.64-.64.427-1.133 1.053-1.48 1.88-.32.827-.48 1.84-.48 3.04V38h-4.56V25.92c0-1.2-.133-2.213-.4-3.04-.24-.827-.626-1.453-1.16-1.88-.506-.427-1.133-.64-1.88-.64-.906 0-1.68.227-2.32.68-.64.427-1.133 1.053-1.48 1.88-.32.827-.48 1.827-.48 3V38h-4.96V16.8h4.48Zm26.723 10.6c0-2.24.427-4.187 1.28-5.84.854-1.68 2.067-2.973 3.64-3.88 1.574-.907 3.4-1.36 5.48-1.36 1.84 0 3.494.413 4.96 1.24 1.467.827 2.64 2.08 3.52 3.76.88 1.653 1.347 3.693 1.4 6.12v1.32h-15.08c.107 1.813.614 3.227 1.52 4.24.907.987 2.134 1.48 3.68 1.48.987 0 1.88-.253 2.68-.76a4.803 4.803 0 0 0 1.84-2.2l5.08.36c-.64 2.027-1.84 3.64-3.6 4.84-1.733 1.173-3.733 1.76-6 1.76-2.08 0-3.906-.453-5.48-1.36-1.573-.907-2.786-2.2-3.64-3.88-.853-1.68-1.28-3.627-1.28-5.84Zm15.16-2.04c-.213-1.733-.76-3.013-1.64-3.84-.853-.827-1.893-1.24-3.12-1.24-1.44 0-2.6.453-3.48 1.36-.88.88-1.44 2.12-1.68 3.72h9.92ZM163.139 9.6V38h-5.04V9.6h5.04Zm8.322 7.2.24 5.88-.64-.36c.32-2.053 1.094-3.56 2.32-4.52 1.254-.987 2.787-1.48 4.6-1.48 2.32 0 4.107.733 5.36 2.2 1.254 1.44 1.88 3.387 1.88 5.84V38h-4.96V25.92c0-1.253-.12-2.28-.36-3.08-.24-.8-.64-1.413-1.2-1.84-.533-.427-1.253-.64-2.16-.64-1.44 0-2.573.48-3.4 1.44-.8.933-1.2 2.307-1.2 4.12V38h-4.96V16.8h4.48Zm30.003 7.72c-.186-1.307-.706-2.32-1.56-3.04-.853-.72-1.866-1.08-3.04-1.08-1.68 0-2.986.613-3.92 1.84-.906 1.227-1.36 2.947-1.36 5.16s.454 3.933 1.36 5.16c.934 1.227 2.24 1.84 3.92 1.84 1.254 0 2.307-.373 3.16-1.12.854-.773 1.387-1.867 1.6-3.28l5.12.24c-.186 1.68-.733 3.147-1.64 4.4-.906 1.227-2.08 2.173-3.52 2.84-1.413.667-2.986 1-4.72 1-2.08 0-3.906-.453-5.48-1.36-1.546-.907-2.76-2.2-3.64-3.88-.853-1.68-1.28-3.627-1.28-5.84 0-2.24.427-4.187 1.28-5.84.88-1.68 2.094-2.973 3.64-3.88 1.574-.907 3.4-1.36 5.48-1.36 1.68 0 3.227.32 4.64.96 1.414.64 2.56 1.56 3.44 2.76.907 1.2 1.454 2.6 1.64 4.2l-5.12.28Zm11.443 8.16V38h-5.6v-5.32h5.6Z"/><path fill="#171717" fill-rule="evenodd" d="m7.839 40.783 16.03-28.054L20 6 0 40.783h7.839Zm8.214 0H40L27.99 19.894l-4.02 7.032 3.976 6.914H20.02l-3.967 6.943Z" clip-rule="evenodd"/></svg>
Binary file
Binary file
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="1200" height="1200" fill="none"><rect width="1200" height="1200" fill="#EAEAEA" rx="3"/><g opacity=".5"><g opacity=".5"><path fill="#FAFAFA" d="M600.709 736.5c-75.454 0-136.621-61.167-136.621-136.62 0-75.454 61.167-136.621 136.621-136.621 75.453 0 136.62 61.167 136.62 136.621 0 75.453-61.167 136.62-136.62 136.62Z"/><path stroke="#C9C9C9" stroke-width="2.418" d="M600.709 736.5c-75.454 0-136.621-61.167-136.621-136.62 0-75.454 61.167-136.621 136.621-136.621 75.453 0 136.62 61.167 136.62 136.621 0 75.453-61.167 136.62-136.62 136.62Z"/></g><path stroke="url(#a)" stroke-width="2.418" d="M0-1.209h553.581" transform="scale(1 -1) rotate(45 1163.11 91.165)"/><path stroke="url(#b)" stroke-width="2.418" d="M404.846 598.671h391.726"/><path stroke="url(#c)" stroke-width="2.418" d="M599.5 795.742V404.017"/><path stroke="url(#d)" stroke-width="2.418" d="m795.717 796.597-391.441-391.44"/><path fill="#fff" d="M600.709 656.704c-31.384 0-56.825-25.441-56.825-56.824 0-31.384 25.441-56.825 56.825-56.825 31.383 0 56.824 25.441 56.824 56.825 0 31.383-25.441 56.824-56.824 56.824Z"/><g clip-path="url(#e)"><path fill="#666" fill-rule="evenodd" d="M616.426 586.58h-31.434v16.176l3.553-3.554.531-.531h9.068l.074-.074 8.463-8.463h2.565l7.18 7.181V586.58Zm-15.715 14.654 3.698 3.699 1.283 1.282-2.565 2.565-1.282-1.283-5.2-5.199h-6.066l-5.514 5.514-.073.073v2.876a2.418 2.418 0 0 0 2.418 2.418h26.598a2.418 2.418 0 0 0 2.418-2.418v-8.317l-8.463-8.463-7.181 7.181-.071.072Zm-19.347 5.442v4.085a6.045 6.045 0 0 0 6.046 6.045h26.598a6.044 6.044 0 0 0 6.045-6.045v-7.108l1.356-1.355-1.282-1.283-.074-.073v-17.989h-38.689v23.43l-.146.146.146.147Z" clip-rule="evenodd"/></g><path stroke="#C9C9C9" stroke-width="2.418" d="M600.709 656.704c-31.384 0-56.825-25.441-56.825-56.824 0-31.384 25.441-56.825 56.825-56.825 31.383 0 56.824 25.441 56.824 56.825 0 31.383-25.441 56.824-56.824 56.824Z"/></g><defs><linearGradient id="a" x1="554.061" x2="-.48" y1=".083" y2=".087" gradientUnits="userSpaceOnUse"><stop stop-color="#C9C9C9" stop-opacity="0"/><stop offset=".208" stop-color="#C9C9C9"/><stop offset=".792" stop-color="#C9C9C9"/><stop offset="1" stop-color="#C9C9C9" stop-opacity="0"/></linearGradient><linearGradient id="b" x1="796.912" x2="404.507" y1="599.963" y2="599.965" gradientUnits="userSpaceOnUse"><stop stop-color="#C9C9C9" stop-opacity="0"/><stop offset=".208" stop-color="#C9C9C9"/><stop offset=".792" stop-color="#C9C9C9"/><stop offset="1" stop-color="#C9C9C9" stop-opacity="0"/></linearGradient><linearGradient id="c" x1="600.792" x2="600.794" y1="403.677" y2="796.082" gradientUnits="userSpaceOnUse"><stop stop-color="#C9C9C9" stop-opacity="0"/><stop offset=".208" stop-color="#C9C9C9"/><stop offset=".792" stop-color="#C9C9C9"/><stop offset="1" stop-color="#C9C9C9" stop-opacity="0"/></linearGradient><linearGradient id="d" x1="404.85" x2="796.972" y1="403.903" y2="796.02" gradientUnits="userSpaceOnUse"><stop stop-color="#C9C9C9" stop-opacity="0"/><stop offset=".208" stop-color="#C9C9C9"/><stop offset=".792" stop-color="#C9C9C9"/><stop offset="1" stop-color="#C9C9C9" stop-opacity="0"/></linearGradient><clipPath id="e"><path fill="#fff" d="M581.364 580.535h38.689v38.689h-38.689z"/></clipPath></defs></svg>
package/src/App.tsx CHANGED
@@ -71,6 +71,7 @@ const ViewOrderPage = lazyImport(() => import("@/pages/view-order"))
71
71
  const ViewSnippetPage = lazyImport(() => import("@/pages/view-snippet"))
72
72
  const DevLoginPage = lazyImport(() => import("@/pages/dev-login"))
73
73
  const BetaPage = lazyImport(() => import("@/pages/beta"))
74
+ const ViewPackagePage = lazyImport(() => import("@/pages/view-package"))
74
75
 
75
76
  class ErrorBoundary extends React.Component<
76
77
  { children: React.ReactNode },
@@ -101,6 +102,11 @@ function App() {
101
102
  <Switch>
102
103
  <Route path="/" component={LandingPage} />
103
104
  <Route path="/beta" component={BetaPage} />
105
+ <Route path="/beta/:author/:packageName" component={BetaPage} />
106
+ <Route
107
+ path="/view-package/:author/:packageName"
108
+ component={ViewPackagePage}
109
+ />
104
110
  <Route path="/editor" component={EditorPage} />
105
111
  <Route path="/quickstart" component={QuickstartPage} />
106
112
  <Route path="/dashboard" component={DashboardPage} />
@@ -0,0 +1,50 @@
1
+ import { useEffect, useMemo } from "react"
2
+ import { useQuery } from "react-query"
3
+ import { createHighlighter, Highlighter } from "shiki"
4
+
5
+ let globalHighlighter$: any
6
+ let globalHighlighter: Highlighter
7
+
8
+ const fileExtensionsToLanguages = {
9
+ ts: "typescript",
10
+ tsx: "typescript",
11
+ js: "javascript",
12
+ jsx: "javascript",
13
+ }
14
+
15
+ export const ShikiCodeViewer = ({
16
+ code,
17
+ filePath,
18
+ }: { code: string; filePath: string }) => {
19
+ useEffect(() => {
20
+ async function setupHighlighter() {
21
+ if (globalHighlighter$) return
22
+ globalHighlighter$ = await createHighlighter({
23
+ langs: ["typescript"],
24
+ themes: ["vitesse-light"],
25
+ })
26
+ globalHighlighter = await globalHighlighter$
27
+ }
28
+ setupHighlighter()
29
+ }, [])
30
+
31
+ const html = useMemo(
32
+ () =>
33
+ globalHighlighter?.codeToHtml(code, {
34
+ lang:
35
+ fileExtensionsToLanguages[
36
+ filePath.split(".").pop() as keyof typeof fileExtensionsToLanguages
37
+ ] || "typescript",
38
+ theme: "vitesse-light",
39
+ }),
40
+ [filePath, code, globalHighlighter],
41
+ )
42
+
43
+ if (!html) {
44
+ return <div>Loading...</div>
45
+ }
46
+
47
+ return (
48
+ <div className="text-sm shiki" dangerouslySetInnerHTML={{ __html: html }} />
49
+ )
50
+ }
@@ -0,0 +1,118 @@
1
+ import { Clock, FileText, Folder, Tag } from "lucide-react"
2
+
3
+ export default function FileExplorer() {
4
+ const files = [
5
+ {
6
+ type: "folder",
7
+ name: "lib",
8
+ message: "Utilities for parsing keyboard layouts",
9
+ time: "last week",
10
+ },
11
+ {
12
+ type: "folder",
13
+ name: "tests",
14
+ message: "Example keyboard configurations",
15
+ time: "2 days ago",
16
+ },
17
+ {
18
+ type: "file",
19
+ name: "LICENSE",
20
+ message: "MIT License",
21
+ time: "2 months ago",
22
+ },
23
+ {
24
+ type: "file",
25
+ name: "README.md",
26
+ message: "Overview of project",
27
+ time: "last month",
28
+ },
29
+ {
30
+ type: "file",
31
+ name: "biome.json",
32
+ message: "Formatting configuration",
33
+ time: "2 months ago",
34
+ },
35
+ {
36
+ type: "file",
37
+ name: "bun.lock",
38
+ message: "",
39
+ time: "2 days ago",
40
+ },
41
+ {
42
+ type: "file",
43
+ name: "package.json",
44
+ message: "Package dependencies",
45
+ time: "2 days ago",
46
+ },
47
+ {
48
+ type: "file",
49
+ name: "tsconfig.json",
50
+ message: "TypeScript configuration",
51
+ time: "2 months ago",
52
+ },
53
+ ]
54
+
55
+ return (
56
+ <div className="border border-gray-200 dark:border-[#30363d] rounded-md overflow-hidden">
57
+ <div className="flex items-center px-4 py-2 md:py-3 bg-gray-100 dark:bg-[#161b22] border-b border-gray-200 dark:border-[#30363d]">
58
+ {/* Desktop view */}
59
+ <div className="hidden md:flex items-center text-xs">
60
+ <Tag className="h-4 w-4 mr-1 text-gray-500 dark:text-[#8b949e]" />
61
+ <span className="text-gray-500 dark:text-[#8b949e]">v0.0.361</span>
62
+ <div className="ml-2 text-green-500 dark:text-[#3fb950]">✓</div>
63
+ </div>
64
+ <div className="hidden md:flex ml-auto items-center text-xs text-gray-500 dark:text-[#8b949e]">
65
+ <Clock className="h-4 w-4 mr-1" />
66
+ <span>2 days ago</span>
67
+ <div className="ml-4 flex items-center">
68
+ <Tag className="h-4 w-4 mr-1" />
69
+ <span>12 Releases</span>
70
+ </div>
71
+ </div>
72
+
73
+ {/* Mobile view */}
74
+ <div className="md:hidden flex items-center justify-between w-full">
75
+ <div className="flex items-center">
76
+ <span className="text-xs text-gray-500 dark:text-[#8b949e]">
77
+ v0.0.361
78
+ </span>
79
+ <div className="ml-1 text-green-500 dark:text-[#3fb950]">✓</div>
80
+ </div>
81
+ <div className="flex items-center space-x-3 text-xs text-gray-500 dark:text-[#8b949e]">
82
+ <div className="flex items-center">
83
+ <Clock className="h-3 w-3 mr-0.5" />
84
+ <span>2d</span>
85
+ </div>
86
+ <div className="flex items-center">
87
+ <Tag className="h-3 w-3 mr-0.5" />
88
+ <span>12</span>
89
+ </div>
90
+ </div>
91
+ </div>
92
+ </div>
93
+
94
+ {/* Files */}
95
+ <div className="bg-white dark:bg-[#0d1117]">
96
+ {files.map((file, index) => (
97
+ <div
98
+ key={index}
99
+ className="flex items-center px-4 py-2 hover:bg-gray-50 dark:hover:bg-[#161b22] border-b border-gray-200 dark:border-[#30363d]"
100
+ >
101
+ {file.type === "folder" ? (
102
+ <Folder className="h-4 w-4 mr-2 text-gray-500 dark:text-[#8b949e]" />
103
+ ) : (
104
+ <FileText className="h-4 w-4 mr-2 text-gray-500 dark:text-[#8b949e]" />
105
+ )}
106
+ <span className="text-sm">{file.name}</span>
107
+ <span className="ml-auto text-xs text-gray-500 dark:text-[#8b949e]">
108
+ {file.message}
109
+ </span>
110
+ <span className="ml-4 text-xs text-gray-500 dark:text-[#8b949e]">
111
+ {file.time}
112
+ </span>
113
+ </div>
114
+ ))}
115
+ </div>
116
+ </div>
117
+ )
118
+ }