feat: 站点访问统计与可配置侧边栏组件
- 新增访问统计:visitstats 服务与查询、visit_capture 中间件、爬虫/来源识别、管理端 analytics 页面 - 新增侧边栏:sidebar 服务与 handler、管理端 sidebar 配置页、前端侧边栏组件 - 新增 widget 嵌入代码生成(widgetCode)与 widgetApi - 遥测逻辑迁移至 handler 层,删除 service/telemetry - env 示例补充 Docker 部署可信代理 IP 说明
This commit is contained in:
54
frontend/components/sidebar/CustomWidgetBlock.tsx
Normal file
54
frontend/components/sidebar/CustomWidgetBlock.tsx
Normal file
@@ -0,0 +1,54 @@
|
||||
"use client";
|
||||
|
||||
import { useEffect, useRef } from "react";
|
||||
import type { SidebarWidgetPublic, User } from "@/lib/api";
|
||||
import { scopeWidgetCss } from "@/lib/widgetCode";
|
||||
import { ensureWidgetApi } from "@/lib/widgetApi";
|
||||
|
||||
// 站长自定义工具块:HTML/CSS 随 SSR 直出(dangerouslySetInnerHTML),
|
||||
// JS 在客户端挂载时注入执行、卸载时移除。站长可信内容,不做消毒/沙箱。
|
||||
// CSS 经 scopeWidgetCss 限定在 `.j13-widget-{id}` 容器内,不污染页面其他区域;
|
||||
// 工具内可直接用站点主题变量(var(--accent) 等)与 window.J13 接口。
|
||||
export default function CustomWidgetBlock({
|
||||
widget,
|
||||
viewer,
|
||||
}: {
|
||||
widget: SidebarWidgetPublic;
|
||||
viewer?: User | null;
|
||||
}) {
|
||||
const hostRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
// 先于站长 JS 建立站点接口(声明顺序保证本 effect 先执行)
|
||||
useEffect(() => {
|
||||
ensureWidgetApi(viewer);
|
||||
}, [viewer]);
|
||||
|
||||
useEffect(() => {
|
||||
const host = hostRef.current;
|
||||
if (!host || !widget.js) return;
|
||||
const script = document.createElement("script");
|
||||
script.dataset.widgetScript = String(widget.id);
|
||||
script.textContent = widget.js;
|
||||
host.appendChild(script);
|
||||
return () => {
|
||||
script.remove();
|
||||
};
|
||||
}, [widget.id, widget.js]);
|
||||
|
||||
return (
|
||||
<section
|
||||
className={`j13-widget-body j13-widget-${widget.id}`}
|
||||
data-widget-id={widget.id}
|
||||
data-widget-name={widget.name}
|
||||
>
|
||||
{widget.css ? (
|
||||
<style dangerouslySetInnerHTML={{ __html: scopeWidgetCss(widget.css, widget.id) }} />
|
||||
) : null}
|
||||
{widget.html ? (
|
||||
<div className="j13-widget-html" dangerouslySetInnerHTML={{ __html: widget.html }} />
|
||||
) : null}
|
||||
{/* 自定义 JS 的宿主节点:脚本由客户端创建后挂到此处执行 */}
|
||||
<div ref={hostRef} />
|
||||
</section>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user