Add CSV import functionality #1
162
src/main.rs
162
src/main.rs
@ -346,18 +346,13 @@ fn draw_title(f: &mut Frame, area: Rect, app: &App) {
|
|||||||
fn draw_content(f: &mut Frame, area: Rect, app: &App) {
|
fn draw_content(f: &mut Frame, area: Rect, app: &App) {
|
||||||
let side_open = app.formula_panel_open || app.category_panel_open || app.view_panel_open;
|
let side_open = app.formula_panel_open || app.category_panel_open || app.view_panel_open;
|
||||||
|
|
||||||
if side_open {
|
let grid_area = if side_open {
|
||||||
let side_w = 32u16;
|
let side_w = 32u16;
|
||||||
let chunks = Layout::default()
|
let chunks = Layout::default()
|
||||||
.direction(Direction::Horizontal)
|
.direction(Direction::Horizontal)
|
||||||
.constraints([Constraint::Min(40), Constraint::Length(side_w)])
|
.constraints([Constraint::Min(40), Constraint::Length(side_w)])
|
||||||
.split(area);
|
.split(area);
|
||||||
|
|
||||||
f.render_widget(
|
|
||||||
GridWidget::new(&app.model, &app.mode, &app.search_query),
|
|
||||||
chunks[0],
|
|
||||||
);
|
|
||||||
|
|
||||||
let side = chunks[1];
|
let side = chunks[1];
|
||||||
let panel_count = [
|
let panel_count = [
|
||||||
app.formula_panel_open,
|
app.formula_panel_open,
|
||||||
@ -366,40 +361,37 @@ fn draw_content(f: &mut Frame, area: Rect, app: &App) {
|
|||||||
]
|
]
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|&&b| b)
|
.filter(|&&b| b)
|
||||||
.count() as u16;
|
.count();
|
||||||
let ph = side.height / panel_count.max(1);
|
|
||||||
let mut y = side.y;
|
let constraints: Vec<Constraint> = std::iter::repeat(Constraint::Fill(1))
|
||||||
|
.take(panel_count)
|
||||||
|
.collect();
|
||||||
|
let panel_areas = Layout::default()
|
||||||
|
.direction(Direction::Vertical)
|
||||||
|
.constraints(constraints)
|
||||||
|
.split(side);
|
||||||
|
let mut slots = panel_areas.iter().copied();
|
||||||
|
|
||||||
if app.formula_panel_open {
|
if app.formula_panel_open {
|
||||||
let a = Rect::new(side.x, y, side.width, ph);
|
f.render_widget(FormulaPanel::new(&app.model, &app.mode, app.formula_cursor), slots.next().unwrap());
|
||||||
f.render_widget(
|
|
||||||
FormulaPanel::new(&app.model, &app.mode, app.formula_cursor),
|
|
||||||
a,
|
|
||||||
);
|
|
||||||
y += ph;
|
|
||||||
}
|
}
|
||||||
if app.category_panel_open {
|
if app.category_panel_open {
|
||||||
let a = Rect::new(side.x, y, side.width, ph);
|
f.render_widget(CategoryPanel::new(&app.model, &app.mode, app.cat_panel_cursor), slots.next().unwrap());
|
||||||
f.render_widget(
|
|
||||||
CategoryPanel::new(&app.model, &app.mode, app.cat_panel_cursor),
|
|
||||||
a,
|
|
||||||
);
|
|
||||||
y += ph;
|
|
||||||
}
|
}
|
||||||
if app.view_panel_open {
|
if app.view_panel_open {
|
||||||
let a = Rect::new(side.x, y, side.width, ph);
|
f.render_widget(ViewPanel::new(&app.model, &app.mode, app.view_panel_cursor), slots.next().unwrap());
|
||||||
f.render_widget(
|
|
||||||
ViewPanel::new(&app.model, &app.mode, app.view_panel_cursor),
|
|
||||||
a,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
chunks[0]
|
||||||
} else {
|
} else {
|
||||||
|
area
|
||||||
|
};
|
||||||
|
|
||||||
f.render_widget(
|
f.render_widget(
|
||||||
GridWidget::new(&app.model, &app.mode, &app.search_query),
|
GridWidget::new(&app.model, &app.mode, &app.search_query),
|
||||||
area,
|
grid_area,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
fn draw_tile_bar(f: &mut Frame, area: Rect, app: &App) {
|
fn draw_tile_bar(f: &mut Frame, area: Rect, app: &App) {
|
||||||
f.render_widget(TileBar::new(&app.model, &app.mode), area);
|
f.render_widget(TileBar::new(&app.model, &app.mode), area);
|
||||||
@ -490,6 +482,37 @@ fn draw_export_prompt(f: &mut Frame, area: Rect, app: &App) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone)]
|
||||||
|
enum LineKind {
|
||||||
|
Intro,
|
||||||
|
Header,
|
||||||
|
Command,
|
||||||
|
Example,
|
||||||
|
Plain,
|
||||||
|
}
|
||||||
|
|
||||||
|
const WELCOME_LINES: &[(&str, LineKind)] = &[
|
||||||
|
("Multi-dimensional data modeling — in your terminal.", LineKind::Intro),
|
||||||
|
("", LineKind::Plain),
|
||||||
|
("Getting started", LineKind::Header),
|
||||||
|
("", LineKind::Plain),
|
||||||
|
(":import <file.json> Import a JSON file", LineKind::Command),
|
||||||
|
(":add-cat <name> Add a category (dimension)", LineKind::Command),
|
||||||
|
(":add-item <cat> <name> Add an item to a category", LineKind::Command),
|
||||||
|
(":formula <cat> <expr> Add a formula, e.g.:", LineKind::Command),
|
||||||
|
(" Profit = Revenue - Cost", LineKind::Example),
|
||||||
|
(":w <file.improv> Save your model", LineKind::Command),
|
||||||
|
("", LineKind::Plain),
|
||||||
|
("Navigation", LineKind::Header),
|
||||||
|
("", LineKind::Plain),
|
||||||
|
("F C V Open panels (Formulas/Categories/Views)", LineKind::Plain),
|
||||||
|
("T Tile-select: pivot rows ↔ cols ↔ page", LineKind::Plain),
|
||||||
|
("i Enter Edit a cell", LineKind::Plain),
|
||||||
|
("[ ] Cycle the page-axis filter", LineKind::Plain),
|
||||||
|
("? or :help Full key reference", LineKind::Plain),
|
||||||
|
(":q Quit", LineKind::Plain),
|
||||||
|
];
|
||||||
|
|
||||||
fn draw_welcome(f: &mut Frame, area: Rect, _app: &App) {
|
fn draw_welcome(f: &mut Frame, area: Rect, _app: &App) {
|
||||||
let w = 58u16.min(area.width.saturating_sub(4));
|
let w = 58u16.min(area.width.saturating_sub(4));
|
||||||
let h = 20u16.min(area.height.saturating_sub(2));
|
let h = 20u16.min(area.height.saturating_sub(2));
|
||||||
@ -506,83 +529,20 @@ fn draw_welcome(f: &mut Frame, area: Rect, _app: &App) {
|
|||||||
let inner = block.inner(popup);
|
let inner = block.inner(popup);
|
||||||
f.render_widget(block, popup);
|
f.render_widget(block, popup);
|
||||||
|
|
||||||
let lines: &[(&str, Style)] = &[
|
for (i, (text, kind)) in WELCOME_LINES.iter().enumerate() {
|
||||||
(
|
|
||||||
"Multi-dimensional data modeling — in your terminal.",
|
|
||||||
Style::default().fg(Color::White),
|
|
||||||
),
|
|
||||||
("", Style::default()),
|
|
||||||
(
|
|
||||||
"Getting started",
|
|
||||||
Style::default()
|
|
||||||
.fg(Color::Blue)
|
|
||||||
.add_modifier(Modifier::BOLD),
|
|
||||||
),
|
|
||||||
("", Style::default()),
|
|
||||||
(
|
|
||||||
":import <file.json> Import a JSON file",
|
|
||||||
Style::default().fg(Color::Cyan),
|
|
||||||
),
|
|
||||||
(
|
|
||||||
":add-cat <name> Add a category (dimension)",
|
|
||||||
Style::default().fg(Color::Cyan),
|
|
||||||
),
|
|
||||||
(
|
|
||||||
":add-item <cat> <name> Add an item to a category",
|
|
||||||
Style::default().fg(Color::Cyan),
|
|
||||||
),
|
|
||||||
(
|
|
||||||
":formula <cat> <expr> Add a formula, e.g.:",
|
|
||||||
Style::default().fg(Color::Cyan),
|
|
||||||
),
|
|
||||||
(
|
|
||||||
" Profit = Revenue - Cost",
|
|
||||||
Style::default().fg(Color::Green),
|
|
||||||
),
|
|
||||||
(
|
|
||||||
":w <file.improv> Save your model",
|
|
||||||
Style::default().fg(Color::Cyan),
|
|
||||||
),
|
|
||||||
("", Style::default()),
|
|
||||||
(
|
|
||||||
"Navigation",
|
|
||||||
Style::default()
|
|
||||||
.fg(Color::Blue)
|
|
||||||
.add_modifier(Modifier::BOLD),
|
|
||||||
),
|
|
||||||
("", Style::default()),
|
|
||||||
(
|
|
||||||
"F C V Open panels (Formulas/Categories/Views)",
|
|
||||||
Style::default(),
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"T Tile-select: pivot rows ↔ cols ↔ page",
|
|
||||||
Style::default(),
|
|
||||||
),
|
|
||||||
("i Enter Edit a cell", Style::default()),
|
|
||||||
(
|
|
||||||
"[ ] Cycle the page-axis filter",
|
|
||||||
Style::default(),
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"? or :help Full key reference",
|
|
||||||
Style::default(),
|
|
||||||
),
|
|
||||||
(":q Quit", Style::default()),
|
|
||||||
];
|
|
||||||
|
|
||||||
for (i, (text, style)) in lines.iter().enumerate() {
|
|
||||||
if i >= inner.height as usize {
|
if i >= inner.height as usize {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
let style = match kind {
|
||||||
|
LineKind::Intro => Style::default().fg(Color::White),
|
||||||
|
LineKind::Header => Style::default().fg(Color::Blue).add_modifier(Modifier::BOLD),
|
||||||
|
LineKind::Command => Style::default().fg(Color::Cyan),
|
||||||
|
LineKind::Example => Style::default().fg(Color::Green),
|
||||||
|
LineKind::Plain => Style::default(),
|
||||||
|
};
|
||||||
f.render_widget(
|
f.render_widget(
|
||||||
Paragraph::new(*text).style(*style),
|
Paragraph::new(*text).style(style),
|
||||||
Rect::new(
|
Rect::new(inner.x + 1, inner.y + i as u16, inner.width.saturating_sub(2), 1),
|
||||||
inner.x + 1,
|
|
||||||
inner.y + i as u16,
|
|
||||||
inner.width.saturating_sub(2),
|
|
||||||
1,
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user