-
Notifications
You must be signed in to change notification settings - Fork 161
/
Copy pathlib.rs
139 lines (120 loc) · 4.06 KB
/
lib.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
use graphql_client::{reqwest::post_graphql, GraphQLQuery};
use std::cell::RefCell;
use std::sync::Mutex;
use wasm_bindgen::prelude::*;
use wasm_bindgen::JsCast;
use wasm_bindgen_futures::future_to_promise;
#[derive(GraphQLQuery)]
#[graphql(
schema_path = "schema.json",
query_path = "src/puppy_smiles.graphql",
response_derives = "Debug"
)]
struct PuppySmiles;
fn log(s: &str) {
web_sys::console::log_1(&JsValue::from_str(s));
}
static LAST_ENTRY: std::sync::LazyLock<Mutex<RefCell<Option<String>>>> =
std::sync::LazyLock::new(|| Mutex::new(RefCell::new(None)));
async fn load_more() -> Result<JsValue, JsValue> {
let url = "https://www.graphqlhub.com/graphql";
let variables = puppy_smiles::Variables {
after: LAST_ENTRY
.lock()
.ok()
.and_then(|opt| opt.borrow().to_owned()),
};
let client = reqwest::Client::new();
let response = post_graphql::<PuppySmiles, _>(&client, url, variables)
.await
.map_err(|err| {
log(&format!("Could not fetch puppies. error: {err:?}"));
JsValue::NULL
})?;
render_response(response);
Ok(JsValue::NULL)
}
fn document() -> web_sys::Document {
web_sys::window()
.expect_throw("no window")
.document()
.expect_throw("no document")
}
fn add_load_more_button() {
let btn = document()
.create_element("button")
.expect_throw("could not create button");
btn.set_inner_html("I WANT MORE PUPPIES");
let on_click = Closure::wrap(
Box::new(move || future_to_promise(load_more())) as Box<dyn FnMut() -> js_sys::Promise>
);
btn.add_event_listener_with_callback(
"click",
on_click
.as_ref()
.dyn_ref()
.expect_throw("on click is not a Function"),
)
.expect_throw("could not add event listener to load more button");
let doc = document().body().expect_throw("no body");
doc.append_child(&btn)
.expect_throw("could not append button");
on_click.forget();
}
fn render_response(response: graphql_client::Response<puppy_smiles::ResponseData>) {
use std::fmt::Write;
log(&format!("response body\n\n{response:?}"));
let parent = document().body().expect_throw("no body");
let json: graphql_client::Response<puppy_smiles::ResponseData> = response;
let response = document()
.create_element("div")
.expect_throw("could not create div");
let mut inner_html = String::new();
let listings = json
.data
.expect_throw("response data")
.reddit
.expect_throw("reddit")
.subreddit
.expect_throw("puppy smiles subreddit")
.new_listings;
let new_cursor: Option<String> = listings[listings.len() - 1]
.as_ref()
.map(|puppy| puppy.fullname_id.clone());
LAST_ENTRY.lock().unwrap_throw().replace(new_cursor);
for puppy in listings.iter().flatten() {
write!(
inner_html,
r#"
<div class="card" style="width: 26rem;">
<img class="img-thumbnail card-img-top" alt="{}" src="{}" />
<div class="card-body">
<h5 class="card-title">{}</h5>
</div>
</div>
"#,
puppy.title, puppy.url, puppy.title
)
.expect_throw("write to string");
}
response.set_inner_html(&format!(
"<h2>response:</h2><div class=\"container\"><div class=\"row\">{inner_html}</div></div>"
));
parent
.append_child(&response)
.expect_throw("could not append response");
}
#[wasm_bindgen(start)]
pub fn run() {
log("Hello there");
let message_area = document()
.create_element("div")
.expect_throw("could not create div");
message_area.set_inner_html("<p>good morning</p>");
let parent = document().body().unwrap_throw();
parent
.append_child(&message_area)
.expect_throw("could not append message area");
add_load_more_button();
log("Bye");
}