OSUI v0.0.9

This commit is contained in:
2025-01-19 23:16:52 +01:00
parent 96fbf15a3c
commit 8fa9506df0
13 changed files with 151 additions and 434 deletions
+7
View File
@@ -0,0 +1,7 @@
kleo-dev:
name: Leo
title: Creator of OSUI
url: https://github.com/kleo-dev
image_url: https://github.com/kleo-dev.png
socials:
github: kleo-dev
+23
View File
@@ -0,0 +1,23 @@
---
title: Releasing OSUI v0.0.9
description: A new upcoming version of OSUI will come out. Let's re-write it.
slug: welcome-docusaurus-v2
authors:
- kleo-dev
---
Why would i bother re-writing a TUI library? Well there was a LOT of things wrong with the old version of OSUI. It had bugs and lacks performance. v0.0.9 fixes all of those and hopefully we can achieve a better future for OSUI. With that being said. Let's get into what i plan on doing.
## ⚙️ OSUI Engine
OSUI v0.0.9 Comes with a engine that works under the hood and can be manipulated to match your needs. Here are a few examples:
- Game engine
- Fluid simulation
- Velocity
This may seem like a gimmick but it's essential to provide features only when needed and prioritize performance to extend reliability. [Read more](/docs/next/engine)
## ⚡️ Improvements
- 📌 Reliable
- 🌿 Minimal
- 🚀 Fast
- 📚 Better documentation (soon)
- 🧑🏻‍💻 Better codebase
+40
View File
@@ -0,0 +1,40 @@
---
title: Engine
slug: /engine
---
The OSUI engine is what goes on under the hood. You might need this on special ocasions (Game engine, Custom animation, Physics, etc) because it's easier to manipulate. Here's an example of an element moving with a velocity of 50:
```rust
use osui::prelude::*;
fn main() -> Result<()> {
let mut con = console::init(true)?;
let velocity = 50;
let mut position = use_state(0);
loop {
con.draw(app(*position), None)?;
std::thread::sleep(std::time::Duration::from_millis(1000 / velocity));
position += 1;
if position + 13 > con.size().0 {
break;
}
}
con.end()
}
pub fn app(pos: u16) -> Element {
std::sync::Arc::new(move |frame, _event| -> Result<()> {
frame.draw(
&"Hello, World!",
Area {
x: Pos::Num(pos),
..Default::default()
},
)?;
Ok(())
})
}
```
+24 -21
View File
@@ -4,48 +4,51 @@ slug: /
--- ---
## Installation ## Installation
On a cargo project run On a cargo project run
```bash ```bash
cargo add osui cargo add osui
``` ```
## Simple app ## Hello world
```rust title='src/main.rs' ```rust title='src/main.rs'
use osui::prelude::*; use osui::prelude::*;
fn main() { fn main() -> Result<()> {
launch!(App); let mut con = console::init(true)?;
con.run(app())?;
con.end()
} }
#[component] pub fn app() -> Element {
fn App() -> Element {
rsx! { rsx! {
text { "Hello, World!" } "Hello, World!"
} }
} }
``` ```
## A slightly more advanced app (counter) ## Counter
This app uses state management and a function using the state as a dependent
```rust title='src/main.rs' ```rust title='src/main.rs'
use osui::prelude::*; use osui::prelude::*;
fn main() { fn main() -> Result<()> {
launch!(App); let mut con = console::init(true)?;
con.run(app())?;
con.end()
} }
#[component] pub fn app() -> Element {
fn App() -> Element { let count = use_state(0);
let count = State::new(0);
rsx! { rsx! {
button { button { on_click: move |_| count+=1, "{count}" }
on_click: fn(_, _, _) @count {
count += 1;
},
"The current count is: {count}"
}
} }
} }
``` ```
-129
View File
@@ -1,129 +0,0 @@
---
title: RSX
---
This macro is the recommended way to describe a ui, it is a div that holds multiple elements
```rust
#[component]
fn App() -> Element {
rsx! {
button { "click me" }
text { "This is some text" }
}
}
```
> :::info `rsx!` is really just a div, so you can just do something like
> ```rust
> rsx! {
> id: "root", class: "root",
>
> button { "click me" }
> text { "This is some text" }
> }
> ```
## Child values
If you want to add more children to values then just simply express it like a `rsx!`
```rust
let x = 69;
rsx! {
div {
text { "the number is {x}, Nice!" }
}
}
```
## Formatted text
```rust
let x = 69;
rsx! {
text { "the number is {x}, Nice!" }
}
```
> :::info You can also do expressions after the string
```rust
text { "the number is {}, Nice!", x }
```
## For loops
```rust
rsx! {
for (i in 0..5) { // () are required
text { "{i}" }
}
}
```
## Attribute
You can change the element's struct fields by just providing some attributes before the children
```rust
rsx! {
text { class: "my_text" }
}
```
## Handler functions
Instead of closures which are tricky to work with on structs, We use `Handler`, It's basically a closure wrapped with a `Arc<Mutex<T>>`
```rust
rsx! {
button {
on_click: fn(btn: &mut Button, event, document) {
// do something
}
}
}
```
## Handler functions (with dependents)
If you have a `State<T>` and want to use it, you have to put a @ before the code block like this
```rust
let count = State::new();
rsx! {
button {
on_click: fn(btn: &mut Button, event, document) @count {
let count = count.use_state(); // locks count so it can be used
},
"Current count: {count}"
}
}
```
> :::info you can add multiple decedents by separating them via `,` like: @var1, var2, var3
## Static text
If your text doesn't use variables that will change you can put `static` right before the text to signal that it's static.
```rust
let count = 69; // count won't change since it's not mutable
rsx! {
text {
static "Current count: {count}"
}
}
```
## Instructions
Add an instruction by putting a `@` before it, like this:
```rust
rsx! {
@SetStyle(css! { // the SetStyle instruction
"title": {
color: Green,
}
})
text { class: "title", static "Hello world!" }
}
```
# Ghost elements
With a `div` you can use tab (or shift+tab) to go through components, But sometimes an element doesn't really do anything, So to skip over the element you can use the ghost syntax `%`. This makes it so that the element is not selectable.
```rust
rsx! {
%text { "This is a ghost title!!!!" }
button { "Click me!" }
}
-48
View File
@@ -1,48 +0,0 @@
---
title: Handler
---
A `Handler` is a closure wrapper. Due to how closures work, they aren't the best to work with on structs (in this case: elements). So to fix this we use a `Handler` which is a wrapper for the closure, Then you can safely clone and use it without any problems (in which a normal closure would fail at)
## Examples
```rust
Handler::new(|btn: &mut Button, event, document| {
// do something
})
```
### Recommended way
```rust
rsx! {
button {
// No need for Handler::new
on_click: fn(btn: &mut Button, event, document) {
// do something
}
}
}
```
### With dependents
If you have a `State<T>` and want to use it in a `fn()`, Pub a @ before the code block like this
```rust
#[component]
pub fn App() -> Element {
let count = State::new(0);
rsx! {
button {
on_click: fn(_, _, _) @count {
count += 1;
},
"The current count is: {count}"
}
}
}
```
### How to call a handler
```rust
my_handler.clone().call();
```
> :::info you can add multiple decedents by separating them via `,` like: @var1, var2, var3
> :::info `fn() {}` is a part of the OSUI macro `rsx!`. In rust you would normally use `|| {}`
-24
View File
@@ -1,24 +0,0 @@
---
title: Component
---
A `Component` is a function but in the backend it's a struct. It's a struct because of named parameters. It can be defiend using the `#[component]` attribute.
```rust
#[component]
pub fn App() -> Element {
rsx! {
User { name: "leo", age: 15 }
}
}
#[component]
pub fn User<'a>(name: &'a str, age: u8) {
rsx! {
text { static "Welcome {}! You are {} years old!", self.name, self.age }
}
}
```
If you're wondering why `User` doesn't have a return type, it's because the `#[component]` attribute sets it automatically, You can also use a custom return type.
The `text` is static because self.name is a reference, dynamic text needs the lifetimes to be `'static`.
-39
View File
@@ -1,39 +0,0 @@
---
title: CSS
---
Along with the `Css` type, This macro provides styling for multiple elements by their class name.
## Example
In this case we will make a button with the classname `my_btn`. And set `styling`
```rust
#[component]
fn App() -> Element {
rsx! {
@SetStyle(css! {
blue-outline {
outline: true,
outline_color: Blue,
}
red {
color: Red,
}
green-hover: "hover" {
color: Green,
}
})
button { class: "red blue-outline green-hover", "Click me!" }
}
}
```
## `hover`
The `hover` state is on every element but only if it's focused/hovered.
```rust
"my_btn": "hover" {
color: Green,
}
```
-20
View File
@@ -1,20 +0,0 @@
---
title: Style
---
Like `css!`, `style!` is a way to style a element. But unlike `css!`, `style!` is only meant to style a single element
```rust
rsx! {
button {
style: style! {
color: Red,
"clicked" { // when the button state is 'clicked'
color: Blue,
}
},
"click me!"
}
}
```
-28
View File
@@ -1,28 +0,0 @@
---
title: Document
---
The `Document` holds the root element and it renders and passes events to the `Element`. It's important for updating the UI.
## Example
```rust
fn(_, _, document) {
if let Some(my_text) = document.get_element_by_id::<Text>("my_text") {
my_text.children.set_text("Updated!");
}
}
```
## Methods
### `exit()`
Exits the program
### `restart()`
Restarts the program
### `get_element_by_id<T>(id: &str) -> Option<&mut Box<T>>`
Retrieves a mutable reference to a boxed element of type T by its string identifier, returning None if no such element exists.
> :::info Please make sure that the type of the element is correctly matched to the element of that id
### `get_element_by_id_raw(id: &str) -> Option<&mut Element>`
> :::warning Not recommended to use this function, Use `get_element_by_id` instead
Retrieves a mutable reference to a boxed element by its string identifier, returning None if no such element exists
### `render()`
Renders/reloads the screen, useful when a element updates
-54
View File
@@ -1,54 +0,0 @@
---
title: Element
---
A element is a very important part of a UI library, It's what makes it possible.
`Element` is a type alias of `Box<dyn ElementWidget>`. It makes the code look cleaner.
# ElementWidget
`ElementWidget` is a trait that defines the Elements and it's rendering / event updates.
## Methods
### `render(&self, focused: bool) -> Option<RenderResult>`
- **required**
- This function renders the element
### `event(&mut self, event: Event, document: &Document)`
- **optional**
- This function updates the element when there is a event
### `event(&mut self, document: &mut Document)`
- **optional**
- This function runs when the app first runs. It helps with element initialization after the `rsx!` stage.
# ElementCore
`ElementCore` is a trait that will automatically be implemented by the `osui_element::element` proc-macro. All of it's functions are used by OSUI.
## `element` proc-macro
This macro adds the essential fields and functions for a `ElementCore` structure.
```rust
use osui_element::element;
#[element]
#[derive(Default, Debug)]
struct MyElement {}
```
## `elem_fn` proc-macro
This macro makes a function that returns a `Box<T>` of which T is the default of `MyElement`
```rust
use osui_element::{element, elem_fn};
#[element]
#[elem_fn]
#[derive(Default, Debug)]
struct MyElement {}
```
>:::info
>You can also define a function for the element manually:
>```rust
>pub fn my_element() -> Box<MyElement> {
> Box::new(MyElement::default())
>}
>```
-11
View File
@@ -1,11 +0,0 @@
---
title: Writer
---
The `Writer` is what makes OSUI efficient and it's magic. `Writer` is used on the `Element::render` function. It get's access to the `Style` and gets a absolute position and ansi coloring, Then it prints and adjusts to what is being written.
## Functions
### `write(&mut self, s: &str)`
This function simply writes s to the screen depending on the absolute positioning.
### `new_frame(&mut self) -> Frame`
This function creates a frame depending on the values. Use this you need to render elements.
+57 -60
View File
@@ -1,48 +1,45 @@
import {themes as prismThemes} from 'prism-react-renderer'; import { themes as prismThemes } from "prism-react-renderer";
import type {Config} from '@docusaurus/types'; import type { Config } from "@docusaurus/types";
import type * as Preset from '@docusaurus/preset-classic'; import type * as Preset from "@docusaurus/preset-classic";
const config: Config = { const config: Config = {
title: 'OSUI', title: "OSUI",
tagline: 'Style your terminal, The creative way', tagline: "Style your terminal, The creative way",
favicon: 'img/favicon.ico', favicon: "img/favicon.ico",
url: 'https://osui.netlify.app', url: "https://osui.netlify.app",
baseUrl: '/', baseUrl: "/",
organizationName: 'osui-rs', organizationName: "osui-rs",
projectName: 'osui', projectName: "osui",
onBrokenLinks: 'throw', onBrokenLinks: "throw",
onBrokenMarkdownLinks: 'warn', onBrokenMarkdownLinks: "warn",
i18n: { i18n: {
defaultLocale: 'en', defaultLocale: "en",
locales: ['en'], locales: ["en"],
}, },
plugins: [require.resolve('docusaurus-lunr-search')], plugins: [require.resolve("docusaurus-lunr-search")],
presets: [ presets: [
[ [
'classic', "classic",
{ {
docs: { docs: {
sidebarPath: './sidebars.json', sidebarPath: "./sidebars.json",
editUrl: editUrl: "https://github.com/osui-rs/docs/tree/master/",
'https://github.com/osui-rs/docs/tree/master/', },
blog: {
showReadingTime: true,
feedOptions: {
type: ["rss", "atom"],
xslt: true,
},
editUrl: "https://github.com/osui-rs/docs/",
onInlineTags: "warn",
onInlineAuthors: "warn",
onUntruncatedBlogPosts: "warn",
}, },
blog: false,
// blog: {
// showReadingTime: true,
// feedOptions: {
// type: ['rss', 'atom'],
// xslt: true,
// },
// editUrl:
// 'https://github.com/osui-rs/docs/',
// onInlineTags: 'warn',
// onInlineAuthors: 'warn',
// onUntruncatedBlogPosts: 'warn',
// },
theme: { theme: {
customCss: './src/css/custom.css', customCss: "./src/css/custom.css",
}, },
} satisfies Preset.Options, } satisfies Preset.Options,
], ],
@@ -50,27 +47,27 @@ const config: Config = {
themeConfig: { themeConfig: {
navbar: { navbar: {
title: 'OSUI', title: "OSUI",
logo: { logo: {
alt: 'OSUI Logo', alt: "OSUI Logo",
src: 'img/osui.png', src: "img/osui.png",
}, },
items: [ items: [
{ {
type: 'docSidebar', type: "docSidebar",
sidebarId: 'docsSidebar', sidebarId: "docsSidebar",
position: 'left', position: "left",
label: 'Docs', label: "Docs",
}, },
// {to: '/blog', label: 'Blog', position: 'left'}, {to: '/blog', label: 'Blog', position: 'left'},
{ {
type: 'docsVersionDropdown', type: "docsVersionDropdown",
position: 'left', position: "left",
dropdownActiveClassDisabled: true, dropdownActiveClassDisabled: true,
}, },
{ {
href: 'https://github.com/osui-rs/osui/', href: "https://github.com/osui-rs/osui/",
position: 'right', position: "right",
html: ` html: `
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="currentColor" class="bi bi-github" viewBox="0 0 16 16"> <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="currentColor" class="bi bi-github" viewBox="0 0 16 16">
<path d="M8 0C3.58 0 0 3.58 0 8a8 8 0 0 0 5.47 7.59c.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.22 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82a7.64 7.64 0 0 1 4.01 0c1.53-1.03 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.28.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.45.55.38A8 8 0 0 0 16 8c0-4.42-3.58-8-8-8z"/> <path d="M8 0C3.58 0 0 3.58 0 8a8 8 0 0 0 5.47 7.59c.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.22 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82a7.64 7.64 0 0 1 4.01 0c1.53-1.03 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.28.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.45.55.38A8 8 0 0 0 16 8c0-4.42-3.58-8-8-8z"/>
@@ -80,40 +77,40 @@ const config: Config = {
], ],
}, },
footer: { footer: {
style: 'dark', style: "dark",
links: [ links: [
{ {
title: 'Docs', title: "Docs",
items: [ items: [
{ {
label: 'Installation', label: "Installation",
to: '/docs/', to: "/docs/",
}, },
], ],
}, },
{ {
title: 'Community', title: "Community",
items: [ items: [
{ {
label: 'Discord', label: "Discord",
href: 'https://discordapp.com/invite/jqc9dR6kBZ', href: "https://discordapp.com/invite/jqc9dR6kBZ",
}, },
{ {
label: 'GitHub', label: "GitHub",
href: 'https://github.com/osui-rs/osui/', href: "https://github.com/osui-rs/osui/",
}, },
], ],
}, },
{ {
title: 'Resources', title: "Resources",
items: [ items: [
{ {
label: 'Crossterm', label: "Crossterm",
href: 'https://github.com/crossterm-rs/crossterm', href: "https://github.com/crossterm-rs/crossterm",
}, },
{ {
label: 'Rust-lang', label: "Rust-lang",
href: 'https://rust-lang.org/', href: "https://rust-lang.org/",
}, },
], ],
}, },