Skip to content

Commit b98a0aa

Browse files
authored
Merge pull request #313 from DguFarmSystem/fix/#309
[Fix] 블로그/프로젝트 태그 추출 방법 및 여러 오류 수정, 소식+블로그/프로젝트 에러 및 로딩 시 스켈레톤 추가
2 parents 7ead4f6 + d2723b7 commit b98a0aa

20 files changed

Lines changed: 362 additions & 158 deletions

apps/website/api/og.js

Lines changed: 0 additions & 91 deletions
This file was deleted.
8.81 KB
Loading

apps/website/src/layouts/DetailLayout/ProjectDetailLayout.styled.ts

Lines changed: 61 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -163,16 +163,73 @@ export const ImageContainer = styled.div<LayoutProps>`
163163
`;
164164

165165
export const Thumbnail = styled.img<LayoutProps>`
166-
width: 827.92px;
167-
// height: 533px;
166+
width: 100%;
167+
max-width: 827.92px;
168168
flex-shrink: 0;
169169
aspect-ratio: 827.92/533.00;
170170
171-
border-top: 3px solid var(--FarmSystem_DarkGrey, #999);
171+
border-top: 1px solid var(--FarmSystem_DarkGrey, #999);
172172
border-bottom: 1px solid var(--FarmSystem_DarkGrey, #999);
173173
background: url(<path-to-image>) lightgray 50% / cover no-repeat;
174174
`;
175175

176+
//프로젝트 디테일 시 이미지 없어서 그냥 맞추어서 작업
177+
export const PlaceholderImage = styled.div<LayoutProps>`
178+
width: 100%;
179+
max-width: 827.92px;
180+
flex-shrink: 0;
181+
aspect-ratio: 827.92/533.00;
182+
183+
display: flex;
184+
align-items: center;
185+
justify-content: center;
186+
187+
background-color: var(--FarmSystem_LightGrey, #E5E5E5);
188+
border-top: 3px solid var(--FarmSystem_DarkGrey, #999);
189+
border-bottom: 1px solid var(--FarmSystem_DarkGrey, #999);
190+
191+
color: var(--FarmSystem_DarkGrey, #999);
192+
font-size: ${({ $isMobile }) => ($isMobile ? "16px": "20px")};
193+
font-weight: 500;
194+
`;
195+
196+
// 예쁜 기본 썸네일
197+
export const DefaultThumbnail = styled.div<LayoutProps>`
198+
width: 100%;
199+
max-width: 827.92px;
200+
flex-shrink: 0;
201+
aspect-ratio: 827.92/533.00;
202+
203+
display: flex;
204+
flex-direction: column;
205+
align-items: center;
206+
justify-content: center;
207+
gap: 16px;
208+
209+
background: linear-gradient(135deg, #f8f9fa 0%, #e9ecef 100%);
210+
border-top: 3px solid var(--FarmSystem_DarkGrey, #999);
211+
border-bottom: 1px solid var(--FarmSystem_DarkGrey, #999);
212+
213+
transition: all 0.3s ease;
214+
215+
&:hover {
216+
background: linear-gradient(135deg, #e9ecef 0%, #dee2e6 100%);
217+
transform: translateY(-2px);
218+
}
219+
`;
220+
221+
export const DefaultThumbnailIcon = styled.div`
222+
font-size: 48px;
223+
opacity: 0.7;
224+
`;
225+
226+
export const DefaultThumbnailText = styled.div<LayoutProps>`
227+
font-size: ${({ $isMobile }) => ($isMobile ? "16px": "20px")};
228+
font-weight: 500;
229+
color: var(--FarmSystem_DarkGrey, #6c757d);
230+
text-align: center;
231+
`;
232+
176233
export const ContentBox = styled.p<LayoutProps>`
177234
width: 100%;
178235
max-width: 800px;
@@ -236,4 +293,4 @@ export const ParticipantContainer = styled.div<LayoutProps>`
236293
justify-content: flex-end;
237294
width: 100%;
238295
min-width: 70%;
239-
`;
296+
`;

apps/website/src/layouts/DetailLayout/ProjectDetailLayout.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import useMediaQueries from "@/hooks/useMediaQueries";
44
import GithubIcon from "@/assets/githubLogo.png";
55
import DeploymentIcon from "@/assets/Icons/deploy_Icon.png";
66
import ResourceIcon from "@/assets/pink_link.png";
7+
import BlankThumbnailImg from "@/assets/Images/Blog_Project/blank_img_project.png";
78

89
interface ProjectDetailLayoutProps {
910
title?: string;
@@ -23,7 +24,7 @@ export default function ProjectDetailLayout({
2324
content = "(임시) 내용",
2425
introduction = "(임시) 소개",
2526
tag = "(임시) 태그",
26-
thumbnailUrl = "",
27+
thumbnailUrl = BlankThumbnailImg,
2728
githubLink = "(임시) 링크",
2829
deploymentLink = "(임시) 링크",
2930
resourceLink = "(임시) 링크",
@@ -92,7 +93,7 @@ export default function ProjectDetailLayout({
9293
<S.ImageContainer $isMobile={isMobile} $isTablet={isTablet} $isDesktop={isDesktop}>
9394
<S.Thumbnail
9495
$isMobile={isMobile} $isTablet={isTablet} $isDesktop={isDesktop}
95-
src={thumbnailUrl}
96+
src={thumbnailUrl || BlankThumbnailImg}
9697
alt={title}
9798
/>
9899
</S.ImageContainer>

apps/website/src/models/blog.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ enum ApiErrorMessages {
4848
export interface BlogItem {
4949
blogId: number;
5050
link: string;
51-
category: string[];
51+
categories: string[];
5252
approvalStatus: string;
5353
}
5454

apps/website/src/pages/Blog/Blog/BlogItem.styles.tsx

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,16 @@ export const Image = styled.div<{$isMobile: boolean; $isTablet: boolean;}>`
2525
height: ${(props) => (props.$isMobile ? '87px' : props.$isTablet ? '150px' : '200px')};
2626
background-color: var(--FarmSystem_LightGrey);
2727
28+
display: flex;
29+
align-items: center;
30+
justify-content: center;
31+
2832
img{
29-
height: ${(props) => (props.$isMobile ? '87px' : props.$isTablet ? '150px' : '200px')};
33+
/* height: ${(props) => (props.$isMobile ? '87px' : props.$isTablet ? '150px' : '200px')}; */
34+
width: 100%;
35+
height: 100%;
3036
object-fit: cover;
37+
object-position: center;
3138
}
3239
`;
3340

apps/website/src/pages/Blog/Blog/BlogItem.tsx

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,13 @@ import BlankImg from '../../../assets/Images/Blog_Project/blank_img.svg';
55
import { APIResponse } from '@/hooks/useLinkPreview';
66

77
export enum BlogCategory {
8-
SEMINAR,
9-
PROJECT,
10-
STUDY,
11-
HACKATHON,
12-
REVIEW,
13-
LECTURE,
14-
ETC,
8+
SEMINAR = "SEMINAR",
9+
PROJECT = "PROJECT",
10+
STUDY = "STUDY",
11+
HACKATHON = "HACKATHON",
12+
REVIEW = "REVIEW",
13+
LECTURE = "LECTURE",
14+
ETC = "ETC",
1515
}
1616

1717
export interface BlogTag {

apps/website/src/pages/Blog/Blog/BlogList.styles.tsx

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,23 @@ export const ListContainer = styled.div<{$isTablet: boolean; $isBig: boolean; $i
139139
140140
`;
141141

142+
143+
export const SkeletonListContainer = styled(ListContainer)``;
144+
145+
export const SkeletonCard = styled.div<{$isMobile: boolean;}>`
146+
width: 300px;
147+
height: ${(props) => (props.$isMobile ? '170px' : '200px')};
148+
border-radius: 16px;
149+
background: linear-gradient(90deg, #f2f2f2 25%, #e6e6e6 37%, #f2f2f2 63%);
150+
background-size: 400% 100%;
151+
animation: skeleton-shimmer 1.2s ease-in-out infinite;
152+
153+
@keyframes skeleton-shimmer {
154+
0% { background-position: 100% 50%; }
155+
100% { background-position: 0 50%; }
156+
}
157+
`;
158+
142159
/* 비어 있을 떄 출력하는 레이아웃 잡는 컨테이너 */
143160
export const DescriptionContainer = styled.div`
144161
width: 100%;

apps/website/src/pages/Blog/Blog/BlogList.tsx

Lines changed: 29 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -12,19 +12,21 @@ import jumpArrow_right from '@/assets/Icons/pagenation_1.png';
1212

1313
// 문자열을 BlogCategory로 변환하는 함수
1414
const convertStringToBlogCategory = (categoryStr: string): BlogCategory => {
15-
switch (categoryStr.toLowerCase()) {
16-
case 'seminar':
15+
switch (categoryStr) {
16+
case 'SEMINAR':
1717
return BlogCategory.SEMINAR;
18-
case 'project':
18+
case 'PROJECT':
1919
return BlogCategory.PROJECT;
20-
case 'study':
20+
case 'STUDY':
2121
return BlogCategory.STUDY;
22-
case 'hackathon':
22+
case 'HACKATHON':
2323
return BlogCategory.HACKATHON;
24-
case 'review':
24+
case 'REVIEW':
2525
return BlogCategory.REVIEW;
26-
case 'lecture':
26+
case 'LECTURE':
2727
return BlogCategory.LECTURE;
28+
case 'ETC':
29+
return BlogCategory.ETC;
2830
default:
2931
return BlogCategory.ETC;
3032
}
@@ -90,7 +92,7 @@ const BlogList: React.FC = () => {
9092
// 최대 7개의 페이지 번호만 표시
9193
const maxVisiblePages = 3;
9294
let startPage = Math.max(0, current - Math.floor(maxVisiblePages / 2));
93-
let endPage = Math.min(totalPages - 1, startPage + maxVisiblePages - 1);
95+
const endPage = Math.min(totalPages - 1, startPage + maxVisiblePages - 1);
9496

9597
// 시작 페이지 조정
9698
if (endPage - startPage < maxVisiblePages - 1) {
@@ -105,7 +107,22 @@ const BlogList: React.FC = () => {
105107
};
106108

107109
if (loading) {
108-
return <div>로딩 중...</div>;
110+
return (
111+
<S.Container>
112+
<S.TableContainer $isTablet={isTablet} $isMobile={isMobile}>
113+
<S.SubDescription $isMobile={isMobile}>
114+
* 블로그 클릭 시 외부 링크로 연결돼요.
115+
</S.SubDescription>
116+
</S.TableContainer>
117+
<S.DescriptionContainer>
118+
<S.SkeletonListContainer $isTablet={isTablet} $isBig={isBig} $isMobile={isMobile}>
119+
{Array.from({ length: 8 }).map((_, idx) => (
120+
<S.SkeletonCard key={idx} $isMobile={isMobile} />
121+
))}
122+
</S.SkeletonListContainer>
123+
</S.DescriptionContainer>
124+
</S.Container>
125+
);
109126
}
110127

111128
if (error) {
@@ -121,16 +138,16 @@ const BlogList: React.FC = () => {
121138
</S.TableContainer>
122139

123140
{/* 블로그 카드 리스트 */}
124-
{blogData && blogData.content.length > 0 ? (
141+
{blogData?.content && blogData.content.length > 0 ? (
125142
<>
126143
<S.DescriptionContainer>
127144
<S.ListContainer $isTablet={isTablet} $isBig={isBig} $isMobile={isMobile}>
128145
{blogData.content.map((blog, index) => (
129146
<BlogItem
130147
key={blog.blogId || index}
131148
blogUrl={blog.link}
132-
tags={blog.category && blog.category.length > 0
133-
? blog.category.map(categoryStr => convertStringToBlogCategory(categoryStr))
149+
tags={blog.categories && blog.categories.length > 0
150+
? blog.categories.map(str=> convertStringToBlogCategory(str))
134151
: [BlogCategory.ETC]
135152
}
136153
metadata={previewMap.get(blog.link) || undefined}

0 commit comments

Comments
 (0)