315 lines
14 KiB
TypeScript
315 lines
14 KiB
TypeScript
import { Box, HStack, Image, Stack, Text, Link, Flex } from '@chakra-ui/react'
|
||
import { motion, useInView } from 'framer-motion'
|
||
import { useEffect, useRef, useState } 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: '**出街食飯死亡率大增近五成!**即睇營養師拆解「油」之迷思',
|
||
url: 'https://www.hk01.com/%E5%81%A5%E5%BA%B7Easy/60225791/%E5%87%BA%E8%A1%97%E9%A3%9F%E9%A3%AF%E6%AD%BB%E4%BA%A1%E7%8E%87%E5%A4%A7%E5%A2%9E%E8%BF%91%E4%BA%94%E6%88%90-%E5%8D%B3%E7%9D%87%E7%87%9F%E9%A4%8A%E5%B8%AB%E6%8B%86%E8%A7%A3-%E6%B2%B9-%E4%B9%8B%E8%BF%B7%E6%80%9D'
|
||
},
|
||
{
|
||
id: 2,
|
||
image: '/images/new/ans_step2.webp',
|
||
desc: '**三高年輕化警號!**營養師揭港人隱形致肥陷阱!一支好油決定血管命運',
|
||
url: 'https://urbanlifehk.com/article/128710/%E4%B8%89%E9%AB%98-%E8%87%B4%E8%82%A5'
|
||
},
|
||
{
|
||
id: 3,
|
||
image: '/images/new/ans_step3.webp',
|
||
desc: '**三高人士同樣啱食!**營養師教你自製健康手撕蔥油雞髀',
|
||
url: 'https://cook1cook.com/posts/29979?srsltid=AfmBOoqWHlmsj4Sk76Hkag0Mp7lMIM_gbFbavrm-q62FwT-GVM4F4lVN'
|
||
},
|
||
{
|
||
id: 4,
|
||
image: '/images/new/ans_step4.webp',
|
||
desc: '**BBC認證豬油是健康食材?**混合食油等於垃圾油?純正食油一定最好? 各種食油迷思可能正在誤導你,由營養學家為你拆解多數人不知道的真相!',
|
||
url: 'https://www.orientalsunday.hk/%E7%94%9F%E6%B4%BB%E5%81%A5%E5%BA%B7/bbc%E8%AA%8D%E8%AD%89-%E5%81%A5%E5%BA%B7-%E6%B7%B7%E5%90%88%E9%A3%9F%E6%B2%B9-%E5%9E%83%E5%9C%BE%E6%B2%B9-1635198/'
|
||
},
|
||
]
|
||
|
||
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/zh-hk/%E7%87%9F%E8%90%83%E8%AD%B7%E5%BF%83%E6%B2%B9/p/BP_401649',
|
||
},
|
||
{
|
||
image: '/images/we.webp',
|
||
link: 'https://www.wellcome.com.hk/zh-hant/p/%E7%8D%85%E7%90%83%E5%98%9C%E7%87%9F%E8%90%83%E8%AD%B7%E5%BF%83%E6%B2%B9%201%E5%85%AC%E5%8D%87/i/101341721.html?srsltid=AfmBOorpxphAzws9TIkKJW5xr1pYOaUOL5kHbsgRjYqwQeaOhq1cPQuO',
|
||
},
|
||
{
|
||
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/%E8%B6%85%E7%B4%9A%E5%B7%BF%E5%A0%B4/%E8%B6%85%E7%B4%9A%E5%B8%82%E5%A0%B4/%E7%B1%B3-%E9%A3%9F%E6%B2%B9/%E9%A3%9F%E6%B2%B9/%E5%85%B6%E4%BB%96/%E7%87%9F%E8%90%83%E8%AD%B7%E5%BF%83%E6%B2%B9%E9%97%9C%E6%B3%A8%E4%B8%89%E9%AB%98%E5%BF%83%E8%A1%80%E7%AE%A1%E5%81%A5%E5%BA%B7%E9%BB%83%E9%87%91%E6%AF%94%E4%BE%8B%E8%84%82%E8%82%AA%E9%85%B8%E5%B0%88%E6%A5%AD%E5%81%A5%E5%BA%B7%E9%85%8D%E6%96%B9%E9%99%8D%E5%A3%9E%E8%86%BD%E5%9B%BA%E9%86%87%E9%9B%B6%E5%8F%8D%E5%BC%8F%E8%84%82%E8%82%AA%E7%85%99%E9%BB%9E%E9%AB%98%E7%85%8E%E7%82%92%E7%85%AE%E7%82%B8/p/H0888001_S_10159486',
|
||
},
|
||
]
|
||
|
||
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 });
|
||
const [hoveredIndex, setHoveredIndex] = useState<number | null>(null);
|
||
|
||
|
||
// 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" }}
|
||
>
|
||
<h2 style={{ position: 'absolute', width: '1px', height: '1px', padding: 0, margin: '-1px', overflow: 'hidden', clip: 'rect(0,0,0,0)', whiteSpace: 'nowrap', border: 0 }}>
|
||
食用油健康真相與獅球嘜購買連結 — 百佳、惠康、HKTVmall有售
|
||
</h2>
|
||
|
||
<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
|
||
mx="auto"
|
||
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" }}
|
||
cursor="pointer"
|
||
onClick={() => {
|
||
const url = item.url;
|
||
if (url) {
|
||
window.open(url, '_blank');
|
||
}
|
||
}}
|
||
onHoverStart={() => setHoveredIndex(index)}
|
||
onHoverEnd={() => setHoveredIndex(null)}
|
||
>
|
||
<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 ? (hoveredIndex === index ?
|
||
{ opacity: 1, scale: 1.2 } :
|
||
{
|
||
opacity: 1,
|
||
scale: [1, 1.05, 1],
|
||
transition: {
|
||
scale: {
|
||
duration: 2.5,
|
||
ease: "easeInOut",
|
||
repeat: Infinity,
|
||
repeatType: "loop"
|
||
}
|
||
}
|
||
}
|
||
) : { opacity: 0, scale: 0.7 }}
|
||
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%'
|
||
mt={5}
|
||
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' }}
|
||
mt={5}
|
||
w="100%"
|
||
justify={{ base: 'center', sm: 'center', md: 'center' }}
|
||
align={{ base: 'center', sm: 'center', md: 'center' }}
|
||
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" }}
|
||
style={{ display: 'flex', justifyContent: 'center' }}
|
||
>
|
||
<MotionStack
|
||
w={{ base: '250px', sm: '250px', md: '220px', lg: '250px', xl: '250px' }}
|
||
justify={'center'}
|
||
align={'center'}
|
||
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} style={{ display: 'flex', justifyContent: 'center' }}>
|
||
<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
|
||
position="relative"
|
||
left="50%"
|
||
src={'/images/fb.webp'}
|
||
alt="salespoint"
|
||
w={"400px"}
|
||
loading='lazy'
|
||
initial={{ opacity: 0, y: 20, x: '-50%' }}
|
||
animate={isTitleInView ? { opacity: 1, y: 0, x: '-50%' } : { opacity: 0, y: 20, x: '-50%' }}
|
||
transition={{ duration: 0.5, delay: 0.6, ease: "easeOut" }}
|
||
/>
|
||
</Link>
|
||
</MotionStack>
|
||
|
||
</MotionBox>
|
||
|
||
|
||
)
|
||
}
|
||
|
||
export default Truth; |