diff --git a/eslint.config.mjs b/eslint.config.mjs index 57cc10e..972f06c 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -22,6 +22,7 @@ const eslintConfig = [ 'unused-imports': unusedImports, }, rules: { + '@typescript-eslint/no-unused-vars': 'warn', 'react/jsx-sort-props': [ 'warn', { diff --git a/src/app/globals.css b/src/app/globals.css index 2cbc91b..7c4672a 100644 --- a/src/app/globals.css +++ b/src/app/globals.css @@ -16,6 +16,8 @@ --color-blog-blue: var(--blog-blue); --color-blog-green: var(--blog-green); --color-blog-yellow: var(--blog-yellow); + --color-blog-black: var(--blog-black); + --color-blog-gray-600: var(--blog-gray-600); --color-blog-gray-500: var(--blog-gray-500); --color-blog-gray-400: var(--blog-gray-400); --color-blog-gray-300: var(--blog-gray-300); @@ -62,6 +64,11 @@ --height-content: calc( 100vh - var(--height-header) - 2 * var(--header-padding-y) ); + --height-footer: var(--footer-height); + --padding-footer: var(--footer-height) 0; + --line-height-footer: calc( + var(--footer-height) - 2 * var(--footer-padding-x) + ); } :root { @@ -70,11 +77,14 @@ --header-padding-x: 1rem; --header-padding-y: 3rem; --card: oklch(1 0 0); + --footer-height: 92px; --blog-purple: oklch(0.6095 0.2382 332.15); --blog-pink: oklch(0.5717 0.2063 13.44); --blog-blue: oklch(0.5332 0.2106 263.54); --blog-green: oklch(0.684 0.1136 154.11); --blog-yellow: oklch(0.7266 0.1318 91.46); + --blog-black: oklch(0.3496 0.0141 274.5); + --blog-gray-600: oklch(0.6428 0.0152 248.06); --blog-gray-500: oklch(0.8196 0.0047 258.33); --blog-gray-400: oklch(0.8779 0.0026 228.79); --blog-gray-300: oklch(0.9401 0 0); @@ -158,6 +168,6 @@ @apply border-border break-keep outline-ring/50; } body { - @apply flex items-center justify-center font-pretendard; + @apply flex items-center justify-center bg-blog-gray-100 font-pretendard; } } diff --git a/src/app/page.tsx b/src/app/page.tsx index a054447..d93e154 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -1,23 +1,31 @@ -import { Button, PostCard } from '@/shared'; +'use client'; + +import { useState } from 'react'; + +import { PostCard, Tabs } from '@/shared'; import { Grid } from '@/widgets'; export default function Home() { + const posts = Array.from({ length: 9 }); // 임시 데이터 + + const [search, setSearch] = useState(''); + + const onChangeSearch = (e: React.ChangeEvent) => { + setSearch(e.target.value); + }; return ( -
-
- - - - -
- - +
+ + + {posts.map((_, index) => ( + + ))}
); diff --git a/src/shared/components/features/Footer.tsx b/src/shared/components/features/Footer.tsx deleted file mode 100644 index 953e687..0000000 --- a/src/shared/components/features/Footer.tsx +++ /dev/null @@ -1,3 +0,0 @@ -export const Footer = () => { - return
Footer
; -}; diff --git a/src/shared/components/features/Header.tsx b/src/shared/components/features/Header.tsx deleted file mode 100644 index c8ca8e0..0000000 --- a/src/shared/components/features/Header.tsx +++ /dev/null @@ -1,20 +0,0 @@ -import Link from 'next/link'; - -import { routerPath } from '@/shared/constants'; -import { Sun } from 'lucide-react'; - -export const Header = () => { - return ( -
- -

Dobblog

- -
- -

About

- - -
-
- ); -}; diff --git a/src/shared/components/features/PostCard.tsx b/src/shared/components/features/PostCard.tsx deleted file mode 100644 index 6998aae..0000000 --- a/src/shared/components/features/PostCard.tsx +++ /dev/null @@ -1,29 +0,0 @@ -import Image from 'next/image'; - -import { Calendar } from 'lucide-react'; - -export const PostCard = () => { - return ( -
-
- thumbnail -
-
-
-
일상
-
게시물 1 제목제목
-
게시물 1에 대한 내용입니다.
-
-
- -

2025년 1월 14일

-
-
-
- ); -}; diff --git a/src/shared/components/features/card/PostCard.tsx b/src/shared/components/features/card/PostCard.tsx new file mode 100644 index 0000000..5da24e7 --- /dev/null +++ b/src/shared/components/features/card/PostCard.tsx @@ -0,0 +1,34 @@ +import Image from 'next/image'; + +import { CalendarDays } from 'lucide-react'; + +export const PostCard = () => { + return ( +
+
+ thumbnail +
+
+
+
일상
+
게시물 1 제목제목
+
+ 게시물 1에 대한 내용입니다.게시물 1에 대한 내용입니다.게시물 1에 + 대한 내용입니다.게시물 1에 대한 내용입니다. +
+
+
+ +

+ 2025년 1월 14일 +

+
+
+
+ ); +}; diff --git a/src/shared/components/features/card/index.ts b/src/shared/components/features/card/index.ts new file mode 100644 index 0000000..4add1a6 --- /dev/null +++ b/src/shared/components/features/card/index.ts @@ -0,0 +1 @@ +export * from './PostCard'; diff --git a/src/shared/components/features/index.ts b/src/shared/components/features/index.ts index aa8cd93..f66f6d1 100644 --- a/src/shared/components/features/index.ts +++ b/src/shared/components/features/index.ts @@ -1,3 +1,3 @@ -export * from './Header'; -export * from './Footer'; -export * from './PostCard'; +export * from './card'; +export * from './layout'; +export * from './tabs'; diff --git a/src/shared/components/features/layout/Footer.tsx b/src/shared/components/features/layout/Footer.tsx new file mode 100644 index 0000000..5483d9f --- /dev/null +++ b/src/shared/components/features/layout/Footer.tsx @@ -0,0 +1,32 @@ +import Link from 'next/link'; + +export const Footer = () => { + return ( +
+
+

+ Copyright © 2025 Dobbymin All rights reserved. +

+
+ gmin0701@knu.ac.kr + . + +82-10-3095-7259 + . + + GitHub + + . + + LinkedIn + +
+
+
+ ); +}; diff --git a/src/shared/components/features/layout/Header.tsx b/src/shared/components/features/layout/Header.tsx new file mode 100644 index 0000000..1e4a352 --- /dev/null +++ b/src/shared/components/features/layout/Header.tsx @@ -0,0 +1,29 @@ +import Link from 'next/link'; + +import { Search, Sun } from 'lucide-react'; + +import { routerPath } from '../../../constants'; +import { Input } from '../../ui'; + +export const Header = () => { + return ( +
+ +

Dobblog

+ +
+ + +
+
+ +

About

+ + +
+
+ ); +}; diff --git a/src/shared/components/features/layout/index.ts b/src/shared/components/features/layout/index.ts new file mode 100644 index 0000000..3384cbe --- /dev/null +++ b/src/shared/components/features/layout/index.ts @@ -0,0 +1,2 @@ +export * from './Footer'; +export * from './Header'; diff --git a/src/shared/components/features/tabs/Tabs.tsx b/src/shared/components/features/tabs/Tabs.tsx new file mode 100644 index 0000000..99fbf71 --- /dev/null +++ b/src/shared/components/features/tabs/Tabs.tsx @@ -0,0 +1,33 @@ +'use client'; + +import { useState } from 'react'; + +export const Tabs = () => { + const [selected, setSelected] = useState(0); + + const tabs = [ + { name: 'All.tsx', count: 49 }, + { name: 'Develop.tsx', count: 3 }, + { name: 'Daily.tsx', count: 9 }, + { name: 'Review.tsx', count: 4 }, + ]; + + return ( +
+ {tabs.map((tab, idx) => ( +
setSelected(idx)} + > +

{tab.name}

+

({tab.count})

+
+ ))} +
+ ); +}; diff --git a/src/shared/components/features/tabs/index.ts b/src/shared/components/features/tabs/index.ts new file mode 100644 index 0000000..856dbbb --- /dev/null +++ b/src/shared/components/features/tabs/index.ts @@ -0,0 +1 @@ +export * from './Tabs'; diff --git a/src/shared/types/css.d.ts b/src/shared/types/css.d.ts new file mode 100644 index 0000000..444f793 --- /dev/null +++ b/src/shared/types/css.d.ts @@ -0,0 +1,4 @@ +declare module '*.css' { + const content: { [className: string]: string }; + export default content; +} diff --git a/src/widgets/grid/Grid.tsx b/src/widgets/grid/Grid.tsx index 2a26d89..04d0eaa 100644 --- a/src/widgets/grid/Grid.tsx +++ b/src/widgets/grid/Grid.tsx @@ -2,49 +2,51 @@ import * as React from 'react'; import { cn } from '@/shared'; -type ResponsiveGrid = Partial<{ - base: number; - sm: number; - md: number; - lg: number; - xl: number; - '2xl': number; -}>; - type Props = { - columns: number | ResponsiveGrid; + cols: string; gap?: number; + maxWidth?: + | 'xs' + | 'sm' + | 'md' + | 'lg' + | 'xl' + | '2xl' + | '3xl' + | '4xl' + | '5xl' + | '6xl' + | '7xl' + | 'full' + | 'none'; + justifyContent?: 'start' | 'center' | 'end' | 'between' | 'around' | 'evenly'; } & React.HTMLAttributes; export const Grid = ({ children, - columns, - gap = 0, + cols, + gap, + maxWidth, + justifyContent, className, ...props }: Props) => { - const gridColsClass = getGridColsClass(columns); - const gapClass = `gap-[${gap}px]`; - + const gapClass = gap ? `gap-${gap}` : ''; + const maxWidthClass = maxWidth ? `max-w-${maxWidth}` : ''; + const justifyContentClass = justifyContent ? `justify-${justifyContent}` : ''; return (
{children}
); }; - -function getGridColsClass(columns: number | ResponsiveGrid) { - if (typeof columns === 'number') { - return `grid-cols-${columns}`; - } - - return Object.entries(columns) - .map(([breakpoint, count]) => { - const prefix = breakpoint === 'base' ? '' : `${breakpoint}:`; - return `${prefix}grid-cols-${count}`; - }) - .join(' '); -} diff --git a/src/widgets/layout/BlogLayout.tsx b/src/widgets/layout/BlogLayout.tsx index 3c0bae0..de764e0 100644 --- a/src/widgets/layout/BlogLayout.tsx +++ b/src/widgets/layout/BlogLayout.tsx @@ -6,10 +6,14 @@ type Props = { export const BlogLayout = ({ children }: Props) => { return ( -
+
-
{children}
-
); };