Skip to content

feat(frontend): 職務経歴書の入力モーダル改善(即時保存・自己PR/職務要約の専用入力UI)#310

Merged
yusuke0610 merged 4 commits into
mainfrom
claude/project-modal-input-ui-nezQj
Jun 6, 2026
Merged

feat(frontend): 職務経歴書の入力モーダル改善(即時保存・自己PR/職務要約の専用入力UI)#310
yusuke0610 merged 4 commits into
mainfrom
claude/project-modal-input-ui-nezQj

Conversation

@yusuke0610

@yusuke0610 yusuke0610 commented Jun 6, 2026

Copy link
Copy Markdown
Owner

概要

職務経歴書フォームの入力体験を 2 点改善します。「Redux 更新」はフォーム一時キャッシュ(store/formCacheSlice)への即時反映を指し、サーバ永続化は従来どおりフォーム上部の保存ボタン経由です。

変更内容

1. プロジェクト編集モーダル: 即時保存 + × 閉じる

  • 「保存」ボタンを廃止し、入力のたびに即時 formCache へ反映(参照等価ガードで未編集時はコミットしない)。
  • 新規プロジェクトは初回入力時に 1 度だけ末尾追加し、確定 index を保持して重複生成を防止(useProjectModalState + getProjectCount 追加)。
  • 「キャンセル」→ × 閉じるボタン化。即時保存化に伴いモーダル内の未保存マーク(🔴)は撤去し、未参照になった useProjectFormDirty を削除。

2. 自己PR・職務要約の専用入力モーダル

  • インラインの大きな入力欄をやめ、フォーム本体は プレビュー + 編集ボタンMarkdownFieldTrigger)に集約。氏名はインライン維持。
  • 専用モーダル(MarkdownFieldModal): 左に大きな入力欄、右に取り込みファイル参照(ResumeSourceTracePanel 再利用)、右下に文字数カウント
  • 文字数は Markdown 記法・空白を除いた表示テキストで算出(**#・リンク URL 等は除外)。
  • 必須未入力で保存すると該当モーダルを自動オープン。

共通化 / その他

  • モーダル外枠を共通シェル components/ui/ModalShell に抽出し、ProjectModal と新モーダルで共有(DRY)。
  • MarkdownTextarea に高さ伸長用の fill オプションを追加(既定 off で既存挙動は不変)。
  • 文言は messages.tsMODAL_CLOSE / FIELD_NOT_ENTERED / charCountLabel)へ集約。

テスト

  • eslint クリーン / vitest 272 pass / tsc -b + vite build 成功
  • 新規フック契約・mutators・markdownToPlainText のユニットテスト追加
  • E2E: 既存スイート + 新規 career-field-modal.spec.ts(モーダル入力・文字数・自動オープン)すべて green

注意(要対応)

  • main に後から入った校正機能(proofread)と CareerResumeForm.tsx が競合します。マージ前に競合解消が必要です(別途対応可否を確認します)。

https://claude.ai/code/session_01S8gCEfqCqjRjC9kuLogy2M


Generated by Claude Code

Summary by CodeRabbit

  • New Features

    • Career summary and self PR now open in dedicated modal editors.
    • Project details auto-save as you edit in the modal.
    • Character count now displays in text input modals.
  • Tests

    • Added E2E tests for career field modal interactions.

claude added 2 commits June 6, 2026 12:30
プロジェクトモーダル:
- 保存ボタンを廃止し、入力のたびに formCache へ即時反映
- 新規プロジェクトは初回入力時に1度だけ追加し重複生成を防止
- キャンセルを × 閉じるボタンに変更、モーダル内の未保存マークを撤去

自己PR・職務要約:
- フォーム本体はプレビュー+編集ボタンに集約し、入力は専用モーダルへ分離
- モーダル右に取り込みファイル参照、右下に文字数カウント(空白除外)
- 必須未入力で保存時は該当モーダルを自動オープン

共通化・後始末:
- モーダル外枠を ModalShell(components/ui) に抽出し ProjectModal と共有
- 文字数カウントを utils/text.ts に分離
- 未参照になった useProjectFormDirty を削除

