Skip to content

feat: plugin flexible layout#1219

Merged
hexqi merged 40 commits intoopentiny:developfrom
SonyLeo:feat/flex-layout
Mar 20, 2025
Merged

feat: plugin flexible layout#1219
hexqi merged 40 commits intoopentiny:developfrom
SonyLeo:feat/flex-layout

Conversation

@SonyLeo
Copy link
Contributor

@SonyLeo SonyLeo commented Mar 14, 2025

English | 简体中文

PR

PR Checklist

Please check if your PR fulfills the following requirements:

  • The commit message follows our Commit Message Guidelines
  • Tests for the changes have been added (for bug fixes / features)
  • Docs have been added / updated (for bug fixes / features)
  • Built its own designer, fully self-validated

PR Type

What kind of change does this PR introduce?

  • Bugfix
  • Feature
  • Code style update (formatting, local variables)
  • Refactoring (no functional changes, no api changes)
  • Build related changes
  • CI related changes
  • Documentation content changes
  • Other... Please describe:

Background and solution

What is the current behavior?

  1. 插件面板的浮动和固定逻辑不统一
  2. 插件面板的宽度不可以通过拖拽调整
  3. 插件的位置不可以调整
  4. 插件的显示和隐藏不可以调整
  5. 插件栏的显示和隐藏不可以调整

Issue Number: N/A

What is the new behavior?

  1. 统一插件面板的浮动和固定逻辑
  2. 重构右侧插件面板的显示逻辑
  3. 手动拖拽插件面板实现宽度可调
  4. 插件的位置可以通过拖拽或右键菜单调整
  5. 插件的显示和隐藏可以通过右键菜单调整
  6. 插件栏的显示和隐藏可以通过右键菜单调整

Does this PR introduce a breaking change?

  • Yes
  • No

Other information

Summary by CodeRabbit

  • New Features

    • Introduced interactive plugin navigation with drag-and-drop reordering and a context menu offering actions such as alignment switching and hide options.
    • Enabled enhanced configurability in plugin settings with dynamic fixed panel management and improved alignment choices.
    • Added new components for context menus and improved plugin settings with dynamic properties.
    • Implemented a new scoped style for non-interactive states in the design canvas.
    • Enhanced the plugin panel with dynamic width and improved scrolling behavior.
    • Added new computed properties and props for better layout management across various components.
    • Introduced new reactive references and methods for improved alignment and state management in design settings and plugins.
    • Updated the help icon and localized title for better user guidance.
  • Refactor

    • Unified panel structures and streamlined state management across multiple components for a more responsive interface.
  • Style

    • Updated visual cues with refined layout adjustments and disabled state styling for smoother interactions.
    • Introduced new CSS variables for consistent styling across components.
  • Chores

    • Upgraded dependencies to boost performance and compatibility.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Mar 14, 2025

Walkthrough

This pull request introduces several layout and UI enhancements across multiple components. Key changes include adding a conditional class and new functions (e.g., getMoveDragBarState) for controlling interactivity in the design canvas, updating plugin panel components with dynamic props and drag-resize functionality, and refactoring numerous plugin components to use consistent alignment properties. Additionally, dependency versions and configuration files are updated. The modifications collectively enhance the layout management, visual feedback, and interactivity of the application.

Changes

File(s) Change Summary
packages/canvas/DesignCanvas/src/DesignCanvas.vue
packages/layout/src/composable/useLayout.js
Added conditional binding (not-selected) based on getMoveDragBarState and introduced various layout management functions (e.g., drag, fixed panels, context menu controls).
packages/common/component/PluginPanel.vue
packages/common/component/PluginRightMenu.vue
packages/common/component/PluginSetting.vue
packages/common/component/index.js
Enhanced <plugin-panel> functionality with dynamic width, header margin, new tooltip, and props (fixedPanels, fixedName, etc.), and introduced a new context menu component export.
packages/layout/src/DesignPlugins.vue
packages/layout/src/DesignSettings.vue
packages/layout/src/Main.vue
Restructured navigation and settings panels with draggable components (vue-draggable-next), added new context menu handlers, and updated reactive state for panel alignment.
Various Plugin Files (e.g., in packages/plugins/block, bridge, datasource, help, i18n, materials, page, robot, schema, script, state, tree, tutorial) Updated alignment properties (e.g., from top/bottom to leftTop/leftBottom), integrated layout management via computed properties and useLayout, and added new props to <plugin-setting>.
packages/register/src/common.js
packages/settings/**
packages/theme/base/src/page/base-config-page.less
packages/toolbars/themeSwitch/src/Main.vue
packages/common/package.json
packages/configurator/package.json
Minor refactoring: added stricter checks (using isRef), updated options structure, modified CSS variable calculations, changed variable declarations (from let to const), and updated dependency versions.

Sequence Diagram(s)

sequenceDiagram
    participant U as User
    participant PP as PluginPanel Component
    participant LP as useLayout Composable

    U->>PP: Initiates drag on resizer (right/left)
    PP->>LP: Call onMouseDownRight/onMouseDownLeft (throttled)
    LP-->>PP: Update panel width and fixed panel state
    PP->>U: Render panel with updated dynamic styles
Loading
sequenceDiagram
    participant U as User
    participant PR as PluginRightMenu Component
    participant Layout as useLayout (for context)

    U->>PR: Right-click on a plugin item
    PR->>PR: Execute showContextMenu (calculate position, set visibility)
    PR->>U: Display context menu with options (hide/switch align)
Loading

Possibly related PRs

  • optimize:Cj subsequent optimization #842: The changes in the main PR are related to those in the retrieved PR as both involve modifications to the getMoveDragBarState function and the application of the not-selected class based on its state, enhancing the visual representation of components.
  • refactor:插件面板优化功能 #632: The changes in the main PR are related to those in the retrieved PR as both involve modifications to the <plugin-panel> component, including the addition of new props and enhancements to its functionality, specifically regarding fixed panels and layout management.
  • fix: fix materials panel #909: The changes in the main PR are related to the modifications in the retrieved PR as both involve enhancements to the functionality of panel components, specifically addressing the management of fixed panel states and their interactions within the user interface.

Suggested labels

ospp-2024

Suggested reviewers

  • hexqi
  • chilingling

Poem

I'm just a bunny on a joyful spree,
Hopping through code with glee, you see.
New panels dance and layouts shine,
Drag and drop—oh, how divine!
In every change, the magic is spun,
CodeRabbit cheers: our work's begun!
🐰✨

✨ 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.
    • Generate unit testing code for this file.
    • 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 generate unit testing code for this file.
    • @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 generate unit testing code.
    • @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.

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 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.

@github-actions github-actions bot added the enhancement New feature or request label Mar 14, 2025
Copy link
Contributor

@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: 5

🧹 Nitpick comments (19)
packages/register/src/constants.js (1)

49-49: Inline Comment Clarity and Consistency Check

The added inline comment (// 页面 JS) provides useful context about the Page property and its association with page-related JavaScript. Ensure that this style of inline commentary aligns with your project's overall guidelines, especially if other properties might benefit from similar annotations for consistency and clarity.

packages/common/component/PluginRightMenu.vue (1)

143-183: Added styling for context menu.

The CSS properly styles the context menu with appropriate positioning, shadows, and hover effects. One minor issue is the comment on line 145 about "importing B's CSS style" which appears to be a development note that should be removed.

Consider removing the comment "/* 引入B的CSS样式 */" which appears to be a development note.

packages/plugins/schema/src/Main.vue (1)

127-128: TODO comment for future implementation.

There's a TODO comment regarding history stack implementation. Consider creating a separate task to track this feature enhancement.

packages/plugins/block/src/Main.vue (3)

12-14: Check naming consistency between “add-page” and “新建区块”

The SVG icon name “add-page” differs from the tooltip text “新建区块,” which can confuse future contributors.

-<svg-button name="add-page" placement="bottom" tips="新建区块" @click="openBlockAdd"></svg-button>
+<svg-button name="add-block" placement="bottom" tips="新建区块" @click="openBlockAdd"></svg-button>

15-119: Consider extracting sub-components for maintainability

This portion of the template is extensive. Splitting the category/group selection, popover, and block-list display into smaller components can shorten the file, reduce complexity, and improve unit test coverage.


220-224: Provide a default value for fixedPanels

Without a default, referencing fixedPanels in parent or child components could cause errors when it’s undefined.

 props: {
   fixedPanels: {
     type: Array,
+    default: () => []
   }
 },
packages/plugins/state/src/Main.vue (2)

12-77: Break down large content section for clarity

The entire data-source logic is placed under the content slot. Consider splitting the left panel, search bar, and right panel configuration into smaller components to ease maintenance.


118-121: Add a default for fixedPanels

As with similar components, consider providing a default array to avoid potential undefined references.

 props: {
   fixedPanels: {
     type: Array,
+    default: () => []
   }
 }
packages/common/component/PluginSetting.vue (1)

103-111: Validate the align prop

Since align is a string, restricting it or documenting allowed values could prevent misconfiguration (e.g., 'leftTop', 'rightBottom', 'leftBottom', etc.).

 align: {
   type: String,
   default: 'leftTop'
+  // Consider validating or enumerating possible values here
 },
packages/layout/src/Main.vue (3)

12-12: Consider unifying the prop names.
You are passing both :plugins="registry.plugins" and :plugin-list="pluginList" to design-plugins. This is slightly duplicative and could cause confusion. Consider using a single source of truth or a more intuitive naming convention to reduce potential inconsistencies.

Also applies to: 14-14


77-82: Evaluate naming consistency for the alignment methods.
changeLeftAlign calls right.value?.changeAlign(pluginId) and vice versa. Although it works logically, consider making the naming more intuitive to reflect moving plugins in or out of each side.


84-118: Wrap localStorage usage in error handling.
Storing plugin data in localStorage is convenient but can fail in some scenarios (e.g., private browsing). Consider adding a try/catch around localStorage.setItem to gracefully handle potential errors.

+ try {
     localStorage.setItem('plugin', JSON.stringify(plugin))
+ } catch (e) {
+   console.warn('Failed to store plugin data in localStorage:', e)
+ }
  initPluginStorageReactive(plugin)
packages/layout/src/DesignPlugins.vue (1)

42-65: Refactor potential for shared logic with top nav.
The bottom nav code is nearly identical to the top nav code. Consider extracting common logic to a helper function or shared component to reduce duplication.

packages/layout/src/DesignSettings.vue (3)

20-36: Use stable keys in v-for iteration.
v-for="(item, index) in settingPlugins" :key="index" can lead to re-rendering issues when the array changes. It is safer to rely on a unique identifier within item (like item.id) as the key if possible.

Consider this diff:

-<div v-for="(item, index) in settingPlugins" :key="index">
+<div v-for="(item, index) in settingPlugins" :key="item.id || index">

108-136: Ensure functions handle uninitialized states.
The methods close, switchAlign, changeAlign, setRender, and clickMenu depend on an existing plugin ID or item. Validate if item might be null or undefined, especially in dynamic plugin scenarios, to avoid runtime errors.

If needed, add null checks or default parameters in these methods to handle edge cases gracefully.


211-295: Recommend clarifying nav-panel display logic.
#tiny-engine-nav-panel toggles .completed class to manage display: block;. If other logic sets display: none; or modifies z-index, it might conflict. Consider consolidating the display logic into a single style or a computed property to avoid drift.

packages/layout/src/composable/useLayout.js (3)

29-31: Fine-grained plugin event management.
pluginEvent: 'all' is a simple approach to unify event handling. Ensure that you properly handle future states if partial events or event scoping become required.


71-84: Unified menu visibility toggles.
leftMenuShownStorage and rightMenuShownStorage effectively maintain persistent visibility states between sessions. Confirm there isn’t an overlap if a user tries to hide both simultaneously, which might block re-opening the UI.


85-97: Refined approach to changing fixed panels.
changeLeftFixedPanels and changeRightFixedPanels handle toggling with arrays. Consider adding a check to prevent the same plugin from appearing in both left and right panels if that isn’t allowed.

📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 46dbbe8 and bf4d156.

📒 Files selected for processing (54)
  • packages/canvas/DesignCanvas/src/DesignCanvas.vue (4 hunks)
  • packages/common/component/PluginPanel.vue (5 hunks)
  • packages/common/component/PluginRightMenu.vue (1 hunks)
  • packages/common/component/PluginSetting.vue (9 hunks)
  • packages/common/component/index.js (1 hunks)
  • packages/layout/package.json (1 hunks)
  • packages/layout/src/DesignPlugins.vue (10 hunks)
  • packages/layout/src/DesignSettings.vue (2 hunks)
  • packages/layout/src/Main.vue (4 hunks)
  • packages/layout/src/composable/useLayout.js (5 hunks)
  • packages/plugins/block/meta.js (1 hunks)
  • packages/plugins/block/src/BlockSetting.vue (4 hunks)
  • packages/plugins/block/src/Main.vue (5 hunks)
  • packages/plugins/bridge/meta.js (1 hunks)
  • packages/plugins/bridge/src/BridgeSetting.vue (4 hunks)
  • packages/plugins/bridge/src/Main.vue (4 hunks)
  • packages/plugins/datasource/meta.js (1 hunks)
  • packages/plugins/datasource/src/DataSourceForm.vue (6 hunks)
  • packages/plugins/datasource/src/DataSourceGlobalDataHandler.vue (3 hunks)
  • packages/plugins/datasource/src/DataSourceRecordList.vue (3 hunks)
  • packages/plugins/datasource/src/DataSourceRemotePanel.vue (5 hunks)
  • packages/plugins/datasource/src/Main.vue (5 hunks)
  • packages/plugins/help/meta.ts (1 hunks)
  • packages/plugins/help/src/HelpIcon.vue (1 hunks)
  • packages/plugins/i18n/meta.js (1 hunks)
  • packages/plugins/i18n/src/Main.vue (4 hunks)
  • packages/plugins/materials/meta.js (1 hunks)
  • packages/plugins/materials/src/meta/block/src/BlockGroupPanel.vue (4 hunks)
  • packages/plugins/materials/src/meta/layout/src/Main.vue (3 hunks)
  • packages/plugins/page/meta.js (1 hunks)
  • packages/plugins/page/src/Main.vue (3 hunks)
  • packages/plugins/page/src/PageFolderSetting.vue (4 hunks)
  • packages/plugins/page/src/PageSetting.vue (4 hunks)
  • packages/plugins/robot/meta.js (1 hunks)
  • packages/plugins/schema/meta.js (1 hunks)
  • packages/plugins/schema/src/Main.vue (5 hunks)
  • packages/plugins/script/meta.js (1 hunks)
  • packages/plugins/script/src/Main.vue (5 hunks)
  • packages/plugins/state/meta.js (1 hunks)
  • packages/plugins/state/src/Main.vue (5 hunks)
  • packages/plugins/tree/meta.js (1 hunks)
  • packages/plugins/tree/src/Main.vue (3 hunks)
  • packages/plugins/tutorial/meta.js (1 hunks)
  • packages/register/src/common.js (2 hunks)
  • packages/register/src/constants.js (1 hunks)
  • packages/settings/events/index.js (1 hunks)
  • packages/settings/events/meta.js (1 hunks)
  • packages/settings/events/src/Main.vue (1 hunks)
  • packages/settings/props/meta.js (1 hunks)
  • packages/settings/props/src/Main.vue (1 hunks)
  • packages/settings/styles/meta.js (1 hunks)
  • packages/settings/styles/src/Main.vue (6 hunks)
  • packages/theme/base/src/page/base-config-page.less (1 hunks)
  • packages/toolbars/themeSwitch/src/Main.vue (1 hunks)
🔇 Additional comments (199)
packages/plugins/script/src/Main.vue (8)

2-30: Improved component architecture with the new plugin-panel implementation.

The template has been restructured to use the <plugin-panel> component, which provides better organization through named slots for the header and content sections. This aligns with the PR objective of implementing a unified logic for plugin panels and will help maintain consistency across the application.


4-5: Flexible panel configuration properties are now properly supported.

The addition of the :fixed-name="PLUGIN_NAME.Page" and :fixedPanels="fixedPanels" props enables the new flexible layout functionality, allowing this panel to participate in the drag-and-drop and fixed/floating state management system.


34-37: Enhanced state management with Composition API.

The addition of reactive and provide imports, along with the use of useLayout hook, indicates a shift towards Vue's Composition API for more reactive state management. This is a good practice that enhances component interactivity.


53-58: Component registration and props definition are properly structured.

The PluginPanel component registration and the fixedPanels prop definition are correctly implemented, with appropriate type checking for the Array type.


65-70: State sharing approach using provide/inject pattern.

The implementation of reactive panelState and providing it to child components follows Vue's recommended pattern for sharing state across component trees. This is a good approach for maintaining state consistency within the plugin panel hierarchy.


111-111: Plugin name constant properly exposed to template.

The PLUGIN_NAME constant from the useLayout hook is correctly returned for use in the template.


130-151: Well-structured styling for the notification indicator and save button.

The styling for the .icon-wrap, .tiny-button, and .red classes is clean and maintainable, providing visual feedback about unsaved changes through the red dot indicator. The positioning and sizing are appropriate for the UI design.


154-157: Editor content styling provides appropriate spacing.

The padding and height calculations for the code editor content provide sufficient space while maintaining a clean appearance, which is important for a good user experience when working with code.

packages/plugins/page/meta.js (1)

6-6: Alignment property standardized to 'leftTop'

This change is part of the standardization of alignment properties across plugin meta files to support the new flexible layout system mentioned in the PR objectives.

packages/plugins/tutorial/meta.js (1)

6-6: Alignment property standardized for plugin positioning

The align property has been updated from 'bottom' to 'leftBottom', which aligns with the PR objective to standardize plugin positioning and enable more flexible layout management.

packages/plugins/materials/meta.js (1)

6-6: Alignment property standardized for materials plugin

The align property has been updated from 'top' to 'leftTop', consistent with the standardization across other plugins to support the new flexible layout system.

packages/common/component/index.js (1)

17-17: New component export added to support plugin context menu

The export of PluginRightMenu is a crucial addition that enables the right-click context menu functionality mentioned in the PR objectives, supporting plugin repositioning and visibility controls.

packages/plugins/datasource/meta.js (1)

5-5: Alignment property standardized for datasource plugin

The align property has been updated from 'top' to 'leftTop', consistent with the pattern applied to other plugins, supporting the new flexible layout system.

packages/plugins/block/meta.js (1)

5-5: Alignment property standardized to new naming convention

The align property has been updated from 'top' to 'leftTop' as part of standardizing alignment properties across plugins for the new flexible layout system.

packages/plugins/robot/meta.js (1)

8-8: Alignment property updated to use new position convention

The align property has been changed from 'bottom' to 'leftBottom', consistent with the standardization of alignment properties across all plugins to support the new flexible layout system.

packages/plugins/bridge/meta.js (1)

5-5: Alignment property standardized to new naming convention

The align property has been updated from 'top' to 'leftTop', following the same pattern as other plugins to support the new flexible layout implementation.

packages/plugins/help/src/HelpIcon.vue (1)

157-157: DOM element reference updated for component settings guide

The domElement selector has been updated from '#tiny-right-panel' to '#rightTop' to reflect the new DOM structure introduced by the flexible layout implementation. This ensures the help guide correctly targets the right panel in the new UI.

packages/plugins/i18n/meta.js (1)

5-6: LGTM: Alignment and width properties updated for flexible layout

The changes to the alignment property from 'top' to 'leftTop' and the addition of a width property (600) align with the PR objective of implementing a flexible layout for plugin panels. These property changes will enable the plugin to properly position itself in the new layout system.

packages/plugins/schema/meta.js (1)

6-7: LGTM: Alignment and width properties updated for flexible layout

The alignment property has been updated from 'bottom' to 'leftBottom' and a width property of 600 has been added. These changes are consistent with the standardization of alignment specifications across plugins for the new flexible layout system.

packages/settings/styles/meta.js (1)

6-7: LGTM: Alignment and icon properties updated for flexible layout

The alignment property has been changed from 'left' to 'rightTop', positioning this panel on the right side of the interface, which differs from the left-side positioning of other plugins. Additionally, the icon has been updated from an empty string to 'display-inline', providing a visual indicator for this setting.

packages/plugins/help/meta.ts (2)

5-5: Added meaningful title for the Help plugin

The title has been updated from an empty string to '帮助' (meaning "Help" in Chinese), which improves the user interface by providing clear labeling for this plugin.


8-8: Standardized alignment property

The alignment property has been changed from 'bottom' to 'leftBottom', providing more precise positioning control. This change is consistent with the PR objective of implementing a unified layout logic for plugins.

packages/settings/props/meta.js (2)

5-5: Updated alignment to right side panel

Changed alignment from 'left' to 'rightTop', which is consistent with the PR objective of restructuring the display logic for the right-side plugin panel.


7-7: Added appropriate icon for properties panel

Added 'form' as the icon, which visually represents the purpose of this panel better than the previous empty string.

packages/settings/events/meta.js (2)

5-5: Updated alignment to right side panel

Changed alignment from 'left' to 'rightTop', maintaining consistency with other settings panels in the right panel structure.


7-7: Added appropriate icon for events panel

Added 'target' as the icon, which provides a visual indicator for the events functionality, improving UI clarity.

packages/plugins/script/meta.js (2)

6-6: Standardized alignment property

The alignment has been changed from 'top' to 'leftTop', following the same pattern as other plugins in this PR, which contributes to the unified layout logic implementation.


7-7: Added width property for draggable panel support

A width value of 600 has been added, which supports the PR objective of enabling users to manually adjust panel width through dragging by providing a default width.

packages/register/src/common.js (1)

12-12: Enhanced object validation to avoid processing Vue refs

The changes add a check to prevent Vue reference objects from being treated as regular objects during registry generation. This is important to prevent potential infinite recursion or undesired behavior when processing the registry.

This change is a good defensive programming practice that handles Vue's reactivity system properly.

Also applies to: 164-164

packages/theme/base/src/page/base-config-page.less (1)

43-43: Fine-tuned collection panel width calculation

The change from 100vw to 99vw in the collection panel width calculation subtly reduces the panel width. This adjustment likely prevents potential horizontal scroll issues that could occur at edge cases.

This is a subtle but effective adjustment to improve the layout's stability.

packages/settings/events/index.js (1)

23-23: Flattened options object structure for better access

The options structure has been changed from a nested object with commonEvents to a flat merged object using Object.assign(). This flattening makes the properties from both commonEvents and metaData.options directly accessible without an additional nesting level.

This simplifies property access and aligns with the new flexible layout implementation for plugins.

packages/canvas/DesignCanvas/src/DesignCanvas.vue (3)

2-2: Added conditional user interaction blocker during drag operations

A new conditional class binding has been added that applies the 'not-selected' class when getMoveDragBarState() returns true. This class disables pointer events and user selection, effectively blocking interaction with the canvas during drag operations.

This prevents unwanted interactions with the canvas while dragging, improving the user experience.


70-71: Added layout state management function

The getMoveDragBarState function from the useLayout composable has been imported and exported from the component's setup. This function determines when drag operations are active.

This addition properly integrates with the new flexible layout system being implemented in this PR.

Also applies to: 280-280


291-296: Added critical CSS to disable interactions during drag

A new scoped style for the .not-selected class has been added that disables pointer events and user selection. This CSS is applied conditionally when drag operations are active.

The CSS implementation is clean and effectively prevents interaction with the canvas during drag operations, which is essential for a good user experience.

packages/plugins/page/src/PageFolderSetting.vue (4)

2-8: Good addition of layout-related properties to plugin-setting

The addition of :fixed-name="PLUGIN_NAME.AppManage" and :align="align" attributes enables this component to work with the new flexible layout system, allowing it to maintain proper positioning and alignment within the UI.


36-41: LGTM - Proper imports for the new layout functionality

The addition of computed from Vue and useLayout from the meta-register package provides the necessary utilities to support the dynamic alignment features.


93-94: Well-structured implementation of layout integration

The extraction of PLUGIN_NAME and getPluginByLayout from the useLayout composable and the creation of a computed property for alignment provides reactive positioning capability, which aligns with the PR's goal of implementing a flexible layout for plugin panels.


209-212: LGTM - Properly exposing layout properties to the template

The addition of align and PLUGIN_NAME to the returned object makes these properties available in the template, completing the implementation of the flexible layout feature for this component.

packages/plugins/datasource/src/DataSourceRecordList.vue (3)

6-7: Good implementation of layout properties for DataSourceRecordList

Adding :fixed-name="PLUGIN_NAME.Collections" and :align="align" attributes to the plugin-setting component enables this component to participate in the flexible layout system, maintaining consistency with other plugin components.


127-128: LGTM - Proper layout implementation with computed binding

Extracting PLUGIN_NAME and getPluginByLayout from useLayout and creating a computed property for alignment provides the necessary reactivity for dynamic positioning, which is essential for the flexible layout feature.


565-566: Well-implemented exposure of layout properties to template

Properly adding align and PLUGIN_NAME to the returned object makes these properties available in the template, ensuring the component can use the flexible layout system.

packages/plugins/datasource/src/DataSourceRemotePanel.vue (4)

5-7: Good addition of alignment and styling for DataSourceRemotePanel

Adding the plugin-datasource class and :align="align" attribute enhances the plugin-setting component with proper styling and positioning capabilities, which is consistent with the PR's flexible layout objectives.


56-65: LGTM - Proper imports for layout functionality

Adding computed from Vue and including useLayout in the imports provides the necessary tools for implementing the dynamic layout features.


118-120: Well-structured layout implementation with reactive properties

The extraction of layout-related utilities and creation of a computed property for alignment provides the necessary reactivity for the panel's positioning, supporting the PR's flexible layout goals.


228-228: Proper exposure of the align property to the template

Adding align to the returned object makes this property available in the template, completing the implementation of the flexible layout feature for this component.

packages/plugins/datasource/src/DataSourceForm.vue (5)

2-8: Good implementation of layout attributes for DataSourceForm

The addition of the plugin-datasource class and layout-related attributes (:fixed-name and :align) enables this component to properly integrate with the flexible layout system, maintaining consistency with other plugin components.


36-36: LGTM - Added computed import for reactive properties

Adding the computed import from Vue enables the creation of reactive properties needed for the dynamic layout system.


100-102: Well-implemented layout integration with computed binding

Extracting layout utilities and creating a computed property for alignment provides the necessary reactivity for dynamic positioning, which is essential for the flexible layout feature.


150-152: Good improvement to watcher configuration

Adding { immediate: true } to the watch configuration ensures that the watcher runs immediately after creation, which is important for properly initializing the component's state based on incoming props.


260-261: Properly exposed layout properties to the template

Adding align and PLUGIN_NAME to the returned object makes these properties available in the template, enabling the component to utilize the flexible layout system.

packages/plugins/tree/src/Main.vue (3)

2-8: Improved panel component integration with the flexible layout system.

The plugin-panel component now includes standard props for fixed panel management (fixed-name and fixedPanels), which integrates well with the new flexible layout system mentioned in the PR objectives.


39-39: Good update to imports for panel state management.

Added provide and nextTick imports from Vue to support the new panel state management pattern.


58-68: Well-implemented panel state management.

The setup function now properly accepts the emit parameter, creates a reactive panelState object, and uses provide to make it available to child components. This approach is consistent with other plugins in the codebase and enables more flexible event handling.

packages/plugins/materials/src/meta/layout/src/Main.vue (3)

2-7: Consistent implementation of flexible panel layout.

The plugin-panel now includes the necessary props for the flexible layout system (fixed-name and fixedPanels), maintaining consistency with other plugin implementations.


23-23: Good import refinement for plugin naming standardization.

Updated import statement to include META_APP as PLUGIN_NAME, which aligns with the standardized approach to plugin naming across components.


83-83: Proper exposure of PLUGIN_NAME to the template.

Added PLUGIN_NAME to the returned values from the setup function, making it accessible in the template for the fixed-name prop.

packages/plugins/block/src/BlockSetting.vue (4)

6-7: Enhanced plugin setting with alignment and fixed-name props.

The plugin-setting component now includes both :align="align" and :fixed-name="PLUGIN_NAME.BlockManage" props, enabling better integration with the flexible layout system and proper alignment handling.


91-98: Organized imports for layout management.

The import statement is properly updated to include useLayout and other necessary modules, with good organization using multi-line import.


164-166: Well-implemented layout integration.

Added PLUGIN_NAME constant and computed align property that uses getPluginByLayout to dynamically determine alignment based on the current layout configuration.


292-293: Proper exposure of layout variables.

Added align and PLUGIN_NAME to the returned values from the setup function, making them accessible in the template.

packages/plugins/page/src/Main.vue (7)

2-10: Well-structured plugin panel with flexible layout support.

The plugin-panel component now includes proper class, fixed-name, and fixedPanels props, along with documentation features (docsUrl and isShowDocsIcon). This implementation aligns perfectly with the PR's goal of unified logic for panel states.


11-26: Properly implemented header actions for page management.

The header slot contains well-positioned SVG buttons for creating new folders and pages, improving the user experience for page management.


28-38: Clean content area implementation with page tree.

The content slot contains the page-tree component with appropriate props and event handlers, maintaining a clean separation of concerns.


47-47: Proper import for layout management.

Updated import statement to include useLayout, necessary for the flexible layout implementation.


79-81: Added required prop for flexible panels.

Added fixedPanels prop with proper type definition, enabling the component to accept an array of fixed panels.


83-94: Well-implemented panel state management.

The setup function now properly accepts the emit parameter, extracts the PLUGIN_NAME constant, and creates a reactive panelState object with the emit function, providing it to child components for consistent event handling.


178-178: Proper exposure of PLUGIN_NAME to the template.

Added PLUGIN_NAME to the returned values from the setup function, ensuring it's accessible for the fixed-name prop in the template.

packages/plugins/datasource/src/Main.vue (6)

2-31: Standardized plugin panel structure with enhanced configurability

The template has been restructured to use <plugin-panel> with new props :fixed-name, :fixedPanels, and :isShowDocsIcon. This aligns with the PR objective of implementing a unified logic for floating and fixed states of the plugin panel.


52-52: Updated imports to support layout functionality

The import statements have been appropriately updated to include necessary components and hooks, particularly useLayout from the meta-register, which is essential for the new flexible layout functionality.

Also applies to: 59-59, 64-65


80-86: Added support for fixed panels via props

New props have been added to accept fixedPanels as an array type, enabling the component to participate in the new flexible layout system.


87-97: Enhanced component communication with reactive state

The setup function now creates and provides a reactive panelState object that includes the emit function, establishing a pattern for component communication that can be reused across the application.

Also applies to: 98-103


153-164: Properly exposing PLUGIN_NAME in the return statement

The PLUGIN_NAME constant obtained from useLayout() is correctly returned from the setup function, making it available to the template for consistent plugin identification.


174-175: Improved responsive styling for add-data-source button

The addition of width: calc(100% - 24px) ensures the button properly adapts to its container width, improving the responsive design of the component.

packages/plugins/datasource/src/DataSourceGlobalDataHandler.vue (4)

2-24: Restructured plugin panel with standardized props

The template has been improved by removing unnecessary wrapper div and adding layout-related props (:align, :fixed-name) to the <plugin-setting> component. This aligns with the PR objective of implementing a more consistent layout system.


28-31: Updated imports to support computed alignment

The import statement now includes computed from Vue and useLayout from the meta-register, providing the necessary tools for dynamic alignment calculation.


57-59: Implemented dynamic alignment based on layout configuration

The component now uses a computed align property derived from the layout configuration, allowing it to dynamically position itself based on the overall layout system.


99-102: Properly exposing alignment and plugin name

The align computed property and PLUGIN_NAME constant are correctly returned from the setup function, making them available to the template for consistent plugin identification and positioning.

packages/settings/styles/src/Main.vue (8)

2-10: Implemented flexible plugin panel with collapse functionality

The template now uses <plugin-panel> with props for fixed panels and collapse functionality, which aligns with the PR objective of creating a more flexible layout system.


10-77: Structured content within template slot

The style editor content is now properly organized within the #content slot of the plugin panel, maintaining the existing functionality while benefiting from the new layout system.


81-81: Updated imports to support layout functionality

The import statements now include necessary Vue features (reactive, provide) and the PluginPanel component, providing the foundation for the flexible layout system.

Also applies to: 83-83, 99-99


120-124: Added support for fixed panels via props

The component now accepts fixedPanels as a prop, allowing it to participate in the flexible layout system being implemented across the application.


138-138: Using reactive ref for collapse state

The isCollapsed state is now a reactive reference, and PLUGIN_NAME is obtained from useLayout(), improving state management and integration with the layout system.

Also applies to: 145-146


147-151: Enhanced component communication with reactive state

A reactive panelState object is created and provided to child components, establishing a consistent pattern for component communication.


223-226: Added method to manage collapse state

The new updateCollapseStatus method properly manages the collapse state of the panel, supporting the PR objective of enhancing the interactivity of the plugin panel.


239-240: Properly exposing new functionality in the return statement

The updateCollapseStatus method and PLUGIN_NAME constant are correctly returned from the setup function, making them available to the template.

packages/settings/events/src/Main.vue (6)

2-8: Implemented flexible plugin panel structure

The template now uses <plugin-panel> with appropriate props for fixed panels and plugin identification, which aligns with the PR objective of implementing a more consistent and flexible layout system.


9-19: Preserved original functionality within content slot

The existing <tiny-collapse> component is now properly contained within a slot of the plugin panel, maintaining functionality while benefiting from the new layout system.


23-28: Updated imports to support new layout functionality

The import statements now include necessary Vue composition API features and the PluginPanel component, along with the useLayout hook for accessing layout information.


30-31: Using layout plugin name constants

The component correctly obtains PLUGIN_NAME from the useLayout hook, ensuring consistent plugin identification across the application.


33-35: Added support for fixed panels via props

The component now accepts fixedPanels as a prop using the defineProps function, allowing it to participate in the flexible layout system.


37-43: Enhanced component communication with reactive state

The component establishes a reactive panelState object that includes the emit function and provides it to child components, creating a consistent pattern for component communication.

packages/plugins/i18n/src/Main.vue (5)

2-10: Implemented fixed panel configuration for flexible layout.

The plugin-panel now includes new props :fixed-name="PLUGIN_NAME.I18n" and :fixedPanels="fixedPanels" which enables it to participate in the new flexible layout system. This allows users to control the panel's positioning and visibility as described in the PR objectives.


124-124: New import for layout functionality.

Added necessary imports including provide from Vue and useLayout from meta-register to support the new layout management functionality.

Also applies to: 130-136


156-160: Added fixedPanels prop for panel configuration.

This new prop allows the component to receive information about fixed panels, which is essential for implementing the unified logic for the floating and fixed states mentioned in the PR objectives.


161-161: Implemented reactive state sharing via provide/inject pattern.

The setup function now correctly receives props and emit, and establishes a reactive state with the emit function that is provided to child components. This enables proper event propagation throughout the component hierarchy.

Also applies to: 169-174


422-423: Exposed PLUGIN_NAME to template.

Now returning PLUGIN_NAME from setup, making it available in the template for the fixed-name prop of the plugin-panel.

packages/plugins/bridge/src/Main.vue (5)

2-9: Implemented fixed panel configuration for resource management.

The plugin-panel now includes new props to participate in the flexible layout system, maintaining consistency with other plugin components and allowing users to control the panel's positioning.


21-23: Added necessary imports for reactive state management.

Imports now include reactive and provide from Vue, and useLayout from meta-register, supporting the new layout functionality.


36-40: Added fixedPanels prop for consistency.

This prop definition matches other plugin components, ensuring a consistent API across the plugin system.


41-41: Implemented event propagation and state sharing.

The setup function now uses the provide/inject pattern with a reactive object to share the emit function with child components, and extracts PLUGIN_NAME from useLayout.

Also applies to: 46-52


66-67: Exposed PLUGIN_NAME to template.

Making PLUGIN_NAME available in the template, which is required for the fixed-name prop.

packages/settings/props/src/Main.vue (5)

2-19: Restructured component using plugin-panel for consistent layout.

The template has been refactored to use the plugin-panel component, which provides a unified layout and behavior consistent with other plugin components. This change is essential for implementing the flexible panel layout described in the PR objectives.


22-24: Updated imports to support new panel layout.

Added imports for reactive state management and layout utilities, including the PluginPanel component.


32-34: Registered PluginPanel component.

Properly registered the PluginPanel component that's used in the template.


35-35: Implemented state sharing for panel management.

Setup function now includes props and emit parameters, and establishes the reactive state sharing pattern consistent with other plugin components.

Also applies to: 40-46


54-55: Exposed PLUGIN_NAME for template usage.

Now returning PLUGIN_NAME from setup, making it available for the fixed-name prop in the template.

packages/common/component/PluginRightMenu.vue (5)

1-26: Implemented context menu for plugin management.

This template creates a context menu that appears at specified coordinates, allowing users to:

  1. Hide specific plugins
  2. Switch plugin alignment between left and right sides
  3. Toggle visibility of multiple plugins via checkboxes

The implementation includes proper conditional rendering and positioning logic, addressing the PR objective of enabling users to control plugins' visibility and position.


28-54: Created reactive state management for context menu.

The component properly defines props for the plugin list and alignment, and sets up a reactive context menu state object to track visibility, position, and the currently selected item. This supports the PR's objective of allowing users to reposition plugins.


55-84: Implemented position-aware context menu display.

The showContextMenu function intelligently positions the menu based on available screen space, ensuring it remains visible when opened near the bottom of the viewport. This provides a better user experience for the new plugin management features.


90-114: Added plugin management actions.

These methods handle the core functionality of the context menu:

  • hidePlugin: Toggles visibility of the selected plugin
  • switchAlign: Emits an event to change plugin alignment
  • changeShowState: Updates the visibility state of a plugin

These functions directly support the PR objective of allowing users to control plugin positioning and visibility.


116-128: Implemented proper click-outside behavior.

The component correctly adds and removes event listeners during its lifecycle to close the context menu when clicking outside, following best practices for modal interfaces.

packages/plugins/bridge/src/BridgeSetting.vue (4)

2-2: The plugin-setting component now supports flexible layout configuration.

The addition of :align="align" and :fixed-name="PLUGIN_NAME.Bridge" properties enhances the plugin panel's configurability, allowing it to participate in the new flexible layout system. This is consistent with the PR's objective to implement unified logic for floating and fixed states.


115-115: Updated imports to support layout functionality.

The import statement now includes useLayout from the meta-register package, which provides the necessary functionality for the flexible layout system.


154-155: Layout hooks properly initialized in setup.

The useLayout hook is correctly used to extract the plugin name constant and the layout retrieval function. The computed align property will reactively update whenever the layout configuration changes.


279-281: Added new properties to component return object.

The align computed property and PLUGIN_NAME constant are correctly exposed to the template, enabling the flexible layout features.

packages/plugins/materials/src/meta/block/src/BlockGroupPanel.vue (4)

2-9: Enhanced plugin-setting component with flexible layout support.

The addition of :align="align" and :fixed-name="PLUGIN_NAME.Materials" properties enables this component to participate in the new flexible layout system. This implementation supports the PR objective of allowing users to adjust panel positioning and visibility.


37-37: Updated imports to include necessary Vue reactivity and layout features.

The import statements now properly include computed from Vue and useLayout from the meta-register package, providing the required functionality for the flexible layout system.

Also applies to: 43-43


128-129: Layout hooks correctly initialized in setup.

The useLayout hook is properly used to extract the plugin name constant and the layout retrieval function. The computed align property will reactively update whenever the layout configuration changes.


285-292: Updated component's return object with layout properties.

The align computed property and PLUGIN_NAME constant are correctly added to the setup function's return object, making them available to the template.

packages/plugins/page/src/PageSetting.vue (4)

2-8: Enhanced plugin-setting component with flexible layout configuration.

The addition of :fixed-name="PLUGIN_NAME.AppManage" and :align="align" properties enables this component to participate in the flexible layout system. This implementation supports the PR's objective to unify floating and fixed states logic.


63-63: Added computed import for reactive alignment support.

The import statement has been updated to include the computed function from Vue, which is necessary for creating the reactive align property.


145-146: Layout hooks properly initialized in setup.

The useLayout hook is correctly used to extract the plugin name constant and the layout retrieval function. The computed align property will reactively update whenever the layout configuration changes.


393-394: Added layout properties to component's return object.

The align computed property and PLUGIN_NAME constant are correctly added to the setup function's return object, making them available to the template.

packages/plugins/schema/src/Main.vue (7)

2-39: Migrated to plugin-panel component with flexible layout support.

The implementation has been refactored to use the <plugin-panel> component instead of custom divs, providing a more consistent UI across plugins with built-in support for the flexible layout system. This change supports the PR objectives of unified plugin panel logic and consistent behavior.

The structure now properly uses named slots for header and content sections, improving maintainability and alignment with the component architecture.


43-47: Updated imports to support plugin panel and layout functionality.

The import statements have been updated to include necessary dependencies:

  • provide from Vue for passing state to child components
  • PluginPanel from common components
  • useLayout from meta-register for flexible layout support

This ensures all required functionality is available for the plugin panel implementation.


61-65: Added fixedPanels prop to support panel management.

The component now accepts a fixedPanels prop which allows for dynamic management of fixed panel states. This enhancement aligns with the PR objective of implementing unified logic for floating and fixed states of the plugin panel.


75-75: Added layout hook for plugin name access.

The useLayout hook is correctly used to extract the plugin name constant, which is needed for the flexible layout system.


77-81: Implemented panel state with context sharing.

A reactive panelState object is created and provided to the component context, facilitating communication between parent and child components. This implementation pattern enhances the component's extensibility.


15-21: Hidden schema import functionality.

The UI includes hidden elements for schema import functionality (a popover and a footer button). If this is intentional (feature flagging), this is fine. If these are meant to be implemented as part of this PR, they should be either completed or removed.

Could you clarify if the hidden schema import functionality is intentionally disabled or if it's a planned feature for a future PR?

Also applies to: 35-37


187-237: Updated styling to support plugin panel.

The CSS has been appropriately adjusted to work with the new component-based structure. The removal of specific header styles and adjustments to content height reflect the shift of styling responsibilities to the <plugin-panel> component.

packages/plugins/block/src/Main.vue (3)

2-11: Good use of <plugin-panel> props

These newly added props (:fixed-name, :fixedPanels, :docsUrl, etc.) integrate smoothly with the existing layout utilities. No immediate issues detected.


473-474: Margin style looks fine

Swapping margin: 12px 0; for margin-bottom: 12px; is a harmless refinement, aligning well if you no longer need top spacing.


273-280:

Details

✅ Verification successful

Verify the panelState injection

You’re providing panelState via provide('panelState', panelState). Ensure child components inject it under the same key and handle events properly.


🏁 Script executed:

#!/bin/bash
# Description: Search for all inject calls referencing 'panelState' in the codebase.
rg "inject\(['\"]panelState['\"]" -A 10

Length of output: 7975


PanelState Injection Verified
The provider in packages/plugins/block/src/Main.vue correctly sets up the panelState object with the emitEvent function. A search of the repository confirms that child components consistently inject it using the key 'panelState', and examples like those in PluginPanel.vue indicate that event handling (using panelState.emitEvent) works as expected.

packages/plugins/state/src/Main.vue (2)

2-11: Smooth transition to <plugin-panel>

Using <plugin-panel> with props like :fixed-name and :fixedPanels appears consistent with other components. No immediate issues found.


146-153: Ensure alignment logic covers multiple layouts

getPluginWidth and getPluginByLayout computations look correct for offsetting a right-side panel. If future layouts require additional top/bottom control, consider extending the logic or verifying it dynamically.

packages/common/component/PluginSetting.vue (3)

3-11: Dynamic alignment is clear

Using align-right and computed styles is a straightforward approach to positioning. Ensure the align logic gracefully handles all future expansions (e.g., top/bottom or diagonal align).


119-131: Confirm offset logic for second-panel usage

firstPanelOffset and alignStyle rely on getPluginWidth. If the panel’s width or position changes at runtime, ensure these computations update correctly without stale references.


154-159: Shadow class usage is consistent

Conditional application of shadow-right or shadow-left improves the UI feedback for different alignments.

packages/layout/src/Main.vue (10)

9-10: Looks good for conditional rendering of the left plugins.
The v-if="leftMenuShownStorage" and ref="left" references appear consistent with the rest of the code and should allow for controlled visibility and programmatic access to the component.


22-22: Right menu rendering approach is consistent.
Using v-if="rightMenuShownStorage" and ref="right" to control and reference the right panel mirrors the logic on the left-hand side, keeping the layouts symmetric.

Also applies to: 23-23


25-26: Props binding for the right panel is clear.
Providing :render-panel="settings.render", :plugin-list="pluginList", and @changeRightAlign="changeRightAlign" ensures the panel’s rendering logic is customizable, matching the left side pattern.

Also applies to: 28-28


42-42: Import statement is appropriate.
Bringing in ref from 'vue' is straightforward and necessary.


61-61: No concerns with the updated setup() signature.
The function signature effectively captures the relevant properties for the layout.


66-67: Destructuring from useLayout() looks valid.
This nicely organizes layout states and methods.


74-75: Reactivity references for left and right.
Using ref(null) for both left and right is a clean way to reference these child components.


121-127: Re-exported references improve clarity.
Exposing these parameters from setup fosters maintainability.


132-132: Returning settings from layoutState is consistent.
No issues spotted with the additional destructuring.


164-165: Flex display for .tiny-engine-right-wrap is appropriate.
This ensures the right panel aligns well for horizontal content arrangement.

packages/layout/src/DesignPlugins.vue (15)

4-6: Efficient use of drag-and-drop for top nav list.
Binding v-model="state.topNavLists", filtering, and grouping under "plugins" looks well-structured. This should simplify reordering.

Also applies to: 9-10


23-23: Context menu logic is well-placed.
Preventing default on right-click ensures the custom menu is displayed instead of the browser’s default context menu.


25-25: Conditional visibility of plugins.
v-if="getPluginShown(item.id)" is a clear approach for toggling plugin display states.


39-41: Separating the bottom nav list enhances clarity.
This layout structure improves user experience by distinctly managing top and bottom plugin lists.


69-88: Plugin container logic is comprehensive.
Wrapping the plugin panel and the “not-selected” class in a separate <div> helps isolate drag bar states and visual cues.


90-90: Right-click menu integration.
Including <plugin-right-menu> with references to the combined top/bottom lists is a neat way to maintain a single context menu for all left-side plugins.


101-101: Importing vue-draggable-next.
Bringing in the library is necessary to support the newly added drag features.


103-103: Consolidating additional components under a single import.
{ PublicIcon, PluginRightMenu } from @opentiny/tiny-engine-common helps maintain a consistent shared library approach.


138-146: Destructuring from useLayout() is well-organized.
Retrieving multiple layout helpers fosters modular design. Keep ensuring these remain cohesive across the codebase.


148-155: showContextMenu function handles various usage scenarios.
Handling both standard and item-specific context menus with the same function is flexible.


159-160: Dynamic assignment for top/bottom nav lists.
Using getPluginsByPosition centralizes retrieval logic and keeps code more maintainable.


168-171: Binding entries and icons in a single pass is clean.
This approach centralizes plugin metadata, improving readability.


185-185: Passing appropriate nav list references to parent events.
Index-based referencing ensures the correct plugin is identified across different alignment lists.


217-227: switchAlign method for moving plugins to the right side.
This function nicely delegates the alignment changes upward (emit('changeLeftAlign', id)) and calls dragPluginLayout.


257-261: Handling drag end across different sides.
Closing the panel if it’s moved to the opposite side is a logical approach to avoid unexpected states.

packages/common/component/PluginPanel.vue (20)

2-3: Responsive styling for the plugin panel.
Binding :style="{ width: panelWidth + 'px' }" and a configurable margin bottom helps adapt the panel’s layout dynamically.


12-22: Tooltip-based collapse icon is a great UI enhancement.
Having a light-effect tooltip for toggling collapse state improves discoverability while keeping the panel’s UI clean.


23-28: Fixed panel toggle.
Using a single button to toggle between fixed and non-fixed states is clear. Ensure that updates propagate consistently in the parent’s state.


32-34: Scrollable container.
Wrapping the main slot in a .scroll-content container with hidden scrollbars is user-friendly, especially for long plugin content.


36-37: Dual-sided resizers for flexible panel sizing.
Declaring .resizer-right and .resizer-left provides symmetrical resizing. This is helpful for panels on either side of the screen.

Also applies to: 38-38


42-42: Additional imports add clarity.
Pulling in inject, ref, computed, onMounted, provide, SvgButton, and Tooltip neatly organizes external dependencies.

Also applies to: 44-44, 47-47, 51-51, 53-54


83-109: Well-structured new props.
Props such as fixedPanels, fixedName, headerMarginBottom, and isShowCollapseIcon are expressive and improve panel configuration.


110-110: Emitting updateCollapseStatus fosters reactivity.
This allows parent components to respond to collapse changes immediately.


118-119: Constants for width boundaries.
MIN_WIDTH and MAX_WIDTH keep resizing logic straightforward and readable.


124-125: Computed icon name for collapsed state is intuitive.
Switching between 'collapse_all' and 'expand_all' clarifies the panel’s state at a glance.


127-127: Injection and panel fixing logic.
Providing isCollapsed and injecting panelState ensure consistent shared state. The fixPanel method delegates updates back to the layout state neatly.

Also applies to: 129-130


134-138: Retrieving plugin layout details.
getPluginWidth, changePluginWidth, and alignment checks are seamlessly integrated for a flexible panel design.


141-151: Responsive resizing logic.
Calculating newWidth based on mouse movement is cleanly done. Hard-limiting to MIN_WIDTH and MAX_WIDTH prevents awkward UI states.


153-173: Throttling enhances performance.
Using a custom throttle function prevents excessive calculations during drag.


175-177: Applying the throttled functions.
throttledMouseMoveRight and throttledMouseMoveLeft properly limit the frequency of redraws.


181-215: Comprehensive event handling for mouse up/down.
Removing event listeners after mouse release and toggling the cursor styles and dragging class are crucial for a polished drag UX.


217-220: Late DOM selection for resizers.
initResizerDOM() is a safe approach for hooking into the DOM after mount, preventing null references.


222-225: clickCollapseIcon triggers an emit.
This straightforward method updates the local collapsed state and notifies the parent seamlessly.


227-229: Resizer initialization on mount.
onMounted(() => { initResizerDOM() }) ensures the resizer elements exist before referencing them.


232-242: Returning the updated references.
Exposing these reactive states and methods from setup maintains a fully open interface for any parent usage.

packages/layout/src/DesignSettings.vue (7)

1-3: Use caution with pointer-events disabling when dragging.
Applying the not-selected class based on getMoveDragBarState() disables pointer events, which is typical for preventing undesired interactions while dragging. However, ensure the user experience remains consistent (e.g., no vital controls become accidentally non-interactive).

Do you have tests confirming that essential UI elements are still accessible when getMoveDragBarState() returns true?


5-16: Validate conditional rendering logic.
Using v-show="renderPanel && components[renderPanel]" is good for performance, but confirm that renderPanel always corresponds to a valid key in components. Otherwise, the empty panel might appear unexpectedly.

Please confirm how you handle scenarios where renderPanel might reference a non-existent component, to prevent unexpected blank UI.


39-44: Review potential overlap in right-click management.
The <plugin-right-menu> component is rendered separately from the main draggable panel. Ensure no event conflicts occur when the user right-clicks multiple plugins in quick succession, as race conditions might cause unexpected menu positioning.


62-72: Props definition confirmed.
Using type: Array with a default empty array is consistent and safe for pluginList. Ensure you validate or filter the array to prevent references to invalid plugin structures.


93-105: Check context menu data flow.
showContextMenu(event, type, item, index, align) directly passes native event coordinates. It's correct for an internal UI, but confirm that item or align can’t be manipulated by external sources, preventing potential code injection or misalignment.

Do you sanitize or restrict item and align to known values?


137-150: Verify drag-and-drop indices.
onEnd(e) calls dragPluginLayout(e.from.id, e.to.id, e.oldIndex, e.newIndex). Confirm that the final list indices match the new plugin order, especially if external state modifies these arrays at the same time.


180-209: Maintain consistent styling for the right panel.
The usage of absolute positioning with right: var(--base-nav-panel-width) and conditionally applying is-fixed is valid. Just ensure the final bounding box remains accessible on variable screen widths.

packages/layout/src/composable/useLayout.js (6)

14-14: Local storage usage.
Importing and using useStorage is a convenient approach. Confirm that potential large amounts of data in storage do not degrade performance, and handle older or missing keys gracefully.


20-27: Good usage of PLUGIN_POSITION constants.
These enumerations clarify plugin alignment states, preventing magic strings. Keep them updated if new positions (like topFixed) emerge.


34-47: Reactive layoutState expansions.
You’ve added more plugin and settings properties. Validate that changes to render, fixedPanels, and activating do not introduce side effects if watchers or other reactive computations rely on them.

Do you have unit tests covering transitions from non-fixed to fixed states?


65-70: Drag bar toggling logic.
getMoveDragBarState and changeMoveDragBarState properly reflect reactive state. If toggling it across multiple UI components, watch out for ephemeral race conditions (e.g., two components toggling the state out of sync).


133-138: Ensure forced closure logic doesn’t break pinned panels.
closeSetting(forceClose) forcibly sets settings.render = null. If a pinned or fixed panel is forcibly closed, ensure consistent re-opening logic is intact.


236-276: Validate drag indices especially across positions.
dragPluginLayout(...) updates item.index for cross-list and same-list drags. If there are external changes to these indices or if new plugins are injected after rendering, the method might cause collisions.

Would you like a shell script or approach to test drag and drop correctness across repeated plugin additions?

packages/plugins/tree/meta.js (1)

6-6: Alignment property updated to support new flexible layout

Changing the alignment from 'top' to 'leftTop' is consistent with the PR's objective of implementing a unified logic for plugin panel positioning. This standardization appears across multiple plugin meta files in this PR and will help support the new draggable functionality.

packages/toolbars/themeSwitch/src/Main.vue (1)

84-84: Good practice: Using const for non-reassigned variable

Changing from let to const is appropriate here since filterList is not reassigned after its initial declaration. This improves code clarity by signaling the immutability intention of this variable.

packages/plugins/state/meta.js (1)

5-5: Alignment property standardized for flexible layout support

This change from 'top' to 'leftTop' is part of the standardization effort across all plugin meta files to support the new flexible layout system. This change ensures consistent positioning behavior with the enhanced plugin panel functionality introduced in this PR.

Copy link
Contributor

@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: 1

🧹 Nitpick comments (4)
packages/layout/src/DesignPlugins.vue (1)

293-294: Consider adding a width constraint for the dynamic panel width.

The CSS changes set width to auto !important, which allows flexible sizing. However, consider adding min/max width constraints to prevent panels from becoming too narrow or too wide.

- width: auto !important;
+ width: auto !important;
+ min-width: 250px;
+ max-width: 600px;
packages/layout/src/DesignSettings.vue (1)

309-312: Consolidate duplicate icon style definitions.

There are duplicate style definitions for .svg-icon.icon-plugin-icon-plugin-help with different font sizes (18px on line 306 and 22px on line 315). This can lead to inconsistent styling.

- :deep(.svg-icon.icon-plugin-icon-plugin-help) {
-   font-size: 18px;
- }
- 
- :deep(.svg-icon.icon-plugin-icon-plugin-help) {
-   font-size: 22px;
- }
+ :deep(.svg-icon.icon-plugin-icon-plugin-help) {
+   font-size: 22px;
+ }

Also applies to: 314-316

packages/layout/src/composable/useLayout.js (2)

170-185: Ensure width limits to prevent UI issues with extremely wide panels.

The changePluginWidth function allows setting any width value. Consider adding validation to ensure width values stay within reasonable limits to prevent UI issues.

const changePluginWidth = (name, width, offset) => {
+   // Ensure width stays within reasonable limits
+   const limitedWidth = Math.max(200, Math.min(800, width))
    if (Object.prototype.hasOwnProperty.call(pluginStorageReactive.value, name)) {
-     pluginStorageReactive.value[name].width = width
+     pluginStorageReactive.value[name].width = limitedWidth
      pluginStorageReactive.value[name].offset = offset
    } else {
      pluginStorageReactive.value[name] = {
-       width
+       width: limitedWidth
      }
    }
}

287-290: Ensure plugin list initialization is robust.

The initPluginStorageReactive function doesn't validate the structure of the provided pluginList. Consider adding validation to ensure it has the expected format.

const initPluginStorageReactive = (pluginList) => {
    if (Object.keys(pluginStorageReactive.value).length) return
+   if (!Array.isArray(pluginList) || !pluginList.length) {
+     console.warn('Invalid plugin list provided for initialization');
+     return;
+   }
    pluginStorageReactive.value = pluginList
}
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between bf4d156 and 5733591.

📒 Files selected for processing (7)
  • packages/common/package.json (1 hunks)
  • packages/configurator/package.json (1 hunks)
  • packages/layout/package.json (1 hunks)
  • packages/layout/src/DesignPlugins.vue (10 hunks)
  • packages/layout/src/DesignSettings.vue (2 hunks)
  • packages/layout/src/composable/useLayout.js (5 hunks)
  • packages/plugins/tree/src/Main.vue (3 hunks)
✅ Files skipped from review due to trivial changes (2)
  • packages/configurator/package.json
  • packages/common/package.json
🚧 Files skipped from review as they are similar to previous changes (2)
  • packages/layout/package.json
  • packages/plugins/tree/src/Main.vue
⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: push-check
🔇 Additional comments (10)
packages/layout/src/DesignPlugins.vue (5)

4-36: Great implementation of drag-and-drop functionality for the top navigation list!

The transition from static lists to vue-draggable-next enhances the user experience by enabling flexible rearrangement of plugins. The proper setup with group name "plugins" ensures consistent dragging behavior.


163-172: Good fix for ensuring plugin deduplication in changeAlign!

The implementation now properly checks and removes existing items before adding them to the target list, which resolves the previous issue noted in past reviews.


264-267: Ensure consistent panel state after drag operations.

The onEnd method properly handles drag completion by closing panels when necessary and updating the layout. Make sure to test this with fixed panels to ensure they maintain their fixed state after dragging.


416-419: Good use of the .not-selected class for drag operations.

The class effectively prevents pointer events and user selection during drag operations, which provides a better user experience.


223-233:

Details

❓ Verification inconclusive

Verify closures on cross-panel alignment changes.

The switchAlign method changes plugin alignment between panels and closes the current panel if necessary, which is good. However, verify that the interaction between close() and dragPluginLayout() doesn't cause unexpected behavior when rapidly switching alignments.


🏁 Script executed:

#!/bin/bash
# Check for any related issues or error handling around plugin alignment changes
rg -B 2 -A 2 "switchAlign|changeAlign|dragPluginLayout" --type vue

Length of output: 96


I'll run a revised shell script that searches for the relevant functions in Vue files using a glob pattern. This should help us gather the necessary context on how close() and dragPluginLayout() interact.


🏁 Script executed:

#!/bin/bash
# Re-run search for 'switchAlign' and 'dragPluginLayout' in .vue files using a glob filter
rg -g "*.vue" -B 2 -A 2 "switchAlign|dragPluginLayout"

Length of output: 5554


Action Required: Verify Rapid Switching Behavior on Panel Alignment

The implementation of switchAlign in both DesignPlugins.vue and DesignSettings.vue follows a consistent pattern—removing the plugin from one panel, emitting an alignment change, conditionally closing the panel, and then triggering dragPluginLayout(). While this ordering appears intentional and consistent across files, it’s important to manually verify that the immediate call to close() before dragPluginLayout() doesn’t introduce race conditions or state inconsistencies when users rapidly toggle alignments.

  • Files to review:
    • packages/layout/src/DesignPlugins.vue (lines 223-233)
    • packages/layout/src/DesignSettings.vue
    • packages/common/component/PluginRightMenu.vue (alignment trigger handlers)

Please ensure that any asynchronous operations or state updates triggered by rapid switching are correctly managed in your manual tests or through additional automated tests to prevent unexpected behavior.

packages/layout/src/DesignSettings.vue (3)

20-37: Well-structured draggable navigation panel for right-side plugins!

The implementation mirrors the left-side panel structure, providing consistent behavior. The context menu integration is properly implemented.


119-127: Great implementation of changeAlign with proper deduplication.

The implementation checks for existing items and properly handles removing duplicates before adding to the target list.


91-99:

Details

❓ Verification inconclusive

Verify context menu positioning for right-side panels.

The showContextMenu function is similar to the left panel implementation. Ensure the menu appears in the correct position for right-aligned elements, as screen coordinates may need adjustment.


🏁 Script executed:

#!/bin/bash
# Check how the context menu positioning is handled in the codebase
rg -A 5 "showContextMenu.*clientX.*clientY" --type vue

Length of output: 84


I'll run a new shell script using an updated rg command that explicitly registers .vue files. This will help verify how the context menu positioning is handled in the DesignSettings.vue file.

Please execute the following script:

#!/bin/bash
# Re-run the search in the DesignSettings.vue file with vue file type explicitly added
rg --type-add "vue:*.vue" -A 5 "rightMenu.value.showContextMenu" packages/layout/src/DesignSettings.vue

Once we have the output of this script, we can confirm if the positioning logic for right-side panels is consistent with the left-side implementation and verify that the screen coordinates are used properly.

packages/layout/src/composable/useLayout.js (2)

20-27: Good use of constants for plugin positions!

Using a constant object for position values ensures consistency throughout the codebase and prevents typos in string values.


224-266: Robust implementation for handling drag operations!

The dragPluginLayout function handles both same-list and cross-list dragging with proper index adjustments. The logic properly accounts for all edge cases.

Copy link
Contributor

@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: 0

🧹 Nitpick comments (6)
packages/layout/src/composable/useLayout.js (6)

156-163: Enhance error handling with contextual information.

The current implementation rethrows the original error without adding context. This makes debugging challenging as it's unclear where the error originated.

  try {
    const storedPlugin = localStorage.getItem('plugin')
    if (storedPlugin) {
      plugin = JSON.parse(storedPlugin)
    }
  } catch (error) {
-    throw new Error(error)
+    throw new Error(`Failed to parse plugin data from localStorage: ${error.message}`)
  }

173-185: Add validation for plugin width.

The changePluginWidth function accepts any value without validation, which could lead to unusable UI if extreme values are provided.

// 修改插件宽度
const changePluginWidth = (name, width, offset) => {
+  // Ensure width is a reasonable value (e.g., between 100 and 800 pixels)
+  const validWidth = Math.max(100, Math.min(width, 800))
  if (Object.prototype.hasOwnProperty.call(pluginStorageReactive.value, name)) {
-    pluginStorageReactive.value[name].width = width
+    pluginStorageReactive.value[name].width = validWidth
    pluginStorageReactive.value[name].offset = offset
  } else {
    pluginStorageReactive.value[name] = {
-      width
+      width: validWidth
    }
  }
}

211-215: Validate layout positions when changing plugin layout.

The changePluginLayout function doesn't verify if the provided layout is a valid position.

// 修改某个插件的布局
const changePluginLayout = (name, layout) => {
+  // Ensure the layout is a valid position
+  if (!Object.values(PLUGIN_POSITION).includes(layout)) {
+    console.warn(`Invalid layout position: ${layout}. Using default position.`)
+    layout = PLUGIN_POSITION.leftTop
+  }
  if (pluginStorageReactive.value[name]) {
    pluginStorageReactive.value[name].align = layout
  }
}

235-243: Translate comments to English for consistency.

The comments "往后移动" and "往前移动" are in Chinese, while the rest of the codebase uses English comments.

if (oldIndex < newIndex) {
-  //往后移动
+  // Moving backward
  items.forEach((item) => {
    if (item !== movedItem && item.align === from && item.index > oldIndex && item.index <= newIndex) {
      item.index -= 1
    }
  })
} else {
-  //往前移动
+  // Moving forward
  items.forEach((item) => {

225-266: Add index bounds validation in dragPluginLayout.

The dragPluginLayout function assumes indices are valid without checking, which could lead to unexpected behavior if invalid indices are provided.

Consider adding validation to ensure indices are non-negative integers and within expected bounds:

const dragPluginLayout = (from, to, oldIndex, newIndex) => {
  if (from === to && oldIndex === newIndex) return
+  
+  // Validate indices are non-negative integers
+  if (!Number.isInteger(oldIndex) || !Number.isInteger(newIndex) || oldIndex < 0 || newIndex < 0) {
+    console.warn('Invalid indices provided to dragPluginLayout. Indices must be non-negative integers.')
+    return
+  }

  const items = Object.values(pluginStorageReactive.value)
  // Record the dragged item
  const movedItem = items.find((item) => item.align === from && item.index === oldIndex)
+  
+  // If no item found with matching position and index, exit early
+  if (!movedItem) {
+    console.warn(`No item found at position ${from} with index ${oldIndex}`)
+    return
+  }

201-208: Add error handling when plugin is not found.

The getPluginById function doesn't handle the case when a plugin with the given ID doesn't exist in the list. This could lead to undefined being returned and potentially cause errors elsewhere.

const getPluginById = (pluginId) => {
-  return pluginList.find((item) => item.id === pluginId)
+  const plugin = pluginList.find((item) => item.id === pluginId)
+  if (!plugin) {
+    console.warn(`Plugin with ID ${pluginId} not found`)
+  }
+  return plugin
}

const getPluginsByPosition = (position, pluginList) => {
-  return getPluginsByLayout(position).map((pluginId) => getPluginById(pluginList, pluginId))
+  return getPluginsByLayout(position)
+    .map((pluginId) => getPluginById(pluginList, pluginId))
+    .filter(Boolean) // Filter out undefined values from plugins not found
}
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 5733591 and 71e55b1.

📒 Files selected for processing (1)
  • packages/layout/src/composable/useLayout.js (5 hunks)
⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: push-check
🔇 Additional comments (4)
packages/layout/src/composable/useLayout.js (4)

48-48: Check for plugin name collisions.

layoutState.plugins.api is an object where all plugin APIs are stored, which could lead to name collisions if two plugins register the same API key.

Consider storing plugin APIs under unique sub-objects, e.g. plugins.api[pluginName] = …, to avoid collisions.


14-14: Great work on the persistent storage implementation.

The use of useStorage from Vue Use to persist layout state is a good practice. The implementation correctly handles initialization and storage, including error handling and type checking.

Also applies to: 154-170, 290-293


20-27: Well-defined position constants.

Creating a clear PLUGIN_POSITION constant object makes the code more maintainable and prevents typos when referencing positions.


268-277: Good implementation of side detection logic.

The isSameSide function is well-implemented, making it easy to determine if two positions are on the same side of the interface. This is crucial for the drag-and-drop functionality.

Copy link
Contributor

@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: 0

🧹 Nitpick comments (10)
packages/layout/src/Main.vue (2)

74-82: Implementation of cross-component communication for alignment changes

The component references and alignment change methods enable communication between the left and right panels, supporting the drag-and-drop functionality mentioned in the PR objectives.

However, consider adding a defensive check for the changeAlign method existence.

const changeLeftAlign = (pluginId) => {
-  right.value?.changeAlign(pluginId)
+  if (right.value && typeof right.value.changeAlign === 'function') {
+    right.value.changeAlign(pluginId)
+  }
}

87-118: Comprehensive plugin alignment initialization logic

This code initializes plugin alignment groups and properties, storing them in localStorage for persistence. This implementation supports the PR objectives of repositioning plugins and controlling visibility.

Consider two improvements:

  1. Extract this logic to a separate function for better readability
  2. Add error handling for localStorage operations
+ const initializePluginAlignments = (pluginList) => {
+   try {
      const alignGroups = {}
      const plugin = {}

      pluginList.forEach((item) => {
        if (item.id) {
          const align = item?.align || 'leftTop'

          // Initialize alignGroups[align]
          if (!alignGroups[align]) {
            alignGroups[align] = []
          }

          // Add item.id to the corresponding alignGroups
          alignGroups[align].push(item.id)

          // Assign index and properties to each plugin
          const index = alignGroups[align].indexOf(item.id)

          plugin[item.id] = {
            width: item?.width || 300,
            align: align,
            index: index,
            isShow: true,
            entry: item.entry,
            id: item.id,
            icon: item.icon
          }
        }
      })
      localStorage.setItem('plugin', JSON.stringify(plugin))
      return plugin
+   } catch (error) {
+     console.error('Failed to initialize plugin alignments:', error)
+     return {}
+   }
+ }
+
+ const plugin = initializePluginAlignments(pluginList)
  initPluginStorageReactive(plugin)
packages/layout/src/composable/useLayout.js (8)

29-31: Consider consolidating plugin state management.

The new pluginState reactive object only has one property (pluginEvent), which seems redundant as layoutState.plugins.pluginEvent also exists (line 47). This could cause confusion about which property should be used in different contexts.

-const pluginState = reactive({
-  pluginEvent: 'all'
-})

const layoutState = reactive({
  isMoveDragBar: false,
  dimension: {
    // ...
  },
  plugins: {
    isShow: true,
    fixedPanels: [PLUGIN_NAME.Materials],
    render: PLUGIN_NAME.Materials,
    pluginEvent: 'all',
    // ...
  },
  // ...
})

44-50: Consider standardizing comment language.

There's a comment in Chinese at line 48 ("插件需要注册交互API到这里") while other comments are in English. Standardizing comment language improves codebase consistency and accessibility for all developers.

plugins: {
  isShow: true,
  fixedPanels: [PLUGIN_NAME.Materials],
  render: PLUGIN_NAME.Materials,
  pluginEvent: 'all',
- api: {}, // 插件需要注册交互API到这里
+ api: {}, // Plugins need to register interaction APIs here
  activating: false, // 右侧面版激活提示状态
  showDesignSettings: true
},

156-163: Improve error handling in localStorage operations.

The current error handling simply rethrows the error without any additional context. Consider adding more descriptive error messages and potentially handling specific error types differently.

try {
  const storedPlugin = localStorage.getItem('plugin')
  if (storedPlugin) {
    plugin = JSON.parse(storedPlugin)
  }
} catch (error) {
-  throw new Error(error)
+  console.error('Failed to parse plugin data from localStorage:', error)
+  plugin = []
}

173-173: Extract magic number to a named constant.

The default plugin width of 300 appears as a magic number. Consider extracting this to a named constant at the top of the file for better maintainability.

+const DEFAULT_PLUGIN_WIDTH = 300
+
// ...

// 获取插件宽度
-const getPluginWidth = (name) => pluginStorageReactive.value[name]?.width || 300
+const getPluginWidth = (name) => pluginStorageReactive.value[name]?.width || DEFAULT_PLUGIN_WIDTH

176-185: Add validation for plugin width values.

The changePluginWidth function doesn't validate the input width. Consider adding validation to ensure the width is reasonable (e.g., positive, not too small or large).

// 修改插件宽度
const changePluginWidth = (name, width, offset) => {
+  // Ensure width is a positive number and within reasonable bounds
+  if (typeof width !== 'number' || width < 100 || width > 800) {
+    console.warn(`Invalid plugin width: ${width}. Using default value.`)
+    width = DEFAULT_PLUGIN_WIDTH
+  }
+
  if (Object.prototype.hasOwnProperty.call(pluginStorageReactive.value, name)) {
    pluginStorageReactive.value[name].width = width
    pluginStorageReactive.value[name].offset = offset
  } else {
    pluginStorageReactive.value[name] = {
      width
    }
  }
}

188-188: Consistent default values across functions.

The getPluginByLayout function uses a default value of 'leftTop', while other functions handling layouts don't specify defaults. Consider using the PLUGIN_POSITION constants for consistency.

// 获取插件布局
-const getPluginByLayout = (name) => pluginStorageReactive.value[name]?.align || 'leftTop'
+const getPluginByLayout = (name) => pluginStorageReactive.value[name]?.align || PLUGIN_POSITION.leftTop

225-266: Enhance documentation for complex drag logic.

The dragPluginLayout function has complex logic for reordering items. While the initial comment is helpful, consider adding additional inline comments to explain the more complex parts of the algorithm.

const dragPluginLayout = (from, to, oldIndex, newIndex) => {
  if (from === to && oldIndex === newIndex) return

  const items = Object.values(pluginStorageReactive.value)
  // 记录拖拽项
  const movedItem = items.find((item) => item.align === from && item.index === oldIndex)
+  
+  // If the item to move wasn't found, exit early
+  if (!movedItem) {
+    console.warn('Could not find item to move in dragPluginLayout')
+    return
+  }

  // 同一列表中的拖拽
  if (from === to) {
+    // Handle reordering within the same list
    if (oldIndex < newIndex) {
      //往后移动
+      // When moving an item backward, decrement indices of items in between
      items.forEach((item) => {
        if (item !== movedItem && item.align === from && item.index > oldIndex && item.index <= newIndex) {
          item.index -= 1
        }
      })
    } else {
      //往前移动
+      // When moving an item forward, increment indices of items in between
      items.forEach((item) => {
        if (item !== movedItem && item.align === from && item.index >= newIndex && item.index < oldIndex) {
          item.index += 1
        }
      })
    }
  } else {
    // 跨列表拖拽
+    // When moving between lists:
+    // 1. Decrement indices of items after the moved item in the source list
+    // 2. Increment indices of items at or after the target position in the destination list
    items.forEach((item) => {
      if (item !== movedItem && item.align === from && item.index > oldIndex) {
        item.index -= 1
      }
      if (item !== movedItem && item.align === to && item.index >= newIndex) {
        item.index += 1
      }
    })
  }

  // 更新拖拽项的位置
-  if (movedItem) {
-    movedItem.align = to
-    movedItem.index = newIndex
-  }
+  // Update the position of the moved item
+  movedItem.align = to
+  movedItem.index = newIndex
}

290-293: Consider validating plugin list in initialization function.

The initPluginStorageReactive function doesn't validate the structure of the provided pluginList. Adding validation would make this function more robust against invalid input.

const initPluginStorageReactive = (pluginList) => {
  if (Object.keys(pluginStorageReactive.value).length) return
+  
+  // Validate that pluginList is an array or object
+  if (!pluginList || (typeof pluginList !== 'object')) {
+    console.warn('Invalid plugin list provided to initPluginStorageReactive')
+    pluginStorageReactive.value = {}
+    return
+  }
+  
  pluginStorageReactive.value = pluginList
}
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 71e55b1 and 6a3b7c1.

📒 Files selected for processing (2)
  • packages/layout/src/Main.vue (4 hunks)
  • packages/layout/src/composable/useLayout.js (5 hunks)
⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: push-check
🔇 Additional comments (10)
packages/layout/src/Main.vue (7)

9-14: Improved flexibility with conditional rendering and plugin list integration

The addition of conditional rendering based on leftMenuShownStorage and passing the combined pluginList enhances the component's flexibility. The reference assignment will enable communication between components via the new alignment change methods.


22-28: Consistent pattern applied to right-side components

Good consistency in applying the same pattern to the right-side components as was done for the left side. The conditional rendering with v-if="rightMenuShownStorage" aligns with the PR's goal of unified logic for plugin panels.


42-42: Added Vue ref import for component references

The import of ref from Vue is necessary for the new reactive references that will hold component instances.


66-67: Enhanced state management with useLayout composable

Good use of destructuring to access the necessary state variables from useLayout, including the new storage states that control panel visibility.


84-86: Unified plugin list for consistent management

Creating a combined list of plugins and settings supports the PR's goal of unified logic for plugin panels and enables cross-panel interactions.


120-135: Updated return values with new refs and methods

The updated return object correctly includes all the new refs, methods, and properties needed for the template.


164-165: Improved right panel layout with flexbox

Changing the styling of .tiny-engine-right-wrap from position-based to flexbox aligns with the PR goal of creating a more flexible layout. This will allow for better control of the panel's dimensions and positioning.

packages/layout/src/composable/useLayout.js (3)

20-27: Good use of constants for plugin positions.

The introduction of the PLUGIN_POSITION constant provides a clean way to reference various plugin positions throughout the code, eliminating magic strings and improving maintainability.


283-288: Good implementation of error handling for changePluginShown.

The changePluginShown function now includes validation to check if the plugin exists, which addresses a previous review comment. This prevents runtime errors when toggling visibility for undefined plugins.


295-330: Good export organization.

The module exports are well-organized and include all the necessary functions for the flexible layout system. This provides a clear interface for other parts of the application to interact with the layout system.

Copy link
Collaborator

@hexqi hexqi left a comment

Choose a reason for hiding this comment

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

右侧展开没有缩放:
image
下面这样是正常的,左侧展开:
image

@hexqi hexqi added this to the v2.4.0 milestone Mar 17, 2025
Copy link
Contributor

@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: 1

♻️ Duplicate comments (1)
packages/layout/src/DesignSettings.vue (1)

315-318: 🛠️ Refactor suggestion

Duplicate CSS class definition.

The .not-selected class is defined twice in this file (see also lines 332-334 in past review), potentially causing confusion about which rules apply.

Consider consolidating the duplicate definitions:

-.not-selected {
-  pointer-events: none;
-  user-select: none;
-}

And keep only one definition that includes both properties.

🧹 Nitpick comments (12)
packages/common/component/PluginPanel.vue (1)

117-119: Consider making min/max width configurable.

The hardcoded min/max width values might not be suitable for all use cases. Consider making these configurable through props to enhance flexibility.

- const MIN_WIDTH = 300 // 固定的最小宽度值
- const MAX_WIDTH = 1000 // 固定的最大宽度值
+ const MIN_WIDTH = props.minWidth || 300 // 固定的最小宽度值
+ const MAX_WIDTH = props.maxWidth || 1000 // 固定的最大宽度值

Also add these to the props definition:

    isShowCollapseIcon: {
      type: Boolean,
      default: false
+   },
+   /**
+    * 面板最小宽度
+    */
+   minWidth: {
+     type: Number,
+     default: 300
+   },
+   /**
+    * 面板最大宽度
+    */
+   maxWidth: {
+     type: Number,
+     default: 1000
    }
packages/plugins/block/src/Main.vue (1)

472-472: Adjusted margin styling for better layout.

Changed from margin: 12px 0; to margin-bottom: 12px; for the .app-manage-type class, improving vertical spacing and visual layout.

packages/layout/src/composable/useLayout.js (10)

29-31: Consider expanding the pluginState object.

The pluginState reactive object currently only contains a single property. As you continue to develop the plugin system, consider structuring this object more comprehensively to avoid adding reactive properties later.


48-48: Use English comments throughout the codebase.

The comment "右侧面版激活提示状态" is in Chinese. For consistency and to improve readability for all team members, consider using English for all comments.

-    activating: false, // 右侧面版激活提示状态
+    activating: false, // Right panel activation indicator state

87-96: Consider consolidating panel management functions.

The changeLeftFixedPanels and changeRightFixedPanels functions are nearly identical. Consider creating a single utility function to avoid code duplication.

-const changeLeftFixedPanels = (pluginName) => {
-  leftFixedPanelsStorage.value = leftFixedPanelsStorage.value?.includes(pluginName)
-    ? leftFixedPanelsStorage.value?.filter((item) => item !== pluginName)
-    : [...leftFixedPanelsStorage.value, pluginName]
-}
-const changeRightFixedPanels = (pluginName) => {
-  rightFixedPanelsStorage.value = rightFixedPanelsStorage.value?.includes(pluginName)
-    ? rightFixedPanelsStorage.value?.filter((item) => item !== pluginName)
-    : [...rightFixedPanelsStorage.value, pluginName]
-}
+const togglePanelPlugin = (storage, pluginName) => {
+  storage.value = storage.value?.includes(pluginName)
+    ? storage.value?.filter((item) => item !== pluginName)
+    : [...storage.value, pluginName]
+}
+
+const changeLeftFixedPanels = (pluginName) => {
+  togglePanelPlugin(leftFixedPanelsStorage, pluginName)
+}
+
+const changeRightFixedPanels = (pluginName) => {
+  togglePanelPlugin(rightFixedPanelsStorage, pluginName)
+}

155-168: Improve error handling for localStorage operations.

The current error handling just re-throws the error without providing context. Consider adding more descriptive error messages and possibly falling back to default values instead of throwing.

  try {
    const storedPlugin = localStorage.getItem('plugin')
    if (storedPlugin) {
      plugin = JSON.parse(storedPlugin)
    }
  } catch (error) {
-    throw new Error(error)
+    console.error('Error parsing plugin data from localStorage:', error)
+    plugin = []
  }

172-172: Extract magic numbers to constants.

The default width of 300 should be extracted to a named constant at the top of the file for better maintainability.

+const DEFAULT_PLUGIN_WIDTH = 300
+
// 获取插件宽度
-const getPluginWidth = (name) => pluginStorageReactive.value[name]?.width || 300
+const getPluginWidth = (name) => pluginStorageReactive.value[name]?.width || DEFAULT_PLUGIN_WIDTH

175-184: Add validation for width parameter.

The changePluginWidth function doesn't validate the width parameter, which could lead to unexpected UI issues if negative or extremely large values are provided.

// 修改插件宽度
const changePluginWidth = (name, width, offset) => {
+  // Ensure width is a reasonable value (e.g., between 100 and 800 pixels)
+  const validWidth = Math.max(100, Math.min(800, width))
+  
  if (Object.prototype.hasOwnProperty.call(pluginStorageReactive.value, name)) {
-    pluginStorageReactive.value[name].width = width
+    pluginStorageReactive.value[name].width = validWidth
    pluginStorageReactive.value[name].offset = offset
  } else {
    pluginStorageReactive.value[name] = {
-      width
+      width: validWidth
    }
  }
}

187-187: Add a fallback for invalid layouts.

The getPluginByLayout function returns a default of 'leftTop', but should verify that this is a valid position from your PLUGIN_POSITION constants.

-const getPluginByLayout = (name) => pluginStorageReactive.value[name]?.align || 'leftTop'
+const getPluginByLayout = (name) => {
+  const align = pluginStorageReactive.value[name]?.align
+  return Object.values(PLUGIN_POSITION).includes(align) ? align : PLUGIN_POSITION.leftTop
+}

190-199: Optimize the getPluginsByLayout function.

The function is well-structured, but could be optimized slightly to avoid redundant sorting when the result is an empty array.

const getPluginsByLayout = (layout = 'all') => {
  // 筛选出符合布局条件的插件名称
  const pluginNames = Object.keys(pluginStorageReactive.value).filter(
    (key) => pluginStorageReactive.value[key].align === layout || layout === 'all'
  )

+  if (pluginNames.length === 0) return pluginNames;
+
  pluginNames.sort((a, b) => pluginStorageReactive.value[a].index - pluginStorageReactive.value[b].index)

  return pluginNames
}

224-265: Optimize the dragPluginLayout function.

The current implementation has multiple iterations over the same items array. Consider consolidating the loops and adding input validation.

  1. Add validation for from, to, oldIndex, and newIndex parameters
  2. Consider using a more efficient algorithm that doesn't require multiple iterations
const dragPluginLayout = (from, to, oldIndex, newIndex) => {
  if (from === to && oldIndex === newIndex) return
  
+  // Validate inputs
+  if (!Object.values(PLUGIN_POSITION).includes(from) || !Object.values(PLUGIN_POSITION).includes(to)) {
+    console.error('Invalid position values in dragPluginLayout:', { from, to })
+    return
+  }
+  
+  if (typeof oldIndex !== 'number' || typeof newIndex !== 'number' || oldIndex < 0 || newIndex < 0) {
+    console.error('Invalid index values in dragPluginLayout:', { oldIndex, newIndex })
+    return
+  }

  const items = Object.values(pluginStorageReactive.value)
  // 记录拖拽项
  const movedItem = items.find((item) => item.align === from && item.index === oldIndex)
  
+  if (!movedItem) {
+    console.error('Could not find item to move in dragPluginLayout')
+    return
+  }

  // Same list logic and cross-list logic remain the same...

289-292: Consider adding validation in initPluginStorageReactive.

The initPluginStorageReactive function doesn't validate the structure of pluginList before assigning it to storage.

const initPluginStorageReactive = (pluginList) => {
  if (Object.keys(pluginStorageReactive.value).length) return
+  
+  // Validate pluginList structure
+  if (!Array.isArray(pluginList) && typeof pluginList !== 'object') {
+    console.error('Invalid pluginList format:', pluginList)
+    return
+  }
+  
  pluginStorageReactive.value = pluginList
}
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 6a3b7c1 and 0d375c4.

📒 Files selected for processing (11)
  • packages/common/component/PluginPanel.vue (5 hunks)
  • packages/common/package.json (1 hunks)
  • packages/layout/src/DesignPlugins.vue (10 hunks)
  • packages/layout/src/DesignSettings.vue (2 hunks)
  • packages/layout/src/composable/useLayout.js (5 hunks)
  • packages/plugins/block/src/Main.vue (6 hunks)
  • packages/plugins/bridge/src/Main.vue (4 hunks)
  • packages/plugins/i18n/src/Main.vue (4 hunks)
  • packages/plugins/page/src/Main.vue (4 hunks)
  • packages/plugins/script/src/Main.vue (5 hunks)
  • packages/settings/events/index.js (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • packages/common/package.json
  • packages/settings/events/index.js
🔇 Additional comments (60)
packages/common/component/PluginPanel.vue (10)

12-22: Great addition of collapsible functionality with tooltip.

The implementation of the collapsible feature with tooltip guidance enhances user experience by providing visual feedback on the action. The conditional rendering based on isShowCollapseIcon prop allows for flexible usage across different panel instances.


23-28: Good implementation of fixed panel functionality.

The fixed panel toggle uses conditional rendering based on the fixedPanels array and fixedName prop, with appropriate tooltip text that changes based on the current state. This provides clear visual indication of panel state to users.


32-34: Good addition of scroll container for content.

Wrapping the content slot in a scrollable div with appropriate CSS ensures content overflow is handled properly while maintaining the overall layout structure.


36-37: Excellent implementation of resize handles.

The conditional rendering of resize handles based on the panel's alignment (left/right) provides intuitive UI for users to adjust panel width according to their needs.


42-42: Good use of useThrottleFn for performance optimization.

Using useThrottleFn from @vueuse/core for throttling mouse move events is an excellent approach to improve performance during resize operations.


84-109: Well-documented props with clear descriptions.

The new props are well documented with clear JSDoc comments explaining their purpose, which improves code maintainability and makes it easier for other developers to understand how to use this component.


140-144: Good implementation of resize handlers with boundary checks.

The resize handler correctly restricts the panel width within the defined min/max boundaries and updates the width through the layout system. The use of changePluginWidth ensures that the changes are properly propagated to the layout system.


152-153: Excellent use of throttling for mouse move events.

Throttling mouse move events is a good practice to prevent performance issues during resize operations. The 50ms throttle interval provides a good balance between responsiveness and performance.


158-164: Proper cleanup of event listeners.

The code properly removes event listeners when the resize operation is complete, which prevents memory leaks and ensures clean event handling. Also, it resets the cursor style and removes the dragging class.


278-326: Well-implemented CSS for resize handles.

The CSS for the resize handles provides good visual feedback with hover effects and clear indication during dragging. The transition effect provides a smooth user experience.

packages/plugins/script/src/Main.vue (5)

2-29: Clean restructuring using the enhanced PluginPanel component.

The template has been nicely refactored to use the enhanced PluginPanel component with proper slot usage for header and content. The structure is clean and follows a consistent pattern with other plugin components.


33-33: Good addition of reactive state management.

Adding reactive from Vue's composition API enhances the component's state management capabilities.


55-57: Proper prop definition for fixedPanels.

The type is correctly defined as Array, matching the expected type in the PluginPanel component.


66-69: Good use of provide/inject pattern for panel state.

Creating a reactive panelState object and providing it to child components establishes a clean communication channel for panel-related events.


129-150: Improved styling with better organization.

The CSS has been restructured with proper nesting and semantic class names, making it easier to maintain and understand.

packages/plugins/page/src/Main.vue (5)

2-38: Well-structured template with clear slot usage.

The template has been organized clearly with properly named slots for header and content. The buttons and icons in the header are well aligned and properly encapsulated within the header slot.


47-48: Good addition of useLayout import.

Adding the useLayout hook provides access to layout-related functionality like PLUGIN_NAME, enhancing the component's integration with the layout system.


79-81: Proper prop definition for fixedPanels.

The fixedPanels prop is correctly defined with the Array type, consistent with other components using the same pattern.


83-83: Good explicit emits declaration.

Explicitly declaring the 'close' emit enhances the component's API clarity and documentation.


90-94: Well-implemented panel state management.

The reactive panelState object with emitEvent method provides a clean way to handle events from the panel.

packages/plugins/i18n/src/Main.vue (4)

2-9: Good integration with the enhanced PluginPanel.

The PluginPanel is properly configured with the required props, including fixedName and fixedPanels, maintaining consistency with other plugin components.


123-135: Good organization of imports.

The imports are well organized, with Vue-related imports first, followed by component imports and then service imports. Using destructuring for the useLayout import is a clean approach.


156-158: Proper prop definition for fixedPanels.

The fixedPanels prop is correctly defined with the Array type, consistent with the implementation in other components.


170-173: Good use of provide/inject pattern.

Creating a reactive panelState object and providing it to child components establishes a consistent communication pattern across the application.

packages/plugins/bridge/src/Main.vue (6)

2-7: Looks good - New plugin panel props added.

The addition of :fixed-name="PLUGIN_NAME.Bridge" and :fixedPanels="fixedPanels" props enhances the plugin panel's configurability, aligning with the PR's goal to implement flexible layout for the plugin panel.


20-22: Added reactive and layout utilities for flexible plugin management.

The addition of reactive and provide imports, along with the useLayout hook, enables reactive state management for the plugin panel's positioning and visibility.


35-39: Good - Added fixedPanels prop.

Adding the fixedPanels prop allows this component to receive information about which panels should be fixed in the layout, supporting the flexible positioning feature.


40-45: Appropriate setup function update.

The setup function now properly accepts props and emit, and retrieves the PLUGIN_NAME constant from useLayout, enabling consistent plugin identification across the application.


47-50: Effective state management with provide/inject pattern.

Creating a reactive panelState object and providing it to child components establishes a clean communication channel for the panel's state.


65-65: Added PLUGIN_NAME to return value.

Exposing PLUGIN_NAME to the template enables proper identification of the plugin in the flexible layout system.

packages/plugins/block/src/Main.vue (5)

1-10: Good restructuring of plugin-panel with flexible layout props.

The plugin-panel component has been enhanced with :fixed-name="PLUGIN_NAME.BlockManage" and :fixedPanels="fixedPanels" props, properly implementing the flexible layout system from the PR objectives.


219-223: Added fixedPanels prop for dynamic panel management.

Adding the fixedPanels prop allows this component to receive and utilize information about which panels should maintain fixed positions in the layout.


273-280: State management with provide/inject pattern implemented.

The addition of the reactive panelState object and providing it to child components establishes a clean communication channel for the panel's state, consistent with the implementation in other plugin components.


318-321: Proper event emission on close.

Adding emit('close') in the close function ensures parent components are properly notified when the panel is closed, maintaining component communication integrity.


436-436: Added PLUGIN_NAME to return value.

Exposing PLUGIN_NAME to the template enables proper identification of the plugin in the flexible layout system, consistent with other plugin implementations.

packages/layout/src/DesignPlugins.vue (10)

3-9: Implemented draggable navigation with vue-draggable-next.

Replaced static lists with draggable components, enabling users to reposition plugins via drag-and-drop as specified in the PR objectives.


23-24: Added context menu support for flexible plugin management.

The @contextmenu.prevent handler enables right-click menu functionality for plugins, supporting the requirement to control plugin visibility and position through a right-click menu.


39-49: Added draggable functionality to bottom navigation.

The bottom navigation list now also implements draggable functionality using vue-draggable-next, completing the flexible layout implementation for all plugin positions.


69-87: Implemented panel visibility toggling with drag state awareness.

The :class="{ 'not-selected': getMoveDragBarState() }" binding disables interaction with panels during drag operations, providing better user experience during layout adjustments.


90-95: Added plugin context menu component.

The integration of the plugin-right-menu component provides a unified interface for plugin management actions, supporting the PR objective of controlling plugin visibility and position.


124-172: Implemented changeAlign with proper deduplication.

The changeAlign function now correctly checks for and removes existing items before adding to the target list, preventing duplicates when changing plugin alignment.


223-238: Implemented panel switching with proper cleanup.

The switchAlign method handles transitioning a plugin between different panel positions, including necessary cleanup and event emissions to maintain layout integrity.


269-272: Added drag event handling for layout updates.

The onEnd method properly processes the completion of drag events, ensuring the layout updates correctly after repositioning plugins.


299-299: Responsive panel width with auto setting.

Setting width: auto !important; for the left panel allows it to adjust based on content, supporting the requirement to make the panel width adjustable.


422-425: Added utility class for drag operations.

The .not-selected class disables pointer events and user selection during drag operations, providing better visual feedback and preventing unintended interactions.

packages/layout/src/DesignSettings.vue (8)

3-19: Implemented flexible panel structure with fixed panel support.

The right panel implementation now supports dynamic rendering and fixed positioning based on the renderPanel prop and rightFixedPanelsStorage state, fulfilling the PR objective for consistent floating and fixed panel logic.


20-37: Implemented draggable navigation for right panel.

Replaced static navigation with vue-draggable-next component, supporting the PR's goal of allowing users to reposition plugins via dragging.


39-44: Added plugin context menu for right panel.

The plugin-right-menu component integration enables right-click management of plugins in the right panel, consistent with the implementation in DesignPlugins.vue.


93-99: Implemented context menu handling.

The showContextMenu method properly handles different context menu scenarios based on event type and position, enhancing user interaction options.


117-122: Implemented cross-panel plugin movement.

The switchAlign method handles moving plugins between panels with proper cleanup, ensuring consistent state across the application.


124-132: Implemented changeAlign with proper deduplication.

Similar to DesignPlugins.vue, this function correctly prevents duplicates when changing plugin alignment by checking and removing existing items before adding.


139-145: Implemented toggle behavior for plugin panels.

The clickMenu method properly handles toggling panel visibility when clicking an already active plugin, improving user experience.


157-160: Added drag event handling with proper cleanup.

The onEnd method properly handles drag completion, including closing panels when appropriate and updating layout state.

packages/layout/src/composable/useLayout.js (7)

14-14: Nice addition of useStorage for persistent state.

Using useStorage from @vueuse/core is a good choice for maintaining state persistence across page reloads, which is essential for remembering user layout preferences.


20-27: Well-structured plugin position constants.

Good job defining a clear enum-like object for plugin positions. This makes the code more maintainable and prevents magic strings across the codebase.


64-69: Good implementation of drag bar state management.

The functions for getting and changing the drag bar state are simple and focused, following good practices for state management.


70-83: Well-designed menu visibility toggle.

The implementation effectively uses persistent storage and provides a clean API for toggling menu visibility. The switch statement is easy to extend if more menu positions are added in the future.


122-127: Good implementation of conditional setting closure.

The closeSetting function properly handles closure conditions based on whether the setting is fixed or needs to be force-closed.


282-287: Good job adding error handling to changePluginShown.

You've added proper error handling to ensure that the plugin exists before toggling its visibility, which helps prevent runtime errors.


294-329: Well-organized exports with comprehensive functionality.

The exported object provides a complete and organized API for layout management, including all the new flexible layout capabilities. The function names are descriptive and follow a consistent pattern.

Copy link
Contributor

@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: 0

🧹 Nitpick comments (1)
packages/layout/src/composable/useLayout.js (1)

225-266: Comprehensive implementation of drag-and-drop functionality.

The dragPluginLayout function handles all possible drag scenarios, including same-list and cross-list dragging, with proper index adjustments. The logic is complex but thorough.

Consider adding more inline comments to document the different scenarios being handled, which would make this complex function easier to maintain in the future.

 const dragPluginLayout = (from, to, oldIndex, newIndex) => {
   if (from === to && oldIndex === newIndex) return

   const items = Object.values(pluginStorageReactive.value)
-  // 记录拖拽项
+  // Record the dragged item
   const movedItem = items.find((item) => item.align === from && item.index === oldIndex)

-  // 同一列表中的拖拽
+  // Handle drag within the same list
   if (from === to) {
     if (oldIndex < newIndex) {
-      //往后移动
+      // Moving backward: decrement indices of items between old and new position
       items.forEach((item) => {
         if (item !== movedItem && item.align === from && item.index > oldIndex && item.index <= newIndex) {
           item.index -= 1
         }
       })
     } else {
-      //往前移动
+      // Moving forward: increment indices of items between new and old position
       items.forEach((item) => {
         if (item !== movedItem && item.align === from && item.index >= newIndex && item.index < oldIndex) {
           item.index += 1
         }
       })
     }
   } else {
-    // 跨列表拖拽
+    // Handle drag between different lists
+    // 1. Decrement indices of items after the old position in source list
     items.forEach((item) => {
       if (item !== movedItem && item.align === from && item.index > oldIndex) {
         item.index -= 1
       }
+      // 2. Increment indices of items at or after the new position in target list
       if (item !== movedItem && item.align === to && item.index >= newIndex) {
         item.index += 1
       }
     })
   }

-  // 更新拖拽项的位置
+  // Update the position of the dragged item
   if (movedItem) {
     movedItem.align = to
     movedItem.index = newIndex
   }
 }
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 0d375c4 and 5b43959.

📒 Files selected for processing (4)
  • packages/canvas/container/src/components/CanvasResize.vue (1 hunks)
  • packages/layout/src/DesignPlugins.vue (9 hunks)
  • packages/layout/src/composable/useLayout.js (5 hunks)
  • packages/utils/src/constants/index.js (1 hunks)
🧰 Additional context used
🧠 Learnings (1)
packages/utils/src/constants/index.js (1)
Learnt from: rhlin
PR: opentiny/tiny-engine#1011
File: packages/utils/src/constants/index.js:101-101
Timestamp: 2025-03-13T02:41:34.105Z
Learning: The `CANVAS_ROUTER_VIEW_SETTING_VIEW_MODE_KEY` constant in `packages/utils/src/constants/index.js` intentionally omits CHANNEL_UID to maintain a single localStorage entry that can be restored across different instances of the designer.
🧬 Code Definitions (1)
packages/layout/src/composable/useLayout.js (1)
packages/utils/src/constants/index.js (4) (4)
  • STORAGE_KEY_LEFT_FIXED_PANELS (100-100)
  • STORAGE_KEY_LEFT_FIXED_PANELS (100-100)
  • STORAGE_KEY_RIGHT_FIXED_PANELS (101-101)
  • STORAGE_KEY_RIGHT_FIXED_PANELS (101-101)
⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: push-check
🔇 Additional comments (18)
packages/utils/src/constants/index.js (1)

100-101: Clean addition of panel storage constants.

These new constants follow the same pattern as CANVAS_ROUTER_VIEW_SETTING_VIEW_MODE_KEY by intentionally omitting the CHANNEL_UID, ensuring that panel configurations persist consistently across different designer instances.

packages/canvas/container/src/components/CanvasResize.vue (1)

109-121: Well-implemented watchers for right panel layout changes.

These watchers provide consistent behavior for right panel layout changes, matching the existing pattern used for left panel changes. The use of flush: 'post' ensures these run after DOM updates, which is appropriate for scale adjustments.

packages/layout/src/DesignPlugins.vue (8)

4-37: Good implementation of draggable plugin navigation.

Replacing the static list with vue-draggable-next significantly improves the user experience by enabling fluid drag-and-drop functionality for plugins, which aligns with the PR's objective of implementing a flexible layout.


39-66: Well-structured bottom navigation area with drag support.

The implementation maintains consistency with the top navigation area while adding proper context menu handling and drag-and-drop support for the bottom section.


69-88: Appropriate use of pointer-events control during drag operations.

The .not-selected class wrapper prevents interaction with the panel when getMoveDragBarState() returns true, which is a good approach to avoid unintended interactions during drag operations.


90-95: Effective implementation of context menu component.

The PluginRightMenu component consolidates context menu functionality, improving code organization and reusability while enabling the new alignment features described in the PR objectives.


155-170: Properly implemented state management for plugin lists.

The reactive state properly initializes the plugin lists based on position, and the changeAlign function now correctly checks for and removes existing items before adding them to a new list, which addresses a concern from a previous review.


226-236: Well-implemented alignment switching logic.

The switchAlign method handles panel repositioning effectively, with proper cleanup of the source list and appropriate API calls. It also appropriately closes panels when switching between sides.


242-246: Good implementation of drag end handler.

The onEnd method properly updates plugin layout after drag operations complete, with appropriate handling of same-side vs. cross-side drag scenarios.


397-400: Effective utility class for preventing interactions.

The .not-selected class provides a clean way to disable pointer events and user selection when needed, which is particularly useful during drag operations.

packages/layout/src/composable/useLayout.js (8)

20-27: Well-defined position constants for flexible layout management.

The PLUGIN_POSITION constant provides a clear enumeration of all possible plugin positions, which supports the flexible layout objectives of the PR.


64-69: Good implementation of drag bar state management.

The getter and setter functions for the drag bar state provide a clean API for controlling the interactive state of the UI during drag operations.


70-83: Clean implementation of menu visibility toggling.

The use of useStorage for persisting menu visibility state across sessions is a good approach, and the changeMenuShown function provides a simple API for toggling visibility.


84-96: Well-implemented panel fixation state management.

The functions leverage the newly added storage constants and provide a clean API for toggling fixed states of panels. The implementation correctly handles both adding and removing panels from the fixed state.


172-185: Robust plugin width management functions.

The implementation properly handles both existing and new plugins, ensuring that width and offset values are correctly stored and retrieved.


187-208: Clean functions for plugin position and layout management.

These utility functions provide a foundation for the flexible layout system, making it easy to retrieve plugins by position, layout, or ID.


268-277: Good utility function for side determination.

The isSameSide function provides a clean way to determine if two positions are on the same side of the layout, which is useful for handling cross-side drag operations.


283-288: Properly fixed plugin visibility toggle function.

The changePluginShown function now includes proper initialization for non-existent plugins, addressing the concern raised in a previous review.

Copy link
Contributor

@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: 0

🧹 Nitpick comments (15)
packages/plugins/script/src/Main.vue (1)

165-165: Removed unnecessary empty line.

The empty line after the closing bracket is unnecessary but doesn't affect functionality.

}
-

:deep(.help-box) {
packages/common/component/PluginSetting.vue (2)

104-111: New props enhance component flexibility

The new fixedName and align props enhance the component's flexibility and reusability across different contexts.

Consider adding more descriptive JSDoc comments for these new props to better document their purpose and accepted values, similar to the existing props.


119-131: Well-structured computed properties for dynamic layout

The computed properties logically break down the positioning calculations, making the code more maintainable. The firstPanelOffset provides the initial panel width, secondPanelAlign determines direction, and alignStyle combines them for positioning.

Consider renaming firstPanelOffset to something more descriptive like firstPanelWidth since it represents width rather than an offset.

packages/common/styles/vars.less (1)

31-32: Consider referencing an existing theming variable to maintain consistency.

The new --te-component-common-resizer-border-color variable introduces a static hex color. If you already have a theming system or brand color reference, referencing that might help keep the styles consistent and maintainable.

packages/plugins/schema/src/Main.vue (2)

76-80: Using panelState with provide is a practical approach.

This approach helps sibling or child components to seamlessly interact with the panel. Ensure there are no reactivity pitfalls or watchers needed if the state changes externally.


188-218: Scoped styling updates.

You’ve introduced styling for the .icon-wrap class and the .source-code-content container. These changes appear consistent with your new layout. However, verify that relying on height: calc(100% - 12px) does not break in smaller screens or alternate usage contexts. A potential fallback or media query may be needed for responsiveness.

packages/common/component/PluginRightMenu.vue (4)

24-50: Review alignment logic in props.

The align prop defaults to 'left', but the usage includes align.includes('right'). This is valid, yet consider normalizing this prop to an enum-like approach ('left' | 'right') for clarity. Right now, string containment checks can be prone to edge cases if used incorrectly in the future.


52-80: Check potential offset issues in showContextMenu.

The code calculates contextMenu.x = x - contextMenuWidth, which may cause negative values if x is near the viewport’s left edge. Consider adding boundary checks so the menu displays properly even at the edges.


112-116: Click-outside approach is good.

Using closest('.plugin-context-menu') to detect outside clicks is straightforward, but watch out for integrations with frameworks that might dynamically change the DOM or introduce shadow roots.


139-180: Basic styling for the context menu.

The styling is minimalistic and likely meets the immediate design requirements. If theming is essential, maybe unify the border and background with other palette variables (like --te-component-common-border-color).

packages/layout/src/DesignPlugins.vue (2)

4-36: Use a stable key in your v-for loop.

Currently, the code uses the loop index as the key (:key="index"). This can cause potential re-render issues if the array is reordered. Consider using item.id or another unique attribute instead:

- <div v-for="(item, index) in state.topNavLists" :key="index">
+ <div v-for="item in state.topNavLists" :key="item.id">

276-277: Avoid !important; if possible.

Line 276 uses width: auto !important;. While it’s sometimes necessary, see if a higher CSS specificity can achieve the same result. Overuse of !important may complicate future styling.

packages/layout/src/DesignSettings.vue (1)

3-45: Use stable keys in the v-for loop for settingPlugins.

Similar to the left panel, using :key="item.id" instead of :key="index" leads to more predictable rendering when dragging or reordering plugins.

packages/common/component/PluginPanel.vue (1)

44-221: Consider removing listeners on unmount to prevent leaks.

If the user navigates away while dragging (before mouseup), the document listeners might remain attached. As a precaution, consider removing them in onBeforeUnmount if still active, preventing potential memory leaks.

packages/layout/src/composable/useLayout.js (1)

236-275: Ensure movedItem always exists in dragPluginLayout.

movedItem is found by matching align === from && index === oldIndex. If not found, the function silently does nothing. If that’s intentional, that’s fine, but confirm you aren’t missing an error log or fallback.

📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 5b43959 and 4fd4959.

⛔ Files ignored due to path filters (3)
  • packages/design-core/assets/display-inline.svg is excluded by !**/*.svg
  • packages/design-core/assets/form.svg is excluded by !**/*.svg
  • packages/design-core/assets/target.svg is excluded by !**/*.svg
📒 Files selected for processing (16)
  • packages/canvas/DesignCanvas/src/DesignCanvas.vue (5 hunks)
  • packages/canvas/container/src/components/CanvasResize.vue (2 hunks)
  • packages/common/component/PluginPanel.vue (5 hunks)
  • packages/common/component/PluginRightMenu.vue (1 hunks)
  • packages/common/component/PluginSetting.vue (9 hunks)
  • packages/common/styles/vars.less (1 hunks)
  • packages/layout/src/DesignPlugins.vue (9 hunks)
  • packages/layout/src/DesignSettings.vue (2 hunks)
  • packages/layout/src/Main.vue (4 hunks)
  • packages/layout/src/composable/useLayout.js (5 hunks)
  • packages/plugins/schema/src/Main.vue (5 hunks)
  • packages/plugins/script/src/Main.vue (5 hunks)
  • packages/plugins/tree/src/Main.vue (3 hunks)
  • packages/settings/props/src/Main.vue (1 hunks)
  • packages/settings/styles/src/Main.vue (7 hunks)
  • packages/utils/src/constants/index.js (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (6)
  • packages/canvas/container/src/components/CanvasResize.vue
  • packages/plugins/tree/src/Main.vue
  • packages/canvas/DesignCanvas/src/DesignCanvas.vue
  • packages/settings/styles/src/Main.vue
  • packages/layout/src/Main.vue
  • packages/settings/props/src/Main.vue
🧰 Additional context used
🧠 Learnings (1)
packages/utils/src/constants/index.js (1)
Learnt from: rhlin
PR: opentiny/tiny-engine#1011
File: packages/utils/src/constants/index.js:101-101
Timestamp: 2025-03-13T02:41:34.105Z
Learning: The `CANVAS_ROUTER_VIEW_SETTING_VIEW_MODE_KEY` constant in `packages/utils/src/constants/index.js` intentionally omits CHANNEL_UID to maintain a single localStorage entry that can be restored across different instances of the designer.
🧬 Code Definitions (1)
packages/layout/src/composable/useLayout.js (1)
packages/utils/src/constants/index.js (6) (6)
  • STORAGE_KEY_LEFT_FIXED_PANELS (100-100)
  • STORAGE_KEY_LEFT_FIXED_PANELS (100-100)
  • STORAGE_KEY_RIGHT_FIXED_PANELS (101-101)
  • STORAGE_KEY_RIGHT_FIXED_PANELS (101-101)
  • PLUGIN_DEFAULT_WIDTH (168-168)
  • PLUGIN_DEFAULT_WIDTH (168-168)
🔇 Additional comments (37)
packages/plugins/script/src/Main.vue (10)

2-11: The new plugin-panel component structure improves layout flexibility.

The replacement of the custom div structure with a reusable plugin-panel component aligns well with the PR's objective to introduce a unified flexible layout system. The addition of properties like :fixed-name, :fixedPanels, and :draggable-enabled="true" enables the panel to participate in the new drag-and-resize functionality.


12-17: Clean implementation of change indicator and save button.

The header slot's implementation with the change indicator dot and save button provides good visual feedback to users about unsaved changes, enhancing the UX.


18-29: Content structure preserved correctly.

The monaco editor implementation has been properly moved to the content slot while maintaining all its functionality, ensuring a seamless transition to the new layout system.


34-37: Good enhancement of reactive capabilities.

The addition of reactive and provide imports from Vue, along with the updated imports for common components, supports the component's enhanced state management approach.


52-54: Proper component registration.

The PluginPanel component is correctly registered, allowing it to be used in the template.


55-59: Added support for fixed panels configuration.

The new fixedPanels prop enables the component to participate in the panel management system, consistent with other components in the PR.


65-70: Effective implementation of shared panel state.

The addition of PLUGIN_NAME from useLayout() and the reactive panelState that's provided to the component context supports the flexible layout system by enabling consistent plugin identification and state sharing between components.


111-111: Good exposure of PLUGIN_NAME to template.

Making PLUGIN_NAME available in the template ensures consistency in plugin identification throughout the component.


130-152: Well-styled change indicator and save button.

The styling for the change indicator and save button is clean and effective, providing good visual feedback when changes are made.


154-157: Appropriate content padding adjustments.

The padding and height calculations for the code editor content have been updated to fit well within the new panel structure.

packages/common/component/PluginSetting.vue (6)

3-11: Enhanced template structure with improved dynamic classes and styling

The template has been improved with a proper ID and dynamic class/style bindings that support the new flexible layout functionality. This approach allows for cleaner styling based on alignment direction.

Adding the ID also makes DOM selection more reliable for external components that might need to reference this element.


42-47: Good addition of necessary imports for the new functionality

Adding computed, nextTick and the useLayout composable from the meta-register aligns well with the PR objectives of implementing a flexible layout for the plugin panel.


133-139: Avoid direct DOM queries in watchEffect

Relying on document.querySelector might cause timing issues in complex UIs. Using a template ref for .second-panel or a reactive approach can reduce risk and simplify testing.

Consider refactoring to use template refs:

-watchEffect(() => {
-  // 处理二级面板偏移量
-  const secondPanelOffset = document.querySelector('.plugin-setting')?.clientWidth + firstPanelOffset.value
-  nextTick(() => {
-    document.querySelector('.second-panel')?.style.setProperty(secondPanelAlign.value, `${secondPanelOffset}px`)
-  })
-})

+// Add refs in the template
+<div
+  id="panel-setting"
+  ref="pluginSettingRef"
+  :class="..."
+  :style="alignStyle"
+>
+
+// In setup
+const pluginSettingRef = ref(null)
+const secondPanelRef = ref(null)
+
+watchEffect(() => {
+  // Only execute if both refs are available
+  if (pluginSettingRef.value && secondPanelRef.value) {
+    const secondPanelOffset = pluginSettingRef.value.clientWidth + firstPanelOffset.value
+    nextTick(() => {
+      secondPanelRef.value.style.setProperty(secondPanelAlign.value, `${secondPanelOffset}px`)
+    })
+  }
+})

154-158: Good use of computed property for dynamic shadow class

The shadowClass computed property elegantly determines the appropriate shadow class based on component props, making the template cleaner and the logic more centralized.


184-192: Good visual enhancement with directional shadows

The shadow classes provide visual depth that changes based on the panel's position, enhancing the UI's visual hierarchy. This aligns well with the PR's goal of improving the plugin panel's visual experience.


256-258: Simple but effective right alignment style

The .align-right class provides a clean way to position the panel on the right side of the screen. This is a key component for the flexible layout functionality mentioned in the PR objectives.

packages/utils/src/constants/index.js (2)

167-168: Validate naming and usage of PLUGIN_DEFAULT_WIDTH.

Adding PLUGIN_DEFAULT_WIDTH is a clear improvement for maintainability. Please place it in relevant usage contexts (e.g., plugin panel sizing) and confirm that no conflicting hardcoded widths remain in the codebase.


100-102:

Details

✅ Verification successful

Confirm consistent usage of new storage keys.

The new constants STORAGE_KEY_LEFT_FIXED_PANELS and STORAGE_KEY_RIGHT_FIXED_PANELS replace a more generic single key. Ensure all references in the codebase are updated and tested to prevent leftover references to the old key.

Run this script to verify references:


🏁 Script executed:

#!/bin/bash
rg --context 3 'STORAGE_KEY_(LEFT|RIGHT)_FIXED_PANELS'

Length of output: 2053


Storage Keys Usage Confirmed
The regex search confirms that both STORAGE_KEY_LEFT_FIXED_PANELS and STORAGE_KEY_RIGHT_FIXED_PANELS are consistently used in the codebase. They appear in packages/utils/src/constants/index.js and in packages/layout/src/composable/useLayout.js with no remnants of the old storage key. Please proceed with comprehensive testing to ensure that all functionality relying on these keys operates as expected.

packages/plugins/schema/src/Main.vue (3)

2-41: Verify that <plugin-panel> is properly replacing any prior container logic.

The introduction of <plugin-panel> to wrap content is a good improvement for consistent layout. Double-check other parts of the application (if any) that formerly controlled container height, drag behavior, or header structure so you don’t accidentally duplicate or conflict with this new approach.


44-46: Imports look good.

Importing PluginPanel from @opentiny/tiny-engine-common aligns with the new usage. No immediate concerns here.


62-66: Prop definition for fixedPanels is clear.

Passing this array into <plugin-panel> is consistent with the changes made in constants/index.js for left and right fixed panels. Good job on decoupling logic from design.

packages/common/component/PluginRightMenu.vue (3)

2-22: Double-check v-if="false" usage.

The entire list is wrapped in v-if="false", which effectively prevents rendering. If this is intentional (e.g., toggled at runtime) and replaced by other logic, clarify or remove it. Otherwise, this might be a placeholder code leftover.


82-98: Ensure consistent naming for hideContextMenu, hidePlugin, and switchAlign.

These methods are well-defined and handle user interactions. Just be sure that transitions (e.g., animations) or other visual cues finish before reflow triggers if you plan to extend the UI.


100-110: Conditional usage in hideSidebar.

Reusing the changeMenuShown method for toggling sidebars is suitable. Confirm anywhere else in the code that depends on the previous approach of toggling the sidebar. Potential race conditions or mismatch states can occur if used simultaneously in multiple components.

packages/layout/src/DesignPlugins.vue (4)

38-66: Similarly use stable keys when iterating bottomNavLists.

Same rationale as the topNavLists. Using item.id as the key will help keep list item states consistent when items are shuffled or re-sorted.


69-95: Looks good!

The usage of <plugin-right-menu> with ref="rightMenu" for context menus is well-structured, and the event-based communication appears clean and maintainable.


99-108: Double-check alignment switching logic to avoid duplicates.

Methods like switchAlign splice the plugin from one list and then emit an event to change alignment. Confirm that if the same plugin already exists in the destination list, it gets cleaned up to prevent duplicates.

Also applies to: 114-185


399-402: Consolidate repeated .not-selected definitions.

A previous review comment suggested merging or reusing this .not-selected style across files to avoid duplication or confusion.

packages/layout/src/DesignSettings.vue (3)

48-60: Import statements look good.

No issues found with import references or version constraints.


62-185: Verify plugin removal when switching sides.

The functions switchAlign and changeAlign effectively splice items when moving them. Please ensure that the plugin cannot remain in both arrays if it was already on the target side, preventing duplicates.


191-318: Unify .not-selected style definitions.

As highlighted in prior reviews, .not-selected is defined more than once in different files. Consolidating it helps reduce confusion and ensure consistent styling.

packages/common/component/PluginPanel.vue (2)

2-39: Conditional draggable sections look fine.

Enabling or disabling the drag behavior via v-if="draggableEnabled" is a neat approach, and the two resizer divs are cleanly separated for left and right usage.


291-344: Styling changes provide clear visual feedback.

The resizer effect, including hover transitions and the .dragging class, is an excellent UX touch. No concerns here.

packages/layout/src/composable/useLayout.js (4)

14-35: New constants and reactive objects are well-organized.

Defining PLUGIN_POSITION and pluginState in one place improves maintainability, and the naming is appropriately descriptive.


84-96: Left/right fixed panels logic is clear.

The toggling logic for changeLeftFixedPanels and changeRightFixedPanels is straightforward, using storage and array operations. Looks good.


128-130: Check if render might be null or undefined.

When computing leftPanelFixed or rightPanelFixed, confirm that layoutState.plugins.render or layoutState.settings.render is always defined. Otherwise, .includes(undefined) can fail.


298-303: Initialization logic is functional.

initPluginStorageReactive and getPluginsByPosition are well designed. They simplify integration by decoupling plugin storage from the rest of the code. Good approach.

Also applies to: 341-341

Copy link
Contributor

@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: 0

🧹 Nitpick comments (8)
packages/plugins/script/src/Main.vue (4)

13-17: Good visual feedback for unsaved changes

The addition of a red indicator dot for unsaved changes provides important visual feedback to users. However, consider adding a tooltip to explicitly communicate its meaning.

- <i v-show="state.isChanged" class="red"></i>
+ <i v-show="state.isChanged" class="red" title="有未保存的更改"></i>

55-58: Improve prop definition with default value and validation

The fixedPanels prop would benefit from a default value and more specific type validation to prevent potential runtime errors.

fixedPanels: {
  type: Array,
+ default: () => [],
+ validator: (value) => Array.isArray(value)
}

67-70: Document the purpose of the provided state

The reactive panelState is provided to child components, but its purpose and consumption pattern aren't clear. Consider adding a comment explaining how this state is used by child components.

// Create reactive panel state for child components
const panelState = reactive({
  emitEvent: emit
})
+ // This state is consumed by child components to access the emit function
provide('panelState', panelState)

167-169: Consider using CSS variables for consistency

For better maintainability, consider using CSS variables for spacing values like padding and margins.

.code-edit-content {
-  padding: 0 12px;
+  padding: 0 var(--te-spacing-s, 12px);
  height: calc(100% - 12px);
}
packages/plugins/block/src/Main.vue (1)

472-473: Margin adjustment improves spacing

Changing from margin: 12px 0 to margin-bottom: 12px removes the top margin, which likely creates a more consistent spacing in the panel's layout.

packages/plugins/state/src/Main.vue (1)

513-514: Improved tab header padding

The update to the tab header padding ensures consistent spacing around the tabs, improving the overall appearance of the plugin panel.

packages/layout/src/DesignSettings.vue (1)

20-36: Well-structured draggable navigation panel.

The navigation panel with drag-and-drop functionality is nicely implemented. The context menu integration is properly handled with the @contextmenu.prevent directive.

Consider using unique IDs instead of array indices as keys for the v-for loop to ensure proper component reconciliation when items are reordered:

- :key="index"
+ :key="item.id"
packages/layout/src/composable/useLayout.js (1)

164-178: Improve error handling in plugin storage initialization.

The current implementation throws the error directly, which might cause the application to crash. Consider logging the error and providing a fallback instead.

try {
  const storedPlugin = localStorage.getItem('plugin')
  if (storedPlugin) {
    plugin = JSON.parse(storedPlugin)
  }
} catch (error) {
-  throw new Error(error)
+  console.error('Failed to parse plugin storage:', error)
+  // Fallback to empty array already happens below
}
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 4fd4959 and bdc039f.

⛔ Files ignored due to path filters (3)
  • packages/design-core/assets/display-inline.svg is excluded by !**/*.svg
  • packages/design-core/assets/form.svg is excluded by !**/*.svg
  • packages/design-core/assets/target.svg is excluded by !**/*.svg
📒 Files selected for processing (58)
  • packages/canvas/DesignCanvas/src/DesignCanvas.vue (5 hunks)
  • packages/canvas/container/src/components/CanvasResize.vue (2 hunks)
  • packages/common/component/PluginPanel.vue (5 hunks)
  • packages/common/component/PluginRightMenu.vue (1 hunks)
  • packages/common/component/PluginSetting.vue (9 hunks)
  • packages/common/component/index.js (1 hunks)
  • packages/common/package.json (1 hunks)
  • packages/common/styles/vars.less (1 hunks)
  • packages/configurator/package.json (1 hunks)
  • packages/layout/package.json (1 hunks)
  • packages/layout/src/DesignPlugins.vue (9 hunks)
  • packages/layout/src/DesignSettings.vue (2 hunks)
  • packages/layout/src/Main.vue (4 hunks)
  • packages/layout/src/composable/useLayout.js (5 hunks)
  • packages/plugins/block/meta.js (1 hunks)
  • packages/plugins/block/src/BlockSetting.vue (4 hunks)
  • packages/plugins/block/src/Main.vue (6 hunks)
  • packages/plugins/bridge/meta.js (1 hunks)
  • packages/plugins/bridge/src/BridgeSetting.vue (4 hunks)
  • packages/plugins/bridge/src/Main.vue (4 hunks)
  • packages/plugins/datasource/meta.js (1 hunks)
  • packages/plugins/datasource/src/DataSourceForm.vue (6 hunks)
  • packages/plugins/datasource/src/DataSourceGlobalDataHandler.vue (3 hunks)
  • packages/plugins/datasource/src/DataSourceRecordList.vue (3 hunks)
  • packages/plugins/datasource/src/DataSourceRemotePanel.vue (5 hunks)
  • packages/plugins/datasource/src/Main.vue (5 hunks)
  • packages/plugins/help/meta.ts (1 hunks)
  • packages/plugins/help/src/HelpIcon.vue (1 hunks)
  • packages/plugins/i18n/meta.js (1 hunks)
  • packages/plugins/i18n/src/Main.vue (4 hunks)
  • packages/plugins/materials/meta.js (1 hunks)
  • packages/plugins/materials/src/meta/block/src/BlockGroupPanel.vue (4 hunks)
  • packages/plugins/materials/src/meta/layout/src/Main.vue (3 hunks)
  • packages/plugins/page/meta.js (1 hunks)
  • packages/plugins/page/src/Main.vue (5 hunks)
  • packages/plugins/page/src/PageFolderSetting.vue (4 hunks)
  • packages/plugins/page/src/PageSetting.vue (4 hunks)
  • packages/plugins/robot/meta.js (1 hunks)
  • packages/plugins/schema/meta.js (1 hunks)
  • packages/plugins/schema/src/Main.vue (5 hunks)
  • packages/plugins/script/meta.js (1 hunks)
  • packages/plugins/script/src/Main.vue (5 hunks)
  • packages/plugins/state/meta.js (1 hunks)
  • packages/plugins/state/src/Main.vue (5 hunks)
  • packages/plugins/tree/meta.js (1 hunks)
  • packages/plugins/tree/src/Main.vue (4 hunks)
  • packages/plugins/tutorial/meta.js (1 hunks)
  • packages/register/src/common.js (2 hunks)
  • packages/settings/events/index.js (1 hunks)
  • packages/settings/events/meta.js (1 hunks)
  • packages/settings/events/src/Main.vue (1 hunks)
  • packages/settings/props/meta.js (1 hunks)
  • packages/settings/props/src/Main.vue (1 hunks)
  • packages/settings/styles/meta.js (1 hunks)
  • packages/settings/styles/src/Main.vue (7 hunks)
  • packages/theme/base/src/page/base-config-page.less (1 hunks)
  • packages/toolbars/themeSwitch/src/Main.vue (1 hunks)
  • packages/utils/src/constants/index.js (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (38)
  • packages/plugins/state/meta.js
  • packages/plugins/tutorial/meta.js
  • packages/plugins/block/meta.js
  • packages/common/package.json
  • packages/common/styles/vars.less
  • packages/plugins/datasource/meta.js
  • packages/plugins/robot/meta.js
  • packages/utils/src/constants/index.js
  • packages/configurator/package.json
  • packages/plugins/help/src/HelpIcon.vue
  • packages/plugins/page/meta.js
  • packages/plugins/bridge/meta.js
  • packages/settings/events/meta.js
  • packages/register/src/common.js
  • packages/common/component/index.js
  • packages/plugins/schema/meta.js
  • packages/toolbars/themeSwitch/src/Main.vue
  • packages/plugins/help/meta.ts
  • packages/plugins/materials/meta.js
  • packages/plugins/page/src/PageFolderSetting.vue
  • packages/plugins/i18n/meta.js
  • packages/plugins/script/meta.js
  • packages/canvas/container/src/components/CanvasResize.vue
  • packages/layout/package.json
  • packages/theme/base/src/page/base-config-page.less
  • packages/plugins/datasource/src/DataSourceRecordList.vue
  • packages/settings/props/meta.js
  • packages/settings/events/index.js
  • packages/plugins/datasource/src/DataSourceForm.vue
  • packages/plugins/bridge/src/BridgeSetting.vue
  • packages/plugins/datasource/src/Main.vue
  • packages/settings/styles/src/Main.vue
  • packages/plugins/tree/meta.js
  • packages/plugins/page/src/Main.vue
  • packages/common/component/PluginRightMenu.vue
  • packages/plugins/materials/src/meta/block/src/BlockGroupPanel.vue
  • packages/settings/styles/meta.js
  • packages/plugins/datasource/src/DataSourceRemotePanel.vue
🧰 Additional context used
🧬 Code Definitions (1)
packages/layout/src/composable/useLayout.js (1)
packages/utils/src/constants/index.js (6) (6)
  • STORAGE_KEY_LEFT_FIXED_PANELS (100-100)
  • STORAGE_KEY_LEFT_FIXED_PANELS (100-100)
  • STORAGE_KEY_RIGHT_FIXED_PANELS (101-101)
  • STORAGE_KEY_RIGHT_FIXED_PANELS (101-101)
  • PLUGIN_DEFAULT_WIDTH (168-168)
  • PLUGIN_DEFAULT_WIDTH (168-168)
⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: push-check
🔇 Additional comments (101)
packages/plugins/script/src/Main.vue (3)

2-11: The new PluginPanel implementation improves layout flexibility

The switch to a structured <plugin-panel> component with key props like fixed-name, fixedPanels, and draggable-enabled aligns well with the PR's goal of creating a flexible layout for plugins. This encapsulation enables the drag functionality and unified fixed/floating logic mentioned in the PR objectives.


34-37: Appropriate Vue composition API usage

The addition of reactive and provide from Vue, along with the new imports for layout utilities, follows good practices for component state management in the Vue composition API.


142-164: Well-structured UI elements for visual feedback

The styling for the icon wrap, save button, and indicator dot is well-implemented. The absolute positioning of the red dot provides a clean visual indicator without disrupting the layout.

packages/settings/events/src/Main.vue (5)

2-19: Good implementation of the plugin-panel component

The code has been restructured to wrap the existing <tiny-collapse> component within a new <plugin-panel> component. This implementation supports the PR's objective of creating a flexible layout for the plugin panel.

The configuration properties like title, fixed-panels, fixed-name, and event handling look correct.


23-28: Appropriate imports added for the new structure

The additional imports support the new component structure properly. Adding reactive, provide, defineProps, defineEmits from Vue along with the engine-specific imports is necessary for the plugin panel enhancements.


31-31: Good usage of layout constants

Extracting PLUGIN_NAME from useLayout() is a clean approach for maintaining consistent naming conventions across the plugin system.


33-35: Props definition looks good

Defining the fixedPanels prop correctly to receive an array of fixed panel configurations.


39-43: Well-structured state management with provide/inject pattern

The reactive state object with the emit function is properly provided to child components. This pattern allows for clean communication between parent and child components in the plugin system.

packages/settings/props/src/Main.vue (6)

2-18: Good implementation of the plugin-panel wrapper

The code correctly wraps the existing content with the new <plugin-panel> component. The configuration properties are consistent with the implementation in other files and support the PR's objective of creating a unified plugin panel layout system.


22-24: Appropriate imports for the new component structure

The modified imports add necessary functionality for the new component structure. Adding reactive and provide from Vue and importing PluginPanel from the common package is appropriate.


32-34: Component registration is properly updated

The PluginPanel component is correctly added to the components list.


35-35: Setup function signature appropriately updated

The updated setup function signature correctly accepts props and { emit } to support the new component structure.


40-45: Good state management implementation

The reactive state with the emit function is properly created and provided to descendant components, consistent with the pattern used in other files.


54-55: Layout constants properly added to the returned object

Adding PLUGIN_NAME to the returned object makes it available in the template, which is necessary for the plugin panel configuration.

packages/plugins/block/src/BlockSetting.vue (4)

6-7: Good implementation of dynamic alignment and fixed naming

Adding the :align and :fixed-name props to the plugin-setting component supports the PR's objective of enabling repositioning of plugins. This will allow the plugin to be dynamically aligned based on the layout configuration.


91-98: Import statement properly updated

The import statement has been correctly structured to include useLayout among other imports. The organization is clean and follows the project's import style.


164-165: Good implementation of layout utilities

Extracting PLUGIN_NAME and getPluginByLayout from useLayout() provides the necessary tools for dynamic plugin positioning. The computed property align correctly uses getPluginByLayout to determine the alignment based on the plugin name.


292-293: Layout configuration properly added to the returned object

Adding align and PLUGIN_NAME to the returned object makes them available in the template, which is necessary for the plugin panel configuration.

packages/plugins/materials/src/meta/layout/src/Main.vue (3)

2-7: Good implementation of the plugin-panel with fixed naming

The plugin-panel component is correctly configured with fixed-name and fixedPanels props. The implementation supports the PR's objective of creating a unified plugin panel layout system.

Note that the header template section has been removed, which is consistent with the new plugin panel design.


23-23: Appropriate import of layout constants

Importing META_APP as PLUGIN_NAME provides consistency with the naming conventions used in other files. This standardization helps maintain a unified approach to plugin configuration.


83-83: Layout constants properly added to the returned object

Adding PLUGIN_NAME to the returned object makes it available in the template, which is necessary for the plugin panel configuration.

packages/plugins/tree/src/Main.vue (3)

9-9: Consider renaming draggable-enabled for clarity.

The prop name draggable-enabled implies general drag functionality, but it specifically controls width resizing through dragging.

Consider renaming to width-resizable or resize-enabled to better represent its functionality.


2-11: LGTM! Panel flexibility enhancement implemented correctly.

The panel now properly accepts fixed-name and fixedPanels properties, enabling the new flexible layout system.


90-93: Good implementation of state management with Vue provide/inject pattern.

Using provide to share the panel state with child components is a clean approach for event handling across component boundaries.

packages/plugins/datasource/src/DataSourceGlobalDataHandler.vue (2)

2-9: Properly configured plugin panel with alignment properties.

The plugin-setting component now correctly uses the align property and fixed-name attributes, consistent with the new plugin layout system.


58-58: Good use of computed property for dynamic alignment.

Computing the alignment based on the layout configuration provides flexibility in positioning the panel.

packages/plugins/i18n/src/Main.vue (2)

2-9: LGTM! Plugin panel configured correctly with fixed-name and fixedPanels.

The component now properly integrates with the flexible layout system.


170-173: Well-structured panel state management.

Using a reactive object to encapsulate the emit function and providing it to child components is a clean approach for communication.

packages/plugins/bridge/src/Main.vue (2)

2-7: Properly integrated with the flexible layout system.

The plugin-panel component now correctly uses the fixed-name and fixedPanels props.


47-50: Consistent implementation of panel state management.

The reactive panelState object with emitEvent maintains consistency with the pattern used across other plugin components.

packages/plugins/schema/src/Main.vue (4)

2-40: Well-structured update to use a plugin-panel component

The refactoring from a div-based structure to a plugin-panel component improves the organization and maintainability of the UI. The added properties for fixedName, fixedPanels, and draggable-enabled align well with the flexible layout objectives of this PR.


44-47: Good import organization

Adding the necessary imports for the new component structure, including provide and PluginPanel, keeps the dependencies clear and properly organized.


62-66: Props and state management properly implemented

The addition of the fixedPanels prop and the panelState reactive object with provide/inject pattern enables effective communication between components, which is essential for the plugin panel's flexible layout functionality.

Also applies to: 78-81


218-219: Height calculation adjusted for new component structure

The height calculation has been updated to accommodate the new component structure, ensuring the Monaco editor properly fills the available space.

packages/plugins/block/src/Main.vue (3)

2-14: Plugin panel implementation consistent with project standards

The implementation of the plugin-panel component with its properties (fixed-name, fixedPanels) maintains consistency with other plugin components, ensuring a uniform approach to flexible layouts throughout the application.


219-223: Well-structured props and panel state management

The addition of the fixedPanels prop and the implementation of the panelState with provide/inject pattern ensures proper state management across components, which is crucial for the plugin's flexible layout functionality.

Also applies to: 273-279


319-321: Proper cleanup on close

The close method now properly emits the close event and calls closePanel(), ensuring that both the UI state and any internal state are properly cleaned up when the panel is closed.

packages/canvas/DesignCanvas/src/DesignCanvas.vue (4)

2-2: Improved interaction state with conditional class

The addition of the not-selected class based on the getMoveDragBarState() function enhances the visual feedback during drag operations, aligning with the PR's goal to improve the dragging experience.


70-71: Good modularization of layout-related functions

Importing specific functions from useLayout maintains good separation of concerns and keeps the code focused on specific functionality.


156-167: Enhanced panel management logic

The updated nodeSelected function now properly respects the fixed status of panels before attempting to close them, ensuring that fixed panels remain open during node selection, which improves user experience.


299-304: Effective pointer event handling

The addition of the not-selected class with pointer-events: none and user-select: none properly prevents interaction with the canvas during drag operations, which is essential for smooth dragging functionality.

packages/plugins/state/src/Main.vue (4)

2-11: Consistent plugin panel implementation

The implementation of the plugin-panel component with appropriate properties maintains consistency with other plugin components and aligns with the PR's goal of implementing a flexible layout.


45-45: Dynamic panel positioning

The addition of :style="alignStyle" to the right panel enables dynamic positioning based on the panel's alignment, which is crucial for the flexible layout functionality.


148-156: Well-implemented dynamic panel offset calculation

The computed properties firstPanelOffset and alignStyle effectively calculate the positioning of panels based on their layout configuration, enabling seamless repositioning of panels via dragging or menu options.


158-162: Effective state sharing with provide/inject

The implementation of the panelState reactive object with provide/inject pattern ensures proper communication between components, which is essential for the flexible panel layout functionality.

packages/plugins/page/src/PageSetting.vue (4)

2-8: Props added for flexible layout management

The plugin-setting component has been enhanced with two new props:

  • :fixed-name="PLUGIN_NAME.AppManage" - Specifies the plugin identifier
  • :align="align" - Determines the alignment of the plugin

These additions are consistent with the PR objective to implement a flexible layout for plugin panels.


63-63: Added computed import to support new reactive property

The import statement now includes computed from Vue, which is necessary for the new dynamic align property.


145-146: Added layout integration for plugin positioning

Destructuring PLUGIN_NAME and getPluginByLayout from useLayout() brings in the necessary layout management utilities. The computed property align determines the plugin's alignment dynamically based on the plugin name.


410-411: Exposed layout properties to the template

Added align and PLUGIN_NAME to the component's return object, making them available in the template.

packages/layout/src/DesignPlugins.vue (11)

4-36: Replaced static nav list with draggable component

The static navigation list has been replaced with a vue-draggable-next component, enabling:

  • Drag-and-drop functionality for plugin reordering
  • Proper event handling with @end="onEnd"
  • Filtering specific plugins with the filter property

This implementation supports the PR's goal of allowing users to reposition plugins via dragging.


39-65: Enhanced bottom navigation with draggable functionality

The bottom navigation area now features:

  • A flexible layout with proper spacing
  • Draggable functionality matching the top navigation
  • Consistent DOM structure with the top navigation
  • Context menu support for plugin repositioning

This maintains consistency with the top navigation while supporting the PR's objective of providing flexible plugin layouts.


69-87: Improved plugin panel rendering with conditional class

The plugin panel now:

  • Includes a conditional class for drag state management
  • Has proper positioning classes based on fixed state
  • Wraps the component in a container for better layout control

The addition of the not-selected class during drag operations prevents unwanted interactions while dragging, improving the user experience.


90-95: Added context menu for plugin management

A new plugin-right-menu component has been integrated to provide:

  • A consistent interface for plugin alignment changes
  • Access to all plugins from both top and bottom lists
  • A centralized way to trigger the switchAlign action

This supports the PR objective of allowing users to control plugin visibility and positioning through right-click menus.


122-123: Added pluginList prop for unified plugin management

Added a new pluginList prop to receive all available plugins (from both left and right panels), enabling:

  • Consistent plugin identification across the application
  • Better management of plugin state and positioning
  • Unified source of truth for plugin information

This prop works together with the existing plugins prop to maintain backward compatibility.


147-153: Improved context menu handling

The showContextMenu method now provides:

  • Different behavior based on click target (plugin vs empty area)
  • Contextual information about the clicked plugin (item, index, position)
  • Proper event positioning using client coordinates

This enhances the right-click functionality required for the flexible plugin layout.


155-170: Fixed plugin duplication issue when changing alignment

The changeAlign method now properly:

  1. Finds and removes the plugin from its current list if it exists
  2. Then adds it to the target list

This fixes the issue identified in the previous review where plugins could be duplicated when changing alignment.


177-182: Enhanced component resolution with safety checks

The currentComponent computed property now:

  • Verifies plugin existence in both navigation lists
  • Returns null when a plugin isn't found
  • Prevents errors when accessing non-existent components

This improves error handling and provides a more robust UI experience.


228-238: Implemented alignment switching with proper cleanup

The switchAlign method:

  • Properly removes the plugin from its source list
  • Emits an event to update the parent component
  • Closes the panel if needed when changing sides
  • Triggers the layout update through dragPluginLayout

This method is key to enabling the flexible plugin positioning required by the PR.


245-248: Added drag end handler for layout updates

The onEnd method properly:

  • Checks if the plugin has moved between different sides
  • Closes the panel if needed
  • Updates the plugin layout based on the drag operation

This completes the drag-and-drop functionality for repositioning plugins.


399-402: Added styling for non-interactive state during dragging

The .not-selected class provides:

  • Disabled pointer events to prevent unwanted interactions
  • User-select prevention to improve drag experience

This small but important style addition improves the drag-and-drop user experience.

packages/layout/src/Main.vue (6)

9-16: Enhanced DesignPlugins with conditional rendering and alignment control

The design-plugins component now:

  • Uses a conditional render with v-if="leftMenuShownStorage" for better control
  • Includes a reference to access methods on the component
  • Passes the combined pluginList for unified plugin management
  • Handles alignment changes with the new @changeLeftAlign event

These changes support the PR's goal of implementing a unified logic for the floating and fixed states of plugin panels.


21-29: Enhanced DesignSettings with conditional rendering and alignment control

Similar to the left panel, the right panel now:

  • Uses conditional rendering with v-if="rightMenuShownStorage"
  • Includes a reference for method access
  • Receives the unified pluginList
  • Handles alignment changes with @changeRightAlign

These parallel changes ensure consistent behavior between left and right panels.


67-68: Expanded layout state access with menu visibility controls

The destructuring now includes:

  • leftMenuShownStorage and rightMenuShownStorage for conditional rendering
  • initPluginStorageReactive for initializing plugin state

This provides the necessary reactive state for controlling panel visibility.


75-83: Added cross-panel communication for alignment changes

The new refs and methods:

  • Create references to both panel components (left and right)
  • Implement methods to propagate alignment changes between panels
  • Enable plugins to move from one panel to another

This is a key mechanism for the flexible layout implementation described in the PR.


86-121: Implemented unified plugin list management with persistent storage

The new plugin management logic:

  1. Combines plugins and settings into a unified pluginList
  2. Organizes plugins by alignment group
  3. Assigns consistent properties to each plugin (width, align, index, etc.)
  4. Persists the configuration to localStorage for state persistence

This comprehensive approach provides a solid foundation for the flexible plugin layout implementation.


167-168: Updated right panel container to use flexbox layout

Changed the .tiny-engine-right-wrap styling from:

  • Position-based layout to flexbox layout
  • Added row direction with nowrap

This provides better structural support for the flexible layout of the right panel.

packages/common/component/PluginSetting.vue (8)

2-12: Enhanced plugin setting with dynamic positioning classes

The plugin setting component now supports:

  • Identification with an ID for easier DOM access
  • Conditional classes for different alignments
  • Shadow styling based on position
  • Dynamic CSS through the computed alignStyle property

These enhancements make the component much more flexible for different layout positions.


42-47: Added necessary imports for enhanced functionality

Added imports:

  • nextTick for proper DOM updates
  • computed for reactive style properties
  • useLayout for accessing the layout management system

These imports enable the new dynamic positioning features of the component.


104-111: Added props for flexible positioning

Two important new props were added:

  • fixedName: Identifies the plugin in the layout system
  • align: Specifies the positioning direction (leftTop, rightTop, etc.)

These props are central to the flexible layout implementation, allowing plugins to be placed consistently in various positions.


121-131: Added computed properties for dynamic positioning

Three new computed properties calculate positioning values:

  • firstPanelOffset: Gets the width of a specified fixed panel
  • secondPanelAlign: Determines alignment direction based on the align prop
  • alignStyle: Constructs the CSS positioning string

These properties enable the component to adapt its position dynamically based on other panels.


133-139: Avoid direct DOM queries in watchEffect

The current implementation directly queries the DOM to adjust panel positioning:

watchEffect(() => {
  const secondPanelOffset = document.querySelector('.plugin-setting')?.clientWidth + firstPanelOffset.value
  nextTick(() => {
    document.querySelector('.second-panel')?.style.setProperty(secondPanelAlign.value, `${secondPanelOffset}px`)
  })
})

This approach may lead to timing issues in complex UIs and can be hard to test.

Consider using template refs instead of direct DOM queries:

-watchEffect(() => {
-  const secondPanelOffset = document.querySelector('.plugin-setting')?.clientWidth + firstPanelOffset.value
-  nextTick(() => {
-    document.querySelector('.second-panel')?.style.setProperty(secondPanelAlign.value, `${secondPanelOffset}px`)
-  })
-})
+// Add refs to the template
+const panelRef = ref(null)
+const secondPanelRef = ref(null)
+
+// Then use the refs in the watchEffect
+watchEffect(() => {
+  if (!panelRef.value || !secondPanelRef.value) return
+  
+  const secondPanelOffset = panelRef.value.clientWidth + firstPanelOffset.value
+  nextTick(() => {
+    secondPanelRef.value.style.setProperty(secondPanelAlign.value, `${secondPanelOffset}px`)
+  })
+})

Don't forget to add the corresponding ref="panelRef" and ref="secondPanelRef" attributes to the relevant elements in the template.


155-158: Added shadow class computation for visual distinction

The shadowClass computed property:

  • Adds no shadow for secondary panels
  • Adds appropriate left or right shadow based on alignment
  • Improves visual hierarchy and separation between panels

This visual enhancement helps users understand the panel structure better.


183-193: Enhanced shadow styling for different alignments

Added specific shadow styles for both left and right aligned panels:

  • .shadow-left applies shadow to the right edge
  • .shadow-right applies shadow to the left edge
  • Both remove their respective borders for a cleaner look

This visual refinement improves the appearance of the flexible panel layout.


256-258: Added right alignment styling

Added the .align-right class to position panels on the right side of the screen, complementing the existing left positioning.

This small but crucial addition enables the right-side panel layout required by the PR.

packages/layout/src/DesignSettings.vue (9)

3-3: Good implementation of drag interaction prevention.

The conditional class .not-selected is a smart way to disable interactions during drag operations, improving the user experience by preventing unintended clicks.


4-18: Clean implementation of the dynamic right panel.

The right panel implementation properly handles conditional rendering based on the selected panel and applies appropriate classes for fixed/floating states. The component structure allows for flexible content rendering.


39-44: Good separation of context menu functionality.

Extracting the right-click menu into a separate component improves code modularity and reusability across the application.


93-99: Clean context menu handling.

The showContextMenu method properly handles different types of context menu interactions based on the provided parameters.


101-104: Efficient plugin component registration.

Using a forEach loop to populate the components and iconComponents objects from the pluginList prop is a clean approach.


124-132: Well-implemented plugin alignment adjustment.

The changeAlign method effectively handles the repositioning of plugins with proper checks for existing items.


139-145: Smart toggle behavior for plugin menu.

The clickMenu method intelligently handles the toggle behavior, closing the panel if it's already open or opening it if it's not.


157-160: Comprehensive drag event handling.

The onEnd method properly handles drag operations, with intelligent panel closing when plugins are moved between sides.


315-318: Duplicate CSS class definition.

The .not-selected class appears to be defined twice in the file - here and at lines 332-334 (not shown in this code but mentioned in previous comments).

packages/common/component/PluginPanel.vue (10)

2-2: Good dynamic width implementation.

Using a binding for the panel width enables responsive resizing and improves user experience.


12-22: Well-implemented collapsible functionality with tooltip.

The collapsible icon with tooltip provides clear user feedback and improves usability.


23-28: Clear visual indication for fixed panel state.

The fixed panel button properly changes its icon and tooltip based on the current state, providing good visual feedback to users.


32-34: Improved content scrolling container.

Wrapping the content slot in a scrollable container improves the handling of overflowing content.


36-39: Well-implemented resizing functionality.

The conditional resizers on both sides allow for flexible panel resizing based on panel position.


166-167: Efficient mouse move handling with throttling.

Using useThrottleFn from @vueuse/core for mouse move events is an excellent optimization that will improve performance during resizing operations.


208-211: Avoid direct DOM queries for resizer elements.

Using document.querySelector to get DOM elements is brittle and can lead to issues if the DOM structure changes.


213-216: Good collapse state management with event emission.

The clickCollapseIcon method properly toggles the state and notifies the parent component via an event.


291-316: Clean resizer styling with visual feedback.

The resizer styles provide appropriate visual feedback with hover and dragging states, improving the user experience during resizing operations.


334-343: Optimized scrolling container styles.

The .scroll-content styles properly hide the scrollbar while maintaining scrolling functionality across different browsers.

packages/layout/src/composable/useLayout.js (8)

20-27: Well-defined plugin position constants.

Creating a PLUGIN_POSITION object with clear constant values improves code readability and maintainability.


64-69: Clean drag bar state management.

The getter and setter functions for the drag bar state provide a clean API for managing this state.


70-83: Persistent menu visibility state.

Using useStorage for menu visibility ensures the user's preferences are preserved across sessions.


84-96: Elegant fixed panels toggle implementation.

The functions for toggling fixed panels use a clean pattern: if the panel exists, remove it; otherwise, add it. This avoids duplication and ensures atomic updates.


126-130: Comprehensive fixed panels status check.

The getFixedPanelsStatus function provides a convenient way to check the fixed status of both panels at once.


182-194: Robust plugin width management.

The width management functions properly handle both existing and new plugins, with appropriate fallback to a default width.


234-275: Comprehensive drag and drop implementation.

The dragPluginLayout function handles complex drag operations including both within-list and cross-list scenarios. The index adjustments ensure consistent ordering after moves.


292-297: Safe plugin visibility toggle with initialization.

The changePluginShown function safely handles the case where a plugin doesn't exist in storage yet by initializing it with a default visibility state.

Copy link
Contributor

@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: 0

🔭 Outside diff range comments (1)
packages/plugins/schema/src/Main.vue (1)

87-98: ⚠️ Potential issue

Fix inverted condition logic in close function.

The condition logic appears to be inverted. If state.pageData === strs is true, there are no changes, but the code treats this as if there are changes.

const close = () => {
  const strs = app.refs.container.getEditor().getValue()
-  const isChanged = state.pageData === strs
+  const isChanged = state.pageData !== strs

  if (!isChanged) {
+    emit('close')
+  } else {
    confirm({
      title: '提示',
      message: '有改动未保存,您确定关闭吗?',
      exec: () => emit('close')
    })
-  } else {
-    emit('close')
  }
}
🧹 Nitpick comments (5)
packages/common/component/PluginPanel.vue (3)

154-164: Reduce code duplication in mouse move handlers.

The right and left mouse move handlers share similar logic with only minor differences. Consider refactoring them into a single function to improve maintainability.

-const onMouseMoveRight = (event) => {
-  const newWidth = startWidth + (event.clientX - startX)
-  panelWidth.value = Math.max(MIN_WIDTH, Math.min(newWidth, MAX_WIDTH))
-  changePluginWidth(props.fixedName, panelWidth.value)
-}
-
-const onMouseMoveLeft = (event) => {
-  const newWidth = startWidth - (event.clientX - startX)
-  panelWidth.value = Math.max(MIN_WIDTH, Math.min(newWidth, MAX_WIDTH))
-  changePluginWidth(props.fixedName, panelWidth.value)
-}

+const onMouseMove = (event, direction = 'right') => {
+  const factor = direction === 'right' ? 1 : -1
+  const newWidth = startWidth + (factor * (event.clientX - startX))
+  panelWidth.value = Math.max(MIN_WIDTH, Math.min(newWidth, MAX_WIDTH))
+  changePluginWidth(props.fixedName, panelWidth.value)
+}
+
+const onMouseMoveRight = (event) => onMouseMove(event, 'right')
+const onMouseMoveLeft = (event) => onMouseMove(event, 'left')

172-206: Implement cleanup for event listeners in component lifecycle.

Event listeners attached to document aren't automatically removed when the component is unmounted, which could lead to memory leaks.

+import { inject, ref, computed, onMounted, onBeforeUnmount, provide } from 'vue'

// ...existing code...

+const removeEventListeners = () => {
+  document.removeEventListener('mousemove', throttledMouseMoveRight)
+  document.removeEventListener('mousemove', throttledMouseMoveLeft)
+  document.removeEventListener('mouseup', onMouseUpRight)
+  document.removeEventListener('mouseup', onMouseUpLeft)
+}

+onBeforeUnmount(() => {
+  removeEventListeners()
+})

const onMouseUpRight = () => {
  changeMoveDragBarState(false)
-  document.removeEventListener('mousemove', throttledMouseMoveRight)
-  document.removeEventListener('mouseup', onMouseUpRight)
+  removeEventListeners()
  rightResizer.value.style.cursor = ''
  rightResizer.value.classList.remove('dragging')
}

// ...similar changes for onMouseUpLeft...

129-131: Consider making width constants configurable through props.

The minimum and maximum width values are currently hardcoded, but could be made configurable for better component reusability.

+    /**
+     * 最小宽度
+     */
+    minWidth: {
+      type: Number,
+      default: () => constants.PLUGIN_DEFAULT_WIDTH
+    },
+    /**
+     * 最大宽度
+     */
+    maxWidth: {
+      type: Number,
+      default: 1000
+    }

// ...in setup function:
-    const MIN_WIDTH = PLUGIN_DEFAULT_WIDTH // 固定的最小宽度值
-    const MAX_WIDTH = 1000 // 固定的最大宽度值
+    const MIN_WIDTH = props.minWidth // 可配置的最小宽度
+    const MAX_WIDTH = props.maxWidth // 可配置的最大宽度
packages/plugins/schema/src/Main.vue (2)

16-22: Remove or implement the hidden import Schema feature.

This popover is permanently hidden with v-show="false". If this feature is not ready yet, consider removing it entirely or adding a prop to conditionally show it.

-<tiny-popover v-show="false" placement="bottom" trigger="hover" append-to-body content="导入 Schema">
+<!-- TODO: Implement import schema functionality -->
+<!-- <tiny-popover placement="bottom" trigger="hover" append-to-body content="导入 Schema">
   <template #reference>
     <span class="icon-wrap">
       <icon-download-link></icon-download-link>
     </span>
   </template>
-</tiny-popover>
+</tiny-popover> -->

36-38: Conditionally render the footer instead of hiding it with CSS.

The footer has display: none in CSS (line 227), but is still being rendered. For better performance, conditionally render it only when needed.

-<div class="source-code-footer">
-  <button>导入 Schema</button>
-</div>
+<!-- TODO: Implement import functionality -->
+<!-- <div class="source-code-footer">
+  <button>导入 Schema</button>
+</div> -->
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between bdc039f and ab2f4f8.

📒 Files selected for processing (4)
  • packages/common/component/PluginPanel.vue (5 hunks)
  • packages/plugins/schema/src/Main.vue (5 hunks)
  • packages/plugins/script/src/Main.vue (5 hunks)
  • packages/plugins/tree/src/Main.vue (4 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/plugins/tree/src/Main.vue
🔇 Additional comments (14)
packages/plugins/script/src/Main.vue (10)

2-11: Good restructuring to a standardized component

The refactoring to use the standardized <plugin-panel> component improves consistency with the rest of the application and adds important functionality like width resizing. The clear prop naming makes the component's purpose evident.


12-17: Well-organized header with visual feedback

The header implementation with the conditional red indicator provides good visual feedback for unsaved changes, and the save button placement is intuitive. The named slot structure improves readability and maintainability.


18-29: Content organization is clean and functional

The content section maintains its functionality while benefiting from the new panel structure. The monaco editor integration remains intact with all necessary event handlers.


34-38: Good Vue 3 composition API usage

The addition of reactive and provide imports, along with the updated component imports, properly leverages Vue 3's composition API for state management. The integration with the engine's layout system via useLayout is a good approach.


53-59: Component registration and props are properly defined

The PluginPanel component registration and the addition of the fixedPanels prop are correctly implemented. The prop type is defined according to Vue best practices.


65-71: Good reactive state management implementation

The implementation of reactive state and providing it to descendant components follows Vue 3 best practices. The extraction of PLUGIN_NAME from useLayout() ensures consistency with the application's layout system.


123-123: Properly exposing PLUGIN_NAME to the template

Adding PLUGIN_NAME to the return object ensures it's available in the template for the fixed-name prop, which is necessary for the panel system to work correctly.


142-164: Well-structured styling for new elements

The styling for the icon wrapper and indicators is well-organized and follows good CSS practices. The positioning of the red dot indicator is precise and provides clear visual feedback.


166-169: Appropriate content area styling

The updated padding and height calculations ensure the editor has sufficient space while maintaining the overall aesthetics of the panel.


177-177: Clean removal of unnecessary styling

The empty line indicates removal of styles that were likely specific to the previous implementation, which is appropriate as part of this refactoring.

packages/common/component/PluginPanel.vue (1)

208-211: Consider using Vue refs instead of direct DOM queries.

Using document.querySelector for DOM elements is fragile and could cause issues if multiple instances of this component exist or if the DOM structure changes.

-  const initResizerDOM = () => {
-    leftResizer.value = document.querySelector('.resizer-left')
-    rightResizer.value = document.querySelector('.resizer-right')
-  }

+  // Add refs in the template
+  // <div class="resizer-right" v-if="isLeftResizer" ref="rightResizerRef" @mousedown="onMouseDownRight"></div>
+  // <div class="resizer-left" v-if="isRightResizer" ref="leftResizerRef" @mousedown="onMouseDownLeft"></div>
+
+  // Then in setup():
+  const rightResizerRef = ref(null)
+  const leftResizerRef = ref(null)
+
+  // Update the references after mount
+  onMounted(() => {
+    leftResizer.value = leftResizerRef.value
+    rightResizer.value = rightResizerRef.value
+  })
+
+  // Include in return statement
+  return {
+    // ...other returns
+    rightResizerRef,
+    leftResizerRef
+  }
packages/plugins/schema/src/Main.vue (3)

77-81: Good use of reactive panelState with provide/inject pattern.

This implementation creates a clean communication channel between components and follows Vue's composition API best practices.


8-8:

Details

❓ Verification inconclusive

Add validation for the width-resizable prop.

You're passing :width-resizable="true" directly, but should verify that the PluginPanel component properly handles this prop.

Run the following script to verify that the width-resizable prop is correctly defined in the PluginPanel component:


🏁 Script executed:

#!/bin/bash
# Description: Check if widthResizable prop is properly defined in PluginPanel

# Search for the prop definition in PluginPanel.vue
rg -A 8 "widthResizable.*type:\s*Boolean" "packages/common/component/PluginPanel.vue"

Length of output: 85


Action Required: Verify Width-Resizable Prop Handling

It appears that our initial search in packages/common/component/PluginPanel.vue did not return any evidence of a defined widthResizable prop (i.e., a Boolean prop definition). Please manually confirm whether the PluginPanel component is intended to accept and validate this prop. If it should, update PluginPanel to include the proper prop definition and validation (ensuring proper handling of the kebab-case to camelCase transformation). If not, consider removing or revising its usage in packages/plugins/schema/src/Main.vue.


6-7:

Details

✅ Verification successful

Ensure consistent handling of fixedPanels and fixedName props.

Make sure the PluginPanel component correctly handles these props and that PLUGIN_NAME.Schema exists.

Run the following script to verify the constant existence and proper handling:


🏁 Script executed:

#!/bin/bash
# Description: Verify PLUGIN_NAME.Schema existence and fixedPanels handling

# Check if PLUGIN_NAME.Schema is defined
rg -A 5 "PLUGIN_NAME\s*=\s*{" --type js

# Check how fixedPanels is used in PluginPanel
rg "fixedPanels.*includes\(fixedName\)" --type vue packages/common/component

Length of output: 250


Below is an updated verification script using corrected regex and file glob patterns. Please run it and manually inspect the output to ensure that the constant is defined and used as expected:

Re-verify fixedPanels and fixedName prop handling in PluginPanel

  • Confirm that the constant PLUGIN_NAME.Schema exists by searching for it in JS files.
  • Verify that the PluginPanel component in packages/common/component (or related Vue components) correctly handles the fixedPanels prop by checking for its use with includes(fixedName).

Once you manually verify that these conditions are met based on the above script’s output, please update or confirm the code accordingly.


🏁 Script executed:

#!/bin/bash
# Verify PLUGIN_NAME.Schema definition in JavaScript files
rg "PLUGIN_NAME\.Schema" --type js

# Verify that fixedPanels is used appropriately in PluginPanel.
# Searching within .vue files in the packages/common/component directory.
rg "fixedPanels.*includes\\(fixedName\\)" -g "*.vue" packages/common/component

Length of output: 544


Re-verified: FixedPanels and FixedName Props Handling

  • Verified that PLUGIN_NAME.Schema is present in packages/plugins/schema/src/Main.vue.
  • Confirmed that the PluginPanel component (in packages/common/component/PluginPanel.vue) correctly uses the fixedPanels prop with the includes(fixedName) logic.

The code handles these props consistently, so no further changes are necessary.

Copy link
Contributor

@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: 0

🧹 Nitpick comments (1)
packages/layout/src/composable/useLayout.js (1)

163-180: Local storage parse fallback
Storing plugin info in localStorage helps user continuity. However, if parsing fails (e.g., corrupted JSON), rethrowing the error might break the UI. Consider a fallback reset or user-facing warning to handle invalid data more gracefully.

 try {
   const storedPlugin = localStorage.getItem('plugin')
   if (storedPlugin) {
     plugin = JSON.parse(storedPlugin)
   }
 } catch (error) {
-  throw new Error(error)
+  console.warn('Invalid plugin data in localStorage; resetting to default.')
+  plugin = []
 }
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between ab2f4f8 and a6db10e.

📒 Files selected for processing (9)
  • packages/common/component/PluginPanel.vue (5 hunks)
  • packages/layout/src/Main.vue (4 hunks)
  • packages/layout/src/composable/useLayout.js (5 hunks)
  • packages/plugins/schema/meta.js (1 hunks)
  • packages/plugins/schema/src/Main.vue (5 hunks)
  • packages/plugins/script/meta.js (1 hunks)
  • packages/plugins/script/src/Main.vue (5 hunks)
  • packages/plugins/tree/meta.js (1 hunks)
  • packages/plugins/tree/src/Main.vue (4 hunks)
🧰 Additional context used
🧬 Code Definitions (1)
packages/layout/src/composable/useLayout.js (1)
packages/utils/src/constants/index.js (6) (6)
  • STORAGE_KEY_LEFT_FIXED_PANELS (100-100)
  • STORAGE_KEY_LEFT_FIXED_PANELS (100-100)
  • STORAGE_KEY_RIGHT_FIXED_PANELS (101-101)
  • STORAGE_KEY_RIGHT_FIXED_PANELS (101-101)
  • PLUGIN_DEFAULT_WIDTH (168-168)
  • PLUGIN_DEFAULT_WIDTH (168-168)
⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: push-check
🔇 Additional comments (42)
packages/plugins/tree/meta.js (1)

6-7: Enhancement to plugin configuration aligns with flexible layout objectives

These changes effectively support the PR's goal of implementing a flexible layout for the plugin panel:

  1. Adding widthResizable: true enables users to manually adjust the panel width through dragging, as specified in the PR objectives.
  2. Changing align from 'top' to 'leftTop' standardizes alignment specification across plugins, supporting the unified logic for floating and fixed states.

Both modifications contribute to the improved layout flexibility while maintaining backward compatibility.

packages/plugins/script/meta.js (1)

6-8: Configuration additions support flexible plugin layout requirements

The changes to the plugin metadata properly implement the flexible layout requirements by:

  1. Standardizing the alignment approach with leftTop instead of top
  2. Setting an initial width of 600px
  3. Enabling width resizing with widthResizable: true

These changes align perfectly with the PR objectives of making the plugin panel width adjustable through dragging.

packages/plugins/script/src/Main.vue (6)

2-29: Improved component architecture with plugin-panel

The template restructuring effectively leverages the plugin-panel component to support the flexible layout requirements. The use of named slots for header and content creates a clean separation of concerns, while properly passing the fixed panel configuration.


33-37: Enhanced reactivity with composition API

Good use of Vue 3's composition API with reactive state management and the useLayout hook to access PLUGIN_NAME constants. This provides a more maintainable and scalable approach.


54-58: Added configuration prop for flexible panels

Adding the fixedPanels prop correctly implements the ability to configure fixed vs floating behavior per the PR requirements.


64-69: State management improvement with provide/inject pattern

The implementation of a reactive panelState that's provided to child components follows best practices for state management in Vue. This enables better component communication and state sharing.


141-162: Well-structured visual feedback for changes

The styling for the change indicator (red dot) and save button is well implemented, providing clear visual feedback to users when there are unsaved changes.


166-167: Simplified content layout

The code-edit-content styling is appropriately simplified, providing proper spacing while maintaining the full height calculation for the editor.

packages/plugins/schema/meta.js (1)

6-8: Updated plugin alignment and added resizing capabilities

These changes align with the PR objective to implement a flexible layout for plugin panels. The align property change positions the schema plugin at the left bottom, while the new widthResizable and width properties enable width adjustment through dragging with a default width of 600px.

packages/plugins/tree/src/Main.vue (2)

2-10: Improved panel structure with unified fixed/floating logic

The template has been simplified to use the plugin-panel component with appropriate props for fixed panel management. This change aligns with the PR objective to implement unified logic for the floating and fixed states of the plugin panel.


78-92: Added panel state management for improved component communication

The new reactive panelState object and provide mechanism create a clean way to share state with child components, enabling better communication between the panel and its parent components.

packages/plugins/schema/src/Main.vue (3)

2-39: Restructured plugin panel with improved layout organization

The template has been completely restructured to use the plugin-panel component with clearly defined header and content slots. This change supports the PR objective of restructuring the display logic for the plugin panel and provides a more consistent UI structure.


77-80: Added panel state management for improved component communication

Similar to the tree plugin, this component now uses a reactive panelState object and provide mechanism to share state with child components, enabling better communication between components.


217-218: Fixed content height calculation

The height calculation has been adjusted to account for the new panel structure, ensuring the content area properly fills the available space with a small margin.

packages/layout/src/Main.vue (5)

9-14: Enhanced plugin panel management with conditional rendering and alignment control

The left plugin panel now uses conditional rendering based on leftMenuShownStorage and includes a reference and event handler for alignment changes, supporting the PR objective of controlling the visibility and position of plugins.


22-28: Added flexible control for the right settings panel

Similar to the left panel, the right settings panel now has conditional rendering, a reference, and alignment control, which supports the PR objective of enabling users to control the visibility and position of plugins.


75-83: Implemented cross-panel communication for alignment changes

The new refs and change alignment methods allow the left and right panels to communicate when plugin alignment changes, ensuring both panels stay in sync when plugins are moved between them.


86-123: Implemented comprehensive plugin organization and storage

This new code segment:

  1. Creates a merged plugin list
  2. Organizes plugins by alignment group
  3. Sets up plugin properties including width, visibility, and resizability
  4. Stores the configuration in localStorage

This is central to the PR objective of implementing a flexible layout system where users can reposition and resize plugins.


169-170: Updated right panel layout to use flexbox

Changed the right panel layout from position-based to flexbox, which provides better flexibility for dynamic content and supports the plugin panel's resizing capabilities.

packages/common/component/PluginPanel.vue (13)

2-3: Use of inline width binding looks good
You correctly bind the width to panelWidth while referencing the DOM element via ref="panel". This ensures the panel’s width is dynamically updated based on reactive state.


12-28: Collapsible tooltip and button implementation is clear
Conditional rendering of <tiny-tooltip> and <svg-button> based on isShowCollapseIcon and isCollapsed is straightforward and easy to maintain. The logic for toggling icon and updates to collapsed/expanded state look sound.


32-39: Scroll and width resizing sections are well separated
Creating a dedicated .scroll-content wrapper and then placing the resizer elements within a conditional block (v-if="isWidthResizable") keeps the layout modular and clear.


44-48: Imports and component registrations are aligned
Using @vueuse/core for throttling, referencing SvgButton, and registering TinyTooltip from @opentiny/vue are all consistent with best practices. The newly introduced or updated imports and component definitions appear correct and match usage.

Also applies to: 51-51, 55-58


86-112: Flexible configuration props and improved documentation
Defining new props (fixedPanels, fixedName, showBottomBorder, and isShowCollapseIcon) and providing clear doc comments make the component more flexible and understandable. Good job ensuring default values and proper type checks.


114-114: New event emission
Emitting updateCollapseStatus on collapse toggle is a clean way to keep the parent component in sync with the panel’s state.


120-134: Resizing parameters are well-defined
Using PLUGIN_DEFAULT_WIDTH for MIN_WIDTH is a sensible baseline, and specifying a MAX_WIDTH of 1000 is fine for normal usage. Injecting panelState to handle fix/unfix logic also seems appropriate, though consider confirming that panelState is always provided to avoid runtime errors.

Would you like to ensure or verify that panelState is always injected by the parent and not undefined?


138-138: Neat computed and layout integration
headerBottomLine and isWidthResizable computed properties integrate smoothly with your layout logic (useLayout), ensuring the panel’s style and resizability respond to the user’s preferences.

Also applies to: 140-140, 143-147


149-211: Throttled drag event handlers
The resizing routines (onMouseDownRight, onMouseMoveRight, etc.) are cleanly implemented with throttling to avoid excessive re-renders. Storing startX/startWidth in outer scope is a standard and clear approach.


203-206: Use refs instead of direct DOM queries
This code reintroduces the approach of querying .resizer-left/.resizer-right via document.querySelector, which can be fragile if the DOM structure changes. Using Vue refs would be more robust. This was previously noted in an older review.


213-230: Mounted lifecycle usage
Calling initResizerDOM() on onMounted is a straightforward approach. If you switch to Vue refs in the future, you can remove direct DOM queries.


286-311: Right resizer CSS
The .resizer-right rules, plus hover and .dragging states, provide clear user feedback. Good job using transitions and distinct cursor styling.


313-339: Left resizer and scroll-content styling
Consistent styling for .resizer-left mirrors the approach on the right side. Hiding scrollbars with ::-webkit-scrollbar { display: none; } can improve the visual design, provided it meets user accessibility needs.

packages/layout/src/composable/useLayout.js (10)

14-14: VueUse for storage looks good
Importing useStorage from @vueuse/core is a concise approach to persisting layout-related states and menu visibility.


18-19: Multi-constant import from constants
Destructuring needed constants, including PLUGIN_DEFAULT_WIDTH, keeps the code organized and clarifies your usage of these layout-specific values.


20-27: Well-defined PLUGIN_POSITION
Mapping out all relevant plugin positions in one object makes references to layout alignment more self-documenting and straightforward to maintain.


29-31: pluginState addresses global plugin events
Storing pluginEvent in a reactive object can be advantageous for watchers or computed logic that might respond to changes. This is a simple approach.


34-34: Expanded layoutState for isShow and fixedPanels
Adding the isShow and fixedPanels fields for plugins/settings clarifies each panel’s visibility and pinned state. The default configuration is well-structured, ensuring minimal setup friction.

Also applies to: 44-49, 51-54


65-69: Menu visibility & fixed panels are elegantly stored
Using useStorage for leftMenuShown/rightMenuShown and leftFixedPanelsStorage/rightFixedPanelsStorage is a neat solution for persisting user preferences. The toggle functions changeMenuShown, changeLeftFixedPanels, and changeRightFixedPanels are straightforward and robust.

Also applies to: 70-72, 73-82, 84-85, 86-86, 87-91, 92-96


101-102: Getter functions for layout states
getPluginState() and getSettingState() provide a clear, typed approach to retrieving layout sub-states. Straightforward and maintainable.


114-114: Highlighting settings with an activation flag
Enabling a short highlight effect (settings.activating = true) is a good UX touch to draw focus to the settings panel.


120-121: Retrieving fixed panels status and closing setting
getFixedPanelsStatus() and closeSetting(forceClose) let you handle pinned states gracefully. The logic to set settings.render = null if not pinned or forced closed stands out as understandable and consistent.

Also applies to: 122-130


181-349: Plugin storage and layout mechanics
Functions (getPluginWidth, changePluginWidth, getPluginByLayout, drag-and-drop logic) thoroughly handle plugin alignment and sizing. The checks for existence in changePluginShown and changePluginWidth help avoid null references. The approach is modular and comprehensible.

@hexqi hexqi merged commit 8d31bd3 into opentiny:develop Mar 20, 2025
2 checks passed
gene9831 pushed a commit to gene9831/tiny-engine that referenced this pull request Mar 20, 2025
@chilingling chilingling mentioned this pull request May 14, 2025
14 tasks
@SonyLeo SonyLeo deleted the feat/flex-layout branch August 24, 2025 01:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants