mirror of
https://github.com/d0zingcat/NotionNext.git
synced 2026-06-04 15:10:23 +00:00
Merge branch 'main' into original-fix
This commit is contained in:
@@ -1,195 +1,179 @@
|
||||
/* eslint-disable @next/next/no-img-element */
|
||||
/* eslint-disable react/no-unescaped-entities */
|
||||
import { siteConfig } from '@/lib/config'
|
||||
import CONFIG from '../config'
|
||||
import Link from 'next/link'
|
||||
|
||||
/**
|
||||
* 首页的关于模块
|
||||
*/
|
||||
export const About = () => {
|
||||
return <>
|
||||
{/* <!-- ====== About Section Start --> */}
|
||||
<section
|
||||
id="about"
|
||||
className="bg-gray-1 pb-8 pt-20 dark:bg-dark-2 lg:pb-[70px] lg:pt-[120px]"
|
||||
>
|
||||
<div className="container">
|
||||
<div className="wow fadeInUp" data-wow-delay=".2s">
|
||||
<div className="-mx-4 flex flex-wrap items-center">
|
||||
return (
|
||||
<>
|
||||
{/* <!-- ====== About Section Start --> */}
|
||||
<section
|
||||
id='about'
|
||||
className='bg-gray-1 pb-8 pt-20 dark:bg-dark-2 lg:pb-[70px] lg:pt-[120px]'>
|
||||
<div className='container'>
|
||||
<div className='wow fadeInUp' data-wow-delay='.2s'>
|
||||
<div className='-mx-4 flex flex-wrap items-center'>
|
||||
{/* 左侧的文字说明板块 */}
|
||||
<div className='w-full px-4 lg:w-1/2'>
|
||||
<div className='mb-12 max-w-[540px] lg:mb-0'>
|
||||
<h2 className='mb-5 text-3xl font-bold leading-tight text-dark dark:text-white sm:text-[40px] sm:leading-[1.2]'>
|
||||
{siteConfig('STARTER_ABOUT_TITLE')}
|
||||
</h2>
|
||||
<p
|
||||
className='mb-10 text-base leading-relaxed text-body-color dark:text-dark-6'
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: siteConfig('STARTER_ABOUT_TEXT')
|
||||
}}></p>
|
||||
|
||||
{/* 左侧的文字说明板块 */}
|
||||
<div className="w-full px-4 lg:w-1/2">
|
||||
<div className="mb-12 max-w-[540px] lg:mb-0">
|
||||
<h2
|
||||
className="mb-5 text-3xl font-bold leading-tight text-dark dark:text-white sm:text-[40px] sm:leading-[1.2]"
|
||||
>
|
||||
{siteConfig('STARTER_ABOUT_TITLE', null, CONFIG)}
|
||||
</h2>
|
||||
<p className="mb-10 text-base leading-relaxed text-body-color dark:text-dark-6"
|
||||
dangerouslySetInnerHTML={
|
||||
{ __html: siteConfig('STARTER_ABOUT_TEXT', null, CONFIG) }
|
||||
}></p>
|
||||
|
||||
<a
|
||||
href={siteConfig('STARTER_ABOUT_BUTTON_URL', null, CONFIG)}
|
||||
className="inline-flex items-center justify-center rounded-md border border-primary bg-primary px-7 py-3 text-center text-base font-medium text-white hover:border-blue-dark hover:bg-blue-dark"
|
||||
>
|
||||
{siteConfig('STARTER_ABOUT_BUTTON_TEXT', null, CONFIG)}
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 右侧的图片海报 */}
|
||||
<div className="w-full px-4 lg:w-1/2">
|
||||
<div className="-mx-2 flex flex-wrap sm:-mx-4 lg:-mx-2 xl:-mx-4">
|
||||
<div className="w-full px-2 sm:w-1/2 sm:px-4 lg:px-2 xl:px-4">
|
||||
<div
|
||||
className="mb-4 sm:mb-8 sm:h-[400px] md:h-[540px] lg:h-[400px] xl:h-[500px]"
|
||||
>
|
||||
<img
|
||||
src={siteConfig('STARTER_ABOUT_IMAGE_1', null, CONFIG)}
|
||||
alt="about image"
|
||||
className="h-full w-full object-cover object-center"
|
||||
/>
|
||||
</div>
|
||||
<Link
|
||||
href={siteConfig('STARTER_ABOUT_BUTTON_URL', '')}
|
||||
className='inline-flex items-center justify-center rounded-md border border-primary bg-primary px-7 py-3 text-center text-base font-medium text-white hover:border-blue-dark hover:bg-blue-dark'>
|
||||
{siteConfig('STARTER_ABOUT_BUTTON_TEXT')}
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="w-full px-2 sm:w-1/2 sm:px-4 lg:px-2 xl:px-4">
|
||||
<div
|
||||
className="mb-4 sm:mb-8 sm:h-[220px] md:h-[346px] lg:mb-4 lg:h-[225px] xl:mb-8 xl:h-[310px]"
|
||||
>
|
||||
<img
|
||||
src={siteConfig('STARTER_ABOUT_IMAGE_2', null, CONFIG)}
|
||||
alt="about image"
|
||||
className="h-full w-full object-cover object-center"
|
||||
/>
|
||||
{/* 右侧的图片海报 */}
|
||||
<div className='w-full px-4 lg:w-1/2'>
|
||||
<div className='-mx-2 flex flex-wrap sm:-mx-4 lg:-mx-2 xl:-mx-4'>
|
||||
<div className='w-full px-2 sm:w-1/2 sm:px-4 lg:px-2 xl:px-4'>
|
||||
<div className='mb-4 sm:mb-8 sm:h-[400px] md:h-[540px] lg:h-[400px] xl:h-[500px]'>
|
||||
<img
|
||||
src={siteConfig('STARTER_ABOUT_IMAGE_1')}
|
||||
alt='about image'
|
||||
className='h-full w-full object-cover object-center'
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
className="relative z-10 mb-4 flex items-center justify-center overflow-hidden bg-primary px-6 py-12 sm:mb-8 sm:h-[160px] sm:p-5 lg:mb-4 xl:mb-8"
|
||||
>
|
||||
<div>
|
||||
<span className="block text-5xl font-extrabold text-white">
|
||||
{siteConfig('STARTER_ABOUT_TIPS_1', null, CONFIG)}
|
||||
</span>
|
||||
<span className="block text-base font-semibold text-white">
|
||||
{siteConfig('STARTER_ABOUT_TIPS_2', null, CONFIG)}
|
||||
</span>
|
||||
<span
|
||||
className="block text-base font-medium text-white text-opacity-70"
|
||||
>
|
||||
{siteConfig('STARTER_ABOUT_TIPS_3', null, CONFIG)}
|
||||
</span>
|
||||
<div className='w-full px-2 sm:w-1/2 sm:px-4 lg:px-2 xl:px-4'>
|
||||
<div className='mb-4 sm:mb-8 sm:h-[220px] md:h-[346px] lg:mb-4 lg:h-[225px] xl:mb-8 xl:h-[310px]'>
|
||||
<img
|
||||
src={siteConfig('STARTER_ABOUT_IMAGE_2')}
|
||||
alt='about image'
|
||||
className='h-full w-full object-cover object-center'
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<span className="absolute left-0 top-0 -z-10">
|
||||
<svg
|
||||
width="106"
|
||||
height="144"
|
||||
viewBox="0 0 106 144"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<rect
|
||||
opacity="0.1"
|
||||
x="-67"
|
||||
y="47.127"
|
||||
width="113.378"
|
||||
height="131.304"
|
||||
transform="rotate(-42.8643 -67 47.127)"
|
||||
fill="url(#paint0_linear_1416_214)"
|
||||
/>
|
||||
<defs>
|
||||
<linearGradient
|
||||
id="paint0_linear_1416_214"
|
||||
x1="-10.3111"
|
||||
y1="47.127"
|
||||
x2="-10.3111"
|
||||
y2="178.431"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
>
|
||||
<stop stopColor="white" />
|
||||
<stop
|
||||
offset="1"
|
||||
stopColor="white"
|
||||
stopOpacity="0"
|
||||
/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
</svg>
|
||||
</span>
|
||||
<span className="absolute right-0 top-0 -z-10">
|
||||
<svg
|
||||
width="130"
|
||||
height="97"
|
||||
viewBox="0 0 130 97"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<rect
|
||||
opacity="0.1"
|
||||
x="0.86792"
|
||||
y="-6.67725"
|
||||
width="155.563"
|
||||
height="140.614"
|
||||
transform="rotate(-42.8643 0.86792 -6.67725)"
|
||||
fill="url(#paint0_linear_1416_215)"
|
||||
/>
|
||||
<defs>
|
||||
<linearGradient
|
||||
id="paint0_linear_1416_215"
|
||||
x1="78.6495"
|
||||
y1="-6.67725"
|
||||
x2="78.6495"
|
||||
y2="133.937"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
>
|
||||
<stop stopColor="white" />
|
||||
<stop
|
||||
offset="1"
|
||||
stopColor="white"
|
||||
stopOpacity="0"
|
||||
/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
</svg>
|
||||
</span>
|
||||
<span className="absolute bottom-0 right-0 -z-10">
|
||||
<svg
|
||||
width="175"
|
||||
height="104"
|
||||
viewBox="0 0 175 104"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<rect
|
||||
opacity="0.1"
|
||||
x="175.011"
|
||||
y="108.611"
|
||||
width="101.246"
|
||||
height="148.179"
|
||||
transform="rotate(137.136 175.011 108.611)"
|
||||
fill="url(#paint0_linear_1416_216)"
|
||||
/>
|
||||
<defs>
|
||||
<linearGradient
|
||||
id="paint0_linear_1416_216"
|
||||
x1="225.634"
|
||||
y1="108.611"
|
||||
x2="225.634"
|
||||
y2="256.79"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
>
|
||||
<stop stopColor="white" />
|
||||
<stop
|
||||
offset="1"
|
||||
stopColor="white"
|
||||
stopOpacity="0"
|
||||
/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
</svg>
|
||||
</span>
|
||||
|
||||
<div className='relative z-10 mb-4 flex items-center justify-center overflow-hidden bg-primary px-6 py-12 sm:mb-8 sm:h-[160px] sm:p-5 lg:mb-4 xl:mb-8'>
|
||||
<div>
|
||||
<span className='block text-5xl font-extrabold text-white'>
|
||||
{siteConfig('STARTER_ABOUT_TIPS_1')}
|
||||
</span>
|
||||
<span className='block text-base font-semibold text-white'>
|
||||
{siteConfig('STARTER_ABOUT_TIPS_2')}
|
||||
</span>
|
||||
<span className='block text-base font-medium text-white text-opacity-70'>
|
||||
{siteConfig('STARTER_ABOUT_TIPS_3')}
|
||||
</span>
|
||||
</div>
|
||||
<div>
|
||||
<span className='absolute left-0 top-0 -z-10'>
|
||||
<svg
|
||||
width='106'
|
||||
height='144'
|
||||
viewBox='0 0 106 144'
|
||||
fill='none'
|
||||
xmlns='http://www.w3.org/2000/svg'>
|
||||
<rect
|
||||
opacity='0.1'
|
||||
x='-67'
|
||||
y='47.127'
|
||||
width='113.378'
|
||||
height='131.304'
|
||||
transform='rotate(-42.8643 -67 47.127)'
|
||||
fill='url(#paint0_linear_1416_214)'
|
||||
/>
|
||||
<defs>
|
||||
<linearGradient
|
||||
id='paint0_linear_1416_214'
|
||||
x1='-10.3111'
|
||||
y1='47.127'
|
||||
x2='-10.3111'
|
||||
y2='178.431'
|
||||
gradientUnits='userSpaceOnUse'>
|
||||
<stop stopColor='white' />
|
||||
<stop
|
||||
offset='1'
|
||||
stopColor='white'
|
||||
stopOpacity='0'
|
||||
/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
</svg>
|
||||
</span>
|
||||
<span className='absolute right-0 top-0 -z-10'>
|
||||
<svg
|
||||
width='130'
|
||||
height='97'
|
||||
viewBox='0 0 130 97'
|
||||
fill='none'
|
||||
xmlns='http://www.w3.org/2000/svg'>
|
||||
<rect
|
||||
opacity='0.1'
|
||||
x='0.86792'
|
||||
y='-6.67725'
|
||||
width='155.563'
|
||||
height='140.614'
|
||||
transform='rotate(-42.8643 0.86792 -6.67725)'
|
||||
fill='url(#paint0_linear_1416_215)'
|
||||
/>
|
||||
<defs>
|
||||
<linearGradient
|
||||
id='paint0_linear_1416_215'
|
||||
x1='78.6495'
|
||||
y1='-6.67725'
|
||||
x2='78.6495'
|
||||
y2='133.937'
|
||||
gradientUnits='userSpaceOnUse'>
|
||||
<stop stopColor='white' />
|
||||
<stop
|
||||
offset='1'
|
||||
stopColor='white'
|
||||
stopOpacity='0'
|
||||
/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
</svg>
|
||||
</span>
|
||||
<span className='absolute bottom-0 right-0 -z-10'>
|
||||
<svg
|
||||
width='175'
|
||||
height='104'
|
||||
viewBox='0 0 175 104'
|
||||
fill='none'
|
||||
xmlns='http://www.w3.org/2000/svg'>
|
||||
<rect
|
||||
opacity='0.1'
|
||||
x='175.011'
|
||||
y='108.611'
|
||||
width='101.246'
|
||||
height='148.179'
|
||||
transform='rotate(137.136 175.011 108.611)'
|
||||
fill='url(#paint0_linear_1416_216)'
|
||||
/>
|
||||
<defs>
|
||||
<linearGradient
|
||||
id='paint0_linear_1416_216'
|
||||
x1='225.634'
|
||||
y1='108.611'
|
||||
x2='225.634'
|
||||
y2='256.79'
|
||||
gradientUnits='userSpaceOnUse'>
|
||||
<stop stopColor='white' />
|
||||
<stop
|
||||
offset='1'
|
||||
stopColor='white'
|
||||
stopOpacity='0'
|
||||
/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
</svg>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -197,8 +181,8 @@ export const About = () => {
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
{/* <!-- ====== About Section End --> */}
|
||||
</section>
|
||||
{/* <!-- ====== About Section End --> */}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
53
themes/starter/components/ArticleLock.js
Normal file
53
themes/starter/components/ArticleLock.js
Normal file
@@ -0,0 +1,53 @@
|
||||
import { useGlobal } from '@/lib/global'
|
||||
import { useEffect, useRef } from 'react'
|
||||
|
||||
/**
|
||||
* 加密文章校验组件
|
||||
* @param {password, validPassword} props
|
||||
* @param password 正确的密码
|
||||
* @param validPassword(bool) 回调函数,校验正确回调入参为true
|
||||
* @returns
|
||||
*/
|
||||
export const ArticleLock = props => {
|
||||
const { validPassword } = props
|
||||
const { locale } = useGlobal()
|
||||
|
||||
const submitPassword = () => {
|
||||
const p = document.getElementById('password')
|
||||
if (!validPassword(p?.value)) {
|
||||
const tips = document.getElementById('tips')
|
||||
if (tips) {
|
||||
tips.innerHTML = ''
|
||||
tips.innerHTML = `<div class='text-red-500 animate__shakeX animate__animated'>${locale.COMMON.PASSWORD_ERROR}</div>`
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const passwordInputRef = useRef(null)
|
||||
useEffect(() => {
|
||||
// 选中密码输入框并将其聚焦
|
||||
passwordInputRef.current.focus()
|
||||
}, [])
|
||||
|
||||
return <div id='container' className='w-full flex justify-center items-center h-96 '>
|
||||
<div className='text-center space-y-3'>
|
||||
<div className='font-bold'>{locale.COMMON.ARTICLE_LOCK_TIPS}</div>
|
||||
<div className='flex'>
|
||||
<input id="password" type='password'
|
||||
onKeyDown={(e) => {
|
||||
if (e.key === 'Enter') {
|
||||
submitPassword()
|
||||
}
|
||||
}}
|
||||
ref={passwordInputRef} // 绑定ref到passwordInputRef变量
|
||||
className='outline-none w-full text-sm pl-5 rounded-l transition focus:shadow-lg font-light leading-10 text-black dark:bg-gray-500 bg-gray-50'
|
||||
></input>
|
||||
<div onClick={submitPassword} className="px-3 whitespace-nowrap cursor-pointer items-center justify-center py-2 rounded-r duration-300 bg-gray-300" >
|
||||
<i className={'duration-200 cursor-pointer fas fa-key dark:text-black'} > {locale.COMMON.SUBMIT}</i>
|
||||
</div>
|
||||
</div>
|
||||
<div id='tips'>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
@@ -1,41 +1,17 @@
|
||||
import throttle from 'lodash.throttle';
|
||||
import throttle from 'lodash.throttle'
|
||||
import { useCallback, useEffect } from 'react'
|
||||
|
||||
/**
|
||||
* 回顶按钮
|
||||
* @returns
|
||||
*/
|
||||
export const BackToTopButton = () => {
|
||||
useEffect(() => {
|
||||
// ====== scroll top js
|
||||
function scrollTo(element, to = 0, duration = 500) {
|
||||
const start = element.scrollTop;
|
||||
const change = to - start;
|
||||
const increment = 20;
|
||||
let currentTime = 0;
|
||||
|
||||
const animateScroll = () => {
|
||||
currentTime += increment;
|
||||
|
||||
const val = Math.easeInOutQuad(currentTime, start, change, duration);
|
||||
|
||||
element.scrollTop = val;
|
||||
|
||||
if (currentTime < duration) {
|
||||
setTimeout(animateScroll, increment);
|
||||
}
|
||||
};
|
||||
|
||||
animateScroll();
|
||||
}
|
||||
|
||||
Math.easeInOutQuad = function (t, b, c, d) {
|
||||
t /= d / 2;
|
||||
if (t < 1) return (c / 2) * t * t + b;
|
||||
t--;
|
||||
return (-c / 2) * (t * (t - 2) - 1) + b;
|
||||
};
|
||||
const backToTop = document.querySelector('.back-to-top')
|
||||
if (backToTop) {
|
||||
backToTop.onclick = () => {
|
||||
scrollTo(document.documentElement);
|
||||
};
|
||||
t /= d / 2
|
||||
if (t < 1) return (c / 2) * t * t + b
|
||||
t--
|
||||
return (-c / 2) * (t * (t - 2) - 1) + b
|
||||
}
|
||||
|
||||
window.addEventListener('scroll', navBarScollListener)
|
||||
@@ -48,20 +24,52 @@ export const BackToTopButton = () => {
|
||||
const throttleMs = 200
|
||||
const navBarScollListener = useCallback(
|
||||
throttle(() => {
|
||||
const scrollY = window.scrollY;
|
||||
const scrollY = window.scrollY
|
||||
// 显示或隐藏返回顶部按钮
|
||||
const backToTop = document.querySelector('.back-to-top');
|
||||
const backToTop = document.querySelector('.back-to-top')
|
||||
if (backToTop) {
|
||||
backToTop.style.display = scrollY > 50 ? 'flex' : 'none';
|
||||
backToTop.style.display = scrollY > 50 ? 'flex' : 'none'
|
||||
}
|
||||
}, throttleMs)
|
||||
)
|
||||
|
||||
return <>
|
||||
{/* <!-- ====== Back To Top Start --> */}
|
||||
<a className="back-to-top fixed bottom-16 left-auto right-8 z-[999] hidden h-10 w-10 items-center justify-center rounded-md bg-primary text-white shadow-md transition duration-300 ease-in-out hover:bg-dark">
|
||||
<span className="mt-[6px] h-3 w-3 rotate-45 border-l border-t border-white" ></span>
|
||||
</a>
|
||||
{/* <!-- ====== Back To Top End --> */}
|
||||
// ====== scroll top js
|
||||
function scrollTo(element, to = 0, duration = 500) {
|
||||
const start = element.scrollTop
|
||||
const change = to - start
|
||||
const increment = 20
|
||||
let currentTime = 0
|
||||
|
||||
const animateScroll = () => {
|
||||
currentTime += increment
|
||||
|
||||
const val = Math.easeInOutQuad(currentTime, start, change, duration)
|
||||
|
||||
element.scrollTop = val
|
||||
|
||||
if (currentTime < duration) {
|
||||
setTimeout(animateScroll, increment)
|
||||
}
|
||||
}
|
||||
|
||||
animateScroll()
|
||||
}
|
||||
|
||||
function scrollTop() {
|
||||
if (document) {
|
||||
scrollTo(document.documentElement)
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
{/* <!-- ====== Back To Top Start --> */}
|
||||
<a
|
||||
onClick={scrollTop}
|
||||
className='back-to-top cursor-pointer fixed bottom-16 left-auto right-8 z-[999] hidden h-10 w-10 items-center justify-center rounded-md bg-primary text-white shadow-md transition duration-300 ease-in-out hover:bg-dark'>
|
||||
<span className='mt-[6px] h-3 w-3 rotate-45 border-l border-t border-white'></span>
|
||||
</a>
|
||||
{/* <!-- ====== Back To Top End --> */}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,30 +1,25 @@
|
||||
/**
|
||||
* 详情页面顶部条
|
||||
* 页面顶部宣传栏
|
||||
* @returns
|
||||
*/
|
||||
export const Banner = ({ title, description }) => {
|
||||
return <>
|
||||
{/* <!-- ====== Banner Section Start --> */}
|
||||
<div
|
||||
className="relative z-10 overflow-hidden pb-[60px] pt-[120px] dark:bg-dark md:pt-[130px] lg:pt-[160px]"
|
||||
>
|
||||
<div
|
||||
className="absolute bottom-0 left-0 w-full h-px bg-gradient-to-r from-stroke/0 via-stroke to-stroke/0 dark:via-dark-3"
|
||||
></div>
|
||||
<div className="container">
|
||||
<div className="flex flex-wrap items-center -mx-4">
|
||||
<div className="w-full px-4">
|
||||
<div className="text-center">
|
||||
<h1
|
||||
className="mb-4 text-3xl font-bold text-dark dark:text-white sm:text-4xl md:text-[40px] md:leading-[1.2]"
|
||||
>
|
||||
{title}
|
||||
</h1>
|
||||
<p className="mb-5 text-base text-body-color dark:text-dark-6">
|
||||
{description}
|
||||
</p>
|
||||
return (
|
||||
<>
|
||||
{/* <!-- ====== Banner Section Start --> */}
|
||||
<div className='relative z-10 overflow-hidden pb-[60px] pt-[120px] dark:bg-dark md:pt-[130px] lg:pt-[160px]'>
|
||||
<div className='absolute bottom-0 left-0 w-full h-px bg-gradient-to-r from-stroke/0 via-stroke to-stroke/0 dark:via-dark-3'></div>
|
||||
<div className='container'>
|
||||
<div className='flex flex-wrap items-center -mx-4'>
|
||||
<div className='w-full px-4'>
|
||||
<div className='text-center'>
|
||||
<h1 className='mb-4 text-3xl font-bold text-dark dark:text-white sm:text-4xl md:text-[40px] md:leading-[1.2]'>
|
||||
{title}
|
||||
</h1>
|
||||
<p className='mb-5 text-base text-body-color dark:text-dark-6'>
|
||||
{description}
|
||||
</p>
|
||||
|
||||
{/* <ul className="flex items-center justify-center gap-[10px]">
|
||||
{/* <ul className="flex items-center justify-center gap-[10px]">
|
||||
<li>
|
||||
<a
|
||||
href="index.html"
|
||||
@@ -43,11 +38,12 @@ export const Banner = ({ title, description }) => {
|
||||
</a>
|
||||
</li>
|
||||
</ul> */}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/* <!-- ====== Banner Section End --> */}
|
||||
{/* <!-- ====== Banner Section End --> */}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
/* eslint-disable @next/next/no-img-element */
|
||||
import { siteConfig } from '@/lib/config'
|
||||
import Link from 'next/link'
|
||||
import CONFIG from '../config'
|
||||
|
||||
/**
|
||||
* 博文列表
|
||||
@@ -19,14 +18,14 @@ export const Blog = ({ posts }) => {
|
||||
<div className='w-full px-4'>
|
||||
<div className='mx-auto mb-[60px] max-w-[485px] text-center'>
|
||||
<span className='mb-2 block text-lg font-semibold text-primary'>
|
||||
{siteConfig('STARTER_BLOG_TITLE', null, CONFIG)}
|
||||
{siteConfig('STARTER_BLOG_TITLE')}
|
||||
</span>
|
||||
<h2 className='mb-4 text-3xl font-bold text-dark dark:text-white sm:text-4xl md:text-[40px] md:leading-[1.2]'>
|
||||
{siteConfig('STARTER_BLOG_TEXT_1', null, CONFIG)}
|
||||
{siteConfig('STARTER_BLOG_TEXT_1')}
|
||||
</h2>
|
||||
<p
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: siteConfig('STARTER_BLOG_TEXT_2', null, CONFIG)
|
||||
__html: siteConfig('STARTER_BLOG_TEXT_2')
|
||||
}}
|
||||
className='text-base text-body-color dark:text-dark-6'></p>
|
||||
</div>
|
||||
@@ -41,13 +40,15 @@ export const Blog = ({ posts }) => {
|
||||
className='wow fadeInUp group mb-10'
|
||||
data-wow-delay='.1s'>
|
||||
<div className='mb-8 overflow-hidden rounded-[5px]'>
|
||||
<Link href={item?.href} className='block'>
|
||||
<img
|
||||
src={item.pageCoverThumbnail}
|
||||
alt={item.title}
|
||||
className='w-full transition group-hover:rotate-6 group-hover:scale-125'
|
||||
/>
|
||||
</Link>
|
||||
{item.pageCoverThumbnail && (
|
||||
<Link href={item?.href} className='block'>
|
||||
<img
|
||||
src={item.pageCoverThumbnail}
|
||||
alt={item.title}
|
||||
className='w-full transition group-hover:rotate-6 group-hover:scale-125'
|
||||
/>
|
||||
</Link>
|
||||
)}
|
||||
</div>
|
||||
<div>
|
||||
<span className='mb-6 inline-block rounded-[5px] bg-primary px-4 py-0.5 text-center text-xs font-medium leading-loose text-white'>
|
||||
|
||||
@@ -1,37 +1,39 @@
|
||||
/* eslint-disable @next/next/no-img-element */
|
||||
|
||||
import CONFIG from '../config'
|
||||
import { siteConfig } from '@/lib/config'
|
||||
|
||||
/**
|
||||
* 合作伙伴
|
||||
* @returns
|
||||
*/
|
||||
export const Brand = () => {
|
||||
return <>
|
||||
|
||||
{/* <!-- ====== Brands Section Start --> */}
|
||||
<section className="pb-20 dark:bg-dark">
|
||||
<div className="container px-4">
|
||||
<div
|
||||
className="-mx-4 flex flex-wrap items-center justify-center gap-8 xl:gap-11"
|
||||
>
|
||||
{CONFIG.STARTER_BRANDS?.map((item, index) => {
|
||||
return <a key={index} href={item.URL}>
|
||||
<img
|
||||
src={item.IMAGE}
|
||||
alt={item.TITLE}
|
||||
className="dark:hidden"
|
||||
/>
|
||||
<img
|
||||
src={item.IMAGE_WHITE}
|
||||
alt={item.TITLE}
|
||||
className="hidden dark:block"
|
||||
/>
|
||||
</a>
|
||||
})}
|
||||
const brands = siteConfig('STARTER_BRANDS')
|
||||
return (
|
||||
<>
|
||||
{/* <!-- ====== Brands Section Start --> */}
|
||||
<section className='py-20 dark:bg-dark'>
|
||||
<div className='container px-4'>
|
||||
<div className='-mx-4 flex flex-wrap items-center justify-center gap-8 xl:gap-11'>
|
||||
{brands?.map((item, index) => {
|
||||
return (
|
||||
<a key={index} href={item.URL}>
|
||||
<img
|
||||
src={item.IMAGE}
|
||||
alt={item.TITLE}
|
||||
className='dark:hidden'
|
||||
/>
|
||||
<img
|
||||
src={item.IMAGE_WHITE}
|
||||
alt={item.TITLE}
|
||||
className='hidden dark:block'
|
||||
/>
|
||||
</a>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
{/* <!-- ====== Brands Section End --> */}
|
||||
</section>
|
||||
{/* <!-- ====== Brands Section End --> */}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,106 +1,112 @@
|
||||
import { siteConfig } from '@/lib/config'
|
||||
import Link from 'next/link'
|
||||
|
||||
/**
|
||||
* CTA,用于创建一个呼吁用户行动的部分(Call To Action,简称 CTA)。
|
||||
* 该组件通过以下方式激励用户进行特定操作
|
||||
* 用户的公告栏内容将在此显示
|
||||
**/
|
||||
export const CTA = () => {
|
||||
return <>
|
||||
|
||||
{/* <!-- ====== CTA Section Start --> */}
|
||||
<section
|
||||
className="relative z-10 overflow-hidden bg-primary py-20 lg:py-[115px]"
|
||||
>
|
||||
<div className="container mx-auto">
|
||||
<div className="relative overflow-hidden">
|
||||
<div className="-mx-4 flex flex-wrap items-stretch">
|
||||
<div className="w-full px-4">
|
||||
<div className="mx-auto max-w-[570px] text-center">
|
||||
<h2
|
||||
className="mb-2.5 text-3xl font-bold text-white md:text-[38px] md:leading-[1.44]"
|
||||
>
|
||||
<span>What Are You Looking For?</span>
|
||||
<span className="text-3xl font-normal md:text-[40px]">
|
||||
Get Started Now
|
||||
</span>
|
||||
</h2>
|
||||
<p
|
||||
className="mx-auto mb-6 max-w-[515px] text-base leading-[1.5] text-white"
|
||||
>
|
||||
There are many variations of passages of Lorem Ipsum but the
|
||||
majority have suffered in some form.
|
||||
</p>
|
||||
<a
|
||||
|
||||
className="inline-block rounded-md border border-transparent bg-secondary px-7 py-3 text-base font-medium text-white transition hover:bg-[#0BB489]"
|
||||
>
|
||||
Start using Play
|
||||
</a>
|
||||
if (!siteConfig('STARTER_CTA_ENABLE')) {
|
||||
return <></>
|
||||
}
|
||||
return (
|
||||
<>
|
||||
{/* <!-- ====== CTA Section Start --> */}
|
||||
<section className='relative z-10 overflow-hidden bg-primary py-20 lg:py-[115px]'>
|
||||
<div className='container mx-auto'>
|
||||
<div className='relative overflow-hidden'>
|
||||
<div className='-mx-4 flex flex-wrap items-stretch'>
|
||||
<div className='w-full px-4'>
|
||||
<div className='mx-auto max-w-[570px] text-center'>
|
||||
<h2 className='mb-2.5 text-3xl font-bold text-white md:text-[38px] md:leading-[1.44]'>
|
||||
<span>{siteConfig('STARTER_CTA_TITLE')}</span>
|
||||
<span className='text-3xl font-normal md:text-[40px]'>
|
||||
{siteConfig('STARTER_CTA_TITLE_2')}
|
||||
</span>
|
||||
</h2>
|
||||
<p className='mx-auto mb-6 max-w-[515px] text-base leading-[1.5] text-white'>
|
||||
{siteConfig('STARTER_CTA_DESCRIOTN')}
|
||||
</p>
|
||||
{siteConfig('STARTER_CTA_BUTTON') && (
|
||||
<>
|
||||
<Link
|
||||
href={siteConfig('STARTER_CTA_BUTTON_URL', '')}
|
||||
className='inline-block rounded-md border border-transparent bg-secondary px-7 py-3 text-base font-medium text-white transition hover:bg-[#0BB489]'>
|
||||
{siteConfig('STARTER_CTA_BUTTON_TEXT')}
|
||||
</Link>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<span className="absolute left-0 top-0">
|
||||
<svg
|
||||
width="495"
|
||||
height="470"
|
||||
viewBox="0 0 495 470"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<circle
|
||||
cx="55"
|
||||
cy="442"
|
||||
r="138"
|
||||
stroke="white"
|
||||
stroke-opacity="0.04"
|
||||
stroke-width="50"
|
||||
/>
|
||||
<circle
|
||||
cx="446"
|
||||
r="39"
|
||||
stroke="white"
|
||||
stroke-opacity="0.04"
|
||||
stroke-width="20"
|
||||
/>
|
||||
<path
|
||||
d="M245.406 137.609L233.985 94.9852L276.609 106.406L245.406 137.609Z"
|
||||
stroke="white"
|
||||
stroke-opacity="0.08"
|
||||
stroke-width="12"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
<span className="absolute bottom-0 right-0">
|
||||
<svg
|
||||
width="493"
|
||||
height="470"
|
||||
viewBox="0 0 493 470"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<circle
|
||||
cx="462"
|
||||
cy="5"
|
||||
r="138"
|
||||
stroke="white"
|
||||
stroke-opacity="0.04"
|
||||
stroke-width="50"
|
||||
/>
|
||||
<circle
|
||||
cx="49"
|
||||
cy="470"
|
||||
r="39"
|
||||
stroke="white"
|
||||
stroke-opacity="0.04"
|
||||
stroke-width="20"
|
||||
/>
|
||||
<path
|
||||
d="M222.393 226.701L272.808 213.192L259.299 263.607L222.393 226.701Z"
|
||||
stroke="white"
|
||||
stroke-opacity="0.06"
|
||||
stroke-width="13"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</div>
|
||||
</section>
|
||||
{/* <!-- ====== CTA Section End --> */}
|
||||
<div>
|
||||
<span className='absolute left-0 top-0'>
|
||||
<svg
|
||||
width='495'
|
||||
height='470'
|
||||
viewBox='0 0 495 470'
|
||||
fill='none'
|
||||
xmlns='http://www.w3.org/2000/svg'>
|
||||
<circle
|
||||
cx='55'
|
||||
cy='442'
|
||||
r='138'
|
||||
stroke='white'
|
||||
stroke-opacity='0.04'
|
||||
stroke-width='50'
|
||||
/>
|
||||
<circle
|
||||
cx='446'
|
||||
r='39'
|
||||
stroke='white'
|
||||
stroke-opacity='0.04'
|
||||
stroke-width='20'
|
||||
/>
|
||||
<path
|
||||
d='M245.406 137.609L233.985 94.9852L276.609 106.406L245.406 137.609Z'
|
||||
stroke='white'
|
||||
stroke-opacity='0.08'
|
||||
stroke-width='12'
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
<span className='absolute bottom-0 right-0'>
|
||||
<svg
|
||||
width='493'
|
||||
height='470'
|
||||
viewBox='0 0 493 470'
|
||||
fill='none'
|
||||
xmlns='http://www.w3.org/2000/svg'>
|
||||
<circle
|
||||
cx='462'
|
||||
cy='5'
|
||||
r='138'
|
||||
stroke='white'
|
||||
stroke-opacity='0.04'
|
||||
stroke-width='50'
|
||||
/>
|
||||
<circle
|
||||
cx='49'
|
||||
cy='470'
|
||||
r='39'
|
||||
stroke='white'
|
||||
stroke-opacity='0.04'
|
||||
stroke-width='20'
|
||||
/>
|
||||
<path
|
||||
d='M222.393 226.701L272.808 213.192L259.299 263.607L222.393 226.701Z'
|
||||
stroke='white'
|
||||
stroke-opacity='0.06'
|
||||
stroke-width='13'
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</div>
|
||||
</section>
|
||||
{/* <!-- ====== CTA Section End --> */}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import { SVGLocation } from './svg/SVGLocation'
|
||||
|
||||
/* eslint-disable react/no-unescaped-entities */
|
||||
export const Contact = () => {
|
||||
const url = siteConfig('STARTER_CONTACT_MSG_EXTERNAL_URL')
|
||||
return (
|
||||
<>
|
||||
{/* <!-- ====== Contact Start ====== --> */}
|
||||
@@ -18,10 +19,10 @@ export const Contact = () => {
|
||||
<div className='ud-contact-content-wrapper'>
|
||||
<div className='ud-contact-title mb-12 lg:mb-[150px]'>
|
||||
<span className='mb-6 block text-base font-medium text-dark dark:text-white'>
|
||||
{siteConfig('STARTER_CONTACT_TITLE', null, CONFIG)}
|
||||
{siteConfig('STARTER_CONTACT_TITLE')}
|
||||
</span>
|
||||
<h2 className='max-w-[260px] text-[35px] font-semibold leading-[1.14] text-dark dark:text-white'>
|
||||
{siteConfig('STARTER_CONTACT_TEXT', null, CONFIG)}
|
||||
{siteConfig('STARTER_CONTACT_TEXT')}
|
||||
</h2>
|
||||
</div>
|
||||
<div className='mb-12 flex flex-wrap justify-between lg:mb-0'>
|
||||
@@ -59,7 +60,7 @@ export const Contact = () => {
|
||||
)}
|
||||
</h5>
|
||||
<p className='text-base text-body-color dark:text-dark-6'>
|
||||
{siteConfig('STARTER_CONTACT_EMAIL_TEXT', null, CONFIG)}
|
||||
{siteConfig('STARTER_CONTACT_EMAIL_TEXT')}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
@@ -67,7 +68,7 @@ export const Contact = () => {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{siteConfig('STARTER_CONTACT_MSG_EXTERNAL_URL', null, CONFIG) && (
|
||||
{url && url !== '' && (
|
||||
<>
|
||||
{/* 联系方式右侧留言 */}
|
||||
<div className='w-full px-4 lg:w-5/12 xl:w-4/12'>
|
||||
|
||||
@@ -1,137 +1,120 @@
|
||||
import { siteConfig } from '@/lib/config';
|
||||
import { siteConfig } from '@/lib/config'
|
||||
import { useEffect } from 'react'
|
||||
import CONFIG from '../config';
|
||||
import { SVGQuestion } from './svg/SVGQuestion';
|
||||
import { SVGCircleBG } from './svg/SVGCircleBG';
|
||||
import { SVGCircleBG } from './svg/SVGCircleBG'
|
||||
import { SVGQuestion } from './svg/SVGQuestion'
|
||||
|
||||
export const FAQ = () => {
|
||||
useEffect(() => {
|
||||
// ===== Faq accordion
|
||||
const faqs = document.querySelectorAll('.single-faq');
|
||||
faqs.forEach((el) => {
|
||||
const faqs = document.querySelectorAll('.single-faq')
|
||||
faqs.forEach(el => {
|
||||
el.querySelector('.faq-btn').addEventListener('click', () => {
|
||||
el.querySelector('.icon').classList.toggle('rotate-180');
|
||||
el.querySelector('.faq-content').classList.toggle('hidden');
|
||||
});
|
||||
});
|
||||
el.querySelector('.icon').classList.toggle('rotate-180')
|
||||
el.querySelector('.faq-content').classList.toggle('hidden')
|
||||
})
|
||||
})
|
||||
})
|
||||
return <>
|
||||
return (
|
||||
<>
|
||||
{/* <!-- ====== FAQ Section Start --> */}
|
||||
<section
|
||||
className="relative z-20 overflow-hidden bg-white pb-8 pt-20 dark:bg-dark lg:pb-[50px] lg:pt-[120px]"
|
||||
>
|
||||
<div className="container mx-auto">
|
||||
<div className="-mx-4 flex flex-wrap">
|
||||
<div className="w-full px-4">
|
||||
<div className="mx-auto mb-[60px] max-w-[520px] text-center">
|
||||
<span className="mb-2 block text-lg font-semibold text-primary">
|
||||
{siteConfig('STARTER_FAQ_TITLE', null, CONFIG)}
|
||||
</span>
|
||||
<h2
|
||||
className="mb-3 text-3xl font-bold leading-[1.2] text-dark dark:text-white sm:text-4xl md:text-[40px]"
|
||||
>
|
||||
{siteConfig('STARTER_FAQ_TEXT_1', null, CONFIG)}
|
||||
</h2>
|
||||
<p
|
||||
className="mx-auto max-w-[485px] text-base text-body-color dark:text-dark-6"
|
||||
>
|
||||
{siteConfig('STARTER_FAQ_TEXT_2', null, CONFIG)}
|
||||
</p>
|
||||
<section className='relative overflow-hidden bg-white pb-8 pt-20 dark:bg-dark lg:pb-[50px] lg:pt-[120px]'>
|
||||
<div className='container mx-auto'>
|
||||
<div className='-mx-4 flex flex-wrap'>
|
||||
<div className='w-full px-4'>
|
||||
<div className='mx-auto mb-[60px] max-w-[520px] text-center'>
|
||||
<span className='mb-2 block text-lg font-semibold text-primary'>
|
||||
{siteConfig('STARTER_FAQ_TITLE')}
|
||||
</span>
|
||||
<h2 className='mb-3 text-3xl font-bold leading-[1.2] text-dark dark:text-white sm:text-4xl md:text-[40px]'>
|
||||
{siteConfig('STARTER_FAQ_TEXT_1')}
|
||||
</h2>
|
||||
<p className='mx-auto max-w-[485px] text-base text-body-color dark:text-dark-6'>
|
||||
{siteConfig('STARTER_FAQ_TEXT_2')}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className='-mx-4 flex flex-wrap'>
|
||||
<div className='w-full px-4 lg:w-1/2'>
|
||||
<div className='mb-12 flex lg:mb-[70px]'>
|
||||
<div className='mr-4 flex h-[50px] w-full max-w-[50px] items-center justify-center rounded-xl bg-primary text-white sm:mr-6 sm:h-[60px] sm:max-w-[60px]'>
|
||||
<SVGQuestion />
|
||||
</div>
|
||||
<div className='w-full'>
|
||||
<h3 className='mb-6 text-xl font-semibold text-dark dark:text-white sm:text-2xl lg:text-xl xl:text-2xl'>
|
||||
{siteConfig('STARTER_FAQ_1_QUESTION')}
|
||||
</h3>
|
||||
<p
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: siteConfig('STARTER_FAQ_1_ANSWER')
|
||||
}}
|
||||
className='text-base text-body-color dark:text-dark-6'></p>
|
||||
</div>
|
||||
</div>
|
||||
<div className='mb-12 flex lg:mb-[70px]'>
|
||||
<div className='mr-4 flex h-[50px] w-full max-w-[50px] items-center justify-center rounded-xl bg-primary text-white sm:mr-6 sm:h-[60px] sm:max-w-[60px]'>
|
||||
<SVGQuestion />
|
||||
</div>
|
||||
<div className='w-full'>
|
||||
<h3 className='mb-6 text-xl font-semibold text-dark dark:text-white sm:text-2xl lg:text-xl xl:text-2xl'>
|
||||
{siteConfig('STARTER_FAQ_2_QUESTION')}
|
||||
</h3>
|
||||
<p
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: siteConfig('STARTER_FAQ_2_ANSWER')
|
||||
}}
|
||||
className='text-base text-body-color dark:text-dark-6'></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className='w-full px-4 lg:w-1/2'>
|
||||
<div className='mb-12 flex lg:mb-[70px]'>
|
||||
<div className='mr-4 flex h-[50px] w-full max-w-[50px] items-center justify-center rounded-xl bg-primary text-white sm:mr-6 sm:h-[60px] sm:max-w-[60px]'>
|
||||
<SVGQuestion />
|
||||
</div>
|
||||
<div className='w-full'>
|
||||
<h3 className='mb-6 text-xl font-semibold text-dark dark:text-white sm:text-2xl lg:text-xl xl:text-2xl'>
|
||||
{siteConfig('STARTER_FAQ_3_QUESTION')}
|
||||
</h3>
|
||||
<p
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: siteConfig('STARTER_FAQ_3_ANSWER')
|
||||
}}
|
||||
className='text-base text-body-color dark:text-dark-6'></p>
|
||||
</div>
|
||||
</div>
|
||||
<div className='mb-12 flex lg:mb-[70px]'>
|
||||
<div className='mr-4 flex h-[50px] w-full max-w-[50px] items-center justify-center rounded-xl bg-primary text-white sm:mr-6 sm:h-[60px] sm:max-w-[60px]'>
|
||||
<SVGQuestion />
|
||||
</div>
|
||||
<div className='w-full'>
|
||||
<h3 className='mb-6 text-xl font-semibold text-dark dark:text-white sm:text-2xl lg:text-xl xl:text-2xl'>
|
||||
{siteConfig('STARTER_FAQ_4_QUESTION')}
|
||||
</h3>
|
||||
<p
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: siteConfig('STARTER_FAQ_4_ANSWER')
|
||||
}}
|
||||
className='text-base text-body-color dark:text-dark-6'></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="-mx-4 flex flex-wrap">
|
||||
<div className="w-full px-4 lg:w-1/2">
|
||||
<div className="mb-12 flex lg:mb-[70px]">
|
||||
<div
|
||||
className="mr-4 flex h-[50px] w-full max-w-[50px] items-center justify-center rounded-xl bg-primary text-white sm:mr-6 sm:h-[60px] sm:max-w-[60px]"
|
||||
>
|
||||
<SVGQuestion/>
|
||||
</div>
|
||||
<div className="w-full">
|
||||
<h3
|
||||
className="mb-6 text-xl font-semibold text-dark dark:text-white sm:text-2xl lg:text-xl xl:text-2xl"
|
||||
>
|
||||
{siteConfig('STARTER_FAQ_1_QUESTION', null, CONFIG)}
|
||||
</h3>
|
||||
<p dangerouslySetInnerHTML={
|
||||
{ __html: siteConfig('STARTER_FAQ_1_ANSWER', null, CONFIG) }
|
||||
} className="text-base text-body-color dark:text-dark-6">
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="mb-12 flex lg:mb-[70px]">
|
||||
<div
|
||||
className="mr-4 flex h-[50px] w-full max-w-[50px] items-center justify-center rounded-xl bg-primary text-white sm:mr-6 sm:h-[60px] sm:max-w-[60px]"
|
||||
>
|
||||
<SVGQuestion/>
|
||||
</div>
|
||||
<div className="w-full">
|
||||
<h3
|
||||
className="mb-6 text-xl font-semibold text-dark dark:text-white sm:text-2xl lg:text-xl xl:text-2xl"
|
||||
>
|
||||
{siteConfig('STARTER_FAQ_2_QUESTION', null, CONFIG)}
|
||||
</h3>
|
||||
<p dangerouslySetInnerHTML={
|
||||
{ __html: siteConfig('STARTER_FAQ_2_ANSWER', null, CONFIG) }
|
||||
} className="text-base text-body-color dark:text-dark-6">
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="w-full px-4 lg:w-1/2">
|
||||
<div className="mb-12 flex lg:mb-[70px]">
|
||||
<div
|
||||
className="mr-4 flex h-[50px] w-full max-w-[50px] items-center justify-center rounded-xl bg-primary text-white sm:mr-6 sm:h-[60px] sm:max-w-[60px]"
|
||||
>
|
||||
<SVGQuestion/>
|
||||
</div>
|
||||
<div className="w-full">
|
||||
<h3
|
||||
className="mb-6 text-xl font-semibold text-dark dark:text-white sm:text-2xl lg:text-xl xl:text-2xl"
|
||||
>
|
||||
{siteConfig('STARTER_FAQ_3_QUESTION', null, CONFIG)}
|
||||
</h3>
|
||||
<p dangerouslySetInnerHTML={
|
||||
{ __html: siteConfig('STARTER_FAQ_3_ANSWER', null, CONFIG) }
|
||||
} className="text-base text-body-color dark:text-dark-6">
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="mb-12 flex lg:mb-[70px]">
|
||||
<div
|
||||
className="mr-4 flex h-[50px] w-full max-w-[50px] items-center justify-center rounded-xl bg-primary text-white sm:mr-6 sm:h-[60px] sm:max-w-[60px]"
|
||||
>
|
||||
<SVGQuestion/>
|
||||
</div>
|
||||
<div className="w-full">
|
||||
<h3
|
||||
className="mb-6 text-xl font-semibold text-dark dark:text-white sm:text-2xl lg:text-xl xl:text-2xl"
|
||||
>
|
||||
{siteConfig('STARTER_FAQ_4_QUESTION', null, CONFIG)}
|
||||
</h3>
|
||||
<p dangerouslySetInnerHTML={
|
||||
{ __html: siteConfig('STARTER_FAQ_4_ANSWER', null, CONFIG) }
|
||||
} className="text-base text-body-color dark:text-dark-6">
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/* 背景图案 */}
|
||||
<div>
|
||||
<span className='absolute left-4 top-4 -z-[1]'>
|
||||
<SVGCircleBG />
|
||||
</span>
|
||||
<span className='absolute bottom-4 right-4 -z-[1]'>
|
||||
<SVGCircleBG />
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 背景图案 */}
|
||||
<div>
|
||||
<span className="absolute left-4 top-4 -z-[1]">
|
||||
<SVGCircleBG/>
|
||||
</span>
|
||||
<span className="absolute bottom-4 right-4 -z-[1]">
|
||||
<SVGCircleBG/>
|
||||
</span>
|
||||
</div>
|
||||
</section>
|
||||
{/* <!-- ====== FAQ Section End --> */}
|
||||
</section>
|
||||
{/* <!-- ====== FAQ Section End --> */}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,135 +1,115 @@
|
||||
import CONFIG from '../config'
|
||||
import { siteConfig } from '@/lib/config';
|
||||
import { SVGGifts } from './svg/SVGGifts';
|
||||
import { SVGTemplate } from './svg/SVGTemplate';
|
||||
import { SVGDesign } from './svg/SVGDesign';
|
||||
import { SVGEssential } from './svg/SVGEssential';
|
||||
import { siteConfig } from '@/lib/config'
|
||||
import { SVGDesign } from './svg/SVGDesign'
|
||||
import { SVGEssential } from './svg/SVGEssential'
|
||||
import { SVGGifts } from './svg/SVGGifts'
|
||||
import { SVGTemplate } from './svg/SVGTemplate'
|
||||
import Link from 'next/link'
|
||||
/**
|
||||
* 产品特性相关,将显示在首页中
|
||||
* @returns
|
||||
*/
|
||||
export const Features = () => {
|
||||
return <>
|
||||
{/* <!-- ====== Features Section Start --> */}
|
||||
<section className="pb-8 pt-20 dark:bg-dark lg:pb-[70px] lg:pt-[120px]">
|
||||
<div className="container">
|
||||
<div className="-mx-4 flex flex-wrap">
|
||||
<div className="w-full px-4">
|
||||
<div className="mx-auto mb-12 max-w-[485px] text-center lg:mb-[70px]">
|
||||
<span className="mb-2 block text-lg font-semibold text-primary">
|
||||
{siteConfig('STARTER_FEATURE_TITLE', null, CONFIG)}
|
||||
</span>
|
||||
<h2
|
||||
className="mb-3 text-3xl font-bold text-dark dark:text-white sm:text-4xl md:text-[40px] md:leading-[1.2]"
|
||||
>
|
||||
{siteConfig('STARTER_FEATURE_TEXT_1', null, CONFIG)}
|
||||
</h2>
|
||||
<p className="text-base text-body-color dark:text-dark-6">
|
||||
{siteConfig('STARTER_FEATURE_TEXT_2', null, CONFIG)}
|
||||
</p>
|
||||
return (
|
||||
<>
|
||||
{/* <!-- ====== Features Section Start --> */}
|
||||
<section className='pb-8 pt-20 dark:bg-dark lg:pb-[70px] lg:pt-[120px]'>
|
||||
<div className='container'>
|
||||
<div className='-mx-4 flex flex-wrap'>
|
||||
<div className='w-full px-4'>
|
||||
<div className='mx-auto mb-12 max-w-[485px] text-center lg:mb-[70px]'>
|
||||
<span className='mb-2 block text-lg font-semibold text-primary'>
|
||||
{siteConfig('STARTER_FEATURE_TITLE')}
|
||||
</span>
|
||||
<h2 className='mb-3 text-3xl font-bold text-dark dark:text-white sm:text-4xl md:text-[40px] md:leading-[1.2]'>
|
||||
{siteConfig('STARTER_FEATURE_TEXT_1')}
|
||||
</h2>
|
||||
<p className='text-base text-body-color dark:text-dark-6'>
|
||||
{siteConfig('STARTER_FEATURE_TEXT_2')}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className='-mx-4 flex flex-wrap'>
|
||||
<div className='w-full px-4 md:w-1/2 lg:w-1/4'>
|
||||
<div className='wow fadeInUp group mb-12' data-wow-delay='.1s'>
|
||||
<div className='relative z-10 mb-10 flex h-[70px] w-[70px] items-center justify-center rounded-[14px] bg-primary'>
|
||||
<span className='absolute left-0 top-0 -z-[1] mb-8 flex h-[70px] w-[70px] rotate-[25deg] items-center justify-center rounded-[14px] bg-primary bg-opacity-20 duration-300 group-hover:rotate-45'></span>
|
||||
<SVGGifts />
|
||||
</div>
|
||||
<h4 className='mb-3 text-xl font-bold text-dark dark:text-white'>
|
||||
{siteConfig('STARTER_FEATURE_1_TITLE_1')}
|
||||
</h4>
|
||||
<p className='mb-8 text-body-color dark:text-dark-6 lg:mb-9'>
|
||||
{siteConfig('STARTER_FEATURE_1_TEXT_1')}
|
||||
</p>
|
||||
<Link
|
||||
href={siteConfig('STARTER_FEATURE_1_BUTTON_URL', '')}
|
||||
className='text-base font-medium text-dark hover:text-primary dark:text-white dark:hover:text-primary'>
|
||||
{siteConfig('STARTER_FEATURE_1_BUTTON_TEXT')}
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
<div className='w-full px-4 md:w-1/2 lg:w-1/4'>
|
||||
<div className='wow fadeInUp group mb-12' data-wow-delay='.15s'>
|
||||
<div className='relative z-10 mb-10 flex h-[70px] w-[70px] items-center justify-center rounded-[14px] bg-primary'>
|
||||
<span className='absolute left-0 top-0 -z-[1] mb-8 flex h-[70px] w-[70px] rotate-[25deg] items-center justify-center rounded-[14px] bg-primary bg-opacity-20 duration-300 group-hover:rotate-45'></span>
|
||||
<SVGTemplate />
|
||||
</div>
|
||||
<h4 className='mb-3 text-xl font-bold text-dark dark:text-white'>
|
||||
{siteConfig('STARTER_FEATURE_2_TITLE_1')}
|
||||
</h4>
|
||||
<p className='mb-8 text-body-color dark:text-dark-6 lg:mb-9'>
|
||||
{siteConfig('STARTER_FEATURE_2_TEXT_1')}
|
||||
</p>
|
||||
<Link
|
||||
href={siteConfig('STARTER_FEATURE_2_BUTTON_URL', '')}
|
||||
className='text-base font-medium text-dark hover:text-primary dark:text-white dark:hover:text-primary'>
|
||||
{siteConfig('STARTER_FEATURE_2_BUTTON_TEXT')}
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
<div className='w-full px-4 md:w-1/2 lg:w-1/4'>
|
||||
<div className='wow fadeInUp group mb-12' data-wow-delay='.2s'>
|
||||
<div className='relative z-10 mb-10 flex h-[70px] w-[70px] items-center justify-center rounded-[14px] bg-primary'>
|
||||
<span className='absolute left-0 top-0 -z-[1] mb-8 flex h-[70px] w-[70px] rotate-[25deg] items-center justify-center rounded-[14px] bg-primary bg-opacity-20 duration-300 group-hover:rotate-45'></span>
|
||||
<SVGDesign />
|
||||
</div>
|
||||
<h4 className='mb-3 text-xl font-bold text-dark dark:text-white'>
|
||||
{siteConfig('STARTER_FEATURE_3_TITLE_1')}
|
||||
</h4>
|
||||
<p className='mb-8 text-body-color dark:text-dark-6 lg:mb-9'>
|
||||
{siteConfig('STARTER_FEATURE_3_TEXT_1')}
|
||||
</p>
|
||||
<Link
|
||||
href={siteConfig('STARTER_FEATURE_3_BUTTON_URL', '')}
|
||||
className='text-base font-medium text-dark hover:text-primary dark:text-white dark:hover:text-primary'>
|
||||
{siteConfig('STARTER_FEATURE_3_BUTTON_TEXT')}
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
<div className='w-full px-4 md:w-1/2 lg:w-1/4'>
|
||||
<div className='wow fadeInUp group mb-12' data-wow-delay='.25s'>
|
||||
<div className='relative z-10 mb-10 flex h-[70px] w-[70px] items-center justify-center rounded-[14px] bg-primary'>
|
||||
<span className='absolute left-0 top-0 -z-[1] mb-8 flex h-[70px] w-[70px] rotate-[25deg] items-center justify-center rounded-[14px] bg-primary bg-opacity-20 duration-300 group-hover:rotate-45'></span>
|
||||
<SVGEssential />
|
||||
</div>
|
||||
<h4 className='mb-3 text-xl font-bold text-dark dark:text-white'>
|
||||
{siteConfig('STARTER_FEATURE_4_TITLE_1')}
|
||||
</h4>
|
||||
<p className='mb-8 text-body-color dark:text-dark-6 lg:mb-9'>
|
||||
{siteConfig('STARTER_FEATURE_4_TEXT_1')}
|
||||
</p>
|
||||
<Link
|
||||
href={siteConfig('STARTER_FEATURE_4_BUTTON_URL', '')}
|
||||
className='text-base font-medium text-dark hover:text-primary dark:text-white dark:hover:text-primary'>
|
||||
{siteConfig('STARTER_FEATURE_3_BUTTON_TEXT')}
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="-mx-4 flex flex-wrap">
|
||||
<div className="w-full px-4 md:w-1/2 lg:w-1/4">
|
||||
<div className="wow fadeInUp group mb-12" data-wow-delay=".1s">
|
||||
<div
|
||||
className="relative z-10 mb-10 flex h-[70px] w-[70px] items-center justify-center rounded-[14px] bg-primary"
|
||||
>
|
||||
<span
|
||||
className="absolute left-0 top-0 -z-[1] mb-8 flex h-[70px] w-[70px] rotate-[25deg] items-center justify-center rounded-[14px] bg-primary bg-opacity-20 duration-300 group-hover:rotate-45"
|
||||
></span>
|
||||
<SVGGifts/>
|
||||
</div>
|
||||
<h4 className="mb-3 text-xl font-bold text-dark dark:text-white">
|
||||
{siteConfig('STARTER_FEATURE_1_TITLE_1', null, CONFIG)}
|
||||
</h4>
|
||||
<p className="mb-8 text-body-color dark:text-dark-6 lg:mb-9">
|
||||
{siteConfig('STARTER_FEATURE_1_TEXT_1', null, CONFIG)}
|
||||
</p>
|
||||
<a
|
||||
href={siteConfig('STARTER_FEATURE_1_BUTTON_URL', null, CONFIG)}
|
||||
className="text-base font-medium text-dark hover:text-primary dark:text-white dark:hover:text-primary"
|
||||
>
|
||||
{siteConfig('STARTER_FEATURE_1_BUTTON_TEXT', null, CONFIG)}
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div className="w-full px-4 md:w-1/2 lg:w-1/4">
|
||||
<div className="wow fadeInUp group mb-12" data-wow-delay=".15s">
|
||||
<div
|
||||
className="relative z-10 mb-10 flex h-[70px] w-[70px] items-center justify-center rounded-[14px] bg-primary"
|
||||
>
|
||||
<span
|
||||
className="absolute left-0 top-0 -z-[1] mb-8 flex h-[70px] w-[70px] rotate-[25deg] items-center justify-center rounded-[14px] bg-primary bg-opacity-20 duration-300 group-hover:rotate-45"
|
||||
></span>
|
||||
<SVGTemplate/>
|
||||
</div>
|
||||
<h4 className="mb-3 text-xl font-bold text-dark dark:text-white">
|
||||
{siteConfig('STARTER_FEATURE_2_TITLE_1', null, CONFIG)}
|
||||
</h4>
|
||||
<p className="mb-8 text-body-color dark:text-dark-6 lg:mb-9">
|
||||
{siteConfig('STARTER_FEATURE_2_TEXT_1', null, CONFIG)}
|
||||
</p>
|
||||
<a
|
||||
href={siteConfig('STARTER_FEATURE_2_BUTTON_URL', null, CONFIG)}
|
||||
className="text-base font-medium text-dark hover:text-primary dark:text-white dark:hover:text-primary"
|
||||
>
|
||||
{siteConfig('STARTER_FEATURE_2_BUTTON_TEXT', null, CONFIG)}
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div className="w-full px-4 md:w-1/2 lg:w-1/4">
|
||||
<div className="wow fadeInUp group mb-12" data-wow-delay=".2s">
|
||||
<div
|
||||
className="relative z-10 mb-10 flex h-[70px] w-[70px] items-center justify-center rounded-[14px] bg-primary"
|
||||
>
|
||||
<span
|
||||
className="absolute left-0 top-0 -z-[1] mb-8 flex h-[70px] w-[70px] rotate-[25deg] items-center justify-center rounded-[14px] bg-primary bg-opacity-20 duration-300 group-hover:rotate-45"
|
||||
></span>
|
||||
<SVGDesign/>
|
||||
</div>
|
||||
<h4 className="mb-3 text-xl font-bold text-dark dark:text-white">
|
||||
{siteConfig('STARTER_FEATURE_3_TITLE_1', null, CONFIG)}
|
||||
</h4>
|
||||
<p className="mb-8 text-body-color dark:text-dark-6 lg:mb-9">
|
||||
{siteConfig('STARTER_FEATURE_3_TEXT_1', null, CONFIG)}
|
||||
</p>
|
||||
<a
|
||||
href={siteConfig('STARTER_FEATURE_3_BUTTON_URL', null, CONFIG)}
|
||||
className="text-base font-medium text-dark hover:text-primary dark:text-white dark:hover:text-primary"
|
||||
>
|
||||
{siteConfig('STARTER_FEATURE_3_BUTTON_TEXT', null, CONFIG)}
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div className="w-full px-4 md:w-1/2 lg:w-1/4">
|
||||
<div className="wow fadeInUp group mb-12" data-wow-delay=".25s">
|
||||
<div
|
||||
className="relative z-10 mb-10 flex h-[70px] w-[70px] items-center justify-center rounded-[14px] bg-primary"
|
||||
>
|
||||
<span
|
||||
className="absolute left-0 top-0 -z-[1] mb-8 flex h-[70px] w-[70px] rotate-[25deg] items-center justify-center rounded-[14px] bg-primary bg-opacity-20 duration-300 group-hover:rotate-45"
|
||||
></span>
|
||||
<SVGEssential/>
|
||||
</div>
|
||||
<h4 className="mb-3 text-xl font-bold text-dark dark:text-white">
|
||||
{siteConfig('STARTER_FEATURE_4_TITLE_1', null, CONFIG)}
|
||||
</h4>
|
||||
<p className="mb-8 text-body-color dark:text-dark-6 lg:mb-9">
|
||||
{siteConfig('STARTER_FEATURE_4_TEXT_1', null, CONFIG)}
|
||||
</p>
|
||||
<a
|
||||
href={siteConfig('STARTER_FEATURE_4_BUTTON_URL', null, CONFIG)}
|
||||
className="text-base font-medium text-dark hover:text-primary dark:text-white dark:hover:text-primary"
|
||||
>
|
||||
{siteConfig('STARTER_FEATURE_3_BUTTON_TEXT', null, CONFIG)}
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
{/* <!-- ====== Features Section End --> */}
|
||||
</section>
|
||||
{/* <!-- ====== Features Section End --> */}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,17 +1,16 @@
|
||||
import { siteConfig } from '@/lib/config'
|
||||
import SocialButton from '@/themes/fukasawa/components/SocialButton'
|
||||
import CONFIG from '../config'
|
||||
import { Logo } from './Logo'
|
||||
import { SVGFooterCircleBG } from './svg/SVGFooterCircleBG'
|
||||
import Link from 'next/link'
|
||||
|
||||
/* eslint-disable @next/next/no-img-element */
|
||||
export const Footer = props => {
|
||||
const latestPosts = props?.latestPosts ? props?.latestPosts.slice(0, 2) : []
|
||||
const STARTER_FOOTER_LINK_GROUP = siteConfig(
|
||||
'STARTER_FOOTER_LINK_GROUP',
|
||||
[],
|
||||
CONFIG
|
||||
)
|
||||
const footerPostCount = siteConfig('STARTER_FOOTER_POST_COUNT', 2)
|
||||
const latestPosts = props?.latestPosts
|
||||
? props?.latestPosts.slice(0, footerPostCount)
|
||||
: []
|
||||
const STARTER_FOOTER_LINK_GROUP = siteConfig('STARTER_FOOTER_LINK_GROUP', [])
|
||||
return (
|
||||
<>
|
||||
{/* <!-- ====== Footer Section Start --> */}
|
||||
@@ -26,7 +25,7 @@ export const Footer = props => {
|
||||
<Logo white={true} />
|
||||
</a>
|
||||
<p className='mb-8 max-w-[270px] text-base text-gray-7'>
|
||||
{siteConfig('STARTER_FOOTER_SLOGAN', null, CONFIG)}
|
||||
{siteConfig('STARTER_FOOTER_SLOGAN')}
|
||||
</p>
|
||||
<div className='-mx-3 flex items-center'>
|
||||
<div className='mx-3'>
|
||||
@@ -50,11 +49,11 @@ export const Footer = props => {
|
||||
{item?.LINK_GROUP?.map((l, i) => {
|
||||
return (
|
||||
<li key={i}>
|
||||
<a
|
||||
<Link
|
||||
href={l.URL}
|
||||
className='mb-3 inline-block text-base text-gray-7 hover:text-primary'>
|
||||
{l.TITLE}
|
||||
</a>
|
||||
</Link>
|
||||
</li>
|
||||
)
|
||||
})}
|
||||
@@ -68,23 +67,28 @@ export const Footer = props => {
|
||||
<div className='w-full px-4 md:w-2/3 lg:w-6/12 xl:w-3/12'>
|
||||
<div className='mb-10 w-full'>
|
||||
<h4 className='mb-9 text-lg font-semibold text-white'>
|
||||
{siteConfig('STARTER_FOOTER_BLOG_LATEST_TITLE', null, CONFIG)}
|
||||
{siteConfig('STARTER_FOOTER_BLOG_LATEST_TITLE')}
|
||||
</h4>
|
||||
{/* 展示两条最新博客文章 */}
|
||||
<div className='flex flex-col gap-8'>
|
||||
{latestPosts?.map((item, index) => {
|
||||
return (
|
||||
<a
|
||||
<Link
|
||||
key={index}
|
||||
href={item?.href}
|
||||
className='group flex items-center gap-[22px]'>
|
||||
<div className='overflow-hidden rounded w-20 h-12'>
|
||||
<img src={item.pageCoverThumbnail} alt={item.title} />
|
||||
</div>
|
||||
{item.pageCoverThumbnail && (
|
||||
<div className='overflow-hidden rounded w-20 h-12'>
|
||||
<img
|
||||
src={item.pageCoverThumbnail}
|
||||
alt={item.title}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
<span className='line-clamp-2 max-w-[180px] text-base text-gray-7 group-hover:text-white'>
|
||||
{item.title}
|
||||
</span>
|
||||
</a>
|
||||
</Link>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
@@ -101,45 +105,27 @@ export const Footer = props => {
|
||||
<div className='w-full px-4 md:w-2/3 lg:w-1/2'>
|
||||
<div className='my-1'>
|
||||
<div className='-mx-3 flex items-center justify-center md:justify-start'>
|
||||
<a
|
||||
<Link
|
||||
href={siteConfig('STARTER_FOOTER_PRIVACY_POLICY_URL', '')}
|
||||
className='px-3 text-base text-gray-7 hover:text-white hover:underline'>
|
||||
{siteConfig('STARTER_FOOTER_PRIVACY_POLICY_TEXT')}
|
||||
</Link>
|
||||
<Link
|
||||
href={siteConfig(
|
||||
'STARTER_FOOTER_PRIVACY_POLICY_URL',
|
||||
null,
|
||||
CONFIG
|
||||
'STARTER_FOOTER_PRIVACY_LEGAL_NOTICE_URL', ''
|
||||
)}
|
||||
className='px-3 text-base text-gray-7 hover:text-white hover:underline'>
|
||||
{siteConfig('STARTER_FOOTER_PRIVACY_LEGAL_NOTICE_TEXT')}
|
||||
</Link>
|
||||
<Link
|
||||
href={siteConfig(
|
||||
'STARTER_FOOTER_PRIVACY_TERMS_OF_SERVICE_URL', ''
|
||||
)}
|
||||
className='px-3 text-base text-gray-7 hover:text-white hover:underline'>
|
||||
{siteConfig(
|
||||
'STARTER_FOOTER_PRIVACY_POLICY_TEXT',
|
||||
null,
|
||||
CONFIG
|
||||
'STARTER_FOOTER_PRIVACY_TERMS_OF_SERVICE_TEXT', ''
|
||||
)}
|
||||
</a>
|
||||
<a
|
||||
href={siteConfig(
|
||||
'STARTER_FOOTER_PRIVACY_LEGAL_NOTICE_URL',
|
||||
null,
|
||||
CONFIG
|
||||
)}
|
||||
className='px-3 text-base text-gray-7 hover:text-white hover:underline'>
|
||||
{siteConfig(
|
||||
'STARTER_FOOTER_PRIVACY_LEGAL_NOTICE_TEXT',
|
||||
null,
|
||||
CONFIG
|
||||
)}
|
||||
</a>
|
||||
<a
|
||||
href={siteConfig(
|
||||
'STARTER_FOOTER_PRIVACY_TERMS_OF_SERVICE_URL',
|
||||
null,
|
||||
CONFIG
|
||||
)}
|
||||
className='px-3 text-base text-gray-7 hover:text-white hover:underline'>
|
||||
{siteConfig(
|
||||
'STARTER_FOOTER_PRIVACY_TERMS_OF_SERVICE_TEXT',
|
||||
null,
|
||||
CONFIG
|
||||
)}
|
||||
</a>
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
117
themes/starter/components/Header.js
Normal file
117
themes/starter/components/Header.js
Normal file
@@ -0,0 +1,117 @@
|
||||
/* eslint-disable no-unreachable */
|
||||
import DashboardButton from '@/components/ui/dashboard/DashboardButton'
|
||||
import { siteConfig } from '@/lib/config'
|
||||
import { useGlobal } from '@/lib/global'
|
||||
import { SignedIn, SignedOut, UserButton } from '@clerk/nextjs'
|
||||
import throttle from 'lodash.throttle'
|
||||
import Link from 'next/link'
|
||||
import { useRouter } from 'next/router'
|
||||
import { useCallback, useEffect, useState } from 'react'
|
||||
import { DarkModeButton } from './DarkModeButton'
|
||||
import { Logo } from './Logo'
|
||||
import { MenuList } from './MenuList'
|
||||
|
||||
/**
|
||||
* 顶部导航栏
|
||||
*/
|
||||
export const Header = props => {
|
||||
const router = useRouter()
|
||||
const { isDarkMode } = useGlobal()
|
||||
const [buttonTextColor, setColor] = useState(
|
||||
router.route === '/' ? 'text-white' : ''
|
||||
)
|
||||
|
||||
const enableClerk = process.env.NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY
|
||||
|
||||
useEffect(() => {
|
||||
if (isDarkMode || router.route === '/') {
|
||||
setColor('text-white')
|
||||
} else {
|
||||
setColor('')
|
||||
}
|
||||
// ======= Sticky
|
||||
window.addEventListener('scroll', navBarScollListener)
|
||||
return () => {
|
||||
window.removeEventListener('scroll', navBarScollListener)
|
||||
}
|
||||
}, [isDarkMode])
|
||||
|
||||
// 滚动监听
|
||||
const throttleMs = 200
|
||||
const navBarScollListener = useCallback(
|
||||
throttle(() => {
|
||||
// eslint-disable-next-line camelcase
|
||||
const ud_header = document.querySelector('.ud-header')
|
||||
const scrollY = window.scrollY
|
||||
// 控制台输出当前滚动位置和 sticky 值
|
||||
if (scrollY > 0) {
|
||||
ud_header?.classList?.add('sticky')
|
||||
} else {
|
||||
ud_header?.classList?.remove('sticky')
|
||||
}
|
||||
}, throttleMs)
|
||||
)
|
||||
|
||||
return (
|
||||
<>
|
||||
{/* <!-- ====== Navbar Section Start --> */}
|
||||
<div className='ud-header absolute left-0 top-0 z-40 flex w-full items-center bg-transparent'>
|
||||
<div className='container'>
|
||||
<div className='relative -mx-4 flex items-center justify-between'>
|
||||
{/* Logo */}
|
||||
<Logo {...props} />
|
||||
|
||||
<div className='flex w-full items-center justify-between px-4'>
|
||||
{/* 中间菜单 */}
|
||||
<MenuList {...props} />
|
||||
|
||||
{/* 右侧功能 */}
|
||||
<div className='flex items-center gap-4 justify-end pr-16 lg:pr-0'>
|
||||
{/* 深色模式切换 */}
|
||||
<DarkModeButton />
|
||||
{/* 注册登录功能 */}
|
||||
{enableClerk && (
|
||||
<>
|
||||
<SignedOut>
|
||||
<div className='hidden sm:flex gap-4'>
|
||||
<Link
|
||||
href={siteConfig('STARTER_NAV_BUTTON_1_URL', '')}
|
||||
className={`loginBtn ${buttonTextColor} p-2 text-base font-medium hover:opacity-70`}>
|
||||
{siteConfig('STARTER_NAV_BUTTON_1_TEXT')}
|
||||
</Link>
|
||||
<Link
|
||||
href={siteConfig('STARTER_NAV_BUTTON_2_URL', '')}
|
||||
className={`signUpBtn ${buttonTextColor} p-2 rounded-md bg-white bg-opacity-20 py-2 text-base font-medium duration-300 ease-in-out hover:bg-opacity-100 hover:text-dark`}>
|
||||
{siteConfig('STARTER_NAV_BUTTON_2_TEXT')}
|
||||
</Link>
|
||||
</div>
|
||||
</SignedOut>
|
||||
<SignedIn>
|
||||
<UserButton />
|
||||
<DashboardButton className={'hidden md:block'} />
|
||||
</SignedIn>
|
||||
</>
|
||||
)}
|
||||
{!enableClerk && (
|
||||
<div className='hidden sm:flex gap-4'>
|
||||
<Link
|
||||
href={siteConfig('STARTER_NAV_BUTTON_1_URL', '')}
|
||||
className={`loginBtn ${buttonTextColor} p-2 text-base font-medium hover:opacity-70`}>
|
||||
{siteConfig('STARTER_NAV_BUTTON_1_TEXT')}
|
||||
</Link>
|
||||
<Link
|
||||
href={siteConfig('STARTER_NAV_BUTTON_2_URL', '')}
|
||||
className={`signUpBtn ${buttonTextColor} p-2 rounded-md bg-white bg-opacity-20 py-2 text-base font-medium duration-300 ease-in-out hover:bg-opacity-100 hover:text-dark`}>
|
||||
{siteConfig('STARTER_NAV_BUTTON_2_TEXT')}
|
||||
</Link>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/* <!-- ====== Navbar Section End --> */}
|
||||
</>
|
||||
)
|
||||
}
|
||||
@@ -1,96 +1,125 @@
|
||||
/* eslint-disable @next/next/no-img-element */
|
||||
import LazyImage from '@/components/LazyImage'
|
||||
import { siteConfig } from '@/lib/config'
|
||||
import CONFIG from '../config'
|
||||
import Link from 'next/link'
|
||||
|
||||
/**
|
||||
* 英雄大图区块
|
||||
*/
|
||||
export const Hero = () => {
|
||||
return <>
|
||||
{/* <!-- ====== Hero Section Start --> */}
|
||||
<div
|
||||
id="home"
|
||||
className="relative overflow-hidden bg-primary pt-[120px] md:pt-[130px] lg:pt-[160px]"
|
||||
>
|
||||
<div className="container">
|
||||
<div className="-mx-4 flex flex-wrap items-center">
|
||||
<div className="w-full px-4">
|
||||
<div
|
||||
className="hero-content wow fadeInUp mx-auto max-w-[780px] text-center"
|
||||
data-wow-delay=".2s"
|
||||
>
|
||||
{/* 主标题 */}
|
||||
<h1
|
||||
className="mb-6 text-3xl font-bold leading-snug text-white sm:text-4xl sm:leading-snug lg:text-5xl lg:leading-[1.2]"
|
||||
>
|
||||
{siteConfig('STARTER_HERO_TITLE_1', null, CONFIG)}
|
||||
</h1>
|
||||
{/* 次标题 */}
|
||||
<p
|
||||
className="mx-auto mb-9 max-w-[600px] text-base font-medium text-white sm:text-lg sm:leading-[1.44]"
|
||||
>
|
||||
{siteConfig('STARTER_HERO_TITLE_2', null, CONFIG)}
|
||||
</p>
|
||||
{/* 按钮组 */}
|
||||
<ul
|
||||
className="mb-10 flex flex-wrap items-center justify-center gap-5"
|
||||
>
|
||||
{siteConfig('STARTER_HERO_BUTTON_1_TEXT', null, CONFIG) &&
|
||||
<li>
|
||||
<a
|
||||
href={siteConfig('STARTER_HERO_BUTTON_1_URL', null, CONFIG)}
|
||||
className="inline-flex items-center justify-center rounded-md bg-white px-7 py-[14px] text-center text-base font-medium text-dark shadow-1 transition duration-300 ease-in-out hover:bg-gray-2 hover:text-body-color"
|
||||
>
|
||||
{siteConfig('STARTER_HERO_BUTTON_1_TEXT', null, CONFIG)}
|
||||
</a>
|
||||
</li>
|
||||
}
|
||||
{siteConfig('STARTER_HERO_BUTTON_2_TEXT', null, CONFIG) &&
|
||||
<li>
|
||||
<a
|
||||
href={siteConfig('STARTER_HERO_BUTTON_2_URL', null, CONFIG)}
|
||||
target="_blank"
|
||||
className="flex items-center rounded-md bg-white/[0.12] px-6 py-[14px] text-base font-medium text-white transition duration-300 ease-in-out hover:bg-white hover:text-dark" rel="noreferrer"
|
||||
>
|
||||
{siteConfig('STARTER_HERO_BUTTON_2_ICON', null, CONFIG) && <img className='mr-4' src={siteConfig('STARTER_HERO_BUTTON_2_ICON', null, CONFIG)}/>}
|
||||
{siteConfig('STARTER_HERO_BUTTON_2_TEXT', null, CONFIG)}
|
||||
</a>
|
||||
</li>
|
||||
}
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 产品预览图片 */}
|
||||
{ siteConfig('STARTER_HERO_PREVIEW_IMAGE', null, CONFIG) && <div className="w-full px-4">
|
||||
<div
|
||||
className="wow fadeInUp relative z-10 mx-auto max-w-[845px]"
|
||||
data-wow-delay=".25s"
|
||||
>
|
||||
|
||||
<div className="mt-16">
|
||||
{/* eslint-disable-next-line @next/next/no-img-element */}
|
||||
<img
|
||||
src={siteConfig('STARTER_HERO_PREVIEW_IMAGE', null, CONFIG)}
|
||||
alt="hero"
|
||||
className="mx-auto max-w-full rounded-t-xl rounded-tr-xl"
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* 背景图 */}
|
||||
<div className="absolute -left-9 bottom-0 z-[-1]">
|
||||
<img src='/images/starter/bg-hero-circle.svg'/>
|
||||
</div>
|
||||
<div className="absolute -right-6 -top-6 z-[-1]">
|
||||
<img src='/images/starter/bg-hero-circle.svg'/>
|
||||
export const Hero = props => {
|
||||
const config = props?.NOTION_CONFIG || CONFIG
|
||||
return (
|
||||
<>
|
||||
{/* <!-- ====== Hero Section Start --> */}
|
||||
<div
|
||||
id='home'
|
||||
className='relative overflow-hidden bg-primary pt-[120px] md:pt-[130px] lg:pt-[160px]'>
|
||||
<div className='container'>
|
||||
<div className='-mx-4 flex flex-wrap items-center'>
|
||||
<div className='w-full px-4'>
|
||||
<div
|
||||
className='hero-content wow fadeInUp mx-auto max-w-[780px] text-center'
|
||||
data-wow-delay='.2s'>
|
||||
{/* 主标题 */}
|
||||
<h1 className='mb-6 text-3xl font-bold leading-snug text-white sm:text-4xl sm:leading-snug lg:text-5xl lg:leading-[1.2]'>
|
||||
{siteConfig('STARTER_HERO_TITLE_1', null, config)}
|
||||
</h1>
|
||||
{/* 次标题 */}
|
||||
<p className='mx-auto mb-9 max-w-[600px] text-base font-medium text-white sm:text-lg sm:leading-[1.44]'>
|
||||
{siteConfig('STARTER_HERO_TITLE_2', null, config)}
|
||||
</p>
|
||||
{/* 按钮组 */}
|
||||
<ul className='mb-10 flex flex-wrap items-center justify-center gap-5'>
|
||||
{siteConfig('STARTER_HERO_BUTTON_1_TEXT', null, config) && (
|
||||
<li>
|
||||
<Link
|
||||
href={siteConfig('STARTER_HERO_BUTTON_1_URL', '')}
|
||||
className='inline-flex items-center justify-center rounded-md bg-white px-7 py-[14px] text-center text-base font-medium text-dark shadow-1 transition duration-300 ease-in-out hover:bg-gray-2 hover:text-body-color'>
|
||||
{siteConfig('STARTER_HERO_BUTTON_1_TEXT', null, config)}
|
||||
</Link>
|
||||
</li>
|
||||
)}
|
||||
{siteConfig('STARTER_HERO_BUTTON_2_TEXT', null, config) && (
|
||||
<li>
|
||||
<Link
|
||||
href={siteConfig(
|
||||
'STARTER_HERO_BUTTON_2_URL',
|
||||
null,
|
||||
config
|
||||
)}
|
||||
target='_blank'
|
||||
className='flex items-center rounded-md bg-white/[0.12] px-6 py-[14px] text-base font-medium text-white transition duration-300 ease-in-out hover:bg-white hover:text-dark'
|
||||
rel='noreferrer'>
|
||||
{siteConfig(
|
||||
'STARTER_HERO_BUTTON_2_ICON',
|
||||
null,
|
||||
config
|
||||
) && (
|
||||
<img
|
||||
className='mr-4'
|
||||
src={siteConfig(
|
||||
'STARTER_HERO_BUTTON_2_ICON',
|
||||
null,
|
||||
config
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
{siteConfig('STARTER_HERO_BUTTON_2_TEXT', null, config)}
|
||||
</Link>
|
||||
</li>
|
||||
)}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
{/* 产品预览图片 */}
|
||||
{siteConfig('STARTER_HERO_PREVIEW_IMAGE', null, config) && (
|
||||
<div className='w-full px-4'>
|
||||
<div
|
||||
className='wow fadeInUp relative z-10 mx-auto max-w-[845px]'
|
||||
data-wow-delay='.25s'>
|
||||
<div className='mt-16'>
|
||||
{/* eslint-disable-next-line @next/next/no-img-element */}
|
||||
<img
|
||||
src={siteConfig(
|
||||
'STARTER_HERO_PREVIEW_IMAGE',
|
||||
null,
|
||||
config
|
||||
)}
|
||||
alt={siteConfig('TITLE', null, config)}
|
||||
title={siteConfig('TITLE', null, config)}
|
||||
className='mx-auto max-w-full rounded-t-xl rounded-tr-xl'
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* 背景图 */}
|
||||
<div className='absolute -left-9 bottom-0 z-[-1]'>
|
||||
<img src='/images/starter/bg-hero-circle.svg' />
|
||||
</div>
|
||||
<div className='absolute -right-6 -top-6 z-[-1]'>
|
||||
<img src='/images/starter/bg-hero-circle.svg' />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/* <!-- ====== Hero Section End --> */}
|
||||
{/* 横幅图片 */}
|
||||
{siteConfig('STARTER_HERO_BANNER_IMAGE', null, config) && (
|
||||
<div className='container'>
|
||||
<LazyImage
|
||||
priority
|
||||
className='w-full'
|
||||
src={siteConfig(
|
||||
'STARTER_HERO_BANNER_IMAGE',
|
||||
null,
|
||||
config
|
||||
)}></LazyImage>
|
||||
</div>
|
||||
)}
|
||||
{/* <!-- ====== Hero Section End --> */}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,20 +1,22 @@
|
||||
/* eslint-disable @next/next/no-img-element */
|
||||
/* eslint-disable @next/next/no-html-link-for-pages */
|
||||
import LazyImage from '@/components/LazyImage'
|
||||
import { siteConfig } from '@/lib/config'
|
||||
import { useGlobal } from '@/lib/global'
|
||||
import throttle from 'lodash.throttle'
|
||||
import { useRouter } from 'next/router'
|
||||
import { useEffect, useState } from 'react'
|
||||
import CONFIG from '../config'
|
||||
|
||||
/**
|
||||
* 站点图标
|
||||
* @returns
|
||||
*/
|
||||
export const Logo = ({ white }) => {
|
||||
export const Logo = props => {
|
||||
const { white, NOTION_CONFIG } = props
|
||||
const router = useRouter()
|
||||
const logoWhite = siteConfig('STARTER_LOGO_WHITE')
|
||||
const logoNormal = siteConfig('STARTER_LOGO')
|
||||
const { isDarkMode } = useGlobal()
|
||||
const logoWhite = siteConfig('STARTER_LOGO_WHITE', null, CONFIG)
|
||||
const [logo, setLogo] = useState(logoWhite)
|
||||
const [logoTextColor, setLogoTextColor] = useState('text-white')
|
||||
|
||||
@@ -25,11 +27,12 @@ export const Logo = ({ white }) => {
|
||||
const scrollY = window.scrollY
|
||||
// 何时显示浅色或白底的logo
|
||||
const homePageNavBar = router.route === '/' && scrollY < 10 // 在首页并且视窗在页面顶部
|
||||
|
||||
if (white || isDarkMode || homePageNavBar) {
|
||||
setLogo(siteConfig('STARTER_LOGO_WHITE', null, CONFIG))
|
||||
setLogo(logoWhite)
|
||||
setLogoTextColor('text-white')
|
||||
} else {
|
||||
setLogo(siteConfig('STARTER_LOGO', null, CONFIG))
|
||||
setLogo(logoNormal)
|
||||
setLogoTextColor('text-black')
|
||||
}
|
||||
}, throttleMs)
|
||||
@@ -46,13 +49,14 @@ export const Logo = ({ white }) => {
|
||||
<div className='navbar-logo flex items-center w-full py-5 cursor-pointer'>
|
||||
{/* eslint-disable-next-line @next/next/no-img-element */}
|
||||
{logo && (
|
||||
<img
|
||||
<LazyImage
|
||||
priority
|
||||
onClick={() => {
|
||||
router.push('/')
|
||||
}}
|
||||
src={logo}
|
||||
alt='logo'
|
||||
className='header-logo w-full'
|
||||
className='header-logo mr-1 h-8'
|
||||
/>
|
||||
)}
|
||||
{/* logo文字 */}
|
||||
@@ -60,7 +64,7 @@ export const Logo = ({ white }) => {
|
||||
onClick={() => {
|
||||
router.push('/')
|
||||
}}
|
||||
className={`${logoTextColor} dark:text-white py-1.5 header-logo-text whitespace-nowrap text-2xl font-semibold`}>
|
||||
className={`${logoTextColor} logo dark:text-white py-1.5 header-logo-text whitespace-nowrap text-2xl font-semibold`}>
|
||||
{siteConfig('TITLE')}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
@@ -1,31 +1,56 @@
|
||||
import Link from 'next/link'
|
||||
import { useRouter } from 'next/router'
|
||||
import { useState } from 'react'
|
||||
|
||||
/**
|
||||
* 菜单链接
|
||||
* @param {*} param0
|
||||
* @returns
|
||||
*/
|
||||
export const MenuItem = ({ link }) => {
|
||||
const hasSubMenu = link?.subMenus?.length > 0
|
||||
const router = useRouter()
|
||||
|
||||
// 管理子菜单的展开状态
|
||||
const [isSubMenuOpen, setIsSubMenuOpen] = useState(false)
|
||||
|
||||
const toggleSubMenu = () => {
|
||||
setIsSubMenuOpen(prev => !prev) // 切换子菜单状态
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
{/* MenuItem */}
|
||||
{/* 普通 MenuItem */}
|
||||
{!hasSubMenu && (
|
||||
<li className='group relative whitespace-nowrap'>
|
||||
<Link
|
||||
href={link?.href}
|
||||
target={link?.target}
|
||||
className={`ud-menu-scroll mx-8 flex py-2 text-base font-medium text-dark group-hover:text-primary dark:text-white lg:mr-0 lg:inline-flex lg:px-0 lg:py-6 ${router.route === '/' ? 'lg:text-white lg:group-hover:text-white' : ''} lg:group-hover:opacity-70`}>
|
||||
className={`ud-menu-scroll mx-8 flex py-2 text-base font-medium text-dark group-hover:text-primary dark:text-white lg:mr-0 lg:inline-flex lg:px-0 lg:py-6 ${
|
||||
router.route === '/'
|
||||
? 'lg:text-white lg:group-hover:text-white'
|
||||
: ''
|
||||
} lg:group-hover:opacity-70`}>
|
||||
{link?.icon && <i className={link.icon + ' mr-2 my-auto'} />}
|
||||
{link?.name}
|
||||
</Link>
|
||||
</li>
|
||||
)}
|
||||
|
||||
{/* 有子菜单的 MenuItem */}
|
||||
{hasSubMenu && (
|
||||
<li className='submenu-item group relative whitespace-nowrap'>
|
||||
{/* 有子菜单的MenuItem */}
|
||||
<a
|
||||
className={`relative mx-8 flex items-center justify-between py-2 text-base font-medium text-dark group-hover:text-primary dark:text-white lg:ml-8 lg:mr-0 lg:inline-flex lg:py-6 lg:pl-0 lg:pr-4 ${router.route === '/' ? 'lg:text-white lg:group-hover:text-white' : ''} lg:group-hover:opacity-70 xl:ml-10`}>
|
||||
{link?.icon && <i className={link.icon + ' mr-2 my-auto'} />}
|
||||
{link?.name}
|
||||
<button
|
||||
onClick={toggleSubMenu}
|
||||
className={`cursor-pointer relative px-8 flex items-center justify-between py-2 text-base font-medium text-dark group-hover:text-primary dark:text-white lg:ml-8 lg:mr-0 lg:inline-flex lg:py-6 lg:pl-0 lg:pr-4 ${
|
||||
router.route === '/'
|
||||
? 'lg:text-white lg:group-hover:text-white'
|
||||
: ''
|
||||
} lg:group-hover:opacity-70 xl:ml-10`}>
|
||||
<span>
|
||||
{link?.icon && <i className={link.icon + ' mr-2 my-auto'} />}
|
||||
{link?.name}
|
||||
</span>
|
||||
|
||||
<svg
|
||||
className='ml-2 fill-current'
|
||||
@@ -36,26 +61,28 @@ export const MenuItem = ({ link }) => {
|
||||
xmlns='http://www.w3.org/2000/svg'>
|
||||
<path d='M7.99999 14.9C7.84999 14.9 7.72499 14.85 7.59999 14.75L1.84999 9.10005C1.62499 8.87505 1.62499 8.52505 1.84999 8.30005C2.07499 8.07505 2.42499 8.07505 2.64999 8.30005L7.99999 13.525L13.35 8.25005C13.575 8.02505 13.925 8.02505 14.15 8.25005C14.375 8.47505 14.375 8.82505 14.15 9.05005L8.39999 14.7C8.27499 14.825 8.14999 14.9 7.99999 14.9Z' />
|
||||
</svg>
|
||||
</a>
|
||||
</button>
|
||||
|
||||
<div className='submenu relative left-0 top-full hidden w-[250px] rounded-sm bg-white p-4 transition-[top] duration-300 group-hover:opacity-100 dark:bg-dark-2 lg:invisible lg:absolute lg:top-[110%] lg:block lg:opacity-0 lg:shadow-lg lg:group-hover:visible lg:group-hover:top-full'>
|
||||
{link.subMenus.map((sLink, index) => {
|
||||
return (
|
||||
<Link
|
||||
key={index}
|
||||
href={sLink.href}
|
||||
target={link?.target}
|
||||
className='block rounded px-4 py-[10px] text-sm text-body-color hover:text-primary dark:text-dark-6 dark:hover:text-primary'>
|
||||
{/* 子菜单SubMenuItem */}
|
||||
<span className='text-sm ml-4 whitespace-nowrap'>
|
||||
{link?.icon && (
|
||||
<i className={sLink.icon + ' mr-2 my-auto'} />
|
||||
)}{' '}
|
||||
{sLink.title}
|
||||
</span>
|
||||
</Link>
|
||||
)
|
||||
})}
|
||||
{/* 子菜单 */}
|
||||
<div
|
||||
className={`submenu dark:border-gray-600 relative left-0 top-full w-[250px] rounded-sm bg-white p-4 transition-all duration-300 dark:bg-dark-2 lg:absolute lg:shadow-lg ${
|
||||
isSubMenuOpen
|
||||
? 'block opacity-100 visible'
|
||||
: 'hidden opacity-0 invisible'
|
||||
}`}>
|
||||
{link.subMenus.map((sLink, index) => (
|
||||
<Link
|
||||
key={index}
|
||||
href={sLink.href}
|
||||
target={link?.target}
|
||||
className='block rounded px-4 py-[10px] text-sm text-body-color hover:text-primary dark:text-dark-6 dark:hover:text-primary'>
|
||||
{/* 子菜单 SubMenuItem */}
|
||||
<span className='text-md ml-2 whitespace-nowrap'>
|
||||
{link?.icon && <i className={sLink.icon + ' mr-2 my-auto'} />}{' '}
|
||||
{sLink.title}
|
||||
</span>
|
||||
</Link>
|
||||
))}
|
||||
</div>
|
||||
</li>
|
||||
)}
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
import BLOG from '@/blog.config'
|
||||
import { siteConfig } from '@/lib/config'
|
||||
import { useGlobal } from '@/lib/global'
|
||||
import { useEffect } from 'react'
|
||||
import CONFIG from '../config'
|
||||
import { useRouter } from 'next/router'
|
||||
import { useEffect, useState } from 'react'
|
||||
import { MenuItem } from './MenuItem'
|
||||
|
||||
/**
|
||||
* 响应式 折叠菜单
|
||||
*/
|
||||
@@ -10,30 +12,33 @@ export const MenuList = props => {
|
||||
const { customNav, customMenu } = props
|
||||
const { locale } = useGlobal()
|
||||
|
||||
const [showMenu, setShowMenu] = useState(false) // 控制菜单展开/收起状态
|
||||
const router = useRouter()
|
||||
|
||||
let links = [
|
||||
{
|
||||
icon: 'fas fa-archive',
|
||||
name: locale.NAV.ARCHIVE,
|
||||
href: '/archive',
|
||||
show: siteConfig('HEO_MENU_ARCHIVE', null, CONFIG)
|
||||
show: siteConfig('HEO_MENU_ARCHIVE')
|
||||
},
|
||||
{
|
||||
icon: 'fas fa-search',
|
||||
name: locale.NAV.SEARCH,
|
||||
href: '/search',
|
||||
show: siteConfig('HEO_MENU_SEARCH', null, CONFIG)
|
||||
show: siteConfig('HEO_MENU_SEARCH')
|
||||
},
|
||||
{
|
||||
icon: 'fas fa-folder',
|
||||
name: locale.COMMON.CATEGORY,
|
||||
href: '/category',
|
||||
show: siteConfig('HEO_MENU_CATEGORY', null, CONFIG)
|
||||
show: siteConfig('HEO_MENU_CATEGORY')
|
||||
},
|
||||
{
|
||||
icon: 'fas fa-tag',
|
||||
name: locale.COMMON.TAGS,
|
||||
href: '/tag',
|
||||
show: siteConfig('HEO_MENU_TAG', null, CONFIG)
|
||||
show: siteConfig('HEO_MENU_TAG')
|
||||
}
|
||||
]
|
||||
|
||||
@@ -41,68 +46,48 @@ export const MenuList = props => {
|
||||
links = customNav.concat(links)
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
// ===== responsive navbar
|
||||
const navbarToggler = document.querySelector('#navbarToggler')
|
||||
const navbarCollapse = document.querySelector('#navbarCollapse')
|
||||
|
||||
// 点击弹出菜单
|
||||
navbarToggler?.addEventListener('click', () => {
|
||||
navbarToggler?.classList.toggle('navbarTogglerActive')
|
||||
navbarCollapse?.classList.toggle('hidden')
|
||||
})
|
||||
|
||||
//= ==== close navbar-collapse when a clicked
|
||||
document
|
||||
.querySelectorAll('#navbarCollapse ul li:not(.submenu-item) a')
|
||||
.forEach(e =>
|
||||
e.addEventListener('click', () => {
|
||||
navbarToggler?.classList.remove('navbarTogglerActive')
|
||||
navbarCollapse?.classList.add('hidden')
|
||||
})
|
||||
)
|
||||
|
||||
// ===== Sub-menu
|
||||
const submenuItems = document.querySelectorAll('.submenu-item')
|
||||
submenuItems.forEach(el => {
|
||||
el.querySelector('a')?.addEventListener('click', () => {
|
||||
el.querySelector('.submenu')?.classList.toggle('hidden')
|
||||
})
|
||||
})
|
||||
}, [])
|
||||
|
||||
// 如果 开启自定义菜单,则覆盖Page生成的菜单
|
||||
if (siteConfig('CUSTOM_MENU')) {
|
||||
if (siteConfig('CUSTOM_MENU', BLOG.CUSTOM_MENU)) {
|
||||
links = customMenu
|
||||
}
|
||||
|
||||
// if (!links || links.length === 0) {
|
||||
// return null
|
||||
// }
|
||||
if (!links || links.length === 0) {
|
||||
return null
|
||||
}
|
||||
|
||||
const toggleMenu = () => {
|
||||
setShowMenu(!showMenu) // 切换菜单状态
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
setShowMenu(false)
|
||||
}, [router])
|
||||
|
||||
return (
|
||||
<>
|
||||
<div>
|
||||
{/* 移动端菜单切换按钮 */}
|
||||
<button
|
||||
id='navbarToggler'
|
||||
className='absolute right-4 top-1/2 block -translate-y-1/2 rounded-lg px-3 py-[6px] ring-primary focus:ring-2 lg:hidden'>
|
||||
<span className='relative my-[6px] block h-[2px] w-[30px] bg-white duration-200 transition-all'></span>
|
||||
<span className='relative my-[6px] block h-[2px] w-[30px] bg-white duration-200 transition-all'></span>
|
||||
<span className='relative my-[6px] block h-[2px] w-[30px] bg-white duration-200 transition-all'></span>
|
||||
</button>
|
||||
<div>
|
||||
{/* 移动端菜单切换按钮 */}
|
||||
<button
|
||||
id='navbarToggler'
|
||||
onClick={toggleMenu}
|
||||
className={`absolute right-4 top-1/2 block -translate-y-1/2 rounded-lg px-3 py-[6px] ring-primary focus:ring-2 lg:hidden ${
|
||||
showMenu ? 'navbarTogglerActive' : ''
|
||||
}`}>
|
||||
<span className='relative my-[6px] block h-[2px] w-[30px] bg-white duration-200 transition-all'></span>
|
||||
<span className='relative my-[6px] block h-[2px] w-[30px] bg-white duration-200 transition-all'></span>
|
||||
<span className='relative my-[6px] block h-[2px] w-[30px] bg-white duration-200 transition-all'></span>
|
||||
</button>
|
||||
|
||||
{/* 响应式菜单 */}
|
||||
<nav
|
||||
id='navbarCollapse'
|
||||
className='absolute right-4 top-full hidden w-full max-w-[250px] rounded-lg bg-white py-5 shadow-lg dark:bg-dark-2 lg:static lg:block lg:w-full lg:max-w-full lg:bg-transparent lg:px-4 lg:py-0 lg:shadow-none dark:lg:bg-transparent xl:px-6'>
|
||||
<ul className='blcok lg:flex 2xl:ml-20'>
|
||||
{links?.map((link, index) => (
|
||||
<MenuItem key={index} link={link} />
|
||||
))}
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
</>
|
||||
<nav
|
||||
id='navbarCollapse'
|
||||
className={`absolute right-4 top-full w-full max-w-[250px] rounded-lg bg-white py-5 shadow-lg dark:bg-dark-2 lg:static lg:block lg:w-full lg:max-w-full lg:bg-transparent lg:px-4 lg:py-0 lg:shadow-none dark:lg:bg-transparent xl:px-6 ${
|
||||
showMenu ? '' : 'hidden'
|
||||
}`}>
|
||||
<ul className='blcok lg:flex 2xl:ml-20'>
|
||||
{links?.map((link, index) => (
|
||||
<MenuItem key={index} link={link} />
|
||||
))}
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import { siteConfig } from '@/lib/config'
|
||||
import CONFIG from '../config'
|
||||
import { useRef, useState } from 'react'
|
||||
|
||||
/**
|
||||
@@ -16,7 +15,7 @@ export const MessageForm = () => {
|
||||
message: ''
|
||||
})
|
||||
|
||||
const handleChange = (e) => {
|
||||
const handleChange = e => {
|
||||
const { name, value } = e.target
|
||||
setFormData(prevState => ({
|
||||
...prevState,
|
||||
@@ -24,89 +23,90 @@ export const MessageForm = () => {
|
||||
}))
|
||||
}
|
||||
|
||||
return <>
|
||||
<h3
|
||||
className="mb-8 text-2xl font-semibold text-dark dark:text-white md:text-[28px] md:leading-[1.42]"
|
||||
>
|
||||
{siteConfig('STARTER_CONTACT_MSG_TITLE', null, CONFIG)}
|
||||
</h3>
|
||||
<form ref={formRef}>
|
||||
<div className="mb-[22px]">
|
||||
<label
|
||||
// for="fullName"
|
||||
className="mb-4 block text-sm text-body-color dark:text-dark-6">
|
||||
{siteConfig('STARTER_CONTACT_MSG_NAME', null, CONFIG)}*
|
||||
</label>
|
||||
<input
|
||||
disabled={success}
|
||||
type="text"
|
||||
name="fullName"
|
||||
value={formData.fullName}
|
||||
onChange={handleChange}
|
||||
placeholder="Adam Gelius"
|
||||
className="w-full border-0 border-b border-[#f1f1f1] bg-transparent pb-3 text-body-color placeholder:text-body-color/60 focus:border-primary focus:outline-none dark:border-dark-3 dark:text-dark-6"
|
||||
/>
|
||||
</div>
|
||||
<div className="mb-[22px]">
|
||||
<label
|
||||
// for="email"
|
||||
className="mb-4 block text-sm text-body-color dark:text-dark-6">
|
||||
{siteConfig('STARTER_CONTACT_MSG_EMAIL', null, CONFIG)}*
|
||||
</label >
|
||||
<input
|
||||
disabled={success}
|
||||
type="email"
|
||||
name="email"
|
||||
value={formData.email}
|
||||
onChange={handleChange}
|
||||
placeholder="example@yourmail.com"
|
||||
className="w-full border-0 border-b border-[#f1f1f1] bg-transparent pb-3 text-body-color placeholder:text-body-color/60 focus:border-primary focus:outline-none dark:border-dark-3 dark:text-dark-6"
|
||||
/>
|
||||
</div>
|
||||
<div className="mb-[22px]">
|
||||
<label
|
||||
// for="phone"
|
||||
className="mb-4 block text-sm text-body-color dark:text-dark-6">
|
||||
{siteConfig('STARTER_CONTACT_MSG_PHONE', null, CONFIG)}*
|
||||
</label >
|
||||
<input
|
||||
disabled={success}
|
||||
type="text"
|
||||
name="phone"
|
||||
value={formData.phone}
|
||||
onChange={handleChange}
|
||||
placeholder="+885 1254 5211 552"
|
||||
className="w-full border-0 border-b border-[#f1f1f1] bg-transparent pb-3 text-body-color placeholder:text-body-color/60 focus:border-primary focus:outline-none dark:border-dark-3 dark:text-dark-6"
|
||||
/>
|
||||
</div>
|
||||
<div className="mb-[30px]">
|
||||
<label
|
||||
// for="message"
|
||||
className="mb-4 block text-sm text-body-color dark:text-dark-6">
|
||||
{siteConfig('STARTER_CONTACT_MSG_TEXT', null, CONFIG)}*
|
||||
</label >
|
||||
<textarea
|
||||
disabled={success}
|
||||
name="message"
|
||||
value={formData.message}
|
||||
onChange={handleChange}
|
||||
rows="1"
|
||||
placeholder="type your message here"
|
||||
className="w-full resize-none border-0 border-b border-[#f1f1f1] bg-transparent pb-3 text-body-color placeholder:text-body-color/60 focus:border-primary focus:outline-none dark:border-dark-3 dark:text-dark-6"
|
||||
></textarea>
|
||||
</div>
|
||||
<div className="mb-0">
|
||||
<button
|
||||
disabled={success}
|
||||
type="submit"
|
||||
className="inline-flex items-center justify-center rounded-md bg-primary px-10 py-3 text-base font-medium text-white transition duration-300 ease-in-out hover:bg-blue-dark"
|
||||
>
|
||||
{siteConfig('STARTER_CONTACT_MSG_SEND', null, CONFIG)}
|
||||
</button>
|
||||
{/* Success message */}
|
||||
{success && <p className="mt-2 text-green-600 text-sm">{siteConfig('STARTER_CONTACT_MSG_THANKS', null, CONFIG)}</p>}
|
||||
|
||||
</div>
|
||||
</form>
|
||||
</>
|
||||
return (
|
||||
<>
|
||||
<h3 className='mb-8 text-2xl font-semibold text-dark dark:text-white md:text-[28px] md:leading-[1.42]'>
|
||||
{siteConfig('STARTER_CONTACT_MSG_TITLE')}
|
||||
</h3>
|
||||
<form ref={formRef}>
|
||||
<div className='mb-[22px]'>
|
||||
<label
|
||||
// for="fullName"
|
||||
className='mb-4 block text-sm text-body-color dark:text-dark-6'>
|
||||
{siteConfig('STARTER_CONTACT_MSG_NAME')}*
|
||||
</label>
|
||||
<input
|
||||
disabled={success}
|
||||
type='text'
|
||||
name='fullName'
|
||||
value={formData.fullName}
|
||||
onChange={handleChange}
|
||||
placeholder='Adam Gelius'
|
||||
className='w-full border-0 border-b border-[#f1f1f1] bg-transparent pb-3 text-body-color placeholder:text-body-color/60 focus:border-primary focus:outline-none dark:border-dark-3 dark:text-dark-6'
|
||||
/>
|
||||
</div>
|
||||
<div className='mb-[22px]'>
|
||||
<label
|
||||
// for="email"
|
||||
className='mb-4 block text-sm text-body-color dark:text-dark-6'>
|
||||
{siteConfig('STARTER_CONTACT_MSG_EMAIL')}*
|
||||
</label>
|
||||
<input
|
||||
disabled={success}
|
||||
type='email'
|
||||
name='email'
|
||||
value={formData.email}
|
||||
onChange={handleChange}
|
||||
placeholder='example@yourmail.com'
|
||||
className='w-full border-0 border-b border-[#f1f1f1] bg-transparent pb-3 text-body-color placeholder:text-body-color/60 focus:border-primary focus:outline-none dark:border-dark-3 dark:text-dark-6'
|
||||
/>
|
||||
</div>
|
||||
<div className='mb-[22px]'>
|
||||
<label
|
||||
// for="phone"
|
||||
className='mb-4 block text-sm text-body-color dark:text-dark-6'>
|
||||
{siteConfig('STARTER_CONTACT_MSG_PHONE')}*
|
||||
</label>
|
||||
<input
|
||||
disabled={success}
|
||||
type='text'
|
||||
name='phone'
|
||||
value={formData.phone}
|
||||
onChange={handleChange}
|
||||
placeholder='+885 1254 5211 552'
|
||||
className='w-full border-0 border-b border-[#f1f1f1] bg-transparent pb-3 text-body-color placeholder:text-body-color/60 focus:border-primary focus:outline-none dark:border-dark-3 dark:text-dark-6'
|
||||
/>
|
||||
</div>
|
||||
<div className='mb-[30px]'>
|
||||
<label
|
||||
// for="message"
|
||||
className='mb-4 block text-sm text-body-color dark:text-dark-6'>
|
||||
{siteConfig('STARTER_CONTACT_MSG_TEXT')}*
|
||||
</label>
|
||||
<textarea
|
||||
disabled={success}
|
||||
name='message'
|
||||
value={formData.message}
|
||||
onChange={handleChange}
|
||||
rows='1'
|
||||
placeholder='type your message here'
|
||||
className='w-full resize-none border-0 border-b border-[#f1f1f1] bg-transparent pb-3 text-body-color placeholder:text-body-color/60 focus:border-primary focus:outline-none dark:border-dark-3 dark:text-dark-6'></textarea>
|
||||
</div>
|
||||
<div className='mb-0'>
|
||||
<button
|
||||
disabled={success}
|
||||
type='submit'
|
||||
className='inline-flex items-center justify-center rounded-md bg-primary px-10 py-3 text-base font-medium text-white transition duration-300 ease-in-out hover:bg-blue-dark'>
|
||||
{siteConfig('STARTER_CONTACT_MSG_SEND')}
|
||||
</button>
|
||||
{/* Success message */}
|
||||
{success && (
|
||||
<p className='mt-2 text-green-600 text-sm'>
|
||||
{siteConfig('STARTER_CONTACT_MSG_THANKS')}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
</form>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,91 +0,0 @@
|
||||
/* eslint-disable no-unreachable */
|
||||
import throttle from 'lodash.throttle';
|
||||
import { useCallback, useEffect, useState } from 'react'
|
||||
import { MenuList } from './MenuList';
|
||||
import { DarkModeButton } from './DarkModeButton';
|
||||
import { Logo } from './Logo';
|
||||
import { useRouter } from 'next/router';
|
||||
import { siteConfig } from '@/lib/config';
|
||||
import CONFIG from '../config';
|
||||
import { useGlobal } from '@/lib/global';
|
||||
|
||||
/**
|
||||
* 顶部导航栏
|
||||
*/
|
||||
export const NavBar = (props) => {
|
||||
const router = useRouter()
|
||||
const { isDarkMode } = useGlobal()
|
||||
const [buttonTextColor, setColor] = useState(router.route === '/' ? 'text-white' : '')
|
||||
useEffect(() => {
|
||||
if (isDarkMode || router.route === '/') {
|
||||
setColor('text-white')
|
||||
} else {
|
||||
setColor('')
|
||||
}
|
||||
// ======= Sticky
|
||||
window.addEventListener('scroll', navBarScollListener)
|
||||
return () => {
|
||||
window.removeEventListener('scroll', navBarScollListener)
|
||||
}
|
||||
}, [[isDarkMode]])
|
||||
|
||||
// 滚动监听
|
||||
const throttleMs = 200
|
||||
const navBarScollListener = useCallback(
|
||||
throttle(() => {
|
||||
// eslint-disable-next-line camelcase
|
||||
const ud_header = document.querySelector('.ud-header');
|
||||
const scrollY = window.scrollY;
|
||||
// 控制台输出当前滚动位置和 sticky 值
|
||||
if (scrollY > 0) {
|
||||
ud_header?.classList?.add('sticky');
|
||||
} else {
|
||||
ud_header?.classList?.remove('sticky');
|
||||
}
|
||||
}, throttleMs)
|
||||
)
|
||||
|
||||
return <>
|
||||
{/* <!-- ====== Navbar Section Start --> */}
|
||||
<div className="ud-header absolute left-0 top-0 z-40 flex w-full items-center bg-transparent" >
|
||||
|
||||
<div className="container">
|
||||
|
||||
<div className="relative -mx-4 flex items-center justify-between">
|
||||
|
||||
{/* Logo */}
|
||||
<Logo/>
|
||||
|
||||
<div className="flex w-full items-center justify-between px-4">
|
||||
|
||||
{/* 中间菜单 */}
|
||||
<MenuList {...props}/>
|
||||
|
||||
{/* 右侧功能 */}
|
||||
<div className="flex items-center justify-end pr-16 lg:pr-0">
|
||||
{/* 深色模式切换 */}
|
||||
<DarkModeButton/>
|
||||
{/* 注册登录功能 */}
|
||||
<div className="hidden sm:flex">
|
||||
<a
|
||||
href={siteConfig('STARTER_NAV_BUTTON_1_URL', null, CONFIG)}
|
||||
className={`loginBtn ${buttonTextColor} px-[22px] py-2 text-base font-medium hover:opacity-70`}
|
||||
>
|
||||
{siteConfig('STARTER_NAV_BUTTON_1_TEXT', null, CONFIG)}
|
||||
</a>
|
||||
<a
|
||||
href={siteConfig('STARTER_NAV_BUTTON_2_URL', null, CONFIG)}
|
||||
className={`signUpBtn ${buttonTextColor} rounded-md bg-white bg-opacity-20 px-6 py-2 text-base font-medium duration-300 ease-in-out hover:bg-opacity-100 hover:text-dark`}
|
||||
>
|
||||
{siteConfig('STARTER_NAV_BUTTON_2_TEXT', null, CONFIG)}
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/* <!-- ====== Navbar Section End --> */}
|
||||
</>
|
||||
}
|
||||
@@ -1,178 +1,178 @@
|
||||
import { siteConfig } from '@/lib/config'
|
||||
import CONFIG from '../config'
|
||||
import Link from 'next/link'
|
||||
|
||||
/**
|
||||
* 价格板块
|
||||
* @returns
|
||||
*/
|
||||
export const Pricing = () => {
|
||||
return <>
|
||||
{/* <!-- ====== Pricing Section Start --> */}
|
||||
<section
|
||||
id="pricing"
|
||||
className="relative z-20 overflow-hidden bg-white pb-12 pt-20 dark:bg-dark lg:pb-[90px] lg:pt-[120px]"
|
||||
>
|
||||
<div className="container mx-auto">
|
||||
<div className="-mx-4 flex flex-wrap">
|
||||
<div className="w-full px-4">
|
||||
<div className="mx-auto mb-[60px] max-w-[510px] text-center">
|
||||
<span className="mb-2 block text-lg font-semibold text-primary">
|
||||
{siteConfig('STARTER_PRICING_TITLE', null, CONFIG)}
|
||||
</span>
|
||||
<h2
|
||||
className="mb-3 text-3xl font-bold text-dark dark:text-white sm:text-4xl md:text-[40px] md:leading-[1.2]"
|
||||
>
|
||||
{siteConfig('STARTER_PRICING_TEXT_1', null, CONFIG)}
|
||||
</h2>
|
||||
<p className="text-base text-body-color dark:text-dark-6">
|
||||
{siteConfig('STARTER_PRICING_TEXT_2', null, CONFIG)}
|
||||
</p>
|
||||
return (
|
||||
<>
|
||||
{/* <!-- ====== Pricing Section Start --> */}
|
||||
<section
|
||||
id='pricing'
|
||||
className='relative overflow-hidden bg-white pb-12 pt-20 dark:bg-dark lg:pb-[90px] lg:pt-[120px]'>
|
||||
<div className='container mx-auto'>
|
||||
<div className='-mx-4 flex flex-wrap'>
|
||||
<div className='w-full px-4'>
|
||||
<div className='mx-auto mb-[60px] max-w-[510px] text-center'>
|
||||
<span className='mb-2 block text-lg font-semibold text-primary'>
|
||||
{siteConfig('STARTER_PRICING_TITLE')}
|
||||
</span>
|
||||
<h2 className='mb-3 text-3xl font-bold text-dark dark:text-white sm:text-4xl md:text-[40px] md:leading-[1.2]'>
|
||||
{siteConfig('STARTER_PRICING_TEXT_1')}
|
||||
</h2>
|
||||
<p className='text-base text-body-color dark:text-dark-6'>
|
||||
{siteConfig('STARTER_PRICING_TEXT_2')}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className='-mx-4 flex flex-wrap justify-center'>
|
||||
{/* 第一个付费计划 */}
|
||||
<div className='w-full px-4 md:w-1/2 lg:w-1/3'>
|
||||
<div className='relative z-10 mb-10 overflow-hidden rounded-xl bg-white px-8 py-10 shadow-pricing dark:bg-dark-2 sm:p-12 lg:px-6 lg:py-10 xl:p-14'>
|
||||
<span className='mb-5 block text-xl font-medium text-dark dark:text-white'>
|
||||
{siteConfig('STARTER_PRICING_1_TITLE')}
|
||||
</span>
|
||||
<h2 className='space-x-1 mb-11 text-4xl font-semibold text-dark dark:text-white xl:text-[42px] xl:leading-[1.21]'>
|
||||
<span className='text-xl font-medium'>
|
||||
{siteConfig('STARTER_PRICING_1_PRICE_CURRENCY')}
|
||||
</span>
|
||||
<span className='-ml-1 -tracking-[2px]'>
|
||||
{siteConfig('STARTER_PRICING_1_PRICE')}
|
||||
</span>
|
||||
<span className='text-base font-normal text-body-color dark:text-dark-6'>
|
||||
{siteConfig('STARTER_PRICING_1_PRICE_PERIOD')}
|
||||
</span>
|
||||
</h2>
|
||||
|
||||
<div className='mb-[50px]'>
|
||||
<h5 className='mb-5 text-lg font-medium text-dark dark:text-white'>
|
||||
{siteConfig('STARTER_PRICING_1_HEADER')}
|
||||
</h5>
|
||||
<div className='flex flex-col gap-[14px]'>
|
||||
{siteConfig('STARTER_PRICING_1_FEATURES')
|
||||
?.split(',')
|
||||
.map((feature, index) => {
|
||||
return (
|
||||
<p
|
||||
key={index}
|
||||
className='text-base text-body-color dark:text-dark-6'>
|
||||
{feature}
|
||||
</p>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
<Link
|
||||
href={siteConfig('STARTER_PRICING_1_BUTTON_URL', '')}
|
||||
className='inline-block rounded-md bg-primary px-7 py-3 text-center text-base font-medium text-white transition hover:bg-blue-dark'>
|
||||
{siteConfig('STARTER_PRICING_1_BUTTON_TEXT')}
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 第二个付费计划 */}
|
||||
<div className='w-full px-4 md:w-1/2 lg:w-1/3'>
|
||||
<div className='relative z-10 mb-10 overflow-hidden rounded-xl bg-white px-8 py-10 shadow-pricing dark:bg-dark-2 sm:p-12 lg:px-6 lg:py-10 xl:p-14'>
|
||||
<p
|
||||
style={{
|
||||
writingMode: 'vertical-rl',
|
||||
textOrientation: 'mixed'
|
||||
}}
|
||||
className='absolute p-1 right-0 top-0 inline-block rounded-bl-md rounded-tl-md bg-primary text-base font-medium text-white tracking-wider'>
|
||||
{siteConfig('STARTER_PRICING_2_TAG')}
|
||||
</p>
|
||||
<span className='mb-5 block text-xl font-medium text-dark dark:text-white'>
|
||||
{siteConfig('STARTER_PRICING_2_TITLE')}
|
||||
</span>
|
||||
<h2 className='space-x-1 mb-11 text-4xl font-semibold text-dark dark:text-white xl:text-[42px] xl:leading-[1.21]'>
|
||||
<span className='text-xl font-medium'>
|
||||
{siteConfig('STARTER_PRICING_2_PRICE_CURRENCY')}
|
||||
</span>
|
||||
<span className='-ml-1 -tracking-[2px]'>
|
||||
{siteConfig('STARTER_PRICING_2_PRICE')}
|
||||
</span>
|
||||
<span className='text-base font-normal text-body-color dark:text-dark-6'>
|
||||
{siteConfig('STARTER_PRICING_2_PRICE_PERIOD')}
|
||||
</span>
|
||||
</h2>
|
||||
|
||||
<div className='mb-[50px]'>
|
||||
<h5 className='mb-5 text-lg font-medium text-dark dark:text-white'>
|
||||
{siteConfig('STARTER_PRICING_2_HEADER')}
|
||||
</h5>
|
||||
<div className='flex flex-col gap-[14px]'>
|
||||
{siteConfig('STARTER_PRICING_2_FEATURES')
|
||||
?.split(',')
|
||||
.map((feature, index) => {
|
||||
return (
|
||||
<p
|
||||
key={index}
|
||||
className='text-base text-body-color dark:text-dark-6'>
|
||||
{feature}
|
||||
</p>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
<Link
|
||||
href={siteConfig('STARTER_PRICING_2_BUTTON_URL', '')}
|
||||
className='inline-block rounded-md bg-primary px-7 py-3 text-center text-base font-medium text-white transition hover:bg-blue-dark'>
|
||||
{siteConfig('STARTER_PRICING_2_BUTTON_TEXT')}
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 第三个付费计划 */}
|
||||
<div className='w-full px-4 md:w-1/2 lg:w-1/3'>
|
||||
<div className='relative z-10 mb-10 overflow-hidden rounded-xl bg-white px-8 py-10 shadow-pricing dark:bg-dark-2 sm:p-12 lg:px-6 lg:py-10 xl:p-14'>
|
||||
<span className='mb-5 block text-xl font-medium text-dark dark:text-white'>
|
||||
{siteConfig('STARTER_PRICING_3_TITLE')}
|
||||
</span>
|
||||
<h2 className='space-x-1 mb-11 text-4xl font-semibold text-dark dark:text-white xl:text-[42px] xl:leading-[1.21]'>
|
||||
<span className='text-xl font-medium'>
|
||||
{siteConfig('STARTER_PRICING_3_PRICE_CURRENCY')}
|
||||
</span>
|
||||
<span className='-ml-1 -tracking-[2px]'>
|
||||
{siteConfig('STARTER_PRICING_3_PRICE')}
|
||||
</span>
|
||||
<span className='text-base font-normal text-body-color dark:text-dark-6'>
|
||||
{siteConfig('STARTER_PRICING_3_PRICE_PERIOD')}
|
||||
</span>
|
||||
</h2>
|
||||
|
||||
<div className='mb-[50px]'>
|
||||
<h5 className='mb-5 text-lg font-medium text-dark dark:text-white'>
|
||||
{siteConfig('STARTER_PRICING_3_HEADER')}
|
||||
</h5>
|
||||
<div className='flex flex-col gap-[14px]'>
|
||||
{siteConfig('STARTER_PRICING_3_FEATURES')
|
||||
?.split(',')
|
||||
.map((feature, index) => {
|
||||
return (
|
||||
<p
|
||||
key={index}
|
||||
className='text-base text-body-color dark:text-dark-6'>
|
||||
{feature}
|
||||
</p>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
<Link
|
||||
href={siteConfig('STARTER_PRICING_3_BUTTON_URL', '')}
|
||||
className='inline-block rounded-md bg-primary px-7 py-3 text-center text-base font-medium text-white transition hover:bg-blue-dark'>
|
||||
{siteConfig('STARTER_PRICING_3_BUTTON_TEXT')}
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="-mx-4 flex flex-wrap justify-center">
|
||||
|
||||
{/* 第一个付费计划 */}
|
||||
<div className="w-full px-4 md:w-1/2 lg:w-1/3">
|
||||
<div
|
||||
className="relative z-10 mb-10 overflow-hidden rounded-xl bg-white px-8 py-10 shadow-pricing dark:bg-dark-2 sm:p-12 lg:px-6 lg:py-10 xl:p-14"
|
||||
>
|
||||
<span
|
||||
className="mb-5 block text-xl font-medium text-dark dark:text-white"
|
||||
>
|
||||
{siteConfig('STARTER_PRICING_1_TITLE', null, CONFIG)}
|
||||
</span>
|
||||
<h2
|
||||
className="space-x-1 mb-11 text-4xl font-semibold text-dark dark:text-white xl:text-[42px] xl:leading-[1.21]"
|
||||
>
|
||||
<span className="text-xl font-medium">{siteConfig('STARTER_PRICING_1_PRICE_CURRENCY', null, CONFIG)}</span>
|
||||
<span className="-ml-1 -tracking-[2px]">{siteConfig('STARTER_PRICING_1_PRICE', null, CONFIG)}</span>
|
||||
<span
|
||||
className="text-base font-normal text-body-color dark:text-dark-6"
|
||||
>
|
||||
{siteConfig('STARTER_PRICING_1_PRICE_PERIOD', null, CONFIG)}
|
||||
</span>
|
||||
</h2>
|
||||
|
||||
<div className="mb-[50px]">
|
||||
<h5 className="mb-5 text-lg font-medium text-dark dark:text-white">
|
||||
{siteConfig('STARTER_PRICING_1_HEADER', null, CONFIG)}
|
||||
</h5>
|
||||
<div className="flex flex-col gap-[14px]">
|
||||
{siteConfig('STARTER_PRICING_1_FEATURES', null, CONFIG)?.split(',').map((feature, index) => {
|
||||
return <p key={index} className="text-base text-body-color dark:text-dark-6">
|
||||
{feature}
|
||||
</p>
|
||||
})}
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<a
|
||||
href={siteConfig('STARTER_PRICING_1_BUTTON_URL', null, CONFIG)}
|
||||
className="inline-block rounded-md bg-primary px-7 py-3 text-center text-base font-medium text-white transition hover:bg-blue-dark"
|
||||
>
|
||||
{siteConfig('STARTER_PRICING_1_BUTTON_TEXT', null, CONFIG)}
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 第二个付费计划 */}
|
||||
<div className="w-full px-4 md:w-1/2 lg:w-1/3">
|
||||
<div
|
||||
className="relative z-10 mb-10 overflow-hidden rounded-xl bg-white px-8 py-10 shadow-pricing dark:bg-dark-2 sm:p-12 lg:px-6 lg:py-10 xl:p-14"
|
||||
>
|
||||
<p style={{ writingMode: 'vertical-rl', textOrientation: 'mixed' }}
|
||||
className="absolute p-1 right-0 top-0 inline-block rounded-bl-md rounded-tl-md bg-primary text-base font-medium text-white tracking-wider"
|
||||
>
|
||||
{siteConfig('STARTER_PRICING_2_TAG', null, CONFIG)}
|
||||
</p>
|
||||
<span
|
||||
className="mb-5 block text-xl font-medium text-dark dark:text-white"
|
||||
>
|
||||
{siteConfig('STARTER_PRICING_2_TITLE', null, CONFIG)}
|
||||
</span>
|
||||
<h2
|
||||
className="space-x-1 mb-11 text-4xl font-semibold text-dark dark:text-white xl:text-[42px] xl:leading-[1.21]"
|
||||
>
|
||||
<span className="text-xl font-medium">{siteConfig('STARTER_PRICING_2_PRICE_CURRENCY', null, CONFIG)}</span>
|
||||
<span className="-ml-1 -tracking-[2px]">{siteConfig('STARTER_PRICING_2_PRICE', null, CONFIG)}</span>
|
||||
<span
|
||||
className="text-base font-normal text-body-color dark:text-dark-6"
|
||||
>
|
||||
{siteConfig('STARTER_PRICING_2_PRICE_PERIOD', null, CONFIG)}
|
||||
</span>
|
||||
</h2>
|
||||
|
||||
<div className="mb-[50px]">
|
||||
<h5 className="mb-5 text-lg font-medium text-dark dark:text-white">
|
||||
{siteConfig('STARTER_PRICING_2_HEADER', null, CONFIG)}
|
||||
</h5>
|
||||
<div className="flex flex-col gap-[14px]">
|
||||
{siteConfig('STARTER_PRICING_2_FEATURES', null, CONFIG)?.split(',').map((feature, index) => {
|
||||
return <p key={index} className="text-base text-body-color dark:text-dark-6">
|
||||
{feature}
|
||||
</p>
|
||||
})}
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<a
|
||||
href={siteConfig('STARTER_PRICING_2_BUTTON_URL', null, CONFIG)}
|
||||
className="inline-block rounded-md bg-primary px-7 py-3 text-center text-base font-medium text-white transition hover:bg-blue-dark"
|
||||
>
|
||||
{siteConfig('STARTER_PRICING_2_BUTTON_TEXT', null, CONFIG)}
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 第三个付费计划 */}
|
||||
<div className="w-full px-4 md:w-1/2 lg:w-1/3">
|
||||
<div
|
||||
className="relative z-10 mb-10 overflow-hidden rounded-xl bg-white px-8 py-10 shadow-pricing dark:bg-dark-2 sm:p-12 lg:px-6 lg:py-10 xl:p-14"
|
||||
>
|
||||
<span
|
||||
className="mb-5 block text-xl font-medium text-dark dark:text-white"
|
||||
>
|
||||
{siteConfig('STARTER_PRICING_3_TITLE', null, CONFIG)}
|
||||
</span>
|
||||
<h2
|
||||
className="space-x-1 mb-11 text-4xl font-semibold text-dark dark:text-white xl:text-[42px] xl:leading-[1.21]"
|
||||
>
|
||||
<span className="text-xl font-medium">{siteConfig('STARTER_PRICING_3_PRICE_CURRENCY', null, CONFIG)}</span>
|
||||
<span className="-ml-1 -tracking-[2px]">{siteConfig('STARTER_PRICING_3_PRICE', null, CONFIG)}</span>
|
||||
<span
|
||||
className="text-base font-normal text-body-color dark:text-dark-6"
|
||||
>
|
||||
{siteConfig('STARTER_PRICING_3_PRICE_PERIOD', null, CONFIG)}
|
||||
</span>
|
||||
</h2>
|
||||
|
||||
<div className="mb-[50px]">
|
||||
<h5 className="mb-5 text-lg font-medium text-dark dark:text-white">
|
||||
{siteConfig('STARTER_PRICING_3_HEADER', null, CONFIG)}
|
||||
</h5>
|
||||
<div className="flex flex-col gap-[14px]">
|
||||
{siteConfig('STARTER_PRICING_3_FEATURES', null, CONFIG)?.split(',').map((feature, index) => {
|
||||
return <p key={index} className="text-base text-body-color dark:text-dark-6">
|
||||
{feature}
|
||||
</p>
|
||||
})}
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<a
|
||||
href={siteConfig('STARTER_PRICING_3_BUTTON_URL', null, CONFIG)}
|
||||
className="inline-block rounded-md bg-primary px-7 py-3 text-center text-base font-medium text-white transition hover:bg-blue-dark"
|
||||
>
|
||||
{siteConfig('STARTER_PRICING_3_BUTTON_TEXT', null, CONFIG)}
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
{/* <!-- ====== Pricing Section End --> */}
|
||||
|
||||
</>
|
||||
</section>
|
||||
{/* <!-- ====== Pricing Section End --> */}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
107
themes/starter/components/SearchInput.js
Normal file
107
themes/starter/components/SearchInput.js
Normal file
@@ -0,0 +1,107 @@
|
||||
import { useGlobal } from '@/lib/global'
|
||||
import { useRouter } from 'next/router'
|
||||
import { useImperativeHandle, useRef, useState } from 'react'
|
||||
|
||||
let lock = false
|
||||
|
||||
/**
|
||||
* 搜索输入框
|
||||
* @param {*} param0
|
||||
* @returns
|
||||
*/
|
||||
const SearchInput = ({ currentTag, keyword, cRef }) => {
|
||||
const { locale } = useGlobal()
|
||||
const router = useRouter()
|
||||
const searchInputRef = useRef(null)
|
||||
useImperativeHandle(cRef, () => {
|
||||
return {
|
||||
focus: () => {
|
||||
searchInputRef?.current?.focus()
|
||||
}
|
||||
}
|
||||
})
|
||||
const handleSearch = () => {
|
||||
const key = searchInputRef.current.value
|
||||
if (key && key !== '') {
|
||||
router.push({ pathname: '/search/' + key }).then(r => {})
|
||||
} else {
|
||||
router.push({ pathname: '/' }).then(r => {})
|
||||
}
|
||||
}
|
||||
const handleKeyUp = e => {
|
||||
if (e.keyCode === 13) {
|
||||
// 回车
|
||||
handleSearch(searchInputRef.current.value)
|
||||
} else if (e.keyCode === 27) {
|
||||
// ESC
|
||||
cleanSearch()
|
||||
}
|
||||
}
|
||||
const cleanSearch = () => {
|
||||
searchInputRef.current.value = ''
|
||||
setShowClean(false)
|
||||
}
|
||||
function lockSearchInput() {
|
||||
lock = true
|
||||
}
|
||||
|
||||
function unLockSearchInput() {
|
||||
lock = false
|
||||
}
|
||||
const [showClean, setShowClean] = useState(false)
|
||||
const updateSearchKey = val => {
|
||||
if (lock) {
|
||||
return
|
||||
}
|
||||
searchInputRef.current.value = val
|
||||
if (val) {
|
||||
setShowClean(true)
|
||||
} else {
|
||||
setShowClean(false)
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<section className='flex w-full bg-gray-100'>
|
||||
<input
|
||||
ref={searchInputRef}
|
||||
type='text'
|
||||
placeholder={
|
||||
currentTag
|
||||
? `${locale.SEARCH.TAGS} #${currentTag}`
|
||||
: `${locale.SEARCH.ARTICLES}`
|
||||
}
|
||||
className={
|
||||
'outline-none w-full text-sm pl-4 transition focus:shadow-lg font-light leading-10 text-black bg-gray-100 dark:bg-gray-900 dark:text-white'
|
||||
}
|
||||
onKeyUp={handleKeyUp}
|
||||
onCompositionStart={lockSearchInput}
|
||||
onCompositionUpdate={lockSearchInput}
|
||||
onCompositionEnd={unLockSearchInput}
|
||||
onChange={e => updateSearchKey(e.target.value)}
|
||||
defaultValue={keyword || ''}
|
||||
/>
|
||||
|
||||
<div
|
||||
className='-ml-8 cursor-pointer float-right items-center justify-center py-2'
|
||||
onClick={handleSearch}>
|
||||
<i
|
||||
className={
|
||||
'hover:text-black transform duration-200 text-gray-500 cursor-pointer fas fa-search'
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{showClean && (
|
||||
<div className='-ml-12 cursor-pointer dark:bg-gray-600 dark:hover:bg-gray-800 float-right items-center justify-center py-2'>
|
||||
<i
|
||||
className='hover:text-black transform duration-200 text-gray-400 cursor-pointer fas fa-times'
|
||||
onClick={cleanSearch}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</section>
|
||||
)
|
||||
}
|
||||
|
||||
export default SearchInput
|
||||
@@ -1,9 +1,9 @@
|
||||
/* eslint-disable @next/next/no-img-element */
|
||||
import { siteConfig } from '@/lib/config'
|
||||
import CONFIG from '../config'
|
||||
import { SVGAvatarBG } from './svg/SVGAvatarBG'
|
||||
|
||||
export const Team = () => {
|
||||
const STARTER_TEAM_ITEMS = siteConfig('STARTER_TEAM_ITEMS', [])
|
||||
return (
|
||||
<>
|
||||
{/* <!-- ====== Team Section Start --> */}
|
||||
@@ -15,14 +15,14 @@ export const Team = () => {
|
||||
<div className='w-full px-4'>
|
||||
<div className='mx-auto mb-[60px] max-w-[485px] text-center'>
|
||||
<span className='mb-2 block text-lg font-semibold text-primary'>
|
||||
{siteConfig('STARTER_TEAM_TITLE', null, CONFIG)}
|
||||
{siteConfig('STARTER_TEAM_TITLE')}
|
||||
</span>
|
||||
<h2 className='mb-3 text-3xl font-bold leading-[1.2] text-dark dark:text-white sm:text-4xl md:text-[40px]'>
|
||||
{siteConfig('STARTER_TEAM_TEXT_1', null, CONFIG)}
|
||||
{siteConfig('STARTER_TEAM_TEXT_1')}
|
||||
</h2>
|
||||
<p
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: siteConfig('STARTER_TEAM_TEXT_2', null, CONFIG)
|
||||
__html: siteConfig('STARTER_TEAM_TEXT_2')
|
||||
}}
|
||||
className='text-base text-body-color dark:text-dark-6'></p>
|
||||
</div>
|
||||
@@ -31,7 +31,7 @@ export const Team = () => {
|
||||
|
||||
{/* 团队成员排列矩阵 */}
|
||||
<div className='-mx-4 flex flex-wrap justify-center'>
|
||||
{CONFIG.STARTER_TEAM_ITEMS.map((item, index) => {
|
||||
{STARTER_TEAM_ITEMS?.map((item, index) => {
|
||||
return (
|
||||
<div
|
||||
key={index}
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
import { siteConfig } from '@/lib/config'
|
||||
import { loadExternalResource } from '@/lib/utils'
|
||||
import { useEffect } from 'react'
|
||||
import CONFIG from '../config'
|
||||
import { SVGLeftArrow } from './svg/SVGLeftArrow'
|
||||
import { SVGRightArrow } from './svg/SVGRightArrow'
|
||||
|
||||
@@ -60,11 +59,7 @@ export const Testimonials = () => {
|
||||
}, [])
|
||||
// 用户评分
|
||||
const ratings = [1, 2, 3, 4, 5]
|
||||
const STARTER_TESTIMONIALS_ITEMS = siteConfig(
|
||||
'STARTER_TESTIMONIALS_ITEMS',
|
||||
[],
|
||||
CONFIG
|
||||
)
|
||||
const STARTER_TESTIMONIALS_ITEMS = siteConfig('STARTER_TESTIMONIALS_ITEMS')
|
||||
return (
|
||||
<>
|
||||
{/* <!-- ====== Testimonial Section Start --> */}
|
||||
@@ -76,13 +71,13 @@ export const Testimonials = () => {
|
||||
<div className='w-full px-4'>
|
||||
<div className='mx-auto mb-[60px] max-w-[485px] text-center'>
|
||||
<span className='mb-2 block text-lg font-semibold text-primary'>
|
||||
{siteConfig('STARTER_TESTIMONIALS_TITLE', null, CONFIG)}
|
||||
{siteConfig('STARTER_TESTIMONIALS_TITLE')}
|
||||
</span>
|
||||
<h2 className='mb-3 text-3xl font-bold leading-[1.2] text-dark dark:text-white sm:text-4xl md:text-[40px]'>
|
||||
{siteConfig('STARTER_TESTIMONIALS_TEXT_1', null, CONFIG)}
|
||||
{siteConfig('STARTER_TESTIMONIALS_TEXT_1')}
|
||||
</h2>
|
||||
<p className='text-base text-body-color dark:text-dark-6'>
|
||||
{siteConfig('STARTER_TESTIMONIALS_TEXT_2', null, CONFIG)}
|
||||
{siteConfig('STARTER_TESTIMONIALS_TEXT_2')}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
@@ -92,7 +87,7 @@ export const Testimonials = () => {
|
||||
<div className='swiper testimonial-carousel common-carousel p-5'>
|
||||
<div className='swiper-wrapper'>
|
||||
{/* 用户评价卡牌 */}
|
||||
{STARTER_TESTIMONIALS_ITEMS.map((item, index) => {
|
||||
{STARTER_TESTIMONIALS_ITEMS?.map((item, index) => {
|
||||
return (
|
||||
<div key={index} className='swiper-slide'>
|
||||
<div className='rounded-xl bg-white px-4 py-[30px] shadow-testimonial dark:bg-dark sm:px-[30px]'>
|
||||
@@ -101,11 +96,7 @@ export const Testimonials = () => {
|
||||
<img
|
||||
key={index}
|
||||
alt='star icon' // 为每个图片设置唯一的 key 属性
|
||||
src={siteConfig(
|
||||
'STARTER_TESTIMONIALS_STAR_ICON',
|
||||
null,
|
||||
CONFIG
|
||||
)}
|
||||
src={siteConfig('STARTER_TESTIMONIALS_STAR_ICON')}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user