2025-1-13
Reactでポートフォリオサイトを作成する 🚀(2)
ReactNext.jsポートフォリオ
はじめに
「自分にとって新しい技術をインプットしたい」と「長く残るアウトプットを作りたい」という思いから、Reactを使ってポートフォリオサイトの作成に挑戦してみることにしました。
この記事を含め、複数回に分けて作成過程を記録していきます。ここまでの記事は以下です。
今回は以下の内容についてご紹介します。
- 【ヘッダー】TOP画面とそれ以外の画面で表示を分ける
- 【プロフィール画面】プロフィールを記載する箱を作成
- 【プロフィール画面】ページタイトルなどをコンポーネント化
【ヘッダー】TOP画面とそれ以外の画面で表示を分ける
以下記事を参考に、ホーム画面以外の時はホーム画面へのリンクを左側に表示させるようにする
usePathnameを利用する時は`"use client"を追加してクライアントコンポーネントにする必要がある
Header.tsx'use client' import Link from 'next/link' import { usePathname } from 'next/navigation' const Header = () => { const pathname = usePathname() const isMainPage = pathname === '/' return ( <header className="pt-5 pl-5 mb-20"> <div className="container mx-auto flex flex-wrap p-5 flex-col md:flex-row items-center"> {!isMainPage && ( <a href="/" className="flex font-mobo font-medium items-center mb-4 md:mb-0" > <span className="ml-3 text-xl">Motoshi Furugen</span> </a> )} <nav className="md:ml-auto flex flex-wrap items-center text-base justify-center font-mobo"> <Link className="mr-10 hover:opacity-50" href="/profile"> プロフィール </Link> <Link className="mr-10 hover:opacity-50" href="#"> 開発ブログ </Link> <Link className="mr-10 hover:opacity-50" href="#"> 実績 </Link> <Link className="mr-10 hover:opacity-50" href="#"> コンタクト </Link> <Link className="mr-10 hover:opacity-50" href="#"> ソースコード </Link> </nav> </div> </header> ) } export default Header
ヘッダーを上部に固定させる。headerに"fixed"を追加して、main要素にpadding-topを追加する。
Header.txs<header className="fixed top-0 left-0 w-full z-50 py-5 pl-5 mb-20 bg-bg-main">
layout.tsx<html lang="en"> <body className={inter.className}> <Header /> <main className="pt-40">{children}</main> </body> </html>
Githubへのリンクを設置する
Header.tsx<Link className="mr-10 hover:bg-gray" href="https://github.com/motoshifurugen/my_site" target="_blank" rel="noopener noreferrer" > <div className="flex items-center border border-gray-300 rounded px-3 py-1"> <FontAwesomeIcon icon={faGithub} className="mr-2" /> ソースコード </div> </Link>
【プロフィール画面】画面作成
MainMessege
コンポーネント内に入れていたプロフィールへのリンク部分はpage.tsx
に一旦移し、メインメッセージをプロフィール画面でも使うことにする。/pofile/page.tsximport MainMessage from '../components/MainMessage' export default function Page() { return ( <section className="profile px-20"> <div className="flex justify-center h-screen"> <MainMessage /> </div> </section> ) }
プロフィール欄を用意して、左に説明・右に写真を配置する。
/pofile/page.tsx<section className="profile px-20"> <h1 className="text-4xl font-bold">プロフィール</h1> <div className="flex justify-center"> <MainMessage /> </div> <div> <h2 className="text-3xl font-bold">経歴</h2> <div className="flex p-10"> <p className="flex w-1/2 text-lg leading-loose items-center"> <p className="mr-6 text-right"> 1998年 <br /> 2017年 <br /> 2020年 <br /> 2021年 <br /> 2023年 <br /> 現在 </p> <p> 沖縄に生まれる <br /> 高校卒業後、広島大学理学部物理学科へ進学する <br /> 大学休学中にプログラミングを始める <br /> 長期インターンでWebエンジニアを経験する <br /> 大学卒業後、エンジニアとして就職する <br /> フロントエンドエンジニアとして奮闘中 </p> </p> <div className="w-1/2 flex justify-end"> <Image src="/images/etsushi.jpg" alt="profile img 01" width={500} height={500} /> </div> </div> </div> </section>
プロフィールで使用した3つの紹介(経歴・興味・趣味)の記述部分をコンポーネント化する。
Card.tsx// components/Card.tsx import { ReactNode } from "react"; import Image from "next/image"; interface CardProps { title: string; content: ReactNode; imageSrc: string; imageAlt: string; } const Card: React.FC<CardProps> = ({ title, content, imageSrc, imageAlt }) => { return ( <div className="card"> <h2 className="text-3xl font-bold">{title}</h2> <div className="flex p-10 font-open-sans"> <div className="flex w-1/2 text-lg leading-loose items-center"> {content} </div> <div className="w-1/2 flex justify-end"> <Image src={imageSrc} alt={imageAlt} width={500} height={500} /> </div> </div> </div> ); }; export default Card;
profile/page.tsx
にて、Card
コンポーネントを使用する。profile/page.tsx<Card title="経歴" content={ <> <p className="mr-6 text-right"> 1998年<br /> 2017年<br /> 2020年<br /> 2021年<br /> 2023年<br /> 現在 </p> <p> 沖縄に生まれる<br /> 高校卒業後、広島大学理学部物理学科へ進学する<br /> 大学休学中にプログラミングを始める<br /> 長期インターンでWebエンジニアを経験する<br /> 大学卒業後、エンジニアとして就職する<br /> フロントエンドエンジニアとして奮闘中 </p> </> } imageSrc="/images/profile_01.jpg" imageAlt="profile img 01" /> <Card title="興味" content={ <> <p> 物理学が目に見えない自然の法則を解き明かすように、<br /> データという見えない情報を扱うことに楽しさを感じています。<br /> 最近はバックエンドやネットワーク分野に興味があり、<br /> 今年はネットワークスペシャリストの資格に挑戦します。<br /> 心が強い方ではないので、メンタルヘルスへの関心も大切にしています。 </p> </> } imageSrc="/images/profile_02.png" imageAlt="profile img 02" /> <Card title="趣味" content={ <> <p> エイサー(沖縄の伝統芸能) ・ 読書(ビジネス書中心) ・<br /> 散歩 ・ 短歌 ・ ギター(アコギ) ・ ドライブ ・ ボウリング <br /> and more<br /> </p> </> } imageSrc="/images/profile_03.jpg" imageAlt="profile img 03" />
【プロフィール画面】ページタイトルなどをコンポーネント化
画面説明部分をコンポーネントに切り分ける
PageFace.tsximport React from 'react'; interface PageFaceProps { title: string; subtitle: string; mainMessage: React.ReactNode; } const PageFace: React.FC<PageFaceProps> = ({ title, subtitle, mainMessage }) => { return ( <div className="flex mb-24"> <div className="w-1/2"> <h1 className="text-4xl font-bold">{title}</h1> <h2 className="text-2xl font-bold mt-5">{subtitle}</h2> </div> <div className="flex justify-left w-1/2"> {mainMessage} </div> </div> ); }; export default PageFace;
/profile/page.tsx<PageFace title="プロフィール" subtitle="古堅基史(Furugen Motoshi)" mainMessage={<MainMessage />} />
PageFaceコンポーネントの下部に直線を表示させる。(アニメーション付き)
PageFace.tsx<div ref={lineRef} className="h-0.5 opacity-50 bg-font-main transition-all duration-1000 ease-in-out w-0 mt-4 mb-24" ></div>
to be continued...
次回はスキル・実績画面の作成を行います。