Skip to content

Commit

Permalink
Initial Project Setup
Browse files Browse the repository at this point in the history
Added initial setup for React/TypeScript project.
Includes webpack, jest, typescript, tslint, and i18next
  • Loading branch information
dmiller9911 committed Apr 13, 2018
1 parent acc5aed commit 5e6191e
Show file tree
Hide file tree
Showing 30 changed files with 8,688 additions and 2 deletions.
50 changes: 50 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*

# Runtime data
pids
*.pid
*.seed
*.pid.lock

# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov

# Coverage directory used by tools like istanbul
coverage

# nyc test coverage
.nyc_output

# node-waf configuration
.lock-wscript

# Compiled binary addons (https://nodejs.org/api/addons.html)
build/Release

# Dependency directories
node_modules/

# Optional npm cache directory
.npm

# Optional eslint cache
.eslintcache

# Optional REPL history
.node_repl_history

# Output of 'npm pack'
*.tgz

# Yarn Integrity file
.yarn-integrity

# dotenv environment variables file
.env

public/
1 change: 1 addition & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
package.json
6 changes: 6 additions & 0 deletions .prettierrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"parser": "typescript",
"singleQuote": true,
"tabWidth": 2,
"useTabs": false
}
16 changes: 16 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"[typescript]": {
"editor.formatOnSave": true
},
"[typescriptreact]": {
"editor.formatOnSave": true
},
"[javascript]": {
"editor.formatOnSave": true
},
"[json]": {
"editor.formatOnSave": true
},
"tslint.autoFixOnSave": true,
"tslint.jsEnable": true
}
44 changes: 42 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,42 @@
# UI
SaltCellar UI
# SaltCellar UI

[![AGPLv3][license-badge]][license]

User interface for SaltCellar based on Patternfly [![Patternfly][pf-logo]][patternfly]

## Requirements
* [NodeJS v8+][nodejs]
* [yarn 1.5+][yarn]

## Getting Started
1. Install requirements listed above.
2. Clone repo, and open a terminal in the base of this project.
3. Run the command `yarn` to install all the dependencies.

### Running Development Server
```
yarn start
```

### Building
```
yarn build
```

### Testing
```
yarn test
```

### Serving Production files
```
yarn build && yarn serve
```


[pf-logo]: https://www.patternfly.org/assets/img/logo.svg
[patternfly]: https://www.patternfly.org/
[yarn]: https://yarnpkg.com/en/
[nodejs]: https://nodejs.org/en/
[license-badge]: https://img.shields.io/github/license/SaltCellar/UI.svg?longCache=true&style=for-the-badge
[license]: https://github.com/SaltCellar/UI/blob/master/LICENSE
12 changes: 12 additions & 0 deletions jest.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
module.exports = {
testEnvironment: 'jsdom',
clearMocks: true,
timers: 'fake',
transform: {
'^.+\\.(ts|tsx)$': '<rootDir>/test/preprocessor.js'
},
setupFiles: ['./test/test.env.ts'],
testRegex: '\\.test\\.(jsx?|tsx?)$',
moduleFileExtensions: ['ts', 'tsx', 'js'],
snapshotSerializers: ['jest-glamor-react', 'enzyme-to-json/serializer']
};
81 changes: 81 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
{
"name": "salt-cellar-ui",
"version": "0.0.1",
"description": "User Interface for Salt Cellar application",
"main": "index.js",
"repository": "https://github.com/SaltCellar/UI.git",
"author": "Red Hat",
"license": "GNU AGPLv3",
"private": true,
"scripts": {
"build": "yarn clean && yarn webpack --env production",
"clean": "rimraf public/",
"lint": "yarn lint:ts && yarn lint:locales",
"lint:locales": "node scripts/syncLocales --check",
"lint:ts": "tslint --project tsconfig.json",
"precommit": "lint-staged",
"serve": "cross-env NODE_ENV=production node ./scripts/serve",
"start": "webpack-dev-server",
"test": "jest",
"verify": "tsc --noEmit"
},
"lint-staged": {
"*.{js,jsx,ts,tsx}": [
"yarn lint:ts --fix",
"prettier --write",
"git add"
]
},
"dependencies": {
"@babel/core": "^7.0.0-beta.44",
"@babel/plugin-syntax-decorators": "^7.0.0-beta.44",
"@babel/plugin-syntax-dynamic-import": "^7.0.0-beta.44",
"@babel/plugin-syntax-jsx": "^7.0.0-beta.44",
"@babel/plugin-syntax-typescript": "^7.0.0-beta.44",
"@types/enzyme": "^3.1.9",
"@types/enzyme-adapter-react-16": "^1.0.2",
"@types/express": "^4.11.1",
"@types/i18next": "^8.4.3",
"@types/jest": "^22.2.3",
"@types/react": "^16.3.9",
"@types/react-dom": "^16.0.5",
"@types/react-i18next": "^7.3.2",
"@types/react-router-dom": "^4.2.6",
"@types/webpack": "^4.1.3",
"babel-loader": "^8.0.0-beta",
"compression": "^1.7.2",
"cross-env": "^5.1.4",
"enzyme": "^3.3.0",
"enzyme-adapter-react-16": "^1.1.1",
"enzyme-to-json": "^3.3.3",
"express": "^4.16.3",
"glamor": "^2.20.40",
"glamorous": "^4.12.2",
"html-loader": "^0.5.5",
"html-webpack-plugin": "^3.2.0",
"i18next": "^11.1.1",
"i18next-express-middleware": "^1.1.1",
"i18next-json-sync": "^2.2.0",
"jest": "^22.4.3",
"jest-glamor-react": "^4.2.1",
"react": "^16.3.1",
"react-dom": "^16.3.1",
"react-hot-loader": "^4.0.1",
"react-i18next": "^7.5.1",
"react-router-dom": "^4.2.2",
"rimraf": "^2.6.2",
"ts-jest": "^22.4.2",
"ts-loader": "^4.2.0",
"tslint": "^5.9.1",
"tslint-config-prettier": "^1.10.0",
"tslint-react": "^3.5.1",
"typescript": "^2.8.1",
"webpack": "^4.5.0",
"webpack-cli": "^2.0.14",
"webpack-dev-server": "^3.1.3"
},
"devDependencies": {
"husky": "^0.14.3",
"lint-staged": "^7.0.4"
}
}
35 changes: 35 additions & 0 deletions scripts/serve.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
const express = require('express');
const path = require('path');
const app = express();
const i18next = require('i18next');
const i18nextMiddleware = require('i18next-express-middleware');
const fs = require('fs');
const url = require('url');
const compression = require('compression');

