diff --git a/apps/desktop/src/features/workspace/SectionRoadmap.test.tsx b/apps/desktop/src/features/workspace/SectionRoadmap.test.tsx
index 5b32019d2..fe4583873 100644
--- a/apps/desktop/src/features/workspace/SectionRoadmap.test.tsx
+++ b/apps/desktop/src/features/workspace/SectionRoadmap.test.tsx
@@ -36,6 +36,24 @@ describe("SectionRoadmap", () => {
expect(screen.getAllByText("verse 들어가기 전에 이 음역을 악기로 확인해 보세요.").length).toBeGreaterThan(0);
});
+ it("keeps unavailable chord edits focusable, visibly described, semantically disabled, and inert", () => {
+ setNavigatorLanguage("ko-KR");
+ const song = createDemoRehearsalSong();
+ const promptSpy = vi.spyOn(window, "prompt");
+
+ render();
+
+ const description = screen.getByText("이 화면에서는 코드를 수정할 수 없습니다.");
+ const button = screen.getByRole("button", { name: "Bass Guitar의 verse 코드 수정, 현재 C#m7" });
+ expect(button.getAttribute("aria-disabled")).toBe("true");
+ expect(button.hasAttribute("disabled")).toBe(false);
+ expect(button.tabIndex).toBe(0);
+ expect(button.getAttribute("aria-describedby")).toBe(description.id);
+
+ fireEvent.click(button);
+ expect(promptSpy).not.toHaveBeenCalled();
+ });
+
it("omits the range row when both notes are unnamed", () => {
setNavigatorLanguage("en-US");
const song = createDemoRehearsalSong();
@@ -90,7 +108,6 @@ describe("SectionRoadmap", () => {
fireEvent.click(screen.getByRole("button", { name: "Bass Guitar의 verse 코드 수정, 현재 C#m7" }));
expect(promptSpy).toHaveBeenCalledWith("새 코드 입력:", "C#m7");
- expect(screen.getAllByTitle("코드 수정").length).toBeGreaterThan(0);
expect(onSongUpdate).toHaveBeenCalledTimes(1);
});
diff --git a/apps/desktop/src/features/workspace/SectionRoadmap.tsx b/apps/desktop/src/features/workspace/SectionRoadmap.tsx
index 834d1e8f0..35daff920 100644
--- a/apps/desktop/src/features/workspace/SectionRoadmap.tsx
+++ b/apps/desktop/src/features/workspace/SectionRoadmap.tsx
@@ -6,6 +6,7 @@ import { fillRangeCopy, playableRange } from "./firstRangeSqueeze";
import { Card, CardContent, CardHeader } from "@/components/ui/card";
import { Badge } from "@/components/ui/badge";
import { Separator } from "@/components/ui/separator";
+import { Tooltip, TooltipContent, TooltipTrigger } from "@/components/ui/tooltip";
import { AlertCircle, CheckCircle2, Music2, Wand2, Lightbulb, Info } from "lucide-react";
interface SectionRoadmapProps {
@@ -17,6 +18,7 @@ interface SectionRoadmapProps {
/** Documented. */
export function SectionRoadmap({ song, activeRole, onSongUpdate }: SectionRoadmapProps) {
const sectionRoadmapTitleId = useId();
+ const chordEditDisabledDescriptionId = useId();
const locale = useMemo(() => detectPreferredLocale(), []);
const t = useMemo(() => createTranslator(locale), [locale]);
@@ -90,12 +92,19 @@ export function SectionRoadmap({ song, activeRole, onSongUpdate }: SectionRoadma
return (
-
-
-
- {t("sectionRoadmapTitle")}
-
-
{t("sectionRoadmapScrollHint")}
+
+
+
+
+ {t("sectionRoadmapTitle")}
+
+ {!onSongUpdate && (
+
+ {t("chordEditDisabledExplanation")}
+
+ )}
+
+
{t("sectionRoadmapScrollHint")}
{t("sectionChordLabel")}
-
+
+ {
+ if (!onSongUpdate) return;
+ handleChordEdit(section.id, role);
+ }}
+ aria-disabled={!onSongUpdate ? "true" : undefined}
+ >
+ {role.harmony.chord}
+
+
+ {onSongUpdate ? t("chordEditTitle") : t("chordEditDisabledExplanation")}
+
+
{role.harmony.source === "user" && (
{t("harmonySourceUserBadge")}
diff --git a/apps/desktop/src/locales/en/common.json b/apps/desktop/src/locales/en/common.json
index d803a765e..c7d4ab595 100644
--- a/apps/desktop/src/locales/en/common.json
+++ b/apps/desktop/src/locales/en/common.json
@@ -59,6 +59,7 @@
"chordEditAriaLabel": "Edit chord for {roleName} in {sectionLabel}, current {chord}",
"chordEditPrompt": "Enter new chord:",
"chordEditTitle": "Click to edit chord",
+ "chordEditDisabledExplanation": "Chord editing is not available in this view.",
"harmonySourceUserBadge": "User",
"roleSwitcherTitle": "Role-specific View",
"allRoles": "All Roles",
diff --git a/apps/desktop/src/locales/ko/common.json b/apps/desktop/src/locales/ko/common.json
index 0f6c6c66d..b50bbef06 100644
--- a/apps/desktop/src/locales/ko/common.json
+++ b/apps/desktop/src/locales/ko/common.json
@@ -59,6 +59,7 @@
"chordEditAriaLabel": "{roleName}의 {sectionLabel} 코드 수정, 현재 {chord}",
"chordEditPrompt": "새 코드 입력:",
"chordEditTitle": "코드 수정",
+ "chordEditDisabledExplanation": "이 화면에서는 코드를 수정할 수 없습니다.",
"harmonySourceUserBadge": "사용자",
"roleSwitcherTitle": "악기/보컬 역할",
"allRoles": "전체 보기",