ポートフォリオサイトの管理画面において、ブログ記事の執筆・編集を快適にするためにおこなった改善の全内容を、仕様と理由を含めて詳しくまとめました。
ポートフォリオサイトの管理画面では、ブログ記事を Markdown で執筆・編集できます。本記事では、スラッグの扱い、Markdown 編集 UI(ツールバー・プレビュー・文字数)、画像の挿入・サイズ・注記・中央揃え、および本文内画像の GUI 編集まで、おこなった改善をすべて詳細にまとめます。
改善内容
新規記事を作成するとき、スラッグ欄の初期値を 「年月日-時:分」 形式(例: 2026-02-14-17:30)にしました。
理由
以前は空欄から入力していたため、毎回スラッグを考える手間がありました。日時ベースにすることで一意になりやすく、かつ「いつ書いたか」がスラッグから分かるようにしています。
仕様
getFullYear(), getMonth()+1, getDate(), getHours(), getMinutes() をゼロ埋めした YYYY-MM-DD-HH:mm です。改善内容
入力中のスラッグが 他の記事ですでに使われている場合、本文エリアの直下に警告文を表示するようにしました。
表示例
「重複: このスラッグは既に別の記事で使われています。保存するとその記事を上書きします。」
仕様
existingSlugs)を取得し、フォームに渡しています。oldSlug)と一致する場合は警告を出しません。別記事と重複したときだけ表示します。改善内容
slug.trim() を必ず使い、空のときにフォールバックで "post" になる仕様は残しつつ、空欄では送信できないようにしたため、意図せず "post" で保存されることはありません。理由
スラッグをいったん消して別のスラッグを打ち直す途中で保存すると、空のまま slug || slugFromTitle(title) || "post" が評価され、"post" で上書きされる事象を防ぐためです。
改善内容
既存記事を編集するときも スラッグ欄を編集可能にしました。あわせて、説明文で「編集可能です。既存のスラッグと重複すると上書きされます(重複時は下に警告表示)。」と明示しています。
理由
重複を解消したり、URL を後から整えたりするために、スラッグを変更できる必要があるためです。変更時は API に oldSlug を渡し、ファイル名のリネームやパスの置換が行われる仕組みになっています。
改善内容
本文エリアの直上に 書式用ツールバー を追加しました。クリックでカーソル位置や選択範囲に Markdown を挿入できます。
対応している書式
** で囲む。未選択時は ** を 2 つ挿入。* で囲む。` で囲む。## または ### を挿入。\n- を挿入。\n1. を挿入。\n> を挿入。[テキスト](URL) を挿入。``` で囲んだ空ブロックを挿入。実装のポイント
insertWrap(before, after) で囲み、ない場合は insertAtCursor(text) で挿入しています。lucide-react(Bold, Italic, Code, Heading2, Heading3, List, ListOrdered, Quote, Link, Image, SquareCode)を使用しています。改善内容
ツールバーの「リンク」ボタンで、表示テキストと URL を入力するダイアログを表示し、「挿入」で [表示テキスト](URL) をカーソル位置に挿入するようにしました。
仕様
# をデフォルト値として使用します。改善内容
表示モード切替(タブ/分割)の横に、本文の文字数(content.length)を「〇〇 文字」の形式で表示するようにしました。
理由
記事のボリューム感を把握しやすくし、執筆の目安にできるようにするためです。
改善内容
ユーザーが 「タブ」 と 「分割」 のどちらで編集・プレビューを表示するかを選べるようにしました。
タブ
分割
md:grid-cols-2)。改善内容
画像をアップロードしたあと、挿入前に 次の項目を指定できるダイアログを表示するようにしました。
挿入される形式
 を挿入。<figure> ブロックを挿入します(<img> に width 属性、必要に応じて <figcaption> 付き)。改善内容
画像の「幅」を、選択式ではなくユーザーが直接入力する形式に変更しました。
仕様
width 属性に反映するため、50% や 400 などを自由に指定できます。改善内容
本文テキストエリアの 下 に、「本文内の画像」用の編集エリアを追加しました。
画像の抽出
<figure>…<img …>…<figcaption>…</figcaption></figure>一覧表示
編集フロー
実装のポイント
<figure> ブロックを Markdown の  に戻して挿入します。改善内容
画像の「注記」を保存したあと、再度「編集」を開いても キャプションが正しく表示・編集できるようにしました。
原因
&, <, > など)して書き込んでいました。対応
parseImagesInContent 内で、<figcaption> の内容を取り出したあと、HTML 実体をデコードする処理を追加しました(&→&, <→<, >→>, "→", '→')。alt 属性も同様にデコードし、再編集時に正しく表示されるようにしています。改善内容
管理画面の Markdown プレビューで、<figure>, <img>, <figcaption> などの HTML がそのままレンダリングされるようにしました。
仕様
ReactMarkdown の rehypePlugins={[rehypeRaw]} で生の HTML を解釈しています。<figure> ブロックがプレビュー上でも図として表示されます。改善内容
ブログ本文および管理画面プレビューで、画像とキャプションが中央揃えで表示されるようにしました。
ブログ本文(MdxComponents)
figure: flex flex-col items-center を付与し、子要素(img と figcaption)を中央に配置。img: ラッパーに flex justify-center を付与し、画像自体を中央に配置(Markdown の  および figure 内の img の両方)。管理画面プレビュー(MarkdownPreview)
ReactMarkdown にカスタム components を渡しました。
figure: className に my-4 flex flex-col items-center を付与。img: flex justify-center の span で囲み、中央に表示。figcaption: text-center を付与。挿入する HTML
<figure> のクラスを、my-4 flex flex-col items-center に統一し、本番・プレビューどちらでも中央揃えになるようにしています。ブログ以外の管理画面についても、以下の改善をおこなっています(ブログ執筆体験とあわせて把握しやすいよう簡潔に記載します)。
dirty を true にし、保存成功時に false に戻しています。/api/admin/upload-project-image)を用意し、public/images/projects/{projectId}/ および public/images/projects/{projectId}/sub/{subId}/ に保存しています。。<figure className="my-4 flex flex-col items-center"> のなかに <img src="..." alt="..." width="..." /> と、必要に応じて <figcaption className="...">...</figcaption> を入れた HTML ブロックとして保存しています。<, >, & は保存時に HTML エスケープし、表示・再編集時にデコードして利用しています。以上が、管理画面のブログエディタおよび関連機能に対しておこなった改善の詳細です。スラッグの扱い、Markdown の書きやすさ、画像の挿入・編集・表示の一貫性を意識してまとめています。追加の要望や不具合があれば、管理画面の運用を踏まえて順次対応していく想定です。