Ajout de l'aide
parent
6cbc951c59
commit
6b09a15e1a
18
kikikoz.css
18
kikikoz.css
|
|
@ -2,10 +2,26 @@ 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[open] {
|
||||
background-color: rgba(0, 0, 0, 0.2);
|
||||
padding: 1ex;
|
||||
border-radius: .5rem;
|
||||
}
|
||||
|
||||
body > div {
|
||||
background-color: aliceblue;
|
||||
display: flex;
|
||||
height: 100vh;
|
||||
min-height: 100vh;
|
||||
padding: 8px;
|
||||
}
|
||||
|
||||
|
|
|
|||
166
src/main.rs
166
src/main.rs
|
|
@ -136,7 +136,9 @@ fn ConfigQueue<'a, G: Html>(cx: Scope<'a>, q: QueueProp<'a>) -> View<G> {
|
|||
});
|
||||
|
||||
section()
|
||||
.c(h3().dyn_t(move || nom.clone()))
|
||||
.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", {
|
||||
|
|
@ -166,9 +168,6 @@ fn ConfigQueue<'a, G: Html>(cx: Scope<'a>, q: QueueProp<'a>) -> View<G> {
|
|||
move || Some(format!("prio_queue_{}", &suffix.clone()))
|
||||
})
|
||||
.dyn_t(|| format!("Priorité: {}", queue.priorité.get())))
|
||||
.c(button()
|
||||
.t("Supprimer")
|
||||
.on("click", move |ev| (queue.à_détruire.set(true))))
|
||||
.view(cx)
|
||||
}
|
||||
|
||||
|
|
@ -192,6 +191,76 @@ fn Queue<'a, G: Html>(cx: Scope<'a>, queue: QueueProp<'a>) -> View<G> {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Prop, Clone, Copy)]
|
||||
struct BarreCôtéProp<'a> {
|
||||
queues: &'a Signal<Vec<ÉtatQueue<'a>>>,
|
||||
}
|
||||
|
||||
fn classe_visible(b: bool) -> &'static str {
|
||||
if b {
|
||||
"visible"
|
||||
} else {
|
||||
"hidden"
|
||||
}
|
||||
}
|
||||
|
||||
#[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."))
|
||||
.c(p().t("Quand vous lancez Kikikoz, l'interface que vous voyez correspond à une réunion avec un tour de parole divisé en deux file. 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, vous allez inscrire son nom dans le champ de texte correspondant à la file d'attente idoine."))
|
||||
.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. 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 conf_visible = create_signal(cx, false);
|
||||
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" }
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
sycamore::render(|cx| {
|
||||
let heure_courante = create_signal(cx, 0.0);
|
||||
|
|
@ -207,21 +276,17 @@ fn main() {
|
|||
let date_prise_parole = create_signal(cx, 0.0);
|
||||
let courantə = create_signal(cx, None);
|
||||
// let courantə2 = create_signal(cx, None).clone();
|
||||
let conf_visible = create_signal(cx, false);
|
||||
let queues = create_signal(
|
||||
cx,
|
||||
vec![ÉtatQueue::new(cx, "Gauche"), ÉtatQueue::new(cx, "Droite")],
|
||||
);
|
||||
let supprime_queue = create_effect(cx, || {
|
||||
create_effect(cx, || {
|
||||
for q in queues.get().iter() {
|
||||
q.à_détruire.track()
|
||||
}
|
||||
queues.modify().retain(|q| !(*q.à_détruire.get()));
|
||||
});
|
||||
|
||||
let index_queues = create_memo(cx, {
|
||||
|| (0..queues.get().len()).into_iter().collect::<Vec<_>>()
|
||||
});
|
||||
let total_priorités: &ReadSignal<usize> = create_memo(cx, {
|
||||
let queues = queues.clone();
|
||||
move || {
|
||||
|
|
@ -233,14 +298,13 @@ fn main() {
|
|||
}
|
||||
});
|
||||
let queue_courante: &ReadSignal<(usize, usize)> = create_memo(cx, {
|
||||
let queues = queues.clone();
|
||||
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))| {
|
||||
.max_by(|(_ia, (_id_a, a)), (_ib, (_id_b, b))| {
|
||||
a.partial_cmp(b).expect("Tried to compare a NaN")
|
||||
})
|
||||
.expect("bla");
|
||||
|
|
@ -248,33 +312,24 @@ fn main() {
|
|||
}
|
||||
});
|
||||
provide_context_ref(cx, queue_courante);
|
||||
let next = {
|
||||
let mut queues = queues.clone();
|
||||
let queue_courante = queue_courante.clone();
|
||||
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 => (),
|
||||
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())
|
||||
}
|
||||
for q in queues.get().iter() {
|
||||
*q.crédit_parole.modify() +=
|
||||
(*q.priorité.get() as f32) / (*total_priorités.get() as f32)
|
||||
None => {
|
||||
courantə.set(None);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let nom_nouvelle_file = create_signal(cx, String::new());
|
||||
let nouvelle_file = {
|
||||
let mut queues = queues.clone();
|
||||
move |_ev| {
|
||||
let q = ÉtatQueue::new(cx, &nom_nouvelle_file.get());
|
||||
queues.modify().push(q);
|
||||
*nom_nouvelle_file.modify() = String::new();
|
||||
for q in queues.get().iter() {
|
||||
*q.crédit_parole.modify() +=
|
||||
(*q.priorité.get() as f32) / (*total_priorités.get() as f32)
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -294,14 +349,16 @@ fn main() {
|
|||
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);
|
||||
format!("On écoute {} depuis {:2}:{:02}", p, 0, temps_parole.as_secs())
|
||||
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) { "Suivantə" }
|
||||
" "
|
||||
button(on:click=pause) { "Pause" }
|
||||
}
|
||||
section(id="les_queues") {
|
||||
Keyed {
|
||||
|
|
@ -319,37 +376,14 @@ fn main() {
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
aside {
|
||||
button(on:click=|_| conf_visible.set(! *conf_visible.get())) {
|
||||
(
|
||||
if *conf_visible.get() {
|
||||
"cacher"
|
||||
} else {
|
||||
"configuration"
|
||||
}
|
||||
)
|
||||
}
|
||||
br {}
|
||||
|
||||
Explications {}
|
||||
|
||||
div(class=if *conf_visible.get() { "visible" } else { "hidden" }) {
|
||||
h2 { "Configuration" }
|
||||
Keyed {
|
||||
iterable: 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=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)
|
||||
}
|
||||
}) {}
|
||||
button(on:click=nouvelle_file) { "Créer" }
|
||||
}
|
||||
}
|
||||
}
|
||||
BarreCôté {
|
||||
queues
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
|
|||
Loading…
Reference in New Issue