initial boilerplate import
commit
fffed7a048
|
|
@ -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*
|
||||
|
|
@ -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.
|
||||
|
|
@ -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=="
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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"
|
||||
}
|
||||
}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 24 KiB |
|
|
@ -0,0 +1,10 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title></title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -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"
|
||||
}
|
||||
|
|
@ -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>
|
||||
|
||||
);
|
||||
}
|
||||
|
|
@ -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>
|
||||
);
|
||||
}
|
||||
|
|
@ -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>
|
||||
);
|
||||
}
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
export * from './header';
|
||||
export * from './about';
|
||||
export * from './members';
|
||||
|
|
@ -0,0 +1 @@
|
|||
export * from './page';
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
import * as React from 'react';
|
||||
|
||||
export const MembersPage: React.StatelessComponent<{}> = () => {
|
||||
return (
|
||||
<div className="row">
|
||||
<h2> Members Page</h2>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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'));
|
||||
|
|
@ -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>
|
||||
);
|
||||
}
|
||||
|
|
@ -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"
|
||||
]
|
||||
}
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"extends": "./tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"module": "commonjs"
|
||||
}
|
||||
}
|
||||
|
|
@ -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"
|
||||
]
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue