mirror of
https://github.com/ClipFusion-org/clipfusion.git
synced 2025-08-05 18:15:08 +00:00
Project Library
title now fades when scrolling up
This commit is contained in:
parent
acd0762f82
commit
35f4084833
@ -32,6 +32,7 @@ import { Sheet, SheetClose, SheetContent, SheetDescription, SheetHeader, SheetTi
|
|||||||
import { Separator } from "@/components/ui/separator";
|
import { Separator } from "@/components/ui/separator";
|
||||||
import StaticSidebarTrigger from "@/components/static-sidebar-trigger";
|
import StaticSidebarTrigger from "@/components/static-sidebar-trigger";
|
||||||
import SidebarTriggerAdjustable from "@/components/sidebar-trigger-adjustable";
|
import SidebarTriggerAdjustable from "@/components/sidebar-trigger-adjustable";
|
||||||
|
import ScrollFadingTitle from "@/components/scroll-fading-title";
|
||||||
|
|
||||||
type SortingType = "byCreationDate"
|
type SortingType = "byCreationDate"
|
||||||
| "byEditDate"
|
| "byEditDate"
|
||||||
@ -491,8 +492,10 @@ export default function Home(): ReactNode {
|
|||||||
<div className="p-5">
|
<div className="p-5">
|
||||||
<div className="flex flex-row items-center gap-2">
|
<div className="flex flex-row items-center gap-2">
|
||||||
<StaticSidebarTrigger />
|
<StaticSidebarTrigger />
|
||||||
<h2 className="font-bold break-keep text-xl sm:text-2xl md:text-3xl lg:text-4xl leading-none">Project Library</h2>
|
<ScrollFadingTitle className="flex flex-row items-center gap-2">
|
||||||
{projects && <Label className="text-muted-foreground text-sm">(Found {projects.length} projects)</Label>}
|
<h2 className="font-bold break-keep text-xl sm:text-2xl md:text-3xl lg:text-4xl leading-none">Project Library</h2>
|
||||||
|
{projects && <Label className="text-muted-foreground text-sm">(Found {projects.length} projects)</Label>}
|
||||||
|
</ScrollFadingTitle>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex flex-col sticky top-safe bg-background gap-2 mt-2 pb-2 pt-2 p-5 w-[100% + 5 * var(--spacing)] z-10 -mx-5">
|
<div className="flex flex-col sticky top-safe bg-background gap-2 mt-2 pb-2 pt-2 p-5 w-[100% + 5 * var(--spacing)] z-10 -mx-5">
|
||||||
<SidebarTriggerAdjustable>
|
<SidebarTriggerAdjustable>
|
||||||
|
24
src/components/scroll-fading-title/ScrollFadingTitle.tsx
Normal file
24
src/components/scroll-fading-title/ScrollFadingTitle.tsx
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
import { ComponentProps, useEffect, useRef, useState } from "react";
|
||||||
|
|
||||||
|
const easeFade = (x: number) => (
|
||||||
|
x === 0 ? 0 : Math.pow(2, 10 * x - 10)
|
||||||
|
);
|
||||||
|
|
||||||
|
export const ScrollFadingTitle = (props: ComponentProps<"div">) => {
|
||||||
|
const elementRef = useRef<HTMLDivElement>(null);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const handleScroll = () => {
|
||||||
|
if (!elementRef.current) return;
|
||||||
|
const opacity = easeFade(1 - (window.scrollY / ( window.innerHeight / 20)));
|
||||||
|
elementRef.current.style.opacity = `${opacity}`;
|
||||||
|
};
|
||||||
|
|
||||||
|
handleScroll();
|
||||||
|
window.addEventListener('scroll', handleScroll);
|
||||||
|
|
||||||
|
return () => window.removeEventListener('scroll', handleScroll);
|
||||||
|
}, [elementRef]);
|
||||||
|
|
||||||
|
return <div style={{opacity: 1}} ref={elementRef} {...props}/>
|
||||||
|
};
|
3
src/components/scroll-fading-title/index.ts
Normal file
3
src/components/scroll-fading-title/index.ts
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
import { ScrollFadingTitle } from "./ScrollFadingTitle";
|
||||||
|
|
||||||
|
export default ScrollFadingTitle;
|
@ -4,43 +4,32 @@ import { cn } from "@/lib/utils";
|
|||||||
import { ComponentProps, useEffect, useState } from "react";
|
import { ComponentProps, useEffect, useState } from "react";
|
||||||
|
|
||||||
const easeSlide = (x: number) => (
|
const easeSlide = (x: number) => (
|
||||||
x
|
1 - Math.pow(1 - x, 3)
|
||||||
);
|
);
|
||||||
|
|
||||||
export const SidebarTriggerAdjustable = (props: ComponentProps<"div">) => {
|
export const SidebarTriggerAdjustable = (props: ComponentProps<"div">) => {
|
||||||
const [scrollY, setScrollY] = useState(0);
|
|
||||||
const [windowHeight, setWindowHeight] = useState(1);
|
|
||||||
const isMobile = useIsMobile();
|
const isMobile = useIsMobile();
|
||||||
|
|
||||||
let ticking = false;
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
const triggerElement = document.querySelector('div[data-sidebar-trigger="true"]');
|
||||||
|
|
||||||
const handleScroll = () => {
|
const handleScroll = () => {
|
||||||
if (!ticking) {
|
if (!triggerElement) {
|
||||||
window.requestAnimationFrame(() => {
|
console.log("triggerElement is null");
|
||||||
setScrollY(window.scrollY);
|
return;
|
||||||
ticking = false;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
const triggerDiv = triggerElement as HTMLDivElement;
|
||||||
|
const slideAmount = easeSlide(Math.max(0, Math.min(1, window.scrollY / (window.innerHeight / 20))));
|
||||||
|
triggerDiv.style.marginLeft = `calc(var(--spacing) * ${12 * slideAmount})`;
|
||||||
|
triggerDiv.style.paddingTop = `calc(var(--spacing) * ${(isMobile ? 1 : 3) * slideAmount})`;
|
||||||
};
|
};
|
||||||
const handleResize = () => setWindowHeight(window.innerHeight);
|
|
||||||
|
|
||||||
setWindowHeight(window.innerHeight);
|
|
||||||
|
|
||||||
window.addEventListener('scroll', handleScroll);
|
window.addEventListener('scroll', handleScroll);
|
||||||
window.addEventListener('resize', handleResize);
|
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
window.removeEventListener('scroll', handleScroll);
|
window.removeEventListener('scroll', handleScroll);
|
||||||
window.removeEventListener('resize', handleResize);
|
|
||||||
};
|
};
|
||||||
}, []);
|
}, [isMobile]);
|
||||||
|
|
||||||
let slideAmount = Math.max(0, Math.min(1, scrollY / (windowHeight / 20)));
|
return <div data-sidebar-trigger="true" {...props}></div>;
|
||||||
slideAmount = easeSlide(slideAmount);
|
|
||||||
|
|
||||||
return <div {...props} style={{
|
|
||||||
marginLeft: `calc(var(--spacing) * ${12 * slideAmount})`,
|
|
||||||
marginTop: `calc(var(--spacing) * ${(isMobile ? 1 : 3) * slideAmount})`
|
|
||||||
}}></div>;
|
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user