Browse Source

Migrated Gatsby website source and config

main
Brian Vaughn 8 years ago
parent
commit
9d9b2021ed
  1. 4
      .babelrc
  2. 7
      .eslintignore
  3. 7
      .eslintrc
  4. 33
      .flowconfig
  5. 4
      .gitignore
  6. 1
      .nvmrc
  7. 393
      LICENSE.md
  8. 54
      README.md
  9. 3
      flow-typed/hex2rgba.js
  10. 142
      gatsby-config.js
  11. 244
      gatsby-node.js
  12. 80
      package.json
  13. 22
      plugins/gatsby-remark-use-jsx/index.js
  14. 4
      plugins/gatsby-remark-use-jsx/package.json
  15. 19
      plugins/gatsby-source-react-error-codes/gatsby-node.js
  16. 4
      plugins/gatsby-source-react-error-codes/package.json
  17. 33
      plugins/gatsby-transformer-authors-yaml/gatsby-node.js
  18. 4
      plugins/gatsby-transformer-authors-yaml/package.json
  19. 282
      src/components/CodeEditor/CodeEditor.js
  20. 14
      src/components/CodeEditor/index.js
  21. 40
      src/components/Container/Container.js
  22. 14
      src/components/Container/index.js
  23. 120
      src/components/ErrorDecoder/ErrorDecoder.js
  24. 14
      src/components/ErrorDecoder/index.js
  25. 45
      src/components/Flex/Flex.js
  26. 14
      src/components/Flex/index.js
  27. 26
      src/components/Header/Header.js
  28. 14
      src/components/Header/index.js
  29. 39
      src/components/LayoutFooter/ExternalFooterLink.js
  30. 193
      src/components/LayoutFooter/Footer.js
  31. 30
      src/components/LayoutFooter/FooterLink.js
  32. 39
      src/components/LayoutFooter/FooterNav.js
  33. 14
      src/components/LayoutFooter/index.js
  34. 251
      src/components/LayoutHeader/Header.js
  35. 74
      src/components/LayoutHeader/HeaderLink.js
  36. 33
      src/components/LayoutHeader/SearchSvg.js
  37. 14
      src/components/LayoutHeader/index.js
  38. 43
      src/components/MarkdownHeader/MarkdownHeader.js
  39. 14
      src/components/MarkdownHeader/index.js
  40. 140
      src/components/MarkdownPage/MarkdownPage.js
  41. 14
      src/components/MarkdownPage/index.js
  42. 199
      src/components/StickyResponsiveSidebar/StickyResponsiveSidebar.js
  43. 14
      src/components/StickyResponsiveSidebar/index.js
  44. 33
      src/components/TitleAndMetaTags/TitleAndMetaTags.js
  45. 14
      src/components/TitleAndMetaTags/index.js
  46. 453
      src/css/algolia.css
  47. 42
      src/css/reset.css
  48. 66
      src/html.js
  49. 1
      src/icons/logo.svg
  50. BIN
      src/images/oss_logo.png
  51. 1
      src/index.js
  52. 85
      src/layouts/index.js
  53. 34
      src/pages/404.js
  54. 88
      src/pages/acknowledgements.html.js
  55. 117
      src/pages/blog/all.html.js
  56. 116
      src/pages/docs/error-decoder.html.js
  57. BIN
      src/pages/favicon.ico
  58. 38
      src/pages/jsx-compiler.html.js
  59. 2
      src/pages/robots.txt
  60. 171
      src/prism-styles.js
  61. 22
      src/site-constants.js
  62. 91
      src/templates/blog.js
  63. 50
      src/templates/community.js
  64. 87
      src/templates/components/ButtonLink/ButtonLink.js
  65. 14
      src/templates/components/ButtonLink/index.js
  66. 41
      src/templates/components/ChevronSvg/index.js
  67. 39
      src/templates/components/ExternalLinkSvg/index.js
  68. 38
      src/templates/components/MetaTitle/index.js
  69. 136
      src/templates/components/NavigationFooter/NavigationFooter.js
  70. 14
      src/templates/components/NavigationFooter/index.js
  71. 96
      src/templates/components/Sidebar/Section.js
  72. 70
      src/templates/components/Sidebar/Sidebar.js
  73. 14
      src/templates/components/Sidebar/index.js
  74. 50
      src/templates/docs.js
  75. 470
      src/templates/home.js
  76. 61
      src/templates/tutorial.js
  77. 407
      src/theme.js
  78. 117
      src/utils/createLink.js
  79. 15
      src/utils/createOgUrl.js
  80. 37
      src/utils/findSectionForPath.js
  81. 35
      src/utils/isItemActive.js
  82. 41
      src/utils/mountCodeExample.js
  83. 32
      src/utils/sectionList.js
  84. 18
      src/utils/slugify.js
  85. 39
      src/utils/toCommaSeparatedList.js
  86. BIN
      static/external.png
  87. BIN
      static/favicon.ico
  88. 12
      static/js/jsfiddle-integration-babel.js
  89. 12
      static/js/jsfiddle-integration.js
  90. 1
      static/large-logo.svg
  91. BIN
      static/logo-og.png
  92. 14
      static/search.svg
  93. 10265
      yarn.lock

4
.babelrc

@ -0,0 +1,4 @@
{
"presets": ['react', 'es2015', 'stage-1'],
"plugins": ['add-module-exports']
}

7
.eslintignore

@ -0,0 +1,7 @@
node_modules/*
# Ignore markdown files and examples
content/*
# Ignore built files
public/*

7
.eslintrc

@ -0,0 +1,7 @@
{
"plugins": [
"prettier",
"react"
],
"parser": "babel-eslint",
}

33
.flowconfig

@ -0,0 +1,33 @@
[ignore]
<PROJECT_ROOT>/content/.*
<PROJECT_ROOT>/node_modules/.*
<PROJECT_ROOT>/public/.*
[include]
[libs]
./node_modules/fbjs/flow/lib/dev.js
./flow
[options]
module.system=haste
esproposal.class_static_fields=enable
esproposal.class_instance_fields=enable
unsafe.enable_getters_and_setters=true
munge_underscores=false
suppress_type=$FlowIssue
suppress_type=$FlowFixMe
suppress_type=$FixMe
suppress_type=$FlowExpectedError
suppress_comment=\\(.\\|\n\\)*\\$FlowFixMe\\($\\|[^(]\\|(\\(>=0\\.\\(3[0-3]\\|[1-2][0-9]\\|[0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*www[a-z,_]*\\)?)\\)
suppress_comment=\\(.\\|\n\\)*\\$FlowIssue\\((\\(>=0\\.\\(3[0-3]\\|[1-2][0-9]\\|[0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*www[a-z,_]*\\)?)\\)?:? #[0-9]+
suppress_comment=\\(.\\|\n\\)*\\$FlowFixedInNextDeploy
suppress_comment=\\(.\\|\n\\)*\\$FlowExpectedError
[version]
^0.56.0

4
.gitignore

@ -0,0 +1,4 @@
.cache
.DS_STORE
node_modules
public

1
.nvmrc

@ -0,0 +1 @@
8.4

393
LICENSE.md

@ -0,0 +1,393 @@
Attribution 4.0 International
=======================================================================
Creative Commons Corporation ("Creative Commons") is not a law firm and
does not provide legal services or legal advice. Distribution of
Creative Commons public licenses does not create a lawyer-client or
other relationship. Creative Commons makes its licenses and related
information available on an "as-is" basis. Creative Commons gives no
warranties regarding its licenses, any material licensed under their
terms and conditions, or any related information. Creative Commons
disclaims all liability for damages resulting from their use to the
fullest extent possible.
Using Creative Commons Public Licenses
Creative Commons public licenses provide a standard set of terms and
conditions that creators and other rights holders may use to share
original works of authorship and other material subject to copyright
and certain other rights specified in the public license below. The
following considerations are for informational purposes only, are not
exhaustive, and do not form part of our licenses.
Considerations for licensors: Our public licenses are
intended for use by those authorized to give the public
permission to use material in ways otherwise restricted by
copyright and certain other rights. Our licenses are
irrevocable. Licensors should read and understand the terms
and conditions of the license they choose before applying it.
Licensors should also secure all rights necessary before
applying our licenses so that the public can reuse the
material as expected. Licensors should clearly mark any
material not subject to the license. This includes other CC-
licensed material, or material used under an exception or
limitation to copyright. More considerations for licensors:
wiki.creativecommons.org/Considerations_for_licensors
Considerations for the public: By using one of our public
licenses, a licensor grants the public permission to use the
licensed material under specified terms and conditions. If
the licensor's permission is not necessary for any reason--for
example, because of any applicable exception or limitation to
copyright--then that use is not regulated by the license. Our
licenses grant only permissions under copyright and certain
other rights that a licensor has authority to grant. Use of
the licensed material may still be restricted for other
reasons, including because others have copyright or other
rights in the material. A licensor may make special requests,
such as asking that all changes be marked or described.
Although not required by our licenses, you are encouraged to
respect those requests where reasonable. More_considerations
for the public:
wiki.creativecommons.org/Considerations_for_licensees
=======================================================================
Creative Commons Attribution 4.0 International Public License
By exercising the Licensed Rights (defined below), You accept and agree
to be bound by the terms and conditions of this Creative Commons
Attribution 4.0 International Public License ("Public License"). To the
extent this Public License may be interpreted as a contract, You are
granted the Licensed Rights in consideration of Your acceptance of
these terms and conditions, and the Licensor grants You such rights in
consideration of benefits the Licensor receives from making the
Licensed Material available under these terms and conditions.
Section 1 -- Definitions.
a. Adapted Material means material subject to Copyright and Similar
Rights that is derived from or based upon the Licensed Material
and in which the Licensed Material is translated, altered,
arranged, transformed, or otherwise modified in a manner requiring
permission under the Copyright and Similar Rights held by the
Licensor. For purposes of this Public License, where the Licensed
Material is a musical work, performance, or sound recording,
Adapted Material is always produced where the Licensed Material is
synched in timed relation with a moving image.
b. Adapter's License means the license You apply to Your Copyright
and Similar Rights in Your contributions to Adapted Material in
accordance with the terms and conditions of this Public License.
c. Copyright and Similar Rights means copyright and/or similar rights
closely related to copyright including, without limitation,
performance, broadcast, sound recording, and Sui Generis Database
Rights, without regard to how the rights are labeled or
categorized. For purposes of this Public License, the rights
specified in Section 2(b)(1)-(2) are not Copyright and Similar
Rights.
d. Effective Technological Measures means those measures that, in the
absence of proper authority, may not be circumvented under laws
fulfilling obligations under Article 11 of the WIPO Copyright
Treaty adopted on December 20, 1996, and/or similar international
agreements.
e. Exceptions and Limitations means fair use, fair dealing, and/or
any other exception or limitation to Copyright and Similar Rights
that applies to Your use of the Licensed Material.
f. Licensed Material means the artistic or literary work, database,
or other material to which the Licensor applied this Public
License.
g. Licensed Rights means the rights granted to You subject to the
terms and conditions of this Public License, which are limited to
all Copyright and Similar Rights that apply to Your use of the
Licensed Material and that the Licensor has authority to license.
h. Licensor means the individual(s) or entity(ies) granting rights
under this Public License.
i. Share means to provide material to the public by any means or
process that requires permission under the Licensed Rights, such
as reproduction, public display, public performance, distribution,
dissemination, communication, or importation, and to make material
available to the public including in ways that members of the
public may access the material from a place and at a time
individually chosen by them.
j. Sui Generis Database Rights means rights other than copyright
resulting from Directive 96/9/EC of the European Parliament and of
the Council of 11 March 1996 on the legal protection of databases,
as amended and/or succeeded, as well as other essentially
equivalent rights anywhere in the world.
k. You means the individual or entity exercising the Licensed Rights
under this Public License. Your has a corresponding meaning.
Section 2 -- Scope.
a. License grant.
1. Subject to the terms and conditions of this Public License,
the Licensor hereby grants You a worldwide, royalty-free,
non-sublicensable, non-exclusive, irrevocable license to
exercise the Licensed Rights in the Licensed Material to:
a. reproduce and Share the Licensed Material, in whole or
in part; and
b. produce, reproduce, and Share Adapted Material.
2. Exceptions and Limitations. For the avoidance of doubt, where
Exceptions and Limitations apply to Your use, this Public
License does not apply, and You do not need to comply with
its terms and conditions.
3. Term. The term of this Public License is specified in Section
6(a).
4. Media and formats; technical modifications allowed. The
Licensor authorizes You to exercise the Licensed Rights in
all media and formats whether now known or hereafter created,
and to make technical modifications necessary to do so. The
Licensor waives and/or agrees not to assert any right or
authority to forbid You from making technical modifications
necessary to exercise the Licensed Rights, including
technical modifications necessary to circumvent Effective
Technological Measures. For purposes of this Public License,
simply making modifications authorized by this Section 2(a)
(4) never produces Adapted Material.
5. Downstream recipients.
a. Offer from the Licensor -- Licensed Material. Every
recipient of the Licensed Material automatically
receives an offer from the Licensor to exercise the
Licensed Rights under the terms and conditions of this
Public License.
b. No downstream restrictions. You may not offer or impose
any additional or different terms or conditions on, or
apply any Effective Technological Measures to, the
Licensed Material if doing so restricts exercise of the
Licensed Rights by any recipient of the Licensed
Material.
6. No endorsement. Nothing in this Public License constitutes or
may be construed as permission to assert or imply that You
are, or that Your use of the Licensed Material is, connected
with, or sponsored, endorsed, or granted official status by,
the Licensor or others designated to receive attribution as
provided in Section 3(a)(1)(A)(i).
b. Other rights.
1. Moral rights, such as the right of integrity, are not
licensed under this Public License, nor are publicity,
privacy, and/or other similar personality rights; however, to
the extent possible, the Licensor waives and/or agrees not to
assert any such rights held by the Licensor to the limited
extent necessary to allow You to exercise the Licensed
Rights, but not otherwise.
2. Patent and trademark rights are not licensed under this
Public License.
3. To the extent possible, the Licensor waives any right to
collect royalties from You for the exercise of the Licensed
Rights, whether directly or through a collecting society
under any voluntary or waivable statutory or compulsory
licensing scheme. In all other cases the Licensor expressly
reserves any right to collect such royalties.
Section 3 -- License Conditions.
Your exercise of the Licensed Rights is expressly made subject to the
following conditions.
a. Attribution.
1. If You Share the Licensed Material (including in modified
form), You must:
a. retain the following if it is supplied by the Licensor
with the Licensed Material:
i. identification of the creator(s) of the Licensed
Material and any others designated to receive
attribution, in any reasonable manner requested by
the Licensor (including by pseudonym if
designated);
ii. a copyright notice;
iii. a notice that refers to this Public License;
iv. a notice that refers to the disclaimer of
warranties;
v. a URI or hyperlink to the Licensed Material to the
extent reasonably practicable;
b. indicate if You modified the Licensed Material and
retain an indication of any previous modifications; and
c. indicate the Licensed Material is licensed under this
Public License, and include the text of, or the URI or
hyperlink to, this Public License.
2. You may satisfy the conditions in Section 3(a)(1) in any
reasonable manner based on the medium, means, and context in
which You Share the Licensed Material. For example, it may be
reasonable to satisfy the conditions by providing a URI or
hyperlink to a resource that includes the required
information.
3. If requested by the Licensor, You must remove any of the
information required by Section 3(a)(1)(A) to the extent
reasonably practicable.
4. If You Share Adapted Material You produce, the Adapter's
License You apply must not prevent recipients of the Adapted
Material from complying with this Public License.
Section 4 -- Sui Generis Database Rights.
Where the Licensed Rights include Sui Generis Database Rights that
apply to Your use of the Licensed Material:
a. for the avoidance of doubt, Section 2(a)(1) grants You the right
to extract, reuse, reproduce, and Share all or a substantial
portion of the contents of the database;
b. if You include all or a substantial portion of the database
contents in a database in which You have Sui Generis Database
Rights, then the database in which You have Sui Generis Database
Rights (but not its individual contents) is Adapted Material; and
c. You must comply with the conditions in Section 3(a) if You Share
all or a substantial portion of the contents of the database.
For the avoidance of doubt, this Section 4 supplements and does not
replace Your obligations under this Public License where the Licensed
Rights include other Copyright and Similar Rights.
Section 5 -- Disclaimer of Warranties and Limitation of Liability.
a. UNLESS OTHERWISE SEPARATELY UNDERTAKEN BY THE LICENSOR, TO THE
EXTENT POSSIBLE, THE LICENSOR OFFERS THE LICENSED MATERIAL AS-IS
AND AS-AVAILABLE, AND MAKES NO REPRESENTATIONS OR WARRANTIES OF
ANY KIND CONCERNING THE LICENSED MATERIAL, WHETHER EXPRESS,
IMPLIED, STATUTORY, OR OTHER. THIS INCLUDES, WITHOUT LIMITATION,
WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR
PURPOSE, NON-INFRINGEMENT, ABSENCE OF LATENT OR OTHER DEFECTS,
ACCURACY, OR THE PRESENCE OR ABSENCE OF ERRORS, WHETHER OR NOT
KNOWN OR DISCOVERABLE. WHERE DISCLAIMERS OF WARRANTIES ARE NOT
ALLOWED IN FULL OR IN PART, THIS DISCLAIMER MAY NOT APPLY TO YOU.
b. TO THE EXTENT POSSIBLE, IN NO EVENT WILL THE LICENSOR BE LIABLE
TO YOU ON ANY LEGAL THEORY (INCLUDING, WITHOUT LIMITATION,
NEGLIGENCE) OR OTHERWISE FOR ANY DIRECT, SPECIAL, INDIRECT,
INCIDENTAL, CONSEQUENTIAL, PUNITIVE, EXEMPLARY, OR OTHER LOSSES,
COSTS, EXPENSES, OR DAMAGES ARISING OUT OF THIS PUBLIC LICENSE OR
USE OF THE LICENSED MATERIAL, EVEN IF THE LICENSOR HAS BEEN
ADVISED OF THE POSSIBILITY OF SUCH LOSSES, COSTS, EXPENSES, OR
DAMAGES. WHERE A LIMITATION OF LIABILITY IS NOT ALLOWED IN FULL OR
IN PART, THIS LIMITATION MAY NOT APPLY TO YOU.
c. The disclaimer of warranties and limitation of liability provided
above shall be interpreted in a manner that, to the extent
possible, most closely approximates an absolute disclaimer and
waiver of all liability.
Section 6 -- Term and Termination.
a. This Public License applies for the term of the Copyright and
Similar Rights licensed here. However, if You fail to comply with
this Public License, then Your rights under this Public License
terminate automatically.
b. Where Your right to use the Licensed Material has terminated under
Section 6(a), it reinstates:
1. automatically as of the date the violation is cured, provided
it is cured within 30 days of Your discovery of the
violation; or
2. upon express reinstatement by the Licensor.
For the avoidance of doubt, this Section 6(b) does not affect any
right the Licensor may have to seek remedies for Your violations
of this Public License.
c. For the avoidance of doubt, the Licensor may also offer the
Licensed Material under separate terms or conditions or stop
distributing the Licensed Material at any time; however, doing so
will not terminate this Public License.
d. Sections 1, 5, 6, 7, and 8 survive termination of this Public
License.
Section 7 -- Other Terms and Conditions.
a. The Licensor shall not be bound by any additional or different
terms or conditions communicated by You unless expressly agreed.
b. Any arrangements, understandings, or agreements regarding the
Licensed Material not stated herein are separate from and
independent of the terms and conditions of this Public License.
Section 8 -- Interpretation.
a. For the avoidance of doubt, this Public License does not, and
shall not be interpreted to, reduce, limit, restrict, or impose
conditions on any use of the Licensed Material that could lawfully
be made without permission under this Public License.
b. To the extent possible, if any provision of this Public License is
deemed unenforceable, it shall be automatically reformed to the
minimum extent necessary to make it enforceable. If the provision
cannot be reformed, it shall be severed from this Public License
without affecting the enforceability of the remaining terms and
conditions.
c. No term or condition of this Public License will be waived and no
failure to comply consented to unless expressly agreed to by the
Licensor.
d. Nothing in this Public License constitutes or may be interpreted
as a limitation upon, or waiver of, any privileges and immunities
that apply to the Licensor or You, including from the legal
processes of any jurisdiction or authority.
=======================================================================
Creative Commons is not a party to its public licenses.
Notwithstanding, Creative Commons may elect to apply one of its public
licenses to material it publishes and in those instances will be
considered the "Licensor." Except for the limited purpose of indicating
that material is shared under a Creative Commons public license or as
otherwise permitted by the Creative Commons policies published at
creativecommons.org/policies, Creative Commons does not authorize the
use of the trademark "Creative Commons" or any other trademark or logo
of Creative Commons without its prior written consent including,
without limitation, in connection with any unauthorized modifications
to any of its public licenses or any other arrangements,
understandings, or agreements concerning use of licensed material. For
the avoidance of doubt, this paragraph does not form part of the public
licenses.
Creative Commons may be contacted at creativecommons.org.

54
README.md

@ -0,0 +1,54 @@
# reactjs.org
## Getting started
### Prerequisites
1. Git
1. Node: install version 8.4 or greater
1. Yarn: `npm i -g yarn` to install it globally via NPM
1. A clone of the [reactjs.org repo](https://github.com/facebook/reactjs.org) on your local machine
1. A fork of the repo (for any contributions)
### Installation
1. `cd reactjs.org` to go into the project root
1. `yarn` to install the website's NPM dependencies
### Running locally
1. `yarn dev` to start the hot-reloading development server (powered by [Gatsby](https://www.gatsbyjs.org))
1. `open http://localhost:8000` to open the site in your favorite browser
## Contributing
### Create a branch
1. `git checkout master` from any folder in your local react repository
1. `git pull origin master` to ensure you have the latest main code
1. `git checkout -b the-name-of-my-branch` (replacing `the-name-of-my-branch` with a suitable name) to create a branch
### Make the change
1. Follow the "Running locally" instructions
1. Save the files and check in the browser
1. Changes to React components in `src` will hot-reload
1. Changes to markdown files in `content` will hot-reload
1. If working with plugins, you may need to remove the `.cache` directory and restart the server
### Test the change
1. If possible, test any visual changes in all latest versions of common browsers, on both desktop and mobile.
1. Run `yarn check-all` from the project root. (This will run Prettier, ESlint, and Flow.)
### Push it
1. `git add -A && git commit -m "My message"` (replacing `My message` with a commit message, such as `Fixed header logo on Android`) to stage and commit your changes
1. `git push my-fork-name the-name-of-my-branch`
1. Go to the [reactjs.org repo](https://github.com/facebook/reactjs.org) and you should see recently pushed branches.
1. Follow GitHub's instructions.
1. If possible include screenshots of visual changes. A Netlify build will also be automatically created once you make your PR so other people can see your change.
## Troubleshooting
- `yarn reset` to clear the local cache

3
flow-typed/hex2rgba.js

@ -0,0 +1,3 @@
declare module 'hex2rgba' {
declare module.exports: (hex : string, alpha? : number) => string;
}

142
gatsby-config.js

@ -0,0 +1,142 @@
/**
* Copyright (c) 2013-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @emails react-core
*/
'use strict';
module.exports = {
siteMetadata: {
title: 'React: A JavaScript library for building user interfaces',
siteUrl: 'https://reactjs.org',
rssFeedTitle: 'React',
rssFeedDescription: 'A JavaScript library for building user interfaces',
},
mapping: {
'MarkdownRemark.frontmatter.author': 'AuthorYaml',
},
plugins: [
'gatsby-source-react-error-codes',
'gatsby-transformer-authors-yaml',
'gatsby-plugin-netlify',
'gatsby-plugin-glamor',
'gatsby-plugin-react-next',
'gatsby-plugin-twitter',
{
resolve: 'gatsby-plugin-nprogress',
options: {
color: '#61dafb',
},
},
{
resolve: 'gatsby-source-filesystem',
options: {
path: `${__dirname}/src/pages`,
name: 'pages',
},
},
{
resolve: 'gatsby-source-filesystem',
options: {
name: 'packages',
path: `${__dirname}/content/`,
},
},
{
resolve: 'gatsby-transformer-remark',
options: {
plugins: [
'gatsby-remark-responsive-iframe',
{
resolve: 'gatsby-remark-images',
options: {
maxWidth: 840,
},
},
'gatsby-remark-autolink-headers',
'gatsby-remark-use-jsx',
{
resolve: 'gatsby-remark-prismjs',
options: {
classPrefix: 'gatsby-code-',
},
},
'gatsby-remark-copy-linked-files',
'gatsby-remark-smartypants',
],
},
},
'gatsby-transformer-sharp',
'gatsby-plugin-sharp',
{
resolve: 'gatsby-plugin-google-analytics',
options: {
trackingId: 'UA-41298772-1',
},
},
{
resolve: 'gatsby-plugin-feed',
options: {
query: `
{
site {
siteMetadata {
title: rssFeedTitle
description: rssFeedDescription
siteUrl
site_url: siteUrl
}
}
}`,
feeds: [
{
serialize: ({query: {site, allMarkdownRemark}}) => {
return allMarkdownRemark.edges.map(edge => {
return Object.assign(
{},
{
title: edge.node.frontmatter.title,
description: edge.node.html,
date: require('moment')(edge.node.fields.date).format(
'MMMM DD, YYYY, h:mm A',
),
url: site.siteMetadata.siteUrl + edge.node.fields.slug,
guid: site.siteMetadata.siteUrl + edge.node.fields.slug,
},
);
});
},
query: `
{
allMarkdownRemark
(limit: 10,
filter: {id: {regex: "/blog/"}},
sort: {fields: [fields___date],
order: DESC}) {
edges {
node {
fields {
date
slug
}
frontmatter {
title
}
html
}
}
}
}
`,
output: '/feed.xml',
},
],
},
},
'gatsby-plugin-react-helmet',
],
};

