jbilcke-hf HF staff commited on
Commit
b594e33
1 Parent(s): 6fcdb95

add prettier config

Browse files
.eslintrc.json CHANGED
@@ -1,3 +1,6 @@
1
  {
2
- "extends": "next/core-web-vitals"
 
 
 
3
  }
 
1
  {
2
+ "extends": [
3
+ "next/core-web-vitals",
4
+ "prettier"
5
+ ]
6
  }
.prettierrc.json ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "trailingComma": "es5",
3
+ "semi": false,
4
+ "tabWidth": 2,
5
+ "singleQuote": true,
6
+ "jsxSingleQuote": false,
7
+ "plugins": ["prettier-plugin-tailwindcss"]
8
+ }
package-lock.json CHANGED
@@ -109,12 +109,15 @@
109
  "@types/uuid": "^9.0.8",
110
  "@vitejs/plugin-react": "^4.3.1",
111
  "eslint": "^8",
112
- "eslint-config-next": "14.2.4",
 
113
  "jsdom": "^24.1.0",
114
  "postcss": "^8",
 
 
115
  "tailwind-scrollbar": "^3.1.0",
116
  "tailwindcss": "^3.4.3",
117
- "typescript": "^5",
118
  "vitest": "^2.0.2"
119
  }
120
  },
@@ -3127,9 +3130,9 @@
3127
  "integrity": "sha512-/zZGkrTOsraVfYjGP8uM0p6r0BDT6xWpkjdVbcz66PJVSpwXX3yNiRycxAuDfBKGWBrZBXRuK/YVlkNgxHGwmA=="
3128
  },
3129
  "node_modules/@next/eslint-plugin-next": {
3130
- "version": "14.2.4",
3131
- "resolved": "https://registry.npmjs.org/@next/eslint-plugin-next/-/eslint-plugin-next-14.2.4.tgz",
3132
- "integrity": "sha512-svSFxW9f3xDaZA3idQmlFw7SusOuWTpDTAeBlO3AEPDltrraV+lqs7mAc6A27YdnpQVVIA3sODqUAAHdWhVWsA==",
3133
  "dev": true,
3134
  "dependencies": {
3135
  "glob": "10.3.10"
@@ -8282,12 +8285,12 @@
8282
  }
8283
  },
8284
  "node_modules/eslint-config-next": {
8285
- "version": "14.2.4",
8286
- "resolved": "https://registry.npmjs.org/eslint-config-next/-/eslint-config-next-14.2.4.tgz",
8287
- "integrity": "sha512-Qr0wMgG9m6m4uYy2jrYJmyuNlYZzPRQq5Kvb9IDlYwn+7yq6W6sfMNFgb+9guM1KYwuIo6TIaiFhZJ6SnQ/Efw==",
8288
  "dev": true,
8289
  "dependencies": {
8290
- "@next/eslint-plugin-next": "14.2.4",
8291
  "@rushstack/eslint-patch": "^1.3.3",
8292
  "@typescript-eslint/parser": "^5.4.2 || ^6.0.0 || 7.0.0 - 7.2.0",
8293
  "eslint-import-resolver-node": "^0.3.6",
@@ -8307,6 +8310,18 @@
8307
  }
8308
  }
8309
  },
 
 
 
 
 
 
 
 
 
 
 
 
8310
  "node_modules/eslint-import-resolver-node": {
8311
  "version": "0.3.9",
8312
  "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz",
@@ -12048,6 +12063,80 @@
12048
  "url": "https://github.com/prettier/prettier?sponsor=1"
12049
  }
12050
  },
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
12051
  "node_modules/pretty-format": {
12052
  "version": "27.5.1",
12053
  "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz",
 
109
  "@types/uuid": "^9.0.8",
110
  "@vitejs/plugin-react": "^4.3.1",
111
  "eslint": "^8",
112
+ "eslint-config-next": "14.2.5",
113
+ "eslint-config-prettier": "^9.1.0",
114
  "jsdom": "^24.1.0",
115
  "postcss": "^8",
116
+ "prettier": "^3.3.3",
117
+ "prettier-plugin-tailwindcss": "^0.6.5",
118
  "tailwind-scrollbar": "^3.1.0",
119
  "tailwindcss": "^3.4.3",
120
+ "typescript": "^5.5.0",
121
  "vitest": "^2.0.2"
122
  }
123
  },
 
3130
  "integrity": "sha512-/zZGkrTOsraVfYjGP8uM0p6r0BDT6xWpkjdVbcz66PJVSpwXX3yNiRycxAuDfBKGWBrZBXRuK/YVlkNgxHGwmA=="
3131
  },
3132
  "node_modules/@next/eslint-plugin-next": {
3133
+ "version": "14.2.5",
3134
+ "resolved": "https://registry.npmjs.org/@next/eslint-plugin-next/-/eslint-plugin-next-14.2.5.tgz",
3135
+ "integrity": "sha512-LY3btOpPh+OTIpviNojDpUdIbHW9j0JBYBjsIp8IxtDFfYFyORvw3yNq6N231FVqQA7n7lwaf7xHbVJlA1ED7g==",
3136
  "dev": true,
3137
  "dependencies": {
3138
  "glob": "10.3.10"
 
8285
  }
8286
  },
8287
  "node_modules/eslint-config-next": {
8288
+ "version": "14.2.5",
8289
+ "resolved": "https://registry.npmjs.org/eslint-config-next/-/eslint-config-next-14.2.5.tgz",
8290
+ "integrity": "sha512-zogs9zlOiZ7ka+wgUnmcM0KBEDjo4Jis7kxN1jvC0N4wynQ2MIx/KBkg4mVF63J5EK4W0QMCn7xO3vNisjaAoA==",
8291
  "dev": true,
8292
  "dependencies": {
8293
+ "@next/eslint-plugin-next": "14.2.5",
8294
  "@rushstack/eslint-patch": "^1.3.3",
8295
  "@typescript-eslint/parser": "^5.4.2 || ^6.0.0 || 7.0.0 - 7.2.0",
8296
  "eslint-import-resolver-node": "^0.3.6",
 
8310
  }
8311
  }
