{"id":48552196,"url":"https://github.com/moneycaringcoder/tuikit-go","last_synced_at":"2026-04-10T13:02:07.314Z","repository":{"id":349858685,"uuid":"1204222438","full_name":"moneycaringcoder/tuikit-go","owner":"moneycaringcoder","description":null,"archived":false,"fork":false,"pushed_at":"2026-04-07T21:41:14.000Z","size":33,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-04-07T22:28:59.554Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/moneycaringcoder.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-04-07T20:05:17.000Z","updated_at":"2026-04-07T21:41:17.000Z","dependencies_parsed_at":null,"dependency_job_id":"c5f498c1-8d9e-4adf-a5b4-b44ec3c719f0","html_url":"https://github.com/moneycaringcoder/tuikit-go","commit_stats":null,"previous_names":["moneycaringcoder/tuikit-go"],"tags_count":4,"template":false,"template_full_name":null,"purl":"pkg:github/moneycaringcoder/tuikit-go","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/moneycaringcoder%2Ftuikit-go","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/moneycaringcoder%2Ftuikit-go/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/moneycaringcoder%2Ftuikit-go/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/moneycaringcoder%2Ftuikit-go/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/moneycaringcoder","download_url":"https://codeload.github.com/moneycaringcoder/tuikit-go/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/moneycaringcoder%2Ftuikit-go/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31547845,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-07T16:28:08.000Z","status":"online","status_checked_at":"2026-04-08T02:00:06.127Z","response_time":54,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-04-08T09:00:38.289Z","updated_at":"2026-04-08T09:01:01.813Z","avatar_url":"https://github.com/moneycaringcoder.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# tuikit-go\n\nA Go toolkit for building terminal UIs fast. Wraps [Bubble Tea](https://github.com/charmbracelet/bubbletea) + [Lip Gloss](https://github.com/charmbracelet/lipgloss) with reusable components, a layout engine, keybinding registry, and theme system. Build a complete TUI app in under 20 lines.\n\n## Install\n\n```bash\ngo get github.com/moneycaringcoder/tuikit-go\n```\n\n## Quick Start\n\n```go\npackage main\n\nimport (\n\t\"fmt\"\n\ttuikit \"github.com/moneycaringcoder/tuikit-go\"\n)\n\nfunc main() {\n\ttable := tuikit.NewTable(\n\t\t[]tuikit.Column{\n\t\t\t{Title: \"Name\", Width: 20, Sortable: true},\n\t\t\t{Title: \"Status\", Width: 15},\n\t\t},\n\t\t[]tuikit.Row{\n\t\t\t{\"Alice\", \"Online\"},\n\t\t\t{\"Bob\", \"Away\"},\n\t\t},\n\t\ttuikit.TableOpts{Sortable: true, Filterable: true},\n\t)\n\n\tapp := tuikit.NewApp(\n\t\ttuikit.WithTheme(tuikit.DefaultTheme()),\n\t\ttuikit.WithComponent(\"main\", table),\n\t\ttuikit.WithStatusBar(\n\t\t\tfunc() string { return \" ? help  q quit\" },\n\t\t\tfunc() string { return fmt.Sprintf(\" %d items\", 2) },\n\t\t),\n\t\ttuikit.WithHelp(),\n\t)\n\n\tapp.Run()\n}\n```\n\n## Full Example\n\nSee [`examples/dashboard/`](examples/dashboard/) for a complete app (Galactic Pizza Tracker) showing all components working together — table, sidebar, config editor, help screen, status bar.\n\n```bash\ngo run ./examples/dashboard/\n```\n\n## Components\n\n### Table\n\nAdaptive table with responsive columns, sorting, filtering, and cursor navigation.\n\n```go\ncolumns := []tuikit.Column{\n    {Title: \"Name\", Width: 20, Sortable: true},\n    {Title: \"Score\", Width: 10, Align: tuikit.Right, Sortable: true},\n    {Title: \"Extra\", Width: 15, MinWidth: 100}, // hides below 100 cols\n}\n\ntable := tuikit.NewTable(columns, rows, tuikit.TableOpts{\n    Sortable:   true,  // 's' to cycle sort\n    Filterable: true,  // '/' to search\n})\n\ntable.SetRows(newRows) // update data dynamically\n```\n\n#### Custom Cell Rendering\n\nFull control over per-cell styling (colors, icons, conditional formatting):\n\n```go\ntuikit.TableOpts{\n    CellRenderer: func(row tuikit.Row, colIdx int, isCursor bool, theme tuikit.Theme) string {\n        val := row[colIdx]\n        if colIdx == 2 \u0026\u0026 val == \"Online\" {\n            return lipgloss.NewStyle().Foreground(lipgloss.Color(theme.Positive)).Render(val)\n        }\n        return val\n    },\n}\n```\n\n#### Custom Sort\n\nNumeric, time-based, or any custom sort logic:\n\n```go\ntuikit.TableOpts{\n    SortFunc: func(a, b tuikit.Row, sortCol int, sortAsc bool) bool {\n        va, _ := strconv.ParseFloat(a[sortCol], 64)\n        vb, _ := strconv.ParseFloat(b[sortCol], 64)\n        if sortAsc { return va \u003c vb }\n        return va \u003e vb\n    },\n}\n```\n\n#### Predicate Filter\n\nFilter rows programmatically alongside text search:\n\n```go\ntable.SetFilter(func(row tuikit.Row) bool {\n    return row[1] == \"online\" // only show online users\n})\ntable.SetFilter(nil) // clear filter\n```\n\n#### Mouse Support\n\nScroll wheel and click are handled automatically when mouse is enabled:\n\n```go\ntuikit.WithMouseSupport()\n```\n\n### Status Bar\n\nFooter with left-aligned hints and right-aligned status.\n\n```go\ntuikit.WithStatusBar(\n    func() string { return \" ? help  q quit\" },\n    func() string { return \" 42 items\" },\n)\n```\n\n### Help Screen\n\nAuto-generated from all registered keybindings. Zero configuration.\n\n```go\ntuikit.WithHelp() // press '?' to toggle\n```\n\n### Config Editor\n\nDeclarative settings overlay with grouped fields and validation.\n\n```go\neditor := tuikit.NewConfigEditor([]tuikit.ConfigField{\n    {\n        Label: \"Refresh Interval\",\n        Group: \"General\",\n        Hint:  \"seconds, min 5\",\n        Get:   func() string { return fmt.Sprint(cfg.Interval) },\n        Set:   func(v string) error {\n            n, _ := strconv.Atoi(v)\n            if n \u003c 5 { return fmt.Errorf(\"must be \u003e= 5\") }\n            cfg.Interval = n\n            return nil\n        },\n    },\n})\n\n// Register as overlay with trigger key\ntuikit.WithOverlay(\"Settings\", \"c\", editor) // press 'c' to open\n```\n\n### Layout\n\nSingle pane or dual pane with collapsible sidebar.\n\n```go\ntuikit.WithLayout(\u0026tuikit.DualPane{\n    Main:         table,\n    Side:         panel,\n    SideWidth:    30,\n    MinMainWidth: 60,  // sidebar auto-hides below this\n    SideRight:    true,\n    ToggleKey:    \"p\",\n})\n```\n\n## Theming\n\nBuilt-in dark and light themes, or create your own from a color map.\n\n```go\n// Built-in\ntuikit.DefaultTheme()\ntuikit.LightTheme()\n\n// From config (YAML/JSON/TOML — you parse, we color)\ntuikit.ThemeFromMap(map[string]string{\n    \"positive\": \"#00ff00\",\n    \"negative\": \"#ff0000\",\n    \"accent\":   \"#0000ff\",\n})\n```\n\nSemantic tokens: `Positive`, `Negative`, `Accent`, `Muted`, `Text`, `TextInverse`, `Cursor`, `Border`, `Flash`.\n\n## Building Custom Components\n\nImplement the `Component` interface to create your own:\n\n```go\ntype Component interface {\n    Init() tea.Cmd\n    Update(msg tea.Msg) (Component, tea.Cmd)\n    View() string\n    KeyBindings() []tuikit.KeyBind\n    SetSize(width, height int)\n    Focused() bool\n    SetFocused(bool)\n}\n```\n\nReturn `tuikit.Consumed()` from `Update` to signal the App that your component handled a key. The App stops dispatching to other components.\n\nTo receive theme updates, implement `Themed`:\n\n```go\ntype Themed interface {\n    SetTheme(tuikit.Theme)\n}\n```\n\nThe App calls `SetTheme` on any component or overlay that implements this interface whenever the theme is set.\n\nFor modal overlays, also implement `Overlay`:\n\n```go\ntype Overlay interface {\n    Component\n    IsActive() bool\n    Close()\n}\n```\n\nRegister overlays with a trigger key:\n\n```go\ntuikit.WithOverlay(\"Help\", \"?\", helpOverlay)\n```\n\n## App-Level Keybindings\n\nRegister global key handlers that run outside any component:\n\n```go\ntuikit.WithKeyBind(tuikit.KeyBind{\n    Key:   \"f\",\n    Label: \"Cycle filter\",\n    Group: \"DATA\",\n    Handler: func() {\n        filterIdx = (filterIdx + 1) % len(modes)\n        table.SetRows(rows) // re-apply filter\n    },\n})\n```\n\nThese appear in the help screen automatically.\n\n## Tick / Timer Support\n\nEnable periodic ticks for animations, flash effects, and polling:\n\n```go\ntuikit.WithTickInterval(100 * time.Millisecond)\n```\n\nComponents receive `tuikit.TickMsg` in their `Update` method.\n\n## External Data (Background Goroutines)\n\nPush data into the app from WebSocket streams, API polling, or any goroutine:\n\n```go\napp := tuikit.NewApp(...)\ngo func() {\n    for data := range stream {\n        app.Send(MyDataMsg{data})\n    }\n}()\napp.Run()\n```\n\nUnknown message types are forwarded to all components via `Update`.\n\n## For AI Agents\n\ntuikit follows predictable patterns:\n\n- All components implement `tuikit.Component`\n- Use `tuikit.NewApp()` with functional options (`WithTheme`, `WithComponent`, `WithLayout`, etc.)\n- Key dispatch: overlay stack → built-in globals (q/tab/?) → pane toggle → overlay triggers → app keybindings → focused component\n- See `examples/dashboard/main.go` for a complete reference\n\n## Dependencies\n\nCharm ecosystem only:\n\n- [Bubble Tea](https://github.com/charmbracelet/bubbletea) — TUI framework\n- [Lip Gloss](https://github.com/charmbracelet/lipgloss) — Styling\n- [Bubbles](https://github.com/charmbracelet/bubbles) — Component primitives\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmoneycaringcoder%2Ftuikit-go","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmoneycaringcoder%2Ftuikit-go","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmoneycaringcoder%2Ftuikit-go/lists"}