🔄

🩺看護師が医療現場で使う計算ツールの開発に挑戦してみた #6:③ ResultBoxデザイン統一と注意表示の最適化

に公開

📘 はじめに

現役看護師として働きながら、Next.js × TypeScript × Tailwind CSSで「看護師向け計算ツールアプリ」を開発しています。
医療現場でも“安心して使える”Webアプリを目指し、UIの改善を段階的に行ってきました。

今回は、ResultBoxコンポーネントを全計算共通化し、注意表示を最適化する工程です。

💡 背景

開発初期では、各ページで結果の見せ方がバラバラでした。
数値の見やすさや注意表示の位置が揃っていないことで、利用者が混乱する場面もありました。

問題点 UX上の影響
数値サイズが小さい 現場で確認しづらい
背景色や余白が統一されていない 一貫性が失われる
注意欄の位置が不明確 見落としリスクあり

これを解決するため、ResultBoxのUI構造を共通化し、どの計算機能でも同じレイアウト・操作感で結果を確認できるようにしました。

⚙️ 改善後のResultBox.tsx

"use client";

import React, { useRef, useEffect, useState } from "react";
import { Disclosure } from "@headlessui/react";
import Image from "next/image";
import { helpTexts } from "@/config/helpTexts";

interface ResultItem {
  label: string;
  value: string | number;
  unit: string;
}

interface ResultBoxProps {
  title?: string;
  results: ResultItem[];
  color?: "green" | "blue" | "amber" | "purple" | "cyan" | "teal" | "fuchsia" | "rose" | "yellow";
  typeId?: string;
}

export const ResultBox: React.FC<ResultBoxProps> = ({
  title = "計算結果",
  results,
  color = "blue",
  typeId,
}) => {
  const bg = {
    green: "bg-green-50 border-green-200 text-green-800",
    blue: "bg-blue-50 border-blue-200 text-blue-800",
    amber: "bg-amber-50 border-amber-200 text-amber-800",
    purple: "bg-purple-50 border-purple-200 text-purple-800",
    cyan: "bg-cyan-50 border-cyan-200 text-cyan-800",
    teal: "bg-teal-50 border-teal-200 text-teal-800",
    fuchsia: "bg-fuchsia-50 border-fuchsia-200 text-fuchsia-800",
    rose: "bg-rose-50 border-rose-200 text-rose-800",
    yellow: "bg-yellow-50 border-yellow-200 text-yellow-800",
  }[color];

  const helpText = typeId ? helpTexts[typeId] : null;
  const panelRef = useRef<HTMLDivElement>(null);
  const [isOpen, setIsOpen] = useState(false);

  useEffect(() => {
    if (isOpen && panelRef.current) {
      panelRef.current.scrollIntoView({ behavior: "smooth", block: "start" });
    }
  }, [isOpen]);

  return (
    <Disclosure>
      {({ open }) => {
        if (open !== isOpen) setIsOpen(open);

        return (
          <div className={`border rounded p-4 ${bg}`}>
            {/* タイトル&ヘルプアイコン */}
            <div className="flex items-start justify-between">
              <h3 className="font-semibold">{title}</h3>
              {helpText && (
                <Disclosure.Button aria-label="注意説明">
                  <Image
                    src="/icons/help-icon.svg"
                    alt="注意"
                    width={28}
                    height={28}
                    className="cursor-pointer"
                  />
                </Disclosure.Button>
              )}
            </div>

            {/* 結果リスト */}
            <ul className="space-y-2 mt-2">
              {results.map((item, i) => (
                <li key={i} className="flex items-baseline gap-2">
                  <span className="text-base">{item.label}:</span>
                  <strong className="text-2xl font-bold">{item.value}</strong>
                  <span className="text-sm">{item.unit}</span>
                </li>
              ))}
            </ul>

            {/* 注意書き */}
            {helpText && (
              <Disclosure.Panel
                ref={panelRef}
                className={`mt-3 p-3 border-t ${bg} rounded-t-none text-sm leading-relaxed`}
              >
                {helpText}
              </Disclosure.Panel>
            )}
          </div>
        );
      }}
    </Disclosure>
  );
};

🎨 デザインの改善ポイント

要素 改善内容 意図
数値 text-2xl font-bold 見やすく即理解
背景色 種別カラーで統一 視覚的一貫性
注意欄 Disclosure+scrollIntoView 自然な展開でUX向上
余白 space-y-2 可読性アップ
アイコン 右上固定+28px 押しやすく統一感

🧠 学びのまとめ

  • ResultBoxは「全計算共通UI」として中心的役割を担う
  • Disclosureを使えば、状態管理+アクセシビリティ対応が簡単
  • scrollIntoViewとの組み合わせでUXが滑らかに
  • 配色・構造・動きを統一することで“安心できるUI”が生まれる

Discussion