8312
  },
8313
+ "node_modules/eslint-config-prettier": {
8314
+ "version": "9.1.0",
8315
+ "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-9.1.0.tgz",
8316
+ "integrity": "sha512-NSWl5BFQWEPi1j4TjVNItzYV7dZXZ+wP6I6ZhrBGpChQhZRUaElihE9uRRkcbRnNb76UMKDF3r+WTmNcGPKsqw==",
8317
+ "dev": true,
8318
+ "bin": {
8319
+ "eslint-config-prettier": "bin/cli.js"
8320
+ },
8321
+ "peerDependencies": {
8322
+ "eslint": ">=7.0.0"
8323
+ }
8324
+ },
8325
  "node_modules/eslint-import-resolver-node": {
8326
  "version": "0.3.9",
8327
  "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz",
 
12063
  "url": "https://github.com/prettier/prettier?sponsor=1"
12064
  }
12065
  },
12066
+ "node_modules/prettier-plugin-tailwindcss": {
12067
+ "version": "0.6.5",
12068
+ "resolved": "https://registry.npmjs.org/prettier-plugin-tailwindcss/-/prettier-plugin-tailwindcss-0.6.5.tgz",
12069
+ "integrity": "sha512-axfeOArc/RiGHjOIy9HytehlC0ZLeMaqY09mm8YCkMzznKiDkwFzOpBvtuhuv3xG5qB73+Mj7OCe2j/L1ryfuQ==",
12070
+ "dev": true,
12071
+ "engines": {
12072
+ "node": ">=14.21.3"
12073
+ },
12074
+ "peerDependencies": {
12075
+ "@ianvs/prettier-plugin-sort-imports": "*",
12076
+ "@prettier/plugin-pug": "*",
12077
+ "@shopify/prettier-plugin-liquid": "*",
12078
+ "@trivago/prettier-plugin-sort-imports": "*",
12079
+ "@zackad/prettier-plugin-twig-melody": "*",
12080
+ "prettier": "^3.0",
12081
+ "prettier-plugin-astro": "*",
12082
+ "prettier-plugin-css-order": "*",
12083
+ "prettier-plugin-import-sort": "*",
12084
+ "prettier-plugin-jsdoc": "*",
12085
+ "prettier-plugin-marko": "*",
12086
+ "prettier-plugin-organize-attributes": "*",
12087
+ "prettier-plugin-organize-imports": "*",
12088
+ "prettier-plugin-sort-imports": "*",
12089
+ "prettier-plugin-style-order": "*",
12090
+ "prettier-plugin-svelte": "*"
12091
+ },
12092
+ "peerDependenciesMeta": {
12093
+ "@ianvs/prettier-plugin-sort-imports": {
12094
+ "optional": true
12095
+ },
12096
+ "@prettier/plugin-pug": {
12097
+ "optional": true
12098
+ },
12099
+ "@shopify/prettier-plugin-liquid": {
12100
+ "optional": true
12101
+ },
12102
+ "@trivago/prettier-plugin-sort-imports": {
12103
+ "optional": true
12104
+ },
12105
+ "@zackad/prettier-plugin-twig-melody": {
12106
+ "optional": true
12107
+ },
12108
+ "prettier-plugin-astro": {
12109
+ "optional": true
12110
+ },
12111
+ "prettier-plugin-css-order": {
12112
+ "optional": true
12113
+ },
12114
+ "prettier-plugin-import-sort": {
12115
+ "optional": true
12116
+ },
12117
+ "prettier-plugin-jsdoc": {
12118
+ "optional": true
12119
+ },
12120
+ "prettier-plugin-marko": {
12121
+ "optional": true
12122
+ },
12123
+ "prettier-plugin-organize-attributes": {
12124
+ "optional": true
12125
+ },
12126
+ "prettier-plugin-organize-imports": {
12127
+ "optional": true
12128
+ },
12129
+ "prettier-plugin-sort-imports": {
12130
+ "optional": true
12131
+ },
12132
+ "prettier-plugin-style-order": {
12133
+ "optional": true
12134
+ },
12135
+ "prettier-plugin-svelte": {
12136
+ "optional": true
12137
+ }
12138
+ }
12139
+ },
12140
  "node_modules/pretty-format": {
12141
  "version": "27.5.1",
12142
  "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz",
package.json CHANGED
@@ -116,12 +116,15 @@
116
  "@types/uuid": "^9.0.8",
117
  "@vitejs/plugin-react": "^4.3.1",
118
  "eslint": "^8",
119
- "eslint-config-next": "14.2.4",
 
120
  "jsdom": "^24.1.0",
121
  "postcss": "^8",
 
 
122
  "tailwind-scrollbar": "^3.1.0",
123
  "tailwindcss": "^3.4.3",
124
- "typescript": "^5",
125
  "vitest": "^2.0.2"
126
  }
127
  }
 
116
  "@types/uuid": "^9.0.8",
117
  "@vitejs/plugin-react": "^4.3.1",
118
  "eslint": "^8",
119
+ "eslint-config-next": "14.2.5",
120
+ "eslint-config-prettier": "^9.1.0",
121
  "jsdom": "^24.1.0",
122
  "postcss": "^8",
123
+ "prettier": "^3.3.3",
124
+ "prettier-plugin-tailwindcss": "^0.6.5",
125
  "tailwind-scrollbar": "^3.1.0",
126
  "tailwindcss": "^3.4.3",
127
+ "typescript": "^5.5.0",
128
  "vitest": "^2.0.2"
129
  }
130
  }
src/app/main.tsx CHANGED
@@ -55,7 +55,7 @@ function MainContent() {
55
 
56
  const searchParams = useSearchParams()
57
  const hasBetaAccess = searchParams.get("beta") === "true"
58
- useEffect(() => { setHasBetaAccess(hasBetaAccess) }, [hasBetaAccess])
59
 
60
  return (
61
  <div
 
55
 
56
  const searchParams = useSearchParams()
57
  const hasBetaAccess = searchParams.get("beta") === "true"
58
+ useEffect(() => { setHasBetaAccess(hasBetaAccess) }, [hasBetaAccess, setHasBetaAccess])
59
 
60
  return (
61
  <div
src/components/core/timeline/index.tsx CHANGED
@@ -34,7 +34,7 @@ export function Timeline() {
34
  // we need to apply theme to it
35
  useUI.getState().applyThemeToComponents()
36
  startLoop()
37
- }, [isReady])
38
 
39
 
40
  return (
 
34
  // we need to apply theme to it
35
  useUI.getState().applyThemeToComponents()
36
  startLoop()
37
+ }, [isReady, setSegmentResolver, setJumpAt, setIsPlaying, setTogglePlayback, startLoop, checkIfPlaying, jumpAt, resolveSegment, togglePlayback])
38
 
39
 
40
  return (
src/components/core/tree/useTreeNode.ts CHANGED
@@ -77,7 +77,7 @@ export function useTreeNode<T extends ElementType>(
77
  // Ensure the action is dispatched only once, otherwise we wouldn't be able to collapse the node
78
  dispatchOnce.current = true
79
  }
80
- }, [id, options.isExpanded, open, dispatch])
81
 
82
  return useMemo(() => {
83
  const isOpen = open.get(id) ?? false
@@ -189,6 +189,8 @@ export function useTreeNode<T extends ElementType>(
189
  open,
190
  options.isFolder,
191
  options.selectionType,
 
 
192
  options.isExpanded,
193
  select,
194
  selectedId,
 
77
  // Ensure the action is dispatched only once, otherwise we wouldn't be able to collapse the node
78
  dispatchOnce.current = true
79
  }
80
+ }, [id, options?.isExpanded, options?.data?.nodeType, open, dispatch])
81
 
82
  return useMemo(() => {
83
  const isOpen = open.get(id) ?? false
 
189
  open,
190
  options.isFolder,
191
  options.selectionType,
192
+ options?.data?.nodeType,
193
+ options?.data?.data,
194
  options.isExpanded,
195
  select,
196
  selectedId,
src/components/core/waveform/useWaveform.ts CHANGED
@@ -58,7 +58,10 @@ export function useWaveform({
58
 
59
  const debounceSize = useDebounce(cacheKey, 300)
60
 
61
- const redraw = () => {
 
 
 
62
  const cachedImage = cache[cacheKey]
63
 
64
  console.log(`redraw() for cache key "${cacheKey}"`)
@@ -100,12 +103,8 @@ export function useWaveform({
100
  } else {
101
  console.error("redraw(): no canvasRenderingContext")
102
  }
103
- }
104
 
105
- useLayoutEffect(() => {
106
- if (error) { return }
107
- redraw()
108
- }, [id, debounceSize, zoom, color, onDone, gain, error])
109
 
110
  return {
111
  canvas,
 
58
 
59
  const debounceSize = useDebounce(cacheKey, 300)
60
 
61
+
62
+ useLayoutEffect(() => {
63
+ if (error) { return }
64
+
65
  const cachedImage = cache[cacheKey]
66
 
67
  console.log(`redraw() for cache key "${cacheKey}"`)
 
103
  } else {
104
  console.error("redraw(): no canvasRenderingContext")
105
  }
 
106
 
107
+ }, [id, debounceSize, zoom, color, onDone, gain, error, height, width, mode, cacheKey])
 
 
 
108
 
109
  return {
110
  canvas,
src/components/editors/ProjectEditor/index.tsx CHANGED
@@ -18,7 +18,7 @@ export function ProjectEditor() {
18
 
19
  useEffect(() => {
20
  setCurrent(clap?.meta)
21
- }, [clap?.meta])
22
 
23
  if (!current) {
24
  return <div>
 
18
 
19
  useEffect(() => {
20
  setCurrent(clap?.meta)
21
+ }, [clap?.meta, setCurrent])
22
 
23
  if (!current) {
24
  return <div>
src/components/editors/SegmentEditor/index.tsx CHANGED
@@ -18,7 +18,8 @@ export function SegmentEditor() {
18
 
19
  useEffect(() => {
20
  setCurrent(selectedSegments.at(-1))
21
- }, [selectedSegments.map(s => s.id).join(',')])
 
22
 
23
  if (!current) {
24
  return <div>
 
18
 
19
  useEffect(() => {
20
  setCurrent(selectedSegments.at(-1))
21
+ // eslint-disable-next-line
22
+ }, [setCurrent, selectedSegments.map(s => s.id).join(',')])
23
 
24
  if (!current) {
25
  return <div>
src/components/forms/FormDir.tsx CHANGED
@@ -34,9 +34,8 @@ export function FormDir({
34
  return
35
  }
36
 
37
- const files = Array.from(event.currentTarget.files || [])
38
- onChange(files)
39
- }, [])
40
 
41
  return (
42
  <FormField
 
34
  return
35
  }
36
 
37
+ onChange(Array.from<File>(event.currentTarget.files || []))
38
+ }, [disabled, onChange])
 
39
 
40
  return (
41
  <FormField
src/components/forms/FormFile.tsx CHANGED
@@ -35,9 +35,8 @@ export function FormFile({
35
  return
36
  }
37
 
38
- const files = Array.from(event.currentTarget.files || [])
39
- onChange(files)
40
- }, [])
41
 
42
  return (
43
  <FormField
 
35
  return
36
  }
37
 
38
+ onChange(Array.from<File>(event.currentTarget.files || []))
39
+ }, [disabled, onChange])
 
40
 
41
  return (
42
  <FormField
src/components/forms/FormInput.tsx CHANGED
@@ -83,7 +83,7 @@ export function FormInput<T>({
83
  } else {
84
  onChange(rawStringValue as T)
85
  }
86
- }, [isNumberInput, isTextInput, minValue, maxValue, defaultValue])
87
 
88
  return (
89
  <FormField
 
83
  } else {
84
  onChange(rawStringValue as T)
85
  }
86
+ }, [isNumberInput, minValue, maxValue, defaultValue, disabled, onChange])
87
 
88
  return (
89
  <FormField
src/components/monitor/DynamicPlayer/StoryboardBuffer.tsx CHANGED
@@ -29,6 +29,7 @@ export function StoryboardBuffer({
29
  className
30
  )}
31
  src={src}
 
32
  />
33
  )
34
  }
 
29
  className
30
  )}
31
  src={src}
32
+ alt="storyboard"
33
  />
34
  )
35
  }
src/components/monitor/DynamicPlayer/index.tsx CHANGED
@@ -69,10 +69,8 @@ export const DynamicPlayer = ({
69
  return () => {
70
  clearTimeout(timeoutRef.current)
71
  }
72
- }, [
73
- currentSegmentKey,
74
- preloadSegmentKey
75
- ])
76
 
77
  return (
78
  <div className={cn(`
 
69
  return () => {
70
  clearTimeout(timeoutRef.current)
71
  }
72
+ // eslint-disable-next-line
73
+ }, [currentSegmentKey, preloadSegmentKey])
 
 
74
 
75
  return (
76
  <div className={cn(`
src/components/monitor/StaticPlayer/index.tsx CHANGED
@@ -44,7 +44,7 @@ export function StaticPlayer({
44
  useEffect(() => {
45
  if (!ref.current) { return }
46
  setStaticVideoRef(ref.current)
47
- }, [ref])
48
 
49
  const placeholder = <div
50
  className="
 
44
  useEffect(() => {
45
  if (!ref.current) { return }
46
  setStaticVideoRef(ref.current)
47
+ }, [setStaticVideoRef])
48
 
49
  const placeholder = <div
50
  className="
src/components/toolbars/top-menu/file/index.tsx CHANGED
@@ -42,7 +42,7 @@ export function TopMenuFile() {
42
  }
43
  await openClapUrl(clapUrl)
44
  })()
45
- }, [clapUrl])
46
 
47
  // const setShowSettings = useUISettings(s => s.setShowSettings)
48
  useHotkeys('ctrl+o', () => openFilePicker(), { preventDefault: true }, [])
 
42
  }
43
  await openClapUrl(clapUrl)
44
  })()
45
+ }, [openClapUrl, clapUrl])
46
 
47
  // const setShowSettings = useUISettings(s => s.setShowSettings)
48
  useHotkeys('ctrl+o', () => openFilePicker(), { preventDefault: true }, [])
src/components/toolbars/top-menu/view/index.tsx CHANGED
@@ -22,22 +22,22 @@ export function TopMenuView() {
22
  if (typeof window !== "undefined") {
23
  ref.current = document.body
24
  }
25
- }, [])
26
 
27
- const showTimeline = useUI((s) => s.showTimeline)
28
- const setShowTimeline = useUI((s) => s.setShowTimeline)
29
 
30
- const showExplorer = useUI((s) => s.showExplorer)
31
- const setShowExplorer = useUI((s) => s.setShowExplorer)
32
 
33
- const showAssistant = useUI((s) => s.showAssistant)
34
- const setShowAssistant = useUI((s) => s.setShowAssistant)
35
 
36
- const showVideoPlayer = useUI((s) => s.showVideoPlayer)
37
- const setShowVideoPlayer = useUI((s) => s.setShowVideoPlayer)
38
 
39
- const followCursor = useUI((s) => s.followCursor)
40
- const setFollowCursor = useUI((s) => s.setFollowCursor)
41
 
42
  const hasBetaAccess = useUI(s => s.hasBetaAccess)
43
 
 
22
  if (typeof window !== "undefined") {
23
  ref.current = document.body
24
  }
25
+ }, [ref])
26
 
27
+ const showTimeline = useUI(s => s.showTimeline)
28
+ const setShowTimeline = useUI(s => s.setShowTimeline)
29
 
30
+ const showExplorer = useUI(s => s.showExplorer)
31
+ const setShowExplorer = useUI(s => s.setShowExplorer)
32
 
33
+ const showAssistant = useUI(s => s.showAssistant)
34
+ const setShowAssistant = useUI(s => s.setShowAssistant)
35
 
36
+ const showVideoPlayer = useUI(s => s.showVideoPlayer)
37
+ const setShowVideoPlayer = useUI(s => s.setShowVideoPlayer)
38
 
39
+ const followCursor = useUI(s => s.followCursor)
40
+ const setFollowCursor = useUI(s => s.setFollowCursor)
41
 
42
  const hasBetaAccess = useUI(s => s.hasBetaAccess)
43
 
src/components/tree-browsers/model-tree-browser/index.tsx CHANGED
@@ -25,18 +25,15 @@ export function ModelTreeBrowser() {
25
  const newReplicateCollections = useReplicateCollections()
26
  useEffect(() => {
27
  setReplicateCollections(newReplicateCollections)
28
- }, [
29
- JSON.stringify(newReplicateCollections) // ... yeah, I know, I know..
30
- ])
31
 
32
  const newCivitaiCollections = useCivitaiCollections()
33
  useEffect(() => {
34
  setCivitaiCollections(newCivitaiCollections)
35
- }, [
36
- JSON.stringify(newCivitaiCollections) // ... yeah, I know, I know..
37
- ])
38
 
39
-
40
  /**
41
  * handle click on tree node
42
  * yes, this is where the magic happens!
 
25
  const newReplicateCollections = useReplicateCollections()
26
  useEffect(() => {
27
  setReplicateCollections(newReplicateCollections)
28
+ // eslint-disable-next-line
29
+ }, [JSON.stringify(newReplicateCollections)]) // ... yeah, I know, I know..
 
30
 
31
  const newCivitaiCollections = useCivitaiCollections()
32
  useEffect(() => {
33
  setCivitaiCollections(newCivitaiCollections)
34
+ // eslint-disable-next-line
35
+ }, [JSON.stringify(newCivitaiCollections)]) // ... yeah, I know, I know..
 
36
 
 
37
  /**
38
  * handle click on tree node
39
  * yes, this is where the magic happens!
src/lib/hf/parseHuggingFaceHubId.test.ts ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { expect, test } from 'vitest'
2
+
3
+ import { parseHuggingFaceHubId } from './parseHuggingFaceHubId'
4
+
5
+ test('parseHuggingFaceHubId', () => {
6
+ expect(parseHuggingFaceHubId("stabilityai/stable-cascade")).toStrictEqual({
7
+ category: "models",
8
+ categoryAndOwnerAndId: "models/stabilityai/stable-cascade",
9
+ id: "stable-cascade",
10
+ owner: "stabilityai",
11
+ ownerAndId: "stabilityai/stable-cascade",
12
+ })
13
+ expect(parseHuggingFaceHubId("spaces/jbilcke-hf/ai-comic-factory")).toStrictEqual({
14
+ category: "spaces",
15
+ categoryAndOwnerAndId: "spaces/jbilcke-hf/ai-comic-factory",
16
+ id: "ai-comic-factory",
17
+ owner: "jbilcke-hf",
18
+ ownerAndId: "jbilcke-hf/ai-comic-factory",
19
+ })
20
+ })
21
+
src/lib/hooks/useAnimationFrame.ts CHANGED
@@ -18,5 +18,6 @@ export function useAnimationFrame(callback: (time: number) => void, deps: Depend
18
  useEffect(() => {
19
  requestRef.current = requestAnimationFrame(animate);
20
  return () => cancelAnimationFrame(requestRef.current as any);
 
21
  }, deps); // Make sure the effect runs only once
22
  }
 
18
  useEffect(() => {
19
  requestRef.current = requestAnimationFrame(animate);
20
  return () => cancelAnimationFrame(requestRef.current as any);
21
+ // eslint-disable-next-line
22
  }, deps); // Make sure the effect runs only once
23
  }
src/lib/hooks/useOpenFilePicker.ts CHANGED
@@ -1,18 +1,18 @@
1
- import { useEffect, useState, useTransition } from "react"
2
  import { useFilePicker } from "use-file-picker"
3
 
4
  import { parseFileName } from "@/services/io/parseFileName"
5
  import { useIO } from "@/services/io/useIO"
6
 
 
 
7
  export function useOpenFilePicker() {
8
  const [isLoading, setIsLoading] = useState(false)
9
  const openClapBlob = useIO(s => s.openClapBlob)
10
  const openScreenplay = useIO(s => s.openScreenplay)
11
 
12
- const supportedExtensions = ['clap', 'txt']
13
-
14
  const { openFilePicker, filesContent, loading } = useFilePicker({
15
- accept: supportedExtensions.map(ext => `.${ext}`),
16
  readAs: "ArrayBuffer"
17
  })
18
 
@@ -58,7 +58,7 @@ export function useOpenFilePicker() {
58
  }
59
  }
60
  fn()
61
- }, [fileData?.name])
62
 
63
  return { openFilePicker, filesContent, fileData, isLoading: loading || isLoading }
64
  }
 
1
+ import { useEffect, useState } from "react"
2
  import { useFilePicker } from "use-file-picker"
3
 
4
  import { parseFileName } from "@/services/io/parseFileName"
5
  import { useIO } from "@/services/io/useIO"
6
 
7
+ const supportedExtensions = ['clap', 'txt']
8
+
9
  export function useOpenFilePicker() {
10
  const [isLoading, setIsLoading] = useState(false)
11
  const openClapBlob = useIO(s => s.openClapBlob)
12
  const openScreenplay = useIO(s => s.openScreenplay)
13
 
 
 
14
  const { openFilePicker, filesContent, loading } = useFilePicker({
15
+ accept: ['clap', 'txt'].map(ext => `.${ext}`),
16
  readAs: "ArrayBuffer"
17
  })
18
 
 
58
  }
59
  }
60
  fn()
61
+ }, [fileData?.name, fileData?.content, openClapBlob, openScreenplay])
62
 
63
  return { openFilePicker, filesContent, fileData, isLoading: loading || isLoading }
64
  }
src/lib/hooks/useRequestAnimationFrame.ts CHANGED
@@ -1,4 +1,4 @@
1
- import * as React from 'react'
2
 
3
  type Config = {
4
  duration?: number
@@ -30,8 +30,8 @@ export const useRequestAnimationFrame = (
30
  }
31
  */
32
 
33
- const frame = React.useRef(0)
34
- const firstFrameTime = React.useRef(performance.now())
35
 
36
  const animate = (now: number) => {
37
  // calculate at what time fraction we are currently of whole time of animation
@@ -48,7 +48,7 @@ export const useRequestAnimationFrame = (
48
  }
49
  }
50
 
51
- React.useEffect(() => {
52
  if (shouldAnimate) {
53
  firstFrameTime.current = performance.now()
54
  frame.current = requestAnimationFrame(animate)
@@ -57,6 +57,7 @@ export const useRequestAnimationFrame = (
57
  }
58
 
59
  return () => cancelAnimationFrame(frame.current)
 
60
  }, [shouldAnimate])
61
  }
62
 
 
1
+ import { useEffect, useRef } from 'react'
2
 
3
  type Config = {
4
  duration?: number
 
30
  }
31
  */
32
 
33
+ const frame = useRef(0)
34
+ const firstFrameTime = useRef(performance.now())
35
 
36
  const animate = (now: number) => {
37
  // calculate at what time fraction we are currently of whole time of animation
 
48
  }
49
  }
50
 
51
+ useEffect(() => {
52
  if (shouldAnimate) {
53
  firstFrameTime.current = performance.now()
54
  frame.current = requestAnimationFrame(animate)
 
57
  }
58
 
59
  return () => cancelAnimationFrame(frame.current)
60
+ // eslint-disable-next-line
61
  }, [shouldAnimate])
62
  }
63
 
src/lib/utils/base64DataUriToBlob.test.ts ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { expect, test } from 'vitest'
2
+
3
+ import { base64DataUriToBlob } from './base64DataUriToBlob'
4
+ import { blobToBase64DataUri } from './blobToBase64DataUri'
5
+
6
+ const gifUri = `data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7`
7
+
8
+ const pngUri = `data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVQYV2NgYAAAAAMAAWgmWQ0AAAAASUVORK5CYII=`
9
+
10
+ const mp4Uri = `data:video/mp4;base64,AAAAIGZ0eXBpc29tAAACAGlzb21pc28yYXZjMW1wNDEAAAAIZnJlZQAAAtJtZGF0AAACrQYF//+p3EXpvebZSLeWLNgg2SPu73gyNjQgLSBjb3JlIDE2NCByMzEwMyA5NDFjYWU2IC0gSC4yNjQvTVBFRy00IEFWQyBjb2RlYyAtIENvcHlsZWZ0IDIwMDMtMjAyMiAtIGh0dHA6Ly93d3cudmlkZW9sYW4ub3JnL3gyNjQuaHRtbCAtIG9wdGlvbnM6IGNhYmFjPTEgcmVmPTMgZGVibG9jaz0xOjA6MCBhbmFseXNlPTB4MzoweDExMyBtZT1oZXggc3VibWU9NyBwc3k9MSBwc3lfcmQ9MS4wMDowLjAwIG1peGVkX3JlZj0xIG1lX3JhbmdlPTE2IGNocm9tYV9tZT0xIHRyZWxsaXM9MSA4eDhkY3Q9MSBjcW09MCBkZWFkem9uZT0yMSwxMSBmYXN0X3Bza2lwPTEgY2hyb21hX3FwX29mZnNldD0tMiB0aHJlYWRzPTEgbG9va2FoZWFkX3RocmVhZHM9MSBzbGljZWRfdGhyZWFkcz0wIG5yPTAgZGVjaW1hdGU9MSBpbnRlcmxhY2VkPTAgYmx1cmF5X2NvbXBhdD0wIGNvbnN0cmFpbmVkX2ludHJhPTAgYmZyYW1lcz0zIGJfcHlyYW1pZD0yIGJfYWRhcHQ9MSBiX2JpYXM9MCBkaXJlY3Q9MSB3ZWlnaHRiPTEgb3Blbl9nb3A9MCB3ZWlnaHRwPTIga2V5aW50PTI1MCBrZXlpbnRfbWluPTEgc2NlbmVjdXQ9NDAgaW50cmFfcmVmcmVzaD0wIHJjX2xvb2thaGVhZD00MCByYz1jcmYgbWJ0cmVlPTEgY3JmPTIzLjAgcWNvbXA9MC42MCBxcG1pbj0wIHFwbWF4PTY5IHFwc3RlcD00IGlwX3JhdGlvPTEuNDAgYXE9MToxLjAwAIAAAAAVZYiEABX//vfJ78Cm6/X2tb9gAQD5AAADBm1vb3YAAABsbXZoZAAAAADgYBEw4GARMAAAA+gAAAPoAAEAAAEAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAIwdHJhawAAAFx0a2hkAAAAA+BgETDgYBEwAAAAAQAAAAAAAAPoAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAQAAAAAAUAAAAFAAAAAAAJGVkdHMAAAAcZWxzdAAAAAAAAAABAAAD6AAAAAAAAQAAAAABqG1kaWEAAAAgbWRoZAAAAADgYBEw4GARMAAAQAAAAEAAVcQAAAAAAC1oZGxyAAAAAAAAAAB2aWRlAAAAAAAAAAAAAAAAVmlkZW9IYW5kbGVyAAAAAVNtaW5mAAAAFHZtaGQAAAABAAAAAAAAAAAAAAAkZGluZgAAABxkcmVmAAAAAAAAAAEAAAAMdXJsIAAAAAEAAAETc3RibAAAAK9zdHNkAAAAAAAAAAEAAACfYXZjMQAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAUABQASAAAAEgAAAAAAAAAARVMYXZjNTkuNTYuMTAwIGxpYngyNjQAAAAAAAAAAAAAABj//wAAADVhdmNDAWQAM//hABhnZAAzrNlJeeeEAAADAAQAAAMACDxgxlgBAAZo6+PLIsD9+PgAAAAAFGJ0cnQAAAAAAAAWUAAAFlAAAAAYc3R0cwAAAAAAAAABAAAAAQAAQAAAAAAcc3RzYwAAAAAAAAABAAAAAQAAAAEAAAABAAAAFHN0c3oAAAAAAAACygAAAAEAAAAUc3RjbwAAAAAAAAABAAAAMAAAAGJ1ZHRhAAAAWm1ldGEAAAAAAAAAIWhkbHIAAAAAAAAAAG1kaXJhcHBsAAAAAAAAAAAAAAAALWlsc3QAAAAlqXRvbwAAAB1kYXRhAAAAAQAAAABMYXZmNTkuMzUuMTAw`
11
+
12
+ test('base64DataUriToBlob', async () => {
13
+ expect(await blobToBase64DataUri(base64DataUriToBlob(gifUri))).toBe(gifUri)
14
+ expect(await blobToBase64DataUri(base64DataUriToBlob(pngUri))).toBe(pngUri)
15
+ expect(await blobToBase64DataUri(base64DataUriToBlob(mp4Uri))).toBe(mp4Uri)
16
+ })
17
+
src/lib/utils/blobToBase64DataUri.ts CHANGED
@@ -1,4 +1,12 @@
1
- export const blobToBase64DataUri = async (blob: Blob): Promise<string> => {
2
- const buffer = Buffer.from(await blob.arrayBuffer())
3
- return "data:" + blob.type + ';base64,' + buffer.toString('base64')
4
- }
 
 
 
 
 
 
 
 
 
1
+ export const blobToBase64DataUri = async (blob: Blob): Promise<string> =>
2
+ new Promise((resolve, reject) => {
3
+ const reader = new FileReader()
4
+
5
+ reader.onload = (event) => {
6
+ const dataUrl = (event.target?.result || "") as string
7
+ if (!dataUrl) { throw new Error(`invalid blob`) }
8
+ resolve(dataUrl)
9
+ };
10
+
11
+ reader.readAsDataURL(blob)
12
+ })
src/lib/utils/cn.test.ts ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
 
1
+ import { expect, test } from 'vitest'
2
+
3
+ import { cn } from './cn'
4
+
5
+ test('cn', () => {
6
+ expect(cn("p-4 m-4", true ? "m-4 p-2" : "p-4 m-2")).toBe("m-4 p-2")
7
+ })
8
+
src/lib/utils/getTypeAndExtension.test.ts ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { expect, test } from 'vitest'
2
+
3
+ import { getTypeAndExtension } from './getTypeAndExtension'
4
+
5
+ const gifUri = `data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7`
6
+
7
+ const pngUri = `data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVQYV2NgYAAAAAMAAWgmWQ0AAAAASUVORK5CYII=`
8
+
9
+ const mp4Uri = `data:video/mp4;base64,AAAAIGZ0eXBpc29tAAACAGlzb21pc28yYXZjMW1wNDEAAAAIZnJlZQAAAtJtZGF0AAACrQYF//+p3EXpvebZSLeWLNgg2SPu73gyNjQgLSBjb3JlIDE2NCByMzEwMyA5NDFjYWU2IC0gSC4yNjQvTVBFRy00IEFWQyBjb2RlYyAtIENvcHlsZWZ0IDIwMDMtMjAyMiAtIGh0dHA6Ly93d3cudmlkZW9sYW4ub3JnL3gyNjQuaHRtbCAtIG9wdGlvbnM6IGNhYmFjPTEgcmVmPTMgZGVibG9jaz0xOjA6MCBhbmFseXNlPTB4MzoweDExMyBtZT1oZXggc3VibWU9NyBwc3k9MSBwc3lfcmQ9MS4wMDowLjAwIG1peGVkX3JlZj0xIG1lX3JhbmdlPTE2IGNocm9tYV9tZT0xIHRyZWxsaXM9MSA4eDhkY3Q9MSBjcW09MCBkZWFkem9uZT0yMSwxMSBmYXN0X3Bza2lwPTEgY2hyb21hX3FwX29mZnNldD0tMiB0aHJlYWRzPTEgbG9va2FoZWFkX3RocmVhZHM9MSBzbGljZWRfdGhyZWFkcz0wIG5yPTAgZGVjaW1hdGU9MSBpbnRlcmxhY2VkPTAgYmx1cmF5X2NvbXBhdD0wIGNvbnN0cmFpbmVkX2ludHJhPTAgYmZyYW1lcz0zIGJfcHlyYW1pZD0yIGJfYWRhcHQ9MSBiX2JpYXM9MCBkaXJlY3Q9MSB3ZWlnaHRiPTEgb3Blbl9nb3A9MCB3ZWlnaHRwPTIga2V5aW50PTI1MCBrZXlpbnRfbWluPTEgc2NlbmVjdXQ9NDAgaW50cmFfcmVmcmVzaD0wIHJjX2xvb2thaGVhZD00MCByYz1jcmYgbWJ0cmVlPTEgY3JmPTIzLjAgcWNvbXA9MC42MCBxcG1pbj0wIHFwbWF4PTY5IHFwc3RlcD00IGlwX3JhdGlvPTEuNDAgYXE9MToxLjAwAIAAAAAVZYiEABX//vfJ78Cm6/X2tb9gAQD5AAADBm1vb3YAAABsbXZoZAAAAADgYBEw4GARMAAAA+gAAAPoAAEAAAEAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAIwdHJhawAAAFx0a2hkAAAAA+BgETDgYBEwAAAAAQAAAAAAAAPoAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAQAAAAAAUAAAAFAAAAAAAJGVkdHMAAAAcZWxzdAAAAAAAAAABAAAD6AAAAAAAAQAAAAABqG1kaWEAAAAgbWRoZAAAAADgYBEw4GARMAAAQAAAAEAAVcQAAAAAAC1oZGxyAAAAAAAAAAB2aWRlAAAAAAAAAAAAAAAAVmlkZW9IYW5kbGVyAAAAAVNtaW5mAAAAFHZtaGQAAAABAAAAAAAAAAAAAAAkZGluZgAAABxkcmVmAAAAAAAAAAEAAAAMdXJsIAAAAAEAAAETc3RibAAAAK9zdHNkAAAAAAAAAAEAAACfYXZjMQAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAUABQASAAAAEgAAAAAAAAAARVMYXZjNTkuNTYuMTAwIGxpYngyNjQAAAAAAAAAAAAAABj//wAAADVhdmNDAWQAM//hABhnZAAzrNlJeeeEAAADAAQAAAMACDxgxlgBAAZo6+PLIsD9+PgAAAAAFGJ0cnQAAAAAAAAWUAAAFlAAAAAYc3R0cwAAAAAAAAABAAAAAQAAQAAAAAAcc3RzYwAAAAAAAAABAAAAAQAAAAEAAAABAAAAFHN0c3oAAAAAAAACygAAAAEAAAAUc3RjbwAAAAAAAAABAAAAMAAAAGJ1ZHRhAAAAWm1ldGEAAAAAAAAAIWhkbHIAAAAAAAAAAG1kaXJhcHBsAAAAAAAAAAAAAAAALWlsc3QAAAAlqXRvbwAAAB1kYXRhAAAAAQAAAABMYXZmNTkuMzUuMTAw`
10
+
11
+ test('getTypeAndExtension', () => {
12
+ expect(getTypeAndExtension(gifUri)).toStrictEqual({
13
+ assetFileFormat: "image/gif",
14
+ category: "image",
15
+ extension: "gif",
16
+ outputType: "image",
17
+ })
18
+ expect(getTypeAndExtension(pngUri)).toStrictEqual({
19
+ assetFileFormat: "image/png",
20
+ category: "image",
21
+ extension: "png",
22
+ outputType: "image",
23
+ })
24
+ expect(getTypeAndExtension(mp4Uri)).toStrictEqual({
25
+ assetFileFormat: "video/mp4",
26
+ category: "video",
27
+ extension: "mp4",
28
+ outputType: "video",
29
+ })
30
+ })
31
+
src/lib/utils/getValidComfyWorkflowTemplate.test.ts ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { expect, test } from 'vitest'
2
+
3
+ import { getValidComfyWorkflowTemplate } from './getValidComfyWorkflowTemplate'
4
+
5
+ const defaultJson = {}
6
+ const defaultStr = JSON.stringify(defaultJson, null, 2)
7
+
8
+ const mockJson = { "3": { "inputs": { "seed": 156680208700286, "steps": 10, "cfg": 2.5, "sampler_name": "dpmpp_2m_sde", "scheduler": "karras", "denoise": 1, "model": [ "4", 0 ], "positive": [ "6", 0 ], "negative": [ "7", 0 ], "latent_image": [ "5", 0 ] }, "class_type": "KSampler", "_meta": { "title": "KSampler" } }, "4": { "inputs": { "ckpt_name": "SDXL-Flash.safetensors" }, "class_type": "CheckpointLoaderSimple", "_meta": { "title": "Load Checkpoint" } }, "5": { "inputs": { "width": 1024, "height": 1024, "batch_size": 1 }, "class_type": "EmptyLatentImage", "_meta": { "title": "Empty Latent Image" } }, "6": { "inputs": { "text": "beautiful scenery nature glass bottle landscape, purple galaxy bottle,", "clip": [ "4", 1 ] }, "class_type": "CLIPTextEncode", "_meta": { "title": "CLIP Text Encode (Prompt)" } }, "7": { "inputs": { "text": "text, watermark", "clip": [ "4", 1 ] }, "class_type": "CLIPTextEncode", "_meta": { "title": "CLIP Text Encode (Prompt)" } }, "8": { "inputs": { "samples": [ "3", 0 ], "vae": [ "4", 2 ] }, "class_type": "VAEDecode", "_meta": { "title": "VAE Decode" } }, "9": { "inputs": { "filename_prefix": "ComfyUI", "images": [ "8", 0 ] }, "class_type": "SaveImage", "_meta": { "title": "Save Image" } }}
9
+ const mockStr = JSON.stringify(mockJson, null, 2)
10
+
11
+ // getValidComfyWorkflowTemplate takes a string, tries to unpack it as JSON to validate it, then returns a string
12
+ test('getValidComfyWorkflowTemplate', () => {
13
+ expect(getValidComfyWorkflowTemplate(null, defaultStr)).toBe(defaultStr)
14
+ expect(getValidComfyWorkflowTemplate(mockStr, defaultStr)).toBe(mockStr)
15
+ })
16
+
src/lib/utils/getValidComfyWorkflowTemplate.ts CHANGED
@@ -1,3 +1,10 @@
 
 
 
 
 
 
 
1
  export function getValidComfyWorkflowTemplate(something: any, defaultComfyWorkflowTemplate: string) {
2
  const strValue = `${something || defaultComfyWorkflowTemplate}`
3
  try {
 
1
+ /**
2
+ * Take a string, try to unpack it as JSON to validate it, return a string
3
+ *
4
+ * @param something
5
+ * @param defaultComfyWorkflowTemplate
6
+ * @returns
7
+ */
8
  export function getValidComfyWorkflowTemplate(something: any, defaultComfyWorkflowTemplate: string) {
9
  const strValue = `${something || defaultComfyWorkflowTemplate}`
10
  try {
src/services/assistant/useVoiceAssistant.ts CHANGED
@@ -9,5 +9,5 @@ export function useVoiceAssistant() {
9
 
10
  useEffect(() => {
11
  processMessage(transcript)
12
- }, [transcript])
13
  }
 
9
 
10
  useEffect(() => {
11
  processMessage(transcript)
12
+ }, [transcript, processMessage])
13
  }