mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-03-12 00:20:15 +00:00
merge main into rh-test
This commit is contained in:
@@ -1,640 +1 @@
|
||||
@layer primevue, tailwind-utilities;
|
||||
|
||||
@layer tailwind-utilities {
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
}
|
||||
|
||||
:root {
|
||||
--fg-color: #000;
|
||||
--bg-color: #fff;
|
||||
--comfy-menu-bg: #353535;
|
||||
--comfy-menu-secondary-bg: #292929;
|
||||
--comfy-topbar-height: 2.5rem;
|
||||
--comfy-input-bg: #222;
|
||||
--input-text: #ddd;
|
||||
--descrip-text: #999;
|
||||
--drag-text: #ccc;
|
||||
--error-text: #ff4444;
|
||||
--border-color: #4e4e4e;
|
||||
--tr-even-bg-color: #222;
|
||||
--tr-odd-bg-color: #353535;
|
||||
--primary-bg: #236692;
|
||||
--primary-fg: #ffffff;
|
||||
--primary-hover-bg: #3485bb;
|
||||
--primary-hover-fg: #ffffff;
|
||||
--content-bg: #e0e0e0;
|
||||
--content-fg: #000;
|
||||
--content-hover-bg: #adadad;
|
||||
--content-hover-fg: #000;
|
||||
|
||||
/* Code styling colors for help menu*/
|
||||
--code-text-color: rgba(0, 122, 255, 1);
|
||||
--code-bg-color: rgba(96, 165, 250, 0.2);
|
||||
--code-block-bg-color: rgba(60, 60, 60, 0.12);
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
:root {
|
||||
--fg-color: #fff;
|
||||
--bg-color: #202020;
|
||||
--content-bg: #4e4e4e;
|
||||
--content-fg: #fff;
|
||||
--content-hover-bg: #222;
|
||||
--content-hover-fg: #fff;
|
||||
}
|
||||
}
|
||||
|
||||
body {
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
margin: 0;
|
||||
overflow: hidden;
|
||||
background: var(--bg-color) var(--bg-img);
|
||||
color: var(--fg-color);
|
||||
min-height: -webkit-fill-available;
|
||||
max-height: -webkit-fill-available;
|
||||
min-width: -webkit-fill-available;
|
||||
max-width: -webkit-fill-available;
|
||||
font-family: Arial, sans-serif;
|
||||
}
|
||||
|
||||
.comfy-multiline-input {
|
||||
background-color: var(--comfy-input-bg);
|
||||
color: var(--input-text);
|
||||
overflow: hidden;
|
||||
overflow-y: auto;
|
||||
padding: 2px;
|
||||
resize: none;
|
||||
border: none;
|
||||
box-sizing: border-box;
|
||||
font-size: var(--comfy-textarea-font-size);
|
||||
}
|
||||
|
||||
.comfy-markdown {
|
||||
/* We assign the textarea and the Tiptap editor to the same CSS grid area to stack them on top of one another. */
|
||||
display: grid;
|
||||
}
|
||||
|
||||
.comfy-markdown > textarea {
|
||||
grid-area: 1 / 1 / 2 / 2;
|
||||
}
|
||||
|
||||
.comfy-markdown .tiptap {
|
||||
grid-area: 1 / 1 / 2 / 2;
|
||||
background-color: var(--comfy-input-bg);
|
||||
color: var(--input-text);
|
||||
overflow: hidden;
|
||||
overflow-y: auto;
|
||||
resize: none;
|
||||
border: none;
|
||||
box-sizing: border-box;
|
||||
font-size: var(--comfy-textarea-font-size);
|
||||
height: 100%;
|
||||
padding: 0.5em;
|
||||
}
|
||||
|
||||
.comfy-markdown.editing .tiptap {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.comfy-markdown .tiptap :first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.comfy-markdown .tiptap :last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.comfy-markdown .tiptap blockquote {
|
||||
border-left: medium solid;
|
||||
margin-left: 1em;
|
||||
padding-left: 0.5em;
|
||||
}
|
||||
|
||||
.comfy-markdown .tiptap pre {
|
||||
border: thin dotted;
|
||||
border-radius: 0.5em;
|
||||
margin: 0.5em;
|
||||
padding: 0.5em;
|
||||
}
|
||||
|
||||
.comfy-markdown .tiptap table {
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
||||
.comfy-markdown .tiptap th {
|
||||
text-align: left;
|
||||
background: var(--comfy-menu-bg);
|
||||
}
|
||||
|
||||
.comfy-markdown .tiptap th,
|
||||
.comfy-markdown .tiptap td {
|
||||
padding: 0.5em;
|
||||
border: thin solid;
|
||||
}
|
||||
|
||||
.comfy-modal {
|
||||
display: none; /* Hidden by default */
|
||||
position: fixed; /* Stay in place */
|
||||
z-index: 100; /* Sit on top */
|
||||
padding: 30px 30px 10px 30px;
|
||||
background-color: var(--comfy-menu-bg); /* Modal background */
|
||||
color: var(--error-text);
|
||||
box-shadow: 0 0 20px #888888;
|
||||
border-radius: 10px;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
max-width: 80vw;
|
||||
max-height: 80vh;
|
||||
transform: translate(-50%, -50%);
|
||||
overflow: hidden;
|
||||
justify-content: center;
|
||||
font-family: monospace;
|
||||
font-size: 15px;
|
||||
}
|
||||
|
||||
.comfy-modal-content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.comfy-modal p {
|
||||
overflow: auto;
|
||||
white-space: pre-line; /* This will respect line breaks */
|
||||
margin-bottom: 20px; /* Add some margin between the text and the close button*/
|
||||
}
|
||||
|
||||
.comfy-modal select,
|
||||
.comfy-modal input[type='button'],
|
||||
.comfy-modal input[type='checkbox'] {
|
||||
margin: 3px 3px 3px 4px;
|
||||
}
|
||||
|
||||
.comfy-menu {
|
||||
font-size: 15px;
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
right: 0;
|
||||
text-align: center;
|
||||
z-index: 999;
|
||||
width: 190px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
color: var(--descrip-text);
|
||||
background-color: var(--comfy-menu-bg);
|
||||
font-family: sans-serif;
|
||||
padding: 10px;
|
||||
border-radius: 0 8px 8px 8px;
|
||||
box-shadow: 3px 3px 8px rgba(0, 0, 0, 0.4);
|
||||
}
|
||||
|
||||
.comfy-menu-header {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.comfy-menu-actions {
|
||||
display: flex;
|
||||
gap: 3px;
|
||||
align-items: center;
|
||||
height: 20px;
|
||||
position: relative;
|
||||
top: -1px;
|
||||
font-size: 22px;
|
||||
}
|
||||
|
||||
.comfy-menu .comfy-menu-actions button {
|
||||
background-color: rgba(0, 0, 0, 0);
|
||||
padding: 0;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
font-size: inherit;
|
||||
}
|
||||
|
||||
.comfy-menu .comfy-menu-actions .comfy-settings-btn {
|
||||
font-size: 0.6em;
|
||||
}
|
||||
|
||||
button.comfy-close-menu-btn {
|
||||
font-size: 1em;
|
||||
line-height: 12px;
|
||||
color: #ccc;
|
||||
position: relative;
|
||||
top: -1px;
|
||||
}
|
||||
|
||||
.comfy-menu-queue-size {
|
||||
flex: auto;
|
||||
}
|
||||
|
||||
.comfy-menu button,
|
||||
.comfy-modal button {
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
.comfy-menu-btns {
|
||||
margin-bottom: 10px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.comfy-menu-btns button {
|
||||
font-size: 10px;
|
||||
width: 50%;
|
||||
color: var(--descrip-text) !important;
|
||||
}
|
||||
|
||||
.comfy-menu > button {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.comfy-btn,
|
||||
.comfy-menu > button,
|
||||
.comfy-menu-btns button,
|
||||
.comfy-menu .comfy-list button,
|
||||
.comfy-modal button {
|
||||
color: var(--input-text);
|
||||
background-color: var(--comfy-input-bg);
|
||||
border-radius: 8px;
|
||||
border-color: var(--border-color);
|
||||
border-style: solid;
|
||||
margin-top: 2px;
|
||||
}
|
||||
|
||||
.comfy-btn:hover:not(:disabled),
|
||||
.comfy-menu > button:hover,
|
||||
.comfy-menu-btns button:hover,
|
||||
.comfy-menu .comfy-list button:hover,
|
||||
.comfy-modal button:hover,
|
||||
.comfy-menu-actions button:hover {
|
||||
filter: brightness(1.2);
|
||||
will-change: transform;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
span.drag-handle {
|
||||
width: 10px;
|
||||
height: 20px;
|
||||
display: inline-block;
|
||||
overflow: hidden;
|
||||
line-height: 5px;
|
||||
padding: 3px 4px;
|
||||
cursor: move;
|
||||
vertical-align: middle;
|
||||
margin-top: -0.4em;
|
||||
margin-left: -0.2em;
|
||||
font-size: 12px;
|
||||
font-family: sans-serif;
|
||||
letter-spacing: 2px;
|
||||
color: var(--drag-text);
|
||||
text-shadow: 1px 0 1px black;
|
||||
touch-action: none;
|
||||
}
|
||||
|
||||
span.drag-handle::after {
|
||||
content: '.. .. ..';
|
||||
}
|
||||
|
||||
.comfy-queue-btn {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.comfy-list {
|
||||
color: var(--descrip-text);
|
||||
background-color: var(--comfy-menu-bg);
|
||||
margin-bottom: 10px;
|
||||
border-color: var(--border-color);
|
||||
border-style: solid;
|
||||
}
|
||||
|
||||
.comfy-list-items {
|
||||
overflow-y: scroll;
|
||||
max-height: 100px;
|
||||
min-height: 25px;
|
||||
background-color: var(--comfy-input-bg);
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
.comfy-list h4 {
|
||||
min-width: 160px;
|
||||
margin: 0;
|
||||
padding: 3px;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
.comfy-list-items button {
|
||||
font-size: 10px;
|
||||
}
|
||||
|
||||
.comfy-list-actions {
|
||||
margin: 5px;
|
||||
display: flex;
|
||||
gap: 5px;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.comfy-list-actions button {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
button.comfy-queue-btn {
|
||||
margin: 6px 0 !important;
|
||||
}
|
||||
|
||||
.comfy-modal.comfy-settings,
|
||||
.comfy-modal.comfy-manage-templates {
|
||||
text-align: center;
|
||||
font-family: sans-serif;
|
||||
color: var(--descrip-text);
|
||||
z-index: 99;
|
||||
}
|
||||
|
||||
.comfy-modal.comfy-settings input[type='range'] {
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.comfy-modal.comfy-settings input[type='range'] + input[type='number'] {
|
||||
width: 3.5em;
|
||||
}
|
||||
|
||||
.comfy-modal input,
|
||||
.comfy-modal select {
|
||||
color: var(--input-text);
|
||||
background-color: var(--comfy-input-bg);
|
||||
border-radius: 8px;
|
||||
border-color: var(--border-color);
|
||||
border-style: solid;
|
||||
font-size: inherit;
|
||||
}
|
||||
|
||||
.comfy-tooltip-indicator {
|
||||
text-decoration: underline;
|
||||
text-decoration-style: dashed;
|
||||
}
|
||||
|
||||
@media only screen and (max-height: 850px) {
|
||||
.comfy-menu {
|
||||
top: 0 !important;
|
||||
bottom: 0 !important;
|
||||
left: auto !important;
|
||||
right: 0 !important;
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
.comfy-menu span.drag-handle {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.comfy-menu-queue-size {
|
||||
flex: unset;
|
||||
}
|
||||
|
||||
.comfy-menu-header {
|
||||
justify-content: space-between;
|
||||
}
|
||||
.comfy-menu-actions {
|
||||
gap: 10px;
|
||||
font-size: 28px;
|
||||
}
|
||||
}
|
||||
|
||||
/* Input popup */
|
||||
|
||||
.graphdialog {
|
||||
min-height: 1em;
|
||||
background-color: var(--comfy-menu-bg);
|
||||
z-index: 41; /* z-index is set to 41 here in order to appear over selection-overlay-container which should have a z-index of 40 */
|
||||
}
|
||||
|
||||
.graphdialog .name {
|
||||
font-size: 14px;
|
||||
font-family: sans-serif;
|
||||
color: var(--descrip-text);
|
||||
}
|
||||
|
||||
.graphdialog button {
|
||||
margin-top: unset;
|
||||
vertical-align: unset;
|
||||
height: 1.6em;
|
||||
padding-right: 8px;
|
||||
}
|
||||
|
||||
.graphdialog input,
|
||||
.graphdialog textarea,
|
||||
.graphdialog select {
|
||||
background-color: var(--comfy-input-bg);
|
||||
border: 2px solid;
|
||||
border-color: var(--border-color);
|
||||
color: var(--input-text);
|
||||
border-radius: 12px 0 0 12px;
|
||||
}
|
||||
|
||||
/* Dialogs */
|
||||
|
||||
dialog {
|
||||
box-shadow: 0 0 20px #888888;
|
||||
}
|
||||
|
||||
dialog::backdrop {
|
||||
background: rgba(0, 0, 0, 0.5);
|
||||
}
|
||||
|
||||
.comfy-dialog.comfyui-dialog.comfy-modal {
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
transform: none;
|
||||
}
|
||||
|
||||
.comfy-dialog.comfy-modal {
|
||||
font-family: Arial, sans-serif;
|
||||
border-color: var(--bg-color);
|
||||
box-shadow: none;
|
||||
border: 2px solid var(--border-color);
|
||||
}
|
||||
|
||||
.comfy-dialog .comfy-modal-content {
|
||||
flex-direction: row;
|
||||
flex-wrap: wrap;
|
||||
gap: 10px;
|
||||
color: var(--fg-color);
|
||||
}
|
||||
|
||||
.comfy-dialog .comfy-modal-content h3 {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.comfy-dialog .comfy-modal-content > p {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.comfy-dialog .comfy-modal-content > .comfyui-button {
|
||||
flex: 1;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
/* Context menu */
|
||||
|
||||
.litegraph .dialog {
|
||||
z-index: 1;
|
||||
font-family: Arial, sans-serif;
|
||||
}
|
||||
|
||||
.litegraph .litemenu-entry.has_submenu {
|
||||
position: relative;
|
||||
padding-right: 20px;
|
||||
}
|
||||
|
||||
.litemenu-entry.has_submenu::after {
|
||||
content: '>';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 2px;
|
||||
}
|
||||
|
||||
.litegraph.litecontextmenu,
|
||||
.litegraph.litecontextmenu.dark {
|
||||
z-index: 9999 !important;
|
||||
background-color: var(--comfy-menu-bg) !important;
|
||||
}
|
||||
|
||||
.litegraph.litecontextmenu
|
||||
.litemenu-entry:hover:not(.disabled):not(.separator) {
|
||||
background-color: var(--comfy-menu-hover-bg, var(--border-color)) !important;
|
||||
color: var(--fg-color);
|
||||
}
|
||||
|
||||
.litegraph.litecontextmenu .litemenu-entry.submenu,
|
||||
.litegraph.litecontextmenu.dark .litemenu-entry.submenu {
|
||||
background-color: var(--comfy-menu-bg) !important;
|
||||
color: var(--input-text);
|
||||
}
|
||||
|
||||
.litegraph.litecontextmenu input {
|
||||
background-color: var(--comfy-input-bg) !important;
|
||||
color: var(--input-text) !important;
|
||||
}
|
||||
|
||||
.comfy-context-menu-filter {
|
||||
box-sizing: border-box;
|
||||
border: 1px solid #999;
|
||||
margin: 0 0 5px 5px;
|
||||
width: calc(100% - 10px);
|
||||
}
|
||||
|
||||
.comfy-img-preview {
|
||||
pointer-events: none;
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-content: flex-start;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.comfy-img-preview img {
|
||||
object-fit: contain;
|
||||
width: var(--comfy-img-preview-width);
|
||||
height: var(--comfy-img-preview-height);
|
||||
}
|
||||
|
||||
.comfy-img-preview video {
|
||||
pointer-events: auto;
|
||||
object-fit: contain;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.comfy-missing-nodes li button {
|
||||
font-size: 12px;
|
||||
margin-left: 5px;
|
||||
}
|
||||
|
||||
/* Search box */
|
||||
|
||||
.litegraph.litesearchbox {
|
||||
z-index: 9999 !important;
|
||||
background-color: var(--comfy-menu-bg) !important;
|
||||
overflow: hidden;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.litegraph.litesearchbox input,
|
||||
.litegraph.litesearchbox select {
|
||||
background-color: var(--comfy-input-bg) !important;
|
||||
color: var(--input-text);
|
||||
}
|
||||
|
||||
.litegraph.lite-search-item {
|
||||
color: var(--input-text);
|
||||
background-color: var(--comfy-input-bg);
|
||||
filter: brightness(80%);
|
||||
will-change: transform;
|
||||
padding-left: 0.2em;
|
||||
}
|
||||
|
||||
.litegraph.lite-search-item.generic_type {
|
||||
color: var(--input-text);
|
||||
filter: brightness(50%);
|
||||
will-change: transform;
|
||||
}
|
||||
|
||||
audio.comfy-audio.empty-audio-widget {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#vue-app {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
/* Set auto complete panel's width as it is not accessible within vue-root */
|
||||
.p-autocomplete-overlay {
|
||||
max-width: 25vw;
|
||||
}
|
||||
|
||||
.p-tree-node-content {
|
||||
padding: var(--comfy-tree-explorer-item-padding) !important;
|
||||
}
|
||||
|
||||
/* Load3d styles */
|
||||
.comfy-load-3d,
|
||||
.comfy-load-3d-animation,
|
||||
.comfy-preview-3d,
|
||||
.comfy-preview-3d-animation{
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background: transparent;
|
||||
flex: 1;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.comfy-load-3d canvas,
|
||||
.comfy-load-3d-animation canvas,
|
||||
.comfy-preview-3d canvas,
|
||||
.comfy-preview-3d-animation canvas,
|
||||
.comfy-load-3d-viewer canvas{
|
||||
display: flex;
|
||||
width: 100% !important;
|
||||
height: 100% !important;
|
||||
}
|
||||
|
||||
/* End of Load3d styles */
|
||||
|
||||
/* [Desktop] Electron window specific styles */
|
||||
.app-drag {
|
||||
app-region: drag;
|
||||
}
|
||||
|
||||
.no-drag {
|
||||
app-region: no-drag;
|
||||
}
|
||||
|
||||
.window-actions-spacer {
|
||||
width: calc(100vw - env(titlebar-area-width, 100vw));
|
||||
}
|
||||
/* End of [Desktop] Electron window specific styles */
|
||||
@import '@comfyorg/design-system/css/style.css';
|
||||
@@ -1,331 +0,0 @@
|
||||
# ComfyUI Icons Guide
|
||||
|
||||
ComfyUI supports three types of icons that can be used throughout the interface. All icons are automatically imported - no manual imports needed!
|
||||
|
||||
## Quick Start - Code Examples
|
||||
|
||||
### 1. PrimeIcons
|
||||
|
||||
```vue
|
||||
<template>
|
||||
<!-- Basic usage -->
|
||||
<i class="pi pi-plus" />
|
||||
<i class="pi pi-cog" />
|
||||
<i class="pi pi-check text-green-500" />
|
||||
|
||||
<!-- In PrimeVue components -->
|
||||
<button icon="pi pi-save" label="Save" />
|
||||
<button icon="pi pi-times" severity="danger" />
|
||||
</template>
|
||||
```
|
||||
|
||||
[Browse all PrimeIcons →](https://primevue.org/icons/#list)
|
||||
|
||||
### 2. Iconify Icons (Recommended)
|
||||
|
||||
```vue
|
||||
<template>
|
||||
<!-- Primary icon set: Lucide -->
|
||||
<i-lucide:download />
|
||||
<i-lucide:settings />
|
||||
<i-lucide:workflow class="text-2xl" />
|
||||
|
||||
<!-- Other popular icon sets -->
|
||||
<i-mdi:folder-open />
|
||||
<!-- Material Design Icons -->
|
||||
<i-heroicons:document-text />
|
||||
<!-- Heroicons -->
|
||||
<i-tabler:brand-github />
|
||||
<!-- Tabler Icons -->
|
||||
<i-carbon:cloud-upload />
|
||||
<!-- Carbon Icons -->
|
||||
|
||||
<!-- With styling -->
|
||||
<i-lucide:save class="w-6 h-6 text-blue-500" />
|
||||
</template>
|
||||
```
|
||||
|
||||
[Browse 200,000+ icons →](https://icon-sets.iconify.design/)
|
||||
|
||||
### 3. Custom Icons
|
||||
|
||||
```vue
|
||||
<template>
|
||||
<!-- Your custom SVG icons from src/assets/icons/custom/ -->
|
||||
<i-comfy:workflow />
|
||||
<i-comfy:node-tree />
|
||||
<i-comfy:my-custom-icon class="text-xl" />
|
||||
|
||||
<!-- In PrimeVue button -->
|
||||
<Button severity="secondary">
|
||||
<template #icon>
|
||||
<i-comfy:workflow />
|
||||
</template>
|
||||
</Button>
|
||||
</template>
|
||||
```
|
||||
|
||||
## Icon Usage Patterns
|
||||
|
||||
### In Buttons
|
||||
|
||||
```vue
|
||||
<template>
|
||||
<!-- PrimeIcon in button (simple) -->
|
||||
<Button icon="pi pi-check" label="Confirm" />
|
||||
|
||||
<!-- Iconify/Custom in button (template) -->
|
||||
<Button>
|
||||
<template #icon>
|
||||
<i-lucide:save />
|
||||
</template>
|
||||
Save File
|
||||
</Button>
|
||||
</template>
|
||||
```
|
||||
|
||||
### Conditional Icons
|
||||
|
||||
```vue
|
||||
<template>
|
||||
<i-lucide:eye v-if="isVisible" />
|
||||
<i-lucide:eye-off v-else />
|
||||
|
||||
<!-- Or with ternary -->
|
||||
<component :is="isLocked ? 'i-lucide:lock' : 'i-lucide:lock-open'" />
|
||||
</template>
|
||||
```
|
||||
|
||||
### With Tooltips
|
||||
|
||||
```vue
|
||||
<template>
|
||||
<i-lucide:info
|
||||
v-tooltip="'Click for more information'"
|
||||
class="cursor-pointer"
|
||||
/>
|
||||
</template>
|
||||
```
|
||||
|
||||
## Using Iconify Icons
|
||||
|
||||
### Finding Icons
|
||||
|
||||
1. Visit [Iconify Icon Sets](https://icon-sets.iconify.design/)
|
||||
2. Search or browse collections
|
||||
3. Click on any icon to get its name
|
||||
4. Use with `i-[collection]:[icon-name]` format
|
||||
|
||||
### Popular Collections
|
||||
|
||||
- **Lucide** (`i-lucide:`) - Our primary icon set, clean and consistent
|
||||
- **Material Design Icons** (`i-mdi:`) - Comprehensive Material Design icons
|
||||
- **Heroicons** (`i-heroicons:`) - Beautiful hand-crafted SVG icons
|
||||
- **Tabler** (`i-tabler:`) - 3000+ free SVG icons
|
||||
- **Carbon** (`i-carbon:`) - IBM's design system icons
|
||||
|
||||
## Adding Custom Icons
|
||||
|
||||
### 1. Add Your SVG
|
||||
|
||||
Place your SVG file in `src/assets/icons/custom/`:
|
||||
|
||||
```
|
||||
src/assets/icons/custom/
|
||||
├── workflow-duplicate.svg
|
||||
├── node-preview.svg
|
||||
└── your-icon.svg
|
||||
```
|
||||
|
||||
### 2. SVG Format Requirements
|
||||
|
||||
```xml
|
||||
<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
||||
<!-- Use currentColor for theme compatibility -->
|
||||
<path fill="currentColor" d="..." />
|
||||
</svg>
|
||||
```
|
||||
|
||||
**Important:**
|
||||
- Use `viewBox` for proper scaling (24x24 is standard)
|
||||
- Don't include `width` or `height` attributes
|
||||
- Use `currentColor` for theme-aware icons
|
||||
- Keep SVGs optimized and simple
|
||||
|
||||
### 3. Use Immediately
|
||||
|
||||
```vue
|
||||
<template>
|
||||
<i-comfy:your-icon />
|
||||
</template>
|
||||
```
|
||||
|
||||
No imports needed - icons are auto-discovered!
|
||||
|
||||
## Icon Guidelines
|
||||
|
||||
### Naming Conventions
|
||||
|
||||
- **Files**: `kebab-case.svg` (workflow-icon.svg)
|
||||
- **Usage**: `<i-comfy:workflow-icon />`
|
||||
|
||||
### Size & Styling
|
||||
|
||||
```vue
|
||||
<template>
|
||||
<!-- Size with Tailwind classes -->
|
||||
<i-lucide:plus class="w-4 h-4" />
|
||||
<!-- 16px -->
|
||||
<i-lucide:plus class="w-6 h-6" />
|
||||
<!-- 24px (default) -->
|
||||
<i-lucide:plus class="w-8 h-8" />
|
||||
<!-- 32px -->
|
||||
|
||||
<!-- Or text size -->
|
||||
<i-lucide:plus class="text-sm" />
|
||||
<i-lucide:plus class="text-2xl" />
|
||||
|
||||
<!-- Colors -->
|
||||
<i-lucide:check class="text-green-500" />
|
||||
<i-lucide:x class="text-red-500" />
|
||||
</template>
|
||||
```
|
||||
|
||||
### Theme Compatibility
|
||||
|
||||
Always use `currentColor` in SVGs for automatic theme adaptation:
|
||||
|
||||
```xml
|
||||
<!-- ✅ Good: Adapts to light/dark theme -->
|
||||
<svg viewBox="0 0 24 24">
|
||||
<path fill="currentColor" d="..." />
|
||||
</svg>
|
||||
|
||||
<!-- ❌ Bad: Fixed colors -->
|
||||
<svg viewBox="0 0 24 24">
|
||||
<path fill="#000000" d="..." />
|
||||
</svg>
|
||||
```
|
||||
|
||||
## Migration Guide
|
||||
|
||||
### From PrimeIcons to Iconify/Custom
|
||||
|
||||
```vue
|
||||
<template>
|
||||
<!-- Before -->
|
||||
<Button icon="pi pi-download" />
|
||||
|
||||
<!-- After -->
|
||||
<Button>
|
||||
<template #icon>
|
||||
<i-lucide:download />
|
||||
</template>
|
||||
</Button>
|
||||
</template>
|
||||
```
|
||||
|
||||
### From Inline SVG to Custom Icon
|
||||
|
||||
```vue
|
||||
<template>
|
||||
<!-- Before: Inline SVG -->
|
||||
<svg class="w-6 h-6" viewBox="0 0 24 24">
|
||||
<path d="..." />
|
||||
</svg>
|
||||
|
||||
<!-- After: Save as custom/my-icon.svg and use -->
|
||||
<i-comfy:my-icon class="w-6 h-6" />
|
||||
</template>
|
||||
```
|
||||
|
||||
## Technical Details
|
||||
|
||||
### Auto-Import System
|
||||
|
||||
Icons are automatically imported using `unplugin-icons` - no manual imports needed! Just use the icon component directly.
|
||||
|
||||
### Configuration
|
||||
|
||||
The icon system has two layers:
|
||||
|
||||
1. **Build-time Processing** (`build/customIconCollection.ts`):
|
||||
- Scans `src/assets/icons/custom/` for SVG files
|
||||
- Validates SVG content and structure
|
||||
- Creates Iconify collection for Tailwind CSS
|
||||
- Provides error handling for malformed files
|
||||
|
||||
2. **Vite Runtime** (`vite.config.mts`):
|
||||
- Enables direct SVG import as Vue components
|
||||
- Supports dynamic icon loading
|
||||
|
||||
```typescript
|
||||
// Build script creates Iconify collection
|
||||
export const iconCollection: IconifyCollection = {
|
||||
prefix: 'comfy',
|
||||
icons: {
|
||||
'workflow': { body: '<svg>...</svg>' },
|
||||
'node': { body: '<svg>...</svg>' }
|
||||
}
|
||||
}
|
||||
|
||||
// Vite configuration for component-based usage
|
||||
Icons({
|
||||
compiler: 'vue3',
|
||||
customCollections: {
|
||||
comfy: FileSystemIconLoader('src/assets/icons/custom')
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
### TypeScript Support
|
||||
|
||||
Icons are fully typed. If TypeScript doesn't recognize a new custom icon:
|
||||
|
||||
1. Restart the dev server
|
||||
2. Ensure the SVG file is valid
|
||||
3. Check filename follows kebab-case
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Icon Not Showing
|
||||
1. **Check filename**: Must be kebab-case without special characters
|
||||
2. **Restart dev server**: Required after adding new icons
|
||||
3. **Verify SVG**: Ensure it's valid SVG syntax (build script validates automatically)
|
||||
4. **Check console**: Look for Vue component resolution errors
|
||||
5. **Build script errors**: Check console during build - malformed SVGs are logged but don't break builds
|
||||
|
||||
### Icon Wrong Color
|
||||
- Replace hardcoded colors with `currentColor`
|
||||
- Use `stroke="currentColor"` for outlines
|
||||
- Use `fill="currentColor"` for filled shapes
|
||||
|
||||
### Icon Wrong Size
|
||||
- Remove `width` and `height` from SVG
|
||||
- Ensure `viewBox` is present
|
||||
- Use CSS classes for sizing: `class="w-6 h-6"`
|
||||
|
||||
## Best Practices
|
||||
|
||||
1. **Optimize SVGs**: Use tools like [SVGO](https://jakearchibald.github.io/svgomg/) to minimize file size
|
||||
2. **Consistent viewBox**: Stick to 24x24 or 16x16 for consistency
|
||||
3. **Semantic names**: Use descriptive names like `workflow-duplicate` not `icon1`
|
||||
4. **Theme support**: Always use `currentColor` for adaptable icons
|
||||
5. **Test both themes**: Verify icons look good in light and dark modes
|
||||
|
||||
## Adding Icon Collections
|
||||
|
||||
To add an entire icon set from npm:
|
||||
|
||||
1. Install the icon package
|
||||
2. Configure in `vite.config.mts`
|
||||
3. Use with the appropriate prefix
|
||||
|
||||
See the [unplugin-icons documentation](https://github.com/unplugin/unplugin-icons) for details.
|
||||
|
||||
## Resources
|
||||
|
||||
- [PrimeIcons List](https://primevue.org/icons/#list)
|
||||
- [Iconify Icon Browser](https://icon-sets.iconify.design/)
|
||||
- [Lucide Icons](https://lucide.dev/icons/)
|
||||
- [unplugin-icons docs](https://github.com/unplugin/unplugin-icons)
|
||||
@@ -1 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 16 16"><g stroke="currentColor" stroke-linecap="round" stroke-width="1.3" clip-path="url(#a)"><path d="m4.998 13.909.557-2.225a1.112 1.112 0 0 0-1.08-1.382H2.32c-.51 0-.955.347-1.079.842L.684 13.37a1.112 1.112 0 0 0 1.079 1.382h2.156c.51 0 .956-.347 1.08-.842ZM6.11 7.234l.557-2.224a1.112 1.112 0 0 0-1.08-1.383H3.433c-.51 0-.956.348-1.08.843l-.556 2.225a1.112 1.112 0 0 0 1.08 1.382h2.156c.51 0 .955-.347 1.079-.843ZM11.673 13.909l.556-2.225a1.112 1.112 0 0 0-1.08-1.382H8.994c-.51 0-.955.347-1.079.842l-.556 2.225a1.112 1.112 0 0 0 1.08 1.382h2.156c.51 0 .955-.347 1.079-.842ZM13.141 5.816l-.784 1.83a.334.334 0 0 1-.614 0l-.785-1.83a.333.333 0 0 0-.175-.176l-1.831-.784a.334.334 0 0 1 0-.614l1.831-.785a.333.333 0 0 0 .175-.175l.785-1.831a.334.334 0 0 1 .614 0l.784 1.831a.334.334 0 0 0 .176.175l1.83.785c.27.116.27.498 0 .614l-1.83.784a.334.334 0 0 0-.176.176Z"/></g><defs><clipPath id="a"><path fill="currentColor" d="M0 0h16v16H0z"/></clipPath></defs></svg>
|
||||
|
Before Width: | Height: | Size: 1.0 KiB |
10
src/assets/icons/custom/dark-info.svg
Normal file
10
src/assets/icons/custom/dark-info.svg
Normal file
@@ -0,0 +1,10 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16" fill="none">
|
||||
<g clip-path="url(#clip0_1416_62)">
|
||||
<path d="M7.99998 10.6667V8.00004M7.99998 5.33337H8.00665M14.6666 8.00004C14.6666 11.6819 11.6819 14.6667 7.99998 14.6667C4.31808 14.6667 1.33331 11.6819 1.33331 8.00004C1.33331 4.31814 4.31808 1.33337 7.99998 1.33337C11.6819 1.33337 14.6666 4.31814 14.6666 8.00004Z" stroke="#171718" stroke-width="1.3" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</g>
|
||||
<defs>
|
||||
<clipPath id="clip0_1416_62">
|
||||
<rect width="16" height="16" fill="white"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 623 B |
@@ -1 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 16 16"><path stroke="currentColor" stroke-linecap="round" stroke-width="1.3" d="m11.2667 10.45-.0842.3156c-.143.5363-.6286.9094-1.18362.9094H4.6945c-.80486 0-1.39102-.7629-1.18364-1.5406l1.30667-4.90002c.143-.53625.62865-.90937 1.18364-.90937h5.46393c.7243 0 1.2518.68663 1.0652 1.38652l-.0301.11275M15.35 8.00001h-4.9m-6.73748 0H.65002"/></svg>
|
||||
|
Before Width: | Height: | Size: 411 B |
@@ -1 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 16 16"><g stroke="currentColor" stroke-linecap="round" stroke-width="1.3" clip-path="url(#a)"><path d="m14.6685 5.7416.6425-2.57c.2028-.811-.4106-1.5967-1.2466-1.5967H2.5782a1.285 1.285 0 0 0-1.2467.9733l-.6425 2.57c-.2027.8111.4107 1.5968 1.2467 1.5968h11.4861a1.285 1.285 0 0 0 1.2467-.9734Zm0 7.7102.6425-2.5701c.2028-.811-.4106-1.5967-1.2466-1.5967h-5.061a1.285 1.285 0 0 0-1.2467.9734l-.6425 2.5701c-.2028.811.4106 1.5966 1.2466 1.5966h5.061a1.285 1.285 0 0 0 1.2467-.9733Zm-10.2802 0 .6425-2.5701c.2027-.811-.4107-1.5967-1.2467-1.5967H2.5782a1.285 1.285 0 0 0-1.2467.9734L.689 12.8285c-.2027.811.4107 1.5966 1.2467 1.5966h1.206a1.285 1.285 0 0 0 1.2466-.9733Z"/></g><defs><clipPath id="a"><path fill="currentColor" d="M0 0h16v16H0z"/></clipPath></defs></svg>
|
||||
|
Before Width: | Height: | Size: 830 B |
@@ -1 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 16 16"><path stroke="currentColor" stroke-linecap="round" stroke-width="1.3" d="M9.18613 3.09999H6.81377M9.18613 12.9H7.55288c-3.08678 0-5.35171-2.99581-4.60305-6.08843l.3054-1.26158M14.7486 2.1721l-.5931 2.45c-.132.54533-.6065.92789-1.1508.92789h-2.2993c-.77173 0-1.33797-.74895-1.1508-1.5221l.5931-2.45c.132-.54533.6065-.9279 1.1508-.9279h2.2993c.7717 0 1.3379.74896 1.1508 1.52211Zm-8.3033 0-.59309 2.45c-.13201.54533-.60646.92789-1.15076.92789H2.4021c-.7717 0-1.33793-.74895-1.15077-1.5221l.59309-2.45c.13201-.54533.60647-.9279 1.15077-.9279h2.29935c.77169 0 1.33792.74896 1.15076 1.52211Zm8.3033 9.8-.5931 2.45c-.132.5453-.6065.9279-1.1508.9279h-2.2993c-.77173 0-1.33797-.749-1.1508-1.5221l.5931-2.45c.132-.5453.6065-.9279 1.1508-.9279h2.2993c.7717 0 1.3379.7489 1.1508 1.5221Z"/></svg>
|
||||
|
Before Width: | Height: | Size: 857 B |
Reference in New Issue
Block a user