loras_gallery / style.css
waveshaker's picture
Update style.css
082e01b verified
Raw History Blame Contribute Delete
19.5 kB
/* =========================================
Reset & Global Styles
========================================= */
* { box-sizing: border-box; margin: 0; padding: 0; }
:root {
--link-color: #6cf;
--primary-btn: #2563eb;
--primary-btn-hover: #1d4ed8;
--border-color: #2a2a2a;
--card-hover-border: #444;
}
body {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
background: #0f0f0f;
color: #e8e8e8;
line-height: 1.5;
max-width: 1400px;
margin: 0 auto;
padding: 2rem 1.5rem;
}
::-webkit-scrollbar { width: 8px; height: 8px; }
::-webkit-scrollbar-track { background: #0f0f0f; }
::-webkit-scrollbar-thumb { background: #333; border-radius: 4px; }
/* =========================================
Header & Links
========================================= */
.page-header { margin-bottom: 2rem; padding-bottom: 1rem; border-bottom: 1px solid var(--border-color); }
.page-header h1 { font-size: 1.8rem; color: #fff; margin-bottom: 0.5rem; }
.header-meta { display: flex; align-items: center; gap: 1rem; flex-wrap: wrap; font-size: 0.9rem; }
.repo-link { color: #888; margin: 0; display: flex; align-items: center; gap: 0.3rem; }
.repo-link a { color: var(--link-color); text-decoration: none; transition: opacity 0.2s; }
.repo-link a:hover { text-decoration: underline; opacity: 0.8; }
.divider { color: #333; font-size: 1.1rem; }
.downloads-badge { font-size: 0.85rem; color: #999; padding: 0.2rem 0.6rem; background: #1a1a1a; border-radius: 6px; display: none; }
/* 顶部 Disclaimer 按钮 */
#open-disclaimer-btn {
color: #b4a57a;
font-weight: normal;
cursor: pointer;
transition: color 0.2s;
}
#open-disclaimer-btn:hover {
color: #d4c59a;
}
/* =========================================
Layout 主布局
========================================= */
.layout {
display: grid;
grid-template-columns: 260px 1fr;
gap: 2rem;
width: 100%;
align-items: start;
}
@media (max-width: 1000px) {
.layout {
grid-template-columns: 1fr;
}
}
.main-content {
display: flex;
flex-direction: column;
width: 100%;
min-width: 0;
}
/* =========================================
左侧边栏 & 搜索框
========================================= */
.sidebar {
position: sticky;
top: 2rem;
display: flex;
flex-direction: column;
gap: 1.5rem;
background: #151515;
padding: 1.2rem;
border-radius: 12px;
border: 1px solid var(--border-color);
overflow: hidden;
}
.search-box input {
width: 100%;
min-width: 0;
padding: 0.6rem 0.8rem;
background: #1e1e1e;
border: 1px solid #333;
color: #fff;
border-radius: 8px;
font-size: 0.85rem;
outline: none;
transition: border-color 0.2s;
}
.search-box input:focus {
border-color: var(--primary-btn);
}
/* =========================================
Navigation 导航区
========================================= */
#nav-container {
display: flex;
flex-direction: column;
gap: 2rem; /* 🌟 核心:让 Base Model 和 Category 两个大块有足够间距 */
}
.nav-section {
margin-bottom: 0;
display: flex;
flex-direction: column;
gap: 0.6rem;
}
.nav-label {
font-size: 0.75rem;
color: #888;
text-transform: uppercase;
letter-spacing: 0.5px;
font-weight: 600;
}
.nav-buttons {
display: flex;
flex-direction: column;
gap: 0.4rem;
position: relative; /* 🌟 新增:给滑块提供定位基准 */
}
.nav-btn {
background: transparent;
border: 1px solid transparent;
color: #aaa;
padding: 0.5rem 0.8rem;
border-radius: 6px;
cursor: pointer;
font-size: 0.85rem;
/* 🌟 修改:只过渡颜色相关属性,防止和滑块的 transform 冲突 */
transition: color 0.2s ease; /* 只过渡文字颜色 */
font-family: inherit;
font-weight: 600;
width: 100%;
display: flex;
justify-content: space-between;
text-align: left;
position: relative; /* 🌟 确保按钮层级高于滑块 */
z-index: 2; /* 🌟 让按钮文字浮在滑块上方 */
}
/* 1. 未被选中时,鼠标悬浮的深灰色效果 */
.nav-btn:hover {
background: #222; /* 深灰背景会盖住底下的蓝块,这是对的 */
color: #fff;
}
/* 2. 选中的按钮,完全透明,把蓝块露出来 */
.nav-btn.active {
color: #fff;
background: transparent; /* 🌟 核心:必须透明 */
}
/* 3. 最关键的一步:如果已经是被选中的按钮,鼠标悬浮时不准变深灰 */
.nav-btn.active:hover {
background: transparent !important;
color: #fff;
}
/* 🌟 新增:侧边栏的高亮滑块 */
.nav-indicator {
position: absolute;
top: 0;
left: 0;
width: 100%;
background: var(--primary-btn);
border-radius: 6px;
z-index: 1;
pointer-events: none;
box-shadow: 0 4px 12px rgba(37, 99, 235, 0.3);
opacity: 0;
/* 🌟 新增:分离图层,防止被主线程的卡片渲染打断 */
will-change: transform;
transform: translateZ(0);
}
/* 骨架屏在导航区的兜底 */
.skeleton-card.nav-btn {
height: 36px;
min-height: 36px;
}
/* =========================================
Card Grid
========================================= */
.grid {
display: grid !important;
grid-template-columns: repeat(auto-fill, minmax(235px, 1fr)) !important;
gap: 1rem; width: 100%; align-items: start;
}
.card {
background: #181818; border: 1px solid #2a2a2a; border-radius: 10px; padding: 0.6rem;
transition: border-color 0.3s ease, box-shadow 0.4s cubic-bezier(0.34, 1.56, 0.64, 1), background 0.3s ease;
display: flex; flex-direction: column; position: relative; min-width: 0; width: 100%; height: fit-content;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
}
.card:hover {
border-color: #666; background: #1e1e1e;
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 15px 35px rgba(0, 0, 0, 0.6), 0 0 20px rgba(37, 99, 235, 0.1);
z-index: 10;
}
.card.hide { display: none !important; }
.card-badge {
position: absolute; z-index: 20; pointer-events: none; text-transform: uppercase;
top: 0.6rem; left: 0.6rem;
background: rgba(0, 0, 0, 0.65); backdrop-filter: blur(4px);
color: #e0e0e0; font-size: 0.7rem; padding: 0.25rem 0.6rem; border-radius: 6px;
border: 1px solid rgba(255,255,255,0.15); font-weight: 600; letter-spacing: 0.5px;
}
/* =========================================
图片区与 Mask 遮罩动画
========================================= */
.card-image-wrap {
width: 100%; aspect-ratio: 3 / 4; position: relative;
border-radius: 6px; overflow: hidden; margin-bottom: 0.6rem; background: #151515;
}
.preview { width: 100%; height: 100%; object-fit: cover; object-position: top center; display: block; }
.preview-missing { background: #151515; display: block; width: 100%; height: 100%; mask-image: none !important; }
.preview-missing::after {
content: "No Image"; position: absolute; top: 50%; left: 50%;
transform: translate(-50%, -50%); color: #444; font-size: 0.8rem; font-weight: 600;
}
.img-skeleton { background: #1a1a1a; }
.img-skeleton::before {
content: ""; position: absolute; top: -50%; left: -50%; width: 200%; height: 200%;
background: linear-gradient(135deg, transparent 30%, rgba(255, 255, 255, 0.08) 50%, transparent 70%);
animation: skeleton-sweep-diagonal 1.5s infinite linear; z-index: 5; pointer-events: none;
}
@keyframes skeleton-sweep-diagonal {
0% { transform: translate(-40%, -40%); }
100% { transform: translate(40%, 40%); }
}
.is-loaded::before { animation: none; opacity: 0; transition: opacity 0.2s; }
.reveal-img {
opacity: 0;
transition: opacity 0.5s ease-in-out;
will-change: opacity;
}
.reveal-img.loaded { opacity: 1; }
.title-overlay {
position: absolute; bottom: -2px; left: 0; right: 0; height: 45%;
background: linear-gradient(to top, rgba(0,0,0,0.65) 0%, rgba(0,0,0,0) 100%);
pointer-events: none; z-index: 5;
}
.image-bottom-info {
position: absolute; bottom: 0; left: 0; right: 0; padding: 0.8rem; z-index: 10;
display: flex; flex-direction: column;
}
.image-bottom-info .card-title {
font-size: 0.85rem; font-weight: 700; color: #fff; line-height: 1.3;
word-break: break-word; text-shadow: 0 1px 3px rgba(0,0,0,0.8); margin-bottom: 0.2rem;
}
.image-bottom-info .card-category {
font-size: 0.6rem; color: #aaa; font-weight: 600; letter-spacing: 0.5px;
text-transform: uppercase; text-shadow: 0 1px 3px rgba(0,0,0,0.8);
}
/* =========================================
Card Info
========================================= */
.card-info { display: flex; flex-direction: column; flex: 1; min-width: 0; }
.card-details { display: flex; flex-direction: column; gap: 0.5rem; margin-bottom: 0.6rem; }
.detail-block { display: flex; flex-direction: column; gap: 0.2rem; }
.detail-label { color: #666; font-size: 0.65rem; text-transform: uppercase; font-weight: 600; }
.path-box, .trigger-box {
display: block; padding: 0.4rem 0.6rem; border-radius: 6px; cursor: pointer;
transition: background 0.15s ease; width: 100%; background: #252525; border: none;
}
.path-box:hover, .trigger-box:hover { background: #333; }
.path-text, .trigger-text {
font-family: ui-monospace, monospace; line-height: 1.5; word-break: break-word;
display: block; color: #e8e8e8; font-size: 0.7rem;
}
.path-box.copied, .trigger-box.copied { background: var(--primary-btn) !important; }
.path-box.copied .path-text, .trigger-box.copied .trigger-text { color: #fff !important; }
.trigger-list { display: flex; flex-direction: column; gap: 0.4rem; width: 100%; }
.trigger-empty { color: #555; font-size: 0.75rem; padding-left: 0.2rem; }
.card-actions {
display: flex; justify-content: space-between; align-items: center;
gap: 0.5rem; margin-top: auto; padding-top: 0.8rem; border-top: 1.1px solid #383838;
}
.action-btn {
display: inline-flex; align-items: center; justify-content: center; gap: 0.3rem;
background: #252525; color: #e8e8e8 !important; padding: 0.4rem 0.6rem;
border-radius: 6px; border: 1px solid #333; transition: all 0.15s ease;
text-decoration: none !important; font-size: 0.75rem; font-weight: 600;
white-space: nowrap; line-height: 1.2; flex: 1; text-align: center;cursor:pointer;
}
.action-btn:hover { background: #333; border-color: #555; color: #fff !important; }
.action-btn.primary { background: var(--primary-btn); border-color: var(--primary-btn); color: #fff !important; }
.action-btn.primary:hover { background: var(--primary-btn-hover); border-color: var(--primary-btn-hover); }
/* =========================================
Dataset Modal 弹窗样式
========================================= */
.modal-overlay {
position: fixed;
top: 0; left: 0; right: 0; bottom: 0;
background: rgba(0, 0, 0, 0.85);
backdrop-filter: blur(8px);
z-index: 10000;
display: flex;
align-items: center;
justify-content: center;
}
.modal-content {
background: #151515;
border: 1px solid #2a2a2a;
border-radius: 12px;
width: 90%;
max-width: 1200px;
height: 85vh;
display: flex;
flex-direction: column;
box-shadow: 0 20px 50px rgba(0, 0, 0, 0.9);
overflow: hidden;
}
.modal-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 1rem 1.5rem;
border-bottom: 1px solid #2a2a2a;
background: #1a1a1a;
}
.modal-header h3 {
margin: 0;
font-size: 1.1rem;
color: #fff;
}
.close-btn {
background: transparent;
border: none;
color: #888;
font-size: 1.8rem;
cursor: pointer;
transition: color 0.2s;
line-height: 1;
}
.close-btn:hover { color: #fff; }
.modal-body {
padding: 1.5rem;
display: flex;
flex-direction: column;
gap: 1rem;
flex: 1;
min-height: 0;
}
.viewer-controls {
display: flex;
align-items: center;
gap: 1rem;
font-size: 0.9rem;
color: #aaa;
margin-bottom: 0.5rem;
}
.viewer-controls select {
background: #252525;
color: #fff;
border: 1px solid #333;
padding: 0.5rem 1rem;
border-radius: 6px;
font-size: 0.9rem;
outline: none;
cursor: pointer;
font-family: inherit;
}
/* =========================================
网格视图 (Grid View)
========================================= */
.viewer-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(120px, 1fr));
gap: 0.8rem;
overflow-y: auto;
flex: 1;
min-height: 0;
align-content: start;
padding: 2px;
}
.grid-thumb-container {
width: 100%;
aspect-ratio: 1 / 1;
background: #1a1a1a;
border-radius: 6px;
overflow: hidden;
position: relative;
}
.grid-thumb-container::after {
content: "";
position: absolute;
inset: 0;
border-radius: 6px;
box-shadow: inset 0 0 0 1px #2a2a2a;
transition: box-shadow 0.15s ease;
pointer-events: none;
z-index: 10;
}
.grid-thumb-container:hover::after {
box-shadow: inset 0 0 0 2px var(--primary-btn);
}
.grid-thumb {
width: 100%;
height: 100%;
object-fit: cover;
cursor: pointer;
border: none;
opacity: 0;
transition: filter 0.15s ease, opacity 0.3s ease-in-out;
will-change: opacity;
}
.grid-thumb.loaded { opacity: 1; }
.grid-thumb-container:hover .grid-thumb { filter: brightness(1.15); }
/* =========================================
详情视图 (Detail View)
========================================= */
.viewer-display {
display: flex;
gap: 1.5rem;
flex: 1;
min-height: 0;
}
.image-container {
flex: 1.5;
background: #0f0f0f;
border-radius: 8px;
display: flex;
align-items: center;
justify-content: center;
overflow: hidden;
border: 1px solid #2a2a2a;
position: relative;
}
/* 🌟 优化:默认透明且不占据点击,由 JS 控制 opacity 和 display */
.image-container img {
max-width: 100%;
max-height: 100%;
object-fit: contain;
display: none;
position: relative;
z-index: 2;
}
.caption-container {
flex: 1;
display: flex;
flex-direction: column;
gap: 0.5rem;
}
.caption-container label {
font-size: 0.85rem;
color: #666;
text-transform: uppercase;
font-weight: 600;
}
.caption-container pre {
flex: 1;
background: #0f0f0f;
border: 1px solid #2a2a2a;
padding: 1rem;
border-radius: 8px;
color: #ccc;
font-family: ui-monospace, monospace;
font-size: 0.85rem;
white-space: pre-wrap;
overflow-y: auto;
margin: 0;
}
/* =========================================
大图 Loading 扫光特效
========================================= */
.viewer-loading-skeleton {
position: absolute;
inset: 0;
background: #181818;
overflow: hidden;
/* 文字居中 */
display: flex;
align-items: center;
justify-content: center;
color: #888;
font-family: ui-monospace, monospace;
font-size: 0.9rem;
z-index: 1; /* 保证在图片下方 */
}
.viewer-loading-skeleton::after {
content: "";
position: absolute;
top: -50%;
left: -50%;
width: 200%;
height: 200%;
/* 🌟 改为和 MainPage 一样的 135deg 斜向渐变 */
background: linear-gradient(135deg, transparent 30%, rgba(255, 255, 255, 0.08) 50%, transparent 70%);
animation: sweep-diagonal 1.5s infinite linear;
}
@keyframes sweep-diagonal {
0% { transform: translate(-40%, -40%); }
100% { transform: translate(40%, 40%); }
}
/* 注:如果你不再需要 pulse 动画,可以将 .loading-text 和 @keyframes pulse 删掉,保持代码整洁 */
/* =========================================
翻页按钮 & 响应式
========================================= */
.nav-btn-arrow {
position: absolute;
top: 50%;
transform: translateY(-50%);
background: rgba(0, 0, 0, 0.6);
color: #fff;
border: 1px solid rgba(255,255,255,0.2);
width: 40px;
height: 40px;
border-radius: 50%;
font-size: 1.2rem;
cursor: pointer;
z-index: 10;
display: flex;
justify-content: center;
align-items: center;
transition: background 0.2s;
}
.nav-btn-arrow:hover {
background: rgba(37, 99, 235, 0.9);
}
@media (max-width: 800px) {
.viewer-display {
flex-direction: column;
}
.image-container {
flex: 1;
}
.caption-container {
flex: 0.5;
}
}
/* =========================================
Pagination 样式
========================================= */
.page-btn {
background: #252525;
border: 1px solid #333;
color: #ccc;
min-width: 32px;
height: 32px;
border-radius: 6px;
display: flex;
justify-content: center;
align-items: center;
cursor: pointer;
font-size: 0.85rem;
font-weight: 600;
transition: all 0.15s ease;
padding: 0 0.5rem;
}
.page-btn:hover:not(:disabled):not(.active) {
background: #333;
border-color: #555;
color: #fff;
}
.page-btn.active {
background: var(--primary-btn);
border-color: var(--primary-btn);
color: #fff;
}
.page-btn:disabled {
opacity: 0.3;
cursor: not-allowed;
}
.page-dots {
color: #666;
font-weight: 600;
padding: 0 0.2rem;
}
/* =========================================
Showcase 专属 UI 样式 (全量最终版)
========================================= */
/* 1. Showcase 主界面的整行按钮 */
.showcase-full-btn {
width: 100%;
background: #252525; /* 和 Dataset 按钮一样的底色 */
border: 1px solid #333;
color: #e8e8e8; /* 用暗金色文字,和顶部 Disclaimer 呼应 */
padding: 0.4rem 0.6rem;
border-radius: 6px;
font-size: 0.75rem;
font-weight: 600;
cursor: pointer;
display: flex;
justify-content: center;
align-items: center;
gap: 0.4rem; /* 增加图标和文字的间距 */
transition: all 0.15s ease;
}
.showcase-full-btn:hover {
background: #333;
border-color: #555;
color: #fff; /* Hover 时文字变白 */
}
/* 2. 右侧整体容器 */
.caption-container {
display: flex;
flex-direction: column;
height: 100%;
overflow: hidden;
gap: 0.6rem;
}
/* 3. 头部 (PROMPT 标签 + Token + Copy 按钮) */
.caption-header {
display: flex;
justify-content: space-between;
align-items: center;
flex-shrink: 0; /* 防止被挤压 */
}
/* 4. 文本框 (核心:撑满下方剩余空间) */
#viewer-txt {
flex: 1; /* 自动拉伸填满 */
margin: 0;
padding: 1rem;
background: #0f0f0f;
border: 1px solid #2a2a2a;
border-radius: 8px;
font-family: ui-monospace, monospace;
color: #d0d0d0;
overflow-y: auto;
white-space: pre-wrap;
}
/* 5. 拖拽提示框 */
#drag-tip {
display: none;
align-items: center;
gap: 0.5rem;
font-size: 0.7rem;
color: #6cf;
background: rgba(108, 204, 255, 0.1);
padding: 0.4rem 0.6rem;
border-radius: 6px;
border: 1px dashed rgba(108, 204, 255, 0.3);
flex-shrink: 0;
}
/* 6. 竖向参数面板 */
#params-panel {
display: none;
flex-direction: column;
gap: 0.4rem;
flex-shrink: 0; /* 保证参数面板不会被压缩 */
}
/* 参数行布局 */
.param-row {
display: flex;
align-items: flex-start;
gap: 0.5rem;
font-size: 0.75rem; /* 整体小巧 */
margin-bottom: 0.2rem; /* 轻微呼吸感 */
}
/* 参数左侧的 Key */
.param-key {
color: #888;
min-width: 55px;
text-align: left;
font-size: 0.65rem;
font-weight: 500;
flex-shrink: 0;
line-height: 1.4;
}
/* 参数右侧的 Value (精致轻量版) */
.param-value {
color: #e0e0e0 !important;
font-weight: 700 !important;
border-radius: 4px;
font-family: ui-monospace, monospace;
font-size: 0.7rem;
word-break: break-all;
line-height: 1.4;
}
/* LoRA 的独立小框容器 */
.lora-container {
display: flex;
flex-wrap: wrap;
gap: 0.3rem;
flex: 1;
}
/* =========================================
Animations
========================================= */
@keyframes pulse {
0% { opacity: 0.6; }
50% { opacity: 1; }
100% { opacity: 0.6; }
}