Commit 98e9ba05 by HoMeTown

feat: 工具

parent a98cce0d
This diff was suppressed by a .gitattributes entry.
This diff was suppressed by a .gitattributes entry.
This diff was suppressed by a .gitattributes entry.
'use client'
import { useState } from 'react'
import { cn } from '@/lib/utils'
interface ShineBorderProps {
borderRadius?: number
borderWidth?: number
duration?: number
className?: string
children: React.ReactNode
}
/**
* @name Shine Border
* @description It is an animated background border effect component with easy to use and configurable props.
* @param borderRadius defines the radius of the border.
* @param borderWidth defines the width of the border.
* @param duration defines the animation duration to be applied on the shining border
* @param color a string or string array to define border color.
* @param className defines the class name to be applied to the component
* @param children contains react node elements.
*/
export default function ShineBorder({
borderRadius = 8,
borderWidth = 1,
duration = 14,
className,
children,
}: ShineBorderProps) {
const color = ['#B4F4FF', '#CBC2FF', '#29B6FD']
const [isIn, setIsIn] = useState(false)
return (
<div
onMouseEnter={() => setIsIn(true)}
onMouseLeave={() => setIsIn(false)}
style={
{
'--border-radius': `${borderRadius}px`,
} as React.CSSProperties
}
className={cn(
'relative grid min-h-[60px] w-fit min-w-[300px] place-items-center rounded-[--border-radius] bg-white p-3 text-black dark:bg-black dark:text-white',
className,
)}
>
<div
style={
{
'opacity': isIn ? 1 : 0,
'transition': 'opacity 0.7s',
'--border-width': `${borderWidth}px`,
'--border-radius': `${borderRadius}px`,
'--shine-pulse-duration': `${duration}s`,
'--mask-linear-gradient': `linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0)`,
'--background-radial-gradient': `radial-gradient(transparent,transparent, ${Array.isArray(color) ? color.join(',') : color},transparent,transparent)`,
} as React.CSSProperties
}
className={`before:bg-shine-size before:absolute before:inset-0 before:aspect-square before:size-full before:rounded-[--border-radius] before:p-[--border-width] before:will-change-[background-position] before:content-[""] before:![-webkit-mask-composite:xor] before:![mask-composite:exclude] before:[background-image:--background-radial-gradient] before:[background-size:300%_300%] before:[mask:--mask-linear-gradient] motion-safe:before:animate-[shine-pulse_var(--shine-pulse-duration)_infinite_linear]`}
>
</div>
{children}
</div>
)
}
......@@ -3,6 +3,11 @@ import { motion } from 'framer-motion'
import styles from './Tools.module.less'
import { Slogan } from './components/Slogan/Slogan'
import { GradientBackground } from '@/components/GradientBackground'
import ToolsNav from '@/assets/tools-nav.png'
import ToolsCalculation from '@/assets/tools-calculation.png'
import ToolsDetail from '@/assets/tools-detail.png'
import useToast from '@/hooks/useToast'
import ShineBorder from '@/components/ShineBorder'
function getAnimationProps(delay: number) {
return {
......@@ -31,6 +36,17 @@ function getAnimationProps(delay: number) {
}
export const Tools: React.FC = () => {
const tools = [
{ name: '产品试算', desc: '支持保险产品保费测算', icon: ToolsCalculation },
{ name: '净值查询', desc: '支持商养产品净值查询', icon: ToolsDetail },
{ name: '商养收益计算器', desc: '查看商养产品详情信息', icon: ToolsNav },
]
const showToast = useToast()
const handleClickToolItem = () => {
showToast('策马加鞭紧急开发中!', 'default', {
icon: '🚧',
})
}
return (
<div className={styles.toolsPage}>
<GradientBackground />
......@@ -46,9 +62,20 @@ export const Tools: React.FC = () => {
<div>
<div className="max-w-[1000px] flex mx-auto mt-[64px] text-18px text-[#5AA9D0] font-light">全部工具</div>
<div className="max-w-[1000px] mx-auto gap-[20px] flex flex-col flex-wrap mt-[22px] sm:flex-row">
<motion.div className=" rounded-[20px] bg-[#fff] flex-1 h-[100px] p-[24px]" {...getAnimationProps(1)}>工具1</motion.div>
<motion.div className=" rounded-[20px] bg-[#fff] flex-1 h-[100px] p-[24px]" {...getAnimationProps(2)}>工具2</motion.div>
<motion.div className=" rounded-[20px] bg-[#fff] flex-1 h-[100px] p-[24px]" {...getAnimationProps(3)}>工具3</motion.div>
{tools.map((item, index) => (
<motion.div key={index} onClick={handleClickToolItem} {...getAnimationProps(index + 1)}>
<ShineBorder
borderRadius={20}
className="rounded-[20px] bg-[#fff] flex-1 h-[100px] p-[24px] flex items-center cursor-pointer"
>
<img className="w-[52px]" src={item.icon} alt="" />
<div className="ml-[20px]">
<h3 className="font-bold">{item.name}</h3>
<p className="text-[14px] text-[#27353CCC] mt-[3px]">{item.desc}</p>
</div>
</ShineBorder>
</motion.div>
)) }
</div>
</div>
</div>
......
......@@ -14,7 +14,21 @@ module.exports = {
md: '1090px',
lg: '1536px',
},
extend: {},
extend: {
keyframes: {
'shine-pulse': {
'0%': {
'background-position': '0% 0%',
},
'50%': {
'background-position': '100% 100%',
},
'to': {
'background-position': '0% 0%',
},
},
},
},
},
darkMode: 'class',
plugins: [
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment