Merge branch 'master' of https://github.com/Demonthos/rink
This commit is contained in:
commit
dd60c9ce3c
8 files changed
+103
-108
No files matched your search
@@ -1,12 +1,67 @@
|
|||||||
# Rink: Like "Ink" but for Rust and Dioxus
|
<div align="center">
|
||||||
|
<h1>Rink</h1>
|
||||||
|
<p>
|
||||||
|
<strong>Beautiful terminal user interfaces in Rust with <a href="https://dioxuslabs.com/">Dioxus </a>.</strong>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
The fastest portable TUIs in the west
|
<div align="center">
|
||||||
🔫🤠🔫
|
<!-- Crates version -->
|
||||||
🐎🔥🔥🔥
|
<a href="https://crates.io/crates/dioxus">
|
||||||
|
<img src="https://img.shields.io/crates/v/dioxus.svg?style=flat-square"
|
||||||
|
alt="Crates.io version" />
|
||||||
|
</a>
|
||||||
|
<!-- Downloads -->
|
||||||
|
<a href="https://crates.io/crates/dioxus">
|
||||||
|
<img src="https://img.shields.io/crates/d/dioxus.svg?style=flat-square"
|
||||||
|
alt="Download" />
|
||||||
|
</a>
|
||||||
|
<!-- docs -->
|
||||||
|
<a href="https://docs.rs/dioxus">
|
||||||
|
<img src="https://img.shields.io/badge/docs-latest-blue.svg?style=flat-square"
|
||||||
|
alt="docs.rs docs" />
|
||||||
|
</a>
|
||||||
|
<!-- CI -->
|
||||||
|
<a href="https://github.com/jkelleyrtp/dioxus/actions">
|
||||||
|
<img src="https://github.com/dioxuslabs/dioxus/actions/workflows/main.yml/badge.svg"
|
||||||
|
alt="CI status" />
|
||||||
|
</a>
|
||||||
|
|
||||||
Rink lets you build terminal user interfaces in Rust with [`Dioxus`](https://dioxuslabs.com/).
|
<!--Awesome -->
|
||||||
|
<a href="https://github.com/dioxuslabs/awesome-dioxus">
|
||||||
|
<img src="https://cdn.rawgit.com/sindresorhus/awesome/d7305f38d29fed78fa85652e3a63e154dd8e8829/media/badge.svg" alt="Awesome Page" />
|
||||||
|
</a>
|
||||||
|
<!-- Discord -->
|
||||||
|
<a href="https://discord.gg/XgGxMSkvUM">
|
||||||
|
<img src="https://img.shields.io/discord/899851952891002890.svg?logo=discord&style=flat-square" alt="Discord Link" />
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
You can use Html-like semantics with stylesheets, inline styles, tree hierarchy, components, and more in your [`text-based user interface (TUI)`](https://en.wikipedia.org/wiki/Text-based_user_interface) application.
|
|
||||||
|
<br/>
|
||||||
|
|
||||||
|
Leverage React-like patterns, CSS, HTML, and Rust to build beautiful, portable, terminal user interfaces with Dioxus.
|
||||||
|
|
||||||
|
```rust
|
||||||
|
fn app(cx: Scope) -> Element {
|
||||||
|
cx.render(rsx!{
|
||||||
|
div {
|
||||||
|
width: "100%",
|
||||||
|
height: "10px",
|
||||||
|
background_color: "red",
|
||||||
|
justify_content: "center",
|
||||||
|
align_items: "center",
|
||||||
|
"Hello world!"
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
## Background
|
||||||
|
|
||||||
|
You can use Html-like semantics with stylesheets, inline styles, tree hierarchy, components, and more in your [`text-based user interface (TUI)`](https://en.wikipedia.org/wiki/Text-based_user_interface) application.
|
||||||
|
|
||||||
Rink is basically a port of [Ink](https://github.com/vadimdemedes/ink) but for [`Rust`](https://www.rust-lang.org/) and [`Dioxus`](https://dioxuslabs.com/). Rink doesn't depend on Node.js or any other JavaScript runtime, so your binaries are portable and beautiful.
|
Rink is basically a port of [Ink](https://github.com/vadimdemedes/ink) but for [`Rust`](https://www.rust-lang.org/) and [`Dioxus`](https://dioxuslabs.com/). Rink doesn't depend on Node.js or any other JavaScript runtime, so your binaries are portable and beautiful.
|
||||||
|
|
||||||
@@ -17,27 +72,6 @@ Terminals can only render a subset of HTML. We support as much as we can.
|
|||||||
- **Particular frontend design**
|
- **Particular frontend design**
|
||||||
Terminals and browsers are and look different. Therefore, the same design might not be the best to cover both renderers.
|
Terminals and browsers are and look different. Therefore, the same design might not be the best to cover both renderers.
|
||||||
|
|
||||||
## Example
|
|
||||||
|
|
||||||
Let's print `Hello world!` in the center of the screen.
|
|
||||||
```rust
|
|
||||||
static App: FC<()> = |cx| {
|
|
||||||
cx.render(rsx!{
|
|
||||||
div {
|
|
||||||
width: "100%",
|
|
||||||
height: "10px",
|
|
||||||
background_color: "red",
|
|
||||||
justify_content: "center",
|
|
||||||
align_items: "center",
|
|
||||||
|
|
||||||
"Hello world!"
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
|
|
||||||
## Status
|
## Status
|
||||||
|
|
||||||
|
|||||||
@@ -7,10 +7,10 @@ fn main() {
|
|||||||
#[derive(Props, PartialEq)]
|
#[derive(Props, PartialEq)]
|
||||||
struct QuadrentProps {
|
struct QuadrentProps {
|
||||||
color: String,
|
color: String,
|
||||||
text: String
|
text: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn Quadrent(cx: Scope<QuadrentProps>) -> Element{
|
fn Quadrent(cx: Scope<QuadrentProps>) -> Element {
|
||||||
cx.render(rsx! {
|
cx.render(rsx! {
|
||||||
div {
|
div {
|
||||||
border_width: "1px",
|
border_width: "1px",
|
||||||
|
|||||||
@@ -1,8 +1,5 @@
|
|||||||
use std::cell::RefCell;
|
|
||||||
|
|
||||||
use crossterm::event::{KeyCode, KeyEvent, MouseEvent};
|
use crossterm::event::{KeyCode, KeyEvent, MouseEvent};
|
||||||
use dioxus::prelude::*;
|
use dioxus::prelude::*;
|
||||||
use rink::InputHandler;
|
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
rink::launch(app);
|
rink::launch(app);
|
||||||
|
|||||||
+2
-3
@@ -1,7 +1,6 @@
|
|||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use dioxus::{core::ElementId, prelude::*};
|
use dioxus::prelude::*;
|
||||||
use rink::TuiNode;
|
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let mut dom = VirtualDom::new(app);
|
let mut dom = VirtualDom::new(app);
|
||||||
@@ -19,7 +18,7 @@ fn main() {
|
|||||||
.compute_layout(node.layout, stretch2::geometry::Size::undefined())
|
.compute_layout(node.layout, stretch2::geometry::Size::undefined())
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
for (id, node) in nodes.drain() {
|
for (_id, node) in nodes.drain() {
|
||||||
println!("{:?}", layout.layout(node.layout));
|
println!("{:?}", layout.layout(node.layout));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+20
-21
@@ -343,7 +343,7 @@ fn apply_overflow(name: &str, value: &str, style: &mut StyleModifer) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn apply_display(name: &str, value: &str, style: &mut StyleModifer) {
|
fn apply_display(_name: &str, value: &str, style: &mut StyleModifer) {
|
||||||
use stretch2::style::Display;
|
use stretch2::style::Display;
|
||||||
style.style.display = match value {
|
style.style.display = match value {
|
||||||
"flex" => Display::Flex,
|
"flex" => Display::Flex,
|
||||||
@@ -387,29 +387,28 @@ fn apply_background(name: &str, value: &str, style: &mut StyleModifer) {
|
|||||||
"white" => style.tui_style.bg.replace(Color::White),
|
"white" => style.tui_style.bg.replace(Color::White),
|
||||||
"black" => style.tui_style.bg.replace(Color::Black),
|
"black" => style.tui_style.bg.replace(Color::Black),
|
||||||
_ => {
|
_ => {
|
||||||
if value.len() == 7{
|
if value.len() == 7 {
|
||||||
let mut values = [0, 0, 0];
|
let mut values = [0, 0, 0];
|
||||||
let mut color_ok = true;
|
let mut color_ok = true;
|
||||||
for i in 0..values.len(){
|
for i in 0..values.len() {
|
||||||
if let Ok(v) = u8::from_str_radix(&value[(1+2*i)..(1+2*(i+1))], 16){
|
if let Ok(v) =
|
||||||
|
u8::from_str_radix(&value[(1 + 2 * i)..(1 + 2 * (i + 1))], 16)
|
||||||
|
{
|
||||||
values[i] = v;
|
values[i] = v;
|
||||||
}
|
} else {
|
||||||
else{
|
|
||||||
color_ok = false;
|
color_ok = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if color_ok{
|
if color_ok {
|
||||||
let color = Color::Rgb(values[0], values[1], values[2]);
|
let color = Color::Rgb(values[0], values[1], values[2]);
|
||||||
style.tui_style.bg.replace(color)
|
style.tui_style.bg.replace(color)
|
||||||
}
|
} else {
|
||||||
else{
|
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else{
|
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
"background" => {}
|
"background" => {}
|
||||||
@@ -424,7 +423,7 @@ fn apply_background(name: &str, value: &str, style: &mut StyleModifer) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn apply_border(name: &str, value: &str, style: &mut StyleModifer) {
|
fn apply_border(name: &str, value: &str, _style: &mut StyleModifer) {
|
||||||
match name {
|
match name {
|
||||||
"border" => {}
|
"border" => {}
|
||||||
"border-bottom" => {}
|
"border-bottom" => {}
|
||||||
@@ -459,7 +458,7 @@ fn apply_border(name: &str, value: &str, style: &mut StyleModifer) {
|
|||||||
"border-top-style" => {}
|
"border-top-style" => {}
|
||||||
"border-top-width" => {}
|
"border-top-width" => {}
|
||||||
"border-width" => {
|
"border-width" => {
|
||||||
if let Ok(px) = value.trim_end_matches("px").parse::<f32>() {
|
if let Ok(_px) = value.trim_end_matches("px").parse::<f32>() {
|
||||||
// tuistyle = px;
|
// tuistyle = px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -467,7 +466,7 @@ fn apply_border(name: &str, value: &str, style: &mut StyleModifer) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn apply_animation(name: &str, value: &str, style: &mut StyleModifer) {
|
fn apply_animation(name: &str, _value: &str, _style: &mut StyleModifer) {
|
||||||
match name {
|
match name {
|
||||||
"animation" => {}
|
"animation" => {}
|
||||||
"animation-delay" => {}
|
"animation-delay" => {}
|
||||||
@@ -482,7 +481,7 @@ fn apply_animation(name: &str, value: &str, style: &mut StyleModifer) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn apply_column(name: &str, value: &str, style: &mut StyleModifer) {
|
fn apply_column(name: &str, _value: &str, _style: &mut StyleModifer) {
|
||||||
match name {
|
match name {
|
||||||
"column-count" => {}
|
"column-count" => {}
|
||||||
"column-fill" => {}
|
"column-fill" => {}
|
||||||
@@ -551,7 +550,7 @@ fn apply_flex(name: &str, value: &str, style: &mut StyleModifer) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn apply_font(name: &str, value: &str, style: &mut StyleModifer) {
|
fn apply_font(_name: &str, _value: &str, _style: &mut StyleModifer) {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -588,15 +587,15 @@ fn apply_padding(name: &str, value: &str, style: &mut StyleModifer) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn apply_text(name: &str, value: &str, style: &mut StyleModifer) {
|
fn apply_text(_name: &str, _value: &str, _style: &mut StyleModifer) {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn apply_transform(name: &str, value: &str, style: &mut StyleModifer) {
|
fn apply_transform(_name: &str, _value: &str, _style: &mut StyleModifer) {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn apply_transition(name: &str, value: &str, style: &mut StyleModifer) {
|
fn apply_transition(_name: &str, _value: &str, _style: &mut StyleModifer) {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -640,7 +639,7 @@ fn apply_align(name: &str, value: &str, style: &mut StyleModifer) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn apply_size(name: &str, value: &str, style: &mut StyleModifer) {
|
pub fn apply_size(_name: &str, _value: &str, _style: &mut StyleModifer) {
|
||||||
//
|
//
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+6
-18
@@ -1,24 +1,12 @@
|
|||||||
use anyhow::Result;
|
use crossterm::event::{Event as TermEvent, KeyEvent, MouseEvent};
|
||||||
use crossterm::{
|
use dioxus::core::*;
|
||||||
event::{
|
use dioxus::prelude::Props;
|
||||||
DisableMouseCapture, EnableMouseCapture, Event as TermEvent, KeyCode, KeyEvent, MouseEvent,
|
use futures::{channel::mpsc::UnboundedReceiver, StreamExt};
|
||||||
},
|
|
||||||
execute,
|
|
||||||
terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen},
|
|
||||||
};
|
|
||||||
use dioxus::{core::exports::futures_channel::mpsc::unbounded, prelude::Props};
|
|
||||||
use dioxus::{core::*, prelude::*};
|
|
||||||
use futures::{channel::mpsc::UnboundedReceiver, future::Either, pin_mut, StreamExt};
|
|
||||||
use std::{
|
use std::{
|
||||||
cell::{Cell, RefCell},
|
cell::{Cell, RefCell},
|
||||||
collections::HashMap,
|
collections::HashMap,
|
||||||
io,
|
|
||||||
rc::Rc,
|
rc::Rc,
|
||||||
time::{Duration, Instant},
|
|
||||||
};
|
};
|
||||||
use stretch2::{prelude::Size, Stretch};
|
|
||||||
use tokio::sync::broadcast::Receiver;
|
|
||||||
use tui::{backend::CrosstermBackend, style::Style as TuiStyle, Terminal};
|
|
||||||
|
|
||||||
pub struct RinkContext {
|
pub struct RinkContext {
|
||||||
last_event: Rc<Cell<Option<TermEvent>>>,
|
last_event: Rc<Cell<Option<TermEvent>>>,
|
||||||
@@ -44,8 +32,8 @@ impl RinkContext {
|
|||||||
});
|
});
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
last_event: last_event,
|
last_event,
|
||||||
subscribers: subscribers,
|
subscribers,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+10
-16
@@ -1,21 +1,15 @@
|
|||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use crossterm::{
|
use crossterm::{
|
||||||
event::{DisableMouseCapture, EnableMouseCapture, Event as TermEvent, KeyCode, KeyEvent},
|
event::{DisableMouseCapture, EnableMouseCapture, Event as TermEvent, KeyCode, KeyModifiers},
|
||||||
execute,
|
execute,
|
||||||
terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen},
|
terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen},
|
||||||
};
|
};
|
||||||
use dioxus::{core::exports::futures_channel::mpsc::unbounded, prelude::Props};
|
use dioxus::core::exports::futures_channel::mpsc::unbounded;
|
||||||
use dioxus::{core::*, prelude::*};
|
use dioxus::core::*;
|
||||||
use futures::{
|
use futures::{channel::mpsc::UnboundedSender, pin_mut, StreamExt};
|
||||||
channel::mpsc::{UnboundedReceiver, UnboundedSender},
|
|
||||||
future::Either,
|
|
||||||
pin_mut, StreamExt,
|
|
||||||
};
|
|
||||||
use std::{
|
use std::{
|
||||||
cell::Cell,
|
|
||||||
collections::HashMap,
|
collections::HashMap,
|
||||||
io,
|
io,
|
||||||
rc::Rc,
|
|
||||||
time::{Duration, Instant},
|
time::{Duration, Instant},
|
||||||
};
|
};
|
||||||
use stretch2::{prelude::Size, Stretch};
|
use stretch2::{prelude::Size, Stretch};
|
||||||
@@ -137,17 +131,17 @@ pub fn render_vdom(vdom: &mut VirtualDom, ctx: UnboundedSender<TermEvent>) -> Re
|
|||||||
pin_mut!(wait);
|
pin_mut!(wait);
|
||||||
|
|
||||||
match select(wait, rx.next()).await {
|
match select(wait, rx.next()).await {
|
||||||
Either::Left((a, b)) => {
|
Either::Left((_a, _b)) => {
|
||||||
//
|
//
|
||||||
}
|
}
|
||||||
Either::Right((evt, o)) => {
|
Either::Right((evt, _o)) => {
|
||||||
//
|
|
||||||
match evt.as_ref().unwrap() {
|
match evt.as_ref().unwrap() {
|
||||||
InputEvent::UserInput(event) => match event {
|
InputEvent::UserInput(event) => match event {
|
||||||
TermEvent::Key(key) => {
|
TermEvent::Key(key) => {
|
||||||
match key.code {
|
if matches!(key.code, KeyCode::Char('c'))
|
||||||
KeyCode::Char('q') => break,
|
&& key.modifiers.contains(KeyModifiers::CONTROL)
|
||||||
_ => {} // handle event
|
{
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
TermEvent::Resize(_, _) | TermEvent::Mouse(_) => {}
|
TermEvent::Resize(_, _) | TermEvent::Mouse(_) => {}
|
||||||
|
|||||||
+2
-18
@@ -1,22 +1,8 @@
|
|||||||
use anyhow::Result;
|
|
||||||
use crossterm::{
|
|
||||||
event,
|
|
||||||
event::{DisableMouseCapture, EnableMouseCapture, Event as TermEvent, KeyCode, KeyEvent},
|
|
||||||
execute,
|
|
||||||
terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen},
|
|
||||||
};
|
|
||||||
use dioxus::core::*;
|
use dioxus::core::*;
|
||||||
use std::{
|
use std::{collections::HashMap, io::Stdout};
|
||||||
collections::HashMap,
|
|
||||||
io::{self, Stdout},
|
|
||||||
sync::mpsc,
|
|
||||||
thread,
|
|
||||||
time::{Duration, Instant},
|
|
||||||
};
|
|
||||||
use stretch2::{
|
use stretch2::{
|
||||||
geometry::Point,
|
geometry::Point,
|
||||||
prelude::{Layout, Size},
|
prelude::{Layout, Size},
|
||||||
style::Style as StretchStyle,
|
|
||||||
Stretch,
|
Stretch,
|
||||||
};
|
};
|
||||||
use tui::{
|
use tui::{
|
||||||
@@ -24,9 +10,7 @@ use tui::{
|
|||||||
buffer::Buffer,
|
buffer::Buffer,
|
||||||
layout::Rect,
|
layout::Rect,
|
||||||
style::Style as TuiStyle,
|
style::Style as TuiStyle,
|
||||||
text::Span,
|
widgets::{Block, Widget},
|
||||||
widgets::{canvas::Label, Block, BorderType, Borders, Widget},
|
|
||||||
Terminal,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::TuiNode;
|
use crate::TuiNode;
|
||||||
|
|||||||
Reference in new issue
Block a user