Skip to content

Commit

Permalink
Merge pull request #284 from alchemix-finance/feat/animated-navigation
Browse files Browse the repository at this point in the history
FEAT: Animated background navigation
  • Loading branch information
t0rbik authored Dec 12, 2024
2 parents c17a38f + 10f2ed5 commit ed01fad
Show file tree
Hide file tree
Showing 2 changed files with 69 additions and 16 deletions.
72 changes: 60 additions & 12 deletions src/components/layout/LeftNav.tsx
Original file line number Diff line number Diff line change
@@ -1,33 +1,54 @@
import { cn } from "@/utils/cn";
import { Link, useMatchRoute } from "@tanstack/react-router";
import { HTMLAttributes, Ref, forwardRef } from "react";
import { useMatchRoute, createLink } from "@tanstack/react-router";
import { m, MotionProps, useReducedMotion } from "framer-motion";

import { cn } from "@/utils/cn";
import {
routeTitleToPathMapping,
RouteTitle,
} from "@/components/layout/Header";
import { useSentinel } from "@/lib/queries/sentinel/useSentinel";

const MotionLinkForwardRef = forwardRef(
(
props: MotionProps & HTMLAttributes<HTMLAnchorElement>,
ref: Ref<HTMLAnchorElement>,
) => {
return <m.a {...props} ref={ref} />;
},
);
MotionLinkForwardRef.displayName = "MotionLinkForwardRef";

const MotionLink = createLink(MotionLinkForwardRef);

export function LeftNav() {
const matchRoute = useMatchRoute();
const isReducedMotion = useReducedMotion();
const { data: isSentinel } = useSentinel();
return (
<nav className="space-y-5">
<p className="my-4 text-xs font-medium uppercase tracking-wider opacity-30">
Navigation
</p>
{Object.keys(routeTitleToPathMapping).map((item) => (
<Link
<MotionLink
key={item}
to={routeTitleToPathMapping[item as RouteTitle].to}
className={cn(
"flex cursor-pointer justify-between rounded-xl p-4 transition-all",
"hover:bg-grey10inverse hover:opacity-100 dark:hover:bg-grey10",
"relative flex cursor-pointer justify-between rounded-xl p-4 transition-all",
"hover:opacity-100",
matchRoute({
to: routeTitleToPathMapping[item as RouteTitle].to,
fuzzy: true,
})
? "bg-grey10inverse opacity-100 dark:bg-grey10"
? "opacity-100"
: "opacity-40",
isReducedMotion &&
matchRoute({
to: routeTitleToPathMapping[item as RouteTitle].to,
fuzzy: true,
}) &&
"bg-grey10inverse dark:bg-grey10",
)}
>
{item}
Expand All @@ -36,20 +57,37 @@ export function LeftNav() {
className="h-7 w-7 invert dark:filter-none"
alt={`${item} icon`}
/>
</Link>

{!isReducedMotion &&
matchRoute({
to: routeTitleToPathMapping[item as RouteTitle].to,
fuzzy: true,
}) ? (
<m.div
layoutId="tab-indicator"
className="absolute inset-0 -z-10 rounded-xl bg-grey10inverse dark:bg-grey10"
/>
) : null}
</MotionLink>
))}
{isSentinel && (
<Link
<MotionLink
to="/sentinel"
className={cn(
"flex cursor-pointer justify-between rounded-xl p-4 transition-all",
"hover:bg-grey10inverse hover:opacity-100 dark:hover:bg-grey10",
"relative flex cursor-pointer justify-between rounded-xl p-4 transition-all",
"hover:opacity-100",
matchRoute({
to: "/sentinel",
fuzzy: true,
})
? "bg-grey10inverse opacity-100 dark:bg-grey10"
? "opacity-100"
: "opacity-40",
isReducedMotion &&
matchRoute({
to: "/sentinel",
fuzzy: true,
}) &&
"bg-grey10inverse dark:bg-grey10",
)}
>
Sentinel
Expand All @@ -58,7 +96,17 @@ export function LeftNav() {
className="h-7 w-7 invert dark:filter-none"
alt="Sentinel icon"
/>
</Link>
{!isReducedMotion &&
matchRoute({
to: "/sentinel",
fuzzy: true,
}) ? (
<m.div
layoutId="tab-indicator"
className="absolute inset-0 -z-10 rounded-xl bg-grey10inverse dark:bg-grey10"
/>
) : null}
</MotionLink>
)}
</nav>
);
Expand Down
13 changes: 9 additions & 4 deletions src/components/providers/FramerMotionProvider.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,20 @@
import { LazyMotion, domAnimation } from "framer-motion";
import { LazyMotion } from "framer-motion";

// NOTE: Reduced bundle size,
// see: https://www.framer.com/motion/guide-reduce-bundle-size/
// NOTE: Reduced initial bundle size.
// Lazy load rest of the Framer Motion features after the initial render.
// See: https://motion.dev/docs/react-reduce-bundle-size

// Make sure to return the specific export containing the feature bundle.
const loadFeatures = () =>
import("framer-motion").then((module) => module.domMax);

export const FramerMotionProvider = ({
children,
}: {
children: React.ReactNode;
}) => {
return (
<LazyMotion features={domAnimation} strict>
<LazyMotion features={loadFeatures} strict>
{children}
</LazyMotion>
);
Expand Down

0 comments on commit ed01fad

Please sign in to comment.