Compare commits
No commits in common. "master" and "6d4e8462b8cd89253a812e8e930f63b4db5bede8" have entirely different histories.
master
...
6d4e8462b8
|
|
@ -1,5 +1,4 @@
|
|||
*~
|
||||
/dist
|
||||
|
||||
# Added by cargo
|
||||
|
||||
|
|
|
|||
|
|
@ -31,95 +31,6 @@ version = "1.0.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||
|
||||
[[package]]
|
||||
name = "futures"
|
||||
version = "0.3.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f73fe65f54d1e12b726f517d3e2135ca3125a437b6d998caf1962961f7172d9e"
|
||||
dependencies = [
|
||||
"futures-channel",
|
||||
"futures-core",
|
||||
"futures-executor",
|
||||
"futures-io",
|
||||
"futures-sink",
|
||||
"futures-task",
|
||||
"futures-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures-channel"
|
||||
version = "0.3.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c3083ce4b914124575708913bca19bfe887522d6e2e6d0952943f5eac4a74010"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
"futures-sink",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures-core"
|
||||
version = "0.3.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0c09fd04b7e4073ac7156a9539b57a484a8ea920f79c7c675d05d289ab6110d3"
|
||||
|
||||
[[package]]
|
||||
name = "futures-executor"
|
||||
version = "0.3.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9420b90cfa29e327d0429f19be13e7ddb68fa1cccb09d65e5706b8c7a749b8a6"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
"futures-task",
|
||||
"futures-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures-io"
|
||||
version = "0.3.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fc4045962a5a5e935ee2fdedaa4e08284547402885ab326734432bed5d12966b"
|
||||
|
||||
[[package]]
|
||||
name = "futures-macro"
|
||||
version = "0.3.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "33c1e13800337f4d4d7a316bf45a567dbcb6ffe087f16424852d97e97a91f512"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures-sink"
|
||||
version = "0.3.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "21163e139fa306126e6eedaf49ecdb4588f939600f0b1e770f4205ee4b7fa868"
|
||||
|
||||
[[package]]
|
||||
name = "futures-task"
|
||||
version = "0.3.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "57c66a976bf5909d801bbef33416c41372779507e7a6b3a5e25e4749c58f776a"
|
||||
|
||||
[[package]]
|
||||
name = "futures-util"
|
||||
version = "0.3.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d8b7abd5d659d9b90c8cba917f6ec750a74e2dc23902ef9cd4cc8c8b22e6036a"
|
||||
dependencies = [
|
||||
"futures-channel",
|
||||
"futures-core",
|
||||
"futures-io",
|
||||
"futures-macro",
|
||||
"futures-sink",
|
||||
"futures-task",
|
||||
"memchr",
|
||||
"pin-project-lite",
|
||||
"pin-utils",
|
||||
"slab",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "getrandom"
|
||||
version = "0.1.16"
|
||||
|
|
@ -146,18 +57,6 @@ dependencies = [
|
|||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gloo-timers"
|
||||
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",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.12.3"
|
||||
|
|
@ -196,10 +95,7 @@ dependencies = [
|
|||
name = "kikikoz"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"futures",
|
||||
"getrandom 0.2.7",
|
||||
"gloo-timers",
|
||||
"js-sys",
|
||||
"rand",
|
||||
"sycamore",
|
||||
"web-sys",
|
||||
|
|
@ -226,12 +122,6 @@ dependencies = [
|
|||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
|
||||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
version = "1.13.0"
|
||||
|
|
@ -244,18 +134,6 @@ version = "1.0.7"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0c520e05135d6e763148b6426a837e239041653ba7becd2e538c076c738025fc"
|
||||
|
||||
[[package]]
|
||||
name = "pin-project-lite"
|
||||
version = "0.2.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116"
|
||||
|
||||
[[package]]
|
||||
name = "pin-utils"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
|
||||
|
||||
[[package]]
|
||||
name = "ppv-lite86"
|
||||
version = "0.2.16"
|
||||
|
|
@ -321,15 +199,6 @@ dependencies = [
|
|||
"rand_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "slab"
|
||||
version = "0.4.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4614a76b2a8be0058caa9dbbaf66d988527d86d003c11a94fbd335d7661edcef"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "slotmap"
|
||||
version = "1.0.6"
|
||||
|
|
@ -352,17 +221,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "3a3fad8d7500e6f00f7415f3f3b4d7c465b9edce7eaa9f2d725ced0f99fae3c2"
|
||||
dependencies = [
|
||||
"ahash",
|
||||
"futures",
|
||||
"indexmap",
|
||||
"js-sys",
|
||||
"paste",
|
||||
"sycamore-core",
|
||||
"sycamore-futures",
|
||||
"sycamore-macro",
|
||||
"sycamore-reactive",
|
||||
"sycamore-web",
|
||||
"wasm-bindgen",
|
||||
"wasm-bindgen-futures",
|
||||
"web-sys",
|
||||
]
|
||||
|
||||
|
|
@ -376,18 +242,6 @@ dependencies = [
|
|||
"sycamore-reactive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sycamore-futures"
|
||||
version = "0.8.0-beta.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "faebade534e638217448ebc6b4cc7a52471ce055a04090e9e628e783bf629e4e"
|
||||
dependencies = [
|
||||
"futures",
|
||||
"sycamore-reactive",
|
||||
"tokio",
|
||||
"wasm-bindgen-futures",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sycamore-macro"
|
||||
version = "0.8.0-beta.7"
|
||||
|
|
@ -440,17 +294,6 @@ dependencies = [
|
|||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio"
|
||||
version = "1.20.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "57aec3cfa4c296db7255446efb4928a6be304b431a806216105542a67b6ca82e"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"once_cell",
|
||||
"pin-project-lite",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.2"
|
||||
|
|
@ -506,18 +349,6 @@ dependencies = [
|
|||
"wasm-bindgen-shared",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-futures"
|
||||
version = "0.4.31"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "de9a9cec1733468a8c657e57fa2413d2ae2c0129b95e87c5b72b8ace4d13f31f"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"js-sys",
|
||||
"wasm-bindgen",
|
||||
"web-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro"
|
||||
version = "0.2.81"
|
||||
|
|
|
|||
11
Cargo.toml
11
Cargo.toml
|
|
@ -6,19 +6,12 @@ edition = "2021"
|
|||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
sycamore = { version = "0.8.0-beta.7", features = ["suspense"]}
|
||||
sycamore = "0.8.0-beta.7"
|
||||
rand = {version = "0.7", features = ["wasm-bindgen"]}
|
||||
getrandom = { version = "0.2", features = ["js"] }
|
||||
gloo-timers = { version = "0.2.3", features = ["futures"] }
|
||||
js-sys = {version = "0.3"}
|
||||
futures = {version = "0.3"}
|
||||
|
||||
[dependencies.web-sys]
|
||||
version = "0.3"
|
||||
features = [
|
||||
'KeyboardEvent',
|
||||
]
|
||||
|
||||
[profile.release]
|
||||
lto = true
|
||||
opt-level = 's'
|
||||
]
|
||||
|
|
@ -20,16 +20,16 @@
|
|||
in pkgs.mkShell {
|
||||
buildInputs = with pkgs; [
|
||||
cargo
|
||||
rustfmt
|
||||
wasm-bindgen-cli
|
||||
trunk
|
||||
nodePackages.sass
|
||||
rust-analyzer
|
||||
|
||||
(rust-bin.stable.latest.default.override {
|
||||
extensions = [ "rust-src" ];
|
||||
targets = [ "wasm32-unknown-unknown" ];
|
||||
})
|
||||
|
||||
# ( )
|
||||
];
|
||||
|
||||
shellHook = "";
|
||||
|
|
|
|||
61
kikikoz.css
61
kikikoz.css
|
|
@ -1,46 +1,12 @@
|
|||
body {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
details.aide[open] {
|
||||
columns: 2;
|
||||
background-color: rgba(255, 255, 255, 0.5);
|
||||
border-radius: .5rem;
|
||||
}
|
||||
|
||||
details.aide > summary {
|
||||
font-weight: 1000;
|
||||
}
|
||||
|
||||
details.configuration {
|
||||
padding: 1ex;
|
||||
}
|
||||
|
||||
details.configuration[open] {
|
||||
background-color: rgba(0, 0, 0, 0.2);
|
||||
|
||||
border-radius: .5rem;
|
||||
}
|
||||
|
||||
details.configuration > summary {
|
||||
width: 100%;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
body > div {
|
||||
background-color: aliceblue;
|
||||
display: flex;
|
||||
min-height: 100vh;
|
||||
padding: 8px;
|
||||
}
|
||||
|
||||
|
||||
section#les_queues {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
#les_queues > div {
|
||||
flex-grow: 1;
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
}
|
||||
|
||||
h1 {
|
||||
|
|
@ -56,13 +22,6 @@ p.orateurice {
|
|||
text-align: center;
|
||||
}
|
||||
|
||||
p.orateurice button{
|
||||
margin: auto;
|
||||
display: block;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
|
||||
li.dernier_arrive {
|
||||
font-style: italic;
|
||||
}
|
||||
|
|
@ -75,17 +34,6 @@ li.dernier_arrive {
|
|||
background-color: lightgreen;
|
||||
}
|
||||
|
||||
|
||||
.active section.queue h3::before {
|
||||
content: ">>> " ;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
|
||||
.active section.queue h3 {
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.attente section.queue {
|
||||
background-color: pink;
|
||||
}
|
||||
|
|
@ -101,8 +49,3 @@ section.queue {
|
|||
.hidden {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#bouton_next {
|
||||
font-size: 1.5rem;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
|
|
|||
514
src/main.rs
514
src/main.rs
|
|
@ -1,388 +1,270 @@
|
|||
use futures::future;
|
||||
use futures::stream::StreamExt;
|
||||
use gloo_timers::future::IntervalStream;
|
||||
use rand::distributions::Alphanumeric;
|
||||
use rand::prelude::*;
|
||||
use sycamore::builder::prelude::*;
|
||||
use sycamore::futures::spawn_local_scoped;
|
||||
use sycamore::prelude::*;
|
||||
use sycamore::builder::prelude::*;
|
||||
use sycamore::rt::JsCast;
|
||||
use rand::prelude::*;
|
||||
use rand::distributions::Alphanumeric;
|
||||
|
||||
enum NomQueue {
|
||||
A, B
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq)]
|
||||
enum ModeQueue {
|
||||
Chrono,
|
||||
Aléatoire,
|
||||
Aléatoire
|
||||
}
|
||||
|
||||
impl ModeQueue {
|
||||
fn set_aléatoire(&mut self, b: bool) {
|
||||
match b {
|
||||
false => *self = ModeQueue::Chrono,
|
||||
true => *self = ModeQueue::Aléatoire,
|
||||
}
|
||||
match b {
|
||||
false => { *self = ModeQueue::Chrono},
|
||||
true => { *self = ModeQueue::Aléatoire},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Display for ModeQueue {
|
||||
fn fmt(&self, fmt: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
|
||||
let s = match self {
|
||||
ModeQueue::Chrono => "Chrono",
|
||||
ModeQueue::Aléatoire => "Aléatoire",
|
||||
};
|
||||
write!(fmt, "{}", s)
|
||||
fn fmt(&self, fmt: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
|
||||
let s = match self {
|
||||
ModeQueue::Chrono => "Chrono",
|
||||
ModeQueue::Aléatoire => "Aléatoire"
|
||||
};
|
||||
write!(fmt, "{}", s)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
struct ÉtatQueue<'a> {
|
||||
nom: String,
|
||||
id: usize,
|
||||
mode: &'a Signal<ModeQueue>,
|
||||
contenu: &'a Signal<Vec<String>>,
|
||||
nouvelleau: &'a Signal<String>,
|
||||
priorité: &'a Signal<u8>,
|
||||
crédit_parole: &'a Signal<f32>,
|
||||
à_détruire: &'a Signal<bool>,
|
||||
}
|
||||
|
||||
impl<'a> PartialEq for ÉtatQueue<'a> {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.id == other.id
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Eq for ÉtatQueue<'a> {}
|
||||
|
||||
impl<'a> ÉtatQueue<'a> {
|
||||
fn new<'b>(cx: BoundedScope<'a, 'b>, nom: &str) -> Self {
|
||||
ÉtatQueue {
|
||||
nom: nom.into(),
|
||||
mode: create_signal(cx, ModeQueue::Aléatoire),
|
||||
contenu: create_signal(cx, vec![]),
|
||||
nouvelleau: create_signal(cx, "".into()),
|
||||
priorité: create_signal(cx, 1),
|
||||
crédit_parole: create_signal(cx, 0.0),
|
||||
id: thread_rng().gen(),
|
||||
à_détruire: create_signal(cx, false),
|
||||
}
|
||||
ÉtatQueue {
|
||||
nom: nom.into(),
|
||||
mode: create_signal(cx, ModeQueue::Aléatoire),
|
||||
contenu: create_signal(cx, vec![]),
|
||||
nouvelleau: create_signal(cx, "".into()),
|
||||
priorité: create_signal(cx, 1.into()),
|
||||
}
|
||||
}
|
||||
|
||||
fn len(&self) -> usize {
|
||||
return self.contenu.get().len();
|
||||
return self.contenu.get().len()
|
||||
}
|
||||
|
||||
fn enqueue(&mut self, rng: &mut ThreadRng) {
|
||||
//
|
||||
let s = &self.nouvelleau;
|
||||
let n = self.len();
|
||||
let k = match *self.mode.get() {
|
||||
ModeQueue::Chrono => n,
|
||||
ModeQueue::Aléatoire => rng.gen_range(0, n + 1),
|
||||
};
|
||||
self.contenu.modify().insert(k, s.to_string())
|
||||
//
|
||||
let s = &self.nouvelleau;
|
||||
let n = self.len();
|
||||
let k = match *self.mode.get() {
|
||||
ModeQueue::Chrono => n,
|
||||
ModeQueue::Aléatoire => {
|
||||
rng.gen_range(0, n + 1)
|
||||
}
|
||||
};
|
||||
self.contenu.modify().insert(k, s.to_string())
|
||||
}
|
||||
|
||||
|
||||
|
||||
fn dequeue(&mut self) -> Option<String> {
|
||||
*self.crédit_parole.modify() -= 1.0;
|
||||
if self.len() > 0 {
|
||||
Some(self.contenu.modify().remove(0))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
if self.len() > 0 {
|
||||
Some(self.contenu.modify().remove(0))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#[derive(Prop)]
|
||||
struct QueueProp<'a> {
|
||||
q: ÉtatQueue<'a>,
|
||||
struct QueueProp<'a>{
|
||||
q: ÉtatQueue<'a>
|
||||
}
|
||||
|
||||
fn validate_queue<'a>(mut queue: ÉtatQueue<'a>) -> impl FnMut(web_sys::Event) + 'a {
|
||||
move |ev: web_sys::Event| {
|
||||
let mut rng = thread_rng();
|
||||
let event: web_sys::KeyboardEvent = ev.unchecked_into();
|
||||
|
||||
if event.key_code() == 13 && !event.ctrl_key() {
|
||||
queue.enqueue(&mut rng);
|
||||
queue.nouvelleau.set(String::new())
|
||||
}
|
||||
}
|
||||
let mut rng = thread_rng();
|
||||
let event : web_sys::KeyboardEvent = ev.unchecked_into();
|
||||
|
||||
if event.key_code() == 13 {
|
||||
queue.enqueue(&mut rng);
|
||||
queue.nouvelleau.set(String::new())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// #[component]
|
||||
// fn Queue<'a, G: Html>(cx: Scope<'a>, queue: QueueProp<'a>) -> View<G> {
|
||||
// let queue_courante = use_context::<Signal<NomQueue>>(cx);
|
||||
|
||||
// }
|
||||
|
||||
|
||||
#[component]
|
||||
fn ConfigQueue<'a, G: Html>(cx: Scope<'a>, q: QueueProp<'a>) -> View<G> {
|
||||
let queue: ÉtatQueue = q.q;
|
||||
fn ConfigQueue<'a, G: Html>(cx: Scope<'a>, queue: QueueProp<'a>) -> View<G> {
|
||||
let prio_str = create_signal(cx, String::new());
|
||||
let est_aléatoire = create_signal(cx, true);
|
||||
let nom = queue.nom;
|
||||
let est_aléatoire = create_signal(cx, true); //*queue.q.mode.get() == ModeQueue::Aléatoire);
|
||||
let nom = queue.q.nom;
|
||||
let suffix = rand::thread_rng()
|
||||
.sample_iter(&Alphanumeric)
|
||||
.take(15)
|
||||
.map(char::from)
|
||||
.collect::<String>();
|
||||
create_effect(cx, ||
|
||||
if let Ok(p) = prio_str.get().parse::<u8>() {
|
||||
queue.q.priorité.set(p)
|
||||
});
|
||||
create_effect(cx, || prio_str.set(format!("{}", queue.q.priorité.get())));
|
||||
|
||||
create_effect(cx, || {
|
||||
if let Ok(p) = prio_str.get().parse::<u8>() {
|
||||
queue.priorité.set(p)
|
||||
}
|
||||
});
|
||||
create_effect(cx, || prio_str.set(format!("{}", queue.priorité.get())));
|
||||
|
||||
create_effect(cx, || {
|
||||
queue.mode.modify().set_aléatoire(*est_aléatoire.get())
|
||||
});
|
||||
create_effect(cx, || {
|
||||
est_aléatoire.set(*queue.mode.get() == ModeQueue::Aléatoire)
|
||||
});
|
||||
create_effect(cx, ||
|
||||
queue.q.mode.modify().set_aléatoire(*est_aléatoire.get()));
|
||||
create_effect(cx, || est_aléatoire.set(*queue.q.mode.get() == ModeQueue::Aléatoire));
|
||||
|
||||
section()
|
||||
.c(h3().dyn_t(move || format!("{} ", nom)).c(button()
|
||||
.t("Supprimer")
|
||||
.on("click", move |_ev| (queue.à_détruire.set(true)))))
|
||||
.c(input()
|
||||
.attr("type", "checkbox")
|
||||
.dyn_attr("id", {
|
||||
let suffix = suffix.clone();
|
||||
move || Some(format!("mode_queue_{}", &suffix.clone()))
|
||||
})
|
||||
.bind_checked(est_aléatoire))
|
||||
.c(label()
|
||||
.dyn_attr("for", {
|
||||
let suffix = suffix.clone();
|
||||
move || Some(format!("mode_queue_{}", &suffix.clone()))
|
||||
})
|
||||
.t("Entrée aléatoire"))
|
||||
.c(br())
|
||||
.c(input()
|
||||
.dyn_attr("id", {
|
||||
let suffix = suffix.clone();
|
||||
move || Some(format!("prio_queue_{}", &suffix.clone()))
|
||||
})
|
||||
.attr("type", "range")
|
||||
.attr("min", "1")
|
||||
.attr("max", "7")
|
||||
.bind_value(prio_str))
|
||||
.c(label()
|
||||
.dyn_attr("for", {
|
||||
let suffix = suffix.clone();
|
||||
move || Some(format!("prio_queue_{}", &suffix.clone()))
|
||||
})
|
||||
.dyn_t(|| format!("Priorité: {}", queue.priorité.get())))
|
||||
.view(cx)
|
||||
.c(h3().dyn_t(move || nom.clone()))
|
||||
.c(input()
|
||||
.attr("type", "checkbox")
|
||||
.dyn_attr("id", { let suffix = suffix.clone();
|
||||
move || Some(format!("mode_queue_{}", &suffix.clone()))
|
||||
})
|
||||
.bind_checked(est_aléatoire)
|
||||
)
|
||||
.c(label()
|
||||
.dyn_attr("for", {
|
||||
let suffix = suffix.clone();
|
||||
move || Some(format!("mode_queue_{}", &suffix.clone()))
|
||||
})
|
||||
.t("Entrée aléatoire")
|
||||
)
|
||||
.c(br())
|
||||
.c(input()
|
||||
.dyn_attr("id", { let suffix = suffix.clone();
|
||||
move || Some(format!("prio_queue_{}", &suffix.clone()))
|
||||
})
|
||||
.attr("type", "range")
|
||||
.attr("min", "1")
|
||||
.attr("max", "7")
|
||||
.bind_value(prio_str)
|
||||
)
|
||||
.c(
|
||||
label()
|
||||
.dyn_attr("for", { let suffix = suffix.clone();
|
||||
move || Some(format!("prio_queue_{}", &suffix.clone()))
|
||||
})
|
||||
.dyn_t(|| format!("Priorité: {}", queue.q.priorité.get()))
|
||||
)
|
||||
.view(cx)
|
||||
}
|
||||
|
||||
|
||||
#[component]
|
||||
fn Queue<'a, G: Html>(cx: Scope<'a>, queue: QueueProp<'a>) -> View<G> {
|
||||
let ok_queue = validate_queue(queue.q.clone());
|
||||
view! { cx,
|
||||
div {
|
||||
section(class="queue") {
|
||||
h3 {(format!("{}", queue.q.nom))}
|
||||
input(type="text", bind:value = queue.q.nouvelleau, on:keypress=ok_queue) {}
|
||||
ul {
|
||||
Keyed {
|
||||
iterable: queue.q.contenu,
|
||||
view: |cx, item: String| view! {cx, li { (item) }},
|
||||
key: |x| x.clone()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Prop, Clone, Copy)]
|
||||
struct BarreCôtéProp<'a> {
|
||||
queues: &'a Signal<Vec<ÉtatQueue<'a>>>,
|
||||
}
|
||||
|
||||
#[component]
|
||||
fn Explications<'a, G: Html>(cx: Scope<'a>) -> View<G> {
|
||||
details()
|
||||
.class("aide")
|
||||
.c(summary().t("Comment utiliser Kikikoz"))
|
||||
.c(p().t("Kikikoz est un outil qui vous aide à répartir la parole dans une réunion. Il s'exécute en toute discrétion dans votre navigateur: ").c(strong().t("il n'envoie aucune donnée où que ce soit.")))
|
||||
.c(p().t("Quand vous lancez Kikikoz, l'interface que vous voyez correspond à une réunion avec un tour de parole divisé en deux files. C'est une pratique que l'on observe souvent, notamment pour répartir équitablement la parole entre femmes et hommes."))
|
||||
.c(p().t("Quand une personne lève la main, inscrivez son nom dans le champ de texte correspondant à la file d'attente idoine, puis pressez ENTRÉE."))
|
||||
.c(p().t("Pour donner la parole à la personne suivante, il suffit de cliquer sur le bouton \"suivantə\", ou de taper CTRL+ENTRÉE. Son nom et son temps de parole apparaissent alors en gros caractères"))
|
||||
.c(p().t("La parole alterne entre les deux files. La prochaine personne à parler est donc celle qui est en tête de la file avec un fond vert et un titre en italique. Vous l'avez peut-être remarqué, quand une personne lève la main, elle ne va pas à la fin de la file, mais à une position aléatoire. C'est inhabituel, mais pas moins juste. Il y a des chances que ce qu'elle à a dire soit plus pertinent, puisqu'elle lève la main après avoir entendu plus de choses. Vous pouvez changer ce comportement pour chaque file."))
|
||||
.c(p().t("Pour faire une pause dans la réunion (quand personne n'a la parole), cliquez sur \"pause\"."))
|
||||
.c(p().t("Vous pouvez configurer toutes sortes de détails via le panneau configaration. Vous pouvez y ajouter ou supprimer des files, décider si l'ajout de personnes dans chaque file doit se faire à une position aléatoire ou à la fin. Vous pouvez également attribuer une priorité différente aux files, si vous décidez que la parole doit revenir à l'une d'entre elles plus souvent qu'aux autres."))
|
||||
.view(cx)
|
||||
}
|
||||
|
||||
#[component]
|
||||
fn BarreCôté<'a, G: Html>(cx: Scope<'a>, p: BarreCôtéProp<'a>) -> View<G> {
|
||||
let nom_nouvelle_file = create_signal(cx, String::new());
|
||||
let nouvelle_file = {
|
||||
let queues = p.queues.clone();
|
||||
move |_ev| {
|
||||
let q = ÉtatQueue::new(cx, &nom_nouvelle_file.get());
|
||||
queues.modify().push(q);
|
||||
*nom_nouvelle_file.modify() = String::new();
|
||||
}
|
||||
};
|
||||
let nouvelle_file_clav = move |ev: web_sys::Event| {
|
||||
let event: web_sys::KeyboardEvent = ev.clone().unchecked_into();
|
||||
if event.key_code() == 13 && !event.ctrl_key() {
|
||||
nouvelle_file(ev)
|
||||
}
|
||||
};
|
||||
|
||||
view! {cx,
|
||||
aside {
|
||||
|
||||
details(class="configuration") {
|
||||
summary { "Configuration " }
|
||||
|
||||
Keyed {
|
||||
iterable: p.queues,
|
||||
key: |q| q.id,
|
||||
view: |cx, q| view!{cx, ConfigQueue{ q }}
|
||||
}
|
||||
|
||||
section {
|
||||
h3 {"Nouvelle file" }
|
||||
input(type="text", bind:value=nom_nouvelle_file, on:keypress=nouvelle_file_clav) {}
|
||||
button(on:click=nouvelle_file) { "Créer" }
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
div {
|
||||
section(class="queue") {
|
||||
h3 {(queue.q.nom)}
|
||||
input(type="text", bind:value = queue.q.nouvelleau, on:keypress=ok_queue) {}
|
||||
ul {
|
||||
Keyed {
|
||||
iterable: queue.q.contenu,
|
||||
view: |cx, item: String| view! {cx, li { (item) }},
|
||||
key: |x| x.clone()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
sycamore::render(|cx| {
|
||||
let heure_courante = create_signal(cx, 0.0);
|
||||
let _ = spawn_local_scoped(cx, async {
|
||||
IntervalStream::new(1000)
|
||||
.for_each(|_| {
|
||||
heure_courante.set(js_sys::Date::now());
|
||||
future::ready(())
|
||||
})
|
||||
.await
|
||||
});
|
||||
|
||||
let date_prise_parole = create_signal(cx, 0.0);
|
||||
let courantə = create_signal(cx, None);
|
||||
// let courantə2 = create_signal(cx, None).clone();
|
||||
let queues = create_signal(
|
||||
cx,
|
||||
vec![ÉtatQueue::new(cx, "Gauche"), ÉtatQueue::new(cx, "Droite")],
|
||||
);
|
||||
create_effect(cx, || {
|
||||
for q in queues.get().iter() {
|
||||
q.à_détruire.track()
|
||||
}
|
||||
queues.modify().retain(|q| !(*q.à_détruire.get()));
|
||||
});
|
||||
|
||||
let total_priorités: &ReadSignal<usize> = create_memo(cx, {
|
||||
let queues = queues.clone();
|
||||
move || {
|
||||
queues
|
||||
.get()
|
||||
.iter()
|
||||
.map(|q| *q.priorité.get() as usize)
|
||||
.sum()
|
||||
}
|
||||
});
|
||||
let queue_courante: &ReadSignal<(usize, usize)> = create_memo(cx, {
|
||||
move || {
|
||||
let (idx, (id, _q)) = queues
|
||||
.get()
|
||||
.iter()
|
||||
.map(|q| (q.id, *q.crédit_parole.get()))
|
||||
.enumerate()
|
||||
.max_by(|(_ia, (_id_a, a)), (_ib, (_id_b, b))| {
|
||||
a.partial_cmp(b).expect("Tried to compare a NaN")
|
||||
})
|
||||
.expect("bla");
|
||||
(idx, id)
|
||||
}
|
||||
});
|
||||
provide_context_ref(cx, queue_courante);
|
||||
let pause = move |_ev| {
|
||||
courantə.set(None);
|
||||
};
|
||||
let next = move |_ev| {
|
||||
//js_sys::alert("coucou");
|
||||
let mut queue: ÉtatQueue = queues.get()[queue_courante.get().0].clone();
|
||||
match queue.dequeue() {
|
||||
Some(p) => {
|
||||
courantə.set(Some(p));
|
||||
date_prise_parole.set(js_sys::Date::now())
|
||||
}
|
||||
None => {
|
||||
courantə.set(None);
|
||||
}
|
||||
}
|
||||
for q in queues.get().iter() {
|
||||
*q.crédit_parole.modify() +=
|
||||
(*q.priorité.get() as f32) / (*total_priorités.get() as f32)
|
||||
}
|
||||
};
|
||||
|
||||
view! { cx,
|
||||
div(on:keypress= {let next = next.clone();
|
||||
move |ev: web_sys::Event| {
|
||||
let event: web_sys::KeyboardEvent = ev.clone().unchecked_into();
|
||||
if event.key_code() == 13 && event.ctrl_key() {
|
||||
next(ev)
|
||||
}
|
||||
}
|
||||
}) {
|
||||
main {
|
||||
h1 { "Kikikoz" }
|
||||
p(class="orateurice") {
|
||||
(
|
||||
match &*courantə.get() {
|
||||
None => "En attente".into(),
|
||||
Some(p) => {
|
||||
let temps_parole = std::time::Duration::from_millis((*heure_courante.get() - *date_prise_parole.get()) as u64).as_secs();
|
||||
format!("On écoute {} depuis {:2}:{:02}", p, temps_parole / 60, temps_parole % 60)
|
||||
|
||||
}
|
||||
}
|
||||
)
|
||||
br {}
|
||||
button(on:click=next, id="bouton_next") { "Suivantə" }
|
||||
" "
|
||||
button(on:click=pause) { "Pause" }
|
||||
}
|
||||
section(id="les_queues") {
|
||||
Keyed {
|
||||
iterable: queues, //_pour_aff,
|
||||
key: |q| q.id,
|
||||
view: {
|
||||
let queue_courante = queue_courante.clone();
|
||||
move |cx, q|
|
||||
view!{ cx,
|
||||
div(class=(if queue_courante.get().1 == q.id {"active"} else {"attente"})) {
|
||||
Queue {q}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
br {}
|
||||
|
||||
Explications {}
|
||||
br {}
|
||||
footer {
|
||||
|
||||
a(href="https://git.tausendblum.site/florent.becker/kikikoz") { "Voir le code source."}
|
||||
}
|
||||
|
||||
}
|
||||
BarreCôté {
|
||||
queues
|
||||
}
|
||||
}
|
||||
let prochainə = create_signal(cx, String::from("personne encore"));
|
||||
let conf_visible = create_signal(cx, false);
|
||||
let queue_A = ÉtatQueue::new(cx, "Gauche");
|
||||
let queue_B = ÉtatQueue::new(cx, "Droite");
|
||||
let queue_courante = create_signal(cx, NomQueue::A);
|
||||
provide_context_ref(cx, queue_courante);
|
||||
let next = {
|
||||
let mut my_queue_A = queue_A.clone();
|
||||
let mut my_queue_B = queue_B.clone();
|
||||
move |_ev| {
|
||||
let (queue, next) = match *queue_courante.get() {
|
||||
NomQueue::A => (&mut my_queue_A, NomQueue::B),
|
||||
NomQueue::B => (&mut my_queue_B, NomQueue::A)
|
||||
};
|
||||
match queue.dequeue() {
|
||||
Some(p) => prochainə.set(p),
|
||||
None => ()
|
||||
}
|
||||
queue_courante.set(next);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
let queue_A_pour_aff = queue_A.clone();
|
||||
let queue_A_pour_conf = queue_A.clone();
|
||||
let queue_B_pour_aff = queue_B.clone();
|
||||
let queue_B_pour_conf = queue_B.clone();
|
||||
|
||||
|
||||
}
|
||||
view! { cx,
|
||||
main {
|
||||
h1 { "Kikikoz" }
|
||||
p(class="orateurice") {
|
||||
"On écoute " (prochainə.get()) "."
|
||||
br {}
|
||||
button(on:click=next) { "Suivantə" }
|
||||
}
|
||||
section(id="les_queues") {
|
||||
div(class=(match *queue_courante.get(){NomQueue::A=> "active", NomQueue::B=>"attente"})) {
|
||||
Queue {
|
||||
q: queue_A_pour_aff
|
||||
}
|
||||
}
|
||||
|
||||
div(class=(match *queue_courante.get(){NomQueue::B=>"active", NomQueue::A=>"attente"})) {
|
||||
Queue {
|
||||
q: queue_B_pour_aff
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
aside {
|
||||
button(on:click=|_| conf_visible.set(! *conf_visible.get())) {
|
||||
(
|
||||
if *conf_visible.get() {
|
||||
"cacher"
|
||||
} else {
|
||||
"configuration"
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
div(class=if *conf_visible.get() { "visible" } else { "hidden" }) {
|
||||
h2 { "Configuration" }
|
||||
ConfigQueue {
|
||||
q: queue_A_pour_conf
|
||||
}
|
||||
ConfigQueue {
|
||||
q: queue_B_pour_conf
|
||||
}
|
||||
// section {
|
||||
// h3 { "Queue B" }
|
||||
// input(type="checkbox", id="mélanger_queue_B") {}
|
||||
// label(for="enable_queue_B") {"Randomiser"}
|
||||
// br {}
|
||||
// input(type="range", id="prio_queue_B", min="1", max="7", bind:value=queue_B.priorité) {}
|
||||
// label(for="prio_queue_B") {"Priorité "} // (queue_B.priorité.get())}
|
||||
// }
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue