Compare commits
21 Commits
v0.26.0-al
...
v0.26.0-al
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fe06f0c7b0 | ||
|
|
43b2b57191 | ||
|
|
50b81c9d4e | ||
|
|
2b4aa46a6a | ||
|
|
e1e85aa7af | ||
|
|
bf67850739 | ||
|
|
1561d64c80 | ||
|
|
ffd5fc79fc | ||
|
|
34648941d4 | ||
|
|
c69ca47922 | ||
|
|
f29c73fb1c | ||
|
|
f2eab71ccf | ||
|
|
6645d2e058 | ||
|
|
2faa879658 | ||
|
|
eb79256cee | ||
|
|
388aa467f1 | ||
|
|
8dd177a051 | ||
|
|
bbf2f906fb | ||
|
|
c24216cf30 | ||
|
|
5db895dcbf | ||
|
|
c50ff08a63 |
18
.github/workflows/check-pr.yml
vendored
18
.github/workflows/check-pr.yml
vendored
@@ -44,6 +44,24 @@ jobs:
|
||||
header: pr-title-lint-error
|
||||
delete: true
|
||||
|
||||
check-signed:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
pull-requests: write
|
||||
steps:
|
||||
# Check commit signature and add comment if needed
|
||||
- name: Check signed commits in PR
|
||||
uses: 1Password/check-signed-commits-action@v1
|
||||
with:
|
||||
comment: |
|
||||
Thank you for opening this pull request!
|
||||
|
||||
We require commits to be signed and it looks like this PR contains unsigned commits.
|
||||
|
||||
Get help in the [CONTRIBUTING.md](https://github.com/ratatui-org/ratatui/blob/main/CONTRIBUTING.md#sign-your-commits)
|
||||
or on [Github doc](https://docs.github.com/en/authentication/managing-commit-signature-verification/signing-commits).
|
||||
|
||||
check-breaking-change-label:
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
|
||||
@@ -15,6 +15,8 @@ This is a quick summary of the sections below:
|
||||
- Removed deprecated `Block::title_on_bottom`
|
||||
- `Line` now has an extra `style` field which applies the style to the entire line
|
||||
- `Block` style methods cannot be created in a const context
|
||||
- `Tabs::new()` now accepts `IntoIterator<Item: Into<Line<'a>>>`
|
||||
- `Table::new` now accepts `IntoIterator<Item: Into<Row<'a>>>`.
|
||||
- [v0.25.0](#v0250)
|
||||
- Removed `Axis::title_style` and `Buffer::set_background`
|
||||
- `List::new()` now accepts `IntoIterator<Item = Into<ListItem<'a>>>`
|
||||
@@ -46,6 +48,49 @@ This is a quick summary of the sections below:
|
||||
|
||||
## v0.26.0 (unreleased)
|
||||
|
||||
### `Table::new()` now accepts `IntoIterator<Item: Into<Row<'a>>>` ([#774])
|
||||
|
||||
[#774]: https://github.com/ratatui-org/ratatui/pull/774
|
||||
|
||||
Previously, `Table::new()` accepted `IntoIterator<Item=Row<'a>>`. The argument change to
|
||||
`IntoIterator<Item: Into<Row<'a>>>`, This allows more flexible types from calling scopes, though it
|
||||
can some break type inference in the calling scope for empty containers.
|
||||
|
||||
This can be resolved either by providing an explicit type (e.g. `Vec::<Row>::new()`), or by using
|
||||
`Table::default()`.
|
||||
|
||||
```diff
|
||||
- let table = Table::new(vec![], widths);
|
||||
// becomes
|
||||
+ let table = Table::default().widths(widths);
|
||||
```
|
||||
|
||||
### `Tabs::new()` now accepts `IntoIterator<Item: Into<Line<'a>>>` ([#776])
|
||||
|
||||
[#776]: https://github.com/ratatui-org/ratatui/pull/776
|
||||
|
||||
Previously, `Tabs::new()` accepted `Vec<T>` where `T: Into<Line<'a>>`. This allows more flexible
|
||||
types from calling scopes, though it can break some type inference in the calling scope.
|
||||
|
||||
This typically occurs when collecting an iterator prior to calling `Tabs::new`, and can be resolved
|
||||
by removing the call to `.collect()`.
|
||||
|
||||
```diff
|
||||
- let tabs = Tabs::new((0.3).map(|i| format!("{i}")).collect());
|
||||
// becomes
|
||||
+ let tabs = Tabs::new((0.3).map(|i| format!("{i}")));
|
||||
```
|
||||
|
||||
### Table::default() now sets segment_size to None and column_spacing to ([#751])
|
||||
|
||||
[#751]: https://github.com/ratatui-org/ratatui/pull/751
|
||||
|
||||
The default() implementation of Table now sets the column_spacing field to 1 and the segment_size
|
||||
field to SegmentSize::None. This will affect the rendering of a small amount of apps.
|
||||
|
||||
To use the previous default values, call `table.segment_size(Default::default())` and
|
||||
`table.column_spacing(0)`.
|
||||
|
||||
### `patch_style` & `reset_style` now consumes and returns `Self` ([#754])
|
||||
|
||||
[#754]: https://github.com/ratatui-org/ratatui/pull/754
|
||||
|
||||
@@ -24,7 +24,7 @@ rust-version = "1.70.0"
|
||||
|
||||
[dependencies]
|
||||
crossterm = { version = "0.27", optional = true }
|
||||
termion = { version = "2.0", optional = true }
|
||||
termion = { version = "3.0", optional = true }
|
||||
termwiz = { version = "0.20.0", optional = true }
|
||||
|
||||
serde = { version = "1", optional = true, features = ["derive"] }
|
||||
@@ -55,6 +55,7 @@ palette = "0.7.3"
|
||||
pretty_assertions = "1.4.0"
|
||||
rand = "0.8.5"
|
||||
rstest = "0.18.2"
|
||||
serde_json = "1.0.109"
|
||||
|
||||
[features]
|
||||
#! The crate provides a set of optional features that can be enabled in your `cargo.toml` file.
|
||||
@@ -268,3 +269,7 @@ doc-scrape-examples = true
|
||||
name = "inline"
|
||||
required-features = ["crossterm"]
|
||||
doc-scrape-examples = true
|
||||
|
||||
[[test]]
|
||||
name = "state_serde"
|
||||
required-features = ["serde"]
|
||||
|
||||
70
README.md
70
README.md
@@ -25,29 +25,22 @@
|
||||
|
||||
<div align="center">
|
||||
|
||||
[![Crate Badge]](https://crates.io/crates/ratatui)
|
||||
[![License Badge]](./LICENSE)
|
||||
[![CI Badge]](https://github.com/ratatui-org/ratatui/actions?query=workflow%3ACI+)
|
||||
[![Docs Badge]](https://docs.rs/crate/ratatui/)<br>
|
||||
[![Dependencies Badge]](https://deps.rs/repo/github/ratatui-org/ratatui)
|
||||
[![Codecov Badge]](https://app.codecov.io/gh/ratatui-org/ratatui)
|
||||
[![Discord Badge]](https://discord.gg/pMCEU9hNEj)
|
||||
[![Matrix Badge]](https://matrix.to/#/#ratatui:matrix.org)<br>
|
||||
[![Crate Badge]][Crate] [![Docs Badge]][API Docs] [![CI Badge]][CI Workflow] [![License
|
||||
Badge]](./LICENSE)<br>
|
||||
[![Codecov Badge]][Codecov] [![Deps.rs Badge]][Deps.rs] [![Discord Badge]][Discord Server]
|
||||
[![Matrix Badge]][Matrix]<br>
|
||||
|
||||
[Documentation](https://docs.rs/ratatui)
|
||||
· [Ratatui Website](https://ratatui.rs)
|
||||
· [Examples](https://github.com/ratatui-org/ratatui/tree/main/examples)
|
||||
· [Report a bug](https://github.com/ratatui-org/ratatui/issues/new?labels=bug&projects=&template=bug_report.md)
|
||||
· [Request a Feature](https://github.com/ratatui-org/ratatui/issues/new?labels=enhancement&projects=&template=feature_request.md)
|
||||
· [Send a Pull Request](https://github.com/ratatui-org/ratatui/compare)
|
||||
[Ratatui Website] · [API Docs] · [Examples]<br>
|
||||
[Contributing] · [Changelog] · [Breaking Changes]<br>
|
||||
[Report a bug] · [Request a Feature] · [Create a Pull Request]
|
||||
|
||||
</div>
|
||||
|
||||
# Ratatui
|
||||
|
||||
[Ratatui] is a crate for cooking up terminal user interfaces in Rust. It is a lightweight
|
||||
library that provides a set of widgets and utilities to build complex Rust TUIs. Ratatui was
|
||||
forked from the [tui-rs] crate in 2023 in order to continue its development.
|
||||
[Ratatui][Ratatui Website] is a crate for cooking up terminal user interfaces in Rust. It is a
|
||||
lightweight library that provides a set of widgets and utilities to build complex Rust TUIs.
|
||||
Ratatui was forked from the [tui-rs] crate in 2023 in order to continue its development.
|
||||
|
||||
## Installation
|
||||
|
||||
@@ -66,16 +59,16 @@ section of the [Ratatui Website] for more details on how to use other backends (
|
||||
Ratatui is based on the principle of immediate rendering with intermediate buffers. This means
|
||||
that for each frame, your app must render all widgets that are supposed to be part of the UI.
|
||||
This is in contrast to the retained mode style of rendering where widgets are updated and then
|
||||
automatically redrawn on the next frame. See the [Rendering] section of the [Ratatui Website] for
|
||||
more info.
|
||||
automatically redrawn on the next frame. See the [Rendering] section of the [Ratatui Website]
|
||||
for more info.
|
||||
|
||||
## Other documentation
|
||||
|
||||
- [Ratatui Website] - explains the library's concepts and provides step-by-step tutorials
|
||||
- [API Docs] - the full API documentation for the library on docs.rs.
|
||||
- [Examples] - a collection of examples that demonstrate how to use the library.
|
||||
- [API Documentation] - the full API documentation for the library on docs.rs.
|
||||
- [Changelog] - generated by [git-cliff] utilizing [Conventional Commits].
|
||||
- [Contributing] - Please read this if you are interested in contributing to the project.
|
||||
- [Changelog] - generated by [git-cliff] utilizing [Conventional Commits].
|
||||
- [Breaking Changes] - a list of breaking changes in the library.
|
||||
|
||||
## Quickstart
|
||||
@@ -83,8 +76,8 @@ more info.
|
||||
The following example demonstrates the minimal amount of code necessary to setup a terminal and
|
||||
render "Hello World!". The full code for this example which contains a little more detail is in
|
||||
[hello_world.rs]. For more guidance on different ways to structure your application see the
|
||||
[Application Patterns] and [Hello World tutorial] sections in the [Ratatui Website] and the various
|
||||
[Examples]. There are also several starter templates available:
|
||||
[Application Patterns] and [Hello World tutorial] sections in the [Ratatui Website] and the
|
||||
various [Examples]. There are also several starter templates available:
|
||||
|
||||
- [template]
|
||||
- [async-template] (book and template)
|
||||
@@ -117,8 +110,8 @@ module] and the [Backends] section of the [Ratatui Website] for more info.
|
||||
|
||||
The drawing logic is delegated to a closure that takes a [`Frame`] instance as argument. The
|
||||
[`Frame`] provides the size of the area to draw to and allows the app to render any [`Widget`]
|
||||
using the provided [`render_widget`] method. See the [Widgets] section of the [Ratatui Website] for
|
||||
more info.
|
||||
using the provided [`render_widget`] method. See the [Widgets] section of the [Ratatui Website]
|
||||
for more info.
|
||||
|
||||
### Handling events
|
||||
|
||||
@@ -131,10 +124,11 @@ Website] for more info. For example, if you are using [Crossterm], you can use t
|
||||
|
||||
```rust
|
||||
use std::io::{self, stdout};
|
||||
|
||||
use crossterm::{
|
||||
event::{self, Event, KeyCode},
|
||||
terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen},
|
||||
ExecutableCommand,
|
||||
terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen}
|
||||
};
|
||||
use ratatui::{prelude::*, widgets::*};
|
||||
|
||||
@@ -160,7 +154,7 @@ fn handle_events() -> io::Result<bool> {
|
||||
if key.kind == event::KeyEventKind::Press && key.code == KeyCode::Char('q') {
|
||||
return Ok(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(false)
|
||||
}
|
||||
@@ -195,7 +189,7 @@ fn ui(frame: &mut Frame) {
|
||||
Constraint::Length(1),
|
||||
Constraint::Min(0),
|
||||
Constraint::Length(1),
|
||||
]
|
||||
],
|
||||
)
|
||||
.split(frame.size());
|
||||
frame.render_widget(
|
||||
@@ -209,7 +203,7 @@ fn ui(frame: &mut Frame) {
|
||||
|
||||
let inner_layout = Layout::new(
|
||||
Direction::Horizontal,
|
||||
[Constraint::Percentage(50), Constraint::Percentage(50)]
|
||||
[Constraint::Percentage(50), Constraint::Percentage(50)],
|
||||
)
|
||||
.split(main_layout[1]);
|
||||
frame.render_widget(
|
||||
@@ -251,7 +245,7 @@ fn ui(frame: &mut Frame) {
|
||||
Constraint::Length(1),
|
||||
Constraint::Length(1),
|
||||
Constraint::Min(0),
|
||||
]
|
||||
],
|
||||
)
|
||||
.split(frame.size());
|
||||
|
||||
@@ -302,9 +296,12 @@ Running this example produces the following output:
|
||||
[template]: https://github.com/ratatui-org/template
|
||||
[async-template]: https://ratatui-org.github.io/async-template
|
||||
[Examples]: https://github.com/ratatui-org/ratatui/tree/main/examples
|
||||
[Report a bug]: https://github.com/ratatui-org/ratatui/issues/new?labels=bug&projects=&template=bug_report.md
|
||||
[Request a Feature]: https://github.com/ratatui-org/ratatui/issues/new?labels=enhancement&projects=&template=feature_request.md
|
||||
[Create a Pull Request]: https://github.com/ratatui-org/ratatui/compare
|
||||
[git-cliff]: https://git-cliff.org
|
||||
[Conventional Commits]: https://www.conventionalcommits.org
|
||||
[API Documentation]: https://docs.rs/ratatui
|
||||
[API Docs]: https://docs.rs/ratatui
|
||||
[Changelog]: https://github.com/ratatui-org/ratatui/blob/main/CHANGELOG.md
|
||||
[Contributing]: https://github.com/ratatui-org/ratatui/blob/main/CONTRIBUTING.md
|
||||
[Breaking Changes]: https://github.com/ratatui-org/ratatui/blob/main/BREAKING-CHANGES.md
|
||||
@@ -324,24 +321,29 @@ Running this example produces the following output:
|
||||
[`Backend`]: backend::Backend
|
||||
[`backend` module]: backend
|
||||
[`crossterm::event`]: https://docs.rs/crossterm/latest/crossterm/event/index.html
|
||||
[Ratatui]: https://ratatui.rs
|
||||
[Crate]: https://crates.io/crates/ratatui
|
||||
[Crossterm]: https://crates.io/crates/crossterm
|
||||
[Termion]: https://crates.io/crates/termion
|
||||
[Termwiz]: https://crates.io/crates/termwiz
|
||||
[tui-rs]: https://crates.io/crates/tui
|
||||
[hello_world.rs]: https://github.com/ratatui-org/ratatui/blob/main/examples/hello_world.rs
|
||||
[Crate Badge]: https://img.shields.io/crates/v/ratatui?logo=rust&style=flat-square
|
||||
[License Badge]: https://img.shields.io/crates/l/ratatui?style=flat-square
|
||||
[CI Badge]:
|
||||
https://img.shields.io/github/actions/workflow/status/ratatui-org/ratatui/ci.yml?style=flat-square&logo=github
|
||||
[CI Workflow]: https://github.com/ratatui-org/ratatui/actions/workflows/ci.yml
|
||||
[Codecov Badge]:
|
||||
https://img.shields.io/codecov/c/github/ratatui-org/ratatui?logo=codecov&style=flat-square&token=BAQ8SOKEST
|
||||
[Dependencies Badge]: https://deps.rs/repo/github/ratatui-org/ratatui/status.svg?style=flat-square
|
||||
[Codecov]: https://app.codecov.io/gh/ratatui-org/ratatui
|
||||
[Deps.rs Badge]: https://deps.rs/repo/github/ratatui-org/ratatui/status.svg?style=flat-square
|
||||
[Deps.rs]: https://deps.rs/repo/github/ratatui-org/ratatui
|
||||
[Discord Badge]:
|
||||
https://img.shields.io/discord/1070692720437383208?label=discord&logo=discord&style=flat-square
|
||||
[Discord Server]: https://discord.gg/pMCEU9hNEj
|
||||
[Docs Badge]: https://img.shields.io/docsrs/ratatui?logo=rust&style=flat-square
|
||||
[License Badge]: https://img.shields.io/crates/l/ratatui?style=flat-square
|
||||
[Matrix Badge]:
|
||||
https://img.shields.io/matrix/ratatui-general%3Amatrix.org?style=flat-square&logo=matrix&label=Matrix
|
||||
[Matrix]: https://matrix.to/#/#ratatui:matrix.org
|
||||
|
||||
<!-- cargo-rdme end -->
|
||||
|
||||
|
||||
@@ -1,5 +1,19 @@
|
||||
# Examples
|
||||
|
||||
> [!WARNING]
|
||||
> The examples in this folder run against the `main` branch. There may be backwards
|
||||
> incompatible changes compared to the [latest stable version](https://github.com/ratatui-org/ratatui/releases/latest).
|
||||
>
|
||||
> If you find that code copied from an example fails to run in your own application, please check
|
||||
> the tag of the release that your project is using.
|
||||
>
|
||||
> To view examples that match the version of Ratatui that you are using checkout the matching tag in
|
||||
> your local git repository, or select the tag in the "Switch branches/tags" button if you're
|
||||
> viewing this file on GitHub.
|
||||
>
|
||||
> To use incompatible example code as is, you can also use the most recent alpha release of Ratatui
|
||||
> (we release these weekly).
|
||||
|
||||
These gifs were created using [VHS](https://github.com/charmbracelet/vhs). Each example has a
|
||||
corresponding `.tape` file that holds instructions for how to generate the images. Note that the
|
||||
images themselves are stored in a separate git branch to avoid bloating the main repository.
|
||||
|
||||
@@ -7,13 +7,12 @@ use crate::app::App;
|
||||
|
||||
pub fn draw(f: &mut Frame, app: &mut App) {
|
||||
let chunks = Layout::vertical([Constraint::Length(3), Constraint::Min(0)]).split(f.size());
|
||||
let titles = app
|
||||
let tabs = app
|
||||
.tabs
|
||||
.titles
|
||||
.iter()
|
||||
.map(|t| text::Line::from(Span::styled(*t, Style::default().fg(Color::Green))))
|
||||
.collect();
|
||||
let tabs = Tabs::new(titles)
|
||||
.collect::<Tabs>()
|
||||
.block(Block::default().borders(Borders::ALL).title(app.title))
|
||||
.highlight_style(Style::default().fg(Color::Yellow))
|
||||
.select(app.tabs.index);
|
||||
|
||||
@@ -146,7 +146,7 @@ fn render_recipe(area: Rect, buf: &mut Buffer) {
|
||||
|
||||
fn render_ingredients(selected_row: usize, area: Rect, buf: &mut Buffer) {
|
||||
let mut state = TableState::default().with_selected(Some(selected_row));
|
||||
let rows = INGREDIENTS.iter().map(|&i| i.into()).collect_vec();
|
||||
let rows = INGREDIENTS.iter().cloned();
|
||||
let theme = THEME.recipe;
|
||||
StatefulWidget::render(
|
||||
Table::new(rows, [Constraint::Length(7), Constraint::Length(30)])
|
||||
|
||||
@@ -100,9 +100,6 @@ fn ui(f: &mut Frame, app: &mut App) {
|
||||
let mut long_line = s.repeat(usize::from(size.width) / s.len() + 4);
|
||||
long_line.push('\n');
|
||||
|
||||
let block = Block::default().black();
|
||||
f.render_widget(block, size);
|
||||
|
||||
let chunks = Layout::vertical([
|
||||
Constraint::Min(1),
|
||||
Constraint::Percentage(25),
|
||||
@@ -143,18 +140,10 @@ fn ui(f: &mut Frame, app: &mut App) {
|
||||
app.vertical_scroll_state = app.vertical_scroll_state.content_length(text.len());
|
||||
app.horizontal_scroll_state = app.horizontal_scroll_state.content_length(long_line.len());
|
||||
|
||||
let create_block = |title| {
|
||||
Block::default()
|
||||
.borders(Borders::ALL)
|
||||
.gray()
|
||||
.title(Span::styled(
|
||||
title,
|
||||
Style::default().add_modifier(Modifier::BOLD),
|
||||
))
|
||||
};
|
||||
let create_block = |title: &'static str| Block::bordered().gray().title(title.bold());
|
||||
|
||||
let title = Block::default()
|
||||
.title("Use h j k l to scroll ◄ ▲ ▼ ►")
|
||||
.title("Use h j k l or ◄ ▲ ▼ ► to scroll ".bold())
|
||||
.title_alignment(Alignment::Center);
|
||||
f.render_widget(title, chunks[0]);
|
||||
|
||||
|
||||
@@ -1,42 +1,23 @@
|
||||
use std::{error::Error, io};
|
||||
use std::{error::Error, io, str::FromStr};
|
||||
|
||||
use crossterm::{
|
||||
event::{self, DisableMouseCapture, EnableMouseCapture, Event, KeyCode, KeyEventKind},
|
||||
execute,
|
||||
terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen},
|
||||
};
|
||||
use itertools::Itertools;
|
||||
use ratatui::{prelude::*, widgets::*};
|
||||
|
||||
struct App<'a> {
|
||||
struct App {
|
||||
state: TableState,
|
||||
items: Vec<Vec<&'a str>>,
|
||||
items: Vec<Vec<String>>,
|
||||
}
|
||||
|
||||
impl<'a> App<'a> {
|
||||
fn new() -> App<'a> {
|
||||
impl App {
|
||||
fn new() -> App {
|
||||
App {
|
||||
state: TableState::default(),
|
||||
items: vec![
|
||||
vec!["Row11", "Row12", "Row13"],
|
||||
vec!["Row21", "Row22", "Row23"],
|
||||
vec!["Row31", "Row32", "Row33"],
|
||||
vec!["Row41", "Row42", "Row43"],
|
||||
vec!["Row51", "Row52", "Row53"],
|
||||
vec!["Row61", "Row62\nTest", "Row63"],
|
||||
vec!["Row71", "Row72", "Row73"],
|
||||
vec!["Row81", "Row82", "Row83"],
|
||||
vec!["Row91", "Row92", "Row93"],
|
||||
vec!["Row101", "Row102", "Row103"],
|
||||
vec!["Row111", "Row112", "Row113"],
|
||||
vec!["Row121", "Row122", "Row123"],
|
||||
vec!["Row131", "Row132", "Row133"],
|
||||
vec!["Row141", "Row142", "Row143"],
|
||||
vec!["Row151", "Row152", "Row153"],
|
||||
vec!["Row161", "Row162", "Row163"],
|
||||
vec!["Row171", "Row172", "Row173"],
|
||||
vec!["Row181", "Row182", "Row183"],
|
||||
vec!["Row191", "Row192", "Row193"],
|
||||
],
|
||||
state: TableState::default().with_selected(0),
|
||||
items: generate_fake_names(),
|
||||
}
|
||||
}
|
||||
pub fn next(&mut self) {
|
||||
@@ -68,6 +49,26 @@ impl<'a> App<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
fn generate_fake_names() -> Vec<Vec<String>> {
|
||||
use fakeit::{address, contact, name};
|
||||
|
||||
(0..20)
|
||||
.map(|_| {
|
||||
let name = name::full();
|
||||
let address = format!(
|
||||
"{}\n{}, {} {}",
|
||||
address::street(),
|
||||
address::city(),
|
||||
address::state(),
|
||||
address::zip()
|
||||
);
|
||||
let email = contact::email();
|
||||
vec![name, address, email]
|
||||
})
|
||||
.sorted_by(|a, b| a[0].cmp(&b[0]))
|
||||
.collect_vec()
|
||||
}
|
||||
|
||||
fn main() -> Result<(), Box<dyn Error>> {
|
||||
// setup terminal
|
||||
enable_raw_mode()?;
|
||||
@@ -116,47 +117,50 @@ fn run_app<B: Backend>(terminal: &mut Terminal<B>, mut app: App) -> io::Result<(
|
||||
fn ui(f: &mut Frame, app: &mut App) {
|
||||
let rects = Layout::vertical([Constraint::Percentage(100)]).split(f.size());
|
||||
|
||||
// colors from https://tailwindcss.com/docs/customizing-colors
|
||||
let header_bg = Color::from_str("#1e3a8a").unwrap();
|
||||
let header_fg = Color::from_str("#eff6ff").unwrap();
|
||||
let header_style = Style::default().fg(header_fg).bg(header_bg);
|
||||
let normal_row_color = Color::from_str("#1e293b").unwrap();
|
||||
let alt_row_color = Color::from_str("#0f172a").unwrap();
|
||||
let selected_style = Style::default().add_modifier(Modifier::REVERSED);
|
||||
let normal_style = Style::default().bg(Color::Blue);
|
||||
let header = ["Header1", "Header2", "Header3"]
|
||||
|
||||
let header = ["Name", "Address", "Email"]
|
||||
.iter()
|
||||
.map(|h| Cell::from(*h).style(Style::default().fg(Color::Red)))
|
||||
.cloned()
|
||||
.map(Cell::from)
|
||||
.collect::<Row>()
|
||||
.style(normal_style)
|
||||
.height(1)
|
||||
.bottom_margin(1);
|
||||
let footer = ["Footer1", "Footer2", "Footer3"]
|
||||
.iter()
|
||||
.map(|f| Cell::from(*f).style(Style::default().fg(Color::Yellow)))
|
||||
.collect::<Row>()
|
||||
.style(normal_style)
|
||||
.height(1)
|
||||
.top_margin(1);
|
||||
let rows = app.items.iter().map(|item| {
|
||||
let height = item
|
||||
.iter()
|
||||
.map(|content| content.chars().filter(|c| *c == '\n').count())
|
||||
.max()
|
||||
.unwrap_or(0)
|
||||
+ 1;
|
||||
.style(header_style)
|
||||
.height(1);
|
||||
let rows = app.items.iter().enumerate().map(|(i, item)| {
|
||||
let color = match i % 2 {
|
||||
0 => normal_row_color,
|
||||
_ => alt_row_color,
|
||||
};
|
||||
item.iter()
|
||||
.cloned()
|
||||
.map(|content| Cell::from(Text::from(format!("\n{}\n", content))))
|
||||
.collect::<Row>()
|
||||
.height(height as u16)
|
||||
.bottom_margin(1)
|
||||
.style(Style::new().bg(color))
|
||||
.height(4)
|
||||
});
|
||||
let bar = " █ ";
|
||||
let t = Table::new(
|
||||
rows,
|
||||
[
|
||||
Constraint::Percentage(50),
|
||||
Constraint::Max(30),
|
||||
Constraint::Min(10),
|
||||
Constraint::Length(15),
|
||||
Constraint::Min(30),
|
||||
Constraint::Min(25),
|
||||
],
|
||||
)
|
||||
.header(header)
|
||||
.footer(footer)
|
||||
.block(Block::default().borders(Borders::ALL).title("Table"))
|
||||
.highlight_style(selected_style)
|
||||
.highlight_symbol(">> ");
|
||||
.highlight_symbol(Text::from(vec![
|
||||
"".into(),
|
||||
bar.into(),
|
||||
bar.into(),
|
||||
"".into(),
|
||||
]))
|
||||
.highlight_spacing(HighlightSpacing::Always);
|
||||
f.render_stateful_widget(t, rects[0], &mut app.state);
|
||||
}
|
||||
|
||||
@@ -3,14 +3,17 @@
|
||||
Output "target/table.gif"
|
||||
Set Theme "Aardvark Blue"
|
||||
Set Width 1200
|
||||
Set Height 600
|
||||
Set Height 800
|
||||
Hide
|
||||
Type "cargo run --example=table --features=crossterm"
|
||||
Enter
|
||||
Sleep 1s
|
||||
Show
|
||||
Down@1s 4
|
||||
Up@1s 2
|
||||
Down@1s 8
|
||||
Up@1s 12
|
||||
Sleep 5s
|
||||
Sleep 2s
|
||||
Set TypingSpeed 0.5s
|
||||
Down 2
|
||||
Up 2
|
||||
Down 8
|
||||
Up 12
|
||||
Down 4
|
||||
Sleep 2s
|
||||
|
||||
@@ -85,15 +85,14 @@ fn ui(f: &mut Frame, app: &App) {
|
||||
|
||||
let block = Block::default().on_white().black();
|
||||
f.render_widget(block, area);
|
||||
let titles = app
|
||||
let tabs = app
|
||||
.titles
|
||||
.iter()
|
||||
.map(|t| {
|
||||
let (first, rest) = t.split_at(1);
|
||||
Line::from(vec![first.yellow(), rest.green()])
|
||||
})
|
||||
.collect();
|
||||
let tabs = Tabs::new(titles)
|
||||
.collect::<Tabs>()
|
||||
.block(Block::default().borders(Borders::ALL).title("Tabs"))
|
||||
.select(app.index)
|
||||
.style(Style::default().cyan().on_gray())
|
||||
|
||||
@@ -8,6 +8,7 @@ use crate::prelude::*;
|
||||
|
||||
mod offset;
|
||||
|
||||
use layout::Size;
|
||||
pub use offset::*;
|
||||
|
||||
/// A simple rectangle used in the computation of the layout and to give widgets a hint about the
|
||||
@@ -25,6 +26,58 @@ pub struct Rect {
|
||||
pub height: u16,
|
||||
}
|
||||
|
||||
/// Manages row divisions within a `Rect`.
|
||||
///
|
||||
/// The `Rows` struct is an iterator that allows iterating through rows of a given `Rect`.
|
||||
pub struct Rows {
|
||||
/// The `Rect` associated with the rows.
|
||||
pub rect: Rect,
|
||||
/// The y coordinate of the row within the `Rect`.
|
||||
pub current_row: u16,
|
||||
}
|
||||
|
||||
impl Iterator for Rows {
|
||||
type Item = Rect;
|
||||
|
||||
/// Retrieves the next row within the `Rect`.
|
||||
///
|
||||
/// Returns `None` when there are no more rows to iterate through.
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
if self.current_row >= self.rect.bottom() {
|
||||
return None;
|
||||
}
|
||||
let row = Rect::new(self.rect.x, self.current_row, self.rect.width, 1);
|
||||
self.current_row += 1;
|
||||
Some(row)
|
||||
}
|
||||
}
|
||||
|
||||
/// Manages column divisions within a `Rect`.
|
||||
///
|
||||
/// The `Columns` struct is an iterator that allows iterating through columns of a given `Rect`.
|
||||
pub struct Columns {
|
||||
/// The `Rect` associated with the columns.
|
||||
pub rect: Rect,
|
||||
/// The x coordinate of the column within the `Rect`.
|
||||
pub current_column: u16,
|
||||
}
|
||||
|
||||
impl Iterator for Columns {
|
||||
type Item = Rect;
|
||||
|
||||
/// Retrieves the next column within the `Rect`.
|
||||
///
|
||||
/// Returns `None` when there are no more columns to iterate through.
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
if self.current_column >= self.rect.right() {
|
||||
return None;
|
||||
}
|
||||
let column = Rect::new(self.current_column, self.rect.y, 1, self.rect.height);
|
||||
self.current_column += 1;
|
||||
Some(column)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Rect {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "{}x{}+{}+{}", self.width, self.height, self.x, self.y)
|
||||
@@ -230,6 +283,57 @@ impl Rect {
|
||||
let y = self.y.clamp(other.y, other.bottom().saturating_sub(height));
|
||||
Rect::new(x, y, width, height)
|
||||
}
|
||||
|
||||
/// Creates an iterator over rows within the `Rect`.
|
||||
///
|
||||
/// This method returns a `Rows` iterator that allows iterating through rows of the `Rect`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use ratatui::prelude::*;
|
||||
/// let area = Rect::new(0, 0, 10, 5);
|
||||
/// for row in area.rows() {
|
||||
/// // Perform operations on each row of the area
|
||||
/// println!("Row: {:?}", row);
|
||||
/// }
|
||||
/// ```
|
||||
pub fn rows(&self) -> Rows {
|
||||
Rows {
|
||||
rect: *self,
|
||||
current_row: self.y,
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates an iterator over columns within the `Rect`.
|
||||
///
|
||||
/// This method returns a `Columns` iterator that allows iterating through columns of the
|
||||
/// `Rect`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use ratatui::prelude::*;
|
||||
/// let area = Rect::new(0, 0, 10, 5);
|
||||
/// for column in area.columns() {
|
||||
/// // Perform operations on each column of the area
|
||||
/// println!("Column: {:?}", column);
|
||||
/// }
|
||||
/// ```
|
||||
pub fn columns(&self) -> Columns {
|
||||
Columns {
|
||||
rect: *self,
|
||||
current_column: self.x,
|
||||
}
|
||||
}
|
||||
|
||||
/// Converts the rect into a size struct.
|
||||
pub fn as_size(self) -> Size {
|
||||
Size {
|
||||
width: self.width,
|
||||
height: self.height,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
@@ -451,4 +555,39 @@ mod tests {
|
||||
let other = Rect::new(10, 10, 100, 100);
|
||||
assert_eq!(rect.clamp(other), expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn rows() {
|
||||
let area = Rect::new(0, 0, 3, 2);
|
||||
let rows: Vec<Rect> = area.rows().collect();
|
||||
|
||||
let expected_rows: Vec<Rect> = vec![Rect::new(0, 0, 3, 1), Rect::new(0, 1, 3, 1)];
|
||||
|
||||
assert_eq!(rows, expected_rows);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn columns() {
|
||||
let area = Rect::new(0, 0, 3, 2);
|
||||
let columns: Vec<Rect> = area.columns().collect();
|
||||
|
||||
let expected_columns: Vec<Rect> = vec![
|
||||
Rect::new(0, 0, 1, 2),
|
||||
Rect::new(1, 0, 1, 2),
|
||||
Rect::new(2, 0, 1, 2),
|
||||
];
|
||||
|
||||
assert_eq!(columns, expected_columns);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn as_size() {
|
||||
assert_eq!(
|
||||
Rect::new(1, 2, 3, 4).as_size(),
|
||||
Size {
|
||||
width: 3,
|
||||
height: 4
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,12 +1,59 @@
|
||||
#![warn(missing_docs)]
|
||||
use crate::prelude::*;
|
||||
|
||||
/// A simple size struct
|
||||
///
|
||||
/// The width and height are stored as `u16` values and represent the number of columns and rows
|
||||
/// respectively.
|
||||
#[derive(Debug, Default, Clone, Copy, Eq, PartialEq, Hash)]
|
||||
pub struct Size {
|
||||
/// The width in columns
|
||||
pub width: u16,
|
||||
/// The height in rows
|
||||
pub height: u16,
|
||||
}
|
||||
|
||||
impl Size {
|
||||
/// Create a new `Size` struct
|
||||
pub fn new(width: u16, height: u16) -> Self {
|
||||
Size { width, height }
|
||||
}
|
||||
}
|
||||
|
||||
impl From<(u16, u16)> for Size {
|
||||
fn from((width, height): (u16, u16)) -> Self {
|
||||
Size { width, height }
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Rect> for Size {
|
||||
fn from(rect: Rect) -> Self {
|
||||
rect.as_size()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn new() {
|
||||
let size = Size::new(10, 20);
|
||||
assert_eq!(size.width, 10);
|
||||
assert_eq!(size.height, 20);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_tuple() {
|
||||
let size = Size::from((10, 20));
|
||||
assert_eq!(size.width, 10);
|
||||
assert_eq!(size.height, 20);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_rect() {
|
||||
let size = Size::from(Rect::new(0, 0, 10, 20));
|
||||
assert_eq!(size.width, 10);
|
||||
assert_eq!(size.height, 20);
|
||||
}
|
||||
}
|
||||
|
||||
46
src/lib.rs
46
src/lib.rs
@@ -4,29 +4,21 @@
|
||||
//!
|
||||
//! <div align="center">
|
||||
//!
|
||||
//! [![Crate Badge]](https://crates.io/crates/ratatui)
|
||||
//! [![License Badge]](./LICENSE)
|
||||
//! [![CI Badge]](https://github.com/ratatui-org/ratatui/actions?query=workflow%3ACI+)
|
||||
//! [![Docs Badge]](https://docs.rs/crate/ratatui/)<br>
|
||||
//! [![Dependencies Badge]](https://deps.rs/repo/github/ratatui-org/ratatui)
|
||||
//! [![Codecov Badge]](https://app.codecov.io/gh/ratatui-org/ratatui)
|
||||
//! [![Discord Badge]](https://discord.gg/pMCEU9hNEj)
|
||||
//! [![Matrix Badge]](https://matrix.to/#/#ratatui:matrix.org)<br>
|
||||
//! [![Crate Badge]][Crate] [![Docs Badge]][API Docs] [![CI Badge]][CI Workflow] [![License
|
||||
//! Badge]](./LICENSE)<br>
|
||||
//! [![Codecov Badge]][Codecov] [![Deps.rs Badge]][Deps.rs] [![Discord Badge]][Discord Server]
|
||||
//! [![Matrix Badge]][Matrix]<br>
|
||||
//!
|
||||
//! [Documentation](https://docs.rs/ratatui)
|
||||
//! · [Ratatui Website](https://ratatui.rs)
|
||||
//! · [Examples](https://github.com/ratatui-org/ratatui/tree/main/examples)
|
||||
//! · [Report a bug](https://github.com/ratatui-org/ratatui/issues/new?labels=bug&projects=&template=bug_report.md)
|
||||
//! · [Request a Feature](https://github.com/ratatui-org/ratatui/issues/new?labels=enhancement&projects=&template=feature_request.md)
|
||||
//! · [Send a Pull Request](https://github.com/ratatui-org/ratatui/compare)
|
||||
//! [Ratatui Website] · [API Docs] · [Examples] · [Changelog] · [Breaking Changes]<br>
|
||||
//! [Contributing] · [Report a bug] · [Request a Feature] · [Create a Pull Request]
|
||||
//!
|
||||
//! </div>
|
||||
//!
|
||||
//! # Ratatui
|
||||
//!
|
||||
//! [Ratatui] is a crate for cooking up terminal user interfaces in Rust. It is a lightweight
|
||||
//! library that provides a set of widgets and utilities to build complex Rust TUIs. Ratatui was
|
||||
//! forked from the [tui-rs] crate in 2023 in order to continue its development.
|
||||
//! [Ratatui][Ratatui Website] is a crate for cooking up terminal user interfaces in Rust. It is a
|
||||
//! lightweight library that provides a set of widgets and utilities to build complex Rust TUIs.
|
||||
//! Ratatui was forked from the [tui-rs] crate in 2023 in order to continue its development.
|
||||
//!
|
||||
//! ## Installation
|
||||
//!
|
||||
@@ -51,10 +43,10 @@
|
||||
//! ## Other documentation
|
||||
//!
|
||||
//! - [Ratatui Website] - explains the library's concepts and provides step-by-step tutorials
|
||||
//! - [API Docs] - the full API documentation for the library on docs.rs.
|
||||
//! - [Examples] - a collection of examples that demonstrate how to use the library.
|
||||
//! - [API Documentation] - the full API documentation for the library on docs.rs.
|
||||
//! - [Changelog] - generated by [git-cliff] utilizing [Conventional Commits].
|
||||
//! - [Contributing] - Please read this if you are interested in contributing to the project.
|
||||
//! - [Changelog] - generated by [git-cliff] utilizing [Conventional Commits].
|
||||
//! - [Breaking Changes] - a list of breaking changes in the library.
|
||||
//!
|
||||
//! ## Quickstart
|
||||
@@ -300,9 +292,12 @@
|
||||
//! [template]: https://github.com/ratatui-org/template
|
||||
//! [async-template]: https://ratatui-org.github.io/async-template
|
||||
//! [Examples]: https://github.com/ratatui-org/ratatui/tree/main/examples
|
||||
//! [Report a bug]: https://github.com/ratatui-org/ratatui/issues/new?labels=bug&projects=&template=bug_report.md
|
||||
//! [Request a Feature]: https://github.com/ratatui-org/ratatui/issues/new?labels=enhancement&projects=&template=feature_request.md
|
||||
//! [Create a Pull Request]: https://github.com/ratatui-org/ratatui/compare
|
||||
//! [git-cliff]: https://git-cliff.org
|
||||
//! [Conventional Commits]: https://www.conventionalcommits.org
|
||||
//! [API Documentation]: https://docs.rs/ratatui
|
||||
//! [API Docs]: https://docs.rs/ratatui
|
||||
//! [Changelog]: https://github.com/ratatui-org/ratatui/blob/main/CHANGELOG.md
|
||||
//! [Contributing]: https://github.com/ratatui-org/ratatui/blob/main/CONTRIBUTING.md
|
||||
//! [Breaking Changes]: https://github.com/ratatui-org/ratatui/blob/main/BREAKING-CHANGES.md
|
||||
@@ -322,24 +317,29 @@
|
||||
//! [`Backend`]: backend::Backend
|
||||
//! [`backend` module]: backend
|
||||
//! [`crossterm::event`]: https://docs.rs/crossterm/latest/crossterm/event/index.html
|
||||
//! [Ratatui]: https://ratatui.rs
|
||||
//! [Crate]: https://crates.io/crates/ratatui
|
||||
//! [Crossterm]: https://crates.io/crates/crossterm
|
||||
//! [Termion]: https://crates.io/crates/termion
|
||||
//! [Termwiz]: https://crates.io/crates/termwiz
|
||||
//! [tui-rs]: https://crates.io/crates/tui
|
||||
//! [hello_world.rs]: https://github.com/ratatui-org/ratatui/blob/main/examples/hello_world.rs
|
||||
//! [Crate Badge]: https://img.shields.io/crates/v/ratatui?logo=rust&style=flat-square
|
||||
//! [License Badge]: https://img.shields.io/crates/l/ratatui?style=flat-square
|
||||
//! [CI Badge]:
|
||||
//! https://img.shields.io/github/actions/workflow/status/ratatui-org/ratatui/ci.yml?style=flat-square&logo=github
|
||||
//! [CI Workflow]: https://github.com/ratatui-org/ratatui/actions/workflows/ci.yml
|
||||
//! [Codecov Badge]:
|
||||
//! https://img.shields.io/codecov/c/github/ratatui-org/ratatui?logo=codecov&style=flat-square&token=BAQ8SOKEST
|
||||
//! [Dependencies Badge]: https://deps.rs/repo/github/ratatui-org/ratatui/status.svg?style=flat-square
|
||||
//! [Codecov]: https://app.codecov.io/gh/ratatui-org/ratatui
|
||||
//! [Deps.rs Badge]: https://deps.rs/repo/github/ratatui-org/ratatui/status.svg?style=flat-square
|
||||
//! [Deps.rs]: https://deps.rs/repo/github/ratatui-org/ratatui
|
||||
//! [Discord Badge]:
|
||||
//! https://img.shields.io/discord/1070692720437383208?label=discord&logo=discord&style=flat-square
|
||||
//! [Discord Server]: https://discord.gg/pMCEU9hNEj
|
||||
//! [Docs Badge]: https://img.shields.io/docsrs/ratatui?logo=rust&style=flat-square
|
||||
//! [License Badge]: https://img.shields.io/crates/l/ratatui?style=flat-square
|
||||
//! [Matrix Badge]:
|
||||
//! https://img.shields.io/matrix/ratatui-general%3Amatrix.org?style=flat-square&logo=matrix&label=Matrix
|
||||
//! [Matrix]: https://matrix.to/#/#ratatui:matrix.org
|
||||
|
||||
// show the feature flags in the generated documentation
|
||||
#![cfg_attr(docsrs, feature(doc_auto_cfg))]
|
||||
|
||||
@@ -72,10 +72,12 @@ use std::fmt::{self, Debug};
|
||||
|
||||
use bitflags::bitflags;
|
||||
|
||||
mod stylize;
|
||||
pub use stylize::{Styled, Stylize};
|
||||
mod color;
|
||||
mod stylize;
|
||||
|
||||
pub use color::Color;
|
||||
pub use stylize::{Styled, Stylize};
|
||||
pub mod palette;
|
||||
|
||||
bitflags! {
|
||||
/// Modifier changes the way a piece of text is displayed.
|
||||
|
||||
@@ -127,6 +127,18 @@ pub enum Color {
|
||||
Indexed(u8),
|
||||
}
|
||||
|
||||
impl Color {
|
||||
/// Convert a u32 to a Color
|
||||
///
|
||||
/// The u32 should be in the format 0x00RRGGBB.
|
||||
pub const fn from_u32(u: u32) -> Color {
|
||||
let r = (u >> 16) as u8;
|
||||
let g = (u >> 8) as u8;
|
||||
let b = u as u8;
|
||||
Color::Rgb(r, g, b)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "serde")]
|
||||
impl<'de> serde::Deserialize<'de> for Color {
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
@@ -270,6 +282,15 @@ mod tests {
|
||||
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn from_u32() {
|
||||
assert_eq!(Color::from_u32(0x000000), Color::Rgb(0, 0, 0));
|
||||
assert_eq!(Color::from_u32(0xFF0000), Color::Rgb(255, 0, 0));
|
||||
assert_eq!(Color::from_u32(0x00FF00), Color::Rgb(0, 255, 0));
|
||||
assert_eq!(Color::from_u32(0x0000FF), Color::Rgb(0, 0, 255));
|
||||
assert_eq!(Color::from_u32(0xFFFFFF), Color::Rgb(255, 255, 255));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_rgb_color() {
|
||||
let color: Color = Color::from_str("#FF0000").unwrap();
|
||||
|
||||
4
src/style/palette.rs
Normal file
4
src/style/palette.rs
Normal file
@@ -0,0 +1,4 @@
|
||||
//! A module for defining color palettes.
|
||||
|
||||
pub mod material;
|
||||
pub mod tailwind;
|
||||
606
src/style/palette/material.rs
Normal file
606
src/style/palette/material.rs
Normal file
@@ -0,0 +1,606 @@
|
||||
//! Material design color palettes.
|
||||
//!
|
||||
//! Represents the colors from the 2014 [Material design color palettes][palettes] by Google.
|
||||
//!
|
||||
//! [palettes]: https://m2.material.io/design/color/the-color-system.html#tools-for-picking-colors
|
||||
//!
|
||||
//! There are 16 palettes with accent colors, and 3 palettes without accent colors. Each palette
|
||||
//! has 10 colors, with variants from 50 to 900. The accent palettes also have 4 accent colors
|
||||
//! with variants from 100 to 700. Black and White are also included for completeness and to avoid
|
||||
//! being affected by any terminal theme that might be in use.
|
||||
//!
|
||||
//! This module exists to provide a convenient way to use the colors from the
|
||||
//! [`matdesign-color` crate] in your application.
|
||||
//!
|
||||
//! <style>
|
||||
//! .color { display: flex; align-items: center; }
|
||||
//! .color > div { width: 2rem; height: 2rem; }
|
||||
//! .color > div.name { width: 150px; !important; }
|
||||
//! </style>
|
||||
//! <div style="overflow-x: auto">
|
||||
//! <div style="display: flex; flex-direction:column; text-align: left">
|
||||
//! <div class="color" style="font-size:0.8em">
|
||||
//! <div class="name"></div>
|
||||
//! <div>C50</div>
|
||||
//! <div>C100</div>
|
||||
//! <div>C200</div>
|
||||
//! <div>C300</div>
|
||||
//! <div>C400</div>
|
||||
//! <div>C500</div>
|
||||
//! <div>C600</div>
|
||||
//! <div>C700</div>
|
||||
//! <div>C800</div>
|
||||
//! <div>C900</div>
|
||||
//! <div>A100</div>
|
||||
//! <div>A200</div>
|
||||
//! <div>A400</div>
|
||||
//! <div>A700</div>
|
||||
//! </div>
|
||||
//! <div class="color">
|
||||
//! <div class="name">
|
||||
//!
|
||||
//! [`RED`]</div>
|
||||
//! <div style="background-color: #FFEBEE"></div>
|
||||
//! <div style="background-color: #FFCDD2"></div>
|
||||
//! <div style="background-color: #EF9A9A"></div>
|
||||
//! <div style="background-color: #E57373"></div>
|
||||
//! <div style="background-color: #EF5350"></div>
|
||||
//! <div style="background-color: #F44336"></div>
|
||||
//! <div style="background-color: #E53935"></div>
|
||||
//! <div style="background-color: #D32F2F"></div>
|
||||
//! <div style="background-color: #C62828"></div>
|
||||
//! <div style="background-color: #B71C1C"></div>
|
||||
//! <div style="background-color: #FF8A80"></div>
|
||||
//! <div style="background-color: #FF5252"></div>
|
||||
//! <div style="background-color: #FF1744"></div>
|
||||
//! <div style="background-color: #D50000"></div>
|
||||
//! </div>
|
||||
//! <div class="color">
|
||||
//! <div class="name">
|
||||
//!
|
||||
//! [`PINK`]</div>
|
||||
//! <div style="background-color: #FCE4EC"></div>
|
||||
//! <div style="background-color: #F8BBD0"></div>
|
||||
//! <div style="background-color: #F48FB1"></div>
|
||||
//! <div style="background-color: #F06292"></div>
|
||||
//! <div style="background-color: #EC407A"></div>
|
||||
//! <div style="background-color: #E91E63"></div>
|
||||
//! <div style="background-color: #D81B60"></div>
|
||||
//! <div style="background-color: #C2185B"></div>
|
||||
//! <div style="background-color: #AD1457"></div>
|
||||
//! <div style="background-color: #880E4F"></div>
|
||||
//! <div style="background-color: #FF80AB"></div>
|
||||
//! <div style="background-color: #FF4081"></div>
|
||||
//! <div style="background-color: #F50057"></div>
|
||||
//! <div style="background-color: #C51162"></div>
|
||||
//! </div>
|
||||
//! <div class="color">
|
||||
//! <div class="name">
|
||||
//!
|
||||
//! [`PURPLE`]</div>
|
||||
//! <div style="background-color: #F3E5F5"></div>
|
||||
//! <div style="background-color: #E1BEE7"></div>
|
||||
//! <div style="background-color: #CE93D8"></div>
|
||||
//! <div style="background-color: #BA68C8"></div>
|
||||
//! <div style="background-color: #AB47BC"></div>
|
||||
//! <div style="background-color: #9C27B0"></div>
|
||||
//! <div style="background-color: #8E24AA"></div>
|
||||
//! <div style="background-color: #7B1FA2"></div>
|
||||
//! <div style="background-color: #6A1B9A"></div>
|
||||
//! <div style="background-color: #4A148C"></div>
|
||||
//! <div style="background-color: #EA80FC"></div>
|
||||
//! <div style="background-color: #E040FB"></div>
|
||||
//! <div style="background-color: #D500F9"></div>
|
||||
//! <div style="background-color: #AA00FF"></div>
|
||||
//! </div>
|
||||
//! <div class="color">
|
||||
//! <div class="name">
|
||||
//!
|
||||
//! [`DEEP_PURPLE`]</div>
|
||||
//! <div style="background-color: #EDE7F6"></div>
|
||||
//! <div style="background-color: #D1C4E9"></div>
|
||||
//! <div style="background-color: #B39DDB"></div>
|
||||
//! <div style="background-color: #9575CD"></div>
|
||||
//! <div style="background-color: #7E57C2"></div>
|
||||
//! <div style="background-color: #673AB7"></div>
|
||||
//! <div style="background-color: #5E35B1"></div>
|
||||
//! <div style="background-color: #512DA8"></div>
|
||||
//! <div style="background-color: #4527A0"></div>
|
||||
//! <div style="background-color: #311B92"></div>
|
||||
//! <div style="background-color: #B388FF"></div>
|
||||
//! <div style="background-color: #7C4DFF"></div>
|
||||
//! <div style="background-color: #651FFF"></div>
|
||||
//! <div style="background-color: #6200EA"></div>
|
||||
//! </div>
|
||||
//! <div class="color">
|
||||
//! <div class="name">
|
||||
//!
|
||||
//! [`INDIGO`]</div>
|
||||
//! <div style="background-color: #E8EAF6"></div>
|
||||
//! <div style="background-color: #C5CAE9"></div>
|
||||
//! <div style="background-color: #9FA8DA"></div>
|
||||
//! <div style="background-color: #7986CB"></div>
|
||||
//! <div style="background-color: #5C6BC0"></div>
|
||||
//! <div style="background-color: #3F51B5"></div>
|
||||
//! <div style="background-color: #3949AB"></div>
|
||||
//! <div style="background-color: #303F9F"></div>
|
||||
//! <div style="background-color: #283593"></div>
|
||||
//! <div style="background-color: #1A237E"></div>
|
||||
//! <div style="background-color: #8C9EFF"></div>
|
||||
//! <div style="background-color: #536DFE"></div>
|
||||
//! <div style="background-color: #3D5AFE"></div>
|
||||
//! <div style="background-color: #304FFE"></div>
|
||||
//! </div>
|
||||
//! <div class="color">
|
||||
//! <div class="name">
|
||||
//!
|
||||
//! [`BLUE`]</div>
|
||||
//! <div style="background-color: #E3F2FD"></div>
|
||||
//! <div style="background-color: #BBDEFB"></div>
|
||||
//! <div style="background-color: #90CAF9"></div>
|
||||
//! <div style="background-color: #64B5F6"></div>
|
||||
//! <div style="background-color: #42A5F5"></div>
|
||||
//! <div style="background-color: #2196F3"></div>
|
||||
//! <div style="background-color: #1E88E5"></div>
|
||||
//! <div style="background-color: #1976D2"></div>
|
||||
//! <div style="background-color: #1565C0"></div>
|
||||
//! <div style="background-color: #0D47A1"></div>
|
||||
//! <div style="background-color: #82B1FF"></div>
|
||||
//! <div style="background-color: #448AFF"></div>
|
||||
//! <div style="background-color: #2979FF"></div>
|
||||
//! <div style="background-color: #2962FF"></div>
|
||||
//! </div>
|
||||
//! <div class="color">
|
||||
//! <div class="name">
|
||||
//!
|
||||
//! [`LIGHT_BLUE`]</div>
|
||||
//! <div style="background-color: #E1F5FE"></div>
|
||||
//! <div style="background-color: #B3E5FC"></div>
|
||||
//! <div style="background-color: #81D4FA"></div>
|
||||
//! <div style="background-color: #4FC3F7"></div>
|
||||
//! <div style="background-color: #29B6F6"></div>
|
||||
//! <div style="background-color: #03A9F4"></div>
|
||||
//! <div style="background-color: #039BE5"></div>
|
||||
//! <div style="background-color: #0288D1"></div>
|
||||
//! <div style="background-color: #0277BD"></div>
|
||||
//! <div style="background-color: #01579B"></div>
|
||||
//! <div style="background-color: #80D8FF"></div>
|
||||
//! <div style="background-color: #40C4FF"></div>
|
||||
//! <div style="background-color: #00B0FF"></div>
|
||||
//! <div style="background-color: #0091EA"></div>
|
||||
//! </div>
|
||||
//! <div class="color">
|
||||
//! <div class="name">
|
||||
//!
|
||||
//! [`CYAN`]</div>
|
||||
//! <div style="background-color: #E0F7FA"></div>
|
||||
//! <div style="background-color: #B2EBF2"></div>
|
||||
//! <div style="background-color: #80DEEA"></div>
|
||||
//! <div style="background-color: #4DD0E1"></div>
|
||||
//! <div style="background-color: #26C6DA"></div>
|
||||
//! <div style="background-color: #00BCD4"></div>
|
||||
//! <div style="background-color: #00ACC1"></div>
|
||||
//! <div style="background-color: #0097A7"></div>
|
||||
//! <div style="background-color: #00838F"></div>
|
||||
//! <div style="background-color: #006064"></div>
|
||||
//! <div style="background-color: #84FFFF"></div>
|
||||
//! <div style="background-color: #18FFFF"></div>
|
||||
//! <div style="background-color: #00E5FF"></div>
|
||||
//! <div style="background-color: #00B8D4"></div>
|
||||
//! </div>
|
||||
//! <div class="color">
|
||||
//! <div class="name">
|
||||
//!
|
||||
//! [`TEAL`]</div>
|
||||
//! <div style="background-color: #E0F2F1"></div>
|
||||
//! <div style="background-color: #B2DFDB"></div>
|
||||
//! <div style="background-color: #80CBC4"></div>
|
||||
//! <div style="background-color: #4DB6AC"></div>
|
||||
//! <div style="background-color: #26A69A"></div>
|
||||
//! <div style="background-color: #009688"></div>
|
||||
//! <div style="background-color: #00897B"></div>
|
||||
//! <div style="background-color: #00796B"></div>
|
||||
//! <div style="background-color: #00695C"></div>
|
||||
//! <div style="background-color: #004D40"></div>
|
||||
//! <div style="background-color: #A7FFEB"></div>
|
||||
//! <div style="background-color: #64FFDA"></div>
|
||||
//! <div style="background-color: #1DE9B6"></div>
|
||||
//! <div style="background-color: #00BFA5"></div>
|
||||
//! </div>
|
||||
//! <div class="color">
|
||||
//! <div class="name">
|
||||
//!
|
||||
//! [`GREEN`]</div>
|
||||
//! <div style="background-color: #E8F5E9"></div>
|
||||
//! <div style="background-color: #C8E6C9"></div>
|
||||
//! <div style="background-color: #A5D6A7"></div>
|
||||
//! <div style="background-color: #81C784"></div>
|
||||
//! <div style="background-color: #66BB6A"></div>
|
||||
//! <div style="background-color: #4CAF50"></div>
|
||||
//! <div style="background-color: #43A047"></div>
|
||||
//! <div style="background-color: #388E3C"></div>
|
||||
//! <div style="background-color: #2E7D32"></div>
|
||||
//! <div style="background-color: #1B5E20"></div>
|
||||
//! <div style="background-color: #B9F6CA"></div>
|
||||
//! <div style="background-color: #69F0AE"></div>
|
||||
//! <div style="background-color: #00E676"></div>
|
||||
//! <div style="background-color: #00C853"></div>
|
||||
//! </div>
|
||||
//! <div class="color">
|
||||
//! <div class="name">
|
||||
//!
|
||||
//! [`LIGHT_GREEN`]</div>
|
||||
//! <div style="background-color: #F1F8E9"></div>
|
||||
//! <div style="background-color: #DCEDC8"></div>
|
||||
//! <div style="background-color: #C5E1A5"></div>
|
||||
//! <div style="background-color: #AED581"></div>
|
||||
//! <div style="background-color: #9CCC65"></div>
|
||||
//! <div style="background-color: #8BC34A"></div>
|
||||
//! <div style="background-color: #7CB342"></div>
|
||||
//! <div style="background-color: #689F38"></div>
|
||||
//! <div style="background-color: #558B2F"></div>
|
||||
//! <div style="background-color: #33691E"></div>
|
||||
//! <div style="background-color: #CCFF90"></div>
|
||||
//! <div style="background-color: #B2FF59"></div>
|
||||
//! <div style="background-color: #76FF03"></div>
|
||||
//! <div style="background-color: #64DD17"></div>
|
||||
//! </div>
|
||||
//! <div class="color">
|
||||
//! <div class="name">
|
||||
//!
|
||||
//! [`LIME`]</div>
|
||||
//! <div style="background-color: #F9FBE7"></div>
|
||||
//! <div style="background-color: #F0F4C3"></div>
|
||||
//! <div style="background-color: #E6EE9C"></div>
|
||||
//! <div style="background-color: #DCE775"></div>
|
||||
//! <div style="background-color: #D4E157"></div>
|
||||
//! <div style="background-color: #CDDC39"></div>
|
||||
//! <div style="background-color: #C0CA33"></div>
|
||||
//! <div style="background-color: #AFB42B"></div>
|
||||
//! <div style="background-color: #9E9D24"></div>
|
||||
//! <div style="background-color: #827717"></div>
|
||||
//! <div style="background-color: #F4FF81"></div>
|
||||
//! <div style="background-color: #EEFF41"></div>
|
||||
//! <div style="background-color: #C6FF00"></div>
|
||||
//! <div style="background-color: #AEEA00"></div>
|
||||
//! </div>
|
||||
//! <div class="color">
|
||||
//! <div class="name">
|
||||
//!
|
||||
//! [`YELLOW`]</div>
|
||||
//! <div style="background-color: #FFFDE7"></div>
|
||||
//! <div style="background-color: #FFF9C4"></div>
|
||||
//! <div style="background-color: #FFF59D"></div>
|
||||
//! <div style="background-color: #FFF176"></div>
|
||||
//! <div style="background-color: #FFEE58"></div>
|
||||
//! <div style="background-color: #FFEB3B"></div>
|
||||
//! <div style="background-color: #FDD835"></div>
|
||||
//! <div style="background-color: #FBC02D"></div>
|
||||
//! <div style="background-color: #F9A825"></div>
|
||||
//! <div style="background-color: #F57F17"></div>
|
||||
//! <div style="background-color: #FFFF8D"></div>
|
||||
//! <div style="background-color: #FFFF00"></div>
|
||||
//! <div style="background-color: #FFEA00"></div>
|
||||
//! <div style="background-color: #FFD600"></div>
|
||||
//! </div>
|
||||
//! <div class="color">
|
||||
//! <div class="name">
|
||||
//!
|
||||
//! [`AMBER`]</div>
|
||||
//! <div style="background-color: #FFF8E1"></div>
|
||||
//! <div style="background-color: #FFECB3"></div>
|
||||
//! <div style="background-color: #FFE082"></div>
|
||||
//! <div style="background-color: #FFD54F"></div>
|
||||
//! <div style="background-color: #FFCA28"></div>
|
||||
//! <div style="background-color: #FFC107"></div>
|
||||
//! <div style="background-color: #FFB300"></div>
|
||||
//! <div style="background-color: #FFA000"></div>
|
||||
//! <div style="background-color: #FF8F00"></div>
|
||||
//! <div style="background-color: #FF6F00"></div>
|
||||
//! <div style="background-color: #FFE57F"></div>
|
||||
//! <div style="background-color: #FFD740"></div>
|
||||
//! <div style="background-color: #FFC400"></div>
|
||||
//! <div style="background-color: #FFAB00"></div>
|
||||
//! </div>
|
||||
//! <div class="color">
|
||||
//! <div class="name">
|
||||
//!
|
||||
//! [`ORANGE`]</div>
|
||||
//! <div style="background-color: #FFF3E0"></div>
|
||||
//! <div style="background-color: #FFE0B2"></div>
|
||||
//! <div style="background-color: #FFCC80"></div>
|
||||
//! <div style="background-color: #FFB74D"></div>
|
||||
//! <div style="background-color: #FFA726"></div>
|
||||
//! <div style="background-color: #FF9800"></div>
|
||||
//! <div style="background-color: #FB8C00"></div>
|
||||
//! <div style="background-color: #F57C00"></div>
|
||||
//! <div style="background-color: #EF6C00"></div>
|
||||
//! <div style="background-color: #E65100"></div>
|
||||
//! <div style="background-color: #FFD180"></div>
|
||||
//! <div style="background-color: #FFAB40"></div>
|
||||
//! <div style="background-color: #FF9100"></div>
|
||||
//! <div style="background-color: #FF6D00"></div>
|
||||
//! </div>
|
||||
//! <div class="color">
|
||||
//! <div class="name">
|
||||
//!
|
||||
//! [`DEEP_ORANGE`]</div>
|
||||
//! <div style="background-color: #FBE9E7"></div>
|
||||
//! <div style="background-color: #FFCCBC"></div>
|
||||
//! <div style="background-color: #FFAB91"></div>
|
||||
//! <div style="background-color: #FF8A65"></div>
|
||||
//! <div style="background-color: #FF7043"></div>
|
||||
//! <div style="background-color: #FF5722"></div>
|
||||
//! <div style="background-color: #F4511E"></div>
|
||||
//! <div style="background-color: #E64A19"></div>
|
||||
//! <div style="background-color: #D84315"></div>
|
||||
//! <div style="background-color: #BF360C"></div>
|
||||
//! <div style="background-color: #FF9E80"></div>
|
||||
//! <div style="background-color: #FF6E40"></div>
|
||||
//! <div style="background-color: #FF3D00"></div>
|
||||
//! <div style="background-color: #DD2C00"></div>
|
||||
//! </div>
|
||||
//! <div class="color">
|
||||
//! <div class="name">
|
||||
//!
|
||||
//! [`BROWN`]</div>
|
||||
//! <div style="background-color: #EFEBE9"></div>
|
||||
//! <div style="background-color: #D7CCC8"></div>
|
||||
//! <div style="background-color: #BCAAA4"></div>
|
||||
//! <div style="background-color: #A1887F"></div>
|
||||
//! <div style="background-color: #8D6E63"></div>
|
||||
//! <div style="background-color: #795548"></div>
|
||||
//! <div style="background-color: #6D4C41"></div>
|
||||
//! <div style="background-color: #5D4037"></div>
|
||||
//! <div style="background-color: #4E342E"></div>
|
||||
//! <div style="background-color: #3E2723"></div>
|
||||
//! </div>
|
||||
//! <div class="color">
|
||||
//! <div class="name">
|
||||
//!
|
||||
//! [`GRAY`]</div>
|
||||
//! <div style="background-color: #FAFAFA"></div>
|
||||
//! <div style="background-color: #F5F5F5"></div>
|
||||
//! <div style="background-color: #EEEEEE"></div>
|
||||
//! <div style="background-color: #E0E0E0"></div>
|
||||
//! <div style="background-color: #BDBDBD"></div>
|
||||
//! <div style="background-color: #9E9E9E"></div>
|
||||
//! <div style="background-color: #757575"></div>
|
||||
//! <div style="background-color: #616161"></div>
|
||||
//! <div style="background-color: #424242"></div>
|
||||
//! <div style="background-color: #212121"></div>
|
||||
//! </div>
|
||||
//! <div class="color">
|
||||
//! <div class="name">
|
||||
//!
|
||||
//! [`BLUE_GRAY`]</div>
|
||||
//! <div style="background-color: #ECEFF1"></div>
|
||||
//! <div style="background-color: #CFD8DC"></div>
|
||||
//! <div style="background-color: #B0BEC5"></div>
|
||||
//! <div style="background-color: #90A4AE"></div>
|
||||
//! <div style="background-color: #78909C"></div>
|
||||
//! <div style="background-color: #607D8B"></div>
|
||||
//! <div style="background-color: #546E7A"></div>
|
||||
//! <div style="background-color: #455A64"></div>
|
||||
//! <div style="background-color: #37474F"></div>
|
||||
//! <div style="background-color: #263238"></div>
|
||||
//! </div>
|
||||
//! <div class="color">
|
||||
//! <div class="name">
|
||||
//!
|
||||
//! [`BLACK`]</div>
|
||||
//! <div class="bw" style="width: 350px; background-color: #000000"></div>
|
||||
//! </div>
|
||||
//! <div class="color">
|
||||
//! <div class="name">
|
||||
//!
|
||||
//! [`WHITE`]</div>
|
||||
//! <div style="width: 350px; background-color: #FFFFFF"></div>
|
||||
//! </div>
|
||||
//! </div>
|
||||
//! </div>
|
||||
//!
|
||||
//! # Example
|
||||
//!
|
||||
//! ```rust
|
||||
//! # use ratatui::prelude::*;
|
||||
//! use ratatui::style::palette::material::{BLUE, RED};
|
||||
//!
|
||||
//! assert_eq!(RED.c500, Color::Rgb(244, 67, 54));
|
||||
//! assert_eq!(BLUE.c500, Color::Rgb(33, 150, 243));
|
||||
//! ```
|
||||
//!
|
||||
//! [`matdesign-color` crate]: https://crates.io/crates/matdesign-color
|
||||
|
||||
use crate::prelude::*;
|
||||
|
||||
/// A palette of colors for use in Material design with accent colors
|
||||
///
|
||||
/// This is a collection of colors that are used in Material design. They consist of a set of
|
||||
/// colors from 50 to 900, and a set of accent colors from 100 to 700.
|
||||
#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
|
||||
pub struct AccentedPalette {
|
||||
pub c50: Color,
|
||||
pub c100: Color,
|
||||
pub c200: Color,
|
||||
pub c300: Color,
|
||||
pub c400: Color,
|
||||
pub c500: Color,
|
||||
pub c600: Color,
|
||||
pub c700: Color,
|
||||
pub c800: Color,
|
||||
pub c900: Color,
|
||||
pub a100: Color,
|
||||
pub a200: Color,
|
||||
pub a400: Color,
|
||||
pub a700: Color,
|
||||
}
|
||||
|
||||
/// A palette of colors for use in Material design without accent colors
|
||||
///
|
||||
/// This is a collection of colors that are used in Material design. They consist of a set of
|
||||
/// colors from 50 to 900.
|
||||
#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
|
||||
pub struct NonAccentedPalette {
|
||||
pub c50: Color,
|
||||
pub c100: Color,
|
||||
pub c200: Color,
|
||||
pub c300: Color,
|
||||
pub c400: Color,
|
||||
pub c500: Color,
|
||||
pub c600: Color,
|
||||
pub c700: Color,
|
||||
pub c800: Color,
|
||||
pub c900: Color,
|
||||
}
|
||||
|
||||
impl AccentedPalette {
|
||||
/// Create a new AccentedPalette from the given variants
|
||||
///
|
||||
/// The variants should be in the format [0x00RRGGBB, ...]
|
||||
pub const fn from_variants(variants: [u32; 14]) -> AccentedPalette {
|
||||
AccentedPalette {
|
||||
c50: Color::from_u32(variants[0]),
|
||||
c100: Color::from_u32(variants[1]),
|
||||
c200: Color::from_u32(variants[2]),
|
||||
c300: Color::from_u32(variants[3]),
|
||||
c400: Color::from_u32(variants[4]),
|
||||
c500: Color::from_u32(variants[5]),
|
||||
c600: Color::from_u32(variants[6]),
|
||||
c700: Color::from_u32(variants[7]),
|
||||
c800: Color::from_u32(variants[8]),
|
||||
c900: Color::from_u32(variants[9]),
|
||||
a100: Color::from_u32(variants[10]),
|
||||
a200: Color::from_u32(variants[11]),
|
||||
a400: Color::from_u32(variants[12]),
|
||||
a700: Color::from_u32(variants[13]),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl NonAccentedPalette {
|
||||
/// Create a new NonAccented from the given variants
|
||||
///
|
||||
/// The variants should be in the format [0x00RRGGBB, ...]
|
||||
pub const fn from_variants(variants: [u32; 10]) -> NonAccentedPalette {
|
||||
NonAccentedPalette {
|
||||
c50: Color::from_u32(variants[0]),
|
||||
c100: Color::from_u32(variants[1]),
|
||||
c200: Color::from_u32(variants[2]),
|
||||
c300: Color::from_u32(variants[3]),
|
||||
c400: Color::from_u32(variants[4]),
|
||||
c500: Color::from_u32(variants[5]),
|
||||
c600: Color::from_u32(variants[6]),
|
||||
c700: Color::from_u32(variants[7]),
|
||||
c800: Color::from_u32(variants[8]),
|
||||
c900: Color::from_u32(variants[9]),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Accented palettes
|
||||
|
||||
pub const RED: AccentedPalette = AccentedPalette::from_variants(variants::RED);
|
||||
pub const PINK: AccentedPalette = AccentedPalette::from_variants(variants::PINK);
|
||||
pub const PURPLE: AccentedPalette = AccentedPalette::from_variants(variants::PURPLE);
|
||||
pub const DEEP_PURPLE: AccentedPalette = AccentedPalette::from_variants(variants::DEEP_PURPLE);
|
||||
pub const INDIGO: AccentedPalette = AccentedPalette::from_variants(variants::INDIGO);
|
||||
pub const BLUE: AccentedPalette = AccentedPalette::from_variants(variants::BLUE);
|
||||
pub const LIGHT_BLUE: AccentedPalette = AccentedPalette::from_variants(variants::LIGHT_BLUE);
|
||||
pub const CYAN: AccentedPalette = AccentedPalette::from_variants(variants::CYAN);
|
||||
pub const TEAL: AccentedPalette = AccentedPalette::from_variants(variants::TEAL);
|
||||
pub const GREEN: AccentedPalette = AccentedPalette::from_variants(variants::GREEN);
|
||||
pub const LIGHT_GREEN: AccentedPalette = AccentedPalette::from_variants(variants::LIGHT_GREEN);
|
||||
pub const LIME: AccentedPalette = AccentedPalette::from_variants(variants::LIME);
|
||||
pub const YELLOW: AccentedPalette = AccentedPalette::from_variants(variants::YELLOW);
|
||||
pub const AMBER: AccentedPalette = AccentedPalette::from_variants(variants::AMBER);
|
||||
pub const ORANGE: AccentedPalette = AccentedPalette::from_variants(variants::ORANGE);
|
||||
pub const DEEP_ORANGE: AccentedPalette = AccentedPalette::from_variants(variants::DEEP_ORANGE);
|
||||
|
||||
// Unaccented palettes
|
||||
pub const BROWN: NonAccentedPalette = NonAccentedPalette::from_variants(variants::BROWN);
|
||||
pub const GRAY: NonAccentedPalette = NonAccentedPalette::from_variants(variants::GRAY);
|
||||
pub const BLUE_GRAY: NonAccentedPalette = NonAccentedPalette::from_variants(variants::BLUE_GRAY);
|
||||
|
||||
// Black and white included for completeness
|
||||
pub const BLACK: Color = Color::from_u32(0x000000);
|
||||
pub const WHITE: Color = Color::from_u32(0xFFFFFF);
|
||||
|
||||
mod variants {
|
||||
pub const RED: [u32; 14] = [
|
||||
0xFFEBEE, 0xFFCDD2, 0xEF9A9A, 0xE57373, 0xEF5350, 0xF44336, 0xE53935, 0xD32F2F, 0xC62828,
|
||||
0xB71C1C, 0xFF8A80, 0xFF5252, 0xFF1744, 0xD50000,
|
||||
];
|
||||
pub const PINK: [u32; 14] = [
|
||||
0xFCE4EC, 0xF8BBD0, 0xF48FB1, 0xF06292, 0xEC407A, 0xE91E63, 0xD81B60, 0xC2185B, 0xAD1457,
|
||||
0x880E4F, 0xFF80AB, 0xFF4081, 0xF50057, 0xC51162,
|
||||
];
|
||||
pub const PURPLE: [u32; 14] = [
|
||||
0xF3E5F5, 0xE1BEE7, 0xCE93D8, 0xBA68C8, 0xAB47BC, 0x9C27B0, 0x8E24AA, 0x7B1FA2, 0x6A1B9A,
|
||||
0x4A148C, 0xEA80FC, 0xE040FB, 0xD500F9, 0xAA00FF,
|
||||
];
|
||||
pub const DEEP_PURPLE: [u32; 14] = [
|
||||
0xEDE7F6, 0xD1C4E9, 0xB39DDB, 0x9575CD, 0x7E57C2, 0x673AB7, 0x5E35B1, 0x512DA8, 0x4527A0,
|
||||
0x311B92, 0xB388FF, 0x7C4DFF, 0x651FFF, 0x6200EA,
|
||||
];
|
||||
pub const INDIGO: [u32; 14] = [
|
||||
0xE8EAF6, 0xC5CAE9, 0x9FA8DA, 0x7986CB, 0x5C6BC0, 0x3F51B5, 0x3949AB, 0x303F9F, 0x283593,
|
||||
0x1A237E, 0x8C9EFF, 0x536DFE, 0x3D5AFE, 0x304FFE,
|
||||
];
|
||||
pub const BLUE: [u32; 14] = [
|
||||
0xE3F2FD, 0xBBDEFB, 0x90CAF9, 0x64B5F6, 0x42A5F5, 0x2196F3, 0x1E88E5, 0x1976D2, 0x1565C0,
|
||||
0x0D47A1, 0x82B1FF, 0x448AFF, 0x2979FF, 0x2962FF,
|
||||
];
|
||||
pub const LIGHT_BLUE: [u32; 14] = [
|
||||
0xE1F5FE, 0xB3E5FC, 0x81D4FA, 0x4FC3F7, 0x29B6F6, 0x03A9F4, 0x039BE5, 0x0288D1, 0x0277BD,
|
||||
0x01579B, 0x80D8FF, 0x40C4FF, 0x00B0FF, 0x0091EA,
|
||||
];
|
||||
pub const CYAN: [u32; 14] = [
|
||||
0xE0F7FA, 0xB2EBF2, 0x80DEEA, 0x4DD0E1, 0x26C6DA, 0x00BCD4, 0x00ACC1, 0x0097A7, 0x00838F,
|
||||
0x006064, 0x84FFFF, 0x18FFFF, 0x00E5FF, 0x00B8D4,
|
||||
];
|
||||
pub const TEAL: [u32; 14] = [
|
||||
0xE0F2F1, 0xB2DFDB, 0x80CBC4, 0x4DB6AC, 0x26A69A, 0x009688, 0x00897B, 0x00796B, 0x00695C,
|
||||
0x004D40, 0xA7FFEB, 0x64FFDA, 0x1DE9B6, 0x00BFA5,
|
||||
];
|
||||
pub const GREEN: [u32; 14] = [
|
||||
0xE8F5E9, 0xC8E6C9, 0xA5D6A7, 0x81C784, 0x66BB6A, 0x4CAF50, 0x43A047, 0x388E3C, 0x2E7D32,
|
||||
0x1B5E20, 0xB9F6CA, 0x69F0AE, 0x00E676, 0x00C853,
|
||||
];
|
||||
pub const LIGHT_GREEN: [u32; 14] = [
|
||||
0xF1F8E9, 0xDCEDC8, 0xC5E1A5, 0xAED581, 0x9CCC65, 0x8BC34A, 0x7CB342, 0x689F38, 0x558B2F,
|
||||
0x33691E, 0xCCFF90, 0xB2FF59, 0x76FF03, 0x64DD17,
|
||||
];
|
||||
pub const LIME: [u32; 14] = [
|
||||
0xF9FBE7, 0xF0F4C3, 0xE6EE9C, 0xDCE775, 0xD4E157, 0xCDDC39, 0xC0CA33, 0xAFB42B, 0x9E9D24,
|
||||
0x827717, 0xF4FF81, 0xEEFF41, 0xC6FF00, 0xAEEA00,
|
||||
];
|
||||
pub const YELLOW: [u32; 14] = [
|
||||
0xFFFDE7, 0xFFF9C4, 0xFFF59D, 0xFFF176, 0xFFEE58, 0xFFEB3B, 0xFDD835, 0xFBC02D, 0xF9A825,
|
||||
0xF57F17, 0xFFFF8D, 0xFFFF00, 0xFFEA00, 0xFFD600,
|
||||
];
|
||||
pub const AMBER: [u32; 14] = [
|
||||
0xFFF8E1, 0xFFECB3, 0xFFE082, 0xFFD54F, 0xFFCA28, 0xFFC107, 0xFFB300, 0xFFA000, 0xFF8F00,
|
||||
0xFF6F00, 0xFFE57F, 0xFFD740, 0xFFC400, 0xFFAB00,
|
||||
];
|
||||
pub const ORANGE: [u32; 14] = [
|
||||
0xFFF3E0, 0xFFE0B2, 0xFFCC80, 0xFFB74D, 0xFFA726, 0xFF9800, 0xFB8C00, 0xF57C00, 0xEF6C00,
|
||||
0xE65100, 0xFFD180, 0xFFAB40, 0xFF9100, 0xFF6D00,
|
||||
];
|
||||
pub const DEEP_ORANGE: [u32; 14] = [
|
||||
0xFBE9E7, 0xFFCCBC, 0xFFAB91, 0xFF8A65, 0xFF7043, 0xFF5722, 0xF4511E, 0xE64A19, 0xD84315,
|
||||
0xBF360C, 0xFF9E80, 0xFF6E40, 0xFF3D00, 0xDD2C00,
|
||||
];
|
||||
pub const BROWN: [u32; 10] = [
|
||||
0xEFEBE9, 0xD7CCC8, 0xBCAAA4, 0xA1887F, 0x8D6E63, 0x795548, 0x6D4C41, 0x5D4037, 0x4E342E,
|
||||
0x3E2723,
|
||||
];
|
||||
pub const GRAY: [u32; 10] = [
|
||||
0xFAFAFA, 0xF5F5F5, 0xEEEEEE, 0xE0E0E0, 0xBDBDBD, 0x9E9E9E, 0x757575, 0x616161, 0x424242,
|
||||
0x212121,
|
||||
];
|
||||
pub const BLUE_GRAY: [u32; 10] = [
|
||||
0xECEFF1, 0xCFD8DC, 0xB0BEC5, 0x90A4AE, 0x78909C, 0x607D8B, 0x546E7A, 0x455A64, 0x37474F,
|
||||
0x263238,
|
||||
];
|
||||
}
|
||||
652
src/style/palette/tailwind.rs
Normal file
652
src/style/palette/tailwind.rs
Normal file
@@ -0,0 +1,652 @@
|
||||
//! Represents the Tailwind CSS [default color palette][palette].
|
||||
//!
|
||||
//! [palette]: https://tailwindcss.com/docs/customizing-colors#default-color-palette
|
||||
//!
|
||||
//! There are 22 palettes. Each palette has 11 colors, with variants from 50 to 950. Black and White
|
||||
//! are also included for completeness and to avoid being affected by any terminal theme that might
|
||||
//! be in use.
|
||||
//!
|
||||
//! <style>
|
||||
//! .color { display: flex; align-items: center; }
|
||||
//! .color > div { width: 2rem; height: 2rem; }
|
||||
//! .color > div.name { width: 150px; !important; }
|
||||
//! </style>
|
||||
//! <div style="overflow-x: auto">
|
||||
//! <div style="display: flex; flex-direction:column; text-align: left">
|
||||
//! <div class="color" style="font-size:0.8em">
|
||||
//! <div class="name"></div>
|
||||
//! <div>C50</div> <div>C100</div> <div>C200</div> <div>C300</div> <div>C400</div>
|
||||
//! <div>C500</div> <div>C600</div> <div>C700</div> <div>C800</div> <div>C900</div>
|
||||
//! <div>C950</div>
|
||||
//! </div>
|
||||
//! <div class="color">
|
||||
//! <div class="name">
|
||||
//!
|
||||
//! [`SLATE`]</div>
|
||||
//! <div style="background-color: #f8fafc"></div> <div style="background-color: #f1f5f9"></div>
|
||||
//! <div style="background-color: #e2e8f0"></div> <div style="background-color: #cbd5e1"></div>
|
||||
//! <div style="background-color: #94a3b8"></div> <div style="background-color: #64748b"></div>
|
||||
//! <div style="background-color: #475569"></div> <div style="background-color: #334155"></div>
|
||||
//! <div style="background-color: #1e293b"></div> <div style="background-color: #0f172a"></div>
|
||||
//! <div style="background-color: #020617"></div>
|
||||
//! </div>
|
||||
//! <div class="color">
|
||||
//! <div class="name">
|
||||
//!
|
||||
//! [`GRAY`]</div>
|
||||
//! <div style="background-color: #f9fafb"></div> <div style="background-color: #f3f4f6"></div>
|
||||
//! <div style="background-color: #e5e7eb"></div> <div style="background-color: #d1d5db"></div>
|
||||
//! <div style="background-color: #9ca3af"></div> <div style="background-color: #6b7280"></div>
|
||||
//! <div style="background-color: #4b5563"></div> <div style="background-color: #374151"></div>
|
||||
//! <div style="background-color: #1f2937"></div> <div style="background-color: #111827"></div>
|
||||
//! <div style="background-color: #0a0a0a"></div>
|
||||
//! </div>
|
||||
//! <div class="color">
|
||||
//! <div class="name">
|
||||
//!
|
||||
//! [`ZINC`]</div>
|
||||
//! <div style="background-color: #fafafa"></div> <div style="background-color: #f5f5f5"></div>
|
||||
//! <div style="background-color: #e5e5e5"></div> <div style="background-color: #d4d4d4"></div>
|
||||
//! <div style="background-color: #a1a1aa"></div> <div style="background-color: #71717a"></div>
|
||||
//! <div style="background-color: #52525b"></div> <div style="background-color: #404040"></div>
|
||||
//! <div style="background-color: #262626"></div> <div style="background-color: #171717"></div>
|
||||
//! <div style="background-color: #0a0a0a"></div>
|
||||
//! </div>
|
||||
//! <div class="color">
|
||||
//! <div class="name">
|
||||
//!
|
||||
//! [`NEUTRAL`]</div>
|
||||
//! <div style="background-color: #fafafa"></div> <div style="background-color: #f5f5f5"></div>
|
||||
//! <div style="background-color: #e5e5e5"></div> <div style="background-color: #d4d4d4"></div>
|
||||
//! <div style="background-color: #a3a3a3"></div> <div style="background-color: #737373"></div>
|
||||
//! <div style="background-color: #525252"></div> <div style="background-color: #404040"></div>
|
||||
//! <div style="background-color: #262626"></div> <div style="background-color: #171717"></div>
|
||||
//! <div style="background-color: #0a0a0a"></div>
|
||||
//! </div>
|
||||
//! <div class="color">
|
||||
//! <div class="name">
|
||||
//!
|
||||
//! [`STONE`]</div>
|
||||
//! <div style="background-color: #fafaf9"></div> <div style="background-color: #f5f5f4"></div>
|
||||
//! <div style="background-color: #e7e5e4"></div> <div style="background-color: #d6d3d1"></div>
|
||||
//! <div style="background-color: #a8a29e"></div> <div style="background-color: #78716c"></div>
|
||||
//! <div style="background-color: #57534e"></div> <div style="background-color: #44403c"></div>
|
||||
//! <div style="background-color: #292524"></div> <div style="background-color: #1c1917"></div>
|
||||
//! <div style="background-color: #0c0a09"></div>
|
||||
//! </div>
|
||||
//! <div class="color">
|
||||
//! <div class="name">
|
||||
//!
|
||||
//! [`RED`]</div>
|
||||
//! <div style="background-color: #fef2f2"></div> <div style="background-color: #fee2e2"></div>
|
||||
//! <div style="background-color: #fecaca"></div> <div style="background-color: #fca5a5"></div>
|
||||
//! <div style="background-color: #f87171"></div> <div style="background-color: #ef4444"></div>
|
||||
//! <div style="background-color: #dc2626"></div> <div style="background-color: #b91c1c"></div>
|
||||
//! <div style="background-color: #991b1b"></div> <div style="background-color: #7f1d1d"></div>
|
||||
//! <div style="background-color: #450a0a"></div>
|
||||
//! </div>
|
||||
//! <div class="color">
|
||||
//! <div class="name">
|
||||
//!
|
||||
//! [`ORANGE`]</div>
|
||||
//! <div style="background-color: #fff7ed"></div> <div style="background-color: #ffedd5"></div>
|
||||
//! <div style="background-color: #fed7aa"></div> <div style="background-color: #fdba74"></div>
|
||||
//! <div style="background-color: #fb923c"></div> <div style="background-color: #f97316"></div>
|
||||
//! <div style="background-color: #ea580c"></div> <div style="background-color: #c2410c"></div>
|
||||
//! <div style="background-color: #9a3412"></div> <div style="background-color: #7c2d12"></div>
|
||||
//! <div style="background-color: #431407"></div>
|
||||
//! </div>
|
||||
//! <div class="color">
|
||||
//! <div class="name">
|
||||
//!
|
||||
//! [`AMBER`]</div>
|
||||
//! <div style="background-color: #fffbeb"></div> <div style="background-color: #fef3c7"></div>
|
||||
//! <div style="background-color: #fde68a"></div> <div style="background-color: #fcd34d"></div>
|
||||
//! <div style="background-color: #fbbf24"></div> <div style="background-color: #f59e0b"></div>
|
||||
//! <div style="background-color: #d97706"></div> <div style="background-color: #b45309"></div>
|
||||
//! <div style="background-color: #92400e"></div> <div style="background-color: #78350f"></div>
|
||||
//! <div style="background-color: #451a03"></div>
|
||||
//! </div>
|
||||
//! <div class="color">
|
||||
//! <div class="name">
|
||||
//!
|
||||
//! [`YELLOW`]</div>
|
||||
//! <div style="background-color: #fefce8"></div> <div style="background-color: #fef9c3"></div>
|
||||
//! <div style="background-color: #fef08a"></div> <div style="background-color: #fde047"></div>
|
||||
//! <div style="background-color: #facc15"></div> <div style="background-color: #eab308"></div>
|
||||
//! <div style="background-color: #ca8a04"></div> <div style="background-color: #a16207"></div>
|
||||
//! <div style="background-color: #854d0e"></div> <div style="background-color: #713f12"></div>
|
||||
//! <div style="background-color: #422006"></div>
|
||||
//! </div>
|
||||
//! <div class="color">
|
||||
//! <div class="name">
|
||||
//!
|
||||
//! [`LIME`]</div>
|
||||
//! <div style="background-color: #f7fee7"></div> <div style="background-color: #ecfccb"></div>
|
||||
//! <div style="background-color: #d9f99d"></div> <div style="background-color: #bef264"></div>
|
||||
//! <div style="background-color: #a3e635"></div> <div style="background-color: #84cc16"></div>
|
||||
//! <div style="background-color: #65a30d"></div> <div style="background-color: #4d7c0f"></div>
|
||||
//! <div style="background-color: #3f6212"></div> <div style="background-color: #365314"></div>
|
||||
//! <div style="background-color: #1a2e05"></div>
|
||||
//! </div>
|
||||
//! <div class="color">
|
||||
//! <div class="name">
|
||||
//!
|
||||
//! [`GREEN`]</div>
|
||||
//! <div style="background-color: #f0fdf4"></div> <div style="background-color: #dcfce7"></div>
|
||||
//! <div style="background-color: #bbf7d0"></div> <div style="background-color: #86efac"></div>
|
||||
//! <div style="background-color: #4ade80"></div> <div style="background-color: #22c55e"></div>
|
||||
//! <div style="background-color: #16a34a"></div> <div style="background-color: #15803d"></div>
|
||||
//! <div style="background-color: #166534"></div> <div style="background-color: #14532d"></div>
|
||||
//! <div style="background-color: #052e16"></div>
|
||||
//! </div>
|
||||
//! <div class="color">
|
||||
//! <div class="name">
|
||||
//!
|
||||
//! [`EMERALD`]</div>
|
||||
//! <div style="background-color: #ecfdf5"></div> <div style="background-color: #d1fae5"></div>
|
||||
//! <div style="background-color: #a7f3d0"></div> <div style="background-color: #6ee7b7"></div>
|
||||
//! <div style="background-color: #34d399"></div> <div style="background-color: #10b981"></div>
|
||||
//! <div style="background-color: #059669"></div> <div style="background-color: #047857"></div>
|
||||
//! <div style="background-color: #065f46"></div> <div style="background-color: #064e3b"></div>
|
||||
//! <div style="background-color: #022c22"></div>
|
||||
//! </div>
|
||||
//! <div class="color">
|
||||
//! <div class="name">
|
||||
//!
|
||||
//! [`TEAL`]</div>
|
||||
//! <div style="background-color: #f0fdfa"></div> <div style="background-color: #ccfbf1"></div>
|
||||
//! <div style="background-color: #99f6e4"></div> <div style="background-color: #5eead4"></div>
|
||||
//! <div style="background-color: #2dd4bf"></div> <div style="background-color: #14b8a6"></div>
|
||||
//! <div style="background-color: #0d9488"></div> <div style="background-color: #0f766e"></div>
|
||||
//! <div style="background-color: #115e59"></div> <div style="background-color: #134e4a"></div>
|
||||
//! <div style="background-color: #042f2e"></div>
|
||||
//! </div>
|
||||
//! <div class="color">
|
||||
//! <div class="name">
|
||||
//!
|
||||
//! [`CYAN`]</div>
|
||||
//! <div style="background-color: #ecfeff"></div> <div style="background-color: #cffafe"></div>
|
||||
//! <div style="background-color: #a5f3fc"></div> <div style="background-color: #67e8f9"></div>
|
||||
//! <div style="background-color: #22d3ee"></div> <div style="background-color: #06b6d4"></div>
|
||||
//! <div style="background-color: #0891b2"></div> <div style="background-color: #0e7490"></div>
|
||||
//! <div style="background-color: #155e75"></div> <div style="background-color: #164e63"></div>
|
||||
//! <div style="background-color: #083344"></div>
|
||||
//! </div>
|
||||
//! <div class="color">
|
||||
//! <div class="name">
|
||||
//!
|
||||
//! [`SKY`]</div>
|
||||
//! <div style="background-color: #f0f9ff"></div> <div style="background-color: #e0f2fe"></div>
|
||||
//! <div style="background-color: #bae6fd"></div> <div style="background-color: #7dd3fc"></div>
|
||||
//! <div style="background-color: #38bdf8"></div> <div style="background-color: #0ea5e9"></div>
|
||||
//! <div style="background-color: #0284c7"></div> <div style="background-color: #0369a1"></div>
|
||||
//! <div style="background-color: #075985"></div> <div style="background-color: #0c4a6e"></div>
|
||||
//! <div style="background-color: #082f49"></div>
|
||||
//! </div>
|
||||
//! <div class="color">
|
||||
//! <div class="name">
|
||||
//!
|
||||
//! [`BLUE`]</div>
|
||||
//! <div style="background-color: #eff6ff"></div> <div style="background-color: #dbeafe"></div>
|
||||
//! <div style="background-color: #bfdbfe"></div> <div style="background-color: #93c5fd"></div>
|
||||
//! <div style="background-color: #60a5fa"></div> <div style="background-color: #3b82f6"></div>
|
||||
//! <div style="background-color: #2563eb"></div> <div style="background-color: #1d4ed8"></div>
|
||||
//! <div style="background-color: #1e40af"></div> <div style="background-color: #1e3a8a"></div>
|
||||
//! <div style="background-color: #172554"></div>
|
||||
//! </div>
|
||||
//! <div class="color">
|
||||
//! <div class="name">
|
||||
//!
|
||||
//! [`INDIGO`]</div>
|
||||
//! <div style="background-color: #eef2ff"></div> <div style="background-color: #e0e7ff"></div>
|
||||
//! <div style="background-color: #c7d2fe"></div> <div style="background-color: #a5b4fc"></div>
|
||||
//! <div style="background-color: #818cf8"></div> <div style="background-color: #6366f1"></div>
|
||||
//! <div style="background-color: #4f46e5"></div> <div style="background-color: #4338ca"></div>
|
||||
//! <div style="background-color: #3730a3"></div> <div style="background-color: #312e81"></div>
|
||||
//! <div style="background-color: #1e1b4b"></div>
|
||||
//! </div>
|
||||
//! <div class="color">
|
||||
//! <div class="name">
|
||||
//!
|
||||
//! [`VIOLET`]</div>
|
||||
//! <div style="background-color: #f5f3ff"></div> <div style="background-color: #ede9fe"></div>
|
||||
//! <div style="background-color: #ddd6fe"></div> <div style="background-color: #c4b5fd"></div>
|
||||
//! <div style="background-color: #a78bfa"></div> <div style="background-color: #8b5cf6"></div>
|
||||
//! <div style="background-color: #7c3aed"></div> <div style="background-color: #6d28d9"></div>
|
||||
//! <div style="background-color: #5b21b6"></div> <div style="background-color: #4c1d95"></div>
|
||||
//! <div style="background-color: #2e1065"></div>
|
||||
//! </div>
|
||||
//! <div class="color">
|
||||
//! <div class="name">
|
||||
//!
|
||||
//! [`PURPLE`]</div>
|
||||
//! <div style="background-color: #faf5ff"></div> <div style="background-color: #f3e8ff"></div>
|
||||
//! <div style="background-color: #e9d5ff"></div> <div style="background-color: #d8b4fe"></div>
|
||||
//! <div style="background-color: #c084fc"></div> <div style="background-color: #a855f7"></div>
|
||||
//! <div style="background-color: #9333ea"></div> <div style="background-color: #7e22ce"></div>
|
||||
//! <div style="background-color: #6b21a8"></div> <div style="background-color: #581c87"></div>
|
||||
//! <div style="background-color: #4c136e"></div>
|
||||
//! </div>
|
||||
//! <div class="color">
|
||||
//! <div class="name">
|
||||
//!
|
||||
//! [`FUCHSIA`]</div>
|
||||
//! <div style="background-color: #fdf4ff"></div> <div style="background-color: #fae8ff"></div>
|
||||
//! <div style="background-color: #f5d0fe"></div> <div style="background-color: #f0abfc"></div>
|
||||
//! <div style="background-color: #e879f9"></div> <div style="background-color: #d946ef"></div>
|
||||
//! <div style="background-color: #c026d3"></div> <div style="background-color: #a21caf"></div>
|
||||
//! <div style="background-color: #86198f"></div> <div style="background-color: #701a75"></div>
|
||||
//! <div style="background-color: #4e145b"></div>
|
||||
//! </div>
|
||||
//! <div class="color">
|
||||
//! <div class="name">
|
||||
//!
|
||||
//! [`PINK`]</div>
|
||||
//! <div style="background-color: #fdf2f8"></div> <div style="background-color: #fce7f3"></div>
|
||||
//! <div style="background-color: #fbcfe8"></div> <div style="background-color: #f9a8d4"></div>
|
||||
//! <div style="background-color: #f472b6"></div> <div style="background-color: #ec4899"></div>
|
||||
//! <div style="background-color: #db2777"></div> <div style="background-color: #be185d"></div>
|
||||
//! <div style="background-color: #9d174d"></div> <div style="background-color: #831843"></div>
|
||||
//! <div style="background-color: #5f0b37"></div>
|
||||
//! </div>
|
||||
//! <div class="color">
|
||||
//! <div class="name">
|
||||
//!
|
||||
//! [`BLACK`]</div>
|
||||
//! <div style="background-color: #000000; width:22rem"></div>
|
||||
//! </div>
|
||||
//! <div class="color">
|
||||
//! <div class="name">
|
||||
//!
|
||||
//! [`WHITE`]</div>
|
||||
//! <div style="background-color: #ffffff; width:22rem"></div>
|
||||
//! </div>
|
||||
//! </div>
|
||||
//! </div>
|
||||
//!
|
||||
//! # Example
|
||||
//!
|
||||
//! ```rust
|
||||
//! # use ratatui::prelude::*;
|
||||
//! use ratatui::style::palette::tailwind::{BLUE, RED};
|
||||
//!
|
||||
//! assert_eq!(RED.c500, Color::Rgb(239, 68, 68));
|
||||
//! assert_eq!(BLUE.c500, Color::Rgb(59, 130, 246));
|
||||
//! ```
|
||||
|
||||
use crate::prelude::*;
|
||||
|
||||
pub struct Palette {
|
||||
pub c50: Color,
|
||||
pub c100: Color,
|
||||
pub c200: Color,
|
||||
pub c300: Color,
|
||||
pub c400: Color,
|
||||
pub c500: Color,
|
||||
pub c600: Color,
|
||||
pub c700: Color,
|
||||
pub c800: Color,
|
||||
pub c900: Color,
|
||||
pub c950: Color,
|
||||
}
|
||||
|
||||
#[rustfmt::skip]
|
||||
/// <style>.palette div{width:22rem;height:2rem}</style><div class="palette" style="display:flex;flex-direction:row"><div style="background-color: #000000"></div></div>
|
||||
pub const BLACK: Color = Color::from_u32(0x000000);
|
||||
|
||||
#[rustfmt::skip]
|
||||
/// <style>.palette div{width:22rem;height:2rem}</style><div class="palette" style="display:flex;flex-direction:row"><div style="background-color: #ffffff"></div></div>
|
||||
pub const WHITE: Color = Color::from_u32(0xffffff);
|
||||
|
||||
#[rustfmt::skip]
|
||||
/// <style>.palette div{width:2rem;height:2rem}</style><div class="palette" style="display:flex;flex-direction:row"><div style="background-color: #f8fafc"></div><div style="background-color: #f1f5f9"></div><div style="background-color: #e2e8f0"></div><div style="background-color: #cbd5e1"></div><div style="background-color: #94a3b8"></div><div style="background-color: #64748b"></div><div style="background-color: #475569"></div><div style="background-color: #334155"></div><div style="background-color: #1e293b"></div><div style="background-color: #0f172a"></div><div style="background-color: #020617"></div></div>
|
||||
pub const SLATE: Palette = Palette {
|
||||
c50: Color::from_u32(0xf8fafc),
|
||||
c100: Color::from_u32(0xf1f5f9),
|
||||
c200: Color::from_u32(0xe2e8f0),
|
||||
c300: Color::from_u32(0xcbd5e1),
|
||||
c400: Color::from_u32(0x94a3b8),
|
||||
c500: Color::from_u32(0x64748b),
|
||||
c600: Color::from_u32(0x475569),
|
||||
c700: Color::from_u32(0x334155),
|
||||
c800: Color::from_u32(0x1e293b),
|
||||
c900: Color::from_u32(0x0f172a),
|
||||
c950: Color::from_u32(0x020617),
|
||||
};
|
||||
|
||||
#[rustfmt::skip]
|
||||
/// <style>.palette div{width:2rem;height:2rem}</style><div class="palette" style="display:flex;flex-direction:row"><div style="background-color: #f9fafb"></div><div style="background-color: #f3f4f6"></div><div style="background-color: #e5e7eb"></div><div style="background-color: #d1d5db"></div><div style="background-color: #9ca3af"></div><div style="background-color: #6b7280"></div><div style="background-color: #4b5563"></div><div style="background-color: #374151"></div><div style="background-color: #1f2937"></div><div style="background-color: #111827"></div><div style="background-color: #030712"></div></div>
|
||||
pub const GRAY: Palette = Palette {
|
||||
c50: Color::from_u32(0xf9fafb),
|
||||
c100: Color::from_u32(0xf3f4f6),
|
||||
c200: Color::from_u32(0xe5e7eb),
|
||||
c300: Color::from_u32(0xd1d5db),
|
||||
c400: Color::from_u32(0x9ca3af),
|
||||
c500: Color::from_u32(0x6b7280),
|
||||
c600: Color::from_u32(0x4b5563),
|
||||
c700: Color::from_u32(0x374151),
|
||||
c800: Color::from_u32(0x1f2937),
|
||||
c900: Color::from_u32(0x111827),
|
||||
c950: Color::from_u32(0x030712),
|
||||
};
|
||||
|
||||
#[rustfmt::skip]
|
||||
/// <style>.palette div{width:2rem;height:2rem}</style><div class="palette" style="display:flex;flex-direction:row"><div style="background-color: #fafafa"></div><div style="background-color: #f5f5f5"></div><div style="background-color: #e5e5e5"></div><div style="background-color: #d4d4d4"></div><div style="background-color: #a1a1aa"></div><div style="background-color: #71717a"></div><div style="background-color: #52525b"></div><div style="background-color: #404040"></div><div style="background-color: #262626"></div><div style="background-color: #171717"></div><div style="background-color: #09090b"></div></div>
|
||||
pub const ZINC: Palette = Palette {
|
||||
c50: Color::from_u32(0xfafafa),
|
||||
c100: Color::from_u32(0xf4f4f5),
|
||||
c200: Color::from_u32(0xe4e4e7),
|
||||
c300: Color::from_u32(0xd4d4d8),
|
||||
c400: Color::from_u32(0xa1a1aa),
|
||||
c500: Color::from_u32(0x71717a),
|
||||
c600: Color::from_u32(0x52525b),
|
||||
c700: Color::from_u32(0x3f3f46),
|
||||
c800: Color::from_u32(0x27272a),
|
||||
c900: Color::from_u32(0x18181b),
|
||||
c950: Color::from_u32(0x09090b),
|
||||
};
|
||||
|
||||
#[rustfmt::skip]
|
||||
/// <style>.palette div{width:2rem;height:2rem}</style><div class="palette" style="display:flex;flex-direction:row"><div style="background-color: #fafafa"></div><div style="background-color: #f5f5f5"></div><div style="background-color: #e5e5e5"></div><div style="background-color: #d4d4d4"></div><div style="background-color: #a3a3a3"></div><div style="background-color: #737373"></div><div style="background-color: #525252"></div><div style="background-color: #404040"></div><div style="background-color: #262626"></div><div style="background-color: #171717"></div><div style="background-color: #0a0a0a"></div></div>
|
||||
pub const NEUTRAL: Palette = Palette {
|
||||
c50: Color::from_u32(0xfafafa),
|
||||
c100: Color::from_u32(0xf5f5f5),
|
||||
c200: Color::from_u32(0xe5e5e5),
|
||||
c300: Color::from_u32(0xd4d4d4),
|
||||
c400: Color::from_u32(0xa3a3a3),
|
||||
c500: Color::from_u32(0x737373),
|
||||
c600: Color::from_u32(0x525252),
|
||||
c700: Color::from_u32(0x404040),
|
||||
c800: Color::from_u32(0x262626),
|
||||
c900: Color::from_u32(0x171717),
|
||||
c950: Color::from_u32(0x0a0a0a),
|
||||
};
|
||||
|
||||
#[rustfmt::skip]
|
||||
/// <style>.palette div{width:2rem;height:2rem}</style><div class="palette" style="display:flex;flex-direction:row"><div style="background-color: #fafaf9"></div><div style="background-color: #f5f5f4"></div><div style="background-color: #e7e5e4"></div><div style="background-color: #d6d3d1"></div><div style="background-color: #a8a29e"></div><div style="background-color: #78716c"></div><div style="background-color: #57534e"></div><div style="background-color: #44403c"></div><div style="background-color: #292524"></div><div style="background-color: #1c1917"></div><div style="background-color: #0c0a09"></div></div>
|
||||
pub const STONE: Palette = Palette {
|
||||
c50: Color::from_u32(0xfafaf9),
|
||||
c100: Color::from_u32(0xf5f5f4),
|
||||
c200: Color::from_u32(0xe7e5e4),
|
||||
c300: Color::from_u32(0xd6d3d1),
|
||||
c400: Color::from_u32(0xa8a29e),
|
||||
c500: Color::from_u32(0x78716c),
|
||||
c600: Color::from_u32(0x57534e),
|
||||
c700: Color::from_u32(0x44403c),
|
||||
c800: Color::from_u32(0x292524),
|
||||
c900: Color::from_u32(0x1c1917),
|
||||
c950: Color::from_u32(0x0c0a09),
|
||||
};
|
||||
|
||||
#[rustfmt::skip]
|
||||
/// <style>.palette div{width:2rem;height:2rem}</style><div class="palette" style="display:flex;flex-direction:row"><div style="background-color: #fef2f2"></div><div style="background-color: #fee2e2"></div><div style="background-color: #fecaca"></div><div style="background-color: #fca5a5"></div><div style="background-color: #f87171"></div><div style="background-color: #ef4444"></div><div style="background-color: #dc2626"></div><div style="background-color: #b91c1c"></div><div style="background-color: #991b1b"></div><div style="background-color: #7f1d1d"></div><div style="background-color: #450a0a"></div></div>
|
||||
pub const RED: Palette = Palette {
|
||||
c50: Color::from_u32(0xfef2f2),
|
||||
c100: Color::from_u32(0xfee2e2),
|
||||
c200: Color::from_u32(0xfecaca),
|
||||
c300: Color::from_u32(0xfca5a5),
|
||||
c400: Color::from_u32(0xf87171),
|
||||
c500: Color::from_u32(0xef4444),
|
||||
c600: Color::from_u32(0xdc2626),
|
||||
c700: Color::from_u32(0xb91c1c),
|
||||
c800: Color::from_u32(0x991b1b),
|
||||
c900: Color::from_u32(0x7f1d1d),
|
||||
c950: Color::from_u32(0x450a0a),
|
||||
};
|
||||
|
||||
#[rustfmt::skip]
|
||||
/// <style>.palette div{width:2rem;height:2rem}</style><div class="palette" style="display:flex;flex-direction:row"><div style="background-color: #fff7ed"></div><div style="background-color: #ffedd5"></div><div style="background-color: #fed7aa"></div><div style="background-color: #fdba74"></div><div style="background-color: #fb923c"></div><div style="background-color: #f97316"></div><div style="background-color: #ea580c"></div><div style="background-color: #c2410c"></div><div style="background-color: #9a3412"></div><div style="background-color: #7c2d12"></div><div style="background-color: #431407"></div></div>
|
||||
pub const ORANGE: Palette = Palette {
|
||||
c50: Color::from_u32(0xfff7ed),
|
||||
c100: Color::from_u32(0xffedd5),
|
||||
c200: Color::from_u32(0xfed7aa),
|
||||
c300: Color::from_u32(0xfdba74),
|
||||
c400: Color::from_u32(0xfb923c),
|
||||
c500: Color::from_u32(0xf97316),
|
||||
c600: Color::from_u32(0xea580c),
|
||||
c700: Color::from_u32(0xc2410c),
|
||||
c800: Color::from_u32(0x9a3412),
|
||||
c900: Color::from_u32(0x7c2d12),
|
||||
c950: Color::from_u32(0x431407),
|
||||
};
|
||||
|
||||
#[rustfmt::skip]
|
||||
/// <style>.palette div{width:2rem;height:2rem}</style><div class="palette" style="display:flex;flex-direction:row"><div style="background-color: #fffbeb"></div><div style="background-color: #fef3c7"></div><div style="background-color: #fde68a"></div><div style="background-color: #fcd34d"></div><div style="background-color: #fbbf24"></div><div style="background-color: #f59e0b"></div><div style="background-color: #d97706"></div><div style="background-color: #b45309"></div><div style="background-color: #92400e"></div><div style="background-color: #78350f"></div><div style="background-color: #451a03"></div></div>
|
||||
pub const AMBER: Palette = Palette {
|
||||
c50: Color::from_u32(0xfffbeb),
|
||||
c100: Color::from_u32(0xfef3c7),
|
||||
c200: Color::from_u32(0xfde68a),
|
||||
c300: Color::from_u32(0xfcd34d),
|
||||
c400: Color::from_u32(0xfbbf24),
|
||||
c500: Color::from_u32(0xf59e0b),
|
||||
c600: Color::from_u32(0xd97706),
|
||||
c700: Color::from_u32(0xb45309),
|
||||
c800: Color::from_u32(0x92400e),
|
||||
c900: Color::from_u32(0x78350f),
|
||||
c950: Color::from_u32(0x451a03),
|
||||
};
|
||||
|
||||
#[rustfmt::skip]
|
||||
/// <style>.palette div{width:2rem;height:2rem}</style><div class="palette" style="display:flex;flex-direction:row"><div style="background-color: #fefce8"></div><div style="background-color: #fef9c3"></div><div style="background-color: #fef08a"></div><div style="background-color: #fde047"></div><div style="background-color: #facc15"></div><div style="background-color: #eab308"></div><div style="background-color: #ca8a04"></div><div style="background-color: #a16207"></div><div style="background-color: #854d0e"></div><div style="background-color: #713f12"></div><div style="background-color: #422006"></div></div>
|
||||
pub const YELLOW: Palette = Palette {
|
||||
c50: Color::from_u32(0xfefce8),
|
||||
c100: Color::from_u32(0xfef9c3),
|
||||
c200: Color::from_u32(0xfef08a),
|
||||
c300: Color::from_u32(0xfde047),
|
||||
c400: Color::from_u32(0xfacc15),
|
||||
c500: Color::from_u32(0xeab308),
|
||||
c600: Color::from_u32(0xca8a04),
|
||||
c700: Color::from_u32(0xa16207),
|
||||
c800: Color::from_u32(0x854d0e),
|
||||
c900: Color::from_u32(0x713f12),
|
||||
c950: Color::from_u32(0x422006),
|
||||
};
|
||||
|
||||
#[rustfmt::skip]
|
||||
/// <style>.palette div{width:2rem;height:2rem}</style><div class="palette" style="display:flex;flex-direction:row"><div style="background-color: #f7fee7"></div><div style="background-color: #ecfccb"></div><div style="background-color: #d9f99d"></div><div style="background-color: #bef264"></div><div style="background-color: #a3e635"></div><div style="background-color: #84cc16"></div><div style="background-color: #65a30d"></div><div style="background-color: #4d7c0f"></div><div style="background-color: #3f6212"></div><div style="background-color: #365314"></div><div style="background-color: #1a2e05"></div></div>
|
||||
pub const LIME: Palette = Palette {
|
||||
c50: Color::from_u32(0xf7fee7),
|
||||
c100: Color::from_u32(0xecfccb),
|
||||
c200: Color::from_u32(0xd9f99d),
|
||||
c300: Color::from_u32(0xbef264),
|
||||
c400: Color::from_u32(0xa3e635),
|
||||
c500: Color::from_u32(0x84cc16),
|
||||
c600: Color::from_u32(0x65a30d),
|
||||
c700: Color::from_u32(0x4d7c0f),
|
||||
c800: Color::from_u32(0x3f6212),
|
||||
c900: Color::from_u32(0x365314),
|
||||
c950: Color::from_u32(0x1a2e05),
|
||||
};
|
||||
|
||||
#[rustfmt::skip]
|
||||
/// <style>.palette div{width:2rem;height:2rem}</style><div class="palette" style="display:flex;flex-direction:row"><div style="background-color: #f0fdf4"></div><div style="background-color: #dcfce7"></div><div style="background-color: #bbf7d0"></div><div style="background-color: #86efac"></div><div style="background-color: #4ade80"></div><div style="background-color: #22c55e"></div><div style="background-color: #16a34a"></div><div style="background-color: #15803d"></div><div style="background-color: #166534"></div><div style="background-color: #14532d"></div><div style="background-color: #052e16"></div></div>
|
||||
pub const GREEN: Palette = Palette {
|
||||
c50: Color::from_u32(0xf0fdf4),
|
||||
c100: Color::from_u32(0xdcfce7),
|
||||
c200: Color::from_u32(0xbbf7d0),
|
||||
c300: Color::from_u32(0x86efac),
|
||||
c400: Color::from_u32(0x4ade80),
|
||||
c500: Color::from_u32(0x22c55e),
|
||||
c600: Color::from_u32(0x16a34a),
|
||||
c700: Color::from_u32(0x15803d),
|
||||
c800: Color::from_u32(0x166534),
|
||||
c900: Color::from_u32(0x14532d),
|
||||
c950: Color::from_u32(0x052e16),
|
||||
};
|
||||
|
||||
#[rustfmt::skip]
|
||||
/// <style>.palette div{width:2rem;height:2rem}</style><div class="palette" style="display:flex;flex-direction:row"><div style="background-color: #f0fdfa"></div><div style="background-color: #ccfbf1"></div><div style="background-color: #99f6e4"></div><div style="background-color: #5eead4"></div><div style="background-color: #2dd4bf"></div><div style="background-color: #14b8a6"></div><div style="background-color: #0d9488"></div><div style="background-color: #0f766e"></div><div style="background-color: #115e59"></div><div style="background-color: #134e4a"></div><div style="background-color: #042f2e"></div></div>
|
||||
pub const EMERALD: Palette = Palette {
|
||||
c50: Color::from_u32(0xecfdf5),
|
||||
c100: Color::from_u32(0xd1fae5),
|
||||
c200: Color::from_u32(0xa7f3d0),
|
||||
c300: Color::from_u32(0x6ee7b7),
|
||||
c400: Color::from_u32(0x34d399),
|
||||
c500: Color::from_u32(0x10b981),
|
||||
c600: Color::from_u32(0x059669),
|
||||
c700: Color::from_u32(0x047857),
|
||||
c800: Color::from_u32(0x065f46),
|
||||
c900: Color::from_u32(0x064e3b),
|
||||
c950: Color::from_u32(0x022c22),
|
||||
};
|
||||
|
||||
#[rustfmt::skip]
|
||||
/// <style>.palette div{width:2rem;height:2rem}</style><div class="palette" style="display:flex;flex-direction:row"><div style="background-color: #f5fdf4"></div><div style="background-color: #e7f9e7"></div><div style="background-color: #c6f6d5"></div><div style="background-color: #9ae6b4"></div><div style="background-color: #68d391"></div><div style="background-color: #48bb78"></div><div style="background-color: #38a169"></div><div style="background-color: #2f855a"></div><div style="background-color: #276749"></div><div style="background-color: #22543d"></div><div style="background-color: #0d3321"></div></div>
|
||||
pub const TEAL: Palette = Palette {
|
||||
c50: Color::from_u32(0xf0fdfa),
|
||||
c100: Color::from_u32(0xccfbf1),
|
||||
c200: Color::from_u32(0x99f6e4),
|
||||
c300: Color::from_u32(0x5eead4),
|
||||
c400: Color::from_u32(0x2dd4bf),
|
||||
c500: Color::from_u32(0x14b8a6),
|
||||
c600: Color::from_u32(0x0d9488),
|
||||
c700: Color::from_u32(0x0f766e),
|
||||
c800: Color::from_u32(0x115e59),
|
||||
c900: Color::from_u32(0x134e4a),
|
||||
c950: Color::from_u32(0x042f2e),
|
||||
};
|
||||
|
||||
#[rustfmt::skip]
|
||||
/// <style>.palette div{width:2rem;height:2rem}</style><div class="palette" style="display:flex;flex-direction:row"><div style="background-color: #ecfeff"></div><div style="background-color: #cffafe"></div><div style="background-color: #a5f3fc"></div><div style="background-color: #67e8f9"></div><div style="background-color: #22d3ee"></div><div style="background-color: #06b6d4"></div><div style="background-color: #0891b2"></div><div style="background-color: #0e7490"></div><div style="background-color: #155e75"></div><div style="background-color: #164e63"></div><div style="background-color: #083344"></div></div>
|
||||
pub const CYAN: Palette = Palette {
|
||||
c50: Color::from_u32(0xecfeff),
|
||||
c100: Color::from_u32(0xcffafe),
|
||||
c200: Color::from_u32(0xa5f3fc),
|
||||
c300: Color::from_u32(0x67e8f9),
|
||||
c400: Color::from_u32(0x22d3ee),
|
||||
c500: Color::from_u32(0x06b6d4),
|
||||
c600: Color::from_u32(0x0891b2),
|
||||
c700: Color::from_u32(0x0e7490),
|
||||
c800: Color::from_u32(0x155e75),
|
||||
c900: Color::from_u32(0x164e63),
|
||||
c950: Color::from_u32(0x083344),
|
||||
};
|
||||
|
||||
#[rustfmt::skip]
|
||||
/// <style>.palette div{width:22rem;height:2rem}</style><div class="palette" style="display:flex;flex-direction:row"><div style="background-color: #f0f9ff"></div><div style="background-color: #e0f2fe"></div><div style="background-color: #bae6fd"></div><div style="background-color: #7dd3fc"></div><div style="background-color: #38bdf8"></div><div style="background-color: #0ea5e9"></div><div style="background-color: #0284c7"></div><div style="background-color: #0369a1"></div><div style="background-color: #075985"></div><div style="background-color: #0c4a6e"></div><div style="background-color: #082f49"></div></div>
|
||||
pub const SKY: Palette = Palette {
|
||||
c50: Color::from_u32(0xf0f9ff),
|
||||
c100: Color::from_u32(0xe0f2fe),
|
||||
c200: Color::from_u32(0xbae6fd),
|
||||
c300: Color::from_u32(0x7dd3fc),
|
||||
c400: Color::from_u32(0x38bdf8),
|
||||
c500: Color::from_u32(0x0ea5e9),
|
||||
c600: Color::from_u32(0x0284c7),
|
||||
c700: Color::from_u32(0x0369a1),
|
||||
c800: Color::from_u32(0x075985),
|
||||
c900: Color::from_u32(0x0c4a6e),
|
||||
c950: Color::from_u32(0x082f49),
|
||||
};
|
||||
|
||||
#[rustfmt::skip]
|
||||
/// <style>.palette div{width:22rem;height:2rem}</style><div class="palette" style="display:flex;flex-direction:row"><div style="background-color: #eff6ff"></div><div style="background-color: #dbeafe"></div><div style="background-color: #bfdbfe"></div><div style="background-color: #93c5fd"></div><div style="background-color: #60a5fa"></div><div style="background-color: #3b82f6"></div><div style="background-color: #2563eb"></div><div style="background-color: #1d4ed8"></div><div style="background-color: #1e40af"></div><div style="background-color: #1e3a8a"></div><div style="background-color: #172554"></div></div>
|
||||
pub const BLUE: Palette = Palette {
|
||||
c50: Color::from_u32(0xeff6ff),
|
||||
c100: Color::from_u32(0xdbeafe),
|
||||
c200: Color::from_u32(0xbfdbfe),
|
||||
c300: Color::from_u32(0x93c5fd),
|
||||
c400: Color::from_u32(0x60a5fa),
|
||||
c500: Color::from_u32(0x3b82f6),
|
||||
c600: Color::from_u32(0x2563eb),
|
||||
c700: Color::from_u32(0x1d4ed8),
|
||||
c800: Color::from_u32(0x1e40af),
|
||||
c900: Color::from_u32(0x1e3a8a),
|
||||
c950: Color::from_u32(0x172554),
|
||||
};
|
||||
|
||||
#[rustfmt::skip]
|
||||
/// <style>.palette div{width:22rem;height:2rem}</style><div class="palette" style="display:flex;flex-direction:row"><div style="background-color: #eef2ff"></div><div style="background-color: #e0e7ff"></div><div style="background-color: #c7d2fe"></div><div style="background-color: #a5b4fc"></div><div style="background-color: #818cf8"></div><div style="background-color: #6366f1"></div><div style="background-color: #4f46e5"></div><div style="background-color: #4338ca"></div><div style="background-color: #3730a3"></div><div style="background-color: #312e81"></div><div style="background-color: #1e1b4b"></div></div>
|
||||
pub const INDIGO: Palette = Palette {
|
||||
c50: Color::from_u32(0xeef2ff),
|
||||
c100: Color::from_u32(0xe0e7ff),
|
||||
c200: Color::from_u32(0xc7d2fe),
|
||||
c300: Color::from_u32(0xa5b4fc),
|
||||
c400: Color::from_u32(0x818cf8),
|
||||
c500: Color::from_u32(0x6366f1),
|
||||
c600: Color::from_u32(0x4f46e5),
|
||||
c700: Color::from_u32(0x4338ca),
|
||||
c800: Color::from_u32(0x3730a3),
|
||||
c900: Color::from_u32(0x312e81),
|
||||
c950: Color::from_u32(0x1e1b4b),
|
||||
};
|
||||
|
||||
#[rustfmt::skip]
|
||||
/// <style>.palette div{width:22rem;height:2rem}</style><div class="palette" style="display:flex;flex-direction:row"><div style="background-color: #f5f3ff"></div><div style="background-color: #ede9fe"></div><div style="background-color: #ddd6fe"></div><div style="background-color: #c4b5fd"></div><div style="background-color: #a78bfa"></div><div style="background-color: #8b5cf6"></div><div style="background-color: #7c3aed"></div><div style="background-color: #6d28d9"></div><div style="background-color: #5b21b6"></div><div style="background-color: #4c1d95"></div><div style="background-color: #2e1065"></div></div>
|
||||
pub const VIOLET: Palette = Palette {
|
||||
c50: Color::from_u32(0xf5f3ff),
|
||||
c100: Color::from_u32(0xede9fe),
|
||||
c200: Color::from_u32(0xddd6fe),
|
||||
c300: Color::from_u32(0xc4b5fd),
|
||||
c400: Color::from_u32(0xa78bfa),
|
||||
c500: Color::from_u32(0x8b5cf6),
|
||||
c600: Color::from_u32(0x7c3aed),
|
||||
c700: Color::from_u32(0x6d28d9),
|
||||
c800: Color::from_u32(0x5b21b6),
|
||||
c900: Color::from_u32(0x4c1d95),
|
||||
c950: Color::from_u32(0x2e1065),
|
||||
};
|
||||
|
||||
#[rustfmt::skip]
|
||||
/// <style>.palette div{width:22rem;height:2rem}</style><div class="palette" style="display:flex;flex-direction:row"><div style="background-color: #faf5ff"></div><div style="background-color: #f3e8ff"></div><div style="background-color: #e9d5ff"></div><div style="background-color: #d8b4fe"></div><div style="background-color: #c084fc"></div><div style="background-color: #a855f7"></div><div style="background-color: #9333ea"></div><div style="background-color: #7e22ce"></div><div style="background-color: #6b21a8"></div><div style="background-color: #581c87"></div><div style="background-color: #3b0764"></div></div>
|
||||
pub const PURPLE: Palette = Palette {
|
||||
c50: Color::from_u32(0xfaf5ff),
|
||||
c100: Color::from_u32(0xf3e8ff),
|
||||
c200: Color::from_u32(0xe9d5ff),
|
||||
c300: Color::from_u32(0xd8b4fe),
|
||||
c400: Color::from_u32(0xc084fc),
|
||||
c500: Color::from_u32(0xa855f7),
|
||||
c600: Color::from_u32(0x9333ea),
|
||||
c700: Color::from_u32(0x7e22ce),
|
||||
c800: Color::from_u32(0x6b21a8),
|
||||
c900: Color::from_u32(0x581c87),
|
||||
c950: Color::from_u32(0x3b0764),
|
||||
};
|
||||
|
||||
#[rustfmt::skip]
|
||||
/// <style>.palette div{width:22rem;height:2rem}</style><div class="palette" style="display:flex;flex-direction:row"><div style="background-color: #fdf4ff"></div><div style="background-color: #fae8ff"></div><div style="background-color: #f5d0fe"></div><div style="background-color: #f0abfc"></div><div style="background-color: #e879f9"></div><div style="background-color: #d946ef"></div><div style="background-color: #c026d3"></div><div style="background-color: #a21caf"></div><div style="background-color: #86198f"></div><div style="background-color: #701a75"></div><div style="background-color: #4a044e"></div></div>
|
||||
pub const FUCHSIA: Palette = Palette {
|
||||
c50: Color::from_u32(0xfdf4ff),
|
||||
c100: Color::from_u32(0xfae8ff),
|
||||
c200: Color::from_u32(0xf5d0fe),
|
||||
c300: Color::from_u32(0xf0abfc),
|
||||
c400: Color::from_u32(0xe879f9),
|
||||
c500: Color::from_u32(0xd946ef),
|
||||
c600: Color::from_u32(0xc026d3),
|
||||
c700: Color::from_u32(0xa21caf),
|
||||
c800: Color::from_u32(0x86198f),
|
||||
c900: Color::from_u32(0x701a75),
|
||||
c950: Color::from_u32(0x4a044e),
|
||||
};
|
||||
|
||||
#[rustfmt::skip]
|
||||
/// <style>.palette div{width:22rem;height:2rem}</style><div class="palette" style="display:flex;flex-direction:row"><div style="background-color: #fdf2f8"></div><div style="background-color: #fce7f3"></div><div style="background-color: #fbcfe8"></div><div style="background-color: #f9a8d4"></div><div style="background-color: #f472b6"></div><div style="background-color: #ec4899"></div><div style="background-color: #db2777"></div><div style="background-color: #be185d"></div><div style="background-color: #9d174d"></div><div style="background-color: #831843"></div><div style="background-color: #500724"></div></div>
|
||||
pub const PINK: Palette = Palette {
|
||||
c50: Color::from_u32(0xfdf2f8),
|
||||
c100: Color::from_u32(0xfce7f3),
|
||||
c200: Color::from_u32(0xfbcfe8),
|
||||
c300: Color::from_u32(0xf9a8d4),
|
||||
c400: Color::from_u32(0xf472b6),
|
||||
c500: Color::from_u32(0xec4899),
|
||||
c600: Color::from_u32(0xdb2777),
|
||||
c700: Color::from_u32(0xbe185d),
|
||||
c800: Color::from_u32(0x9d174d),
|
||||
c900: Color::from_u32(0x831843),
|
||||
c950: Color::from_u32(0x500724),
|
||||
};
|
||||
|
||||
#[rustfmt::skip]
|
||||
/// <style>.palette div{width:22rem;height:2rem}</style><div class="palette" style="display:flex;flex-direction:row"><div style="background-color: #fff1f2"></div><div style="background-color: #ffe4e6"></div><div style="background-color: #fecdd3"></div><div style="background-color: #fda4af"></div><div style="background-color: #fb7185"></div><div style="background-color: #f43f5e"></div><div style="background-color: #e11d48"></div><div style="background-color: #be123c"></div><div style="background-color: #9f1239"></div><div style="background-color: #881337"></div><div style="background-color: #4c0519"></div></div>
|
||||
pub const ROSE: Palette = Palette {
|
||||
c50: Color::from_u32(0xfff1f2),
|
||||
c100: Color::from_u32(0xffe4e6),
|
||||
c200: Color::from_u32(0xfecdd3),
|
||||
c300: Color::from_u32(0xfda4af),
|
||||
c400: Color::from_u32(0xfb7185),
|
||||
c500: Color::from_u32(0xf43f5e),
|
||||
c600: Color::from_u32(0xe11d48),
|
||||
c700: Color::from_u32(0xbe123c),
|
||||
c800: Color::from_u32(0x9f1239),
|
||||
c900: Color::from_u32(0x881337),
|
||||
c950: Color::from_u32(0x4c0519),
|
||||
};
|
||||
@@ -26,6 +26,9 @@ pub struct Frame<'a> {
|
||||
|
||||
/// The buffer that is used to draw the current frame
|
||||
pub(crate) buffer: &'a mut Buffer,
|
||||
|
||||
/// The frame count indicating the sequence number of this frame.
|
||||
pub(crate) count: usize,
|
||||
}
|
||||
|
||||
/// `CompletedFrame` represents the state of the terminal after all changes performed in the last
|
||||
@@ -37,6 +40,8 @@ pub struct CompletedFrame<'a> {
|
||||
pub buffer: &'a Buffer,
|
||||
/// The size of the last frame.
|
||||
pub area: Rect,
|
||||
/// The frame count indicating the sequence number of this frame.
|
||||
pub count: usize,
|
||||
}
|
||||
|
||||
impl Frame<'_> {
|
||||
@@ -119,4 +124,32 @@ impl Frame<'_> {
|
||||
pub fn buffer_mut(&mut self) -> &mut Buffer {
|
||||
self.buffer
|
||||
}
|
||||
|
||||
/// Returns the current frame count.
|
||||
///
|
||||
/// This method provides access to the frame count, which is a sequence number indicating
|
||||
/// how many frames have been rendered up to (but not including) this one. It can be used
|
||||
/// for purposes such as animation, performance tracking, or debugging.
|
||||
///
|
||||
/// Each time a frame has been rendered, this count is incremented,
|
||||
/// providing a consistent way to reference the order and number of frames processed by the
|
||||
/// terminal. When count reaches its maximum value (usize::MAX), it wraps around to zero.
|
||||
///
|
||||
/// This count is particularly useful when dealing with dynamic content or animations where the
|
||||
/// state of the display changes over time. By tracking the frame count, developers can
|
||||
/// synchronize updates or changes to the content with the rendering process.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// # use ratatui::{backend::TestBackend, prelude::*, widgets::*};
|
||||
/// # let backend = TestBackend::new(5, 5);
|
||||
/// # let mut terminal = Terminal::new(backend).unwrap();
|
||||
/// # let mut frame = terminal.get_frame();
|
||||
/// let current_count = frame.count();
|
||||
/// println!("Current frame count: {}", current_count);
|
||||
/// ```
|
||||
pub fn count(&self) -> usize {
|
||||
self.count
|
||||
}
|
||||
}
|
||||
|
||||
@@ -71,6 +71,8 @@ where
|
||||
/// Last known position of the cursor. Used to find the new area when the viewport is inlined
|
||||
/// and the terminal resized.
|
||||
last_known_cursor_pos: (u16, u16),
|
||||
/// Number of frames rendered up until current time.
|
||||
frame_count: usize,
|
||||
}
|
||||
|
||||
/// Options to pass to [`Terminal::with_options`]
|
||||
@@ -149,15 +151,18 @@ where
|
||||
viewport_area,
|
||||
last_known_size: size,
|
||||
last_known_cursor_pos: cursor_pos,
|
||||
frame_count: 0,
|
||||
})
|
||||
}
|
||||
|
||||
/// Get a Frame object which provides a consistent view into the terminal state for rendering.
|
||||
pub fn get_frame(&mut self) -> Frame {
|
||||
let count = self.frame_count;
|
||||
Frame {
|
||||
cursor_position: None,
|
||||
viewport_area: self.viewport_area,
|
||||
buffer: self.current_buffer_mut(),
|
||||
count,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -279,10 +284,16 @@ where
|
||||
// Flush
|
||||
self.backend.flush()?;
|
||||
|
||||
Ok(CompletedFrame {
|
||||
let completed_frame = CompletedFrame {
|
||||
buffer: &self.buffers[1 - self.current],
|
||||
area: self.last_known_size,
|
||||
})
|
||||
count: self.frame_count,
|
||||
};
|
||||
|
||||
// increment frame count before returning from draw
|
||||
self.frame_count = self.frame_count.wrapping_add(1);
|
||||
|
||||
Ok(completed_frame)
|
||||
}
|
||||
|
||||
/// Hides the cursor.
|
||||
|
||||
27
src/widgets/list.rs
Normal file → Executable file
27
src/widgets/list.rs
Normal file → Executable file
@@ -45,6 +45,7 @@ use crate::{
|
||||
/// # }
|
||||
/// ```
|
||||
#[derive(Debug, Default, Clone, Eq, PartialEq, Hash)]
|
||||
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||
pub struct ListState {
|
||||
offset: usize,
|
||||
selected: Option<usize>,
|
||||
@@ -399,6 +400,16 @@ where
|
||||
///
|
||||
/// frame.render_stateful_widget(list, area, &mut state);
|
||||
/// # }
|
||||
/// ```
|
||||
///
|
||||
/// In addition to `List::new`, any iterator whose element is convertible to `ListItem` can be
|
||||
/// collected into `List`.
|
||||
///
|
||||
/// ```
|
||||
/// use ratatui::widgets::List;
|
||||
///
|
||||
/// (0..5).map(|i| format!("Item{i}")).collect::<List>();
|
||||
/// ```
|
||||
#[derive(Debug, Clone, Eq, PartialEq, Hash, Default)]
|
||||
pub struct List<'a> {
|
||||
block: Option<Block<'a>>,
|
||||
@@ -877,6 +888,15 @@ impl<'a> Styled for ListItem<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, Item> FromIterator<Item> for List<'a>
|
||||
where
|
||||
Item: Into<ListItem<'a>>,
|
||||
{
|
||||
fn from_iter<Iter: IntoIterator<Item = Item>>(iter: Iter) -> Self {
|
||||
List::new(iter)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::borrow::Cow;
|
||||
@@ -1327,6 +1347,13 @@ mod tests {
|
||||
assert_buffer_eq!(buffer, expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_collect_list_from_iterator() {
|
||||
let collected: List = (0..3).map(|i| format!("Item{i}")).collect();
|
||||
let expected = List::new(["Item0", "Item1", "Item2"]);
|
||||
assert_eq!(collected, expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_list_block() {
|
||||
let items = list_items(vec!["Item 0", "Item 1", "Item 2"]);
|
||||
|
||||
@@ -42,6 +42,7 @@ pub enum ScrollDirection {
|
||||
/// If you don't have multi-line content, you can leave the `viewport_content_length` set to the
|
||||
/// default of 0 and it'll use the track size as a `viewport_content_length`.
|
||||
#[derive(Debug, Default, Clone, Copy, Eq, PartialEq, Hash)]
|
||||
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||
pub struct ScrollbarState {
|
||||
// The total length of the scrollable content.
|
||||
content_length: usize,
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
use std::iter;
|
||||
|
||||
use itertools::Itertools;
|
||||
use unicode_width::UnicodeWidthStr;
|
||||
|
||||
use super::*;
|
||||
use crate::{
|
||||
@@ -14,7 +13,7 @@ use crate::{
|
||||
///
|
||||
/// A `Table` is a collection of [`Row`]s, each composed of [`Cell`]s:
|
||||
///
|
||||
/// You can consutrct a [`Table`] using either [`Table::new`] or [`Table::default`] and then chain
|
||||
/// You can construct a [`Table`] using either [`Table::new`] or [`Table::default`] and then chain
|
||||
/// builder style methods to set the desired properties.
|
||||
///
|
||||
/// Make sure to call the [`Table::widths`] method, otherwise the columns will all have a width of 0
|
||||
@@ -133,6 +132,22 @@ use crate::{
|
||||
/// Cell::from(Text::from("text"));
|
||||
/// ```
|
||||
///
|
||||
/// Just as rows can be collected from iterators of `Cell`s, tables can be collected from iterators
|
||||
/// of `Row`s. This will create a table with column widths evenly dividing the space available.
|
||||
/// These default columns widths can be overridden using the `Table::widths` method.
|
||||
///
|
||||
/// ```rust
|
||||
/// use ratatui::{prelude::*, widgets::*};
|
||||
///
|
||||
/// let text = "Mary had a\nlittle lamb.";
|
||||
///
|
||||
/// let table = text
|
||||
/// .split("\n")
|
||||
/// .map(|line: &str| -> Row { line.split_ascii_whitespace().collect() })
|
||||
/// .collect::<Table>()
|
||||
/// .widths([Constraint::Length(10); 3]);
|
||||
/// ```
|
||||
///
|
||||
/// `Table` also implements the [`Styled`] trait, which means you can use style shorthands from
|
||||
/// the [`Stylize`] trait to set the style of the widget more concisely.
|
||||
///
|
||||
@@ -173,7 +188,7 @@ use crate::{
|
||||
///
|
||||
/// frame.render_stateful_widget(table, area, &mut table_state);
|
||||
/// # }
|
||||
#[derive(Debug, Default, Clone, Eq, PartialEq, Hash)]
|
||||
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
|
||||
pub struct Table<'a> {
|
||||
/// Data to display in each row
|
||||
rows: Vec<Row<'a>>,
|
||||
@@ -200,7 +215,7 @@ pub struct Table<'a> {
|
||||
highlight_style: Style,
|
||||
|
||||
/// Symbol in front of the selected rom
|
||||
highlight_symbol: Option<&'a str>,
|
||||
highlight_symbol: Text<'a>,
|
||||
|
||||
/// Decides when to allocate spacing for the row selection
|
||||
highlight_spacing: HighlightSpacing,
|
||||
@@ -209,6 +224,24 @@ pub struct Table<'a> {
|
||||
segment_size: SegmentSize,
|
||||
}
|
||||
|
||||
impl<'a> Default for Table<'a> {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
rows: Default::default(),
|
||||
header: Default::default(),
|
||||
footer: Default::default(),
|
||||
widths: Default::default(),
|
||||
column_spacing: 1,
|
||||
block: Default::default(),
|
||||
style: Default::default(),
|
||||
highlight_style: Default::default(),
|
||||
highlight_symbol: Default::default(),
|
||||
highlight_spacing: Default::default(),
|
||||
segment_size: SegmentSize::None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Table<'a> {
|
||||
/// Creates a new [`Table`] widget with the given rows.
|
||||
///
|
||||
@@ -233,18 +266,18 @@ impl<'a> Table<'a> {
|
||||
/// ```
|
||||
pub fn new<R, C>(rows: R, widths: C) -> Self
|
||||
where
|
||||
R: IntoIterator<Item = Row<'a>>,
|
||||
R: IntoIterator,
|
||||
R::Item: Into<Row<'a>>,
|
||||
C: IntoIterator,
|
||||
C::Item: Into<Constraint>,
|
||||
{
|
||||
let widths = widths.into_iter().map(Into::into).collect_vec();
|
||||
ensure_percentages_less_than_100(&widths);
|
||||
|
||||
let rows = rows.into_iter().map(Into::into).collect();
|
||||
Self {
|
||||
rows: rows.into_iter().collect(),
|
||||
rows,
|
||||
widths,
|
||||
column_spacing: 1,
|
||||
// Note: None is not the default value for SegmentSize, so we need to explicitly set it
|
||||
segment_size: SegmentSize::None,
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
@@ -469,8 +502,8 @@ impl<'a> Table<'a> {
|
||||
/// let table = Table::new(rows, widths).highlight_symbol(">>");
|
||||
/// ```
|
||||
#[must_use = "method moves the value of self and returns the modified value"]
|
||||
pub fn highlight_symbol(mut self, highlight_symbol: &'a str) -> Self {
|
||||
self.highlight_symbol = Some(highlight_symbol);
|
||||
pub fn highlight_symbol<T: Into<Text<'a>>>(mut self, highlight_symbol: T) -> Self {
|
||||
self.highlight_symbol = highlight_symbol.into();
|
||||
self
|
||||
}
|
||||
|
||||
@@ -520,11 +553,10 @@ impl<'a> Table<'a> {
|
||||
/// to the last column.
|
||||
#[cfg_attr(feature = "unstable", doc = " ```")]
|
||||
#[cfg_attr(not(feature = "unstable"), doc = " ```ignore")]
|
||||
/// # use ratatui::layout::Constraint;
|
||||
/// # use ratatui::layout::SegmentSize;
|
||||
/// # use ratatui::widgets::Table;
|
||||
/// # use ratatui::layout::{Constraint, SegmentSize};
|
||||
/// # use ratatui::widgets::{Table, Row};
|
||||
/// let widths = [Constraint::Min(10), Constraint::Min(10), Constraint::Min(10)];
|
||||
/// let table = Table::new([], widths)
|
||||
/// let table = Table::new(Vec::<Row>::new(), widths)
|
||||
/// .segment_size(SegmentSize::LastTakesRemainder);
|
||||
/// ```
|
||||
#[stability::unstable(
|
||||
@@ -557,8 +589,6 @@ impl StatefulWidget for Table<'_> {
|
||||
}
|
||||
let selection_width = self.selection_width(state);
|
||||
let columns_widths = self.get_columns_widths(table_area.width, selection_width);
|
||||
let highlight_symbol = self.highlight_symbol.unwrap_or("");
|
||||
|
||||
let (header_area, rows_area, footer_area) = self.layout(table_area);
|
||||
|
||||
self.render_header(header_area, buf, &columns_widths);
|
||||
@@ -568,7 +598,7 @@ impl StatefulWidget for Table<'_> {
|
||||
buf,
|
||||
state,
|
||||
selection_width,
|
||||
highlight_symbol,
|
||||
&self.highlight_symbol,
|
||||
&columns_widths,
|
||||
);
|
||||
|
||||
@@ -634,7 +664,7 @@ impl Table<'_> {
|
||||
buf: &mut Buffer,
|
||||
state: &mut TableState,
|
||||
selection_width: u16,
|
||||
highlight_symbol: &str,
|
||||
highlight_symbol: &Text<'_>,
|
||||
columns_widths: &[(u16, u16)],
|
||||
) {
|
||||
if self.rows.is_empty() {
|
||||
@@ -666,13 +696,9 @@ impl Table<'_> {
|
||||
// this should in normal cases be safe, because "get_columns_widths" allocates
|
||||
// "highlight_symbol.width()" space but "get_columns_widths"
|
||||
// currently does not bind it to max table.width()
|
||||
buf.set_stringn(
|
||||
row_area.x,
|
||||
row_area.y,
|
||||
highlight_symbol,
|
||||
area.width as usize,
|
||||
row.style,
|
||||
);
|
||||
for (line, line_row) in highlight_symbol.lines.iter().zip(row_area.rows()) {
|
||||
line.clone().style(row.style).render(line_row, buf);
|
||||
}
|
||||
};
|
||||
for ((x, width), cell) in columns_widths.iter().zip(row.cells.iter()) {
|
||||
cell.render(
|
||||
@@ -769,7 +795,7 @@ impl Table<'_> {
|
||||
fn selection_width(&self, state: &TableState) -> u16 {
|
||||
let has_selection = state.selected().is_some();
|
||||
if self.highlight_spacing.should_add(has_selection) {
|
||||
self.highlight_symbol.map_or(0, UnicodeWidthStr::width) as u16
|
||||
self.highlight_symbol.width() as u16
|
||||
} else {
|
||||
0
|
||||
}
|
||||
@@ -799,6 +825,20 @@ impl<'a> Styled for Table<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, Item> FromIterator<Item> for Table<'a>
|
||||
where
|
||||
Item: Into<Row<'a>>,
|
||||
{
|
||||
/// Collects an iterator of rows into a table.
|
||||
///
|
||||
/// When collecting from an iterator into a table, the user must provide the widths using
|
||||
/// `Table::widths` after construction.
|
||||
fn from_iter<Iter: IntoIterator<Item = Item>>(rows: Iter) -> Self {
|
||||
let widths: [Constraint; 0] = [];
|
||||
Table::new(rows, widths)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::vec;
|
||||
@@ -817,7 +857,50 @@ mod tests {
|
||||
let widths = [Constraint::Percentage(100)];
|
||||
let table = Table::new(rows.clone(), widths);
|
||||
assert_eq!(table.rows, rows);
|
||||
assert_eq!(table.header, None);
|
||||
assert_eq!(table.footer, None);
|
||||
assert_eq!(table.widths, widths);
|
||||
assert_eq!(table.column_spacing, 1);
|
||||
assert_eq!(table.block, None);
|
||||
assert_eq!(table.style, Style::default());
|
||||
assert_eq!(table.highlight_style, Style::default());
|
||||
assert_eq!(table.highlight_symbol, Text::default());
|
||||
assert_eq!(table.highlight_spacing, HighlightSpacing::WhenSelected);
|
||||
assert_eq!(table.segment_size, SegmentSize::None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn default() {
|
||||
let table = Table::default();
|
||||
assert_eq!(table.rows, vec![]);
|
||||
assert_eq!(table.header, None);
|
||||
assert_eq!(table.footer, None);
|
||||
assert_eq!(table.widths, vec![]);
|
||||
assert_eq!(table.column_spacing, 1);
|
||||
assert_eq!(table.block, None);
|
||||
assert_eq!(table.style, Style::default());
|
||||
assert_eq!(table.highlight_style, Style::default());
|
||||
assert_eq!(table.highlight_symbol, Text::default());
|
||||
assert_eq!(table.highlight_spacing, HighlightSpacing::WhenSelected);
|
||||
assert_eq!(table.segment_size, SegmentSize::None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn collect() {
|
||||
let table = (0..4)
|
||||
.map(|i| -> Row { (0..4).map(|j| format!("{i}*{j} = {}", i * j)).collect() })
|
||||
.collect::<Table>()
|
||||
.widths([Constraint::Percentage(25); 4]);
|
||||
|
||||
let expected_rows: Vec<Row> = vec![
|
||||
Row::new(["0*0 = 0", "0*1 = 0", "0*2 = 0", "0*3 = 0"]),
|
||||
Row::new(["1*0 = 0", "1*1 = 1", "1*2 = 2", "1*3 = 3"]),
|
||||
Row::new(["2*0 = 0", "2*1 = 2", "2*2 = 4", "2*3 = 6"]),
|
||||
Row::new(["3*0 = 0", "3*1 = 3", "3*2 = 6", "3*3 = 9"]),
|
||||
];
|
||||
|
||||
assert_eq!(table.rows, expected_rows);
|
||||
assert_eq!(table.widths, [Constraint::Percentage(25); 4]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -883,7 +966,7 @@ mod tests {
|
||||
#[test]
|
||||
fn highlight_symbol() {
|
||||
let table = Table::default().highlight_symbol(">>");
|
||||
assert_eq!(table.highlight_symbol, Some(">>"));
|
||||
assert_eq!(table.highlight_symbol, Text::from(">>"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -901,24 +984,24 @@ mod tests {
|
||||
#[test]
|
||||
fn widths_conversions() {
|
||||
let array = [Constraint::Percentage(100)];
|
||||
let table = Table::new(vec![], array);
|
||||
let table = Table::new(Vec::<Row>::new(), array);
|
||||
assert_eq!(table.widths, vec![Constraint::Percentage(100)], "array");
|
||||
|
||||
let array_ref = &[Constraint::Percentage(100)];
|
||||
let table = Table::new(vec![], array_ref);
|
||||
let table = Table::new(Vec::<Row>::new(), array_ref);
|
||||
assert_eq!(table.widths, vec![Constraint::Percentage(100)], "array ref");
|
||||
|
||||
let vec = vec![Constraint::Percentage(100)];
|
||||
let slice = vec.as_slice();
|
||||
let table = Table::new(vec![], slice);
|
||||
let table = Table::new(Vec::<Row>::new(), slice);
|
||||
assert_eq!(table.widths, vec![Constraint::Percentage(100)], "slice");
|
||||
|
||||
let vec = vec![Constraint::Percentage(100)];
|
||||
let table = Table::new(vec![], vec);
|
||||
let table = Table::new(Vec::<Row>::new(), vec);
|
||||
assert_eq!(table.widths, vec![Constraint::Percentage(100)], "vec");
|
||||
|
||||
let vec_ref = &vec![Constraint::Percentage(100)];
|
||||
let table = Table::new(vec![], vec_ref);
|
||||
let table = Table::new(Vec::<Row>::new(), vec_ref);
|
||||
assert_eq!(table.widths, vec![Constraint::Percentage(100)], "vec ref");
|
||||
}
|
||||
|
||||
@@ -1087,7 +1170,7 @@ mod tests {
|
||||
#[test]
|
||||
fn render_with_overflow_does_not_panic() {
|
||||
let mut buf = Buffer::empty(Rect::new(0, 0, 20, 3));
|
||||
let table = Table::new(vec![], [Constraint::Min(20); 1])
|
||||
let table = Table::new(Vec::<Row>::new(), [Constraint::Min(20); 1])
|
||||
.header(Row::new([Line::from("").alignment(Alignment::Right)]))
|
||||
.footer(Row::new([Line::from("").alignment(Alignment::Right)]));
|
||||
Widget::render(table, Rect::new(0, 0, 20, 3), &mut buf);
|
||||
@@ -1128,7 +1211,7 @@ mod tests {
|
||||
selection_width: u16,
|
||||
expected: &[(u16, u16)],
|
||||
) {
|
||||
let table = Table::new(vec![], constraints).segment_size(segment_size);
|
||||
let table = Table::new(Vec::<Row>::new(), constraints).segment_size(segment_size);
|
||||
|
||||
let widths = table.get_columns_widths(available_width, selection_width);
|
||||
assert_eq!(widths, expected);
|
||||
|
||||
@@ -45,6 +45,7 @@
|
||||
/// [`Table::widths`]: crate::widgets::Table::widths
|
||||
/// [`Frame::render_stateful_widget`]: crate::Frame::render_stateful_widget
|
||||
#[derive(Debug, Default, Clone, Eq, PartialEq, Hash)]
|
||||
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||
pub struct TableState {
|
||||
pub(crate) offset: usize,
|
||||
pub(crate) selected: Option<usize>,
|
||||
|
||||
43
src/widgets/tabs.rs
Normal file → Executable file
43
src/widgets/tabs.rs
Normal file → Executable file
@@ -28,6 +28,15 @@ const DEFAULT_HIGHLIGHT_STYLE: Style = Style::new().add_modifier(Modifier::REVER
|
||||
/// .divider(symbols::DOT)
|
||||
/// .padding("->", "<-");
|
||||
/// ```
|
||||
///
|
||||
/// In addition to `Tabs::new`, any iterator whose element is convertible to `Line` can be collected
|
||||
/// into `Tabs`.
|
||||
///
|
||||
/// ```
|
||||
/// use ratatui::widgets::Tabs;
|
||||
///
|
||||
/// (0..5).map(|i| format!("Tab{i}")).collect::<Tabs>();
|
||||
/// ```
|
||||
#[derive(Debug, Default, Clone, Eq, PartialEq, Hash)]
|
||||
pub struct Tabs<'a> {
|
||||
/// A block to wrap this widget in if necessary
|
||||
@@ -79,9 +88,10 @@ impl<'a> Tabs<'a> {
|
||||
/// # use ratatui::{prelude::*, widgets::Tabs};
|
||||
/// let tabs = Tabs::new(vec!["Tab 1".red(), "Tab 2".blue()]);
|
||||
/// ```
|
||||
pub fn new<T>(titles: Vec<T>) -> Tabs<'a>
|
||||
pub fn new<Iter>(titles: Iter) -> Tabs<'a>
|
||||
where
|
||||
T: Into<Line<'a>>,
|
||||
Iter: IntoIterator,
|
||||
Iter::Item: Into<Line<'a>>,
|
||||
{
|
||||
Tabs {
|
||||
block: None,
|
||||
@@ -306,6 +316,15 @@ impl<'a> Widget for Tabs<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, Item> FromIterator<Item> for Tabs<'a>
|
||||
where
|
||||
Item: Into<Line<'a>>,
|
||||
{
|
||||
fn from_iter<Iter: IntoIterator<Item = Item>>(iter: Iter) -> Self {
|
||||
Self::new(iter)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
@@ -335,6 +354,26 @@ mod tests {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn new_from_vec_of_str() {
|
||||
Tabs::new(vec!["a", "b"]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn collect() {
|
||||
let tabs: Tabs = (0..5).map(|i| format!("Tab{i}")).collect();
|
||||
assert_eq!(
|
||||
tabs.titles,
|
||||
vec![
|
||||
Line::from("Tab0"),
|
||||
Line::from("Tab1"),
|
||||
Line::from("Tab2"),
|
||||
Line::from("Tab3"),
|
||||
Line::from("Tab4"),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
fn render(tabs: Tabs, area: Rect) -> Buffer {
|
||||
let mut buffer = Buffer::empty(area);
|
||||
tabs.render(area, &mut buffer);
|
||||
|
||||
204
tests/state_serde.rs
Normal file
204
tests/state_serde.rs
Normal file
@@ -0,0 +1,204 @@
|
||||
//! State like [`ListState`], [`TableState`] and [`ScrollbarState`] can be serialized and
|
||||
//! deserialized through serde. This allows saving your entire state to disk when the user exits the
|
||||
//! the app, and restore it again upon re-opening the app.
|
||||
//! This way, they get right back to where they were, without having to re-seek to their previous
|
||||
//! position, if that's applicable for the app at hand.
|
||||
//!
|
||||
//! **Note**: For this pattern to work easily, you need to have some toplevel struct which stores
|
||||
//! _only_ state and not any draw commands.
|
||||
//!
|
||||
//! **Note**: For many applications, it might be beneficial to instead keep your own state and
|
||||
//! instead construct the state for widgets on the fly instead, if that allows you to express you
|
||||
//! the semantic meaning of your state better or only fetch part of a dataset.
|
||||
|
||||
// not too happy about the redundancy in these tests,
|
||||
// but if that helps readability then it's ok i guess /shrug
|
||||
|
||||
use ratatui::{backend::TestBackend, prelude::*, widgets::*};
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
|
||||
struct AppState {
|
||||
list_state: ListState,
|
||||
table_state: TableState,
|
||||
scrollbar_state: ScrollbarState,
|
||||
}
|
||||
|
||||
impl Default for AppState {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
list_state: ListState::default(),
|
||||
table_state: TableState::default(),
|
||||
scrollbar_state: ScrollbarState::new(10),
|
||||
}
|
||||
}
|
||||
}
|
||||
impl AppState {
|
||||
fn select(&mut self, index: usize) {
|
||||
self.list_state.select(Some(index));
|
||||
self.table_state.select(Some(index));
|
||||
self.scrollbar_state = self.scrollbar_state.position(index);
|
||||
}
|
||||
}
|
||||
|
||||
/// Renders the list to a TestBackend and asserts that the result matches the expected buffer.
|
||||
#[track_caller]
|
||||
fn assert_buffer(state: &mut AppState, expected: &Buffer) {
|
||||
let backend = TestBackend::new(21, 5);
|
||||
let mut terminal = Terminal::new(backend).unwrap();
|
||||
terminal
|
||||
.draw(|f| {
|
||||
let items = vec![
|
||||
"awa", "banana", "Cats!!", "d20", "Echo", "Foxtrot", "Golf", "Hotel", "IwI",
|
||||
"Juliett",
|
||||
];
|
||||
|
||||
use Constraint::*;
|
||||
let layout = Layout::default()
|
||||
.direction(Direction::Horizontal)
|
||||
.constraints([Length(10), Length(10), Length(1)])
|
||||
.split(f.size());
|
||||
let list = List::new(items.clone())
|
||||
.highlight_symbol(">>")
|
||||
.block(Block::default().borders(Borders::RIGHT));
|
||||
f.render_stateful_widget(list, layout[0], &mut state.list_state);
|
||||
|
||||
let table = Table::new(
|
||||
items.iter().map(|i| Row::new(vec![*i])),
|
||||
[Constraint::Length(10); 5],
|
||||
)
|
||||
.highlight_symbol(">>");
|
||||
f.render_stateful_widget(table, layout[1], &mut state.table_state);
|
||||
|
||||
let scrollbar = Scrollbar::new(ScrollbarOrientation::VerticalRight);
|
||||
f.render_stateful_widget(scrollbar, layout[2], &mut state.scrollbar_state);
|
||||
})
|
||||
.unwrap();
|
||||
terminal.backend().assert_buffer(expected);
|
||||
}
|
||||
|
||||
const DEFAULT_STATE_BUFFER: [&str; 5] = [
|
||||
"awa │awa ▲",
|
||||
"banana │banana █",
|
||||
"Cats!! │Cats!! ║",
|
||||
"d20 │d20 ║",
|
||||
"Echo │Echo ▼",
|
||||
];
|
||||
|
||||
const DEFAULT_STATE_REPR: &str = r#"{
|
||||
"list_state": {
|
||||
"offset": 0,
|
||||
"selected": null
|
||||
},
|
||||
"table_state": {
|
||||
"offset": 0,
|
||||
"selected": null
|
||||
},
|
||||
"scrollbar_state": {
|
||||
"content_length": 10,
|
||||
"position": 0,
|
||||
"viewport_content_length": 0
|
||||
}
|
||||
}"#;
|
||||
|
||||
#[test]
|
||||
fn default_state_serialize() {
|
||||
let mut state = AppState::default();
|
||||
|
||||
let expected = Buffer::with_lines(DEFAULT_STATE_BUFFER.to_vec());
|
||||
assert_buffer(&mut state, &expected);
|
||||
|
||||
let state = serde_json::to_string_pretty(&state).unwrap();
|
||||
assert_eq!(state, DEFAULT_STATE_REPR);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn default_state_deserialize() {
|
||||
let expected = Buffer::with_lines(DEFAULT_STATE_BUFFER.to_vec());
|
||||
let mut state: AppState = serde_json::from_str(DEFAULT_STATE_REPR).unwrap();
|
||||
assert_buffer(&mut state, &expected);
|
||||
}
|
||||
|
||||
const SELECTED_STATE_BUFFER: [&str; 5] = [
|
||||
" awa │ awa ▲",
|
||||
">>banana │>>banana █",
|
||||
" Cats!! │ Cats!! ║",
|
||||
" d20 │ d20 ║",
|
||||
" Echo │ Echo ▼",
|
||||
];
|
||||
const SELECTED_STATE_REPR: &str = r#"{
|
||||
"list_state": {
|
||||
"offset": 0,
|
||||
"selected": 1
|
||||
},
|
||||
"table_state": {
|
||||
"offset": 0,
|
||||
"selected": 1
|
||||
},
|
||||
"scrollbar_state": {
|
||||
"content_length": 10,
|
||||
"position": 1,
|
||||
"viewport_content_length": 0
|
||||
}
|
||||
}"#;
|
||||
|
||||
#[test]
|
||||
fn selected_state_serialize() {
|
||||
let mut state = AppState::default();
|
||||
state.select(1);
|
||||
|
||||
let expected = Buffer::with_lines(SELECTED_STATE_BUFFER.to_vec());
|
||||
assert_buffer(&mut state, &expected);
|
||||
|
||||
let state = serde_json::to_string_pretty(&state).unwrap();
|
||||
assert_eq!(state, SELECTED_STATE_REPR);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn selected_state_deserialize() {
|
||||
let expected = Buffer::with_lines(SELECTED_STATE_BUFFER.to_vec());
|
||||
let mut state: AppState = serde_json::from_str(SELECTED_STATE_REPR).unwrap();
|
||||
assert_buffer(&mut state, &expected);
|
||||
}
|
||||
|
||||
const SCROLLED_STATE_BUFFER: [&str; 5] = [
|
||||
" Echo │ Echo ▲",
|
||||
" Foxtrot│ Foxtrot ║",
|
||||
" Golf │ Golf ║",
|
||||
" Hotel │ Hotel █",
|
||||
">>IwI │>>IwI ▼",
|
||||
];
|
||||
|
||||
const SCROLLED_STATE_REPR: &str = r#"{
|
||||
"list_state": {
|
||||
"offset": 4,
|
||||
"selected": 8
|
||||
},
|
||||
"table_state": {
|
||||
"offset": 4,
|
||||
"selected": 8
|
||||
},
|
||||
"scrollbar_state": {
|
||||
"content_length": 10,
|
||||
"position": 8,
|
||||
"viewport_content_length": 0
|
||||
}
|
||||
}"#;
|
||||
|
||||
#[test]
|
||||
fn scrolled_state_serialize() {
|
||||
let mut state = AppState::default();
|
||||
state.select(8);
|
||||
|
||||
let expected = Buffer::with_lines(SCROLLED_STATE_BUFFER.to_vec());
|
||||
assert_buffer(&mut state, &expected);
|
||||
|
||||
let state = serde_json::to_string_pretty(&state).unwrap();
|
||||
assert_eq!(state, SCROLLED_STATE_REPR);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn scrolled_state_deserialize() {
|
||||
let expected = Buffer::with_lines(SCROLLED_STATE_BUFFER.to_vec());
|
||||
let mut state: AppState = serde_json::from_str(SCROLLED_STATE_REPR).unwrap();
|
||||
assert_buffer(&mut state, &expected);
|
||||
}
|
||||
@@ -50,6 +50,31 @@ fn terminal_draw_returns_the_completed_frame() -> Result<(), Box<dyn Error>> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn terminal_draw_increments_frame_count() -> Result<(), Box<dyn Error>> {
|
||||
let backend = TestBackend::new(10, 10);
|
||||
let mut terminal = Terminal::new(backend)?;
|
||||
let frame = terminal.draw(|f| {
|
||||
assert_eq!(f.count(), 0);
|
||||
let paragraph = Paragraph::new("Test");
|
||||
f.render_widget(paragraph, f.size());
|
||||
})?;
|
||||
assert_eq!(frame.count, 0);
|
||||
let frame = terminal.draw(|f| {
|
||||
assert_eq!(f.count(), 1);
|
||||
let paragraph = Paragraph::new("test");
|
||||
f.render_widget(paragraph, f.size());
|
||||
})?;
|
||||
assert_eq!(frame.count, 1);
|
||||
let frame = terminal.draw(|f| {
|
||||
assert_eq!(f.count(), 2);
|
||||
let paragraph = Paragraph::new("test");
|
||||
f.render_widget(paragraph, f.size());
|
||||
})?;
|
||||
assert_eq!(frame.count, 2);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn terminal_insert_before_moves_viewport() -> Result<(), Box<dyn Error>> {
|
||||
// When we have a terminal with 5 lines, and a single line viewport, if we insert a
|
||||
|
||||
2
tests/widgets_table.rs
Normal file → Executable file
2
tests/widgets_table.rs
Normal file → Executable file
@@ -849,7 +849,7 @@ fn widgets_table_should_render_even_if_empty() {
|
||||
.draw(|f| {
|
||||
let size = f.size();
|
||||
let table = Table::new(
|
||||
vec![],
|
||||
Vec::<Row>::new(),
|
||||
[
|
||||
Constraint::Length(6),
|
||||
Constraint::Length(6),
|
||||
|
||||
@@ -4,7 +4,6 @@ use ratatui::{
|
||||
layout::Rect,
|
||||
style::{Style, Stylize},
|
||||
symbols,
|
||||
text::Line,
|
||||
widgets::Tabs,
|
||||
Terminal,
|
||||
};
|
||||
@@ -15,7 +14,7 @@ fn widgets_tabs_should_not_panic_on_narrow_areas() {
|
||||
let mut terminal = Terminal::new(backend).unwrap();
|
||||
terminal
|
||||
.draw(|f| {
|
||||
let tabs = Tabs::new(["Tab1", "Tab2"].iter().cloned().map(Line::from).collect());
|
||||
let tabs = Tabs::new(["Tab1", "Tab2"]);
|
||||
f.render_widget(
|
||||
tabs,
|
||||
Rect {
|
||||
@@ -37,7 +36,7 @@ fn widgets_tabs_should_truncate_the_last_item() {
|
||||
let mut terminal = Terminal::new(backend).unwrap();
|
||||
terminal
|
||||
.draw(|f| {
|
||||
let tabs = Tabs::new(["Tab1", "Tab2"].iter().cloned().map(Line::from).collect());
|
||||
let tabs = Tabs::new(["Tab1", "Tab2"]);
|
||||
f.render_widget(
|
||||
tabs,
|
||||
Rect {
|
||||
|
||||
Reference in New Issue
Block a user