Merge pull request #96 from unix/contributors

docs: show contributors on document site
This commit is contained in:
witt
2020-04-13 20:50:38 +08:00
committed by GitHub
8 changed files with 206 additions and 17 deletions

View File

@@ -1,6 +1,6 @@
version: 2
jobs:
docs:
lint:
docker:
- image: circleci/node:12.0
@@ -21,7 +21,7 @@ jobs:
- node_modules
key: v2-dependencies-{{ checksum "package.json" }}
- run: yarn run now-build
- run: yarn run lint
build:
docker:
@@ -49,5 +49,5 @@ workflows:
version: 2
build_and_test:
jobs:
- docs
- lint
- build

6
.nowignore Normal file
View File

@@ -0,0 +1,6 @@
.idea
.git
.DS_Store
.env
examples
.circleci

View File

@@ -1,20 +1,35 @@
import React, { useMemo } from 'react'
import { Card, Link, Spacer, useTheme } from 'components'
import { Card, Link, Spacer, Avatar, Tooltip, useTheme } from 'components'
import AttributesTitle from './attributes-title'
import VirtualAnchor from 'lib/components/anchor'
import { useConfigs } from '../../config-context'
import ContributorMetadatas from 'lib/data/contributors.json'
const GithubURL = 'https://github.com/zeit-ui/react/blob/master'
export interface AttributesProps {
edit: string
}
export interface Contributor {
name: string
avatar: string
url: string
}
export type ContributorMeta = {
[key: string]: Array<Contributor>
}
const Attributes: React.FC<React.PropsWithChildren<AttributesProps>> = React.memo(({
edit, children,
}) => {
const theme = useTheme()
const { isChinese } = useConfigs()
const link = useMemo(() => {
return `https://github.com/zeit-ui/react/blob/master${edit || '/pages'}`
const link = useMemo(() => `${GithubURL}${edit || '/pages'}`, [])
const contributors = useMemo(() => {
const key = edit.replace('/pages', 'pages')
const users = (ContributorMetadatas as ContributorMeta)[key]
return users || []
}, [])
return (
@@ -24,10 +39,22 @@ const Attributes: React.FC<React.PropsWithChildren<AttributesProps>> = React.mem
<Card className="attr">
{children}
</Card>
<Spacer y={1} />
<Link color target="_blank" className="attributes-link" href={link} rel="nofollow">
{isChinese ? '在 GitHub 上编辑此页面' : 'Edit this page on GitHub'}
</Link>
<Spacer y={3} />
<h4 className="contributor-title">{isChinese ? '文档贡献者' : 'Contributors'}</h4>
<div className="contributors">
{contributors.map((user, index) => (
<Tooltip text={<b>{user.name}</b>} key={`${user.url}-${index}`}>
<Link color pure target="_blank" rel="nofollow" href={user.url}>
<Avatar src={user.avatar} />
</Link>
</Tooltip>
))}
<Tooltip text={isChinese ? '在 GitHub 上编辑此页面' : 'Edit this page on GitHub'} type="dark">
<Link color pure target="_blank" rel="nofollow" href={link}>
<Avatar text="Add" />
</Link>
</Tooltip>
</div>
<style global jsx>{`
.attr table {
@@ -46,10 +73,6 @@ const Attributes: React.FC<React.PropsWithChildren<AttributesProps>> = React.mem
margin-top: 0;
}
.attributes-link {
float: right;
}
.attr table {
border-collapse: separate;
border-spacing: 0;
@@ -105,6 +128,25 @@ const Attributes: React.FC<React.PropsWithChildren<AttributesProps>> = React.mem
border-left: 1px solid transparent;
}
.contributor-title {
text-transform: uppercase;
font-size: 1rem;
letter-spacing: 1.5px;
}
.contributors {
padding-left: ${theme.layout.gap};
padding-top: ${theme.layout.gap};
max-width: 100%;
height: auto;
display: flex;
flex-wrap: wrap;
}
.contributors :global(.tooltip) {
margin-right: 3px;
}
@media only screen and (max-width: ${theme.layout.breakpointMobile}) {
.attr {
overflow-x: scroll;

File diff suppressed because one or more lines are too long

View File

@@ -1,5 +1,10 @@
{
"github": {
"silent": true
},
"build": {
"env": {
"GIT_ORG_READONLY": "@git-org-readonly"
}
}
}

View File

@@ -8,10 +8,11 @@
"types": "dist/index.d.ts",
"license": "MIT",
"scripts": {
"dev": "yarn run docs-collect && next dev",
"docs-build": "yarn run docs-collect && next build",
"dev": "yarn docs-collect && next dev",
"docs-build": "yarn docs-collect && yarn contributor-collect && next build",
"docs-start": "next start",
"docs-collect": "node scripts/collect-meta.js",
"contributor-collect": "node scripts/collect-contributors.js",
"clear": "rm -rf dist",
"lint": "eslint \"{components,lib}/**/*.{js,ts,tsx}\"",
"now-build": "yarn run docs-build",
@@ -55,11 +56,13 @@
"@typescript-eslint/eslint-plugin": "^2.24.0",
"@typescript-eslint/parser": "^2.24.0",
"babel-loader": "^8.0.6",
"dotenv": "^8.2.0",
"eslint": "^6.8.0",
"eslint-config-ts-lambdas": "^1.2.0",
"eslint-plugin-react": "^7.19.0",
"extract-mdx-metadata": "^1.0.0",
"fs-extra": "^8.1.0",
"graphql-request": "^1.8.2",
"next": "^9.3.4",
"react": "^16.13.0",
"react-color": "^2.18.0",
@@ -71,4 +74,4 @@
"webpack-cli": "^3.3.11"
},
"dependencies": {}
}
}

View File

@@ -0,0 +1,102 @@
const token = process.env.GIT_ORG_READONLY
if (!token) require('dotenv').config()
const fs = require('fs-extra')
const path = require('path')
const { GraphQLClient } = require('graphql-request')
const target = path.join(__dirname, '../lib/data/', 'contributors.json')
if (!token) {
console.error('> Not found "GIT_ORG_READONLY" in "process.env".\n')
console.log(' Env variables are automatically injected at production.')
console.log(' If you want to test, run [echo "GIT_ORG_READONLY=your_git_token" > .env ]\n')
process.exit(1)
}
const client = new GraphQLClient('https://api.github.com/graphql', {
headers: {
Authorization: `Bearer ${token}`,
},
})
const pagePrefix = path.join(__dirname, '../pages')
const filterContributors = data => {
if (!data || !data.repository) return []
const nodes = data.repository.object.history.nodes
let users = [], keys = {}
for (const item of nodes) {
const key = item.author.user.url
if (!keys[key]) {
keys[key] = 1
users.push({
name: item.author.name,
avatar: item.author.user.avatarUrl,
url: item.author.user.url,
})
}
}
return users
}
const getContributors = async repoFilePath => {
const query = `query($path: String!) {
repository(owner: "zeit-ui", name: "react") {
object(expression: "master") {
... on Commit {
history(first: 100, path: $path) {
nodes {
author {
name
user {
avatarUrl
url
}
}
}
}
}
}
}
}`
const data = await client.request(query, { path: repoFilePath })
return filterContributors(data)
}
const getFiles = async dirPath => {
const files = await fs.readdir(dirPath)
return files.filter(name => name.endsWith('.mdx'))
}
const getUrls = async () => {
const en = path.join(pagePrefix, 'en-us', 'components')
const zh = path.join(pagePrefix, 'zh-cn', 'components')
const enFiles = await getFiles(en)
const zhFiles = await getFiles(zh)
return enFiles
.map(name => `pages/en-us/components/${name}`)
.concat(zhFiles.map(name => `pages/zh-cn/components/${name}`))
}
;(async () => {
const urls = await getUrls()
const users = await Promise.all(urls.map(async url => {
try {
return {
name: url,
users: await getContributors(url),
}
} catch (e) {
return {}
}
}))
const contributors = users.reduce((pre, current) => {
if (!current.name) return pre
return {
...pre,
[current.name]: current.users,
}
}, {})
fs.writeJSONSync(target, contributors)
})()

View File

@@ -2288,6 +2288,14 @@ create-react-context@0.2.2:
fbjs "^0.8.0"
gud "^1.0.0"
cross-fetch@2.2.2:
version "2.2.2"
resolved "https://registry.yarnpkg.com/cross-fetch/-/cross-fetch-2.2.2.tgz#a47ff4f7fc712daba8f6a695a11c948440d45723"
integrity sha1-pH/09/xxLauo9qaVoRyUhEDUVyM=
dependencies:
node-fetch "2.1.2"
whatwg-fetch "2.0.4"
cross-fetch@3.0.4:
version "3.0.4"
resolved "https://registry.yarnpkg.com/cross-fetch/-/cross-fetch-3.0.4.tgz#7bef7020207e684a7638ef5f2f698e24d9eb283c"
@@ -2530,6 +2538,11 @@ dot-case@^2.1.0:
dependencies:
no-case "^2.2.0"
dotenv@^8.2.0:
version "8.2.0"
resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-8.2.0.tgz#97e619259ada750eea3e4ea3e26bceea5424b16a"
integrity sha512-8sJ78ElpbDJBHNeBzUbUVLsqKdccaa/BXF1uPTw3GrvQTBgrQrtObr2mUrE38vzYd8cEv+m/JBfDLioYcfXoaw==
duplexify@^3.4.2, duplexify@^3.6.0:
version "3.7.1"
resolved "https://registry.yarnpkg.com/duplexify/-/duplexify-3.7.1.tgz#2a4df5317f6ccfd91f86d6fd25d8d8a103b88309"
@@ -3231,6 +3244,13 @@ graceful-fs@^4.1.11, graceful-fs@^4.1.15, graceful-fs@^4.1.2, graceful-fs@^4.1.6
resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.3.tgz#4a12ff1b60376ef09862c2093edd908328be8423"
integrity sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ==
graphql-request@^1.8.2:
version "1.8.2"
resolved "https://registry.yarnpkg.com/graphql-request/-/graphql-request-1.8.2.tgz#398d10ae15c585676741bde3fc01d5ca948f8fbe"
integrity sha512-dDX2M+VMsxXFCmUX0Vo0TopIZIX4ggzOtiCsThgtrKR4niiaagsGTDIHj3fsOMFETpa064vzovI+4YV4QnMbcg==
dependencies:
cross-fetch "2.2.2"
gud@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/gud/-/gud-1.0.0.tgz#a489581b17e6a70beca9abe3ae57de7a499852c0"
@@ -4410,6 +4430,11 @@ no-case@^2.2.0, no-case@^2.3.2:
dependencies:
lower-case "^1.1.1"
node-fetch@2.1.2:
version "2.1.2"
resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.1.2.tgz#ab884e8e7e57e38a944753cec706f788d1768bb5"
integrity sha1-q4hOjn5X44qUR1POxwb3iNF2i7U=
node-fetch@2.6.0:
version "2.6.0"
resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.0.tgz#e633456386d4aa55863f676a7ab0daa8fdecb0fd"
@@ -6588,6 +6613,11 @@ webpack@4.42.0, webpack@^4.41.6:
watchpack "^1.6.0"
webpack-sources "^1.4.1"
whatwg-fetch@2.0.4:
version "2.0.4"
resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-2.0.4.tgz#dde6a5df315f9d39991aa17621853d720b85566f"
integrity sha512-dcQ1GWpOD/eEQ97k66aiEVpNnapVj90/+R+SXTPYGHpYBBypfKJEQjLrvMZ7YXbKm21gXd4NcuxUTjiv1YtLng==
whatwg-fetch@3.0.0, whatwg-fetch@>=0.10.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-3.0.0.tgz#fc804e458cc460009b1a2b966bc8817d2578aefb"