initial boilerplate import
This commit is contained in:
21
.gitignore
vendored
Normal file
21
.gitignore
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
# See https://help.github.com/ignore-files/ for more about ignoring files.
|
||||
|
||||
# dependencies
|
||||
/node_modules
|
||||
|
||||
# testing
|
||||
/coverage
|
||||
|
||||
# production
|
||||
/build
|
||||
|
||||
# misc
|
||||
.DS_Store
|
||||
.env.local
|
||||
.env.development.local
|
||||
.env.test.local
|
||||
.env.production.local
|
||||
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
22
SPEC.md
Normal file
22
SPEC.md
Normal file
@@ -0,0 +1,22 @@
|
||||
Q1 Blogging platform with in-place comments
|
||||
Tests: Machine coding, technology decision making, experience with web apps in production, problem solving
|
||||
|
||||
Criteria. We evaluate that you can:
|
||||
Break down code into a tiered structure
|
||||
Present working code
|
||||
Write code that is testable
|
||||
Create something that can be deployed with ease.
|
||||
Design use-able APIs around abstract product requirements
|
||||
|
||||
Problem statement:
|
||||
You are to create a blogging product that supports comments on paragraphs. Not comments on the blog, but on a specific paragraph. Requirements follow:
|
||||
I should be able to add blog posts. Blog posts have a unique random identifier, a title and plain text where paragraphs are separated by two new-line characters.
|
||||
I should be able to view all blog posts (list-mode) starting with first 5 and then the next 5 and so on. This view will not have any comments.
|
||||
I should be able to click on one of these blogs to view it in full-mode. In full-mode, all past comments on the text are visible next to the text. Also, the viewer is able to comment on a paragraph of text. In essence, the comment is on a paragraph.
|
||||
The API, when it responds with comments should provide some means to figure out which comment is on which paragraph. The notation for that is up to you to choose.
|
||||
|
||||
Non-requirements: Please do not think of or address any of these items:
|
||||
There are no users. No authentication. Everyone could be an admin and a viewer.
|
||||
The comments are not attached to any user, because there are none. There are just blogs and comments.
|
||||
You are not required to create the UI to achieve any of the goals. Simple APIs are all we are looking for. These could be HTTP APIs. The HTTP APIs should be able to respond to all the user stories enumerated above.
|
||||
You are not required to write tests for this. You may, if that is how you work.
|
||||
24
package-lock.json
generated
Normal file
24
package-lock.json
generated
Normal file
@@ -0,0 +1,24 @@
|
||||
{
|
||||
"name": "typeset-blog",
|
||||
"version": "0.1.0",
|
||||
"lockfileVersion": 1,
|
||||
"dependencies": {
|
||||
"@types/history": {
|
||||
"version": "4.6.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/history/-/history-4.6.0.tgz",
|
||||
"integrity": "sha512-2A0stT6b61DANLErAfSkeQ77N+A3FbR7ardUJUP3xm9f4W8qtG9ispBYDUX42Fl1EbR0rqSV3IWjbB6ew7hXRw=="
|
||||
},
|
||||
"@types/react-router": {
|
||||
"version": "4.0.14",
|
||||
"resolved": "https://registry.npmjs.org/@types/react-router/-/react-router-4.0.14.tgz",
|
||||
"integrity": "sha512-wbcqBGFv2KcBo0fIief2MJeE5e1Ph9Z35FzWPmadNMzd5dwpFGLVxyDQiLc30u3ehNrgG7JlQcFYLe5YJnToyA==",
|
||||
"dependencies": {
|
||||
"@types/react": {
|
||||
"version": "16.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/react/-/react-16.0.1.tgz",
|
||||
"integrity": "sha512-0ofqK0AZwPGnbWrpowUsdSVxI7iqt6vpIpf9OC6hvAo/ZzJ7eNibys6kuE3aJwcLLIsDinU1ent/n3oYj+99yQ=="
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
27
package.json
Normal file
27
package.json
Normal file
@@ -0,0 +1,27 @@
|
||||
{
|
||||
"name": "typeset-blog",
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@types/jest": "^20.0.6",
|
||||
"@types/node": "^8.0.20",
|
||||
"@types/react": "^16.0.1",
|
||||
"@types/react-dom": "^15.5.2",
|
||||
"@types/react-router": "^4.0.14",
|
||||
"@types/react-router-dom": "^4.0.7",
|
||||
"react": "^15.6.1",
|
||||
"react-dom": "^15.6.1",
|
||||
"react-router": "^4.1.2",
|
||||
"react-router-dom": "^4.1.2",
|
||||
"react-scripts-ts": "2.5.0",
|
||||
"react-semantic-ui": "^0.2.0",
|
||||
"semantic-ui-react": "^0.71.3"
|
||||
},
|
||||
"devDependencies": {},
|
||||
"scripts": {
|
||||
"start": "react-scripts-ts start",
|
||||
"build": "react-scripts-ts build",
|
||||
"test": "react-scripts-ts test --env=jsdom",
|
||||
"eject": "react-scripts-ts eject"
|
||||
}
|
||||
}
|
||||
BIN
public/favicon.ico
Normal file
BIN
public/favicon.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 24 KiB |
10
public/index.html
Executable file
10
public/index.html
Executable file
@@ -0,0 +1,10 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title></title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
</body>
|
||||
</html>
|
||||
15
public/manifest.json
Normal file
15
public/manifest.json
Normal file
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"short_name": "React App",
|
||||
"name": "Create React App Sample",
|
||||
"icons": [
|
||||
{
|
||||
"src": "favicon.ico",
|
||||
"sizes": "192x192",
|
||||
"type": "image/png"
|
||||
}
|
||||
],
|
||||
"start_url": "./index.html",
|
||||
"display": "standalone",
|
||||
"theme_color": "#000000",
|
||||
"background_color": "#ffffff"
|
||||
}
|
||||
12
src/app.tsx
Executable file
12
src/app.tsx
Executable file
@@ -0,0 +1,12 @@
|
||||
import * as React from 'react';
|
||||
import { Header } from './components';
|
||||
|
||||
export const App: React.StatelessComponent<{}> = (props) => {
|
||||
return (
|
||||
<div className="container-fluid">
|
||||
<Header />
|
||||
{props.children}
|
||||
</div>
|
||||
|
||||
);
|
||||
}
|
||||
79
src/components/about.tsx
Executable file
79
src/components/about.tsx
Executable file
@@ -0,0 +1,79 @@
|
||||
import * as React from 'react';
|
||||
|
||||
export const About: React.StatelessComponent<{}> = () => {
|
||||
return (
|
||||
<div className="row about-page">
|
||||
<h1 className="jumbotron">03 Navigation</h1>
|
||||
|
||||
<div className="col-xs-12">
|
||||
<h1>
|
||||
<small>
|
||||
This sample takes as starting point sample "02 Components".
|
||||
</small>
|
||||
</h1>
|
||||
<div className="col-xs-12">
|
||||
<h3>
|
||||
<small>
|
||||
We are adding page navigation to this project:
|
||||
</small>
|
||||
</h3>
|
||||
<ul>
|
||||
<li><h3><small>We have added two pages (about, members).</small></h3></li>
|
||||
<li><h3><small>The user can navigate by clicking on links in a common navbar.</small></h3></li>
|
||||
</ul>
|
||||
<h3>
|
||||
<small>
|
||||
We are using <a target="_blank" href="https://github.com/reactjs/react-router">react-router</a> for the navigation support
|
||||
</small>
|
||||
</h3>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="col-xs-12 top-buffer">
|
||||
<h3>Highlights</h3>
|
||||
<hr />
|
||||
<h3>
|
||||
<small>
|
||||
The most interesting parts worth to take a look
|
||||
</small>
|
||||
</h3>
|
||||
</div>
|
||||
|
||||
<div className="col-xs-12 top-buffer">
|
||||
<ul>
|
||||
<li className="top-buffer">
|
||||
<h4><b>Router:</b></h4>
|
||||
<ul className="top-buffer">
|
||||
<li>
|
||||
<h4>
|
||||
index.ts: <small>routes configuration.</small>
|
||||
</h4>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
|
||||
<li className="top-buffer">
|
||||
<h4><b>Components:</b></h4>
|
||||
<ul className="top-buffer">
|
||||
<li>
|
||||
<h4>
|
||||
app.tsx: <small>header + page container.</small>
|
||||
</h4>
|
||||
</li>
|
||||
<li>
|
||||
<h4>
|
||||
header.tsx: <small>navigation links.</small>
|
||||
</h4>
|
||||
</li>
|
||||
<li>
|
||||
<h4>
|
||||
aboutPage.tsx / membersPage.tsx: <small>pages</small>
|
||||
</h4>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
17
src/components/header.tsx
Executable file
17
src/components/header.tsx
Executable file
@@ -0,0 +1,17 @@
|
||||
import * as React from 'react';
|
||||
import { Link } from 'react-router-dom';
|
||||
|
||||
export const Header: React.StatelessComponent<{}> = () => {
|
||||
return (
|
||||
<div className="row">
|
||||
<nav className="navbar navbar-default">
|
||||
<div className="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
|
||||
<ul className="nav navbar-nav">
|
||||
<li><Link to="/about">About</Link></li>
|
||||
<li><Link to="/members">Members</Link></li>
|
||||
</ul>
|
||||
</div>
|
||||
</nav>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
3
src/components/index.ts
Executable file
3
src/components/index.ts
Executable file
@@ -0,0 +1,3 @@
|
||||
export * from './header';
|
||||
export * from './about';
|
||||
export * from './members';
|
||||
1
src/components/members/index.ts
Executable file
1
src/components/members/index.ts
Executable file
@@ -0,0 +1 @@
|
||||
export * from './page';
|
||||
9
src/components/members/page.tsx
Executable file
9
src/components/members/page.tsx
Executable file
@@ -0,0 +1,9 @@
|
||||
import * as React from 'react';
|
||||
|
||||
export const MembersPage: React.StatelessComponent<{}> = () => {
|
||||
return (
|
||||
<div className="row">
|
||||
<h2> Members Page</h2>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
21
src/css/site.css
Executable file
21
src/css/site.css
Executable file
@@ -0,0 +1,21 @@
|
||||
.top-buffer{
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.about-page{
|
||||
position: relative;
|
||||
top: -20px;
|
||||
}
|
||||
|
||||
.about-page .jumbotron{
|
||||
margin: 0;
|
||||
background:rgba(9,69,95,0.8);
|
||||
color: white;
|
||||
border-radius: 0 !important;
|
||||
}
|
||||
|
||||
/*React apply activeClassName to <a> element, but Bootstrap active class is over <li> element*/
|
||||
.navbar .nav .active, .navbar-default .navbar-nav > .active > a, .navbar-default .navbar-nav > .active > a:hover, .navbar-default .navbar-nav > .active > a:focus{
|
||||
background: #e7e7e7 !important;
|
||||
color: #333 !important;
|
||||
}
|
||||
7
src/index.tsx
Executable file
7
src/index.tsx
Executable file
@@ -0,0 +1,7 @@
|
||||
import * as React from 'react';
|
||||
import * as ReactDOM from 'react-dom';
|
||||
import { AppRouter } from './router';
|
||||
|
||||
ReactDOM.render(
|
||||
<AppRouter />
|
||||
, document.getElementById('root'));
|
||||
16
src/router.tsx
Executable file
16
src/router.tsx
Executable file
@@ -0,0 +1,16 @@
|
||||
import * as React from 'react';
|
||||
import { Route, HashRouter } from 'react-router-dom';
|
||||
import { App } from './app';
|
||||
import { About, MembersPage } from './components';
|
||||
|
||||
export const AppRouter: React.StatelessComponent<{}> = () => {
|
||||
return (
|
||||
<HashRouter>
|
||||
<div >
|
||||
<Route exact={true} path="/" component={App} />
|
||||
<Route path="/about" component={About} />
|
||||
<Route path="/members" component={MembersPage} />
|
||||
</div>
|
||||
</HashRouter>
|
||||
);
|
||||
}
|
||||
29
tsconfig.json
Normal file
29
tsconfig.json
Normal file
@@ -0,0 +1,29 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"outDir": "build/dist",
|
||||
"module": "esnext",
|
||||
"target": "es5",
|
||||
"lib": ["es6", "dom"],
|
||||
"sourceMap": true,
|
||||
"allowJs": true,
|
||||
"jsx": "react",
|
||||
"moduleResolution": "node",
|
||||
"rootDir": "src",
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"noImplicitReturns": true,
|
||||
"noImplicitThis": true,
|
||||
"noImplicitAny": true,
|
||||
"strictNullChecks": true,
|
||||
"suppressImplicitAnyIndexErrors": true,
|
||||
"noUnusedLocals": true
|
||||
},
|
||||
"exclude": [
|
||||
"node_modules",
|
||||
"build",
|
||||
"scripts",
|
||||
"acceptance-tests",
|
||||
"webpack",
|
||||
"jest",
|
||||
"src/setupTests.ts"
|
||||
]
|
||||
}
|
||||
6
tsconfig.test.json
Normal file
6
tsconfig.test.json
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"extends": "./tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"module": "commonjs"
|
||||
}
|
||||
}
|
||||
99
tslint.json
Normal file
99
tslint.json
Normal file
@@ -0,0 +1,99 @@
|
||||
{
|
||||
"extends": ["tslint-react"],
|
||||
"rules": {
|
||||
"align": [
|
||||
true,
|
||||
"parameters",
|
||||
"arguments",
|
||||
"statements"
|
||||
],
|
||||
"ban": false,
|
||||
"class-name": true,
|
||||
"comment-format": [
|
||||
true,
|
||||
"check-space"
|
||||
],
|
||||
"curly": true,
|
||||
"eofline": false,
|
||||
"forin": true,
|
||||
"indent": [ true, "spaces" ],
|
||||
"interface-name": [true, "never-prefix"],
|
||||
"jsdoc-format": true,
|
||||
"jsx-no-lambda": false,
|
||||
"jsx-no-multiline-js": false,
|
||||
"label-position": true,
|
||||
"max-line-length": [ true, 120 ],
|
||||
"member-ordering": [
|
||||
true,
|
||||
"public-before-private",
|
||||
"static-before-instance",
|
||||
"variables-before-functions"
|
||||
],
|
||||
"no-any": true,
|
||||
"no-arg": true,
|
||||
"no-bitwise": true,
|
||||
"no-console": [
|
||||
true,
|
||||
"log",
|
||||
"error",
|
||||
"debug",
|
||||
"info",
|
||||
"time",
|
||||
"timeEnd",
|
||||
"trace"
|
||||
],
|
||||
"no-consecutive-blank-lines": true,
|
||||
"no-construct": true,
|
||||
"no-debugger": true,
|
||||
"no-duplicate-variable": true,
|
||||
"no-empty": true,
|
||||
"no-eval": true,
|
||||
"no-shadowed-variable": true,
|
||||
"no-string-literal": true,
|
||||
"no-switch-case-fall-through": true,
|
||||
"no-trailing-whitespace": false,
|
||||
"no-unused-expression": true,
|
||||
"no-use-before-declare": true,
|
||||
"one-line": [
|
||||
true,
|
||||
"check-catch",
|
||||
"check-else",
|
||||
"check-open-brace",
|
||||
"check-whitespace"
|
||||
],
|
||||
"quotemark": [true, "single", "jsx-double"],
|
||||
"radix": true,
|
||||
"semicolon": [true, "always"],
|
||||
"switch-default": true,
|
||||
|
||||
"trailing-comma": false,
|
||||
|
||||
"triple-equals": [ true, "allow-null-check" ],
|
||||
"typedef": [
|
||||
true,
|
||||
"parameter",
|
||||
"property-declaration"
|
||||
],
|
||||
"typedef-whitespace": [
|
||||
true,
|
||||
{
|
||||
"call-signature": "nospace",
|
||||
"index-signature": "nospace",
|
||||
"parameter": "nospace",
|
||||
"property-declaration": "nospace",
|
||||
"variable-declaration": "nospace"
|
||||
}
|
||||
],
|
||||
"variable-name": [true, "ban-keywords", "check-format", "allow-leading-underscore", "allow-pascal-case"],
|
||||
"whitespace": [
|
||||
true,
|
||||
"check-branch",
|
||||
"check-decl",
|
||||
"check-module",
|
||||
"check-operator",
|
||||
"check-separator",
|
||||
"check-type",
|
||||
"check-typecast"
|
||||
]
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user