Skip to content

Commit

Permalink
메인 페이지 마크업 (#2)
Browse files Browse the repository at this point in the history
* feat: pc 네비게이션 코드 추가

* feat: 링크 추가

* feat: 페이지 추가

* feat: about 레이아웃 추가

* fix: 링크 수정
  • Loading branch information
Yummy-sk authored Dec 28, 2023
1 parent 10a3288 commit b7d83de
Show file tree
Hide file tree
Showing 13 changed files with 422 additions and 9 deletions.
16 changes: 16 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
"lint": "next lint"
},
"dependencies": {
"@headlessui/react": "^1.7.17",
"clsx": "^2.0.0",
"next": "14.0.4",
"next-themes": "^0.2.1",
Expand Down
7 changes: 7 additions & 0 deletions src/app/articles/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export default function Page(): JSX.Element {
return (
<div>
<h1>Page</h1>
</div>
);
}
10 changes: 7 additions & 3 deletions src/app/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import clsx from 'clsx';
import type { Metadata } from 'next';
import { Inter } from 'next/font/google';
import Provider from '@/components/providers';
import Provider from '@/providers';
import './globals.css';
import Header from '@/components/header';
import Footer from '@/components/footer';

const inter = Inter({ subsets: ['latin'] });

Expand All @@ -26,9 +27,12 @@ export default function RootLayout({ children }: Props) {
)}
>
<Provider>
<div className="bg-white w-full max-w-6xl ring-1 ring-zinc-100 dark:bg-zinc-900 dark:ring-zinc-300/20">
<div className="flex flex-col justify-between relative bg-white w-full max-w-6xl ring-1 ring-zinc-100 dark:bg-zinc-900 dark:ring-zinc-300/20">
<Header />
{children}
<main className="px-4 sm:px-8 lg:px-12 mt-16 sm:mt-32">
{children}
</main>
<Footer />
</div>
</Provider>
</body>
Expand Down
143 changes: 140 additions & 3 deletions src/app/page.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,144 @@
export default function Page(): JSX.Element {
import { type Metadata } from 'next';
import Image from 'next/image';
import Link from 'next/link';
import clsx from 'clsx';
import {
GitHubIcon,
InstagramIcon,
LinkedInIcon,
TwitterIcon,
} from '@/components/icons';
import portraitImage from '@/images/portrait.jpg';

interface SocialProps {
className?: string;
href: string;
icon: React.ComponentType<{ className?: string }>;
children: React.ReactNode;
}

function SocialLink({ className, href, children, icon: Icon }: SocialProps) {
return (
<li className={clsx(className, 'flex')}>
<Link
href={href}
className="group flex text-sm font-medium text-zinc-800 transition hover:text-teal-500 dark:text-zinc-200 dark:hover:text-teal-500"
>
<Icon className="h-6 w-6 flex-none fill-zinc-500 transition group-hover:fill-teal-500" />
<span className="ml-4">{children}</span>
</Link>
</li>
);
}

function MailIcon(props: React.ComponentPropsWithoutRef<'svg'>) {
return (
<svg viewBox="0 0 24 24" aria-hidden="true" {...props}>
<path
fillRule="evenodd"
d="M6 5a3 3 0 0 0-3 3v8a3 3 0 0 0 3 3h12a3 3 0 0 0 3-3V8a3 3 0 0 0-3-3H6Zm.245 2.187a.75.75 0 0 0-.99 1.126l6.25 5.5a.75.75 0 0 0 .99 0l6.25-5.5a.75.75 0 0 0-.99-1.126L12 12.251 6.245 7.187Z"
/>
</svg>
);
}

export const metadata: Metadata = {
title: 'About',
description:
'Hi! I’m Spencer Sharp. I live in New York City, where I design the future.',
};

export default function Page() {
return (
<div>
<h1>Page</h1>
<div className="grid grid-cols-1 gap-y-16 lg:grid-cols-2 lg:grid-rows-[auto_1fr] lg:gap-y-12">
<div className="lg:pl-20">
<div className="max-w-xs px-2.5 lg:max-w-none">
<Image
src={portraitImage}
alt=""
sizes="(min-width: 1024px) 32rem, 20rem"
className="aspect-square rotate-3 rounded-2xl bg-zinc-100 object-cover dark:bg-zinc-800"
/>
</div>
</div>
<div className="lg:order-first lg:row-span-2">
<h1 className="text-4xl font-bold tracking-tight text-zinc-800 dark:text-zinc-100 sm:text-5xl">
Hi! I’m Sang Kwon Yeum
</h1>
<div className="mt-6 space-y-7 text-base text-zinc-600 dark:text-zinc-400">
<p>
I’m a Front End Developer located in Korea. I’m interested in UI
effects, animations and creating intuitive, dynamic user
experiences.
</p>
<p>
What excites me most about working in software development is
being able to design and create things that have purpose and solve
real problems. I want to solve the problems of the world in
software and contribute to a better world.
</p>
</div>
<h2 className="text-2xl font-bold tracking-tight text-zinc-800 dark:text-zinc-100 sm:text-2xl mt-6">
Skill
</h2>
<div className="mt-6 space-y-7 text-base text-zinc-600 dark:text-zinc-400">
<fieldset className="border-b border-t border-gray-200">
<legend className="sr-only">Notifications</legend>
<div className="divide-y divide-gray-200">
<div className="relative flex items-start pb-4 pt-3.5">
<div className="min-w-0 flex-1 text-sm leading-6">
<h3 className="font-medium text-gray-900">Language</h3>
<p id="comments-description" className="text-gray-500">
JavaScript ・ TypeScript ・ ReScript ・ GraphQL
</p>
</div>
<div className="ml-3 flex h-6 items-center" />
</div>
<div className="relative flex items-start pb-4 pt-3.5">
<div className="min-w-0 flex-1 text-sm leading-6">
<h3 className="font-medium text-gray-900">Framework</h3>
<p id="comments-description" className="text-gray-500">
React.js ・ Next.js ・ Nest.js
</p>
</div>
</div>
<div className="relative flex items-start pb-4 pt-3.5">
<div className="min-w-0 flex-1 text-sm leading-6">
<h3 className="font-medium text-gray-900">API Client</h3>
<p id="comments-description" className="text-gray-500">
React Query ・ Relay
</p>
</div>
</div>
</div>
</fieldset>
</div>
</div>
<div className="lg:pl-20">
<ul>
<SocialLink href="#" icon={TwitterIcon}>
Twitter
</SocialLink>
<SocialLink href="#" icon={InstagramIcon} className="mt-4">
Instagram
</SocialLink>
<SocialLink href="#" icon={GitHubIcon} className="mt-4">
GitHub
</SocialLink>
<SocialLink href="#" icon={LinkedInIcon} className="mt-4">
LinkedIn
</SocialLink>
<SocialLink
href="mailto:[email protected]"
icon={MailIcon}
className="mt-8 border-t border-zinc-100 pt-8 dark:border-zinc-700/40"
>
[email protected]
</SocialLink>
</ul>
</div>
</div>
</div>
)
);
}
7 changes: 7 additions & 0 deletions src/app/projects/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export default function Page(): JSX.Element {
return (
<div>
<h1>Page</h1>
</div>
);
}
37 changes: 37 additions & 0 deletions src/components/footer/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import Link from 'next/link';

