diff --git a/package.json b/package.json index 1178eb9..a95d346 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,9 @@ "dependencies": { "inferno": "^3.9.0", "inferno-component": "^3.9.0", - "inferno-scripts": "4.2.0" + "inferno-router": "^3.9.0", + "inferno-scripts": "4.2.0", + "milligram": "^1.3.0" }, "proxy": "http://localhost:3000", "scripts": { diff --git a/src/App.css b/src/App.css deleted file mode 100644 index bd8fe9f..0000000 --- a/src/App.css +++ /dev/null @@ -1,22 +0,0 @@ -.App { - text-align: center; -} - -.App-logo { - height: 80px; -} - -.App-header { - background-color: #f8f8f8; - height: 150px; - padding: 20px; - color: #3d464d; -} - -.App-intro { - font-size: large; -} - -code { - color: #e73a37; -} \ No newline at end of file diff --git a/src/App.js b/src/App.js index 8038db6..398e404 100644 --- a/src/App.js +++ b/src/App.js @@ -1,21 +1,17 @@ -import { version } from 'inferno'; import Component from 'inferno-component'; import './registerServiceWorker'; -import Logo from './logo'; -import './App.css'; + +import Navbar from './Navbar'; class App extends Component { - render() { + render({ children }) { return ( -
-
- -

{`Welcome to Inferno ${version}`}

-
-

- To get started, edit src/App.js and save to reload. -

-
+
+ +
+ {children} +
+
); } } diff --git a/src/Login/index.js b/src/Login/index.js new file mode 100644 index 0000000..7116037 --- /dev/null +++ b/src/Login/index.js @@ -0,0 +1,35 @@ +import Component from 'inferno-component'; + +class Login extends Component { + state = { + email: '' + } + onChange = e => { + this.setState({ email: e.target.value }) + } + onSubmit = e => { + e.preventDefault(); + const { email } = this.state; + window.email = email; + window.localStorage.setItem('email', email); + window.browserHistory.push('/') + } + render() { + const { email } = this.state; + + return ( +
+

Login

+
+
+ + +
+ +
+
+ ) + } +} + +export default Login; diff --git a/src/Logout/index.js b/src/Logout/index.js new file mode 100644 index 0000000..5fbe255 --- /dev/null +++ b/src/Logout/index.js @@ -0,0 +1,13 @@ +import Component from 'inferno-component'; + +class Logout extends Component { + render() { + window.email = ''; + window.localStorage.removeItem('email'); + window.browserHistory.push('/') + + return
+ } +} + +export default Logout; diff --git a/src/Navbar/index.js b/src/Navbar/index.js new file mode 100644 index 0000000..044fd7f --- /dev/null +++ b/src/Navbar/index.js @@ -0,0 +1,17 @@ +import './navbar.css'; +import { Link } from 'inferno-router'; + +export default () => ( + +) diff --git a/src/Navbar/navbar.css b/src/Navbar/navbar.css new file mode 100644 index 0000000..a427b25 --- /dev/null +++ b/src/Navbar/navbar.css @@ -0,0 +1,53 @@ +.navigation { + background:#f4f5f6; + border-bottom:.1rem solid #d1d1d1; + display:block; + height:5.2rem; + left:0; + max-width:100%; + position:fixed; + right:0; + top:0; + width:100%; + z-index:1 +} +.navigation .container { + padding-bottom:0; + padding-top:0 +} +.navigation .navigation-list { + list-style:none; + margin-bottom:0; + margin-right:5rem +} +@media (min-width:80rem) { + .navigation .navigation-list { + margin-right:0 + } +} +.navigation .navigation-item { + float:left; + margin-bottom:0; + margin-left:2.5rem; + position:relative +} +.navigation .img { + fill:#9b4dca; + height:2rem; + position:relative; + top:.3rem +} +.navigation .navigation-title,.navigation .title { + color:#606c76; + position:relative +} +.navigation .navigation-link,.navigation .navigation-title,.navigation .title { + display:inline; + font-size:1.6rem; + line-height:5.2rem; + padding:0; + text-decoration:none +} +.navigation .navigation-link.active { + color:#606c76 +} diff --git a/src/QuestionViewer/index.js b/src/QuestionViewer/index.js new file mode 100644 index 0000000..cd35227 --- /dev/null +++ b/src/QuestionViewer/index.js @@ -0,0 +1,33 @@ +/* global fetchWithAuth */ + +import Component from 'inferno-component'; + +class QuestionViewer extends Component { + state = { + question: {}, + loading: true, + error: '', + } + async componentDidMount() { + const { qno } = this.props.params; + var res = await fetchWithAuth(`/questions/${qno}`); + res = await res.json(); + if (!res.error) this.setState({ question: res, loading: false }) + else this.setState({ error: res.error, loading: false }) + } + render() { + const { loading, question, error } = this.state + return ( +
+ {loading &&
Loading...
} +

Q{question.qno}: {question.title}

+

+ {question.body} +

+ {error &&
ERROR: {error}
} +
+ ) + } +} + +export default QuestionViewer; diff --git a/src/QuestionsList/index.js b/src/QuestionsList/index.js new file mode 100644 index 0000000..b7806b2 --- /dev/null +++ b/src/QuestionsList/index.js @@ -0,0 +1,41 @@ +/* global fetchWithAuth */ + +import Component from 'inferno-component'; +import { Link } from 'inferno-router'; + +class QuestionsList extends Component { + state = { + questions: [], + loading: true, + error: '', + } + async componentDidMount() { + var res = await fetchWithAuth('/questions'); + res = await res.json(); + if (!res.error) this.setState({ questions: res, loading: false }) + else this.setState({ error: res.error, loading: false }) + } + render() { + const { loading, questions, error } = this.state + return ( +
+ {!window.email ? + + : + + } +

Questions

+ {loading &&
Loading...
} + + {error &&
ERROR: {error}
} +
+ ) + } +} + +export default QuestionsList; diff --git a/src/fetchWithAuth.js b/src/fetchWithAuth.js new file mode 100644 index 0000000..7769daa --- /dev/null +++ b/src/fetchWithAuth.js @@ -0,0 +1,18 @@ +window.fetchWithAuth = (url, options = {}) => { + url = url.startsWith('/') ? url : '/' + url; + var body = options.body; + if (body && typeof body.getAll !== 'function') { // is not formdata + body = new FormData(); + for ( var key in options.body ) { + body.append(key, options.body[key]); + } + } + return fetch(url, { + ...options, + body, + headers: { + ...options.headers, + email: window.email + } + }) +} diff --git a/src/index.css b/src/index.css index bac0002..d29c531 100644 --- a/src/index.css +++ b/src/index.css @@ -1,5 +1,19 @@ -body { - margin: 0; - padding: 0; - font-family: "Open Sans", "lucida grande", "Segoe UI", arial, verdana, "lucida sans unicode", tahoma, sans-serif; +@import "../node_modules/milligram/dist/milligram.min.css"; + +.wrapper { + display:block; + overflow:hidden; + position:relative; + width:100% +} +.wrapper .container { + max-width:80rem +} +.wrapper>.container { + padding-bottom:7.5rem; + padding-top:7.5rem +} + +.error { + color: red; } diff --git a/src/index.js b/src/index.js index 1d556d4..8d6ccdb 100644 --- a/src/index.js +++ b/src/index.js @@ -2,4 +2,30 @@ import { render } from 'inferno'; import App from './App'; import './index.css'; -render(, document.getElementById('app')); +import { Router, Route, IndexRoute } from 'inferno-router'; +import createBrowserHistory from 'history/createBrowserHistory'; + +import './fetchWithAuth'; + +import Login from './Login'; +import Logout from './Logout'; +import QuestionsList from './QuestionsList'; +import QuestionViewer from './QuestionViewer'; + +const browserHistory = createBrowserHistory(); +window.browserHistory = browserHistory; + +window.email = window.localStorage.getItem('email') + +const routes = ( + + + + + + + + +); + +render(routes, document.getElementById('app')); diff --git a/src/logo.js b/src/logo.js deleted file mode 100644 index de95269..0000000 --- a/src/logo.js +++ /dev/null @@ -1,23 +0,0 @@ -export default ({ width, height }) => { - return ( - - - - - - - ); -}; diff --git a/yarn.lock b/yarn.lock index dc070dc..1770c23 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2874,6 +2874,16 @@ he@1.1.x: version "1.1.1" resolved "https://registry.yarnpkg.com/he/-/he-1.1.1.tgz#93410fd21b009735151f8868c2f271f3427e23fd" +history@^4.7.2: + version "4.7.2" + resolved "https://registry.yarnpkg.com/history/-/history-4.7.2.tgz#22b5c7f31633c5b8021c7f4a8a954ac139ee8d5b" + dependencies: + invariant "^2.2.1" + loose-envify "^1.2.0" + resolve-pathname "^2.2.0" + value-equal "^0.4.0" + warning "^3.0.0" + hmac-drbg@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1" @@ -3042,7 +3052,7 @@ indexof@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/indexof/-/indexof-0.0.1.tgz#82dc336d232b9062179d05ab3293a66059fd435d" -inferno-component@3.9.0, inferno-component@^3.7.0: +inferno-component@3.9.0, inferno-component@^3.7.0, inferno-component@^3.9.0: version "3.9.0" resolved "https://registry.yarnpkg.com/inferno-component/-/inferno-component-3.9.0.tgz#26a653bd9f055df49116facf54321ece990798f8" dependencies: @@ -3050,6 +3060,15 @@ inferno-component@3.9.0, inferno-component@^3.7.0: inferno-shared "3.9.0" inferno-vnode-flags "3.9.0" +inferno-create-element@3.9.0: + version "3.9.0" + resolved "https://registry.yarnpkg.com/inferno-create-element/-/inferno-create-element-3.9.0.tgz#7b7a15a2b3f9ae57e353b29640e01cc6e1abce7d" + dependencies: + inferno "3.9.0" + inferno-component "3.9.0" + inferno-shared "3.9.0" + inferno-vnode-flags "3.9.0" + inferno-dev-utils@^3.2.0: version "3.2.0" resolved "https://registry.yarnpkg.com/inferno-dev-utils/-/inferno-dev-utils-3.2.0.tgz#cdddaf555658ffda48fd27473e73c6ca088556a1" @@ -3084,6 +3103,19 @@ inferno-error-overlay@^2.2.0: settle-promise "1.0.0" source-map "0.5.6" +inferno-router@^3.9.0: + version "3.9.0" + resolved "https://registry.yarnpkg.com/inferno-router/-/inferno-router-3.9.0.tgz#15ae0263a8ab724ff939ab18e2f4fa8ccf47b3fb" + dependencies: + history "^4.7.2" + inferno "3.9.0" + inferno-component "3.9.0" + inferno-create-element "3.9.0" + inferno-shared "3.9.0" + inferno-vnode-flags "3.9.0" + path-to-regexp "^1.7.0" + path-to-regexp-es6 "0.0.2" + inferno-scripts@4.2.0: version "4.2.0" resolved "https://registry.yarnpkg.com/inferno-scripts/-/inferno-scripts-4.2.0.tgz#d9dba9c46712f900746f993def723bbeb99ab3a4" @@ -3146,7 +3178,7 @@ inferno-vnode-flags@3.9.0: version "3.9.0" resolved "https://registry.yarnpkg.com/inferno-vnode-flags/-/inferno-vnode-flags-3.9.0.tgz#8e358803b8c396788070d54786d86894cecd4a46" -inferno@3.9.0, inferno@^3.7.0: +inferno@3.9.0, inferno@^3.7.0, inferno@^3.9.0: version "3.9.0" resolved "https://registry.yarnpkg.com/inferno/-/inferno-3.9.0.tgz#4e9a312e9929abb741dfe285630841b0d7e95e62" dependencies: @@ -3220,7 +3252,7 @@ interpret@^1.0.0: version "1.0.4" resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.0.4.tgz#820cdd588b868ffb191a809506d6c9c8f212b1b0" -invariant@^2.2.2: +invariant@^2.2.1, invariant@^2.2.2: version "2.2.2" resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.2.tgz#9e1f56ac0acdb6bf303306f338be3b204ae60360" dependencies: @@ -4005,7 +4037,7 @@ longest@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/longest/-/longest-1.0.1.tgz#30a0b2da38f73770e8294a0d22e6625ed77d0097" -loose-envify@^1.0.0: +loose-envify@^1.0.0, loose-envify@^1.2.0: version "1.3.1" resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.3.1.tgz#d1a8ad33fa9ce0e713d65fdd0ac8b748d478c848" dependencies: @@ -4133,6 +4165,12 @@ miller-rabin@^4.0.0: bn.js "^4.0.0" brorand "^1.0.1" +milligram@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/milligram/-/milligram-1.3.0.tgz#a5d980ef8eaf79337c96a8d7c7e176764931042c" + dependencies: + normalize.css "~5.0.0" + "mime-db@>= 1.29.0 < 2", mime-db@~1.30.0: version "1.30.0" resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.30.0.tgz#74c643da2dd9d6a45399963465b26d5ca7d71f01" @@ -4339,6 +4377,10 @@ normalize-url@^1.4.0: query-string "^4.1.0" sort-keys "^1.0.0" +normalize.css@~5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/normalize.css/-/normalize.css-5.0.0.tgz#7cec875ce8178a5333c4de80b68ea9c18b9d7c37" + npm-run-path@^2.0.0: version "2.0.2" resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f" @@ -4595,11 +4637,21 @@ path-parse@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.5.tgz#3c1adf871ea9cd6c9431b6ea2bd74a0ff055c4c1" +path-to-regexp-es6@0.0.2: + version "0.0.2" + resolved "https://registry.yarnpkg.com/path-to-regexp-es6/-/path-to-regexp-es6-0.0.2.tgz#80cf615ce3220a29af9fe54f8862c730d9b56e0b" + dependencies: + path-to-regexp "*" + +path-to-regexp@*: + version "2.0.0" + resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-2.0.0.tgz#b77a8168c2e78bc31f3d312d71b1ace97df23870" + path-to-regexp@0.1.7: version "0.1.7" resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c" -path-to-regexp@^1.0.1: +path-to-regexp@^1.0.1, path-to-regexp@^1.7.0: version "1.7.0" resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-1.7.0.tgz#59fde0f435badacba103a84e9d3bc64e96b9937d" dependencies: @@ -5362,6 +5414,10 @@ resolve-from@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-1.0.1.tgz#26cbfe935d1aeeeabb29bc3fe5aeb01e93d44226" +resolve-pathname@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/resolve-pathname/-/resolve-pathname-2.2.0.tgz#7e9ae21ed815fd63ab189adeee64dc831eefa879" + resolve@1.1.7: version "1.1.7" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.1.7.tgz#203114d82ad2c5ed9e8e0411b3932875e889e97b" @@ -6179,6 +6235,10 @@ validate-npm-package-license@^3.0.1: spdx-correct "~1.0.0" spdx-expression-parse "~1.0.0" +value-equal@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/value-equal/-/value-equal-0.4.0.tgz#c5bdd2f54ee093c04839d71ce2e4758a6890abc7" + vary@~1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.1.tgz#67535ebb694c1d52257457984665323f587e8d37" @@ -6207,6 +6267,12 @@ walker@~1.0.5: dependencies: makeerror "1.0.x" +warning@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/warning/-/warning-3.0.0.tgz#32e5377cb572de4ab04753bdf8821c01ed605b7c" + dependencies: + loose-envify "^1.0.0" + watch@~0.10.0: version "0.10.0" resolved "https://registry.yarnpkg.com/watch/-/watch-0.10.0.tgz#77798b2da0f9910d595f1ace5b0c2258521f21dc"