-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
049593e
commit ab4a90e
Showing
29 changed files
with
317 additions
and
16 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,180 @@ | ||
import { useCallback, useEffect, useRef, useState } from "react"; | ||
|
||
import type { Action, CatType } from "./Cats"; | ||
import { cat1, cat5, CatTalk } from "./Cats"; | ||
|
||
import { | ||
Tooltip, | ||
TooltipContent, | ||
TooltipProvider, | ||
TooltipTrigger, | ||
} from "@/components/ui/tooltip"; | ||
|
||
import Image from "next/image"; | ||
|
||
// Pixels per second | ||
const DEFAULT_SPEED = 30; | ||
const RUNNING_SPEED = 60; | ||
|
||
type CatProps = { | ||
id: string; | ||
name: string; | ||
onClick: () => void; | ||
}; | ||
|
||
function Cat({ name }: CatProps) { | ||
let currPet: CatType; | ||
switch (name) { | ||
case "cat1": | ||
currPet = cat1; | ||
break; | ||
case "cat5": | ||
currPet = cat5; | ||
break; | ||
default: | ||
currPet = cat1; | ||
} | ||
const petRef = useRef<HTMLDivElement>(null); | ||
const actionRef = useRef<Action>("idle"); | ||
|
||
const [position, setPosition] = useState({ x: 90, y: -4 }); | ||
const [moveDuration, setMoveDuration] = useState(0); | ||
const [faceRight, setFaceRight] = useState(true); | ||
const [currAction, setCurrAction] = useState<Action>("laying"); | ||
const [catSpeech, setCatSpeech] = useState(""); | ||
|
||
const getRelativePosition = useCallback(() => { | ||
if (!petRef.current) return { x: 0, y: 0 }; | ||
|
||
const petRect = petRef.current.getBoundingClientRect(); | ||
const container = petRef.current.parentNode as HTMLElement; | ||
const containerRect = container.getBoundingClientRect(); | ||
|
||
return { | ||
x: petRect.left - containerRect.left, | ||
y: petRect.top - containerRect.top, | ||
}; | ||
}, []); | ||
|
||
const rest = useCallback(() => { | ||
actionRef.current = "idle"; | ||
setCurrAction("idle"); | ||
setMoveDuration(0); | ||
}, []); | ||
|
||
const move = useCallback(() => { | ||
if (actionRef.current === "walking") { | ||
return; | ||
} | ||
|
||
actionRef.current = "walking"; | ||
|
||
// First determine the direction | ||
let direction = Math.random() > 0.5 ? 1 : -1; | ||
// Then determine the distance without running into the bounding box | ||
const currentPosition = getRelativePosition(); | ||
const distance = Math.floor(Math.random() * 200 + 50); | ||
const futureX = currentPosition.x + direction * distance; | ||
|
||
// Collision detection with container boundaries | ||
const container = petRef.current?.parentNode as HTMLElement; | ||
if (container) { | ||
const containerWidth = container.offsetWidth; | ||
|
||
if (futureX < 0 || futureX > containerWidth - 40) { | ||
direction *= -1; // Reverse the direction | ||
} | ||
} | ||
// set new direction | ||
setFaceRight(direction === 1); | ||
|
||
const gottaRun = distance > 150; | ||
setCurrAction(gottaRun ? "running" : "walking"); | ||
|
||
// Calculate duration | ||
const moveDuration = gottaRun | ||
? distance / RUNNING_SPEED | ||
: distance / DEFAULT_SPEED; | ||
setMoveDuration(moveDuration); | ||
|
||
// Update position with possibly reversed direction | ||
setPosition((prev) => { | ||
return { x: prev.x + direction * distance, y: prev.y }; | ||
}); | ||
|
||
// Set a timeout to stop walking after the calculated duration | ||
setTimeout(() => { | ||
rest(); | ||
}, moveDuration * 1000); | ||
}, [getRelativePosition, rest]); | ||
|
||
// Simulate some autonomous behavior | ||
useEffect(() => { | ||
// Interval to change the cat's behavior periodically | ||
|
||
const interval = setInterval(() => { | ||
if (actionRef.current === "walking" || actionRef.current === "running") { | ||
return; | ||
} | ||
const shouldMove = Math.random() > 0.5; | ||
if (shouldMove) { | ||
move(); | ||
} else { | ||
rest(); | ||
} | ||
}, 7000); | ||
|
||
return () => clearInterval(interval); | ||
}, [move, rest]); | ||
|
||
const generateMessage = useCallback(() => { | ||
const randomIndex = Math.floor(Math.random() * CatTalk.length); | ||
setCatSpeech(CatTalk[randomIndex] as string); | ||
}, []); | ||
|
||
return ( | ||
<div | ||
className="absolute bottom-3 h-10 w-10 border-yellow-500" | ||
style={{ | ||
left: position.x, | ||
bottom: position.y, | ||
transition: `all ${moveDuration}s linear`, | ||
}} | ||
ref={petRef} | ||
> | ||
<Image | ||
alt="cat" | ||
className="absolute inset-0 scale-150" | ||
style={{ | ||
transform: ` | ||
${faceRight ? "scaleX(1)" : "scaleX(-1)"} | ||
scaleX(1.25) | ||
scaleY(1.25) | ||
`, | ||
}} | ||
src={currPet[currAction]} | ||
/> | ||
<TooltipProvider delayDuration={50}> | ||
<Tooltip | ||
onOpenChange={(open) => { | ||
if (open) { | ||
generateMessage(); | ||
} | ||
}} | ||
> | ||
<TooltipTrigger> | ||
<div | ||
className="absolute bottom-0 left-1 right-2 top-3 m-auto cursor-pointer border-green-800" | ||
onClick={move} | ||
/> | ||
</TooltipTrigger> | ||
<TooltipContent sideOffset={7} align="start"> | ||
<p className="text-xs">{catSpeech}</p> | ||
</TooltipContent> | ||
</Tooltip> | ||
</TooltipProvider> | ||
</div> | ||
); | ||
} | ||
|
||
export default Cat; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
import cat1Walking from "public/cats/cat01_gifs/cat01_walk_8fps.gif"; | ||
import cat1Idle from "public/cats/cat01_gifs/cat01_idle_blink_8fps.gif"; | ||
import cat1Laying from "public/cats/cat01_gifs/cat01_liedown_8fps.gif"; | ||
import cat1Running from "public/cats/cat01_gifs/cat01_run_12fps.gif"; | ||
|
||
import cat5Walking from "public/cats/cat05_gifs/cat05_walk_8fps.gif"; | ||
import cat5Idle from "public/cats/cat05_gifs/cat05_idle_blink_8fps.gif"; | ||
import cat5Laying from "public/cats/cat05_gifs/cat05_liedown_8fps.gif"; | ||
import cat5Running from "public/cats/cat05_gifs/cat05_run_12fps.gif"; | ||
|
||
import type { StaticImageData } from "next/image"; | ||
|
||
export type Action = "idle" | "walking" | "laying" | "running"; | ||
|
||
export type CatType = { | ||
[K in Action]: StaticImageData; | ||
}; | ||
|
||
const cat1: CatType = { | ||
walking: cat1Walking, | ||
idle: cat1Idle, | ||
laying: cat1Laying, | ||
running: cat1Running, | ||
}; | ||
|
||
const cat5: CatType = { | ||
walking: cat5Walking, | ||
idle: cat5Idle, | ||
laying: cat5Laying, | ||
running: cat5Running, | ||
}; | ||
|
||
// TODO: make very dramatic reminders to complete habits | ||
const CatTalk = [ | ||
"Meow", | ||
"Purrrrr", | ||
"Hi, I'm Puffin!", | ||
"I love you!", | ||
"Feed me!", | ||
"I'm hungry~", | ||
]; | ||
|
||
export { cat1, cat5, CatTalk }; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
import * as React from "react"; | ||
import * as TooltipPrimitive from "@radix-ui/react-tooltip"; | ||
|
||
import { cn } from "@/lib/utils"; | ||
|
||
const TooltipProvider = TooltipPrimitive.Provider; | ||
|
||
const Tooltip = TooltipPrimitive.Root; | ||
|
||
const TooltipTrigger = TooltipPrimitive.Trigger; | ||
|
||
const TooltipContent = React.forwardRef< | ||
React.ElementRef<typeof TooltipPrimitive.Content>, | ||
React.ComponentPropsWithoutRef<typeof TooltipPrimitive.Content> | ||
>(({ className, sideOffset = 4, ...props }, ref) => ( | ||
<TooltipPrimitive.Content | ||
ref={ref} | ||
sideOffset={sideOffset} | ||
className={cn( | ||
"z-100 overflow-hidden rounded-md border bg-popover px-1 py-0.5 text-sm text-popover-foreground shadow-md animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2", | ||
className | ||
)} | ||
{...props} | ||
/> | ||
)); | ||
TooltipContent.displayName = TooltipPrimitive.Content.displayName; | ||
|
||
export { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider }; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -1990,6 +1990,25 @@ | |
"@radix-ui/react-roving-focus" "1.0.4" | ||
"@radix-ui/react-use-controllable-state" "1.0.1" | ||
|
||
"@radix-ui/react-tooltip@^1.0.7": | ||
version "1.0.7" | ||
resolved "https://registry.yarnpkg.com/@radix-ui/react-tooltip/-/react-tooltip-1.0.7.tgz#8f55070f852e7e7450cc1d9210b793d2e5a7686e" | ||
integrity sha512-lPh5iKNFVQ/jav/j6ZrWq3blfDJ0OH9R6FlNUHPMqdLuQ9vwDgFsRxvl8b7Asuy5c8xmoojHUxKHQSOAvMHxyw== | ||
dependencies: | ||
"@babel/runtime" "^7.13.10" | ||
"@radix-ui/primitive" "1.0.1" | ||
"@radix-ui/react-compose-refs" "1.0.1" | ||
"@radix-ui/react-context" "1.0.1" | ||
"@radix-ui/react-dismissable-layer" "1.0.5" | ||
"@radix-ui/react-id" "1.0.1" | ||
"@radix-ui/react-popper" "1.1.3" | ||
"@radix-ui/react-portal" "1.0.4" | ||
"@radix-ui/react-presence" "1.0.1" | ||
"@radix-ui/react-primitive" "1.0.3" | ||
"@radix-ui/react-slot" "1.0.2" | ||
"@radix-ui/react-use-controllable-state" "1.0.1" | ||
"@radix-ui/react-visually-hidden" "1.0.3" | ||
|
||
"@radix-ui/[email protected]": | ||
version "1.0.0" | ||
resolved "https://registry.npmjs.org/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.0.0.tgz" | ||
|
@@ -2057,6 +2076,14 @@ | |
"@babel/runtime" "^7.13.10" | ||
"@radix-ui/react-use-layout-effect" "1.0.1" | ||
|
||
"@radix-ui/[email protected]": | ||
version "1.0.3" | ||
resolved "https://registry.yarnpkg.com/@radix-ui/react-visually-hidden/-/react-visually-hidden-1.0.3.tgz#51aed9dd0fe5abcad7dee2a234ad36106a6984ac" | ||
integrity sha512-D4w41yN5YRKtu464TLnByKzMDG/JlMPHtfZgQAu9v6mNakUqGUI9vUrfQKz8NK41VMm/xbZbh76NUTVtIYqOMA== | ||
dependencies: | ||
"@babel/runtime" "^7.13.10" | ||
"@radix-ui/react-primitive" "1.0.3" | ||
|
||
"@radix-ui/[email protected]": | ||
version "1.0.1" | ||
resolved "https://registry.yarnpkg.com/@radix-ui/rect/-/rect-1.0.1.tgz#bf8e7d947671996da2e30f4904ece343bc4a883f" | ||
|