Files
llmx/llmx-rs/tui/src/onboarding/welcome.rs
Sebastian Krüger ca37c07257 chore: Remove OpenAI branding and references
Update project branding to reflect community fork status:

- Changed welcome message from "OpenAI's command-line coding agent"
  to "your command-line coding agent"
- Updated system prompt from "led by OpenAI" to "community project"
- Removed broken developers.openai.com/llmx documentation URLs
- Updated Windows setup instructions with correct npm package name
- Removed OpenAI CLA (not applicable to community fork)
- Removed OpenAI open source fund documentation
- Updated config docs to remove managed configuration references
- Changed npm package reference from @openai/llmx to @valknarthing/llmx

These changes complete the rebranding from OpenAI's project to an
independent community fork while maintaining proper attribution to
the original project in README.md.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-13 10:52:57 +01:00

144 lines
4.4 KiB
Rust

use crossterm::event::KeyCode;
use crossterm::event::KeyEvent;
use crossterm::event::KeyEventKind;
use crossterm::event::KeyModifiers;
use ratatui::buffer::Buffer;
use ratatui::layout::Rect;
use ratatui::prelude::Widget;
use ratatui::style::Stylize;
use ratatui::text::Line;
use ratatui::widgets::Clear;
use ratatui::widgets::Paragraph;
use ratatui::widgets::WidgetRef;
use ratatui::widgets::Wrap;
use crate::ascii_animation::AsciiAnimation;
use crate::onboarding::onboarding_screen::KeyboardHandler;
use crate::onboarding::onboarding_screen::StepStateProvider;
use crate::tui::FrameRequester;
use super::onboarding_screen::StepState;
const MIN_ANIMATION_HEIGHT: u16 = 20;
const MIN_ANIMATION_WIDTH: u16 = 60;
pub(crate) struct WelcomeWidget {
pub is_logged_in: bool,
animation: AsciiAnimation,
}
impl KeyboardHandler for WelcomeWidget {
fn handle_key_event(&mut self, key_event: KeyEvent) {
if key_event.kind == KeyEventKind::Press
&& key_event.code == KeyCode::Char('.')
&& key_event.modifiers.contains(KeyModifiers::CONTROL)
{
tracing::warn!("Welcome background to press '.'");
let _ = self.animation.pick_random_variant();
}
}
}
impl WelcomeWidget {
pub(crate) fn new(is_logged_in: bool, request_frame: FrameRequester) -> Self {
Self {
is_logged_in,
animation: AsciiAnimation::new(request_frame),
}
}
}
impl WidgetRef for &WelcomeWidget {
fn render_ref(&self, area: Rect, buf: &mut Buffer) {
Clear.render(area, buf);
self.animation.schedule_next_frame();
// Skip the animation entirely when the viewport is too small so we don't clip frames.
let show_animation =
area.height >= MIN_ANIMATION_HEIGHT && area.width >= MIN_ANIMATION_WIDTH;
let mut lines: Vec<Line> = Vec::new();
if show_animation {
let frame = self.animation.current_frame();
// let frame_line_count = frame.lines().count();
// lines.reserve(frame_line_count + 2);
lines.extend(frame.lines().map(Into::into));
lines.push("".into());
}
lines.push(Line::from(vec![
" ".into(),
"Welcome to ".into(),
"LLMX".bold(),
", your command-line coding agent".into(),
]));
Paragraph::new(lines)
.wrap(Wrap { trim: false })
.render(area, buf);
}
}
impl StepStateProvider for WelcomeWidget {
fn get_step_state(&self) -> StepState {
match self.is_logged_in {
true => StepState::Hidden,
false => StepState::Complete,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use ratatui::buffer::Buffer;
use ratatui::layout::Rect;
static VARIANT_A: [&str; 1] = ["frame-a"];
static VARIANT_B: [&str; 1] = ["frame-b"];
static VARIANTS: [&[&str]; 2] = [&VARIANT_A, &VARIANT_B];
#[test]
fn welcome_renders_animation_on_first_draw() {
let widget = WelcomeWidget::new(false, FrameRequester::test_dummy());
let area = Rect::new(0, 0, MIN_ANIMATION_WIDTH, MIN_ANIMATION_HEIGHT);
let mut buf = Buffer::empty(area);
(&widget).render(area, &mut buf);
let mut found = false;
let mut last_non_empty: Option<u16> = None;
for y in 0..area.height {
for x in 0..area.width {
if !buf[(x, y)].symbol().trim().is_empty() {
found = true;
last_non_empty = Some(y);
break;
}
}
}
assert!(found, "expected welcome animation to render characters");
let measured_rows = last_non_empty.map(|v| v + 2).unwrap_or(0);
assert!(
measured_rows >= MIN_ANIMATION_HEIGHT,
"expected measurement to report at least {MIN_ANIMATION_HEIGHT} rows, got {measured_rows}"
);
}
#[test]
fn ctrl_dot_changes_animation_variant() {
let mut widget = WelcomeWidget {
is_logged_in: false,
animation: AsciiAnimation::with_variants(FrameRequester::test_dummy(), &VARIANTS, 0),
};
let before = widget.animation.current_frame();
widget.handle_key_event(KeyEvent::new(KeyCode::Char('.'), KeyModifiers::CONTROL));
let after = widget.animation.current_frame();
assert_ne!(
before, after,
"expected ctrl+. to switch welcome animation variant"
);
}
}