|
|
@@ -1,156 +1,203 @@
|
|
|
-import React, { useState, useEffect } from 'react';
|
|
|
+import React from 'react';
|
|
|
import DarkOverlay from "@/components/common/DarkOverlay.jsx";
|
|
|
import businessItems from '@/data/business';
|
|
|
import {useScrollAnimation} from "@/hooks/useScrollAnimation";
|
|
|
-import { useCountUp } from "@/hooks/useCountUp";
|
|
|
-import { useNavigate } from 'react-router-dom';
|
|
|
+import {useCountUp} from "@/hooks/useCountUp";
|
|
|
+import {useNavigate} from 'react-router-dom';
|
|
|
|
|
|
-const RankBox = (title: string, rank: string, topPercent: string, isVisible: boolean) => {
|
|
|
- const rankNumber = parseInt(rank.replace('위', ''));
|
|
|
- const percentNumber = parseInt(topPercent.replace('%', ''));
|
|
|
+const RankSection = ({title, rank, topPercent, visible, colorPrimary, colorSecondary}: {
|
|
|
+ title: string;
|
|
|
+ rank: string;
|
|
|
+ topPercent: string;
|
|
|
+ visible: boolean;
|
|
|
+ colorPrimary: string;
|
|
|
+ colorSecondary?: string;
|
|
|
+}) => {
|
|
|
+ const rankNumber = parseInt(rank.replace("위", ""));
|
|
|
+ const percentNumber = parseInt(topPercent.replace("%", ""));
|
|
|
|
|
|
- const animatedRank = useCountUp({
|
|
|
- end: rankNumber,
|
|
|
- start: rankNumber === 1 ? 100 : 50,
|
|
|
- duration: 2000,
|
|
|
- isVisible
|
|
|
- });
|
|
|
+ const animatedRank = useCountUp({
|
|
|
+ end: rankNumber,
|
|
|
+ start: rankNumber === 1 ? 100 : 50,
|
|
|
+ duration: 2000,
|
|
|
+ isVisible: visible,
|
|
|
+ });
|
|
|
|
|
|
- const animatedPercent = useCountUp({
|
|
|
- end: percentNumber,
|
|
|
- start: 20,
|
|
|
- duration: 2000,
|
|
|
- isVisible
|
|
|
- });
|
|
|
+ const animatedPercent = useCountUp({
|
|
|
+ end: percentNumber,
|
|
|
+ start: 20,
|
|
|
+ duration: 2000,
|
|
|
+ isVisible: visible,
|
|
|
+ });
|
|
|
|
|
|
- return (
|
|
|
+ const secondary = colorSecondary ?? colorPrimary;
|
|
|
+
|
|
|
+ return (
|
|
|
+ <>
|
|
|
+ <div className="flex justify-center items-center">
|
|
|
+ <svg
|
|
|
+ width={40}
|
|
|
+ height={41}
|
|
|
+ viewBox="0 0 98 99"
|
|
|
+ fill="none"
|
|
|
+ xmlns="http://www.w3.org/2000/svg"
|
|
|
+ className="w-8 h-8 sm:w-10 sm:h-10 lg:w-16 lg:h-16"
|
|
|
+ aria-hidden
|
|
|
+ >
|
|
|
+ <path d="M40.833 45.417H65.333L89.793 4.583H65.293L40.833 45.417Z" fill={colorPrimary}/>
|
|
|
+ <path d="M57.126 45.417H32.626L8.167 4.583h24.5L57.126 45.417Z" fill={secondary}/>
|
|
|
+ <path
|
|
|
+ d="M49 94.417c15.786 0 28.583-12.797 28.583-28.583 0-15.786-12.797-28.583-28.583-28.583S20.417 50.048 20.417 65.834 33.214 94.417 49 94.417Z"
|
|
|
+ fill="#E7ECEF"/>
|
|
|
+ </svg>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div className="flex justify-center">
|
|
|
<div className="flex flex-col items-center justify-center w-full max-w-[280px] mx-auto">
|
|
|
- <div className="text-center text-black/40 text-xs sm:text-lg lg:text-2xl font-semibold font-['Noto_Sans_KR'] mb-3 sm:mb-6 lg:mb-10 antialiased">
|
|
|
- {title}
|
|
|
+ <div className="text-center text-black/40 text-xs sm:text-lg lg:text-2xl font-semibold font-['Noto_Sans_KR'] mb-3 sm:mb-6 lg:mb-10 antialiased">
|
|
|
+ {title}
|
|
|
+ </div>
|
|
|
+ <div className="flex w-full justify-center items-center mb-2 sm:mb-4">
|
|
|
+ <div className="text-black/40 text-sm sm:text-lg lg:text-3xl font-semibold font-['Noto_Sans_KR'] mr-4 sm:mr-6 antialiased">
|
|
|
+ 지역
|
|
|
</div>
|
|
|
- <div className="flex w-full justify-center items-center mb-2 sm:mb-4">
|
|
|
- <div className="text-black/40 text-sm sm:text-lg lg:text-3xl font-semibold font-['Noto_Sans_KR'] mr-4 sm:mr-6 antialiased">
|
|
|
- 지역
|
|
|
- </div>
|
|
|
- <div className="text-blue-900 text-xl sm:text-3xl lg:text-6xl font-bold font-['Noto_Sans_KR'] antialiased" style={{opacity: animatedRank.opacity}}>
|
|
|
- {animatedRank.count}<span className="text-lg sm:text-xl lg:text-3xl ml-1">위</span>
|
|
|
- </div>
|
|
|
+ <div className="flex text-blue-900 text-xl sm:text-3xl lg:text-6xl font-bold font-['Noto_Sans_KR'] antialiased" style={{opacity: animatedRank.opacity}}>
|
|
|
+ {animatedRank.count}
|
|
|
+ <span className="text-lg sm:text-xl lg:text-3xl ml-1">위</span>
|
|
|
</div>
|
|
|
- <div className="flex w-full justify-center items-center">
|
|
|
- <div className="text-black/40 text-sm sm:text-lg lg:text-3xl font-semibold font-['Noto_Sans_KR'] mr-4 sm:mr-6 antialiased">
|
|
|
- 상위
|
|
|
- </div>
|
|
|
- <div className="text-blue-900 text-xl sm:text-3xl lg:text-6xl font-bold font-['Noto_Sans_KR'] antialiased" style={{opacity: animatedPercent.opacity}}>
|
|
|
- {animatedPercent.count}<span className="text-lg sm:text-xl lg:text-3xl ml-1">%</span>
|
|
|
- </div>
|
|
|
+ </div>
|
|
|
+ <div className="flex w-full justify-center items-center">
|
|
|
+ <div className="text-black/40 text-sm sm:text-lg lg:text-3xl font-semibold font-['Noto_Sans_KR'] mr-4 sm:mr-6 antialiased">
|
|
|
+ 상위
|
|
|
+ </div>
|
|
|
+ <div
|
|
|
+ className="text-blue-900 text-xl sm:text-3xl lg:text-6xl font-bold font-['Noto_Sans_KR'] antialiased"
|
|
|
+ style={{opacity: animatedPercent.opacity}}
|
|
|
+ >
|
|
|
+ {animatedPercent.count}
|
|
|
+ <span className="text-lg sm:text-xl lg:text-3xl ml-1">%</span>
|
|
|
</div>
|
|
|
+ </div>
|
|
|
</div>
|
|
|
- );
|
|
|
+ </div>
|
|
|
+ </>
|
|
|
+ );
|
|
|
};
|
|
|
|
|
|
+const rankItems = [
|
|
|
+ {
|
|
|
+ title: "소방공사",
|
|
|
+ rank: "15위",
|
|
|
+ topPercent: "5%",
|
|
|
+ colorPrimary: "#CC0000",
|
|
|
+ },
|
|
|
+ {
|
|
|
+ title: "통신공사",
|
|
|
+ rank: "1위",
|
|
|
+ topPercent: "1%",
|
|
|
+ colorPrimary: "#005CFF",
|
|
|
+ colorSecondary: "#1E5CFF",
|
|
|
+ },
|
|
|
+ {
|
|
|
+ title: "전기공사",
|
|
|
+ rank: "9위",
|
|
|
+ topPercent: "2%",
|
|
|
+ colorPrimary: "#FFCC00",
|
|
|
+ },
|
|
|
+];
|
|
|
|
|
|
const Business = () => {
|
|
|
- const { ref: businessRef, isVisible: businessVisible } = useScrollAnimation({ threshold: 0.1 });
|
|
|
- const { ref: rankRef, isVisible: rankVisible } = useScrollAnimation({ threshold: 0.1 });
|
|
|
- const navigate = useNavigate();
|
|
|
+ const {ref: businessRef, isVisible: businessVisible} = useScrollAnimation({threshold: 0.1});
|
|
|
+ const {ref: rankRef, isVisible: rankVisible} = useScrollAnimation({threshold: 0.1});
|
|
|
+ const navigate = useNavigate();
|
|
|
|
|
|
- const years27 = useCountUp({ end: 27, start: 0, duration: 2000, isVisible: rankVisible });
|
|
|
- const years947 = useCountUp({ end: 947, start: 0, duration: 2500, isVisible: rankVisible });
|
|
|
- const rank1 = useCountUp({ end: 1, start: 30, duration: 2000, isVisible: rankVisible });
|
|
|
+ const years27 = useCountUp({end: 27, start: 0, duration: 2000, isVisible: rankVisible});
|
|
|
+ const years947 = useCountUp({end: 947, start: 0, duration: 2500, isVisible: rankVisible});
|
|
|
+ const rank1 = useCountUp({end: 1, start: 30, duration: 2000, isVisible: rankVisible});
|
|
|
|
|
|
- const handleCardClick = (item: any) => {
|
|
|
- navigate('/business/sections', { state: { selectedItem: item } });
|
|
|
- };
|
|
|
+ const handleCardClick = (item: any) => {
|
|
|
+ navigate('/business/sections', {state: {selectedItem: item}});
|
|
|
+ };
|
|
|
|
|
|
- return (
|
|
|
- <div className="max-w-7xl mx-auto px-[2vw] py-[4vw] space-y-[5vw]">
|
|
|
- <div ref={businessRef} className={`transition-all duration-1000 ${businessVisible ? 'opacity-100 translate-y-0' : 'opacity-0 translate-y-10'}`}>
|
|
|
- <div className="space-y-3 mb-4">
|
|
|
- <div className="text-blue-900 text-2xl sm:text-3xl lg:text-4xl font-bold font-['Noto_Sans_KR'] antialiased">반도산전 Business Solution</div>
|
|
|
- <div className="text-zinc-500 text-sm sm:text-md font-semibold font-['Noto_Sans_KR'] antialiased">반도산전이 선도하는 힘</div>
|
|
|
- </div>
|
|
|
+ return (
|
|
|
+ <div className="max-w-7xl mx-auto px-[2vw] py-[4vw] space-y-[5vw]">
|
|
|
+ <div ref={businessRef}
|
|
|
+ className={`transition-all duration-1000 ${businessVisible ? 'opacity-100 translate-y-0' : 'opacity-0 translate-y-10'}`}>
|
|
|
+ <div className="space-y-3 mb-4">
|
|
|
+ <div
|
|
|
+ className="text-blue-900 text-2xl sm:text-3xl lg:text-4xl font-bold font-['Noto_Sans_KR'] antialiased">반도산전
|
|
|
+ Business Solution
|
|
|
+ </div>
|
|
|
+ <div className="text-zinc-500 text-sm sm:text-md font-semibold font-['Noto_Sans_KR'] antialiased">반도산전이 선도하는
|
|
|
+ 힘
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
|
|
|
- <div className="bg-white flex flex-wrap gap-2 sm:gap-[0.3vw] w-full">
|
|
|
- {businessItems.map((item, index) => (
|
|
|
- <div
|
|
|
- key={index}
|
|
|
- onClick={() => handleCardClick(item)}
|
|
|
- className="relative flex-[0_0_calc(50%-4px)] sm:flex-[0_0_calc(33.33%-8px)] lg:flex-[0_0_calc((100%-24px)/5)] bg-cover bg-center h-36 sm:h-40 lg:h-44 cursor-pointer"
|
|
|
- style={{backgroundImage: `url(${item.image})`}}
|
|
|
- >
|
|
|
- <DarkOverlay />
|
|
|
-
|
|
|
- <div className="relative p-3 sm:p-4 h-full flex flex-col justify-end">
|
|
|
- <div className="text-white text-sm sm:text-base lg:text-lg font-bold font-['Noto_Sans_KR'] antialiased leading-tight mb-1">
|
|
|
- {item.label.split('\n').map((line, idx) => (
|
|
|
- <div key={idx}>{line}</div>
|
|
|
- ))}
|
|
|
- </div>
|
|
|
- <div className="text-white text-xs sm:text-sm lg:text-base font-medium font-['Noto_Sans_KR'] antialiased">상세보기</div>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- ))}
|
|
|
- </div>
|
|
|
- </div>
|
|
|
+ <div className="bg-white flex flex-wrap gap-2 sm:gap-[0.3vw] w-full">
|
|
|
+ {businessItems.map((item, index) => (
|
|
|
+ <div
|
|
|
+ key={index}
|
|
|
+ onClick={() => handleCardClick(item)}
|
|
|
+ className="relative flex-[0_0_calc(50%-4px)] sm:flex-[0_0_calc(33.33%-8px)] lg:flex-[0_0_calc((100%-24px)/5)] bg-cover bg-center h-36 sm:h-40 lg:h-44 cursor-pointer"
|
|
|
+ style={{backgroundImage: `url(${item.image})`}}
|
|
|
+ >
|
|
|
+ <DarkOverlay/>
|
|
|
|
|
|
- <div ref={rankRef} className={`transition-all duration-1000 ${rankVisible ? 'opacity-100 translate-y-0' : 'opacity-0 translate-y-10'}`}>
|
|
|
- <div className="space-y-2 mb-2.5 pb-6">
|
|
|
- <div className="text-2xl sm:text-3xl lg:text-4xl text-blue-900 font-bold font-['Noto_Sans_KR'] antialiased">반도산전은</div>
|
|
|
+ <div className="relative p-3 sm:p-4 h-full flex flex-col justify-end">
|
|
|
+ <div
|
|
|
+ className="text-white text-sm sm:text-base lg:text-lg font-bold font-['Noto_Sans_KR'] antialiased leading-tight mb-1">
|
|
|
+ {item.label.split('\n').map((line, idx) => (
|
|
|
+ <div key={idx}>{line}</div>
|
|
|
+ ))}
|
|
|
</div>
|
|
|
- <div>
|
|
|
- <div className="text-center mb-10 sm:mb-15 px-4">
|
|
|
- <div className="text-zinc-600 font-semibold font-['Noto_Sans_KR'] leading-loose sm:leading-[60px] text-xs sm:text-sm lg:text-lg xl:text-xl antialiased">
|
|
|
- 1997년부터 2025년까지 <span className="text-blue-900 text-lg sm:text-xl lg:text-2xl xl:text-3xl" style={{opacity: years27.opacity}}>{years27.count}</span>년간 축적된 기술력과 신뢰를 바탕으로,
|
|
|
- </div>
|
|
|
- <div className="text-zinc-600 font-semibold font-['Noto_Sans_KR'] leading-loose sm:leading-[60px] text-xs sm:text-sm lg:text-lg xl:text-xl antialiased">
|
|
|
- 부산 · 울산 · 경남 시공능력평가 <span className="text-blue-900 text-lg sm:text-xl lg:text-2xl xl:text-3xl" style={{opacity: rank1.opacity}}>{rank1.count}</span>위를 달성하였으며,
|
|
|
- </div>
|
|
|
- <div className="text-zinc-600 font-semibold font-['Noto_Sans_KR'] leading-loose sm:leading-[60px] text-xs sm:text-sm lg:text-lg xl:text-xl antialiased">
|
|
|
- <span className="text-blue-900 text-lg sm:text-xl lg:text-2xl xl:text-3xl" style={{opacity: years947.opacity}}>{years947.count}</span>억 매출을 달성한 외감법인입니다.
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- <div className="flex flex-wrap justify-center items-center gap-3 sm:gap-4 lg:gap-8 max-w-6xl mx-auto">
|
|
|
- <div className="flex justify-center items-center">
|
|
|
- <svg width="40" height="41" viewBox="0 0 98 99" fill="none" xmlns="http://www.w3.org/2000/svg" className="w-8 h-8 sm:w-10 sm:h-10 lg:w-16 lg:h-16">
|
|
|
- <path d="M40.8333 45.4166H65.3333L89.7925 4.58325H65.2925L40.8333 45.4166Z" fill="#CC0000"/>
|
|
|
- <path d="M57.1258 45.4166H32.6258L8.16666 4.58325H32.6667L57.1258 45.4166Z" fill="#CC0000"/>
|
|
|
- <path d="M49 94.4167C64.7862 94.4167 77.5833 81.6195 77.5833 65.8333C77.5833 50.0472 64.7862 37.25 49 37.25C33.2139 37.25 20.4167 50.0472 20.4167 65.8333C20.4167 81.6195 33.2139 94.4167 49 94.4167Z" fill="#E7ECEF"/>
|
|
|
- </svg>
|
|
|
- </div>
|
|
|
- <div className="flex justify-center">
|
|
|
- {RankBox("소방공사", "15위", "5%", rankVisible)}
|
|
|
- </div>
|
|
|
-
|
|
|
- <div className="w-px h-16 lg:h-24 bg-gray-200"></div>
|
|
|
-
|
|
|
- <div className="flex justify-center items-center">
|
|
|
- <svg width="40" height="41" viewBox="0 0 98 99" fill="none" xmlns="http://www.w3.org/2000/svg" className="w-8 h-8 sm:w-10 sm:h-10 lg:w-16 lg:h-16">
|
|
|
- <path d="M40.8333 45.4166H65.3333L89.7925 4.58325H65.2925L40.8333 45.4166Z" fill="#005CFF"/>
|
|
|
- <path d="M57.1258 45.4166H32.6258L8.16666 4.58325H32.6667L57.1258 45.4166Z" fill="#1E5CFF"/>
|
|
|
- <path d="M49 94.4167C64.7862 94.4167 77.5833 81.6195 77.5833 65.8333C77.5833 50.0472 64.7862 37.25 49 37.25C33.2139 37.25 20.4167 50.0472 20.4167 65.8333C20.4167 81.6195 33.2139 94.4167 49 94.4167Z" fill="#E7ECEF"/>
|
|
|
- </svg>
|
|
|
- </div>
|
|
|
-
|
|
|
- <div className="flex justify-center">
|
|
|
- {RankBox("통신공사", "1위", "1%", rankVisible)}
|
|
|
- </div>
|
|
|
-
|
|
|
- <div className="w-px h-16 lg:h-24 bg-gray-200"></div>
|
|
|
- <div className="flex justify-center items-center">
|
|
|
- <svg width="40" height="41" viewBox="0 0 98 99" fill="none" xmlns="http://www.w3.org/2000/svg" className="w-8 h-8 sm:w-10 sm:h-10 lg:w-16 lg:h-16">
|
|
|
- <path d="M40.8333 45.4166H65.3333L89.7925 4.58325H65.2925L40.8333 45.4166Z" fill="#FFCC00"/>
|
|
|
- <path d="M57.1258 45.4166H32.6258L8.16666 4.58325H32.6667L57.1258 45.4166Z" fill="#FFCC00"/>
|
|
|
- <path d="M49 94.4167C64.7862 94.4167 77.5833 81.6195 77.5833 65.8333C77.5833 50.0472 64.7862 37.25 49 37.25C33.2139 37.25 20.4167 50.0472 20.4167 65.8333C20.4167 81.6195 33.2139 94.4167 49 94.4167Z" fill="#E7ECEF"/>
|
|
|
- </svg>
|
|
|
- </div>
|
|
|
- <div className="flex justify-center">
|
|
|
- {RankBox("전기공사", "9위", "2%", rankVisible)}
|
|
|
- </div>
|
|
|
- </div>
|
|
|
+ <div
|
|
|
+ className="text-white text-xs sm:text-sm lg:text-base font-medium font-['Noto_Sans_KR'] antialiased">상세보기
|
|
|
</div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ ))}
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div ref={rankRef}
|
|
|
+ className={`transition-all duration-1000 ${rankVisible ? 'opacity-100 translate-y-0' : 'opacity-0 translate-y-10'}`}>
|
|
|
+ <div className="space-y-2 mb-2.5 pb-6">
|
|
|
+ <div
|
|
|
+ className="text-2xl sm:text-3xl lg:text-4xl text-blue-900 font-bold font-['Noto_Sans_KR'] antialiased">반도산전은
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div>
|
|
|
+ <div className="text-center mb-10 sm:mb-15 px-4">
|
|
|
+ <div
|
|
|
+ className="text-zinc-600 font-semibold font-['Noto_Sans_KR'] leading-loose sm:leading-[60px] text-xs sm:text-sm lg:text-lg xl:text-xl antialiased">
|
|
|
+ 1997년부터 2025년까지 <span className="text-blue-900 text-lg sm:text-xl lg:text-2xl xl:text-3xl"
|
|
|
+ style={{opacity: years27.opacity}}>{years27.count}</span>년간 축적된 기술력과 신뢰를 바탕으로,
|
|
|
+ </div>
|
|
|
+ <div
|
|
|
+ className="text-zinc-600 font-semibold font-['Noto_Sans_KR'] leading-loose sm:leading-[60px] text-xs sm:text-sm lg:text-lg xl:text-xl antialiased">
|
|
|
+ 부산 · 울산 · 경남 시공능력평가 <span className="text-blue-900 text-lg sm:text-xl lg:text-2xl xl:text-3xl"
|
|
|
+ style={{opacity: rank1.opacity}}>{rank1.count}</span>위를 달성하였으며,
|
|
|
+ </div>
|
|
|
+ <div
|
|
|
+ className="text-zinc-600 font-semibold font-['Noto_Sans_KR'] leading-loose sm:leading-[60px] text-xs sm:text-sm lg:text-lg xl:text-xl antialiased">
|
|
|
+ <span className="text-blue-900 text-lg sm:text-xl lg:text-2xl xl:text-3xl"
|
|
|
+ style={{opacity: years947.opacity}}>{years947.count}</span>억 매출을 달성한 외감법인입니다.
|
|
|
</div>
|
|
|
+ </div>
|
|
|
+ <div className="flex justify-center items-center gap-3 sm:gap-4 lg:gap-8 max-w-6xl mx-auto overflow-auto">
|
|
|
+ {rankItems.map((item, idx) => (
|
|
|
+ <React.Fragment key={item.title}>
|
|
|
+ <RankSection {...item} visible={rankVisible}/>
|
|
|
+ {idx < rankItems.length - 1 && (
|
|
|
+ <div className="w-px h-16 lg:h-24 bg-gray-200"></div>
|
|
|
+ )}
|
|
|
+ </React.Fragment>
|
|
|
+ ))}
|
|
|
+ </div>
|
|
|
</div>
|
|
|
- )
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ )
|
|
|
}
|
|
|
|
|
|
export default Business;
|