Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
"lucide-react": "^0.344.0",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-icons": "^5.4.0",
"react-icons": "^5.5.0",
"react-query": "^3.39.3",
"react-quill": "^2.0.0",
"react-router-dom": "^6.22.1"
Expand Down
Binary file added src/assets/img/support/support_banner.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
10 changes: 10 additions & 0 deletions src/assets/img/support/support_process_group1.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
6 changes: 6 additions & 0 deletions src/assets/img/support/support_process_group2.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 2 additions & 1 deletion src/components/Header/Header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,8 @@ const menuItems = [
label: "GALLERY",
hasDropdown: false,
path: "/gallery",
}
},
{ label: "SUPPORT", path: "/support", hasDropdown: false },
/* { label: "NEWS", hasDropdown: false },
{ label: "SUPPORT", hasDropdown: false },
{ label: "COC", hasDropdown: false },*/
Expand Down
111 changes: 111 additions & 0 deletions src/components/SupportCards/SupportCards.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
import React from 'react';
import { IoIosArrowForward } from 'react-icons/io';
import financialIcon from '@/assets/img/support/support_process_group1.svg';
import materialIcon from '@/assets/img/support/support_process_group2.svg';

interface SupportCardProps {
subtitle: string;
title: string;
description: string[];
icon: string;
}

const SupportCard: React.FC<SupportCardProps> = ({ subtitle, title, description, icon }) => (
<div className="w-full lg:w-[617px] h-auto lg:h-[304px] relative">
<div className="bg-white-1 rounded-3xl border-solid border-purple-5 border w-full h-full absolute left-0 top-0" />
<div className="flex flex-col lg:flex-row items-start justify-between w-full h-full relative p-6 lg:p-0">
<div className="flex flex-col gap-6 lg:gap-[60px] items-start justify-start w-full lg:w-[388px] lg:absolute lg:left-[70px] lg:top-[52px]">
<div className="flex flex-col gap-0.5 items-start justify-start self-stretch shrink-0 relative">
<div className="text-purple-2 text-left font-['Pretendard-SemiBold',_sans-serif] text-base leading-normal font-semibold relative self-stretch">
{subtitle}
</div>
<div className="text-black-1 text-left font-['Pretendard-SemiBold',_sans-serif] text-2xl lg:text-[28px] leading-[130%] font-semibold relative self-stretch">
{title}
</div>
</div>
<div className="text-gray-3 text-left font-['Pretendard-Light',_sans-serif] text-base lg:text-lg leading-normal font-light relative self-stretch">
{description.map((line, index) => (
<React.Fragment key={index}>
{line}
{index < description.length - 1 && <br />}
</React.Fragment>
))}
</div>
</div>
<div className="w-[100px] h-[100px] lg:w-[150px] lg:h-[115px] relative lg:absolute lg:right-[70px] lg:top-[19px] overflow-hidden mt-4 lg:mt-0">
<img
className="w-full h-full object-contain"
src={icon}
alt={`${title} icon`}
/>
</div>
</div>
</div>
);

const SupportCards = () => {
const supportCards = [
{
subtitle: "작은 나눔 큰 변화",
title: "금전적 후원",
description: [
"계좌이체를 통해 후원금을 입금하실 수 있습니다.",
"여러분의 소중한 후원은 큰 힘이 됩니다."
],
icon: financialIcon
},
{
subtitle: "나누는 기쁨",
title: "물품 기부",
description: [
"도서 및 이벤트 상품 등 다양한 물품 기부를 받습니다.",
"기부 물품을 구체적으로 작성해주시면,",
"이메일로 절차를 안내해 드리겠습니다."
],
icon: materialIcon
}
];

const handleApplicationClick = () => {
window.open('https://forms.gle/your-google-form-id', '_blank');
};

return (
<div className="flex flex-col gap-6 lg:gap-10 items-start justify-start relative w-full">
{/* Cards Container */}
<div className="flex flex-col lg:flex-row gap-6 lg:gap-[43px] items-start justify-start w-full">
{supportCards.map((card, index) => (
<SupportCard key={index} {...card} />
))}
</div>

{/* Application Card */}
<div
className="w-full h-auto lg:h-[200px] relative cursor-pointer transition-transform hover:scale-[1.02]"
onClick={handleApplicationClick}
>
<div
className="rounded-3xl border-solid border-purple-5 border w-full h-full absolute left-0 top-0"
style={{
background: 'linear-gradient(92.54deg, rgba(209, 97, 246, 1) 0%, rgba(137, 31, 189, 1) 100%)'
}}
/>
<div className="flex flex-col gap-4 lg:gap-[15px] items-center justify-center w-full lg:w-[500px] relative lg:absolute lg:left-1/2 lg:top-1/2 lg:-translate-x-1/2 lg:-translate-y-1/2 p-6 lg:p-0">
<div className="text-purple-8 text-center font-['Pretendard-SemiBold',_sans-serif] text-2xl lg:text-[28px] leading-[130%] font-semibold relative self-stretch">
후원 신청하기
</div>
<div className="text-gray-5 text-center font-['Pretendard-Light',_sans-serif] text-base lg:text-lg leading-normal font-light relative self-stretch">
아래 구글폼을 통해 후원에 필요한 정보를 입력해 주세요.
<br />
제출하신 정보는 내부 검토 후, 후원 방법에 대해 안내드리겠습니다.
</div>
</div>
<div className="hidden lg:block absolute right-[70px] top-1/2 -translate-y-1/2">
<IoIosArrowForward className="w-[60px] h-[60px] text-white" />
</div>
</div>
</div>
);
};

export default SupportCards;
155 changes: 155 additions & 0 deletions src/components/Timeline/Timeline.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
import React, { useState, useEffect } from 'react';
import { IoIosArrowBack, IoIosArrowForward } from 'react-icons/io';
import { AboutSectionTitle } from '../AboutSection';

const Timeline = () => {
const [currentSlide, setCurrentSlide] = useState(0);
const [slidesToShow, setSlidesToShow] = useState(1);

const events = [
{
year: 24,
month: 'SEP',
title: 'HelloPY 탄생',
description: '파이몬 생일\nDiscord, Instagram, Youtube 개설',
position: 'right'
},

{
year: 24,
month: 'OCT',
title: '컨퍼런스 & 파이콘',
description: 'HelloPY 컨퍼런스 VOL.1\n파이콘 한국 2024 부스 운영\nDiscord User 100명 달성',
position: 'left'
},
{
year: 24,
month: 'NOV',
title: '제1회 OnOFF 모각클',
description: "'모여서 각자 작업하는 모임'\n매주 2회 대면/비대면 활동 개최",
position: 'right'
},
{
year: 24,
month: 'DEC',
title: '파이콘 공유회',
description: '월드와이드 파이콘 공유회\nLinkedIn 개설',
position: 'left'
},
{
year: 25,
month: 'MAR',
title: '홈페이지 리뉴얼',
description: 'HelloPY 공식 홈페이지 제작',
position: 'right'
},
];

useEffect(() => {
const handleResize = () => {
if (window.innerWidth >= 1024) { // lg breakpoint
setSlidesToShow(3);
} else if (window.innerWidth >= 768) { // md breakpoint
setSlidesToShow(2);
} else {
setSlidesToShow(1);
}
};

handleResize(); // 초기 설정
window.addEventListener('resize', handleResize);
return () => window.removeEventListener('resize', handleResize);
}, []);

const handlePrevSlide = () => {
setCurrentSlide((prev) => (prev > 0 ? prev - 1 : events.length - slidesToShow));
};

const handleNextSlide = () => {
setCurrentSlide((prev) => (prev < events.length - slidesToShow ? prev + 1 : 0));
};

const isFirstSlide = currentSlide === 0;
const isLastSlide = currentSlide >= events.length - slidesToShow;

return (
<div className="relative w-full overflow-hidden">
<div className="bg-purple-7 w-full h-[900px] absolute left-0 top-0"></div>
<div className="container mx-auto relative px-4 py-8">
<AboutSectionTitle
subtitle={"HelloPY History"}
title={" Our Journey"}
description={[]}
/>

{/* Timeline Events Container */}
<div className="relative w-full mt-32">
<div className="relative overflow-hidden">
<div
className="flex transition-transform duration-500 ease-in-out"
style={{ transform: `translateX(-${currentSlide * (100 / slidesToShow)}%)` }}
>
{events.map((event, index) => (
<div
key={index}
className="flex-shrink-0 w-full md:w-1/2 lg:w-1/3 px-4"
style={{
marginLeft: event.position === 'right' ? 'auto' : '0',
marginRight: event.position === 'left' ? 'auto' : '0'
}}
>
<div className="flex flex-row gap-3.5 items-start justify-start w-full">
<div className="bg-purple-4 shrink-0 w-2 h-[98px] relative"></div>
<div className="flex flex-col gap-[30px] items-start justify-start shrink-0 w-full relative">
<div className="flex flex-col gap-1 items-start justify-start self-stretch shrink-0 relative">
<div className="text-purple-2 text-left font-['Pretendard-Bold',_sans-serif] text-2xl md:text-3xl font-bold relative self-stretch" style={{ letterSpacing: '-0.02em' }}>
{event.year}.{event.month}
</div>
<div className="text-black-1 text-left font-['Pretendard-Medium',_sans-serif] text-xl md:text-2xl leading-tight font-medium relative w-full" style={{ letterSpacing: '-0.02em' }}>
{event.title}
</div>
</div>
<div className="text-black text-left text-base leading-[130%] font-light relative self-stretch whitespace-pre-line">
{event.description}
</div>
</div>
</div>
</div>
))}
</div>
</div>

{/* Navigation Buttons */}
<div className="flex justify-between mt-8">
<button
onClick={handlePrevSlide}
disabled={isFirstSlide}
className={`w-12 h-12 md:w-[66px] md:h-[66px] flex items-center justify-center rounded-full transition-colors ${
isFirstSlide
? 'invisible'
: 'bg-white/10 hover:bg-white/20 cursor-pointer'
}`}
aria-label="Previous"
>
<IoIosArrowBack className="w-6 h-6 md:w-8 md:h-8 text-purple-2" />
</button>
<button
onClick={handleNextSlide}
disabled={isLastSlide}
className={`w-12 h-12 md:w-[66px] md:h-[66px] flex items-center justify-center rounded-full transition-colors ${
isLastSlide
? 'invisible'
: 'bg-white/10 hover:bg-white/20 cursor-pointer'
}`}
aria-label="Next"
>
<IoIosArrowForward className="w-6 h-6 md:w-8 md:h-8 text-purple-2" />
</button>
</div>
</div>
</div>
</div>
);
};

