Skip to content

refactor(plugins): 将插件列表重构为 Element Plus 组件体系 - #14

Open
jacksixth wants to merge 4 commits into
KarinJS:docsfrom
jacksixth:docs
Open

refactor(plugins): 将插件列表重构为 Element Plus 组件体系#14
jacksixth wants to merge 4 commits into
KarinJS:docsfrom
jacksixth:docs

Conversation

@jacksixth

@jacksixth jacksixth commented Jul 27, 2026

Copy link
Copy Markdown
  • 使用 el-card/el-table/el-pagination 替代自定义布局
  • 新增 PluginDetailDrawer 抽屉组件展示插件详情
  • 统一使用 TypeScript <script setup> 语法
  • 优化暗色模式自动检测与切换逻辑
  • 调整样式,移除冗余的动画与交互效果

Summary by CodeRabbit

  • New Features
    • Refreshed the plugin catalog UI into a card grid with Element Plus-based search, filtering, pagination, and improved loading/error handling.
    • Plugin details now open in a responsive drawer with README preview, home link, and an npm install command (with one-click copy and toast feedback).
  • Bug Fixes
    • Improved mobile drawer behavior and interaction flow for viewing plugin information.
  • Style
    • Updated the documentation look and Element Plus integration, including refined search/form layout and more consistent component styling.
    • Search options were adjusted (including repository type choices).

- 使用 el-card/el-table/el-pagination 替代自定义布局
- 新增 PluginDetailDrawer 抽屉组件展示插件详情
- 统一使用 TypeScript <script setup> 语法
- 优化暗色模式自动检测与切换逻辑
- 调整样式,移除冗余的动画与交互效果
@gemini-code-assist

Copy link
Copy Markdown
Contributor

Caution

The consumer version of Gemini Code Assist on GitHub has been sunset. All code review activity has officially ceased.

@netlify

netlify Bot commented Jul 27, 2026

Copy link
Copy Markdown

Deploy Preview for zippy-cactus-2e87a5 ready!

Name Link
🔨 Latest commit 899fc2f
🔍 Latest deploy log https://app.netlify.com/projects/zippy-cactus-2e87a5/deploys/6a68161930c5e60008cab5b4
😎 Deploy Preview https://deploy-preview-14--zippy-cactus-2e87a5.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@netlify

netlify Bot commented Jul 27, 2026

Copy link
Copy Markdown

Deploy Preview for node-karin ready!

Name Link
🔨 Latest commit 899fc2f
🔍 Latest deploy log https://app.netlify.com/projects/node-karin/deploys/6a6816194b9b310008b81052
😎 Deploy Preview https://deploy-preview-14--node-karin.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@coderabbitai

coderabbitai Bot commented Jul 27, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: e72268a1-f22c-4419-b608-304d010ec08c

📥 Commits

Reviewing files that changed from the base of the PR and between 08a3714 and 899fc2f.

📒 Files selected for processing (2)
  • docs/.vuepress/theme/components/PluginDetailDrawer.vue
  • docs/.vuepress/theme/components/PluginList.vue
💤 Files with no reviewable changes (1)
  • docs/.vuepress/theme/components/PluginList.vue
🚧 Files skipped from review as they are similar to previous changes (1)
  • docs/.vuepress/theme/components/PluginDetailDrawer.vue

📝 Walkthrough

Walkthrough

The plugin browser is rewritten with typed Vue 3 Composition API components and Element Plus controls. Search and pagination use reactive state, plugin cards emit detail events, and a drawer fetches and renders plugin README content with install and homepage actions.

Changes

Plugin Browser Redesign

Layer / File(s) Summary
Element Plus client setup
docs/.vuepress/client.ts
Adds the Element Plus stylesheet and normalizes client configuration method syntax.
Typed search and plugin listing
docs/.vuepress/theme/utils/test-url.ts, docs/.vuepress/theme/components/SearchBar.vue, docs/.vuepress/theme/components/PluginList.vue
Replaces the previous Options API controls with typed search state, Element Plus form controls, computed filtering, pagination, loading skeletons, and plugin data loading.
Plugin card interaction
docs/.vuepress/theme/components/PluginCard.vue
Replaces the previous card interactions with a typed Element Plus card that emits openDetail and supports external navigation.
README detail drawer
docs/.vuepress/theme/components/PluginDetailDrawer.vue
Adds a drawer with plugin actions, clipboard feedback, GitHub branch resolution, proxied README fetching, Markdown rendering, and README styling.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant SearchBar
  participant PluginList
  participant PluginCard
  participant PluginDetailDrawer
  participant GitHubProxy
  SearchBar->>PluginList: emit search parameters
  PluginList->>PluginList: filter and paginate plugins
  PluginList->>PluginCard: render paginated plugin
  PluginCard->>PluginList: emit openDetail
  PluginList->>PluginDetailDrawer: set plugin and open drawer
  PluginDetailDrawer->>GitHubProxy: fetch README through proxy
  GitHubProxy-->>PluginDetailDrawer: return README text
  PluginDetailDrawer->>PluginDetailDrawer: parse and render Markdown
Loading
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: refactoring the plugin list to an Element Plus-based component system.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 9

🧹 Nitpick comments (11)
docs/.vuepress/theme/components/PluginDetailDrawer.vue (5)

26-26: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

watch is imported but unused.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/.vuepress/theme/components/PluginDetailDrawer.vue` at line 26, Remove
the unused watch import from the Vue import declaration in
PluginDetailDrawer.vue, while preserving the existing onMounted and ref imports.

50-59: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

navigator.clipboard is undefined on non-secure origins. The try will throw a TypeError and hit the error branch, so behavior degrades gracefully — but drop the redundant console.log on success.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/.vuepress/theme/components/PluginDetailDrawer.vue` around lines 50 - 59,
Remove the redundant success-path console.log from copyInstallCommand while
preserving the clipboard write and success ElMessage behavior; leave the
existing catch and error notification unchanged.

94-111: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

No request timeout and data may not be a string.

axios.get without timeout can hang the loading state indefinitely if the proxy stalls. Also force responseType: 'text' — a README served as JSON would make marked.parse receive an object.

♻️ Proposed change
-    const { data } = await axios.get(proxiedUrl)
+    const { data } = await axios.get<string>(proxiedUrl, {
+      timeout: 10000,
+      responseType: 'text',
+      transformResponse: [(d) => d]
+    })
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/.vuepress/theme/components/PluginDetailDrawer.vue` around lines 94 -
111, Update fetchReadme to configure the axios.get request with an explicit
finite timeout and responseType set to text before passing data to marked.parse.
Preserve the existing loading, error, and cleanup behavior.

132-141: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Unscoped .el-drawer global styles leak to every drawer in the app. header-class/body-class are already unique — target .drawer-header/.drawer-body directly, or scope under a component-specific class passed via class on el-drawer.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/.vuepress/theme/components/PluginDetailDrawer.vue` around lines 132 -
141, Update the styles in PluginDetailDrawer so they no longer globally affect
every .el-drawer; target the unique drawer-header and drawer-body classes
directly, or scope them beneath a component-specific class applied to this
el-drawer while preserving the existing margin and padding rules.

121-143: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Three <style> blocks with a trailing empty scoped one. Remove line 143; consider merging the global block into the first file-level styles for clarity.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/.vuepress/theme/components/PluginDetailDrawer.vue` around lines 121 -
143, Remove the trailing empty scoped <style> block from PluginDetailDrawer.vue.
Leave the existing readme-content and global el-drawer styles unchanged; merging
them is optional and not required.
docs/.vuepress/theme/components/PluginCard.vue (2)

59-61: 🔒 Security & Privacy | 🔵 Trivial | ⚡ Quick win

Add noopener to window.open. Without it the opened page gets a window.opener reference (reverse tabnabbing) on older browsers.

 const jumpTo = (url: string) => {
-  window.open(url, '_blank')
+  window.open(url, '_blank', 'noopener,noreferrer')
 }

Same applies to jumpTo in PluginDetailDrawer.vue.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/.vuepress/theme/components/PluginCard.vue` around lines 59 - 61, Update
the jumpTo functions in PluginCard.vue and PluginDetailDrawer.vue to pass
noopener in the window.open feature options, preventing the opened page from
retaining a window.opener reference while preserving the existing URL and
new-tab behavior.

5-9: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Card header / author / body are click handlers on plain divs — not keyboard reachable. Consider el-link/button semantics or tabindex + @keyup.enter for the primary actions.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/.vuepress/theme/components/PluginCard.vue` around lines 5 - 9, The
PluginCard header click target around replaceName and jumpTo is a plain div and
is not keyboard accessible. Replace it with an appropriate interactive element
such as el-link or button, or add keyboard focusability and Enter-key handling
while preserving the existing jumpTo(plugin.home) behavior.
docs/.vuepress/theme/components/PluginList.vue (3)

30-30: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

showPlugin! non-null assertion is safe only because of the v-if. Prefer gating on the value itself so the assertion isn't needed.

-    <PluginDetailDrawer v-if="drawerVisible" v-model:drawer-visible="drawerVisible" :plugin="showPlugin!" />
+    <PluginDetailDrawer v-if="drawerVisible && showPlugin" v-model:drawer-visible="drawerVisible" :plugin="showPlugin" />
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/.vuepress/theme/components/PluginList.vue` at line 30, Update the
PluginDetailDrawer rendering in PluginList to gate directly on showPlugin rather
than drawerVisible, allowing the plugin prop to be passed without the non-null
assertion. Preserve the drawer visibility behavior through the existing v-model
binding.

45-50: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

useToggle(isDark) is a no-op here. It returns a toggle function but never invokes it; the preceding assignment already sets isDark. Drop the branch.

♻️ Proposed cleanup
 const checkDark = () => {
   isDark.value = document.documentElement.getAttribute('data-theme') === 'dark'
-  if (isDark.value) {
-    useToggle(isDark)
-  }
 }

Also remove useToggle from the @vueuse/core import.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/.vuepress/theme/components/PluginList.vue` around lines 45 - 50, Remove
the redundant if branch and useToggle(isDark) call from checkDark, since
isDark.value is already assigned directly. Also remove the unused useToggle
import from `@vueuse/core`.

98-103: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Debug console.log and unused errorMsg.

errorMsg is set but never rendered — load failures show an empty grid with no feedback. Either surface it in the template or drop it, and remove the console log.

♻️ Proposed cleanup
   } finally {
     loading.value = false
-    console.log(allPlugins.value)
   }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/.vuepress/theme/components/PluginList.vue` around lines 98 - 103, Update
the PluginList component’s error handling so load failures are surfaced through
the template using errorMsg, or remove errorMsg entirely if no user-facing
message is desired; also remove the debug console.log from the finally block
while preserving loading.value cleanup.
docs/.vuepress/theme/components/SearchBar.vue (1)

70-71: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Redundant computed wrapper. props.authorOptions is already reactive in the template; authorOptions computed only shadows the prop name.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/.vuepress/theme/components/SearchBar.vue` around lines 70 - 71, Remove
the redundant authorOptions computed wrapper and update the template or
component references to use props.authorOptions directly. Preserve the existing
author options behavior and remove any now-unused computed import or related
code.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@docs/.vuepress/theme/components/PluginCard.vue`:
- Around line 5-9: Stop click propagation on the author homepage link and the
corresponding author target so activating either does not trigger the parent
`.card-body` openDetail handler; update the relevant click bindings around
`PluginCard` while preserving homepage navigation.
- Around line 19-23: Update the author rendering in PluginCard so it safely
handles an empty plugin.author array before accessing author[0].home or
author[0].name. Preserve the existing clickable author display when an author
exists, and render an appropriate empty-safe result when it does not.

In `@docs/.vuepress/theme/components/PluginDetailDrawer.vue`:
- Around line 62-73: Update getRawReadmeUrl to return an empty or established
sentinel value for non-GitHub URLs instead of returning homeUrl, including npmjs
plugin homes. Update the drawer’s README loading/rendering flow to detect that
sentinel and display the “无 README” state without fetching or rendering the HTML
page.
- Around line 12-14: Move the npm-type conditional from the el-button to the
surrounding el-tooltip in PluginDetailDrawer, so the tooltip itself is only
rendered when plugin.type is npm while preserving the existing button and
copyInstallCommand behavior.
- Line 19: Sanitize the rendered Markdown before assigning it to readmeHtml,
covering both remote and local README content, then continue using the sanitized
value in the v-html binding. Add and use an established sanitizer dependency
such as DOMPurify or sanitize-html, ensuring raw HTML, scripts, and event
handlers cannot reach PluginDetailDrawer’s rendered output.

In `@docs/.vuepress/theme/components/PluginList.vue`:
- Around line 57-67: Extract the duplicated Plugin type into a shared module,
such as docs/.vuepress/theme/types/plugin.ts, preserving its existing fields.
Remove the local type and import the shared Plugin type in
docs/.vuepress/theme/components/PluginList.vue#L57-L67,
docs/.vuepress/theme/components/PluginCard.vue#L34-L44 for Props['plugin'], and
docs/.vuepress/theme/components/PluginDetailDrawer.vue#L31-L41.
- Around line 4-29: Update the empty-state rendering in the PluginList template
so el-empty is shown only after a successful load, not when the plugin fetch
fails. Use the component’s existing loading and error state, or add the
necessary error-state distinction in the fetch flow, while preserving the empty
result for successful responses with no plugins.
- Around line 35-41: Update the component imports in PluginList.vue to use the
exact case of the filenames: SearchBar.vue, PluginCard.vue, and
PluginDetailDrawer.vue. Leave the remaining imports unchanged.
- Line 136: Update the author matching expression in the keyword search to
compare a normalized author name against the lowercased keyword using substring
matching rather than exact equality. Preserve optional-author handling and
ensure the "作者" search matches regardless of name casing.

---

Nitpick comments:
In `@docs/.vuepress/theme/components/PluginCard.vue`:
- Around line 59-61: Update the jumpTo functions in PluginCard.vue and
PluginDetailDrawer.vue to pass noopener in the window.open feature options,
preventing the opened page from retaining a window.opener reference while
preserving the existing URL and new-tab behavior.
- Around line 5-9: The PluginCard header click target around replaceName and
jumpTo is a plain div and is not keyboard accessible. Replace it with an
appropriate interactive element such as el-link or button, or add keyboard
focusability and Enter-key handling while preserving the existing
jumpTo(plugin.home) behavior.

In `@docs/.vuepress/theme/components/PluginDetailDrawer.vue`:
- Line 26: Remove the unused watch import from the Vue import declaration in
PluginDetailDrawer.vue, while preserving the existing onMounted and ref imports.
- Around line 50-59: Remove the redundant success-path console.log from
copyInstallCommand while preserving the clipboard write and success ElMessage
behavior; leave the existing catch and error notification unchanged.
- Around line 94-111: Update fetchReadme to configure the axios.get request with
an explicit finite timeout and responseType set to text before passing data to
marked.parse. Preserve the existing loading, error, and cleanup behavior.
- Around line 132-141: Update the styles in PluginDetailDrawer so they no longer
globally affect every .el-drawer; target the unique drawer-header and
drawer-body classes directly, or scope them beneath a component-specific class
applied to this el-drawer while preserving the existing margin and padding
rules.
- Around line 121-143: Remove the trailing empty scoped <style> block from
PluginDetailDrawer.vue. Leave the existing readme-content and global el-drawer
styles unchanged; merging them is optional and not required.

In `@docs/.vuepress/theme/components/PluginList.vue`:
- Line 30: Update the PluginDetailDrawer rendering in PluginList to gate
directly on showPlugin rather than drawerVisible, allowing the plugin prop to be
passed without the non-null assertion. Preserve the drawer visibility behavior
through the existing v-model binding.
- Around line 45-50: Remove the redundant if branch and useToggle(isDark) call
from checkDark, since isDark.value is already assigned directly. Also remove the
unused useToggle import from `@vueuse/core`.
- Around line 98-103: Update the PluginList component’s error handling so load
failures are surfaced through the template using errorMsg, or remove errorMsg
entirely if no user-facing message is desired; also remove the debug console.log
from the finally block while preserving loading.value cleanup.

In `@docs/.vuepress/theme/components/SearchBar.vue`:
- Around line 70-71: Remove the redundant authorOptions computed wrapper and
update the template or component references to use props.authorOptions directly.
Preserve the existing author options behavior and remove any now-unused computed
import or related code.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: ca3a9c61-6aae-45ca-9e91-e66d89a3ca10

📥 Commits

Reviewing files that changed from the base of the PR and between a559c0a and cb99fbd.

📒 Files selected for processing (5)
  • docs/.vuepress/client.ts
  • docs/.vuepress/theme/components/PluginCard.vue
  • docs/.vuepress/theme/components/PluginDetailDrawer.vue
  • docs/.vuepress/theme/components/PluginList.vue
  • docs/.vuepress/theme/components/SearchBar.vue

Comment thread docs/.vuepress/theme/components/PluginCard.vue Outdated
Comment thread docs/.vuepress/theme/components/PluginCard.vue Outdated
Comment thread docs/.vuepress/theme/components/PluginDetailDrawer.vue Outdated
<el-divider style="margin: 12px 0" />
<div v-if="readmeLoading" style="text-align: center; padding: 24px">加载 README 中...</div>
<div v-else-if="readmeError" style="text-align: center; padding: 24px; color: #999">{{ readmeError }}</div>
<div v-else class="readme-content" v-html="readmeHtml"></div>

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔒 Security & Privacy | 🔴 Critical | ⚡ Quick win

🧩 Analysis chain

🌐 Web query:

marked v15 sanitize option removed DOMPurify recommendation

💡 Result:

The sanitize and sanitizer options were removed from the Marked library in version 8.0.0 [1][2]. Marked explicitly does not sanitize output HTML, as this is not considered the responsibility of the markdown parser [3]. Instead, the official recommendation is to sanitize the resulting HTML output using a dedicated third-party library [4][5]. DOMPurify is the most frequently recommended option, though other libraries like sanitize-html and insane are also cited [1][6]. You can implement this sanitization in a few ways: 1. Wrapping the output: const sanitizedHtml = DOMPurify.sanitize(marked.parse(markdownString)); [4][5] 2. Using an extension hook: Marked supports a postprocess hook that can be used to automatically sanitize all output [7][8]. marked.use({ hooks: { postprocess(html) { return DOMPurify.sanitize(html); } } }); [7][8]

Citations:


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "## locate file"
fd -a 'PluginDetailDrawer\.vue$' . || true

echo "## file excerpt"
file="$(fd 'PluginDetailDrawer\.vue$' . | head -n 1)"
if [ -n "${file:-}" ]; then
  wc -l "$file"
  cat -n "$file"
fi

echo "## package manifests"
fd '(^|/)package\.json$|package-lock\.json$|pnpm-lock\.yaml$|yarn\.lock$|bun\.lockb?|bun\.lock$' . -d 4 -x sh -c 'echo "--- $1"; sed -n "1,220p" "$1" | rg -n "marked|vuepress|dependencies|devDependencies|scripts" -C 2 || true' sh {}

Repository: KarinJS/karin-docs

Length of output: 4958


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "## tracked matching files"
git ls-files | rg '(^|/)PluginDetailDrawer\.vue$|PluginDetailDrawer' || true

echo "## search for v-html and marked/readmeHtml"
rg -n "v-html|readmeHtml|marked\.parse|PluginDetailDrawer" docs . --glob '!node_modules' --glob '!dist' || true

