Files
Victor_Jay 4ac4f64f33 feat: @提及功能优化 + 默认头像改用SVG图标
- 评论区有效@提及渲染为蓝色链接跳转/space/{uid},无效@保持纯文本
- 输入@触发悬浮窗,根据输入实时搜索用户(含头像+等级)
- 无匹配时显示未搜索到用户,选中后插入为@用户名 格式(尾部空格)
- 悬浮窗定位于输入光标上方,不遮挡输入内容
- 后端Comment新增Mentions字段,批量加载提及映射供前端判断
- SearchUsers/parseMentions 统一限制LV2+用户
- 所有默认头像由首字符文字改为统一SVG人形图标(nav/home/space/mention等7处)
2026-06-03 00:49:24 +08:00

697 lines
20 KiB
CSS
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/* ============================================================
MetaLab Space Styles — 统一空间页面(文章/关注/收藏/设置)
============================================================ */
/* ---------- Error State ---------- */
.space-error {
text-align: center;
padding: 80px 20px;
flex: 1;
display: flex;
align-items: center;
justify-content: center;
}
.space-error h1 {
font-size: 1.5rem;
color: var(--color-secondary);
margin-bottom: 1.5rem;
}
.space-error .btn {
display: inline-block;
padding: .6rem 1.8rem;
background: var(--color-accent);
color: #fff;
border-radius: var(--radius);
font-weight: 600;
transition: var(--transition);
}
.space-error .btn:hover { background: #2980b9; transform: translateY(-1px); }
/* ---------- Page Layout ---------- */
.space-page {
flex: 1;
}
/* ============================================================
Profile Header顶部信息栏
============================================================ */
.space-profile-header {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
padding: 1.25rem 0;
}
.space-header-inner {
max-width: 1200px;
margin: 0 auto;
padding: 0 1rem;
display: flex;
align-items: center;
justify-content: space-between;
}
.space-header-user {
display: flex;
align-items: center;
gap: .75rem;
}
.space-avatar-link {
text-decoration: none;
display: block;
}
.space-avatar-img {
width: 56px; height: 56px;
border-radius: 50%;
object-fit: cover;
border: 2px solid rgba(255,255,255,.4);
display: block;
}
.space-avatar-placeholder {
width: 56px; height: 56px;
border-radius: 50%;
background: rgba(255,255,255,.25);
color: rgba(255,255,255,.75);
display: flex;
align-items: center;
justify-content: center;
border: 2px solid rgba(255,255,255,.4);
}
.space-avatar-placeholder svg {
width: 55%;
height: 55%;
}
.space-header-info {
color: #fff;
}
.space-username {
font-size: 1.2rem;
font-weight: 700;
color: #fff;
}
.space-header-bio {
font-size: .8rem;
color: rgba(255,255,255,.75);
margin: .15rem 0 0;
}
.space-header-actions {
display: flex;
gap: .5rem;
align-items: center;
}
.space-action-btn {
padding: .45rem 1.1rem;
border-radius: var(--radius);
font-size: .85rem;
font-weight: 500;
cursor: pointer;
border: none;
transition: all .15s ease;
background: rgba(255,255,255,.2);
color: #fff;
}
.space-action-btn:hover { background: rgba(255,255,255,.35); }
.space-action-btn.primary { background: #00a1d6; }
.space-action-btn.primary:hover { background: #0090c0; }
.space-action-btn.primary.followed { background: rgba(255,255,255,.2); }
.space-action-btn.icon-only {
padding: .45rem .6rem; font-size: 1.2rem;
line-height: 1;
}
/* ============================================================
Tab Navigation BarTab 导航栏)
============================================================ */
.space-tab-bar {
max-width: 1200px;
margin: 0 auto;
padding: 0 1rem;
display: flex;
align-items: center;
border-bottom: 1px solid var(--color-border, #e5e7eb);
background: var(--color-surface, #fff);
position: sticky;
top: 0;
z-index: 10;
}
.space-tab-bar.owner { justify-content: space-between; max-width: none; }
.space-tab-bar.visitor { }
.space-tabs-left {
display: flex;
align-items: center;
gap: .125rem;
overflow-x: auto;
}
.space-tab {
display: flex;
align-items: center;
gap: .3rem;
padding: .85rem 1.1rem;
text-decoration: none;
color: var(--color-text);
font-size: .92rem;
white-space: nowrap;
border-bottom: 2px solid transparent;
transition: all .15s ease;
position: relative;
}
.space-tab:hover { color: var(--color-accent); background: rgba(0,161,214,.04); }
.space-tab.active { color: var(--color-accent); border-bottom-color: var(--color-accent); font-weight: 600; }
.space-tab svg { opacity: .7; }
.space-tab.active svg { opacity: 1; }
.tab-count {
font-size: .78rem; color: var(--color-secondary); font-weight: 400;
}
.space-tab.active .tab-count { color: var(--color-accent); }
/* 右侧统计区域(本人视图)*/
.space-stats-right {
display: flex;
gap: 1.5rem;
padding-right: .5rem;
flex-shrink: 0;
}
.stat-item {
text-align: right;
}
.stat-label {
display: block; font-size: .72rem; color: var(--color-secondary);
}
.stat-value {
display: block; font-size: .88rem; font-weight: 600; color: var(--color-primary);
}
/* 访客视图:内联统计 */
.stat-item-inline {
display: flex; align-items: baseline; gap: .25rem; padding: 0 .6rem;
border-left: 1px solid var(--color-border, #eee); font-size: .82rem;
}
.stat-label-inline { color: var(--color-secondary); white-space: nowrap; }
.stat-value-inline { font-weight: 600; color: var(--color-primary); }
/* ============================================================
Card Layout — 左右分栏
============================================================ */
.space-card-layout {
display: flex;
max-width: 1200px;
margin: 0 auto;
padding: 1.5rem 1rem;
gap: 1.5rem;
min-height: calc(100vh - 220px);
}
/* ============================================================
Sidebar左侧导航
============================================================ */
.space-sidebar {
width: 200px;
flex-shrink: 0;
}
.space-sidebar-title {
font-size: .95rem;
font-weight: 600;
color: var(--color-primary);
margin-bottom: .75rem;
padding-left: .25rem;
display: flex; align-items: center; justify-content: space-between;
}
.space-sidebar-title.collapsible { cursor: pointer; user-select: none; }
.collapse-arrow { transition: transform .2s; opacity: .5; }
.space-sidebar-title.collapsed .collapse-arrow { transform: rotate(-180deg); }
.space-sidebar-nav {
display: flex; flex-direction: column; gap: 2px;
}
.space-sidebar-nav.collapsed { display: none; }
.space-sidebar-link {
display: flex; align-items: center; gap: .5rem;
padding: .65rem .75rem;
border-radius: var(--radius);
text-decoration: none;
color: var(--color-text);
font-size: .9rem;
transition: background-color .15s ease;
}
.space-sidebar-link:hover { background-color: #f5f5f5; }
.space-sidebar-link.active {
background-color: var(--color-accent);
color: #fff; font-weight: 500;
}
.space-sidebar-link.active:hover { background-color: #2980b9; }
.space-sidebar-icon { flex-shrink: 0; opacity: .8; }
.space-sidebar-link.active .space-sidebar-icon { opacity: 1; }
.space-sidebar-count { margin-left: auto; font-size: .8rem; opacity: .7; }
.space-sidebar-link.active .space-sidebar-count { opacity: 1; }
.new-folder-btn { color: var(--color-accent) !important; font-size: .85rem !important; }
.new-folder-btn:hover { background-color: rgba(0,161,214,.06) !important; }
#new-folder-input {
display: flex; gap: .35rem; padding: .35rem .25rem;
}
.new-folder-input {
flex: 1; padding: .35rem .55rem;
border: 1px solid var(--color-border, #ddd);
border-radius: 4px; font-size: .82rem; outline: none;
}
.new-folder-input:focus { border-color: var(--color-accent); }
.new-folder-submit {
padding: .35rem .55rem; background: var(--color-accent);
color: #fff; border: none; border-radius: 4px;
font-size: .8rem; cursor: pointer;
}
.new-folder-submit:hover { background: #2980b9; }
/* ============================================================
Main Content右侧内容区
============================================================ */
.space-main {
flex: 1; min-width: 0;
}
.space-main-full { width: 100%; }
.space-main-title {
font-size: 1.35rem;
font-weight: 700;
color: var(--color-primary);
margin-bottom: 1.25rem;
}
.space-section-title {
font-size: 1.35rem;
font-weight: 700;
color: var(--color-primary);
margin-bottom: 1.5rem;
}
/* ============================================================
关注列表搜索框
============================================================ */
.space-follow-search {
display: flex;
margin-bottom: 1.25rem;
border: 1px solid var(--color-border, #e5e7eb);
border-radius: 20px;
padding: .35rem 1rem;
background: var(--color-surface, #fff);
transition: border-color .15s;
}
.space-follow-search:focus-within {
border-color: var(--color-accent);
}
.follow-search-input {
flex: 1;
border: none;
outline: none;
font-size: .88rem;
background: transparent;
color: var(--color-text);
}
.follow-search-input::placeholder { color: var(--color-secondary); }
.follow-search-btn {
border: none; background: none; cursor: pointer;
padding: .15rem; color: var(--color-secondary);
display: flex; align-items: center;
}
.follow-search-btn:hover { color: var(--color-accent); }
/* ============================================================
User Card Grid — 用户卡片网格(关注/粉丝列表)
============================================================ */
.space-user-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
gap: 1rem;
}
.space-user-card {
display: flex;
align-items: flex-start;
gap: .75rem;
padding: 1rem 1.1rem;
background: var(--color-surface, #fff);
border: 1px solid var(--color-border, #e5e7eb);
border-radius: var(--radius);
transition: box-shadow .2s ease, border-color .2s ease;
}
.space-user-card:hover {
box-shadow: 0 2px 12px rgba(0,0,0,.06);
border-color: #ccc;
}
.space-user-avatar-wrap { flex-shrink: 0; text-decoration: none; display: block; }
.space-user-avatar-img {
width: 48px; height: 48px; border-radius: 50%; object-fit: cover; display: block;
}
.space-user-avatar-placeholder {
width: 48px; height: 48px; border-radius: 50%;
background: var(--color-accent); color: rgba(255,255,255,.75);
display: flex; align-items: center; justify-content: center;
}
.space-user-avatar-placeholder svg {
width: 55%;
height: 55%;
}
.space-user-info { flex: 1; min-width: 0; }
.space-user-name {
display: block; font-size: .92rem; font-weight: 600;
color: var(--color-primary); text-decoration: none;
line-height: 1.3; margin-bottom: .2rem;
overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.space-user-name:hover { color: var(--color-accent); }
.space-user-bio {
font-size: .8rem; color: var(--color-text-light);
line-height: 1.4; margin: 0;
display: -webkit-box; -webkit-line-clamp: 2;
-webkit-box-orient: vertical; overflow: hidden; word-break: break-word;
}
/* Follow Button in Card */
.space-follow-btn {
flex-shrink: 0; padding: .28rem .7rem;
border: 1.5px solid var(--color-accent);
border-radius: 6px; font-size: .8rem; font-weight: 500;
cursor: pointer; transition: all .15s ease;
background: transparent; color: var(--color-accent); line-height: 1.4;
}
.space-follow-btn:hover { background: var(--color-accent); color: #fff; }
.space-follow-btn.followed {
background: transparent; border-color: var(--color-border, #e5e7eb);
color: var(--color-secondary); cursor: default;
}
.space-follow-btn.followed:hover { background: transparent; color: var(--color-secondary); }
.space-follow-btn.waiting { opacity: .6; pointer-events: none; }
/* ============================================================
Post List — 文章列表
============================================================ */
.space-post-list {
display: flex; flex-direction: column; gap: .75rem;
}
.space-post-card {
padding: 1.1rem 1.3rem;
background: var(--color-surface, #fff);
border: 1px solid var(--color-border, #e5e7eb);
border-radius: var(--radius);
transition: box-shadow .2s ease, border-color .2s ease;
}
.space-post-card:hover {
box-shadow: 0 2px 12px rgba(0,0,0,.06);
border-color: #ccc;
}
.space-post-title {
font-size: 1.05rem; font-weight: 600;
color: var(--color-primary); text-decoration: none;
display: block; line-height: 1.4; margin-bottom: .4rem;
}
.space-post-title:hover { color: var(--color-accent); }
.space-post-excerpt {
font-size: .86rem; color: var(--color-text-light);
line-height: 1.6; margin: 0 0 .6rem;
display: -webkit-box; -webkit-line-clamp: 2;
-webkit-box-orient: vertical; overflow: hidden;
}
.space-post-meta {
display: flex; align-items: center; gap: 1rem;
font-size: .78rem; color: var(--color-secondary);
}
.post-meta-item {
display: flex; align-items: center; gap: .2rem;
}
.post-meta-time { margin-left: auto; }
/* ============================================================
Article Grid — 收藏夹文章卡片网格
============================================================ */
.space-article-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
gap: 1rem;
}
.space-article-card {
background: var(--color-surface, #fff);
border: 1px solid var(--color-border, #e5e7eb);
border-radius: var(--radius);
overflow: hidden;
transition: box-shadow .2s ease, border-color .2s ease;
cursor: pointer;
}
.space-article-card:hover {
box-shadow: 0 3px 12px rgba(0,0,0,.08);
border-color: #ccc;
}
.article-card-link {
display: block; padding: 1rem; text-decoration: none;
}
.article-card-title {
font-size: .9rem; font-weight: 600;
color: var(--color-primary);
line-height: 1.4;
margin: 0;
display: -webkit-box; -webkit-line-clamp: 2;
-webkit-box-orient: vertical; overflow: hidden;
}
.article-card-link:hover .article-card-title { color: var(--color-accent); }
.article-card-footer {
display: flex; align-items: center; justify-content: space-between;
padding: .5rem 1rem; border-top: 1px solid var(--color-border, #f0f0f0);
font-size: .72rem; color: var(--color-secondary);
}
.article-card-author { display: flex; align-items: center; gap: .2rem; }
.article-card-time { flex-shrink: 0; }
/* ============================================================
Collection Header收藏夹头部信息
============================================================ */
.collection-header { margin-bottom: 1.25rem; }
.collection-cover-placeholder {
width: 160px; height: 90px; border-radius: var(--radius);
background: linear-gradient(135deg, #667eea20, #764ba220);
margin-bottom: .75rem;
}
.collection-info-row {
display: flex; align-items: flex-start; justify-content: space-between;
gap: 1rem;
}
.collection-name { font-size: 1.2rem; font-weight: 700; color: var(--color-primary); margin: 0 0 .2rem; }
.collection-meta { font-size: .82rem; color: var(--color-secondary); margin: 0; }
.collection-actions { display: flex; gap: .5rem; flex-shrink: 0; }
.space-action-btn.small { padding: .35rem .85rem; font-size: .8rem; }
.space-action-btn.outline {
background: transparent; border: 1px solid var(--color-border, #ddd);
color: var(--color-text);
}
.space-action-btn.outline:hover { border-color: var(--color-accent); color: var(--color-accent); }
/* Collection Sort Bar */
.collection-sort-bar {
display: flex; align-items: center; justify-content: space-between;
gap: 1rem; margin-bottom: 1.25rem;
padding-bottom: .75rem;
border-bottom: 1px solid var(--color-border, #f0f0f0);
}
.sort-tabs { display: flex; gap: .25rem; }
.sort-tab {
padding: .35rem .85rem; border: 1px solid transparent;
border-radius: 16px; font-size: .84rem; cursor: pointer;
background: transparent; color: var(--color-secondary); transition: all .15s;
}
.sort-tab.active { background: var(--color-accent); color: #fff; border-color: var(--color-accent); }
.sort-tab:hover:not(.active) { background: #f5f5f5; color: var(--color-text); }
.collection-filter { display: flex; align-items: center; gap: .5rem; }
.filter-select {
padding: .3rem .5rem; border: 1px solid var(--color-border, #ddd);
border-radius: 4px; font-size: .82rem; outline: none; color: var(--color-text);
}
.filter-search {
display: flex; align-items: center;
border: 1px solid var(--color-border, #ddd); border-radius: 20px;
padding: .2rem .6rem; transition: border-color .15s;
}
.filter-search:focus-within { border-color: var(--color-accent); }
.filter-search-input {
border: none; outline: none; font-size: .82rem; width: 140px;
background: transparent;
}
.filter-search-input::placeholder { color: var(--color-secondary); }
.filter-search-btn { border:none; background:none; cursor:pointer; padding:.15rem; color:var(--color-secondary); display:flex; align-items:center;}
.filter-search-btn:hover { color:var(--color-accent); }
/* ============================================================
Privacy Settings — 隐私设置页
============================================================ */
.privacy-settings-grid {
display: grid;
grid-template-columns: 1fr 1fr 1fr;
gap: 1.25rem 2rem;
}
.privacy-row {
display: flex; align-items: center; justify-content: space-between;
padding: .6rem 0;
}
.privacy-label {
font-size: .9rem; color: var(--color-text); font-weight: 500;
}
/* Toggle Switch */
.toggle-switch {
position: relative; display: inline-block; width: 44px; height: 24px;
flex-shrink: 0; cursor: pointer;
}
.toggle-switch input { opacity: 0; width: 0; height: 0; }
.toggle-slider {
position: absolute; inset: 0; background: #ccc;
border-radius: 24px; transition: .25s;
}
.toggle-slider::before {
content: ''; position: absolute; height: 18px; width: 18px;
left: 3px; bottom: 3px; background: #fff;
border-radius: 50%; transition: .25s;
}
.toggle-switch input:checked + .toggle-slider { background: var(--color-accent); }
.toggle-switch input:checked + .toggle-slider::before { transform: translateX(20px); }
/* ============================================================
Empty / Private States
============================================================ */
.space-empty-state {
text-align: center; padding: 4rem 1rem; color: var(--color-secondary); font-size: .95rem;
}
.space-private-empty {
display: flex; flex-direction: column; align-items: center;
justify-content: center; padding: 5rem 1rem; text-align: center;
}
.space-private-illustration { margin-bottom: 1.25rem; opacity: .6; }
.space-private-text { color: var(--color-secondary); font-size: .95rem; margin-bottom: 1rem; }
.space-private-setting-btn {
display: inline-block; padding: .5rem 1.25rem;
background: var(--color-accent); color: #fff; border-radius: var(--radius);
font-size: .88rem; text-decoration: none; transition: background .15s;
}
.space-private-setting-btn:hover { background: #2980b9; }
/* ============================================================
Pagination
============================================================ */
.pagination {
display: flex; justify-content: center; align-items: center;
gap: 1rem; margin-top: 2rem; font-size: .9rem;
}
.page-link {
padding: .4rem 1rem; border: 1px solid var(--color-border);
border-radius: var(--radius); color: var(--color-accent); transition: var(--transition);
}
.page-link:hover { border-color: var(--color-accent); background: rgba(52,152,219,.05); }
.page-info { color: var(--color-secondary); }
/* ============================================================
Responsive 响应式
============================================================ */
@media (max-width: 768px) {
.space-profile-header { padding: 1rem 0; }
.space-header-inner { flex-wrap: wrap; gap: .5rem; }
.space-header-actions { width: 100%; justify-content: flex-end; }
.space-tab-bar { overflow-x: auto; }
.space-tab-bar.owner { flex-direction: column; align-items: stretch; }
.space-stats-right { justify-content: flex-start; gap: 1rem; padding: .5rem 0; }
.stat-item-inline { border-left: none; padding-left: 0; }
.space-card-layout { flex-direction: column; padding: 1rem .75rem; }
.space-sidebar { width: 100%; }
.space-sidebar-nav { flex-direction: row; overflow-x: auto; gap: .5rem; -webkit-overflow-scrolling: touch; }
.space-sidebar-link { white-space: nowrap; flex-shrink: 0; }
.space-user-grid { grid-template-columns: 1fr; }
.space-article-grid { grid-template-columns: 1fr 1fr; }
.privacy-settings-grid { grid-template-columns: 1fr; }
.collection-info-row { flex-direction: column; }
.collection-sort-bar { flex-direction: column; align-items: stretch; }
.collection-filter { justify-content: flex-end; }
}
@media (max-width: 480px) {
.space-article-grid { grid-template-columns: 1fr; }
.space-username { font-size: 1rem; }
.space-avatar-img, .space-avatar-placeholder { width: 44px; height: 44px; }
}