forked from hypertrons/hypertrons-crx
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(contributor-button): 添加数据未找到组件并初始化React模块- 创建DataNotFound组件,用于在未找到数据时展示可能的原因。- 在index.ts中引入contributor_button模块,确保其在页面加载时被初始化。 - 初始化contributor_button模块的React组件,包括状态管理、数据获取和视图渲染逻辑。 - 添加必要的类型定义和全局变量,以支持贡献者按钮功能的正确运行。 - 通过ReactModal和Graph组件增强用户界面,提供切换视图的功能。 在贡献者提供了贡献者网络视图 Active Developer Collaboration Network,以及切换按钮,通过点击可以切换贡献者展示视图.增强了对GitHub仓库页面中贡献者列表的展示功能,提供了更丰富的交互体验。
- Loading branch information
1 parent
4a09f0d
commit f14faf9
Showing
10 changed files
with
367 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
26 changes: 26 additions & 0 deletions
26
src/pages/ContentScripts/features/contributor_button/DataNotFound.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
import React from 'react'; | ||
|
||
const DataNotFound = () => { | ||
return ( | ||
<div | ||
style={{ | ||
display: 'flex', | ||
flexDirection: 'column', | ||
justifyContent: 'center', | ||
alignItems: 'center', | ||
color: 'var(--color-fg-muted)', | ||
}} | ||
> | ||
<h3>Data Not Found</h3> | ||
<div style={{ width: '300px', margin: '2em' }}> | ||
<p>Possible reasons are:</p> | ||
<ul style={{ marginLeft: '1em' }}> | ||
<li>This repository is too new, so its data has not been generated</li> | ||
<li>This repository is not active enough, so its data are not generated</li> | ||
</ul> | ||
</div> | ||
</div> | ||
); | ||
}; | ||
|
||
export default DataNotFound; |
78 changes: 78 additions & 0 deletions
78
src/pages/ContentScripts/features/contributor_button/index.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
/** | ||
* 该模块负责在GitHub仓库页面中,增强贡献者列表的功能。 | ||
* 它使用React来渲染贡献者列表,并通过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"; | ||
|
||
// 全局变量用于存储仓库名称和网络数据,以便在不同函数间共享 | ||
// 定义全局变量,用于存储仓库名称和网络数据。 | ||
let repoName: string; | ||
let developerNetworks: any; | ||
let repoNetworks: any; | ||
let target: any; | ||
|
||
// 获取当前模块的特征ID,用于特性管理。 | ||
const featureId = features.getFeatureID(import.meta.url); | ||
|
||
/** | ||
* 异步获取仓库开发者和仓库的网络数据。 | ||
*/ | ||
const getData = async () => { | ||
developerNetworks = await getDeveloperNetwork(repoName); | ||
repoNetworks = await getRepoNetwork(repoName); | ||
}; | ||
|
||
/** | ||
* 替换贡献者列表为React组件。 | ||
* @param target 要替换的目标元素。 | ||
*/ | ||
const replaceContributorList = (target: HTMLElement) => { | ||
const originalHTML = target.innerHTML; | ||
|
||
render( | ||
<React.Fragment> | ||
<View developerNetwork={developerNetworks} target={originalHTML} /> | ||
</React.Fragment>, | ||
document.querySelector('.list-style-none.d-flex.flex-wrap.mb-n2') as HTMLElement | ||
); | ||
}; | ||
|
||
/** | ||
* 初始化功能,包括获取仓库名称和数据,以及替换贡献者列表。 | ||
*/ | ||
const init = async (): Promise<void> => { | ||
repoName = getRepoName(); | ||
const targetElement = document.querySelector('.list-style-none.d-flex.flex-wrap.mb-n2') as HTMLElement; | ||
await getData(); | ||
replaceContributorList(targetElement); | ||
}; | ||
|
||
/** | ||
* 在页面刷新或导航时恢复功能,重新加载数据和渲染列表。 | ||
*/ | ||
const restore = async () => { | ||
if (repoName !== getRepoName()) { | ||
repoName = getRepoName(); | ||
await getData(); | ||
} | ||
$('div.ReactModalPortal').remove(); | ||
replaceContributorList(target); | ||
}; | ||
|
||
|
||
// 将功能添加到特性管理器中,配置初始化和恢复函数。 | ||
features.add(featureId, { | ||
// asLongAs: [pageDetect.isUserProfile], | ||
awaitDomReady: false, | ||
init, | ||
restore, | ||
}); |
64 changes: 64 additions & 0 deletions
64
src/pages/ContentScripts/features/contributor_button/view.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
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'; | ||
|
||
// 定义开发者和仓库的时间周期 | ||
const DEVELOPER_PERIOD = 90; | ||
const REPO_PERIOD = 90; | ||
|
||
// 定义Props接口,包括开发者网络和目标HTML | ||
interface Props { | ||
developerNetwork: any; | ||
target: any; | ||
} | ||
|
||
// 定义图表样式 | ||
const graphStyle = { | ||
width: '296px', | ||
height: '400px', | ||
}; | ||
|
||
// 定义View组件 | ||
const View = ({ developerNetwork, target}: Props): JSX.Element => { | ||
// 定义状态变量,包括选项、是否显示图表和是否显示仓库网络 | ||
const [options, setOptions] = useState<HypercrxOptions>(defaults); | ||
const [showGraph, setShowGraph] = useState(true); | ||
const [showRepoNetwork, setShowRepoNetwork] = useState(false); | ||
|
||
// 使用翻译函数 | ||
const { t, i18n } = useTranslation(); | ||
|
||
// 使用useEffect钩子来处理副作用,包括获取选项和改变语言 | ||
useEffect(() => { | ||
(async function () { | ||
setOptions(await optionsStorage.getAll()); | ||
i18n.changeLanguage(options.locale); | ||
})(); | ||
}, [options.locale]); | ||
|
||
// 返回JSX元素,包括一个按钮和一个条件渲染的图表或目标HTML | ||
return ( | ||
<div> | ||
<button onClick={() => setShowGraph(!showGraph)}> | ||
切换视图 | ||
</button> | ||
{showGraph ? ( | ||
<div className="hypertrons-crx-border hypertrons-crx-container"> | ||
<div className="d-flex flex-wrap flex-items-center" style={{ margin: '0 0 0 0', padding: "0"}}> | ||
<div style={{ margin: '0 0 0 0', padding: "0", display: "block"}}> | ||
<Graph data={developerNetwork} style={graphStyle} /> | ||
</div> | ||
</div> | ||
</div> | ||
) : ( | ||
<div dangerouslySetInnerHTML={{ __html: target }} style={{margin: '0', padding: "0"}} /> | ||
)} | ||
</div> | ||
); | ||
}; | ||
|
||
// 导出View组件 | ||
export default View; |
157 changes: 157 additions & 0 deletions
157
src/pages/ContentScripts/features/repo-header-labels/ContributorChart.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,157 @@ | ||
import React, { useEffect, useRef } from 'react'; | ||
import * as echarts from 'echarts'; | ||
|
||
import { formatNum, numberWithCommas } from '../../../../helpers/formatter'; | ||
|
||
const LIGHT_THEME = { | ||
FG_COLOR: '#24292F', | ||
BG_COLOR: '#ffffff', | ||
SPLIT_LINE_COLOR: '#D0D7DE', | ||
BAR_COLOR: '#3E90F1', | ||
LINE_COLOR: '#267FE8', | ||
}; | ||
|
||
const DARK_THEME = { | ||
FG_COLOR: '#c9d1d9', | ||
BG_COLOR: '#0d1118', | ||
SPLIT_LINE_COLOR: '#30363D', | ||
BAR_COLOR: '#3E90F1', | ||
LINE_COLOR: '#82BBFF', | ||
}; | ||
|
||
interface ContributorChartProps { | ||
theme: 'light' | 'dark'; | ||
width: number; | ||
height: number; | ||
data: [string, number][]; | ||
} | ||
|
||
const ContributorChart = (props: ContributorChartProps): JSX.Element => { | ||
const { theme, width, height, data } = props; | ||
|
||
const divEL = useRef(null); | ||
|
||
const TH = theme == 'light' ? LIGHT_THEME : DARK_THEME; | ||
|
||
const option: echarts.EChartsOption = { | ||
tooltip: { | ||
trigger: 'axis', | ||
textStyle: { | ||
color: TH.FG_COLOR, | ||
}, | ||
backgroundColor: TH.BG_COLOR, | ||
formatter: tooltipFormatter, | ||
}, | ||
grid: { | ||
top: '10%', | ||
bottom: '5%', | ||
left: '8%', | ||
right: '5%', | ||
containLabel: true, | ||
}, | ||
xAxis: { | ||
type: 'time', | ||
// 30 * 3600 * 24 * 1000 milliseconds | ||
minInterval: 2592000000, | ||
splitLine: { | ||
show: false, | ||
}, | ||
axisLabel: { | ||
color: TH.FG_COLOR, | ||
formatter: { | ||
year: '{yearStyle|{yy}}', | ||
month: '{MMM}', | ||
}, | ||
rich: { | ||
yearStyle: { | ||
fontWeight: 'bold', | ||
}, | ||
}, | ||
}, | ||
}, | ||
yAxis: [ | ||
{ | ||
type: 'value', | ||
position: 'left', | ||
axisLabel: { | ||
color: TH.FG_COLOR, | ||
formatter: formatNum, | ||
}, | ||
splitLine: { | ||
lineStyle: { | ||
color: TH.SPLIT_LINE_COLOR, | ||
}, | ||
}, | ||
}, | ||
], | ||
dataZoom: [ | ||
{ | ||
type: 'inside', | ||
start: 0, | ||
end: 100, | ||
minValueSpan: 3600 * 24 * 1000 * 180, | ||
}, | ||
], | ||
series: [ | ||
{ | ||
type: 'bar', | ||
data: data, | ||
itemStyle: { | ||
color: '#ff8061', | ||
}, | ||
emphasis: { | ||
focus: 'series', | ||
}, | ||
yAxisIndex: 0, | ||
}, | ||
{ | ||
type: 'line', | ||
symbol: 'none', | ||
lineStyle: { | ||
color: '#ff8061', | ||
}, | ||
data: data, | ||
emphasis: { | ||
focus: 'series', | ||
}, | ||
yAxisIndex: 0, | ||
}, | ||
], | ||
animationEasing: 'elasticOut', | ||
animationDelayUpdate: function (idx: any) { | ||
return idx * 5; | ||
}, | ||
}; | ||
|
||
useEffect(() => { | ||
let chartDOM = divEL.current; | ||
const instance = echarts.init(chartDOM as any); | ||
|
||
return () => { | ||
instance.dispose(); | ||
}; | ||
}, []); | ||
|
||
useEffect(() => { | ||
let chartDOM = divEL.current; | ||
const instance = echarts.getInstanceByDom(chartDOM as any); | ||
if (instance) { | ||
instance.setOption(option); | ||
} | ||
}, []); | ||
|
||
return <div ref={divEL} style={{ width, height }}></div>; | ||
}; | ||
|
||
const tooltipFormatter = (params: any) => { | ||
const res = ` | ||
${params[0].data[0]}<br/> | ||
${params[0].marker} | ||
<span style="font-weight:bold;"> | ||
${numberWithCommas(params[0].data[1])} | ||
</span> | ||
`; | ||
return res; | ||
}; | ||
|
||
export default ContributorChart; |
Oops, something went wrong.