Skip to content

Commit

Permalink
Merge branch 'main' into refactor/reduce-bundler-size
Browse files Browse the repository at this point in the history
  • Loading branch information
junyeokk committed Dec 5, 2024
2 parents aa0d0b8 + 0a97511 commit fb6fc7f
Show file tree
Hide file tree
Showing 53 changed files with 1,190 additions and 239 deletions.
9 changes: 9 additions & 0 deletions client/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { ReactQueryDevtools } from "@tanstack/react-query-devtools";

const Home = lazy(() => import("@/pages/Home"));
const Admin = lazy(() => import("@/pages/Admin"));
const AboutService = lazy(() => import("@/pages/AboutService"));

const queryClient = new QueryClient();

Expand Down Expand Up @@ -37,6 +38,14 @@ export default function App() {
</Suspense>
}
/>
<Route
path="/about"
element={
<Suspense fallback={<LoadingPage />}>
<AboutService />
</Suspense>
}
/>
</Routes>
<ReactQueryDevtools />
</QueryClientProvider>
Expand Down
31 changes: 31 additions & 0 deletions client/src/components/about/CTASection.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { Link } from "react-router-dom";

import { Section } from "@/components/about/Section.tsx";
import { Button } from "@/components/ui/button";

export const CTASection = () => {
const scrollToTop = () => {
window.scrollTo({
top: 0,
behavior: "smooth",
});
};

return (
<Section id="cta-section" className="min-h-screen flex items-center px-8">
<div className="max-w-3xl mx-auto text-center">
<h2 className="text-3xl font-bold mb-6">지금 바로 시작하세요</h2>
<p className="text-gray-600 mb-8">개발자들의 인사이트 가득한 블로그 세상으로 초대합니다</p>
<div className="flex items-center justify-center space-x-4">
<Link to="/">
<Button size="lg">블로그 둘러보기</Button>
</Link>

<Button variant="outline" size="lg" onClick={scrollToTop}>
다시 알아보기
</Button>
</div>
</div>
</Section>
);
};
48 changes: 48 additions & 0 deletions client/src/components/about/ExtraFeatureSection.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import { Section } from "@/components/about/Section";

import { EXTRA_FEATURES } from "@/constants/about";

export const ExtraFeatureSection = () => {
return (
<Section className="py-20 px-8 bg-gray-50">
<div className="max-w-6xl mx-auto">
<div className="mb-16">
<h1 className="text-l font-bold mb-2 text-primary">{EXTRA_FEATURES.mainTitle}</h1>
<p className="text-2xl font-semibold whitespace-pre-line leading-normal">{EXTRA_FEATURES.groupTitle}</p>
</div>

<div className="space-y-20">
{EXTRA_FEATURES.sections.map((section, idx) => (
<div key={idx} className="space-y-8">
<h2 className="text-2xl font-bold text-gray-800">{section.title}</h2>

<div className="grid grid-cols-1 md:grid-cols-2 gap-8">
{section.features.map((feature, featureIdx) => (
<div key={featureIdx} className="bg-white rounded-xl p-8 shadow-sm hover:shadow-md transition-shadow">
<div className="flex items-center gap-3 mb-4">
<div className="p-2 bg-primary/10 rounded-lg">
<feature.icon className="w-6 h-6 text-primary" />
</div>
<h3 className="text-xl font-semibold">{feature.shortTitle}</h3>
</div>

<p className="text-gray-600 mb-6">{feature.description}</p>

<ul className="space-y-3">
{feature.items.map((item, itemIdx) => (
<li key={itemIdx} className="flex items-center gap-2 text-gray-600">
<div className="w-1.5 h-1.5 rounded-full bg-primary" />
{item}
</li>
))}
</ul>
</div>
))}
</div>
</div>
))}
</div>
</div>
</Section>
);
};
42 changes: 42 additions & 0 deletions client/src/components/about/FeatureCard.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { useInView } from "@/hooks/common/useInView";

import { cn } from "@/lib/utils";
import { FeatureItem } from "@/types/about";

interface FeatureCardProps {
feature: FeatureItem;
}

export const FeatureCard = ({ feature }: FeatureCardProps) => {
const { ref, isInView } = useInView<HTMLDivElement>({ once: true });
const Icon = feature.icon;

return (
<div
ref={ref}
className={cn(
"transition-all duration-1000 ease-out",
isInView ? "opacity-100 translate-y-0" : "opacity-0 translate-y-10"
)}
>
<div className="grid grid-cols-1 lg:grid-cols-2 gap-8">
{feature.imageSrc ? (
<img src={feature.imageSrc} alt={feature.imageAlt} className="w-full aspect-video object-cover" />
) : (
<div className="w-full aspect-video flex items-center justify-center">
<span>이미지 준비 중</span>
</div>
)}

<div className="flex flex-col justify-center">
<div className="flex items-center gap-2">
<Icon className="w-4 h-8 text-primary" />
<h4 className="text-l font-semibold text-primary">{feature.shortTitle}</h4>
</div>
<h3 className="text-2xl font-bold">{feature.longTitle}</h3>
<p className="text-lg pt-6 text-gray-400 font-semibold whitespace-pre-line">{feature.description}</p>
</div>
</div>
</div>
);
};
31 changes: 31 additions & 0 deletions client/src/components/about/FeatureSection.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { Section } from "@/components/about/Section.tsx";

import { FEATURES } from "@/constants/about";

import { FeatureCard } from "./FeatureCard";
import { cn } from "@/lib/utils";

export const FeatureSection = () => {
return (
<div>
{FEATURES.map((feature, idx) => (
<Section key={idx} className={cn("py-20 px-8", idx % 2 === 0 ? "bg-white" : "bg-gray-50")}>
<div className="max-w-6xl mx-auto">
<div className="space-y-16">
<div className="mb-12">
<p className="text-l font-bold mb-2 text-primary">{feature.mainTitle}</p>
<h2 className="text-2xl font-semibold whitespace-pre-line leading-normal">{feature.groupTitle}</h2>
</div>

<div className="space-y-20">
{feature.features.map((featureItem, itemIdx) => (
<FeatureCard key={itemIdx} feature={featureItem} />
))}
</div>
</div>
</div>
</Section>
))}
</div>
);
};
57 changes: 57 additions & 0 deletions client/src/components/about/Footer.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import { footerLinks, teamMembers } from "@/constants/footer";

import type { FooterLink } from "@/types/footer";

export const Footer = () => {
const renderFooterLink = (link: FooterLink) => (
<div className="flex flex-col space-y-2">
<a
href={link.href}
target="_blank"
rel="noopener noreferrer"
className="flex flex-col space-y-2 hover:text-primary transition-colors"
>
<div className="flex items-center gap-2 text-gray-500">
<link.icon className="w-4 h-4" />
<span className="text-sm">{link.label}</span>
</div>
<span className="text-sm font-medium">{link.value}</span>
</a>
{link.subLinks?.map((subLink, subIdx) => (
<a
key={subIdx}
href={subLink.href}
target="_blank"
rel="noopener noreferrer"
className="text-sm text-gray-500 hover:text-primary transition-colors ml-6"
>
{subLink.label}
</a>
))}
</div>
);

return (
<footer className="bg-gray-50 border-t border-gray-200">
<div className="max-w-6xl mx-auto px-8 py-12">
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-8">
{footerLinks.map((link, idx) => (
<div key={idx}>{renderFooterLink(link)}</div>
))}
</div>

<div className="mt-8 pt-8">
<div className="text-center text-[10px] text-gray-500">
<span>Made by </span>
{teamMembers.map((name, idx) => (
<span key={idx}>
{name}
{idx !== teamMembers.length - 1 && ", "}
</span>
))}
</div>
</div>
</div>
</footer>
);
};
48 changes: 48 additions & 0 deletions client/src/components/about/HeroSection.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import { ChevronsDown } from "lucide-react";

import { Section } from "@/components/about/Section.tsx";
import { Button } from "@/components/ui/button";

import logo from "@/assets/logo-denamu-main.svg";

export const HeroSection = () => {
const scrollToBottom = () => {
const ctaSection = document.querySelector("#cta-section");
if (ctaSection) {
ctaSection.scrollIntoView({ behavior: "smooth" });
}
};

return (
<Section className="min-h-screen relative flex flex-col">
<div className="flex-shrink-0 min-h-[400px] md:min-h-[45vh] flex items-center justify-center p-8">
<div className="text-center max-w-4xl">
<div className="flex items-center justify-center space-x-2 mb-6">
<img src={logo} className="w-32 md:w-52" />
</div>
<h1 className="text-3xl md:text-5xl font-bold mb-6 bg-clip-text text-transparent bg-gradient-to-r from-[#27ae60] via-[#2596be] to-[#228be6]">
개발자를 위한 최고의 블로그 허브
</h1>
<p className="text-lg md:text-xl mb-8">기술 블로그를 한눈에 모아보고, 개발자들과 함께 성장하세요.</p>
<div className="flex items-center justify-center space-x-4">
<Button size="lg" onClick={scrollToBottom}>
바로 시작하기
</Button>
</div>
</div>
</div>

<div className="flex-grow flex items-start justify-center p-4 md:p-8">
<img
src="https://github.com/user-attachments/assets/e91e80c0-1c1b-40d0-ae6c-0f0151e03796"
alt="Service Preview"
className="max-w-[90%] md:max-w-[80%] h-auto object-contain"
/>
</div>

<div className="absolute bottom-4 md:bottom-8 left-1/2 -translate-x-1/2">
<ChevronsDown className="w-8 h-8 md:w-12 md:h-12 text-gray-400 animate-slow-bounce" />
</div>
</Section>
);
};
29 changes: 29 additions & 0 deletions client/src/components/about/Section.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { HTMLAttributes, forwardRef } from "react";

import { useInView } from "@/hooks/common/useInView.ts";

import { cn } from "@/lib/utils";

interface SectionProps extends HTMLAttributes<HTMLElement> {
children: React.ReactNode;
}

export const Section = forwardRef<HTMLElement, SectionProps>(({ children, className, ...props }) => {
const { ref, isInView } = useInView<HTMLElement>({ once: true });

return (
<section
ref={ref}
className={cn(
"transition-all duration-1000",
isInView ? "opacity-100 translate-y-0" : "opacity-0 translate-y-10",
className
)}
{...props}
>
{children}
</section>
);
});

Section.displayName = "Section";
2 changes: 1 addition & 1 deletion client/src/components/admin/rss/RssResponseCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ export const RssResponseCard = ({ request }: RssResponseCardProps) => {
<div className="space-y-2">
<h3 className="text-lg font-semibold">{request.name}</h3>
<p className="text-sm text-muted-foreground">{request.rssUrl}</p>
<p className="text-sm text-muted-foreground">거부 사유:{request.description}</p>
{request.description && <p className="text-sm text-muted-foreground">거부 사유:{request.description}</p>}
<div className="flex items-center space-x-4">
<span className="text-sm text-muted-foreground">신청자: {request.userName}</span>
</div>
Expand Down
4 changes: 2 additions & 2 deletions client/src/components/chart/PieChartItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ const chartConfig: ChartConfig = {
label: "Velog",
color: "hsl(150, 60%, 70%)",
},
etc: {
label: "etc",
medium: {
label: "Medium",
color: "hsl(30, 60%, 70%)",
},
} satisfies ChartConfig;
Expand Down
2 changes: 1 addition & 1 deletion client/src/components/chat/Chat.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ export function Chat() {

return (
<Sidebar side="right" variant="floating">
<SidebarContent className="flex flex-col h-full w-full">
<SidebarContent>
<ChatHeader />
<ChatSection isFull={isFull} />
<ChatFooter />
Expand Down
Loading

0 comments on commit fb6fc7f

Please sign in to comment.