皆さんこんにちは。
前回に引き続き、チュートリアルの解説を行います。この記事では、初学者の方向けに最新の、NextJSを使用したチュートリアルとしてポートフォリオサイトの作成について解説しています。
今回は、第4回でWorksページの作成を初学者の方向けにわかりやすく解説していきます。
本記事はシリーズとなっております。
もし、概要ページや前回のページをご覧になってない方は、ぜひ下記に示す解説記事を順番にご覧いただければ幸いです。
ポートフォリオ作成 全編
- ポートフォリオ作成 概要編(No.1)
- ポートフォリオ作成 Topページ編(No.2)
- ポートフォリオ作成 Aboutページ編(No.3)
- ポートフォリオ作成 Skillsページ編(No.4)
- ポートフォリオ作成 Worksページ編(No.5) <<< 今回の記事
- ポートフォリオ作成 Hobbysページ編(No.6)
ポートフォリオ作成 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ページについて解説いたしますので、ぜひ御覧ください。
お疲れさまでした。