diff --git a/frontend/realtime/package-lock.json b/frontend/realtime/package-lock.json index a5ef4e0a7a..8f2b1bd6de 100644 --- a/frontend/realtime/package-lock.json +++ b/frontend/realtime/package-lock.json @@ -8,6 +8,7 @@ "name": "storyteller-board", "version": "0.0.0", "dependencies": { + "@devnomic/marquee": "^1.0.3", "@fortawesome/free-brands-svg-icons": "^6.6.0", "@headlessui/react": "^2.1.3", "@preact/signals-react": "^2.2.0", @@ -381,6 +382,21 @@ "node": ">=6.9.0" } }, + "node_modules/@devnomic/marquee": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@devnomic/marquee/-/marquee-1.0.3.tgz", + "integrity": "sha512-q8QUtNO8ff+UvfrKJsHBtxh4fbOfhGk6SSdK0Uu/XZFdEzrmiGJ/l0FuVHRYsPAmzgnhVVnz1dGNB5CWGLMVvw==", + "dependencies": { + "clsx": "^2.1.0", + "tailwind-merge": "^2.2.0" + }, + "peerDependencies": { + "@types/react": "^18.2.47", + "@types/react-dom": "^18.2.18", + "react": "^18.2.0", + "react-dom": "^18.2.0" + } + }, "node_modules/@emotion/is-prop-valid": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-1.3.0.tgz", @@ -1510,14 +1526,12 @@ "node_modules/@types/prop-types": { "version": "15.7.12", "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.12.tgz", - "integrity": "sha512-5zvhXYtRNRluoE/jAp4GVsSduVUzNWKkOZrCDBWYtE7biZywwdC2AcEzg+cSMLFRfVgeAFqpfNabiPjxFddV1Q==", - "dev": true + "integrity": "sha512-5zvhXYtRNRluoE/jAp4GVsSduVUzNWKkOZrCDBWYtE7biZywwdC2AcEzg+cSMLFRfVgeAFqpfNabiPjxFddV1Q==" }, "node_modules/@types/react": { "version": "18.3.4", "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.4.tgz", "integrity": "sha512-J7W30FTdfCxDDjmfRM+/JqLHBIyl7xUIp9kwK637FGmY7+mkSFSe6L4jpZzhj5QMfLssSDP4/i75AKkrdC7/Jw==", - "dev": true, "dependencies": { "@types/prop-types": "*", "csstype": "^3.0.2" @@ -1527,7 +1541,6 @@ "version": "18.3.0", "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.0.tgz", "integrity": "sha512-EhwApuTmMBmXuFOikhQLIBUn6uFg81SwLMOAUgodJF14SOBOCMdU04gDoYi0WOJJHD144TL32z4yDqCW3dnkQg==", - "dev": true, "dependencies": { "@types/react": "*" } @@ -2364,8 +2377,7 @@ "node_modules/csstype": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", - "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", - "dev": true + "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==" }, "node_modules/data-view-buffer": { "version": "1.0.1", diff --git a/frontend/realtime/package.json b/frontend/realtime/package.json index a71eaa21b2..74261bea47 100644 --- a/frontend/realtime/package.json +++ b/frontend/realtime/package.json @@ -11,6 +11,7 @@ "preview": "vite preview" }, "dependencies": { + "@devnomic/marquee": "^1.0.3", "@fortawesome/free-brands-svg-icons": "^6.6.0", "@headlessui/react": "^2.1.3", "@preact/signals-react": "^2.2.0", diff --git a/frontend/realtime/public/images/generate/image0.png b/frontend/realtime/public/images/generate/image0.png new file mode 100644 index 0000000000..d69369ae9f Binary files /dev/null and b/frontend/realtime/public/images/generate/image0.png differ diff --git a/frontend/realtime/public/images/generate/image1.png b/frontend/realtime/public/images/generate/image1.png new file mode 100644 index 0000000000..b7e944d140 Binary files /dev/null and b/frontend/realtime/public/images/generate/image1.png differ diff --git a/frontend/realtime/public/images/generate/image10.png b/frontend/realtime/public/images/generate/image10.png new file mode 100644 index 0000000000..e6e74a9828 Binary files /dev/null and b/frontend/realtime/public/images/generate/image10.png differ diff --git a/frontend/realtime/public/images/generate/image11.png b/frontend/realtime/public/images/generate/image11.png new file mode 100644 index 0000000000..77ea5e4b56 Binary files /dev/null and b/frontend/realtime/public/images/generate/image11.png differ diff --git a/frontend/realtime/public/images/generate/image12.png b/frontend/realtime/public/images/generate/image12.png new file mode 100644 index 0000000000..f226cc3429 Binary files /dev/null and b/frontend/realtime/public/images/generate/image12.png differ diff --git a/frontend/realtime/public/images/generate/image13.png b/frontend/realtime/public/images/generate/image13.png new file mode 100644 index 0000000000..d3aa3add12 Binary files /dev/null and b/frontend/realtime/public/images/generate/image13.png differ diff --git a/frontend/realtime/public/images/generate/image14.png b/frontend/realtime/public/images/generate/image14.png new file mode 100644 index 0000000000..49563c366d Binary files /dev/null and b/frontend/realtime/public/images/generate/image14.png differ diff --git a/frontend/realtime/public/images/generate/image15.png b/frontend/realtime/public/images/generate/image15.png new file mode 100644 index 0000000000..ddc1f5060f Binary files /dev/null and b/frontend/realtime/public/images/generate/image15.png differ diff --git a/frontend/realtime/public/images/generate/image16.png b/frontend/realtime/public/images/generate/image16.png new file mode 100644 index 0000000000..b2374e90e9 Binary files /dev/null and b/frontend/realtime/public/images/generate/image16.png differ diff --git a/frontend/realtime/public/images/generate/image17.png b/frontend/realtime/public/images/generate/image17.png new file mode 100644 index 0000000000..1520a72bc1 Binary files /dev/null and b/frontend/realtime/public/images/generate/image17.png differ diff --git a/frontend/realtime/public/images/generate/image18.png b/frontend/realtime/public/images/generate/image18.png new file mode 100644 index 0000000000..411ac1e4f2 Binary files /dev/null and b/frontend/realtime/public/images/generate/image18.png differ diff --git a/frontend/realtime/public/images/generate/image19.png b/frontend/realtime/public/images/generate/image19.png new file mode 100644 index 0000000000..3afb4ed2bb Binary files /dev/null and b/frontend/realtime/public/images/generate/image19.png differ diff --git a/frontend/realtime/public/images/generate/image2.png b/frontend/realtime/public/images/generate/image2.png new file mode 100644 index 0000000000..652a008e4c Binary files /dev/null and b/frontend/realtime/public/images/generate/image2.png differ diff --git a/frontend/realtime/public/images/generate/image20.png b/frontend/realtime/public/images/generate/image20.png new file mode 100644 index 0000000000..45a335385c Binary files /dev/null and b/frontend/realtime/public/images/generate/image20.png differ diff --git a/frontend/realtime/public/images/generate/image3.png b/frontend/realtime/public/images/generate/image3.png new file mode 100644 index 0000000000..7efbe26eed Binary files /dev/null and b/frontend/realtime/public/images/generate/image3.png differ diff --git a/frontend/realtime/public/images/generate/image4.png b/frontend/realtime/public/images/generate/image4.png new file mode 100644 index 0000000000..102b2fa652 Binary files /dev/null and b/frontend/realtime/public/images/generate/image4.png differ diff --git a/frontend/realtime/public/images/generate/image5.png b/frontend/realtime/public/images/generate/image5.png new file mode 100644 index 0000000000..fdac17b380 Binary files /dev/null and b/frontend/realtime/public/images/generate/image5.png differ diff --git a/frontend/realtime/public/images/generate/image6.png b/frontend/realtime/public/images/generate/image6.png new file mode 100644 index 0000000000..2d8e34a0eb Binary files /dev/null and b/frontend/realtime/public/images/generate/image6.png differ diff --git a/frontend/realtime/public/images/generate/image7.png b/frontend/realtime/public/images/generate/image7.png new file mode 100644 index 0000000000..c457d2279d Binary files /dev/null and b/frontend/realtime/public/images/generate/image7.png differ diff --git a/frontend/realtime/public/images/generate/image8.png b/frontend/realtime/public/images/generate/image8.png new file mode 100644 index 0000000000..aac964e0c6 Binary files /dev/null and b/frontend/realtime/public/images/generate/image8.png differ diff --git a/frontend/realtime/public/images/generate/image9.png b/frontend/realtime/public/images/generate/image9.png new file mode 100644 index 0000000000..d5b34b0b44 Binary files /dev/null and b/frontend/realtime/public/images/generate/image9.png differ diff --git a/frontend/realtime/src/GenerationRootComponent/BackgroundGallery.tsx b/frontend/realtime/src/GenerationRootComponent/BackgroundGallery.tsx new file mode 100644 index 0000000000..0408ca8f02 --- /dev/null +++ b/frontend/realtime/src/GenerationRootComponent/BackgroundGallery.tsx @@ -0,0 +1,145 @@ +import { useEffect, useState } from "react"; +import { Marquee } from "@devnomic/marquee"; +import "@devnomic/marquee/dist/index.css"; + +function getRandomImages(count: number) { + const images = Array.from({ length: count }, (_, i) => ({ + id: i + 1, + src: `/images/generate/image${i + 1}.png`, + alt: `Generated image ${i + 1}`, + })); + + // Shuffle the array + return [...images].sort(() => Math.random() - 0.5); +} + +interface ImageColumnProps { + images: Array<{ id: number; src: string; alt: string }>; + delay: number; + reverse?: boolean; + isLoaded: boolean; + duration?: number; +} + +function ImageColumn({ + images, + delay, + reverse = false, + duration = 100, + isLoaded, +}: ImageColumnProps) { + return ( +
+ + {images.map((image, i) => ( +
+ {image.alt} +
+ ))} +
+
+ ); +} + +export default function GalleryBackground() { + const [images, _setImages] = useState(() => getRandomImages(20)); + const [isLoaded, setIsLoaded] = useState(false); + + useEffect(() => { + // delay for smooth animation + const timer = setTimeout(() => { + setIsLoaded(true); + }, 100); + + return () => clearTimeout(timer); + }, []); + + // Columns for masonry layout + const columns = { + col1: images.filter((_, i) => i % 5 === 0), + col2: images.filter((_, i) => i % 5 === 1), + col3: images.filter((_, i) => i % 5 === 2), + col4: images.filter((_, i) => i % 5 === 3), + col5: images.filter((_, i) => i % 5 === 4), + }; + + return ( + <> +
+
+
+
+ + + + + +
+
+
+ + ); +} diff --git a/frontend/realtime/src/GenerationRootComponent/GenerationRootComponent.tsx b/frontend/realtime/src/GenerationRootComponent/GenerationRootComponent.tsx index ea5ef959e5..35a5fac7e7 100644 --- a/frontend/realtime/src/GenerationRootComponent/GenerationRootComponent.tsx +++ b/frontend/realtime/src/GenerationRootComponent/GenerationRootComponent.tsx @@ -3,7 +3,10 @@ import { useSignals } from "@preact/signals-react/runtime"; import { Button, LoadingSpinner } from "~/components/ui"; import { useRenderCounter } from "~/hooks/useRenderCounter"; import { GenerationLoadingState, generationSignal } from "~/signals"; -import { useRef } from "react"; +import { useRef, useState } from "react"; +import BackgroundGallery from "./BackgroundGallery"; +import { twMerge } from "tailwind-merge"; +import { Transition } from "@headlessui/react"; export const GenerationRootComponent = () => { // This is a hook that will log the number of times the component has rerendered @@ -12,22 +15,29 @@ export const GenerationRootComponent = () => { useSignals(); const generationState = generationSignal.value; - const inputRef = useRef(null); + const inputRef = useRef(null); + const [isInputFocused, setIsInputFocused] = useState(false); const handleGenerate = () => { if (!inputRef.current) { - return - }; + return; + } // TODO: For testing only!!! Remove when finished if (generationState.loadingState === GenerationLoadingState.GENERATING) { - generationSignal.value = { loadingState: GenerationLoadingState.INIT, prompt: "" }; + generationSignal.value = { + loadingState: GenerationLoadingState.INIT, + prompt: "", + }; return; } const prompt = inputRef.current.value; - generationSignal.value = { loadingState: GenerationLoadingState.GENERATING, prompt }; - + generationSignal.value = { + loadingState: GenerationLoadingState.GENERATING, + prompt, + }; + // TODO: Write the signal change effect in generationSignals.ts // TODO: Call the server to generate the image }; @@ -35,15 +45,17 @@ export const GenerationRootComponent = () => { let contentElement; switch (generationState.loadingState) { case GenerationLoadingState.INIT: - contentElement = -
- Generate Image - Imagine, Describe, Generate. -
- break; + contentElement = null; + break; case GenerationLoadingState.GENERATING: case GenerationLoadingState.GENERATED: - contentElement = + contentElement = ( + + ); break; } @@ -52,50 +64,129 @@ export const GenerationRootComponent = () => { return ( <> -
+
+ {contentElement} -
- - + +
+ +
+ Generate Image + + Imagine, Describe, Generate. +
+
+
+