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
Binary file added src/assets/img/gallery/banner_gallery.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
5 changes: 5 additions & 0 deletions src/components/Header/Header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,11 @@ const menuItems = [
hasDropdown: false,
path: "/coc",
},
{
label: "GALLERY",
hasDropdown: false,
path: "/gallery",
}
/* { label: "NEWS", hasDropdown: false },
{ label: "SUPPORT", hasDropdown: false },
{ label: "COC", hasDropdown: false },*/
Expand Down
7 changes: 6 additions & 1 deletion src/components/Layout/Layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,12 @@ import Footer from "@/components/Footer/Footer.tsx";
const Layout = () => {
const location = useLocation();
const isYellow = (): boolean => {
return location.pathname === "/about" || location.pathname === "/about/md";
return (
location.pathname === "/about" ||
location.pathname === "/about/md" ||
location.pathname === "/coc" ||
location.pathname === "/gallery"
);
};
return (
<div>
Expand Down
51 changes: 51 additions & 0 deletions src/pages/gallery/$id.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import * as React from "react";
import { Container } from "@/components/Container";
import { useGetNotice } from "@/quries/useGetNotice.ts";
import { useNavigate, useParams } from "react-router-dom";

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

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

const notice = data?.data ?? undefined;

return (
notice && (
<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}
</h1>
<p className="py-4 text-base font-light text-[#2d003d]">
{new Date(notice.created_at).toLocaleDateString()}
</p>
{/* REVIEW: 해시태그 컴포넌트는 없나? todo: hashtag*/}
{/*<div>#컨퍼런스</div>*/}
</header>
<section>
<p dangerouslySetInnerHTML={{ __html: notice.content }} />
</section>
</article>
</section>
<div className="flex justify-end">
<button
className="ml-auto inline-flex rounded-xl bg-[#302633] px-8 py-3 text-white"
onClick={goToList}
>
목록
</button>
</div>
</Container>
)
);
};

export default NoticeDetail;
136 changes: 136 additions & 0 deletions src/pages/gallery/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@

import BgImg from "@/assets/img/gallery/banner_gallery.png";

import { HeaderBanner } from "@/components/HeaderBanner";
import { Breadcrumb } from "@/components/Breadcrumb";
import { AboutSection, AboutSectionTitle } from "@/components/AboutSection";

import { SelectBox } from "@/components/SelectBox";
import { useEffect, useState } from "react";
import { Gallery, SelectValue } from "@/types/common.ts";
import { useGetGallery } from "@/quries/useGetGallery";
import { Pagination } from "@/components/Pagination";

const selectedOptions = [
{ label: "2024년", value: "2024" },
{ label: "2025년", value: "2025" },
];


