ratatui_ruby 0.4.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.builds/ruby-3.2.yml +1 -1
- data/.builds/ruby-3.3.yml +1 -1
- data/.builds/ruby-3.4.yml +1 -1
- data/.builds/ruby-4.0.0.yml +1 -1
- data/AGENTS.md +87 -171
- data/CHANGELOG.md +38 -1
- data/README.md +8 -3
- data/REUSE.toml +20 -0
- data/doc/application_architecture.md +105 -45
- data/doc/application_testing.md +5 -3
- data/doc/contributors/design/ruby_frontend.md +9 -5
- data/doc/contributors/developing_examples.md +76 -18
- data/doc/contributors/documentation_style.md +7 -0
- data/doc/contributors/index.md +2 -0
- data/doc/event_handling.md +10 -4
- data/doc/images/app_all_events.png +0 -0
- data/doc/images/app_color_picker.png +0 -0
- data/doc/images/verify_readme_usage.png +0 -0
- data/doc/images/widget_barchart_demo.png +0 -0
- data/doc/images/widget_block_padding.png +0 -0
- data/doc/images/widget_block_titles.png +0 -0
- data/doc/images/widget_box_demo.png +0 -0
- data/doc/images/widget_calendar_demo.png +0 -0
- data/doc/images/widget_cell_demo.png +0 -0
- data/doc/images/widget_chart_demo.png +0 -0
- data/doc/images/widget_gauge_demo.png +0 -0
- data/doc/images/widget_layout_split.png +0 -0
- data/doc/images/widget_line_gauge_demo.png +0 -0
- data/doc/images/widget_list_demo.png +0 -0
- data/doc/images/widget_ratatui_logo_demo.png +0 -0
- data/doc/images/widget_ratatui_mascot_demo.png +0 -0
- data/doc/images/widget_render.png +0 -0
- data/doc/images/widget_scrollbar_demo.png +0 -0
- data/doc/images/widget_sparkline_demo.png +0 -0
- data/doc/images/widget_style_colors.png +0 -0
- data/doc/images/widget_table_flex.png +0 -0
- data/doc/images/widget_tabs_demo.png +0 -0
- data/doc/interactive_design.md +25 -30
- data/doc/quickstart.md +147 -120
- data/examples/app_all_events/README.md +81 -0
- data/examples/app_all_events/app.rb +93 -0
- data/examples/app_all_events/model/event_color_cycle.rb +41 -0
- data/examples/app_all_events/model/event_entry.rb +75 -0
- data/examples/app_all_events/model/events.rb +180 -0
- data/examples/app_all_events/model/highlight.rb +57 -0
- data/examples/app_all_events/model/timestamp.rb +54 -0
- data/examples/app_all_events/test/snapshots/after_focus_lost.txt +24 -0
- data/examples/app_all_events/test/snapshots/after_focus_regained.txt +24 -0
- data/examples/app_all_events/test/snapshots/after_horizontal_resize.txt +24 -0
- data/examples/app_all_events/test/snapshots/after_key_a.txt +24 -0
- data/examples/app_all_events/test/snapshots/after_key_ctrl_x.txt +24 -0
- data/examples/app_all_events/test/snapshots/after_mouse_click.txt +24 -0
- data/examples/app_all_events/test/snapshots/after_mouse_drag.txt +24 -0
- data/examples/app_all_events/test/snapshots/after_multiple_events.txt +24 -0
- data/examples/app_all_events/test/snapshots/after_paste.txt +24 -0
- data/examples/app_all_events/test/snapshots/after_resize.txt +24 -0
- data/examples/app_all_events/test/snapshots/after_right_click.txt +24 -0
- data/examples/app_all_events/test/snapshots/after_vertical_resize.txt +24 -0
- data/examples/app_all_events/test/snapshots/initial_state.txt +24 -0
- data/examples/app_all_events/view/app_view.rb +78 -0
- data/examples/app_all_events/view/controls_view.rb +50 -0
- data/examples/app_all_events/view/counts_view.rb +55 -0
- data/examples/app_all_events/view/live_view.rb +69 -0
- data/examples/app_all_events/view/log_view.rb +60 -0
- data/examples/app_all_events/view.rb +7 -0
- data/examples/app_all_events/view_state.rb +42 -0
- data/examples/app_color_picker/README.md +94 -0
- data/examples/app_color_picker/app.rb +112 -0
- data/examples/app_color_picker/clipboard.rb +84 -0
- data/examples/app_color_picker/color.rb +191 -0
- data/examples/app_color_picker/copy_dialog.rb +170 -0
- data/examples/app_color_picker/harmony.rb +56 -0
- data/examples/app_color_picker/input.rb +142 -0
- data/examples/app_color_picker/palette.rb +80 -0
- data/examples/app_color_picker/scene.rb +201 -0
- data/examples/{login_form → app_login_form}/app.rb +39 -42
- data/examples/{map_demo → app_map_demo}/app.rb +24 -21
- data/examples/{table_select → app_table_select}/app.rb +68 -65
- data/examples/{quickstart_dsl → verify_quickstart_dsl}/app.rb +15 -6
- data/examples/verify_quickstart_layout/app.rb +69 -0
- data/examples/{quickstart_lifecycle → verify_quickstart_lifecycle}/app.rb +19 -10
- data/examples/verify_readme_usage/app.rb +34 -0
- data/examples/widget_barchart_demo/app.rb +238 -0
- data/examples/{block_padding → widget_block_padding}/app.rb +17 -13
- data/examples/{block_titles → widget_block_titles}/app.rb +25 -17
- data/examples/{box_demo → widget_box_demo}/app.rb +99 -65
- data/examples/widget_calendar_demo/app.rb +109 -0
- data/examples/widget_cell_demo/app.rb +104 -0
- data/examples/widget_chart_demo/app.rb +213 -0
- data/examples/widget_gauge_demo/app.rb +212 -0
- data/examples/widget_layout_split/app.rb +246 -0
- data/examples/widget_line_gauge_demo/app.rb +217 -0
- data/examples/widget_list_demo/app.rb +382 -0
- data/examples/widget_list_styles/app.rb +141 -0
- data/examples/widget_popup_demo/app.rb +104 -0
- data/examples/widget_ratatui_logo_demo/app.rb +103 -0
- data/examples/widget_ratatui_mascot_demo/app.rb +93 -0
- data/examples/widget_rect/app.rb +205 -0
- data/examples/widget_render/app.rb +184 -0
- data/examples/widget_rich_text/app.rb +137 -0
- data/examples/widget_scroll_text/app.rb +108 -0
- data/examples/widget_scrollbar_demo/app.rb +153 -0
- data/examples/widget_sparkline_demo/app.rb +274 -0
- data/examples/widget_style_colors/app.rb +19 -21
- data/examples/widget_table_flex/app.rb +95 -0
- data/examples/widget_tabs_demo/app.rb +167 -0
- data/ext/ratatui_ruby/Cargo.lock +1 -1
- data/ext/ratatui_ruby/Cargo.toml +1 -1
- data/ext/ratatui_ruby/src/events.rs +121 -36
- data/ext/ratatui_ruby/src/frame.rs +115 -0
- data/ext/ratatui_ruby/src/lib.rs +79 -26
- data/ext/ratatui_ruby/src/rendering.rs +8 -4
- data/ext/ratatui_ruby/src/style.rs +138 -57
- data/ext/ratatui_ruby/src/terminal.rs +5 -9
- data/ext/ratatui_ruby/src/text.rs +13 -6
- data/ext/ratatui_ruby/src/widgets/barchart.rs +56 -54
- data/ext/ratatui_ruby/src/widgets/block.rs +7 -6
- data/ext/ratatui_ruby/src/widgets/canvas.rs +21 -3
- data/ext/ratatui_ruby/src/widgets/chart.rs +20 -10
- data/ext/ratatui_ruby/src/widgets/layout.rs +9 -4
- data/ext/ratatui_ruby/src/widgets/list.rs +32 -9
- data/ext/ratatui_ruby/src/widgets/overlay.rs +2 -1
- data/ext/ratatui_ruby/src/widgets/paragraph.rs +1 -1
- data/ext/ratatui_ruby/src/widgets/ratatui_logo.rs +19 -8
- data/ext/ratatui_ruby/src/widgets/ratatui_mascot.rs +17 -10
- data/ext/ratatui_ruby/src/widgets/scrollbar.rs +4 -2
- data/ext/ratatui_ruby/src/widgets/sparkline.rs +14 -11
- data/ext/ratatui_ruby/src/widgets/table.rs +8 -4
- data/ext/ratatui_ruby/src/widgets/tabs.rs +11 -11
- data/lib/ratatui_ruby/cell.rb +3 -3
- data/lib/ratatui_ruby/event/key.rb +1 -1
- data/lib/ratatui_ruby/event/none.rb +43 -0
- data/lib/ratatui_ruby/event.rb +56 -4
- data/lib/ratatui_ruby/frame.rb +87 -0
- data/lib/ratatui_ruby/schema/bar_chart/bar.rb +11 -11
- data/lib/ratatui_ruby/schema/bar_chart/bar_group.rb +1 -5
- data/lib/ratatui_ruby/schema/bar_chart.rb +217 -217
- data/lib/ratatui_ruby/schema/block.rb +163 -168
- data/lib/ratatui_ruby/schema/calendar.rb +66 -67
- data/lib/ratatui_ruby/schema/canvas.rb +63 -63
- data/lib/ratatui_ruby/schema/center.rb +46 -46
- data/lib/ratatui_ruby/schema/chart.rb +135 -143
- data/lib/ratatui_ruby/schema/clear.rb +42 -42
- data/lib/ratatui_ruby/schema/constraint.rb +76 -76
- data/lib/ratatui_ruby/schema/cursor.rb +25 -25
- data/lib/ratatui_ruby/schema/gauge.rb +53 -53
- data/lib/ratatui_ruby/schema/layout.rb +87 -87
- data/lib/ratatui_ruby/schema/line_gauge.rb +62 -62
- data/lib/ratatui_ruby/schema/list.rb +86 -84
- data/lib/ratatui_ruby/schema/overlay.rb +31 -31
- data/lib/ratatui_ruby/schema/paragraph.rb +80 -80
- data/lib/ratatui_ruby/schema/ratatui_logo.rb +10 -6
- data/lib/ratatui_ruby/schema/ratatui_mascot.rb +10 -5
- data/lib/ratatui_ruby/schema/rect.rb +60 -60
- data/lib/ratatui_ruby/schema/scrollbar.rb +119 -119
- data/lib/ratatui_ruby/schema/shape/label.rb +1 -1
- data/lib/ratatui_ruby/schema/sparkline.rb +111 -110
- data/lib/ratatui_ruby/schema/style.rb +46 -46
- data/lib/ratatui_ruby/schema/table.rb +112 -119
- data/lib/ratatui_ruby/schema/tabs.rb +66 -67
- data/lib/ratatui_ruby/session/autodoc.rb +417 -0
- data/lib/ratatui_ruby/session.rb +40 -23
- data/lib/ratatui_ruby/test_helper.rb +185 -19
- data/lib/ratatui_ruby/version.rb +1 -1
- data/lib/ratatui_ruby.rb +65 -39
- data/{examples/sparkline_demo → sig/examples/app_all_events}/app.rbs +3 -2
- data/sig/examples/app_all_events/model/event_entry.rbs +16 -0
- data/sig/examples/app_all_events/model/events.rbs +15 -0
- data/sig/examples/app_all_events/model/timestamp.rbs +11 -0
- data/sig/examples/app_all_events/view/app_view.rbs +8 -0
- data/sig/examples/app_all_events/view/controls_view.rbs +6 -0
- data/sig/examples/app_all_events/view/counts_view.rbs +6 -0
- data/sig/examples/app_all_events/view/live_view.rbs +6 -0
- data/sig/examples/app_all_events/view/log_view.rbs +6 -0
- data/sig/examples/app_all_events/view.rbs +8 -0
- data/sig/examples/app_all_events/view_state.rbs +15 -0
- data/{examples/list_demo → sig/examples/app_color_picker}/app.rbs +2 -2
- data/sig/examples/app_login_form/app.rbs +11 -0
- data/sig/examples/app_map_demo/app.rbs +11 -0
- data/sig/examples/app_table_select/app.rbs +11 -0
- data/sig/examples/verify_quickstart_dsl/app.rbs +11 -0
- data/sig/examples/verify_quickstart_lifecycle/app.rbs +11 -0
- data/sig/examples/verify_readme_usage/app.rbs +11 -0
- data/sig/examples/widget_block_padding/app.rbs +11 -0
- data/sig/examples/widget_block_titles/app.rbs +11 -0
- data/sig/examples/widget_box_demo/app.rbs +11 -0
- data/sig/examples/widget_calendar_demo/app.rbs +11 -0
- data/sig/examples/widget_cell_demo/app.rbs +11 -0
- data/sig/examples/widget_chart_demo/app.rbs +11 -0
- data/{examples/gauge_demo → sig/examples/widget_gauge_demo}/app.rbs +4 -0
- data/sig/examples/widget_layout_split/app.rbs +10 -0
- data/sig/examples/widget_line_gauge_demo/app.rbs +11 -0
- data/sig/examples/widget_list_demo/app.rbs +12 -0
- data/sig/examples/widget_list_styles/app.rbs +11 -0
- data/sig/examples/widget_popup_demo/app.rbs +11 -0
- data/sig/examples/widget_ratatui_logo_demo/app.rbs +11 -0
- data/sig/examples/widget_ratatui_mascot_demo/app.rbs +11 -0
- data/sig/examples/widget_rect/app.rbs +12 -0
- data/sig/examples/widget_render/app.rbs +10 -0
- data/sig/examples/widget_rich_text/app.rbs +11 -0
- data/sig/examples/widget_scroll_text/app.rbs +11 -0
- data/sig/examples/widget_scrollbar_demo/app.rbs +11 -0
- data/sig/examples/widget_sparkline_demo/app.rbs +10 -0
- data/{examples → sig/examples}/widget_style_colors/app.rbs +1 -1
- data/sig/examples/widget_table_flex/app.rbs +11 -0
- data/sig/ratatui_ruby/frame.rbs +9 -0
- data/sig/ratatui_ruby/ratatui_ruby.rbs +3 -2
- data/sig/ratatui_ruby/schema/draw.rbs +4 -0
- data/sig/ratatui_ruby/schema/layout.rbs +1 -1
- data/sig/ratatui_ruby/session.rbs +94 -0
- data/tasks/autodoc/inventory.rb +61 -0
- data/tasks/autodoc/member.rb +56 -0
- data/tasks/autodoc/name.rb +19 -0
- data/tasks/autodoc/notice.rb +26 -0
- data/tasks/autodoc/rbs.rb +38 -0
- data/tasks/autodoc/rdoc.rb +45 -0
- data/tasks/autodoc.rake +47 -0
- data/tasks/bump/history.rb +2 -2
- data/tasks/doc.rake +600 -6
- data/tasks/example_viewer.html.erb +172 -0
- data/tasks/lint.rake +8 -4
- data/tasks/resources/index.html.erb +6 -0
- data/tasks/sourcehut.rake +4 -4
- data/tasks/terminal_preview/app_screenshot.rb +1 -3
- data/tasks/terminal_preview/crash_report.rb +7 -9
- data/tasks/terminal_preview/launcher_script.rb +4 -6
- data/tasks/terminal_preview/preview_collection.rb +4 -6
- data/tasks/terminal_preview/safety_confirmation.rb +3 -5
- data/tasks/terminal_preview/saved_screenshot.rb +7 -9
- data/tasks/terminal_preview/terminal_window.rb +7 -9
- data/tasks/test.rake +1 -1
- data/tasks/website/index_page.rb +3 -3
- data/tasks/website/version.rb +10 -10
- data/tasks/website/version_menu.rb +10 -12
- data/tasks/website/versioned_documentation.rb +49 -17
- data/tasks/website/website.rb +6 -8
- data/tasks/website.rake +4 -4
- metadata +156 -125
- data/LICENSES/BSD-2-Clause.txt +0 -9
- data/doc/contributors/better_dx.md +0 -543
- data/doc/contributors/example_analysis.md +0 -82
- data/doc/images/all_events.png +0 -0
- data/doc/images/block_padding.png +0 -0
- data/doc/images/block_titles.png +0 -0
- data/doc/images/box_demo.png +0 -0
- data/doc/images/calendar_demo.png +0 -0
- data/doc/images/cell_demo.png +0 -0
- data/doc/images/chart_demo.png +0 -0
- data/doc/images/flex_layout.png +0 -0
- data/doc/images/gauge_demo.png +0 -0
- data/doc/images/line_gauge_demo.png +0 -0
- data/doc/images/list_demo.png +0 -0
- data/doc/images/readme_usage.png +0 -0
- data/doc/images/scrollbar_demo.png +0 -0
- data/doc/images/sparkline_demo.png +0 -0
- data/doc/images/table_flex.png +0 -0
- data/examples/all_events/app.rb +0 -169
- data/examples/all_events/app.rbs +0 -7
- data/examples/all_events/test_app.rb +0 -139
- data/examples/analytics/app.rb +0 -258
- data/examples/analytics/app.rbs +0 -7
- data/examples/analytics/test_app.rb +0 -132
- data/examples/block_padding/app.rbs +0 -7
- data/examples/block_padding/test_app.rb +0 -31
- data/examples/block_titles/app.rbs +0 -7
- data/examples/block_titles/test_app.rb +0 -34
- data/examples/box_demo/app.rbs +0 -7
- data/examples/box_demo/test_app.rb +0 -88
- data/examples/calendar_demo/app.rb +0 -101
- data/examples/calendar_demo/app.rbs +0 -7
- data/examples/calendar_demo/test_app.rb +0 -108
- data/examples/cell_demo/app.rb +0 -108
- data/examples/cell_demo/app.rbs +0 -7
- data/examples/cell_demo/test_app.rb +0 -36
- data/examples/chart_demo/app.rb +0 -203
- data/examples/chart_demo/app.rbs +0 -7
- data/examples/chart_demo/test_app.rb +0 -102
- data/examples/custom_widget/app.rb +0 -51
- data/examples/custom_widget/app.rbs +0 -7
- data/examples/custom_widget/test_app.rb +0 -30
- data/examples/flex_layout/app.rb +0 -156
- data/examples/flex_layout/app.rbs +0 -7
- data/examples/flex_layout/test_app.rb +0 -65
- data/examples/gauge_demo/app.rb +0 -182
- data/examples/gauge_demo/test_app.rb +0 -120
- data/examples/hit_test/app.rb +0 -175
- data/examples/hit_test/app.rbs +0 -7
- data/examples/hit_test/test_app.rb +0 -102
- data/examples/line_gauge_demo/app.rb +0 -190
- data/examples/line_gauge_demo/app.rbs +0 -7
- data/examples/line_gauge_demo/test_app.rb +0 -129
- data/examples/list_demo/app.rb +0 -253
- data/examples/list_demo/test_app.rb +0 -237
- data/examples/list_styles/app.rb +0 -140
- data/examples/list_styles/app.rbs +0 -7
- data/examples/list_styles/test_app.rb +0 -157
- data/examples/login_form/app.rbs +0 -7
- data/examples/login_form/test_app.rb +0 -51
- data/examples/map_demo/app.rbs +0 -7
- data/examples/map_demo/test_app.rb +0 -149
- data/examples/mouse_events/app.rb +0 -97
- data/examples/mouse_events/app.rbs +0 -7
- data/examples/mouse_events/test_app.rb +0 -53
- data/examples/popup_demo/app.rb +0 -103
- data/examples/popup_demo/app.rbs +0 -7
- data/examples/popup_demo/test_app.rb +0 -54
- data/examples/quickstart_dsl/app.rbs +0 -7
- data/examples/quickstart_dsl/test_app.rb +0 -29
- data/examples/quickstart_lifecycle/app.rbs +0 -7
- data/examples/quickstart_lifecycle/test_app.rb +0 -29
- data/examples/ratatui_logo_demo/app.rb +0 -79
- data/examples/ratatui_logo_demo/app.rbs +0 -7
- data/examples/ratatui_logo_demo/test_app.rb +0 -51
- data/examples/ratatui_mascot_demo/app.rb +0 -84
- data/examples/ratatui_mascot_demo/app.rbs +0 -7
- data/examples/ratatui_mascot_demo/test_app.rb +0 -47
- data/examples/readme_usage/app.rb +0 -29
- data/examples/readme_usage/app.rbs +0 -7
- data/examples/readme_usage/test_app.rb +0 -29
- data/examples/rich_text/app.rb +0 -141
- data/examples/rich_text/app.rbs +0 -7
- data/examples/rich_text/test_app.rb +0 -166
- data/examples/scroll_text/app.rb +0 -103
- data/examples/scroll_text/app.rbs +0 -7
- data/examples/scroll_text/test_app.rb +0 -110
- data/examples/scrollbar_demo/app.rb +0 -143
- data/examples/scrollbar_demo/app.rbs +0 -7
- data/examples/scrollbar_demo/test_app.rb +0 -77
- data/examples/sparkline_demo/app.rb +0 -240
- data/examples/sparkline_demo/test_app.rb +0 -107
- data/examples/table_flex/app.rb +0 -65
- data/examples/table_flex/app.rbs +0 -7
- data/examples/table_flex/test_app.rb +0 -36
- data/examples/table_select/app.rbs +0 -7
- data/examples/table_select/test_app.rb +0 -180
- data/examples/widget_style_colors/test_app.rb +0 -48
- /data/doc/images/{analytics.png → app_analytics.png} +0 -0
- /data/doc/images/{custom_widget.png → app_custom_widget.png} +0 -0
- /data/doc/images/{login_form.png → app_login_form.png} +0 -0
- /data/doc/images/{map_demo.png → app_map_demo.png} +0 -0
- /data/doc/images/{mouse_events.png → app_mouse_events.png} +0 -0
- /data/doc/images/{table_select.png → app_table_select.png} +0 -0
- /data/doc/images/{quickstart_dsl.png → verify_quickstart_dsl.png} +0 -0
- /data/doc/images/{ratatui_logo_demo.png → verify_quickstart_layout.png} +0 -0
- /data/doc/images/{quickstart_lifecycle.png → verify_quickstart_lifecycle.png} +0 -0
- /data/doc/images/{list_styles.png → widget_list_styles.png} +0 -0
- /data/doc/images/{popup_demo.png → widget_popup_demo.png} +0 -0
- /data/doc/images/{hit_test.png → widget_rect.png} +0 -0
- /data/doc/images/{rich_text.png → widget_rich_text.png} +0 -0
- /data/doc/images/{scroll_text.png → widget_scroll_text.png} +0 -0
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
<%#
|
|
2
|
+
SPDX-FileCopyrightText: 2025 Kerrick Long <me@kerricklong.com>
|
|
3
|
+
SPDX-License-Identifier: AGPL-3.0-or-later
|
|
4
|
+
%>
|
|
5
|
+
<!DOCTYPE html>
|
|
6
|
+
<html lang="en">
|
|
7
|
+
<head>
|
|
8
|
+
<meta charset="UTF-8">
|
|
9
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
10
|
+
<title><%= page_title %> - Example Viewer</title>
|
|
11
|
+
|
|
12
|
+
<script>
|
|
13
|
+
var rdoc_rel_prefix = "<%= doc_root_link.sub('index.html', '') %>";
|
|
14
|
+
var index_rel_prefix = "<%= '../' * (relative_path.split('/').size - 1) %>";
|
|
15
|
+
</script>
|
|
16
|
+
|
|
17
|
+
<script src="<%= '../' * (relative_path.split('/').size - 1) %>js/search_navigation.js" defer></script>
|
|
18
|
+
<script src="<%= '../' * (relative_path.split('/').size - 1) %>js/search_data.js" defer></script>
|
|
19
|
+
<script src="<%= '../' * (relative_path.split('/').size - 1) %>js/search_ranker.js" defer></script>
|
|
20
|
+
<script src="<%= '../' * (relative_path.split('/').size - 1) %>js/search_controller.js" defer></script>
|
|
21
|
+
<script src="<%= '../' * (relative_path.split('/').size - 1) %>js/aliki.js" defer></script>
|
|
22
|
+
|
|
23
|
+
<link href="<%= doc_root_link.sub('index.html', '') %>css/rdoc.css" rel="stylesheet">
|
|
24
|
+
<link href="<%= doc_root_link.sub('index.html', '') %>custom.css" rel="stylesheet">
|
|
25
|
+
</head>
|
|
26
|
+
<body class="file<%= ' has-toc' unless toc_items.empty? %>">
|
|
27
|
+
<%= icons_svg %>
|
|
28
|
+
<header class="top-navbar">
|
|
29
|
+
<div class="navbar-brand">
|
|
30
|
+
Example Viewer
|
|
31
|
+
</div>
|
|
32
|
+
|
|
33
|
+
<!-- Desktop search bar -->
|
|
34
|
+
<div class="navbar-search navbar-search-desktop" role="search">
|
|
35
|
+
<form action="#" method="get" accept-charset="utf-8">
|
|
36
|
+
<input id="search-field" role="combobox" aria-label="Search"
|
|
37
|
+
aria-autocomplete="list" aria-controls="search-results-desktop"
|
|
38
|
+
type="text" name="search" placeholder="Search (/) examples..."
|
|
39
|
+
spellcheck="false" autocomplete="off"
|
|
40
|
+
title="Type to search, Up and Down to navigate, Enter to load">
|
|
41
|
+
<ul id="search-results-desktop" aria-label="Search Results"
|
|
42
|
+
aria-busy="false" aria-expanded="false"
|
|
43
|
+
aria-atomic="false" class="initially-hidden search-results"></ul>
|
|
44
|
+
</form>
|
|
45
|
+
</div>
|
|
46
|
+
|
|
47
|
+
<!-- Mobile search icon button -->
|
|
48
|
+
<button id="search-toggle" class="navbar-search-mobile" aria-label="Open search" type="button">
|
|
49
|
+
<span aria-hidden="true">🔍</span>
|
|
50
|
+
</button>
|
|
51
|
+
|
|
52
|
+
<button id="theme-toggle" class="theme-toggle" aria-label="Switch to dark mode" type="button" onclick="cycleColorMode()">
|
|
53
|
+
<span class="theme-toggle-icon" aria-hidden="true">🌙</span>
|
|
54
|
+
</button>
|
|
55
|
+
</header>
|
|
56
|
+
|
|
57
|
+
<!-- Search Modal (Mobile) -->
|
|
58
|
+
<div id="search-modal" class="search-modal" hidden aria-modal="true" role="dialog" aria-label="Search">
|
|
59
|
+
<div class="search-modal-backdrop"></div>
|
|
60
|
+
<div class="search-modal-content">
|
|
61
|
+
<div class="search-modal-header">
|
|
62
|
+
<form class="search-modal-form" action="#" method="get" accept-charset="utf-8">
|
|
63
|
+
<span class="search-modal-icon" aria-hidden="true">🔍</span>
|
|
64
|
+
<input id="search-field-mobile" role="combobox" aria-label="Search"
|
|
65
|
+
aria-autocomplete="list" aria-controls="search-results-mobile"
|
|
66
|
+
type="text" name="search" placeholder="Search examples"
|
|
67
|
+
spellcheck="false" autocomplete="off">
|
|
68
|
+
<button type="button" class="search-modal-close" aria-label="Close search" id="search-modal-close">
|
|
69
|
+
<span aria-hidden="true">esc</span>
|
|
70
|
+
</button>
|
|
71
|
+
</form>
|
|
72
|
+
</div>
|
|
73
|
+
<div class="search-modal-body">
|
|
74
|
+
<ul id="search-results-mobile" aria-label="Search Results"
|
|
75
|
+
aria-busy="false" aria-expanded="false"
|
|
76
|
+
aria-atomic="false" class="search-results search-modal-results initially-hidden"></ul>
|
|
77
|
+
<div class="search-modal-empty">
|
|
78
|
+
<p>No recent searches</p>
|
|
79
|
+
</div>
|
|
80
|
+
</div>
|
|
81
|
+
</div>
|
|
82
|
+
</div>
|
|
83
|
+
|
|
84
|
+
<nav id="navigation" role="navigation">
|
|
85
|
+
<div id="fileindex-section" class="nav-section">
|
|
86
|
+
<details class="nav-section-collapsible" open>
|
|
87
|
+
<summary class="nav-section-header">
|
|
88
|
+
<span class="nav-section-icon">
|
|
89
|
+
<svg><use href="#icon-file"></use></svg>
|
|
90
|
+
</span>
|
|
91
|
+
<span class="nav-section-title">Examples</span>
|
|
92
|
+
<span class="nav-section-chevron">
|
|
93
|
+
<svg><use href="#icon-chevron"></use></svg>
|
|
94
|
+
</span>
|
|
95
|
+
</summary>
|
|
96
|
+
<ul class="nav-list">
|
|
97
|
+
<li><a href="<%= doc_root_link %>">← Back to Docs</a></li>
|
|
98
|
+
</ul>
|
|
99
|
+
</details>
|
|
100
|
+
</div>
|
|
101
|
+
<div class="nav-section">
|
|
102
|
+
<details class="nav-section-collapsible" open>
|
|
103
|
+
<summary class="nav-section-header">
|
|
104
|
+
<span class="nav-section-icon">
|
|
105
|
+
<svg><use href="#icon-layers"></use></svg>
|
|
106
|
+
</span>
|
|
107
|
+
<span class="nav-section-title">Files</span>
|
|
108
|
+
<span class="nav-section-chevron">
|
|
109
|
+
<svg><use href="#icon-chevron"></use></svg>
|
|
110
|
+
</span>
|
|
111
|
+
</summary>
|
|
112
|
+
<ul class="link-list nav-list">
|
|
113
|
+
<%= render_tree(tree_data, relative_path, current_file_html) %>
|
|
114
|
+
</ul>
|
|
115
|
+
</details>
|
|
116
|
+
</div>
|
|
117
|
+
</nav>
|
|
118
|
+
|
|
119
|
+
<main role="main">
|
|
120
|
+
<div class="breadcrumb">
|
|
121
|
+
<%= breadcrumb_path %>
|
|
122
|
+
</div>
|
|
123
|
+
<%= file_header_html %>
|
|
124
|
+
<div class="content">
|
|
125
|
+
<%= file_content_html %>
|
|
126
|
+
</div>
|
|
127
|
+
</main>
|
|
128
|
+
|
|
129
|
+
<% unless toc_items.empty? %>
|
|
130
|
+
<aside class="table-of-contents" role="complementary" aria-label="Table of Contents">
|
|
131
|
+
<div class="toc-sticky">
|
|
132
|
+
<div class="toc-list">
|
|
133
|
+
<h3>On This Page</h3>
|
|
134
|
+
<%= render_toc(toc_items) %>
|
|
135
|
+
</div>
|
|
136
|
+
</div>
|
|
137
|
+
</aside>
|
|
138
|
+
<% end %>
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
<script>
|
|
142
|
+
const modes = ['auto', 'light', 'dark'];
|
|
143
|
+
const icons = { auto: '🌓', light: '☀️', dark: '🌙' };
|
|
144
|
+
|
|
145
|
+
function setColorMode(mode) {
|
|
146
|
+
if (mode === 'auto') {
|
|
147
|
+
document.documentElement.removeAttribute('data-theme');
|
|
148
|
+
const systemTheme = (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) ? 'dark' : 'light';
|
|
149
|
+
document.documentElement.setAttribute('data-theme', systemTheme);
|
|
150
|
+
} else {
|
|
151
|
+
document.documentElement.setAttribute('data-theme', mode);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
const icon = icons[mode];
|
|
155
|
+
const toggle = document.getElementById('theme-toggle');
|
|
156
|
+
toggle.querySelector('.theme-toggle-icon').textContent = icon;
|
|
157
|
+
|
|
158
|
+
localStorage.setItem('rdoc-theme', mode);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
function cycleColorMode() {
|
|
162
|
+
const current = localStorage.getItem('rdoc-theme') || 'auto';
|
|
163
|
+
const currentIndex = modes.indexOf(current);
|
|
164
|
+
const nextMode = modes[(currentIndex + 1) % modes.length];
|
|
165
|
+
setColorMode(nextMode);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
const savedMode = localStorage.getItem('rdoc-theme') || 'auto';
|
|
169
|
+
setColorMode(savedMode);
|
|
170
|
+
</script>
|
|
171
|
+
</body>
|
|
172
|
+
</html>
|
data/tasks/lint.rake
CHANGED
|
@@ -9,9 +9,9 @@ require "inch/rake"
|
|
|
9
9
|
|
|
10
10
|
RuboCop::RakeTask.new
|
|
11
11
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
12
|
+
# Run rubycritic in a shell to prevent it from exiting the rake process
|
|
13
|
+
task :rubycritic do
|
|
14
|
+
sh "bundle exec rubycritic --no-browser exe lib sig"
|
|
15
15
|
end
|
|
16
16
|
|
|
17
17
|
Inch::Rake::Suggest.new("doc:suggest", "exe/**/*.rb", "lib/**/*.rb", "sig/**/*.rbs") do |suggest|
|
|
@@ -39,7 +39,11 @@ end
|
|
|
39
39
|
task(:reuse) { Rake::Task["reuse:lint"].invoke }
|
|
40
40
|
|
|
41
41
|
namespace :lint do
|
|
42
|
-
task
|
|
42
|
+
task :safe_rdoc_coverage do
|
|
43
|
+
sh "bundle exec rake rdoc:coverage"
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
task docs: %w[autodoc rubycritic safe_rdoc_coverage reuse:lint]
|
|
43
47
|
task code: %w[rubocop rubycritic cargo:fmt cargo:clippy cargo:test]
|
|
44
48
|
task licenses: %w[reuse:lint]
|
|
45
49
|
task all: %w[docs code licenses]
|
data/tasks/sourcehut.rake
CHANGED
|
@@ -9,18 +9,18 @@ task :sourcehut do
|
|
|
9
9
|
require "yaml"
|
|
10
10
|
|
|
11
11
|
spec = Gem::Specification.load("ratatui_ruby.gemspec")
|
|
12
|
-
|
|
12
|
+
|
|
13
13
|
# Read version directly from file to ensure we get the latest version
|
|
14
14
|
# even if it was just bumped in the same Rake execution
|
|
15
15
|
version_content = File.read("lib/ratatui_ruby/version.rb")
|
|
16
16
|
version = version_content.match(/VERSION = "(.+?)"/)[1]
|
|
17
|
-
|
|
17
|
+
|
|
18
18
|
gem_filename = "#{spec.name}-#{version}.gem"
|
|
19
19
|
|
|
20
20
|
rubies = YAML.load_file("tasks/resources/rubies.yml")
|
|
21
|
-
|
|
21
|
+
|
|
22
22
|
bundler_version = File.read("Gemfile.lock").match(/BUNDLED WITH\n\s+([\d.]+)/)[1]
|
|
23
|
-
|
|
23
|
+
|
|
24
24
|
template = File.read("tasks/resources/build.yml.erb")
|
|
25
25
|
erb = ERB.new(template, trim_mode: "-")
|
|
26
26
|
|
|
@@ -26,29 +26,27 @@ class CrashReport < Data.define(:app, :error, :preamble)
|
|
|
26
26
|
TEXT
|
|
27
27
|
end
|
|
28
28
|
|
|
29
|
-
private
|
|
30
|
-
|
|
31
|
-
def box_top
|
|
32
|
-
"┌" + "─" * (width - 2) + "┐"
|
|
29
|
+
private def box_top
|
|
30
|
+
"┌#{'─' * (width - 2)}┐"
|
|
33
31
|
end
|
|
34
32
|
|
|
35
|
-
def box_bottom
|
|
36
|
-
"
|
|
33
|
+
private def box_bottom
|
|
34
|
+
"└#{'─' * (width - 2)}┘"
|
|
37
35
|
end
|
|
38
36
|
|
|
39
|
-
def border_top(title)
|
|
37
|
+
private def border_top(title)
|
|
40
38
|
left = "┌─ #{title} "
|
|
41
39
|
right = "┐"
|
|
42
40
|
dashes = "─" * (width - left.length - right.length)
|
|
43
41
|
left + dashes + right
|
|
44
42
|
end
|
|
45
43
|
|
|
46
|
-
def format_line(line)
|
|
44
|
+
private def format_line(line)
|
|
47
45
|
truncated = line[0...(width - 4)]
|
|
48
46
|
"│ #{truncated.ljust(width - 4)} │"
|
|
49
47
|
end
|
|
50
48
|
|
|
51
|
-
def width
|
|
49
|
+
private def width
|
|
52
50
|
80
|
|
53
51
|
end
|
|
54
52
|
end
|
|
@@ -26,16 +26,14 @@ class LauncherScript < Data.define(:app_path, :repo_root)
|
|
|
26
26
|
File.join(Dir.tmpdir, "preview_launcher.pid")
|
|
27
27
|
end
|
|
28
28
|
|
|
29
|
-
private
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
File.delete(path) if File.exist?(path)
|
|
33
|
-
File.delete(pid_file) if File.exist?(pid_file)
|
|
29
|
+
private def cleanup
|
|
30
|
+
FileUtils.rm_f(path)
|
|
31
|
+
FileUtils.rm_f(pid_file)
|
|
34
32
|
rescue Errno::ENOENT
|
|
35
33
|
# Already deleted
|
|
36
34
|
end
|
|
37
35
|
|
|
38
|
-
def write
|
|
36
|
+
private def write
|
|
39
37
|
File.open(path, "w") do |f|
|
|
40
38
|
f.puts "#!/bin/zsh"
|
|
41
39
|
f.puts "cd '#{repo_root}'"
|
|
@@ -31,7 +31,7 @@ class PreviewCollection
|
|
|
31
31
|
|
|
32
32
|
puts "\nHere we go!"
|
|
33
33
|
failures = apps.count { |app| !capture_app(app) }
|
|
34
|
-
|
|
34
|
+
|
|
35
35
|
if failures.zero?
|
|
36
36
|
puts "\n✨ All captures complete. Check doc/images/."
|
|
37
37
|
else
|
|
@@ -39,13 +39,11 @@ class PreviewCollection
|
|
|
39
39
|
end
|
|
40
40
|
end
|
|
41
41
|
|
|
42
|
-
private
|
|
43
|
-
|
|
44
|
-
def count_stale_apps(apps)
|
|
42
|
+
private def count_stale_apps(apps)
|
|
45
43
|
apps.count { |app| SavedScreenshot.for(app, @output_dir).stale? }
|
|
46
44
|
end
|
|
47
45
|
|
|
48
|
-
def capture_app(app)
|
|
46
|
+
private def capture_app(app)
|
|
49
47
|
saved = SavedScreenshot.for(app, @output_dir)
|
|
50
48
|
|
|
51
49
|
if saved.stale?
|
|
@@ -57,4 +55,4 @@ class PreviewCollection
|
|
|
57
55
|
true
|
|
58
56
|
end
|
|
59
57
|
end
|
|
60
|
-
|
|
58
|
+
end
|
|
@@ -17,11 +17,9 @@ class SafetyConfirmation
|
|
|
17
17
|
wait_for_user
|
|
18
18
|
end
|
|
19
19
|
|
|
20
|
-
private
|
|
21
|
-
|
|
22
|
-
def print_warning
|
|
20
|
+
private def print_warning
|
|
23
21
|
unchanged_count = @total_count - @stale_count
|
|
24
|
-
puts "\n
|
|
22
|
+
puts "\n#{'=' * 60}"
|
|
25
23
|
puts " 📸 NATIVE TERMINAL CAPTURE 📸"
|
|
26
24
|
puts "=" * 60
|
|
27
25
|
puts "This task will:"
|
|
@@ -41,7 +39,7 @@ class SafetyConfirmation
|
|
|
41
39
|
puts
|
|
42
40
|
end
|
|
43
41
|
|
|
44
|
-
def wait_for_user
|
|
42
|
+
private def wait_for_user
|
|
45
43
|
loop do
|
|
46
44
|
print "Continue? [Y/n]: "
|
|
47
45
|
response = $stdin.gets.strip.downcase
|
|
@@ -16,13 +16,11 @@ class SavedScreenshot < Data.define(:app, :path)
|
|
|
16
16
|
app_last_modified > screenshot_last_commit_time
|
|
17
17
|
end
|
|
18
18
|
|
|
19
|
-
private
|
|
20
|
-
|
|
21
|
-
def exists?
|
|
19
|
+
private def exists?
|
|
22
20
|
File.exist?(path)
|
|
23
21
|
end
|
|
24
22
|
|
|
25
|
-
def app_last_modified
|
|
23
|
+
private def app_last_modified
|
|
26
24
|
# If the file has staged or unstaged changes, it's definitely stale
|
|
27
25
|
return Time.now.to_i if changed?
|
|
28
26
|
|
|
@@ -30,26 +28,26 @@ class SavedScreenshot < Data.define(:app, :path)
|
|
|
30
28
|
app_last_commit_time
|
|
31
29
|
end
|
|
32
30
|
|
|
33
|
-
def changed?
|
|
31
|
+
private def changed?
|
|
34
32
|
system("git diff HEAD --quiet #{app.app_path} 2>/dev/null")
|
|
35
33
|
!$?.success?
|
|
36
34
|
end
|
|
37
35
|
|
|
38
|
-
def app_last_commit_time
|
|
36
|
+
private def app_last_commit_time
|
|
39
37
|
output = `git log -1 --format=%cI "#{app.app_path}" 2>/dev/null`.strip
|
|
40
38
|
return 0 if output.empty?
|
|
41
39
|
|
|
42
40
|
Time.iso8601(output).to_i
|
|
43
|
-
rescue
|
|
41
|
+
rescue
|
|
44
42
|
0
|
|
45
43
|
end
|
|
46
44
|
|
|
47
|
-
def screenshot_last_commit_time
|
|
45
|
+
private def screenshot_last_commit_time
|
|
48
46
|
output = `git log -1 --format=%cI "#{path}" 2>/dev/null`.strip
|
|
49
47
|
return Time.now.to_i if output.empty?
|
|
50
48
|
|
|
51
49
|
Time.iso8601(output).to_i
|
|
52
|
-
rescue
|
|
50
|
+
rescue
|
|
53
51
|
Time.now.to_i
|
|
54
52
|
end
|
|
55
53
|
end
|
|
@@ -41,9 +41,7 @@ class TerminalWindow
|
|
|
41
41
|
@window_id
|
|
42
42
|
end
|
|
43
43
|
|
|
44
|
-
private
|
|
45
|
-
|
|
46
|
-
def close
|
|
44
|
+
private def close
|
|
47
45
|
try_graceful_shutdown
|
|
48
46
|
kill_process if process_still_alive?
|
|
49
47
|
|
|
@@ -60,7 +58,7 @@ class TerminalWindow
|
|
|
60
58
|
system("osascript", "-e", delay_script, out: File::NULL, err: File::NULL)
|
|
61
59
|
end
|
|
62
60
|
|
|
63
|
-
def wait_for_startup
|
|
61
|
+
private def wait_for_startup
|
|
64
62
|
sleep PreviewTiming.window_startup
|
|
65
63
|
|
|
66
64
|
unless @window_id.valid?
|
|
@@ -73,7 +71,7 @@ class TerminalWindow
|
|
|
73
71
|
end
|
|
74
72
|
end
|
|
75
73
|
|
|
76
|
-
def try_graceful_shutdown
|
|
74
|
+
private def try_graceful_shutdown
|
|
77
75
|
shutdown_script = <<~APPLESCRIPT
|
|
78
76
|
tell application "Terminal"
|
|
79
77
|
try
|
|
@@ -86,7 +84,7 @@ class TerminalWindow
|
|
|
86
84
|
sleep 0.2
|
|
87
85
|
end
|
|
88
86
|
|
|
89
|
-
def process_still_alive?
|
|
87
|
+
private def process_still_alive?
|
|
90
88
|
return false unless @pid_file && File.exist?(@pid_file)
|
|
91
89
|
|
|
92
90
|
pid = File.read(@pid_file).strip.to_i
|
|
@@ -96,7 +94,7 @@ class TerminalWindow
|
|
|
96
94
|
false
|
|
97
95
|
end
|
|
98
96
|
|
|
99
|
-
def kill_process
|
|
97
|
+
private def kill_process
|
|
100
98
|
return unless @pid_file && File.exist?(@pid_file)
|
|
101
99
|
|
|
102
100
|
pid = File.read(@pid_file).strip.to_i
|
|
@@ -105,7 +103,7 @@ class TerminalWindow
|
|
|
105
103
|
# Process already gone or PID file doesn't exist
|
|
106
104
|
end
|
|
107
105
|
|
|
108
|
-
def process_running?
|
|
106
|
+
private def process_running?
|
|
109
107
|
check_script = <<~APPLESCRIPT
|
|
110
108
|
tell application "Terminal"
|
|
111
109
|
try
|
|
@@ -121,7 +119,7 @@ class TerminalWindow
|
|
|
121
119
|
result == "true"
|
|
122
120
|
end
|
|
123
121
|
|
|
124
|
-
def contents
|
|
122
|
+
private def contents
|
|
125
123
|
read_script = <<~APPLESCRIPT
|
|
126
124
|
tell application "Terminal"
|
|
127
125
|
try
|
data/tasks/test.rake
CHANGED
data/tasks/website/index_page.rb
CHANGED
|
@@ -8,17 +8,17 @@ require "erb"
|
|
|
8
8
|
class IndexPage
|
|
9
9
|
def initialize(versions)
|
|
10
10
|
@versions = versions
|
|
11
|
-
|
|
11
|
+
|
|
12
12
|
latest_version = @versions.find { |v| v.is_a?(Tagged) }
|
|
13
13
|
latest_version.is_latest = true if latest_version
|
|
14
14
|
end
|
|
15
15
|
|
|
16
16
|
def publish_to(path, project_name:)
|
|
17
17
|
puts "Generating index page..."
|
|
18
|
-
|
|
18
|
+
|
|
19
19
|
template_path = File.expand_path("../resources/index.html.erb", __dir__)
|
|
20
20
|
template = File.read(template_path)
|
|
21
|
-
|
|
21
|
+
|
|
22
22
|
versions = @versions
|
|
23
23
|
# project_name is used in the ERB
|
|
24
24
|
html_content = ERB.new(template).result(binding)
|
data/tasks/website/version.rb
CHANGED
|
@@ -10,9 +10,9 @@ class Version
|
|
|
10
10
|
def self.all
|
|
11
11
|
tags = `git tag`.split.grep(/^v\d/)
|
|
12
12
|
sorted_versions = tags.map { |t| Tagged.new(t) }
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
13
|
+
.sort_by(&:semver)
|
|
14
|
+
.reverse
|
|
15
|
+
|
|
16
16
|
[Edge.new] + sorted_versions
|
|
17
17
|
end
|
|
18
18
|
|
|
@@ -31,11 +31,11 @@ class Version
|
|
|
31
31
|
def checkout(globs:, &block)
|
|
32
32
|
raise NotImplementedError
|
|
33
33
|
end
|
|
34
|
-
|
|
34
|
+
|
|
35
35
|
def latest?
|
|
36
36
|
false
|
|
37
37
|
end
|
|
38
|
-
|
|
38
|
+
|
|
39
39
|
def edge?
|
|
40
40
|
false
|
|
41
41
|
end
|
|
@@ -53,7 +53,7 @@ class Edge < Version
|
|
|
53
53
|
def type
|
|
54
54
|
:edge
|
|
55
55
|
end
|
|
56
|
-
|
|
56
|
+
|
|
57
57
|
def edge?
|
|
58
58
|
true
|
|
59
59
|
end
|
|
@@ -64,14 +64,14 @@ class Edge < Version
|
|
|
64
64
|
files = `git ls-files`.split("\n").select do |f|
|
|
65
65
|
globs.any? { |glob| File.fnmatch(glob, f, File::FNM_PATHNAME) }
|
|
66
66
|
end
|
|
67
|
-
|
|
67
|
+
|
|
68
68
|
files.each do |file|
|
|
69
69
|
dest = File.join(path, file)
|
|
70
70
|
next unless File.exist?(file) # Skip files that are in the index but deleted in the working tree
|
|
71
71
|
FileUtils.mkdir_p(File.dirname(dest))
|
|
72
72
|
FileUtils.cp(file, dest)
|
|
73
73
|
end
|
|
74
|
-
|
|
74
|
+
|
|
75
75
|
yield path
|
|
76
76
|
end
|
|
77
77
|
end
|
|
@@ -99,9 +99,9 @@ class Tagged < Version
|
|
|
99
99
|
def semver
|
|
100
100
|
Gem::Version.new(@tag.sub(/^v/, ""))
|
|
101
101
|
end
|
|
102
|
-
|
|
102
|
+
|
|
103
103
|
attr_accessor :is_latest
|
|
104
|
-
|
|
104
|
+
|
|
105
105
|
def latest?
|
|
106
106
|
@is_latest
|
|
107
107
|
end
|
|
@@ -11,21 +11,19 @@ class VersionMenu
|
|
|
11
11
|
|
|
12
12
|
def run
|
|
13
13
|
puts "Injecting version menu into generated HTML..."
|
|
14
|
-
|
|
14
|
+
|
|
15
15
|
# Process all HTML files in the output directory
|
|
16
16
|
Dir.glob(File.join(@root, "**/*.html")).each do |file|
|
|
17
17
|
inject_menu(file)
|
|
18
18
|
end
|
|
19
19
|
end
|
|
20
20
|
|
|
21
|
-
private
|
|
22
|
-
|
|
23
|
-
def inject_menu(file)
|
|
21
|
+
private def inject_menu(file)
|
|
24
22
|
content = File.read(file)
|
|
25
|
-
|
|
23
|
+
|
|
26
24
|
# Find the injection point (before the theme toggle button)
|
|
27
25
|
pattern = /(<button[^>]*id="theme-toggle"[^>]*>)/mi
|
|
28
|
-
|
|
26
|
+
|
|
29
27
|
unless content.match?(pattern)
|
|
30
28
|
# warn "Could not find theme-toggle in #{file}"
|
|
31
29
|
return
|
|
@@ -35,11 +33,11 @@ class VersionMenu
|
|
|
35
33
|
file_dir = File.dirname(file)
|
|
36
34
|
relative_path_to_root = Pathname.new(@root).relative_path_from(Pathname.new(file_dir)).to_s
|
|
37
35
|
relative_path_to_root += "/" unless relative_path_to_root.end_with?("/")
|
|
38
|
-
|
|
36
|
+
|
|
39
37
|
# Determine current version from file path
|
|
40
38
|
relative_path_from_root = Pathname.new(file).relative_path_from(Pathname.new(@root)).to_s
|
|
41
39
|
current_version_slug = relative_path_from_root.split("/").first
|
|
42
|
-
|
|
40
|
+
|
|
43
41
|
# Build options
|
|
44
42
|
options = @versions.map do |version|
|
|
45
43
|
value = "#{relative_path_to_root}#{version.slug}/index.html"
|
|
@@ -47,10 +45,10 @@ class VersionMenu
|
|
|
47
45
|
display_name = version.name
|
|
48
46
|
display_name += " (latest)" if version.respond_to?(:latest?) && version.latest?
|
|
49
47
|
display_name += " (dev)" if version.edge?
|
|
50
|
-
|
|
48
|
+
|
|
51
49
|
%Q{<option value="#{value}" #{selected}>#{display_name}</option>}
|
|
52
50
|
end.join("\n")
|
|
53
|
-
|
|
51
|
+
|
|
54
52
|
# margin-left: auto pushes it to the right
|
|
55
53
|
# margin-right: 1rem spacing from the theme toggle
|
|
56
54
|
switcher_html = <<~HTML
|
|
@@ -59,10 +57,10 @@ class VersionMenu
|
|
|
59
57
|
<option value="#{relative_path_to_root}index.html">All Versions</option>
|
|
60
58
|
</select>
|
|
61
59
|
HTML
|
|
62
|
-
|
|
60
|
+
|
|
63
61
|
# Inject before the button
|
|
64
62
|
new_content = content.sub(pattern, "#{switcher_html}\n\\1")
|
|
65
|
-
|
|
63
|
+
|
|
66
64
|
File.write(file, new_content)
|
|
67
65
|
end
|
|
68
66
|
end
|