diff --git a/components/CursorDot.js b/components/CursorDot.js new file mode 100644 index 00000000..72fef5ca --- /dev/null +++ b/components/CursorDot.js @@ -0,0 +1,97 @@ +import { useEffect } from 'react'; + +const CursorDot = () => { + useEffect(() => { + // 创建小白点元素 + const dot = document.createElement('div'); + dot.classList.add('cursor-dot'); + document.body.appendChild(dot); + + // 鼠标坐标和缓动目标坐标 + let mouse = { x: -100, y: -100 }; // 初始位置在屏幕外 + let dotPos = { x: mouse.x, y: mouse.y }; + + // 监听鼠标移动 + const handleMouseMove = (e) => { + mouse.x = e.clientX; + mouse.y = e.clientY; + }; + document.addEventListener('mousemove', handleMouseMove); + + // 监听鼠标悬停在可点击对象上的事件 + const handleMouseEnter = () => { + dot.classList.add('cursor-dot-hover'); // 添加放大样式 + }; + const handleMouseLeave = () => { + dot.classList.remove('cursor-dot-hover'); // 移除放大样式 + }; + + + // 为所有可点击元素和包含 hover 或 group-hover 类名的元素添加事件监听 + const clickableElements = document.querySelectorAll( + 'a, button, [role="button"], [onclick], [cursor="pointer"], [class*="hover"], [class*="group-hover"]' + ); + clickableElements.forEach((el) => { + el.addEventListener('mouseenter', handleMouseEnter); + el.addEventListener('mouseleave', handleMouseLeave); + }); + + // 动画循环:延迟更新小白点位置 + const updateDotPosition = () => { + const damping = 0.2; // 阻尼系数,值越小延迟越明显 + dotPos.x += (mouse.x - dotPos.x) * damping; + dotPos.y += (mouse.y - dotPos.y) * damping; + + // 更新DOM + dot.style.left = `${dotPos.x}px`; + dot.style.top = `${dotPos.y}px`; + + requestAnimationFrame(updateDotPosition); + }; + + // 启动动画 + updateDotPosition(); + + // 清理函数 + return () => { + document.removeEventListener('mousemove', handleMouseMove); + clickableElements.forEach((el) => { + el.removeEventListener('mouseenter', handleMouseEnter); + el.removeEventListener('mouseleave', handleMouseLeave); + }); + document.body.removeChild(dot); + }; + }, []); + + return ( + + ); +}; + +export default CursorDot; \ No newline at end of file diff --git a/components/Lenis.js b/components/Lenis.js index b0ed5ed8..43b1c062 100644 --- a/components/Lenis.js +++ b/components/Lenis.js @@ -1,52 +1,53 @@ -/** - * 鼠标滚动阻尼感 - */ -import { useEffect } from 'react' +import { useEffect, useRef } from 'react' import { loadExternalResource } from '@/lib/utils' /** - * 鼠标点击烟花特效 + * 滚动阻尼特效 + * 目前只用在proxio主题 * @returns */ const Lenis = () => { + const lenisRef = useRef(null) // 用于存储 Lenis 实例 useEffect(() => { // 异步加载 async function loadLenis() { - loadExternalResource( - '/js/lenis.js', - 'js' - ).then(() => { - console.log('Lenis',window.Lenis) - if(!window.Lenis) { + loadExternalResource('/js/lenis.js', 'js').then(() => { + // console.log('Lenis', window.Lenis) + if (!window.Lenis) { console.error('Lenis not loaded') return } const Lenis = window.Lenis - // 创建 Lenis 实例 - const lenis = new Lenis({ - duration: 1.2, - easing: (t) => Math.min(1, 1.001 - Math.pow(2, -10 * t)), // https://www.desmos.com/calculator/brs54l4xou - direction: 'vertical', // vertical, horizontal - gestureDirection: 'vertical', // vertical, horizontal, both - smooth: true, - mouseMultiplier: 1, - smoothTouch: false, - touchMultiplier: 2, - infinite: false, - }) - - //get scroll value - lenis.on('scroll', ({ scroll, limit, velocity, direction, progress }) => { console.log({ scroll, limit, velocity, direction, progress }) - }) - - function raf(time) { - lenis.raf(time) - requestAnimationFrame(raf) - } - - requestAnimationFrame(raf) + // 创建 Lenis 实例 + const lenis = new Lenis({ + duration: 1.2, + easing: (t) => Math.min(1, 1.001 - Math.pow(2, -10 * t)), // https://www.desmos.com/calculator/brs54l4xou + direction: 'vertical', // vertical, horizontal + gestureDirection: 'vertical', // vertical, horizontal, both + smooth: true, + mouseMultiplier: 1, + smoothTouch: false, + touchMultiplier: 2, + infinite: false, + }) + + // 存储实例到 ref + lenisRef.current = lenis + + // 监听滚动事件 + // lenis.on('scroll', ({ scroll, limit, velocity, direction, progress }) => { + // // console.log({ scroll, limit, velocity, direction, progress }) + // }) + + // 动画帧循环 + function raf(time) { + lenis.raf(time) + requestAnimationFrame(raf) + } + + requestAnimationFrame(raf) }) } @@ -54,6 +55,11 @@ const Lenis = () => { return () => { // 在组件卸载时清理资源 + if (lenisRef.current) { + lenisRef.current.destroy() // 销毁 Lenis 实例 + lenisRef.current = null + // console.log('Lenis instance destroyed') + } } }, []) diff --git a/public/images/themes-preview/proxio.png b/public/images/themes-preview/proxio.png new file mode 100644 index 00000000..8aa0a3e1 Binary files /dev/null and b/public/images/themes-preview/proxio.png differ diff --git a/themes/proxio/components/Announcement.js b/themes/proxio/components/Announcement.js index 2a72cea0..24de87eb 100644 --- a/themes/proxio/components/Announcement.js +++ b/themes/proxio/components/Announcement.js @@ -13,7 +13,7 @@ const Announcement = ({ post, className }) => {
+ className='rounded-xl px-2 wow fadeInUp' data-wow-delay='.2s'> {/*
{locale.COMMON.ANNOUNCEMENT}
*/} {post && (
diff --git a/themes/proxio/components/Blog.js b/themes/proxio/components/Blog.js index 5d516fd7..040edbd3 100644 --- a/themes/proxio/components/Blog.js +++ b/themes/proxio/components/Blog.js @@ -15,7 +15,7 @@ export const Blog = ({ posts }) => {
{/* 区块标题文字 */} -
+
@@ -33,21 +33,25 @@ export const Blog = ({ posts }) => { return (
-
+ {/* 图片部分 */} +
{item.pageCoverThumbnail && ( )} + {/* 遮罩层,仅覆盖图片部分 */} +
-
- + {/* 内容部分 */} +
+ {item.publishDay}

@@ -71,4 +75,4 @@ export const Blog = ({ posts }) => { {/* */} ) -} +} \ No newline at end of file diff --git a/themes/proxio/components/CTA.js b/themes/proxio/components/CTA.js index 830d38ce..0c31970e 100644 --- a/themes/proxio/components/CTA.js +++ b/themes/proxio/components/CTA.js @@ -13,26 +13,26 @@ export const CTA = () => { return ( <> {/* */} -
+
-
+
-

+

{siteConfig('PROXIO_CTA_TITLE')} {siteConfig('PROXIO_CTA_TITLE_2')}

-

+

{siteConfig('PROXIO_CTA_DESCRIPTION')}

{siteConfig('PROXIO_CTA_BUTTON') && ( <> + className='inline-flex items-center justify-center rounded-2xl 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'> {siteConfig('PROXIO_CTA_BUTTON_TEXT')} diff --git a/themes/proxio/components/Footer.js b/themes/proxio/components/Footer.js index 427f913c..0f68f4ab 100644 --- a/themes/proxio/components/Footer.js +++ b/themes/proxio/components/Footer.js @@ -1,168 +1,96 @@ +import AnalyticsBusuanzi from '@/components/AnalyticsBusuanzi' +import { BeiAnGongAn } from '@/components/BeiAnGongAn' +import BeiAnSite from '@/components/BeiAnSite' +import CopyRightDate from '@/components/CopyRightDate' +import DarkModeButton from '@/components/DarkModeButton' +import LazyImage from '@/components/LazyImage' +import PoweredBy from '@/components/PoweredBy' import { siteConfig } from '@/lib/config' -import SocialButton from '@/themes/fukasawa/components/SocialButton' -import { Logo } from './Logo' -import { SVGFooterCircleBG } from './svg/SVGFooterCircleBG' +import { useGlobal } from '@/lib/global' import Link from 'next/link' +import CONFIG from '../config' +import SocialButton from './SocialButton' + +/** + * 网页底脚 + */ +export const Footer = ({ title }) => { + const { siteInfo } = useGlobal() + const PROXIO_FOOTER_LINKS = siteConfig('PROXIO_FOOTER_LINKS', [], CONFIG) -/* eslint-disable @next/next/no-img-element */ -export const Footer = props => { - const footerPostCount = siteConfig('PROXIO_FOOTER_POST_COUNT', 2) - const latestPosts = props?.latestPosts - ? props?.latestPosts.slice(0, footerPostCount) - : [] - const PROXIO_FOOTER_LINK_GROUP = siteConfig('PROXIO_FOOTER_LINK_GROUP', []) return ( - <> - {/* */} -
-
-
-
-
- - - -

- {siteConfig('PROXIO_FOOTER_SLOGAN')} -

-
-
- -
-
-
+
+
+ {/* 信息与链接区块 */} +
+
+
+ +

{title}

+ + {siteConfig('AUTHOR')} +
+
{siteConfig('DESCRIPTION')}
+
{siteConfig('CONTACT_EMAIL')}
+
- {/* 中间三列菜单组 */} - {PROXIO_FOOTER_LINK_GROUP?.map((item, index) => { + {/* 右侧链接区块 */} +
+ {PROXIO_FOOTER_LINKS?.map((group, index) => { return ( -
-
-

- {item.TITLE} -

-
    - {item?.LINK_GROUP?.map((l, i) => { - return ( -
  • - - {l.TITLE} - -
  • - ) - })} -
+
+
+ {group.name} +
+
+ {group?.menus?.map((menu, index) => { + return ( +
+ + {menu.title} + +
+ ) + })}
) })} +
+
- {/* 页脚右侧最新博文 */} -
-
-

- {siteConfig('PROXIO_FOOTER_BLOG_LATEST_TITLE')} -

- {/* 展示两条最新博客文章 */} -
- {latestPosts?.map((item, index) => { - return ( - - {item.pageCoverThumbnail && ( -
- {item.title} -
- )} - - {item.title} - - - ) - })} -
-
+ {/* 页脚 */} +
+
+ + +
+ + + +
+
+ +
- {/* 底部版权信息相关 */} - -
-
-
-
-
-
- - {siteConfig('PROXIO_FOOTER_PRIVACY_POLICY_TEXT')} - - - {siteConfig('PROXIO_FOOTER_PRIVACY_LEGAL_NOTICE_TEXT')} - - - {siteConfig( - 'PROXIO_FOOTER_PRIVACY_TERMS_OF_SERVICE_TEXT', '' - )} - -
-
-
-
-
-

- Designed and Developed by - - NotionNext {siteConfig('VERSION')} - -

-
-
-
-
+ {/* 备案 */} +
+ +
- - {/* Footer 背景 */} -
- - - - - - - - - - - -
-
- {/* */} - +
+
) -} +} \ No newline at end of file diff --git a/themes/proxio/components/LoadingCover.js b/themes/proxio/components/LoadingCover.js new file mode 100644 index 00000000..a8d134e8 --- /dev/null +++ b/themes/proxio/components/LoadingCover.js @@ -0,0 +1,168 @@ +import { siteConfig } from '@/lib/config'; +import { useEffect, useState } from 'react'; + +const LoadingCover = ({ onFinishLoading }) => { + const [isVisible, setIsVisible] = useState(true); + const welcomeText = siteConfig('PROXIO_WELCOME_TEXT', '欢迎来到我们的网站!'); + + // 定义颜色变量 + const colors = { + backgroundStart: '#1a1a1a', // 深灰色 + backgroundMiddle: '#4d4d4d', // 中灰色 + backgroundEnd: '#e6e6e6', // 浅灰色 + textColor: '#ffffff', // 白色 + rippleColor: 'rgba(255, 255, 255, 0.6)', // 半透明白色 + }; + + useEffect(() => { + const pageContainer = document.getElementById('pageContainer'); + + const handleClick = (e) => { + // 创建扩散光圈 + const ripple = document.createElement('div'); + ripple.classList.add('ripple'); + ripple.style.left = `${e.clientX - 10}px`; + ripple.style.top = `${e.clientY - 10}px`; + document.body.appendChild(ripple); + + // 添加页面缩放 + 模糊动画 + pageContainer.classList.add('page-clicked'); + + // 模拟加载完成,调用回调函数 + setTimeout(() => { + setIsVisible(false); // 淡出动画 + setTimeout(() => { + if (onFinishLoading) { + onFinishLoading(); + } + }, 600); // 等待淡出动画完成 + }, 1200); + + // 清理 ripple 元素 + setTimeout(() => { + ripple.remove(); + }, 1000); + }; + + document.body.addEventListener('click', handleClick); + + return () => { + document.body.removeEventListener('click', handleClick); + }; + }, [onFinishLoading]); + + if (!isVisible) return null; + + return ( +
+
+ {welcomeText} +
+ +
+ ); +}; + +export default LoadingCover; \ No newline at end of file diff --git a/themes/proxio/components/Logo.js b/themes/proxio/components/Logo.js index 5bb1b6d8..d361de75 100644 --- a/themes/proxio/components/Logo.js +++ b/themes/proxio/components/Logo.js @@ -12,12 +12,10 @@ import { useEffect, useState } from 'react' * @returns */ export const Logo = props => { - const { white, NOTION_CONFIG } = props + const { siteInfo, white } = props const router = useRouter() - const logoWhite = siteConfig('PROXIO_LOGO_WHITE') - const logoNormal = siteConfig('PROXIO_LOGO') + const { isDarkMode } = useGlobal() - const [logo, setLogo] = useState(logoWhite) const [logoTextColor, setLogoTextColor] = useState('text-white') useEffect(() => { @@ -29,10 +27,8 @@ export const Logo = props => { const homePageNavBar = router.route === '/' && scrollY < 10 // 在首页并且视窗在页面顶部 if (white || isDarkMode || homePageNavBar) { - setLogo(logoWhite) setLogoTextColor('text-white') } else { - setLogo(logoNormal) setLogoTextColor('text-black') } }, throttleMs) @@ -47,18 +43,14 @@ export const Logo = props => { return (
- {/* eslint-disable-next-line @next/next/no-img-element */} - {logo && ( - { - router.push('/') - }} - src={logo} - alt='logo' - className='header-logo mr-1 h-8' - /> - )} + {/* logo文字 */} { diff --git a/themes/proxio/config.js b/themes/proxio/config.js index e1606d92..dee09788 100644 --- a/themes/proxio/config.js +++ b/themes/proxio/config.js @@ -2,11 +2,7 @@ * 另一个落地页主题 */ const CONFIG = { - // 默认只展示Logo文字,如果设置了logo图片,会在文字左侧显示图标 - PROXIO_LOGO: '', // 普通logo图片 示例:/images/starter/logo/logo.svg - PROXIO_LOGO_WHITE: '', // 透明底浅色logo 示例: /images/starter/logo/logo-white.svg - - // MENU , 菜单部分不在此处配置,请在Notion数据库中添加MENU + PROXIO_WELCOME_TEXT:'欢迎来到此网站,点击任意位置进入', // 欢迎文字,留空则不启用 // 英雄区块导航 PROXIO_HERO_ENABLE: true, // 开启英雄区 @@ -205,16 +201,16 @@ const CONFIG = { PROXIO_ABOUT_TEXT_1: '我们的开发者团队', PROXIO_ABOUT_TEXT_2: 'NotionNext 由众多开源技术爱好者们共同合作完成,感谢每一位贡献者', - PROXIO_ABOUT_PHOTO_URL:'', - PROXIO_ABOUT_KEY_1:'经验年限', - PROXIO_ABOUT_VAL_1:'10年+', - PROXIO_ABOUT_KEY_2:'客户', - PROXIO_ABOUT_VAL_2:'1000+', - PROXIO_ABOUT_KEY_3:'交付项目', - PROXIO_ABOUT_VAL_3:'5000+', - PROXIO_ABOUT_KEY_4:'累积创作时长(小时)', - PROXIO_ABOUT_VAL_4:'10000+', - + PROXIO_ABOUT_PHOTO_URL: '', + PROXIO_ABOUT_KEY_1: '经验年限', + PROXIO_ABOUT_VAL_1: '10年+', + PROXIO_ABOUT_KEY_2: '客户', + PROXIO_ABOUT_VAL_2: '1000+', + PROXIO_ABOUT_KEY_3: '交付项目', + PROXIO_ABOUT_VAL_3: '5000+', + PROXIO_ABOUT_KEY_4: '累积创作时长(小时)', + PROXIO_ABOUT_VAL_4: '10000+', + // 联系模块 PROXIO_CONTACT_ENABLE: true, // 联系模块开关 @@ -274,54 +270,43 @@ const CONFIG = { PROXIO_FOOTER_SLOGAN: '我们通过技术为品牌和公司创造数字体验。', // 页脚三列菜单组 - PROXIO_FOOTER_LINK_GROUP: [ + // 页脚菜单 + PROXIO_FOOTER_LINKS: [ { - TITLE: '关于我们', - LINK_GROUP: [ - { TITLE: '官方主页', URL: '/#home' }, - { TITLE: '操作文档', URL: 'https://docs.tangly1024.com/about' }, + name: '友情链接', + menus: [ { - TITLE: '帮助支持', - URL: 'https://docs.tangly1024.com/article/how-to-question' + title: 'Tangly的学习笔记', + href: 'https://blog.tangly1024.com' }, { - TITLE: '合作申请', - URL: 'https://docs.tangly1024.com/article/my-service' + title: 'NotionNext', + href: 'https://www.tangly1024.com' } ] }, { - TITLE: '功能特性', - LINK_GROUP: [ + name: '开发者', + menus: [ + { title: 'Github', href: 'https://github.com/tangly1024/NotionNext' }, { - TITLE: '部署指南', - URL: 'https://docs.tangly1024.com/article/vercel-deploy-notion-next' + title: '开发帮助', + href: 'https://docs.tangly1024.com/article/how-to-develop-with-notion-next' }, { - TITLE: '升级指南', - URL: 'https://docs.tangly1024.com/article/how-to-update-notionnext' - }, - { TITLE: '最新版本', URL: 'https://docs.tangly1024.com/article/latest' } - ] - }, - { - TITLE: 'Notion写作', - LINK_GROUP: [ - { - TITLE: 'Notion开始写作', - URL: 'https://docs.tangly1024.com/article/start-to-write' + title: '功能反馈', + href: 'https://github.com/tangly1024/NotionNext/issues/new/choose' }, { - TITLE: '快捷键提升效率', - URL: 'https://docs.tangly1024.com/article/notion-short-key' + title: '技术讨论', + href: 'https://github.com/tangly1024/NotionNext/discussions' }, { - TITLE: '中国大陆使用Notion', - URL: 'https://docs.tangly1024.com/article/notion-faster' + title: '关于作者', + href: 'https://blog.tangly1024.com/about' } ] - } - ], + }], PROXIO_FOOTER_BLOG_LATEST_TITLE: '最新文章', diff --git a/themes/proxio/index.js b/themes/proxio/index.js index 61725ab6..4cb3a130 100644 --- a/themes/proxio/index.js +++ b/themes/proxio/index.js @@ -42,6 +42,8 @@ import { SignUpForm } from './components/SignUpForm' import { SVG404 } from './components/svg/SVG404' import Lenis from '@/components/Lenis' import Announcement from './components/Announcement' +import CursorDot from '@/components/CursorDot' +import LoadingCover from './components/LoadingCover' /** * 布局框架 @@ -77,9 +79,10 @@ const LayoutBase = props => { {/* 悬浮按钮 */} - {/* 鼠标阻尼效果 */} + {/* 鼠标阻尼动画 */} - + {/* 鼠标跟随动画 */} + {/* */}
) @@ -118,6 +121,7 @@ const LayoutIndex = props => { className={ 'announncement text-center py-16' } + />} {/* 团队介绍 */} @@ -128,6 +132,7 @@ const LayoutIndex = props => { {/* 产品特性 */} {siteConfig('PROXIO_FEATURE_ENABLE', true, CONFIG) && } + {/* 生涯 */} {siteConfig('PROXIO_CAREER_ENABLE', true, CONFIG) && } @@ -136,7 +141,6 @@ const LayoutIndex = props => { {/* {siteConfig('PROXIO_PRICING_ENABLE', true, CONFIG) && } */} - {/* 评价展示 */} {siteConfig('PROXIO_TESTIMONIALS_ENABLE', true, CONFIG) && ( @@ -147,6 +151,8 @@ const LayoutIndex = props => { {/* 行动呼吁 */} {siteConfig('PROXIO_CTA_ENABLE', true, CONFIG) && } + + ) }