Yew
This commit is contained in:
parent
77d2ce983e
commit
00814fa01c
|
@ -757,6 +757,7 @@ version = "0.2.3"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a8d5564e570a38b43d78bdc063374a0c3098c4f0d64005b12f9bbe87e869b6d7"
|
||||
dependencies = [
|
||||
"futures-channel",
|
||||
"gloo-events",
|
||||
"js-sys",
|
||||
"wasm-bindgen",
|
||||
|
@ -794,6 +795,8 @@ version = "0.2.4"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5fb7d06c1c8cc2a29bee7ec961009a0b2caa0793ee4900c2ffb348734ba1c8f9"
|
||||
dependencies = [
|
||||
"futures-channel",
|
||||
"futures-core",
|
||||
"js-sys",
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
@ -1099,7 +1102,15 @@ dependencies = [
|
|||
name = "lan_party_web"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"lan_party_core",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"thiserror",
|
||||
"wasm-bindgen",
|
||||
"wasm-bindgen-futures",
|
||||
"web-sys",
|
||||
"yew",
|
||||
"yew-router",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1861,6 +1872,12 @@ dependencies = [
|
|||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "route-recognizer"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "afab94fb28594581f62d981211a9a4d53cc8130bbcbbb89a0440d9b8e81a7746"
|
||||
|
||||
[[package]]
|
||||
name = "rustc_version"
|
||||
version = "0.2.3"
|
||||
|
@ -2013,6 +2030,18 @@ dependencies = [
|
|||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde-wasm-bindgen"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "618365e8e586c22123d692b72a7d791d5ee697817b65a218cdf12a98870af0f7"
|
||||
dependencies = [
|
||||
"fnv",
|
||||
"js-sys",
|
||||
"serde",
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_bytes"
|
||||
version = "0.11.7"
|
||||
|
@ -2056,6 +2085,18 @@ dependencies = [
|
|||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_urlencoded"
|
||||
version = "0.7.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd"
|
||||
dependencies = [
|
||||
"form_urlencoded",
|
||||
"itoa",
|
||||
"ryu",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_with"
|
||||
version = "1.14.0"
|
||||
|
@ -2809,6 +2850,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "fc7652e3f6c4706c8d9cd54832c4a4ccb9b5336e2c3bd154d5cccfbf1c1f5f7d"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"wasm-bindgen-macro",
|
||||
]
|
||||
|
||||
|
@ -3077,3 +3120,34 @@ dependencies = [
|
|||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "yew-router"
|
||||
version = "0.16.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "155804f6f3aa309f596d5c3fa14486a94e7756f1edd7634569949e401d5099f2"
|
||||
dependencies = [
|
||||
"gloo",
|
||||
"gloo-utils",
|
||||
"js-sys",
|
||||
"route-recognizer",
|
||||
"serde",
|
||||
"serde-wasm-bindgen",
|
||||
"serde_urlencoded",
|
||||
"thiserror",
|
||||
"wasm-bindgen",
|
||||
"web-sys",
|
||||
"yew",
|
||||
"yew-router-macro",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "yew-router-macro"
|
||||
version = "0.16.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "39049d193b52eaad4ffc80916bf08806d142c90b5edcebd527644de438a7e19a"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
mod api;
|
||||
|
||||
use rocket::fs::FileServer;
|
||||
use rocket_cors::CorsOptions;
|
||||
use rocket_db_pools::{mongodb, Database};
|
||||
use rocket_okapi::{
|
||||
|
@ -32,7 +33,7 @@ fn rocket() -> _ {
|
|||
let building_rocket = rocket::build()
|
||||
.attach(Db::init())
|
||||
.attach(cors)
|
||||
.mount("/", routes![index])
|
||||
.mount("/", FileServer::from("./web/dist"))
|
||||
.mount(
|
||||
"/swagger",
|
||||
make_swagger_ui(&SwaggerUIConfig {
|
||||
|
|
|
@ -27,9 +27,9 @@ pub enum PartyError {
|
|||
#[cfg_attr(feature = "rocket", derive(FromFormField))]
|
||||
#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))]
|
||||
pub enum Ordering {
|
||||
#[cfg_attr(feature = "serde", field(value = "desc"))]
|
||||
#[cfg_attr(feature = "rocket", field(value = "desc"))]
|
||||
Desc,
|
||||
#[cfg_attr(feature = "serde", field(value = "asc"))]
|
||||
#[cfg_attr(feature = "rocket", field(value = "asc"))]
|
||||
Asc,
|
||||
}
|
||||
|
||||
|
|
|
@ -7,3 +7,11 @@ edition = "2021"
|
|||
|
||||
[dependencies]
|
||||
yew = "0.19"
|
||||
yew-router = "0.16"
|
||||
web-sys = { version = "0.3", features = ["Request", "RequestInit", "RequestMode", "Response", "Headers"] }
|
||||
lan_party_core = { path = "../core", features = ["serde"] }
|
||||
wasm-bindgen = { version = "0.2", features = ["serde-serialize"] }
|
||||
wasm-bindgen-futures = "0.4"
|
||||
serde = "1"
|
||||
serde_json = "1"
|
||||
thiserror = "1"
|
||||
|
|
Binary file not shown.
|
@ -1,45 +1,6 @@
|
|||
|
||||
let wasm;
|
||||
|
||||
const heap = new Array(32).fill(undefined);
|
||||
|
||||
heap.push(undefined, null, true, false);
|
||||
|
||||
function getObject(idx) { return heap[idx]; }
|
||||
|
||||
let heap_next = heap.length;
|
||||
|
||||
function addHeapObject(obj) {
|
||||
if (heap_next === heap.length) heap.push(heap.length + 1);
|
||||
const idx = heap_next;
|
||||
heap_next = heap[idx];
|
||||
|
||||
heap[idx] = obj;
|
||||
return idx;
|
||||
}
|
||||
|
||||
function isLikeNone(x) {
|
||||
return x === undefined || x === null;
|
||||
}
|
||||
|
||||
let cachedFloat64Memory0 = new Float64Array();
|
||||
|
||||
function getFloat64Memory0() {
|
||||
if (cachedFloat64Memory0.byteLength === 0) {
|
||||
cachedFloat64Memory0 = new Float64Array(wasm.memory.buffer);
|
||||
}
|
||||
return cachedFloat64Memory0;
|
||||
}
|
||||
|
||||
let cachedInt32Memory0 = new Int32Array();
|
||||
|
||||
function getInt32Memory0() {
|
||||
if (cachedInt32Memory0.byteLength === 0) {
|
||||
cachedInt32Memory0 = new Int32Array(wasm.memory.buffer);
|
||||
}
|
||||
return cachedInt32Memory0;
|
||||
}
|
||||
|
||||
const cachedTextDecoder = new TextDecoder('utf-8', { ignoreBOM: true, fatal: true });
|
||||
|
||||
cachedTextDecoder.decode();
|
||||
|
@ -57,6 +18,100 @@ function getStringFromWasm0(ptr, len) {
|
|||
return cachedTextDecoder.decode(getUint8Memory0().subarray(ptr, ptr + len));
|
||||
}
|
||||
|
||||
const heap = new Array(32).fill(undefined);
|
||||
|
||||
heap.push(undefined, null, true, false);
|
||||
|
||||
let heap_next = heap.length;
|
||||
|
||||
function addHeapObject(obj) {
|
||||
if (heap_next === heap.length) heap.push(heap.length + 1);
|
||||
const idx = heap_next;
|
||||
heap_next = heap[idx];
|
||||
|
||||
heap[idx] = obj;
|
||||
return idx;
|
||||
}
|
||||
|
||||
function getObject(idx) { return heap[idx]; }
|
||||
|
||||
let WASM_VECTOR_LEN = 0;
|
||||
|
||||
const cachedTextEncoder = new TextEncoder('utf-8');
|
||||
|
||||
const encodeString = (typeof cachedTextEncoder.encodeInto === 'function'
|
||||
? function (arg, view) {
|
||||
return cachedTextEncoder.encodeInto(arg, view);
|
||||
}
|
||||
: function (arg, view) {
|
||||
const buf = cachedTextEncoder.encode(arg);
|
||||
view.set(buf);
|
||||
return {
|
||||
read: arg.length,
|
||||
written: buf.length
|
||||
};
|
||||
});
|
||||
|
||||
function passStringToWasm0(arg, malloc, realloc) {
|
||||
|
||||
if (realloc === undefined) {
|
||||
const buf = cachedTextEncoder.encode(arg);
|
||||
const ptr = malloc(buf.length);
|
||||
getUint8Memory0().subarray(ptr, ptr + buf.length).set(buf);
|
||||
WASM_VECTOR_LEN = buf.length;
|
||||
return ptr;
|
||||
}
|
||||
|
||||
let len = arg.length;
|
||||
let ptr = malloc(len);
|
||||
|
||||
const mem = getUint8Memory0();
|
||||
|
||||
let offset = 0;
|
||||
|
||||
for (; offset < len; offset++) {
|
||||
const code = arg.charCodeAt(offset);
|
||||
if (code > 0x7F) break;
|
||||
mem[ptr + offset] = code;
|
||||
}
|
||||
|
||||
if (offset !== len) {
|
||||
if (offset !== 0) {
|
||||
arg = arg.slice(offset);
|
||||
}
|
||||
ptr = realloc(ptr, len, len = offset + arg.length * 3);
|
||||
const view = getUint8Memory0().subarray(ptr + offset, ptr + len);
|
||||
const ret = encodeString(arg, view);
|
||||
|
||||
offset += ret.written;
|
||||
}
|
||||
|
||||
WASM_VECTOR_LEN = offset;
|
||||
return ptr;
|
||||
}
|
||||
|
||||
let cachedInt32Memory0 = new Int32Array();
|
||||
|
||||
function getInt32Memory0() {
|
||||
if (cachedInt32Memory0.byteLength === 0) {
|
||||
cachedInt32Memory0 = new Int32Array(wasm.memory.buffer);
|
||||
}
|
||||
return cachedInt32Memory0;
|
||||
}
|
||||
|
||||
function isLikeNone(x) {
|
||||
return x === undefined || x === null;
|
||||
}
|
||||
|
||||
let cachedFloat64Memory0 = new Float64Array();
|
||||
|
||||
function getFloat64Memory0() {
|
||||
if (cachedFloat64Memory0.byteLength === 0) {
|
||||
cachedFloat64Memory0 = new Float64Array(wasm.memory.buffer);
|
||||
}
|
||||
return cachedFloat64Memory0;
|
||||
}
|
||||
|
||||
function dropObject(idx) {
|
||||
if (idx < 36) return;
|
||||
heap[idx] = heap_next;
|
||||
|
@ -134,61 +189,6 @@ function debugString(val) {
|
|||
return className;
|
||||
}
|
||||
|
||||
let WASM_VECTOR_LEN = 0;
|
||||
|
||||
const cachedTextEncoder = new TextEncoder('utf-8');
|
||||
|
||||
const encodeString = (typeof cachedTextEncoder.encodeInto === 'function'
|
||||
? function (arg, view) {
|
||||
return cachedTextEncoder.encodeInto(arg, view);
|
||||
}
|
||||
: function (arg, view) {
|
||||
const buf = cachedTextEncoder.encode(arg);
|
||||
view.set(buf);
|
||||
return {
|
||||
read: arg.length,
|
||||
written: buf.length
|
||||
};
|
||||
});
|
||||
|
||||
function passStringToWasm0(arg, malloc, realloc) {
|
||||
|
||||
if (realloc === undefined) {
|
||||
const buf = cachedTextEncoder.encode(arg);
|
||||
const ptr = malloc(buf.length);
|
||||
getUint8Memory0().subarray(ptr, ptr + buf.length).set(buf);
|
||||
WASM_VECTOR_LEN = buf.length;
|
||||
return ptr;
|
||||
}
|
||||
|
||||
let len = arg.length;
|
||||
let ptr = malloc(len);
|
||||
|
||||
const mem = getUint8Memory0();
|
||||
|
||||
let offset = 0;
|
||||
|
||||
for (; offset < len; offset++) {
|
||||
const code = arg.charCodeAt(offset);
|
||||
if (code > 0x7F) break;
|
||||
mem[ptr + offset] = code;
|
||||
}
|
||||
|
||||
if (offset !== len) {
|
||||
if (offset !== 0) {
|
||||
arg = arg.slice(offset);
|
||||
}
|
||||
ptr = realloc(ptr, len, len = offset + arg.length * 3);
|
||||
const view = getUint8Memory0().subarray(ptr + offset, ptr + len);
|
||||
const ret = encodeString(arg, view);
|
||||
|
||||
offset += ret.written;
|
||||
}
|
||||
|
||||
WASM_VECTOR_LEN = offset;
|
||||
return ptr;
|
||||
}
|
||||
|
||||
function makeClosure(arg0, arg1, dtor, f) {
|
||||
const state = { a: arg0, b: arg1, cnt: 1, dtor };
|
||||
const real = (...args) => {
|
||||
|
@ -210,8 +210,52 @@ function makeClosure(arg0, arg1, dtor, f) {
|
|||
|
||||
return real;
|
||||
}
|
||||
function __wbg_adapter_18(arg0, arg1, arg2) {
|
||||
wasm._dyn_core__ops__function__Fn__A____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__hdd7f308d47caeab7(arg0, arg1, addHeapObject(arg2));
|
||||
function __wbg_adapter_24(arg0, arg1, arg2) {
|
||||
wasm._dyn_core__ops__function__Fn__A____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__hf2a95eaa6a1fe8eb(arg0, arg1, addHeapObject(arg2));
|
||||
}
|
||||
|
||||
function makeMutClosure(arg0, arg1, dtor, f) {
|
||||
const state = { a: arg0, b: arg1, cnt: 1, dtor };
|
||||
const real = (...args) => {
|
||||
// First up with a closure we increment the internal reference
|
||||
// count. This ensures that the Rust closure environment won't
|
||||
// be deallocated while we're invoking it.
|
||||
state.cnt++;
|
||||
const a = state.a;
|
||||
state.a = 0;
|
||||
try {
|
||||
return f(a, state.b, ...args);
|
||||
} finally {
|
||||
if (--state.cnt === 0) {
|
||||
wasm.__wbindgen_export_2.get(state.dtor)(a, state.b);
|
||||
|
||||
} else {
|
||||
state.a = a;
|
||||
}
|
||||
}
|
||||
};
|
||||
real.original = state;
|
||||
|
||||
return real;
|
||||
}
|
||||
|
||||
let stack_pointer = 32;
|
||||
|
||||
function addBorrowedObject(obj) {
|
||||
if (stack_pointer == 1) throw new Error('out of js stack');
|
||||
heap[--stack_pointer] = obj;
|
||||
return stack_pointer;
|
||||
}
|
||||
function __wbg_adapter_27(arg0, arg1, arg2) {
|
||||
try {
|
||||
wasm._dyn_core__ops__function__FnMut___A____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__h3700fed383a0f072(arg0, arg1, addBorrowedObject(arg2));
|
||||
} finally {
|
||||
heap[stack_pointer++] = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
function __wbg_adapter_30(arg0, arg1, arg2) {
|
||||
wasm._dyn_core__ops__function__FnMut__A____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__h0ff5f5f93b8ace87(arg0, arg1, addHeapObject(arg2));
|
||||
}
|
||||
|
||||
let cachedUint32Memory0 = new Uint32Array();
|
||||
|
@ -275,10 +319,30 @@ async function load(module, imports) {
|
|||
function getImports() {
|
||||
const imports = {};
|
||||
imports.wbg = {};
|
||||
imports.wbg.__wbindgen_string_new = function(arg0, arg1) {
|
||||
const ret = getStringFromWasm0(arg0, arg1);
|
||||
return addHeapObject(ret);
|
||||
};
|
||||
imports.wbg.__wbindgen_object_clone_ref = function(arg0) {
|
||||
const ret = getObject(arg0);
|
||||
return addHeapObject(ret);
|
||||
};
|
||||
imports.wbg.__wbindgen_json_parse = function(arg0, arg1) {
|
||||
const ret = JSON.parse(getStringFromWasm0(arg0, arg1));
|
||||
return addHeapObject(ret);
|
||||
};
|
||||
imports.wbg.__wbindgen_json_serialize = function(arg0, arg1) {
|
||||
const obj = getObject(arg1);
|
||||
const ret = JSON.stringify(obj === undefined ? null : obj);
|
||||
const ptr0 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
|
||||
const len0 = WASM_VECTOR_LEN;
|
||||
getInt32Memory0()[arg0 / 4 + 1] = len0;
|
||||
getInt32Memory0()[arg0 / 4 + 0] = ptr0;
|
||||
};
|
||||
imports.wbg.__wbindgen_is_undefined = function(arg0) {
|
||||
const ret = getObject(arg0) === undefined;
|
||||
return ret;
|
||||
};
|
||||
imports.wbg.__wbindgen_number_get = function(arg0, arg1) {
|
||||
const obj = getObject(arg1);
|
||||
const ret = typeof(obj) === 'number' ? obj : undefined;
|
||||
|
@ -289,13 +353,6 @@ function getImports() {
|
|||
const ret = arg0;
|
||||
return addHeapObject(ret);
|
||||
};
|
||||
imports.wbg.__wbindgen_string_new = function(arg0, arg1) {
|
||||
const ret = getStringFromWasm0(arg0, arg1);
|
||||
return addHeapObject(ret);
|
||||
};
|
||||
imports.wbg.__wbindgen_object_drop_ref = function(arg0) {
|
||||
takeObject(arg0);
|
||||
};
|
||||
imports.wbg.__wbg_error_09919627ac0992f5 = function(arg0, arg1) {
|
||||
try {
|
||||
console.error(getStringFromWasm0(arg0, arg1));
|
||||
|
@ -314,6 +371,18 @@ function getImports() {
|
|||
getInt32Memory0()[arg0 / 4 + 1] = len0;
|
||||
getInt32Memory0()[arg0 / 4 + 0] = ptr0;
|
||||
};
|
||||
imports.wbg.__wbindgen_object_drop_ref = function(arg0) {
|
||||
takeObject(arg0);
|
||||
};
|
||||
imports.wbg.__wbindgen_cb_drop = function(arg0) {
|
||||
const obj = takeObject(arg0).original;
|
||||
if (obj.cnt-- == 1) {
|
||||
obj.a = 0;
|
||||
return true;
|
||||
}
|
||||
const ret = false;
|
||||
return ret;
|
||||
};
|
||||
imports.wbg.__wbg_warn_921059440157e870 = function(arg0, arg1) {
|
||||
var v0 = getArrayJsValueFromWasm0(arg0, arg1).slice();
|
||||
wasm.__wbindgen_free(arg0, arg1 * 4);
|
||||
|
@ -327,6 +396,18 @@ function getImports() {
|
|||
const ret = getObject(arg0).document;
|
||||
return isLikeNone(ret) ? 0 : addHeapObject(ret);
|
||||
};
|
||||
imports.wbg.__wbg_location_312161fbd0cf64f0 = function(arg0) {
|
||||
const ret = getObject(arg0).location;
|
||||
return addHeapObject(ret);
|
||||
};
|
||||
imports.wbg.__wbg_history_cb2cdfbe20fef7ad = function() { return handleError(function (arg0) {
|
||||
const ret = getObject(arg0).history;
|
||||
return addHeapObject(ret);
|
||||
}, arguments) };
|
||||
imports.wbg.__wbg_fetch_9a5cb9d8a96004d0 = function(arg0, arg1) {
|
||||
const ret = getObject(arg0).fetch(getObject(arg1));
|
||||
return addHeapObject(ret);
|
||||
};
|
||||
imports.wbg.__wbg_body_5e6efc7a3c1b65f3 = function(arg0) {
|
||||
const ret = getObject(arg0).body;
|
||||
return isLikeNone(ret) ? 0 : addHeapObject(ret);
|
||||
|
@ -343,6 +424,36 @@ function getImports() {
|
|||
const ret = getObject(arg0).createTextNode(getStringFromWasm0(arg1, arg2));
|
||||
return addHeapObject(ret);
|
||||
};
|
||||
imports.wbg.__wbg_querySelector_73feab41810011dc = function() { return handleError(function (arg0, arg1, arg2) {
|
||||
const ret = getObject(arg0).querySelector(getStringFromWasm0(arg1, arg2));
|
||||
return isLikeNone(ret) ? 0 : addHeapObject(ret);
|
||||
}, arguments) };
|
||||
imports.wbg.__wbg_instanceof_HtmlInputElement_3fad42774bc62388 = function(arg0) {
|
||||
const ret = getObject(arg0) instanceof HTMLInputElement;
|
||||
return ret;
|
||||
};
|
||||
imports.wbg.__wbg_setchecked_a450b330df6b3fa5 = function(arg0, arg1) {
|
||||
getObject(arg0).checked = arg1 !== 0;
|
||||
};
|
||||
imports.wbg.__wbg_value_30770021ca38e0db = function(arg0, arg1) {
|
||||
const ret = getObject(arg1).value;
|
||||
const ptr0 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
|
||||
const len0 = WASM_VECTOR_LEN;
|
||||
getInt32Memory0()[arg0 / 4 + 1] = len0;
|
||||
getInt32Memory0()[arg0 / 4 + 0] = ptr0;
|
||||
};
|
||||
imports.wbg.__wbg_setvalue_7b7950dacc5eb607 = function(arg0, arg1, arg2) {
|
||||
getObject(arg0).value = getStringFromWasm0(arg1, arg2);
|
||||
};
|
||||
imports.wbg.__wbg_addEventListener_ec92ea1297eefdfc = function() { return handleError(function (arg0, arg1, arg2, arg3, arg4) {
|
||||
getObject(arg0).addEventListener(getStringFromWasm0(arg1, arg2), getObject(arg3), getObject(arg4));
|
||||
}, arguments) };
|
||||
imports.wbg.__wbg_removeEventListener_bfe676215a590711 = function() { return handleError(function (arg0, arg1, arg2, arg3, arg4) {
|
||||
getObject(arg0).removeEventListener(getStringFromWasm0(arg1, arg2), getObject(arg3), arg4 !== 0);
|
||||
}, arguments) };
|
||||
imports.wbg.__wbg_pushState_65b5fb0f30ca9d61 = function() { return handleError(function (arg0, arg1, arg2, arg3, arg4, arg5) {
|
||||
getObject(arg0).pushState(getObject(arg1), getStringFromWasm0(arg2, arg3), arg4 === 0 ? undefined : getStringFromWasm0(arg4, arg5));
|
||||
}, arguments) };
|
||||
imports.wbg.__wbg_parentElement_14138ef2ff0b9c88 = function(arg0) {
|
||||
const ret = getObject(arg0).parentElement;
|
||||
return isLikeNone(ret) ? 0 : addHeapObject(ret);
|
||||
|
@ -366,6 +477,20 @@ function getImports() {
|
|||
const ret = getObject(arg0).removeChild(getObject(arg1));
|
||||
return addHeapObject(ret);
|
||||
}, arguments) };
|
||||
imports.wbg.__wbg_new_4cba26249c1686cd = function() { return handleError(function () {
|
||||
const ret = new Headers();
|
||||
return addHeapObject(ret);
|
||||
}, arguments) };
|
||||
imports.wbg.__wbg_append_9c6d4d7f71076e48 = function() { return handleError(function (arg0, arg1, arg2, arg3, arg4) {
|
||||
getObject(arg0).append(getStringFromWasm0(arg1, arg2), getStringFromWasm0(arg3, arg4));
|
||||
}, arguments) };
|
||||
imports.wbg.__wbg_pathname_c08f1ef51f6ebba9 = function() { return handleError(function (arg0, arg1) {
|
||||
const ret = getObject(arg1).pathname;
|
||||
const ptr0 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
|
||||
const len0 = WASM_VECTOR_LEN;
|
||||
getInt32Memory0()[arg0 / 4 + 1] = len0;
|
||||
getInt32Memory0()[arg0 / 4 + 0] = ptr0;
|
||||
}, arguments) };
|
||||
imports.wbg.__wbg_instanceof_Element_1714e50f9bda1d15 = function(arg0) {
|
||||
const ret = getObject(arg0) instanceof Element;
|
||||
return ret;
|
||||
|
@ -383,6 +508,28 @@ function getImports() {
|
|||
imports.wbg.__wbg_setAttribute_8cfc462c0dedd03b = function() { return handleError(function (arg0, arg1, arg2, arg3, arg4) {
|
||||
getObject(arg0).setAttribute(getStringFromWasm0(arg1, arg2), getStringFromWasm0(arg3, arg4));
|
||||
}, arguments) };
|
||||
imports.wbg.__wbg_log_17733ab6fa45831d = function(arg0) {
|
||||
console.log(getObject(arg0));
|
||||
};
|
||||
imports.wbg.__wbg_instanceof_Response_240e67e5796c3c6b = function(arg0) {
|
||||
const ret = getObject(arg0) instanceof Response;
|
||||
return ret;
|
||||
};
|
||||
imports.wbg.__wbg_json_30d916f3f34485ab = function() { return handleError(function (arg0) {
|
||||
const ret = getObject(arg0).json();
|
||||
return addHeapObject(ret);
|
||||
}, arguments) };
|
||||
imports.wbg.__wbg_pathname_8ed2fc02f98aeaaf = function(arg0, arg1) {
|
||||
const ret = getObject(arg1).pathname;
|
||||
const ptr0 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
|
||||
const len0 = WASM_VECTOR_LEN;
|
||||
getInt32Memory0()[arg0 / 4 + 1] = len0;
|
||||
getInt32Memory0()[arg0 / 4 + 0] = ptr0;
|
||||
};
|
||||
imports.wbg.__wbg_new_d1d1300265e34170 = function() { return handleError(function (arg0, arg1) {
|
||||
const ret = new URL(getStringFromWasm0(arg0, arg1));
|
||||
return addHeapObject(ret);
|
||||
}, arguments) };
|
||||
imports.wbg.__wbg_value_eb32f706ae6bfab2 = function(arg0, arg1) {
|
||||
const ret = getObject(arg1).value;
|
||||
const ptr0 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
|
||||
|
@ -393,18 +540,9 @@ function getImports() {
|
|||
imports.wbg.__wbg_setvalue_3dd349be116107ce = function(arg0, arg1, arg2) {
|
||||
getObject(arg0).value = getStringFromWasm0(arg1, arg2);
|
||||
};
|
||||
imports.wbg.__wbg_setchecked_a450b330df6b3fa5 = function(arg0, arg1) {
|
||||
getObject(arg0).checked = arg1 !== 0;
|
||||
};
|
||||
imports.wbg.__wbg_value_30770021ca38e0db = function(arg0, arg1) {
|
||||
const ret = getObject(arg1).value;
|
||||
const ptr0 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
|
||||
const len0 = WASM_VECTOR_LEN;
|
||||
getInt32Memory0()[arg0 / 4 + 1] = len0;
|
||||
getInt32Memory0()[arg0 / 4 + 0] = ptr0;
|
||||
};
|
||||
imports.wbg.__wbg_setvalue_7b7950dacc5eb607 = function(arg0, arg1, arg2) {
|
||||
getObject(arg0).value = getStringFromWasm0(arg1, arg2);
|
||||
imports.wbg.__wbg_instanceof_Event_8c74064684d03e14 = function(arg0) {
|
||||
const ret = getObject(arg0) instanceof Event;
|
||||
return ret;
|
||||
};
|
||||
imports.wbg.__wbg_target_68a5c10e2732a79e = function(arg0) {
|
||||
const ret = getObject(arg0).target;
|
||||
|
@ -414,8 +552,16 @@ function getImports() {
|
|||
const ret = getObject(arg0).cancelBubble;
|
||||
return ret;
|
||||
};
|
||||
imports.wbg.__wbg_addEventListener_ec92ea1297eefdfc = function() { return handleError(function (arg0, arg1, arg2, arg3, arg4) {
|
||||
getObject(arg0).addEventListener(getStringFromWasm0(arg1, arg2), getObject(arg3), getObject(arg4));
|
||||
imports.wbg.__wbg_href_cae04ee9562fc683 = function(arg0, arg1) {
|
||||
const ret = getObject(arg1).href;
|
||||
const ptr0 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
|
||||
const len0 = WASM_VECTOR_LEN;
|
||||
getInt32Memory0()[arg0 / 4 + 1] = len0;
|
||||
getInt32Memory0()[arg0 / 4 + 0] = ptr0;
|
||||
};
|
||||
imports.wbg.__wbg_newwithstrandinit_de7c409ec8538105 = function() { return handleError(function (arg0, arg1, arg2) {
|
||||
const ret = new Request(getStringFromWasm0(arg0, arg1), getObject(arg2));
|
||||
return addHeapObject(ret);
|
||||
}, arguments) };
|
||||
imports.wbg.__wbg_newnoargs_971e9a5abe185139 = function(arg0, arg1) {
|
||||
const ret = new Function(getStringFromWasm0(arg0, arg1));
|
||||
|
@ -437,6 +583,18 @@ function getImports() {
|
|||
const ret = new Object();
|
||||
return addHeapObject(ret);
|
||||
};
|
||||
imports.wbg.__wbg_resolve_0107b3a501450ba0 = function(arg0) {
|
||||
const ret = Promise.resolve(getObject(arg0));
|
||||
return addHeapObject(ret);
|
||||
};
|
||||
imports.wbg.__wbg_then_18da6e5453572fc8 = function(arg0, arg1) {
|
||||
const ret = getObject(arg0).then(getObject(arg1));
|
||||
return addHeapObject(ret);
|
||||
};
|
||||
imports.wbg.__wbg_then_e5489f796341454b = function(arg0, arg1, arg2) {
|
||||
const ret = getObject(arg0).then(getObject(arg1), getObject(arg2));
|
||||
return addHeapObject(ret);
|
||||
};
|
||||
imports.wbg.__wbg_globalThis_3348936ac49df00a = function() { return handleError(function () {
|
||||
const ret = globalThis.globalThis;
|
||||
return addHeapObject(ret);
|
||||
|
@ -461,10 +619,6 @@ function getImports() {
|
|||
const ret = Reflect.set(getObject(arg0), getObject(arg1), getObject(arg2));
|
||||
return ret;
|
||||
}, arguments) };
|
||||
imports.wbg.__wbindgen_is_undefined = function(arg0) {
|
||||
const ret = getObject(arg0) === undefined;
|
||||
return ret;
|
||||
};
|
||||
imports.wbg.__wbindgen_debug_string = function(arg0, arg1) {
|
||||
const ret = debugString(getObject(arg1));
|
||||
const ptr0 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
|
||||
|
@ -475,8 +629,16 @@ function getImports() {
|
|||
imports.wbg.__wbindgen_throw = function(arg0, arg1) {
|
||||
throw new Error(getStringFromWasm0(arg0, arg1));
|
||||
};
|
||||
imports.wbg.__wbindgen_closure_wrapper1877 = function(arg0, arg1, arg2) {
|
||||
const ret = makeClosure(arg0, arg1, 97, __wbg_adapter_18);
|
||||
imports.wbg.__wbindgen_closure_wrapper7414 = function(arg0, arg1, arg2) {
|
||||
const ret = makeClosure(arg0, arg1, 466, __wbg_adapter_24);
|
||||
return addHeapObject(ret);
|
||||
};
|
||||
imports.wbg.__wbindgen_closure_wrapper8075 = function(arg0, arg1, arg2) {
|
||||
const ret = makeMutClosure(arg0, arg1, 520, __wbg_adapter_27);
|
||||
return addHeapObject(ret);
|
||||
};
|
||||
imports.wbg.__wbindgen_closure_wrapper8354 = function(arg0, arg1, arg2) {
|
||||
const ret = makeMutClosure(arg0, arg1, 525, __wbg_adapter_30);
|
||||
return addHeapObject(ret);
|
||||
};
|
||||
|
||||
|
@ -512,7 +674,7 @@ function initSync(bytes) {
|
|||
|
||||
async function init(input) {
|
||||
if (typeof input === 'undefined') {
|
||||
input = new URL('index-1257202110ca2b53_bg.wasm', import.meta.url);
|
||||
input = new URL('index-8b6dadb5b2545aea_bg.wasm', import.meta.url);
|
||||
}
|
||||
const imports = getImports();
|
||||
|
Binary file not shown.
|
@ -1,34 +1,12 @@
|
|||
<!DOCTYPE html><html><head>
|
||||
<meta charset="utf-8">
|
||||
<link rel="stylesheet" href="/tailwind-9741b801a155bf5f.css">
|
||||
<link href="https://cdn.jsdelivr.net/npm/@mdi/font@6.9.96/css/materialdesignicons.min.css" rel="stylesheet">
|
||||
<title>Yew App</title>
|
||||
|
||||
<link rel="preload" href="/index-1257202110ca2b53_bg.wasm" as="fetch" type="application/wasm" crossorigin="">
|
||||
<link rel="modulepreload" href="/index-1257202110ca2b53.js"></head>
|
||||
<body>
|
||||
<script type="module">import init from '/index-1257202110ca2b53.js';init('/index-1257202110ca2b53_bg.wasm');</script><script>(function () {
|
||||
var url = 'ws://' + window.location.host + '/_trunk/ws';
|
||||
var poll_interval = 5000;
|
||||
var reload_upon_connect = () => {
|
||||
window.setTimeout(
|
||||
() => {
|
||||
// when we successfully reconnect, we'll force a
|
||||
// reload (since we presumably lost connection to
|
||||
// trunk due to it being killed, so it will have
|
||||
// rebuilt on restart)
|
||||
var ws = new WebSocket(url);
|
||||
ws.onopen = () => window.location.reload();
|
||||
ws.onclose = reload_upon_connect;
|
||||
},
|
||||
poll_interval);
|
||||
};
|
||||
<link rel="preload" href="/index-8b6dadb5b2545aea_bg.wasm" as="fetch" type="application/wasm" crossorigin="">
|
||||
<link rel="modulepreload" href="/index-8b6dadb5b2545aea.js"></head>
|
||||
<body class="base theme-dark bg-gray-900 text-gray-400">
|
||||
|
||||
|
||||
var ws = new WebSocket(url);
|
||||
ws.onmessage = (ev) => {
|
||||
const msg = JSON.parse(ev.data);
|
||||
if (msg.reload) {
|
||||
window.location.reload();
|
||||
}
|
||||
};
|
||||
ws.onclose = reload_upon_connect;
|
||||
})()
|
||||
</script></body></html>
|
||||
<script type="module">import init from '/index-8b6dadb5b2545aea.js';init('/index-8b6dadb5b2545aea_bg.wasm');</script></body></html>
|
File diff suppressed because it is too large
Load Diff
|
@ -2,6 +2,10 @@
|
|||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<link data-trunk href="tailwind.css" rel="css">
|
||||
<link href="https://cdn.jsdelivr.net/npm/@mdi/font@6.9.96/css/materialdesignicons.min.css" rel="stylesheet">
|
||||
<title>Yew App</title>
|
||||
</head>
|
||||
<body class="base theme-dark bg-gray-900 text-gray-400">
|
||||
</body>
|
||||
</html>
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,59 @@
|
|||
use yew::{function_component, html, Callback, Classes, Component, Properties};
|
||||
|
||||
/*
|
||||
pub enum Msg {
|
||||
Click,
|
||||
}
|
||||
|
||||
pub struct Button;
|
||||
|
||||
impl Component for Button {
|
||||
type Message = Msg;
|
||||
type Properties = Props;
|
||||
|
||||
fn create(ctx: &yew::Context<Self>) -> Self {
|
||||
Self
|
||||
}
|
||||
|
||||
fn update(&mut self, ctx: &yew::Context<Self>, msg: Self::Message) -> bool {
|
||||
match msg {
|
||||
Msg::Click => ctx.props().onclick.emit(()),
|
||||
};
|
||||
|
||||
false
|
||||
}
|
||||
|
||||
fn view(&self, ctx: &yew::Context<Self>) -> yew::Html {
|
||||
let link = ctx.link().clone();
|
||||
|
||||
html! {
|
||||
<button class="bg-gray-700 hover:bg-gray-800 text-gray-400 font-bold py-2 px-2 rounded inline-flex items-center" onclick={link.callback(|_| Msg::Click)}>{ "+1" }</button>
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
#[derive(Properties, PartialEq, Default)]
|
||||
pub struct Props {
|
||||
pub onclick: Callback<()>,
|
||||
#[prop_or_default]
|
||||
pub text: String,
|
||||
#[prop_or_default]
|
||||
pub icon: String,
|
||||
}
|
||||
|
||||
#[function_component(Button)]
|
||||
pub fn button(props: &Props) -> Html {
|
||||
let mut icon_class = Classes::from("mdi");
|
||||
|
||||
if !props.icon.is_empty() {
|
||||
icon_class.push(&props.icon);
|
||||
}
|
||||
|
||||
html! {
|
||||
<button class="bg-gray-700 hover:bg-gray-800 text-gray-400 font-bold py-2 px-2 rounded inline-flex items-center" onclick={props.onclick.reform(move |_| ())}>
|
||||
<span class={icon_class}></span>
|
||||
<span>{ &props.text }</span>
|
||||
</button>
|
||||
}
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
mod button;
|
||||
mod table;
|
||||
|
||||
pub use button::Button;
|
||||
pub use table::Table;
|
||||
use yew::{function_component, html, Children, Html, Properties};
|
||||
|
||||
use wasm_bindgen::{JsCast, UnwrapThrowExt};
|
||||
use web_sys::{Event, HtmlInputElement, InputEvent};
|
||||
use yew::prelude::*;
|
||||
|
||||
#[derive(Clone, PartialEq, Properties)]
|
||||
pub struct InputProps {
|
||||
pub value: String,
|
||||
pub on_change: Callback<String>,
|
||||
}
|
||||
|
||||
fn get_value_from_input_event(e: InputEvent) -> String {
|
||||
let event: Event = e.dyn_into().unwrap_throw();
|
||||
let event_target = event.target().unwrap_throw();
|
||||
let target: HtmlInputElement = event_target.dyn_into().unwrap_throw();
|
||||
web_sys::console::log_1(&target.value().into());
|
||||
target.value()
|
||||
}
|
||||
|
||||
/// Controlled Text Input Component
|
||||
#[function_component(TextInput)]
|
||||
pub fn text_input(props: &InputProps) -> Html {
|
||||
let InputProps { value, on_change } = props.clone();
|
||||
|
||||
let oninput = Callback::from(move |input_event: InputEvent| {
|
||||
on_change.emit(get_value_from_input_event(input_event));
|
||||
});
|
||||
|
||||
html! {
|
||||
<input type="text" class="mx-2 appearance-none block bg-gray-700 text-slate-400 border border-gray-600 rounded py-2 px-2 w-10 leading-tight focus:outline-none focus:ring-1 focus:ring-gray-500 focus:border-gray-500" {value} {oninput} />
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Properties, PartialEq, Default)]
|
||||
pub struct PageProps {
|
||||
#[prop_or_default]
|
||||
pub children: Children,
|
||||
}
|
||||
|
||||
#[function_component(Page)]
|
||||
pub fn page(props: &PageProps) -> Html {
|
||||
html! { <div class="max-w-7xl mx-auto">{ for props.children.iter() }</div> }
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
use yew::{function_component, html, Children, Html, Properties};
|
||||
|
||||
#[derive(Properties, PartialEq, Default)]
|
||||
pub struct Props {
|
||||
pub headers: Vec<String>,
|
||||
pub rows: Vec<Vec<String>>,
|
||||
pub loading: bool,
|
||||
|
||||
#[prop_or_default]
|
||||
pub children: Children,
|
||||
}
|
||||
|
||||
#[function_component(Table)]
|
||||
pub fn table(props: &Props) -> Html {
|
||||
html! {
|
||||
<div class="inline-block min-w-full py-2 align-middle">
|
||||
<div class="overflow-hidden shadow ring-1 ring-black ring-opacity-5 md:rounded-lg">
|
||||
<table class="min-w-full divide-y divide-gray-600">
|
||||
<thead class="bg-gray-800">
|
||||
<tr>
|
||||
{props.headers.iter().map(|header| html! {
|
||||
<th scope="col" class="px-3 py-3.5 text-left text-sm font-semibold text-gray-400">{header}</th>
|
||||
}).collect::<Html>()}
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="divide-y divide-gray-600 bg-gray-700">
|
||||
{props.rows.iter().map(|row| html! {
|
||||
<tr>
|
||||
{row.iter().map(|value| html! {
|
||||
<td class="whitespace-nowrap px-3 py-4 text-sm text-gray-400">{value}</td>
|
||||
}).collect::<Html>()}
|
||||
</tr>
|
||||
}).collect::<Html>()}
|
||||
{ for props.children.iter() }
|
||||
{if props.loading == true { html! {
|
||||
<tr>
|
||||
<td colspan={(props.headers.len() + 1).to_string()} class="py-3">
|
||||
<div class="grid place-items-center">
|
||||
{ "Loading ..." }
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
}} else { html! {} }}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
}
|
135
web/src/main.rs
135
web/src/main.rs
|
@ -1,44 +1,133 @@
|
|||
use yew::prelude::*;
|
||||
mod components;
|
||||
mod pages;
|
||||
pub mod util;
|
||||
|
||||
enum Msg {
|
||||
AddOne,
|
||||
use pages::UsersPage;
|
||||
use yew::prelude::*;
|
||||
use yew_router::prelude::*;
|
||||
|
||||
#[derive(Clone, Debug, Routable, PartialEq)]
|
||||
enum Route {
|
||||
#[at("/")]
|
||||
Home,
|
||||
#[at("/users")]
|
||||
Users,
|
||||
#[at("/events")]
|
||||
Events,
|
||||
}
|
||||
|
||||
struct Model {
|
||||
value: i64,
|
||||
pages: Vec<Page>,
|
||||
}
|
||||
|
||||
impl Component for Model {
|
||||
type Message = Msg;
|
||||
type Message = ();
|
||||
type Properties = ();
|
||||
|
||||
fn create(_ctx: &Context<Self>) -> Self {
|
||||
Self { value: 0 }
|
||||
}
|
||||
|
||||
fn update(&mut self, _ctx: &Context<Self>, msg: Self::Message) -> bool {
|
||||
match msg {
|
||||
Msg::AddOne => {
|
||||
self.value += 1;
|
||||
// the value has changed so we need to
|
||||
// re-render for it to appear on the page
|
||||
true
|
||||
}
|
||||
Self {
|
||||
pages: vec![
|
||||
Page {
|
||||
target: Route::Home,
|
||||
name: "Home".into(),
|
||||
},
|
||||
Page {
|
||||
target: Route::Users,
|
||||
name: "Users".into(),
|
||||
},
|
||||
Page {
|
||||
target: Route::Events,
|
||||
name: "Events".into(),
|
||||
},
|
||||
],
|
||||
}
|
||||
}
|
||||
|
||||
fn view(&self, ctx: &Context<Self>) -> Html {
|
||||
// This gives us a component's "`Scope`" which allows us to send messages, etc to the component.
|
||||
let link = ctx.link();
|
||||
fn view(&self, _ctx: &Context<Self>) -> Html {
|
||||
html! {
|
||||
<div>
|
||||
<button onclick={link.callback(|_| Msg::AddOne)}>{ "+1" }</button>
|
||||
<p>{ self.value }</p>
|
||||
</div>
|
||||
<BrowserRouter>
|
||||
<Navbar pages={self.pages.clone()} />
|
||||
<Switch<Route> render={Switch::render(switch)} />
|
||||
</BrowserRouter>
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn switch(routes: &Route) -> Html {
|
||||
match routes {
|
||||
Route::Home => html! { <h1>{ "Home" }</h1> },
|
||||
Route::Users => html! {
|
||||
<UsersPage />
|
||||
},
|
||||
Route::Events => html! { <h1>{ "Events" }</h1> },
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
struct Page {
|
||||
name: String,
|
||||
target: Route,
|
||||
}
|
||||
|
||||
#[derive(Properties, PartialEq, Default)]
|
||||
struct NavbarProps {
|
||||
#[prop_or_default]
|
||||
pub children: Children,
|
||||
|
||||
pub pages: Vec<Page>,
|
||||
}
|
||||
|
||||
#[function_component(Navbar)]
|
||||
fn navbar(props: &NavbarProps) -> Html {
|
||||
let active_target = use_state(|| 0);
|
||||
|
||||
let history = use_history().unwrap();
|
||||
|
||||
let onclick = |i: usize| {
|
||||
let active_target = active_target.clone();
|
||||
let history = history.clone();
|
||||
let route = props.pages[i].target.clone();
|
||||
|
||||
Callback::from(move |_| {
|
||||
history.push(route.clone());
|
||||
active_target.set(i)
|
||||
})
|
||||
};
|
||||
|
||||
html! {
|
||||
<nav class="bg-gray-800">
|
||||
<div class="mx-auto max-w-7xl px-2 sm:px-6 lg:px-8">
|
||||
<div class="relative flex h-16 items-center justify-between">
|
||||
<div class="flex flex-1 items-center justify-center sm:items-stretch sm:justify-start">
|
||||
<div class="hidden sm:ml-6 sm:block">
|
||||
<div class="flex space-x-4">
|
||||
{
|
||||
props.pages.iter().enumerate().map(|(i, page)| {
|
||||
let mut link_class =
|
||||
Classes::from(&["text-sm", "font-medium", "rounded-md", "px-3", "py-2"] as &[&'static str]);
|
||||
|
||||
if *active_target == i {
|
||||
link_class.push(&["bg-gray-900", "text-gray-400"] as &[&'static str])
|
||||
} else {
|
||||
link_class.push(&["hover:bg-gray-700", "text-gray-400"] as &[&'static str])
|
||||
}
|
||||
|
||||
html! {
|
||||
<a role={"button"} onclick={onclick(i)} class={link_class}>{&page.name}</a>
|
||||
}
|
||||
}).collect::<Html>()
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{ for props.children.iter() }
|
||||
</div>
|
||||
</nav>
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
yew::start_app::<Model>();
|
||||
}
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
mod users;
|
||||
|
||||
pub use users::UsersPage;
|
|
@ -0,0 +1,107 @@
|
|||
use crate::components::{Button, Page, Table, TextInput};
|
||||
use lan_party_core::user::User;
|
||||
use wasm_bindgen_futures::spawn_local;
|
||||
use yew::prelude::*;
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
pub struct UsersPage {
|
||||
headers: Vec<String>,
|
||||
users: Vec<User>,
|
||||
score_edit: Option<usize>,
|
||||
current_score: String,
|
||||
}
|
||||
|
||||
pub enum Msg {
|
||||
UpdateList(Vec<User>),
|
||||
UpdateScoreInput(String),
|
||||
UpdateScore(usize),
|
||||
EditScore(usize),
|
||||
DeleteUser(usize),
|
||||
}
|
||||
|
||||
impl Component for UsersPage {
|
||||
type Message = Msg;
|
||||
type Properties = ();
|
||||
|
||||
fn create(ctx: &Context<Self>) -> Self {
|
||||
Self {
|
||||
headers: vec!["Username".into(), "Score".into(), "".into()],
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
|
||||
fn rendered(&mut self, ctx: &Context<Self>, first_render: bool) {
|
||||
let link = ctx.link().clone();
|
||||
|
||||
if first_render {
|
||||
spawn_local(async move {
|
||||
let res: Result<Vec<User>, _> =
|
||||
crate::util::api_request("GET", "/user", Option::<()>::None).await;
|
||||
link.send_message(Msg::UpdateList(res.unwrap()))
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
fn update(&mut self, _ctx: &Context<Self>, msg: Self::Message) -> bool {
|
||||
match msg {
|
||||
Msg::UpdateList(list) => {
|
||||
self.users = list;
|
||||
true
|
||||
}
|
||||
Msg::UpdateScoreInput(value) => {
|
||||
self.current_score = value;
|
||||
true
|
||||
}
|
||||
Msg::EditScore(i) => {
|
||||
self.current_score = self.users[i].score.to_string();
|
||||
self.score_edit = Some(i);
|
||||
true
|
||||
}
|
||||
Msg::UpdateScore(i) => {
|
||||
self.score_edit = None;
|
||||
true
|
||||
}
|
||||
Msg::DeleteUser(i) => true,
|
||||
_ => todo!(),
|
||||
}
|
||||
}
|
||||
|
||||
fn view(&self, ctx: &Context<Self>) -> Html {
|
||||
let link = ctx.link().clone();
|
||||
|
||||
html! {
|
||||
<Page>
|
||||
<Table headers={self.headers.clone()} loading=false rows={vec![]}>
|
||||
{self.users.iter().enumerate().map(|(i, user)| html! {
|
||||
<tr>
|
||||
<td class="whitespace-nowrap px-3 py-4 text-sm text-slate-400">{&user.name}</td>
|
||||
<td class="whitespace-nowrap px-3 text-sm text-slate-400">
|
||||
{if Some(i) == self.score_edit { html! {
|
||||
<>
|
||||
<span class="inline-block">
|
||||
<TextInput
|
||||
on_change={link.callback(Msg::UpdateScoreInput)}
|
||||
value={self.current_score.clone()}
|
||||
/>
|
||||
</span>
|
||||
<Button icon={"mdi-check"} onclick={link.callback(move |_| Msg::UpdateScore(i))} />
|
||||
</>
|
||||
}} else { html! {
|
||||
<>
|
||||
<span class="my-3 w-20">
|
||||
{user.score}
|
||||
</span>
|
||||
<Button icon={"mdi-pencil"} onclick={link.callback(move |_| Msg::EditScore(i))} />
|
||||
</>
|
||||
}}}
|
||||
</td>
|
||||
<td class="whitespace-nowrap py-4 text-sm text-slate-400">
|
||||
<Button icon={"mdi-delete"} onclick={link.callback(move |_| Msg::DeleteUser(i))} />
|
||||
</td>
|
||||
</tr>
|
||||
}).collect::<Html>()}
|
||||
</Table>
|
||||
</Page>
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
use serde::{Deserialize, Serialize};
|
||||
use thiserror::Error;
|
||||
use wasm_bindgen::{prelude::*, JsCast};
|
||||
use wasm_bindgen_futures::JsFuture;
|
||||
use web_sys::{Headers, Request, RequestInit, RequestMode, Response};
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
pub enum FetchError {
|
||||
#[error("javascript error")]
|
||||
JsError(JsValue),
|
||||
#[error("failed to serialize json: {source:?}")]
|
||||
SerializationError {
|
||||
#[from]
|
||||
source: serde_json::Error,
|
||||
},
|
||||
}
|
||||
|
||||
impl From<JsValue> for FetchError {
|
||||
fn from(value: JsValue) -> Self {
|
||||
Self::JsError(value)
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn api_request<B: Serialize, R: for<'a> Deserialize<'a>>(
|
||||
method: &str,
|
||||
endpoint: &str,
|
||||
body: Option<B>,
|
||||
) -> Result<R, FetchError> {
|
||||
let api_key = "7de10bf6-278d-11ed-ad60-a8a15919d1b3";
|
||||
|
||||
let mut req_opts = RequestInit::new();
|
||||
req_opts.method(method);
|
||||
|
||||
let headers = Headers::new()?;
|
||||
headers.append("X-API-Key", api_key)?;
|
||||
req_opts.headers(&headers);
|
||||
|
||||
if let Some(body) = body {
|
||||
let value = JsValue::from_serde(&body)?;
|
||||
req_opts.body(Some(&value));
|
||||
}
|
||||
|
||||
let request = Request::new_with_str_and_init(
|
||||
&format!("http://localhost:8000/api/{}", endpoint),
|
||||
&req_opts,
|
||||
)?;
|
||||
|
||||
let window = web_sys::window().unwrap();
|
||||
let resp_value = JsFuture::from(window.fetch_with_request(&request)).await?;
|
||||
let resp: Response = resp_value.dyn_into().unwrap();
|
||||
|
||||
Ok(JsFuture::from(resp.json()?).await?.into_serde()?)
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
module.exports = {
|
||||
purge: [],
|
||||
darkMode: false, // or 'media' or 'class'
|
||||
theme: {
|
||||
extend: {},
|
||||
},
|
||||
variants: {
|
||||
extend: {},
|
||||
},
|
||||
plugins: [],
|
||||
}
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue