Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a36de297f7 | ||
|
|
8cf4fd4ef7 | ||
|
|
f330f3dd7c | ||
|
|
155665721d | ||
|
|
f03a046a93 | ||
|
|
62a2029fe9 | ||
|
|
9fa5d1b3d9 | ||
|
|
4b8d36c51c | ||
|
|
106d1835fa | ||
|
|
a1f8cfbeb7 | ||
|
|
3db929b1bd | ||
|
|
7626bc6e99 | ||
|
|
c5869332ae | ||
|
|
01f56bfe06 | ||
|
|
9b913eecb8 | ||
|
|
e06bf54607 | ||
|
|
c9786121b1 | ||
|
|
0bbc93a39f | ||
|
|
5dcd58934d | ||
|
|
ff3b58c2e1 | ||
|
|
e53365fd2d | ||
|
|
fe3d4fc25e | ||
|
|
657230e8aa | ||
|
|
863f7cefef |
@@ -1,2 +1,19 @@
|
||||
# Auto detect text files and perform LF normalization
|
||||
# Set default behavior to automatically normalize line endings
|
||||
* text=auto
|
||||
|
||||
# Explicitly declare text files you want to always be normalized and converted
|
||||
*.md text
|
||||
*.py text
|
||||
*.js text
|
||||
*.css text
|
||||
*.html text
|
||||
|
||||
# Declare files that will always have CRLF line endings on checkout
|
||||
*.bat text eol=crlf
|
||||
|
||||
# Denote all files that are truly binary and should not be modified
|
||||
*.png binary
|
||||
*.jpg binary
|
||||
*.gif binary
|
||||
*.ico binary
|
||||
*.zip binary
|
||||
@@ -83,5 +83,13 @@ npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
|
||||
# AF speciffic
|
||||
Status.txt
|
||||
# Ruff cache
|
||||
.ruff_cache/
|
||||
|
||||
# AF specific
|
||||
Status.txt
|
||||
*.psd
|
||||
*.docx
|
||||
helpers/
|
||||
nodes.zip
|
||||
node.zip
|
||||
@@ -1,93 +1,171 @@
|
||||
# ****** ComfyUI-AF - Enhanced HTML-NOTE ******
|
||||
#
|
||||
# Creator: Alex Furer - Co-Creator(s): Claude AI & DeepSeek
|
||||
#
|
||||
# Praise, comment, bugs, improvements: https://github.com/alFrame/ComfyUI_AF_FindNodeByID
|
||||
#
|
||||
# LICENSE: MIT License
|
||||
#
|
||||
# v0.0.05
|
||||
#
|
||||
# Description:
|
||||
# A ComfyUI Note node with html capabilities. Create notes, UI's and ReadMe's directly inside the workflow, using html.
|
||||
#
|
||||
# Usage:
|
||||
# Read Me on Github
|
||||
#
|
||||
# Changelog:
|
||||
# v0.0.05
|
||||
# - Made edit mode less intrusive and keep ComfyUI canvas navigation (panning, zooming [space bar] and [H] now work to pan around the canvas)
|
||||
# v0.0.04
|
||||
# - Fixed node selection and resizing by removing OUTPUT_NODE and using proper widget approach
|
||||
# - Double clicking is now used to edit the html
|
||||
# - Mouse interaction is now persistent to ComfyUI behavior. Except middle mouse button for panning.
|
||||
# v0.0.03
|
||||
# - Fixed node resizing issues on save/reload
|
||||
# - Improved selection and edit mode behavior to match ComfyUI core notes
|
||||
# - Fixed middle mouse button panning over the node
|
||||
# - Improved HTML indentation in default content
|
||||
# v0.0.02
|
||||
# - Fixed naming consistency to HTML_Note
|
||||
# - Implemented single-window toggle behavior
|
||||
# v0.0.01
|
||||
# - Initial Version
|
||||
#
|
||||
|
||||
class AF_Enhanced_HTML_Note:
|
||||
"""
|
||||
AF Enhanced HTML-Note node with colored sections and rich formatting
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls):
|
||||
return {
|
||||
"required": {
|
||||
"html_content": ("STRING", {
|
||||
"multiline": True,
|
||||
"default": """<div class="af-section af-positive">
|
||||
<h2>🟢 Positive Prompts</h2>
|
||||
<p>Your positive prompts go here...</p>
|
||||
<a href="https://www.fullframestudios.ch" onclick="alert('Link clicked!')">Click me!</a>
|
||||
</div>
|
||||
|
||||
<div class="af-spacer"></div>
|
||||
|
||||
<div class="af-section af-negative">
|
||||
<h2>🔴 Negative Prompts</h2>
|
||||
<p>Your negative prompts go here...</p>
|
||||
</div>
|
||||
|
||||
<div class="af-spacer-large"></div>
|
||||
|
||||
<div class="af-section af-neutral">
|
||||
<h3>📝 Notes</h3>
|
||||
<p>Additional notes and information...</p>
|
||||
<ul>
|
||||
<li>Item 1</li>
|
||||
<li>Item 2</li>
|
||||
</ul>
|
||||
</div>""",
|
||||
"placeholder": "Enter your HTML content here..."
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
RETURN_TYPES = ()
|
||||
FUNCTION = "display_html"
|
||||
CATEGORY = "AF - Nodes"
|
||||
OUTPUT_NODE = False
|
||||
|
||||
def display_html(self, html_content):
|
||||
"""
|
||||
Display enhanced HTML content
|
||||
"""
|
||||
return {"ui": {"text": html_content}, "result": (html_content,)}
|
||||
|
||||
# Node mappings for ComfyUI
|
||||
NODE_CLASS_MAPPINGS = {
|
||||
"AF_Enhanced_HTML_Note": AF_Enhanced_HTML_Note,
|
||||
}
|
||||
|
||||
NODE_DISPLAY_NAME_MAPPINGS = {
|
||||
"AF_Enhanced_HTML_Note": "AF - Enhanced HTML Note",
|
||||
}
|
||||
# ****** ComfyUI-AF - Enhanced HTML-NOTE ******
|
||||
#
|
||||
# Creator: Alex Furer - Co-Creator(s): Claude AI & DeepSeek
|
||||
#
|
||||
# Description: A ComfyUI Note node with html capabilities. Create notes, UI's and ReadMe's directly inside the workflow, using html.
|
||||
#
|
||||
# Repo and ReadMe URL: https://github.com/alFrame/ComfyUI-AF-Enhanced-HTML-Note
|
||||
#
|
||||
# Issues praise, comment, bugs, improvements: https://github.com/alFrame/ComfyUI-AF-Enhanced-HTML-Note/issues
|
||||
#
|
||||
# LICENSE: MIT License
|
||||
#
|
||||
# Usage: https://github.com/alFrame/ComfyUI-AF-Enhanced-HTML-Note
|
||||
#
|
||||
# Feature Requests / Wet Dreams
|
||||
# -
|
||||
|
||||
class AF_Enhanced_HTML_Note:
|
||||
"""
|
||||
AF Enhanced HTML-Note node with colored sections and rich formatting
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls):
|
||||
return {
|
||||
"required": {
|
||||
"html_content": ("STRING", {
|
||||
"multiline": True,
|
||||
"default": """<h2>Positive Prompt Section</h2>
|
||||
<div class="af-section af-positive">
|
||||
<h2>🟢 Positive Prompts</h2>
|
||||
<p><strong>masterpiece, best quality, highly detailed</strong></p>
|
||||
<ul>
|
||||
<li>Professional lighting</li>
|
||||
<li>Sharp focus</li>
|
||||
<li>8K resolution</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
|
||||
<h2>Negative Prompt Section</h2>
|
||||
<div class="af-section af-negative">
|
||||
<h2>🔴 Negative Prompts</h2>
|
||||
<p><em>low quality, blurry, distorted</em></p>
|
||||
<p><code>nsfw, watermark, signature, bad anatomy</code></p>
|
||||
</div>
|
||||
|
||||
|
||||
<h2>Neutral Prompt Section</h2>
|
||||
<div class="af-section af-neutral">
|
||||
<h3>📝 Notes</h3>
|
||||
<p>General notes and information...</p>
|
||||
<ul>
|
||||
<li>Item 1</li>
|
||||
<li>Item 2</li>
|
||||
<li>Item 3</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<h2>Info Section</h2>
|
||||
<div class="af-section af-info">
|
||||
<h3>ℹ️ Information</h3>
|
||||
<p>Using: <strong>SDXL 1.0</strong></p>
|
||||
<p>Steps: <code>25</code> | CFG: <code>7.5</code> | Sampler: <code>DPM++ 2M Karras</code></p>
|
||||
</div>
|
||||
|
||||
<h2>Warning Section</h2>
|
||||
<div class="af-section af-warning">
|
||||
<h3>⚠️ Warning</h3>
|
||||
<p>This workflow requires:</p>
|
||||
<ol>
|
||||
<li>High VRAM (8GB+)</li>
|
||||
<li>Latest ComfyUI version</li>
|
||||
<li>SDXL compatible models</li>
|
||||
</ol>
|
||||
</div>
|
||||
|
||||
<h2>Column Layouts</h2>
|
||||
<div class="row">
|
||||
<div class="af-column-half-left">
|
||||
<div class="af-section af-positive">
|
||||
<h3>🎨 Style Settings</h3>
|
||||
<ul>
|
||||
<li>Style: Photorealistic</li>
|
||||
<li>Aspect: 16:9</li>
|
||||
<li>Quality: Ultra High</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="af-spacer"></div>
|
||||
|
||||
<div class="af-section af-info">
|
||||
<h3>⚙️ Technical</h3>
|
||||
<p>Resolution: <code>1920x1080</code></p>
|
||||
<p>Batch: <code>4</code></p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="af-column-half-right">
|
||||
<div class="af-section af-negative">
|
||||
<h3>🚫 Exclusions</h3>
|
||||
<ul>
|
||||
<li>No text in image</li>
|
||||
<li>Avoid oversaturation</li>
|
||||
<li>No watermarks</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="af-spacer"></div>
|
||||
|
||||
<div class="af-section af-warning">
|
||||
<h3>💡 Tips</h3>
|
||||
<p>Use lower CFG for more creative results</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h2>Clickable Links & Actions</h2>
|
||||
<div class="af-section af-info">
|
||||
<h3>🔗 Interactive Links</h3>
|
||||
|
||||
<!-- External links (opens in new tab with Ctrl+click) -->
|
||||
<h4>External link (opens in new tab with Ctrl+click)</h4>
|
||||
<p><a href="https://www.fullframestudios.ch/">Full Frame Studios - Alex Furer</a></p>
|
||||
|
||||
<h4>Anchor Links</h4>
|
||||
<p><a href="https://www.fullframestudios.ch/#ThreeDee">Full Frame Studios - Alex Furer - 3D</a></p>
|
||||
</div>
|
||||
|
||||
<h2>Custom Info Cards</h2>
|
||||
<div style="display: flex; gap: 10px; flex-wrap: wrap;">
|
||||
<div style="flex: 1; min-width: 150px; background: rgba(144, 238, 144, 0.1); border: 1px solid #90EE90; padding: 12px; border-radius: 6px; text-align: center;">
|
||||
<strong style="color: #90EE90; display: block; margin-bottom: 4px;">Steps</strong>
|
||||
<p style="margin: 0; font-size: 24px; color: #fff; font-weight: bold;">25</p>
|
||||
</div>
|
||||
|
||||
<div style="flex: 1; min-width: 150px; background: rgba(135, 206, 235, 0.1); border: 1px solid #87CEEB; padding: 12px; border-radius: 6px; text-align: center;">
|
||||
<strong style="color: #87CEEB; display: block; margin-bottom: 4px;">CFG Scale</strong>
|
||||
<p style="margin: 0; font-size: 24px; color: #fff; font-weight: bold;">7.5</p>
|
||||
</div>
|
||||
|
||||
<div style="flex: 1; min-width: 150px; background: rgba(186, 85, 211, 0.1); border: 1px solid #BA55D3; padding: 12px; border-radius: 6px; text-align: center;">
|
||||
<strong style="color: #BA55D3; display: block; margin-bottom: 4px;">Batch Size</strong>
|
||||
<p style="margin: 0; font-size: 24px; color: #fff; font-weight: bold;">4</p>
|
||||
</div>
|
||||
</div>""",
|
||||
"placeholder": "Enter your HTML content here..."
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
RETURN_TYPES = ()
|
||||
FUNCTION = "display_html"
|
||||
CATEGORY = "AF - Nodes/AF - HTML Pack"
|
||||
OUTPUT_NODE = False
|
||||
|
||||
def display_html(self, html_content):
|
||||
"""
|
||||
Display enhanced HTML content
|
||||
"""
|
||||
return {"ui": {"text": html_content}, "result": (html_content,)}
|
||||
|
||||
# Node mappings for ComfyUI
|
||||
NODE_CLASS_MAPPINGS = {
|
||||
"AF_Enhanced_HTML_Note": AF_Enhanced_HTML_Note,
|
||||
}
|
||||
|
||||
NODE_DISPLAY_NAME_MAPPINGS = {
|
||||
"AF_Enhanced_HTML_Note": "AF - Enhanced HTML Note",
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
## Changelog
|
||||
|
||||
### v0.0.12
|
||||
- Updated the README. Explained the limitation of the middle mouse ComfyUI panning being blocked by the node
|
||||
- Changed the ComfyUI category for cleanliness and standardization
|
||||
|
||||
### v0.0.11
|
||||
- Changed Icon location to my own website as the ComfyUI Registry botched out on any GitHub URL I tried...
|
||||
|
||||
### v0.0.10
|
||||
- Updated the README (CSS file editing)
|
||||
|
||||
### v0.0.09
|
||||
- Added nodes.py and node.js for ComfyUI registry and Manager compliance
|
||||
- Made sure the repo name change from "ComfyUI-AF-Enhanced_HTML_Note" to "ComfyUI-AF-Enhanced-HTML-Note" is consistent for all links and such
|
||||
|
||||
### v0.0.08
|
||||
- Moved the CSS from the JS file to it's own file.
|
||||
- Added CHANGELOG.md
|
||||
- Added package.json for ComfyUI Manager compliance
|
||||
- Added pyproject.toml for registry compliance
|
||||
- Reworked the README
|
||||
- Added the "helpers" folder to the .gitignore
|
||||
- Added an icon to the pyproject.toml
|
||||
|
||||
### v0.0.07
|
||||
- Comsetics, making tis a version
|
||||
|
||||
### v0.0.06
|
||||
- Removed all Java Script functionality for links and updated README
|
||||
|
||||
### v0.0.05
|
||||
- Made edit mode less intrusive and keep ComfyUI canvas navigation (panning, zooming [space bar] and [H] now work to pan around the canvas)
|
||||
|
||||
### v0.0.04
|
||||
- Fixed node selection and resizing by removing OUTPUT_NODE and using proper widget approach. Double clicking is now used to edit the html Mouse interaction is now persistent to ComfyUI behavior. Except middle mouse button for panning.
|
||||
|
||||
### v0.0.03
|
||||
- Fixed node resizing issues on save/reload. Improved selection and edit mode behavior to match ComfyUI core notes. Fixed middle mouse button panning over the node. Improved HTML indentation in default content
|
||||
|
||||
### v0.0.02
|
||||
- Fixed naming consistency to HTML_Note Implemented single-window toggle behavior
|
||||
|
||||
### v0.0.01
|
||||
- Initial Version
|
||||
|
After Width: | Height: | Size: 22 KiB |
|
After Width: | Height: | Size: 68 KiB |
|
After Width: | Height: | Size: 39 KiB |
|
After Width: | Height: | Size: 22 KiB |
|
After Width: | Height: | Size: 33 KiB |
|
After Width: | Height: | Size: 30 KiB |
|
After Width: | Height: | Size: 22 KiB |
|
After Width: | Height: | Size: 28 KiB |
|
After Width: | Height: | Size: 26 KiB |
|
After Width: | Height: | Size: 23 KiB |
|
After Width: | Height: | Size: 26 KiB |
|
After Width: | Height: | Size: 24 KiB |
|
After Width: | Height: | Size: 22 KiB |
|
After Width: | Height: | Size: 25 KiB |
|
After Width: | Height: | Size: 35 KiB |
|
After Width: | Height: | Size: 31 KiB |
|
After Width: | Height: | Size: 25 KiB |
|
After Width: | Height: | Size: 23 KiB |
|
After Width: | Height: | Size: 7.7 KiB |
@@ -1,15 +1,44 @@
|
||||
# AF Enhanced HTML Node - Usage Guide
|
||||
# AF Enhanced HTML Node - Complete Usage Guide
|
||||
|
||||
A ComfyUI Note node with HTML capabilities. Create notes, UI's and ReadMe's directly inside the workflow using rich HTML formatting.
|
||||
|
||||
---
|
||||
|
||||
## ✨ Key Features
|
||||
|
||||
- **Rich HTML Support** - Full HTML formatting with colored sections, lists, tables, code blocks, and more
|
||||
- **Non-Intrusive Design** - Doesn't interfere with normal ComfyUI workflow interactions
|
||||
- **Easy Editing** - Double-click anywhere on the content to edit HTML
|
||||
- **Smart Links** - Ctrl+click to open external links or trigger custom actions
|
||||
- **Smart Links** - Ctrl+click to open external links (JavaScript disabled for security)
|
||||
- **Beautiful Styling** - Predefined color schemes that match ComfyUI's theme
|
||||
- **No Dependencies** - All CSS is inlined for reliable performance
|
||||
- **Custom HTML Support** - Write your own HTML with inline styles or customize the external CSS file
|
||||
|
||||
## ⚠️ Known Limitation: Middle Mouse Button Panning
|
||||
|
||||
**Issue:** Middle mouse button panning does not work when the cursor is over this node.
|
||||
|
||||
**Workaround:** Use the hand tool by pressing `Space` on your keyboard, or pan from outside the node area.
|
||||
|
||||
**Technical Context:** Since this node renders HTML content, the browser intercepts middle mouse button events before they can reach the ComfyUI canvas. Despite multiple attempts to capture and forward these events to the underlying canvas, browser security and event handling policies prevent a reliable solution.
|
||||
|
||||
If you have ideas for resolving this limitation, please open an [issue](https://github.com/alFrame/ComfyUI-AF-Enhanced-HTML-Note/issues) on the repository.
|
||||
|
||||
---
|
||||
|
||||
## 🛠️ Installation
|
||||
|
||||
### Via ComfyUI Manager (Recommended)
|
||||
1. Open ComfyUI Manager
|
||||
2. Search for "AF - Enhanced HTML Note"
|
||||
3. Install
|
||||
|
||||
### Manual Installation
|
||||
1. Clone this repository into your `ComfyUI/custom_nodes/` directory:
|
||||
```bash
|
||||
git clone https://github.com/alFrame/ComfyUI-AF-Enhanced-HTML-Note.git
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🎮 Interaction Guide
|
||||
|
||||
@@ -21,81 +50,65 @@ A ComfyUI Note node with HTML capabilities. Create notes, UI's and ReadMe's dire
|
||||
### Using Links
|
||||
- **Hold Control key + Click** on any link to activate it
|
||||
- External links open in new tabs
|
||||
- JavaScript actions and alerts work when Control is held
|
||||
- JavaScript execution is disabled for security
|
||||
|
||||
### Node Management
|
||||
- **Click and drag** the node title bar to move
|
||||
- **Drag edges/corners** to resize
|
||||
- **Middle mouse button** works for canvas panning (like other nodes)
|
||||
|
||||
## 🎨 Basic Section Colors
|
||||
---
|
||||
|
||||
## 🎨 Custom CSS Styling
|
||||
|
||||
The node uses an external CSS file (`AF-Enhanced-HTML-Note.css`) that you can customize to match your preferences or create your own styling themes.
|
||||
|
||||
### Editing the CSS
|
||||
|
||||
The CSS file is located at:
|
||||
```
|
||||
ComfyUI/custom_nodes/ComfyUI-AF-Enhanced-HTML-Note/web/AF-Enhanced-HTML-Note.css
|
||||
```
|
||||
|
||||
You can edit this file directly to:
|
||||
- Change colors of predefined sections (`.af-positive`, `.af-negative`, etc.)
|
||||
- Modify spacing and padding
|
||||
- Adjust font sizes and typography
|
||||
- Create new custom section classes
|
||||
- Change scrollbar styling
|
||||
- Customize the edit button appearance
|
||||
- OR **completely** replace the entire CSS and use your own classes. (Don't forget to change the classes in the HTML node in your ComfyUI workflow !!)
|
||||
|
||||
### Example: Creating a Custom Section Color
|
||||
|
||||
Add this to the CSS file to create a new teal section style:
|
||||
```css
|
||||
.af-html-note-content .af-section.af-teal {
|
||||
background: rgba(64, 224, 208, 0.1);
|
||||
border-left-color: #40E0D0;
|
||||
}
|
||||
```
|
||||
|
||||
Then use it in your HTML:
|
||||
```html
|
||||
<!-- Positive section (green) -->
|
||||
<div class="af-section af-positive">
|
||||
<h2>🟢 Positive Prompts</h2>
|
||||
<p>Your positive prompts go here...</p>
|
||||
</div>
|
||||
|
||||
<!-- Negative section (red) -->
|
||||
<div class="af-section af-negative">
|
||||
<h2>🔴 Negative Prompts</h2>
|
||||
<p>Your negative prompts go here...</p>
|
||||
</div>
|
||||
|
||||
<!-- Neutral section (gray) -->
|
||||
<div class="af-section af-neutral">
|
||||
<h3>📝 Notes</h3>
|
||||
<p>General notes and information...</p>
|
||||
</div>
|
||||
|
||||
<!-- Info section (blue) -->
|
||||
<div class="af-section af-info">
|
||||
<h3>ℹ️ Information</h3>
|
||||
<p>Important information...</p>
|
||||
</div>
|
||||
|
||||
<!-- Warning section (yellow) -->
|
||||
<div class="af-section af-warning">
|
||||
<h3>⚠️ Warning</h3>
|
||||
<p>Warning or caution messages...</p>
|
||||
</div>
|
||||
|
||||
<!-- Custom section (purple) -->
|
||||
<div class="af-section af-custom">
|
||||
<h3>🎨 Custom</h3>
|
||||
<p>Custom styled content...</p>
|
||||
<div class="af-section af-teal">
|
||||
<h3>🟢 Teal Section</h3>
|
||||
<p>Your custom styled content...</p>
|
||||
</div>
|
||||
```
|
||||
## 📐 Spacers
|
||||
```html
|
||||
<!-- Small spacer -->
|
||||
<div class="af-spacer-small"></div>
|
||||
|
||||
<!-- Regular spacer -->
|
||||
<div class="af-spacer"></div>
|
||||
**Note:** After editing the CSS file, refresh your browser (Ctrl+F5 or Cmd+Shift+R) to see the changes.
|
||||
|
||||
<!-- Large spacer -->
|
||||
<div class="af-spacer-large"></div>
|
||||
---
|
||||
|
||||
<!-- Extra large spacer -->
|
||||
<div class="af-spacer-xl"></div>
|
||||
## 🎨 Predefined Section Colors
|
||||
|
||||
#🔗 Clickable Links & Actions
|
||||
The node comes with several predefined colored section styles. Click each section below to see the code and rendered example.
|
||||
|
||||
<!-- External link (opens in new tab with Ctrl+click) -->
|
||||
<a href="https://github.com/comfyanonymous/ComfyUI">ComfyUI GitHub</a>
|
||||
<details>
|
||||
<summary><b>🟢 Positive Section (Green)</b></summary>
|
||||
|
||||
<!-- Alert action (triggers with Ctrl+click) -->
|
||||
<a href="#" onclick="alert('Custom action triggered!')">Click for alert</a>
|
||||
|
||||
<!-- Multiple actions -->
|
||||
<a href="https://example.com" onclick="console.log('Link clicked')">Link with multiple actions</a>
|
||||
|
||||
<!-- JavaScript links -->
|
||||
<a href="javascript:alert('Hello!')">JavaScript link</a>
|
||||
```
|
||||
## 📋 Complete Example Template
|
||||
### Code:
|
||||
```html
|
||||
<div class="af-section af-positive">
|
||||
<h2>🟢 Positive Prompts</h2>
|
||||
@@ -105,30 +118,76 @@ A ComfyUI Note node with HTML capabilities. Create notes, UI's and ReadMe's dire
|
||||
<li>Sharp focus</li>
|
||||
<li>8K resolution</li>
|
||||
</ul>
|
||||
<a href="#" onclick="alert('Positive prompts copied!')">📋 Copy Prompts</a>
|
||||
</div>
|
||||
```
|
||||
|
||||
<div class="af-spacer"></div>
|
||||
### Rendered Result:
|
||||

|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><b>🔴 Negative Section (Red)</b></summary>
|
||||
|
||||
### Code:
|
||||
```html
|
||||
<div class="af-section af-negative">
|
||||
<h2>🔴 Negative Prompts</h2>
|
||||
<p><em>low quality, blurry, distorted</em></p>
|
||||
<code>nsfw, watermark, signature, bad anatomy</code>
|
||||
<p><code>nsfw, watermark, signature, bad anatomy</code></p>
|
||||
</div>
|
||||
```
|
||||
|
||||
<div class="af-spacer-large"></div>
|
||||
### Rendered Result:
|
||||

|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><b>📝 Neutral Section (Gray)</b></summary>
|
||||
|
||||
### Code:
|
||||
```html
|
||||
<div class="af-section af-neutral">
|
||||
<h3>📝 Notes</h3>
|
||||
<p>General notes and information...</p>
|
||||
<ul>
|
||||
<li>Item 1</li>
|
||||
<li>Item 2</li>
|
||||
<li>Item 3</li>
|
||||
</ul>
|
||||
</div>
|
||||
```
|
||||
|
||||
### Rendered Result:
|
||||

|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><b>ℹ️ Info Section (Light Blue)</b></summary>
|
||||
|
||||
### Code:
|
||||
```html
|
||||
<div class="af-section af-info">
|
||||
<h3>ℹ️ Model Information</h3>
|
||||
<h3>ℹ️ Information</h3>
|
||||
<p>Using: <strong>SDXL 1.0</strong></p>
|
||||
<p>Steps: <code>25</code> | CFG: <code>7.5</code> | Sampler: <code>DPM++ 2M Karras</code></p>
|
||||
<a href="https://huggingface.co/stabilityai/stable-diffusion-xl-base-1.0">Model Page</a>
|
||||
</div>
|
||||
```
|
||||
|
||||
<div class="af-spacer"></div>
|
||||
### Rendered Result:
|
||||

|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><b>⚠️ Warning Section (Yellow)</b></summary>
|
||||
|
||||
### Code:
|
||||
```html
|
||||
<div class="af-section af-warning">
|
||||
<h3>⚠️ Important Notes</h3>
|
||||
<h3>⚠️ Warning</h3>
|
||||
<p>This workflow requires:</p>
|
||||
<ol>
|
||||
<li>High VRAM (8GB+)</li>
|
||||
@@ -136,69 +195,598 @@ A ComfyUI Note node with HTML capabilities. Create notes, UI's and ReadMe's dire
|
||||
<li>SDXL compatible models</li>
|
||||
</ol>
|
||||
</div>
|
||||
```
|
||||
|
||||
### Rendered Result:
|
||||

|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><b>💛 Yellow Section (Alternative)</b></summary>
|
||||
|
||||
### Code:
|
||||
```html
|
||||
<div class="af-section af-yellow">
|
||||
<h3>💛 Yellow Section</h3>
|
||||
<p>Alternative yellow styled content with different shade...</p>
|
||||
</div>
|
||||
```
|
||||
|
||||
### Rendered Result:
|
||||

|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><b>🔵 Blue Section (Deep Blue)</b></summary>
|
||||
|
||||
### Code:
|
||||
```html
|
||||
<div class="af-section af-blue">
|
||||
<h3>🔵 Blue Section</h3>
|
||||
<p>Deep blue styled content for technical information...</p>
|
||||
</div>
|
||||
```
|
||||
|
||||
### Rendered Result:
|
||||

|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><b>🎨 Custom Section (Purple)</b></summary>
|
||||
|
||||
### Code:
|
||||
```html
|
||||
<div class="af-section af-custom">
|
||||
<h3>🎨 Custom</h3>
|
||||
<p>Purple custom styled content for special cases...</p>
|
||||
</div>
|
||||
```
|
||||
|
||||
### Rendered Result:
|
||||

|
||||
|
||||
</details>
|
||||
|
||||
---
|
||||
|
||||
## 📏 Predefined Spacers
|
||||
|
||||
Use these spacer classes to control vertical spacing between elements.
|
||||
|
||||
<details>
|
||||
<summary><b>All Spacer Sizes</b> - Click to see examples</summary>
|
||||
|
||||
### Code:
|
||||
```html
|
||||
<div class="af-section af-positive">Content Block 1</div>
|
||||
|
||||
<!-- Top spacer (2px) -->
|
||||
<div class="af-spacer-top"></div>
|
||||
|
||||
<div class="af-section af-negative">Content Block 2</div>
|
||||
|
||||
<!-- Mini spacer (4px) -->
|
||||
<div class="af-spacer-mini"></div>
|
||||
|
||||
<div class="af-section af-neutral">Content Block 3</div>
|
||||
|
||||
<!-- Small spacer (8px) -->
|
||||
<div class="af-spacer-small"></div>
|
||||
|
||||
<div class="af-section af-info">Content Block 4</div>
|
||||
|
||||
<!-- Regular spacer (16px) -->
|
||||
<div class="af-spacer"></div>
|
||||
|
||||
<div class="af-section af-warning">Content Block 5</div>
|
||||
|
||||
<!-- Large spacer (32px) -->
|
||||
<div class="af-spacer-large"></div>
|
||||
|
||||
<div class="af-section af-custom">Content Block 6</div>
|
||||
|
||||
<!-- Extra large spacer (48px) -->
|
||||
<div class="af-spacer-xl"></div>
|
||||
|
||||
<div class="af-section af-blue">Content Block 7</div>
|
||||
```
|
||||
|
||||
### Rendered Result:
|
||||

|
||||
|
||||
### Size Reference:
|
||||
- `af-spacer-top` → 2px
|
||||
- `af-spacer-mini` → 4px
|
||||
- `af-spacer-small` → 8px
|
||||
- `af-spacer` → 16px (default)
|
||||
- `af-spacer-large` → 32px
|
||||
- `af-spacer-xl` → 48px
|
||||
|
||||
</details>
|
||||
|
||||
---
|
||||
|
||||
## 📐 Column Layouts
|
||||
|
||||
Create two-column layouts using the predefined column classes.
|
||||
|
||||
<details>
|
||||
<summary><b>Two-Column Layout Example</b></summary>
|
||||
|
||||
### Code:
|
||||
```html
|
||||
<div class="row">
|
||||
<div class="af-column-half-left">
|
||||
<div class="af-section af-positive">
|
||||
<h3>🎨 Style Settings</h3>
|
||||
<ul>
|
||||
<li>Style: Photorealistic</li>
|
||||
<li>Aspect: 16:9</li>
|
||||
<li>Quality: Ultra High</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="af-spacer"></div>
|
||||
|
||||
<div class="af-section af-info">
|
||||
<h3>⚙️ Technical</h3>
|
||||
<p>Resolution: <code>1920x1080</code></p>
|
||||
<p>Batch: <code>4</code></p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="af-column-half-right">
|
||||
<div class="af-section af-negative">
|
||||
<h3>🚫 Exclusions</h3>
|
||||
<ul>
|
||||
<li>No text in image</li>
|
||||
<li>Avoid oversaturation</li>
|
||||
<li>No watermarks</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="af-spacer"></div>
|
||||
|
||||
<div class="af-section af-warning">
|
||||
<h3>💡 Tips</h3>
|
||||
<p>Use lower CFG for more creative results</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
```
|
||||
|
||||
### Rendered Result:
|
||||

|
||||
|
||||
**Note:** The `row` class ensures proper column wrapping, and each column is 49% width with 1% margin.
|
||||
|
||||
</details>
|
||||
|
||||
---
|
||||
|
||||
## 🔗 Clickable Links & Actions
|
||||
|
||||
All links require **Ctrl+Click** to activate for safety and to prevent accidental navigation. JavaScript actions work on links when Ctrl+Click is used.
|
||||
|
||||
<details>
|
||||
<summary><b>Link Examples</b></summary>
|
||||
|
||||
### Code:
|
||||
```html
|
||||
<div class="af-section af-info">
|
||||
<h3>🔗 Interactive Links</h3>
|
||||
|
||||
<!-- External link (opens in new tab with Ctrl+click) -->
|
||||
<p><a href="https://github.com/comfyanonymous/ComfyUI">ComfyUI GitHub Repository</a></p>
|
||||
|
||||
<!-- Anchor link (page navigation with Ctrl+click) -->
|
||||
<p><a href="#section-name">Jump to section</a></p>
|
||||
|
||||
<!-- Mailto link (opens email client with Ctrl+click) -->
|
||||
<p><a href="mailto:example@domain.com">Send Email</a></p>
|
||||
|
||||
<!-- Relative URL (opens in new tab with Ctrl+click) -->
|
||||
<p><a href="docs/page.html">Documentation</a></p>
|
||||
</div>
|
||||
```
|
||||
|
||||
**Remember:** Hold **Ctrl** while clicking any link to activate it!
|
||||
|
||||
### Rendered Result:
|
||||

|
||||
|
||||
</details>
|
||||
|
||||
### Supported Link Types:
|
||||
- ✅ **External URLs** (`https://`, `http://`) - Open in new tab
|
||||
- ✅ **Anchor links** (`#section`) - Page navigation
|
||||
- ✅ **Mailto links** (`mailto:`) - Open email client
|
||||
- ✅ **Tel links** (`tel:`) - Open phone app
|
||||
- ✅ **Relative URLs** - Open in new tab
|
||||
|
||||
### Not Supported Link Types:
|
||||
- ❌ **JavaScript links** (`javascript:`) - Blocked for security
|
||||
- ❌ **onclick handlers** - Ignored for security
|
||||
|
||||
### Security Restrictions:
|
||||
- **No JavaScript execution** - All JavaScript is blocked for security
|
||||
- **No `<script>` tags** - Script tags are not executed
|
||||
- **No external scripts** - Cannot load external JavaScript files
|
||||
- **Ctrl+Click required** - All link interactions require Control key
|
||||
- **Safe HTML only** - Only styling and navigation features are supported
|
||||
- **No DOM manipulation** - JavaScript cannot modify the HTML content
|
||||
- **No browser storage** - `localStorage` and `sessionStorage` are blocked
|
||||
|
||||
---
|
||||
|
||||
## 💻 Custom HTML & Inline Styles
|
||||
|
||||
The node supports **standard HTML** with **inline CSS styling**. You can write custom HTML just like you would for a webpage.
|
||||
|
||||
### ✅ Supported Features
|
||||
|
||||
- **All standard HTML tags**: `<div>`, `<span>`, `<p>`, `<h1>`-`<h6>`, `<ul>`, `<ol>`, `<li>`, `<table>`, etc.
|
||||
- **Inline CSS styles**: Use the `style` attribute on any element
|
||||
- **Text formatting**: `<strong>`, `<em>`, `<u>`, `<small>`, `<code>`, `<pre>`
|
||||
- **Lists**: Ordered and unordered lists
|
||||
- **Tables**: Full table support with styling
|
||||
- **Horizontal rules**: `<hr>` for dividers
|
||||
- **Code blocks**: `<code>` and `<pre>` tags
|
||||
|
||||
---
|
||||
|
||||
## 🎨 Custom Styling Examples
|
||||
|
||||
<details>
|
||||
<summary><b>Custom Spacers with Inline Styles</b></summary>
|
||||
|
||||
### Code:
|
||||
```html
|
||||
<div class="af-section af-positive">First Section</div>
|
||||
|
||||
<!-- Custom 12px spacer -->
|
||||
<div style="height: 12px;"></div>
|
||||
|
||||
<div class="af-section af-negative">Second Section</div>
|
||||
|
||||
<!-- Custom 24px spacer -->
|
||||
<div style="height: 24px;"></div>
|
||||
|
||||
<div class="af-section af-info">Third Section</div>
|
||||
|
||||
<!-- Custom 50px spacer -->
|
||||
<div style="height: 50px;"></div>
|
||||
|
||||
<div class="af-section af-warning">Fourth Section</div>
|
||||
```
|
||||
|
||||
### Rendered Result:
|
||||

|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><b>Custom Colored Sections</b></summary>
|
||||
|
||||
### Code:
|
||||
```html
|
||||
<!-- Custom pink section -->
|
||||
<div style="background: rgba(255, 100, 150, 0.1); border-left: 4px solid #ff6496; padding: 12px; border-radius: 6px; margin: 8px 0;">
|
||||
<h3 style="color: #ff6496; margin-top: 0;">Custom Pink Section</h3>
|
||||
<p>Your content here with custom colors...</p>
|
||||
</div>
|
||||
|
||||
<!-- Custom teal section -->
|
||||
<div style="background: rgba(64, 224, 208, 0.1); border-left: 4px solid #40E0D0; padding: 12px; border-radius: 6px; margin: 8px 0;">
|
||||
<h3 style="color: #40E0D0; margin-top: 0;">Custom Teal Section</h3>
|
||||
<p>Different color scheme for variety...</p>
|
||||
</div>
|
||||
|
||||
<!-- Custom orange section -->
|
||||
<div style="background: rgba(255, 165, 0, 0.1); border-left: 4px solid #FFA500; padding: 12px; border-radius: 6px; margin: 8px 0;">
|
||||
<h3 style="color: #FFA500; margin-top: 0;">Custom Orange Section</h3>
|
||||
<p>Create any color combination you need...</p>
|
||||
</div>
|
||||
```
|
||||
|
||||
### Rendered Result:
|
||||

|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><b>Custom Text Styling</b></summary>
|
||||
|
||||
### Code:
|
||||
```html
|
||||
<div class="af-section af-neutral">
|
||||
<!-- Large blue bold text -->
|
||||
<p style="font-size: 18px; color: #58a6ff; font-weight: bold;">
|
||||
Large blue bold text for emphasis
|
||||
</p>
|
||||
|
||||
<!-- Small gray italic text -->
|
||||
<p style="font-size: 12px; color: #888; font-style: italic;">
|
||||
Small gray italic text for subtitles
|
||||
</p>
|
||||
|
||||
<!-- Highlighted text -->
|
||||
<p style="background: rgba(255, 255, 0, 0.2); padding: 4px 8px; border-radius: 3px;">
|
||||
Highlighted text with yellow background
|
||||
</p>
|
||||
|
||||
<!-- Custom monospace -->
|
||||
<p style="font-family: 'Courier New', monospace; color: #90EE90; background: rgba(0,0,0,0.4); padding: 8px; border-radius: 4px;">
|
||||
Custom monospace text for code-like display
|
||||
</p>
|
||||
</div>
|
||||
```
|
||||
|
||||
### Rendered Result:
|
||||

|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><b>Custom Borders and Boxes</b></summary>
|
||||
|
||||
### Code:
|
||||
```html
|
||||
<!-- Dashed border box -->
|
||||
<div style="border: 2px dashed #90EE90; padding: 16px; margin: 10px 0; background: rgba(0, 0, 0, 0.2); border-radius: 8px;">
|
||||
<p><strong>Dashed Border Box</strong></p>
|
||||
<p>Content in a custom dashed border box</p>
|
||||
</div>
|
||||
|
||||
<!-- Solid border with shadow effect -->
|
||||
<div style="border: 2px solid #58a6ff; padding: 16px; margin: 10px 0; background: rgba(88, 166, 255, 0.05); box-shadow: 0 4px 8px rgba(0,0,0,0.3); border-radius: 8px;">
|
||||
<p><strong>Solid Border with Shadow</strong></p>
|
||||
<p>Creates depth with shadow effect</p>
|
||||
</div>
|
||||
|
||||
<!-- Thick left border -->
|
||||
<div style="border-left: 8px solid #BA55D3; padding: 16px; margin: 10px 0; background: rgba(186, 85, 211, 0.1);">
|
||||
<p><strong>Thick Left Border</strong></p>
|
||||
<p>Emphasizes content with thick accent border</p>
|
||||
</div>
|
||||
```
|
||||
|
||||
### Rendered Result:
|
||||

|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><b>Custom Layouts and Alignment</b></summary>
|
||||
|
||||
### Code:
|
||||
```html
|
||||
<!-- Centered content -->
|
||||
<div style="text-align: center; padding: 20px; background: rgba(255,255,255,0.05); border-radius: 8px; margin: 10px 0;">
|
||||
<h2 style="margin: 0 0 12px 0;">Centered Title</h2>
|
||||
<p style="margin: 0;">Centered paragraph text for announcements</p>
|
||||
</div>
|
||||
|
||||
<!-- Right-aligned content -->
|
||||
<div style="text-align: right; padding: 10px; border-top: 1px solid #555; margin-top: 20px;">
|
||||
<small style="color: #888;">Right-aligned footer note</small>
|
||||
</div>
|
||||
|
||||
<!-- Flex layout for inline elements -->
|
||||
<div style="display: flex; gap: 10px; align-items: center; padding: 12px; background: rgba(0,0,0,0.2); border-radius: 6px;">
|
||||
<span style="background: #90EE90; color: #000; padding: 4px 8px; border-radius: 4px; font-weight: bold;">Tag 1</span>
|
||||
<span style="background: #58a6ff; color: #fff; padding: 4px 8px; border-radius: 4px; font-weight: bold;">Tag 2</span>
|
||||
<span style="background: #FFA500; color: #fff; padding: 4px 8px; border-radius: 4px; font-weight: bold;">Tag 3</span>
|
||||
</div>
|
||||
```
|
||||
|
||||
### Rendered Result:
|
||||

|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><b>Custom Info Cards</b></summary>
|
||||
|
||||
### Code:
|
||||
```html
|
||||
<div style="display: flex; gap: 10px; flex-wrap: wrap;">
|
||||
<div style="flex: 1; min-width: 150px; background: rgba(144, 238, 144, 0.1); border: 1px solid #90EE90; padding: 12px; border-radius: 6px; text-align: center;">
|
||||
<strong style="color: #90EE90; display: block; margin-bottom: 4px;">Steps</strong>
|
||||
<p style="margin: 0; font-size: 24px; color: #fff; font-weight: bold;">25</p>
|
||||
</div>
|
||||
|
||||
<div style="flex: 1; min-width: 150px; background: rgba(135, 206, 235, 0.1); border: 1px solid #87CEEB; padding: 12px; border-radius: 6px; text-align: center;">
|
||||
<strong style="color: #87CEEB; display: block; margin-bottom: 4px;">CFG Scale</strong>
|
||||
<p style="margin: 0; font-size: 24px; color: #fff; font-weight: bold;">7.5</p>
|
||||
</div>
|
||||
|
||||
<div style="flex: 1; min-width: 150px; background: rgba(186, 85, 211, 0.1); border: 1px solid #BA55D3; padding: 12px; border-radius: 6px; text-align: center;">
|
||||
<strong style="color: #BA55D3; display: block; margin-bottom: 4px;">Batch Size</strong>
|
||||
<p style="margin: 0; font-size: 24px; color: #fff; font-weight: bold;">4</p>
|
||||
</div>
|
||||
</div>
|
||||
```
|
||||
|
||||
### Rendered Result:
|
||||

|
||||
|
||||
</details>
|
||||
|
||||
---
|
||||
|
||||
## 📋 Complete Workflow Example
|
||||
|
||||
<details>
|
||||
<summary><b>Full Workflow Documentation Template</b></summary>
|
||||
|
||||
### Code:
|
||||
```html
|
||||
<div class="af-section af-positive">
|
||||
<h2>🟢 Positive Prompts</h2>
|
||||
<p><strong>masterpiece, best quality, highly detailed, 8k uhd, professional photography</strong></p>
|
||||
<ul>
|
||||
<li>Professional lighting and composition</li>
|
||||
<li>Sharp focus with bokeh background</li>
|
||||
<li>Photorealistic textures and materials</li>
|
||||
<li>Award-winning cinematography</li>
|
||||
</ul>
|
||||
<a href="https://example.com/prompts">📋 View Prompt Guide</a>
|
||||
</div>
|
||||
|
||||
<div class="af-spacer"></div>
|
||||
|
||||
<div class="af-section af-negative">
|
||||
<h2>🔴 Negative Prompts</h2>
|
||||
<p><em>low quality, worst quality, blurry, out of focus</em></p>
|
||||
<p><code>nsfw, watermark, signature, text, bad anatomy, deformed, ugly, mutation</code></p>
|
||||
</div>
|
||||
|
||||
<div class="af-spacer-large"></div>
|
||||
|
||||
<div class="af-section af-info">
|
||||
<h3>ℹ️ Model Information</h3>
|
||||
<p>Model: <strong>SDXL 1.0 Base</strong></p>
|
||||
<p>Settings: Steps <code>25</code> | CFG <code>7.5</code> | Sampler <code>DPM++ 2M Karras</code></p>
|
||||
<p>Resolution: <code>1024x1024</code> | Batch Size: <code>4</code></p>
|
||||
<a href="https://huggingface.co/stabilityai/stable-diffusion-xl-base-1.0">📦 Model Page</a>
|
||||
</div>
|
||||
|
||||
<div class="af-spacer"></div>
|
||||
|
||||
<div class="af-section af-warning">
|
||||
<h3>⚠️ System Requirements</h3>
|
||||
<p>This workflow requires:</p>
|
||||
<ol>
|
||||
<li>GPU with 8GB+ VRAM (12GB recommended)</li>
|
||||
<li>ComfyUI latest version</li>
|
||||
<li>SDXL compatible checkpoint</li>
|
||||
<li>Required custom nodes installed</li>
|
||||
</ol>
|
||||
</div>
|
||||
|
||||
<div class="af-spacer"></div>
|
||||
|
||||
<div class="af-section af-neutral">
|
||||
<h3>📝 Workflow Notes</h3>
|
||||
<p>Remember to:</p>
|
||||
<p><strong>Tips for best results:</strong></p>
|
||||
<ul>
|
||||
<li>Check image dimensions before generating</li>
|
||||
<li>Adjust CFG scale for different results</li>
|
||||
<li>Save frequently!</li>
|
||||
<li>Verify image dimensions before generating</li>
|
||||
<li>Lower CFG (6-7) for more creative interpretations</li>
|
||||
<li>Higher CFG (8-10) for more prompt adherence</li>
|
||||
<li>Save your workflow frequently!</li>
|
||||
</ul>
|
||||
<hr>
|
||||
<p><small>Last updated: Today | Created with AF Enhanced HTML Node</small></p>
|
||||
<p><small>Last updated: 2025-01-15 | Created with AF Enhanced HTML Node v0.0.5</small></p>
|
||||
</div>
|
||||
```
|
||||
## 🛠️ Installation
|
||||
Create folder: ComfyUI/custom_nodes/ComfyUI-AF_Enhanced_HTML_Note/
|
||||
|
||||
Add the Python file: AF_Enhanced_HTML_Note.py
|
||||
### Rendered Result:
|
||||

|
||||
|
||||
Add the init file: __init__.py
|
||||
</details>
|
||||
|
||||
Create web/ subfolder
|
||||
|
||||
Add the JavaScript file: web/AF_Enhanced_HTML_Note.js
|
||||
|
||||
Restart ComfyUI
|
||||
|
||||
Find the node under AF - Nodes > AF - Enhanced HTML Note
|
||||
|
||||
## 🔧 Technical Details
|
||||
Node Name: AF_Enhanced_HTML_Note
|
||||
|
||||
Category: AF - Nodes
|
||||
|
||||
Input: HTML content (multiline string)
|
||||
|
||||
Output: None (display only)
|
||||
|
||||
Compatibility: ComfyUI latest version
|
||||
---
|
||||
|
||||
## 🐛 Troubleshooting
|
||||
Node won't select/move?
|
||||
|
||||
Click on the node's title bar or edges, not the HTML content area
|
||||
<details>
|
||||
<summary><b>Common Issues and Solutions</b></summary>
|
||||
|
||||
Links not working?
|
||||
### Node won't select/move?
|
||||
**Solution:** Click on the node's title bar or edges, not the HTML content area
|
||||
|
||||
Remember to hold the Control key while clicking links
|
||||
### Links not working?
|
||||
**Solution:** Remember to hold the **Control key** while clicking links
|
||||
|
||||
Can't edit content?
|
||||
### JavaScript not working?
|
||||
**Solution:** JavaScript execution is disabled for security. Only standard navigation links work.
|
||||
|
||||
Double-click directly on the HTML content (not the node borders)
|
||||
### Can't edit content?
|
||||
**Solution:** Double-click directly on the HTML content (not the node borders)
|
||||
|
||||
Scrollbar appears unnecessarily?
|
||||
### Scrollbar appears unnecessarily?
|
||||
**Solution:** The node has minimal padding; resize if you need more space
|
||||
|
||||
The node has minimal padding; resize if you need more space
|
||||
### Styling not applying?
|
||||
**Solution:**
|
||||
- Use inline styles with the `style` attribute
|
||||
- Check for CSS syntax errors in your inline styles
|
||||
- Predefined classes must be spelled exactly as documented
|
||||
|
||||
## 📞 Support
|
||||
Creator: Alex Furer
|
||||
### Content not saving?
|
||||
**Solution:**
|
||||
- Press **Escape** or click outside to exit edit mode
|
||||
- Ensure you're not just closing the browser/tab
|
||||
- Save your ComfyUI workflow after making changes
|
||||
|
||||
Co-Creators: Claude AI & DeepSeek
|
||||
</details>
|
||||
|
||||
GitHub: https://github.com/alFrame/ComfyUI_AF_FindNodeByID
|
||||
---
|
||||
|
||||
License: MIT License
|
||||
## 📚 Quick Reference
|
||||
|
||||
### Predefined Color Classes
|
||||
| Class | Color | Use Case |
|
||||
|-------|-------|----------|
|
||||
| `af-positive` | Green | Positive prompts, success messages |
|
||||
| `af-negative` | Red | Negative prompts, errors, warnings |
|
||||
| `af-neutral` | Gray | General notes, neutral information |
|
||||
| `af-info` | Light Blue | Information, technical details |
|
||||
| `af-warning` | Yellow | Warnings, cautions |
|
||||
| `af-yellow` | Yellow | Alternative yellow styling |
|
||||
| `af-blue` | Deep Blue | Technical information |
|
||||
| `af-custom` | Purple | Custom content, special cases |
|
||||
|
||||
### Predefined Spacer Classes
|
||||
| Class | Height | Use Case |
|
||||
|-------|--------|----------|
|
||||
| `af-spacer-top` | 2px | Minimal spacing |
|
||||
| `af-spacer-mini` | 4px | Tiny spacing |
|
||||
| `af-spacer-small` | 8px | Small spacing |
|
||||
| `af-spacer` | 16px | Default spacing |
|
||||
| `af-spacer-large` | 32px | Large spacing |
|
||||
| `af-spacer-xl` | 48px | Extra large spacing |
|
||||
|
||||
### Column Layout Classes
|
||||
| Class | Width | Use Case |
|
||||
|-------|-------|----------|
|
||||
| `af-column-half-left` | 49% | Left column in two-column layout |
|
||||
| `af-column-half-right` | 49% | Right column in two-column layout |
|
||||
| `row` | Container | Wrap around columns for proper layout |
|
||||
|
||||
### Keyboard Shortcuts
|
||||
| Shortcut | Action |
|
||||
|----------|--------|
|
||||
| **Double-click** | Enter edit mode |
|
||||
| **Escape** | Exit edit mode and save |
|
||||
| **Ctrl+Click** | Activate links (JavaScript disabled) |
|
||||
|
||||
---
|
||||
|
||||
## ⚠️ Disclaimer
|
||||
|
||||
This ComfyUI custom node is developed through AI-assisted coding. While carefully tested, it is provided **"as is" without warranty**.
|
||||
|
||||
**By using this node:**
|
||||
- You install and run at your own risk
|
||||
- The creator is not liable for damages or data loss
|
||||
- Compatibility with your setup is not guaranteed
|
||||
- Test in a safe environment before production use
|
||||
|
||||
Report issues on GitHub - we appreciate your feedback!
|
||||
|
||||
---
|
||||
|
||||
## 📚 Additional Resources
|
||||
|
||||
- **[Changelog](CHANGELOG.md)** - Version history and updates
|
||||
- [GitHub Issues](https://github.com/alFrame/ComfyUI-AF-Enhanced-HTML-Note/issues) - Report bugs & request features
|
||||
- [License](LICENSE) - MIT License details
|
||||
|
||||
---
|
||||
|
||||
**Made with ❤️ by Alex Furer & Qwen3, Claude AI, DeepSeek**
|
||||
|
||||
@@ -1,25 +1,23 @@
|
||||
# AF - Enhanced HTML-Note Node for ComfyUI
|
||||
# File: __init__.py
|
||||
|
||||
import os
|
||||
from .AF_Enhanced_HTML_Note import NODE_CLASS_MAPPINGS, NODE_DISPLAY_NAME_MAPPINGS
|
||||
|
||||
# Tell ComfyUI about our web files
|
||||
WEB_DIRECTORY = "./web"
|
||||
|
||||
__all__ = ['NODE_CLASS_MAPPINGS', 'NODE_DISPLAY_NAME_MAPPINGS', 'WEB_DIRECTORY']
|
||||
__version__ = "0.0.05"
|
||||
__author__ = "Alex Furer"
|
||||
|
||||
print("* * * * * * * * * * * * * * * * * * * * * * * * * *")
|
||||
print(r"""
|
||||
___ ____ _____ ___ __ ______ _ __ __
|
||||
/ _ | / __/ ____ / ___/__ __ _ / _/_ __/ / / / _/ / |/ /__ ___/ /__ ___
|
||||
/ __ |/ _/ /___/ / /__/ _ \/ ' \/ _/ // / /_/ // / / / _ Y _ / -_|_-<
|
||||
/_/ |_/_/ \___/\___/_/_/_/_/ \_, /\____/___/ /_/|_/\___|_,_/\__/___/
|
||||
/___/
|
||||
|
||||
📋 AF - Enhanced HTML Note Loaded !
|
||||
|
||||
""")
|
||||
print("* * * * * * * * * * * * * * * * * * * * * * * * * *")
|
||||
"""
|
||||
@author: Alex Furer
|
||||
@title: AF - Enhanced HTML Note
|
||||
@nickname: AF - Enhanced HTML Note
|
||||
@description: A ComfyUI custom node that allows you to create a note node with HTML support.
|
||||
"""
|
||||
|
||||
import os
|
||||
from .node import NODE_CLASS_MAPPINGS, NODE_DISPLAY_NAME_MAPPINGS
|
||||
|
||||
# Tell ComfyUI about our web files
|
||||
WEB_DIRECTORY = "./web"
|
||||
|
||||
__all__ = ['NODE_CLASS_MAPPINGS', 'NODE_DISPLAY_NAME_MAPPINGS', 'WEB_DIRECTORY']
|
||||
|
||||
|
||||
print("* * * * * * * * * * * * * * * * *")
|
||||
print(r"""
|
||||
AF - ComfyUI Nodes
|
||||
|
||||
📋 AF - Enhanced HTML Note Loaded !
|
||||
""")
|
||||
print("* * * * * * * * * * * * * * * * *")
|
||||
@@ -0,0 +1,150 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>AF - SDXL Workflow - Help-A</title>
|
||||
|
||||
<link rel="stylesheet" href="./styles.css">
|
||||
|
||||
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div class="af-html-note-container">
|
||||
<div class="af-html-note-content">
|
||||
<!-- THIS CONTENT TO JS FILE -->
|
||||
|
||||
<div style="height: 3px;"></div>
|
||||
|
||||
<div class="af-section af-positive">
|
||||
<h2>🟢 Generated Positive Global Prompt</h2>
|
||||
<p>If you use any of the prompt generators ( [A], [B], [C], [D], [E] )<br/>
|
||||
the genertaed prompt will be sent to this widget.<br/><br/>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div style="height: 12px;"></div>
|
||||
|
||||
<div class="af-section af-positive">
|
||||
<h2>🟢 Manual Positive Global Prompt</h2>
|
||||
<p>You can either write your own prompt, or use a generated prompt.<br/>
|
||||
To use the generated prompt without editing, leave this widget empty.<br/>
|
||||
If you wish to edit the generated prompt, click the "Copy Generated Prompt for Editing" button.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div style="height: 2px;"></div>
|
||||
|
||||
<div class="af-section af-neutral">
|
||||
<p>Button to copy and edit the generated prompt.<p>
|
||||
</div>
|
||||
|
||||
<div style="height: 65px;"></div>
|
||||
|
||||
<div class="af-section af-negative">
|
||||
<h2>🔴 Generated Negative Global Prompt</h2>
|
||||
<p>Your generated negative prompt will be sent to this widget (same as above).</p>
|
||||
</div>
|
||||
|
||||
<div style="height: 10px;"></div>
|
||||
|
||||
<div class="af-section af-negative">
|
||||
<h2>🔴 Manual Negative Global Prompt</h2>
|
||||
<p>Here you can either enter a rompt manually, or copy the generated to edit (same as above).</p>
|
||||
</div>
|
||||
|
||||
<div style="height: 2px;"></div>
|
||||
|
||||
<div class="af-section af-neutral">
|
||||
<p>Button to copy and edit the generated prompt.<p>
|
||||
</div>
|
||||
|
||||
<div style="height: 170px;"></div>
|
||||
|
||||
<div class="af-section af-positive">
|
||||
<h2>🟢 Generated Positive Local Prompt</h2>
|
||||
<p>Same as above. <strong>BUT</strong> make sure to set "5. Plain Prompt OR TextEncoded Prompt" to true for this prompt to take effect !!
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div style="height: 10px;"></div>
|
||||
|
||||
<div class="af-section af-positive">
|
||||
<h2>🟢 Manual Positive Local Prompt</h2>
|
||||
<p>Here you can either enter a rompt manually, or copy the generated to edit (same as above).
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div style="height: 2px;"></div>
|
||||
|
||||
<div class="af-section af-neutral">
|
||||
<p>Button to copy and edit the generated prompt.<p>
|
||||
</div>
|
||||
|
||||
<div style="height: 152px;"></div>
|
||||
|
||||
<div class="af-section af-blue">
|
||||
<h2>Styles Drop-Down's</h2>
|
||||
<p>Here you can choose up to four styles that will be applied.</p>
|
||||
</div>
|
||||
|
||||
<div style="height: 2px;"></div>
|
||||
|
||||
<div class="af-section af-neutral">
|
||||
<p>Button to copy and edit the generated prompt.<p>
|
||||
</div>
|
||||
|
||||
<div style="height: 350px;"></div>
|
||||
|
||||
<div class="row">
|
||||
<div class="af-column-half-left af-section af-positive">
|
||||
<h2>Positive Prompt Text Encoding</h2>
|
||||
<p>The CLIP Text Encode SDXL node encodes text prompts into SDXL-compatible conditioning embeddings using a dual CLIP encoder system, while incorporating image dimensions, crop, and target parameters to provide spatial context for the diffusion model.<br/><br/>
|
||||
In other words, it can improve your image creation.<br/><br/>
|
||||
<a href="https://docs.comfy.org/built-in-nodes/ClipTextEncodeSdxl">ComyUI manual page</a></p>
|
||||
</div>
|
||||
<div class="af-column-half-right af-section af-negative">
|
||||
<h2>Negative Prompt Text Encoding</h2>
|
||||
<p>The same as on the positive Prompt Text Encode<br/><br/><br/><br/><br/><br/><br/><br/><br/></p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style="height: 126px;"></div>
|
||||
|
||||
<div class="af-section af-blue">
|
||||
<h2>Plain Prompt, OR Text Encoded Prompt (Subgraph)</h2>
|
||||
<p>Here you can choose if you want to use the plain prompt, or the Text Encoded Prompt.<br/><br/>
|
||||
If you choose to use the <strong>plain prompt (false)</strong>, it means that the <strong>local prompts</strong> will be ignored and the prompt will not be text encoded !!</p>
|
||||
</div>
|
||||
|
||||
<div style="height: 225px;"></div>
|
||||
|
||||
<div class="af-section af-yellow">
|
||||
<h2>Save that hard earned prompting</h2>
|
||||
<p>Here you can choose setup the <strong>Folder</strong and the <strong>File Name</strong> of the .csv file that will store all your prompts.<br/>
|
||||
Additionally you can also define a <strong>Project Name</strong>, which will let you identify the relevant prompts later.</p>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
<div class="af-section af-neutral">
|
||||
<h3>📝 Notes</h3>
|
||||
<p>Additional notes and information...</p>
|
||||
<ul>
|
||||
<li>Item 1</li>
|
||||
<li>Item 2</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<!-- END THIS CONTENT TO JS FILE -->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,408 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>AF - Enhanced HTML Note - Default Content</title>
|
||||
|
||||
<link rel="stylesheet" href="./styles.css">
|
||||
|
||||
|
||||
</head>
|
||||
<body style="background-color: #2a2a2a;">
|
||||
|
||||
<div class="af-html-note-container">
|
||||
<div class="af-html-note-content">
|
||||
<!-- THIS CONTENT TO JS FILE -->
|
||||
|
||||
<h1>Predefined Section Colors</h1>
|
||||
<h2>Positive Prompt Section</h2>
|
||||
<div style="border: 1px solid #808080; padding: 8px; border-radius: 6px; margin: 8px 0;">
|
||||
<div class="af-section af-positive">
|
||||
<h2>🟢 Positive Prompts</h2>
|
||||
<p><strong>masterpiece, best quality, highly detailed</strong></p>
|
||||
<ul>
|
||||
<li>Professional lighting</li>
|
||||
<li>Sharp focus</li>
|
||||
<li>8K resolution</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h2>Negative Prompt Section</h2>
|
||||
<div style="border: 1px solid #808080; padding: 8px; border-radius: 6px; margin: 8px 0;">
|
||||
<div class="af-section af-negative">
|
||||
<h2>🔴 Negative Prompts</h2>
|
||||
<p><em>low quality, blurry, distorted</em></p>
|
||||
<p><code>nsfw, watermark, signature, bad anatomy</code></p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h2>Neutral Prompt Section</h2>
|
||||
<div style="border: 1px solid #808080; padding: 8px; border-radius: 6px; margin: 8px 0;">
|
||||
<div class="af-section af-neutral">
|
||||
<h3>📝 Notes</h3>
|
||||
<p>General notes and information...</p>
|
||||
<ul>
|
||||
<li>Item 1</li>
|
||||
<li>Item 2</li>
|
||||
<li>Item 3</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h2>Info Section</h2>
|
||||
<div style="border: 1px solid #808080; padding: 8px; border-radius: 6px; margin: 8px 0;">
|
||||
<div class="af-section af-info">
|
||||
<h3>ℹ️ Information</h3>
|
||||
<p>Using: <strong>SDXL 1.0</strong></p>
|
||||
<p>Steps: <code>25</code> | CFG: <code>7.5</code> | Sampler: <code>DPM++ 2M Karras</code></p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h2>Warning Section</h2>
|
||||
<div style="border: 1px solid #808080; padding: 8px; border-radius: 6px; margin: 8px 0;">
|
||||
<div class="af-section af-warning">
|
||||
<h3>⚠️ Warning</h3>
|
||||
<p>This workflow requires:</p>
|
||||
<ol>
|
||||
<li>High VRAM (8GB+)</li>
|
||||
<li>Latest ComfyUI version</li>
|
||||
<li>SDXL compatible models</li>
|
||||
</ol>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h2>Yellow Section</h2>
|
||||
<div style="border: 1px solid #808080; padding: 8px; border-radius: 6px; margin: 8px 0;">
|
||||
<div class="af-section af-yellow">
|
||||
<h3>💛 Yellow Section</h3>
|
||||
<p>Alternative yellow styled content with different shade...</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h2>Blue Section</h2>
|
||||
<div style="border: 1px solid #808080; padding: 8px; border-radius: 6px; margin: 8px 0;">
|
||||
<div class="af-section af-blue">
|
||||
<h3>🔵 Blue Section</h3>
|
||||
<p>Deep blue styled content for technical information...</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h2>Custom Section</h2>
|
||||
<div style="border: 1px solid #808080; padding: 8px; border-radius: 6px; margin: 8px 0;">
|
||||
<div class="af-section af-custom">
|
||||
<h3>🎨 Custom</h3>
|
||||
<p>Purple custom styled content for special cases...</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h1>Predefined Spacers</h1>
|
||||
<h2>Top spacer (2px)</h2>
|
||||
<div style="border: 1px solid #808080; padding: 8px; border-radius: 6px; margin: 8px 0;">
|
||||
<div class="af-spacer-top"></div>
|
||||
|
||||
<div class="af-section af-negative">Content Block 1</div>
|
||||
</div>
|
||||
|
||||
<h2>Mini spacer (4px)</h2>
|
||||
<div style="border: 1px solid #808080; padding: 8px; border-radius: 6px; margin: 8px 0;">
|
||||
<div class="af-spacer-mini"></div>
|
||||
|
||||
<div class="af-section af-neutral">Content Block 2</div>
|
||||
</div>
|
||||
|
||||
<h2>Small spacer (8px)</h2>
|
||||
<div style="border: 1px solid #808080; padding: 8px; border-radius: 6px; margin: 8px 0;">
|
||||
<div class="af-spacer-small"></div>
|
||||
|
||||
<div class="af-section af-info">Content Block 3</div>
|
||||
</div>
|
||||
|
||||
<h2>Regular spacer (16px)</h2>
|
||||
<div style="border: 1px solid #808080; padding: 8px; border-radius: 6px; margin: 8px 0;">
|
||||
<div class="af-spacer"></div>
|
||||
|
||||
<div class="af-section af-warning">Content Block 4</div>
|
||||
</div>
|
||||
|
||||
<h2>Large spacer (32px)</h2>
|
||||
<div style="border: 1px solid #808080; padding: 8px; border-radius: 6px; margin: 8px 0;">
|
||||
<div class="af-spacer-large"></div>
|
||||
|
||||
<div class="af-section af-custom">Content Block 5</div>
|
||||
</div>
|
||||
|
||||
<h2>Extra large spacer (48px)</h2>
|
||||
<div style="border: 1px solid #808080; padding: 8px; border-radius: 6px; margin: 8px 0;">
|
||||
<div class="af-spacer-xl"></div>
|
||||
|
||||
<div class="af-section af-blue">Content Block 6</div>
|
||||
</div>
|
||||
|
||||
<h2>Column Layouts</h2>
|
||||
<div style="border: 1px solid #808080; padding: 8px; border-radius: 6px; margin: 8px 0;">
|
||||
<div class="row">
|
||||
<div class="af-column-half-left">
|
||||
<div class="af-section af-positive">
|
||||
<h3>🎨 Style Settings</h3>
|
||||
<ul>
|
||||
<li>Style: Photorealistic</li>
|
||||
<li>Aspect: 16:9</li>
|
||||
<li>Quality: Ultra High</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="af-spacer"></div>
|
||||
|
||||
<div class="af-section af-info">
|
||||
<h3>⚙️ Technical</h3>
|
||||
<p>Resolution: <code>1920x1080</code></p>
|
||||
<p>Batch: <code>4</code></p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="af-column-half-right">
|
||||
<div class="af-section af-negative">
|
||||
<h3>🚫 Exclusions</h3>
|
||||
<ul>
|
||||
<li>No text in image</li>
|
||||
<li>Avoid oversaturation</li>
|
||||
<li>No watermarks</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="af-spacer"></div>
|
||||
|
||||
<div class="af-section af-warning">
|
||||
<h3>💡 Tips</h3>
|
||||
<p>Use lower CFG for more creative results</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h2>Clickable Links & Actions</h2>
|
||||
<div style="border: 1px solid #808080; padding: 8px; border-radius: 6px; margin: 8px 0;">
|
||||
<div class="af-section af-info">
|
||||
<h3>🔗 Interactive Links</h3>
|
||||
|
||||
<!-- External links (opens in new tab with Ctrl+click) -->
|
||||
<h4>External link (opens in new tab with Ctrl+click)</h4>
|
||||
<p><a href="https://www.fullframestudios.ch/">Full Frame Studios - Alex Furer</a></p>
|
||||
|
||||
<h4>Anchor Links</h4>
|
||||
<p><a href="https://www.fullframestudios.ch/#ThreeDee">Full Frame Studios - Alex Furer - 3D</a></p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h2>Custom Styling Examples</h2>
|
||||
<div style="border: 1px solid #808080; padding: 8px; border-radius: 6px; margin: 8px 0;">
|
||||
<div class="af-section af-positive">First Section</div>
|
||||
|
||||
<h2>Custom 12px spacer</h2>
|
||||
<div style="height: 12px;"></div>
|
||||
|
||||
<div class="af-section af-negative">Second Section</div>
|
||||
|
||||
<h2>Custom 24px spacer</h2>
|
||||
<div style="height: 24px;"></div>
|
||||
|
||||
<div class="af-section af-info">Third Section</div>
|
||||
|
||||
<h2>Custom 50px spacer</h2>
|
||||
<div style="height: 50px;"></div>
|
||||
|
||||
<div class="af-section af-warning">Fourth Section</div>
|
||||
</div>
|
||||
|
||||
<h1>Custom Color Sections</h1>
|
||||
<h2>Custom pink section</h2>
|
||||
<div style="border: 1px solid #808080; padding: 8px; border-radius: 6px; margin: 8px 0;">
|
||||
<div style="background: rgba(255, 100, 150, 0.1); border-left: 4px solid #ff6496; padding: 12px; border-radius: 6px; margin: 8px 0;">
|
||||
<h3 style="color: #ff6496; margin-top: 0;">Custom Pink Section</h3>
|
||||
<p>Your content here with custom colors...</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h2>Custom teal section</h2>
|
||||
<div style="border: 1px solid #808080; padding: 8px; border-radius: 6px; margin: 8px 0;">
|
||||
<div style="background: rgba(64, 224, 208, 0.1); border-left: 4px solid #40E0D0; padding: 12px; border-radius: 6px; margin: 8px 0;">
|
||||
<h3 style="color: #40E0D0; margin-top: 0;">Custom Teal Section</h3>
|
||||
<p>Different color scheme for variety...</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h2>Custom orange section</h2>
|
||||
<div style="border: 1px solid #808080; padding: 8px; border-radius: 6px; margin: 8px 0;">
|
||||
<div style="background: rgba(255, 165, 0, 0.1); border-left: 4px solid #FFA500; padding: 12px; border-radius: 6px; margin: 8px 0;">
|
||||
<h3 style="color: #FFA500; margin-top: 0;">Custom Orange Section</h3>
|
||||
<p>Create any color combination you need...</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h2>Text Examples</h2>
|
||||
<div style="border: 1px solid #808080; padding: 8px; border-radius: 6px; margin: 8px 0;">
|
||||
<div class="af-section af-neutral">
|
||||
<!-- Large blue bold text -->
|
||||
<p style="font-size: 18px; color: #58a6ff; font-weight: bold;">
|
||||
Large blue bold text for emphasis
|
||||
</p>
|
||||
|
||||
<!-- Small gray italic text -->
|
||||
<p style="font-size: 12px; color: #888; font-style: italic;">
|
||||
Small gray italic text for subtitles
|
||||
</p>
|
||||
|
||||
<!-- Highlighted text -->
|
||||
<p style="background: rgba(255, 255, 0, 0.2); padding: 4px 8px; border-radius: 3px;">
|
||||
Highlighted text with yellow background
|
||||
</p>
|
||||
|
||||
<!-- Custom monospace -->
|
||||
<p style="font-family: 'Courier New', monospace; color: #90EE90; background: rgba(0,0,0,0.4); padding: 8px; border-radius: 4px;">
|
||||
Custom monospace text for code-like display
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h1>Custom Border Sections</h1>
|
||||
<h2>Dashed border box</h2>
|
||||
<div style="border: 1px solid #808080; padding: 8px; border-radius: 6px; margin: 8px 0;">
|
||||
<div style="border: 2px dashed #90EE90; padding: 16px; margin: 10px 0; background: rgba(0, 0, 0, 0.2); border-radius: 8px;">
|
||||
<p><strong>Dashed Border Box</strong></p>
|
||||
<p>Content in a custom dashed border box</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h2>Solid border with shadow effect</h2>
|
||||
<div style="border: 1px solid #808080; padding: 8px; border-radius: 6px; margin: 8px 0;">
|
||||
<div style="border: 2px solid #58a6ff; padding: 16px; margin: 10px 0; background: rgba(88, 166, 255, 0.05); box-shadow: 0 4px 8px rgba(0,0,0,0.3); border-radius: 8px;">
|
||||
<p><strong>Solid Border with Shadow</strong></p>
|
||||
<p>Creates depth with shadow effect</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h2>Thick left border</h2>
|
||||
<div style="border: 1px solid #808080; padding: 8px; border-radius: 6px; margin: 8px 0;">
|
||||
<div style="border-left: 8px solid #BA55D3; padding: 16px; margin: 10px 0; background: rgba(186, 85, 211, 0.1);">
|
||||
<p><strong>Thick Left Border</strong></p>
|
||||
<p>Emphasizes content with thick accent border</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h1>Align Content</h1>
|
||||
<h2>Centered content</h2>
|
||||
<div style="border: 1px solid #808080; padding: 8px; border-radius: 6px; margin: 8px 0;">
|
||||
<div style="text-align: center; padding: 20px; background: rgba(255,255,255,0.05); border-radius: 8px; margin: 10px 0;">
|
||||
<h2 style="margin: 0 0 12px 0;">Centered Title</h2>
|
||||
<p style="margin: 0;">Centered paragraph text for announcements</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h2>Right-aligned content</h2>
|
||||
<div style="border: 1px solid #808080; padding: 8px; border-radius: 6px; margin: 8px 0;">
|
||||
<div style="text-align: right; padding: 10px; border-top: 1px solid #555; margin-top: 20px;">
|
||||
<small style="color: #888;">Right-aligned footer note</small>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h2>Flex layout for inline elements</h2>
|
||||
<div style="border: 1px solid #808080; padding: 8px; border-radius: 6px; margin: 8px 0;">
|
||||
<div style="display: flex; gap: 10px; align-items: center; padding: 12px; background: rgba(0,0,0,0.2); border-radius: 6px;">
|
||||
<span style="background: #90EE90; color: #000; padding: 4px 8px; border-radius: 4px; font-weight: bold;">Tag 1</span>
|
||||
<span style="background: #58a6ff; color: #fff; padding: 4px 8px; border-radius: 4px; font-weight: bold;">Tag 2</span>
|
||||
<span style="background: #FFA500; color: #fff; padding: 4px 8px; border-radius: 4px; font-weight: bold;">Tag 3</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h2>Custom Info Cards</h2>
|
||||
<div style="border: 1px solid #808080; padding: 8px; border-radius: 6px; margin: 8px 0;">
|
||||
<div style="display: flex; gap: 10px; flex-wrap: wrap;">
|
||||
<div style="flex: 1; min-width: 150px; background: rgba(144, 238, 144, 0.1); border: 1px solid #90EE90; padding: 12px; border-radius: 6px; text-align: center;">
|
||||
<strong style="color: #90EE90; display: block; margin-bottom: 4px;">Steps</strong>
|
||||
<p style="margin: 0; font-size: 24px; color: #fff; font-weight: bold;">25</p>
|
||||
</div>
|
||||
|
||||
<div style="flex: 1; min-width: 150px; background: rgba(135, 206, 235, 0.1); border: 1px solid #87CEEB; padding: 12px; border-radius: 6px; text-align: center;">
|
||||
<strong style="color: #87CEEB; display: block; margin-bottom: 4px;">CFG Scale</strong>
|
||||
<p style="margin: 0; font-size: 24px; color: #fff; font-weight: bold;">7.5</p>
|
||||
</div>
|
||||
|
||||
<div style="flex: 1; min-width: 150px; background: rgba(186, 85, 211, 0.1); border: 1px solid #BA55D3; padding: 12px; border-radius: 6px; text-align: center;">
|
||||
<strong style="color: #BA55D3; display: block; margin-bottom: 4px;">Batch Size</strong>
|
||||
<p style="margin: 0; font-size: 24px; color: #fff; font-weight: bold;">4</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h2>Complete Workflow Example</h2>
|
||||
<div style="border: 1px solid #808080; padding: 8px; border-radius: 6px; margin: 8px 0;">
|
||||
<div class="af-section af-positive">
|
||||
<h2>🟢 Positive Prompts</h2>
|
||||
<p><strong>masterpiece, best quality, highly detailed, 8k uhd, professional photography</strong></p>
|
||||
<ul>
|
||||
<li>Professional lighting and composition</li>
|
||||
<li>Sharp focus with bokeh background</li>
|
||||
<li>Photorealistic textures and materials</li>
|
||||
<li>Award-winning cinematography</li>
|
||||
</ul>
|
||||
<a href="#" onclick="alert('Positive prompts copied to clipboard!')">📋 Copy Prompts</a>
|
||||
</div>
|
||||
|
||||
<div class="af-spacer"></div>
|
||||
|
||||
<div class="af-section af-negative">
|
||||
<h2>🔴 Negative Prompts</h2>
|
||||
<p><em>low quality, worst quality, blurry, out of focus</em></p>
|
||||
<p><code>nsfw, watermark, signature, text, bad anatomy, deformed, ugly, mutation</code></p>
|
||||
</div>
|
||||
|
||||
<div class="af-spacer-large"></div>
|
||||
|
||||
<div class="af-section af-info">
|
||||
<h3>ℹ️ Model Information</h3>
|
||||
<p>Model: <strong>SDXL 1.0 Base</strong></p>
|
||||
<p>Settings: Steps <code>25</code> | CFG <code>7.5</code> | Sampler <code>DPM++ 2M Karras</code></p>
|
||||
<p>Resolution: <code>1024x1024</code> | Batch Size: <code>4</code></p>
|
||||
<a href="https://huggingface.co/stabilityai/stable-diffusion-xl-base-1.0">📦 Model Page</a>
|
||||
</div>
|
||||
|
||||
<div class="af-spacer"></div>
|
||||
|
||||
<div class="af-section af-warning">
|
||||
<h3>⚠️ System Requirements</h3>
|
||||
<p>This workflow requires:</p>
|
||||
<ol>
|
||||
<li>GPU with 8GB+ VRAM (12GB recommended)</li>
|
||||
<li>ComfyUI latest version</li>
|
||||
<li>SDXL compatible checkpoint</li>
|
||||
<li>Required custom nodes installed</li>
|
||||
</ol>
|
||||
</div>
|
||||
|
||||
<div class="af-spacer"></div>
|
||||
|
||||
<div class="af-section af-neutral">
|
||||
<h3>📝 Workflow Notes</h3>
|
||||
<p><strong>Tips for best results:</strong></p>
|
||||
<ul>
|
||||
<li>Verify image dimensions before generating</li>
|
||||
<li>Lower CFG (6-7) for more creative interpretations</li>
|
||||
<li>Higher CFG (8-10) for more prompt adherence</li>
|
||||
<li>Save your workflow frequently!</li>
|
||||
</ul>
|
||||
<hr>
|
||||
<p><small>Last updated: 2025-01-15 | Created with AF Enhanced HTML Node v0.0.5</small></p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- END THIS CONTENT TO JS FILE -->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,145 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>AF - Enhanced HTML Note - Default Content</title>
|
||||
|
||||
<link rel="stylesheet" href="./styles.css">
|
||||
|
||||
|
||||
</head>
|
||||
<body style="background-color: #2a2a2a;">
|
||||
|
||||
<div class="af-html-note-container">
|
||||
<div class="af-html-note-content">
|
||||
<!-- BEGINNING: THIS CONTENT TO MAIN.PY FILE -->
|
||||
|
||||
|
||||
|
||||
<h2>Positive Prompt Section</h2>
|
||||
<div class="af-section af-positive">
|
||||
<h2>🟢 Positive Prompts</h2>
|
||||
<p><strong>masterpiece, best quality, highly detailed</strong></p>
|
||||
<ul>
|
||||
<li>Professional lighting</li>
|
||||
<li>Sharp focus</li>
|
||||
<li>8K resolution</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
|
||||
<h2>Negative Prompt Section</h2>
|
||||
<div class="af-section af-negative">
|
||||
<h2>🔴 Negative Prompts</h2>
|
||||
<p><em>low quality, blurry, distorted</em></p>
|
||||
<p><code>nsfw, watermark, signature, bad anatomy</code></p>
|
||||
</div>
|
||||
|
||||
|
||||
<h2>Neutral Prompt Section</h2>
|
||||
<div class="af-section af-neutral">
|
||||
<h3>📝 Notes</h3>
|
||||
<p>General notes and information...</p>
|
||||
<ul>
|
||||
<li>Item 1</li>
|
||||
<li>Item 2</li>
|
||||
<li>Item 3</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<h2>Info Section</h2>
|
||||
<div class="af-section af-info">
|
||||
<h3>ℹ️ Information</h3>
|
||||
<p>Using: <strong>SDXL 1.0</strong></p>
|
||||
<p>Steps: <code>25</code> | CFG: <code>7.5</code> | Sampler: <code>DPM++ 2M Karras</code></p>
|
||||
</div>
|
||||
|
||||
<h2>Warning Section</h2>
|
||||
<div class="af-section af-warning">
|
||||
<h3>⚠️ Warning</h3>
|
||||
<p>This workflow requires:</p>
|
||||
<ol>
|
||||
<li>High VRAM (8GB+)</li>
|
||||
<li>Latest ComfyUI version</li>
|
||||
<li>SDXL compatible models</li>
|
||||
</ol>
|
||||
</div>
|
||||
|
||||
<h2>Column Layouts</h2>
|
||||
<div class="row">
|
||||
<div class="af-column-half-left">
|
||||
<div class="af-section af-positive">
|
||||
<h3>🎨 Style Settings</h3>
|
||||
<ul>
|
||||
<li>Style: Photorealistic</li>
|
||||
<li>Aspect: 16:9</li>
|
||||
<li>Quality: Ultra High</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="af-spacer"></div>
|
||||
|
||||
<div class="af-section af-info">
|
||||
<h3>⚙️ Technical</h3>
|
||||
<p>Resolution: <code>1920x1080</code></p>
|
||||
<p>Batch: <code>4</code></p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="af-column-half-right">
|
||||
<div class="af-section af-negative">
|
||||
<h3>🚫 Exclusions</h3>
|
||||
<ul>
|
||||
<li>No text in image</li>
|
||||
<li>Avoid oversaturation</li>
|
||||
<li>No watermarks</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="af-spacer"></div>
|
||||
|
||||
<div class="af-section af-warning">
|
||||
<h3>💡 Tips</h3>
|
||||
<p>Use lower CFG for more creative results</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h2>Clickable Links & Actions</h2>
|
||||
<div class="af-section af-info">
|
||||
<h3>🔗 Interactive Links</h3>
|
||||
|
||||
<!-- External links (opens in new tab with Ctrl+click) -->
|
||||
<h4>External link (opens in new tab with Ctrl+click)</h4>
|
||||
<p><a href="https://www.fullframestudios.ch/">Full Frame Studios - Alex Furer</a></p>
|
||||
|
||||
<h4>Anchor Links</h4>
|
||||
<p><a href="https://www.fullframestudios.ch/#ThreeDee">Full Frame Studios - Alex Furer - 3D</a></p>
|
||||
</div>
|
||||
|
||||
<h2>Custom Info Cards</h2>
|
||||
<div style="display: flex; gap: 10px; flex-wrap: wrap;">
|
||||
<div style="flex: 1; min-width: 150px; background: rgba(144, 238, 144, 0.1); border: 1px solid #90EE90; padding: 12px; border-radius: 6px; text-align: center;">
|
||||
<strong style="color: #90EE90; display: block; margin-bottom: 4px;">Steps</strong>
|
||||
<p style="margin: 0; font-size: 24px; color: #fff; font-weight: bold;">25</p>
|
||||
</div>
|
||||
|
||||
<div style="flex: 1; min-width: 150px; background: rgba(135, 206, 235, 0.1); border: 1px solid #87CEEB; padding: 12px; border-radius: 6px; text-align: center;">
|
||||
<strong style="color: #87CEEB; display: block; margin-bottom: 4px;">CFG Scale</strong>
|
||||
<p style="margin: 0; font-size: 24px; color: #fff; font-weight: bold;">7.5</p>
|
||||
</div>
|
||||
|
||||
<div style="flex: 1; min-width: 150px; background: rgba(186, 85, 211, 0.1); border: 1px solid #BA55D3; padding: 12px; border-radius: 6px; text-align: center;">
|
||||
<strong style="color: #BA55D3; display: block; margin-bottom: 4px;">Batch Size</strong>
|
||||
<p style="margin: 0; font-size: 24px; color: #fff; font-weight: bold;">4</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<!-- END: THIS CONTENT TO MAIN.PY FILE -->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,276 @@
|
||||
.af-html-note-container {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
min-height: 100px;
|
||||
background: var(--comfy-menu-bg, #2a2a2a);
|
||||
/* border: 1px solid var(--border-color, #555); */
|
||||
padding: 8px;
|
||||
box-sizing: border-box;
|
||||
overflow: hidden;
|
||||
cursor: default;
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', sans-serif;
|
||||
line-height: 1.6;
|
||||
color: var(--input-text, #ffffff);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.af-html-note-content {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow-y: auto;
|
||||
flex: 1;
|
||||
/* Prevent text selection */
|
||||
user-select: none;
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
cursor: default;
|
||||
/* Prevent keyboard focus */
|
||||
outline: none;
|
||||
}
|
||||
|
||||
/* Ensure content area can't be focused */
|
||||
.af-html-note-content:focus {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.af-html-note-editor {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: var(--comfy-menu-bg, #2a2a2a);
|
||||
border: 1px solid var(--border-color, #555);
|
||||
padding: 8px;
|
||||
font-family: 'Monaco', 'Consolas', 'Courier New', monospace;
|
||||
line-height: 1.4;
|
||||
color: var(--input-text, #ffffff);
|
||||
box-sizing: border-box;
|
||||
resize: none;
|
||||
outline: none;
|
||||
font-size: 14px;
|
||||
display: none;
|
||||
flex: 1;
|
||||
/* Add text selection capabilities */
|
||||
user-select: auto;
|
||||
-webkit-user-select: auto;
|
||||
-moz-user-select: auto;
|
||||
-ms-user-select: auto;
|
||||
cursor: text;
|
||||
}
|
||||
|
||||
/* Floating edit button */
|
||||
.af-floating-edit-btn {
|
||||
position: absolute;
|
||||
top: 4px;
|
||||
right: 4px;
|
||||
background: rgba(0, 0, 0, 0.8);
|
||||
border: 1px solid var(--border-color, #555);
|
||||
color: var(--input-text, #ffffff);
|
||||
border-radius: 3px;
|
||||
width: 22px;
|
||||
height: 22px;
|
||||
cursor: pointer;
|
||||
z-index: 1000;
|
||||
font-size: 11px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
opacity: 0.7;
|
||||
transition: opacity 0.2s ease;
|
||||
}
|
||||
|
||||
.af-floating-edit-btn:hover {
|
||||
opacity: 1;
|
||||
background: rgba(0, 0, 0, 0.9);
|
||||
border-color: #777;
|
||||
}
|
||||
|
||||
/* Enable link interactions only when Ctrl is held */
|
||||
.af-html-note-content a {
|
||||
color: #58a6ff;
|
||||
text-decoration: none;
|
||||
/* Links are never directly clickable - only via Ctrl */
|
||||
pointer-events: none;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
body.af-ctrl-active .af-html-note-content a {
|
||||
/* Only become clickable when Ctrl is held globally */
|
||||
pointer-events: auto;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
body.af-ctrl-active .af-html-note-content a:hover {
|
||||
color: #79c0ff;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.af-html-note-container.edit-mode .af-html-note-content {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.af-html-note-container.edit-mode .af-html-note-editor {
|
||||
display: block;
|
||||
}
|
||||
|
||||
/* Hide edit button in edit mode */
|
||||
.af-html-note-container.edit-mode .af-floating-edit-btn {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* Rest of your CSS remains the same... */
|
||||
.af-html-note-content h1, .af-html-note-content h2, .af-html-note-content h3,
|
||||
.af-html-note-content h4, .af-html-note-content h5, .af-html-note-content h6 {
|
||||
margin-top: 0;
|
||||
margin-bottom: 12px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.af-html-note-content h1 { font-size: 1.5em; }
|
||||
.af-html-note-content h2 { font-size: 1.3em; }
|
||||
.af-html-note-content h3 { font-size: 1.1em; }
|
||||
|
||||
.af-html-note-content .af-section {
|
||||
padding: 8px 16px;
|
||||
margin: 8px 0;
|
||||
border-radius: 6px;
|
||||
border-left: 4px solid;
|
||||
}
|
||||
|
||||
.af-html-note-content .af-section.af-positive {
|
||||
background: rgba(144, 238, 144, 0.1);
|
||||
border-left-color: #90EE90;
|
||||
}
|
||||
|
||||
.af-html-note-content .af-section.af-negative {
|
||||
background: rgba(255, 107, 107, 0.1);
|
||||
border-left-color: #FF6B6B;
|
||||
}
|
||||
|
||||
.af-html-note-content .af-section.af-neutral {
|
||||
background: rgba(224, 224, 224, 0.1);
|
||||
border-left-color: #E0E0E0;
|
||||
}
|
||||
|
||||
.af-html-note-content .af-section.af-info {
|
||||
background: rgba(135, 206, 235, 0.1);
|
||||
border-left-color: #87CEEB;
|
||||
}
|
||||
|
||||
.af-html-note-content .af-section.af-warning {
|
||||
background: rgba(255, 128, 0, 0.1);
|
||||
border-left-color: #FFD700;
|
||||
}
|
||||
|
||||
.af-html-note-content .af-section.af-yellow {
|
||||
background: rgba(255, 128, 0, 0.1);
|
||||
border-left-color: #FFD700;
|
||||
}
|
||||
|
||||
.af-html-note-content .af-section.af-blue {
|
||||
background: rgba(102, 105, 255, 0.1);
|
||||
border-left-color: #000099;
|
||||
}
|
||||
|
||||
.af-html-note-content .af-section.af-custom {
|
||||
background: rgba(186, 85, 211, 0.1);
|
||||
border-left-color: #BA55D3;
|
||||
}
|
||||
|
||||
.af-html-note-content .af-spacer-top { height: 2px; margin: 4px 0; }
|
||||
.af-html-note-content .af-spacer-mini { height: 4px; margin: 4px 0; }
|
||||
.af-html-note-content .af-spacer-small { height: 8px; margin: 4px 0; }
|
||||
.af-html-note-content .af-spacer { height: 16px; margin: 8px 0; }
|
||||
.af-html-note-content .af-spacer-large { height: 32px; margin: 16px 0; }
|
||||
.af-html-note-content .af-spacer-xl { height: 48px; margin: 24px 0; }
|
||||
|
||||
.af-html-note-content code {
|
||||
background: rgba(0,0,0,0.3);
|
||||
padding: 2px 6px;
|
||||
border-radius: 4px;
|
||||
font-family: 'Monaco', 'Consolas', 'Courier New', monospace;
|
||||
font-size: 0.9em;
|
||||
color: #f0f6fc;
|
||||
}
|
||||
|
||||
.af-html-note-content pre {
|
||||
background: rgba(0,0,0,0.4);
|
||||
border: 1px solid #444;
|
||||
border-radius: 6px;
|
||||
padding: 12px;
|
||||
margin: 16px 0;
|
||||
overflow-x: auto;
|
||||
}
|
||||
|
||||
.af-html-note-content pre code {
|
||||
background: transparent;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.af-html-note-content ul, .af-html-note-content ol {
|
||||
padding-left: 20px;
|
||||
margin: 12px 0;
|
||||
}
|
||||
|
||||
.af-html-note-content li { margin: 4px 0; }
|
||||
.af-html-note-content p { margin: 8px 0; }
|
||||
|
||||
.af-html-note-content table {
|
||||
border-collapse: collapse;
|
||||
width: 100%;
|
||||
margin: 16px 0;
|
||||
}
|
||||
|
||||
.af-html-note-content th, .af-html-note-content td {
|
||||
border: 1px solid var(--border-color, #555);
|
||||
padding: 8px 12px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.af-html-note-content th {
|
||||
background: rgba(255,255,255,0.1);
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.af-html-note-content hr {
|
||||
border: none;
|
||||
border-top: 1px solid var(--border-color, #555);
|
||||
margin: 16px 0;
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
.af-html-note-container::-webkit-scrollbar { width: 8px; }
|
||||
.af-html-note-container::-webkit-scrollbar-track { background: rgba(0,0,0,0.1); }
|
||||
.af-html-note-container::-webkit-scrollbar-thumb {
|
||||
background: var(--border-color, #555);
|
||||
border-radius: 4px;
|
||||
}
|
||||
.af-html-note-container::-webkit-scrollbar-thumb:hover { background: #777; }
|
||||
|
||||
.af-html-note-editor::-webkit-scrollbar { width: 8px; }
|
||||
.af-html-note-editor::-webkit-scrollbar-track { background: rgba(0,0,0,0.1); }
|
||||
.af-html-note-editor::-webkit-scrollbar-thumb {
|
||||
background: var(--border-color, #555);
|
||||
border-radius: 4px;
|
||||
}
|
||||
.af-html-note-editor::-webkit-scrollbar-thumb:hover { background: #777; }
|
||||
|
||||
/* ****** MY OWN STYLES ****** */
|
||||
.af-column-half-left {
|
||||
box-sizing: border-box;
|
||||
float: left;
|
||||
width: 49%;
|
||||
margin-right: 1% !important;
|
||||
}
|
||||
.af-column-half-right {
|
||||
box-sizing: border-box;
|
||||
float: left;
|
||||
width: 49%;
|
||||
margin-left: 1% !important;
|
||||
}
|
||||
.row:after {
|
||||
content: "";
|
||||
display: table;
|
||||
clear: both;
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
# node.py - Main entry point for ComfyUI registry
|
||||
|
||||
from .AF_Enhanced_HTML_Note import NODE_CLASS_MAPPINGS, NODE_DISPLAY_NAME_MAPPINGS
|
||||
|
||||
__all__ = ['NODE_CLASS_MAPPINGS', 'NODE_DISPLAY_NAME_MAPPINGS']
|
||||
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"name": "comfyui-af-enhanced-html-note",
|
||||
"version": "0.0.12",
|
||||
"description": "A ComfyUI Note node with HTML capabilities. Create notes, UI's and ReadMe's directly inside the workflow using rich HTML formatting.",
|
||||
"author": "Alex Furer",
|
||||
"license": "MIT",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/alFrame/ComfyUI-AF-Enhanced-HTML-Note"
|
||||
},
|
||||
"nodepath": "custom_nodes/ComfyUI-AF-Enhanced-HTML-Note"
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
[project]
|
||||
name = "comfyui-af-enhanced-html-note"
|
||||
description = "A ComfyUI Note node with HTML capabilities. Create notes, UI's and ReadMe's directly inside the workflow using rich HTML formatting."
|
||||
version = "0.0.12"
|
||||
license = {file = "LICENSE"}
|
||||
dependencies = []
|
||||
|
||||
[project.urls]
|
||||
Repository = "https://github.com/alFrame/ComfyUI-AF-Enhanced-HTML-Note"
|
||||
|
||||
[tool.comfy]
|
||||
PublisherId = "alframe"
|
||||
DisplayName = "ComfyUI AF - Enhanced HTML Note"
|
||||
Icon = "https://fullframestudios.ch/ComfyUI-Icon/icon.png"
|
||||
@@ -0,0 +1,276 @@
|
||||
.af-html-note-container {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
min-height: 100px;
|
||||
background: var(--comfy-menu-bg, #2a2a2a);
|
||||
/* border: 1px solid var(--border-color, #555); */
|
||||
padding: 8px;
|
||||
box-sizing: border-box;
|
||||
overflow: hidden;
|
||||
cursor: default;
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', sans-serif;
|
||||
line-height: 1.6;
|
||||
color: var(--input-text, #ffffff);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.af-html-note-content {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow-y: auto;
|
||||
flex: 1;
|
||||
/* Prevent text selection */
|
||||
user-select: none;
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
cursor: default;
|
||||
/* Prevent keyboard focus */
|
||||
outline: none;
|
||||
}
|
||||
|
||||
/* Ensure content area can't be focused */
|
||||
.af-html-note-content:focus {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.af-html-note-editor {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: var(--comfy-menu-bg, #2a2a2a);
|
||||
border: 1px solid var(--border-color, #555);
|
||||
padding: 8px;
|
||||
font-family: 'Monaco', 'Consolas', 'Courier New', monospace;
|
||||
line-height: 1.4;
|
||||
color: var(--input-text, #ffffff);
|
||||
box-sizing: border-box;
|
||||
resize: none;
|
||||
outline: none;
|
||||
font-size: 14px;
|
||||
display: none;
|
||||
flex: 1;
|
||||
/* Add text selection capabilities */
|
||||
user-select: auto;
|
||||
-webkit-user-select: auto;
|
||||
-moz-user-select: auto;
|
||||
-ms-user-select: auto;
|
||||
cursor: text;
|
||||
}
|
||||
|
||||
/* Floating edit button */
|
||||
.af-floating-edit-btn {
|
||||
position: absolute;
|
||||
top: 4px;
|
||||
right: 4px;
|
||||
background: rgba(0, 0, 0, 0.8);
|
||||
border: 1px solid var(--border-color, #555);
|
||||
color: var(--input-text, #ffffff);
|
||||
border-radius: 3px;
|
||||
width: 22px;
|
||||
height: 22px;
|
||||
cursor: pointer;
|
||||
z-index: 1000;
|
||||
font-size: 11px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
opacity: 0.7;
|
||||
transition: opacity 0.2s ease;
|
||||
}
|
||||
|
||||
.af-floating-edit-btn:hover {
|
||||
opacity: 1;
|
||||
background: rgba(0, 0, 0, 0.9);
|
||||
border-color: #777;
|
||||
}
|
||||
|
||||
/* Enable link interactions only when Ctrl is held */
|
||||
.af-html-note-content a {
|
||||
color: #58a6ff;
|
||||
text-decoration: none;
|
||||
/* Links are never directly clickable - only via Ctrl */
|
||||
pointer-events: none;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
body.af-ctrl-active .af-html-note-content a {
|
||||
/* Only become clickable when Ctrl is held globally */
|
||||
pointer-events: auto;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
body.af-ctrl-active .af-html-note-content a:hover {
|
||||
color: #79c0ff;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.af-html-note-container.edit-mode .af-html-note-content {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.af-html-note-container.edit-mode .af-html-note-editor {
|
||||
display: block;
|
||||
}
|
||||
|
||||
/* Hide edit button in edit mode */
|
||||
.af-html-note-container.edit-mode .af-floating-edit-btn {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* Rest of your CSS remains the same... */
|
||||
.af-html-note-content h1, .af-html-note-content h2, .af-html-note-content h3,
|
||||
.af-html-note-content h4, .af-html-note-content h5, .af-html-note-content h6 {
|
||||
margin-top: 0;
|
||||
margin-bottom: 12px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.af-html-note-content h1 { font-size: 1.5em; }
|
||||
.af-html-note-content h2 { font-size: 1.3em; }
|
||||
.af-html-note-content h3 { font-size: 1.1em; }
|
||||
|
||||
.af-html-note-content .af-section {
|
||||
padding: 8px 16px;
|
||||
margin: 8px 0;
|
||||
border-radius: 6px;
|
||||
border-left: 4px solid;
|
||||
}
|
||||
|
||||
.af-html-note-content .af-section.af-positive {
|
||||
background: rgba(144, 238, 144, 0.1);
|
||||
border-left-color: #90EE90;
|
||||
}
|
||||
|
||||
.af-html-note-content .af-section.af-negative {
|
||||
background: rgba(255, 107, 107, 0.1);
|
||||
border-left-color: #FF6B6B;
|
||||
}
|
||||
|
||||
.af-html-note-content .af-section.af-neutral {
|
||||
background: rgba(224, 224, 224, 0.1);
|
||||
border-left-color: #E0E0E0;
|
||||
}
|
||||
|
||||
.af-html-note-content .af-section.af-info {
|
||||
background: rgba(135, 206, 235, 0.1);
|
||||
border-left-color: #87CEEB;
|
||||
}
|
||||
|
||||
.af-html-note-content .af-section.af-warning {
|
||||
background: rgba(255, 128, 0, 0.1);
|
||||
border-left-color: #FFD700;
|
||||
}
|
||||
|
||||
.af-html-note-content .af-section.af-yellow {
|
||||
background: rgba(255, 128, 0, 0.1);
|
||||
border-left-color: #FFD700;
|
||||
}
|
||||
|
||||
.af-html-note-content .af-section.af-blue {
|
||||
background: rgba(102, 105, 255, 0.1);
|
||||
border-left-color: #000099;
|
||||
}
|
||||
|
||||
.af-html-note-content .af-section.af-custom {
|
||||
background: rgba(186, 85, 211, 0.1);
|
||||
border-left-color: #BA55D3;
|
||||
}
|
||||
|
||||
.af-html-note-content .af-spacer-top { height: 2px; margin: 4px 0; }
|
||||
.af-html-note-content .af-spacer-mini { height: 4px; margin: 4px 0; }
|
||||
.af-html-note-content .af-spacer-small { height: 8px; margin: 4px 0; }
|
||||
.af-html-note-content .af-spacer { height: 16px; margin: 8px 0; }
|
||||
.af-html-note-content .af-spacer-large { height: 32px; margin: 16px 0; }
|
||||
.af-html-note-content .af-spacer-xl { height: 48px; margin: 24px 0; }
|
||||
|
||||
.af-html-note-content code {
|
||||
background: rgba(0,0,0,0.3);
|
||||
padding: 2px 6px;
|
||||
border-radius: 4px;
|
||||
font-family: 'Monaco', 'Consolas', 'Courier New', monospace;
|
||||
font-size: 0.9em;
|
||||
color: #f0f6fc;
|
||||
}
|
||||
|
||||
.af-html-note-content pre {
|
||||
background: rgba(0,0,0,0.4);
|
||||
border: 1px solid #444;
|
||||
border-radius: 6px;
|
||||
padding: 12px;
|
||||
margin: 16px 0;
|
||||
overflow-x: auto;
|
||||
}
|
||||
|
||||
.af-html-note-content pre code {
|
||||
background: transparent;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.af-html-note-content ul, .af-html-note-content ol {
|
||||
padding-left: 20px;
|
||||
margin: 12px 0;
|
||||
}
|
||||
|
||||
.af-html-note-content li { margin: 4px 0; }
|
||||
.af-html-note-content p { margin: 8px 0; }
|
||||
|
||||
.af-html-note-content table {
|
||||
border-collapse: collapse;
|
||||
width: 100%;
|
||||
margin: 16px 0;
|
||||
}
|
||||
|
||||
.af-html-note-content th, .af-html-note-content td {
|
||||
border: 1px solid var(--border-color, #555);
|
||||
padding: 8px 12px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.af-html-note-content th {
|
||||
background: rgba(255,255,255,0.1);
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.af-html-note-content hr {
|
||||
border: none;
|
||||
border-top: 1px solid var(--border-color, #555);
|
||||
margin: 16px 0;
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
.af-html-note-container::-webkit-scrollbar { width: 8px; }
|
||||
.af-html-note-container::-webkit-scrollbar-track { background: rgba(0,0,0,0.1); }
|
||||
.af-html-note-container::-webkit-scrollbar-thumb {
|
||||
background: var(--border-color, #555);
|
||||
border-radius: 4px;
|
||||
}
|
||||
.af-html-note-container::-webkit-scrollbar-thumb:hover { background: #777; }
|
||||
|
||||
.af-html-note-editor::-webkit-scrollbar { width: 8px; }
|
||||
.af-html-note-editor::-webkit-scrollbar-track { background: rgba(0,0,0,0.1); }
|
||||
.af-html-note-editor::-webkit-scrollbar-thumb {
|
||||
background: var(--border-color, #555);
|
||||
border-radius: 4px;
|
||||
}
|
||||
.af-html-note-editor::-webkit-scrollbar-thumb:hover { background: #777; }
|
||||
|
||||
/* ****** MY OWN STYLES ****** */
|
||||
.af-column-half-left {
|
||||
box-sizing: border-box;
|
||||
float: left;
|
||||
width: 49%;
|
||||
margin-right: 1% !important;
|
||||
}
|
||||
.af-column-half-right {
|
||||
box-sizing: border-box;
|
||||
float: left;
|
||||
width: 49%;
|
||||
margin-left: 1% !important;
|
||||
}
|
||||
.row:after {
|
||||
content: "";
|
||||
display: table;
|
||||
clear: both;
|
||||
}
|
||||
@@ -0,0 +1,247 @@
|
||||
// File: web/AF-Enhanced-HTML-Note.js
|
||||
|
||||
import { app } from "../../scripts/app.js";
|
||||
|
||||
// Inject styles from external CSS file
|
||||
function injectStyles() {
|
||||
const styleId = 'af-html-note-styles';
|
||||
if (!document.getElementById(styleId)) {
|
||||
const link = document.createElement('link');
|
||||
link.id = styleId;
|
||||
link.rel = 'stylesheet';
|
||||
|
||||
// Use the same base path as our JS file
|
||||
const jsPath = import.meta.url;
|
||||
const basePath = jsPath.substring(0, jsPath.lastIndexOf('/'));
|
||||
link.href = basePath + '/AF-Enhanced-HTML-Note.css';
|
||||
|
||||
document.head.appendChild(link);
|
||||
}
|
||||
}
|
||||
|
||||
app.registerExtension({
|
||||
name: "AF.enhanced.html.note",
|
||||
|
||||
async beforeRegisterNodeDef(nodeType, nodeData, app) {
|
||||
if (nodeData.name === "AF_Enhanced_HTML_Note") {
|
||||
injectStyles();
|
||||
|
||||
// Store the original onNodeCreated
|
||||
const originalOnNodeCreated = nodeType.prototype.onNodeCreated;
|
||||
|
||||
nodeType.prototype.onNodeCreated = function() {
|
||||
const result = originalOnNodeCreated?.apply(this, arguments);
|
||||
|
||||
this.isEditMode = false;
|
||||
this.size = [400, 300];
|
||||
|
||||
// Don't hide the original widget - instead, replace it with our custom display
|
||||
setTimeout(() => {
|
||||
const htmlWidget = this.widgets?.find(w => w.name === "html_content");
|
||||
if (htmlWidget && htmlWidget.element) {
|
||||
// Store the original value
|
||||
this.htmlContent = htmlWidget.value;
|
||||
|
||||
// Create our custom container
|
||||
this.createHTMLNoteDisplay(this.htmlContent);
|
||||
|
||||
// Hide the original widget but keep its value
|
||||
htmlWidget.computeSize = () => [0, 0];
|
||||
htmlWidget.element.style.display = 'none';
|
||||
}
|
||||
}, 0);
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
nodeType.prototype.createHTMLNoteDisplay = function(content) {
|
||||
// Create container element
|
||||
this.containerElement = document.createElement("div");
|
||||
this.containerElement.className = "af-html-note-container";
|
||||
|
||||
// Create HTML content display
|
||||
this.contentElement = document.createElement("div");
|
||||
this.contentElement.className = "af-html-note-content";
|
||||
this.contentElement.innerHTML = content;
|
||||
|
||||
// Create editor element
|
||||
this.editorElement = document.createElement("textarea");
|
||||
this.editorElement.className = "af-html-note-editor";
|
||||
this.editorElement.value = content;
|
||||
|
||||
// Create floating edit button
|
||||
this.editButton = document.createElement("div");
|
||||
this.editButton.className = "af-floating-edit-btn";
|
||||
this.editButton.innerHTML = "✏️";
|
||||
this.editButton.title = "Edit HTML";
|
||||
|
||||
// Append all elements to container
|
||||
this.containerElement.appendChild(this.contentElement);
|
||||
this.containerElement.appendChild(this.editorElement);
|
||||
this.containerElement.appendChild(this.editButton);
|
||||
|
||||
// Edit button click handler
|
||||
this.editButton.addEventListener('click', (e) => {
|
||||
if (!this.isEditMode) {
|
||||
this.enterEditMode();
|
||||
e.stopPropagation();
|
||||
}
|
||||
});
|
||||
|
||||
// Add back double-click editing (user-friendly alternative)
|
||||
this.contentElement.addEventListener('dblclick', (e) => {
|
||||
if (!this.isEditMode) {
|
||||
this.enterEditMode();
|
||||
e.stopPropagation();
|
||||
}
|
||||
});
|
||||
|
||||
// Handle links
|
||||
this.handleLinksInHTML();
|
||||
|
||||
// Handle editor events
|
||||
this.editorElement.addEventListener('keydown', (e) => {
|
||||
if (e.key === 'Escape') {
|
||||
this.exitEditMode();
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
}
|
||||
});
|
||||
|
||||
// Comment
|
||||
this.contentElement.setAttribute('tabindex', '-1');
|
||||
|
||||
this.editorElement.addEventListener('blur', () => {
|
||||
setTimeout(() => {
|
||||
if (this.isEditMode && document.activeElement !== this.editorElement) {
|
||||
this.exitEditMode();
|
||||
}
|
||||
}, 10);
|
||||
});
|
||||
|
||||
this.contentElement.addEventListener('mousedown', (e) => {
|
||||
// Prevent the content area from getting focus on click
|
||||
e.preventDefault();
|
||||
|
||||
// But don't stop propagation - let ComfyUI handle node selection
|
||||
// Only prevent the default focus behavior
|
||||
});
|
||||
|
||||
// Add as DOM widget
|
||||
this.addDOMWidget("html_note_display", "div", this.containerElement);
|
||||
};
|
||||
|
||||
nodeType.prototype.enterEditMode = function() {
|
||||
if (this.isEditMode) return;
|
||||
|
||||
this.isEditMode = true;
|
||||
this.containerElement.classList.add('edit-mode');
|
||||
this.editorElement.value = this.htmlContent;
|
||||
|
||||
setTimeout(() => {
|
||||
this.editorElement.focus();
|
||||
this.editorElement.select();
|
||||
}, 10);
|
||||
};
|
||||
|
||||
nodeType.prototype.exitEditMode = function() {
|
||||
if (!this.isEditMode) return;
|
||||
|
||||
this.isEditMode = false;
|
||||
this.containerElement.classList.remove('edit-mode');
|
||||
this.htmlContent = this.editorElement.value;
|
||||
this.contentElement.innerHTML = this.htmlContent;
|
||||
|
||||
// Update the original widget value
|
||||
const htmlWidget = this.widgets?.find(w => w.name === "html_content");
|
||||
if (htmlWidget) {
|
||||
htmlWidget.value = this.htmlContent;
|
||||
if (htmlWidget.callback) {
|
||||
htmlWidget.callback(this.htmlContent);
|
||||
}
|
||||
}
|
||||
|
||||
// Re-attach link handlers
|
||||
this.handleLinksInHTML();
|
||||
};
|
||||
|
||||
// Updated link handler - REMOVED JavaScript execution
|
||||
nodeType.prototype.handleLinksInHTML = function() {
|
||||
if (!this.contentElement) return;
|
||||
|
||||
const links = this.contentElement.querySelectorAll('a');
|
||||
links.forEach(link => {
|
||||
// Remove any existing onclick handlers to prevent JavaScript execution
|
||||
link.onclick = null;
|
||||
|
||||
link.addEventListener('click', (e) => {
|
||||
// Only allow clicks when Ctrl is held
|
||||
if (!document.body.classList.contains('af-ctrl-active')) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
return false;
|
||||
}
|
||||
|
||||
const href = link.getAttribute('href');
|
||||
|
||||
// Handle different types of links
|
||||
if (href) {
|
||||
// External URLs and anchor links - open in new tab
|
||||
if (href.startsWith('http://') ||
|
||||
href.startsWith('https://') ||
|
||||
href.startsWith('mailto:') ||
|
||||
href.startsWith('tel:')) {
|
||||
e.preventDefault();
|
||||
window.open(href, '_blank');
|
||||
}
|
||||
// Internal anchor links (page navigation) - let browser handle
|
||||
else if (href.startsWith('#') || href === '#') {
|
||||
// Allow default behavior for anchor links
|
||||
// They will navigate within the same page
|
||||
}
|
||||
// JavaScript links - BLOCK for security
|
||||
else if (href.startsWith('javascript:')) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
console.warn('AF HTML Note: JavaScript links are disabled for security');
|
||||
return false;
|
||||
}
|
||||
// Relative URLs and other links - open in new tab
|
||||
else {
|
||||
e.preventDefault();
|
||||
window.open(href, '_blank');
|
||||
}
|
||||
}
|
||||
|
||||
e.stopPropagation();
|
||||
return false;
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
// Global Ctrl key handling
|
||||
let ctrlKeyActive = false;
|
||||
|
||||
document.addEventListener('keydown', (e) => {
|
||||
if (e.key === 'Control') {
|
||||
ctrlKeyActive = true;
|
||||
document.body.classList.add('af-ctrl-active');
|
||||
}
|
||||
});
|
||||
|
||||
document.addEventListener('keyup', (e) => {
|
||||
if (e.key === 'Control') {
|
||||
ctrlKeyActive = false;
|
||||
document.body.classList.remove('af-ctrl-active');
|
||||
}
|
||||
});
|
||||
|
||||
// Clean up when node is removed
|
||||
const originalOnRemoved = nodeType.prototype.onRemoved;
|
||||
nodeType.prototype.onRemoved = function() {
|
||||
document.body.classList.remove('af-ctrl-active');
|
||||
originalOnRemoved?.apply(this, arguments);
|
||||
};
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -1,470 +0,0 @@
|
||||
// File: web/AF_Enhanced_HTML_Note.js
|
||||
|
||||
import { app } from "../../scripts/app.js";
|
||||
|
||||
// Define inline CSS styles
|
||||
const AF_HTML_NOTE_STYLES = `
|
||||
.af-html-note-container {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
min-height: 100px;
|
||||
background: var(--comfy-menu-bg, #2a2a2a);
|
||||
border: 1px solid var(--border-color, #555);
|
||||
padding: 8px;
|
||||
box-sizing: border-box;
|
||||
overflow: hidden;
|
||||
cursor: default;
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', sans-serif;
|
||||
line-height: 1.6;
|
||||
color: var(--input-text, #ffffff);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.af-html-note-content {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow-y: auto;
|
||||
flex: 1;
|
||||
/* NO pointer-events here - let ComfyUI handle interactions */
|
||||
}
|
||||
|
||||
.af-html-note-editor {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: var(--comfy-menu-bg, #2a2a2a);
|
||||
border: 1px solid var(--border-color, #555);
|
||||
padding: 8px;
|
||||
font-family: 'Monaco', 'Consolas', 'Courier New', monospace;
|
||||
line-height: 1.4;
|
||||
color: var(--input-text, #ffffff);
|
||||
box-sizing: border-box;
|
||||
resize: none;
|
||||
outline: none;
|
||||
font-size: 14px;
|
||||
display: none;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
/* Floating edit button */
|
||||
.af-floating-edit-btn {
|
||||
position: absolute;
|
||||
top: 4px;
|
||||
right: 4px;
|
||||
background: rgba(0, 0, 0, 0.8);
|
||||
border: 1px solid var(--border-color, #555);
|
||||
color: var(--input-text, #ffffff);
|
||||
border-radius: 3px;
|
||||
width: 22px;
|
||||
height: 22px;
|
||||
cursor: pointer;
|
||||
z-index: 1000;
|
||||
font-size: 11px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
opacity: 0.7;
|
||||
transition: opacity 0.2s ease;
|
||||
}
|
||||
|
||||
.af-floating-edit-btn:hover {
|
||||
opacity: 1;
|
||||
background: rgba(0, 0, 0, 0.9);
|
||||
border-color: #777;
|
||||
}
|
||||
|
||||
/* Enable link interactions only when Ctrl is held */
|
||||
.af-html-note-content a {
|
||||
color: #58a6ff;
|
||||
text-decoration: none;
|
||||
/* Links are never directly clickable - only via Ctrl */
|
||||
pointer-events: none;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
body.af-ctrl-active .af-html-note-content a {
|
||||
/* Only become clickable when Ctrl is held globally */
|
||||
pointer-events: auto;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
body.af-ctrl-active .af-html-note-content a:hover {
|
||||
color: #79c0ff;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.af-html-note-container.edit-mode .af-html-note-content {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.af-html-note-container.edit-mode .af-html-note-editor {
|
||||
display: block;
|
||||
}
|
||||
|
||||
/* Hide edit button in edit mode */
|
||||
.af-html-note-container.edit-mode .af-floating-edit-btn {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* Rest of your CSS remains the same... */
|
||||
.af-html-note-content h1, .af-html-note-content h2, .af-html-note-content h3,
|
||||
.af-html-note-content h4, .af-html-note-content h5, .af-html-note-content h6 {
|
||||
margin-top: 0;
|
||||
margin-bottom: 12px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.af-html-note-content h1 { font-size: 1.5em; }
|
||||
.af-html-note-content h2 { font-size: 1.3em; }
|
||||
.af-html-note-content h3 { font-size: 1.1em; }
|
||||
|
||||
.af-html-note-content .af-section {
|
||||
padding: 8px 16px;
|
||||
margin: 8px 0;
|
||||
border-radius: 6px;
|
||||
border-left: 4px solid;
|
||||
}
|
||||
|
||||
.af-html-note-content .af-section.af-positive {
|
||||
background: rgba(144, 238, 144, 0.1);
|
||||
border-left-color: #90EE90;
|
||||
}
|
||||
|
||||
.af-html-note-content .af-section.af-negative {
|
||||
background: rgba(255, 107, 107, 0.1);
|
||||
border-left-color: #FF6B6B;
|
||||
}
|
||||
|
||||
.af-html-note-content .af-section.af-neutral {
|
||||
background: rgba(224, 224, 224, 0.1);
|
||||
border-left-color: #E0E0E0;
|
||||
}
|
||||
|
||||
.af-html-note-content .af-section.af-info {
|
||||
background: rgba(135, 206, 235, 0.1);
|
||||
border-left-color: #87CEEB;
|
||||
}
|
||||
|
||||
.af-html-note-content .af-section.af-warning {
|
||||
background: rgba(255, 128, 0, 0.1);
|
||||
border-left-color: #FFD700;
|
||||
}
|
||||
|
||||
.af-html-note-content .af-section.af-yellow {
|
||||
background: rgba(255, 128, 0, 0.1);
|
||||
border-left-color: #FFD700;
|
||||
}
|
||||
|
||||
.af-html-note-content .af-section.af-blue {
|
||||
background: rgba(102, 105, 255, 0.1);
|
||||
border-left-color: #000099;
|
||||
}
|
||||
|
||||
.af-html-note-content .af-section.af-custom {
|
||||
background: rgba(186, 85, 211, 0.1);
|
||||
border-left-color: #BA55D3;
|
||||
}
|
||||
|
||||
.af-html-note-content .af-spacer-top { height: 2px; margin: 4px 0; }
|
||||
.af-html-note-content .af-spacer-mini { height: 4px; margin: 4px 0; }
|
||||
.af-html-note-content .af-spacer-small { height: 8px; margin: 4px 0; }
|
||||
.af-html-note-content .af-spacer { height: 16px; margin: 8px 0; }
|
||||
.af-html-note-content .af-spacer-large { height: 32px; margin: 16px 0; }
|
||||
.af-html-note-content .af-spacer-xl { height: 48px; margin: 24px 0; }
|
||||
|
||||
.af-html-note-content code {
|
||||
background: rgba(0,0,0,0.3);
|
||||
padding: 2px 6px;
|
||||
border-radius: 4px;
|
||||
font-family: 'Monaco', 'Consolas', 'Courier New', monospace;
|
||||
font-size: 0.9em;
|
||||
color: #f0f6fc;
|
||||
}
|
||||
|
||||
.af-html-note-content pre {
|
||||
background: rgba(0,0,0,0.4);
|
||||
border: 1px solid #444;
|
||||
border-radius: 6px;
|
||||
padding: 12px;
|
||||
margin: 16px 0;
|
||||
overflow-x: auto;
|
||||
}
|
||||
|
||||
.af-html-note-content pre code {
|
||||
background: transparent;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.af-html-note-content ul, .af-html-note-content ol {
|
||||
padding-left: 20px;
|
||||
margin: 12px 0;
|
||||
}
|
||||
|
||||
.af-html-note-content li { margin: 4px 0; }
|
||||
.af-html-note-content p { margin: 8px 0; }
|
||||
|
||||
.af-html-note-content table {
|
||||
border-collapse: collapse;
|
||||
width: 100%;
|
||||
margin: 16px 0;
|
||||
}
|
||||
|
||||
.af-html-note-content th, .af-html-note-content td {
|
||||
border: 1px solid var(--border-color, #555);
|
||||
padding: 8px 12px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.af-html-note-content th {
|
||||
background: rgba(255,255,255,0.1);
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.af-html-note-content hr {
|
||||
border: none;
|
||||
border-top: 1px solid var(--border-color, #555);
|
||||
margin: 16px 0;
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
.af-html-note-container::-webkit-scrollbar { width: 8px; }
|
||||
.af-html-note-container::-webkit-scrollbar-track { background: rgba(0,0,0,0.1); }
|
||||
.af-html-note-container::-webkit-scrollbar-thumb {
|
||||
background: var(--border-color, #555);
|
||||
border-radius: 4px;
|
||||
}
|
||||
.af-html-note-container::-webkit-scrollbar-thumb:hover { background: #777; }
|
||||
|
||||
.af-html-note-editor::-webkit-scrollbar { width: 8px; }
|
||||
.af-html-note-editor::-webkit-scrollbar-track { background: rgba(0,0,0,0.1); }
|
||||
.af-html-note-editor::-webkit-scrollbar-thumb {
|
||||
background: var(--border-color, #555);
|
||||
border-radius: 4px;
|
||||
}
|
||||
.af-html-note-editor::-webkit-scrollbar-thumb:hover { background: #777; }
|
||||
|
||||
/* ****** MY OWN STYLES ****** */
|
||||
.af-column-half-left {
|
||||
box-sizing: border-box;
|
||||
float: left;
|
||||
width: 49%;
|
||||
margin-right: 1% !important;
|
||||
}
|
||||
.af-column-half-right {
|
||||
box-sizing: border-box;
|
||||
float: left;
|
||||
width: 49%;
|
||||
margin-left: 1% !important;
|
||||
}
|
||||
.row:after {
|
||||
content: "";
|
||||
display: table;
|
||||
clear: both;
|
||||
}
|
||||
`;
|
||||
|
||||
// Inject styles
|
||||
function injectStyles() {
|
||||
const styleId = 'af-html-note-styles';
|
||||
if (!document.getElementById(styleId)) {
|
||||
const style = document.createElement('style');
|
||||
style.id = styleId;
|
||||
style.textContent = AF_HTML_NOTE_STYLES;
|
||||
document.head.appendChild(style);
|
||||
}
|
||||
}
|
||||
|
||||
app.registerExtension({
|
||||
name: "AF.enhanced.html.note",
|
||||
|
||||
async beforeRegisterNodeDef(nodeType, nodeData, app) {
|
||||
if (nodeData.name === "AF_Enhanced_HTML_Note") {
|
||||
injectStyles();
|
||||
|
||||
// Store the original onNodeCreated
|
||||
const originalOnNodeCreated = nodeType.prototype.onNodeCreated;
|
||||
|
||||
nodeType.prototype.onNodeCreated = function() {
|
||||
const result = originalOnNodeCreated?.apply(this, arguments);
|
||||
|
||||
this.isEditMode = false;
|
||||
this.size = [400, 300];
|
||||
|
||||
// Don't hide the original widget - instead, replace it with our custom display
|
||||
setTimeout(() => {
|
||||
const htmlWidget = this.widgets?.find(w => w.name === "html_content");
|
||||
if (htmlWidget && htmlWidget.element) {
|
||||
// Store the original value
|
||||
this.htmlContent = htmlWidget.value;
|
||||
|
||||
// Create our custom container
|
||||
this.createHTMLNoteDisplay(this.htmlContent);
|
||||
|
||||
// Hide the original widget but keep its value
|
||||
htmlWidget.computeSize = () => [0, 0];
|
||||
htmlWidget.element.style.display = 'none';
|
||||
}
|
||||
}, 0);
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
nodeType.prototype.createHTMLNoteDisplay = function(content) {
|
||||
// Create container element
|
||||
this.containerElement = document.createElement("div");
|
||||
this.containerElement.className = "af-html-note-container";
|
||||
|
||||
// Create HTML content display
|
||||
this.contentElement = document.createElement("div");
|
||||
this.contentElement.className = "af-html-note-content";
|
||||
this.contentElement.innerHTML = content;
|
||||
|
||||
// Create editor element
|
||||
this.editorElement = document.createElement("textarea");
|
||||
this.editorElement.className = "af-html-note-editor";
|
||||
this.editorElement.value = content;
|
||||
|
||||
// Create floating edit button
|
||||
this.editButton = document.createElement("div");
|
||||
this.editButton.className = "af-floating-edit-btn";
|
||||
this.editButton.innerHTML = "✏️";
|
||||
this.editButton.title = "Edit HTML";
|
||||
|
||||
// Append all elements to container
|
||||
this.containerElement.appendChild(this.contentElement);
|
||||
this.containerElement.appendChild(this.editorElement);
|
||||
this.containerElement.appendChild(this.editButton);
|
||||
|
||||
// Edit button click handler
|
||||
this.editButton.addEventListener('click', (e) => {
|
||||
if (!this.isEditMode) {
|
||||
this.enterEditMode();
|
||||
e.stopPropagation();
|
||||
}
|
||||
});
|
||||
|
||||
// Add back double-click editing (user-friendly alternative)
|
||||
this.contentElement.addEventListener('dblclick', (e) => {
|
||||
if (!this.isEditMode) {
|
||||
this.enterEditMode();
|
||||
e.stopPropagation();
|
||||
}
|
||||
});
|
||||
|
||||
// Handle links
|
||||
this.handleLinksInHTML();
|
||||
|
||||
// Handle editor events
|
||||
this.editorElement.addEventListener('keydown', (e) => {
|
||||
if (e.key === 'Escape') {
|
||||
this.exitEditMode();
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
}
|
||||
});
|
||||
|
||||
this.editorElement.addEventListener('blur', () => {
|
||||
setTimeout(() => {
|
||||
if (this.isEditMode && document.activeElement !== this.editorElement) {
|
||||
this.exitEditMode();
|
||||
}
|
||||
}, 10);
|
||||
});
|
||||
|
||||
// Add as DOM widget
|
||||
this.addDOMWidget("html_note_display", "div", this.containerElement);
|
||||
};
|
||||
|
||||
nodeType.prototype.enterEditMode = function() {
|
||||
if (this.isEditMode) return;
|
||||
|
||||
this.isEditMode = true;
|
||||
this.containerElement.classList.add('edit-mode');
|
||||
this.editorElement.value = this.htmlContent;
|
||||
|
||||
setTimeout(() => {
|
||||
this.editorElement.focus();
|
||||
this.editorElement.select();
|
||||
}, 10);
|
||||
};
|
||||
|
||||
nodeType.prototype.exitEditMode = function() {
|
||||
if (!this.isEditMode) return;
|
||||
|
||||
this.isEditMode = false;
|
||||
this.containerElement.classList.remove('edit-mode');
|
||||
this.htmlContent = this.editorElement.value;
|
||||
this.contentElement.innerHTML = this.htmlContent;
|
||||
|
||||
// Update the original widget value
|
||||
const htmlWidget = this.widgets?.find(w => w.name === "html_content");
|
||||
if (htmlWidget) {
|
||||
htmlWidget.value = this.htmlContent;
|
||||
if (htmlWidget.callback) {
|
||||
htmlWidget.callback(this.htmlContent);
|
||||
}
|
||||
}
|
||||
|
||||
// Re-attach link handlers
|
||||
this.handleLinksInHTML();
|
||||
};
|
||||
|
||||
nodeType.prototype.handleLinksInHTML = function() {
|
||||
if (!this.contentElement) return;
|
||||
|
||||
const links = this.contentElement.querySelectorAll('a');
|
||||
links.forEach(link => {
|
||||
// Remove any existing handlers
|
||||
link.onclick = null;
|
||||
|
||||
// Add clean, simple handler
|
||||
link.addEventListener('click', (e) => {
|
||||
// Only handle links when Ctrl is active
|
||||
if (!document.body.classList.contains('af-ctrl-active')) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
return false;
|
||||
}
|
||||
|
||||
// Ctrl is held - handle external links only
|
||||
if (link.href &&
|
||||
!link.href.startsWith('javascript:') &&
|
||||
!(link.href.startsWith('#') || link.href === '#')) {
|
||||
e.preventDefault();
|
||||
window.open(link.href, '_blank');
|
||||
}
|
||||
|
||||
// Stop propagation to ComfyUI
|
||||
e.stopPropagation();
|
||||
return false;
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
// Global Ctrl key handling
|
||||
let ctrlKeyActive = false;
|
||||
|
||||
document.addEventListener('keydown', (e) => {
|
||||
if (e.key === 'Control') {
|
||||
ctrlKeyActive = true;
|
||||
document.body.classList.add('af-ctrl-active');
|
||||
}
|
||||
});
|
||||
|
||||
document.addEventListener('keyup', (e) => {
|
||||
if (e.key === 'Control') {
|
||||
ctrlKeyActive = false;
|
||||
document.body.classList.remove('af-ctrl-active');
|
||||
}
|
||||
});
|
||||
|
||||
// Clean up when node is removed
|
||||
const originalOnRemoved = nodeType.prototype.onRemoved;
|
||||
nodeType.prototype.onRemoved = function() {
|
||||
document.body.classList.remove('af-ctrl-active');
|
||||
originalOnRemoved?.apply(this, arguments);
|
||||
};
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,2 @@
|
||||
// web/nodes.js - Entry point for ComfyUI
|
||||
import './AF-Enhanced-HTML-Note.js';
|
||||