Files
healthy_oil/src/components/new_ui/truth.tsx
2025-11-02 20:36:37 +08:00

277 lines
11 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { Box, HStack, Image, Stack, Text, Link, Flex } from '@chakra-ui/react'
import { motion, useInView } from 'framer-motion'
import { useEffect, useRef } from 'react';
const MotionBox = motion.create(Box)
const MotionStack = motion.create(Stack)
const MotionHStack = motion.create(HStack)
const MotionText = motion.create(Text)
const MotionImage = motion.create(Image)
const MotionFlex = motion.create(Flex)
const truthItems = [
{
id: 1,
image: '/images/new/ans_step1.webp',
desc: '**出街食飯死亡率大增近五成!**即睇營養師拆解「油」之迷思。'
},
{
id: 2,
image: '/images/new/ans_step2.webp',
desc: '**三高年輕化警號!**營養師揭港人隱形致肥陷阱!一支好油決定血管命運。'
},
{
id: 3,
image: '/images/new/ans_step3.webp',
desc: '**三高人士同樣啱食!**營養師教你自製健康手撕蔥油雞髀。'
},
{
id: 4,
image: '/images/new/ans_step4.webp',
desc: '**BBC認證豬油是健康食材**混合食油等於垃圾油?純正食油一定最好? 各種食油迷思可能正在誤導你,由營養學家為你拆解多數人不知道的真相!'
},
]
const renderDescription = (text: string) => {
const parts = text.split(/(\*\*.*?\*\*)/)
return parts.map((part, index) => {
if (part.startsWith('**') && part.endsWith('**')) {
return (
<Text as="span" key={index} fontWeight={800}>
{part.slice(2, -2)}
</Text>
)
}
return <Text as="span" key={index}>{part}</Text>
})
}
function Truth() {
const shopImages = [
{
image: '/images/pp.webp',
link: 'https://www.pns.hk/en/all-brands/b/112546/lion-globe',
},
{
image: '/images/we.webp',
link: 'https://www.wellcome.com.hk/zh-hant/search?keyword=%E7%8D%85%E7%90%83%E5%98%9C&page=1',
},
{
image: '/images/hk.webp',
link: 'https://www.hktvmall.com/hktv/zh/main/%E7%8D%85%E7%90%83%E5%98%9C%E6%97%97%E8%89%A6%E5%BA%97/s/H1261001',
},
]
const fbContainerRef = useRef<HTMLDivElement>(null);
const mainRef = useRef<HTMLDivElement>(null);
const titleRef = useRef<HTMLDivElement>(null);
const isMainInView = useInView(mainRef, { once: true });
const isTitleInView = useInView(titleRef, { once: true });
// Load Facebook SDK and initialize the plugin
useEffect(() => {
// Add Facebook SDK if it doesn't exist
if (!document.getElementById('facebook-jssdk')) {
const script = document.createElement('script');
script.id = 'facebook-jssdk';
script.src = 'https://connect.facebook.net/en_US/sdk.js#xfbml=1&version=v18.0';
script.async = true;
script.defer = true;
document.body.appendChild(script);
}
// Parse XFBML when SDK is loaded
const handleSDKLoad = () => {
if ((window as any).FB && fbContainerRef.current) {
(window as any).FB.XFBML.parse(fbContainerRef.current);
}
};
// Check if FB is already loaded
if ((window as any).FB) {
handleSDKLoad();
} else {
// Listen for SDK load
(window as any).fbAsyncInit = handleSDKLoad;
}
return () => {
// Clean up
(window as any).fbAsyncInit = undefined;
};
}, []);
return (
<MotionBox
id="truth"
ref={mainRef}
position="relative"
w="100%"
bgColor="white"
zIndex={3}
overflow="hidden"
justifyItems={'center'}
initial={{ opacity: 0 }}
animate={isMainInView ? { opacity: 1 } : { opacity: 0 }}
transition={{ duration: 0.5, ease: "easeOut" }}
>
<MotionText
className='font-melle font-xbold'
color='#458B02'
mt={{ base: 10, sm: 10, md: 10, lg: 10, xl: 10 }}
fontSize={{ base: '2xl', sm: '3xl', md: '5xl', lg: '5xl', xl: '5xl' }}
textAlign={'center'}
initial={{ opacity: 0, y: -30 }}
animate={isMainInView ? { opacity: 1, y: 0 } : { opacity: 0, y: -30 }}
transition={{ duration: 0.5, delay: 0.1, ease: "easeOut" }}
>
</MotionText>
<MotionStack
mt={{ base: 3, sm: -5, md: -5, lg: -5, xl: -5 }}
columns={{ base: 1, sm: 1, md: 2 }}
p={{ base: 5, sm: 12, md: 20 }}
w={{ base: '100%', sm: '100%', md: '80%', lg: '80%', xl: '60%' }}
h={'auto'}
gap={{ base: 7, md: 7 }}
justifyItems={'center'}
alignItems={'flex-start'}
initial={{ opacity: 0, y: 50 }}
animate={isMainInView ? { opacity: 1, y: 0 } : { opacity: 0, y: 50 }}
transition={{ duration: 0.5, delay: 0.2, ease: "easeOut" }}
>
{truthItems.map((item, index) => (
<MotionHStack
key={item.id}
gap={{ base: 4, md: 5 }}
justifyItems={'flex-start'}
alignItems={'flex-start'}
initial={{ opacity: 0, x: -30 }}
animate={isMainInView ? { opacity: 1, x: 0 } : { opacity: 0, x: -30 }}
transition={{ duration: 0.5, delay: 0.3 + index * 0.1, ease: "easeOut" }}
>
<MotionImage
src={item.image}
alt={`truth item ${item.id}`}
w={{ base: '70px', sm: '70px', md: '70px', lg: '70px', xl: '70px' }}
initial={{ opacity: 0, scale: 0.8 }}
animate={isMainInView ? { opacity: 1, scale: 1 } : { opacity: 0, scale: 0.8 }}
transition={{ duration: 0.4, delay: 0.4 + index * 0.1, ease: "easeOut" }}
/>
<MotionText
className="font-noto-sans font-regular"
color='#458B02'
fontSize={{ base: 'lg', sm: 'lg', md: 'lg', lg: 'lg', xl: 'lg' }}
initial={{ opacity: 0, y: 20 }}
animate={isMainInView ? { opacity: 1, y: 0 } : { opacity: 0, y: 20 }}
transition={{ duration: 0.5, delay: 0.5 + index * 0.1, ease: "easeOut" }}
>
{renderDescription(item.desc)}
</MotionText>
</MotionHStack>
))}
</MotionStack>
<motion.div
ref={titleRef}
initial={{ opacity: 0, y: 50 }}
animate={isTitleInView ? { opacity: 1, y: 0 } : { opacity: 0, y: 50 }}
transition={{ duration: 0.7 }}
>
<MotionStack
w='100%'
justify={'center'}
align={'center'}
initial={{ opacity: 0, scale: 0.9 }}
animate={isTitleInView ? { opacity: 1, scale: 1 } : { opacity: 0, scale: 0.9 }}
transition={{ duration: 0.5, delay: 0.2, ease: "easeOut" }}
>
<MotionText
className='font-melle font-xbold'
color={"#458B02"}
fontSize={{ base: '2xl', sm: '3xl', md: '5xl', lg: '5xl', xl: '5xl' }}
initial={{ opacity: 0 }}
animate={isTitleInView ? { opacity: 1 } : { opacity: 0 }}
transition={{ duration: 0.4, delay: 0.3, ease: "easeOut" }}
>
</MotionText>
</MotionStack>
</motion.div>
<MotionFlex
gap={12}
direction={{ base: 'column', sm: 'column', md: 'row' }}
justify="center"
mt={5}
align={'flex-end'}
initial={{ opacity: 0, y: 30 }}
animate={isTitleInView ? { opacity: 1, y: 0 } : { opacity: 0, y: 30 }}
transition={{ duration: 0.8, delay: 0.2, ease: "easeOut" }}
>
{shopImages.map((image, index) => (
<motion.div
key={index}
initial={{ opacity: 0, scale: 0.8 }}
animate={isTitleInView ? { opacity: 1, scale: 1 } : { opacity: 0, scale: 0.8 }}
transition={{ duration: 0.5, delay: 0.5 + index * 0.2, ease: "easeOut" }}
>
<MotionStack
w='250px'
justify={'flex-end'}
initial={{ opacity: 0, y: 20 }}
animate={isTitleInView ? { opacity: 1, y: 0 } : { opacity: 0, y: 20 }}
transition={{ duration: 0.4, delay: 0.6 + index * 0.2, ease: "easeOut" }}
>
<Link href={image.link}>
<MotionImage src={image.image} cursor="pointer" fit={'contain'}
loading="lazy"
initial={{ opacity: 0, scale: 0.9 }}
animate={isTitleInView ? { opacity: 1, scale: 1 } : { opacity: 0, scale: 0.9 }}
transition={{ duration: 0.3, delay: 0.7 + index * 0.2, ease: "easeOut" }}
/>
</Link>
</MotionStack>
</motion.div>
))}
</MotionFlex>
<MotionStack
my={15}
ml={2}
mt={10}
initial={{ opacity: 0, scale: 0.9 }}
animate={isTitleInView ? { opacity: 1, scale: 1 } : { opacity: 0, scale: 0.9 }}
transition={{ duration: 0.6, delay: 0.6, ease: "easeOut" }}
>
<Link href={"https://www.facebook.com/profile.php?id=100064320806613"}
_focus={{ outline: 'none', boxShadow: 'none' }}
_active={{ outline: 'none', boxShadow: 'none' }}>
<MotionImage
src={'/images/facebook.webp'}
alt="salespoint"
w={"400px"}
loading='lazy'
initial={{ opacity: 0, y: 20 }}
animate={isTitleInView ? { opacity: 1, y: 0 } : { opacity: 0, y: 20 }}
transition={{ duration: 0.5, delay: 0.6, ease: "easeOut" }}
/>
</Link>
</MotionStack>
</MotionBox>
)
}
export default Truth;