The structure of the website
carbondesignsystem.com is created with React and is using a combination of tools and packages in order to render its content. This page explains how the website is set up and how to update certain parts of the website.
Before getting started, make sure you have a local version of the website and that you are working from a fork and a branch.
The main structure of the website is the following:
build
config
├── env.js
├── paths.js
├── polyfills.js
├── webpack.config.dev.js
├── webpack.config.prod.js
public
scripts
├── build.js
├── crawler.js
├── frontmatter.js
├── start.js
src
├── app
│ └── components
│ └── custom
│ └── internal
│ └── pages
│ └── add-ons
│ └── component-status
│ └── components
│ └── data-vis
│ └── getting-started
│ └── guidelines
│ └── overview
│ └── resources
│ └── style
│ └── themes
│ └── whats-new
│ ├── 404.js
│ └── scss
│ └── global
│ ├── main.scss
├──assets
│ └── downloads
│ └── fonts
│ └── images
│ └── syntax
├── content
│ └── add-ons
│ └── components
│ └── getting-started
│ └── guidelines
│ └── overview
│ └── resources
│ └── style
│ └── themes
│ └── whats-new
│ ├── main.scss
├── data
│ └── add-ons
│ └── components
│ └── guidelines
│ ├── colors.json
│ ├── component-status.json
│ ├── data-vis-colors.json
│ ├── site-nav-structure.json
│ ├── sitecontent.js
├── polyfills
│ ├── custom-event.js
│ ├── element-closest.js
│ ├── element-matches.js
│ ├── index.js
│ ├── toggle-class.js
├── carbon-components.js
├── index.js
├── routes.js
index.js
manifest.yml
The build
folder is auto-generated when running the commands npm run build-external
or npm run build-internal
. We run these commands before deploying the website to IBM Cloud both for our public site (http://www.carbondesignsystem.com) and our internal site (http://design-system.stage1.mybluemix.net/). It is used by express
in the root index.js
file to serve our static files such as images, CSS files, and JavaScript files. The CSS and JavaScript files are generated using webpack
while the HTML is being generated from the index.hbs
file in the public
folder.
app.use(express.static('./build'));
app.get('/*', (req, res) => {
res.setHeader('Content-Type', 'text/html; charset=UTF-8');
res.sendFile(path.join(__dirname, './build', 'index.html'));
});
The config
folder includes the files needed for the webpack
configuration and the files are all based directly off of the files used in create-react-app.
env.js
defines the environment variables used in the webpack config.
paths.js
includes shorthands for all the different paths used in the webpack config.
polyfills.js
includes some of the polyfills needed for React.
webpack.config.dev.js
is the Webpack configuration file for the dev setup.
It takes care of parsing our React application and making sure a static website is bundled up and generated with all of our needed assets.
webpack.config.prod.js
is the Webpack configuration file for the production setup.
The biggest difference between the dev config and the prod config is that the prod config includes parts for uglifying our HTML and JS.
The scripts
folder includes some of the scripts we use on the website to automate certain tasks and to generate content.
The build.js
file generates our build folder and is triggered using the commands npm run build-external
and npm run build-internal
. These two commands both run this file, but with different environment variables set based on whether or not the website needs to be built for internal or external purposes.
The crawler.js
file is used to build the internal search on the website. It goes thorugh each of the markdown files on the website and creates JavaScript objects for them to be consumed in the React component created for the internal search.
The frontmatter.js
file is a script file that goes through the code.md
file for each component. The code.md
file includes information that we're using to display the code for each component on the Component pages on the website. We will explain this further later.
The start.js
file is used to start the server after the website is built and is run by running the command npm run start
. This is useful for doublechecking that the website is running as expected before deploying to IBM Cloud.
The src
folder is where most of the work on the website is done.
The app
folder is the main folder for all of the React components used on the website. The components
folder contains the components needed to built pages on the website. They are divided into 2 categories - custom
and internal
.
The internal components are used to create important parts of the website such as the page header, the page footer, the page itself, etc.
The custom components are React components that we build into the markdown files in order to show more complex content on some of the pages without adding too much markup to the content files (which are all markdown files). To create a custom component you can do the following:
- Find the content markdown file for the page you want to add the custom component. For example, if you want to add a custom component to the Motion page, open the
motion.md
file in thecontent
folder. Find the place in the markdown file where you want the custom component to be inserted. Then add the following line:
<div data-insert-component="NameOfCustomComponent"></div>
If you need to add any props to your custom component, then you can add it using the data-attribute data-props
and pass them in the order you are going to accept them in your custom component.
<div data-insert-component="NameOfCustomComponent" data-props="prop1,prop2,prop3"></div>
- Create the React component in the
custom
folder. Example:
import React, { Component } from 'react';
import PropTypes from 'prop-types';
class NameOfCustomComponent extends Component {
static propTypes = {
prop1: PropTypes.string,
prop2: PropTypes.string,
prop3: PropTypes.string,
}
render() {
const {
prop1,
prop2,
prop3,
} = this.props;
return (
<div>My custom component here</div>
);
}
}
export default NameOfCustomComponent;
- Import the component in
Page.js
, and add it to theaddCustomComponent
method.
// Page.js
import NameOfCustomComponent from '../../custom/NameOfCustomComponent';
...
addCustomComponent = () => {
const customComponents = {
...
NameOfCustomComponent
};
...
// If your component uses props, add an `else if` statement to the end of the method
} else if (comp === 'Video') {
const videoProp = component.dataset.props;
ReactDOM.render(<NewComponent videoLink={videoProp} />, component);
// Your code begins here
} else if (comp === 'NameOfCustomComponent') {
const props = component.dataset.props.split(',');
ReactDOM.render(
<NewComponent
prop1={props[0]}
prop2={props[1]}
prop3={props[2]}
/>,
component
);
} else {
ReactDOM.render(<NewComponent />, component);
}
}
If the custom component needs any CSS, then you have to also import this file in src/app/scss/main.scss
.
Some of the content on the website is only available on our internal staging website. We're using environment variables to differentiate between internal and external. This is used in the SideNav
component (line 123-128) to make sure that the internal pages are not rendered on the external site's side nav. It is also used on the pages that are internal. Right now this is only the YourProductOnIBMCloud.js
component.
To view the internal website while developing, run ENV=internal npm run dev
.