Skip to content
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

Merged
merged 3 commits into from
Nov 21, 2023
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 53 additions & 0 deletions new-website/deepchem/components/Layers/FilterButton.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import Image from "next/image";
Copy link
Contributor

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 named Common and use it in both models and layers page.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done.


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;
59 changes: 59 additions & 0 deletions new-website/deepchem/components/Layers/LayerCard.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import Image from "next/image";
import Link from "next/link";
Copy link
Contributor

Choose a reason for hiding this comment

The 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;
155 changes: 155 additions & 0 deletions new-website/deepchem/pages/layers.js
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([]);
Copy link
Contributor

Choose a reason for hiding this comment

The 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?

Copy link
Contributor Author

Choose a reason for hiding this comment

The 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;
47 changes: 47 additions & 0 deletions new-website/deepchem/styles/globals.css
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ canvas {
.explore,
.about,
.models,
.layers,
.tutorials {
zoom: 0.8;
}
Expand Down Expand Up @@ -227,3 +228,49 @@ footer {
@apply pb-4;
}
}

/* layers page */
Copy link
Contributor

Choose a reason for hiding this comment

The 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.

Copy link
Contributor Author

Choose a reason for hiding this comment

The 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];
}

}

Loading