feat: 论坛 emoji 表情支持

- 新增 dyEmoji 表情库与解析测试、EmojiPicker 选择器与 EmojiImg 组件
- Markdown 编辑器/渲染支持表情图片,新增 public/emoji 资源与生成脚本
- 聊天室与首页适配
This commit is contained in:
2026-09-28 01:28:41 +08:00
parent 2f96a36275
commit 34aee91a13
3522 changed files with 1560 additions and 251 deletions

View File

@@ -3662,20 +3662,50 @@ select:focus-visible {
.j13-chat-composer-input:focus-visible {
outline: none !important;
box-shadow: none !important;
resize: none !important;
}
.j13-chat-composer-input.has-value {
color: transparent;
/* 富输入区(contentEditable):表情图片与 @ 胶囊直接在输入框内渲染 */
.j13-chat-rich-input {
white-space: pre-wrap;
overflow-wrap: break-word;
word-break: break-word;
overflow-y: auto;
cursor: text;
min-height: 36px;
max-height: 128px;
color: var(--ink);
caret-color: var(--ink);
}
/* 框选时 ::selection 前景色会盖过透明字色,露出底层真实文本(@用户名);
这里保持字形透明 + 半透明高亮,让镜像层的 @昵称 透出(宽度已补偿对齐) */
.j13-chat-composer-input.has-value::selection {
background: color-mix(in srgb, var(--accent) 24%, transparent);
color: transparent;
.j13-chat-rich-input:empty::before {
content: attr(data-placeholder);
color: var(--ink-3);
pointer-events: none;
}
.j13-chat-composer-input.has-value::placeholder {
color: transparent;
.j13-input-emoji {
display: inline-block;
width: 20px;
height: 20px;
object-fit: contain;
/* 与汉字视觉居中:汉字字面中心在基线上方 ≈0.385em,vertical-align = 0.385×字号 − 图高/2
20px 图 @14px 字号:5.4 − 10 = −4.6(负值=图片下沉;middle 会以 x-height 对齐导致偏下) */
vertical-align: -4.6px;
margin: 0 1px;
cursor: default;
user-select: none;
-webkit-user-select: none;
-webkit-touch-callout: none;
}
/* 输入框内的 @ 胶囊:与镜像期一致的蓝色文字风格,contenteditable=false 原子整体 */
.j13-chat-rich-input .j13-mention-token {
display: inline;
padding: 0;
margin: 0;
line-height: inherit;
font-weight: 500;
border-radius: 0;
box-shadow: none;
background: transparent !important;
color: var(--accent) !important;
cursor: text;
}
.admin-field-shell,
@@ -3732,16 +3762,6 @@ select:focus-visible {
width: 0;
height: 0;
}
.j13-chat-composer-mirror {
position: absolute;
inset: 0;
overflow: hidden;
pointer-events: none;
white-space: pre-wrap;
overflow-wrap: break-word;
word-break: break-word;
color: var(--ink);
}
.j13-mention-token {
display: inline-block;
padding: 2px 8px;
@@ -3768,19 +3788,6 @@ a.j13-mention-token:hover {
background: var(--accent);
color: var(--accent-on) !important;
}
/* 输入镜像层:token 仅蓝色文字(胶囊样式只在发出后的气泡里显示);
基础胶囊色带 !important,此处需同权重覆盖 */
.j13-chat-composer-mirror .j13-mention-token {
display: inline;
padding: 0;
margin: 0;
line-height: inherit;
font-weight: 500;
border-radius: 0;
box-shadow: none;
background: transparent !important;
color: var(--accent) !important;
}
@layer components {
/* ----- 小标签(旧名 .kicker 保留兼容) ----- */
@@ -8586,6 +8593,8 @@ html.dark .prose-content pre[data-theme] span {
}
/* 首页桌面:顶部留白 20px → 8px,中栏信息流上移贴页头;
main 变 flex 列、三栏区 flex:1 撑满 main——分隔线不随帖子数量缩短,
从页头下沿贯通到页脚上沿;
sticky 侧栏的 --rail-top/--rail-max-h 在 #main 上重算(custom property
在声明处求值,:root 的 --rail-max-h 不会因子级重定义 --rail-top 而更新) */
@media (min-width: 1024px) {
@@ -8593,6 +8602,13 @@ html.dark .prose-content pre[data-theme] span {
padding-top: 0.5rem;
--rail-top: calc(var(--header-h) + 0.5rem);
--rail-max-h: calc(100vh - var(--rail-top) - 1rem);
display: flex;
flex-direction: column;
}
.j13-fluid-home {
display: flex;
flex-direction: column;
flex: 1;
}
}
@@ -8644,7 +8660,9 @@ html:not(.j13-has-site-bg) #main {
font-size: 13px;
}
/* 首页三栏竖向分隔线:与页头下边线同色同宽,居中于栏间距(gap-6 / xl:gap-7),
画在中栏伪元素上与左右栏共用一条;类名跟随左右栏显隐,避免悬空线 */
画在中栏伪元素上与左右栏共用一条;类名跟随左右栏显隐,避免悬空线。
上接页头下边线(抵消 #main 顶部 0.5rem)、下接页脚上沿(抵消 #main 底部
--main-pad-y):中栏 self-stretch 撑满行高(左右栏保持 items-start 不破坏 sticky) */
.j13-home-sep-l,
.j13-home-sep-r {
position: relative;
@@ -8654,8 +8672,8 @@ html:not(.j13-has-site-bg) #main {
.j13-home-sep-r::after {
content: "";
position: absolute;
top: 0;
bottom: 0;
top: -0.5rem;
bottom: calc(-1 * var(--main-pad-y));
width: 1px;
background: var(--line);
}
@@ -9768,3 +9786,150 @@ html.j13-reduce-chrome .j13-att-card.is-fresh {
min-width: 0;
}
/* ── 抖音表情(douyin-emoji):编辑器弹层面板 / 聊天面板 / 行内图片 ── */
.j13-emoji-picker {
display: flex;
flex-direction: column;
min-width: 0;
}
.j13-emoji-tabs {
display: flex;
gap: 2px;
padding: 0 0 6px;
border-bottom: 1px solid var(--line);
margin-bottom: 6px;
}
.j13-emoji-tabs button {
padding: 4px 10px;
border-radius: 8px;
border: 0;
appearance: none;
-webkit-appearance: none;
font-size: 12.5px;
font-weight: 500;
cursor: pointer;
color: var(--ink-2);
background: transparent;
transition: background 0.12s ease, color 0.12s ease;
}
.j13-emoji-tabs button:hover {
background: var(--panel-2);
color: var(--ink);
}
.j13-emoji-tabs button.is-on {
background: var(--accent-soft);
color: var(--accent);
}
/* 分组滚动容器:整体滚动,分组小标题随内容排列 */
.j13-emoji-scroll {
max-height: 264px;
overflow-y: auto;
overscroll-behavior: contain;
}
.j13-emoji-group + .j13-emoji-group {
margin-top: 4px;
}
.j13-emoji-group-label {
padding: 6px 2px 4px;
font-size: 11.5px;
color: var(--ink-3);
}
.j13-emoji-grid {
display: grid;
grid-template-columns: repeat(auto-fill, 36px);
justify-content: space-between;
gap: 2px;
}
.j13-emoji-cell {
width: 36px;
height: 36px;
display: inline-flex;
align-items: center;
justify-content: center;
border: 0;
appearance: none;
-webkit-appearance: none;
border-radius: 8px;
background: transparent;
cursor: pointer;
transition: background 0.12s ease;
}
.j13-emoji-cell:hover {
background: var(--panel-2);
}
.j13-emoji-cell:focus-visible {
outline: 2px solid var(--accent);
outline-offset: 0;
}
.j13-emoji-cell img {
width: 28px;
height: 28px;
object-fit: contain;
pointer-events: none;
}
.j13-emoji-empty {
grid-column: 1 / -1;
text-align: center;
padding: 18px 0;
}
/* Markdown 正文中的表情:当作文字表情而非媒体图片——
显式关闭 .prose-content img 的边框/放大手势/hover 阴影;
垂直方向贴合文字视觉中线 */
.md-content-img.j13-md-emoji,
.prose-content img.j13-md-emoji {
display: inline-block;
width: 28px;
height: 28px;
object-fit: contain;
/* 与汉字视觉居中:28px 图 @16.5px 正文:6.35 − 14 = −7.7(推导同 .j13-input-emoji) */
vertical-align: -7.7px;
margin: 0 1px;
border: 0;
border-radius: 0;
cursor: default;
user-select: none;
-webkit-user-select: none;
-webkit-touch-callout: none;
}
/* 聊天消息气泡中的表情:视为文字表情而非图片——
不可选中、不可拖拽、长按/右键不出现图片操作(保存/拷贝图像等);
垂直方向贴合文字视觉中线 */
.j13-chat-emoji {
display: inline-block;
width: 28px;
height: 28px;
object-fit: contain;
/* 与汉字视觉居中:28px 图 @14px 字号:5.4 − 14 = −8.6(推导同 .j13-input-emoji) */
vertical-align: -8.6px;
margin: 0 1px;
cursor: default;
user-select: none;
-webkit-user-select: none;
-webkit-touch-callout: none;
}
/* 纯表情消息的贴纸大图 */
.j13-chat-emoji-lg {
width: 96px;
height: 96px;
vertical-align: middle;
}
/* 编辑器弹层里的表情面板容器 */
.j13-md-emoji-popover {
width: 320px;
max-width: calc(100vw - 32px);
}
/* 聊天输入区上方的表情面板 */
.j13-chat-emoji-panel {
position: absolute;
bottom: calc(100% + 8px);
left: 0;
z-index: 40;
width: 320px;
max-width: calc(100vw - 48px);
padding: 10px;
border-radius: 14px;
background: var(--panel);
border: 1px solid var(--line);
box-shadow: var(--shadow-lg);
}