const publicDir = path.resolve(__dirname, '../public');
const languages = fs.readdirSync(publicDir);

i18next.use(i18nextMiddleware.LanguageDetector).init({
languages,
whitelist: languages
});

app.use(
compression(),
i18nextMiddleware.handle(i18next),
(req, res, next) => {
req.url = `/${req.language}${req.url}`;
next();
},
express.static(publicDir)
);

// ALlow the Client Router to handle 404 pages.
app.get('*', (req, res) => {
res.sendFile(path.join(publicDir, req.language, 'index.html'));
});

app.listen(3000, () => {
console.log('🌎 Example app listening on port 3000'); // tslint:disable-line no-console
});
15 changes: 15 additions & 0 deletions scripts/syncLocales.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
const sync = require('i18next-json-sync').default;
const path = require('path');

const check = process.argv.includes('--check');
const srcDir = path.resolve(__dirname, '../src');

sync({
check,
files: path.join(srcDir, '**/locales/*.json'),
primary: 'en',
createResources: [],
space: 2,
lineEndings: 'LF',
finalNewline: true
});
11 changes: 11 additions & 0 deletions src/App.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
jest.mock('./i18next');

import { shallow } from 'enzyme';
import React from 'react';
import App from './App';

// TODO: Replace with useful test
test('renders', () => {
const view = shallow(<App language="en" />);
expect(view).toMatchSnapshot();
});
54 changes: 54 additions & 0 deletions src/App.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import React from 'react';
import { hot } from 'react-hot-loader';
import { I18nextProvider } from 'react-i18next';
import { Route, Switch } from 'react-router-dom';
import { initI18next } from './i18next';
import { styled } from './styles/styled';
import asyncComponent from './utils/asyncComponent';

const NotFound = asyncComponent(() =>
import(/* webpackChunkName: "notFound" */ './components/notFound')
);

const Home = asyncComponent(() =>
import(/* webpackChunkName: "home" */ './components/home')
);

interface Props {
language: string;
}

interface State {
isLoaded: boolean;
}

const Header = styled('header');
const Content = styled('main');
const Navigation = styled('aside');

class App extends React.Component<Props, State> {
public state = {
isLoaded: false
};

private i18n = initI18next(this.props.language);

public render() {
return (
<I18nextProvider i18n={this.i18n}>
<>
<Header>Header</Header>
<Navigation>Side Navigation</Navigation>
<Content>
<Switch>
<Route exact component={Home} path="/" />
<Route component={NotFound} />
</Switch>
</Content>
</>
</I18nextProvider>
);
}
}

export default hot(module)(App);
1 change: 1 addition & 0 deletions src/__mocks__/i18next.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export const initI18next = jest.fn(() => ({}));
28 changes: 28 additions & 0 deletions src/__snapshots__/App.test.tsx.snap
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`renders 1`] = `
<I18nextProvider
i18n={Object {}}
>
<React.Fragment>
<glamorous(header)>
Header
</glamorous(header)>
<glamorous(aside)>
Side Navigation
</glamorous(aside)>
<glamorous(main)>
<Switch>
<Route
component={[Function]}
exact={true}
path="/"
/>
<Route
component={[Function]}
/>
</Switch>
</glamorous(main)>
</React.Fragment>
</I18nextProvider>
`;
11 changes: 11 additions & 0 deletions src/components/home/home.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import React from 'react';
import { I18n } from 'react-i18next';
import { RouteComponentProps } from 'react-router-dom';

interface Props extends RouteComponentProps<{}> {}

const Home: React.SFC<Props> = () => (
<I18n>{t => <div>{t('hello')}</div>}</I18n>
);

export default Home;
4 changes: 4 additions & 0 deletions src/components/home/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import { hot } from 'react-hot-loader';
import Home from './home';

export default hot(module)(Home);
4 changes: 4 additions & 0 deletions src/components/notFound/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import { hot } from 'react-hot-loader';
import NotFound from './notFound';

export default hot(module)(NotFound);
Loading

0 comments on commit 5e6191e

Please sign in to comment.