feat: 论坛贴吧风格大升级(L1版块索引+L2版块页+L3楼层帖+置顶/加精/多版主/admin超管+后台帖子管理+分享)

This commit is contained in:
2026-08-12 18:14:12 +08:00
parent cdd72e29d1
commit a9726df1ee
18 changed files with 1783 additions and 443 deletions
+53
View File
@@ -0,0 +1,53 @@
import React from 'react';
/**
* 论坛版块图标(L1/L2 共用):
* - cat.icon 非空:http(s) 开头渲染图片;否则按单个 emoji 字符渲染
* - 无 icon 时取名称首字(大写)
* - 底色:icon_color 自定义 hex(自动按亮度选深/浅文字色);
* 空则按名称哈希选 12 色 MD3 container/onContainer 对(style.css 的 .tone-N,深浅色自适应)
*/
export default function ForumIcon({ icon = '', name = '', iconColor = '', size = 40 }) {
const raw = String(icon || '').trim();
const isUrl = /^https?:\/\//i.test(raw);
const isEmoji = !!raw && !isUrl;
const letter = (name || '').trim().charAt(0).toUpperCase() || '?';
// 名称哈希 → 0..11 的色调组
let h = 0;
const key = String(name || '');
for (let i = 0; i < key.length; i += 1) h = (h * 31 + key.charCodeAt(i)) >>> 0;
const style = { width: size, height: size, fontSize: Math.round(size * 0.48), borderRadius: 12 };
// 自定义 icon_colorhex → 按 luma 选深/浅文字色(近似 MD3 on-container
if (iconColor) {
let hex = String(iconColor).replace('#', '');
if (hex.length === 3) hex = hex.split('').map((c) => c + c).join('');
const n = parseInt(hex, 16);
if (!isNaN(n) && hex.length === 6) {
const r = (n >> 16) & 255;
const g = (n >> 8) & 255;
const b = n & 255;
const luma = (0.299 * r + 0.587 * g + 0.114 * b) / 255;
style.background = '#' + hex;
style.color = luma > 0.6 ? 'rgba(0,0,0,0.8)' : '#ffffff';
}
}
if (isUrl) {
return (
<span className="forum-icon forum-icon-img" style={{ ...style, background: 'var(--md-ref-surface-container-high)' }}>
<img src={raw} alt="" />
</span>
);
}
if (isEmoji) {
return (
<span className="forum-icon" style={{ ...style, background: 'var(--md-ref-surface-container-high)' }}>
{raw}
</span>
);
}
return <span className={'forum-icon tone-' + (h % 12)} style={style}>{letter}</span>;
}