export default Timeline;
19 changes: 8 additions & 11 deletions src/pages/gallery/$id.tsx
Original file line number Diff line number Diff line change
@@ -1,37 +1,34 @@
import * as React from "react";
import { Container } from "@/components/Container";
import { useGetNotice } from "@/quries/useGetNotice.ts";
import { useNavigate, useParams } from "react-router-dom";
import { useGetGalleryItem } from "@/quries/useGetGalleryItem";

export const NoticeDetail: React.FC = () => {
const { id } = useParams();
const nav = useNavigate();
const { data } = useGetNotice(id);
const { data } = useGetGalleryItem(id ? Number(id) : undefined);

const goToList = () => {
nav("/board/notice");
nav("/gallery");
};

const notice = data?.data ?? undefined;
const galleryItem = data?.data ?? undefined;

return (
notice && (
galleryItem && (
<Container className={"px-5 py-10 md:px-40"}>
<p className="px-4 py-2 text-lg font-medium text-[#2d003d]">공지사항</p>
<section className="mb-8 border-y border-black px-4 py-8">
<article>
<header className="pb-12">
<h1 className="text-4xl font-semibold text-[#2d003d]">
{notice.title}
{galleryItem.title}
</h1>
<p className="py-4 text-base font-light text-[#2d003d]">
{new Date(notice.created_at).toLocaleDateString()}
</p>
{/* REVIEW: 해시태그 컴포넌트는 없나? todo: hashtag*/}
{/*<div>#컨퍼런스</div>*/}
{galleryItem?.tags?.map((tag:{id: number, name: string}) => <div>{tag.name}</div>)}
</header>
<section>
<p dangerouslySetInnerHTML={{ __html: notice.content }} />
<p dangerouslySetInnerHTML={{ __html: galleryItem.content }} />
</section>
</article>
</section>
Expand Down
Loading