This commit is contained in:
Daan Vanoverloop 2022-09-04 19:43:16 +02:00
parent 77d2ce983e
commit 00814fa01c
Signed by: Danacus
GPG Key ID: F2272B50E129FC5C
20 changed files with 365367 additions and 179 deletions

74
Cargo.lock generated
View File

@ -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",
]

View File

@ -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 {

View File

@ -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,
}

View File

@ -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.

View File

@ -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();

BIN
web/dist/index-8b6dadb5b2545aea_bg.wasm vendored Normal file

Binary file not shown.

36
web/dist/index.html vendored
View File

@ -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>

182269
web/dist/tailwind-9741b801a155bf5f.css vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@ -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>

3
web/materialdesignicons.min.css vendored Normal file

File diff suppressed because one or more lines are too long

View File

@ -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>
}
}

49
web/src/components/mod.rs Normal file
View File

@ -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> }
}

View File

@ -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>
}
}

View File

@ -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>();
}

3
web/src/pages/mod.rs Normal file
View File

@ -0,0 +1,3 @@
mod users;
pub use users::UsersPage;

107
web/src/pages/users.rs Normal file
View File

@ -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>
}
}
}

53
web/src/util.rs Normal file
View File

@ -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()?)
}

11
web/tailwind.config.js Normal file
View File

@ -0,0 +1,11 @@
module.exports = {
purge: [],
darkMode: false, // or 'media' or 'class'
theme: {
extend: {},
},
variants: {
extend: {},
},
plugins: [],
}

182269
web/tailwind.css Normal file

File diff suppressed because it is too large Load Diff