const ActivityGallery = () => {
const [yearList, setYearList] = useState<SelectValue[]>([]);
const [selectedYear, setSelectedYear] = useState<number>(2025);
const [page, setPage] = useState<number>(1);

const { data } = useGetGallery(page);

const galleryData: Gallery[] = data?.data ?? [];
const pagination = data?.pagination;

useEffect(() => {
setYearList(
selectedOptions.map(
(option) =>
({
...option,
checked: option.value === String(selectedYear),
}) as SelectValue,
),
);
}, []);

const onPageChange = (val: number) => {
setPage(val);
};

const onSelectYear = (value: string) => {
setSelectedYear(Number(value));
setYearList(
selectedOptions.map(
(option) =>
({ ...option, checked: option.value === value }) as SelectValue,
),
);
};

return (
<div className="align-center flex flex-col">
<HeaderBanner
backgroundImage={BgImg}
title={"Community Log"}
description={`HelloPY는 주니어 개발자들의 성장을 돕고 파이썬 교육 확산을 위한 커뮤니티입니다. <br/>온오프라인에서 학습하고 파이썬 기술과 트렌드를 공유하며, 다양한 외부 협업도 진행합니다. 헬로파이의 다양한 활동을 확인해보세요!`}
>
<Breadcrumb
children={[
<a href="/">Home</a>,
<a href="/gallery">GALLERY</a>
]}
/>
</HeaderBanner>

<AboutSection>
<div className="mb-[106px] mt-[180px] flex flex-col items-center justify-start gap-2">
<div className="self-stretch text-center text-[20px] font-bold text-hellopy-purple-200">
HelloPY COC(Code of Conduct)
</div>
<div className="self-stretch text-center text-[28px] font-bold text-black">
HelloPY 활동 가이드
</div>
<div className="self-stretch text-center text-[15px] text-black">
신규 멤버는 자기소개, 기사 공유, 모각작 참여 등 기본 활동을 수행해야 합니다. <br/>각 게시판에 정보를 공유하고 질문하거나 성과를 기록할 수 있으며, 활동량에 따라 등급이 상승합니다. <br/>등급은 레몬파이부터 블루베리파이까지 나뉘며 오프라인 모임 또는 컨퍼런스 발표를 통해 추가 승급이 가능합니다.
</div>
</div>
</AboutSection>

<div className={"bg-[#FCF7FF]"}>
<AboutSection>

</AboutSection>
</div>


<AboutSection>
<AboutSectionTitle
title={"HelloPY Gallery"}
subtitle={"HelloPY 활동 갤러리"}
description={[]}
/>
<SelectBox options={yearList} onSelect={onSelectYear} />
<div className="bg-purple-7 relative flex w-full flex-col items-start justify-start gap-[50px]">
<div className="relative flex w-full flex-wrap items-start justify-start gap-[30px]">
{galleryData
.filter((item) => item.title?.includes(String(selectedYear)))
.map((item, index) => (
<div key={index} className="relative flex flex-col gap-5">
<img
className="w-52 object-cover"
src={item.thumbnail}
alt={`gallery-${item.id}`}
/>
<div className="flex w-full flex-col items-start justify-start gap-0">
<div className="text-black-1 w-full text-left text-xl font-semibold leading-normal">
{item.title}
</div>
<div
className="text-black-1 w-full text-left text-base font-light leading-normal line-clamp-2 overflow-hidden text-ellipsis"
dangerouslySetInnerHTML={{ __html: item.content }}
/>
</div>
</div>
))}

{galleryData && galleryData.length > 0 && pagination !== null && (
<Pagination
totalCount={pagination?.count ?? 0}
currentPage={page}
onPageChange={onPageChange}
/>
)}
</div>
</div>
</AboutSection>
</div>
);
};

export default ActivityGallery;
2 changes: 1 addition & 1 deletion src/pages/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ export const Home = () => {
`}
buttonText="전체 활동 보기 →"
textPosition="right"
buttonUrl="none"
buttonUrl="/gallery"
/>

<HomeCard
Expand Down
9 changes: 9 additions & 0 deletions src/quries/useGetGallery.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { useQuery } from "react-query";
import { GalleryService } from "@/service/galleryService";

export const useGetGallery = (page: number) => {
return useQuery({
queryKey: [GalleryService.QueryKey.getGallery, page],
queryFn: () => GalleryService.getGallery(page),
});
};
2 changes: 2 additions & 0 deletions src/quries/useGetNotice.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,5 @@ export const useGetNotice = (id?: string) => {
enabled: !!id,
});
};


14 changes: 14 additions & 0 deletions src/service/galleryService.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import instance from "@/hooks/useAxios.ts";

export const GalleryService = {
QueryKey: {
getGallery: "getGallery",
},


getGallery: async (page: number) => {
const { data } = await instance.get(`/activity-gallery/?page_size=10&page=${page}`);

return data;
},
};
9 changes: 9 additions & 0 deletions src/types/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,3 +27,12 @@ export type MD = {
image: string;
name: string;
};

export type Gallery = {
id: number,
title: string,
content: string,
thumbnail: string,
tags: {id: number, name: string}[],
photos: string[]
}