Skip to content

Commit

Permalink
lint stuff
Browse files Browse the repository at this point in the history
  • Loading branch information
k2xl committed Dec 26, 2024
1 parent ebf8c31 commit 23367b6
Show file tree
Hide file tree
Showing 28 changed files with 523 additions and 469 deletions.
215 changes: 108 additions & 107 deletions components/counters/AnimateCounterOne.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,125 +10,126 @@ interface AnimateCounterOneProps {
}

export const STREAK_RANK_GROUPS = [
{ min: 0, max: 1, title: "It Begins", emoji: "🌱" },
{ min: 2, max: 4, title: "Getting Comfortable", emoji: "👀" },
{ min: 5, max: 8, title: "Forming Habit", emoji: "🕐" },
{ min: 9, max: 14, title: "Habit Formed", emoji: "✅" },
{ min: 15, max: 22, title: "Routine", emoji: "🔄" },
{ min: 23, max: 29, title: "Hooked", emoji: "🪝" },
{ min: 30, max: 39, title: "Losing Grip", emoji: "🌀" },
{ min: 40, max: 54, title: "All-Consuming", emoji: "🌋" },
{ min: 55, max: 69, title: "Forming Addiction", emoji: "💥" },
{ min: 70, max: 89, title: "Addiction Formed", emoji: "🔥" },
{ min: 90, max: 119, title: "No Turning Back", emoji: "🚫" },
{ min: 120, max: 149, title: "Deeply Bound", emoji: "🕸️" },
{ min: 150, max: 189, title: "Ever Growing", emoji: "🌿" },
{ min: 190, max: 239, title: "Magnetic Force", emoji: "🧲" },
{ min: 240, max: 299, title: "Unshakable", emoji: "🤜" },
{ min: 300, max: 369, title: "Irreversible", emoji: "♾️" },
{ min: 370, max: 449, title: "Inescapable", emoji: "🤯" },
{ min: 450, max: 549, title: "Unbreakable Chain", emoji: "⛓️" },
{ min: 550, max: 649, title: "Endless Spiral", emoji: "🌪️" },
{ min: 650, max: 729, title: "Thinky Lifer", emoji: "🌳" },
{ min: 730, max: Infinity, title: "Never Enough", emoji: "♾️" },
{ min: 0, max: 1, title: 'It Begins', emoji: '🌱' },
{ min: 2, max: 4, title: 'Getting Comfortable', emoji: '👀' },
{ min: 5, max: 8, title: 'Forming Habit', emoji: '🕐' },
{ min: 9, max: 14, title: 'Habit Formed', emoji: '✅' },
{ min: 15, max: 22, title: 'Routine', emoji: '🔄' },
{ min: 23, max: 29, title: 'Hooked', emoji: '🪝' },
{ min: 30, max: 39, title: 'Losing Grip', emoji: '🌀' },
{ min: 40, max: 54, title: 'All-Consuming', emoji: '🌋' },
{ min: 55, max: 69, title: 'Forming Addiction', emoji: '💥' },
{ min: 70, max: 89, title: 'Addiction Formed', emoji: '🔥' },
{ min: 90, max: 119, title: 'No Turning Back', emoji: '🚫' },
{ min: 120, max: 149, title: 'Deeply Bound', emoji: '🕸️' },
{ min: 150, max: 189, title: 'Ever Growing', emoji: '🌿' },
{ min: 190, max: 239, title: 'Magnetic Force', emoji: '🧲' },
{ min: 240, max: 299, title: 'Unshakable', emoji: '🤜' },
{ min: 300, max: 369, title: 'Irreversible', emoji: '♾️' },
{ min: 370, max: 449, title: 'Inescapable', emoji: '🤯' },
{ min: 450, max: 549, title: 'Unbreakable Chain', emoji: '⛓️' },
{ min: 550, max: 649, title: 'Endless Spiral', emoji: '🌪️' },
{ min: 650, max: 729, title: 'Thinky Lifer', emoji: '🌳' },
{ min: 730, max: Infinity, title: 'Never Enough', emoji: '♾️' },
] as const;