244
gatsby-node.js

@ -0,0 +1,244 @@
/**
* Copyright (c) 2013-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @emails react-core
*/
'use strict';
const {resolve} = require('path');
const webpack = require('webpack');
exports.modifyWebpackConfig = ({config, stage}) => {
// See https://github.com/FormidableLabs/react-live/issues/5
config.plugin('ignore', () => new webpack.IgnorePlugin(/^(xor|props)$/));
config.merge({
resolve: {
root: resolve(__dirname, './src'),
extensions: ['', '.js', '.jsx', '.json'],
},
});
return config;
};
exports.createPages = async ({graphql, boundActionCreators}) => {
const {createPage, createRedirect} = boundActionCreators;
const blogTemplate = resolve('./src/templates/blog.js');
const communityTemplate = resolve('./src/templates/community.js');
const docsTemplate = resolve('./src/templates/docs.js');
const tutorialTemplate = resolve('./src/templates/tutorial.js');
const homeTemplate = resolve('./src/templates/home.js');
const allMarkdown = await graphql(
`
{
allMarkdownRemark(limit: 1000) {
edges {
node {
fields {
redirect
slug
}
}
}
}
}
`,
);
if (allMarkdown.errors) {
console.error(allMarkdown.errors);
throw Error(allMarkdown.errors);
}
allMarkdown.data.allMarkdownRemark.edges.forEach(edge => {
const slug = edge.node.fields.slug;
if (slug === '/index.html') {
createPage({
path: '/',
component: homeTemplate,
context: {
slug,
},
});
} else if (slug === 'docs/error-decoder.html') {
// No-op so far as markdown templates go.
// Error codes are managed by a page in src/pages
// (which gets created by Gatsby during a separate phase).
} else if (
slug.includes('blog/') ||
slug.includes('community/') ||
slug.includes('contributing/') ||
slug.includes('docs/') ||
slug.includes('tutorial/') ||
slug.includes('warnings/')
) {
let template;
if (slug.includes('blog/')) {
template = blogTemplate;
} else if (slug.includes('community/')) {
template = communityTemplate;
} else if (
slug.includes('contributing/') ||
slug.includes('docs/') ||
slug.includes('warnings/')
) {
template = docsTemplate;
} else if (slug.includes('tutorial/')) {
template = tutorialTemplate;
}
const createArticlePage = path =>
createPage({
path: path,
component: template,
context: {
slug,
},
});
// Register primary URL.
createArticlePage(slug);
// Register redirects as well if the markdown specifies them.
if (edge.node.fields.redirect) {
let redirect = JSON.parse(edge.node.fields.redirect);
if (!Array.isArray(redirect)) {
redirect = [redirect];
}
redirect.forEach(fromPath =>
createRedirect({
fromPath: `/${fromPath}`,
redirectInBrowser: true,
toPath: `/${slug}`,
}),
);
}
}
});
const newestBlogEntry = await graphql(
`
{
allMarkdownRemark(
limit: 1,
filter: { id: { regex: "/blog/" } }
sort: { fields: [fields___date], order: DESC }
) {
edges {
node {
fields {
slug
}
}
}
}
}
`,
);
const newestBlogNode = newestBlogEntry.data.allMarkdownRemark.edges[0].node;
// Blog landing page should always show the most recent blog entry.
createRedirect({
fromPath: '/blog/',
redirectInBrowser: true,
toPath: newestBlogNode.fields.slug,
});
};
// Parse date information out of blog post filename.
const BLOG_POST_FILENAME_REGEX = /([0-9]+)\-([0-9]+)\-([0-9]+)\-(.+)\.md$/;
// Add custom fields to MarkdownRemark nodes.
exports.onCreateNode = ({node, boundActionCreators, getNode}) => {
const {createNodeField} = boundActionCreators;
switch (node.internal.type) {
case 'MarkdownRemark':
const {permalink, redirect_from} = node.frontmatter;
const {relativePath} = getNode(node.parent);
let slug = permalink;
if (!slug) {
if (relativePath.includes('blog')) {
// Blog posts don't have embedded permalinks.
// Their slugs follow a pattern: /blog/<year>/<month>/<day>/<slug>.html
// The date portion comes from the file name: <date>-<title>.md
const match = BLOG_POST_FILENAME_REGEX.exec(relativePath);
const year = match[1];
const month = match[2];
const day = match[3];
const filename = match[4];
slug = `/blog/${year}/${month}/${day}/${filename}.html`;
const date = new Date(year, month - 1, day);
// Blog posts are sorted by date and display the date in their header.
createNodeField({
node,
name: 'date',
value: date.toJSON(),
});
}
}
if (!slug) {
slug = `/${relativePath.replace('.md', '.html')}`;
// This should (probably) only happen for the index.md,
// But let's log it in case it happens for other files also.
console.warn(
`Warning: No slug found for "${relativePath}". Falling back to default "${slug}".`,
);
}
// Used to generate URL to view this content.
createNodeField({
node,
name: 'slug',
value: slug,
});
// Used to generate a GitHub edit link.
createNodeField({
node,
name: 'path',
value: relativePath,
});
// Used by createPages() above to register redirects.
createNodeField({
node,
name: 'redirect',
value: redirect_from ? JSON.stringify(redirect_from) : '',
});
return;
}
};
exports.onCreatePage = async ({page, boundActionCreators}) => {
const {createPage} = boundActionCreators;
return new Promise(resolvePromise => {
// page.matchPath is a special key that's used for matching pages only on the client.
// Explicitly wire up all error code wildcard matches to redirect to the error code page.
if (page.path.includes('docs/error-decoder.html')) {
page.matchPath = 'docs/error-decoder:path?';
page.context.slug = 'docs/error-decoder.html';
createPage(page);
}
resolvePromise();
});
};

80
package.json

@ -0,0 +1,80 @@
{
"name": "react-website",
"description": "React website",
"version": "0.0.1",
"bugs": {
"url": "https://github.com/facebook/react"
},
"resolutions": {
"gatsby/graphql": "0.10.5",
"gatsby/react": "16.0.0",
"gatsby/react-dom": "16.0.0"
},
"dependencies": {
"@gaearon/react-live": "1.7.1-with-safari-fix",
"array-from": "^2.1.1",
"babel-eslint": "^8.0.1",
"eslint": "^4.8.0",
"eslint-config-react": "^1.1.7",
"eslint-plugin-flowtype": "^2.37.0",
"eslint-plugin-prettier": "^2.3.1",
"eslint-plugin-react": "^7.4.0",
"flow-bin": "^0.56.0",
"gatsby": "^1.9.9",
"gatsby-link": "^1.6.9",
"gatsby-plugin-feed": "^1.3.9",
"gatsby-plugin-glamor": "^1.6.4",
"gatsby-plugin-google-analytics": "^1.0.4",
"gatsby-plugin-manifest": "^1.0.4",
"gatsby-plugin-netlify": "^1.0.4",
"gatsby-plugin-nprogress": "^1.0.7",
"gatsby-plugin-react-helmet": "^1.0.3",
"gatsby-plugin-react-next": "^1.0.3",
"gatsby-plugin-sharp": "^1.6.2",
"gatsby-plugin-twitter": "^1.0.10",
"gatsby-remark-autolink-headers": "^1.4.4",
"gatsby-remark-copy-linked-files": "^1.5.2",
"gatsby-remark-images": "^1.5.11",
"gatsby-remark-prismjs": "^1.2.1",
"gatsby-remark-responsive-iframe": "^1.4.3",
"gatsby-remark-smartypants": "^1.4.3",
"gatsby-source-filesystem": "^1.4.4",
"gatsby-transformer-remark": "^1.7.2",
"gatsby-transformer-sharp": "^1.6.1",
"glamor": "^2.20.40",
"hex2rgba": "^0.0.1",
"prettier": "^1.7.4",
"remarkable": "^1.7.1",
"request-promise": "^4.2.2",
"rimraf": "^2.6.1",
"slugify": "^1.2.1",
"string.prototype.includes": "^1.0.0",
"string.prototype.repeat": "^0.2.0",
"unist-util-visit": "^1.1.3"
},
"engines": {
"node": ">=8.4.0"
},
"homepage": "https://reactjs.org/",
"keywords": [
"gatsby"
],
"license": "MIT",
"main": "n/a",
"repository": {
"type": "git",
"url": "git+https://github.com/facebook/react.git"
},
"scripts": {
"build": "gatsby build",
"check-all": "yarn prettier && yarn lint && yarn flow",
"dev": "gatsby develop -H 0.0.0.0",
"lint": "eslint .",
"netlify": "yarn install && yarn build",
"prettier": "prettier --no-bracket-spacing --single-quote --jsx-bracket-same-line --trailing-comma all --print-width 80 --parser flow --write 'src/**/*.js'",
"reset": "rimraf ./.cache"
},
"devDependencies": {
"eslint-config-prettier": "^2.6.0"
}
}

22
plugins/gatsby-remark-use-jsx/index.js

@ -0,0 +1,22 @@
const visit = require('unist-util-visit');
// Always treat JS blocks as JSX.
// TODO: maybe we can just change it in Markdown in the future?
module.exports = ({markdownAST}) => {
visit(markdownAST, `code`, node => {
if (typeof node.lang !== 'string') {
return;
}
if (node.lang.indexOf('jsx') === 0) {
// Already JSX (with optional line range).
return;
}
// Turn JS into JSX, preserving the optional line range.
if (node.lang.indexOf('js') === 0) {
node.lang = 'jsx' + node.lang.substring('js'.length);
}
if (node.lang.indexOf('javascript') === 0) {
node.lang = 'jsx' + node.lang.substring('javascript'.length);
}
});
};

4
plugins/gatsby-remark-use-jsx/package.json

@ -0,0 +1,4 @@
{
"name": "gatsby-remark-use-jsx",
"version": "0.0.1"
}

19
plugins/gatsby-source-react-error-codes/gatsby-node.js

