diff --git a/assets/locale/en.toml b/assets/locale/en.toml index 9df98d1..c53a136 100644 --- a/assets/locale/en.toml +++ b/assets/locale/en.toml @@ -18,6 +18,9 @@ update = "Update available" update_detail = "%s is available (current: %s)" update_hint = "Run `eitango version` to see release details" keys = "Tab=mode Enter=start/resume n=new r=review s=stats c=settings q=quit" +key_start = "start" +key_toggle_mode = "mode" +key_new = "new" [settings] title = "Home settings" diff --git a/assets/locale/ja.toml b/assets/locale/ja.toml index fbe97f3..172ef27 100644 --- a/assets/locale/ja.toml +++ b/assets/locale/ja.toml @@ -18,6 +18,9 @@ update = "更新があります" update_detail = "%s を利用できます (現在: %s)" update_hint = "`eitango version` でリリース情報を確認できます" keys = "Tab=回答方式 Enter=開始/再開 n=新規 r=復習 s=統計 c=設定 q=終了" +key_start = "開始" +key_toggle_mode = "方式切替" +key_new = "新規" [settings] title = "ホーム設定" diff --git a/internal/app/view.go b/internal/app/view.go index 440e419..156406b 100644 --- a/internal/app/view.go +++ b/internal/app/view.go @@ -83,16 +83,7 @@ func (m RootModel) renderHome() string { } lines = append(lines, "", - m.styles.Muted.Render(m.renderInlineGuides( - keymap.ContextHome, - keymap.ActionToggleAnswerMode, - keymap.ActionConfirm, - keymap.ActionNewSession, - keymap.ActionReview, - keymap.ActionStats, - keymap.ActionSettings, - keymap.ActionQuit, - )), + m.styles.Muted.Render(m.renderHomeGuides()), ) return m.styles.Panel.Render(strings.Join(lines, "\n")) } @@ -848,17 +839,67 @@ func (m RootModel) binding(ctx keymap.Context, action keymap.Action) key.Binding } func (m RootModel) renderInlineGuides(ctx keymap.Context, actions ...keymap.Action) string { + return m.renderActionGuides(ctx, nil, actions...) +} + +func (m RootModel) renderActionGuides(ctx keymap.Context, labels map[keymap.Action]string, actions ...keymap.Action) string { parts := make([]string, 0, len(actions)) for _, action := range actions { - help := m.binding(ctx, action).Help() - if help.Key == "" || help.Desc == "" { + keys := m.keymap.Keys(ctx, action) + if labels != nil { + if part, ok := renderBracketedGuide(keys, labels[action]); ok { + parts = append(parts, part) + } + continue + } + if len(keys) == 0 { continue } - parts = append(parts, fmt.Sprintf("%s=%s", help.Key, help.Desc)) + help := m.binding(ctx, action).Help() + if help.Key != "" && help.Desc != "" { + parts = append(parts, fmt.Sprintf("%s=%s", help.Key, help.Desc)) + } } return strings.Join(parts, " ") } +type homeGuideItem struct { + action keymap.Action + label string +} + +func (m RootModel) renderHomeGuides() string { + primary := m.renderHomeGuideLine( + homeGuideItem{action: keymap.ActionConfirm, label: i18n.T(i18n.HomeKeyStart)}, + homeGuideItem{action: keymap.ActionToggleAnswerMode, label: i18n.T(i18n.HomeKeyToggleMode)}, + homeGuideItem{action: keymap.ActionQuit, label: i18n.T(i18n.KeyQuit)}, + ) + secondary := m.renderHomeGuideLine( + homeGuideItem{action: keymap.ActionNewSession, label: i18n.T(i18n.HomeKeyNew)}, + homeGuideItem{action: keymap.ActionReview, label: i18n.T(i18n.KeyReview)}, + homeGuideItem{action: keymap.ActionStats, label: i18n.T(i18n.KeyStats)}, + homeGuideItem{action: keymap.ActionSettings, label: i18n.T(i18n.KeySettings)}, + ) + return strings.TrimSpace(strings.Join([]string{primary, secondary}, "\n")) +} + +func (m RootModel) renderHomeGuideLine(items ...homeGuideItem) string { + actions := make([]keymap.Action, 0, len(items)) + labels := make(map[keymap.Action]string, len(items)) + for _, item := range items { + actions = append(actions, item.action) + labels[item.action] = item.label + } + return m.renderActionGuides(keymap.ContextHome, labels, actions...) +} + +func renderBracketedGuide(keys []string, label string) (string, bool) { + if len(keys) == 0 || label == "" { + return "", false + } + return fmt.Sprintf("[%s]%s", keymap.FormatKeys([]string{keys[0]}), label), true +} + func (m RootModel) keymapFilterLabel(filter keymap.Context) string { if filter == "" { return i18n.T(i18n.KeymapFilterAll) diff --git a/internal/app/view_test.go b/internal/app/view_test.go index 66c827b..8a20446 100644 --- a/internal/app/view_test.go +++ b/internal/app/view_test.go @@ -221,6 +221,23 @@ func TestRenderHomeShowsWaitToday(t *testing.T) { if !strings.Contains(got, i18n.T(i18n.AnswerModeWrite)) { t.Fatalf("renderHome() missing selected answer mode:\n%s", got) } + primary := model.renderHomeGuideLine( + homeGuideItem{action: keymap.ActionConfirm, label: i18n.T(i18n.HomeKeyStart)}, + homeGuideItem{action: keymap.ActionToggleAnswerMode, label: i18n.T(i18n.HomeKeyToggleMode)}, + homeGuideItem{action: keymap.ActionQuit, label: i18n.T(i18n.KeyQuit)}, + ) + if !strings.Contains(got, primary) { + t.Fatalf("renderHome() missing primary compact key guide:\n%s", got) + } + secondary := model.renderHomeGuideLine( + homeGuideItem{action: keymap.ActionNewSession, label: i18n.T(i18n.HomeKeyNew)}, + homeGuideItem{action: keymap.ActionReview, label: i18n.T(i18n.KeyReview)}, + homeGuideItem{action: keymap.ActionStats, label: i18n.T(i18n.KeyStats)}, + homeGuideItem{action: keymap.ActionSettings, label: i18n.T(i18n.KeySettings)}, + ) + if !strings.Contains(got, secondary) { + t.Fatalf("renderHome() missing secondary compact key guide:\n%s", got) + } } func TestRenderHomeLocalizesActiveSessionMode(t *testing.T) { diff --git a/internal/i18n/i18n_test.go b/internal/i18n/i18n_test.go index daf6c2a..e68d407 100644 --- a/internal/i18n/i18n_test.go +++ b/internal/i18n/i18n_test.go @@ -84,6 +84,7 @@ func TestAllJAKeysExistInEN(t *testing.T) { i18n.HomeConfirmBody, i18n.HomeConfirmCurrent, i18n.HomeConfirmTarget, i18n.HomeConfirmKeys, i18n.HomeUpdate, i18n.HomeUpdateDetail, i18n.HomeUpdateHint, i18n.HomeKeys, + i18n.HomeKeyStart, i18n.HomeKeyToggleMode, i18n.HomeKeyNew, i18n.SettingsTitle, i18n.SettingsQuestions, i18n.SettingsWriteDifficulty, i18n.SettingsWriteDifficultyBasic, i18n.SettingsWriteDifficultyHard, i18n.SettingsAudioEnabled, i18n.SettingsAudioAutoplay, diff --git a/internal/i18n/keys.go b/internal/i18n/keys.go index a74362e..6931430 100644 --- a/internal/i18n/keys.go +++ b/internal/i18n/keys.go @@ -22,6 +22,9 @@ const ( HomeUpdateDetail = "home.update_detail" HomeUpdateHint = "home.update_hint" HomeKeys = "home.keys" + HomeKeyStart = "home.key_start" + HomeKeyToggleMode = "home.key_toggle_mode" + HomeKeyNew = "home.key_new" ) // Home settings overlay