原来的生成器只能配「背景 + 人物 + 道具」三件套,预览还是自己画的仿制页面 —— 跟真实页面不像,也没法给不同页面配不同内容。 机制层: - internal/context.pageScope() 按路径归类,输出 <html data-page-scope>: box / question / admin / profile / vote(首页与 /explore 不加载主题,不列) - /user/questions 单独归为 admin:题目列表信息密,和设置表单的装饰诉求不同 - base.css 装饰槽位 6 -> 10,背景 8 层 -> 12 层;主题按作用域覆盖时同样写满 10 个 - 新增 TestDecoSlotCount:逐文件逐声明检查 10 个值。少写一个不报错, 只会让图层与 size/position 错位(整页重复同一张图 / 人物跑到左上角),注释守不住 生成器: - 画板改成 iframe 加载 outputs/preview-*.html(真实模板渲染),配 serve.py 起本地服务 解决 file:// 下父页面读不到 iframe DOM 的问题 - 八个页面作用域(去掉不生效的首页/探索),每个可独立配背景与最多 10 层装饰 - 图层类型:图片 / 径向光斑 / 线性光;9 宫格锚点 + 像素偏移,可在画板上直接拖 - 位置统一写 calc(0%|50%|100% ± Npx):百分比是相对 (容器-图片), 不用 left/bottom 关键字混搭,避免三值语法非法导致整条声明作废 - 配色只填 6 个基础色,其余 4 个必需令牌按方向派生(surface-2 往 text 靠, 浅色变深、深色变亮,方向自动正确) 配套: - zz_preview_test.go 增加单题页 / 题目列表 / 投票页预览,作为生成器画板 - docs/theme-page-scope.md 记录作用域取值、选择器特异性与 10 槽位约束 - StaticVersion 20261020e(base.css 变了) 验证:生成器导出的 CSS 通过 TestThemeCSSComplete + TestDecoSlotCount; 真实箱主页计算样式为 12 层对齐;临时主题验证「question 覆盖为 none」生效、 未覆盖时回退全局。
154 lines
6.8 KiB
Go
154 lines
6.8 KiB
Go
// Copyright 2022 E99p1ant. All rights reserved.
|
||
// Use of this source code is governed by a MIT-style
|
||
// license that can be found in the LICENSE file.
|
||
|
||
package conf
|
||
|
||
// ⚠️ 仅应由 "-ldflags" 注入。
|
||
var (
|
||
BuildTime string
|
||
BuildCommit = "dev"
|
||
|
||
// StaticVersion 静态资源缓存版本号:base.css 与主题 css 共用,改样式只改这一处。
|
||
StaticVersion = "20261020e"
|
||
)
|
||
|
||
// 文本审核通道取值([security] text_censor_source)。定义在 conf 侧,
|
||
// 让配置校验(conf.Init)与通道装配(internal/security/censor)共用同一份字面量。
|
||
const (
|
||
CensorSourceAuto = "auto" // 七牛优先、阿里云兜底(历史行为,留空同义)
|
||
CensorSourceQiniu = "qiniu"
|
||
CensorSourceAliyun = "aliyun"
|
||
)
|
||
|
||
var (
|
||
App struct {
|
||
Production bool `ini:"production"`
|
||
ExternalURL string `ini:"external_url"`
|
||
ICP string `ini:"icp"`
|
||
DefaultLang string `ini:"default_lang"` // 站点默认语言(zh-CN/zh-TW/en/ja),留空回退简体中文
|
||
UptraceDSN string `ini:"uptrace_dsn"`
|
||
QiniuAccessKey string `ini:"qiniu_access_key"`
|
||
QiniuAccessSecret string `ini:"qiniu_access_secret"`
|
||
AliyunAccessKey string `ini:"aliyun_access_key"`
|
||
AliyunAccessKeySecret string `ini:"aliyun_access_key_secret"`
|
||
SentryDSN string `ini:"sentry_dsn"`
|
||
MaintenanceMode bool `ini:"maintenance_mode"`
|
||
ShareBackground string `ini:"share_background"`
|
||
FontPath string `ini:"font_path"`
|
||
}
|
||
|
||
// Theme 主题系统([theme] 段)。
|
||
// default :站点默认主题 slug,留空/非法回退内置 default(= 现在的外观)。
|
||
// available :启用哪些主题(逗号分隔),同时是箱主设置页的白名单;
|
||
// 列了但缺少 css 文件的会被忽略并告警(见 internal/theme)。
|
||
Theme struct {
|
||
Default string `ini:"default"`
|
||
Available string `ini:"available"`
|
||
}
|
||
|
||
Security struct {
|
||
EnableTextCensor bool `ini:"enable_text_censor"`
|
||
IPBlacklist string `ini:"ip_blacklist"`
|
||
IPBlacklistRedirectURL string `ini:"ip_blacklist_redirect_url"`
|
||
// TrustProxy 为 true 时信任 CDN 权威客户端头 CF-Connecting-IP / EO-Client-IP
|
||
// (以及受信代理设置的 X-Real-IP / X-Forwarded-For);否则一律用 RemoteAddr,
|
||
// 防止伪造 header 绕过速率限制与 IP 黑名单。
|
||
TrustProxy bool `ini:"trust_proxy"`
|
||
// TrustedProxies 逗号分隔的 IP / CIDR,仅限自己的反向代理 / LB。仅当 TCP 对端
|
||
// 落在该清单内才解析 X-Forwarded-For / X-Real-IP;留空则这两个头永不被信任
|
||
// (CDN 权威头仍会采用,前提是源站已由 Cloudflare Tunnel / 回源网段锁定,
|
||
// 从而免于维护上游 CDN 的庞大 CIDR 清单)。
|
||
TrustedProxies string `ini:"trusted_proxies"`
|
||
EnableAutoBan bool `ini:"enable_auto_ban"` // fail2ban 风格:检测到扫描特征后临时封禁来源 IP
|
||
// BanTrackNotFound 是否把未注册路径的 404 计入封禁统计。默认 false:仅命中后台
|
||
// 扫描特征路径(KindSensitive)才统计,避免共享出口(CDN 边缘 / CGNAT)下
|
||
// 正常用户被 404 探测流量连坐误伤。
|
||
BanTrackNotFound bool `ini:"ban_track_notfound"`
|
||
BanThresholdSensitive int `ini:"ban_threshold_sensitive"` // 窗口内敏感路径命中次数
|
||
BanThreshold404 int `ini:"ban_threshold_404"` // 窗口内 404 次数
|
||
BanWindowSeconds int `ini:"ban_window_seconds"` // 统计窗口(秒)
|
||
BanDurationMinutes int `ini:"ban_duration_minutes"` // 封禁时长(分钟)
|
||
// DefaultModerationStrictness 站点默认审核严格度(lax / standard / strict),
|
||
// 仅对未单独设置档位的账号生效(见 moderation.StrictnessFor)。留空或非法值回退
|
||
// strict(最严档),保证升级不会放宽拦截;默认拦截面可能较升级前略有扩大,
|
||
// 希望更少误伤则显式写 standard。
|
||
DefaultModerationStrictness string `ini:"default_moderation_strictness"`
|
||
// TextCensorSource 文本审核通道:qiniu / aliyun(内容安全 2.0 TextModeration,
|
||
// 个人实名账号即可开通)/ auto(默认,留空同义:七牛优先、阿里云复核)。
|
||
// 仅显式选定的通道会被调用,缺凭据时启动即报错(见 conf.Init)——
|
||
// 审核失败是 fail-closed(拒绝提交),会让发布与私信整站不可用且现象隐蔽。
|
||
TextCensorSource string `ini:"text_censor_source"`
|
||
SecurityAlertEmail string `ini:"security_alert_email"` // 触发封禁时告警收件人(留空不发送)
|
||
}
|
||
|
||
Server struct {
|
||
Port int `ini:"port"`
|
||
Listen string `ini:"listen"` // 绑定监听地址(含端口)。留空则默认 ":port"(监听所有网卡)。
|
||
Salt string `ini:"salt"`
|
||
XSRFKey string `ini:"xsrf_key"`
|
||
}
|
||
|
||
Database struct {
|
||
DSN string
|
||
|
||
Type string `ini:"type"`
|
||
User string `ini:"user"`
|
||
Password string `ini:"password"`
|
||
Host string `ini:"host"`
|
||
Port uint `ini:"port"`
|
||
Name string `ini:"name"`
|
||
Schema string `ini:"schema"`
|
||
DedupeUniqueFields bool `ini:"dedupe_unique_fields"`
|
||
}
|
||
|
||
Redis struct {
|
||
Addr string `ini:"addr"`
|
||
Password string `ini:"password"`
|
||
}
|
||
|
||
Recaptcha struct {
|
||
CaptchaType string `ini:"captcha_type"`
|
||
Domain string `ini:"domain"`
|
||
SiteKey string `ini:"site_key"`
|
||
ServerKey string `ini:"server_key"`
|
||
TurnstileStyle bool `ini:"turnstile_style"`
|
||
}
|
||
|
||
Pixel struct {
|
||
Host string `ini:"host"`
|
||
}
|
||
|
||
Upload struct {
|
||
DefaultAvatarURL string `ini:"default_avatar"`
|
||
DefaultBackground string `ini:"default_background"`
|
||
DefaultBackgroundImageURL string `ini:"default_qrbackgroundimage"`
|
||
AliyunEndpoint string `ini:"aliyun_endpoint"`
|
||
AliyunAccessID string `ini:"aliyun_access_id"`
|
||
AliyunAccessSecret string `ini:"aliyun_access_secret"`
|
||
AliyunBucket string `ini:"aliyun_bucket"`
|
||
AliyunBucketCDNHost string `ini:"aliyun_bucket_cdn_host"`
|
||
ImageEndpoint string `ini:"image_endpoint"`
|
||
ImageAccessID string `ini:"image_access_id"`
|
||
ImageAccessSecret string `ini:"image_access_secret"`
|
||
ImageBucket string `ini:"image_bucket"`
|
||
ImageBucketCDNHost string `ini:"image_bucket_cdn_host"`
|
||
}
|
||
|
||
Mail struct {
|
||
Account string `ini:"account"`
|
||
Password string `ini:"password"`
|
||
Port int `ini:"port"`
|
||
SMTP string `ini:"smtp"`
|
||
SkipTLSVerify bool `ini:"skip_tls_verify"` // 仅自签名 / 内网 SMTP 需要
|
||
}
|
||
|
||
Service struct {
|
||
Backends []struct {
|
||
Prefix string `ini:"prefix"`
|
||
ForwardURL string `ini:"forward_url"`
|
||
}
|
||
TLSInsecureSkipVerify bool `ini:"tls_insecure_skip_verify"` // 仅内网自签名后端需要
|
||
}
|
||
)
|