Files
hanzo.ai/components/ui/animation-variants.ts
zeekayandHanzo Dev d6fd0ebf07 types: zero errors, and the checker is back on
The last 39 errors were not noise — most marked v8 props that silently did
nothing at runtime:

- gui 8 renamed `animation` to `transition`; the old name was inert in JSX
  spreads, so faq's disclosure and page-kit's rise had no easing at all.
- v4 media keys are mobile-first: `$gtSm`/`$gtLg` no longer exist, so the
  wide gutter and grid columns never applied. Now `$sm`/`$lg`.
- ModelStatus comparisons tested `contact-sales`/`coming-soon`, which the
  @zenlm/models union does not contain: dead in both directions — no badge
  ever rendered, and 8 weightless models linked to fabricated
  huggingface.co/zenlm/<id> 404s. `cloud-only` is the real status.
- gui TextArea emits the VALUE, not a DOM event — onChange handlers typed
  for textarea routed nothing; now onChangeText.
- `theme="active"` names a sub-theme this config does not declare; the
  primary Export button looked identical to Filter. Emphasis from tokens.
- Raw CSS (color-mix, var() tracking/leading, display:grid) moves to the
  `style` prop — gui's escape hatch — instead of posing as tokens.
- hooks/use-toast.ts deleted: the last shadcn artefact; its 3 callers now
  use @hanzo/ui's toast.
- sitemap: explicit encoding on both readdirSync calls, or @types/node
  resolves the Buffer overloads.

tsc: 743 -> 0. typescript.ignoreBuildErrors and eslint.ignoreDuringBuilds
are DELETED from next.config.mjs; the build now runs both and exits 0
(709 pages; /models count follows the live catalog — 374 models today).
Homepage 46,904 bytes, zero inline <style>.

Co-authored-by: Hanzo Dev <[email protected]>
2026-07-31 11:22:15 -07:00

154 lines
3.2 KiB
TypeScript

'use client'
import { Variants } from "framer-motion";
// Animation timing presets (in seconds)
export const timing = {
fast: 0.3,
medium: 0.5,
slow: 0.8
};
// Animation curves. The tuple type is load-bearing: framer-motion's `Easing` is a
// named easing OR a four-point cubic-bezier TUPLE, and a bare array literal infers
// as number[], which satisfies neither.
type Curve = [number, number, number, number]
export const curves: Record<'snappy' | 'bouncy' | 'smooth' | 'precise', Curve> = {
snappy: [0.2, 0.8, 0.2, 1],
bouncy: [0.22, 1.28, 0, 1],
smooth: [0.4, 0, 0.2, 1],
precise: [0.4, 0, 0.6, 1]
};
// Configurable animation factory
export const createAnimationVariant = (
type: "fadeIn" | "slideUp" | "scaleIn" | "popIn" | "fadeInBlur",
options?: {
duration?: number;
delay?: number;
staggerChildren?: number;
curve?: Curve;
distance?: number;
blur?: number;
}
): Variants => {
const {
duration = timing.fast,
delay = 0,
staggerChildren = 0.05,
curve = curves.snappy,
distance = 20,
blur = 10
} = options || {};
const baseTransition = {
duration,
ease: curve,
delay
};
// Animation variants
switch (type) {
case "fadeIn":
return {
hidden: { opacity: 0, y: distance },
visible: {
opacity: 1,
y: 0,
transition: baseTransition
}
};
case "fadeInBlur":
return {
hidden: {
opacity: 0,
y: distance,
filter: `blur(${blur}px)`
},
visible: {
opacity: 1,
y: 0,
filter: "blur(0px)",
transition: baseTransition
}
};
case "slideUp":
return {
hidden: { y: distance },
visible: {
y: 0,
transition: baseTransition
}
};
case "scaleIn":
return {
hidden: { scale: 0.92, opacity: 0 },
visible: {
scale: 1,
opacity: 1,
transition: baseTransition
}
};
case "popIn":
return {
hidden: {
scale: 0.8,
opacity: 0,
filter: `blur(${blur}px)`
},
visible: {
scale: 1,
opacity: 1,
filter: "blur(0px)",
transition: {
...baseTransition,
ease: curves.bouncy
}
}
};
default:
return {
hidden: { opacity: 0 },
visible: {
opacity: 1,
transition: baseTransition
}
};
}
};
// Staggered container
export const staggerContainer = (staggerChildren = 0.1): Variants => ({
hidden: { opacity: 0 },
visible: {
opacity: 1,
transition: {
staggerChildren,
delayChildren: 0.1
}
}
});
// Animation hooks for common page sections
export const sectionAnimation = createAnimationVariant("fadeInBlur", {
duration: 0.4,
curve: curves.smooth
});
export const headingAnimation = createAnimationVariant("fadeInBlur", {
duration: 0.3,
curve: curves.snappy
});
export const cardAnimation = createAnimationVariant("popIn", {
duration: 0.35,
curve: curves.bouncy
});
export const buttonAnimation = createAnimationVariant("scaleIn", {
duration: 0.25,
curve: curves.bouncy
});