메인스타일, 호버 등
This commit is contained in:
@@ -218,7 +218,7 @@ export function BoardPanelClient({
|
||||
// attachments에서 이미지를 먼저 찾고, 없으면 content에서 추출
|
||||
const firstImage = post.attachments?.[0]?.url || extractImageFromContent(post.content);
|
||||
return (
|
||||
<Link key={post.id} href={`/posts/${post.id}`} className="flex h-[150px] items-start rounded-[16px] overflow-hidden bg-white">
|
||||
<Link key={post.id} href={`/posts/${post.id}`} className="group flex h-[150px] items-start rounded-[16px] overflow-hidden bg-white">
|
||||
<div className="h-[150px] w-[214px] relative shrink-0 bg-[#ededed] overflow-hidden">
|
||||
{firstImage ? (
|
||||
<img
|
||||
@@ -248,7 +248,7 @@ export function BoardPanelClient({
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
<span className="text-[16px] leading-[22px] text-[#5c5c5c] truncate">{stripHtml(post.title)}</span>
|
||||
<span className="text-[16px] leading-[22px] text-[#5c5c5c] truncate group-hover:text-[var(--red-50,#F94B37)] group-hover:font-[700]" style={{ fontFamily: "var(--font-family-Font-1, Pretendard)" }}>{stripHtml(post.title)}</span>
|
||||
{(post.stat?.commentsCount ?? 0) > 0 && (
|
||||
<span className="ml-1 text-[14px] text-[#f45f00] font-bold shrink-0">[{post.stat?.commentsCount}]</span>
|
||||
)}
|
||||
@@ -314,9 +314,9 @@ export function BoardPanelClient({
|
||||
<div className="bg-white px-[24px] pt-[8px] pb-[16px]">
|
||||
<ul className="min-h-[326px]">
|
||||
{selectedBoardData.textPosts.map((p) => (
|
||||
<li key={p.id} className="border-b border-[#ededed] h-[56px] pl-0 pr-[24px] pt-[16px] pb-[16px]">
|
||||
<li key={p.id} className="border-b border-[#ededed] h-[28px] pl-0 pr-[24px] pt-0 pb-0">
|
||||
<div className="flex items-center justify-between w-full">
|
||||
<Link href={`/posts/${p.id}`} className="flex items-center gap-[4px] h-[24px] overflow-hidden flex-1 min-w-0">
|
||||
<Link href={`/posts/${p.id}`} className="group flex items-center gap-[4px] h-[32px] overflow-hidden flex-1 min-w-0">
|
||||
<div className="relative w-[16px] h-[16px] shrink-0">
|
||||
{isNewWithin1Hour(p.createdAt) && (
|
||||
<>
|
||||
@@ -327,7 +327,7 @@ export function BoardPanelClient({
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
<span className="text-[16px] leading-[22px] text-[#5c5c5c] truncate max-w-[calc(100vw-280px)]">{stripHtml(p.title)}</span>
|
||||
<span className="text-[14px] leading-[20px] text-[#5c5c5c] truncate max-w-[calc(100vw-280px)] group-hover:text-[var(--red-50,#F94B37)] group-hover:font-[700]" style={{ fontFamily: "var(--font-family-Font-1, Pretendard)" }}>{stripHtml(p.title)}</span>
|
||||
{(p.stat?.commentsCount ?? 0) > 0 && (
|
||||
<span className="text-[14px] text-[#f45f00] font-bold">[{p.stat?.commentsCount}]</span>
|
||||
)}
|
||||
@@ -339,7 +339,7 @@ export function BoardPanelClient({
|
||||
</ul>
|
||||
</div>
|
||||
) : (
|
||||
<PostList key={board.id} boardId={board.id} sort="recent" />
|
||||
<PostList key={board.id} boardId={board.id} sort="recent" titleHoverOrange pageSizeOverride={16} compact />
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -35,7 +35,7 @@ function stripHtml(html: string | null | undefined): string {
|
||||
return html.replace(/<[^>]*>/g, "").trim();
|
||||
}
|
||||
|
||||
export function PostList({ boardId, sort = "recent", q, tag, author, authorId, start, end, variant = "default", newPostHref }: { boardId?: string; sort?: "recent" | "popular"; q?: string; tag?: string; author?: string; authorId?: string; start?: string; end?: string; variant?: "default" | "board"; newPostHref?: string }) {
|
||||
export function PostList({ boardId, sort = "recent", q, tag, author, authorId, start, end, variant = "default", newPostHref, titleHoverOrange, pageSizeOverride, compact }: { boardId?: string; sort?: "recent" | "popular"; q?: string; tag?: string; author?: string; authorId?: string; start?: string; end?: string; variant?: "default" | "board"; newPostHref?: string; titleHoverOrange?: boolean; pageSizeOverride?: number; compact?: boolean }) {
|
||||
const sp = useSearchParams();
|
||||
const listContainerRef = useRef<HTMLDivElement | null>(null);
|
||||
const [lockedMinHeight, setLockedMinHeight] = useState<number | null>(null);
|
||||
@@ -43,7 +43,9 @@ export function PostList({ boardId, sort = "recent", q, tag, author, authorId, s
|
||||
// board 변형에서는 URL에서 pageSize를 읽고, 기본값은 20
|
||||
const defaultPageSize = variant === "board" ? 20 : 10;
|
||||
const pageSizeParam = sp.get("pageSize");
|
||||
const pageSize = pageSizeParam ? Math.min(50, Math.max(10, parseInt(pageSizeParam, 10))) : defaultPageSize;
|
||||
const pageSize = (variant === "board" && pageSizeOverride)
|
||||
? pageSizeOverride
|
||||
: (pageSizeParam ? Math.min(50, Math.max(10, parseInt(pageSizeParam, 10))) : defaultPageSize);
|
||||
|
||||
// board 변형: 번호 페이지네이션
|
||||
const initialPage = useMemo(() => Math.max(1, parseInt(sp.get("page") || "1", 10)), [sp]);
|
||||
@@ -168,15 +170,17 @@ export function PostList({ boardId, sort = "recent", q, tag, author, authorId, s
|
||||
<div ref={listContainerRef} style={{ minHeight: lockedMinHeight ? `${lockedMinHeight}px` : undefined }}>
|
||||
<ul className="divide-y divide-[#ececec]">
|
||||
{items.map((p) => (
|
||||
<li key={p.id} className={`px-4 ${variant === "board" ? "py-2.5" : "py-3 md:py-3"} hover:bg-neutral-50 transition-colors`}>
|
||||
<li key={p.id} className={`px-4 ${variant === "board" ? (compact ? "py-1.5" : "py-2.5") : "py-3 md:py-3"} hover:bg-neutral-50 transition-colors`}>
|
||||
<div className="grid grid-cols-1 md:grid-cols-[20px_1fr_120px_120px_80px] items-center gap-2">
|
||||
{/* bullet/공지 아이콘 자리 */}
|
||||
<div className="hidden md:flex items-center justify-center text-[#f94b37]">{p.isPinned ? "★" : "•"}</div>
|
||||
|
||||
<div className="min-w-0">
|
||||
<Link href={`/posts/${p.id}`} className="block truncate text-[15px] md:text-base text-neutral-900">
|
||||
<Link href={`/posts/${p.id}`} className={`group block truncate text-neutral-900`}>
|
||||
{p.isPinned && <span className="mr-2 inline-flex items-center rounded bg-orange-100 text-orange-700 px-1.5 py-0.5 text-[11px]">공지</span>}
|
||||
{stripHtml(p.title)}
|
||||
<span className={`${titleHoverOrange ? "group-hover:text-[var(--red-50,#F94B37)] group-hover:font-[700] group-hover:text-[16px] group-hover:leading-[22px]" : ""} ${compact ? "text-[14px] leading-[20px]" : "text-[15px] md:text-base"}`} style={{ fontFamily: "var(--font-family-Font-1, Pretendard)" }}>
|
||||
{stripHtml(p.title)}
|
||||
</span>
|
||||
{(p.stat?.commentsCount ?? 0) > 0 && (
|
||||
<span className="ml-1 text-[12px] md:text-[12px] text-[#f94b37] align-middle">[{p.stat?.commentsCount}]</span>
|
||||
)}
|
||||
|
||||
@@ -57,6 +57,14 @@ export default async function Home({ searchParams }: { searchParams: Promise<{ s
|
||||
if (admin) currentUser = admin;
|
||||
}
|
||||
|
||||
// 내가 쓴 게시글/댓글 수
|
||||
let myPostsCount = 0;
|
||||
let myCommentsCount = 0;
|
||||
if (currentUser) {
|
||||
myPostsCount = await prisma.post.count({ where: { authorId: currentUser.userId, status: "published" } });
|
||||
myCommentsCount = await prisma.comment.count({ where: { authorId: currentUser.userId } });
|
||||
}
|
||||
|
||||
// 메인페이지 설정 불러오기
|
||||
const SETTINGS_KEY = "mainpage_settings" as const;
|
||||
const settingRow = await prisma.setting.findUnique({ where: { key: SETTINGS_KEY } });
|
||||
@@ -164,7 +172,7 @@ export default async function Home({ searchParams }: { searchParams: Promise<{ s
|
||||
where: { boardId: sb.id, status: "published" },
|
||||
select: { id: true, title: true, createdAt: true, stat: { select: { recommendCount: true, commentsCount: true } } },
|
||||
orderBy: { createdAt: "desc" },
|
||||
take: 7,
|
||||
take: 16,
|
||||
});
|
||||
}
|
||||
// 기본 타입은 PostList가 자체적으로 API를 호출하므로 데이터 미리 가져오지 않음
|
||||
@@ -270,28 +278,38 @@ export default async function Home({ searchParams }: { searchParams: Promise<{ s
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex flex-col gap-[12px] relative z-10">
|
||||
<Link href="/my-page" className="relative w-[300px] h-[32px] rounded-full bg-[#8c8c8c] hover:bg-[#7a7a7a] text-white text-[12px] font-[700] flex items-center justify-center">
|
||||
<span className="inline-flex items-center">
|
||||
<SearchIcon width={16} height={16} />
|
||||
<span className="ml-[8px]">내 정보 페이지</span>
|
||||
<Link href="/my-page" className="w-[300px] h-[32px] rounded-full bg-[#8c8c8c] hover:bg-[#5c5c5c] text-white text-[12px] font-[700] flex items-center px-[12px]">
|
||||
<span className="flex items-center w-full pl-[88px]">
|
||||
<span className="flex items-center gap-[8px]">
|
||||
<SearchIcon width={16} height={16} />
|
||||
<span>내 정보 페이지</span>
|
||||
</span>
|
||||
</span>
|
||||
</Link>
|
||||
<Link href="/my-page?tab=points" className="relative w-[300px] h-[32px] rounded-full bg-[#8c8c8c] hover:bg-[#7a7a7a] text-white text-[12px] font-[700] flex items-center">
|
||||
<span className="absolute left-[100px] inline-flex items-center">
|
||||
<SearchIcon width={16} height={16} />
|
||||
<span className="ml-[8px]">포인트 히스토리</span>
|
||||
<Link href="/my-page?tab=points" className="w-[300px] h-[32px] rounded-full bg-[#8c8c8c] hover:bg-[#5c5c5c] text-white text-[12px] font-[700] flex items-center px-[12px]">
|
||||
<span className="flex items-center w-full pl-[88px]">
|
||||
<span className="flex items-center gap-[8px]">
|
||||
<SearchIcon width={16} height={16} />
|
||||
<span>포인트 히스토리</span>
|
||||
</span>
|
||||
</span>
|
||||
</Link>
|
||||
<Link href={`/my-page?tab=posts`} className="relative w-[300px] h-[32px] rounded-full bg-[#8c8c8c] hover:bg-[#7a7a7a] text-white text-[12px] font-[700] flex items-center">
|
||||
<span className="absolute left-[100px] inline-flex items-center">
|
||||
<SearchIcon width={16} height={16} />
|
||||
<span className="ml-[8px]">내가 쓴 게시글</span>
|
||||
<Link href={`/my-page?tab=posts`} className="w-[300px] h-[32px] rounded-full bg-[#8c8c8c] hover:bg-[#5c5c5c] text-white text-[12px] font-[700] flex items-center px-[12px]">
|
||||
<span className="flex items-center w-full pl-[88px]">
|
||||
<span className="flex items-center gap-[8px]">
|
||||
<SearchIcon width={16} height={16} />
|
||||
<span>내가 쓴 게시글</span>
|
||||
</span>
|
||||
<span className="ml-auto inline-flex items-center justify-center h-[20px] px-[8px] rounded-full bg-white text-[#5c5c5c] text-[12px] leading-[20px] shrink-0">{myPostsCount.toLocaleString()}개</span>
|
||||
</span>
|
||||
</Link>
|
||||
<Link href={`/my-page?tab=comments`} className="relative w-[300px] h-[32px] rounded-full bg-[#8c8c8c] hover:bg-[#7a7a7a] text-white text-[12px] font-[700] flex items-center">
|
||||
<span className="absolute left-[100px] inline-flex items-center">
|
||||
<SearchIcon width={16} height={16} />
|
||||
<span className="ml-[8px]">내가 쓴 댓글</span>
|
||||
<Link href={`/my-page?tab=comments`} className="w-[300px] h-[32px] rounded-full bg-[#8c8c8c] hover:bg-[#5c5c5c] text-white text-[12px] font-[700] flex items-center px-[12px]">
|
||||
<span className="flex items-center w-full pl-[88px]">
|
||||
<span className="flex items-center gap-[8px]">
|
||||
<SearchIcon width={16} height={16} />
|
||||
<span>내가 쓴 댓글</span>
|
||||
</span>
|
||||
<span className="ml-auto inline-flex items-center justify-center h-[20px] px-[8px] rounded-full bg-white text-[#5c5c5c] text-[12px] leading-[20px] shrink-0">{myCommentsCount.toLocaleString()}개</span>
|
||||
</span>
|
||||
</Link>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user