interface NavLinkProps {
href: string;
children: React.ReactNode;
}

function NavLink({ href, children }: NavLinkProps) {
return (
<Link
href={href}
className="transition hover:text-teal-500 dark:hover:text-teal-400"
>
{children}
</Link>
);
}

export default function Footer() {
return (
<footer className="px-4 sm:px-8 lg:px-12 mt-32 flex-none">
<div className="border-t border-zinc-100 pb-16 pt-10 dark:border-zinc-700/40">
<div className="flex flex-col items-center justify-between gap-6 sm:flex-row">
<div className="flex flex-wrap justify-center gap-x-6 gap-y-1 text-sm font-medium text-zinc-800 dark:text-zinc-200">
<NavLink href="/">About</NavLink>
<NavLink href="/articles">Articles</NavLink>
<NavLink href="/projects">Projects</NavLink>
</div>
<p className="text-sm text-zinc-400 dark:text-zinc-500">
&copy; {new Date().getFullYear()} SangKwon Yeum. All rights
reserved.
</p>
</div>
</div>
</footer>
);
}
18 changes: 15 additions & 3 deletions src/components/header/index.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,21 @@
import Theme from '@/components/header/theme';
import MobileNav from './mobile_nav';
import PcNav from './pc_nav';

export default function Header() {
return (
<>
<Theme />
</>
<header className="pointer-events-none z-50 flex flex-none flex-col relative py-4 px-5">
<div className="relative flex items-center ">
<div className="flex flex-1 justify-start md:justify-center">
<MobileNav className="pointer-events-auto md:hidden" />
<PcNav className="pointer-events-auto hidden md:block" />
</div>
<div className="flex justify-end ml-4">
<div className="pointer-events-auto">
<Theme />
</div>
</div>
</div>
</header>
);
}
107 changes: 107 additions & 0 deletions src/components/header/mobile_nav.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
'use client';

import { Popover, Transition } from '@headlessui/react';
import Link from 'next/link';
import { Fragment } from 'react';

function CloseIcon(props: React.ComponentPropsWithoutRef<'svg'>) {
return (
<svg viewBox="0 0 24 24" aria-hidden="true" {...props}>
<path
d="m17.25 6.75-10.5 10.5M6.75 6.75l10.5 10.5"
fill="none"
stroke="currentColor"
strokeWidth="1.5"
strokeLinecap="round"
strokeLinejoin="round"
/>
</svg>
);
}

function ChevronDownIcon(props: React.ComponentPropsWithoutRef<'svg'>) {
return (
<svg viewBox="0 0 8 6" aria-hidden="true" {...props}>
<path
d="M1.75 1.75 4 4.25l2.25-2.5"
fill="none"
strokeWidth="1.5"
strokeLinecap="round"
strokeLinejoin="round"
/>
</svg>
);
}

interface ItemProps {
href: string;
text: string;
}

function Item({ href, text }: ItemProps) {
return (
<li>
<Popover.Button as={Link} href={href} className="block py-2">
{text}
</Popover.Button>
</li>
);
}

interface Props {
className?: string;
}

export default function MobileNav({ className = '' }: Props) {
return (
<Popover className={className}>
<Popover.Button className="group flex items-center rounded-full bg-white/90 px-4 py-2 text-sm font-medium text-zinc-800 shadow-lg shadow-zinc-800/5 ring-1 ring-zinc-900/5 backdrop-blur dark:bg-zinc-800/90 dark:text-zinc-200 dark:ring-white/10 dark:hover:ring-white/20">
Menu
<ChevronDownIcon className="ml-3 h-auto w-2 stroke-zinc-500 group-hover:stroke-zinc-700 dark:group-hover:stroke-zinc-400" />
</Popover.Button>
<Transition.Root>
<Transition.Child
as={Fragment}
enter="duration-150 ease-out"
enterFrom="opacity-0"
enterTo="opacity-100"
leave="duration-150 ease-in"
leaveFrom="opacity-100"
leaveTo="opacity-0"
>
<Popover.Overlay className="fixed inset-0 z-50 bg-zinc-800/40 backdrop-blur-sm dark:bg-black/80" />
</Transition.Child>
<Transition.Child
as={Fragment}
enter="duration-150 ease-out"
enterFrom="opacity-0 scale-95"
enterTo="opacity-100 scale-100"
leave="duration-150 ease-in"
leaveFrom="opacity-100 scale-100"
leaveTo="opacity-0 scale-95"
>
<Popover.Panel
focus
className="fixed inset-x-4 top-8 z-50 origin-top rounded-3xl bg-white p-8 ring-1 ring-zinc-900/5 dark:bg-zinc-900 dark:ring-zinc-800"
>
<div className="flex flex-row-reverse items-center justify-between">
<Popover.Button aria-label="Close menu" className="-m-1 p-1">
<CloseIcon className="h-6 w-6 text-zinc-500 dark:text-zinc-400" />
</Popover.Button>
<h2 className="text-sm font-medium text-zinc-600 dark:text-zinc-400">
Navigation
</h2>
</div>
<nav className="mt-6">
<ul className="-my-2 divide-y divide-zinc-100 text-base text-zinc-800 dark:divide-zinc-100/5 dark:text-zinc-300">
<Item href="/" text="About" />
<Item href="/articles" text="Articles" />
<Item href="/projects" text="Projects" />
</ul>
</nav>
</Popover.Panel>
</Transition.Child>
</Transition.Root>
</Popover>
);
}
Loading

0 comments on commit b7d83de

Please sign in to comment.