feat(canvas): replace sidebar fade with progressive blur
This commit is contained in:
@@ -22,6 +22,7 @@
|
||||
"hooks": "@/hooks"
|
||||
},
|
||||
"registries": {
|
||||
"@tool-ui": "https://www.tool-ui.com/r/{name}.json"
|
||||
"@tool-ui": "https://www.tool-ui.com/r/{name}.json",
|
||||
"@magicui": "https://magicui.design/r/{name}"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,6 +31,7 @@ import {
|
||||
} from "lucide-react";
|
||||
|
||||
import { CanvasUserMenu } from "@/components/canvas/canvas-user-menu";
|
||||
import { ProgressiveBlur } from "@/components/ui/progressive-blur";
|
||||
import { useAuthQuery } from "@/hooks/use-auth-query";
|
||||
import { api } from "@/convex/_generated/api";
|
||||
import type { Id } from "@/convex/_generated/dataModel";
|
||||
@@ -240,15 +241,13 @@ export default function CanvasSidebar({
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
<div
|
||||
aria-hidden="true"
|
||||
className={cn(
|
||||
"pointer-events-none absolute inset-x-0 bottom-0 z-10",
|
||||
railMode
|
||||
? "h-16 bg-gradient-to-t from-black via-black/80 to-transparent"
|
||||
: "h-24 bg-gradient-to-t from-black via-black/80 to-transparent",
|
||||
)}
|
||||
/>
|
||||
<div aria-hidden="true">
|
||||
<ProgressiveBlur
|
||||
position="bottom"
|
||||
height={railMode ? "4rem" : "6rem"}
|
||||
blurLevels={[0.5, 1, 2, 4, 8, 12, 16, 24]}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="relative z-20 bg-background">
|
||||
|
||||
113
components/ui/progressive-blur.tsx
Normal file
113
components/ui/progressive-blur.tsx
Normal file
@@ -0,0 +1,113 @@
|
||||
"use client"
|
||||
|
||||
import React from "react"
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
export interface ProgressiveBlurProps {
|
||||
className?: string
|
||||
height?: string
|
||||
position?: "top" | "bottom" | "both"
|
||||
blurLevels?: number[]
|
||||
children?: React.ReactNode
|
||||
}
|
||||
|
||||
export function ProgressiveBlur({
|
||||
className,
|
||||
height = "30%",
|
||||
position = "bottom",
|
||||
blurLevels = [0.5, 1, 2, 4, 8, 16, 32, 64],
|
||||
}: ProgressiveBlurProps) {
|
||||
// Create array with length equal to blurLevels.length - 2 (for before/after pseudo elements)
|
||||
const divElements = Array(blurLevels.length - 2).fill(null)
|
||||
|
||||
return (
|
||||
<div
|
||||
className={cn(
|
||||
"gradient-blur pointer-events-none absolute inset-x-0 z-10",
|
||||
className,
|
||||
position === "top"
|
||||
? "top-0"
|
||||
: position === "bottom"
|
||||
? "bottom-0"
|
||||
: "inset-y-0"
|
||||
)}
|
||||
style={{
|
||||
height: position === "both" ? "100%" : height,
|
||||
}}
|
||||
>
|
||||
{/* First blur layer (pseudo element) */}
|
||||
<div
|
||||
className="absolute inset-0"
|
||||
style={{
|
||||
zIndex: 1,
|
||||
backdropFilter: `blur(${blurLevels[0]}px)`,
|
||||
WebkitBackdropFilter: `blur(${blurLevels[0]}px)`,
|
||||
maskImage:
|
||||
position === "bottom"
|
||||
? `linear-gradient(to bottom, rgba(0,0,0,0) 0%, rgba(0,0,0,1) 12.5%, rgba(0,0,0,1) 25%, rgba(0,0,0,0) 37.5%)`
|
||||
: position === "top"
|
||||
? `linear-gradient(to top, rgba(0,0,0,0) 0%, rgba(0,0,0,1) 12.5%, rgba(0,0,0,1) 25%, rgba(0,0,0,0) 37.5%)`
|
||||
: `linear-gradient(rgba(0,0,0,0) 0%, rgba(0,0,0,1) 5%, rgba(0,0,0,1) 95%, rgba(0,0,0,0) 100%)`,
|
||||
WebkitMaskImage:
|
||||
position === "bottom"
|
||||
? `linear-gradient(to bottom, rgba(0,0,0,0) 0%, rgba(0,0,0,1) 12.5%, rgba(0,0,0,1) 25%, rgba(0,0,0,0) 37.5%)`
|
||||
: position === "top"
|
||||
? `linear-gradient(to top, rgba(0,0,0,0) 0%, rgba(0,0,0,1) 12.5%, rgba(0,0,0,1) 25%, rgba(0,0,0,0) 37.5%)`
|
||||
: `linear-gradient(rgba(0,0,0,0) 0%, rgba(0,0,0,1) 5%, rgba(0,0,0,1) 95%, rgba(0,0,0,0) 100%)`,
|
||||
}}
|
||||
/>
|
||||
|
||||
{/* Middle blur layers */}
|
||||
{divElements.map((_, index) => {
|
||||
const blurIndex = index + 1
|
||||
const startPercent = blurIndex * 12.5
|
||||
const midPercent = (blurIndex + 1) * 12.5
|
||||
const endPercent = (blurIndex + 2) * 12.5
|
||||
|
||||
const maskGradient =
|
||||
position === "bottom"
|
||||
? `linear-gradient(to bottom, rgba(0,0,0,0) ${startPercent}%, rgba(0,0,0,1) ${midPercent}%, rgba(0,0,0,1) ${endPercent}%, rgba(0,0,0,0) ${endPercent + 12.5}%)`
|
||||
: position === "top"
|
||||
? `linear-gradient(to top, rgba(0,0,0,0) ${startPercent}%, rgba(0,0,0,1) ${midPercent}%, rgba(0,0,0,1) ${endPercent}%, rgba(0,0,0,0) ${endPercent + 12.5}%)`
|
||||
: `linear-gradient(rgba(0,0,0,0) 0%, rgba(0,0,0,1) 5%, rgba(0,0,0,1) 95%, rgba(0,0,0,0) 100%)`
|
||||
|
||||
return (
|
||||
<div
|
||||
key={`blur-${index}`}
|
||||
className="absolute inset-0"
|
||||
style={{
|
||||
zIndex: index + 2,
|
||||
backdropFilter: `blur(${blurLevels[blurIndex]}px)`,
|
||||
WebkitBackdropFilter: `blur(${blurLevels[blurIndex]}px)`,
|
||||
maskImage: maskGradient,
|
||||
WebkitMaskImage: maskGradient,
|
||||
}}
|
||||
/>
|
||||
)
|
||||
})}
|
||||
|
||||
{/* Last blur layer (pseudo element) */}
|
||||
<div
|
||||
className="absolute inset-0"
|
||||
style={{
|
||||
zIndex: blurLevels.length,
|
||||
backdropFilter: `blur(${blurLevels[blurLevels.length - 1]}px)`,
|
||||
WebkitBackdropFilter: `blur(${blurLevels[blurLevels.length - 1]}px)`,
|
||||
maskImage:
|
||||
position === "bottom"
|
||||
? `linear-gradient(to bottom, rgba(0,0,0,0) 87.5%, rgba(0,0,0,1) 100%)`
|
||||
: position === "top"
|
||||
? `linear-gradient(to top, rgba(0,0,0,0) 87.5%, rgba(0,0,0,1) 100%)`
|
||||
: `linear-gradient(rgba(0,0,0,0) 0%, rgba(0,0,0,1) 5%, rgba(0,0,0,1) 95%, rgba(0,0,0,0) 100%)`,
|
||||
WebkitMaskImage:
|
||||
position === "bottom"
|
||||
? `linear-gradient(to bottom, rgba(0,0,0,0) 87.5%, rgba(0,0,0,1) 100%)`
|
||||
: position === "top"
|
||||
? `linear-gradient(to top, rgba(0,0,0,0) 87.5%, rgba(0,0,0,1) 100%)`
|
||||
: `linear-gradient(rgba(0,0,0,0) 0%, rgba(0,0,0,1) 5%, rgba(0,0,0,1) 95%, rgba(0,0,0,0) 100%)`,
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user