Skip to content

feat: 添加 ContributorsGrid 组件以显示 GitHub 贡献者#16

Merged
xingwangzhe merged 7 commits into
SeaLantern-Studio:mainfrom
ChouChiu:main
Feb 26, 2026
Merged

feat: 添加 ContributorsGrid 组件以显示 GitHub 贡献者#16
xingwangzhe merged 7 commits into
SeaLantern-Studio:mainfrom
ChouChiu:main

Conversation

@ChouChiu
Copy link
Copy Markdown
Contributor

@ChouChiu ChouChiu commented Feb 25, 2026

看原本的贡献者卡片没了,就vibe了一个,有错误请指正。
原本想用 contrib.rocks 的但是太糊了

由 Sourcery 提供的摘要

向 VitePress 主题中新增一个可复用的贡献者网格组件,并将其集成到贡献者页面中。

新功能:

  • 引入一个 ContributorsGrid Vue 组件,用于获取并在自适应网格中展示 GitHub 仓库的贡献者。

文档:

  • 在所有本地化的贡献者页面中,用新的 ContributorsGrid 组件替换外部贡献者图片嵌入,并对指向完整 GitHub 贡献者图的链接进行说明和澄清。
Original summary in English

Summary by Sourcery

Add a reusable contributors grid component to the VitePress theme and integrate it into the contributor pages.

New Features:

  • Introduce a ContributorsGrid Vue component that fetches and displays GitHub repository contributors in a responsive grid.

Documentation:

  • Replace the external contributors image embed with the new ContributorsGrid component across all localized contributor pages and clarify the link to the full GitHub contributors graph.

@sourcery-ai
Copy link
Copy Markdown
Contributor

sourcery-ai Bot commented Feb 25, 2026

Reviewer's Guide

添加了一个可复用的 ContributorsGrid Vue 组件,用于获取并展示 GitHub 仓库贡献者,将其接入 VitePress 主题,并在所有语言的贡献者页面中,用它替换之前基于图片的贡献者徽章。

ContributorsGrid 获取并渲染贡献者的时序图

sequenceDiagram
  actor User
  participant Browser
  participant ContributorsGrid
  participant GitHubAPI

  User->>Browser: Navigate to contributor_page
  Browser->>ContributorsGrid: Instantiate_with_props(repo, perPage, max)
  Browser->>ContributorsGrid: onMounted()
  activate ContributorsGrid
  ContributorsGrid->>ContributorsGrid: set loading = true
  ContributorsGrid->>ContributorsGrid: clear error
  ContributorsGrid->>GitHubAPI: GET /repos/{repo}/contributors?per_page={perPage}
  alt Response_OK
    GitHubAPI-->>ContributorsGrid: contributors_json_array
    ContributorsGrid->>ContributorsGrid: slice(0, max) into contributors
    ContributorsGrid->>ContributorsGrid: set loading = false
    ContributorsGrid-->>Browser: Render grid_of_contributors
  else Response_error_or_invalid
    GitHubAPI-->>ContributorsGrid: error_status_or_invalid_body
    ContributorsGrid->>ContributorsGrid: set error_message
    ContributorsGrid->>ContributorsGrid: set loading = false
    ContributorsGrid-->>Browser: Render error_message
  end
  deactivate ContributorsGrid
Loading

新的 ContributorsGrid Vue 组件的类图

classDiagram
  class ContributorsGrid {
    +repo: string
    +perPage: number
    +max: number
    +loading: boolean
    +error: string
    +contributors: Array
    +fetchContributors(): Promise
  }
Loading

文件级变更

Change Details Files
Introduce a ContributorsGrid Vue component that fetches contributors from the GitHub API and renders them in a styled grid.
  • Define typed props for repository name, page size, and maximum contributors with sensible defaults.
  • Implement asynchronous fetching of contributors from the GitHub REST API with basic error handling and loading state.
  • Render contributors as linked avatar/name tiles in a responsive CSS grid with hover styling and scoped styles.
.vitepress/theme/components/ContributorsGrid.vue
Register the ContributorsGrid component globally in the VitePress theme so it can be used in markdown content.
  • Import the new ContributorsGrid component into the custom VitePress theme index.
  • Update enhanceApp to accept the app instance and register ContributorsGrid as a global component while preserving existing title link enhancement.
.vitepress/theme/index.ts
Replace static contributor image embeds with the new ContributorsGrid component in all contributor documentation pages.
  • Update the English contributor page to use the ContributorsGrid component and slightly clarify the GitHub contributors link text.
  • Update the Traditional Chinese contributor page to embed ContributorsGrid instead of the remote image badge.
  • Update the Simplified Chinese contributor page to embed ContributorsGrid instead of the remote image badge.
en/contributor.md
zh-tw/contributor.md
zh/contributor.md

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

Original review guide in English

Reviewer's Guide

Adds a reusable ContributorsGrid Vue component that fetches and displays GitHub repository contributors, wires it into the VitePress theme, and replaces the previous image-based contributors badge on contributor pages in all locales.

Sequence diagram for ContributorsGrid fetching and rendering contributors

sequenceDiagram
  actor User
  participant Browser
  participant ContributorsGrid
  participant GitHubAPI

  User->>Browser: Navigate to contributor_page
  Browser->>ContributorsGrid: Instantiate_with_props(repo, perPage, max)
  Browser->>ContributorsGrid: onMounted()
  activate ContributorsGrid
  ContributorsGrid->>ContributorsGrid: set loading = true
  ContributorsGrid->>ContributorsGrid: clear error
  ContributorsGrid->>GitHubAPI: GET /repos/{repo}/contributors?per_page={perPage}
  alt Response_OK
    GitHubAPI-->>ContributorsGrid: contributors_json_array
    ContributorsGrid->>ContributorsGrid: slice(0, max) into contributors
    ContributorsGrid->>ContributorsGrid: set loading = false
    ContributorsGrid-->>Browser: Render grid_of_contributors
  else Response_error_or_invalid
    GitHubAPI-->>ContributorsGrid: error_status_or_invalid_body
    ContributorsGrid->>ContributorsGrid: set error_message
    ContributorsGrid->>ContributorsGrid: set loading = false
    ContributorsGrid-->>Browser: Render error_message
  end
  deactivate ContributorsGrid
Loading

Class diagram for the new ContributorsGrid Vue component

classDiagram
  class ContributorsGrid {
    +repo: string
    +perPage: number
    +max: number
    +loading: boolean
    +error: string
    +contributors: Array
    +fetchContributors(): Promise
  }
Loading

File-Level Changes

Change Details Files
Introduce a ContributorsGrid Vue component that fetches contributors from the GitHub API and renders them in a styled grid.
  • Define typed props for repository name, page size, and maximum contributors with sensible defaults.
  • Implement asynchronous fetching of contributors from the GitHub REST API with basic error handling and loading state.
  • Render contributors as linked avatar/name tiles in a responsive CSS grid with hover styling and scoped styles.
.vitepress/theme/components/ContributorsGrid.vue
Register the ContributorsGrid component globally in the VitePress theme so it can be used in markdown content.
  • Import the new ContributorsGrid component into the custom VitePress theme index.
  • Update enhanceApp to accept the app instance and register ContributorsGrid as a global component while preserving existing title link enhancement.
.vitepress/theme/index.ts
Replace static contributor image embeds with the new ContributorsGrid component in all contributor documentation pages.
  • Update the English contributor page to use the ContributorsGrid component and slightly clarify the GitHub contributors link text.
  • Update the Traditional Chinese contributor page to embed ContributorsGrid instead of the remote image badge.
  • Update the Simplified Chinese contributor page to embed ContributorsGrid instead of the remote image badge.
en/contributor.md
zh-tw/contributor.md
zh/contributor.md

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

Copy link
Copy Markdown
Contributor

