Add web frontend in Yew
This commit is contained in:
82
Cargo.lock
generated
82
Cargo.lock
generated
@@ -486,6 +486,11 @@ dependencies = [
|
|||||||
name = "contextswitch-web"
|
name = "contextswitch-web"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"contextswitch",
|
||||||
|
"reqwasm",
|
||||||
|
"serde",
|
||||||
|
"uikit-rs",
|
||||||
|
"wasm-bindgen-futures",
|
||||||
"yew",
|
"yew",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -524,9 +529,9 @@ checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cpufeatures"
|
name = "cpufeatures"
|
||||||
version = "0.2.1"
|
version = "0.2.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "95059428f66df56b63431fdb4e1947ed2190586af5c5a8a8b71122bdf5a7f469"
|
checksum = "59a6001667ab124aebae2a495118e11d30984c3a653e99d86d58971708cf5e4b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
@@ -803,6 +808,26 @@ dependencies = [
|
|||||||
"web-sys",
|
"web-sys",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "gloo-net"
|
||||||
|
version = "0.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2899cb1a13be9020b010967adc6b2a8a343b6f1428b90238c9d53ca24decc6db"
|
||||||
|
dependencies = [
|
||||||
|
"futures-channel",
|
||||||
|
"futures-core",
|
||||||
|
"futures-sink",
|
||||||
|
"gloo-utils",
|
||||||
|
"js-sys",
|
||||||
|
"pin-project",
|
||||||
|
"serde",
|
||||||
|
"serde_json",
|
||||||
|
"thiserror",
|
||||||
|
"wasm-bindgen",
|
||||||
|
"wasm-bindgen-futures",
|
||||||
|
"web-sys",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "gloo-render"
|
name = "gloo-render"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
@@ -1048,9 +1073,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libc"
|
name = "libc"
|
||||||
version = "0.2.119"
|
version = "0.2.121"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1bf2e165bb3457c8e098ea76f3e3bc9db55f87aa90d52d0e6be741470916aaa4"
|
checksum = "efaa7b300f3b5fe8eb6bf21ce3895e1751d9665086af2d64b42f19701015ff4f"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "linked-hash-map"
|
name = "linked-hash-map"
|
||||||
@@ -1145,9 +1170,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "mio"
|
name = "mio"
|
||||||
version = "0.8.1"
|
version = "0.8.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7ba42135c6a5917b9db9cd7b293e5409e1c6b041e6f9825e92e55a894c63b6f8"
|
checksum = "52da4364ffb0e4fe33a9841a98a3f3014fb964045ce4f7a45a398243c8d6b0c9"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
"log",
|
"log",
|
||||||
@@ -1195,13 +1220,12 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nom"
|
name = "nom"
|
||||||
version = "7.1.0"
|
version = "7.1.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1b1d11e1ef389c76fe5b81bcaf2ea32cf88b62bc494e19f493d0b30e7a930109"
|
checksum = "a8903e5a29a317527874d0402f867152a3d21c908bb0b933e416c65e301d4c36"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"memchr",
|
"memchr",
|
||||||
"minimal-lexical",
|
"minimal-lexical",
|
||||||
"version_check",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -1244,9 +1268,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "num_threads"
|
name = "num_threads"
|
||||||
version = "0.1.4"
|
version = "0.1.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c539a50b93a303167eded6e8dff5220cd39447409fb659f4cd24b1f72fe4f133"
|
checksum = "aba1801fb138d8e85e11d0fc70baf4fe1cdfffda7c6cd34a854905df588e5ed0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
@@ -1501,9 +1525,9 @@ checksum = "a993555f31e5a609f617c12db6250dedcac1b0a85076912c436e6fc9b2c8e6a3"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "quote"
|
name = "quote"
|
||||||
version = "1.0.15"
|
version = "1.0.16"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "864d3e96a899863136fc6e99f3d7cae289dafe43bf2c5ac19b70df7210c0a145"
|
checksum = "b4af2ec4714533fcdf07e886f17025ace8b997b9ce51204ee69b6da831c3da57"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
]
|
]
|
||||||
@@ -1592,10 +1616,19 @@ dependencies = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "reqwest"
|
name = "reqwasm"
|
||||||
version = "0.11.9"
|
version = "0.5.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "87f242f1488a539a79bac6dbe7c8609ae43b7914b7736210f239a37cccb32525"
|
checksum = "05b89870d729c501fa7a68c43bf4d938bbb3a8c156d333d90faa0e8b3e3212fb"
|
||||||
|
dependencies = [
|
||||||
|
"gloo-net",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "reqwest"
|
||||||
|
version = "0.11.10"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "46a1f7aa4f35e5e8b4160449f51afc758f0ce6454315a9fa7d0d113e958c41eb"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"base64",
|
"base64",
|
||||||
"bytes",
|
"bytes",
|
||||||
@@ -1847,9 +1880,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "syn"
|
name = "syn"
|
||||||
version = "1.0.86"
|
version = "1.0.89"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8a65b3f4ffa0092e9887669db0eae07941f023991ab58ea44da8fe8e2d511c6b"
|
checksum = "ea297be220d52398dcc07ce15a209fce436d361735ac1db700cab3b6cdfb9f54"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
@@ -2160,6 +2193,15 @@ version = "0.1.3"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "56dee185309b50d1f11bfedef0fe6d036842e3fb77413abef29f8f8d1c5d4c1c"
|
checksum = "56dee185309b50d1f11bfedef0fe6d036842e3fb77413abef29f8f8d1c5d4c1c"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "uikit-rs"
|
||||||
|
version = "0.1.0"
|
||||||
|
source = "git+https://github.com/dax/uikit-rs.git#2414ccb2878a1cbec7bbe32b8ebd217b0684d0a8"
|
||||||
|
dependencies = [
|
||||||
|
"regex",
|
||||||
|
"yew",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicode-bidi"
|
name = "unicode-bidi"
|
||||||
version = "0.3.7"
|
version = "0.3.7"
|
||||||
@@ -2397,9 +2439,9 @@ checksum = "504a2476202769977a040c6364301a3f65d0cc9e3fb08600b2bda150a0488316"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "winreg"
|
name = "winreg"
|
||||||
version = "0.7.0"
|
version = "0.10.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0120db82e8a1e0b9fb3345a539c478767c0048d842860994d96113d5b667bd69"
|
checksum = "80d0f4e272c85def139476380b12f9ac60926689dd2e01d4923222f40580869d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"winapi",
|
"winapi",
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ condition = {}
|
|||||||
workspace = false
|
workspace = false
|
||||||
|
|
||||||
[tasks.run-api]
|
[tasks.run-api]
|
||||||
install_crate = "bunyan"
|
install_crate = { crate_name = "bunyan", binary = "bunyan" }
|
||||||
env = { "CONFIG_PATH" = "api/config", "TASKRC" = "$PWD/api/taskrc" }
|
env = { "CONFIG_PATH" = "api/config", "TASKRC" = "$PWD/api/taskrc" }
|
||||||
command = "bash"
|
command = "bash"
|
||||||
args = ["-c", "cargo run -p contextswitch-api | bunyan"]
|
args = ["-c", "cargo run -p contextswitch-api | bunyan"]
|
||||||
@@ -29,7 +29,7 @@ workspace = false
|
|||||||
watch = { watch = ["./api/"], no_git_ignore = true }
|
watch = { watch = ["./api/"], no_git_ignore = true }
|
||||||
|
|
||||||
[tasks.run-web]
|
[tasks.run-web]
|
||||||
install_crate = "trunk"
|
install_crate = { crate_name = "trunk", binary = "trunk" }
|
||||||
command = "bash"
|
command = "bash"
|
||||||
args = ["-c", "cd web; trunk serve"]
|
args = ["-c", "cd web; trunk serve"]
|
||||||
workspace = false
|
workspace = false
|
||||||
|
|||||||
@@ -4,9 +4,17 @@ version = "0.1.0"
|
|||||||
edition = "2021"
|
edition = "2021"
|
||||||
authors = ["David Rousselie <david@rousselie.name>"]
|
authors = ["David Rousselie <david@rousselie.name>"]
|
||||||
|
|
||||||
|
[lib]
|
||||||
|
path = "src/lib.rs"
|
||||||
|
|
||||||
[[bin]]
|
[[bin]]
|
||||||
path = "src/main.rs"
|
path = "src/main.rs"
|
||||||
name = "contextswitch-web"
|
name = "contextswitch-web"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
contextswitch = { path = ".." }
|
||||||
yew = "0.19"
|
yew = "0.19"
|
||||||
|
reqwasm = "0.5"
|
||||||
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
|
wasm-bindgen-futures = "0.4"
|
||||||
|
uikit-rs = { git = "https://github.com/dax/uikit-rs.git" }
|
||||||
|
|||||||
1
web/css/uikit.min.css
vendored
Normal file
1
web/css/uikit.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
@@ -3,5 +3,11 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8" />
|
<meta charset="utf-8" />
|
||||||
<title>Contextswitch</title>
|
<title>Contextswitch</title>
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<link rel="stylesheet" href="css/uikit.min.css" />
|
||||||
|
<script src="js/uikit.min.js"></script>
|
||||||
|
<script src="js/uikit-icons.min.js"></script>
|
||||||
|
<link data-trunk rel="copy-dir" href="css" />
|
||||||
|
<link data-trunk rel="copy-dir" href="js" />
|
||||||
</head>
|
</head>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
1
web/js/uikit-icons.min.js
vendored
Normal file
1
web/js/uikit-icons.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
1
web/js/uikit.min.js
vendored
Normal file
1
web/js/uikit.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
2
web/src/components/mod.rs
Normal file
2
web/src/components/mod.rs
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
pub mod task;
|
||||||
|
pub mod tasks_list;
|
||||||
190
web/src/components/task.rs
Normal file
190
web/src/components/task.rs
Normal file
@@ -0,0 +1,190 @@
|
|||||||
|
use contextswitch;
|
||||||
|
use uikit_rs as uk;
|
||||||
|
use yew::{classes, function_component, html, Callback, Classes, Html, MouseEvent, Properties};
|
||||||
|
|
||||||
|
#[derive(Properties, PartialEq)]
|
||||||
|
pub struct TaskProps {
|
||||||
|
pub task: contextswitch::Task,
|
||||||
|
#[prop_or_default]
|
||||||
|
pub selected: bool,
|
||||||
|
#[prop_or_default]
|
||||||
|
pub on_task_select: Callback<Option<contextswitch::Task>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[function_component(Task)]
|
||||||
|
pub fn task(
|
||||||
|
TaskProps {
|
||||||
|
task,
|
||||||
|
selected,
|
||||||
|
on_task_select,
|
||||||
|
}: &TaskProps,
|
||||||
|
) -> Html {
|
||||||
|
let toggle_details = {
|
||||||
|
let task = task.clone();
|
||||||
|
let on_task_select = on_task_select.clone();
|
||||||
|
let is_task_selected = *selected;
|
||||||
|
Callback::from(move |_| {
|
||||||
|
on_task_select.emit(if is_task_selected {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(task.clone())
|
||||||
|
})
|
||||||
|
})
|
||||||
|
};
|
||||||
|
|
||||||
|
let text_style = if task.status == contextswitch::Status::Completed {
|
||||||
|
uk::Text::Success
|
||||||
|
} else {
|
||||||
|
uk::Text::Emphasis
|
||||||
|
};
|
||||||
|
let arrow = if *selected {
|
||||||
|
uk::IconType::TriangleDown
|
||||||
|
} else {
|
||||||
|
uk::IconType::TriangleRight
|
||||||
|
};
|
||||||
|
|
||||||
|
let task_status_class: Classes = format!("task-status-{}", task.status).into();
|
||||||
|
let bookmark_count = if let Some(contextswitch) = &task.contextswitch {
|
||||||
|
contextswitch.bookmarks.len()
|
||||||
|
} else {
|
||||||
|
0
|
||||||
|
};
|
||||||
|
|
||||||
|
html! {
|
||||||
|
<uk::Card size={uk::CardSize::Small}
|
||||||
|
style={uk::CardStyle::Default}
|
||||||
|
hover={true}
|
||||||
|
width={uk::Width::_1_1}
|
||||||
|
class={task_status_class}>
|
||||||
|
<uk::CardBody padding={vec![uk::Padding::RemoveVertical]}
|
||||||
|
margin={vec![uk::Margin::SmallTop, uk::Margin::SmallBottom]}>
|
||||||
|
<uk::Grid gap_size={uk::GridGapSize::Small}
|
||||||
|
vertical_alignement={uk::FlexVerticalAlignement::Middle}>
|
||||||
|
<uk::Icon icon_type={uk::IconType::Check}
|
||||||
|
text_style={vec![text_style]} />
|
||||||
|
<TaskDescription task={task.clone()}
|
||||||
|
onclick={toggle_details.clone()} />
|
||||||
|
<uk::IconNav>
|
||||||
|
<li>
|
||||||
|
<uk::Icon icon_type={uk::IconType::FileEdit} href="#" />
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<uk::Link href="#" onclick={toggle_details.clone()}>
|
||||||
|
<uk::Icon icon_type={uk::IconType::Bookmark} />
|
||||||
|
<span> {bookmark_count}</span>
|
||||||
|
</uk::Link>
|
||||||
|
</li>
|
||||||
|
</uk::IconNav>
|
||||||
|
<uk::Icon icon_type={arrow} href="#" onclick={toggle_details} />
|
||||||
|
</uk::Grid>
|
||||||
|
{
|
||||||
|
if *selected {
|
||||||
|
html! {
|
||||||
|
<TaskDetails task={task.clone()} />
|
||||||
|
}
|
||||||
|
} else { html! {} }
|
||||||
|
}
|
||||||
|
</uk::CardBody>
|
||||||
|
</uk::Card>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Properties, PartialEq)]
|
||||||
|
pub struct TaskDescriptionProps {
|
||||||
|
pub task: contextswitch::Task,
|
||||||
|
#[prop_or_default]
|
||||||
|
pub onclick: Callback<MouseEvent>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[function_component(TaskDescription)]
|
||||||
|
pub fn task_description(TaskDescriptionProps { task, onclick }: &TaskDescriptionProps) -> Html {
|
||||||
|
html! {
|
||||||
|
<uk::Flex width={uk::Width::_Expand} onclick={onclick}>
|
||||||
|
<uk::CardTitle text_style={vec![uk::Text::Lighter]}>
|
||||||
|
{task.description.clone()}
|
||||||
|
</uk::CardTitle>
|
||||||
|
</uk::Flex>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Properties, PartialEq)]
|
||||||
|
pub struct TaskDetailsProps {
|
||||||
|
pub task: contextswitch::Task,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[function_component(TaskDetails)]
|
||||||
|
pub fn task_details(TaskDetailsProps { task }: &TaskDetailsProps) -> Html {
|
||||||
|
let priority = task
|
||||||
|
.priority
|
||||||
|
.as_ref()
|
||||||
|
.map(|prio| prio.to_string())
|
||||||
|
.unwrap_or_else(|| "-".to_string());
|
||||||
|
let project = task
|
||||||
|
.project
|
||||||
|
.as_ref()
|
||||||
|
.map(|proj| proj.to_string())
|
||||||
|
.unwrap_or_else(|| "-".to_string());
|
||||||
|
|
||||||
|
html! {
|
||||||
|
<div class={classes!(uk::Margin::Small)}>
|
||||||
|
<uk::Divider margin={vec![uk::Margin::Small]} />
|
||||||
|
{
|
||||||
|
if let Some(contextswitch) = &task.contextswitch {
|
||||||
|
html! {
|
||||||
|
<TaskContextswitch contextswitch={contextswitch.clone()} />
|
||||||
|
}
|
||||||
|
} else { html! {} }
|
||||||
|
}
|
||||||
|
<uk::Grid gap_size={uk::GridGapSize::Small}
|
||||||
|
child_width={uk::ChildWidth::_Expand}>
|
||||||
|
<span class={classes!(uk::Text::Meta)}>
|
||||||
|
{ format!("priority: {}", priority) }
|
||||||
|
</span>
|
||||||
|
<span class={classes!(uk::Text::Meta)}>
|
||||||
|
{ format!("project: {}", project) }
|
||||||
|
</span>
|
||||||
|
</uk::Grid>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Properties, PartialEq)]
|
||||||
|
pub struct TaskContextswitchProps {
|
||||||
|
pub contextswitch: contextswitch::ContextswitchData,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[function_component(TaskContextswitch)]
|
||||||
|
pub fn task_contextswitch(
|
||||||
|
TaskContextswitchProps { contextswitch }: &TaskContextswitchProps,
|
||||||
|
) -> Html {
|
||||||
|
html! {
|
||||||
|
<uk::Grid gap_size={uk::GridGapSize::Small} height_match={true}>
|
||||||
|
{
|
||||||
|
contextswitch.bookmarks.iter().map(|bookmark| {
|
||||||
|
html! {
|
||||||
|
<TaskBookmark bookmark={bookmark.clone()} />
|
||||||
|
}
|
||||||
|
}).collect::<Html>()
|
||||||
|
}
|
||||||
|
<uk::Icon icon_type={uk::IconType::Plus}
|
||||||
|
margin={vec![uk::Margin::Remove]} />
|
||||||
|
</uk::Grid>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Properties, PartialEq)]
|
||||||
|
pub struct TaskBookmarkProps {
|
||||||
|
pub bookmark: contextswitch::Bookmark,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[function_component(TaskBookmark)]
|
||||||
|
pub fn task_bookmark(TaskBookmarkProps { bookmark }: &TaskBookmarkProps) -> Html {
|
||||||
|
html! {
|
||||||
|
<div class={classes!(uk::Width::_1_1, uk::Text::Small, uk::Margin::Remove)}>
|
||||||
|
<uk::Grid gap_size={uk::GridGapSize::Small} vertical_alignement={uk::FlexVerticalAlignement::Middle}>
|
||||||
|
<uk::Icon icon_type={uk::IconType::Bookmark} />
|
||||||
|
<uk::Link href={bookmark.uri.to_string()}>{bookmark.uri.to_string()}</uk::Link>
|
||||||
|
</uk::Grid>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
}
|
||||||
38
web/src/components/tasks_list.rs
Normal file
38
web/src/components/tasks_list.rs
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
use crate::components::task;
|
||||||
|
use contextswitch::Task;
|
||||||
|
use yew::prelude::*;
|
||||||
|
|
||||||
|
#[derive(Properties, PartialEq)]
|
||||||
|
pub struct TasksListProps {
|
||||||
|
#[prop_or_default]
|
||||||
|
pub tasks: Vec<Task>,
|
||||||
|
#[prop_or_default]
|
||||||
|
pub selected_task: Option<Task>,
|
||||||
|
#[prop_or_default]
|
||||||
|
pub on_task_select: Callback<Option<Task>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[function_component(TasksList)]
|
||||||
|
pub fn tasks_list(
|
||||||
|
TasksListProps {
|
||||||
|
tasks,
|
||||||
|
selected_task,
|
||||||
|
on_task_select,
|
||||||
|
}: &TasksListProps,
|
||||||
|
) -> Html {
|
||||||
|
tasks
|
||||||
|
.iter()
|
||||||
|
.map(|task| {
|
||||||
|
let task_is_selected = selected_task
|
||||||
|
.clone()
|
||||||
|
.map(|t| t.id == task.id)
|
||||||
|
.unwrap_or(false);
|
||||||
|
|
||||||
|
html! {
|
||||||
|
<task::Task selected={task_is_selected}
|
||||||
|
on_task_select={on_task_select}
|
||||||
|
task={task.clone()} />
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
62
web/src/lib.rs
Normal file
62
web/src/lib.rs
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
use components::tasks_list::TasksList;
|
||||||
|
use contextswitch::Task;
|
||||||
|
use reqwasm::http::Request;
|
||||||
|
use uikit_rs as uk;
|
||||||
|
use yew::prelude::*;
|
||||||
|
|
||||||
|
mod components;
|
||||||
|
|
||||||
|
#[function_component(App)]
|
||||||
|
pub fn app() -> Html {
|
||||||
|
let tasks = use_state(Vec::new);
|
||||||
|
{
|
||||||
|
let tasks = tasks.clone();
|
||||||
|
use_effect_with_deps(
|
||||||
|
move |_| {
|
||||||
|
wasm_bindgen_futures::spawn_local(async move {
|
||||||
|
let fetched_tasks: Vec<Task> =
|
||||||
|
Request::get("http://localhost:8000/tasks?filter=task")
|
||||||
|
.send()
|
||||||
|
.await
|
||||||
|
.unwrap() // TODO
|
||||||
|
.json()
|
||||||
|
.await
|
||||||
|
.unwrap(); // TODO
|
||||||
|
tasks.set(fetched_tasks);
|
||||||
|
});
|
||||||
|
|| ()
|
||||||
|
},
|
||||||
|
(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
let selected_task = use_state(|| None);
|
||||||
|
let on_task_select = {
|
||||||
|
let selected_task = selected_task.clone();
|
||||||
|
Callback::from(move |task: Option<Task>| {
|
||||||
|
selected_task.set(task);
|
||||||
|
})
|
||||||
|
};
|
||||||
|
|
||||||
|
html! {
|
||||||
|
<uk::Section style={uk::SectionStyle::Default}>
|
||||||
|
<uk::Container size={uk::ContainerSize::Small}>
|
||||||
|
<uk::Filter target=".status-filter"
|
||||||
|
filter_width={uk::Width::_Expand}
|
||||||
|
filter_component={uk::UIKitComponent::SubNav}
|
||||||
|
filter_class={"uk-subnav-pill"}
|
||||||
|
filters={vec![uk::FilterData { class: "".to_string(), label: "all".to_string() },
|
||||||
|
uk::FilterData { class: ".task-status-pending".to_string(), label: "pending".to_string() },
|
||||||
|
uk::FilterData { class: ".task-status-completed".to_string(), label: "completed".to_string() }]}>
|
||||||
|
<uk::Grid gap_size={uk::GridGapSize::Small}
|
||||||
|
margin={vec![uk::Margin::Default]}
|
||||||
|
height_match={true}
|
||||||
|
class={"status-filter"}>
|
||||||
|
<TasksList tasks={(*tasks).clone()}
|
||||||
|
selected_task={(*selected_task).clone()}
|
||||||
|
on_task_select={on_task_select} />
|
||||||
|
</uk::Grid>
|
||||||
|
</uk::Filter>
|
||||||
|
</uk::Container>
|
||||||
|
</uk::Section>
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,11 +1,4 @@
|
|||||||
use yew::prelude::*;
|
use contextswitch_web::App;
|
||||||
|
|
||||||
#[function_component(App)]
|
|
||||||
fn app() -> Html {
|
|
||||||
html! {
|
|
||||||
<h1>{ "Hello World" }</h1>
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
yew::start_app::<App>();
|
yew::start_app::<App>();
|
||||||
|
|||||||
Reference in New Issue
Block a user