안녕하세요?
지난 블로그에서 NextJS와 Typescript 그리고 Tailwind CSS까지 적용된 템플릿을 만들었는데요.
이번 시간에는 거기에 추가해서 Tailwind CSS를 이용한 모바일 적용되는 반응형 템플릿을 만들어 보겠습니다.
이렇게 하는 이유는 한번 만들어 놓으면 나중에 재사용이 쉬워서 그렇습니다.
디자인은 원하시는 방향으로 만들어도 상관없습니다.
전체적인 Responsive(반응형) 디자인이 목적이니까요?
일단 components 폴더를 만듭시다.
그리고 Layout.tsx파일도 생성시킵시다.
mkdir components
cd components
touch Layout.tsx
Layout.tsx파일을 만들기 전에 _app.tsx에 Layout을 적용시켜 볼까요?
/pages/_app.tsx
import '../styles/globals.css'
import Layout from "../components/Layout";
function MyApp({ Component, pageProps }) {
return (
<Layout>
<Component {...pageProps} />
</Layout>
);
}
export default MyApp;
_app.tsx파일은 간단합니다.
앞으로 만들 모든 페이지는 Layout을 가진다는 뜻입니다.
이제 Layout.tsx파일을 볼까요?
/components/Layout.tsx
import React from "react";
import NavBar from "./Navbar";
type Props = {
children: React.ReactNode;
};
export default function Layout(props: Props) {
return (
<div className="w-full p-0">
<NavBar />
{props.children}
</div>
);
}
위 코드를 보시면 전체적으로 우리의 Layout은 w-full p-0으로 지정했습니다.
width: 100%; padding : 0px; 이란 뜻이죠.
그리고 Navbar 컴포넌트가 보이네요.
상단 Navbar인데요.
이제 Navbar.tsx 파일을 components 폴더에 만듭시다.
/components/Navbar.tsx
import React, { useState } from "react";
import { MenuIcon, XIcon } from "@heroicons/react/outline";
const Navbar = () => {
const [menuToggle, setMenuToggle] = useState(false);
return (
// navbar goes here
<nav className="bg-gray-100">
<div className="max-w-6xl mx-auto px-4">
<div className="flex justify-between">
<div className="flex space-x-4">
{/* logo */}
<div>
<a href="/" className="flex items-center py-5 px-2 text-gray-700">
<svg
xmlns="http://www.w3.org/2000/svg"
className="h-5 w-5 mr-2 text-blue-400"
viewBox="0 0 20 20"
fill="currentColor"
>
<path
fillRule="evenodd"
d="M9.504 1.132a1 1 0 01.992 0l1.75 1a1 1 0 11-.992 1.736L10 3.152l-1.254.716a1 1 0 11-.992-1.736l1.75-1zM5.618 4.504a1 1 0 01-.372 1.364L5.016 6l.23.132a1 1 0 11-.992 1.736L4 7.723V8a1 1 0 01-2 0V6a.996.996 0 01.52-.878l1.734-.99a1 1 0 011.364.372zm8.764 0a1 1 0 011.364-.372l1.733.99A1.002 1.002 0 0118 6v2a1 1 0 11-2 0v-.277l-.254.145a1 1 0 11-.992-1.736l.23-.132-.23-.132a1 1 0 01-.372-1.364zm-7 4a1 1 0 011.364-.372L10 8.848l1.254-.716a1 1 0 11.992 1.736L11 10.58V12a1 1 0 11-2 0v-1.42l-1.246-.712a1 1 0 01-.372-1.364zM3 11a1 1 0 011 1v1.42l1.246.712a1 1 0 11-.992 1.736l-1.75-1A1 1 0 012 14v-2a1 1 0 011-1zm14 0a1 1 0 011 1v2a1 1 0 01-.504.868l-1.75 1a1 1 0 11-.992-1.736L16 13.42V12a1 1 0 011-1zm-9.618 5.504a1 1 0 011.364-.372l.254.145V16a1 1 0 112 0v.277l.254-.145a1 1 0 11.992 1.736l-1.735.992a.995.995 0 01-1.022 0l-1.735-.992a1 1 0 01-.372-1.364z"
clipRule="evenodd"
/>
</svg>
<span className="font-bold">Home</span>
</a>
</div>
{/* primary nav */}
<div className="hidden md:flex items-center space-x-1">
<a
href="/features"
className="py-5 px-3 text-gray-700 hover:text-gray-900"
>
Features
</a>
<a
href="#"
className="py-5 px-3 text-gray-700 hover:text-gray-900"
>
Pricing
</a>
</div>
</div>
{/* secondary nav */}
<div className="hidden md:flex items-center space-x-1">
<a href="#" className="py-5 px-3">
Login
</a>
<a
href="#"
className="py-2 px-3 bg-yellow-400 hover:bg-yellow-300 text-yellow-900 hover:text-yellow-800 rounded transition duration-300"
>
Signup
</a>
</div>
{/* mobile menu */}
<div className="md:hidden flex items-center">
<button onClick={() => setMenuToggle(!menuToggle)}>
{menuToggle ? (
<XIcon className="w-6 h-6" />
) : (
<MenuIcon className="w-6 h-6" />
)}
</button>
</div>
</div>
</div>
{/* mobile menu items */}
<div className={`${!menuToggle ? "hidden" : ""} md:hidden`}>
<a
href="/features"
className="block py-2 px-4 text-sm hover:bg-gray-200"
>
Features
</a>
<a href="#" className="block py-2 px-4 text-sm hover:bg-gray-200">
Pricing
</a>
<a href="#" className="block py-2 px-4 text-sm hover:bg-gray-200">
Login
</a>
<a href="#" className="block py-2 px-4 text-sm hover:bg-gray-200">
Signup
</a>
</div>
</nav>
);
};
export default Navbar;
Navbar 컴포넌트를 보면 아이콘 관련하여 @heroicons/react/outline 모듈이 보이는데요.
우리가 쓸 메뉴 관련 아이콘 모듈입니다.
이걸 다음과 같이 설치해 주십시오.
npm i @heroicons/react
or
yarn add @heroicons/react
이제 전체적인 모양새가 완성됐으니까 실행시켜 볼까요?
npm run dev
or
yarn dev
브라우저 크기를 줄이니까 모바일 방식으로 나타나네요.
이렇게 전체적으로 반응형 방식의 NextJS + Typescript + Tailwind CSS 템플릿 초안이 완성되었습니다.
여기서 추가로 모바일 메뉴에 있는 Features 파일을 만들어 볼까요?
/pages/features.tsx 파일을 다음과 같이 만듭시다.
/pages/features.tsx
import Head from "next/head";
import Card from "../components/Card";
export default function Features() {
return (
<div>
<Head>
<title>Tailwind CSS Tutorial - Features</title>
<link rel="icon" href="/favicon.ico" />
</Head>
<div className="container px-5 py-10 mx-auto">
{/* Cards Page - Title */}
<div className="text-center mb-12">
<h1 className="text-4xl md:text-6xl text-gray-700 font-semibold">
Tailwind Css Responsive Cards
</h1>
</div>
<div className="flex flex-wrap -m-4">
{/* First Card */}
<Card
imageSrc="https://picsum.photos/id/188/720/400/"
date="Oct 15, 2021"
title="Cities are crowded"
desc="Lorem ipsum dolor sit amet consectetur adipisicing elit. Aperiam
modi, expedita quos doloremque autem ipsum itaque incidunt ipsam
reprehenderit fuga! Dolores quisquam eius cum accusamus?"
viewed="1.2K"
reply={6}
/>
{/* Second Card */}
<Card
imageSrc="https://picsum.photos/id/1016/720/400"
date="Oct 16, 2021"
title="Mountains are alone"
desc="Lorem ipsum dolor sit amet consectetur adipisicing elit. Aperiam
modi, expedita quos doloremque autem ipsum itaque incidunt ipsam
reprehenderit fuga! Dolores quisquam eius cum accusamus?"
viewed="1.1K"
reply={5}
/>
{/* Third Card */}
<Card
imageSrc="https://picsum.photos/id/1011/720/400"
date="Oct 17, 2021"
title="Lakes are silent"
desc="Lorem ipsum dolor sit amet consectetur adipisicing elit. Aperiam
modi, expedita quos doloremque autem ipsum itaque incidunt ipsam
reprehenderit fuga! Dolores quisquam eius cum accusamus?"
viewed="1.0K"
reply={3}
/>
</div>
</div>
</div>
);
}
코드를 보니까 components 폴더에서 Card 컴포넌트를 불러오는데요.
Card 컴포넌트는 지난번에 만들었던 카드형 디자인입니다.
/components/Card.tsx 파일을 다음과 같이 만들어 볼까요?
/components/Card.tsx
import { ArrowRightIcon, EyeIcon, ChatIcon } from "@heroicons/react/outline";
export interface CardProps {
imageSrc: string;
date: string;
title: string;
desc: string;
viewed: string;
reply: number;
}
const Card = (props: CardProps) => {
return (
<div className="p-4 sm:w-1/2 lg:w-1/3">
<div className="h-full border-2 border-gray-200 border-opacity-60 rounded-lg overflow-hidden">
<img
className="lg:h-72 md:h-48 w-full object-cover object-center"
src={props.imageSrc}
alt="blog"
/>
<div className="p-6 hover:bg-indigo-600 hover:text-white transition duration-300 ease-in">
<h2 className="text-base font-medium text-indigo-300 mb-1">
{props.date}
</h2>
<h1 className="text-2xl font-semibold mb-3">{props.title}</h1>
<p className="leading-relaxed mb-3">{props.desc}</p>
<div className="flex items-center flex-wrap ">
<a className="text-indigo-300 inline-flex items-center md:mb-2 lg:mb-0">
Read More
<ArrowRightIcon className="w-4 h-4 ml-2" />
</a>
<span className="text-gray-400 mr-3 inline-flex items-center lg:ml-auto md:ml-0 ml-auto leading-none text-sm pr-3 py-1 border-r-2 border-gray-200">
<EyeIcon className="w-4 h-4 mr-1" />
{props.viewed}
</span>
<span className="text-gray-400 inline-flex items-center leading-none text-sm">
<ChatIcon className="w-4 h-4 mr-1" />
{props.reply}
</span>
</div>
</div>
</div>
</div>
);
};
export default Card;
이제 실행결과를 볼까요?
정말 멋진 카드형 UI가 완성되었네요.
그럼.
'코딩 > React' 카테고리의 다른 글
NextAuth.js로 NextJS앱에 로그인 로직 만들기 2편 (1) | 2021.12.26 |
---|---|
NextAuth.js로 NextJS앱에 로그인 로직 만들기 (3) | 2021.12.26 |
NextJS + Typescript + TailwindCSS 설치 방법 (2) | 2021.12.26 |
TailwindCSS 강좌 3편 - Card 만들기 (6) | 2021.10.16 |
Tailwind CSS 강좌 2편 - 반응형 Sidebar Navbar 만들기 (0) | 2021.10.13 |