Jump to content
Search Community

Taun

Members
  • Posts

    9
  • Joined

  • Last visited

Everything posted by Taun

  1. Any solution? My animations for menu and work item don't fire the first click, but fire after that fine.
  2. Cool, thanks. It seems to be working now. I just needed some fresh air to notice the obvious.
  3. I've gone through the examples and read the docs. My confusion lies in the wrapping of animations with useLayoutEffect. The GSAP examples don't express the complexity of multiple React animations called inside and outside of useEffect. I think this may be more of a React question, but if you can help that'll be great. So I can't call the animateIn() function because it's defined inside of the useLayout. If I wrap all animations inside useLayout hooks, I can't call them outside of that hook, so I can't call it onClick that's defined in the return statement? Do I then have multiple gsap.context functions within each useLayout? What do you suggest?
  4. Thanks, I'll study those examples and read through the docs again tomorrow.
  5. Hi. How should I apply gsapContext() in this React project? I've read the docs - " Let's say you've got a big block of GSAP code that's creating a bunch of different animations and you need to be able to revert() them all... let ctx = gsap.context(() => { gsap.to(...); gsap.from(...); gsap.timeline().to(...).to(...); ... }); // then later... ctx.revert(); // BOOM! Every GSAP animation created in that function gets reverted!" When I try wrap the animation code with ctx, I get syntax errors. I don't know what I'm doing. Any suggestions? Codesandbox: https://codesandbox.io/p/github/taunhealy/Circa9_Website1/remote?layout=%7B%22sidebarPanel%22%3A%22EXPLORER%22%2C%22rootPanelGroup%22%3A%7B%22direction%22%3A%22horizontal%22%2C%22contentType%22%3A%22UNKNOWN%22%2C%22type%22%3A%22PANEL_GROUP%22%2C%22id%22%3A%22ROOT_LAYOUT%22%2C%22panels%22%3A%5B%7B%22type%22%3A%22PANEL_GROUP%22%2C%22contentType%22%3A%22UNKNOWN%22%2C%22direction%22%3A%22vertical%22%2C%22id%22%3A%22clpilwho400i7356he4lpemkn%22%2C%22sizes%22%3A%5B70%2C30%5D%2C%22panels%22%3A%5B%7B%22type%22%3A%22PANEL_GROUP%22%2C%22contentType%22%3A%22EDITOR%22%2C%22direction%22%3A%22horizontal%22%2C%22id%22%3A%22EDITOR%22%2C%22panels%22%3A%5B%7B%22type%22%3A%22PANEL%22%2C%22contentType%22%3A%22EDITOR%22%2C%22id%22%3A%22clpilwho400i2356h5bzguxv5%22%7D%5D%7D%2C%7B%22type%22%3A%22PANEL_GROUP%22%2C%22contentType%22%3A%22SHELLS%22%2C%22direction%22%3A%22horizontal%22%2C%22id%22%3A%22SHELLS%22%2C%22panels%22%3A%5B%7B%22type%22%3A%22PANEL%22%2C%22contentType%22%3A%22SHELLS%22%2C%22id%22%3A%22clpilwho400i4356hwsxjaz1b%22%7D%5D%2C%22sizes%22%3A%5B100%5D%7D%5D%7D%2C%7B%22type%22%3A%22PANEL_GROUP%22%2C%22contentType%22%3A%22DEVTOOLS%22%2C%22direction%22%3A%22vertical%22%2C%22id%22%3A%22DEVTOOLS%22%2C%22panels%22%3A%5B%7B%22type%22%3A%22PANEL%22%2C%22contentType%22%3A%22DEVTOOLS%22%2C%22id%22%3A%22clpilwho400i6356hy0h1wjva%22%7D%5D%2C%22sizes%22%3A%5B100%5D%7D%5D%2C%22sizes%22%3A%5B45.91051099661234%2C54.08948900338766%5D%7D%2C%22tabbedPanels%22%3A%7B%22clpilwho400i2356h5bzguxv5%22%3A%7B%22tabs%22%3A%5B%7B%22id%22%3A%22clpilwho400i1356hzmk7l9tz%22%2C%22mode%22%3A%22permanent%22%2C%22type%22%3A%22FILE%22%2C%22filepath%22%3A%22%2FREADME.md%22%2C%22state%22%3A%22IDLE%22%7D%5D%2C%22id%22%3A%22clpilwho400i2356h5bzguxv5%22%2C%22activeTabId%22%3A%22clpilwho400i1356hzmk7l9tz%22%7D%2C%22clpilwho400i6356hy0h1wjva%22%3A%7B%22tabs%22%3A%5B%7B%22id%22%3A%22clpilwho400i5356hmfd9pzie%22%2C%22mode%22%3A%22permanent%22%2C%22type%22%3A%22TASK_PORT%22%2C%22taskId%22%3A%22dev%22%2C%22port%22%3A3000%2C%22path%22%3A%22%2F%22%7D%5D%2C%22id%22%3A%22clpilwho400i6356hy0h1wjva%22%2C%22activeTabId%22%3A%22clpilwho400i5356hmfd9pzie%22%7D%2C%22clpilwho400i4356hwsxjaz1b%22%3A%7B%22tabs%22%3A%5B%7B%22id%22%3A%22clpilwho400i3356hrt4hf4ia%22%2C%22mode%22%3A%22permanent%22%2C%22type%22%3A%22TASK_LOG%22%2C%22taskId%22%3A%22dev%22%7D%5D%2C%22id%22%3A%22clpilwho400i4356hwsxjaz1b%22%2C%22activeTabId%22%3A%22clpilwho400i3356hrt4hf4ia%22%7D%7D%2C%22showDevtools%22%3Atrue%2C%22showShells%22%3Atrue%2C%22showSidebar%22%3Atrue%2C%22sidebarPanelSize%22%3A22.61421301650344%7D Relevant code: ``` "use client"; import React, { useState, useMemo, useEffect, useRef } from "react"; import gsap from "gsap"; import "./sliderswiper.css"; interface Item { id: number; title: string; img: string; date: string; brand: string; desc?: string; director?: string; producer?: string; cinematographer?: string; } interface SliderProps { items: Item[]; } const SliderSwiper: React.FC<SliderProps> = ({ items }) => { const [currentIndex, setCurrentIndex] = useState(0); const [selectedBrand, setSelectedBrand] = useState<string | null>("Recent"); const brands = useMemo(() => { const uniqueBrands = Array.from( new Set( items.filter((item) => item.brand !== "all").map((item) => item.brand) ) ); return ["Recent", ...uniqueBrands]; }, [items]); const filteredItems = useMemo(() => { if (selectedBrand === "Recent") { const validDateItems = items.filter((item) => item.date); return validDateItems .sort((a, b) => new Date(b.date).getTime() - new Date(a.date).getTime()) .slice(0, 9); } else { return items.filter((item) => item.brand === selectedBrand); } }, [items, selectedBrand]); const itemTitlesRef = useRef<NodeListOf<Element> | null>(null); const itemImageRef = useRef<HTMLImageElement | null>(null); const buttonPrevRef = useRef<HTMLButtonElement | null>(null); const buttonNextRef = useRef<HTMLButtonElement | null>(null); const brandFilterButtonsRef = useRef<NodeListOf<Element> | null>(null); useEffect(() => { // Store refs to elements itemTitlesRef.current = document.querySelectorAll(".item-titles"); itemImageRef.current = document.querySelector(".item-image"); buttonPrevRef.current = document.querySelector(".button-prev"); buttonNextRef.current = document.querySelector(".button-next"); brandFilterButtonsRef.current = document.querySelectorAll( ".brand-filter-buttons" ); }, []); const handleFilterChange = (brand: string | null): void => { gsap.to( [ itemTitlesRef.current, itemImageRef.current, buttonPrevRef.current, buttonNextRef.current, brandFilterButtonsRef.current, ], { opacity: 0, duration: 0.3, ease: "power3.out", onComplete: () => { setSelectedBrand(brand); setCurrentIndex(0); animateIn(); }, } ); }; const animateIn = () => { const timeline = gsap.timeline({ defaults: { ease: "power3.out" } }); timeline.fromTo( itemTitlesRef.current, { opacity: 0, y: 20 }, { opacity: 1, y: 0, duration: 1 }, "start" ); timeline.fromTo( itemImageRef.current, { opacity: 0, y: 20 }, { opacity: 1, y: 0, duration: 1 }, "start+=0.2" ); timeline.fromTo( buttonPrevRef.current, { opacity: 0, x: -20 }, { opacity: 1, x: 0, duration: 0.3, stagger: 0.1 }, "start+=0.5" ); timeline.fromTo( buttonNextRef.current, { opacity: 0, x: -20 }, { opacity: 1, x: 0, duration: 0.3, stagger: 0.1 }, "start+=0.5" ); timeline.fromTo( brandFilterButtonsRef.current, { opacity: 0, y: 20 }, { opacity: 1, y: 0, duration: 0.5 }, "start+=0.5" ); }; const handleNextItem = () => { gsap.to( [ itemTitlesRef.current, itemImageRef.current, buttonPrevRef.current, buttonNextRef.current, ], { opacity: 0, duration: 0.3, ease: "power3.out", onComplete: () => { setCurrentIndex( (prevIndex) => (prevIndex + 1) % filteredItems.length ); animateIn(); }, } ); }; const handlePrevItem = () => { gsap.to( [ itemImageRef.current, itemTitlesRef.current, buttonPrevRef.current, buttonNextRef.current, ], { opacity: 0, duration: 0.3, ease: "power3.out", onComplete: () => { setCurrentIndex( (prevIndex) => (prevIndex - 1 + filteredItems.length) % filteredItems.length ); animateIn(); }, } ); }; return ( <div className="item-background-container"> {filteredItems.length > 0 && ( <section className="item-titles"> <div className="brand-title">{filteredItems[currentIndex].brand}</div> <div className="item-title">{filteredItems[currentIndex].title}</div> </section> )} <div className="brand-filter-sidebar"> {brands.map((brand) => ( <button key={brand} className={`brand-filter-buttons ${ selectedBrand === brand ? "active" : "" }`} onClick={() => handleFilterChange(brand)} > {brand} </button> ))} </div> <div className="item-image-container"> {filteredItems.length > 0 && ( <img className="item-image" src={filteredItems[currentIndex].img} alt={filteredItems[currentIndex].title} /> )} </div> <div className="nextprev-button-wrapper"> <button type="button" className="button-prev" onClick={handlePrevItem}> <img src="/arrows/left-chevron-svgrepo-com.svg" alt="Previous" /> </button> <button type="button" className="button-next" onClick={handleNextItem}> <img src="/arrows/right-chevron-svgrepo-com.svg" alt="Next" /> </button> </div> </div> ); }; export default SliderSwiper;``` I'd like to prevent the flashing that sometimes happens when animations fire.
  6. Hi. I don't understand why my code isn't rendering? When I got it to render in VSCode, it rendered the images vertically in a column, not horizontally. I thought flex-direction:row would make the slider display in a row? Code Sandbox: https://codesandbox.io/s/gsap-horizontalscrolltrigger-mz7d68?file=/src/components/scrollsection.scss:47-167 .scroll-section-inner { height: 100vh; width: 100vw; display: flex; flex-direction: row; position: relative; }
  7. The CodeSandbox isn't loading anything? It's loading fine locally via VSCode.
  8. Hi. I'd like to create a portfolio website wherein there's a fixed sidebar with the portfolio titles and alongside that, centered to the page, is a Hero component that renders containers with thumbnail images. When the user clicks on a portfolio title it should scroll down to the thumbnail. In the test Codesandbox project, the button displays and works, but there's no styling for the containers? Do you know how I can show their colors? What CSS approach do you recommend to display the nav of portfolio items on the left side of the page? CSS grid? I know this a CSS query, though once I'm passed this stage I'm sure I'll have related GSAP questions. CodeSandbox: https://codesandbox.io/s/gsap-scrolltosection-mz7d68?file=/src/index.js
×
×
  • Create New...