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  <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:
parent
0bacd60caf
commit
4ad56e8afc
@ -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",
|
||||
|
@ -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);
|
||||
|
92
website/src/theme/DocItem/Footer/GitHubContributors.jsx
Normal file
92
website/src/theme/DocItem/Footer/GitHubContributors.jsx
Normal 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;
|
23
website/src/theme/DocItem/Footer/contributors.js
Normal file
23
website/src/theme/DocItem/Footer/contributors.js
Normal 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;
|
||||
};
|
56
website/src/theme/DocItem/Footer/contributors.module.scss
Normal file
56
website/src/theme/DocItem/Footer/contributors.module.scss
Normal 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;
|
||||
}
|
||||
}
|
99
website/src/theme/DocItem/Footer/contributors.test.js
Normal file
99
website/src/theme/DocItem/Footer/contributors.test.js
Normal 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);
|
||||
});
|
25
website/src/theme/DocItem/Footer/index.jsx
Normal file
25
website/src/theme/DocItem/Footer/index.jsx
Normal 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} />
|
||||
</>
|
||||
);
|
||||
}
|
@ -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 |
@ -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"
|
||||
|
Loading…
Reference in New Issue
Block a user