@ -0,0 +1,19 @@
const request = require('request-promise');
const errorCodesUrl = 'http://raw.githubusercontent.com/facebook/react/master/scripts/error-codes/codes.json';
exports.sourceNodes = async ({ boundActionCreators }) => {
const { createNode } = boundActionCreators;
const jsonString = await request(errorCodesUrl);
createNode({
id: 'error-codes',
children: [],
parent: 'ERRORS',
internal: {
type: 'ErrorCodesJson',
contentDigest: jsonString,
},
});
};

4
plugins/gatsby-source-react-error-codes/package.json

@ -0,0 +1,4 @@
{
"name": "gatsby-source-react-error-codes",
"version": "0.0.1"
}

33
plugins/gatsby-transformer-authors-yaml/gatsby-node.js

@ -0,0 +1,33 @@
const readFileSync = require('fs').readFileSync;
const resolve = require('path').resolve;
const safeLoad = require('js-yaml').safeLoad;
// TODO It would be nice to replace this plugin with gatsby-transformer-yaml
// That plugin errors on some of the YML files in the docs folder though,
// And doesn't currently support any options to whitelist/blacklist files.
// Reads authors.yml data into GraphQL.
// This is auto-linked by gatsby-config.js to blog posts.
exports.sourceNodes = ({graphql, boundActionCreators}) => {
const {createNode} = boundActionCreators;
const path = resolve(__dirname, '../../content/authors.yml');
const file = readFileSync(path, 'utf8');
const authors = safeLoad(file);
// authors.yml structure is {[username: string]: {name: string, url: string}}
Object.keys(authors).forEach(username => {
const author = authors[username];
createNode({
id: username,
children: [],
parent: 'AUTHORS',
internal: {
type: 'AuthorYaml',
contentDigest: JSON.stringify(author),
},
frontmatter: author,
});
});
};

4
plugins/gatsby-transformer-authors-yaml/package.json

@ -0,0 +1,4 @@
{
"name": "gatsby-transformer-authors-yaml",
"version": "0.0.1"
}

282
src/components/CodeEditor/CodeEditor.js

@ -0,0 +1,282 @@
/**
* Copyright (c) 2013-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @emails react-core
*/
'use strict';
import React, {Component} from 'react';
import ReactDOM from 'react-dom';
import Remarkable from 'remarkable';
// TODO: switch back to the upstream version of react-live
// once https://github.com/FormidableLabs/react-live/issues/37 is fixed.
import {LiveProvider, LiveEditor} from '@gaearon/react-live';
import {colors, media} from 'theme';
import MetaTitle from 'templates/components/MetaTitle';
const compile = code =>
Babel.transform(code, {presets: ['es2015', 'react']}).code; // eslint-disable-line no-undef
class CodeEditor extends Component {
constructor(props, context) {
super(props, context);
this.state = this._updateState(props.code);
}
componentDidMount() {
// Initial render() will always be a no-op,
// Because the mountNode ref won't exist yet.
this._render();
}
componentDidUpdate(prevProps, prevState) {
if (prevState.compiled !== this.state.compiled) {
this._render();
}
}
render() {
const {children, code} = this.props;
const {error} = this.state;
return (
<LiveProvider code={code} mountStylesheet={false}>
<div
css={{
[media.greaterThan('xlarge')]: {
display: 'flex',
flexDirection: 'row',
},
[media.lessThan('large')]: {
display: 'block',
},
}}>
{children && (
<div
css={{
flex: '0 0 33%',
[media.lessThan('xlarge')]: {
marginBottom: 20,
},
'& h3': {
color: colors.dark,
maxWidth: '11em',
paddingTop: 0,
},
'& p': {
marginTop: 15,
marginRight: 40,
lineHeight: 1.7,
[media.greaterThan('xlarge')]: {
marginTop: 25,
},
},
}}>
{children}
</div>
)}
<div
css={{
[media.greaterThan('medium')]: {
flex: '0 0 67%',
display: 'flex',
alignItems: 'stretch',
flexDirection: 'row',
},
[media.lessThan('small')]: {
display: 'block',
},
}}>
<div
css={{
flex: '0 0 70%',
overflow: 'hidden',
borderRadius: '10px 0 0 10px',
[media.lessThan('small')]: {
borderRadius: '10px 10px 0 0',
},
}}>
<div
css={{
padding: '0px 10px',
background: colors.darker,
color: colors.white,
}}>
<MetaTitle onDark={true}>Live JSX Editor</MetaTitle>
</div>
<div
css={{
height: '100%',
width: '100%',
borderRadius: '0',
marginTop: '0 !important',
marginLeft: '0 !important',
paddingLeft: '0 !important',
marginRight: '0 !important',
paddingRight: '0 !important',
'& pre.prism-code[contenteditable]': {
maxHeight: '280px !important',
outline: 0,
},
}}
className="gatsby-highlight">
<LiveEditor onChange={this._onChange} />
</div>
</div>
{error && (
<div
css={{
flex: '0 0 30%',
overflow: 'hidden',
border: `1px solid ${colors.error}`,
borderRadius: '0 10px 10px 0',
fontSize: 12,
lineHeight: 1.5,
[media.lessThan('small')]: {
borderRadius: '0 0 10px 10px',
},
}}>
<div
css={{
padding: '0px 10px',
background: colors.error,
color: colors.white,
}}>
<MetaTitle
cssProps={{
color: colors.white,
}}>
Error
</MetaTitle>
</div>
<pre
css={{
whiteSpace: 'pre-wrap',
wordBreak: 'break-word',
color: colors.error,
padding: 10,
}}>
{error.message}
</pre>
</div>
)}
{!error && (
<div
css={{
flex: '0 0 30%',
overflow: 'hidden',
border: `1px solid ${colors.divider}`,
borderRadius: '0 10px 10px 0',
[media.lessThan('small')]: {
borderRadius: '0 0 10px 10px',
},
}}>
<div
css={{
padding: '0 10px',
backgroundColor: colors.divider,
}}>
<MetaTitle>Result</MetaTitle>
</div>
<div
css={{
padding: 10,
'& input': {
width: '100%',
display: 'block',
border: '1px solid #ccc', // TODO
padding: 5,
},
'& button': {
marginTop: 10,
padding: '5px 10px',
},
'& textarea': {
width: '100%',
marginTop: 10,
height: 60,
padding: 5,
},
}}
ref={this._setMountRef}
/>
</div>
)}
</div>
</div>
</LiveProvider>
);
}
_render() {
if (!this._mountNode) {
return;
}
const {compiled} = this.state;
try {
// Example code requires React, ReactDOM, and Remarkable to be within scope.
// It also requires a "mountNode" variable for ReactDOM.render()
// eslint-disable-next-line no-new-func
new Function('React', 'ReactDOM', 'Remarkable', 'mountNode', compiled)(
React,
ReactDOM,
Remarkable,
this._mountNode,
);
} catch (error) {
console.error(error);
this.setState({
compiled: null,
error,
});
}
}
_setMountRef = ref => {
this._mountNode = ref;
};
_updateState(code) {
try {
return {
compiled: compile(code),
error: null,
};
} catch (error) {
console.error(error);
return {
compiled: null,
error,
};
}
}
_onChange = code => {
this.setState(this._updateState(code));
};
}
export default CodeEditor;

14
src/components/CodeEditor/index.js

@ -0,0 +1,14 @@
/**
* Copyright (c) 2013-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @emails react-core
*/
'use strict';
import CodeEditor from './CodeEditor';
export default CodeEditor;

40
src/components/Container/Container.js

@ -0,0 +1,40 @@
/**
* Copyright (c) 2013-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @emails react-core
*/
'use strict';
import React from 'react';
import {media} from 'theme';
/**
* This component wraps page content sections (eg header, footer, main).
* It provides consistent margin and max width behavior.
*/
const Container = ({children}) => (
<div
css={{
paddingLeft: 20,
paddingRight: 20,
marginLeft: 'auto',
marginRight: 'auto',
[media.greaterThan('medium')]: {
width: '90%',
},
[media.size('xxlarge')]: {
maxWidth: 1260,
},
}}>
{children}
</div>
);
export default Container;

14
src/components/Container/index.js

@ -0,0 +1,14 @@
/**
* Copyright (c) 2013-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @emails react-core
*/
'use strict';
import Container from './Container';
export default Container;

120
src/components/ErrorDecoder/ErrorDecoder.js

@ -0,0 +1,120 @@
/**
* Copyright (c) 2013-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @emails react-core
*/
'use strict';
import React, {Component} from 'react';
import PropTypes from 'prop-types';
function replaceArgs(msg, argList) {
let argIdx = 0;
return msg.replace(/%s/g, function() {
const arg = argList[argIdx++];
return arg === undefined ? '[missing argument]' : arg;
});
}
function urlify(str) {
const urlRegex = /(https:\/\/fb\.me\/[a-z\-]+)/g;
const segments = str.split(urlRegex);
for (let i = 0; i < segments.length; i++) {
if (i % 2 === 1) {
segments[i] = (
<a key={i} target="_blank" rel="noopener" href={segments[i]}>
{segments[i]}
</a>
);
}
}
return segments;
}
// ?invariant=123&args[]=foo&args[]=bar
function parseQueryString(location) {
const rawQueryString = location.search.substring(1);
if (!rawQueryString) {
return null;
}
let code = '';
let args = [];
const queries = rawQueryString.split('&');
for (let i = 0; i < queries.length; i++) {
const query = decodeURIComponent(queries[i]);
if (query.indexOf('invariant=') === 0) {
code = query.slice(10);
} else if (query.indexOf('args[]=') === 0) {
args.push(query.slice(7));
}
}
return [code, args];
}
function ErrorResult(props) {
const code = props.code;
const errorMsg = props.msg;
if (!code) {
return (
<p>
When you encounter an error, you'll receive a link to this page for that
specific error and we'll show you the full error text.
</p>
);
}
return (
<div>
<p>The full text of the error you just encountered is:</p>
<code>{urlify(errorMsg)}</code>
</div>
);
}
class ErrorDecoder extends Component {
constructor(...args) {
super(...args);
this.state = {
code: null,
errorMsg: '',
};
}
componentWillMount() {
const {errorCodesString} = this.props;
const errorCodes = JSON.parse(errorCodesString);
const parseResult = parseQueryString(this.props.location);
if (parseResult != null) {
const [code, args] = parseResult;
if (errorCodes[code]) {
this.setState({
code: code,
errorMsg: replaceArgs(errorCodes[code], args),
});
}
}
}
render() {
return <ErrorResult code={this.state.code} msg={this.state.errorMsg} />;
}
}
ErrorDecoder.propTypes = {
errorCodesString: PropTypes.string.isRequired,
location: PropTypes.object.isRequired,
};
export default ErrorDecoder;

14
src/components/ErrorDecoder/index.js

@ -0,0 +1,14 @@
/**
* Copyright (c) 2013-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @emails react-core
*/
'use strict';
import ErrorDecoder from './ErrorDecoder';
export default ErrorDecoder;

45
src/components/Flex/Flex.js

@ -0,0 +1,45 @@
/**
* Copyright (c) 2013-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @emails react-core
*/
'use strict';
import {createElement} from 'glamor/react';
/**
* Convenience component for declaring a flexbox layout.
*/
const Flex = ({
basis = 'auto',
children,
direction = 'row',
grow = 0,
halign = 'flex-start',
shrink = 1,
type = 'div',
valign = 'flex-start',
...rest
}) =>
createElement(
type,
{
css: {
display: 'flex',
flexDirection: direction,
flexGrow: grow,
flexShrink: shrink,
flexBasis: basis,
justifyContent: direction === 'row' ? halign : valign,
alignItems: direction === 'row' ? valign : halign,
},
...rest,
},
children,
);
export default Flex;

14
src/components/Flex/index.js

@ -0,0 +1,14 @@
/**
* Copyright (c) 2013-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @emails react-core
*/
'use strict';
import Flex from './Flex';
export default Flex;

26
src/components/Header/Header.js

@ -0,0 +1,26 @@
/**
* Copyright (c) 2013-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @emails react-core
*/
'use strict';
import React from 'react';
import {colors, fonts} from 'theme';
const Header = ({children}) => (
<h1
css={{
color: colors.dark,
marginRight: '5%',
...fonts.header,
}}>
{children}
</h1>
);
export default Header;

14
src/components/Header/index.js

@ -0,0 +1,14 @@
/**
* Copyright (c) 2013-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @emails react-core
*/
'use strict';
import Header from './Header';
export default Header;

39
src/components/LayoutFooter/ExternalFooterLink.js

@ -0,0 +1,39 @@
/**
* Copyright (c) 2013-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @emails react-core
*/
'use strict';
import React from 'react';
import {colors} from 'theme';
import ExternalLinkSvg from 'templates/components/ExternalLinkSvg';
const ExternalFooterLink = ({children, href, target, rel}) => (
<a
css={{
lineHeight: 2,
':hover': {
color: colors.brand,
},
}}
href={href}
target={target}
rel={rel}>
{children}
<ExternalLinkSvg
cssProps={{
verticalAlign: -2,
display: 'inline-block',
marginLeft: 5,
color: colors.subtle,
}}
/>
</a>
);
export default ExternalFooterLink;

193
src/components/LayoutFooter/Footer.js

@ -0,0 +1,193 @@
/**
* Copyright (c) 2013-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @emails react-core
*/
'use strict';
import Container from 'components/Container';
import ExternalFooterLink from './ExternalFooterLink';
import FooterLink from './FooterLink';
import FooterNav from './FooterNav';
import MetaTitle from 'templates/components/MetaTitle';
import React from 'react';
import {colors, media} from 'theme';
import ossLogoPng from 'images/oss_logo.png';
const Footer = ({layoutHasSidebar = false}) => (
<footer
css={{
backgroundColor: colors.darker,
color: colors.white,
paddingTop: 10,
paddingBottom: 50,
[media.size('sidebarFixed')]: {
paddingTop: 40,
},
}}>
<Container>
<div
css={{
display: 'flex',
flexDirection: 'row',
flexWrap: 'wrap',
[media.between('small', 'medium')]: {
paddingRight: layoutHasSidebar ? 240 : null,
},
[media.between('large', 'largerSidebar')]: {
paddingRight: layoutHasSidebar ? 280 : null,
},
[media.between('largerSidebar', 'sidebarFixed', true)]: {
paddingRight: layoutHasSidebar ? 380 : null,
},
}}>
<div
css={{
flexWrap: 'wrap',
display: 'flex',
[media.lessThan('large')]: {
width: '100%',
},
[media.greaterThan('xlarge')]: {
width: 'calc(100% / 3 * 2)',
paddingLeft: 40,
},
}}>
<FooterNav layoutHasSidebar={layoutHasSidebar}>
<MetaTitle onDark={true}>Docs</MetaTitle>
<FooterLink to="/docs/hello-world.html">Quick Start</FooterLink>
<FooterLink to="/docs/thinking-in-react.html">
Thinking in React
</FooterLink>
<FooterLink to="/tutorial/tutorial.html">Tutorial</FooterLink>
<FooterLink to="/docs/jsx-in-depth.html">
Advanced Guides
</FooterLink>
</FooterNav>
<FooterNav layoutHasSidebar={layoutHasSidebar}>
<MetaTitle onDark={true}>Community</MetaTitle>
<ExternalFooterLink
href="http://stackoverflow.com/questions/tagged/reactjs"
target="_blank"
rel="noopener">
Stack Overflow
</ExternalFooterLink>
<ExternalFooterLink
href="https://discuss.reactjs.org"
target="_blank"
rel="noopener">
Discussion Forum
</ExternalFooterLink>
<ExternalFooterLink
href="https://discord.gg/0ZcbPKXt5bZjGY5n"
target="_blank"
rel="noopener">
Reactiflux Chat
</ExternalFooterLink>
<ExternalFooterLink
href="https://www.facebook.com/react"
target="_blank"
rel="noopener">
Facebook
</ExternalFooterLink>
<ExternalFooterLink
href="https://twitter.com/reactjs"
target="_blank"
rel="noopener">
Twitter
</ExternalFooterLink>
</FooterNav>
<FooterNav layoutHasSidebar={layoutHasSidebar}>
<MetaTitle onDark={true}>Resources</MetaTitle>
<FooterLink to="/community/conferences.html">
Conferences
</FooterLink>
<FooterLink to="/community/videos.html">Videos</FooterLink>
<ExternalFooterLink
href="https://github.com/facebook/react/wiki/Examples"
target="_blank"
rel="noopener">
Examples
</ExternalFooterLink>
<ExternalFooterLink
href="https://github.com/facebook/react/wiki/Complementary-Tools"
target="_blank"
rel="noopener">
Complementary Tools
</ExternalFooterLink>
</FooterNav>
<FooterNav layoutHasSidebar={layoutHasSidebar}>
<MetaTitle onDark={true}>More</MetaTitle>
<FooterLink to="/blog/">Blog</FooterLink>
<ExternalFooterLink
href="https://github.com/facebook/react"
target="_blank"
rel="noopener">
GitHub
</ExternalFooterLink>
<ExternalFooterLink
href="http://facebook.github.io/react-native/"
target="_blank"
rel="noopener">
React Native
</ExternalFooterLink>
<FooterLink to="/acknowledgements.html">
Acknowledgements
</FooterLink>
</FooterNav>
</div>
<section
css={{
paddingTop: 40,
display: 'block !important', // Override 'Installation' <style> specifics
[media.greaterThan('xlarge')]: {
width: 'calc(100% / 3)',
order: -1,
},
[media.greaterThan('large')]: {
order: -1,
width: layoutHasSidebar ? null : 'calc(100% / 3)',
},
[media.lessThan('large')]: {
textAlign: 'center',
width: '100%',
paddingTop: 40,
},
}}>
<a
href="https://code.facebook.com/projects/"
target="_blank"
rel="noopener">
<img
alt="Facebook Open Source"
css={{
maxWidth: 160,
height: 'auto',
}}
src={ossLogoPng}
/>
</a>
<p
css={{
color: colors.subtleOnDark,
paddingTop: 15,
}}>
Copyright © 2017 Facebook Inc.
</p>
</section>
</div>
</Container>
</footer>
);
export default Footer;

