feat(品牌): 支持 _local 外部优先 Logo 与图标覆盖

新增 /admin/brand-assets 静态挂载,并在前端与桌面端统一采用外部优先、内置兜底的品牌资源解析;同时补充 BRANDING 文档与 README 入口说明。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
oliver 2026-05-07 10:12:16 +08:00
parent b15ff4c31c
commit acf1266e90
7 changed files with 106 additions and 13 deletions

View file

@ -1934,7 +1934,8 @@ function prependMessageTime(node, tsIso) {
node.insertBefore(el("div", { class: "chat-msg__time", text: txt }), node.firstChild);
}
const CHAT_BOT_LOGO_SRC = "/admin/assets/oliver.svg";
const CHAT_BOT_LOGO_SRC = "/admin/brand-assets/logo.svg";
const CHAT_BOT_LOGO_FALLBACK_SRC = "/admin/assets/oliver.svg";
/** 内置默认用户头像(与助手头像同尺寸与底栏样式,SVG) */
const DEFAULT_USER_AVATAR_SRC = "/admin/assets/default-user-avatar.svg";
@ -1950,12 +1951,22 @@ async function loadMeProfile() {
}
function buildBotAvatarImg() {
return el("img", {
const img = el("img", {
class: "chat-avatar chat-avatar--bot",
src: CHAT_BOT_LOGO_SRC,
alt: "",
loading: "lazy",
});
img.addEventListener(
"error",
() => {
if (img.dataset.logoFallbackApplied === "1") return;
img.dataset.logoFallbackApplied = "1";
img.src = CHAT_BOT_LOGO_FALLBACK_SRC;
},
{ once: true },
);
return img;
}
function buildUserAvatarSlot() {
@ -2331,13 +2342,21 @@ function mount(node) {
}
function buildChatBrandLogoNode() {
return el("div", { class: "chat-nav__brandWrap" }, [
el("img", {
class: "chat-nav__brandLogo",
src: "/admin/assets/oliver.svg",
alt: "oliver logo",
}),
]);
const img = el("img", {
class: "chat-nav__brandLogo",
src: CHAT_BOT_LOGO_SRC,
alt: "site logo",
});
img.addEventListener(
"error",
() => {
if (img.dataset.logoFallbackApplied === "1") return;
img.dataset.logoFallbackApplied = "1";
img.src = CHAT_BOT_LOGO_FALLBACK_SRC;
},
{ once: true },
);
return el("div", { class: "chat-nav__brandWrap" }, [img]);
}
function resolveAdminHashUrl(hashPath, sessionId) {