Some checks failed
ci/woodpecker/pr/check Pipeline failed
CI / Check (pull_request) Has been cancelled
CI / Format (pull_request) Has been cancelled
CI / Clippy (pull_request) Has been cancelled
CI / Build (macos-latest) (pull_request) Has been cancelled
CI / Build (ubuntu-latest) (pull_request) Has been cancelled
CI / Build (windows-latest) (pull_request) Has been cancelled
105 lines
3.6 KiB
Rust
105 lines
3.6 KiB
Rust
use ratatui::{
|
|
layout::{Alignment, Rect},
|
|
style::{Color, Modifier, Style},
|
|
text::{Line, Span},
|
|
widgets::{Block, Borders, Clear, Paragraph},
|
|
Frame,
|
|
};
|
|
|
|
/// Рендерит модалку выбора реакций (emoji picker)
|
|
///
|
|
/// # Параметры
|
|
/// - `f`: Frame для рендеринга
|
|
/// - `area`: Область экрана
|
|
/// - `available_reactions`: Список доступных эмодзи
|
|
/// - `selected_index`: Индекс выбранного эмодзи
|
|
pub fn render_emoji_picker(
|
|
f: &mut Frame,
|
|
area: Rect,
|
|
available_reactions: &[String],
|
|
selected_index: usize,
|
|
) {
|
|
// Размеры модалки (зависят от количества реакций)
|
|
let emojis_per_row = 8;
|
|
let rows = available_reactions.len().div_ceil(emojis_per_row);
|
|
let modal_width = 50u16;
|
|
let modal_height = (rows + 4) as u16; // +4 для заголовка, отступов и подсказки
|
|
|
|
// Центрируем модалку
|
|
let x = area.x + (area.width.saturating_sub(modal_width)) / 2;
|
|
let y = area.y + (area.height.saturating_sub(modal_height)) / 2;
|
|
|
|
let modal_area = Rect::new(x, y, modal_width.min(area.width), modal_height.min(area.height));
|
|
|
|
// Очищаем область под модалкой
|
|
f.render_widget(Clear, modal_area);
|
|
|
|
// Формируем содержимое - сетка эмодзи
|
|
let mut text_lines = vec![Line::from("")]; // Пустая строка сверху
|
|
|
|
for row in 0..rows {
|
|
let mut row_spans = vec![Span::raw(" ")]; // Отступ слева
|
|
|
|
for col in 0..emojis_per_row {
|
|
let idx = row * emojis_per_row + col;
|
|
if idx >= available_reactions.len() {
|
|
break;
|
|
}
|
|
|
|
let emoji = &available_reactions[idx];
|
|
let is_selected = idx == selected_index;
|
|
|
|
let style = if is_selected {
|
|
Style::default()
|
|
.fg(Color::Yellow)
|
|
.add_modifier(Modifier::BOLD)
|
|
.add_modifier(Modifier::REVERSED)
|
|
} else {
|
|
Style::default().fg(Color::White)
|
|
};
|
|
|
|
row_spans.push(Span::styled(format!(" {} ", emoji), style));
|
|
row_spans.push(Span::raw(" ")); // Пробел между эмодзи
|
|
}
|
|
|
|
text_lines.push(Line::from(row_spans));
|
|
}
|
|
|
|
// Добавляем пустую строку и подсказку
|
|
text_lines.push(Line::from(""));
|
|
text_lines.push(Line::from(vec![
|
|
Span::styled(
|
|
" [←/→/↑/↓] ",
|
|
Style::default()
|
|
.fg(Color::Cyan)
|
|
.add_modifier(Modifier::BOLD),
|
|
),
|
|
Span::raw("Выбор "),
|
|
Span::styled(
|
|
" [Enter] ",
|
|
Style::default()
|
|
.fg(Color::Green)
|
|
.add_modifier(Modifier::BOLD),
|
|
),
|
|
Span::raw("Добавить "),
|
|
Span::styled(" [Esc] ", Style::default().fg(Color::Red).add_modifier(Modifier::BOLD)),
|
|
Span::raw("Отмена"),
|
|
]));
|
|
|
|
let modal = Paragraph::new(text_lines)
|
|
.block(
|
|
Block::default()
|
|
.borders(Borders::ALL)
|
|
.border_style(Style::default().fg(Color::Yellow))
|
|
.title(" Выбери реакцию ")
|
|
.title_style(
|
|
Style::default()
|
|
.fg(Color::Yellow)
|
|
.add_modifier(Modifier::BOLD),
|
|
),
|
|
)
|
|
.alignment(Alignment::Center);
|
|
|
|
f.render_widget(modal, modal_area);
|
|
}
|