@tscircuit/fake-snippets 0.0.81 → 0.0.83

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 (37) hide show
  1. package/bun-tests/fake-snippets-api/routes/package_releases/create.test.ts +3 -3
  2. package/dist/bundle.js +41 -13
  3. package/dist/index.d.ts +24 -4
  4. package/dist/index.js +5 -1
  5. package/dist/schema.d.ts +37 -5
  6. package/dist/schema.js +5 -1
  7. package/fake-snippets-api/lib/db/schema.ts +5 -1
  8. package/fake-snippets-api/lib/public-mapping/public-map-package-release.ts +14 -1
  9. package/fake-snippets-api/routes/api/package_releases/get.ts +11 -3
  10. package/fake-snippets-api/routes/api/package_releases/list.ts +8 -1
  11. package/fake-snippets-api/routes/api/packages/generate_from_jlcpcb.ts +3 -3
  12. package/package.json +1 -1
  13. package/src/App.tsx +0 -2
  14. package/src/components/JLCPCBImportDialog.tsx +164 -62
  15. package/src/components/PackageBuildsPage/LogContent.tsx +12 -5
  16. package/src/components/PackageBuildsPage/PackageBuildDetailsPage.tsx +8 -7
  17. package/src/components/PackageBuildsPage/build-preview-content.tsx +1 -1
  18. package/src/components/PackageBuildsPage/collapsible-section.tsx +14 -46
  19. package/src/components/PackageBuildsPage/package-build-details-panel.tsx +28 -10
  20. package/src/components/PackageBuildsPage/package-build-header.tsx +16 -4
  21. package/src/components/ViewPackagePage/components/build-status.tsx +24 -85
  22. package/src/components/ViewPackagePage/components/important-files-view.tsx +8 -1
  23. package/src/components/ViewPackagePage/components/sidebar-releases-section.tsx +28 -5
  24. package/src/components/ViewPackagePage/hooks/use-toast.tsx +70 -0
  25. package/src/components/dialogs/{import-snippet-dialog.tsx → import-package-dialog.tsx} +25 -24
  26. package/src/components/package-port/CodeEditor.tsx +9 -1
  27. package/src/components/package-port/CodeEditorHeader.tsx +7 -6
  28. package/src/components/ui/toaster.tsx +1 -33
  29. package/src/hooks/use-current-package-release.ts +14 -3
  30. package/src/hooks/use-now.ts +12 -0
  31. package/src/hooks/use-package-release.ts +17 -15
  32. package/src/hooks/use-toast.tsx +50 -169
  33. package/src/pages/dashboard.tsx +3 -1
  34. package/src/pages/user-profile.tsx +9 -2
  35. package/src/pages/view-package.tsx +1 -0
  36. package/.github/workflows/formatbot.yml +0 -63
  37. package/src/components/ViewPackagePage/hooks/use-toast.ts +0 -191
@@ -1,191 +1,72 @@
1
- import * as React from "react"
1
+ import toastLibrary, { Toaster, type Toast } from "react-hot-toast"
2
+ import React from "react"
2
3
 
3
- import type { ToastActionElement, ToastProps } from "@/components/ui/toast"
4
-
5
- const TOAST_LIMIT = 1
6
- const TOAST_REMOVE_DELAY = 1000000
7
-
8
- export type ToasterToast = ToastProps & {
9
- id: string
4
+ export interface ToasterToast {
10
5
  title?: React.ReactNode
11
6
  description?: React.ReactNode
12
- action?: ToastActionElement
13
- }
14
-
15
- const actionTypes = {
16
- ADD_TOAST: "ADD_TOAST",
17
- UPDATE_TOAST: "UPDATE_TOAST",
18
- DISMISS_TOAST: "DISMISS_TOAST",
19
- REMOVE_TOAST: "REMOVE_TOAST",
20
- } as const
21
-
22
- let count = 0
23
-
24
- function genId() {
25
- count = (count + 1) % Number.MAX_SAFE_INTEGER
26
- return count.toString()
7
+ variant?: "default" | "destructive"
8
+ duration?: number
27
9
  }
28
10
 
29
- type ActionType = typeof actionTypes
30
-
31
- type Action =
32
- | {
33
- type: ActionType["ADD_TOAST"]
34
- toast: ToasterToast
35
- }
36
- | {
37
- type: ActionType["UPDATE_TOAST"]
38
- toast: Partial<ToasterToast>
39
- }
40
- | {
41
- type: ActionType["DISMISS_TOAST"]
42
- toastId?: ToasterToast["id"]
43
- }
44
- | {
45
- type: ActionType["REMOVE_TOAST"]
46
- toastId?: ToasterToast["id"]
47
- }
48
-
49
- interface State {
50
- toasts: ToasterToast[]
11
+ function ToastContent({
12
+ title,
13
+ description,
14
+ variant,
15
+ t,
16
+ }: ToasterToast & { t: Toast }) {
17
+ return (
18
+ <div
19
+ className={`rounded-md border p-4 shadow-lg transition-all ${
20
+ t.visible
21
+ ? "animate-in fade-in slide-in-from-top-full"
22
+ : "animate-out fade-out slide-out-to-right-full"
23
+ } ${
24
+ variant === "destructive"
25
+ ? "border-red-500 bg-red-500 text-slate-50"
26
+ : "border-slate-200 bg-white text-slate-950 dark:bg-slate-950 dark:text-slate-50"
27
+ }`}
28
+ >
29
+ {title && <div className="text-sm font-semibold">{title}</div>}
30
+ {description && <div className="text-sm opacity-90">{description}</div>}
31
+ </div>
32
+ )
51
33
  }
52
34
 
53
- const toastTimeouts = new Map<string, ReturnType<typeof setTimeout>>()
54
-
55
- const addToRemoveQueue = (toastId: string) => {
56
- if (toastTimeouts.has(toastId)) {
57
- return
35
+ const toast = ({
36
+ duration,
37
+ description,
38
+ variant = "default",
39
+ title,
40
+ }: ToasterToast) => {
41
+ if (description) {
42
+ return toastLibrary.custom(
43
+ (t) => (
44
+ <ToastContent
45
+ title={title}
46
+ description={description}
47
+ variant={variant}
48
+ t={t}
49
+ />
50
+ ),
51
+ { duration },
52
+ )
58
53
  }
59
54
 
60
- const timeout = setTimeout(() => {
61
- toastTimeouts.delete(toastId)
62
- dispatch({
63
- type: "REMOVE_TOAST",
64
- toastId: toastId,
65
- })
66
- }, TOAST_REMOVE_DELAY)
67
-
68
- toastTimeouts.set(toastId, timeout)
69
- }
70
-
71
- export const reducer = (state: State, action: Action): State => {
72
- switch (action.type) {
73
- case "ADD_TOAST":
74
- return {
75
- ...state,
76
- toasts: [action.toast, ...state.toasts].slice(0, TOAST_LIMIT),
77
- }
78
-
79
- case "UPDATE_TOAST":
80
- return {
81
- ...state,
82
- toasts: state.toasts.map((t) =>
83
- t.id === action.toast.id ? { ...t, ...action.toast } : t,
84
- ),
85
- }
86
-
87
- case "DISMISS_TOAST": {
88
- const { toastId } = action
89
-
90
- // ! Side effects ! - This could be extracted into a dismissToast() action,
91
- // but I'll keep it here for simplicity
92
- if (toastId) {
93
- addToRemoveQueue(toastId)
94
- } else {
95
- state.toasts.forEach((toast) => {
96
- addToRemoveQueue(toast.id)
97
- })
98
- }
99
-
100
- return {
101
- ...state,
102
- toasts: state.toasts.map((t) =>
103
- t.id === toastId || toastId === undefined
104
- ? {
105
- ...t,
106
- open: false,
107
- }
108
- : t,
109
- ),
110
- }
111
- }
112
- case "REMOVE_TOAST":
113
- if (action.toastId === undefined) {
114
- return {
115
- ...state,
116
- toasts: [],
117
- }
118
- }
119
- return {
120
- ...state,
121
- toasts: state.toasts.filter((t) => t.id !== action.toastId),
122
- }
55
+ if (variant === "destructive") {
56
+ return toastLibrary.error(<>{title}</>, { duration })
123
57
  }
124
- }
125
-
126
- const listeners: Array<(state: State) => void> = []
127
-
128
- let memoryState: State = { toasts: [] }
129
-
130
- function dispatch(action: Action) {
131
- memoryState = reducer(memoryState, action)
132
- listeners.forEach((listener) => {
133
- listener(memoryState)
134
- })
135
- }
136
-
137
- type Toast = Omit<ToasterToast, "id">
138
58
 
139
- function toast({ ...props }: Toast) {
140
- const id = genId()
141
-
142
- const update = (props: ToasterToast) =>
143
- dispatch({
144
- type: "UPDATE_TOAST",
145
- toast: { ...props, id },
146
- })
147
- const dismiss = () => dispatch({ type: "DISMISS_TOAST", toastId: id })
148
-
149
- dispatch({
150
- type: "ADD_TOAST",
151
- toast: {
152
- ...props,
153
- id,
154
- open: true,
155
- onOpenChange: (open) => {
156
- if (!open) dismiss()
157
- },
158
- },
159
- })
160
-
161
- return {
162
- id: id,
163
- dismiss,
164
- update,
165
- }
59
+ return toastLibrary(<>{title}</>, { duration })
166
60
  }
167
61
 
168
62
  function useToast() {
169
- const [state, setState] = React.useState<State>(memoryState)
170
-
171
- React.useEffect(() => {
172
- listeners.push(setState)
173
- return () => {
174
- const index = listeners.indexOf(setState)
175
- if (index > -1) {
176
- listeners.splice(index, 1)
177
- }
178
- }
179
- }, [state])
180
-
181
63
  return {
182
- ...state,
183
64
  toast,
184
- dismiss: (toastId?: string) => dispatch({ type: "DISMISS_TOAST", toastId }),
65
+ dismiss: toastLibrary.dismiss,
185
66
  }
186
67
  }
187
68
 
188
- export { useToast, toast }
69
+ export { useToast, toast, Toaster }
189
70
 
190
71
  export function useNotImplementedToast() {
191
72
  const { toast } = useToast()
@@ -34,8 +34,9 @@ export const DashboardPage = () => {
34
34
  data: myPackages,
35
35
  isLoading,
36
36
  error,
37
+ refetch: refetchUserPackages,
37
38
  } = useQuery<Package[]>(
38
- "userPackages",
39
+ ["userPackages", currentUser],
39
40
  async () => {
40
41
  const response = await axios.post(`/packages/list`, {
41
42
  owner_github_username: currentUser,
@@ -195,6 +196,7 @@ export const DashboardPage = () => {
195
196
  packageId={packageToDelete.package_id}
196
197
  packageName={packageToDelete.unscoped_name}
197
198
  packageOwner={packageToDelete.owner_github_username ?? ""}
199
+ refetchUserPackages={refetchUserPackages}
198
200
  />
199
201
  )}
200
202
  </div>
@@ -48,7 +48,10 @@ export const UserProfilePage = () => {
48
48
  })
49
49
  return response.data
50
50
  },
51
- { retry: false },
51
+ {
52
+ retry: false,
53
+ refetchOnWindowFocus: false,
54
+ },
52
55
  )
53
56
 
54
57
  // use the username stored in the database so the correct case is displayed
@@ -71,7 +74,10 @@ export const UserProfilePage = () => {
71
74
  })
72
75
  return response.data.packages
73
76
  },
74
- { enabled: Boolean(githubUsername) },
77
+ {
78
+ enabled: Boolean(githubUsername),
79
+ refetchOnWindowFocus: false,
80
+ },
75
81
  )
76
82
 
77
83
  const { data: starredPackages, isLoading: isLoadingStarredPackages } =
@@ -85,6 +91,7 @@ export const UserProfilePage = () => {
85
91
  },
86
92
  {
87
93
  enabled: activeTab === "starred" && Boolean(githubUsername),
94
+ refetchOnWindowFocus: false,
88
95
  },
89
96
  )
90
97
 
@@ -24,6 +24,7 @@ export const ViewPackagePage = () => {
24
24
  } = usePackageRelease({
25
25
  is_latest: true,
26
26
  package_name: `${author}/${packageName}`,
27
+ include_ai_review: true,
27
28
  })
28
29
 
29
30
  const { data: packageFiles } = usePackageFiles(
@@ -1,63 +0,0 @@
1
- name: Format PR
2
-
3
- on:
4
- pull_request:
5
- types: [opened, synchronize, reopened, ready_for_review]
6
-
7
- jobs:
8
- format:
9
- name: Format code
10
- runs-on: ubuntu-latest
11
- if: github.event.pull_request.draft == false
12
-
13
- steps:
14
- - name: Determine if fork
15
- id: check_fork
16
- run: |
17
- if [ "${{ github.event.pull_request.head.repo.full_name }}" = "${{ github.repository }}" ]; then
18
- echo "is_fork=false" >> $GITHUB_OUTPUT
19
- else
20
- echo "is_fork=true" >> $GITHUB_OUTPUT
21
- fi
22
-
23
- - name: Checkout code
24
- uses: actions/checkout@v4
25
- with:
26
- token: ${{ steps.check_fork.outputs.is_fork == 'true' && secrets.GITHUB_TOKEN || secrets.TSCIRCUIT_BOT_GITHUB_TOKEN }}
27
-
28
- - name: Setup bun
29
- uses: oven-sh/setup-bun@v2
30
- with:
31
- bun-version: latest
32
-
33
- - name: Get @biomejs/biome version
34
- id: get-biome-version
35
- run: echo "BIOME_VERSION=$(node -p "require('./package.json').devDependencies['@biomejs/biome']")" >> $GITHUB_OUTPUT
36
-
37
- - name: Install @biomejs/biome
38
- run: bun install @biomejs/biome@${{ steps.get-biome-version.outputs.BIOME_VERSION }}
39
-
40
- - name: Run Formatter and autofix
41
- if: steps.check_fork.outputs.is_fork == 'false'
42
- run: npx @biomejs/biome format . --write
43
-
44
- - name: Format Check (cannot autofix against forks)
45
- if: steps.check_fork.outputs.is_fork == 'true'
46
- run: npx @biomejs/biome format .
47
-
48
- - name: Restore lock files
49
- if: steps.check_fork.outputs.is_fork == 'false'
50
- run: |
51
- git checkout -- *lock.json || true
52
- git checkout -- *.lock || true
53
- git checkout -- *.lockb || true
54
-
55
- - name: Commit changes
56
- if: steps.check_fork.outputs.is_fork == 'false'
57
- uses: stefanzweifel/git-auto-commit-action@v4
58
- with:
59
- commit_message: "formatbot: Automatically format code"
60
- branch: ${{ github.head_ref }}
61
- commit_user_name: tscircuitbot
62
- commit_user_email: tscircuitbot@users.noreply.github.com
63
- commit_author: tscircuitbot <tscircuitbot@users.noreply.github.com>
@@ -1,191 +0,0 @@
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 }