From bed476517c256508e7b382f4480103229959f7cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dandelion=20Man=C3=A9?= Date: Mon, 6 May 2019 18:15:39 +0300 Subject: [PATCH] Port skeleton of Odyssey frontend (#1132) This commit integrates an bare skeleton of the odyssey frontend that we implemented in the [odyssey-hackathon] repository. You can see the working frontend that we are trying to port over at [sourcecred.io/odyssey-hackathon/][scio]. The prototype in the other repository has some tooling choices which are incompatible/redundant with decisions in our codebase (sass vs aphrodite), and requires some tools not yet present here (svg-react-loader). This commit includes the build and integration work needed to port the prototype frontend into mainline SourceCred. The frontend scaffold isn't yet integrated with any "real" Odyssey data. One potential issue: right now, every page that is rendered from the SourceCred homepage is contained within a [homepage/Page], meaning that it has full SourceCred website styling, along with the SourceCred website header. The [application][scio] also has a header. Currently, I work around this by having the Odyssey UI cover up the base header (via absolute positioning), which works but is hacky. We can consider more principled solutions: - Finding a way to specify routes which aren't contained by [homepage/Page]; maybe by adding a new top-level route [here][route-alternative]. - Unify the headers for the Odyssey viewer and the page as a whole (sounds like inappropriate entanglement?) - Have a website header and also an application header (sounds ugly?) [homepage/Page]: https://github.com/sourcecred/sourcecred/blob/ee1d2fb996718fe41325711271542a54c197a1ed/src/homepage/Page.js [route-alternative]: https://github.com/sourcecred/sourcecred/blob/ee1d2fb996718fe41325711271542a54c197a1ed/src/homepage/createRoutes.js#L17 Test plan: Run `yarn start`, and then navigate to `localhost:8080/odyssey/`. observe that a working website is displayed, and that the cred logo next to the word "SourceCred" is loaded properly (i.e. svg-react-loader is integrated properly). Observe that there are no build/compile errors from either `yarn start` or `yarn build`. Also, observe that the UI looks passably nice, and that if the number of elements in the entity lists is larger than can be displayed, the sidebar pane scrolls independently. The UI was tested in both Chrome and Firefox. [odyssey-hackathon]: https://github.com/sourcecred/odyssey-hackathon [scio]: https://sourcecred.io/odyssey-hackathon/ Thanks to @jmnemo, as the implementation is based on [his work]. [his work]: https://github.com/jmnemo/hackathon-event/ --- config/webpack.config.web.js | 5 + package.json | 1 + src/homepage/OdysseyPage.js | 12 +++ src/homepage/routeData.js | 9 ++ src/plugins/odyssey/ui/App.js | 153 ++++++++++++++++++++++++++++ src/plugins/odyssey/ui/Header.js | 66 ++++++++++++ src/plugins/odyssey/ui/img/logo.svg | 8 ++ yarn.lock | 68 +++++++++++-- 8 files changed, 314 insertions(+), 8 deletions(-) create mode 100644 src/homepage/OdysseyPage.js create mode 100644 src/plugins/odyssey/ui/App.js create mode 100644 src/plugins/odyssey/ui/Header.js create mode 100755 src/plugins/odyssey/ui/img/logo.svg diff --git a/config/webpack.config.web.js b/config/webpack.config.web.js index 974abda..9b57f1c 100644 --- a/config/webpack.config.web.js +++ b/config/webpack.config.web.js @@ -184,6 +184,11 @@ function makeConfig(mode /*: "production" | "development" */) /*: mixed */ { test: /\.css$/, loader: "css-loader", // TODO(@wchargin): add csso-loader }, + { + test: /\.svg$/, + exclude: /node_modules/, + loader: "svg-react-loader", + }, // "file" loader makes sure assets end up in the `build` folder. // When you `import` an asset, you get its filename. // This loader doesn't use a "test" so it will catch all modules diff --git a/package.json b/package.json index 1c7e443..ad9eb09 100644 --- a/package.json +++ b/package.json @@ -23,6 +23,7 @@ "react-dom": "^16.4.1", "react-router": "3.2.1", "retry": "^0.12.0", + "svg-react-loader": "^0.4.6", "tmp": "^0.0.33", "whatwg-fetch": "2.0.3" }, diff --git a/src/homepage/OdysseyPage.js b/src/homepage/OdysseyPage.js new file mode 100644 index 0000000..de468b9 --- /dev/null +++ b/src/homepage/OdysseyPage.js @@ -0,0 +1,12 @@ +// @flow + +import React from "react"; + +import OdysseyApp from "../plugins/odyssey/ui/App"; +import type {Assets} from "../webutil/assets"; + +export default class HomePage extends React.Component<{|+assets: Assets|}> { + render() { + return ; + } +} diff --git a/src/homepage/routeData.js b/src/homepage/routeData.js index 6342436..852dfea 100644 --- a/src/homepage/routeData.js +++ b/src/homepage/routeData.js @@ -56,6 +56,15 @@ function makeRouteData(registry /*: RepoIdRegistry */) /*: RouteData */ { title: `${entry.repoId.owner}/${entry.repoId.name} • SourceCred`, navTitle: null, })), + { + path: "/odyssey/", + contents: { + type: "PAGE", + component: () => require("./OdysseyPage").default, + }, + title: "Odyssey Prototype", + navTitle: null, + }, { path: "/discord-invite/", contents: { diff --git a/src/plugins/odyssey/ui/App.js b/src/plugins/odyssey/ui/App.js new file mode 100644 index 0000000..4ef9415 --- /dev/null +++ b/src/plugins/odyssey/ui/App.js @@ -0,0 +1,153 @@ +// @flow +import React, {Component} from "react"; +import {StyleSheet, css} from "aphrodite/no-important"; + +import {Header} from "./Header"; + +type AppProps = {||}; +type AppState = {||}; + +type Entity = {| + +name: string, + +score: number, +|}; + +const exampleValues: $ReadOnlyArray = [ + {name: "Implementation", score: 1002}, + {name: "Research", score: 1001}, + {name: "Ethics", score: 1000}, + {name: "Learning", score: 999}, + {name: "Something With A Long Name, Really Quite Long", score: 999}, + {name: "@1", score: 998}, + {name: "@2", score: 998}, + {name: "@3", score: 998}, + {name: "@4", score: 998}, + {name: "@5", score: 998}, + {name: "@6", score: 998}, +]; + +const examplePeople: $ReadOnlyArray = [ + {name: "@decentralion", score: 1002}, + {name: "@wchargin", score: 1001}, + {name: "@mzargham", score: 1000}, + {name: "@brianlitwin", score: 999}, + {name: "@anthrocypher", score: 998}, + {name: "@brutalfluffy", score: 998}, + {name: "@1", score: 998}, + {name: "@2", score: 998}, + {name: "@3", score: 998}, + {name: "@4", score: 998}, + {name: "@5", score: 998}, + {name: "@6", score: 998}, + {name: "@7", score: 998}, + {name: "@8", score: 998}, + {name: "@9", score: 998}, +]; + +class App extends Component { + scoreList(title: string, entities: $ReadOnlyArray) { + const entries = entities.map(({name, score}) => ( +
+
{name}
+
{score.toFixed(0)} ¤
+
+ )); + return ( +
+

{title}

+ {entries} +
+ ); + } + + render() { + return ( +
+
+ +
+
+ {this.scoreList("Our Values", exampleValues)} + {this.scoreList("Our People", examplePeople)} +
+ +
Chart to go here.
+
+
+ ); + } +} + +const styles = StyleSheet.create({ + app: { + // HACK: Position absolute / top:0 to cover up the header from the + // default SourceCred UI. There's some discussion in the pull request: + // https://github.com/sourcecred/sourcecred/pull/1132 + top: "0px", + position: "absolute", + display: "flex", + flexDirection: "column", + height: "100%", + width: "100%", + }, + + scoreList: { + padding: "20px 20px 50px 20px", + }, + + scoreListTitle: { + fontSize: "28px", + lineHeight: "36px", + color: "#fff", + fontFamily: "'DINCondensed', sans-serif", + fontWeight: "700", + letterSpacing: "0.04em", + margin: "0 0 20px 0", + }, + + entityRow: { + display: "flex", + justifyContent: "space-between", + alignItems: "center", + fontSize: "16px", + lineHeight: "19px", + marginTop: "20px", + cursor: "pointer", + }, + + entityName: { + fontWeight: "700", + color: "#E9EDEC", + letterSpacing: "-0.2px", + }, + + entityScore: { + color: "#EDAD47", + fontWeight: "600", + flexShrink: 0, + paddingLeft: "5px", + }, + + scoreListsContainer: { + display: "flex", + flexDirection: "column", + backgroundColor: "#242424", + "overflow-y": "scroll", + minWidth: "400px", + }, + + nonHeader: { + display: "flex", + flexDirection: "row", + paddingTop: "80px", + overflow: "hidden", + }, + + chartContainer: { + width: "100%", + padding: "42px", + display: "flex", + }, +}); + +export default App; diff --git a/src/plugins/odyssey/ui/Header.js b/src/plugins/odyssey/ui/Header.js new file mode 100644 index 0000000..d0ad408 --- /dev/null +++ b/src/plugins/odyssey/ui/Header.js @@ -0,0 +1,66 @@ +// @flow +import React, {Component} from "react"; +import {StyleSheet, css} from "aphrodite/no-important"; + +import LogoIcon from "./img/logo.svg"; + +export type Props = {||}; +export class Header extends Component { + render() { + return ( +
+
+
Project Name Here
+
+ SourceCred + +
+
+
+ ); + } +} + +const styles = StyleSheet.create({ + header: { + position: "fixed", + display: "flex", + justifyContent: "space-between", + alignItems: "center", + top: "0", + left: "0", + height: "80px", + width: "100%", + backgroundColor: "#1D1D1C", + padding: "0 50px", + zIndex: "776", + }, + + titleBlock: { + minWidth: "380px", + color: "#E9EDEC", + fontSize: "32px", + lineHeight: "30px", + fontFamily: "'DINCondensed', sans-serif", + fontWeight: "700", + }, + + logo: { + display: "flex", + alignItems: "center", + fontSize: "20px", + lineHeight: "20px", + color: "#8E8F91", + letterSpacing: "-0.25px", + + span: { + height: "16px", + }, + + svg: { + width: "20px", + height: "20px", + marginLeft: "7px", + }, + }, +}); diff --git a/src/plugins/odyssey/ui/img/logo.svg b/src/plugins/odyssey/ui/img/logo.svg new file mode 100755 index 0000000..134fda3 --- /dev/null +++ b/src/plugins/odyssey/ui/img/logo.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/yarn.lock b/yarn.lock index a49a336..7b77811 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2150,6 +2150,16 @@ css-what@2.1: resolved "https://registry.yarnpkg.com/css-what/-/css-what-2.1.0.tgz#9467d032c38cfaefb9f2d79501253062f87fa1bd" integrity sha1-lGfQMsOM+u+58teVASUwYvh/ob0= +css@2.2.4: + version "2.2.4" + resolved "https://registry.yarnpkg.com/css/-/css-2.2.4.tgz#c646755c73971f2bba6a601e2cf2fd71b1298929" + integrity sha512-oUnjmWpy0niI3x/mPL8dVEI1l7MnG3+HHyRPHf+YFSbK+svOhXpmSOcDURUh2aOCgl2grzrOPt1nHLuCVFULLw== + dependencies: + inherits "^2.0.3" + source-map "^0.6.1" + source-map-resolve "^0.5.2" + urix "^0.1.0" + cssesc@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-0.1.0.tgz#c814903e45623371a0477b40109aaafbeeaddbb4" @@ -5254,7 +5264,7 @@ loader-runner@^2.3.0: resolved "https://registry.yarnpkg.com/loader-runner/-/loader-runner-2.3.0.tgz#f482aea82d543e07921700d5a46ef26fdac6b8a2" integrity sha1-9IKuqC1UPgeSFwDVpG7yb9rGuKI= -loader-utils@^1.0.2, loader-utils@^1.1.0: +loader-utils@1.1.0, loader-utils@^1.0.2, loader-utils@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-1.1.0.tgz#c98aef488bcceda2ffb5e2de646d6a754429f5cd" integrity sha1-yYrvSIvM7aL/teLeZG1qdUQp9c0= @@ -5376,16 +5386,16 @@ lodash.uniq@^4.5.0: resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.5.tgz#99a92d65c0272debe8c96b6057bc8fbfa3bed511" integrity sha512-svL3uiZf1RwhH+cWrfZn3A4+U58wbP0tGVTLQPbjplZxZ8ROD9VLuNgsRniTlLe7OlSqR79RUehXgpBW/s0IQw== +lodash@^4.0.0, lodash@^4.17.10: + version "4.17.11" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.11.tgz#b39ea6229ef607ecd89e2c8df12536891cac9b8d" + integrity sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg== + lodash@^4.13.1: version "4.17.10" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.10.tgz#1b7793cf7259ea38fb3661d4d38b3260af8ae4e7" integrity sha512-UejweD1pDoXu+AD825lWwp4ZGtSwgnpZxb3JDViD7StjQz+Nb/6l093lx4OQ0foGWNRoc19mWy7BzL+UAK2iVg== -lodash@^4.17.10: - version "4.17.11" - resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.11.tgz#b39ea6229ef607ecd89e2c8df12536891cac9b8d" - integrity sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg== - loglevel@^1.4.1: version "1.6.1" resolved "https://registry.yarnpkg.com/loglevel/-/loglevel-1.6.1.tgz#e0fc95133b6ef276cdc8887cdaf24aa6f156f8fa" @@ -6955,6 +6965,11 @@ railroad-diagrams@^1.0.0: resolved "https://registry.yarnpkg.com/railroad-diagrams/-/railroad-diagrams-1.0.0.tgz#eb7e6267548ddedfb899c1b90e57374559cddb7e" integrity sha1-635iZ1SN3t+4mcG5Dlc3RVnN234= +ramda@0.21.0: + version "0.21.0" + resolved "https://registry.yarnpkg.com/ramda/-/ramda-0.21.0.tgz#a001abedb3ff61077d4ff1d577d44de77e8d0a35" + integrity sha1-oAGr7bP/YQd9T/HVd9RN536NCjU= + randexp@0.4.6: version "0.4.6" resolved "https://registry.yarnpkg.com/randexp/-/randexp-0.4.6.tgz#e986ad5e5e31dae13ddd6f7b3019aa7c87f60ca3" @@ -7515,6 +7530,11 @@ rx-lite@*, rx-lite@^4.0.8: resolved "https://registry.yarnpkg.com/rx-lite/-/rx-lite-4.0.8.tgz#0b1e11af8bc44836f04a6407e92da42467b79444" integrity sha1-Cx4Rr4vESDbwSmQH6S2kJGe3lEQ= +rx@4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/rx/-/rx-4.1.0.tgz#a5f13ff79ef3b740fe30aa803fb09f98805d4782" + integrity sha1-pfE/957zt0D+MKqAP7CfmIBdR4I= + safe-buffer@5.1.1, safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@~5.1.0, safe-buffer@~5.1.1: version "5.1.1" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.1.tgz#893312af69b2123def71f57889001671eeb2c853" @@ -7553,7 +7573,7 @@ sane@^2.0.0: optionalDependencies: fsevents "^1.2.3" -sax@^1.2.4, sax@~1.2.1: +sax@>=0.6.0, sax@^1.2.4, sax@~1.2.1: version "1.2.4" resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw== @@ -7834,7 +7854,7 @@ source-list-map@^2.0.0: resolved "https://registry.yarnpkg.com/source-list-map/-/source-list-map-2.0.0.tgz#aaa47403f7b245a92fbc97ea08f250d6087ed085" integrity sha512-I2UmuJSRr/T8jisiROLU3A3ltr+swpniSmNPI4Ml3ZCX6tVnDsuZzK7F2hl5jTqbZBWCEKlj5HRQiPExXLgE8A== -source-map-resolve@^0.5.0: +source-map-resolve@^0.5.0, source-map-resolve@^0.5.2: version "0.5.2" resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.5.2.tgz#72e2cc34095543e43b2c62b2c4c10d4a9054f259" integrity sha512-MjqsvNwyz1s0k81Goz/9vRBe9SZdB09Bdw+/zYyO+3CuPk6fouTaxscHkgtE8jKvf01kVfl8riHzERQ/kefaSA== @@ -8157,6 +8177,18 @@ supports-color@^5.1.0: dependencies: has-flag "^2.0.0" +svg-react-loader@^0.4.6: + version "0.4.6" + resolved "https://registry.yarnpkg.com/svg-react-loader/-/svg-react-loader-0.4.6.tgz#b263efb3e3d2fff4c682a729351aba5f185051a1" + integrity sha512-HVEypjWQsQuJdBIPzXGxpmQsQts7QwfQuYgK1rah6BVCMoLNSCh/ESKVNd7/tHq8DkWYHHTyaUMDA1FjqZYrgA== + dependencies: + css "2.2.4" + loader-utils "1.1.0" + ramda "0.21.0" + rx "4.1.0" + traverse "0.6.6" + xml2js "0.4.17" + svgo@^0.7.0: version "0.7.2" resolved "https://registry.yarnpkg.com/svgo/-/svgo-0.7.2.tgz#9f5772413952135c6fefbf40afe6a4faa88b4bb5" @@ -8359,6 +8391,11 @@ tr46@^1.0.1: dependencies: punycode "^2.1.0" +traverse@0.6.6: + version "0.6.6" + resolved "https://registry.yarnpkg.com/traverse/-/traverse-0.6.6.tgz#cbdf560fd7b9af632502fed40f918c157ea97137" + integrity sha1-y99WD9e5r2MlAv7UD5GMFX6pcTc= + trim-newlines@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/trim-newlines/-/trim-newlines-1.0.0.tgz#5887966bb582a4503a41eb524f7d35011815a613" @@ -8909,6 +8946,21 @@ xml-name-validator@^3.0.0: resolved "https://registry.yarnpkg.com/xml-name-validator/-/xml-name-validator-3.0.0.tgz#6ae73e06de4d8c6e47f9fb181f78d648ad457c6a" integrity sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw== +xml2js@0.4.17: + version "0.4.17" + resolved "https://registry.yarnpkg.com/xml2js/-/xml2js-0.4.17.tgz#17be93eaae3f3b779359c795b419705a8817e868" + integrity sha1-F76T6q4/O3eTWceVtBlwWogX6Gg= + dependencies: + sax ">=0.6.0" + xmlbuilder "^4.1.0" + +xmlbuilder@^4.1.0: + version "4.2.1" + resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-4.2.1.tgz#aa58a3041a066f90eaa16c2f5389ff19f3f461a5" + integrity sha1-qlijBBoGb5DqoWwvU4n/GfP0YaU= + dependencies: + lodash "^4.0.0" + xtend@^4.0.0, xtend@~4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af"