diff --git a/components/Display.tsx b/components/Display.tsx index 52801c2..8c7bb79 100644 --- a/components/Display.tsx +++ b/components/Display.tsx @@ -55,7 +55,12 @@ function Display(props: DisplayProps) { // ) if (props.loading) return ( -
Loading...
+
+
+ Loading... +
+
+
); return ( diff --git a/components/Options.tsx b/components/Options.tsx index 0ed7fef..b232e49 100644 --- a/components/Options.tsx +++ b/components/Options.tsx @@ -1,5 +1,5 @@ -import React, {useState, useCallback, useEffect} from "react"; -import {InputLabel, TextField, Select, MenuItem, Paper, FormControl, InputAdornment, IconButton} from "@mui/material" +import React, {useState, useCallback, useEffect, forwardRef} from "react"; +import {Grid, InputLabel, TextField, Select, MenuItem, Paper, FormControl, InputAdornment, IconButton} from "@mui/material" import {ClearRounded} from "@mui/icons-material" import MultiSelectField from "./msf"; // import {data as listOpts} from "../components/student_data_getter.tsx"; @@ -30,7 +30,9 @@ interface OptionsProps { loading: boolean; } -function Options(props: OptionsProps) { + + +function PreOptions (props: OptionsProps, ref: any) { // const [listOpts, setOpts]:[OptionsType, Function]= useState({ // batch:[], // hall:[], @@ -71,7 +73,8 @@ function Options(props: OptionsProps) { return ( -
+ + - - + + +
+ Gender - +
+
+ -
-
+ + - + + - + + -
- -
+ + +
-
- +
+ + + + +
); } +const Options = forwardRef(PreOptions); + export default Options; diff --git a/components/Overlay.tsx b/components/Overlay.tsx index 46f8e61..9b8b380 100644 --- a/components/Overlay.tsx +++ b/components/Overlay.tsx @@ -39,7 +39,8 @@ export default function Overlay(props: OverlayProps) { {

{props.data.n}

{props.data.i}

+ {Array.isArray(props.data.c) && props.data.c.length > 0 &&
+ +
}
+ ); case true: diff --git a/components/UserImage.tsx b/components/UserImage.tsx index 71760df..960f6e2 100644 --- a/components/UserImage.tsx +++ b/components/UserImage.tsx @@ -15,15 +15,6 @@ interface ImageProps { // console.log(Female); export default function Image(props: ImageProps) { -// return ( -// -// -// -// -// -// -// ); - console.log(Male); return (
{ -// return ( -// -// {React.Children.map(props.children, (child) => { -// return ( -// -// {child} -// -// ); -// })} -// -// ); - return ( +
+ {props.label === undefined ? props.name[0].toUpperCase() + props.name.slice(1,props.name.length).toLowerCase() @@ -40,5 +41,6 @@ export default function MultiSelectField(props: MSFProps) { ))} +
); } diff --git a/components/treeSCard.tsx b/components/treeSCard.tsx index ae7fd27..3076512 100644 --- a/components/treeSCard.tsx +++ b/components/treeSCard.tsx @@ -44,7 +44,16 @@ function TreeCard(props: TreeCardProps) { compact={"ultra"} data={el} key={el.i} - onClick={()=>{ + onClick={(e)=>{ + //smoothly scroll to top + document.getElementsByClassName("MuiModal-root")[0].scrollTo(0,0); +// let start = null; +// let scroll = window +// window.requestAnimationFrame(function step(currentTime) { +// if (!start) start = currentTime; +// +// }); + //actually show the card props.displayCard(el); }} /> diff --git a/pages/index.tsx b/pages/index.tsx index 5931b90..bfcafca 100644 --- a/pages/index.tsx +++ b/pages/index.tsx @@ -2,7 +2,7 @@ import Options from "../components/Options"; import Display from "../components/Display"; import Overlay from "../components/Overlay"; import ReactDOM from 'react-dom/client'; -import React, {useState, useEffect} from "react"; +import React, {useState, useEffect, useRef} from "react"; import {ThemeProvider,createTheme} from "@mui/material/styles"; import TextField from '@mui/material/TextField'; import Fab from "@mui/material/Fab"; @@ -19,9 +19,7 @@ if (!(typeof window === "undefined") && window.Worker) {//only on the client, TO var searcher = new Worker(new URL("../components/data_worker", import.meta.url)); } - - - +const isIFrame = (typeof window !== "undefined") && (window.top === window.self); export default function Home(props: Object) { @@ -37,11 +35,19 @@ export default function Home(props: Object) { dept:["Loading..."], bloodgrp:["Loading..."] }); + const [iFrame, setIFrame] = useState(false); + const searchBar = useRef(null); function queryHandler(event: any) { // console.log("Query result received"); if (event.data[0] == "query") { - setStudents(event.data[1]); + setStudents(event.data[1].toSorted((a:StudentType, b:StudentType) => { + try { + return (Number(a.i) > Number(b.i)); + } catch (err) { + return (a.i > b.i); + } + })); // setLoading(false); } } @@ -90,15 +96,16 @@ export default function Home(props: Object) { if (event.data !== "Worker ready") { //error condition errorHandler({data: "Error"}); - } else { -// console.log(searcher.onmessage); -// console.log("Worker should be ready now"); -// console.log("geting options list"); searcher.onmessage = (event) => { if (event.data[0] != "Options") return; setLoading(false); -// console.log("options list gotten"); + setTimeout(() => { + if (searchBar.current) { + // console.log("focusing search bar"); + searchBar.current.focus(); + } + }, 0); //I don't know why but it just won't focus without a timeout setOpts(event.data[1]); searcher.onmessage = null; //remove this event handler searcher.addEventListener("message", queryHandler); @@ -115,7 +122,29 @@ export default function Home(props: Object) { useEffect(() => { setDarkMode(localStorage.getItem("darkmode") !== "false") - },[props]); + },[]); + //on mount: load darkmode setting + + useEffect(() => { + setIFrame(!isIFrame); + }, []); + //on mount: load the iframe stopper, need to do it this way so that static generation generates the page normally (isIFrame is false when building because typeof window is "undefined" then) but if the page is indeed an iframe, the app stops working + //can't stop iframes the normal way (setting HTTP header to disallow them) because github pages doesn't allow you to set HTTP headers :( + + const keydownfxn = (e: any) => { + if (e.key === "/" && searchBar.current && document.activeElement != searchBar.current) { + e.preventDefault(); + searchBar.current.focus(); + } else if (e.key === "Escape" && document.activeElement && document.activeElement instanceof HTMLElement) { + document.activeElement.blur(); + } + }; + + useEffect(() => { + document.addEventListener("keydown", keydownfxn); + return () => {document.removeEventListener("keydown", keydownfxn)} + }, []) + //on mount: add / button detection to move focus to search bar useEffect(() => { if (darkMode) { @@ -124,7 +153,6 @@ export default function Home(props: Object) { document.body.style.backgroundColor = "#efefef"; } },[darkMode]); - //props should only change at start -> shouldn't change afterwards -> this should be good for loading darkmode pref at start const sendQuery = (query: QueryType)=> { @@ -166,7 +194,7 @@ export default function Home(props: Object) { searcher.postMessage(["ft", student]); } - return ( + if (!iFrame) return (
{`The data here is scraped from the Office Automation Portal. The data there can be updated via the Login Based Services > Student Profile > PI form . If you have had a branch change, please go to the ID Cell and update your ID Card to update your branch.`}

The changes if any will be reflected in about a week.

{`I can't see students' pictures/I can't access student data.`}

-

{`Access to student data is restricted to those currently on campus or connecting via VPN. Please visit the website once via either method so that the data can be stored locally. After this, you will be able to access student data from anywhere (as long as you don't wipe your cache or local files.)`}

+

{`Access to student data is restricted to those currently on campus or connecting via VPN. Please visit the website once via either method so that the data can be stored locally. After this, you will be able to access student data from anywhere (as long as you don't wipe your cache or local files).`}

+

Credits

+

Student Search has gone through many iterations over the years. The current one was made by Deven Gangwani and Krishnansh Agrawal (both Y21).The one just before this was made by Yash Srivastav (Y15).

+

Credit for Student Guide data (bacche, ammas and baapus) goes to the Counselling Service, IITK.

); }} @@ -254,6 +285,7 @@ export default function Home(props: Object) { sendQuery={sendQuery} listOpts={listOpts} loading={loading} + ref={searchBar} />
+ ); + else return ( +

Please view this page at search.pclub.in

); } diff --git a/styles/styles.css b/styles/styles.css index c27c156..b734aaa 100644 --- a/styles/styles.css +++ b/styles/styles.css @@ -2,6 +2,7 @@ body { background-color:#000; overflow-y: scroll; overflow-x: hidden; + /* font-family:Helvetica, sans-serif; */ } img { @@ -39,7 +40,7 @@ a { width: 80%; max-width: 900px; margin: auto; - padding:10px; + padding:30px 0px; display:flex; flex-direction:column; align-items: center; @@ -61,6 +62,7 @@ a { .options .field { width: 200px; + margin: auto; } .options .main-text { @@ -195,24 +197,32 @@ a { .overlay { width:80vw; - margin:auto; - display:flex; + margin:0 auto; + /* filter: drop-shadow(0px 5px 5px #777); */ + /* +display:flex; justify-content:center; - filter: drop-shadow(0px 5px 5px #777); - +*/ + display:grid; + grid-template-columns: 1fr; + align-content: start; } .overlay > * { margin:auto; - + margin-top:5vh; + grid-row-start: 1; + grid-column-start: 1; } #count { - display:flex; - justify-content:space-evenly; + width:200px; + margin:auto; } #count * { + margin:10px auto; + width:fit-content; padding: 10px; } @@ -229,13 +239,19 @@ a { } .overlay > .fade-enter { - position: absolute; - align-self:center; + /* position: absolute; */ + align-self:start; + margin:auto; + margin-top:5vh + /* justify-self:start; */ } .overlay > .fade-exit { - position: absolute; - align-self:center; + /* position: absolute; */ + align-self:start; + margin:auto; + margin-top:5vh + /* justify-self:start; */ } @@ -253,11 +269,11 @@ a { .loader { - width: 100px; - height: 100px; - border-radius: 100px; - border: dashed 10px #008888; - animation: loading 5s infinite linear; + width: 100px !important; + height: 100px !important; + border-radius: 100px !important; + border: dashed 10px #008888 !important; + animation: loading 5s infinite linear !important; } @keyframes loading {