NextJS チュートリアル ポートフォリオサイト作成 Worksページ編 わかりやすく解説

React
この記事は約30分で読めます。

皆さんこんにちは。
前回に引き続き、チュートリアルの解説を行います。この記事では、初学者の方向けに最新の、NextJSを使用したチュートリアルとしてポートフォリオサイトの作成について解説しています。
今回は、第4回でWorksページの作成を初学者の方向けにわかりやすく解説していきます。

本記事はシリーズとなっております。
もし、概要ページや前回のページをご覧になってない方は、ぜひ下記に示す解説記事を順番にご覧いただければ幸いです。

ポートフォリオ作成 全編

ポートフォリオ作成 Worksページ解説

では解説を始めていきます。
前回までの解説を終えた時点で、現在のディレクトリはこの様になっています。

$ tree ./pages/components 

pages/components
├── modules
│   ├── skillCard.tsx
└── organisms
    ├── about.tsx
    ├── footer.tsx
    ├── header.tsx
    ├── skills.tsx
    ├── top.tsx



// 略

ここで、./app/pages/components/organisms ディレクトリ内に新たに works.tsx ファイルを作成してください。
そして、作成したファイルを下記のように編集してください。

import React from "react";
import Header from "./header";
import Footer from "./footer";
import WorksCard from "../modules/workCard";
import { worksCardContents } from "../../api/variable";
import { workTypes } from "../../api/type";


const Works:React.VFC = () => {

    return(
        <>
            <Header />
            <div className="min-h-screen flex justify-center items-center flex-wrap md:mx-3 mx-1">
                {worksCardContents.map((contents:workTypes) => {
                    return (
                        <WorksCard contents={contents} key={contents.id}/>
                    );
                })}
            </div>
            <Footer />
        </>
    );
}

export default Works;

この Worksページのデザインは先日解説した、Skillsページと同じような形式にしております。works.tsx はページの本体となっています。

ポートフォリオ作成 WorkCard解説

./app/pages/components/modules/ ディレクトリ内に workCard.tsx ファイルを作成し、下記のように編集してください。

import React from "react";
import "devicon";
import GitHub from "@mui/icons-material/GitHub";
import {workTypes,worktechTypes} from '../../api/type';
const NoImage = require("../../../public/no_image_logo.png").default;

const WorksCard:React.VFC = ({contents}:{contents:workTypes}) =>{

    const onClickGit = (url:string):void => {
        window.open(url);
    }

    return (
        <div className="p-5">
            <div className="bg-gradient-to-r from-blue-500 to-blue-300 w-11/12 md:w-148 md:h-120 m-auto rounded-xl shadow-2xl transform hover:scale-110 transition-transform">
                    {contents.image.src ? (
                        <div className="flex justify-center m-1 p-3 h-60">
                            <img src={contents.image.src} alt={`img${contents.title}`}/>
                        </div>
                    ):(
                        <div className="flex justify-center m-1 p-3 h-60">
                            <img src={NoImage.src} alt="img"/>
                        </div>
                    )}
                <div className="m-0 p-0 border-t-2"></div>
                <div className="m-3">
                    <div className="mx-1 my-1 flex">
                        <p className="mx-1 text-2xl sm:text-4xl">{contents.title}</p>
                        <GitHub
                            className="my-1 mx-4 p-0 cursor-pointer"
                            sx={{fontSize:33}}
                            onClick={()=> onClickGit(contents.repository)}
                        />
                    </div>
                    <div className="mx-1 my-2 p-0 flex flex-wrap">
                        <p className="mx-1 p-0 text-lg">{contents.description}</p>
                    </div>
                    <span className="mx-2 my-3 py-2 flex flex-wrap">
                        {contents.useTech.map((tech:worktechTypes) => {
                            return(
                                <span className={`${tech.mark} text-3xl sm:text-5xl mx-1 my-1 p-1`} key={tech.id}></span>
                            );
                        })}
                    </span>
                </div>
            </div>
        </div>
    );
};

export default WorksCard;

workCard.tsx がWorksページに表示するカードUIとなっています。ただ、skillCardより大きく、カードUIの中のデザインも少し異なっております。

ポートフォリオ作成 変数・型解説

最後に、Worksページで使う変数と型について解説します。
./app/pages/api/ ディレクトリ内にある type.ts ファイルと variable.ts ファイルをそれぞれ次のように編集してください。

//ここから新しく追加した部分
export type worktechTypes = {
    id: number,
    mark: string
};

export type workTypes = {
    id: number,
    image: any,
    title: string,
    description: string,
    useTech:{
        id: number,
        mark: string,
    }[],
    repository:string
};
//ここまで

export type skillTypes = {
    id: number
    image: any
    title: string
    stars: number
    description: string
    color:string
};

export type skillCardCol = {
    red: string;
    blue: string;
    indigo: string;
    green: string;
}

export type topImage = {
    id: number;
    image: any;
}

export type urls = {
    urlBlog:string;
    urlGit:string;
    urlTwitter:string;
}

import {workTypes,skillTypes,importImage,hobbysTypes,hobbysdescType,worktechTypes,topImage,skillCardCol, urls} from './type';

export const webTitle: string = "Jiro's Portrait Site";

export const url: urls= {
    urlBlog:"https://www.s-gakuenblog.com/",
    urlGit:"https://github.com/POD-azlamarhyu",
    urlTwitter:"https://twitter.com/Inc_capitalist",
};

export const copyright: string = "shell varng 2022";

export const topImages:topImage[] = [
    {   
        id:0,
        image:require("../../public/topimage1.png").default,
    },
    {   
        id:1,
        image:require("../../public/topimage2.png").default,
    },
    {   
        id:2,
        image:require("../../public/topimage3.png").default,
    },
    {   
        id:3,
        image:require("../../public/topimage4.png").default,
    }
];
//ここからが新しい編集部分
export const worksCardContents:workTypes[] = [
    {
        id: 0,
        image: require("../../public/portrait_e.png").default,
        title: "Portrait Site",
        description: "紹介サイト作成したいと思ったのでNextの練習も兼ねて作成しました.",
        useTech: [
            {
                id:0,
                mark: "devicon-javascript-plain colored",
            },
            {
                id: 1,
                mark:"devicon-nextjs-plain-wordmark colored", 
            },
            {
                id:2,
                mark:"devicon-materialui-plain colored",
            },
            {
                id:3,
                mark:"devicon-tailwindcss-plain colored",
            }
        ],
        repository:"https://github.com/POD-azlamarhyu/portraitSite",
    },
    {
        id: 1,
        image: require("../../public/twitter_clone.png").default,
        title: "Twitter Clone SPA",
        description: "TwitterのクローンをDjangoRF,postgreSQL,NextJS,Dockerを用いてSPAとして作成.",
        useTech: [
            {
                id:0,
                mark: "devicon-python-plain colored",
            },
            {
                id: 1,
                mark:"devicon-django-plain-wordmark colored",
            },
            {
                id:2,
                mark:"devicon-nextjs-original-wordmark colored",
            },
            {
                id:3,
                mark:"devicon-typescript-plain colored"
            },
            {
                id:4,
                mark:"devicon-materialui-plain colored"
            },
            {
                id:5,
                mark:"devicon-tailwindcss-plain colored",
            },
            {
                id:6,
                mark:'devicon-docker-plain colored',
            },
            {
                id:7,
                mark:'devicon-postgresql-plain colored',
            }
        ],
        repository:"https://github.com/POD-azlamarhyu/Twitter_clone_SPA"
    },
    {
        id: 1,
        image: require("../../public/toweet_e.png").default,
        title: "Django Tweet App",
        description: "twitterのクローンをDjangoの練習も兼ねて作成しました.",
        useTech: [
            {
                id:0,
                mark: "devicon-python-plain colored",
            },
            {
                id: 1,
                mark:"devicon-django-plain-wordmark colored",
            },
            {
                id:2,
                mark:"devicon-javascript-plain colored",
            },
            {
                id:3,
                mark:"devicon-bootstrap-plain colored"
            }
        ],
        repository:"https://github.com/POD-azlamarhyu/Twitter_clone_with_Django"
    },
    {
        id: 2,
        image:'',
        title: "Stock data scraiping",
        description: "株のデータを収集するために作成しました.",
        useTech: [
            {
                id:0,
                mark: "devicon-python-plain colored",
            },
            {
                id: 1,
                mark:"devicon-numpy-original colored"
            }
        ],
        repository: "https://github.com/POD-azlamarhyu/getStockdata",
    },
    {
        id: 3,
        image: require("../../public/watch_e.png").default,
        title: "JS Web Watch",
        description: "DOMの理解のため,WEB時計を作成しました.",
        useTech: [
            {
                id:0,
                mark: "devicon-javascript-plain colored",
            }
            
        ],
        repository: "https://github.com/POD-azlamarhyu/Javascript_light_watch",
    },
    {
        id: 4,
        image: require("../../public/unity_e.png").default,
        title: "Unity Ball Rolling Game",
        description: "Unityを使った3Dコースゲームです.",
        useTech: [
            
            {
                id:0,
                mark: "devicon-csharp-plain colored",
            },
            {
                id: 1,
                mark:"devicon-unity-original colored"
            },
        ],
        repository: "https://github.com/POD-azlamarhyu/unity_tutorial_scrollegame",
    },
    {
        id: 5,
        image: require("../../public/portrait_e.png").default,
        title: "Portrait Site TypeScript ver.",
        description: "上記自己紹介サイトのTypeScript版です. ",
        useTech: [
            {
                id:0,
                mark: "devicon-typescript-plain colored",
            },
            {
                id: 1,
                mark:"devicon-nextjs-plain-wordmark colored", 
            },
            {
                id:2,
                mark:"devicon-materialui-plain colored",
            },
            {
                id:3,
                mark:"devicon-tailwindcss-plain colored",
            }
        ],
        repository:"https://github.com/POD-azlamarhyu/portraitSite_ts",
    },
];
//ここまで

