light cycle
This commit is contained in:
151
src/components/new_ui/CyclingImage.tsx
Normal file
151
src/components/new_ui/CyclingImage.tsx
Normal file
@@ -0,0 +1,151 @@
|
||||
import { Box, Image, Button, HStack, VStack, Text } from '@chakra-ui/react'
|
||||
import { useState, useEffect, CSSProperties } from 'react'
|
||||
|
||||
interface CyclingImageProps {
|
||||
src: string
|
||||
position?: CSSProperties['position']
|
||||
w?: any
|
||||
left?: any
|
||||
top?: any
|
||||
right?: any
|
||||
bottom?: any
|
||||
cycleDuration?: number // Duration of one complete cycle in seconds
|
||||
intensity?: number // How dark/light it gets (0-1, where 1 is maximum)
|
||||
timingFunction?: string // CSS timing function
|
||||
showControls?: boolean // Show play/pause and speed controls
|
||||
autoStart?: boolean // Auto-start animation
|
||||
style?: CSSProperties // Additional CSS styles
|
||||
}
|
||||
|
||||
const CyclingImage = ({
|
||||
src,
|
||||
position = 'relative',
|
||||
w,
|
||||
left,
|
||||
top,
|
||||
right,
|
||||
bottom,
|
||||
cycleDuration = 3,
|
||||
intensity = 0.5,
|
||||
timingFunction = 'ease-in-out',
|
||||
showControls = false,
|
||||
autoStart = true,
|
||||
style = {}
|
||||
}: CyclingImageProps) => {
|
||||
const [isPlaying, setIsPlaying] = useState(autoStart)
|
||||
const [speed, setSpeed] = useState(cycleDuration)
|
||||
const [currentIntensity, setCurrentIntensity] = useState(intensity)
|
||||
|
||||
useEffect(() => {
|
||||
setSpeed(cycleDuration)
|
||||
}, [cycleDuration])
|
||||
|
||||
const togglePlayPause = () => {
|
||||
setIsPlaying(!isPlaying)
|
||||
}
|
||||
|
||||
const handleSpeedChange = (value: number) => {
|
||||
setSpeed(value)
|
||||
}
|
||||
|
||||
const handleIntensityChange = (value: number) => {
|
||||
setCurrentIntensity(value)
|
||||
}
|
||||
|
||||
// CSS keyframes animation
|
||||
const animationName = 'lightToDarkCycle'
|
||||
const animationStyle = `
|
||||
@keyframes ${animationName} {
|
||||
0% {
|
||||
filter: brightness(${1 + currentIntensity});
|
||||
}
|
||||
50% {
|
||||
filter: brightness(${1 - currentIntensity});
|
||||
}
|
||||
100% {
|
||||
filter: brightness(${1 + currentIntensity}) ;
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
return (
|
||||
<>
|
||||
<style>{animationStyle}</style>
|
||||
<Image
|
||||
src={src}
|
||||
position={position}
|
||||
w={w}
|
||||
left={left}
|
||||
top={top}
|
||||
right={right}
|
||||
bottom={bottom}
|
||||
style={{
|
||||
...style,
|
||||
animation: isPlaying ? `${animationName} ${speed}s ${timingFunction} infinite` : 'none',
|
||||
willChange: 'filter',
|
||||
transition: 'filter 0.3s ease'
|
||||
}}
|
||||
/>
|
||||
|
||||
{showControls && (
|
||||
<Box
|
||||
position="absolute"
|
||||
bottom={typeof bottom === 'object' ? '-120px' : `calc(${bottom} - 120px)`}
|
||||
left={left}
|
||||
zIndex={10}
|
||||
bg="rgba(0, 0, 0, 0.7)"
|
||||
borderRadius="md"
|
||||
p={3}
|
||||
minW="250px"
|
||||
>
|
||||
<VStack gap={3} align="stretch">
|
||||
<HStack justify="space-between">
|
||||
<Text color="white" fontSize="sm" fontWeight="bold">
|
||||
Animation Controls
|
||||
</Text>
|
||||
<Button
|
||||
size="sm"
|
||||
onClick={togglePlayPause}
|
||||
colorScheme={isPlaying ? 'red' : 'green'}
|
||||
>
|
||||
{isPlaying ? 'Pause' : 'Play'}
|
||||
</Button>
|
||||
</HStack>
|
||||
|
||||
<Box>
|
||||
<Text color="white" fontSize="xs" mb={1}>
|
||||
Speed: {speed.toFixed(1)}s
|
||||
</Text>
|
||||
<input
|
||||
type="range"
|
||||
value={speed}
|
||||
onChange={(e) => handleSpeedChange(parseFloat(e.target.value))}
|
||||
min={0.5}
|
||||
max={10}
|
||||
step={0.5}
|
||||
style={{ width: '100%', cursor: 'pointer' }}
|
||||
/>
|
||||
</Box>
|
||||
|
||||
<Box>
|
||||
<Text color="white" fontSize="xs" mb={1}>
|
||||
Intensity: {(currentIntensity * 100).toFixed(0)}%
|
||||
</Text>
|
||||
<input
|
||||
type="range"
|
||||
value={currentIntensity}
|
||||
onChange={(e) => handleIntensityChange(parseFloat(e.target.value))}
|
||||
min={0}
|
||||
max={1}
|
||||
step={0.1}
|
||||
style={{ width: '100%', cursor: 'pointer' }}
|
||||
/>
|
||||
</Box>
|
||||
</VStack>
|
||||
</Box>
|
||||
)}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export default CyclingImage
|
||||
219
src/components/new_ui/CyclingImageDemo.tsx
Normal file
219
src/components/new_ui/CyclingImageDemo.tsx
Normal file
@@ -0,0 +1,219 @@
|
||||
import { Box, Heading, VStack, Text, SimpleGrid } from '@chakra-ui/react'
|
||||
import CyclingImage from './CyclingImage'
|
||||
|
||||
/**
|
||||
* Demo component showcasing various configurations of CyclingImage
|
||||
* This demonstrates the different ways to use the cycling animation effect
|
||||
*/
|
||||
function CyclingImageDemo() {
|
||||
return (
|
||||
<Box p={8} bg="gray.50" minH="100vh">
|
||||
<VStack gap={8} align="stretch">
|
||||
<Box textAlign="center">
|
||||
<Heading size="2xl" mb={2}>CyclingImage Component Demo</Heading>
|
||||
<Text color="gray.600">
|
||||
Showcasing continuous light-to-dark color cycling animations
|
||||
</Text>
|
||||
</Box>
|
||||
|
||||
<SimpleGrid columns={{ base: 1, md: 2 }} gap={8}>
|
||||
{/* Example 1: Default Settings */}
|
||||
<Box bg="white" p={6} borderRadius="lg" shadow="md">
|
||||
<Heading size="md" mb={4}>Default Settings</Heading>
|
||||
<Text fontSize="sm" color="gray.600" mb={4}>
|
||||
3s cycle, 50% intensity, auto-start
|
||||
</Text>
|
||||
<Box position="relative" h="300px" bg="gray.100" borderRadius="md">
|
||||
<CyclingImage
|
||||
src="/images/new/threehightext.webp"
|
||||
position="absolute"
|
||||
w="200px"
|
||||
left="50%"
|
||||
top="50%"
|
||||
style={{ transform: 'translate(-50%, -50%)' } as any}
|
||||
/>
|
||||
</Box>
|
||||
</Box>
|
||||
|
||||
{/* Example 2: With Controls */}
|
||||
<Box bg="white" p={6} borderRadius="lg" shadow="md">
|
||||
<Heading size="md" mb={4}>With Interactive Controls</Heading>
|
||||
<Text fontSize="sm" color="gray.600" mb={4}>
|
||||
Adjustable speed and intensity
|
||||
</Text>
|
||||
<Box position="relative" h="300px" bg="gray.100" borderRadius="md">
|
||||
<CyclingImage
|
||||
src="/images/new/fattext.webp"
|
||||
position="absolute"
|
||||
w="200px"
|
||||
left="50%"
|
||||
top="50%"
|
||||
style={{ transform: 'translate(-50%, -50%)' } as any}
|
||||
showControls={true}
|
||||
cycleDuration={4}
|
||||
intensity={0.7}
|
||||
/>
|
||||
</Box>
|
||||
</Box>
|
||||
|
||||
{/* Example 3: Fast Cycle */}
|
||||
<Box bg="white" p={6} borderRadius="lg" shadow="md">
|
||||
<Heading size="md" mb={4}>Fast Cycle (1s)</Heading>
|
||||
<Text fontSize="sm" color="gray.600" mb={4}>
|
||||
Quick pulsing effect with high intensity
|
||||
</Text>
|
||||
<Box position="relative" h="300px" bg="gray.100" borderRadius="md">
|
||||
<CyclingImage
|
||||
src="/images/new/centerfattext.webp"
|
||||
position="absolute"
|
||||
w="200px"
|
||||
left="50%"
|
||||
top="50%"
|
||||
style={{ transform: 'translate(-50%, -50%)' } as any}
|
||||
cycleDuration={1}
|
||||
intensity={0.8}
|
||||
/>
|
||||
</Box>
|
||||
</Box>
|
||||
|
||||
{/* Example 4: Slow & Subtle */}
|
||||
<Box bg="white" p={6} borderRadius="lg" shadow="md">
|
||||
<Heading size="md" mb={4}>Slow & Subtle (8s)</Heading>
|
||||
<Text fontSize="sm" color="gray.600" mb={4}>
|
||||
Gentle breathing effect with low intensity
|
||||
</Text>
|
||||
<Box position="relative" h="300px" bg="gray.100" borderRadius="md">
|
||||
<CyclingImage
|
||||
src="/images/new/hairlosstext.webp"
|
||||
position="absolute"
|
||||
w="200px"
|
||||
left="50%"
|
||||
top="50%"
|
||||
style={{ transform: 'translate(-50%, -50%)' } as any}
|
||||
cycleDuration={8}
|
||||
intensity={0.3}
|
||||
timingFunction="linear"
|
||||
/>
|
||||
</Box>
|
||||
</Box>
|
||||
|
||||
{/* Example 5: Paused by Default */}
|
||||
<Box bg="white" p={6} borderRadius="lg" shadow="md">
|
||||
<Heading size="md" mb={4}>Paused by Default</Heading>
|
||||
<Text fontSize="sm" color="gray.600" mb={4}>
|
||||
Animation starts paused, with controls
|
||||
</Text>
|
||||
<Box position="relative" h="300px" bg="gray.100" borderRadius="md">
|
||||
<CyclingImage
|
||||
src="/images/new/threehightext.webp"
|
||||
position="absolute"
|
||||
w="200px"
|
||||
left="50%"
|
||||
top="50%"
|
||||
style={{ transform: 'translate(-50%, -50%)' } as any}
|
||||
showControls={true}
|
||||
autoStart={false}
|
||||
cycleDuration={3}
|
||||
intensity={0.6}
|
||||
/>
|
||||
</Box>
|
||||
</Box>
|
||||
|
||||
{/* Example 6: Custom Timing Function */}
|
||||
<Box bg="white" p={6} borderRadius="lg" shadow="md">
|
||||
<Heading size="md" mb={4}>Ease-In-Out-Back</Heading>
|
||||
<Text fontSize="sm" color="gray.600" mb={4}>
|
||||
Custom cubic-bezier timing function
|
||||
</Text>
|
||||
<Box position="relative" h="300px" bg="gray.100" borderRadius="md">
|
||||
<CyclingImage
|
||||
src="/images/new/fattext.webp"
|
||||
position="absolute"
|
||||
w="200px"
|
||||
left="50%"
|
||||
top="50%"
|
||||
style={{ transform: 'translate(-50%, -50%)' } as any}
|
||||
cycleDuration={5}
|
||||
intensity={0.7}
|
||||
timingFunction="cubic-bezier(0.68, -0.55, 0.265, 1.55)"
|
||||
/>
|
||||
</Box>
|
||||
</Box>
|
||||
</SimpleGrid>
|
||||
|
||||
{/* Features List */}
|
||||
<Box bg="white" p={6} borderRadius="lg" shadow="md">
|
||||
<Heading size="md" mb={4}>Component Features</Heading>
|
||||
<VStack align="start" gap={2}>
|
||||
<Text>✅ Smooth continuous light-to-dark cycling animation</Text>
|
||||
<Text>✅ Fully responsive with all Chakra UI responsive props</Text>
|
||||
<Text>✅ Maintains absolute/relative positioning</Text>
|
||||
<Text>✅ Customizable cycle duration (0.5s - 10s+)</Text>
|
||||
<Text>✅ Adjustable intensity (0-100%)</Text>
|
||||
<Text>✅ Multiple timing functions (ease, linear, cubic-bezier)</Text>
|
||||
<Text>✅ Play/Pause controls (optional)</Text>
|
||||
<Text>✅ Real-time speed adjustment</Text>
|
||||
<Text>✅ Real-time intensity adjustment</Text>
|
||||
<Text>✅ Auto-start or paused initial state</Text>
|
||||
<Text>✅ CSS-based animations (hardware accelerated)</Text>
|
||||
<Text>✅ Minimal performance impact</Text>
|
||||
</VStack>
|
||||
</Box>
|
||||
|
||||
{/* Usage Examples */}
|
||||
<Box bg="white" p={6} borderRadius="lg" shadow="md">
|
||||
<Heading size="md" mb={4}>Usage Examples</Heading>
|
||||
<VStack align="start" gap={4}>
|
||||
<Box>
|
||||
<Text fontWeight="bold" mb={2}>Basic Usage:</Text>
|
||||
<Box as="pre" bg="gray.100" p={3} borderRadius="md" fontSize="sm" overflowX="auto">
|
||||
{`<CyclingImage
|
||||
src="/path/to/image.png"
|
||||
position="absolute"
|
||||
w="200px"
|
||||
left="50px"
|
||||
top="100px"
|
||||
/>`}
|
||||
</Box>
|
||||
</Box>
|
||||
|
||||
<Box>
|
||||
<Text fontWeight="bold" mb={2}>With Custom Settings:</Text>
|
||||
<Box as="pre" bg="gray.100" p={3} borderRadius="md" fontSize="sm" overflowX="auto">
|
||||
{`<CyclingImage
|
||||
src="/path/to/image.png"
|
||||
position="absolute"
|
||||
w={{ base: "100px", lg: "200px" }}
|
||||
left={{ base: "20px", lg: "50px" }}
|
||||
top="100px"
|
||||
cycleDuration={5}
|
||||
intensity={0.7}
|
||||
timingFunction="ease-in-out"
|
||||
/>`}
|
||||
</Box>
|
||||
</Box>
|
||||
|
||||
<Box>
|
||||
<Text fontWeight="bold" mb={2}>With Interactive Controls:</Text>
|
||||
<Box as="pre" bg="gray.100" p={3} borderRadius="md" fontSize="sm" overflowX="auto">
|
||||
{`<CyclingImage
|
||||
src="/path/to/image.png"
|
||||
position="absolute"
|
||||
w="200px"
|
||||
left="50px"
|
||||
top="100px"
|
||||
showControls={true}
|
||||
autoStart={false}
|
||||
cycleDuration={3}
|
||||
intensity={0.6}
|
||||
/>`}
|
||||
</Box>
|
||||
</Box>
|
||||
</VStack>
|
||||
</Box>
|
||||
</VStack>
|
||||
</Box>
|
||||
)
|
||||
}
|
||||
|
||||
export default CyclingImageDemo
|
||||
@@ -1,4 +1,5 @@
|
||||
import { Box, Image, Stack, } from '@chakra-ui/react'
|
||||
import CyclingImage from './CyclingImage'
|
||||
|
||||
function Hero1() {
|
||||
const bigWarningSize = { base: "80px", sm: "100px", md: "120px", lg: "9vw", xl: "8vw" };
|
||||
@@ -32,54 +33,78 @@ function Hero1() {
|
||||
maxW={{ base: "40px", sm: "50px", md: "60px", lg: "70%", xl: "70%" }}
|
||||
bottom={'10px'} />
|
||||
{/* signs */}
|
||||
<Image src="/images/new/bigwarning.webp"
|
||||
<CyclingImage
|
||||
src="/images/new/bigwarning.webp"
|
||||
position={'absolute'}
|
||||
w={bigWarningSize}
|
||||
left={'20vw'}
|
||||
top={'5vw'}
|
||||
cycleDuration={3}
|
||||
intensity={0.1}
|
||||
/>
|
||||
<Image src="/images/new/bigwarning.webp"
|
||||
<CyclingImage
|
||||
src="/images/new/bigwarning.webp"
|
||||
position={'absolute'}
|
||||
w={smallWarningSize}
|
||||
left={'25vw'}
|
||||
bottom={'18vw'}
|
||||
cycleDuration={3}
|
||||
intensity={0.1}
|
||||
/>
|
||||
<Image src="/images/new/bigwarning.webp"
|
||||
<CyclingImage
|
||||
src="/images/new/bigwarning.webp"
|
||||
position={'absolute'}
|
||||
w={bigWarningSize}
|
||||
right={'20vw'}
|
||||
top={'25vw'}
|
||||
cycleDuration={3}
|
||||
intensity={0.1}
|
||||
/>
|
||||
<Image src="/images/new/bigwarning.webp"
|
||||
<CyclingImage
|
||||
src="/images/new/bigwarning.webp"
|
||||
position={'absolute'}
|
||||
w={bigWarningSize}
|
||||
right={'18vw'}
|
||||
top={'10vw'}
|
||||
cycleDuration={3}
|
||||
intensity={0.1}
|
||||
/>
|
||||
{/* Warning Texts */}
|
||||
<Image src="/images/new/threehightext.webp"
|
||||
<CyclingImage
|
||||
src="/images/new/threehightext.webp"
|
||||
position={'absolute'}
|
||||
w={{ base: "100px", sm: "120px", md: "150px", lg: "11vw", xl: "10vw" }}
|
||||
left={{ base: "20px", sm: "30px", md: "40px", lg: "30vw", xl: "37vw" }}
|
||||
top={{ base: "3vw", sm: "3vw", md: "3vw", lg: "7vw", xl: "3vw" }}
|
||||
cycleDuration={3}
|
||||
intensity={0.1}
|
||||
/>
|
||||
<Image src="/images/new/fattext.webp"
|
||||
<CyclingImage
|
||||
src="/images/new/fattext.webp"
|
||||
position={'absolute'}
|
||||
w={{ base: "100px", sm: "120px", md: "150px", lg: "10vw", xl: "9vw" }}
|
||||
left={{ base: "25vw", sm: "25vw", md: "25vw", lg: "18vw", xl: "25vw" }}
|
||||
top={{ base: "14vw", sm: "14vw", md: "14vw", lg: "20vw", xl: "14vw" }}
|
||||
cycleDuration={3}
|
||||
intensity={0.1}
|
||||
/>
|
||||
<Image src="/images/new/centerfattext.webp"
|
||||
<CyclingImage
|
||||
src="/images/new/centerfattext.webp"
|
||||
position={'absolute'}
|
||||
w={{ base: "100px", sm: "120px", md: "150px", lg: "14vw", xl: "13vw" }}
|
||||
right={{ base: "35vw", sm: "35vw", md: "35vw", lg: "34vw", xl: "35vw" }}
|
||||
top={{ base: "5vw", sm: "5vw", md: "5vw", lg: "7vw", xl: "5vw" }}
|
||||
cycleDuration={3}
|
||||
intensity={0.1}
|
||||
/>
|
||||
<Image src="/images/new/hairlosstext.webp"
|
||||
<CyclingImage
|
||||
src="/images/new/hairlosstext.webp"
|
||||
position={'absolute'}
|
||||
w={{ base: "100px", sm: "120px", md: "150px", lg: "8vw", xl: "7vw" }}
|
||||
right={{ base: "26vw", sm: "26vw", md: "26vw", lg: "26vw", xl: "26vw" }}
|
||||
top={{ base: "12vw", sm: "12vw", md: "12vw", lg: "18vw", xl: "12vw" }}
|
||||
cycleDuration={3}
|
||||
intensity={0.1}
|
||||
/>
|
||||
</Box>
|
||||
</Stack>
|
||||
|
||||
Reference in New Issue
Block a user