diff --git a/src/components/contrib-module.js b/src/components/contrib-module.js
new file mode 100644
index 0000000..e5dfd27
--- /dev/null
+++ b/src/components/contrib-module.js
@@ -0,0 +1,70 @@
+import { makeStyles } from '@material-ui/core/styles';
+import React from 'react';
+import Typography from '@material-ui/core/Typography';
+import { Link } from 'gatsby-material-ui-components';
+import Card from '@material-ui/core/Card';
+import CardActions from '@material-ui/core/CardActions';
+import CardContent from '@material-ui/core/CardContent';
+import Button from '@material-ui/core/Button';
+import WarningIcon from '@material-ui/icons/Warning';
+import InfoIcon from '@material-ui/icons/Info';
+import Paper from '@material-ui/core/Paper';
+import theme from '../theme';
+
+const useStyles = makeStyles({
+ root: {
+ height: '100%',
+ display: 'flex',
+ flexDirection: 'column',
+ justifyContent: 'space-between',
+ },
+ title: {
+ fontSize: '1.3rem !important',
+ marginTop: '0 !important',
+ },
+ pos: {
+ marginBottom: 12,
+ },
+ consideration: {
+ background: theme.palette.primary.light,
+ display: 'flex',
+ alignItems: 'center',
+ padding: '5px',
+ fontSize: '.8rem',
+ lineHeight: '1.2',
+ marginTop: '.5rem',
+ color: 'white',
+ },
+ 'consideration--warning': {
+ background: '#ffc107'
+ },
+ icon: {
+ marginRight: '5px',
+ fontSize: '1.3rem'
+ }
+});
+
+export default function ContribModule({module}) {
+ const classes = useStyles();
+
+ return (
+
+
+ {module.name}
+ {module.description}
+ {module.considerations && module.considerations.map(info => {
+ return (
+
+ { info.type === 'info' && ()}
+ { info.type === 'warning' && ()}
+ {info.value}
+
+ )
+ })}
+
+
+
+
+
+ );
+}
diff --git a/src/content/config.yml b/src/content/config.yml
index 2a86a0e..7478f26 100644
--- a/src/content/config.yml
+++ b/src/content/config.yml
@@ -11,3 +11,4 @@ nav:
- Press: community/press.md
- Trademark: community/trademark.md
- Donate: donate.md
+ - Contrib modules: community/modules
diff --git a/src/pages/community/modules/index.js b/src/pages/community/modules/index.js
new file mode 100644
index 0000000..e102d9c
--- /dev/null
+++ b/src/pages/community/modules/index.js
@@ -0,0 +1,61 @@
+import * as React from "react"
+import { useEffect, useState } from "react";
+import { Helmet } from "react-helmet";
+import { makeStyles } from '@material-ui/core/styles';
+import { Box, Typography } from '@material-ui/core';
+import theme from '../../../theme';
+import ContribModule from '../../../components/contrib-module';
+import Grid from '@material-ui/core/Grid';
+
+const useStyles = makeStyles({
+ main: {
+ '& h1': {
+ color: theme.palette.text.secondary,
+ fontWeight: 300,
+ fontSize: '2rem',
+ lineHeight: 1.3,
+ letterSpacing: '-.01em',
+ margin: '0 0 1.25rem',
+ },
+ '& h2': {
+ margin: '1.6rem 0 0.64rem',
+ fontSize: '1.5625rem',
+ fontWeight: 300,
+ lineHeight: 1.4,
+ letterSpacing: '-.01em',
+ }
+ },
+ modules: {
+ flexGrow: 1,
+ }
+});
+
+const ProjectsPage = () => {
+ const classes = useStyles();
+ const [contribModules, setContribModules] = useState([]);
+ useEffect(() => {
+ async function fetchData() {
+ const response = await fetch(`https://raw.githubusercontent.com/wotnak/farmos-community-projects/main/projects.json`)
+ const data = await response.json();
+ if (data.projects) {
+ setContribModules(data.projects)
+ }
+ }
+ fetchData();
+ }, []);
+ return (
+ <>
+
+
+ Contrib modules
+
+ {contribModules.length > 0 && contribModules.map(module => {
+ return ()
+ })}
+
+
+ >
+ );
+};
+
+export default ProjectsPage;