diff --git a/apps/web/app/page.tsx b/apps/web/app/page.tsx index 73648b90..6b8d687c 100644 --- a/apps/web/app/page.tsx +++ b/apps/web/app/page.tsx @@ -7,6 +7,7 @@ import Footer from "../components/main/footer"; import Head from "../components/main/head"; function Main() { + return (
diff --git a/apps/web/components/card.tsx b/apps/web/components/card.tsx index 29f09527..81c308c4 100644 --- a/apps/web/components/card.tsx +++ b/apps/web/components/card.tsx @@ -3,6 +3,9 @@ import { useRouter } from "next/navigation"; import "../style/card.css"; +import "../style/scrollAnimate.css" +import { useRef } from "react"; +import { useScrollAnimate } from "@/hooks/useScrollAnimate"; function Card() { const router = useRouter(); @@ -10,10 +13,15 @@ function Card() { router.push("/edit-template"); }; + + const boxRef = useRef(null); // 指定ref的类型为HTMLDivElement + useScrollAnimate(boxRef); + return (
+
{/* (null); // 指定ref的类型为HTMLDivElement + useScrollAnimate(boxRef); + return ( -
+
-
- {Array.from({ length: 8 }, (_, index) => ( +
+ {Array.from({ length: 7 }, (_, index) => ( ))}
@@ -40,7 +40,7 @@ function Index(props: any) {
-
+
{Array.from({ length: 4 }, (_, index) => ( ))} diff --git a/apps/web/components/main/head.tsx b/apps/web/components/main/head.tsx index 33266417..f309205a 100644 --- a/apps/web/components/main/head.tsx +++ b/apps/web/components/main/head.tsx @@ -4,20 +4,22 @@ import Link from "next/link"; function Head(props: any) { return ( -
-
+ //
+
+
POSTERCRAFT
-
+ {/*
*/} +
我的作品
-
+
我的账号
-
+
创建设计
diff --git a/apps/web/hooks/useScrollAnimate.ts b/apps/web/hooks/useScrollAnimate.ts new file mode 100644 index 00000000..bea8864d --- /dev/null +++ b/apps/web/hooks/useScrollAnimate.ts @@ -0,0 +1,33 @@ +import { useEffect, useRef } from "react"; +/** + * 滚动动画 Hook + *1.使用时先在相应页面引入style下的scrollAnimate.css文件; + *2.然后定义const boxRef = useRef(null); + *3.在需要监听的元素上添加ref={boxRef}和className="box" + *4.最后调用钩子useScrollAnimate(boxRef),传入需要监听的元素 + * @param boxRef 传入需要监听滚动的 HTML 元素的 React Ref + * @returns 无返回值 + */ +export function useScrollAnimate(boxRef:React.RefObject) { + + useEffect(() => { + const handleScroll = () => { + const box = boxRef.current; + if (box) { + const isBoxVisible = box.getBoundingClientRect().top+100 < window.innerHeight; + if (isBoxVisible && !box.classList.contains('isVisible')) { + box.classList.add('isVisible'); + } + if (!isBoxVisible && box.classList.contains('isVisible')) { + box.classList.remove('isVisible'); + } + } + }; + + window.addEventListener('scroll', handleScroll); + + return () => { + window.removeEventListener('scroll', handleScroll); + }; + }, [boxRef]); +} diff --git a/apps/web/package.json b/apps/web/package.json index 2f40b907..239fb16f 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -30,6 +30,7 @@ "@types/node": "^20", "@types/react": "^18", "@types/react-dom": "^18", + "css-types": "^1.1.0", "daisyui": "^4.12.10", "eslint": "^8", "eslint-config-next": "14.2.4", diff --git a/apps/web/style/scrollAnimate.css b/apps/web/style/scrollAnimate.css new file mode 100644 index 00000000..8eaa3f0a --- /dev/null +++ b/apps/web/style/scrollAnimate.css @@ -0,0 +1,23 @@ +@keyframes fadeIn { + from { + opacity: 0; + transform: translateY(20px); + } + to { + opacity: 1; + transform: translateY(0); + } +} + +.box { + opacity: 0; + transform: translateY(20px); + transition: opacity 0.9s ease-in-out, transform 0.9s ease-in-out; + will-change: opacity, transform; + /* 初始状态模拟动画开始前的状态 */ +} + +.isVisible { + animation: fadeIn 0.9s forwards; + /* 当添加is-visible类时,触发fadeIn动画 */ +} \ No newline at end of file diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index a403d3aa..a5d53085 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -59,7 +59,7 @@ importers: version: 5.5.3 vitest: specifier: ^2.0.2 - version: 2.0.2(@types/node@20.14.10)(jsdom@24.1.0)(terser@5.31.2) + version: 2.0.2(@types/node@20.14.10)(jsdom@24.1.0)(sass@1.77.8)(terser@5.31.2) apps/monitor: {} @@ -209,13 +209,13 @@ importers: version: 0.400.0(react@18.3.1) next: specifier: 14.2.4 - version: 14.2.4(@babel/core@7.24.7)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + version: 14.2.4(@babel/core@7.24.7)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.77.8) next-auth: specifier: ^4.24.7 - version: 4.24.7(next@14.2.4(@babel/core@7.24.7)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + version: 4.24.7(next@14.2.4(@babel/core@7.24.7)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.77.8))(react-dom@18.3.1(react@18.3.1))(react@18.3.1) next-themes: specifier: 0.2.1 - version: 0.2.1(next@14.2.4(@babel/core@7.24.7)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + version: 0.2.1(next@14.2.4(@babel/core@7.24.7)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.77.8))(react-dom@18.3.1(react@18.3.1))(react@18.3.1) react: specifier: ^18 version: 18.3.1 @@ -244,6 +244,9 @@ importers: '@types/react-dom': specifier: ^18 version: 18.3.0 + css-types: + specifier: ^1.1.0 + version: 1.1.0 daisyui: specifier: ^4.12.10 version: 4.12.10(postcss@8.4.39) @@ -283,7 +286,7 @@ importers: dependencies: vitepress: specifier: ^1.2.3 - version: 1.3.0(@algolia/client-search@4.24.0)(@types/node@20.14.10)(@types/react@18.3.3)(axios@1.7.2)(postcss@8.4.39)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(search-insights@2.15.0)(terser@5.31.2)(typescript@5.5.3) + version: 1.3.0(@algolia/client-search@4.24.0)(@types/node@20.14.10)(@types/react@18.3.3)(axios@1.7.2)(postcss@8.4.39)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.77.8)(search-insights@2.15.0)(terser@5.31.2)(typescript@5.5.3) packages/schema: dependencies: @@ -1388,24 +1391,28 @@ packages: engines: {node: '>= 10'} cpu: [arm64] os: [linux] + libc: [glibc] '@next/swc-linux-arm64-musl@14.2.4': resolution: {integrity: sha512-Alv8/XGSs/ytwQcbCHwze1HmiIkIVhDHYLjczSVrf0Wi2MvKn/blt7+S6FJitj3yTlMwMxII1gIJ9WepI4aZ/A==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] + libc: [musl] '@next/swc-linux-x64-gnu@14.2.4': resolution: {integrity: sha512-ze0ShQDBPCqxLImzw4sCdfnB3lRmN3qGMB2GWDRlq5Wqy4G36pxtNOo2usu/Nm9+V2Rh/QQnrRc2l94kYFXO6Q==} engines: {node: '>= 10'} cpu: [x64] os: [linux] + libc: [glibc] '@next/swc-linux-x64-musl@14.2.4': resolution: {integrity: sha512-8dwC0UJoc6fC7PX70csdaznVMNr16hQrTDAMPvLPloazlcaWfdPogq+UpZX6Drqb1OBlwowz8iG7WR0Tzk/diQ==} engines: {node: '>= 10'} cpu: [x64] os: [linux] + libc: [musl] '@next/swc-win32-arm64-msvc@14.2.4': resolution: {integrity: sha512-jxyg67NbEWkDyvM+O8UDbPAyYRZqGLQDTPwvrBBeOSyVWW/jFQkQKQ70JDqDSYg1ZDdl+E3nkbFbq8xM8E9x8A==} @@ -1541,46 +1548,55 @@ packages: resolution: {integrity: sha512-P9bSiAUnSSM7EmyRK+e5wgpqai86QOSv8BwvkGjLwYuOpaeomiZWifEos517CwbG+aZl1T4clSE1YqqH2JRs+g==} cpu: [arm] os: [linux] + libc: [glibc] '@rollup/rollup-linux-arm-musleabihf@4.18.1': resolution: {integrity: sha512-5RnjpACoxtS+aWOI1dURKno11d7krfpGDEn19jI8BuWmSBbUC4ytIADfROM1FZrFhQPSoP+KEa3NlEScznBTyQ==} cpu: [arm] os: [linux] + libc: [musl] '@rollup/rollup-linux-arm64-gnu@4.18.1': resolution: {integrity: sha512-8mwmGD668m8WaGbthrEYZ9CBmPug2QPGWxhJxh/vCgBjro5o96gL04WLlg5BA233OCWLqERy4YUzX3bJGXaJgQ==} cpu: [arm64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-arm64-musl@4.18.1': resolution: {integrity: sha512-dJX9u4r4bqInMGOAQoGYdwDP8lQiisWb9et+T84l2WXk41yEej8v2iGKodmdKimT8cTAYt0jFb+UEBxnPkbXEQ==} cpu: [arm64] os: [linux] + libc: [musl] '@rollup/rollup-linux-powerpc64le-gnu@4.18.1': resolution: {integrity: sha512-V72cXdTl4EI0x6FNmho4D502sy7ed+LuVW6Ym8aI6DRQ9hQZdp5sj0a2usYOlqvFBNKQnLQGwmYnujo2HvjCxQ==} cpu: [ppc64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-riscv64-gnu@4.18.1': resolution: {integrity: sha512-f+pJih7sxoKmbjghrM2RkWo2WHUW8UbfxIQiWo5yeCaCM0TveMEuAzKJte4QskBp1TIinpnRcxkquY+4WuY/tg==} cpu: [riscv64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-s390x-gnu@4.18.1': resolution: {integrity: sha512-qb1hMMT3Fr/Qz1OKovCuUM11MUNLUuHeBC2DPPAWUYYUAOFWaxInaTwTQmc7Fl5La7DShTEpmYwgdt2hG+4TEg==} cpu: [s390x] os: [linux] + libc: [glibc] '@rollup/rollup-linux-x64-gnu@4.18.1': resolution: {integrity: sha512-7O5u/p6oKUFYjRbZkL2FLbwsyoJAjyeXHCU3O4ndvzg2OFO2GinFPSJFGbiwFDaCFc+k7gs9CF243PwdPQFh5g==} cpu: [x64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-x64-musl@4.18.1': resolution: {integrity: sha512-pDLkYITdYrH/9Cv/Vlj8HppDuLMDUBmgsM0+N+xLtFd18aXgM9Nyqupb/Uw+HeidhfYg2lD6CXvz6CjoVOaKjQ==} cpu: [x64] os: [linux] + libc: [musl] '@rollup/rollup-win32-arm64-msvc@4.18.1': resolution: {integrity: sha512-W2ZNI323O/8pJdBGil1oCauuCzmVd9lDmWBBqxYZcOqWD6aWqJtVBQ1dFrF4dYpZPks6F+xCZHfzG5hYlSHZ6g==} @@ -2640,6 +2656,10 @@ packages: css-selector-tokenizer@0.8.0: resolution: {integrity: sha512-Jd6Ig3/pe62/qe5SBPTN8h8LeUg/pT4lLgtavPf7updwwHpvFzxvOQBHYj2LZDMjUnBzgvIUSjRcf6oT5HzHFg==} + css-types@1.1.0: + resolution: {integrity: sha512-2Z7B/oM+PYb4jmMOQzU5EIF5q6zZNMWzuLxo27QN+ZeKNQBI8AZpaEKP5i+EQR00i/BI3Uq8weTkhhNnxgUvyA==} + hasBin: true + cssesc@3.0.0: resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==} engines: {node: '>=4'} @@ -3572,6 +3592,9 @@ packages: resolution: {integrity: sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==} engines: {node: '>= 4'} + immutable@4.3.6: + resolution: {integrity: sha512-Ju0+lEMyzMVZarkTn/gqRpdqd5dOPaz1mCZ0SH3JV6iFw81PldE/PEB1hWVEA288HPt4WXW8O7AWxB10M+03QQ==} + import-fresh@3.3.0: resolution: {integrity: sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==} engines: {node: '>=6'} @@ -5031,6 +5054,11 @@ packages: safer-buffer@2.1.2: resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} + sass@1.77.8: + resolution: {integrity: sha512-4UHg6prsrycW20fqLGPShtEvo/WyHRVRHwOP4DzkUrObWoWI05QBSfzU71TVB7PFaL104TwNaHpjlWXAZbQiNQ==} + engines: {node: '>=14.0.0'} + hasBin: true + saxes@6.0.0: resolution: {integrity: sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==} engines: {node: '>=v12.22.7'} @@ -7511,9 +7539,9 @@ snapshots: '@ungap/structured-clone@1.2.0': {} - '@vitejs/plugin-vue@5.0.5(vite@5.3.3(@types/node@20.14.10)(terser@5.31.2))(vue@3.4.31(typescript@5.5.3))': + '@vitejs/plugin-vue@5.0.5(vite@5.3.3(@types/node@20.14.10)(sass@1.77.8)(terser@5.31.2))(vue@3.4.31(typescript@5.5.3))': dependencies: - vite: 5.3.3(@types/node@20.14.10)(terser@5.31.2) + vite: 5.3.3(@types/node@20.14.10)(sass@1.77.8)(terser@5.31.2) vue: 3.4.31(typescript@5.5.3) '@vitest/expect@2.0.2': @@ -8475,6 +8503,10 @@ snapshots: cssesc: 3.0.0 fastparse: 1.1.2 + css-types@1.1.0: + dependencies: + sass: 1.77.8 + cssesc@3.0.0: {} cssstyle@4.0.1: @@ -9629,6 +9661,8 @@ snapshots: ignore@5.3.1: {} + immutable@4.3.6: {} + import-fresh@3.3.0: dependencies: parent-module: 1.0.1 @@ -10660,13 +10694,13 @@ snapshots: neo-async@2.6.2: {} - next-auth@4.24.7(next@14.2.4(@babel/core@7.24.7)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1): + next-auth@4.24.7(next@14.2.4(@babel/core@7.24.7)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.77.8))(react-dom@18.3.1(react@18.3.1))(react@18.3.1): dependencies: '@babel/runtime': 7.24.7 '@panva/hkdf': 1.2.1 cookie: 0.5.0 jose: 4.15.9 - next: 14.2.4(@babel/core@7.24.7)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + next: 14.2.4(@babel/core@7.24.7)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.77.8) oauth: 0.9.15 openid-client: 5.6.5 preact: 10.22.1 @@ -10675,13 +10709,13 @@ snapshots: react-dom: 18.3.1(react@18.3.1) uuid: 8.3.2 - next-themes@0.2.1(next@14.2.4(@babel/core@7.24.7)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1): + next-themes@0.2.1(next@14.2.4(@babel/core@7.24.7)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.77.8))(react-dom@18.3.1(react@18.3.1))(react@18.3.1): dependencies: - next: 14.2.4(@babel/core@7.24.7)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + next: 14.2.4(@babel/core@7.24.7)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.77.8) react: 18.3.1 react-dom: 18.3.1(react@18.3.1) - next@14.2.4(@babel/core@7.24.7)(react-dom@18.3.1(react@18.3.1))(react@18.3.1): + next@14.2.4(@babel/core@7.24.7)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.77.8): dependencies: '@next/env': 14.2.4 '@swc/helpers': 0.5.5 @@ -10702,6 +10736,7 @@ snapshots: '@next/swc-win32-arm64-msvc': 14.2.4 '@next/swc-win32-ia32-msvc': 14.2.4 '@next/swc-win32-x64-msvc': 14.2.4 + sass: 1.77.8 transitivePeerDependencies: - '@babel/core' - babel-plugin-macros @@ -11289,6 +11324,12 @@ snapshots: safer-buffer@2.1.2: {} + sass@1.77.8: + dependencies: + chokidar: 3.6.0 + immutable: 4.3.6 + source-map-js: 1.2.0 + saxes@6.0.0: dependencies: xmlchars: 2.2.0 @@ -12011,13 +12052,13 @@ snapshots: vary@1.1.2: {} - vite-node@2.0.2(@types/node@20.14.10)(terser@5.31.2): + vite-node@2.0.2(@types/node@20.14.10)(sass@1.77.8)(terser@5.31.2): dependencies: cac: 6.7.14 debug: 4.3.5(supports-color@5.5.0) pathe: 1.1.2 tinyrainbow: 1.2.0 - vite: 5.3.3(@types/node@20.14.10)(terser@5.31.2) + vite: 5.3.3(@types/node@20.14.10)(sass@1.77.8)(terser@5.31.2) transitivePeerDependencies: - '@types/node' - less @@ -12028,7 +12069,7 @@ snapshots: - supports-color - terser - vite@5.3.3(@types/node@20.14.10)(terser@5.31.2): + vite@5.3.3(@types/node@20.14.10)(sass@1.77.8)(terser@5.31.2): dependencies: esbuild: 0.21.5 postcss: 8.4.39 @@ -12036,16 +12077,17 @@ snapshots: optionalDependencies: '@types/node': 20.14.10 fsevents: 2.3.3 + sass: 1.77.8 terser: 5.31.2 - vitepress@1.3.0(@algolia/client-search@4.24.0)(@types/node@20.14.10)(@types/react@18.3.3)(axios@1.7.2)(postcss@8.4.39)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(search-insights@2.15.0)(terser@5.31.2)(typescript@5.5.3): + vitepress@1.3.0(@algolia/client-search@4.24.0)(@types/node@20.14.10)(@types/react@18.3.3)(axios@1.7.2)(postcss@8.4.39)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.77.8)(search-insights@2.15.0)(terser@5.31.2)(typescript@5.5.3): dependencies: '@docsearch/css': 3.6.0 '@docsearch/js': 3.6.0(@algolia/client-search@4.24.0)(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(search-insights@2.15.0) '@shikijs/core': 1.10.3 '@shikijs/transformers': 1.10.3 '@types/markdown-it': 14.1.1 - '@vitejs/plugin-vue': 5.0.5(vite@5.3.3(@types/node@20.14.10)(terser@5.31.2))(vue@3.4.31(typescript@5.5.3)) + '@vitejs/plugin-vue': 5.0.5(vite@5.3.3(@types/node@20.14.10)(sass@1.77.8)(terser@5.31.2))(vue@3.4.31(typescript@5.5.3)) '@vue/devtools-api': 7.3.5 '@vue/shared': 3.4.31 '@vueuse/core': 10.11.0(vue@3.4.31(typescript@5.5.3)) @@ -12054,7 +12096,7 @@ snapshots: mark.js: 8.11.1 minisearch: 6.3.0 shiki: 1.10.3 - vite: 5.3.3(@types/node@20.14.10)(terser@5.31.2) + vite: 5.3.3(@types/node@20.14.10)(sass@1.77.8)(terser@5.31.2) vue: 3.4.31(typescript@5.5.3) optionalDependencies: postcss: 8.4.39 @@ -12085,7 +12127,7 @@ snapshots: - typescript - universal-cookie - vitest@2.0.2(@types/node@20.14.10)(jsdom@24.1.0)(terser@5.31.2): + vitest@2.0.2(@types/node@20.14.10)(jsdom@24.1.0)(sass@1.77.8)(terser@5.31.2): dependencies: '@ampproject/remapping': 2.3.0 '@vitest/expect': 2.0.2 @@ -12103,8 +12145,8 @@ snapshots: tinybench: 2.8.0 tinypool: 1.0.0 tinyrainbow: 1.2.0 - vite: 5.3.3(@types/node@20.14.10)(terser@5.31.2) - vite-node: 2.0.2(@types/node@20.14.10)(terser@5.31.2) + vite: 5.3.3(@types/node@20.14.10)(sass@1.77.8)(terser@5.31.2) + vite-node: 2.0.2(@types/node@20.14.10)(sass@1.77.8)(terser@5.31.2) why-is-node-running: 2.3.0 optionalDependencies: '@types/node': 20.14.10