30
src/components/LayoutFooter/FooterLink.js

@ -0,0 +1,30 @@
/**
* Copyright (c) 2013-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @emails react-core
*/
'use strict';
import Link from 'gatsby-link';
import React from 'react';
import {colors} from 'theme';
const FooterLink = ({children, target, to}) => (
<Link
css={{
lineHeight: 2,
':hover': {
color: colors.brand,
},
}}
to={to}
target={target}>
{children}
</Link>
);
export default FooterLink;

39
src/components/LayoutFooter/FooterNav.js

@ -0,0 +1,39 @@
/**
* Copyright (c) 2013-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @emails react-core
*/
'use strict';
import React from 'react';
import {media} from 'theme';
const FooterNav = ({children, title, layoutHasSidebar = false}) => (
<div
css={{
display: 'flex',
flexDirection: 'column',
alignItems: 'flex-start',
width: '50%',
paddingTop: 40,
[media.size('sidebarFixed')]: {
paddingTop: 0,
width: '25%',
},
}}>
<div
css={{
display: 'inline-flex',
flexDirection: 'column',
}}>
{children}
</div>
</div>
);
export default FooterNav;

14
src/components/LayoutFooter/index.js

@ -0,0 +1,14 @@
/**
* Copyright (c) 2013-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @emails react-core
*/
'use strict';
import Footer from './Footer';
export default Footer;

251
src/components/LayoutHeader/Header.js

@ -0,0 +1,251 @@
/**
* Copyright (c) 2013-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @emails react-core
*/
'use strict';
import Container from 'components/Container';
import HeaderLink from './HeaderLink';
import Link from 'gatsby-link';
import React from 'react';
import {colors, fonts, media} from 'theme';
import {version} from 'site-constants';
import ExternalLinkSvg from 'templates/components/ExternalLinkSvg';
import logoSvg from 'icons/logo.svg';
const Header = ({location}) => (
<header
css={{
backgroundColor: colors.darker,
color: colors.white,
position: 'fixed',
zIndex: 1,
width: '100%',
top: 0,
left: 0,
}}>
<Container>
<div
css={{
display: 'flex',
flexDirection: 'row',
alignItems: 'center',
height: 60,
[media.between('small', 'large')]: {
height: 50,
},
[media.lessThan('small')]: {
height: 40,
},
}}>
<Link
css={{
display: 'flex',
marginRight: 10,
height: '100%',
alignItems: 'center',
[media.greaterThan('small')]: {
width: 'calc(100% / 6)',
},
[media.lessThan('small')]: {
flex: '0 0 auto',
},
}}
to="/">
<img src={logoSvg} alt="" height="20" />
<span
css={{
color: colors.brand,
marginLeft: 10,
fontWeight: 700,
fontSize: 20,
lineHeight: '20px',
[media.lessThan('large')]: {
fontSize: 16,
marginTop: 1,
},
[media.lessThan('small')]: {
// Visually hidden
position: 'absolute',
overflow: 'hidden',
clip: 'rect(0 0 0 0)',
height: 1,
width: 1,
margin: -1,
padding: 0,
border: 0,
},
}}>
React
</span>
</Link>
<nav
css={{
display: 'flex',
flexDirection: 'row',
alignItems: 'stretch',
overflowX: 'auto',
overflowY: 'hidden',
WebkitOverflowScrolling: 'touch',
height: '100%',
width: '60%',
[media.size('xsmall')]: {
flexGrow: '1',
width: 'auto',
},
[media.greaterThan('xlarge')]: {
width: null,
},
[media.lessThan('small')]: {
maskImage:
'linear-gradient(to right, transparent, black 20px, black 90%, transparent)',
},
}}>
<HeaderLink
isActive={location.pathname.includes('/docs/')}
title="Docs"
to="/docs/hello-world.html"
/>
<HeaderLink
isActive={location.pathname.includes('/tutorial/')}
title="Tutorial"
to="/tutorial/tutorial.html"
/>
<HeaderLink
isActive={location.pathname.includes('/community/')}
title="Community"
to="/community/support.html"
/>
<HeaderLink
isActive={location.pathname.includes('/blog')}
title="Blog"
to="/blog/"
/>
</nav>
<form
css={{
display: 'flex',
flex: '0 0 auto',
flexDirection: 'row',
alignItems: 'center',
paddingLeft: '0.5rem',
paddingRight: '0.5rem',
[media.lessThan('small')]: {
justifyContent: 'flex-end',
},
[media.lessThan('large')]: {
marginRight: 10,
},
[media.between('small', 'medium')]: {
width: 'calc(100% / 3)',
},
[media.between('medium', 'xlarge')]: {
width: 'calc(100% / 6)',
},
[media.greaterThan('small')]: {
minWidth: 120,
},
}}>
<input
css={{
appearance: 'none',
background: 'transparent',
border: 0,
color: colors.white,
fontSize: 18,
fontWeight: 300,
fontFamily: 'inherit',
position: 'relative',
paddingLeft: '24px',
backgroundImage: 'url(/search.svg)',
backgroundSize: '16px 16px',
backgroundRepeat: 'no-repeat',
backgroundPositionY: 'center',
backgroundPositionX: 'left',
[media.lessThan('large')]: {
fontSize: 16,
},
[media.greaterThan('small')]: {
width: '100%',
},
[media.lessThan('small')]: {
width: '16px',
transition: 'width 0.2s ease, padding 0.2s ease',
paddingLeft: '16px',
':focus': {
paddingLeft: '24px',
width: '8rem',
outline: 'none',
},
},
}}
id="algolia-doc-search"
type="search"
placeholder="Search docs"
aria-label="Search docs"
/>
</form>
<div
css={{
[media.lessThan('medium')]: {
display: 'none',
},
[media.greaterThan('large')]: {
width: 'calc(100% / 6)',
},
}}>
<a
css={{
padding: '5px 10px',
backgroundColor: colors.lighter,
borderRadius: 15,
whiteSpace: 'nowrap',
...fonts.small,
}}
href="https://github.com/facebook/react/releases"
target="_blank"
rel="noopener">
v{version}
</a>
<a
css={{
padding: '5px 10px',
marginLeft: 10,
whiteSpace: 'nowrap',
...fonts.small,
':hover': {
color: colors.brand,
},
}}
href="https://github.com/facebook/react/"
target="_blank"
rel="noopener">
GitHub
<ExternalLinkSvg
cssProps={{
marginLeft: 5,
verticalAlign: -2,
color: colors.subtle,
}}
/>
</a>
</div>
</div>
</Container>
</header>
);
export default Header;

74
src/components/LayoutHeader/HeaderLink.js

@ -0,0 +1,74 @@
/**
* Copyright (c) 2013-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @emails react-core
*/
'use strict';
import Link from 'gatsby-link';
import React from 'react';
import {colors, media} from 'theme';
const HeaderLink = ({isActive, title, to}) => (
<Link css={[style, isActive && activeStyle]} to={to}>
{title}
{isActive && <span css={activeAfterStyle} />}
</Link>
);
const style = {
display: 'flex',
flexDirection: 'row',
alignItems: 'center',
color: colors.white,
transition: 'color 0.2s ease-out',
paddingLeft: 15,
paddingRight: 15,
fontWeight: 300,
[media.size('xsmall')]: {
paddingLeft: 8,
paddingRight: 8,
},
[media.between('small', 'medium')]: {
paddingLeft: 10,
paddingRight: 10,
},
[media.greaterThan('xlarge')]: {
paddingLeft: 20,
paddingRight: 20,
fontSize: 18,
':hover': {
color: colors.brand,
},
},
};
const activeStyle = {
color: colors.brand,
[media.greaterThan('small')]: {
position: 'relative',
},
};
const activeAfterStyle = {
[media.greaterThan('small')]: {
position: 'absolute',
bottom: -1,
height: 4,
background: colors.brand,
left: 0,
right: 0,
zIndex: 1,
},
};
export default HeaderLink;

33
src/components/LayoutHeader/SearchSvg.js

@ -0,0 +1,33 @@
/**
* Copyright (c) 2013-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @emails react-core
*/
'use strict';
import React from 'react';
const SearchSvg = () => (
<svg
alt="Search"
height="16"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 16 16">
<title>Search</title>
<path
d={`
M6.02945,10.20327a4.17382,4.17382,0,1,1,4.17382-4.17382A4.15609,4.15609,
0,0,1,6.02945,10.20327Zm9.69195,4.2199L10.8989,9.59979A5.88021,5.88021,
0,0,0,12.058,6.02856,6.00467,6.00467,0,1,0,9.59979,10.8989l4.82338,
4.82338a.89729.89729,0,0,0,1.29912,0,.89749.89749,0,0,0-.00087-1.29909Z
`}
fill="currentColor"
/>
</svg>
);
export default SearchSvg;

14
src/components/LayoutHeader/index.js

@ -0,0 +1,14 @@
/**
* Copyright (c) 2013-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @emails react-core
*/
'use strict';
import Header from './Header';
export default Header;

43
src/components/MarkdownHeader/MarkdownHeader.js

@ -0,0 +1,43 @@
/**
* Copyright (c) 2013-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @emails react-core
*/
'use strict';
import Flex from 'components/Flex';
import PropTypes from 'prop-types';
import React from 'react';
import {colors, fonts, media} from 'theme';
const MarkdownHeader = ({title}) => (
<Flex type="header" halign="space-between" valign="baseline">
<h1
css={{
color: colors.dark,
marginBottom: 0,
marginTop: 40,
...fonts.header,
[media.size('medium')]: {
marginTop: 60,
},
[media.greaterThan('large')]: {
marginTop: 80,
},
}}>
{title}
</h1>
</Flex>
);
MarkdownHeader.propTypes = {
title: PropTypes.string.isRequired,
};
export default MarkdownHeader;

14
src/components/MarkdownHeader/index.js

@ -0,0 +1,14 @@
/**
* Copyright (c) 2013-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @emails react-core
*/
'use strict';
import MarkdownHeader from './MarkdownHeader';
export default MarkdownHeader;

140
src/components/MarkdownPage/MarkdownPage.js

@ -0,0 +1,140 @@
/**
* Copyright (c) 2013-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @emails react-core
*/
'use strict';
import Container from 'components/Container';
import Flex from 'components/Flex';
import MarkdownHeader from 'components/MarkdownHeader';
import NavigationFooter from 'templates/components/NavigationFooter';
import PropTypes from 'prop-types';
import React from 'react';
import StickyResponsiveSidebar from 'components/StickyResponsiveSidebar';
import TitleAndMetaTags from 'components/TitleAndMetaTags';
import findSectionForPath from 'utils/findSectionForPath';
import toCommaSeparatedList from 'utils/toCommaSeparatedList';
import {sharedStyles} from 'theme';
import createOgUrl from 'utils/createOgUrl';
const MarkdownPage = ({
authors,
createLink,
date,
ogDescription,
location,
markdownRemark,
sectionList,
titlePostfix = '',
}) => {
const hasAuthors = authors.length > 0;
const titlePrefix = markdownRemark.frontmatter.title || '';
return (
<Flex
direction="column"
grow="1"
shrink="0"
halign="stretch"
css={{
width: '100%',
flex: '1 0 auto',
position: 'relative',
zIndex: 0,
}}>
<TitleAndMetaTags
ogDescription={ogDescription}
ogUrl={createOgUrl(markdownRemark.fields.slug)}
title={`${titlePrefix}${titlePostfix}`}
/>
<div css={{flex: '1 0 auto'}}>
<Container>
<div css={sharedStyles.articleLayout.container}>
<Flex type="article" direction="column" grow="1" halign="stretch">
<MarkdownHeader title={titlePrefix} />
{(date || hasAuthors) && (
<div css={{marginTop: 15}}>
{date}{' '}
{hasAuthors && (
<span>
by{' '}
{toCommaSeparatedList(authors, author => (
<a
css={sharedStyles.link}
href={author.frontmatter.url}
key={author.frontmatter.name}>
{author.frontmatter.name}
</a>
))}
</span>
)}
</div>
)}
<div css={sharedStyles.articleLayout.content}>
<div
css={[sharedStyles.markdown]}
dangerouslySetInnerHTML={{__html: markdownRemark.html}}
/>
{markdownRemark.fields.path && (
<div css={{marginTop: 80}}>
<a
css={sharedStyles.articleLayout.editLink}
href={`https://github.com/facebook/react/tree/master/docs/${markdownRemark
.fields.path}`}>
Edit this page
</a>
</div>
)}
</div>
</Flex>
<div css={sharedStyles.articleLayout.sidebar}>
<StickyResponsiveSidebar
createLink={createLink}
defaultActiveSection={findSectionForPath(
location.pathname,
sectionList,
)}
location={location}
sectionList={sectionList}
/>
</div>
</div>
</Container>
</div>
{/* TODO Read prev/next from index map, not this way */}
{(markdownRemark.frontmatter.next || markdownRemark.frontmatter.prev) && (
<NavigationFooter
location={location}
next={markdownRemark.frontmatter.next}
prev={markdownRemark.frontmatter.prev}
/>
)}
</Flex>
);
};
MarkdownPage.defaultProps = {
authors: [],
};
// TODO Better types
MarkdownPage.propTypes = {
authors: PropTypes.array.isRequired,
createLink: PropTypes.func.isRequired,
date: PropTypes.string,
location: PropTypes.object.isRequired,
markdownRemark: PropTypes.object.isRequired,
sectionList: PropTypes.array.isRequired,
};
export default MarkdownPage;

14
src/components/MarkdownPage/index.js

@ -0,0 +1,14 @@
/**
* Copyright (c) 2013-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @emails react-core
*/
'use strict';
import MarkdownPage from './MarkdownPage';
export default MarkdownPage;

199
src/components/StickyResponsiveSidebar/StickyResponsiveSidebar.js

@ -0,0 +1,199 @@
/**
* Copyright (c) 2013-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @emails react-core
*/
'use strict';
import Container from 'components/Container';
import {Component, React} from 'react';
import Sidebar from 'templates/components/Sidebar';
import {colors, media} from 'theme';
import ChevronSvg from 'templates/components/ChevronSvg';
class StickyResponsiveSidebar extends Component {
constructor(props, context) {
super(props, context);
this.state = {
open: false,
};
this._openNavMenu = this._openNavMenu.bind(this);
this._closeNavMenu = this._closeNavMenu.bind(this);
}
_openNavMenu() {
this.setState({open: !this.state.open});
}
_closeNavMenu() {
this.setState({open: false});
}
render() {
const {open} = this.state;
const smallScreenSidebarStyles = {
top: 0,
left: 0,
bottom: 0,
right: 0,
position: 'fixed',
backgroundColor: colors.white,
zIndex: 2,
height: '100vh',
overflowY: 'auto',
WebkitOverflowScrolling: 'touch',
pointerEvents: open ? 'auto' : 'none',
};
const smallScreenBottomBarStyles = {
display: 'inline-block',
};
const iconOffset = open ? 8 : -4;
const menuOpacity = open ? 1 : 0;
const menuOffset = open ? 0 : 40;
// TODO: role and aria props for 'close' button?
return (
<div>
<div
style={{
opacity: menuOpacity,
transition: 'opacity 0.5s ease',
}}
css={{
[media.lessThan('small')]: smallScreenSidebarStyles,
[media.greaterThan('medium')]: {
marginRight: -999,
paddingRight: 999,
backgroundColor: '#f7f7f7',
},
[media.between('medium', 'sidebarFixed', true)]: {
position: 'fixed',
zIndex: 2,
height: '100%',
},
[media.greaterThan('small')]: {
position: 'fixed',
zIndex: 2,
height: 'calc(100vh - 60px)',
overflowY: 'auto',
WebkitOverflowScrolling: 'touch',
marginRight: -999,
paddingRight: 999,
backgroundColor: '#f7f7f7',
opacity: '1 !important',
},
[media.size('small')]: {
height: 'calc(100vh - 40px)',
},
[media.between('medium', 'large')]: {
height: 'calc(100vh - 50px)',
},
[media.greaterThan('sidebarFixed')]: {
borderLeft: '1px solid #ececec',
},
}}>
<div
style={{
transform: `translate(0px, ${menuOffset}px)`,
transition: 'transform 0.5s ease',
}}
css={{
marginTop: 60,
[media.size('xsmall')]: {
marginTop: 40,
},
[media.between('small', 'medium')]: {
marginTop: 0,
},
[media.between('medium', 'large')]: {
marginTop: 50,
},
[media.greaterThan('small')]: {
tranform: 'none !important',
},
}}>
<Sidebar closeParentMenu={this._closeNavMenu} {...this.props} />
</div>
</div>
<div
css={{
backgroundColor: colors.darker,
bottom: 44, // iOS Safari's inert "bottom 44px"
color: colors.brand,
display: 'none', // gets overriden at small screen sizes
cursor: 'pointer',
position: 'fixed',
right: 20,
zIndex: 3,
borderRadius: '50%',
border: '1px solid rgba(255, 255, 255, 0.1)',
boxShadow: '0 0 20px rgba(0, 0, 0, 0.3)',
[media.lessThan('small')]: smallScreenBottomBarStyles,
}}
onClick={this._openNavMenu}>
<Container>
<div
css={{
display: 'flex',
flexDirection: 'row',
alignItems: 'center',
height: 60,
[media.between('medium', 'large')]: {
height: 50,
},
[media.lessThan('small')]: {
height: 60,
overflow: 'hidden',
alignItems: 'flex-start',
},
}}>
<div
css={{
width: 20,
height: 20,
alignSelf: 'center',
display: 'flex',
flexDirection: 'column',
color: colors.brand,
}}>
<ChevronSvg
size={15}
cssProps={{
transform: `translate(2px, ${iconOffset}px) rotate(180deg)`,
transition: 'transform 0.2s ease',
}}
/>
<ChevronSvg
size={15}
cssProps={{
transform: `translate(2px, ${0 - iconOffset}px)`,
transition: 'transform 0.2s ease',
}}
/>
</div>
</div>
</Container>
</div>
</div>
);
}
}
export default StickyResponsiveSidebar;

14
src/components/StickyResponsiveSidebar/index.js

@ -0,0 +1,14 @@
/**
* Copyright (c) 2013-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @emails react-core
*/
'use strict';
import StickyResponsiveSidebar from './StickyResponsiveSidebar';
export default StickyResponsiveSidebar;

33
src/components/TitleAndMetaTags/TitleAndMetaTags.js

@ -0,0 +1,33 @@
/**
* Copyright (c) 2013-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @emails react-core
*/
'use strict';
import Helmet from 'react-helmet';
import React from 'react';
const defaultDescription = 'A JavaScript library for building user interfaces';
const TitleAndMetaTags = ({title, ogDescription, ogUrl}) => {
return (
<Helmet title={title}>
<meta property="og:title" content={title} />
<meta property="og:type" content="website" />
{ogUrl && <meta property="og:url" content={ogUrl} />}
<meta property="og:image" content="/logo-og.png" />
<meta
property="og:description"
content={ogDescription || defaultDescription}
/>
<meta property="fb:app_id" content="623268441017527" />
</Helmet>
);
};
export default TitleAndMetaTags;

14
src/components/TitleAndMetaTags/index.js

@ -0,0 +1,14 @@
/**
* Copyright (c) 2013-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @emails react-core
*/
'use strict';
import TitleAndMetaTags from './TitleAndMetaTags';
export default TitleAndMetaTags;

453
src/css/algolia.css

File diff suppressed because one or more lines are too long

42
src/css/reset.css

@ -0,0 +1,42 @@
html {
box-sizing: border-box;
font-family: -apple-system, BlinkMacSystemFont,
"Segoe UI", "Roboto", "Oxygen", "Ubuntu", "Cantarell",
"Fira Sans", "Droid Sans", "Helvetica Neue",
sans-serif;
font-weight: 400;
font-style: normal;
-webkit-font-smoothing: antialiased;
}
body {
overflow-x: hidden;
position: relative;
}
* {
margin: 0;
padding: 0;
}
*, *::before, *::after {
box-sizing: inherit;
}
a {
color: inherit;
text-decoration: none;
}
ul, ol {
list-style: none;
}
img {
display: inline-block;
vertical-align: top;
}
pre, code {
font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New", monospace;
}

66
src/html.js

@ -0,0 +1,66 @@
/**
* Copyright (c) 2013-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @emails react-core
*/
'use strict';
import React, {Component} from 'react';
let stylesStr;
if (process.env.NODE_ENV === `production`) {
try {
stylesStr = require(`!raw-loader!../public/styles.css`);
} catch (e) {
console.log(e);
}
}
const JS_NPM_URLS = [
'//unpkg.com/docsearch.js@2.4.1/dist/cdn/docsearch.min.js',
'//unpkg.com/babel-standalone@6.26.0/babel.min.js',
];
export default class HTML extends Component {
render() {
let css;
if (process.env.NODE_ENV === 'production') {
css = (
<style
id="gatsby-inlined-css"
dangerouslySetInnerHTML={{__html: stylesStr}}
/>
);
}
const js = JS_NPM_URLS.map(url => <script key={url} src={url} />);
return (
<html lang="en">
<head>
<meta charSet="utf-8" />
<meta httpEquiv="X-UA-Compatible" content="IE=edge" />
<meta
name="viewport"
content="width=device-width, initial-scale=1.0"
/>
<link rel="icon" href="/favicon.ico" />
{this.props.headComponents}
{js}
{css}
</head>
<body>
<div
id="___gatsby"
dangerouslySetInnerHTML={{__html: this.props.body}}
/>
{this.props.postBodyComponents}
</body>
</html>
);
}
}

1
src/icons/logo.svg

@ -0,0 +1 @@
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 23 20.46348"><title>logo</title><path d="M18.9107,6.63257h0q-.36721-.126-.74042-.2333.06187-.25141.11441-.505c.56045-2.72064.194-4.91237-1.05739-5.63386-1.1998-.692-3.1621.02952-5.14394,1.75414q-.29293.2555-.57267.52554-.18727-.17951-.3811-.352C9.05257.3439,6.97066-.43316,5.72058.29046,4.52191.98436,4.16686,3.04489,4.67144,5.62322q.0753.383.17.76179c-.29458.08367-.57908.17284-.85127.26771C1.55514,7.50165,0,8.83225,0,10.21231c0,1.42546,1.66935,2.8552,4.20575,3.722q.3085.10494.62193.19442-.10179.408-.18068.82114c-.48106,2.53354-.10535,4.54521,1.09017,5.23484,1.23481.712,3.30725-.01985,5.32533-1.78387q.23926-.20917.47994-.44238.3029.29225.62173.56727c1.95477,1.68207,3.88531,2.36132,5.07982,1.66986,1.23369-.71416,1.63454-2.87525,1.114-5.50459q-.05955-.30124-.13792-.61481.21834-.06443.42772-.13355C21.28454,13.06915,23,11.65681,23,10.21232,23,8.82726,21.39478,7.48771,18.9107,6.63257ZM12.7284,2.75581C14.42646,1.278,16.01346.69457,16.73657,1.1116h0c.77014.44421,1.06971,2.2354.5858,4.58441q-.04758.22953-.10342.45724a23.53752,23.53752,0,0,0-3.07527-.48584A23.08128,23.08128,0,0,0,12.1995,3.24094Q12.45788,2.99184,12.7284,2.75581ZM6.79111,11.39124q.312.60265.65207,1.19013.34692.59911.7221,1.18117a20.92168,20.92168,0,0,1-2.11967-.3408C6.24867,12.766,6.49887,12.08443,6.79111,11.39124ZM6.79,9.08041c-.28613-.67863-.53093-1.34586-.73085-1.99019.65624-.14688,1.356-.26689,2.08516-.358q-.36611.571-.7051,1.15877Q7.10076,8.478,6.79,9.08041Zm.52228,1.15552q.45411-.94517.9783-1.8542v.0002q.52369-.90857,1.11521-1.77542c.684-.05171,1.38536-.07879,2.09432-.07879.71212,0,1.41437.02728,2.09819.0794q.58514.86487,1.10818,1.76941.52565.90635.99153,1.84545-.46083.94817-.98828,1.86173h-.0001q-.52261.90786-1.1034,1.7803c-.6824.04876-1.3876.0739-2.10623.0739-.71568,0-1.41193-.02229-2.08241-.06575q-.59555-.86995-1.12406-1.78305Q7.76789,11.18148,7.31227,10.23593Zm8.24853,2.33862q.347-.60182.667-1.21863h0a20.86671,20.86671,0,0,1,.77238,2.02327,20.85164,20.85164,0,0,1-2.14552.36573Q15.21935,13.16682,15.5608,12.57455Zm.65767-3.49343q-.31883-.605-.66163-1.19684h0q-.33727-.58258-.6994-1.15022c.7339.09263,1.437.21579,2.09717.36654A20.95909,20.95909,0,0,1,16.21847,9.08112ZM11.511,3.94359a21.01288,21.01288,0,0,1,1.3535,1.63393q-1.35843-.06419-2.7184-.00061C10.593,4.98765,11.0507,4.44022,11.511,3.94359ZM6.21284,1.14081c.76953-.44543,2.47095.18973,4.26428,1.782.11461.10179.22974.20836.34507.3186A23.54542,23.54542,0,0,0,8.86294,5.66608a24.008,24.008,0,0,0-3.06916.477q-.088-.35228-.15808-.70866v.0001C5.20339,3.22536,5.49044,1.559,6.21284,1.14081ZM5.09132,13.18233q-.286-.08187-.56778-.17773A8.32371,8.32371,0,0,1,1.841,11.57955a2.03072,2.03072,0,0,1-.85849-1.36724c0-.83742,1.24865-1.90571,3.33117-2.63178q.39208-.1361.79162-.24908a23.56455,23.56455,0,0,0,1.121,2.90478A23.92247,23.92247,0,0,0,5.09132,13.18233ZM10.41594,17.661a8.32161,8.32161,0,0,1-2.57467,1.61184h-.0001a2.03042,2.03042,0,0,1-1.61306.06067c-.72556-.41836-1.02706-2.03376-.61573-4.20035q.07337-.38407.168-.76363a23.10444,23.10444,0,0,0,3.0995.44869,23.90954,23.90954,0,0,0,1.97431,2.43929Q10.64,17.46459,10.41594,17.661Zm1.12223-1.11053c-.46569-.50253-.93015-1.05831-1.38383-1.65612q.66051.026,1.34566.02606.70326,0,1.38841-.03084A20.89425,20.89425,0,0,1,11.53817,16.55045Zm5.96651,1.367a2.03039,2.03039,0,0,1-.753,1.4278c-.72485.41958-2.275-.12581-3.94659-1.56431q-.2875-.24735-.57837-.52727a23.08914,23.08914,0,0,0,1.9279-2.448,22.93647,22.93647,0,0,0,3.11507-.48014q.07024.284.12449.55638h0A8.32,8.32,0,0,1,17.50468,17.91749Zm.83417-4.90739h-.0001c-.12571.04163-.25478.08184-.38629.12082a23.06121,23.06121,0,0,0-1.16468-2.91373,23.05112,23.05112,0,0,0,1.11938-2.87128c.23524.0682.46365.14.68372.21579,2.12842.73258,3.42665,1.81593,3.42665,2.65061C22.01753,11.10145,20.61538,12.25574,18.33885,13.0101Z" fill="#61dafb"/><path d="M11.5,8.1585a2.05386,2.05386,0,1,1-2.05381,2.05381A2.05381,2.05381,0,0,1,11.5,8.1585" fill="#61dafb"/></svg>

After

Width:  |  Height:  |  Size: 3.9 KiB

BIN
src/images/oss_logo.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

1
src/index.js

@ -0,0 +1 @@
var foo = 'bar';

85
src/layouts/index.js

@ -0,0 +1,85 @@
/**
* Copyright (c) 2013-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @emails react-core
*/
'use strict';
// Polyfills for IE
import 'array-from';
import 'string.prototype.includes';
import 'string.prototype.repeat';
import React, {Component} from 'react';
import Flex from 'components/Flex';
import Footer from 'components/LayoutFooter';
import Header from 'components/LayoutHeader';
import {media} from 'theme';
// Import global styles
import '../prism-styles';
import 'glamor/reset';
import 'css/reset.css';
import 'css/algolia.css';
class Template extends Component {
componentDidMount() {
// Initialize Algolia search.
// TODO Is this expensive? Should it be deferred until a user is about to search?
// eslint-disable-next-line no-undef
docsearch({
apiKey: '36221914cce388c46d0420343e0bb32e',
indexName: 'react',
inputSelector: '#algolia-doc-search',
});
}
render() {
const {children, location} = this.props;
// TODO - is there a better way to check if we need we have a sidebar?
let layoutHasSidebar = false;
if (
location.pathname.match(
/^\/(docs|tutorial|community|blog|contributing|warnings)/,
)
) {
layoutHasSidebar = true;
}
return (
<div
css={{
display: 'flex',
flexDirection: 'column',
minHeight: 'calc(100vh - 40px)',
}}>
<Header location={location} />
<Flex
direction="column"
shrink="0"
grow="1"
valign="stretch"
css={{
flex: '1 0 auto',
marginTop: 60,
[media.between('medium', 'large')]: {
marginTop: 50,
},
[media.lessThan('medium')]: {
marginTop: 40,
},
}}>
{children()}
</Flex>
<Footer layoutHasSidebar={layoutHasSidebar} />
</div>
);
}
}
export default Template;

34
src/pages/404.js

@ -0,0 +1,34 @@
/**
* Copyright (c) 2013-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @emails react-core
*/
'use strict';
import Container from 'components/Container';
import Header from 'components/Header';
import React from 'react';
import {sharedStyles} from 'theme';
const PageNotFound = () => (
<Container>
<div css={sharedStyles.articleLayout.container}>
<div css={sharedStyles.articleLayout.content}>
<Header>Page Not Found</Header>
<div css={sharedStyles.markdown}>
<p>We couldn't find what you were looking for.</p>
<p>
Please contact the owner of the site that linked you to the original
URL and let them know their link is broken.
</p>
</div>
</div>
</div>
</Container>
);
export default PageNotFound;

88
src/pages/acknowledgements.html.js

@ -0,0 +1,88 @@
/**
* Copyright (c) 2013-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @emails react-core
*/
'use strict';
import Container from 'components/Container';
import Header from 'components/Header';
import React from 'react';
import {sharedStyles} from 'theme';
import names from '../../content/acknowledgements.yml';
const Acknowlegements = ({data, location}) => (
<Container>
<div css={sharedStyles.articleLayout.container}>
<div css={sharedStyles.articleLayout.content}>
<Header>Acknowledgements</Header>
<div css={sharedStyles.markdown}>
<p>We'd like to thank all of our contributors:</p>
<ul
css={{
display: 'flex',
flexWrap: 'wrap',
}}>
{names.map((name, index) => (
<li
css={{
flex: '1 0 200px',
}}
key={index}>
{name}
</li>
))}
</ul>
<p>In addition, we're grateful to</p>
<ul>
<li>
<a href="https://github.com/jeffbski">Jeff Barczewski</a> for
allowing us to use the{' '}
<a href="https://www.npmjs.com/package/react">react</a> package
name on npm.
</li>
<li>
<a href="http://christopheraue.net/">Christopher Aue</a> for
letting us use the <a href="http://reactjs.com/">
reactjs.com
</a>{' '}
domain name and the{' '}
<a href="https://twitter.com/reactjs">@reactjs</a> username on
Twitter.
</li>
<li>
<a href="https://github.com/ProjectMoon">ProjectMoon</a> for
letting us use the{' '}
<a href="https://www.npmjs.com/package/flux">flux</a> package name
on npm.
</li>
<li>
Shane Anderson for allowing us to use the{' '}
<a href="https://github.com/react">react</a> org on GitHub.
</li>
<li>
<a href="https://github.com/voronianski">
Dmitri Voronianski
</a>{' '}
for letting us use the{' '}
<a href="https://labs.voronianski.com/oceanic-next-color-scheme/">
Oceanic Next
</a>{' '}
color scheme on this website.
</li>
</ul>
</div>
</div>
</div>
</Container>
);
export default Acknowlegements;

117
src/pages/blog/all.html.js

@ -0,0 +1,117 @@
/**
* Copyright (c) 2013-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @emails react-core
*/
'use strict';
import Link from 'gatsby-link';
import Container from 'components/Container';
import Header from 'components/Header';
import React from 'react';
import {colors, media, sharedStyles} from 'theme';
import toCommaSeparatedList from 'utils/toCommaSeparatedList';
import MetaTitle from 'templates/components/MetaTitle';
const AllBlogPosts = ({data}) => (
<Container>
<div css={sharedStyles.articleLayout.container}>
<div css={sharedStyles.articleLayout.content}>
<Header>All Posts</Header>
<ul
css={{
display: 'flex',
flexWrap: 'wrap',
marginLeft: -40,
}}>
{data.allMarkdownRemark.edges.map(({node}) => (
<li
css={{
paddingLeft: 40,
paddingTop: 40,
borderTop: '1px dotted #ececec',
paddingBottom: 40,
width: '100%',
[media.size('medium')]: {
width: '50%',
},
[media.greaterThan('large')]: {
width: '33.33%',
},
}}
key={node.fields.slug}>
<h2
css={{
fontSize: 24,
color: colors.dark,
lineHeight: 1.3,
fontWeight: 700,
}}>
<Link
css={{
borderBottom: '1px solid #ececec',
':hover': {
borderBottomColor: colors.black,
},
}}
key={node.fields.slug}
to={node.fields.slug}>
{node.frontmatter.title}
</Link>
</h2>
<MetaTitle>{node.fields.date}</MetaTitle>
<div
css={{
color: colors.subtle,
marginTop: -5,
}}>
by{' '}
{toCommaSeparatedList(node.frontmatter.author, author => (
<span key={author.frontmatter.name}>
{author.frontmatter.name}
</span>
))}
</div>
</li>
))}
</ul>
</div>
</div>
</Container>
);
// eslint-disable-next-line no-undef
export const pageQuery = graphql`
query AllBlogPostsPageQuery {
allMarkdownRemark(
filter: {id: {regex: "/blog/"}}
sort: {fields: [fields___date], order: DESC}
) {
edges {
node {
frontmatter {
title
author {
frontmatter {
name
url
}
}
}
fields {
date(formatString: "MMMM DD, YYYY")
slug
}
}
}
}
}
`;
export default AllBlogPosts;

116
src/pages/docs/error-decoder.html.js

@ -0,0 +1,116 @@
/**
* Copyright (c) 2013-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @emails react-core
*/
'use strict';
import Container from 'components/Container';
import ErrorDecoder from 'components/ErrorDecoder';
import Flex from 'components/Flex';
import hex2rgba from 'hex2rgba';
import MarkdownHeader from 'components/MarkdownHeader';
import React from 'react';
import StickyResponsiveSidebar from 'components/StickyResponsiveSidebar';
import {colors, sharedStyles} from 'theme';
import {createLinkDocs} from 'utils/createLink';
import findSectionForPath from 'utils/findSectionForPath';
import {sectionListDocs} from 'utils/sectionList';
const ErrorPage = ({data, location}) => (
<Flex
direction="column"
grow="1"
shrink="0"
halign="stretch"
css={{
width: '100%',
flex: '1 0 auto',
position: 'relative',
zIndex: 0,
}}>
<Container>
<div css={sharedStyles.articleLayout.container}>
<Flex
type="article"
direction="column"
grow="1"
halign="stretch"
css={{
minHeight: 'calc(100vh - 40px)',
}}>
<MarkdownHeader
path={data.markdownRemark.fields.path}
title={data.markdownRemark.frontmatter.title}
/>
<div css={sharedStyles.articleLayout.content}>
<div
css={sharedStyles.markdown}
dangerouslySetInnerHTML={{__html: data.markdownRemark.html}}
/>
<div
css={[
sharedStyles.markdown,
{
marginTop: 30,
'& code': {
display: 'block',
marginTop: 30,
padding: '1rem',
borderRadius: '0.5rem',
backgroundColor: hex2rgba(colors.error, 0.1),
color: colors.error,
},
},
]}>
<ErrorDecoder
errorCodesString={data.errorCodesJson.internal.contentDigest}
location={location}
/>
</div>
</div>
</Flex>
<div css={sharedStyles.articleLayout.sidebar}>
<StickyResponsiveSidebar
createLink={createLinkDocs}
defaultActiveSection={findSectionForPath(
location.pathname,
sectionListDocs,
)}
location={location}
sectionList={sectionListDocs}
title={data.markdownRemark.frontmatter.title}
/>
</div>
</div>
</Container>
</Flex>
);
// eslint-disable-next-line no-undef
export const pageQuery = graphql`
query ErrorPageMarkdown($slug: String!) {
markdownRemark(fields: {slug: {eq: $slug}}) {
html
fields {
path
}
frontmatter {
title
}
}
errorCodesJson {
internal {
contentDigest
}
}
}
`;
export default ErrorPage;