echo "## package-lock snippets if present"
if [ -f package.json ]; then cat -n package.json | sed -n '1,80p'; fi

Repository: KarinJS/karin-docs

Length of output: 2338


Sanitize Markdown before injecting it with v-html.

marked does not sanitize output, so README content can render raw HTML/<script>/event handlers. Sanitize before assigning to readmeHtml, e.g. with DOMPurify/sanitize-html, and add the sanitizer as a dependency; apply this whether the content is remote or local.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/.vuepress/theme/components/PluginDetailDrawer.vue` at line 19, Sanitize
the rendered Markdown before assigning it to readmeHtml, covering both remote
and local README content, then continue using the sanitized value in the v-html
binding. Add and use an established sanitizer dependency such as DOMPurify or
sanitize-html, ensuring raw HTML, scripts, and event handlers cannot reach
PluginDetailDrawer’s rendered output.

Comment thread docs/.vuepress/theme/components/PluginDetailDrawer.vue
Comment thread docs/.vuepress/theme/components/PluginList.vue Outdated
Comment thread docs/.vuepress/theme/components/PluginList.vue Outdated
Comment thread docs/.vuepress/theme/components/PluginList.vue Outdated
Comment thread docs/.vuepress/theme/components/PluginList.vue Outdated
- 将 Plugin 类型定义集中提取到 test-url.ts 工具模块,消除组件内的重复类型声明
- 修复搜索关键词匹配逻辑,支持作者名称的模糊大小写搜索
- 修复加载失败时错误提示与骨架屏状态冲突的问题,统一错误处理流程
- 调整组件文件名大小写以符合 Vue 规范
- 优化 README 获取逻辑,提前处理无法获取的情况

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
docs/.vuepress/theme/utils/test-url.ts (1)

99-100: 🗄️ Data Integrity & Integration | 🔵 Trivial | ⚡ Quick win

Separate the raw API payload type from the normalized Plugin type.

PluginList.vue types each raw data.plugins item as Plugin, but this definition requires author to already be an array while the same loader explicitly handles non-array values. This weakens TypeScript’s protection against schema drift. Keep Plugin as the normalized UI type and introduce a separate payload type (or runtime schema validation) for the API response, then map it into Plugin.

This is based on the normalization in docs/.vuepress/theme/components/PluginList.vue and array consumption in docs/.vuepress/theme/components/PluginCard.vue.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/.vuepress/theme/utils/test-url.ts` around lines 99 - 100, Separate the
raw API plugin payload type from the normalized Plugin type in test-url.ts.
Update the PluginList.vue loader to type data.plugins with the payload shape
that permits non-array author values, then normalize each item into the existing
Plugin shape before passing it to PluginCard.vue. Keep Plugin.author as the
array consumed by the UI.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@docs/.vuepress/theme/utils/test-url.ts`:
- Around line 99-100: Separate the raw API plugin payload type from the
normalized Plugin type in test-url.ts. Update the PluginList.vue loader to type
data.plugins with the payload shape that permits non-array author values, then
normalize each item into the existing Plugin shape before passing it to
PluginCard.vue. Keep Plugin.author as the array consumed by the UI.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 1668db4f-872b-4957-842c-21e45e756f8c

📥 Commits

Reviewing files that changed from the base of the PR and between cb99fbd and 08a3714.

📒 Files selected for processing (4)
  • docs/.vuepress/theme/components/PluginCard.vue
  • docs/.vuepress/theme/components/PluginDetailDrawer.vue
  • docs/.vuepress/theme/components/PluginList.vue
  • docs/.vuepress/theme/utils/test-url.ts
🚧 Files skipped from review as they are similar to previous changes (3)
  • docs/.vuepress/theme/components/PluginCard.vue
  • docs/.vuepress/theme/components/PluginDetailDrawer.vue
  • docs/.vuepress/theme/components/PluginList.vue

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.

1 participant