Storybook + MUI5 + Nextjs - theme issue? - reactjs

I finally managed to get SB working with mui4, but after upgrading the mui5, i can't get it going.
installed with Npx sb init —builder webpack5
updated sb main.js as per
Complained that "compressible' module couldn't be found so installed that.
Ran npm i core-js#3.8.2 as gives out about es-weak-map + others not found.
Added web pack 5 as a dev dependency npm install webpack#5 --save-dev
npx sb#next upgrade --prerelease.
plus literally every other suggestion i came across online, which you can see in these files (leaving some comments in so you can see what else i tried in some cases)
.storybook>main.js
const path = require('path');
const toPath = filePath => path.join(process.cwd(), filePath);
module.exports = {
stories: ['../src/**/*.stories.mdx', '../src/**/*.stories.#(js|jsx|ts|tsx)'],
addons: [
'#storybook/addon-links',
'#storybook/addon-essentials',
'#storybook/addon-interactions',
// 'storybook-addon-designs',
// 'storybook-anima',
// '#storybook/addon-actions',
{
name: '#storybook/addon-docs',
options: {
configureJSX: true,
babelOptions: {},
sourceLoaderOptions: null,
transcludeMarkdown: true,
},
},
'#storybook/builder-webpack5',
],
framework: '#storybook/react',
core: {
// builder: '#storybook/builder-webpack5',
builder: 'webpack5',
},
typescript: { reactDocgen: false },
features: {
emotionAlias: false,
modernInlineRendering: true,
},
webpackFinal: async (config, { configType }) => {
config.resolve.modules = [path.resolve(__dirname, '..', '.'), 'node_modules'];
config.resolve.alias = {
...config.resolve.alias,
'#emotion/core': toPath('node_modules/#emotion/react'),
'emotion-theming': toPath('node_modules/#emotion/react'),
// 'core-js/modules/es.weak-map.js': toPath('core-js/modules/es6.weak-map.js'),
};
return config;
// return {
// ...config,
// resolve: {
// ...config.resolve,
// alias: {
// ...config.resolve.alias,
// '#emotion/core': toPath('node_modules/#emotion/react'),
// 'emotion-theming': toPath('node_modules/#emotion/react'),
// },
// },
// };
},
};
.package.json
{ "dependencies": {
"#auth0/nextjs-auth0": "^1.7.0",
"#emotion/react": "^11.8.2",
"#emotion/styled": "^11.8.1",
"#material-ui/core": "^4.12.0",
"#material-ui/icons": "^4.11.2",
"#material-ui/lab": "^4.0.0-alpha.60",
"#mui/icons-material": "^5.5.1",
"#mui/lab": "^5.0.0-alpha.75",
"#mui/material": "^5.5.3",
"#mui/styles": "^5.5.3",
"core-js": "^3.8.2",
"cors": "^2.8.5",
"next": "^12.1.4",
"react": "latest",
},
"devDependencies": {
"#storybook/addon-actions": "^6.5.0-alpha.59",
"#storybook/addon-essentials": "^6.5.0-alpha.59",
"#storybook/addon-interactions": "^6.5.0-alpha.59",
"#storybook/addon-links": "^6.5.0-alpha.59",
"#storybook/builder-webpack5": "^6.5.0-alpha.59",
"#storybook/manager-webpack5": "^6.5.0-alpha.59",
"#storybook/node-logger": "^6.5.0-alpha.59",
"#storybook/preset-create-react-app": "^4.1.0",
"#storybook/react": "^6.5.0-alpha.59",
"#storybook/testing-library": "^0.0.9",
"#svgr/webpack": "^6.2.1",
"compressible": "^2.0.18",
"webpack": "^5.72.0"
},
"eslintConfig": {
"overrides": [
{"files": ["**/*.stories.*"],
"rules": {"import/no-anonymous-default-export": "off"}
}]
},
"resolutions": {"#storybook/{app}/webpack": "^5"}
}
my Story
// import { ThemeProvider } from '#mui/styles';
import { ThemeProvider as MUIThemeProvider, createTheme } from '#mui/material/styles';
import { ThemeProvider } from 'emotion-theming';
import React from 'react';
//import theme from 'src/themes/theme.js';
// import DuplicateComponent from 'src/components/helpers/DuplicateComponent';
// import TickerTicket from 'src/components/modules/dashboard/TickerTicket';
import DataLanes from '.';
export default {
title: 'components/common/dataDisplay/DataLanes',
component: DataLanes,
};
export const Bare = () => (
// <MUIThemeProvider theme={theme}>
// <ThemeProvider theme={theme}>
<DataLanes borderBottom>
<div>1</div>
<div>2</div>
<div>3</div>
</DataLanes>
// </ThemeProvider>
// </MUIThemeProvider>
);
My Component
import { Box } from '#mui/material';
import clsx from 'clsx';
import React from 'react';
import PropTypes from 'prop-types';
import useStyles from './styles';
export default function DataLanes(props) {
const classes = useStyles();
const { borderBottom, borderTop, className, children, ...others } = props;
return (
<Box
className={clsx(classes.dataLanes, className, {
borderBottom: borderBottom,
borderTop: borderTop,
})}
{...others}
>
{children}
</Box>
);
}
its styling
import makeStyles from '#mui/styles/makeStyles';
const useStyles = makeStyles(theme => ({
dataLanes: {
width: '100%',
background: theme.palette.background.paper,
display: 'flex',
paddingTop: theme.spacing(1),
paddingBottom: theme.spacing(1),
overflowY: 'auto',
'& > * ': {
flexGrow: 1,
borderRight: `1px solid ${theme.palette.grey[300]}`,
},
'&.borderBottom': {
borderBottom: `1px solid ${theme.palette.grey[300]}`,
},
'&.borderTop': {
borderTop: `1px solid ${theme.palette.grey[300]}`,
},
},
}));
export default useStyles;
Any thoughts? It seems like it's the background: theme.palette.background.paper,
in the style.js.

