diff --git a/src/pages/ContentScripts/features/contributor_button/DataNotFound.tsx b/src/pages/ContentScripts/features/contributor_button/DataNotFound.tsx new file mode 100644 index 00000000..9ee69d34 --- /dev/null +++ b/src/pages/ContentScripts/features/contributor_button/DataNotFound.tsx @@ -0,0 +1,26 @@ +import React from 'react'; + +const DataNotFound = () => { + return ( +
+

Data Not Found

+
+

Possible reasons are:

+ +
+
+ ); +}; + +export default DataNotFound; diff --git a/src/pages/ContentScripts/features/contributor_button/index.tsx b/src/pages/ContentScripts/features/contributor_button/index.tsx new file mode 100644 index 00000000..f23725ab --- /dev/null +++ b/src/pages/ContentScripts/features/contributor_button/index.tsx @@ -0,0 +1,77 @@ +/** + * This module is responsible for enhancing the contributor list on the GitHub repository page. + * It uses React to render the contributor list and fetches additional network data through the API. + */ + +import React, { useState, useEffect } from 'react'; +import { render } from 'react-dom'; +import $ from 'jquery'; +import View from './view'; +import { getRepoName } from '../../../../helpers/get-repo-info'; +import { getDeveloperNetwork, getRepoNetwork } from '../../../../api/repo'; +import features from '../../../../feature-manager'; +import * as pageDetect from 'github-url-detection'; +import elementReady from 'element-ready'; + +// Global variables are used to store the repository name and network data for sharing between different functions. +// Define global variables to store the repository name and network data. +let repoName: string; +let developerNetworks: any; +let repoNetworks: any; +let target: any; + +// Get the feature ID of the current module for feature management. +const featureId = features.getFeatureID(import.meta.url); + +/** + * Asynchronously fetch network data of the repository developer and the repository. + */ +const getData = async () => { + developerNetworks = await getDeveloperNetwork(repoName); + repoNetworks = await getRepoNetwork(repoName); +}; + +/** + * Replace the contributor list with a React component. + * @param target The target element to be replaced. + */ +const renderTo = (target: HTMLElement) => { + const originalHTML = target.innerHTML; + + render( + + + , + document.querySelector('.list-style-none.d-flex.flex-wrap.mb-n2') as HTMLElement + ); +}; + +/** + * Initialize the feature, including fetching the repository name and data, and replacing the contributor list. + */ +const init = async (): Promise => { + repoName = getRepoName(); + const targetElement = document.querySelector('.list-style-none.d-flex.flex-wrap.mb-n2') as HTMLElement; + await getData(); + renderTo(targetElement); +}; + +/** + * Restore the feature when the page is refreshed or navigated, reload the data and render the list. + */ +const restore = async () => { + if (repoName !== getRepoName()) { + repoName = getRepoName(); + await getData(); + } + $('div.ReactModalPortal').remove(); + renderTo(target); +}; + +// Add the feature to the feature manager, configure the initialization and restore functions. +features.add(featureId, { + // asLongAs: [pageDetect.isUserProfile], + awaitDomReady: false, + init, + restore, +}); diff --git a/src/pages/ContentScripts/features/contributor_button/view.tsx b/src/pages/ContentScripts/features/contributor_button/view.tsx new file mode 100644 index 00000000..451f5673 --- /dev/null +++ b/src/pages/ContentScripts/features/contributor_button/view.tsx @@ -0,0 +1,95 @@ +import React, { useState, useEffect } from 'react'; +import ReactModal from 'react-modal'; +import Graph from '../../../../components/Graph'; +import optionsStorage, { HypercrxOptions, defaults } from '../../../../options-storage'; +import { useTranslation } from 'react-i18next'; +import '../../../../helpers/i18n'; + +// Define the time period for the developer and the repository +const DEVELOPER_PERIOD = 90; +const REPO_PERIOD = 90; + +// Define the Props interface, including the developer network and the target HTML +interface Props { + developerNetwork: any; + target: any; +} + +const borderStyle = { + 'margin-top': '0', +}; + +// Define the chart style +const graphStyle = { + width: '296px', + height: '400px', +}; + +const targetStyle = { + width: '296px', + height: '80px', + display: 'flex', + 'justify-content': 'flex-start', + 'align-items': 'flex-start', + 'align-content': 'flex-start', + 'flex-wrap': 'wrap', +}; + +const buttonStyle = { + margin: '-5px 0px 10px 0px', + padding: '6px 14px', + 'font-size': '14px', + 'font-family': 'inherit', + 'font-weight': '500', + 'box-shadow': + 'var(--button-default-shadow-resting, var(--color-btn-shadow, 0 1px 0 rgba(27, 31, 36, 0.04))), var(--button-default-shadow-inset, var(--color-btn-inset-shadow, inset 0 1px 0 rgba(255, 255, 255, 0.25)))', + 'border-radius': '6px', + 'border-width': '1px', + 'border-style': 'solid', + 'border-image': 'initial', + 'border-color': + 'var(--button-default-borderColor-rest, var(--button-default-borderColor-rest, var(--color-btn-border, rgba(27, 31, 36, 0.15))))', + 'text-decoration': 'none', +}; + +// Define the View component +const View = ({ developerNetwork, target }: Props): JSX.Element => { + // Define state variables, including options, whether to show the chart, and whether to show the repository network + const [options, setOptions] = useState(defaults); + const [showGraph, setShowGraph] = useState(true); + const [showRepoNetwork, setShowRepoNetwork] = useState(false); + + // Use the translation function + const { t, i18n } = useTranslation(); + + // Use the useEffect hook to handle side effects, including fetching options and changing the language + useEffect(() => { + (async function () { + setOptions(await optionsStorage.getAll()); + i18n.changeLanguage(options.locale); + })(); + }, [options.locale]); + + // Return JSX elements, including a button and a conditionally rendered chart or target HTML + return ( +
+ + {showGraph ? ( +
+
+
+ +
+
+
+ ) : ( +
+ )} +
+ ); +}; + +// Export the View component +export default View; diff --git a/src/pages/ContentScripts/index.ts b/src/pages/ContentScripts/index.ts index bab274a3..c2e3cbb8 100644 --- a/src/pages/ContentScripts/index.ts +++ b/src/pages/ContentScripts/index.ts @@ -1,5 +1,5 @@ import './index.scss'; - +import './features/contributor_button'; import './features/repo-activity-openrank-trends'; import './features/developer-activity-openrank-trends'; import './features/repo-header-labels';