Compare commits
3 commits
b3f1d08ecf
...
c921ed1ebd
Author | SHA1 | Date | |
---|---|---|---|
Yash Karandikar | c921ed1ebd | ||
Yash Karandikar | e2bfe635a9 | ||
Yash Karandikar | 93818956a7 |
23
quicksilver/README.md
Normal file
23
quicksilver/README.md
Normal file
|
@ -0,0 +1,23 @@
|
|||
# Quicksilver
|
||||
|
||||
[Live App](https://etc.karx.xyz/rgl/quicksilver/)
|
||||
|
||||
## Running Locally
|
||||
1. Install dependencies
|
||||
|
||||
First, install `rust` from [the Rust website](https://www.rust-lang.org/). Then, install `trunk`:
|
||||
```bash
|
||||
cargo install --locked trunk
|
||||
```
|
||||
This project requires `rustc` version `1.60.0 stable` because it uses the 2021 edition of Rust and sycamore 0.8!
|
||||
2. Build project
|
||||
```bash
|
||||
cd /path/to/quicksilver
|
||||
trunk serve
|
||||
```
|
||||
3. Open in browser
|
||||
|
||||
[Check the supported browser list](https://rustwasm.github.io/docs/wasm-bindgen/reference/browser-support.html) and open https://localhost:8080 in one of the supported browsers.
|
||||
|
||||
|
||||
<small>Created using [Sycamore](https://crates.io/crates/sycamore) and Rust with WebAssembly</small>
|
|
@ -4,6 +4,12 @@ function get_token() {
|
|||
return token;
|
||||
}
|
||||
|
||||
function get_edit_token() {
|
||||
let params = new URLSearchParams(document.location.search);
|
||||
let token = params.get("edit");
|
||||
return token;
|
||||
}
|
||||
|
||||
function set_location(l) {
|
||||
window.location = l;
|
||||
}
|
||||
|
|
|
@ -43,6 +43,7 @@ struct Card {
|
|||
}
|
||||
|
||||
wasm_import!(get_token() -> Option<String>);
|
||||
wasm_import!(get_edit_token() -> Option<String>);
|
||||
wasm_import!(prompt(s: &str) -> Option<String>);
|
||||
wasm_import!(set_location(l: &str));
|
||||
wasm_import!(alert(s: &str));
|
||||
|
@ -82,9 +83,15 @@ fn CardsComponent<G: Html>(ctx: Scope) -> View<G> {
|
|||
|
||||
let go_home = |_| set_location("/");
|
||||
|
||||
let go_modify = move |_| {
|
||||
let location = format!("/?edit={}", token);
|
||||
set_location(&location);
|
||||
};
|
||||
|
||||
view! {ctx,
|
||||
div(class="text-align-center") {
|
||||
button(on:click=go_home) { "Home" }
|
||||
button(on:click=go_modify) { "Edit Deck" }
|
||||
button(on:click=recompute_current) { "Next" }
|
||||
}
|
||||
({
|
||||
|
@ -107,6 +114,25 @@ fn CardsComponent<G: Html>(ctx: Scope) -> View<G> {
|
|||
|
||||
#[component]
|
||||
fn CreatorComponent<G: Html>(ctx: Scope) -> View<G> {
|
||||
let front = create_signal(ctx, String::new());
|
||||
let back = create_signal(ctx, String::new());
|
||||
|
||||
let error_empty = create_signal(ctx, false);
|
||||
let error_parse = create_signal(ctx, false);
|
||||
|
||||
let cards = create_signal(ctx, Vec::new());
|
||||
|
||||
if let Some(token) = get_edit_token() {
|
||||
let stripped = token
|
||||
.chars()
|
||||
.filter(|c| !c.is_whitespace())
|
||||
.collect::<String>();
|
||||
let decoded = base64::decode(stripped.as_bytes()).unwrap_or_default();
|
||||
let parsed = String::from_utf8(decoded).unwrap_or_default();
|
||||
let items: Vec<Card> = serde_json::from_str(&parsed).unwrap_or_default();
|
||||
*cards.modify() = items;
|
||||
}
|
||||
|
||||
let do_import = |_| {
|
||||
let p = prompt("Deck code:");
|
||||
if let Some(inp) = p {
|
||||
|
@ -119,14 +145,6 @@ fn CreatorComponent<G: Html>(ctx: Scope) -> View<G> {
|
|||
}
|
||||
};
|
||||
|
||||
let front = create_signal(ctx, String::new());
|
||||
let back = create_signal(ctx, String::new());
|
||||
|
||||
let error_empty = create_signal(ctx, false);
|
||||
let error_parse = create_signal(ctx, false);
|
||||
|
||||
let cards = create_signal(ctx, Vec::new());
|
||||
|
||||
let do_add = |_| {
|
||||
let f = (*front.get()).clone();
|
||||
let b = (*back.get()).clone();
|
||||
|
@ -163,9 +181,33 @@ fn CreatorComponent<G: Html>(ctx: Scope) -> View<G> {
|
|||
}
|
||||
};
|
||||
|
||||
let do_use_current = |_| {
|
||||
let d = Deck((*cards.get()).clone());
|
||||
|
||||
if d.is_empty() {
|
||||
return;
|
||||
}
|
||||
|
||||
let r = serde_json::to_string(&d);
|
||||
|
||||
if let Ok(s) = r {
|
||||
error_parse.set(false);
|
||||
let e = base64::encode(s.as_bytes());
|
||||
let f = format!("/?deck={}", e);
|
||||
set_location(&f);
|
||||
} else {
|
||||
error_parse.set(true);
|
||||
}
|
||||
};
|
||||
|
||||
let do_delete_last = |_| {
|
||||
cards.modify().pop();
|
||||
};
|
||||
|
||||
view! {ctx,
|
||||
div(class="text-align-center") {
|
||||
button(on:click=do_import) {"Import"}
|
||||
button(on:click=do_use_current) {"Use Current Deck"}
|
||||
button(on:click=do_export) {"Export"}
|
||||
br
|
||||
input(bind:value=front)
|
||||
|
@ -181,14 +223,15 @@ fn CreatorComponent<G: Html>(ctx: Scope) -> View<G> {
|
|||
view! {ctx,}
|
||||
})
|
||||
button(on:click=do_add) {"Add"}
|
||||
button(on:click=do_delete_last) {"Delete Last"}
|
||||
Indexed {
|
||||
iterable: cards,
|
||||
view: |ctx, card| view! {ctx,
|
||||
div(class="card", style="background-color: white;") {
|
||||
"Front:"
|
||||
div(class="card", style="background-color: white; padding: 5px; transform: none") {
|
||||
"Front: "
|
||||
(card.front)
|
||||
br
|
||||
"Back:"
|
||||
"Back: "
|
||||
(card.back)
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue