Skip to content

Commit

Permalink
Add search feature.
Browse files Browse the repository at this point in the history
  • Loading branch information
AhmedBasem20 committed Aug 12, 2023
1 parent 7594cb1 commit 2b810a7
Show file tree
Hide file tree
Showing 4 changed files with 150 additions and 9 deletions.
1 change: 1 addition & 0 deletions aiida-registry-app/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
"@emotion/styled": "^11.11.0",
"@mui/icons-material": "^5.14.0",
"@mui/material": "^5.14.0",
"fuse.js": "^6.6.2",
"markdown-to-jsx": "^7.2.1",
"react": "^18.2.0",
"react-dom": "^18.2.0",
Expand Down
51 changes: 51 additions & 0 deletions aiida-registry-app/src/App.css
Original file line number Diff line number Diff line change
Expand Up @@ -429,8 +429,59 @@ content: "→";
padding-right: 5px;
}

.search {
position: relative;
margin-bottom: 10px;
}

.search-form {
display: flex;
min-height: 50px;
}

input[type='text'] {
padding: 8px;
border: 1px solid #ccc;
border-radius: 4px;
flex: 1;
}

/* Styles for the suggestions list */
.suggestions-list {
position: absolute;
list-style: none;
padding: 0;
margin: 0;
max-height: 200px; /* Add a max-height to limit the suggestions' height */
overflow-y: auto; /* Enable vertical scrolling if there are too many suggestions */
background-color: #fff;
border: 1px solid #ccc;
border-radius: 4px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}

.suggestion-item {
padding: 8px;
cursor: pointer;
border-bottom: 1px solid #ccc;
}

.suggestion-item:last-child {
border-bottom: none;
}

.suggestion-item:hover {
background-color: #f2f2f2;
}


@media only screen and (min-width : 150px) and (max-width : 780px)
{
.search
{
width: 45%;
margin: 0 auto;
}
.globalsummary-box
{
width:90%;
Expand Down
21 changes: 18 additions & 3 deletions aiida-registry-app/src/App.jsx
Original file line number Diff line number Diff line change
@@ -1,26 +1,41 @@
import { Route, Routes } from 'react-router-dom';
import { useParams } from 'react-router-dom';
import Logo from './assets/logo.svg'
import whiteLogo from './assets/logo-white-text.svg'
import MARVEL from './assets/MARVEL.png'
import MaX from './assets/MaX.png'
import './App.css'
import { useEffect } from 'react';

import { useEffect, createContext, useState, useContext } from 'react';
import MainIndex from './Components/MainIndex'
import Details from './Components/Details'
import Sidebar from './Components/Sidebar';

//The search context enables accessing the search query among different components.
const SearchContext = createContext();

export const useSearchContext = () => useContext(SearchContext);

const SearchContextProvider = ({ children }) => {
const [searchQuery, setSearchQuery] = useState('');

return (
<SearchContext.Provider value={{ searchQuery, setSearchQuery }}>
{children}
</SearchContext.Provider>
);
};

function App() {

return (
<>
<Header />
<div style={{marginTop:'155px'}}>
<SearchContextProvider>
<Routes>
<Route path="/" element={<MainIndex />} />
<Route path="/:key" element={<DetailsContainer />} />
</Routes>
</SearchContextProvider>
</div>
<Footer />
</>
Expand Down
86 changes: 80 additions & 6 deletions aiida-registry-app/src/Components/MainIndex.jsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { useState } from 'react';
import { Link, Route, Routes } from 'react-router-dom';
import { Link } from 'react-router-dom';
import jsonData from '../plugins_metadata.json'
import base64Icon from '../base64Icon';
import Box from '@mui/material/Box';
Expand All @@ -8,16 +8,82 @@ import MenuItem from '@mui/material/MenuItem';
import FormControl from '@mui/material/FormControl';
import Select from '@mui/material/Select';
import CheckCircleIcon from '@mui/icons-material/CheckCircle';

import SearchIcon from '@mui/icons-material/Search';
import Fuse from 'fuse.js'
import {useSearchContext} from '../App.jsx'
const globalsummary = jsonData["globalsummary"]
const plugins = jsonData["plugins"]
const status_dict = jsonData["status_dict"]
const length = Object.keys(plugins).length;
const currentPath = import.meta.env.VITE_PR_PREVIEW_PATH || "/aiida-registry/";

//This is a global variable that will change based on search query or sort order.
let sortedData = plugins


//Convert the plugins object to a list and save it to plugins_index variable.
//Needed because Fuse.js only accepts arrays.
let plugins_index = []
Object.entries(plugins).map(([key, value]) => (
plugins_index.push(value)
))

function Search() {
const { searchQuery, setSearchQuery } = useSearchContext();
// Update searchQuery when input changes
const handleSearch = (searchQuery) => {
setSearchQuery(searchQuery);
}
//Create a fuce instance for searching the provided keys.
//TODO: add entry points data to the keys to be searched.
const fuse = new Fuse(plugins_index, {
keys: [ 'name', 'metadata.description', 'entry_point_prefix', 'metadata.author'],
includeScore: true,
ignoreLocation: true,
threshold: 0.2
})
let searchRes = fuse.search(searchQuery)
const suggestions = searchRes.map((item) => item.item.name); //get the list searched plugins
const resultObject = {};

//Convert the search results array to object
searchRes.forEach(item => {
resultObject[item.item.name] = item.item;
});

//Update the sortedData object with the search results
//This method doesn't correctly display the plugins.
//TODO: try useContext or any state management instead.
const handleSubmit = (e) => {
e.preventDefault();
sortedData = resultObject;
};

//return the suggestions list
return (
<>
<div className="search">
<form className="search-form">
<input type="text" placeholder="Search for plugins" value={searchQuery} label = "search" onChange={(e) => handleSearch(e.target.value)} />
<button style={{fontSize:'20px'}} onClick={(e) => {handleSubmit(e);}}><SearchIcon /></button>
</form>
</div>
{/* Display the list of suggestions */}
<ul className="suggestions-list">
{suggestions.map((suggestion) => (
<Link to={`/${suggestion}`}><li key={suggestion} className="suggestion-item">
{suggestion}
</li></Link>
))}
</ul>
</>
)
}


function MainIndex() {
const { searchQuery, setSearchQuery } = useSearchContext();
const [sortOption, setSortOption] = useState('alpha');
const [sortedData, setSortedData] = useState(plugins);
document.documentElement.style.scrollBehavior = 'auto';

function setupScrollBehavior() {
Expand Down Expand Up @@ -54,8 +120,11 @@ function MainIndex() {
sortedPlugins = plugins;
}

setSortedData(sortedPlugins);
sortedData = sortedPlugins
};
if (searchQuery == "" && sortOption !== 'commits') {
sortedData = plugins
}
return (
<main className='fade-enter'>

Expand All @@ -80,10 +149,14 @@ function MainIndex() {
</div>
</div>
<div id='entrylist'>
<h1 style={{display: 'inline'}}>
<div style={{display:'flex', flexDirection:'row', alignItems:'center'}}>
<h1 style={{minHeight:'50px', padding:'15px 8px', display:'flex', flexDirection:'column'}}>
Package list
</h1>
<Box sx={{ minWidth: 120 }} style={{display:'inline', padding:'20px'}}>
<div style={{minHeight:'50px', padding:'15px 8px', borderRadius:'0 0 0 0', flex:'1'}}>
<Search />
</div>
<Box style={{minHeight:'50px', minWidth:'600px', padding:'15px 8px', display:'flex'}}>
<FormControl style={{width:'25%'}}>
<InputLabel id="demo-simple-select-label">Sort</InputLabel>
<Select
Expand All @@ -94,6 +167,7 @@ function MainIndex() {
</Select>
</FormControl>
</Box>
</div>

{Object.entries(sortedData).map(([key, value]) => (
<div className='submenu-entry' key={key}>
Expand Down

0 comments on commit 2b810a7

Please sign in to comment.