update info and oilinfo, added animation to the "click to see recipe" section, and added alt and title attributes to images for better SEO and accessibility
This commit is contained in:
@@ -5,6 +5,7 @@ import { motion } from 'framer-motion'
|
|||||||
const MotionImage = motion.create(Image)
|
const MotionImage = motion.create(Image)
|
||||||
const MotionFlex = motion.create(Flex)
|
const MotionFlex = motion.create(Flex)
|
||||||
const MotionBox = motion.create(Box)
|
const MotionBox = motion.create(Box)
|
||||||
|
const MotionDiv = motion.div
|
||||||
|
|
||||||
interface InfoData {
|
interface InfoData {
|
||||||
id: number
|
id: number
|
||||||
@@ -101,12 +102,20 @@ function Info() {
|
|||||||
transition={{ duration: 0.8, delay: 0.2, ease: "easeOut" }}
|
transition={{ duration: 0.8, delay: 0.2, ease: "easeOut" }}
|
||||||
>
|
>
|
||||||
{infoData.map((info) => (
|
{infoData.map((info) => (
|
||||||
<Box
|
<MotionDiv
|
||||||
key={info.id}
|
key={info.id}
|
||||||
|
whileHover={{ scale: 1.07 }}
|
||||||
|
whileTap={{ scale: 0.95 }}
|
||||||
|
animate={selectedInfo !== info.id ? { opacity: [1, 0.45, 1] } : { opacity: 1 }}
|
||||||
|
transition={selectedInfo !== info.id ? {
|
||||||
|
opacity: { duration: 1.6, repeat: Infinity, ease: "easeInOut", delay: info.id * 0.2 }
|
||||||
|
} : { type: "spring", stiffness: 300, damping: 20 }}
|
||||||
|
style={{ cursor: 'pointer' }}
|
||||||
|
onClick={() => setSelectedInfo(info.id)}
|
||||||
|
>
|
||||||
|
<Box
|
||||||
w={{ base: '20vw', sm: '110px', md: '150px', lg: '150px', xl: '150px' }}
|
w={{ base: '20vw', sm: '110px', md: '150px', lg: '150px', xl: '150px' }}
|
||||||
h={{ base: '15vw', sm: '70px', md: '90px', lg: '90px', xl: '90px' }}
|
h={{ base: '15vw', sm: '70px', md: '90px', lg: '90px', xl: '90px' }}
|
||||||
cursor="pointer"
|
|
||||||
onClick={() => setSelectedInfo(info.id)}
|
|
||||||
bg={selectedInfo === info.id ? '#3D6741' : '#BCBCBC'}
|
bg={selectedInfo === info.id ? '#3D6741' : '#BCBCBC'}
|
||||||
border={selectedInfo === info.id ? { base: "1px solid #99BF35", sm: "1px solid #99BF35", md: "4px solid #99BF35", lg: "4px solid #99BF35", xl: "4px solid #99BF35" } : "none"}
|
border={selectedInfo === info.id ? { base: "1px solid #99BF35", sm: "1px solid #99BF35", md: "4px solid #99BF35", lg: "4px solid #99BF35", xl: "4px solid #99BF35" } : "none"}
|
||||||
borderRadius={{ base: '15px', sm: '15px', md: '18px', lg: '20px', xl: '20px' }}
|
borderRadius={{ base: '15px', sm: '15px', md: '18px', lg: '20px', xl: '20px' }}
|
||||||
@@ -126,6 +135,7 @@ function Info() {
|
|||||||
>
|
>
|
||||||
{info.title}
|
{info.title}
|
||||||
</Box>
|
</Box>
|
||||||
|
</MotionDiv>
|
||||||
))}
|
))}
|
||||||
</MotionFlex>
|
</MotionFlex>
|
||||||
|
|
||||||
|
|||||||
@@ -1,11 +1,13 @@
|
|||||||
import { Box, Image, SimpleGrid } from '@chakra-ui/react'
|
import { Box, Image, SimpleGrid, Text } from '@chakra-ui/react'
|
||||||
import { motion, useInView } from 'framer-motion'
|
import { motion, useInView } from 'framer-motion'
|
||||||
import { useRef } from 'react'
|
import { useRef } from 'react'
|
||||||
import {useRouterState } from '@tanstack/react-router'
|
import { useRouterState } from '@tanstack/react-router'
|
||||||
|
|
||||||
const MotionImage = motion.create(Image)
|
const MotionImage = motion.create(Image)
|
||||||
const MotionBox = motion.create(Box)
|
const MotionBox = motion.create(Box)
|
||||||
|
const MotionText = motion.create(Text)
|
||||||
const MotionSimpleGrid = motion.create(SimpleGrid)
|
const MotionSimpleGrid = motion.create(SimpleGrid)
|
||||||
|
const MotionDiv = motion.div
|
||||||
|
|
||||||
function OilInfo() {
|
function OilInfo() {
|
||||||
const mainRef = useRef(null);
|
const mainRef = useRef(null);
|
||||||
@@ -75,21 +77,44 @@ function OilInfo() {
|
|||||||
|
|
||||||
<MotionBox
|
<MotionBox
|
||||||
display="flex"
|
display="flex"
|
||||||
|
flexDirection="column"
|
||||||
justifyContent="center"
|
justifyContent="center"
|
||||||
alignItems="center"
|
alignItems="center"
|
||||||
|
gap={3}
|
||||||
initial={{ opacity: 0, x: 50 }}
|
initial={{ opacity: 0, x: 50 }}
|
||||||
animate={isMainInView ? { opacity: 1, x: 0 } : { opacity: 0, x: 50 }}
|
animate={isMainInView ? { opacity: 1, x: 0 } : { opacity: 0, x: 50 }}
|
||||||
transition={{ duration: 0.6, delay: 0.8, ease: "easeOut" }}
|
transition={{ duration: 0.6, delay: 0.8, ease: "easeOut" }}
|
||||||
|
cursor="pointer"
|
||||||
|
onClick={handleRecipeNavigation}
|
||||||
|
whileHover={{ scale: 1.04 }}
|
||||||
|
whileTap={{ scale: 0.97 }}
|
||||||
>
|
>
|
||||||
|
<MotionDiv
|
||||||
|
animate={{ y: [0, 6, 0] }}
|
||||||
|
transition={{ duration: 1.4, repeat: Infinity, ease: "easeInOut", delay: 1.3 }}
|
||||||
|
style={{ display: 'flex', flexDirection: 'column', alignItems: 'center' }}
|
||||||
|
>
|
||||||
|
<MotionText
|
||||||
|
fontSize={{ base: 'sm', md: 'md' }}
|
||||||
|
color="#5a8c3a"
|
||||||
|
fontWeight={700}
|
||||||
|
fontFamily="'MElleHK', sans-serif"
|
||||||
|
letterSpacing="0.05em"
|
||||||
|
userSelect="none"
|
||||||
|
>
|
||||||
|
點擊了解更多食譜
|
||||||
|
</MotionText>
|
||||||
|
<Text fontSize="xl" color="#5a8c3a" lineHeight="1" userSelect="none">▼</Text>
|
||||||
|
</MotionDiv>
|
||||||
<MotionImage
|
<MotionImage
|
||||||
src='/images/new/buttons.webp'
|
src='/images/new/buttons.webp'
|
||||||
w={{ base: '100%', sm: '100%', md: '90%' }}
|
w={{ base: '100%', sm: '100%', md: '90%' }}
|
||||||
initial={{ opacity: 0, scale: 0.8 }}
|
initial={{ opacity: 0, scale: 0.8 }}
|
||||||
animate={isMainInView ? { opacity: 1, scale: 1 } : { opacity: 0, scale: 0.8 }}
|
animate={isMainInView ? { opacity: 1, scale: 1 } : { opacity: 0, scale: 0.8 }}
|
||||||
transition={{ duration: 0.5, delay: 1.0, ease: "easeOut" }}
|
transition={{ duration: 0.5, delay: 1.0, ease: "easeOut" }}
|
||||||
cursor="pointer"
|
pointerEvents="none"
|
||||||
onClick={handleRecipeNavigation}
|
|
||||||
/>
|
/>
|
||||||
|
|
||||||
</MotionBox>
|
</MotionBox>
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user