Skip to content

Commit a550c28

Browse files
authored
fix(banner): update launch banner to "NEMO RELAY" (#150)
#### Overview Updates the CLI welcome banner from the old Flow wordmark to a centered ANSI Shadow `NEMO RELAY` banner while preserving the existing green styling, rounded border, and docked version tag behavior. - [x] I confirm this contribution is my own work, or I have the right to submit it under this project's license. - [x] I searched existing issues and open pull requests, and this does not duplicate existing work. #### Details - Replaces the existing banner art with ANSI Shadow-style `NEMO RELAY` text. - Removes the experimental checkered flag columns from the banner. - Centers the banner as a single FIGlet block so all rows share the same left edge. - Keeps the existing plain-mode, color-mode, border, version tag, and cursor-control behavior. - Adds a regression test that verifies the FIGlet rows are centered together as one block. #### Where should the reviewer start? Start with `crates/cli/src/banner.rs` for the rendering change, then review `crates/cli/tests/coverage/banner_tests.rs` for the centering regression coverage. #### Related Issues: (use one of the action keywords Closes / Fixes / Resolves / Relates to) - Relates to # ## Summary by CodeRabbit * **Style** * Updated the CLI banner with a new glyph layout design featuring improved visual appearance. * Improved horizontal centering of banner content within the display frame. [![Review Change Stack](https://storage.googleapis.com/coderabbit_public_assets/review-stack-in-coderabbit-ui.svg)](https://app.coderabbit.ai/change-stack/NVIDIA/NeMo-Relay/pull/150?utm_source=github_walkthrough&utm_medium=github&utm_campaign=change_stack) Authors: - Bryan Bednarski (https://github.com/bbednarski9) Approvers: - Will Killian (https://github.com/willkill07) URL: #150
1 parent acafd6f commit a550c28

2 files changed

Lines changed: 75 additions & 14 deletions

File tree

crates/cli/src/banner.rs

Lines changed: 33 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -14,16 +14,15 @@
1414
1515
use std::io::IsTerminal;
1616

17-
/// Filled-block NeMo Relay figlet with a per-row right shift so the letters lean italic. Six
18-
/// content rows; the renderer prepends one blank row above and appends one below for spacing
19-
/// and the docked version tag.
17+
/// Filled-block NeMo Relay figlet generated with ANSI Shadow. Six content rows; the renderer
18+
/// prepends one blank row above and appends one below for spacing and the docked version tag.
2019
const BANNER_LINES: &[&str] = &[
21-
" ███╗ ██╗███████╗███╗ ███╗ ██████╗ ███████╗██╗ █████╗ ██╗ ██╗",
22-
" ████╗ ██║██╔════╝████╗ ████║██╔═══██╗ ██╔════╝██║ ██╔══██╗██║ ██║",
23-
" ██╔██╗ ██║█████╗ ██╔████╔██║██║ ██║ █████╗ ██║ ██║ ██║██║ █╗██║",
24-
" ██║╚██╗██║██╔══╝ ██║╚██╔╝██║██║ ██║ ██╔══╝ ██║ ██║ ██║██║██║██║",
25-
" ██║ ╚████║███████╗██║ ╚═╝ ██║╚██████╔╝ ██║ ███████╗╚██████╔╝╚███╔███╔╝",
26-
" ╚═╝ ╚═══╝╚══════╝╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚══════╚═════ ╚══╝╚══╝",
20+
"███╗ ██╗███████╗███╗ ███╗ ██████╗ ██████╗ ███████╗██╗ █████╗ ██╗ ██╗",
21+
"████╗ ██║██╔════╝████╗ ████║██╔═══██╗ ██╔══██╗██╔════╝██║ ██╔══██╗╚██╗ ██╔╝",
22+
"██╔██╗ ██║█████╗ ██╔████╔██║██║ ██║ ██████╔╝█████╗ ██║ ███████║ ╚████╔╝",
23+
"██║╚██╗██║██╔══╝ ██║╚██╔╝██║██║ ██║ ██╔══██╗██╔══╝ ██║ ██╔══██╚██╔╝",
24+
"██║ ╚████║███████╗██║ ╚═╝ ██║╚██████╔╝ ██║ ██║███████╗███████╗██║ ██║ ██║",
25+
"╚═╝ ╚═══╝╚══════╝╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═╝╚══════╝╚══════╝╚═╝ ╚═╝ ╚═╝",
2726
];
2827

2928
/// Banner geometry (visual rows including the top and bottom spacing rails).
@@ -32,7 +31,7 @@ const BOTTOM_RAIL: usize = FIGLET_ROWS + 1; // row index of the row below the fi
3231
const TOTAL_ROWS: usize = FIGLET_ROWS + 2; // top rail + 6 figlet rows + bottom rail
3332

3433
/// Version tag position, measured in columns.
35-
const COL_END: usize = 92; // right edge below "Flow"
34+
const COL_END: usize = 92; // version tag dock
3635

3736
const MIN_WIDTH: usize = 105;
3837

@@ -141,15 +140,35 @@ fn build_grid(width: usize) -> Vec<Vec<char>> {
141140
// Empty top rail, the 6 figlet rows, and an empty bottom rail. Each cell is a single char
142141
// because the figlet's block and box glyphs render as one display column in target terminals.
143142
let mut grid = Vec::with_capacity(TOTAL_ROWS);
143+
let art_width = banner_art_width();
144+
let start_col = width.saturating_sub(art_width) / 2;
144145
grid.push(vec![' '; width]);
145-
grid.extend(BANNER_LINES.iter().map(|line| padded_row(line, width)));
146+
grid.extend(
147+
BANNER_LINES
148+
.iter()
149+
.map(|line| padded_row(line, width, start_col)),
150+
);
146151
grid.push(vec![' '; width]);
147152
grid
148153
}
149154

150-
fn padded_row(line: &str, width: usize) -> Vec<char> {
151-
let mut row: Vec<char> = line.chars().collect();
152-
row.resize(width, ' ');
155+
fn banner_art_width() -> usize {
156+
BANNER_LINES
157+
.iter()
158+
.map(|line| line.chars().count())
159+
.max()
160+
.unwrap_or(0)
161+
}
162+
163+
fn padded_row(line: &str, width: usize, start_col: usize) -> Vec<char> {
164+
let mut row = vec![' '; width];
165+
166+
for (index, ch) in line.chars().enumerate() {
167+
if let Some(cell) = row.get_mut(start_col + index) {
168+
*cell = ch;
169+
}
170+
}
171+
153172
row
154173
}
155174

crates/cli/tests/coverage/banner_tests.rs

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,30 @@ fn render_frame_settled_contains_figlet_glyphs() {
88
let frame = render_frame(false);
99
// ANSI Shadow figlet uses filled blocks and box-drawing corners.
1010
assert!(frame.contains('█'), "frame missing figlet block glyph");
11+
assert!(
12+
!frame.contains("_/=|") && !frame.contains("|=\\_") && !frame.contains("╔██╗██╗"),
13+
"frame should not include flag columns"
14+
);
1115
assert!(
1216
frame.contains('╗') || frame.contains('╔'),
1317
"frame missing figlet corners"
1418
);
1519
}
1620

21+
#[test]
22+
fn figlet_rows_are_centered_as_one_block() {
23+
let frame = render_frame(false);
24+
let rows = frame_grid_rows(&frame);
25+
let figlet_rows = &rows[1..=FIGLET_ROWS];
26+
let left_edges: Vec<usize> = figlet_rows.iter().map(|row| first_art_col(row)).collect();
27+
let expected_left_edge = (frame_inner_width(&frame) - banner_art_width()) / 2;
28+
29+
assert!(
30+
left_edges.iter().all(|edge| *edge == expected_left_edge),
31+
"figlet rows should share centered left edge {expected_left_edge}; got {left_edges:?}"
32+
);
33+
}
34+
1735
#[test]
1836
fn render_frame_plain_mode_has_no_ansi_escapes() {
1937
let frame = render_frame(false);
@@ -66,3 +84,27 @@ fn docked_frame_includes_version_tag() {
6684
"docked frame should not include a bullet dot before the version"
6785
);
6886
}
87+
88+
fn frame_grid_rows(frame: &str) -> Vec<&str> {
89+
frame
90+
.lines()
91+
.filter(|line| line.starts_with('│') && line.ends_with('│'))
92+
.map(|line| line.trim_matches('│'))
93+
.collect()
94+
}
95+
96+
fn frame_inner_width(frame: &str) -> usize {
97+
frame
98+
.lines()
99+
.find(|line| line.starts_with('╭'))
100+
.expect("frame should include a top border")
101+
.trim_matches(['╭', '╮'])
102+
.chars()
103+
.count()
104+
}
105+
106+
fn first_art_col(row: &str) -> usize {
107+
row.chars()
108+
.position(|ch| !ch.is_whitespace())
109+
.expect("figlet row should contain art")
110+
}

0 commit comments

Comments
 (0)