Browse Source

feat : si 페이지 추가

remotes/origin/main
이시연 3 weeks ago
parent
commit
4c778e284c
  1. BIN
      public/images/si_img1.png
  2. 84
      src/css/common.css
  3. 420
      src/pages/business/SiPage.jsx

BIN
public/images/si_img1.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 MiB

After

Width:  |  Height:  |  Size: 874 KiB

84
src/css/common.css

@ -915,9 +915,9 @@ body{overflow-x:hidden;}
/* ======================================== /* ========================================
SI PAGE - PROJECT ARCHIVE SECTION SI PAGE - PROJECT ARCHIVE SECTION
======================================== */ ======================================== */
.si-archive-wrap .inner-wrap { max-width: none; padding: 0; margin: 0; }
.si_archive { padding:100px 0 120px; max-width:1660px; margin-left: auto; margin-right: 0;} .si_archive { padding:100px 0 120px; max-width:1660px; margin-left: auto; margin-right: 0;}
.si_archive__main { display:flex; align-items:flex-start; gap:48px; } .si_archive__main { display:flex; align-items:flex-start; gap:46px; }
.si_archive__header { flex: 0 0 320px; padding-top: 24px; } .si_archive__header { flex: 0 0 320px; padding-top: 24px; }
.si_archive__right { flex:1; min-width:0; } .si_archive__right { flex:1; min-width:0; }
.si_archive__eyebrow { display:block; font-size:12px; font-weight:600; letter-spacing:.12em; color:#2563eb; text-transform:uppercase; margin-bottom:16px; } .si_archive__eyebrow { display:block; font-size:12px; font-weight:600; letter-spacing:.12em; color:#2563eb; text-transform:uppercase; margin-bottom:16px; }
@ -930,12 +930,10 @@ body{overflow-x:hidden;}
.si_archive__slider { overflow: hidden; user-select: none; cursor: grab} .si_archive__slider { overflow: hidden; user-select: none; cursor: grab}
.si_archive__slider:active { cursor: grabbing; } .si_archive__slider:active { cursor: grabbing; }
.si_archive__track { display:flex; gap:18px; will-change:transform; } .si_archive__track { display: flex; gap: 18px; will-change: transform; padding-right: 40px; }
.si_archive__card { flex: 0 0 65%; padding: 20px; overflow: hidden; background: #fff; border: 1px solid #e5e7eb; border-radius: 14px; box-sizing: border-box; display: flex; flex-direction: column; isolation: isolate; }
.si_archive__card { flex: 0 0 65%; padding: 20px; overflow: hidden; background: #fff; border: 1px solid #e5e7eb; border-radius: 14px; box-sizing: border-box; display: flex; flex-direction: column; }
.si_archive__card-header { display: flex; align-items: center; gap: 12px; } .si_archive__card-header { display: flex; align-items: center; gap: 12px; }
.si_archive__card-img { width: 100%; aspect-ratio: 16/8; flex-shrink: 0; background: #eef2f7; border: 1px solid #e5e7eb; border-radius: 8px; overflow: hidden; } .si_archive__card-img { width: 100%; aspect-ratio: 16/8; flex-shrink: 0; background: #eef2f7; border: 1px solid #e5e7eb; border-radius: 8px; overflow: hidden; }.si_archive__card-img img { width: 100%; height: 100%; object-fit: cover; object-position: top; display: block; border-radius: 8px; }
.si_archive__card-img img { width: 100%; height: 100%; object-fit: cover; object-position: top; display: block; border-radius: 8px; }
.si_archive__card-img-placeholder { position:absolute; inset:0; background:linear-gradient(135deg,#cbd5e1 0%,#94a3b8 100%); } .si_archive__card-img-placeholder { position:absolute; inset:0; background:linear-gradient(135deg,#cbd5e1 0%,#94a3b8 100%); }
.si_archive__card-img img + .si_archive__card-img-placeholder { display:none; } .si_archive__card-img img + .si_archive__card-img-placeholder { display:none; }
.si_archive__card-body { padding-top: 16px; display: flex; flex-direction: column; gap: 12px; } .si_archive__card-body { padding-top: 16px; display: flex; flex-direction: column; gap: 12px; }
@ -947,9 +945,9 @@ body{overflow-x:hidden;}
.si_archive__tag { padding: 3px 8px; border: 1px solid #d1d5db; border-radius: 999px; font-size: 10px; color: #555; background: #fff; } .si_archive__tag { padding: 3px 8px; border: 1px solid #d1d5db; border-radius: 999px; font-size: 10px; color: #555; background: #fff; }
.si_archive__card-desc { display: grid; grid-template-columns: repeat(3, 1fr); gap: 12px; margin: 0; padding: 0; list-style: none; border-top: 1px solid #f1f1f1; padding-top: 14px; } .si_archive__card-desc { display: grid; grid-template-columns: repeat(3, 1fr); gap: 12px; margin: 0; padding: 0; list-style: none; border-top: 1px solid #f1f1f1; padding-top: 14px; }
.si_archive__card-desc li { display: flex; flex-direction: column; gap: 6px; } .si_archive__card-desc li { display: flex; flex-direction: column; gap: 6px; }
.si_archive__card-desc-icon { width: 28px; height: 28px; background: #f3f4f6; border-radius: 8px; display: flex; align-items: center; justify-content: center; font-size: 14px; } .si_archive__card-desc-icon { width: 28px; height: 28px; background: #f3f4f6; border-radius: 8px; display: flex; align-items: center; justify-content: center; font-size: 14px; color: var(--color-primary); }
.si_archive__card-desc-title { font-size: 12px; font-weight: 700; color: #111; } .si_archive__card-desc-title { font-size: 13px; font-weight: 700; color: #111; }
.si_archive__card-desc-text { font-size: 11px; line-height: 1.5; color: #888; } .si_archive__card-desc-text { font-size: 12px; line-height: 1.5; color: #888; }
.si_archive__nav { width: 100%; margin-top: 40px; display: flex; align-items: center; gap: 16px; } .si_archive__nav { width: 100%; margin-top: 40px; display: flex; align-items: center; gap: 16px; }
.si_archive__nav-btn { width: 40px; height: 40px; border-radius: 50%; border: 1.5px solid #e5e7eb; background: transparent; font-size: 16px; cursor: pointer; display: flex; align-items: center; justify-content: center; color: #111; flex-shrink: 0; transition: all .25s; } .si_archive__nav-btn { width: 40px; height: 40px; border-radius: 50%; border: 1.5px solid #e5e7eb; background: transparent; font-size: 16px; cursor: pointer; display: flex; align-items: center; justify-content: center; color: #111; flex-shrink: 0; transition: all .25s; }
@ -961,40 +959,54 @@ body{overflow-x:hidden;}
.si_archive__progress-divider { font-size: 14px; color: #ccc; } .si_archive__progress-divider { font-size: 14px; color: #ccc; }
.si_archive__progress-total { font-size: 14px; font-weight: 500; color: #bbb; min-width: 28px; } .si_archive__progress-total { font-size: 14px; font-weight: 500; color: #bbb; min-width: 28px; }
@media (max-width:1200px) {
.si_archive__main { gap:36px; } @media (max-width: 1200px) {
.si_archive__main { gap: 36px; }
.si_archive__header { flex: 0 0 260px; } .si_archive__header { flex: 0 0 260px; }
.si_archive__card { flex: 0 0 72%; } .si_archive__card { flex: 0 0 72%; }
.si_archive__nav { width:70%; }
} }
@media (max-width:1024px) { @media (max-width: 1024px) {
.si_archive { padding:72px 0 80px; } .si_archive { padding: 72px 0 80px; }
.si_archive__main { flex-direction:column; gap:36px; } .si_archive__main { flex-direction: column; gap: 36px; }
.si_archive__header { flex:none; width:100%; padding-top:0; } .si_archive__header { flex: none; width: 100%; padding-top: 0; }
.si_archive__title br, .si_archive__right { width: 100%; }
.si_archive__desc br { display:none; }
.si_archive__right { width:100%; }
.si_archive__card { flex: 0 0 80%; } .si_archive__card { flex: 0 0 80%; }
.si_archive__nav { width:100%; margin-top:30px; } .si_archive__card-desc { grid-template-columns: repeat(2, 1fr); }
.si_archive__nav { margin-top: 20px; }
} }
@media (max-width:768px) { @media (max-width: 768px) {
.si_archive { padding:56px 0 64px; } .si-archive-wrap .inner-wrap { padding: 0 20px; }
.si_archive__main { gap:28px; } .si_archive { padding: 56px 0 64px; }
.si_archive__slider { gap:14px; overflow-x:auto; padding-bottom:4px; scrollbar-width:none; } .si_archive__main { gap: 28px; }
.si_archive__slider::-webkit-scrollbar { display:none; } .si_archive__right { margin-left: -20px; margin-right: -20px; width: calc(100% + 40px); }
.si_archive__slider { overflow-x: auto; padding: 0 20px 4px; scrollbar-width: none; }
.si_archive__slider::-webkit-scrollbar { display: none; }
.si_archive__track { gap: 14px; }
.si_archive__card { flex: 0 0 82%; } .si_archive__card { flex: 0 0 82%; }
.si_archive__card-img { aspect-ratio:16/10; }
.si_archive__card-body { padding:18px 18px 20px; } .si_archive__card-img { aspect-ratio: 16/6; }
.si_archive__nav { gap:14px; margin-top:26px; } .si_archive__card-body { padding-top: 12px; gap: 10px; }
.si_archive__nav-btn { width:40px; height:40px; font-size:16px; } .si_archive__nav { gap: 14px; margin-top: 20px; }
} .si_archive__nav-btn { width: 40px; height: 40px; font-size: 16px; }
.si_archive__card-desc { grid-template-columns: repeat(1, 1fr); gap: 10px; }
.si_archive__card-desc li { flex-direction: row; align-items: flex-start; gap: 10px; align-items: center;}
.si_archive__card-desc-icon { flex-shrink: 0; }
.si_archive__card-desc-title { font-size: 12px; margin-bottom: 2px; }
.si_archive__card-desc-text { font-size: 11px; }
.si_archive__desc br { display: none; }
@media (max-width:480px) {
.si_archive__card { flex:0 0 86%; }
.si_archive__title { font-size:30px; }
.si_archive__desc { font-size:13px; }
.si_archive__progress { gap:8px; }
} }
@media (max-width: 480px) {
.si-archive-wrap .inner-wrap { padding: 0 16px; }
.si_archive__right { margin-left: -16px; margin-right: -16px; width: calc(100% + 32px); }
.si_archive__slider { padding: 0 16px 4px; }
.si_archive__card { flex: 0 0 calc(100vw - 48px); }
.si_archive__card-img { aspect-ratio: 8/6; }
.si_archive__card-desc { grid-template-columns: repeat(1, 1fr); }
.si_archive__title { font-size: 30px; }
.si_archive__desc { font-size: 13px; }
.si_archive__progress { gap: 8px; }
}

420
src/pages/business/SiPage.jsx

@ -2,7 +2,24 @@ import { useRef, useState, useEffect } from "react";
import { motion, AnimatePresence, useInView } from "framer-motion"; import { motion, AnimatePresence, useInView } from "framer-motion";
import SubHero from "../../components/SubHero"; import SubHero from "../../components/SubHero";
import useFadeIn from "../../hooks/useFadeIn"; import useFadeIn from "../../hooks/useFadeIn";
import {
Plane,
Globe,
UtensilsCrossed,
Thermometer,
MapPin,
Link,
QrCode,
Users,
Siren,
Wrench,
PlusCircle,
Settings,
ShieldCheck,
Monitor,
Building2,
ClipboardList,
} from "lucide-react";
const ease = [0.25, 0.1, 0.25, 1]; const ease = [0.25, 0.1, 0.25, 1];
const PROJECTS = [ const PROJECTS = [
@ -13,17 +30,17 @@ const PROJECTS = [
image: "/images/si_img1.png", image: "/images/si_img1.png",
desc: [ desc: [
{ {
icon: "✈", icon: <Plane size={14} />,
title: "통합 여행 포털", title: "통합 여행 포털",
text: "렌터카·숙박·항공 통합 서비스 구축", text: "렌터카·숙박·항공 통합 서비스 구축",
}, },
{ {
icon: "🌏", icon: <Globe size={14} />,
title: "해외시장 진출", title: "해외시장 진출",
text: "국제선 항공으로 해외시장 초석 마련", text: "국제선 항공으로 해외시장 초석 마련",
}, },
{ {
icon: "🍽", icon: <UtensilsCrossed size={14} />,
title: "종합 서비스", title: "종합 서비스",
text: "맛집·카페로 이어지는 제주패스 구현", text: "맛집·카페로 이어지는 제주패스 구현",
}, },
@ -36,17 +53,17 @@ const PROJECTS = [
image: "/images/si_img2.png", image: "/images/si_img2.png",
desc: [ desc: [
{ {
icon: "🌡", icon: <Thermometer size={14} />,
title: "건강 상태 관리", title: "건강 상태 관리",
text: "체류 기간 중 건강 상태 체크 및 관리", text: "체류 기간 중 건강 상태 체크 및 관리",
}, },
{ {
icon: "📍", icon: <MapPin size={14} />,
title: "동선 파악", title: "동선 파악",
text: "이동 동선 파악 및 정보 관리 시스템", text: "이동 동선 파악 및 정보 관리 시스템",
}, },
{ {
icon: "🔗", icon: <Link size={14} />,
title: "시스템 연계", title: "시스템 연계",
text: "중국전담여행사 전자관리시스템 연계", text: "중국전담여행사 전자관리시스템 연계",
}, },
@ -59,17 +76,17 @@ const PROJECTS = [
image: "/images/si_img3.png", image: "/images/si_img3.png",
desc: [ desc: [
{ {
icon: "📱", icon: <QrCode size={14} />,
title: "QR 방역 관리", title: "QR 방역 관리",
text: "QR코드 활용 방문자 방역 관리 구축", text: "QR코드 활용 방문자 방역 관리 구축",
}, },
{ {
icon: "👥", icon: <Users size={14} />,
title: "방문자 관리", title: "방문자 관리",
text: "체계적 방문자 관리 및 출입 정보 제공", text: "체계적 방문자 관리 및 출입 정보 제공",
}, },
{ {
icon: "🚨", icon: <Siren size={14} />,
title: "신속 대응", title: "신속 대응",
text: "확진자 발생 시 신속한 방역 대응 지원", text: "확진자 발생 시 신속한 방역 대응 지원",
}, },
@ -82,17 +99,17 @@ const PROJECTS = [
image: "/images/si_img4.png", image: "/images/si_img4.png",
desc: [ desc: [
{ {
icon: "🔧", icon: <Wrench size={14} />,
title: "오류 수정", title: "오류 수정",
text: "시스템 오류 수정 및 불편 요소 개선", text: "시스템 오류 수정 및 불편 요소 개선",
}, },
{ {
icon: "➕", icon: <PlusCircle size={14} />,
title: "기능 추가", title: "기능 추가",
text: "필요 기능 추가 개발 및 데이터 추출", text: "필요 기능 추가 개발 및 데이터 추출",
}, },
{ {
icon: "⚙", icon: <Settings size={14} />,
title: "운영 안정화", title: "운영 안정화",
text: "시스템 최적화를 통한 운영 안정화", text: "시스템 최적화를 통한 운영 안정화",
}, },
@ -105,17 +122,17 @@ const PROJECTS = [
image: "/images/si_img5.png", image: "/images/si_img5.png",
desc: [ desc: [
{ {
icon: "📱", icon: <QrCode size={14} />,
title: "QR 방문자 관리", title: "QR 방문자 관리",
text: "QR코드 활용 방문자 방역 관리 시스템", text: "QR코드 활용 방문자 방역 관리 시스템",
}, },
{ {
icon: "🚨", icon: <Siren size={14} />,
title: "출입 정보 제공", title: "출입 정보 제공",
text: "확진자 발생 시 정확한 출입 정보 제공", text: "확진자 발생 시 정확한 출입 정보 제공",
}, },
{ {
icon: "🖥", icon: <Monitor size={14} />,
title: "미디어 월 연동", title: "미디어 월 연동",
text: "미디어 월 연동을 통한 고객 응대", text: "미디어 월 연동을 통한 고객 응대",
}, },
@ -128,52 +145,32 @@ const PROJECTS = [
image: "/images/si_img6.png", image: "/images/si_img6.png",
desc: [ desc: [
{ {
icon: "🏗", icon: <Building2 size={14} />,
title: "인프라 구축", title: "인프라 구축",
text: "항공 운송사업자 필수 서비스 및 인프라", text: "항공 운송사업자 필수 서비스 및 인프라",
}, },
{ {
icon: "✈", icon: <Plane size={14} />,
title: "국제선 대응", title: "국제선 대응",
text: "국제선 취항 대응 및 부가서비스 매출 증대", text: "국제선 취항 대응 및 부가서비스 매출 증대",
}, },
{ {
icon: "📋", icon: <ClipboardList size={14} />,
title: "고도화 체계", title: "고도화 체계",
text: "국토부 필수 시스템 및 서비스 고도화", text: "국토부 필수 시스템 및 서비스 고도화",
}, },
], ],
}, },
{
id: "07",
title: "하이에어 항공 시스템 운영",
tags: ["항공", "운영/유지보수"],
image: "/images/si_img7.png",
desc: [
{
icon: "🔧",
title: "오류 수정",
text: "시스템 오류 수정 및 불편 요소 개선",
},
{
icon: "➕",
title: "기능 추가",
text: "필요 기능 추가 개발 및 데이터 추출",
},
{
icon: "⚙",
title: "운영 안정화",
text: "시스템 최적화를 통한 운영 안정화",
},
],
},
]; ];
const AUTO_DELAY = 4000;
const AUTO_DELAY = 3000;
function SiPage() { function SiPage() {
const basePath = import.meta.env.BASE_URL; const basePath = import.meta.env.BASE_URL;
const ref = useFadeIn(); const ref = useFadeIn();
const sectionRef = useRef(null); const sectionRef = useRef(null);
const sliderRef = useRef(null);
const cardRef = useRef(null);
const dragStartX = useRef(null); const dragStartX = useRef(null);
const dragStartCurrent = useRef(null); const dragStartCurrent = useRef(null);
const inView = useInView(sectionRef, { once: true, margin: "-100px" }); const inView = useInView(sectionRef, { once: true, margin: "-100px" });
@ -181,25 +178,55 @@ function SiPage() {
const [paused, setPaused] = useState(false); const [paused, setPaused] = useState(false);
const total = PROJECTS.length; const total = PROJECTS.length;
const canPrev = current > 0; const [cardWidth, setCardWidth] = useState(0);
const canNext = current < total - 1;
useEffect(() => {
const update = () => {
if (cardRef.current) {
setCardWidth(cardRef.current.offsetWidth);
}
};
update();
window.addEventListener("resize", update);
return () => window.removeEventListener("resize", update);
}, []);
const scrollToCard = (index) => {
if (window.innerWidth <= 768 && sliderRef.current && cardRef.current) {
const cardW = cardRef.current.offsetWidth;
const gap = window.innerWidth <= 480 ? 14 : 14;
sliderRef.current.scrollTo({
left: index * (cardW + gap),
behavior: "smooth",
});
}
};
const prev = () => { const prev = () => {
if (!canPrev) return; setCurrent((c) => {
setCurrent((c) => c - 1); const nextIdx = c <= 0 ? total - 1 : c - 1;
scrollToCard(nextIdx);
return nextIdx;
});
}; };
const next = () => { const next = () => {
if (!canNext) return; setCurrent((c) => {
setCurrent((c) => c + 1); const nextIdx = c >= total - 1 ? 0 : c + 1;
scrollToCard(nextIdx);
return nextIdx;
});
}; };
useEffect(() => { useEffect(() => {
if (paused) return; if (paused) return;
const timer = setInterval(() => { const timer = setInterval(() => {
setCurrent((c) => (c + 1) % total); setCurrent((c) => {
const nextIdx = (c + 1) % total;
scrollToCard(nextIdx);
return nextIdx;
});
}, AUTO_DELAY); }, AUTO_DELAY);
return () => clearInterval(timer); return () => clearInterval(timer);
}, [paused, total]); }, [paused, total]);
const handleDragStart = (e) => { const handleDragStart = (e) => {
dragStartX.current = dragStartX.current =
e.type === "touchstart" ? e.touches[0].clientX : e.clientX; e.type === "touchstart" ? e.touches[0].clientX : e.clientX;
@ -233,144 +260,185 @@ function SiPage() {
navItems={BUSINESS_NAV} navItems={BUSINESS_NAV}
/> />
<div className="sub-content"> <div className="sub-content si-archive-wrap">
<section <div className="inner-wrap">
className="si_archive" <section
ref={sectionRef} className="si_archive"
onMouseEnter={() => setPaused(true)} ref={sectionRef}
onMouseLeave={() => setPaused(false)} onMouseEnter={() => setPaused(true)}
> onMouseLeave={() => setPaused(false)}
<div className="si_archive__main"> >
{/* 헤더 */} <div className="si_archive__main">
<div className="si_archive__header"> {/* 헤더 */}
<motion.span <div className="si_archive__header">
className="fc-eyebrow" <motion.span
initial={{ opacity: 0, y: 16 }} className="fc-eyebrow"
animate={inView ? { opacity: 1, y: 0 } : {}} initial={{ opacity: 0, y: 16 }}
transition={{ duration: 0.6, ease }} animate={inView ? { opacity: 1, y: 0 } : {}}
> transition={{ duration: 0.6, ease }}
PROJECT ARCHIVE >
</motion.span> PROJECT ARCHIVE
<motion.h2 </motion.span>
className="si_archive__title" <motion.h2
initial={{ opacity: 0, y: 20 }} className="si_archive__title"
animate={inView ? { opacity: 1, y: 0 } : {}} initial={{ opacity: 0, y: 20 }}
transition={{ duration: 0.6, delay: 0.1, ease }} animate={inView ? { opacity: 1, y: 0 } : {}}
> transition={{ duration: 0.6, delay: 0.1, ease }}
수행사업 >
<br /> {window.innerWidth <= 768 ? (
아카이브 "수행사업 아카이브"
</motion.h2> ) : (
<motion.p <>
className="si_archive__desc" 수행사업
initial={{ opacity: 0, y: 16 }} <br />
animate={inView ? { opacity: 1, y: 0 } : {}} 아카이브
transition={{ duration: 0.6, delay: 0.2, ease }} </>
> )}
PAL Networks가 구축한 </motion.h2>
<br /> <motion.p
주요 프로젝트를 소개합니다. className="si_archive__desc"
</motion.p> initial={{ opacity: 0, y: 16 }}
animate={inView ? { opacity: 1, y: 0 } : {}}
{/* 네비게이션 */} transition={{ duration: 0.6, delay: 0.2, ease }}
<div className="si_archive__nav">
<button
className="si_archive__nav-btn"
onClick={prev}
disabled={!canPrev}
aria-label="이전"
> >
{window.innerWidth <= 768 ? (
</button> "PAL Networks가 구축한 주요 프로젝트를 소개합니다."
) : (
<>
PAL Networks가 구축한
<br />
주요 프로젝트를 소개합니다.
</>
)}
</motion.p>
<div className="si_archive__progress"> {/* 네비게이션 */}
<span className="si_archive__progress-cur"> <div className="si_archive__nav">
{String(current + 1).padStart(2, "0")} <motion.button
</span> className="si_archive__nav-btn"
<span className="si_archive__progress-divider">/</span> onClick={prev}
<span className="si_archive__progress-total"> aria-label="이전"
{String(total).padStart(2, "0")} initial={{ opacity: 0, y: 16 }}
</span> animate={inView ? { opacity: 1, y: 0 } : {}}
</div> transition={{ duration: 0.6, delay: 0.4, ease }}
>
</motion.button>
<button <motion.div
className="si_archive__nav-btn" className="si_archive__progress"
onClick={next} initial={{ opacity: 0, y: 16 }}
disabled={!canNext} animate={inView ? { opacity: 1, y: 0 } : {}}
aria-label="다음" transition={{ duration: 0.6, delay: 0.4, ease }}
> >
<span className="si_archive__progress-cur">
</button> {String(current + 1).padStart(2, "0")}
</span>
<span className="si_archive__progress-divider">/</span>
<span className="si_archive__progress-total">
{String(total).padStart(2, "0")}
</span>
</motion.div>
<motion.button
className="si_archive__nav-btn"
onClick={next}
aria-label="다음"
initial={{ opacity: 0, y: 16 }}
animate={inView ? { opacity: 1, y: 0 } : {}}
transition={{ duration: 0.6, delay: 0.4, ease }}
>
</motion.button>
</div>
</div> </div>
</div>
{/* 슬라이더 */} {/* 슬라이더 */}
<div className="si_archive__right"> <div className="si_archive__right">
<div
className="si_archive__slider"
style={{ display: "flex" }}
onMouseDown={handleDragStart}
onMouseUp={handleDragEnd}
onTouchStart={handleDragStart}
onTouchEnd={handleDragEnd}
>
<motion.div <motion.div
className="si_archive__track" initial={{ opacity: 0, y: 30 }}
animate={{ x: `calc(-${current} * (65% + 18px))` }} animate={inView ? { opacity: 1, y: 0 } : {}}
transition={{ duration: 0.55, ease }} transition={{ duration: 0.6, delay: 0.3, ease }}
style={{ alignItems: "stretch" }}
> >
{PROJECTS.map((project) => ( <div
<div key={project.id} className="si_archive__card"> className="si_archive__slider"
<div className="si_archive__card-img"> style={{ display: "flex" }}
<img onMouseDown={handleDragStart}
src={`${basePath}images/si_img${parseInt(project.id)}.png`} onMouseUp={handleDragEnd}
alt={project.title} onTouchStart={handleDragStart}
/> onTouchEnd={handleDragEnd}
<div className="si_archive__card-img-placeholder" /> ref={sliderRef}
</div> >
<motion.div
<div className="si_archive__card-body"> className="si_archive__track"
<div className="si_archive__card-header"> animate={{
<div className="si_archive__card-num"> x:
{project.id} window.innerWidth <= 768
? 0
: cardWidth
? -(current * (cardWidth + 18))
: 0,
}}
transition={{ duration: 0.55, ease }}
style={{ alignItems: "stretch" }}
>
{PROJECTS.map((project, idx) => (
<div
key={project.id}
className="si_archive__card"
ref={idx === 0 ? cardRef : null}
>
<div className="si_archive__card-img">
<img
src={`${basePath}images/si_img${parseInt(project.id)}.png`}
alt={project.title}
/>
<div className="si_archive__card-img-placeholder" />
</div> </div>
<h3 className="si_archive__card-title">
{project.title}
</h3>
</div>
<div className="si_archive__card-tags"> <div className="si_archive__card-body">
{project.tags.map((tag) => ( <div className="si_archive__card-header">
<span key={tag} className="si_archive__tag"> <div className="si_archive__card-num">
{tag} {project.id}
</span>
))}
</div>
<ul className="si_archive__card-desc">
{project.desc.map((item, i) => (
<li key={i}>
<div className="si_archive__card-desc-icon">
{item.icon}
</div>
<div className="si_archive__card-desc-title">
{item.title}
</div> </div>
<div className="si_archive__card-desc-text"> <h3 className="si_archive__card-title">
{item.text} {project.title}
</div> </h3>
</li> </div>
))}
</ul> <div className="si_archive__card-tags">
</div> {project.tags.map((tag) => (
</div> <span key={tag} className="si_archive__tag">
))} {tag}
</span>
))}
</div>
<ul className="si_archive__card-desc">
{project.desc.map((item, i) => (
<li key={i}>
<div className="si_archive__card-desc-icon">
{item.icon}
</div>
<div className="si_archive__card-desc-title">
{item.title}
</div>
<div className="si_archive__card-desc-text">
{item.text}
</div>
</li>
))}
</ul>
</div>
</div>
))}
</motion.div>
</div>
</motion.div> </motion.div>
</div> </div>
</div> </div>
</div> </section>
</section> </div>
</div> </div>
</article> </article>
); );

Loading…
Cancel
Save