@tscircuit/fake-snippets 0.0.27 → 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.
- package/bun-tests/fake-snippets-api/routes/package_files/create.test.ts +5 -6
- package/bun-tests/fake-snippets-api/routes/packages/list-1.test.ts +3 -0
- package/bun-tests/fake-snippets-api/routes/packages/list-2.test.ts +2 -0
- package/bun-tests/fake-snippets-api/routes/snippets/list_newest.test.ts +5 -3
- package/bun-tests/fake-snippets-api/routes/snippets/list_trending.test.ts +8 -5
- package/bun-tests/fake-snippets-api/routes/snippets/update.test.ts +1 -1
- package/bun.lock +110 -5
- package/dist/bundle.js +14 -9
- package/dist/index.d.ts +5 -0
- package/dist/index.js +4 -2
- package/fake-snippets-api/lib/db/autoload-snippets.json +4 -0
- package/fake-snippets-api/lib/db/db-client.ts +2 -1
- package/fake-snippets-api/lib/db/schema.ts +1 -0
- package/fake-snippets-api/lib/public-mapping/public-map-package.ts +1 -0
- package/fake-snippets-api/routes/api/package_files/list.ts +6 -3
- package/fake-snippets-api/routes/api/packages/create.ts +2 -1
- package/fake-snippets-api/routes/api/snippets/create.ts +1 -0
- package/package.json +2 -1
- package/public/placeholder-logo.png +0 -0
- package/public/placeholder-logo.svg +1 -0
- package/public/placeholder-user.jpg +0 -0
- package/public/placeholder.jpg +0 -0
- package/public/placeholder.svg +1 -0
- package/src/App.tsx +5 -0
- package/src/components/ViewPackagePage/components/ShikiCodeViewer.tsx +50 -0
- package/src/components/ViewPackagePage/components/file-explorer.tsx +118 -0
- package/src/components/ViewPackagePage/components/important-files-view.tsx +231 -0
- package/src/components/ViewPackagePage/components/main-content-header.tsx +172 -0
- package/src/components/ViewPackagePage/components/main-content-view-selector.tsx +106 -0
- package/src/components/ViewPackagePage/components/mobile-sidebar.tsx +130 -0
- package/src/components/ViewPackagePage/components/package-header.tsx +107 -0
- package/src/components/ViewPackagePage/components/preview-image-squares.tsx +63 -0
- package/src/components/ViewPackagePage/components/readme-view.tsx +58 -0
- package/src/components/ViewPackagePage/components/repo-header-button.tsx +36 -0
- package/src/components/ViewPackagePage/components/repo-header.tsx +4 -0
- package/src/components/ViewPackagePage/components/repo-page-content.tsx +213 -0
- package/src/components/ViewPackagePage/components/repo-tab-header.tsx +12 -0
- package/src/components/ViewPackagePage/components/sidebar-about-section.tsx +103 -0
- package/src/components/ViewPackagePage/components/sidebar-contributors-section.tsx +31 -0
- package/src/components/ViewPackagePage/components/sidebar-packages-section.tsx +16 -0
- package/src/components/ViewPackagePage/components/sidebar-releases-section.tsx +44 -0
- package/src/components/ViewPackagePage/components/sidebar.tsx +40 -0
- package/src/components/ViewPackagePage/components/tab-views/3d-view.tsx +9 -0
- package/src/components/ViewPackagePage/components/tab-views/bom-view.tsx +9 -0
- package/src/components/ViewPackagePage/components/tab-views/files-view.tsx +166 -0
- package/src/components/ViewPackagePage/components/tab-views/pcb-view.tsx +9 -0
- package/src/components/ViewPackagePage/components/tab-views/schematic-view.tsx +9 -0
- package/src/components/ViewPackagePage/components/theme-toggle.tsx +42 -0
- package/src/components/ViewPackagePage/hooks/use-mobile.tsx +19 -0
- package/src/components/ViewPackagePage/hooks/use-toast.ts +191 -0
- package/src/components/ViewPackagePage/simulate-page.tsx +120 -0
- package/src/components/ViewPackagePage/utils/is-package-file-important.ts +21 -0
- package/src/hooks/use-package-files.ts +1 -1
- package/src/index.css +15 -0
- package/src/pages/view-package.tsx +38 -0
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
"use client"
|
|
2
|
+
|
|
3
|
+
import { useTheme } from "next-themes"
|
|
4
|
+
import { Moon, Sun } from "lucide-react"
|
|
5
|
+
import { Button } from "@/components/ui/button"
|
|
6
|
+
import { useEffect, useState } from "react"
|
|
7
|
+
|
|
8
|
+
export default function ThemeToggle() {
|
|
9
|
+
const { theme, setTheme } = useTheme()
|
|
10
|
+
const [mounted, setMounted] = useState(false)
|
|
11
|
+
|
|
12
|
+
// Ensure component is mounted before accessing theme
|
|
13
|
+
useEffect(() => {
|
|
14
|
+
setMounted(true)
|
|
15
|
+
}, [])
|
|
16
|
+
|
|
17
|
+
if (!mounted) {
|
|
18
|
+
return (
|
|
19
|
+
<Button
|
|
20
|
+
variant="outline"
|
|
21
|
+
size="icon"
|
|
22
|
+
className="border-gray-300 dark:border-[#30363d] bg-gray-100 hover:bg-gray-200 dark:bg-[#21262d] dark:hover:bg-[#30363d] text-gray-700 dark:text-[#c9d1d9]"
|
|
23
|
+
>
|
|
24
|
+
<Sun className="h-4 w-4" />
|
|
25
|
+
<span className="sr-only">Toggle theme</span>
|
|
26
|
+
</Button>
|
|
27
|
+
)
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
return (
|
|
31
|
+
<Button
|
|
32
|
+
variant="outline"
|
|
33
|
+
size="icon"
|
|
34
|
+
className="border-gray-300 dark:border-[#30363d] bg-gray-100 hover:bg-gray-200 dark:bg-[#21262d] dark:hover:bg-[#30363d] text-gray-700 dark:text-[#c9d1d9]"
|
|
35
|
+
onClick={() => setTheme(theme === "dark" ? "light" : "dark")}
|
|
36
|
+
>
|
|
37
|
+
<Sun className="h-4 w-4 rotate-0 scale-100 transition-all dark:-rotate-90 dark:scale-0" />
|
|
38
|
+
<Moon className="absolute h-4 w-4 rotate-90 scale-0 transition-all dark:rotate-0 dark:scale-100" />
|
|
39
|
+
<span className="sr-only">Toggle theme</span>
|
|
40
|
+
</Button>
|
|
41
|
+
)
|
|
42
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import * as React from "react"
|
|
2
|
+
|
|
3
|
+
const MOBILE_BREAKPOINT = 768
|
|
4
|
+
|
|
5
|
+
export function useIsMobile() {
|
|
6
|
+
const [isMobile, setIsMobile] = React.useState<boolean | undefined>(undefined)
|
|
7
|
+
|
|
8
|
+
React.useEffect(() => {
|
|
9
|
+
const mql = window.matchMedia(`(max-width: ${MOBILE_BREAKPOINT - 1}px)`)
|
|
10
|
+
const onChange = () => {
|
|
11
|
+
setIsMobile(window.innerWidth < MOBILE_BREAKPOINT)
|
|
12
|
+
}
|
|
13
|
+
mql.addEventListener("change", onChange)
|
|
14
|
+
setIsMobile(window.innerWidth < MOBILE_BREAKPOINT)
|
|
15
|
+
return () => mql.removeEventListener("change", onChange)
|
|
16
|
+
}, [])
|
|
17
|
+
|
|
18
|
+
return !!isMobile
|
|
19
|
+
}
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
"use client"
|
|
2
|
+
|
|
3
|
+
// Inspired by react-hot-toast library
|
|
4
|
+
import * as React from "react"
|
|
5
|
+
|
|
6
|
+
import type { ToastActionElement, ToastProps } from "@/components/ui/toast"
|
|
7
|
+
|
|
8
|
+
const TOAST_LIMIT = 1
|
|
9
|
+
const TOAST_REMOVE_DELAY = 1000000
|
|
10
|
+
|
|
11
|
+
type ToasterToast = ToastProps & {
|
|
12
|
+
id: string
|
|
13
|
+
title?: React.ReactNode
|
|
14
|
+
description?: React.ReactNode
|
|
15
|
+
action?: ToastActionElement
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const actionTypes = {
|
|
19
|
+
ADD_TOAST: "ADD_TOAST",
|
|
20
|
+
UPDATE_TOAST: "UPDATE_TOAST",
|
|
21
|
+
DISMISS_TOAST: "DISMISS_TOAST",
|
|
22
|
+
REMOVE_TOAST: "REMOVE_TOAST",
|
|
23
|
+
} as const
|
|
24
|
+
|
|
25
|
+
let count = 0
|
|
26
|
+
|
|
27
|
+
function genId() {
|
|
28
|
+
count = (count + 1) % Number.MAX_SAFE_INTEGER
|
|
29
|
+
return count.toString()
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
type ActionType = typeof actionTypes
|
|
33
|
+
|
|
34
|
+
type Action =
|
|
35
|
+
| {
|
|
36
|
+
type: ActionType["ADD_TOAST"]
|
|
37
|
+
toast: ToasterToast
|
|
38
|
+
}
|
|
39
|
+
| {
|
|
40
|
+
type: ActionType["UPDATE_TOAST"]
|
|
41
|
+
toast: Partial<ToasterToast>
|
|
42
|
+
}
|
|
43
|
+
| {
|
|
44
|
+
type: ActionType["DISMISS_TOAST"]
|
|
45
|
+
toastId?: ToasterToast["id"]
|
|
46
|
+
}
|
|
47
|
+
| {
|
|
48
|
+
type: ActionType["REMOVE_TOAST"]
|
|
49
|
+
toastId?: ToasterToast["id"]
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
interface State {
|
|
53
|
+
toasts: ToasterToast[]
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const toastTimeouts = new Map<string, ReturnType<typeof setTimeout>>()
|
|
57
|
+
|
|
58
|
+
const addToRemoveQueue = (toastId: string) => {
|
|
59
|
+
if (toastTimeouts.has(toastId)) {
|
|
60
|
+
return
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const timeout = setTimeout(() => {
|
|
64
|
+
toastTimeouts.delete(toastId)
|
|
65
|
+
dispatch({
|
|
66
|
+
type: "REMOVE_TOAST",
|
|
67
|
+
toastId: toastId,
|
|
68
|
+
})
|
|
69
|
+
}, TOAST_REMOVE_DELAY)
|
|
70
|
+
|
|
71
|
+
toastTimeouts.set(toastId, timeout)
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export const reducer = (state: State, action: Action): State => {
|
|
75
|
+
switch (action.type) {
|
|
76
|
+
case "ADD_TOAST":
|
|
77
|
+
return {
|
|
78
|
+
...state,
|
|
79
|
+
toasts: [action.toast, ...state.toasts].slice(0, TOAST_LIMIT),
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
case "UPDATE_TOAST":
|
|
83
|
+
return {
|
|
84
|
+
...state,
|
|
85
|
+
toasts: state.toasts.map((t) =>
|
|
86
|
+
t.id === action.toast.id ? { ...t, ...action.toast } : t,
|
|
87
|
+
),
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
case "DISMISS_TOAST": {
|
|
91
|
+
const { toastId } = action
|
|
92
|
+
|
|
93
|
+
// ! Side effects ! - This could be extracted into a dismissToast() action,
|
|
94
|
+
// but I'll keep it here for simplicity
|
|
95
|
+
if (toastId) {
|
|
96
|
+
addToRemoveQueue(toastId)
|
|
97
|
+
} else {
|
|
98
|
+
state.toasts.forEach((toast) => {
|
|
99
|
+
addToRemoveQueue(toast.id)
|
|
100
|
+
})
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
return {
|
|
104
|
+
...state,
|
|
105
|
+
toasts: state.toasts.map((t) =>
|
|
106
|
+
t.id === toastId || toastId === undefined
|
|
107
|
+
? {
|
|
108
|
+
...t,
|
|
109
|
+
open: false,
|
|
110
|
+
}
|
|
111
|
+
: t,
|
|
112
|
+
),
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
case "REMOVE_TOAST":
|
|
116
|
+
if (action.toastId === undefined) {
|
|
117
|
+
return {
|
|
118
|
+
...state,
|
|
119
|
+
toasts: [],
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
return {
|
|
123
|
+
...state,
|
|
124
|
+
toasts: state.toasts.filter((t) => t.id !== action.toastId),
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
const listeners: Array<(state: State) => void> = []
|
|
130
|
+
|
|
131
|
+
let memoryState: State = { toasts: [] }
|
|
132
|
+
|
|
133
|
+
function dispatch(action: Action) {
|
|
134
|
+
memoryState = reducer(memoryState, action)
|
|
135
|
+
listeners.forEach((listener) => {
|
|
136
|
+
listener(memoryState)
|
|
137
|
+
})
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
type Toast = Omit<ToasterToast, "id">
|
|
141
|
+
|
|
142
|
+
function toast({ ...props }: Toast) {
|
|
143
|
+
const id = genId()
|
|
144
|
+
|
|
145
|
+
const update = (props: ToasterToast) =>
|
|
146
|
+
dispatch({
|
|
147
|
+
type: "UPDATE_TOAST",
|
|
148
|
+
toast: { ...props, id },
|
|
149
|
+
})
|
|
150
|
+
const dismiss = () => dispatch({ type: "DISMISS_TOAST", toastId: id })
|
|
151
|
+
|
|
152
|
+
dispatch({
|
|
153
|
+
type: "ADD_TOAST",
|
|
154
|
+
toast: {
|
|
155
|
+
...props,
|
|
156
|
+
id,
|
|
157
|
+
open: true,
|
|
158
|
+
onOpenChange: (open) => {
|
|
159
|
+
if (!open) dismiss()
|
|
160
|
+
},
|
|
161
|
+
},
|
|
162
|
+
})
|
|
163
|
+
|
|
164
|
+
return {
|
|
165
|
+
id: id,
|
|
166
|
+
dismiss,
|
|
167
|
+
update,
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
function useToast() {
|
|
172
|
+
const [state, setState] = React.useState<State>(memoryState)
|
|
173
|
+
|
|
174
|
+
React.useEffect(() => {
|
|
175
|
+
listeners.push(setState)
|
|
176
|
+
return () => {
|
|
177
|
+
const index = listeners.indexOf(setState)
|
|
178
|
+
if (index > -1) {
|
|
179
|
+
listeners.splice(index, 1)
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
}, [state])
|
|
183
|
+
|
|
184
|
+
return {
|
|
185
|
+
...state,
|
|
186
|
+
toast,
|
|
187
|
+
dismiss: (toastId?: string) => dispatch({ type: "DISMISS_TOAST", toastId }),
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
export { useToast, toast }
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
"use client"
|
|
2
|
+
|
|
3
|
+
import { useState, useEffect } from "react"
|
|
4
|
+
import RepoPageContent from "./components/repo-page-content"
|
|
5
|
+
|
|
6
|
+
// Sample data for simulation
|
|
7
|
+
const samplePackageFiles = [
|
|
8
|
+
{
|
|
9
|
+
package_file_id: "1",
|
|
10
|
+
package_release_id: "1",
|
|
11
|
+
file_path: "README.md",
|
|
12
|
+
content_text:
|
|
13
|
+
"# @tscircuit/keyboard-default60\n\nA Default 60 keyboard created with tscircuit\n\n## Features\n\n- Full mechanical keyboard PCB design\n- Compatible with standard 60% cases\n- USB-C connector\n- Supports QMK firmware",
|
|
14
|
+
created_at: "2023-04-15T12:00:00Z",
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
package_file_id: "2",
|
|
18
|
+
package_release_id: "1",
|
|
19
|
+
file_path: "LICENSE",
|
|
20
|
+
content_text:
|
|
21
|
+
'MIT License\n\nCopyright (c) 2023 tscircuit\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions...',
|
|
22
|
+
created_at: "2023-04-15T12:00:00Z",
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
package_file_id: "3",
|
|
26
|
+
package_release_id: "1",
|
|
27
|
+
file_path: "lib/index.tsx",
|
|
28
|
+
content_text:
|
|
29
|
+
"import React from 'react'\nimport { PCB, Resistor, Capacitor, LED } from '@tscircuit/react'\n\nexport const KeyboardDefault60 = () => {\n return (\n <PCB name=\"keyboard-default60\">\n {/* Main controller */}\n <Microcontroller x={50} y={50} name=\"MCU1\" />\n \n {/* Key matrix */}\n <KeyMatrix x={100} y={100} rows={5} cols={14} />\n \n {/* Power circuit */}\n <PowerCircuit x={20} y={20} />\n </PCB>\n )\n}",
|
|
30
|
+
created_at: "2023-04-15T12:00:00Z",
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
package_file_id: "4",
|
|
34
|
+
package_release_id: "1",
|
|
35
|
+
file_path: "lib/components/KeyMatrix.tsx",
|
|
36
|
+
content_text:
|
|
37
|
+
"import React from 'react'\nimport { Switch, Diode } from '@tscircuit/react'\n\ninterface KeyMatrixProps {\n x: number\n y: number\n rows: number\n cols: number\n}\n\nexport const KeyMatrix = ({ x, y, rows, cols }: KeyMatrixProps) => {\n const keys = []\n \n for (let row = 0; row < rows; row++) {\n for (let col = 0; col < cols; col++) {\n keys.push(\n <Switch\n key={`key-${row}-${col}`}\n x={x + col * 19.05}\n y={y + row * 19.05}\n name={`SW${row * cols + col + 1}`}\n />\n )\n \n keys.push(\n <Diode\n key={`diode-${row}-${col}`}\n x={x + col * 19.05 + 5}\n y={y + row * 19.05 + 5}\n name={`D${row * cols + col + 1}`}\n />\n )\n }\n }\n \n return <>{keys}</>\n}",
|
|
38
|
+
created_at: "2023-04-15T12:00:00Z",
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
package_file_id: "5",
|
|
42
|
+
package_release_id: "1",
|
|
43
|
+
file_path: "lib/components/PowerCircuit.tsx",
|
|
44
|
+
content_text:
|
|
45
|
+
'import React from \'react\'\nimport { Capacitor, Resistor, Regulator } from \'@tscircuit/react\'\n\ninterface PowerCircuitProps {\n x: number\n y: number\n}\n\nexport const PowerCircuit = ({ x, y }: PowerCircuitProps) => {\n return (\n <>\n <Regulator\n x={x}\n y={y}\n name="U1"\n value="AP2112K-3.3"\n />\n <Capacitor\n x={x - 10}\n y={y}\n name="C1"\n value="10uF"\n />\n <Capacitor\n x={x + 10}\n y={y}\n name="C2"\n value="10uF"\n />\n <Resistor\n x={x}\n y={y + 10}\n name="R1"\n value="10k"\n />\n </>\n )\n}',
|
|
46
|
+
created_at: "2023-04-15T12:00:00Z",
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
package_file_id: "6",
|
|
50
|
+
package_release_id: "1",
|
|
51
|
+
file_path: "package.json",
|
|
52
|
+
content_text:
|
|
53
|
+
'{\n "name": "@tscircuit/keyboard-default60",\n "version": "0.0.361",\n "description": "A Default 60 keyboard created with tscircuit",\n "main": "dist/index.js",\n "types": "dist/index.d.ts",\n "scripts": {\n "build": "tsc",\n "test": "jest"\n },\n "dependencies": {\n "@tscircuit/react": "^0.1.0",\n "react": "^18.2.0"\n },\n "devDependencies": {\n "typescript": "^5.0.0",\n "jest": "^29.0.0"\n },\n "license": "MIT"\n}',
|
|
54
|
+
created_at: "2023-04-15T12:00:00Z",
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
package_file_id: "7",
|
|
58
|
+
package_release_id: "1",
|
|
59
|
+
file_path: "tsconfig.json",
|
|
60
|
+
content_text:
|
|
61
|
+
'{\n "compilerOptions": {\n "target": "es2020",\n "module": "esnext",\n "moduleResolution": "node",\n "declaration": true,\n "outDir": "./dist",\n "strict": true,\n "esModuleInterop": true,\n "skipLibCheck": true,\n "forceConsistentCasingInFileNames": true,\n "jsx": "react"\n },\n "include": ["lib/**/*"],\n "exclude": ["node_modules", "**/*.test.ts"]\n}',
|
|
62
|
+
created_at: "2023-04-15T12:00:00Z",
|
|
63
|
+
},
|
|
64
|
+
]
|
|
65
|
+
|
|
66
|
+
const samplePackageInfo = {
|
|
67
|
+
name: "@tscircuit/keyboard-default60",
|
|
68
|
+
unscoped_name: "keyboard-default60",
|
|
69
|
+
owner_github_username: "tscircuit",
|
|
70
|
+
star_count: "16",
|
|
71
|
+
description: "A Default 60 keyboard created with tscircuit",
|
|
72
|
+
ai_description:
|
|
73
|
+
"This package contains the PCB design for a standard 60% mechanical keyboard layout, created using the tscircuit library. It includes the schematic, PCB layout, and 3D model.",
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export default function SimulatePage() {
|
|
77
|
+
const [packageFiles, setPackageFiles] = useState<any>(null)
|
|
78
|
+
const [packageInfo, setPackageInfo] = useState<any>(null)
|
|
79
|
+
const [loading, setLoading] = useState(true)
|
|
80
|
+
|
|
81
|
+
useEffect(() => {
|
|
82
|
+
// Simulate loading data after 1 second
|
|
83
|
+
const timer = setTimeout(() => {
|
|
84
|
+
setPackageFiles(samplePackageFiles)
|
|
85
|
+
setPackageInfo(samplePackageInfo)
|
|
86
|
+
setLoading(false)
|
|
87
|
+
}, 1000)
|
|
88
|
+
|
|
89
|
+
return () => clearTimeout(timer)
|
|
90
|
+
}, [])
|
|
91
|
+
|
|
92
|
+
// Event handlers with window.alert for testing
|
|
93
|
+
const handleFileClicked = (file: any) => {
|
|
94
|
+
window.alert(`File clicked: ${file.name}`)
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
const handleDirectoryClicked = (directory: any) => {
|
|
98
|
+
window.alert(`Directory clicked: ${directory.name}`)
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
const handleExportClicked = (exportType: string) => {
|
|
102
|
+
window.alert(`Export clicked: ${exportType}`)
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
const handleEditClicked = () => {
|
|
106
|
+
window.alert("Edit button clicked")
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
return (
|
|
110
|
+
<RepoPageContent
|
|
111
|
+
packageFiles={packageFiles}
|
|
112
|
+
packageInfo={packageInfo}
|
|
113
|
+
importantFilePaths={["README.md", "LICENSE", "package.json"]}
|
|
114
|
+
onFileClicked={handleFileClicked}
|
|
115
|
+
onDirectoryClicked={handleDirectoryClicked}
|
|
116
|
+
onExportClicked={handleExportClicked}
|
|
117
|
+
onEditClicked={handleEditClicked}
|
|
118
|
+
/>
|
|
119
|
+
)
|
|
120
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
const importanceMap = {
|
|
2
|
+
"readme.md": 200,
|
|
3
|
+
license: 100,
|
|
4
|
+
"license.md": 100,
|
|
5
|
+
"index.ts": 90,
|
|
6
|
+
"index.tsx": 90,
|
|
7
|
+
"circuit.tsx": 90,
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export const scorePackageFileImportance = (filePath: string) => {
|
|
11
|
+
for (const [key, value] of Object.entries(importanceMap)) {
|
|
12
|
+
if (filePath.endsWith(key)) {
|
|
13
|
+
return value
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
return 0
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export const isPackageFileImportant = (filePath: string) => {
|
|
20
|
+
return scorePackageFileImportance(filePath) > 0
|
|
21
|
+
}
|
|
@@ -84,7 +84,7 @@ export const usePackageFileByRelease = (
|
|
|
84
84
|
}
|
|
85
85
|
|
|
86
86
|
// Hook to list all files for a package release
|
|
87
|
-
export const usePackageFiles = (packageReleaseId
|
|
87
|
+
export const usePackageFiles = (packageReleaseId?: string | null) => {
|
|
88
88
|
const axios = useAxios()
|
|
89
89
|
|
|
90
90
|
return useQuery<PackageFile[], Error & { status: number }>(
|
package/src/index.css
CHANGED
|
@@ -19,3 +19,18 @@
|
|
|
19
19
|
.animate-fadeIn {
|
|
20
20
|
animation: fadeIn 0.3s ease-in-out;
|
|
21
21
|
}
|
|
22
|
+
|
|
23
|
+
.shiki code {
|
|
24
|
+
counter-reset: step;
|
|
25
|
+
counter-increment: step 0;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
.shiki code .line::before {
|
|
29
|
+
content: counter(step);
|
|
30
|
+
counter-increment: step;
|
|
31
|
+
width: 1rem;
|
|
32
|
+
margin-right: 1.5rem;
|
|
33
|
+
display: inline-block;
|
|
34
|
+
text-align: right;
|
|
35
|
+
color: rgba(115, 138, 148, 0.4);
|
|
36
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import RepoPageContent from "@/components/ViewPackagePage/components/repo-page-content"
|
|
2
|
+
import SimulatePage from "@/components/ViewPackagePage/simulate-page"
|
|
3
|
+
import { usePackageByName } from "@/hooks/use-package-by-package-name"
|
|
4
|
+
import { usePackageFiles } from "@/hooks/use-package-files"
|
|
5
|
+
import { usePackageRelease } from "@/hooks/use-package-release"
|
|
6
|
+
import { useLocation } from "wouter"
|
|
7
|
+
|
|
8
|
+
export const ViewPackagePage = () => {
|
|
9
|
+
// Get the current path and extract author/packageName
|
|
10
|
+
const [location] = useLocation()
|
|
11
|
+
const pathParts = location.split("/")
|
|
12
|
+
const author = pathParts[2]
|
|
13
|
+
const urlPackageName = pathParts[3]
|
|
14
|
+
const fullPackageName = `${author}/${urlPackageName}`
|
|
15
|
+
|
|
16
|
+
const { data: packageInfo } = usePackageByName(fullPackageName)
|
|
17
|
+
|
|
18
|
+
const { data: packageRelease } = usePackageRelease({
|
|
19
|
+
is_latest: true,
|
|
20
|
+
package_name: fullPackageName,
|
|
21
|
+
})
|
|
22
|
+
|
|
23
|
+
const { data: packageFiles } = usePackageFiles(
|
|
24
|
+
packageRelease?.package_release_id,
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
return (
|
|
28
|
+
<RepoPageContent
|
|
29
|
+
packageFiles={packageFiles as any}
|
|
30
|
+
packageInfo={packageInfo as any}
|
|
31
|
+
importantFilePaths={["README.md", "LICENSE", "package.json"]}
|
|
32
|
+
onFileClicked={() => {}}
|
|
33
|
+
onDirectoryClicked={() => {}}
|
|
34
|
+
onExportClicked={() => {}}
|
|
35
|
+
onEditClicked={() => {}}
|
|
36
|
+
/>
|
|
37
|
+
)
|
|
38
|
+
}
|