https://claude.ai/code/session_01S8gCEfqCqjRjC9kuLogy2M
自己PR・職務要約の文字数カウントを生文字数ではなく描画後の表示テキストの
文字数にする。`**` などの記法・リンクURL・空白はカウント対象から外す。

- utils/markdown.ts に markdownToPlainText を追加(renderMarkdown の sanitize 済み
  HTML を DOMParser で解釈し textContent を抽出。live DOM へは挿入しない)
- CharCount は countNonWhitespace(markdownToPlainText(value)) で算出
- markdownToPlainText のユニットテストを追加

https://claude.ai/code/session_01S8gCEfqCqjRjC9kuLogy2M
@coderabbitai

coderabbitai Bot commented Jun 6, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@yusuke0610, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 18 minutes and 37 seconds. Learn how PR review limits work.

Your organization has run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 7aaac12d-b1fe-46be-ae80-93164d79182e

📥 Commits

Reviewing files that changed from the base of the PR and between 818329a and a093778.

📒 Files selected for processing (9)
  • frontend/e2e/career-field-modal.spec.ts
  • frontend/src/components/forms/CareerResumeForm.tsx
  • frontend/src/components/forms/MarkdownFieldTrigger.module.css
  • frontend/src/components/forms/MarkdownFieldTrigger.tsx
  • frontend/src/components/forms/sections/CareerBasicInfoSection.tsx
  • frontend/src/components/forms/sections/CareerSelfPrSection.tsx
  • frontend/src/components/ui/ModalShell.module.css
  • frontend/src/components/ui/ModalShell.tsx
  • frontend/src/constants/messages.ts
📝 Walkthrough

Walkthrough

This PR refactors resume form editing by introducing a reusable modal shell component and moving inline markdown field editing (career summary, self-PR) into dedicated modals with auto-focused, full-height textareas and character counts. ProjectModal is simultaneously refactored to auto-save changes and delegate modal layout responsibility to the new ModalShell.

Changes

Modal-based markdown field editing with auto-save project workflows

