moved to motion.dev

This commit is contained in:
MasterGordon 2025-06-14 04:37:10 +02:00
parent 781d80f5e5
commit e8d1a8afde
19 changed files with 81 additions and 66 deletions

1
bad
View File

@ -1 +0,0 @@
f7360d42-dcc1-4e1e-a90b-ef2295298872

BIN
bun.lockb

Binary file not shown.

View File

@ -35,9 +35,9 @@
"clsx": "^2.1.1", "clsx": "^2.1.1",
"dayjs": "^1.11.13", "dayjs": "^1.11.13",
"drizzle-orm": "0.33.0", "drizzle-orm": "0.33.0",
"framer-motion": "^11.11.8",
"jotai": "^2.10.0", "jotai": "^2.10.0",
"lucide-react": "^0.452.0", "lucide-react": "^0.452.0",
"motion": "^12.18.1",
"pixi-viewport": "^5.0.3", "pixi-viewport": "^5.0.3",
"pixi.js": "^7.0.0", "pixi.js": "^7.0.0",
"pixi.js-legacy": "^7.4.2", "pixi.js-legacy": "^7.4.2",
@ -69,6 +69,7 @@
"typescript": "^5.6.3", "typescript": "^5.6.3",
"typescript-eslint": "^8.8.1", "typescript-eslint": "^8.8.1",
"vite": "^5.4.8", "vite": "^5.4.8",
"vite-bundle-analyzer": "^0.22.3",
"vite-imagetools": "^7.0.4" "vite-imagetools": "^7.0.4"
} }
} }

View File

@ -1,6 +1,6 @@
import { type PropsWithChildren, useEffect, useRef, useState } from "react"; import { type PropsWithChildren, useEffect, useRef, useState } from "react";
import { Button } from "./components/Button"; import { Button } from "./components/Button";
import { motion } from "framer-motion"; import { motion } from "motion/react";
import { import {
GitBranch, GitBranch,
History, History,

View File

@ -10,8 +10,8 @@ import {
type LoadedTexture, type LoadedTexture,
type LoadedTheme, type LoadedTheme,
type Theme, type Theme,
useTheme,
} from "../themes/Theme"; } from "../themes/Theme";
import { useTheme } from "../themes/useTheme";
import { Container, Sprite, Stage, useTick } from "@pixi/react"; import { Container, Sprite, Stage, useTick } from "@pixi/react";
import Viewport from "./pixi/PixiViewport"; import Viewport from "./pixi/PixiViewport";
import type { Viewport as PixiViewport } from "pixi-viewport"; import type { Viewport as PixiViewport } from "pixi-viewport";

View File

@ -1,4 +1,4 @@
import { animate, motion } from "framer-motion"; import { animate, motion } from "motion/react";
import { useRef } from "react"; import { useRef } from "react";
const BounceImg = ({ src, className }: { src: string; className?: string }) => { const BounceImg = ({ src, className }: { src: string; className?: string }) => {

View File

@ -1,4 +1,4 @@
import { AnimatePresence, motion } from "framer-motion"; import { AnimatePresence, motion } from "motion/react";
import { useAtom } from "jotai"; import { useAtom } from "jotai";
import { feedItemsAtom, lootboxResultAtom } from "../../atoms"; import { feedItemsAtom, lootboxResultAtom } from "../../atoms";
import FeedItemElement from "./FeedItem"; import FeedItemElement from "./FeedItem";

View File

@ -1,4 +1,4 @@
import { motion } from "framer-motion"; import { motion } from "motion/react";
import type { PropsWithChildren } from "react"; import type { PropsWithChildren } from "react";
import { formatTimeSpan } from "../../../shared/time"; import { formatTimeSpan } from "../../../shared/time";
import GemsIcon from "../GemIcon"; import GemsIcon from "../GemIcon";

View File

@ -0,0 +1,3 @@
import { lazy } from "react";
export const Board = lazy(() => import("./Board"));

View File

@ -12,7 +12,7 @@ import Home from "./views/home/Home.tsx";
import Settings from "./views/settings/Settings.tsx"; import Settings from "./views/settings/Settings.tsx";
import MatchHistory from "./views/match-history/MatchHistory.tsx"; import MatchHistory from "./views/match-history/MatchHistory.tsx";
import Collection from "./views/collection/Collection.tsx"; import Collection from "./views/collection/Collection.tsx";
import { AnimatePresence } from "framer-motion"; import { AnimatePresence } from "motion/react";
import Store from "./views/store/Store.tsx"; import Store from "./views/store/Store.tsx";
import Profile from "./views/profile/Profile.tsx"; import Profile from "./views/profile/Profile.tsx";

View File

@ -1,10 +1,9 @@
import { Assets, Texture } from "pixi.js"; import type { Texture } from "pixi.js";
import { useEffect, useState } from "react";
type Png = typeof import("*.png"); type Png = typeof import("*.png");
type LazySprite = () => Promise<Png>; type LazySprite = () => Promise<Png>;
interface WeightedLazySprites { export interface WeightedLazySprites {
weight: number; weight: number;
sprite: LazySprite; sprite: LazySprite;
} }
@ -54,36 +53,3 @@ export const mainWithSpecials = (
...specials.map((sprite) => ({ weight: 0.05, sprite })), ...specials.map((sprite) => ({ weight: 0.05, sprite })),
]; ];
}; };
export const useTheme = (theme: Theme) => {
const [loadedTheme, setLoadedTheme] = useState<LoadedTheme | undefined>(
undefined
);
useEffect(() => {
const loadTheme = async () => {
const loadedEntries = await Promise.all(
Object.entries(theme).map(async ([key, value]) => {
let loaded = value;
if (typeof value === "function") {
loaded = await Assets.load((await value()).default);
}
if (Array.isArray(value)) {
loaded = await Promise.all(
loaded.map(async (sprite: WeightedLazySprites) => {
return {
weight: sprite.weight,
sprite: await Assets.load((await sprite.sprite()).default),
};
})
);
}
return [key, loaded] as const;
})
);
setLoadedTheme(Object.fromEntries(loadedEntries) as LoadedTheme);
};
loadTheme();
}, [theme]);
return loadedTheme;
};

36
src/themes/useTheme.ts Normal file
View File

@ -0,0 +1,36 @@
import { Assets } from "pixi.js";
import { useState, useEffect } from "react";
import type { Theme, LoadedTheme, WeightedLazySprites } from "./Theme";
export const useTheme = (theme: Theme) => {
const [loadedTheme, setLoadedTheme] = useState<LoadedTheme | undefined>(
undefined,
);
useEffect(() => {
const loadTheme = async () => {
const loadedEntries = await Promise.all(
Object.entries(theme).map(async ([key, value]) => {
let loaded = value;
if (typeof value === "function") {
loaded = await Assets.load((await value()).default);
}
if (Array.isArray(value)) {
loaded = await Promise.all(
loaded.map(async (sprite: WeightedLazySprites) => {
return {
weight: sprite.weight,
sprite: await Assets.load((await sprite.sprite()).default),
};
}),
);
}
return [key, loaded] as const;
}),
);
setLoadedTheme(Object.fromEntries(loadedEntries) as LoadedTheme);
};
loadTheme();
}, [theme]);
return loadedTheme;
};

View File

@ -1,6 +1,6 @@
import { Ellipsis } from "lucide-react"; import { Ellipsis } from "lucide-react";
import { testBoard } from "../../../shared/testBoard"; import { testBoard } from "../../../shared/testBoard";
import Board from "../../components/Board"; import { Board } from "../../components/LazyBoard";
import { Button } from "../../components/Button"; import { Button } from "../../components/Button";
import { themes } from "../../themes"; import { themes } from "../../themes";
import { import {

View File

@ -1,10 +1,10 @@
import Board from "../../components/Board";
import { useWSMutation, useWSQuery } from "../../hooks"; import { useWSMutation, useWSQuery } from "../../hooks";
import { useAtom } from "jotai"; import { useAtom } from "jotai";
import { gameIdAtom } from "../../atoms"; import { gameIdAtom } from "../../atoms";
import { Button } from "../../components/Button"; import { Button } from "../../components/Button";
import LeaderboardButton from "../../components/LeaderboardButton"; import LeaderboardButton from "../../components/LeaderboardButton";
import { Fragment, useEffect } from "react"; import { Fragment, useEffect } from "react";
import { Board } from "../../components/LazyBoard";
interface EndlessProps { interface EndlessProps {
gameId?: string; gameId?: string;

View File

@ -1,4 +1,4 @@
import { animate, motion, useMotionValue, useTransform } from "framer-motion"; import { animate, motion, useMotionValue, useTransform } from "motion/react";
import { useEffect } from "react"; import { useEffect } from "react";
import { useWSQuery } from "../../hooks"; import { useWSQuery } from "../../hooks";
import { Tag } from "../../components/Tag"; import { Tag } from "../../components/Tag";

View File

@ -4,7 +4,7 @@ import {
useMotionTemplate, useMotionTemplate,
useScroll, useScroll,
useTransform, useTransform,
} from "framer-motion"; } from "motion/react";
import { useEffect, useRef, useState } from "react"; import { useEffect, useRef, useState } from "react";
import { cn } from "../../lib/utils"; import { cn } from "../../lib/utils";
@ -48,8 +48,10 @@ const Section = ({ text, image, left }: SectionProps) => {
className="md:w-[50%] h-90" className="md:w-[50%] h-90"
// float up and down // float up and down
animate={{ animate={{
translateY: [0, 10, 0], // translate: ["0 0", "5 10", "0 0"],
translateX: [0, 5, 0], // transform: ["translate"]
x: [0, 10, 0],
y: [0, 5, 0],
}} }}
transition={{ transition={{
repeat: Infinity, repeat: Infinity,
@ -71,7 +73,7 @@ const Section = ({ text, image, left }: SectionProps) => {
translateY, translateY,
}} }}
transition={{ transition={{
type: "just", type: "spring",
delay: 0.5, delay: 0.5,
}} }}
srcSet={image.map((i) => `${i.src} ${i.width}w`).join(", ")} srcSet={image.map((i) => `${i.src} ${i.width}w`).join(", ")}

View File

@ -40,7 +40,9 @@ const Profile: React.FC = () => {
<div className="border-l-white border-l p-2 text-lg"> <div className="border-l-white border-l p-2 text-lg">
<p>Total Games: {profile?.totalGames}</p> <p>Total Games: {profile?.totalGames}</p>
<p>Highest Stage: {profile?.highestStage}</p> <p>Highest Stage: {profile?.highestStage}</p>
<p>Average Stage: {profile?.averageStage}</p> <p>
Average Stage: {Math.round(profile?.averageStage ?? 1 * 100) / 100}
</p>
</div> </div>
</div> </div>
<div className="flex flex-col gap-4"> <div className="flex flex-col gap-4">

View File

@ -16,9 +16,7 @@ import { lootboxResultAtom } from "../../atoms";
import { useAtom } from "jotai"; import { useAtom } from "jotai";
import { useEffect } from "react"; import { useEffect } from "react";
import Particles, { initParticlesEngine } from "@tsparticles/react"; import Particles, { initParticlesEngine } from "@tsparticles/react";
import { loadSlim } from "@tsparticles/slim"; import { motion } from "motion/react";
import { loadSeaAnemonePreset } from "@tsparticles/preset-sea-anemone";
import { motion } from "framer-motion";
import BounceImg from "../../components/BounceImg"; import BounceImg from "../../components/BounceImg";
const Store = () => { const Store = () => {
@ -29,6 +27,11 @@ const Store = () => {
// this should be run only once per application lifetime // this should be run only once per application lifetime
useEffect(() => { useEffect(() => {
const cb = async () => {
const { loadSlim } = await import("@tsparticles/slim");
const { loadSeaAnemonePreset } = await import(
"@tsparticles/preset-sea-anemone"
);
initParticlesEngine(async (engine) => { initParticlesEngine(async (engine) => {
// you can initiate the tsParticles instance (engine) here, adding custom shapes or presets // you can initiate the tsParticles instance (engine) here, adding custom shapes or presets
// this loads the tsparticles package bundle, it's the easiest method for getting everything ready // this loads the tsparticles package bundle, it's the easiest method for getting everything ready
@ -40,6 +43,8 @@ const Store = () => {
//await loadBasic(engine); //await loadBasic(engine);
}); });
};
cb();
}, []); }, []);
return ( return (

View File

@ -2,11 +2,12 @@ import { defineConfig } from "vite";
import react from "@vitejs/plugin-react-swc"; import react from "@vitejs/plugin-react-swc";
import tailwindcss from "@tailwindcss/vite"; import tailwindcss from "@tailwindcss/vite";
import { imagetools } from "vite-imagetools"; import { imagetools } from "vite-imagetools";
import { analyzer } from "vite-bundle-analyzer";
// https://vitejs.dev/config/ // https://vitejs.dev/config/
export default defineConfig({ export default defineConfig({
server: { server: {
port: 3003, port: 3003,
}, },
plugins: [react(), tailwindcss(), imagetools()], plugins: [react(), tailwindcss(), imagetools(), analyzer()],
}); });