From 439ddaebf5ec0a63f9d118dd8ccb26d1e1f3da45 Mon Sep 17 00:00:00 2001 From: boojack Date: Thu, 14 May 2026 20:38:00 +0800 Subject: [PATCH] refactor(placeholder): extract tile sprite strip --- .../Placeholder/TileSpriteStrip.tsx | 67 ++++++++++++++++ web/src/components/Placeholder/index.tsx | 46 +---------- web/src/pages/About.tsx | 79 +------------------ 3 files changed, 73 insertions(+), 119 deletions(-) create mode 100644 web/src/components/Placeholder/TileSpriteStrip.tsx diff --git a/web/src/components/Placeholder/TileSpriteStrip.tsx b/web/src/components/Placeholder/TileSpriteStrip.tsx new file mode 100644 index 000000000..4d8e4238f --- /dev/null +++ b/web/src/components/Placeholder/TileSpriteStrip.tsx @@ -0,0 +1,67 @@ +import { cn } from "@/lib/utils"; +import type { TileSprite } from "./tileSprites"; + +interface TileSpriteStripProps { + sprite: TileSprite; + scale?: number; + className?: string; + testId?: string; +} + +const DEFAULT_SCALE = 2; + +const getAnimationName = (sprite: TileSprite, scale: number) => `tile-sprite-${sprite.name}-${scale}x`; + +const TileSpriteStrip = ({ sprite, scale = DEFAULT_SCALE, className, testId }: TileSpriteStripProps) => { + const stripWidth = sprite.frameWidth * sprite.frames; + const displayStripWidth = stripWidth * scale; + const displayStripHeight = sprite.frameHeight * scale; + const displayFrameWidth = sprite.frameWidth * scale; + const animationName = getAnimationName(sprite, scale); + + return ( + <> + + + + ); +}; + +export default TileSpriteStrip; diff --git a/web/src/components/Placeholder/index.tsx b/web/src/components/Placeholder/index.tsx index 5c11483e6..a53623596 100644 --- a/web/src/components/Placeholder/index.tsx +++ b/web/src/components/Placeholder/index.tsx @@ -1,6 +1,7 @@ import { type ReactNode, useState } from "react"; import { cn } from "@/lib/utils"; import { DEFAULT_MESSAGES, type PlaceholderVariant } from "./messages"; +import TileSpriteStrip from "./TileSpriteStrip"; import { pickTileSprite } from "./tileSprites"; interface PlaceholderProps { @@ -10,17 +11,12 @@ interface PlaceholderProps { className?: string; } -const TILE_SIZE = 32; const DISPLAY_SCALE = 2; -const DISPLAY_SIZE = TILE_SIZE * DISPLAY_SCALE; const Placeholder = ({ variant, message, children, className }: PlaceholderProps) => { const [sprite] = useState(pickTileSprite); const resolvedMessage = message ?? DEFAULT_MESSAGES[variant]; const isLoading = variant === "loading"; - const stripWidth = sprite.frameWidth * sprite.frames; - const displayStripWidth = stripWidth * DISPLAY_SCALE; - const displayStripHeight = sprite.frameHeight * DISPLAY_SCALE; return (
- - +

{resolvedMessage}

{children &&
{children}
}
diff --git a/web/src/pages/About.tsx b/web/src/pages/About.tsx index b1cbb5bd2..d5de1a82c 100644 --- a/web/src/pages/About.tsx +++ b/web/src/pages/About.tsx @@ -1,4 +1,5 @@ import { ExternalLinkIcon } from "lucide-react"; +import TileSpriteStrip from "@/components/Placeholder/TileSpriteStrip"; import { TILE_SPRITES, type TileSprite } from "@/components/Placeholder/tileSprites"; import SettingGroup from "@/components/Settings/SettingGroup"; import SettingSection from "@/components/Settings/SettingSection"; @@ -14,82 +15,12 @@ const PRODUCT_LINKS = [ const PRODUCT_POINTS = ["Open. Write. Done.", "Markdown-native.", "Fully yours."]; -const BIRD_META: Record = { - OwlBlink: { - label: "Owl", - description: "Night watch idle with a compact blink.", - }, - EagleIdle: { - label: "Eagle", - description: "Perched idle with a sharp head and steady chest motion.", - }, - ToucanIdle: { - label: "Toucan", - description: "Calm tropical idle built around a large curved beak.", - }, -}; - -const getBirdAnimationName = (sprite: TileSprite) => `about-bird-${sprite.name}`; - -const BIRD_KEYFRAMES_CSS = ` - ${TILE_SPRITES.map( - (sprite) => ` - @keyframes ${getBirdAnimationName(sprite)} { - from { transform: translateX(0); } - to { transform: translateX(-${sprite.frameWidth * sprite.frames * SPRITE_SCALE}px); } - } - `, - ).join("\n")} - - @media (prefers-reduced-motion: reduce) { - .about-bird-strip { - animation: none !important; - transform: translateX(0) !important; - } - } -`; - const BirdSprite = ({ sprite }: { sprite: TileSprite }) => { - const stripWidth = sprite.frameWidth * sprite.frames; - const displayWidth = stripWidth * SPRITE_SCALE; - const displayHeight = sprite.frameHeight * SPRITE_SCALE; - const frameDisplayWidth = displayWidth / sprite.frames; - const meta = BIRD_META[sprite.name]; - return ( -
- +
+
-
-

{sprite.name}

- {meta.label} -
-

{meta.description}

+

{sprite.name}

); @@ -98,8 +29,6 @@ const BirdSprite = ({ sprite }: { sprite: TileSprite }) => { const About = () => { return (
- -