1
0
mirror of https://github.com/Unleash/unleash.git synced 2025-03-18 00:19:49 +01:00

Adds contributors to docs (#6900)

Hello!

We wanted to make the docs less impersonal, so we decided to add
contributors. Now each doc page that has an `editUrl` (i.e, isn't
generated) shows a list of everyone that contributed to it.

This list is generated by:
1. Running `swizzle` on the `DocItem/Footer` in Docusaurus.
2. Grabbing metadata for the current file using an internal docusaurus
API (Thank you to @homotechsual for the help there)
3. Getting the commits to the file in question with the GitHub API


![image](https://github.com/Unleash/unleash/assets/107407814/fd9c92ef-36ab-4d9e-ac11-6d724fd55d11)

<details>
 <summary> Here's the command I ran, for posterity </summary>
<code>npm run swizzle @docusaurus/theme-classic DocItem/Footer --
--wrap</code>
</details>


## Discussion points

1. Design. What do you think of the layout?
2. Right now I'm hardcoding the info of Unleash team members. This
creates a small maintenance burden, but it's something we wanted to add.
This commit is contained in:
Alvin Bryan 2024-04-30 15:19:38 +01:00 committed by GitHub
parent 0bacd60caf
commit 4ad56e8afc
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 339 additions and 1 deletions

View File

@ -31,6 +31,7 @@
"docusaurus-plugin-openapi-docs": "2.0.0-beta.3",
"docusaurus-plugin-remote-content": "^3.1.0",
"docusaurus-theme-openapi-docs": "2.0.0-beta.2",
"git-url-parse": "^14.0.0",
"plugin-image-zoom": "flexanalytics/plugin-image-zoom",
"prism-svelte": "^0.5.0",
"react": "18.2.0",

View File

@ -17,6 +17,7 @@
--navbar-link-color: #122d33;
--unleash-font-size-smaller: 90%;
--ifm-footer-logo-max-width: 250px;
/* navbar is independent of the theme in general */
--ifm-navbar-background-color: var(--unleash-color-green);

View File

@ -0,0 +1,92 @@
// biome-ignore lint/correctness/noUnusedImports: Needs this for React to work
import React, { useState, useEffect } from 'react';
import { getContributors } from './contributors';
import styles from './contributors.module.scss';
const unleashTeam = new Map([
['alvinometric', 'developer advocate, Unleash'],
['andreas-unleash', 'developer, Unleash'],
['chriswk', 'principal developer, Unleash'],
['daveleek', 'developer, Unleash'],
['FredrikOseberg', 'principal developer, Unleash'],
['gardleopard', 'platform lead, Unleash'],
['gastonfournier', 'senior developer, Unleash'],
['ivarconr', 'co-founder, Unleash'],
['kwasniew', 'senior developer, Unleash'],
['nnennandukwe', 'developer advocate, Unleash'],
['nunogois', 'senior developer, Unleash'],
['sighphyre', 'senior developer, Unleash'],
['sjaanus', 'senior developer, Unleash'],
['thomasheartman', 'developer, Unleash'],
['Tymek', 'developer, Unleash'],
]);
const GitHubContributors = ({ owner, repo, filePath }) => {
const [contributors, setContributors] = useState([]);
const url = `https://api.github.com/repos/${owner}/${repo}/commits?path=${filePath}`;
useEffect(() => {
const fetchFileContributors = () => {
fetch(url)
.then((response) => response.json())
.then((commits) => {
const contributors = getContributors(commits);
contributors.sort((a, b) => {
if (unleashTeam.has(a.login)) {
return -1;
}
return 1;
});
setContributors(contributors);
})
.catch((error) => {
console.error(error);
setContributors([]);
});
};
fetchFileContributors();
}, []);
if (!contributors.length) {
return null;
}
return (
<div className={styles.contributors}>
<h3>Contributors</h3>
<ul className={styles.wrapper}>
{contributors?.map((contributor) => {
const isUnleashTeam = unleashTeam.has(contributor.login);
const name = isUnleashTeam
? `${contributor.login}, ${unleashTeam.get(
contributor.login,
)}`
: contributor.login;
return (
<li
key={contributor.login}
className={styles.contributor}
>
<a
href={contributor.html_url}
className={isUnleashTeam ? styles.unleash : ''}
title={`@${name}`}
>
<img
src={contributor.avatar_url}
alt={contributor.login}
width={70}
/>
</a>
</li>
);
})}
</ul>
</div>
);
};
export default GitHubContributors;

View File

@ -0,0 +1,23 @@
export const getContributors = (commits) => {
// filter out commits that don't have an author
const commitsWithAuthors = commits.filter((commit) => !!commit.author);
// use a Set to deduplicate the list of contributors
const contributorSet = new Set();
for (const commit of commitsWithAuthors) {
contributorSet.add(JSON.stringify(commit.author));
}
const contributors = Array.from(contributorSet).map((str) => {
const contributor = JSON.parse(str);
const { login, html_url, avatar_url } = contributor;
return { login, html_url, avatar_url };
});
// sort alphabetically
contributors.sort((a, b) => {
return a.login.localeCompare(b.login);
});
return contributors;
};

View File

@ -0,0 +1,56 @@
.contributors {
margin-block: var(--ifm-spacing-vertical);
}
.wrapper {
display: flex;
flex-wrap: wrap;
gap: 20px;
margin: 0;
padding: 0;
li{
list-style: none;
}
}
.unleash{
position: relative;
display: block;
}
.unleash:before{
display: block;
position: absolute;
z-index: 2;
content: '';
top: -5px;
right: -5px;
width: 30px;
height: 30px;
background-image: url(/img/logo.svg);
}
.contributor {
margin-top: 10px;
img{
border-radius: 100%;
margin:0;
padding: 0;
border: 2px solid var(--unleash-color-gray);
transition: border-color var(--ifm-transition-fast) var(--ifm-transition-timing-default),
scale var(--ifm-transition-fast) var(--ifm-transition-timing-default);
}
}
.contributor img:hover{
border-color: var(--ifm-pagination-nav-color-hover);
scale: 1.1;
}
@media (max-width: 600px) {
.wrapper {
display: block;
}
}

View File

@ -0,0 +1,99 @@
const commits = [
{
sha: '2754c26f2e022b623e46e08fc1108b350710ef91',
node_id:
'C_kwDOAXdJ9doAKDI3NTRjMjZmMmUwMjJiNjIzZTQ2ZTA4ZmMxMTA4YjM1MDcxMGVmOTE',
url: 'https://api.github.com/repos/Unleash/unleash/commits/2754c26f2e022b623e46e08fc1108b350710ef91',
html_url:
'https://github.com/Unleash/unleash/commit/2754c26f2e022b623e46e08fc1108b350710ef91',
comments_url:
'https://api.github.com/repos/Unleash/unleash/commits/2754c26f2e022b623e46e08fc1108b350710ef91/comments',
author: {
login: 'markunl',
id: 128738155,
node_id: 'U_kgDOB6xjaw',
avatar_url: 'https://avatars.githubusercontent.com/u/128738155?v=4',
gravatar_id: '',
url: 'https://api.github.com/users/markunl',
html_url: 'https://github.com/markunl',
type: 'User',
site_admin: false,
},
},
{
sha: 'd5fbd0b743cc99791d34864c70f78985cc83b2d8',
node_id:
'C_kwDOAXdJ9doAKGQ1ZmJkMGI3NDNjYzk5NzkxZDM0ODY0YzcwZjc4OTg1Y2M4M2IyZDg',
url: 'https://api.github.com/repos/Unleash/unleash/commits/d5fbd0b743cc99791d34864c70f78985cc83b2d8',
html_url:
'https://github.com/Unleash/unleash/commit/d5fbd0b743cc99791d34864c70f78985cc83b2d8',
comments_url:
'https://api.github.com/repos/Unleash/unleash/commits/d5fbd0b743cc99791d34864c70f78985cc83b2d8/comments',
author: {
login: 'thomasheartman',
id: 17786332,
node_id: 'MDQ6VXNlcjE3Nzg2MzMy',
avatar_url: 'https://avatars.githubusercontent.com/u/17786332?v=4',
gravatar_id: '',
url: 'https://api.github.com/users/thomasheartman',
html_url: 'https://github.com/thomasheartman',
type: 'User',
site_admin: false,
},
},
{
sha: 'ebcab898e7610082d3ada81ab0b729ba1f17655d',
node_id:
'C_kwDOAXdJ9doAKGViY2FiODk4ZTc2MTAwODJkM2FkYTgxYWIwYjcyOWJhMWYxNzY1NWQ',
url: 'https://api.github.com/repos/Unleash/unleash/commits/ebcab898e7610082d3ada81ab0b729ba1f17655d',
html_url:
'https://github.com/Unleash/unleash/commit/ebcab898e7610082d3ada81ab0b729ba1f17655d',
comments_url:
'https://api.github.com/repos/Unleash/unleash/commits/ebcab898e7610082d3ada81ab0b729ba1f17655d/comments',
author: {
login: 'thomasheartman',
id: 17786332,
node_id: 'MDQ6VXNlcjE3Nzg2MzMy',
avatar_url: 'https://avatars.githubusercontent.com/u/17786332?v=4',
gravatar_id: '',
url: 'https://api.github.com/users/thomasheartman',
html_url: 'https://github.com/thomasheartman',
type: 'User',
site_admin: false,
},
},
{
sha: 'ead86ed62191777895d5a5f1a7c58f16a87ebde7',
node_id:
'C_kwDOAXdJ9doAKGVhZDg2ZWQ2MjE5MTc3Nzg5NWQ1YTVmMWE3YzU4ZjE2YTg3ZWJkZTc',
author: {
login: 'thomasheartman',
id: 17786332,
node_id: 'MDQ6VXNlcjE3Nzg2MzMy',
avatar_url: 'https://avatars.githubusercontent.com/u/17786332?v=4',
gravatar_id: '',
url: 'https://api.github.com/users/thomasheartman',
html_url: 'https://github.com/thomasheartman',
type: 'User',
site_admin: false,
},
},
];
const expectedContributors = [
{
login: 'thomasheartman',
html_url: 'https://github.com/thomasheartman',
avatar_url: 'https://avatars.githubusercontent.com/u/17786332?v=4',
},
{
login: 'markunl',
html_url: 'https://github.com/markunl',
avatar_url: 'https://avatars.githubusercontent.com/u/128738155?v=4',
},
];
test('getContributors should return the correct list of contributors', () => {
const contributors = getContributors(commits);
expect(contributors).toEqual(expectedContributors);
});

View File

@ -0,0 +1,25 @@
// biome-ignore lint/correctness/noUnusedImports: Needs this for React to work
import React from 'react';
import Footer from '@theme-original/DocItem/Footer';
import { useDoc } from '@docusaurus/theme-common/internal';
import GitHubContributors from './GitHubContributors';
import GitUrlParse from 'git-url-parse';
export default function FooterWrapper(props) {
const { metadata } = useDoc();
const file = metadata.editUrl;
if (!file) {
return <Footer {...props} />;
}
const info = GitUrlParse(file);
const { name, owner, filepath } = info;
return (
<>
<Footer {...props} />
<GitHubContributors repo={name} owner={owner} filePath={filepath} />
</>
);
}

View File

@ -1 +1 @@
<svg id="bg" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 251.43 251.03"><defs><style>.cls-1{fill:#1a4049;}.cls-2{fill:#fff;}.cls-3{fill:#817afe;}</style></defs><circle class="cls-1" cx="125.71" cy="125.31" r="80"/><polygon class="cls-2" points="137.14 91.03 137.14 113.88 137.14 136.74 160 136.74 160 113.88 160 91.03 137.14 91.03"/><polygon class="cls-2" points="114.29 113.88 114.29 91.03 91.43 91.03 91.43 113.88 91.43 136.74 91.43 159.6 114.29 159.6 137.14 159.6 137.14 136.74 114.29 136.74 114.29 113.88"/><rect class="cls-3" x="137.14" y="136.74" width="22.86" height="22.86"/></svg>
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 161 161"><path fill="#1A4049" d="M80.71 160.31c44.183 0 80-35.817 80-80s-35.817-80-80-80-80 35.817-80 80 35.817 80 80 80Z"/><path fill="#fff" d="M92.14 46.03v45.71H115V46.03H92.14ZM69.29 68.88V46.03H46.43v68.57h45.71V91.74H69.29V68.88Z"/><path fill="#817AFE" d="M115 91.74H92.14v22.86H115V91.74Z"/></svg>

Before

Width:  |  Height:  |  Size: 593 B

After

Width:  |  Height:  |  Size: 369 B

View File

@ -6743,6 +6743,21 @@ get-stream@^6.0.0, get-stream@^6.0.1:
resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-6.0.1.tgz#a262d8eef67aced57c2852ad6167526a43cbf7b7"
integrity sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==
git-up@^7.0.0:
version "7.0.0"
resolved "https://registry.yarnpkg.com/git-up/-/git-up-7.0.0.tgz#bace30786e36f56ea341b6f69adfd83286337467"
integrity sha512-ONdIrbBCFusq1Oy0sC71F5azx8bVkvtZtMJAsv+a6lz5YAmbNnLD6HAB4gptHZVLPR8S2/kVN6Gab7lryq5+lQ==
dependencies:
is-ssh "^1.4.0"
parse-url "^8.1.0"
git-url-parse@^14.0.0:
version "14.0.0"
resolved "https://registry.yarnpkg.com/git-url-parse/-/git-url-parse-14.0.0.tgz#18ce834726d5fbca0c25a4555101aa277017418f"
integrity sha512-NnLweV+2A4nCvn4U/m2AoYu0pPKlsmhK9cknG7IMwsjFY1S2jxM+mAhsDxyxfCIGfGaD+dozsyX4b6vkYc83yQ==
dependencies:
git-up "^7.0.0"
github-slugger@^1.4.0:
version "1.5.0"
resolved "https://registry.yarnpkg.com/github-slugger/-/github-slugger-1.5.0.tgz#17891bbc73232051474d68bd867a34625c955f7d"
@ -7645,6 +7660,13 @@ is-root@^2.1.0:
resolved "https://registry.yarnpkg.com/is-root/-/is-root-2.1.0.tgz#809e18129cf1129644302a4f8544035d51984a9c"
integrity sha512-AGOriNp96vNBd3HtU+RzFEc75FfR5ymiYv8E553I71SCeXBiMsVDUtdio1OEFvrPyLIQ9tVR5RxXIFe5PUFjMg==
is-ssh@^1.4.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/is-ssh/-/is-ssh-1.4.0.tgz#4f8220601d2839d8fa624b3106f8e8884f01b8b2"
integrity sha512-x7+VxdxOdlV3CYpjvRLBv5Lo9OJerlYanjwFrPR9fuGPjCiNiCzFgAWpiLAohSbsnH4ZAys3SBh+hq5rJosxUQ==
dependencies:
protocols "^2.0.1"
is-stream@^2.0.0:
version "2.0.1"
resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.1.tgz#fac1e3d53b97ad5a9d0ae9cef2389f5810a5c077"
@ -9020,6 +9042,20 @@ parse-numeric-range@^1.3.0:
resolved "https://registry.yarnpkg.com/parse-numeric-range/-/parse-numeric-range-1.3.0.tgz#7c63b61190d61e4d53a1197f0c83c47bb670ffa3"
integrity sha512-twN+njEipszzlMJd4ONUYgSfZPDxgHhT9Ahed5uTigpQn90FggW4SA/AIPq/6a149fTbE9qBEcSwE3FAEp6wQQ==
parse-path@^7.0.0:
version "7.0.0"
resolved "https://registry.yarnpkg.com/parse-path/-/parse-path-7.0.0.tgz#605a2d58d0a749c8594405d8cc3a2bf76d16099b"
integrity sha512-Euf9GG8WT9CdqwuWJGdf3RkUcTBArppHABkO7Lm8IzRQp0e2r/kkFnmhu4TSK30Wcu5rVAZLmfPKSBBi9tWFog==
dependencies:
protocols "^2.0.0"
parse-url@^8.1.0:
version "8.1.0"
resolved "https://registry.yarnpkg.com/parse-url/-/parse-url-8.1.0.tgz#972e0827ed4b57fc85f0ea6b0d839f0d8a57a57d"
integrity sha512-xDvOoLU5XRrcOZvnI6b8zA6n9O9ejNk/GExuz1yBuWUGn9KA97GI6HTs6u02wKara1CeVmZhH+0TZFdWScR89w==
dependencies:
parse-path "^7.0.0"
parse5-htmlparser2-tree-adapter@^7.0.0:
version "7.0.0"
resolved "https://registry.yarnpkg.com/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-7.0.0.tgz#23c2cc233bcf09bb7beba8b8a69d46b08c62c2f1"
@ -9567,6 +9603,11 @@ property-information@^6.0.0:
resolved "https://registry.yarnpkg.com/property-information/-/property-information-6.1.1.tgz#5ca85510a3019726cb9afed4197b7b8ac5926a22"
integrity sha512-hrzC564QIl0r0vy4l6MvRLhafmUowhO/O3KgVSoXIbbA2Sz4j8HGpJc6T2cubRVwMwpdiG/vKGfhT4IixmKN9w==
protocols@^2.0.0, protocols@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/protocols/-/protocols-2.0.1.tgz#8f155da3fc0f32644e83c5782c8e8212ccf70a86"
integrity sha512-/XJ368cyBJ7fzLMwLKv1e4vLxOju2MNAIokcr7meSaNcVbWz/CPcW22cP04mwxOErdA5mwjA8Q6w/cdAQxVn7Q==
proxy-addr@~2.0.7:
version "2.0.7"
resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.7.tgz#f19fe69ceab311eeb94b42e70e8c2070f9ba1025"