/** Helper to find the rank index based on the current streak. */
export function getStreakRankIndex(value: number): number {
const idx = STREAK_RANK_GROUPS.findIndex(rank => value >= rank.min && value <= rank.max);
return idx !== -1 ? idx : STREAK_RANK_GROUPS.length - 1;
const idx = STREAK_RANK_GROUPS.findIndex(rank => value >= rank.min && value <= rank.max);

return idx !== -1 ? idx : STREAK_RANK_GROUPS.length - 1;
}

export const AnimateCounterOne: React.FC<AnimateCounterOneProps> = ({ gameId, value }) => {
const [currentValue, setCurrentValue] = useState(value - 1);
const [isAnimating, setIsAnimating] = useState(false);
const [showRankUp, setShowRankUp] = useState(false);
// Find current rank info
const currentRankIndex = getStreakRankIndex(value);
const currentRank = STREAK_RANK_GROUPS[currentRankIndex];
const nextRank = STREAK_RANK_GROUPS[currentRankIndex + 1];

// Check if we're exactly at a rank threshold
const isExactRank = currentRank.min === value;

// Handle animations
useEffect(() => {
// Start counter animation
setCurrentValue(value - 1);
setIsAnimating(true);

const counterTimeout = setTimeout(() => {
setCurrentValue(value);
setIsAnimating(false);
}, 300);

// Show rank up animation if at exact rank
if (isExactRank) {
setShowRankUp(true);
const rankTimeout = setTimeout(() => setShowRankUp(false), 2000);
return () => {
clearTimeout(counterTimeout);
clearTimeout(rankTimeout);
};
}

return () => clearTimeout(counterTimeout);
}, [value, isExactRank]);

// Calculate progress to next rank
const progressPercent = nextRank ? Math.min(
((value - currentRank.min) / (nextRank.min - currentRank.min)) * 100,
100
) : 100;

return (
<div className="flex flex-col gap-2 max-w-sm mx-auto bg-white pt-3 rounded-lg">
{/* Main Row: Counter + Title + Emoji */}
<div className="flex items-center gap-1">
{/* Counter on the left */}
<div className="font-bold flex text-gray-400 flex-row gap-1 text-xs items-center absolute top-2 left-1/2 -translate-x-1/2">
<GameLogo gameId={gameId} id={gameId + 'animate-counter-one'} size={10} />
{getGameFromId(gameId).displayName}
</div>
<div className={`transition-all duration-700 ${showRankUp ? 'text-green-600' : ''}`}>
<Counter value={currentValue} />
</div>

<div className='flex flex-col'>
{/* Title and Emoji */}
<div
className={`flex items-center gap-2 text-sm font-medium text-gray-700 transition-all duration-700
const [currentValue, setCurrentValue] = useState(value - 1);
const [isAnimating, setIsAnimating] = useState(false);
const [showRankUp, setShowRankUp] = useState(false);

// Find current rank info
const currentRankIndex = getStreakRankIndex(value);
const currentRank = STREAK_RANK_GROUPS[currentRankIndex];
const nextRank = STREAK_RANK_GROUPS[currentRankIndex + 1];

// Check if we're exactly at a rank threshold
const isExactRank = currentRank.min === value;

// Handle animations
useEffect(() => {
// Start counter animation
setCurrentValue(value - 1);
setIsAnimating(true);

const counterTimeout = setTimeout(() => {
setCurrentValue(value);
setIsAnimating(false);
}, 300);

// Show rank up animation if at exact rank
if (isExactRank) {
setShowRankUp(true);
const rankTimeout = setTimeout(() => setShowRankUp(false), 2000);

return () => {
clearTimeout(counterTimeout);
clearTimeout(rankTimeout);
};
}

return () => clearTimeout(counterTimeout);
}, [value, isExactRank]);

// Calculate progress to next rank
const progressPercent = nextRank ? Math.min(
((value - currentRank.min) / (nextRank.min - currentRank.min)) * 100,
100
) : 100;

return (
<div className='flex flex-col gap-2 max-w-sm mx-auto bg-white pt-3 rounded-lg'>
{/* Main Row: Counter + Title + Emoji */}
<div className='flex items-center gap-1'>
{/* Counter on the left */}
<div className='font-bold flex text-gray-400 flex-row gap-1 text-xs items-center absolute top-2 left-1/2 -translate-x-1/2'>
<GameLogo gameId={gameId} id={gameId + 'animate-counter-one'} size={10} />
{getGameFromId(gameId).displayName}
</div>
<div className={`transition-all duration-700 ${showRankUp ? 'text-green-600' : ''}`}>
<Counter value={currentValue} />
</div>
<div className='flex flex-col'>

{/* Title and Emoji */}
<div
className={`flex items-center gap-2 text-sm font-medium text-gray-700 transition-all duration-700
${showRankUp ? 'text-green-600 font-bold' : ''}
`}
>
{currentRank.title}
<span className={`text-2xl transition-all duration-300
>
{currentRank.title}
<span className={`text-2xl transition-all duration-300
${isAnimating ? 'scale-125' : ''}
${showRankUp ? 'animate-pulse' : ''}
`}>
{currentRank.emoji}
</span>
</div>
{/* Progress Indicator */}
{nextRank && (
<div className="w-full space-y-0.5">
<div className="h-1 bg-gray-100 rounded-full overflow-hidden">
<div
className={`h-full transition-all duration-700
{currentRank.emoji}
</span>
</div>
{/* Progress Indicator */}
{nextRank && (
<div className='w-full space-y-0.5'>
<div className='h-1 bg-gray-100 rounded-full overflow-hidden'>
<div
className={`h-full transition-all duration-700
${showRankUp ? 'bg-green-400' : 'bg-green-500'}`}
style={{ width: `${progressPercent}%` }}
/>
</div>
<div className="text-xs text-gray-500 text-center">
style={{ width: `${progressPercent}%` }}
/>
</div>
<div className='text-xs text-gray-500 text-center'>
Next rank {nextRank.min - value === 1 ? 'tomorrow' : `in ${nextRank.min - value} days`}
</div>
</div>
)}</div>

</div>
</div>

</div>
);
};
)}</div>

</div>

</div>
);
};
22 changes: 11 additions & 11 deletions components/counters/Counter.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { MotionValue, motion, useSpring, useTransform } from "framer-motion";
import { useEffect, useState } from "react";
import { motion, MotionValue, useSpring, useTransform } from 'framer-motion';
import React, { useEffect } from 'react';

const fontSize = 30;
const padding = 15;
Expand All @@ -8,11 +8,11 @@ const height = fontSize + padding;
export function Counter({ value }: { value: number }) {
// Convert number to string and remove leading zeros
const displayValue = value.toString();

return (
<div
style={{ fontSize }}
className="flex space-x-1 overflow-hidden rounded bg-white px-2 leading-none text-gray-900"
className='flex space-x-1 overflow-hidden rounded bg-white px-2 leading-none text-gray-900'
>
{displayValue.split('').map((digit, i) => (
<Digit key={i} place={Math.pow(10, displayValue.length - i - 1)} value={value} />
Expand All @@ -22,15 +22,15 @@ export function Counter({ value }: { value: number }) {
}

function Digit({ place, value }: { place: number; value: number }) {
let valueRoundedToPlace = Math.floor(value / place);
let animatedValue = useSpring(valueRoundedToPlace);
const valueRoundedToPlace = Math.floor(value / place);
const animatedValue = useSpring(valueRoundedToPlace);

useEffect(() => {
animatedValue.set(valueRoundedToPlace);
}, [animatedValue, valueRoundedToPlace]);

return (
<div style={{ height }} className="relative w-[1ch] tabular-nums border-2 rounded-md p-4 border-gray-500">
<div style={{ height }} className='relative w-[1ch] tabular-nums border-2 rounded-md p-4 border-gray-500'>
{[...Array(10).keys()].map((i) => (
<Number key={i} mv={animatedValue} number={i} />
))}
Expand All @@ -39,9 +39,9 @@ function Digit({ place, value }: { place: number; value: number }) {
}

function Number({ mv, number }: { mv: MotionValue; number: number }) {
let y = useTransform(mv, (latest) => {
let placeValue = latest % 10;
let offset = (10 + number - placeValue) % 10;
const y = useTransform(mv, (latest) => {
const placeValue = latest % 10;
const offset = (10 + number - placeValue) % 10;

let memo = offset * height;

Expand All @@ -55,7 +55,7 @@ function Number({ mv, number }: { mv: MotionValue; number: number }) {
return (
<motion.span
style={{ y }}
className="absolute inset-0 flex items-center justify-center"
className='absolute inset-0 flex items-center justify-center'
>
{number}
</motion.span>
Expand Down
4 changes: 2 additions & 2 deletions components/formatted/formattedUser.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -113,8 +113,8 @@ export default function FormattedUser({ className, hideAvatar, id, noLinks, noTo
{ userExtendedData.user.config?.calcCurrentStreak && userExtendedData.user.config?.calcCurrentStreak > 0 &&
<div className='flex gap-1'>
<span className='font-medium'>{game.displayName} Streak</span>
<span className='gray'>{userExtendedData.user.config?.calcCurrentStreak ?? 0} days</span>
</div>
<span className='gray'>{userExtendedData.user.config?.calcCurrentStreak ?? 0} days</span>
</div>
}
{!game.isNotAGame &&
<div className='flex gap-1'>
Expand Down
1 change: 1 addition & 0 deletions components/gameLogo.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ export default function GameLogo({ gameId, id, size = 28, tooltip = false }: Gam
if (!gameId) {
return null;
}

const game = getGameFromId(gameId);
const tooltipId = `${game.id}-tooltip-${id}`;
const src = game.logo;
Expand Down
10 changes: 5 additions & 5 deletions components/level/game.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ import { PageContext } from '../../contexts/pageContext';
import Control from '../../models/control';
import Level from '../../models/db/level';
import GameLayout from './gameLayout';
import Scrubber from './scrubber';

interface SessionCheckpoint {
_id: Types.ObjectId;
Expand Down Expand Up @@ -762,20 +761,21 @@ export default function Game({
const handleScrub = useCallback((moveIndex: number) => {
setGameState(prevGameState => {
const newGameState = cloneGameState(prevGameState);

// Reset to initial state
while (newGameState.moves.length > 0) {
undo(newGameState);
}

// Apply moves up to moveIndex
for (let i = 0; i < moveIndex; i++) {
if (newGameState.redoStack.length > 0) {
const direction = newGameState.redoStack[newGameState.redoStack.length - 1];

makeMove(newGameState, direction, false);
}
}

return newGameState;
});
}, []);
Expand All @@ -794,7 +794,7 @@ export default function Game({
gameState={gameState}
level={level}
onCellClick={(x, y) => onCellClick(x, y)}
onScrub={handleScrub}
onScrub={disableScrubber ? undefined : handleScrub}
isPro={pro}
/>
</GameContext.Provider>
Expand Down
5 changes: 3 additions & 2 deletions components/level/gameLayout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ interface GameLayoutProps {
gameState: GameState;
level: EnrichedLevel;
onCellClick: (x: number, y: number) => void;
onScrub: (moveIndex: number) => void;
onScrub?: (moveIndex: number) => void;
isPro: boolean;
}

Expand Down Expand Up @@ -58,11 +58,12 @@ export default function GameLayout({ controls, disableCheckpoints, gameState, le
optimizeDom
/>
<div className='gap-2 mx-3 transition-opacity flex flex-col'>
<Scrubber
{onScrub && <Scrubber
gameState={gameState}
onScrub={onScrub}
isPro={isPro}
/>
}
<div className='gap-2 flex'>
{!disableCheckpoints && !fullScreen &&
<>
Expand Down
1 change: 1 addition & 0 deletions components/level/grid.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,7 @@ export default function Grid({ cellClassName, cellStyle, disableAnimation, gameO

// Prevent hydration mismatch by not rendering theme class until mounted
const [mounted, setMounted] = useState(false);

useEffect(() => {
setMounted(true);
}, []);
Expand Down
Loading

0 comments on commit 23367b6

Please sign in to comment.