mirror of
https://github.com/DioxusLabs/dioxus
synced 2025-02-17 14:18:27 +00:00
Merge branch 'master' of https://github.com/Demonthos/rink
This commit is contained in:
commit
dd60c9ce3c
8 changed files with 103 additions and 108 deletions
88
README.md
88
README.md
|
@ -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!"
|
||||
}
|
||||
})
|
||||
}
|
||||
```
|
||||
|
||||
![demo app](examples/example.png)
|
||||
|
||||
## 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.
|
||||
|
||||
|
@ -17,27 +72,6 @@ Terminals can only render a subset of HTML. We support as much as we can.
|
|||
- **Particular frontend design**
|
||||
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!"
|
||||
}
|
||||
})
|
||||
}
|
||||
```
|
||||
|
||||
![demo app](examples/example.png)
|
||||
|
||||
|
||||
## Status
|
||||
|
||||
|
|
|
@ -7,10 +7,10 @@ fn main() {
|
|||
#[derive(Props, PartialEq)]
|
||||
struct QuadrentProps {
|
||||
color: String,
|
||||
text: String
|
||||
text: String,
|
||||
}
|
||||
|
||||
fn Quadrent(cx: Scope<QuadrentProps>) -> Element{
|
||||
fn Quadrent(cx: Scope<QuadrentProps>) -> Element {
|
||||
cx.render(rsx! {
|
||||
div {
|
||||
border_width: "1px",
|
||||
|
|
|
@ -1,8 +1,5 @@
|
|||
use std::cell::RefCell;
|
||||
|
||||
use crossterm::event::{KeyCode, KeyEvent, MouseEvent};
|
||||
use dioxus::prelude::*;
|
||||
use rink::InputHandler;
|
||||
|
||||
fn main() {
|
||||
rink::launch(app);
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
use std::collections::HashMap;
|
||||
|
||||
use dioxus::{core::ElementId, prelude::*};
|
||||
use rink::TuiNode;
|
||||
use dioxus::prelude::*;
|
||||
|
||||
fn main() {
|
||||
let mut dom = VirtualDom::new(app);
|
||||
|
@ -19,7 +18,7 @@ fn main() {
|
|||
.compute_layout(node.layout, stretch2::geometry::Size::undefined())
|
||||
.unwrap();
|
||||
|
||||
for (id, node) in nodes.drain() {
|
||||
for (_id, node) in nodes.drain() {
|
||||
println!("{:?}", layout.layout(node.layout));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
style.style.display = match value {
|
||||
"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),
|
||||
"black" => style.tui_style.bg.replace(Color::Black),
|
||||
_ => {
|
||||
if value.len() == 7{
|
||||
if value.len() == 7 {
|
||||
let mut values = [0, 0, 0];
|
||||
let mut color_ok = true;
|
||||
for i in 0..values.len(){
|
||||
if let Ok(v) = u8::from_str_radix(&value[(1+2*i)..(1+2*(i+1))], 16){
|
||||
for i in 0..values.len() {
|
||||
if let Ok(v) =
|
||||
u8::from_str_radix(&value[(1 + 2 * i)..(1 + 2 * (i + 1))], 16)
|
||||
{
|
||||
values[i] = v;
|
||||
}
|
||||
else{
|
||||
} else {
|
||||
color_ok = false;
|
||||
}
|
||||
}
|
||||
if color_ok{
|
||||
if color_ok {
|
||||
let color = Color::Rgb(values[0], values[1], values[2]);
|
||||
style.tui_style.bg.replace(color)
|
||||
}
|
||||
else{
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
else{
|
||||
} else {
|
||||
None
|
||||
}
|
||||
},
|
||||
}
|
||||
};
|
||||
}
|
||||
"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 {
|
||||
"border" => {}
|
||||
"border-bottom" => {}
|
||||
|
@ -459,7 +458,7 @@ fn apply_border(name: &str, value: &str, style: &mut StyleModifer) {
|
|||
"border-top-style" => {}
|
||||
"border-top-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;
|
||||
}
|
||||
}
|
||||
|
@ -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 {
|
||||
"animation" => {}
|
||||
"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 {
|
||||
"column-count" => {}
|
||||
"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!()
|
||||
}
|
||||
|
||||
|
@ -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!()
|
||||
}
|
||||
|
||||
fn apply_transform(name: &str, value: &str, style: &mut StyleModifer) {
|
||||
fn apply_transform(_name: &str, _value: &str, _style: &mut StyleModifer) {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn apply_transition(name: &str, value: &str, style: &mut StyleModifer) {
|
||||
fn apply_transition(_name: &str, _value: &str, _style: &mut StyleModifer) {
|
||||
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) {
|
||||
//
|
||||
}
|
||||
|
||||
|
|
24
src/hooks.rs
24
src/hooks.rs
|
@ -1,24 +1,12 @@
|
|||
use anyhow::Result;
|
||||
use crossterm::{
|
||||
event::{
|
||||
DisableMouseCapture, EnableMouseCapture, Event as TermEvent, KeyCode, KeyEvent, MouseEvent,
|
||||
},
|
||||
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 crossterm::event::{Event as TermEvent, KeyEvent, MouseEvent};
|
||||
use dioxus::core::*;
|
||||
use dioxus::prelude::Props;
|
||||
use futures::{channel::mpsc::UnboundedReceiver, StreamExt};
|
||||
use std::{
|
||||
cell::{Cell, RefCell},
|
||||
collections::HashMap,
|
||||
io,
|
||||
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 {
|
||||
last_event: Rc<Cell<Option<TermEvent>>>,
|
||||
|
@ -44,8 +32,8 @@ impl RinkContext {
|
|||
});
|
||||
|
||||
Self {
|
||||
last_event: last_event,
|
||||
subscribers: subscribers,
|
||||
last_event,
|
||||
subscribers,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
26
src/lib.rs
26
src/lib.rs
|
@ -1,21 +1,15 @@
|
|||
use anyhow::Result;
|
||||
use crossterm::{
|
||||
event::{DisableMouseCapture, EnableMouseCapture, Event as TermEvent, KeyCode, KeyEvent},
|
||||
event::{DisableMouseCapture, EnableMouseCapture, Event as TermEvent, KeyCode, KeyModifiers},
|
||||
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, UnboundedSender},
|
||||
future::Either,
|
||||
pin_mut, StreamExt,
|
||||
};
|
||||
use dioxus::core::exports::futures_channel::mpsc::unbounded;
|
||||
use dioxus::core::*;
|
||||
use futures::{channel::mpsc::UnboundedSender, pin_mut, StreamExt};
|
||||
use std::{
|
||||
cell::Cell,
|
||||
collections::HashMap,
|
||||
io,
|
||||
rc::Rc,
|
||||
time::{Duration, Instant},
|
||||
};
|
||||
use stretch2::{prelude::Size, Stretch};
|
||||
|
@ -137,17 +131,17 @@ pub fn render_vdom(vdom: &mut VirtualDom, ctx: UnboundedSender<TermEvent>) -> Re
|
|||
pin_mut!(wait);
|
||||
|
||||
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() {
|
||||
InputEvent::UserInput(event) => match event {
|
||||
TermEvent::Key(key) => {
|
||||
match key.code {
|
||||
KeyCode::Char('q') => break,
|
||||
_ => {} // handle event
|
||||
if matches!(key.code, KeyCode::Char('c'))
|
||||
&& key.modifiers.contains(KeyModifiers::CONTROL)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
TermEvent::Resize(_, _) | TermEvent::Mouse(_) => {}
|
||||
|
|
|
@ -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 std::{
|
||||
collections::HashMap,
|
||||
io::{self, Stdout},
|
||||
sync::mpsc,
|
||||
thread,
|
||||
time::{Duration, Instant},
|
||||
};
|
||||
use std::{collections::HashMap, io::Stdout};
|
||||
use stretch2::{
|
||||
geometry::Point,
|
||||
prelude::{Layout, Size},
|
||||
style::Style as StretchStyle,
|
||||
Stretch,
|
||||
};
|
||||
use tui::{
|
||||
|
@ -24,9 +10,7 @@ use tui::{
|
|||
buffer::Buffer,
|
||||
layout::Rect,
|
||||
style::Style as TuiStyle,
|
||||
text::Span,
|
||||
widgets::{canvas::Label, Block, BorderType, Borders, Widget},
|
||||
Terminal,
|
||||
widgets::{Block, Widget},
|
||||
};
|
||||
|
||||
use crate::TuiNode;
|
||||
|
|
Loading…
Add table
Reference in a new issue