From b4e8a1353a0fe9a427095b964d41d70337f613d0 Mon Sep 17 00:00:00 2001 From: Marc-Antoine Manningham <marc-antoine.m@outlook.com> Date: Tue, 10 Dec 2024 17:40:04 -0500 Subject: [PATCH] refactor: format all files --- aep-schedule-website/src/backend/fileserv.rs | 2 +- aep-schedule-website/src/frontend/app.rs | 89 ++++-- .../components/common/autocomplete.rs | 52 ++-- .../components/common/number_input.rs | 47 +++- .../frontend/components/common/schedule.rs | 43 ++- .../src/frontend/components/common/tab.rs | 5 +- .../src/frontend/components/icons/download.rs | 2 +- .../src/frontend/components/notifications.rs | 20 +- .../components/options/courses_selector.rs | 261 +++++++++++------- .../src/frontend/components/options/form.rs | 18 +- .../components/options/optimizations.rs | 52 ++-- .../frontend/components/options/personal.rs | 72 ++--- .../src/frontend/components/options/search.rs | 7 +- .../src/frontend/components/options/todo.rs | 128 ++++++--- .../src/frontend/components/schedule.rs | 62 +++-- .../src/frontend/components/schedules.rs | 58 ++-- .../src/frontend/pages/apropos.rs | 39 ++- .../src/frontend/pages/classroom.rs | 48 +++- .../src/frontend/pages/generator.rs | 39 +-- 19 files changed, 693 insertions(+), 351 deletions(-) diff --git a/aep-schedule-website/src/backend/fileserv.rs b/aep-schedule-website/src/backend/fileserv.rs index 904ebf2..9a0424e 100644 --- a/aep-schedule-website/src/backend/fileserv.rs +++ b/aep-schedule-website/src/backend/fileserv.rs @@ -21,7 +21,7 @@ pub async fn file_and_error_handler( if res.status() == StatusCode::OK { res.into_response() } else { - let handler = leptos_axum::render_app_to_stream(move || view! {<App/>}); + let handler = leptos_axum::render_app_to_stream(move || view! { <App /> }); handler(req).await.into_response() } } diff --git a/aep-schedule-website/src/frontend/app.rs b/aep-schedule-website/src/frontend/app.rs index 85d7f17..961fe02 100644 --- a/aep-schedule-website/src/frontend/app.rs +++ b/aep-schedule-website/src/frontend/app.rs @@ -16,15 +16,15 @@ pub fn shell(options: LeptosOptions) -> impl IntoView { <!DOCTYPE html> <html lang="fr"> <head> - <meta charset="utf-8"/> - <meta name="viewport" content="width=device-width, initial-scale=1"/> + <meta charset="utf-8" /> + <meta name="viewport" content="width=device-width, initial-scale=1" /> <AutoReload options=options.clone() /> - <HydrationScripts options/> - <link rel="stylesheet" id="leptos" href="/pkg/aep-schedule-website.css"/> - <MetaTags/> + <HydrationScripts options /> + <link rel="stylesheet" id="leptos" href="/pkg/aep-schedule-website.css" /> + <MetaTags /> </head> <body> - <App/> + <App /> </body> </html> } @@ -37,26 +37,61 @@ pub fn Nav() -> impl IntoView { view! { <header> <nav class=("active", is_active) class="flex-wrap overflow-x-hidden"> - <span class="text-2xl font-semibold leading-none font-sans tracking-tight">"Générateur d'horaire de l'AEP" - <span class="text-amber-600">"v2"</span> + <span class="text-2xl font-semibold leading-none font-sans tracking-tight"> + "Générateur d'horaire de l'AEP" <span class="text-amber-600">"v2"</span> </span> - <span class="bg-red-200 text-red-800 text-lg font-sans tracking-tight font-medium me-2 px-2.5 py-0.5 rounded-full shrink">"Beta - "<a class="text-gray-800" href="https://horaires.aep.polymtl.ca/">"Retourner à l'ancien générateur"</a></span> - <A href="/"><span class="rounded-md font-medium text-gray-700 text-lg font-sans tracking-tight">"Générateur d'horaire"</span></A> - <A href="/local"><span class="rounded-md font-medium text-gray-700 text-lg font-sans tracking-tight">"Horaire d'un local"</span></A> - <A href="/apropos"><span class="rounded-md font-medium text-gray-700 text-lg font-sans tracking-tight">"À propos"</span></A> - + <span class="bg-red-200 text-red-800 text-lg font-sans tracking-tight font-medium me-2 px-2.5 py-0.5 rounded-full shrink"> + "Beta - "<a class="text-gray-800" href="https://horaires.aep.polymtl.ca/"> + "Retourner à l'ancien générateur" + </a> + </span> + <A href="/"> + <span class="rounded-md font-medium text-gray-700 text-lg font-sans tracking-tight"> + "Générateur d'horaire" + </span> + </A> + <A href="/local"> + <span class="rounded-md font-medium text-gray-700 text-lg font-sans tracking-tight"> + "Horaire d'un local" + </span> + </A> + <A href="/apropos"> + <span class="rounded-md font-medium text-gray-700 text-lg font-sans tracking-tight"> + "À propos" + </span> + </A> - <a href="https://forms.gle/u5AWgGx7vcLbCPCc7" class="sources pad-left" target="_blank"> - <span class="rounded-md font-medium text-gray-700 text-lg font-sans tracking-tight">"Signaler un bug"</span> - <Bug size="3vh"/> + <a + href="https://forms.gle/u5AWgGx7vcLbCPCc7" + class="sources pad-left" + target="_blank" + > + <span class="rounded-md font-medium text-gray-700 text-lg font-sans tracking-tight"> + "Signaler un bug" + </span> + <Bug size="3vh" /> + </a> + <a + href="https://git.step.polymtl.ca/Lemark/aep-schedule-generator-rusty" + class="sources" + target="_blank" + > + <span class="rounded-md font-medium text-gray-700 text-lg font-sans tracking-tight"> + "Sources " + </span> + <GitlabLogo weight=IconWeight::Regular size="3vh" /> </a> - <a href="https://git.step.polymtl.ca/Lemark/aep-schedule-generator-rusty" class="sources" target="_blank" ><span class="rounded-md font-medium text-gray-700 text-lg font-sans tracking-tight">"Sources "</span><GitlabLogo weight=IconWeight::Regular size="3vh"/></a> </nav> - <div class=("active", is_active) class="hamburger" on:pointerdown=move |_| { - set_active.update(|active| { - *active = !*active; - }); - }> + <div + class=("active", is_active) + class="hamburger" + on:pointerdown=move |_| { + set_active + .update(|active| { + *active = !*active; + }); + } + > <span class="hamburger-bar"></span> <span class="hamburger-bar"></span> <span class="hamburger-bar"></span> @@ -71,13 +106,13 @@ pub fn App() -> impl IntoView { view! { <Router> - <Title text="Générateur d'horaire"/> - <Nav/> + <Title text="Générateur d'horaire" /> + <Nav /> <main class="h-full"> <FlatRoutes fallback=|| "Not found"> - <Route path=StaticSegment("/") view=GeneratorPage/> - <Route path=StaticSegment("/apropos") view=HomePage/> - <Route path=StaticSegment("/local") view=ClassRoomComponent/> + <Route path=StaticSegment("/") view=GeneratorPage /> + <Route path=StaticSegment("/apropos") view=HomePage /> + <Route path=StaticSegment("/local") view=ClassRoomComponent /> </FlatRoutes> </main> </Router> diff --git a/aep-schedule-website/src/frontend/components/common/autocomplete.rs b/aep-schedule-website/src/frontend/components/common/autocomplete.rs index 816bb1b..21c9300 100644 --- a/aep-schedule-website/src/frontend/components/common/autocomplete.rs +++ b/aep-schedule-website/src/frontend/components/common/autocomplete.rs @@ -72,28 +72,44 @@ pub fn AutoComplete<F: FnMut(String) + Copy + Clone + 'static>( view! { <div class="relative search-container ".to_owned() + &class> - <input type="text" class="py-2 px-3 block w-full border-gray-200 rounded-lg text-sm focus:border-blue-500 focus:ring-blue-500 disabled:opacity-50 disabled:pointer-events-none text-black" on:input=on_input placeholder=placeholder prop:value=input id=id on:keyup=move |ev| { - if ev.key() == "Enter" && !is_hidden.get() { - let course = input.get().trim().to_uppercase(); - select_choice(course); + <input + type="text" + class="py-2 px-3 block w-full border-gray-200 rounded-lg text-sm focus:border-blue-500 focus:ring-blue-500 disabled:opacity-50 disabled:pointer-events-none text-black" + on:input=on_input + placeholder=placeholder + prop:value=input + id=id + on:keyup=move |ev| { + if ev.key() == "Enter" && !is_hidden.get() { + let course = input.get().trim().to_uppercase(); + select_choice(course); + } } - } /> - <button class=button_theme on:pointerdown=move |_| { - let input = input.get().trim().to_uppercase(); - select_choice(input); - }> - <PlusCircle size="2em"/> + <button + class=button_theme + on:pointerdown=move |_| { + let input = input.get().trim().to_uppercase(); + select_choice(input); + } + > + <PlusCircle size="2em" /> </button> <div class="result-box"> - {suggestions.into_iter().enumerate().map(|(i, autocomplete)| view!{ - <div - class=("hidden", move || {!suggestion_range.get().contains(&i)}) - on:pointerdown=move |_| select_choice(autocomplete.value.clone()) - > - {autocomplete.label} - </div> - }).collect_view()} + {suggestions + .into_iter() + .enumerate() + .map(|(i, autocomplete)| { + view! { + <div + class=("hidden", move || { !suggestion_range.get().contains(&i) }) + on:pointerdown=move |_| select_choice(autocomplete.value.clone()) + > + {autocomplete.label} + </div> + } + }) + .collect_view()} </div> </div> } diff --git a/aep-schedule-website/src/frontend/components/common/number_input.rs b/aep-schedule-website/src/frontend/components/common/number_input.rs index c5ded8d..4c2e5a2 100644 --- a/aep-schedule-website/src/frontend/components/common/number_input.rs +++ b/aep-schedule-website/src/frontend/components/common/number_input.rs @@ -36,9 +36,25 @@ where <div class="flex flex-row gap-8 items-center"> <p class="text-white font-sans font-medium tracking-tight">{label}</p> <div class="relative flex items-center max-w-20"> - <button on:pointerdown=minus type="button" class="bg-gray-100 hover:bg-gray-200 border border-gray-300 rounded-s-lg p-1 h-7 focus:ring-gray-100 focus:ring-2 focus:outline-none"> - <svg class="w-3 h-3 text-gray-900" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 18 2"> - <path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M1 1h16"/> + <button + on:pointerdown=minus + type="button" + class="bg-gray-100 hover:bg-gray-200 border border-gray-300 rounded-s-lg p-1 h-7 focus:ring-gray-100 focus:ring-2 focus:outline-none" + > + <svg + class="w-3 h-3 text-gray-900" + aria-hidden="true" + xmlns="http://www.w3.org/2000/svg" + fill="none" + viewBox="0 0 18 2" + > + <path + stroke="currentColor" + stroke-linecap="round" + stroke-linejoin="round" + stroke-width="2" + d="M1 1h16" + /> </svg> </button> <input @@ -49,10 +65,27 @@ where min="0" max=max prop:value=value - required /> - <button on:pointerdown=plus type="button" class="bg-gray-100 hover:bg-gray-200 border border-gray-300 rounded-e-lg p-1 h-7 focus:ring-gray-100 focus:ring-2 focus:outline-none"> - <svg class="w-3 h-3 text-gray-900" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 18 18"> - <path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 1v16M1 9h16"/> + required + /> + <button + on:pointerdown=plus + type="button" + class="bg-gray-100 hover:bg-gray-200 border border-gray-300 rounded-e-lg p-1 h-7 focus:ring-gray-100 focus:ring-2 focus:outline-none" + > + <svg + class="w-3 h-3 text-gray-900" + aria-hidden="true" + xmlns="http://www.w3.org/2000/svg" + fill="none" + viewBox="0 0 18 18" + > + <path + stroke="currentColor" + stroke-linecap="round" + stroke-linejoin="round" + stroke-width="2" + d="M9 1v16M1 9h16" + /> </svg> </button> </div> diff --git a/aep-schedule-website/src/frontend/components/common/schedule.rs b/aep-schedule-website/src/frontend/components/common/schedule.rs index 94a2380..8962ea5 100644 --- a/aep-schedule-website/src/frontend/components/common/schedule.rs +++ b/aep-schedule-website/src/frontend/components/common/schedule.rs @@ -21,16 +21,45 @@ pub fn Schedule( view! { <div class="schedule"> - <div class="days" style={format!("grid-template-columns:2em 10px repeat({}, 1fr)", day_week.len())}> + <div + class="days" + style=format!("grid-template-columns:2em 10px repeat({}, 1fr)", day_week.len()) + > <div></div> <div></div> - {day_week.iter().map(|d| view!{<div class="day">{*d}</div>}).collect_view()} + {day_week.iter().map(|d| view! { <div class="day">{*d}</div> }).collect_view()} </div> - <div class="content" style={format!("grid-template-columns:2em 10px repeat({}, 1fr);grid-template-rows: repeat(58, {});", day_week.len(), col_height)}> - {hours.clone().into_iter().enumerate().map(|(i, h)| view!{<div class="time" style={format!("grid-row:{}", 4 * (i + 1))}>{h}</div>}).collect_view()} + <div + class="content" + style=format!( + "grid-template-columns:2em 10px repeat({}, 1fr);grid-template-rows: repeat(58, {});", + day_week.len(), + col_height, + ) + > + {hours + .clone() + .into_iter() + .enumerate() + .map(|(i, h)| { + view! { + <div class="time" style=format!("grid-row:{}", 4 * (i + 1))> + {h} + </div> + } + }) + .collect_view()} <div class="filler-col"></div> - {(3..=(day_week.len()+2)).map(|i| view!{<div class="col" style={format!("grid-column:{i}")}></div>}).collect_view()} - {(1..=hours.len()).map(|i| view!{<div class="row" style={format!("grid-row:{}/ span 2", 4 * i - 1)}></div>}).collect_view()} + {(3..=(day_week.len() + 2)) + .map(|i| view! { <div class="col" style=format!("grid-column:{i}")></div> }) + .collect_view()} + {(1..=hours.len()) + .map(|i| { + view! { + <div class="row" style=format!("grid-row:{}/ span 2", 4 * i - 1)></div> + } + }) + .collect_view()} {children.map(|c| c())} </div> </div> @@ -53,7 +82,7 @@ pub fn ScheduleEvent( len * 4 ); view! { - <div style={style} class="event".to_owned() + &class> + <div style=style class="event".to_owned() + &class> {children()} </div> } diff --git a/aep-schedule-website/src/frontend/components/common/tab.rs b/aep-schedule-website/src/frontend/components/common/tab.rs index 6993eee..014ef07 100644 --- a/aep-schedule-website/src/frontend/components/common/tab.rs +++ b/aep-schedule-website/src/frontend/components/common/tab.rs @@ -3,7 +3,10 @@ use leptos::prelude::*; #[component] pub fn Tab(active_tab: ReadSignal<String>, tab_id: String, children: Children) -> impl IntoView { view! { - <div class="relative card tab shrink w-full overflow-y-auto" class=("hidden", {move || tab_id != active_tab.get()})> + <div + class="relative card tab shrink w-full overflow-y-auto" + class=("hidden", { move || tab_id != active_tab.get() }) + > {children()} </div> } diff --git a/aep-schedule-website/src/frontend/components/icons/download.rs b/aep-schedule-website/src/frontend/components/icons/download.rs index 9bceace..35cbea7 100644 --- a/aep-schedule-website/src/frontend/components/icons/download.rs +++ b/aep-schedule-website/src/frontend/components/icons/download.rs @@ -13,7 +13,7 @@ pub fn Download( match weight { IconWeight::Fill => view! { <path d="M74.34,85.66A8,8,0,0,1,85.66,74.34L120,108.69V24a8,8,0,0,1,16,0v84.69l34.34-34.35a8,8,0,0,1,11.32,11.32l-48,48a8,8,0,0,1-11.32,0ZM240,136v64a16,16,0,0,1-16,16H32a16,16,0,0,1-16-16V136a16,16,0,0,1,16-16H84.4a4,4,0,0,1,2.83,1.17L111,145A24,24,0,0,0,145,145l23.8-23.8A4,4,0,0,1,171.6,120H224A16,16,0,0,1,240,136Zm-40,32a12,12,0,1,0-12,12A12,12,0,0,0,200,168Z"></path> - }.into_any(), + }.into_any(), IconWeight::Duotone => view! { <path d="M232,136v64a8,8,0,0,1-8,8H32a8,8,0,0,1-8-8V136a8,8,0,0,1,8-8H224A8,8,0,0,1,232,136Z" diff --git a/aep-schedule-website/src/frontend/components/notifications.rs b/aep-schedule-website/src/frontend/components/notifications.rs index b8adfe6..61dde28 100644 --- a/aep-schedule-website/src/frontend/components/notifications.rs +++ b/aep-schedule-website/src/frontend/components/notifications.rs @@ -44,18 +44,20 @@ pub fn Notifications( view! { <div class=class> <div class="notif-body"> - <div class="close-button" on:pointerdown=move |_| { - set_modal.set(None); - }> + <div + class="close-button" + on:pointerdown=move |_| { + set_modal.set(None); + } + > <X size="2em"></X> </div> <form on:submit=on_submit> - <p>"Entrez votre courriel pour recevoir des notifications quand la section ouvrira"</p> - <input type="text" - pattern=r"[^@\s]+@[^@\s]+\.[^@\s]+" - node_ref=input_element - /> - <input type="submit" value="Envoyer"/> + <p> + "Entrez votre courriel pour recevoir des notifications quand la section ouvrira" + </p> + <input type="text" pattern=r"[^@\s]+@[^@\s]+\.[^@\s]+" node_ref=input_element /> + <input type="submit" value="Envoyer" /> </form> </div> </div> diff --git a/aep-schedule-website/src/frontend/components/options/courses_selector.rs b/aep-schedule-website/src/frontend/components/options/courses_selector.rs index 41f98aa..40e3852 100644 --- a/aep-schedule-website/src/frontend/components/options/courses_selector.rs +++ b/aep-schedule-website/src/frontend/components/options/courses_selector.rs @@ -31,38 +31,43 @@ where // let set_modal = SetModal::from_context(); view! { - <div on:pointerdown=move |_| { + <div + on:pointerdown=move |_| { open.update(|b| *b = !*b); submit(); } class="gap-2 cursor-pointer items-center py-1.5 px-3 rounded-lg flex" - class=("bg-green-500", move || {open.get()}) - class=("bg-red-500", move || {!open.get()}) + class=("bg-green-500", move || { open.get() }) + class=("bg-red-500", move || { !open.get() }) > <span class="text-lg text-bold text-sans">{group.number.to_string()}</span> <div class="flex flex-col justify-between w-full"> - {group.periods.iter().map(|p| { - view!{ - <div class="flex group-text w-full justify-between"> - <span>{p.day.to_string()}</span> - <span class="period-group">{p.hours.to_string()}</span> - <span>{p.week_nb.to_string()}</span> - </div> - } - }).collect_view()} + {group + .periods + .iter() + .map(|p| { + view! { + <div class="flex group-text w-full justify-between"> + <span>{p.day.to_string()}</span> + <span class="period-group">{p.hours.to_string()}</span> + <span>{p.week_nb.to_string()}</span> + </div> + } + }) + .collect_view()} </div> - //{match group.open { - // false => Some(view !{ - // <div on:pointerdown=move |ev| { - // ev.stop_propagation(); - // let sigle_group = SigleGroup::new(course_sigle.clone(), group_type, group.number); - // set_modal.set(Some(sigle_group)); - // }> - // <BellRinging size="1em"/> - // </div> - // }), - // true => None, - //}} + // {match group.open { + // false => Some(view !{ + // <div on:pointerdown=move |ev| { + // ev.stop_propagation(); + // let sigle_group = SigleGroup::new(course_sigle.clone(), group_type, group.number); + // set_modal.set(Some(sigle_group)); + // }> + // <BellRinging size="1em"/> + // </div> + // }), + // true => None, + // }} </div> } } @@ -79,13 +84,22 @@ where F: Fn() + Copy + 'static, { view! { - {groups.into_iter().enumerate().map(|(i, group)| { + {groups + .into_iter() + .enumerate() + .map(|(i, group)| { let open = open[i]; view! { - <GroupsChips open group _course_sigle=course_sigle.clone() _group_type=group_type submit/> + <GroupsChips + open + group + _course_sigle=course_sigle.clone() + _group_type=group_type + submit + /> } - }).collect_view() - } + }) + .collect_view()} } } @@ -99,52 +113,84 @@ where <Tab active_tab tab_id=course.sigle.to_string()> <p>{course.name}</p> <div class="flex justify-around"> - { - match course.course_type { - ReactiveCourseType::TheoOnly { theo_open, theo_groups } => { - let groups = theo_groups; - view!{ - <div class="flex gap-2 flex-col pb-2 max-h-[26rem] overflow-y-auto"> - <h3>"Théorie"</h3> - <GroupsSettings groups open=theo_open course_sigle group_type=GroupType::TheoGroup submit/> - </div> - }.into_any() - }, - ReactiveCourseType::LabOnly { lab_open, lab_groups } => { - let groups = lab_groups; - view!{ - <div class="flex gap-2 flex-col pb-2 overflow-y-auto"> - <h3>"Laboratoire"</h3> - <GroupsSettings groups open=lab_open course_sigle=course_sigle.clone() group_type=GroupType::LabGroup submit/> - </div> - }.into_any() - }, - ReactiveCourseType::Both { theo_open, theo_groups, lab_open, lab_groups } => { - let theo_groups = theo_groups; - let lab_groups = lab_groups; - view!{ - <div class="flex gap-2 flex-col pb-2 overflow-y-auto"> - <h3>"Théorie"</h3> - <GroupsSettings groups=theo_groups open=theo_open course_sigle=course_sigle.clone() group_type=GroupType::TheoGroup submit/> - </div> - <div class="vertical-bar"></div> - <div class="flex gap-2 flex-col pb-2 overflow-y-auto"> - <h3>"Laboratoire"</h3> - <GroupsSettings groups=lab_groups open=lab_open course_sigle=course_sigle.clone() group_type=GroupType::LabGroup submit/> - </div> - }.into_any() - }, - ReactiveCourseType::Linked { both_open, theo_groups, lab_groups } => { - let groups = theo_groups.merge(lab_groups); - view!{ - <div class="flex gap-2 flex-col pb-2 overflow-y-auto"> - <h3>"Théorie et laboratoire lié"</h3> - <GroupsSettings groups open=both_open course_sigle=course_sigle group_type=GroupType::LabGroup submit/> - </div> - }.into_any() - }, + {match course.course_type { + ReactiveCourseType::TheoOnly { theo_open, theo_groups } => { + let groups = theo_groups; + view! { + <div class="flex gap-2 flex-col pb-2 max-h-[26rem] overflow-y-auto"> + <h3>"Théorie"</h3> + <GroupsSettings + groups + open=theo_open + course_sigle + group_type=GroupType::TheoGroup + submit + /> + </div> + } + .into_any() } - } + ReactiveCourseType::LabOnly { lab_open, lab_groups } => { + let groups = lab_groups; + view! { + <div class="flex gap-2 flex-col pb-2 overflow-y-auto"> + <h3>"Laboratoire"</h3> + <GroupsSettings + groups + open=lab_open + course_sigle=course_sigle.clone() + group_type=GroupType::LabGroup + submit + /> + </div> + } + .into_any() + } + ReactiveCourseType::Both { theo_open, theo_groups, lab_open, lab_groups } => { + let theo_groups = theo_groups; + let lab_groups = lab_groups; + view! { + <div class="flex gap-2 flex-col pb-2 overflow-y-auto"> + <h3>"Théorie"</h3> + <GroupsSettings + groups=theo_groups + open=theo_open + course_sigle=course_sigle.clone() + group_type=GroupType::TheoGroup + submit + /> + </div> + <div class="vertical-bar"></div> + <div class="flex gap-2 flex-col pb-2 overflow-y-auto"> + <h3>"Laboratoire"</h3> + <GroupsSettings + groups=lab_groups + open=lab_open + course_sigle=course_sigle.clone() + group_type=GroupType::LabGroup + submit + /> + </div> + } + .into_any() + } + ReactiveCourseType::Linked { both_open, theo_groups, lab_groups } => { + let groups = theo_groups.merge(lab_groups); + view! { + <div class="flex gap-2 flex-col pb-2 overflow-y-auto"> + <h3>"Théorie et laboratoire lié"</h3> + <GroupsSettings + groups + open=both_open + course_sigle=course_sigle + group_type=GroupType::LabGroup + submit + /> + </div> + } + .into_any() + } + }} </div> </Tab> } @@ -161,21 +207,21 @@ where let courses = state.courses; view! { - <Await - future=get_courses() - let:all_courses - > - <SearchCourse set_active_tab all_courses=all_courses.clone()/> + <Await future=get_courses() let:all_courses> + <SearchCourse set_active_tab all_courses=all_courses.clone() /> </Await> <div class="flex w-full flex-wrap gap-1"> - <button class="flex items-center py-1 px-2 rounded-xl bg-amber-500 text-black transition" class=("opacity-75", move || active_tab.get() != "") id="personal" on:pointerdown={ - move |_| set_active_tab.set("".to_string()) - }> - <CalendarX weight=IconWeight::Regular size="16px"/> + <button + class="flex items-center py-1 px-2 rounded-xl bg-amber-500 text-black transition" + class=("opacity-75", move || active_tab.get() != "") + id="personal" + on:pointerdown=move |_| set_active_tab.set("".to_string()) + > + <CalendarX weight=IconWeight::Regular size="16px" /> {"Horaire personnel"} </button> <For - each=move || {courses.get()} + each=move || { courses.get() } key=|c| c.sigle.clone() children=move |course| { let sigle = course.sigle.to_string(); @@ -183,22 +229,33 @@ where let sigle = course.sigle.to_string(); let sigle2 = course.sigle.to_string(); let sigle3 = course.sigle.to_string(); - view!{ - <button class="flex items-center py-1 px-2 rounded-xl bg-amber-500 text-black transition" class=("opacity-75", add_hidden) id=sigle3 on:pointerdown={ - let sigle = sigle.clone(); - move |_| set_active_tab.set(sigle.clone()) - }> - {sigle2} - <button class="close" on:click={ - let sigle = sigle.clone(); - move |_| { - state.courses.update(|courses| { - courses.retain(|c| c.sigle.as_str() != sigle); - }); - submit(); + view! { + <button + class="flex items-center py-1 px-2 rounded-xl bg-amber-500 text-black transition" + class=("opacity-75", add_hidden) + id=sigle3 + on:pointerdown={ + let sigle = sigle.clone(); + move |_| set_active_tab.set(sigle.clone()) } - }> - <X weight=IconWeight::Regular size="16px"/></button> + > + {sigle2} + <button + class="close" + on:click={ + let sigle = sigle.clone(); + move |_| { + state + .courses + .update(|courses| { + courses.retain(|c| c.sigle.as_str() != sigle); + }); + submit(); + } + } + > + <X weight=IconWeight::Regular size="16px" /> + </button> </button> } } @@ -207,12 +264,8 @@ where <Tab active_tab tab_id="".to_string()> <PersonalTimeSelector week=state.week submit></PersonalTimeSelector> </Tab> - <For - each=move || {courses.get()} - key=|c| c.sigle.clone() - let:course - > - <CourseTab course active_tab submit/> + <For each=move || { courses.get() } key=|c| c.sigle.clone() let:course> + <CourseTab course active_tab submit /> </For> } } diff --git a/aep-schedule-website/src/frontend/components/options/form.rs b/aep-schedule-website/src/frontend/components/options/form.rs index 6e6c027..0e1f693 100644 --- a/aep-schedule-website/src/frontend/components/options/form.rs +++ b/aep-schedule-website/src/frontend/components/options/form.rs @@ -31,10 +31,20 @@ pub fn OptionsForms() -> impl IntoView { }; view! { - <CoursesSelector submit/> + <CoursesSelector submit /> <span class="grow"></span> - <NumberInput value=state.max_nb_conflicts max=127 label="Nombre de période de cours en conflits maximum: " submit/> - <SelectOptimizations submit/> - <button on:pointerdown=submit_mobile class="lg:hidden select-none rounded-lg bg-amber-500 py-2 text-xl px-4 w-64 self-center text-center align-middle text-black shadow-md shadow-amber-500/20 transition-all hover:shadow-lg hover:shadow-amber-500/40 focus:opacity-[0.85] focus:shadow-none active:opacity-[0.85] active:shadow-none disabled:pointer-events-none disabled:opacity-50 disabled:shadow-none">"Générer les horaires"</button> + <NumberInput + value=state.max_nb_conflicts + max=127 + label="Nombre de période de cours en conflits maximum: " + submit + /> + <SelectOptimizations submit /> + <button + on:pointerdown=submit_mobile + class="lg:hidden select-none rounded-lg bg-amber-500 py-2 text-xl px-4 w-64 self-center text-center align-middle text-black shadow-md shadow-amber-500/20 transition-all hover:shadow-lg hover:shadow-amber-500/40 focus:opacity-[0.85] focus:shadow-none active:opacity-[0.85] active:shadow-none disabled:pointer-events-none disabled:opacity-50 disabled:shadow-none" + > + "Générer les horaires" + </button> } } diff --git a/aep-schedule-website/src/frontend/components/options/optimizations.rs b/aep-schedule-website/src/frontend/components/options/optimizations.rs index 918ac1e..bbf62e8 100644 --- a/aep-schedule-website/src/frontend/components/options/optimizations.rs +++ b/aep-schedule-website/src/frontend/components/options/optimizations.rs @@ -31,31 +31,51 @@ where view! { <div class="three-col"> <div class="flex flex-col items-center"> - <House weight=weight_house size="10vh"/> + <House weight=weight_house size="10vh" /> <p class="font-sans font-medium tracking-tight">"Plus de congés"</p> - <input type="range" min="0" max="4" class="lg:w-24 w-16 accent-amber-500" prop:value=state.day_off on:input=move |ev| { - state.day_off.set(event_target_value(&ev).parse::<u8>().unwrap()); - submit(); - }/> + <input + type="range" + min="0" + max="4" + class="lg:w-24 w-16 accent-amber-500" + prop:value=state.day_off + on:input=move |ev| { + state.day_off.set(event_target_value(&ev).parse::<u8>().unwrap()); + submit(); + } + /> </div> <div class="flex flex-col items-center"> <div class="flex"> - <SunHorizon weight=weight_early size="10vh"/> - <Sun weight=weight_morning size="10vh"/> + <SunHorizon weight=weight_early size="10vh" /> + <Sun weight=weight_morning size="10vh" /> </div> <p class="font-sans font-medium tracking-tight">"Cours plus tôt ou plus tard"</p> - <input type="range" min="-4" max="4" class="lg:w-48 w-32 accent-amber-500" prop:value=state.morning on:input=move |ev| { - state.morning.set(event_target_value(&ev).parse::<i8>().unwrap()); - submit(); - }/> + <input + type="range" + min="-4" + max="4" + class="lg:w-48 w-32 accent-amber-500" + prop:value=state.morning + on:input=move |ev| { + state.morning.set(event_target_value(&ev).parse::<i8>().unwrap()); + submit(); + } + /> </div> <div class="flex flex-col items-center"> - <CalendarCheck weight=weight_finish size="10vh"/> + <CalendarCheck weight=weight_finish size="10vh" /> <p class="font-sans font-medium tracking-tight">"Finir plus tôt"</p> - <input type="range" min="0" max="4" class="lg:w-24 w-16 accent-amber-500" prop:value=state.finish_early on:input=move |ev| { - state.finish_early.set(event_target_value(&ev).parse::<u8>().unwrap()); - submit(); - } + <input + type="range" + min="0" + max="4" + class="lg:w-24 w-16 accent-amber-500" + prop:value=state.finish_early + on:input=move |ev| { + state.finish_early.set(event_target_value(&ev).parse::<u8>().unwrap()); + submit(); + } /> </div> </div> diff --git a/aep-schedule-website/src/frontend/components/options/personal.rs b/aep-schedule-website/src/frontend/components/options/personal.rs index fa342b8..3ebbf69 100644 --- a/aep-schedule-website/src/frontend/components/options/personal.rs +++ b/aep-schedule-website/src/frontend/components/options/personal.rs @@ -60,39 +60,47 @@ where }; view! { <Schedule col_height="0.4em"> - {(0..5).into_iter().map(|i| { - (0..26).into_iter().map(|j| { - let j = 2 * j; - let style = format!( - "grid-column:{};grid-row:{} / span {};", - i + 3, - j + 5, - 2 - ); - let class = move || { - let day = week[i].get(); - let hour = day & (1 << j); - if hour != 0 { - "touch-none selected-hour" - } else { - "touch-none" - } - }; - view! { - <div style=style class=class - on:pointerdown=move |e| { - set_initial.set(Some((i, j))); - set_positive.set((week[i].get() & (1 << j)) == 0); - let _ = e.target().unwrap().dyn_ref::<Element>().unwrap().release_pointer_capture(e.pointer_id()); + {(0..5) + .into_iter() + .map(|i| { + (0..26) + .into_iter() + .map(|j| { + let j = 2 * j; + let style = format!( + "grid-column:{};grid-row:{} / span {};", + i + 3, + j + 5, + 2, + ); + let class = move || { + let day = week[i].get(); + let hour = day & (1 << j); + if hour != 0 { "touch-none selected-hour" } else { "touch-none" } + }; + view! { + <div + style=style + class=class + on:pointerdown=move |e| { + set_initial.set(Some((i, j))); + set_positive.set((week[i].get() & (1 << j)) == 0); + let _ = e + .target() + .unwrap() + .dyn_ref::<Element>() + .unwrap() + .release_pointer_capture(e.pointer_id()); + } + on:pointerover=move |_| { + set_destination.set((i, j)); + } + ></div> } - on:pointerover=move |_| { - set_destination.set((i, j)); - }> - </div> - } - }).collect_view() - }).collect_view()} - <div style=selection class=selection_class></div> + }) + .collect_view() + }) + .collect_view()} <div style=selection class=selection_class></div> </Schedule> } } diff --git a/aep-schedule-website/src/frontend/components/options/search.rs b/aep-schedule-website/src/frontend/components/options/search.rs index ab8f109..43d5070 100644 --- a/aep-schedule-website/src/frontend/components/options/search.rs +++ b/aep-schedule-website/src/frontend/components/options/search.rs @@ -26,6 +26,11 @@ pub fn SearchCourse( }; Some(view! { - <AutoComplete suggestion_list=courses placeholder="Cours" submit=on_submit id="course-submitter"/> + <AutoComplete + suggestion_list=courses + placeholder="Cours" + submit=on_submit + id="course-submitter" + /> }) } diff --git a/aep-schedule-website/src/frontend/components/options/todo.rs b/aep-schedule-website/src/frontend/components/options/todo.rs index 5f15b8c..50acbbb 100644 --- a/aep-schedule-website/src/frontend/components/options/todo.rs +++ b/aep-schedule-website/src/frontend/components/options/todo.rs @@ -23,24 +23,40 @@ pub fn Step( view! { <div class="flex"> <div class="flex flex-col items-center mr-4"> - <div> - <div class=bg_color> - <svg class="w-4 text-gray-600" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" viewBox="0 0 24 24"> - <line fill="none" stroke-miterlimit="10" x1="12" y1="2" x2="12" y2="22"></line> - <polyline fill="none" stroke-miterlimit="10" points="19,15 12,22 5,15"></polyline> - </svg> + <div> + <div class=bg_color> + <svg + class="w-4 text-gray-600" + stroke="currentColor" + stroke-width="2" + stroke-linecap="round" + stroke-linejoin="round" + viewBox="0 0 24 24" + > + <line + fill="none" + stroke-miterlimit="10" + x1="12" + y1="2" + x2="12" + y2="22" + ></line> + <polyline + fill="none" + stroke-miterlimit="10" + points="19,15 12,22 5,15" + ></polyline> + </svg> + </div> </div> - </div> - <div class="w-px h-full bg-gray-300"></div> - </div> - <div class="pt-1 pb-8"> - <p class="mb-2 text-lg font-bold">{n}" - "{title}</p> - <p class="text-gray-700"> - {description} - </p> - {children.map(|c| c())} + <div class="w-px h-full bg-gray-300"></div> + </div> + <div class="pt-1 pb-8"> + <p class="mb-2 text-lg font-bold">{n}" - "{title}</p> + <p class="text-gray-700">{description}</p> + {children.map(|c| c())} + </div> </div> - </div> } } @@ -68,35 +84,79 @@ pub fn Todo() -> impl IntoView { <div class="px-4 py-4 mx-auto"> <div class="grid gap-6 row-gap-10"> <div class="lg:py-6 lg:pr-16"> - <Step n=1 step title="Ajoutez vos cours" description="Utilisez la barre de recherche à gauche pour trouver et sélectionner vos cours. Une fois les cours sélectionnés, ils apparaîtront comme un onglet."/> - <Step n=2 step title="Ouvrez des sections" description="Assurez d'avoir au moins une section d'ouverte pour la théorie et la pratique. En sélectionnant l'onglet du cours et en appuyant sur les sections."> - <div class="warning-box" class=("hidden", move || state.section_error.get().is_empty())> - <WarningCircle size="2em"/> - <span> - {state.section_error} - </span> + <Step + n=1 + step + title="Ajoutez vos cours" + description="Utilisez la barre de recherche à gauche pour trouver et sélectionner vos cours. Une fois les cours sélectionnés, ils apparaîtront comme un onglet." + /> + <Step + n=2 + step + title="Ouvrez des sections" + description="Assurez d'avoir au moins une section d'ouverte pour la théorie et la pratique. En sélectionnant l'onglet du cours et en appuyant sur les sections." + > + <div + class="warning-box" + class=("hidden", move || state.section_error.get().is_empty()) + > + <WarningCircle size="2em" /> + <span>{state.section_error}</span> </div> </Step> - <Step n=3 step title="Forcer des heures libres" description="Sélectionnez une plage de temps à avoir absolument libre en pressant et relâchant sur votre horaire personnel."> - <div class="warning-box" class=("hidden", move || state.personal_error.get().is_empty())> - <WarningCircle size="2em"/> - <span> - {state.personal_error} - </span> + <Step + n=3 + step + title="Forcer des heures libres" + description="Sélectionnez une plage de temps à avoir absolument libre en pressant et relâchant sur votre horaire personnel." + > + <div + class="warning-box" + class=("hidden", move || state.personal_error.get().is_empty()) + > + <WarningCircle size="2em" /> + <span>{state.personal_error}</span> </div> </Step> - <Step n=4 step title="Ajustez les paramètres" description="Bougez les curseurs en bas pour ajuster vos préférences. Vous pouvez choisir d'avoir plus de congés, de commencer en moyenne les cours plus tôt ou plus tard, ou de finir en moyenne plus tôt."/> + <Step + n=4 + step + title="Ajustez les paramètres" + description="Bougez les curseurs en bas pour ajuster vos préférences. Vous pouvez choisir d'avoir plus de congés, de commencer en moyenne les cours plus tôt ou plus tard, ou de finir en moyenne plus tôt." + /> <div class="flex items-center"> <div class="flex flex-col items-center mr-4"> <div> - <div class="flex transition-colors items-center justify-center w-10 h-10 border rounded-full" class=("bg-gray-100", move || step.get() < 5) class=("bg-green-400", move || step.get() == 5) class=("bg-amber-400", move || step.get() == 6) > - <svg class="w-6 text-gray-600" stroke="currentColor" viewBox="0 0 24 24"> - <polyline fill="none" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" points="6,12 10,16 18,8"></polyline> + <div + class="flex transition-colors items-center justify-center w-10 h-10 border rounded-full" + class=("bg-gray-100", move || step.get() < 5) + class=("bg-green-400", move || step.get() == 5) + class=("bg-amber-400", move || step.get() == 6) + > + <svg + class="w-6 text-gray-600" + stroke="currentColor" + viewBox="0 0 24 24" + > + <polyline + fill="none" + stroke-width="2" + stroke-linecap="round" + stroke-linejoin="round" + stroke-miterlimit="10" + points="6,12 10,16 18,8" + ></polyline> </svg> </div> </div> </div> - <button on:pointerdown=submit class="select-none rounded-lg bg-amber-500 py-1 text-lg font-sans font-semibold px-2 w-64 self-center text-center align-middle text-black shadow-md shadow-amber-500/20 transition-all hover:shadow-lg hover:shadow-amber-500/40 focus:opacity-[0.85] focus:shadow-none active:opacity-[0.85] active:shadow-none disabled:pointer-events-none disabled:opacity-50 disabled:shadow-none" prop:disabled=disab>"Générer les horaires"</button> + <button + on:pointerdown=submit + class="select-none rounded-lg bg-amber-500 py-1 text-lg font-sans font-semibold px-2 w-64 self-center text-center align-middle text-black shadow-md shadow-amber-500/20 transition-all hover:shadow-lg hover:shadow-amber-500/40 focus:opacity-[0.85] focus:shadow-none active:opacity-[0.85] active:shadow-none disabled:pointer-events-none disabled:opacity-50 disabled:shadow-none" + prop:disabled=disab + > + "Générer les horaires" + </button> </div> </div> </div> diff --git a/aep-schedule-website/src/frontend/components/schedule.rs b/aep-schedule-website/src/frontend/components/schedule.rs index e7c4cc7..3a5d569 100644 --- a/aep-schedule-website/src/frontend/components/schedule.rs +++ b/aep-schedule-website/src/frontend/components/schedule.rs @@ -90,7 +90,7 @@ fn CoursePeriods(i: usize, course: TakenCourse) -> impl IntoView { .into_iter() .map(|p| { let course = Arc::clone(&course); - view! {<PeriodEvent i period=p course period_type="T"/>} + view! { <PeriodEvent i period=p course period_type="T" /> } }) .collect_view() .into_any(), @@ -99,7 +99,7 @@ fn CoursePeriods(i: usize, course: TakenCourse) -> impl IntoView { .into_iter() .map(|p| { let course = Arc::clone(&course); - view! {<PeriodEvent i period=p course period_type="L"/>} + view! { <PeriodEvent i period=p course period_type="L" /> } }) .collect_view() .into_any(), @@ -111,18 +111,22 @@ fn CoursePeriods(i: usize, course: TakenCourse) -> impl IntoView { theo_group, lab_group, } => view! { - { - theo_group.periods.into_iter().map(|p| { + {theo_group + .periods + .into_iter() + .map(|p| { let course = Arc::clone(&course); - view! {<PeriodEvent i period=p course period_type="T"/>} - }).collect_view() - } - { - lab_group.periods.into_iter().map(|p| { + view! { <PeriodEvent i period=p course period_type="T" /> } + }) + .collect_view()} + {lab_group + .periods + .into_iter() + .map(|p| { let course = Arc::clone(&course); - view! {<PeriodEvent i period=p course period_type="L"/>} - }).collect_view() - } + view! { <PeriodEvent i period=p course period_type="L" /> } + }) + .collect_view()} } .into_any(), } @@ -140,19 +144,31 @@ pub fn ScheduleComponent(schedule: Schedule, calendar: Arc<Calendar>) -> impl In <div class="flex flex-col w-full items-center card p-2"> <a class="hidden" download="cours.ics" href=move || download.get() node_ref=link></a> <table class="cours"> - {courses.into_iter().enumerate().map(|(i, c)| view!{<Course i course={c} />}).collect_view()} + {courses + .into_iter() + .enumerate() + .map(|(i, c)| view! { <Course i course=c /> }) + .collect_view()} </table> - <Schedule last_day=schedule.last_day> - {courses2.into_iter().enumerate().map(|(i, c)| view!{<CoursePeriods i course=c />}).collect_view()} + <Schedule last_day=schedule + .last_day> + {courses2 + .into_iter() + .enumerate() + .map(|(i, c)| view! { <CoursePeriods i course=c /> }) + .collect_view()} </Schedule> - <button class="button-download flex" on:pointerdown=move |_| { - let ics = calendar.generate_ics(&schedule2); - let url = url_escape::encode_fragment(&ics); - set_download("data:text/plain;charset=utf-8,".to_string() + &url); - link.get().unwrap().click(); - }> - <Download weight=IconWeight::Regular size="3vh"/> - <span>"Télécharger le calendrier de cet horaire"</span> + <button + class="button-download flex" + on:pointerdown=move |_| { + let ics = calendar.generate_ics(&schedule2); + let url = url_escape::encode_fragment(&ics); + set_download("data:text/plain;charset=utf-8,".to_string() + &url); + link.get().unwrap().click(); + } + > + <Download weight=IconWeight::Regular size="3vh" /> + <span>"Télécharger le calendrier de cet horaire"</span> </button> </div> } diff --git a/aep-schedule-website/src/frontend/components/schedules.rs b/aep-schedule-website/src/frontend/components/schedules.rs index 17f3d96..2ebe5ca 100644 --- a/aep-schedule-website/src/frontend/components/schedules.rs +++ b/aep-schedule-website/src/frontend/components/schedules.rs @@ -14,40 +14,52 @@ pub fn SchedulesComponent() -> impl IntoView { <Await future=get_calendar() children=move |calendar| { + let calendar = Arc::new(calendar.clone().unwrap()); let bad_generation = state.schedule.get().is_empty(); let generated = state.step.get() == 6; match generated && !bad_generation { true => { - let calendar = Arc::new(calendar.clone().unwrap()); - view !{ + view! { <For each=move || state.schedule.get() - key= |course| course.id - children= move |schedule| { + key=|course| course.id + children=move |schedule| { let calendar = Arc::clone(&calendar); - view !{ - <ScheduleComponent schedule calendar/> - } + view! { <ScheduleComponent schedule calendar /> } } /> - }.into_any() - }, - _ => view ! { - <Todo/> - { - match generated && bad_generation { - true => Some(view !{ - <div class="warning-box"> - <WarningCircle size="4em"/> - <span> - "Aucun horaire n'a pu être généré, augmentez le nombre de conflits ou ouvrez des sections. Probablement que deux groupes sont toujours en conflits." - </span> - </div> - }), + } + .into_any() + } + _ => { + view! { + <Todo /> + <For + each=move || state.schedule.get() + key=|course| course.id + children=move |schedule| { + let calendar = Arc::clone(&calendar); + view! { <ScheduleComponent schedule calendar /> } + } + /> + {match generated && bad_generation { + true => { + Some( + view! { + <div class="warning-box"> + <WarningCircle size="4em" /> + <span> + "Aucun horaire n'a pu être généré, augmentez le nombre de conflits ou ouvrez des sections. Probablement que deux groupes sont toujours en conflits." + </span> + </div> + }, + ) + } false => None, - } + }} } - }.into_any() + .into_any() + } } } /> diff --git a/aep-schedule-website/src/frontend/pages/apropos.rs b/aep-schedule-website/src/frontend/pages/apropos.rs index 4921cbc..36406ba 100644 --- a/aep-schedule-website/src/frontend/pages/apropos.rs +++ b/aep-schedule-website/src/frontend/pages/apropos.rs @@ -5,26 +5,45 @@ pub fn HomePage() -> impl IntoView { view! { <section class="p-1 w-full h-full"> <div class="container flex flex-col justify-center p-4 mx-auto md:p-8"> - <p class="p-2 text-sm font-medium tracking-wider text-center uppercase">"Comment ça marche?"</p> - <h2 class="mb-12 text-4xl font-bold leading-none text-center sm:text-5xl">"Foires aux questions"</h2> + <p class="p-2 text-sm font-medium tracking-wider text-center uppercase"> + "Comment ça marche?" + </p> + <h2 class="mb-12 text-4xl font-bold leading-none text-center sm:text-5xl"> + "Foires aux questions" + </h2> <div class="grid gap-10 md:gap-8 sm:p-3 md:grid-cols-2 lg:px-12"> <div> - <h3 class="font-semibold">"Pourquoi avoir refait l'ancien générateur?"</h3> + <h3 class="font-semibold"> + "Pourquoi avoir refait l'ancien générateur?" + </h3> <p class="mt-1 dark:text-gray-600"> - "L'ancien générateur d'horaire était en mode maintenance depuis au moins 15 ans et changer l'architecture aurait été très difficile, en effet la vénérable base de code contenait littéralement 5 langages de programmation différents!"<br/> "- Marc-Antoine Manningham" + "L'ancien générateur d'horaire était en mode maintenance depuis au moins 15 ans et changer l'architecture aurait été très difficile, en effet la vénérable base de code contenait littéralement 5 langages de programmation différents!" + <br /> "- Marc-Antoine Manningham" </p> </div> <div> - <h3 class="font-semibold">"Qui sont les auteurs de la refonte du générateur d'horaire?"</h3> - <p class="mt-1 dark:text-gray-600">"Marc-Antoine Manningham - Création du frontend et du backend entièrement en Rust. Raphael Salvas, Achille Saint-Hillier, Sunnee Chevalier et Gabriel Billard - Inspiration de leur TP3 de LOG2420 pour l'interface de la refonte du générateur"</p> + <h3 class="font-semibold"> + "Qui sont les auteurs de la refonte du générateur d'horaire?" + </h3> + <p class="mt-1 dark:text-gray-600"> + "Marc-Antoine Manningham - Création du frontend et du backend entièrement en Rust. Raphael Salvas, Achille Saint-Hillier, Sunnee Chevalier et Gabriel Billard - Inspiration de leur TP3 de LOG2420 pour l'interface de la refonte du générateur" + </p> </div> <div> - <h3 class="font-semibold">"Comment le générateur génère aussi vite?"</h3> - <p class="mt-1 dark:text-gray-600">"D'abord, les horaires sont généré directement dans le navigateur de l'utilisateur en WebAssembly plutôt que sur le serveur. Aussi, plutôt que de générer tout les horaires, juste le top des horaires sont générés. Plusieurs techniques pour couper l'espace de combinaisons sont utilisées pour éliminer les branches qui ne respectent pas les contraintes ou qui sont sous-optimales. (branch and bound)"</p> + <h3 class="font-semibold"> + "Comment le générateur génère aussi vite?" + </h3> + <p class="mt-1 dark:text-gray-600"> + "D'abord, les horaires sont généré directement dans le navigateur de l'utilisateur en WebAssembly plutôt que sur le serveur. Aussi, plutôt que de générer tout les horaires, juste le top des horaires sont générés. Plusieurs techniques pour couper l'espace de combinaisons sont utilisées pour éliminer les branches qui ne respectent pas les contraintes ou qui sont sous-optimales. (branch and bound)" + </p> </div> <div> - <h3 class="font-semibold">"Si j'ai des suggestions où aller les mettre?"</h3> - <p class="mt-1 dark:text-gray-600">"Le bouton signaler un bug peut aussi être utilisé pour soumettre une fonctionnalité sur le GitLab. Sinon, les contributions sont aussi les bienvenues si vous êtes prêt à faire un peu de Rust!"</p> + <h3 class="font-semibold"> + "Si j'ai des suggestions où aller les mettre?" + </h3> + <p class="mt-1 dark:text-gray-600"> + "Le bouton signaler un bug peut aussi être utilisé pour soumettre une fonctionnalité sur le GitLab. Sinon, les contributions sont aussi les bienvenues si vous êtes prêt à faire un peu de Rust!" + </p> </div> </div> </div> diff --git a/aep-schedule-website/src/frontend/pages/classroom.rs b/aep-schedule-website/src/frontend/pages/classroom.rs index dbb2186..1e247cd 100644 --- a/aep-schedule-website/src/frontend/pages/classroom.rs +++ b/aep-schedule-website/src/frontend/pages/classroom.rs @@ -55,25 +55,45 @@ pub fn ClassRoomComponent() -> impl IntoView { view! { <section class="flex flex-col w-full justify-between items-center p-4"> <div class="warning-box"> - <WarningCircle size="5em"/> + <WarningCircle size="5em" /> <span> - <span>"Cet horaire est construit à partir de l'horaire général des cours de Polytechnique Montréal. D'autres activités peuvent occuper un local. Pour connaître l'horaire complet d'un local ou le réserver: "</span> - <a href="https://www.polymtl.ca/renseignements-generaux/reserver-une-salle-ou-organiser-un-evenement">"Réserver une salle"</a> + <span> + "Cet horaire est construit à partir de l'horaire général des cours de Polytechnique Montréal. D'autres activités peuvent occuper un local. Pour connaître l'horaire complet d'un local ou le réserver: " + </span> + <a href="https://www.polymtl.ca/renseignements-generaux/reserver-une-salle-ou-organiser-un-evenement"> + "Réserver une salle" + </a> </span> </div> - <Await - future=get_classrooms() - let:classrooms - > - {classrooms.as_ref().map(|classrooms| { - let classrooms = classrooms.into_iter().map(|c| AutoCompleteOption::new(c.to_string(), c.to_string())).collect(); - view!{ - <AutoComplete suggestion_list=classrooms placeholder="Local" class="w-96 shadow-2xl border-b-4 border-amber-500 focus:outline-none focus:ring-0" submit=on_submit id="input-classroom"/> - } - }).ok()} + <Await future=get_classrooms() let:classrooms> + {classrooms + .as_ref() + .map(|classrooms| { + let classrooms = classrooms + .into_iter() + .map(|c| AutoCompleteOption::new(c.to_string(), c.to_string())) + .collect(); + view! { + <AutoComplete + suggestion_list=classrooms + placeholder="Local" + class="w-96 shadow-2xl border-b-4 border-amber-500 focus:outline-none focus:ring-0" + submit=on_submit + id="input-classroom" + /> + } + }) + .ok()} </Await> <Schedule last_day=5 col_height="0.6em"> - {move || periods.get().into_iter().enumerate().map(|(i, p)| view!{<PeriodEvent i period_course=p/>}).collect_view()} + {move || { + periods + .get() + .into_iter() + .enumerate() + .map(|(i, p)| view! { <PeriodEvent i period_course=p /> }) + .collect_view() + }} </Schedule> </section> } diff --git a/aep-schedule-website/src/frontend/pages/generator.rs b/aep-schedule-website/src/frontend/pages/generator.rs index b1504b2..8babed2 100644 --- a/aep-schedule-website/src/frontend/pages/generator.rs +++ b/aep-schedule-website/src/frontend/pages/generator.rs @@ -29,27 +29,28 @@ pub fn GeneratorPage() -> impl IntoView { view! { <aside class="left-panel" class=("hide-left-panel", hide)> - <OptionsForms/> + <OptionsForms /> </aside> - <section class="right-panel" - // on:scroll=move |ev| { - // use web_sys::wasm_bindgen::JsCast; - // let target = ev - // .target() - // .unwrap() - // .dyn_into::<web_sys::Element>() - // .unwrap(); - // let scroll_top = target.scroll_top() as f64; - // let client_height = target.client_height() as f64; - // let scroll_height = target.scroll_height() as f64; - // if (scroll_top + client_height >= scroll_height - 500.0) && state.step.get() == 6 { - // state.regenerate(); - // } + <section class="right-panel"> + // on:scroll=move |ev| { + // use web_sys::wasm_bindgen::JsCast; + // let target = ev + // .target() + // .unwrap() + // .dyn_into::<web_sys::Element>() + // .unwrap(); + // let scroll_top = target.scroll_top() as f64; + // let client_height = target.client_height() as f64; + // let scroll_height = target.scroll_height() as f64; + // if (scroll_top + client_height >= scroll_height - 500.0) && state.step.get() == 6 { + // state.regenerate(); + // } - > - <SchedulesComponent/> + <SchedulesComponent /> </section> - <Notifications modal set_modal/> - <button on:pointerdown=move |_| {hide.set(false)} id="go-back"><CaretDoubleRight weight=IconWeight::Regular size="3vh"/></button> + <Notifications modal set_modal /> + <button on:pointerdown=move |_| { hide.set(false) } id="go-back"> + <CaretDoubleRight weight=IconWeight::Regular size="3vh" /> + </button> } } -- GitLab