Skip to content

Commit 848bb16

Browse files
feat(ui): add GitHub discussions shortcut and redesign empty state
- Add dedicated keybinding and UI elements for GitHub Discussions - Redesign the empty state with a centered layout and new iconography - Improve theme legibility by updating the Nord theme's muted color - Refactor footer labels for better clarity and consistency
1 parent 2cf6353 commit 848bb16

9 files changed

Lines changed: 58 additions & 45 deletions

File tree

CHANGELOG.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,14 @@ All notable changes to this project will be documented in this file.
55
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
66
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

8+
## [1.2.3]
9+
10+
### Added
11+
12+
* **GitHub Discussions (`u`)**: Added dedicated shortcut to open the project's GitHub Discussions page.
13+
* **Empty State Redesign**: Removed the box border in the empty state and introduced an attractive, centered layout with a minimalist rocket icon and inspiring prompt.
14+
* **Theme Improvements**: Updated the `Nord` theme's muted color to a more prominent tone for improved legibility.
15+
816
## [1.2.2]
917

1018
### Added

configs/kairo.example.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,4 +51,5 @@ open_plugin_dir = "ctrl+g"
5151
toggle_strike = "z"
5252
help = "?"
5353
issues = "i"
54+
discussions = "u"
5455
changelog = "c"

internal/app/model.go

Lines changed: 25 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -751,6 +751,9 @@ func (m *Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
751751
if keymapMatch(m.km.Issues, km) {
752752
return m, openURLCmd("https://github.com/programmersd21/kairo/issues")
753753
}
754+
if keymapMatch(m.km.Discussions, km) {
755+
return m, openURLCmd("https://github.com/programmersd21/kairo/discussions")
756+
}
754757
if keymapMatch(m.km.Changelog, km) {
755758
return m, openURLCmd("https://github.com/programmersd21/kairo/blob/main/CHANGELOG.md")
756759
}
@@ -1185,34 +1188,36 @@ func (m *Model) renderFooter() string {
11851188
case ModeTagFilter:
11861189
left = " " + m.s.Muted.Render("enter "+styles.IconDone+"apply • esc "+styles.IconClose+"cancel • ctrl+u clear")
11871190
case ModeDetail:
1188-
left = " " + m.s.Muted.Render(
1191+
left = " " + m.s.Accent.Background(m.s.Theme.Bg).Render(
11891192
fk(m.km.Back)+" "+styles.IconBack+"back • "+
11901193
fk(m.km.EditTask)+" "+styles.IconEdit+"edit • "+
1191-
fk(m.km.Palette)+" "+styles.IconPalette+"pal • "+
1194+
fk(m.km.Palette)+" "+styles.IconPalette+"palette • "+
11921195
fk(m.km.Help)+" "+styles.IconHelp+"help • "+
1193-
fk(m.km.Issues)+" "+styles.IconIssues+"iss • "+
1194-
fk(m.km.Changelog)+" "+styles.IconChangelog+"log",
1196+
fk(m.km.Issues)+" "+styles.IconIssues+"issues • "+
1197+
fk(m.km.Discussions)+" "+styles.IconDiscuss+"discussions • "+
1198+
fk(m.km.Changelog)+" "+styles.IconChangelog+"changelog",
11951199
)
11961200
case ModeEditor:
1197-
left = " " + m.s.Muted.Render("ctrl+s "+styles.IconDone+"save • esc "+styles.IconClose+"cls • tab nav")
1201+
left = " " + m.s.Muted.Render("ctrl+s "+styles.IconDone+"save • esc "+styles.IconClose+"cancel • tab nav")
11981202
case ModePalette:
1199-
left = " " + m.s.Muted.Render("enter "+styles.IconEnter+"sel • esc/p "+styles.IconClose+"cls • "+styles.IconUp+styles.IconDown+" nav")
1203+
left = " " + m.s.Muted.Render("enter "+styles.IconEnter+"select • esc/p "+styles.IconClose+"cancel • "+styles.IconUp+styles.IconDown+" nav")
12001204
case ModeHelp:
1201-
left = " " + m.s.Muted.Render("esc/q/"+fk(m.km.Help)+" "+styles.IconClose+"cls")
1205+
left = " " + m.s.Muted.Render("esc/q/"+fk(m.km.Help)+" "+styles.IconClose+"cancel")
12021206
case ModeThemeMenu:
1203-
left = " " + m.s.Muted.Render("enter "+styles.IconDone+"sel • esc/q/"+fk(m.km.CycleTheme)+" "+styles.IconClose+"cls • "+styles.IconUp+styles.IconDown+" nav")
1207+
left = " " + m.s.Muted.Render("enter "+styles.IconDone+"select • esc/q/"+fk(m.km.CycleTheme)+" "+styles.IconClose+"cancel • "+styles.IconUp+styles.IconDown+" nav")
12041208
case ModePluginMenu:
1205-
left = " " + m.s.Muted.Render("enter det • u uninst • o open • r reload • p/"+fk(m.km.ManagePlugins)+" "+styles.IconClose+"cls • "+styles.IconUp+styles.IconDown+" nav")
1209+
left = " " + m.s.Muted.Render("enter detail • u uninstall • o open • r reload • p/"+fk(m.km.ManagePlugins)+" "+styles.IconClose+"cancel • "+styles.IconUp+styles.IconDown+" nav")
12061210
default:
1207-
left = " " + m.s.Muted.Render(
1208-
fk(m.km.Palette)+" "+styles.IconPalette+"pal • "+
1211+
left = " " + m.s.Accent.Background(m.s.Theme.Bg).Render(
1212+
fk(m.km.Palette)+" "+styles.IconPalette+"palette • "+
12091213
fk(m.km.NewTask)+" "+styles.IconNew+"new • "+
12101214
"f "+styles.IconTag+"tag • "+
12111215
fk(m.km.ToggleStrike)+" "+styles.IconStrike+"done • "+
1212-
fk(m.km.DeleteTask)+" "+styles.IconDelete+"del • "+
1216+
fk(m.km.DeleteTask)+" "+styles.IconDelete+"delete • "+
12131217
fk(m.km.Help)+" "+styles.IconHelp+"help • "+
1214-
fk(m.km.Issues)+" "+styles.IconIssues+"iss • "+
1215-
fk(m.km.Changelog)+" "+styles.IconChangelog+"log",
1218+
fk(m.km.Issues)+" "+styles.IconIssues+"issues • "+
1219+
fk(m.km.Discussions)+" "+styles.IconDiscuss+"discussions • "+
1220+
fk(m.km.Changelog)+" "+styles.IconChangelog+"changelog",
12161221
)
12171222
}
12181223

@@ -1221,14 +1226,14 @@ func (m *Model) renderFooter() string {
12211226
icon := styles.IconInfo
12221227
if m.isErr {
12231228
icon = styles.IconError
1224-
right = m.s.Muted.Foreground(m.s.Theme.Bad).Bold(true).Render(icon+" ") + m.s.Muted.Render(m.statusText+" ")
1229+
right = m.s.Accent.Background(m.s.Theme.Bg).Render(icon + " " + m.statusText + " ")
12251230
} else {
1226-
right = m.s.Muted.Foreground(m.s.Theme.Good).Bold(true).Render(icon+" ") + m.s.Muted.Render(m.statusText+" ")
1231+
right = m.s.Accent.Background(m.s.Theme.Bg).Render(icon + " " + m.statusText + " ")
12271232
}
12281233
} else {
1229-
syncStatus := ""
1234+
syncLogo := ""
12301235
if m.syncEngine != nil && m.syncEngine.Enabled() {
1231-
syncStatus = styles.IconSync + " "
1236+
syncLogo = styles.IconSync + " "
12321237
}
12331238

12341239
versionText := buildinfo.VersionTag()
@@ -1241,11 +1246,9 @@ func (m *Model) renderFooter() string {
12411246
if !strings.HasPrefix(lat, "v") {
12421247
lat = "v" + lat
12431248
}
1244-
versionText = fmt.Sprintf("Update: %s → %s (run `kairo update`)", cur, lat)
1245-
right = m.s.Muted.Foreground(m.s.Theme.Accent).Bold(true).Render(syncStatus + versionText + " ")
1246-
} else {
1247-
right = m.s.Muted.Render(syncStatus + versionText + " ")
1249+
versionText = fmt.Sprintf("Update: %s → %s", cur, lat)
12481250
}
1251+
right = m.s.Accent.Background(m.s.Theme.Bg).Render(syncLogo + versionText + " ")
12491252
}
12501253

12511254
line := render.BarLine(left, right, m.width, m.s.Theme.Bg)

internal/config/config.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ type KeymapConfig struct {
8080
ToggleStrike string `toml:"toggle_strike"`
8181
Help string `toml:"help"`
8282
Issues string `toml:"issues"`
83+
Discussions string `toml:"discussions"`
8384
Changelog string `toml:"changelog"`
8485
}
8586

@@ -138,6 +139,7 @@ func Default() Config {
138139
ToggleStrike: "z",
139140
Help: "?",
140141
Issues: "i",
142+
Discussions: "u",
141143
Changelog: "c",
142144
},
143145
}
@@ -265,6 +267,9 @@ func Load() (Config, error) {
265267
if cfg.Keymap.Issues == "" {
266268
cfg.Keymap.Issues = defaults.Keymap.Issues
267269
}
270+
if cfg.Keymap.Discussions == "" {
271+
cfg.Keymap.Discussions = defaults.Keymap.Discussions
272+
}
268273
if cfg.Keymap.Changelog == "" {
269274
cfg.Keymap.Changelog = defaults.Keymap.Changelog
270275
}

internal/ui/help/model.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,8 @@ func (m Model) View() string {
9191
{getK(m.km.ManagePlugins), styles.IconPlugin + "Manage plugins"},
9292
{getK(m.km.Help), styles.IconHelp + "Show help"},
9393
{getK(m.km.Issues), styles.IconIssues + "Open GitHub issues"},
94-
{getK(m.km.Changelog), styles.IconChangelog + "Show changelog"},
94+
{getK(m.km.Discussions), styles.IconDiscuss + "Open GitHub discussions"},
95+
{getK(m.km.Changelog), styles.IconChangelog + "Open changelog"},
9596
{getK(m.km.Quit), "󰈆 " + "Quit"},
9697
},
9798
},

internal/ui/keymap/keymap.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ type Keymap struct {
3131
ToggleStrike key.Binding
3232
Help key.Binding
3333
Issues key.Binding
34+
Discussions key.Binding
3435
Changelog key.Binding
3536
}
3637

@@ -58,6 +59,7 @@ func FromConfig(c config.KeymapConfig) Keymap {
5859
ToggleStrike: bind(c.ToggleStrike, "strike", "toggle completion with animation"),
5960
Help: bind(c.Help, "help", "show help"),
6061
Issues: bind(c.Issues, "issues", "open github issues"),
62+
Discussions: bind(c.Discussions, "discussions", "open github discussions"),
6163
Changelog: bind(c.Changelog, "changelog", "open changelog"),
6264
}
6365
}

internal/ui/styles/styles.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ const (
4242
IconUp = "↑ "
4343
IconDown = "↓ "
4444
IconEnter = "↵ "
45+
IconDiscuss = "󰭹 "
4546
)
4647

4748
// Design System Constants

internal/ui/tasklist/model.go

Lines changed: 13 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -174,13 +174,16 @@ func (m Model) View() string {
174174
func (m Model) renderEmpty() string {
175175
boxWidth := min(60, m.width-4)
176176

177+
// Gradient accent
178+
accent := m.styles.Theme.Accent
179+
177180
icon := lipgloss.NewStyle().
178-
Foreground(m.styles.Theme.Accent).
181+
Foreground(accent).
179182
Background(m.styles.Theme.Bg).
180183
Bold(true).
181184
Width(boxWidth).
182185
Align(lipgloss.Center).
183-
Render("\u2728 " + styles.IconTask)
186+
Render("󰇍")
184187

185188
title := lipgloss.NewStyle().
186189
Foreground(m.styles.Theme.Fg).
@@ -189,15 +192,15 @@ func (m Model) renderEmpty() string {
189192
Margin(1, 0, 0, 0).
190193
Width(boxWidth).
191194
Align(lipgloss.Center).
192-
Render("No tasks here yet")
195+
Render("Nothing on the horizon")
193196

194197
subtitle := lipgloss.NewStyle().
195198
Foreground(m.styles.Theme.Muted).
196199
Background(m.styles.Theme.Bg).
197200
Margin(1, 0, 0, 0).
198201
Width(boxWidth).
199202
Align(lipgloss.Center).
200-
Render("Press 'n' to create a new task and start your journey")
203+
Render("Press 'n' to plant the seed for a new task")
201204

202205
paletteKeys := strings.Join(m.km.Palette.Keys(), ", ")
203206
hint := lipgloss.NewStyle().
@@ -209,23 +212,12 @@ func (m Model) renderEmpty() string {
209212
Align(lipgloss.Center).
210213
Render(fmt.Sprintf("Tip: Use the command palette (%s) to access all features", paletteKeys))
211214

212-
content := lipgloss.JoinVertical(lipgloss.Left,
213-
icon,
214-
title,
215-
subtitle,
216-
hint,
217-
)
218-
219-
card := m.styles.Card.
220-
Width(boxWidth).
221-
Padding(2, 0). // Horizontal padding removed to respect explicit line widths
222-
Render(content)
223-
224-
// Place centered; FillViewport at the top level will handle ANSI fixup.
225-
return lipgloss.Place(m.width, m.height, lipgloss.Center, lipgloss.Center, card,
226-
lipgloss.WithWhitespaceChars(" "),
227-
lipgloss.WithWhitespaceBackground(m.styles.Theme.Bg),
228-
)
215+
// Center in view
216+
return lipgloss.NewStyle().
217+
Width(m.width).
218+
Height(m.height).
219+
Align(lipgloss.Center, lipgloss.Center).
220+
Render(lipgloss.JoinVertical(lipgloss.Center, icon, title, subtitle, hint))
229221
}
230222

231223
func (m Model) renderRow(t core.Task, selected bool) string {

internal/ui/theme/theme.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ var Nord = Theme{
6767
IsLight: false,
6868
Bg: lipgloss.Color("#2E3440"),
6969
Fg: lipgloss.Color("#D8DEE9"),
70-
Muted: lipgloss.Color("#4C566A"),
70+
Muted: lipgloss.Color("#81A1C1"),
7171
Border: lipgloss.Color("#3B4252"),
7272
Accent: lipgloss.Color("#88C0D0"),
7373
Good: lipgloss.Color("#A3BE8C"),

0 commit comments

Comments
 (0)