diff --git a/package.json b/package.json index 3635f4c..3c71abf 100644 --- a/package.json +++ b/package.json @@ -45,6 +45,7 @@ "jest": "^27.4.3", "jest-resolve": "^27.4.2", "jest-watch-typeahead": "^1.0.0", + "lenis": "^1.3.19", "mime": "^4.0.7", "mini-css-extract-plugin": "^2.4.5", "motion": "^12.23.25", @@ -56,6 +57,7 @@ "postcss-preset-env": "^7.0.1", "prompts": "^2.4.2", "react": "^19.1.0", + "react-activation": "^0.13.4", "react-app-polyfill": "^3.0.0", "react-dev-utils": "^12.0.1", "react-dom": "^19.1.0", @@ -79,8 +81,7 @@ "webpack-manifest-plugin": "^4.0.2", "winston": "^3.17.0", "workbox-webpack-plugin": "^6.4.1", - "zustand": "^5.0.11", - "react-activation": "^0.13.4" + "zustand": "^5.0.11" }, "scripts": { "dev": "node --stack-size=12800 --stack-trace-limit=20 scripts/start.js", diff --git a/src/components/SineWaveTimeline/index.module.css b/src/components/SineWaveTimeline/index.module.css index 9c1bb14..2d880bc 100644 --- a/src/components/SineWaveTimeline/index.module.css +++ b/src/components/SineWaveTimeline/index.module.css @@ -2,6 +2,7 @@ width: 100%; overflow-x: auto; overflow-y: auto; + cursor: all-scroll; } .content { diff --git a/src/components/SineWaveTimeline/index.tsx b/src/components/SineWaveTimeline/index.tsx index 1b19f87..6884e59 100644 --- a/src/components/SineWaveTimeline/index.tsx +++ b/src/components/SineWaveTimeline/index.tsx @@ -19,6 +19,7 @@ export type TimelineItem = { type Props = { items: TimelineItem[]; height?: number; + refElement?: React.RefObject; }; function generateSinePath( @@ -101,7 +102,7 @@ function computeContentWidth(items: TimelineItem[]): number { return lastX + 280; } -export default function SineWaveTimeline({ items, height: propHeight = 400 }: Props) { +export default function SineWaveTimeline({ items, height: propHeight = 400, refElement }: Props) { if (!items?.length) return null; const height = propHeight ?? 400; @@ -112,7 +113,7 @@ export default function SineWaveTimeline({ items, height: propHeight = 400 }: Pr const bgPathD = generateCosinePath(contentWidth, height, AMPLITUDE * 0.9); return ( -
+
-

{data.title}{data.content}

+

{data.title} {data.content}

{data.statsData && } + { + data.tags &&
+ { + data.tags.map((tag) => ( +
{tag}
+ )) + } +
+ } {children} diff --git a/src/components/layout/StatsRow/StatsRow.module.css b/src/components/layout/StatsRow/StatsRow.module.css index fb6cd93..1c473c0 100644 --- a/src/components/layout/StatsRow/StatsRow.module.css +++ b/src/components/layout/StatsRow/StatsRow.module.css @@ -35,4 +35,5 @@ .statLabel { font-size: 1rem; color: var(--stats-label-color); + text-align: center; } \ No newline at end of file diff --git a/src/components/layout/TopTabsSection/TopTabs.tsx b/src/components/layout/TopTabsSection/TopTabs.tsx index 1fe37ed..3f12187 100644 --- a/src/components/layout/TopTabsSection/TopTabs.tsx +++ b/src/components/layout/TopTabsSection/TopTabs.tsx @@ -1,6 +1,7 @@ import { useRef, useEffect, useState, useCallback } from 'react'; import { LeftOutlined, RightOutlined } from '@ant-design/icons'; import styles from './index.module.css'; +import { useStore } from '@/store'; type Data = { tabItems: { @@ -19,6 +20,8 @@ type Data = { className?: string; } export default function TopTabs({ data, activeIndex, setActiveIndex, className }: { data: Data, activeIndex: number, setActiveIndex: (index: number) => void, className?: string }) { + const store = useStore(); + const locale = useStore((state) => state.locale); const containerRef = useRef(null); const scrollRef = useRef(null); @@ -99,9 +102,17 @@ export default function TopTabs({ data, activeIndex, setActiveIndex, className } }; }, [activeIndex, data.tabItems.length, updateIndicatorPosition, updateScrollState]); + + useEffect(() => { + console.log('locale', locale); + updateIndicatorPosition(); + }, [locale]); + + return (
-
+
{canScrollLeft && (
); } + + +function TimeLineComponent({ section4Data }: { section4Data: any }) { + const refElement = useRef(null); + const sectionRef = useRef(null); + const [isSectionInView, setIsSectionInView] = useState(false); + + useEffect(() => { + if (!sectionRef.current) return; + + const observer = new IntersectionObserver(([entry]) => { + setIsSectionInView(entry.isIntersecting); + }, { + threshold: 0.2, + }); + + observer.observe(sectionRef.current); + return () => { + observer.disconnect(); + }; + }, []); + + useEffect(() => { + if (!isSectionInView || !refElement.current) return; + + const wrapper = refElement.current; + const content = wrapper.firstElementChild as HTMLElement | null; + if (!content) return; + + const lenis = new Lenis({ + wrapper, + content, + orientation: "horizontal", + gestureOrientation: "both", + smoothWheel: true, + }); + + let rafId = 0; + const raf = (time: number) => { + lenis.raf(time); + rafId = requestAnimationFrame(raf); + }; + + rafId = requestAnimationFrame(raf); + + return () => { + cancelAnimationFrame(rafId); + lenis.destroy(); + }; + }, [isSectionInView]); + return ( + <> + {section4Data && ( +
+
{section4Data?.title}
+
+ +
+
+ )} + + ) +} \ No newline at end of file diff --git a/src/pages/Business/CommercialGroup.module.css b/src/pages/Business/CommercialGroup.module.css index 0d494ee..01203de 100644 --- a/src/pages/Business/CommercialGroup.module.css +++ b/src/pages/Business/CommercialGroup.module.css @@ -205,17 +205,20 @@ .featuresHeroTabRow { display: flex; + justify-content: space-evenly; flex-direction: row; - justify-content: center; - gap: 200px; + /* gap: 100px; */ } .featuresHeroTab { font-weight: 500; font-size: 20px; color: #FFFFFF; - line-height: 60px; height: 60px; + display: flex; + align-items: center; + justify-content: center; + text-align: center; cursor: pointer; } diff --git a/src/pages/Business/CommercialGroup.tsx b/src/pages/Business/CommercialGroup.tsx index 3e111f4..8e7fc57 100644 --- a/src/pages/Business/CommercialGroup.tsx +++ b/src/pages/Business/CommercialGroup.tsx @@ -16,6 +16,7 @@ function PlaceholderImage() { export default function BusinessCommercialGroup() { const appConfig = useStore((s) => s.appConfig); + const { viewDetail="查看详情" } = appConfig?.__global__?.others const data = appConfig?.business?.commercialGroup; const section3Data = data?.section3Data; @@ -113,12 +114,12 @@ export default function BusinessCommercialGroup() { )}
-

{section2Data.tabItems[activeTabIndex]?.content}

+

- 查看详情 + {viewDetail}
@@ -186,7 +187,7 @@ export default function BusinessCommercialGroup() {
物业服务

国内一流物业服务品牌

- 查看详情 + {viewDetail}
diff --git a/src/pages/Join/Campus.tsx b/src/pages/Join/Campus.tsx index ae7256c..541285f 100644 --- a/src/pages/Join/Campus.tsx +++ b/src/pages/Join/Campus.tsx @@ -22,6 +22,7 @@ type SelectOption = { label: string; value: string }; export default function JoinCampus() { const appConfig = useStore((s) => s.appConfig); + const { viewDetail="查看详情" } = appConfig?.__global__?.others const supportLocales = useStore((s) => s.supportLocales); const categoryList = useStore((s) => s.categoryList); const locale = useStore((s) => s.locale); @@ -132,7 +133,7 @@ export default function JoinCampus() {
{item.title}
-
查看详情
+
{viewDetail}
{item.labels.map((label, index) => (