Quantcast
Channel: Active questions tagged svelte - Stack Overflow
Viewing all articles
Browse latest Browse all 1812

Slider that translates content in and out of container based on slider x-axis position

$
0
0

I'm working on a slider that has 4 stages of content. I am trying to translate the content in and out of the container based on the slider's position on the x-axis. I need the content to move with the slider, not transition or animate automatically. I have been working on this for days and I cannot figure it out. I'm working with svelte, typescript, and tailwind css, which I'm relatively new to svelte and typescript. I'm not sure if this would be easier to achieve with GSAP? (which I have a little bit of experience with) Here is my current code:

<script lang="ts">  import { onMount } from "svelte";  import { writable } from "svelte/store";  import { projects } from "../../data/project";  import Header from "../Header.svelte";  import { MoveRight, MoveLeft, ArrowLeft } from "lucide-svelte";  function navigateHome() {    window.location.href = "/";  }  const currentStage = writable(0);  let left = 0;  let moving = false;  let button: HTMLElement;  let h2Stage2: HTMLDivElement;  let h2Stage3: HTMLDivElement;  let imgStage2: HTMLDivElement;  let imgStage3: HTMLDivElement;  let stage1Content: HTMLDivElement;  let stage4Content: HTMLDivElement;  function onMouseDown() {    moving = true;  }  function onMouseMove(e: MouseEvent) {    if (moving) {      const container = document.querySelector(".draggable-container"      ) as HTMLElement;      if (!container) return;      const containerWidth = container.offsetWidth;      const buttonWidth = button.offsetWidth;      const maxDraggableWidth = containerWidth * 0.9;      let newPosition =        e.clientX - container.getBoundingClientRect().left - buttonWidth / 2;      newPosition = Math.min(        Math.max(0, newPosition),        maxDraggableWidth - buttonWidth      );      const percentage = (newPosition / maxDraggableWidth) * 100;      currentStage.set(calculateStage(percentage));      left = percentage;      updateStagePositions(percentage);    }  }  function onMouseUp() {    moving = false;  }  function calculateStage(percentage: number): number {    if (percentage <= 25) {      return 0;    } else if (percentage <= 50) {      return 1;    } else if (percentage <= 75) {      return 2;    } else {      return 3;    }  }  function updateStagePositions(percentage: number) {    const translateValue = (100 - percentage * 4).toFixed(2); // calculate translate value    const reverseTranslateValue = (percentage * 4 - 100).toFixed(2); // reverse translate value    if ($currentStage === 0) {      stage1Content.style.transform = `translateY(${translateValue}px)`;    } else if ($currentStage === 1) {      h2Stage2.style.transform = `translateY(${translateValue}px)`;      imgStage2.style.transform = `translateY(${reverseTranslateValue}px)`;    } else if ($currentStage === 2) {      h2Stage3.style.transform = `translateY(${translateValue}px)`;      imgStage3.style.transform = `translateY(${reverseTranslateValue}px)`;    } else if ($currentStage === 3) {      stage4Content.style.transform = `translateY(${translateValue}px)`;    }  }  onMount(() => {    window.scrollTo(0, 0);  });  export let slug: string;  interface Project {    image: string | null | undefined;    title: string;    description: string;    heading: string;    subhead1: string;    subhead2: string;    info: string;    featuredImage1: string;    featuredImage2: string;    featuredImage3: string;    highlights: string;    highlightList: string[];    media: string;    pcoeTeam: string;    tags: string[];    team: string[];  }  let project: Project | null = null;  onMount(() => {    project = projects.find((p) => p.slug === slug) || null;  });</script><Header /><div  class="projectDescription grid gap-2 justify-enter text-white bg-black text-center uppercase"><h2 class="text-6xl font-thin">Meta</h2><h3 class="text-3xl font-medium">Pursuit Innovation Exhibit</h3><button    class="absolute cursor-pointer flex gap-2 uppercase top-48 left-80 text-white bg-black"    on:click={navigateHome}    tabindex="0"    on:keydown={(event) => {      if (event.key === "Enter") {        navigateHome();      }    }}><ArrowLeft />Back</button></div><div class="main bg-black py-12"><div    class="draggable-container h-[70vh] relative flex justify-center w-[60vw] m-auto overflow-hidden">    {#if $currentStage === 0}<div        class="absolute grid grid-cols-2 top-0 left-0 right-0 bottom-0 rounded-2xl pl-16 py-12 pr-12 bg-cover bg-no-repeat"        style="background-image: url('../../../public/slide.jpg');"><div          class="tag-container absolute flex flex-row gap-6 pt-8 pl-16 text-[#34F0FF] uppercase font-semibold">          {#each project?.tags ?? [] as tag}<div class="tag">{tag}</div>          {/each}</div><div class="stage1-left pt-16" bind:this={stage1Content}><h2 class="text-6xl">{project?.heading}</h2><h3 class="text-2xl font-bold uppercase pt-6 w-96">            {project?.subhead1}</h3></div></div>    {:else if $currentStage === 1}<div        class="absolute grid grid-cols-2 top-0 left-0 right-0 bottom-0 rounded-2xl pl-16 py-12 pr-12 bg-cover bg-no-repeat"        style="background-image: linear-gradient(to top right, #A8F9FF 55%, #34F0FF);"><div          class="tag-container absolute flex flex-row gap-6 pt-8 pl-16 text-[#34F0FF] uppercase font-semibold opacity-30"><div class="tag">Tag 1</div><div class="tag">Tag 2</div><div class="tag">Tag 3</div><div class="tag">Tag 4</div></div><div class="stage2-left w-[400px] pt-16" bind:this={h2Stage2}><h2 class="text-3xl font-black uppercase pb-2">            {project?.subhead2}</h2><p>{project?.info}</p></div><div class="stage2-right" bind:this={imgStage2}><img src={project?.featuredImage1} alt="Meta" class="w-full mt-12" /></div></div>    {:else if $currentStage === 2}<div        class="absolute grid grid-cols-2 top-0 left-0 right-0 bottom-0 rounded-2xl pl-16 py-12 pr-12 bg-cover bg-no-repeat"        style="background-image: linear-gradient(to top right, #A8F9FF 55%, #34F0FF);"><div          class="tag-container absolute flex flex-row gap-6 pt-8 pl-16 text-[#34F0FF] uppercase font-semibold opacity-30">          {#each project?.tags ?? [] as tag}<div class="tag">{tag}</div>          {/each}</div><div class="stage3-left pt-16" bind:this={h2Stage3}><div class="image-container grid gap-2"><img src={project?.featuredImage2} alt="Meta" class="px-5" /><img src={project?.featuredImage3} alt="Meta" class="w-fit" /></div></div><div          class="stage3-right grid pt-16 justify-center grid-rows-[50px_1fr_1fr_1fr_1fr"          bind:this={imgStage3}><h2 class="text-3xl font-black uppercase w-full text-center">            {project?.highlights}</h2><ul class="highlights grid gap-2 w-full px-14 text-sm">            {#each project?.highlightList ?? [] as highlight}<li class="highlights">{highlight}</li>            {/each}</ul></div></div>    {:else if $currentStage === 3}<div        class="absolute grid grid-cols-2 top-0 left-0 right-0 bottom-0 rounded-2xl pl-16 py-12 pr-12 bg-cover bg-no-repeat"        style="background-image: linear-gradient(to top right, #A8F9FF 55%, #34F0FF);"><div          class="tag-container absolute flex flex-row gap-6 pt-8 pl-16 text-[#34F0FF] uppercase font-semibold opacity-30">          {#each project?.tags ?? [] as tag}<div class="tag">{tag}</div>          {/each}</div><div class="stage4-left grid content-center" bind:this={stage4Content}><div class="image-container pl-12"><img src={project?.media} alt="Meta" /></div></div><div          class="stage4-right ml-24 grid gap-2 content-center justify-end border-l-2 border-y-2 border-white pr-12 rounded-l-xl"><h2 class="font-black uppercase text-black text-xl">            {project?.pcoeTeam}</h2><ul>            {#each project?.team ?? [] as team}<li>{team}</li>            {/each}</ul><button            class="uppercase flex items-center gap-2 text-sm text-black font-black mt-16 border-white rounded-full border-2 px-6 py-1">            Access Files<MoveRight /></button></div></div>    {/if}<section      class="draggable absolute bottom-5 h-16 flex items-center"      style="left: {left}%"      bind:this={button}      on:mousedown={onMouseDown}      role="button"      tabindex="0"><button        class="w-auto h-12 font-black uppercase bg-[#34F0FF] border-solid border-white border-2 flex gap-2 px-2 items-center justify-center rounded-full cursor-pointer ml-6 z-10"><MoveLeft size="30" />Drag<MoveRight size="30" /></button></section><div class="dragLine absolute bottom-12 w-[50vw] h-[2px] bg-white"></div></div></div><svelte:window on:mouseup={onMouseUp} on:mousemove={onMouseMove} /><style lang="postcss">  .tag {    background: #0d4246;    padding: 6px 27px;    border-radius: 0 18px;  }  .highlights li {    background: #34f0ff;    border-radius: 0 18px;    padding: 10px 16px;  }</style>

Is there any other way to achieve this or am I even going in the right direction? Any feedback, suggestions, or help is greatly appreciated.


Viewing all articles
Browse latest Browse all 1812

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>