mirror of
https://github.com/hanzo-apps/hanzo.ai.git
synced 2026-10-29 07:20:43 +00:00
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]>
154 lines
3.2 KiB
TypeScript
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
|
|
});
|