ジャーナルアプリ

1 日 3 善ジャーナルアプリ

毎日、3つの良い行いをメモする なんでもいいので、今日の良い行いを 3 つ書き出す ランダム、音声読み上げ機能 マインドセットを変化する

プロジェクトを作成

cd desktop/projects/nextproject
mkdir 3-good-a-day-journal
cd 3-good-a-day-journal
npm create cloudflare@latest . -- --framework=next
code .

不要なコードを削除

globals.css から、以下のようにコードを削除します。

  @tailwind base;
  @tailwind components;
  @tailwind utilities;

- :root {
-   --foreground-rgb: 0, 0, 0;
-   --background-start-rgb: 214, 219, 220;
-   --background-end-rgb: 255, 255, 255;
- }
-
- @media (prefers-color-scheme: dark) {
-   :root {
-     --foreground-rgb: 255, 255, 255;
-     --background-start-rgb: 0, 0, 0;
-     --background-end-rgb: 0, 0, 0;
-   }
- }
-
- body {
-   color: rgb(var(--foreground-rgb));
-   background: linear-gradient(
-       to bottom,
-       transparent,
-       rgb(var(--background-end-rgb))
-     )
-     rgb(var(--background-start-rgb));
- }
-
- @layer utilities {
-   .text-balance {
-     text-wrap: balance;
-   }
- }

page.tsx から、main タグ内の div タグを全て削除します。 また、main タグの className も削除します。

export default function Home() {
  return <main className="">Home</main>;
}

layout.tsx

フォントをInterからNoto Sans JPに変更します。

フォントの変更

  import type { Metadata } from "next";
- import { Inter } from "next/font/google";
+ import { Noto_Sans_JP } from "next/font/google";
  import "./globals.css";

- const inter = Inter({ subsets: ["latin"] });
+ const noto_sans_jp = Noto_Sans_JP({ subsets: ["latin"] });

  export const metadata: Metadata = {
    title: "Create Next App",
    description: "Generated by create next app",
  };

  export default function RootLayout({
    children,
  }: Readonly<{
    children: React.ReactNode;
  }>) {
    return (
      <html lang="en">
-       <body className={inter.className}>{children}</body>
+       <body className={noto_sans_jp.className}>{children}</body>
      </html>
    );
  }

言語の変更

言語を英語から日本語に変更します。

- <html lang="en">
+ <html lang="ja">
    <body className={noto_sans_jp.className}>{children}</body>
  </html>

メタデータの変更

メタデータのタイトルと説明を変更します。

  export const metadata: Metadata = {
-   title: "Create Next App",
+   title: "3 Good a day Journal",
-   description: "Generated by create next app",
+   description: "3 Good a day Journal app",
  };

mainルートグループを作成

appディレクトリに(main)ディレクトリを作成します。 appディレクトリのpage.tsxを作成した(main)ディレクトリに移動します。 また、(main)ディレクトリにlayout.tsxを作成します。

export default function MainLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  return <div className="container mx-auto p-2">{children}</div>;
}

shadcn/uiをインストール

npx shadcn-ui@latest init

ダミーデータを作成

export const goodData = [
  {
    id: 20240603,
    oneGood: "洗濯物を干した",
    twoGood: "風呂掃除をした",
    threeGood: "買い物に行った",
    date: "2024-06-03",
  },
  {
    id: 20240604,
    oneGood: "風呂掃除をした",
    twoGood: "洗濯物を干した",
    threeGood: "買い物に行った",
    date: "2024-06-04",
  },
  {
    id: 20240605,
    oneGood: "買い物に行った",
    twoGood: "洗濯物を干した",
    threeGood: "風呂掃除をした",
    date: "2024-06-05",
  },
];

ダミーデータを表示

+ import { goodData } from "@/data";
  
  export default function Home() {
    return (
      <main className="">
-     Home
+       {goodData.map(({ id, oneGood, date }) => (
+         <div key={id}>
+           {date}:{oneGood}
+         </div>
+       ))}
      </main>
    );
  }

Calendarコンポーネントを追加

npx shadcn-ui@latest add calendar

Calendarコンポーネントを設置

+ "use client";
+
+ import { Calendar } from "@/components/ui/calendar";
  import { goodData } from "@/data";
+ import { useState } from "react";
  
  export default function Home() {
+   const [date, setDate] = useState<Date | undefined>(new Date());
    return (
      <main className="">
        {goodData.map(({ id, oneGood, date }) => (
          <div key={id}>
            {date}:{oneGood}
          </div>
        ))}
+       <Calendar
+         mode="single"
+         selected={date}
+         onSelect={setDate}
+         className="rounded-md border w-[280px]"
+       />
      </main>
    );
  }

Calendarコンポーネントを設置します。 ドキュメントからコードを貼り付けます。 "use client"を追加して、クライアントコンポーネントにします。 useStateを追加して、Calendarコンポーネントで選択した日付のステート状態を更新します。 Calendarコンポーネントを追加します。 modeプロパティは選択モードを設定します。 singleは1度に1つの日付だけ選択できるようにします。 selectedプロパティは選択した日付を指定します。 初期値はuseStateの初期値である現在の日付になります。 onSelectプロパティは日付を選択したときに呼び出されます。 ここでは、setDateを呼び出して、選択した日付をdateに保存します。 そして、selectedプロパティの値が変更されます。 classNameにw-[280px]を追加します。 ブラウザで確認すると、初期値の今日の日付が選択されています。 違う日付を選択するとマークされます。 選択された日付をクリックすると、マークが外れます。

  <Calendar
    mode="single"
    selected={date}
    onSelect={setDate}
    className="rounded-md border w-[280px]"
+   required
  />

Calendarコンポーネントにrequiredプロパティを追加すると、マークは外せなくなります。