BIN
src/pages/favicon.ico

Binary file not shown.

After

Width:  |  Height:  |  Size: 198 B

38
src/pages/jsx-compiler.html.js

@ -0,0 +1,38 @@
/**
* Copyright (c) 2013-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @emails react-core
*/
'use strict';
import Container from 'components/Container';
import Header from 'components/Header';
import React from 'react';
import {sharedStyles} from 'theme';
const JsxCompiler = () => (
<Container>
<div css={sharedStyles.articleLayout.container}>
<div css={sharedStyles.articleLayout.content}>
<Header>JSX Compiler Service</Header>
<div css={sharedStyles.markdown}>
<p>
<strong>
This tool has been removed as JSXTransformer has been deprecated.
</strong>
</p>
<p>
We recommend using another tool such as{' '}
<a href="https://babeljs.io/repl/">the Babel REPL</a>.
</p>
</div>
</div>
</div>
</Container>
);
export default JsxCompiler;

2
src/pages/robots.txt

@ -0,0 +1,2 @@
User-agent: *
Disallow:

171
src/prism-styles.js

@ -0,0 +1,171 @@
/**
* Copyright (c) 2013-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @emails react-core
*/
'use strict';
import {css} from 'glamor';
import {colors} from 'theme';
const prismColors = {
char: '#D8DEE9',
comment: '#999999',
keyword: '#c5a5c5',
lineHighlight: '#14161a',
primitive: '#5a9bcf',
string: '#8dc891',
variable: '#d7deea',
boolean: '#ff8b50',
punctuation: '#5FB3B3',
tag: '#fc929e',
function: '#79b6f2',
className: '#FAC863',
method: '#6699CC',
operator: '#fc929e',
};
css.global('.gatsby-highlight', {
background: colors.dark,
color: colors.white,
borderRadius: 10,
overflow: 'auto',
tabSize: '1.5em',
});
css.global(
`
.gatsby-highlight code[class*="gatsby-code-"],
.gatsby-highlight pre[class*="gatsby-code-"],
.gatsby-highlight pre.prism-code`,
{
height: 'auto !important',
margin: '1rem',
fontSize: 14,
lineHeight: '20px',
whiteSpace: 'pre-wrap',
wordBreak: 'break-word',
},
);
css.global('.gatsby-highlight + .gatsby-highlight', {
marginTop: 20,
});
css.global('.gatsby-highlight-code-line', {
backgroundColor: prismColors.lineHighlight,
display: 'block',
margin: '-0.125rem calc(-1rem - 15px)',
padding: '0.125rem calc(1rem + 15px)',
});
css.global('.token.attr-name', {
color: prismColors.keyword,
});
css.global(
`
.token.comment,
.token.block-comment,
.token.prolog,
.token.doctype,
.token.cdata`,
{
color: prismColors.comment,
},
);
css.global(
`
.token.property,
.token.number,
.token.function-name,
.token.constant,
.token.symbol,
.token.deleted`,
{
color: prismColors.primitive,
},
);
css.global(`.token.boolean`, {
color: prismColors.boolean,
});
css.global(`.token.tag`, {
color: prismColors.tag,
});
css.global(`.token.string`, {
color: prismColors.string,
});
css.global(`.token.punctuation`, {
color: prismColors.punctuation,
});
css.global(
`
.token.selector,
.token.char,
.token.builtin,
.token.inserted`,
{
color: prismColors.char,
},
);
css.global(`.token.function`, {
color: prismColors.function,
});
css.global(
`
.token.operator,
.token.entity,
.token.url,
.token.variable`,
{
color: prismColors.variable,
},
);
css.global('.token.attr-value', {
color: prismColors.string,
});
css.global('.token.keyword', {
color: prismColors.keyword,
});
css.global(
`
.token.atrule,
.token.class-name`,
{
color: prismColors.className,
},
);
css.global('.token.important', {
fontWeight: 400,
});
css.global('.token.bold', {
fontWeight: 700,
});
css.global('.token.italic', {
fontStyle: 'italic',
});
css.global('.token.entity', {
cursor: 'help',
});
css.global('.namespace', {
opacity: 0.7,
});

22
src/site-constants.js

@ -0,0 +1,22 @@
/**
* Copyright (c) 2013-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @emails react-core
* @flow
*/
'use strict';
/**
* Variables shared by multiple components.
*/
export default {
// NOTE: We can't just use `location.toString()` because when we are rendering
// the SSR part in node.js we won't have a proper location.
urlRoot: 'https://reactjs.org',
version: '16.0.0',
};

91
src/templates/blog.js

@ -0,0 +1,91 @@
/**
* Copyright (c) 2013-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @emails react-core
*/
'use strict';
import PropTypes from 'prop-types';
import React from 'react';
import MarkdownPage from 'components/MarkdownPage';
import {createLinkBlog} from 'utils/createLink';
const toSectionList = allMarkdownRemark => [
{
title: 'Recent Posts',
items: allMarkdownRemark.edges
.map(({node}) => ({
id: node.fields.slug,
title: node.frontmatter.title,
}))
.concat({
id: '/blog/all.html',
title: 'All posts ...',
}),
},
];
const Blog = ({data, location}) => (
<MarkdownPage
authors={data.markdownRemark.frontmatter.author}
createLink={createLinkBlog}
date={data.markdownRemark.fields.date}
location={location}
ogDescription={data.markdownRemark.excerpt}
markdownRemark={data.markdownRemark}
sectionList={toSectionList(data.allMarkdownRemark)}
titlePostfix=" - React Blog"
/>
);
Blog.propTypes = {
data: PropTypes.object.isRequired,
};
// eslint-disable-next-line no-undef
export const pageQuery = graphql`
query TemplateBlogMarkdown($slug: String!) {
markdownRemark(fields: {slug: {eq: $slug}}) {
html
excerpt(pruneLength: 500)
frontmatter {
title
next
prev
author {
frontmatter {
name
url
}
}
}
fields {
date(formatString: "MMMM DD, YYYY")
path
slug
}
}
allMarkdownRemark(
limit: 10
filter: {id: {regex: "/blog/"}}
sort: {fields: [fields___date], order: DESC}
) {
edges {
node {
frontmatter {
title
}
fields {
slug
}
}
}
}
}
`;
export default Blog;

50
src/templates/community.js

@ -0,0 +1,50 @@
/**
* Copyright (c) 2013-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @emails react-core
*/
'use strict';
import MarkdownPage from 'components/MarkdownPage';
import PropTypes from 'prop-types';
import React from 'react';
import {createLinkCommunity} from 'utils/createLink';
import {sectionListCommunity} from 'utils/sectionList';
const Community = ({data, location}) => (
<MarkdownPage
createLink={createLinkCommunity}
location={location}
markdownRemark={data.markdownRemark}
sectionList={sectionListCommunity}
titlePostfix=" - React"
/>
);
Community.propTypes = {
data: PropTypes.object.isRequired,
};
// eslint-disable-next-line no-undef
export const pageQuery = graphql`
query TemplateCommunityMarkdown($slug: String!) {
markdownRemark(fields: {slug: {eq: $slug}}) {
html
frontmatter {
title
next
prev
}
fields {
path
slug
}
}
}
`;
export default Community;

87
src/templates/components/ButtonLink/ButtonLink.js

@ -0,0 +1,87 @@
/**
* Copyright (c) 2013-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @emails react-core
*/
'use strict';
import Link from 'gatsby-link';
import React from 'react';
import {colors, media} from 'theme';
const ArrowSvg = ({cssProps = {}}) => (
<svg
css={cssProps}
height="12"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 4.53657 8.69699">
<path
d={`
M.18254,8.697a.18149.18149,0,0,1-.12886-.31034L4.09723,4.34126.05369.29954a.18149.18149,
0,0,1,.2559-.2559L4.4838,4.21785a.18149.18149,0,0,1,0,.2559L.30958,8.648A.18149.18149,
0,0,1,.18254,8.697Z
`}
fill="currentColor"
/>
</svg>
);
const ButtonLink = ({children, type, ...rest}) => {
let typeStyle;
switch (type) {
case 'primary':
typeStyle = primaryStyle;
break;
case 'secondary':
typeStyle = secondaryStyle;
break;
}
return (
<Link {...rest} css={[style, typeStyle]}>
{children}
{type === 'secondary' && <ArrowSvg cssProps={{marginLeft: 10}} />}
</Link>
);
};
const style = {
display: 'inline-block',
fontSize: 16,
[media.greaterThan('xlarge')]: {
fontSize: 20,
},
};
const primaryStyle = {
backgroundColor: colors.brand,
color: colors.black,
padding: '10px 25px',
whiteSpace: 'nowrap',
transition: 'background-color 0.2s ease-out',
[media.greaterThan('xlarge')]: {
paddingTop: 15,
paddingBottom: 15,
},
':hover': {
backgroundColor: colors.white,
},
};
const secondaryStyle = {
color: colors.brand,
transition: 'color 0.2s ease-out',
':hover': {
color: colors.white,
},
};
export default ButtonLink;

14
src/templates/components/ButtonLink/index.js

@ -0,0 +1,14 @@
/**
* Copyright (c) 2013-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @emails react-core
*/
'use strict';
import ButtonLink from './ButtonLink';
export default ButtonLink;

41
src/templates/components/ChevronSvg/index.js

@ -0,0 +1,41 @@
/**
* Copyright (c) 2013-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @emails react-core
*/
'use strict';
import React from 'react';
const ChevronSvg = ({size = 10, cssProps = {}}) => (
<svg
css={cssProps}
viewBox="0 0 926.23699 573.74994"
version="1.1"
x="0px"
y="0px"
width={size}
height={size}>
<g transform="translate(904.92214,-879.1482)">
<path
d={`
m -673.67664,1221.6502 -231.2455,-231.24803 55.6165,
-55.627 c 30.5891,-30.59485 56.1806,-55.627 56.8701,-55.627 0.6894,
0 79.8637,78.60862 175.9427,174.68583 l 174.6892,174.6858 174.6892,
-174.6858 c 96.079,-96.07721 175.253196,-174.68583 175.942696,
-174.68583 0.6895,0 26.281,25.03215 56.8701,
55.627 l 55.6165,55.627 -231.245496,231.24803 c -127.185,127.1864
-231.5279,231.248 -231.873,231.248 -0.3451,0 -104.688,
-104.0616 -231.873,-231.248 z
`}
fill="currentColor"
/>
</g>
</svg>
);
export default ChevronSvg;

39
src/templates/components/ExternalLinkSvg/index.js

@ -0,0 +1,39 @@
/**
* Copyright (c) 2013-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @emails react-core
*/
'use strict';
import React from 'react';
const ExternalLinkSvg = ({cssProps = {}}) => (
<svg
x="0px"
y="0px"
viewBox="0 0 100 100"
width={15}
height={15}
css={cssProps}>
<path
fill="currentColor"
d={`
M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,
0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z
`}
/>
<polygon
fill="currentColor"
points={`
45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,
14.9 62.8,22.9 71.5,22.9
`}
/>
</svg>
);
export default ExternalLinkSvg;

38
src/templates/components/MetaTitle/index.js

@ -0,0 +1,38 @@
/**
* Copyright (c) 2013-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @emails react-core
*/
'use strict';
import React from 'react';
import {colors} from 'theme';
const MetaTitle = ({
children,
title,
cssProps = {},
onClick,
onDark = false,
}) => (
<div
onClick={onClick}
css={{
color: onDark ? colors.subtleOnDark : colors.subtle,
cursor: onClick ? 'pointer' : null,
fontSize: 14,
fontWeight: 700,
lineHeight: 3,
textTransform: 'uppercase',
letterSpacing: '0.08em',
...cssProps,
}}>
{children}
</div>
);
export default MetaTitle;

136
src/templates/components/NavigationFooter/NavigationFooter.js

@ -0,0 +1,136 @@
/**
* Copyright (c) 2013-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @emails react-core
*/
'use strict';
import Container from 'components/Container';
import Flex from 'components/Flex';
import Link from 'gatsby-link';
import PropTypes from 'prop-types';
import React from 'react';
import {colors, fonts, media} from 'theme';
const NavigationFooter = ({next, prev, location}) => {
return (
<div
css={{
background: colors.dark,
color: colors.white,
paddingTop: 50,
paddingBottom: 50,
}}>
<Container>
<Flex
type="ul"
halign="space-between"
css={{
[media.between('small', 'medium')]: {
paddingRight: 240,
},
[media.between('large', 'largerSidebar')]: {
paddingRight: 280,
},
[media.between('largerSidebar', 'sidebarFixed', true)]: {
paddingRight: 380,
},
}}>
<Flex basis="50%" type="li">
{prev && (
<div>
<SecondaryLabel>Previous article</SecondaryLabel>
<div
css={{
paddingTop: 10,
}}>
<PrimaryLink location={location} to={prev}>
{linkToTitle(prev)}
</PrimaryLink>
</div>
</div>
)}
</Flex>
{next && (
<Flex
halign="flex-end"
basis="50%"
type="li"
css={{
textAlign: 'right',
}}>
<div>
<SecondaryLabel>Next article</SecondaryLabel>
<div
css={{
paddingTop: 10,
}}>
<PrimaryLink location={location} to={next}>
{linkToTitle(next)}
</PrimaryLink>
</div>
</div>
</Flex>
)}
</Flex>
</Container>
</div>
);
};
NavigationFooter.propTypes = {
next: PropTypes.string,
prev: PropTypes.string,
};
export default NavigationFooter;
const linkToTitle = link => link.replace(/-/g, ' ').replace('.html', '');
const PrimaryLink = ({children, to, location}) => {
// quick fix
// TODO: replace this with better method of getting correct full url
const updatedUrl =
(location && location.pathname.replace(/\/[^/]+\.html/, '/' + to)) || to;
return (
<Link
css={{
display: 'inline',
textTransform: 'capitalize',
borderColor: colors.subtle,
transition: 'border-color 0.2s ease',
fontSize: 30,
borderBottomWidth: 1,
borderBottomStyle: 'solid',
[media.lessThan('large')]: {
fontSize: 24,
},
[media.size('xsmall')]: {
fontSize: 16,
},
':hover': {
borderColor: colors.white,
},
}}
to={updatedUrl}>
{children}
</Link>
);
};
const SecondaryLabel = ({children}) => (
<div
css={{
color: colors.brand,
...fonts.small,
}}>
{children}
</div>
);

14
src/templates/components/NavigationFooter/index.js

@ -0,0 +1,14 @@
/**
* Copyright (c) 2013-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @emails react-core
*/
'use strict';
import NavigationFooter from './NavigationFooter';
export default NavigationFooter;

96
src/templates/components/Sidebar/Section.js

@ -0,0 +1,96 @@
/**
* Copyright (c) 2013-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @emails react-core
*/
'use strict';
import React from 'react';
import {colors, media} from 'theme';
import MetaTitle from '../MetaTitle';
import ChevronSvg from '../ChevronSvg';
// TODO Update isActive link as document scrolls past anchor tags
// Maybe used 'hashchange' along with 'scroll' to set/update active links
const Section = ({
createLink,
isActive,
location,
onLinkClick,
onSectionTitleClick,
section,
}) => (
<div>
<MetaTitle
onClick={onSectionTitleClick}
cssProps={{
marginTop: 10,
[media.greaterThan('small')]: {
color: isActive ? colors.text : colors.subtle,
':hover': {
color: colors.text,
},
},
}}>
{section.title}
<ChevronSvg
cssProps={{
marginLeft: 7,
transform: isActive ? 'rotateX(180deg)' : 'rotateX(0deg)',
transition: 'transform 0.2s ease',
[media.lessThan('small')]: {
display: 'none',
},
}}
/>
</MetaTitle>
<ul
css={{
marginBottom: 10,
[media.greaterThan('small')]: {
display: isActive ? 'block' : 'none',
},
}}>
{section.items.map(item => (
<li
key={item.id}
css={{
marginTop: 5,
}}>
{createLink({
item,
location,
onLinkClick,
section,
})}
{item.subitems && (
<ul css={{marginLeft: 20}}>
{item.subitems.map(subitem => (
<li key={subitem.id}>
{createLink({
item: subitem,
location,
onLinkClick,
section,
})}
</li>
))}
</ul>
)}
</li>
))}
</ul>
</div>
);
export default Section;

70
src/templates/components/Sidebar/Sidebar.js

@ -0,0 +1,70 @@
/**
* Copyright (c) 2013-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @emails react-core
*/
'use strict';
import React, {Component} from 'react';
import Flex from 'components/Flex';
import Section from './Section';
import {media} from 'theme';
class Sidebar extends Component {
constructor(props, context) {
super(props, context);
this.state = {
activeSection: props.defaultActiveSection,
};
}
render() {
const {closeParentMenu, createLink, location, sectionList} = this.props;
const {activeSection} = this.state;
return (
<Flex
type="nav"
direction="column"
halign="stretch"
css={{
width: '100%',
paddingLeft: 20,
position: 'relative',
[media.greaterThan('largerSidebar')]: {
paddingLeft: 40,
},
[media.lessThan('small')]: {
paddingBottom: 100,
},
}}>
{sectionList.map((section, index) => (
<Section
createLink={createLink}
isActive={activeSection === section || sectionList.length === 1}
key={index}
location={location}
onLinkClick={closeParentMenu}
onSectionTitleClick={() => this._toggleSection(section)}
section={section}
/>
))}
</Flex>
);
}
_toggleSection(section) {
this.setState(state => ({
activeSection: state.activeSection === section ? null : section,
}));
}
}
export default Sidebar;

14
src/templates/components/Sidebar/index.js

@ -0,0 +1,14 @@
/**
* Copyright (c) 2013-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @emails react-core
*/
'use strict';
import Sidebar from './Sidebar';
export default Sidebar;

50
src/templates/docs.js

@ -0,0 +1,50 @@
/**
* Copyright (c) 2013-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @emails react-core
*/
'use strict';
import MarkdownPage from 'components/MarkdownPage';
import PropTypes from 'prop-types';
import React from 'react';
import {createLinkDocs} from 'utils/createLink';
import {sectionListDocs} from 'utils/sectionList';
const Docs = ({data, location}) => (
<MarkdownPage
createLink={createLinkDocs}
location={location}
markdownRemark={data.markdownRemark}
sectionList={sectionListDocs}
titlePostfix=" - React"
/>
);
Docs.propTypes = {
data: PropTypes.object.isRequired,
};
// eslint-disable-next-line no-undef
export const pageQuery = graphql`
query TemplateDocsMarkdown($slug: String!) {
markdownRemark(fields: {slug: {eq: $slug}}) {
html
frontmatter {
title
next
prev
}
fields {
path
slug
}
}
}
`;
export default Docs;

470
src/templates/home.js

@ -0,0 +1,470 @@
/**
* Copyright (c) 2013-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @emails react-core
*/
'use strict';
import ButtonLink from './components/ButtonLink';
import Container from 'components/Container';
import Flex from 'components/Flex';
import mountCodeExample from 'utils/mountCodeExample';
import PropTypes from 'prop-types';
import React, {Component} from 'react';
import TitleAndMetaTags from 'components/TitleAndMetaTags';
import {colors, media, sharedStyles} from 'theme';
import createOgUrl from 'utils/createOgUrl';
class Home extends Component {
componentDidMount() {
mountCodeExample('helloExample', HELLO_COMPONENT);
mountCodeExample('timerExample', TIMER_COMPONENT);
mountCodeExample('todoExample', TODO_COMPONENT);
mountCodeExample('markdownExample', MARKDOWN_COMPONENT);
}
render() {
const {data} = this.props;
const title = 'React - A JavaScript library for building user interfaces';
return (
<div css={{width: '100%'}}>
<TitleAndMetaTags
title={title}
ogUrl={createOgUrl(data.markdownRemark.fields.slug)}
/>
<header
css={{
backgroundColor: colors.dark,
color: colors.white,
}}>
<div
css={{
paddingTop: 45,
paddingBottom: 20,
[media.greaterThan('small')]: {
paddingTop: 60,
paddingBottom: 70,
},
[media.greaterThan('xlarge')]: {
paddingTop: 95,
paddingBottom: 85,
maxWidth: 1500, // Positioning of background logo
marginLeft: 'auto',
marginRight: 'auto',
backgroundImage: 'url(/large-logo.svg)',
backgroundRepeat: 'no-repeat',
backgroundPosition: '100% 100px',
backgroundSize: '50% auto',
},
}}>
<Container>
<h1
css={{
color: colors.brand,
textAlign: 'center',
margin: 0,
fontSize: 45,
letterSpacing: '0.01em',
[media.size('xsmall')]: {
fontSize: 30,
},
[media.greaterThan('xlarge')]: {
fontSize: 60,
},
}}>
React
</h1>
<p
css={{
paddingTop: 15,
textAlign: 'center',
fontSize: 24,
letterSpacing: '0.01em',
fontWeight: 200,
[media.size('xsmall')]: {
fontSize: 16,
maxWidth: '12em',
marginLeft: 'auto',
marginRight: 'auto',
},
[media.greaterThan('xlarge')]: {
paddingTop: 20,
fontSize: 30,
},
}}>
A JavaScript library for building user interfaces
</p>
<Flex
valign="center"
css={{
paddingTop: 40,
[media.greaterThan('xlarge')]: {
paddingTop: 65,
},
}}>
<CtaItem>
<ButtonLink to="/docs/hello-world.html" type="primary">
Get Started
</ButtonLink>
</CtaItem>
<CtaItem>
<ButtonLink to="/tutorial/tutorial.html" type="secondary">
Take the Tutorial
</ButtonLink>
</CtaItem>
</Flex>
</Container>
</div>
</header>
<Container>
<div
css={[sharedStyles.markdown, markdownStyles]}
dangerouslySetInnerHTML={{__html: data.markdownRemark.html}}
/>
</Container>
<section
css={{
background: colors.dark,
color: colors.white,
paddingTop: 45,
paddingBottom: 45,
}}>
<Container>
<Flex valign="center">
<CtaItem>
<ButtonLink to="/docs/hello-world.html" type="primary">
Get Started
</ButtonLink>
</CtaItem>
<CtaItem>
<ButtonLink to="/tutorial/tutorial.html" type="secondary">
Take the Tutorial
</ButtonLink>
</CtaItem>
</Flex>
</Container>
</section>
</div>
);
}
}
Home.propTypes = {
data: PropTypes.object.isRequired,
location: PropTypes.object.isRequired,
};
const CtaItem = ({children, primary = false}) => (
<div
css={{
width: '50%',
[media.between('small', 'large')]: {
paddingLeft: 20,
},
[media.greaterThan('xlarge')]: {
paddingLeft: 40,
},
'&:first-child': {
textAlign: 'right',
paddingRight: 15,
},
'&:nth-child(2)': {
[media.greaterThan('small')]: {
paddingLeft: 15,
},
},
}}>
{children}
</div>
);
// eslint-disable-next-line no-undef
export const pageQuery = graphql`
query HomeMarkdown($slug: String!) {
markdownRemark(fields: {slug: {eq: $slug}}) {
html
frontmatter {
title
}
fields {
slug
}
}
}
`;
export default Home;
// TODO This nasty CSS is required because 'docs/index.md' defines hard-coded class names.
const markdownStyles = {
'& .home-section': {
marginTop: 20,
marginBottom: 15,
[media.greaterThan('medium')]: {
marginTop: 60,
marginBottom: 65,
},
},
'& .home-section:first-child': {
[media.lessThan('medium')]: {
marginTop: 0,
marginBottom: 0,
overflowX: 'auto',
paddingTop: 30,
WebkitOverflowScrolling: 'touch',
position: 'relative',
maskImage:
'linear-gradient(to right, transparent, white 10px, white 90%, transparent)',
},
},
'& .homeDivider': {
height: 1,
marginBottom: -1,
border: 'none',
borderBottom: `1 solid ${colors.divider}`,
},
'& .marketing-row': {
display: 'flex',
flexDirection: 'row',
[media.lessThan('medium')]: {
display: 'block',
whiteSpace: 'nowrap',
},
},
'& .marketing-col': {
display: 'flex',
flexDirection: 'column',
flex: '0 1 33%',
marginLeft: 40,
'&:first-of-type': {
marginLeft: 0,
[media.lessThan('medium')]: {
marginLeft: 10,
},
},
[media.lessThan('medium')]: {
display: 'inline-block',
verticalAlign: 'top',
marginLeft: 0,
whiteSpace: 'normal',
width: '75%',
marginRight: 20,
paddingBottom: 40,
'&:first-of-type': {
marginTop: 0,
},
},
'& h3': {
color: colors.subtle,
paddingTop: 0,
fontWeight: 300,
fontSize: 20,
[media.greaterThan('xlarge')]: {
fontSize: 24,
fontWeight: 200,
},
},
'& p': {
lineHeight: 1.7,
},
'& h3 + p': {
marginTop: 20,
},
},
'& .example': {
marginTop: 40,
'&:first-child': {
marginTop: 0,
},
[media.greaterThan('xlarge')]: {
marginTop: 80,
},
},
};
// TODO Move these hard-coded examples into example files and out of the template?
// Alternately, move them into the markdown and transform them during build?
// This could be done via a new Gatsby transform plug-in that auto-converts to runnable REPLs?
const name = Math.random() > 0.5 ? 'John' : 'Jane';
const HELLO_COMPONENT = `
class HelloMessage extends React.Component {
render() {
return (
<div>
Hello {this.props.name}
</div>
);
}
}
ReactDOM.render(
<HelloMessage name="${name}" />,
mountNode
);
`.trim();
const TIMER_COMPONENT = `
class Timer extends React.Component {
constructor(props) {
super(props);
this.state = { seconds: 0 };
}
tick() {
this.setState((prevState) => ({
seconds: prevState.seconds + 1
}));
}
componentDidMount() {
this.interval = setInterval(() => this.tick(), 1000);
}
componentWillUnmount() {
clearInterval(this.interval);
}
render() {
return (
<div>
Seconds: {this.state.seconds}
</div>
);
}
}
ReactDOM.render(<Timer />, mountNode);
`.trim();
var TODO_COMPONENT = `
class TodoApp extends React.Component {
constructor(props) {
super(props);
this.state = { items: [], text: '' };
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
render() {
return (
<div>
<h3>TODO</h3>
<TodoList items={this.state.items} />
<form onSubmit={this.handleSubmit}>
<input
onChange={this.handleChange}
value={this.state.text}
/>
<button>
Add #{this.state.items.length + 1}
</button>
</form>
</div>
);
}
handleChange(e) {
this.setState({ text: e.target.value });
}
handleSubmit(e) {
e.preventDefault();
if (!this.state.text.length) {
return;
}
const newItem = {
text: this.state.text,
id: Date.now()
};
this.setState((prevState) => ({
items: prevState.items.concat(newItem),
text: ''
}));
}
}
class TodoList extends React.Component {
render() {
return (
<ul>
{this.props.items.map(item => (
<li key={item.id}>{item.text}</li>
))}
</ul>
);
}
}
ReactDOM.render(<TodoApp />, mountNode);
`.trim();
var MARKDOWN_COMPONENT = `
class MarkdownEditor extends React.Component {
constructor(props) {
super(props);
this.handleChange = this.handleChange.bind(this);
this.state = { value: 'Type some *markdown* here!' };
}
handleChange(e) {
this.setState({ value: e.target.value });
}
getRawMarkup() {
const md = new Remarkable();
return { __html: md.render(this.state.value) };
}
render() {
return (
<div className="MarkdownEditor">
<h3>Input</h3>
<textarea
onChange={this.handleChange}
defaultValue={this.state.value}
/>
<h3>Output</h3>
<div
className="content"
dangerouslySetInnerHTML={this.getRawMarkup()}
/>
</div>
);
}
}
ReactDOM.render(<MarkdownEditor />, mountNode);
`.trim();

61
src/templates/tutorial.js

@ -0,0 +1,61 @@
/**
* Copyright (c) 2013-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @emails react-core
*/
'use strict';
import MarkdownPage from 'components/MarkdownPage';
import PropTypes from 'prop-types';
import React from 'react';
import {createLinkTutorial} from 'utils/createLink';
import {sectionListTutorial} from 'utils/sectionList';
const Tutorial = ({data, location}) => {
// HACK The injected location prop doesn't update when hash changes
// This might be a gatsby issue, or a react-router/history issue,
// Or we might be using either library incorrectly.
// For now this patch keeps the hash in sync by JIT copying it from window.
// The undefined check prevents us from breaking on production build.
if (typeof window !== 'undefined' && typeof window.location !== 'undefined') {
location.hash = window.location.hash;
}
return (
<MarkdownPage
createLink={createLinkTutorial}
location={location}
markdownRemark={data.markdownRemark}
sectionList={sectionListTutorial}
titlePostfix=" - React"
/>
);
};
Tutorial.propTypes = {
data: PropTypes.object.isRequired,
};
// eslint-disable-next-line no-undef
export const pageQuery = graphql`
query TemplateTutorialMarkdown($slug: String!) {
markdownRemark(fields: {slug: {eq: $slug}}) {
html
frontmatter {
title
next
prev
}
fields {
path
slug
}
}
}
`;
export default Tutorial;

407
src/theme.js

@ -0,0 +1,407 @@
/**
* Copyright (c) 2013-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @emails react-core
* @flow
*/
'use strict';
/**
* Theme contains variables shared by styles of multiple components.
*/
import hex2rgba from 'hex2rgba';
const colors = {
lighter: '#373940', // light blue
dark: '#282c34', // dark blue
darker: '#20232a', // really dark blue
brand: '#61dafb', // electric blue
brandLight: '#bbeffd',
text: '#1a1a1a', // very dark grey / black substitute
subtle: '#6d6d6d', // light grey for text
subtleOnDark: '#999',
divider: '#ececec', // very light grey
note: '#ffe564', // yellow
error: '#ff6464', // yellow
white: '#ffffff',
black: '#000000',
};
const SIZES = {
xsmall: {min: 0, max: 599},
small: {min: 600, max: 779},
medium: {min: 780, max: 979},
large: {min: 980, max: 1279},
xlarge: {min: 1280, max: 1339},
xxlarge: {min: 1340, max: Infinity},
// Sidebar/nav related tweakpoints
largerSidebar: {min: 1100, max: 1339},
sidebarFixed: {min: 2000, max: Infinity},
};
type Size = $Keys<typeof SIZES>;
const media = {
between(smallKey: Size, largeKey: Size, excludeLarge: boolean = false) {
if (excludeLarge) {
return `@media (min-width: ${SIZES[smallKey]
.min}px) and (max-width: ${SIZES[largeKey].min - 1}px)`;
} else {
if (SIZES[largeKey].max === Infinity) {
return `@media (min-width: ${SIZES[smallKey].min}px)`;
} else {
return `@media (min-width: ${SIZES[smallKey]
.min}px) and (max-width: ${SIZES[largeKey].max}px)`;
}
}
},
greaterThan(key: Size) {
return `@media (min-width: ${SIZES[key].min}px)`;
},
lessThan(key: Size) {
return `@media (max-width: ${SIZES[key].min - 1}px)`;
},
size(key: Size) {
const size = SIZES[key];
if (size.min == null) {
return media.lessThan(key);
} else if (size.max == null) {
return media.greaterThan(key);
} else {
return media.between(key, key);
}
},
};
const fonts = {
header: {
fontSize: 60,
lineHeight: '65px',
fontWeight: 700,
[media.lessThan('medium')]: {
fontSize: 40,
lineHeight: '45px',
},
},
small: {
fontSize: 14,
},
};
// Shared styles are generally better as components,
// Except when they must be used within nested CSS selectors.
// This is the case for eg markdown content.
const linkStyle = {
backgroundColor: hex2rgba(colors.brandLight, 0.5),
borderBottom: `1px solid ${hex2rgba(colors.black, 0.2)}`,
color: colors.text,
':hover': {
backgroundColor: colors.brandLight,
borderBottomColor: colors.text,
},
};
const sharedStyles = {
link: linkStyle,
articleLayout: {
container: {
display: 'flex',
minHeight: 'calc(100vh - 60px)',
[media.greaterThan('sidebarFixed')]: {
maxWidth: 840,
marginLeft: 'auto',
marginRight: 'auto',
},
},
content: {
marginTop: 40,
marginBottom: 120,
[media.greaterThan('medium')]: {
marginTop: 50,
},
},
sidebar: {
display: 'flex',
flexDirection: 'column',
[media.between('small', 'sidebarFixed')]: {
borderLeft: '1px solid #ececec',
marginLeft: 80,
},
[media.between('small', 'largerSidebar')]: {
flex: '0 0 200px',
marginLeft: 80,
},
[media.between('small', 'medium')]: {
marginLeft: 40,
},
[media.greaterThan('largerSidebar')]: {
flex: '0 0 300px',
},
[media.greaterThan('sidebarFixed')]: {
position: 'fixed',
right: 0,
width: 300,
zIndex: 2,
},
},
editLink: {
color: colors.subtle,
borderColor: colors.divider,
transition: 'all 0.2s ease',
transitionPropery: 'color, border-color',
whiteSpace: 'nowrap',
borderBottomWidth: 1,
borderBottomStyle: 'solid',
':hover': {
color: colors.text,
borderColor: colors.text,
},
},
},
markdown: {
lineHeight: '25px',
'& .gatsby-highlight': {
marginTop: 25,
marginLeft: -30,
marginRight: -30,
marginBottom: 25,
paddingLeft: 15,
paddingRight: 15,
[media.lessThan('small')]: {
marginLeft: -20,
marginRight: -20,
borderRadius: 0,
},
},
'& a:not(.anchor):not(.gatsby-resp-image-link)': linkStyle,
'& > p:first-child': {
fontSize: 18,
fontWeight: 300,
color: colors.subtle,
[media.greaterThan('xlarge')]: {
fontSize: 24,
},
'& a, & strong': {
fontWeight: 400,
},
},
'& p': {
marginTop: 30,
fontSize: 17,
lineHeight: 1.7,
maxWidth: '42em',
'&:first-of-type': {
marginTop: 15,
},
'&:first-child': {
marginTop: 0,
},
[media.lessThan('large')]: {
fontSize: 16,
marginTop: 25,
},
},
'& h3 + p, & h3 + p:first-of-type': {
marginTop: 20,
},
'& p > code, & li > code': {
background: hex2rgba(colors.note, 0.3),
padding: '0 3px',
fontSize: 'inherit',
color: colors.text,
wordBreak: 'break-word',
},
'& hr': {
height: 1,
marginBottom: -1,
border: 'none',
borderBottom: `1px solid ${colors.divider}`,
marginTop: 40,
':first-child': {
marginTop: 0,
},
},
'& h1': {
lineHeight: 1.2,
[media.size('xsmall')]: {
fontSize: 30,
},
[media.between('small', 'large')]: {
fontSize: 45,
},
[media.greaterThan('xlarge')]: {
fontSize: 60,
},
},
'& h2': {
borderTop: `1px solid ${colors.divider}`,
marginTop: 44,
paddingTop: 40,
lineHeight: 1.2,
':first-child': {
borderTop: 0,
marginTop: 0,
paddingTop: 0,
},
[media.lessThan('large')]: {
fontSize: 20,
},
[media.greaterThan('xlarge')]: {
fontSize: 35,
},
},
'& hr + h2': {
borderTop: 0,
marginTop: 0,
},
'& h3': {
paddingTop: 45,
[media.greaterThan('xlarge')]: {
fontSize: 25,
lineHeight: 1.3,
},
},
'& h2 + h3, & h2 + h3:first-of-type': {
paddingTop: 30,
},
'& h4': {
fontSize: 20,
color: colors.subtle,
lineHeight: 1.3,
marginTop: 50,
fontWeight: 400,
},
'& h4 + p': {
marginTop: 20,
},
'& ol, & ul': {
marginTop: 20,
fontSize: 16,
color: colors.text,
[media.lessThan('small')]: {
paddingLeft: 20,
},
'& p, & p:first-of-type': {
fontSize: 16,
marginTop: 0,
lineHeight: 1.2,
},
'& li': {
marginTop: 20,
},
'& li.button-newapp': {
marginTop: 0,
},
'& ol, & ul': {
marginLeft: 20,
},
},
'& img': {
maxWidth: '100%',
},
'& ol': {
listStyle: 'decimal',
},
'& ul': {
listStyle: 'disc',
},
'& blockquote': {
backgroundColor: hex2rgba('#ffe564', 0.3),
borderLeftColor: colors.note,
borderLeftWidth: 9,
borderLeftStyle: 'solid',
padding: '20px 45px 20px 26px',
marginBottom: 30,
marginTop: 20,
marginLeft: -30,
marginRight: -30,
[media.lessThan('small')]: {
marginLeft: -20,
marginRight: -20,
},
'& p': {
marginTop: 15,
'&:first-of-type': {
fontWeight: 700,
marginTop: 0,
},
'&:nth-of-type(2)': {
marginTop: 0,
},
},
},
'& .gatsby-highlight + blockquote': {
marginTop: 40,
},
},
};
export default {
colors,
fonts,
media,
sharedStyles,
};

117
src/utils/createLink.js

@ -0,0 +1,117 @@
/**
* Copyright 2015-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
* @emails react-core
*/
'use strict';
import Link from 'gatsby-link';
import React from 'react';
import ExternalLinkSvg from 'templates/components/ExternalLinkSvg';
import isItemActive from 'utils/isItemActive';
import slugify from 'utils/slugify';
import {colors, media} from 'theme';
const createLinkBlog = ({item, location, section}) => {
const isActive = isItemActive(location, item);
return (
<Link css={[linkCss, isActive && activeLinkCss]} to={item.id}>
{isActive && <span css={activeLinkBefore} />}
{item.title}
</Link>
);
};
const createLinkCommunity = ({item, location, section}) => {
if (item.href) {
return (
<a css={[linkCss]} href={item.href} target="_blank" rel="noopener">
{item.title}
<ExternalLinkSvg
cssProps={{
verticalAlign: -2,
display: 'inline-block',
marginLeft: 5,
color: colors.subtle,
}}
/>
</a>
);
}
return createLinkDocs({
item,
location,
section,
});
};
const createLinkDocs = ({item, location, section}) => {
const isActive = isItemActive(location, item);
return (
<Link
css={[linkCss, isActive && activeLinkCss]}
to={slugify(item.id, section.directory)}>
{isActive && <span css={activeLinkBefore} />}
{item.title}
</Link>
);
};
const createLinkTutorial = ({item, location, onLinkClick, section}) => {
const isActive = isItemActive(location, item);
return (
<Link
css={[linkCss, isActive && activeLinkCss]}
onClick={onLinkClick}
to={item.href}>
{isActive && <span css={activeLinkBefore} />}
{item.title}
</Link>
);
};
const activeLinkCss = {
fontWeight: 700,
};
const activeLinkBefore = {
width: 4,
height: 25,
borderLeft: `4px solid ${colors.brand}`,
paddingLeft: 16,
position: 'absolute',
left: 0,
marginTop: -3,
[media.greaterThan('largerSidebar')]: {
left: 15,
},
};
const linkCss = {
color: colors.text,
display: 'inline-block',
borderBottom: '1px solid transparent',
transition: 'border 0.2s ease',
marginTop: 5,
'&:hover': {
color: colors.subtle,
},
};
export default {
createLinkBlog,
createLinkCommunity,
createLinkDocs,
createLinkTutorial,
};

15
src/utils/createOgUrl.js

@ -0,0 +1,15 @@
/**
* Copyright (c) 2013-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @emails react-core
*/
'use strict';
import {urlRoot} from 'site-constants';
export default slug =>
slug == null ? null : `${urlRoot}/${slug.replace(/^\//, '')}`;

37
src/utils/findSectionForPath.js

@ -0,0 +1,37 @@
/**
* Copyright (c) 2013-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @emails react-core
*/
'use strict';
import slugify from './slugify';
/**
* Helper method to locate the section containing the current URL/path.
* This method specifically works with the nav_*.yml format.
*/
const findSectionForPath = (pathname, sections) => {
let activeSection;
const slugId = pathname.split('/').slice(-1)[0];
sections.forEach(section => {
const match = section.items.some(
item =>
slugId === slugify(item.id) ||
(item.subitems &&
item.subitems.some(subitem => slugId === slugify(subitem.id))),
);
if (match) {
activeSection = section;
}
});
return activeSection;
};
export default findSectionForPath;

35
src/utils/isItemActive.js

@ -0,0 +1,35 @@
/**
* Copyright (c) 2013-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @emails react-core
*/
'use strict';
import slugify from 'utils/slugify';
const toAnchor = (href = '') => {
const index = href.indexOf('#');
return index >= 0 ? href.substr(index) : '';
};
// TODO Account for redirect_from URLs somehow; they currently won't match.
// This comment should not be true anymore since we're using 300 redirects
const isItemActive = (location, item) => {
if (location.hash) {
if (item.href) {
return location.hash === toAnchor(item.href);
}
} else if (item.id.includes('html')) {
return location.pathname.includes(item.id);
} else {
const slugId = location.pathname.split('/').slice(-1)[0];
return slugId === slugify(item.id);
}
};
export default isItemActive;

41
src/utils/mountCodeExample.js

@ -0,0 +1,41 @@
/**
* Copyright (c) 2013-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @emails react-core
*/
'use strict';
import CodeEditor from '../components/CodeEditor';
import React from 'react';
import ReactDOM from 'react-dom';
// TODO This is a huge hack.
// Remark transform this template to split code examples and their targets apart.
const mountCodeExample = (containerId, code) => {
const container = document.getElementById(containerId);
const parent = container.parentElement;
const children = Array.prototype.filter.call(
parent.children,
child => child !== container,
);
children.forEach(child => parent.removeChild(child));
const description = children
.map(child => child.outerHTML)
.join('')
.replace(/`([^`]+)`/g, '<code>$1</code>');
ReactDOM.render(
<CodeEditor code={code}>
{<div dangerouslySetInnerHTML={{__html: description}} />}
</CodeEditor>,
container,
);
};
export default mountCodeExample;

32
src/utils/sectionList.js

@ -0,0 +1,32 @@
/**
* Copyright 2015-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
* @emails react-core
*/
'use strict';
import navCommunity from '../../content/community/nav.yml';
import navDocs from '../../content/docs/nav.yml';
import navTutorial from '../../content/tutorial/nav.yml';
const sectionListDocs = navDocs.map(item => ({
...item,
directory: 'docs',
}));
const sectionListCommunity = navCommunity.map(item => ({
...item,
directory: 'community',
}));
export {
sectionListCommunity,
sectionListDocs,
navTutorial as sectionListTutorial,
};

18
src/utils/slugify.js

@ -0,0 +1,18 @@
/**
* Copyright (c) 2013-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @emails react-core
*/
'use strict';
import slugify from 'slugify';
export default (string, directory) => {
const filename = slugify(string) + '.html';
return directory ? `/${directory}/${filename}` : filename;
};

39
src/utils/toCommaSeparatedList.js

@ -0,0 +1,39 @@
/**
* Copyright (c) 2013-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @emails react-core
*/
'use strict';
import React from 'react';
const addString = (list, string) =>
list.push(<span key={`${list.length}-${string}`}>{string}</span>);
const toCommaSeparatedList = (array, renderCallback) => {
if (array.length <= 1) {
return array.map(renderCallback);
}
const list = [];
array.forEach((item, index) => {
if (index === array.length - 1) {
addString(list, array.length === 2 ? ' and ' : ', and ');
list.push(renderCallback(item, index));
} else if (index > 0) {
addString(list, ', ');
list.push(renderCallback(item, index));
} else {
list.push(renderCallback(item, index));
}
});
return list;
};
export default toCommaSeparatedList;

BIN
static/external.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

BIN
static/favicon.ico

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

12
static/js/jsfiddle-integration-babel.js

@ -0,0 +1,12 @@
// Do not delete or move this file.
// Many fiddles reference it so we have to keep it here.
(function() {
var tag = document.querySelector(
'script[type="application/javascript;version=1.7"]'
);
if (!tag || tag.textContent.indexOf('window.onload=function(){') !== -1) {
alert('Bad JSFiddle configuration, please fork the original React JSFiddle');
}
tag.setAttribute('type', 'text/babel');
tag.textContent = tag.textContent.replace(/^\/\/<!\[CDATA\[/, '');
})();

12
static/js/jsfiddle-integration.js

@ -0,0 +1,12 @@
// Do not delete or move this file.
// Many fiddles reference it so we have to keep it here.
(function() {
var tag = document.querySelector(
'script[type="application/javascript;version=1.7"]'
);
if (!tag || tag.textContent.indexOf('window.onload=function(){') !== -1) {
alert('Bad JSFiddle configuration, please fork the original React JSFiddle');
}
tag.setAttribute('type', 'text/jsx;harmony=true');
tag.textContent = tag.textContent.replace(/^\/\/<!\[CDATA\[/, '');
})();

1
static/large-logo.svg

@ -0,0 +1 @@
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 823.85795 733"><title>large-logo</title><g opacity="0.05"><path d="M677.3796,237.5782v-.00013q-13.15347-4.51184-26.52168-8.35682,2.2162-9.00546,4.09815-18.08832c20.07545-97.45293,6.9495-175.96071-37.87563-201.8043C574.10386-15.45755,503.81433,10.386,432.82482,72.16188q-10.49272,9.15182-20.513,18.8248-6.70815-6.42994-13.651-12.60818c-74.39859-66.06005-148.97227-93.89436-193.75-67.97423-42.93648,24.85548-55.65406,98.66342-37.5803,191.01912q2.69729,13.71891,6.08893,27.28742c-10.55176,2.99712-20.74263,6.19108-30.49228,9.58925C55.70506,268.70848,0,316.37033,0,365.80411c0,51.06,59.796,102.27313,150.64951,133.32334q11.05033,3.759,22.27764,6.96393-3.64625,14.61321-6.47177,29.4132c-17.23148,90.75134-3.77376,162.80916,39.04973,187.51155,44.23076,25.50438,118.46536-.71107,190.75293-63.898q8.57022-7.49254,17.19138-15.84583,10.8498,10.46823,22.27032,20.3197c70.01968,60.25168,139.17161,84.58221,181.9586,59.81425,44.19066-25.581,58.549-102.99126,39.90285-197.17376q-2.13293-10.79053-4.94043-22.02241,7.82091-2.308,15.32089-4.78369C762.41022,468.13563,823.858,417.546,823.858,365.80425,823.858,316.19178,766.35894,268.20914,677.3796,237.5782ZM455.93017,98.71275c60.82417-52.934,117.67049-73.83348,143.5724-58.89543h.00007c27.58633,15.9116,38.31685,80.072,20.98329,164.213q-1.70415,8.22186-3.70447,16.37829A843.11184,843.11184,0,0,0,506.62552,203.0058c-22.63859-32.23516-46.09393-61.54615-69.6405-86.91573Q446.24028,107.16747,455.93017,98.71275ZM243.25691,408.03318q11.17562,21.58674,23.35692,42.63018,12.4265,21.46008,25.86547,42.30946a749.41279,749.41279,0,0,1-75.92641-12.20726C223.8269,457.27737,232.789,432.86312,243.25691,408.03318Zm-.0401-82.7737c-10.24913-24.30852-19.018-48.20874-26.17895-71.28855,23.50634-5.26129,48.57329-9.56006,74.69032-12.82331q-13.1139,20.4542-25.25653,41.50721Q254.34864,303.68289,243.21681,325.25948ZM261.9249,366.65q16.266-33.856,35.04269-66.41735v.00731q18.75838-32.54479,39.94668-63.59526c24.50177-1.85227,49.62338-2.82209,75.01843-2.82209,25.50817,0,50.66256.97714,75.15708,2.844q20.95959,30.97974,39.695,63.38007,18.82881,32.46544,35.51663,66.10381-16.50682,33.96338-35.39993,66.68714l-.00366.00007q-18.71978,32.51932-39.52367,63.77022c-24.44345,1.7466-49.70364,2.64707-75.44509,2.64707-25.63571,0-50.575-.79833-74.5919-2.35527q-21.33273-31.16146-40.26388-63.86883Q278.245,400.51974,261.9249,366.65Zm295.46159,83.76919q12.43081-21.55706,23.8929-43.65115h.00007a747.44376,747.44376,0,0,1,27.66653,72.4735,746.90393,746.90393,0,0,1-76.85248,13.10041Q545.15579,471.63431,557.38649,450.41918ZM580.944,325.28495Q569.52351,303.615,557.24445,282.4141v.00007q-12.081-20.868-25.05238-41.20092c26.2884,3.31791,51.472,7.72974,75.12057,13.1296A750.753,750.753,0,0,1,580.944,325.28495ZM412.32291,141.25908A752.67935,752.67935,0,0,1,460.805,199.78624q-48.65887-2.29927-97.37267-.02188C379.43872,178.65711,395.83523,159.04842,412.32291,141.25908ZM222.5434,40.86376C250.10793,24.9084,311.05246,47.66,375.2895,104.696c4.10546,3.64609,8.22921,7.46354,12.36021,11.41226a843.39474,843.39474,0,0,0-70.18008,86.8501A859.96423,859.96423,0,0,0,207.53247,220.044q-3.15066-12.6187-5.66241-25.38408v.00359C186.38506,115.5322,196.667,55.84191,222.5434,40.86376ZM182.3707,472.19q-10.24566-2.93259-20.33792-6.3661c-40.17271-13.73122-73.34857-31.57522-96.0893-51.04533-20.43275-17.50133-30.75117-34.875-30.75117-48.97441,0-29.99646,44.72664-68.26231,119.3222-94.26995q14.04424-4.87509,28.35573-8.922A844.0802,844.0802,0,0,0,223.02473,366.661,856.90089,856.90089,0,0,0,182.3707,472.19ZM373.09815,632.61472c-31.96537,27.94364-63.99632,47.76386-92.22443,57.736l-.00366-.00013c-25.36593,8.95844-45.56892,9.21367-57.7797,2.17319-25.98942-14.9856-36.78916-72.84909-22.05526-150.45626q2.62813-13.75741,6.01605-27.35312c33.74463,7.46354,71.0989,12.83435,111.02376,16.07206a856.43741,856.43741,0,0,0,70.71972,87.37518Q381.12547,625.58012,373.09815,632.61472Zm40.19824-39.779c-16.68093-18.00074-33.318-37.90848-49.56871-59.322q23.65952.92986,48.20142.93338,25.19087,0,49.73277-1.10475A748.43012,748.43012,0,0,1,413.2964,592.83569Zm213.71969,48.96723c-4.90764,26.44873-14.774,44.0814-26.97381,51.14381-25.96389,15.02922-81.49033-4.50652-141.36655-56.0333q-10.29837-8.85989-20.71716-18.88671c23.21474-25.3914,46.41485-54.91026,69.05717-87.68879,39.83-3.53291,77.45769-9.31215,111.58149-17.19849q2.51586,10.17258,4.45924,19.92955v-.00013C631.3003,574.71465,632.47794,612.3679,627.01609,641.80291Zm29.87976-175.78216h-.00359c-4.50293,1.49124-9.12622,2.93148-13.837,4.3279-10.42787-33.00808-24.50177-68.10909-41.71868-104.36958a825.689,825.689,0,0,0,40.09617-102.84915c8.42612,2.44291,16.60791,5.01338,24.4908,7.72974,76.24,26.241,122.74232,65.0464,122.74232,94.94445C788.6659,397.65278,738.44091,438.99953,656.89585,466.02076Z" fill="#fff"/><path d="M411.929,292.23677a73.56917,73.56917,0,1,1-73.56735,73.56735A73.56713,73.56713,0,0,1,411.929,292.23677" fill="#fff"/></g></svg>

After

Width:  |  Height:  |  Size: 4.8 KiB

BIN
static/logo-og.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

14
static/search.svg

@ -0,0 +1,14 @@
<svg
alt="Search"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 16 16"
>
<path
d="
M6.02945,10.20327a4.17382,4.17382,0,1,1,4.17382-4.17382A4.15609,4.15609,
0,0,1,6.02945,10.20327Zm9.69195,4.2199L10.8989,9.59979A5.88021,5.88021,
0,0,0,12.058,6.02856,6.00467,6.00467,0,1,0,9.59979,10.8989l4.82338,
4.82338a.89729.89729,0,0,0,1.29912,0,.89749.89749,0,0,0-.00087-1.29909Z"
fill="#ffffff"
/>
</svg>

After

Width:  |  Height:  |  Size: 437 B

10265
yarn.lock

File diff suppressed because it is too large
Loading…
Cancel
Save