- Operating System: macOS Sierra (10.12) or later, Windows 10, or Linux.
- Node.js 10.13.0 (LTS) or higher.
- A code editor, such as Visual Studio Code.
- Git version control system.
- npm package manager.
- Gatsby command line interface (CLI).
- A GitHub account.
- A Microsoft Azure account (if deploying with Azure).
- Click the
Use this template
button. - Select a name for your new repository.
- Click
Create repository from template
. - Click the
Code
button to clone the repository and follow instructions to clone to your local machine. - Navigate to the directory on your local machine.
- Install dependencies with
npm install
. - Add
env.development
file to the root directory of your project. This file should follow the structure of the/.env.template
file. Fill in your secrets. - Run the Gatsby development server
gatsby develop
ornpm run dev
.
.github
. If you deploy with Azure, you will generate your own.github/workflows/azure-static-web-apps-<RANDOM_NAME>.yml
file.src/constants
. You can edit the files in this folder to update links and add additional language support.src/images
. Edit contents in this folder to update the agency logos, background image used in the hero, or the images in the graphics section. See Changing Images.src/locales
. This folder contains folders for each language used and correspondingtranslation.json
files. These translation files include the text for elements that are included in every page of the webapp, such as the header, footer, navigation bar, and language selector module.src/markdown-pages
. This folder contains folders that correspond to each template page. Within each of those folders (ex.documentation
orlanding
) there are markdown files that include the content of the specific template page, and each markdown file represents a different language. These are the files you will change to customize the text in the body of each page to fit your specific project and to provide translations of the content.src/styles/_custom-theme.scss
. You can edit this file to customize the theme of the webapp, including changing the color scheme and font. See Customizing the Theme.README.md
. You can update this file to provide information about your project.
/public
. This folder is automatically generated by Gatsby.src/components
.src/pages
.src/styles/
. Do not edit any files except forsrc/styles/_custom-theme.scss
.src/templates
. Do not edit existing templates..eslintrc
..gitignore
.gatsby-browser.js
,gatsby-config.js
, orgatsby-node.js
.LICENSE.md
.package-lock.json
orpackage.json
.
To update the theme, you only need to edit src/styles/_custom-theme.scss
. In this file, edit the values assigned to variables that begin with $custom-
.
If you feel the need to customize the theme even further, you can use the variables from USWDS that begin with $theme-
in src/styles/_custom-theme.scss
. You can read more about USWDS theme variables here.
- The hero background image is set in
src/styles/_custom-theme.scss
, as follows$custom-hero-image: '../images/hero.png'
. - To update the hero background image either replace
src/images/hero.png
with a file of the same name and extension or add a new image file and update the file path name assigned to the variable$custom-hero-image
.
- Replace the files in
src/images/logos
. - If you replace the images with files of the same names and extensions then no other changes are needed. Replacing the logo image files with files of the same names and extensions is recommended.
- If you replace the images with files of different names or extensions, you will need to edit the exports in
src/images/index.js
. In this case, only change the path name, not the variable name of the exported image.
- Replace the files in
src/images/graphics
. - If you replace the images with files of the same names and extensions then no other changes are needed. Replacing the graphics image files with files of the same names and extensions is recommended.
- If you replace the images with files of different names or extensions, you will need to edit the imports in
src/images/index.js
. In this case, only change the path name, not the variable name.
The content that is unique to a specific page (ex. documentation
or landing
) is stored in markdown files (src/markdown-pages/documentation
or src/markdown-pages/landing
).
- If the content is in the front matter of the markdown file (if it is in between the three dashes
---
) only edit the text after the colon. The front matter follows YAML syntax. For instance, you can edit the text “Everything up to this point…”, but you should not editsection:
,heading
, ortext
. Also, do not edit the indents already in the front matter.
section:
heading: Section heading
text: Everything up to this point should help people understand your agency or project who you are, your goal or mission, and how you approach it.
- If the content is below the three dashes, it uses markdown syntax.
- Create a new
.jsx
file insrc/templates/
. - Create corresponding markdown files for this template page as shown in
src/documentation/
andsrc/landing/
. - In the front matter of the new markdown files, include:
lang
,templateKey
,slug
, andpageTitle
. These represent the language of the page (language code), the template being used insrc/templates
(file name), the path for this page (shown in the address bar), and the title of the page, respectively.
---
lang: en
templateKey: documentation-page
slug: documentation
pageTitle: Project | Documentation
---
- In your newly created
.jsx
file from step one, do the following: Create a new component (we recommend using a functional component) and export it by default.
import React from 'react';
function NewTemplatePage() {}
export default NewTemplatePage;
- Import the layout component
src/components/layout.jsx
. This includes the header, navigation, language selection, and footer. You must use this to make sure navigation takes place effectively from your page to other pages.
import { Layout } from '../components';
function NewTemplatePage() {
return <Layout>{/* your stuff inside layout */}</Layout>;
}
export default NewTemplatePage;
- Import GraphQL from Gatsby. Write a GraphQL query to get content from markdown files. See Gatsby’s GraphQL Concepts for more information or check out existing templates.
import { graphql } from 'gatsby';
- Include
data
as a prop in your template component. Using the following syntax, you will be able to access the elements of the front matter and markdown body:
const { markdownRemark } = data;
const { frontmatter, html } = markdownRemark;
You can access front matter elements as properties of the frontmatter object, using object dot notation as follows: frontmatter.pageTitle
.
In the template’s JSX, you can set the HTML as follows: <div dangerouslySetInnerHTML={{ __html: html }}/>
.
Include pageContext
as a prop as well and use the following syntax to access the languageList
, which is an array of all the languages used in the src/locales
folder:
const { languageList } = pageContext;
- Import
useTranslation
fromi18next
.
import { useTranslation } from 'react-i18next';
- Within the component use the following syntax to access the i18n object:
const { i18n } = useTranslation();
- Use React Helmet to set the page title and language:
import { Helmet } from 'react-helmet';
import { useTranslation } from 'react-i18next';
function NewTemplatePage() {
const { i18n } = useTranslation();
return (
<>
<Helmet
title={frontmatter.pageTitle}
htmlAttributes={{ lang: i18n.language }}
/>
<Layout>
<main>
{/* use main tags to indicate the main content */}
{/* your code inside main */}
</main>
</Layout>
</>
);
}
- Import components from
src/components/
as needed. - Pass
languageList
andfrontmatter.slug
as props to theLayout
component. You can also pass data from the front matter to other components as well. See the following example:
function NewTemplatePage() {
const { i18n } = useTranslation();
return (
<>
<Helmet
title={frontmatter.pageTitle}
htmlAttributes={{ lang: i18n.language }}
/>
<Layout languageList={languageList} slug={frontmatter.slug}>
<main>
<h1>{frontmatter.heading}</h1>
<p className="usa-intro">{frontmatter.prose}</p>
</main>
</Layout>
</>
);
}
The src/locales
folder contains folders for each language used, which are named according to their language code. Each of the language folders has a translation.json
file, which contains the text for elements that are included in every page of the webapp, such as the header, footer, navigation bar, and language selector module.
The LPAAS 2.0 template already contains placeholder translation and markdown files for the 10 designated citywide languages under Local Law 30.
- To add a new language, create a new folder in
src/locales
. The name of this folder should be the language code. - Within the new folder, create a
translation.json
file. - Copy and paste the JSON object from another translation file and replace all of the string values in the key-value pairs with the corresponding translations. Do not change any of the keys. In the following example, you can translate “Project Title”, but should not edit “title”.
{
"title": "Project Title"
}
- In
src/i18n-config.js
, add the new language to resources. See the example below:
resources: {
ar: {
translations: require('./locales/ar/translation.json'),
},
bn: {
translations: require('./locales/bn/translation.json'),
},
//other language resources not shown for brevity
- If the language you are adding is not one of the designated citywide languages under Local Law 30 and is not already included in
src/constants/languages.js
, add the language name and language code as key value pairs of an object in the languages array, as follows:
{
lang: 'English',
langKey: 'en',
}
- In
src/markdown-pages
, create a new markdown file for each template in your new language. For instance, if you were adding pages in Spanish, you would need to create a new file in each folder (404
,documentation
,landing
, and any additional folders). We recommend that each of the new files should be named the same thing as the folder, followed by a dash, and language code:src/markdown-pages/landing/landing-es.md
andsrc/markdown-pages/documentation/documentation-es.md
- To delete a language, delete the corresponding folder in
src/locales
and its contents. - In
src/i18n-config.js
, delete the language from theresources
object. - In
src/markdown-pages
, delete the corresponding markdown file from each folder.
- Navigation links are stored in
src/constants/links
, while navigation labels are stored in the translation files insrc/locales
. The links in the navigation in the header are also shown in the footer for accessibility.
- To edit the link itself, simply change the desired path in
src/constants/links
. - To edit the label of the link, update the text in all of the translation files in
src/locales
.
- Navigation links and labels are stored as key-value pairs. The label values are pulled from the translation files. Add the label using object property syntax and the link to
src/constants/links.js
. Internal links should not begin with a forward slash/
. In the header, links can either be in navigation dropdown menus or standalone links (parent links). In the example below, the first array innavDropDowns
will be included in one dropdown menu and the second array will be in another.
export const header = {
navDropDowns: [
// dropdowns
// first dropdown start
[
{
LABEL: 'navigation.dropdowns.0.linkLabels.0',
LINK: 'link-one',
},
{
LABEL: 'navigation.dropdowns.0.linkLabels.1',
LINK: 'link-two',
},
],
// first dropdown end
// second dropdown start
[
{
LABEL: 'navigation.dropdowns.1.linkLabels.0',
LINK: 'link-three',
},
{
LABEL: 'navigation.dropdowns.1.linkLabels.1',
LINK: 'link-four',
},
],
// second dropdown end
],
parentLinks: [{ LABEL: 'navigation.parentLinkLabels.0', LINK: 'link-five' }], // parent (standalone) links
};
We suggest not having more than three links per dropdown menu and not having more than eight links in the dropdown menus and standalone links combined.
- Add the label for the link in each translation file in
src/locales
, corresponding to the label location in the previous step.
- Delete the object associated with the link in
src/constants/links
. - Delete the label in each translation file in
src/locales
. Be sure to complete this step, otherwise labels and links could be mismatched.
- To edit the label of the dropdown menu, update the text of
buttonLabel
innavigation.dropdowns
in all of the translation files insrc/locales
. - To edit the links and associated labels for the links in a dropdown menu, see Editing Navigation Links, Adding Navigation Links, or Deleting Navigation Links.
- Add a subarray to the header.navDropDowns array in
src/constants/links.js
. The elements of the subarray are objects with label and link keys. - Each label will correspond to a
linkLabel
in thetranslation.json
files. - Add the corresponding link labels in the
translation.json
files insrc/locales
. In the translation files, each object in thenavigation.dropdowns
array corresponds to a dropdown menu. ThebuttonLabel
is the label of the dropdown button. ThelinkLabels
array contains the labels of all of the links listed in the dropdown menu. See the example below:
"navigation": {
"dropdowns": [
{
"buttonLabel": "Nav Label 1",
"linkLabels": ["Simple link one", "Simple link two"]
}
]
}
- Delete the desired subarray to the
header.navDropDowns
array insrc/constants/links.js
. - Delete the desired element in the
navigation.dropdowns
array in everytranslation.json
file.
- Button links are stored in
src/constants/links.js
and can be updated there. - Button labels are stored in translation files if the buttons occur on every page and are stored in markdown files if the buttons are specific to a singular page.
To deploy your site using Azure, follow the Publish a Gatsby site to Azure Static Web Apps tutorial, starting at the Deploy your web app section.
In order to set environment variables, follow the Configure application settings for Azure Static Web Apps tutorial. Enter the environment variables (application settings) for GATSBY_ENDPOINT
and GATSBY_TITLE
.
To edit your site's GitHub Actions build workflow in .github/workflows
, follow the GitHub Actions workflows for Azure Static Web Apps tutorial.
To create a DNS record, follow the Create DNS records in a custom domain for a web app tutorial.
If node_modules
was not installed properly, you might have to run npm install --legacy-peer-deps
.
The Mayor's Office of the CTO would like to thank Anya Dunaif (@aannyyaa), Saiful Islam (@saifulislamdev), and Britney Johnson for their significant contributions to this project as a summer CIC Fellow in 2021.