const skillCardCol:skillCardCol = {
    red:`bg-gradient-to-r from-fuchsia-500 to-fuchsia-200 w-full md:w-132 md:h-80 m-auto rounded-xl shadow-2xl transform hover:scale-110 transition-transform`,
    blue:`bg-gradient-to-r from-blue-500 to-blue-200 md:w-132 w-full md:h-80 m-auto rounded-xl shadow-2xl transform hover:scale-110 transition-transform`,
    indigo:`bg-gradient-to-r from-indigo-500 to-indigo-200 w-full md:w-132 md:h-80 m-auto rounded-xl shadow-2xl transform hover:scale-110 transition-transform`,
    green:`bg-gradient-to-r from-gray-500 to-gray-200 w-full md:w-132 md:h-80 m-auto rounded-xl shadow-2xl transform hover:scale-110 transition-transform`
}

export const skillCardContents:skillTypes[] = [
    {
        id: 0,
        image: "devicon-python-plain colored",
        title: "Python 3",
        stars: 4,
        description: "最も触れている言語の一つです.",
        color: skillCardCol.blue,
    },
    {
        id: 1,
        image: "devicon-c-plain colored",
        title: "C lang",
        stars: 1,
        description: "ポインターでメモリ管理の勉強を行うため,使ってました.",
        color: skillCardCol.blue,
    },
    {
        id: 2,
        image: "devicon-csharp-plain colored",
        title: "C#",
        stars: 2,
        description: "主にWindows開発とUnityでのゲーム開発で使っています.FPS作りたい.",
        color: skillCardCol.blue,
    },
    {
        id: 3,
        image: "devicon-javascript-plain colored",
        title: "JavaScript",
        stars: 4,
        description: "フロントエンドの開発で主に使っています.",
        color: skillCardCol.red,
    },
    {
        id: 4,
        image: "devicon-typescript-plain colored",
        title: "TypeScript",
        stars: 3,
        description: "JSと並行して型付になれるため勉強していきます.",
        color: skillCardCol.red,
    },
    {
        id: 5,
        image: "devicon-java-plain colored",
        title: "Java",
        stars: 2,
        description: "主に研究でのAndroid開発に使っています.",
        color: skillCardCol.blue,
    },
    {
        id:6,
        image: "devicon-ruby-plain colored",
        title: "Ruby",
        stars: 3,
        description: "大学の授業のほか,サーバサイド言語の習得のため学んでいます.",
        color: skillCardCol.blue,
    },

    {
        id: 7,
        image: "devicon-android-plain colored",
        title: "Android",
        stars: 2,
        description: "研究のほか,個人開発でアプリの方面も触っています.",
        color: skillCardCol.green,
    },
    {
        id: 8,
        image: "devicon-react-original colored",
        title: "React JS",
        stars: 4,
        description: "フレームワークの中で最も触っています.",
        color: skillCardCol.green
    },
    {
        id: 9,
        image: "devicon-nextjs-plain-wordmark colored",
        title: "Next JS",
        stars: 4,
        description: "フレームワークの中で最も触っています.SSGやSSRをするためにやっています.",
        color: skillCardCol.green,
    },
    {
        id: 10,
        image: "devicon-django-plain-wordmark colored",
        title: "Django",
        stars: 4,
        description: "サーバサイドのフレームワークとして使っています.Pythonが最もなれているのでこれを選びました.",
        color: skillCardCol.green,
    },
    {
        id:11,
        image: "devicon-rails-plain colored",
        title: "Ruby on Rails",
        stars: 1,
        description: "日本はRailsが実務で使われていることが多いので勉強しています.",
        color :skillCardCol.green,
    },
    {
        id: 12,
        image: "devicon-unity-original colored",
        title: "Unity",
        stars: 2,
        description: "ゲームエンジンとして使っています.",
        color: skillCardCol.green,
    },
    {
        id:13,
        image: "devicon-postgresql-plain colored",
        title: "PostgreSQL",
        stars: 4,
        description: "データベースでOSSなので使っています.SQLは実務でかなり鍛えられました.",
        color: skillCardCol.indigo,
    },
    {
        id: 14,
        image: "devicon-git-plain colored",
        title: "Git",
        stars: 4,
        description: "ソースコード管理に使ってます.",
        color: skillCardCol.indigo,
    },
    {
        id:15,
        image: "devicon-github-original colored",
        title: "GitHub",
        stars: 4,
        description: "Gitのウェブサービスとして使ってます.",
        color: skillCardCol.indigo,
    },
    {
        id:16,
        image: "devicon-tensorflow-original colored",
        title: "Tensorflow",
        stars: 3,
        description: "機械学習で使っています.",
        color: skillCardCol.blue,
    },
    {
        id:17,
        image: "devicon-tailwindcss-plain colored",
        title: "Tailwind CSS",
        stars: 4,
        description: "フロントエンドで重宝しています.かなりの頻度で使っていますので結構覚えました.",
        color: skillCardCol.red,
    },
    {
        id:18,
        image: "devicon-bulma-plain colored",
        title: "Bulma",
        stars: 2,
        description: "フロントエンドでサブのCSSフレームワークとして使ってます.最近はあまり使ってません.",
        color: skillCardCol.red,
    },
    {
        id:19,
        image: "devicon-sass-original colored",
        title: "SASS (SCSS)",
        stars: 2,
        description: "CSSをより効率的に書くために使ってます.",
        color: skillCardCol.red,
    },
];

前回解説した内容と同様に、今回はSkillsページとデザインは似ているので、同様の設計です。Worksページで表示する内容とその型を宣言しています。宣言はそれぞれ、別ファイルで行います。

Worksページにこれと同じ内容を宣言することも可能です。しかし、とてつもなく長いコードになってしまいます。なので、今回はファイルごとに区切ることにしました。
画像に関してましては、皆様のお好きなものを選び、publicディレクトリ内に格納してください。

ポートフォリオ作成 実行

ここまできましたら、実際に実行して確認してみましょう。

$ npm run dev

前回で解説したように、上記のコマンドを実行して、ローカルホストの3000ポートにアクセスしましょう。ヘッダーのメニューからSkillsページへ飛んでみましょう。そうすると、先程作成したページが表示されると思います。

まとめ

では本日のまとめに入ります。
本日は初学者の方向けにポートフォリオ作成について解説いたしました。

次回は最終回、Hobbysページについて解説いたしますので、ぜひ御覧ください。
お疲れさまでした。

タイトルとURLをコピーしました