Layer / File(s) Summary
Modal shell layout and reusable structure
frontend/src/components/ui/ModalShell.tsx, frontend/src/components/ui/ModalShell.module.css
New ModalShell component provides a responsive two-column modal layout with optional right sidebar (for PDF/source trace), draggable splitter, header with close button, and configurable import panel resizing. Styling supports responsive behavior on small/narrow screens.
Markdown field trigger and modal components
frontend/src/components/forms/MarkdownFieldTrigger.tsx, frontend/src/components/forms/MarkdownFieldTrigger.module.css, frontend/src/components/forms/MarkdownFieldModal.tsx
New MarkdownFieldTrigger displays a clickable preview button (with dirty/invalid/loading states) for markdown-backed fields; MarkdownFieldModal uses ModalShell to render a full-height textarea with auto-focus on validation error and live character count.
MarkdownTextarea fill layout support
frontend/src/components/forms/MarkdownTextarea.tsx, frontend/src/components/forms/MarkdownTextarea.module.css
MarkdownTextarea component extended with optional fill prop and supporting CSS to enable flex-based stretching within modal layouts without overflow.
Plain-text conversion and character counting utilities
frontend/src/utils/markdown.ts, frontend/src/utils/markdown.test.ts, frontend/src/utils/text.ts, frontend/src/utils/text.test.ts, frontend/src/components/ui/CharCount.tsx, frontend/src/components/ui/CharCount.module.css, frontend/src/constants/messages.ts
New utilities for converting markdown to plain text (for preview and character counting), counting non-whitespace characters, and a CharCount component that displays formatted character counts in the modal footer.
CareerResumeForm modal state and integration
frontend/src/components/forms/CareerResumeForm.tsx
Form introduces editingField state to track which markdown field is being edited, opens the corresponding MarkdownFieldModal on validation failure, and wires onEditCareerSummary and onEdit callbacks to child sections.
CareerBasicInfoSection and CareerSelfPrSection trigger-based editing
frontend/src/components/forms/sections/CareerBasicInfoSection.tsx, frontend/src/components/forms/sections/CareerSelfPrSection.tsx
Both sections switch from inline MarkdownTextarea to MarkdownFieldTrigger; CareerBasicInfoSection adds onEditCareerSummary callback, and CareerSelfPrSection replaces onChange with onEdit handler to open the modal.
ProjectModal render refactor and auto-save logic
frontend/src/components/forms/ProjectModal.tsx
ProjectModal refactored to use ModalShell instead of custom overlay, removes dirty indicators and explicit Save/Cancel buttons, introduces initialRef snapshot and useEffect that auto-saves on every local change, and delegates PDF column layout to ModalShell's assist prop.
Project modal state hook with getProjectCount
frontend/src/hooks/career/useProjectModalState.ts, frontend/src/hooks/career/useProjectModalState.test.ts
useProjectModalState hook now accepts getProjectCount callback and handles new project creation by computing indices; existing projects save immediately without closing the modal.
CareerExperienceSection and getProjectCount integration
frontend/src/components/forms/sections/CareerExperienceSection.tsx, frontend/src/hooks/career/useCareerExperienceMutators.ts, frontend/src/hooks/career/useCareerExperienceMutators.test.ts
CareerExperienceSection passes getProjectCount to useProjectModalState; useCareerExperienceMutators adds getProjectCount helper method to return current project count for a given experience/client coordinate.
ProjectModal test updates for auto-save and inline validation
frontend/src/components/forms/ProjectModal.test.tsx
ProjectModal tests updated to verify save button no longer exists, auto-save is triggered on field changes, and validation errors are displayed inline.
E2E tests for self-PR and career summary modal editing
frontend/e2e/career-field-modal.spec.ts
New Playwright E2E suite covering self-PR and career summary modal workflows: opening editor, editing with character count updates, closing modal, and verifying preview changes propagate to main form.
Updated E2E tests for ProjectModal dirty indicators
frontend/e2e/career-dirty-indicator.spec.ts
Existing dirty-indicator test refactored to reflect auto-save behavior: edits immediately propagate and dirty indicator visibility is verified without expecting multiple 🔴 instances.
Architecture documentation and CSS comment updates
.claude/rules/frontend/architecture.md, frontend/src/components/forms/ProjectModal.module.css
Architecture docs updated to remove useProjectFormDirty from hooks list; ProjectModal CSS header clarified to note that shared modal styles are in ModalShell.module.css.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~75 minutes

Possibly related PRs

  • yusuke0610/devforge#308: Modifies the same CareerResumeForm.tsx component—main PR rewires validation/submit to open MarkdownFieldModal, while #308 changes the same component's submit feedback to use toast notifications.
  • yusuke0610/devforge#300: Both refactor ProjectModal.tsx to replace the PDF trace panel layout with the import/original panel approach via ModalShell and useImportPanelLayout.
  • yusuke0610/devforge#306: Updates the resume diff preview endpoint (/api/resumes/preview) and diff modal behavior that the dirty-indicator E2E test in this PR depends on.

Poem

🐰 Whispers through the modal's gentle frame,
Modal shells now dance the same refrain,
Markdown fields in textareas take flight,
Character counts shimmer in the light,
Auto-saves keep dirty trackers bright!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main changes: improved career resume input modals with real-time saving and dedicated input UIs for self-PR and career summary fields.
Docstring Coverage ✅ Passed Docstring coverage is 89.47% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch claude/project-modal-input-ui-nezQj

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

main の校正機能(proofread)取り込みに伴う CareerResumeForm.tsx の競合を解消。
changes の baseline フォールバックは main 側のロジック(createInitialCareerForm())を採用。
入力モーダル関連の変更は維持。

https://claude.ai/code/session_01S8gCEfqCqjRjC9kuLogy2M

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 8

🧹 Nitpick comments (2)
frontend/src/components/forms/ProjectModal.test.tsx (1)

51-72: ⚡ Quick win

Consider adding test coverage for the "no-op on untouched modal" guard.

The test verifies that onSave is called immediately when input changes, but doesn't verify the critical guard mentioned in ProjectModal.tsx:150 — that opening and immediately closing the modal without edits prevents erroneous commits, especially during StrictMode double-execution.

🧪 Suggested additional test case
+  it("モーダルを開いて編集せず閉じた場合は onSave を呼ばない", () => {
+    const onSave = vi.fn();
+    const { unmount } = render(
+      <ProjectModal
+        project={emptyProject}
+        onSave={onSave}
+        onClose={vi.fn()}
+        techStackNamesByCategory={new Map()}
+      />,
+    );
+    // 何も編集せずアンマウント
+    unmount();
+    // onSave は一度も呼ばれていないこと
+    expect(onSave).not.toHaveBeenCalled();
+  });
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@frontend/src/components/forms/ProjectModal.test.tsx` around lines 51 - 72,
Add a test in ProjectModal.test.tsx that verifies the "no-op on untouched modal"
guard: render <ProjectModal project={emptyProject} onSave={onSave}
onClose={onClose} ... />, do not change any inputs, immediately close the modal
(simulate user closing by clicking the modal's close/cancel button via
screen.getByRole('button', { name: /閉じる|キャンセル/ }) or fallback to calling the
provided onClose mock), and assert onSave was not called (also repeat the
open->close sequence or render inside React.StrictMode to simulate
double-execution). Target the ProjectModal component and the onSave/onClose
mocks to locate where to add the assertion.
frontend/src/components/forms/ProjectModal.tsx (1)

152-157: Autosave useEffect guard/deps: reference-equality and onSave exclusion are consistent

  • local === initialRef.current is mount-scoped: useProjectModalForm initializes local once via initProject(project) (structuredClone) and every edit updates local with a new object reference, so the guard prevents the initial save (including React StrictMode’s double-mount).
  • Excluding onSave from the useEffect([local]) deps is safe in this setup: the effect only runs when local’s reference changes, and uses the onSave captured in the same render that produced that local (so onSave/handleProjectSave identity changes won’t cause re-saves by themselves). useProjectModalState also updates modalTarget.projIndex after the initial append, matching the intended “append once, then update” behavior.
  • Optional: avoid the eslint-disable by keeping onSave in a useRef and still triggering only on [local].
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@frontend/src/components/forms/ProjectModal.tsx` around lines 152 - 157, The
autosave effect currently disables eslint for excluding onSave; instead create a
stable ref for the callback (e.g., const onSaveRef = useRef(onSave)) and update
onSaveRef.current = onSave in a small effect or useLayoutEffect, then in the
autosave effect call onSaveRef.current(local) and remove the eslint-disable;
this keeps the guard using local and initialRef.current intact and avoids
depending on onSave while preserving the intended behavior in
useProjectModalForm / ProjectModal.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@frontend/e2e/career-field-modal.spec.ts`:
- Around line 3-4: Replace the hard-coded UI literal ("9 文字") in the e2e test
assertions with the shared SSoT formatter introduced in this PR (use the
charCountLabel helper or UI_MESSAGES.charCountLabel(...) instead of a literal);
update both occurrences (around the import area and the later assertion at line
~64) to call the formatter with the numeric count so the test derives its
expected string from the single source of truth.
- Around line 83-85: The assertion after clicking the save/update button is too
broad (await expect(page.locator("textarea")).toBeVisible()) and may match
unrelated textareas; narrow it to the specific 職務要約 field by asserting the
modal/field element directly (e.g., replace the textarea locator with a targeted
locator such as page.getByLabel("職務要約") or page.getByRole("textbox", { name:
/職務要約/ })) so the check verifies that the 職務要約 field/modal opened after await
page.getByRole("button", { name: /更新する|保存する/ }).click().

In `@frontend/src/components/forms/CareerResumeForm.tsx`:
- Around line 224-233: Replace the hardcoded title literals in
CareerResumeForm's MarkdownFieldModal with SSoT constants: add FIELD_SELF_PR =
"自己PR" and FIELD_CAREER_SUMMARY = "職務要約" to the messages/constants export
(frontend/src/constants/messages.ts), then change the title expression in
CareerResumeForm (where MarkdownFieldModal is rendered based on editingField) to
use those constants (e.g., editingField === "self_pr" ? messages.FIELD_SELF_PR :
messages.FIELD_CAREER_SUMMARY), keeping the existing onChange/onClose/invalid
logic intact.

In `@frontend/src/components/forms/MarkdownFieldTrigger.module.css`:
- Around line 15-34: The .trigger rule currently uses all: unset which removes
native focus outlines, so add a keyboard-visible focus style by defining
.trigger:focus-visible (and ensure the element is focusable) to restore an
accessible outline/box-shadow/border-color on keyboard focus; update the
.trigger selector usage where the button element is rendered (the trigger
element/class) to include tabindex or ensure it's a <button>, then add a
.trigger:focus-visible rule that sets a visible outline or border-color (e.g.,
var(--accent)) and optional box-shadow to match hover styling.

In `@frontend/src/components/forms/MarkdownFieldTrigger.tsx`:
- Line 63: Add a new SSoT constant EDIT_LABEL = "編集" (as const) to
frontend/src/constants/messages.ts, then replace the string literal "を編集" in
MarkdownFieldTrigger.tsx (the aria-label construction using label + "を編集") to
use the messages constant (concatenate label and the EDIT_LABEL constant) so the
displayed suffix comes from the centralized messages file; reference the
constant name EDIT_LABEL and the component MarkdownFieldTrigger.tsx when making
the change.
- Line 69: Replace the hard-coded label "編集" in the MarkdownFieldTrigger
component (the span using className={styles.editLabel}) with a SSoT message
constant: add EDIT_LABEL: "編集" to the messages constants file if it doesn't
exist, import the messages constant into MarkdownFieldTrigger, and use that
constant instead of the literal so the span renders messages.

In `@frontend/src/components/ui/ModalShell.module.css`:
- Around line 44-57: The .closeButton rule removes native focus but doesn't add
a replacement focus indicator; add a visible, high-contrast keyboard focus style
(use .closeButton:focus-visible) that restores an outline or ring/box-shadow
(matching the button's border-radius) and does not rely on color-only changes so
keyboard users can see focus; ensure you target :focus-visible rather than
:focus to avoid showing the indicator on mouse clicks and keep existing hover
styles intact.

In `@frontend/src/components/ui/ModalShell.tsx`:
- Around line 54-66: The ModalShell component's modal container (styles.modal)
needs proper ARIA and keyboard support: add role="dialog" and aria-modal="true"
to the modal div, add a useEffect hook that listens for 'Escape' keydown and
calls onClose (remember to import useEffect and include onClose in deps), and
implement focus trapping when the modal is open (use a small library like
focus-trap-react or a custom hook to move focus into the modal on open and
prevent Tab from escaping, and restore focus on close).

---

Nitpick comments:
In `@frontend/src/components/forms/ProjectModal.test.tsx`:
- Around line 51-72: Add a test in ProjectModal.test.tsx that verifies the
"no-op on untouched modal" guard: render <ProjectModal project={emptyProject}
onSave={onSave} onClose={onClose} ... />, do not change any inputs, immediately
close the modal (simulate user closing by clicking the modal's close/cancel
button via screen.getByRole('button', { name: /閉じる|キャンセル/ }) or fallback to
calling the provided onClose mock), and assert onSave was not called (also
repeat the open->close sequence or render inside React.StrictMode to simulate
double-execution). Target the ProjectModal component and the onSave/onClose
mocks to locate where to add the assertion.

In `@frontend/src/components/forms/ProjectModal.tsx`:
- Around line 152-157: The autosave effect currently disables eslint for
excluding onSave; instead create a stable ref for the callback (e.g., const
onSaveRef = useRef(onSave)) and update onSaveRef.current = onSave in a small
effect or useLayoutEffect, then in the autosave effect call
onSaveRef.current(local) and remove the eslint-disable; this keeps the guard
using local and initialRef.current intact and avoids depending on onSave while
preserving the intended behavior in useProjectModalForm / ProjectModal.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: b163034d-8d26-468a-9783-8087ecaef598

📥 Commits

Reviewing files that changed from the base of the PR and between f2f3513 and 818329a.

📒 Files selected for processing (30)
  • .claude/rules/frontend/architecture.md
  • frontend/e2e/career-dirty-indicator.spec.ts
  • frontend/e2e/career-field-modal.spec.ts
  • frontend/src/components/forms/CareerResumeForm.tsx
  • frontend/src/components/forms/MarkdownFieldModal.tsx
  • frontend/src/components/forms/MarkdownFieldTrigger.module.css
  • frontend/src/components/forms/MarkdownFieldTrigger.tsx
  • frontend/src/components/forms/MarkdownTextarea.module.css
  • frontend/src/components/forms/MarkdownTextarea.tsx
  • frontend/src/components/forms/ProjectModal.module.css
  • frontend/src/components/forms/ProjectModal.test.tsx
  • frontend/src/components/forms/ProjectModal.tsx
  • frontend/src/components/forms/sections/CareerBasicInfoSection.tsx
  • frontend/src/components/forms/sections/CareerExperienceSection.tsx
  • frontend/src/components/forms/sections/CareerSelfPrSection.tsx
  • frontend/src/components/ui/CharCount.module.css
  • frontend/src/components/ui/CharCount.tsx
  • frontend/src/components/ui/ModalShell.module.css
  • frontend/src/components/ui/ModalShell.tsx
  • frontend/src/constants/messages.ts
  • frontend/src/hooks/career/useCareerExperienceMutators.test.ts
  • frontend/src/hooks/career/useCareerExperienceMutators.ts
  • frontend/src/hooks/career/useProjectFormDirty.test.ts
  • frontend/src/hooks/career/useProjectFormDirty.ts
  • frontend/src/hooks/career/useProjectModalState.test.ts
  • frontend/src/hooks/career/useProjectModalState.ts
  • frontend/src/utils/markdown.test.ts
  • frontend/src/utils/markdown.ts
  • frontend/src/utils/text.test.ts
  • frontend/src/utils/text.ts
💤 Files with no reviewable changes (2)
  • frontend/src/hooks/career/useProjectFormDirty.test.ts
  • frontend/src/hooks/career/useProjectFormDirty.ts

Comment thread frontend/e2e/career-field-modal.spec.ts Outdated
Comment thread frontend/e2e/career-field-modal.spec.ts
Comment thread frontend/src/components/forms/CareerResumeForm.tsx
Comment thread frontend/src/components/forms/MarkdownFieldTrigger.module.css
Comment thread frontend/src/components/forms/MarkdownFieldTrigger.tsx Outdated
Comment thread frontend/src/components/forms/MarkdownFieldTrigger.tsx Outdated
Comment thread frontend/src/components/ui/ModalShell.module.css
Comment thread frontend/src/components/ui/ModalShell.tsx
CodeRabbit のレビュー指摘のうち妥当なものを反映。

- ModalShell に role="dialog" / aria-modal / aria-labelledby と Escape での
  クローズを追加(ProjectModal・入力モーダル共通でキーボード操作性を改善)
- ModalShell / MarkdownFieldTrigger のボタンに :focus-visible を追加し
  キーボードフォーカスを可視化(all:unset で消えたネイティブ outline の代替)
- 自己PR / 職務要約 / 編集 ラベルを messages.ts の定数(FIELD_SELF_PR /
  FIELD_CAREER_SUMMARY / EDIT)へ集約し、各所のリテラルを置換
- e2e: 文字数アサートを charCountLabel(9) に、自動オープン確認をモーダル
  タイトル完全一致に変更(SSoT 化・対象限定)

focus-trap(タブ移動の閉じ込め)は依存追加を伴うため本PRの範囲外とする。

https://claude.ai/code/session_01S8gCEfqCqjRjC9kuLogy2M
@yusuke0610
yusuke0610 merged commit 5d2e061 into main Jun 6, 2026
18 checks passed
@yusuke0610
yusuke0610 deleted the claude/project-modal-input-ui-nezQj branch June 10, 2026 05:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants