charming 0.2.2 → 0.3.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/README.md +16 -3
- data/lib/charming/application.rb +7 -0
- data/lib/charming/cli.rb +16 -4
- data/lib/charming/controller/class_methods.rb +13 -2
- data/lib/charming/controller/timers.rb +25 -0
- data/lib/charming/controller.rb +7 -2
- data/lib/charming/generators/app_file_generator.rb +29 -0
- data/lib/charming/generators/app_generator.rb +12 -25
- data/lib/charming/generators/base.rb +5 -0
- data/lib/charming/generators/layout_generator.rb +155 -0
- data/lib/charming/generators/screen_generator.rb +0 -29
- data/lib/charming/generators/templates/app/README.md.template +15 -1
- data/lib/charming/generators/templates/app/application.template +0 -6
- data/lib/charming/generators/templates/app/application_controller.template +0 -10
- data/lib/charming/generators/templates/app/layout.template +4 -93
- data/lib/charming/generators/templates/app/routes.template +3 -1
- data/lib/charming/generators/templates/layout/sidebar/application_layout.rb.template +110 -0
- data/lib/charming/image/protocol/kitty.rb +7 -0
- data/lib/charming/image/source.rb +10 -0
- data/lib/charming/internal/event_loop.rb +25 -2
- data/lib/charming/internal/timer_control.rb +48 -0
- data/lib/charming/presentation/components/autocomplete.rb +7 -0
- data/lib/charming/presentation/components/form/field.rb +5 -0
- data/lib/charming/presentation/components/form/input.rb +14 -4
- data/lib/charming/presentation/components/form/textarea.rb +18 -8
- data/lib/charming/presentation/components/form.rb +6 -0
- data/lib/charming/presentation/components/modal.rb +4 -4
- data/lib/charming/presentation/components/stopwatch.rb +1 -1
- data/lib/charming/presentation/components/text_area.rb +2 -2
- data/lib/charming/presentation/components/text_input.rb +2 -2
- data/lib/charming/presentation/components/timer.rb +1 -1
- data/lib/charming/presentation/components/toast.rb +4 -3
- data/lib/charming/presentation/components/viewport.rb +11 -1
- data/lib/charming/projectile.rb +64 -0
- data/lib/charming/runtime.rb +25 -4
- data/lib/charming/spring.rb +126 -0
- data/lib/charming/version.rb +1 -1
- data/lib/charming/welcome/controller.rb +23 -0
- data/lib/charming/welcome/show_view.rb +113 -0
- data/lib/charming/welcome.rb +13 -0
- data/lib/charming.rb +6 -0
- metadata +10 -7
- data/lib/charming/generators/templates/app/home_controller.template +0 -6
- data/lib/charming/generators/templates/app/home_state.template +0 -7
- data/lib/charming/generators/templates/app/spec_controller.template +0 -17
- data/lib/charming/generators/templates/app/spec_state.template +0 -17
- data/lib/charming/generators/templates/app/spec_view.template +0 -16
- data/lib/charming/generators/templates/app/view.template +0 -21
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# ******************************************************************************
|
|
4
|
+
#
|
|
5
|
+
# Copyright (c) 2008-2012 Ryan Juckett
|
|
6
|
+
# http://www.ryanjuckett.com/
|
|
7
|
+
#
|
|
8
|
+
# This software is provided 'as-is', without any express or implied
|
|
9
|
+
# warranty. In no event will the authors be held liable for any damages
|
|
10
|
+
# arising from the use of this software.
|
|
11
|
+
#
|
|
12
|
+
# Permission is granted to anyone to use this software for any purpose,
|
|
13
|
+
# including commercial applications, and to alter it and redistribute it
|
|
14
|
+
# freely, subject to the following restrictions:
|
|
15
|
+
#
|
|
16
|
+
# 1. The origin of this software must not be misrepresented; you must not
|
|
17
|
+
# claim that you wrote the original software. If you use this software
|
|
18
|
+
# in a product, an acknowledgment in the product documentation would be
|
|
19
|
+
# appreciated but is not required.
|
|
20
|
+
#
|
|
21
|
+
# 2. Altered source versions must be plainly marked as such, and must not be
|
|
22
|
+
# misrepresented as being the original software.
|
|
23
|
+
#
|
|
24
|
+
# 3. This notice may not be removed or altered from any source
|
|
25
|
+
# distribution.
|
|
26
|
+
#
|
|
27
|
+
# ******************************************************************************
|
|
28
|
+
#
|
|
29
|
+
# Ported to Go by Charmbracelet, Inc. in 2021 (charmbracelet/harmonica, MIT).
|
|
30
|
+
# Ported to Ruby for Charming in 2026 from charmbracelet/harmonica.
|
|
31
|
+
#
|
|
32
|
+
# For background on the algorithm see:
|
|
33
|
+
# https://www.ryanjuckett.com/damped-springs/
|
|
34
|
+
|
|
35
|
+
module Charming
|
|
36
|
+
# Spring is a damped harmonic oscillator for physics-based animation. It
|
|
37
|
+
# precomputes motion coefficients for a fixed time step so each frame update
|
|
38
|
+
# is four multiply-adds. Instances are immutable; the caller owns position
|
|
39
|
+
# and velocity (typically as Float attributes on an ApplicationState) and
|
|
40
|
+
# feeds them back in every frame:
|
|
41
|
+
#
|
|
42
|
+
# SPRING = Charming::Spring.new(delta_time: Charming.fps(60))
|
|
43
|
+
# position, velocity = SPRING.update(position, velocity, target)
|
|
44
|
+
#
|
|
45
|
+
# The damping ratio shapes the motion: below 1 overshoots and oscillates,
|
|
46
|
+
# exactly 1 reaches the target as fast as possible without overshooting,
|
|
47
|
+
# above 1 approaches slower still. Angular frequency scales the speed.
|
|
48
|
+
class Spring
|
|
49
|
+
def initialize(delta_time:, angular_frequency: 6.0, damping_ratio: 0.5)
|
|
50
|
+
angular_frequency = [0.0, angular_frequency].max
|
|
51
|
+
damping_ratio = [0.0, damping_ratio].max
|
|
52
|
+
@pos_pos, @pos_vel, @vel_pos, @vel_vel =
|
|
53
|
+
coefficients(delta_time, angular_frequency, damping_ratio)
|
|
54
|
+
freeze
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
# Advances one frame toward *target*, returning `[new_position, new_velocity]`.
|
|
58
|
+
def update(position, velocity, target)
|
|
59
|
+
relative = position - target
|
|
60
|
+
[relative * @pos_pos + velocity * @pos_vel + target,
|
|
61
|
+
relative * @vel_pos + velocity * @vel_vel]
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
# True once the motion has effectively come to rest at *target* — the guard
|
|
65
|
+
# for stopping an animation timer.
|
|
66
|
+
def settled?(position, velocity, target, epsilon: 0.01)
|
|
67
|
+
(position - target).abs < epsilon && velocity.abs < epsilon
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
private
|
|
71
|
+
|
|
72
|
+
def coefficients(delta_time, frequency, ratio)
|
|
73
|
+
return [1.0, 0.0, 0.0, 1.0] if frequency < Float::EPSILON
|
|
74
|
+
|
|
75
|
+
if ratio > 1.0 + Float::EPSILON
|
|
76
|
+
over_damped(delta_time, frequency, ratio)
|
|
77
|
+
elsif ratio < 1.0 - Float::EPSILON
|
|
78
|
+
under_damped(delta_time, frequency, ratio)
|
|
79
|
+
else
|
|
80
|
+
critically_damped(delta_time, frequency)
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def over_damped(delta_time, frequency, ratio)
|
|
85
|
+
za = -frequency * ratio
|
|
86
|
+
zb = frequency * Math.sqrt(ratio * ratio - 1.0)
|
|
87
|
+
z1 = za - zb
|
|
88
|
+
z2 = za + zb
|
|
89
|
+
e2 = Math.exp(z2 * delta_time)
|
|
90
|
+
e1_over_two_zb = Math.exp(z1 * delta_time) / (2.0 * zb)
|
|
91
|
+
e2_over_two_zb = e2 / (2.0 * zb)
|
|
92
|
+
z1e1_over_two_zb = z1 * e1_over_two_zb
|
|
93
|
+
z2e2_over_two_zb = z2 * e2_over_two_zb
|
|
94
|
+
|
|
95
|
+
[e1_over_two_zb * z2 - z2e2_over_two_zb + e2,
|
|
96
|
+
-e1_over_two_zb + e2_over_two_zb,
|
|
97
|
+
(z1e1_over_two_zb - z2e2_over_two_zb + e2) * z2,
|
|
98
|
+
-z1e1_over_two_zb + z2e2_over_two_zb]
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
def under_damped(delta_time, frequency, ratio)
|
|
102
|
+
omega_zeta = frequency * ratio
|
|
103
|
+
alpha = frequency * Math.sqrt(1.0 - ratio * ratio)
|
|
104
|
+
exp_term = Math.exp(-omega_zeta * delta_time)
|
|
105
|
+
exp_sin = exp_term * Math.sin(alpha * delta_time)
|
|
106
|
+
exp_cos = exp_term * Math.cos(alpha * delta_time)
|
|
107
|
+
exp_omega_zeta_sin_over_alpha = omega_zeta * exp_sin / alpha
|
|
108
|
+
|
|
109
|
+
[exp_cos + exp_omega_zeta_sin_over_alpha,
|
|
110
|
+
exp_sin / alpha,
|
|
111
|
+
-exp_sin * alpha - omega_zeta * exp_omega_zeta_sin_over_alpha,
|
|
112
|
+
exp_cos - exp_omega_zeta_sin_over_alpha]
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
def critically_damped(delta_time, frequency)
|
|
116
|
+
exp_term = Math.exp(-frequency * delta_time)
|
|
117
|
+
time_exp = delta_time * exp_term
|
|
118
|
+
time_exp_freq = time_exp * frequency
|
|
119
|
+
|
|
120
|
+
[time_exp_freq + exp_term,
|
|
121
|
+
time_exp,
|
|
122
|
+
-frequency * time_exp_freq,
|
|
123
|
+
-time_exp_freq + exp_term]
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
end
|
data/lib/charming/version.rb
CHANGED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Charming
|
|
4
|
+
module Welcome
|
|
5
|
+
# Controller for the built-in welcome screen. Renders without an app layout and
|
|
6
|
+
# binds only `q` to quit.
|
|
7
|
+
class Controller < Charming::Controller
|
|
8
|
+
key "q", :quit, scope: :global
|
|
9
|
+
|
|
10
|
+
def show
|
|
11
|
+
render_view ShowView, app_name: app_display_name
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
private
|
|
15
|
+
|
|
16
|
+
# The app's namespace for the welcome heading, or "Charming" for anonymous apps.
|
|
17
|
+
def app_display_name
|
|
18
|
+
name = application.class.namespace
|
|
19
|
+
name.to_s.empty? ? "Charming" : name
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Charming
|
|
4
|
+
module Welcome
|
|
5
|
+
# The welcome screen body: a pastel Miami-deco skyline over the app name, tagline,
|
|
6
|
+
# Charming version, and project link, centered on the terminal.
|
|
7
|
+
class ShowView < Charming::View
|
|
8
|
+
SKYLINE_COLORS = {
|
|
9
|
+
"F" => "#f0437c", # flamingo
|
|
10
|
+
"B" => "#f9cfd8", # blush
|
|
11
|
+
"M" => "#bfe8dc", # mint
|
|
12
|
+
"C" => "#f3e6c9", # cream
|
|
13
|
+
"P" => "#fdfaf3", # plaster
|
|
14
|
+
"G" => "#1d4b44" # palm green
|
|
15
|
+
}.freeze
|
|
16
|
+
|
|
17
|
+
# Rows of [art, color mask] pairs; each mask letter colors the glyph above it.
|
|
18
|
+
SKYLINE = [
|
|
19
|
+
[" ▲ ",
|
|
20
|
+
" F "],
|
|
21
|
+
[" █ ",
|
|
22
|
+
" F "],
|
|
23
|
+
[" ▄▄▄ ▄█▄ ▄▄▄ ",
|
|
24
|
+
" BBB PFP MMM "],
|
|
25
|
+
[" ███ ▐███▌ ███ ",
|
|
26
|
+
" BBB PPPPP MMM "],
|
|
27
|
+
[" █▀▀▀█ ▐███▌ █▀▀▀█ ",
|
|
28
|
+
" BBBBB PPPPP MMMMM "],
|
|
29
|
+
[" ▄█▄ █████ ▐█████▌ █████ ▄█▄ ",
|
|
30
|
+
" GGG BBBBB PPPPPPP MMMMM GGG "],
|
|
31
|
+
[" █ ▄▄▄ ██▀▀▀██ ▐█████▌ ██▀▀▀██ ▄▄▄ █ ",
|
|
32
|
+
" G CCC BBBBBBB PPPPPPP MMMMMMM CCC G "],
|
|
33
|
+
[" █ ███ ███████ ▐███████▌ ███████ ███ █ ",
|
|
34
|
+
" G CCC BBBBBBB PPPPPPPPP MMMMMMM CCC G "],
|
|
35
|
+
[" █ ███ ███████ ▐███████▌ ███████ ███ █ ",
|
|
36
|
+
" G CCC BBBBBBB PPPPPPPPP MMMMMMM CCC G "],
|
|
37
|
+
["▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁",
|
|
38
|
+
"CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC"]
|
|
39
|
+
].freeze
|
|
40
|
+
SKYLINE_WIDTH = SKYLINE.map { |art, _mask| art.length }.max
|
|
41
|
+
SKYLINE_HEIGHT = SKYLINE.length
|
|
42
|
+
|
|
43
|
+
def render
|
|
44
|
+
screen_layout(background: theme.background) do
|
|
45
|
+
pane(style: centered) do
|
|
46
|
+
welcome_content
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
private
|
|
52
|
+
|
|
53
|
+
def centered
|
|
54
|
+
style.align(:center).align_vertical(:middle)
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def welcome_content
|
|
58
|
+
column(*blocks, gap: 1, align: :center)
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def blocks
|
|
62
|
+
[skyline, heading, tagline, footer, hint].compact
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def skyline
|
|
66
|
+
return unless skyline_fits?
|
|
67
|
+
|
|
68
|
+
column(*SKYLINE.map { |art, mask| paint_row(art, mask) })
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
# Leave room below the art for the heading, tagline, footer, and hint lines.
|
|
72
|
+
def skyline_fits?
|
|
73
|
+
layout_screen.width >= SKYLINE_WIDTH && layout_screen.height >= SKYLINE_HEIGHT + 8
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def paint_row(art, mask)
|
|
77
|
+
color_runs(art, mask).map { |run, key| paint(run, key) }.join
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
# Groups adjacent glyphs sharing a mask letter into [run, letter] pairs.
|
|
81
|
+
def color_runs(art, mask)
|
|
82
|
+
art.chars.zip(mask.chars)
|
|
83
|
+
.chunk { |_glyph, key| key || " " }
|
|
84
|
+
.map { |key, pairs| [pairs.map(&:first).join, key] }
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def paint(run, key)
|
|
88
|
+
color = SKYLINE_COLORS[key]
|
|
89
|
+
color ? style.foreground(color).render(run) : run
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
def heading
|
|
93
|
+
text app_name, style: theme.title
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def tagline
|
|
97
|
+
text "A Rails-inspired Ruby TUI framework", style: theme.text
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
def footer
|
|
101
|
+
column(
|
|
102
|
+
text("Charming v#{Charming::VERSION}", style: theme.muted),
|
|
103
|
+
text("https://github.com/pandorocks/charming", style: theme.muted),
|
|
104
|
+
align: :center
|
|
105
|
+
)
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
def hint
|
|
109
|
+
text "Define a root route in config/routes.rb to replace this screen.", style: theme.muted
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
end
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Charming
|
|
4
|
+
# Welcome is the built-in placeholder screen shown when an application defines no
|
|
5
|
+
# routes yet — the TUI equivalent of Rails' welcome page. It lives in the gem and is
|
|
6
|
+
# never copied into apps: defining any route in config/routes.rb replaces it.
|
|
7
|
+
module Welcome
|
|
8
|
+
# The fallback route the Runtime uses when the application has no routes.
|
|
9
|
+
def self.route
|
|
10
|
+
Router::Route.new(path: "/", controller_class: Controller, action: :show, title: "Welcome", params: {})
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
data/lib/charming.rb
CHANGED
|
@@ -43,6 +43,12 @@ module Charming
|
|
|
43
43
|
Runtime.new(application, backend: backend).run
|
|
44
44
|
end
|
|
45
45
|
|
|
46
|
+
# Returns the seconds-per-frame time delta for a frame rate, for initializing
|
|
47
|
+
# physics primitives: `Charming::Spring.new(delta_time: Charming.fps(60))`.
|
|
48
|
+
def self.fps(frames_per_second)
|
|
49
|
+
1.0 / frames_per_second
|
|
50
|
+
end
|
|
51
|
+
|
|
46
52
|
# Returns the normalized key symbol for an event-like object — `event.key` when the object responds
|
|
47
53
|
# to it, otherwise `event.to_sym`. Lets components treat raw strings and KeyEvent objects uniformly.
|
|
48
54
|
def self.key_of(event)
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: charming
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.3.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- pando
|
|
@@ -206,6 +206,7 @@ files:
|
|
|
206
206
|
- lib/charming/controller/session_state.rb
|
|
207
207
|
- lib/charming/controller/sidebar_navigation.rb
|
|
208
208
|
- lib/charming/controller/terminal.rb
|
|
209
|
+
- lib/charming/controller/timers.rb
|
|
209
210
|
- lib/charming/database/commands.rb
|
|
210
211
|
- lib/charming/escape.rb
|
|
211
212
|
- lib/charming/events/focus_event.rb
|
|
@@ -223,6 +224,7 @@ files:
|
|
|
223
224
|
- lib/charming/generators/controller_generator.rb
|
|
224
225
|
- lib/charming/generators/database_installer.rb
|
|
225
226
|
- lib/charming/generators/error.rb
|
|
227
|
+
- lib/charming/generators/layout_generator.rb
|
|
226
228
|
- lib/charming/generators/migration_generator.rb
|
|
227
229
|
- lib/charming/generators/migration_timestamp.rb
|
|
228
230
|
- lib/charming/generators/model_generator.rb
|
|
@@ -239,21 +241,16 @@ files:
|
|
|
239
241
|
- lib/charming/generators/templates/app/dot_rspec.template
|
|
240
242
|
- lib/charming/generators/templates/app/executable.template
|
|
241
243
|
- lib/charming/generators/templates/app/gemspec.template
|
|
242
|
-
- lib/charming/generators/templates/app/home_controller.template
|
|
243
|
-
- lib/charming/generators/templates/app/home_state.template
|
|
244
244
|
- lib/charming/generators/templates/app/keep.template
|
|
245
245
|
- lib/charming/generators/templates/app/layout.template
|
|
246
246
|
- lib/charming/generators/templates/app/root_file.template
|
|
247
247
|
- lib/charming/generators/templates/app/routes.template
|
|
248
248
|
- lib/charming/generators/templates/app/seeds.template
|
|
249
|
-
- lib/charming/generators/templates/app/spec_controller.template
|
|
250
249
|
- lib/charming/generators/templates/app/spec_helper.template
|
|
251
|
-
- lib/charming/generators/templates/app/spec_state.template
|
|
252
|
-
- lib/charming/generators/templates/app/spec_view.template
|
|
253
250
|
- lib/charming/generators/templates/app/version.template
|
|
254
|
-
- lib/charming/generators/templates/app/view.template
|
|
255
251
|
- lib/charming/generators/templates/component/component.rb.template
|
|
256
252
|
- lib/charming/generators/templates/controller/controller.rb.template
|
|
253
|
+
- lib/charming/generators/templates/layout/sidebar/application_layout.rb.template
|
|
257
254
|
- lib/charming/generators/templates/model/migration.rb.template
|
|
258
255
|
- lib/charming/generators/templates/model/model.rb.template
|
|
259
256
|
- lib/charming/generators/templates/model/spec.rb.template
|
|
@@ -280,6 +277,7 @@ files:
|
|
|
280
277
|
- lib/charming/internal/terminal/modified_key_parser.rb
|
|
281
278
|
- lib/charming/internal/terminal/mouse_parser.rb
|
|
282
279
|
- lib/charming/internal/terminal/tty_backend.rb
|
|
280
|
+
- lib/charming/internal/timer_control.rb
|
|
283
281
|
- lib/charming/presentation/component.rb
|
|
284
282
|
- lib/charming/presentation/components/activity_indicator.rb
|
|
285
283
|
- lib/charming/presentation/components/audio.rb
|
|
@@ -370,10 +368,12 @@ files:
|
|
|
370
368
|
- lib/charming/presentation/ui/truncate.rb
|
|
371
369
|
- lib/charming/presentation/ui/width.rb
|
|
372
370
|
- lib/charming/presentation/view.rb
|
|
371
|
+
- lib/charming/projectile.rb
|
|
373
372
|
- lib/charming/response.rb
|
|
374
373
|
- lib/charming/router.rb
|
|
375
374
|
- lib/charming/runtime.rb
|
|
376
375
|
- lib/charming/screen.rb
|
|
376
|
+
- lib/charming/spring.rb
|
|
377
377
|
- lib/charming/tasks/cancelled.rb
|
|
378
378
|
- lib/charming/tasks/inline_executor.rb
|
|
379
379
|
- lib/charming/tasks/progress.rb
|
|
@@ -381,6 +381,9 @@ files:
|
|
|
381
381
|
- lib/charming/tasks/threaded_executor.rb
|
|
382
382
|
- lib/charming/test_helper.rb
|
|
383
383
|
- lib/charming/version.rb
|
|
384
|
+
- lib/charming/welcome.rb
|
|
385
|
+
- lib/charming/welcome/controller.rb
|
|
386
|
+
- lib/charming/welcome/show_view.rb
|
|
384
387
|
- sig/charming.rbs
|
|
385
388
|
homepage: https://github.com/pandorocks/charming
|
|
386
389
|
licenses:
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require "__APP_SNAKE__"
|
|
4
|
-
|
|
5
|
-
RSpec.describe __APP_CLASS__::HomeController do
|
|
6
|
-
let(:application) { __APP_CLASS__::Application.new }
|
|
7
|
-
|
|
8
|
-
subject(:controller) { described_class.new(application: application) }
|
|
9
|
-
|
|
10
|
-
describe "#show" do
|
|
11
|
-
it "renders the view with the state" do
|
|
12
|
-
response = controller.dispatch(:show)
|
|
13
|
-
|
|
14
|
-
expect(response).to respond_to(:body)
|
|
15
|
-
end
|
|
16
|
-
end
|
|
17
|
-
end
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require "__APP_SNAKE__"
|
|
4
|
-
|
|
5
|
-
RSpec.describe __APP_CLASS__::HomeState do
|
|
6
|
-
describe "#title" do
|
|
7
|
-
it "has the correct default string value" do
|
|
8
|
-
instance = described_class.new
|
|
9
|
-
expect(instance.title).to eq("__APP_NAME__")
|
|
10
|
-
end
|
|
11
|
-
|
|
12
|
-
it "accepts overridden title values" do
|
|
13
|
-
instance = described_class.new(title: "Alternative")
|
|
14
|
-
expect(instance.title).to eq("Alternative")
|
|
15
|
-
end
|
|
16
|
-
end
|
|
17
|
-
end
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require "__APP_SNAKE__"
|
|
4
|
-
|
|
5
|
-
RSpec.describe __APP_CLASS__::Home::ShowView do
|
|
6
|
-
describe "#render" do
|
|
7
|
-
it "renders the state title" do
|
|
8
|
-
view = described_class.new(
|
|
9
|
-
home: double(title: "__APP_NAME__"),
|
|
10
|
-
theme: __APP_CLASS__::Application.new.theme
|
|
11
|
-
)
|
|
12
|
-
|
|
13
|
-
expect(view.render).to include("__APP_NAME__")
|
|
14
|
-
end
|
|
15
|
-
end
|
|
16
|
-
end
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module __APP_CLASS__
|
|
4
|
-
module Home
|
|
5
|
-
class ShowView < Charming::View
|
|
6
|
-
def render
|
|
7
|
-
column(title_line, help_line, gap: 1)
|
|
8
|
-
end
|
|
9
|
-
|
|
10
|
-
private
|
|
11
|
-
|
|
12
|
-
def title_line
|
|
13
|
-
text home.title, style: theme.title
|
|
14
|
-
end
|
|
15
|
-
|
|
16
|
-
def help_line
|
|
17
|
-
text "Press ctrl+p for commands, q to quit.", style: theme.muted
|
|
18
|
-
end
|
|
19
|
-
end
|
|
20
|
-
end
|
|
21
|
-
end
|