-
Notifications
You must be signed in to change notification settings - Fork 12
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Layers page #31
Layers page #31
Changes from 2 commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
import Image from "next/image"; | ||
|
||
import deepchemCross from "../../public/icons/deepchem-cross.png"; | ||
|
||
/** | ||
* The FilterButton component is used to create a button for each filter | ||
* @component | ||
* @param {Object} props - props passed to the component | ||
* @param {Array} props.category - array of all the available filters | ||
* @param {String} props.name - name of the particular filter | ||
* @param {Image} props.image - image associated to the filter | ||
* @return {JSX.Element} - A JSX element representing the FilterButton | ||
*/ | ||
const FilterButton = ({ category, name, image }) => { | ||
const TRUNC_LENGTH = 20; | ||
const nameShort = name.replace(/Model$/g, ""); | ||
|
||
return ( | ||
<> | ||
<div | ||
className={`${ | ||
category.includes(name) ? "btn-selected-filter" : "btn-filter" | ||
}`} | ||
title={name} | ||
> | ||
{image ? ( | ||
<Image | ||
src={category.includes(name) ? deepchemCross : image} | ||
alt={name} | ||
width={14} | ||
/> | ||
) : ( | ||
category.includes(name) && ( | ||
<Image src={deepchemCross} alt={name} width={14} /> | ||
) | ||
)} | ||
<p | ||
className={`${ | ||
category.includes(name) | ||
? "btn-text-selected-filter" | ||
: "btn-text-filter" | ||
}`} | ||
> | ||
{nameShort.length > TRUNC_LENGTH | ||
? nameShort.substring(0, TRUNC_LENGTH) + "..." | ||
: nameShort} | ||
</p> | ||
</div> | ||
</> | ||
); | ||
}; | ||
|
||
export default FilterButton; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
import Image from "next/image"; | ||
import Link from "next/link"; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This component is also very similar. I think some part has been omitted out, but I think can be reused. |
||
|
||
import deepchemPytorch from "../../public/icons/deepchem-pytorch.png"; | ||
import deepchemKeras from "../../public/icons/deepchem-keras.png"; | ||
|
||
/** | ||
* Function to parse and format strings that are passed to the model card | ||
* @function | ||
* @param {string} name - string of the name passed | ||
* @return {string} - The parsed and formatted string | ||
*/ | ||
function parseName(name) { | ||
name = name.replaceAll(/([A-Z]+)/g, " $1"); | ||
name = name.replace(/([^ ])(Layer)/, "$1 Layer"); | ||
return name; | ||
} | ||
|
||
const LayerCard = ({ layer }) => { | ||
let models = layer.models.length | ||
? layer.models.join(", ") | ||
: "N/A"; | ||
models = models + " " + "\xa0".repeat(300); | ||
|
||
return ( | ||
<> | ||
<Link href={layer.url} target="_blank"> | ||
<div className="flex flex-col gap-4 py-4 px-5 bg-white shadow-[0_4px_4px_rgba(0,0,0,0.25)] rounded-[10px] layer-card hover:scale-[1.03] transition-all"> | ||
<div className="flex flex-row justify-between w-full gap-8 items-start"> | ||
<div className="text-xl font-medium text-dc-orange"> | ||
{parseName(layer.name)} | ||
</div> | ||
<div className="flex flex-row items-center gap-1.5 bg-dc-light-blue/5 px-2 py-1 rounded-md"> | ||
{layer.category === "torch" && ( | ||
<Image src={deepchemPytorch} alt="PyTorch" width={16} /> | ||
)} | ||
{layer.category === "keras" && ( | ||
<Image src={deepchemKeras} alt="Keras" width={16} /> | ||
)} | ||
</div> | ||
<div className="font-medium text-sm text-dc-gray"> | ||
{layer.category} | ||
</div> | ||
</div> | ||
{ | ||
<div className="text-base font-medium text-dc-light-blue w-full mt-4 md:mt-auto"> | ||
<p className="text-dc-gray/60">Acceptable Models</p> | ||
<p className="text-xs text-dc-gray font-medium break-all"> | ||
{models} | ||
</p> | ||
</div> | ||
} | ||
</div> | ||
</Link> | ||
</> | ||
); | ||
}; | ||
|
||
export default LayerCard; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,155 @@ | ||
import React, { useEffect, useState } from "react"; | ||
|
||
import Image from "next/image"; | ||
|
||
import LayerCard from "/components/Layers/LayerCard"; | ||
import FilterButton from "/components/Layers/FilterButton"; | ||
|
||
import layers from "/data/layers/layers.json"; | ||
import modelList from "/data/layers/models.json"; | ||
|
||
import deepchemPyTorch from "/public/icons/deepchem-pytorch.png"; | ||
import deepchemKeras from "/public/icons/deepchem-keras.png"; | ||
import deepchemFilter from "/public/icons/deepchem-filter.png"; | ||
|
||
|
||
/** | ||
* Models component that displays the models page of the application | ||
* @component | ||
* @return {JSX.Element} The JSX element to render the Model component | ||
*/ | ||
const Layers = () => { | ||
|
||
const [filteredLayers, setFilteredLayers] = useState(layers); | ||
const [models, setModels] = useState([]); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I am not sure what models exactly are in the layers page, is the naming intended? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Models that use the layers so layers can be filtered with their respective models. |
||
const [isPopUp, setIsPopUp] = useState(false); | ||
|
||
const handleClick = (category, value) => { | ||
switch (category) { | ||
case "models": | ||
models.includes(value) | ||
? setModels(models.filter((item) => item !== value)) | ||
: setModels([...models, value]); | ||
break; | ||
default: | ||
break; | ||
} | ||
}; | ||
|
||
const handlePopUp = () => { | ||
setIsPopUp(!isPopUp); | ||
}; | ||
|
||
useEffect(() => { | ||
let newlayers = []; | ||
const flayers = layers; | ||
if ( | ||
models.length === 0 | ||
) { | ||
newlayers = layers; | ||
} else { | ||
flayers.map((flayer) => { | ||
let exist = 1; | ||
models.map((value) => { | ||
if (!flayer.models.includes(value)) { | ||
exist = 0; | ||
} | ||
}); | ||
if (exist == 1) { | ||
newlayers.push(flayer); | ||
} | ||
}); | ||
} | ||
|
||
setFilteredLayers(newlayers); | ||
}, [models]); | ||
|
||
useEffect(() => { | ||
window.addEventListener("resize", () => { | ||
if (window.innerWidth > 1024) { | ||
setIsPopUp(false); | ||
} | ||
}); | ||
}, []); | ||
|
||
return ( | ||
|
||
<div className="layers"> | ||
<div | ||
className={`${ | ||
isPopUp ? "flex" : "hidden" | ||
} fixed bg-dc-gray/80 w-full h-[100vh] top-0 lg:hidden`} | ||
onClick={handlePopUp} | ||
></div> | ||
<div className= "flex flex-col items-start w-full px-[25px] 2xl:px-[300px] py-8 lg:py-16 gap-6"> | ||
{/* HEADING BEGIN */} | ||
<div className="flex flex-row w-[100%] items-center justify-between py-2.5"> | ||
<div className="lg:text-4xl text-[26px]">Our Layers</div> | ||
<div className="lg:hidden"> | ||
<button className="min-w-0" onClick={handlePopUp}> | ||
<Image src={deepchemFilter} alt={"Filter Button"} width={18} /> | ||
</button> | ||
</div> | ||
{/* HEADING END */} | ||
{/* BODY BEGIN */} | ||
<div className="flex flex-row items-start gap-12 w-full"> | ||
{/* FILTER SECTION BEGIN */} | ||
<div | ||
className={`${ | ||
isPopUp | ||
? "fixed flex left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2 px-8 py-6 bg-white shadow-[0_4px_4px_rgba(0,0,0,0.25)] rounded-[10px] w-[89%] overflow-y-auto h-[85vh]" | ||
: "hidden" | ||
} lg:flex lg:relative lg:left-0 lg:top-0 lg:translate-x-0 lg:translate-y-0 lg:shadow-none lg:rounded-none flex-col items-start gap-5 lg:min-w-[240px] lg:max-w-[240px] lg:border-r-2 lg:py-0 lg:pl-0 pr-4 lg:border-dc-light-gray`} | ||
></div> | ||
{/* MODEL BEGIN */} | ||
<div className="category-filter"> | ||
<div className="category-text-filter">Model</div> | ||
<div className="btn-container-filter"> | ||
{modelList.map((model, index) => ( | ||
<div key={`feat-${index}`}> | ||
<button | ||
className="rmv-filter" | ||
onClick={() => { | ||
handleClick("models", model); | ||
}} | ||
> | ||
<FilterButton | ||
category={models} | ||
name={model} | ||
image={null} | ||
/> | ||
</button> | ||
</div> | ||
))} | ||
</div> | ||
</div> | ||
{/* MODEL END */} | ||
{/* LAYER CARDS SECTION BEGIN */} | ||
<div | ||
className={`items-start ${ | ||
filteredLayers.length | ||
? "gap-8 justify-center layer-container" | ||
: "" | ||
} w-full`} | ||
> | ||
{filteredLayers.length ? ( | ||
filteredLayers.map((layer) => ( | ||
<LayerCard key={layer.id} layer={layer} /> | ||
)) | ||
) : ( | ||
<div className="w-full mt-[5vh] flex items-center flex-col flex-grow"> | ||
<i className="fa-solid fa-triangle-exclamation text-7xl text-dc-gray/10 mb-2"></i> | ||
<p className="text-dc-gray/60">No such layers exist!</p> | ||
</div> | ||
)} | ||
</div> | ||
{/* MODEL CARDS SECTION END */} | ||
</div> | ||
{/*BODY END*/} | ||
</div> | ||
</div> | ||
</div> | ||
); | ||
}; | ||
|
||
export default Layers; |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -42,6 +42,7 @@ canvas { | |
.explore, | ||
.about, | ||
.models, | ||
.layers, | ||
.tutorials { | ||
zoom: 0.8; | ||
} | ||
|
@@ -227,3 +228,49 @@ footer { | |
@apply pb-4; | ||
} | ||
} | ||
|
||
/* layers page */ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If you are using the exact same styling, you can just reuse the classes. No need to redeclare with a different class name. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. done. |
||
@layer component { | ||
|
||
.btn-container-filter { | ||
@apply flex flex-row items-start gap-2.5 flex-wrap; | ||
} | ||
|
||
.rmv-filter { | ||
@apply p-0 normal-case min-w-0; | ||
} | ||
|
||
.btn-filter { | ||
@apply flex flex-row items-center gap-2.5 py-0.5 px-2 box-border bg-white border border-solid border-dc-light-gray rounded-md; | ||
} | ||
|
||
.btn-selected-filter { | ||
@apply flex flex-row items-center gap-2.5 py-0.5 px-2 box-border bg-dc-light-gray border border-solid border-dc-light-gray rounded-md; | ||
} | ||
|
||
.btn-text-filter { | ||
@apply text-[0.8rem] text-dc-gray text-ellipsis font-medium; | ||
} | ||
|
||
.btn-text-selected-filter { | ||
@apply text-[0.8rem] text-dc-white break-all; | ||
} | ||
|
||
.category-text-filter { | ||
@apply text-lg text-dc-light-blue; | ||
} | ||
|
||
.category-filter { | ||
@apply flex flex-col items-start gap-2.5; | ||
} | ||
|
||
.layer-container { | ||
@apply w-full grid grid-cols-1 md:grid-cols-2 3xl:grid-cols-3; | ||
} | ||
|
||
.layer-card { | ||
@apply h-fit md:min-h-[260px]; | ||
} | ||
|
||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This component is also exactly the same as
Models/FilterButton.jsx
. Please reuse the component, maybe move it to a directory namedCommon
and use it in both models and layers page.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done.