Radially simplify homepage2 (#1854)

This drastically streamlines the new frontend entry directory.
All the logos, the nav bar, the pages, etc, are all gone.
Now there's just a landing page that reads "Under Construction".

Test plan: Run `yarn start2`, observe that there's just an empty landing
page that we'll rebuild from.
This commit is contained in:
Dandelion Mané 2020-06-17 18:45:16 -07:00 committed by GitHub
parent f25bc795c6
commit 4b0fcb96be
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 2 additions and 552 deletions

View File

@ -1,22 +0,0 @@
// @flow
import React from "react";
type Props = {|
+className: string,
+altText: string,
|};
export default function DiscordLogo(props: Props) {
return (
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 245 240"
aria-label={props.altText}
role="img"
className={props.className}
>
<path d="M104.4 103.9c-5.7 0-10.2 5-10.2 11.1s4.6 11.1 10.2 11.1c5.7 0 10.2-5 10.2-11.1.1-6.1-4.5-11.1-10.2-11.1zM140.9 103.9c-5.7 0-10.2 5-10.2 11.1s4.6 11.1 10.2 11.1c5.7 0 10.2-5 10.2-11.1s-4.5-11.1-10.2-11.1z" />
<path d="M189.5 20h-134C44.2 20 35 29.2 35 40.6v135.2c0 11.4 9.2 20.6 20.5 20.6h113.4l-5.3-18.5 12.8 11.9 12.1 11.2 21.5 19V40.6c0-11.4-9.2-20.6-20.5-20.6zm-38.6 130.6s-3.6-4.3-6.6-8.1c13.1-3.7 18.1-11.9 18.1-11.9-4.1 2.7-8 4.6-11.5 5.9-5 2.1-9.8 3.5-14.5 4.3-9.6 1.8-18.4 1.3-25.9-.1-5.7-1.1-10.6-2.7-14.7-4.3-2.3-.9-4.8-2-7.3-3.4-.3-.2-.6-.3-.9-.5-.2-.1-.3-.2-.4-.3-1.8-1-2.8-1.7-2.8-1.7s4.8 8 17.5 11.8c-3 3.8-6.7 8.3-6.7 8.3-22.1-.7-30.5-15.2-30.5-15.2 0-32.2 14.4-58.3 14.4-58.3 14.4-10.8 28.1-10.5 28.1-10.5l1 1.2c-18 5.2-26.3 13.1-26.3 13.1s2.2-1.2 5.9-2.9c10.7-4.7 19.2-6 22.7-6.3.6-.1 1.1-.2 1.7-.2 6.1-.8 13-1 20.2-.2 9.5 1.1 19.7 3.9 30.1 9.6 0 0-7.9-7.5-24.9-12.7l1.4-1.6s13.7-.3 28.1 10.5c0 0 14.4 26.1 14.4 58.3 0 0-8.5 14.5-30.6 15.2z" />
</svg>
);
}

View File

@ -1,22 +0,0 @@
// @flow
import React from "react";
type Props = {|
+className: string,
+altText: string,
|};
export default function GithubLogo(props: Props) {
return (
<svg
aria-label={props.altText}
role="img"
className={props.className}
viewBox="0 0 1024 1024"
xmlns="http://www.w3.org/2000/svg"
>
<title>{props.altText}</title>
<path d="M512 0C229.25 0 0 229.25 0 512c0 226.25 146.688 418.125 350.156 485.812 25.594 4.688 34.938-11.125 34.938-24.625 0-12.188-0.469-52.562-0.719-95.312C242 908.812 211.906 817.5 211.906 817.5c-23.312-59.125-56.844-74.875-56.844-74.875-46.531-31.75 3.53-31.125 3.53-31.125 51.406 3.562 78.47 52.75 78.47 52.75 45.688 78.25 119.875 55.625 149 42.5 4.654-33 17.904-55.625 32.5-68.375C304.906 725.438 185.344 681.5 185.344 485.312c0-55.938 19.969-101.562 52.656-137.406-5.219-13-22.844-65.094 5.062-135.562 0 0 42.938-13.75 140.812 52.5 40.812-11.406 84.594-17.031 128.125-17.219 43.5 0.188 87.312 5.875 128.188 17.281 97.688-66.312 140.688-52.5 140.688-52.5 28 70.531 10.375 122.562 5.125 135.5 32.812 35.844 52.625 81.469 52.625 137.406 0 196.688-119.75 240-233.812 252.688 18.438 15.875 34.75 47 34.75 94.75 0 68.438-0.688 123.625-0.688 140.5 0 13.625 9.312 29.562 35.25 24.562C877.438 930 1024 738.125 1024 512 1024 229.25 794.75 0 512 0z" />
</svg>
);
}

View File

@ -3,198 +3,18 @@
import React from "react";
import type {Assets} from "../webutil/assets";
import Link from "../webutil/Link";
import {StyleSheet, css} from "aphrodite/no-important";
export default class HomePage extends React.Component<{|+assets: Assets|}> {
render() {
const urls = {
numpyFunding:
"https://numfocus.org/blog/numpy-receives-first-ever-funding-thanks-to-moore-foundation",
opensslFunding:
"https://arstechnica.com/information-technology/2014/04/tech-giants-chastened-by-heartbleed-finally-agree-to-fund-openssl/",
graph: "https://en.wikipedia.org/wiki/Graph_(discrete_mathematics)",
pagerank: "https://en.wikipedia.org/wiki/PageRank",
ast: "https://en.wikipedia.org/wiki/Abstract_syntax_tree",
protocolLabs: "https://protocol.ai/",
discord: "https://discord.gg/tsBTgc9",
github: "https://github.com/sourcecred/sourcecred",
contributionsWelcome:
"https://github.com/sourcecred/sourcecred/issues?q=is%3Aissue+is%3Aopen+label%3A%22contributions+welcome%22",
readme: "https://github.com/sourcecred/sourcecred/blob/master/README.md",
};
return (
<div className={css(styles.container)}>
<h1>SourceCred vision</h1>
<p>
<strong>The open-source movement is amazing. </strong>
Its inspiring that some of our best technology is developed in the
open and available to everyone.
</p>
<p>
Despite all the value provided by open-source projects, many are
chronically underfunded. For example, NumPy{" "}
<Link href={urls.numpyFunding}>
received no funding at all until 2017
</Link>
, and{" "}
<Link href={urls.opensslFunding}>
a world where OpenSSL was funded might have been a world without
Heartbleed
</Link>
.
</p>
<p>
These projects also impose a heavy burden on maintainers. Popular
projects have hundreds or thousands of open issues, with many new ones
being created every day, and only a few overworked volunteers trying
to triage and respond to them. Burnout is inevitable.
</p>
<p>SourceCred is our attempt to help.</p>
<h2>Mission</h2>
<p>
SourceCred aims to empower open-source developers and communities by
creating a project-specific reputation metric called <em>cred</em>.
</p>
<p>
A projects contributors earn cred for helping out. For example, a
project might reward:
</p>
<ul style={{marginTop: "-1.5ex"}}>
<li>Triaging issues</li>
<li>Maintaining the build</li>
<li>Fixing bugs</li>
<li>Writing documentation</li>
<li>Refactoring code</li>
<li>Adding features</li>
</ul>
<p>
SourceCred will build social capital within communities, recognize
their hardworking contributors, and encourage more people to help
maintain and develop open-source projects.
</p>
<p>Were designing SourceCred around the following four principles:</p>
<dl>
<Dt>Transparency</Dt>
<Dd>
It should be easy to see why cred is attributed as it is, and link a
persons cred directly to contributions theyve made.
</Dd>
<Dt>Extensibility</Dt>
<Dd>
SourceCred is designed around a plugin architecture, so you can add
support for new data sources, new algorithms, or even entirely new
kinds of work.
</Dd>
<Dt>Community control</Dt>
<Dd>
Each community has the final say on that communitys cred. When the
algorithm and the community disagree, the community wins.
</Dd>
<Dt>Decentralization</Dt>
<Dd>
Projects own their own data, and control their own cred. The
SourceCred project provides tools, but has no control.
</Dd>
</dl>
<h2>How cred works</h2>
<p>
Cred is computed by first creating a contribution{" "}
<Link href={urls.graph}>graph</Link>, which contains every
contribution to the project and the relations among them. For example,
GitHub issues, Git commits, and individual files and functions can be
included in the graph. Then, SourceCred runs a modified version of{" "}
<Link href={urls.pagerank}>PageRank</Link> on that graph to produce a
cred attribution. The attribution is highly configurable; project
maintainers can add new heuristics and adjust weights.
</p>
<p>
This approach satisfies our four principles. Its transparent: you can
always see how a nodes weight dervies from its neighbors. Its
extensible: plugins can embed new types of nodes and edges into the
graph. Its community-controlled: the weights, heuristics, and
algorithms are all configured by the project. Finally, its
decentralized: every project can run its own instance.
</p>
<p>
Naturally, there will be attempts to game the system. Well provide
tools that make it obvious when people are gaming their cred, and
empower maintainers to moderate and correct the attribution when
needed. In case of deeply contentious disagreements, cred can be
forked alongside the project.
</p>
<h2>Roadmap</h2>
<p>
SourceCred is under active development.{" "}
<Link to="/prototype/">We have a prototype</Link> that ingests data
from Git and GitHub, computes cred, and allows the user to explore and
experiment on the results. We have a long way to go to realize
SourceCreds full vision, but the prototype can already surface some
interesting insights!
</p>
<p>
In the near term, we want to help with issue triage and
prioritization. Open-source projects are drowning in issues; many
people file them, but few are motivated to triage them. We want to
recognize the people who show up to do that work, and reward them by
giving them more influence over issue prioritization.
</p>
<p>
In the longer term, we will continue to add signal to cred
attribution. For example, we plan to parse the{" "}
<Link href={urls.ast}>AST</Link> of a projects code so that we can
attribute cred at the level of individual functions, and create a
spotlight mechanic that will let contributors flow more cred to
their peers important contributions. As SourceCred improves, we have
plans for how to use it to help open-source projects become
financially sustainable.
</p>
<h2>About</h2>
<p>
SourceCred is an open-source project, and is committed to being
decentralized. We dont think communities should have to give their
data to us, or entrust us with control over their cred. The lead
developers are grateful to be supported by{" "}
<Link href={urls.protocolLabs}>Protocol Labs</Link>.
</p>
<p>
If you think this vision is exciting, wed love for you to get
involved! You can join our <Link href={urls.discord}>Discord</Link>{" "}
and check out our <Link href={urls.github}>GitHub</Link>many of our
issues are marked{" "}
<Link href={urls.contributionsWelcome}>contributions welcome</Link>.
If you want to try running SourceCred on open-source projects you care
about, check out <Link href={urls.readme}>our README</Link>.
</p>
<h1>Under Construction</h1>
</div>
);
}
}
function Dt(props) {
return <dt style={{fontWeight: "bold"}}>{props.children}</dt>;
}
function Dd(props) {
return <dd style={{marginBottom: 15}}>{props.children}</dd>;
}
const styles = StyleSheet.create({
container: {
maxWidth: 900,

View File

@ -4,13 +4,7 @@ import React, {type Node} from "react";
import {StyleSheet, css} from "aphrodite/no-important";
import type {Assets} from "../webutil/assets";
import Colors from "../webutil/Colors";
import Link from "../webutil/Link";
import GithubLogo from "./GithubLogo";
import TwitterLogo from "./TwitterLogo";
import DiscordLogo from "./DiscordLogo";
import type {RouteData} from "./routeData";
import * as NullUtil from "../util/null";
import {VERSION_SHORT, VERSION_FULL} from "../core/version";
export default class Page extends React.Component<{|
@ -22,62 +16,6 @@ export default class Page extends React.Component<{|
return (
<React.Fragment>
<div className={css(style.nonFooter)}>
<header>
<nav className={css(style.nav)}>
<ul className={css(style.navList)}>
<li className={css(style.navItem, style.navItemLeft)}>
<Link to="/" styles={[style.navLink, style.navLinkTitle]}>
SourceCred
</Link>
</li>
{this.props.routeData.map(({navTitle, path}) =>
NullUtil.map(navTitle, (navTitle) => (
<li
key={path}
className={css(style.navItem, style.navItemRight)}
>
<Link to={path} styles={[style.navLink]}>
{navTitle}
</Link>
</li>
))
)}
<li className={css(style.navItem, style.navItemRight)}>
<Link
styles={[style.navLink]}
href="https://github.com/sourcecred/sourcecred"
>
<GithubLogo
altText="SourceCred Github"
className={css(style.navLogoSmall)}
/>
</Link>
</li>
<li className={css(style.navItem, style.navItemRight)}>
<Link
styles={[style.navLink]}
href="https://twitter.com/sourcecred"
>
<TwitterLogo
altText="SourceCred Twitter"
className={css(style.navLogoSmall)}
/>
</Link>
</li>
<li className={css(style.navItem, style.navItemRightSmall)}>
<Link
styles={[style.navLink]}
href="https://discordapp.com/invite/tsBTgc9"
>
<DiscordLogo
altText="Join the SourceCred Discord"
className={css(style.navLogoMedium)}
/>
</Link>
</li>
</ul>
</nav>
</header>
<main>{this.props.children}</main>
</div>
<footer className={css(style.footer)}>
@ -112,51 +50,4 @@ const style = StyleSheet.create({
nonFooter: {
minHeight: `calc(100vh - ${footerHeight}px)`,
},
nav: {
padding: "20px 50px 0 50px",
maxWidth: 900,
margin: "0 auto",
},
navLinkTitle: {
fontSize: 24,
},
navItem: {
display: "inline-block",
},
navList: {
listStyle: "none",
paddingLeft: 0,
margin: 0,
display: "flex",
},
navLink: {
fontFamily: "Roboto Condensed",
fontSize: 18,
textDecoration: "none",
":hover": {
textDecoration: "underline",
},
":visited:not(:active)": {
color: Colors.brand.medium,
fill: Colors.brand.medium, // for SVG icons
},
},
navItemLeft: {
flex: 1,
},
navItemRight: {
marginLeft: 20,
},
navItemRightSmall: {
marginLeft: 15,
},
navLogoSmall: {
height: 20,
width: 20,
},
navLogoMedium: {
height: 25,
width: 25,
transform: "translateY(-1px)",
},
});

View File

@ -1,18 +0,0 @@
// @flow
import React, {type ComponentType} from "react";
import type {Assets} from "../webutil/assets";
import HomepageExplorer from "./homepageExplorer";
export default function makeProjectPage(
projectId: string
): ComponentType<{|+assets: Assets|}> {
return class ProjectPage extends React.Component<{|+assets: Assets|}> {
render() {
return (
<HomepageExplorer assets={this.props.assets} projectId={projectId} />
);
}
};
}

View File

@ -1,35 +0,0 @@
// @flow
import React, {type ComponentType} from "react";
import Link from "../webutil/Link";
import type {Assets} from "../webutil/assets";
export default function makePrototypesPage(
projectIds: $ReadOnlyArray<string>
): ComponentType<{|+assets: Assets|}> {
return class PrototypesPage extends React.Component<{|+assets: Assets|}> {
render() {
return (
<div
style={{
maxWidth: 900,
margin: "0 auto",
padding: "0 10px",
lineHeight: 1.5,
height: "100%",
}}
>
<p>Select a project:</p>
<ul>
{projectIds.map((projectId) => (
<li key={projectId}>
<Link to={`/timeline/${projectId}/`}>{`${projectId}`}</Link>
</li>
))}
</ul>
</div>
);
}
};
}

View File

@ -1,18 +0,0 @@
// @flow
import React, {type ComponentType} from "react";
import type {Assets} from "../webutil/assets";
import HomepageTimeline from "./homepageTimeline";
export default function makeTimelinePage(
projectId: string
): ComponentType<{|+assets: Assets|}> {
return class TimelinePage extends React.Component<{|+assets: Assets|}> {
render() {
return (
<HomepageTimeline assets={this.props.assets} projectId={projectId} />
);
}
};
}

View File

@ -1,34 +0,0 @@
// @flow
import React from "react";
type Props = {|
+className: string,
+altText: string,
|};
export default function TwitterLogo(props: Props) {
return (
<svg
aria-label={props.altText}
role="img"
className={props.className}
version="1.1"
xmlns="http://www.w3.org/2000/svg"
x="0px"
y="0px"
viewBox="0 0 512 512"
>
<title>{props.altText}</title>
<path
d="M512,97.209c-18.838,8.354-39.082,14.001-60.329,16.54c21.687-13,38.343-33.585,46.187-58.114
c-20.299,12.038-42.778,20.779-66.705,25.489c-19.16-20.415-46.461-33.17-76.674-33.17c-58.012,0-105.043,47.029-105.043,105.039
c0,8.233,0.929,16.25,2.72,23.939c-87.3-4.382-164.701-46.2-216.509-109.753c-9.042,15.514-14.224,33.558-14.224,52.809
c0,36.444,18.544,68.596,46.73,87.433c-17.219-0.546-33.416-5.271-47.577-13.139c-0.01,0.438-0.01,0.878-0.01,1.321
c0,50.894,36.209,93.348,84.261,103c-8.813,2.398-18.094,3.686-27.674,3.686c-6.77,0-13.349-0.66-19.764-1.887
c13.367,41.73,52.159,72.104,98.126,72.949c-35.95,28.175-81.243,44.967-130.458,44.967c-8.479,0-16.841-0.497-25.059-1.471
c46.486,29.806,101.701,47.197,161.021,47.197c193.211,0,298.868-160.063,298.868-298.873c0-4.554-0.104-9.084-0.305-13.59
C480.11,136.773,497.918,118.273,512,97.209z"
/>
</svg>
);
}

View File

@ -1,17 +0,0 @@
// @flow
import React from "react";
import type {Assets} from "../webutil/assets";
import {AppPage} from "../explorer/legacy/App";
export default class HomepageExplorer extends React.Component<{|
+assets: Assets,
+projectId: string,
|}> {
render() {
return (
<AppPage assets={this.props.assets} projectId={this.props.projectId} />
);
}
}

View File

@ -1,21 +0,0 @@
// @flow
import React from "react";
import type {Assets} from "../webutil/assets";
import {TimelineApp, defaultLoader} from "../explorer/TimelineApp";
export default class TimelineExplorer extends React.Component<{|
+assets: Assets,
+projectId: string,
|}> {
render() {
return (
<TimelineApp
assets={this.props.assets}
projectId={this.props.projectId}
loader={defaultLoader}
/>
);
}
}

View File

@ -26,37 +26,8 @@ type RouteDatum = {|
export type RouteData = $ReadOnlyArray<RouteDatum>;
*/
/**
* Adds an 'Inspection Test', which is a standalone React component
* which allows us to manually inspect some frontend behavior.
*
* Writing inspection tests is especially convenient for cases where it's
* easy to verify that a component is working properly by manually interacting
* with it, but hard/expensive to test automatically.
*
* An example is a FileUploader component which uploads a file from the user,
* goes through the FileReader API, etc.
*
* TODO([#1148]): Improve the inspection testing system (e.g. so we can access
* a list of all tests from the frontend), and separate it from serving the
* homepage.
*
* [#1148]: https://github.com/sourcecred/sourcecred/issues/1148
*/
function inspectionTestFor(name, component) /*: RouteDatum */ {
return {
path: "/test/" + name + "/",
contents: {
type: "PAGE",
component: component,
},
title: "Inspection test for: " + name,
navTitle: null,
};
}
function makeRouteData(
projectIds /*: $ReadOnlyArray<string> */
_unused_projectIds /*: $ReadOnlyArray<string> */
) /*: RouteData */ {
return [
{
@ -68,51 +39,6 @@ function makeRouteData(
title: "SourceCred",
navTitle: "Home",
},
{
path: "/prototype/",
contents: {
type: "PAGE",
component: () => require("./PrototypesPage").default(projectIds),
},
title: "SourceCred prototype",
navTitle: "Prototype",
},
...projectIds.map((id) => ({
path: `/prototype/${id}/`,
contents: {
type: "PAGE",
component: () => require("./ProjectPage").default(id),
},
title: `${id} • SourceCred`,
navTitle: null,
})),
...projectIds.map((id) => ({
path: `/timeline/${id}/`,
contents: {
type: "PAGE",
component: () => require("./TimelinePage").default(id),
},
title: `${id} • Timeline`,
navTitle: null,
})),
{
path: "/discord-invite/",
contents: {
type: "EXTERNAL_REDIRECT",
redirectTo: "https://discord.gg/tsBTgc9",
},
title: "SourceCred Discord invite",
navTitle: null,
},
// Inspection Tests Below //
inspectionTestFor(
"FileUploader",
() => require("../util/FileUploaderInspectionTest").default
),
inspectionTestFor(
"TimelineCredView",
() => require("../explorer/TimelineCredViewInspectionTest").default
),
];
}
exports.makeRouteData = makeRouteData;