For similar issues I encountered with MUI and storybook this change at the preview.js in the .storybook folder solved it.
.storybook>preview.js
import React from 'react';
import { addDecorator } from '#storybook/react';
import { ThemeProvider } from '#mui/material/styles';
import { theme } from '../src/Theme'; //. Please replace the path for the theme with yours.
export const parameters = {
actions: { argTypesRegex: '^on[A-Z].*' },
controls: {
matchers: {
color: /(background|color)$/i,
date: /Date$/,
},
},
};
addDecorator(story => <ThemeProvider theme={theme}>{story()}</ThemeProvider>);

Related

Storybook play function doesn't show interactions in the bottom panel

I am using storybook interactions addon and the play functionality. This is my code:
export default {
component: MyComponent,
title: "My Component",
args: {
someId: "someId",
},
decorators: [
(Story) => (
<QueryClientProvider client={queryClient}>
<Header />
<Box sx={{ float: "right" }}>
<Layout>
<Story />
</Layout>
</Box>
</QueryClientProvider>
),
],
} as ComponentMeta<typeof MyComponent>;
const Template: ComponentStory<typeof MyComponent> = (args: any) => {
return <MyComponent {...args} />;
};
export const MyComponentWithInteraction = Template.bind({});
MyComponentWithInteraction.play = async ({ canvasElement }) => {
const canvas = within(canvasElement);
const addButton = canvas.getAllByText("+ Add")[0];
await userEvent.click(addButton);
};
My component appears on my storybook, but the interaction tab shows no interactions:
These are the packages related to storybook in my devDependencise
"#storybook/addon-essentials": "6.5.16",
"#storybook/addon-interactions": "6.5.16",
"#storybook/addon-knobs": "^6.4.0",
"#storybook/builder-webpack5": "6.5.16",
"#storybook/jest": "0.0.10",
"#storybook/manager-webpack5": "6.5.16",
"#storybook/react": "^6.5.15",
"#storybook/testing-library": "0.0.13",
"#types/storybook__addon-knobs": "^5.2.1",
"#types/storybook__react": "^5.2.1",
"msw-storybook-addon": "1.7.0",
"tsconfig-paths-webpack-plugin": "4.0.0",
"webpack": "5"
This is my main.ts
module.exports = {
stories: ["../src/**/*.stories.#(mdx|tsx|ts|jsx|js)"],
logLevel: "debug",
addons: [
"#storybook/addon-essentials",
"#storybook/addon-links",
"#storybook/addon-interactions",
"msw-storybook-addon",
],
framework: "#storybook/react",
features: {
interactionsDebugger: true,
},
webpackFinal: async (config, { configType }) => {
config.module.rules.push({
include: path.resolve(__dirname, "../src"),
});
config.resolve.plugins = [
new TsconfigPathsPlugin({
configFile: path.resolve(__dirname, "../tsconfig.json"),
}),
];
// Return the altered config
return config;
},
core: {
builder: "#storybook/builder-webpack5",
},
docs: {
autodocs: true,
},
};
If I add this line of code at the end of my story:
await expect(canvas.getByText("Some text")).toBeInTheDocument();
I see that it fails, because it is comparing it against the initial view before the click. But if I get rid of this line, it shows me the view that is the result of the click. I don't see any running in the control tab of the bottom panel either. This is strange.
I found the issue, although it is not shown in my question, I'm going to answer it here ,maybe I can save someone from spending 3-4 hours on this. my imports looked like this which was wrong:
import { within } from "#testing-library/react";
import userEvent from "#testing-library/user-event";
This is the right import
import { userEvent, within } from "#storybook/testing-library";

expect(...).toBeInTheDocument is not a function after setting up

I have '#testing-library/jest-dom' installed so it should be there. Also have the below imports, anything wrong with my config?
TypeError: expect(...).toBeInTheDocument is not a function
52 | renderIt(onSubmit);
53 |
> 54 | expect(screen.getByText(/alberta/i)).toBeInTheDocument();
My test:
import { render, screen } from '#testing-library/react';
import { Formik, Form } from 'formik';
import { Select } from '.';
const options = [
'Alberta',
'British Columbia',
'Manitoba',
'New Brunswick',
'Newfoundland & Labrador',
'Northwest Territories',
'Nova Scotia',
'Nunavut',
'Ontario',
'Prince Edward Island',
'Quebec',
'Saskatchewan',
'Yukon',
];
const renderIt = (onSubmit: () => void) => render(
<Formik
initialValues={{ province: '' }}
onSubmit={onSubmit}
>
<Form>
<Select name="province" options={options} />
</Form>
</Formik>,
);
describe('Select component', () => {
test('It renders', () => {
const onSubmit = jest.fn();
renderIt(onSubmit);
expect(screen.getByText(/alberta/i)).toBeInTheDocument();
});
});
My src/setupTests.ts file:
// jest-dom adds custom jest matchers for asserting on DOM nodes.
// allows you to do things like:
// expect(element).toHaveTextContent(/react/i)
// learn more: https://github.com/testing-library/jest-dom
import '#testing-library/jest-dom';
import '#testing-library/jest-dom/extend-expect';
package.json:
"devDependencies": {
"#testing-library/dom": "8.11.3",
"#testing-library/jest-dom": "5.16.2",
"#testing-library/react": "^13.0.0-alpha.6",
"#testing-library/react-hooks": "7.0.2",
"#testing-library/user-event": "13.5.0",
"#types/jest": "27.4.1",
"jest": "27.5.1",
"ts-jest": "27.1.3",
"typescript": "4.6.2"
},
jest.config.js:
module.exports = {
testEnvironment: 'jsdom',
preset: 'ts-jest',
moduleNameMapper: {
'\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$':
'<rootDir>/__mocks__/fileMock.js',
'\\.(css|less)$': 'identity-obj-proxy',
},
};
You should declare the setupTests.ts in you jest configuration using the setupFilesAfterEnv property.
jest.config.js
module.exports = {
testEnvironment: 'jsdom',
setupFilesAfterEnv: ['<rootDir>/src/setupTests.ts'],
preset: 'ts-jest',
moduleNameMapper: {
'\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$':
'<rootDir>/__mocks__/fileMock.js',
'\\.(css|less)$': 'identity-obj-proxy',
},
};

Published styled-components react library does not have access to user app ThemeProvider

So i'm building a design system for this company and the component system is displayed correctly in the design system storybook. But when I import it in the consumer app I get the following error
TypeError: Cannot read property 'width' of undefined in theme.border.width
Design System project:
/// src/components/Button/index.js
import { Wrapper } from './styles'
import React from 'react'
export const Button = (props) => (
<Wrapper {...props}>
{children}
</Wrapper>
)
.
///src/components/Button/styles.js
export const Wrapper = styled.button`
...
border-width: ${({theme}) => theme.border.width};
...
`
.
/// .storybook/preview.js
import React from 'react'
import { ThemeProvider } from 'styled-components'
import { GlobalStyle } from '../src/styles/globalStyles'
import { theme } from '../src/styles/theme'
export const parameters = {
actions: { argTypesRegex: '^on[A-Z].*' }
}
export const decorators = [
Story => (
<ThemeProvider theme={theme}>
<GlobalStyle />
<Story />
</ThemeProvider>
)
]
.
/// src/index.js
...
export { Button } from 'components/Button'
export { theme } from 'style/theme'
...
.
/// babel.config.js
module.exports = {
presets: [
[
'#babel/env',
{
modules: false
}
],
['#babel/preset-react']
],
plugins: [
[
'styled-components',
{
ssr: true,
displayName: true,
preprocess: false,
minify: false
}
]
]
}
.
///rollup.config.js
import babel from 'rollup-plugin-babel'
import includePaths from 'rollup-plugin-includepaths'
import peerDepsExternal from 'rollup-plugin-peer-deps-external'
export default [
{
input: 'src/index.js',
output: [
{
name: 'rollup-tutorial',
file: 'dist/index.js',
format: 'es'
}
],
plugins: [
babel({
exclude: 'node_modules/**'
}),
includePaths({
paths: ['src'],
extensions: ['.js', '.json', '.html']
}),
peerDepsExternal()
]
}
]
.
/// package.json
{
"name": "design-system",
"main": "dist/index.js"
"files: ["dist"],
"scripts": {
...
"build": "rollup --config"
...
},
"devDependencies": {
"#babel/core": "^7.12.10",
"#babel/preset-react": "^7.12.10",
"#babel/preset-env": "^7.12.13",
"react": "17.0.1",
"react-dom": "17.0.1",
"rollup": "^2.38.4",
"rollup-plugin-babel": "^4.4.0",
"rollup-plugin-includepaths": "^0.2.4",
"rollup-plugin-peer-deps-external": "^2.2.4",
"styled-components": "^5.2.1",
},
"peerDependencies": {
"prop-types": ">= 15.x.x",
"react": ">= 17.x.x",
"styled-components": ">= 5.x.x",
}
}
App consumer NextJs default config
/// .babelrc
{
"presets": ["next/babel"],
"env": {
"development": {
"plugins": [
[
"styled-components",
{
"ssr": true,
"displayName": true
}
]
]
},
"production": {
"presets": [
"next/babel"
],
"plugins": [
[
"styled-components",
{
"ssr": true,
"displayName": false
}
]
]
}
}
}
.
///package.json
{
...
"dependencies": {
...
"design-system": "../design-system/",
...
}
...
}
.
/// pages/_app.js
import { ThemeProvider } from 'styled-components'
import { theme } from 'design-system'
function MyApp({ Component, pageProps }) {
console.log(theme)
return (
<ThemeProvider theme={theme}>
<Component {...pageProps} />
</ThemeProvider>
)
}
.
///pages/index.js
import { Button } 'design-system'
export default function Home() {
return (
<Button />
)
}
Note:
The console.log(theme) prints the expected theme however the button doesnt have access to the theme provided by styled-components.
I guess i'm missing some important configurantion in babel rollup or something
Note 2:
I already tried wrapping up the components in withComponent HOC
the only working solution was the next piece of code
///pages/index.js
import { Button } 'design-system'
import { useTheme } 'styled-components'
export default function Home() {
const theme = useTheme()
return (
<Button theme={theme} />
)
}
But this loses the whole point of using context
Thanks in advance
I've had a similar issue when developing a component library using storybook and emotion/styled-components. The issue was that I was using the styled-components' ThemeProvider from the consumer app, as you did in your _app.js. The solution was to create and export a custom ThemeProvider on the component library, using the library's styled-component package, like so:
import { ThemeProvider } from 'styled-components'
import { theme as defaultTheme } from '../src/styles/theme'
const CustomThemeProvider = ({ theme = defaultTheme, children }) => (
<ThemeProvider theme={theme}>
{children}
</ThemeProvider>
)
export { CustomThemeProvider }
and then use in your consumer app
/// pages/_app.js
import { CustomThemeProvider, theme } from 'design-system'
function MyApp({ Component, pageProps }) {
console.log(theme)
return (
<CustomThemeProvider theme={theme}>
<Component {...pageProps} />
</CustomThemeProvider>
)
}
The styled-components FAQ suggests to not ship your styled-components along with your bundle. This resolved the above mentioned issue for me.
https://styled-components.com/docs/faqs#i-am-a-library-author-should-i-bundle-styledcomponents-with-my-library

GatsbyJS + Netlify + MDX loader issue

I am making a style guide with a CMS and running into a few issues.
This is my webpack config
exports.onCreateWebpackConfig = ({ actions }) => {
actions.setWebpackConfig({
plugins: [
new WebpackNotifierPlugin({
skipFirstNotification: true,
}),
],
resolve: {
// Enable absolute import paths
modules: [path.resolve(__dirname, 'src'), 'node_modules'],
extensions: ['.js', '.jsx', '.json', '.tsx'],
},
})
}
This is my package.json
"#babel/core": "^7.2.2",
"#material-ui/core": "^4.9.1",
"#material-ui/icons": "^4.9.1",
"#mdx-js/mdx": "^0.16.8",
"#mdx-js/tag": "^0.16.6",
"#reach/router": "^1.2.1",
"#typescript-eslint/parser": "^2.19.0",
"d3-ease": "^1.0.5",
"docz-utils": "^0.13.6",
"gatsby": "^2.0.76",
"gatsby-image": "^2.0.20",
"gatsby-link": "^2.2.29",
"gatsby-mdx": "^0.3.4",
"gatsby-plugin-catch-links": "^2.0.9",
"gatsby-plugin-manifest": "^2.0.9",
"gatsby-plugin-mdx": "^1.0.67",
"gatsby-plugin-netlify-cms": "4.1.40",
"gatsby-plugin-offline": "^2.0.16",
"gatsby-plugin-sharp": "^2.0.14",
"gatsby-react-router-scroll": "^2.1.21",
"gatsby-source-filesystem": "^2.0.16",
"gatsby-transformer-sharp": "^2.1.8",
"hast-util-to-string": "^1.0.1",
"jss": "^10.0.4",
"jsx-to-string": "^1.4.0",
"lodash": "^4.17.11",
"marked": "^0.6.0",
"netlify-cms-app": "2.9.1",
"netlify-cms-widget-mdx": "^0.4.3",
"netlify-identity-widget": "^1.5.6",
"prismjs": "^1.15.0",
"prop-types": "^15.6.2",
"react": "^16.8.0",
"react-dom": "^16.8.0",
"react-head": "^3.0.2",
"react-highlight": "^0.12.0",
"react-powerplug": "^1.0.0",
"styled-system": "^3.2.1",
"unstated": "^2.1.1",
"write": "^1.0.3"
This is my component:
interface IButtons {
children: React.ReactElement;
}
const useStyles = makeStyles({
root: {
},
button: {
display: 'flex',
justifyContent: 'space-between' as 'space-between',
padding: `16px 8px`,
paddingRight: '50px',
background: `#F7F9FE`,
position: 'relative' as 'relative'
},
expand: {
position: 'absolute' as 'absolute',
top: 0,
right: 0,
cursor: 'pointer'
},
code: {
padding: `16px`,
fontSize: `14px`
}
});
const Buttons = (props: IButtons) => {
const classes = useStyles();
const [isCodeOpen, setCode] = useState(false)
const children = React.Children.toArray(props.children)
const stringChildren = useMemo(() => {
let stringed: string[] | string = []
for (let i = 0; i < React.Children.count(children); i++) {
stringed
.push(jsxToString(props.children[i])
.replace('WithStyles(ForwardRef(Button))', 'Button')
.replace('/WithStyles(ForwardRef(Button))', '/Button'))
}
return stringed.join("\n\n")
}, [props.children])
return (
<section className={classes.root}>
<div className={classes.button}>
<CodeIcon className={classes.expand} fontSize='small' onClick={() => setCode(!isCodeOpen)}></CodeIcon>
{props.children}
</div>
{isCodeOpen &&
<Highlight language="javascript" className={classes.code}>
{stringChildren}
</Highlight>}
</section>
)
}
And these are my UI components
export const UIComponents = {
...UI,
DeleteIcon,
Buttons,
// TODO: include additional custom components here, eg:
Janky: props => <UI.TextField {...props} placeholder={'janky'} />
}
And my query
{
resolve: "gatsby-mdx",
options: {
extensions: [".mdx", ".md"],
defaultLayouts: {
default: require.resolve("./src/components/Layout/index.tsx"),
},
globalScope: `
import { UIComponents } from 'Theme'
export default {
...UIComponents
}
`,
// mdPlugins: [],
// gatsbyRemarkPlugins: [{}],
},
},
The first issue I am encountering when starting the app is I get this error message. I am not sure what loaders I need to put.
Module parse failed: The keyword 'interface' is reserved (8:0)
You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file. See https://webpack.js.org/concepts#loaders
| import jsxToString from 'jsx-to-string';
|
> interface IButtons {
| children: React.ReactElement;
| }
# ./src/Theme.jsx 32:0-43 123:11-18
# ./src/cms/cms.jsx
# multi ./node_modules/gatsby-plugin-netlify-cms/cms.js ./src/cms/cms
The second issue is that in my netlify cms preview I get:
Invalid MDX:
ReferenceError: Buttons is not defined
Even though in the App itself the Buttons component renders, in the preview it does not.
Gatsby does not ship with Typescript support out of the box, but you can add it easily with the gatsby-plugin-typescript plugin.
Install
npm install gatsby-plugin-typescript
How to use
Include the plugin in your gatsby-config.js file.
Write your components in TSX or TypeScript.
You’re good to go.
gatsby-config.js
module.exports = {
// ...,
plugins: [`gatsby-plugin-typescript`],
}

gatsby-source-graphql only absolute urls are supported

I'm integrating graphQL into my gatsby site. I am getting an error that says "only absolute urls are supported" and then points to some code in the node-fetch library. There isn't an obvious path to how I'm getting that code to execute though, so I'm not sure what the source of my issue is. I have done several days worth of searching, and while I have found several threads about this error, it's never been in the context of gatsby-source-graphql. Any help would be appreciated.
package.json
{
.
.
.
"dependencies": {
"ajv": "^6.9.2",
"core-js": "^2.6.5",
"fullcalendar": "^3.9.0",
"fullcalendar-reactwrapper": "^1.0.7",
"gatsby": "^2.12.0",
"gatsby-cli": "^2.7.20",
"gatsby-plugin-manifest": "^2.0.2",
"gatsby-plugin-netlify-cms": "^4.0.1",
"gatsby-plugin-offline": "^2.0.5",
"gatsby-plugin-react-helmet": "^3.0.0",
"gatsby-plugin-sass": "^2.0.1",
"gatsby-source-filesystem": "^2.1.6",
"gatsby-source-graphql": "^2.1.3",
"gatsby-transformer-remark": "^2.6.9",
"graphql": "^14.1.1",
"jquery": "^3.3.1",
"moment": "^2.22.2",
"netlify-cms-app": "^2.9.1",
"node-sass": "^4.9.3",
"react": "^16.5.1",
"react-calendar": "^2.17.5",
"react-dom": "^16.6.3",
"react-helmet": "^5.2.0",
"react-native-calendars": "^1.21.0"
},
.
.
.
"devDependencies": {
"#material-ui/core": "^3.9.2",
"#material-ui/icons": "^3.0.2",
"material-icons-react": "^1.0.4",
"prettier": "^1.14.2",
"react-tooltip": "^3.9.2",
"surge": "^0.20.1"
},
.
.
.
}
UpcomingScheduleChanges.js
import React from 'react';
import { StaticQuery, graphql } from 'gatsby';
import Cancellations from './Cancellations';
class UpcomingScheduleChanges extends React.Component {
render() {
console.log(this.props.cancellations)
return (
<div className="col-6">
<header className="major">
<h2>Upcoming Schedule Changes</h2>
</header>
{this.props.cancellations ? (
<Cancellations cancellations={this.props.cancellations}></Cancellations>
) : (
<p>There are no upcomimng schedule changes!</p>
)}
</div>
)
}
}
export default () => (
<StaticQuery
query={graphql`
query ScheduleChanges {
allMarkdownRemark {
edges {
node {
frontmatter {
cancellation {
date(formatString: "MMMM DD")
day
location
type
}
}
}
}
}
}
`}
render={(data) => <UpcomingScheduleChanges cancellations={data.allMarkdownRemark.edges[0].node.frontmatter.cancellation} />}
/>
);
index.js
import React from "react";
import Helmet from "react-helmet";
import Layout from "../components/layout";
import ReactTooltip from "react-tooltip";
import ContactForm from "../components/ContactForm";
import Schedule from '../components/Schedule';
import Welcome from "../components/Welcome";
import Administrators from "../components/Administrators";
import MailingList from "../components/MailingList";
class Homepage extends React.Component {
handleClick(url) {
window.open(url, "_blank");
}
render() {
const siteTitle = "...";
return (
<Layout>
<Helmet title={siteTitle}>
<script src="https://identity.netlify.com/v1/netlify-identity-widget.js"></script>
</Helmet>
<Welcome></Welcome>
<Schedule></Schedule>
<Administrators></Administrators>
<MailingList></MailingList>
<ContactForm></ContactForm>
<ReactTooltip />
<script>
{`if (window.netlifyIdentity) {
window.netlifyIdentity.on("init", user => {
if (!user) {
window.netlifyIdentity.on("login", () => {
document.location.href = "/admin/";
});
}
});
}`}
</script>
</Layout>
);
}
}
export default Homepage;
gatsby-config.js
module.exports = {
siteMetadata: {
title: "...",
author: "...",
description: "..."
},
plugins: [
'gatsby-plugin-react-helmet',
{
resolve: `gatsby-plugin-manifest`,
options: {
name: '...',
short_name: '...',
start_url: '/',
background_color: '#FFFFFF',
theme_color: '#FFFFFF',
display: 'minimal-ui',
icon: 'src/assets/images/banner_small.png', // This path is relative to the root of the site.
},
},
'gatsby-plugin-sass',
'gatsby-transformer-remark',
{
resolve: 'gatsby-source-filesystem',
options: {
path: `${__dirname}/static/content`,
name: 'content'
}
},
{
resolve: "gatsby-source-graphql",
options: {
typeName: "cancellations",
fieldName: "cancellations",
url: `${__dirname}/static/content/cancellations.md`
}
},
'gatsby-plugin-offline',
'gatsby-plugin-netlify-cms'
],
}
config.yml
backend:
name: git-gateway
branch: master #branch to update (optional; defaults to master)
publish_mode: editorial_workflow #allows for a drafting, reviewing, and approving process for changes
media_folder: "src/assets/images/uploads"
public_folder: "/images"
#collections
collections:
- label: "Upcoming Schedule Changes"
name: "upcoming schedule changes"
files:
- label: "Cancellations"
name: "cancellations"
file: "static/content/cancellations.md"
fields:
- label: "Cancellations"
name: "cancellations"
create: true
widget: "list"
fields:
- {label: "Date", name: "date", widget: "date"}
- {label: "Day", name: "day", widget: "select", options: ["Thursday", "Friday", "Sunday"]}
- {label: "Location", name: "location", widget: "select", options: ["Location1", "Location2", "Location3"]}
- {label: "Type", name: "type", widget: "select", options: ["Cancelled", "Delayed", "Relocated"]}

Resources