diff --git a/aep-schedule-website/src/backend/fileserv.rs b/aep-schedule-website/src/backend/fileserv.rs index 904ebf2b1b2e774b3684eded0dc7e9c57fb50b9b..9a0424e70bec000b73cef47fd51918fe41b6c423 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 85d7f17fa4ae411ca8fb78b3114270028949f9ae..961fe026b4ed505bcbc30fcd54401c097e8170fc 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 816bb1be73167619943846f6d1e5a2d90c674e43..21c930061ec84822848fc02014c52c0f27be1fda 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 c5ded8dcfe24bdbcff21ee8781507981f65fceec..4c2e5a2aabf25eab6c94202bf536b7c18996f4fe 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 94a238074d8c9cbc3839cde45e24146163a73ae4..8962ea503b893c568fc100cd51dd513e83e3caa7 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 6993eee0f44b6532efcab44fa08c734ef1e7e9e5..014ef07d282cf756979c139529518fcb4cbaab4c 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 9bceace913599d717c88fae3919e6dda3931f362..35cbea70246fe48f5f0bac00db0d917686eb9b81 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 b8adfe645ee3af62e30bd3223e69e1d6ff41799e..61dde2871d804fe4baf3ee0ed01c7855529d8c90 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 41f98aa4e5645ead9fe407ec49b04100b1a10b35..40e3852095e7f054bac9c2e93747d31d71f5348c 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 6e6c027c177e498e3168833932e3740be1f59c46..0e1f693cd6e29053933fc59c3afa1796e241acea 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 918ac1e79a618d7689ddbab40c3c99dc81d2cbd4..bbf62e87ce980ecdae89db8e19a09c221c071173 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 fa342b8fd89e032ca2f104853c329c5d2f96c391..3ebbf6989d14a62ea7d111045f6a938c6c3afb54 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 ab8f10935e423fc2bebc0e0d63993361227d821f..43d5070445000b8fe4de90524ccd580b8b06df16 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 5f15b8c27f498bd96d0885c51f6d905c79dca6c2..50acbbb42729961d421fe7a7270f8f2ed3fab44e 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 e7c4cc7f07c6a9c87cb95d529ad8f005e38f5eb9..3a5d56946c912492767711e64dbb0a15442f74dd 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 17f3d96a2c9e9f998337ba84e88fc5834b2171d4..2ebe5caf15a33cb054e4925354daf95ffdf95ebb 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 4921cbc00c2ae5de412ef32fac034a51ad4c46aa..36406ba6f4b9637c2347882ec02f3fb392629a52 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 dbb21863e035f008b45f4febe75d1024a85980d4..1e247cd63bcff251c996834e293081e2b467fd4d 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 b1504b2ef5304a2449f601cb65976a9d1ee07d18..8babed2a3a37637ccc45a765b1060840fcc11e66 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> } }