about summary refs log blame commit diff
path: root/frontend/src/main.rs
blob: 2d7cf3a9db6f8bee1d8231a09827b67be1081ed0 (plain) (tree)
1
2
3
4
5
6
7
8
9
                       
                            
                         
                       
                       

                                 

                                             

                    
                                              
                                    












                                                                   












                                                             






                                              


                             
                                                                    





                                     
                      

       













                                                                                  

                                                                             








                                      

      












                                                                            
 











                                                                 
                                                       








                                                                                                   
                                                       







                                                   


                                              
           
          





                                                                                                                
                              




                                                                                                                                  
                                                                                    
                                       

                                         









                                                                                                                                                                                   


                                                                          
                              
                          







                                                                                                                
                              



                                                                                                        
           


     



                          
                



       


                                       


                            
use gloo::console::log;
use gloo_net::http::Request;
use itertools::Itertools;
use serde::Deserialize;
use std::cmp::Ordering;
use std::hash::{Hash, Hasher};
use std::{ops::Deref, sync::Arc};
use wasm_bindgen::*;
use web_sys::{EventTarget, HtmlInputElement};
use yew::prelude::*;

//TODO: we should import this from the indexer
#[derive(Debug, Clone, Deserialize)]
struct CrawledResource {
    url: String,
    priority: u32, //how do we even calculate this
    word: Arc<String>,
}

//We implement PartialEq, Eq and Hash to ignore the priority field.
impl PartialEq for CrawledResource {
    fn eq(&self, other: &Self) -> bool {
        self.url == other.url && self.word == other.word
    }
}
impl Eq for CrawledResource {}

impl PartialOrd for CrawledResource {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

impl Ord for CrawledResource {
    fn cmp(&self, other: &Self) -> Ordering {
        self.priority.cmp(&other.priority)
    }
}

impl Hash for CrawledResource {
    fn hash<H: Hasher>(&self, state: &mut H) {
        self.url.hash(state);
        self.word.hash(state);
    }
}

#[derive(Debug, Clone)]
struct State {
    pub search_query: String,
    pub results: Option<Vec<CrawledResource>>, //TODO: some loading?
}

#[function_component(OSSE)]
fn osse() -> Html {
    let state = use_state(|| State {
        search_query: "".to_string(),
        results: None,
    });

    let display_results = |maybe_results: &Option<Vec<CrawledResource>>| -> Html {
        let maybe_results = maybe_results.as_ref();
        if maybe_results.is_none() {
            return html! {};
        }

        let results = maybe_results.unwrap();
        if !results.is_empty() {
            results
                .iter()
                .sorted()
                .map(|r| {
                    html! {
                        <div key={r.url.to_owned()}>
                        //Show page title and description
                            <a href={r.url.to_owned()}>{r.url.to_owned()}</a>
                        </div>
                    }
                })
                .collect::<Html>()
        } else {
            html! {
                <p>{"No results!"}</p>
            }
        }
    };

    let search_query_changed = {
        let cloned_state = state.clone();
        Callback::from(move |event: InputEvent| {
            let target: EventTarget = event
                .target()
                .expect("Event should have a target when dispatched");
            let input = target.unchecked_into::<HtmlInputElement>().value();
            log!("Input changed: {}", &input);
            let mut state = cloned_state.deref().clone();
            state.search_query = input;
            cloned_state.set(state);
        })
    };

    let on_submit = {
        let cloned_state = state.clone();

        Callback::from(move |event: FocusEvent| {
            event.prevent_default();
            let state = cloned_state.deref().clone();

            //fetch
            {
                let cloned_state = cloned_state.clone();
                wasm_bindgen_futures::spawn_local(async move {
                    let mut state = cloned_state.deref().clone();
                    //TODO: what if its on another host
                    let endpoint = format!("http://127.0.0.1:4444/search/{}", &state.search_query);

                    let fetched_results = Request::get(endpoint.as_str()).send().await.unwrap();

                    let fetched_json: Vec<CrawledResource> = match fetched_results.json().await {
                        Err(e) => panic!("Im panic: {}", e),
                        Ok(json) => json,
                    };

                    state.results = Some(fetched_json);

                    cloned_state.set(state);
                });
            }

            log!("Submit: {}", state.search_query);
        })
    };

    let curr_state = state.deref().to_owned();

    html! {
        <>
            <header>
                <nav class="navbar bg-light sticky-top">
                    <div class="container-fluid">
                        <div>
                            <a href="https://github.com/Baitinq/OSSE" class="navbar-brand h1 mx-2">{"OSSE"}</a>
                            <span class="navbar-text mb-0">{"| Your favorite independent search engine."}</span>
                        </div>
                        <a href="https://github.com/Baitinq" class="navbar-text">{"Made by Baitinq"}</a>
                    </div>
                </nav>
            </header>
            <main style="display: flex; flex-direction: column; min-height: 100vh; align-items: center; justify-content: center;">
                //SET AT MIDDLE OF VIEWPORT IF NO SEARCHING AND TOP 25% IF SEARCHING
                <div class="container">
                    <div class="row">
                        <div class="col">
                                <section class="my-5">
                                    <b class="display-4">{"OSSE"}</b>
                                    <p>{"Your favorite independent search engine."}</p>
                                    <form onsubmit={on_submit}>
                                        <div class="input-group input-group-lg my-2">
                                            <input oninput={search_query_changed} value={curr_state.search_query}type="text" class="form-control" placeholder="Search with OSSE" />
                                            <button class="btn btn-primary" type="submit" >{"Search!"}</button>
                                        </div>
                                    </form>
                                </section>
                                <section>
                                    {display_results(&curr_state.results)}
                                </section>
                        </div>
                    </div>
                </div>
            </main>
            <footer class="mt-5">
                <nav class="navbar bg-light">
                    <div class="container-fluid">
                        <div>
                            <a href="https://github.com/Baitinq/OSSE" class="navbar-brand h1 mx-2">{"OSSE"}</a>
                            <span class="navbar-text mb-0">{"| Your favorite independent search engine."}</span>
                        </div>
                        <a href="https://github.com/Baitinq" class="navbar-text">{"Made by Baitinq"}</a>
                    </div>
                </nav>
            </footer>
        </>
    }
}

#[function_component(App)]
fn app() -> Html {
    html! {
    <>
        <OSSE />
    </>
    }
}

//Your favorite search engine in navbar
//Search in middle

fn main() {
    yew::start_app::<App>();
}