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
25 changes: 25 additions & 0 deletions app/(main)/_components/FeedSection.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { FeedCard } from "@/entities/feed/ui/FeedCard";

import { Container } from "@/shared/container/Container";

import * as styles from "./feedSection.css";

//TODO - 반응형해야함
export const FeedSection = () => {
return (
<Container>
<header className={styles.header}>
<h2 className={styles.h2}>잡만리에서 지금 화제인 글</h2>
<span className={styles.span}>실시간 좋아요 & 트렌드</span>
</header>

<div className={styles.cardGrid}>
<FeedCard />
<FeedCard />
<FeedCard />
<FeedCard />
<FeedCard />
</div>
</Container>
);
};
41 changes: 41 additions & 0 deletions app/(main)/_components/feedSection.css.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { style } from "@vanilla-extract/css";

export const header = style({
display: "flex",
flexDirection: "row",
justifyContent: "space-between",
alignItems: "center",
"@media": {
"screen and (max-width: 768px)": {
flexDirection: "column",
alignItems: "flex-start",
padding: "16px 0",
},
},
});

export const h2 = style({
fontSize: "24px",
fontWeight: 600,
"@media": {
"screen and (max-width: 768px)": {
margin: "4px 0",
},
},
});

export const span = style({
color: "gray",
});

export const cardGrid = style({
display: "grid",
gridTemplateColumns: "repeat(3, 1fr)",
gap: "1rem",
"@media": {
"screen and (max-width: 768px)": {
gridTemplateColumns: "repeat(2,1fr)",
gap: "0.5rem",
},
},
});
11 changes: 10 additions & 1 deletion app/(main)/page.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,14 @@
import { Spacing } from "@/shared/ui/spacing";

import { CompanyListSection } from "./_components/CompanyListSection";
import { FeedSection } from "./_components/FeedSection";

export default function Home() {
return <CompanyListSection />;
return (
<>
<CompanyListSection />
<Spacing direction="vertical" size={30} />
<FeedSection />
</>
);
}
6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,9 @@
"@vanilla-extract/vite-plugin": "^5.1.3",
"ky": "^1.14.1",
"lucide-react": "^0.555.0",
"next": "15.5.7",
"react": "^19.2.1",
"react-dom": "^19.2.1"
"next": "15.5.9",
"react": "^19.2.2",
"react-dom": "^19.2.2"
},
"devDependencies": {
"@chromatic-com/storybook": "^4.1.3",
Expand Down
13 changes: 13 additions & 0 deletions src/entities/feed/ui/FeedCard.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { FeedContent, FeedFooter, FeedHeader } from "@/entities/feed/ui";

import * as styles from "./feedCard.css";

export const FeedCard = () => {
return (
<article className={styles.cardContainer}>
<FeedHeader />
<FeedContent />
<FeedFooter />
</article>
);
};
15 changes: 15 additions & 0 deletions src/entities/feed/ui/FeedContent.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { Badge } from "@/shared/ui/badge/Badge";

import * as styles from "./feedContent.css";

export const FeedContent = () => {
return (
<section className={styles.contentContainer}>
<p className={styles.contentBody}>피드 내용</p>
<div className={styles.hashtagContainer}>
<Badge>태그1</Badge>
<Badge>태그2</Badge>
</div>
</section>
);
};
38 changes: 38 additions & 0 deletions src/entities/feed/ui/FeedFooter.tsx
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

좋아요개수나 댓글개수는 추후에 props 로 뚫는게 좋겠네요

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

현재 생각중인건 FeedSection에서 data를 props로 내려주는 방식을 고려중입니닷

Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
"use client";
import { useState } from "react";

import { Heart, MessageCircle } from "lucide-react";

import * as styles from "./feedFooter.css";

export const FeedFooter = () => {
const [isLiked, setIsLiked] = useState(false);
return (
<footer className={styles.footerContainer}>
<div className={styles.statsContainer}>
<button className={styles.likeContainer} aria-label={isLiked ? "좋아요 취소" : "좋아요"}>
<Heart
size={16}
className={styles.likeButton}
onClick={() => setIsLiked(!isLiked)}
fill={isLiked ? "#EF4444" : "none"}
stroke={isLiked ? "none" : "#64748B"}
aria-hidden="true"
/>
{/** TODO - 좋아요,댓글 수 props */}
<span>좋아요</span>
<span aria-label={`현재 좋아요 개수 ${112}개`}>112</span>
</button>
<div className={styles.commentCount}>
<MessageCircle size={16} />
<span>댓글</span>
<span>7</span>
</div>
</div>

<div className={styles.messageContainer}>
<button className={styles.messageButton}>쪽지 보내기</button>
</div>
</footer>
);
};
19 changes: 19 additions & 0 deletions src/entities/feed/ui/FeedHeader.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { Badge } from "@/shared/ui/badge/Badge";

import * as styles from "./feedHeader.css";

export const FeedHeader = () => {
return (
<div className={styles.headerContainer}>
<header className={styles.cardHeader}>
<Badge>태그</Badge>
<span className={styles.tagText}>피드 분류</span>
</header>
<h3 className={styles.cardTitle}>피드 제목</h3>
<div className={styles.cardMeta}>
<span>작성자</span>
<span>날짜</span>
</div>
</div>
);
};
18 changes: 18 additions & 0 deletions src/entities/feed/ui/feedCard.css.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { style } from "@vanilla-extract/css";

export const cardContainer = style({
display: "flex",
flexDirection: "column",
gap: "12px",
padding: "24px",
border: "1px solid #E2E8F0",
borderRadius: "16px",
backgroundColor: "white",
boxShadow: "0 1px 3px rgba(0, 0, 0, 0.1)",
transition: "box-shadow 0.2s",
maxWidth: "350px",
width: "100%",
":hover": {
boxShadow: "0 4px 12px rgba(0, 0, 0, 0.15)",
},
});
19 changes: 19 additions & 0 deletions src/entities/feed/ui/feedContent.css.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { style } from "@vanilla-extract/css";

export const contentContainer = style({
display: "flex",
flexDirection: "column",
gap: "12px",
});

export const contentBody = style({
fontSize: "16px",
lineHeight: "1.6",
margin: 0,
});

export const hashtagContainer = style({
display: "flex",
flexWrap: "wrap",
gap: "8px",
});
77 changes: 77 additions & 0 deletions src/entities/feed/ui/feedFooter.css.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import { style, keyframes } from "@vanilla-extract/css";

const heartBeat = keyframes({
"0%": { transform: "scale(1)" },
"25%": { transform: "scale(1.2)" },
"50%": { transform: "scale(1.1)" },
"100%": { transform: "scale(1)" },
});

export const footerContainer = style({
display: "flex",
flexDirection: "column",
gap: "8px",
paddingTop: "16px",
});

export const statsContainer = style({
display: "flex",
gap: "8px",
alignItems: "center",
"@media": {
"screen and (max-width: 768px)": {
flexDirection: "column",
alignItems: "flex-start",
},
},
});

export const likeContainer = style({
display: "flex",
alignItems: "center",
gap: "4px",
padding: "0",
border: "none",
backgroundColor: "transparent",
fontSize: "14px",
color: "#64748B",
});

export const likeButton = style({
cursor: "pointer",
});

export const commentCount = style({
display: "flex",
alignItems: "center",
gap: "6px",
fontSize: "14px",
color: "#64748B",
});

export const messageContainer = style({
display: "flex",
});

export const messageButton = style({
padding: "10px 16px",
backgroundColor: "#F1F5F9",
color: "#64748B",
border: "none",
borderRadius: "8px",
fontSize: "14px",
fontWeight: 500,
cursor: "pointer",
":hover": {
backgroundColor: "#E2E8F0",
},
});

export const heartIcon = style({
transition: "all 0.3s ease",
cursor: "pointer",
});

export const heartIconLiked = style({
animation: `${heartBeat} 0.4s ease`,
});
33 changes: 33 additions & 0 deletions src/entities/feed/ui/feedHeader.css.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { style } from "@vanilla-extract/css";

export const headerContainer = style({
display: "flex",
flexDirection: "column",
gap: "8px",
});

export const cardHeader = style({
display: "inline-flex",
flexDirection: "row",
gap: "8px",
alignItems: "center",
});

export const tagText = style({
color: "#64748B",
fontSize: "14px",
});

export const cardTitle = style({
fontSize: "24px",
fontWeight: 600,
margin: "4px 0",
});

export const cardMeta = style({
display: "flex",
flexDirection: "column",
gap: "4px",
fontSize: "14px",
color: "#94A3B8",
});
4 changes: 4 additions & 0 deletions src/entities/feed/ui/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export { FeedContent } from "./FeedContent";
export { FeedFooter } from "./FeedFooter";
export { FeedHeader } from "./FeedHeader";
export { FeedCard } from "./FeedCard";
2 changes: 1 addition & 1 deletion src/shared/container/container.css.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,5 @@ export const container = style({
backgroundColor: "#ffffff",
border: "1px solid rgba(0, 0, 0, 0.10)",
borderRadius: "24px",
padding: "40px",
padding: "30px",
});
16 changes: 16 additions & 0 deletions src/shared/ui/badge/Badge.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { ReactNode } from "react";
import { RecipeVariants } from "@vanilla-extract/recipes";

import * as styles from "./badge.css";

type BadgeVariants = NonNullable<RecipeVariants<typeof styles.badge>>;

interface BadgeProps {
children: ReactNode;
variant?: BadgeVariants["variant"];
size?: BadgeVariants["size"];
}

export const Badge = ({ children, variant, size }: BadgeProps) => {
return <span className={styles.badge({ variant, size })}>{children}</span>;
};
Loading
Loading