1 連絡・概要
1.1 課題3
詳細は、前回の講義資料を確認してください。
README.mdの記述がポイントになります。説明をよく読むようにしてください。- 学年末なので特に期限に注意してください (提出後にアプリのバージョンアップを継続することは問題ありません)。
開発例 (高専テクノゼミ 実践教育プログラム 2025春 「Web開発」から抜粋)。
1.2 小テスト❺
次回の授業 (試験返却期間) では「小テスト❺」を実施します。範囲は全体になります。「定着確認」として示している以外からも出題します (総合的な知識の定着を確認します)。
1.3 ゲーム\(\times\)IT業界フォーラム
業界研究&インターンシップ 「ゲーム\(\times\)IT業界フォーラム」の案内です。詳細はこちらから確認してください。
2/13 (木) と 14 (金) の 10:40-18:00 にオンライン形式で実施されます (要・事前登録)。
(1)「業界」や「会社」「仕事」について話が聞ける!
ゲーム・IT業界を代表する企業や急成長している企業から会社のことや仕事の話を聞き、理解を深められます。(2)このイベントでしか得られないインターンシップ情報をGETできる!
就業体験の場であるインターンシップを行う企業から「実施内容」「スケジュール」「選考方法」などについて直接情報を得られます。(対応は企業により異なります)
1.4 高専テクノゼミ 1
高専テクノゼミ「実践教育プログラム2025春」のエントリが開始されています。
実践教育プログラム ❶ AI 入門講座!
長期休暇を利用して、Kaggleのデータ分析コンペに挑戦します。
プログラミング完全初心者でも参加大歓迎ですので、「AIって興味あるけどなかなか自分だと勉強できない」という方から、「もっとAI活用で遊びたい」という方までおすすめのプログラムです。学生の参加費は完全無料ですので、ぜひ参加してください!
実践教育プログラム ❷ まちづくりへのデータ活用!
全国にキャンパスが分散している高専の特性を活かして、高校生や大学生も含めたチームで自分たちの街についてデータを用いて考えます。東京大学特任准教授の吉村先生監修の実践的なプログラムにぜひ挑戦してください!
1.5 高専テクノゼミ 2
高専テクノゼミ「春季講習(高専生)」のエントリが開始されています。大学編入学のための補習講座 になります。必要に応じて利用ください。詳細はこちらから確認してください。なお、1年後の今頃から勉強を開始するようでは、完全に手遅れなので注意してください。
勉強したい科目が選択できるようです : 基礎数学、微分積分1、微分積分2、線形代数、確率・統計、 確率・統計
受験勉強と進学のモチベーションをキープするためのコミュニティや習慣、情報共有や相談のコネクションづくりにも活用できると思います (むしろ、その意味で活用するほうがよいと思います)。
インスタ @unikosen
1.6 Next.js のバージョンに関する注意
完全新規でオリジナルアプリを開発する場合は、環境構築の際に Next.js のバージョン に注意してください。
最新バージョンである「15」を使用すると、この授業で示したサンプルコードでは動作しない場合があります。特に、バックエンドにおける
/api/posts/[id] のような ルートパラメータ
の取得方法が非同期に変わっているので注意してください。このあたりの対応に不安がある場合は、第06回講義で解説したように、バージョン「14」を使用してください。
1.7 schema.prisma のシンタックスハイライト
VSCode の拡張機能として Prisma (識別子 prisma.prisma) をインストールすると
schema.prisma がシンタックスハイライトされるようになります。
2 トースト通知機能
react-hot-toastというライブラリを使用して トースト通知 の機能を実装したサンプルを紹介します。
2.1 実装の手順
VSCodeのターミナル (Ctrl+J)
から以下のコマンドを実行してライブラリをインストールします。
npm i react-hot-toast
サンプルコードを以下に示します。
"use client";
import toast, { Toaster } from "react-hot-toast";
import { twMerge } from "tailwind-merge";
const Page: React.FC = () => {
const buttonStyle = twMerge(
"rounded-md px-3 py-1 ",
"font-bold text-white",
"bg-indigo-500 hover:bg-indigo-700"
);
const successNotify = (msg: string) => toast.success(msg);
const errorNotify = (msg: string) => toast.error(msg);
return (
<main>
<div className="mb-2 text-2xl font-bold ">トースト通知</div>
<div className="flex gap-x-3">
<button
className={buttonStyle}
onClick={() => successNotify("成功スタイルのトースト通知")}
>
success
</button>
<button
className={buttonStyle}
onClick={() => errorNotify("エラースタイルのトースト通知")}
>
error
</button>
</div>
<Toaster position="top-center" />
</main>
);
};
export default Page;トーストの「表示位置」や「外観 (アイコンや背景色)」、表示されてから自動消去されるまでの時間 などもカスタマイズ可能です。詳細については公式ドキュメントを参照してください。
3 モーダル表示
react-modalというライブラリを使用して モーダルウィンドウ を実装したサンプルを紹介します。
3.1 実装の手順
VSCodeのターミナルからライブラリをインストールします。react-modal は
TypeScriptの型定義が同梱されていないため、別途 @types
パッケージとして提供されている型定義ファイル
をインストールする必要があります(型定義ファイルは開発時のみ必要なため、devDependencies として
-D オプションを付けてインストールします)。
npm i react-modal
npm i -D @types/react-modal
まずは、モーダルウィンドウの外観を定義するコンポーネントを実装します。
"use client";
import React, { ReactNode } from "react";
import ReactModal from "react-modal";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faXmark } from "@fortawesome/free-solid-svg-icons";
interface Props {
isOpen: boolean;
onClose: () => void;
children: ReactNode;
}
export const Modal: React.FC<Props> = (props) => {
const { isOpen, onClose, children } = props;
return (
<ReactModal
isOpen={isOpen}
onRequestClose={onClose}
contentLabel="Modal"
closeTimeoutMS={300}
ariaHideApp={false}
className="relative z-50 h-screen w-screen bg-black/50"
overlayClassName="fixed inset-0 bg-black_main flex items-center justify-center z-50"
>
<div className="flex size-full flex-col items-center justify-center">
<div className="flex w-full justify-end md:w-[640px]">
<button className="px-3 py-0.5 md:px-1" onClick={onClose}>
<FontAwesomeIcon
className="cursor-pointer text-2xl text-white hover:text-gray-300"
icon={faXmark}
/>
</button>
</div>
<div className="w-full bg-white p-3 md:w-[640px] md:rounded-md">
{children}
</div>
</div>
</ReactModal>
);
};つづいて、上記で定義した Modal コンポーネントを呼び出します。
"use client";
import { useState } from "react";
import { twMerge } from "tailwind-merge";
import { Modal } from "./_components/Modal"; // コンポーネントのインポート
const Page: React.FC = () => {
const [isModalOpen, setIsModalOpen] = useState(false);
return (
<main>
<div className="mb-2 text-2xl font-bold">モーダル</div>
<div className="flex gap-x-3">
<button
className={twMerge(
"rounded-md px-3 py-1",
"font-bold text-white",
"bg-indigo-500 hover:bg-indigo-700"
)}
onClick={() => setIsModalOpen(true)}
>
モーダルウィンドウを開く
</button>
</div>
<Modal isOpen={isModalOpen} onClose={() => setIsModalOpen(false)}>
{/* モーダル内に表示するコンテンツを <Modal>...</Modal> の子要素として与える */}
<div>
<div className="text-xl font-bold">徒然草</div>
<div>
<p>
つれづれなるままに、日暮らし硯に向かひて、心にうつりゆくよしなしごとを、
そこはかとなく書きつくれば、あやしうこそものぐるほしけれ。
</p>
</div>
</div>
</Modal>
</main>
);
};
export default Page;4 shadcn/ui
shadcn/uiという UIコンポーネントコレクション を利用するサンプルを示します。以下に示すように「スイッチ」や「カレンダ」「アコーディオン」「ドロップダウンメニュー」など 統一感のある各種UIコンポーネントを提供 してくれます。
利用可能なコンポーネントの一覧はこちらから確認することができます。
4.1 実装の手順
shadcn/ui のセットアップは一般的なライブラリとはやや異なります。まずは、VSCodeのターミナルから、以下のコマンドを実行してください。
npx shadcn@latest init
いくつかの質問が表示されるので、以下のように回答します。
Which style would you like to use? » New York
Which color would you like to use as the base color? » Slate
Would you like to use CSS variables for theming? … yes
(実行例)
Need to install the following packages:
shadcn@2.3.0
Ok to proceed? (y) y
✔ Preflight checks.
✔ Verifying framework. Found Next.js.
✔ Validating Tailwind CSS.
✔ Validating import alias.
√ Which style would you like to use? » New York
√ Which color would you like to use as the base color? » Slate
√ Would you like to use CSS variables for theming? ... yes
✔ Writing components.json.
✔ Checking registry.
✔ Updating tailwind.config.ts
✔ Updating src\app\globals.css
✔ Installing dependencies.
✔ Created 1 file:
- src\lib\utils.ts
Success! Project initialization completed.
You may now add components.
つづいて、必要なUIを選んでインストールします。例えばスイッチUIを追加する場合は、以下のようにコマンドを実行します。
npx shadcn@latest add switch
また、カレンダUIを追加する場合は、以下のようにコマンドを実行します。
npx shadcn@latest add calendar
上記によってインストールされたライブラリは /src/components/ui/
にインストールされます。
実装例を以下に示します。
サンプルコードを以下に示します。
"use client";
import { useState } from "react";
import dayjs from "dayjs";
import { Switch } from "@/components/ui/switch";
import { Calendar } from "@/components/ui/calendar";
const Page: React.FC = () => {
// スイッチ関連
const [isDebugMode, setIsDebugMode] = useState(false);
const handleIsDebugModeChange = (checked: boolean) => {
if (checked) {
console.log("Debug mode is enabled.");
} else {
console.log("Debug mode is disabled.");
}
setIsDebugMode(checked);
};
// カレンダ関連
const dtFmt = "YYYY年MM月DD日が選択されました。";
const [date, setDate] = useState<Date | undefined>();
const [msg, setMsg] = useState<string>("日付を選択してください。");
const handleDateChange = (date: Date | undefined) => {
if (date === undefined) {
setMsg("日付を選択してください。");
return;
}
setMsg(dayjs(date).format(dtFmt));
setDate(date);
};
return (
<main>
<div className="mb-4 text-2xl font-bold">shadcn/ui</div>
<div className="flex flex-col gap-y-4">
<div className="flex items-center gap-x-3">
<Switch
id="debug-mode"
checked={isDebugMode}
onCheckedChange={handleIsDebugModeChange}
/>
<label htmlFor="debug-mode" className="cursor-pointer">
デバッグモード
</label>
</div>
<div className="">
<Calendar
mode="single"
selected={date}
onSelect={handleDateChange}
className="inline-block rounded-md border"
/>
</div>
<div>{msg}</div>
</div>
</main>
);
};
export default Page;5 Lucide React Icon
shadcn/ui をインストールすると、それに関連する関係で lucide-react
という「アイコンセットを提供するライブラリ」もインストールされます。このライブラリはアイコンは、既に紹介済みのFontAwesomeと併用することも可能です。
Lucide React が提供するアイコンの一覧 (2025/01/29時点で1548個) はこちらから検索・確認できます。
以下に、実装例を示します。
"use client";
import { Camera, ThumbsUp, Squirrel, Settings } from "lucide-react";
const Page: React.FC = () => {
return (
<main>
<div className="mb-4 text-2xl font-bold">Lucide React Icon</div>
<div className="flex gap-4">
<div className="flex flex-col items-center">
<div className="rounded-md border-2 p-2">
<Camera className="size-24 text-red-500" />
</div>
<div>Camera</div>
</div>
<div className="flex flex-col items-center">
<div className="rounded-md border-2 p-2">
<ThumbsUp className="size-24 text-red-500" />
</div>
<div>ThumbsUp</div>
</div>
<div className="flex flex-col items-center">
<div className="rounded-md border-2 p-2">
<Squirrel className="size-24 text-red-500" />
</div>
<div>Squirrel</div>
</div>
<div className="flex flex-col items-center">
<div className="rounded-md border-2 p-2">
<Settings className="size-24 text-red-500" />
</div>
<div>Settings</div>
</div>
</div>
</main>
);
};
export default Page;