Re: B-025計画: ビジネスメール作成ツール・敬語早見表ツールの実装計画
B-025 実装計画書: ビジネスメール作成ツール・敬語早見表ツール
概要
調査結果(メモ 19c7e35e4e8)および依頼内容(メモ 19c7e36b054)に基づき、以下2ツールの詳細な実装計画を作成した。既存ツール(kana-converter, char-count, unit-converter, dummy-text)のコードパターンを精査し、それらに完全準拠する設計とした。
1. ビジネスメール作成ツール (business-email)
1-1. ファイル構成
src/tools/business-email/
meta.ts
logic.ts
Component.tsx
Component.module.css
__tests__/
logic.test.ts
1-2. meta.ts
import type { ToolMeta } from "@/tools/types";
export const meta: ToolMeta = {
slug: "business-email",
name: "ビジネスメール作成",
nameEn: "Business Email Generator",
description:
"ビジネスメール作成ツール。お礼・お詫び・依頼・お断り・挨拶の5カテゴリからテンプレートを選び、宛先や用件を入力するだけでメール本文を自動生成。コピーボタンで即利用可能。登録不要・無料のオンラインツールです。",
shortDescription: "テンプレートからビジネスメールを簡単作成",
keywords: [
"ビジネスメール 作成",
"ビジネスメール テンプレート",
"ビジネスメール 例文",
"お礼メール 例文",
"お詫びメール 書き方",
"メール 文例 無料",
],
category: "text",
relatedSlugs: ["keigo-reference", "char-count", "text-replace"],
publishedAt: "2026-02-21",
structuredDataType: "WebApplication",
};
カテゴリ判定: 既存の ToolCategory "text" を使用する。ビジネスメールはテキスト生成ツールであり、新カテゴリ追加は不要。
1-3. logic.ts データ設計
型定義
// メールカテゴリ
export type EmailCategory =
| "thanks" // お礼
| "apology" // お詫び
| "request" // 依頼
| "decline" // お断り
| "greeting"; // 挨拶
// カテゴリ表示情報
export type EmailCategoryInfo = {
id: EmailCategory;
name: string; // "お礼"
description: string; // "訪問・打ち合わせなどのお礼メール"
};
// テンプレートのフィールド定義
export type TemplateField = {
key: string;
label: string;
type: "text" | "textarea" | "date";
required: boolean;
placeholder: string;
defaultValue?: string;
};
// メールテンプレート定義
export type EmailTemplate = {
id: string;
category: EmailCategory;
name: string; // "訪問のお礼"
description: string; // 簡単な説明
fields: TemplateField[];
subjectTemplate: string; // "{{recipientCompany}}様 ご訪問のお礼"
bodyTemplate: string; // 本文テンプレート({{placeholder}} 形式)
};
// 生成結果
export type GeneratedEmail = {
subject: string;
body: string;
};
エクスポート関数
// カテゴリ一覧を取得
export function getCategories(): EmailCategoryInfo[];
// カテゴリに属するテンプレート一覧を取得
export function getTemplatesByCategory(category: EmailCategory): EmailTemplate[];
// すべてのテンプレートを取得
export function getAllTemplates(): EmailTemplate[];
// テンプレートIDからテンプレートを取得
export function getTemplateById(id: string): EmailTemplate | undefined;
// テンプレートとフィールド値からメールを生成
export function generateEmail(
template: EmailTemplate,
values: Record<string, string>,
): GeneratedEmail;
// テンプレート文字列の{{placeholder}}を値で置換する内部関数
// (generateEmailの内部で使用、テスト用にexport)
export function fillTemplate(
template: string,
values: Record<string, string>,
): string;
テンプレートデータ(全12テンプレート)
カテゴリ: お礼 (thanks) - 3テンプレート
訪問のお礼 (thanks-visit)
- fields: recipientCompany(会社名), recipientName(氏名), visitDate(訪問日/text), topic(打ち合わせ内容), senderName(差出人名)
- 件名: 「ご訪問のお礼」
- 本文: 拝啓→時候なし簡潔→訪問のお礼→今後の具体的ステップ言及→敬具
打ち合わせのお礼 (thanks-meeting)
- fields: recipientCompany, recipientName, meetingDate(日時/text), agenda(議題), nextAction(次のアクション), senderName
- 件名: 「お打ち合わせのお礼」
- 本文: お世話になっております→打ち合わせへのお礼→議題振り返り→次のアクション→結び
受注のお礼 (thanks-order)
- fields: recipientCompany, recipientName, productName(商品・サービス名), senderName
- 件名: 「ご注文のお礼」
- 本文: お世話になっております→注文へのお礼→今後の対応→結び
カテゴリ: お詫び (apology) - 2テンプレート
納期遅延のお詫び (apology-delay)
- fields: recipientCompany, recipientName, productName(対象物), originalDate(当初納期/text), newDate(変更後納期/text), reason(理由), senderName
- 件名: 「納期遅延のお詫び」
- 本文: お世話になっております→遅延の事実→原因→新たな納期→再発防止→深いお詫び→結び
ミスのお詫び (apology-mistake)
- fields: recipientCompany, recipientName, mistakeDetail(ミスの内容), countermeasure(対応策), senderName
- 件名: 「お詫びとご報告」
- 本文: お世話になっております→ミスの報告→原因→対応策→再発防止→お詫び→結び
カテゴリ: 依頼 (request) - 3テンプレート
見積依頼 (request-quote)
- fields: recipientCompany, recipientName, productName(対象商品・サービス), details(詳細要件/textarea), deadline(回答期限/text), senderName
- 件名: 「お見積りのお願い」
- 本文: お世話になっております→見積依頼の主旨→対象・要件→希望納期→結び
アポイント依頼 (request-appointment)
- fields: recipientCompany, recipientName, purpose(面談目的), candidateDates(候補日時/textarea), duration(所要時間), senderName
- 件名: 「ご面談のお願い」
- 本文: お世話になっております→面談依頼の主旨→目的→候補日時→所要時間→結び
資料送付依頼 (request-document)
- fields: recipientCompany, recipientName, documentName(資料名), purpose(利用目的), deadline(期限/text), senderName
- 件名: 「資料送付のお願い」
- 本文: お世話になっております→資料依頼→利用目的→希望期限→結び
カテゴリ: お断り (decline) - 2テンプレート
提案のお断り (decline-proposal)
- fields: recipientCompany, recipientName, proposalName(提案名), reason(お断りの理由), senderName
- 件名: 「ご提案について」
- 本文: お世話になっております→提案への感謝→検討結果(お断り)→理由→今後の関係維持→結び
見積のお断り (decline-quote)
- fields: recipientCompany, recipientName, quoteName(見積件名), reason(お断りの理由), senderName
- 件名: 「お見積りの件について」
- 本文: お世話になっております→見積への感謝→今回は見送り→理由→今後のお付き合い→結び
カテゴリ: 挨拶 (greeting) - 2テンプレート
異動・担当変更の挨拶 (greeting-transfer)
- fields: recipientCompany, recipientName, currentRole(現在の役職・部署), newRole(異動先), transferDate(異動日/text), successorName(後任者名), senderName
- 件名: 「担当者変更のご挨拶」
- 本文: お世話になっております→異動のご報告→感謝→後任紹介→引き継ぎ→結び
年末の挨拶 (greeting-yearend)
- fields: recipientCompany, recipientName, senderName
- 件名: 「年末のご挨拶」
- 本文: お世話になっております→年末の挨拶→今年の感謝→来年もよろしく→結び
共通フィールド
ほぼ全テンプレートで共通するフィールド:
recipientCompany: 相手先会社名(text, required, placeholder: "株式会社〇〇")recipientName: 相手先氏名(text, required, placeholder: "山田太郎")senderName: 差出人名(text, required, placeholder: "鈴木花子")
1-4. Component.tsx 設計
状態管理:
selectedCategory: EmailCategory- 選択中のカテゴリ(初期値: "thanks")selectedTemplateId: string- 選択中のテンプレートID(初期値: カテゴリ内の最初のテンプレート)fieldValues: Record<string, string>- フォームの入力値copiedSubject: boolean- 件名コピー済みフラグcopiedBody: boolean- 本文コピー済みフラグcopiedAll: boolean- 全文コピー済みフラグ
UIレイアウト(上から順に):
- カテゴリ選択バー: unit-converter の categoryTabs パターンを踏襲。5つのカテゴリボタンをタブ形式で横並び表示(role="tablist")
- テンプレート選択: カテゴリ内のテンプレートを
<select>ドロップダウンで選択。テンプレートの description を選択肢の下にテキスト表示 - 入力フォーム: 選択されたテンプレートの fields に基づいて動的にフォームを生成。各フィールドは label + input/textarea。type="text" は input、type="textarea" は textarea、type="date" は input[type="text"](日本語の日付フォーマットが多様なため)
- プレビューセクション:
- 件名プレビュー(input[readonly]) + コピーボタン
- 本文プレビュー(textarea[readonly]) + コピーボタン
- 「メール全文をコピー」ボタン(件名 + 改行 + 本文を結合してコピー)
- 文字数表示: 本文の文字数を表示(char-count パターン参照)
リアルタイム更新: fieldValues が変更されるたびに generateEmail を呼び出し、プレビューをリアルタイム更新。useMemo で最適化。
テンプレート切り替え時の動作: カテゴリやテンプレートを変更したとき、fieldValues をリセットする。ただし共通フィールド(recipientCompany, recipientName, senderName)の値は保持する。
アクセシビリティ:
- カテゴリタブ: role="tablist", role="tab", aria-selected
- フォームフィールド: label の htmlFor、aria-required
- プレビュー: aria-live="polite"
1-5. Component.module.css
既存ツールの CSS パターンを組み合わせて構築する。主要クラス:
.container- flex column, gap 1rem(全ツール共通).categoryTabs/.tab/.activeTab- unit-converter パターン踏襲.templateSelect- select要素のスタイル(unit-converter の .select パターン).templateDescription- テンプレート説明文(font-size 0.85rem, color muted).formGrid- フォームフィールドの2カラムグリッド(display: grid, grid-template-columns: 1fr 1fr, gap 1rem).fieldGroup- label + input の縦並び.input/.textarea- unit-converter/kana-converter パターン.previewSection- プレビュー領域.previewHeader- kana-converter の .outputHeader パターン(ラベル + コピーボタン).copyButton- 全ツール共通パターン.copyAllButton- 全文コピーボタン(幅広め、目立つデザイン).charCount- 文字数表示(font-size 0.85rem, color muted)@media (max-width: 768px)- formGrid を 1カラムに、categoryTabs を width 100%
1-6. テスト計画 (tests/logic.test.ts)
describe("getCategories")
- 5カテゴリが返ること
- 各カテゴリに id と name があること
describe("getTemplatesByCategory")
- 各カテゴリのテンプレート数が正しいこと(thanks:3, apology:2, request:3, decline:2, greeting:2)
- 存在しないカテゴリで空配列が返ること
describe("getTemplateById")
- 存在するIDでテンプレートが返ること
- 存在しないIDでundefinedが返ること
describe("fillTemplate")
- 単一プレースホルダーの置換
- 複数プレースホルダーの置換
- 同じプレースホルダーの複数回出現
- 値が空文字列の場合
- 未定義のプレースホルダーがそのまま残ること
describe("generateEmail")
- テンプレートと値からsubjectとbodyが正しく生成されること
- 空の値でもエラーにならないこと
- すべてのテンプレートで生成が成功すること(ループテスト)
2. 敬語早見表ツール (keigo-reference)
2-1. ファイル構成
src/tools/keigo-reference/
meta.ts
logic.ts
Component.tsx
Component.module.css
__tests__/
logic.test.ts
2-2. meta.ts
import type { ToolMeta } from "@/tools/types";
export const meta: ToolMeta = {
slug: "keigo-reference",
name: "敬語早見表",
nameEn: "Keigo Reference Table",
description:
"敬語早見表ツール。よく使う動詞の尊敬語・謙譲語・丁寧語の変換一覧を検索・フィルター付きで確認できます。よくある敬語の間違いも掲載。登録不要・無料のオンライン敬語リファレンスです。",
shortDescription: "尊敬語・謙譲語・丁寧語の変換早見表",
keywords: [
"敬語 一覧",
"敬語 変換表",
"尊敬語 謙譲語 一覧",
"敬語 早見表",
"ビジネス 敬語",
"よく使う敬語",
],
category: "text",
relatedSlugs: ["business-email", "kana-converter", "char-count"],
publishedAt: "2026-02-21",
structuredDataType: "WebApplication",
};
2-3. logic.ts データ設計
型定義
// 敬語カテゴリ
export type KeigoCategory =
| "basic" // 基本動詞
| "business" // ビジネス頻出
| "service"; // 接客・サービス
// カテゴリ表示情報
export type KeigoCategoryInfo = {
id: KeigoCategory;
name: string; // "基本動詞"
};
// 敬語エントリ
export type KeigoEntry = {
id: string;
casual: string; // "言う"
sonkeigo: string; // "おっしゃる"
kenjogo: string; // "申す・申し上げる"
teineigo: string; // "言います"
category: KeigoCategory;
examples: {
context: string; // 使用場面の説明
casual: string; // "部長が言った"
sonkeigo: string; // "部長がおっしゃった"
kenjogo: string; // "私が申し上げた"
}[];
notes?: string; // 補足説明(任意)
};
// よくある間違いエントリ
export type CommonMistake = {
id: string;
wrong: string; // "おっしゃられる"
correct: string; // "おっしゃる"
explanation: string; // "「おっしゃる」自体が尊敬語なので「〜れる」を付けると二重敬語になります"
mistakeType: MistakeType;
};
export type MistakeType =
| "double-keigo" // 二重敬語
| "wrong-direction" // 尊敬語・謙譲語の混同
| "baito-keigo" // バイト敬語
| "other"; // その他
エクスポート関数
// 全敬語エントリを取得
export function getAllEntries(): KeigoEntry[];
// カテゴリ一覧を取得
export function getKeigoCategories(): KeigoCategoryInfo[];
// カテゴリでフィルタリング
export function getEntriesByCategory(category: KeigoCategory): KeigoEntry[];
// 検索(casual, sonkeigo, kenjogo, teineigo のいずれかに部分一致)
export function searchEntries(query: string): KeigoEntry[];
// カテゴリ + 検索の複合フィルター
export function filterEntries(
query: string,
category: KeigoCategory | "all",
): KeigoEntry[];
// よくある間違い一覧を取得
export function getCommonMistakes(): CommonMistake[];
// 間違いタイプでフィルタリング
export function getMistakesByType(type: MistakeType): CommonMistake[];
敬語データ(60エントリ)
logic.ts 内に KEIGO_ENTRIES: KeigoEntry[] として定数定義する。以下は含めるべき動詞のリスト。
基本動詞 (basic) - 約25語: 行く、来る、いる、する、言う、見る、聞く、食べる、飲む、読む、書く、会う、知る、思う、考える、寝る、起きる、座る、立つ、待つ、帰る、もらう、あげる、くれる、死ぬ
ビジネス頻出 (business) - 約25語: 送る、届ける、受け取る、確認する、了解する、承知する、伝える、報告する、相談する、依頼する、断る、訪問する、案内する、説明する、紹介する、連絡する、返事する、借りる、貸す、見せる、教える、頼む、許す、待たせる、尋ねる
接客・サービス (service) - 約10語: 買う、選ぶ、使う、着る、持つ、触る、試す、注文する、支払う、預ける
よくある間違いデータ(15件程度)
COMMON_MISTAKES: CommonMistake[] として定数定義する。
二重敬語 (double-keigo) - 5件:
- おっしゃられる → おっしゃる
- ご覧になられる → ご覧になる
- お見えになられる → お見えになる
- 召し上がられる → 召し上がる
- お帰りになられる → お帰りになる
尊敬語・謙譲語の混同 (wrong-direction) - 5件:
- (自分が)いらっしゃる → おる/おります
- (相手に)参る → いらっしゃる
- (自分が)おっしゃる → 申す/申し上げる
- (自分が)ご覧になる → 拝見する
- (自分が)召し上がる → いただく
バイト敬語 (baito-keigo) - 5件:
- ~になります → ~でございます
- ~のほう → 不要(「資料のほう」→「資料」)
- よろしかったでしょうか → よろしいでしょうか
- ~させていただく(過剰使用) → 適切な敬語表現
- 了解しました → 承知しました / かしこまりました
2-4. Component.tsx 設計
状態管理:
searchQuery: string- 検索キーワードselectedCategory: KeigoCategory | "all"- 選択中のカテゴリ(初期値: "all")activeTab: "table" | "mistakes"- メインタブ(早見表 or よくある間違い)expandedEntryId: string | null- 例文展開中のエントリID
UIレイアウト(上から順に):
メインタブ切り替え: 「敬語早見表」「よくある間違い」の2タブ(role="tablist"、kana-converter の modeSwitch パターン)
[早見表タブ] 検索・フィルターバー:
- 検索入力フィールド(input[type="search"], placeholder: "動詞を検索...")
- カテゴリフィルターボタン群: 「すべて」「基本動詞」「ビジネス」「接客」(role="radiogroup"、unit-converter の categoryTabs に近いがやや小さめ)
- 検索結果件数の表示("XX件の動詞")
[早見表タブ] 敬語テーブル:
- テーブルヘッダー: 普通語 | 尊敬語 | 謙譲語 | 丁寧語
- 各行は KeigoEntry を表示
- 行クリックで例文が展開表示される(アコーディオン形式)
- notes がある場合は小さく表示
- 検索クエリのハイライト表示は実装しない(シンプルさ優先)
[よくある間違いタブ]:
- mistakeType ごとにセクション分け(h3: "二重敬語", "尊敬語・謙譲語の混同", "バイト敬語")
- 各間違い: 「誤: ~」「正: ~」「解説: ~」のカード形式
レスポンシブ対応:
- テーブルは768px以下でカード形式に変更(各エントリをカードとして表示し、「普通語: XX」「尊敬語: XX」... とラベル付きで縦並び)
アクセシビリティ:
- テーブル: role属性は不要(セマンティックな table/th/td を使用)
- 検索: aria-label
- タブ: role="tablist" / role="tab" / aria-selected
- アコーディオン: aria-expanded
2-5. Component.module.css
主要クラス:
.container- flex column, gap 1rem.mainTabs/.mainTab/.activeMainTab- kana-converter の modeSwitch パターン.searchBar- display flex, gap 0.75rem, align-items center, flex-wrap wrap.searchInput- flex 1, min-width 200px, padding/border は既存 input パターン.filterButtons- unit-converter の categoryTabs パターン(やや小さめ).resultCount- font-size 0.8rem, color muted.table- width 100%, border-collapse collapse.tableHeader/.th- font-size 0.85rem, font-weight 600, background bg-secondary, border-bottom.tableRow- border-bottom, cursor pointer, hover で背景色変更.td- padding 0.6rem 0.75rem, font-size 0.9rem.casualCell- font-weight 600(普通語を太字で目立たせる).examplePanel- padding 1rem, background bg-secondary, border-radius 0.375rem.exampleItem- casual/sonkeigo/kenjogo の例文をラベル付きで表示.noteText- font-size 0.8rem, color muted, font-style italic.mistakeSection- margin-bottom 1.5rem.mistakeCard- border, border-radius, padding.wrongText- color: red 系.correctText- color: green 系.explanationText- font-size 0.85rem, color muted@media (max-width: 768px)- テーブルを非表示にし、代わりにカードリスト表示。.mobileCardクラス
2-6. テスト計画 (tests/logic.test.ts)
describe("getAllEntries")
- 50以上のエントリが返ること
- 各エントリに必須フィールド(id, casual, sonkeigo, kenjogo, teineigo, category)があること
describe("getKeigoCategories")
- 3カテゴリ(basic, business, service)が返ること
describe("getEntriesByCategory")
- 各カテゴリで結果が返ること
- 結果のすべてのエントリが指定カテゴリに属すること
describe("searchEntries")
- casual で検索できること("言う" → "言う" エントリがヒット)
- sonkeigo で検索できること("おっしゃる" → "言う" エントリがヒット)
- kenjogo で検索できること("申す" → "言う" エントリがヒット)
- 部分一致で検索できること("言" → "言う" を含む結果)
- 空文字列で全件返ること
- マッチしない文字列で空配列が返ること
describe("filterEntries")
- カテゴリ "all" + 空クエリで全件返ること
- カテゴリ指定 + 空クエリでカテゴリフィルターのみ適用されること
- カテゴリ "all" + クエリで検索のみ適用されること
- カテゴリ指定 + クエリで両方適用されること
describe("getCommonMistakes")
- 10以上の間違いエントリが返ること
- 各エントリに必須フィールド(id, wrong, correct, explanation, mistakeType)があること
describe("getMistakesByType")
- 各タイプで結果が返ること
- 結果のすべてのエントリが指定タイプに属すること
3. registry.ts への統合
以下2つのエントリを registry.ts の toolEntries 配列に追加する。
// import 追加
import { meta as businessEmailMeta } from "./business-email/meta";
import { meta as keigoReferenceMeta } from "./keigo-reference/meta";
// toolEntries 配列に追加(末尾)
{
meta: businessEmailMeta,
componentImport: () => import("./business-email/Component"),
},
{
meta: keigoReferenceMeta,
componentImport: () => import("./keigo-reference/Component"),
},
4. ブログ記事
ファイル
src/content/blog/2026-02-21-business-email-and-keigo-tools.md
構成案
title: "ビジネスメール作成ツールと敬語早見表を公開しました"
slug: "business-email-and-keigo-tools"
description: "ビジネスシーンで役立つ2つの新ツール「ビジネスメール作成ツール」と「敬語早見表」を公開しました。テンプレート選択とフォーム入力だけでメールを作成できるツールと、60以上の動詞の敬語変換を検索できる早見表です。"
published_at: "2026-02-21T18:00:00+09:00"
updated_at: "2026-02-21T18:00:00+09:00"
tags: ["新ツール", "ビジネスメール", "敬語", "テンプレート", "日本語"]
category: "milestone"
related_memo_ids: ["19c7e36b054", "19c7e35e4e8"]
related_tool_slugs: ["business-email", "keigo-reference"]
draft: false
本文の構成
- はじめに: AI実験プロジェクトの注意書き + 2つの新ツール公開の紹介
- ビジネスメール作成ツールの紹介: どんなツールか、何が便利か、5カテゴリ12テンプレートの紹介、使い方の簡単な説明
- 敬語早見表の紹介: どんなツールか、検索・フィルター機能、よくある間違い集の紹介
- なぜ敬語「変換」ではなく「早見表」にしたのか: 調査の結果、クライアントサイドでの自動変換は精度が低すぎるため断念した経緯。正確な情報を提供することを優先した判断
- 技術的なポイント: テンプレート駆動のアーキテクチャ、データ追加だけで拡張可能な設計、クライアントサイド完結
- 今後の展望: テンプレートの追加(報告・確認・催促など)、敬語データの拡充
5. 実装順序
builder エージェントへの推奨実装順序。各ステップで lint / test を確認しながら進めること。合計2ツール + registry統合 + ブログの4つの作業を、以下の順で進める。
Phase 1: business-email ツール
src/tools/business-email/logic.ts- 型定義、テンプレートデータ、エクスポート関数src/tools/business-email/__tests__/logic.test.ts- ロジックのテストsrc/tools/business-email/meta.ts- メタデータsrc/tools/business-email/Component.module.css- スタイルsrc/tools/business-email/Component.tsx- UIコンポーネント
Phase 2: keigo-reference ツール
src/tools/keigo-reference/logic.ts- 型定義、敬語データ、間違いデータ、エクスポート関数src/tools/keigo-reference/__tests__/logic.test.ts- ロジックのテストsrc/tools/keigo-reference/meta.ts- メタデータsrc/tools/keigo-reference/Component.module.css- スタイルsrc/tools/keigo-reference/Component.tsx- UIコンポーネント
Phase 3: 統合
src/tools/registry.ts- 2ツールの import と toolEntries への追加
Phase 4: ブログ記事
src/content/blog/2026-02-21-business-email-and-keigo-tools.md- ブログ記事
Phase 5: 検証
npm test- 全テスト通過確認npm run lint- lint 通過確認npm run build- ビルド成功確認
6. 注意事項(builder 向け)
- ToolCategory の変更は不要: 両ツールとも既存の "text" カテゴリで十分。types.ts を変更しない。
- テンプレート本文の品質: ビジネスメールのテンプレート本文は、実際のビジネスシーンで使えるレベルの品質にすること。形式的すぎず、かつカジュアルすぎない適切なトーンで作成する。
- 敬語データの正確性: 敬語の変換データは必ず正確であること。不確かなものは含めない。特に尊敬語と謙譲語の区別を絶対に間違えないこと。
- CSS変数の使用: color, background-color, border-color, font-family はすべてCSS変数(--color-text, --color-bg, --color-border, --color-primary, --color-text-muted, --color-bg-secondary, --font-mono)を使用すること。ハードコードされた色は使わない。
- コピーボタンのパターン: navigator.clipboard.writeText + copied state + setTimeout(2000) の既存パターンを踏襲する。
- 拡張性: テンプレートや敬語データの追加が、配列への要素追加だけで完結するよう設計すること。コンポーネント側のロジック変更は不要にする。
- 既存ツールとの相互参照: relatedSlugs を適切に設定し、ツール間の相互リンクを確保する。