diff --git a/package-lock.json b/package-lock.json index 3028c587..e0f99eeb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,9 +11,9 @@ "dependencies": { "@aitube/broadway": "0.1.2", "@aitube/clap": "0.1.2", - "@aitube/clapper-services": "0.1.2-0", + "@aitube/clapper-services": "0.1.2-1", "@aitube/engine": "0.1.2", - "@aitube/timeline": "0.1.2", + "@aitube/timeline": "0.1.2-0", "@fal-ai/serverless-client": "^0.13.0", "@ffmpeg/ffmpeg": "^0.12.10", "@ffmpeg/util": "^0.12.1", @@ -57,6 +57,7 @@ "@tailwindcss/container-queries": "^0.1.1", "@types/dom-speech-recognition": "^0.0.4", "@xenova/transformers": "github:xenova/transformers.js#v3", + "@xyflow/react": "^12.0.3", "autoprefixer": "10.4.19", "base64-arraybuffer": "^1.0.2", "class-variance-authority": "^0.7.0", @@ -163,12 +164,12 @@ } }, "node_modules/@aitube/clapper-services": { - "version": "0.1.2-0", - "resolved": "https://registry.npmjs.org/@aitube/clapper-services/-/clapper-services-0.1.2-0.tgz", - "integrity": "sha512-8rXuys53qBgIcbqCcpUcGFSkSkuNfQRUiZ8Wsw5YJsFtvJo+uqxfZZcfghaImnMNQVPrc72QVRj4o5Ph6e85Og==", + "version": "0.1.2-1", + "resolved": "https://registry.npmjs.org/@aitube/clapper-services/-/clapper-services-0.1.2-1.tgz", + "integrity": "sha512-xLReBwJ+yojRBHbKnjaMBszHGcikLlD5jSOlYaRUIWndiWFIzvZXxhehxjMQdV2mFiEwgLYITSADuihFlq/BzA==", "peerDependencies": { "@aitube/clap": "0.1.2", - "@aitube/timeline": "0.1.2", + "@aitube/timeline": "0.1.2-0", "@monaco-editor/react": "4.6.0", "monaco-editor": "0.50.0", "react": "*", @@ -194,9 +195,9 @@ } }, "node_modules/@aitube/timeline": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/@aitube/timeline/-/timeline-0.1.2.tgz", - "integrity": "sha512-cCAPJBjV8x2yh1lGIBAKISNY5eqOqFA2iWrO7u0TvCMNOxgpOIgHsATiQmGih3WjcbQQ8rdHfCGgxFZagLBh3A==", + "version": "0.1.2-0", + "resolved": "https://registry.npmjs.org/@aitube/timeline/-/timeline-0.1.2-0.tgz", + "integrity": "sha512-6KuiwBMgEt8U9xQZs+v4SQuy3RgcHOMz2HrLy2V4qERtFzNbyQnRHXx4u0iGn9Z/BbvVTBPbSLiJOhAMteHeeg==", "dependencies": { "date-fns": "^3.6.0", "react-virtualized-auto-sizer": "^1.0.24" @@ -6521,6 +6522,49 @@ "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.6.0.tgz", "integrity": "sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA==" }, + "node_modules/@types/d3-color": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/@types/d3-color/-/d3-color-3.1.3.tgz", + "integrity": "sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A==" + }, + "node_modules/@types/d3-drag": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/@types/d3-drag/-/d3-drag-3.0.7.tgz", + "integrity": "sha512-HE3jVKlzU9AaMazNufooRJ5ZpWmLIoc90A37WU2JMmeq28w1FQqCZswHZ3xR+SuxYftzHq6WU6KJHvqxKzTxxQ==", + "dependencies": { + "@types/d3-selection": "*" + } + }, + "node_modules/@types/d3-interpolate": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/d3-interpolate/-/d3-interpolate-3.0.4.tgz", + "integrity": "sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA==", + "dependencies": { + "@types/d3-color": "*" + } + }, + "node_modules/@types/d3-selection": { + "version": "3.0.10", + "resolved": "https://registry.npmjs.org/@types/d3-selection/-/d3-selection-3.0.10.tgz", + "integrity": "sha512-cuHoUgS/V3hLdjJOLTT691+G2QoqAjCVLmr4kJXR4ha56w1Zdu8UUQ5TxLRqudgNjwXeQxKMq4j+lyf9sWuslg==" + }, + "node_modules/@types/d3-transition": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/@types/d3-transition/-/d3-transition-3.0.8.tgz", + "integrity": "sha512-ew63aJfQ/ms7QQ4X7pk5NxQ9fZH/z+i24ZfJ6tJSfqxJMrYLiK01EAs2/Rtw/JreGUsS3pLPNV644qXFGnoZNQ==", + "dependencies": { + "@types/d3-selection": "*" + } + }, + "node_modules/@types/d3-zoom": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/@types/d3-zoom/-/d3-zoom-3.0.8.tgz", + "integrity": "sha512-iqMC4/YlFCSlO8+2Ii1GGGliCAY4XdeG748w5vQUbevlbDu0zSjH/+jojorQVBK/se0j6DUFNPBGSqD3YWYnDw==", + "dependencies": { + "@types/d3-interpolate": "*", + "@types/d3-selection": "*" + } + }, "node_modules/@types/dom-speech-recognition": { "version": "0.0.4", "resolved": "https://registry.npmjs.org/@types/dom-speech-recognition/-/dom-speech-recognition-0.0.4.tgz", @@ -7019,6 +7063,34 @@ "node": ">=10.0.0" } }, + "node_modules/@xyflow/react": { + "version": "12.0.3", + "resolved": "https://registry.npmjs.org/@xyflow/react/-/react-12.0.3.tgz", + "integrity": "sha512-PJB9ARsyDesjS9fY3b62mm36nHx9aRA8tvUc5y0ubrMkSCvQRECkOamVDyx+u65UgUkZCgcO/KFdXPdbTWwaJQ==", + "dependencies": { + "@xyflow/system": "0.0.37", + "classcat": "^5.0.3", + "zustand": "^4.4.0" + }, + "peerDependencies": { + "react": ">=17", + "react-dom": ">=17" + } + }, + "node_modules/@xyflow/system": { + "version": "0.0.37", + "resolved": "https://registry.npmjs.org/@xyflow/system/-/system-0.0.37.tgz", + "integrity": "sha512-hSIhezhxgftPUpC+xiQVIorcRILZUOWlLjpYPTyGWRu8s4RJvM4GqvrsFmD5OnMKXLgpU7/PqqUibDVO67oWQQ==", + "dependencies": { + "@types/d3-drag": "^3.0.7", + "@types/d3-selection": "^3.0.10", + "@types/d3-transition": "^3.0.8", + "@types/d3-zoom": "^3.0.8", + "d3-drag": "^3.0.0", + "d3-selection": "^3.0.0", + "d3-zoom": "^3.0.0" + } + }, "node_modules/abbrev": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-2.0.0.tgz", @@ -8270,6 +8342,11 @@ "node": ">=6" } }, + "node_modules/classcat": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/classcat/-/classcat-5.0.5.tgz", + "integrity": "sha512-JhZUT7JFcQy/EzW605k/ktHtncoo9vnyW/2GspNYwFlN1C/WmjuV/xtS04e9SOkL2sTdw0VAZ2UGCcQ9lR6p6w==" + }, "node_modules/classnames": { "version": "2.5.1", "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.5.1.tgz", @@ -9003,6 +9080,102 @@ "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==" }, + "node_modules/d3-color": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-3.1.0.tgz", + "integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-dispatch": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-dispatch/-/d3-dispatch-3.0.1.tgz", + "integrity": "sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-drag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-drag/-/d3-drag-3.0.0.tgz", + "integrity": "sha512-pWbUJLdETVA8lQNJecMxoXfH6x+mO2UQo8rSmZ+QqxcbyA3hfeprFgIT//HW2nlHChWeIIMwS2Fq+gEARkhTkg==", + "dependencies": { + "d3-dispatch": "1 - 3", + "d3-selection": "3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-ease": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-3.0.1.tgz", + "integrity": "sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-interpolate": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-3.0.1.tgz", + "integrity": "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==", + "dependencies": { + "d3-color": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-selection": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-3.0.0.tgz", + "integrity": "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-timer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-3.0.1.tgz", + "integrity": "sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-transition": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-transition/-/d3-transition-3.0.1.tgz", + "integrity": "sha512-ApKvfjsSR6tg06xrL434C0WydLr7JewBB3V+/39RMHsaXTOG0zmt/OAXeng5M5LBm0ojmxJrpomQVZ1aPvBL4w==", + "dependencies": { + "d3-color": "1 - 3", + "d3-dispatch": "1 - 3", + "d3-ease": "1 - 3", + "d3-interpolate": "1 - 3", + "d3-timer": "1 - 3" + }, + "engines": { + "node": ">=12" + }, + "peerDependencies": { + "d3-selection": "2 - 3" + } + }, + "node_modules/d3-zoom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-zoom/-/d3-zoom-3.0.0.tgz", + "integrity": "sha512-b8AmV3kfQaqWAuacbPuNbL6vahnOJflOhexLzMMNLga62+/nh0JzvJ0aO/5a5MVgUFGS7Hu1P9P03o3fJkDCyw==", + "dependencies": { + "d3-dispatch": "1 - 3", + "d3-drag": "2 - 3", + "d3-interpolate": "1 - 3", + "d3-selection": "2 - 3", + "d3-transition": "2 - 3" + }, + "engines": { + "node": ">=12" + } + }, "node_modules/damerau-levenshtein": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz", diff --git a/package.json b/package.json index 3519623a..525448bf 100644 --- a/package.json +++ b/package.json @@ -38,9 +38,9 @@ "dependencies": { "@aitube/broadway": "0.1.2", "@aitube/clap": "0.1.2", - "@aitube/clapper-services": "0.1.2-0", + "@aitube/clapper-services": "0.1.2-1", "@aitube/engine": "0.1.2", - "@aitube/timeline": "0.1.2", + "@aitube/timeline": "0.1.2-0", "@fal-ai/serverless-client": "^0.13.0", "@ffmpeg/ffmpeg": "^0.12.10", "@ffmpeg/util": "^0.12.1", @@ -84,6 +84,7 @@ "@tailwindcss/container-queries": "^0.1.1", "@types/dom-speech-recognition": "^0.0.4", "@xenova/transformers": "github:xenova/transformers.js#v3", + "@xyflow/react": "^12.0.3", "autoprefixer": "10.4.19", "base64-arraybuffer": "^1.0.2", "class-variance-authority": "^0.7.0", diff --git a/src/app/main.tsx b/src/app/main.tsx index 9524080e..db0a481e 100644 --- a/src/app/main.tsx +++ b/src/app/main.tsx @@ -26,6 +26,8 @@ type DroppableThing = { files: File[] } function MainContent() { const ref = useRef(null) const showWelcomeScreen = useUI((s) => s.showWelcomeScreen) + const showExplorer = useUI((s) => s.showExplorer) + const showVideoPlayer = useUI((s) => s.showVideoPlayer) const showTimeline = useUI((s) => s.showTimeline) const showAssistant = useUI((s) => s.showAssistant) const theme = useTheme() @@ -58,7 +60,7 @@ function MainContent() {
- + - - - - + {showVideoPlayer && } + {showVideoPlayer && ( + + + + )} - @@ -167,6 +177,7 @@ function MainContent() { +
) } diff --git a/src/components/editors/WorkflowEditor/index.tsx b/src/components/editors/WorkflowEditor/index.tsx index 768da4fd..208d40ba 100644 --- a/src/components/editors/WorkflowEditor/index.tsx +++ b/src/components/editors/WorkflowEditor/index.tsx @@ -3,6 +3,7 @@ import { useEffect } from 'react' import { FormInput } from '@/components/forms/FormInput' import { FormSection } from '@/components/forms/FormSection' import { useWorkflowEditor } from '@/services/editors' +import { useUI } from '@/services' export function WorkflowEditor() { const current = useWorkflowEditor((s) => s.current) @@ -11,6 +12,8 @@ export function WorkflowEditor() { const undo = useWorkflowEditor((s) => s.undo) const redo = useWorkflowEditor((s) => s.redo) + const hasBetaAccess = useUI((s) => s.hasBetaAccess) + if (!current) { return ( diff --git a/src/components/editors/WorkflowEditor/viewer/Node.tsx b/src/components/editors/WorkflowEditor/viewer/Node.tsx new file mode 100644 index 00000000..6639271f --- /dev/null +++ b/src/components/editors/WorkflowEditor/viewer/Node.tsx @@ -0,0 +1,39 @@ +import React, { memo } from 'react' +import { Handle, Position } from '@xyflow/react' + +function NodeComponent({ + data, +}: { + data: { + name: string + job: string + emoji: string + } +}) { + return ( +
+
+
+ {data.emoji} +
+
+
{data.name}
+
{data.job}
+
+
+ + + +
+ ) +} + +export const Node = memo(NodeComponent) diff --git a/src/components/editors/WorkflowEditor/viewer/README.md b/src/components/editors/WorkflowEditor/viewer/README.md new file mode 100644 index 00000000..dd049b13 --- /dev/null +++ b/src/components/editors/WorkflowEditor/viewer/README.md @@ -0,0 +1 @@ +# Workflow diff --git a/src/components/editors/WorkflowEditor/viewer/WorkflowView.tsx b/src/components/editors/WorkflowEditor/viewer/WorkflowView.tsx new file mode 100644 index 00000000..816cec54 --- /dev/null +++ b/src/components/editors/WorkflowEditor/viewer/WorkflowView.tsx @@ -0,0 +1,79 @@ +import React, { useCallback } from 'react' +import { + ReactFlow, + useNodesState, + useEdgesState, + addEdge, + MiniMap, + Controls, + OnConnect, +} from '@xyflow/react' + +import '@xyflow/react/dist/base.css' + +import { Node } from './Node' + +const nodeTypes = { + custom: Node, +} + +const initNodes = [ + { + id: '1', + type: 'custom', + data: { name: 'Jane Doe', job: 'CEO', emoji: '😎' }, + position: { x: 0, y: 50 }, + }, + { + id: '2', + type: 'custom', + data: { name: 'Tyler Weary', job: 'Designer', emoji: '🤓' }, + + position: { x: -200, y: 200 }, + }, + { + id: '3', + type: 'custom', + data: { name: 'Kristi Price', job: 'Developer', emoji: '🤩' }, + position: { x: 200, y: 200 }, + }, +] + +const initEdges = [ + { + id: 'e1-2', + source: '1', + target: '2', + }, + { + id: 'e1-3', + source: '1', + target: '3', + }, +] + +export function WorkflowView() { + const [nodes, setNodes, onNodesChange] = useNodesState(initNodes) + const [edges, setEdges, onEdgesChange] = useEdgesState(initEdges) + + const onConnect: OnConnect = useCallback( + (params) => setEdges((eds) => addEdge(params, eds)), + [] + ) + + return ( + + + + + ) +} diff --git a/src/components/toolbars/top-menu/ToggleView/index.tsx b/src/components/toolbars/top-menu/ToggleView/index.tsx new file mode 100644 index 00000000..46bf4fbf --- /dev/null +++ b/src/components/toolbars/top-menu/ToggleView/index.tsx @@ -0,0 +1,46 @@ +import { ReactNode } from 'react' + +import { cn } from '@/lib/utils' +import { + Tooltip, + TooltipContent, + TooltipTrigger, +} from '@/components/ui/tooltip' + +export function ToggleView({ + children, + isVisible = false, + setVisible, + className = '', +}: { + children?: ReactNode + isVisible?: boolean + setVisible: (isVisible: boolean) => void + className?: string +}) { + return ( + + +
{ + setVisible(!isVisible) + }} + > +
+
+
+ + {children} + +
+ ) +} diff --git a/src/components/toolbars/top-menu/index.tsx b/src/components/toolbars/top-menu/index.tsx index 3aab24a9..d5cbc3eb 100644 --- a/src/components/toolbars/top-menu/index.tsx +++ b/src/components/toolbars/top-menu/index.tsx @@ -21,10 +21,19 @@ import { TooltipContent, TooltipTrigger, } from '@/components/ui/tooltip' +import { ToggleView } from './ToggleView' export function TopMenu() { const isBusyResolving = useResolver((s) => s.isBusyResolving) + const showTimeline = useUI((s) => s.showTimeline) + const setShowTimeline = useUI((s) => s.setShowTimeline) + const showExplorer = useUI((s) => s.showExplorer) + const setShowExplorer = useUI((s) => s.setShowExplorer) + const showVideoPlayer = useUI((s) => s.showVideoPlayer) + const setShowVideoPlayer = useUI((s) => s.setShowVideoPlayer) + const showAssistant = useUI((s) => s.showAssistant) + const setShowAssistant = useUI((s) => s.setShowAssistant) const setIsTopMenuOpen = useUI((s) => s.setIsTopMenuOpen) const hasBetaAccess = useUI((s) => s.hasBetaAccess) @@ -55,9 +64,42 @@ export function TopMenu() { { // clap?.meta?.title || "Untitled" } + + {/* + Toggle Tree browser + */} + {/* + + Toggle Timeline + + */} + + + Toggle Monitor + + + Toggle Assistant + + -
+
diff --git a/src/components/toolbars/top-menu/view/index.tsx b/src/components/toolbars/top-menu/view/index.tsx index 2d492aa1..3ffb64ae 100644 --- a/src/components/toolbars/top-menu/view/index.tsx +++ b/src/components/toolbars/top-menu/view/index.tsx @@ -85,17 +85,6 @@ export function TopMenuView() { }} >Show asset explorer */} - { - setShowAssistant(!showAssistant) - e.stopPropagation() - e.preventDefault() - return false - }} - > - Show assistant - setEdges((eds) => addEdge(params, eds)), + [] + ) + + return ( + + + + + ) +} diff --git a/src/experiments/moodboard/Node.tsx b/src/experiments/moodboard/Node.tsx new file mode 100644 index 00000000..6639271f --- /dev/null +++ b/src/experiments/moodboard/Node.tsx @@ -0,0 +1,39 @@ +import React, { memo } from 'react' +import { Handle, Position } from '@xyflow/react' + +function NodeComponent({ + data, +}: { + data: { + name: string + job: string + emoji: string + } +}) { + return ( +
+
+
+ {data.emoji} +
+
+
{data.name}
+
{data.job}
+
+
+ + + +
+ ) +} + +export const Node = memo(NodeComponent) diff --git a/src/lib/core/constants.ts b/src/lib/core/constants.ts index df11b2c4..279ca5c8 100644 --- a/src/lib/core/constants.ts +++ b/src/lib/core/constants.ts @@ -3,7 +3,7 @@ export const HARD_LIMIT_NB_MAX_ASSETS_TO_GENERATE_IN_PARALLEL = 32 export const APP_NAME = 'Clapper.app' -export const APP_REVISION = '20240725+0155' +export const APP_REVISION = '20240725+1822' export const APP_DOMAIN = 'Clapper.app' export const APP_LINK = 'https://clapper.app'