Skip to content

Commit f5e84ad

Browse files
committed
add spair and spair-qr
1 parent 2813c8c commit f5e84ad

18 files changed

+706
-0
lines changed

frameworks/keyed/spair-qr/.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
node_modules
2+
/target

frameworks/keyed/spair-qr/Cargo.toml

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
[package]
2+
name = "spair_qr_benchmark"
3+
version = "0.1.0"
4+
edition = "2021"
5+
6+
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
7+
8+
[dependencies]
9+
spair = { git = "https://github.com/aclueless/spair.git", features = ["queue-render"] }
10+
getrandom = { version = "0.2.6", features = ["js"] }
11+
rand = { version = "0.8.5", features = ["small_rng"] }
12+
13+
[profile.release]
14+
lto = true
15+
codegen-units = 1

frameworks/keyed/spair-qr/README.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
Because of the heavy amount of Rust dependencies, this example is pre-compiled, so you don't need to compile anything.
2+
3+
However, if you do want to compile it, you will need the following:
4+
5+
* [Rust](https://www.rust-lang.org/tools/install)
6+
* [Trunk](https://trunkrs.dev/)
7+
8+
After installing those, run these commands:
9+
10+
```
11+
npm install
12+
npm run build-prod-force
13+
```

frameworks/keyed/spair-qr/Trunk.toml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
[build]
2+
# The index HTML file to drive the bundling process.
3+
target = "trunk_index.html"
4+
# The output dir for all final assets.
5+
dist = "bundled-dist"
6+
# The public URL from which assets are to be served.
7+
public_url = "/frameworks/keyed/spair-qr/bundled-dist/"
8+
# Whether to include hash values in the output file names.
9+
filehash = true

frameworks/keyed/spair-qr/build.sh

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
#!/bin/sh
2+
3+
set -e
4+
5+
rustup target add wasm32-unknown-unknown
6+
7+
trunk build --release
8+
mv bundled-dist/index.html index.html

frameworks/keyed/spair-qr/package-lock.json

Lines changed: 14 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
{
2+
"name": "js-framework-benchmark-keyed-spair-qr",
3+
"version": "1.0.0",
4+
"description": "Benchmark for Spair-qr",
5+
"license": "ISC",
6+
"js-framework-benchmark": {
7+
"frameworkVersion": "0.0.6"
8+
},
9+
"scripts": {
10+
"build-prod": "echo This is a no-op. && echo Due to heavy dependencies, the generated javascript is already provided. && echo If you really want to rebuild from source use: && echo npm run build-prod-force",
11+
"build-prod-force": "./build.sh"
12+
},
13+
"repository": {
14+
"type": "git",
15+
"url": "https://github.com/krausest/js-framework-benchmark.git"
16+
},
17+
"devDependencies": {}
18+
}

frameworks/keyed/spair-qr/src/main.rs

Lines changed: 268 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,268 @@
1+
use spair::prelude::*;
2+
use rand::prelude::*;
3+
4+
fn main() {
5+
App::mount_to_element_id("main");
6+
}
7+
8+
#[derive(Debug, Clone, PartialEq, Eq)]
9+
struct RowData {
10+
id: u64,
11+
label: String,
12+
}
13+
14+
struct App {
15+
last_id: u64,
16+
rows: spair::QrVec<RowData>,
17+
selected_id: Option<u64>,
18+
}
19+
20+
impl App {
21+
fn append_rows(&mut self, clear_first: bool, count: usize) {
22+
let mut rng = SmallRng::from_entropy();
23+
let mut rows = self.rows.get_mut();
24+
if clear_first {
25+
rows.clear();
26+
}
27+
rows.reserve(count);
28+
for i in 0..count {
29+
let adjective = ADJECTIVES.choose(&mut rng).unwrap_throw();
30+
let colour = COLOURS.choose(&mut rng).unwrap_throw();
31+
let noun = NOUNS.choose(&mut rng).unwrap_throw();
32+
let capacity = adjective.len() + colour.len() + noun.len() + 2;
33+
let mut label = String::with_capacity(capacity);
34+
label.push_str(adjective);
35+
label.push(' ');
36+
label.push_str(colour);
37+
label.push(' ');
38+
label.push_str(noun);
39+
let id = self.last_id + i as u64 + 1;
40+
rows.push(RowData{
41+
id,
42+
label,
43+
}.into());
44+
}
45+
self.last_id += count as u64;
46+
}
47+
48+
fn append(&mut self, count: usize) {
49+
self.append_rows(false, count);
50+
}
51+
52+
fn create(&mut self, count: usize) {
53+
self.selected_id = None;
54+
self.append_rows(true, count);
55+
}
56+
57+
fn update_every_10th(&mut self) {
58+
self.rows.get_mut().iter_mut().step_by(10).for_each(|mut row| {
59+
row.modify(|row| row.label += " !!!");
60+
});
61+
}
62+
63+
fn swap(&mut self, a: usize, b: usize) {
64+
self.rows.get_mut().swap(a, b).unwrap_throw();
65+
}
66+
67+
fn remove_by_id(&mut self, id: u64) {
68+
self.rows.get_mut().retain(|r| r.id != id);
69+
}
70+
71+
fn clear(&mut self) {
72+
self.rows.get_mut().clear();
73+
self.selected_id = None;
74+
}
75+
76+
fn set_selected_id(&mut self, id: u64) {
77+
let mut rows = self.rows.get_mut();
78+
let old_index = self.selected_id.and_then(|id| rows.iter().position(|rd| rd.id == id));
79+
let new_index = rows.iter().position(|rd| rd.id == id);
80+
81+
self.selected_id = Some(id);
82+
rows.request_render_at(old_index);
83+
rows.request_render_at(new_index);
84+
}
85+
}
86+
87+
impl spair::Application for App {
88+
fn init(_: &spair::Comp<App>) -> Self {
89+
Self {
90+
last_id: 0,
91+
rows: Default::default(),
92+
selected_id: None,
93+
}
94+
}
95+
}
96+
97+
impl spair::Component for App {
98+
type Routes = ();
99+
100+
fn default_should_render() -> spair::ShouldRender {
101+
spair::ShouldRender::No
102+
}
103+
104+
fn render(&self, e: spair::Element<Self>) {
105+
e.div(|d| {
106+
d
107+
.class("container")
108+
.static_nodes()
109+
.div(render_header)
110+
.update_nodes()
111+
.table(|t| {
112+
t.static_attributes()
113+
.class("table")
114+
.class("table-hover")
115+
.class("table-striped")
116+
.class("test-data")
117+
.tbody(|b| {
118+
b.id("tbody")
119+
.qr_list_clone(&self.rows);
120+
});
121+
})
122+
.span(|s| {
123+
s.class("preloadicon")
124+
.class("glyphicon")
125+
.class("glyphicon-remove")
126+
.set_attribute_str("aria-hidden", "true");
127+
});
128+
});
129+
}
130+
}
131+
132+
fn render_header(div: spair::Element<App>) {
133+
let comp = div.comp();
134+
div.class("jumbotron")
135+
.div(|d| {
136+
d.class("row")
137+
.div(|d| d.class("col-md-6").h1(|h| h.rstatic("Spair queue-render").done()).done())
138+
.div(|d| {
139+
d.class("col-md-6")
140+
.div(|d| {
141+
d.class("row")
142+
.rupdate(Button(
143+
"run",
144+
"Create 1,000 rows",
145+
comp.handler_mut(|state| state.create(1000)),
146+
))
147+
.rupdate(Button(
148+
"runlots",
149+
"Create 10,000 rows",
150+
comp.handler_mut(|state| state.create(10000)),
151+
))
152+
.rupdate(Button(
153+
"add",
154+
"Append 1,000 rows",
155+
comp.handler_mut(|state| state.append(1000)),
156+
))
157+
.rupdate(Button(
158+
"update",
159+
"Update every 10th row",
160+
comp.handler_mut(App::update_every_10th),
161+
))
162+
.rupdate(Button(
163+
"clear",
164+
"Clear",
165+
comp.handler_mut(App::clear),
166+
))
167+
.rupdate(Button(
168+
"swaprows",
169+
"Swap rows",
170+
comp.handler_mut(|state| state.swap(1, 998)),
171+
));
172+
});
173+
});
174+
});
175+
}
176+
177+
struct Button<H>(&'static str, &'static str, H);
178+
impl<H: spair::Click> spair::Render<App> for Button<H> {
179+
fn render(self, nodes: spair::Nodes<App>) {
180+
let Button(id, title, handler) = self;
181+
nodes.div(|d| {
182+
d.class("col-sm-6").class("smallpad")
183+
.button(|i| {
184+
i.id(id)
185+
.r#type(spair::InputType::Button)
186+
.class("btn")
187+
.class("btn-primary")
188+
.class("btn-block")
189+
.on_click(handler)
190+
.rstatic(title);
191+
});
192+
});
193+
}
194+
}
195+
196+
impl spair::ElementRender<App> for RowData {
197+
const ELEMENT_TAG: &'static str = "tr";
198+
fn render(self, e: spair::Element<App>) {
199+
let state = e.state();
200+
let comp = e.comp();
201+
let id = self.id;
202+
let in_danger = state.selected_id == Some(self.id);
203+
e
204+
.class_if(in_danger, "danger")
205+
.td(|d| d.class("col-md-1").rupdate(self.id).done())
206+
.td(|d| {
207+
d.class("col-md-4")
208+
.static_attributes()
209+
.on_click(comp.handler_mut(move |state| state.set_selected_id(id)))
210+
.a(|a| a.class("lbl").rupdate(&self.label).done());
211+
})
212+
.td(|d| {
213+
d.class("col-md-1")
214+
.a(|a| {
215+
a.class("remove")
216+
.static_attributes()
217+
.on_click(comp.handler_mut(move |state| state.remove_by_id(id)))
218+
.static_nodes()
219+
.span(|s| {
220+
s.class("remove")
221+
.class("glyphicon")
222+
.class("glyphicon-remove")
223+
.class("remove")
224+
.set_attribute_str("aria-hidden", "true");
225+
});
226+
});
227+
})
228+
.td(|d| d.class("col-md-6").done());
229+
}
230+
}
231+
232+
static ADJECTIVES: &[&str] = &[
233+
"pretty",
234+
"large",
235+
"big",
236+
"small",
237+
"tall",
238+
"short",
239+
"long",
240+
"handsome",
241+
"plain",
242+
"quaint",
243+
"clean",
244+
"elegant",
245+
"easy",
246+
"angry",
247+
"crazy",
248+
"helpful",
249+
"mushy",
250+
"odd",
251+
"unsightly",
252+
"adorable",
253+
"important",
254+
"inexpensive",
255+
"cheap",
256+
"expensive",
257+
"fancy",
258+
];
259+
260+
static COLOURS: &[&str] = &[
261+
"red", "yellow", "blue", "green", "pink", "brown", "purple", "brown", "white", "black",
262+
"orange",
263+
];
264+
265+
static NOUNS: &[&str] = &[
266+
"table", "chair", "house", "bbq", "desk", "car", "pony", "cookie", "sandwich", "burger",
267+
"pizza", "mouse", "keyboard",
268+
];
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<!DOCTYPE html><html lang="en"><head>
2+
<meta charset="UTF-8">
3+
<title>Spair queue render</title>
4+
<link href="/css/currentStyle.css" rel="stylesheet">
5+
<link data-trunk rel="rust">
6+
</head>
7+
<body>
8+
<div id="main"></div>
9+
</body></html>

frameworks/keyed/spair/.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
node_modules
2+
/target

0 commit comments

Comments
 (0)