日ごとの予報の格子

今日から3日ぶんを3列に並べて、1日を1列に要約する事例です。曜日、天気、最低と最高の気温、6時間ごとの降水確率を、上から順に積みます。

プレビュー

状態とバリエーション

3日並ぶ

朝5時の発表の直後に開くと、今日の降水確率は 0〜6時・6〜12時・12〜18時・18〜24時の4つがそろいます。

日ごとの予報 気象庁

今日

9/19(土)

くもり 時々 雨

最低 21°最高 26°

0-6時
20%
6-12時
30%
12-18時
50%
18-24時
50%

あす

9/20(日)

雨 所により 朝から 雷を伴い 激しく降る

最低 21°最高 24°

0-6時
80%
6-12時
80%
12-18時
80%
18-24時
80%

月曜

9/21(月)

雨

最低 20°最高 28°

降水確率は未発表

今日の過ぎた時間帯は出さない

13時に開いたら、今日の降水確率は 12〜18時と 18〜24時の2つだけにします。

日ごとの予報 気象庁

今日

9/19(土)

くもり 時々 雨

最低 21°最高 26°

12-18時
50%
18-24時
50%

あす

9/20(日)

雨 所により 朝から 雷を伴い 激しく降る

最低 21°最高 24°

0-6時
80%
6-12時
80%
12-18時
80%
18-24時
80%

月曜

9/21(月)

雨

最低 20°最高 28°

降水確率は未発表

日付が変わった直後

0時を過ぎても、次の発表(朝5時)までは前の日の予報を使います。その予報の「今日」の列はもう昨日なので外し、残る2日を「今日」「あす」と呼び直して2列で出します。

日ごとの予報 気象庁

今日

9/20(日)

雨 所により 朝から 雷を伴い 激しく降る

最低 21°最高 24°

0-6時
80%
6-12時
80%
12-18時
80%
18-24時
80%

あす

9/21(月)

雨

最低 20°最高 28°

降水確率は未発表

降水確率が無い日

6時間ごとの降水確率は、今日とあすのぶんしか発表されません。3日目の欄は「—」だけにします。

日ごとの予報 気象庁

今日

9/17(木)

くもり 時々 雨

最低 21°最高 26°

12-18時
50%
18-24時
50%

あす

9/18(金)

雨 所により 朝から 雷を伴い 激しく降る

最低 21°最高 24°

0-6時
80%
6-12時
80%
12-18時
80%
18-24時
80%

土曜

9/19(土)

雨

最低 20°最高 28°

降水確率は未発表

土日の色

土曜は青、日曜は赤で、GUNJO の Calendar(日付を選ぶカレンダー)と同じ色です。「あす」のような呼び名で出す日も、土日なら色を付けます。

日ごとの予報 気象庁

今日

9/18(金)

くもり 時々 雨

最低 21°最高 26°

0-6時
20%
6-12時
30%
12-18時
50%
18-24時
50%

あす

9/19(土)

雨 所により 朝から 雷を伴い 激しく降る

最低 21°最高 24°

0-6時
80%
6-12時
80%
12-18時
80%
18-24時
80%

日曜

9/20(日)

雨

最低 20°最高 28°

降水確率は未発表

0時から朝5時の発表までのあいだだけ、列が2つになります。

1日ぶんのデータ

表は横にスクロールできます
プロパティ型初期値説明
datestring-その日の日付(YYYY-MM-DD)。呼び名と曜日の色はここから決める。
kind"sun" | "cloud" | "rain" | "storm"-天気の絵。
textstring-天気の文。長さはまちまち。
min / maxnumber | null-最低と最高の気温。無ければ「—」。
pops{ from: number; value: number }[]-6時間ごとの降水確率。今日とあすだけ。無い日は空の配列。

使い方

"use client";

import { IconCloud, IconCloudRain } from "@tabler/icons-react";
import { Card, Grid, Icon } from "@gunjo/ui";

const DAYS = [
  { name: "今日", date: "9/19(土)", weekday: 6, icon: IconCloud,
    text: "くもり 時々 雨", min: 21, max: 26,
    pops: [["12-18", 50], ["18-24", 50]] },
  { name: "あす", date: "9/20(日)", weekday: 0, icon: IconCloudRain,
    text: "雨 所により 朝から 雷を伴い 激しく降る", min: 21, max: 24,
    pops: [["0-6", 80], ["6-12", 80], ["12-18", 80], ["18-24", 80]] },
  { name: "月曜", date: "9/21(月)", weekday: 1, icon: IconCloudRain,
    text: "雨", min: 20, max: 28, pops: [] },
] as const;

// 土曜は青、日曜は赤(Calendar と同じトークン)
const tone = (w: number) => (w === 6 ? "text-info" : w === 0 ? "text-destructive" : undefined);

export function ForecastDays() {
  return (
    <Card className="overflow-hidden">
      {/* subgrid で行を3列で共有する=長い文の列があっても気温の段がそろう */}
      <Grid cols={3} gap={0} className="grid-rows-[auto_auto_auto_auto_auto] divide-x divide-border">
        {DAYS.map((d) => (
          <div key={d.date} className="row-span-5 grid grid-rows-subgrid px-2 py-3 text-center">
            <div className={tone(d.weekday)}>
              <p className="text-sm font-semibold">{d.name}</p>
              <p className="text-xs">{d.date}</p>
            </div>
            <div className="flex justify-center py-2"><Icon icon={d.icon} size="xl" /></div>
            <p className="text-xs">{d.text}</p>
            <p className="mt-2 text-sm tabular-nums">最低 {d.min}° 最高 {d.max}°</p>
            <div className="mt-2 border-t pt-2 text-xs tabular-nums">
              {d.pops.length
                ? d.pops.map(([h, v]) => <span key={h} className="mx-1 inline-block">{h}時 {v}%</span>)
                : "—"}
            </div>
          </div>
        ))}
      </Grid>
    </Card>
  );
}

設計の判断

  • 各列の上に、呼び名を出します。「今日」「あす」、3列目は「あさって」ではなく「月曜」のように曜日で呼びます。呼び名の下に、日付と曜日を「9/21(月)」の形で小さく添えます。「あす」の列でも曜日が読めます。
  • 気温には「最低」「最高」と語を添えます。
  • 土日も気温も、色だけで区別しません。
  • 天気の文は長さがまちまちです(「雨 所により 朝から 雷を伴い 激しく降る」のような長い文もあります)。文の欄は、3列でいちばん長い文に高さを合わせます。気温と降水確率の段が3列でそろいます。
  • 数字は等幅の数字にして、列ごとに桁をそろえます。
  • 格子の上の見出しに、予報の出どころ(例:気象庁)を添えます。

使用コンポーネント

  • WeekView

    時刻を軸にした週の予定表。1日を1列に要約しない。

  • ScheduleGrid

    時間割。行が時刻で、要約の段を持たない。

  • Calendar

    日付を選ぶ。土日の色はここと同じ。

いつ・なぜ使うか(UIXHERO)

「いつ・なぜ使うか」は姉妹サイト UIXHERO の記事で解説する予定です。記事を書くまでは、起票した issue を置いています。