はじめに
今回から数回の記事に分けて、個人開発したWebサイトの紹介をしたいと思います!
2024年から本格的にフロントエンドを学び始め、一番最初の成果物になります。
間違った技術の使い方をしている部分等ありましたら、ぜひコメント等でご指摘いただければ幸いです!
成果物
早速ですが、こちらが成果物です!
友人(ラクロス選手)のWebサイトを制作しました!!
プロジェクト名
Tetsuya Yamada Official Home Page
きっかけ
プロジェクト名にもあるTetsuya Yamada(以降、ヤマディー)は、私の高校からの友人です。
ヤマディーは大学卒業後、某メガベンチャーに入社しましたが、
2028年LA五輪のラクロス代表を目指すために、1年未満で退社し、カナダに渡り、ラクロスに専念する道を選びました。
彼の行動力と夢に向かって挑戦する姿は、ソフトウェアエンジニアを目指す自分の行動のきっかけにもなりました。
どうせ何かを作るなら自分の技術力アップだけでなく、誰かのためになるものを作ろうと思い、彼への恩返しも兼ねてWebサイトを作らせてもらうことになりました。
使用技術
言語:TypeScript
フレームワーク:Next.js(App Router), React
スタイル:Tailwind CSS
その他:microCMS、EmailJS
デプロイ:Vercel
サイトの構成
- レイアウト (ヘッダー、フッター)
- Top(トップページ)
- Profile (自己紹介ページ)
- Gallery (ギャラリーページ)
- Blog (ブログページ)
- Contact (問合せページ)
レイアウト
では早速、レイアウト部分の説明からさせていただきます。
レイアウト部分はNext.jsプロジェクトにおいて共通のレイアウトを記載できる「layout.tsx」(app直下)に実装しました。
layout.tsx内でHeaderコンポーネントとFooterコンポーネントを呼び出しています。
import type { Metadata } from "next";
import "./globals.css";
import Header from "./components/layouts/Header/Header";
import Footer from "./components/layouts/Footer";
import "animate.css";
export const metadata: Metadata = {
title: "Yamada Tetsuya Official",
description: "Generated by create next app",
};
export default function RootLayout({
children,
}: Readonly<{
children: React.ReactNode;
}>) {
return (
<html lang="ja">
<body>
<div className=" bg-[url('/images/bg/bg.jpeg')] text-white ">
<Header />
{children}
<Footer />
</div>
</body>
</html>
);
}
ファイル構造は以下の通りです。
HeaderコンポーネントとFooterコンポーネントは、app/components/layoutsに置きました。
app/compenentsフォルダは、プロジェクト全体の共通部品を管理するフォルダです。
ヘッダー
ヘッダーはごく普通のヘッダーです。
タイトルの横にメニューリストがあり、それぞれのページに遷移するようになっております。(Next.jsのLinkタグ使用)
(アイコン画像はNext.jsのImageタグ使用)
またメニューリストはレスポンシブ対応しており、一定の画面幅を下回ると、ハンバーガーメニューに置き換わるように実装しました。
import Image from "next/image";
import Link from "next/link";
import HeaderHamburger from "./HeaderHamburger";
// ヘッダー
function Header() {
return (
<header className="text-black hadow-md">
<div className="container mx-auto px-3 py-4 flex justify-between items-center">
<div className="flex items-center space-x-4">
{/* ロゴ1 */}
<Image
src="/images/top/img11.png"
alt="teamIcon"
width={100}
height={100}
className="hidden lg:block w-24 h-24"
/>
{/* ロゴ2 */}
<Image
src="/images/top/img12.jpeg"
alt="teamIcon"
width={100}
height={100}
className="hidden lg:block w-24 h-24"
/>
{/* メインタイトル */}
<Link
href="/"
className="text-4xl xl:text-6xl font-bold hover:text-yellow-500"
>
Tetsuya Yamada
</Link>
</div>
{/* メニューバー(画面サイズがlg以上の時) */}
<nav className="hidden lg:flex space-x-8">
<Link
href="/"
className="hover:underline underline-offset-8 decoration-yellow-500 text-xl xl:text-3xl font-bold"
>
Top
</Link>
<Link
href="/profile"
className="hover:underline underline-offset-8 decoration-yellow-500 text-xl xl:text-3xl font-bold"
>
Profile
</Link>
<Link
href="/gallery"
className="hover:underline underline-offset-8 decoration-yellow-500 text-xl xl:text-3xl font-bold"
>
Gallery
</Link>
<Link
href="/blog"
className="hover:underline underline-offset-8 decoration-yellow-500 text-xl xl:text-3xl font-bold"
>
Blog
</Link>
<Link
href="/contact"
className="hover:underline underline-offset-8 decoration-yellow-500 text-xl xl:text-3xl font-bold"
>
Contact
</Link>
</nav>
{/* ハンバーガーメニュー(画面サイズがlg以下の時) */}
<HeaderHamburger />
</div>
</header>
);
}
export default Header;
また、ハンバーガーメニューは、useStateを使用し、ハンバーガーアイコンのクリック状態を管理することで、クリックに応じてメニューが開閉するように実装しました。
import Image from "next/image";
import Link from "next/link";
import HeaderHamburger from "./HeaderHamburger";
// ヘッダー
function Header() {
return (
<header className="text-black hadow-md">
<div className="container mx-auto px-3 py-4 flex justify-between items-center">
<div className="flex items-center space-x-4">
{/* ロゴ1 */}
<Image
src="/images/top/img11.png"
alt="teamIcon"
width={100}
height={100}
className="hidden lg:block w-24 h-24"
/>
{/* ロゴ2 */}
<Image
src="/images/top/img12.jpeg"
alt="teamIcon"
width={100}
height={100}
className="hidden lg:block w-24 h-24"
/>
{/* メインタイトル */}
<Link
href="/"
className="text-4xl xl:text-6xl font-bold hover:text-yellow-500"
>
Tetsuya Yamada
</Link>
</div>
{/* メニューバー(画面サイズがlg以上の時) */}
<nav className="hidden lg:flex space-x-8">
<Link
href="/"
className="hover:underline underline-offset-8 decoration-yellow-500 text-xl xl:text-3xl font-bold"
>
Top
</Link>
<Link
href="/profile"
className="hover:underline underline-offset-8 decoration-yellow-500 text-xl xl:text-3xl font-bold"
>
Profile
</Link>
<Link
href="/gallery"
className="hover:underline underline-offset-8 decoration-yellow-500 text-xl xl:text-3xl font-bold"
>
Gallery
</Link>
<Link
href="/blog"
className="hover:underline underline-offset-8 decoration-yellow-500 text-xl xl:text-3xl font-bold"
>
Blog
</Link>
<Link
href="/contact"
className="hover:underline underline-offset-8 decoration-yellow-500 text-xl xl:text-3xl font-bold"
>
Contact
</Link>
</nav>
{/* ハンバーガーメニュー(画面サイズがlg以下の時) */}
<HeaderHamburger />
</div>
</header>
);
}
export default Header;
フッター
次にフッターの説明です。
フッターには、メニューと各 SNSへのリンクを記載しました。
特記するような技術は使用していませんので、コードの掲載は割愛します。
最後に
最後までお読みいただきありがとうございました!
#1はレイアウト部分の説明までとさせていただきます。
#2では、共通機能(プロジェクト全体で使用しているアニメーション機能の実装)について紹介予定です。
ありがとうございました!!!