Last active
January 23, 2026 06:58
-
-
Save glinesbdev/d40f9d7b9ed1e18ff1a074b83454cbc8 to your computer and use it in GitHub Desktop.
Ratatui Ruby
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| source 'https://rubygems.org' | |
| gem 'ratatui_ruby' |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| require 'bundler/setup' | |
| require 'ratatui_ruby' | |
| class DukeTui | |
| STYLES = { | |
| active: { fg: :green }, | |
| inactive: { fg: :grey } | |
| }.freeze | |
| def initialize | |
| @input = '' | |
| @render_history = false | |
| @tui = RatatuiRuby::TUI.new | |
| @mode = :form | |
| @selected_column = 0 | |
| @selected_row = 0 | |
| @items = [ | |
| { | |
| name: 'https://zombo.com/', | |
| value: 'https://zombo.com/', | |
| tags: %w[fun] | |
| }, | |
| { | |
| name: 'something', | |
| value: 'this does nothing', | |
| tags: %w[these are whatever] | |
| } | |
| ] | |
| @selected_item = @items.first | |
| end | |
| def run | |
| render_app | |
| end | |
| private | |
| def render_app | |
| RatatuiRuby.run(viewport: :inline, height: 50) do | |
| loop do | |
| render_layout | |
| if handle_input == :quit | |
| area = @tui.viewport_area | |
| RatatuiRuby.cursor_position = [0, area.y + area.height] | |
| break | |
| end | |
| end | |
| end | |
| end | |
| def render_layout | |
| @tui.draw do |frame| | |
| content_area, form_area = @tui.layout_split( | |
| frame.area, | |
| direction: :vertical, | |
| constraints: [ | |
| @tui.constraint_fill(1), | |
| @tui.constraint_length(3) | |
| ] | |
| ) | |
| render_form_area(frame, form_area) | |
| render_content_area(frame, content_area) | |
| end | |
| end | |
| def render_form_area(frame, form_area) | |
| border_color = @mode == :form ? :green : :grey | |
| cursor_x = 1 + @input.length | |
| cursor_y = 1 | |
| form = @tui.overlay(layers: [ | |
| @tui.paragraph( | |
| text: @input, | |
| block: @tui.block(borders: :all, title: 'Duke Of Url', border_style: @tui.style(fg: border_color)), | |
| alignment: :left | |
| ), | |
| @tui.cursor(x: cursor_x, y: cursor_y) | |
| ]) | |
| frame.render_widget(form, form_area) | |
| end | |
| def render_content_area(frame, content_area) | |
| border_color = @mode == :content ? :green : :grey | |
| widths = [ | |
| @tui.constraint_percentage(75), | |
| @tui.constraint_percentage(50), | |
| ] | |
| content = @tui.table( | |
| rows: build_rows, | |
| widths: widths, | |
| selected_row: @selected_row, | |
| selected_column: @selected_column, | |
| row_highlight_style: @tui.style(bg: :dark_grey), | |
| highlight_symbol: '> ', | |
| flex: :flex, | |
| block: @tui.block(title: 'Look at all this content!', borders: :all, border_style: @tui.style(fg: border_color)) | |
| ) | |
| frame.render_widget(content, content_area) | |
| end | |
| def build_rows | |
| @items.map do |item| | |
| @tui.table_row(cells: [item[:name], item[:tags]]) | |
| end | |
| end | |
| def handle_input | |
| case @mode | |
| when :form then handle_form_input | |
| when :content then handle_content_input | |
| end | |
| end | |
| def handle_form_input | |
| case @tui.poll_event | |
| in { type: :key, code: "c", modifiers: ["ctrl"] } | |
| :quit | |
| in { type: :key, code: "q" } | |
| :quit | |
| in { type: :key, code: "esc" } | |
| :quit | |
| in { type: :key, code: "enter" } | |
| @mode = :content | |
| nil | |
| in { type: :key, code: "backspace" } | |
| @input.chop! | |
| nil | |
| in { type: :key, code: "up" } | |
| @mode = :content | |
| nil | |
| in { type: :key, code:, modifiers: [] } if code.length == 1 | |
| @input += code | |
| nil | |
| else | |
| nil | |
| end | |
| end | |
| def handle_content_input | |
| case @tui.poll_event | |
| in { type: :key, code: "q" } | |
| @mode = :form | |
| nil | |
| in { type: :key, code: "esc" } | |
| @mode = :form | |
| nil | |
| in { type: :key, code: "up" } | |
| @selected_row = (@selected_row - 1) % @items.length | |
| nil | |
| in { type: :key, code: "down" } | |
| @selected_row += 1 | |
| @mode = :form if @selected_row >= @items.length | |
| nil | |
| in { type: :key, code: "left" } | |
| @selected_column = (@selected_column - 1) % @items.length | |
| nil | |
| in { type: :key, code: "right" } | |
| @selected_column = (@selected_column + 1) % @items.length | |
| nil | |
| else | |
| nil | |
| end | |
| end | |
| end | |
| DukeTui.new.run |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment