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;
|
return token;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function get_edit_token() {
|
||||||
|
let params = new URLSearchParams(document.location.search);
|
||||||
|
let token = params.get("edit");
|
||||||
|
return token;
|
||||||
|
}
|
||||||
|
|
||||||
function set_location(l) {
|
function set_location(l) {
|
||||||
window.location = l;
|
window.location = l;
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,6 +43,7 @@ struct Card {
|
||||||
}
|
}
|
||||||
|
|
||||||
wasm_import!(get_token() -> Option<String>);
|
wasm_import!(get_token() -> Option<String>);
|
||||||
|
wasm_import!(get_edit_token() -> Option<String>);
|
||||||
wasm_import!(prompt(s: &str) -> Option<String>);
|
wasm_import!(prompt(s: &str) -> Option<String>);
|
||||||
wasm_import!(set_location(l: &str));
|
wasm_import!(set_location(l: &str));
|
||||||
wasm_import!(alert(s: &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_home = |_| set_location("/");
|
||||||
|
|
||||||
|
let go_modify = move |_| {
|
||||||
|
let location = format!("/?edit={}", token);
|
||||||
|
set_location(&location);
|
||||||
|
};
|
||||||
|
|
||||||
view! {ctx,
|
view! {ctx,
|
||||||
div(class="text-align-center") {
|
div(class="text-align-center") {
|
||||||
button(on:click=go_home) { "Home" }
|
button(on:click=go_home) { "Home" }
|
||||||
|
button(on:click=go_modify) { "Edit Deck" }
|
||||||
button(on:click=recompute_current) { "Next" }
|
button(on:click=recompute_current) { "Next" }
|
||||||
}
|
}
|
||||||
({
|
({
|
||||||
|
@ -107,6 +114,25 @@ fn CardsComponent<G: Html>(ctx: Scope) -> View<G> {
|
||||||
|
|
||||||
#[component]
|
#[component]
|
||||||
fn CreatorComponent<G: Html>(ctx: Scope) -> View<G> {
|
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 do_import = |_| {
|
||||||
let p = prompt("Deck code:");
|
let p = prompt("Deck code:");
|
||||||
if let Some(inp) = p {
|
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 do_add = |_| {
|
||||||
let f = (*front.get()).clone();
|
let f = (*front.get()).clone();
|
||||||
let b = (*back.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,
|
view! {ctx,
|
||||||
div(class="text-align-center") {
|
div(class="text-align-center") {
|
||||||
button(on:click=do_import) {"Import"}
|
button(on:click=do_import) {"Import"}
|
||||||
|
button(on:click=do_use_current) {"Use Current Deck"}
|
||||||
button(on:click=do_export) {"Export"}
|
button(on:click=do_export) {"Export"}
|
||||||
br
|
br
|
||||||
input(bind:value=front)
|
input(bind:value=front)
|
||||||
|
@ -181,14 +223,15 @@ fn CreatorComponent<G: Html>(ctx: Scope) -> View<G> {
|
||||||
view! {ctx,}
|
view! {ctx,}
|
||||||
})
|
})
|
||||||
button(on:click=do_add) {"Add"}
|
button(on:click=do_add) {"Add"}
|
||||||
|
button(on:click=do_delete_last) {"Delete Last"}
|
||||||
Indexed {
|
Indexed {
|
||||||
iterable: cards,
|
iterable: cards,
|
||||||
view: |ctx, card| view! {ctx,
|
view: |ctx, card| view! {ctx,
|
||||||
div(class="card", style="background-color: white;") {
|
div(class="card", style="background-color: white; padding: 5px; transform: none") {
|
||||||
"Front:"
|
"Front: "
|
||||||
(card.front)
|
(card.front)
|
||||||
br
|
br
|
||||||
"Back:"
|
"Back: "
|
||||||
(card.back)
|
(card.back)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue