From d935409709460f996d5fcf960507b00c36c1bf44 Mon Sep 17 00:00:00 2001 From: Tenth-crew Date: Thu, 11 Jul 2024 16:43:10 +0800 Subject: [PATCH 01/22] run prettier --- .../developer-avator-openrank/index.tsx | 55 ++++++++++++++ src/pages/ContentScripts/index.ts | 1 + yarn.lock | 73 +++++++++++++++++++ 3 files changed, 129 insertions(+) create mode 100644 src/pages/ContentScripts/features/developer-avator-openrank/index.tsx diff --git a/src/pages/ContentScripts/features/developer-avator-openrank/index.tsx b/src/pages/ContentScripts/features/developer-avator-openrank/index.tsx new file mode 100644 index 00000000..97617da3 --- /dev/null +++ b/src/pages/ContentScripts/features/developer-avator-openrank/index.tsx @@ -0,0 +1,55 @@ +import features from '../../../../feature-manager'; + +import { getOpenrank } from '../../../../api/developer'; + +const featureId = features.getFeatureID(import.meta.url); + +const getData = async (developerName: string): Promise => { + return await getOpenrank(developerName); +}; + +const getDeveloperName = (target: HTMLElement): string | null => { + if (!target) return null; + // 假设需要从容器的内容中获取第一个单词作为开发者名称 + const containerText = target.textContent?.trim(); + if (!containerText) return null; + return containerText.split(' ')[0]; +}; + +// 初始化函数 +const init = async (): Promise => { + document.addEventListener('mouseover', async (event) => { + const target = event.target as HTMLElement; + + // 检查是否悬停在 id 为 js-global-screen-reader-notice 的容器上 + if (target.id === 'js-global-screen-reader-notice') { + // 获取开发者名称 + const developerName = getDeveloperName(target); + if (!developerName) { + console.error('Developer name not found'); + return; + } + + // 获取开发者的排名信息 + const openrank = await getData(developerName); + if (openrank === null) { + console.error('Rank data not found'); + return; + } + + // 创建新的 HTML 元素 + const para = document.createElement('p'); + para.id = 'current-developer-openrank'; + para.innerHTML = `OpenRank ${openrank}`; + para.style.color = 'red'; + + // 将新创建的元素插入到容器内容的前面 + target.insertBefore(para, target.firstChild); + } + }); +}; + +features.add(featureId, { + awaitDomReady: false, + init, +}); diff --git a/src/pages/ContentScripts/index.ts b/src/pages/ContentScripts/index.ts index bab274a3..3df37e8e 100644 --- a/src/pages/ContentScripts/index.ts +++ b/src/pages/ContentScripts/index.ts @@ -13,3 +13,4 @@ import './features/repo-networks'; import './features/developer-networks'; import './features/oss-gpt'; import './features/repo-activity-racing-bar'; +import './features/developer-avator-openrank'; diff --git a/yarn.lock b/yarn.lock index b180687c..89971dc2 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2500,6 +2500,13 @@ cross-env@^7.0.3: dependencies: cross-spawn "^7.0.1" +cross-fetch@4.0.0: + version "4.0.0" + resolved "https://registry.npmmirror.com/cross-fetch/-/cross-fetch-4.0.0.tgz#f037aef1580bb3a1a35164ea2a848ba81b445983" + integrity sha512-e4a5N8lVvuLgAWgnCrLr2PP0YyDOTHa9H/Rj54dirp61qXnNq46m82bRhNqIA5VccJtWBvPTFRV3TtvHUKPB1g== + dependencies: + node-fetch "^2.6.12" + cross-spawn@^7.0.0, cross-spawn@^7.0.1, cross-spawn@^7.0.3: version "7.0.3" resolved "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" @@ -3436,6 +3443,13 @@ html-minifier-terser@^6.0.2: relateurl "^0.2.7" terser "^5.10.0" +html-parse-stringify@^3.0.1: + version "3.0.1" + resolved "https://registry.npmmirror.com/html-parse-stringify/-/html-parse-stringify-3.0.1.tgz#dfc1017347ce9f77c8141a507f233040c59c55d2" + integrity sha512-KknJ50kTInJ7qIScF3jeaFRpMpE8/lfiTdzf/twXyPBLAGrLRTmkz3AdTnKeh40X8k9L2fdYwEp/42WGXIRGcg== + dependencies: + void-elements "3.1.0" + html-webpack-plugin@^5.5.0: version "5.6.0" resolved "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-5.6.0.tgz#50a8fa6709245608cb00e811eacecb8e0d7b7ea0" @@ -3553,6 +3567,27 @@ husky@^8.0.1: resolved "https://registry.npmjs.org/husky/-/husky-8.0.3.tgz#4936d7212e46d1dea28fef29bb3a108872cd9184" integrity sha512-+dQSyqPh4x1hlO1swXBiNb2HzTDN1I2IGLQx1GrBuiqFJfoMrnZWwVmatvSiO+Iz8fBUnf+lekwNo4c2LlXItg== +i18next-browser-languagedetector@^8.0.0: + version "8.0.0" + resolved "https://registry.npmmirror.com/i18next-browser-languagedetector/-/i18next-browser-languagedetector-8.0.0.tgz#b6fdd9b43af67c47f2c26c9ba27710a1eaf31e2f" + integrity sha512-zhXdJXTTCoG39QsrOCiOabnWj2jecouOqbchu3EfhtSHxIB5Uugnm9JaizenOy39h7ne3+fLikIjeW88+rgszw== + dependencies: + "@babel/runtime" "^7.23.2" + +i18next-http-backend@^2.5.2: + version "2.5.2" + resolved "https://registry.npmmirror.com/i18next-http-backend/-/i18next-http-backend-2.5.2.tgz#3d846cc239987fe7700d1cf0f17975807bfd25d3" + integrity sha512-+K8HbDfrvc1/2X8jpb7RLhI9ZxBDpx3xogYkQwGKlWAUXLSEGXzgdt3EcUjLlBCdMwdQY+K+EUF6oh8oB6rwHw== + dependencies: + cross-fetch "4.0.0" + +i18next@^23.11.5: + version "23.11.5" + resolved "https://registry.npmmirror.com/i18next/-/i18next-23.11.5.tgz#d71eb717a7e65498d87d0594f2664237f9e361ef" + integrity sha512-41pvpVbW9rhZPk5xjCX2TPJi2861LEig/YRhUkY+1FQ2IQPS0bKUDYnEqY8XPPbB48h1uIwLnP9iiEfuSl20CA== + dependencies: + "@babel/runtime" "^7.23.2" + iconv-lite@0.4.24: version "0.4.24" resolved "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" @@ -4239,6 +4274,13 @@ node-bitmap@0.0.1: resolved "https://registry.npmjs.org/node-bitmap/-/node-bitmap-0.0.1.tgz#180eac7003e0c707618ef31368f62f84b2a69091" integrity sha512-Jx5lPaaLdIaOsj2mVLWMWulXF6GQVdyLvNSxmiYCvZ8Ma2hfKX0POoR2kgKOqz+oFsRreq0yYZjQ2wjE9VNzCA== +node-fetch@^2.6.12: + version "2.7.0" + resolved "https://registry.npmmirror.com/node-fetch/-/node-fetch-2.7.0.tgz#d0f0fa6e3e2dc1d27efcd8ad99d550bda94d187d" + integrity sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A== + dependencies: + whatwg-url "^5.0.0" + node-forge@^1: version "1.3.1" resolved "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz#be8da2af243b2417d5f646a770663a92b7e9ded3" @@ -5107,6 +5149,14 @@ react-hot-loader@^4.13.0: shallowequal "^1.1.0" source-map "^0.7.3" +react-i18next@^14.1.2: + version "14.1.2" + resolved "https://registry.npmmirror.com/react-i18next/-/react-i18next-14.1.2.tgz#cd57a755f25a32a5fcc3dbe546cf3cc62b4f3ebd" + integrity sha512-FSIcJy6oauJbGEXfhUgVeLzvWBhIBIS+/9c6Lj4niwKZyGaGb4V4vUbATXSlsHJDXXB+ociNxqFNiFuV1gmoqg== + dependencies: + "@babel/runtime" "^7.23.9" + html-parse-stringify "^3.0.1" + react-is@^16.13.1, react-is@^16.7.0: version "16.13.1" resolved "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4" @@ -5855,6 +5905,11 @@ tough-cookie@~2.5.0: psl "^1.1.28" punycode "^2.1.1" +tr46@~0.0.3: + version "0.0.3" + resolved "https://registry.npmmirror.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a" + integrity sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw== + ts-loader@^9.2.6: version "9.5.1" resolved "https://registry.npmjs.org/ts-loader/-/ts-loader-9.5.1.tgz#63d5912a86312f1fbe32cef0859fb8b2193d9b89" @@ -6013,6 +6068,11 @@ verror@1.10.0: core-util-is "1.0.2" extsprintf "^1.2.0" +void-elements@3.1.0: + version "3.1.0" + resolved "https://registry.npmmirror.com/void-elements/-/void-elements-3.1.0.tgz#614f7fbf8d801f0bb5f0661f5b2f5785750e4f09" + integrity sha512-Dhxzh5HZuiHQhbvTW9AMetFfBHDMYpo23Uo9btPXgdYP+3T5S+p+jgNy7spra+veYhBP2dCSgxR/i2Y02h5/6w== + warning@^4.0.3: version "4.0.3" resolved "https://registry.npmjs.org/warning/-/warning-4.0.3.tgz#16e9e077eb8a86d6af7d64aa1e05fd85b4678ca3" @@ -6035,6 +6095,11 @@ wbuf@^1.1.0, wbuf@^1.7.3: dependencies: minimalistic-assert "^1.0.0" +webidl-conversions@^3.0.0: + version "3.0.1" + resolved "https://registry.npmmirror.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871" + integrity sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ== + webpack-cli@^4.9.2: version "4.10.0" resolved "https://registry.npmjs.org/webpack-cli/-/webpack-cli-4.10.0.tgz#37c1d69c8d85214c5a65e589378f53aec64dab31" @@ -6158,6 +6223,14 @@ websocket-extensions@>=0.1.1: resolved "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.4.tgz#7f8473bc839dfd87608adb95d7eb075211578a42" integrity sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg== +whatwg-url@^5.0.0: + version "5.0.0" + resolved "https://registry.npmmirror.com/whatwg-url/-/whatwg-url-5.0.0.tgz#966454e8765462e37644d3626f6742ce8b70965d" + integrity sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw== + dependencies: + tr46 "~0.0.3" + webidl-conversions "^3.0.0" + which@^2.0.1: version "2.0.2" resolved "https://registry.npmjs.org/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" From 406ccf9c0f47be3988f65f7d4fac38d1e5c2f220 Mon Sep 17 00:00:00 2001 From: Tenth-crew Date: Fri, 12 Jul 2024 11:12:05 +0800 Subject: [PATCH 02/22] Modified the developer name acquisition method and tried other monitoring methods --- .../developer-avator-openrank/index.tsx | 43 ++++++++++++++----- 1 file changed, 32 insertions(+), 11 deletions(-) diff --git a/src/pages/ContentScripts/features/developer-avator-openrank/index.tsx b/src/pages/ContentScripts/features/developer-avator-openrank/index.tsx index 97617da3..6053d5c2 100644 --- a/src/pages/ContentScripts/features/developer-avator-openrank/index.tsx +++ b/src/pages/ContentScripts/features/developer-avator-openrank/index.tsx @@ -8,28 +8,49 @@ const getData = async (developerName: string): Promise => { return await getOpenrank(developerName); }; +// 获取开发者名称的函数 const getDeveloperName = (target: HTMLElement): string | null => { - if (!target) return null; - // 假设需要从容器的内容中获取第一个单词作为开发者名称 - const containerText = target.textContent?.trim(); - if (!containerText) return null; - return containerText.split(' ')[0]; + const hovercardUrl = target.getAttribute('data-hovercard-url'); + if (!hovercardUrl) return null; + + // 假设 URL 格式为 /users/tyn1998/hovercard + const matches = hovercardUrl.match(/\/users\/([^\/]+)\/hovercard/); + return matches ? matches[1] : null; }; +// 初始化函数 // 初始化函数 const init = async (): Promise => { - document.addEventListener('mouseover', async (event) => { + // 监听全局鼠标悬停事件 + document.onmouseover = async (event) => { const target = event.target as HTMLElement; - // 检查是否悬停在 id 为 js-global-screen-reader-notice 的容器上 - if (target.id === 'js-global-screen-reader-notice') { + console.log('target:', target.id); + + // 检查是否悬停在 img 元素或其最近的父元素上 + let elementWithHovercard: HTMLElement | null = null; + + if (target.tagName === 'img' && target.hasAttribute('data-hovercard-type')) { + elementWithHovercard = target; + } else { + elementWithHovercard = target.closest('[data-hovercard-type]'); + } + + if (elementWithHovercard) { // 获取开发者名称 - const developerName = getDeveloperName(target); + const developerName = getDeveloperName(elementWithHovercard); if (!developerName) { console.error('Developer name not found'); return; } + // 获取 js-global-screen-reader-notice 容器 + const noticeContainer = document.getElementById('js-global-screen-reader-notice'); + if (!noticeContainer) { + console.error('Notice container not found'); + return; + } + // 获取开发者的排名信息 const openrank = await getData(developerName); if (openrank === null) { @@ -44,9 +65,9 @@ const init = async (): Promise => { para.style.color = 'red'; // 将新创建的元素插入到容器内容的前面 - target.insertBefore(para, target.firstChild); + noticeContainer.insertBefore(para, noticeContainer.firstChild); } - }); + }; }; features.add(featureId, { From ebaab93db4fca143b96259680af340248abf0872 Mon Sep 17 00:00:00 2001 From: Tenth-crew Date: Mon, 15 Jul 2024 16:00:06 +0800 Subject: [PATCH 03/22] modify evenlistener method and add openrank info --- .../developer-avator-openrank/index.tsx | 62 +++++++++---------- 1 file changed, 28 insertions(+), 34 deletions(-) diff --git a/src/pages/ContentScripts/features/developer-avator-openrank/index.tsx b/src/pages/ContentScripts/features/developer-avator-openrank/index.tsx index 6053d5c2..24db9524 100644 --- a/src/pages/ContentScripts/features/developer-avator-openrank/index.tsx +++ b/src/pages/ContentScripts/features/developer-avator-openrank/index.tsx @@ -1,11 +1,21 @@ import features from '../../../../feature-manager'; import { getOpenrank } from '../../../../api/developer'; +import elementReady from 'element-ready'; const featureId = features.getFeatureID(import.meta.url); + const getData = async (developerName: string): Promise => { - return await getOpenrank(developerName); + const jsonData = await getOpenrank(developerName); + if (!jsonData) return null; + + const keys = Object.keys(jsonData); + if (keys.length === 0) return null; + + keys.sort(); // 按键排序,假设键是 ISO 日期格式 + const latestKey = keys[keys.length - 1]; + return jsonData[latestKey]; }; // 获取开发者名称的函数 @@ -18,38 +28,26 @@ const getDeveloperName = (target: HTMLElement): string | null => { return matches ? matches[1] : null; }; -// 初始化函数 // 初始化函数 const init = async (): Promise => { - // 监听全局鼠标悬停事件 - document.onmouseover = async (event) => { - const target = event.target as HTMLElement; - - console.log('target:', target.id); - - // 检查是否悬停在 img 元素或其最近的父元素上 - let elementWithHovercard: HTMLElement | null = null; + // 监听具有 data-hovercard-type="user" 属性的元素 + document.querySelectorAll('[data-hovercard-type="user"]').forEach((element) => { + element.addEventListener('mouseover', async () => { + console.log('mouseover', element); - if (target.tagName === 'img' && target.hasAttribute('data-hovercard-type')) { - elementWithHovercard = target; - } else { - elementWithHovercard = target.closest('[data-hovercard-type]'); - } - - if (elementWithHovercard) { // 获取开发者名称 - const developerName = getDeveloperName(elementWithHovercard); + const developerName = getDeveloperName(element as HTMLElement); if (!developerName) { console.error('Developer name not found'); return; } - // 获取 js-global-screen-reader-notice 容器 - const noticeContainer = document.getElementById('js-global-screen-reader-notice'); - if (!noticeContainer) { - console.error('Notice container not found'); - return; - } + console.log("developerName", developerName); + + // 获取悬浮卡片容器 + const $popoverContainer = 'body > div.sr-only.mt-n1'; + const popover = await elementReady($popoverContainer, { stopOnDomReady: false }); + console.log("popover", popover); // 获取开发者的排名信息 const openrank = await getData(developerName); @@ -58,16 +56,12 @@ const init = async (): Promise => { return; } - // 创建新的 HTML 元素 - const para = document.createElement('p'); - para.id = 'current-developer-openrank'; - para.innerHTML = `OpenRank ${openrank}`; - para.style.color = 'red'; - - // 将新创建的元素插入到容器内容的前面 - noticeContainer.insertBefore(para, noticeContainer.firstChild); - } - }; + // 将 OpenRank 信息作为红色文本直接插入到悬浮卡片容器内容的前面 + if (popover) { + popover.innerHTML = `OpenRank ${openrank} ` + popover.innerHTML; + } + }); + }); }; features.add(featureId, { From 1d57e562fd61a673882b1ab31e4e42024a4e4bfa Mon Sep 17 00:00:00 2001 From: Tenth-crew Date: Mon, 15 Jul 2024 16:00:34 +0800 Subject: [PATCH 04/22] feat: add the developer-avator-openrank --- .../features/developer-avator-openrank/index.tsx | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/pages/ContentScripts/features/developer-avator-openrank/index.tsx b/src/pages/ContentScripts/features/developer-avator-openrank/index.tsx index 24db9524..8ad1db8d 100644 --- a/src/pages/ContentScripts/features/developer-avator-openrank/index.tsx +++ b/src/pages/ContentScripts/features/developer-avator-openrank/index.tsx @@ -5,7 +5,6 @@ import elementReady from 'element-ready'; const featureId = features.getFeatureID(import.meta.url); - const getData = async (developerName: string): Promise => { const jsonData = await getOpenrank(developerName); if (!jsonData) return null; @@ -42,12 +41,12 @@ const init = async (): Promise => { return; } - console.log("developerName", developerName); + console.log('developerName', developerName); // 获取悬浮卡片容器 const $popoverContainer = 'body > div.sr-only.mt-n1'; const popover = await elementReady($popoverContainer, { stopOnDomReady: false }); - console.log("popover", popover); + console.log('popover', popover); // 获取开发者的排名信息 const openrank = await getData(developerName); From 6a9cfb51901aa5b946910ca43751e58b89670b65 Mon Sep 17 00:00:00 2001 From: Tenth-crew Date: Tue, 16 Jul 2024 13:34:17 +0800 Subject: [PATCH 05/22] Modified the presentation of OpenRank --- .../developer-avator-openrank/index.tsx | 130 ++++++++++++++---- 1 file changed, 102 insertions(+), 28 deletions(-) diff --git a/src/pages/ContentScripts/features/developer-avator-openrank/index.tsx b/src/pages/ContentScripts/features/developer-avator-openrank/index.tsx index 8ad1db8d..8e6dff38 100644 --- a/src/pages/ContentScripts/features/developer-avator-openrank/index.tsx +++ b/src/pages/ContentScripts/features/developer-avator-openrank/index.tsx @@ -1,5 +1,4 @@ import features from '../../../../feature-manager'; - import { getOpenrank } from '../../../../api/developer'; import elementReady from 'element-ready'; @@ -12,54 +11,129 @@ const getData = async (developerName: string): Promise => { const keys = Object.keys(jsonData); if (keys.length === 0) return null; - keys.sort(); // 按键排序,假设键是 ISO 日期格式 + keys.sort(); // 假设键是按时间顺序排列的 const latestKey = keys[keys.length - 1]; return jsonData[latestKey]; }; -// 获取开发者名称的函数 const getDeveloperName = (target: HTMLElement): string | null => { const hovercardUrl = target.getAttribute('data-hovercard-url'); if (!hovercardUrl) return null; - // 假设 URL 格式为 /users/tyn1998/hovercard const matches = hovercardUrl.match(/\/users\/([^\/]+)\/hovercard/); return matches ? matches[1] : null; }; -// 初始化函数 +const createTooltip = (text: string): HTMLDivElement => { + const tooltip = document.createElement('div'); + tooltip.id = 'openrank-tooltip'; + tooltip.style.position = 'absolute'; + tooltip.style.backgroundColor = 'rgba(0, 0, 0, 0.7)'; + tooltip.style.color = 'white'; + tooltip.style.padding = '5px 10px'; + tooltip.style.borderRadius = '4px'; + tooltip.style.zIndex = '1000'; + tooltip.style.pointerEvents = 'none'; // 避免阻挡鼠标事件 + tooltip.innerText = text; + document.body.appendChild(tooltip); + return tooltip; +}; + const init = async (): Promise => { - // 监听具有 data-hovercard-type="user" 属性的元素 - document.querySelectorAll('[data-hovercard-type="user"]').forEach((element) => { - element.addEventListener('mouseover', async () => { - console.log('mouseover', element); - - // 获取开发者名称 - const developerName = getDeveloperName(element as HTMLElement); - if (!developerName) { - console.error('Developer name not found'); - return; + // 函数来处理鼠标悬停事件 + const handleMouseOver = async (element: HTMLElement, event: MouseEvent) => { + const developerName = getDeveloperName(element); + if (!developerName) { + console.error('Developer name not found'); + return; + } + + console.log('Developer Name:', developerName); + + const openrank = await getData(developerName); + if (openrank === null) { + console.error('Rank data not found'); + return; + } + + const openrankText = `OpenRank ${openrank}`; + let tooltip = document.getElementById('openrank-tooltip') as HTMLDivElement; + + if (!tooltip) { + tooltip = createTooltip(openrankText); + } else { + tooltip.innerText = openrankText; + } + + const updateTooltipPosition = (e: MouseEvent) => { + const tooltipWidth = tooltip.offsetWidth; + const tooltipHeight = tooltip.offsetHeight; + const offsetX = 15; + const offsetY = 15; + + let left = e.clientX + offsetX + window.scrollX; + let top = e.clientY + offsetY + window.scrollY; + + // Check if the tooltip goes beyond the right edge of the viewport + if (left + tooltipWidth > window.innerWidth + window.scrollX) { + left = e.clientX - tooltipWidth - offsetX + window.scrollX; } - console.log('developerName', developerName); + // Check if the tooltip goes beyond the bottom edge of the viewport + if (top + tooltipHeight > window.innerHeight + window.scrollY) { + top = e.clientY - tooltipHeight - offsetY + window.scrollY; + } - // 获取悬浮卡片容器 - const $popoverContainer = 'body > div.sr-only.mt-n1'; - const popover = await elementReady($popoverContainer, { stopOnDomReady: false }); - console.log('popover', popover); + // Ensure tooltip doesn't go beyond the left edge of the viewport + if (left < window.scrollX) { + left = window.scrollX; + } - // 获取开发者的排名信息 - const openrank = await getData(developerName); - if (openrank === null) { - console.error('Rank data not found'); - return; + // Ensure tooltip doesn't go beyond the top edge of the viewport + if (top < window.scrollY) { + top = window.scrollY; } - // 将 OpenRank 信息作为红色文本直接插入到悬浮卡片容器内容的前面 - if (popover) { - popover.innerHTML = `OpenRank ${openrank} ` + popover.innerHTML; + tooltip.style.left = `${left}px`; + tooltip.style.top = `${top}px`; + }; + + updateTooltipPosition(event); + const mouseMoveHandler = updateTooltipPosition as EventListener; + element.addEventListener('mousemove', mouseMoveHandler); + + element.addEventListener( + 'mouseout', + () => { + if (tooltip) { + tooltip.remove(); + } + element.removeEventListener('mousemove', mouseMoveHandler); + }, + { once: true } + ); + }; + + const bindEventListeners = () => { + document.querySelectorAll('[data-hovercard-type="user"]').forEach((element) => { + if (!element.getAttribute('data-openrank-bound')) { + element.setAttribute('data-openrank-bound', 'true'); + element.addEventListener('mouseover', (event) => handleMouseOver(element as HTMLElement, event as MouseEvent)); } }); + }; + + // 初始绑定 + bindEventListeners(); + + // 观察 DOM 变化,动态为新添加的元素绑定事件 + const observer = new MutationObserver(() => { + bindEventListeners(); + }); + + observer.observe(document.body, { + childList: true, + subtree: true, }); }; From 4e2b8b80f9ff8c54ec15ce42df8c4b9ac13e2834 Mon Sep 17 00:00:00 2001 From: Tenth-crew Date: Tue, 16 Jul 2024 13:42:44 +0800 Subject: [PATCH 06/22] Improved the situation when openrank does not exist --- .../developer-avator-openrank/index.tsx | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) diff --git a/src/pages/ContentScripts/features/developer-avator-openrank/index.tsx b/src/pages/ContentScripts/features/developer-avator-openrank/index.tsx index 8e6dff38..f352f966 100644 --- a/src/pages/ContentScripts/features/developer-avator-openrank/index.tsx +++ b/src/pages/ContentScripts/features/developer-avator-openrank/index.tsx @@ -40,7 +40,6 @@ const createTooltip = (text: string): HTMLDivElement => { }; const init = async (): Promise => { - // 函数来处理鼠标悬停事件 const handleMouseOver = async (element: HTMLElement, event: MouseEvent) => { const developerName = getDeveloperName(element); if (!developerName) { @@ -50,19 +49,19 @@ const init = async (): Promise => { console.log('Developer Name:', developerName); - const openrank = await getData(developerName); + let openrank = await getData(developerName); if (openrank === null) { console.error('Rank data not found'); - return; + openrank = 'OpenRank data not found'; + } else { + openrank = `OpenRank ${openrank}`; } - const openrankText = `OpenRank ${openrank}`; let tooltip = document.getElementById('openrank-tooltip') as HTMLDivElement; - if (!tooltip) { - tooltip = createTooltip(openrankText); + tooltip = createTooltip(openrank); } else { - tooltip.innerText = openrankText; + tooltip.innerText = openrank; } const updateTooltipPosition = (e: MouseEvent) => { @@ -74,22 +73,18 @@ const init = async (): Promise => { let left = e.clientX + offsetX + window.scrollX; let top = e.clientY + offsetY + window.scrollY; - // Check if the tooltip goes beyond the right edge of the viewport if (left + tooltipWidth > window.innerWidth + window.scrollX) { left = e.clientX - tooltipWidth - offsetX + window.scrollX; } - // Check if the tooltip goes beyond the bottom edge of the viewport if (top + tooltipHeight > window.innerHeight + window.scrollY) { top = e.clientY - tooltipHeight - offsetY + window.scrollY; } - // Ensure tooltip doesn't go beyond the left edge of the viewport if (left < window.scrollX) { left = window.scrollX; } - // Ensure tooltip doesn't go beyond the top edge of the viewport if (top < window.scrollY) { top = window.scrollY; } @@ -123,10 +118,8 @@ const init = async (): Promise => { }); }; - // 初始绑定 bindEventListeners(); - // 观察 DOM 变化,动态为新添加的元素绑定事件 const observer = new MutationObserver(() => { bindEventListeners(); }); From abb9dbce68fafa4df71cc4483b34e56d751627b6 Mon Sep 17 00:00:00 2001 From: Tenth-crew Date: Tue, 16 Jul 2024 14:05:08 +0800 Subject: [PATCH 07/22] delete console.log --- .../features/developer-avator-openrank/index.tsx | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/pages/ContentScripts/features/developer-avator-openrank/index.tsx b/src/pages/ContentScripts/features/developer-avator-openrank/index.tsx index f352f966..91f7640b 100644 --- a/src/pages/ContentScripts/features/developer-avator-openrank/index.tsx +++ b/src/pages/ContentScripts/features/developer-avator-openrank/index.tsx @@ -47,11 +47,8 @@ const init = async (): Promise => { return; } - console.log('Developer Name:', developerName); - let openrank = await getData(developerName); if (openrank === null) { - console.error('Rank data not found'); openrank = 'OpenRank data not found'; } else { openrank = `OpenRank ${openrank}`; From 3576a19174f8d399f4cebb5e7ec73d49493b62b9 Mon Sep 17 00:00:00 2001 From: Tenth-crew Date: Wed, 17 Jul 2024 23:22:24 +0800 Subject: [PATCH 08/22] Introduce openrank information to the bottom of the hovercard --- .../developer-avator-openrank/index.tsx | 140 +++++------------- 1 file changed, 39 insertions(+), 101 deletions(-) diff --git a/src/pages/ContentScripts/features/developer-avator-openrank/index.tsx b/src/pages/ContentScripts/features/developer-avator-openrank/index.tsx index 91f7640b..f8ad7b78 100644 --- a/src/pages/ContentScripts/features/developer-avator-openrank/index.tsx +++ b/src/pages/ContentScripts/features/developer-avator-openrank/index.tsx @@ -5,15 +5,13 @@ import elementReady from 'element-ready'; const featureId = features.getFeatureID(import.meta.url); const getData = async (developerName: string): Promise => { - const jsonData = await getOpenrank(developerName); - if (!jsonData) return null; - - const keys = Object.keys(jsonData); - if (keys.length === 0) return null; - - keys.sort(); // 假设键是按时间顺序排列的 - const latestKey = keys[keys.length - 1]; - return jsonData[latestKey]; + const data = await getOpenrank(developerName); + if (data) { + const keys = Object.keys(data); + const latestKey = keys[keys.length - 1]; + return data[latestKey]; + } + return null; }; const getDeveloperName = (target: HTMLElement): string | null => { @@ -24,106 +22,46 @@ const getDeveloperName = (target: HTMLElement): string | null => { return matches ? matches[1] : null; }; -const createTooltip = (text: string): HTMLDivElement => { - const tooltip = document.createElement('div'); - tooltip.id = 'openrank-tooltip'; - tooltip.style.position = 'absolute'; - tooltip.style.backgroundColor = 'rgba(0, 0, 0, 0.7)'; - tooltip.style.color = 'white'; - tooltip.style.padding = '5px 10px'; - tooltip.style.borderRadius = '4px'; - tooltip.style.zIndex = '1000'; - tooltip.style.pointerEvents = 'none'; // 避免阻挡鼠标事件 - tooltip.innerText = text; - document.body.appendChild(tooltip); - return tooltip; -}; - const init = async (): Promise => { - const handleMouseOver = async (element: HTMLElement, event: MouseEvent) => { - const developerName = getDeveloperName(element); - if (!developerName) { - console.error('Developer name not found'); - return; - } - - let openrank = await getData(developerName); - if (openrank === null) { - openrank = 'OpenRank data not found'; - } else { - openrank = `OpenRank ${openrank}`; - } - - let tooltip = document.getElementById('openrank-tooltip') as HTMLDivElement; - if (!tooltip) { - tooltip = createTooltip(openrank); - } else { - tooltip.innerText = openrank; - } - - const updateTooltipPosition = (e: MouseEvent) => { - const tooltipWidth = tooltip.offsetWidth; - const tooltipHeight = tooltip.offsetHeight; - const offsetX = 15; - const offsetY = 15; - - let left = e.clientX + offsetX + window.scrollX; - let top = e.clientY + offsetY + window.scrollY; - - if (left + tooltipWidth > window.innerWidth + window.scrollX) { - left = e.clientX - tooltipWidth - offsetX + window.scrollX; + // 监听具有 data-hovercard-type="user" 属性的元素 + document.querySelectorAll('[data-hovercard-type="user"]').forEach((element) => { + element.addEventListener('mouseover', async () => { + console.log('mouseover', element); + + // 获取开发者名称 + const developerName = getDeveloperName(element as HTMLElement); + if (!developerName) { + console.error('Developer name not found'); + return; } - if (top + tooltipHeight > window.innerHeight + window.scrollY) { - top = e.clientY - tooltipHeight - offsetY + window.scrollY; - } + console.log('developerName', developerName); - if (left < window.scrollX) { - left = window.scrollX; + // 获取开发者的排名信息 + const openrank = await getData(developerName); + if (openrank === null) { + console.error('Rank data not found'); + return; } - if (top < window.scrollY) { - top = window.scrollY; - } - - tooltip.style.left = `${left}px`; - tooltip.style.top = `${top}px`; - }; - - updateTooltipPosition(event); - const mouseMoveHandler = updateTooltipPosition as EventListener; - element.addEventListener('mousemove', mouseMoveHandler); - - element.addEventListener( - 'mouseout', - () => { - if (tooltip) { - tooltip.remove(); - } - element.removeEventListener('mousemove', mouseMoveHandler); - }, - { once: true } - ); - }; - - const bindEventListeners = () => { - document.querySelectorAll('[data-hovercard-type="user"]').forEach((element) => { - if (!element.getAttribute('data-openrank-bound')) { - element.setAttribute('data-openrank-bound', 'true'); - element.addEventListener('mouseover', (event) => handleMouseOver(element as HTMLElement, event as MouseEvent)); + // 获取悬浮卡片容器 + const $popoverContainer = + 'body > div.logged-in.env-production.page-responsive > div.Popover.js-hovercard-content.position-absolute > div > div > div'; + const popover = await elementReady($popoverContainer, { stopOnDomReady: false }); + console.log('popover', popover); + + // 检查是否已经插入了 OpenRank 信息 + if (popover && !popover.querySelector('.openrank-info')) { + // 将 OpenRank 信息作为红色文本直接插入到悬浮卡片容器内容的前面 + const openRankDiv = document.createElement('div'); + openRankDiv.classList.add('openrank-info'); + openRankDiv.style.color = 'black'; + openRankDiv.textContent = ` OpenRank ${openrank} `; + popover.appendChild(openRankDiv); + } else { + console.error('Popover container not found or OpenRank info already inserted'); } }); - }; - - bindEventListeners(); - - const observer = new MutationObserver(() => { - bindEventListeners(); - }); - - observer.observe(document.body, { - childList: true, - subtree: true, }); }; From be224b1ae17425e4928a3a30e3f2051131990b3f Mon Sep 17 00:00:00 2001 From: Tenth-crew Date: Wed, 17 Jul 2024 23:25:49 +0800 Subject: [PATCH 09/22] delete some console.log information --- .../features/developer-avator-openrank/index.tsx | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/pages/ContentScripts/features/developer-avator-openrank/index.tsx b/src/pages/ContentScripts/features/developer-avator-openrank/index.tsx index f8ad7b78..28d6ad73 100644 --- a/src/pages/ContentScripts/features/developer-avator-openrank/index.tsx +++ b/src/pages/ContentScripts/features/developer-avator-openrank/index.tsx @@ -26,7 +26,6 @@ const init = async (): Promise => { // 监听具有 data-hovercard-type="user" 属性的元素 document.querySelectorAll('[data-hovercard-type="user"]').forEach((element) => { element.addEventListener('mouseover', async () => { - console.log('mouseover', element); // 获取开发者名称 const developerName = getDeveloperName(element as HTMLElement); @@ -35,8 +34,6 @@ const init = async (): Promise => { return; } - console.log('developerName', developerName); - // 获取开发者的排名信息 const openrank = await getData(developerName); if (openrank === null) { @@ -59,7 +56,7 @@ const init = async (): Promise => { openRankDiv.textContent = ` OpenRank ${openrank} `; popover.appendChild(openRankDiv); } else { - console.error('Popover container not found or OpenRank info already inserted'); + console.error('OpenRank info already inserted'); } }); }); From 867eee3cd5a61d19a3a3a28bfaf259f0724454d7 Mon Sep 17 00:00:00 2001 From: Tenth-crew Date: Wed, 17 Jul 2024 23:29:34 +0800 Subject: [PATCH 10/22] Remove debug information --- .../ContentScripts/features/developer-avator-openrank/index.tsx | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/pages/ContentScripts/features/developer-avator-openrank/index.tsx b/src/pages/ContentScripts/features/developer-avator-openrank/index.tsx index 28d6ad73..f35edd9e 100644 --- a/src/pages/ContentScripts/features/developer-avator-openrank/index.tsx +++ b/src/pages/ContentScripts/features/developer-avator-openrank/index.tsx @@ -26,7 +26,6 @@ const init = async (): Promise => { // 监听具有 data-hovercard-type="user" 属性的元素 document.querySelectorAll('[data-hovercard-type="user"]').forEach((element) => { element.addEventListener('mouseover', async () => { - // 获取开发者名称 const developerName = getDeveloperName(element as HTMLElement); if (!developerName) { @@ -45,7 +44,6 @@ const init = async (): Promise => { const $popoverContainer = 'body > div.logged-in.env-production.page-responsive > div.Popover.js-hovercard-content.position-absolute > div > div > div'; const popover = await elementReady($popoverContainer, { stopOnDomReady: false }); - console.log('popover', popover); // 检查是否已经插入了 OpenRank 信息 if (popover && !popover.querySelector('.openrank-info')) { From 2eab96f7684a104eff37c13722a5eb914f3a47e2 Mon Sep 17 00:00:00 2001 From: Tenth-crew Date: Thu, 18 Jul 2024 09:42:44 +0800 Subject: [PATCH 11/22] Modify the names of some functions and fields --- .../features/developer-avator-openrank/index.tsx | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/pages/ContentScripts/features/developer-avator-openrank/index.tsx b/src/pages/ContentScripts/features/developer-avator-openrank/index.tsx index f35edd9e..f4f6bd63 100644 --- a/src/pages/ContentScripts/features/developer-avator-openrank/index.tsx +++ b/src/pages/ContentScripts/features/developer-avator-openrank/index.tsx @@ -4,21 +4,21 @@ import elementReady from 'element-ready'; const featureId = features.getFeatureID(import.meta.url); -const getData = async (developerName: string): Promise => { +const getDeveloperLatestOpenrank = async (developerName: string): Promise => { const data = await getOpenrank(developerName); if (data) { - const keys = Object.keys(data); - const latestKey = keys[keys.length - 1]; - return data[latestKey]; + const values = Object.values(data) as string[]; + const latestValue = values[values.length - 1]; + return latestValue; } return null; }; const getDeveloperName = (target: HTMLElement): string | null => { - const hovercardUrl = target.getAttribute('data-hovercard-url'); - if (!hovercardUrl) return null; + const hovercardUrlAttribute = target.getAttribute('data-hovercard-url'); + if (!hovercardUrlAttribute) return null; - const matches = hovercardUrl.match(/\/users\/([^\/]+)\/hovercard/); + const matches = hovercardUrlAttribute.match(/\/users\/([^\/]+)\/hovercard/); return matches ? matches[1] : null; }; @@ -34,7 +34,7 @@ const init = async (): Promise => { } // 获取开发者的排名信息 - const openrank = await getData(developerName); + const openrank = await getDeveloperLatestOpenrank(developerName); if (openrank === null) { console.error('Rank data not found'); return; From 67ff6e8a1104f2e7996027511d15646ded2c2558 Mon Sep 17 00:00:00 2001 From: Tenth-crew Date: Thu, 18 Jul 2024 14:52:19 +0800 Subject: [PATCH 12/22] Add view.tsx and Adjust some details --- .../developer-hovercard-info/base64.ts | 5 ++ .../index.tsx | 37 ++++++------ .../developer-hovercard-info/view.tsx | 60 +++++++++++++++++++ src/pages/ContentScripts/index.ts | 2 +- 4 files changed, 86 insertions(+), 18 deletions(-) create mode 100644 src/pages/ContentScripts/features/developer-hovercard-info/base64.ts rename src/pages/ContentScripts/features/{developer-avator-openrank => developer-hovercard-info}/index.tsx (71%) create mode 100644 src/pages/ContentScripts/features/developer-hovercard-info/view.tsx diff --git a/src/pages/ContentScripts/features/developer-hovercard-info/base64.ts b/src/pages/ContentScripts/features/developer-hovercard-info/base64.ts new file mode 100644 index 00000000..7d2a7452 --- /dev/null +++ b/src/pages/ContentScripts/features/developer-hovercard-info/base64.ts @@ -0,0 +1,5 @@ +export const rocketLight = + 'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjxzdmcKICAgdD0iMTY2NDg5Mjg4OTU4NiIKICAgY2xhc3M9Imljb24iCiAgIHZpZXdCb3g9IjAgMCAxMDI0IDEwMjQiCiAgIHZlcnNpb249IjEuMSIKICAgcC1pZD0iNzQzMTAiCiAgIHdpZHRoPSIzMiIKICAgaGVpZ2h0PSIzMiIKICAgaWQ9InN2ZzYiCiAgIHNvZGlwb2RpOmRvY25hbWU9IueBq+eurSAoNSkucG5nIgogICBpbmtzY2FwZTp2ZXJzaW9uPSIxLjIgKGRjMmFlZGEsIDIwMjItMDUtMTUpIgogICB4bWxuczppbmtzY2FwZT0iaHR0cDovL3d3dy5pbmtzY2FwZS5vcmcvbmFtZXNwYWNlcy9pbmtzY2FwZSIKICAgeG1sbnM6c29kaXBvZGk9Imh0dHA6Ly9zb2RpcG9kaS5zb3VyY2Vmb3JnZS5uZXQvRFREL3NvZGlwb2RpLTAuZHRkIgogICB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciCiAgIHhtbG5zOnN2Zz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPgogIDxkZWZzCiAgICAgaWQ9ImRlZnMxMCIgLz4KICA8c29kaXBvZGk6bmFtZWR2aWV3CiAgICAgaWQ9Im5hbWVkdmlldzgiCiAgICAgcGFnZWNvbG9yPSIjZmZmZmZmIgogICAgIGJvcmRlcmNvbG9yPSIjMDAwMDAwIgogICAgIGJvcmRlcm9wYWNpdHk9IjAuMjUiCiAgICAgaW5rc2NhcGU6c2hvd3BhZ2VzaGFkb3c9IjIiCiAgICAgaW5rc2NhcGU6cGFnZW9wYWNpdHk9IjAuMCIKICAgICBpbmtzY2FwZTpwYWdlY2hlY2tlcmJvYXJkPSIwIgogICAgIGlua3NjYXBlOmRlc2tjb2xvcj0iI2QxZDFkMSIKICAgICBzaG93Z3JpZD0iZmFsc2UiCiAgICAgaW5rc2NhcGU6em9vbT0iNy4zNzUiCiAgICAgaW5rc2NhcGU6Y3g9IjE1LjkzMjIwMyIKICAgICBpbmtzY2FwZTpjeT0iMTQuOTE1MjU0IgogICAgIGlua3NjYXBlOndpbmRvdy13aWR0aD0iMTMxMyIKICAgICBpbmtzY2FwZTp3aW5kb3ctaGVpZ2h0PSI0NTgiCiAgICAgaW5rc2NhcGU6d2luZG93LXg9IjM0NiIKICAgICBpbmtzY2FwZTp3aW5kb3cteT0iMTI5MSIKICAgICBpbmtzY2FwZTp3aW5kb3ctbWF4aW1pemVkPSIwIgogICAgIGlua3NjYXBlOmN1cnJlbnQtbGF5ZXI9InN2ZzYiIC8+CiAgPHBhdGgKICAgICBkPSJtIDUwNy4zODUxMywzNzYuNTk3ODIgYyAtNDYuODk5OTMsMCAtODUuMDU3NjIsMzguMTU3NjkgLTg1LjA1NzYyLDg1LjA1NzYxIDAsNDYuODk5OTMgMzguMTU3NjksODUuMDU2NDkgODUuMDU3NjIsODUuMDU2NDkgNDYuODk5OTIsMCA4NS4wNTc2MSwtMzguMTU3NjggODUuMDU3NjEsLTg1LjA1NzYxIDAsLTQ2Ljg5OTkzIC0zOC4xNTc2OSwtODUuMDU2NDkgLTg1LjA1NzYxLC04NS4wNTY0OSB6IG0gMCwxMDYuMzIwODkgYyAtMTEuNzI3NTEsMCAtMjEuMjY0NDEsLTkuNTQyNTEgLTIxLjI2NDQxLC0yMS4yNjQ0IDAsLTExLjcyMTg5IDkuNTM2OSwtMjEuMjY0NCAyMS4yNjQ0MSwtMjEuMjY0NCAxMS43Mjc1MSwwIDIxLjI2NDQsOS41NDI1MSAyMS4yNjQ0LDIxLjI2NDQgMCwxMS43MjMwMSAtOS41MzY4OSwyMS4yNjQ0IC0yMS4yNjQ0LDIxLjI2NDQgeiIKICAgICBwLWlkPSI3NDMxMSIKICAgICBmaWxsPSIjNTc2MDZhIgogICAgIGlkPSJwYXRoMiIKICAgICBzdHlsZT0ic3Ryb2tlLXdpZHRoOjA7c3Ryb2tlLWRhc2hhcnJheTpub25lIiAvPgogIDxwYXRoCiAgICAgZD0ibSA3MzguMjk3MDUsNjIzLjUwOTQ3IHYgLTk1Ljk3MDI0IGMgMCwtODcuNjk0NDUgLTI1LjE0NzcyLC0xNTEuNjY0MTIgLTcyLjcyMjAzLC0yMjUuMjA2NjUgLTMxLjY1Nzc2LC00OC45MzU0NCAtNzIuMjM0MjMsLTkwLjc5NDM2IC0xMTkuMjAxNiwtMTI0LjA5NzYxIC0xMi41NjgyNCwtOC45MDg1OSAtMjUuNTIwODgsLTE3LjI5MjI5IC0zOC45ODgyOSwtMjQuOTEzOTQgLTEzLjQ2MTgsNy42MjE2NSAtMjYuNDE0NDQsMTYuMDA1MzUgLTM4Ljk4MjY4LDI0LjkxMzk0IC00Ni45NjczNywzMy4zMDMyNSAtODcuNTQzODQsNzUuMTYyMTcgLTExOS4yMDE2LDEyNC4wOTc2MSAtNDcuNTc0MzEsNzMuNTQyNTMgLTcyLjcyMjAzLDEzNy41MTIyIC03Mi43MjIwMywyMjUuMjA2NjUgdiA5NS45NzAyNCBsIC00MS45ODM2OCw4NC41MTY5OCB2IDk3Ljg1OTY0IGggNTQ1Ljc4NTU5IHYgLTk3Ljg1OTY0IHogbSAtMjEuODA5NTMsMTE4LjU4MzQxIGggLTQxOC4yMDAzIHYgLTcuNjUxOTkgTCAzNDAuMjcwOSw2NDkuOTIzOTEgViA1MjcuNTM5MjMgYyAwLC03NS4zNzAxMSAyMS42MTE3MSwtMTI3LjM1NzEzIDYyLjQ4OTQxLC0xOTAuNTU4MDEgMjcuNzA3LC00Mi44MjQ0MSA2My4zMDk5LC03OS4zNjY5NCAxMDQuNjIzNjksLTEwOC4xOTU2NyA0MS4zMTM4LDI4LjgyODczIDc2LjkyMjMxLDY1LjM3MTI2IDEwNC42MjkzMiwxMDguMTk1NjcgNDAuODc3NjksNjMuMjAwODggNjIuNDg5NCwxMTUuMTg5MDIgNjIuNDg5NCwxOTAuNTU4MDEgdiAxMjIuMzgzNTYgbCA0MS45ODM2OCw4NC41MTY5OCB2IDcuNjUzMTEgeiBtIC0yMDkuMDk3OSwxMjcuMzg0MTEgYyAtMjUuMjA1MDQsLTEyLjg3NTA5IC00MS4zNjU0OSwtMjguNDU2NyAtNjAuNjAwMDEsLTQ2LjMyODk1IGggLTkwLjY5NTQ0IGMgMzkuOTc0MDIsNDYuNDkxOTIgODEuMDQzOTEsODQuMzgyMSAxMzcuODgwODYsMTEwLjczNDcyIGwgMTMuNDE0NTksNi4yMTg5MyAxMy40MTQ1OSwtNi4yMTg5MyBjIDU2LjgzMTM0LC0yNi4zNTE0OSA5Ny44OTU2MSwtNjQuMjM5NDMgMTM3Ljg3MDc1LC0xMTAuNzM0NzIgaCAtOTAuNjg1MzMgYyAtMTkuMjMzMzksMTcuODcxMTMgLTM1LjM5NDk2LDMzLjQ1Mzg2IC02MC42MDAwMSw0Ni4zMjg5NSB6IgogICAgIHAtaWQ9Ijc0MzEyIgogICAgIGZpbGw9IiM1NzYwNmEiCiAgICAgaWQ9InBhdGg0IgogICAgIHN0eWxlPSJzdHJva2Utd2lkdGg6MDtzdHJva2UtZGFzaGFycmF5Om5vbmUiIC8+Cjwvc3ZnPgo='; + +export const rocketDark = + 'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjxzdmcKICAgdD0iMTY2NDg5Mjg4OTU4NiIKICAgY2xhc3M9Imljb24iCiAgIHZpZXdCb3g9IjAgMCAxMDI0IDEwMjQiCiAgIHZlcnNpb249IjEuMSIKICAgcC1pZD0iNzQzMTAiCiAgIHdpZHRoPSIzMiIKICAgaGVpZ2h0PSIzMiIKICAgaWQ9InN2ZzYiCiAgIHNvZGlwb2RpOmRvY25hbWU9IueBq+eurSAoNSlkYXJrLnBuZyIKICAgaW5rc2NhcGU6dmVyc2lvbj0iMS4yIChkYzJhZWRhLCAyMDIyLTA1LTE1KSIKICAgeG1sbnM6aW5rc2NhcGU9Imh0dHA6Ly93d3cuaW5rc2NhcGUub3JnL25hbWVzcGFjZXMvaW5rc2NhcGUiCiAgIHhtbG5zOnNvZGlwb2RpPSJodHRwOi8vc29kaXBvZGkuc291cmNlZm9yZ2UubmV0L0RURC9zb2RpcG9kaS0wLmR0ZCIKICAgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIgogICB4bWxuczpzdmc9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KICA8ZGVmcwogICAgIGlkPSJkZWZzMTAiIC8+CiAgPHNvZGlwb2RpOm5hbWVkdmlldwogICAgIGlkPSJuYW1lZHZpZXc4IgogICAgIHBhZ2Vjb2xvcj0iI2ZmZmZmZiIKICAgICBib3JkZXJjb2xvcj0iIzAwMDAwMCIKICAgICBib3JkZXJvcGFjaXR5PSIwLjI1IgogICAgIGlua3NjYXBlOnNob3dwYWdlc2hhZG93PSIyIgogICAgIGlua3NjYXBlOnBhZ2VvcGFjaXR5PSIwLjAiCiAgICAgaW5rc2NhcGU6cGFnZWNoZWNrZXJib2FyZD0iMCIKICAgICBpbmtzY2FwZTpkZXNrY29sb3I9IiNkMWQxZDEiCiAgICAgc2hvd2dyaWQ9ImZhbHNlIgogICAgIGlua3NjYXBlOnpvb209IjcuMzc1IgogICAgIGlua3NjYXBlOmN4PSIxNS45MzIyMDMiCiAgICAgaW5rc2NhcGU6Y3k9IjE2IgogICAgIGlua3NjYXBlOndpbmRvdy13aWR0aD0iMTMxMyIKICAgICBpbmtzY2FwZTp3aW5kb3ctaGVpZ2h0PSI0NTgiCiAgICAgaW5rc2NhcGU6d2luZG93LXg9IjM1NyIKICAgICBpbmtzY2FwZTp3aW5kb3cteT0iMTM3NSIKICAgICBpbmtzY2FwZTp3aW5kb3ctbWF4aW1pemVkPSIwIgogICAgIGlua3NjYXBlOmN1cnJlbnQtbGF5ZXI9InN2ZzYiIC8+CiAgPHBhdGgKICAgICBkPSJNNTExLjk5OCAzNjAuNjQ5Yy00MS43MjcgMC03NS42NzYgMzMuOTQ5LTc1LjY3NiA3NS42NzZTNDcwLjI3MSA1MTIgNTExLjk5OCA1MTJzNzUuNjc2LTMzLjk0OSA3NS42NzYtNzUuNjc2LTMzLjk0OS03NS42NzUtNzUuNjc2LTc1LjY3NXogbTAgOTQuNTk0Yy0xMC40MzQgMC0xOC45MTktOC40OS0xOC45MTktMTguOTE5czguNDg1LTE4LjkxOSAxOC45MTktMTguOTE5YzEwLjQzNCAwIDE4LjkxOSA4LjQ5IDE4LjkxOSAxOC45MTkgMCAxMC40My04LjQ4NSAxOC45MTktMTguOTE5IDE4LjkxOXoiCiAgICAgcC1pZD0iNzQzMTEiCiAgICAgZmlsbD0iIzU3NjA2YSIKICAgICBpZD0icGF0aDIiCiAgICAgc3R5bGU9ImZpbGw6IzhiOTQ5ZTtmaWxsLW9wYWNpdHk6MSIgLz4KICA8cGF0aAogICAgIGQ9Ik03MTcuNDQxIDU4MC4zMjd2LTg1LjM4NWMwLTc4LjAyMi0yMi4zNzQtMTM0LjkzNi02NC43MDEtMjAwLjM2Ny0yOC4xNjYtNDMuNTM4LTY0LjI2Ny04MC43OC0xMDYuMDU0LTExMC40MS0xMS4xODItNy45MjYtMjIuNzA2LTE1LjM4NS0zNC42ODgtMjIuMTY2LTExLjk3NyA2Ljc4MS0yMy41MDEgMTQuMjQtMzQuNjgzIDIyLjE2Ni00MS43ODcgMjkuNjMtNzcuODg4IDY2Ljg3Mi0xMDYuMDU0IDExMC40MS00Mi4zMjcgNjUuNDMxLTY0LjcwMSAxMjIuMzQ1LTY0LjcwMSAyMDAuMzY3djg1LjM4NWwtMzcuMzUzIDc1LjE5NXY4Ny4wNjZoNDg1LjU4N3YtODcuMDY2bC0zNy4zNTMtNzUuMTk1eiBtLTE5LjQwNCAxMDUuNTA0SDMyNS45NjN2LTYuODA4bDM3LjM1My03NS4xOTVWNDk0Ljk0MmMwLTY3LjA1NyAxOS4yMjgtMTEzLjMxIDU1LjU5Ny0xNjkuNTQgMjQuNjUxLTM4LjEwMSA1Ni4zMjctNzAuNjEzIDkzLjA4NC05Ni4yNjIgMzYuNzU3IDI1LjY0OSA2OC40MzggNTguMTYxIDkzLjA4OSA5Ni4yNjIgMzYuMzY5IDU2LjIzIDU1LjU5NyAxMDIuNDg0IDU1LjU5NyAxNjkuNTR2MTA4Ljg4NWwzNy4zNTMgNzUuMTk1djYuODA5ek01MTIuMDAyIDc5OS4xNjVjLTIyLjQyNS0xMS40NTUtMzYuODAzLTI1LjMxOC01My45MTYtNDEuMjE5aC04MC42OTJjMzUuNTY1IDQxLjM2NCA3Mi4xMDUgNzUuMDc1IDEyMi42NzMgOTguNTIxTDUxMi4wMDIgODYybDExLjkzNS01LjUzM2M1MC41NjMtMjMuNDQ1IDg3LjA5OC01Ny4xNTQgMTIyLjY2NC05OC41MjFoLTgwLjY4M2MtMTcuMTEyIDE1LjktMzEuNDkxIDI5Ljc2NC01My45MTYgNDEuMjE5eiIKICAgICBwLWlkPSI3NDMxMiIKICAgICBmaWxsPSIjNTc2MDZhIgogICAgIGlkPSJwYXRoNCIKICAgICBzdHlsZT0iZmlsbDojOGI5NDllO2ZpbGwtb3BhY2l0eToxIiAvPgo8L3N2Zz4K'; diff --git a/src/pages/ContentScripts/features/developer-avator-openrank/index.tsx b/src/pages/ContentScripts/features/developer-hovercard-info/index.tsx similarity index 71% rename from src/pages/ContentScripts/features/developer-avator-openrank/index.tsx rename to src/pages/ContentScripts/features/developer-hovercard-info/index.tsx index f4f6bd63..30bab3a0 100644 --- a/src/pages/ContentScripts/features/developer-avator-openrank/index.tsx +++ b/src/pages/ContentScripts/features/developer-hovercard-info/index.tsx @@ -1,6 +1,7 @@ import features from '../../../../feature-manager'; import { getOpenrank } from '../../../../api/developer'; import elementReady from 'element-ready'; +import { renderOpenRank } from './view'; const featureId = features.getFeatureID(import.meta.url); @@ -23,38 +24,40 @@ const getDeveloperName = (target: HTMLElement): string | null => { }; const init = async (): Promise => { - // 监听具有 data-hovercard-type="user" 属性的元素 + // Listen for elements with data-hovercard-type="user" attribute document.querySelectorAll('[data-hovercard-type="user"]').forEach((element) => { element.addEventListener('mouseover', async () => { - // 获取开发者名称 const developerName = getDeveloperName(element as HTMLElement); if (!developerName) { console.error('Developer name not found'); return; } - // 获取开发者的排名信息 + // Get the floating card container + const $popoverContainer = + 'body > div.logged-in.env-production.page-responsive > div.Popover.js-hovercard-content.position-absolute > div > div > div'; + const popover = await elementReady($popoverContainer, { stopOnDomReady: false }); + + const openRankDiv = popover?.querySelector('.openrank-info-container'); + if (openRankDiv) { + const existingDeveloperName = openRankDiv.getAttribute('data-developer-name'); + if (existingDeveloperName === developerName) { + return; + } else { + openRankDiv.remove(); + } + } + const openrank = await getDeveloperLatestOpenrank(developerName); if (openrank === null) { console.error('Rank data not found'); return; } - // 获取悬浮卡片容器 - const $popoverContainer = - 'body > div.logged-in.env-production.page-responsive > div.Popover.js-hovercard-content.position-absolute > div > div > div'; - const popover = await elementReady($popoverContainer, { stopOnDomReady: false }); - - // 检查是否已经插入了 OpenRank 信息 - if (popover && !popover.querySelector('.openrank-info')) { - // 将 OpenRank 信息作为红色文本直接插入到悬浮卡片容器内容的前面 - const openRankDiv = document.createElement('div'); - openRankDiv.classList.add('openrank-info'); - openRankDiv.style.color = 'black'; - openRankDiv.textContent = ` OpenRank ${openrank} `; - popover.appendChild(openRankDiv); + if (popover) { + renderOpenRank(popover, developerName, openrank); } else { - console.error('OpenRank info already inserted'); + console.error('Popover container not found'); } }); }); diff --git a/src/pages/ContentScripts/features/developer-hovercard-info/view.tsx b/src/pages/ContentScripts/features/developer-hovercard-info/view.tsx new file mode 100644 index 00000000..16ff418f --- /dev/null +++ b/src/pages/ContentScripts/features/developer-hovercard-info/view.tsx @@ -0,0 +1,60 @@ +import React, { useState, useEffect } from 'react'; +import ReactDOM from 'react-dom'; +import getGithubTheme from '../../../../helpers/get-github-theme'; +import optionsStorage, { HypercrxOptions, defaults } from '../../../../options-storage'; +import { useTranslation } from 'react-i18next'; +import '../../../../helpers/i18n'; +import { numberWithCommas } from '../../../../helpers/formatter'; +import { rocketLight, rocketDark } from './base64'; + +interface OpenRankProps { + developerName: string; + openrank: string; +} + +const OpenRankView: React.FC = ({ developerName, openrank }) => { + const [theme, setTheme] = useState<'light' | 'dark'>(getGithubTheme() as 'light' | 'dark'); + const [options, setOptions] = useState(defaults); + const { t, i18n } = useTranslation(); + useEffect(() => { + (async function () { + setOptions(await optionsStorage.getAll()); + i18n.changeLanguage(options.locale); + })(); + }, [options.locale]); + + useEffect(() => { + const handleThemeChange = () => { + const newTheme = getGithubTheme() as 'light' | 'dark'; + setTheme(newTheme); + }; + + // Listen for theme change events + window.addEventListener('themeChange', handleThemeChange); + + return () => { + window.removeEventListener('themeChange', handleThemeChange); + }; + }, []); + + return ( +
+
+ + OpenRank {openrank} +
+
+ ); +}; + +export const renderOpenRank = (container: HTMLElement, developerName: string, openrank: string) => { + const openRankContainer = document.createElement('div'); + container.appendChild(openRankContainer); + ReactDOM.render(, openRankContainer); +}; diff --git a/src/pages/ContentScripts/index.ts b/src/pages/ContentScripts/index.ts index 3df37e8e..11a5dc6f 100644 --- a/src/pages/ContentScripts/index.ts +++ b/src/pages/ContentScripts/index.ts @@ -13,4 +13,4 @@ import './features/repo-networks'; import './features/developer-networks'; import './features/oss-gpt'; import './features/repo-activity-racing-bar'; -import './features/developer-avator-openrank'; +import './features/developer-hovercard-info'; From 4a2dadb996c3b0c6909b99e2f73782dea37d9f75 Mon Sep 17 00:00:00 2001 From: Tenth-crew Date: Thu, 18 Jul 2024 15:39:02 +0800 Subject: [PATCH 13/22] remove console.error --- .../features/developer-hovercard-info/index.tsx | 12 ++---------- .../features/developer-hovercard-info/view.tsx | 2 +- 2 files changed, 3 insertions(+), 11 deletions(-) diff --git a/src/pages/ContentScripts/features/developer-hovercard-info/index.tsx b/src/pages/ContentScripts/features/developer-hovercard-info/index.tsx index 30bab3a0..cb5fec97 100644 --- a/src/pages/ContentScripts/features/developer-hovercard-info/index.tsx +++ b/src/pages/ContentScripts/features/developer-hovercard-info/index.tsx @@ -27,11 +27,7 @@ const init = async (): Promise => { // Listen for elements with data-hovercard-type="user" attribute document.querySelectorAll('[data-hovercard-type="user"]').forEach((element) => { element.addEventListener('mouseover', async () => { - const developerName = getDeveloperName(element as HTMLElement); - if (!developerName) { - console.error('Developer name not found'); - return; - } + const developerName = getDeveloperName(element as HTMLElement) as string; // Get the floating card container const $popoverContainer = @@ -48,11 +44,7 @@ const init = async (): Promise => { } } - const openrank = await getDeveloperLatestOpenrank(developerName); - if (openrank === null) { - console.error('Rank data not found'); - return; - } + const openrank = (await getDeveloperLatestOpenrank(developerName)) as string; if (popover) { renderOpenRank(popover, developerName, openrank); diff --git a/src/pages/ContentScripts/features/developer-hovercard-info/view.tsx b/src/pages/ContentScripts/features/developer-hovercard-info/view.tsx index 16ff418f..8b4bffe1 100644 --- a/src/pages/ContentScripts/features/developer-hovercard-info/view.tsx +++ b/src/pages/ContentScripts/features/developer-hovercard-info/view.tsx @@ -43,7 +43,7 @@ const OpenRankView: React.FC = ({ developerName, openrank }) => { From dcd16a11cc44aacf82820cb535fb2e6e55c3efb1 Mon Sep 17 00:00:00 2001 From: Tenth-crew Date: Thu, 18 Jul 2024 16:03:38 +0800 Subject: [PATCH 14/22] Adjust openrank icon position --- .../ContentScripts/features/developer-hovercard-info/view.tsx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/pages/ContentScripts/features/developer-hovercard-info/view.tsx b/src/pages/ContentScripts/features/developer-hovercard-info/view.tsx index 8b4bffe1..e09e116d 100644 --- a/src/pages/ContentScripts/features/developer-hovercard-info/view.tsx +++ b/src/pages/ContentScripts/features/developer-hovercard-info/view.tsx @@ -4,7 +4,6 @@ import getGithubTheme from '../../../../helpers/get-github-theme'; import optionsStorage, { HypercrxOptions, defaults } from '../../../../options-storage'; import { useTranslation } from 'react-i18next'; import '../../../../helpers/i18n'; -import { numberWithCommas } from '../../../../helpers/formatter'; import { rocketLight, rocketDark } from './base64'; interface OpenRankProps { @@ -43,7 +42,7 @@ const OpenRankView: React.FC = ({ developerName, openrank }) => { From 9f7fc18c07c3dd7fad67f6013827bb234d71bfae Mon Sep 17 00:00:00 2001 From: Tenth-crew Date: Thu, 18 Jul 2024 16:28:18 +0800 Subject: [PATCH 15/22] Solved the problem of mismatch between OpenRank information and people --- .../developer-hovercard-info/index.tsx | 22 ++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/src/pages/ContentScripts/features/developer-hovercard-info/index.tsx b/src/pages/ContentScripts/features/developer-hovercard-info/index.tsx index cb5fec97..0892dfde 100644 --- a/src/pages/ContentScripts/features/developer-hovercard-info/index.tsx +++ b/src/pages/ContentScripts/features/developer-hovercard-info/index.tsx @@ -24,11 +24,15 @@ const getDeveloperName = (target: HTMLElement): string | null => { }; const init = async (): Promise => { - // Listen for elements with data-hovercard-type="user" attribute - document.querySelectorAll('[data-hovercard-type="user"]').forEach((element) => { + const hovercardSelector = '[data-hovercard-type="user"]'; + + document.querySelectorAll(hovercardSelector).forEach((element) => { element.addEventListener('mouseover', async () => { const developerName = getDeveloperName(element as HTMLElement) as string; + // Create a unique identifier for the popover + const popoverId = `popover-${developerName}`; + // Get the floating card container const $popoverContainer = 'body > div.logged-in.env-production.page-responsive > div.Popover.js-hovercard-content.position-absolute > div > div > div'; @@ -44,12 +48,20 @@ const init = async (): Promise => { } } + // Set the popover's unique identifier + popover?.setAttribute('data-popover-id', popoverId); + const openrank = (await getDeveloperLatestOpenrank(developerName)) as string; + if (!openrank) { + return; + } + if (popover) { - renderOpenRank(popover, developerName, openrank); - } else { - console.error('Popover container not found'); + // Check if the popover is still associated with the correct developer + if (popover.getAttribute('data-popover-id') === popoverId) { + renderOpenRank(popover, developerName, openrank); + } } }); }); From 1c9e98e4b72686b34b28fee472b1ec41a7a4acac Mon Sep 17 00:00:00 2001 From: Tenth-crew Date: Thu, 18 Jul 2024 16:40:40 +0800 Subject: [PATCH 16/22] Fixed the bug that OpenRank information was added multiple times --- .../features/developer-hovercard-info/index.tsx | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/pages/ContentScripts/features/developer-hovercard-info/index.tsx b/src/pages/ContentScripts/features/developer-hovercard-info/index.tsx index 0892dfde..cabaea2e 100644 --- a/src/pages/ContentScripts/features/developer-hovercard-info/index.tsx +++ b/src/pages/ContentScripts/features/developer-hovercard-info/index.tsx @@ -25,9 +25,15 @@ const getDeveloperName = (target: HTMLElement): string | null => { const init = async (): Promise => { const hovercardSelector = '[data-hovercard-type="user"]'; - document.querySelectorAll(hovercardSelector).forEach((element) => { + let isProcessing = false; + element.addEventListener('mouseover', async () => { + if (isProcessing) { + return; + } + isProcessing = true; + const developerName = getDeveloperName(element as HTMLElement) as string; // Create a unique identifier for the popover @@ -63,6 +69,8 @@ const init = async (): Promise => { renderOpenRank(popover, developerName, openrank); } } + + isProcessing = false; }); }); }; From 45759760466a58724d2b63c6d6a2d3845b55f338 Mon Sep 17 00:00:00 2001 From: Tenth-crew Date: Thu, 18 Jul 2024 16:48:33 +0800 Subject: [PATCH 17/22] Adjust the display position of OpenRank --- .../ContentScripts/features/developer-hovercard-info/view.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pages/ContentScripts/features/developer-hovercard-info/view.tsx b/src/pages/ContentScripts/features/developer-hovercard-info/view.tsx index e09e116d..f614b7b8 100644 --- a/src/pages/ContentScripts/features/developer-hovercard-info/view.tsx +++ b/src/pages/ContentScripts/features/developer-hovercard-info/view.tsx @@ -42,11 +42,11 @@ const OpenRankView: React.FC = ({ developerName, openrank }) => { - OpenRank {openrank} + OpenRank {openrank} ); From a2c134950162c18dc2df1107332147d2711a3351 Mon Sep 17 00:00:00 2001 From: Tenth-crew Date: Thu, 18 Jul 2024 16:54:11 +0800 Subject: [PATCH 18/22] Improve the comment --- .../ContentScripts/features/developer-hovercard-info/index.tsx | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/pages/ContentScripts/features/developer-hovercard-info/index.tsx b/src/pages/ContentScripts/features/developer-hovercard-info/index.tsx index cabaea2e..352e2c84 100644 --- a/src/pages/ContentScripts/features/developer-hovercard-info/index.tsx +++ b/src/pages/ContentScripts/features/developer-hovercard-info/index.tsx @@ -26,6 +26,7 @@ const getDeveloperName = (target: HTMLElement): string | null => { const init = async (): Promise => { const hovercardSelector = '[data-hovercard-type="user"]'; document.querySelectorAll(hovercardSelector).forEach((element) => { + // isProcessing is used to Prevent OpenRank from adding duplicates let isProcessing = false; element.addEventListener('mouseover', async () => { @@ -55,6 +56,7 @@ const init = async (): Promise => { } // Set the popover's unique identifier + // make the current OpenRank information and person match popover?.setAttribute('data-popover-id', popoverId); const openrank = (await getDeveloperLatestOpenrank(developerName)) as string; @@ -70,6 +72,7 @@ const init = async (): Promise => { } } + // Regardless of whether the current event is being processed, check and update the openrank information if necessary. isProcessing = false; }); }); From b49de0574bf1d234198d4e043c3213fcfdd1c073 Mon Sep 17 00:00:00 2001 From: Tenth-crew Date: Sun, 21 Jul 2024 11:14:03 +0800 Subject: [PATCH 19/22] Introducing the renderTo function --- .../developer-hovercard-info/index.tsx | 30 ++++++++------ .../developer-hovercard-info/view.tsx | 41 ++++--------------- 2 files changed, 26 insertions(+), 45 deletions(-) diff --git a/src/pages/ContentScripts/features/developer-hovercard-info/index.tsx b/src/pages/ContentScripts/features/developer-hovercard-info/index.tsx index 352e2c84..20df6306 100644 --- a/src/pages/ContentScripts/features/developer-hovercard-info/index.tsx +++ b/src/pages/ContentScripts/features/developer-hovercard-info/index.tsx @@ -1,7 +1,9 @@ import features from '../../../../feature-manager'; import { getOpenrank } from '../../../../api/developer'; import elementReady from 'element-ready'; -import { renderOpenRank } from './view'; +import React from 'react'; +import ReactDOM from 'react-dom'; +import View from './view'; // 引入 OpenRankView 组件 const featureId = features.getFeatureID(import.meta.url); @@ -23,6 +25,12 @@ const getDeveloperName = (target: HTMLElement): string | null => { return matches ? matches[1] : null; }; +const renderTo = (container: HTMLElement, developerName: string, openrank: string) => { + const openRankContainer = document.createElement('div'); + container.appendChild(openRankContainer); + ReactDOM.render(, openRankContainer); +}; + const init = async (): Promise => { const hovercardSelector = '[data-hovercard-type="user"]'; document.querySelectorAll(hovercardSelector).forEach((element) => { @@ -46,30 +54,26 @@ const init = async (): Promise => { const popover = await elementReady($popoverContainer, { stopOnDomReady: false }); const openRankDiv = popover?.querySelector('.openrank-info-container'); - if (openRankDiv) { - const existingDeveloperName = openRankDiv.getAttribute('data-developer-name'); - if (existingDeveloperName === developerName) { - return; - } else { - openRankDiv.remove(); - } + const existingDeveloperName = openRankDiv?.getAttribute('data-developer-name'); + if (existingDeveloperName === developerName) { + return; } + openRankDiv?.remove(); // Set the popover's unique identifier // make the current OpenRank information and person match popover?.setAttribute('data-popover-id', popoverId); - const openrank = (await getDeveloperLatestOpenrank(developerName)) as string; + const openrank = await getDeveloperLatestOpenrank(developerName); if (!openrank) { + isProcessing = false; return; } - if (popover) { + if (popover && popover.getAttribute('data-popover-id') === popoverId) { // Check if the popover is still associated with the correct developer - if (popover.getAttribute('data-popover-id') === popoverId) { - renderOpenRank(popover, developerName, openrank); - } + renderTo(popover, developerName, openrank); // 调用 renderTo 函数 } // Regardless of whether the current event is being processed, check and update the openrank information if necessary. diff --git a/src/pages/ContentScripts/features/developer-hovercard-info/view.tsx b/src/pages/ContentScripts/features/developer-hovercard-info/view.tsx index f614b7b8..def2c6e4 100644 --- a/src/pages/ContentScripts/features/developer-hovercard-info/view.tsx +++ b/src/pages/ContentScripts/features/developer-hovercard-info/view.tsx @@ -1,8 +1,6 @@ import React, { useState, useEffect } from 'react'; import ReactDOM from 'react-dom'; import getGithubTheme from '../../../../helpers/get-github-theme'; -import optionsStorage, { HypercrxOptions, defaults } from '../../../../options-storage'; -import { useTranslation } from 'react-i18next'; import '../../../../helpers/i18n'; import { rocketLight, rocketDark } from './base64'; @@ -11,34 +9,15 @@ interface OpenRankProps { openrank: string; } -const OpenRankView: React.FC = ({ developerName, openrank }) => { - const [theme, setTheme] = useState<'light' | 'dark'>(getGithubTheme() as 'light' | 'dark'); - const [options, setOptions] = useState(defaults); - const { t, i18n } = useTranslation(); - useEffect(() => { - (async function () { - setOptions(await optionsStorage.getAll()); - i18n.changeLanguage(options.locale); - })(); - }, [options.locale]); +const View: React.FC = ({ developerName, openrank }) => { + const theme = getGithubTheme() as 'light' | 'dark'; - useEffect(() => { - const handleThemeChange = () => { - const newTheme = getGithubTheme() as 'light' | 'dark'; - setTheme(newTheme); - }; - - // Listen for theme change events - window.addEventListener('themeChange', handleThemeChange); - - return () => { - window.removeEventListener('themeChange', handleThemeChange); - }; - }, []); + const textColor = theme === 'light' ? '#717981' : '#878f98'; + const fontSize = '13px'; return (
-
+
= ({ developerName, openrank }) => { src={theme === 'light' ? rocketLight : rocketDark} alt="" /> - OpenRank {openrank} + + OpenRank {openrank} +
); }; -export const renderOpenRank = (container: HTMLElement, developerName: string, openrank: string) => { - const openRankContainer = document.createElement('div'); - container.appendChild(openRankContainer); - ReactDOM.render(, openRankContainer); -}; +export default View; From 9269528d6bed39ec37f9cb6756895e1bfd9223d3 Mon Sep 17 00:00:00 2001 From: Tenth-crew Date: Sun, 21 Jul 2024 11:32:02 +0800 Subject: [PATCH 20/22] deal yarn.lock merge conflict --- yarn.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/yarn.lock b/yarn.lock index 89971dc2..e1dd5f88 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2502,7 +2502,7 @@ cross-env@^7.0.3: cross-fetch@4.0.0: version "4.0.0" - resolved "https://registry.npmmirror.com/cross-fetch/-/cross-fetch-4.0.0.tgz#f037aef1580bb3a1a35164ea2a848ba81b445983" + resolved "https://registry.yarnpkg.com/cross-fetch/-/cross-fetch-4.0.0.tgz#f037aef1580bb3a1a35164ea2a848ba81b445983" integrity sha512-e4a5N8lVvuLgAWgnCrLr2PP0YyDOTHa9H/Rj54dirp61qXnNq46m82bRhNqIA5VccJtWBvPTFRV3TtvHUKPB1g== dependencies: node-fetch "^2.6.12" From b7ba00574729f003872f40f9d6847992d08026a2 Mon Sep 17 00:00:00 2001 From: Tenth-crew Date: Sun, 21 Jul 2024 12:02:50 +0800 Subject: [PATCH 21/22] deal yarn.lock conflict --- yarn.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/yarn.lock b/yarn.lock index e1dd5f88..baf05595 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3445,7 +3445,7 @@ html-minifier-terser@^6.0.2: html-parse-stringify@^3.0.1: version "3.0.1" - resolved "https://registry.npmmirror.com/html-parse-stringify/-/html-parse-stringify-3.0.1.tgz#dfc1017347ce9f77c8141a507f233040c59c55d2" + resolved "https://registry.yarnpkg.com/html-parse-stringify/-/html-parse-stringify-3.0.1.tgz#dfc1017347ce9f77c8141a507f233040c59c55d2" integrity sha512-KknJ50kTInJ7qIScF3jeaFRpMpE8/lfiTdzf/twXyPBLAGrLRTmkz3AdTnKeh40X8k9L2fdYwEp/42WGXIRGcg== dependencies: void-elements "3.1.0" From 5a1804ef7ba2b2cc5d8979c67fa5907d992e9d30 Mon Sep 17 00:00:00 2001 From: Tenth-crew Date: Sun, 21 Jul 2024 12:39:44 +0800 Subject: [PATCH 22/22] remove chinese comment --- .../features/developer-hovercard-info/index.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pages/ContentScripts/features/developer-hovercard-info/index.tsx b/src/pages/ContentScripts/features/developer-hovercard-info/index.tsx index 20df6306..cde898cf 100644 --- a/src/pages/ContentScripts/features/developer-hovercard-info/index.tsx +++ b/src/pages/ContentScripts/features/developer-hovercard-info/index.tsx @@ -3,7 +3,7 @@ import { getOpenrank } from '../../../../api/developer'; import elementReady from 'element-ready'; import React from 'react'; import ReactDOM from 'react-dom'; -import View from './view'; // 引入 OpenRankView 组件 +import View from './view'; const featureId = features.getFeatureID(import.meta.url); @@ -73,7 +73,7 @@ const init = async (): Promise => { if (popover && popover.getAttribute('data-popover-id') === popoverId) { // Check if the popover is still associated with the correct developer - renderTo(popover, developerName, openrank); // 调用 renderTo 函数 + renderTo(popover, developerName, openrank); } // Regardless of whether the current event is being processed, check and update the openrank information if necessary.