// A devlog by mood.

個人用に旅行日程サイトを作った話

Notionで作っていた旅行日程表が使いづらくなり、GW旅行に合わせて2日ほどで小さな旅行日程表サイトを作ったメモ。

旅行の予定はこれまでNotionでまとめていました。

日程、行きたい場所、メモ、予約情報あたりを1ページに置いておくと便利ではあるんですが、旅行中にスマホで見ると少し使いづらい。
表だと横スクロールで見づらいし、スポット間の移動時間は調べる必要があってしゃらくさいです。

今回のGW旅行でも日程表を作る必要があったので、せっかくなら自分用に使いやすいものを作ってしまおーって感じで作りました。

作業日数はだいたい2日くらい。
急ぎではありつつ、最低限サイトとして形にしました。
(時間もないのでAIに任せたのでデザインは、、ご愛嬌ですね。)

※日程はダミーです

作ったもの

ざっくり言うと、旅行ごとに日程表を作るサイトです。

  • 旅行を作成する
  • ステータスを 予定 / 旅行中 / 過去 / 下書き で管理する
  • Dayごとにスポットを追加する
  • スポット名、滞在時間、カテゴリ、住所、GoogleマップURL、メモを入れる
  • スポットから住所、マップURL自動生成
  • スポット間の移動時間を自動で表示する
  • 自動移動時間から次のスポットの時間も自動で反映
  • スポット一覧から目的の場所へジャンプする
  • ドラッグでスポット移動できる

アプリなら似たようなものあるんですけどわざわざ入れたくないし、自動系有料課金だったりしたので自作にしました。

技術構成

構成はこんな感じです。

  • Astro
  • TypeScript
  • Tailwind CSS
  • Cloudflare Workers
  • Cloudflare D1
  • Geoapify API

AstroはページとAPI Routesの両方で使っています。
Cloudflare Workersに載せて、旅行データはD1に保存する形です。

データ構造はかなりシンプルで、旅行ごとにtitleやstatusを持たせつつ、日程の中身はdays_jsonにまとめています。

日程やスポットは入れ替えが多いので、最初から細かくテーブルを分けるより、まずは1つの旅行データとして扱えるほうが作りやすかったです。

Geoapifyでやったこと

スポット名を入力したときの候補表示と、スポット間の移動時間計算にGeoapifyを使っています。
※ほんとはGoogleの方使いたかった…

スポット名を入れると候補を出して、選択したら緯度経度を持たせる。
その緯度経度を使って、次のスポットまでの移動時間を取得する流れです。

車移動の場合は渋滞を少し加味した値も見ています。
ただ、外部APIの結果は場所や道路によって大きく振れることがあるので、手入力で上書きできるようにもしました。

作っていてよかったところ

一番よかったのは、日程を考える画面がそのまま当日のしおりになることです。

「計画用の画面」と「見るための画面」を分けすぎると、作る側も使う側も少し面倒になります。
今回は編集画面の見た目をしおりっぽくして、入力中も旅行の流れが見えるようにしました。

スポットごとにメモ欄もあるので、予約番号、持ち物、営業時間、ちょっとした注意点もそこに入れておけます。

詳細表示で一瞬崩れて見える問題も直しました。

最初は、静的HTMLを先に出してからAPIで旅行データを取得し、JSで画面を差し替える構成にしていました。
ただ、このやり方だと初回表示の一瞬だけプレースホルダーや空状態が見えて、詳細ページが崩れたように感じます。

対策として、詳細ページの初期表示はサーバー側でD1からデータを取得して、HTMLに埋め込む形にしました。
Astro側で最初から実データを描画して、フロントのJSはその後の編集や保存を担当する構成です。

あと、スポット一覧を下に固定しておいたのも便利でした。
日程が長くなるとスクロールが増えるので、一覧から目的のスポットへ飛べるだけでかなり楽になります。

迷ったところ

D1の持ち方は少し迷いました。

スポットや日程を別テーブルにすれば、検索や集計はしやすくなります。
ただ、今回のサイトでは「1つの旅行を丸ごと編集して保存する」動きが中心です。

そのため、まずはD1に旅行単位で保存して、日程の詳細はJSONで持つ形にしました。

最初の実装としては、このくらいのほうが全体を小さく保ててよかったです。

これからやりたいこと

まだ作りたいものはいくつかあります。

  • デザイン大幅改修
  • 画像アップ機能

ともかく突貫で作り上げたがなんとか間に合ってよかったです。

以上、おわり。