feat: 品牌裁剪弹窗/Markdown 行内短代码与详情视频块等

新增:
- BrandCropModal 品牌图裁剪弹窗 + cropImage 工具
- Markdown 行内短代码(inlineShortcodes + remark 插件)
- MdDetails 折叠块、MdVideo 视频块组件
- directiveBlocks/inlineShortcodes 测试

其它:
- 聊天后端(handler/service chat)调整
- Markdown 渲染链路、编辑器、全局样式与品牌相关面板更新
This commit is contained in:
2026-10-02 01:40:06 +08:00
parent 3e98052c16
commit 99c0f0319d
23 changed files with 2012 additions and 119 deletions

View File

@@ -237,7 +237,11 @@ body {
/* 亚像素渲染在 Windows 高分屏更实;强制 grayscale 会让 400/500 中文偏虚 */
-webkit-font-smoothing: auto;
text-rendering: optimizeLegibility;
font-synthesis: none; /* 禁止伪粗,避免缺档字重糊成一团 */
/* 长手属性只禁伪粗(缺档字重糊成一团);放开伪斜体,让 em/斜体按钮生效。
首行兜底:不支持长手属性的老浏览器维持全禁。 */
font-synthesis: none;
font-synthesis-weight: none;
font-synthesis-style: auto;
isolation: isolate; /* 让 z-index:-1 的画布层停在内容之下、html 之上 */
}
@@ -4699,7 +4703,9 @@ a.j13-mention-token:hover {
color: var(--ink-3);
}
.admin-brand-swatch img {
max-height: 3.5rem;
/* 按槽位高度铺满,宽度按比例自适应;超宽时由 max-width + contain 收边 */
height: 100%;
width: auto;
max-width: 100%;
object-fit: contain;
}
@@ -8271,6 +8277,248 @@ a.j13-mention-token:hover {
--entry-title-size: 1.4rem;
}
}
/* ----- 正文短代码:[details] 折叠 / [bilibili][youtube] 视频 / ==高亮== / [kbd] 键帽 ----- */
.prose-content .j13-md-details {
margin: 1rem 0;
border: 1px solid var(--line);
border-radius: var(--r-sm);
background: var(--panel);
overflow: hidden;
}
.prose-content .j13-md-details > summary {
display: flex;
align-items: center;
gap: 0.4rem;
padding: 0.55rem 0.9rem;
cursor: pointer;
user-select: none;
font-weight: 600;
font-size: 0.95em;
color: var(--ink);
list-style: none;
}
.prose-content .j13-md-details > summary::-webkit-details-marker {
display: none;
}
.prose-content .j13-md-details > summary:hover {
background: var(--tint);
}
.prose-content .j13-md-details[open] > summary {
border-bottom: 1px solid var(--line);
}
.prose-content .j13-md-details .j13-md-details-caret {
flex-shrink: 0;
color: var(--ink-3);
transition: transform 0.18s ease;
}
.prose-content .j13-md-details[open] .j13-md-details-caret {
transform: rotate(180deg);
}
.prose-content .j13-md-details-body {
padding: 0.35rem 0.9rem 0.6rem;
}
.prose-content .j13-md-details-body > :first-child {
margin-top: 0.35rem;
}
.prose-content .j13-md-details-body > :last-child {
margin-bottom: 0.35rem;
}
/* 视频嵌入:16:9 容器 + 懒加载 iframe 铺满 */
.j13-md-video {
position: relative;
aspect-ratio: 16 / 9;
margin: 1rem 0;
border-radius: var(--r-sm);
overflow: hidden;
background: var(--tint);
border: 1px solid var(--line);
}
.j13-md-video iframe {
position: absolute;
inset: 0;
width: 100%;
height: 100%;
border: 0;
}
/* ==高亮==:荧光笔。UA 默认黄底黑字在暗色下刺眼,显式覆盖 */
.prose-content mark {
background: color-mix(in srgb, #fde047 55%, transparent);
color: inherit;
padding: 0.05em 0.25em;
border-radius: 4px;
-webkit-box-decoration-break: clone;
box-decoration-break: clone;
}
.dark .prose-content mark {
background: color-mix(in srgb, #facc15 30%, transparent);
color: #fef9c3;
}
/* [kbd] 键帽:等宽 + 下边加厚模拟按键立体 */
.prose-content kbd {
display: inline-block;
padding: 0.1em 0.45em;
border: 1px solid var(--line-2);
border-bottom-width: 2px;
border-radius: 6px;
background: var(--panel);
color: var(--ink);
font-family: var(--font-mono);
font-size: 0.82em;
line-height: 1.45;
vertical-align: baseline;
}
/* 编辑器「文字颜色」弹窗:前景/背景两行,每行预设 + 色轮 + hex 输入 */
.j13-md-color-popover {
width: 288px;
}
.j13-md-color-row {
display: flex;
flex-direction: column;
gap: 5px;
margin-bottom: 10px;
}
.j13-md-color-row-label {
font-size: 12px;
color: var(--ink-3);
font-weight: 600;
}
.j13-md-color-row-items {
display: flex;
align-items: center;
flex-wrap: wrap;
gap: 5px;
}
.j13-md-color-none {
height: 26px;
padding: 0 9px;
border-radius: 8px;
border: 1px solid var(--line);
background: transparent;
color: var(--ink-3);
font-size: 12px;
cursor: pointer;
}
.j13-md-color-none.is-active {
border-color: var(--accent);
color: var(--accent);
font-weight: 600;
}
.j13-md-color-dot {
width: 26px;
height: 26px;
border-radius: 8px;
border: 1px solid var(--line-2);
cursor: pointer;
padding: 0;
}
.j13-md-color-dot.is-active {
outline: 2px solid var(--accent);
outline-offset: 1px;
}
/* 自定义取色器触发按钮:彩虹渐变底 + 吸管图标 */
.j13-md-color-wheel {
width: 26px;
height: 26px;
border-radius: 8px;
border: 1px solid var(--line-2);
padding: 0;
display: inline-flex;
align-items: center;
justify-content: center;
cursor: pointer;
flex-shrink: 0;
color: #fff;
background: conic-gradient(
from 210deg,
#f00, #ff0, #0f0, #0ff, #00f, #f0f, #f00
);
}
.j13-md-color-wheel svg {
filter: drop-shadow(0 1px 1.5px rgba(0, 0, 0, 0.65));
}
.j13-md-color-wheel:hover {
transform: scale(1.08);
}
.j13-md-color-wheel.is-active {
outline: 2px solid var(--accent);
outline-offset: 1px;
}
.j13-md-color-hex {
flex: 1 1 90px;
min-width: 90px;
font-family: var(--font-mono);
font-size: 12px;
}
/* 内联 HSV 取色器:在弹层文档流内展开,只撑开不浮层,不遮挡预览 */
.j13-md-hsv {
margin-top: 8px;
}
.j13-md-hsv-sv {
position: relative;
height: 110px;
border-radius: 8px;
overflow: hidden;
cursor: crosshair;
touch-action: none;
border: 1px solid var(--line);
}
.j13-md-hsv-sv-thumb {
position: absolute;
width: 12px;
height: 12px;
border-radius: 50%;
border: 2px solid #fff;
box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.45);
transform: translate(-50%, -50%);
pointer-events: none;
}
.j13-md-hsv-hue {
position: relative;
height: 12px;
border-radius: 6px;
margin-top: 8px;
cursor: pointer;
touch-action: none;
border: 1px solid var(--line);
background: linear-gradient(
to right,
#f00, #ff0, #0f0, #0ff, #00f, #f0f, #f00
);
}
.j13-md-hsv-hue-thumb {
position: absolute;
top: 50%;
width: 10px;
height: 18px;
border-radius: 4px;
background: #fff;
border: 1px solid rgba(0, 0, 0, 0.35);
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);
transform: translate(-50%, -50%);
pointer-events: none;
}
/* 实时预览置于弹层顶部:取色器在行内展开时始终可见,未选背景时透明棋盘格 */
.j13-md-color-preview {
display: flex;
justify-content: center;
padding: 7px 10px;
margin-bottom: 10px;
border: 1px dashed var(--line);
border-radius: 8px;
background:
repeating-conic-gradient(var(--tint) 0% 25%, transparent 0% 50%) 0 0 / 14px 14px;
}
.j13-md-color-preview span {
padding: 2px 10px;
border-radius: 6px;
font-size: 13px;
font-weight: 600;
}
.prose-content h1 { font-size: 1.75rem; font-weight: 800; margin: 1.6rem 0 0.8rem; }
.prose-content h2 {
font-size: 1.4rem;