diff --git a/public/images/icons/honor-left.png b/public/images/icons/honor-left.png new file mode 100644 index 0000000..85ffdfe Binary files /dev/null and b/public/images/icons/honor-left.png differ diff --git a/public/images/icons/honor-right.png b/public/images/icons/honor-right.png new file mode 100644 index 0000000..eb08ad3 Binary files /dev/null and b/public/images/icons/honor-right.png differ diff --git a/public/images/icons/icon-value1.png b/public/images/icons/icon-value1.png new file mode 100644 index 0000000..b8a812a Binary files /dev/null and b/public/images/icons/icon-value1.png differ diff --git a/public/images/icons/icon-value2.png b/public/images/icons/icon-value2.png new file mode 100644 index 0000000..a982f54 Binary files /dev/null and b/public/images/icons/icon-value2.png differ diff --git a/public/images/icons/icon-value3.png b/public/images/icons/icon-value3.png new file mode 100644 index 0000000..ddc9ee4 Binary files /dev/null and b/public/images/icons/icon-value3.png differ diff --git a/src/components/layout/Article/index.module.css b/src/components/layout/Article/index.module.css index fd8f682..c86a304 100644 --- a/src/components/layout/Article/index.module.css +++ b/src/components/layout/Article/index.module.css @@ -1,7 +1,7 @@ .article { width: 100%; min-height: 100vh; - padding: 120px 100px; + padding: 120px auto; .articleHeaderLine { height: 100px; diff --git a/src/components/layout/BottomTabsSection/index.module.css b/src/components/layout/BottomTabsSection/index.module.css index 8ada4e9..9b896c0 100644 --- a/src/components/layout/BottomTabsSection/index.module.css +++ b/src/components/layout/BottomTabsSection/index.module.css @@ -2,7 +2,7 @@ width: 100%; /* height: 1080px; */ height: 100vh; - padding: 100px 260px; + padding: 100px auto; background-size: cover; background-position: center; background-repeat: no-repeat; @@ -44,7 +44,7 @@ justify-content: center; gap: auto; border-top: 1px solid rgba(255,255,255,0.5); - padding: 0 200px; + padding: 0 auto; } .bottomTabsSectionContentTab { diff --git a/src/components/layout/HonorGrids/index.module.css b/src/components/layout/HonorGrids/index.module.css index 2e30e83..0229779 100644 --- a/src/components/layout/HonorGrids/index.module.css +++ b/src/components/layout/HonorGrids/index.module.css @@ -1,7 +1,7 @@ .honorGrids { width: 100%; - padding: 100px 300px; - background: rgba(216,216,216,0.5); + padding: 100px 0; + background: rgba(216, 216, 216, 0.5); .honorGridsTitle { font-family: Source Han Sans, Source Han Sans; @@ -9,11 +9,15 @@ font-size: 40px; color: #222222; line-height: 50px; - margin-bottom: 100px; text-align: center; + width: 1320px; + margin: 0 auto; + margin-bottom: 100px; } .honorGridsItems { + width: 1320px; + margin: 0 auto; /* 4*n */ display: grid; grid-template-columns: repeat(4, 1fr); @@ -23,16 +27,42 @@ .honorGridsItem { height: 116px; display: flex; + flex-direction: column; align-items: center; justify-content: center; - border: 1px solid #666; + position: relative; + padding: 0 50px; + text-align: center; .honorGridsTitle { font-weight: 400; + font-size: 16px; + color: #222222; + } + .honorGridsItemLargeTitle { + font-weight: 600; font-size: 20px; color: #222222; line-height: 30px; } + + .honorGridsItemBgleft, + .honorGridsItemBgright { + width: 70px; + height: 116px; + position: absolute; + background-size: cover; + background-position: left; + background-repeat: no-repeat; + } + + .honorGridsItemBgleft { + left: 0; + } + + .honorGridsItemBgright { + right: 0; + } } } } \ No newline at end of file diff --git a/src/components/layout/HonorGrids/index.tsx b/src/components/layout/HonorGrids/index.tsx index 0936a97..4907469 100644 --- a/src/components/layout/HonorGrids/index.tsx +++ b/src/components/layout/HonorGrids/index.tsx @@ -3,10 +3,11 @@ import styles from './index.module.css'; type Data = { title: string; items: { + largeTitle: string; title: string; }[]; } -export default function HonorGrids({ data }: {data: Data}) { +export default function HonorGrids({ data }: { data: Data }) { return (
{data.title}
@@ -14,7 +15,14 @@ export default function HonorGrids({ data }: {data: Data}) {
{data.items.map((item) => (
+
+
{item.largeTitle}
{item.title}
+
))}
diff --git a/src/components/layout/RowAccordion/index.tsx b/src/components/layout/RowAccordion/index.tsx index 94093da..f2e4f47 100644 --- a/src/components/layout/RowAccordion/index.tsx +++ b/src/components/layout/RowAccordion/index.tsx @@ -65,6 +65,10 @@ export default function RowAccordion({ data, placement='bottom' }: Props) { } }, [isInView]); + const getToPath = (link: { text: string; path: string }) => { + return link.path.includes("{id}") ? link.path.replace("{id}", link.text) : link.path; + } + return (
@@ -115,7 +119,7 @@ export default function RowAccordion({ data, placement='bottom' }: Props) { {item.links && (
{item.links?.map((link) => ( - {link.text} + {link.text} ))}
)} diff --git a/src/components/layout/TopTabsSection/index.module.css b/src/components/layout/TopTabsSection/index.module.css index 7a81683..b2c8af8 100644 --- a/src/components/layout/TopTabsSection/index.module.css +++ b/src/components/layout/TopTabsSection/index.module.css @@ -9,13 +9,13 @@ .topTabsTabs { position: relative; - /* height: 60px; */ + height: 60px; font-weight: 400; font-size: 24px; line-height: 34px; border-bottom: 1px solid #D5D8DC; width: 100%; - overflow: hidden; + overflow-y: hidden; } .topTabsNavBtn { @@ -80,8 +80,8 @@ } .topTabsTabItem { - height: 90px; - line-height: 90px; + /* height: 90px; + line-height: 90px; */ flex-shrink: 0; cursor: pointer; color: #222222; diff --git a/src/index.css b/src/index.css index fb7e8b9..9399d6f 100644 --- a/src/index.css +++ b/src/index.css @@ -35,6 +35,7 @@ html { body { margin: 0; + min-width: 1320px; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif; diff --git a/src/pages/About/Founder.module.css b/src/pages/About/Founder.module.css index 1100b5f..795b672 100644 --- a/src/pages/About/Founder.module.css +++ b/src/pages/About/Founder.module.css @@ -99,6 +99,12 @@ font-size: 1rem; color: #fff; margin-top: 3.125rem; + transition: all 0.3s ease-in-out; + li { + list-style: disc; + margin: 10px 0; + margin-left: 20px; + } } .sectionFounder { @@ -139,6 +145,11 @@ .founderPhotoContent { padding-top: 6.25rem; padding-right: 6.25rem; + li { + list-style: disc; + margin: 8px 0; + margin-left: 20px; + } } .founderPhotoContent p { diff --git a/src/pages/About/Founder.tsx b/src/pages/About/Founder.tsx index d4b80c4..c9edc70 100644 --- a/src/pages/About/Founder.tsx +++ b/src/pages/About/Founder.tsx @@ -37,7 +37,7 @@ export default function AboutFounder() {
{item.title}
-
{item.content}
+
))} diff --git a/src/pages/About/History.module.css b/src/pages/About/History.module.css index 25ba9c6..50da37a 100644 --- a/src/pages/About/History.module.css +++ b/src/pages/About/History.module.css @@ -9,7 +9,8 @@ ); min-height: 100vh; width: 100%; - padding: 6.25rem 18.75rem; + padding: 6.25rem auto; + padding-bottom: 100px; display: flex; flex-direction: column; } @@ -86,12 +87,30 @@ line-height: 1.6; color: #333; margin: 0; - max-width: 33.75rem; - margin-top: 1.875rem; + max-width: 600px; + margin-top: 20px; + + list-style: disc; + margin-left: 20px; } .timelineItem.left .desc { text-align: right; + list-style: none; + margin-left: 0; + margin-right: 20px; +} + + +.timelineItem.left li { + display: flex; + flex-direction: row; + justify-content: flex-end; +} +.timelineItem.left li.desc::after { + content: "•"; + display: block; + margin-left: 0.5em; } .dotWrapper { diff --git a/src/pages/About/History.tsx b/src/pages/About/History.tsx index 52cef3f..99dd262 100644 --- a/src/pages/About/History.tsx +++ b/src/pages/About/History.tsx @@ -107,7 +107,11 @@ function TimelineItemRow({ {!isRight && (
{item.year} -

{item.content}

+ { + item.content.split('\n').map((line, index) => ( +
  • {line}
  • + )) + }
    )} @@ -119,7 +123,11 @@ function TimelineItemRow({ {isRight && (
    {item.year} -

    {item.content}

    + { + item.content.split('\n').map((line, index) => ( +
  • {line}
  • + )) + }
    )} diff --git a/src/pages/Business/CommercialGroup.module.css b/src/pages/Business/CommercialGroup.module.css index 34f9121..0d494ee 100644 --- a/src/pages/Business/CommercialGroup.module.css +++ b/src/pages/Business/CommercialGroup.module.css @@ -139,6 +139,25 @@ background-position: center; background-repeat: no-repeat; padding: 100px 260px; + position: relative; +} + +.featuresHeroBg { + position: absolute; + inset: 0; + z-index: -1; + overflow: hidden; + pointer-events: none; +} + +.featuresHeroBgLayer { + position: absolute; + inset: 0; + background-size: cover; + background-position: center; + background-repeat: no-repeat; + transition: opacity 1s cubic-bezier(0.4, 0, 0.2, 1); + will-change: opacity; } .featuresHeroContent { @@ -167,11 +186,28 @@ } .featuresHeroTabs { + position: relative; + border-top: 1px solid rgba(255, 255, 255, 0.5); +} + +.featuresHeroTabIndicator { + position: absolute; + top: -1px; + left: 0; + height: 2px; + background: #ffffff; + pointer-events: none; + transition: + transform 0.35s cubic-bezier(0.4, 0, 0.2, 1), + width 0.35s cubic-bezier(0.4, 0, 0.2, 1), + opacity 0.2s ease; +} + +.featuresHeroTabRow { display: flex; flex-direction: row; justify-content: center; gap: 200px; - border-top: 1px solid rgba(255, 255, 255, 0.5); } .featuresHeroTab { @@ -183,11 +219,6 @@ cursor: pointer; } -.featuresHeroTab.active { - border-top: 2px solid #FFFFFF; -} - - .propertyServices { height: 100vh; color: #fff; diff --git a/src/pages/Business/CommercialGroup.tsx b/src/pages/Business/CommercialGroup.tsx index f7d2b72..3e111f4 100644 --- a/src/pages/Business/CommercialGroup.tsx +++ b/src/pages/Business/CommercialGroup.tsx @@ -1,4 +1,4 @@ -import { useState } from "react"; +import { useLayoutEffect, useRef, useState } from "react"; import { Link } from "react-router-dom"; import { useStore } from "@/store"; import styles from "./CommercialGroup.module.css"; @@ -17,17 +17,71 @@ function PlaceholderImage() { export default function BusinessCommercialGroup() { const appConfig = useStore((s) => s.appConfig); const data = appConfig?.business?.commercialGroup; + const section3Data = data?.section3Data; const [in77ImgError, setIn77ImgError] = useState(false); const [activeTabIndex, setActiveTabIndex] = useState(0); const [activeFeaturesTabIndex, setActiveFeaturesTabIndex] = useState(0); + const featuresHeroTabsRef = useRef(null); + const featuresTabItemRefs = useRef<(HTMLDivElement | null)[]>([]); + const [featuresTabIndicator, setFeaturesTabIndicator] = useState({ x: 0, width: 0 }); + + const featuresFirstBg = section3Data?.tabItems?.[0]?.backgroundImage ?? ""; + const [featuresBg, setFeaturesBg] = useState({ + a: featuresFirstBg, + b: featuresFirstBg, + showA: true, + }); + + useLayoutEffect(() => { + if (!section3Data?.tabItems?.length) return; + const next = section3Data.tabItems[activeFeaturesTabIndex]?.backgroundImage ?? ""; + setFeaturesBg((prev) => { + const visible = prev.showA ? prev.a : prev.b; + if (next === visible) return prev; + // 数据首帧就绪:直接铺满两层,避免从空图做一次淡入 + if (!visible && next) { + return { a: next, b: next, showA: true }; + } + if (prev.showA) { + return { ...prev, b: next, showA: false }; + } + return { ...prev, a: next, showA: true }; + }); + }, [activeFeaturesTabIndex, section3Data]); + + useLayoutEffect(() => { + if (!section3Data?.tabItems?.length) return; + const root = featuresHeroTabsRef.current; + if (!root) return; + + const updateIndicator = () => { + const tab = featuresTabItemRefs.current[activeFeaturesTabIndex]; + if (!tab) return; + const rootRect = root.getBoundingClientRect(); + const tabRect = tab.getBoundingClientRect(); + setFeaturesTabIndicator({ + x: tabRect.left - rootRect.left, + width: tabRect.width, + }); + }; + + updateIndicator(); + const ro = new ResizeObserver(updateIndicator); + ro.observe(root); + window.addEventListener("resize", updateIndicator); + return () => { + ro.disconnect(); + window.removeEventListener("resize", updateIndicator); + }; + }, [activeFeaturesTabIndex, section3Data?.tabItems]); + if (!data) return null; const banner = data.banner; const section1Data = data.section1Data; const section2Data = data.section2Data; - const section3Data = data.section3Data; return (
    @@ -41,7 +95,7 @@ export default function BusinessCommercialGroup() { {section1Data && }
    @@ -72,25 +126,53 @@ export default function BusinessCommercialGroup() {
    +
    +
    +
    +
    {section3Data.tabItems[activeFeaturesTabIndex]?.tabName}
    {section3Data.tabItems[activeFeaturesTabIndex]?.content}
    -
    - {section3Data.tabItems.map((item: { tabName: string }, i: number) => ( -
    setActiveFeaturesTabIndex(i)} - > - {item.tabName} -
    - ))} +
    +
    0 ? 1 : 0, + }} + /> +
    + {section3Data.tabItems.map((item: { tabName: string }, i: number) => ( +
    { + featuresTabItemRefs.current[i] = el; + }} + className={styles.featuresHeroTab} + onClick={() => setActiveFeaturesTabIndex(i)} + > + {item.tabName} +
    + ))} +
    diff --git a/src/pages/Business/InvestGroup.tsx b/src/pages/Business/InvestGroup.tsx index 4f294f9..dd72973 100644 --- a/src/pages/Business/InvestGroup.tsx +++ b/src/pages/Business/InvestGroup.tsx @@ -68,6 +68,7 @@ export default function InvestGroup() { background={section4Data.backgroundImage} maskBackground="rgba(20,53,92,0.1)" className={styles.industryFoster} + height="100vh" >
    {section4Data.title}