@sourcery-ai sourcery-ai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - 我发现了两个问题,并提供了一些整体性的反馈:

  • 建议将 contributors: ref<any[]>([]) 替换为针对 GitHub 贡献者响应的带类型接口,以便让后续使用更安全、并具备自我文档化的效果。
  • perPagemax 这两个 prop 之间可能存在冲突(例如,当 max > perPage 时,max 将无法被完全利用);你可以考虑从 max 推导出 perPage,或者对这两个值进行校验/归一化处理,以确保行为是可预期的。
  • 组件内部硬编码的英文加载/错误信息会破坏 zh/zh-tw 页面本地化;可以考虑通过插槽或 props 接受文案,以便在每个页面按需进行翻译。
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- Consider replacing `contributors: ref<any[]>([])` with a typed interface for the GitHub contributor response to make downstream usage safer and self-documented.
- The `perPage` and `max` props can conflict (e.g., `max > perPage` will never be fully used); you might want to derive `perPage` from `max` or validate/normalize these values so the behavior is predictable.
- The hardcoded English loading/error messages inside the component break localization for the zh/zh-tw pages; consider accepting message slots or props so they can be translated per page.

## Individual Comments

### Comment 1
<location path=".vitepress/theme/components/ContributorsGrid.vue" line_range="15" />
<code_context>
+
+const loading = ref(true)
+const error = ref('')
+const contributors = ref<any[]>([])
+
+async function fetchContributors() {
</code_context>
<issue_to_address>
**suggestion:** Avoid `any[]` for contributors and use a typed structure instead.

`any[]` removes type safety for fields like `c.login` and `c.avatar_url`. Define a minimal `Contributor` interface with the properties you use (e.g. `id`, `login`, `avatar_url`, `html_url`, `contributions`) and type this as `ref<Contributor[]>([])` to keep the component safe and maintainable.

Suggested implementation:

```
interface Contributor {
  id: number
  login: string
  avatar_url: string
  html_url: string
  contributions: number
}

const loading = ref(true)
const error = ref('')
const contributors = ref<Contributor[]>([])

```

```
    const res = await fetch(url, { headers: { Accept: 'application/vnd.github.v3+json' } })
    if (!res.ok) throw new Error(`HTTP ${res.status}`)
    const data = await res.json() as Contributor[]

```

Review all usages of `contributors` in this component/template to ensure they only access properties defined on `Contributor` (`id`, `login`, `avatar_url`, `html_url`, `contributions`). If additional fields are used (e.g. `type`, `site_admin`), add them to the `Contributor` interface with appropriate types so that the template type-checks correctly.
</issue_to_address>

### Comment 2
<location path=".vitepress/theme/components/ContributorsGrid.vue" line_range="17-32" />
<code_context>
+  try {
+    const url = `https://api.github.com/repos/${props.repo}/contributors?per_page=${props.perPage}`
+    const res = await fetch(url, { headers: { Accept: 'application/vnd.github.v3+json' } })
+    if (!res.ok) throw new Error(`HTTP ${res.status}`)
+    const data = await res.json()
+    if (!Array.isArray(data)) throw new Error('Invalid response')
+    contributors.value = data.slice(0, props.max)
+  } catch (e: any) {
+    error.value = e.message || String(e)
+  } finally {
+    loading.value = false
</code_context>
<issue_to_address>
**suggestion:** User-facing error messages are quite low-level; consider mapping to friendlier text.

The UI will currently surface raw messages like `HTTP 403`, which isn’t very helpful for docs users. Consider mapping common statuses (e.g., 403/404/429) to clearer, user-friendly messages and logging the detailed error to the console for debugging instead of showing it directly.

```suggestion
async function fetchContributors() {
  loading.value = true
  error.value = ''
  try {
    const url = `https://api.github.com/repos/${props.repo}/contributors?per_page=${props.perPage}`
    const res = await fetch(url, { headers: { Accept: 'application/vnd.github.v3+json' } })

    if (!res.ok) {
      const status = res.status
      const statusText = res.statusText || ''
      // Log detailed technical information for debugging
      console.error('[ContributorsGrid] Failed to fetch contributors', {
        url,
        status,
        statusText,
      })

      let friendlyMessage = 'Failed to load contributors. Please try again later.'

      if (status === 403) {
        friendlyMessage = 'GitHub rate limit reached. Please try again in a few minutes.'
      } else if (status === 404) {
        friendlyMessage = 'Contributors could not be found for this repository.'
      } else if (status === 429) {
        friendlyMessage = 'Too many requests to GitHub. Please wait a moment and try again.'
      }

      throw new Error(friendlyMessage)
    }

    const data = await res.json()

    if (!Array.isArray(data)) {
      console.error('[ContributorsGrid] Unexpected contributors response shape', data)
      throw new Error('Failed to load contributors.')
    }

    contributors.value = data.slice(0, props.max)
  } catch (e: any) {
    console.error('[ContributorsGrid] Error while loading contributors', e)
    error.value = e?.message || 'Failed to load contributors.'
  } finally {
    loading.value = false
  }
}
```
</issue_to_address>

Sourcery 对开源项目免费——如果你觉得这些 review 有帮助,欢迎分享 ✨
帮我变得更有用!请在每条评论上点 👍 或 👎,我会根据你的反馈改进后续的 review。
Original comment in English

Hey - I've found 2 issues, and left some high level feedback:

  • Consider replacing contributors: ref<any[]>([]) with a typed interface for the GitHub contributor response to make downstream usage safer and self-documented.
  • The perPage and max props can conflict (e.g., max > perPage will never be fully used); you might want to derive perPage from max or validate/normalize these values so the behavior is predictable.
  • The hardcoded English loading/error messages inside the component break localization for the zh/zh-tw pages; consider accepting message slots or props so they can be translated per page.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- Consider replacing `contributors: ref<any[]>([])` with a typed interface for the GitHub contributor response to make downstream usage safer and self-documented.
- The `perPage` and `max` props can conflict (e.g., `max > perPage` will never be fully used); you might want to derive `perPage` from `max` or validate/normalize these values so the behavior is predictable.
- The hardcoded English loading/error messages inside the component break localization for the zh/zh-tw pages; consider accepting message slots or props so they can be translated per page.

## Individual Comments

### Comment 1
<location path=".vitepress/theme/components/ContributorsGrid.vue" line_range="15" />
<code_context>
+
+const loading = ref(true)
+const error = ref('')
+const contributors = ref<any[]>([])
+
+async function fetchContributors() {
</code_context>
<issue_to_address>
**suggestion:** Avoid `any[]` for contributors and use a typed structure instead.

`any[]` removes type safety for fields like `c.login` and `c.avatar_url`. Define a minimal `Contributor` interface with the properties you use (e.g. `id`, `login`, `avatar_url`, `html_url`, `contributions`) and type this as `ref<Contributor[]>([])` to keep the component safe and maintainable.

Suggested implementation:

```
interface Contributor {
  id: number
  login: string
  avatar_url: string
  html_url: string
  contributions: number
}

const loading = ref(true)
const error = ref('')
const contributors = ref<Contributor[]>([])

```

```
    const res = await fetch(url, { headers: { Accept: 'application/vnd.github.v3+json' } })
    if (!res.ok) throw new Error(`HTTP ${res.status}`)
    const data = await res.json() as Contributor[]

```

Review all usages of `contributors` in this component/template to ensure they only access properties defined on `Contributor` (`id`, `login`, `avatar_url`, `html_url`, `contributions`). If additional fields are used (e.g. `type`, `site_admin`), add them to the `Contributor` interface with appropriate types so that the template type-checks correctly.
</issue_to_address>

### Comment 2
<location path=".vitepress/theme/components/ContributorsGrid.vue" line_range="17-32" />
<code_context>
+  try {
+    const url = `https://api.github.com/repos/${props.repo}/contributors?per_page=${props.perPage}`
+    const res = await fetch(url, { headers: { Accept: 'application/vnd.github.v3+json' } })
+    if (!res.ok) throw new Error(`HTTP ${res.status}`)
+    const data = await res.json()
+    if (!Array.isArray(data)) throw new Error('Invalid response')
+    contributors.value = data.slice(0, props.max)
+  } catch (e: any) {
+    error.value = e.message || String(e)
+  } finally {
+    loading.value = false
</code_context>
<issue_to_address>
**suggestion:** User-facing error messages are quite low-level; consider mapping to friendlier text.

The UI will currently surface raw messages like `HTTP 403`, which isn’t very helpful for docs users. Consider mapping common statuses (e.g., 403/404/429) to clearer, user-friendly messages and logging the detailed error to the console for debugging instead of showing it directly.

```suggestion
async function fetchContributors() {
  loading.value = true
  error.value = ''
  try {
    const url = `https://api.github.com/repos/${props.repo}/contributors?per_page=${props.perPage}`
    const res = await fetch(url, { headers: { Accept: 'application/vnd.github.v3+json' } })

    if (!res.ok) {
      const status = res.status
      const statusText = res.statusText || ''
      // Log detailed technical information for debugging
      console.error('[ContributorsGrid] Failed to fetch contributors', {
        url,
        status,
        statusText,
      })

      let friendlyMessage = 'Failed to load contributors. Please try again later.'

      if (status === 403) {
        friendlyMessage = 'GitHub rate limit reached. Please try again in a few minutes.'
      } else if (status === 404) {
        friendlyMessage = 'Contributors could not be found for this repository.'
      } else if (status === 429) {
        friendlyMessage = 'Too many requests to GitHub. Please wait a moment and try again.'
      }

      throw new Error(friendlyMessage)
    }

    const data = await res.json()

    if (!Array.isArray(data)) {
      console.error('[ContributorsGrid] Unexpected contributors response shape', data)
      throw new Error('Failed to load contributors.')
    }

    contributors.value = data.slice(0, props.max)
  } catch (e: any) {
    console.error('[ContributorsGrid] Error while loading contributors', e)
    error.value = e?.message || 'Failed to load contributors.'
  } finally {
    loading.value = false
  }
}
```
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment thread .vitepress/theme/components/ContributorsGrid.vue Outdated
Comment thread .vitepress/theme/components/ContributorsGrid.vue
Co-authored-by: sourcery-ai[bot] <58596630+sourcery-ai[bot]@users.noreply.github.com>
@xingwangzhe
Copy link
Copy Markdown
Member

请提供截图,包括明暗模式的

@ChouChiu
Copy link
Copy Markdown
Contributor Author

ChouChiu commented Feb 26, 2026

请提供截图,包括明暗模式的

不好意思这么晚才回复

模式 效果
image image
image image

|

srds 不可以拉到本地吗

Copilot AI review requested due to automatic review settings February 26, 2026 08:52
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds a reusable VitePress theme component to render a contributors grid by fetching GitHub repo contributor data, and replaces the old external contributors image embed across localized contributor pages.

Changes:

  • Add ContributorsGrid Vue component that fetches and displays GitHub contributors in a responsive grid.
  • Register ContributorsGrid globally in the VitePress theme.
  • Update contributor pages (en / zh / zh-tw) to use the new component and adjust the GitHub link text.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
en/contributor.md Replaces external contributors image with <ContributorsGrid /> and clarifies link to full GitHub graph.
zh/contributor.md Replaces external contributors image with <ContributorsGrid />.
zh-tw/contributor.md Replaces external contributors image with <ContributorsGrid />.
.vitepress/theme/index.ts Registers ContributorsGrid as a global theme component.
.vitepress/theme/components/ContributorsGrid.vue Implements client-side GitHub contributors fetching + grid UI.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread .vitepress/theme/components/ContributorsGrid.vue
Comment on lines +68 to +70
}))

contributors.value = mapped.slice(0, props.max)
Copy link

Copilot AI Feb 26, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

contributors.value = mapped.slice(0, props.max) behaves unexpectedly if max is negative (slice will drop items from the end). Also, since only one page is fetched, max > perPage can never be fulfilled. Clamp max/perPage to positive integers (and to GitHub’s per_page max) and/or implement pagination when max > perPage.

Copilot uses AI. Check for mistakes.
Comment on lines +79 to +80
onMounted(fetchContributors)
</script>
Copy link

Copilot AI Feb 26, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The component only loads once in onMounted. If repo, perPage, or max props change, the grid won’t refetch and will show stale data. Consider watching the relevant props (with { immediate: true }) and calling fetchContributors on change.

Copilot uses AI. Check for mistakes.
Comment thread .vitepress/theme/components/ContributorsGrid.vue Outdated
Comment thread .vitepress/theme/index.ts Outdated
@xingwangzhe xingwangzhe merged commit 5d0d218 into SeaLantern-Studio:main Feb 26, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants