diff --git a/README.md b/README.md index c6ec85a..04be822 100644 --- a/README.md +++ b/README.md @@ -1,238 +1,273 @@ - -# EasyKit-NodeAlign-Pro [↙切换中文] 🎨 + +# EasyKit-NodeAlign-Pro [↙Switch to Chinese] 🎨 -[](https://github.com/ArtsticH/ComfyUI_EasyKitHT_NodeAlignPro/stargazers) [](LICENSE) [](README_ZH.md) [](README.md) +[](https://github.com/ArtsticH/ComfyUI_EasyKitHT_NodeAlignPro/stargazers) [](LICENSE) [](README_ZH.md) [](README.md) -## 📋 Project Overview +## 📋 Project Introduction -**EasyKit-NodeAlign-Pro**, independently developed by a designer (formerly: ComfyUI_EasyKitHT_NodeAlign Pro): - -**v2.1.13: 🔥First-to-support the latest ComfyUI Node2.0 nodes. Pioneering Node2.0-based alignment algorithm (Innovative adaptation)**: An essential plugin for managing node layout and color schemes in ComfyUI, featuring professional alignment tools and a real-time node color picker. **Now fully compatible with ComfyUI Node2.0**. Key functions include alignment distribution, real-time node color picker, color palette, 7 preset colors, grayscale/custom modes, and one-click reverse alignment. It provides a new suite of alignment tools and a professional node color management system. The layout of the built-in alignment tools follows industry-standard logic for a better user experience, and the versatile coloring tool offers multiple intuitive coloring modes. (Natively supports multi-language UI display). - -Features an original node-based real-time color preview/picker component for quick node coloring. This plugin is designed to boost ComfyUI users' productivity by simplifying node layout and color management through an intuitive interface and rich feature set. +**EasyKit-NodeAlign-Pro** is independently developed by a designer (original name: ComfyUI_EasyKitHT_NodeAlign Pro): +**v2.1.14: 🔥This plugin is the first to support - the latest ComfyUI Node2.0 nodes. Pioneering alignment algorithm based on Node2.0 (innovative adaptation)**: An essential plugin for managing node layout and color schemes in ComfyUI, featuring professional alignment functions and a real-time node color picker **now adapted for ComfyUI Node2.0**. Functions cover alignment distribution, real-time node color picker, color palette, 7 preset colors, grayscale/custom modes, and one-click reverse alignment, providing new alignment tools and a professional node color management system. The layout of the built-in alignment tools aligns better with industry-standard operational logic and experience, and the coloring tools with multiple coloring modes are more rational. (Natively supports multilingual UI display) +Original real-time preview color adjustment/picking component based on nodes, facilitating quick node color picking/coloring. This plugin aims to enhance ComfyUI users' workflow efficiency by simplifying node layout and color management processes with an intuitive interface and rich features. --- -## 🔥 What's New in v2.1 (Enhanced Alignment for ComfyUI Node 2.0) +## 🔥 v2.1 New Version Update Notes (Adapted for Node2.0) -**The new v2.0 is fully adapted with an i18n multilingual configuration file, natively supporting languages like Chinese, English (and can be extended in the future to support more languages such as Russian, French, etc.), making it more user-friendly for friends around the world.** -While preserving the UI and interaction habits of the previous version as much as possible, the interface interaction logic has been fine-tuned, and the UI continues to be iteratively updated (see images below). +**The new v2.0 is fully adapted with i18n multilingual configuration files, natively supporting Chinese, English, and other languages (more languages such as Russian, French can be added later if needed), making it more friendly to international friends worldwide.** +While preserving the previous version's UI and interaction habits as much as possible, the interface interaction logic has been fine-tuned, and the UI continues to be updated and iterated (see details in the image below). -#### ✅【Update 260125】: Added ComfyUI menu, new i18n multilingual adaptation (now integrated into the official menu page)👇 - - +#### ✅【h260201 Update】: Added automatic theme color (automatically follows ComfyUI theme color)👇 + -#### If you like it, feel free to give it a **⭐Star**! Your encouragement is my greatest motivation! +#### ✅【h260125 Update】: Added ComfyUI menu, added i18n multilingual adaptation (now integrated into the official menu page)👇 + + + +#### If you find it useful, please give it a **⭐Star**, your encouragement is my greatest motivation~ - ⚠️ Legacy v1.0.4_rc UI... + ⚠️Old version v1.0.4_rc UI interface... -**Legacy v1.0.4_rc**: Only provided basic node alignment tools and a fixed coloring tool: - +**Old version v1.0.4_rc**: Only provides basic node alignment tools and fixed coloring tools: + -## ✨ Core Features (Officially Released) +## ✨ Core Features (Officially Launched) -| 💫 Node 2.0 Alignment System | 💫 New Coloring System | 💫 User-Centric Design | 💫 New Color Picker (Original Design) | -|------------------------------|----------------------------|----------------------------|---------------------------------------| -| 🔥 **New Node 2.0 Algorithms** | 🖼️ One-Click Color Mgmt. | 🖱️ Hovering Tool Panel | ✅ **Original Real-Time Preview Color Picker/Adjuster** | -| 📐 **Original Alt Reverse-Baseline Algo.** | 🔗 Live Full-Screen Picker | ⚙️ New Custom Configuration | 🎨 Color Mode: Colorful/Grayscale/Custom | -| 📊 Two Alignment/Distribution Algorithms | 🎨 Whole Node/Title-Only Coloring | 💾 Layout Memory & Restore | 🧩 Swatches: Random/Favorite/Remove/Manual | -| 🧩 Multiple Alignment Modes | 🧩 Custom Swatch Favorites & Restore | 🌐 Native i18n Multilingual | 🎨 Presets: Specially Tuned Color Values | +| 💫Node2.0 Node Alignment System | 💫New Coloring System | 💫User-friendly Interaction Design | 💫New Color Picker (Original Design) | +|---------------------------|---------------------------|---------------------------|---------------------------| +| 🔥 **New Node2.0 Node Algorithm** | 🖼️ One-click Color Management Scheme | 🖱️ Floating Tool Panel | ✅ **Original Real-time Preview Color Adjustment/Picking Component** | +| 📐 **Original Alt Reverse Baseline Alignment Algorithm** | 🔗 Real-time Full-screen Color Picker Linkage | ⚙️ New Custom Configuration | 🎨 Color Card Modes: Color/Grayscale/Custom | +| 📊 Two Sets of Alignment Distribution Algorithms | 🎨 Whole Node Coloring / Title-only Coloring Modes | 💾 Layout Memory and Recovery System | 🧩 Color Cards: Random/Favorite/Remove/Manual | +| 🧩 Multiple Alignment Distribution Modes | 🧩 Custom Color Card Favorite and Recovery System | 🌐 Native i18n Multilingual System | 🎨 Preset Colors: Specially Tuned Color Values | #### 🎯 Advanced Features -- **i18n Multilingual**: Natively adapted i18n multilingual system. -- **Node 2.0 Support**: Brand new support for ComfyUI Node 2.0 nodes. -- **ComfyUI System Menu Integration**: Permanently visible or auto-shown with selection. -- **Custom Drag & Scale**: Freely draggable and scalable operation panel. -- **AcBar Link Mode**: Linked positioning with ComfyUI's Run button. -- **Right-Click Menu**: Rich settings and quick actions. -- **Batch Node Selection**: Multiple selection tools and magic wand (In development/debugging...). -- **Batch Node Renaming**: Batch rename node feature (In development/debugging...). +- **i18n Multilingual**: Natively adapted i18n multilingual system +- **Supports Node2.0 Nodes**: New support for ComfyUI Node2.0 nodes 【v2.1.13+ added】 +- **ComfyUI System Menu Integration**: Can perform related settings in the ComfyUI system menu (including advanced settings) 【v2.0.3_rc added】 +- **Custom Drag and Scale**: Freely draggable and scalable operation panel +- **AcBar Linkage Mode**: Linkage drag positioning with ComfyUI run button +- **Right-click Menu**: Rich setting options and quick operations +- **Node Batch Selection**: Multiple selection tools and magic wand function (Under development/debugging...) +- **Node Batch Rename**: Batch rename node function (Under development/debugging...) #### 🎨 Color Management Module -- **Two Coloring Modes**: Color only node title / Color entire node 【Added in v2.0.3_rc】. -- **Seven Preset Color Groups**: Quickly apply standard colors to selected nodes. -- **Grayscale Palette**: Hold **Shift** to switch to grayscale mode 【Added in v2.0.1_rc】. -- **Custom Palette**: Hold **Alt** to enter custom color mode 【Added in v2.0.1_rc】. -- **Color Favorites**: **Ctrl+Alt** to lock/unlock custom colors 【Added in v2.0.1_rc】. -- **Random Color**: Click the random color button for one random color 【Added in v2.0.1_rc】. -- **Super Random Colors**: **Alt** + **Random Color Button** randomizes 7 colors at once and applies them in real-time to selected nodes 【Added in v2.0.1_rc】. -- **Live Color Picker**: Built-in **Full-Screen Live Color Picker** 【Added in v2.0.1_rc】 (Zero dependencies, pure native JS+CSS). -- **Node Color Adjustment Live Preview Component**: Original real-time preview color adjuster/picker component based on nodes 【Added in v2.0.1_rc】 (Zero dependencies, pure native JS+CSS). +- **Two Coloring Modes**: Color node title only / Color entire node 【v2.0.3_rc added】 +- **Seven Groups of Preset Colors**: Quickly apply standard colors to selected nodes +- **Grayscale Palette**: Hold **Shift key** to switch to grayscale color mode 【v2.0.1_rc added】 +- **Custom Palette**: Hold **Alt key** to enter custom color mode 【v2.0.1_rc added】 +- **Color Favorites**: **Ctrl+Alt combination** locks/unlocks custom colors 【v2.0.1_rc added】 +- **Random Color**: Click the random color button to get a random color 【v2.0.1_rc added】 +- **Super Random Color**: Press **Alt key** + **Random Color Button** to randomly generate 7 colors at once and apply random colors to selected nodes in real-time 【v2.0.1_rc added】 +- **Real-time Color Picker**: Built-in **full-screen real-time color picker** 【v2.0.1_rc added】 (0 dependencies, purely native js+css development design) +- **Node Color Adjustment Real-time Preview Component**: Original real-time preview color adjustment/picking component based on nodes 【v2.0.1_rc added】 (0 dependencies, purely native js+css development design) #### 🔧 Node Alignment Module -- **Basic Alignment**: Left, Right, Top, Bottom. -- **Center Alignment**: Vertical Center and Horizontal Center. -- **Even Distribution**: Horizontal Even Distribution and Vertical Even Distribution. -- **Uniform Sizing**: Equal Width and Equal Height. -- **Reverse-Baseline Mode**: **Alt** + Click corresponding **Alignment Button** for reverse-baseline alignment 【Added in v2.0.1_rc】. +- **Basic Alignment**: Left-align, Right-align, Top-align, Bottom-align +- **Center Distribution**: Vertical center and horizontal center +- **Equal Spacing Distribution**: Horizontal equal spacing and vertical equal spacing +- **Size Unification**: Equal width and equal height adjustment +- **Reverse Baseline Mode**: Press **Alt key** + click the corresponding **alignment button** to achieve reverse baseline alignment 【v2.0.1_rc added】 --- -## 🚀 Installation +## 🚀 Plugin Installation -#### Method 1: Via ComfyUI Manager (Recommended) -1. Search for "**NodeAlign Pro**" in **ComfyUI Manager** (note the space before "Pro"). -2. Find `EasyKit-NodeAlign-Pro`, click Install `(This method installs the ComfyUI registered plugin version: will auto-generate the official easykit-node-align directory)`. -3. Wait for prompt, restart ComfyUI. +#### Method 1: ComfyUI Manager (Recommended) +1. Search for "**NodeAlign Pro**" in **ComfyUI Manager** (note the space before "Pro") +2. Find `EasyKit-NodeAlign-Pro`, click install `(This method is the ComfyUI registered plugin: will automatically generate the easykit-node-align directory under ComfyUI's official standard ecosystem)` +3. Wait for the prompt to restart ComfyUI, then it's ready to use #### Method 2: Git Clone (Recommended) -1. Navigate to your ComfyUI/custom_nodes directory, run `(This method installs the git version: will auto-generate the ComfyUI_EasyKitHT_NodeAlignPro directory)`: +1. Navigate to the ComfyUI/custom_nodes directory and execute the following command `(This method is the git version plugin: will automatically generate the ComfyUI_EasyKitHT_NodeAlignPro directory)`: ``` git clone https://github.com/ArtsticH/ComfyUI_EasyKitHT_NodeAlignPro.git ``` -- For users in China or those who cannot access GitHub, use the Gitee mirror: +- For Chinese users and those unable to access github, please use the gitee mirror source: ``` git clone https://gitee.com/ArtsticH/ComfyUI_EasyKitHT_NodeAlignPro.git ``` -3. Restart ComfyUI. +3. Restart ComfyUI, then it's ready to use -#### Method 3: Comfy Install -`(This method installs the ComfyUI registered plugin version: will auto-generate the official easykit-node-align directory)` +#### Method 3: comfy install +`(This method is the ComfyUI registered plugin: will automatically generate the easykit-node-align directory under ComfyUI's official standard ecosystem)` ``` comfy node install easykit-node-align ``` -#### Method 4: Manual Git Install -1. Go to the project page: https://github.com/ArtsticH/ComfyUI_EasyKitHT_NodeAlignPro -2. Download the ZIP (`<>Code` > `Download ZIP`). -3. Extract to `ComfyUI/custom_nodes` directory (Ensure correct path: `ComfyUI/custom_nodes/ComfyUI_EasyKitHT_NodeAlignPro`). -4. Restart ComfyUI. +#### Method 4: Git Manual Installation +1. Open the project address: https://github.com/ArtsticH/ComfyUI_EasyKitHT_NodeAlignPro +2. Download the plugin zip file (`<>Code` > `Download ZIP`) +3. Extract to the `ComfyUI/custom_nodes` directory (Note: The correct directory level should be: `ComfyUI/custom_nodes/ComfyUI_EasyKitHT_NodeAlignPro`) +4. Restart ComfyUI, then it's ready to use ## 🚀 Plugin Update -#### Method 1: Update via ComfyUI Manager (Recommended) -1. In **ComfyUI Manager**, search for "**NodeAlign Pro**" (note the space before "Pro"). -2. Find `EasyKit-NodeAlign-Pro`, click Install/Update. -3. Wait for prompt, restart ComfyUI. +#### Method 1: ComfyUI Manager Update (Recommended) +1. Search for "**NodeAlign Pro**" in **ComfyUI Manager** (note the space before "Pro") +2. Find `EasyKit-NodeAlign-Pro`, click install `(This method is the ComfyUI registered plugin: will automatically generate the easykit-node-align directory under ComfyUI's official standard ecosystem)` +3. Wait for the prompt to restart ComfyUI, then it's ready to use -#### Method 2: Git Update (Navigate to ComfyUI_EasyKitHT_NodeAlignPro directory first) +#### Method 2: Git Update (First navigate to the ComfyUI_EasyKitHT_NodeAlignPro directory) ``` git fetch --all && git reset --hard origin/main ``` - --- #### 🚀 Quick Start (Brief Guide) -After successful installation, basic operations (for reference). +After successfully installing NodeAlignPro, basic operations (for reference only) -1. **Color a Node**: In ComfyUI, select any node(s) > click any **color button** in the NodeAlignPro panel (hereafter NAP panel) (🔴🟠🟡🟢🔵🟣🟤, `Clear Color` `Color Picker` `Random Color`). -2. **Custom Color**: Select any node(s) > click the **Color Picker button** in the NAP panel. -3. **Align Nodes**: Select any node(s) > click any **alignment button** in the NAP panel. -4. **Reverse-Baseline Alignment**: Select any node(s) > Hold **Alt** + Click the corresponding **alignment button** for reverse-baseline alignment. - └ Example: `Left Align` → select multiple nodes > `Alt`+`Left Align Button` uses the `rightmost node` as the `baseline` for `left alignment` (Default left align uses the `leftmost node` as the `baseline`). -5. **Drag NAP Panel**: Without selecting any node > Click the buttons on either side of the NAP panel, wait for the four-way arrow cursor (↕↔) to appear, then drag. -6. **Reset Settings**: Without selecting any node > Right-click within the NAP panel > 【One-Click Reset】. -7. **Advanced Tips**: Please refer to the **User Guide** below 👇. +1. **Node Coloring**: Enter ComfyUI, select any node > click any **color button** on the NodeAlignPro panel (hereinafter referred to as NAP panel) (🔴🟠🟡🟢🔵🟣🟤, `Clear Color` `Color Picker` `Random Color`); +2. **Custom Color**: Select any node > click the **color picker button** on the NAP panel; +3. **Node Alignment**: Select any node > click any **alignment button** on the NAP panel; +4. **Reverse Alignment**: Select any node > press **Alt key** + click the corresponding **alignment button** to achieve reverse baseline alignment; + └Example: `Left-align` → Select multiple nodes > press `Alt key`+`Left-align button`, then uses the `rightmost node` as the `baseline` for `left-align` (default left-align uses the `leftmost node` as the `baseline` for `left-align`); +5. **Drag NAP Panel**: No need to select any node > click the buttons on the left and right sides of the NAP panel, a four-way arrow cursor (↕↔) will appear, then you can drag it +6. **Reset Settings**: No need to select any node > in the NAP panel >【Right-click】 >【One-click Reset】; +7. **Advanced Techniques**: Please refer to the **Usage Guide** below 👇. - 🖥️ 《User Guide》... + 🖥️ 《Usage Guide》... #### Basic Operations -1. **Start Plugin**: Plugin loads automatically after ComfyUI starts. -2. **Show/Hide**: Control visibility via right-click menu or hotkeys. -3. **Drag to Move**: Drag the title bar or separator line to move the panel. -4. **Scale Adjustment**: Adjust UI scaling via right-click menu. +1. **Start Plugin**: Plugin loads automatically after ComfyUI starts +2. **Show/Hide**: Control display via right-click menu or shortcuts +3. **Drag to Move**: Drag the title bar or separator to move the panel +4. **Scale Adjustment**: Adjust UI scaling via right-click menu #### Color Mode Switching -| Key Combination | Mode | Description | -|-----------------|---------------|---------------------------------| -| **No Key** | Default Mode | Seven preset colors | -| **Shift** | Grayscale Mode| Black/White/Gray series colors | -| **Alt** | Custom Mode | Custom color management | -| **Ctrl+Alt** | Lock Mode | Lock/Unlock custom colors | +| Key Combination | Mode Description | Function Description | +|---------|---------|---------| +| **No Key** | Default Mode | Seven preset colors | +| **Shift** | Grayscale Mode | Black, white, gray series colors | +| **Alt** | Custom Mode | Custom color management | +| **Ctrl+Alt** | Lock Mode | Lock/Unlock custom colors | #### Alignment Operations -1. Select 2 or more nodes on the ComfyUI canvas. +1. Select 2 or more nodes on the ComfyUI canvas 2. Click the corresponding button on the alignment panel: - - **Left Align**: All nodes align to the left. - - **Vertical Center**: All nodes align to the vertical center. - - **Right Align**: All nodes align to the right. - - **Top Align**: All nodes align to the top. - - **Horizontal Center**: All nodes align to the horizontal center. - - **Bottom Align**: All nodes align to the bottom. + - **Left-align**: All nodes align left + - **Vertical Center**: All nodes align vertically centered + - **Right-align**: All nodes align right + - **Top-align**: All nodes align top + - **Horizontal Center**: All nodes align horizontally centered + - **Bottom-align**: All nodes align bottom -#### Advanced Tips -- **Alt + Alignment Button**: Use "Reverse Baseline" for alignment. -- **Double-click Color Picker Preview**: Toggle between coloring entire node or title only. -- **Right-Click Menu**: Access full settings and reset functions. -- **Container Link**: Link the operation panel position with the Run button. +#### Advanced Techniques +- **Alt + Alignment Button**: Use "reverse baseline" for alignment +- **Double-click Color Picker Preview**: Switch between whole node / title-only coloring mode +- **Right-click Menu**: Access complete settings and reset functions +- **Container Linkage**: Link the operation panel with the run button for positioning -## 🐛 FAQ -- **Q: How to switch language?** -→ A: Click the menu at the bottom left of ComfyUI > 🔥 NodeAlignPro> NodeAlignPro基本设置(Basic Settings)> NodeAlignPro UI语言(Language). +## 🐛 Frequently Asked Questions -- **Q: Colors won't apply to nodes?** -→ A: Ensure nodes are selected, check if nodes are locked, try refreshing the page. +#### Q: How to turn on/off 【Automatic】 theme color? +→A: Click the menu in the lower left corner of ComfyUI> 🔥 NodeAlignPro> 🎨NodeAlignPro Color preset(Color preset)> Use ComfyUI theme color(Use ComfyUI theme color)> **【Turn On/Off】**; + -- **Q: Alignment doesn't work?** -→ A: Ensure 2 or more nodes are selected, check node selection status, try clearing and re-selecting. +#### Q: How to 【Customize】 theme color? +→A: ...> 🔥 NodeAlignPro> 🎨NodeAlignPro Color preset(Color preset)> Use ComfyUI theme color(Use ComfyUI theme color)> **【Turn On】**; + -- **Q: How to reset all settings?** -→ A: Right-click menu → "One-Click Reset", OR ComfyUI bottom-left menu > 🔥 NodeAlignPro> Z开发人员选项(Developer Options)> ⚠强制重置NodeAlignPro插件. +#### Q: How to switch languages? +→A: ...> 🔥 NodeAlignPro> NodeAlignPro Basic Settings(Basic Settings)> **NodeAlignPro UI Language(Language)**; -- **Q: What if the plugin doesn't show up?** -→ A: Click ComfyUI bottom-left menu > 🔥 NodeAlignPro> Z开发人员选项(Developer Options)> ⚠强制重置NodeAlignPro插件. - -```↑ If it still doesn't work after 【Force Reset】, use ComfyUI Manager to check if the plugin is installed correctly. If not installed, search for "NodeAlign Pro" to reinstall. If installed, try FIX/Repair or Update.``` +#### Q: How to use alignment/distribution/coloring functions in the new Node2.0 mode? +→A-Method1: Right-click on the plugin toolbar> Work Mode(Work Mode)> Node2.0 + +→A-Method2: ...> 🔥 NodeAlignPro> NodeAlignPro Basic Settings(Basic Settings)> Work Mode (Work Mode)> Node2.0; + +#### Q: My plugin is in Node2.0 mode, but there is a noticeable delay after clicking the alignment button? +→A-Method1: You are currently using the traditional Canvas nodes. If you need to maintain the current traditional Canvas node usage environment, please switch the plugin's work mode to traditional mode: Work Mode(Work Mode)> **Traditional Alignment(AlignStd)** + +→A-Method2: You are currently using the traditional Canvas nodes. If you must use the new Node2.0 mode, please manually enable ComfyUI's new Node2.0 switch (see image below) + + +#### Q: Color cannot be applied to nodes? →A: Ensure nodes are selected, check if nodes are locked, try refreshing the page; + +#### Q: Alignment function is invalid? →A: Ensure 2 or more nodes are selected, check node selection status, try clearing selection and re-selecting; + +#### Q: How to reset all settings? +→A: Right-click menu → "One-click reset", or ComfyUI lower left corner menu> 🔥 NodeAlignPro> Z Developer Options(Developer Options)> ⚠Force reset NodeAlignPro plugin; + +#### Q: What if the plugin doesn't show up? +→A: Click the menu in the lower left corner of ComfyUI> 🔥 NodeAlignPro> Z Developer Options(Developer Options)> ⚠Force reset NodeAlignPro plugin. + +```↑If still not effective after 【Force Reset】, please use ComfyUI Manager to check if the plugin is correctly installed. If not installed, search for "NodeAlign Pro" and reinstall. If installed, try FIX repair or try Update.``` --- ## 🔄 Changelog -### v2.1.0 (Latest 2.1 Release) -- Optimized ComfyUI menu, added i18n multilingual adaptation (integrated into official menu page). -- Refactored color conversion logic. -- Refactored screen color picker functionality. -- Revised and improved Readme documentation. -- Fixed several bugs. +### v2.1.14 (Latest Official Release) -260201 Update +- **Major Update:** Added automatic theme color (automatically follows ComfyUI theme color) +- Fully added alignment algorithm based on ComfyUI Node2.0, while retaining and being compatible with the original traditional Canvas alignment mode +- Added Node2.0-based alignment mode (can be used by changing the work mode to "Node2.0" in the right-click menu or ComfyUI menu) +- Refactored ComfyUI menu +- Optimized right-click menu logic +- Optimized i18n multilingual adaptation +- Fixed several potentially non-critical syntax issues +- Fixed several bugs +- Revised and improved Readme documentation - 📄 Previous Versions... + 📄 Historical Versions... + +##### v2.1.12 +- Optimized ComfyUI menu +- Optimized i18n multilingual adaptation +- Optimized Node2.0-based alignment algorithm (minor test refactoring) +- Revised and improved Readme documentation +- Fixed several bugs + +##### v2.1.0 【v2.1 Release】 +- Optimized ComfyUI menu, added i18n multilingual adaptation +- Optimized some parameters +- Revised and improved Readme documentation +- Fixed several bugs ##### v2.0.3_rc -- Added ComfyUI menu (integrated into official menu page). -- Refactored color conversion logic. -- Refactored screen color picker functionality. -- Revised and improved Readme documentation. -- Fixed several bugs. +- Added ComfyUI menu (integrated into the official menu page) +- Refactored color conversion logic +- Refactored screen color picking function +- Revised and improved Readme documentation +- Fixed several bugs ##### v2.0.2_rc (2025-12-22) -- Improved new version (v2.0.3_rc) interface prompts. -- Fixed some bugs. -- Rewrote md tutorial documentation (Chinese/English bilingual). +- Improved new version (v2.0.3_rc) interface prompts +- Fixed some bugs +- Rewrote md tutorial documents (Chinese and English bilingual) -##### v2.0.1_rc (2025-12-22) 【2.0 Release】 -- Added Shift/Alt/Ctrl key combination modes. -- Improved color picker performance and stability. -- Added node preview functionality. -- Optimized UI interaction experience. +##### v2.0.1_rc (2025-12-22)【v2.0 Release】 +- Added Shift/Alt/Ctrl combination key modes +- Improved color picker performance and stability +- Added node preview function +- Optimized UI interaction experience ##### v1.0.4_rc (2025-08-14) ##### v1.0.3_rc (2025-05-01) ##### v1.0.2_rc (2025-04-30) -##### v1.0.1_rc (2025-04-29) 【1.0 Release】 -- Initial version release. -- Complete alignment and color features. -- Draggable container system. -- Integrated color picker tool. +##### v1.0.1_rc (2025-04-29)【v1.0 Release】 +- Initial version release +- Complete alignment and color functions +- Draggable container system +- Integrated color picker tool 📄 Historical Changelog... ``` -v2.0.2_rc 8a12160: 🔥NodeAlignPro major version update, optimized file structure (new UI, comprehensive node coloring system) → see readme for details. +v2.0.2_rc 8a12160: 🔥NodeAlignPro major version update, optimized file structure (new UI, more comprehensive node coloring system)→See readme for details ---------------- -v2.0.1_rc dd2a09f: 🔥NodeAlignPro major version update released (new UI, comprehensive node coloring system) -d90bd02: 🔥Update Preview (A Major Update for the Upcoming Version 😁)→See README for details. +v2.0.1_rc dd2a09f: 🔥NodeAlignPro major version update released (new UI, more comprehensive node coloring system) +d90bd02: 🔥Update Preview (A Major Update for the Upcoming Version 😁)→See README for details.🔥Major update preview (a major update is coming soon 😁)→See readme for details. ---------------- -v1.0.4_rc b77a9d7: FIX README, optimized ht history log. +v1.0.4_rc b77a9d7: FIX README, ht history optimization ---------------- v1.0.3_rc a62e3a6: Fix the ui scaling adaptation issue, The interlocking control function has been newly added. d067502: remove res, add hPic, FIX README,FIX README_ZH.md @@ -241,58 +276,61 @@ v1.0.2_rc b11f325: upload README cb93ffa-461032d: README modifications 4e60dc2: Fixed REEADME, Rename some img, Add README_ZH.md fac4c81: UPLoad README , Create README_ZH.md -9f1839e: README修改-新增UI缩放适配 -ef5735d: Added UI scaling, fixed issue where color removal didn't work in old version. -8ac01db: Added main features: alignment/distribution, node coloring. Fixed Readme image display issue. +9f1839e: README modifications - added UI scaling adaptation +ef5735d: Added UI scaling, fixed issue where color removal didn't work in old version +8ac01db: Added main functions: alignment distribution, node coloring. Fixed Readme image display abnormality. ---------------- -v1.0.1_rc 2926b82: README修改 -10749c7: ComfyUI_EasyKitHT_NodeAlignPro is a newly designed ComfyUI node alignment and coloring plugin. - Brand new visual UI, relatively more aligned with the operational logic familiar to designer friends. - Added main features: alignment/distribution, node coloring. +v1.0.1_rc 2926b82: README modifications +10749c7: ComfyUI_EasyKitHT_NodeAlignPro is a newly designed ComfyUI node alignment plugin, node coloring plugin. + New visual UI, more in line with the usual operational logic of designer friends. Aims to provide a relatively beautiful user experience for everyone. + Added main functions: alignment distribution, node coloring. ---------------- ca28236: Initial commit ---------------- /** * @Artstich_Example * @name easykit-node-align (ComfyUI Plugin) - * @description Professional alignment & real-time node color picker. A must-have plugin for managing node layout and color schemes in ComfyUI. Features a real-time color picker, alignment, 7 preset colors, grayscale/custom modes, and one-click reverse alignment. + * @description Node2.0-based professional alignment & real-time node color picker - innovative first support: A must-have plugin for managing node layout and color schemes in ComfyUI. Features a real-time color picker, alignment, 7 preset colors, grayscale/custom modes, and one-click reverse alignment. * @author ArtsticH - * @see https://registry.comfy.org/zh/nodes/easykit-node-align + * @see https://registry.comfy.org/nodes/easykit-node-align * @see https://github.com/ArtsticH/ComfyUI_EasyKitHT_NodeAlignPro * @see https://gitee.com/ArtsticH/ComfyUI_EasyKitHT_NodeAlignPro * @installCommand comfy node install easykit-node-align * @installCommand git clone https://github.com/ArtsticH/ComfyUI_EasyKitHT_NodeAlignPro.git * @installCommand git clone https://gitee.com/ArtsticH/ComfyUI_EasyKitHT_NodeAlignPro.git - * @created 2025-04-29 @date 2025-06-15 @version v2.0.3 @lastUpdated 2026-01-24 @license GPL-3.0 + * @created 2025-04-29 @date 2025-06-15 @lastUpdated 2026-01-28 @version v2.1.14 @license GPL-3.0 * @copyright ©2012-2026, All rights reserved. Freely open to use, modify, and distribute in accordance with the GPL-3.0 license. */ ``` -## 🤝 Contributing +## 🤝 Contribution Guide -- Welcome to participate and improve through: -```Submit feedback```, `New Issue`, `Discussions`, ```Improve code logic```, `Fork & PR`, ```Improve multilingual docs```, ```Share your creative node layouts```, ```Share your custom color swatches``` - -## 📜 License - - - This project is licensed under **GPL-3.0**. See the [LICENSE](LICENSE) file for details. +- Welcome to participate in improvements through the following ways: +[🥰Submit Usage Feedback](https://github.com/ArtsticH/ComfyUI_EasyKitHT_NodeAlignPro/issues)、[👾New Issue](https://github.com/ArtsticH/ComfyUI_EasyKitHT_NodeAlignPro/issues)、[💬Discussions](https://github.com/ArtsticH/ComfyUI_EasyKitHT_NodeAlignPro/discussions)、[📚️WiKi](https://github.com/ArtsticH/ComfyUI_EasyKitHT_NodeAlignPro/wiki/)、 +as well as Fork & PR, improve multilingual documentation, share your creative node layouts, share your custom color cards... ## 👥 Contributors -- Project Initiator & Main Developer: [@ArtsticH](https://github.com/ArtsticH) -- Issues & Discussions: [@JGDMGJAPT](https://github.com/jgdmgjapt) , [@MAOMAOCHONGNE](https://github.com/MAOMAOCHONGNE), [@aimposer](https://github.com/ArtsticH/ComfyUI_EasyKitHT_NodeAlignPro/issues/3), [@Rock-suv](https://github.com/ArtsticH/ComfyUI_EasyKitHT_NodeAlignPro/issues/4), [@BlissiraHQ](https://github.com/BlissiraHQ)... -- Thanks to all designers, developers, testers, ComfyUI users, and feedback providers who have helped. +- Creator: [@ArtsticH](https://github.com/ArtsticH) +- Advocates & Shapers: [👤@kakachiex2](https://github.com/kakachiex2)([👾issues-page](https://github.com/ArtsticH/ComfyUI_EasyKitHT_NodeAlignPro/issues/8))、[👤@aimposer](https://github.com/aimposer)([👾issues-page](https://github.com/ArtsticH/ComfyUI_EasyKitHT_NodeAlignPro/issues/3))、[👤@Rock-suv](https://github.com/Rock-suv)([👾issues-page](https://github.com/ArtsticH/ComfyUI_EasyKitHT_NodeAlignPro/issues/4))、[👤@JGDMGJAPT](https://github.com/jgdmgjapt) 、👤[@MAOMAOCHONGNE](https://github.com/MAOMAOCHONGNE)、[👤@BlissiraHQ](https://github.com/BlissiraHQ)... +- Thanks All: Thanks to everyone who contributed — including all designers, developers, testers, ComfyUI users, and those who provided feedback. ## 🌐 Related Links -- [Source 1: Last Releases](https://github.com/ArtsticH/ComfyUI_EasyKitHT_NodeAlignPro/releases) | [Source 2: Comfy registry](https://registry.comfy.org/zh/nodes/easykit-node-align) | [Source 3: Gitee Mirror](https://gitee.com/ArtsticH/ComfyUI_EasyKitHT_NodeAlignPro) | [Issues](https://github.com/ArtsticH/ComfyUI_EasyKitHT_NodeAlignPro/issues) | [ComfyUI Community](https://github.com/comfyanonymous/ComfyUI) | [ComfyUI-Manager](https://github.com/Comfy-Org/ComfyUI-Manager/tree/main) -- Author's Video Tutorial (Legacy v1.0.4_rc): https://www.bilibili.com/video/BV1V7G9z9EcU (New v2.1.0 tutorial pending recording) +- 🧩**NodeAlign Pro** Source 1: [📥︎ Last Releases](https://github.com/ArtsticH/ComfyUI_EasyKitHT_NodeAlignPro/releases) | Source 2: [📥︎ Comfy registry](https://registry.comfy.org/zh/nodes/easykit-node-align) | Source 3: [📥︎ Gitee Mirror](https://gitee.com/ArtsticH/ComfyUI_EasyKitHT_NodeAlignPro) +[👾Problem Feedback](https://github.com/ArtsticH/ComfyUI_EasyKitHT_NodeAlignPro/issues) | [ComfyUI Community](https://github.com/comfyanonymous/ComfyUI) | [ComfyUI-Manager](https://github.com/Comfy-Org/ComfyUI-Manager/tree/main) +- Author's Video Tutorial Link: https://www.bilibili.com/video/BV1V7G9z9EcU (This link is for the old version `v1.0.4_rc` tutorial, new version v2.1.0 tutorial to be recorded) + +## 📜 License + + - This project adopts the **GPL-3.0** license. For details, please see the [LICENSE](LICENSE) file. --- -👨💻 The first small project developed by a designer in their spare time. Feedback is welcome! -⚠️ There might be untested edge cases, please report via Issues (If you like it, feel free to give it a **Star⭐**, your encouragement is my greatest motivation!). Welcome to join if you're interested! +👨💻 A designer's first small project developed in spare time, welcome to report usage issues +⚠️ There may be anomalies in untested scenarios, please report via Issues +(If you find it good, welcome to give it a **Star⭐**, thank you) Welcome interested friends to join! -Document last updated: Jan 25, 2026, 10:24 @[ArtsticH](https://github.com/ArtsticH/ComfyUI_EasyKitHT_NodeAlignPro)·2025 \ No newline at end of file +This document updated: 2026 January 28 16:21 @[ArtsticH](https://github.com/ArtsticH/ComfyUI_EasyKitHT_NodeAlignPro)·2026 \ No newline at end of file diff --git a/README_ZH.md b/README_ZH.md index ea95974..e14f0aa 100644 --- a/README_ZH.md +++ b/README_ZH.md @@ -1,4 +1,4 @@ - +![NodeAlignPro_v2_UI]() # EasyKit-NodeAlign-Pro [↙切换中文] 🎨 [](https://github.com/ArtsticH/ComfyUI_EasyKitHT_NodeAlignPro/stargazers) [](LICENSE) [](README_ZH.md) [](README.md) @@ -6,7 +6,7 @@ ## 📋 项目简介 **EasyKit-NodeAlign-Pro** 由设计师独立开发(原名称:ComfyUI_EasyKitHT_NodeAlign Pro): -**v2.1.13:🔥本插件首发支持-最新版ComfyUI Node2.0节点。首创基于 Node2.0 的对齐算法(创新性适配)**: 用于管理 ComfyUI 中节点布局和配色方案的必备插件,具备专业的对齐功能和实时节点取色器 **已适配ComfyUI Node2.0** 。功能能涵盖对齐分布、实时节点取色器、调色盘、7 种预设颜色、灰度/自定义模式以及一键反向对齐等功能,提供全新对齐工具和专业的节点色彩管理系统。内置对齐工具的布局更符合设业通用的操作逻辑和体验,多种上色模式的上色工具更合理。(原生支持多语言UI界面显示) +**v2.1.14:🔥本插件首发支持-最新版ComfyUI Node2.0节点。首创基于 Node2.0 的对齐算法(创新性适配)**: 用于管理 ComfyUI 中节点布局和配色方案的必备插件,具备专业的对齐功能和实时节点取色器 **已适配ComfyUI Node2.0** 。功能能涵盖对齐分布、实时节点取色器、调色盘、7 种预设颜色、灰度/自定义模式以及一键反向对齐等功能,提供全新对齐工具和专业的节点色彩管理系统。内置对齐工具的布局更符合设业通用的操作逻辑和体验,多种上色模式的上色工具更合理。(原生支持多语言UI界面显示) 原创基于节点的实时预览调色/取色组件,方便快速节点取色/上色。该插件旨在提升ComfyUI用户的工作效率,通过直观的界面和丰富的功能简化节点布局与颜色管理流程。 --- @@ -16,9 +16,12 @@ **新版v2.0全新适配i18n多语言配置文件,原生支持中文、English等语言(后续视情况还可扩展支持更多诸如俄语、法语等语言),对世界各地的国际友人更友好。** 同样在尽可能保留上一版UI及交互习惯的前提下,微调界面交互逻辑,继续更新迭代UI(详见下图)。 -#### ✅【260125更新】:新增ComfyUI菜单、新增i18n多语言适配 (现以集成到官方菜单页面)👇 - - +#### ✅【h260201更新】:新增自动主题色(自动跟随ComfyUI主题色)👇 +![插件截图]() + +#### ✅【h260125更新】:新增ComfyUI菜单、新增i18n多语言适配 (现以集成到官方菜单页面)👇 +![插件截图]() +![NodeAlignPro_v2_MENU]() #### 如果觉得还可以,欢迎帮忙点下**⭐Star**,您的鼓励就是我最大的动力~ @@ -26,7 +29,7 @@ ⚠️旧版v1.0.4_rc UI界面... **旧版v1.0.4_rc**: 只提供基础的节点对齐工具和固定的上色工具: - +![NodeAlignPro_v2_UI]() ## ✨ 核心功能 (已正式上线) @@ -40,8 +43,8 @@ #### 🎯 高级特性 - **i18n多语言**:原生适配i18n多语言系统 -- **Node2.0节点**:全新支持ComfyUI Node2.0节点 -- **ComfyUI系统菜单集成**:常驻显示或跟随选框自动显示 +- **支持Node2.0节点**:全新支持ComfyUI Node2.0节点 【v2.1.13+新增】 +- **ComfyUI系统菜单集成**:可在ComfyUI系统菜单里进行相关设置(含高级设置项) 【v2.0.3_rc新增】 - **自定义拖动及缩放**:可自由拖拽和缩放的操作面板 - **AcBar联动模式**:与ComfyUI运行按钮联动拖移定位 - **右键菜单**:丰富的设置选项和快捷操作 @@ -163,19 +166,39 @@ git fetch --all && git reset --hard origin/main ## 🐛 常见问题 -- **Q: 如何切换语言?** -→A: 直接点击ComfyUI左下角菜单> 🔥 NodeAlignPro> NodeAlignPro基本设置(Basic Settings)> NodeAlignPro UI语言(Language); -- **Q: 颜色无法应用到节点?** →A: 确保已选中节点,检查节点是否处于锁定状态,尝试刷新页面; +#### Q: 如何开启/关闭【自动】主题色? +→A: 直接点击ComfyUI左下角菜单> 🔥 NodeAlignPro> 🎨NodeAlignPro颜色预设(Color preset)> 使用ComfyUI主题配色(Use ComfyUI theme color)> **【开启/关闭】**; +![开启自动主题]() -- **Q: 对齐功能无效?** →A: 确保选中2个或更多节点,检查节点选择状态,尝试清除选择后重新选择; +#### Q: 如何【自定义】主题色? +→A: ...> 🔥 NodeAlignPro> 🎨NodeAlignPro颜色预设(Color preset)> 使用ComfyUI主题配色(Use ComfyUI theme color)> **【开启】**; +![开启自动主题]() -- **Q: 如何重置所有设置?** +#### Q: 如何切换语言? +→A: ...> 🔥 NodeAlignPro> NodeAlignPro基本设置(Basic Settings)> **NodeAlignPro UI语言(Language)**; + +#### Q: 如何在新版Node2.0模式下使用对齐/分布/上色功能? +→A-方式1: 插件工具栏上右键> 工作模式(Work Mode)> Node2.0 +![alt text]() +→A-方式2: ...> 🔥 NodeAlignPro> NodeAlignPro基本设置(Basic Settings)> 工作模式 (Work Mode)> Node2.0; + +#### Q: 我的插件开启了Node2.0模式,但点击对齐按钮后存在明显延迟? +→A-方式1: 您当前使用的是传统Canvas节点。若需保持当前传统Canvas节点的使用环境,请切换插件的工作模式为传统模式:工作模式(Work Mode)> **传统对齐(AlignStd)** + +→A-方式2: 您当前使用的是传统Canvas节点。若就是需要使用新版Node2.0模式,请手动开启ComfyUI的新版Node2.开关(详见下图) +![alt text]() + +#### Q: 颜色无法应用到节点?→A: 确保已选中节点,检查节点是否处于锁定状态,尝试刷新页面; + +#### Q: 对齐功能无效?→A: 确保选中2个或更多节点,检查节点选择状态,尝试清除选择后重新选择; + +#### Q: 如何重置所有设置? →A: 右键菜单 → "一键重置",或ComfyUI左下角菜单> 🔥 NodeAlignPro> Z开发人员选项(Developer Options)> ⚠强制重置NodeAlignPro插件; -- **Q: 插件不显示怎么办?** +#### Q: 插件不显示怎么办? →A: 直接点击ComfyUI左下角菜单> 🔥 NodeAlignPro> Z开发人员选项(Developer Options)> ⚠强制重置NodeAlignPro插件。 -![强制重置]() +![强制重置]() ```↑若【强制重置】后仍未生效,请使用ComfyUI Manager检查插件是否正确安装,若未安装请搜索"NodeAlign Pro"重新安装,若安装请尝试FIX修复或尝试更新Update。``` --- @@ -183,16 +206,33 @@ git fetch --all && git reset --hard origin/main ## 🔄 更新日志 -### v2.1.0 (最新2.1版发布) -- 优化ComfyUI菜单、新增i18n多语言适配(集成到官方菜单页面) -- 重构颜色转换逻辑 -- 重构屏幕取色功能 -- 修订并完善Readme文档 +### v2.1.14 (最新版正式发布) -260201更新 +- **重大更新:** 新增自动主题色(自动跟随ComfyUI主题色) +- 全量新增基于ComfyUI Node2.0的对齐算法,同时保留并兼容原有的传统Canvas对齐模式 +- 新增基于Node2.0的对齐模式(可在右键菜单或ComfyUI菜单更改工作模式为"Node2.0"进行使用) +- 重构ComfyUI菜单 +- 优化右键菜单逻辑 +- 优化i18n多语言适配 +- 修复若干个可能存在非致命性错误的语法问题 - 修复若干bug +- 修订并完善Readme文档 📄 历史版本... +##### v2.1.12 +- 优化ComfyUI菜单 +- 优化i18n多语言适配 +- 优化基于Node2.0的对齐算法(少量测试性重构) +- 修订并完善Readme文档 +- 修复若干bug + +##### v2.1.0 【2.1版发布】 +- 优化ComfyUI菜单、新增i18n多语言适配 +- 优化部分参数 +- 修订并完善Readme文档 +- 修复若干bug + ##### v2.0.3_rc - 新增ComfyUI菜单(集成到官方菜单页面) - 重构颜色转换逻辑 @@ -253,15 +293,15 @@ ca28236: Initial commit /** * @Artstich_Example * @name easykit-node-align (ComfyUI Plugin) - * @description Professional alignment & real-time node color picker. A must-have plugin for managing node layout and color schemes in ComfyUI. Features a real-time color picker, alignment, 7 preset colors, grayscale/custom modes, and one-click reverse alignment. + * @description Node2.0-based professional alignment & real-time node color picker - innovative first support: A must-have plugin for managing node layout and color schemes in ComfyUI. Features a real-time color picker, alignment, 7 preset colors, grayscale/custom modes, and one-click reverse alignment. * @author ArtsticH - * @see https://registry.comfy.org/zh/nodes/easykit-node-align + * @see https://registry.comfy.org/nodes/easykit-node-align * @see https://github.com/ArtsticH/ComfyUI_EasyKitHT_NodeAlignPro * @see https://gitee.com/ArtsticH/ComfyUI_EasyKitHT_NodeAlignPro * @installCommand comfy node install easykit-node-align * @installCommand git clone https://github.com/ArtsticH/ComfyUI_EasyKitHT_NodeAlignPro.git * @installCommand git clone https://gitee.com/ArtsticH/ComfyUI_EasyKitHT_NodeAlignPro.git - * @created 2025-04-29 @date 2025-06-15 @version v2.0.3 @lastUpdated 2026-01-24 @license GPL-3.0 + * @created 2025-04-29 @date 2025-06-15 @lastUpdated 2026-01-28 @version v2.1.14 @license GPL-3.0 * @copyright ©2012-2026, All rights reserved. Freely open to use, modify, and distribute in accordance with the GPL-3.0 license. */ ``` @@ -271,26 +311,29 @@ ca28236: Initial commit ## 🤝 贡献指南 - 欢迎通过以下方式参与改进: -```提交使用反馈```、`New Issue`、`Discussions`、```改进代码逻辑```、`Fork & PR`、```完善多语言文档```、```分享你的创意节点布局```、```分享你的自定义色卡``` +[🥰提交使用反馈](https://github.com/ArtsticH/ComfyUI_EasyKitHT_NodeAlignPro/issues)、[👾New Issue](https://github.com/ArtsticH/ComfyUI_EasyKitHT_NodeAlignPro/issues)、[💬Discussions](https://github.com/ArtsticH/ComfyUI_EasyKitHT_NodeAlignPro/discussions)、[📚️WiKi](https://github.com/ArtsticH/ComfyUI_EasyKitHT_NodeAlignPro/wiki/)、 +以及Fork & PR、完善多语言文档、分享你的创意节点布局、分享你的自定义色卡…… + +## 👥 贡献者 + +- 开发: [👤@ArtsticH](https://github.com/ArtsticH) +- 致谢: [👤@kakachiex2](https://github.com/kakachiex2)([👾issues-page](https://github.com/ArtsticH/ComfyUI_EasyKitHT_NodeAlignPro/issues/8))、[👤@aimposer](https://github.com/aimposer)([👾issues-page](https://github.com/ArtsticH/ComfyUI_EasyKitHT_NodeAlignPro/issues/3))、[👤@Rock-suv](https://github.com/Rock-suv)([👾issues-page](https://github.com/ArtsticH/ComfyUI_EasyKitHT_NodeAlignPro/issues/4))、[👤@JGDMGJAPT](https://github.com/jgdmgjapt) 、👤[@MAOMAOCHONGNE](https://github.com/MAOMAOCHONGNE)、[👤@BlissiraHQ](https://github.com/BlissiraHQ)... +- 感谢上述及所有提供帮助的设计师、开发者、测试者、ComfyUI用户和反馈者 + +## 🌐 相关链接 + +- 🧩**NodeAlign Pro** 源1: [📥︎ Last Releases](https://github.com/ArtsticH/ComfyUI_EasyKitHT_NodeAlignPro/releases) | 源2: [📥︎ Comfy registry](https://registry.comfy.org/zh/nodes/easykit-node-align) | 源3: [📥︎ Gitee镜像](https://gitee.com/ArtsticH/ComfyUI_EasyKitHT_NodeAlignPro) +[👾问题反馈](https://github.com/ArtsticH/ComfyUI_EasyKitHT_NodeAlignPro/issues) | [ComfyUI社区](https://github.com/comfyanonymous/ComfyUI) | [ComfyUI-Manager](https://github.com/Comfy-Org/ComfyUI-Manager/tree/main) +- 作者视频教程链接:https://www.bilibili.com/video/BV1V7G9z9EcU (此链接为旧版`v1.0.4_rc`教程,新版v2.1.0待录制) ## 📜 许可证 - 本项目采用 **GPL-3.0** 许可证。详细信息请查看 [LICENSE](LICENSE) 文件。 -## 👥 贡献者 - -- 项目发起人 & 主要开发者: [@ArtsticH](https://github.com/ArtsticH) -- ISISUES & Discussions: [@JGDMGJAPT](https://github.com/jgdmgjapt) 、[@MAOMAOCHONGNE](https://github.com/MAOMAOCHONGNE)、[@aimposer](https://github.com/ArtsticH/ComfyUI_EasyKitHT_NodeAlignPro/issues/3)、[@Rock-suv](https://github.com/ArtsticH/ComfyUI_EasyKitHT_NodeAlignPro/issues/4)、[@BlissiraHQ](https://github.com/BlissiraHQ)... -- 感谢所有提供帮助的设计师、开发者、测试者、ComfyUI用户和反馈者 - -## 🌐 相关链接 - -- [源1: Last Releases](https://github.com/ArtsticH/ComfyUI_EasyKitHT_NodeAlignPro/releases) | [源2: Comfy registry](https://registry.comfy.org/zh/nodes/easykit-node-align) | [源3: Gitee镜像](https://gitee.com/ArtsticH/ComfyUI_EasyKitHT_NodeAlignPro) | [问题反馈](https://github.com/ArtsticH/ComfyUI_EasyKitHT_NodeAlignPro/issues) | [ComfyUI社区](https://github.com/comfyanonymous/ComfyUI) | [ComfyUI-Manager](https://github.com/Comfy-Org/ComfyUI-Manager/tree/main) -- 作者视频教程链接:https://www.bilibili.com/video/BV1V7G9z9EcU (此链接为旧版`v1.0.4_rc`教程,新版v2.1.0待录制) - --- 👨💻 设计师业余开发的第一个小项目,欢迎反馈使用问题 -⚠️ 可能存在未测试场景的异常,请通过Issues报告(如果觉得还可以,欢迎帮忙**Star⭐**一下,您的鼓励就是我最大的动力~)欢迎有兴趣的小伙伴们一起加入! +⚠️ 可能存在未测试场景的异常,请通过Issues报告 +(如果觉得还可以,欢迎帮忙给个**Star⭐**,谢谢)欢迎有兴趣的小伙伴们一起加入! -本文档更新于:2026年01月25日 10:24 @[ArtsticH](https://github.com/ArtsticH/ComfyUI_EasyKitHT_NodeAlignPro)·2025 \ No newline at end of file +本文档更新于:2026年01月28日 16:21 @[ArtsticH](https://github.com/ArtsticH/ComfyUI_EasyKitHT_NodeAlignPro)·2026 \ No newline at end of file diff --git a/__init__.py b/__init__.py index 4d40cef..1f7dcf7 100644 --- a/__init__.py +++ b/__init__.py @@ -1,7 +1,7 @@ import os # 版本定义 -# __version__ = "2.1.13" +# __version__ = "2.1.14" # VERSION = __version__ # 节点注册 @@ -14,4 +14,5 @@ WEB_DIRECTORY = os.path.join(os.path.dirname(__file__), 'web') # 当前目录设置 # current_directory = os.path.dirname(os.path.abspath(__file__)) -NODE_JS = ["web/hNodeAlignPro.js", "web/hNodeAlignPro_cfg.js"] # , "web/hNodeAlignPro_settings.js", "web/hNodeAlignPro_n2.js" \ No newline at end of file +NODE_JS = ["web/hLanguage.js", "web/hNodeAlignPro_cfg.js", "web/hNodeAlignPro.js"] +# , "web/hNodeAlignPro_n2.js" \ No newline at end of file diff --git a/docs/images/h_NodeAlignPro_v1__UI.webp b/docs/images/h_NodeAlignPro_v1__UI.webp deleted file mode 100644 index b196c4e..0000000 Binary files a/docs/images/h_NodeAlignPro_v1__UI.webp and /dev/null differ diff --git a/docs/images/h_NodeAlignPro_v2-1_i18nMenu.webp b/docs/images/h_NodeAlignPro_v2-1_i18nMenu.webp deleted file mode 100644 index f3b618a..0000000 Binary files a/docs/images/h_NodeAlignPro_v2-1_i18nMenu.webp and /dev/null differ diff --git a/docs/images/h_NodeAlignPro_v2__UI.webp b/docs/images/h_NodeAlignPro_v2__UI.webp deleted file mode 100644 index 3d5506f..0000000 Binary files a/docs/images/h_NodeAlignPro_v2__UI.webp and /dev/null differ diff --git a/web/h_NodeAlignPro_v2__UI__Mgr_banner.webp b/docs/images/h_NodeAlignPro_v2__UI__Mgr_banner.webp similarity index 100% rename from web/h_NodeAlignPro_v2__UI__Mgr_banner.webp rename to docs/images/h_NodeAlignPro_v2__UI__Mgr_banner.webp diff --git a/docs/images/h_NodeAlignPro_v2__UI__Skin9.webp b/docs/images/h_NodeAlignPro_v2__UI__Skin9.webp new file mode 100644 index 0000000..89af204 Binary files /dev/null and b/docs/images/h_NodeAlignPro_v2__UI__Skin9.webp differ diff --git a/pyproject.toml b/pyproject.toml index 49fe07a..225b25c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,8 +1,8 @@ [project] name = "easykit-node-align" # name = "easykitht_nodealignpro" -description = "Professional alignment & real-time node color picker. A must-have plugin for managing node layout and color schemes in ComfyUI. Features a real-time color picker, alignment, 7 preset colors, grayscale/custom modes, and one-click reverse alignment." -version = "2.1.13" +description = "Node2.0-based professional alignment & real-time node color picker - innovative first support: A must-have plugin for managing node layout and color schemes in ComfyUI. Features a real-time color picker, alignment, 7 preset colors, grayscale/custom modes, and one-click reverse alignment." +version = "2.1.14" license = {file = "LICENSE"} [project.urls] @@ -15,8 +15,8 @@ Documentation = "https://github.com/ArtsticH/ComfyUI_EasyKitHT_NodeAlignPro#read PublisherId = "artstich" DisplayName = "EasyKit-NodeAlign-Pro" # DisplayName = "ComfyUI_EasyKitHT_NodeAlignPro" -Icon = "https://raw.githubusercontent.com/ArtsticH/ComfyUI_EasyKitHT_NodeAlignPro/main/web/hNodeAlignPro__LOGO_icon.svg" -Banner = "https://raw.githubusercontent.com/ArtsticH/ComfyUI_EasyKitHT_NodeAlignPro/main/web/h_NodeAlignPro_v2__UI__Mgr_banner.png" +Icon = "https://cdn.jsdelivr.net/gh/ArtsticH/ComfyUI_EasyKitHT_NodeAlignPro@main/web/hNodeAlignPro__LOGO_icon.svg" +Banner = "https://cdn.jsdelivr.net/gh/ArtsticH/h-Readme-res@main/ComfyUI_EasyKitHT_NodeAlignPro/web/h_NodeAlignPro_v2__UI__Mgr_banner.png" includes = [] # "requires-comfyui" = ">=1.0.0" # ComfyUI version compatibility diff --git a/web/hLanguage.js b/web/hLanguage.js index f6a4b29..0ff84e4 100644 --- a/web/hLanguage.js +++ b/web/hLanguage.js @@ -1,15 +1,15 @@ /** * @Artstich_Example * @name easykit-node-align (ComfyUI Plugin) - * @description Professional alignment & real-time node color picker. A must-have plugin for managing node layout and color schemes in ComfyUI. Features a real-time color picker, alignment, 7 preset colors, grayscale/custom modes, and one-click reverse alignment. + * @description Node2.0-based professional alignment & real-time node color picker - innovative first support: A must-have plugin for managing node layout and color schemes in ComfyUI. Features a real-time color picker, alignment, 7 preset colors, grayscale/custom modes, and one-click reverse alignment. * @author ArtsticH - * @see https://registry.comfy.org/zh/nodes/easykit-node-align + * @see https://registry.comfy.org/nodes/easykit-node-align * @see https://github.com/ArtsticH/ComfyUI_EasyKitHT_NodeAlignPro * @see https://gitee.com/ArtsticH/ComfyUI_EasyKitHT_NodeAlignPro * @installCommand comfy node install easykit-node-align * @installCommand git clone https://github.com/ArtsticH/ComfyUI_EasyKitHT_NodeAlignPro.git * @installCommand git clone https://gitee.com/ArtsticH/ComfyUI_EasyKitHT_NodeAlignPro.git - * @created 2025-04-29 @date 2025-06-15 @version v2.0.3 @lastUpdated 2026-01-24 @license GPL-3.0 + * @created 2025-04-29 @date 2025-06-15 @lastUpdated 2026-02-01 @version v2.1.14 @license GPL-3.0 * @copyright ©2012-2026, All rights reserved. Freely open to use, modify, and distribute in accordance with the GPL-3.0 license. */ @@ -21,8 +21,6 @@ (function(){ 'use strict'; const data = { - // 格式:{ cn: '中文文本', en: 'English Text' } - // 保持单行格式以便于快速编辑 NodeAlignPro_Title: {cn: 'Node Align Pro', en: 'Node Align Pro'}, // 头部/菜单/标签文字 Menu_LogoTitle: {cn: '菜单栏 LOGO', en: 'Menu Logo'}, @@ -72,6 +70,8 @@ Setting_DisplayMode: {cn: '显示模式 (Display Mode)', en: 'Display Mode'}, Setting_AlignBtnColor: {cn: '对齐按钮颜色 (Align Button Color)', en: 'Align Button Color'}, Setting_ToolbarBgColor: {cn: '工具栏背景色 (Toolbar Background Color)', en: 'Toolbar Background Color'}, + Setting_ToolbarColor_Auto: {cn: '使用ComfyUI主题配色(Use ComfyUI theme color)', en: 'Use ComfyUI theme color'}, + Setting_ToolbarColor_Auto1: {cn: '若开启,将ComfyUI主题配色,下方手动设置的颜色将无效(If enabled, ComfyUI theme color will be used, and manual color setting will be ignored)', en: 'If enabled, ComfyUI theme color will be used, and manual color setting will be ignored'}, Setting_ToolbarOpacity: {cn: '工具栏透明度 (Toolbar Opacity)', en: 'Toolbar Opacity'}, Setting_NewVersionTips: {cn: '新版说明 (New Version Tips)', en: 'New Version Tips'}, Setting_ColorApplyMode: {cn: '上色模式 (Color Apply Mode)', en: 'Color Apply Mode'}, @@ -106,7 +106,10 @@ Option_Color_TitleOnly: {cn: '仅标题', en: 'Title Only'}, Option_Color_TitleOnly2: {cn: '仅标题(Title)', en: 'Title Only'}, - Debug_Tips: {cn: 'v2.0.3_rc新版功能:按Shift、Alt、Ctrl Alt切换不同色卡模式...\nAlt+对齐按钮:对齐到“反向基准”节点^_^(右键菜单>【新版说明】隐藏本提示)', en: 'v2.0.3_rc: Use Shift/Alt/Ctrl+Alt to switch Alignment Mode...\nAlt+Align button: align to reversed reference node ^_^ (HideThis: Right-click > New Tips)'}, + hDebug_Tips: { + cn: 'v2.1.14新功能:	0. 启用自动主题色:左下角ComfyUI设置>🔥NodeAlignPro>【使用ComfyUI主题配色】	1. 启用新版Node2.0模式:右键菜单>工作模式>【Node2.0】	2. 高级对齐:Alt+对齐按钮:对齐到“反向基准”节点	3. 色卡切换:按Shift、Alt、Ctrl Alt切换不同色卡模式...^_^(右键菜单>新版说明隐藏本提示)', + en: 'v2.1.14 New Features:	0. Auto-Theme-Color: Bottom left Settings > 🔥NodeAlignPro > 【Use ComfyUI Theme Colors】	1. Node2.0 Mode: Right-click Menu > Work Mode > 【Node2.0】	2. Advanced Alignment: Alt + Align Button: Align to "Reverse Reference" Node	3. Color Palette Switching: Press Shift, Alt, Ctrl+Alt to switch different color palette modes...^_^ (Right-click Menu > NewTips to hide this tip)' + }, Aria_ClearColor: {cn: '清除颜色', en: 'Clear Color'}, Aria_Pick: {cn: '取色', en: 'Pick Color'}, Aria_RandomColor: {cn: '随机颜色', en: 'Random Color'}, @@ -159,9 +162,26 @@ return entry[langToUse] || entry.cn || Object.values(entry)[0]; } + // 增强的翻译函数:支持HTML标签和换行符 + function tHtml(key) { + if (!key) return ''; + const entry = data[key]; + if (!entry) return key; + const langToUse = (state.lang === 'auto') ? detectLang() : (state.lang || 'cn'); + let text = entry[langToUse] || entry.cn || Object.values(entry)[0]; + + if (!text) return ''; + + // 处理换行符:将\n转换为 + text = text.replace(/\n/g, ''); + + return text; + } + // 将API暴露在window对象上 window.hLanguage = { t, + tHtml, // 新增支持HTML的翻译函数 data, getLang() { return state.lang; }, setLang(l) { state.lang = (l === 'auto') ? 'auto' : ((l === 'en') ? 'en' : 'cn'); return state.lang; }, @@ -175,13 +195,23 @@ if (el.hasAttribute('data-i18n-attr')) return; // 保留SVG/图标内容不翻译 const key = el.getAttribute('data-i18n'); if (!key) return; - const text = t(key); + + // 检查是否需要HTML支持 + const useHtml = el.hasAttribute('data-i18n-html'); + const text = useHtml ? tHtml(key) : t(key); + if (!text) return; if (el.tagName === 'INPUT' || el.tagName === 'TEXTAREA') { el.placeholder = text; if (el.type === 'button' || el.type === 'submit') el.value = text; } else { - el.textContent = text; + if (useHtml) { + // 使用innerHTML来支持HTML标签 + el.innerHTML = text; + } else { + // 使用textContent保持原有行为 + el.textContent = text; + } } }); @@ -191,7 +221,11 @@ const key = el.getAttribute('data-i18n'); const attrName = el.getAttribute('data-i18n-attr'); if (!key || !attrName) return; - const text = t(key); + + // 检查是否需要HTML支持 + const useHtml = el.hasAttribute('data-i18n-html'); + const text = useHtml ? tHtml(key) : t(key); + if (!text) return; el.setAttribute(attrName, text); } catch (ee) { /* 忽略单个元素的翻译错误 */ } @@ -209,3 +243,5 @@ setTimeout(() => window.hLanguage.applyToDOM(document), 50); } })(); + +export default window.hLanguage; \ No newline at end of file diff --git a/web/hNodeAlignPro.js b/web/hNodeAlignPro.js index ad69cf1..928ff32 100644 --- a/web/hNodeAlignPro.js +++ b/web/hNodeAlignPro.js @@ -1,21 +1,24 @@ /** * @Artstich_Example * @name easykit-node-align (ComfyUI Plugin) - * @description Professional alignment & real-time node color picker. A must-have plugin for managing node layout and color schemes in ComfyUI. Features a real-time color picker, alignment, 7 preset colors, grayscale/custom modes, and one-click reverse alignment. + * @description Node2.0-based professional alignment & real-time node color picker - innovative first support: A must-have plugin for managing node layout and color schemes in ComfyUI. Features a real-time color picker, alignment, 7 preset colors, grayscale/custom modes, and one-click reverse alignment. * @author ArtsticH - * @see https://registry.comfy.org/zh/nodes/easykit-node-align + * @see https://registry.comfy.org/nodes/easykit-node-align * @see https://github.com/ArtsticH/ComfyUI_EasyKitHT_NodeAlignPro * @see https://gitee.com/ArtsticH/ComfyUI_EasyKitHT_NodeAlignPro * @installCommand comfy node install easykit-node-align * @installCommand git clone https://github.com/ArtsticH/ComfyUI_EasyKitHT_NodeAlignPro.git * @installCommand git clone https://gitee.com/ArtsticH/ComfyUI_EasyKitHT_NodeAlignPro.git - * @created 2025-04-29 @date 2025-06-15 @version v2.0.3 @lastUpdated 2026-01-24 @license GPL-3.0 + * @created 2025-04-29 @date 2025-06-15 @lastUpdated 2026-02-01 @version v2.1.14 @license GPL-3.0 * @copyright ©2012-2026, All rights reserved. Freely open to use, modify, and distribute in accordance with the GPL-3.0 license. */ (function () { 'use strict'; + // 简单的国际化助手,当hLanguage未就绪时回退到提供的中文文本 + function h_i18n(key, fallback) { try { return window.hLanguage && typeof window.hLanguage.t === 'function' ? window.hLanguage.t(key) : (fallback || key); } catch (e) { return fallback || key; } } + // 针对旧版本或分叉环境中缺失辅助函数的安全回退处理 if (typeof addInputEventListeners === 'undefined') { // 使用显式的 window 对象赋值,避免块级作用域的函数声明问题 @@ -171,8 +174,8 @@ --rotate-in-angle: 75deg; --easing-standard: cubic-bezier(0.34, 1.56, 0.64, 1); --easing-out: cubic-bezier(0.22, 1, 0.36, 1); - .hDebugInfo { display: none; position: fixed; top: -40px; left: 0px; background: rgba(0,0,0,0.7); color: rgb(var(--hC_hBtn_svg)); padding: 8px; border-radius: 8px; font-size: 12px; font-family: monospace; z-index: calc(var(--hZindex) + 10010); } - .hDebugInfo_V2 { display: none !important; position: fixed !important; top: var(--h108) !important; left: var(--h64) !important; color: rgb(var(--hC_hBtn_svg)) !important; padding: var(--h8) !important; border-radius: var(--h8) !important; font-size: var(--h12) !important; font-family: monospace !important; z-index: var(--h512) !important; transform: none !important; box-sizing: border-box !important; pointer-events: auto !important; will-change: transform !important; isolation: isolate !important; } + .hDebugInfo { display: none; position: fixed; top: 90px; left: 0px; width: 100%; background: rgba(var(--hC_Bg),0.8); color: rgb(var(--hC_hBtn_svg)); padding: 8px; border-radius: 8px; font-size: 12px; font-family: monospace; z-index: calc(var(--h32)); } + .hDebugInfo_V2 { display: none !important; position: fixed !important; top: var(--h108) !important; left: var(--h64) !important; color: rgb(var(--hC_hBtn_svg)) !important; padding: var(--h8) !important; border-radius: var(--h8) !important; font-size: var(--h12) !important; font-family: monospace !important; z-index: 6 !important; transform: none !important; box-sizing: border-box !important; pointer-events: auto !important; will-change: transform !important; isolation: isolate !important; } /* Z-index 层级管理 */ --hZindex: 10001; @@ -237,7 +240,7 @@ .hIconC { width: 100%; height: 100%; display: block; } .hIcon { width: 100%; height: 100%; object-fit: contain; pointer-events: none; } -#hClear, #hPick, #hRandom { background-color: rgb(var(--hC_BW1_Black)); } +#hClear, #hPick, #hRandom, #hZoom { background-color: rgb(var(--hC_BW1_Black)); } .hColorA_Clear__Slash { fill: rgb(var(--hC1_Red)); } #hColorA_Clear, #hColorB_Pick, #hColorC_Random { transition: transform var(--hTrans3) var(--easing-standard); } #hClear:hover, #hPick:hover, #hRandom:hover, #hZoom:hover { transform: scale(var(--btn-hover-scale)) rotate(var(--rotate-in-angle)); animation: rotateIn var(--rotate-in-duration) var(--easing-out); } @@ -358,8 +361,8 @@ .hCPr__sliderValue { width: 40px; height: 22px; background: rgb(var(--hC_BW1_Black)); border: 1px solid rgb(var(--hC_Border)); border-radius: var(--border-radius); padding: 0px; color: rgb(var(--hC_hBtn_svg)); text-align: center; } .hCPr__valueG { display: flex; align-items: center; gap: 0; } .hCPr__valueLabel { width: 58px; font-size: 12px; color: rgb(var(--hC_CPr6__hNodeText)); height: 16px; line-height: 16px; padding: 0 4px; white-space: nowrap; text-align: right; } -.value-input { height: 22px; background: rgb(var(--hC_BW1_Black)); border: 1px solid rgb(var(--hC_Border)); color: rgb(var(--hC_hBtn_svg)); font-size: 12px; font-weight: bold; padding: 0 4px; line-height: 14px; width: 48px; border-radius: 0; outline: none; } -.value-input:first-of-type { border-radius: var(--border-radius) 0 0 var(--border-radius); border-right: none; } +.hValue-input { height: 22px; background: rgb(var(--hC_BW1_Black)); border: 1px solid rgb(var(--hC_Border)); color: rgb(var(--hC_hBtn_svg)); font-size: 12px; font-weight: bold; padding: 0 4px; line-height: 14px; width: 48px; border-radius: 0; outline: none; } +.hValue-input:first-of-type { border-radius: var(--border-radius) 0 0 var(--border-radius); border-right: none; } .rgb-input { width: 32px; border-radius: 0; border-right: none; } .rgb-input:first-of-type { border-radius: var(--border-radius) 0 0 var(--border-radius); } .rgb-input:last-of-type { border-right: 1px solid rgb(var(--hC_Border)); border-radius: 0; } @@ -457,7 +460,7 @@ /** RGB对象转字符串 @param {{r: number, g: number, b: number}} rgb - RGB对象 @returns {string} RGB颜色字符串 */ static rgbObjectToString(rgb) { return `rgb(${rgb.r}, ${rgb.g}, ${rgb.b})`; } - } + } window.__hColorConvert = __hColorConvert; // 【== 全局上色模式管理器 ==】 class __hMgr_ColorModeFc { @@ -468,8 +471,7 @@ getModeText() { try { if (window.hLanguage && typeof window.hLanguage.t === 'function') return window.hLanguage.t(this.mode === 0 ? 'Option_Color_TitleOnly' : 'Option_Color_Whole'); } catch (e) {} return this.mode === 0 ? '仅标题' : '整体色'; } saveMode() { localStorage.setItem('NodeAlignPro_ColorApplyMode', this.mode.toString()); } loadMode() { const saved = localStorage.getItem('NodeAlignPro_ColorApplyMode'); this.mode = saved !== null ? parseInt(saved) : 1; } - } - window.__hMgr_ColorModeFc = new __hMgr_ColorModeFc(); // 创建全局实例 + } window.__hMgr_ColorModeFc = new __hMgr_ColorModeFc(); // 创建全局实例 // 【== 例外颜色管理器 ==】 class __hMgr_ExceptionColors { @@ -483,8 +485,7 @@ getExceptionColors = () => [...this.exceptionColors]; /** 获取例外颜色列表 @returns {Array} 例外颜色数组 */ setTolerance = (tolerance) => (this.tolerance = { ...this.tolerance, ...tolerance }, hLog.info('--@ExceptionColors', `容差已更新: H:${this.tolerance.h}, S:${this.tolerance.s}, B:${this.tolerance.b}`)); /** 设置容差 @param {Object} tolerance 容差对象 {h, s, b} */ getDefaultExceptionColor = () => this.exceptionColors.length > 0 ? this.exceptionColors[0] : null; /** 获取默认例外颜色(第一个)@returns {Object} 默认例外颜色 */ - } - window.__hMgr_ExceptionColors = new __hMgr_ExceptionColors(); // 创建全局例外颜色管理器实例 + } window.__hMgr_ExceptionColors = new __hMgr_ExceptionColors(); // 创建全局例外颜色管理器实例 // 【== 全局日志管理器 ==】 class __hMgr_Log { @@ -556,7 +557,7 @@ function __hCreateHTML() { const container = document.createElement('div'); container.id = 'hNodeAlignKit'; container.innerHTML = ` -v2.0.3_rc新版功能:按Shift、Alt、Ctrl Alt切换不同色卡模式...Alt+对齐按钮:对齐到“反向基准”节点^_^(右键菜单>【新版说明】隐藏本提示) +v2.0.3_rc新版功能:按Shift、Alt、Ctrl Alt切换不同色卡模式...Alt+对齐按钮:对齐到“反向基准”节点^_^(右键菜单>【新版说明】隐藏本提示) @@ -567,12 +568,12 @@ - - - + + + - - + + @@ -581,13 +582,13 @@ hColorPicker™ 十六进制: - + RGB: - - - + + + @@ -610,11 +611,11 @@ 👆双击切换上色模式: 整体色 色相(H): - 饱和(S): + 饱和(S): - 亮度(B): + 亮度(B): - + @@ -646,7 +647,7 @@ - + @@ -655,7 +656,7 @@ - + @@ -682,29 +683,29 @@ - + 后缀 - + - 拖拽方式 + 拖拽方式 解 耦 解 耦联 动 - UI缩放 + UI缩放 1x 0.5x0.75x1x1.25x1.5x2x - 工作模式 - 传统对齐 + 工作模式 + 传统对齐 @@ -715,13 +716,13 @@ 专 业 - 显示模式常驻显示常驻显示跟随选框 + 显示模式常驻显示常驻显示跟随选框 一键重置 bug反馈 使用教程 - 新版说明 - + 新版说明 + `; return container; } @@ -1196,7 +1197,26 @@ } catch (e) { console.warn('同步工作模式UI失败:', e); } } - function __hSetAlignLogicMode(mode) { try { window.__hAlignLogicMode = mode; localStorage.setItem('hNodeAlignPro_Logic', mode); console.log('hNodeAlignPro: 对齐逻辑切换为', mode); __hSync_WorkModeUI(mode); } catch (e) { } } + function __hSetAlignLogicMode(mode) { try { + // 确保window.__hAlignLogicMode已初始化 + if (typeof window.__hAlignLogicMode === 'undefined') { + window.__hAlignLogicMode = mode; + localStorage.setItem('hNodeAlignPro_Logic', mode); + console.log('hNodeAlignPro: 对齐逻辑切换为', mode); + __hSync_WorkModeUI(mode); + return; + } + + // 避免相同模式的重复设置 + if (window.__hAlignLogicMode === mode) { + return; // 模式未改变,直接返回 + } + + window.__hAlignLogicMode = mode; + localStorage.setItem('hNodeAlignPro_Logic', mode); + console.log('hNodeAlignPro: 对齐逻辑切换为', mode); + __hSync_WorkModeUI(mode); + } catch (e) { } } window.__hSetAlignLogicMode = __hSetAlignLogicMode; function __hIsNode2Mode() { @@ -1788,7 +1808,7 @@ } updateZoomButtonColor(color) { if (!this.zoomBtn) return; __hUpdater_UI.updateButtonSvgColor(this.zoomBtn, color); } // 更新zoom按钮颜色 - resetZoomButtonColor() { if (!this.zoomBtn) return; __hUpdater_UI.restoreDefaultSvgColor(this.zoomBtn); } // 重置按钮颜色 + resetZoomButtonColor() { if (!this.zoomBtn) return; /* 不使用restoreDefaultSvgColor,直接设置默认样式 */ this.zoomBtn.style.color = ''; this.zoomBtn.style.backgroundColor = ''; } // 重置按钮颜色 calculateBrightness(color) { return __hColorConvert.calculateBrightness(color); } // 计算颜色亮度 hexToRgb(hex) { return __hColorConvert.hexToRgb(hex); } // HEX转RGB - 现在使用统一的颜色转换管理器 getCurrentPickedColor() { return this.currentPickedColor; } @@ -1931,7 +1951,7 @@ } handleClearBtnClick() { - if (this.funcButtons.clear.classList.contains('disabled-state')) return; this.funcButtons.random && (this.funcButtons.random.style.backgroundColor = '', __hUpdater_UI.restoreDefaultSvgColor(this.funcButtons.random)); this.resetColorPicker(); + if (this.funcButtons.clear.classList.contains('disabled-state')) return; this.funcButtons.random && (this.funcButtons.random.style.backgroundColor = '', this.funcButtons.random.style.color = ''); this.resetColorPicker(); switch (this.currentMode) { case 'default': __hMgr_ComfyUINode.resetNodesColor(); hLog.warn('--@hClearBtn', '已清除节点颜色(仅对选择的节点时生效)'); break; case 'alt': for (let i = 0; i < 7; i++) !this.lockedColors[i] && (this.customColors[i] = null); this.renderColorButtons(); __hMgr_ComfyUINode.resetNodesColor(); hLog.warn('--@hClearBtn', '已清除自定义颜色(Alt)(不含锁定色)'); break; @@ -2528,9 +2548,9 @@ keysToClear.forEach(k => localStorage.removeItem(k)); // 强制恢复默认对齐逻辑与UI if (typeof __hSetAlignLogicMode === 'function') __hSetAlignLogicMode('align'); - // 让设置管理器重新加载(若存在)以同步状态 - if (window.NodeAlignProSettingsManager && typeof window.NodeAlignProSettingsManager.loadSettingsFromStorage === 'function') { - window.NodeAlignProSettingsManager.loadSettingsFromStorage(); + // 重置设置管理器的当前工作模式,避免重复设置 + if (window.NodeAlignProSettingsManager) { + window.NodeAlignProSettingsManager.currentWorkMode = 'hApBar2_Align'; } } catch (e) { console.warn('重置时清理本地存储失败:', e); } window.containerController && window.containerController.updateTransform(); window.__hMgr_MenuHide ? window.__hMgr_MenuHide.hideMenu() : (() => { const menuContainer = document.getElementById('h6__hMenu'); menuContainer && (menuContainer.style.display = 'none'); })(); @@ -2662,14 +2682,14 @@ case 'hDispMode0_Always': window.__hMgr_DisplayMode && window.__hMgr_DisplayMode.setPermanentMode(); break; case 'hDispMode1_Follow': window.__hMgr_DisplayMode && window.__hMgr_DisplayMode.setFollowingMode(); break; // 新增:通过工作模式下拉显式切换对齐逻辑(优先于自动检测) - case 'hApBar2_Node2': __hSetAlignLogicMode('node2'); console.log('工作模式: Node2.0 对齐逻辑已启用'); break; - case 'hApBar2_Align': __hSetAlignLogicMode('align'); console.log('工作模式: 原始对齐逻辑已启用'); break; + case 'hApBar2_Node2': __hSetAlignLogicMode('node2'); break; + case 'hApBar2_Align': __hSetAlignLogicMode('align'); break; case 'hApBar1_Color': // 仅显示色卡面板 - try { __hSync_WorkModeUI('hApBar1_Color'); console.log('工作模式: 色卡 (只显示色卡面板)'); } catch (e) { } + try { __hSync_WorkModeUI('hApBar1_Color'); } catch (e) { } break; case 'hApBar0_AlignAuto': // 自动(保留未来扩展) case 'hAlign_Auto': - try { __hSync_WorkModeUI('auto'); console.log('工作模式: 自动 (Auto)'); } catch (e) { } + try { __hSync_WorkModeUI('auto'); } catch (e) { } break; } }; @@ -2704,24 +2724,21 @@ setTimeout(() => { hLog.debug('NodeAlignPro核心组件初始化完毕! 请等待其它插件加载...🔥v2.0.3_rc新版教程文档请点击:右键菜单>【使用教程】查看...'); window.containerController = new __hController_hNAPKit(container), window.__hMgr_PopEl__Position = new __hMgr_PopEl__Position(), window.__hMgr_PopEl__Position.init(container), window.__hMgr_MenuHide = new __hMgr_MenuHide(); __hInit_AllIcons(), __hInit_MainInterface(), __hInit_hMenu__Dropdown(); window.__hColor_Module = new __hColor_Module(); __hInit_ColorPicker(); window.NodeAlignProSettingsManager = new __hMgr_Settings(); // 初始化设置管理器 - // 尝试同步工作模式UI(优先使用设置管理器加载结果,兼容旧存储键) + // 尝试同步工作模式UI(设置管理器的loadSettingsFromStorage已处理,此处仅兼容旧存储键) try { const storedWorkMode = localStorage.getItem('NodeAlignPro_WorkMode'); - if (storedWorkMode && window.NodeAlignProSettingsManager && typeof window.NodeAlignProSettingsManager.setWorkMode === 'function') { - window.NodeAlignProSettingsManager.setWorkMode(storedWorkMode); - } else { - const legacy = localStorage.getItem('hNodeAlignPro_Logic'); - if (legacy && typeof __hSync_WorkModeUI === 'function') { - if (legacy === 'node2') __hSync_WorkModeUI('hApBar2_Node2'); - else if (legacy === 'color') __hSync_WorkModeUI('hApBar1_Color'); - else __hSync_WorkModeUI('hApBar2_Align'); - } + const legacy = localStorage.getItem('hNodeAlignPro_Logic'); + // 只有当没有存储的工作模式且存在旧逻辑键时,才需要同步UI + if (!storedWorkMode && legacy && typeof __hSync_WorkModeUI === 'function') { + if (legacy === 'node2') __hSync_WorkModeUI('hApBar2_Node2'); + else if (legacy === 'color') __hSync_WorkModeUI('hApBar1_Color'); + else __hSync_WorkModeUI('hApBar2_Align'); } } catch (e) { } window.__hMenu_Selection = __hMenu_Selection; window.__hMgr_ACbar = __hMgr_ACbar; // 确保关键函数暴露 window.__hMgr_DisplayMode = new __hMgr_DisplayMode(); const savedDisplayMode = localStorage.getItem('NodeAlignProDisplayMode'); savedDisplayMode === 'following' ? (window.__hMgr_DisplayMode.setFollowingMode(), hLog.info('显示模式: 跟随选框')) : (window.__hMgr_DisplayMode.setPermanentMode(), hLog.info('显示模式: 常驻显示')); hLog.log('NodeAlignPro 插件初始化完成'); setTimeout(() => { __hMgr_ACbar.loadModeFromStorage(); hLog.info('联动模式: 已禁用'); __hMgr_ACbar.linkMode === 1 && __hMgr_ACbar.syncRunButtonPosition(); hLog.info('联动模式: 已启用'); }, 500); - setTimeout(() => { const debugInfo = document.querySelector('.hDebugInfo'); if (debugInfo) debugInfo.style.display = 'none'; hLog.info('debugInfo 已自动隐藏 (24秒超时)'); }, 3000); window.hScreenColorPicker = window.__hColor_Module?.screenColorPicker; + setTimeout(() => { const debugInfo = document.querySelector('.hDebugInfo'); if (debugInfo) debugInfo.style.display = 'none'; hLog.info('debugInfo 已自动隐藏 (6秒超时)'); }, 6000); window.hScreenColorPicker = window.__hColor_Module?.screenColorPicker; }, 100); }; @@ -2733,7 +2750,7 @@ // =========== NodeAlignPro 设置管理器 =========== class __hMgr_Settings { - constructor() { this.settings = {}; this.init(); } + constructor() { this.settings = {}; this.currentWorkMode = null; this.init(); } init() { this.loadSettingsFromStorage(); setTimeout(() => this.checkAndFixLinkMode(), 1000); } // 确保历史版本的调用者不会因方法缺失而报错,同时尝试与 ACbar 的状态保持同步 @@ -2834,9 +2851,14 @@ // 设置工作模式(来自设置面板或本地存储) setWorkMode(value) { try { + // 避免相同值的重复设置 + if (this.currentWorkMode === value) { + return; // 值未改变,直接返回 + } + // value 可能为设置面板的值(如'hApBar1_Color','hApBar2_Align','hApBar2_Node2','hAlign_Auto') if (typeof __hMenu_Selection === 'function') { - try { __hMenu_Selection(value); localStorage.setItem('NodeAlignPro_WorkMode', value); return; } catch (e) { console.warn('调用 __hMenu_Selection 失败:', e); } + try { __hMenu_Selection(value); localStorage.setItem('NodeAlignPro_WorkMode', value); this.currentWorkMode = value; return; } catch (e) { console.warn('调用 __hMenu_Selection 失败:', e); } } // 回退:直接调用对齐逻辑/UI同步函数 if (typeof __hSetAlignLogicMode === 'function') { @@ -2846,6 +2868,7 @@ else { __hSetAlignLogicMode('align'); } } localStorage.setItem('NodeAlignPro_WorkMode', value); + this.currentWorkMode = value; // 更新当前工作模式 hLog && hLog.info('--@hSetting', `工作模式已设置为: ${value}`); } catch (error) { hLog && hLog.error('--@hSetting', '设置工作模式失败:', error); } } diff --git a/web/hNodeAlignPro_cfg.js b/web/hNodeAlignPro_cfg.js index 834e765..1f1a10a 100644 --- a/web/hNodeAlignPro_cfg.js +++ b/web/hNodeAlignPro_cfg.js @@ -1,104 +1,303 @@ /** * @Artstich_Example * @name easykit-node-align (ComfyUI Plugin) - * @description Professional alignment & real-time node color picker. A must-have plugin for managing node layout and color schemes in ComfyUI. Features a real-time color picker, alignment, 7 preset colors, grayscale/custom modes, and one-click reverse alignment. + * @description Node2.0-based professional alignment & real-time node color picker - innovative first support: A must-have plugin for managing node layout and color schemes in ComfyUI. Features a real-time color picker, alignment, 7 preset colors, grayscale/custom modes, and one-click reverse alignment. * @author ArtsticH - * @see https://registry.comfy.org/zh/nodes/easykit-node-align + * @see https://registry.comfy.org/nodes/easykit-node-align * @see https://github.com/ArtsticH/ComfyUI_EasyKitHT_NodeAlignPro * @see https://gitee.com/ArtsticH/ComfyUI_EasyKitHT_NodeAlignPro * @installCommand comfy node install easykit-node-align * @installCommand git clone https://github.com/ArtsticH/ComfyUI_EasyKitHT_NodeAlignPro.git * @installCommand git clone https://gitee.com/ArtsticH/ComfyUI_EasyKitHT_NodeAlignPro.git - * @created 2025-04-29 @date 2025-06-15 @version v2.0.3 @lastUpdated 2026-01-24 @license GPL-3.0 + * @created 2025-04-29 @date 2025-06-15 @lastUpdated 2026-02-01 @version v2.1.14 @license GPL-3.0 * @copyright ©2012-2026, All rights reserved. Freely open to use, modify, and distribute in accordance with the GPL-3.0 license. */ import { app } from "../../scripts/app.js"; // 简单的国际化助手,当hLanguage未就绪时回退到提供的中文文本 -function h_i18n(key, fallback) { - try { return window.hLanguage && typeof window.hLanguage.t === 'function' ? window.hLanguage.t(key) : (fallback || key); } catch (e) { return fallback || key; } -} +function h_i18n(key, fallback) { try { return window.hLanguage && typeof window.hLanguage.t === 'function' ? window.hLanguage.t(key) : (fallback || key); } catch (e) { return fallback || key; } } // 辅助函数:安全地调用存在的方法,否则存储待处理的值 function __hNodeAlignPro_safeCall(target, methodName, keyForPending, value) { - try { - if (target && typeof target[methodName] === 'function') { - target[methodName](value); - return true; - } - } catch (e) { console.warn(`[NodeAlignPro 设置模块] 调用 ${methodName} 失败:`, e); } - // 存储待处理值供主模块稍后获取 - try { - window.__hNodeAlignPro_pendingSettings = window.__hNodeAlignPro_pendingSettings || {}; - window.__hNodeAlignPro_pendingSettings[keyForPending] = value; - console.info(`[NodeAlignPro 设置模块] 挂起设置 ${keyForPending}=${value},等待主模块处理`); - } catch (e) { /* 忽略 */ } + try { if (target && typeof target[methodName] === 'function') return target[methodName](value), true; } catch (e) { console.warn(`[NodeAlignPro 设置模块] 调用 ${methodName} 失败:`, e); } + try { window.__hNodeAlignPro_pendingSettings = window.__hNodeAlignPro_pendingSettings || {}; window.__hNodeAlignPro_pendingSettings[keyForPending] = value; console.info(`[NodeAlignPro 设置模块] 挂起设置 ${keyForPending}=${value},等待主模块处理`); } catch (e) { /* 忽略 */ } // 存储待处理值供主模块稍后获取 return false; } +// 【前景色】的选择器(--color-muted) +let hAutoTheme__FgColor = [ + '#hCPr__nodePreviewTips', // ID选择器 + '.hCPr__valueLabel', // 类选择器 + '.hSelKit-label', //右键菜单标签文本 + '.copy-btn', //取色器复制图标 + '.hCPr__hsbBar_sliderLabel' //取色器hsb滑块标签 +]; + +// 【背景色】的选择器(--comfy-menu-bg) +let hAutoTheme__BgColor = [ + '.Artstich_hColorPicker', + '#h2__hNodeAlignPro', + '#h6__hMenu', + '.hCPr__sliderValue', // HSB颜色文本框 + '.hValue-input', //取色器文本框 + '.hCPr__sliderValue', //取色器hsb文本框 + '.hCPr__copyIcon-front', '.hCPr__copyIcon-back', //取色器复制图标 + '#debugInfo' +]; + +// 【边框色】的选择器(--border-color) +let hAutoTheme__BorderColor = [ + '.Artstich_hColorPicker', + '#h2__hNodeAlignPro', + '#h6__hMenu', + '.hCPr__sliderValue', // HSB颜色文本框 + '.hValue-input', //取色器文本框 + '.hCPr__sliderValue', //取色器hsb文本框 + '.hCPr__header', //取色器标题下划线 + '#debugInfo' +]; + +// 【分割线颜色】的选择器(使用主题边框色作为填充色) +let hAutoTheme__DividerColor = [ + '.hBarDivider' +]; + +// 【悬浮背景色】的选择器(--comfy-menu-hover-bg) +let hAutoTheme__HoverColor = [ + '.btn:hover' // 对齐按钮悬浮状态 +]; + +// 备份原始数组 +const ORIGINAL_SELECTORS = { hAutoTheme__FgColor: [...hAutoTheme__FgColor], hAutoTheme__BgColor: [...hAutoTheme__BgColor], hAutoTheme__BorderColor: [...hAutoTheme__BorderColor], hAutoTheme__HoverColor: [...hAutoTheme__HoverColor], hAutoTheme__DividerColor: [...hAutoTheme__DividerColor] }; + +// 清空选择器数组(开关关闭时调用) +function disableThemeSelectors() { hAutoTheme__FgColor = []; hAutoTheme__BgColor = []; hAutoTheme__BorderColor = []; hAutoTheme__HoverColor = []; hAutoTheme__DividerColor = []; console.log('主题选择器已禁用(数组已清空)'); } + +// 恢复选择器数组(开关开启时调用) +function enableThemeSelectors() { + hAutoTheme__FgColor = [...ORIGINAL_SELECTORS.hAutoTheme__FgColor]; + hAutoTheme__BgColor = [...ORIGINAL_SELECTORS.hAutoTheme__BgColor]; + hAutoTheme__BorderColor = [...ORIGINAL_SELECTORS.hAutoTheme__BorderColor]; + hAutoTheme__HoverColor = [...ORIGINAL_SELECTORS.hAutoTheme__HoverColor]; + hAutoTheme__DividerColor = [...ORIGINAL_SELECTORS.hAutoTheme__DividerColor]; + console.log('主题选择器已启用(数组已恢复)'); +} + +// 封装函数:为颜色添加0.8透明度 +function h_getColorWithOpacity(colorValue, opacity = 0.8) { + if (!colorValue || colorValue === 'auto') return colorValue; + let r, g, b; + if (colorValue.startsWith('rgb')) { // 处理RGB格式 + const rgbMatch = colorValue.match(/rgb\((\d+),\s*(\d+),\s*(\d+)\)/); + if (rgbMatch) [r, g, b] = rgbMatch.slice(1, 4).map(Number); + } else { // 处理十六进制格式 + const hex = colorValue.replace('#', ''); + r = parseInt(hex.substring(0, 2), 16), g = parseInt(hex.substring(2, 4), 16), b = parseInt(hex.substring(4, 6), 16); + } + return r != undefined ? `rgba(${r}, ${g}, ${b}, ${opacity})` : colorValue; +} + +// 判断是否为DebugInfo元素 +function h_isDebugInfoElement(selectorOrElement, isElement = false) { + return isElement + ? selectorOrElement.classList?.contains('hDebugInfo') || selectorOrElement.id === 'debugInfo' + : (selectorOrElement = selectorOrElement.trim(), selectorOrElement === '.hDebugInfo' || selectorOrElement === '#debugInfo'); +} + +// 通用选择器样式应用函数 +function hAutoTheme__ApplyStyle(selectors, styleProperty, styleValue, pseudoClass = '') { + if (!selectors?.length) return; + + // 将JavaScript样式属性名转换为CSS属性名(camelCase -> kebab-case) + const cssPropertyName = styleProperty.replace(/[A-Z]/g, letter => `-${letter.toLowerCase()}`); + + if (pseudoClass) { // 批量处理伪类选择器 + const styleId = `hThemeStyle_${styleProperty}_${pseudoClass.replace(':', '')}`; let styleElement = document.getElementById(styleId); + if (styleValue === null || styleValue === 'auto') styleElement && styleElement.parentNode && styleElement.parentNode.removeChild(styleElement); // 清除样式 + else { // 批量生成CSS规则 + const cssRules = selectors.map(selector => { let finalValue = styleValue, trimmedSelector = selector.trim(); styleProperty === 'backgroundColor' && h_isDebugInfoElement(trimmedSelector) && (finalValue = h_getColorWithOpacity(finalValue)); return `${trimmedSelector}${pseudoClass} { ${cssPropertyName}: ${finalValue} !important; }`; }).join('\n'); // 为DebugInfo元素添加0.8透明度 + styleElement.textContent = cssRules; + } + return; + } + + // 批量处理普通选择器 + selectors.forEach(selector => { + let trimmedSelector = selector?.trim(); if (!trimmedSelector) return; + try { + const isIdSelector = trimmedSelector.startsWith('#'); + const targetElements = isIdSelector ? [document.getElementById(trimmedSelector.slice(1))].filter(Boolean) : document.querySelectorAll(trimmedSelector); targetElements.length > 0 && targetElements.forEach(element => { if (styleValue === null || styleValue === 'auto') element.style.removeProperty(cssPropertyName); else { let finalValue = styleValue; styleProperty === 'backgroundColor' && h_isDebugInfoElement(element, true) && (finalValue = h_getColorWithOpacity(finalValue)); element.style[styleProperty] = finalValue; } }); + } catch (error) { console.warn(`应用样式到选择器 ${selector} 失败:`, error); } + }); +} + +// 【== 统一颜色管理函数 ==】 +// 统一应用颜色到选择器 +function hNAP_applyColorToSelectors(colorType, colorValue) { + try { + // 根据颜色类型确定选择器、样式属性和伪类 - 使用对象映射替代switch + const colorConfig = { + fg: { selectors: hAutoTheme__FgColor, styleProperty: 'color' }, + bg: { selectors: hAutoTheme__BgColor, styleProperty: 'backgroundColor' }, + border: { selectors: hAutoTheme__BorderColor, styleProperty: 'borderColor' }, + hover: { selectors: hAutoTheme__HoverColor, styleProperty: 'backgroundColor', pseudoClass: ':hover' }, + divider: { selectors: hAutoTheme__DividerColor, styleProperty: 'backgroundColor' } + }; + + const config = colorConfig[colorType]; + if (!config) return console.warn(`[NodeAlignPro] 未知的颜色类型: ${colorType}`); + + hAutoTheme__ApplyStyle(config.selectors, config.styleProperty, colorValue, config.pseudoClass || ''); + } catch (error) { console.error(`[NodeAlignPro] 应用颜色到选择器失败 (${colorType}):`, error); } +} + +// 统一应用主题色到CSS变量 +function hNAP_applyThemeToCSSVars(fgColor) { + try { + if (!fgColor) return document.documentElement.style.removeProperty('--hC_hBtn_svg'); // 应用前景色到CSS变量(对齐按钮颜色) + let r, g, b; + if (fgColor.startsWith('rgb')) { // RGB格式:rgb(r, g, b) + const rgbMatch = fgColor.match(/rgb\((\d+),\s*(\d+),\s*(\d+)\)/); + rgbMatch && ([r, g, b] = rgbMatch.slice(1, 4)); + } else { // 非RGB格式,使用全局颜色转换工具处理 + try { const colorWithHash = fgColor.startsWith('#') ? fgColor : `#${fgColor}`; const rgbObj = window.__hColorConvert ? window.__hColorConvert.hexToRgb(colorWithHash) : null; if (rgbObj) [r, g, b] = [rgbObj.r, rgbObj.g, rgbObj.b]; else r = g = 107, b = 112; } catch (e) { r = g = 107, b = 112; } // 确保颜色有#前缀,使用全局转换工具,失败则用默认值 + } + r !== undefined && g !== undefined && b !== undefined && document.documentElement.style.setProperty('--hC_hBtn_svg', `${r}, ${g}, ${b}`); // 设置CSS变量 + } catch (error) { console.error('[NodeAlignPro] 应用主题色到CSS变量失败:', error); } +} + +// 统一应用手动颜色到CSS变量 +function hNAP_applyManualToCSSVars(alignColor) { + try { + // 处理对齐按钮颜色:通过CSS变量--hC_hBtn_svg设置 + const alignColorHex = alignColor.startsWith('#') ? alignColor.slice(1) : alignColor; + const r = parseInt(alignColorHex.substr(0, 2), 16), g = parseInt(alignColorHex.substr(2, 2), 16), b = parseInt(alignColorHex.substr(4, 2), 16); + document.documentElement.style.setProperty('--hC_hBtn_svg', `${r}, ${g}, ${b}`); + } catch (error) { console.error('[NodeAlignPro] 应用手动颜色到CSS变量失败:', error); } +} + +// 标准化主题色应用函数 +function hAutoTheme__ApplyColors(fgColor, bgColor, borderColor, hoverColor) { + try { + // 应用主题色到CSS变量及各类型颜色 + hNAP_applyThemeToCSSVars(fgColor); hNAP_applyColorToSelectors('fg', fgColor); hNAP_applyColorToSelectors('bg', bgColor); + hNAP_applyColorToSelectors('border', borderColor); hNAP_applyColorToSelectors('hover', hoverColor); hNAP_applyColorToSelectors('divider', borderColor); + // 确保取色器按钮的核心CSS变量不被清除 + const root = document.documentElement; + !root.style.getPropertyValue('--hC_BW1_Black') && root.style.removeProperty('--hC_BW1_Black'); // 移除内联样式,恢复CSS文件中的默认值 + } catch (error) { console.error('应用主题色到选择器失败:', error); } +} + +// 获取ComfyUI主题颜色 +function getComfyUIThemeColors() { + try { + const root = document.documentElement, computedStyles = getComputedStyle(root); // 获取根元素和计算样式 + // 获取ComfyUI主题的文字颜色(用于对齐按钮) + let textColor = computedStyles.getPropertyValue('--color-muted').trim(); + textColor = !textColor ? (computedStyles.getPropertyValue('--comfy-input-text').trim() || computedStyles.getPropertyValue('--comfy-menu-text').trim()) : textColor; + // 获取主题相关颜色:背景色、悬浮色、边框色 + const bgColor = computedStyles.getPropertyValue('--comfy-menu-bg').trim(); + const hoverBgColor = computedStyles.getPropertyValue('--comfy-menu-hover-bg').trim() || computedStyles.getPropertyValue('--comfy-focus-bg').trim(); + const borderColor = computedStyles.getPropertyValue('--border-color').trim() || computedStyles.getPropertyValue('--comfy-border-color').trim(); + return { textColor, bgColor, hoverBgColor, borderColor }; + } catch (error) { console.error('获取ComfyUI主题颜色失败:', error); return null; } +} + +// 应用主题颜色的函数 +function applyThemeColors(forceApply = false) { + try { + // 快速检查主题色开关状态,避免不必要的计算 + const useThemeColor = forceApply ? true : (app.ui?.settings?.getSettingValue("hNodeAlignPro.hColor_AutoTtheme") || false); + if (!useThemeColor) return; // 如果开关关闭且非强制应用,直接返回 + // 缓存主题颜色,避免重复获取 + const themeColors = getComfyUIThemeColors(); + if (!themeColors) return; + const { textColor, bgColor, hoverBgColor, borderColor } = themeColors; + hAutoTheme__ApplyColors(textColor, bgColor, borderColor, hoverBgColor); // 直接应用主题色,hAutoTheme__ApplyColors内部会处理样式清除 + } catch (error) { console.error('应用ComfyUI主题配色失败:', error); } +} + +// 应用手动设置的颜色 +function applyManualColors() { + try { + const savedAlignColor = app.ui.settings.getSettingValue("hNodeAlignPro.hColor_SVG") || "6B6B70", savedBgColor = app.ui.settings.getSettingValue("hNodeAlignPro.hColor_bg") || "18181B"; // 从设置中获取用户手动设置的颜色 + const alignColor = savedAlignColor.startsWith('#') ? savedAlignColor : `#${savedAlignColor}`, bgColor = savedBgColor.startsWith('#') ? savedBgColor : `#${savedBgColor}`; // 确保颜色值有#前缀 + hNAP_applyManualToCSSVars(alignColor); // 应用手动颜色到CSS变量 + const resetBorderColor = null, resetHoverBgColor = null; // 对于没有手动设置选项的悬浮色和边框色,清除样式以恢复默认的CSS变量值 + // 使用原始选择器数组,确保手动颜色能正确应用 + hAutoTheme__ApplyStyle(ORIGINAL_SELECTORS.hAutoTheme__FgColor, 'color', alignColor); + hAutoTheme__ApplyStyle(ORIGINAL_SELECTORS.hAutoTheme__BgColor, 'backgroundColor', bgColor); + hAutoTheme__ApplyStyle(ORIGINAL_SELECTORS.hAutoTheme__BorderColor, 'borderColor', resetBorderColor); + hAutoTheme__ApplyStyle(ORIGINAL_SELECTORS.hAutoTheme__HoverColor, 'backgroundColor', resetHoverBgColor, ':hover'); + hAutoTheme__ApplyStyle(ORIGINAL_SELECTORS.hAutoTheme__DividerColor, 'backgroundColor', resetBorderColor); + // 确保取色器按钮(包括#hZoom)的样式正确 + ['#hClear', '#hPick', '#hRandom', '#hZoom'].forEach(selector => { + try { const element = document.querySelector(selector); element && (element.style.removeProperty('background-color'), element.style.removeProperty('border-color')); } catch (e) { console.warn(`恢复取色器按钮样式失败 (${selector}):`, e); } + }); + } catch (error) { console.error('应用手动设置颜色失败:', error); } +} + +// 防抖函数,用于优化高频触发的函数调用 +function debounce(func, wait) { let timeout; return function executedFunction(...args) { const later = () => { clearTimeout(timeout); func(...args); }; clearTimeout(timeout); timeout = setTimeout(later, wait); }; } + +// 设置主题变化监听 +function setupThemeChangeListener() { + const root = document.documentElement; + const debouncedApplyThemeColors = debounce(() => { applyThemeColors(); }, 100); // 100ms防抖主题色更新函数,避免频繁触发 + const observer = new MutationObserver((mutations) => { mutations.forEach((mutation) => { mutation.attributeName === 'style' && debouncedApplyThemeColors(); }); }); // 创建MutationObserver监听根元素的style属性变化 主题变化时重新应用颜色 + observer.observe(root, { attributes: true, attributeFilter: ['style'] }); + window.__hNodeAlignPro_themeObserver = observer; // 配置观察器并存储观察器引用,以便在需要时可以移除 +} + const NodeAlignProSettings = [ { - id: "hNodeAlignPro.ShowOperationLog", name: h_i18n('Setting_ShowOperationLog','显示操作日志'), type: "boolean", + id: "hNodeAlignPro.ShowOperationLog", name: h_i18n('Setting_ShowOperationLog', '显示操作日志'), type: "boolean", defaultValue: false, - category: ["🔥 NodeAlignPro", "Z开发人员选项 (Developer Options)", h_i18n('Setting_ShowOperationLog','显示操作日志')], - tooltip: h_i18n('Setting_ShowOperationLog','开启后,插件操作日志将输出到页面左上角,方便进阶用户调试'), + category: ["🔥 NodeAlignPro", "🛠️Z开发人员选项 (Developer Options)", h_i18n('Setting_ShowOperationLog', '显示操作日志')], + tooltip: h_i18n('Setting_ShowOperationLog', '开启后,插件操作日志将输出到页面左上角,方便进阶用户调试'), onChange: (value) => { try { if (window.NodeAlignProSettingsManager) { window.NodeAlignProSettingsManager.setShowOperationLog(value); } } catch (error) { console.error('设置操作日志显示失败:', error); } } }, { - id: "hNodeAlignPro.hReset", name: h_i18n('Setting_ForceReset','⚠强制重置NodeAlignPro插件'), type: "boolean", + id: "hNodeAlignPro.hReset", name: h_i18n('Setting_ForceReset', '⚠强制重置NodeAlignPro插件'), type: "boolean", defaultValue: false, - category: ["🔥 NodeAlignPro", "Z开发人员选项 (Developer Options)", h_i18n('Setting_ForceReset','⚠强制重置NodeAlignPro插件')], - tooltip: h_i18n('Setting_ForceReset','⚠此操作会强制刷新页面,请务必先保存工作流! 开启后会强制重建NodeAlignPro插件,仅在插件异常时使用! '), + category: ["🔥 NodeAlignPro", "🛠️Z开发人员选项 (Developer Options)", h_i18n('Setting_ForceReset', '⚠强制重置NodeAlignPro插件')], + tooltip: h_i18n('Setting_ForceReset', '⚠此操作会强制刷新页面,请务必先保存工作流! 开启后会强制重建NodeAlignPro插件,仅在插件异常时使用! '), onChange: (value) => { if (value) try { - if (typeof __hReset__hNAP_State === 'function') __hReset__hNAP_State(); else resetNodeAlignProManually(); // 1. 调用核心文件中的重置函数。如果核心重置函数不存在,执行手动重置 - resetAllSettings(); clearAllStorage(); // 2. 重置所有设置;3. 清除所有本地存储 - setTimeout(() => { // 4. 刷新页面以完全重置插件 - const isResetEnabled = app.ui?.settings?.getSettingValue?.("hNodeAlignPro.hReset"); // 检查开关是否处于关闭状态 - if (isResetEnabled === true) location.reload(); // 只有当开关处于开启状态时才刷新 - else { if (hLog) hLog.info('--@hSetting', '🔥NodeAlignPro已重置!直接可用,无需重复刷新页面'); console.log('🔥NodeAlignPro已重置!直接可用,无需重复刷新页面'); } // 如果开关已关闭,则不刷新,仅记录日志 - }, 500); - if (hLog) hLog.info('--@hSetting', '插件已通过设置菜单强制重置,页面将重新加载...'); - } catch (error) { console.error('重置插件失败:', error); if (hLog) hLog.error('--@hSetting', '重置失败:', error); } + (typeof __hReset__hNAP_State === 'function' ? __hReset__hNAP_State() : resetNodeAlignProManually()); // 调用核心文件中的重置函数,核心函数不存在则执行手动重置 + resetAllSettings(); clearAllStorage(); // 重置所有设置并清除本地存储 + setTimeout(() => { const isResetEnabled = app.ui?.settings?.getSettingValue?.('hNodeAlignPro.hReset'); isResetEnabled === true ? location.reload() : (hLog && hLog.info('--@hSetting', '🔥NodeAlignPro已重置!直接可用,无需重复刷新页面'), console.log('🔥NodeAlignPro已重置!直接可用,无需重复刷新页面')); }, 500); // 检查开关状态,开启则刷新,否则记录日志 + hLog && hLog.info('--@hSetting', '插件已通过设置菜单强制重置,页面将重新加载...'); + } catch (error) { console.error('重置插件失败:', error); hLog && hLog.error('--@hSetting', '重置失败:', error); } } }, - // { id: "hNodeAlignPro.button_test", name: "测试", type: "input", defaultValue: "测试文本", category: ["🔥 NodeAlignPro", "NodeAlignPro颜色预设 (Color preset)", "测试"], onChange: (newVal) => { } }, + // { id: "hNodeAlignPro.button_test", name: "测试", type: "input", defaultValue: "测试文本", category: ["🔥 NodeAlignPro", "🎨NodeAlignPro颜色预设 (Color preset)", "测试"], onChange: (newVal) => { } }, { - id: "hNodeAlignPro.linkMode", name: h_i18n('Setting_DragMode','拖拽方式'), type: "combo", - options: [{ value: "hDragMode1_Split", text: h_i18n('hSelKit_DragSplit2','解 耦') }, { value: "hDragMode0_Link", text: h_i18n('hSelKit_DragLink2','联 动') }], + id: "hNodeAlignPro.linkMode", name: h_i18n('Setting_DragMode', '拖拽方式'), type: "combo", + options: [{ value: "hDragMode1_Split", text: h_i18n('hSelKit_DragSplit2', '解 耦') }, { value: "hDragMode0_Link", text: h_i18n('hSelKit_DragLink2', '联 动') }], defaultValue: "hDragMode1_Split", - category: ["🔥 NodeAlignPro", "NodeAlignPro基本设置 (Basic Settings)", h_i18n('Setting_DragMode','拖拽方式')], - tooltip: h_i18n('Setting_DragMode','切换是否联动[运行/Action]按钮到插件面板(与插件右键菜单设置同步)'), + category: ["🔥 NodeAlignPro", "⚙️NodeAlignPro基本设置 (Basic Settings)", h_i18n('Setting_DragMode', '拖拽方式')], + tooltip: h_i18n('Setting_DragMode', '切换是否联动[运行/Action]按钮到插件面板(与插件右键菜单设置同步)'), onChange: (value) => { try { const mode = value === "hDragMode0_Link" ? 1 : 0; - // 首先尝试显式的全局处理函数 - if (typeof __hMenu_Selection === 'function') { - try { __hMenu_Selection(value); return; } catch (e) { console.warn('调用 __hMenu_Selection 失败:', e); } - } - // 如果可用,尝试设置管理器方法 - if (window.NodeAlignProSettingsManager && typeof window.NodeAlignProSettingsManager.setLinkMode === 'function') { - try { window.NodeAlignProSettingsManager.setLinkMode(mode); return; } catch (e) { console.warn('调用 NodeAlignProSettingsManager.setLinkMode 失败:', e); } - } - // 尝试ACbar管理器 - if (window.__hMgr_ACbar && typeof window.__hMgr_ACbar.setLinkMode === 'function') { - try { window.__hMgr_ACbar.setLinkMode(mode); return; } catch (e) { console.warn('调用 __hMgr_ACbar.setLinkMode 失败:', e); } - } - // 回退:存储待处理值供主模块稍后获取 - __hNodeAlignPro_safeCall(null, null, 'linkMode', mode); + if (typeof __hMenu_Selection === 'function') { try { __hMenu_Selection(value); return; } catch (e) { console.warn('调用 __hMenu_Selection 失败:', e); } } + if (window.NodeAlignProSettingsManager && typeof window.NodeAlignProSettingsManager.setLinkMode === 'function') { try { window.NodeAlignProSettingsManager.setLinkMode(mode); return; } catch (e) { console.warn('调用 NodeAlignProSettingsManager.setLinkMode 失败:', e); } } + if (window.__hMgr_ACbar && typeof window.__hMgr_ACbar.setLinkMode === 'function') { try { window.__hMgr_ACbar.setLinkMode(mode); return; } catch (e) { console.warn('调用 __hMgr_ACbar.setLinkMode 失败:', e); } } + __hNodeAlignPro_safeCall(null, null, 'linkMode', mode); // 回退:存储待处理值供主模块稍后获取 } catch (error) { console.error('设置拖拽方式失败:', error); } } }, { - id: "hNodeAlignPro.UIScale", name: h_i18n('Setting_UIScale','UI缩放'), type: "combo", + id: "hNodeAlignPro.UIScale", name: h_i18n('Setting_UIScale', 'UI缩放'), type: "combo", options: [{ value: "hUIScale_0_5x", text: "0.5x" }, { value: "hUIScale_0_75x", text: "0.75x" }, { value: "hUIScale_1x", text: "1x(默认)" }, { value: "hUIScale_1_25x", text: "1.25x" }, { value: "hUIScale_1_5x", text: "1.5x" }, { value: "hUIScale_2x", text: "2x" }], defaultValue: "hUIScale_1x", - category: ["🔥 NodeAlignPro", "NodeAlignPro基本设置 (Basic Settings)", h_i18n('Setting_UIScale','UI缩放')], + category: ["🔥 NodeAlignPro", "⚙️NodeAlignPro基本设置 (Basic Settings)", h_i18n('Setting_UIScale', 'UI缩放')], tooltip: "调整插件UI缩放比例(与插件右键菜单设置同步)", onChange: (value) => { try { if (window.NodeAlignProSettingsManager && typeof window.NodeAlignProSettingsManager.setUIScale === 'function') { window.NodeAlignProSettingsManager.setUIScale(value); } else __hNodeAlignPro_safeCall(null, null, 'uiScale', value); } catch (error) { console.error('设置UI缩放失败:', error); } } }, @@ -106,7 +305,7 @@ const NodeAlignProSettings = [ id: "hNodeAlignPro.UIScale_v2", name: "UI缩放v2", type: "combo", options: [{ value: "hUIScale_0_5x", text: "0.5x" }, { value: "hUIScale_0_75x", text: "0.75x" }, { value: "hUIScale_1x", text: "1x(默认)" }, { value: "hUIScale_1_25x", text: "1.25x" }, { value: "hUIScale_1_5x", text: "1.5x" }, { value: "hUIScale_2x", text: "2x" }], defaultValue: "hUIScale_1x", - category: ["🔥 NodeAlignPro", "NodeAlignPro基本设置 (Basic Settings)", "UI缩放v2"], + category: ["🔥 NodeAlignPro", "⚙️NodeAlignPro基本设置 (Basic Settings)", "UI缩放v2"], attrs: { editable: true, filter: true, filterPlaceholder: "输入/选择缩放比例...", showClear: true, loading: false, loadingIcon: "pi pi-spinner pi-spin" }, onChange: (newVal, oldVal) => { try { @@ -124,145 +323,132 @@ const NodeAlignProSettings = [ }, }, */ { - id: "hNodeAlignPro.WorkMode", name: h_i18n('Setting_WorkMode','工作模式'), type: "combo", + id: "hNodeAlignPro.WorkMode", name: h_i18n('Setting_WorkMode', '工作模式'), type: "combo", options: [ - // { value: 'hAlign_Auto', text: h_i18n('hSelKit_AlignAuto2','自动(Auto)') }, - // { value: "hApBar1_Color", text: h_i18n('hSelKit_ColorBar2', '色卡(ColorBar)') }, - { value: "hApBar2_Align", text: h_i18n('hSelKit_AlignBar2', '传统对齐(AlignStd)') }, - { value: "hApBar2_Node2", text: h_i18n('hSelKit_Node2', 'Node2.0') } + // { value: 'hAlign_Auto', text: h_i18n('hSelKit_AlignAuto2','自动(Auto)') }, { value: "hApBar1_Color", text: h_i18n('hSelKit_ColorBar2', '色卡(ColorBar)') }, + { value: "hApBar2_Align", text: h_i18n('hSelKit_AlignBar2', '传统对齐(AlignStd)') }, { value: "hApBar2_Node2", text: h_i18n('hSelKit_Node2', 'Node2.0') } ], defaultValue: "hApBar2_Align", - category: ["🔥 NodeAlignPro", "NodeAlignPro基本设置 (Basic Settings)", h_i18n('Setting_WorkMode','工作模式')], - tooltip: h_i18n('hTooltip_WorkMode','工作模式 (Work Mode):切换插件工作模式(与插件右键菜单设置同步)。可开启新版Node2.0对齐模式'), + category: ["🔥 NodeAlignPro", "⚙️NodeAlignPro基本设置 (Basic Settings)", h_i18n('Setting_WorkMode', '工作模式')], + tooltip: h_i18n('hTooltip_WorkMode', '工作模式 (Work Mode):切换插件工作模式(与插件右键菜单设置同步)。可开启新版Node2.0对齐模式'), onChange: (value) => { try { if (window.NodeAlignProSettingsManager && typeof window.NodeAlignProSettingsManager.setWorkMode === 'function') { window.NodeAlignProSettingsManager.setWorkMode(value); } else __hNodeAlignPro_safeCall(null, null, 'workMode', value); } catch (error) { console.error('设置工作模式失败:', error); } } }, { - id: "hNodeAlignPro.DisplayMode", name: h_i18n('Setting_DisplayMode','显示模式'), type: "combo", - options: [{ value: "hDispMode0_Always", text: h_i18n('hSelKit_Always2','常驻显示') }, { value: "hDispMode1_Follow", text: h_i18n('hSelKit_Follow2','跟随选框') }], + id: "hNodeAlignPro.DisplayMode", name: h_i18n('Setting_DisplayMode', '显示模式'), type: "combo", + options: [{ value: "hDispMode0_Always", text: h_i18n('hSelKit_Always2', '常驻显示') }, { value: "hDispMode1_Follow", text: h_i18n('hSelKit_Follow2', '跟随选框') }], defaultValue: "hDispMode0_Always", - category: ["🔥 NodeAlignPro", "NodeAlignPro基本设置 (Basic Settings)", h_i18n('Setting_DisplayMode','显示模式')], - tooltip: h_i18n('Setting_DisplayMode','切换插件面板的显示模式(与插件右键菜单设置同步)'), + category: ["🔥 NodeAlignPro", "⚙️NodeAlignPro基本设置 (Basic Settings)", h_i18n('Setting_DisplayMode', '显示模式')], + tooltip: h_i18n('Setting_DisplayMode', '切换插件面板的显示模式(与插件右键菜单设置同步)'), onChange: (value) => { try { if (window.NodeAlignProSettingsManager && typeof window.NodeAlignProSettingsManager.setDisplayMode === 'function') { window.NodeAlignProSettingsManager.setDisplayMode(value); } else __hNodeAlignPro_safeCall(null, null, 'displayMode', value); } catch (error) { console.error('设置显示模式失败:', error); } } }, // 语言选择(优先级高于浏览器语言),切换即刻生效 { - id: "hNodeAlignPro.Language", name: h_i18n('Setting_Language','语言'), type: "combo", - options: [ - { value: 'auto', text: h_i18n('hSelKit_AlignAuto','自动(Auto)') }, - { value: 'cn', text: h_i18n('Option_Lang_CN','中文') }, - { value: 'en', text: h_i18n('Option_Lang_EN','English') } - ], + id: "hNodeAlignPro.Language", name: h_i18n('Setting_Language', '语言'), type: "combo", + options: [{ value: 'auto', text: h_i18n('hSelKit_AlignAuto', '自动(Auto)') }, { value: 'cn', text: h_i18n('Option_Lang_CN', '中文') }, { value: 'en', text: h_i18n('Option_Lang_EN', 'English') }], defaultValue: 'cn', - category: ["🔥 NodeAlignPro", "NodeAlignPro基本设置 (Basic Settings)", h_i18n('Setting_Language','语言')], - tooltip: h_i18n('Setting_Language','选择插件界面语言(优先于浏览器语言设置)'), + category: ["🔥 NodeAlignPro", "⚙️NodeAlignPro基本设置 (Basic Settings)", h_i18n('Setting_Language', '语言')], + tooltip: h_i18n('Setting_Language', '选择插件界面语言(优先于浏览器语言设置)'), onChange: (value) => { try { if (window.hLanguage && typeof window.hLanguage.setLang === 'function') { - // 'auto'表示不强制特定语言;遵循浏览器/ComfyUI设置 - if (value === 'auto') window.hLanguage.setLang('auto'); else window.hLanguage.setLang(value); - // 立即应用到文档和现有插件容器 - try { window.hLanguage.applyToDOM(document); } catch (e) { console.warn('应用语言到DOM失败:', e); } - // 如果存在插件容器,也应用到该容器 - try { const c = document.getElementById('hNodeAlignKit'); if (c && window.hLanguage) window.hLanguage.applyToDOM(c); } catch (e) { /* 忽略 */ } + window.hLanguage.setLang(value === 'auto' ? 'auto' : value); // 'auto'表示不强制特定语言;遵循浏览器/ComfyUI设置 + try { window.hLanguage.applyToDOM(document); } catch (e) { console.warn('应用语言到DOM失败:', e); } // 立即应用到文档和现有插件容器 + try { const c = document.getElementById('hNodeAlignKit'); c && window.hLanguage && window.hLanguage.applyToDOM(c); } catch (e) { /* 忽略 */ } // 如果存在插件容器,也应用到该容器 console.info('[NodeAlignPro 设置] 语言已切换为', window.hLanguage.getLang()); - } else { - __hNodeAlignPro_safeCall(null, null, 'language', value); - } + } else { __hNodeAlignPro_safeCall(null, null, 'language', value); } } catch (error) { console.error('设置语言失败:', error); } } }, { - id: "hNodeAlignPro.hColor_SVG", name: h_i18n('Setting_AlignBtnColor','对齐按钮颜色'), type: "color", + id: "hNodeAlignPro.hColor_SVG", name: h_i18n('Setting_AlignBtnColor', '对齐按钮颜色'), type: "color", defaultValue: "6B6B70", - category: ["🔥 NodeAlignPro", "NodeAlignPro颜色预设 (Color preset)", h_i18n('Setting_AlignBtnColor','对齐按钮颜色')], - tooltip: h_i18n('Setting_AlignBtnColor','控制对齐按钮颜色'), - onChange: (newVal) => { try { if (window.NodeAlignProSettingsManager && typeof window.NodeAlignProSettingsManager.setAlignButtonColor === 'function') { window.NodeAlignProSettingsManager.setAlignButtonColor(newVal); } else __hNodeAlignPro_safeCall(null, null, 'alignButtonColor', newVal); } catch (error) { console.error('设置对齐按钮颜色失败:', error); } } + category: ["🔥 NodeAlignPro", "🎨NodeAlignPro颜色预设 (Color preset)", h_i18n('Setting_AlignBtnColor', '对齐按钮颜色')], + tooltip: h_i18n('Setting_AlignBtnColor', '控制对齐按钮颜色'), + onChange: (newVal) => { try { const useThemeColor = app.ui?.settings?.getSettingValue("hNodeAlignPro.hColor_AutoTtheme") || false; !useThemeColor && applyManualColors(); } catch (error) { console.error('设置对齐按钮颜色失败:', error); } } // 检查主题配色是否启用,如果启用则不做处理 }, { - id: "hNodeAlignPro.hColor_bg", name: h_i18n('Setting_ToolbarBgColor','工具栏背景色'), type: "color", + id: "hNodeAlignPro.hColor_AutoTtheme", name: h_i18n('Setting_ToolbarColor_Auto', '使用ComfyUI主题配色(Use ComfyUI theme color)'), type: "boolean", + defaultValue: false, + category: ["🔥 NodeAlignPro", "🎨NodeAlignPro颜色预设 (Color preset)", h_i18n('Setting_ToolbarColor_Auto', '使用ComfyUI theme color)')], + tooltip: h_i18n('Setting_ToolbarColor_Auto1', '若开启,将ComfyUI主题配色,下方手动设置的颜色将无效(If enabled, ComfyUI theme color will be used, and manual color setting will be ignored)'), + onChange: (value) => { + try { + value ? (enableThemeSelectors(), applyThemeColors(true), !window.__hNodeAlignPro_themeObserver && setupThemeChangeListener()) : (window.__hNodeAlignPro_themeObserver?.disconnect(), window.__hNodeAlignPro_themeObserver = null, hAutoTheme__ApplyColors(null, null, null, null), applyManualColors()); // 开启时:启用选择器数组,应用主题色并设置监听;关闭时:移除主题监听、清除主题样式、应用手动颜色 + } catch (error) { console.error('使用ComfyUI主题配色失败:', error); } + } + }, + + { + id: "hNodeAlignPro.hColor_bg", name: h_i18n('Setting_ToolbarBgColor', '工具栏背景色'), type: "color", defaultValue: "18181B", - category: ["🔥 NodeAlignPro", "NodeAlignPro颜色预设 (Color preset)", h_i18n('Setting_ToolbarBgColor','工具栏背景色')], - tooltip: h_i18n('Setting_ToolbarBgColor','控制对齐组件的背景色'), - onChange: (newVal) => { try { if (window.NodeAlignProSettingsManager && typeof window.NodeAlignProSettingsManager.setToolbarBgColor === 'function') { window.NodeAlignProSettingsManager.setToolbarBgColor(newVal); } else __hNodeAlignPro_safeCall(null, null, 'toolbarBgColor', newVal); } catch (error) { console.error('设置工具栏背景色失败:', error); } } + category: ["🔥 NodeAlignPro", "🎨NodeAlignPro颜色预设 (Color preset)", h_i18n('Setting_ToolbarBgColor', '工具栏背景色')], + tooltip: h_i18n('Setting_ToolbarBgColor', '控制对齐组件的背景色'), + onChange: (newVal) => { try { const useThemeColor = app.ui?.settings?.getSettingValue("hNodeAlignPro.hColor_AutoTtheme") || false; !useThemeColor && applyManualColors(); } catch (error) { console.error('设置工具栏背景色失败:', error); } } // 检查主题配色是否启用,如果启用则不做处理 }, { - id: "hNodeAlignPro.hOpacity", name: h_i18n('Setting_ToolbarOpacity','工具栏透明度'), type: "slider", - defaultValue: 95, + id: "hNodeAlignPro.hOpacity", name: h_i18n('Setting_ToolbarOpacity', '工具栏透明度'), type: "slider", + defaultValue: 100, attrs: { min: 0, max: 100, step: 1 }, - category: ["🔥 NodeAlignPro", "NodeAlignPro颜色预设 (Color preset)", h_i18n('Setting_ToolbarOpacity','工具栏透明度')], - tooltip: h_i18n('Setting_ToolbarOpacity','控制对齐组件的背景透明度'), + category: ["🔥 NodeAlignPro", "🎨NodeAlignPro颜色预设 (Color preset)", h_i18n('Setting_ToolbarOpacity', '工具栏透明度')], + tooltip: h_i18n('Setting_ToolbarOpacity', '控制对齐组件的背景透明度'), onChange: (newVal) => { try { if (window.NodeAlignProSettingsManager && typeof window.NodeAlignProSettingsManager.setToolbarOpacity === 'function') { window.NodeAlignProSettingsManager.setToolbarOpacity(newVal); } else __hNodeAlignPro_safeCall(null, null, 'toolbarOpacity', newVal); } catch (error) { console.error('设置工具栏透明度失败:', error); } } }, { - id: "hNodeAlignPro.NewVersionTips", name: h_i18n('Setting_NewVersionTips','新版说明'), type: "boolean", + id: "hNodeAlignPro.NewVersionTips", name: h_i18n('Setting_NewVersionTips', '新版说明'), type: "boolean", defaultValue: true, - category: ["🔥 NodeAlignPro", "NodeAlignPro基本设置 (Basic Settings)", h_i18n('Setting_NewVersionTips','新版说明')], - tooltip: h_i18n('Setting_NewVersionTips','v2.0.3_rc新版功能:按Shift、Alt、Ctrl Alt切换不同色卡模式... Alt+对齐按钮:对齐到“反向基准”节点^_^'), + category: ["🔥 NodeAlignPro", "⚙️NodeAlignPro基本设置 (Basic Settings)", h_i18n('Setting_NewVersionTips', '新版说明')], + tooltip: h_i18n('Setting_NewVersionTips', 'v2.0.3_rc新版功能:按Shift、Alt、Ctrl Alt切换不同色卡模式... Alt+对齐按钮:对齐到"反向基准"节点^_^'), onChange: (value) => { try { if (window.NodeAlignProSettingsManager && typeof window.NodeAlignProSettingsManager.setNewVersionTips === 'function') { window.NodeAlignProSettingsManager.setNewVersionTips(value); } else __hNodeAlignPro_safeCall(null, null, 'newVersionTips', value); } catch (error) { console.error('设置新版说明失败:', error); } } }, { - id: "hNodeAlignPro.ColorApplyMode", name: h_i18n('Setting_ColorApplyMode','上色模式'), type: "combo", - options: [ { value: "1", text: h_i18n('Option_Color_Whole2','整体色') }, { value: "0", text: h_i18n('Option_Color_TitleOnly2','仅标题') } ], + id: "hNodeAlignPro.ColorApplyMode", name: h_i18n('Setting_ColorApplyMode', '上色模式'), type: "combo", + options: [{ value: "1", text: h_i18n('Option_Color_Whole2', '整体色') }, { value: "0", text: h_i18n('Option_Color_TitleOnly2', '仅标题') }], defaultValue: "1", - category: ["🔥 NodeAlignPro", "NodeAlignPro节点设置 (Node Settings)", h_i18n('Setting_ColorApplyMode','上色模式')], - tooltip: h_i18n('Setting_ColorApplyMode','设置节点上色模式:整体色(背景+标题)或仅标题色'), + category: ["🔥 NodeAlignPro", "🧩NodeAlignPro节点设置 (Node Settings)", h_i18n('Setting_ColorApplyMode', '上色模式')], + tooltip: h_i18n('Setting_ColorApplyMode', '设置节点上色模式:整体色(背景+标题)或仅标题色'), onChange: (value) => { try { const intVal = parseInt(value); if (window.NodeAlignProSettingsManager && typeof window.NodeAlignProSettingsManager.setColorApplyMode === 'function') { window.NodeAlignProSettingsManager.setColorApplyMode(intVal); } else __hNodeAlignPro_safeCall(null, null, 'colorApplyMode', intVal); } catch (error) { console.error('设置上色模式失败:', error); } } } ]; -// 初始化函数 +// 初始化函数-延迟执行,确保核心文件已加载:设置管理器会自动从localStorage加载设置 function initNodeAlignProSettings() { try { - setTimeout(() => { // 延迟执行,确保核心文件已加载 - if (window.NodeAlignProSettingsManager) { console.log('NodeAlignPro 设置系统已初始化'); if (window.hLog) hLog.info('--@hSetting', 'NodeAlignPro 设置系统已初始化'); } else console.warn('NodeAlignProSettingsManager 未找到,设置可能未完全加载'); // 设置管理器会自动从localStorage加载设置 - }, 2000); + setTimeout(() => { if (window.NodeAlignProSettingsManager) { console.log('NodeAlignPro 设置系统已初始化'); if (window.hLog) hLog.info('--@hSetting', 'NodeAlignPro 设置系统已初始化'); } else console.warn('NodeAlignProSettingsManager 未找到,设置可能未完全加载'); }, 2000); } catch (error) { console.error('初始化NodeAlignPro设置失败:', error); } } -// 注册扩展 +// 注册扩展-初始化代码 app.registerExtension({ - name: "NodeAlignPro.Settings", settings: NodeAlignProSettings, + name: "NodeAlignProSettings", setup() { - try { - // ComfyUI会自动注册通过`settings`字段传递的设置 - // 避免在此处手动调用addSetting,以防止重复注册错误 - initNodeAlignProSettings(); // 初始化设置管理器和相关回调 - console.info("[NodeAlignPro 设置模块] 已注册( NodeAlignPro.Settings)", NodeAlignProSettings.map(s => s.id)); - } catch (e) { console.error('[NodeAlignPro 设置模块] 初始化时发生异常( NodeAlignPro.Settings):', e); } - }, - beforeConfigureGraph(graph) { setTimeout(initNodeAlignProSettings, 2000); } // 延迟初始化,确保DOM已准备好 + NodeAlignProSettings.forEach(setting => { app.ui.settings.addSetting(setting); }); // 注册设置 + const useThemeColor = app.ui?.settings?.getSettingValue("hNodeAlignPro.hColor_AutoTtheme") || false; // 检查初始状态,如果主题配色功能已开启,则应用颜色并设置监听 + setTimeout(() => { useThemeColor ? (applyThemeColors(), setupThemeChangeListener()) : applyManualColors(); }, 500); // 如果未开启主题配色,应用手动设置的颜色 + } }); // 重置所有设置 function resetAllSettings() { try { - const defaultSettings = { - "hNodeAlignPro.ShowOperationLog": false, "hNodeAlignPro.hReset": false, "hNodeAlignPro.button_test": "测试文本", - "hNodeAlignPro.linkMode": "hDragMode1_Split", "hNodeAlignPro.UIScale": "hUIScale_1x", "hNodeAlignPro.UIScale_v2": "hUIScale_1x", - "hNodeAlignPro.WorkMode": "hApBar2_Align", "hNodeAlignPro.DisplayMode": "hDispMode0_Always", "hNodeAlignPro.hColor_SVG": "6B6B70", - "hNodeAlignPro.hColor_bg": "18181B", "hNodeAlignPro.hOpacity": 95, "hNodeAlignPro.NewVersionTips": true - }; - Object.keys(defaultSettings).forEach(settingId => { // 设置每个配置项到默认值 - try { app.ui.settings?.setSettingValue?.(settingId, defaultSettings[settingId]); } catch (e) { console.warn(`重置设置 ${settingId} 失败:`, e); } - }); + const defaultSettings = {}; // 从NodeAlignProSettings数组动态获取所有设置项的默认值 + NodeAlignProSettings.forEach(setting => { defaultSettings[setting.id] = setting.defaultValue; }); // 遍历所有设置项,收集默认值 + defaultSettings["hNodeAlignPro.hReset"] = false; // 添加特殊处理项确保重置选项本身被重置为false + Object.keys(defaultSettings).forEach(settingId => { try { app.ui.settings?.setSettingValue?.(settingId, defaultSettings[settingId]); } catch (e) { console.warn(`重置设置 ${settingId} 失败:`, e); } }); // 设置每个配置项到默认值 console.log('所有设置项已重置为默认值'); } catch (error) { console.error('重置设置项失败:', error); } } // 手动重置插件 function resetNodeAlignProManually() { try { - const container = document.getElementById('hNodeAlignKit'); // 重置容器位置和缩放 - if (container) container.style.transform = 'translate(0px, 0px) scale(1)', container.style.left = '', container.style.top = ''; - if (window.__hColor_Module) window.__hColor_Module.reset(); - if (window.__hMgr_DisplayMode) window.__hMgr_DisplayMode.reset(); - if (window.__hMgr_ACbar) window.__hMgr_ACbar.setLinkMode(0); + window.containerController?.reset() || (() => { const el = document.getElementById('hNodeAlignKit'); el && (el.style.left = '', el.style.top = ''); })(); // 优先使用容器控制器的reset方法,它已经实现了正确的位置重置逻辑 + window.__hColor_Module && window.__hColor_Module.reset(), window.__hMgr_DisplayMode && window.__hMgr_DisplayMode.reset(), window.__hMgr_ACbar && window.__hMgr_ACbar.setLinkMode(0); // 重置各个模块状态 console.log('NodeAlignPro 已手动重置'); } catch (error) { console.error('手动重置失败:', error); } } @@ -272,179 +458,4 @@ function clearAllStorage() { const storageKeys = ['NodeAlignPro_ShowOperationLog', 'NodeAlignPro_WorkMode', 'NodeAlignPro_AlignButtonColor', 'NodeAlignPro_ToolbarBgColor', 'NodeAlignPro_ToolbarOpacity', 'NodeAlignPro_NewVersionTips', 'NodeAlignPro_LinkMode', 'NodeAlignProPosition', 'NodeAlignProRunButtonLink', 'NodeAlignProDisplayMode', 'NodeAlignPro_ColorApplyMode', 'hNodeAlignPro_Logic']; storageKeys.forEach(key => { localStorage.removeItem(key); }); console.log('所有相关localStorage项已清除'); } catch (error) { console.error('清除localStorage失败:', error); } -} - -// 【== 节点对齐工具 ==】 -const __hNAP_AlignTools = { - // 左对齐(X轴) - hBtnA_alignLeft(e) { - if (__hIsNode2Mode()) { - const nodes = __hNode2_getSelectedNodes(); - if (nodes && nodes.length) { - const isAlt = !!(e && e.altKey); - // 找到基准节点:Alt+点击时使用最右侧节点的左边缘,否则使用最左侧节点的左边缘 - const refNode = isAlt ? nodes.reduce((maxNode, node) => { - const pos = __hNode2_getNodePos(node); - const maxPos = __hNode2_getNodePos(maxNode); - return (pos.x + __hNode2_getNodeSize(node).w) > (maxPos.x + __hNode2_getNodeSize(maxNode).w) ? node : maxNode; - }, nodes[0]) : nodes.reduce((minNode, node) => { - const pos = __hNode2_getNodePos(node); - const minPos = __hNode2_getNodePos(minNode); - return pos.x < minPos.x ? node : minNode; - }, nodes[0]); - - const refX = __hNode2_getNodePos(refNode).x; - const result = nodes.map(node => ({ - node: node, - newPos: { x: refX, y: __hNode2_getNodePos(node).y }, - newSize: __hNode2_getNodeSize(node) - })); - - if (window.app && window.app.canvas && typeof window.app.canvas.repositionNodesVueMode === 'function') { - window.app.canvas.repositionNodesVueMode(result); - return; - } - } - } - // 传统模式下的修复:确保Alt+点击时使用最右侧节点的左边缘 - __hNAP_AlignFc.handleAlign(e, 0, (nodes, isAlt) => { - if (isAlt) { - // 找到最右侧节点 - const rightmostNode = nodes.reduce((maxNode, node) => - (node.pos[0] + node.size[0]) > (maxNode.pos[0] + maxNode.size[0]) ? node : maxNode - , nodes[0]); - return rightmostNode.pos[0]; - } - return Math.min(...nodes.map(n => n.pos[0])); - }, (n, ref) => n.pos[0] = ref); - }, - - // 右对齐(X轴) - hBtnC_alignRight(e) { - if (__hIsNode2Mode()) { - const nodes = __hNode2_getSelectedNodes(); - if (nodes && nodes.length) { - const isAlt = !!(e && e.altKey); - // 找到基准节点:Alt+点击时使用最左侧节点的右边缘,否则使用最右侧节点的右边缘 - const refNode = isAlt ? nodes.reduce((minNode, node) => { - const pos = __hNode2_getNodePos(node); - const minPos = __hNode2_getNodePos(minNode); - return pos.x < minPos.x ? node : minNode; - }, nodes[0]) : nodes.reduce((maxNode, node) => { - const pos = __hNode2_getNodePos(node); - const maxPos = __hNode2_getNodePos(maxNode); - return (pos.x + __hNode2_getNodeSize(node).w) > (maxPos.x + __hNode2_getNodeSize(maxNode).w) ? node : maxNode; - }, nodes[0]); - - const refX = __hNode2_getNodePos(refNode).x + __hNode2_getNodeSize(refNode).w; - const result = nodes.map(node => ({ - node: node, - newPos: { x: refX - __hNode2_getNodeSize(node).w, y: __hNode2_getNodePos(node).y }, - newSize: __hNode2_getNodeSize(node) - })); - - if (window.app && window.app.canvas && typeof window.app.canvas.repositionNodesVueMode === 'function') { - window.app.canvas.repositionNodesVueMode(result); - return; - } - } - } - // 传统模式下的修复:确保Alt+点击时使用最左侧节点的右边缘 - __hNAP_AlignFc.handleAlign(e, 0, (nodes, isAlt) => { - if (isAlt) { - // 找到最左侧节点 - const leftmostNode = nodes.reduce((minNode, node) => - node.pos[0] < minNode.pos[0] ? node : minNode - , nodes[0]); - return leftmostNode.pos[0] + leftmostNode.size[0]; - } - return Math.max(...nodes.map(n => n.pos[0] + n.size[0])); - }, (n, ref) => n.pos[0] = ref - n.size[0]); - }, - - // 顶对齐(Y轴) - hBtnD_alignTop(e) { - if (__hIsNode2Mode()) { - const nodes = __hNode2_getSelectedNodes(); - if (nodes && nodes.length) { - const isAlt = !!(e && e.altKey); - // 找到基准节点:Alt+点击时使用最底部节点的上边缘,否则使用最顶部节点的上边缘 - const refNode = isAlt ? nodes.reduce((maxNode, node) => { - const pos = __hNode2_getNodePos(node); - const maxPos = __hNode2_getNodePos(maxNode); - return (pos.y + __hNode2_getNodeSize(node).h) > (maxPos.y + __hNode2_getNodeSize(maxNode).h) ? node : maxNode; - }, nodes[0]) : nodes.reduce((minNode, node) => { - const pos = __hNode2_getNodePos(node); - const minPos = __hNode2_getNodePos(minNode); - return pos.y < minPos.y ? node : minNode; - }, nodes[0]); - - const refY = __hNode2_getNodePos(refNode).y; - const result = nodes.map(node => ({ - node: node, - newPos: { x: __hNode2_getNodePos(node).x, y: refY }, - newSize: __hNode2_getNodeSize(node) - })); - - if (window.app && window.app.canvas && typeof window.app.canvas.repositionNodesVueMode === 'function') { - window.app.canvas.repositionNodesVueMode(result); - return; - } - } - } - // 传统模式下的修复:确保Alt+点击时使用最底部节点的上边缘 - __hNAP_AlignFc.handleAlign(e, 1, (nodes, isAlt) => { - if (isAlt) { - // 找到最底部节点 - const bottommostNode = nodes.reduce((maxNode, node) => - (node.pos[1] + node.size[1]) > (maxNode.pos[1] + maxNode.size[1]) ? node : maxNode - , nodes[0]); - return bottommostNode.pos[1]; - } - return Math.min(...nodes.map(n => n.pos[1])); - }, (n, ref) => n.pos[1] = ref); - }, - - // 底对齐(Y轴) - hBtnF_alignButton(e) { - if (__hIsNode2Mode()) { - const nodes = __hNode2_getSelectedNodes(); - if (nodes && nodes.length) { - const isAlt = !!(e && e.altKey); - // 找到基准节点:Alt+点击时使用最顶部节点的下边缘,否则使用最底部节点的下边缘 - const refNode = isAlt ? nodes.reduce((minNode, node) => { - const pos = __hNode2_getNodePos(node); - const minPos = __hNode2_getNodePos(minNode); - return pos.y < minPos.y ? node : minNode; - }, nodes[0]) : nodes.reduce((maxNode, node) => { - const pos = __hNode2_getNodePos(node); - const maxPos = __hNode2_getNodePos(maxNode); - return (pos.y + __hNode2_getNodeSize(node).h) > (maxPos.y + __hNode2_getNodeSize(maxNode).h) ? node : maxNode; - }, nodes[0]); - - const refY = __hNode2_getNodePos(refNode).y + __hNode2_getNodeSize(refNode).h; - const result = nodes.map(node => ({ - node: node, - newPos: { x: __hNode2_getNodePos(node).x, y: refY - __hNode2_getNodeSize(node).h }, - newSize: __hNode2_getNodeSize(node) - })); - - if (window.app && window.app.canvas && typeof window.app.canvas.repositionNodesVueMode === 'function') { - window.app.canvas.repositionNodesVueMode(result); - return; - } - } - } - // 传统模式下的修复:确保Alt+点击时使用最顶部节点的下边缘 - __hNAP_AlignFc.handleAlign(e, 1, (nodes, isAlt) => { - if (isAlt) { - // 找到最顶部节点 - const topmostNode = nodes.reduce((minNode, node) => - node.pos[1] < minNode.pos[1] ? node : minNode - , nodes[0]); - return topmostNode.pos[1] + topmostNode.size[1]; - } - return Math.max(...nodes.map(n => n.pos[1] + n.size[1])); - }, (n, ref) => n.pos[1] = ref - n.size[1]); - } -}; \ No newline at end of file +} \ No newline at end of file