Files
ComfyUI-Lora-Manager/static/css/components/lora-modal/lora-modal.css
Will Miao a7ee883227 feat(modal): add license restriction indicators to model modal
Add visual indicators for commercial license restrictions in the model modal. New CSS classes and JavaScript utilities handle the display of restriction icons for selling, renting, and image usage limitations. The modal header actions container has been restructured to accommodate the new license restriction section.

- Add `.modal-header-actions` and `.license-restrictions` CSS classes
- Implement commercial license icon configuration and rendering logic
- Normalize and sanitize commercial restriction values
- Update header layout to remove bottom margin for better visual alignment
2025-11-06 21:04:59 +08:00

862 lines
19 KiB
CSS

/* Lora Modal Header */
.modal-header {
display: flex;
flex-direction: column;
justify-content: flex-start;
align-items: flex-start;
margin-bottom: var(--space-3);
padding-bottom: var(--space-2);
border-bottom: 1px solid var(--lora-border);
}
.modal-header-actions {
display: flex;
align-items: center;
gap: var(--space-2);
flex-wrap: wrap;
width: 100%;
margin-bottom: var(--space-1);
}
.modal-header-actions .license-restrictions {
margin-left: auto;
}
.license-restrictions {
display: flex;
align-items: center;
gap: 8px;
padding: 4px 0;
}
.license-restrictions .license-icon {
width: 22px;
height: 22px;
display: inline-block;
background-color: var(--text-muted);
-webkit-mask: var(--license-icon-image) center/contain no-repeat;
mask: var(--license-icon-image) center/contain no-repeat;
transition: background-color 0.2s ease, transform 0.2s ease;
cursor: default;
}
.license-restrictions .license-icon:hover {
background-color: var(--text-color);
transform: translateY(-1px);
}
/* Info Grid */
.info-grid {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: var(--space-2);
margin-bottom: var(--space-3);
}
.info-item {
padding: var(--space-2);
background: rgba(0, 0, 0, 0.03);
border: 1px solid rgba(0, 0, 0, 0.1);
border-radius: var(--border-radius-sm);
}
/* 调整深色主题下的样式 */
[data-theme="dark"] .info-item {
background: rgba(255, 255, 255, 0.03);
border: 1px solid var(--lora-border);
}
.info-item.full-width {
grid-column: 1 / -1;
}
.info-item label {
display: block;
font-size: 0.85em;
color: var(--text-color);
opacity: 0.8;
margin-bottom: 4px;
}
.info-item span {
color: var(--text-color);
word-break: break-word;
}
.info-item.usage-tips,
.info-item.notes {
grid-column: 1 / -1 !important; /* Make notes section full width */
}
/* Add specific styles for notes content */
.info-item.notes .editable-field [contenteditable] {
min-height: 60px; /* Increase height for multiple lines */
max-height: 150px; /* Limit maximum height */
overflow-y: auto; /* Add scrolling for long content */
white-space: pre-wrap; /* Preserve line breaks */
line-height: 1.5; /* Improve readability */
padding: 8px 12px; /* Slightly increase padding */
}
.file-path {
font-family: monospace;
font-size: 0.9em;
}
.file-path[data-action="open-file-location"] {
cursor: pointer;
text-decoration: underline;
}
.file-path[data-action="open-file-location"]:hover {
opacity: 0.8;
}
.description-text {
line-height: 1.5;
max-height: 100px;
overflow-y: auto;
}
/* Editable Fields */
.editable-field {
position: relative;
display: flex;
gap: 8px;
align-items: flex-start;
}
.editable-field [contenteditable] {
flex: 1;
min-height: 24px;
padding: 4px 8px;
background: var(--bg-color);
border: 1px solid var(--border-color);
border-radius: var(--border-radius-xs);
font-size: 0.9em;
line-height: 1.4;
color: var(--text-color);
transition: border-color 0.2s;
word-break: break-word;
}
.editable-field [contenteditable]:focus {
outline: none;
border-color: var(--lora-accent);
background: var(--bg-color);
}
.editable-field [contenteditable]:empty::before {
content: attr(data-placeholder);
color: var(--text-color);
opacity: 0.5;
}
.notes-hint {
font-size: 0.8em;
color: var(--text-color);
opacity: 0.7;
margin-left: 5px;
cursor: help;
position: relative; /* Add positioning context */
}
@media (max-width: 640px) {
.info-item.usage-tips,
.info-item.notes {
grid-column: 1 / -1;
}
}
/* 修改 back-to-top 按钮样式,使其固定在 modal 内部 */
.modal-content .back-to-top {
position: sticky; /* 改用 sticky 定位 */
float: right; /* 使用 float 确保按钮在右侧 */
bottom: 20px; /* 距离底部的距离 */
margin-right: 20px; /* 右侧间距 */
margin-top: -56px; /* 负边距确保不占用额外空间 */
width: 36px;
height: 36px;
border-radius: 50%;
background: var(--card-bg);
border: 1px solid var(--border-color);
color: var(--text-color);
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
opacity: 0;
visibility: hidden;
transform: translateY(10px);
transition: all 0.3s ease;
z-index: 10;
}
.modal-content .back-to-top.visible {
opacity: 1;
visibility: visible;
transform: translateY(0);
}
.modal-content .back-to-top:hover {
background: var(--lora-accent);
color: white;
transform: translateY(-2px);
}
/* File name copy styles */
.file-name-wrapper {
display: flex;
align-items: center;
gap: 8px;
padding: 4px;
border-radius: var(--border-radius-xs);
transition: background-color 0.2s;
position: relative;
}
.file-name-content {
padding: 2px 4px;
border-radius: var(--border-radius-xs);
border: 1px solid transparent;
flex: 1;
}
.file-name-wrapper.editing .file-name-content {
border: 1px solid var(--lora-accent);
background: var(--bg-color);
outline: none;
}
/* 合并编辑按钮样式 */
.edit-model-name-btn,
.edit-file-name-btn,
.edit-base-model-btn,
.edit-model-description-btn {
background: transparent;
border: none;
color: var(--text-color);
opacity: 0;
cursor: pointer;
padding: 2px 5px;
border-radius: var(--border-radius-xs);
transition: all 0.2s ease;
margin-left: var(--space-1);
}
.edit-model-name-btn.visible,
.edit-file-name-btn.visible,
.edit-base-model-btn.visible,
.edit-model-description-btn.visible,
.model-name-header:hover .edit-model-name-btn,
.file-name-wrapper:hover .edit-file-name-btn,
.base-model-display:hover .edit-base-model-btn,
.model-name-header:hover .edit-model-description-btn {
opacity: 0.5;
}
.edit-model-name-btn:hover,
.edit-file-name-btn:hover,
.edit-base-model-btn:hover,
.edit-model-description-btn:hover {
opacity: 0.8 !important;
background: rgba(0, 0, 0, 0.05);
}
[data-theme="dark"] .edit-model-name-btn:hover,
[data-theme="dark"] .edit-file-name-btn:hover,
[data-theme="dark"] .edit-base-model-btn:hover {
background: rgba(255, 255, 255, 0.05);
}
/* Base Model and Size combined styles */
.info-item.base-size {
display: flex;
gap: var(--space-3);
}
.base-wrapper {
flex: 2; /* 分配更多空间给base model */
}
/* Base model display and editing styles */
.base-model-display {
display: flex;
align-items: center;
position: relative;
}
.base-model-content {
padding: 2px 4px;
border-radius: var(--border-radius-xs);
border: 1px solid transparent;
color: var(--text-color);
flex: 1;
}
.base-model-selector {
width: 100%;
padding: 3px 5px;
background: var(--bg-color);
border: 1px solid var(--lora-accent);
border-radius: var(--border-radius-xs);
color: var(--text-color);
font-size: 0.9em;
outline: none;
margin-right: var(--space-1);
}
.size-wrapper {
flex: 1;
border-left: 1px solid var(--lora-border);
padding-left: var(--space-3);
}
.base-wrapper label,
.size-wrapper label {
display: block;
margin-bottom: 4px;
}
.size-wrapper span {
font-family: monospace;
font-size: 0.9em;
opacity: 0.9;
}
/* New Model Name Header Styles */
.model-name-header {
display: flex;
align-items: center;
width: calc(100% - 40px); /* Avoid overlap with close button */
position: relative;
}
.model-name-content {
margin: 0;
padding: var(--space-1);
border-radius: var(--border-radius-xs);
font-size: 1.5em !important;
font-weight: 600;
line-height: 1.2;
color: var(--text-color);
border: 1px solid transparent;
outline: none;
flex: 1;
}
.model-name-content:focus {
border: 1px solid var(--lora-accent);
background: var(--bg-color);
}
/* Tab System Styling */
.showcase-tabs {
display: flex;
border-bottom: 1px solid var(--lora-border);
margin-bottom: var(--space-2);
position: relative;
z-index: 2;
}
.tab-btn {
display: inline-flex;
align-items: center;
justify-content: center;
gap: var(--space-1);
padding: var(--space-1) var(--space-2);
background: transparent;
border: none;
border-bottom: 2px solid transparent;
color: var(--text-color);
cursor: pointer;
font-size: 0.95em;
transition: all 0.2s;
opacity: 0.7;
position: relative;
}
.tab-btn:hover {
opacity: 1;
background: oklch(var(--lora-accent-l) var(--lora-accent-c) var(--lora-accent-h) / 0.05);
}
.tab-btn.active {
border-bottom: 2px solid var(--lora-accent);
opacity: 1;
font-weight: 600;
}
.tab-btn .tab-label {
display: inline-flex;
align-items: center;
line-height: 1.2;
}
.tab-btn .tab-badge {
display: inline-flex;
align-items: center;
padding: 2px 8px;
border-radius: var(--border-radius-xs);
background: var(--badge-update-bg);
color: var(--badge-update-text);
font-size: 0.68em;
font-weight: 600;
letter-spacing: 0.06em;
text-transform: uppercase;
box-shadow: 0 3px 10px var(--badge-update-glow);
border: 1px solid color-mix(in oklab, var(--badge-update-bg) 55%, transparent);
line-height: 1;
}
.tab-badge--update {
animation: tab-badge-pulse 2.8s ease-in-out infinite;
}
.tab-btn--has-update:not(.active) {
color: color-mix(in oklch, var(--text-color) 70%, var(--badge-update-bg) 30%);
}
.tab-btn--has-update.active {
border-bottom-color: var(--badge-update-bg);
}
@keyframes tab-badge-pulse {
0%, 100% {
box-shadow: 0 3px 10px color-mix(in oklch, var(--badge-update-glow) 100%, transparent);
transform: translateY(0);
}
50% {
box-shadow: 0 5px 14px color-mix(in oklch, var(--badge-update-glow) 90%, transparent);
transform: translateY(-1px);
}
}
.tab-content {
position: relative;
min-height: 100px;
}
.tab-pane {
display: none;
}
.tab-pane.active {
display: block;
}
.recipes-header {
display: flex;
align-items: flex-start;
justify-content: space-between;
gap: var(--space-3);
padding: var(--space-2) 0 var(--space-3);
margin-bottom: var(--space-2);
border-bottom: 1px solid var(--lora-border);
}
.recipes-header__text {
display: flex;
flex-direction: column;
gap: 6px;
max-width: 520px;
}
.recipes-header__eyebrow {
font-size: 0.75em;
text-transform: uppercase;
letter-spacing: 0.12em;
font-weight: 600;
color: var(--text-color);
opacity: 0.6;
}
.recipes-header__text h3 {
margin: 0;
font-size: 1.1em;
line-height: 1.4;
}
.recipes-header__description {
margin: 0;
font-size: 0.9em;
line-height: 1.5;
color: var(--text-color);
opacity: 0.75;
}
.recipes-header__view-all {
display: inline-flex;
align-items: center;
gap: var(--space-1);
padding: 8px 14px;
border: 1px solid oklch(var(--lora-accent-l) var(--lora-accent-c) var(--lora-accent-h) / 0.35);
background: transparent;
color: var(--lora-accent);
border-radius: var(--border-radius-sm);
cursor: pointer;
font-size: 0.9em;
font-weight: 600;
transition: background 0.2s ease, border-color 0.2s ease, transform 0.2s ease;
}
.recipes-header__view-all i {
font-size: 0.85em;
}
.recipes-header__view-all:hover,
.recipes-header__view-all:focus-visible {
background: oklch(var(--lora-accent-l) var(--lora-accent-c) var(--lora-accent-h) / 0.15);
border-color: var(--lora-accent);
outline: none;
transform: translateY(-1px);
}
.recipes-header__view-all:active {
transform: translateY(0);
}
.recipes-card-grid {
max-width: none;
margin: var(--space-3) 0 0;
padding: 0;
grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
gap: var(--space-3);
row-gap: var(--space-3);
}
.recipe-card {
background: var(--lora-surface);
border: 1px solid var(--lora-border);
border-radius: var(--border-radius-base);
display: flex;
flex-direction: column;
overflow: hidden;
min-height: 320px;
transition: transform 0.2s ease, border-color 0.2s ease, box-shadow 0.2s ease;
}
.recipe-card:hover {
transform: translateY(-4px);
border-color: oklch(var(--lora-accent-l) var(--lora-accent-c) var(--lora-accent-h) / 0.6);
box-shadow: 0 16px 32px rgba(17, 17, 26, 0.18);
}
.recipe-card:focus-visible {
outline: 2px solid var(--lora-accent);
outline-offset: 3px;
}
.recipe-card__media {
position: relative;
overflow: hidden;
aspect-ratio: 4 / 3;
background: var(--lora-surface);
}
.recipe-card__media img {
width: 100%;
height: 100%;
object-fit: cover;
transition: transform 0.25s ease;
}
.recipe-card:hover .recipe-card__media img {
transform: scale(1.02);
}
.recipe-card__media::after {
content: "";
position: absolute;
left: 0;
right: 0;
bottom: 0;
height: 36%;
background: linear-gradient(180deg, transparent 0%, rgba(12, 13, 24, 0.55) 100%);
pointer-events: none;
}
.recipe-card__media-top {
position: absolute;
top: var(--space-1);
right: var(--space-1);
display: flex;
gap: var(--space-1);
}
.recipe-card__copy {
background: rgba(15, 21, 40, 0.6);
border: none;
border-radius: 999px;
color: white;
display: inline-flex;
align-items: center;
justify-content: center;
padding: 6px 10px;
cursor: pointer;
transition: background 0.2s ease, transform 0.2s ease, opacity 0.2s ease;
}
.recipe-card__copy i {
font-size: 0.85em;
}
.recipe-card__copy:hover,
.recipe-card__copy:focus-visible {
background: rgba(15, 21, 40, 0.8);
transform: translateY(-1px);
outline: none;
}
.recipe-card__copy:active {
transform: translateY(0);
}
[data-theme="light"] .recipe-card__copy {
background: rgba(255, 255, 255, 0.85);
color: rgba(17, 23, 41, 0.8);
box-shadow: 0 4px 12px rgba(15, 23, 42, 0.08);
}
[data-theme="light"] .recipe-card__copy:hover,
[data-theme="light"] .recipe-card__copy:focus-visible {
background: rgba(255, 255, 255, 0.95);
}
.recipe-card__body {
display: flex;
flex-direction: column;
gap: var(--space-2);
padding: var(--space-2);
flex: 1;
}
.recipe-card__title {
margin: 0;
font-size: 1.05em;
line-height: 1.4;
font-weight: 600;
overflow: hidden;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
}
.recipe-card__meta {
display: flex;
flex-wrap: wrap;
gap: var(--space-1);
}
.recipe-card__badge {
display: inline-flex;
align-items: center;
gap: 6px;
padding: 4px 10px;
border-radius: 999px;
font-size: 0.78em;
font-weight: 600;
line-height: 1;
background: rgba(255, 255, 255, 0.08);
color: var(--text-color);
}
.recipe-card__badge i {
font-size: 0.85em;
}
.recipe-card__badge--base {
background: rgba(255, 255, 255, 0.1);
color: var(--text-color);
}
[data-theme="light"] .recipe-card__badge {
background: rgba(15, 23, 42, 0.08);
}
[data-theme="light"] .recipe-card__badge--base {
background: rgba(15, 23, 42, 0.12);
}
.recipe-card__badge--ready {
background: rgba(34, 197, 94, 0.18);
color: #4ade80;
}
.recipe-card__badge--missing {
background: rgba(234, 179, 8, 0.2);
color: #facc15;
}
.recipe-card__badge--empty {
background: rgba(148, 163, 184, 0.18);
color: #e2e8f0;
}
[data-theme="light"] .recipe-card__badge--ready {
color: #157347;
background: rgba(76, 167, 120, 0.16);
}
[data-theme="light"] .recipe-card__badge--missing {
color: #9f580a;
background: rgba(245, 199, 43, 0.22);
}
[data-theme="light"] .recipe-card__badge--empty {
color: rgba(71, 85, 105, 0.9);
background: rgba(148, 163, 184, 0.2);
}
.recipe-card__cta {
display: inline-flex;
align-items: center;
gap: var(--space-1);
color: var(--lora-accent);
font-size: 0.9em;
font-weight: 600;
pointer-events: none;
}
.recipe-card__cta i {
font-size: 0.85em;
transition: transform 0.2s ease;
}
.recipe-card:hover .recipe-card__cta i {
transform: translateX(4px);
}
@media (max-width: 900px) {
.recipes-header {
flex-direction: column;
align-items: flex-start;
}
.recipes-header__view-all {
align-self: flex-start;
}
}
@media (max-width: 640px) {
.recipes-card-grid {
grid-template-columns: 1fr;
}
}
/* Loading, error and empty states */
.recipes-loading,
.recipes-error,
.recipes-empty {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 40px;
text-align: center;
min-height: 200px;
}
.recipes-loading i,
.recipes-error i,
.recipes-empty i {
font-size: 32px;
margin-bottom: 15px;
color: var(--lora-accent);
}
.recipes-error i {
color: var(--lora-error);
}
/* Creator Information Styles */
.creator-info {
display: flex;
align-items: center;
gap: 10px;
padding: 2px 10px;
background: rgba(0, 0, 0, 0.03);
border: 1px solid rgba(0, 0, 0, 0.1);
border-radius: var(--border-radius-sm);
max-width: fit-content;
cursor: pointer;
transition: all 0.2s;
}
[data-theme="dark"] .creator-info,
[data-theme="dark"] .civitai-view {
background: rgba(255, 255, 255, 0.03);
border: 1px solid var(--lora-border);
}
.creator-avatar {
width: 26px;
height: 26px;
border-radius: 50%;
overflow: hidden;
flex-shrink: 0;
display: flex;
align-items: center;
justify-content: center;
background: var(--lora-surface);
border: 1px solid var(--lora-border);
}
.creator-avatar img {
width: 100%;
height: 100%;
object-fit: cover;
}
.creator-placeholder {
background: var(--lora-accent);
color: white;
display: flex;
align-items: center;
justify-content: center;
}
.creator-username {
font-size: 0.9em;
font-weight: 500;
color: var(--text-color);
}
/* Add hover effect for creator info */
.creator-info:hover,
.civitai-view:hover {
background: oklch(var(--lora-accent-l) var(--lora-accent-c) var(--lora-accent-h) / 0.1);
border-color: var(--lora-accent);
transform: translateY(-1px);
}
.creator-actions {
display: flex;
align-items: center;
gap: 10px;
margin-bottom: 0;
flex-wrap: wrap;
}
.civitai-view {
display: flex;
align-items: center;
gap: 6px;
padding: 6px 12px;
background: rgba(0, 0, 0, 0.03);
border: 1px solid rgba(0, 0, 0, 0.1);
border-radius: var(--border-radius-sm);
color: var(--text-color);
cursor: pointer;
font-weight: 500;
font-size: 0.9em;
transition: all 0.2s;
}
.civitai-view i {
font-size: 20px;
display: flex;
align-items: center;
justify-content: center;
}