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
55 changes: 2 additions & 53 deletions components/features/home/FeedCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,58 +16,7 @@ import { useAuthStore } from "@/store/auth.store";
import { LoginPromptDialog } from "@/components/features/auth/LoginPromptDialog";
import type { Content } from "@/types/content";
import { isStackOverflowSource } from "@/lib/content/sourceGuards";

// ─── helpers ──────────────────────────────────────────────────────────────────

const SOURCE_BADGE: Record<
string,
{ bg: string; text: string; label: string }
> = {
velog: { bg: "#20C997", text: "#fff", label: "V" },
naver_d2: { bg: "#03C75A", text: "#fff", label: "D2" },
kakao_tech: { bg: "#FEE500", text: "#3A1D1D", label: "K" },
우아한형제들: { bg: "#3399FF", text: "#fff", label: "W" },
toss_tech: { bg: "#0064FF", text: "#fff", label: "T" },
oliveyoung_tech: { bg: "#3A7D44", text: "#fff", label: "O" },
};

function SourceBadge({ sourceName }: { sourceName: string }) {
const key = sourceName.trim().toLowerCase();

// Medium_ 접두사로 시작하는 소스는 모두 Medium 배지로 표시
const style = key.startsWith("medium")
? { bg: "#000000", text: "#fff", label: "M" }
: SOURCE_BADGE[key];

if (isStackOverflowSource(sourceName)) {
return (
<span
className="flex h-[17px] w-[17px] shrink-0 items-center justify-center rounded text-[8px] font-bold leading-none"
style={{ background: "#F48024", color: "#fff" }}
>
SO
</span>
);
}

if (style) {
return (
<span
className="flex h-[17px] shrink-0 items-center justify-center rounded px-1 text-[8px] font-bold leading-none"
style={{ background: style.bg, color: style.text, minWidth: "17px" }}
>
{style.label}
</span>
);
}

// 기본: 이니셜 회색 원형
return (
<span className="flex h-[17px] w-[17px] shrink-0 items-center justify-center rounded-full bg-muted text-[9px] font-bold text-muted-foreground">
{sourceName.charAt(0).toUpperCase()}
</span>
);
}
import { SourceLogo } from "@/components/features/home/SourceLogo";

// ─── FeedCard ─────────────────────────────────────────────────────────────────

Expand Down Expand Up @@ -183,7 +132,7 @@ export function FeedCard({ content }: FeedCardProps) {
{/* Header: source badge + name + date + optional Q&A pill */}
<div className="mb-3 flex items-center justify-between">
<div className="flex items-center gap-2 text-xs font-medium text-muted-foreground">
<SourceBadge sourceName={content.sourceName} />
<SourceLogo sourceName={content.sourceName} />
<span className="font-semibold">{content.sourceName}</span>
<span className="text-muted-foreground/40">·</span>
<span>{formatDate(content.publishedAt)}</span>
Expand Down
69 changes: 69 additions & 0 deletions components/features/home/SourceLogo.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import { isStackOverflowSource } from "@/lib/content/sourceGuards";

interface SourceLogoProps {
sourceName: string;
size?: number;
}

type LogoConfig = {
src: string;
bg?: string;
innerPadding?: number;
};

const SOURCE_LOGO: Record<string, LogoConfig> = {
velog: { src: "/icons/sources/velog.svg" },
naver_d2: { src: "/icons/sources/naver.svg", bg: "#03C75A", innerPadding: 2 },
kakao_tech: { src: "/icons/sources/kakao.svg", bg: "#FEE500", innerPadding: 2 },
toss_tech: { src: "/icons/sources/toss.png" },
oliveyoung_tech: { src: "/icons/sources/oliveyoung.svg" },
};

export function SourceLogo({ sourceName, size = 17 }: SourceLogoProps) {
const key = sourceName.trim().toLowerCase();

let config: LogoConfig | undefined;

if (isStackOverflowSource(sourceName)) {
config = { src: "/icons/sources/stackoverflow.svg" };
} else if (key.startsWith("medium")) {
config = { src: "/icons/sources/medium.svg" };
} else {
config = SOURCE_LOGO[key];
}

if (config) {
const pad = config.innerPadding ?? 0;
const innerSize = size - pad * 2;
return (
<span
className="flex shrink-0 items-center justify-center overflow-hidden rounded"
style={{
width: size,
height: size,
minWidth: size,
backgroundColor: config.bg,
padding: pad > 0 ? pad : undefined,
}}
>
{/* eslint-disable-next-line @next/next/no-img-element */}
<img
src={config.src}
alt={sourceName}
width={innerSize}
height={innerSize}
style={{ objectFit: "contain", display: "block" }}
/>
</span>
);
}

return (
<span
className="flex shrink-0 items-center justify-center rounded-full bg-muted text-[9px] font-bold text-muted-foreground"
style={{ width: size, height: size, minWidth: size }}
>
{sourceName.charAt(0).toUpperCase()}
</span>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import Image from "next/image";
import Link from "next/link";
import { ChevronDown, ChevronUp } from "lucide-react";
import type { SearchResultItem } from "@/types/search";
import { SourceLogo } from "@/components/features/home/SourceLogo";

interface HomeSearchResultAccordionItemProps {
item: SearchResultItem;
Expand All @@ -21,9 +22,7 @@ export function HomeSearchResultAccordionItem({
onClick={onToggle}
className="flex w-full cursor-pointer items-center gap-3 py-3 text-left"
>
<span className="shrink-0 rounded bg-muted px-1.5 py-0.5 text-[11px] font-medium text-muted-foreground">
{item.sourceName}
</span>
<SourceLogo sourceName={item.sourceName} size={20} />
<span className="flex-1 truncate text-sm font-medium text-foreground">
{item.title}
</span>
Expand Down
53 changes: 28 additions & 25 deletions components/features/landing/LandingPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -272,51 +272,51 @@ const SOURCES = [
{
name: "Stack Overflow",
sub: "",
bg: "bg-[#F48024]",
textColor: "text-white",
initial: "SO",
containerBg: "bg-white",
logo: "/icons/sources/stackoverflow.svg",
logoPadding: "p-2",
},
{
name: "Velog",
sub: "",
bg: "bg-[#20C997]",
textColor: "text-white",
initial: "V",
containerBg: "bg-white",
logo: "/icons/sources/velog.svg",
logoPadding: "",
},
{
name: "NAVER D2",
sub: "기술 블로그",
bg: "bg-[#03C75A]",
textColor: "text-white",
initial: "N",
containerBg: "bg-[#03C75A]",
logo: "/icons/sources/naver.svg",
logoPadding: "p-3.5",
},
{
name: "Kakao Tech",
sub: "",
bg: "bg-[#FEE500]",
textColor: "text-neutral-900",
initial: "K",
containerBg: "bg-[#FEE500]",
logo: "/icons/sources/kakao.svg",
logoPadding: "p-2",
},
{
name: "Toss Tech",
sub: "",
bg: "bg-[#0064FF]",
textColor: "text-white",
initial: "T",
containerBg: "bg-white",
logo: "/icons/sources/toss.png",
logoPadding: "p-0.5",
},
{
name: "OliveYoung Tech",
sub: "",
bg: "bg-[#3A7D44]",
textColor: "text-white",
initial: "O",
containerBg: "bg-white",
logo: "/icons/sources/oliveyoung.svg",
logoPadding: "p-1.5",
},
{
name: "Medium",
sub: "당근 · 무신사 · 마이리얼트립 · 넷플릭스",
bg: "bg-black",
textColor: "text-white",
initial: "M",
containerBg: "bg-white",
logo: "/icons/sources/medium.svg",
logoPadding: "",
},
];

Expand Down Expand Up @@ -409,11 +409,14 @@ function FeaturesSection() {
className="flex flex-col items-center gap-1.5"
>
<div
className={`flex h-12 w-12 items-center justify-center rounded-lg shadow-sm ${source.bg}`}
className={`flex h-12 w-12 items-center justify-center overflow-hidden rounded-lg shadow-sm ${source.containerBg} ${source.logoPadding}`}
>
<span className={`text-sm font-bold ${source.textColor}`}>
{source.initial}
</span>
{/* eslint-disable-next-line @next/next/no-img-element */}
<img
src={source.logo}
alt={source.name}
className="h-full w-full object-contain"
/>
</div>
<div className="text-center">
<p className="text-sm font-semibold text-foreground">
Expand Down
1 change: 1 addition & 0 deletions public/icons/sources/kakao.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions public/icons/sources/medium.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions public/icons/sources/naver.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions public/icons/sources/oliveyoung.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions public/icons/sources/stackoverflow.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/icons/sources/toss.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions public/icons/sources/velog.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading