diff --git a/data-flow-diagram.png b/data-flow-diagram.png index 13962b6..bbe8dcd 100644 Binary files a/data-flow-diagram.png and b/data-flow-diagram.png differ diff --git a/gatsby-browser.js b/gatsby-browser.js index e4d2343..8f3b9ae 100644 --- a/gatsby-browser.js +++ b/gatsby-browser.js @@ -1,6 +1,15 @@ import React from "react" import { Layout } from "./src/components/layout" +import { CssVarsProvider } from '@mui/joy/styles'; +import theme from './src/styles/theme' +import { PositionsProvider } from './src/components/positions' export const wrapPageElement = ({ element, props }) => { - return {element} -} + return ( + + + {element} + + + ) +} \ No newline at end of file diff --git a/gatsby-config.js b/gatsby-config.js index 04eee45..f61a506 100644 --- a/gatsby-config.js +++ b/gatsby-config.js @@ -1,5 +1,10 @@ +require('dotenv').config({ + path: `.env.${ process.env.NODE_ENV }`, +}) + module.exports = { plugins: [ + /* image plugins */ `gatsby-plugin-image`, { resolve: `gatsby-source-filesystem`, @@ -8,6 +13,9 @@ module.exports = { path: `${__dirname}/src/images`, }, }, + `gatsby-transformer-sharp`, + `gatsby-plugin-sharp`, + /* content plugins */ `gatsby-transformer-yaml`, { resolve: `gatsby-source-filesystem`, @@ -37,18 +45,23 @@ module.exports = { path: `${__dirname}/src/content/theme`, }, }, - `gatsby-transformer-sharp`, - `gatsby-plugin-sharp`, + /* custom plugins */ + { + resolve: `gatsby-source-monday`, + options: { + API_TOKEN: process.env.MONDAY_API_TOKEN, + } + }, + `gatsby-transformer-monday`, + /* manifest */ { resolve: `gatsby-plugin-manifest`, options: { - name: `gatsby-starter-default`, - short_name: `starter`, + name: `star-website`, + short_name: `star`, start_url: `/`, - background_color: `#663399`, - // This will impact how browsers show your PWA/website - // https://css-tricks.com/meta-theme-color-and-trickery/ - // theme_color: `#663399`, + background_color: `#007abc`, + theme_color: `#007abc`, display: `minimal-ui`, icon: `src/images/favicon.png`, // This path is relative to the root of the site. }, diff --git a/gatsby-node.js b/gatsby-node.js index ff1a65d..fa9ee5f 100644 --- a/gatsby-node.js +++ b/gatsby-node.js @@ -5,29 +5,7 @@ const { paramCase, pascalCase } = require('change-case') // -const contentYamlDir = path.join(`src`, `pages`) -const sectionYamlDir = path.join(`src`, `content`, `sections`) -const contentImagesDir = path.join(`src`, `content`, `images`) -const pageTemplate = require.resolve('./src/templates/page.js') - -// page yaml files -const pageFilenames = [ - `home.yaml`, - `students.yaml`, - `staff.yaml`, -] - -/** - * looks up section content by its id. - * - * @param {string} sectionId The section id to lookup. - * @returns {object} the section's YAML data as an object - */ -function getSectionContent(sectionId) { - const sectionFile = fs.readFileSync(path.join(sectionYamlDir, `${ sectionId }.yaml`), 'utf8') - const content = yaml.load(sectionFile) - return content -} +const stackedPageTemplate = require.resolve('./src/templates/stacked-page.js') exports.createPages = async ({ actions, graphql, reporter }) => { const { createPage } = actions @@ -36,7 +14,6 @@ exports.createPages = async ({ actions, graphql, reporter }) => { allPagesYaml { nodes { path - sections } } }`) @@ -46,7 +23,7 @@ exports.createPages = async ({ actions, graphql, reporter }) => { // create page and pass section content in context createPage({ path: node.path, - component: pageTemplate, + component: stackedPageTemplate, context: { pagePath: node.path, }, @@ -70,7 +47,7 @@ exports.createSchemaCustomization = ({ actions }) => { hero: Hero sections: [String!]! } - type Project { + type Student { student_name: String! student_photo: File! @link(by: "relativePath") project_description: String! @@ -80,7 +57,7 @@ exports.createSchemaCustomization = ({ actions }) => { background_image: File! @link(by: "relativePath") } type SectionsYaml implements Node { - projects: [Project!] + students: [Student!] students_cta: CtaButton! staff_cta: CtaButton! } diff --git a/gatsby-ssr.js b/gatsby-ssr.js index e4d2343..8f3b9ae 100644 --- a/gatsby-ssr.js +++ b/gatsby-ssr.js @@ -1,6 +1,15 @@ import React from "react" import { Layout } from "./src/components/layout" +import { CssVarsProvider } from '@mui/joy/styles'; +import theme from './src/styles/theme' +import { PositionsProvider } from './src/components/positions' export const wrapPageElement = ({ element, props }) => { - return {element} -} + return ( + + + {element} + + + ) +} \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 7391b52..6e065d9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,6 +12,7 @@ "@emotion/react": "^11.11.1", "@emotion/styled": "^11.11.0", "@fontsource/inter": "^5.0.8", + "@mui/icons-material": "^5.14.19", "@mui/joy": "^5.0.0-beta.7", "change-case": "^4.1.2", "gatsby": "^5.12.4", @@ -24,7 +25,8 @@ "js-yaml": "^4.1.0", "react": "^18.2.0", "react-dom": "^18.2.0", - "react-markdown": "^9.0.0" + "react-markdown": "^9.0.0", + "swiper": "^11.0.5" }, "devDependencies": { "prettier": "^2.8.8" @@ -1871,9 +1873,9 @@ } }, "node_modules/@babel/runtime": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.22.15.tgz", - "integrity": "sha512-T0O+aa+4w0u06iNmapipJXMV4HoUir03hpx3/YqXXhu9xim3w+dVphjFWl1OH8NbZHw5Lbm9k45drDkgq2VNNA==", + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.23.6.tgz", + "integrity": "sha512-zHd0eUrf5GZoOWVCXp6koAKQTfZV07eit6bGPmJgnZdnSAvvZee6zniW2XMF7Cmc4ISOOnPy3QaSiIJGJkVEDQ==", "dependencies": { "regenerator-runtime": "^0.14.0" }, @@ -2210,9 +2212,9 @@ } }, "node_modules/@floating-ui/react-dom": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.0.2.tgz", - "integrity": "sha512-5qhlDvjaLmAst/rKb3VdlCinwTF4EYMiVxuuc/HVUjs46W0zgtbMmAZ1UTsDrRTxRmUEzl92mOtWbeeXL26lSQ==", + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.0.4.tgz", + "integrity": "sha512-CF8k2rgKeh/49UrnIBs4BdxPUV6vize/Db1d/YbCLyp9GiVZ0BEwf5AiDSxJRCr6yOkGqTFHtmrULxkEfYZ7dQ==", "dependencies": { "@floating-ui/dom": "^1.5.1" }, @@ -3016,12 +3018,37 @@ } }, "node_modules/@mui/core-downloads-tracker": { - "version": "5.14.10", - "resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-5.14.10.tgz", - "integrity": "sha512-kPHu/NhZq1k+vSZR5wq3AyUfD4bnfWAeuKpps0+8PS7ZHQ2Lyv1cXJh+PlFdCIOa0PK98rk3JPwMzS8BMhdHwQ==", + "version": "5.14.20", + "resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-5.14.20.tgz", + "integrity": "sha512-fXoGe8VOrIYajqALysFuyal1q1YmBARqJ3tmnWYDVl0scu8f6h6tZQbS2K8BY28QwkWNGyv4WRfuUkzN5HR3Ow==", "funding": { "type": "opencollective", - "url": "https://opencollective.com/mui" + "url": "https://opencollective.com/mui-org" + } + }, + "node_modules/@mui/icons-material": { + "version": "5.14.19", + "resolved": "https://registry.npmjs.org/@mui/icons-material/-/icons-material-5.14.19.tgz", + "integrity": "sha512-yjP8nluXxZGe3Y7pS+yxBV+hWZSsSBampCxkZwaw+1l+feL+rfP74vbEFbMrX/Kil9I/Y1tWfy5bs/eNvwNpWw==", + "dependencies": { + "@babel/runtime": "^7.23.4" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@mui/material": "^5.0.0", + "@types/react": "^17.0.0 || ^18.0.0", + "react": "^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } } }, "node_modules/@mui/joy": { @@ -3064,13 +3091,96 @@ } } }, + "node_modules/@mui/material": { + "version": "5.14.20", + "resolved": "https://registry.npmjs.org/@mui/material/-/material-5.14.20.tgz", + "integrity": "sha512-SUcPZnN6e0h1AtrDktEl76Dsyo/7pyEUQ+SAVe9XhHg/iliA0b4Vo+Eg4HbNkELsMbpDsUF4WHp7rgflPG7qYQ==", + "peer": true, + "dependencies": { + "@babel/runtime": "^7.23.4", + "@mui/base": "5.0.0-beta.26", + "@mui/core-downloads-tracker": "^5.14.20", + "@mui/system": "^5.14.20", + "@mui/types": "^7.2.10", + "@mui/utils": "^5.14.20", + "@types/react-transition-group": "^4.4.9", + "clsx": "^2.0.0", + "csstype": "^3.1.2", + "prop-types": "^15.8.1", + "react-is": "^18.2.0", + "react-transition-group": "^4.4.5" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@emotion/react": "^11.5.0", + "@emotion/styled": "^11.3.0", + "@types/react": "^17.0.0 || ^18.0.0", + "react": "^17.0.0 || ^18.0.0", + "react-dom": "^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@emotion/react": { + "optional": true + }, + "@emotion/styled": { + "optional": true + }, + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/material/node_modules/@mui/base": { + "version": "5.0.0-beta.26", + "resolved": "https://registry.npmjs.org/@mui/base/-/base-5.0.0-beta.26.tgz", + "integrity": "sha512-gPMRKC84VRw+tjqYoyBzyrBUqHQucMXdlBpYazHa5rCXrb91fYEQk5SqQ2U5kjxx9QxZxTBvWAmZ6DblIgaGhQ==", + "peer": true, + "dependencies": { + "@babel/runtime": "^7.23.4", + "@floating-ui/react-dom": "^2.0.4", + "@mui/types": "^7.2.10", + "@mui/utils": "^5.14.20", + "@popperjs/core": "^2.11.8", + "clsx": "^2.0.0", + "prop-types": "^15.8.1" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@types/react": "^17.0.0 || ^18.0.0", + "react": "^17.0.0 || ^18.0.0", + "react-dom": "^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/material/node_modules/react-is": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", + "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", + "peer": true + }, "node_modules/@mui/private-theming": { - "version": "5.14.10", - "resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-5.14.10.tgz", - "integrity": "sha512-f67xOj3H06wWDT9xBg7hVL/HSKNF+HG1Kx0Pm23skkbEqD2Ef2Lif64e5nPdmWVv+7cISCYtSuE2aeuzrZe78w==", + "version": "5.14.20", + "resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-5.14.20.tgz", + "integrity": "sha512-WV560e1vhs2IHCh0pgUaWHznrcrVoW9+cDCahU1VTkuwPokWVvb71ccWQ1f8Y3tRBPPcNkU2dChkkRJChLmQlQ==", "dependencies": { - "@babel/runtime": "^7.22.15", - "@mui/utils": "^5.14.10", + "@babel/runtime": "^7.23.4", + "@mui/utils": "^5.14.20", "prop-types": "^15.8.1" }, "engines": { @@ -3078,7 +3188,7 @@ }, "funding": { "type": "opencollective", - "url": "https://opencollective.com/mui" + "url": "https://opencollective.com/mui-org" }, "peerDependencies": { "@types/react": "^17.0.0 || ^18.0.0", @@ -3091,11 +3201,11 @@ } }, "node_modules/@mui/styled-engine": { - "version": "5.14.10", - "resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-5.14.10.tgz", - "integrity": "sha512-EJckxmQHrsBvDbFu1trJkvjNw/1R7jfNarnqPSnL+jEQawCkQIqVELWLrlOa611TFtxSJGkdUfCFXeJC203HVg==", + "version": "5.14.20", + "resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-5.14.20.tgz", + "integrity": "sha512-Vs4nGptd9wRslo9zeRkuWcZeIEp+oYbODy+fiZKqqr4CH1Gfi9fdP0Q1tGYk8OiJ2EPB/tZSAyOy62Hyp/iP7g==", "dependencies": { - "@babel/runtime": "^7.22.15", + "@babel/runtime": "^7.23.4", "@emotion/cache": "^11.11.0", "csstype": "^3.1.2", "prop-types": "^15.8.1" @@ -3105,7 +3215,7 @@ }, "funding": { "type": "opencollective", - "url": "https://opencollective.com/mui" + "url": "https://opencollective.com/mui-org" }, "peerDependencies": { "@emotion/react": "^11.4.1", @@ -3122,15 +3232,15 @@ } }, "node_modules/@mui/system": { - "version": "5.14.10", - "resolved": "https://registry.npmjs.org/@mui/system/-/system-5.14.10.tgz", - "integrity": "sha512-QQmtTG/R4gjmLiL5ECQ7kRxLKDm8aKKD7seGZfbINtRVJDyFhKChA1a+K2bfqIAaBo1EMDv+6FWNT1Q5cRKjFA==", - "dependencies": { - "@babel/runtime": "^7.22.15", - "@mui/private-theming": "^5.14.10", - "@mui/styled-engine": "^5.14.10", - "@mui/types": "^7.2.4", - "@mui/utils": "^5.14.10", + "version": "5.14.20", + "resolved": "https://registry.npmjs.org/@mui/system/-/system-5.14.20.tgz", + "integrity": "sha512-jKOGtK4VfYZG5kdaryUHss4X6hzcfh0AihT8gmnkfqRtWP7xjY+vPaUhhuSeibE5sqA5wCtdY75z6ep9pxFnIg==", + "dependencies": { + "@babel/runtime": "^7.23.4", + "@mui/private-theming": "^5.14.20", + "@mui/styled-engine": "^5.14.19", + "@mui/types": "^7.2.10", + "@mui/utils": "^5.14.20", "clsx": "^2.0.0", "csstype": "^3.1.2", "prop-types": "^15.8.1" @@ -3140,7 +3250,7 @@ }, "funding": { "type": "opencollective", - "url": "https://opencollective.com/mui" + "url": "https://opencollective.com/mui-org" }, "peerDependencies": { "@emotion/react": "^11.5.0", @@ -3161,11 +3271,11 @@ } }, "node_modules/@mui/types": { - "version": "7.2.4", - "resolved": "https://registry.npmjs.org/@mui/types/-/types-7.2.4.tgz", - "integrity": "sha512-LBcwa8rN84bKF+f5sDyku42w1NTxaPgPyYKODsh01U1fVstTClbUoSA96oyRBnSNyEiAVjKm6Gwx9vjR+xyqHA==", + "version": "7.2.10", + "resolved": "https://registry.npmjs.org/@mui/types/-/types-7.2.10.tgz", + "integrity": "sha512-wX1vbDC+lzF7FlhT6A3ffRZgEoKWPF8VqRoTu4lZwouFX2t90KyCMsgepMw5DxLak1BSp/KP86CmtZttikb/gQ==", "peerDependencies": { - "@types/react": "*" + "@types/react": "^17.0.0 || ^18.0.0" }, "peerDependenciesMeta": { "@types/react": { @@ -3174,12 +3284,12 @@ } }, "node_modules/@mui/utils": { - "version": "5.14.10", - "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-5.14.10.tgz", - "integrity": "sha512-Rn+vYQX7FxkcW0riDX/clNUwKuOJFH45HiULxwmpgnzQoQr3A0lb+QYwaZ+FAkZrR7qLoHKmLQlcItu6LT0y/Q==", + "version": "5.14.20", + "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-5.14.20.tgz", + "integrity": "sha512-Y6yL5MoFmtQml20DZnaaK1znrCEwG6/vRSzW8PKOTrzhyqKIql0FazZRUR7sA5EPASgiyKZfq0FPwISRXm5NdA==", "dependencies": { - "@babel/runtime": "^7.22.15", - "@types/prop-types": "^15.7.5", + "@babel/runtime": "^7.23.4", + "@types/prop-types": "^15.7.11", "prop-types": "^15.8.1", "react-is": "^18.2.0" }, @@ -3188,7 +3298,7 @@ }, "funding": { "type": "opencollective", - "url": "https://opencollective.com/mui" + "url": "https://opencollective.com/mui-org" }, "peerDependencies": { "@types/react": "^17.0.0 || ^18.0.0", @@ -4323,9 +4433,9 @@ "integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==" }, "node_modules/@types/prop-types": { - "version": "15.7.5", - "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz", - "integrity": "sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==" + "version": "15.7.11", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.11.tgz", + "integrity": "sha512-ga8y9v9uyeiLdpKddhxYQkxNDrfvuPrlFb0N1qnZZByvcElJaXthF1UhvCh9TLWJBEHeNtdnbysW7Y6Uq8CVng==" }, "node_modules/@types/reach__router": { "version": "1.3.11", @@ -4345,6 +4455,15 @@ "csstype": "^3.0.2" } }, + "node_modules/@types/react-transition-group": { + "version": "4.4.10", + "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.10.tgz", + "integrity": "sha512-hT/+s0VQs2ojCX823m60m5f0sL5idt9SO6Tj6Dg+rdphGPIeJbJ6CxvBYkgkGKrYeDjvIpKTR38UzmtHJOGW3Q==", + "peer": true, + "dependencies": { + "@types/react": "*" + } + }, "node_modules/@types/responselike": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/@types/responselike/-/responselike-1.0.0.tgz", @@ -7117,6 +7236,16 @@ "utila": "~0.4" } }, + "node_modules/dom-helpers": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.1.tgz", + "integrity": "sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==", + "peer": true, + "dependencies": { + "@babel/runtime": "^7.8.7", + "csstype": "^3.0.2" + } + }, "node_modules/dom-serializer": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz", @@ -14244,6 +14373,22 @@ "node": ">=0.4.0" } }, + "node_modules/react-transition-group": { + "version": "4.4.5", + "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz", + "integrity": "sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==", + "peer": true, + "dependencies": { + "@babel/runtime": "^7.5.5", + "dom-helpers": "^5.0.1", + "loose-envify": "^1.4.0", + "prop-types": "^15.6.2" + }, + "peerDependencies": { + "react": ">=16.6.0", + "react-dom": ">=16.6.0" + } + }, "node_modules/read": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/read/-/read-1.0.7.tgz", @@ -15627,6 +15772,24 @@ "tslib": "^2.0.3" } }, + "node_modules/swiper": { + "version": "11.0.5", + "resolved": "https://registry.npmjs.org/swiper/-/swiper-11.0.5.tgz", + "integrity": "sha512-rhCwupqSyRnWrtNzWzemnBLMoyYuoDgGgspAm/8iBD3jCvAWycPLH4Z3TB0O5520DHLzMx94yUMH/B9Efpa48w==", + "funding": [ + { + "type": "patreon", + "url": "https://www.patreon.com/swiperjs" + }, + { + "type": "open_collective", + "url": "http://opencollective.com/swiper" + } + ], + "engines": { + "node": ">= 4.7.0" + } + }, "node_modules/table": { "version": "6.8.1", "resolved": "https://registry.npmjs.org/table/-/table-6.8.1.tgz", @@ -18263,9 +18426,9 @@ } }, "@babel/runtime": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.22.15.tgz", - "integrity": "sha512-T0O+aa+4w0u06iNmapipJXMV4HoUir03hpx3/YqXXhu9xim3w+dVphjFWl1OH8NbZHw5Lbm9k45drDkgq2VNNA==", + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.23.6.tgz", + "integrity": "sha512-zHd0eUrf5GZoOWVCXp6koAKQTfZV07eit6bGPmJgnZdnSAvvZee6zniW2XMF7Cmc4ISOOnPy3QaSiIJGJkVEDQ==", "requires": { "regenerator-runtime": "^0.14.0" }, @@ -18539,9 +18702,9 @@ } }, "@floating-ui/react-dom": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.0.2.tgz", - "integrity": "sha512-5qhlDvjaLmAst/rKb3VdlCinwTF4EYMiVxuuc/HVUjs46W0zgtbMmAZ1UTsDrRTxRmUEzl92mOtWbeeXL26lSQ==", + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.0.4.tgz", + "integrity": "sha512-CF8k2rgKeh/49UrnIBs4BdxPUV6vize/Db1d/YbCLyp9GiVZ0BEwf5AiDSxJRCr6yOkGqTFHtmrULxkEfYZ7dQ==", "requires": { "@floating-ui/dom": "^1.5.1" } @@ -19168,9 +19331,17 @@ } }, "@mui/core-downloads-tracker": { - "version": "5.14.10", - "resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-5.14.10.tgz", - "integrity": "sha512-kPHu/NhZq1k+vSZR5wq3AyUfD4bnfWAeuKpps0+8PS7ZHQ2Lyv1cXJh+PlFdCIOa0PK98rk3JPwMzS8BMhdHwQ==" + "version": "5.14.20", + "resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-5.14.20.tgz", + "integrity": "sha512-fXoGe8VOrIYajqALysFuyal1q1YmBARqJ3tmnWYDVl0scu8f6h6tZQbS2K8BY28QwkWNGyv4WRfuUkzN5HR3Ow==" + }, + "@mui/icons-material": { + "version": "5.14.19", + "resolved": "https://registry.npmjs.org/@mui/icons-material/-/icons-material-5.14.19.tgz", + "integrity": "sha512-yjP8nluXxZGe3Y7pS+yxBV+hWZSsSBampCxkZwaw+1l+feL+rfP74vbEFbMrX/Kil9I/Y1tWfy5bs/eNvwNpWw==", + "requires": { + "@babel/runtime": "^7.23.4" + } }, "@mui/joy": { "version": "5.0.0-beta.7", @@ -19187,55 +19358,98 @@ "prop-types": "^15.8.1" } }, + "@mui/material": { + "version": "5.14.20", + "resolved": "https://registry.npmjs.org/@mui/material/-/material-5.14.20.tgz", + "integrity": "sha512-SUcPZnN6e0h1AtrDktEl76Dsyo/7pyEUQ+SAVe9XhHg/iliA0b4Vo+Eg4HbNkELsMbpDsUF4WHp7rgflPG7qYQ==", + "peer": true, + "requires": { + "@babel/runtime": "^7.23.4", + "@mui/base": "5.0.0-beta.26", + "@mui/core-downloads-tracker": "^5.14.20", + "@mui/system": "^5.14.20", + "@mui/types": "^7.2.10", + "@mui/utils": "^5.14.20", + "@types/react-transition-group": "^4.4.9", + "clsx": "^2.0.0", + "csstype": "^3.1.2", + "prop-types": "^15.8.1", + "react-is": "^18.2.0", + "react-transition-group": "^4.4.5" + }, + "dependencies": { + "@mui/base": { + "version": "5.0.0-beta.26", + "resolved": "https://registry.npmjs.org/@mui/base/-/base-5.0.0-beta.26.tgz", + "integrity": "sha512-gPMRKC84VRw+tjqYoyBzyrBUqHQucMXdlBpYazHa5rCXrb91fYEQk5SqQ2U5kjxx9QxZxTBvWAmZ6DblIgaGhQ==", + "peer": true, + "requires": { + "@babel/runtime": "^7.23.4", + "@floating-ui/react-dom": "^2.0.4", + "@mui/types": "^7.2.10", + "@mui/utils": "^5.14.20", + "@popperjs/core": "^2.11.8", + "clsx": "^2.0.0", + "prop-types": "^15.8.1" + } + }, + "react-is": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", + "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", + "peer": true + } + } + }, "@mui/private-theming": { - "version": "5.14.10", - "resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-5.14.10.tgz", - "integrity": "sha512-f67xOj3H06wWDT9xBg7hVL/HSKNF+HG1Kx0Pm23skkbEqD2Ef2Lif64e5nPdmWVv+7cISCYtSuE2aeuzrZe78w==", + "version": "5.14.20", + "resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-5.14.20.tgz", + "integrity": "sha512-WV560e1vhs2IHCh0pgUaWHznrcrVoW9+cDCahU1VTkuwPokWVvb71ccWQ1f8Y3tRBPPcNkU2dChkkRJChLmQlQ==", "requires": { - "@babel/runtime": "^7.22.15", - "@mui/utils": "^5.14.10", + "@babel/runtime": "^7.23.4", + "@mui/utils": "^5.14.20", "prop-types": "^15.8.1" } }, "@mui/styled-engine": { - "version": "5.14.10", - "resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-5.14.10.tgz", - "integrity": "sha512-EJckxmQHrsBvDbFu1trJkvjNw/1R7jfNarnqPSnL+jEQawCkQIqVELWLrlOa611TFtxSJGkdUfCFXeJC203HVg==", + "version": "5.14.20", + "resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-5.14.20.tgz", + "integrity": "sha512-Vs4nGptd9wRslo9zeRkuWcZeIEp+oYbODy+fiZKqqr4CH1Gfi9fdP0Q1tGYk8OiJ2EPB/tZSAyOy62Hyp/iP7g==", "requires": { - "@babel/runtime": "^7.22.15", + "@babel/runtime": "^7.23.4", "@emotion/cache": "^11.11.0", "csstype": "^3.1.2", "prop-types": "^15.8.1" } }, "@mui/system": { - "version": "5.14.10", - "resolved": "https://registry.npmjs.org/@mui/system/-/system-5.14.10.tgz", - "integrity": "sha512-QQmtTG/R4gjmLiL5ECQ7kRxLKDm8aKKD7seGZfbINtRVJDyFhKChA1a+K2bfqIAaBo1EMDv+6FWNT1Q5cRKjFA==", - "requires": { - "@babel/runtime": "^7.22.15", - "@mui/private-theming": "^5.14.10", - "@mui/styled-engine": "^5.14.10", - "@mui/types": "^7.2.4", - "@mui/utils": "^5.14.10", + "version": "5.14.20", + "resolved": "https://registry.npmjs.org/@mui/system/-/system-5.14.20.tgz", + "integrity": "sha512-jKOGtK4VfYZG5kdaryUHss4X6hzcfh0AihT8gmnkfqRtWP7xjY+vPaUhhuSeibE5sqA5wCtdY75z6ep9pxFnIg==", + "requires": { + "@babel/runtime": "^7.23.4", + "@mui/private-theming": "^5.14.20", + "@mui/styled-engine": "^5.14.19", + "@mui/types": "^7.2.10", + "@mui/utils": "^5.14.20", "clsx": "^2.0.0", "csstype": "^3.1.2", "prop-types": "^15.8.1" } }, "@mui/types": { - "version": "7.2.4", - "resolved": "https://registry.npmjs.org/@mui/types/-/types-7.2.4.tgz", - "integrity": "sha512-LBcwa8rN84bKF+f5sDyku42w1NTxaPgPyYKODsh01U1fVstTClbUoSA96oyRBnSNyEiAVjKm6Gwx9vjR+xyqHA==", + "version": "7.2.10", + "resolved": "https://registry.npmjs.org/@mui/types/-/types-7.2.10.tgz", + "integrity": "sha512-wX1vbDC+lzF7FlhT6A3ffRZgEoKWPF8VqRoTu4lZwouFX2t90KyCMsgepMw5DxLak1BSp/KP86CmtZttikb/gQ==", "requires": {} }, "@mui/utils": { - "version": "5.14.10", - "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-5.14.10.tgz", - "integrity": "sha512-Rn+vYQX7FxkcW0riDX/clNUwKuOJFH45HiULxwmpgnzQoQr3A0lb+QYwaZ+FAkZrR7qLoHKmLQlcItu6LT0y/Q==", + "version": "5.14.20", + "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-5.14.20.tgz", + "integrity": "sha512-Y6yL5MoFmtQml20DZnaaK1znrCEwG6/vRSzW8PKOTrzhyqKIql0FazZRUR7sA5EPASgiyKZfq0FPwISRXm5NdA==", "requires": { - "@babel/runtime": "^7.22.15", - "@types/prop-types": "^15.7.5", + "@babel/runtime": "^7.23.4", + "@types/prop-types": "^15.7.11", "prop-types": "^15.8.1", "react-is": "^18.2.0" }, @@ -20010,9 +20224,9 @@ "integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==" }, "@types/prop-types": { - "version": "15.7.5", - "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz", - "integrity": "sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==" + "version": "15.7.11", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.11.tgz", + "integrity": "sha512-ga8y9v9uyeiLdpKddhxYQkxNDrfvuPrlFb0N1qnZZByvcElJaXthF1UhvCh9TLWJBEHeNtdnbysW7Y6Uq8CVng==" }, "@types/reach__router": { "version": "1.3.11", @@ -20032,6 +20246,15 @@ "csstype": "^3.0.2" } }, + "@types/react-transition-group": { + "version": "4.4.10", + "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.10.tgz", + "integrity": "sha512-hT/+s0VQs2ojCX823m60m5f0sL5idt9SO6Tj6Dg+rdphGPIeJbJ6CxvBYkgkGKrYeDjvIpKTR38UzmtHJOGW3Q==", + "peer": true, + "requires": { + "@types/react": "*" + } + }, "@types/responselike": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/@types/responselike/-/responselike-1.0.0.tgz", @@ -22089,6 +22312,16 @@ "utila": "~0.4" } }, + "dom-helpers": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.1.tgz", + "integrity": "sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==", + "peer": true, + "requires": { + "@babel/runtime": "^7.8.7", + "csstype": "^3.0.2" + } + }, "dom-serializer": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz", @@ -27112,6 +27345,18 @@ } } }, + "react-transition-group": { + "version": "4.4.5", + "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz", + "integrity": "sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==", + "peer": true, + "requires": { + "@babel/runtime": "^7.5.5", + "dom-helpers": "^5.0.1", + "loose-envify": "^1.4.0", + "prop-types": "^15.6.2" + } + }, "read": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/read/-/read-1.0.7.tgz", @@ -28160,6 +28405,11 @@ "tslib": "^2.0.3" } }, + "swiper": { + "version": "11.0.5", + "resolved": "https://registry.npmjs.org/swiper/-/swiper-11.0.5.tgz", + "integrity": "sha512-rhCwupqSyRnWrtNzWzemnBLMoyYuoDgGgspAm/8iBD3jCvAWycPLH4Z3TB0O5520DHLzMx94yUMH/B9Efpa48w==" + }, "table": { "version": "6.8.1", "resolved": "https://registry.npmjs.org/table/-/table-6.8.1.tgz", diff --git a/package.json b/package.json index 2d77db0..e99c332 100644 --- a/package.json +++ b/package.json @@ -7,6 +7,7 @@ "@emotion/react": "^11.11.1", "@emotion/styled": "^11.11.0", "@fontsource/inter": "^5.0.8", + "@mui/icons-material": "^5.14.19", "@mui/joy": "^5.0.0-beta.7", "change-case": "^4.1.2", "gatsby": "^5.12.4", @@ -19,7 +20,8 @@ "js-yaml": "^4.1.0", "react": "^18.2.0", "react-dom": "^18.2.0", - "react-markdown": "^9.0.0" + "react-markdown": "^9.0.0", + "swiper": "^11.0.5" }, "devDependencies": { "prettier": "^2.8.8" @@ -35,6 +37,7 @@ "start": "gatsby develop", "serve": "gatsby serve", "clean": "gatsby clean", + "cleanstart": "gatsby clean && npm start", "test": "echo \"Write tests! -> https://gatsby.dev/unit-testing\" && exit 1" }, "repository": { diff --git a/plugins/gatsby-source-monday/assemble-columns.js b/plugins/gatsby-source-monday/assemble-columns.js new file mode 100644 index 0000000..17166d5 --- /dev/null +++ b/plugins/gatsby-source-monday/assemble-columns.js @@ -0,0 +1,30 @@ +const columnMap = require('./column-map') + +/* This function massages column data into a form suitable for building + * position filters client-side. Our filters are select boxes, so we'll + * only need to consider columns with enumerable possible values; that is + * only those with a type of `status`. Additionally, we only care about + * those appearing in the `columnMap` object. + * + * @param array columns Monday response columns defined in query above. + * + * @return array columns as objects. + * */ +module.exports = function assembleColumnData({ columns }) { + return columns.reduce((acc, column) => { + const { id, title, type, settings_str } = column + const { labels = {} } = JSON.parse(settings_str) + if (title in columnMap && type === 'status') { + acc.push({ + id, + // `field` defines the property on position objects, + // client-side, that correpond to this column on positions. + field: columnMap[title], + options: Object.values(labels), + title, + }) + } + return acc + }, []) +} + diff --git a/plugins/gatsby-source-monday/assemble-positions.js b/plugins/gatsby-source-monday/assemble-positions.js new file mode 100644 index 0000000..ac9ba8a --- /dev/null +++ b/plugins/gatsby-source-monday/assemble-positions.js @@ -0,0 +1,25 @@ +const columnMap = require('./column-map') + +/* This function massages row data into an array of position objects + * with fields defined by `columnMap` + * + * @param array columns Monday response columns defined in query above. + * @param array items Monday response items defined in query above. + * + * @return array positions as objects. + * */ +module.exports = function assemblePositionData({ groups }) { + if (!groups) { return } + return groups[0].items_page.items.reduce((acc, item) => { + const { id, name, column_values } = item + const extractedColumnValues = column_values + .reduce((acc, { column, text }) => { + if (column.title in columnMap) { + acc[columnMap[column.title]] = text + } + return acc + }, {}) + acc.push({ id, name, ...extractedColumnValues }) + return acc + }, []) +} \ No newline at end of file diff --git a/plugins/gatsby-source-monday/column-map.js b/plugins/gatsby-source-monday/column-map.js new file mode 100644 index 0000000..5607539 --- /dev/null +++ b/plugins/gatsby-source-monday/column-map.js @@ -0,0 +1,14 @@ +// columns (keys) end up as item object properties (values) +module.exports = { + 'Minimum Education': 'education', + 'RENCI Domain': 'domain', + 'Group': 'group', + 'Project/Team Name': 'division', + 'Semester': 'semester', + 'Anticipated Start Date': 'startDate', + 'Estimated Duration (in weeks)': 'duration', + 'Project Abstract': 'abstract', + 'Position Description': 'description', + 'Pay Range': 'pay', + 'PD Link': 'url', +} diff --git a/plugins/gatsby-source-monday/fetch-board-data.js b/plugins/gatsby-source-monday/fetch-board-data.js new file mode 100644 index 0000000..9243d2f --- /dev/null +++ b/plugins/gatsby-source-monday/fetch-board-data.js @@ -0,0 +1,16 @@ +const axios = require('axios') +const query = require('./query') +const API_URL = `https://api.monday.com/v2` + +module.exports = async function fetchBoardData(options) { + try { + const response = await axios.post(API_URL, { query }, options) + if (response?.status !== 200 || !response?.data) { + return + } + return response.data.data + } catch (error) { + console.error(error) + return [] + } +} diff --git a/plugins/gatsby-source-monday/gatsby-node.js b/plugins/gatsby-source-monday/gatsby-node.js new file mode 100644 index 0000000..61fdfcb --- /dev/null +++ b/plugins/gatsby-source-monday/gatsby-node.js @@ -0,0 +1,52 @@ +const fs = require('fs') + +const fetchBoardData = require('./fetch-board-data') + +const axiosOptions = { headers: { + 'API-Version': '2023-10', +} } + +exports.sourceNodes = async (gatsbyApi, pluginOptions) => { + const { actions, createContentDigest, createNodeId, reporter } = gatsbyApi + const timer = reporter.activityTimer(`source Monday.com boards`) + + function createBoardNode(data) { + // console.log(JSON.stringify(data, null, 2)) + actions.createNode({ + ...data, + parent: null, + children: [], + internal: { + type: 'MondayBoard', + contentDigest: createContentDigest(data) + }, + }) + } + + timer.start() + try { + // fetch the board data + axiosOptions.headers.Authorization = `bearer ${ pluginOptions.API_TOKEN }` + timer.setStatus(`Fetching board data`) + const boardData = await fetchBoardData(axiosOptions) + if (!boardData) { + throw new Error(`Failed to fetch board data`) + } + + // create board nodes + timer.setStatus(`Assembling board data`) + if (!boardData) { + throw new Error(`Failed to process board data`) + } + timer.setStatus(`Sourced ${ Object.keys(boardData).length } boards`) + Object.keys(boardData).forEach(key => { + createBoardNode(boardData[key][0]) + }) + timer.setStatus(`Created ${ Object.keys(boardData).length } board nodes`) + } catch (error) { + timer.panicOnBuild(error) + timer.setStatus(`Could not source boards from API.`) + } +} + + diff --git a/plugins/gatsby-source-monday/package-lock.json b/plugins/gatsby-source-monday/package-lock.json new file mode 100644 index 0000000..285b482 --- /dev/null +++ b/plugins/gatsby-source-monday/package-lock.json @@ -0,0 +1,115 @@ +{ + "name": "gatsby-source-monday", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "gatsby-source-monday", + "version": "1.0.0", + "license": "ISC", + "devDependencies": { + "axios": "^1.5.0" + } + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "dev": true + }, + "node_modules/axios": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.5.0.tgz", + "integrity": "sha512-D4DdjDo5CY50Qms0qGQTTw6Q44jl7zRwY7bthds06pUGfChBCTcQs+N743eFWGEd6pRTMd6A+I87aWyFV5wiZQ==", + "dev": true, + "dependencies": { + "follow-redirects": "^1.15.0", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" + } + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dev": true, + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/follow-redirects": { + "version": "1.15.3", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.3.tgz", + "integrity": "sha512-1VzOtuEM8pC9SFU1E+8KfTjZyMztRsgEfwQl44z8A25uy13jSzTj6dyK2Df52iV0vgHCfBwLhDWevLn95w5v6Q==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "dev": true, + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dev": true, + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", + "dev": true + } + } +} diff --git a/plugins/gatsby-source-monday/package.json b/plugins/gatsby-source-monday/package.json new file mode 100644 index 0000000..926bbc1 --- /dev/null +++ b/plugins/gatsby-source-monday/package.json @@ -0,0 +1,15 @@ +{ + "name": "gatsby-source-monday", + "version": "1.0.0", + "description": "", + "main": "gatsby-node.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "keywords": [], + "author": "", + "license": "ISC", + "devDependencies": { + "axios": "^1.5.0" + } +} diff --git a/plugins/gatsby-source-monday/query.js b/plugins/gatsby-source-monday/query.js new file mode 100644 index 0000000..7d43245 --- /dev/null +++ b/plugins/gatsby-source-monday/query.js @@ -0,0 +1,56 @@ +module.exports = `query { + dates: boards(ids:[6391840129]) { + id + columns(ids: ["date6","date4","date","date5","date42","status5"]) { + id + settings_str + title + type + } + + groups(ids:["topics"]) { + id + title + items_page { + items { + id + name + column_values(ids: ["date6","date4","date","date5","date42","status5"]) { + id + text + } + } + } + } + } + + positions: boards(ids:[5267641585]) { + id + columns { + id + settings_str + title + type + } + groups(ids: ["group_title", "topics", "new_group"]) { + id + title + items_page { + cursor + items { + id + name + column_values { + id + text + column { + id + title + } + value + } + } + } + } + } +}` \ No newline at end of file diff --git a/plugins/gatsby-source-monday/sample-data.json b/plugins/gatsby-source-monday/sample-data.json new file mode 100644 index 0000000..451461a --- /dev/null +++ b/plugins/gatsby-source-monday/sample-data.json @@ -0,0 +1,83 @@ +{ + "positions": [ + { + "id": "sample-pos-1", + "name": "Sample position 1", + "education": "Undergraduate: Freshman/Sophomore", + "domain": "Research", + "group": "Software Architecture", + "division": "HeLx, EduHeLx, ORDR-D", + "semester": "Spring Semester", + "startDate": "2024-01-10", + "duration": "16", + "abstract": "Ut pariatur laborum laborum eu ex eu ullamco adipisicing sit.", + "description": "In nisi officia labore duis exercitation culpa fugiat dolore est.", + "pay": "$12-$18 per hour", + "url": "https://example.com/" + }, + { + "id": "sample-pos-2", + "name": "Sample position 2", + "education": "Undergraduate: Freshman/Sophomore", + "domain": "Collaborations", + "group": "National Consortium for Data Science", + "division": "National Consortium for Data Science", + "semester": "Spring Semester", + "startDate": "2024-01-10", + "duration": "12 weeks", + "abstract": "Ut occaecat in cupidatat ullamco officia adipisicing aliqua et nostrud ut.", + "description": "Amet veniam labore commodo ea deserunt nisi non dolore amet exercitation irure proident ad irure.", + "pay": "$12-18 per hour", + "url": "https://example.com/" + } + ], + "columns": [ + { + "id": "status8", + "field": "education", + "options": [ + "Undergraduate: Freshman/Sophomore", + "Undergraduate: Junior/Senior", + "Graduate" + ], + "title": "Minimum Education" + }, + { + "id": "status", + "field": "domain", + "options": [ "Research", "Operations", "Collaborations" ], + "title": "RENCI Domain" + }, + { + "id": "status1", + "field": "group", + "options": [ + "Office of the Director", + "Project Management", + "Coordination Team", + "Finance", + "Earth Data Science", + "Data Science & Analytics", + "Clinical Informatics", + "Software Architecture", + "Networking Research & Infrastructure", + "Advanced Cyber Infrastructure Support", + "Communications", + "Human Resources", + "BioData Catalyst Coordinating Center", + "NIH Heal Data Stewardship Group", + "National Consortium for Data Science", + "RADx Data Hub", + "iRODS Consortium", + "South Big Data Hub" + ], + "title": "Group" + }, + { + "id": "status3", + "field": "semester", + "options": [ "Spring Semester", "Fall Semester", "Summer Semester" ], + "title": "Semester" + } + ] +} diff --git a/plugins/gatsby-transformer-monday/assemble-columns.js b/plugins/gatsby-transformer-monday/assemble-columns.js new file mode 100644 index 0000000..df934de --- /dev/null +++ b/plugins/gatsby-transformer-monday/assemble-columns.js @@ -0,0 +1,29 @@ +const columnMap = require('./column-map') + +/* This function massages column data into a form suitable for building + * position filters client-side. Our filters are select boxes, so we'll + * only need to consider columns with enumerable possible values; that is + * only those with a type of `status`. Additionally, we only care about + * those appearing in the `columnMap` object. + * + * @param array columns Monday response columns defined in query above. + * + * @return array columns as objects. + * */ +module.exports = function assembleColumnData({ columns }) { + return columns.reduce((acc, column) => { + const { id, title, type, settings_str } = column + const { labels = {} } = JSON.parse(settings_str) + if (title in columnMap && type === 'status') { + acc.push({ + id, + // `field` defines the property on position objects, + // client-side, that correpond to this column on positions. + field: columnMap[title], + options: Object.values(labels), + title, + }) + } + return acc + }, []) +} diff --git a/plugins/gatsby-transformer-monday/assemble-dates.js b/plugins/gatsby-transformer-monday/assemble-dates.js new file mode 100644 index 0000000..f24051e --- /dev/null +++ b/plugins/gatsby-transformer-monday/assemble-dates.js @@ -0,0 +1,36 @@ +/* This function massages row data into an array of date objects. + * + * @param array columns Monday response columns. + * + * @return array dates as objects. + * */ +module.exports = function assembleDatesData({ columns, groups }) { + + const years = columns + .filter(col => col.type === 'date') + .reduce((acc, col) => { + acc[col.id] = col.title + return acc + }, {}) + const dates = groups[0].items_page.items.map(item => { + // the `Viewer` column has `id` of `status5` in the Monday board. + const audience = item.column_values.find(col => col.id === 'status5').text + const values = item.column_values + .filter(col => col.id.startsWith('date')) + .reduce((acc, { id, text }) => { + acc.push({ + date: text, + year: years[id], + }) + return acc + }, []) + return { + id: item.id, + name: item.name, + dates: values, + audience, + } + }) + + return dates +} \ No newline at end of file diff --git a/plugins/gatsby-transformer-monday/assemble-positions.js b/plugins/gatsby-transformer-monday/assemble-positions.js new file mode 100644 index 0000000..c4d1bb5 --- /dev/null +++ b/plugins/gatsby-transformer-monday/assemble-positions.js @@ -0,0 +1,32 @@ +const columnMap = require('./column-map') + +/* This function massages row data into an array of position objects + * with fields defined by `columnMap.positions` + * + * @param array groups Monday response groups defined in query. + * + * @return array positions as objects. + * */ +module.exports = function assemblePositionData({ groups }) { + if (!groups) { return } + return groups.reduce((acc, group) => { + acc.push(...group.items_page.items.reduce((itemAcc, item) => { + const { id, name, column_values } = item + const extractedColumnValues = column_values + .reduce((itemAcc, { column, text }) => { + if (column.title in columnMap) { + itemAcc[columnMap[column.title]] = text + } + return itemAcc + }, {}) + itemAcc.push({ + id, + name, + status: group.title, + ...extractedColumnValues, + }) + return itemAcc + }, [])) + return acc + }, []) +} \ No newline at end of file diff --git a/plugins/gatsby-transformer-monday/column-map.js b/plugins/gatsby-transformer-monday/column-map.js new file mode 100644 index 0000000..5607539 --- /dev/null +++ b/plugins/gatsby-transformer-monday/column-map.js @@ -0,0 +1,14 @@ +// columns (keys) end up as item object properties (values) +module.exports = { + 'Minimum Education': 'education', + 'RENCI Domain': 'domain', + 'Group': 'group', + 'Project/Team Name': 'division', + 'Semester': 'semester', + 'Anticipated Start Date': 'startDate', + 'Estimated Duration (in weeks)': 'duration', + 'Project Abstract': 'abstract', + 'Position Description': 'description', + 'Pay Range': 'pay', + 'PD Link': 'url', +} diff --git a/plugins/gatsby-transformer-monday/gatsby-node.js b/plugins/gatsby-transformer-monday/gatsby-node.js new file mode 100644 index 0000000..ec98bba --- /dev/null +++ b/plugins/gatsby-transformer-monday/gatsby-node.js @@ -0,0 +1,98 @@ +const assemblePositionData = require('./assemble-positions') +const assembleColumnData = require('./assemble-columns') +const assembleDatesData = require('./assemble-dates') + +const DEBUG = true + +async function onCreateNode({ + actions, + createContentDigest, + loadNodeContent, + node, + reporter, +}) { + const timer = reporter.activityTimer(`transforming Monday.com boards`) + + timer.setStatus(`Look for boards`) + + if (!node) { + return + } + + if (node.internal.type !== 'MondayBoard') { + return + } + + + const createPositionNodes = positionData => { + timer.setStatus(`Create PositionItem nodes`) + for (const position of positionData) { + actions.createNode({ + ...position, + parent: null, + children: [], + internal: { + type: 'PositionItem', + contentDigest: createContentDigest(position) + } + }) + } + } + + const createColumnNodes = columnData => { + timer.setStatus(`Create PositionColumn nodes`) + for (const column of columnData) { + actions.createNode({ + ...column, + parent: null, + children: [], + internal: { + type: 'PositionColumn', + contentDigest: createContentDigest(column) + } + }) + } + } + + const createDateNodes = datesData => { + timer.setStatus(`Create ImportantDate nodes`) + datesData.forEach(date => { + actions.createNode({ + ...date, + parent: null, + children: [], + internal: { + type: 'ImportantDate', + contentDigest: createContentDigest(date) + } + }) + }) + } + + try { + if (node.id === `6391840129`) { + const datesData = assembleDatesData(node) + if (DEBUG) { console.log(JSON.stringify(datesData, null, 2)) } + createDateNodes(datesData) + timer.setStatus(`Created ImportantDate nodes`) + } + + if (node.id === `5267641585`) { + const positionData = assemblePositionData(node) + if (DEBUG) { console.log(JSON.stringify(positionData, null, 2)) } + createPositionNodes(positionData) + timer.setStatus(`Created PositionItem nodes`) + + const columnData = assembleColumnData(node) + if (DEBUG) { console.log(JSON.stringify(columnData, null, 2)) } + createColumnNodes(columnData) + timer.setStatus(`Created PositionColumn nodes`) + } + } catch (error) { + timer.panicOnBuild(error) + timer.setStatus(`Could not transform Monday.com position and dates boards.`) + } + +} + +exports.onCreateNode = onCreateNode diff --git a/plugins/gatsby-transformer-monday/package.json b/plugins/gatsby-transformer-monday/package.json new file mode 100644 index 0000000..d3ed001 --- /dev/null +++ b/plugins/gatsby-transformer-monday/package.json @@ -0,0 +1,12 @@ +{ + "name": "gatsby-transformer-monday", + "version": "1.0.0", + "description": "", + "main": "gatsby-node.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "keywords": [], + "author": "", + "license": "ISC" +} diff --git a/src/components/button.js b/src/components/button.js new file mode 100644 index 0000000..2ecfd57 --- /dev/null +++ b/src/components/button.js @@ -0,0 +1,35 @@ +import React from 'react' +import { Button as MUIButton, Typography} from '@mui/joy' +import { Link } from './link' +import OpenInNew from '@mui/icons-material/OpenInNew'; + +export const Button = ({children, to, large, external, color, text, hero, ...props}) => { + + return ( + } + + sx={{ + padding: large ? '1rem 3rem' : '0.5rem 2rem', + backgroundColor: color, + ':hover': { + backgroundColor: `${color}99` + }, + filter: hero ? 'drop-shadow(5px 5px 8px #00000090);' : null + }} + > + + {children} + + + ) +} diff --git a/src/components/carousel.js b/src/components/carousel.js new file mode 100644 index 0000000..d171c3d --- /dev/null +++ b/src/components/carousel.js @@ -0,0 +1,68 @@ +import React from 'react'; +// Import Swiper React components +import { Swiper, SwiperSlide } from 'swiper/react'; +import 'swiper/css'; +import 'swiper/css/pagination'; +import 'swiper/css/navigation'; +import { Keyboard, Navigation, Pagination } from 'swiper/modules'; + +import { StudentSlide, MobileSlide } from './student-slide' + +export const Carousel = ({students}) => { + + return ( + + { + students.map((student) => ( + + + + )) + } + + ); +} + +export const MobileCarousel = ({students}) => { + + return ( + + { + students.map((student) => ( + + + + )) + } + + ) +} \ No newline at end of file diff --git a/src/components/container.js b/src/components/container.js index f0418a7..a21a58c 100644 --- a/src/components/container.js +++ b/src/components/container.js @@ -5,6 +5,7 @@ export const Container = ({ children, className = 'container', // allows custom styling maxWidth = '1200px', + sx = {}, }) => { return ( { children } diff --git a/src/components/cta-button.js b/src/components/cta-button.js new file mode 100644 index 0000000..5c5492b --- /dev/null +++ b/src/components/cta-button.js @@ -0,0 +1,78 @@ +import React from 'react' +import { + AspectRatio, Card, CardOverflow, + Link as JoyLink, Typography +} from '@mui/joy' +import { GatsbyImage, getImage } from 'gatsby-plugin-image' +import { Link } from './link' +import NavigateNextIcon from '@mui/icons-material/NavigateNext'; +import DownloadIcon from '@mui/icons-material/Download'; + +export const CtaButton = ({ + background_image, href, title, backgroundColor, interview +}) => { + const bgImage = getImage(background_image) + return ( + + + { + interview ? ( + + + + ) : ( + + + + ) + } + + + + { + interview ? ( + + { title } + + ) : ( + + { title } + + + ) + } + + + + ) +} \ No newline at end of file diff --git a/src/components/dates-table.js b/src/components/dates-table.js new file mode 100644 index 0000000..c609447 --- /dev/null +++ b/src/components/dates-table.js @@ -0,0 +1,75 @@ +import React from 'react' +import {Table, Box} from "@mui/joy/" + +export const DatesTable = ({content, type}) => { + const createDatesArray = (content) => { + const { date_titles, dates } = content + const keysArray = Object.keys(date_titles) + + return keysArray.map((key) => { + const semesterDates = dates.map((date) => date.semester_dates[key]); + return [date_titles[key], ...semesterDates]; + }); + } + + const datesArray = createDatesArray(content) + + const studentsArray = [ + datesArray[2], + datesArray[3], + datesArray[4], + datesArray[5], + datesArray[7], + datesArray[8], + datesArray[9] + ] + + const staffArray = [ + datesArray[0], + datesArray[1], + datesArray[2], + datesArray[4], + datesArray[6], + datesArray[7], + datesArray[8] + ] + return ( + + + + + + + {content.dates.map(({semester}, i) => ( + + ))} + + + + { type==="students" ? studentsArray.map((row, rowIndex) => ( + + {row.map((cell, cellIndex) => ( + + ))} + + )) : staffArray.map((row, rowIndex) => ( + + {row.map((cell, cellIndex) => ( + + ))} + + ))} + +
{semester}
{cell}
{cell}
+
+ + ) +} \ No newline at end of file diff --git a/src/components/footer.js b/src/components/footer.js index bc8f1ce..2d4fec7 100644 --- a/src/components/footer.js +++ b/src/components/footer.js @@ -1,7 +1,9 @@ import React from 'react' import { graphql, useStaticQuery } from 'gatsby' -import { Sheet, Typography } from '@mui/joy' -import { Container } from './container' +import { Typography, Box, Container, Grid, useTheme } from '@mui/joy' +// import { Container } from './container' +import { Link } from './link' +import starRenciLogo from '../images/star-renci-logo-combined.png' export const Footer = () => { const data = useStaticQuery(graphql` @@ -9,33 +11,75 @@ export const Footer = () => { themeYaml { footer { copyright + email + socials { + name + url + } } } } `) + const theme = useTheme() return ( - - - - © { new Date().getFullYear() } · { data.themeYaml.footer.copyright } - + + + + + + + + Student Achievement at RENCI + Europa Center + 100 Europa Drive, Suite 540 + Chapel Hill, NC 27517 + {data.themeYaml.footer.email} + 919-445-9640 + + + Stay Connected with RENCI +
    + { + data.themeYaml.footer.socials.map((item) => ( +
  • {item.name}
  • + )) + } +
+
+ + + © { new Date().getFullYear() } + +
-
+ ) } -export default Footer +export default Footer \ No newline at end of file diff --git a/src/components/header.js b/src/components/header.js index 3338aac..1dddba9 100644 --- a/src/components/header.js +++ b/src/components/header.js @@ -2,9 +2,9 @@ import React, { useMemo } from 'react' import { useStaticQuery, graphql } from 'gatsby' import { Sheet } from '@mui/joy' import { Container } from './container' -import { useScrolling } from '../hooks' -import { Link } from './link' +import { useScrolling, useWindowWidth } from '../hooks' import { Menu } from './menu' +import { MobileMenu } from './mobile-menu' const Header = ({ siteTitle, menuOptions }) => { const data = useStaticQuery(graphql` @@ -16,6 +16,7 @@ const Header = ({ siteTitle, menuOptions }) => { } } `) + const { isCompact } = useWindowWidth(); const { scrollPosition } = useScrolling() @@ -29,14 +30,11 @@ const Header = ({ siteTitle, menuOptions }) => { { display: 'flex', alignItems: 'center', justifyContent: 'flex-start', + m: 0, + p: 0 }, px: 1, - minHeight: reducedHeader ? '3rem' : '5rem', - '.brand': { - p: 1, - alignSelf:'stretch', - display: 'flex', - justifyContent: 'center', - alignItems: 'center', - }, + minHeight: reducedHeader ? '3.5rem' : '4.5rem', + }} > - { data.themeYaml.metadata.title } - + + { + isCompact ? : + } + ) diff --git a/src/components/hero.js b/src/components/hero.js index 39ef08a..9fdd160 100644 --- a/src/components/hero.js +++ b/src/components/hero.js @@ -2,14 +2,24 @@ import React, { useEffect, useRef } from 'react' import PropTypes from 'prop-types' import { GatsbyImage, getImage } from 'gatsby-plugin-image' import { - Button, FormControl, Input, Sheet, Stack, Typography, + Sheet, Stack, Typography, Box } from '@mui/joy' import { useScrolling } from '../hooks' +import { Button } from './button' +import { Link } from './link' +import { useWindowWidth } from '../hooks' -export const Hero = ({ background_image, blurb, title }) => { +export const Hero = ({ + background_image, + blurb, + title, + titleColor, + buttons +}) => { const heroImage = getImage(background_image) const { scrollPosition } = useScrolling() const heroRef = useRef() + const { isCompact } = useWindowWidth(); useEffect(() => { if (!heroRef.current) return @@ -21,29 +31,42 @@ export const Hero = ({ background_image, blurb, title }) => { ref={ heroRef } sx={{ display: 'flex', - height: '600px', + height: isCompact ? '650px' :'600px', position: 'relative', '.background-image': { position: 'absolute', - left: 0, top: 0, width: '100%', height: '600px', + left: 0, top: 0, width: '100%', height: isCompact ? '650px' :'600px', }, '.overlay': { zIndex: 8, - px: 4, margin: 'auto', - width: '1200px', + width: '100%', + height:'100%', + background: isCompact? 'linear-gradient(145deg, #000 0%, #00000020 100%)' :'linear-gradient(90deg, #000 0%, rgba(0, 0, 0, 0) 100%)', + '.content': { + zIndex: 9, + maxWidth: '1200px', + margin: 'auto', + px: isCompact ? 1: 0, + height:'100%', + }, '.title': { - maxWidth: '66%', - fontSize: '400%', - backgroundColor: '#cccc', + maxWidth: isCompact ? '100% ':'66%', + fontSize: isCompact ? '250% ':'400%', + color: '#EDCB5B', p: 1, + letterSpacing: '1px', + fontWeight: '300' }, '.subtitle': { - maxWidth: '66%', - fontSize: '120%', - backgroundColor: '#cccc', - lineHeight: 1.75, + maxWidth: isCompact ? '100%':'55%', + fontSize: isCompact ? '130%' :'150%', + color: '#fff', + lineHeight: 1.5, p: 1, + letterSpacing: '0.01px', + fontWeight: '500', + filter: 'drop-shadow(5px 5px 5px black)' }, '.search-button': { borderTopLeftRadius: 0, @@ -53,29 +76,41 @@ export const Hero = ({ background_image, blurb, title }) => { }} > + - { title } - { blurb } - - Search - } - sx={{ '--Input-decoratorChildHeight': '45px' }} - /> - + + { title } + { blurb } + + {buttons && ( + + {buttons.map((button)=> ( + + ))} + + )} + ) } diff --git a/src/components/layout.js b/src/components/layout.js index e4a0faa..7cc09ea 100644 --- a/src/components/layout.js +++ b/src/components/layout.js @@ -1,33 +1,29 @@ import React, { Fragment } from 'react' import { CssBaseline, Sheet } from '@mui/joy' - import Header from './header' import Footer from './footer' -export const Layout = ({ children }) => { - return ( - - - -
- -
- { children } -
+export const Layout = ({ children }) => ( + + + +
+ +
+ { children } +
-