mirror of
https://github.com/spacedriveapp/spacedrive.git
synced 2026-05-02 20:34:16 -04:00
before-after component implementation
This commit is contained in:
@@ -11,7 +11,7 @@ export async function Header() {
|
||||
const release = await githubFetch(getLatestRelease);
|
||||
const { frontmatter } = getReleaseFrontmatter(release);
|
||||
return (
|
||||
<div className="flex flex-col items-center w-full px-4">
|
||||
<div className="flex w-full flex-col items-center px-4">
|
||||
<div className="mt-22 lg:mt-28" id="content" aria-hidden="true" />
|
||||
<div className="mt-24 lg:mt-8" aria-hidden="true" />
|
||||
|
||||
@@ -29,7 +29,7 @@ export async function Header() {
|
||||
</span>
|
||||
</h1>
|
||||
|
||||
<p className="z-30 max-w-4xl mt-1 mb-8 text-center animation-delay-1 fade-in-heading text-md leading-2 text-gray-450 lg:text-lg lg:leading-8">
|
||||
<p className="animation-delay-1 fade-in-heading text-md leading-2 z-30 mb-8 mt-1 max-w-4xl text-center text-gray-450 lg:text-lg lg:leading-8">
|
||||
Your files, always within reach. Experience seamless synchronization, intuitive
|
||||
management, and powerful discovery tools — all in one place.
|
||||
</p>
|
||||
|
||||
@@ -14,7 +14,7 @@ export const metadata = {
|
||||
|
||||
export default function Page() {
|
||||
return (
|
||||
<div className="flex flex-col gap-12 md:gap-[200px]">
|
||||
<div className="flex flex-col gap-6 md:gap-[200px]">
|
||||
<Header />
|
||||
<Explorer />
|
||||
<Features />
|
||||
|
||||
@@ -1,11 +1,22 @@
|
||||
'use client';
|
||||
|
||||
import React from 'react';
|
||||
import After from '~/assets/after.jpg';
|
||||
import Before from '~/assets/before.jpg';
|
||||
import { Slider } from '~/components/before-after';
|
||||
|
||||
interface Props {
|
||||
// props
|
||||
}
|
||||
|
||||
const Page: React.FC<Props> = () => {
|
||||
return <h1>Teams</h1>;
|
||||
return (
|
||||
<div className="flex w-full flex-col items-center px-4">
|
||||
<div className="mt-22 lg:mt-28" id="content" aria-hidden="true" />
|
||||
<div className="mt-24 lg:mt-8" aria-hidden="true" /> <h1>Teams</h1>
|
||||
<Slider beforeImage={Before} afterImage={After} />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default Page;
|
||||
|
||||
BIN
apps/landing/src/assets/after.jpg
Normal file
BIN
apps/landing/src/assets/after.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 882 KiB |
BIN
apps/landing/src/assets/before.jpg
Normal file
BIN
apps/landing/src/assets/before.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 902 KiB |
80
apps/landing/src/components/before-after.tsx
Normal file
80
apps/landing/src/components/before-after.tsx
Normal file
@@ -0,0 +1,80 @@
|
||||
'use client';
|
||||
|
||||
import { ArrowsInLineHorizontal, CaretUpDown } from '@phosphor-icons/react';
|
||||
import Image, { StaticImageData } from 'next/image';
|
||||
import { useState } from 'react';
|
||||
|
||||
interface SliderProps {
|
||||
beforeImage: string | StaticImageData;
|
||||
afterImage: string | StaticImageData;
|
||||
}
|
||||
|
||||
export const Slider: React.FC<SliderProps> = ({ beforeImage, afterImage }) => {
|
||||
const [sliderPosition, setSliderPosition] = useState(50);
|
||||
const [isDragging, setIsDragging] = useState(false);
|
||||
|
||||
const handleMove = (event: React.MouseEvent<HTMLDivElement, MouseEvent>) => {
|
||||
if (!isDragging) return;
|
||||
|
||||
const rect = event.currentTarget.getBoundingClientRect();
|
||||
const x = Math.max(0, Math.min(event.clientX - rect.left, rect.width));
|
||||
const percent = Math.max(0, Math.min((x / rect.width) * 100, 100));
|
||||
|
||||
setSliderPosition(percent);
|
||||
};
|
||||
|
||||
const handleMouseDown = () => {
|
||||
setIsDragging(true);
|
||||
};
|
||||
|
||||
const handleMouseUp = () => {
|
||||
setIsDragging(false);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="relative w-full" onMouseUp={handleMouseUp}>
|
||||
<div
|
||||
className="relative m-auto aspect-[5/3] max-h-[300px] w-full max-w-[1000px] select-none overflow-hidden rounded-lg shadow-xl"
|
||||
onMouseMove={handleMove}
|
||||
onMouseDown={handleMouseDown}
|
||||
>
|
||||
<Image
|
||||
alt="Before"
|
||||
fill
|
||||
draggable={false}
|
||||
priority
|
||||
src={beforeImage}
|
||||
className="rounded-lg"
|
||||
/>
|
||||
|
||||
<div
|
||||
className="absolute inset-x-0 top-0 m-auto aspect-[70/45] max-h-[300px] w-full max-w-[1000px] select-none overflow-hidden rounded-lg"
|
||||
style={{ clipPath: `inset(0 ${100 - sliderPosition}% 0 0)` }}
|
||||
>
|
||||
<Image
|
||||
fill
|
||||
priority
|
||||
draggable={false}
|
||||
alt="After"
|
||||
src={afterImage}
|
||||
className="rounded-lg"
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Slider handle */}
|
||||
<div
|
||||
className="absolute bottom-0 top-0 w-[2px] cursor-ew-resize bg-white"
|
||||
style={{
|
||||
left: `calc(${sliderPosition}% - 1px)`
|
||||
}}
|
||||
>
|
||||
<CaretUpDown
|
||||
size={48}
|
||||
className="absolute -left-[22px] top-[calc(50%-10px)]"
|
||||
style={{ transform: 'rotate(90deg)' }}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -29,7 +29,7 @@ import { ExternalLinkRegex } from '~/utils/regex-external-link';
|
||||
const NAVIGATION_ITEMS: { label: string; href: string; adornment?: string }[] = [
|
||||
{ label: 'Explorer', href: '#' },
|
||||
{ label: 'Cloud', href: '#' },
|
||||
{ label: 'Teams', href: '#' },
|
||||
{ label: 'Teams', href: '/teams' },
|
||||
{ label: 'Assistant', href: '#', adornment: 'New' },
|
||||
{ label: 'Store', href: '#' },
|
||||
{ label: 'Use Cases', href: '#' },
|
||||
|
||||
Reference in New Issue
Block a user