見出し画像

【IT】「忘れ物ゼロ」へ。かわいいToDoで毎日をちょっと良くする話

— 無料版から“使い心地”を一段上げる → 本編で一気に完成へ

この記事は、無料パート(保存つき最小ToDo)を触った人が、
“使い心地の良さ”と“アプリとしての仕上げ”に踏み出すためのガイドです。
最後に、本編(有料)で得られる“完成体験”をまとめたので、気になったら覗いてみてください。
本編:かわいいToDoアプリをゼロから完成まで(PWA/公開/はまり対処)



✅ 限定公開URLと推奨環境

前回、有料パートで作成したToDoアプリの完成版を限定公開します。

  • 限定公開URL:https://tabi-cat-todo-555.pages.dev/
    ※予告なく、公開を終了したり、クラウドホスティングサービスを変更することがございます。あらかじめご了承ください。

  • 推奨環境:

    • Android / PC:Chrome, Edge, Firefox, Safari(最新)

    • iPhone / iPad(iOS Safari):ホーム画面追加は可能。ただし 圏外では起動しません
      事前にオンラインで開いておけば、一部画面や静的資産がキャッシュで表示される場合がありますが、動作は保証できません。


まず「ここが変わる」を3行で

  • スマホで触りやすい:下固定の入力バー+安全なボタン配置

  • 達成感が続く:未完了/完了/すべて切替+進捗バー、100%で紙吹雪

  • 毎日使える:PWA対応でホーム追加&オフラインでも起動

ポイント:無料版でもリロードで保持されています。ここからは“使うたび小さな喜びがある”設計を足していきます。


5分で試せる「快適化」ミニ改良(無料のまま)

無料パートのコードに最小の追記で、体験がガラッと良くなるところだけ先出しします。

1) 三分割フィルタと進捗(導出は `$derived`)

<script lang="ts">
  import { todos, type Todo } from '$lib/stores/todos';
  type Filter = 'all' | 'todo' | 'done';

  let filter = $state<Filter>('all');
  let list = $state<Todo[]>([]);
  $effect(() => todos.subscribe(v => list = v));

  function applyFilter(a: Todo[], f: Filter){
    if (f === 'todo') return a.filter(t => !t.done);
    if (f === 'done') return a.filter(t => t.done);
    return a;
  }
  const filtered = $derived(applyFilter(list, filter));
  const stats = $derived({
    total: list.length,
    done:  list.filter(t => t.done).length,
    rate:  list.length ? Math.round(list.filter(t=>t.done).length / list.length * 100) : 0
  });
</script>

<div class="segbar card">
  <button class="segbtn" class:active={filter==='todo'} onclick={() => filter='todo'}>
    未完了 <span class="pill">{stats.total - stats.done}</span>
  </button>
  <button class="segbtn" class:active={filter==='done'} onclick={() => filter='done'}>
    完了 <span class="pill">{stats.done}</span>
  </button>
  <button class="segbtn" class:active={filter==='all'} onclick={() => filter='all'}>
    すべて <span class="pill">{stats.total}</span>
  </button>
</div>

コツ:Svelte v5/Runesでは、`bind:value` の相手は `$state`。導出は `$derived` を“式”で書くと素直に動きます。

2) 100%達成で“ちょい紙吹雪”

<script lang="ts">
  let last = $state(0);
  $effect(() => {
    if (stats.rate === 100 && Date.now() - last > 1500) { boom(); last = Date.now(); }
  });
  function boom(){
    const root = document.querySelector('.confetti')!;
    root.innerHTML = '';
    const colors=['#FF8FB1','#A7E8F8','#FDE68A','#55C3A6'];
    for(let i=0;i<60;i++){
      const s=document.createElement('span');
      s.style.left=Math.random()*100+'vw';
      s.style.top='-5vh';
      s.style.animationDuration=(1.6+Math.random()*1.2)+'s';
      s.style.animationDelay=(Math.random()*0.6)+'s';
      s.style.background=colors[i%colors.length];
      root.appendChild(s);
    }
    setTimeout(()=>root.innerHTML='',3200);
  }
</script>
<div class="confetti" aria-hidden="true"></div>

心理効果:軽い演出でも「終わらせたい気持ち」が続きます。


デザインは“透け”で整える(無料のまま)

背景イラストをWebP優先PNGフォールバック。カードは白の半透明で可読性を確保。

/* src/app.css(抜粋) */
html, body { height: 100%; }
body{
  min-height: 100dvh;
  background:
    image-set(
      url('/bg-cat.webp') type('image/webp') 1x,
      url('/bg-cat.png')  type('image/png')  1x
    ) center / cover no-repeat;
}
.card{ background: rgba(255,255,255,.74); border-radius: 18px; box-shadow: 0 8px 28px rgba(0,0,0,.08); }

「ここから先」を本編で得られること(要点だけ先出し)

✅ PWA:ホーム追加&オフライン(iOS/Androidの違いも“迷わない”)

  • manifest の正解:`id/start_url/scope` を '/'で統一(警告回避)

  • iOSの真実:インストールバナーは出ません → 共有から「ホーム画面に追加」

  • アイコン生成の沼回避(`192x188`にならない ImageMagick の式)

magick ./WORK/tabi-cat.jpg -resize "192x192^" -gravity center -extent 192x192 -strip ./static/icons/icon-192.png
magick ./WORK/tabi-cat.jpg -resize "512x512^" -gravity center -extent 512x512 -strip ./static/icons/icon-512.png

✅ 本当に毎日使えるUI:親指で届く設計

  • 下固定の入力バー(セーフエリア対応

  • ボタンは誤タップを防ぐ角丸+十分なタップ領域

✅ 本番運用の壁をショートカット

  • Workbox 2MB問題(大きい背景は precache されない)→ 実害の線引きと対処

  • each_key_duplicate(キー重複)→ `(t.id)`必須+古いデータのid補完

  • Vercelで反映されない → Service Worker の更新(Unregister/Reload)

こうした「作るより時間を奪う“迷い”」に答えを用意しました。
スクショ/設定例/コピペOKの最小スニペット付きで、迷わず完成させます。


Before / After(たった30分で体験がこう変わる)


まずはここまでできたらOK(無料の最終チェック)

  • 追加・切替・削除ができ、リロード後も保持される

  • 未完了/完了/すべての切替&進捗バーが動く

  • 背景は最初から下まで表示、カードは半透明で可読性高い

ここからPWA対応→配布(Vercel)→“毎日使う”完成まで、
具体例と“はまり対処”をまとめたのが本編です👇


本編のご案内(ここで迷わず一気に完成)

  • PWAの正解セット(manifest・iOS/Android差分・インストール導線UI)

  • アイコン/スクショの作り方テンプレ(失敗しないImageMagick式)

  • Vercelでの公開・更新の勘所(SW更新/キャッシュ癖を含む)

  • 実装のはまりケースを丸ごと時短(`crossorigin`型、`each_key_duplicate`ほか)

本編:かわいいToDoアプリをゼロから完成まで(PWA/公開/はまり対処)
👉 https://note.com/t_ak66/n/n690e65a9a535


追伸

「買い物メモをまた忘れた」「今日やることを見失う」— それ、UIと小さな演出で意外と解決します。
せっかく動くToDoがあるなら、“毎日使いたくなるToDo”に変えましょう。
続きは本編で。

では
また!


過去のSvelte学習記事


いいなと思ったら応援しよう!