Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 3 additions & 19 deletions app/contribute/contribute-view.tsx
Original file line number Diff line number Diff line change
@@ -1,20 +1,9 @@
"use client";

import { motion } from "framer-motion";
import { ContributeHero } from "@/components/contribute/contribute-hero";
import { ContributionCard } from "@/components/contribute/contribution-card";
import { ContributionEmptyState } from "@/components/contribute/contribution-empty-state";
import { ContributionHint } from "@/components/contribute/contribution-hint";

const containerVariants = {
hidden: { opacity: 0 },
visible: {
opacity: 1,
transition: {
staggerChildren: 0.1,
},
},
};
import { MotionSection } from "@/components/ui/motion/motion-components";

export interface ContributionCardData {
id?: string | null;
Expand All @@ -39,12 +28,7 @@ export default function ContributeView({ cards }: { cards: ContributionCardData[

<div className="relative z-10 mx-auto max-w-[90rem] px-4 pb-24 sm:px-6 lg:px-8">
{cards.length > 0 ? (
<motion.div
animate="visible"
className="grid gap-8 md:grid-cols-2 lg:grid-cols-3"
initial="hidden"
variants={containerVariants}
>
<MotionSection className="grid gap-8 md:grid-cols-2 lg:grid-cols-3" stagger={0.1}>
{cards.map((card, index) => (
<ContributionCard
actionText={card.actionText}
Expand All @@ -56,7 +40,7 @@ export default function ContributeView({ cards }: { cards: ContributionCardData[
title={card.title}
/>
))}
</motion.div>
</MotionSection>
) : (
<ContributionEmptyState />
)}
Expand Down
12 changes: 3 additions & 9 deletions app/docs/view.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
"use client";

import { motion } from "framer-motion";
import { containerVariants } from "@/components/docs/view/animations";
import { DocsBackground } from "@/components/docs/view/docs-background";
import { DocsCard } from "@/components/docs/view/docs-card";
import { DocsHeader } from "@/components/docs/view/docs-header";
import Cta from "@/components/shared/cta-section";
import { MotionSection } from "@/components/ui/motion/motion-components";
import { DOC_PROJECTS } from "@/lib/docs-projects";

export function DocsView() {
Expand All @@ -16,16 +15,11 @@ export function DocsView() {
<DocsHeader />

<div className="relative z-10 mx-auto max-w-[90rem] px-4 pb-6 sm:px-6 lg:px-8">
<motion.div
animate="visible"
className="grid gap-8 md:grid-cols-2 lg:grid-cols-3"
initial="hidden"
variants={containerVariants}
>
<MotionSection className="grid gap-8 md:grid-cols-2 lg:grid-cols-3" stagger={0.08}>
{DOC_PROJECTS.map((project) => (
<DocsCard key={project.path} project={project} />
))}
</motion.div>
</MotionSection>

<div className="relative mt-20">
<div className="absolute top-full left-1/2 -z-10 h-[300px] w-[300px] -translate-x-1/2 -translate-y-1/2 rounded-full bg-blue-500/10 blur-3xl filter will-change-transform md:h-[600px] md:w-[600px] dark:bg-blue-500/5" />
Expand Down
19 changes: 11 additions & 8 deletions app/projects/eternalcombat/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,14 @@ import { useRef } from "react";
import { Button } from "@/components/ui/button";
import { FacadePattern } from "@/components/ui/facade-pattern";
import { FadeIn, SlideIn } from "@/components/ui/motion/motion-components";
import { useReducedMotion } from "@/hooks/use-reduced-motion";
import { pulse, sway, type MotionCustom } from "@/lib/animations/variants";

import { ConfigPreview } from "./config-preview";

export default function EternalCombatPage() {
const targetRef = useRef(null);
const prefersReducedMotion = useReducedMotion();
const { scrollYProgress } = useScroll({
target: targetRef,
offset: ["start start", "end start"],
Expand Down Expand Up @@ -80,12 +83,10 @@ export default function EternalCombatPage() {
<div className="flex items-center gap-3">
<div className="flex h-10 w-10 items-center justify-center rounded-xl bg-red-100 text-red-600 dark:bg-red-500/10 dark:text-red-500">
<motion.div
animate={{ rotate: [-6, 6, -6] }}
transition={{
duration: 3,
repeat: Number.POSITIVE_INFINITY,
ease: "easeInOut",
}}
custom={{ reduced: prefersReducedMotion, duration: 3 } satisfies MotionCustom}
initial="initial"
variants={sway}
animate="animate"
>
<Swords className="h-5 w-5" />
</motion.div>
Expand All @@ -105,8 +106,10 @@ export default function EternalCombatPage() {
<div className="flex items-center gap-3">
<div className="flex h-10 w-10 items-center justify-center rounded-xl bg-yellow-100 text-yellow-600 dark:bg-yellow-500/10 dark:text-yellow-500">
<motion.div
animate={{ opacity: [1, 0.6, 1], scale: [1, 1.05, 1] }}
transition={{ duration: 3, repeat: Number.POSITIVE_INFINITY }}
custom={{ reduced: prefersReducedMotion, duration: 3 } satisfies MotionCustom}
initial="initial"
variants={pulse}
animate="animate"
>
<Zap className="h-5 w-5 fill-current" />
</motion.div>
Expand Down
50 changes: 32 additions & 18 deletions app/projects/eternalcore/eternal-showcase.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,15 @@ import Image from "next/image";
import { useEffect, useState } from "react";
import { createPortal } from "react-dom";
import { FadeIn } from "@/components/ui/motion/motion-components";
import { useReducedMotion } from "@/hooks/use-reduced-motion";
import {
fadeIn,
marqueeHalf,
marqueeHalfReverse,
popIn,
hoverScaleSoft,
type MotionCustom,
} from "@/lib/animations/variants";

const marqueeItems = [
// Row 1: Essentials & Chat
Expand Down Expand Up @@ -60,6 +69,8 @@ const ShowcaseModal = ({
item: (typeof marqueeItems)[0];
onClose: () => void;
}) => {
const prefersReducedMotion = useReducedMotion();

// Prevent body scroll when modal is open
useEffect(() => {
document.body.style.overflow = "hidden";
Expand All @@ -70,19 +81,22 @@ const ShowcaseModal = ({

return createPortal(
<motion.div
animate={{ opacity: 1 }}
className="fixed inset-0 z-[100] flex items-center justify-center bg-black/80 p-4 backdrop-blur-sm"
exit={{ opacity: 0 }}
initial={{ opacity: 0 }}
custom={{ reduced: prefersReducedMotion } satisfies MotionCustom}
exit="hidden"
initial="hidden"
variants={fadeIn}
animate="visible"
onClick={onClose}
>
<motion.div
animate={{ scale: 1, opacity: 1, y: 0 }}
className="relative w-full max-w-5xl overflow-hidden rounded-2xl bg-white shadow-2xl ring-1 ring-gray-200 dark:bg-gray-900 dark:ring-white/10"
exit={{ scale: 0.9, opacity: 0, y: 20 }}
initial={{ scale: 0.9, opacity: 0, y: 20 }}
custom={{ reduced: prefersReducedMotion, distance: 20, scale: 0.9 } satisfies MotionCustom}
exit="exit"
initial="hidden"
onClick={(e) => e.stopPropagation()}
transition={{ type: "spring", damping: 25, stiffness: 300 }}
variants={popIn}
animate="visible"
>
<div className="relative aspect-video w-full bg-black/5 dark:bg-black">
<Image
Expand Down Expand Up @@ -124,30 +138,30 @@ const InfiniteMarquee = ({
speed?: number;
onItemClick: (item: (typeof marqueeItems)[0]) => void;
}) => {
const prefersReducedMotion = useReducedMotion();

return (
<div className="relative flex w-full overflow-hidden">
<motion.div
animate={{
x: direction === "left" ? ["0%", "-50%"] : ["-50%", "0%"],
}}
className="flex gap-4 py-4"
custom={{ reduced: prefersReducedMotion, duration: speed } satisfies MotionCustom}
initial="initial"
style={{
width: "max-content",
}}
transition={{
duration: speed,
ease: "linear",
repeat: Number.POSITIVE_INFINITY,
repeatType: "loop",
}}
variants={direction === "left" ? marqueeHalf : marqueeHalfReverse}
animate="animate"
>
{[...items, ...items].map((item, i) => (
<motion.div
className="group relative aspect-video w-[400px] shrink-0 cursor-pointer overflow-hidden rounded-xl border border-gray-200 bg-gray-100 shadow-sm transition-all hover:border-[#9d6eef]/50 hover:shadow-[#9d6eef]/20 hover:shadow-lg dark:border-gray-800 dark:bg-gray-900"
custom={{ reduced: prefersReducedMotion, scale: 1.02, tapScale: 0.98 } satisfies MotionCustom}
key={`${item.id}-${i}`}
onClick={() => onItemClick(item)}
whileHover={{ scale: 1.02 }}
whileTap={{ scale: 0.98 }}
initial="initial"
variants={hoverScaleSoft}
whileHover="hover"
whileTap="tap"
>
<Image
alt={item.id}
Expand Down
18 changes: 13 additions & 5 deletions app/projects/eternalcore/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,15 @@ import { Button } from "@/components/ui/button";
import { Card } from "@/components/ui/card";
import { FacadePattern } from "@/components/ui/facade-pattern";
import { FadeIn, MotionSection, ScaleIn, SlideIn } from "@/components/ui/motion/motion-components";
import { slideUp } from "@/lib/animations/variants";
import { useReducedMotion } from "@/hooks/use-reduced-motion";
import { slideUp, type MotionCustom } from "@/lib/animations/variants";

import { ConfigPreview } from "./config-preview";
import { EternalShowcase } from "./eternal-showcase";

export default function EternalCorePage() {
const targetRef = useRef(null);
const prefersReducedMotion = useReducedMotion();
const { scrollYProgress } = useScroll({
target: targetRef,
offset: ["start start", "end start"],
Expand Down Expand Up @@ -43,14 +45,14 @@ export default function EternalCorePage() {
{/* Text Content */}
<div className="flex-1 text-center lg:text-left">
<MotionSection className="flex flex-col items-center lg:items-start">
<m.div variants={slideUp}>
<m.div custom={{ reduced: prefersReducedMotion } satisfies MotionCustom} variants={slideUp}>
<div className="mb-6 inline-flex items-center gap-2 rounded-full bg-[#9d6eef]/5 px-3 py-1 font-bold text-[#9d6eef] text-[10px] uppercase tracking-widest">
<Zap className="h-3 w-3" />
Next-Gen Essentials
</div>
</m.div>

<m.div variants={slideUp}>
<m.div custom={{ reduced: prefersReducedMotion } satisfies MotionCustom} variants={slideUp}>
<h1 className="mb-6 font-extrabold text-4xl text-gray-900 tracking-tight md:text-5xl lg:text-6xl dark:text-white">
Essential commands.
<br />
Expand All @@ -60,7 +62,7 @@ export default function EternalCorePage() {
</h1>
</m.div>

<m.div variants={slideUp}>
<m.div custom={{ reduced: prefersReducedMotion } satisfies MotionCustom} variants={slideUp}>
<p className="mx-auto mb-8 max-w-2xl text-gray-600 text-lg leading-relaxed lg:mx-0 dark:text-gray-400">
EternalCore is a modern, open-source replacement for EssentialsX. Built for
Paper & Folia to deliver maximum performance without the legacy bloat.
Expand All @@ -69,6 +71,7 @@ export default function EternalCorePage() {

<m.div
className="flex flex-col justify-center gap-4 sm:flex-row lg:justify-start"
custom={{ reduced: prefersReducedMotion } satisfies MotionCustom}
variants={slideUp}
>
<Button
Expand Down Expand Up @@ -160,7 +163,12 @@ export default function EternalCorePage() {
gradient: "from-blue-500/20 to-cyan-500/20",
},
].map((feature) => (
<m.div className="h-full" key={feature.title} variants={slideUp}>
<m.div
className="h-full"
custom={{ reduced: prefersReducedMotion } satisfies MotionCustom}
key={feature.title}
variants={slideUp}
>
<Card className="group relative flex h-full flex-col p-6 transition-all hover:-translate-y-1 hover:bg-gray-50 hover:shadow-lg dark:hover:bg-gray-800/60">
<div
className={`absolute inset-0 bg-gradient-to-br opacity-0 transition-opacity duration-500 group-hover:opacity-100 ${feature.gradient} pointer-events-none`}
Expand Down
5 changes: 3 additions & 2 deletions components/builds/build-controls.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import type { Project } from "@/app/api/builds/builds";
import { Dropdown } from "@/components/ui/dropdown";
import { FadeIn } from "@/components/ui/motion/motion-components";
import { useReducedMotion } from "@/hooks/use-reduced-motion";
import { interactionSpring } from "@/lib/animations/variants";

interface BuildControlsProps {
projects: Project[];
Expand Down Expand Up @@ -65,7 +66,7 @@ export function BuildControls({
<motion.div
className="absolute inset-0 rounded-lg bg-white shadow-xs dark:bg-gray-800"
layoutId="active-tab"
transition={{ type: "spring", bounce: 0.2, duration: 0.6 }}
transition={interactionSpring}
/>
)}
{activeTab === "STABLE" && prefersReducedMotion && (
Expand Down Expand Up @@ -95,7 +96,7 @@ export function BuildControls({
<motion.div
className="absolute inset-0 rounded-lg bg-white shadow-xs dark:bg-gray-800"
layoutId="active-tab"
transition={{ type: "spring", bounce: 0.2, duration: 0.6 }}
transition={interactionSpring}
/>
)}
{activeTab === "DEV" && prefersReducedMotion && (
Expand Down
21 changes: 4 additions & 17 deletions components/builds/build-row.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { motion, type Variants } from "framer-motion";
import { motion } from "framer-motion";
import { Calendar, Download, GitBranch, Package } from "lucide-react";
import { Button } from "@/components/ui/button";
import { useReducedMotion } from "@/hooks/use-reduced-motion";
import { tableRow, type MotionCustom } from "@/lib/animations/variants";

export interface Build {
id: string;
Expand Down Expand Up @@ -76,32 +77,18 @@ const fullDateFormatter = new Intl.DateTimeFormat("en-US", {
minute: "numeric",
});

const rowVariants: Variants = {
hidden: { opacity: 0, y: 10 },
visible: (i: number) => ({
opacity: 1,
y: 0,
transition: {
delay: i * 0.03,
duration: 0.2,
ease: "easeOut",
},
}),
exit: { opacity: 0, y: -5, transition: { duration: 0.1 } },
};

export function BuildRow({ build, index, lastDownloadedId, onDownload }: BuildRowProps) {
const prefersReducedMotion = useReducedMotion();

return (
<motion.tr
animate={prefersReducedMotion ? undefined : "visible"}
className="group transition-colors hover:bg-white dark:hover:bg-gray-800/50"
custom={index}
custom={{ reduced: prefersReducedMotion, delay: prefersReducedMotion ? 0 : index * 0.03 } satisfies MotionCustom}
exit={prefersReducedMotion ? undefined : "exit"}
initial={prefersReducedMotion ? undefined : "hidden"}
layoutId={build.id}
variants={prefersReducedMotion ? undefined : rowVariants}
variants={prefersReducedMotion ? undefined : tableRow}
>
<th
className="px-4 py-3 text-left font-medium text-gray-900 md:px-6 dark:text-white"
Expand Down
21 changes: 8 additions & 13 deletions components/contribute/contribution-card.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,8 @@ import { m } from "framer-motion";
import { LucideIcon } from "@/components/lucide-icon";
import { Button } from "@/components/ui/button";
import { Card } from "@/components/ui/card";

const itemVariants = {
hidden: { y: 20, opacity: 0 },
visible: {
y: 0,
opacity: 1,
transition: {
duration: 0.4,
ease: [0.22, 1, 0.36, 1],
},
},
} as const;
import { useReducedMotion } from "@/hooks/use-reduced-motion";
import { slideUp, type MotionCustom } from "@/lib/animations/variants";

interface ContributionCardProps {
icon: string;
Expand All @@ -35,9 +25,14 @@ export function ContributionCard({
color,
}: ContributionCardProps) {
const external = href.startsWith("http");
const prefersReducedMotion = useReducedMotion();

return (
<m.div className="h-full" variants={itemVariants}>
<m.div
className="h-full"
custom={{ reduced: prefersReducedMotion, distance: 20 } satisfies MotionCustom}
variants={slideUp}
>
<Card className="group flex h-full flex-col p-6 transition-colors duration-300 hover:bg-gray-50 hover:shadow-md dark:hover:bg-gray-800/60">
<div
className="pointer-events-none absolute inset-0 bg-linear-to-br opacity-0 transition-opacity duration-500 group-hover:opacity-100"
Expand Down
Loading