Skip to content

feat: add SuggestionPopover component with demos and docs#59

Merged
hexqi merged 13 commits intodevelopfrom
feat/my-questions
May 27, 2025
Merged

feat: add SuggestionPopover component with demos and docs#59
hexqi merged 13 commits intodevelopfrom
feat/my-questions

Conversation

@gene9831
Copy link
Copy Markdown
Collaborator

@gene9831 gene9831 commented May 26, 2025

Summary by CodeRabbit

  • New Features

    • Introduced the SuggestionPopover component, offering an interactive popover for displaying suggestions with support for grouping, loading, empty states, and mobile adaptation.
    • Added multiple demo examples illustrating basic usage, trigger modes, grouped data, and various states of SuggestionPopover.
    • Included comprehensive documentation for SuggestionPopover, detailing its props, slots, events, and usage scenarios.
    • Added a flow layout button component for managing grouped tabs within the popover.
  • Enhancements

    • Updated several components to use a new icon (IconSparkles) for improved visual consistency.
  • Refactor

    • Centralized CSS unit formatting by introducing a shared utility function.
  • Documentation

    • Added sidebar navigation and new documentation for the SuggestionPopover component.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 26, 2025

Walkthrough

A new SuggestionPopover Vue component is introduced, providing a customizable suggestion popover with grouping, event handling, and responsive design. Supporting types, documentation, and demos are added. A utility for CSS unit formatting is centralized. A new FlowLayoutButtons component is implemented. Several icons are updated from IconHotQuestion to IconSparkles. The SuggestionPopover and FlowLayoutButtons components are registered globally. Documentation sidebar is updated accordingly.

Changes

File(s) Change Summary
docs/.vitepress/config.mts Adds sidebar entry for "SuggestionPopover 建议弹出框" in documentation.
docs/src/components/suggestion-popover.md Adds comprehensive documentation for SuggestionPopover, including API, usage, slots, and types.
docs/demos/suggestion/popover-basic.vue
docs/demos/suggestion/popover-grouped.vue
docs/demos/suggestion/popover-other-status.vue
docs/demos/suggestion/popover-trigger.vue
Adds demo Vue components showcasing basic, grouped, loading/empty, and trigger/manual usage of SuggestionPopover.
packages/components/src/suggestion-popover/index.vue Implements the new SuggestionPopover Vue component with grouping, responsive behavior, event handling, and slots.
packages/components/src/suggestion-popover/index.type.ts Declares TypeScript types/interfaces for SuggestionPopover props, slots, and events.
packages/components/src/suggestion-popover/index.ts Exports SuggestionPopover with Vue plugin install method.
packages/components/src/index.ts Registers and exports SuggestionPopover globally (named and aliased); adds TODO for types.
packages/components/src/flow-layout-buttons/index.vue Adds FlowLayoutButtons Vue component for grouped button layouts with "more" dropdown.
packages/components/src/flow-layout-buttons/index.type.ts Declares types/interfaces for FlowLayoutButtons props and events.
packages/components/src/flow-layout-buttons/index.ts Exports FlowLayoutButtons with Vue plugin install method.
packages/components/src/shared/utils.ts Adds toCssUnit utility for normalizing CSS units.
packages/components/src/shared/index.ts Re-exports shared utilities (including toCssUnit).
packages/components/src/icon-button/index.vue Refactors to use toCssUnit utility instead of local function for size formatting.
packages/components/src/question/index.vue
packages/components/src/question/components/HotQuestions.vue
packages/components/src/suggestion/components/SuggestionPanel.vue
packages/components/src/suggestion/index.vue
Replaces usage of IconHotQuestion with IconSparkles and updates icon color to #1476ff.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant Button as Trigger Button
    participant SuggestionPopover
    participant App

    User->>Button: Click
    Button->>SuggestionPopover: Open popover
    SuggestionPopover->>App: Emit item-click/group-click/close events
    App->>SuggestionPopover: (Optional) Update props/model
    User->>SuggestionPopover: Click suggestion or group
    SuggestionPopover->>SuggestionPopover: Update selection/close
Loading

Poem

(\(\
( -.-) A popover pops, suggestions in tow,
o_(")(") With groups and with icons, in a tidy row.

Sparkles replace the old,
Utilities refactored bold,

Rabbits cheer for features new—
Pop! goes the UI, fresh for you!
🐇✨

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

packages/components/src/shared/utils.ts

Oops! Something went wrong! :(

ESLint: 9.27.0

Error: The 'jiti' library is required for loading TypeScript configuration files. Make sure to install it.
at /node_modules/.pnpm/eslint@9.27.0/node_modules/eslint/lib/config/config-loader.js:142:9
at async loadTypeScriptConfigFileWithJiti (/node_modules/.pnpm/eslint@9.27.0/node_modules/eslint/lib/config/config-loader.js:141:25)
at async loadConfigFile (/node_modules/.pnpm/eslint@9.27.0/node_modules/eslint/lib/config/config-loader.js:259:11)
at async ConfigLoader.calculateConfigArray (/node_modules/.pnpm/eslint@9.27.0/node_modules/eslint/lib/config/config-loader.js:578:23)
at async #calculateConfigArray (/node_modules/.pnpm/eslint@9.27.0/node_modules/eslint/lib/config/config-loader.js:759:23)
at async /node_modules/.pnpm/eslint@9.27.0/node_modules/eslint/lib/eslint/eslint.js:760:6
at async Promise.all (index 0)
at async ESLint.lintFiles (/node_modules/.pnpm/eslint@9.27.0/node_modules/eslint/lib/eslint/eslint.js:757:19)
at async Object.execute (/node_modules/.pnpm/eslint@9.27.0/node_modules/eslint/lib/cli.js:639:14)
at async main (/node_modules/.pnpm/eslint@9.27.0/node_modules/eslint/bin/eslint.js:175:19)

Warning

Review ran into problems

🔥 Problems

GitHub Actions and Pipeline Checks: Resource not accessible by integration - https://docs.github.com/rest/actions/workflow-runs#list-workflow-runs-for-a-repository.

Please grant the required permissions to the CodeRabbit GitHub App under the organization or repository settings.


📜 Recent review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 682997c and 0d27225.

📒 Files selected for processing (1)
  • packages/components/src/shared/utils.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/components/src/shared/utils.ts
✨ Finishing Touches
  • 📝 Generate Docstrings

🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Comment thread docs/.vitepress/config.mts Outdated
Comment thread packages/components/src/flow-layout/index.ts Outdated
Comment thread packages/components/src/shared/index.ts
Comment thread packages/components/src/suggestion-popover/index.vue Outdated
Comment thread packages/components/src/suggestion-popover/index.vue Outdated
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 6

🧹 Nitpick comments (14)
packages/components/src/question/components/HotQuestions.vue (1)

95-95: Icon usage updated with consistent styling.

The template correctly uses the new icon with consistent blue color styling. Consider extracting the hardcoded color value to a CSS variable or design token for better maintainability across components.

-          <div><IconSparkles style="color: #1476ff" /></div>
+          <div><IconSparkles class="icon-primary" /></div>

Then define the color in CSS:

.icon-primary {
  color: var(--primary-color, #1476ff);
}
packages/components/src/suggestion/components/SuggestionPanel.vue (1)

93-93: Slot content updated with new icon.

The new icon usage in the title-icon slot is correct and maintains the same visual styling. Same suggestion as other files regarding color value extraction for maintainability.

packages/components/src/question/index.vue (1)

82-82: Trigger button icon updated correctly.

The new icon usage in the trigger button maintains the same functionality and visual appearance.

packages/components/src/suggestion/index.vue (2)

266-266: Trigger icon correctly updated.

The new icon usage in the trigger button maintains consistent styling with other components.


313-313: Title icon updated with appropriate sizing.

The larger font-size (36px) for the title-icon slot is intentionally different from other usages, which is appropriate for the context. The color value could benefit from the same CSS variable extraction suggested for other files.

packages/components/src/flow-layout-buttons/index.ts (1)

4-4: Consider aligning component name with filename.

The component name 'TrFlowLayout' doesn't fully match the filename flow-layout-buttons. Consider using 'TrFlowLayoutButtons' for better consistency and clarity.

-FlowLayoutButtons.name = 'TrFlowLayout'
+FlowLayoutButtons.name = 'TrFlowLayoutButtons'
docs/demos/suggestion/popover-basic.vue (1)

10-21: Consider removing duplicate items in demo data.

The data array contains several duplicate items (e.g., b1 and b6 both have "什么是弹性云服务器?"). For a cleaner demo experience, consider providing unique suggestions or clarify if the duplicates are intentional for testing purposes.

 const data = [
   { id: 'b1', text: '什么是弹性云服务器?' },
   { id: 'b2', text: '如何登录到Windows云服务器?' },
   { id: 'b3', text: '弹性公网IP为什么ping不通?' },
   { id: 'b4', text: '云服务器安全组如何配置?' },
   { id: 'b5', text: '如何查看云服务器密码?' },
-  { id: 'b6', text: '什么是弹性云服务器?' },
-  { id: 'b7', text: '如何登录到Windows云服务器?' },
-  { id: 'b8', text: '弹性公网IP为什么ping不通?' },
-  { id: 'b9', text: '云服务器安全组如何配置?' },
-  { id: 'b0', text: '如何查看云服务器密码?' },
+  { id: 'b6', text: '如何备份云服务器数据?' },
+  { id: 'b7', text: '云服务器如何扩容?' },
+  { id: 'b8', text: '如何监控云服务器性能?' },
+  { id: 'b9', text: '云服务器网络如何配置?' },
+  { id: 'b0', text: '如何迁移云服务器?' },
 ]
packages/components/src/index.ts (1)

24-25: Address the type conflict when possible.

The TODO comment indicates type conflicts between suggestion and suggestion-popover. Consider prioritizing this resolution to maintain type safety across the component library.

Would you like me to help analyze the type conflicts and suggest a resolution strategy?

docs/src/components/suggestion-popover.md (1)

17-17: Fix typo in trigger property description.

There's a typo in the word "trigger" in the documentation.

-使用 `trggier` 来决定弹出框的触发方式。目前有 `click` 和 `manual` 两种方式,默认为 `click`。`trggier` 为 `manual` 时,需要你手动修改弹出框显示状态
+使用 `trigger` 来决定弹出框的触发方式。目前有 `click` 和 `manual` 两种方式,默认为 `click`。`trigger` 为 `manual` 时,需要你手动修改弹出框显示状态
packages/components/src/flow-layout-buttons/index.vue (2)

73-77: Debounce resize watcher to reduce layout thrashing

useElementSize triggers on every pixel change; updateMoreIndex() runs a nextTick() with costly DOM reads each time.
Wrap the call with useDebounceFn (from VueUse) or a manual setTimeout to avoid dozens of recalculations during a single resize/mutation frame.

-import { computed, nextTick, ref, useTemplateRef, watch } from 'vue'
+import { computed, nextTick, ref, useTemplateRef, watch } from 'vue'
+import { useDebounceFn } from '@vueuse/core'

...
-watch(width, (w) => {
-  if (w > 0) {
-    updateMoreIndex()
-  }
-})
+watch(
+  width,
+  useDebounceFn((w) => w > 0 && updateMoreIndex(), 100)
+)

This keeps UX smooth for rapidly changing containers.


135-143: Add an accessible label to the “more” icon-only button

Screen-reader users have no textual clue what the icon does.
Include aria-label="More" (or a prop-driven label) and title for hover hints:

 <button
   :class="['tr-flow-layout__item', 'icon-only', { selected: moreButtonSelected }]"
   v-if="!hideMoreButton"
   ref="more-button"
+  aria-label="More options"
+  title="More options"
   @click="handleClickMore"

Improves WCAG compliance at minimal cost.

packages/components/src/flow-layout-buttons/index.type.ts (1)

3-6: Consider collapsing the symmetric union into a single interface

FlowLayoutItem allows both “icon-mandatory” and “label-mandatory” variants, but in practice the component treats both props as optional (icon, label).
A simpler definition is clearer for users and tooling:

export interface FlowLayoutItem {
  id: string
  icon?: VNode | Component
  label?: string
}

If strict mutual-exclusion is desired, use a discriminated union instead.

packages/components/src/suggestion-popover/index.type.ts (1)

35-39: Minor: add JSDoc for style-related props

popoverWidth, popoverHeight, and topOffset drive layout but lack comments.
Documenting units and default behaviour aids IDE tooltips and prevents misuse (e.g., forgetting px).

/**
 * 宽度(如 '240px'、'16rem'、300)。默认根据内容自适应
 */
popoverWidth?: string | number

Same for the other two.

packages/components/src/suggestion-popover/index.vue (1)

49-55: selectedGroup not updated on dynamic prop changes
If props.data is loaded asynchronously or replaced, the initialisation block won’t run again, leaving selectedGroup stale. Watching the prop keeps reactivity intact:

+watch(
+  () => props.data,
+  (val) => {
+    if (isGrouped.value && val.length) {
+      selectedGroup.value ??= (val as SuggestionGroup[])[0].group
+    }
+  },
+  { immediate: true }
+)
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f2327db and 3709104.

⛔ Files ignored due to path filters (4)
  • packages/components/src/assets/svgs/no-data.svg is excluded by !**/*.svg
  • packages/svgs/src/assets/close.svg is excluded by !**/*.svg
  • packages/svgs/src/assets/hot-question.svg is excluded by !**/*.svg
  • packages/svgs/src/assets/sparkles.svg is excluded by !**/*.svg
📒 Files selected for processing (20)
  • docs/.vitepress/config.mts (1 hunks)
  • docs/demos/suggestion/popover-basic.vue (1 hunks)
  • docs/demos/suggestion/popover-grouped.vue (1 hunks)
  • docs/demos/suggestion/popover-other-status.vue (1 hunks)
  • docs/demos/suggestion/popover-trigger.vue (1 hunks)
  • docs/src/components/suggestion-popover.md (1 hunks)
  • packages/components/src/flow-layout-buttons/index.ts (1 hunks)
  • packages/components/src/flow-layout-buttons/index.type.ts (1 hunks)
  • packages/components/src/flow-layout-buttons/index.vue (1 hunks)
  • packages/components/src/icon-button/index.vue (1 hunks)
  • packages/components/src/index.ts (4 hunks)
  • packages/components/src/question/components/HotQuestions.vue (2 hunks)
  • packages/components/src/question/index.vue (2 hunks)
  • packages/components/src/shared/index.ts (1 hunks)
  • packages/components/src/shared/utils.ts (1 hunks)
  • packages/components/src/suggestion-popover/index.ts (1 hunks)
  • packages/components/src/suggestion-popover/index.type.ts (1 hunks)
  • packages/components/src/suggestion-popover/index.vue (1 hunks)
  • packages/components/src/suggestion/components/SuggestionPanel.vue (2 hunks)
  • packages/components/src/suggestion/index.vue (3 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (2)
packages/components/src/suggestion-popover/index.ts (1)
packages/components/src/index.ts (3)
  • SuggestionPopover (80-80)
  • SuggestionPopover (81-81)
  • install (45-50)
packages/components/src/flow-layout-buttons/index.ts (1)
packages/components/src/index.ts (1)
  • install (45-50)
🔇 Additional comments (18)
packages/components/src/shared/index.ts (1)

1-1: Good fix for the previously empty index file.

This properly exports the utilities and addresses the previous review comment about the file being empty. The export pattern is correct and follows standard practices.

packages/components/src/icon-button/index.vue (2)

3-3: Good refactoring to use shared utility.

Importing toCssUnit from the shared utilities centralizes the CSS unit formatting logic and eliminates code duplication.


11-12: Clean implementation using the shared utility.

The computed properties now properly use the centralized toCssUnit function, which maintains the same functionality while improving code organization.

docs/.vitepress/config.mts (1)

45-45: Documentation entry properly added.

The new sidebar entry for SuggestionPopover is correctly formatted and follows the established pattern. The spelling issue mentioned in previous reviews appears to be resolved.

packages/components/src/question/components/HotQuestions.vue (1)

7-7: Icon import updated correctly.

The import change from IconHotQuestion to IconSparkles aligns with the UI consistency update mentioned in the PR objectives.

packages/components/src/suggestion/components/SuggestionPanel.vue (1)

6-6: Icon import correctly updated.

The import change maintains consistency with other components in this PR.

packages/components/src/question/index.vue (1)

8-8: Import statement correctly updated.

The icon import change is consistent with the codebase-wide icon standardization.

packages/components/src/suggestion/index.vue (1)

15-15: Icon import updated consistently.

The import change aligns with the standardization across all question and suggestion components.

docs/demos/suggestion/popover-other-status.vue (1)

1-14: LGTM! Clean demo showcasing loading and empty states.

The demo effectively demonstrates the loading and empty states of the SuggestionPopover component with clear, descriptive button labels in Chinese.

packages/components/src/flow-layout-buttons/index.ts (1)

6-12: LGTM! Follows established Vue plugin pattern.

The install function and export pattern correctly follows the established conventions seen in other components within this library, ensuring proper Vue plugin functionality.

docs/demos/suggestion/popover-basic.vue (1)

1-5: LGTM! Clean basic demo implementation.

The template correctly demonstrates the SuggestionPopover usage with proper event handling and slot content.

packages/components/src/suggestion-popover/index.ts (1)

1-12: LGTM! Correctly implements Vue plugin pattern.

The implementation follows the established Vue plugin pattern used throughout the component library, with proper component naming, install function, and type-safe export.

docs/demos/suggestion/popover-trigger.vue (1)

1-34: LGTM! Well-structured demo component.

The demo effectively showcases both trigger modes (click and manual) with proper reactive state management and event handling. The component usage follows Vue 3 composition API best practices.

packages/components/src/index.ts (2)

13-13: LGTM! Component import follows the established pattern.

The import is consistent with other component imports in the file.


41-41: LGTM! Component registration is consistent.

The component is properly added to the components array and exported with both original and aliased names, following the established pattern for other components.

Also applies to: 80-81

docs/src/components/suggestion-popover.md (1)

1-111: Excellent comprehensive documentation.

The documentation is well-structured and provides clear guidance on:

  • Multiple usage scenarios with demo references
  • Complete API documentation with types and descriptions
  • Clear type definitions for all data structures
  • Mobile adaptation considerations

This will help users understand and implement the component effectively.

docs/demos/suggestion/popover-grouped.vue (1)

1-69: LGTM! Comprehensive grouped data demo.

The demo effectively showcases the grouped functionality with:

  • Proper SuggestionGroup data structure
  • Correct icon imports from @opentiny/tiny-robot-svgs
  • Event handling for both item and group clicks
  • Mixed groups with populated and empty items for testing different scenarios

The implementation follows Vue 3 composition API best practices.

packages/components/src/suggestion-popover/index.vue (1)

76-78: 👍 Correct ref naming aligns with previous feedback
popoverRef is spelled correctly, resolving the typo highlighted in an earlier review.

Comment thread packages/components/src/shared/utils.ts
Comment thread packages/components/src/flow-layout-buttons/index.vue
Comment thread packages/components/src/flow-layout-buttons/index.vue Outdated
Comment thread packages/components/src/suggestion-popover/index.vue Outdated
Comment thread packages/components/src/suggestion-popover/index.vue
Comment thread packages/components/src/suggestion-popover/index.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.

2 participants