Showing preview only (447K chars total). Download the full file or copy to clipboard to get everything.
Repository: scalable-react/scalable-react-typescript-boilerplate
Branch: master
Commit: 9c6eb0bb74a1
Files: 414
Total size: 346.7 KB
Directory structure:
gitextract_ld6wikvo/
├── .babelrc
├── .eslintignore
├── .github/
│ ├── CHANGELOG.md
│ └── CONTRIBUTING.md
├── .gitignore
├── .nvmrc
├── .travis.yml
├── LICENSE
├── Procfile
├── README.md
├── config/
│ ├── .storybook/
│ │ ├── addons.js
│ │ ├── config.js
│ │ ├── stories/
│ │ │ └── index.js
│ │ └── webpack.config.js
│ ├── generators/
│ │ ├── cli.js
│ │ ├── component/
│ │ │ ├── es6class.tsx.hbs
│ │ │ ├── export.ts.hbs
│ │ │ ├── import.ts.hbs
│ │ │ ├── index.js
│ │ │ ├── stateless.tsx.hbs
│ │ │ ├── styles.ts.hbs
│ │ │ └── types.ts.hbs
│ │ ├── container/
│ │ │ ├── actionCreators.js.hbs
│ │ │ ├── actions.js.hbs
│ │ │ ├── constants.js.hbs
│ │ │ ├── export.js.hbs
│ │ │ ├── import.js.hbs
│ │ │ ├── index.js
│ │ │ ├── index.js.hbs
│ │ │ ├── presentation.js.hbs
│ │ │ ├── reducer.export-state.js.hbs
│ │ │ ├── reducer.export.js.hbs
│ │ │ ├── reducer.import.js.hbs
│ │ │ ├── reducer.js.hbs
│ │ │ ├── selectors.js.hbs
│ │ │ ├── state-type.js.hbs
│ │ │ ├── state.import.js.hbs
│ │ │ ├── state.js.hbs
│ │ │ ├── styles.js.hbs
│ │ │ ├── types.export.ts.hbs
│ │ │ ├── types.import.ts.hbs
│ │ │ └── types.ts.hbs
│ │ └── utils/
│ │ ├── index.js
│ │ └── safeString.js
│ ├── ignoreAssets.js
│ ├── scripts/
│ │ └── clean.js
│ ├── testing/
│ │ ├── __mocks__/
│ │ │ ├── fileMock.js
│ │ │ └── styleMock.js
│ │ ├── preprocessor.js
│ │ └── templates/
│ │ └── _index.prod.html
│ └── types/
│ └── require.d.ts
├── devServer.js
├── index.html
├── lerna.json
├── netlify.toml
├── package.json
├── packages/
│ ├── docs/
│ │ ├── .babelrc
│ │ ├── config/
│ │ │ ├── generators/
│ │ │ │ ├── cli.js
│ │ │ │ ├── component/
│ │ │ │ │ ├── es6class.tsx.hbs
│ │ │ │ │ ├── export.ts.hbs
│ │ │ │ │ ├── import.ts.hbs
│ │ │ │ │ ├── index.js
│ │ │ │ │ ├── stateless.tsx.hbs
│ │ │ │ │ ├── styles.ts.hbs
│ │ │ │ │ └── types.ts.hbs
│ │ │ │ ├── container/
│ │ │ │ │ ├── actionCreators.js.hbs
│ │ │ │ │ ├── actions.js.hbs
│ │ │ │ │ ├── constants.js.hbs
│ │ │ │ │ ├── export.js.hbs
│ │ │ │ │ ├── import.js.hbs
│ │ │ │ │ ├── index.js
│ │ │ │ │ ├── index.js.hbs
│ │ │ │ │ ├── presentation.js.hbs
│ │ │ │ │ ├── reducer.export-state.js.hbs
│ │ │ │ │ ├── reducer.export.js.hbs
│ │ │ │ │ ├── reducer.import.js.hbs
│ │ │ │ │ ├── reducer.js.hbs
│ │ │ │ │ ├── selectors.js.hbs
│ │ │ │ │ ├── state-type.js.hbs
│ │ │ │ │ ├── state.import.js.hbs
│ │ │ │ │ ├── state.js.hbs
│ │ │ │ │ ├── styles.js.hbs
│ │ │ │ │ ├── types.export.ts.hbs
│ │ │ │ │ ├── types.import.ts.hbs
│ │ │ │ │ └── types.ts.hbs
│ │ │ │ └── utils/
│ │ │ │ ├── index.js
│ │ │ │ └── safeString.js
│ │ │ ├── ignoreAssets.js
│ │ │ └── types/
│ │ │ └── require.d.ts
│ │ ├── devServer.js
│ │ ├── index.html
│ │ ├── package.json
│ │ ├── server.js
│ │ ├── src/
│ │ │ ├── client/
│ │ │ │ ├── apolloClient.ts
│ │ │ │ ├── components/
│ │ │ │ │ ├── AddComment/
│ │ │ │ │ │ ├── __tests__/
│ │ │ │ │ │ │ ├── __mocks__/
│ │ │ │ │ │ │ │ └── addCommentMocks.mock.ts
│ │ │ │ │ │ │ ├── __snapshots__/
│ │ │ │ │ │ │ │ └── index.test.tsx.snap
│ │ │ │ │ │ │ └── index.test.tsx
│ │ │ │ │ │ ├── index.tsx
│ │ │ │ │ │ ├── styles.ts
│ │ │ │ │ │ └── types.ts
│ │ │ │ │ ├── Comment/
│ │ │ │ │ │ ├── __tests__/
│ │ │ │ │ │ │ ├── __mocks__/
│ │ │ │ │ │ │ │ └── commentMocks.mock.ts
│ │ │ │ │ │ │ ├── __snapshots__/
│ │ │ │ │ │ │ │ └── index.test.tsx.snap
│ │ │ │ │ │ │ └── index.test.tsx
│ │ │ │ │ │ ├── index.tsx
│ │ │ │ │ │ ├── styles.ts
│ │ │ │ │ │ └── types.ts
│ │ │ │ │ ├── Html/
│ │ │ │ │ │ └── index.tsx
│ │ │ │ │ ├── NavBar/
│ │ │ │ │ │ ├── __tests__/
│ │ │ │ │ │ │ ├── __mocks__/
│ │ │ │ │ │ │ │ └── navBarMocks.mock.ts
│ │ │ │ │ │ │ ├── __snapshots__/
│ │ │ │ │ │ │ │ └── index.test.tsx.snap
│ │ │ │ │ │ │ └── index.test.tsx
│ │ │ │ │ │ ├── index.tsx
│ │ │ │ │ │ ├── styles.ts
│ │ │ │ │ │ └── types.ts
│ │ │ │ │ ├── Pic/
│ │ │ │ │ │ ├── index.tsx
│ │ │ │ │ │ ├── styles.ts
│ │ │ │ │ │ └── types.ts
│ │ │ │ │ ├── Post/
│ │ │ │ │ │ ├── index.tsx
│ │ │ │ │ │ └── types.ts
│ │ │ │ │ ├── PostCard/
│ │ │ │ │ │ ├── index.tsx
│ │ │ │ │ │ ├── shortenText.ts
│ │ │ │ │ │ ├── styles.ts
│ │ │ │ │ │ └── types.ts
│ │ │ │ │ ├── index.ts
│ │ │ │ │ └── utils/
│ │ │ │ │ ├── index.ts
│ │ │ │ │ └── remStringFromPx.ts
│ │ │ │ ├── containers/
│ │ │ │ │ ├── About/
│ │ │ │ │ │ ├── about.ts
│ │ │ │ │ │ ├── contributors.ts
│ │ │ │ │ │ ├── index.tsx
│ │ │ │ │ │ └── styles.ts
│ │ │ │ │ ├── App/
│ │ │ │ │ │ ├── __tests__/
│ │ │ │ │ │ │ ├── __snapshots__/
│ │ │ │ │ │ │ │ └── index.test.tsx.snap
│ │ │ │ │ │ │ ├── actionCreators.test.ts
│ │ │ │ │ │ │ ├── index.test.tsx
│ │ │ │ │ │ │ ├── reducer.test.ts
│ │ │ │ │ │ │ └── selectors.test.ts
│ │ │ │ │ │ ├── actionCreators.ts
│ │ │ │ │ │ ├── actions.ts
│ │ │ │ │ │ ├── constants.ts
│ │ │ │ │ │ ├── index.tsx
│ │ │ │ │ │ ├── presentation.tsx
│ │ │ │ │ │ ├── reducer.ts
│ │ │ │ │ │ ├── selectors.ts
│ │ │ │ │ │ ├── state.ts
│ │ │ │ │ │ ├── styles.ts
│ │ │ │ │ │ └── types.ts
│ │ │ │ │ ├── Blog/
│ │ │ │ │ │ ├── index.tsx
│ │ │ │ │ │ ├── posts.graphql.ts
│ │ │ │ │ │ ├── styles.ts
│ │ │ │ │ │ └── types.ts
│ │ │ │ │ ├── BlogPost/
│ │ │ │ │ │ ├── __tests__/
│ │ │ │ │ │ │ ├── __mocks__/
│ │ │ │ │ │ │ │ ├── blogPostPresentation.mock.ts
│ │ │ │ │ │ │ │ └── blogPostSelectors.mock.ts
│ │ │ │ │ │ │ ├── __snapshots__/
│ │ │ │ │ │ │ │ └── index.test.tsx.snap
│ │ │ │ │ │ │ ├── actionCreators.test.ts
│ │ │ │ │ │ │ ├── index.test.tsx
│ │ │ │ │ │ │ ├── reducer.test.ts
│ │ │ │ │ │ │ └── selectors.test.ts
│ │ │ │ │ │ ├── actionCreators.ts
│ │ │ │ │ │ ├── actions.ts
│ │ │ │ │ │ ├── apollo.ts
│ │ │ │ │ │ ├── commentMutation.graphql.ts
│ │ │ │ │ │ ├── constants.ts
│ │ │ │ │ │ ├── index.tsx
│ │ │ │ │ │ ├── postQuery.graphql.ts
│ │ │ │ │ │ ├── presentation.tsx
│ │ │ │ │ │ ├── reducer.ts
│ │ │ │ │ │ ├── selectors.ts
│ │ │ │ │ │ ├── state.ts
│ │ │ │ │ │ ├── styles.ts
│ │ │ │ │ │ └── types.ts
│ │ │ │ │ ├── Docs/
│ │ │ │ │ │ ├── __tests__/
│ │ │ │ │ │ │ ├── __mocks__/
│ │ │ │ │ │ │ │ └── docsMocks.mock.ts
│ │ │ │ │ │ │ ├── __snapshots__/
│ │ │ │ │ │ │ │ └── index.test.tsx.snap
│ │ │ │ │ │ │ ├── actionCreators.test.ts
│ │ │ │ │ │ │ ├── index.test.tsx
│ │ │ │ │ │ │ ├── logic.test.ts
│ │ │ │ │ │ │ ├── reducer.test.ts
│ │ │ │ │ │ │ └── selectors.test.ts
│ │ │ │ │ │ ├── actionCreators.ts
│ │ │ │ │ │ ├── actions.ts
│ │ │ │ │ │ ├── constants.ts
│ │ │ │ │ │ ├── index.tsx
│ │ │ │ │ │ ├── logic.ts
│ │ │ │ │ │ ├── presentation.tsx
│ │ │ │ │ │ ├── reducer.ts
│ │ │ │ │ │ ├── selectors.ts
│ │ │ │ │ │ ├── state.ts
│ │ │ │ │ │ ├── styles.ts
│ │ │ │ │ │ └── types.ts
│ │ │ │ │ ├── Features/
│ │ │ │ │ │ ├── features.ts
│ │ │ │ │ │ ├── index.tsx
│ │ │ │ │ │ ├── styles.ts
│ │ │ │ │ │ └── types.ts
│ │ │ │ │ ├── Home/
│ │ │ │ │ │ ├── index.tsx
│ │ │ │ │ │ ├── presentation.tsx
│ │ │ │ │ │ ├── styles.ts
│ │ │ │ │ │ └── types.ts
│ │ │ │ │ ├── TodoApp/
│ │ │ │ │ │ ├── __tests__/
│ │ │ │ │ │ │ ├── __mocks__/
│ │ │ │ │ │ │ │ ├── presentation.mock.ts
│ │ │ │ │ │ │ │ └── selectors.mock.ts
│ │ │ │ │ │ │ ├── __snapshots__/
│ │ │ │ │ │ │ │ └── index.test.tsx.snap
│ │ │ │ │ │ │ ├── actionCreators.test.ts
│ │ │ │ │ │ │ ├── index.test.tsx
│ │ │ │ │ │ │ ├── reducer.test.ts
│ │ │ │ │ │ │ └── selectors.test.ts
│ │ │ │ │ │ ├── actionCreators.ts
│ │ │ │ │ │ ├── actions.ts
│ │ │ │ │ │ ├── constants.ts
│ │ │ │ │ │ ├── index.tsx
│ │ │ │ │ │ ├── presentation.tsx
│ │ │ │ │ │ ├── reducer.ts
│ │ │ │ │ │ ├── selectors.ts
│ │ │ │ │ │ ├── state.ts
│ │ │ │ │ │ ├── styles.ts
│ │ │ │ │ │ └── types.ts
│ │ │ │ │ └── index.ts
│ │ │ │ ├── index.tsx
│ │ │ │ ├── logic.ts
│ │ │ │ ├── reducers.ts
│ │ │ │ ├── routes.tsx
│ │ │ │ ├── shared/
│ │ │ │ │ ├── actionCreators.ts
│ │ │ │ │ ├── actions.ts
│ │ │ │ │ └── constants.ts
│ │ │ │ ├── state.ts
│ │ │ │ ├── store.tsx
│ │ │ │ ├── test/
│ │ │ │ │ └── mockstore.ts
│ │ │ │ ├── theming/
│ │ │ │ │ ├── colorMap.ts
│ │ │ │ │ ├── globalCss.ts
│ │ │ │ │ ├── index.ts
│ │ │ │ │ └── types.ts
│ │ │ │ └── types.ts
│ │ │ └── server/
│ │ │ ├── db/
│ │ │ │ ├── index.ts
│ │ │ │ ├── models/
│ │ │ │ │ ├── comment.ts
│ │ │ │ │ └── post.ts
│ │ │ │ └── utils/
│ │ │ │ └── uuid.ts
│ │ │ ├── graph/
│ │ │ │ ├── index.ts
│ │ │ │ ├── mutations/
│ │ │ │ │ ├── comment/
│ │ │ │ │ │ ├── createComment.ts
│ │ │ │ │ │ └── index.ts
│ │ │ │ │ └── index.ts
│ │ │ │ ├── queries/
│ │ │ │ │ ├── comment/
│ │ │ │ │ │ ├── comment.ts
│ │ │ │ │ │ ├── comments.ts
│ │ │ │ │ │ └── index.ts
│ │ │ │ │ ├── index.ts
│ │ │ │ │ └── post/
│ │ │ │ │ ├── index.ts
│ │ │ │ │ ├── post.ts
│ │ │ │ │ └── posts.ts
│ │ │ │ ├── schema.json
│ │ │ │ └── types/
│ │ │ │ ├── comment/
│ │ │ │ │ ├── comment.ts
│ │ │ │ │ └── commentInput.ts
│ │ │ │ ├── index.ts
│ │ │ │ └── post/
│ │ │ │ ├── post.ts
│ │ │ │ └── postInput.ts
│ │ │ ├── graphqlEntry.ts
│ │ │ └── index.tsx
│ │ ├── tsconfig.json
│ │ ├── webpack.config.js
│ │ ├── webpack.config.prod.js
│ │ └── webpack.config.server.js
│ └── openui/
│ ├── package.json
│ ├── src/
│ │ ├── Anchor/
│ │ │ ├── __tests__/
│ │ │ │ ├── __mocks__/
│ │ │ │ │ └── anchorMocks.mock.ts
│ │ │ │ ├── __snapshots__/
│ │ │ │ │ └── index.test.tsx.snap
│ │ │ │ └── index.test.tsx
│ │ │ ├── index.tsx
│ │ │ ├── styles.ts
│ │ │ └── types.ts
│ │ ├── Article/
│ │ │ ├── __tests__/
│ │ │ │ ├── __mocks__/
│ │ │ │ │ └── articleMocks.mock.ts
│ │ │ │ ├── __snapshots__/
│ │ │ │ │ └── index.test.tsx.snap
│ │ │ │ └── index.test.tsx
│ │ │ ├── index.tsx
│ │ │ ├── styles.ts
│ │ │ └── types.ts
│ │ ├── Avatar/
│ │ │ ├── __tests__/
│ │ │ │ ├── __mocks__/
│ │ │ │ │ └── avatarMocks.mock.ts
│ │ │ │ ├── __snapshots__/
│ │ │ │ │ └── index.test.tsx.snap
│ │ │ │ └── index.test.tsx
│ │ │ ├── default.ts
│ │ │ ├── index.tsx
│ │ │ ├── maps.ts
│ │ │ ├── styles.ts
│ │ │ └── types.ts
│ │ ├── Box/
│ │ │ ├── __tests__/
│ │ │ │ ├── __mocks__/
│ │ │ │ │ └── boxMocks.mock.ts
│ │ │ │ ├── __snapshots__/
│ │ │ │ │ └── index.test.tsx.snap
│ │ │ │ └── index.test.tsx
│ │ │ ├── index.tsx
│ │ │ ├── maps.ts
│ │ │ ├── styleUtils.ts
│ │ │ ├── styles.ts
│ │ │ └── types.ts
│ │ ├── Button/
│ │ │ ├── __tests__/
│ │ │ │ ├── __mocks__/
│ │ │ │ │ └── buttonMocks.mock.ts
│ │ │ │ ├── __snapshots__/
│ │ │ │ │ └── index.test.tsx.snap
│ │ │ │ └── index.test.tsx
│ │ │ ├── index.tsx
│ │ │ ├── maps.ts
│ │ │ ├── styles.ts
│ │ │ └── types.ts
│ │ ├── Footer/
│ │ │ ├── __tests__/
│ │ │ │ ├── __mocks__/
│ │ │ │ │ └── footerMocks.mock.ts
│ │ │ │ ├── __snapshots__/
│ │ │ │ │ └── index.test.tsx.snap
│ │ │ │ └── index.test.tsx
│ │ │ ├── index.tsx
│ │ │ ├── styles.ts
│ │ │ └── types.ts
│ │ ├── Header/
│ │ │ ├── header.tsx
│ │ │ ├── index.tsx
│ │ │ ├── styles.ts
│ │ │ ├── types.ts
│ │ │ └── utils.ts
│ │ ├── Heading/
│ │ │ ├── __tests__/
│ │ │ │ ├── __mocks__/
│ │ │ │ │ └── headingProps.mock.ts
│ │ │ │ ├── __snapshots__/
│ │ │ │ │ └── index.test.tsx.snap
│ │ │ │ └── index.test.tsx
│ │ │ ├── index.tsx
│ │ │ ├── styleUtils.ts
│ │ │ ├── styles.ts
│ │ │ └── types.ts
│ │ ├── Headline/
│ │ │ ├── __tests__/
│ │ │ │ ├── __mocks__/
│ │ │ │ │ └── headlineProps.mock.ts
│ │ │ │ ├── __snapshots__/
│ │ │ │ │ └── index.test.tsx.snap
│ │ │ │ └── index.test.tsx
│ │ │ ├── index.tsx
│ │ │ ├── styleUtils.ts
│ │ │ ├── styles.ts
│ │ │ └── types.ts
│ │ ├── Hero/
│ │ │ ├── __tests__/
│ │ │ │ ├── __mocks__/
│ │ │ │ │ └── heroMocks.mock.ts
│ │ │ │ ├── __snapshots__/
│ │ │ │ │ └── index.test.tsx.snap
│ │ │ │ └── index.test.tsx
│ │ │ ├── index.tsx
│ │ │ ├── styles.ts
│ │ │ └── types.ts
│ │ ├── Image/
│ │ │ ├── __tests__/
│ │ │ │ ├── __mocks__/
│ │ │ │ │ └── imageMocks.mock.ts
│ │ │ │ ├── __snapshots__/
│ │ │ │ │ └── index.test.tsx.snap
│ │ │ │ └── index.test.tsx
│ │ │ ├── index.tsx
│ │ │ ├── styles.ts
│ │ │ └── types.ts
│ │ ├── LoadingIndicator/
│ │ │ ├── __tests__/
│ │ │ │ ├── __mocks__/
│ │ │ │ │ └── loadingIndicatorMocks.mock.ts
│ │ │ │ ├── __snapshots__/
│ │ │ │ │ └── index.test.tsx.snap
│ │ │ │ └── index.test.tsx
│ │ │ ├── index.tsx
│ │ │ ├── styles.ts
│ │ │ └── types.ts
│ │ ├── Markdown/
│ │ │ ├── index.tsx
│ │ │ ├── styles.ts
│ │ │ └── types.ts
│ │ ├── Notification/
│ │ │ ├── __tests__/
│ │ │ │ ├── __mocks__/
│ │ │ │ │ └── notificationMocks.mock.ts
│ │ │ │ ├── __snapshots__/
│ │ │ │ │ └── index.test.tsx.snap
│ │ │ │ └── index.test.tsx
│ │ │ ├── index.tsx
│ │ │ ├── styles.ts
│ │ │ └── types.ts
│ │ ├── Paragraph/
│ │ │ ├── index.tsx
│ │ │ ├── styleUtils.ts
│ │ │ ├── styles.ts
│ │ │ └── types.ts
│ │ ├── Section/
│ │ │ ├── __tests__/
│ │ │ │ ├── __mocks__/
│ │ │ │ │ └── sectionMocks.mock.ts
│ │ │ │ ├── __snapshots__/
│ │ │ │ │ └── index.test.tsx.snap
│ │ │ │ └── index.test.tsx
│ │ │ ├── index.tsx
│ │ │ └── styles.ts
│ │ ├── SvgIcon/
│ │ │ ├── index.tsx
│ │ │ └── types.ts
│ │ ├── Toast/
│ │ │ ├── __tests__/
│ │ │ │ ├── __mocks__/
│ │ │ │ │ └── toast.mock.ts
│ │ │ │ ├── __snapshots__/
│ │ │ │ │ └── index.test.tsx.snap
│ │ │ │ └── index.test.tsx
│ │ │ ├── index.tsx
│ │ │ ├── styles.ts
│ │ │ └── types.ts
│ │ ├── WithAnimation/
│ │ │ ├── animation.ts
│ │ │ ├── index.tsx
│ │ │ └── types.ts
│ │ ├── index.ts
│ │ ├── theming/
│ │ │ ├── colorMap.ts
│ │ │ ├── globalCss.ts
│ │ │ ├── index.ts
│ │ │ └── types.ts
│ │ └── utils/
│ │ ├── index.ts
│ │ └── remStringFromPx.ts
│ └── tsconfig.json
├── server.js
├── src/
│ ├── client/
│ │ ├── apolloClient.ts
│ │ ├── components/
│ │ │ ├── Html/
│ │ │ │ └── index.tsx
│ │ │ └── index.ts
│ │ ├── features/
│ │ │ ├── Landing/
│ │ │ │ ├── index.tsx
│ │ │ │ ├── presentation.tsx
│ │ │ │ ├── styles.ts
│ │ │ │ └── types.ts
│ │ │ ├── Layout/
│ │ │ │ ├── index.tsx
│ │ │ │ ├── main.ts
│ │ │ │ ├── presentation.tsx
│ │ │ │ ├── styles.ts
│ │ │ │ └── types.ts
│ │ │ └── index.ts
│ │ ├── index.tsx
│ │ ├── logic.ts
│ │ ├── reducers.ts
│ │ ├── routes.tsx
│ │ ├── shared/
│ │ │ ├── actionCreators.ts
│ │ │ ├── actions.ts
│ │ │ └── constants.ts
│ │ ├── state.ts
│ │ ├── store.tsx
│ │ ├── test/
│ │ │ └── mockstore.ts
│ │ ├── theming/
│ │ │ ├── colorMap.ts
│ │ │ ├── globalCss.ts
│ │ │ ├── index.ts
│ │ │ └── types.ts
│ │ └── types.ts
│ └── server/
│ ├── db/
│ │ ├── index.ts
│ │ ├── models/
│ │ │ └── post.ts
│ │ └── utils/
│ │ └── uuid.ts
│ ├── graph/
│ │ ├── index.ts
│ │ ├── mutations/
│ │ │ └── index.ts
│ │ ├── queries/
│ │ │ └── index.ts
│ │ ├── schema.json
│ │ └── types/
│ │ └── index.ts
│ ├── graphqlEntry.ts
│ └── index.tsx
├── tsconfig.json
├── tslint.json
├── webpack.config.js
├── webpack.config.prod.js
└── webpack.config.server.js
================================================
FILE CONTENTS
================================================
================================================
FILE: .babelrc
================================================
{
"presets": ["es2015", "react", "stage-0"],
"env": {
"development": {
"plugins": [
"react-hot-loader/babel"
]
},
"test": {
"plugins": [
[
"babel-plugin-webpack-alias", {
"config": "./webpack.config.prod.js"
}
]
]
},
"server": {
"plugins": [
[
"babel-plugin-webpack-alias", {
"config": "./webpack.config.server.js"
}
]
]
}
}
}
================================================
FILE: .eslintignore
================================================
**/*.ts
**/*.tsx
================================================
FILE: .github/CHANGELOG.md
================================================
# Change Log
## 1.0.1
- Add jest snapshot / enzyme testing
- Introduce changelog, contributing.md and roadmap.md
================================================
FILE: .github/CONTRIBUTING.md
================================================
# Contributing
When contributing to this repository, please first discuss the change you wish to make via issue,
email, or any other method with the owners of this repository before making a change.
Please note we have a code of conduct, please follow it in all your interactions with the project.
## Pull Request Process
We are following the [feature branch git workflow](https://www.atlassian.com/git/tutorials/comparing-workflows). Please post an issue if you have any questions about this process.
1. Ensure any install or build dependencies are removed before the end of the layer when doing a
build.
2. Update the README.md with details of changes to the interface, this includes new environment
variables, exposed ports, useful file locations and container parameters.
3. Increase the version numbers in any examples files and the README.md to the new version that this
Pull Request would represent. The versioning scheme we use is [SemVer](http://semver.org/).
4. You may merge the Pull Request in once you have the sign-off of two other developers, or if you
do not have permission to do that, you may request the second reviewer to merge it for you.
5. Write tests if you can!
## Code of Conduct
### Our Pledge
In the interest of fostering an open and welcoming environment, we as
contributors and maintainers pledge to making participation in our project and
our community a harassment-free experience for everyone, regardless of age, body
size, disability, ethnicity, gender identity and expression, level of experience,
nationality, personal appearance, race, religion, or sexual identity and
orientation.
### Our Standards
Examples of behavior that contributes to creating a positive environment
include:
* Using welcoming and inclusive language
* Being respectful of differing viewpoints and experiences
* Gracefully accepting constructive criticism
* Focusing on what is best for the community
* Showing empathy towards other community members
Examples of unacceptable behavior by participants include:
* The use of sexualized language or imagery and unwelcome sexual attention or
advances
* Trolling, insulting/derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or electronic
address, without explicit permission
* Other conduct which could reasonably be considered inappropriate in a
professional setting
### Our Responsibilities
Project maintainers are responsible for clarifying the standards of acceptable
behavior and are expected to take appropriate and fair corrective action in
response to any instances of unacceptable behavior.
Project maintainers have the right and responsibility to remove, edit, or
reject comments, commits, code, wiki edits, issues, and other contributions
that are not aligned to this Code of Conduct, or to ban temporarily or
permanently any contributor for other behaviors that they deem inappropriate,
threatening, offensive, or harmful.
### Scope
This Code of Conduct applies both within project spaces and in public spaces
when an individual is representing the project or its community. Examples of
representing a project or community include using an official project e-mail
address, posting via an official social media account, or acting as an appointed
representative at an online or offline event. Representation of a project may be
further defined and clarified by project maintainers.
### Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported by contacting the project team at [INSERT EMAIL ADDRESS]. All
complaints will be reviewed and investigated and will result in a response that
is deemed necessary and appropriate to the circumstances. The project team is
obligated to maintain confidentiality with regard to the reporter of an incident.
Further details of specific enforcement policies may be posted separately.
Project maintainers who do not follow or enforce the Code of Conduct in good
faith may face temporary or permanent repercussions as determined by other
members of the project's leadership.
### Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
available at [http://contributor-covenant.org/version/1/4][version]
[homepage]: http://contributor-covenant.org
[version]: http://contributor-covenant.org/version/1/4/
================================================
FILE: .gitignore
================================================
node_modules
build
dist
npm-debug.log
.vscode
coverage
yarn-error.log
.DS_STORE
lerna-debug.log
================================================
FILE: .nvmrc
================================================
6.9.5
================================================
FILE: .travis.yml
================================================
language: node_js
node_js:
- "6.9.5"
script: npm run test
notifications:
slack: scalable-react:HPFuyoipfw9RROPGrZrczz1m
email:
on_failure: always
================================================
FILE: LICENSE
================================================
The MIT License (MIT)
Copyright (c) 2016 Ryan Collins
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
================================================
FILE: Procfile
================================================
web: cross-env NODE_ENV=server node server.js
================================================
FILE: README.md
================================================

# __NOTICE__:
The maintainers of this repo are no longer able to support a thriving open source community. This repo will stay put to serve as an example for the community, but should not be depended on in a production application unless you and are your team intend to build upon it.
If you're interested in helping to support and grow this library, please let us know in the issues!
### Open UI
We are working on a ui kit, which you'll find located in the packages directory. Much like this project, this code is not yet production ready and we have yet to document it. Please stay tuned.

# Scalable React TS Boilerplate
[](https://travis-ci.org/scalable-react/scalable-react-typescript-boilerplate)
[](http://makeapullrequest.com)
[](https://github.com/scalable-react/scalable-react-typescript-boilerplate#roadmap)
[](https://github.com/scalable-react/scalable-react-typescript-boilerplate/stargazers)
[](https://github.com/scalable-react/scalable-react-typescript-boilerplate/watchers)
[](https://twitter.com/intent/tweet?text=Check%20out%20scalable-react-typescript-boilerplate!%20https://github.com/scalable-react/scalable-react-typescript-boilerplate%20%F0%9F%91%8D)
Checkout [our website](https://scalable-react-ts-boilerplate.herokuapp.com/) for documentation and examples.
## Background Info
We know that there are a ton of react boilerplates and starter projects to choose from. Our hope with this project is to provide an example of one of the best front-end architectural patterns available: Feature First. We started initially with a vanilla JS version of this architecture and have since converted it entirely to strongly-typed TypeScript. Above all else, the hope of this repository is to provide the open source community with a great example of how to build large-scale apps with React and TypeScript using the feature-first modularization pattern. Read on to get started!
## Main Features
- Feature First
- Statically Typed
- TypeScript
- Lerna
- Starter UI Kit (Open UI)
- Redux Logic
- Webpack 2
- React
- Redux
- Hot Module Reloading
- Server Side Rendering
- Highly optimized webpack configuration
- Code Chunking
- Lazy route loading
- Uglification / minification
## Getting Started
1. Clone the Repo
`git clone https://github.com/RyanCCollins/scalable-react-ts-boilerplate`
2. Install Dependencies
From the root of the project directory, run `yarn` if you have yarn installed globally.
--- or ---
`npm install`.
3. Clear out the code you don't want.
Run `npm run clean` to get rid of the docs package and to reset the codebase to the bare minimum (note: we are still working on this and this would be a great place to submit an improvement).
4. Start the Development Server
Run `npm run start` then browse http://localhost:1337 to see your running app.
## What is Feature First?
In many projects and frameworks, files are organized by their file type. For example, you will find tests in a test folder, reducers in a reducers folder and so on and so forth. This framework takes a different approach.
We encourage modularization / encapsulation of features by asking that you organize your files by feature, rather than file type. When you begin working on your next container, instead of having to root through multiple files to find all of the files that the container depends on, you can expect to find these files in one place: with the feature that they represent. This helps to decouple the features in your app, lending itself well to code reuse, scalability and modularization.
On top of that, we also ask that you think about separation of concern as you are building your features. You will see in the example application in this repository that a feature is built up of a dozen or so small, single purpose modules. By following these simple patterns, you will set yourself up for maximum scalability. Give it a try! We think you will enjoy it.
## Lerna
We are hard at work converting the structure of this boilerplate to use Lerna. Stay tuned for more information!
## Styled Components
This project embraces [styled-components](https://github.com/styled-components/styled-components) as it's a fantastic way to style your React components.
Check the components directory for examples.
## Full Stack
This boilerplate contains setup to quickly get started with a full stack application. Within the [`src/`](https://github.com/scalable-react/scalable-react-typescript-boilerplate/tree/master/src) directory, you will find a server and a client folder.
## File Tree Structure
### Client File Structure
```
src/client
├── apolloClient.ts
├── components
│ ├── Box
│ │ ├── __tests__
│ │ │ ├── __mocks__
│ │ │ │ └── boxMocks.mock.ts
│ │ │ ├── __snapshots__
│ │ │ │ └── index.test.tsx.snap
│ │ │ └── index.test.tsx
│ │ ├── index.tsx
│ │ ├── maps.ts
│ │ ├── styleUtils.ts
│ │ ├── styles.ts
│ │ └── types.ts
│ ├── Section
│ │ ├── __tests__
│ │ │ ├── __mocks__
│ │ │ │ └── sectionMocks.mock.ts
│ │ │ ├── __snapshots__
│ │ │ │ └── index.test.tsx.snap
│ │ │ └── index.test.tsx
│ │ ├── index.tsx
│ │ └── styles.ts
│ └── index.ts
├── containers
│ ├── Blog
│ │ ├── index.tsx
│ │ ├── posts.graphql.ts
│ │ └── styles.ts
│ ├── BlogPost
│ │ ├── comments.graphql.ts
│ │ ├── index.tsx
│ │ ├── post.graphql.ts
│ │ └── styles.ts
│ └── index.ts
├── index.tsx
├── reducers.ts
├── routes.tsx
├── store.tsx
└── styles
└── index.css
```
### Server file structure
```
src/server
├── db
│ ├── index.ts
│ ├── models
│ │ ├── comment.ts
│ │ └── post.ts
│ └── utils
│ └── uuid.ts
├── graph
│ ├── index.ts
│ ├── mutations
│ │ ├── comment
│ │ │ ├── createComment.ts
│ │ │ └── index.ts
│ │ └── index.ts
│ ├── queries
│ │ ├── comment
│ │ │ ├── comment.ts
│ │ │ ├── comments.ts
│ │ │ └── index.ts
│ │ ├── index.ts
│ │ └── post
│ │ ├── index.ts
│ │ ├── post.ts
│ │ └── posts.ts
│ ├── schema.json
│ └── types
│ ├── comment
│ │ ├── comment.ts
│ │ └── commentInput.ts
│ ├── index.ts
│ └── post
│ ├── post.ts
│ └── postInput.ts
├── graphqlEntry.ts
└── index.tsx
```
## Apollo GraphQL
Recently, we've added support for Apollo and GraphQL both server and client side. The starter code in this repo demonstrates how to setup your GraphQL server. The `/blog` route will show you a very simple example of loading data via Apollo Graphql.
## UI Components
#### Build your next UIKit with this library!
Included in this project are a few primitive components that you can use to bootstrap your next project, or as a reference for building a UIKit.
- [Box](https://github.com/scalable-react/scalable-react-typescript-boilerplate/blob/master/src/client/components/Box/index.tsx)
- Flex Box component! Whoot!
- [Section](https://github.com/scalable-react/scalable-react-typescript-boilerplate/blob/master/src/client/components/Section/index.tsx)
- A section component. Extends the Box component giving flex-box properties.
- [Anchor](https://github.com/scalable-react/scalable-react-typescript-boilerplate/blob/master/src/client/components/Anchor/index.tsx)
- [Article](https://github.com/scalable-react/scalable-react-typescript-boilerplate/blob/master/src/client/components/Article/index.tsx)
- [Button](https://github.com/scalable-react/scalable-react-typescript-boilerplate/blob/master/src/client/components/Button/index.tsx)
- [Footer](https://github.com/scalable-react/scalable-react-typescript-boilerplate/blob/master/src/client/components/Footer/index.tsx)
- [Heading](https://github.com/scalable-react/scalable-react-typescript-boilerplate/blob/master/src/client/components/Heading/index.tsx)
- [Headline](https://github.com/scalable-react/scalable-react-typescript-boilerplate/blob/master/src/client/components/Headline/index.tsx)
- [Hero](https://github.com/scalable-react/scalable-react-typescript-boilerplate/blob/master/src/client/components/Hero/index.tsx)
- [Image](https://github.com/scalable-react/scalable-react-typescript-boilerplate/blob/master/src/client/components/Image/index.tsx)
- [Markdown](https://github.com/scalable-react/scalable-react-typescript-boilerplate/blob/master/src/client/components/Markdown/index.tsx)
- [NavBar](https://github.com/scalable-react/scalable-react-typescript-boilerplate/blob/master/src/client/components/NavBar/index.tsx)
- [Paragraph](https://github.com/scalable-react/scalable-react-typescript-boilerplate/blob/master/src/client/components/Paragraph/index.tsx)
- [SvgIcon](https://github.com/scalable-react/scalable-react-typescript-boilerplate/blob/master/src/client/components/SvgIcon/index.tsx)
- And more!
## React Storybook
We've included react storybook to make it easy for you to test your ui kit components.
Run `npm run storybook` and navigate to `http://localhost:9001` to see your stories.
You can add more stories as you are building out your components within the `./config/.storybook/stories` folder.
Simply [write a story](https://getstorybook.io/docs/react-storybook/basics/writing-stories) and export it in the `stories/index.js` file. Checkout the [React Storybook](https://getstorybook.io/) docs for more info!
Note: the components are currently being served from the `build` directory, so please make sure you have compiled (`npm run compile`) the app before running.
## Generators
We've included some generators so that you can easily scaffold out components & containers from the command line.
To use the generators, run `npm run generator` and select the options you want to use. The generators will create your component or container and their accompanying imports / exports.
## Server Rendering
We have included setup to get you server-rendering out of the box. Included in the setup is an [Express server](https://github.com/RyanCCollins/scalable-react-ts-boilerplate/blob/master/src/server.tsx) that will server render. Note that the server-rendering will not work with the TypeScript source code, so you must compile the project into the Build directory first. Also, you must copy any other assets (images, markdown, etc.) into the build folder.
## Testing
Included is a test framework for all of your React testing needs. We are using Jest to run the test suite and generate snapshots, plus Enzyme for component introspection.
Tests should be collocated within the component / container they represent. Test files should be named `index.test.tsx` and mocks must be named `myMock.mock.ts`.
Please reference the [`Box`](https://github.com/RyanCCollins/scalable-react-typescript-boilerplate/tree/master/src/client/components/Box) and [`Section`](https://github.com/RyanCCollins/scalable-react-typescript-boilerplate/tree/master/src/client/components/Section) components for example tests. More will be added at a later time.
Note that the test are not compiled by TypeScript, that way there is no code duplication and you can use static types in your tests.
P.S. If you are looking to contribute, this would be a great first contribution!
## Deployment
<!-- HTML snippet -->
<a href="https://app.netlify.com/start/deploy?repository=https://github.com/RyanCCollins/scalable-react-ts-boilerplate">
<img src="https://www.netlify.com/img/deploy/button.svg" title="Deploy to Netlify">
</a>
The [documentation website](https://scalable-react-ts-boilerplate.herokuapp.com/) built for this boilerplate is deployed to Heroku. Included is a Procfile that will run the server. The deployment is automated completely. After the install script, the deploy script will run on the server in order to compile the bundle and prepare the build folder for server-rendering.
## Scripts
- `npm run setup:yarn`
- Install the package dependencies via yarn (recomended)
- `npm install`
- Install dependencies (the ol' fashioned way)
- `npm run start`
- Start the dev server
- `npm run build`
- Build the project
- `npm run deploy`
- Create a production bundle for deployment
- `npm run serve`
- Serve the production bundle on port 1337
- `npm run test`
- Run the test suite
- `npm run test:watch`
- Run the test suite in watch mode
- `npm run test:update`
- Update the failing snapshot tests
- `npm run storybook`
- Run the storybook server
## Resources
- [JavaScript Code Quality with Free Tools](https://dev-blog.apollodata.com/javascript-code-quality-with-free-tools-9a6d80e29f2d#.1unvvh8vw)
- [Working with React & TypeScript](http://blog.wolksoftware.com/working-with-react-and-typescript)
- [Setting up a New React / TypeScript Project](http://blog.tomduncalf.com/posts/setting-up-typescript-and-react/)
- [Feature First Architecture](https://medium.com/front-end-hacking/the-secret-to-organization-in-functional-programming-913484e85fc9#.8nerdsqhd)
## Contributing
See here for our [contribution guide](https://github.com/RyanCCollins/scalable-react-typescript-boilerplate/blob/master/CONTRIBUTING.md). We are on slack, please go [here for an invite](https://scalable-react-slack.herokuapp.com/)! We'd love to hear from you!
## License
See here for the [license](https://github.com/RyanCCollins/scalable-react-typescript-boilerplate/blob/master/LICENSE).
## Roadmap
### v1.0.2
- [X] Add CI
- [x] Introduce an async redux workflow
- Redux logic
- [x] Integrate storybook
- [x] Standardize the tslint configuration
- [x] Add more reusable modules, ala box / section
- [x] Refactor reusable modules into uikit
- [x] Remove requires and use es6 imports for all libs
- [x] Add a no any rule and update source to use it
- [ ] Migrate to a multi-module pattern using lerna (in progress)
## Troubleshooting
Make sure to use the right version of node. You can reference the version in the `.nvmrc` file. For help installing and using NVM, please refer to this [gist](https://gist.github.com/RyanCCollins/1a5686ff9dd51b72eb2d4dc70aa6c1f4).
================================================
FILE: config/.storybook/addons.js
================================================
// To get default addons (actions and links)
import '@kadira/storybook/addons';
// To add the knobs addon
import '@kadira/storybook-addon-knobs/register'
================================================
FILE: config/.storybook/config.js
================================================
import { configure, setAddon } from '@kadira/storybook';
import infoAddon from '@kadira/react-storybook-addon-info';
import withPropsCombinations, { setDefaults } from 'react-storybook-addon-props-combinations'
setAddon(withPropsCombinations)
setAddon(infoAddon);
function loadStories() {
require('./stories/index.js');
}
configure(loadStories, module);
================================================
FILE: config/.storybook/stories/index.js
================================================
================================================
FILE: config/.storybook/webpack.config.js
================================================
const path = require('path');
const config = require('../../webpack.config.server.js');
const ROOT_PATH = path.resolve(__dirname, '../../');
module.exports = {
resolve: {
extensions: ['', '.js', '.jsx', '.json', '.css'],
alias: config.resolve.alias,
},
module: {
loaders: [
{ test: /\.css$/, loaders: ['style-loader', 'css-loader'] },
]
}
}
================================================
FILE: config/generators/cli.js
================================================
const componentGenerator = require('./component/index.js');
const SafeString = require('./utils/safeString').SafeString;
const containerGenerator = require('./container/index.js');
module.exports = (plop) => {
plop.setGenerator('component', componentGenerator);
plop.setGenerator('feature', containerGenerator);
plop.addHelper('uppercase', (text) => {
return text.toUpperCase();
});
plop.addHelper('getPath', (p, itemName) => {
const pathParts = p.split('/');
const index = pathParts.indexOf(itemName);
const newPath = pathParts.slice(index + 1, pathParts.length);
return newPath.length < 1 ? `./${newPath}` : `./${newPath.join('/')}/`;
});
plop.addHelper('createImports', (list) => {
const items = list.map((item) => `import ${item} from 'grommet/components/${item}';`).join('\n');
return new SafeString(items);
});
plop.addHelper('curly', (object, open) => (open ? '{' : '}'));
};
================================================
FILE: config/generators/component/es6class.tsx.hbs
================================================
import * as React from 'react';
import Component from './styles';
export interface Props extends React.HTMLProps<typeof {{ properCase name }}> {
children: JSX.Element;
}
class {{ properCase name }} extends React.Component<Props, undefined> {
public render() {
const {
children,
} = this.props;
return (
<Component>
{children}
</Component>
);
}
}
export default {{ properCase name }};
================================================
FILE: config/generators/component/export.ts.hbs
================================================
$1
{{ properCase name }},
================================================
FILE: config/generators/component/import.ts.hbs
================================================
$1
import {{ properCase name }} from '{{ getPath path 'components' }}{{ properCase name }}';
================================================
FILE: config/generators/component/index.js
================================================
const path = require('path');
const { trimTemplateFile } = require('../utils/');
module.exports = {
description: 'Generate a component',
prompts: [
{
type: 'input',
name: 'name',
message: 'What is the name of the component?',
default: 'Post',
validate: (value) => {
if ((/.+/).test(value)) {
return true;
}
return 'The name is required.';
}
},
{
type: 'input',
name: 'path',
message: 'What directory would you like your component in? (relative)',
default: './src/client/components',
validate: (value) => {
return true;
}
},
{
type: 'list',
name: 'type',
message: 'Select the type of component',
default: 'Stateless Function',
choices: () => ['ES6 Class', 'Stateless Function']
},
],
actions: (data) => {
const componentPath = path.resolve(process.cwd(), `${data.path}/{{properCase name}}/`);
const rootPath = path.resolve(process.cwd(), `./src/client/components/index.ts`);
const actions = [{
type: 'add',
path: `${componentPath}/index.tsx`,
templateFile: data.type === 'ES6 Class' ?
'./component/es6class.tsx.hbs' : './component/stateless.tsx.hbs',
abortOnFail: true
}, {
type: 'add',
path: `${componentPath}/types.ts`,
templateFile: './component/types.ts.hbs',
abortOnFail: true
}, {
type: 'add',
path: `${componentPath}/styles.ts`,
templateFile: './component/styles.ts.hbs',
abortOnFail: true
}, {
type: 'modify',
path: rootPath,
pattern: /(\/\* GENERATOR-IMPORT \*\/)/g,
template: trimTemplateFile('./config/generators/component/import.ts.hbs'),
abortOnFail: false
}, {
type: 'modify',
path: rootPath,
pattern: /(\/\* GENERATOR-EXPORT \*\/)/g,
template: trimTemplateFile('./config/generators/component/export.ts.hbs'),
abortOnFail: false
}];
return actions;
}
};
================================================
FILE: config/generators/component/stateless.tsx.hbs
================================================
import * as React from 'react';
import Component from './styles';
export interface Props extends React.HTMLProps<typeof {{ properCase name }}> {
children: JSX.Element;
}
export default function {{ properCase name }}({
children,
}: Props): JSX.Element {
return (
<Component>
{children}
</Component>
);
};
================================================
FILE: config/generators/component/styles.ts.hbs
================================================
import styled from 'styled-components';
export default styled.div`
height: 100px;
width: 200px;
`;
================================================
FILE: config/generators/component/types.ts.hbs
================================================
export { Props } from './';
================================================
FILE: config/generators/container/actionCreators.js.hbs
================================================
import * as T from './constants';
import {
LoadInitiationAction,
LoadSuccessAction,
LoadFailureAction,
LoadCancelAction,
} from './actions';
import { ErrorType } from './types';
export const loadInitiation = (): LoadInitiationAction => ({
type: T.LOAD_INITIATION,
});
export const loadSuccess = (data: string): LoadSuccessAction => ({
type: T.LOAD_SUCCESS,
payload: data,
});
export const loadFailure = (error: ErrorType): LoadFailureAction => ({
type: T.LOAD_FAILURE,
payload: error,
});
export const loadCancel = (): LoadCancelAction => ({
type: T.LOAD_CANCEL,
});
export const actionCreators = {
loadInitiation,
loadSuccess,
loadFailure,
loadCancel,
};
export default actionCreators;
================================================
FILE: config/generators/container/actions.js.hbs
================================================
import { PayloadAction } from 'root/types';
import { ErrorType } from './types';
import * as T from './constants';
export interface LoadInitiationAction extends PayloadAction<undefined> {
type: T.LOAD_INITIATION_TYPE;
}
export interface LoadSuccessAction extends PayloadAction<string> {
type: T.LOAD_SUCCESS_TYPE;
payload: string;
}
export interface LoadFailureAction extends PayloadAction<ErrorType> {
type: T.LOAD_FAILURE_TYPE;
payload: ErrorType;
}
export interface LoadCancelAction extends PayloadAction<undefined> {
type: T.LOAD_CANCEL_TYPE;
}
export type Action = LoadInitiationAction | LoadSuccessAction | LoadFailureAction | LoadCancelAction;
================================================
FILE: config/generators/container/constants.js.hbs
================================================
export type LOAD_INITIATION_TYPE = '{{ uppercase name }}/LOAD_INITIATION';
export const LOAD_INITIATION: LOAD_INITIATION_TYPE = '{{ uppercase name }}/LOAD_INITIATION';
export type LOAD_SUCCESS_TYPE = '{{ uppercase name }}/LOAD_SUCCESS';
export const LOAD_SUCCESS: LOAD_SUCCESS_TYPE = '{{ uppercase name }}/LOAD_SUCCESS';
export type LOAD_FAILURE_TYPE = '{{ uppercase name }}/LOAD_FAILURE';
export const LOAD_FAILURE: LOAD_FAILURE_TYPE = '{{ uppercase name }}/LOAD_FAILURE';
export type LOAD_CANCEL_TYPE = '{{ uppercase name }}/LOAD_CANCEL';
export const LOAD_CANCEL: LOAD_CANCEL_TYPE = '{{ uppercase name }}/LOAD_CANCEL';
export type ActionType = LOAD_INITIATION_TYPE | LOAD_SUCCESS_TYPE | LOAD_FAILURE_TYPE | LOAD_CANCEL_TYPE;
================================================
FILE: config/generators/container/export.js.hbs
================================================
$1
{{ properCase name }},
================================================
FILE: config/generators/container/import.js.hbs
================================================
$1
import {{ properCase name }} from '{{ getPath path 'features' }}{{ properCase name }}';
================================================
FILE: config/generators/container/index.js
================================================
const path = require('path');
const { trimTemplateFile } = require('../utils/');
module.exports = {
description: 'Add a feature',
prompts: [
{
type: 'input',
name: 'name',
message: 'What should it be called?',
default: 'Dashboard',
validate: value => {
if ((/.+/).test(value)) {
return true;
}
return 'The name is required';
}
},
{
type: 'input',
name: 'path',
message: 'What directory would you like your container in? (relative)',
default: './src/client/features',
validate: (value) => {
return true;
}
},
{
type: 'confirm',
name: 'wantActionsAndReducer',
default: true,
message: 'Do you want actions/constants/reducer for this feature?'
},
{
type: 'confirm',
name: 'wantSelectors',
default: true,
message: 'Do you want to use reselect?'
}
],
actions: (data) => {
const containerPath = path.resolve(process.cwd(), `${data.path}/{{properCase name}}/`);
const rootPath = path.resolve(process.cwd(), `./src/client/features/index.ts`);
const reducersPath = path.resolve(process.cwd(), './src/client/reducers.ts');
const typesPath = path.resolve(process.cwd(), './src/client/types.ts');
const statePath = path.resolve(process.cwd(), './src/client/state.ts');
const actions = [
{
type: 'add',
path: `${containerPath}/index.tsx`,
templateFile: './container/index.js.hbs',
abortOnFail: true
},
{
type: 'add',
path: `${containerPath}/presentation.tsx`,
templateFile: './container/presentation.js.hbs',
abortOnFail: true
},
{
type: 'modify',
path: rootPath,
pattern: /(\/\* GENERATOR-IMPORT \*\/)/g,
template: trimTemplateFile('./config/generators/container/import.js.hbs'),
abortOnFail: false
},
{
type: 'modify',
path: rootPath,
pattern: /(\/\* GENERATOR-EXPORT \*\/)/g,
template: trimTemplateFile('./config/generators/container/export.js.hbs'),
abortOnFail: false
},
{
type: 'modify',
path: typesPath,
pattern: /(\/\* GENERATOR-IMPORT \*\/)/g,
template: trimTemplateFile('./config/generators/container/types.import.ts.hbs'),
abortOnFail: false
},
{
type: 'modify',
path: typesPath,
pattern: /(\/\* GENERATOR-EXPORT \*\/)/g,
template: trimTemplateFile('./config/generators/container/types.export.ts.hbs'),
abortOnFail: false
}
];
actions.push({
type: 'add',
path: `${containerPath}/styles.ts`,
templateFile: './container/styles.js.hbs',
abortOnFail: true
});
actions.push( {
type: 'add',
path: `${containerPath}/types.ts`,
templateFile: './container/types.ts.hbs',
abortOnFail: true
});
if (data.wantSelectors) {
actions.push({
type: 'add',
path: `${containerPath}/selectors.ts`,
templateFile: './container/selectors.js.hbs',
abortOnFail: true
});
}
// If they want actions and a reducer, generate actions.js, constants.js,
// reducer.js and the corresponding tests for actions and the reducer
if (data.wantActionsAndReducer) {
// Actions
actions.push({
type: 'add',
path: `${containerPath}/actionCreators.ts`,
templateFile: './container/actionCreators.js.hbs',
abortOnFail: true
});
actions.push({
type: 'add',
path: `${containerPath}/state.ts`,
templateFile: './container/state.js.hbs',
abortOnFail: true
});
actions.push({
type: 'add',
path: `${containerPath}/actions.ts`,
templateFile: './container/actions.js.hbs',
abortOnFail: true
});
// Constants
actions.push({
type: 'add',
path: `${containerPath}/constants.ts`,
templateFile: './container/constants.js.hbs',
abortOnFail: true
});
// Reducer
actions.push({
type: 'add',
path: `${containerPath}/reducer.ts`,
templateFile: './container/reducer.js.hbs',
abortOnFail: true
});
actions.push({
type: 'modify',
path: reducersPath,
pattern: /(\/\* GENERATOR-IMPORT-REDUCER \*\/)/g,
template: trimTemplateFile('./config/generators/container/reducer.import.js.hbs'),
abortOnFail: false
});
actions.push({
type: 'modify',
path: reducersPath,
pattern: /(\/\* GENERATOR-EXPORT-REDUCER \*\/)/g,
template: trimTemplateFile('./config/generators/container/reducer.export.js.hbs'),
abortOnFail: false
});
actions.push({
type: 'modify',
path: statePath,
pattern: /(\/\* GENERATOR-IMPORT-STATE \*\/)/g,
template: trimTemplateFile('./config/generators/container/state.import.js.hbs'),
abortOnFail: false
});
actions.push({
type: 'modify',
path: statePath,
pattern: /(\/\* GENERATOR-EXPORT-STATE \*\/)/g,
template: trimTemplateFile('./config/generators/container/reducer.export-state.js.hbs'),
abortOnFail: false
});
actions.push({
type: 'modify',
path: statePath,
pattern: /(\/\* GENERATOR-EXPORT-STATE-TYPE \*\/)/g,
template: trimTemplateFile('./config/generators/container/state-type.js.hbs'),
abortOnFail: false
});
}
return actions;
}
};
================================================
FILE: config/generators/container/index.js.hbs
================================================
import * as React from 'react';
{{#if wantActionsAndReducer}}
import { connect } from 'react-redux';
import { bindActionCreators, Dispatch } from 'redux';
import { State as GlobalState } from 'root/state';
import { Action, ActionMap, ErrorType } from './types';
import actionCreators from './actionCreators';
{{/if}}
{{#if wantSelectors}}
import * as selectors from './selectors';
{{/if}}
import Presentation from './presentation';
{{#if wantActionsAndReducer}}
{{#if wantSelectors}}
type MapStateToProps = (state: GlobalState) => StateProps;
const mapStateToProps: MapStateToProps = (state) => ({
isLoading: selectors.selectIsLoading(state),
error: selectors.selectError(state),
data: selectors.selectData(state),
});
{{else}}
type MapStateToProps = (state: GlobalState): StateProps;
const mapStateToProps: MapStateToProps = (state) => ({
isLoading: state.{{ camelCase name }}.isLoading,
error: state.{{ camelCase name }}.error,
data: state.{{ camelCase name }}.data,
});
{{/if}}
type MapDispatchToProps = (dispatch: Dispatch<Action>) => DispatchProps;
const mapDispatchToProps: MapDispatchToProps = (dispatch) => ({
actions: bindActionCreators(
actionCreators,
dispatch,
),
});
export interface DispatchProps {
actions: ActionMap;
}
export interface StateProps {
isLoading: boolean;
error?: ErrorType;
data?: string;
}
export type Props = StateProps & DispatchProps;
class {{ properCase name }} extends React.Component<Props, undefined> {
{{else}}
export interface Props {
}
class {{ properCase name }} extends React.Component<Props, undefined> {
{{/if}}
public render() {
return (
<Presentation {...this.props} />
);
}
}
{{#if wantActionsAndReducer}}
export default connect(
mapStateToProps,
mapDispatchToProps,
)({{ properCase name }});
{{else}}
export default {{ properCase name }};
{{/if}}
================================================
FILE: config/generators/container/presentation.js.hbs
================================================
import * as React from 'react';
{{#if wantActionsAndReducer}}
import { StateProps } from './types';
{{else}}
import { Props as ParentProps } from './types';
{{/if}}
import { Heading, Section } from './styles';
{{#if wantActionsAndReducer}}
export default class Presentation extends React.Component<StateProps, undefined> {
{{else}}
export interface Props extends ParentProps {
// own props
}
export default class Presentation extends React.Component<Props, undefined> {
{{/if}}
public render() {
{{#if wantActionsAndReducer}}
const {
isLoading,
error,
data,
} = this.props;
{{/if}}
return (
<Section>
<Heading>
Best container ever!
</Heading>
</Section>
);
}
}
================================================
FILE: config/generators/container/reducer.export-state.js.hbs
================================================
$1
{{ camelCase name }}: {{ camelCase name }}State,
================================================
FILE: config/generators/container/reducer.export.js.hbs
================================================
$1
{{ camelCase name }},
================================================
FILE: config/generators/container/reducer.import.js.hbs
================================================
$1
import {{ camelCase name }} from './features/{{ properCase name }}/reducer';
================================================
FILE: config/generators/container/reducer.js.hbs
================================================
import * as T from './constants';
import initialState from './state';
import {
Action,
State,
} from './types';
const reducer = (
state: State = initialState,
action: Action,
): State => {
switch (action.type) {
case T.LOAD_INITIATION:
return Object.assign({}, state, {
isLoading: true,
});
case T.LOAD_SUCCESS:
return Object.assign({}, state, {
isLoading: false,
data: action.payload,
});
case T.LOAD_FAILURE:
return Object.assign({}, state, {
isLoading: false,
error: action.payload,
});
default:
return state;
}
};
export default reducer;
================================================
FILE: config/generators/container/selectors.js.hbs
================================================
import { State as GlobalState } from '../../state';
import { State, ErrorType } from './types';
import { createSelector, Selector } from 'reselect';
export const select{{ properCase name }} = () => (state: GlobalState): State => state.{{ camelCase name }};
export type SelectIsLoading = Selector<GlobalState, boolean>;
export const selectIsLoading: SelectIsLoading = createSelector(
select{{ properCase name }}(),
({{ camelCase name }}) => {{ camelCase name }}.isLoading,
);
export type SelectError = Selector<GlobalState, ErrorType>;
export const selectError: SelectError = createSelector(
select{{ properCase name }}(),
({{ camelCase name }}) => {{ camelCase name }}.error,
);
export type SelectData = Selector<GlobalState, string>;
export const selectData: SelectData = createSelector(
select{{ properCase name }}(),
({{ camelCase name }}) => {{ camelCase name }}.data,
);
================================================
FILE: config/generators/container/state-type.js.hbs
================================================
$1
{{ camelCase name }}: {{ properCase name }}State;
================================================
FILE: config/generators/container/state.import.js.hbs
================================================
$1
import { initialState as {{ camelCase name }}State, State as {{ properCase name }}State } from './features/{{ properCase name }}/state';
================================================
FILE: config/generators/container/state.js.hbs
================================================
import { ErrorType } from './types';
export interface State {
isLoading: boolean;
error?: ErrorType;
data?: string;
}
export const initialState: State = {
isLoading: false,
error: null,
data: null,
};
export default initialState;
================================================
FILE: config/generators/container/styles.js.hbs
================================================
import styled from 'styled-components';
export const Section = styled.section`
padding: 60px;
background-color: #f5f5f5;
min-height: calc(100vh - 50px);
`;
export const Heading = styled.h1`
text-align: center;
`;
================================================
FILE: config/generators/container/types.export.ts.hbs
================================================
$1
{{ properCase name }}Types,
================================================
FILE: config/generators/container/types.import.ts.hbs
================================================
$1
import * as {{ properCase name }}Types from './features/{{ properCase name }}/types';
================================================
FILE: config/generators/container/types.ts.hbs
================================================
{{#if wantActionsAndReducer}}
import { ActionCreatorsMapObject } from 'redux';
import {
LoadInitiationAction,
LoadSuccessAction,
LoadFailureAction,
LoadCancelAction,
} from './actions';
export { State } from './state';
export { Props, StateProps, DispatchProps } from './';
export { ActionType } from './constants';
export { Action } from './actions';
export interface ErrorType { message: string }
export interface ActionMap extends ActionCreatorsMapObject {
loadInitiation: () => LoadInitiationAction;
loadSuccess: (data: string) => LoadSuccessAction;
loadFailure: (error: ErrorType) => LoadFailureAction;
loadCancel: () => LoadCancelAction;
}
{{else}}
export { Props } from './';
{{/if}}
================================================
FILE: config/generators/utils/index.js
================================================
const fs = require('fs');
const trimTemplateFile = (template) => {
// Loads the template file and trims the whitespace and then returns the content as a string.
return fs.readFileSync(template, 'utf8').replace(/\s*$/, '');
};
module.exports = {
trimTemplateFile
};
================================================
FILE: config/generators/utils/safeString.js
================================================
function SafeString(string) {
this.string = string;
}
SafeString.prototype.toString = SafeString.prototype.toHTML = function() {
return '' + this.string;
};
module.exports = {
SafeString
};
================================================
FILE: config/ignoreAssets.js
================================================
/* eslint-disable */
(function() {
require.extensions['.scss'] = () => {
return;
};
require.extensions['.css'] = () => {
return;
};
require.extensions['.png'] = () => {
return;
};
require.extensions['.jpg'] = () => {
return;
};
require.extensions['.md'] = () => {
return;
};
})();
================================================
FILE: config/scripts/clean.js
================================================
require('shelljs/global');
rm('-fr', './packages/docs');
================================================
FILE: config/testing/__mocks__/fileMock.js
================================================
module.exports = 'test-file-stub';
================================================
FILE: config/testing/__mocks__/styleMock.js
================================================
module.exports = {};
================================================
FILE: config/testing/preprocessor.js
================================================
'use strict';
const babel = require('babel-core');
const tsc = require('typescript');
const crypto = require('crypto');
const fs = require('fs');
const jestPreset = require('babel-preset-jest');
const es2015Preset = require('babel-preset-es2015');
const path = require('path');
const BABELRC_FILENAME = '.babelrc';
const cache = Object.create(null);
const tsconfig = require('../../tsconfig.json');
const getBabelRC = (filename, {useCache}) => {
const paths = [];
let directory = filename;
while (directory !== (directory = path.dirname(directory))) {
if (useCache && cache[directory]) {
break;
}
paths.push(directory);
const configFilePath = path.join(directory, BABELRC_FILENAME);
if (fs.existsSync(configFilePath)) {
cache[directory] = fs.readFileSync(configFilePath, 'utf8');
break;
}
}
paths.forEach(directoryPath => {
cache[directoryPath] = cache[directory];
});
return cache[directory] || '';
};
const createTransformer = (options) => {
options = Object.assign({}, options, {
// auxiliaryCommentBefore: ' istanbul ignore next ',
presets: ((options && options.presets) || []).concat([jestPreset]),
retainLines: true,
});
delete options.cacheDirectory;
options.presets = options.presets.concat([es2015Preset]);
return {
canInstrument: true,
getCacheKey(
fileData,
filename,
configString,
{instrument, watch}
) {
return crypto.createHash('md5')
.update(fileData)
.update(configString)
// Don't use the in-memory cache in watch mode because the .babelrc
// file may be modified.
.update(getBabelRC(filename, {useCache: !watch}))
.update(instrument ? 'instrument' : '')
.digest('hex');
},
process(
src,
filename,
config,
transformOptions
) {
let plugins = options.plugins || [];
if (transformOptions && transformOptions.instrument) {
// Copied from jest-runtime transform.js
plugins = plugins.concat([
[
require('babel-plugin-istanbul').default,
{
// files outside `cwd` will not be instrumented
cwd: config.rootDir,
exclude: [],
},
],
]);
}
// console.log(transformOptions);
// console.log(JSON.stringify(options));
// console.log('src', src);
// ts compile
const diag = [];
const tsOutput = tsc.transpileModule(src, {diagnostics: diag, filename, compilerOptions: tsconfig.compilerOptions, reportDiagnostics: true});
// console.log(tsOutput.outputText)
if (babel.util.canCompile(filename) || true) {
const babelOutput = babel.transform(
tsOutput.outputText,
Object.assign({}, options, {filename, plugins})
);
// console.log('babelOutput', babelOutput.code);
return babelOutput.code;
}
// return src;
},
};
};
module.exports = createTransformer();
================================================
FILE: config/testing/templates/_index.prod.html
================================================
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv=X-UA-Compatible content="IE=edge">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>React TS Starter</title>
<link href="https://fonts.googleapis.com/css?family=Hind|Montserrat|Roboto+Mono" rel="stylesheet">
</head>
<body>
<div id="app"></div>
</body>
</html>
================================================
FILE: config/types/require.d.ts
================================================
declare var require: {
(path: string): any;
<T>(path: string): T;
(paths: string[], callback: (...modules: any[]) => void): void;
ensure: (paths: string[], callback: (require: <T>(path: string) => T) => void) => void;
};
================================================
FILE: devServer.js
================================================
var path = require('path');
var webpack = require('webpack');
var express = require('express');
var devMiddleware = require('webpack-dev-middleware');
var hotMiddleware = require('webpack-hot-middleware');
var config = require('./webpack.config');
var app = express();
var compiler = webpack(config);
app.use(devMiddleware(compiler, {
publicPath: config.output.publicPath,
historyApiFallback: true,
}));
app.use(hotMiddleware(compiler));
app.get('*', function (req, res) {
res.sendFile(path.join(__dirname, 'index.html'));
});
app.listen(1337, function (err) {
if (err) {
return console.error(err);
}
console.log('Listening at http://localhost:1337/');
});
================================================
FILE: index.html
================================================
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>React TS Starter</title>
<link href="https://fonts.googleapis.com/css?family=Hind|Montserrat|Roboto+Mono" rel="stylesheet">
</head>
<body>
<div id="app"></div>
<script src="/app.js"></script>
</body>
</html>
================================================
FILE: lerna.json
================================================
{
"lerna": "2.0.0-beta.38",
"packages": [
"packages/*"
],
"version": "independent"
}
================================================
FILE: netlify.toml
================================================
[build]
command = "npm run deploy"
publish = "build/public"
================================================
FILE: package.json
================================================
{
"name": "scalable-react-typescript-boilerplate",
"version": "1.0.1",
"description": "React + TypeScript boilerplate",
"main": "index.js",
"author": "RyanCCollins",
"license": "MIT",
"engines": {
"node": "6.9.5",
"npm": "3.10.8"
},
"jest": {
"moduleFileExtensions": [
"ts",
"tsx",
"js"
],
"moduleNameMapper": {
"\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$": "<rootDir>/config/testing/__mocks__/fileMock.js",
"\\.(css|less)$": "<rootDir>/config/testing/__mocks__/styleMock.js"
},
"testPathIgnorePatterns": [
"<rootDir>/(build|docs|node_modules)/",
"/__mocks__/"
],
"transform": {
".*": "<rootDir>/config/testing/preprocessor.js"
},
"testRegex": "(/__tests__/.*|\\.(test|spec))\\.(ts|tsx|js)$"
},
"scripts": {
"build": "webpack --config ./webpack.config.js",
"start": "node devServer.js",
"predeploy": "rimraf build/public/*.*",
"deploy": "cross-env NODE_ENV=production ./node_modules/.bin/webpack --config ./webpack.config.prod.js",
"postdeploy": "npm run compile",
"compile": "./node_modules/.bin/tsc",
"setup:yarn": "yarn",
"preserve": "npm run compile",
"lint": "tslint \"packages/**/*.ts{,x}\" && tslint \"src/**/*.ts{,x}\"",
"serve": "cross-env NODE_ENV=server node server.js",
"postinstall": "npm run deploy",
"generator": "plop --plopfile ./config/generators/cli.js",
"test": "cross-env NODE_ENV=test jest",
"test:watch": "npm run test -- --watch",
"test:update": "npm run test -- --u",
"storybook": "start-storybook -p 9001 -c ./config/.storybook",
"clean": "shjs ./config/scripts/clean.js"
},
"dependencies": {
"@kadira/react-storybook-addon-info": "^3.3.0",
"@kadira/storybook": "^2.35.3",
"@kadira/storybook-addon-knobs": "^1.7.1",
"@types/body-parser": "^0.0.34",
"@types/compression": "latest",
"@types/express": "latest",
"@types/graphql": "latest",
"@types/isomorphic-fetch": "^0.0.33",
"@types/mongoose": "^4.7.7",
"@types/morgan": "latest",
"@types/node": "^6.0.64",
"@types/react": "^15.0.14",
"@types/react-dom": "^0.14.23",
"@types/react-ga": "^1.4.7",
"@types/react-redux": "^4.4.35",
"@types/react-router": "^3.0.6",
"@types/react-router-redux": "^4.0.42",
"@types/reselect": "^2.0.27",
"@types/sinon": "^1.16.35",
"@types/webpack": "^2.2.11",
"apollo-client": "^0.10.1",
"apollo-codegen": "^0.10.8",
"autoprefixer": "^6.7.6",
"axios": "^0.15.3",
"babel-polyfill": "^6.23.0",
"body-parser": "^1.17.0",
"compression": "^1.6.2",
"cors": "^2.8.1",
"exports-loader": "^0.6.4",
"express": "^4.15.0",
"github-markdown-css": "^2.4.1",
"graphql": "^0.9.1",
"graphql-server-express": "^0.7.2",
"graphql-tag": "^1.3.1",
"html-webpack-plugin": "^2.28.0",
"imports-loader": "^0.7.1",
"isomorphic-fetch": "^2.2.1",
"json-loader": "^0.5.4",
"markdown-loader": "^2.0.0",
"mongoose": "^4.8.5",
"morgan": "^1.8.1",
"node-env-file": "^0.1.8",
"openui": "1.0.3",
"plop": "^1.7.4",
"precss": "^1.4.0",
"react": "^15.4.1",
"react-addons-test-utils": "^15.4.2",
"react-apollo": "^0.13.2",
"react-dom": "^15.4.1",
"react-ga": "^2.1.2",
"react-hot-loader": "3.0.0-beta.6",
"react-markdown": "^2.4.5",
"react-redux": "^5.0.3",
"react-router": "^3.0.2",
"react-router-redux": "^4.0.8",
"redux": "^3.6.0",
"redux-connect": "^5.0.0",
"redux-logic": "^0.11.7",
"redux-mock-provider": "^1.0.0",
"reselect": "^2.5.4",
"rxjs": "^5.2.0",
"serialize-javascript": "^1.3.0",
"shelljs": "^0.7.7",
"shortid": "^2.2.6",
"sinon": "^1.17.7",
"styled-components": "^1.4.4"
},
"devDependencies": {
"@types/enzyme": "^2.7.5",
"@types/jest": "^18.1.1",
"babel-core": "^6.23.1",
"babel-loader": "^6.3.2",
"babel-plugin-webpack-alias": "^2.1.2",
"babel-preset-es2015": "^6.18.0",
"babel-preset-jest": "^19.0.0",
"babel-preset-react": "^6.23.0",
"babel-preset-stage-0": "^6.16.0",
"cross-env": "^3.2.3",
"css-loader": "^0.26.2",
"enzyme": "^2.7.1",
"enzyme-to-json": "^1.5.0",
"extract-text-webpack-plugin": "^2.0.0",
"html-loader": "^0.4.5",
"jest": "^19.0.2",
"lerna": "2.0.0-beta.38",
"postcss-loader": "^1.3.3",
"react-storybook-addon-props-combinations": "^0.3.0",
"redux-logic-test": "^1.0.3",
"redux-mock-store": "^1.2.2",
"rimraf": "^2.6.1",
"style-loader": "^0.13.2",
"ts-jest": "^19.0.0",
"ts-loader": "^2.0.1",
"tslint": "^4.5.1",
"tslint-eslint-rules": "^3.5.1",
"tslint-loader": "^3.4.3",
"tslint-react": "^2.5.0",
"typescript": "^2.2.1",
"webpack": "^2.2.1",
"webpack-dev-middleware": "^1.10.1",
"webpack-hot-middleware": "^2.17.1",
"webpack-manifest-plugin": "^1.1.0"
}
}
================================================
FILE: packages/docs/.babelrc
================================================
{
"presets": ["es2015", "react", "stage-0"],
"env": {
"development": {
"plugins": [
"react-hot-loader/babel"
]
},
"test": {
"plugins": [
[
"babel-plugin-webpack-alias", {
"config": "./webpack.config.prod.js"
}
]
]
},
"server": {
"plugins": [
[
"babel-plugin-webpack-alias", {
"config": "./webpack.config.server.js"
}
]
]
}
}
}
================================================
FILE: packages/docs/config/generators/cli.js
================================================
const componentGenerator = require('./component/index.js');
const SafeString = require('./utils/safeString').SafeString;
const containerGenerator = require('./container/index.js');
module.exports = (plop) => {
plop.setGenerator('component', componentGenerator);
plop.setGenerator('container', containerGenerator);
plop.addHelper('uppercase', (text) => {
return text.toUpperCase();
});
plop.addHelper('getPath', (p, itemName) => {
const pathParts = p.split('/');
const index = pathParts.indexOf(itemName);
const newPath = pathParts.slice(index + 1, pathParts.length);
return newPath.length < 1 ? `./${newPath}` : `./${newPath.join('/')}/`;
});
plop.addHelper('createImports', (list) => {
const items = list.map((item) => `import ${item} from 'grommet/components/${item}';`).join('\n');
return new SafeString(items);
});
plop.addHelper('curly', (object, open) => (open ? '{' : '}'));
};
================================================
FILE: packages/docs/config/generators/component/es6class.tsx.hbs
================================================
import * as React from 'react';
import Component from './styles';
export interface Props extends React.HTMLProps<typeof {{ properCase name }}> {
children: JSX.Element;
}
class {{ properCase name }} extends React.Component<Props, undefined> {
public render() {
const {
children,
} = this.props;
return (
<Component>
{children}
</Component>
);
}
}
export default {{ properCase name }};
================================================
FILE: packages/docs/config/generators/component/export.ts.hbs
================================================
$1
{{ properCase name }},
================================================
FILE: packages/docs/config/generators/component/import.ts.hbs
================================================
$1
import {{ properCase name }} from '{{ getPath path 'components' }}{{ properCase name }}';
================================================
FILE: packages/docs/config/generators/component/index.js
================================================
const path = require('path');
const { trimTemplateFile } = require('../utils/');
module.exports = {
description: 'Generate a component',
prompts: [
{
type: 'input',
name: 'name',
message: 'What is the name of the component?',
default: 'Post',
validate: (value) => {
if ((/.+/).test(value)) {
return true;
}
return 'The name is required.';
}
},
{
type: 'input',
name: 'path',
message: 'What directory would you like your component in? (relative)',
default: './src/client/components',
validate: (value) => {
return true;
}
},
{
type: 'list',
name: 'type',
message: 'Select the type of component',
default: 'Stateless Function',
choices: () => ['ES6 Class', 'Stateless Function']
},
],
actions: (data) => {
const componentPath = path.resolve(process.cwd(), `${data.path}/{{properCase name}}/`);
const rootPath = path.resolve(process.cwd(), `./src/client/components/index.ts`);
const actions = [{
type: 'add',
path: `${componentPath}/index.tsx`,
templateFile: data.type === 'ES6 Class' ?
'./component/es6class.tsx.hbs' : './component/stateless.tsx.hbs',
abortOnFail: true
}, {
type: 'add',
path: `${componentPath}/types.ts`,
templateFile: './component/types.ts.hbs',
abortOnFail: true
}, {
type: 'add',
path: `${componentPath}/styles.ts`,
templateFile: './component/styles.ts.hbs',
abortOnFail: true
}, {
type: 'modify',
path: rootPath,
pattern: /(\/\* GENERATOR-IMPORT \*\/)/g,
template: trimTemplateFile('./config/generators/component/import.ts.hbs'),
abortOnFail: false
}, {
type: 'modify',
path: rootPath,
pattern: /(\/\* GENERATOR-EXPORT \*\/)/g,
template: trimTemplateFile('./config/generators/component/export.ts.hbs'),
abortOnFail: false
}];
return actions;
}
};
================================================
FILE: packages/docs/config/generators/component/stateless.tsx.hbs
================================================
import * as React from 'react';
import Component from './styles';
export interface Props extends React.HTMLProps<typeof {{ properCase name }}> {
children: JSX.Element;
}
export default function {{ properCase name }}({
children,
}: Props): JSX.Element {
return (
<Component>
{children}
</Component>
);
};
================================================
FILE: packages/docs/config/generators/component/styles.ts.hbs
================================================
import styled from 'styled-components';
export default styled.div`
height: 100px;
width: 200px;
`;
================================================
FILE: packages/docs/config/generators/component/types.ts.hbs
================================================
export { Props } from './';
================================================
FILE: packages/docs/config/generators/container/actionCreators.js.hbs
================================================
import * as T from './constants';
import {
LoadInitiationAction,
LoadSuccessAction,
LoadFailureAction,
LoadCancelAction,
} from './actions';
import { ErrorType } from './types';
export const loadInitiation = (): LoadInitiationAction => ({
type: T.LOAD_INITIATION,
});
export const loadSuccess = (data: string): LoadSuccessAction => ({
type: T.LOAD_SUCCESS,
payload: data,
});
export const loadFailure = (error: ErrorType): LoadFailureAction => ({
type: T.LOAD_FAILURE,
payload: error,
});
export const loadCancel = (): LoadCancelAction => ({
type: T.LOAD_CANCEL,
});
export const actionCreators = {
loadInitiation,
loadSuccess,
loadFailure,
loadCancel,
};
export default actionCreators;
================================================
FILE: packages/docs/config/generators/container/actions.js.hbs
================================================
import { PayloadAction } from 'root/types';
import { ErrorType } from './types';
import * as T from './constants';
export interface LoadInitiationAction extends PayloadAction<undefined> {
type: T.LOAD_INITIATION_TYPE;
}
export interface LoadSuccessAction extends PayloadAction<string> {
type: T.LOAD_SUCCESS_TYPE;
payload: string;
}
export interface LoadFailureAction extends PayloadAction<ErrorType> {
type: T.LOAD_FAILURE_TYPE;
payload: ErrorType;
}
export interface LoadCancelAction extends PayloadAction<undefined> {
type: T.LOAD_CANCEL_TYPE;
}
export type Action = LoadInitiationAction | LoadSuccessAction | LoadFailureAction | LoadCancelAction;
================================================
FILE: packages/docs/config/generators/container/constants.js.hbs
================================================
export type LOAD_INITIATION_TYPE = '{{ uppercase name }}/LOAD_INITIATION';
export const LOAD_INITIATION: LOAD_INITIATION_TYPE = '{{ uppercase name }}/LOAD_INITIATION';
export type LOAD_SUCCESS_TYPE = '{{ uppercase name }}/LOAD_SUCCESS';
export const LOAD_SUCCESS: LOAD_SUCCESS_TYPE = '{{ uppercase name }}/LOAD_SUCCESS';
export type LOAD_FAILURE_TYPE = '{{ uppercase name }}/LOAD_FAILURE';
export const LOAD_FAILURE: LOAD_FAILURE_TYPE = '{{ uppercase name }}/LOAD_FAILURE';
export type LOAD_CANCEL_TYPE = '{{ uppercase name }}/LOAD_CANCEL';
export const LOAD_CANCEL: LOAD_CANCEL_TYPE = '{{ uppercase name }}/LOAD_CANCEL';
export type ActionType = LOAD_INITIATION_TYPE | LOAD_SUCCESS_TYPE | LOAD_FAILURE_TYPE | LOAD_CANCEL_TYPE;
================================================
FILE: packages/docs/config/generators/container/export.js.hbs
================================================
$1
{{ properCase name }},
================================================
FILE: packages/docs/config/generators/container/import.js.hbs
================================================
$1
import {{ properCase name }} from '{{ getPath path 'containers' }}{{ properCase name }}';
================================================
FILE: packages/docs/config/generators/container/index.js
================================================
const path = require('path');
const { trimTemplateFile } = require('../utils/');
module.exports = {
description: 'Add a container component',
prompts: [
{
type: 'input',
name: 'name',
message: 'What should it be called?',
default: 'Dashboard',
validate: value => {
if ((/.+/).test(value)) {
return true;
}
return 'The name is required';
}
},
{
type: 'input',
name: 'path',
message: 'What directory would you like your container in? (relative)',
default: './src/client/containers',
validate: (value) => {
return true;
}
},
{
type: 'confirm',
name: 'wantActionsAndReducer',
default: true,
message: 'Do you want actions/constants/reducer for this container?'
},
{
type: 'confirm',
name: 'wantSelectors',
default: true,
message: 'Do you want to use reselect?'
}
],
actions: (data) => {
const containerPath = path.resolve(process.cwd(), `${data.path}/{{properCase name}}/`);
const rootPath = path.resolve(process.cwd(), `./src/client/containers/index.ts`);
const reducersPath = path.resolve(process.cwd(), './src/client/reducers.ts');
const typesPath = path.resolve(process.cwd(), './src/client/types.ts');
const statePath = path.resolve(process.cwd(), './src/client/state.ts');
const actions = [
{
type: 'add',
path: `${containerPath}/index.tsx`,
templateFile: './container/index.js.hbs',
abortOnFail: true
},
{
type: 'add',
path: `${containerPath}/presentation.tsx`,
templateFile: './container/presentation.js.hbs',
abortOnFail: true
},
{
type: 'modify',
path: rootPath,
pattern: /(\/\* GENERATOR-IMPORT \*\/)/g,
template: trimTemplateFile('./config/generators/container/import.js.hbs'),
abortOnFail: false
},
{
type: 'modify',
path: rootPath,
pattern: /(\/\* GENERATOR-EXPORT \*\/)/g,
template: trimTemplateFile('./config/generators/container/export.js.hbs'),
abortOnFail: false
},
{
type: 'modify',
path: typesPath,
pattern: /(\/\* GENERATOR-IMPORT \*\/)/g,
template: trimTemplateFile('./config/generators/container/types.import.ts.hbs'),
abortOnFail: false
},
{
type: 'modify',
path: typesPath,
pattern: /(\/\* GENERATOR-EXPORT \*\/)/g,
template: trimTemplateFile('./config/generators/container/types.export.ts.hbs'),
abortOnFail: false
}
];
actions.push({
type: 'add',
path: `${containerPath}/styles.ts`,
templateFile: './container/styles.js.hbs',
abortOnFail: true
});
actions.push( {
type: 'add',
path: `${containerPath}/types.ts`,
templateFile: './container/types.ts.hbs',
abortOnFail: true
});
if (data.wantSelectors) {
actions.push({
type: 'add',
path: `${containerPath}/selectors.ts`,
templateFile: './container/selectors.js.hbs',
abortOnFail: true
});
}
// If they want actions and a reducer, generate actions.js, constants.js,
// reducer.js and the corresponding tests for actions and the reducer
if (data.wantActionsAndReducer) {
// Actions
actions.push({
type: 'add',
path: `${containerPath}/actionCreators.ts`,
templateFile: './container/actionCreators.js.hbs',
abortOnFail: true
});
actions.push({
type: 'add',
path: `${containerPath}/state.ts`,
templateFile: './container/state.js.hbs',
abortOnFail: true
});
actions.push({
type: 'add',
path: `${containerPath}/actions.ts`,
templateFile: './container/actions.js.hbs',
abortOnFail: true
});
// Constants
actions.push({
type: 'add',
path: `${containerPath}/constants.ts`,
templateFile: './container/constants.js.hbs',
abortOnFail: true
});
// Reducer
actions.push({
type: 'add',
path: `${containerPath}/reducer.ts`,
templateFile: './container/reducer.js.hbs',
abortOnFail: true
});
actions.push({
type: 'modify',
path: reducersPath,
pattern: /(\/\* GENERATOR-IMPORT-REDUCER \*\/)/g,
template: trimTemplateFile('./config/generators/container/reducer.import.js.hbs'),
abortOnFail: false
});
actions.push({
type: 'modify',
path: reducersPath,
pattern: /(\/\* GENERATOR-EXPORT-REDUCER \*\/)/g,
template: trimTemplateFile('./config/generators/container/reducer.export.js.hbs'),
abortOnFail: false
});
actions.push({
type: 'modify',
path: statePath,
pattern: /(\/\* GENERATOR-IMPORT-STATE \*\/)/g,
template: trimTemplateFile('./config/generators/container/state.import.js.hbs'),
abortOnFail: false
});
actions.push({
type: 'modify',
path: statePath,
pattern: /(\/\* GENERATOR-EXPORT-STATE \*\/)/g,
template: trimTemplateFile('./config/generators/container/reducer.export-state.js.hbs'),
abortOnFail: false
});
actions.push({
type: 'modify',
path: statePath,
pattern: /(\/\* GENERATOR-EXPORT-STATE-TYPE \*\/)/g,
template: trimTemplateFile('./config/generators/container/state-type.js.hbs'),
abortOnFail: false
});
}
return actions;
}
};
================================================
FILE: packages/docs/config/generators/container/index.js.hbs
================================================
import * as React from 'react';
{{#if wantActionsAndReducer}}
import { connect } from 'react-redux';
import { bindActionCreators, Dispatch } from 'redux';
import { State as GlobalState } from 'root/state';
import { Action, ActionMap, ErrorType } from './types';
import actionCreators from './actionCreators';
{{/if}}
{{#if wantSelectors}}
import * as selectors from './selectors';
{{/if}}
import Presentation from './presentation';
{{#if wantActionsAndReducer}}
{{#if wantSelectors}}
type MapStateToProps = (state: GlobalState) => StateProps;
const mapStateToProps: MapStateToProps = (state) => ({
isLoading: selectors.selectIsLoading(state),
error: selectors.selectError(state),
data: selectors.selectData(state),
});
{{else}}
type MapStateToProps = (state: GlobalState): StateProps;
const mapStateToProps: MapStateToProps = (state) => ({
isLoading: state.{{ camelCase name }}.isLoading,
error: state.{{ camelCase name }}.error,
data: state.{{ camelCase name }}.data,
});
{{/if}}
type MapDispatchToProps = (dispatch: Dispatch<Action>) => DispatchProps;
const mapDispatchToProps: MapDispatchToProps = (dispatch) => ({
actions: bindActionCreators(
actionCreators,
dispatch,
),
});
export interface DispatchProps {
actions: ActionMap;
}
export interface StateProps {
isLoading: boolean;
error?: ErrorType;
data?: string;
}
export type Props = StateProps & DispatchProps;
class {{ properCase name }} extends React.Component<Props, undefined> {
{{else}}
export interface Props {
}
class {{ properCase name }} extends React.Component<Props, undefined> {
{{/if}}
public render() {
return (
<Presentation {...this.props} />
);
}
}
{{#if wantActionsAndReducer}}
export default connect(
mapStateToProps,
mapDispatchToProps,
)({{ properCase name }});
{{else}}
export default {{ properCase name }};
{{/if}}
================================================
FILE: packages/docs/config/generators/container/presentation.js.hbs
================================================
import * as React from 'react';
{{#if wantActionsAndReducer}}
import { StateProps } from './types';
{{else}}
import { Props as ParentProps } from './types';
{{/if}}
import { Heading, Section } from './styles';
{{#if wantActionsAndReducer}}
export default class Presentation extends React.Component<StateProps, undefined> {
{{else}}
export interface Props extends ParentProps {
// own props
}
export default class Presentation extends React.Component<Props, undefined> {
{{/if}}
public render() {
{{#if wantActionsAndReducer}}
const {
isLoading,
error,
data,
} = this.props;
{{/if}}
return (
<Section>
<Heading>
Best container ever!
</Heading>
</Section>
);
}
}
================================================
FILE: packages/docs/config/generators/container/reducer.export-state.js.hbs
================================================
$1
{{ camelCase name }}: {{ camelCase name }}State,
================================================
FILE: packages/docs/config/generators/container/reducer.export.js.hbs
================================================
$1
{{ camelCase name }},
================================================
FILE: packages/docs/config/generators/container/reducer.import.js.hbs
================================================
$1
import {{ camelCase name }} from './containers/{{ properCase name }}/reducer';
================================================
FILE: packages/docs/config/generators/container/reducer.js.hbs
================================================
import * as T from './constants';
import initialState from './state';
import {
Action,
State,
} from './types';
const reducer = (
state: State = initialState,
action: Action,
): State => {
switch (action.type) {
case T.LOAD_INITIATION:
return Object.assign({}, state, {
isLoading: true,
});
case T.LOAD_SUCCESS:
return Object.assign({}, state, {
isLoading: false,
data: action.payload,
});
case T.LOAD_FAILURE:
return Object.assign({}, state, {
isLoading: false,
error: action.payload,
});
default:
return state;
}
};
export default reducer;
================================================
FILE: packages/docs/config/generators/container/selectors.js.hbs
================================================
import { State as GlobalState } from '../../state';
import { State, ErrorType } from './types';
import { createSelector, Selector } from 'reselect';
export const select{{ properCase name }} = () => (state: GlobalState): State => state.{{ camelCase name }};
export type SelectIsLoading = Selector<GlobalState, boolean>;
export const selectIsLoading: SelectIsLoading = createSelector(
select{{ properCase name }}(),
({{ camelCase name }}) => {{ camelCase name }}.isLoading,
);
export type SelectError = Selector<GlobalState, ErrorType>;
export const selectError: SelectError = createSelector(
select{{ properCase name }}(),
({{ camelCase name }}) => {{ camelCase name }}.error,
);
export type SelectData = Selector<GlobalState, string>;
export const selectData: SelectData = createSelector(
select{{ properCase name }}(),
({{ camelCase name }}) => {{ camelCase name }}.data,
);
================================================
FILE: packages/docs/config/generators/container/state-type.js.hbs
================================================
$1
{{ camelCase name }}: {{ properCase name }}State;
================================================
FILE: packages/docs/config/generators/container/state.import.js.hbs
================================================
$1
import { initialState as {{ camelCase name }}State, State as {{ properCase name }}State } from './containers/{{ properCase name }}/state';
================================================
FILE: packages/docs/config/generators/container/state.js.hbs
================================================
import { ErrorType } from './types';
export interface State {
isLoading: boolean;
error?: ErrorType;
data?: string;
}
export const initialState: State = {
isLoading: false,
error: null,
data: null,
};
export default initialState;
================================================
FILE: packages/docs/config/generators/container/styles.js.hbs
================================================
import styled from 'styled-components';
export const Section = styled.section`
padding: 60px;
background-color: #f5f5f5;
min-height: calc(100vh - 50px);
`;
export const Heading = styled.h1`
text-align: center;
`;
================================================
FILE: packages/docs/config/generators/container/types.export.ts.hbs
================================================
$1
{{ properCase name }}Types,
================================================
FILE: packages/docs/config/generators/container/types.import.ts.hbs
================================================
$1
import * as {{ properCase name }}Types from './containers/{{ properCase name }}/types';
================================================
FILE: packages/docs/config/generators/container/types.ts.hbs
================================================
{{#if wantActionsAndReducer}}
import { ActionCreatorsMapObject } from 'redux';
import {
LoadInitiationAction,
LoadSuccessAction,
LoadFailureAction,
LoadCancelAction,
} from './actions';
export { State } from './state';
export { Props, StateProps, DispatchProps } from './';
export { ActionType } from './constants';
export { Action } from './actions';
export interface ErrorType { message: string }
export interface ActionMap extends ActionCreatorsMapObject {
loadInitiation: () => LoadInitiationAction;
loadSuccess: (data: string) => LoadSuccessAction;
loadFailure: (error: ErrorType) => LoadFailureAction;
loadCancel: () => LoadCancelAction;
}
{{else}}
export { Props } from './';
{{/if}}
================================================
FILE: packages/docs/config/generators/utils/index.js
================================================
const fs = require('fs');
const trimTemplateFile = (template) => {
// Loads the template file and trims the whitespace and then returns the content as a string.
return fs.readFileSync(template, 'utf8').replace(/\s*$/, '');
};
module.exports = {
trimTemplateFile
};
================================================
FILE: packages/docs/config/generators/utils/safeString.js
================================================
function SafeString(string) {
this.string = string;
}
SafeString.prototype.toString = SafeString.prototype.toHTML = function() {
return '' + this.string;
};
module.exports = {
SafeString
};
================================================
FILE: packages/docs/config/ignoreAssets.js
================================================
/* eslint-disable */
(function() {
require.extensions['.scss'] = () => {
return;
};
require.extensions['.css'] = () => {
return;
};
require.extensions['.png'] = () => {
return;
};
require.extensions['.jpg'] = () => {
return;
};
require.extensions['.md'] = () => {
return;
};
})();
================================================
FILE: packages/docs/config/types/require.d.ts
================================================
declare var require: {
(path: string): any;
<T>(path: string): T;
(paths: string[], callback: (...modules: any[]) => void): void;
ensure: (paths: string[], callback: (require: <T>(path: string) => T) => void) => void;
};
================================================
FILE: packages/docs/devServer.js
================================================
var path = require('path');
var webpack = require('webpack');
var express = require('express');
var devMiddleware = require('webpack-dev-middleware');
var hotMiddleware = require('webpack-hot-middleware');
var config = require('./webpack.config');
var app = express();
var compiler = webpack(config);
app.use(devMiddleware(compiler, {
publicPath: config.output.publicPath,
historyApiFallback: true,
}));
app.use(hotMiddleware(compiler));
app.get('*', function (req, res) {
res.sendFile(path.join(__dirname, 'index.html'));
});
app.listen(1339, function (err) {
if (err) {
return console.error(err);
}
console.log('Listening at http://localhost:1339/');
});
================================================
FILE: packages/docs/index.html
================================================
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>React TS Starter</title>
<link href="https://fonts.googleapis.com/css?family=Hind|Montserrat|Roboto+Mono" rel="stylesheet">
</head>
<body>
<div id="app"></div>
<script src="/app.js"></script>
</body>
</html>
================================================
FILE: packages/docs/package.json
================================================
{
"name": "srtb-docs",
"version": "1.0.0",
"description": "Docs for the scalable-react-typescript-boilerplate project",
"main": "index.js",
"author": "RyanCCollins",
"license": "MIT",
"engines": {
"node": "6.9.5",
"npm": "3.10.8"
},
"scripts": {
"precommit": "npm run lint --silent && npm run test",
"build": "webpack --config ./webpack.config.js",
"start": "node devServer.js",
"predeploy": "rimraf build/public/*.*",
"deploy": "cross-env NODE_ENV=production ./node_modules/.bin/webpack --config ./webpack.config.prod.js",
"postdeploy": "npm run compile",
"compile": "./node_modules/.bin/tsc",
"setup:yarn": "yarn",
"preserve": "npm run compile",
"lint": "tslint \"packages/**/*.ts{,x}\" && tslint \"src/**/*.ts{,x}\"",
"serve": "cross-env NODE_ENV=server node server.js",
"postinstall": "npm run deploy",
"generator": "plop --plopfile ./config/generators/cli.js"
},
"dependencies": {
"@types/body-parser": "^0.0.34",
"@types/compression": "latest",
"@types/express": "latest",
"@types/graphql": "latest",
"@types/isomorphic-fetch": "^0.0.33",
"@types/mongoose": "^4.7.7",
"@types/morgan": "latest",
"@types/node": "^6.0.64",
"@types/react": "^15.0.14",
"@types/react-dom": "^0.14.23",
"@types/react-ga": "^1.4.7",
"@types/react-redux": "^4.4.35",
"@types/react-router": "^3.0.6",
"@types/react-router-redux": "^4.0.42",
"@types/reselect": "^2.0.27",
"@types/sinon": "^1.16.35",
"@types/webpack": "^2.2.11",
"apollo-client": "^0.10.1",
"apollo-codegen": "^0.10.8",
"autoprefixer": "^6.7.6",
"axios": "^0.15.3",
"babel-polyfill": "^6.23.0",
"body-parser": "^1.17.0",
"compression": "^1.6.2",
"cors": "^2.8.1",
"exports-loader": "^0.6.4",
"express": "^4.15.0",
"github-markdown-css": "^2.4.1",
"graphql": "^0.9.1",
"graphql-server-express": "0.7.2",
"graphql-tag": "^1.3.1",
"html-webpack-plugin": "^2.28.0",
"imports-loader": "^0.7.1",
"isomorphic-fetch": "^2.2.1",
"json-loader": "^0.5.4",
"markdown-loader": "^2.0.0",
"mongoose": "^4.8.5",
"morgan": "^1.8.1",
"node-env-file": "^0.1.8",
"openui": "1.0.4",
"plop": "^1.7.4",
"precss": "^1.4.0",
"react": "^15.4.1",
"react-addons-test-utils": "^15.4.2",
"react-apollo": "^0.13.2",
"react-dom": "^15.4.1",
"react-ga": "^2.1.2",
"react-hot-loader": "3.0.0-beta.6",
"react-markdown": "^2.4.5",
"react-redux": "^5.0.3",
"react-router": "^3.0.2",
"react-router-redux": "^4.0.8",
"redux": "^3.6.0",
"redux-connect": "^5.0.0",
"redux-logic": "^0.11.7",
"redux-mock-provider": "^1.0.0",
"reselect": "^2.5.4",
"rxjs": "^5.2.0",
"serialize-javascript": "^1.3.0",
"shortid": "^2.2.6",
"sinon": "^1.17.7",
"styled-components": "^1.4.4"
},
"devDependencies": {
"@types/enzyme": "^2.7.5",
"babel-core": "^6.23.1",
"babel-loader": "^6.3.2",
"babel-plugin-webpack-alias": "^2.1.2",
"babel-preset-es2015": "^6.18.0",
"babel-preset-react": "^6.23.0",
"babel-preset-stage-0": "^6.16.0",
"cross-env": "^3.2.3",
"css-loader": "^0.26.2",
"enzyme": "^2.7.1",
"enzyme-to-json": "^1.5.0",
"extract-text-webpack-plugin": "^2.0.0",
"html-loader": "^0.4.5",
"husky": "^0.13.2",
"lerna": "2.0.0-beta.38",
"postcss-loader": "^1.3.3",
"redux-logic-test": "^1.0.3",
"redux-mock-store": "^1.2.2",
"rimraf": "^2.6.1",
"style-loader": "^0.13.2",
"ts-loader": "^2.0.1",
"tslint": "^4.5.1",
"tslint-eslint-rules": "^3.5.1",
"tslint-loader": "^3.4.3",
"tslint-react": "^2.5.0",
"typescript": "^2.2.1",
"webpack": "^2.2.1",
"webpack-dev-middleware": "^1.10.1",
"webpack-hot-middleware": "^2.17.1",
"webpack-manifest-plugin": "^1.1.0"
}
}
================================================
FILE: packages/docs/server.js
================================================
require('babel-core/register');
require('./config/ignoreAssets');
var app = require('./build/src/server/index.jsx');
================================================
FILE: packages/docs/src/client/apolloClient.ts
================================================
import { ApolloClient, createNetworkInterface } from 'apollo-client';
declare var window: {
__INITIAL_STATE__: string,
};
const uri = process.env.API_URL || 'http://0.0.0.0:1338/api';
const client = new ApolloClient({
networkInterface: createNetworkInterface({
uri,
}),
initialState: typeof window !== 'undefined' ? window.__INITIAL_STATE__ : null, // eslint-disable-line
ssrForceFetchDelay: 100,
});
export default client;
================================================
FILE: packages/docs/src/client/components/AddComment/__tests__/__mocks__/addCommentMocks.mock.ts
================================================
export const addCommentProps = {
input: 'Mock input for test',
onSubmit: jest.fn(),
onChange: jest.fn(),
onKeyUp: jest.fn(),
};
================================================
FILE: packages/docs/src/client/components/AddComment/__tests__/__snapshots__/index.test.tsx.snap
================================================
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`<AddComment /> rendering should render with supplied props 1`] = `
<styled.div>
<styled.div>
<styled.div />
</styled.div>
<styled.div>
<form>
<styled.textarea
cols={30}
id="comment-input"
name="comment-input"
onChange={[Function]}
onKeyUp={[Function]}
placeholder="Add comment..."
rows={3}
value="Mock input for test"
/>
</form>
<styled.footer>
<styled.ul>
<styled.li
onClick={[Function]}
>
<styled.a>
Submit
</styled.a>
</styled.li>
</styled.ul>
</styled.footer>
</styled.div>
</styled.div>
`;
================================================
FILE: packages/docs/src/client/components/AddComment/__tests__/index.test.tsx
================================================
import { shallow, mount } from 'enzyme';
import { shallowToJson } from 'enzyme-to-json';
import * as React from 'react';
import AddComment from '../';
import { addCommentProps } from './__mocks__/addCommentMocks.mock';
describe('<AddComment /> rendering', () => {
it('should render with supplied props', () => {
const wrapper = shallow(
<AddComment {...addCommentProps} />,
);
expect(shallowToJson(wrapper)).toMatchSnapshot();
});
});
describe('<AddComment /> onSubmit event testing', () => {
let addCommentComponent;
beforeEach(() => {
addCommentComponent = mount(
<AddComment {...addCommentProps} />,
);
});
it('AddComment requires onSubmit prop', () => {
expect(addCommentComponent.props().onSubmit).toBeDefined();
});
it('AddComment renders an anchor tag for OnClick event', () => {
const renderedAnchorTag = addCommentComponent.find('a').first();
expect(renderedAnchorTag).toBeDefined();
});
it('Clicking anchor tag calls onSubmit()', () => {
const renderedAnchorTag = addCommentComponent.find('a').first();
renderedAnchorTag.simulate('click');
expect(addCommentProps.onSubmit).toBeCalled();
});
});
describe('<AddComment /> onChange event testing', () => {
let addCommentComponent;
beforeEach(() => {
addCommentComponent = mount(
<AddComment {...addCommentProps} />,
);
});
it('AddComment requires onChange prop', () => {
expect(addCommentComponent.props().onChange).toBeDefined();
});
it('AddComment renders textarea for OnChange event', () => {
const renderedTextArea = addCommentComponent.find('textarea').first();
expect(renderedTextArea).toBeDefined();
});
it('Changing textarea triggers OnChange()', () => {
const renderedTextArea = addCommentComponent.find('textarea').first();
renderedTextArea.simulate('change');
expect(addCommentProps.onChange).toBeCalled();
});
});
describe('<AddComment /> onKeyUp event testing', () => {
let addCommentComponent;
beforeEach(() => {
addCommentComponent = mount(
<AddComment {...addCommentProps} />,
);
});
it('AddComment requires onKeyUp prop', () => {
expect(addCommentComponent.props().onKeyUp).toBeDefined();
});
it('AddComment renders textarea for OnKeyUp event', () => {
const renderedTextArea = addCommentComponent.find('textarea').first();
expect(renderedTextArea).toBeDefined();
});
it('KeyUp in textarea triggers OnKeyUp()', () => {
const renderedTextArea = addCommentComponent.find('textarea').first();
renderedTextArea.simulate('keyup');
expect(addCommentProps.onKeyUp).toBeCalled();
});
});
================================================
FILE: packages/docs/src/client/components/AddComment/index.tsx
================================================
import * as React from 'react';
import { AddCommentProps } from './types';
import {
Wrapper,
CommentWrapper,
PicWrapper,
Pic,
TextArea,
Footer,
Actions,
Action,
ActionButton,
} from './styles';
export default function AddComment({
onSubmit,
input,
onChange,
onKeyUp,
}: AddCommentProps): JSX.Element {
return (
<Wrapper>
<PicWrapper>
<Pic />
</PicWrapper>
<CommentWrapper>
<form>
<TextArea
onKeyUp={onKeyUp}
value={input}
onChange={onChange}
name="comment-input"
id="comment-input"
cols={30}
rows={3}
placeholder="Add comment..."
/>
</form>
<Footer>
<Actions>
<Action onClick={onSubmit}>
<ActionButton>Submit</ActionButton>
</Action>
</Actions>
</Footer>
</CommentWrapper>
</Wrapper>
);
};
================================================
FILE: packages/docs/src/client/components/AddComment/styles.ts
================================================
import styled from 'styled-components';
export const Wrapper = styled.div`
min-height: 5.3125rem;
margin-bottom: 1.25rem;
width: 100%;
display: flex;
flex-direction: row;
`;
export const CommentWrapper = styled.div`
padding: 1rem;
background-color: #fff;
vertical-align: top;
border-radius: 0.1875rem;
box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.08);
flex: 1;
`;
export const Footer = styled.footer`
color: #acb4c2;
font-size: 0.875rem;
display: flex;
align-items: baseline;
justify-content: flex-end;
flex-direction: row;
`;
export const Actions = styled.ul`
list-style: none;
`;
export const Action = styled.li`
padding-right: 0.75rem;
`;
export const ActionButton = styled.a`
cursor: pointer;
`;
export const PicWrapper = styled.div`
padding-top: 0.625rem;
width: 3.5rem;
`;
export const Pic = styled.div`
height: 2.25rem;
width: 2.25rem;
border-radius: 50%;
background-size: contain;
background-image: url('https://github.com/RyanCCollins/cdn/blob/master/misc/missing.png?raw=true');
`;
export const TextArea = styled.textarea`
width: 100%;
resize: none;
outline: none;
border: none;
display: block;
margin: 0;
padding: 0;
-webkit-font-smoothing: antialiased;
font-family: "PT Sans", "Helvetica Neue", "Helvetica", "Roboto", "Arial", sans-serif;
font-size: 1rem;
color: #555f77;
`;
================================================
FILE: packages/docs/src/client/components/AddComment/types.ts
================================================
import * as React from 'react';
import AddComment from './';
export interface AddCommentProps extends React.Props<typeof AddComment> {
input: string;
onSubmit: React.EventHandler<React.MouseEvent<HTMLLIElement>>;
onChange: React.EventHandler<React.FormEvent<HTMLTextAreaElement>>;
onKeyUp: React.EventHandler<React.KeyboardEvent<HTMLTextAreaElement>>;
}
================================================
FILE: packages/docs/src/client/components/Comment/__tests__/__mocks__/commentMocks.mock.ts
================================================
export const commentProps = {
author: 'Comment Author',
body: 'Comment Body',
};
export const commentPicProps = {
author: 'Comment Author',
body: 'Comment Body',
picUrl: 'https://github.com/RyanCCollins/cdn/blob/master/misc/missing.png?raw=true',
};
================================================
FILE: packages/docs/src/client/components/Comment/__tests__/__snapshots__/index.test.tsx.snap
================================================
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`<Comment /> default should render a plain comment with other props 1`] = `
<styled.div>
<styled.div>
<styled.div
url="https://github.com/RyanCCollins/cdn/blob/master/misc/missing.png?raw=true"
/>
</styled.div>
<styled.div>
<styled.p>
Comment Body
</styled.p>
<styled.footer>
Comment Author
| Aug 24, 2014 @ 2:35 PM
</styled.footer>
</styled.div>
</styled.div>
`;
exports[`<Comment /> default should render a plain comment with required props 1`] = `
<styled.div>
<styled.div>
<styled.div
url="https://github.com/RyanCCollins/cdn/blob/master/misc/missing.png?raw=true"
/>
</styled.div>
<styled.div>
<styled.p>
Comment Body
</styled.p>
<styled.footer>
Comment Author
| Aug 24, 2014 @ 2:35 PM
</styled.footer>
</styled.div>
</styled.div>
`;
================================================
FILE: packages/docs/src/client/components/Comment/__tests__/index.test.tsx
================================================
import { shallow } from 'enzyme';
import { shallowToJson } from 'enzyme-to-json';
import * as React from 'react';
import Comment from '../';
import { commentProps, commentPicProps } from './__mocks__/commentMocks.mock';
describe('<Comment /> default', () => {
it('should render a plain comment with required props', () => {
const wrapper = shallow(
<Comment {...commentProps} />,
);
expect(shallowToJson(wrapper)).toMatchSnapshot();
});
it('should render a plain comment with other props', () => {
const wrapper = shallow(
<Comment {...commentPicProps} />,
);
expect(shallowToJson(wrapper)).toMatchSnapshot();
});
});
================================================
FILE: packages/docs/src/client/components/Comment/index.tsx
================================================
import * as React from 'react';
import defaultImage from './default';
import { CommentProps } from './types';
import {
Wrapper,
CommentWrapper,
PicWrapper,
Pic,
CommentText,
Footer,
} from './styles';
export default function Comment({
author,
body,
picUrl,
}: CommentProps): JSX.Element {
const url = picUrl || defaultImage;
return (
<Wrapper>
<PicWrapper>
<Pic url={url} />
</PicWrapper>
<CommentWrapper>
<CommentText>{body}</CommentText>
<Footer>
{author} | Aug 24, 2014 @ 2:35 PM
</Footer>
</CommentWrapper>
</Wrapper>
);
}
================================================
FILE: packages/docs/src/client/components/Comment/styles.ts
================================================
import styled from 'styled-components';
export const Wrapper = styled.div`
min-height: 5.3125rem;
margin-bottom: 1.25rem;
width: 100%;
display: flex;
flex-direction: row;
`;
export const CommentWrapper = styled.div`
padding: 1rem;
background-color: #fff;
vertical-align: top;
border-radius: 0.1875rem;
box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.08);
flex: 1;
`;
export const CommentText = styled.p`
color: #555f77;
margin-bottom: 1.25rem;
line-height: 1.3125rem;
`;
export const PicWrapper = styled.div`
padding-top: 0.625rem;
width: 3.5rem;
`;
interface PicProps {
url?: string;
}
export const Pic = styled.div`
height: 2.25rem;
width: 2.25rem;
border-radius: 50%;
background-size: contain;
background-image: url(${(props: PicProps) => props.url});
`;
export const Footer = styled.footer`
color: #acb4c2;
font-size: 0.875rem;
display: flex;
align-items: baseline;
justify-content: space-between;
flex-direction: row;
`;
================================================
FILE: packages/docs/src/client/components/Comment/types.ts
================================================
import * as React from 'react';
import Comment from '../';
export interface CommentProps extends React.Props<typeof Comment> {
author?: string;
body?: string;
picUrl?: string;
}
================================================
FILE: packages/docs/src/client/components/Html/index.tsx
================================================
import * as React from 'react';
import serialize from 'serialize-javascript';
const Html = (props: {
content: string,
state: {},
scriptHash: string,
vendorHash: string,
cssHash: string,
styles: string,
}) => (
<html lang="en">
<head>
<meta charSet="UTF-8" />
<meta httpEquiv="Content-Language" content="en" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<title>Scalable React TypeScript Boilerplate</title>
<link href="https://fonts.googleapis.com/css?family=Hind|Montserrat|Roboto+Mono" rel="stylesheet" />
<link href={`public${props.cssHash}`} rel="stylesheet" />
<style dangerouslySetInnerHTML={{ __html: props.styles }} />
</head>
<body>
<div id="app" dangerouslySetInnerHTML={{ __html: props.content }} />
<script src={`public${props.scriptHash}`} charSet="UTF-8" />
<script src={`public${props.vendorHash}`} type="text/javascript" />
<script
dangerouslySetInnerHTML={{
__html: `window.__INITIAL_STATE__=${serialize(props.state, { isJSON: true })};`,
}}
charSet="UTF-8"
/>
</body>
</html>
);
export default Html;
================================================
FILE: packages/docs/src/client/components/NavBar/__tests__/__mocks__/navBarMocks.mock.ts
================================================
const links = [
{
url: 'https://medium.com',
text: 'Medium',
},
{
url: 'https://www.ryancollins.io/',
text: 'RyanCollins',
},
];
export const navbarProps = {
logoText: 'NavBar Test',
links,
};
================================================
FILE: packages/docs/src/client/components/NavBar/__tests__/__snapshots__/index.test.tsx.snap
================================================
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`<NavBar /> default should render NavBar with links and text 1`] = `
<styled.nav>
<styled.div>
<styled.div>
<withRouter(Anchor)
color="#007acc"
path="/"
plain={true}
>
NavBar Test
</withRouter(Anchor)>
</styled.div>
<styled.div>
<styled.ul>
<styled.li>
<withRouter(Anchor)
path="https://medium.com"
plain={true}
>
Medium
</withRouter(Anchor)>
</styled.li>
<styled.li>
<withRouter(Anchor)
path="https://www.ryancollins.io/"
plain={true}
>
RyanCollins
</withRouter(Anchor)>
</styled.li>
</styled.ul>
</styled.div>
</styled.div>
</styled.nav>
`;
================================================
FILE: packages/docs/src/client/components/NavBar/__tests__/index.test.tsx
================================================
import { shallow } from 'enzyme';
import { shallowToJson } from 'enzyme-to-json';
import * as React from 'react';
import { navbarProps } from './__mocks__/navBarMocks.mock';
import NavBar from '../';
describe('<NavBar /> default', () => {
it('should render NavBar with links and text', () => {
const wrapper = shallow(
<NavBar {...navbarProps} />,
);
expect(shallowToJson(wrapper)).toMatchSnapshot();
});
});
================================================
FILE: packages/docs/src/client/components/NavBar/index.tsx
================================================
import * as React from 'react';
import { Anchor } from 'openui';
import { NavBarProps } from './types';
import {
Nav,
InnerNav,
LeftMenu,
RightMenu,
Menu,
MenuItem,
} from './styles';
export default function NavBar({
logoText,
links,
}: NavBarProps): JSX.Element {
return (
<Nav>
<InnerNav>
<LeftMenu>
<Anchor plain path="/" color="#007acc">
{logoText}
</Anchor>
</LeftMenu>
<RightMenu>
<Menu>
{links.map((item, i) =>
<MenuItem key={i}>
<Anchor
plain
path={item.url}
>
{item.text}
</Anchor>
</MenuItem>,
)}
</Menu>
</RightMenu>
</InnerNav>
</Nav>
);
}
================================================
FILE: packages/docs/src/client/components/NavBar/styles.ts
================================================
import styled from 'styled-components';
export const Nav = styled.nav`
width: 100%;
background: #0a0a0a;
color: #fefefe;
padding: .5rem;
box-sizing: border-box;
`;
export const InnerNav = styled.div`
width: 100%;
display: flex;
flex-direction: row;
align-items: center;
justify-content: space-between;
`;
export const LeftMenu = styled.div`
margin-right: 1rem;
margin-left: 1rem;
`;
export const RightMenu = styled.div`
max-width: 400px;
margin-right: 1rem;
`;
export const Menu = styled.ul`
margin: 0;
list-style-type: none;
`;
export const MenuItem = styled.li`
display: table-cell;
vertical-align: middle;
a {
color: #fff;
display: block;
padding: .7rem 1rem;
line-height: 1;
}
`;
================================================
FILE: packages/docs/src/client/components/NavBar/types.ts
================================================
import * as React from 'react';
import NavBar from './';
interface Navlink { url: string; text: string; }
export interface NavBarProps extends React.Props<typeof NavBar> {
logoText: string;
links: Navlink[];
}
================================================
FILE: packages/docs/src/client/components/Pic/index.tsx
================================================
import styled from 'styled-components';
import {PicStyle} from './styles';
export interface PicProps {
url?: string;
}
export const Pic = styled.div`
${PicStyle}
`;
export default Pic;
================================================
FILE: packages/docs/src/client/components/Pic/styles.ts
================================================
import { css } from 'styled-components';
import {PicProps} from './index';
export const PicStyle = css`
height: 2.25rem;
width: 2.25rem;
border-radius: 50%;
background-size: contain;
background-image: url(${(props: PicProps) => props.url});
`;
================================================
FILE: packages/docs/src/client/components/Pic/types.ts
================================================
export * from './index';
================================================
FILE: packages/docs/src/client/components/Post/index.tsx
================================================
import * as React from 'react';
import { Markdown, Image, Headline, Article, Box } from 'openui';
import { Comment, AddComment } from 'components';
import { PostProps } from './types';
export default function Post({
content,
title,
image,
comments,
comment,
}: PostProps): JSX.Element {
return (
<Article
pad="medium"
backgroundColor="#fff"
alignItems="center"
margin={{ vertical: 'medium' }}
boxSize={{ horizontal: 'xxlarge' }}
>
<Box pad="medium" alignItems="center">
<Image alt={title} imageSize="large" src={image} />
<Headline>
{title}
</Headline>
<Markdown content={content} />
<h1>Comments</h1>
<AddComment
{...comment}
/>
{comments && comments.map((item, i) =>
<Comment key={i} {...item} />,
)}
</Box>
</Article>
);
};
================================================
FILE: packages/docs/src/client/components/Post/types.ts
================================================
interface PostComment {
body: string;
author: string;
}
export interface PostProps {
content: string;
image: string;
title: string;
comments?: PostComment[];
comment: {
input: string;
onSubmit: React.EventHandler<React.MouseEvent<HTMLLIElement>>;
onChange: React.EventHandler<React.FormEvent<HTMLTextAreaElement>>;
onKeyUp: React.EventHandler<React.KeyboardEvent<HTMLTextAreaElement>>;
}
}
================================================
FILE: packages/docs/src/client/components/PostCard/index.tsx
================================================
import * as React from 'react';
import { Link } from 'react-router';
import shortenText from './shortenText';
import {
Icon,
Card,
CardFooter,
CardThumbnail,
CardHeading,
CardDescription,
Anchor,
CardContents,
} from './styles';
import { PostCardProps } from './types';
export default function PostCard({
content,
image,
title,
id,
}: PostCardProps): JSX.Element {
return (
<Card>
<CardThumbnail image={image} />
<CardContents>
<CardHeading>
{title}
</CardHeading>
<CardDescription>
{shortenText(content, 150)}
</CardDescription>
<CardFooter>
<Link to={`/blog/posts/${id}`}>
<Icon>
<path fill="none" d="M2,12 L22,12 M13,3 L22,12 L13,21" />
</Icon>
<Anchor>Read More</Anchor>
</Link>
</CardFooter>
</CardContents>
</Card>
);
};
================================================
FILE: packages/docs/src/client/components/PostCard/shortenText.ts
================================================
export default function shortenText(text: string, maxLength: number) {
if (text.length > maxLength) {
return `${text.substr(0, maxLength - 3)}...`;
}
return text;
};
================================================
FILE: packages/docs/src/client/components/PostCard/styles.ts
================================================
import styled from 'styled-components';
import { SvgIcon } from 'openui';
export interface CardThumbnailProps {
image: string;
}
export const Card = styled.div`
width: 384px;
flex-direction: column;
display: flex;
flex-wrap: wrap;
padding: 0px;
background-color: white;
`;
export const CardThumbnail = styled.div`
background: url('${(props: CardThumbnailProps) => props.image}') center center / cover no-repeat;
min-height: 192px;
align-items: center;
justify-content: center;
`;
export const CardContents = styled.div`
padding: 24px;
`;
export const CardHeading = styled.h2`
font-size: 2.25rem;
font-weight: 700;
margin-bottom: 12px;
line-height: 1.23;
`;
export const CardDescription = styled.p`
color: #333;
font-size: 24px;
line-height: 1.167;
margin-top: 24px;
margin-bottom: 24px;
`;
export const Icon = styled(SvgIcon)`
vertical-align: middle;
margin-right: 12px;
transition: all .3s ease-in-out;
display: inline-block;
width: 24px;
height: 24px;
fill: #007acc;
stroke: #007acc;
flex: 0 0 auto;
stroke-width: 2;
&:hover {
transform: translate(4px, 0px);
}
`;
export const Anchor = styled.a`
color: #007acc;
font-size: 1.1875rem;
line-height: 24px;
font-weight: 600;
`;
export const CardFooter = styled.footer``;
================================================
FILE: packages/docs/src/client/components/PostCard/types.ts
================================================
export interface PostCardProps {
content: string;
id: string;
image: string;
title: string;
}
================================================
FILE: packages/docs/src/client/components/index.ts
================================================
/* GENERATOR-IMPORT */
import PostCard from './PostCard';
import AddComment from './AddComment';
import Comment from './Comment';
import Post from './Post';
import NavBar from './NavBar';
import Pic from './Pic';
export {
/* GENERATOR-EXPORT */
PostCard,
AddComment,
Comment,
Post,
NavBar,
Pic,
};
================================================
FILE: packages/docs/src/client/components/utils/index.ts
================================================
import remStringFromPx from './remStringFromPx';
export default remStringFromPx;
================================================
FILE: packages/docs/src/client/components/utils/remStringFromPx.ts
================================================
type Px = number;
type Rem = number;
const rootRem: number = 16;
const calculateRem = (px: Px): Rem => (px / rootRem);
export default (px: Px): string => `${calculateRem(px)}rem`;
================================================
FILE: packages/docs/src/client/containers/About/about.ts
================================================
// tslint:disable
export default {
githubLogo: 'https://github.com/RyanCCollins/cdn/blob/master/misc/github-512.png?raw=true',
aboutContent: `
# Scalable React TypeScript Boilerplate
The boilerplate aims to follow best practices for building highly scalable and reusable apps and component libraries with React and cutting edge TypeScript.
This project was inspired by the Scalable React Boilerplate project and inherits the same organizational strategy and general best-practices.
You can read more about the organizational strategy used in this app in [this Medium post](https://medium.com/front-end-hacking/the-secret-to-organization-in-functional-programming-913484e85fc9#.6htl4s54y).
`,
aboutRyan: `Hi, I'm Ryan. I’m a software engineer working on building the web one component at a time. I am a UI / UX Engineer on the Grommet UX team, building the world's most advanced UX framework. I'm also an avid functional programmer and a student of Deep Learning / AI.`,
aboutAbhi: `I am a Full Stack Engineer focussing on newest front-end and scalable back-end technologies. My keen area of interests are React, Redux, GraphQL, Google App Engine, Flask, Python and NodeJS to name a few.`,
};
================================================
FILE: packages/docs/src/client/containers/About/contributors.ts
================================================
import bio from './about';
interface Contributor {
name: string;
avatar: string;
github: string;
bio: string;
};
const contributors: Contributor[] = [
{
name: 'Ryan Collins',
avatar: 'https://avatars0.githubusercontent.com/u/13810084?v=3&s=460',
github: 'https://github.com/RyanCCollins',
bio: `${bio.aboutRyan}`,
},
{
name: 'Abhishek Ghosh',
avatar: 'https://raw.githubusercontent.com/ghoshabhi/cdn/master/profile_ag.jpg',
github: 'https://github.com/ghoshabhi',
bio: `${bio.aboutAbhi}`,
},
];
export default contributors;
================================================
FILE: packages/docs/src/client/containers/About/index.tsx
================================================
import * as React from 'react';
import {
Avatar,
Anchor,
Article,
Image,
Markdown,
Heading,
Headline,
} from 'openui';
import {
Container,
AboutSection,
AboutSectionInner,
StyledHr,
AvatarContainer,
Content,
Card,
CardFooter,
Transform,
} from './styles';
import about from './about';
import contributors from './contributors';
class About extends React.Component<undefined, undefined> {
public render() {
return (
<Container>
<AboutSection id="about-section-1">
<Headline fontWeight={700}>
About
<StyledHr />
</Headline>
<AboutSectionInner>
<Article
pad="large"
backgroundColor="#fff"
margin={{ vertical: 'medium' }}
boxSize={{ horizontal: 'xxlarge' }}
content={`${about.aboutContent}`}
/>
</AboutSectionInner>
</AboutSection>
<AboutSection id="about-section-two" padBottom>
<Headline fontWeight={700}>
Team Members
<StyledHr/>
</Headline>
<AboutSectionInner>
{contributors.map((contributor, index) =>
<Card key={index}>
<AvatarContainer>
<Transform>
<Avatar
name={contributor.name}
src={contributor.avatar}
/>
</Transform>
<Content>
<Heading textAlign="center">
{contributor.name}
</Heading>
<Markdown content={contributor.bio} />
</Content>
<CardFooter>
<Anchor href={contributor.github}>
<Image alt="github logo" src={about.githubLogo} imageSize="small"/>
</Anchor>
</CardFooter>
</AvatarContainer>
</Card>,
)}
</AboutSectionInner>
</AboutSection>
</Container>
);
}
}
export default About;
================================================
FILE: packages/docs/src/client/containers/About/styles.ts
================================================
import styled from 'styled-components';
export const Container = styled.div`
min-height: calc(100vh - 54px);
width: 100vw;
`;
interface AboutSectionProps {
padBottom?: boolean
}
export const AboutSection = styled.section`
display: flex;
align-items: center;
flex-direction: column;
background-color: #f5f5f5;
padding-bottom: ${(props: AboutSectionProps) => props.padBottom ? 100 : 0}px;
`;
interface AboutSectionInnerProps {
reverse?: boolean
}
export const AboutSectionInner = styled.div`
padding: 30px 60px;
display: flex;
margin-top: 60px;
flex-direction: row;
@media screen and (max-width: 768px) {
flex-wrap: ${(props: AboutSectionInnerProps) => props.reverse ? 'wrap-reverse' : 'wrap'};
padding: 60px 20px;
margin-top: 0px;
}
`;
export const Card = styled.div`
display: flex;
margin-bottom: 2rem;
flex-direction: column;
align-items: center;
justify-content: center;
margin-right: 2.19492%;
width: 28.5rem !important;
box-sizing: border-box;
background: whitesmoke;
height: 36rem;
border: 1px solid #dbe2e8;
box-shadow: 12px 15px 20px 0px rgba(46,61,73,0.15);
border-radius: 6px;
transition: box-shadow 0.3s ease, border 0.3s ease;
&:hover {
box-shadow: 2px 4px 8px 0px rgba(46,61,73,0.2);
}
@media screen and (max-width: 768px) {
margin-top: 100px;
margin-left: 1.69492%;
width: 100vw !important;
}
`;
export const StyledHr = styled.hr`
border-top: 4px solid;
`;
export const Transform = styled.div`
transform: translate(0px, -75px);
position: absolute;
`;
export const AvatarContainer = styled.div`
width: 100%;
align-items: center;
display: flex;
flex-direction: column;
flex-grow: 1;
`;
export const Content = styled.div`
flex-grow: 1;
padding: 30px;
max-height: 238px;
margin-top: 50px;
box-sizing: border-box;
text-align: justify;
text-justify: inter-word;
p {
font-family: 'Roboto';
font-size: 21px;
}
`;
export const CardFooter = styled.footer`
display: flex;
align-items: flex-end;
justify-content: center;
flex-grow: 1;
padding: 30px;
`;
export const Divider = styled.div`
position:absolute;
left:50%;
top:10%;
bottom:10%;
border-left:1px solid black;
`;
================================================
FILE: packages/docs/src/client/containers/App/__tests__/__snapshots__/index.test.tsx.snap
================================================
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`DocsContainer should render with default props 1`] = `<Connect(Feature) />`;
================================================
FILE: packages/docs/src/client/containers/App/__tests__/actionCreators.test.ts
================================================
import { actionCreators } from '../actionCreators';
import * as types from '../constants';
// Action Creator Test as a rule return very little value. Focus on tests that give more value first
describe('App actionCreators', () => {
it('properly creates SET_MOBILE action with isMobile = true', () => {
expect(actionCreators.setIsMobile(true),
).toEqual({
type: types.SET_MOBILE,
isMobile: true,
});
});
it('properly creates SET_MOBILE action with isMobile = false', () => {
expect(actionCreators.setIsMobile(false),
).toEqual({
type: types.SET_MOBILE,
isMobile: false,
});
});
});
================================================
FILE: packages/docs/src/client/containers/App/__tests__/index.test.tsx
================================================
import * as React from 'react';
import Container from '../';
import State from '../state';
import { shallow } from 'enzyme';
import { shallowToJson } from 'enzyme-to-json';
import { Store } from 'redux';
import { Provider } from 'react-redux';
import mockStore from 'test/mockstore';
const testState: State = {
isMobile: true,
logoText: 'logo',
navLinks: [{
text: 'demo',
url: 'www.google.com',
}, {
text: 'demo2',
url: 'www.gmail.com',
}],
};
describe('DocsContainer ', () => {
let store: Store<State>;
beforeEach(() => {
store = mockStore(testState);
});
it('should render with default props', () => {
const wrapper = shallow(
<Provider store={store}>
<Container />
</Provider>,
);
expect(shallowToJson(wrapper)).toMatchSnapshot();
});
});
================================================
FILE: packages/docs/src/client/containers/App/__tests__/reducer.test.ts
================================================
import reducer from '../reducer';
import { actionCreators } from '../actionCreators';
import { initialState } from '../state';
describe('app reducer', () => {
it('should return the initial state with default action', () => {
expect(
reducer(undefined, actionCreators.defaultAction()),
).toEqual(initialState);
});
it('should handle SET_ISMOBILE with true', () => {
expect(
reducer(initialState, actionCreators.setIsMobile(true)).isMobile,
).toEqual(true);
});
it('should handle SET_ISMOBILE with false', () => {
expect(
reducer(initialState, actionCreators.setIsMobile(false)).isMobile,
).toEqual(false);
});
});
================================================
FILE: packages/docs/src/client/containers/App/__tests__/selectors.test.ts
================================================
import { selectIsMobile, selectLogoText, selectNavLinks } from '../selectors';
import { State } from '../../../State';
const testState: State = {
app: {
isMobile: true,
navLinks: [{
text: 'demo2',
url: 'www.google.com',
}],
logoText: null,
},
docs: null,
todoApp: null,
blogPost: null,
};
const testState2: State = {
app: {
isMobile: false,
navLinks: [{
text: 'demo',
url: 'www.gmail.com',
}, {
text: 'demo3',
url: 'www.rediff.com',
}],
logoText: 'demo',
},
docs: null,
todoApp: null,
blogPost: null,
};
describe('app selectors', () => {
describe('app selectIsMobile', () => {
it('should return true', () => {
expect(
selectIsMobile(testState))
.toBe(true);
});
it('should return false', () => {
expect(
selectIsMobile(testState2))
.toBe(false);
});
});
describe('app selectLogoText', () => {
it('should return null', () => {
expect(
selectLogoText(testState))
.toBe(null);
});
it('should return string', () => {
expect(
selectLogoText(testState2))
.toBe('demo');
});
});
describe('app selectNavLinks', () => {
it('should return count', () => {
expect(
selectNavLinks(testState).length)
.toBe(1);
});
it('should return count', () => {
expect(
selectNavLinks(testState2).length)
.toBe(2);
});
it('should return string', () => {
expect(
selectNavLinks(testState)[0])
.toEqual({
text: 'demo2',
url: 'www.google.com',
});
});
it('should return string', () => {
expect(
selectNavLinks(testState2)[1])
.toEqual({
text: 'demo3',
url: 'www.rediff.com',
});
});
});
});
================================================
FILE: packages/docs/src/client/containers/App/actionCreators.ts
================================================
import * as types from './constants';
import { defaultAction } from 'shared/actionCreators';
import {
SetIsMobileAction,
} from './actions';
export const setIsMobile = (isMobile: boolean): SetIsMobileAction => ({
type: types.SET_MOBILE,
isMobile,
});
export const actionCreators = {
setIsMobile,
defaultAction,
};
export default actionCreators;
================================================
FILE: packages/docs/src/client/containers/App/actions.ts
================================================
import { DefaultAction } from 'shared/actions';
import * as types from './constants';
import { Action } from 'redux';
export interface SetIsMobileAction extends Action {
type: types.SET_MOBILE_TYPE,
isMobile: boolean
}
export type FeatureAction =
SetIsMobileAction |
DefaultAction;
================================================
FILE: packages/docs/src/client/containers/App/constants.ts
================================================
export type SET_MOBILE_TYPE = 'APP/SET_MOBILE';
export const SET_MOBILE: SET_MOBILE_TYPE = 'APP/SET_MOBILE';
================================================
FILE: packages/docs/src/client/containers/App/index.tsx
================================================
import * as React from 'react';
import { connect } from 'react-redux';
import { bindActionCreators, Dispatch } from 'redux';
import { State } from '../../state';
import actionCreators from './actionCreators';
import { selectIsMobile, selectNavLinks, selectLogoText } from './selectors';
import Feature, { StateProps, DispatchProps } from './presentation';
import { FeatureAction } from './actions';
// tslint:disable-next-line
interface OwnProps { }; // for props that are not passed down to inner component
const mapStateToProps = (state: State): StateProps => ({
isMobile: selectIsMobile(state),
navLinks: selectNavLinks(state),
logoText: selectLogoText(state),
});
const mapDispatchToProps = (dispatch: Dispatch<FeatureAction>): DispatchProps => ({
actions: bindActionCreators(
actionCreators,
dispatch,
),
});
const Container: React.ComponentClass<OwnProps> = connect(
mapStateToProps,
mapDispatchToProps,
)(Feature);
export default Container;
================================================
FILE: packages/docs/src/client/containers/App/presentation.tsx
================================================
import * as React from 'react';
import { NavBar } from 'components';
import { Box, Heading, Footer, Paragraph, SvgIcon, Anchor } from 'openui';
import { SetIsMobileAction } from './actions';
import { State } from './state';
import { Author, Main } from './styles';
export type StateProps = State;
export interface DispatchProps {
actions: {
setIsMobile: (isMobile: boolean) => SetIsMobileAction,
};
};
export type FeatureProps = React.Props<Feature> & StateProps & DispatchProps;
export default class Feature extends React.Component<FeatureProps, undefined> {
constructor(props) {
super(props);
};
public componentDidMount() {
window.addEventListener('resize', this.handleMobile);
}
public componentWillUnmount() {
window.removeEventListener('resize', this.handleMobile);
}
private handleMobile = () => {
const isMobile = window.innerWidth <= 768;
if (isMobile !== this.props.isMobile) {
this.props.actions.setIsMobile(isMobile);
}
}
public render() {
const {
children,
navLinks,
logoText,
} = this.props;
return (
<Main>
<NavBar
links={navLinks}
logoText={logoText}
/>
{children}
<Footer>
<Box alignItems="center" >
<Heading>
React + TypeScript
</Heading>
<Paragraph margin="none">
Scalable React TS Boilerplate
</Paragraph>
</Box>
<Author>
<span>By </span>
<Anchor plain color="#007acc" href="http://www.ryancollins.io/" > Ryan C.Collins </Anchor>
</Author>
<Box flexDirection="row" alignItems="center" justifyContent="center" >
<Box margin="small" >
<Anchor href="https://github.com/RyanCCollins/scalable-react-ts-boilerplate" >
<SvgIcon style={{ height: 35, width: 35, fill: 'white' }} viewBox="0 0 1792 1792" >
<path // tslint:disable-next-line
d="M1664 896q0 251-146.5 451.5t-378.5 277.5q-27 5-39.5-7t-12.5-30v-211q0-97-52-142 57-6 102.5-18t94-39 81-66.5 53-105 20.5-150.5q0-121-79-206 37-91-8-204-28-9-81 11t-92 44l-38 24q-93-26-192-26t-192 26q-16-11-42.5-27t-83.5-38.5-86-13.5q-44 113-7 204-79 85-79 206 0 85 20.5 150t52.5 105 80.5 67 94 39 102.5 18q-40 36-49 103-21 10-45 15t-57 5-65.5-21.5-55.5-62.5q-19-32-48.5-52t-49.5-24l-20-3q-21 0-29 4.5t-5 11.5 9 14 13 12l7 5q22 10 43.5 38t31.5 51l10 23q13 38 44 61.5t67 30 69.5 7 55.5-3.5l23-4q0 38 .5 89t.5 54q0 18-13 30t-40 7q-232-77-378.5-277.5t-146.5-451.5q0-209 103-385.5t279.5-279.5 385.5-103 385.5 103 279.5 279.5 103 385.5z"
/>
</SvgIcon>
</Anchor>
</Box>
<Box margin="small" >
<Anchor href="https://scalable-react-slack.herokuapp.com/" >
<SvgIcon style={{ height: 35, width: 35, fill: 'white' }} viewBox="0 0 256 256" >
<path // tslint:disable-next-line
d="M165.964 15.838c-3.89-11.975-16.752-18.528-28.725-14.636-11.975 3.89-18.528 16.752-14.636 28.725l58.947 181.365c4.048 11.187 16.132 17.473 27.732 14.135 12.1-3.483 19.475-16.334 15.614-28.217L165.964 15.838" fill="#DFA22F" /><path d="M74.626 45.516C70.734 33.542 57.873 26.989 45.9 30.879 33.924 34.77 27.37 47.631 31.263 59.606l58.948 181.366c4.047 11.186 16.132 17.473 27.732 14.132 12.099-3.481 19.474-16.332 15.613-28.217L74.626 45.516" fill="#3CB187" /><path d="M240.162 166.045c11.975-3.89 18.526-16.75 14.636-28.726-3.89-11.973-16.752-18.527-28.725-14.636L44.708 181.632c-11.187 4.046-17.473 16.13-14.135 27.73 3.483 12.099 16.334 19.475 28.217 15.614l181.372-58.93" fill="#CE1E5B" /><path d="M82.508 217.27l43.347-14.084-14.086-43.352-43.35 14.09 14.089 43.347" fill="#392538" /><path d="M173.847 187.591c16.388-5.323 31.62-10.273 43.348-14.084l-14.088-43.36-43.35 14.09 14.09 43.354" fill="#BB242A" /><path d="M210.484 74.706c11.974-3.89 18.527-16.751 14.637-28.727-3.89-11.973-16.752-18.526-28.727-14.636L15.028 90.293C3.842 94.337-2.445 106.422.896 118.022c3.481 12.098 16.332 19.474 28.217 15.613l181.371-58.93" fill="#72C5CD" /><path d="M52.822 125.933c11.805-3.836 27.025-8.782 43.354-14.086-5.323-16.39-10.273-31.622-14.084-43.352l-43.36 14.092 14.09 43.346" fill="#248C73" /><path d="M144.16 96.256l43.356-14.088a546179.21 546179.21 0 0 0-14.089-43.36L130.07 52.9l14.09 43.356" fill="#62803A" />
</SvgIcon>
</Anchor>
</Box>
</Box>
</Footer>
</Main>
);
}
}
================================================
FILE: packages/docs/src/client/containers/App/reducer.ts
================================================
import { Reducer } from 'redux';
import * as types from './constants';
import { FeatureAction } from './actions';
import { defaultAction } from 'shared/actionCreators';
import { State, initialState } from './state';
const reducer: Reducer<State> = (state: State = initialState, action: FeatureAction = defaultAction()) => {
switch (action.type) {
case types.SET_MOBILE:
return {
...state,
isMobile: action.isMobile,
};
default:
return state;
}
};
export default reducer;
================================================
FILE: packages/docs/src/client/containers/App/selectors.ts
================================================
import { createSelector, Selector } from 'reselect';
import { State } from 'state';
import { State as FeatureState, NavLink } from './state';
const selectFeature = () => (state: State): FeatureState => state.app;
export const selectIsMobile: Selector<State, boolean> = createSelector(
selectFeature(),
(feature) => feature.isMobile,
);
export const selectLogoText: Selector<State, string> = createSelector(
selectFeature(),
(feature) => feature.logoText,
);
export const selectNavLinks: Selector<State, NavLink[]> = createSelector(
selectFeature(),
(feature) => feature.navLinks,
);
================================================
FILE: packages/docs/src/client/containers/App/state.ts
================================================
export interface NavLink {
text: string;
url: string;
}
export interface State {
isMobile: boolean;
navLinks: NavLink[];
logoText: string;
};
export const initialState: State = {
isMobile: false,
navLinks: [
{
text: 'Docs',
url: '/docs',
},
{
text: 'About',
url: '/about',
},
{
text: 'Blog',
url: '/blog',
},
],
logoText: 'React + TypeScript',
};
export default State;
================================================
FILE: packages/docs/src/client/containers/App/styles.ts
================================================
import styled from 'styled-components';
export const Author = styled.div`
color: white;
padding: 10px;
`;
export const Main = styled.main`
max-width: 100vw;
box-sizing: border-box;
`;
================================================
FILE: packages/docs/src/client/containers/App/types.ts
================================================
import App from '../';
export interface NavLink { url: string; text: string; };
export interface Props extends React.Props<typeof App> {
children: JSX.Element;
actions: {
appSetMobile: (isMobile: boolean) => void,
};
isMobile: boolean;
navLinks: NavLink[];
logoText: string;
};
================================================
FILE: packages/docs/src/client/containers/Blog/index.tsx
================================================
import * as React from 'react';
import { graphql } from 'react-apollo';
import { Box, Headline, Section, LoadingIndicator, Notification } from 'openui';
import { PostCard } from 'components';
import POST_QUERY from './posts.graphql';
import Hr from './styles';
import { Props, State } from './types';
class Blog extends React.Component<Props, State> {
constructor() {
super();
this.handleClearError = this.handleClearError.bind(this);
this.state = {
showError: true,
};
}
private handleClearError() {
this.setState({
showError: false,
});
}
public render() {
const { loading, posts, error } = this.props;
const { showError } = this.state;
return (
<Box
alignItems="center"
flexDirection="column"
pad={{ vertical: 'medium', horizontal: 'small' }}
full={{ vertical: true }}
backgroundColor="#f5f5f5"
>
<Headline fontWeight={700}>
Blog
<Hr />
</Headline>
{error && showError &&
<Notification
status="error"
onClick={this.handleClearError}
message={error.message}
/>
}
<LoadingIndicator isLoading={loading} />
<Section
flexWrap
justifyContent="center"
alignItems="center"
flexDirection="row"
boxSize={{ horizontal: 'full' }}
>
{posts && posts.map((item, i) =>
<Box key={i} pad="medium">
<PostCard
{...item}
/>
</Box>,
)}
</Section>
</Box>
);
}
}
const withData = graphql(POST_QUERY, {
props: ({ data: { loading, posts, error } }) => ({
loading,
posts,
error,
}),
});
export default withData(Blog);
================================================
FILE: packages/docs/src/client/containers/Blog/posts.graphql.ts
================================================
import gql from 'graphql-tag';
export default gql`
query Posts {
posts {
id: _id
title
image
content
}
}
`;
================================================
FILE: packages/docs/src/client/containers/Blog/styles.ts
================================================
import styled from 'styled-components';
export default styled.hr`
border-top: 4px solid;
`;
================================================
FILE: packages/docs/src/client/containers/Blog/types.ts
================================================
import Blog from '../';
export interface Post {
id: string;
title: string;
image: string;
content: string;
}
export interface Props extends React.Props<typeof Blog> {
loading: boolean;
error?: { message: string };
posts?: Post[];
}
export interface State {
showError: boolean;
}
================================================
FILE: packages/docs/src/client/containers/BlogPost/__tests__/__mocks__/blogPostPresentation.mock.ts
================================================
export default {
post: {
id: '58a0ccb112b4c56440f5d6a7',
title: 'Welcome!',
image: 'https://raw.githubusercontent.com/RyanCCollins/cdn/master/stsb-images/ts-resized-2.png',
content: 'Hey there! Welcome to the blog of Scalable-React-TypeScript! '
+ 'This is just an introductory post, but stay tuned for more!',
comments: [
{
body: 'This is the first comment!',
author: 'Admin User',
},
],
},
error: { message: 'oops' },
input: 'foo',
loading: false,
onChange: jest.fn(),
onSubmit: jest.fn(),
onKeyUp: jest.fn(),
};
================================================
FILE: packages/docs/src/client/containers/BlogPost/__tests__/__mocks__/blogPostSelectors.mock.ts
================================================
export default {
blogPost: {
input: 'Money',
},
};
================================================
FILE: packages/docs/src/client/containers/BlogPost/__tests__/__snapshots__/index.test.tsx.snap
================================================
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`<BlogPost /> container should render as expected 1`] = `
<Provider
store={
Object {
"clearActions": [Function],
"dispatch": [Function],
"getActions": [Function],
"getState": [Function],
"replaceReducer": [Function],
"subscribe": [Function],
}
}
>
<Connect(_class) />
</Provider>
`;
exports[`<BlogPostPresentation /> should render as expected 1`] = `
<Section
alignItems="center"
backgroundColor="#f5f5f5"
flexDirection="column"
full={
Object {
"vertical": true,
}
}
pad={
Object {
"horizontal": "small",
"vertical": "large",
}
}
>
<Notification
message="oops"
status="error"
/>
<LoadingIndicator
isLoading={false}
/>
<undefined
comment={
Object {
"input": "foo",
"onChange": [Function],
"onKeyUp": [Function],
"onSubmit": [Function],
}
}
comments={
Array [
Object {
"author": "Admin User",
"body": "This is the first comment!",
},
]
}
content="Hey there! Welcome to the blog of Scalable-React-TypeScript! This is just an introductory post, but stay tuned for more!"
id="58a0ccb112b4c56440f5d6a7"
image="https://raw.githubusercontent.com/RyanCCollins/cdn/master/stsb-images/ts-resized-2.png"
title="Welcome!"
/>
</Section>
`;
================================================
FILE: packages/docs/src/client/containers/BlogPost/__tests__/actionCreators.test.ts
================================================
import * as T from '../constants';
import actionCreators from '../actionCreators';
describe('blogPost actionCreators', () => {
it('should have a type of INPUT', () => {
const input = 'bar';
const expected = { type: T.INPUT, input };
expect(actionCreators.input(input)).toEqual(expected);
});
});
================================================
FILE: packages/docs/src/client/containers/BlogPost/__tests__/index.test.tsx
================================================
import MockProvider, { getMockStore } from 'redux-mock-provider';
import { shallowToJson } from 'enzyme-to-json';
import { shallow } from 'enzyme';
import * as React from 'react';
import { initialState } from '../state';
import BlogPost from '../';
import BlogPostPresentation from '../presentation';
import props from './__mocks__/blogPostPresentation.mock';
import colors from '../../../theming';
const store = getMockStore({
key: 'blogPost',
state: initialState,
});
describe('<BlogPost /> container', () => {
it('should render as expected', () => {
const wrapper = shallow(
<MockProvider store={store}>
<BlogPost />
</MockProvider>,
);
expect(shallowToJson(wrapper)).toMatchSnapshot();
});
});
describe('<BlogPostPresentation />', () => {
it('should render as expected', () => {
const wrapper = shallow(
<BlogPostPresentation {...props} theme={colors} />,
);
expect(shallowToJson(wrapper)).toMatchSnapshot();
});
});
================================================
FILE: packages/docs/src/client/containers/BlogPost/__tests__/reducer.test.ts
================================================
import reducer from '../reducer';
import actionCreators from '../actionCreators';
import { initialState } from '../state';
describe('blogPost reducer', () => {
it('should handle reducer for INPUT', () => {
const input = 'foo';
const stateBefore = initialState;
const stateAfter = {
...initialState,
input,
};
expect(
reducer(stateBefore, actionCreators.input(input)),
).toEqual(stateAfter);
});
});
================================================
FILE: packages/docs/src/client/containers/BlogPost/__tests__/selectors.test.ts
================================================
import state from './__mocks__/blogPostSelectors.mock';
import { initialState as globalState } from '../../../state';
import { selectInput } from '../selectors';
let mockState;
describe('blogPost selectors', () => {
beforeEach(() => {
mockState = {
...globalState,
blogPost: state.blogPost,
};
});
describe('select input', () => {
it('should select an empty string', () => {
expect(
selectInput(globalState),
).toEqual('');
});
it('should select input', () => {
expect(
selectInput(mockState),
).toEqual(state.blogPost.input);
});
});
});
================================================
FILE: packages/docs/src/client/containers/BlogPost/actionCreators.ts
================================================
import { ActionCreator, ActionCreatorsMapObject } from 'redux';
import { Input } from './types';
import * as types from './constants';
import {
InputAction,
} from './actions';
type InputActionCreator = ActionCreator<InputAction>;
export const input: InputActionCreator = (input: Input) => ({
type: types.INPUT,
input,
});
export interface ActionCreatorTypes extends ActionCreatorsMapObject {
input: InputActionCreator;
}
export const actionCreators: ActionCreatorTypes = {
input,
};
export default actionCreators;
================================================
FILE: packages/docs/src/client/containers/BlogPost/actions.ts
================================================
import { Action } from 'redux';
import { Input } from './types';
import * as T from './constants';
export interface InputAction extends Action {
type: T.INPUT_TYPE;
input: Input;
}
export type ActionTypes = InputAction;
================================================
FILE: packages/docs/src/client/containers/BlogPost/apollo.ts
================================================
import { graphql } from 'react-apollo';
import BlogPost from './';
import PostQuery from './postQuery.graphql';
import CommentMutation from './commentMutation.graphql';
export const withData = graphql(PostQuery, {
skip: ({ params }) => !params || (params && !params.postId),
options: ({ params }) => ({
variables: {
id: params.postId,
},
}),
props: ({ data: { loading, post, error, refetch } }) => ({
loading,
post,
error,
refetch,
}),
});
export const withMutation = graphql(CommentMutation, {
props: ({ mutate }) => ({
submitComment: mutate,
}),
});
const withApollo = (component: typeof BlogPost): typeof BlogPost =>
withData(withMutation(component));
export default withApollo;
================================================
FILE: packages/docs/src/client/containers/BlogPost/commentMutation.graphql.ts
================================================
import gql from 'graphql-tag';
export default gql`
mutation CreateComment($post: ID!, $body: String, $author: String) {
createComment(data:{ post: $post, body: $body, author: $author })
}
`;
================================================
FILE: packages/docs/src/client/containers/BlogPost/constants.ts
================================================
export type INPUT_TYPE = 'BLOG_POST/INPUT';
export const INPUT: INPUT_TYPE = 'BLOG_POST/INPUT';
================================================
FILE: packages/docs/src/client/containers/BlogPost/index.tsx
================================================
import * as React from 'react';
import { Dispatch, bindActionCreators } from 'redux';
import { connect } from 'react-redux';
import { FormControlEventTarget } from '../../types';
import BlogPresentation from './presentation';
import { ThemeColorMap } from '../../types';
import { Props, ActionCreatorTypes, ActionTypes, Input, ErrorType, Post, SubmitComment } from './types';
import { State } from '../../state';
import { selectInput } from './selectors';
import actionCreators from './actionCreators';
import withApollo from './apollo';
import { withTheme } from 'styled-components';
type MapStateToProps = (state: State) => StateProps;
const mapStateToProps: MapStateToProps = (state) => ({
input: selectInput(state),
});
type MapDispatch = (dispatch: Dispatch<ActionTypes>) => DispatchProps;
const mapDispatchToProps: MapDispatch = (dispatch) => ({
actions: bindActionCreators(
actionCreators,
dispatch,
),
});
export interface Props {
loading: boolean;
error?: ErrorType;
post?: Post;
theme: ThemeColorMap;
submitComment?: SubmitComment;
refetch: () => void;
params: {
postId: String;
};
}
export interface StateProps {
input: Input,
}
export interface DispatchProps {
actions: ActionCreatorTypes;
}
export type PropTypes = StateProps & DispatchProps & Props;
class BlogPost extends React.Component<PropTypes, undefined> {
constructor() {
super();
this.handleAddingComment = this.handleAddingComment.bind(this);
this.handleInput = this.handleInput.bind(this);
this.handleEnterKeyUp = this.handleEnterKeyUp.bind(this);
}
private handleInput(e: React.SyntheticEvent<undefined>) {
e.preventDefault();
const input = (e.target as FormControlEventTarget).value;
this.props.actions.input(input);
}
private handleAddingComment() {
const { input } = this.props;
const author = 'Unknown';
const { postId } = this.props.params;
const variables = {
post: postId as string,
author,
body: input,
};
this.props.submitComment({ variables }).then(() => {
this.props.refetch();
this.props.actions.input('');
});
}
private handleEnterKeyUp(e: React.KeyboardEvent<undefined>) {
if (e.keyCode === 13) {
e.preventDefault();
this.handleAddingComment();
}
}
public render() {
return (
<BlogPresentation
onChange={this.handleInput}
onSubmit={this.handleAddingComment}
onKeyUp={this.handleEnterKeyUp}
{...this.props}
/>
);
}
}
const ComponentWithData = withApollo(BlogPost);
const ComponentWithTheme = withTheme(ComponentWithData as typeof BlogPost);
export default connect(
mapStateToProps,
mapDispatchToProps,
)(ComponentWithTheme);
================================================
FILE: packages/docs/src/client/containers/BlogPost/postQuery.graphql.ts
================================================
import gql from 'graphql-tag';
export default gql`
query Post($id: ID!) {
post(id: $id) {
id: _id
title
image
content
comments {
body
author
}
}
}
`;
================================================
FILE: packages/docs/src/client/containers/BlogPost/presentation.tsx
================================================
import * as React from 'react';
import { Post } from 'components';
import { LoadingIndicator, Section, Notification } from 'openui';
import { ErrorType, Post as PostType, OnInput, OnSubmit, OnKeyUp } from './types';
import { ThemeColorMap } from '../../types';
export interface Props {
onChange: OnInput;
onSubmit: OnSubmit;
onKeyUp: OnKeyUp;
loading: boolean;
post: PostType;
error: ErrorType;
input: string;
theme: ThemeColorMap;
}
export default class BlogPostPresentation extends React.Component<Props, undefined> {
public render() {
const { loading, post, error, theme, ...rest } = this.props;
return (
<Section
alignItems="center"
flexDirection="column"
pad={{ vertical: 'large', horizontal: 'small' }}
full={{ vertical: true }}
backgroundColor={theme.offwhite}
>
{error && <Notification status="error" message={error.message} />}
<LoadingIndicator isLoading={loading} />
{post &&
<Post
comment={{...rest}}
{...post}
/>
}
</Section>
);
}
}
================================================
FILE: packages/docs/src/client/containers/BlogPost/reducer.ts
================================================
import { Reducer } from 'redux';
import * as T from './constants';
import { ActionTypes } from './actions';
import { State, initialState } from './state';
const reducer: Reducer<State> = (state: State = initialState, action: ActionTypes) => {
switch (action.type) {
case T.INPUT:
return {
...state,
input: action.input,
};
default:
return state;
}
};
export default reducer;
================================================
FILE: packages/docs/src/client/containers/BlogPost/selectors.ts
================================================
import { createSelector, Selector } from 'reselect';
import { State } from '../../state';
import { State as BlogPostState } from './types';
const selectBlogPost = () => (state: State): BlogPostState => state.blogPost;
export const selectInput: Selector<State, string> = createSelector(
selectBlogPost(),
(blogPost) => blogPost.input,
);
================================================
FILE: packages/docs/src/client/containers/BlogPost/state.ts
================================================
import { Input } from './types';
export interface State {
input?: Input;
}
export const initialState: State = {
input: '',
};
export default State;
================================================
FILE: packages/docs/src/client/containers/BlogPost/styles.ts
================================================
import styled from 'styled-components';
export const StyledHr = styled.hr`
border-top: 4px solid;
`;
================================================
FILE: packages/docs/src/client/containers/BlogPost/types.ts
================================================
import * as React from 'react';
import { Props } from './';
import { Props as PresentationProps } from './presentation';
import { State } from './state';
import { ActionCreatorTypes } from './actionCreators';
import { ActionTypes } from './actions';
export { Props, PresentationProps, State, ActionCreatorTypes, ActionTypes };
export type OnInput = (e: React.SyntheticEvent<undefined>) => void;
export type OnSubmit = () => void;
export type OnKeyUp = (e: React.KeyboardEvent<undefined>) => void;
export interface PostComment {
body: string;
author: string;
}
export interface Post {
id: string;
title: string;
image: string;
content: string;
comments: PostComment[];
}
export interface ErrorType { message: string; }
export type Input = string;
export type Body = string;
export type Author = string;
export type PostId = string;
export interface PostSubmission {
variables: {
body: Body;
author: Author;
post: PostId;
}
};
export type SubmitComment = (post: PostSubmission) => Promise<undefined>;
================================================
FILE: packages/docs/src/client/containers/Docs/__tests__/__mocks__/docsMocks.mock.ts
================================================
export default {
pad: 'medium',
size: 'large',
};
================================================
FILE: packages/docs/src/client/containers/Docs/__tests__/__snapshots__/index.test.tsx.snap
================================================
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`DocsContainer should render with default props 1`] = `<Connect(Feature) />`;
================================================
FILE: packages/docs/src/client/containers/Docs/__tests__/actionCreators.test.ts
================================================
import * as types from '../constants';
import { actionCreators } from '../actionCreators';
// Action Creator Test as a rule return very little value. Focus on tests that give more value first
describe('docs actionCreators', () => {
it('properly creates LOAD_INTIATION action', () => {
expect(actionCreators.loadInitiation(),
).toEqual({
type: types.LOAD_INITIATION,
});
});
it('properly creates LOAD_SUCCESS action', () => {
const testData: string = 'test string';
expect(actionCreators.loadSuccess(testData),
).toEqual({
type: types.LOAD_SUCCESS,
payload: testData,
});
});
it('properly creates LOAD_INTIATION action', () => {
expect(actionCreators.loadCancel(),
).toEqual({
type: types.LOAD_CANCEL,
});
});
it('properly creates LOAD_SUCCESS action', () => {
const testMessage: string = 'test error Message';
expect(actionCreators.loadFailure(testMessage),
).toEqual({
type: types.LOAD_FAILURE,
error: testMessage,
});
it('properly creates LOAD_SUCCESS action', () => {
expect(actionCreators.clearError(),
).toEqual({
type: types.CLEAR_ERROR,
});
});
});
});
================================================
FILE: packages/docs/src/client/containers/Docs/__tests__/index.test.tsx
================================================
import * as React from 'react';
import { Provider } from 'react-redux';
import { Store } from 'redux';
import { shallow } from 'enzyme';
import { shallowToJson } from 'enzyme-to-json';
import DocsContainer from '../';
import State from '../state';
import mockStore from '../../../test/mockstore';
const testState: State = {
error: null,
isLoading: false,
markdownContent: '',
};
describe('DocsContainer ', () => {
let store: Store<State>;
beforeEach(() => {
store = mockStore(testState);
});
it('should render with default props', () => {
const wrapper = shallow(
<Provider store={store}>
<DocsContainer/>
</Provider>,
);
expect(shallowToJson(wrapper)).toMatchSnapshot();
});
});
================================================
FILE: packages/docs/src/client/containers/Docs/__tests__/logic.test.ts
================================================
import { createMockStore } from 'redux-logic-test';
import * as actionTypes from '../constants';
import rootLogic from '../logic';
const dependencies = {
httpClient: { // simulate an async fetch
get(url) { return Promise.resolve({ data: 'testData' }); },
},
};
describe('rootLogic tests', () => {
describe('rootLogic test without reducers', () => {
let store;
beforeEach(() => {
store = createMockStore({
logic: rootLogic,
injectedDeps: dependencies,
});
});
it('should do something', (done) => {
store.dispatch({ type: actionTypes.LOAD_INITIATION });
store.whenComplete(() => {
expect(store.actions).toEqual([
{ type: actionTypes.LOAD_INITIATION },
{ type: actionTypes.LOAD_SUCCESS, payload: 'testData' },
]);
done();
});
});
});
});
================================================
FILE: packages/docs/src/client/containers/Docs/__tests__/reducer.test.ts
================================================
import reducer from '../reducer';
import { actionCreators } from '../actionCreators';
import { initialState } from '../state';
describe('docs reducer', () => {
it('should return the initial state with default action', () => {
expect(
reducer(undefined, actionCreators.defaultAction()),
).toEqual(initialState);
});
it('should handle LOAD_INTIATION', () => {
expect(
reducer(initialState, actionCreators.loadInitiation()).isLoading,
).toEqual(true);
});
it('should handle LOAD_SUCCESS', () => {
const testData: string = 'test string';
expect(
reducer(initialState, actionCreators.loadSuccess(testData)).markdownContent,
).toEqual(testData);
});
it('should handle LOAD_FAILURE', () => {
const testMessage: string = 'test error message';
expect(
reducer(initialState, actionCreators.loadFailure(testMessage)).error,
).toEqual(testMessage);
});
it('should handle LOAD_CANCEL', () => {
expect(
reducer(initialState, actionCreators.loadCancel()).isLoading,
).toEqual(false);
});
});
================================================
FILE: packages/docs/src/client/containers/Docs/__tests__/selectors.test.ts
================================================
import { selectIsLoading, selectError } from '../selectors';
import { State } from '../../../State';
const testError: string = 'some error';
const testMarkDown: string = '#Test Markdown';
const testState: State = {
app: {},
todoApp: null,
blogPost: null,
docs: {
error: null,
isLoading: false,
markdownContent: null,
},
};
const testState2: State = {
app: {},
todoApp: null,
blogPost: null,
docs: {
error: testError,
isLoading: true,
markdownContent: testMarkDown,
},
};
describe('docs selectors', () => {
describe('docs selectIsLoading', () => {
it('should return false', () => {
expect(
selectIsLoading(testState))
.toBe(false);
});
it('should return true', () => {
expect(
selectIsLoading(testState2))
.toBe(true);
});
});
describe('docs selectError', () => {
it('should return null', () => {
expect(
selectError(testState))
.toBe(null);
});
it('should return string', () => {
expect(
selectIsLoading(testState2))
.toBe(true);
});
});
describe('docs selectMarkdownContent', () => {
it('should return null', () => {
expect(
selectError(testState))
.toBe(null);
});
it('should return string', () => {
expect(
selectIsLoading(testState2))
.toBe(true);
});
});
});
================================================
FILE: packages/docs/src/client/containers/Docs/actionCreators.ts
================================================
import * as types from './constants';
import { defaultAction } from 'shared/actionCreators';
import {
LoadInitiationAction,
LoadSuccessAction,
LoadFailureAction,
LoadCancelAction,
ClearErrorAction,
} from './actions';
export const loadInitiation = (): LoadInitiationAction => ({
type: types.LOAD_INITIATION,
});
export const loadSuccess = (data: string): LoadSuccessAction => ({
type: types.LOAD_SUCCESS,
payload: data,
});
export const loadFailure = (error: string): LoadFailureAction => ({
type: types.LOAD_FAILURE,
error,
});
export const loadCancel = (): LoadCancelAction => ({
type: types.LOAD_CANCEL,
});
export const clearError = (): ClearErrorAction => ({
type: types.CLEAR_ERROR,
});
export const actionCreators = {
loadInitiation,
loadSuccess,
loadFailure,
loadCancel,
clearError,
defaultAction,
};
export default actionCreators;
================================================
FILE: packages/docs/src/client/containers/Docs/actions.ts
================================================
import { DefaultAction } from 'shared/actions';
import * as types from './constants';
import { Action } from 'redux';
export interface LoadInitiationAction extends Action {
type: types.LOAD_INITIATION_TYPE;
}
export interface LoadSuccessAction extends Action {
type: types.LOAD_SUCCESS_TYPE;
payload: string;
}
export interface LoadFailureAction extends Action {
type: types.LOAD_FAILURE_TYPE;
error: string;
}
export interface LoadCancelAction extends Action {
type: types.LOAD_CANCEL_TYPE;
}
export interface ClearErrorAction extends Action {
type: types.CLEAR_ERROR_TYPE;
}
export type FeatureAction =
LoadInitiationAction |
LoadSuccessAction |
LoadFailureAction |
LoadCancelAction |
ClearErrorAction |
DefaultAction;
================================================
FILE: packages/docs/src/client/containers/Docs/constants.ts
================================================
export type LOAD_INITIATION_TYPE = 'DOCS/LOAD_INITIATION';
export const LOAD_INITIATION: LOAD_INITIATION_TYPE = 'DOCS/LOAD_INITIATION';
export type LOAD_SUCCESS_TYPE = 'DOCS/LOAD_SUCCESS';
export const LOAD_SUCCESS: LOAD_SUCCESS_TYPE = 'DOCS/LOAD_SUCCESS';
export type LOAD_FAILURE_TYPE = 'DOCS/LOAD_FAILURE';
export const LOAD_FAILURE: LOAD_FAILURE_TYPE = 'DOCS/LOAD_FAILURE';
export type LOAD_CANCEL_TYPE = 'DOCS/LOAD_CANCEL';
export const LOAD_CANCEL: LOAD_CANCEL_TYPE = 'DOCS/LOAD_CANCEL';
export type CLEAR_ERROR_TYPE = 'DOCS/CLEAR_ERROR';
export const CLEAR_ERROR: CLEAR_ERROR_TYPE = 'DOCS/CLEAR_ERROR';
================================================
FILE: packages/docs/src/client/containers/Docs/index.tsx
================================================
import * as React from 'react';
import { connect } from 'react-redux';
import { bindActionCreators, Dispatch } from 'redux';
import { State } from '../../state';
import actionCreators from './actionCreators';
import { selectError, selectIsLoading, selectMarkdownContent } from './selectors';
import Feature, { StateProps, DispatchProps } from './presentation';
import { FeatureAction } from './actions';
// tslint:disable-next-line
interface OwnProps { }; // for props that are not passed down to inner component
const mapStateToProps = (state: State): StateProps => ({
error: selectError(state),
markdownContent: selectMarkdownContent(state),
isLoading: selectIsLoading(state),
});
const mapDispatchToProps = (dispatch: Dispatch<FeatureAction>): DispatchProps => ({
actions: bindActionCreators(
actionCreators,
dispatch,
),
});
const Container: React.ComponentClass<OwnProps> = connect(
mapStateToProps,
mapDispatchToProps,
)(Feature);
export default Container;
================================================
FILE: packages/docs/src/client/containers/Docs/logic.ts
================================================
import { createLogic } from 'redux-logic';
import * as actionTypes from './constants';
const url = 'https://raw.githubusercontent.com/RyanCCollins/scalable-react-ts-boilerplate/master/README.md';
export const fetchLogic = createLogic({
type: actionTypes.LOAD_INITIATION,
cancelType: actionTypes.LOAD_CANCEL,
latest: true, // take latest only
processOptions: {
dispatchReturn: true,
successType: actionTypes.LOAD_SUCCESS,
failType: actionTypes.LOAD_FAILURE,
},
process({ httpClient }) {
return httpClient.get(url)
.then((response) => response.data);
},
});
export default [
fetchLogic,
];
================================================
FILE: packages/docs/src/client/containers/Docs/presentation.tsx
================================================
import * as React from 'react';
import { Article, Headline, LoadingIndicator, Section, Notification } from 'openui';
import Hr from './styles';
import { State } from './state';
import {
LoadInitiationAction,
LoadSuccessAction,
LoadFailureAction,
ClearErrorAction,
} from './actions';
export type StateProps = State;
export interface DispatchProps {
actions: {
loadInitiation: () => LoadInitiationAction,
loadSuccess: (data: string) => LoadSuccessAction,
loadFailure: (error: string) => LoadFailureAction,
clearError: () => ClearErrorAction,
};
}
export type FeatureProps = React.Props<Feature> & StateProps & DispatchProps;
export default class Feature extends React.Component<FeatureProps, undefined> {
constructor(props) {
super(props);
const { markdownContent } = props;
if (markdownContent === null) {
this.props.actions.loadInitiation();
}
};
public render() {
const {
markdownContent,
isLoading,
error,
actions,
} = this.props;
return (
<Section
alignItems="center"
flexDirection="column"
pad="medium"
full={{ vertical: true }}
backgroundColor="#f5f5f5"
>
<Headline fontWeight={700}>
Docs
<Hr />
</Headline>
{error &&
<Notification
status="error"
onClick={actions.clearError}
message={error}
/>
}
<LoadingIndicator isLoading={isLoading} />
{typeof markdownContent === 'string' &&
<Article
pad="large"
boxSize={{ horizontal: 'xxlarge' }}
margin={{ vertical: 'large' }}
backgroundColor="#FFF"
content={markdownContent}
/>
}
</Section>
);
}
}
================================================
FILE: packages/docs/src/client/containers/Docs/reducer.ts
================================================
import { Reducer } from 'redux';
import * as types from './constants';
import { FeatureAction } from './actions';
import { defaultAction } from 'shared/actionCreators';
import { State, initialState } from './state';
const reducer: Reducer<State> = (state: State = initialState, action: FeatureAction = defaultAction()) => {
switch (action.type) {
case types.LOAD_INITIATION:
return {
...state,
isLoading: true,
};
case types.LOAD_SUCCESS:
return {
...state,
isLoading: false,
markdownContent: action.payload,
};
case types.LOAD_FAILURE:
return {
...state,
isLoading: false,
error: action.error,
};
case types.CLEAR_ERROR:
return {
...state,
error: null,
};
case types.LOAD_CANCEL:
return {
...state,
isLoading: false,
};
default:
return state;
}
};
export default reducer;
================================================
FILE: packages/docs/src/client/containers/Docs/selectors.ts
================================================
import { createSelector, Selector } from 'reselect';
import { State } from 'state';
import { State as FeatureState } from './state';
const selectFeature = () => (state: State): FeatureState => state.docs;
export const selectError: Selector<State, string> = createSelector(
selectFeature(),
(feature) => feature.error,
);
export const selectIsLoading: Selector<State, boolean> = createSelector(
selectFeature(),
(feature) => feature.isLoading,
);
export const selectMarkdownContent: Selector<State, string> = createSelector(
selectFeature(),
(feature) => feature.markdownContent,
);
================================================
FILE: packages/docs/src/client/containers/Docs/state.ts
================================================
export interface State {
markdownContent?: string;
error?: string;
isLoading: boolean;
}
export const initialState: State = {
markdownContent: null,
error: null,
isLoading: false,
};
export default State;
================================================
FILE: packages/docs/src/client/containers/Docs/styles.ts
================================================
import styled from 'styled-components';
export default styled.hr`
border-top: 4px solid;
`;
================================================
FILE: packages/docs/src/client/containers/Docs/types.ts
================================================
export { actionCreators } from './actionCreators';
export * from './actions';
export * from './constants';
export * from './index';
export { FeatureProps } from './presentation';
export { State } from './state';
================================================
FILE: packages/docs/src/client/containers/Features/features.ts
================================================
// tslint:disable
export default {
styledComponents: `__Visual Primitives for the component age.__
Use the best bits of ES6 to style your apps without stress! \`styled-components\` allows you to write actual CSS code to style your components.
It also removes the mapping between components and styles – using components as a low-level styling construct could not be easier!`,
featureFirst: `__Component based file organization.__
Code reuse has _never_ been easier. Organizing your UI components by feature, rather than file-type, will help you to reuse code and facilitates building of UI component libraries.
We've included component / container generators for you to easily get started using the feature-first architecture. Try it __now__ and thank us later!`,
typeScript: `TypeScript is a _typed superset_ of JavaScript that compiles to plain JavaScript!
TypeScript allows you to write the JavaScript you are used to while adding type annotiations that provide you with powerful static analysis.
It helps to [bridge the gap](https://medium.com/@ryancollinsio/bridging-the-gap-between-elm-and-javascript-with-typescript-375771ebcd4c#.64jw0aqki) between JavaScript and a fully functional language, such as Elm.`,
};
================================================
FILE: packages/docs/src/client/containers/Features/index.tsx
================================================
import * as React from 'react';
import { Heading, Headline, Image, Button, Markdown, Anchor } from 'openui';
import { Props } from './types';
import {
Container,
FeatureImage,
Card,
FeaturesSection,
Feature,
FeatureSectionInner,
} from './styles';
import features from './features';
import { withTheme } from 'styled-components';
class Features extends React.Component<Props, undefined> {
public render() {
const { theme } = this.props;
return (
<Container>
<FeaturesSection id="features-section-one" background="#f3f3f3">
<Headline>
Features
</Headline>
<FeatureSectionInner>
<Feature>
<Image
imageSize="small"
alt="Type-Script Logo"
src="https://raw.githubusercontent.com/RyanCCollins/cdn/master/stsb-images/ts-resized-2.png"
/>
</Feature>
<Feature>
<Card>
<Heading textAlign="left" color="black">TypeScript</Heading>
<Markdown
content={features.typeScript}
/>
<Anchor
color="#fff"
href="http://www.typescriptlang.org/docs/tutorial.html"
>
<Button color={theme.secondary}>
View Website
</Button>
</Anchor>
</Card>
</Feature>
</FeatureSectionInner>
</FeaturesSection>
<FeaturesSection id="features-section-two" background="#e6e8ec">
<FeatureSectionInner reverse>
<Feature>
<Card>
<Heading textAlign="left" color="black">Styled Components</Heading>
<Markdown
content={features.styledComponents}
/>
<Anchor
color="#fff"
href="https://styled-components.com/"
>
<Button color="#c05b4d">
View Website
</Button>
</Anchor>
</Card>
</Feature>
<Feature>
<Image
imageSize="small"
alt="Styled-components logo"
src="https://github.com/RyanCCollins/cdn/blob/master/stsb-images/sc.png?raw=true"
/>
</Feature>
</FeatureSectionInner>
<FeatureImage>
<Image
imageSize="small"
alt="Styled-components example"
src="https://github.com/RyanCCollins/cdn/blob/master/stsb-images/sc-example.png?raw=true"
/>
</FeatureImage>
</FeaturesSection>
<FeaturesSection id="features-section-three" background="#f3f3f3">
<FeatureSectionInner>
<Feature>
<Image
imageSize="small"
alt="feature-first logo"
src="https://github.com/RyanCCollins/cdn/blob/master/stsb-images/feature-first.png?raw=true"
/>
</Feature>
<Feature>
<Card>
<Heading textAlign="left" color="black">Feature First</Heading>
<Markdown
content={features.featureFirst}
/>
</Card>
</Feature>
</FeatureSectionInner>
<FeatureImage>
<Image
imageSize="medium"
alt="feature-first example"
src="https://github.com/RyanCCollins/cdn/blob/master/stsb-images/feature-first-example.png?raw=true"
/>
</FeatureImage>
</FeaturesSection>
</Container>
);
}
}
export default withTheme(Features);
================================================
FILE: packages/docs/src/client/containers/Features/styles.ts
================================================
import styled from 'styled-components';
export const Container = styled.div`
min-height: 100vh;
width: 100vw;
`;
interface FeaturesSectionProps {
background: string
}
export const FeaturesSection = styled.section`
width: 100%;
background: ${(props: FeaturesSectionProps) => props.background}
display: flex;
flex-direction: column;
align-items: center;
`;
interface FeatureSectionInnerProps {
reverse?: boolean;
}
export const FeatureSectionInner = styled.div`
display: flex;
flex-direction: row;
max-width: 1000px;
padding: 60px 120px;
@media screen and (max-width: 768px) {
flex-wrap: ${(props: FeatureSectionInnerProps) => props.reverse ? 'wrap-reverse' : 'wrap'};
padding: 60px 20px;
padding-top:
}
`;
export const Feature = styled.div`
flex-basis: 50%;
display: flex;
justify-content: center;
margin: 20px;
min-width: 300px;
@media screen and (max-width: 768px) {
max-width: 100vw !important;
flex-basis: 100%;
}
`;
export const Card = styled.div`
max-width: 540px;
h1 {
margin-top: 0 !important;
}
`;
export const FeatureImage = styled.div`
width: 100%;
display: flex;
justify-content: center;
padding: 60px;
`;
================================================
FILE: packages/docs/src/client/containers/Features/types.ts
================================================
import Features from './';
import * as React from 'react';
import { ThemeColorMap } from '../../types';
export interface Props extends React.Props<typeof Features> {
theme?: ThemeColorMap;
}
================================================
FILE: packages/docs/src/client/containers/Home/index.tsx
================================================
import * as React from 'react';
import { Features } from 'containers';
import { ThemeColorMap } from '../../types';
import HomePresentation from './presentation';
import { withTheme } from 'styled-components';
export interface Props { theme: ThemeColorMap; }
class Home extends React.Component<Props, undefined> {
public render() {
return (
<HomePresentation theme={this.props.theme}>
<Features />
</HomePresentation>
);
}
}
export default withTheme(Home);
================================================
FILE: packages/docs/src/client/containers/Home/presentation.tsx
================================================
import * as React from 'react';
import { Heading, Section, Hero, Paragraph, Button, Anchor, Box } from 'openui';
import { Container, HeroLogo, HeroLogoRow, HeadingContainer, GetStartedButtons } from './styles';
import { Props as HomeProps } from './types';
export interface Props extends HomeProps {
children?: JSX.Element;
}
export default function HomePresentation({
children,
theme,
}: Props): JSX.Element {
return (
<Container>
<Section
alignItems="center"
flexDirection="column"
full={{ horizontal: true }}
backgroundColor={theme.offwhite}
>
<Hero backgroundColor={theme.black2}>
<HeroLogoRow>
<HeroLogo>
TS
</HeroLogo>
</HeroLogoRow>
<HeadingContainer>
<Heading margin="small" tag="h1" color={theme.primary}>
Scalable React TypeScript Boilerplate
</Heading>
<Paragraph margin="small" paragraphSize="large">
Scaling JavaScript apps has never been easier
</Paragraph>
</HeadingContainer>
<GetStartedButtons>
<Box margin="small">
<Anchor
plain
color={theme.white1}
path="/docs"
>
<Button
fontSize="xlarge"
backgroundColor={theme.secondary}
>
Read the docs
</Button>
</Anchor>
</Box>
<Box margin="small">
<Anchor
plain
color={theme.white1}
path="/todo-app"
>
<Button
style={{ margin: 10 }}
fontSize="xlarge"
backgroundColor={theme.secondary}
>
View Example App
</Button>
</Anchor>
</Box>
</GetStartedButtons>
</Hero>
</Section>
{children}
</Container>
);
}
================================================
FILE: packages/docs/src/client/containers/Home/styles.ts
================================================
import styled from 'styled-components';
export const Container = styled.div`
min-height: 100vh;
width: 100vw;
`;
export const HeroLogo = styled.div`
margin-bottom: 20px;
justify-content: center;
height: 100px;
width: 100px;
background: #007acc;
color: white;
font-size: 68px;
`;
export const HeroLogoRow = styled.div`
width: 100%;
display: flex;
align-items: center;
justify-content: center;
`;
export const HeadingContainer = styled.div`
display: flex;
align-items: center;
flex-direction: column;
padding: 20px;
`;
export const GetStartedButtons = styled.div`
display: flex;
align-items: center;
justify-content: center;
flex-direction: row;
@media screen and (max-width: 768px) {
flex-direction: column;
}
`;
================================================
FILE: packages/docs/src/client/containers/Home/types.ts
================================================
import { Props } from './';
import { Props as PresentationProps } from './presentation';
export { Props, PresentationProps };
================================================
FILE: packages/docs/src/client/containers/TodoApp/__tests__/__mocks__/presentation.mock.ts
================================================
export default {
todos: [
{
text: 'foo',
},
{
text: 'bar',
},
],
input: 'foo',
onInput: jest.fn(),
onAddition: jest.fn(),
onDeletion: jest.fn(),
};
================================================
FILE: packages/docs/src/client/containers/TodoApp/__tests__/__mocks__/selectors.mock.ts
================================================
export default {
todoApp: {
todos: [
{
text: 'LOL',
},
{
text: '🐒🚀',
},
],
input: 'Money',
},
};
================================================
FILE: packages/docs/src/client/containers/TodoApp/__tests__/__snapshots__/index.test.tsx.snap
================================================
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`<TodoApp /> container should render as expected 1`] = `
<Provider
store={
Object {
"clearActions": [Function],
"dispatch": [Function],
"getActions": [Function],
"getState": [Function],
"replaceReducer": [Function],
"subscribe": [Function],
}
}
>
<Connect(TodoApp) />
</Provider>
`;
exports[`<TodoAppPresentation /> should render as expected 1`] = `
<styled.div>
<styled.h1>
Example Todo App
</styled.h1>
<styled.div>
<styled.section>
<styled.header>
<styled.input
autoFocus={true}
onChange={[Function]}
onKeyPress={[Function]}
placeholder="Start typing to add a Todo..."
value="foo"
/>
</styled.header>
<styled.section>
<styled.ul>
<styled.li>
<styled.label>
foo
</styled.label>
<styled.button
onClick={[Function]}
/>
</styled.li>
<styled.li>
<styled.label>
bar
</styled.label>
<styled.button
onClick={[Function]}
/>
</styled.li>
</styled.ul>
</styled.section>
</styled.section>
</styled.div>
</styled.div>
`;
================================================
FILE: packages/docs/src/client/containers/TodoApp/__tests__/actionCreators.test.ts
================================================
import * as T from '../constants';
import actionCreators from '../actionCreators';
describe('todoApp actionCreators', () => {
it('should have a type of ADD_TODO', () => {
const todo = { text: 'foo' };
const expected = { type: T.ADD_TODO, todo };
expect(actionCreators.addTodo(todo)).toEqual(expected);
});
it('should have a type of INPUT', () => {
const input = 'bar';
const expected = { type: T.INPUT, input };
expect(actionCreators.input(input)).toEqual(expected);
});
it('should have a type of DELETE_TODO', () => {
const index = 1;
const expected = { type: T.DELETE_TODO, index };
expect(actionCreators.deleteTodo(index)).toEqual(expected);
});
});
================================================
FILE: packages/docs/src/client/containers/TodoApp/__tests__/index.test.tsx
================================================
import MockProvider, { getMockStore } from 'redux-mock-provider';
import { shallowToJson } from 'enzyme-to-json';
import { shallow } from 'enzyme';
import * as React from 'react';
import { initialState } from '../state';
import TodoAppContainer from '../';
import TodoAppPresentation from '../presentation';
import props from './__mocks__/presentation.mock';
const store = getMockStore({
key: 'todoApp',
state: initialState,
});
describe('<TodoApp /> container', () => {
it('should render as expected', () => {
const wrapper = shallow(
<MockProvider store={store}>
<TodoAppContainer />
</MockProvider>,
);
expect(shallowToJson(wrapper)).toMatchSnapshot();
});
});
describe('<TodoAppPresentation />', () => {
it('should render as expected', () => {
const wrapper = shallow(
<TodoAppPresentation {...props} />,
);
expect(shallowToJson(wrapper)).toMatchSnapshot();
});
});
================================================
FILE: packages/docs/src/client/containers/TodoApp/__tests__/reducer.test.ts
================================================
import reducer from '../reducer';
import actionCreators from '../actionCreators';
import { initialState } from '../state';
describe('todo app reducer', () => {
it('should handle reducer for ADD_TODO', () => {
const todos = [
{
text: 'bar',
},
];
const todo = { text: 'foo' };
const stateBefore = {
...initialState,
todos,
};
const stateAfter = {
...initialState,
todos: [
...todos,
todo,
],
};
expect(
reducer(stateBefore, actionCreators.addTodo(todo)),
).toEqual(stateAfter);
});
it('should handle reducer for DELETE_TODO', () => {
const todos = [
{
text: 'bar',
},
];
const index = 0;
const stateBefore = {
...initialState,
todos,
};
const stateAfter = {
...initialState,
todos: [],
};
expect(
reducer(stateBefore, actionCreators.deleteTodo(index)),
).toEqual(stateAfter);
});
it('should handle reducer for INPUT', () => {
const input = 'foo';
const stateBefore = initialState;
const stateAfter = {
...initialState,
input,
};
expect(
reducer(stateBefore, actionCreators.input(input)),
).toEqual(stateAfter);
});
});
================================================
FILE: packages/docs/src/client/containers/TodoApp/__tests__/selectors.test.ts
================================================
import state from './__mocks__/selectors.mock';
import { initialState as globalState } from '../../../state';
import { selectTodos, selectInput } from '../selectors';
let mockState;
describe('todoApp selectors', () => {
beforeEach(() => {
mockState = {
...globalState,
todoApp: state.todoApp,
};
});
describe('select todos', () => {
it('should select an empty array', () => {
expect(
selectTodos(globalState),
).toEqual([]);
});
it('should select two todos', () => {
expect(
selectTodos(mockState),
).toEqual(state.todoApp.todos);
});
});
describe('select input', () => {
it('should select an empty string', () => {
expect(
selectInput(globalState),
).toEqual('');
});
it('should select input', () => {
expect(
selectInput(mockState),
).toEqual(state.todoApp.input);
});
});
});
================================================
FILE: packages/docs/src/client/containers/TodoApp/actionCreators.ts
================================================
import { ActionCreator, ActionCreatorsMapObject } from 'redux';
import { Todo, Input, Index } from './types';
import * as types from './constants';
import {
AddTodoAction,
DeleteTodoAction,
InputAction,
} from './actions';
type AddTodoActionCreator = ActionCreator<AddTodoAction>;
export const addTodo: AddTodoActionCreator = (todo: Todo) => ({
type: types.ADD_TODO,
todo,
});
type InputActionCreator = ActionCreator<InputAction>;
export const input: InputActionCreator = (input: Input) => ({
type: types.INPUT,
input,
});
type DeleteTodoActionCreator = ActionCreator<DeleteTodoAction>;
export const deleteTodo: DeleteTodoActionCreator = (index: Index) => ({
type: types.DELETE_TODO,
index,
});
export interface ActionCreatorTypes extends ActionCreatorsMapObject {
addTodo: AddTodoActionCreator;
input: InputActionCreator;
deleteTodo: DeleteTodoActionCreator;
}
export const actionCreators: ActionCreatorTypes = {
addTodo,
input,
deleteTodo,
};
export default actionCreators;
================================================
FILE: packages/docs/src/client/containers/TodoApp/actions.ts
================================================
import { Action } from 'redux';
import { Todo, Input, Index } from './types';
import * as T from './constants';
export interface AddTodoAction extends Action {
type: T.ADD_TODO_TYPE;
todo: Todo;
}
export interface InputAction extends Action {
type: T.INPUT_TYPE;
input: Input;
}
export interface DeleteTodoAction extends Action {
type: T.DELETE_TODO_TYPE;
index: Index;
}
export type ActionTypes = AddTodoAction | InputAction | DeleteTodoAction;
================================================
FILE: packages/docs/src/client/containers/TodoApp/constants.ts
================================================
export type ADD_TODO_TYPE = 'TODO_APP/ADD_TODO';
export const ADD_TODO: ADD_TODO_TYPE = 'TODO_APP/ADD_TODO';
export type INPUT_TYPE = 'TODO_APP/INPUT';
export const INPUT: INPUT_TYPE = 'TODO_APP/INPUT';
export type DELETE_TODO_TYPE = 'TODO_APP/DELETE_TODO';
export const DELETE_TODO: DELETE_TODO_TYPE = 'TODO_APP/DELETE_TODO';
================================================
FILE: packages/docs/src/client/containers/TodoApp/index.tsx
================================================
import * as React from 'react';
import { Dispatch, bindActionCreators } from 'redux';
import { connect } from 'react-redux';
import { FormControlEventTarget } from '../../types';
import { State } from '../../state';
import actionCreators from './actionCreators';
import Presentation from './presentation';
import { Todo, Input as In, ActionCreatorTypes, ActionTypes, Index } from './types';
import {
selectTodos,
selectInput,
} from './selectors';
const mapStateToProps = (state: State): StateProps => ({
todos: selectTodos(state),
input: selectInput(state),
});
const mapDispatchToProps = (dispatch: Dispatch<ActionTypes>): DispatchProps => ({
actions: bindActionCreators(
actionCreators,
dispatch,
),
});
export interface StateProps extends React.Props<TodoApp> {
todos: Todo[],
input: In,
}
export interface DispatchProps {
actions: ActionCreatorTypes;
}
export type Props = DispatchProps & StateProps;
class TodoApp extends React.Component<Props, undefined> {
constructor() {
super();
this.handleAddition = this.handleAddition.bind(this);
this.handleInput = this.handleInput.bind(this);
this.handleDeletion = this.handleDeletion.bind(this);
}
private handleAddition(e: React.KeyboardEvent<undefined>) {
if (e.key === 'Enter') {
e.preventDefault();
const { input, actions } = this.props;
actions.addTodo({ text: input });
}
}
private handleInput(e: React.SyntheticEvent<undefined>) {
e.preventDefault();
const input = (e.target as FormControlEventTarget).value;
this.props.actions.input(input);
}
private handleDeletion(i: Index) {
this.props.actions.deleteTodo(i);
}
public render() {
return (
<Presentation
todos={this.props.todos}
input={this.props.input}
onInput={this.handleInput}
onAddition={this.handleAddition}
onDeletion={this.handleDeletion}
/>
);
}
}
export default connect(
mapStateToProps,
mapDispatchToProps,
)(TodoApp);
================================================
FILE: packages/docs/src/client/containers/TodoApp/presentation.tsx
================================================
import * as React from 'react';
import { StateProps } from './types';
import {
Container,
DeleteButton,
Section,
Input,
Header,
InnerContainer,
Ul,
Li,
Todos,
Todo as TodoLabel,
H1,
} from './styles';
interface Props extends StateProps {
onInput: React.EventHandler<React.FormEvent<HTMLInputElement>>;
onDeletion: (index: number) => void;
onAddition: React.EventHandler<React.KeyboardEvent<HTMLInputElement>>;
}
class TodoAppPresentation extends React.Component<Props, undefined> {
public render() {
const {
todos,
input,
onInput,
onDeletion,
onAddition,
} = this.props;
return (
<Container>
<H1>
Example Todo App
</H1>
<InnerContainer>
<Section>
<Header>
<Input
value={input}
onChange={onInput}
onKeyPress={onAddition}
autoFocus
placeholder="Start typing to add a Todo..."
/>
</Header>
<Todos>
<Ul>
{todos && todos.map((item, i) =>
<Li key={i}>
<TodoLabel>
{item.text}
</TodoLabel>
<DeleteButton
onClick={() => onDeletion(i)}
/>
</Li>,
)}
</Ul>
</Todos>
</Section>
</InnerContainer>
</Container>
);
}
}
export default TodoAppPresentation;
================================================
FILE: packages/docs/src/client/containers/TodoApp/reducer.ts
================================================
import { Reducer } from 'redux';
import * as T from './constants';
import { ActionTypes } from './actions';
import { State, initialState } from './state';
const reducer: Reducer<State> = (state: State = initialState, action: ActionTypes) => {
switch (action.type) {
case T.ADD_TODO:
return {
...state,
input: '',
todos: [
...state.todos,
action.todo,
],
};
case T.INPUT:
return {
...state,
input: action.input,
};
case T.DELETE_TODO:
return {
...state,
todos: [
...state.todos.slice(0, action.index),
...state.todos.slice(action.index + 1),
],
};
default:
return state;
}
};
export default reducer;
================================================
FILE: packages/docs/src/client/containers/TodoApp/selectors.ts
================================================
import { createSelector, Selector } from 'reselect';
import { State } from '../../state';
import { State as TodoAppState, Todo } from './types';
const selectTodoApp = () => (state: State): TodoAppState => state.todoApp;
export const selectTodos: Selector<State, Todo[]> = createSelector(
selectTodoApp(),
(todoApp) => todoApp.todos,
);
export const selectInput: Selector<State, string> = createSelector(
selectTodoApp(),
(todoApp) => todoApp.input,
);
================================================
FILE: packages/docs/src/client/containers/TodoApp/state.ts
================================================
import { Todo, Input } from './types';
export interface State {
todos?: Todo[];
input?: Input;
}
export const initialState: State = {
todos: [],
input: '',
};
export default State;
================================================
FILE: packages/docs/src/client/containers/TodoApp/styles.ts
================================================
import styled from 'styled-components';
export const Container = styled.div`
min-height: 100vh;
background: #f5f5f5;
width: 100%;
`;
export const InnerContainer = styled.div`
line-height: 1.4em;
color: #4d4d4d;
min-width: 230px;
max-width: 550px;
margin: 0 auto;
font-smoothing: antialiased;
font-weight: 300;
padding-top: 130px;
min-height: 100vh;
`;
export const Section = styled.section`
background: #fff;
position: relative;
box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.2), 0 25px 50px 0 rgba(0, 0, 0, 0.1);
`;
export const Header = styled.header`
display: block;
`;
export const Input = styled.input`
padding: 16px 16px 16px 60px;
border: none;
background: rgba(0, 0, 0, 0.003);
box-shadow: inset 0 -2px 1px rgba(0,0,0,0.03);
position: relative;
margin: 0;
width: 100%;
font-size: 24px;
font-family: inherit;
font-weight: inherit;
line-height: 1.4em;
border: 0;
outline: none;
color: inherit;
border: 1px solid #999;
box-shadow: inset 0 -1px 5px 0 rgba(0, 0, 0, 0.2);
box-sizing: border-box;
font-smoothing: antialiased;
`;
export const Todos = styled.section`
position: relative;
z-index: 2;
border-top: 1px solid #e6e6e6;
`;
export const Ul = styled.ul`
margin: 0;
padding: 0;
list-style: none;
`;
export const Li = styled.li`
position: relative;
font-size: 24px;
border-bottom: 1px solid #ededed;
`;
export const Todo = styled.label`
white-space: pre-line;
word-break: break-all;
padding: 15px 60px 15px 15px;
margin-left: 45px;
display: block;
line-height: 1.2;
transition: color 0.4s;
`;
export const DeleteButton = styled.button`
cursor: pointer;
position: absolute;
top: 0;
right: 10px;
bottom: 0;
width: 40px;
height: 35px;
margin: auto 0;
font-size: 30px;
color: #cc9a9a;
margin-bottom: 11px;
transition: color 0.2s ease-out;
border: none;
background: transparent;
font-size: 16px;
&:after {
content: '✕';
}
&:hover {
color: #af5b5e;
}
`;
export const H1 = styled.h1`
text-align: center;
font-size: 48px;
margin: 0;
padding-top: 60px;
text-align: center;
color: #000000;
`;
================================================
FILE: packages/docs/src/client/containers/TodoApp/types.ts
================================================
import { Props, StateProps } from './';
import { State } from './state';
import { ActionCreatorTypes } from './actionCreators';
import { ActionTypes } from './actions';
export interface Todo {
text: string;
}
export type Input = string;
export type Index = number;
export { Props, State, ActionCreatorTypes, ActionTypes, StateProps };
================================================
FILE: packages/docs/src/client/containers/index.ts
================================================
/* GENERATOR-IMPORT */
import Blog from './Blog';
import BlogPost from './BlogPost';
import App from './App';
import Home from './Home';
import Docs from './Docs';
import Features from './Features';
import About from './About';
import TodoApp from './TodoApp';
export {
/* GENERATOR-EXPORT */
Blog,
BlogPost,
App,
Home,
Docs,
Features,
About,
TodoApp,
};
================================================
FILE: packages/docs/src/client/index.tsx
================================================
import * as React from 'react';
import { render } from 'react-dom';
import RouterApp from './routes';
import { AppContainer } from 'react-hot-loader';
import './theming/globalCss';
declare var module: {
hot: {
accept: (s: string, f: () => void) => void,
},
}
gitextract_ld6wikvo/ ├── .babelrc ├── .eslintignore ├── .github/ │ ├── CHANGELOG.md │ └── CONTRIBUTING.md ├── .gitignore ├── .nvmrc ├── .travis.yml ├── LICENSE ├── Procfile ├── README.md ├── config/ │ ├── .storybook/ │ │ ├── addons.js │ │ ├── config.js │ │ ├── stories/ │ │ │ └── index.js │ │ └── webpack.config.js │ ├── generators/ │ │ ├── cli.js │ │ ├── component/ │ │ │ ├── es6class.tsx.hbs │ │ │ ├── export.ts.hbs │ │ │ ├── import.ts.hbs │ │ │ ├── index.js │ │ │ ├── stateless.tsx.hbs │ │ │ ├── styles.ts.hbs │ │ │ └── types.ts.hbs │ │ ├── container/ │ │ │ ├── actionCreators.js.hbs │ │ │ ├── actions.js.hbs │ │ │ ├── constants.js.hbs │ │ │ ├── export.js.hbs │ │ │ ├── import.js.hbs │ │ │ ├── index.js │ │ │ ├── index.js.hbs │ │ │ ├── presentation.js.hbs │ │ │ ├── reducer.export-state.js.hbs │ │ │ ├── reducer.export.js.hbs │ │ │ ├── reducer.import.js.hbs │ │ │ ├── reducer.js.hbs │ │ │ ├── selectors.js.hbs │ │ │ ├── state-type.js.hbs │ │ │ ├── state.import.js.hbs │ │ │ ├── state.js.hbs │ │ │ ├── styles.js.hbs │ │ │ ├── types.export.ts.hbs │ │ │ ├── types.import.ts.hbs │ │ │ └── types.ts.hbs │ │ └── utils/ │ │ ├── index.js │ │ └── safeString.js │ ├── ignoreAssets.js │ ├── scripts/ │ │ └── clean.js │ ├── testing/ │ │ ├── __mocks__/ │ │ │ ├── fileMock.js │ │ │ └── styleMock.js │ │ ├── preprocessor.js │ │ └── templates/ │ │ └── _index.prod.html │ └── types/ │ └── require.d.ts ├── devServer.js ├── index.html ├── lerna.json ├── netlify.toml ├── package.json ├── packages/ │ ├── docs/ │ │ ├── .babelrc │ │ ├── config/ │ │ │ ├── generators/ │ │ │ │ ├── cli.js │ │ │ │ ├── component/ │ │ │ │ │ ├── es6class.tsx.hbs │ │ │ │ │ ├── export.ts.hbs │ │ │ │ │ ├── import.ts.hbs │ │ │ │ │ ├── index.js │ │ │ │ │ ├── stateless.tsx.hbs │ │ │ │ │ ├── styles.ts.hbs │ │ │ │ │ └── types.ts.hbs │ │ │ │ ├── container/ │ │ │ │ │ ├── actionCreators.js.hbs │ │ │ │ │ ├── actions.js.hbs │ │ │ │ │ ├── constants.js.hbs │ │ │ │ │ ├── export.js.hbs │ │ │ │ │ ├── import.js.hbs │ │ │ │ │ ├── index.js │ │ │ │ │ ├── index.js.hbs │ │ │ │ │ ├── presentation.js.hbs │ │ │ │ │ ├── reducer.export-state.js.hbs │ │ │ │ │ ├── reducer.export.js.hbs │ │ │ │ │ ├── reducer.import.js.hbs │ │ │ │ │ ├── reducer.js.hbs │ │ │ │ │ ├── selectors.js.hbs │ │ │ │ │ ├── state-type.js.hbs │ │ │ │ │ ├── state.import.js.hbs │ │ │ │ │ ├── state.js.hbs │ │ │ │ │ ├── styles.js.hbs │ │ │ │ │ ├── types.export.ts.hbs │ │ │ │ │ ├── types.import.ts.hbs │ │ │ │ │ └── types.ts.hbs │ │ │ │ └── utils/ │ │ │ │ ├── index.js │ │ │ │ └── safeString.js │ │ │ ├── ignoreAssets.js │ │ │ └── types/ │ │ │ └── require.d.ts │ │ ├── devServer.js │ │ ├── index.html │ │ ├── package.json │ │ ├── server.js │ │ ├── src/ │ │ │ ├── client/ │ │ │ │ ├── apolloClient.ts │ │ │ │ ├── components/ │ │ │ │ │ ├── AddComment/ │ │ │ │ │ │ ├── __tests__/ │ │ │ │ │ │ │ ├── __mocks__/ │ │ │ │ │ │ │ │ └── addCommentMocks.mock.ts │ │ │ │ │ │ │ ├── __snapshots__/ │ │ │ │ │ │ │ │ └── index.test.tsx.snap │ │ │ │ │ │ │ └── index.test.tsx │ │ │ │ │ │ ├── index.tsx │ │ │ │ │ │ ├── styles.ts │ │ │ │ │ │ └── types.ts │ │ │ │ │ ├── Comment/ │ │ │ │ │ │ ├── __tests__/ │ │ │ │ │ │ │ ├── __mocks__/ │ │ │ │ │ │ │ │ └── commentMocks.mock.ts │ │ │ │ │ │ │ ├── __snapshots__/ │ │ │ │ │ │ │ │ └── index.test.tsx.snap │ │ │ │ │ │ │ └── index.test.tsx │ │ │ │ │ │ ├── index.tsx │ │ │ │ │ │ ├── styles.ts │ │ │ │ │ │ └── types.ts │ │ │ │ │ ├── Html/ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ ├── NavBar/ │ │ │ │ │ │ ├── __tests__/ │ │ │ │ │ │ │ ├── __mocks__/ │ │ │ │ │ │ │ │ └── navBarMocks.mock.ts │ │ │ │ │ │ │ ├── __snapshots__/ │ │ │ │ │ │ │ │ └── index.test.tsx.snap │ │ │ │ │ │ │ └── index.test.tsx │ │ │ │ │ │ ├── index.tsx │ │ │ │ │ │ ├── styles.ts │ │ │ │ │ │ └── types.ts │ │ │ │ │ ├── Pic/ │ │ │ │ │ │ ├── index.tsx │ │ │ │ │ │ ├── styles.ts │ │ │ │ │ │ └── types.ts │ │ │ │ │ ├── Post/ │ │ │ │ │ │ ├── index.tsx │ │ │ │ │ │ └── types.ts │ │ │ │ │ ├── PostCard/ │ │ │ │ │ │ ├── index.tsx │ │ │ │ │ │ ├── shortenText.ts │ │ │ │ │ │ ├── styles.ts │ │ │ │ │ │ └── types.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ └── utils/ │ │ │ │ │ ├── index.ts │ │ │ │ │ └── remStringFromPx.ts │ │ │ │ ├── containers/ │ │ │ │ │ ├── About/ │ │ │ │ │ │ ├── about.ts │ │ │ │ │ │ ├── contributors.ts │ │ │ │ │ │ ├── index.tsx │ │ │ │ │ │ └── styles.ts │ │ │ │ │ ├── App/ │ │ │ │ │ │ ├── __tests__/ │ │ │ │ │ │ │ ├── __snapshots__/ │ │ │ │ │ │ │ │ └── index.test.tsx.snap │ │ │ │ │ │ │ ├── actionCreators.test.ts │ │ │ │ │ │ │ ├── index.test.tsx │ │ │ │ │ │ │ ├── reducer.test.ts │ │ │ │ │ │ │ └── selectors.test.ts │ │ │ │ │ │ ├── actionCreators.ts │ │ │ │ │ │ ├── actions.ts │ │ │ │ │ │ ├── constants.ts │ │ │ │ │ │ ├── index.tsx │ │ │ │ │ │ ├── presentation.tsx │ │ │ │ │ │ ├── reducer.ts │ │ │ │ │ │ ├── selectors.ts │ │ │ │ │ │ ├── state.ts │ │ │ │ │ │ ├── styles.ts │ │ │ │ │ │ └── types.ts │ │ │ │ │ ├── Blog/ │ │ │ │ │ │ ├── index.tsx │ │ │ │ │ │ ├── posts.graphql.ts │ │ │ │ │ │ ├── styles.ts │ │ │ │ │ │ └── types.ts │ │ │ │ │ ├── BlogPost/ │ │ │ │ │ │ ├── __tests__/ │ │ │ │ │ │ │ ├── __mocks__/ │ │ │ │ │ │ │ │ ├── blogPostPresentation.mock.ts │ │ │ │ │ │ │ │ └── blogPostSelectors.mock.ts │ │ │ │ │ │ │ ├── __snapshots__/ │ │ │ │ │ │ │ │ └── index.test.tsx.snap │ │ │ │ │ │ │ ├── actionCreators.test.ts │ │ │ │ │ │ │ ├── index.test.tsx │ │ │ │ │ │ │ ├── reducer.test.ts │ │ │ │ │ │ │ └── selectors.test.ts │ │ │ │ │ │ ├── actionCreators.ts │ │ │ │ │ │ ├── actions.ts │ │ │ │ │ │ ├── apollo.ts │ │ │ │ │ │ ├── commentMutation.graphql.ts │ │ │ │ │ │ ├── constants.ts │ │ │ │ │ │ ├── index.tsx │ │ │ │ │ │ ├── postQuery.graphql.ts │ │ │ │ │ │ ├── presentation.tsx │ │ │ │ │ │ ├── reducer.ts │ │ │ │ │ │ ├── selectors.ts │ │ │ │ │ │ ├── state.ts │ │ │ │ │ │ ├── styles.ts │ │ │ │ │ │ └── types.ts │ │ │ │ │ ├── Docs/ │ │ │ │ │ │ ├── __tests__/ │ │ │ │ │ │ │ ├── __mocks__/ │ │ │ │ │ │ │ │ └── docsMocks.mock.ts │ │ │ │ │ │ │ ├── __snapshots__/ │ │ │ │ │ │ │ │ └── index.test.tsx.snap │ │ │ │ │ │ │ ├── actionCreators.test.ts │ │ │ │ │ │ │ ├── index.test.tsx │ │ │ │ │ │ │ ├── logic.test.ts │ │ │ │ │ │ │ ├── reducer.test.ts │ │ │ │ │ │ │ └── selectors.test.ts │ │ │ │ │ │ ├── actionCreators.ts │ │ │ │ │ │ ├── actions.ts │ │ │ │ │ │ ├── constants.ts │ │ │ │ │ │ ├── index.tsx │ │ │ │ │ │ ├── logic.ts │ │ │ │ │ │ ├── presentation.tsx │ │ │ │ │ │ ├── reducer.ts │ │ │ │ │ │ ├── selectors.ts │ │ │ │ │ │ ├── state.ts │ │ │ │ │ │ ├── styles.ts │ │ │ │ │ │ └── types.ts │ │ │ │ │ ├── Features/ │ │ │ │ │ │ ├── features.ts │ │ │ │ │ │ ├── index.tsx │ │ │ │ │ │ ├── styles.ts │ │ │ │ │ │ └── types.ts │ │ │ │ │ ├── Home/ │ │ │ │ │ │ ├── index.tsx │ │ │ │ │ │ ├── presentation.tsx │ │ │ │ │ │ ├── styles.ts │ │ │ │ │ │ └── types.ts │ │ │ │ │ ├── TodoApp/ │ │ │ │ │ │ ├── __tests__/ │ │ │ │ │ │ │ ├── __mocks__/ │ │ │ │ │ │ │ │ ├── presentation.mock.ts │ │ │ │ │ │ │ │ └── selectors.mock.ts │ │ │ │ │ │ │ ├── __snapshots__/ │ │ │ │ │ │ │ │ └── index.test.tsx.snap │ │ │ │ │ │ │ ├── actionCreators.test.ts │ │ │ │ │ │ │ ├── index.test.tsx │ │ │ │ │ │ │ ├── reducer.test.ts │ │ │ │ │ │ │ └── selectors.test.ts │ │ │ │ │ │ ├── actionCreators.ts │ │ │ │ │ │ ├── actions.ts │ │ │ │ │ │ ├── constants.ts │ │ │ │ │ │ ├── index.tsx │ │ │ │ │ │ ├── presentation.tsx │ │ │ │ │ │ ├── reducer.ts │ │ │ │ │ │ ├── selectors.ts │ │ │ │ │ │ ├── state.ts │ │ │ │ │ │ ├── styles.ts │ │ │ │ │ │ └── types.ts │ │ │ │ │ └── index.ts │ │ │ │ ├── index.tsx │ │ │ │ ├── logic.ts │ │ │ │ ├── reducers.ts │ │ │ │ ├── routes.tsx │ │ │ │ ├── shared/ │ │ │ │ │ ├── actionCreators.ts │ │ │ │ │ ├── actions.ts │ │ │ │ │ └── constants.ts │ │ │ │ ├── state.ts │ │ │ │ ├── store.tsx │ │ │ │ ├── test/ │ │ │ │ │ └── mockstore.ts │ │ │ │ ├── theming/ │ │ │ │ │ ├── colorMap.ts │ │ │ │ │ ├── globalCss.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ └── types.ts │ │ │ │ └── types.ts │ │ │ └── server/ │ │ │ ├── db/ │ │ │ │ ├── index.ts │ │ │ │ ├── models/ │ │ │ │ │ ├── comment.ts │ │ │ │ │ └── post.ts │ │ │ │ └── utils/ │ │ │ │ └── uuid.ts │ │ │ ├── graph/ │ │ │ │ ├── index.ts │ │ │ │ ├── mutations/ │ │ │ │ │ ├── comment/ │ │ │ │ │ │ ├── createComment.ts │ │ │ │ │ │ └── index.ts │ │ │ │ │ └── index.ts │ │ │ │ ├── queries/ │ │ │ │ │ ├── comment/ │ │ │ │ │ │ ├── comment.ts │ │ │ │ │ │ ├── comments.ts │ │ │ │ │ │ └── index.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ └── post/ │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── post.ts │ │ │ │ │ └── posts.ts │ │ │ │ ├── schema.json │ │ │ │ └── types/ │ │ │ │ ├── comment/ │ │ │ │ │ ├── comment.ts │ │ │ │ │ └── commentInput.ts │ │ │ │ ├── index.ts │ │ │ │ └── post/ │ │ │ │ ├── post.ts │ │ │ │ └── postInput.ts │ │ │ ├── graphqlEntry.ts │ │ │ └── index.tsx │ │ ├── tsconfig.json │ │ ├── webpack.config.js │ │ ├── webpack.config.prod.js │ │ └── webpack.config.server.js │ └── openui/ │ ├── package.json │ ├── src/ │ │ ├── Anchor/ │ │ │ ├── __tests__/ │ │ │ │ ├── __mocks__/ │ │ │ │ │ └── anchorMocks.mock.ts │ │ │ │ ├── __snapshots__/ │ │ │ │ │ └── index.test.tsx.snap │ │ │ │ └── index.test.tsx │ │ │ ├── index.tsx │ │ │ ├── styles.ts │ │ │ └── types.ts │ │ ├── Article/ │ │ │ ├── __tests__/ │ │ │ │ ├── __mocks__/ │ │ │ │ │ └── articleMocks.mock.ts │ │ │ │ ├── __snapshots__/ │ │ │ │ │ └── index.test.tsx.snap │ │ │ │ └── index.test.tsx │ │ │ ├── index.tsx │ │ │ ├── styles.ts │ │ │ └── types.ts │ │ ├── Avatar/ │ │ │ ├── __tests__/ │ │ │ │ ├── __mocks__/ │ │ │ │ │ └── avatarMocks.mock.ts │ │ │ │ ├── __snapshots__/ │ │ │ │ │ └── index.test.tsx.snap │ │ │ │ └── index.test.tsx │ │ │ ├── default.ts │ │ │ ├── index.tsx │ │ │ ├── maps.ts │ │ │ ├── styles.ts │ │ │ └── types.ts │ │ ├── Box/ │ │ │ ├── __tests__/ │ │ │ │ ├── __mocks__/ │ │ │ │ │ └── boxMocks.mock.ts │ │ │ │ ├── __snapshots__/ │ │ │ │ │ └── index.test.tsx.snap │ │ │ │ └── index.test.tsx │ │ │ ├── index.tsx │ │ │ ├── maps.ts │ │ │ ├── styleUtils.ts │ │ │ ├── styles.ts │ │ │ └── types.ts │ │ ├── Button/ │ │ │ ├── __tests__/ │ │ │ │ ├── __mocks__/ │ │ │ │ │ └── buttonMocks.mock.ts │ │ │ │ ├── __snapshots__/ │ │ │ │ │ └── index.test.tsx.snap │ │ │ │ └── index.test.tsx │ │ │ ├── index.tsx │ │ │ ├── maps.ts │ │ │ ├── styles.ts │ │ │ └── types.ts │ │ ├── Footer/ │ │ │ ├── __tests__/ │ │ │ │ ├── __mocks__/ │ │ │ │ │ └── footerMocks.mock.ts │ │ │ │ ├── __snapshots__/ │ │ │ │ │ └── index.test.tsx.snap │ │ │ │ └── index.test.tsx │ │ │ ├── index.tsx │ │ │ ├── styles.ts │ │ │ └── types.ts │ │ ├── Header/ │ │ │ ├── header.tsx │ │ │ ├── index.tsx │ │ │ ├── styles.ts │ │ │ ├── types.ts │ │ │ └── utils.ts │ │ ├── Heading/ │ │ │ ├── __tests__/ │ │ │ │ ├── __mocks__/ │ │ │ │ │ └── headingProps.mock.ts │ │ │ │ ├── __snapshots__/ │ │ │ │ │ └── index.test.tsx.snap │ │ │ │ └── index.test.tsx │ │ │ ├── index.tsx │ │ │ ├── styleUtils.ts │ │ │ ├── styles.ts │ │ │ └── types.ts │ │ ├── Headline/ │ │ │ ├── __tests__/ │ │ │ │ ├── __mocks__/ │ │ │ │ │ └── headlineProps.mock.ts │ │ │ │ ├── __snapshots__/ │ │ │ │ │ └── index.test.tsx.snap │ │ │ │ └── index.test.tsx │ │ │ ├── index.tsx │ │ │ ├── styleUtils.ts │ │ │ ├── styles.ts │ │ │ └── types.ts │ │ ├── Hero/ │ │ │ ├── __tests__/ │ │ │ │ ├── __mocks__/ │ │ │ │ │ └── heroMocks.mock.ts │ │ │ │ ├── __snapshots__/ │ │ │ │ │ └── index.test.tsx.snap │ │ │ │ └── index.test.tsx │ │ │ ├── index.tsx │ │ │ ├── styles.ts │ │ │ └── types.ts │ │ ├── Image/ │ │ │ ├── __tests__/ │ │ │ │ ├── __mocks__/ │ │ │ │ │ └── imageMocks.mock.ts │ │ │ │ ├── __snapshots__/ │ │ │ │ │ └── index.test.tsx.snap │ │ │ │ └── index.test.tsx │ │ │ ├── index.tsx │ │ │ ├── styles.ts │ │ │ └── types.ts │ │ ├── LoadingIndicator/ │ │ │ ├── __tests__/ │ │ │ │ ├── __mocks__/ │ │ │ │ │ └── loadingIndicatorMocks.mock.ts │ │ │ │ ├── __snapshots__/ │ │ │ │ │ └── index.test.tsx.snap │ │ │ │ └── index.test.tsx │ │ │ ├── index.tsx │ │ │ ├── styles.ts │ │ │ └── types.ts │ │ ├── Markdown/ │ │ │ ├── index.tsx │ │ │ ├── styles.ts │ │ │ └── types.ts │ │ ├── Notification/ │ │ │ ├── __tests__/ │ │ │ │ ├── __mocks__/ │ │ │ │ │ └── notificationMocks.mock.ts │ │ │ │ ├── __snapshots__/ │ │ │ │ │ └── index.test.tsx.snap │ │ │ │ └── index.test.tsx │ │ │ ├── index.tsx │ │ │ ├── styles.ts │ │ │ └── types.ts │ │ ├── Paragraph/ │ │ │ ├── index.tsx │ │ │ ├── styleUtils.ts │ │ │ ├── styles.ts │ │ │ └── types.ts │ │ ├── Section/ │ │ │ ├── __tests__/ │ │ │ │ ├── __mocks__/ │ │ │ │ │ └── sectionMocks.mock.ts │ │ │ │ ├── __snapshots__/ │ │ │ │ │ └── index.test.tsx.snap │ │ │ │ └── index.test.tsx │ │ │ ├── index.tsx │ │ │ └── styles.ts │ │ ├── SvgIcon/ │ │ │ ├── index.tsx │ │ │ └── types.ts │ │ ├── Toast/ │ │ │ ├── __tests__/ │ │ │ │ ├── __mocks__/ │ │ │ │ │ └── toast.mock.ts │ │ │ │ ├── __snapshots__/ │ │ │ │ │ └── index.test.tsx.snap │ │ │ │ └── index.test.tsx │ │ │ ├── index.tsx │ │ │ ├── styles.ts │ │ │ └── types.ts │ │ ├── WithAnimation/ │ │ │ ├── animation.ts │ │ │ ├── index.tsx │ │ │ └── types.ts │ │ ├── index.ts │ │ ├── theming/ │ │ │ ├── colorMap.ts │ │ │ ├── globalCss.ts │ │ │ ├── index.ts │ │ │ └── types.ts │ │ └── utils/ │ │ ├── index.ts │ │ └── remStringFromPx.ts │ └── tsconfig.json ├── server.js ├── src/ │ ├── client/ │ │ ├── apolloClient.ts │ │ ├── components/ │ │ │ ├── Html/ │ │ │ │ └── index.tsx │ │ │ └── index.ts │ │ ├── features/ │ │ │ ├── Landing/ │ │ │ │ ├── index.tsx │ │ │ │ ├── presentation.tsx │ │ │ │ ├── styles.ts │ │ │ │ └── types.ts │ │ │ ├── Layout/ │ │ │ │ ├── index.tsx │ │ │ │ ├── main.ts │ │ │ │ ├── presentation.tsx │ │ │ │ ├── styles.ts │ │ │ │ └── types.ts │ │ │ └── index.ts │ │ ├── index.tsx │ │ ├── logic.ts │ │ ├── reducers.ts │ │ ├── routes.tsx │ │ ├── shared/ │ │ │ ├── actionCreators.ts │ │ │ ├── actions.ts │ │ │ └── constants.ts │ │ ├── state.ts │ │ ├── store.tsx │ │ ├── test/ │ │ │ └── mockstore.ts │ │ ├── theming/ │ │ │ ├── colorMap.ts │ │ │ ├── globalCss.ts │ │ │ ├── index.ts │ │ │ └── types.ts │ │ └── types.ts │ └── server/ │ ├── db/ │ │ ├── index.ts │ │ ├── models/ │ │ │ └── post.ts │ │ └── utils/ │ │ └── uuid.ts │ ├── graph/ │ │ ├── index.ts │ │ ├── mutations/ │ │ │ └── index.ts │ │ ├── queries/ │ │ │ └── index.ts │ │ ├── schema.json │ │ └── types/ │ │ └── index.ts │ ├── graphqlEntry.ts │ └── index.tsx ├── tsconfig.json ├── tslint.json ├── webpack.config.js ├── webpack.config.prod.js └── webpack.config.server.js
SYMBOL INDEX (313 symbols across 129 files)
FILE: config/.storybook/config.js
function loadStories (line 9) | function loadStories() {
FILE: config/.storybook/webpack.config.js
constant ROOT_PATH (line 3) | const ROOT_PATH = path.resolve(__dirname, '../../');
FILE: config/generators/utils/safeString.js
function SafeString (line 1) | function SafeString(string) {
FILE: config/testing/preprocessor.js
constant BABELRC_FILENAME (line 12) | const BABELRC_FILENAME = '.babelrc';
method getCacheKey (line 52) | getCacheKey(
method process (line 67) | process(
FILE: packages/docs/config/generators/utils/safeString.js
function SafeString (line 1) | function SafeString(string) {
FILE: packages/docs/src/client/components/AddComment/index.tsx
function AddComment (line 15) | function AddComment({
FILE: packages/docs/src/client/components/AddComment/types.ts
type AddCommentProps (line 4) | interface AddCommentProps extends React.Props<typeof AddComment> {
FILE: packages/docs/src/client/components/Comment/index.tsx
function Comment (line 13) | function Comment({
FILE: packages/docs/src/client/components/Comment/styles.ts
type PicProps (line 30) | interface PicProps {
FILE: packages/docs/src/client/components/Comment/types.ts
type CommentProps (line 4) | interface CommentProps extends React.Props<typeof Comment> {
FILE: packages/docs/src/client/components/NavBar/index.tsx
function NavBar (line 13) | function NavBar({
FILE: packages/docs/src/client/components/NavBar/types.ts
type Navlink (line 4) | interface Navlink { url: string; text: string; }
type NavBarProps (line 5) | interface NavBarProps extends React.Props<typeof NavBar> {
FILE: packages/docs/src/client/components/Pic/index.tsx
type PicProps (line 4) | interface PicProps {
FILE: packages/docs/src/client/components/Post/index.tsx
function Post (line 6) | function Post({
FILE: packages/docs/src/client/components/Post/types.ts
type PostComment (line 1) | interface PostComment {
type PostProps (line 6) | interface PostProps {
FILE: packages/docs/src/client/components/PostCard/index.tsx
function PostCard (line 16) | function PostCard({
FILE: packages/docs/src/client/components/PostCard/shortenText.ts
function shortenText (line 1) | function shortenText(text: string, maxLength: number) {
FILE: packages/docs/src/client/components/PostCard/styles.ts
type CardThumbnailProps (line 4) | interface CardThumbnailProps {
FILE: packages/docs/src/client/components/PostCard/types.ts
type PostCardProps (line 1) | interface PostCardProps {
FILE: packages/docs/src/client/components/utils/remStringFromPx.ts
type Px (line 1) | type Px = number;
type Rem (line 2) | type Rem = number;
FILE: packages/docs/src/client/containers/About/contributors.ts
type Contributor (line 3) | interface Contributor {
FILE: packages/docs/src/client/containers/About/index.tsx
class About (line 25) | class About extends React.Component<undefined, undefined> {
method render (line 26) | public render() {
FILE: packages/docs/src/client/containers/About/styles.ts
type AboutSectionProps (line 8) | interface AboutSectionProps {
type AboutSectionInnerProps (line 20) | interface AboutSectionInnerProps {
FILE: packages/docs/src/client/containers/App/actions.ts
type SetIsMobileAction (line 5) | interface SetIsMobileAction extends Action {
type FeatureAction (line 10) | type FeatureAction =
FILE: packages/docs/src/client/containers/App/constants.ts
type SET_MOBILE_TYPE (line 1) | type SET_MOBILE_TYPE = 'APP/SET_MOBILE';
constant SET_MOBILE (line 2) | const SET_MOBILE: SET_MOBILE_TYPE = 'APP/SET_MOBILE';
FILE: packages/docs/src/client/containers/App/index.tsx
type OwnProps (line 11) | interface OwnProps { }
FILE: packages/docs/src/client/containers/App/presentation.tsx
type StateProps (line 8) | type StateProps = State;
type DispatchProps (line 10) | interface DispatchProps {
type FeatureProps (line 16) | type FeatureProps = React.Props<Feature> & StateProps & DispatchProps;
class Feature (line 18) | class Feature extends React.Component<FeatureProps, undefined> {
method constructor (line 19) | constructor(props) {
method componentDidMount (line 23) | public componentDidMount() {
method componentWillUnmount (line 27) | public componentWillUnmount() {
method render (line 38) | public render() {
FILE: packages/docs/src/client/containers/App/state.ts
type NavLink (line 1) | interface NavLink {
type State (line 6) | interface State {
FILE: packages/docs/src/client/containers/App/types.ts
type NavLink (line 3) | interface NavLink { url: string; text: string; }
type Props (line 5) | interface Props extends React.Props<typeof App> {
FILE: packages/docs/src/client/containers/Blog/index.tsx
class Blog (line 9) | class Blog extends React.Component<Props, State> {
method constructor (line 10) | constructor() {
method handleClearError (line 17) | private handleClearError() {
method render (line 22) | public render() {
FILE: packages/docs/src/client/containers/Blog/types.ts
type Post (line 3) | interface Post {
type Props (line 10) | interface Props extends React.Props<typeof Blog> {
type State (line 16) | interface State {
FILE: packages/docs/src/client/containers/BlogPost/actionCreators.ts
type InputActionCreator (line 8) | type InputActionCreator = ActionCreator<InputAction>;
type ActionCreatorTypes (line 14) | interface ActionCreatorTypes extends ActionCreatorsMapObject {
FILE: packages/docs/src/client/containers/BlogPost/actions.ts
type InputAction (line 5) | interface InputAction extends Action {
type ActionTypes (line 10) | type ActionTypes = InputAction;
FILE: packages/docs/src/client/containers/BlogPost/constants.ts
type INPUT_TYPE (line 1) | type INPUT_TYPE = 'BLOG_POST/INPUT';
constant INPUT (line 2) | const INPUT: INPUT_TYPE = 'BLOG_POST/INPUT';
FILE: packages/docs/src/client/containers/BlogPost/index.tsx
type MapStateToProps (line 14) | type MapStateToProps = (state: State) => StateProps;
type MapDispatch (line 19) | type MapDispatch = (dispatch: Dispatch<ActionTypes>) => DispatchProps;
type Props (line 27) | interface Props {
type StateProps (line 39) | interface StateProps {
type DispatchProps (line 42) | interface DispatchProps {
type PropTypes (line 45) | type PropTypes = StateProps & DispatchProps & Props;
class BlogPost (line 46) | class BlogPost extends React.Component<PropTypes, undefined> {
method constructor (line 47) | constructor() {
method handleInput (line 53) | private handleInput(e: React.SyntheticEvent<undefined>) {
method handleAddingComment (line 58) | private handleAddingComment() {
method handleEnterKeyUp (line 72) | private handleEnterKeyUp(e: React.KeyboardEvent<undefined>) {
method render (line 78) | public render() {
FILE: packages/docs/src/client/containers/BlogPost/presentation.tsx
type Props (line 7) | interface Props {
class BlogPostPresentation (line 17) | class BlogPostPresentation extends React.Component<Props, undefined> {
method render (line 18) | public render() {
FILE: packages/docs/src/client/containers/BlogPost/state.ts
type State (line 3) | interface State {
FILE: packages/docs/src/client/containers/BlogPost/types.ts
type OnInput (line 10) | type OnInput = (e: React.SyntheticEvent<undefined>) => void;
type OnSubmit (line 11) | type OnSubmit = () => void;
type OnKeyUp (line 12) | type OnKeyUp = (e: React.KeyboardEvent<undefined>) => void;
type PostComment (line 14) | interface PostComment {
type Post (line 19) | interface Post {
type ErrorType (line 27) | interface ErrorType { message: string; }
type Input (line 29) | type Input = string;
type Body (line 31) | type Body = string;
type Author (line 32) | type Author = string;
type PostId (line 33) | type PostId = string;
type PostSubmission (line 34) | interface PostSubmission {
type SubmitComment (line 42) | type SubmitComment = (post: PostSubmission) => Promise<undefined>;
FILE: packages/docs/src/client/containers/Docs/__tests__/logic.test.ts
method get (line 7) | get(url) { return Promise.resolve({ data: 'testData' }); }
FILE: packages/docs/src/client/containers/Docs/actions.ts
type LoadInitiationAction (line 5) | interface LoadInitiationAction extends Action {
type LoadSuccessAction (line 9) | interface LoadSuccessAction extends Action {
type LoadFailureAction (line 14) | interface LoadFailureAction extends Action {
type LoadCancelAction (line 19) | interface LoadCancelAction extends Action {
type ClearErrorAction (line 23) | interface ClearErrorAction extends Action {
type FeatureAction (line 27) | type FeatureAction =
FILE: packages/docs/src/client/containers/Docs/constants.ts
type LOAD_INITIATION_TYPE (line 1) | type LOAD_INITIATION_TYPE = 'DOCS/LOAD_INITIATION';
constant LOAD_INITIATION (line 2) | const LOAD_INITIATION: LOAD_INITIATION_TYPE = 'DOCS/LOAD_INITIATION';
type LOAD_SUCCESS_TYPE (line 4) | type LOAD_SUCCESS_TYPE = 'DOCS/LOAD_SUCCESS';
constant LOAD_SUCCESS (line 5) | const LOAD_SUCCESS: LOAD_SUCCESS_TYPE = 'DOCS/LOAD_SUCCESS';
type LOAD_FAILURE_TYPE (line 7) | type LOAD_FAILURE_TYPE = 'DOCS/LOAD_FAILURE';
constant LOAD_FAILURE (line 8) | const LOAD_FAILURE: LOAD_FAILURE_TYPE = 'DOCS/LOAD_FAILURE';
type LOAD_CANCEL_TYPE (line 10) | type LOAD_CANCEL_TYPE = 'DOCS/LOAD_CANCEL';
constant LOAD_CANCEL (line 11) | const LOAD_CANCEL: LOAD_CANCEL_TYPE = 'DOCS/LOAD_CANCEL';
type CLEAR_ERROR_TYPE (line 13) | type CLEAR_ERROR_TYPE = 'DOCS/CLEAR_ERROR';
constant CLEAR_ERROR (line 14) | const CLEAR_ERROR: CLEAR_ERROR_TYPE = 'DOCS/CLEAR_ERROR';
FILE: packages/docs/src/client/containers/Docs/index.tsx
type OwnProps (line 11) | interface OwnProps { }
FILE: packages/docs/src/client/containers/Docs/logic.ts
method process (line 16) | process({ httpClient }) {
FILE: packages/docs/src/client/containers/Docs/presentation.tsx
type StateProps (line 12) | type StateProps = State;
type DispatchProps (line 14) | interface DispatchProps {
type FeatureProps (line 23) | type FeatureProps = React.Props<Feature> & StateProps & DispatchProps;
class Feature (line 25) | class Feature extends React.Component<FeatureProps, undefined> {
method constructor (line 26) | constructor(props) {
method render (line 34) | public render() {
FILE: packages/docs/src/client/containers/Docs/state.ts
type State (line 1) | interface State {
FILE: packages/docs/src/client/containers/Features/index.tsx
class Features (line 15) | class Features extends React.Component<Props, undefined> {
method render (line 16) | public render() {
FILE: packages/docs/src/client/containers/Features/styles.ts
type FeaturesSectionProps (line 8) | interface FeaturesSectionProps {
type FeatureSectionInnerProps (line 20) | interface FeatureSectionInnerProps {
FILE: packages/docs/src/client/containers/Features/types.ts
type Props (line 5) | interface Props extends React.Props<typeof Features> {
FILE: packages/docs/src/client/containers/Home/index.tsx
type Props (line 7) | interface Props { theme: ThemeColorMap; }
class Home (line 8) | class Home extends React.Component<Props, undefined> {
method render (line 9) | public render() {
FILE: packages/docs/src/client/containers/Home/presentation.tsx
type Props (line 6) | interface Props extends HomeProps {
function HomePresentation (line 9) | function HomePresentation({
FILE: packages/docs/src/client/containers/TodoApp/actionCreators.ts
type AddTodoActionCreator (line 10) | type AddTodoActionCreator = ActionCreator<AddTodoAction>;
type InputActionCreator (line 16) | type InputActionCreator = ActionCreator<InputAction>;
type DeleteTodoActionCreator (line 22) | type DeleteTodoActionCreator = ActionCreator<DeleteTodoAction>;
type ActionCreatorTypes (line 28) | interface ActionCreatorTypes extends ActionCreatorsMapObject {
FILE: packages/docs/src/client/containers/TodoApp/actions.ts
type AddTodoAction (line 5) | interface AddTodoAction extends Action {
type InputAction (line 10) | interface InputAction extends Action {
type DeleteTodoAction (line 15) | interface DeleteTodoAction extends Action {
type ActionTypes (line 20) | type ActionTypes = AddTodoAction | InputAction | DeleteTodoAction;
FILE: packages/docs/src/client/containers/TodoApp/constants.ts
type ADD_TODO_TYPE (line 1) | type ADD_TODO_TYPE = 'TODO_APP/ADD_TODO';
constant ADD_TODO (line 2) | const ADD_TODO: ADD_TODO_TYPE = 'TODO_APP/ADD_TODO';
type INPUT_TYPE (line 4) | type INPUT_TYPE = 'TODO_APP/INPUT';
constant INPUT (line 5) | const INPUT: INPUT_TYPE = 'TODO_APP/INPUT';
type DELETE_TODO_TYPE (line 7) | type DELETE_TODO_TYPE = 'TODO_APP/DELETE_TODO';
constant DELETE_TODO (line 8) | const DELETE_TODO: DELETE_TODO_TYPE = 'TODO_APP/DELETE_TODO';
FILE: packages/docs/src/client/containers/TodoApp/index.tsx
type StateProps (line 26) | interface StateProps extends React.Props<TodoApp> {
type DispatchProps (line 30) | interface DispatchProps {
type Props (line 33) | type Props = DispatchProps & StateProps;
class TodoApp (line 34) | class TodoApp extends React.Component<Props, undefined> {
method constructor (line 35) | constructor() {
method handleAddition (line 41) | private handleAddition(e: React.KeyboardEvent<undefined>) {
method handleInput (line 48) | private handleInput(e: React.SyntheticEvent<undefined>) {
method handleDeletion (line 53) | private handleDeletion(i: Index) {
method render (line 56) | public render() {
FILE: packages/docs/src/client/containers/TodoApp/presentation.tsx
type Props (line 17) | interface Props extends StateProps {
class TodoAppPresentation (line 22) | class TodoAppPresentation extends React.Component<Props, undefined> {
method render (line 23) | public render() {
FILE: packages/docs/src/client/containers/TodoApp/state.ts
type State (line 3) | interface State {
FILE: packages/docs/src/client/containers/TodoApp/types.ts
type Todo (line 6) | interface Todo {
type Input (line 10) | type Input = string;
type Index (line 12) | type Index = number;
FILE: packages/docs/src/client/shared/actions.ts
type DefaultAction (line 4) | interface DefaultAction extends Action {
type PayloadAction (line 8) | interface PayloadAction<P> extends Action {
FILE: packages/docs/src/client/shared/constants.ts
type DEFAULT_ACTION_TYPE (line 1) | type DEFAULT_ACTION_TYPE = '';
constant DEFAULT_ACTION_TYPE (line 2) | const DEFAULT_ACTION_TYPE: DEFAULT_ACTION_TYPE = '';
FILE: packages/docs/src/client/state.ts
type State (line 7) | interface State {
FILE: packages/docs/src/client/store.tsx
function createThunkMiddleware (line 16) | function createThunkMiddleware() {
FILE: packages/docs/src/client/theming/types.ts
type ThemeColorMap (line 1) | interface ThemeColorMap {
FILE: packages/docs/src/client/types.ts
type PayloadAction (line 12) | interface PayloadAction<P> extends Action {
type FormControlEventTarget (line 17) | interface FormControlEventTarget extends EventTarget {
FILE: packages/docs/src/server/db/index.ts
function seedPosts (line 5) | function seedPosts() {
function createSeedPosts (line 16) | function createSeedPosts() {
function createSeedData (line 34) | function createSeedData() {
FILE: packages/docs/src/server/db/utils/uuid.ts
function uuid (line 2) | function uuid() {
FILE: packages/docs/src/server/graph/mutations/comment/createComment.ts
method resolve (line 16) | async resolve(_, args, __) {
FILE: packages/docs/src/server/graph/queries/comment/comment.ts
method resolve (line 16) | resolve(_, args, __) {
FILE: packages/docs/src/server/graph/queries/comment/comments.ts
method resolve (line 16) | resolve(_, args, __) {
FILE: packages/docs/src/server/graph/queries/post/post.ts
method resolve (line 16) | resolve(_, args, __) {
FILE: packages/docs/src/server/graph/queries/post/posts.ts
method resolve (line 11) | resolve() {
FILE: packages/docs/src/server/graphqlEntry.ts
function createSchema (line 12) | function createSchema() {
function graphqlEntry (line 30) | function graphqlEntry(app): Promise<express.Application> {
FILE: packages/docs/webpack.config.js
constant ROOT_PATH (line 3) | const ROOT_PATH = path.resolve(__dirname);
FILE: packages/docs/webpack.config.prod.js
constant ROOT_PATH (line 9) | const ROOT_PATH = path.resolve(__dirname);
FILE: packages/docs/webpack.config.server.js
constant ROOT_PATH (line 3) | const ROOT_PATH = path.resolve(__dirname);
FILE: packages/openui/src/Anchor/index.tsx
type Method (line 7) | type Method = 'push' | 'replace';
type Props (line 8) | interface Props extends React.Props<typeof Anchor> {
class Anchor (line 18) | class Anchor extends React.Component<Props, undefined> {
method render (line 35) | public render() {
FILE: packages/openui/src/Article/index.tsx
type Props (line 6) | interface Props extends BoxProps {
function Article (line 10) | function Article({
FILE: packages/openui/src/Avatar/index.tsx
type ImageSize (line 5) | type ImageSize = 'thumb' | 'small' | 'medium' | 'large';
type Props (line 6) | interface Props {
FILE: packages/openui/src/Box/index.tsx
function Box (line 5) | function Box({
FILE: packages/openui/src/Box/maps.ts
constant SIZE_MAP (line 1) | const SIZE_MAP = {
constant BOX_SIZE_MAP (line 9) | const BOX_SIZE_MAP = {
constant BREAKPOINTS (line 19) | const BREAKPOINTS = {
FILE: packages/openui/src/Box/styleUtils.ts
function calculateFlexWrap (line 22) | function calculateFlexWrap(wrap?: boolean, reverse?: boolean): WrapOption {
function sizeToString (line 32) | function sizeToString(size: Size | SizeObject, smallSize: boolean = fals...
function stringBoxStyle (line 46) | function stringBoxStyle(size: BoxSize): SizeStyle {
function objectBoxStyle (line 60) | function objectBoxStyle(size: BoxSizeObject): SizeStyle {
function boxSizeToStyle (line 79) | function boxSizeToStyle(size: BoxSize | BoxSizeObject): SizeStyle {
function calculateFullStyle (line 89) | function calculateFullStyle(full: Full, postFix: 'vw' | 'vh'): string {
FILE: packages/openui/src/Box/types.ts
type Size (line 1) | type Size = 'none' | 'small' | 'medium' | 'large' | 'xlarge';
type SizeObject (line 2) | interface SizeObject { horizontal?: Size; vertical?: Size; }
type Breakpoint (line 3) | type Breakpoint = 'mobile' | 'tablet' | 'desktop';
type ResponsiveSize (line 4) | interface ResponsiveSize {
type BoxSize (line 9) | type BoxSize = 'xsmall' | 'small' | 'medium' | 'large' | 'xlarge' | 'xx...
type BoxSizeObject (line 10) | interface BoxSizeObject { horizontal?: BoxSize; vertical?: BoxSize; }
type FullObject (line 11) | interface FullObject { horizontal?: boolean; vertical?: boolean; }
type Full (line 12) | type Full = boolean | FullObject;
type WrapOption (line 13) | type WrapOption = 'wrap' | 'wrap-reverse' | 'nowrap';
type Rem (line 14) | type Rem = number;
type Px (line 15) | type Px = number;
type SizeStyle (line 17) | interface SizeStyle {
type Props (line 22) | interface Props {
FILE: packages/openui/src/Button/index.tsx
type Props (line 7) | interface Props extends React.HTMLProps<HTMLButtonElement & typeof Butto...
class Button (line 16) | class Button extends React.Component<Props, undefined> {
method render (line 23) | public render() {
FILE: packages/openui/src/Button/types.ts
type Size (line 4) | type Size = 'xsmall' | 'small' | 'medium' | 'large' | 'xlarge';
FILE: packages/openui/src/Footer/index.tsx
type Props (line 4) | interface Props extends React.Props<typeof Footer> {
function Footer (line 7) | function Footer({
FILE: packages/openui/src/Header/header.tsx
type Props (line 5) | interface Props {
function Header (line 15) | function Header(props: Props): JSX.Element {
FILE: packages/openui/src/Header/index.tsx
type Props (line 5) | interface Props {
type State (line 9) | interface State {
class Header (line 13) | class Header extends React.Component<Props, State> {
method constructor (line 14) | public constructor() {
method componentDidMount (line 26) | public componentDidMount() {
method componentWillUnmount (line 31) | public componentWillUnmount() {
method handleScroll (line 36) | private handleScroll() {
method backgroundColor (line 43) | private backgroundColor() {
method render (line 53) | public render() {
FILE: packages/openui/src/Header/styles.ts
function translateStyle (line 4) | function translateStyle({ state, height }: HeaderComponentProps) {
type OwnProps (line 12) | type OwnProps = Props & HeaderComponentProps;
function headerStyles (line 13) | function headerStyles() {
FILE: packages/openui/src/Header/utils.ts
type State (line 1) | type State = 'Pinned' | 'Unpinned';
type HeaderState (line 2) | interface HeaderState {
type GetHeaderState (line 8) | type GetHeaderState = (
FILE: packages/openui/src/Heading/index.tsx
type Tag (line 5) | type Tag = 'h1' | 'h2' | 'h3' | 'h4' | 'h5';
type Props (line 7) | interface Props {
class Heading (line 16) | class Heading extends React.Component<Props, undefined> {
method render (line 25) | public render() {
FILE: packages/openui/src/Headline/index.tsx
type Props (line 6) | interface Props {
class Headline (line 14) | class Headline extends React.Component<Props, undefined> {
method render (line 22) | public render() {
FILE: packages/openui/src/Headline/styleUtils.ts
type SizeMap (line 3) | interface SizeMap {
type HeadlineSize (line 17) | type HeadlineSize = 'small' | 'medium' | 'xlage' | 'xlarge';
function calculateSize (line 18) | function calculateSize(size: HeadlineSize): string {
FILE: packages/openui/src/Headline/types.ts
type TextAligment (line 4) | type TextAligment = 'center' | 'left' | 'right' | 'justify';
type FontWeight (line 5) | type FontWeight = 100 | 200 | 300 | 400 | 500 | 600 | 700 | 800;
FILE: packages/openui/src/Hero/index.tsx
type Props (line 4) | interface Props extends React.HTMLProps<typeof Hero> {
function Hero (line 10) | function Hero({
FILE: packages/openui/src/Hero/styles.ts
function background (line 4) | function background(props: Props) {
function height (line 16) | function height(props: Props) {
FILE: packages/openui/src/Image/index.tsx
type ImageSize (line 4) | type ImageSize = 'thumb' | 'xxsmall' | 'xsmall' | 'small' | 'medium' | '...
type Props (line 6) | interface Props {
FILE: packages/openui/src/LoadingIndicator/index.tsx
type Props (line 6) | interface Props extends React.Props<typeof LoadingIndicator> {
function LoadingIndicator (line 9) | function LoadingIndicator({
FILE: packages/openui/src/Markdown/index.tsx
type Props (line 5) | interface Props extends React.Props<typeof Markdown> {
function Markdown (line 8) | function Markdown({
FILE: packages/openui/src/Notification/index.tsx
type Props (line 6) | interface Props extends React.HTMLProps<typeof Notification> {
function Notification (line 10) | function Notification({
FILE: packages/openui/src/Notification/types.ts
type Status (line 2) | type Status = 'none' | 'ok' | 'warning' | 'error';
FILE: packages/openui/src/Paragraph/index.tsx
type ParagraphSize (line 4) | type ParagraphSize = 'small' | 'medium' | 'large' | 'xlarge';
type Margin (line 5) | type Margin = 'none' | 'small' | 'medium' | 'large';
type SizeMap (line 7) | interface SizeMap {
type MarginSizeMap (line 14) | interface MarginSizeMap {
type Props (line 21) | interface Props {
FILE: packages/openui/src/Paragraph/styleUtils.ts
function calculateMargin (line 18) | function calculateMargin(margin: Margin): string {
function calculateSize (line 22) | function calculateSize(size: ParagraphSize): string {
FILE: packages/openui/src/Paragraph/styles.ts
function marginCss (line 12) | function marginCss(margin: Margin) {
FILE: packages/openui/src/Section/index.tsx
function Section (line 5) | function Section({
FILE: packages/openui/src/SvgIcon/index.tsx
type Props (line 4) | type Props = SvgProps & React.HTMLProps<typeof SvgIcon>;
function SvgIcon (line 5) | function SvgIcon({
FILE: packages/openui/src/SvgIcon/types.ts
type SvgProps (line 2) | interface SvgProps extends React.SVGProps {
FILE: packages/openui/src/Toast/index.tsx
type Props (line 7) | interface Props extends BoxProps {
type State (line 14) | interface State {
class Toast (line 19) | class Toast extends React.Component<Props, State> {
method constructor (line 23) | constructor() {
method componentDidMount (line 31) | public componentDidMount() {
method handleClose (line 36) | private handleClose() {
method render (line 50) | public render() {
FILE: packages/openui/src/Toast/types.ts
type Status (line 3) | type Status = 'ok' | 'warning' | 'error' | 'none';
FILE: packages/openui/src/WithAnimation/animation.ts
function styles (line 4) | function styles(props: Props) {
function transition (line 23) | function transition(props: Props) {
function delay (line 30) | function delay({ delay }: Props) {
FILE: packages/openui/src/WithAnimation/index.tsx
type Props (line 6) | interface Props {
type HOC (line 15) | type HOC = (props: Props) => JSX.Element;
FILE: packages/openui/src/WithAnimation/types.ts
type AnimationType (line 3) | type AnimationType = 'fadeIn' | 'fadeInUp';
FILE: packages/openui/src/theming/types.ts
type ThemeColorMap (line 1) | interface ThemeColorMap {
FILE: packages/openui/src/utils/remStringFromPx.ts
type Px (line 1) | type Px = number;
type Rem (line 2) | type Rem = number;
FILE: src/client/components/Html/index.tsx
type Props (line 4) | interface Props {
function Html (line 12) | function Html({
FILE: src/client/features/Landing/index.tsx
type Props (line 4) | interface Props {
class Landing (line 8) | class Landing extends React.Component<Props, undefined> {
method render (line 9) | public render() {
FILE: src/client/features/Landing/presentation.tsx
function LandingPresentation (line 6) | function LandingPresentation({ title }: Props) {
FILE: src/client/features/Layout/index.tsx
type Props (line 4) | interface Props {
class Layout (line 8) | class Layout extends React.Component<Props, undefined> {
method render (line 9) | public render() {
FILE: src/client/features/Layout/presentation.tsx
function LayoutPresentation (line 5) | function LayoutPresentation({ children }: Props): JSX.Element {
FILE: src/client/shared/actions.ts
type DefaultAction (line 4) | interface DefaultAction extends Action {
type PayloadAction (line 8) | interface PayloadAction<P> extends Action {
FILE: src/client/shared/constants.ts
type DEFAULT_ACTION_TYPE (line 1) | type DEFAULT_ACTION_TYPE = '';
constant DEFAULT_ACTION_TYPE (line 2) | const DEFAULT_ACTION_TYPE: DEFAULT_ACTION_TYPE = '';
FILE: src/client/state.ts
type State (line 3) | interface State {
FILE: src/client/store.tsx
function createThunkMiddleware (line 16) | function createThunkMiddleware() {
FILE: src/client/theming/types.ts
type ThemeColorMap (line 1) | interface ThemeColorMap {
FILE: src/client/types.ts
type PayloadAction (line 7) | interface PayloadAction<P> extends Action {
type FormControlEventTarget (line 12) | interface FormControlEventTarget extends EventTarget {
FILE: src/server/db/index.ts
function seedPosts (line 5) | function seedPosts() {
function createSeedPosts (line 16) | function createSeedPosts() {
function createSeedData (line 34) | function createSeedData() {
FILE: src/server/db/utils/uuid.ts
function uuid (line 2) | function uuid() {
FILE: src/server/graphqlEntry.ts
function createSchema (line 12) | function createSchema() {
function graphqlEntry (line 30) | function graphqlEntry(app): Promise<express.Application> {
FILE: webpack.config.js
constant ROOT_PATH (line 4) | const ROOT_PATH = path.resolve(__dirname);
FILE: webpack.config.prod.js
constant ROOT_PATH (line 9) | const ROOT_PATH = path.resolve(__dirname);
FILE: webpack.config.server.js
constant ROOT_PATH (line 3) | const ROOT_PATH = path.resolve(__dirname);
Condensed preview — 414 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (407K chars).
[
{
"path": ".babelrc",
"chars": 497,
"preview": "{\n \"presets\": [\"es2015\", \"react\", \"stage-0\"],\n \"env\": {\n \"development\": {\n \"plugins\": [\n \"react-hot-loa"
},
{
"path": ".eslintignore",
"chars": 17,
"preview": "**/*.ts\n**/*.tsx\n"
},
{
"path": ".github/CHANGELOG.md",
"chars": 113,
"preview": "# Change Log\n\n## 1.0.1\n- Add jest snapshot / enzyme testing\n- Introduce changelog, contributing.md and roadmap.md"
},
{
"path": ".github/CONTRIBUTING.md",
"chars": 4425,
"preview": "# Contributing\n\nWhen contributing to this repository, please first discuss the change you wish to make via issue,\nemail,"
},
{
"path": ".gitignore",
"chars": 95,
"preview": "node_modules\nbuild\ndist\nnpm-debug.log\n.vscode\ncoverage\nyarn-error.log\n.DS_STORE\nlerna-debug.log"
},
{
"path": ".nvmrc",
"chars": 5,
"preview": "6.9.5"
},
{
"path": ".travis.yml",
"chars": 157,
"preview": "language: node_js\nnode_js:\n - \"6.9.5\"\nscript: npm run test\nnotifications:\n slack: scalable-react:HPFuyoipfw9RROPGrZr"
},
{
"path": "LICENSE",
"chars": 1079,
"preview": "The MIT License (MIT)\n\nCopyright (c) 2016 Ryan Collins\n\nPermission is hereby granted, free of charge, to any person obta"
},
{
"path": "Procfile",
"chars": 46,
"preview": "web: cross-env NODE_ENV=server node server.js\n"
},
{
"path": "README.md",
"chars": 15007,
"preview": "\n\n# __NOTICE__:\nThe maintainers of t"
},
{
"path": "config/.storybook/addons.js",
"chars": 157,
"preview": "// To get default addons (actions and links) \nimport '@kadira/storybook/addons';\n// To add the knobs addon\nimport '@ka"
},
{
"path": "config/.storybook/config.js",
"chars": 360,
"preview": "import { configure, setAddon } from '@kadira/storybook';\nimport infoAddon from '@kadira/react-storybook-addon-info';\nimp"
},
{
"path": "config/.storybook/stories/index.js",
"chars": 0,
"preview": ""
},
{
"path": "config/.storybook/webpack.config.js",
"chars": 372,
"preview": "const path = require('path');\nconst config = require('../../webpack.config.server.js');\nconst ROOT_PATH = path.resolve(_"
},
{
"path": "config/generators/cli.js",
"chars": 930,
"preview": "const componentGenerator = require('./component/index.js');\nconst SafeString = require('./utils/safeString').SafeString;"
},
{
"path": "config/generators/component/es6class.tsx.hbs",
"chars": 434,
"preview": "import * as React from 'react';\nimport Component from './styles';\n\nexport interface Props extends React.HTMLProps<typeof"
},
{
"path": "config/generators/component/export.ts.hbs",
"chars": 27,
"preview": "$1\n {{ properCase name }},"
},
{
"path": "config/generators/component/import.ts.hbs",
"chars": 93,
"preview": "$1\nimport {{ properCase name }} from '{{ getPath path 'components' }}{{ properCase name }}';\n"
},
{
"path": "config/generators/component/index.js",
"chars": 2022,
"preview": "const path = require('path');\nconst { trimTemplateFile } = require('../utils/');\n\nmodule.exports = {\n description: 'Gen"
},
{
"path": "config/generators/component/stateless.tsx.hbs",
"chars": 327,
"preview": "import * as React from 'react';\nimport Component from './styles';\n\nexport interface Props extends React.HTMLProps<typeof"
},
{
"path": "config/generators/component/styles.ts.hbs",
"chars": 104,
"preview": "import styled from 'styled-components';\n\nexport default styled.div`\n height: 100px;\n width: 200px;\n`;\n"
},
{
"path": "config/generators/component/types.ts.hbs",
"chars": 28,
"preview": "export { Props } from './';\n"
},
{
"path": "config/generators/container/actionCreators.js.hbs",
"chars": 721,
"preview": "import * as T from './constants';\nimport {\n LoadInitiationAction,\n LoadSuccessAction,\n LoadFailureAction,\n LoadCance"
},
{
"path": "config/generators/container/actions.js.hbs",
"chars": 668,
"preview": "import { PayloadAction } from 'root/types';\nimport { ErrorType } from './types';\nimport * as T from './constants';\n\nexpo"
},
{
"path": "config/generators/container/constants.js.hbs",
"chars": 732,
"preview": "export type LOAD_INITIATION_TYPE = '{{ uppercase name }}/LOAD_INITIATION';\nexport const LOAD_INITIATION: LOAD_INITIATION"
},
{
"path": "config/generators/container/export.js.hbs",
"chars": 27,
"preview": "$1\n {{ properCase name }},"
},
{
"path": "config/generators/container/import.js.hbs",
"chars": 91,
"preview": "$1\nimport {{ properCase name }} from '{{ getPath path 'features' }}{{ properCase name }}';\n"
},
{
"path": "config/generators/container/index.js",
"chars": 5654,
"preview": "const path = require('path');\nconst { trimTemplateFile } = require('../utils/');\n\nmodule.exports = {\n description: 'Add"
},
{
"path": "config/generators/container/index.js.hbs",
"chars": 1858,
"preview": "import * as React from 'react';\n{{#if wantActionsAndReducer}}\nimport { connect } from 'react-redux';\nimport { bindAction"
},
{
"path": "config/generators/container/presentation.js.hbs",
"chars": 748,
"preview": "import * as React from 'react';\n{{#if wantActionsAndReducer}}\nimport { StateProps } from './types';\n{{else}}\nimport { Pr"
},
{
"path": "config/generators/container/reducer.export-state.js.hbs",
"chars": 54,
"preview": "$1\n {{ camelCase name }}: {{ camelCase name }}State,\n"
},
{
"path": "config/generators/container/reducer.export.js.hbs",
"chars": 26,
"preview": "$1\n {{ camelCase name }},"
},
{
"path": "config/generators/container/reducer.import.js.hbs",
"chars": 79,
"preview": "$1\nimport {{ camelCase name }} from './features/{{ properCase name }}/reducer';"
},
{
"path": "config/generators/container/reducer.js.hbs",
"chars": 622,
"preview": "import * as T from './constants';\nimport initialState from './state';\nimport {\n Action,\n State,\n} from './types';\n\ncon"
},
{
"path": "config/generators/container/selectors.js.hbs",
"chars": 892,
"preview": "import { State as GlobalState } from '../../state';\nimport { State, ErrorType } from './types';\nimport { createSelector,"
},
{
"path": "config/generators/container/state-type.js.hbs",
"chars": 54,
"preview": "$1\n {{ camelCase name }}: {{ properCase name }}State;"
},
{
"path": "config/generators/container/state.import.js.hbs",
"chars": 139,
"preview": "$1\nimport { initialState as {{ camelCase name }}State, State as {{ properCase name }}State } from './features/{{ properC"
},
{
"path": "config/generators/container/state.js.hbs",
"chars": 245,
"preview": "import { ErrorType } from './types';\n\nexport interface State {\n isLoading: boolean;\n error?: ErrorType;\n data?: strin"
},
{
"path": "config/generators/container/styles.js.hbs",
"chars": 223,
"preview": "import styled from 'styled-components';\n\nexport const Section = styled.section`\n padding: 60px;\n background-color: #f5"
},
{
"path": "config/generators/container/types.export.ts.hbs",
"chars": 32,
"preview": "$1\n {{ properCase name }}Types,"
},
{
"path": "config/generators/container/types.import.ts.hbs",
"chars": 88,
"preview": "$1\nimport * as {{ properCase name }}Types from './features/{{ properCase name }}/types';"
},
{
"path": "config/generators/container/types.ts.hbs",
"chars": 708,
"preview": "{{#if wantActionsAndReducer}}\nimport { ActionCreatorsMapObject } from 'redux';\nimport {\n LoadInitiationAction,\n LoadSu"
},
{
"path": "config/generators/utils/index.js",
"chars": 273,
"preview": "const fs = require('fs');\n\nconst trimTemplateFile = (template) => {\n // Loads the template file and trims the whitespac"
},
{
"path": "config/generators/utils/safeString.js",
"chars": 198,
"preview": "function SafeString(string) {\n this.string = string;\n}\n\nSafeString.prototype.toString = SafeString.prototype.toHTML = f"
},
{
"path": "config/ignoreAssets.js",
"chars": 321,
"preview": "/* eslint-disable */\n(function() {\n require.extensions['.scss'] = () => {\n return;\n };\n require.extensions['.css']"
},
{
"path": "config/scripts/clean.js",
"chars": 58,
"preview": "require('shelljs/global');\n\nrm('-fr', './packages/docs');\n"
},
{
"path": "config/testing/__mocks__/fileMock.js",
"chars": 34,
"preview": "module.exports = 'test-file-stub';"
},
{
"path": "config/testing/__mocks__/styleMock.js",
"chars": 20,
"preview": "module.exports = {};"
},
{
"path": "config/testing/preprocessor.js",
"chars": 3042,
"preview": "'use strict';\n\n\nconst babel = require('babel-core');\nconst tsc = require('typescript');\nconst crypto = require('crypto')"
},
{
"path": "config/testing/templates/_index.prod.html",
"chars": 378,
"preview": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n <meta charset=\"UTF-8\">\n <meta http-equiv=X-UA-Compatible content=\"IE=edge\">\n "
},
{
"path": "config/types/require.d.ts",
"chars": 229,
"preview": "declare var require: {\n (path: string): any;\n <T>(path: string): T;\n (paths: string[], callback: (...modules: any[]) "
},
{
"path": "devServer.js",
"chars": 678,
"preview": "var path = require('path');\nvar webpack = require('webpack');\nvar express = require('express');\nvar devMiddleware = requ"
},
{
"path": "index.html",
"chars": 358,
"preview": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n <meta charset=\"UTF-8\">\n <meta name=\"viewport\" content=\"width=device-width,ini"
},
{
"path": "lerna.json",
"chars": 97,
"preview": "{\n \"lerna\": \"2.0.0-beta.38\",\n \"packages\": [\n \"packages/*\"\n ],\n \"version\": \"independent\"\n}\n"
},
{
"path": "netlify.toml",
"chars": 64,
"preview": "[build]\n command = \"npm run deploy\"\n publish = \"build/public\"\n"
},
{
"path": "package.json",
"chars": 4993,
"preview": "{\n \"name\": \"scalable-react-typescript-boilerplate\",\n \"version\": \"1.0.1\",\n \"description\": \"React + TypeScript boilerpl"
},
{
"path": "packages/docs/.babelrc",
"chars": 497,
"preview": "{\n \"presets\": [\"es2015\", \"react\", \"stage-0\"],\n \"env\": {\n \"development\": {\n \"plugins\": [\n \"react-hot-loa"
},
{
"path": "packages/docs/config/generators/cli.js",
"chars": 932,
"preview": "const componentGenerator = require('./component/index.js');\nconst SafeString = require('./utils/safeString').SafeString;"
},
{
"path": "packages/docs/config/generators/component/es6class.tsx.hbs",
"chars": 434,
"preview": "import * as React from 'react';\nimport Component from './styles';\n\nexport interface Props extends React.HTMLProps<typeof"
},
{
"path": "packages/docs/config/generators/component/export.ts.hbs",
"chars": 27,
"preview": "$1\n {{ properCase name }},"
},
{
"path": "packages/docs/config/generators/component/import.ts.hbs",
"chars": 93,
"preview": "$1\nimport {{ properCase name }} from '{{ getPath path 'components' }}{{ properCase name }}';\n"
},
{
"path": "packages/docs/config/generators/component/index.js",
"chars": 2022,
"preview": "const path = require('path');\nconst { trimTemplateFile } = require('../utils/');\n\nmodule.exports = {\n description: 'Gen"
},
{
"path": "packages/docs/config/generators/component/stateless.tsx.hbs",
"chars": 327,
"preview": "import * as React from 'react';\nimport Component from './styles';\n\nexport interface Props extends React.HTMLProps<typeof"
},
{
"path": "packages/docs/config/generators/component/styles.ts.hbs",
"chars": 104,
"preview": "import styled from 'styled-components';\n\nexport default styled.div`\n height: 100px;\n width: 200px;\n`;\n"
},
{
"path": "packages/docs/config/generators/component/types.ts.hbs",
"chars": 28,
"preview": "export { Props } from './';\n"
},
{
"path": "packages/docs/config/generators/container/actionCreators.js.hbs",
"chars": 721,
"preview": "import * as T from './constants';\nimport {\n LoadInitiationAction,\n LoadSuccessAction,\n LoadFailureAction,\n LoadCance"
},
{
"path": "packages/docs/config/generators/container/actions.js.hbs",
"chars": 668,
"preview": "import { PayloadAction } from 'root/types';\nimport { ErrorType } from './types';\nimport * as T from './constants';\n\nexpo"
},
{
"path": "packages/docs/config/generators/container/constants.js.hbs",
"chars": 732,
"preview": "export type LOAD_INITIATION_TYPE = '{{ uppercase name }}/LOAD_INITIATION';\nexport const LOAD_INITIATION: LOAD_INITIATION"
},
{
"path": "packages/docs/config/generators/container/export.js.hbs",
"chars": 27,
"preview": "$1\n {{ properCase name }},"
},
{
"path": "packages/docs/config/generators/container/import.js.hbs",
"chars": 93,
"preview": "$1\nimport {{ properCase name }} from '{{ getPath path 'containers' }}{{ properCase name }}';\n"
},
{
"path": "packages/docs/config/generators/container/index.js",
"chars": 5672,
"preview": "const path = require('path');\nconst { trimTemplateFile } = require('../utils/');\n\nmodule.exports = {\n description: 'Add"
},
{
"path": "packages/docs/config/generators/container/index.js.hbs",
"chars": 1858,
"preview": "import * as React from 'react';\n{{#if wantActionsAndReducer}}\nimport { connect } from 'react-redux';\nimport { bindAction"
},
{
"path": "packages/docs/config/generators/container/presentation.js.hbs",
"chars": 748,
"preview": "import * as React from 'react';\n{{#if wantActionsAndReducer}}\nimport { StateProps } from './types';\n{{else}}\nimport { Pr"
},
{
"path": "packages/docs/config/generators/container/reducer.export-state.js.hbs",
"chars": 54,
"preview": "$1\n {{ camelCase name }}: {{ camelCase name }}State,\n"
},
{
"path": "packages/docs/config/generators/container/reducer.export.js.hbs",
"chars": 26,
"preview": "$1\n {{ camelCase name }},"
},
{
"path": "packages/docs/config/generators/container/reducer.import.js.hbs",
"chars": 81,
"preview": "$1\nimport {{ camelCase name }} from './containers/{{ properCase name }}/reducer';"
},
{
"path": "packages/docs/config/generators/container/reducer.js.hbs",
"chars": 622,
"preview": "import * as T from './constants';\nimport initialState from './state';\nimport {\n Action,\n State,\n} from './types';\n\ncon"
},
{
"path": "packages/docs/config/generators/container/selectors.js.hbs",
"chars": 892,
"preview": "import { State as GlobalState } from '../../state';\nimport { State, ErrorType } from './types';\nimport { createSelector,"
},
{
"path": "packages/docs/config/generators/container/state-type.js.hbs",
"chars": 54,
"preview": "$1\n {{ camelCase name }}: {{ properCase name }}State;"
},
{
"path": "packages/docs/config/generators/container/state.import.js.hbs",
"chars": 141,
"preview": "$1\nimport { initialState as {{ camelCase name }}State, State as {{ properCase name }}State } from './containers/{{ prope"
},
{
"path": "packages/docs/config/generators/container/state.js.hbs",
"chars": 245,
"preview": "import { ErrorType } from './types';\n\nexport interface State {\n isLoading: boolean;\n error?: ErrorType;\n data?: strin"
},
{
"path": "packages/docs/config/generators/container/styles.js.hbs",
"chars": 223,
"preview": "import styled from 'styled-components';\n\nexport const Section = styled.section`\n padding: 60px;\n background-color: #f5"
},
{
"path": "packages/docs/config/generators/container/types.export.ts.hbs",
"chars": 32,
"preview": "$1\n {{ properCase name }}Types,"
},
{
"path": "packages/docs/config/generators/container/types.import.ts.hbs",
"chars": 90,
"preview": "$1\nimport * as {{ properCase name }}Types from './containers/{{ properCase name }}/types';"
},
{
"path": "packages/docs/config/generators/container/types.ts.hbs",
"chars": 708,
"preview": "{{#if wantActionsAndReducer}}\nimport { ActionCreatorsMapObject } from 'redux';\nimport {\n LoadInitiationAction,\n LoadSu"
},
{
"path": "packages/docs/config/generators/utils/index.js",
"chars": 273,
"preview": "const fs = require('fs');\n\nconst trimTemplateFile = (template) => {\n // Loads the template file and trims the whitespac"
},
{
"path": "packages/docs/config/generators/utils/safeString.js",
"chars": 198,
"preview": "function SafeString(string) {\n this.string = string;\n}\n\nSafeString.prototype.toString = SafeString.prototype.toHTML = f"
},
{
"path": "packages/docs/config/ignoreAssets.js",
"chars": 321,
"preview": "/* eslint-disable */\n(function() {\n require.extensions['.scss'] = () => {\n return;\n };\n require.extensions['.css']"
},
{
"path": "packages/docs/config/types/require.d.ts",
"chars": 229,
"preview": "declare var require: {\n (path: string): any;\n <T>(path: string): T;\n (paths: string[], callback: (...modules: any[]) "
},
{
"path": "packages/docs/devServer.js",
"chars": 678,
"preview": "var path = require('path');\nvar webpack = require('webpack');\nvar express = require('express');\nvar devMiddleware = requ"
},
{
"path": "packages/docs/index.html",
"chars": 358,
"preview": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n <meta charset=\"UTF-8\">\n <meta name=\"viewport\" content=\"width=device-width,ini"
},
{
"path": "packages/docs/package.json",
"chars": 3905,
"preview": "{\n \"name\": \"srtb-docs\",\n \"version\": \"1.0.0\",\n \"description\": \"Docs for the scalable-react-typescript-boilerplate proj"
},
{
"path": "packages/docs/server.js",
"chars": 117,
"preview": "require('babel-core/register');\nrequire('./config/ignoreAssets');\nvar app = require('./build/src/server/index.jsx');\n"
},
{
"path": "packages/docs/src/client/apolloClient.ts",
"chars": 442,
"preview": "import { ApolloClient, createNetworkInterface } from 'apollo-client';\n\ndeclare var window: {\n __INITIAL_STATE__: string"
},
{
"path": "packages/docs/src/client/components/AddComment/__tests__/__mocks__/addCommentMocks.mock.ts",
"chars": 136,
"preview": "export const addCommentProps = {\n input: 'Mock input for test',\n onSubmit: jest.fn(),\n onChange: jest.fn(),\n onKeyUp"
},
{
"path": "packages/docs/src/client/components/AddComment/__tests__/__snapshots__/index.test.tsx.snap",
"chars": 730,
"preview": "// Jest Snapshot v1, https://goo.gl/fbAQLP\n\nexports[`<AddComment /> rendering should render with supplied props 1`] = `\n"
},
{
"path": "packages/docs/src/client/components/AddComment/__tests__/index.test.tsx",
"chars": 2659,
"preview": "import { shallow, mount } from 'enzyme';\nimport { shallowToJson } from 'enzyme-to-json';\nimport * as React from 'react';"
},
{
"path": "packages/docs/src/client/components/AddComment/index.tsx",
"chars": 967,
"preview": "import * as React from 'react';\nimport { AddCommentProps } from './types';\nimport {\n Wrapper,\n CommentWrapper,\n PicWr"
},
{
"path": "packages/docs/src/client/components/AddComment/styles.ts",
"chars": 1367,
"preview": "import styled from 'styled-components';\n\nexport const Wrapper = styled.div`\n min-height: 5.3125rem;\n margin-bottom: 1."
},
{
"path": "packages/docs/src/client/components/AddComment/types.ts",
"chars": 363,
"preview": "import * as React from 'react';\nimport AddComment from './';\n\nexport interface AddCommentProps extends React.Props<typeo"
},
{
"path": "packages/docs/src/client/components/Comment/__tests__/__mocks__/commentMocks.mock.ts",
"chars": 261,
"preview": "export const commentProps = {\n author: 'Comment Author',\n body: 'Comment Body',\n};\n\nexport const commentPicProps = {\n "
},
{
"path": "packages/docs/src/client/components/Comment/__tests__/__snapshots__/index.test.tsx.snap",
"chars": 906,
"preview": "// Jest Snapshot v1, https://goo.gl/fbAQLP\n\nexports[`<Comment /> default should render a plain comment with other props "
},
{
"path": "packages/docs/src/client/components/Comment/__tests__/index.test.tsx",
"chars": 663,
"preview": "import { shallow } from 'enzyme';\nimport { shallowToJson } from 'enzyme-to-json';\nimport * as React from 'react';\nimport"
},
{
"path": "packages/docs/src/client/components/Comment/index.tsx",
"chars": 626,
"preview": "import * as React from 'react';\nimport defaultImage from './default';\nimport { CommentProps } from './types';\nimport {\n "
},
{
"path": "packages/docs/src/client/components/Comment/styles.ts",
"chars": 980,
"preview": "import styled from 'styled-components';\n\nexport const Wrapper = styled.div`\n min-height: 5.3125rem;\n margin-bottom: 1."
},
{
"path": "packages/docs/src/client/components/Comment/types.ts",
"chars": 185,
"preview": "import * as React from 'react';\nimport Comment from '../';\n\nexport interface CommentProps extends React.Props<typeof Com"
},
{
"path": "packages/docs/src/client/components/Html/index.tsx",
"chars": 1184,
"preview": "import * as React from 'react';\nimport serialize from 'serialize-javascript';\n\nconst Html = (props: {\n content: string,"
},
{
"path": "packages/docs/src/client/components/NavBar/__tests__/__mocks__/navBarMocks.mock.ts",
"chars": 222,
"preview": "const links = [\n {\n url: 'https://medium.com',\n text: 'Medium',\n },\n {\n url: 'https://www.ryancollins.io/',\n"
},
{
"path": "packages/docs/src/client/components/NavBar/__tests__/__snapshots__/index.test.tsx.snap",
"chars": 841,
"preview": "// Jest Snapshot v1, https://goo.gl/fbAQLP\n\nexports[`<NavBar /> default should render NavBar with links and text 1`] = `"
},
{
"path": "packages/docs/src/client/components/NavBar/__tests__/index.test.tsx",
"chars": 432,
"preview": "import { shallow } from 'enzyme';\nimport { shallowToJson } from 'enzyme-to-json';\nimport * as React from 'react';\nimport"
},
{
"path": "packages/docs/src/client/components/NavBar/index.tsx",
"chars": 831,
"preview": "import * as React from 'react';\nimport { Anchor } from 'openui';\nimport { NavBarProps } from './types';\nimport {\n Nav,\n"
},
{
"path": "packages/docs/src/client/components/NavBar/styles.ts",
"chars": 746,
"preview": "import styled from 'styled-components';\n\nexport const Nav = styled.nav`\n width: 100%;\n background: #0a0a0a;\n color: #"
},
{
"path": "packages/docs/src/client/components/NavBar/types.ts",
"chars": 215,
"preview": "import * as React from 'react';\nimport NavBar from './';\n\ninterface Navlink { url: string; text: string; }\nexport interf"
},
{
"path": "packages/docs/src/client/components/Pic/index.tsx",
"chars": 192,
"preview": "import styled from 'styled-components';\nimport {PicStyle} from './styles';\n\nexport interface PicProps {\n url?: string;\n"
},
{
"path": "packages/docs/src/client/components/Pic/styles.ts",
"chars": 255,
"preview": "import { css } from 'styled-components';\nimport {PicProps} from './index';\n\nexport const PicStyle = css`\n height: 2.25r"
},
{
"path": "packages/docs/src/client/components/Pic/types.ts",
"chars": 25,
"preview": "export * from './index';\n"
},
{
"path": "packages/docs/src/client/components/Post/index.tsx",
"chars": 898,
"preview": "import * as React from 'react';\nimport { Markdown, Image, Headline, Article, Box } from 'openui';\nimport { Comment, AddC"
},
{
"path": "packages/docs/src/client/components/Post/types.ts",
"chars": 423,
"preview": "interface PostComment {\n body: string;\n author: string;\n}\n\nexport interface PostProps {\n content: string;\n image: st"
},
{
"path": "packages/docs/src/client/components/PostCard/index.tsx",
"chars": 920,
"preview": "import * as React from 'react';\nimport { Link } from 'react-router';\nimport shortenText from './shortenText';\nimport {\n "
},
{
"path": "packages/docs/src/client/components/PostCard/shortenText.ts",
"chars": 176,
"preview": "export default function shortenText(text: string, maxLength: number) {\n if (text.length > maxLength) {\n return `${te"
},
{
"path": "packages/docs/src/client/components/PostCard/styles.ts",
"chars": 1306,
"preview": "import styled from 'styled-components';\nimport { SvgIcon } from 'openui';\n\nexport interface CardThumbnailProps {\n image"
},
{
"path": "packages/docs/src/client/components/PostCard/types.ts",
"chars": 102,
"preview": "export interface PostCardProps {\n content: string;\n id: string;\n image: string;\n title: string;\n}\n"
},
{
"path": "packages/docs/src/client/components/index.ts",
"chars": 313,
"preview": "/* GENERATOR-IMPORT */\nimport PostCard from './PostCard';\nimport AddComment from './AddComment';\nimport Comment from './"
},
{
"path": "packages/docs/src/client/components/utils/index.ts",
"chars": 82,
"preview": "import remStringFromPx from './remStringFromPx';\n\nexport default remStringFromPx;\n"
},
{
"path": "packages/docs/src/client/components/utils/remStringFromPx.ts",
"chars": 181,
"preview": "type Px = number;\ntype Rem = number;\n\nconst rootRem: number = 16;\nconst calculateRem = (px: Px): Rem => (px / rootRem);\n"
},
{
"path": "packages/docs/src/client/containers/About/about.ts",
"chars": 1202,
"preview": "// tslint:disable\nexport default {\n githubLogo: 'https://github.com/RyanCCollins/cdn/blob/master/misc/github-512.png?ra"
},
{
"path": "packages/docs/src/client/containers/About/contributors.ts",
"chars": 576,
"preview": "import bio from './about';\n\ninterface Contributor {\n name: string;\n avatar: string;\n github: string;\n bio: string;\n}"
},
{
"path": "packages/docs/src/client/containers/About/index.tsx",
"chars": 2126,
"preview": "import * as React from 'react';\nimport {\n Avatar,\n Anchor,\n Article,\n Image,\n Markdown,\n Heading,\n Headline,\n} fr"
},
{
"path": "packages/docs/src/client/containers/About/styles.ts",
"chars": 2238,
"preview": "import styled from 'styled-components';\n\nexport const Container = styled.div`\n min-height: calc(100vh - 54px);\n width:"
},
{
"path": "packages/docs/src/client/containers/App/__tests__/__snapshots__/index.test.tsx.snap",
"chars": 131,
"preview": "// Jest Snapshot v1, https://goo.gl/fbAQLP\n\nexports[`DocsContainer should render with default props 1`] = `<Connect(Fea"
},
{
"path": "packages/docs/src/client/containers/App/__tests__/actionCreators.test.ts",
"chars": 641,
"preview": "import { actionCreators } from '../actionCreators';\nimport * as types from '../constants';\n\n// Action Creator Test as a "
},
{
"path": "packages/docs/src/client/containers/App/__tests__/index.test.tsx",
"chars": 817,
"preview": "import * as React from 'react';\nimport Container from '../';\nimport State from '../state';\nimport { shallow } from 'enzy"
},
{
"path": "packages/docs/src/client/containers/App/__tests__/reducer.test.ts",
"chars": 671,
"preview": "import reducer from '../reducer';\nimport { actionCreators } from '../actionCreators';\nimport { initialState } from '../s"
},
{
"path": "packages/docs/src/client/containers/App/__tests__/selectors.test.ts",
"chars": 1872,
"preview": "import { selectIsMobile, selectLogoText, selectNavLinks } from '../selectors';\nimport { State } from '../../../State';\n\n"
},
{
"path": "packages/docs/src/client/containers/App/actionCreators.ts",
"chars": 358,
"preview": "import * as types from './constants';\nimport { defaultAction } from 'shared/actionCreators';\nimport {\n SetIsMobileActio"
},
{
"path": "packages/docs/src/client/containers/App/actions.ts",
"chars": 292,
"preview": "import { DefaultAction } from 'shared/actions';\nimport * as types from './constants';\nimport { Action } from 'redux';\n\ne"
},
{
"path": "packages/docs/src/client/containers/App/constants.ts",
"chars": 109,
"preview": "export type SET_MOBILE_TYPE = 'APP/SET_MOBILE';\nexport const SET_MOBILE: SET_MOBILE_TYPE = 'APP/SET_MOBILE';\n"
},
{
"path": "packages/docs/src/client/containers/App/index.tsx",
"chars": 976,
"preview": "import * as React from 'react';\nimport { connect } from 'react-redux';\nimport { bindActionCreators, Dispatch } from 'red"
},
{
"path": "packages/docs/src/client/containers/App/presentation.tsx",
"chars": 4584,
"preview": "import * as React from 'react';\nimport { NavBar } from 'components';\nimport { Box, Heading, Footer, Paragraph, SvgIcon, "
},
{
"path": "packages/docs/src/client/containers/App/reducer.ts",
"chars": 505,
"preview": "import { Reducer } from 'redux';\nimport * as types from './constants';\nimport { FeatureAction } from './actions';\nimport"
},
{
"path": "packages/docs/src/client/containers/App/selectors.ts",
"chars": 600,
"preview": "import { createSelector, Selector } from 'reselect';\nimport { State } from 'state';\nimport { State as FeatureState, NavL"
},
{
"path": "packages/docs/src/client/containers/App/state.ts",
"chars": 450,
"preview": "export interface NavLink {\n text: string;\n url: string;\n}\n\nexport interface State {\n isMobile: boolean;\n navLinks: N"
},
{
"path": "packages/docs/src/client/containers/App/styles.ts",
"chars": 194,
"preview": "import styled from 'styled-components';\n\nexport const Author = styled.div`\n color: white;\n padding: 10px;\n`;\n\nexport c"
},
{
"path": "packages/docs/src/client/containers/App/types.ts",
"chars": 296,
"preview": "import App from '../';\n\nexport interface NavLink { url: string; text: string; };\n\nexport interface Props extends React.P"
},
{
"path": "packages/docs/src/client/containers/Blog/index.tsx",
"chars": 1813,
"preview": "import * as React from 'react';\nimport { graphql } from 'react-apollo';\nimport { Box, Headline, Section, LoadingIndicato"
},
{
"path": "packages/docs/src/client/containers/Blog/posts.graphql.ts",
"chars": 145,
"preview": "import gql from 'graphql-tag';\n\nexport default gql`\n query Posts {\n posts {\n id: _id\n title\n image\n "
},
{
"path": "packages/docs/src/client/containers/Blog/styles.ts",
"chars": 95,
"preview": "import styled from 'styled-components';\n\nexport default styled.hr`\n border-top: 4px solid;\n`;\n"
},
{
"path": "packages/docs/src/client/containers/Blog/types.ts",
"chars": 298,
"preview": "import Blog from '../';\n\nexport interface Post {\n id: string;\n title: string;\n image: string;\n content: string;\n}\n\ne"
},
{
"path": "packages/docs/src/client/containers/BlogPost/__tests__/__mocks__/blogPostPresentation.mock.ts",
"chars": 590,
"preview": "export default {\n post: {\n id: '58a0ccb112b4c56440f5d6a7',\n title: 'Welcome!',\n image: 'https://raw.githubuser"
},
{
"path": "packages/docs/src/client/containers/BlogPost/__tests__/__mocks__/blogPostSelectors.mock.ts",
"chars": 59,
"preview": "export default {\n blogPost: {\n input: 'Money',\n },\n};\n"
},
{
"path": "packages/docs/src/client/containers/BlogPost/__tests__/__snapshots__/index.test.tsx.snap",
"chars": 1426,
"preview": "// Jest Snapshot v1, https://goo.gl/fbAQLP\n\nexports[`<BlogPost /> container should render as expected 1`] = `\n<Provider\n"
},
{
"path": "packages/docs/src/client/containers/BlogPost/__tests__/actionCreators.test.ts",
"chars": 313,
"preview": "import * as T from '../constants';\nimport actionCreators from '../actionCreators';\n\ndescribe('blogPost actionCreators', "
},
{
"path": "packages/docs/src/client/containers/BlogPost/__tests__/index.test.tsx",
"chars": 986,
"preview": "import MockProvider, { getMockStore } from 'redux-mock-provider';\nimport { shallowToJson } from 'enzyme-to-json';\nimport"
},
{
"path": "packages/docs/src/client/containers/BlogPost/__tests__/reducer.test.ts",
"chars": 446,
"preview": "import reducer from '../reducer';\nimport actionCreators from '../actionCreators';\nimport { initialState } from '../state"
},
{
"path": "packages/docs/src/client/containers/BlogPost/__tests__/selectors.test.ts",
"chars": 624,
"preview": "import state from './__mocks__/blogPostSelectors.mock';\nimport { initialState as globalState } from '../../../state';\nim"
},
{
"path": "packages/docs/src/client/containers/BlogPost/actionCreators.ts",
"chars": 528,
"preview": "import { ActionCreator, ActionCreatorsMapObject } from 'redux';\nimport { Input } from './types';\nimport * as types from "
},
{
"path": "packages/docs/src/client/containers/BlogPost/actions.ts",
"chars": 226,
"preview": "import { Action } from 'redux';\nimport { Input } from './types';\nimport * as T from './constants';\n\nexport interface Inp"
},
{
"path": "packages/docs/src/client/containers/BlogPost/apollo.ts",
"chars": 736,
"preview": "import { graphql } from 'react-apollo';\nimport BlogPost from './';\nimport PostQuery from './postQuery.graphql';\nimport C"
},
{
"path": "packages/docs/src/client/containers/BlogPost/commentMutation.graphql.ts",
"chars": 200,
"preview": "import gql from 'graphql-tag';\n\nexport default gql`\n mutation CreateComment($post: ID!, $body: String, $author: String)"
},
{
"path": "packages/docs/src/client/containers/BlogPost/constants.ts",
"chars": 96,
"preview": "export type INPUT_TYPE = 'BLOG_POST/INPUT';\nexport const INPUT: INPUT_TYPE = 'BLOG_POST/INPUT';\n"
},
{
"path": "packages/docs/src/client/containers/BlogPost/index.tsx",
"chars": 2739,
"preview": "import * as React from 'react';\nimport { Dispatch, bindActionCreators } from 'redux';\nimport { connect } from 'react-red"
},
{
"path": "packages/docs/src/client/containers/BlogPost/postQuery.graphql.ts",
"chars": 215,
"preview": "import gql from 'graphql-tag';\n\nexport default gql`\n query Post($id: ID!) {\n post(id: $id) {\n id: _id\n tit"
},
{
"path": "packages/docs/src/client/containers/BlogPost/presentation.tsx",
"chars": 1113,
"preview": "import * as React from 'react';\nimport { Post } from 'components';\nimport { LoadingIndicator, Section, Notification } fr"
},
{
"path": "packages/docs/src/client/containers/BlogPost/reducer.ts",
"chars": 409,
"preview": "import { Reducer } from 'redux';\nimport * as T from './constants';\nimport { ActionTypes } from './actions';\nimport { Sta"
},
{
"path": "packages/docs/src/client/containers/BlogPost/selectors.ts",
"chars": 344,
"preview": "import { createSelector, Selector } from 'reselect';\nimport { State } from '../../state';\nimport { State as BlogPostStat"
},
{
"path": "packages/docs/src/client/containers/BlogPost/state.ts",
"chars": 155,
"preview": "import { Input } from './types';\n\nexport interface State {\n input?: Input;\n}\n\nexport const initialState: State = {\n in"
},
{
"path": "packages/docs/src/client/containers/BlogPost/styles.ts",
"chars": 104,
"preview": "import styled from 'styled-components';\n\nexport const StyledHr = styled.hr`\n border-top: 4px solid;\n`;\n"
},
{
"path": "packages/docs/src/client/containers/BlogPost/types.ts",
"chars": 1037,
"preview": "import * as React from 'react';\nimport { Props } from './';\nimport { Props as PresentationProps } from './presentation';"
},
{
"path": "packages/docs/src/client/containers/Docs/__tests__/__mocks__/docsMocks.mock.ts",
"chars": 54,
"preview": "export default {\n pad: 'medium',\n size: 'large',\n};\n"
},
{
"path": "packages/docs/src/client/containers/Docs/__tests__/__snapshots__/index.test.tsx.snap",
"chars": 131,
"preview": "// Jest Snapshot v1, https://goo.gl/fbAQLP\n\nexports[`DocsContainer should render with default props 1`] = `<Connect(Fea"
},
{
"path": "packages/docs/src/client/containers/Docs/__tests__/actionCreators.test.ts",
"chars": 1211,
"preview": "import * as types from '../constants';\nimport { actionCreators } from '../actionCreators';\n\n// Action Creator Test as a "
},
{
"path": "packages/docs/src/client/containers/Docs/__tests__/index.test.tsx",
"chars": 736,
"preview": "import * as React from 'react';\nimport { Provider } from 'react-redux';\nimport { Store } from 'redux';\nimport { shallow "
},
{
"path": "packages/docs/src/client/containers/Docs/__tests__/logic.test.ts",
"chars": 860,
"preview": "import { createMockStore } from 'redux-logic-test';\nimport * as actionTypes from '../constants';\nimport rootLogic from '"
},
{
"path": "packages/docs/src/client/containers/Docs/__tests__/reducer.test.ts",
"chars": 1081,
"preview": "import reducer from '../reducer';\nimport { actionCreators } from '../actionCreators';\nimport { initialState } from '../s"
},
{
"path": "packages/docs/src/client/containers/Docs/__tests__/selectors.test.ts",
"chars": 1410,
"preview": "import { selectIsLoading, selectError } from '../selectors';\nimport { State } from '../../../State';\n\nconst testError: s"
},
{
"path": "packages/docs/src/client/containers/Docs/actionCreators.ts",
"chars": 883,
"preview": "import * as types from './constants';\nimport { defaultAction } from 'shared/actionCreators';\nimport {\n LoadInitiationAc"
},
{
"path": "packages/docs/src/client/containers/Docs/actions.ts",
"chars": 753,
"preview": "import { DefaultAction } from 'shared/actions';\nimport * as types from './constants';\nimport { Action } from 'redux';\n\ne"
},
{
"path": "packages/docs/src/client/containers/Docs/constants.ts",
"chars": 614,
"preview": "export type LOAD_INITIATION_TYPE = 'DOCS/LOAD_INITIATION';\nexport const LOAD_INITIATION: LOAD_INITIATION_TYPE = 'DOCS/LO"
},
{
"path": "packages/docs/src/client/containers/Docs/index.tsx",
"chars": 991,
"preview": "import * as React from 'react';\nimport { connect } from 'react-redux';\nimport { bindActionCreators, Dispatch } from 'red"
},
{
"path": "packages/docs/src/client/containers/Docs/logic.ts",
"chars": 630,
"preview": "import { createLogic } from 'redux-logic';\nimport * as actionTypes from './constants';\n\nconst url = 'https://raw.githubu"
},
{
"path": "packages/docs/src/client/containers/Docs/presentation.tsx",
"chars": 1819,
"preview": "import * as React from 'react';\nimport { Article, Headline, LoadingIndicator, Section, Notification } from 'openui';\nimp"
},
{
"path": "packages/docs/src/client/containers/Docs/reducer.ts",
"chars": 907,
"preview": "import { Reducer } from 'redux';\nimport * as types from './constants';\nimport { FeatureAction } from './actions';\nimport"
},
{
"path": "packages/docs/src/client/containers/Docs/selectors.ts",
"chars": 599,
"preview": "import { createSelector, Selector } from 'reselect';\nimport { State } from 'state';\nimport { State as FeatureState } fro"
},
{
"path": "packages/docs/src/client/containers/Docs/state.ts",
"chars": 219,
"preview": "export interface State {\n markdownContent?: string;\n error?: string;\n isLoading: boolean;\n}\n\nexport const initialStat"
},
{
"path": "packages/docs/src/client/containers/Docs/styles.ts",
"chars": 95,
"preview": "import styled from 'styled-components';\n\nexport default styled.hr`\n border-top: 4px solid;\n`;\n"
},
{
"path": "packages/docs/src/client/containers/Docs/types.ts",
"chars": 212,
"preview": "export { actionCreators } from './actionCreators';\nexport * from './actions';\nexport * from './constants';\nexport * from"
},
{
"path": "packages/docs/src/client/containers/Features/features.ts",
"chars": 1244,
"preview": "// tslint:disable\nexport default {\n styledComponents: `__Visual Primitives for the component age.__\n\n Use the best bit"
},
{
"path": "packages/docs/src/client/containers/Features/index.tsx",
"chars": 3795,
"preview": "import * as React from 'react';\nimport { Heading, Headline, Image, Button, Markdown, Anchor } from 'openui';\nimport { Pr"
},
{
"path": "packages/docs/src/client/containers/Features/styles.ts",
"chars": 1206,
"preview": "import styled from 'styled-components';\n\nexport const Container = styled.div`\n min-height: 100vh;\n width: 100vw;\n`;\n\ni"
},
{
"path": "packages/docs/src/client/containers/Features/types.ts",
"chars": 194,
"preview": "import Features from './';\nimport * as React from 'react';\nimport { ThemeColorMap } from '../../types';\n\nexport interfac"
},
{
"path": "packages/docs/src/client/containers/Home/index.tsx",
"chars": 491,
"preview": "import * as React from 'react';\nimport { Features } from 'containers';\nimport { ThemeColorMap } from '../../types';\nimpo"
},
{
"path": "packages/docs/src/client/containers/Home/presentation.tsx",
"chars": 2074,
"preview": "import * as React from 'react';\nimport { Heading, Section, Hero, Paragraph, Button, Anchor, Box } from 'openui';\nimport "
},
{
"path": "packages/docs/src/client/containers/Home/styles.ts",
"chars": 767,
"preview": "import styled from 'styled-components';\n\nexport const Container = styled.div`\n min-height: 100vh;\n width: 100vw;\n`;\n\ne"
},
{
"path": "packages/docs/src/client/containers/Home/types.ts",
"chars": 127,
"preview": "import { Props } from './';\nimport { Props as PresentationProps } from './presentation';\n\nexport { Props, PresentationPr"
},
{
"path": "packages/docs/src/client/containers/TodoApp/__tests__/__mocks__/presentation.mock.ts",
"chars": 188,
"preview": "export default {\n todos: [\n {\n text: 'foo',\n },\n {\n text: 'bar',\n },\n ],\n input: 'foo',\n onInp"
},
{
"path": "packages/docs/src/client/containers/TodoApp/__tests__/__mocks__/selectors.mock.ts",
"chars": 153,
"preview": "export default {\n todoApp: {\n todos: [\n {\n text: 'LOL',\n },\n {\n text: '🐒🚀',\n },\n "
},
{
"path": "packages/docs/src/client/containers/TodoApp/__tests__/__snapshots__/index.test.tsx.snap",
"chars": 1332,
"preview": "// Jest Snapshot v1, https://goo.gl/fbAQLP\n\nexports[`<TodoApp /> container should render as expected 1`] = `\n<Provider\n "
},
{
"path": "packages/docs/src/client/containers/TodoApp/__tests__/actionCreators.test.ts",
"chars": 702,
"preview": "import * as T from '../constants';\nimport actionCreators from '../actionCreators';\n\ndescribe('todoApp actionCreators', ("
},
{
"path": "packages/docs/src/client/containers/TodoApp/__tests__/index.test.tsx",
"chars": 935,
"preview": "import MockProvider, { getMockStore } from 'redux-mock-provider';\nimport { shallowToJson } from 'enzyme-to-json';\nimport"
},
{
"path": "packages/docs/src/client/containers/TodoApp/__tests__/reducer.test.ts",
"chars": 1267,
"preview": "import reducer from '../reducer';\nimport actionCreators from '../actionCreators';\nimport { initialState } from '../state"
}
]
// ... and 214 more files (download for full content)
About this extraction
This page contains the full source code of the scalable-react/scalable-react-typescript-boilerplate GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 414 files (346.7 KB), approximately 102.0k tokens, and a symbol index with 313 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.