Tailwind UIベースでカレンダー作ってみた

Tailwind UIベースでカレンダー作ってみた

https://almap.hata6502.com/ にUIを置いた

遠くのカレンダーに移動したいときは、 < > ボタンを連打せずに 2023年3月 を押して入力できるようにした
目立たないけどボタンっぽい見た目にしてみた
ドラムロールとか作れるといいとは思うけど、まずはwindow.promptで勘弁

Tailwind Plusのカレンダーがオリジナル

Tailwind UIはあくまでテンプレート集なので、ロジックは実装されていない
日付の配列もベタ書き
js
Copied!
const days = [
{ date: '2021-12-27' },
{ date: '2021-12-28' },
{ date: '2021-12-29' },
// ...
]
ロジックを自力で書かなきゃいけないのは大変
しかし、プロダクトごとの選定ライブラリに合わせて実装できるとも思えた
JavaScriptの日付周りは、多種多様なライブラリがある状況
momentから脱出できていないかもしれないし
Temporalを試しているかもしれない

hata6502はライブラリ使わず、素朴にDateとIntlでロジックを書いてみた
Dateにいろんなハマりどころがあるのは有名な話
getMonth()は0-based
getDay()は日付ではなく曜日
js
Copied!
const getDaysOfMonth = (dateOfMonth: Date) => {
const days: Date[] = [];
for (
const day = new Date(dateOfMonth.getFullYear(), dateOfMonth.getMonth(), 1);
day.getMonth() === dateOfMonth.getMonth();
day.setDate(day.getDate() + 1)
) {
days.push(new Date(day));
}

// 先月分を埋める
while (days[0].getDay() !== 0) {
const day = new Date(days[0]);
day.setDate(day.getDate() - 1);
days.unshift(day);
}
// 翌月分を埋める
while (days[days.length - 1].getDay() !== 6) {
const day = new Date(days[days.length - 1]);
day.setDate(day.getDate() + 1);
days.push(day);
}

return days;
};
js
Copied!
<button
type="button"
className="rounded bg-indigo-50 px-2 py-1 text-xs text-gray-900 shadow-sm hover:bg-indigo-100"
onClick={handleCurrentMonthButtonClick}
>
{new Intl.DateTimeFormat([], {
year: "numeric",
month: "long",
}).format(dateOfMonth)}
</button>

範囲選択するロジックも作った
けっこう要件が複雑
初期状態は全選択
範囲選択しないときは、内部的には全選択した状態とする
しかし全日付を選択状態の見た目にしたら、強調だらけになってしまう
全選択しているときは、普通のカレンダーを表示することにした
広い範囲を選択したいこともある
ステートはなるべく増やしたくないけど、2クリックで範囲選択することにした
ドラッグ&ドロップでは、月をまたいで選択できない
選択範囲と非選択範囲の対比を、色反転ではなく浮かび上がる感じ?にしてみた
コントラスト強すぎない感じになった
〇〇日以前や〇〇日以降を選択したいこともある
選択範囲の端をクリックしたら、解除するようにした
開始日時をクリックしたら、〇〇日以前を選択する
終了日時をクリックしたら、〇〇日以降を選択する
開始日時と終了日時を同時にクリックしたら、全選択になる
選択範囲の端に特別な動作を仕込んだので、色も変えてみる

日付範囲を選択するUI、難しくてチャレンジ感あるhata6502
Powered by Helpfeel