From 5ef548749d8ef733e84be67acd4e2f1bd0d60f35 Mon Sep 17 00:00:00 2001 From: sbailo Date: Wed, 22 Sep 2021 11:06:51 +0200 Subject: [PATCH 01/68] custumize accordions in aitoolkit --- gui/src/components/aitoolkit/AIToolkitPage.js | 61 +++++++++++++++++-- 1 file changed, 57 insertions(+), 4 deletions(-) diff --git a/gui/src/components/aitoolkit/AIToolkitPage.js b/gui/src/components/aitoolkit/AIToolkitPage.js index fd794b220..740772398 100644 --- a/gui/src/components/aitoolkit/AIToolkitPage.js +++ b/gui/src/components/aitoolkit/AIToolkitPage.js @@ -16,7 +16,10 @@ * limitations under the License. */ import React, { useMemo } from 'react' -import { Typography, Accordion, AccordionSummary, AccordionDetails, makeStyles, Link, AccordionActions, Button, Grid, TextField } from '@material-ui/core' +import { Divider, Typography, AccordionDetails, makeStyles, Link, AccordionActions, Button, Grid, TextField } from '@material-ui/core' +import MUIAccordion from '@material-ui/core/Accordion'; +import MUIAccordionSummary from "@material-ui/core/AccordionSummary"; +import { withStyles } from "@material-ui/core/styles"; import tutorials from '../../toolkitMetadata' import ExpandMoreIcon from '@material-ui/icons/ExpandMore' import Markdown from '../Markdown' @@ -107,6 +110,49 @@ export default function AIToolkitPage() { methods: Object.keys(methods).sort() } }, []) + + const Accordion = withStyles({ + root: { + border: '5px solid rgba(127, 239, 239, 1)', + scrollbarGutter: 'false', + boxShadow: 'none', + marginLeft: '100px', + boxShadow: '0 3px 5px 2px rgba(127, 239, 239, 0.5)', + borderRadius: '10px 10px 10px 10px', + '&:not(:last-child)': { + borderBottom: 0, + }, + '&:before': { + display: 'none', + }, + '&$expanded': { + margin: 'auto', + }, + }, + heading: { + fontSize: 35, + flexBasis: '33.33%', + flexShrink: 0, + }, + secondaryHeading: { + fontSize: 10, + }, + expanded: {}, + })(MUIAccordion); + + const AccordionSummary = withStyles({ + root: { + flexDirection: "column" + }, + content: { + marginBottom: 0, + flexGrow: 1 + }, + expandIcon: { + marginRight: '10px', + paddingTop: '10px' + } + })(MUIAccordionSummary); return @@ -122,11 +168,13 @@ export default function AIToolkitPage() { `} + {
} {sections.map(section => (
- {section.title} + {/* {section.title} */}
{section.tutorials.map(tutorial => { + // const key = tutorial.key return }> - {tutorial.title} + {tutorial.title} + @@ -193,16 +242,20 @@ export default function AIToolkitPage() { - + + })} +
+
))}
-- GitLab From 09fcb3b83ac2811f9e8380cb5854cd85bf9e5744 Mon Sep 17 00:00:00 2001 From: sbailo Date: Wed, 22 Sep 2021 12:41:26 +0200 Subject: [PATCH 02/68] Fix lint errors --- gui/src/components/aitoolkit/AIToolkitPage.js | 38 +++++++++---------- 1 file changed, 18 insertions(+), 20 deletions(-) diff --git a/gui/src/components/aitoolkit/AIToolkitPage.js b/gui/src/components/aitoolkit/AIToolkitPage.js index 740772398..233ade555 100644 --- a/gui/src/components/aitoolkit/AIToolkitPage.js +++ b/gui/src/components/aitoolkit/AIToolkitPage.js @@ -12,14 +12,14 @@ * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and +* See the License for the specific language governing permissions and * limitations under the License. */ import React, { useMemo } from 'react' -import { Divider, Typography, AccordionDetails, makeStyles, Link, AccordionActions, Button, Grid, TextField } from '@material-ui/core' -import MUIAccordion from '@material-ui/core/Accordion'; -import MUIAccordionSummary from "@material-ui/core/AccordionSummary"; -import { withStyles } from "@material-ui/core/styles"; +import { Divider, Typography, AccordionDetails, makeStyles, Link, AccordionActions, Button, Grid, TextField } from '@material-ui/core' +import MUIAccordion from '@material-ui/core/Accordion' +import MUIAccordionSummary from '@material-ui/core/AccordionSummary' +import { withStyles } from '@material-ui/core/styles' import tutorials from '../../toolkitMetadata' import ExpandMoreIcon from '@material-ui/icons/ExpandMore' import Markdown from '../Markdown' @@ -110,39 +110,38 @@ export default function AIToolkitPage() { methods: Object.keys(methods).sort() } }, []) - + const Accordion = withStyles({ root: { border: '5px solid rgba(127, 239, 239, 1)', scrollbarGutter: 'false', - boxShadow: 'none', marginLeft: '100px', boxShadow: '0 3px 5px 2px rgba(127, 239, 239, 0.5)', borderRadius: '10px 10px 10px 10px', '&:not(:last-child)': { - borderBottom: 0, + borderBottom: 0 }, '&:before': { - display: 'none', + display: 'none' }, '&$expanded': { - margin: 'auto', - }, + margin: 'auto' + } }, heading: { fontSize: 35, flexBasis: '33.33%', - flexShrink: 0, + flexShrink: 0 }, secondaryHeading: { - fontSize: 10, + fontSize: 10 }, - expanded: {}, - })(MUIAccordion); + expanded: {} + })(MUIAccordion) const AccordionSummary = withStyles({ root: { - flexDirection: "column" + flexDirection: 'column' }, content: { marginBottom: 0, @@ -152,7 +151,7 @@ export default function AIToolkitPage() { marginRight: '10px', paddingTop: '10px' } - })(MUIAccordionSummary); + })(MUIAccordionSummary) return @@ -174,7 +173,7 @@ export default function AIToolkitPage() { {/* {section.title} */}
{section.tutorials.map(tutorial => { - // + // const key = tutorial.key return }> - {tutorial.title} + {tutorial.title} @@ -251,7 +250,6 @@ export default function AIToolkitPage() { - })}
-- GitLab From b277af435eca0014bb5abb695871789f0615e663 Mon Sep 17 00:00:00 2001 From: sbailo Date: Wed, 29 Sep 2021 10:47:40 +0200 Subject: [PATCH 03/68] Add fonts titillium regular and bold --- .../aitoolkit/fonts/TitilliumWeb-Bold.ttf | Bin 0 -> 53896 bytes .../aitoolkit/fonts/TitilliumWeb-Regular.ttf | Bin 0 -> 57392 bytes gui/src/index.css | 8 ++++++++ 3 files changed, 8 insertions(+) create mode 100644 gui/src/components/aitoolkit/fonts/TitilliumWeb-Bold.ttf create mode 100644 gui/src/components/aitoolkit/fonts/TitilliumWeb-Regular.ttf diff --git a/gui/src/components/aitoolkit/fonts/TitilliumWeb-Bold.ttf b/gui/src/components/aitoolkit/fonts/TitilliumWeb-Bold.ttf new file mode 100644 index 0000000000000000000000000000000000000000..b51a4d638774a8b5636e7cbef7e0a4d4b3ddf582 GIT binary patch literal 53896 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 z zWmev})p+_g&rrSBY8>}C<38`;U7uU;eb!apXzjIHN1xBl*7qoRqo?fib?>t7^Iq(r z&o|O{T5s`IYt8x*@n-97-fdl&`?mM@PPU@Qspcaej<@)7+u|+0oTr<*elItat~pWF z%fq|AqK&Ps{q1D^I=Qub0-dMl{L!A2HY;tGXO|JMNH&kDv6Y^`nfWvrn`WEnXeD?o1gXtLVH>t|0G#ovd>a|UaHufF<8rA3)-;Sx$DQ;S8>;3 zJl=#)ort$RGgyAxIh{Dd@2U7X4b8AHrR{UFbC1-z7UFu-alM5Zw7(OoGV>BR4KLm@ zDQ1z?Y<&!ApD~6wb57cyxK`8|bsV_G*)0T*<}01mwv=9;U_Rwk+L`@rpB*a#{r_zX z%>QNf5n7vV?QbWNU}))NTePsf&C_EGy0`*-Zi);#jx&73xMg54dfpEJnJ zn%^W8_e|ps%VK@Csvk^)g}4(o6qYroX+ypqWIMEdEEqd0?7a1f_y1e1?xa&_Y4(XV z_F9%RRoPQ%Y3FB#)@GmRL40y)4_bS3jvmwe%+cpLt{wmDBtw^@oj6IqGt5B8V+uZX zBHEH+5jr08)8BD?@dO<2cN_j2h&tQoJa!oVcOn=V?_mcH*Q3dB1X)eh$B_1$#}Mlh zX8nz8MV(Q{fm@v2LX;04X0?Skoy)3b($4H}c6R9MaWwk>Z_A=&M9ZaC#hQFQiNjnj zjSZjro!fYPkmF!WueOdz<)f7=MA#!L|f*< z9qI4zq@mNn(VP{t{w&vJwW!~9_22LMeUUTHJz}f{UDn39&abS7R=XEkd9!0>2_Kw_2tB0-fG{Ya~{ybKz8mrN&``+q}HK+d2wK~?F(yGIvpIY@NK2xk+ J6)Ps@{uh*&W)T1Y literal 0 HcmV?d00001 diff --git a/gui/src/components/aitoolkit/fonts/TitilliumWeb-Regular.ttf b/gui/src/components/aitoolkit/fonts/TitilliumWeb-Regular.ttf new file mode 100644 index 0000000000000000000000000000000000000000..a54ad4b93dea7fefe7b6f30ec7470eb7c8e41159 GIT binary patch literal 57392 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 XCsnH!M?balzj!b5tkplUC-eUSNwFir literal 0 HcmV?d00001 diff --git a/gui/src/index.css b/gui/src/index.css index b4cc7250b..34d4c0f2b 100644 --- a/gui/src/index.css +++ b/gui/src/index.css @@ -3,3 +3,11 @@ body { padding: 0; font-family: sans-serif; } + +@font-face { + font-family: 'TitilliumRegular'; + src: url(./components/aitoolkit/fonts/TitilliumWeb-Regular.ttf) format('truetype');} + +@font-face { + font-family: 'TitilliumBold'; + src: url(./components/aitoolkit/fonts/TitilliumWeb-Bold.ttf) format('truetype');} \ No newline at end of file -- GitLab From 814db395f0ac2f060100feaf3f2c9efd3d4eae88 Mon Sep 17 00:00:00 2001 From: sbailo Date: Wed, 29 Sep 2021 18:56:44 +0200 Subject: [PATCH 04/68] Add icons and background --- .../aitoolkit/assets/AIT_bg_title.jpg | Bin 0 -> 98641 bytes .../aitoolkit/assets/AIT_ico_bb_query.svg | 1 + .../aitoolkit/assets/AIT_ico_bb_replicate.svg | 1 + .../aitoolkit/assets/AIT_ico_bb_tutorial.svg | 1 + .../aitoolkit/assets/AIT_ico_bb_work.svg | 1 + 5 files changed, 4 insertions(+) create mode 100644 gui/src/components/aitoolkit/assets/AIT_bg_title.jpg create mode 100644 gui/src/components/aitoolkit/assets/AIT_ico_bb_query.svg create mode 100644 gui/src/components/aitoolkit/assets/AIT_ico_bb_replicate.svg create mode 100644 gui/src/components/aitoolkit/assets/AIT_ico_bb_tutorial.svg create mode 100644 gui/src/components/aitoolkit/assets/AIT_ico_bb_work.svg diff --git a/gui/src/components/aitoolkit/assets/AIT_bg_title.jpg b/gui/src/components/aitoolkit/assets/AIT_bg_title.jpg new file mode 100644 index 0000000000000000000000000000000000000000..511cde7740e76186408a15dc766a2fb7c6dff10a GIT binary patch literal 98641 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ΜMpwqHKksQiln$UH%~nh(ocG}v|DMZN-!AU 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

~}m>yLxmaWGH0n;MA$6pvbF# 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 DXTYSy literal 0 HcmV?d00001 diff --git a/gui/src/components/aitoolkit/assets/AIT_ico_bb_query.svg b/gui/src/components/aitoolkit/assets/AIT_ico_bb_query.svg new file mode 100644 index 000000000..f88f33ce3 --- /dev/null +++ b/gui/src/components/aitoolkit/assets/AIT_ico_bb_query.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/gui/src/components/aitoolkit/assets/AIT_ico_bb_replicate.svg b/gui/src/components/aitoolkit/assets/AIT_ico_bb_replicate.svg new file mode 100644 index 000000000..7970f37dd --- /dev/null +++ b/gui/src/components/aitoolkit/assets/AIT_ico_bb_replicate.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/gui/src/components/aitoolkit/assets/AIT_ico_bb_tutorial.svg b/gui/src/components/aitoolkit/assets/AIT_ico_bb_tutorial.svg new file mode 100644 index 000000000..cd40c353b --- /dev/null +++ b/gui/src/components/aitoolkit/assets/AIT_ico_bb_tutorial.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/gui/src/components/aitoolkit/assets/AIT_ico_bb_work.svg b/gui/src/components/aitoolkit/assets/AIT_ico_bb_work.svg new file mode 100644 index 000000000..6a3dfc30c --- /dev/null +++ b/gui/src/components/aitoolkit/assets/AIT_ico_bb_work.svg @@ -0,0 +1 @@ + \ No newline at end of file -- GitLab From d59014849666b592a1e346fb80e96625ba78a3da Mon Sep 17 00:00:00 2001 From: sbailo Date: Wed, 29 Sep 2021 18:57:42 +0200 Subject: [PATCH 05/68] Customize aitoolkit page with background and icons --- gui/src/components/aitoolkit/AIToolkitPage.js | 349 +++++------------- 1 file changed, 93 insertions(+), 256 deletions(-) diff --git a/gui/src/components/aitoolkit/AIToolkitPage.js b/gui/src/components/aitoolkit/AIToolkitPage.js index 233ade555..807c23855 100644 --- a/gui/src/components/aitoolkit/AIToolkitPage.js +++ b/gui/src/components/aitoolkit/AIToolkitPage.js @@ -12,49 +12,67 @@ * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and + * See the License for the specific language governing permissions and * limitations under the License. */ -import React, { useMemo } from 'react' -import { Divider, Typography, AccordionDetails, makeStyles, Link, AccordionActions, Button, Grid, TextField } from '@material-ui/core' -import MUIAccordion from '@material-ui/core/Accordion' -import MUIAccordionSummary from '@material-ui/core/AccordionSummary' -import { withStyles } from '@material-ui/core/styles' -import tutorials from '../../toolkitMetadata' -import ExpandMoreIcon from '@material-ui/icons/ExpandMore' -import Markdown from '../Markdown' -import { StringParam, useQueryParams, useQueryParam } from 'use-query-params' -import Autocomplete from '@material-ui/lab/Autocomplete' +import React from 'react' +import { makeStyles, Grid, Box } from '@material-ui/core' +import Background from './assets/AIT_bg_title.jpg' +import IconQuery from './assets/AIT_ico_bb_query.svg' +import IconReplicate from './assets/AIT_ico_bb_replicate.svg' +import IconTutorial from './assets/AIT_ico_bb_tutorial.svg' +import IconWork from './assets/AIT_ico_bb_work.svg' const useStyles = makeStyles(theme => ({ root: { - margin: theme.spacing(3), width: '100%', - marginLeft: 'auto', - marginRight: 'auto', - maxWidth: 1024 + maxWidth: '1920px', + backgroundImage: `url(${Background})`, + color: 'white', + height: '700px' }, - section: { - marginTop: theme.spacing(3) + title: { + fontSize: '50px', + margin: 'auto', + textAlign: 'center', + align: 'center', + marginTop: '50px', + width: '450px', + height: '140px', + fontFamily: 'TitilliumBold', + letterSpacing: 0, + wordSpacing: '10px', + lineHeight: '60px', + color: 'white' }, - sectionTitle: { - marginBottom: theme.spacing(1), - marginLeft: theme.spacing(2) + deck: { + fontFamily: 'TitilliumRegular', + letterSpacing: 0, + marginTop: '-45px', + wordSpacing: '5px', + lineHeight: '30px', + color: 'white', + fontSize: '30px', + margin: 'auto', + textAlign: 'center', + align: 'center', + left: '736px', + top: '270px', + width: '500px', + height: '140px' }, - tutorial: { + button: { + backgroundColor: 'white', + fontSize: 20, + fontFamily: 'TitilliumBold', + color: '#2A3C67', + textAlign: 'center', + align: 'center', + borderRadius: '25px', + width: '200px', + height: '70px', + lineHeight: '20px' - }, - tutorialTitle: { - fontWeight: 'bold' - }, - tutorialDetails: { - flexDirection: 'column', - '& *': { - marginTop: theme.spacing(1) - }, - '& :first-child': { - marginTop: -theme.spacing(2) - } }, link: { cursor: 'pointer' @@ -63,234 +81,53 @@ const useStyles = makeStyles(theme => ({ export default function AIToolkitPage() { const classes = useStyles() - const [expanded, setExpanded] = useQueryParam('expanded', StringParam) - const [queryParameters, setQueryParameters] = useQueryParams({ - author: StringParam, keyword: StringParam, method: StringParam, filterString: StringParam - }) - const emptyQuery = { - author: null, - keyword: null, - method: null, - filterString: null - } - - const filter = tutorial => { - const {author, keyword, method} = queryParameters - if (author && tutorial.authors.indexOf(author) === -1) { - return false - } - if (keyword && tutorial.labels.application_keyword.indexOf(keyword) === -1) { - return false - } - if (method && tutorial.labels.data_analytics_method.indexOf(method) === -1) { - return false - } - return true - } - - const {sections, authors, keywords, methods} = useMemo(() => { - const authors = {} - const keywords = {} - const methods = {} - const sectionMap = tutorials.tutorials.reduce((sections, tutorial) => { - tutorial.labels.application_section.forEach(sectionTitle => { - sections[sectionTitle] = sections[sectionTitle] || {title: sectionTitle, tutorials: []} - tutorial.key = tutorial.title.replace(/\W/gm, '_').toLowerCase() - sections[sectionTitle].tutorials.push(tutorial) - tutorial.authors.forEach(i => { authors[i] = i }) - tutorial.labels.application_keyword.forEach(i => { keywords[i] = i }) - tutorial.labels.data_analytics_method.forEach(i => { methods[i] = i }) - }) - return sections - }, {}) - return { - sections: Object.keys(sectionMap).map(key => sectionMap[key]).sort((a, b) => a.title.localeCompare(b.title)), - authors: Object.keys(authors).sort(), - keywords: Object.keys(keywords).sort(), - methods: Object.keys(methods).sort() - } - }, []) - - const Accordion = withStyles({ - root: { - border: '5px solid rgba(127, 239, 239, 1)', - scrollbarGutter: 'false', - marginLeft: '100px', - boxShadow: '0 3px 5px 2px rgba(127, 239, 239, 0.5)', - borderRadius: '10px 10px 10px 10px', - '&:not(:last-child)': { - borderBottom: 0 - }, - '&:before': { - display: 'none' - }, - '&$expanded': { - margin: 'auto' - } - }, - heading: { - fontSize: 35, - flexBasis: '33.33%', - flexShrink: 0 - }, - secondaryHeading: { - fontSize: 10 - }, - expanded: {} - })(MUIAccordion) - - const AccordionSummary = withStyles({ - root: { - flexDirection: 'column' - }, - content: { - marginBottom: 0, - flexGrow: 1 - }, - expandIcon: { - marginRight: '10px', - paddingTop: '10px' - } - })(MUIAccordionSummary) return - - {` - # NOMAD Artificial Intelligence Toolkit - We develop and implement methods that identify correlations and structure in big data - of materials. This will enable scientists and engineers to decide which materials are - useful for specific applications or which new materials should be the focus of future studies. - The following tutorials are designed to get started with the AI Toolkit. - - To log in directly, click [here](https://analytics-toolkit.nomad-coe.eu/hub). - `} + + + Powerful Tools for Materials Science - - {


} - {sections.map(section => ( -
- {/* {section.title} */} -
- {section.tutorials.map(tutorial => { - // - const key = tutorial.key - return setExpanded(expanded === key ? null : key)} - className={classes.tutorial} - > - }> - {tutorial.title} - - - - - {tutorial.authors - .map(name => { - const label = name.split(',').reverse().join(' ') - return setQueryParameters({ - ...emptyQuery, - author: queryParameters.author === name ? null : name - })} - > - {label} - - }).reduce((prev, curr) => [prev, ', ', curr]) - } - - - {tutorial.description} - - - keywords: {tutorial.labels.application_keyword - .map(keyword => ( - setQueryParameters({ - ...emptyQuery, - keyword: queryParameters.keyword === keyword ? null : keyword - })} - > - {keyword} - - )).reduce((prev, curr) => [prev, ', ', curr]) - } - - - method: {tutorial.labels.data_analytics_method - .map(method => ( - setQueryParameters({ - ...emptyQuery, - method: queryParameters.method === method ? null : method - })} - > - {method} - - )).reduce((prev, curr) => [prev, ', ', curr]) - } - - - - - - - - - })} - -
- -
- ))} + + + Find new Patterns and Information in Materials Science Big Data + + + + + + - - option} - style={{ width: '100%', marginBottom: 8 }} - renderInput={params => ( - - )} - value={queryParameters.author} - onChange={(_, value) => setQueryParameters({...emptyQuery, author: value})} - /> - option} - style={{ width: '100%', marginBottom: 8 }} - renderInput={params => ( - - )} - value={queryParameters.keyword} - onChange={(_, value) => setQueryParameters({...emptyQuery, keyword: value})} - /> - ( - - )} - value={queryParameters.method} - onChange={(_, value) => setQueryParameters({...emptyQuery, method: value})} - /> - {/* */} + + + + + + + + + + + + + + } -- GitLab From ed0fe12b0755ab17b75bb2e0f5b87ba1bfa2b819 Mon Sep 17 00:00:00 2001 From: sbailo Date: Wed, 29 Sep 2021 18:58:14 +0200 Subject: [PATCH 06/68] Create tutorials and reproduce pages --- gui/src/components/aitoolkit/ReproducePage.js | 296 ++++++++++++++++++ gui/src/components/aitoolkit/TutorialsPage.js | 296 ++++++++++++++++++ 2 files changed, 592 insertions(+) create mode 100644 gui/src/components/aitoolkit/ReproducePage.js create mode 100644 gui/src/components/aitoolkit/TutorialsPage.js diff --git a/gui/src/components/aitoolkit/ReproducePage.js b/gui/src/components/aitoolkit/ReproducePage.js new file mode 100644 index 000000000..443c0a8df --- /dev/null +++ b/gui/src/components/aitoolkit/ReproducePage.js @@ -0,0 +1,296 @@ +/* + * Copyright The NOMAD Authors. + * + * This file is part of NOMAD. See https://nomad-lab.eu for further info. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and + * limitations under the License. + */ +import React, { useMemo } from 'react' +import { Divider, Typography, AccordionDetails, makeStyles, Link, AccordionActions, Button, Grid, TextField } from '@material-ui/core' +import MUIAccordion from '@material-ui/core/Accordion' +import MUIAccordionSummary from '@material-ui/core/AccordionSummary' +import { withStyles } from '@material-ui/core/styles' +import tutorials from '../../toolkitMetadata' +import ExpandMoreIcon from '@material-ui/icons/ExpandMore' +import Markdown from '../Markdown' +import { StringParam, useQueryParams, useQueryParam } from 'use-query-params' +import Autocomplete from '@material-ui/lab/Autocomplete' + +const useStyles = makeStyles(theme => ({ + root: { + margin: theme.spacing(3), + width: '100%', + marginLeft: 'auto', + marginRight: 'auto', + maxWidth: 1024 + }, + section: { + marginTop: theme.spacing(3) + }, + sectionTitle: { + marginBottom: theme.spacing(1), + marginLeft: theme.spacing(2) + }, + tutorial: { + + }, + tutorialTitle: { + fontWeight: 'bold', + }, + tutorialDetails: { + flexDirection: 'column', + '& *': { + marginTop: theme.spacing(1) + }, + '& :first-child': { + marginTop: -theme.spacing(2) + } + }, + link: { + cursor: 'pointer' + } +})) + +export default function AIToolkitPage() { + const classes = useStyles() + const [expanded, setExpanded] = useQueryParam('expanded', StringParam) + const [queryParameters, setQueryParameters] = useQueryParams({ + author: StringParam, keyword: StringParam, method: StringParam, filterString: StringParam + }) + const emptyQuery = { + author: null, + keyword: null, + method: null, + filterString: null + } + + const filter = tutorial => { + const {author, keyword, method} = queryParameters + if (author && tutorial.authors.indexOf(author) === -1) { + return false + } + if (keyword && tutorial.labels.application_keyword.indexOf(keyword) === -1) { + return false + } + if (method && tutorial.labels.data_analytics_method.indexOf(method) === -1) { + return false + } + return true + } + + const {sections, authors, keywords, methods} = useMemo(() => { + const authors = {} + const keywords = {} + const methods = {} + const sectionMap = tutorials.tutorials.reduce((sections, tutorial) => { + tutorial.labels.application_section.forEach(sectionTitle => { + sections[sectionTitle] = sections[sectionTitle] || {title: sectionTitle, tutorials: []} + tutorial.key = tutorial.title.replace(/\W/gm, '_').toLowerCase() + sections[sectionTitle].tutorials.push(tutorial) + tutorial.authors.forEach(i => { authors[i] = i }) + tutorial.labels.application_keyword.forEach(i => { keywords[i] = i }) + tutorial.labels.data_analytics_method.forEach(i => { methods[i] = i }) + }) + return sections + }, {}) + return { + sections: Object.keys(sectionMap).map(key => sectionMap[key]).sort((a, b) => a.title.localeCompare(b.title)), + authors: Object.keys(authors).sort(), + keywords: Object.keys(keywords).sort(), + methods: Object.keys(methods).sort() + } + }, []) + + const Accordion = withStyles({ + root: { + border: '5px solid rgba(127, 239, 239, 1)', + scrollbarGutter: 'false', + marginLeft: '100px', + boxShadow: '0 3px 5px 2px rgba(127, 239, 239, 0.5)', + borderRadius: '10px 10px 10px 10px', + '&:not(:last-child)': { + borderBottom: 0 + }, + '&:before': { + display: 'none' + }, + '&$expanded': { + margin: 'auto' + } + }, + heading: { + fontSize: 35, + flexBasis: '33.33%', + flexShrink: 0 + }, + secondaryHeading: { + fontSize: 10 + }, + expanded: {} + })(MUIAccordion) + + const AccordionSummary = withStyles({ + root: { + flexDirection: 'column' + }, + content: { + marginBottom: 0, + flexGrow: 1 + }, + expandIcon: { + marginRight: '10px', + paddingTop: '10px' + } + })(MUIAccordionSummary) + + return + + {` + # Reproduce published results + + We develop and implement methods that identify correlations and structure in big data + of materials. This will enable scientists and engineers to decide which materials are + useful for specific applications or which new materials should be the focus of future studies. + The following tutorials are designed to get started with the AI Toolkit. + + To log in directly, click [here](https://analytics-toolkit.nomad-coe.eu/hub). + `} + + + {
} + {sections.map(section => ( +
+ {/* {section.title} */} +
+ {section.tutorials.map(tutorial => { + // + const key = tutorial.key + return setExpanded(expanded === key ? null : key)} + className={classes.tutorial} + > + }> + {tutorial.title} + + + + + {tutorial.authors + .map(name => { + const label = name.split(',').reverse().join(' ') + return setQueryParameters({ + ...emptyQuery, + author: queryParameters.author === name ? null : name + })} + > + {label} + + }).reduce((prev, curr) => [prev, ', ', curr]) + } + + + {tutorial.description} + + + keywords: {tutorial.labels.application_keyword + .map(keyword => ( + setQueryParameters({ + ...emptyQuery, + keyword: queryParameters.keyword === keyword ? null : keyword + })} + > + {keyword} + + )).reduce((prev, curr) => [prev, ', ', curr]) + } + + + method: {tutorial.labels.data_analytics_method + .map(method => ( + setQueryParameters({ + ...emptyQuery, + method: queryParameters.method === method ? null : method + })} + > + {method} + + )).reduce((prev, curr) => [prev, ', ', curr]) + } + + + + + + + + + })} + +
+ +
+ ))} +
+ + option} + style={{ width: '100%', marginBottom: 8 }} + renderInput={params => ( + + )} + value={queryParameters.author} + onChange={(_, value) => setQueryParameters({...emptyQuery, author: value})} + /> + option} + style={{ width: '100%', marginBottom: 8 }} + renderInput={params => ( + + )} + value={queryParameters.keyword} + onChange={(_, value) => setQueryParameters({...emptyQuery, keyword: value})} + /> + ( + + )} + value={queryParameters.method} + onChange={(_, value) => setQueryParameters({...emptyQuery, method: value})} + /> + {/* */} + +
+} diff --git a/gui/src/components/aitoolkit/TutorialsPage.js b/gui/src/components/aitoolkit/TutorialsPage.js new file mode 100644 index 000000000..3c3686426 --- /dev/null +++ b/gui/src/components/aitoolkit/TutorialsPage.js @@ -0,0 +1,296 @@ +/* + * Copyright The NOMAD Authors. + * + * This file is part of NOMAD. See https://nomad-lab.eu for further info. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and + * limitations under the License. + */ +import React, { useMemo } from 'react' +import { Divider, Typography, AccordionDetails, makeStyles, Link, AccordionActions, Button, Grid, TextField } from '@material-ui/core' +import MUIAccordion from '@material-ui/core/Accordion' +import MUIAccordionSummary from '@material-ui/core/AccordionSummary' +import { withStyles } from '@material-ui/core/styles' +import tutorials from '../../toolkitMetadata' +import ExpandMoreIcon from '@material-ui/icons/ExpandMore' +import Markdown from '../Markdown' +import { StringParam, useQueryParams, useQueryParam } from 'use-query-params' +import Autocomplete from '@material-ui/lab/Autocomplete' + +const useStyles = makeStyles(theme => ({ + root: { + margin: theme.spacing(3), + width: '100%', + marginLeft: 'auto', + marginRight: 'auto', + maxWidth: 1024 + }, + section: { + marginTop: theme.spacing(3) + }, + sectionTitle: { + marginBottom: theme.spacing(1), + marginLeft: theme.spacing(2) + }, + tutorial: { + + }, + tutorialTitle: { + fontWeight: 'bold', + }, + tutorialDetails: { + flexDirection: 'column', + '& *': { + marginTop: theme.spacing(1) + }, + '& :first-child': { + marginTop: -theme.spacing(2) + } + }, + link: { + cursor: 'pointer' + } +})) + +export default function AIToolkitPage() { + const classes = useStyles() + const [expanded, setExpanded] = useQueryParam('expanded', StringParam) + const [queryParameters, setQueryParameters] = useQueryParams({ + author: StringParam, keyword: StringParam, method: StringParam, filterString: StringParam + }) + const emptyQuery = { + author: null, + keyword: null, + method: null, + filterString: null + } + + const filter = tutorial => { + const {author, keyword, method} = queryParameters + if (author && tutorial.authors.indexOf(author) === -1) { + return false + } + if (keyword && tutorial.labels.application_keyword.indexOf(keyword) === -1) { + return false + } + if (method && tutorial.labels.data_analytics_method.indexOf(method) === -1) { + return false + } + return true + } + + const {sections, authors, keywords, methods} = useMemo(() => { + const authors = {} + const keywords = {} + const methods = {} + const sectionMap = tutorials.tutorials.reduce((sections, tutorial) => { + tutorial.labels.application_section.forEach(sectionTitle => { + sections[sectionTitle] = sections[sectionTitle] || {title: sectionTitle, tutorials: []} + tutorial.key = tutorial.title.replace(/\W/gm, '_').toLowerCase() + sections[sectionTitle].tutorials.push(tutorial) + tutorial.authors.forEach(i => { authors[i] = i }) + tutorial.labels.application_keyword.forEach(i => { keywords[i] = i }) + tutorial.labels.data_analytics_method.forEach(i => { methods[i] = i }) + }) + return sections + }, {}) + return { + sections: Object.keys(sectionMap).map(key => sectionMap[key]).sort((a, b) => a.title.localeCompare(b.title)), + authors: Object.keys(authors).sort(), + keywords: Object.keys(keywords).sort(), + methods: Object.keys(methods).sort() + } + }, []) + + const Accordion = withStyles({ + root: { + border: '5px solid rgba(127, 239, 239, 1)', + scrollbarGutter: 'false', + marginLeft: '100px', + boxShadow: '0 3px 5px 2px rgba(127, 239, 239, 0.5)', + borderRadius: '10px 10px 10px 10px', + '&:not(:last-child)': { + borderBottom: 0 + }, + '&:before': { + display: 'none' + }, + '&$expanded': { + margin: 'auto' + } + }, + heading: { + fontSize: 35, + flexBasis: '33.33%', + flexShrink: 0 + }, + secondaryHeading: { + fontSize: 10 + }, + expanded: {} + })(MUIAccordion) + + const AccordionSummary = withStyles({ + root: { + flexDirection: 'column' + }, + content: { + marginBottom: 0, + flexGrow: 1 + }, + expandIcon: { + marginRight: '10px', + paddingTop: '10px' + } + })(MUIAccordionSummary) + + return + + {` + # Learn from tutorials + + We develop and implement methods that identify correlations and structure in big data + of materials. This will enable scientists and engineers to decide which materials are + useful for specific applications or which new materials should be the focus of future studies. + The following tutorials are designed to get started with the AI Toolkit. + + To log in directly, click [here](https://analytics-toolkit.nomad-coe.eu/hub). + `} + + + {
} + {sections.map(section => ( +
+ {/* {section.title} */} +
+ {section.tutorials.map(tutorial => { + // + const key = tutorial.key + return setExpanded(expanded === key ? null : key)} + className={classes.tutorial} + > + }> + {tutorial.title} + + + + + {tutorial.authors + .map(name => { + const label = name.split(',').reverse().join(' ') + return setQueryParameters({ + ...emptyQuery, + author: queryParameters.author === name ? null : name + })} + > + {label} + + }).reduce((prev, curr) => [prev, ', ', curr]) + } + + + {tutorial.description} + + + keywords: {tutorial.labels.application_keyword + .map(keyword => ( + setQueryParameters({ + ...emptyQuery, + keyword: queryParameters.keyword === keyword ? null : keyword + })} + > + {keyword} + + )).reduce((prev, curr) => [prev, ', ', curr]) + } + + + method: {tutorial.labels.data_analytics_method + .map(method => ( + setQueryParameters({ + ...emptyQuery, + method: queryParameters.method === method ? null : method + })} + > + {method} + + )).reduce((prev, curr) => [prev, ', ', curr]) + } + + + + + + + + + })} + +
+ +
+ ))} +
+ + option} + style={{ width: '100%', marginBottom: 8 }} + renderInput={params => ( + + )} + value={queryParameters.author} + onChange={(_, value) => setQueryParameters({...emptyQuery, author: value})} + /> + option} + style={{ width: '100%', marginBottom: 8 }} + renderInput={params => ( + + )} + value={queryParameters.keyword} + onChange={(_, value) => setQueryParameters({...emptyQuery, keyword: value})} + /> + ( + + )} + value={queryParameters.method} + onChange={(_, value) => setQueryParameters({...emptyQuery, method: value})} + /> + {/* */} + +
+} -- GitLab From b788f2c0198172f153366ed789e5f22bcd3542e6 Mon Sep 17 00:00:00 2001 From: sbailo Date: Wed, 29 Sep 2021 18:58:41 +0200 Subject: [PATCH 07/68] Add routes to tutorials and reproduce pages --- gui/src/components/nav/Routes.js | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/gui/src/components/nav/Routes.js b/gui/src/components/nav/Routes.js index b9136d16c..8f5260ea3 100644 --- a/gui/src/components/nav/Routes.js +++ b/gui/src/components/nav/Routes.js @@ -21,6 +21,8 @@ import { Route, useLocation } from 'react-router-dom' import About from '../About' import APIs from '../APIs' import AIToolkitPage from '../aitoolkit/AIToolkitPage' +import TutorialsPage from '../aitoolkit/TutorialsPage' +import ReproducePage from '../aitoolkit/ReproducePage' import { MetainfoPage, help as metainfoHelp } from '../archive/MetainfoBrowser' import ResolveDOI from '../dataset/ResolveDOI' import DatasetPage from '../DatasetPage' @@ -162,6 +164,18 @@ const routeSpecs = [ navPath: 'analyze/aitoolkit', component: AIToolkitPage }, + { + path: '/tutorials', + title: 'Artificial Intelligence Toolkit', + navPath: 'analyze/tutorials', + component: TutorialsPage + }, + { + path: '/reproduce', + title: 'Artificial Intelligence Toolkit', + navPath: 'analyze/reproduce', + component: ReproducePage + }, { exact: true, path: '/apis', -- GitLab From bbc121bc65c72311c2792ff97fb07778b3c486ab Mon Sep 17 00:00:00 2001 From: sbailo Date: Mon, 4 Oct 2021 21:39:41 +0200 Subject: [PATCH 08/68] Tutorials page filters only 'tutorials' among notebooks --- gui/src/components/aitoolkit/TutorialsPage.js | 203 ++++++++---------- 1 file changed, 95 insertions(+), 108 deletions(-) diff --git a/gui/src/components/aitoolkit/TutorialsPage.js b/gui/src/components/aitoolkit/TutorialsPage.js index 3c3686426..ea84a831b 100644 --- a/gui/src/components/aitoolkit/TutorialsPage.js +++ b/gui/src/components/aitoolkit/TutorialsPage.js @@ -45,7 +45,7 @@ const useStyles = makeStyles(theme => ({ }, tutorialTitle: { - fontWeight: 'bold', + fontWeight: 'bold' }, tutorialDetails: { flexDirection: 'column', @@ -88,28 +88,25 @@ export default function AIToolkitPage() { return true } - const {sections, authors, keywords, methods} = useMemo(() => { + const tutorials_list = tutorials.tutorials.filter(tutorial => tutorial.labels.application_section[0] === 'Tutorials for artificial-intelligence methods') + + const {authors, keywords, methods} = useMemo(() => { const authors = {} const keywords = {} const methods = {} - const sectionMap = tutorials.tutorials.reduce((sections, tutorial) => { - tutorial.labels.application_section.forEach(sectionTitle => { - sections[sectionTitle] = sections[sectionTitle] || {title: sectionTitle, tutorials: []} - tutorial.key = tutorial.title.replace(/\W/gm, '_').toLowerCase() - sections[sectionTitle].tutorials.push(tutorial) - tutorial.authors.forEach(i => { authors[i] = i }) - tutorial.labels.application_keyword.forEach(i => { keywords[i] = i }) - tutorial.labels.data_analytics_method.forEach(i => { methods[i] = i }) - }) - return sections - }, {}) + tutorials_list.forEach(tutorial => { + tutorial.key = tutorial.title.replace(/\W/gm, '_').toLowerCase() + tutorial.authors.forEach(i => { authors[i] = i }) + tutorial.labels.application_keyword.forEach(i => { keywords[i] = i }) + tutorial.labels.data_analytics_method.forEach(i => { methods[i] = i }) + } + ) return { - sections: Object.keys(sectionMap).map(key => sectionMap[key]).sort((a, b) => a.title.localeCompare(b.title)), authors: Object.keys(authors).sort(), keywords: Object.keys(keywords).sort(), methods: Object.keys(methods).sort() } - }, []) + }, [tutorials_list]) const Accordion = withStyles({ root: { @@ -156,104 +153,94 @@ export default function AIToolkitPage() { return {` - # Learn from tutorials + # Learn from tutorials - We develop and implement methods that identify correlations and structure in big data - of materials. This will enable scientists and engineers to decide which materials are - useful for specific applications or which new materials should be the focus of future studies. - The following tutorials are designed to get started with the AI Toolkit. + We develop and implement methods that identify correlations and structure in big data + of materials. This will enable scientists and engineers to decide which materials are + useful for specific applications or which new materials should be the focus of future studies. + The following tutorials are designed to get started with the AI Toolkit. - To log in directly, click [here](https://analytics-toolkit.nomad-coe.eu/hub). - `} + To log in directly, click [here](https://analytics-toolkit.nomad-coe.eu/hub). + `} - {
} - {sections.map(section => ( -
- {/* {section.title} */} -
- {section.tutorials.map(tutorial => { - // - const key = tutorial.key - return setExpanded(expanded === key ? null : key)} - className={classes.tutorial} - > - }> - {tutorial.title} - - - - - {tutorial.authors - .map(name => { - const label = name.split(',').reverse().join(' ') - return setQueryParameters({ - ...emptyQuery, - author: queryParameters.author === name ? null : name - })} - > - {label} - - }).reduce((prev, curr) => [prev, ', ', curr]) - } - - - {tutorial.description} - - - keywords: {tutorial.labels.application_keyword - .map(keyword => ( - setQueryParameters({ - ...emptyQuery, - keyword: queryParameters.keyword === keyword ? null : keyword - })} - > - {keyword} - - )).reduce((prev, curr) => [prev, ', ', curr]) - } - - - method: {tutorial.labels.data_analytics_method - .map(method => ( - setQueryParameters({ - ...emptyQuery, - method: queryParameters.method === method ? null : method - })} - > - {method} - - )).reduce((prev, curr) => [prev, ', ', curr]) - } - - - - - + - - - - })} - -
- + + + +
))}
@@ -290,7 +277,7 @@ export default function AIToolkitPage() { value={queryParameters.method} onChange={(_, value) => setQueryParameters({...emptyQuery, method: value})} /> - {/* */} +
} -- GitLab From ec02447b136a1f17f0d1c360e70a62f57294bb60 Mon Sep 17 00:00:00 2001 From: sbailo Date: Tue, 5 Oct 2021 11:20:54 +0200 Subject: [PATCH 09/68] Fix linting --- gui/src/components/aitoolkit/ReproducePage.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gui/src/components/aitoolkit/ReproducePage.js b/gui/src/components/aitoolkit/ReproducePage.js index 443c0a8df..f51dba107 100644 --- a/gui/src/components/aitoolkit/ReproducePage.js +++ b/gui/src/components/aitoolkit/ReproducePage.js @@ -45,7 +45,7 @@ const useStyles = makeStyles(theme => ({ }, tutorialTitle: { - fontWeight: 'bold', + fontWeight: 'bold' }, tutorialDetails: { flexDirection: 'column', -- GitLab From facc1cadaa4be9a16633b7773394e6ae9afe34fc Mon Sep 17 00:00:00 2001 From: sbailo Date: Tue, 5 Oct 2021 17:24:24 +0200 Subject: [PATCH 10/68] Add icon Use nested grid containers --- gui/src/components/aitoolkit/TutorialsPage.js | 279 ++++++++++-------- 1 file changed, 150 insertions(+), 129 deletions(-) diff --git a/gui/src/components/aitoolkit/TutorialsPage.js b/gui/src/components/aitoolkit/TutorialsPage.js index ea84a831b..9dee64123 100644 --- a/gui/src/components/aitoolkit/TutorialsPage.js +++ b/gui/src/components/aitoolkit/TutorialsPage.js @@ -16,7 +16,7 @@ * limitations under the License. */ import React, { useMemo } from 'react' -import { Divider, Typography, AccordionDetails, makeStyles, Link, AccordionActions, Button, Grid, TextField } from '@material-ui/core' +import { Box, Divider, Typography, AccordionDetails, makeStyles, Link, AccordionActions, Button, Grid, TextField } from '@material-ui/core' import MUIAccordion from '@material-ui/core/Accordion' import MUIAccordionSummary from '@material-ui/core/AccordionSummary' import { withStyles } from '@material-ui/core/styles' @@ -25,13 +25,16 @@ import ExpandMoreIcon from '@material-ui/icons/ExpandMore' import Markdown from '../Markdown' import { StringParam, useQueryParams, useQueryParam } from 'use-query-params' import Autocomplete from '@material-ui/lab/Autocomplete' +import IconTutorial from './assets/AIT_ico_bb_tutorial.svg' const useStyles = makeStyles(theme => ({ root: { margin: theme.spacing(3), width: '100%', - marginLeft: 'auto', - marginRight: 'auto', + // marginLeft: 'auto', + // marginRight: 'auto', + marginLeft: '100px', + marginRight: '100px', maxWidth: 1024 }, section: { @@ -41,8 +44,19 @@ const useStyles = makeStyles(theme => ({ marginBottom: theme.spacing(1), marginLeft: theme.spacing(2) }, - tutorial: { - + title: { + fontWeight: 'bold', + color: '#2A3C67', + fontSize: 30 + }, + deck: { + color: '#2A3C67', + fontSize: 15 + }, + icon: { + // backgroundColor: 'green', + height: '400px', + marginTop: '-50px' }, tutorialTitle: { fontWeight: 'bold' @@ -151,133 +165,140 @@ export default function AIToolkitPage() { })(MUIAccordionSummary) return - - {` - # Learn from tutorials - - We develop and implement methods that identify correlations and structure in big data - of materials. This will enable scientists and engineers to decide which materials are - useful for specific applications or which new materials should be the focus of future studies. - The following tutorials are designed to get started with the AI Toolkit. - - To log in directly, click [here](https://analytics-toolkit.nomad-coe.eu/hub). - `} + + + + { + 'Learn from tutorials' + } + + + { + 'We develop and implement methods that identify correlations and structure in big data of materials. This will enable scientists and engineers to decide which materials are useful for specific applications or which new materials should be the focus of future studies. The following tutorials are designed to get started with the AI Toolkit.' + } + + + + + - - {tutorials_list.map(tutorial => ( -
- setExpanded(expanded === tutorial.key ? null : tutorial.key)} - className={classes.tutorial} - > - }> - {tutorial.title} - - - - - {tutorial.authors - .map(name => { - const label = name.split(',').reverse().join(' ') - return setQueryParameters({ - ...emptyQuery, - author: queryParameters.author === name ? null : name - })} - > - {label} - - }).reduce((prev, curr) => [prev, ', ', curr]) - } - - - {tutorial.description} - - - keywords: {tutorial.labels.application_keyword - .map(keyword => ( - setQueryParameters({ - ...emptyQuery, - keyword: queryParameters.keyword === keyword ? null : keyword - })} - > - {keyword} - - )).reduce((prev, curr) => [prev, ', ', curr]) - } - - - method: {tutorial.labels.data_analytics_method - .map(method => ( - setQueryParameters({ - ...emptyQuery, - method: queryParameters.method === method ? null : method - })} - > - {method} - - )).reduce((prev, curr) => [prev, ', ', curr]) - } - - - - - + - - - -
- ))} -
- - option} - style={{ width: '100%', marginBottom: 8 }} - renderInput={params => ( - - )} - value={queryParameters.author} - onChange={(_, value) => setQueryParameters({...emptyQuery, author: value})} - /> - option} - style={{ width: '100%', marginBottom: 8 }} - renderInput={params => ( - - )} - value={queryParameters.keyword} - onChange={(_, value) => setQueryParameters({...emptyQuery, keyword: value})} - /> - ( - - )} - value={queryParameters.method} - onChange={(_, value) => setQueryParameters({...emptyQuery, method: value})} - /> - + + + + + + ))} + + + option} + style={{ width: '100%', marginBottom: 8 }} + renderInput={params => ( + + )} + value={queryParameters.author} + onChange={(_, value) => setQueryParameters({...emptyQuery, author: value})} + /> + option} + style={{ width: '100%', marginBottom: 8 }} + renderInput={params => ( + + )} + value={queryParameters.keyword} + onChange={(_, value) => setQueryParameters({...emptyQuery, keyword: value})} + /> + ( + + )} + value={queryParameters.method} + onChange={(_, value) => setQueryParameters({...emptyQuery, method: value})} + /> + +
} -- GitLab From e961c3096f1b1c2afa4c9964cf03272f84013b3e Mon Sep 17 00:00:00 2001 From: sbailo Date: Wed, 6 Oct 2021 13:44:58 +0200 Subject: [PATCH 11/68] Customize autocomplete --- gui/src/components/aitoolkit/TutorialsPage.js | 187 ++++++++++-------- 1 file changed, 107 insertions(+), 80 deletions(-) diff --git a/gui/src/components/aitoolkit/TutorialsPage.js b/gui/src/components/aitoolkit/TutorialsPage.js index 9dee64123..cd1e6e433 100644 --- a/gui/src/components/aitoolkit/TutorialsPage.js +++ b/gui/src/components/aitoolkit/TutorialsPage.js @@ -51,12 +51,26 @@ const useStyles = makeStyles(theme => ({ }, deck: { color: '#2A3C67', - fontSize: 15 + fontSize: 15, + marginTop: '20px' }, icon: { - // backgroundColor: 'green', height: '400px', - marginTop: '-50px' + marginTop: '-20px' + }, + filter: { + fontWeight: 'bold', + color: '#2A3C67', + fontSize: 13, + marginTop: '-100px' + }, + autocomplete: { + height: 'auto', + color: '#2A3C67', + border: '3px solid rgba(127, 239, 239, 1)', + borderRadius: '10px 10px 10px 10px', + marginTop: '-70px' + }, tutorialTitle: { fontWeight: 'bold' @@ -75,6 +89,47 @@ const useStyles = makeStyles(theme => ({ } })) +const Accordion = withStyles({ + root: { + borderTop: '5px solid rgba(127, 239, 239, 1)', + scrollbarGutter: 'false', + boxShadow: '0 3px 5px 2px rgba(127, 239, 239, 0.5)', + borderRadius: '10px 10px 10px 10px', + '&:not(:last-child)': { + borderBottom: 0 + }, + '&:before': { + display: 'none' + }, + '&$expanded': { + margin: 'auto' + } + }, + heading: { + fontSize: 35, + flexBasis: '33.33%', + flexShrink: 0 + }, + secondaryHeading: { + fontSize: 10 + }, + expanded: {} +})(MUIAccordion) + +const AccordionSummary = withStyles({ + root: { + flexDirection: 'column' + }, + content: { + marginBottom: 0, + flexGrow: 1 + }, + expandIcon: { + marginRight: '10px', + paddingTop: '10px' + } +})(MUIAccordionSummary) + export default function AIToolkitPage() { const classes = useStyles() const [expanded, setExpanded] = useQueryParam('expanded', StringParam) @@ -122,48 +177,6 @@ export default function AIToolkitPage() { } }, [tutorials_list]) - const Accordion = withStyles({ - root: { - border: '5px solid rgba(127, 239, 239, 1)', - scrollbarGutter: 'false', - marginLeft: '100px', - boxShadow: '0 3px 5px 2px rgba(127, 239, 239, 0.5)', - borderRadius: '10px 10px 10px 10px', - '&:not(:last-child)': { - borderBottom: 0 - }, - '&:before': { - display: 'none' - }, - '&$expanded': { - margin: 'auto' - } - }, - heading: { - fontSize: 35, - flexBasis: '33.33%', - flexShrink: 0 - }, - secondaryHeading: { - fontSize: 10 - }, - expanded: {} - })(MUIAccordion) - - const AccordionSummary = withStyles({ - root: { - flexDirection: 'column' - }, - content: { - marginBottom: 0, - flexGrow: 1 - }, - expandIcon: { - marginRight: '10px', - paddingTop: '10px' - } - })(MUIAccordionSummary) - return @@ -182,6 +195,55 @@ export default function AIToolkitPage() { + + + + { + 'Filter Tutorials' + } + + + + option} + renderInput={params => ( + + )} + value={queryParameters.author} + onChange={(_, value) => setQueryParameters({...emptyQuery, author: value})} + /> + + + option} + renderInput={params => ( + + )} + value={queryParameters.keyword} + onChange={(_, value) => setQueryParameters({...emptyQuery, keyword: value})} + /> + + + ( + + )} + value={queryParameters.method} + onChange={(_, value) => setQueryParameters({...emptyQuery, method: value})} + /> + + + {tutorials_list.map(tutorial => ( @@ -264,41 +326,6 @@ export default function AIToolkitPage() { ))} - - option} - style={{ width: '100%', marginBottom: 8 }} - renderInput={params => ( - - )} - value={queryParameters.author} - onChange={(_, value) => setQueryParameters({...emptyQuery, author: value})} - /> - option} - style={{ width: '100%', marginBottom: 8 }} - renderInput={params => ( - - )} - value={queryParameters.keyword} - onChange={(_, value) => setQueryParameters({...emptyQuery, keyword: value})} - /> - ( - - )} - value={queryParameters.method} - onChange={(_, value) => setQueryParameters({...emptyQuery, method: value})} - /> - - } -- GitLab From 96f033ef8a2224823573adc4917ce114453af960 Mon Sep 17 00:00:00 2001 From: sbailo Date: Wed, 6 Oct 2021 14:58:37 +0200 Subject: [PATCH 12/68] Add icons to accordions buttons --- gui/src/components/aitoolkit/TutorialsPage.js | 16 +++++++++------- .../assets/AIT_ico_bd_link_external_big.svg | 1 + .../aitoolkit/assets/AIT_ico_bd_youtube.svg | 1 + 3 files changed, 11 insertions(+), 7 deletions(-) create mode 100644 gui/src/components/aitoolkit/assets/AIT_ico_bd_link_external_big.svg create mode 100644 gui/src/components/aitoolkit/assets/AIT_ico_bd_youtube.svg diff --git a/gui/src/components/aitoolkit/TutorialsPage.js b/gui/src/components/aitoolkit/TutorialsPage.js index cd1e6e433..90f8df067 100644 --- a/gui/src/components/aitoolkit/TutorialsPage.js +++ b/gui/src/components/aitoolkit/TutorialsPage.js @@ -25,7 +25,9 @@ import ExpandMoreIcon from '@material-ui/icons/ExpandMore' import Markdown from '../Markdown' import { StringParam, useQueryParams, useQueryParam } from 'use-query-params' import Autocomplete from '@material-ui/lab/Autocomplete' -import IconTutorial from './assets/AIT_ico_bb_tutorial.svg' +import TutorialsIcon from './assets/AIT_ico_bb_tutorial.svg' +import AccessIcon from './assets/AIT_ico_bd_link_external_big.svg' +import WatchIcon from './assets/AIT_ico_bd_youtube.svg' const useStyles = makeStyles(theme => ({ root: { @@ -61,7 +63,7 @@ const useStyles = makeStyles(theme => ({ filter: { fontWeight: 'bold', color: '#2A3C67', - fontSize: 13, + fontSize: 15, marginTop: '-100px' }, autocomplete: { @@ -192,7 +194,7 @@ export default function AIToolkitPage() {
- +
@@ -314,11 +316,11 @@ export default function AIToolkitPage() { - - diff --git a/gui/src/components/aitoolkit/assets/AIT_ico_bd_link_external_big.svg b/gui/src/components/aitoolkit/assets/AIT_ico_bd_link_external_big.svg new file mode 100644 index 000000000..b2d331e82 --- /dev/null +++ b/gui/src/components/aitoolkit/assets/AIT_ico_bd_link_external_big.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/gui/src/components/aitoolkit/assets/AIT_ico_bd_youtube.svg b/gui/src/components/aitoolkit/assets/AIT_ico_bd_youtube.svg new file mode 100644 index 000000000..60df30297 --- /dev/null +++ b/gui/src/components/aitoolkit/assets/AIT_ico_bd_youtube.svg @@ -0,0 +1 @@ + \ No newline at end of file -- GitLab From 5f7c96ae4ade6393b5beb99ed0489e7f0f26d350 Mon Sep 17 00:00:00 2001 From: sbailo Date: Wed, 6 Oct 2021 16:58:55 +0200 Subject: [PATCH 13/68] Add tutorial icon --- gui/src/components/aitoolkit/assets/AIT_ico_bp_tutorial.svg | 1 + 1 file changed, 1 insertion(+) create mode 100644 gui/src/components/aitoolkit/assets/AIT_ico_bp_tutorial.svg diff --git a/gui/src/components/aitoolkit/assets/AIT_ico_bp_tutorial.svg b/gui/src/components/aitoolkit/assets/AIT_ico_bp_tutorial.svg new file mode 100644 index 000000000..205051226 --- /dev/null +++ b/gui/src/components/aitoolkit/assets/AIT_ico_bp_tutorial.svg @@ -0,0 +1 @@ + \ No newline at end of file -- GitLab From 4ff63ee3c87af03f7ce523cce813d9401bd5b3c0 Mon Sep 17 00:00:00 2001 From: sbailo Date: Wed, 6 Oct 2021 17:42:30 +0200 Subject: [PATCH 14/68] Authors list is in Accordion summary --- gui/src/components/aitoolkit/TutorialsPage.js | 76 ++++++++++++------- 1 file changed, 48 insertions(+), 28 deletions(-) diff --git a/gui/src/components/aitoolkit/TutorialsPage.js b/gui/src/components/aitoolkit/TutorialsPage.js index 90f8df067..3fbec50fa 100644 --- a/gui/src/components/aitoolkit/TutorialsPage.js +++ b/gui/src/components/aitoolkit/TutorialsPage.js @@ -25,7 +25,7 @@ import ExpandMoreIcon from '@material-ui/icons/ExpandMore' import Markdown from '../Markdown' import { StringParam, useQueryParams, useQueryParam } from 'use-query-params' import Autocomplete from '@material-ui/lab/Autocomplete' -import TutorialsIcon from './assets/AIT_ico_bb_tutorial.svg' +import TutorialsIcon from './assets/AIT_ico_bp_tutorial.svg' import AccessIcon from './assets/AIT_ico_bd_link_external_big.svg' import WatchIcon from './assets/AIT_ico_bd_youtube.svg' @@ -75,7 +75,17 @@ const useStyles = makeStyles(theme => ({ }, tutorialTitle: { - fontWeight: 'bold' + fontWeight: 'bold', + fontSize: 25, + lineHeight: '30px', + color: '#2A3C67' + }, + tutorialAuthors: { + color: '#2A3C67', + fontWeight: 'bold', + fontSize: 15, + lineHeight: '20px', + align: 'right' }, tutorialDetails: { flexDirection: 'column', @@ -87,18 +97,17 @@ const useStyles = makeStyles(theme => ({ } }, link: { - cursor: 'pointer' + cursor: 'pointer', + fontWeight: 'normal' + } })) const Accordion = withStyles({ root: { - borderTop: '5px solid rgba(127, 239, 239, 1)', + borderTop: '10px solid rgba(127, 239, 239, 1)', scrollbarGutter: 'false', - boxShadow: '0 3px 5px 2px rgba(127, 239, 239, 0.5)', - borderRadius: '10px 10px 10px 10px', '&:not(:last-child)': { - borderBottom: 0 }, '&:before': { display: 'none' @@ -247,38 +256,48 @@ export default function AIToolkitPage() { - + {tutorials_list.map(tutorial => ( -
+
setExpanded(expanded === tutorial.key ? null : tutorial.key)} className={classes.tutorial} + elevation={0} > }> - {tutorial.title} - + + + + {tutorial.title} + + + + + {'Authors: '} + {tutorial.authors + .map(name => { + const label = name.split(',').reverse().join(' ') + return setQueryParameters({ + ...emptyQuery, + author: queryParameters.author === name ? null : name + })} + > + {label} + + }).reduce((prev, curr) => [prev, ', ', curr]) + } + + + + - - {tutorial.authors - .map(name => { - const label = name.split(',').reverse().join(' ') - return setQueryParameters({ - ...emptyQuery, - author: queryParameters.author === name ? null : name - })} - > - {label} - - }).reduce((prev, curr) => [prev, ', ', curr]) - } - {tutorial.description} @@ -315,6 +334,7 @@ export default function AIToolkitPage() { } + - + + + + -- GitLab From 644f4e9f5ed198238d39391f35c69d1504603011 Mon Sep 17 00:00:00 2001 From: sbailo Date: Thu, 7 Oct 2021 15:16:58 +0200 Subject: [PATCH 16/68] Fix grids size in landing page --- gui/src/components/aitoolkit/AIToolkitPage.js | 86 ++++++++++--------- 1 file changed, 46 insertions(+), 40 deletions(-) diff --git a/gui/src/components/aitoolkit/AIToolkitPage.js b/gui/src/components/aitoolkit/AIToolkitPage.js index 807c23855..59f8e49c5 100644 --- a/gui/src/components/aitoolkit/AIToolkitPage.js +++ b/gui/src/components/aitoolkit/AIToolkitPage.js @@ -26,17 +26,22 @@ import IconWork from './assets/AIT_ico_bb_work.svg' const useStyles = makeStyles(theme => ({ root: { width: '100%', - maxWidth: '1920px', + maxWidth: 'auto', backgroundImage: `url(${Background})`, color: 'white', - height: '700px' + height: '1000px' + }, + boxIcons: { + width: '1000px', + margin: 'auto', + marginTop: '-200px' }, title: { fontSize: '50px', margin: 'auto', textAlign: 'center', align: 'center', - marginTop: '50px', + marginTop: '200px', width: '450px', height: '140px', fontFamily: 'TitilliumBold', @@ -48,7 +53,7 @@ const useStyles = makeStyles(theme => ({ deck: { fontFamily: 'TitilliumRegular', letterSpacing: 0, - marginTop: '-45px', + marginTop: '-200px', wordSpacing: '5px', lineHeight: '30px', color: 'white', @@ -92,42 +97,43 @@ export default function AIToolkitPage() { Find new Patterns and Information in Materials Science Big Data - - - - - - - + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - } -- GitLab From 0ef2572c147ab8d62a078507a0a0540bcd51bf8d Mon Sep 17 00:00:00 2001 From: sbailo Date: Fri, 8 Oct 2021 16:41:03 +0200 Subject: [PATCH 17/68] Add resources icons --- gui/src/components/aitoolkit/TutorialsPage.js | 175 ++++++++++++------ .../aitoolkit/assets/AIT_ico_bd_link_doi.svg | 7 + .../aitoolkit/assets/AIT_ico_bd_link_pdf.svg | 9 + 3 files changed, 133 insertions(+), 58 deletions(-) create mode 100644 gui/src/components/aitoolkit/assets/AIT_ico_bd_link_doi.svg create mode 100644 gui/src/components/aitoolkit/assets/AIT_ico_bd_link_pdf.svg diff --git a/gui/src/components/aitoolkit/TutorialsPage.js b/gui/src/components/aitoolkit/TutorialsPage.js index bd4c55dd9..c4c6d3a53 100644 --- a/gui/src/components/aitoolkit/TutorialsPage.js +++ b/gui/src/components/aitoolkit/TutorialsPage.js @@ -30,8 +30,11 @@ import Autocomplete from '@material-ui/lab/Autocomplete' import TutorialsIcon from './assets/AIT_ico_bp_tutorial.svg' import AccessIcon from './assets/AIT_ico_bd_link_external_big.svg' import WatchIcon from './assets/AIT_ico_bd_youtube.svg' +import PdfIcon from './assets/AIT_ico_bd_link_pdf.svg' +import DoiIcon from './assets/AIT_ico_bd_link_doi.svg' const useStyles = makeStyles(theme => ({ + root: { margin: theme.spacing(3), width: '100%', @@ -50,24 +53,31 @@ const useStyles = makeStyles(theme => ({ title: { fontWeight: 'bold', color: '#2A3C67', - fontSize: 30 + fontSize: 30, + marginLeft: '-10px', + fontFamily: 'TitilliumBold' + }, deck: { color: '#2A3C67', fontSize: 15, - marginTop: '20px' + marginTop: '20px', + lineHeight: '24px', + marginLeft: '-10px', + fontFamily: 'TitilliumRegular' }, icon: { height: '350px', marginTop: '-20px', - marginLeft: '200px' + marginLeft: '100px' }, filter: { fontWeight: 'bold', color: '#2A3C67', fontSize: 15, - marginTop: '140px', - marginLeft: '20px' + marginTop: '60px', + marginLeft: '0px', + fontFamily: 'TitilliumBold' }, autocomplete: { height: 'auto', @@ -75,47 +85,60 @@ const useStyles = makeStyles(theme => ({ border: '3px solid rgba(127, 239, 239, 1)', borderRadius: '10px 10px 10px 10px', marginTop: '10px', - marginLeft: '20px' + marginLeft: '0px' }, tutorialsList: { marginTop: '50px' }, - tutorialTitle: { - fontWeight: 'bold', - fontSize: 25, + tutorialTitleGrid: { + marginRight: '40px' + }, + tutorialTitleText: { + fontSize: 22, lineHeight: '30px', - color: '#2A3C67' + color: '#2A3C67', + fontFamily: 'TitilliumBold' }, - tutorialAuthors: { + authorsGrid: { + marginLeft: '150px', + marginRight: '30px' + }, + fieldText: { color: '#2A3C67', - fontWeight: 'bold', - fontSize: 15, - lineHeight: '20px', - align: 'right', - marginLeft: '-30px' - + fontWeight: 'TitilliumBold' }, - tutorialDescription: { - marginTop: '-30px', - marginLeft: '50px' + linkAuthors: { + color: '#2A3C67', + cursor: 'pointer', + fontFamily: 'TitilliumRegular', + lineHeight: '20px' }, - tutorialActions: { + tutorialDescriptionGrid: { + marginTop: '-30px', marginLeft: '50px' }, - tutorialKeyworks: { - marginTop: '-30px' + tutorialDescriptionText: { + fontFamily: 'TitilliumRegular', + color: '#2A3C67' }, - link: { - color: '#2A3C67', - cursor: 'pointer', - fontWeight: 'normal' + keyworksGrid: { + marginTop: '-30px', + marginLeft: '63px' }, linkKeywords: { border: '1.5px solid rgba(127, 239, 239, 1)', lineHeight: '35px', color: '#2A3C67', cursor: 'pointer', - fontWeight: 'normal' + fontStyle: 'normal', + fontFamily: 'TitilliumRegular' + }, + tutorialActions: { + marginLeft: '50px' + }, + tutorialResources: { + marginTop: '-17px', + marginLeft: '-6px' } })) @@ -229,7 +252,7 @@ export default function AIToolkitPage() { return - + { 'Learn from tutorials' @@ -245,7 +268,7 @@ export default function AIToolkitPage() { - + { @@ -253,36 +276,42 @@ export default function AIToolkitPage() { } - + option} + style={{height: '50px', width: '150px'}} renderInput={params => ( - + )} value={queryParameters.author} onChange={(_, value) => setQueryParameters({...emptyQuery, author: value})} /> - + option} renderInput={params => ( - + )} value={queryParameters.keyword} onChange={(_, value) => setQueryParameters({...emptyQuery, keyword: value})} /> - + ( - + )} value={queryParameters.method} onChange={(_, value) => setQueryParameters({...emptyQuery, method: value})} @@ -303,29 +332,29 @@ export default function AIToolkitPage() { elevation={0} > }> - - - + + + {tutorial.title} - - - {'Authors: '} + + + {Authors: } {tutorial.authors .map(name => { const label = name.split(',').reverse().join(' ') return setQueryParameters({ ...emptyQuery, author: queryParameters.author === name ? null : name })} > - {label} + {label} - }).reduce((prev, curr) => [prev, ', ', curr]) + }).reduce((prev, curr) => [prev, ' | ', curr]) } @@ -334,13 +363,13 @@ export default function AIToolkitPage() { - - + + {tutorial.description} - - + + Keywords: @@ -359,7 +388,7 @@ export default function AIToolkitPage() { )).reduce((prev, curr) => [prev, ' ', curr]) } - + Methods: @@ -383,14 +412,44 @@ export default function AIToolkitPage() { - - - - + + + + + + + + + + + + + + + + + + + Additional Resources: + + + + + + + + + diff --git a/gui/src/components/aitoolkit/assets/AIT_ico_bd_link_doi.svg b/gui/src/components/aitoolkit/assets/AIT_ico_bd_link_doi.svg new file mode 100644 index 000000000..f170ac2f8 --- /dev/null +++ b/gui/src/components/aitoolkit/assets/AIT_ico_bd_link_doi.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/gui/src/components/aitoolkit/assets/AIT_ico_bd_link_pdf.svg b/gui/src/components/aitoolkit/assets/AIT_ico_bd_link_pdf.svg new file mode 100644 index 000000000..3b7df00b3 --- /dev/null +++ b/gui/src/components/aitoolkit/assets/AIT_ico_bd_link_pdf.svg @@ -0,0 +1,9 @@ + + + + + + + + + -- GitLab From da44ced14397707d3eea4fca65c8cbe8a4ca034a Mon Sep 17 00:00:00 2001 From: sbailo Date: Fri, 8 Oct 2021 17:39:58 +0200 Subject: [PATCH 18/68] Place expansion arrow to the left Reduce height accordions --- gui/src/components/aitoolkit/TutorialsPage.js | 104 +++++++----------- 1 file changed, 38 insertions(+), 66 deletions(-) diff --git a/gui/src/components/aitoolkit/TutorialsPage.js b/gui/src/components/aitoolkit/TutorialsPage.js index c4c6d3a53..abc4bc933 100644 --- a/gui/src/components/aitoolkit/TutorialsPage.js +++ b/gui/src/components/aitoolkit/TutorialsPage.js @@ -17,11 +17,11 @@ */ import React, { useMemo } from 'react' import { Box, Divider, Typography, makeStyles, Link, AccordionActions, Button, Grid, TextField } from '@material-ui/core' -import MUIAccordion from '@material-ui/core/Accordion' -import MUIAccordionSummary from '@material-ui/core/AccordionSummary' -import MUIAccordionDetails from '@material-ui/core/AccordionDetails' - -import { withStyles } from '@material-ui/core/styles' +import MuiAccordion from '@material-ui/core/Accordion' +import MuiAccordionSummary from '@material-ui/core/AccordionSummary' +import MuiAccordionDetails from '@material-ui/core/AccordionDetails' +import { styled } from '@material-ui/core/styles' +import ArrowForwardIosSharpIcon from '@material-ui/icons/ArrowForwardIosSharp' import tutorials from '../../toolkitMetadata' import ExpandMoreIcon from '@material-ui/icons/ExpandMore' import Markdown from '../Markdown' @@ -114,7 +114,6 @@ const useStyles = makeStyles(theme => ({ lineHeight: '20px' }, tutorialDescriptionGrid: { - marginTop: '-30px', marginLeft: '50px' }, tutorialDescriptionText: { @@ -122,8 +121,7 @@ const useStyles = makeStyles(theme => ({ color: '#2A3C67' }, keyworksGrid: { - marginTop: '-30px', - marginLeft: '63px' + marginLeft: '80px' }, linkKeywords: { border: '1.5px solid rgba(127, 239, 239, 1)', @@ -142,66 +140,37 @@ const useStyles = makeStyles(theme => ({ } })) -const Accordion = withStyles({ - root: { - borderTop: '10px solid rgba(127, 239, 239, 1)', - scrollbarGutter: 'false', - width: '100%', - display: 'block', - '&:not(:last-child)': { - }, - '&:before': { - display: 'none' - }, - '&$expanded': { - margin: 'auto' - } - }, - heading: { - fontSize: 35, - flexBasis: '33.33%', - flexShrink: 0, - marginLeft: '0px' - }, - secondaryHeading: { - fontSize: 10 +const Accordion = styled((props) => ( + +))(({ theme }) => ({ + borderTop: '8px solid rgba(127, 239, 239, 1)', + '&:not(:last-child)': { + borderBottom: 0 }, - expanded: {} -})(MUIAccordion) - -const AccordionSummary = withStyles({ - root: { - // flexDirection: 'column', - // height: '150px', - width: '100%', - display: 'block' + '&:before': { + display: 'none' } - // content: { - // marginBottom: 0, - // flexGrow: 1 - // }, - // expandIcon: { - // marginRight: '10px', - // paddingTop: '10px' - // } -})(MUIAccordionSummary) +})) -const AccordionDetails = withStyles({ - root: { - width: '100%', - display: 'block', - marginTop: '30px' +const AccordionSummary = styled((props) => ( + } + {...props} + /> +))(({ theme }) => ({ + flexDirection: 'row-reverse', + '& .MuiAccordionSummary-expandIconWrapper.Mui-expanded': { + transform: 'rotate(90deg)' + }, + '& .MuiAccordionSummary-content': { + marginLeft: theme.spacing(1) } - // content: { - // marginBottom: 0, - // flexGrow: 1 - // }, - // expandIcon: { - // marginRight: '10px', - // paddingTop: '20px' - // } -})(MUIAccordionDetails) +})) + +const AccordionDetails = styled(MuiAccordionDetails)(({ theme }) => ({ + padding: theme.spacing(2) +})) export default function AIToolkitPage() { const classes = useStyles() @@ -412,7 +381,9 @@ export default function AIToolkitPage() { + + @@ -420,16 +391,15 @@ export default function AIToolkitPage() { Access tutorial - - + + @@ -441,6 +411,7 @@ export default function AIToolkitPage() { Additional Resources: + @@ -449,6 +420,7 @@ export default function AIToolkitPage() { + -- GitLab From 3a285ad365c86587d5d85cc40975dd7e7ff7553e Mon Sep 17 00:00:00 2001 From: sbailo Date: Mon, 11 Oct 2021 11:56:18 +0200 Subject: [PATCH 19/68] Add bottom addressing to published results --- gui/src/components/aitoolkit/TutorialsPage.js | 53 +++++++++++++++++-- .../assets/AIT_ico_bd_link_go_to.svg | 1 + .../aitoolkit/assets/AIT_illu_AIT.svg | 27 ++++++++++ 3 files changed, 78 insertions(+), 3 deletions(-) create mode 100644 gui/src/components/aitoolkit/assets/AIT_ico_bd_link_go_to.svg create mode 100644 gui/src/components/aitoolkit/assets/AIT_illu_AIT.svg diff --git a/gui/src/components/aitoolkit/TutorialsPage.js b/gui/src/components/aitoolkit/TutorialsPage.js index abc4bc933..ff08dc6cf 100644 --- a/gui/src/components/aitoolkit/TutorialsPage.js +++ b/gui/src/components/aitoolkit/TutorialsPage.js @@ -32,6 +32,8 @@ import AccessIcon from './assets/AIT_ico_bd_link_external_big.svg' import WatchIcon from './assets/AIT_ico_bd_youtube.svg' import PdfIcon from './assets/AIT_ico_bd_link_pdf.svg' import DoiIcon from './assets/AIT_ico_bd_link_doi.svg' +import ArrowIcon from './assets/AIT_ico_bd_link_go_to.svg' +import ReproduceIcon from './assets/AIT_ico_bb_replicate.svg' const useStyles = makeStyles(theme => ({ @@ -56,7 +58,6 @@ const useStyles = makeStyles(theme => ({ fontSize: 30, marginLeft: '-10px', fontFamily: 'TitilliumBold' - }, deck: { color: '#2A3C67', @@ -105,7 +106,7 @@ const useStyles = makeStyles(theme => ({ }, fieldText: { color: '#2A3C67', - fontWeight: 'TitilliumBold' + // fontWeight: 'TitilliumBold' }, linkAuthors: { color: '#2A3C67', @@ -137,6 +138,32 @@ const useStyles = makeStyles(theme => ({ tutorialResources: { marginTop: '-17px', marginLeft: '-6px' + }, + titleSecondary: { + fontWeight: 'bold', + color: 'rgba(127, 239, 239, 1)', + fontSize: 30, + marginLeft: '-10px', + fontFamily: 'TitilliumRegular' + }, + bottomButton: { + color: '#F3F2F5', + backgroundColor: '#F3F2F5', + borderRadius: '30px', + width: '242px', + height: '70px', + textAlign: 'center', + align: 'center', + marginTop: '40px', + textTransform: 'none', + fontSize: '12pt', + lineHeight: '20px', + fontFamily: 'TitilliumBold' + }, + bottomIcon: { + height: '300px', + marginTop: '80px', + marginLeft: '120px' } })) @@ -220,7 +247,7 @@ export default function AIToolkitPage() { }, [tutorials_list]) return - + { @@ -431,5 +458,25 @@ export default function AIToolkitPage() { ))} + + + { + 'Next advanced level' + } + + + { + 'After learning the basics of machine learning, you can apply the latest AI developments to timely problems in materials science. These outstanding applications allow to reproduce results that have been recently published in scientific journals.' + } + + + + + + } diff --git a/gui/src/components/aitoolkit/assets/AIT_ico_bd_link_go_to.svg b/gui/src/components/aitoolkit/assets/AIT_ico_bd_link_go_to.svg new file mode 100644 index 000000000..515dbec13 --- /dev/null +++ b/gui/src/components/aitoolkit/assets/AIT_ico_bd_link_go_to.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/gui/src/components/aitoolkit/assets/AIT_illu_AIT.svg b/gui/src/components/aitoolkit/assets/AIT_illu_AIT.svg new file mode 100644 index 000000000..1e8d3b265 --- /dev/null +++ b/gui/src/components/aitoolkit/assets/AIT_illu_AIT.svg @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + -- GitLab From 214ba5af8f8072055c1f86ab3f7fc20e3a1c02b3 Mon Sep 17 00:00:00 2001 From: sbailo Date: Mon, 11 Oct 2021 16:38:32 +0200 Subject: [PATCH 20/68] Accordions list is an external component --- .../components/aitoolkit/AccordionsList.js | 328 ++++++++++++++++++ gui/src/components/aitoolkit/TutorialsPage.js | 233 ++----------- 2 files changed, 361 insertions(+), 200 deletions(-) create mode 100644 gui/src/components/aitoolkit/AccordionsList.js diff --git a/gui/src/components/aitoolkit/AccordionsList.js b/gui/src/components/aitoolkit/AccordionsList.js new file mode 100644 index 000000000..afe20af5f --- /dev/null +++ b/gui/src/components/aitoolkit/AccordionsList.js @@ -0,0 +1,328 @@ +import React from 'react' +import { Divider, Typography, makeStyles, Link, AccordionActions, Button, Grid } from '@material-ui/core' +import MuiAccordion from '@material-ui/core/Accordion' +import MuiAccordionSummary from '@material-ui/core/AccordionSummary' +import MuiAccordionDetails from '@material-ui/core/AccordionDetails' +import { styled } from '@material-ui/core/styles' +import ArrowForwardIosSharpIcon from '@material-ui/icons/ArrowForwardIosSharp' +import ExpandMoreIcon from '@material-ui/icons/ExpandMore' +import Markdown from '../Markdown' +import { StringParam, useQueryParam } from 'use-query-params' +import AccessIcon from './assets/AIT_ico_bd_link_external_big.svg' +import WatchIcon from './assets/AIT_ico_bd_youtube.svg' +import PdfIcon from './assets/AIT_ico_bd_link_pdf.svg' +import DoiIcon from './assets/AIT_ico_bd_link_doi.svg' + +const useStyles = makeStyles(theme => ({ + + root: { + margin: theme.spacing(3), + width: '100%', + marginLeft: 'auto', + marginRight: 'auto', + maxWidth: '1052px' + }, + sectionIcon: { + marginTop: theme.spacing(3) + }, + sectionTitle: { + marginBottom: theme.spacing(1), + marginLeft: theme.spacing(2), + marginTop: '105px' + }, + title: { + fontWeight: 'bold', + color: '#2A3C67', + fontSize: '35px', + marginLeft: '-10px', + fontFamily: 'TitilliumBold', + marginTop: '-70px' + }, + deck: { + color: '#2A3C67', + fontSize: '22px', + marginTop: '20px', + lineHeight: '30px', + marginLeft: '-10px', + fontFamily: 'TitilliumRegular', + width: '518px' + }, + icon: { + height: '371px', + marginTop: '-20px', + marginLeft: '100px' + }, + filter: { + fontWeight: 'bold', + color: '#2A3C67', + fontSize: '20px', + marginTop: '60px', + marginLeft: '0px', + fontFamily: 'TitilliumBold' + }, + autocomplete: { + height: 'auto', + color: '#2A3C67', + border: '3px solid rgba(127, 239, 239, 1)', + borderRadius: '10px 10px 10px 10px', + marginTop: '10px', + marginLeft: '0px' + }, + tutorialsList: { + marginTop: '50px' + }, + tutorialTitleGrid: { + marginRight: '40px' + }, + tutorialTitleText: { + fontSize: '28px', + color: '#2A3C67', + fontFamily: 'TitilliumBold' + }, + authorsGrid: { + marginLeft: '150px', + marginRight: '30px' + }, + fieldText: { + color: '#2A3C67' + }, + linkAuthors: { + color: '#2A3C67', + cursor: 'pointer', + fontFamily: 'TitilliumRegular', + lineHeight: '20px', + fontSize: '16px' + }, + tutorialDescriptionGrid: { + marginLeft: '50px' + }, + tutorialDescriptionText: { + fontFamily: 'TitilliumRegular', + color: '#2A3C67', + fontSize: '18px' + }, + keyworksGrid: { + marginLeft: '80px' + }, + linkKeywords: { + border: '1.5px solid rgba(127, 239, 239, 1)', + lineHeight: '35px', + color: '#2A3C67', + cursor: 'pointer', + fontStyle: 'normal', + fontFamily: 'TitilliumRegular', + fontSize: '16px' + }, + tutorialActions: { + marginLeft: '50px' + }, + tutorialResources: { + marginTop: '-17px', + marginLeft: '-6px' + }, + titleSecondary: { + fontWeight: 'bold', + color: 'rgba(127, 239, 239, 1)', + fontSize: '35px', + marginLeft: '-10px', + fontFamily: 'TitilliumRegular' + }, + bottomButton: { + color: '#F3F2F5', + backgroundColor: '#F3F2F5', + borderRadius: '30px', + width: '242px', + height: '70px', + textAlign: 'center', + align: 'center', + marginTop: '40px', + textTransform: 'none', + fontSize: '12pt', + lineHeight: '20px', + fontFamily: 'TitilliumBold' + }, + bottomIcon: { + height: '300px', + marginTop: '80px', + marginLeft: '120px' + } +})) + +const Accordion = styled((props) => ( + +))(({ theme }) => ({ + borderBottom: '8px solid rgba(127, 239, 239, 1)', + '&:not(:last-child)': { + borderBottom: 0 + }, + '&:before': { + display: 'none' + } +})) + +const AccordionSummary = styled((props) => ( + } + {...props} + /> +))(({ theme }) => ({ + + flexDirection: 'row-reverse', + '& .MuiAccordionSummary-expandIconWrapper.Mui-expanded': { + transform: 'rotate(90deg)' + }, + '& .MuiAccordionSummary-content': { + marginLeft: theme.spacing(1) + } +})) + +const AccordionDetails = styled(MuiAccordionDetails)(({ theme }) => ({ + padding: theme.spacing(2) +})) + +function AccordionsList(props) { + const classes = useStyles() + const [expanded, setExpanded] = useQueryParam('expanded', StringParam) + return ( + props.tutorials_list.map(tutorial => ( +
+ setExpanded(expanded === tutorial.key ? null : tutorial.key)} + className={classes.tutorial} + elevation={0} + > + }> + + + + {tutorial.title} + + + + + {Authors: } + {tutorial.authors + .map(name => { + const label = name.split(',').reverse().join(' ') + return props.setQueryParameters({ + ...props.emptyQuery, + author: props.queryParameters.author === name ? null : name + })} + > + {label} + + }).reduce((prev, curr) => [prev, ' | ', curr]) + } + + + + + + + + + + {tutorial.description} + + + + + Keywords: + + + {tutorial.labels.application_keyword + .map(keyword => ( + props.setQueryParameters({ + ...props.emptyQuery, + keyword: props.queryParameters.keyword === keyword ? null : keyword + })} + > + {keyword} + + )).reduce((prev, curr) => [prev, ' ', curr]) + } + + + Methods: + + + {tutorial.labels.data_analytics_method + .map(method => ( + props.setQueryParameters({ + ...props.emptyQuery, + method: props.queryParameters.method === method ? null : method + })} + > + {method} + + )).reduce((prev, curr) => [prev, ' ', curr]) + } + + + + + + + + + + + + + + + + + + + + + + + + + + Additional Resources: + + + + + + + + + + + + + + + + +
+ ))) +} + +export default AccordionsList diff --git a/gui/src/components/aitoolkit/TutorialsPage.js b/gui/src/components/aitoolkit/TutorialsPage.js index ff08dc6cf..a9d02de91 100644 --- a/gui/src/components/aitoolkit/TutorialsPage.js +++ b/gui/src/components/aitoolkit/TutorialsPage.js @@ -16,24 +16,14 @@ * limitations under the License. */ import React, { useMemo } from 'react' -import { Box, Divider, Typography, makeStyles, Link, AccordionActions, Button, Grid, TextField } from '@material-ui/core' -import MuiAccordion from '@material-ui/core/Accordion' -import MuiAccordionSummary from '@material-ui/core/AccordionSummary' -import MuiAccordionDetails from '@material-ui/core/AccordionDetails' -import { styled } from '@material-ui/core/styles' -import ArrowForwardIosSharpIcon from '@material-ui/icons/ArrowForwardIosSharp' +import { Box, Button, Grid, TextField, makeStyles } from '@material-ui/core' import tutorials from '../../toolkitMetadata' -import ExpandMoreIcon from '@material-ui/icons/ExpandMore' -import Markdown from '../Markdown' import { StringParam, useQueryParams, useQueryParam } from 'use-query-params' import Autocomplete from '@material-ui/lab/Autocomplete' import TutorialsIcon from './assets/AIT_ico_bp_tutorial.svg' -import AccessIcon from './assets/AIT_ico_bd_link_external_big.svg' -import WatchIcon from './assets/AIT_ico_bd_youtube.svg' -import PdfIcon from './assets/AIT_ico_bd_link_pdf.svg' -import DoiIcon from './assets/AIT_ico_bd_link_doi.svg' import ArrowIcon from './assets/AIT_ico_bd_link_go_to.svg' import ReproduceIcon from './assets/AIT_ico_bb_replicate.svg' +import AccordionsList from './AccordionsList' const useStyles = makeStyles(theme => ({ @@ -42,7 +32,7 @@ const useStyles = makeStyles(theme => ({ width: '100%', marginLeft: 'auto', marginRight: 'auto', - maxWidth: '1024px' + maxWidth: '1052px' }, sectionIcon: { marginTop: theme.spacing(3) @@ -55,27 +45,29 @@ const useStyles = makeStyles(theme => ({ title: { fontWeight: 'bold', color: '#2A3C67', - fontSize: 30, + fontSize: '35px', marginLeft: '-10px', - fontFamily: 'TitilliumBold' + fontFamily: 'TitilliumBold', + marginTop: '-70px' }, deck: { color: '#2A3C67', - fontSize: 15, + fontSize: '22px', marginTop: '20px', - lineHeight: '24px', + lineHeight: '30px', marginLeft: '-10px', - fontFamily: 'TitilliumRegular' + fontFamily: 'TitilliumRegular', + width: '518px' }, icon: { - height: '350px', + height: '371px', marginTop: '-20px', marginLeft: '100px' }, filter: { fontWeight: 'bold', color: '#2A3C67', - fontSize: 15, + fontSize: '20px', marginTop: '60px', marginLeft: '0px', fontFamily: 'TitilliumBold' @@ -95,8 +87,7 @@ const useStyles = makeStyles(theme => ({ marginRight: '40px' }, tutorialTitleText: { - fontSize: 22, - lineHeight: '30px', + fontSize: '28px', color: '#2A3C67', fontFamily: 'TitilliumBold' }, @@ -105,21 +96,22 @@ const useStyles = makeStyles(theme => ({ marginRight: '30px' }, fieldText: { - color: '#2A3C67', - // fontWeight: 'TitilliumBold' + color: '#2A3C67' }, linkAuthors: { color: '#2A3C67', cursor: 'pointer', fontFamily: 'TitilliumRegular', - lineHeight: '20px' + lineHeight: '20px', + fontSize: '16px' }, tutorialDescriptionGrid: { marginLeft: '50px' }, tutorialDescriptionText: { fontFamily: 'TitilliumRegular', - color: '#2A3C67' + color: '#2A3C67', + fontSize: '18px' }, keyworksGrid: { marginLeft: '80px' @@ -130,7 +122,8 @@ const useStyles = makeStyles(theme => ({ color: '#2A3C67', cursor: 'pointer', fontStyle: 'normal', - fontFamily: 'TitilliumRegular' + fontFamily: 'TitilliumRegular', + fontSize: '16px' }, tutorialActions: { marginLeft: '50px' @@ -142,7 +135,7 @@ const useStyles = makeStyles(theme => ({ titleSecondary: { fontWeight: 'bold', color: 'rgba(127, 239, 239, 1)', - fontSize: 30, + fontSize: '35px', marginLeft: '-10px', fontFamily: 'TitilliumRegular' }, @@ -167,38 +160,6 @@ const useStyles = makeStyles(theme => ({ } })) -const Accordion = styled((props) => ( - -))(({ theme }) => ({ - borderTop: '8px solid rgba(127, 239, 239, 1)', - '&:not(:last-child)': { - borderBottom: 0 - }, - '&:before': { - display: 'none' - } -})) - -const AccordionSummary = styled((props) => ( - } - {...props} - /> -))(({ theme }) => ({ - - flexDirection: 'row-reverse', - '& .MuiAccordionSummary-expandIconWrapper.Mui-expanded': { - transform: 'rotate(90deg)' - }, - '& .MuiAccordionSummary-content': { - marginLeft: theme.spacing(1) - } -})) - -const AccordionDetails = styled(MuiAccordionDetails)(({ theme }) => ({ - padding: theme.spacing(2) -})) - export default function AIToolkitPage() { const classes = useStyles() const [expanded, setExpanded] = useQueryParam('expanded', StringParam) @@ -228,6 +189,10 @@ export default function AIToolkitPage() { const tutorials_list = tutorials.tutorials.filter(tutorial => tutorial.labels.application_section[0] === 'Tutorials for artificial-intelligence methods') + const tutorials_list_beginner = tutorials_list.filter(tutorial => tutorial.labels.category[0] === 'beginner_tutorial') + + const tutorials_list_intermediate = tutorials_list.filter(tutorial => tutorial.labels.category[0] === 'intermediate_tutorial') + const {authors, keywords, methods} = useMemo(() => { const authors = {} const keywords = {} @@ -314,148 +279,16 @@ export default function AIToolkitPage() { />
- - {tutorials_list.map(tutorial => ( -
- setExpanded(expanded === tutorial.key ? null : tutorial.key)} - className={classes.tutorial} - elevation={0} - > - }> - - - - {tutorial.title} - - - - - {Authors: } - {tutorial.authors - .map(name => { - const label = name.split(',').reverse().join(' ') - return setQueryParameters({ - ...emptyQuery, - author: queryParameters.author === name ? null : name - })} - > - {label} - - }).reduce((prev, curr) => [prev, ' | ', curr]) - } - - - - - - - - - - {tutorial.description} - - - - - Keywords: - - - {tutorial.labels.application_keyword - .map(keyword => ( - setQueryParameters({ - ...emptyQuery, - keyword: queryParameters.keyword === keyword ? null : keyword - })} - > - {keyword} - - )).reduce((prev, curr) => [prev, ' ', curr]) - } - - - Methods: - - - {tutorial.labels.data_analytics_method - .map(method => ( - setQueryParameters({ - ...emptyQuery, - method: queryParameters.method === method ? null : method - })} - > - {method} - - )).reduce((prev, curr) => [prev, ' ', curr]) - } - - - - - - - - - - - - - - - - - - - - - - - - - - Additional Resources: - - - - - - - - - - - - - - - - -
- ))} +
-- GitLab From d0ccf94f9d3becec0d21e1d05e10aa574f321939 Mon Sep 17 00:00:00 2001 From: sbailo Date: Mon, 11 Oct 2021 17:39:49 +0200 Subject: [PATCH 21/68] Tutorials are divided in beginner and intermediate Customize accordions --- .../components/aitoolkit/AccordionsList.js | 2 +- gui/src/components/aitoolkit/TutorialsPage.js | 46 ++++++++++++++++++- 2 files changed, 45 insertions(+), 3 deletions(-) diff --git a/gui/src/components/aitoolkit/AccordionsList.js b/gui/src/components/aitoolkit/AccordionsList.js index afe20af5f..161c541fd 100644 --- a/gui/src/components/aitoolkit/AccordionsList.js +++ b/gui/src/components/aitoolkit/AccordionsList.js @@ -151,7 +151,7 @@ const useStyles = makeStyles(theme => ({ const Accordion = styled((props) => ( ))(({ theme }) => ({ - borderBottom: '8px solid rgba(127, 239, 239, 1)', + borderBottom: '13px solid rgba(127, 239, 239, 1)', '&:not(:last-child)': { borderBottom: 0 }, diff --git a/gui/src/components/aitoolkit/TutorialsPage.js b/gui/src/components/aitoolkit/TutorialsPage.js index a9d02de91..ff7b78138 100644 --- a/gui/src/components/aitoolkit/TutorialsPage.js +++ b/gui/src/components/aitoolkit/TutorialsPage.js @@ -16,7 +16,7 @@ * limitations under the License. */ import React, { useMemo } from 'react' -import { Box, Button, Grid, TextField, makeStyles } from '@material-ui/core' +import { Box, Button, Grid, TextField, makeStyles, Divider, Typography } from '@material-ui/core' import tutorials from '../../toolkitMetadata' import { StringParam, useQueryParams, useQueryParam } from 'use-query-params' import Autocomplete from '@material-ui/lab/Autocomplete' @@ -125,6 +125,18 @@ const useStyles = makeStyles(theme => ({ fontFamily: 'TitilliumRegular', fontSize: '16px' }, + textLevel: { + textAlign: 'left', + color: 'rgba(127, 239, 239, 1)', + fontSize: '22px', + fontFamily: 'TitilliumRegular', + marginTop: '-10px' + }, + tutorialsDivider: { + backgroundColor: 'rgba(127, 239, 239, 1)', + height: '13px', + borderRadius: '4px' + }, tutorialActions: { marginLeft: '50px' }, @@ -281,7 +293,15 @@ export default function AIToolkitPage() { - + + BEGINNER LEVEL + + + + + + + + + + INTERMEDIATE LEVEL + + + + + + + + + +
@@ -311,5 +352,6 @@ export default function AIToolkitPage() { + } -- GitLab From 814d28943a983c7c9ed30efd332231425aefc3f6 Mon Sep 17 00:00:00 2001 From: sbailo Date: Tue, 12 Oct 2021 11:43:16 +0200 Subject: [PATCH 22/68] Styles are in a separate file --- .../components/aitoolkit/AccordionsList.js | 149 +---------------- gui/src/components/aitoolkit/TutorialsPage.js | 155 +----------------- gui/src/components/aitoolkit/styles.js | 153 +++++++++++++++++ 3 files changed, 165 insertions(+), 292 deletions(-) create mode 100644 gui/src/components/aitoolkit/styles.js diff --git a/gui/src/components/aitoolkit/AccordionsList.js b/gui/src/components/aitoolkit/AccordionsList.js index 161c541fd..a142b454b 100644 --- a/gui/src/components/aitoolkit/AccordionsList.js +++ b/gui/src/components/aitoolkit/AccordionsList.js @@ -1,5 +1,6 @@ import React from 'react' -import { Divider, Typography, makeStyles, Link, AccordionActions, Button, Grid } from '@material-ui/core' +import {useStyles} from './styles.js' +import { Divider, Typography, Link, AccordionActions, Button, Grid } from '@material-ui/core' import MuiAccordion from '@material-ui/core/Accordion' import MuiAccordionSummary from '@material-ui/core/AccordionSummary' import MuiAccordionDetails from '@material-ui/core/AccordionDetails' @@ -13,141 +14,6 @@ import WatchIcon from './assets/AIT_ico_bd_youtube.svg' import PdfIcon from './assets/AIT_ico_bd_link_pdf.svg' import DoiIcon from './assets/AIT_ico_bd_link_doi.svg' -const useStyles = makeStyles(theme => ({ - - root: { - margin: theme.spacing(3), - width: '100%', - marginLeft: 'auto', - marginRight: 'auto', - maxWidth: '1052px' - }, - sectionIcon: { - marginTop: theme.spacing(3) - }, - sectionTitle: { - marginBottom: theme.spacing(1), - marginLeft: theme.spacing(2), - marginTop: '105px' - }, - title: { - fontWeight: 'bold', - color: '#2A3C67', - fontSize: '35px', - marginLeft: '-10px', - fontFamily: 'TitilliumBold', - marginTop: '-70px' - }, - deck: { - color: '#2A3C67', - fontSize: '22px', - marginTop: '20px', - lineHeight: '30px', - marginLeft: '-10px', - fontFamily: 'TitilliumRegular', - width: '518px' - }, - icon: { - height: '371px', - marginTop: '-20px', - marginLeft: '100px' - }, - filter: { - fontWeight: 'bold', - color: '#2A3C67', - fontSize: '20px', - marginTop: '60px', - marginLeft: '0px', - fontFamily: 'TitilliumBold' - }, - autocomplete: { - height: 'auto', - color: '#2A3C67', - border: '3px solid rgba(127, 239, 239, 1)', - borderRadius: '10px 10px 10px 10px', - marginTop: '10px', - marginLeft: '0px' - }, - tutorialsList: { - marginTop: '50px' - }, - tutorialTitleGrid: { - marginRight: '40px' - }, - tutorialTitleText: { - fontSize: '28px', - color: '#2A3C67', - fontFamily: 'TitilliumBold' - }, - authorsGrid: { - marginLeft: '150px', - marginRight: '30px' - }, - fieldText: { - color: '#2A3C67' - }, - linkAuthors: { - color: '#2A3C67', - cursor: 'pointer', - fontFamily: 'TitilliumRegular', - lineHeight: '20px', - fontSize: '16px' - }, - tutorialDescriptionGrid: { - marginLeft: '50px' - }, - tutorialDescriptionText: { - fontFamily: 'TitilliumRegular', - color: '#2A3C67', - fontSize: '18px' - }, - keyworksGrid: { - marginLeft: '80px' - }, - linkKeywords: { - border: '1.5px solid rgba(127, 239, 239, 1)', - lineHeight: '35px', - color: '#2A3C67', - cursor: 'pointer', - fontStyle: 'normal', - fontFamily: 'TitilliumRegular', - fontSize: '16px' - }, - tutorialActions: { - marginLeft: '50px' - }, - tutorialResources: { - marginTop: '-17px', - marginLeft: '-6px' - }, - titleSecondary: { - fontWeight: 'bold', - color: 'rgba(127, 239, 239, 1)', - fontSize: '35px', - marginLeft: '-10px', - fontFamily: 'TitilliumRegular' - }, - bottomButton: { - color: '#F3F2F5', - backgroundColor: '#F3F2F5', - borderRadius: '30px', - width: '242px', - height: '70px', - textAlign: 'center', - align: 'center', - marginTop: '40px', - textTransform: 'none', - fontSize: '12pt', - lineHeight: '20px', - fontFamily: 'TitilliumBold' - }, - bottomIcon: { - height: '300px', - marginTop: '80px', - marginLeft: '120px' - } -})) - const Accordion = styled((props) => ( ))(({ theme }) => ({ @@ -196,11 +62,13 @@ function AccordionsList(props) { > }> + {tutorial.title} + {Authors: } @@ -226,11 +94,13 @@ function AccordionsList(props) { + {tutorial.description} + Keywords: @@ -275,7 +145,6 @@ function AccordionsList(props) { - @@ -287,7 +156,6 @@ function AccordionsList(props) { - -
+ @@ -305,7 +173,6 @@ function AccordionsList(props) { Additional Resources: - @@ -314,10 +181,10 @@ function AccordionsList(props) { -
+ diff --git a/gui/src/components/aitoolkit/TutorialsPage.js b/gui/src/components/aitoolkit/TutorialsPage.js index ff7b78138..65900d3f8 100644 --- a/gui/src/components/aitoolkit/TutorialsPage.js +++ b/gui/src/components/aitoolkit/TutorialsPage.js @@ -16,165 +16,18 @@ * limitations under the License. */ import React, { useMemo } from 'react' -import { Box, Button, Grid, TextField, makeStyles, Divider, Typography } from '@material-ui/core' +import {useStyles} from './styles.js' +import { Box, Button, Grid, TextField, Divider } from '@material-ui/core' import tutorials from '../../toolkitMetadata' -import { StringParam, useQueryParams, useQueryParam } from 'use-query-params' +import { StringParam, useQueryParams } from 'use-query-params' import Autocomplete from '@material-ui/lab/Autocomplete' import TutorialsIcon from './assets/AIT_ico_bp_tutorial.svg' import ArrowIcon from './assets/AIT_ico_bd_link_go_to.svg' import ReproduceIcon from './assets/AIT_ico_bb_replicate.svg' import AccordionsList from './AccordionsList' -const useStyles = makeStyles(theme => ({ - - root: { - margin: theme.spacing(3), - width: '100%', - marginLeft: 'auto', - marginRight: 'auto', - maxWidth: '1052px' - }, - sectionIcon: { - marginTop: theme.spacing(3) - }, - sectionTitle: { - marginBottom: theme.spacing(1), - marginLeft: theme.spacing(2), - marginTop: '105px' - }, - title: { - fontWeight: 'bold', - color: '#2A3C67', - fontSize: '35px', - marginLeft: '-10px', - fontFamily: 'TitilliumBold', - marginTop: '-70px' - }, - deck: { - color: '#2A3C67', - fontSize: '22px', - marginTop: '20px', - lineHeight: '30px', - marginLeft: '-10px', - fontFamily: 'TitilliumRegular', - width: '518px' - }, - icon: { - height: '371px', - marginTop: '-20px', - marginLeft: '100px' - }, - filter: { - fontWeight: 'bold', - color: '#2A3C67', - fontSize: '20px', - marginTop: '60px', - marginLeft: '0px', - fontFamily: 'TitilliumBold' - }, - autocomplete: { - height: 'auto', - color: '#2A3C67', - border: '3px solid rgba(127, 239, 239, 1)', - borderRadius: '10px 10px 10px 10px', - marginTop: '10px', - marginLeft: '0px' - }, - tutorialsList: { - marginTop: '50px' - }, - tutorialTitleGrid: { - marginRight: '40px' - }, - tutorialTitleText: { - fontSize: '28px', - color: '#2A3C67', - fontFamily: 'TitilliumBold' - }, - authorsGrid: { - marginLeft: '150px', - marginRight: '30px' - }, - fieldText: { - color: '#2A3C67' - }, - linkAuthors: { - color: '#2A3C67', - cursor: 'pointer', - fontFamily: 'TitilliumRegular', - lineHeight: '20px', - fontSize: '16px' - }, - tutorialDescriptionGrid: { - marginLeft: '50px' - }, - tutorialDescriptionText: { - fontFamily: 'TitilliumRegular', - color: '#2A3C67', - fontSize: '18px' - }, - keyworksGrid: { - marginLeft: '80px' - }, - linkKeywords: { - border: '1.5px solid rgba(127, 239, 239, 1)', - lineHeight: '35px', - color: '#2A3C67', - cursor: 'pointer', - fontStyle: 'normal', - fontFamily: 'TitilliumRegular', - fontSize: '16px' - }, - textLevel: { - textAlign: 'left', - color: 'rgba(127, 239, 239, 1)', - fontSize: '22px', - fontFamily: 'TitilliumRegular', - marginTop: '-10px' - }, - tutorialsDivider: { - backgroundColor: 'rgba(127, 239, 239, 1)', - height: '13px', - borderRadius: '4px' - }, - tutorialActions: { - marginLeft: '50px' - }, - tutorialResources: { - marginTop: '-17px', - marginLeft: '-6px' - }, - titleSecondary: { - fontWeight: 'bold', - color: 'rgba(127, 239, 239, 1)', - fontSize: '35px', - marginLeft: '-10px', - fontFamily: 'TitilliumRegular' - }, - bottomButton: { - color: '#F3F2F5', - backgroundColor: '#F3F2F5', - borderRadius: '30px', - width: '242px', - height: '70px', - textAlign: 'center', - align: 'center', - marginTop: '40px', - textTransform: 'none', - fontSize: '12pt', - lineHeight: '20px', - fontFamily: 'TitilliumBold' - }, - bottomIcon: { - height: '300px', - marginTop: '80px', - marginLeft: '120px' - } -})) - export default function AIToolkitPage() { const classes = useStyles() - const [expanded, setExpanded] = useQueryParam('expanded', StringParam) const [queryParameters, setQueryParameters] = useQueryParams({ author: StringParam, keyword: StringParam, method: StringParam, filterString: StringParam }) @@ -311,7 +164,7 @@ export default function AIToolkitPage() { emptyQuery={queryParameters} />
- + INTERMEDIATE LEVEL diff --git a/gui/src/components/aitoolkit/styles.js b/gui/src/components/aitoolkit/styles.js new file mode 100644 index 000000000..6c4e6c450 --- /dev/null +++ b/gui/src/components/aitoolkit/styles.js @@ -0,0 +1,153 @@ + +import {makeStyles} from '@material-ui/core' + +const useStyles = makeStyles(theme => ({ + + root: { + margin: theme.spacing(3), + width: '100%', + marginLeft: 'auto', + marginRight: 'auto', + maxWidth: '1052px' + }, + sectionIcon: { + marginTop: theme.spacing(3) + }, + sectionTitle: { + marginBottom: theme.spacing(1), + marginLeft: theme.spacing(2), + marginTop: '105px' + }, + title: { + fontWeight: 'bold', + color: '#2A3C67', + fontSize: '35px', + marginLeft: '-10px', + fontFamily: 'TitilliumBold', + marginTop: '-70px' + }, + deck: { + color: '#2A3C67', + fontSize: '22px', + marginTop: '20px', + lineHeight: '30px', + marginLeft: '-10px', + fontFamily: 'TitilliumRegular', + width: '518px' + }, + icon: { + height: '371px', + marginTop: '-20px', + marginLeft: '100px' + }, + filter: { + fontWeight: 'bold', + color: '#2A3C67', + fontSize: '20px', + marginTop: '60px', + marginLeft: '0px', + fontFamily: 'TitilliumBold' + }, + autocomplete: { + height: 'auto', + color: '#2A3C67', + border: '3px solid rgba(127, 239, 239, 1)', + borderRadius: '10px 10px 10px 10px', + marginTop: '10px', + marginLeft: '0px' + }, + tutorialsList: { + marginTop: '50px' + }, + tutorialTitleGrid: { + marginRight: '40px' + }, + tutorialTitleText: { + fontSize: '28px', + color: '#2A3C67', + fontFamily: 'TitilliumBold', + lineHeight: '30px' + }, + authorsGrid: { + marginLeft: '150px', + marginRight: '30px' + }, + fieldText: { + color: '#2A3C67' + }, + linkAuthors: { + color: '#2A3C67', + cursor: 'pointer', + fontFamily: 'TitilliumRegular', + lineHeight: '20px', + fontSize: '16px' + }, + tutorialDescriptionGrid: { + marginLeft: '50px' + }, + tutorialDescriptionText: { + fontFamily: 'TitilliumRegular', + color: '#2A3C67', + fontSize: '18px' + }, + keyworksGrid: { + marginLeft: '80px' + }, + linkKeywords: { + border: '1.5px solid rgba(127, 239, 239, 1)', + lineHeight: '35px', + color: '#2A3C67', + cursor: 'pointer', + fontStyle: 'normal', + fontFamily: 'TitilliumRegular', + fontSize: '16px' + }, + textLevel: { + textAlign: 'left', + color: 'rgba(127, 239, 239, 1)', + fontSize: '22px', + height: '22px', + fontFamily: 'TitilliumRegular', + marginTop: '-16px' + }, + tutorialsDivider: { + backgroundColor: 'rgba(127, 239, 239, 1)', + height: '13px', + borderRadius: '4px' + }, + tutorialActions: { + marginLeft: '50px' + }, + tutorialResources: { + marginTop: '-17px', + marginLeft: '-6px' + }, + titleSecondary: { + fontWeight: 'bold', + color: 'rgba(127, 239, 239, 1)', + fontSize: '35px', + marginLeft: '-10px', + fontFamily: 'TitilliumRegular' + }, + bottomButton: { + color: '#F3F2F5', + backgroundColor: '#F3F2F5', + borderRadius: '30px', + width: '242px', + height: '70px', + textAlign: 'center', + align: 'center', + marginTop: '40px', + textTransform: 'none', + fontSize: '12pt', + lineHeight: '20px', + fontFamily: 'TitilliumBold' + }, + bottomIcon: { + height: '300px', + marginTop: '80px', + marginLeft: '120px' + } +})) + +export { useStyles } -- GitLab From a9434c0e74cbe7c040053323c39e90f06d76367a Mon Sep 17 00:00:00 2001 From: sbailo Date: Tue, 12 Oct 2021 12:44:40 +0200 Subject: [PATCH 23/68] Use external style file for landing page Separate landing and list styles --- gui/src/components/aitoolkit/AIToolkitPage.js | 67 +----------------- .../components/aitoolkit/AccordionsList.js | 8 ++- gui/src/components/aitoolkit/TutorialsPage.js | 4 +- gui/src/components/aitoolkit/styles.js | 68 ++++++++++++++++++- 4 files changed, 75 insertions(+), 72 deletions(-) diff --git a/gui/src/components/aitoolkit/AIToolkitPage.js b/gui/src/components/aitoolkit/AIToolkitPage.js index 59f8e49c5..6a62fdace 100644 --- a/gui/src/components/aitoolkit/AIToolkitPage.js +++ b/gui/src/components/aitoolkit/AIToolkitPage.js @@ -16,76 +16,15 @@ * limitations under the License. */ import React from 'react' -import { makeStyles, Grid, Box } from '@material-ui/core' -import Background from './assets/AIT_bg_title.jpg' +import { Grid, Box } from '@material-ui/core' import IconQuery from './assets/AIT_ico_bb_query.svg' import IconReplicate from './assets/AIT_ico_bb_replicate.svg' import IconTutorial from './assets/AIT_ico_bb_tutorial.svg' import IconWork from './assets/AIT_ico_bb_work.svg' - -const useStyles = makeStyles(theme => ({ - root: { - width: '100%', - maxWidth: 'auto', - backgroundImage: `url(${Background})`, - color: 'white', - height: '1000px' - }, - boxIcons: { - width: '1000px', - margin: 'auto', - marginTop: '-200px' - }, - title: { - fontSize: '50px', - margin: 'auto', - textAlign: 'center', - align: 'center', - marginTop: '200px', - width: '450px', - height: '140px', - fontFamily: 'TitilliumBold', - letterSpacing: 0, - wordSpacing: '10px', - lineHeight: '60px', - color: 'white' - }, - deck: { - fontFamily: 'TitilliumRegular', - letterSpacing: 0, - marginTop: '-200px', - wordSpacing: '5px', - lineHeight: '30px', - color: 'white', - fontSize: '30px', - margin: 'auto', - textAlign: 'center', - align: 'center', - left: '736px', - top: '270px', - width: '500px', - height: '140px' - }, - button: { - backgroundColor: 'white', - fontSize: 20, - fontFamily: 'TitilliumBold', - color: '#2A3C67', - textAlign: 'center', - align: 'center', - borderRadius: '25px', - width: '200px', - height: '70px', - lineHeight: '20px' - - }, - link: { - cursor: 'pointer' - } -})) +import {useStylesLanding} from './styles.js' export default function AIToolkitPage() { - const classes = useStyles() + const classes = useStylesLanding() return diff --git a/gui/src/components/aitoolkit/AccordionsList.js b/gui/src/components/aitoolkit/AccordionsList.js index a142b454b..6c7516b58 100644 --- a/gui/src/components/aitoolkit/AccordionsList.js +++ b/gui/src/components/aitoolkit/AccordionsList.js @@ -1,5 +1,5 @@ import React from 'react' -import {useStyles} from './styles.js' +import {useStylesList} from './styles.js' import { Divider, Typography, Link, AccordionActions, Button, Grid } from '@material-ui/core' import MuiAccordion from '@material-ui/core/Accordion' import MuiAccordionSummary from '@material-ui/core/AccordionSummary' @@ -38,7 +38,9 @@ const AccordionSummary = styled((props) => ( transform: 'rotate(90deg)' }, '& .MuiAccordionSummary-content': { - marginLeft: theme.spacing(1) + marginLeft: theme.spacing(1), + marginTop: '20px', + marginBottom: '20px' } })) @@ -47,7 +49,7 @@ const AccordionDetails = styled(MuiAccordionDetails)(({ theme }) => ({ })) function AccordionsList(props) { - const classes = useStyles() + const classes = useStylesList() const [expanded, setExpanded] = useQueryParam('expanded', StringParam) return ( props.tutorials_list.map(tutorial => ( diff --git a/gui/src/components/aitoolkit/TutorialsPage.js b/gui/src/components/aitoolkit/TutorialsPage.js index 65900d3f8..85b212878 100644 --- a/gui/src/components/aitoolkit/TutorialsPage.js +++ b/gui/src/components/aitoolkit/TutorialsPage.js @@ -16,7 +16,7 @@ * limitations under the License. */ import React, { useMemo } from 'react' -import {useStyles} from './styles.js' +import {useStylesList} from './styles.js' import { Box, Button, Grid, TextField, Divider } from '@material-ui/core' import tutorials from '../../toolkitMetadata' import { StringParam, useQueryParams } from 'use-query-params' @@ -27,7 +27,7 @@ import ReproduceIcon from './assets/AIT_ico_bb_replicate.svg' import AccordionsList from './AccordionsList' export default function AIToolkitPage() { - const classes = useStyles() + const classes = useStylesList() const [queryParameters, setQueryParameters] = useQueryParams({ author: StringParam, keyword: StringParam, method: StringParam, filterString: StringParam }) diff --git a/gui/src/components/aitoolkit/styles.js b/gui/src/components/aitoolkit/styles.js index 6c4e6c450..8b41ae3eb 100644 --- a/gui/src/components/aitoolkit/styles.js +++ b/gui/src/components/aitoolkit/styles.js @@ -1,7 +1,7 @@ - import {makeStyles} from '@material-ui/core' +import Background from './assets/AIT_bg_title.jpg' -const useStyles = makeStyles(theme => ({ +const useStylesList = makeStyles(theme => ({ root: { margin: theme.spacing(3), @@ -150,4 +150,66 @@ const useStyles = makeStyles(theme => ({ } })) -export { useStyles } +const useStylesLanding = makeStyles(theme => ({ + root: { + width: '100%', + maxWidth: 'auto', + backgroundImage: `url(${Background})`, + color: 'white', + height: '1000px' + }, + boxIcons: { + width: '1000px', + margin: 'auto', + marginTop: '-200px' + }, + title: { + fontSize: '50px', + margin: 'auto', + textAlign: 'center', + align: 'center', + marginTop: '200px', + width: '450px', + height: '140px', + fontFamily: 'TitilliumBold', + letterSpacing: 0, + wordSpacing: '10px', + lineHeight: '60px', + color: 'white' + }, + deck: { + fontFamily: 'TitilliumRegular', + letterSpacing: 0, + marginTop: '-200px', + wordSpacing: '5px', + lineHeight: '30px', + color: 'white', + fontSize: '30px', + margin: 'auto', + textAlign: 'center', + align: 'center', + left: '736px', + top: '270px', + width: '500px', + height: '140px' + }, + button: { + backgroundColor: 'white', + fontSize: 20, + fontFamily: 'TitilliumBold', + color: '#2A3C67', + textAlign: 'center', + align: 'center', + borderRadius: '25px', + width: '200px', + height: '70px', + lineHeight: '20px' + + }, + link: { + cursor: 'pointer' + } +})) + +export { useStylesList } +export { useStylesLanding } -- GitLab From 5c5b13bc0b3c9af4945b65ea2396fd20dad75873 Mon Sep 17 00:00:00 2001 From: sbailo Date: Tue, 12 Oct 2021 13:38:55 +0200 Subject: [PATCH 24/68] Customize button in landing page --- gui/src/components/aitoolkit/AIToolkitPage.js | 52 ++++++++++--------- gui/src/components/aitoolkit/styles.js | 29 ++++++----- 2 files changed, 42 insertions(+), 39 deletions(-) diff --git a/gui/src/components/aitoolkit/AIToolkitPage.js b/gui/src/components/aitoolkit/AIToolkitPage.js index 6a62fdace..36df7f597 100644 --- a/gui/src/components/aitoolkit/AIToolkitPage.js +++ b/gui/src/components/aitoolkit/AIToolkitPage.js @@ -16,12 +16,13 @@ * limitations under the License. */ import React from 'react' -import { Grid, Box } from '@material-ui/core' +import { Grid, Box, Button } from '@material-ui/core' import IconQuery from './assets/AIT_ico_bb_query.svg' import IconReplicate from './assets/AIT_ico_bb_replicate.svg' import IconTutorial from './assets/AIT_ico_bb_tutorial.svg' import IconWork from './assets/AIT_ico_bb_work.svg' import {useStylesLanding} from './styles.js' +import ArrowIcon from './assets/AIT_ico_bd_link_go_to.svg' export default function AIToolkitPage() { const classes = useStylesLanding() @@ -37,41 +38,42 @@ export default function AIToolkitPage() { Find new Patterns and Information in Materials Science Big Data
- + - + - + - + - + - + - + - + + diff --git a/gui/src/components/aitoolkit/styles.js b/gui/src/components/aitoolkit/styles.js index 8b41ae3eb..a6b38ef33 100644 --- a/gui/src/components/aitoolkit/styles.js +++ b/gui/src/components/aitoolkit/styles.js @@ -161,50 +161,51 @@ const useStylesLanding = makeStyles(theme => ({ boxIcons: { width: '1000px', margin: 'auto', - marginTop: '-200px' + marginTop: '-350px' }, title: { - fontSize: '50px', + fontSize: '55px', margin: 'auto', textAlign: 'center', align: 'center', - marginTop: '200px', + marginTop: '100px', width: '450px', height: '140px', fontFamily: 'TitilliumBold', letterSpacing: 0, - wordSpacing: '10px', - lineHeight: '60px', + lineHeight: '62px', color: 'white' }, deck: { fontFamily: 'TitilliumRegular', letterSpacing: 0, - marginTop: '-200px', + marginTop: '-250px', wordSpacing: '5px', - lineHeight: '30px', + lineHeight: '43px', color: 'white', - fontSize: '30px', + fontSize: '34px', margin: 'auto', textAlign: 'center', align: 'center', left: '736px', top: '270px', - width: '500px', + width: '550px', height: '140px' }, button: { backgroundColor: 'white', - fontSize: 20, + fontSize: '20px', + lineHeight: '20px', fontFamily: 'TitilliumBold', color: '#2A3C67', textAlign: 'center', align: 'center', - borderRadius: '25px', - width: '200px', + borderRadius: '30px', + width: '207px', height: '70px', - lineHeight: '20px' - + textTransform: 'none', + marginTop: '-50px', + zIndex: 0 }, link: { cursor: 'pointer' -- GitLab From 2127b1b64b84b0d777967928621956a8e38e525c Mon Sep 17 00:00:00 2001 From: sbailo Date: Tue, 12 Oct 2021 17:00:31 +0200 Subject: [PATCH 25/68] Add logo and text to landing page --- gui/src/components/aitoolkit/AIToolkitPage.js | 92 +++++++++++-------- gui/src/components/aitoolkit/styles.js | 39 ++++++-- 2 files changed, 85 insertions(+), 46 deletions(-) diff --git a/gui/src/components/aitoolkit/AIToolkitPage.js b/gui/src/components/aitoolkit/AIToolkitPage.js index 36df7f597..230076bbb 100644 --- a/gui/src/components/aitoolkit/AIToolkitPage.js +++ b/gui/src/components/aitoolkit/AIToolkitPage.js @@ -16,65 +16,79 @@ * limitations under the License. */ import React from 'react' -import { Grid, Box, Button } from '@material-ui/core' +import { Grid, Box, Button, Typography } from '@material-ui/core' import IconQuery from './assets/AIT_ico_bb_query.svg' import IconReplicate from './assets/AIT_ico_bb_replicate.svg' import IconTutorial from './assets/AIT_ico_bb_tutorial.svg' import IconWork from './assets/AIT_ico_bb_work.svg' import {useStylesLanding} from './styles.js' import ArrowIcon from './assets/AIT_ico_bd_link_go_to.svg' +import FigureAI from './assets/AIT_illu_AIT.svg' +import ReactPlayer from 'react-player/youtube' export default function AIToolkitPage() { const classes = useStylesLanding() return - - - + + + Powerful Tools for Materials Science - - - - Find new Patterns and Information in Materials Science Big Data - - - - - - - - + + + Find new Patterns and Information in Materials Science Big Data - - - - - + + + - - - + + + - - - + + + + + + + + + + + What is the NOMAD Artificial Intelligence Toolkit? + The preparation, synthesis, and characterization of new materials is a complex and costly aspect of materials design. The number of possible materials is practically infinite, about 200,000 materials are “known” to exist. But the basic properties (e.g., optical gap, elasticity constants, plasticity, piezoelectric tensors, conductivity, etc.) have been determined for very few of them. NOMAD develops and provides a big set of tools- the Artificial Intelligence Toolkit - using the latest machine learning and artificial intelligence approaches that make it possible to sort all available material data, to identify correlations and structures, and to detect trends and anomalies. Thus, the Artificial Intelligence Toolkit enables scientists and engineers to decide which materials are useful for specific applications or which new materials should be the focus of future studies. + + + + + } diff --git a/gui/src/components/aitoolkit/styles.js b/gui/src/components/aitoolkit/styles.js index a6b38ef33..d837eb4d3 100644 --- a/gui/src/components/aitoolkit/styles.js +++ b/gui/src/components/aitoolkit/styles.js @@ -152,16 +152,21 @@ const useStylesList = makeStyles(theme => ({ const useStylesLanding = makeStyles(theme => ({ root: { + margin: theme.spacing(3), width: '100%', - maxWidth: 'auto', + marginLeft: 'auto', + marginRight: 'auto', + maxWidth: '1920px' + }, + background: { backgroundImage: `url(${Background})`, - color: 'white', - height: '1000px' + height: '840px', + marginTop: '-50px' }, boxIcons: { width: '1000px', margin: 'auto', - marginTop: '-350px' + marginTop: '-150px' }, title: { fontSize: '55px', @@ -179,7 +184,7 @@ const useStylesLanding = makeStyles(theme => ({ deck: { fontFamily: 'TitilliumRegular', letterSpacing: 0, - marginTop: '-250px', + marginTop: '-170px', wordSpacing: '5px', lineHeight: '43px', color: 'white', @@ -207,8 +212,28 @@ const useStylesLanding = makeStyles(theme => ({ marginTop: '-50px', zIndex: 0 }, - link: { - cursor: 'pointer' + body: { + width: '1052px', + margin: theme.spacing(3), + marginLeft: 'auto', + marginRight: 'auto' + }, + highlightedText: { + fontWeight: 'bold', + color: 'rgba(127, 239, 239, 1)', + fontSize: '35px', + width: '518px', + lineHeight: '42px', + fontFamily: 'TitilliumRegular', + marginTop: '80px' + }, + bodyText: { + color: '#2A3C67', + fontFamily: 'TitilliumRegular', + lineHeight: '30px', + fontSize: '22px', + width: '607px', + marginTop: '40px' } })) -- GitLab From 381853ce9cc94de8be048c829a54c2e561193ea9 Mon Sep 17 00:00:00 2001 From: sbailo Date: Tue, 12 Oct 2021 20:10:32 +0200 Subject: [PATCH 26/68] Add buttons at the bottom of landing page --- gui/src/components/aitoolkit/AIToolkitPage.js | 63 +++++- .../aitoolkit/assets/AIT_ico_bp_query.svg | 1 + .../aitoolkit/assets/AIT_ico_bp_replicate.svg | 1 + .../aitoolkit/assets/AIT_ico_bp_work.svg | 1 + gui/src/components/aitoolkit/styles.js | 195 ++++++++++-------- 5 files changed, 167 insertions(+), 94 deletions(-) create mode 100644 gui/src/components/aitoolkit/assets/AIT_ico_bp_query.svg create mode 100644 gui/src/components/aitoolkit/assets/AIT_ico_bp_replicate.svg create mode 100644 gui/src/components/aitoolkit/assets/AIT_ico_bp_work.svg diff --git a/gui/src/components/aitoolkit/AIToolkitPage.js b/gui/src/components/aitoolkit/AIToolkitPage.js index 230076bbb..13ba11d25 100644 --- a/gui/src/components/aitoolkit/AIToolkitPage.js +++ b/gui/src/components/aitoolkit/AIToolkitPage.js @@ -1,3 +1,4 @@ +/* eslint-disable react/no-unescaped-entities */ /* * Copyright The NOMAD Authors. * @@ -21,10 +22,15 @@ import IconQuery from './assets/AIT_ico_bb_query.svg' import IconReplicate from './assets/AIT_ico_bb_replicate.svg' import IconTutorial from './assets/AIT_ico_bb_tutorial.svg' import IconWork from './assets/AIT_ico_bb_work.svg' +import IconQuery2 from './assets/AIT_ico_bp_query.svg' +import IconReplicate2 from './assets/AIT_ico_bp_replicate.svg' +import IconTutorial2 from './assets/AIT_ico_bp_tutorial.svg' +import IconWork2 from './assets/AIT_ico_bp_work.svg' import {useStylesLanding} from './styles.js' import ArrowIcon from './assets/AIT_ico_bd_link_go_to.svg' import FigureAI from './assets/AIT_illu_AIT.svg' -import ReactPlayer from 'react-player/youtube' + +// import ReactPlayer from 'react-player/youtube' export default function AIToolkitPage() { const classes = useStylesLanding() @@ -49,28 +55,28 @@ export default function AIToolkitPage() { - - - - + + + + + + + + + + + } diff --git a/gui/src/components/aitoolkit/assets/AIT_ico_bp_query.svg b/gui/src/components/aitoolkit/assets/AIT_ico_bp_query.svg new file mode 100644 index 000000000..474547487 --- /dev/null +++ b/gui/src/components/aitoolkit/assets/AIT_ico_bp_query.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/gui/src/components/aitoolkit/assets/AIT_ico_bp_replicate.svg b/gui/src/components/aitoolkit/assets/AIT_ico_bp_replicate.svg new file mode 100644 index 000000000..0a1f1075e --- /dev/null +++ b/gui/src/components/aitoolkit/assets/AIT_ico_bp_replicate.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/gui/src/components/aitoolkit/assets/AIT_ico_bp_work.svg b/gui/src/components/aitoolkit/assets/AIT_ico_bp_work.svg new file mode 100644 index 000000000..8ef95da19 --- /dev/null +++ b/gui/src/components/aitoolkit/assets/AIT_ico_bp_work.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/gui/src/components/aitoolkit/styles.js b/gui/src/components/aitoolkit/styles.js index d837eb4d3..24a35d141 100644 --- a/gui/src/components/aitoolkit/styles.js +++ b/gui/src/components/aitoolkit/styles.js @@ -1,6 +1,114 @@ import {makeStyles} from '@material-ui/core' import Background from './assets/AIT_bg_title.jpg' +const useStylesLanding = makeStyles(theme => ({ + root: { + margin: theme.spacing(3), + width: '100%', + marginLeft: 'auto', + marginRight: 'auto', + maxWidth: '1920px' + }, + background: { + backgroundImage: `url(${Background})`, + height: '840px', + marginTop: '-50px' + }, + boxIcons: { + width: '1000px', + margin: 'auto', + marginTop: '-150px' + }, + title: { + fontSize: '55px', + margin: 'auto', + textAlign: 'center', + align: 'center', + marginTop: '100px', + width: '450px', + height: '140px', + fontFamily: 'TitilliumBold', + letterSpacing: 0, + lineHeight: '62px', + color: 'white' + }, + deck: { + fontFamily: 'TitilliumRegular', + letterSpacing: 0, + marginTop: '-170px', + wordSpacing: '5px', + lineHeight: '43px', + color: 'white', + fontSize: '34px', + margin: 'auto', + textAlign: 'center', + align: 'center', + left: '736px', + top: '270px', + width: '550px', + height: '140px' + }, + button: { + backgroundColor: 'rgba(255,255,255,1)', + fontSize: '20px', + lineHeight: '20px', + fontFamily: 'TitilliumBold', + color: '#2A3C67', + textAlign: 'center', + align: 'center', + borderRadius: '30px', + width: '207px', + height: '70px', + textTransform: 'none', + marginTop: '-50px', + zIndex: 0 + }, + body: { + width: '1052px', + margin: theme.spacing(3), + marginLeft: 'auto', + marginRight: 'auto' + }, + highlightedText: { + fontWeight: 'bold', + color: 'rgba(127, 239, 239, 1)', + fontSize: '35px', + width: '518px', + lineHeight: '42px', + fontFamily: 'TitilliumRegular', + marginTop: '80px' + }, + bodyText: { + color: '#2A3C67', + fontFamily: 'TitilliumRegular', + lineHeight: '30px', + fontSize: '22px', + width: '607px', + marginTop: '40px' + }, + boxIconsBottom: { + width: '1000px', + margin: 'auto', + marginTop: '50px' + }, + buttonBottom: { + backgroundColor: '#F3F2F5', + fontSize: '20px', + lineHeight: '20px', + fontFamily: 'TitilliumBold', + color: '#2A3C67', + textAlign: 'center', + align: 'center', + borderRadius: '30px', + width: '207px', + height: '70px', + textTransform: 'none' + }, + iconsBottom: { + width: '200px' + } +})) + const useStylesList = makeStyles(theme => ({ root: { @@ -150,92 +258,5 @@ const useStylesList = makeStyles(theme => ({ } })) -const useStylesLanding = makeStyles(theme => ({ - root: { - margin: theme.spacing(3), - width: '100%', - marginLeft: 'auto', - marginRight: 'auto', - maxWidth: '1920px' - }, - background: { - backgroundImage: `url(${Background})`, - height: '840px', - marginTop: '-50px' - }, - boxIcons: { - width: '1000px', - margin: 'auto', - marginTop: '-150px' - }, - title: { - fontSize: '55px', - margin: 'auto', - textAlign: 'center', - align: 'center', - marginTop: '100px', - width: '450px', - height: '140px', - fontFamily: 'TitilliumBold', - letterSpacing: 0, - lineHeight: '62px', - color: 'white' - }, - deck: { - fontFamily: 'TitilliumRegular', - letterSpacing: 0, - marginTop: '-170px', - wordSpacing: '5px', - lineHeight: '43px', - color: 'white', - fontSize: '34px', - margin: 'auto', - textAlign: 'center', - align: 'center', - left: '736px', - top: '270px', - width: '550px', - height: '140px' - }, - button: { - backgroundColor: 'white', - fontSize: '20px', - lineHeight: '20px', - fontFamily: 'TitilliumBold', - color: '#2A3C67', - textAlign: 'center', - align: 'center', - borderRadius: '30px', - width: '207px', - height: '70px', - textTransform: 'none', - marginTop: '-50px', - zIndex: 0 - }, - body: { - width: '1052px', - margin: theme.spacing(3), - marginLeft: 'auto', - marginRight: 'auto' - }, - highlightedText: { - fontWeight: 'bold', - color: 'rgba(127, 239, 239, 1)', - fontSize: '35px', - width: '518px', - lineHeight: '42px', - fontFamily: 'TitilliumRegular', - marginTop: '80px' - }, - bodyText: { - color: '#2A3C67', - fontFamily: 'TitilliumRegular', - lineHeight: '30px', - fontSize: '22px', - width: '607px', - marginTop: '40px' - } -})) - export { useStylesList } export { useStylesLanding } -- GitLab From 876081ca5055e30672069c8ef1a5f5e3d16e0d71 Mon Sep 17 00:00:00 2001 From: sbailo Date: Tue, 12 Oct 2021 20:46:12 +0200 Subject: [PATCH 27/68] Adapt reproduce page --- gui/src/components/aitoolkit/ReproducePage.js | 355 ++++++------------ 1 file changed, 121 insertions(+), 234 deletions(-) diff --git a/gui/src/components/aitoolkit/ReproducePage.js b/gui/src/components/aitoolkit/ReproducePage.js index f51dba107..2e6aac0bf 100644 --- a/gui/src/components/aitoolkit/ReproducePage.js +++ b/gui/src/components/aitoolkit/ReproducePage.js @@ -15,55 +15,20 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + import React, { useMemo } from 'react' -import { Divider, Typography, AccordionDetails, makeStyles, Link, AccordionActions, Button, Grid, TextField } from '@material-ui/core' -import MUIAccordion from '@material-ui/core/Accordion' -import MUIAccordionSummary from '@material-ui/core/AccordionSummary' -import { withStyles } from '@material-ui/core/styles' +import {useStylesList} from './styles.js' +import { Box, Button, Grid, TextField, Divider } from '@material-ui/core' import tutorials from '../../toolkitMetadata' -import ExpandMoreIcon from '@material-ui/icons/ExpandMore' -import Markdown from '../Markdown' -import { StringParam, useQueryParams, useQueryParam } from 'use-query-params' +import { StringParam, useQueryParams } from 'use-query-params' import Autocomplete from '@material-ui/lab/Autocomplete' - -const useStyles = makeStyles(theme => ({ - root: { - margin: theme.spacing(3), - width: '100%', - marginLeft: 'auto', - marginRight: 'auto', - maxWidth: 1024 - }, - section: { - marginTop: theme.spacing(3) - }, - sectionTitle: { - marginBottom: theme.spacing(1), - marginLeft: theme.spacing(2) - }, - tutorial: { - - }, - tutorialTitle: { - fontWeight: 'bold' - }, - tutorialDetails: { - flexDirection: 'column', - '& *': { - marginTop: theme.spacing(1) - }, - '& :first-child': { - marginTop: -theme.spacing(2) - } - }, - link: { - cursor: 'pointer' - } -})) +import TutorialsIcon from './assets/AIT_ico_bb_tutorial.svg' +import ArrowIcon from './assets/AIT_ico_bd_link_go_to.svg' +import ReproduceIcon from './assets/AIT_ico_bp_replicate.svg' +import AccordionsList from './AccordionsList' export default function AIToolkitPage() { - const classes = useStyles() - const [expanded, setExpanded] = useQueryParam('expanded', StringParam) + const classes = useStylesList() const [queryParameters, setQueryParameters] = useQueryParams({ author: StringParam, keyword: StringParam, method: StringParam, filterString: StringParam }) @@ -88,209 +53,131 @@ export default function AIToolkitPage() { return true } - const {sections, authors, keywords, methods} = useMemo(() => { + const tutorials_list_advanced = tutorials.tutorials.filter(tutorial => tutorial.labels.category[0] === 'advanced_tutorial') + + const {authors, keywords, methods} = useMemo(() => { const authors = {} const keywords = {} const methods = {} - const sectionMap = tutorials.tutorials.reduce((sections, tutorial) => { - tutorial.labels.application_section.forEach(sectionTitle => { - sections[sectionTitle] = sections[sectionTitle] || {title: sectionTitle, tutorials: []} - tutorial.key = tutorial.title.replace(/\W/gm, '_').toLowerCase() - sections[sectionTitle].tutorials.push(tutorial) - tutorial.authors.forEach(i => { authors[i] = i }) - tutorial.labels.application_keyword.forEach(i => { keywords[i] = i }) - tutorial.labels.data_analytics_method.forEach(i => { methods[i] = i }) - }) - return sections - }, {}) + tutorials_list_advanced.forEach(tutorial => { + tutorial.key = tutorial.title.replace(/\W/gm, '_').toLowerCase() + tutorial.authors.forEach(i => { authors[i] = i }) + tutorial.labels.application_keyword.forEach(i => { keywords[i] = i }) + tutorial.labels.data_analytics_method.forEach(i => { methods[i] = i }) + } + ) return { - sections: Object.keys(sectionMap).map(key => sectionMap[key]).sort((a, b) => a.title.localeCompare(b.title)), authors: Object.keys(authors).sort(), keywords: Object.keys(keywords).sort(), methods: Object.keys(methods).sort() } - }, []) - - const Accordion = withStyles({ - root: { - border: '5px solid rgba(127, 239, 239, 1)', - scrollbarGutter: 'false', - marginLeft: '100px', - boxShadow: '0 3px 5px 2px rgba(127, 239, 239, 0.5)', - borderRadius: '10px 10px 10px 10px', - '&:not(:last-child)': { - borderBottom: 0 - }, - '&:before': { - display: 'none' - }, - '&$expanded': { - margin: 'auto' - } - }, - heading: { - fontSize: 35, - flexBasis: '33.33%', - flexShrink: 0 - }, - secondaryHeading: { - fontSize: 10 - }, - expanded: {} - })(MUIAccordion) + }, [tutorials_list_advanced]) - const AccordionSummary = withStyles({ - root: { - flexDirection: 'column' - }, - content: { - marginBottom: 0, - flexGrow: 1 - }, - expandIcon: { - marginRight: '10px', - paddingTop: '10px' - } - })(MUIAccordionSummary) - - return - - {` - # Reproduce published results - - We develop and implement methods that identify correlations and structure in big data - of materials. This will enable scientists and engineers to decide which materials are - useful for specific applications or which new materials should be the focus of future studies. - The following tutorials are designed to get started with the AI Toolkit. - - To log in directly, click [here](https://analytics-toolkit.nomad-coe.eu/hub). - `} + return + + + + { + 'Reproduce published results' + } + + + { + 'We develop and implement methods that identify correlations and structure in big data of materials. This will enable scientists and engineers to decide which materials are useful for specific applications or which new materials should be the focus of future studies. The following tutorials are designed to reproduce result published in scientific journals.' + } + + + + + - - {
} - {sections.map(section => ( -
- {/* {section.title} */} -
- {section.tutorials.map(tutorial => { - // - const key = tutorial.key - return setExpanded(expanded === key ? null : key)} - className={classes.tutorial} - > - }> - {tutorial.title} - - - - - {tutorial.authors - .map(name => { - const label = name.split(',').reverse().join(' ') - return setQueryParameters({ - ...emptyQuery, - author: queryParameters.author === name ? null : name - })} - > - {label} - - }).reduce((prev, curr) => [prev, ', ', curr]) - } - - - {tutorial.description} - - - keywords: {tutorial.labels.application_keyword - .map(keyword => ( - setQueryParameters({ - ...emptyQuery, - keyword: queryParameters.keyword === keyword ? null : keyword - })} - > - {keyword} - - )).reduce((prev, curr) => [prev, ', ', curr]) - } - - - method: {tutorial.labels.data_analytics_method - .map(method => ( - setQueryParameters({ - ...emptyQuery, - method: queryParameters.method === method ? null : method - })} - > - {method} - - )).reduce((prev, curr) => [prev, ', ', curr]) - } - - - - - - - - - })} + + + + { + 'Filter Tutorials' + } + + + + option} + style={{height: '50px', width: '150px'}} + renderInput={params => ( + + )} + value={queryParameters.author} + onChange={(_, value) => setQueryParameters({...emptyQuery, author: value})} + /> + + + option} + renderInput={params => ( + + )} + value={queryParameters.keyword} + onChange={(_, value) => setQueryParameters({...emptyQuery, keyword: value})} + /> + + + ( + + )} + value={queryParameters.method} + onChange={(_, value) => setQueryParameters({...emptyQuery, method: value})} + /> + + + -
+ + + + + + -
- ))}
- - option} - style={{ width: '100%', marginBottom: 8 }} - renderInput={params => ( - - )} - value={queryParameters.author} - onChange={(_, value) => setQueryParameters({...emptyQuery, author: value})} - /> - option} - style={{ width: '100%', marginBottom: 8 }} - renderInput={params => ( - - )} - value={queryParameters.keyword} - onChange={(_, value) => setQueryParameters({...emptyQuery, keyword: value})} - /> - ( - - )} - value={queryParameters.method} - onChange={(_, value) => setQueryParameters({...emptyQuery, method: value})} - /> - {/* */} + + + { + 'Explore the basics of AI' + } + + + { + 'Recent applications of artificial-intelligence in science build on top of solid methodologies, that have been developing over last decades. You can learn the basics of AI to better understand its latest applications in materials science.' + } + + + + + + } -- GitLab From d50f4782e99ac4ea3e7b1b68bfd260b06cb4df64 Mon Sep 17 00:00:00 2001 From: sbailo Date: Tue, 12 Oct 2021 21:01:32 +0200 Subject: [PATCH 28/68] Update toolkit metadata --- gui/src/toolkitMetadata.json | 660 +++++++++++++++++++++++++++++------ 1 file changed, 554 insertions(+), 106 deletions(-) diff --git a/gui/src/toolkitMetadata.json b/gui/src/toolkitMetadata.json index b25582e65..50e492c86 100644 --- a/gui/src/toolkitMetadata.json +++ b/gui/src/toolkitMetadata.json @@ -1,10 +1,141 @@ { "tutorials": [ + { + "authors": [ + "Sbail\u00f2, Luigi", + "Ghiringhelli, Luca M." + ], + "email": "sbailo@fhi-berlin.mpg.de", + "title": "Introduction to clustering", + "description": "In this tutorial we introduce to the most popular clustering algorithms. We focus on partitioning, hierarchical and density-based clustering algorithms, and methods are tested on artificial datasets of increasing complexity", + "url": "https://gitlab.mpcdf.mpg.de/nomad-lab/analytics-clustering-tutorial", + "link": "https://analytics-toolkit.nomad-coe.eu/hub/user-redirect/notebooks/tutorials/clustering_tutorial.ipynb", + "link_public": "https://analytics-toolkit.nomad-coe.eu/public/user-redirect/notebooks/tutorials/clustering_tutorial.ipynb", + "updated": "2020-12-2", + "flags": { + "featured": true, + "top_of_list": false + }, + "labels": { + "application_keyword": [ + "k-means", + "Hierarchical clustering", + "DBSCAN", + "HDBSCAN" + ], + "application_section": [ + "Tutorials for artificial-intelligence methods" + ], + "application_system": [ + "Artificial dataset" + ], + "category": [ + "beginner_tutorial" + ], + "data_analytics_method": [ + "Clustering" + ], + "platform": [ + "jupyter" + ] + } + }, + { + "authors": [ + "Sbailò, Luigi", + "Ghiringhelli, Luca M." + ], + "email": "sbailo@fhi-berlin.mpg.de", + "title": "Exploratory analysis of octet-binary compounds ", + "description": "Exploratory analyses make use of unsupervised learning techniques to extract information from unknown datasets. In this tutorial, we make use of some of the most popular clustering and dimension reduction algorithms to analyze a dataset composed of 82 octet-binary compounds.", + "url": "https://gitlab.mpcdf.mpg.de/nomad-lab/analytics-exploratory-analysis", + "link": "https://analytics-toolkit.nomad-coe.eu/hub/user-redirect/notebooks/tutorials/exploratory_analysis.ipynb", + "link_public": "https://analytics-toolkit.nomad-coe.eu/public/user-redirect/notebooks/tutorials/exploratory_analysis.ipynb", + "link_video": "https://www.youtube.com/watch?v=EJTjF9ehp7k", + "updated": "2021-01-11", + "flags":{ + "featured": true, + "top_of_list": false, + "video": true + }, + "labels": { + "application_keyword": [ + "k-means", + "Hierarchical clustering", + "DBSCAN", + "HDBSCAN", + "DenPeak", + "PCA", + "t-SNE", + "MDS", + "Octet binaries" + ], + "application_section": [ + "Tutorials for artificial-intelligence methods" + ], + "application_system": [ + "octet-binary materials" + ], + "category": [ + "beginner_tutorial" + ], + "data_analytics_method": [ + "Clustering", + "Dimension reduction" + ], + "platform": [ + "jupyter" + ] + } + }, { + "authors": [ + "Speckhard, Daniel", + "Leitherer, Andreas", + "Ghiringhelli, Luca M." + ], + "email": "speckhard@fhi-berlin.mpg.de", + "title": "Decision tree tutorial", + "description": "In this tutorial we will introduce decision trees. We go through a toy model introducing the SKLearn API. We then discuss piece by piece the different theoretical aspects of trees. We then move to training a regression tree and classification tree on different datasets related to materials sceience. We end the tutorial by covering random forests and bagging classfifers.", + "url": "https://gitlab.mpcdf.mpg.de/nomad-lab/analytics-decision-tree", + "link": "https://analytics-toolkit.nomad-coe.eu/hub/user-redirect/notebooks/tutorials/decision_tree.ipynb", + "link_public": "https://analytics-toolkit.nomad-coe.eu/public/user-redirect/notebooks/tutorials/decision_tree.ipynb", + "link_video" : "https://www.youtube.com/watch?v=YBy9STVaqvU", + "updated": "2020-12-08", + "flags": { + "featured": true, + "top_of_list": false, + "video": true + }, + "labels": { + "application_keyword": [ + "Images" + ], + "application_section": [ + "Tutorials for artificial-intelligence methods" + ], + "application_system": [ + "Imates" + ], + "category": [ + "beginner_tutorial" + ], + "data_analytics_method": [ + "Decison tree", + "Random forest", + "Bagging classifier" + ], + "platform": [ + "jupyter" + ] + } + }, + { "authors": [ "Ahmetcik, Emre", "Ziletti, Angelo", "Ouyang, Runhai", + "Luigi Sbail\u00f2", "Scheffler, Matthias", "Ghiringhelli, Luca M." ], @@ -14,10 +145,14 @@ "url": "https://gitlab.mpcdf.mpg.de/nomad-lab/analytics-compressed-sensing", "link": "https://analytics-toolkit.nomad-coe.eu/hub/user-redirect/notebooks/tutorials/compressed_sensing.ipynb", "link_public": "https://analytics-toolkit.nomad-coe.eu/public/user-redirect/notebooks/tutorials/compressed_sensing.ipynb", - "updated": "2019-04-05", + "link_video": "https://www.youtube.com/watch?v=73mLp6C2opY", + "link_paper": "https://th.fhi-berlin.mpg.de/site/uploads/Publications/NJP-19-023017-2017.pdf", + "updated": "2020-12-8", "flags": { "featured": true, - "top_of_list": false + "top_of_list": false, + "video": true, + "paper": true }, "labels": { "application_keyword": [ @@ -32,7 +167,7 @@ "Octet binary materials" ], "category": [ - "Tutorial" + "intermediate_utorial" ], "data_analytics_method": [ "LASSO", @@ -46,47 +181,78 @@ }, { "authors": [ - "Liu, Xiangyue", - "Sutton, Christopher", - "Yamamoto, Takenori", - "Lysogorskiy, Yury", - "Blumenthal, Lars", - "Hammerschmidt, Thomas", - "Golebiowski, Jacek", - "Ziletti, Angelo", - "Scheffler, Matthias", - "Ghiringhelli, Luca M." + "Langer, Marcel F." ], - "email": "ghiringhelli@fhi-berlin.mpg.de", - "title": "NOMAD 2018 Kaggle research competition", - "description": "In this tutorial, we will explore the best results of the NOMAD 2018 Kaggle research competition. The goal of this competition was to develop machine-learning models for the prediction of two target properties: the formation energy and the bandgap energy of transparent semiconducting oxides. The purpose of the modelling is to facilitate the discovery of new such materials and allow for advancements in (opto)electronic technologies", - "url": "https://gitlab.mpcdf.mpg.de/nomad-lab/analytics-kaggle-competition", - "link": "https://analytics-toolkit.nomad-coe.eu/hub/user-redirect/notebooks/tutorials/kaggle_competition.ipynb", - "link_public": "https://analytics-toolkit.nomad-coe.eu/public/user-redirect/notebooks/tutorials/kaggle_competition.ipynb", - "updated": "2020-02-06", + "email": "langer@fhi-berlin.mpg.de", + "title": "Kernel Ridge Regression for Materials Property Prediction: A Tutorial Introduction", + "description": "In this tutorial, we'll explore the application of kernel ridge regression to the prediction of materials properties. We will begin with a largely informal, pragmatic introduction to kernel ridge regression, including a rudimentary implementation, in order to become familiar with the basic terminology and considerations. We will then discuss representations, and re-trace the NOMAD 2018 Kaggle challenge.", + "url": "https://gitlab.mpcdf.mpg.de/nomad-lab/analytics-krr4mat", + "link": "https://analytics-toolkit.nomad-coe.eu/hub/user-redirect/notebooks/tutorials/krr4mat.ipynb", + "link_public": "https://analytics-toolkit.nomad-coe.eu/public/user-redirect/notebooks/tutorials/krr4mat.ipynb", + "link_video": "https://www.youtube.com/watch?v=H_MVlljpYHw", + "updated": "2020-10-30", "flags": { "featured": true, - "top_of_list": false + "top_of_list": false, + "video": true }, "labels": { "application_keyword": [ - "Formation energy prediction", - "Band gap energy prediction" + "Formation energy prediction" ], "application_section": [ - "Timely artificial-intelligence applications to Materials Science" + "Tutorials for artificial-intelligence methods" ], "application_system": [ - "Group-III oxidess" + "Group-III oxides" ], "category": [ - "Tutorial" + "beginner_tutorial" + ], + "data_analytics_method": [ + "Kernel ridge regression", + "SOAP" + ], + "platform": [ + "jupyter" + ] + } + }, + { + "authors": [ + "Langer, Marcel F." + ], + "email": "langer@fhi-berlin.mpg.de", + "title": "cmlkit: Toolkit for Machine Learning in Computational Condensed Matter Physics and Quantum Chemistry", + "description": "In this tutorial we will get to know cmlkit, a python package for specifying, evaluating, and optimising machine learning models, and use it to compete in the Nomad 2018 Kaggle challenge.", + "url": "https://gitlab.mpcdf.mpg.de/nomad-lab/analytics-cmlkit", + "link": "https://analytics-toolkit.nomad-coe.eu/hub/user-redirect/notebooks/tutorials/cmlkit.ipynb", + "link_public": "https://analytics-toolkit.nomad-coe.eu/public/user-redirect/notebooks/tutorials/cmlkit.ipynb", + "link_paper": "https://arxiv.org/abs/2003.12081", + "updated": "2020-03-26", + "flags": { + "featured": true, + "top_of_list": false, + "paper": true + }, + "labels": { + "application_keyword": [ + "Formation energy prediction" + ], + "application_section": [ + "Tutorials for artificial-intelligence methods" + ], + "application_system": [ + "Group-III oxides" + ], + "category": [ + "intermediate_tutorial" ], "data_analytics_method": [ "Kernel ridge regression", - "Neural networks", "SOAP", - "n-gram" + "MBTR", + "Symmetry Functions" ], "platform": [ "jupyter" @@ -105,10 +271,12 @@ "url": "https://gitlab.mpcdf.mpg.de/nomad-lab/analytics-convolutional-nn", "link": "https://analytics-toolkit.nomad-coe.eu/hub/user-redirect/notebooks/tutorials/convolutional_nn.ipynb", "link_public": "https://analytics-toolkit.nomad-coe.eu/public/user-redirect/notebooks/tutorials/convolutional_nn.ipynb", + "link_video": "https://youtu.be/MST8X1yCWK8", "updated": "2019-04-01", "flags": { "featured": true, - "top_of_list": false + "top_of_list": false, + "video": true }, "labels": { "application_keyword": [ @@ -122,7 +290,7 @@ "Images" ], "category": [ - "Tutorial" + "intermediate_tutorial" ], "data_analytics_method": [ "Convolutional Neural networks", @@ -133,6 +301,54 @@ ] } }, + { + "authors": [ + "Regler, Benjamin", + "Scheffler, Matthias", + "Ghiringhelli, Luca M." + ], + "email": "regler@fhi-berlin.mpg.de", + "title": "Total cumulative mutual information", + "description": "This interactive notebook includes the original implementation of total cumulative mutual information (TCMI) to reproduce the main results presented in the publication.", + "url": "https://gitlab.mpcdf.mpg.de/nomad-lab/analytics-tcmi", + "link": "https://analytics-toolkit.nomad-coe.eu/hub/user-redirect/notebooks/tutorials/tcmi.ipynb", + "link_public": "https://analytics-toolkit.nomad-coe.eu/public/user-redirect/notebooks/tutorials/tcmi.ipynb", + "link_paper": "https://th.fhi.mpg.de/site/uploads/Publications/2001.11212.pdf", + "updated": "2020-01-14", + "flags": { + "featured": true, + "top_of_list": false, + "paper": true + }, + "labels": { + "application_keyword": [ + "information theory", + "mutual information", + "cumulative entropy", + "feature selection" + ], + "application_section": [ + "Tutorials for artificial-intelligence methods" + ], + "application_system": [ + "System" + ], + "category": [ + "intermediate_tutorial" + ], + "data_analytics_method": [ + "Clustering", + "TCMI" + ], + "language": [ + "python", + "javascript" + ], + "platform": [ + "jupyter" + ] + } + }, { "authors": [ "Fekete, \u00c1d\u00e1m", @@ -142,33 +358,35 @@ "Cs\u00e1nyi, G\u00e1bor" ], "email": "adam.fekete@kcl.ac.uk", - "title": "The SOAP descriptor, Gaussian Approximation Potentials (GAP) and machine-learning of force fields", - "description": "In this tutorial we will be using a Gaussian Approximation Potentials to analyse results of TB DFT calculations of Si surface. Along the way we will learn about different descriptors (2b, 3b, soap) to describe local atomic environment in order to predict energies and forces of Si surface.", - "url": "https://gitlab.mpcdf.mpg.de/nomad-lab/analytics-gap-si-surface", - "link": "https://analytics-toolkit.nomad-coe.eu/hub/user-redirect/notebooks/tutorials/gap_si_surface.ipynb", - "link_public": "https://analytics-toolkit.nomad-coe.eu/public/user-redirect/notebooks/tutorials/gap_si_surface.ipynb", + "title": "Grain boundaries of alpha-Fe tutorial", + "description": "In this tutorial we will be using a machine learning method (clustering) to analyse results of Grain Boundary (GB) calculations of alpha-iron. Along the way we will learn about different methods to describe local atomic environment in order to calculate properties of GBs. We will use these properties to separate the different regions of the GB using clustering methods. Finally we will determine how the energy of the GB is changing according to the angle difference of the regions.", + "url": "https://gitlab.mpcdf.mpg.de/nomad-lab/analytics-grain-boundaries", + "link": "https://analytics-toolkit.nomad-coe.eu/hub/user-redirect/notebooks/tutorials/grain_boundaries.ipynb", + "link_public": "https://analytics-toolkit.nomad-coe.eu/public/user-redirect/notebooks/tutorials/grain_boundaries.ipynb", + "link_paper": "https://www.sciencedirect.com/science/article/pii/S0010465518301450?via%3Dihub", "updated": "2019-06-01", "flags": { "featured": true, - "top_of_list": false + "top_of_list": false, + "paper": true }, "labels": { "application_keyword": [ - "SOAP descriptor", - "Gaussian Approximation Potentials (GAP)" + "Grain boundaries" ], "application_section": [ - "Tutorials for artificial-intelligence methods" + "Timely artificial-intelligence applications to Materials Science" ], "application_system": [ - "Si" + "Iron" ], "category": [ - "Tutorial" + "advanced_tutorial" ], "data_analytics_method": [ - "Gaussian-process regression", - "Kernel ridge regression" + "Clustering", + "K-means", + "Gaussian mixture" ], "platform": [ "jupyter" @@ -202,7 +420,7 @@ "GDB7" ], "category": [ - "Tutorial" + "intermediate_tutorial" ], "data_analytics_method": [ "Gaussian-process regression", @@ -215,40 +433,39 @@ }, { "authors": [ - "Fekete, \u00c1d\u00e1m", - "Stella, Martina", - "Lambert, Henry", - "De Vita, Alessandro", - "Cs\u00e1nyi, G\u00e1bor" + "Bieniek, Bj\u00f6rn", + "Strange, Mikkel", + "Carbogno, Christian", + "Arif, Mohammad-Yasin", + "Sbail\u00f2, Luigi", + "Scheffler, Matthias" ], - "email": "adam.fekete@kcl.ac.uk", - "title": "Grain boundaries of alpha-Fe tutorial", - "description": "In this tutorial we will be using a machine learning method (clustering) to analyse results of Grain Boundary (GB) calculations of alpha-iron. Along the way we will learn about different methods to describe local atomic environment in order to calculate properties of GBs. We will use these properties to separate the different regions of the GB using clustering methods. Finally we will determine how the energy of the GB is changing according to the angle difference of the regions.", - "url": "https://gitlab.mpcdf.mpg.de/nomad-lab/analytics-grain-boundaries", - "link": "https://analytics-toolkit.nomad-coe.eu/hub/user-redirect/notebooks/tutorials/grain_boundaries.ipynb", - "link_public": "https://analytics-toolkit.nomad-coe.eu/public/user-redirect/notebooks/tutorials/grain_boundaries.ipynb", - "updated": "2019-06-01", + "email": "ghiringhelli@fhi-berlin.mpg.de", + "title": "Error estimates from high-accuracy electronic structure reference calculations", + "description": "A set of tools to analyze the error in electronic structure calculations due to the choice of numerical settings. We use the NOMAD infrastructure to systematically investigate the deviances in total and relative energies as function of typical settings for basis sets, k-grids, etc. for 71 elemental and 81 binary solids in three different electronic-structure codes.", + "url": "https://gitlab.mpcdf.mpg.de/nomad-lab/analytics-error-estimates", + "link": "https://analytics-toolkit.nomad-coe.eu/hub/user-redirect/notebooks/tutorials/error_estimates.ipynb", + "link_public": "https://analytics-toolkit.nomad-coe.eu/public/user-redirect/notebooks/tutorials/error_estimates.ipynb", + "link_paper": "https://th.fhi-berlin.mpg.de/site/uploads/Publications/2008.10402.pdf", + "updated": "2020-07-03", "flags": { "featured": true, - "top_of_list": false + "top_of_list": false, + "paper": true }, "labels": { "application_keyword": [ - "Grain boundaries" + "Binaries", + "Elemental solids" ], "application_section": [ "Timely artificial-intelligence applications to Materials Science" ], - "application_system": [ - "Iron" - ], "category": [ - "Tutorial" + "advanced_tutorial" ], "data_analytics_method": [ - "Clustering", - "K-means", - "Gaussian mixture" + "Linear Least-squares Regression" ], "platform": [ "jupyter" @@ -257,27 +474,31 @@ }, { "authors": [ - "Regler, Benjamin", - "Scheffler, Matthias", + "Arif, Mohammad-Yasin", + "Sbail\u00f2, Luigi", "Ghiringhelli, Luca M." ], - "email": "regler@fhi-berlin.mpg.de", - "title": "Total cumulative mutual information", - "description": "This interactive notebook includes the original implementation of total cumulative mutual information (TCMI) to reproduce the main results presented in the publication.", - "url": "https://gitlab.mpcdf.mpg.de/nomad-lab/analytics-tcmi", - "link": "https://analytics-toolkit.nomad-coe.eu/hub/user-redirect/notebooks/tutorials/tcmi.ipynb", - "link_public": "https://analytics-toolkit.nomad-coe.eu/public/user-redirect/notebooks/tutorials/tcmi.ipynb", - "updated": "2020-01-14", + "email": "ghiringhelli@fhi-berlin.mpg.de", + "title": "Identifying Domains of Applicability of Machine-Learning Models for Materials Science", + "description": "In this tutorial, we present a method, based on subgroup discovery, for detecting domains of applicability (DA) of ML models within a materials class. The domain of applicability of an ML model is the region of input space where the model predicts the target property with the smallest uncertainty. The utility of this approach is demonstrated by analyzing three state-of-the-art ML models for predicting the formation energy of transparent conducting oxides.", + "url": "https://gitlab.mpcdf.mpg.de/nomad-lab/analytics-domain-of-applicability", + "link": "https://analytics-toolkit.nomad-coe.eu/hub/user-redirect/notebooks/tutorials/domain_of_applicability.ipynb", + "link_public": "https://analytics-toolkit.nomad-coe.eu/public/user-redirect/notebooks/tutorials/domain_of_applicability.ipynb", + "link_paper": " https://th.fhi-berlin.mpg.de/site/uploads/Publications/s41467-020-17112-9.pdf", + "updated": "2021-01-28", "flags": { "featured": true, - "top_of_list": false + "top_of_list": false, + "paper": true }, "labels": { "application_keyword": [ - "information theory", - "mutual information", - "cumulative entropy", - "feature selection" + "SOAP", + "MBTR", + "n-gram", + "Formation energy prediction", + "Transparent Conducting Oxides", + "heterogeneous catalysis" ], "application_section": [ "Timely artificial-intelligence applications to Materials Science" @@ -286,15 +507,53 @@ "System" ], "category": [ - "Tutorial" + "advanced_utorial" ], "data_analytics_method": [ - "Clustering", - "TCMI" + "Subgroup discovery", + "Kernel ridge regression" ], - "language": [ - "python", - "javascript" + "platform": [ + "jupyter" + ] + } + }, + { + "authors": [ + "Fekete, \u00c1d\u00e1m", + "Stella, Martina", + "Lambert, Henry", + "De Vita, Alessandro", + "Cs\u00e1nyi, G\u00e1bor" + ], + "email": "adam.fekete@kcl.ac.uk", + "title": "The SOAP descriptor, Gaussian Approximation Potentials (GAP) and machine-learning of force fields", + "description": "In this tutorial we will be using a Gaussian Approximation Potentials to analyse results of TB DFT calculations of Si surface. Along the way we will learn about different descriptors (2b, 3b, soap) to describe local atomic environment in order to predict energies and forces of Si surface.", + "url": "https://gitlab.mpcdf.mpg.de/nomad-lab/analytics-gap-si-surface", + "link": "https://analytics-toolkit.nomad-coe.eu/hub/user-redirect/notebooks/tutorials/gap_si_surface.ipynb", + "link_public": "https://analytics-toolkit.nomad-coe.eu/public/user-redirect/notebooks/tutorials/gap_si_surface.ipynb", + "updated": "2019-06-01", + "flags": { + "featured": true, + "top_of_list": false + }, + "labels": { + "application_keyword": [ + "SOAP descriptor", + "Gaussian Approximation Potentials (GAP)" + ], + "application_section": [ + "Tutorials for artificial-intelligence methods" + ], + "application_system": [ + "Si" + ], + "category": [ + "advanced_tutorial" + ], + "data_analytics_method": [ + "Gaussian-process regression", + "Kernel ridge regression" ], "platform": [ "jupyter" @@ -315,10 +574,12 @@ "url": "https://gitlab.mpcdf.mpg.de/nomad-lab/analytics-descriptor-role", "link": "https://analytics-toolkit.nomad-coe.eu/hub/user-redirect/notebooks/tutorials/descriptor_role.ipynb", "link_public": "https://analytics-toolkit.nomad-coe.eu/public/user-redirect/notebooks/tutorials/descriptor_role.ipynb", + "link_paper": "https://th.fhi.mpg.de/site/uploads/Publications/PRL-114-105503-2015.pdf", "updated": "2020-09-5", "flags": { "featured": true, - "top_of_list": false + "top_of_list": false, + "paper": true }, "labels": { "application_keyword": [ @@ -332,7 +593,7 @@ "Zinc blende" ], "category": [ - "Tutorial" + "advanced_tutorial" ], "data_analytics_method": [ "SISSO" @@ -344,37 +605,49 @@ }, { "authors": [ - "Bieniek, Bj\u00f6rn", - "Strange, Mikkel", - "Carbogno, Christian", - "Arif, Mohammad-Yasin", - "Sbail\u00f2, Luigi", - "Scheffler, Matthias" + "Liu, Xiangyue", + "Sutton, Christopher", + "Yamamoto, Takenori", + "Lysogorskiy, Yury", + "Blumenthal, Lars", + "Hammerschmidt, Thomas", + "Golebiowski, Jacek", + "Ziletti, Angelo", + "Scheffler, Matthias", + "Ghiringhelli, Luca M." ], "email": "ghiringhelli@fhi-berlin.mpg.de", - "title": "Error estimates from high-accuracy electronic structure reference calculations", - "description": "A set of tools to analyze the error in electronic structure calculations due to the choice of numerical settings. We use the NOMAD infrastructure to systematically investigate the deviances in total and relative energies as function of typical settings for basis sets, k-grids, etc. for 71 elemental and 81 binary solids in three different electronic-structure codes.", - "url": "https://gitlab.mpcdf.mpg.de/nomad-lab/analytics-error-estimates", - "link": "https://analytics-toolkit.nomad-coe.eu/hub/user-redirect/notebooks/tutorials/error_estimates.ipynb", - "link_public": "https://analytics-toolkit.nomad-coe.eu/public/user-redirect/notebooks/tutorials/error_estimates.ipynb", - "updated": "2020-07-03", + "title": "NOMAD 2018 Kaggle research competition", + "description": "In this tutorial, we will explore the best results of the NOMAD 2018 Kaggle research competition. The goal of this competition was to develop machine-learning models for the prediction of two target properties: the formation energy and the bandgap energy of transparent semiconducting oxides. The purpose of the modelling is to facilitate the discovery of new such materials and allow for advancements in (opto)electronic technologies", + "url": "https://gitlab.mpcdf.mpg.de/nomad-lab/analytics-kaggle-competition", + "link": "https://analytics-toolkit.nomad-coe.eu/hub/user-redirect/notebooks/tutorials/kaggle_competition.ipynb", + "link_public": "https://analytics-toolkit.nomad-coe.eu/public/user-redirect/notebooks/tutorials/kaggle_competition.ipynb", + "link_paper": "https://th.fhi.mpg.de/site/uploads/Publications/s41524-019-0239-3.pdf", + "updated": "2020-02-06", "flags": { "featured": true, - "top_of_list": false + "top_of_list": false, + "paper": true }, "labels": { "application_keyword": [ - "Binaries", - "Elemental solids" + "Formation energy prediction", + "Band gap energy prediction" ], "application_section": [ "Timely artificial-intelligence applications to Materials Science" ], + "application_system": [ + "Group-III oxidess" + ], "category": [ - "Demo" + "advanced_tutorial" ], "data_analytics_method": [ - "Linear Least-squares Regression" + "Kernel ridge regression", + "Neural networks", + "SOAP", + "n-gram" ], "platform": [ "jupyter" @@ -410,7 +683,7 @@ "Materials" ], "category": [ - "Tutorial" + "query_tutorial" ], "data_analytics_method": [ "Clustering", @@ -421,6 +694,181 @@ "jupyter" ] } + }, + { + "authors": [ + "Sbail\u00f2, Luigi", + "Purcell, Thomas A. R.", + "Ghiringhelli, Luca M.", + "Scheffler, Matthias" + ], + "email": "ghiringhelli@fhi-berlin.mpg.de", + "title": "Discovery of new topological insulators in alloyed tetradymites", + "description": "Learn how to find descriptive parameters (short formulas) that predict whether alloyed materials are topological or trivial insulators, using the example of tetradymites. This notebook is based on the algorithm 'sure independence screening and sparsifying operator' (SISSO) that enables to search for optimal descriptor by scanning huge feature spaces.", + "url": "https://gitlab.mpcdf.mpg.de/nomad-lab/analytics-tetradymite-PRM2020", + "link": "https://analytics-toolkit.nomad-coe.eu/hub/user-redirect/notebooks/tutorials/tetradymite_PRM2020.ipynb", + "link_public": "https://analytics-toolkit.nomad-coe.eu/public/user-redirect/notebooks/tutorials/tetradymite_PRM2020.ipynb", + "link_paper": "https://th.fhi.mpg.de/site/uploads/Publications/PhysRevMaterials.4.034204.pdf", + "updated": "2020-12-09", + "flags": { + "featured": true, + "top_of_list": false, + "paper": true + }, + "labels": { + "application_keyword": [ + "Tetradymites", + "Topological insulators" + ], + "application_section": [ + "Timely artificial-intelligence applications to Materials Science" + ], + "application_system": [ + "Tetradymites" + ], + "category": [ + "advanced_tutorial" + ], + "data_analytics_method": [ + "SISSO", + "Classification" + ], + "platform": [ + "jupyter" + ] + } + }, + { + "authors": [ + "Leitherer, Andreas", + "Ziletti, Angelo", + "Ghiringhelli, Luca M." + ], + "email": "leitherer@fhi-berlin.mpg.de", + "title": "ARISE - Robust recognition and exploratory analysis of crystal structures via Bayesian-deep-learning", + "description": "In this tutorial we will give an introduction to ARISE (Leitherer, Ziletti, Ghiringhelli arXiv:2103.09777).", + "url": "https://gitlab.mpcdf.mpg.de/nomad-lab/analytics-arise", + "link": "https://analytics-toolkit.nomad-coe.eu/hub/user-redirect/notebooks/tutorials/ARISE.ipynb", + "link_public": "https://analytics-toolkit.nomad-coe.eu/public/user-redirect/notebooks/tutorials/ARISE.ipynb", + "link_paper": "https://arxiv.org/abs/2103.09777", + "updated": "2021-03-22", + "flags":{ + "featured": true, + "top_of_list": false, + "paper": true + }, + "labels": { + "application_keyword": [ + "Bayesian deep learning", + "Unsupervised learning", + "SOAP", + "grain boundaries", + "binaries", + "ternaries", + "low-dimensional materials" + ], + "application_section": [ + "Timely artificial-intelligence applications to Materials Science" + ], + "application_system": [ + "System" + ], + "category": [ + "advanced_tutorial" + ], + "data_analytics_method": [ + "Bayesian deep learning", + "Unsupervised learning" + ], + "platform": [ + "jupyter" + ] + } + }, + { + "authors": [ + "Leitherer, Andreas", + "Ziletti, Angelo", + "Sbailò, Luigi", + "Scheffler, Matthias", + "Ghiringhelli, Luca M." + ], + "email": "leitherer@fhi-berlin.mpg.de", + "title": "Hands-on tutorial: Regression using multilayer perceptrons", + "description": "In this tutorial we will use the ElemNet neural network architecture (https://github.com/NU-CUCIS/ElemNet) to predict the volume per atom of inorganic compounds, where the open quantum materials database (OQMD) is used as a resource (specifically, the data is taken from Ward et. al., npj Comput. Mater. 2, 16028 (2016)).", + "url": "https://gitlab.mpcdf.mpg.de/nomad-lab/analytics-nn-regression", + "link": "https://analytics-toolkit.nomad-coe.eu/hub/user-redirect/notebooks/tutorials/nn_regression.ipynb", + "link_public": "https://analytics-toolkit.nomad-coe.eu/public/user-redirect/notebooks/tutorials/nn_regression.ipynb", + "link_video": "https://www.youtube.com/watch?v=U0lI5n8Hleo", + "updated": "2020-04-09", + "flags":{ + "featured": true, + "top_of_list": false, + "video": true + }, + "labels": { + "application_keyword": [ + "Deep neural networks", + "Descriptors" + ], + "application_section": [ + "Tutorials for artificial-intelligence methods" + ], + "application_system": [ + "Inorganic compounds taken from the OQMD database" + ], + "category": [ + "beginner_tutorial" + ], + "data_analytics_method": [ + "Neural networks" + ], + "platform": [ + "jupyter" + ] + } + }, + { + "authors": [ + "Mazheika, Aliaksei", + "Sbailò, Luigi", + "Ghiringhelli, Luca", + "Levchenko, Sergey", + "Scheffler, Matthias" + ], + "email": "mazheika@fhi-berlin.mpg.de", + "title": "Subgroup discovery for carbon-dioxide activation", + "description": "In this interactive tutorial we show the application of subgroup discovery for the search for indicators of carbond-dioxide activation with the aim of its further conversion.", + "url": "https://gitlab.mpcdf.mpg.de/nomad-lab/analytics-co2-sgd-tutorial", + "link": "https://analytics-toolkit.nomad-coe.eu/hub/user-redirect/notebooks/tutorials/CO2_SGD.ipynb", + "link_public": "https://analytics-toolkit.nomad-coe.eu/public/user-redirect/notebooks/tutorials/CO2_SGD.ipynb", + "link_paper": "https://arxiv.org/abs/1912.06515", + "updated": "2020-09-21", + "flags":{ + "featured": true, + "top_of_list": false + }, + "labels": { + "application_keyword": [ + "CO2 activation", + "heterogeneous catalysis" + ], + "application_section": [ + "Timely artificial-intelligence applications to Materials Science" + ], + "application_system": [ + "System" + ], + "category": [ + "advanced_tutorial" + ], + "data_analytics_method": [ + "Subgroup discovery" + ], + "platform": [ + "jupyter" + ] + } } - ] + ] } -- GitLab From bb85375f606a5d6d4aa684e4c276e546c4818a68 Mon Sep 17 00:00:00 2001 From: sbailo Date: Wed, 13 Oct 2021 14:37:50 +0200 Subject: [PATCH 29/68] Add embed videos in landing page --- gui/src/components/aitoolkit/AIToolkitPage.js | 19 +++++++++++++---- gui/src/components/aitoolkit/YoutubeEmbed.js | 21 +++++++++++++++++++ 2 files changed, 36 insertions(+), 4 deletions(-) create mode 100644 gui/src/components/aitoolkit/YoutubeEmbed.js diff --git a/gui/src/components/aitoolkit/AIToolkitPage.js b/gui/src/components/aitoolkit/AIToolkitPage.js index 13ba11d25..9ec549db4 100644 --- a/gui/src/components/aitoolkit/AIToolkitPage.js +++ b/gui/src/components/aitoolkit/AIToolkitPage.js @@ -29,8 +29,7 @@ import IconWork2 from './assets/AIT_ico_bp_work.svg' import {useStylesLanding} from './styles.js' import ArrowIcon from './assets/AIT_ico_bd_link_go_to.svg' import FigureAI from './assets/AIT_illu_AIT.svg' - -// import ReactPlayer from 'react-player/youtube' +import YoutubeEmbed from './YoutubeEmbed' export default function AIToolkitPage() { const classes = useStylesLanding() @@ -94,10 +93,22 @@ export default function AIToolkitPage() { + + How to get started +
+ +
+ + NOMAD Artificial Toolkit is very accessible. Watch this video and learn more about its features. Our philosophy is... +
+
+ +
+ Access the tutorials - Ready to start? Click on one of the options below. If you're new, we suggest starting with the AI Tutorials for materials science. + Ready to start? Click on one of the options below. If you're new, we suggest starting with the tutorials.
@@ -111,7 +122,7 @@ export default function AIToolkitPage() { -