From 7251b39cc3e3fffdd94120f67208692ca89fbd04 Mon Sep 17 00:00:00 2001 From: mrjvs <jellevs@gmail.com> Date: Sun, 20 Aug 2023 21:03:59 +0200 Subject: [PATCH] Add media card flare --- src/components/media/MediaCard.tsx | 45 +++++++++++++++++----------- src/components/utils/Flare.tsx | 9 +++--- src/components/utils/Lightbar.css | 48 ++++++++++++++++++++++++------ src/components/utils/Lightbar.tsx | 1 + tailwind.config.js | 12 ++++++++ 5 files changed, 83 insertions(+), 32 deletions(-) diff --git a/src/components/media/MediaCard.tsx b/src/components/media/MediaCard.tsx index 828f6bd7..608458a8 100644 --- a/src/components/media/MediaCard.tsx +++ b/src/components/media/MediaCard.tsx @@ -1,9 +1,11 @@ +import c from "classnames"; import { useTranslation } from "react-i18next"; import { Link } from "react-router-dom"; import { TMDBMediaToId } from "@/backend/metadata/tmdb"; import { MWMediaMeta } from "@/backend/metadata/types/mw"; import { DotList } from "@/components/text/DotList"; +import { Flare } from "@/components/utils/Flare"; import { IconPatch } from "../buttons/IconPatch"; import { Icons } from "../Icon"; @@ -39,19 +41,27 @@ function MediaCardContent({ if (media.year) dotListContent.push(media.year); return ( - <div - className={`group -m-3 mb-2 rounded-xl bg-denim-300 bg-opacity-0 transition-colors duration-100 ${ - canLink ? "hover:bg-opacity-100" : "" + <Flare.Base + className={`group -m-3 mb-2 rounded-xl bg-background-main transition-colors duration-100 ${ + canLink ? "hover:bg-mediaCard-hoverBackground" : "" }`} > - <article + <Flare.Light + flareSize={300} + cssColorVar="--colors-mediaCard-hoverAccent" + backgroundClass="bg-mediaCard-hoverBackground duration-100" + className={c({ + "rounded-xl bg-background-main group-hover:opacity-100": canLink, + })} + /> + <Flare.Child className={`pointer-events-auto relative mb-2 p-3 transition-transform duration-100 ${ canLink ? "group-hover:scale-95" : "" }`} > <div className={[ - "relative mb-4 aspect-[2/3] w-full overflow-hidden rounded-xl bg-denim-500 bg-cover bg-center transition-[border-radius] duration-100", + "relative mb-4 aspect-[2/3] w-full overflow-hidden rounded-xl bg-mediaCard-hoverBackground bg-cover bg-center transition-[border-radius] duration-100", closable ? "" : "group-hover:rounded-lg", ].join(" ")} style={{ @@ -61,13 +71,12 @@ function MediaCardContent({ {series ? ( <div className={[ - "absolute right-2 top-2 rounded-md bg-denim-200 px-2 py-1 transition-colors", - closable ? "" : "group-hover:bg-denim-500", + "absolute right-2 top-2 rounded-md bg-mediaCard-badge px-2 py-1 transition-colors", ].join(" ")} > <p className={[ - "text-center text-xs font-bold text-slate-400 transition-colors", + "text-center text-xs font-bold text-mediaCard-badgeText transition-colors", closable ? "" : "group-hover:text-white", ].join(" ")} > @@ -82,19 +91,19 @@ function MediaCardContent({ {percentage !== undefined ? ( <> <div - className={`absolute inset-x-0 bottom-0 h-12 bg-gradient-to-t from-denim-300 to-transparent transition-colors ${ - canLink ? "group-hover:from-denim-100" : "" + className={`absolute inset-x-0 bottom-0 h-12 bg-gradient-to-t from-mediaCard-shadow to-transparent transition-colors ${ + canLink ? "group-hover:from-mediaCard-hoverShadow" : "" }`} /> <div - className={`absolute inset-x-0 bottom-0 h-12 bg-gradient-to-t from-denim-300 to-transparent transition-colors ${ - canLink ? "group-hover:from-denim-100" : "" + className={`absolute inset-x-0 bottom-0 h-12 bg-gradient-to-t from-mediaCard-shadow to-transparent transition-colors ${ + canLink ? "group-hover:from-mediaCard-hoverShadow" : "" }`} /> <div className="absolute inset-x-0 bottom-0 p-3"> - <div className="relative h-1 overflow-hidden rounded-full bg-denim-600"> + <div className="relative h-1 overflow-hidden rounded-full bg-mediaCard-barColor"> <div - className="absolute inset-y-0 left-0 rounded-full bg-bink-700" + className="absolute inset-y-0 left-0 rounded-full bg-mediaCard-barFillColor" style={{ width: percentageString, }} @@ -105,13 +114,13 @@ function MediaCardContent({ ) : null} <div - className={`absolute inset-0 flex items-center justify-center bg-denim-200 bg-opacity-80 transition-opacity duration-200 ${ + className={`absolute inset-0 flex items-center justify-center bg-mediaCard-badge bg-opacity-80 transition-opacity duration-200 ${ closable ? "opacity-100" : "pointer-events-none opacity-0" }`} > <IconPatch clickable - className="text-2xl text-slate-400" + className="text-2xl text-mediaCard-badgeText" onClick={() => closable && onClose?.()} icon={Icons.X} /> @@ -121,8 +130,8 @@ function MediaCardContent({ <span>{media.title}</span> </h1> <DotList className="text-xs" content={dotListContent} /> - </article> - </div> + </Flare.Child> + </Flare.Base> ); } diff --git a/src/components/utils/Flare.tsx b/src/components/utils/Flare.tsx index 86ea0bfe..267f4c85 100644 --- a/src/components/utils/Flare.tsx +++ b/src/components/utils/Flare.tsx @@ -30,13 +30,14 @@ function Light(props: FlareProps) { function mouseMove(e: MouseEvent) { if (!outerRef.current) return; const rect = outerRef.current.getBoundingClientRect(); + const halfSize = size / 2; outerRef.current.style.setProperty( "--bg-x", - `${(e.clientX - rect.left - size / 2).toFixed(0)}px` + `${(e.clientX - rect.left - halfSize).toFixed(0)}px` ); outerRef.current.style.setProperty( "--bg-y", - `${(e.clientY - rect.top - size / 2).toFixed(0)}px` + `${(e.clientY - rect.top - halfSize).toFixed(0)}px` ); } document.addEventListener("mousemove", mouseMove); @@ -58,13 +59,12 @@ function Light(props: FlareProps) { backgroundImage: `radial-gradient(circle at center, rgba(var(${cssVar}), 1), rgba(var(${cssVar}), 0) 70%)`, backgroundPosition: `var(--bg-x) var(--bg-y)`, backgroundRepeat: "no-repeat", - backgroundAttachment: "fixed", backgroundSize: `${size.toFixed(0)}px ${size.toFixed(0)}px`, }} > <div className={c( - "absolute inset-[2px] overflow-hidden", + "absolute inset-[1px] overflow-hidden", props.className, props.backgroundClass )} @@ -75,7 +75,6 @@ function Light(props: FlareProps) { background: `radial-gradient(circle at center, rgba(var(${cssVar}), 1), rgba(var(${cssVar}), 0) 70%)`, backgroundPosition: `var(--bg-x) var(--bg-y)`, backgroundRepeat: "no-repeat", - backgroundAttachment: "fixed", backgroundSize: `${size.toFixed(0)}px ${size.toFixed(0)}px`, }} /> diff --git a/src/components/utils/Lightbar.css b/src/components/utils/Lightbar.css index c49e144f..d2eb265c 100644 --- a/src/components/utils/Lightbar.css +++ b/src/components/utils/Lightbar.css @@ -1,11 +1,24 @@ -.lightbar { - position: absolute; - left: -25vw; - top: 0; - width: 150vw; +.lightbar, .lightbar-visual { + position: absolute; + top: 0; + width: 150vw; height: 800px; pointer-events: none; user-select: none; +} + +.lightbar { + left: -25vw; + display: flex; + justify-content: center; + align-items: center; + --d: 3s; + --animation: cubic-bezier(.75,-0.00,.25,1); + animation: boot var(--d) var(--animation) forwards; +} + +.lightbar-visual { + left: 0; --top: theme('colors.background.main'); --bottom: theme('colors.lightBar.light'); --first: conic-gradient(from 90deg at 80% 50%,var(--top),var(--bottom)); @@ -19,13 +32,30 @@ transform: rotate(180deg) translateZ(0px) translateY(400px); transform-origin: center center; background-repeat: no-repeat; - display: flex; - justify-content: center; - align-items: center; + animation: lightbarBoot var(--d) var(--animation) forwards; } .lightbar canvas { width: 40%; height: 300px; - transform: translateY(-50%) rotate(180deg); + transform: translateY(-250px); +} + +@keyframes boot { + from { + + opacity: 0.25; + } + to { + opacity: 1; + } +} + +@keyframes lightbarBoot { + 0% { + transform: rotate(180deg) translateZ(0px) translateY(400px) scaleX(0.8); + } + 100% { + transform: rotate(180deg) translateZ(0px) translateY(400px) scaleX(1); + } } diff --git a/src/components/utils/Lightbar.tsx b/src/components/utils/Lightbar.tsx index bfcfd592..a1ca0fe6 100644 --- a/src/components/utils/Lightbar.tsx +++ b/src/components/utils/Lightbar.tsx @@ -139,6 +139,7 @@ export function Lightbar(props: { className?: string }) { <div className={props.className}> <div className="lightbar"> <ParticlesCanvas /> + <div className="lightbar-visual" /> </div> </div> ); diff --git a/tailwind.config.js b/tailwind.config.js index 7fd185a2..17534fe1 100644 --- a/tailwind.config.js +++ b/tailwind.config.js @@ -83,6 +83,18 @@ module.exports = { placeholder: "#4A4A71", icon: "#545476", text: "#FFFFFF" + }, + + // media cards + mediaCard: { + hoverBackground: "#161622", + hoverAccent: "#4D79A8", + hoverShadow: "#0A0A10", + shadow: "#161622", + barColor: "#4B4B63", + barFillColor: "#BA7FD6", + badge: "#151522", + badgeText: "#5F5F7A" } } }