Skip to content

Commit a2ed297

Browse files
authored
Merge pull request #2 from feijihe/main
feat: i18n
2 parents 4fa5cea + 2b301ef commit a2ed297

102 files changed

Lines changed: 2280 additions & 88 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

astro.config.mjs

Lines changed: 203 additions & 50 deletions
Large diffs are not rendered by default.
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
---
2+
title: Animation
3+
---
4+
5+
## Introduction
6+
7+
Deft supports animation, similar to CSS animations.
8+
9+
## Define Animation
10+
11+
Unlike the @keyframes in Web, in Deft, you need to define the animation by `animation_create`, currently only the `transform` property is supported.
12+
13+
**Example**
14+
15+
```javascript
16+
// Create a rotate animation, the animation name is my-rotate
17+
animation_create("my-rotate", {
18+
// Start frame
19+
"0": {
20+
transform: 'rotate(0deg)'
21+
},
22+
// end frame
23+
"1": {
24+
transform: 'rotate(360deg)'
25+
}
26+
});
27+
```
28+
29+
_Note: The animation name should be unique_
30+
31+
## Apply Animation
32+
33+
Like Web CSS animations, Deft applies animations through css, supporting the following CSS properties:
34+
35+
**animation-name** Animation name, defined by `animation_create` function
36+
37+
**animation-duration** Animation duration, in milliseconds
38+
39+
**animation-iteration-count** Animation loop count, default is 1
40+
41+
42+
**Example**
43+
44+
```jsx
45+
<Button style={{
46+
animationName: 'my-rotate',
47+
animationDuration: 2000,
48+
}}>MyButton</Button>
49+
```
Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
---
2+
title: Custom Components (Rust)
3+
---
4+
5+
import { Image } from 'astro:assets';
6+
import initImg from "../../../../assets/hello-element/init.png";
7+
import renderImg from "../../../../assets/hello-element/render.png";
8+
9+
10+
Deft includes some commonly used basic components and allows you to create custom components to meet complex requirements.
11+
12+
_Note: Custom components here refer to basic components like Label and Button. If you need to create custom React/Vue/Solid components, you should refer to the custom component tutorials for the respective frameworks; this tutorial does not apply._
13+
14+
### Creating a Custom Component
15+
16+
Creating a custom component is very simple—you only need to implement the `ElementBackend` trait.
17+
18+
The `ElementBackend` trait has several methods, but only the `create` method is mandatory. Other methods can be implemented optionally based on requirements.
19+
20+
First, we need to create a struct to represent our custom component. Here, we use `HelloBackend` as an example.
21+
22+
```rust
23+
pub struct HelloBackend {
24+
element_weak: ElementWeak,
25+
}
26+
27+
impl ElementBackend for HelloBackend {
28+
fn create(element: &mut Element) -> Self where Self: Sized {
29+
Self {
30+
// Save a weak reference to the element, which will be used later
31+
element_weak: element.as_weak(),
32+
}
33+
}
34+
}
35+
```
36+
37+
### Registering the Custom Component
38+
39+
After creating the custom component, it needs to be registered. This can be done during the initialization of the JS engine.
40+
41+
```rust
42+
impl IApp for AppImpl {
43+
44+
fn init_js_engine(&mut self, _js_engine: &mut JsEngine) {
45+
// Register our custom component with the tag "hello"
46+
register_component::<HelloBackend>("hello");
47+
}
48+
...
49+
}
50+
```
51+
52+
Here, we register this component as the `hello` component.
53+
54+
### Creating JS Binding for the Custom Component
55+
56+
To use this custom component in JS, we need to create a JS binding: `HelloElement` .
57+
58+
```javascript
59+
class HelloElement extends Element {
60+
constructor() {
61+
// "hello" is the element's tag, which must match the tag declared during registration
62+
super("hello");
63+
}
64+
}
65+
```
66+
67+
`HelloElement` inherits from the `Element` class, which is the base class for all components.
68+
69+
### Using the Custom Component
70+
71+
After completing the three steps of `creation`, `registration`, and `binding`, the component can be directly used in JS code.
72+
73+
First, define some basic styles for it.
74+
75+
```css
76+
body {
77+
justify-content: center;
78+
align-items: center;
79+
}
80+
hello {
81+
width: 100px;
82+
height: 100px;
83+
background: #ccc;
84+
}
85+
```
86+
87+
Then, instantiate a `hello` component and add it to the document flow.
88+
89+
```javascript
90+
const helloElement = new HelloElement();
91+
window.body.addChild(helloElement);
92+
```
93+
94+
The running effect is as follows:
95+
96+
<Image src={initImg} alt="hello element" width="300" />
97+
98+
### Rendering the Component
99+
100+
As shown, our custom component is displayed in the window, but it doesn't do anything yet. Now, let's enhance this component by adding custom rendering logic, which is typically required for custom components.
101+
102+
To add custom rendering logic, implement the `ElementBackend::render` method.
103+
104+
```rust
105+
impl ElementBackend for HelloBackend {
106+
...
107+
fn render(&mut self) -> RenderFn {
108+
// Upgrade the weak reference to the element to a strong reference
109+
let element = self.element_weak.upgrade_mut().unwrap();
110+
// Get the element's size information
111+
let bounds = element.get_bounds();
112+
// Get the center coordinates of the element
113+
let center = (bounds.width / 2.0, bounds.height / 2.0);
114+
// Calculate the radius
115+
let radius = f32::min(center.0, center.1);
116+
RenderFn::new(move |painter| {
117+
let mut paint = Paint::default();
118+
// Use fill style
119+
paint.set_style(PaintStyle::Fill);
120+
paint.set_color(Color::from_rgb(0, 80, 0));
121+
// Draw a circle
122+
painter.canvas.draw_circle(center, radius, &paint);
123+
})
124+
}
125+
}
126+
```
127+
128+
The `render` method returns a `RenderFn` object containing our component's rendering logic. In the example above, we draw a solid circle. Rerun the application to see the final effect:
129+
130+
<Image src={renderImg} alt="custom element with renderer" width="300" />
131+
132+
### Related Code and Reference Examples
133+
134+
The complete code for this article can be found in the Deft repository: https://github.com/deft-ui/deft/blob/main/examples/custom_element.rs
135+
136+
More reference examples:
137+
138+
1. Video playback (ffmpeg): https://github.com/deft-ui/deft-video
139+
2. Remote desktop (SPICE): https://github.com/kasonyang/tiny-spice
140+
141+
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
---
2+
title: Cross-Language Call
3+
---
4+
5+
## JavaScript Call Rust
6+
7+
1. Declare a Rust function
8+
9+
Sync function
10+
```rust
11+
#[deft_macros::js_func]
12+
pub fn hello(message: String) -> String {
13+
println("value from js: ", message);
14+
"Hi, I am Rust".to_string()
15+
}
16+
```
17+
Async function
18+
```rust
19+
#[deft_macros::js_func]
20+
pub async fn hello_async(message: String) -> String {
21+
println("value from js: ", message);
22+
"Hi, I am Rust".to_string()
23+
}
24+
```
25+
2. Register Rust functions to JavaScript engine
26+
```rust
27+
impl IApp for YourApp {
28+
fn init_js_engine(&mut self, js_engine: &mut JsEngine) {
29+
js_engine.add_global_func(hello::new());
30+
js_engine.add_global_func(hello_async::new());
31+
}
32+
...
33+
}
34+
```
35+
3. JavaScript调用
36+
```javascript
37+
// Call sync function
38+
const value = hello("Hello, I am JavaScript");
39+
console.log('value from rust', value);
40+
41+
// Call async function
42+
const value = await hello_async("Hello, I am JavaScript");
43+
console.log('value from rust', value);
44+
```
45+
46+
## Rust Call JavaScript
47+
48+
**Rust global execute JavaScript code**
49+
50+
```rust
51+
let mut js_engine = JsEngine::get();
52+
js_engine.eval_module("console.log(111)", "test.js");
53+
```
54+
55+
**Rust call JavaScript function**
56+
JavaScript call Rust, and pass a JavaScript function as a parameter to Rust, at this time, Rust can use `call_as_function` to call the JavaScript function.
57+
```rust
58+
#[deft_macros::js_func]
59+
pub fn my_rust_fn(callback: JsValue) {
60+
// callback is a function object passed from JavaScript
61+
// execute JavaScript callback
62+
callback.call_as_function(vec![JsValue::Bool(true)]);
63+
}
64+
```
65+
66+
67+
68+
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
---
2+
title: Renderers
3+
---
4+
5+
### Introduction
6+
7+
Deft comes with the following 3 renderers.
8+
9+
| Name | Description | Support Platforms |
10+
|------------|---------------------------------|-----------------------------|
11+
| SoftBuffer | CPU rendering | Windows/MacOS/Linux |
12+
| GL | GPU rendering | Windows/MacOS/Linux/Android |
13+
| SoftGL | CPU rendering, GPU presentation | Windows/MacOS/Linux/Android |
14+
15+
Usually, `GL` renderer has better performance, but consumes more memory, and `SoftGL` is suitable for scenarios where `SoftBuffer` is not supported but still want to use CPU rendering.
16+
17+
By default, Deft will automatically match a renderer based on the order in the table. If you want to change the default matching order, you can set it as follows.
18+
19+
1. Create a window and specify the `preferredRenderers` parameter, for example:
20+
```javascript
21+
const window = new Window({
22+
// prioritize use GL renderers
23+
preferredRenderers: ["GL", "SoftBuffer"]
24+
});
25+
```
26+
2. Set the `DEFT_RENDERERS` environment variable, which will take effect for all Deft applications, for example:
27+
```
28+
export DEFT_RENDERERS=GL,SoftBuffer
29+
```

0 commit comments

Comments
 (0)