theme v1
@@ -298,3 +298,90 @@ home-light / home-dark / explore-light 三页差异均 **0.024%**,bbox 只有
|
|||||||
|
|
||||||
**教训(重要)**:像素测量脚本的扫描范围必须覆盖整幅图,循环上界不能与被测对象边界重合,
|
**教训(重要)**:像素测量脚本的扫描范围必须覆盖整幅图,循环上界不能与被测对象边界重合,
|
||||||
否则会把"边界截断"读成"图形特征"。之前 3.77→6.89 那组对比不知是否也受此影响,需复查时再确认。
|
否则会把"边界截断"读成"图形特征"。之前 3.77→6.89 那组对比不知是否也受此影响,需复查时再确认。
|
||||||
|
|
||||||
|
## P2 补漏部署后复测(12:48)
|
||||||
|
|
||||||
|
- `base.css?v=20261019d` 上线,24023 字节与本地逐字节一致。
|
||||||
|
- 删掉 `fieldTypeLabelClass` 后**无运行期报错**:公开投票页 3 个(200,tb-chip 8/16/4,uk-label 各 1 = 状态)、
|
||||||
|
结果页 4 个(200,tb-chip 8/2/0/16,彩色 label 全 0,progress 7/0/10/19)、
|
||||||
|
草稿预览页 2 个(200,tb-chip 2/6)。
|
||||||
|
- 巡检 `/ /explore /rules /user/questions /user/profile?tab=security /_/admin6 /_/admin3` 全 200 无模板错误。
|
||||||
|
- `/user/votes/{id}/preview` 对**已发布**投票 302 到 `/vote/{token}` 是设计如此(vote.go:1093),不是回归。
|
||||||
|
- 截图核对:结果页「1 単選 / 2 多選」已为浅色胶囊,进度条 10px 圆角 6px;参与页字段头同样统一。
|
||||||
|
|
||||||
|
## "移动端语言/主题按钮不见了"排查(结论:非缺陷)
|
||||||
|
|
||||||
|
实测(线上测试环境,`--force-device-scale-factor=1`):
|
||||||
|
- 宽 360/390/414/640 → 顶栏 `.tb-nav-utils` = `display:none`,底栏 `#tb-mobile-utils` = `flex`,
|
||||||
|
rect `0,639,W,46`,语言 `block`、主题按钮 `block`(48×30,SVG 16×16),命中测试落在 `mobile-lang-select`。
|
||||||
|
- 宽 700/768/980 → 底栏 `none`,顶栏 `flex`,右上角地球 + 月亮都可见(截图 `outputs/t-nav-right.png`)。
|
||||||
|
- 页面级差异:`/_/admin6` 底栏**只有月亮没有语言下拉** —— `IsUserPage=true` 让语言块整体不渲染(桌面同样没有)。
|
||||||
|
- 生产 `box.shiroko.one` 仍是旧构建(页面无 `base.css` 引用,底栏是 emoji 月亮),移动端同样正常。
|
||||||
|
|
||||||
|
用户确认是忘了「移动端移到固定底栏」这个设计,不是 bug。
|
||||||
|
留下的真实缺口:**箱主页(最常见的外部入口)完全没有语言切换**,见 MEMORY.md 前端样式条目。
|
||||||
|
|
||||||
|
## 修正:箱主页无语言切换是设计,不是缺口
|
||||||
|
|
||||||
|
上一节把它记成"真实缺口"是错的。用户明确:**箱主页属箱主个性化,以箱主配置为主**,
|
||||||
|
语言入口不出现是有意为之(`IsUserPage` 门控)。
|
||||||
|
MEMORY.md 对应条目已改为"有意设计、别当 bug 修、要动先问"。
|
||||||
|
|
||||||
|
## 备份(用户要求)
|
||||||
|
|
||||||
|
`../TamaBox-v4-mainline-20261019-1445.tar.gz`(940K,302 条目,排除 .git/.workbuddy/outputs)。
|
||||||
|
P1 剩余两项(首屏跟随系统深色、首页 Waline 懒加载)用户明确**先不做**。
|
||||||
|
|
||||||
|
## 主题系统方案(只出设计,未实现)
|
||||||
|
|
||||||
|
用户诉求:箱主在后台选主题、仅对箱主相关页面生效;站点级默认主题在配置里;要一份可复用的主题底稿。
|
||||||
|
|
||||||
|
已确认的现状事实(设计依据):
|
||||||
|
- 设计令牌只有 16 个,集中在 `static/css/base.css` 的 `:root`(亮) + `html[data-theme="dark"]`(暗)。
|
||||||
|
- `<html lang>` 在 `templates/base/header.html:2`,服务端渲染;主题属性可放在这里(无 FOUC)。
|
||||||
|
- `question.Pager`(`route/question/page.go:45`)是 `/_/{domain}` 与 `/_/{domain}/{id}` 的共同中间件
|
||||||
|
→ 打主题标记的唯一合适位置。
|
||||||
|
- `/user/*` 与 `/_/*` 共用 `IsUserPage`(context.go:241 按 URL 前缀判定),所以「箱主相关页面」
|
||||||
|
≠ IsUserPage,必须单独区分,否则设置页会被主题化。
|
||||||
|
- `static/fs.go` 与 `templates/embed.go` 都是显式 embed 清单(新增主题 css 必须手加)。
|
||||||
|
- 用户模型已有大量个性化字段(usernamecolor/introcolor/background…),主题作为 `users.theme` 同族最自然。
|
||||||
|
- 分享卡是服务端绘制图片(`route/question/share.go`),不经过 CSS → 主题不覆盖它。
|
||||||
|
|
||||||
|
关键结论(写进方案的核心):令牌覆盖必须用
|
||||||
|
`html[data-theme-style="x"]`(0,1,1,压过 `:root` 的 0,1,0)+
|
||||||
|
`html[data-theme="dark"][data-theme-style="x"]`(0,2,1,压过 base 的 dark)。
|
||||||
|
只写浅色块会让深色模式被浅色令牌污染(同特异性 + 主题文件后加载)。
|
||||||
|
|
||||||
|
## 主题系统初版(已实现,未部署)
|
||||||
|
|
||||||
|
用户拍板:①作用范围跟随箱主配置(即 /_/ 箱主相关页面)②主题只做配色/图案/整页背景,**不涉及布局**
|
||||||
|
③主题名可本地化 ④分享卡不参与。
|
||||||
|
|
||||||
|
实现:
|
||||||
|
- `internal/theme`:注册表 + 三级回退。`[theme] default/available` → 白名单(slug 正则 + css 是否存在),
|
||||||
|
`Resolve(用户值)`:`default`→空串(不加载)/命中→该 slug/其余→站点默认。"" 与 "default" 语义不同:
|
||||||
|
""=跟随站点默认,"default"=箱主明确选基础外观。
|
||||||
|
设置页色块从主题 css 浅色块里抓 `--tb-bg`/`--tb-primary` 拼渐变(值必须过色值正则,防注入)。
|
||||||
|
- `users.theme varchar(32) default ''`(AutoMigrate 加列)+ `UpdateTheme` 单列更新。
|
||||||
|
- `question.Pager` 注入 `Data["ThemeSlug"]`(`/_/{domain}`、单题、密码页、分享卡路由共用这一个中间件);
|
||||||
|
header.html 在 `<html>` 输出 `data-theme-style` 并条件加载 `themes/<slug>.css`。
|
||||||
|
- 设置页账号面板末尾新增「主题外观」卡片(独立表单 `POST /user/profile/theme`,不塞进 UpdateProfile,
|
||||||
|
避免与该面板其它字段互相覆盖);`{{ if .Themes }}` 包裹,未配置主题时不显示。
|
||||||
|
- 静态版本号统一 `conf.StaticVersion = "20261019e"`(base.css 与主题 css 共用,改样式只改一处)。
|
||||||
|
- `static/fs.go` 改嵌目录 `css/themes`(以后加主题文件不用再改 embed 清单)。
|
||||||
|
- 主题文件:`_scaffold.css`(底稿,含 19 令牌说明 + 素材规格 + 特异性规范)、`default.css`(恒等,仅色块预览)、
|
||||||
|
`sakura.css`(示例,纯 CSS 网点图案 + 粉调)。
|
||||||
|
- base.css:body 接 `--tb-page-image` / `--tb-page-pattern` / `--tb-page-pattern-size` 两层背景;
|
||||||
|
**UIkit 主色是编译期常量 #1e87f0**,新增映射块把 a/uk-link、uk-button-primary、checkbox/radio、input:focus、
|
||||||
|
uk-tab active 接到 `--tb-primary`(基础主题值相同,默认外观零变化)。
|
||||||
|
|
||||||
|
实测(无头 Chrome,box 页 data-theme-style=sakura):
|
||||||
|
- 浅色 primary `#e5678f`/bg `#fff6f8`/pattern 16px 网点命中;深色 `#ff8ab0`/`#241a1f`,卡片表面各自跟随。
|
||||||
|
- 未选主题的 box 页:无 data 属性、无 themes link、主按钮仍 `rgb(30,135,240)` → 零回归。
|
||||||
|
|
||||||
|
踩坑:
|
||||||
|
1. 第一版 sakura 页「发送提问」还是蓝色 —— UIkit 组件色写死,令牌覆盖不到,必须按组件映射。
|
||||||
|
2. 预览里 `{{ .StaticVersion }}` 为空(预览夹具没这个键),导致按固定串替换主题 css 失败;改用正则。
|
||||||
|
3. `writePreview` 用全文搜 `data-theme="dark"` 判断是否已加属性 → 命中内联主题 css 里的选择器,深色预览没生效;
|
||||||
|
改为只看 `<html ...>` 开标签。
|
||||||
|
4. 脚本改 form/user.go 时把插入块写在结构体中间,拼出 `} Language ...`;靠 Read 复查发现并重写。
|
||||||
|
|||||||
@@ -88,6 +88,13 @@
|
|||||||
- 静态文件是**显式 embed 清单**(`static/fs.go`),新增 css/js 必须手动加进 `//go:embed` 那行,否则运行期 404。
|
- 静态文件是**显式 embed 清单**(`static/fs.go`),新增 css/js 必须手动加进 `//go:embed` 那行,否则运行期 404。
|
||||||
- 主题属性在 head 内联脚本里打(cookie `theme`),**不能挪回 body**,否则深色用户白闪。
|
- 主题属性在 head 内联脚本里打(cookie `theme`),**不能挪回 body**,否则深色用户白闪。
|
||||||
- 页面级样式尽量用类,不用 `style=`(深色下内联写死色值会露白,`.tb-img-uploader` 踩过)。
|
- 页面级样式尽量用类,不用 `style=`(深色下内联写死色值会露白,`.tb-img-uploader` 踩过)。
|
||||||
|
- **移动端(≤640px)语言切换与主题按钮不在顶栏**:顶栏 `.tb-nav-utils` 被 `display:none !important` 隐藏,
|
||||||
|
改由 `#tb-mobile-utils` 固定底栏承载(`position:fixed;bottom:0;z-index:1000`,body 预留 `padding-bottom:56px`)。
|
||||||
|
顶栏图标只在 >640px 出现。用户曾误以为"按钮不见了",先解释位置再排查。
|
||||||
|
⚠️ `/_/{domain}` 箱主页把 `IsUserPage` 设为 true(`route/question/page.go:133`),语言切换整块包在
|
||||||
|
`{{ if not .IsUserPage }}` 里(header.html:272 桌面 / :314 移动),所以**箱主页没有语言切换入口**——
|
||||||
|
**这是有意设计,不是缺陷**(用户 2026-10-19 明确:箱主页属箱主个性化,以箱主配置为准)。
|
||||||
|
别把它当 bug 去"修",要动先问。
|
||||||
- ⚠️ **UIkit 3.3.3 有 `.uk-flex::before/::after{display:none}`**:给带 `uk-flex` 的元素加伪元素遮罩必须写
|
- ⚠️ **UIkit 3.3.3 有 `.uk-flex::before/::after{display:none}`**:给带 `uk-flex` 的元素加伪元素遮罩必须写
|
||||||
`.tb-cover.uk-flex::after` 这类复合选择器,否则静默失效(不报错)。
|
`.tb-cover.uk-flex::after` 这类复合选择器,否则静默失效(不报错)。
|
||||||
- 视觉自检:`TEST_PREVIEW=1 go test ./templates -run TestGenPreview` → `outputs/preview-*.html`;
|
- 视觉自检:`TEST_PREVIEW=1 go test ./templates -run TestGenPreview` → `outputs/preview-*.html`;
|
||||||
@@ -99,6 +106,21 @@
|
|||||||
(置顶/私密/被举报/已读、投票未开始/进行中/已结束/已参与)。题型配色曾由 Go 的
|
(置顶/私密/被举报/已读、投票未开始/进行中/已结束/已参与)。题型配色曾由 Go 的
|
||||||
`fieldTypeLabelClass` 生成(已删),故 grep `uk-label` 搜不到,改前先搜模板函数名。
|
`fieldTypeLabelClass` 生成(已删),故 grep `uk-label` 搜不到,改前先搜模板函数名。
|
||||||
|
|
||||||
|
## 主题系统
|
||||||
|
|
||||||
|
- 一套主题 = `static/css/themes/<slug>.css` 一个文件,**只覆盖令牌**(配色/图案/整页背景),不碰布局。
|
||||||
|
新增主题:复制 `_scaffold.css` → 改名 → 登记到 `[theme] available`;`static/fs.go` 已嵌整个目录,无需改清单。
|
||||||
|
- 作用域:仅 `/_/*` 箱主相关页面(`question.Pager` 注入 `ThemeSlug`);`/user` 后台与全站其它页面不主题化。
|
||||||
|
优先级 `users.theme > [theme] default > 基础外观`;`""`=跟随站点默认,`"default"`=箱主明确选基础外观(不加载 css)。
|
||||||
|
- ⚠️ 主题 css **必须成对写**:`html[data-theme-style="x"]`(0,1,1,压过 `:root` 的 0,1,0)+
|
||||||
|
`html[data-theme="dark"][data-theme-style="x"]`(0,2,1,压过 base 的 dark)。只写浅色块会让深色模式被浅色令牌污染。
|
||||||
|
兜底测试 `TestThemeCSSComplete`(检查两个选择器 + 10 个颜色令牌齐全)。
|
||||||
|
- ⚠️ **UIkit 3.3.3 的主题色是编译期常量 `#1e87f0`**,令牌注入不进去。base.css 里有一段「UIkit 组件跟随主题色」
|
||||||
|
按组件映射(a/uk-link、uk-button-primary、checkbox/radio、input:focus、uk-tab active)。新增会显示主色的组件时,
|
||||||
|
先确认它是否已映射,否则换主题后会出现「页面变粉、按钮还蓝」。
|
||||||
|
- 静态资源版本号统一 `conf.StaticVersion`(base.css 与主题 css 共用),改样式只改这一处;页面通过 `.StaticVersion` 取。
|
||||||
|
- 整页背景用 `--tb-page-image`(cover)与 `--tb-page-pattern`(平铺,`--tb-page-pattern-size` 控尺寸),图案叠在图片之上。
|
||||||
|
|
||||||
## 其它约定
|
## 其它约定
|
||||||
|
|
||||||
- 校验靠 `valid:"required;maxlen:N"` 标签(`internal/form/*.go`),别在 handler 手写。
|
- 校验靠 `valid:"required;maxlen:N"` 标签(`internal/form/*.go`),别在 handler 手写。
|
||||||
|
|||||||
@@ -181,3 +181,13 @@ chat_message_len = 2000
|
|||||||
chat_max_messages = 200
|
chat_max_messages = 200
|
||||||
; 单用户每日私信条数上限(用户可设范围 0..该值;0 表示不限制每日条数)
|
; 单用户每日私信条数上限(用户可设范围 0..该值;0 表示不限制每日条数)
|
||||||
daily_message_limit_max = 999
|
daily_message_limit_max = 999
|
||||||
|
|
||||||
|
[theme]
|
||||||
|
; 主题系统:只改配色 / 图案 / 整页背景,不涉及布局;仅提问箱相关页面生效。
|
||||||
|
; default :站点默认主题(箱主未选择时使用)。填 default 或留空 = 现有外观。
|
||||||
|
; available :启用哪些主题,逗号分隔,同时是箱主设置页的白名单;
|
||||||
|
; 列了但 static/css/themes/<slug>.css 不存在的会被忽略并告警。
|
||||||
|
; 新增主题:把 static/css/themes/_scaffold.css 复制成 <slug>.css,
|
||||||
|
; 改选择器与令牌值,再把 <slug> 加进 available —— 不需要改模板。
|
||||||
|
default = default
|
||||||
|
available = default,sakura
|
||||||
|
|||||||
@@ -89,6 +89,12 @@ func Init() error {
|
|||||||
// ini 键留空会被 int 解析为 0;<1 的值一律回退内置默认,防止上限被静默置零。
|
// ini 键留空会被 int 解析为 0;<1 的值一律回退内置默认,防止上限被静默置零。
|
||||||
sanitizeLimits(&Limits)
|
sanitizeLimits(&Limits)
|
||||||
|
|
||||||
|
// 主题:默认 slug 与启用清单。段缺失时 MapTo 得到空值,运行期回退内置 default,
|
||||||
|
// 因此老配置文件不写 [theme] 也能正常启动。
|
||||||
|
if err := File.Section("theme").MapTo(&Theme); err != nil {
|
||||||
|
return errors.Wrap(err, "map 'theme'")
|
||||||
|
}
|
||||||
|
|
||||||
if err := File.Section("mail").MapTo(&Mail); err != nil {
|
if err := File.Section("mail").MapTo(&Mail); err != nil {
|
||||||
return errors.Wrap(err, "map 'mail'")
|
return errors.Wrap(err, "map 'mail'")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,9 @@ package conf
|
|||||||
var (
|
var (
|
||||||
BuildTime string
|
BuildTime string
|
||||||
BuildCommit = "dev"
|
BuildCommit = "dev"
|
||||||
|
|
||||||
|
// StaticVersion 静态资源缓存版本号:base.css 与主题 css 共用,改样式只改这一处。
|
||||||
|
StaticVersion = "20261019e"
|
||||||
)
|
)
|
||||||
|
|
||||||
// 文本审核通道取值([security] text_censor_source)。定义在 conf 侧,
|
// 文本审核通道取值([security] text_censor_source)。定义在 conf 侧,
|
||||||
@@ -35,6 +38,15 @@ var (
|
|||||||
FontPath string `ini:"font_path"`
|
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 {
|
Security struct {
|
||||||
EnableTextCensor bool `ini:"enable_text_censor"`
|
EnableTextCensor bool `ini:"enable_text_censor"`
|
||||||
IPBlacklist string `ini:"ip_blacklist"`
|
IPBlacklist string `ini:"ip_blacklist"`
|
||||||
|
|||||||
@@ -284,6 +284,8 @@ func Contexter() flamego.Handler {
|
|||||||
|
|
||||||
c.Data["CurrentURI"] = ctx.Request().Request.RequestURI
|
c.Data["CurrentURI"] = ctx.Request().Request.RequestURI
|
||||||
c.Data["ExternalURL"] = conf.App.ExternalURL
|
c.Data["ExternalURL"] = conf.App.ExternalURL
|
||||||
|
// 静态资源版本号:base.css 与主题 css 共用同一个值,改样式只需改 conf.StaticVersion。
|
||||||
|
c.Data["StaticVersion"] = conf.StaticVersion
|
||||||
|
|
||||||
// 默认头像/背景图兜底:未设置自定义头像的箱主,其二维码 logo 应与页面头像一致回退到 default_avatar。
|
// 默认头像/背景图兜底:未设置自定义头像的箱主,其二维码 logo 应与页面头像一致回退到 default_avatar。
|
||||||
// 模板按原始 URL 直连(easy.qrcode 以 crossOrigin:'anonymous' 加载,配合对象存储桶 CORS
|
// 模板按原始 URL 直连(easy.qrcode 以 crossOrigin:'anonymous' 加载,配合对象存储桶 CORS
|
||||||
|
|||||||
@@ -40,6 +40,7 @@ type UsersStore interface {
|
|||||||
// UpdateModerationStrictness 更新内容审核严格度(lax / standard / strict,空值表示跟随站点默认)。
|
// UpdateModerationStrictness 更新内容审核严格度(lax / standard / strict,空值表示跟随站点默认)。
|
||||||
// 只写 moderation_strictness 列,不影响防骚扰与屏蔽词。
|
// 只写 moderation_strictness 列,不影响防骚扰与屏蔽词。
|
||||||
UpdateModerationStrictness(ctx context.Context, id uint, strictness string) error
|
UpdateModerationStrictness(ctx context.Context, id uint, strictness string) error
|
||||||
|
UpdateTheme(ctx context.Context, id uint, theme string) error
|
||||||
Authenticate(ctx context.Context, email, password string) (*User, error)
|
Authenticate(ctx context.Context, email, password string) (*User, error)
|
||||||
ChangePassword(ctx context.Context, id uint, oldPassword, newPassword string) error
|
ChangePassword(ctx context.Context, id uint, oldPassword, newPassword string) error
|
||||||
UpdatePassword(ctx context.Context, id uint, newPassword string) error
|
UpdatePassword(ctx context.Context, id uint, newPassword string) error
|
||||||
@@ -106,6 +107,9 @@ type User struct {
|
|||||||
Xiaohongshulink string `json:"xiaohongshulink"`
|
Xiaohongshulink string `json:"xiaohongshulink"`
|
||||||
Qrcodepdpcolor string `json:"qrcodepdpcolor"`
|
Qrcodepdpcolor string `json:"qrcodepdpcolor"`
|
||||||
Backgroundimagealpha string `json:"Backgroundimagealpha"`
|
Backgroundimagealpha string `json:"Backgroundimagealpha"`
|
||||||
|
// Theme 箱主选择的主题 slug(空串=跟随站点默认,default=基础外观)。
|
||||||
|
// 取值合法性由 route/user 在写入前校验,读取侧由 internal/theme 回退。
|
||||||
|
Theme string `json:"theme" gorm:"column:theme;type:varchar(32);default:''"`
|
||||||
Notify NotifyType `json:"notify"`
|
Notify NotifyType `json:"notify"`
|
||||||
HarassmentSetting HarassmentSettingType `json:"harassment_setting" gorm:"default:'none'"`
|
HarassmentSetting HarassmentSettingType `json:"harassment_setting" gorm:"default:'none'"`
|
||||||
BlockWords string `json:"-"`
|
BlockWords string `json:"-"`
|
||||||
@@ -445,6 +449,16 @@ func (db *users) UpdateModerationStrictness(ctx context.Context, id uint, strict
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// UpdateTheme 仅更新主题 slug,不动其它个性化字段(背景/颜色各自独立保存)。
|
||||||
|
func (db *users) UpdateTheme(ctx context.Context, id uint, theme string) error {
|
||||||
|
if err := db.WithContext(ctx).Model(&User{}).Where("id = ?", id).Updates(map[string]interface{}{
|
||||||
|
"Theme": theme,
|
||||||
|
}).Error; err != nil {
|
||||||
|
return errors.Wrap(err, "update user")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (db *users) Authenticate(ctx context.Context, email, password string) (*User, error) {
|
func (db *users) Authenticate(ctx context.Context, email, password string) (*User, error) {
|
||||||
u, err := db.GetByEmail(ctx, email)
|
u, err := db.GetByEmail(ctx, email)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -26,6 +26,13 @@ type UpdateProfile struct {
|
|||||||
Language string `form:"language"`
|
Language string `form:"language"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// UpdateProfileTheme 主题外观。空串表示跟随站点默认主题;
|
||||||
|
// 取值在白名单之外时保存被拒绝(见 route/user.UpdateTheme),
|
||||||
|
// 这样箱主不会「选了个不存在的主题,然后看起来什么都没变」。
|
||||||
|
type UpdateProfileTheme struct {
|
||||||
|
Theme string `valid:"maxlen:32" label:"主题" msg:"profile.theme.invalid"`
|
||||||
|
}
|
||||||
|
|
||||||
// UpdateHarassment 仅「允许注册用户向我提问」开关(防骚扰类型)。
|
// UpdateHarassment 仅「允许注册用户向我提问」开关(防骚扰类型)。
|
||||||
// 全局屏蔽词为独立入口 UpdateBlockWords:二者分处不同设置面板保存,
|
// 全局屏蔽词为独立入口 UpdateBlockWords:二者分处不同设置面板保存,
|
||||||
// 若仍共用一个结构体会互相覆盖对方字段(见 route/user/harassment.go 注释)。
|
// 若仍共用一个结构体会互相覆盖对方字段(见 route/user/harassment.go 注释)。
|
||||||
|
|||||||
@@ -930,4 +930,14 @@ var enDict = map[string]string{
|
|||||||
"form.register.recaptcha": "Unable to load the CAPTCHA. Please refresh the page or switch your network and try again",
|
"form.register.recaptcha": "Unable to load the CAPTCHA. Please refresh the page or switch your network and try again",
|
||||||
"form.register.agreeRules": "Please read and accept the community rules first",
|
"form.register.agreeRules": "Please read and accept the community rules first",
|
||||||
"form.register.repeatPassword": "The two passwords do not match",
|
"form.register.repeatPassword": "The two passwords do not match",
|
||||||
|
|
||||||
|
// 主题:设置页选择器与主题显示名(theme.name.<slug> 由 internal/theme 约定)
|
||||||
|
"profile.theme.title": "Theme",
|
||||||
|
"profile.theme.hint": "Applies to your question box pages only; the rest of the site keeps the default look.",
|
||||||
|
"profile.theme.followDefault": "Follow site default",
|
||||||
|
"profile.theme.save": "Save theme",
|
||||||
|
"profile.theme.saved": "Theme saved",
|
||||||
|
"profile.theme.invalid": "That theme is unavailable — pick one from the list",
|
||||||
|
"theme.name.default": "Default look",
|
||||||
|
"theme.name.sakura": "Sakura",
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -930,4 +930,14 @@ var jaDict = map[string]string{
|
|||||||
"form.register.recaptcha": "CAPTCHAを読み込めません。ページを再読み込みするか、ネットワークを変更してお試しください",
|
"form.register.recaptcha": "CAPTCHAを読み込めません。ページを再読み込みするか、ネットワークを変更してお試しください",
|
||||||
"form.register.agreeRules": "コミュニティルールをお読みのうえ同意してください",
|
"form.register.agreeRules": "コミュニティルールをお読みのうえ同意してください",
|
||||||
"form.register.repeatPassword": "入力した2つのパスワードが一致しません",
|
"form.register.repeatPassword": "入力した2つのパスワードが一致しません",
|
||||||
|
|
||||||
|
// 主题:设置页选择器与主题显示名(theme.name.<slug> 由 internal/theme 约定)
|
||||||
|
"profile.theme.title": "テーマ",
|
||||||
|
"profile.theme.hint": "質問箱のページにのみ適用されます。他のページは既定の外観のままです。",
|
||||||
|
"profile.theme.followDefault": "サイト既定に従う",
|
||||||
|
"profile.theme.save": "テーマを保存",
|
||||||
|
"profile.theme.saved": "テーマを保存しました",
|
||||||
|
"profile.theme.invalid": "このテーマは利用できません。一覧から選択してください",
|
||||||
|
"theme.name.default": "標準の外観",
|
||||||
|
"theme.name.sakura": "さくら",
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -872,6 +872,16 @@ var zhCNDict = map[string]string{
|
|||||||
"profile.saveSocial": "保存社交链接",
|
"profile.saveSocial": "保存社交链接",
|
||||||
"profile.err.cropLibUnavailable": "图片裁剪组件加载失败,请刷新页面后重试",
|
"profile.err.cropLibUnavailable": "图片裁剪组件加载失败,请刷新页面后重试",
|
||||||
|
|
||||||
|
// 主题:设置页选择器与主题显示名(theme.name.<slug> 由 internal/theme 约定)
|
||||||
|
"profile.theme.title": "主题外观",
|
||||||
|
"profile.theme.hint": "仅对提问箱页面生效,站内其它页面保持默认外观。",
|
||||||
|
"profile.theme.followDefault": "跟随站点默认",
|
||||||
|
"profile.theme.save": "保存主题",
|
||||||
|
"profile.theme.saved": "主题已保存",
|
||||||
|
"profile.theme.invalid": "该主题不可用,请从列表中选择",
|
||||||
|
"theme.name.default": "基础外观",
|
||||||
|
"theme.name.sakura": "樱花",
|
||||||
|
|
||||||
// 验证码 JSON 接口:前端消费(P2)
|
// 验证码 JSON 接口:前端消费(P2)
|
||||||
"captcha.json.badRequest": "请求格式错误",
|
"captcha.json.badRequest": "请求格式错误",
|
||||||
"captcha.json.idRequired": "验证码 ID 不能为空",
|
"captcha.json.idRequired": "验证码 ID 不能为空",
|
||||||
|
|||||||
@@ -930,4 +930,14 @@ var zhTWDict = map[string]string{
|
|||||||
"form.register.recaptcha": "無法人機驗證,請重新整理頁面或更換網路後重試",
|
"form.register.recaptcha": "無法人機驗證,請重新整理頁面或更換網路後重試",
|
||||||
"form.register.agreeRules": "請先閱讀並同意社群規則",
|
"form.register.agreeRules": "請先閱讀並同意社群規則",
|
||||||
"form.register.repeatPassword": "兩次輸入的密碼不一致",
|
"form.register.repeatPassword": "兩次輸入的密碼不一致",
|
||||||
|
|
||||||
|
// 主题:设置页选择器与主题显示名(theme.name.<slug> 由 internal/theme 约定)
|
||||||
|
"profile.theme.title": "主題外觀",
|
||||||
|
"profile.theme.hint": "僅對提問箱頁面生效,站內其他頁面維持預設外觀。",
|
||||||
|
"profile.theme.followDefault": "跟隨站點預設",
|
||||||
|
"profile.theme.save": "儲存主題",
|
||||||
|
"profile.theme.saved": "主題已儲存",
|
||||||
|
"profile.theme.invalid": "該主題無法使用,請從清單中選擇",
|
||||||
|
"theme.name.default": "基礎外觀",
|
||||||
|
"theme.name.sakura": "櫻花",
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -346,6 +346,7 @@ func New() *flamego.Flame {
|
|||||||
f.Post("/update", form.Bind(form.UpdateProfile{}), rateLimitMiddleware(10, 1*time.Minute), user.UpdateProfile)
|
f.Post("/update", form.Bind(form.UpdateProfile{}), rateLimitMiddleware(10, 1*time.Minute), user.UpdateProfile)
|
||||||
f.Post("/export", user.ExportProfile)
|
f.Post("/export", user.ExportProfile)
|
||||||
f.Post("/export-json", user.ExportProfileJSON)
|
f.Post("/export-json", user.ExportProfileJSON)
|
||||||
|
f.Post("/theme", form.Bind(form.UpdateProfileTheme{}), rateLimitMiddleware(10, 1*time.Minute), user.UpdateTheme)
|
||||||
f.Combo("/deactivate").Get(user.DeactivateProfile).Post(user.DeactivateProfileAction)
|
f.Combo("/deactivate").Get(user.DeactivateProfile).Post(user.DeactivateProfileAction)
|
||||||
|
|
||||||
f.Post("/update-page-password", form.Bind(form.UpdatePagePassword{}), rateLimitMiddleware(10, 1*time.Minute), user.UpdatePagePassword)
|
f.Post("/update-page-password", form.Bind(form.UpdatePagePassword{}), rateLimitMiddleware(10, 1*time.Minute), user.UpdatePagePassword)
|
||||||
|
|||||||
@@ -0,0 +1,176 @@
|
|||||||
|
// Package theme 维护箱主主题的注册表与取值回退。
|
||||||
|
//
|
||||||
|
// 一个主题就是一个 CSS 文件(static/css/themes/<slug>.css),只覆盖设计令牌:
|
||||||
|
// 配色、页面背景图/图案,不涉及布局。新增主题不需要改任何模板或 Go 代码,
|
||||||
|
// 只要放文件并在 [theme] available 里登记。
|
||||||
|
package theme
|
||||||
|
|
||||||
|
import (
|
||||||
|
"regexp"
|
||||||
|
"strings"
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
|
|
||||||
|
"github.com/tamakyi/TamaBox/internal/conf"
|
||||||
|
"github.com/tamakyi/TamaBox/static"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// DefaultSlug 内置默认主题:不加载任何 css,等价于站点原本的外观。
|
||||||
|
DefaultSlug = "default"
|
||||||
|
|
||||||
|
themeCSSDir = "css/themes/"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
slugRe = regexp.MustCompile(`^[a-z0-9][a-z0-9-]{0,31}$`)
|
||||||
|
// 仅接受纯色值,避免把主题文件里的任意内容拼进设置页的 style 属性。
|
||||||
|
colorRe = regexp.MustCompile(`^(#[0-9a-fA-F]{3,8}|rgba?\([0-9.,\s%/]+\))$`)
|
||||||
|
)
|
||||||
|
|
||||||
|
// Theme 是设置页需要的一项。名称由 i18n 键 theme.name.<slug> 提供,
|
||||||
|
// Swatch 是可直接放进 style 的预览背景(取不到颜色时为空)。
|
||||||
|
type Theme struct {
|
||||||
|
Slug string
|
||||||
|
Swatch string
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
once sync.Once
|
||||||
|
themes []Theme
|
||||||
|
bySlug map[string]Theme
|
||||||
|
siteDef string // 站点默认主题;空串表示「基础外观,不加载主题 css」
|
||||||
|
)
|
||||||
|
|
||||||
|
func load() {
|
||||||
|
once.Do(func() {
|
||||||
|
themes, siteDef, bySlug = build(conf.Theme.Default, conf.Theme.Available)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// build 是注册表的纯函数形态,便于单测直接喂配置。
|
||||||
|
func build(defaultSlug, available string) ([]Theme, string, map[string]Theme) {
|
||||||
|
bySlug := make(map[string]Theme)
|
||||||
|
var list []Theme
|
||||||
|
|
||||||
|
add := func(slug string) {
|
||||||
|
if _, ok := bySlug[slug]; ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
css, err := static.FS.ReadFile(themeCSSDir + slug + ".css")
|
||||||
|
if err != nil {
|
||||||
|
logrus.WithField("theme", slug).Warn("主题文件不存在,已从可用列表忽略")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
t := Theme{Slug: slug, Swatch: swatchOf(string(css), slug)}
|
||||||
|
bySlug[slug] = t
|
||||||
|
list = append(list, t)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, raw := range strings.Split(available, ",") {
|
||||||
|
slug := normalize(raw)
|
||||||
|
if slug == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
add(slug)
|
||||||
|
}
|
||||||
|
|
||||||
|
def := normalize(defaultSlug)
|
||||||
|
if def == DefaultSlug || def == "" {
|
||||||
|
def = ""
|
||||||
|
} else if _, ok := bySlug[def]; !ok {
|
||||||
|
logrus.WithField("theme", def).Warn("站点默认主题不可用,回退基础外观")
|
||||||
|
def = ""
|
||||||
|
}
|
||||||
|
return list, def, bySlug
|
||||||
|
}
|
||||||
|
|
||||||
|
func normalize(slug string) string {
|
||||||
|
slug = strings.ToLower(strings.TrimSpace(slug))
|
||||||
|
if !slugRe.MatchString(slug) {
|
||||||
|
if slug != "" {
|
||||||
|
logrus.WithField("theme", slug).Warn("主题 slug 非法(只允许小写字母/数字/连字符),已忽略")
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return slug
|
||||||
|
}
|
||||||
|
|
||||||
|
// swatchOf 从主题 css 的浅色块里取底色与主色,拼成设置页的小预览。
|
||||||
|
// 取不到(或颜色格式可疑)就返回空串,模板退化为纯色占位。
|
||||||
|
func swatchOf(css, slug string) string {
|
||||||
|
block := ruleBody(css, `html[data-theme-style="`+slug+`"]`)
|
||||||
|
if block == "" {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
bg := tokenValue(block, "--tb-bg")
|
||||||
|
primary := tokenValue(block, "--tb-primary")
|
||||||
|
if !colorRe.MatchString(bg) || !colorRe.MatchString(primary) {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return "linear-gradient(135deg, " + bg + " 0 45%, " + primary + " 45% 100%)"
|
||||||
|
}
|
||||||
|
|
||||||
|
// ruleBody 返回 selector 对应的第一个声明块内容(主题令牌块内不含嵌套规则)。
|
||||||
|
func ruleBody(css, selector string) string {
|
||||||
|
i := strings.Index(css, selector)
|
||||||
|
if i < 0 {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
open := strings.IndexByte(css[i:], '{')
|
||||||
|
if open < 0 {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
start := i + open + 1
|
||||||
|
end := strings.IndexByte(css[start:], '}')
|
||||||
|
if end < 0 {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return css[start : start+end]
|
||||||
|
}
|
||||||
|
|
||||||
|
func tokenValue(block, name string) string {
|
||||||
|
for _, line := range strings.Split(block, ";") {
|
||||||
|
kv := strings.SplitN(line, ":", 2)
|
||||||
|
if len(kv) != 2 || strings.TrimSpace(kv[0]) != name {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
return strings.TrimSpace(kv[1])
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
// List 返回设置页可选项(顺序与 [theme] available 一致)。
|
||||||
|
func List() []Theme {
|
||||||
|
load()
|
||||||
|
return themes
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsAvailable 判断 slug 是否在白名单内且文件存在。
|
||||||
|
func IsAvailable(slug string) bool {
|
||||||
|
load()
|
||||||
|
_, ok := bySlug[strings.ToLower(strings.TrimSpace(slug))]
|
||||||
|
return ok
|
||||||
|
}
|
||||||
|
|
||||||
|
// Resolve 返回该页面要加载的主题 slug;空串表示不加载主题 css(基础外观)。
|
||||||
|
//
|
||||||
|
// 回退顺序:箱主选择 > 站点默认 > 基础外观。
|
||||||
|
// 注意 "" 与 "default" 语义不同:"" 是「没选,跟随站点默认」,
|
||||||
|
// "default" 是箱主明确选择基础外观(即使站点默认是别的主题也不覆盖)。
|
||||||
|
func Resolve(userTheme string) string {
|
||||||
|
load()
|
||||||
|
return resolve(userTheme, siteDef, bySlug)
|
||||||
|
}
|
||||||
|
|
||||||
|
func resolve(userTheme, siteDef string, available map[string]Theme) string {
|
||||||
|
slug := strings.ToLower(strings.TrimSpace(userTheme))
|
||||||
|
if slug == DefaultSlug {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
if _, ok := available[slug]; ok {
|
||||||
|
return slug
|
||||||
|
}
|
||||||
|
return siteDef
|
||||||
|
}
|
||||||
@@ -0,0 +1,104 @@
|
|||||||
|
package theme
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io/fs"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
|
"github.com/tamakyi/TamaBox/static"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 主题必须自带的一套颜色令牌(形状/字体/阴影允许继承基础层)。
|
||||||
|
var requiredTokens = []string{
|
||||||
|
"--tb-bg", "--tb-surface", "--tb-surface-2", "--tb-surface-hover", "--tb-border",
|
||||||
|
"--tb-text", "--tb-text-secondary", "--tb-text-muted",
|
||||||
|
"--tb-primary", "--tb-primary-weak",
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestBuildAvailable(t *testing.T) {
|
||||||
|
list, def, _ := build("sakura", "default, sakura ,bad_Slug,missing")
|
||||||
|
|
||||||
|
assert.Equal(t, "sakura", def, "站点默认应取配置值")
|
||||||
|
var slugs []string
|
||||||
|
for _, item := range list {
|
||||||
|
slugs = append(slugs, item.Slug)
|
||||||
|
}
|
||||||
|
// bad_Slug 非法、missing 没有 css 文件,都应被忽略
|
||||||
|
assert.Equal(t, []string{"default", "sakura"}, slugs)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestBuildInvalidDefault(t *testing.T) {
|
||||||
|
_, def, _ := build("does-not-exist", "sakura")
|
||||||
|
assert.Equal(t, "", def, "默认主题不可用时回退基础外观")
|
||||||
|
|
||||||
|
_, def, _ = build("default", "default,sakura")
|
||||||
|
assert.Equal(t, "", def, "default 语义即基础外观,不应产生 css 请求")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestResolve(t *testing.T) {
|
||||||
|
// 站点默认是 sakura
|
||||||
|
themes, siteDef, index := build("sakura", "default,sakura")
|
||||||
|
require.Equal(t, "sakura", siteDef)
|
||||||
|
require.Contains(t, index, "sakura")
|
||||||
|
require.NotEmpty(t, themes)
|
||||||
|
|
||||||
|
assert.Equal(t, "sakura", resolve("", siteDef, index), "未选择时跟随站点默认")
|
||||||
|
assert.Equal(t, "sakura", resolve("SAKURA", siteDef, index), "大小写不敏感")
|
||||||
|
assert.Equal(t, "", resolve("default", siteDef, index), "显式选 default = 基础外观,不回退站点默认")
|
||||||
|
assert.Equal(t, "sakura", resolve("nope", siteDef, index), "非法值回退站点默认")
|
||||||
|
|
||||||
|
// 站点默认是基础外观
|
||||||
|
_, def2, index2 := build("default", "default,sakura")
|
||||||
|
assert.Equal(t, "", resolve("", def2, index2))
|
||||||
|
assert.Equal(t, "sakura", resolve("sakura", def2, index2))
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestThemeCSSComplete 防止「复制底稿只写了浅色块」这类问题:
|
||||||
|
// 半套主题不会报错,只会让深色模式变成浅色配色。
|
||||||
|
func TestThemeCSSComplete(t *testing.T) {
|
||||||
|
entries, err := fs.ReadDir(static.FS, strings.TrimSuffix(themeCSSDir, "/"))
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.NotEmpty(t, entries)
|
||||||
|
|
||||||
|
for _, e := range entries {
|
||||||
|
name := e.Name()
|
||||||
|
if !strings.HasSuffix(name, ".css") {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
slug := strings.TrimSuffix(name, ".css")
|
||||||
|
// _scaffold.css 是给人复制的模板,default.css 永不加载(仅提供色块预览)
|
||||||
|
if strings.HasPrefix(slug, "_") || slug == DefaultSlug {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
raw, err := static.FS.ReadFile(themeCSSDir + name)
|
||||||
|
require.NoError(t, err)
|
||||||
|
css := string(raw)
|
||||||
|
|
||||||
|
light := ruleBody(css, `html[data-theme-style="`+slug+`"]`)
|
||||||
|
require.NotEmpty(t, light, "%s:缺少浅色块 html[data-theme-style=\"%s\"]", name, slug)
|
||||||
|
|
||||||
|
dark := ruleBody(css, `html[data-theme="dark"][data-theme-style="`+slug+`"]`)
|
||||||
|
require.NotEmpty(t, dark, "%s:缺少深色块 html[data-theme=\"dark\"][data-theme-style=\"%s\"]", name, slug)
|
||||||
|
|
||||||
|
for _, tok := range requiredTokens {
|
||||||
|
assert.NotEmpty(t, tokenValue(light, tok), "%s 浅色块缺少 %s", name, tok)
|
||||||
|
assert.NotEmpty(t, tokenValue(dark, tok), "%s 深色块缺少 %s", name, tok)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSwatch(t *testing.T) {
|
||||||
|
raw, err := static.FS.ReadFile(themeCSSDir + "sakura.css")
|
||||||
|
require.NoError(t, err)
|
||||||
|
sw := swatchOf(string(raw), "sakura")
|
||||||
|
assert.True(t, strings.HasPrefix(sw, "linear-gradient("), "swatch 应为渐变串,实际 %q", sw)
|
||||||
|
assert.Contains(t, sw, "#e5678f")
|
||||||
|
|
||||||
|
assert.Equal(t, "", swatchOf("/* 空文件 */", "sakura"), "取不到颜色时返回空串")
|
||||||
|
assert.Equal(t, "", swatchOf(`html[data-theme-style="x"] { --tb-bg: url(evil); --tb-primary: #fff; }`, "x"),
|
||||||
|
"非色值内容不得进入 swatch")
|
||||||
|
}
|
||||||
|
After Width: | Height: | Size: 54 KiB |
|
After Width: | Height: | Size: 39 KiB |
|
After Width: | Height: | Size: 51 KiB |
|
After Width: | Height: | Size: 14 KiB |
|
After Width: | Height: | Size: 134 KiB |
|
After Width: | Height: | Size: 38 KiB |
|
After Width: | Height: | Size: 20 KiB |
|
After Width: | Height: | Size: 46 KiB |
@@ -3,7 +3,7 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
<title>预览 12:01 · </title>
|
<title>预览 15:15 · </title>
|
||||||
<meta name="msvalidate.01" content="2F185E8E63C93635F50B3574F3B31E42" />
|
<meta name="msvalidate.01" content="2F185E8E63C93635F50B3574F3B31E42" />
|
||||||
<meta name="description" content="狼的提问箱——一个无需注册、可匿名提问的匿名提问箱,安全地倾诉与回应。">
|
<meta name="description" content="狼的提问箱——一个无需注册、可匿名提问的匿名提问箱,安全地倾诉与回应。">
|
||||||
<meta name="keywords" content="匿名提问箱,提问箱,匿名提问,狼的提问箱,匿名问答,匿名提问网站">
|
<meta name="keywords" content="匿名提问箱,提问箱,匿名提问,狼的提问箱,匿名问答,匿名提问网站">
|
||||||
@@ -20,675 +20,8 @@
|
|||||||
|
|
||||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/uikit/3.3.3/css/uikit.min.css"/>
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/uikit/3.3.3/css/uikit.min.css"/>
|
||||||
|
|
||||||
<style>/* TamaBox 全站基础样式:设计令牌 / 主题覆盖 / 组件质感 / 响应式。
|
<link rel="stylesheet" href="/static/css/base.css?v="/>
|
||||||
由 base/header.html 内联块抽出,集中一份便于缓存与维护。
|
|
||||||
⚠️ 改完务必把 header 里的 ?v= 版本号 +1,否则老访客仍用缓存。 */
|
|
||||||
|
|
||||||
/* 设计令牌:亮色为默认(:root),深色在 html[data-theme="dark"] 覆盖。
|
|
||||||
页面与组件样式一律引用 var(--tb-*),不再写死色值/圆角/阴影;
|
|
||||||
var() 的第二个参数仅作兜底(旧缓存页、邮件模板等不引入本文件的场景)。
|
|
||||||
改配色只动这一块,亮暗两套自动保持一致。 */
|
|
||||||
:root {
|
|
||||||
--tb-bg: #f7f8fa;
|
|
||||||
--tb-surface: #ffffff;
|
|
||||||
--tb-surface-2: #f4f6f8;
|
|
||||||
--tb-surface-hover: #f3f7ff;
|
|
||||||
--tb-border: #e8eaee;
|
|
||||||
--tb-text: #1f2329;
|
|
||||||
--tb-text-secondary: #5c6370;
|
|
||||||
--tb-text-muted: #8a919c;
|
|
||||||
--tb-primary: #1e87f0;
|
|
||||||
--tb-primary-weak: rgba(30, 135, 240, 0.10);
|
|
||||||
--tb-radius: 12px;
|
|
||||||
--tb-radius-sm: 8px;
|
|
||||||
--tb-radius-xs: 6px;
|
|
||||||
--tb-shadow: 0 1px 2px rgba(16, 24, 40, 0.04), 0 12px 28px -18px rgba(16, 24, 40, 0.20);
|
|
||||||
--tb-shadow-hover: 0 1px 2px rgba(16, 24, 40, 0.05), 0 18px 40px -20px rgba(16, 24, 40, 0.28);
|
|
||||||
--tb-font: system-ui, -apple-system, "Segoe UI", "PingFang SC", "Hiragino Sans GB", "Noto Sans CJK SC", "Microsoft YaHei", sans-serif;
|
|
||||||
}
|
|
||||||
html[data-theme="dark"] {
|
|
||||||
--tb-bg: #1a1d23;
|
|
||||||
--tb-surface: #242830;
|
|
||||||
--tb-surface-2: #2d323c;
|
|
||||||
--tb-surface-hover: rgba(92, 141, 255, 0.12);
|
|
||||||
--tb-border: #3a404c;
|
|
||||||
--tb-text: #d8dce4;
|
|
||||||
--tb-text-secondary: #a8b0bd;
|
|
||||||
--tb-text-muted: #8b93a1;
|
|
||||||
--tb-primary: #5c8dff;
|
|
||||||
--tb-primary-weak: rgba(92, 141, 255, 0.14);
|
|
||||||
--tb-shadow: 0 1px 2px rgba(0, 0, 0, 0.30), 0 12px 28px -18px rgba(0, 0, 0, 0.55);
|
|
||||||
--tb-shadow-hover: 0 1px 2px rgba(0, 0, 0, 0.35), 0 18px 40px -20px rgba(0, 0, 0, 0.65);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* UIkit 补丁:复刻原自建版 "modify-black-font"(官方版与自建版仅 3 处颜色差异——把有色容器内默认白字/白标题改为黑字)。
|
|
||||||
模板当前只用到 .uk-light 容器(用户背景封面,question/list.html、question-not-found.html;
|
|
||||||
其中 h3/p 已由 #usernamecolor/#introcolor 内联 style 覆盖),故只需补该容器的 3 处投影即可保持渲染一致。
|
|
||||||
若日后新增 .uk-card-primary/.uk-card-secondary/.uk-section-primary/.uk-tile-*/.uk-overlay-primary 等容器且需黑字,须同步扩展。 */
|
|
||||||
.uk-light { color: rgba(0,0,0,.7); }
|
|
||||||
.uk-light .uk-h1, .uk-light .uk-h2, .uk-light .uk-h3, .uk-light .uk-h4, .uk-light .uk-h5, .uk-light .uk-h6,
|
|
||||||
.uk-light .uk-heading-2xlarge, .uk-light .uk-heading-large, .uk-light .uk-heading-medium, .uk-light .uk-heading-small, .uk-light .uk-heading-xlarge,
|
|
||||||
.uk-light h1, .uk-light h2, .uk-light h3, .uk-light h4, .uk-light h5, .uk-light h6 { color: #000; }
|
|
||||||
.uk-light .uk-table th { color: rgba(0,0,0,.7); }
|
|
||||||
|
|
||||||
.grecaptcha-badge {visibility: hidden;}
|
|
||||||
.icon-container {
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
.icon {
|
|
||||||
margin-left: 10px;
|
|
||||||
width: 20px; /* 设置图标的宽度 */
|
|
||||||
height: auto; /* 保持图标的高度自动调整 */
|
|
||||||
}
|
|
||||||
.emoji-placeholder {
|
|
||||||
display: inline-block;
|
|
||||||
animation: jump 0.5s ease-in-out;
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes jump {
|
|
||||||
0%, 100% { transform: translateY(0); }
|
|
||||||
50% { transform: translateY(-5px); }
|
|
||||||
}
|
|
||||||
/* 防止 UIkit Dropbar 初始闪烁 */
|
|
||||||
.uk-dropbar {
|
|
||||||
opacity: 0;
|
|
||||||
visibility: hidden;
|
|
||||||
transition: opacity 0.2s ease, visibility 0.2s ease;
|
|
||||||
}
|
|
||||||
|
|
||||||
.uk-dropbar.uk-open {
|
|
||||||
opacity: 1;
|
|
||||||
visibility: visible;
|
|
||||||
}
|
|
||||||
|
|
||||||
a.uk-button.uk-button-link {
|
|
||||||
text-transform: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 移动端优化:缩小字体和间距,避免右侧空白 */
|
|
||||||
@media (max-width: 640px) {
|
|
||||||
.uk-logo {
|
|
||||||
font-size: 1rem;
|
|
||||||
}
|
|
||||||
.uk-navbar-nav a {
|
|
||||||
font-size: 0.78rem;
|
|
||||||
padding: 0 4px;
|
|
||||||
}
|
|
||||||
.emoji-placeholder {
|
|
||||||
font-size: 1rem;
|
|
||||||
}
|
|
||||||
/* 移动端用户名限宽省略,避免长英文用户名撑爆顶栏 */
|
|
||||||
.tb-nav-username {
|
|
||||||
max-width: 64px;
|
|
||||||
overflow: hidden;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
white-space: nowrap;
|
|
||||||
display: inline-block;
|
|
||||||
vertical-align: middle;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 深色模式:html[data-theme="dark"] 时覆盖 UIkit 3.3.3 编译主题的关键颜色 */
|
|
||||||
/* 变量(--tb-*)已上移到 head 顶部的令牌块,亮暗两套同名常量在那里定义。 */
|
|
||||||
/* 根元素与 body 一起覆盖,确保整个视口(含内容不足一屏时的空白区)都是深色背景 */
|
|
||||||
html[data-theme="dark"],
|
|
||||||
html[data-theme="dark"] body {
|
|
||||||
background-color: var(--tb-bg) !important;
|
|
||||||
color: var(--tb-text) !important;
|
|
||||||
}
|
|
||||||
/* 通用表面容器 */
|
|
||||||
html[data-theme="dark"] .uk-card,
|
|
||||||
html[data-theme="dark"] .uk-card-default,
|
|
||||||
html[data-theme="dark"] .uk-card-secondary,
|
|
||||||
html[data-theme="dark"] .uk-dropbar,
|
|
||||||
html[data-theme="dark"] .uk-navbar-dropdown,
|
|
||||||
html[data-theme="dark"] .uk-modal-dialog,
|
|
||||||
html[data-theme="dark"] .uk-dropdown,
|
|
||||||
html[data-theme="dark"] .uk-offcanvas-bar,
|
|
||||||
html[data-theme="dark"] .uk-section,
|
|
||||||
html[data-theme="dark"] .uk-tile,
|
|
||||||
html[data-theme="dark"] .uk-panel,
|
|
||||||
html[data-theme="dark"] .uk-background-default,
|
|
||||||
html[data-theme="dark"] .uk-search-default .uk-search-input {
|
|
||||||
background-color: var(--tb-surface) !important;
|
|
||||||
color: var(--tb-text) !important;
|
|
||||||
}
|
|
||||||
html[data-theme="dark"] .uk-navbar-container {
|
|
||||||
background-color: var(--tb-surface) !important;
|
|
||||||
color: var(--tb-text) !important;
|
|
||||||
}
|
|
||||||
html[data-theme="dark"] .uk-navbar-nav > li > a,
|
|
||||||
html[data-theme="dark"] .uk-card a,
|
|
||||||
html[data-theme="dark"] .uk-link,
|
|
||||||
html[data-theme="dark"] a.uk-button-link,
|
|
||||||
html[data-theme="dark"] .uk-navbar-dropdown-nav > li > a,
|
|
||||||
html[data-theme="dark"] .uk-dropdown-nav > li > a,
|
|
||||||
html[data-theme="dark"] .uk-list a {
|
|
||||||
color: var(--tb-text) !important;
|
|
||||||
}
|
|
||||||
html[data-theme="dark"] .uk-navbar-nav > li > a:hover,
|
|
||||||
html[data-theme="dark"] .uk-card a:hover,
|
|
||||||
html[data-theme="dark"] .uk-navbar-dropdown-nav > li > a:hover,
|
|
||||||
html[data-theme="dark"] .uk-dropdown-nav > li > a:hover {
|
|
||||||
color: var(--tb-primary) !important;
|
|
||||||
}
|
|
||||||
html[data-theme="dark"] .uk-input,
|
|
||||||
html[data-theme="dark"] .uk-textarea,
|
|
||||||
html[data-theme="dark"] .uk-select {
|
|
||||||
background-color: var(--tb-surface-2) !important;
|
|
||||||
color: var(--tb-text) !important;
|
|
||||||
border-color: var(--tb-border) !important;
|
|
||||||
}
|
|
||||||
html[data-theme="dark"] .uk-input:focus,
|
|
||||||
html[data-theme="dark"] .uk-textarea:focus,
|
|
||||||
html[data-theme="dark"] .uk-select:focus {
|
|
||||||
border-color: var(--tb-primary) !important;
|
|
||||||
}
|
|
||||||
html[data-theme="dark"] .uk-text-muted,
|
|
||||||
html[data-theme="dark"] .uk-text-meta,
|
|
||||||
html[data-theme="dark"] .uk-text-secondary,
|
|
||||||
html[data-theme="dark"] .uk-text-muted a,
|
|
||||||
html[data-theme="dark"] .uk-text-small.uk-text-muted {
|
|
||||||
color: var(--tb-text-muted) !important;
|
|
||||||
}
|
|
||||||
html[data-theme="dark"] .uk-divider-icon::after,
|
|
||||||
html[data-theme="dark"] hr,
|
|
||||||
html[data-theme="dark"] .uk-table th,
|
|
||||||
html[data-theme="dark"] .uk-table td,
|
|
||||||
html[data-theme="dark"] .uk-list-divider > li:nth-child(n+2) {
|
|
||||||
border-color: var(--tb-border) !important;
|
|
||||||
}
|
|
||||||
html[data-theme="dark"] .uk-button-default {
|
|
||||||
background-color: var(--tb-surface-2) !important;
|
|
||||||
color: var(--tb-text) !important;
|
|
||||||
border-color: var(--tb-border) !important;
|
|
||||||
}
|
|
||||||
html[data-theme="dark"] .uk-modal-title,
|
|
||||||
html[data-theme="dark"] h1, html[data-theme="dark"] h2, html[data-theme="dark"] h3,
|
|
||||||
html[data-theme="dark"] h4, html[data-theme="dark"] h5, html[data-theme="dark"] h6,
|
|
||||||
html[data-theme="dark"] .uk-card-title {
|
|
||||||
color: var(--tb-text) !important;
|
|
||||||
}
|
|
||||||
html[data-theme="dark"] .uk-alert-warning,
|
|
||||||
html[data-theme="dark"] .uk-alert-danger,
|
|
||||||
html[data-theme="dark"] .uk-alert-success,
|
|
||||||
html[data-theme="dark"] .uk-alert-primary {
|
|
||||||
background-color: var(--tb-surface-2) !important;
|
|
||||||
color: var(--tb-text) !important;
|
|
||||||
}
|
|
||||||
html[data-theme="dark"] #math-captcha-modal .uk-modal-dialog {
|
|
||||||
background-color: var(--tb-surface) !important;
|
|
||||||
color: var(--tb-text) !important;
|
|
||||||
}
|
|
||||||
html[data-theme="dark"] #math-captcha-modal .captcha-equation-box {
|
|
||||||
background-color: var(--tb-surface-2) !important;
|
|
||||||
border-color: var(--tb-border) !important;
|
|
||||||
}
|
|
||||||
html[data-theme="dark"] #math-captcha-modal .math-captcha-modal-question {
|
|
||||||
color: var(--tb-text) !important;
|
|
||||||
}
|
|
||||||
html[data-theme="dark"] #math-captcha-modal #captcha-modal-answer {
|
|
||||||
background-color: var(--tb-surface) !important;
|
|
||||||
color: var(--tb-text) !important;
|
|
||||||
border-color: var(--tb-border) !important;
|
|
||||||
}
|
|
||||||
html[data-theme="dark"] #math-captcha-modal #captcha-modal-answer::placeholder {
|
|
||||||
color: var(--tb-text-muted) !important;
|
|
||||||
}
|
|
||||||
html[data-theme="dark"] #math-captcha-modal .uk-text-meta,
|
|
||||||
html[data-theme="dark"] #math-captcha-modal #captcha-modal-refresh {
|
|
||||||
color: var(--tb-text-muted) !important;
|
|
||||||
}
|
|
||||||
html[data-theme="dark"] #math-captcha-modal #captcha-modal-refresh:hover {
|
|
||||||
color: var(--tb-primary) !important;
|
|
||||||
}
|
|
||||||
html[data-theme="dark"] .uk-label {
|
|
||||||
color: #fff !important;
|
|
||||||
}
|
|
||||||
/* 自定义组件(探索页推荐卡片等)深色覆盖 */
|
|
||||||
html[data-theme="dark"] .recommend-card,
|
|
||||||
html[data-theme="dark"] .recommend-card:hover {
|
|
||||||
background-color: var(--tb-surface-2) !important;
|
|
||||||
}
|
|
||||||
html[data-theme="dark"] .explore-name a {
|
|
||||||
color: var(--tb-text) !important;
|
|
||||||
}
|
|
||||||
html[data-theme="dark"] .explore-name a:hover {
|
|
||||||
color: var(--tb-primary) !important;
|
|
||||||
}
|
|
||||||
html[data-theme="dark"] .explore-intro {
|
|
||||||
color: var(--tb-text-muted) !important;
|
|
||||||
}
|
|
||||||
/* 切换按钮图标切换(内联 SVG,不依赖 UIkit 图标库) */
|
|
||||||
#theme-toggle .tb-icon-light, #theme-toggle-mobile .tb-icon-light,
|
|
||||||
#theme-toggle .tb-icon-dark, #theme-toggle-mobile .tb-icon-dark {
|
|
||||||
display: inline-flex;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
#theme-toggle .tb-icon-light svg, #theme-toggle-mobile .tb-icon-light svg,
|
|
||||||
#theme-toggle .tb-icon-dark svg, #theme-toggle-mobile .tb-icon-dark svg { display: block; }
|
|
||||||
#theme-toggle .tb-icon-dark, #theme-toggle-mobile .tb-icon-dark { display: none; }
|
|
||||||
html[data-theme="dark"] #theme-toggle .tb-icon-light,
|
|
||||||
html[data-theme="dark"] #theme-toggle-mobile .tb-icon-light { display: none; }
|
|
||||||
html[data-theme="dark"] #theme-toggle .tb-icon-dark,
|
|
||||||
html[data-theme="dark"] #theme-toggle-mobile .tb-icon-dark { display: inline-flex; }
|
|
||||||
|
|
||||||
/* 基础质感层:只调整外观(圆角/投影/字体/数字对齐),不改任何结构与布局。
|
|
||||||
颜色一律取自头部令牌,亮暗两套自动生效,因此这里不需要再写 html[data-theme="dark"] 分支。 */
|
|
||||||
/* 根元素与 body 同时上色:内容不足一屏时,body 之外的视口区域也要是同一底色 */
|
|
||||||
html,
|
|
||||||
body {
|
|
||||||
font-family: var(--tb-font);
|
|
||||||
background-color: var(--tb-bg);
|
|
||||||
color: var(--tb-text);
|
|
||||||
-webkit-font-smoothing: antialiased;
|
|
||||||
-moz-osx-font-smoothing: grayscale;
|
|
||||||
}
|
|
||||||
/* 卡片:12px 圆角 + 一层极淡接触影 + 一层大扩散影(UIkit 默认的 0 5px 15px 偏硬) */
|
|
||||||
.uk-card {
|
|
||||||
border-radius: var(--tb-radius);
|
|
||||||
}
|
|
||||||
.uk-card-default {
|
|
||||||
background-color: var(--tb-surface);
|
|
||||||
box-shadow: var(--tb-shadow);
|
|
||||||
}
|
|
||||||
.uk-card-default.uk-card-hover:hover {
|
|
||||||
box-shadow: var(--tb-shadow-hover);
|
|
||||||
}
|
|
||||||
.uk-card-header {
|
|
||||||
border-radius: var(--tb-radius) var(--tb-radius) 0 0;
|
|
||||||
}
|
|
||||||
.uk-card-footer {
|
|
||||||
border-radius: 0 0 var(--tb-radius) var(--tb-radius);
|
|
||||||
}
|
|
||||||
.uk-card,
|
|
||||||
.uk-button,
|
|
||||||
.uk-alert,
|
|
||||||
.uk-label {
|
|
||||||
transition: box-shadow 0.18s ease, background-color 0.18s ease, border-color 0.18s ease, color 0.18s ease;
|
|
||||||
}
|
|
||||||
/* 交互元素:统一 8px 圆角,标签 6px */
|
|
||||||
.uk-button {
|
|
||||||
border-radius: var(--tb-radius-sm);
|
|
||||||
}
|
|
||||||
.uk-input,
|
|
||||||
.uk-select,
|
|
||||||
.uk-textarea,
|
|
||||||
.uk-form-small,
|
|
||||||
.uk-search-input {
|
|
||||||
border-radius: var(--tb-radius-sm);
|
|
||||||
}
|
|
||||||
.uk-label {
|
|
||||||
border-radius: var(--tb-radius-xs);
|
|
||||||
}
|
|
||||||
.uk-alert {
|
|
||||||
border-radius: 10px;
|
|
||||||
}
|
|
||||||
.uk-modal-dialog {
|
|
||||||
border-radius: 14px;
|
|
||||||
}
|
|
||||||
.uk-dropdown,
|
|
||||||
.uk-navbar-dropdown {
|
|
||||||
border-radius: 10px;
|
|
||||||
box-shadow: var(--tb-shadow);
|
|
||||||
}
|
|
||||||
.uk-navbar-container:not(.uk-navbar-transparent) {
|
|
||||||
background-color: var(--tb-surface);
|
|
||||||
}
|
|
||||||
/* 键盘可达性:仅在键盘聚焦时出现描边,鼠标点击不出现 */
|
|
||||||
.uk-button:focus-visible,
|
|
||||||
.uk-navbar-nav > li > a:focus-visible {
|
|
||||||
outline: 2px solid var(--tb-primary);
|
|
||||||
outline-offset: 2px;
|
|
||||||
}
|
|
||||||
/* 次要文字统一走令牌,避免 #999 / #8a919c 混用 */
|
|
||||||
.uk-text-muted,
|
|
||||||
.uk-text-meta {
|
|
||||||
color: var(--tb-text-muted);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 轻量胶囊:用于投票类型、热门标签等「只是分类信息」的位置。
|
|
||||||
实心 uk-label 一屏多个会变成一排色块,这里统一降级为浅底 + 次要色文字。 */
|
|
||||||
.tb-chip {
|
|
||||||
display: inline-block;
|
|
||||||
padding: 1px 8px;
|
|
||||||
border-radius: var(--tb-radius-xs);
|
|
||||||
background-color: var(--tb-surface-2);
|
|
||||||
color: var(--tb-text-secondary);
|
|
||||||
font-size: 0.72rem;
|
|
||||||
line-height: 1.7;
|
|
||||||
white-space: nowrap;
|
|
||||||
}
|
|
||||||
a.tb-chip:hover {
|
|
||||||
background-color: var(--tb-primary-weak);
|
|
||||||
color: var(--tb-primary);
|
|
||||||
text-decoration: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 统计/日期等数字列等宽对齐,避免刷新时左右跳动 */
|
|
||||||
.uk-table,
|
|
||||||
.tb-num {
|
|
||||||
font-variant-numeric: tabular-nums;
|
|
||||||
}
|
|
||||||
/* 图片上传条:原为 item/new-question 两处各写一份内联 style(写死 #f8f8f8,深色下露白),
|
|
||||||
收敛到一处并走令牌,亮暗自动适配 */
|
|
||||||
.tb-img-uploader {
|
|
||||||
width: 100%;
|
|
||||||
background-color: var(--tb-surface-2);
|
|
||||||
display: flex;
|
|
||||||
padding-top: 5px;
|
|
||||||
padding-bottom: 5px;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: flex-start;
|
|
||||||
gap: 5px;
|
|
||||||
}
|
|
||||||
/* 背景图封面(提问箱主页):渐变遮罩,保证用户自选文字色叠加后仍可读。
|
|
||||||
默认浅色遮罩(页面 .uk-light 补丁把文字兜底成深色);若箱主选了浅色文字,
|
|
||||||
question/list.html 会按亮度加上 .tb-cover-dark 换成深色遮罩。 */
|
|
||||||
.tb-cover {
|
|
||||||
position: relative;
|
|
||||||
border-radius: var(--tb-radius) var(--tb-radius) 0 0;
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
/* ⚠️ 必须带 .uk-flex 复合选择器:UIkit 3.3.3 里有
|
|
||||||
.uk-flex::after,.uk-flex::before{display:none}(优先级 0,2,0),
|
|
||||||
会把这个遮罩伪元素整个干掉——不报错、只是什么都不显示(踩过一次)。
|
|
||||||
单写 .tb-cover::after 优先级不够,会被它压回 display:none。 */
|
|
||||||
.tb-cover::after,
|
|
||||||
.tb-cover.uk-flex::after {
|
|
||||||
content: "";
|
|
||||||
display: block;
|
|
||||||
position: absolute;
|
|
||||||
inset: 0;
|
|
||||||
z-index: 0;
|
|
||||||
background: linear-gradient(180deg, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.58) 55%, rgba(255, 255, 255, 0.84) 100%);
|
|
||||||
pointer-events: none;
|
|
||||||
}
|
|
||||||
.tb-cover.tb-cover-dark::after {
|
|
||||||
background: linear-gradient(180deg, rgba(0, 0, 0, 0) 0%, rgba(0, 0, 0, 0.16) 45%, rgba(0, 0, 0, 0.46) 100%);
|
|
||||||
}
|
|
||||||
.tb-cover > * {
|
|
||||||
position: relative;
|
|
||||||
z-index: 1;
|
|
||||||
}
|
|
||||||
.tb-cover h3,
|
|
||||||
.tb-cover p {
|
|
||||||
text-shadow: 0 1px 10px rgba(255, 255, 255, 0.65);
|
|
||||||
}
|
|
||||||
.tb-cover.tb-cover-dark h3,
|
|
||||||
.tb-cover.tb-cover-dark p {
|
|
||||||
text-shadow: 0 1px 12px rgba(0, 0, 0, 0.45);
|
|
||||||
}
|
|
||||||
/* 尊重系统的减少动效设置 */
|
|
||||||
@media (prefers-reduced-motion: reduce) {
|
|
||||||
.uk-card,
|
|
||||||
.uk-button,
|
|
||||||
.emoji-placeholder {
|
|
||||||
transition: none;
|
|
||||||
animation: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 顶栏自适应:导航全部直接显示,窄屏时分级缩小字号/间距,保证英文/日文等长文字不溢出 */
|
|
||||||
.uk-navbar-nav a {
|
|
||||||
font-size: 0.95rem;
|
|
||||||
padding: 0 10px;
|
|
||||||
}
|
|
||||||
/* 未登录移动端占位:桌面端隐藏,仅 ≤640px 显示(见下方 media 查询)。
|
|
||||||
桌面端布局与改动前完全一致,不受影响。 */
|
|
||||||
.tb-mobile-balancer { display: none; }
|
|
||||||
/* 桌面端保持 UIkit 原生居中三列布局(无需额外 CSS) */
|
|
||||||
.tb-navbar .uk-logo {
|
|
||||||
white-space: nowrap;
|
|
||||||
}
|
|
||||||
@media (max-width: 1200px) {
|
|
||||||
.uk-navbar-nav a {
|
|
||||||
font-size: 0.88rem;
|
|
||||||
padding: 0 8px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@media (max-width: 1000px) {
|
|
||||||
.uk-navbar-nav a {
|
|
||||||
font-size: 0.82rem;
|
|
||||||
padding: 0 6px;
|
|
||||||
}
|
|
||||||
.uk-logo {
|
|
||||||
font-size: 1.1rem;
|
|
||||||
}
|
|
||||||
/* 登录用户名限宽,过长省略号截断 */
|
|
||||||
.tb-nav-username {
|
|
||||||
max-width: 110px;
|
|
||||||
overflow: hidden;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
white-space: nowrap;
|
|
||||||
display: inline-block;
|
|
||||||
vertical-align: middle;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@media (max-width: 800px) {
|
|
||||||
.uk-navbar-nav a {
|
|
||||||
font-size: 0.78rem;
|
|
||||||
padding: 0 4px;
|
|
||||||
}
|
|
||||||
.uk-logo {
|
|
||||||
font-size: 1rem;
|
|
||||||
}
|
|
||||||
.tb-nav-username {
|
|
||||||
max-width: 80px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* 手机端(≤640px):沿用 UIkit 桌面端 navbar 的原生三列定位。
|
|
||||||
不再重写 .uk-navbar-center / center-left / center-right 的定位,
|
|
||||||
避免 logo 被挤到下一行;底部语言与深色模式按钮仍由下方独立栏承载。 */
|
|
||||||
@media (max-width: 640px) {
|
|
||||||
.tb-navbar {
|
|
||||||
position: relative;
|
|
||||||
min-height: 56px;
|
|
||||||
overflow: visible;
|
|
||||||
}
|
|
||||||
.tb-navbar > .uk-navbar-center {
|
|
||||||
position: relative !important;
|
|
||||||
top: auto !important;
|
|
||||||
left: auto !important;
|
|
||||||
right: auto !important;
|
|
||||||
bottom: auto !important;
|
|
||||||
transform: none !important;
|
|
||||||
display: flex !important;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
width: 100%;
|
|
||||||
min-height: 56px;
|
|
||||||
white-space: nowrap;
|
|
||||||
flex-wrap: nowrap;
|
|
||||||
}
|
|
||||||
.tb-navbar .uk-navbar-center-left,
|
|
||||||
.tb-navbar .uk-navbar-center-right {
|
|
||||||
position: static !important;
|
|
||||||
top: auto !important;
|
|
||||||
left: auto !important;
|
|
||||||
right: auto !important;
|
|
||||||
bottom: auto !important;
|
|
||||||
transform: none !important;
|
|
||||||
display: flex !important;
|
|
||||||
align-items: center;
|
|
||||||
flex: 0 0 auto;
|
|
||||||
white-space: nowrap;
|
|
||||||
}
|
|
||||||
.tb-navbar .uk-navbar-center-left > div,
|
|
||||||
.tb-navbar .uk-navbar-center-right > div {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
white-space: nowrap;
|
|
||||||
}
|
|
||||||
.tb-navbar .uk-navbar-nav {
|
|
||||||
display: flex;
|
|
||||||
flex-wrap: nowrap;
|
|
||||||
flex: 0 0 auto;
|
|
||||||
}
|
|
||||||
.tb-navbar .uk-navbar-nav > li > a,
|
|
||||||
.tb-navbar .uk-logo {
|
|
||||||
white-space: nowrap;
|
|
||||||
}
|
|
||||||
/* 未登录:移动端显示与「我的」等宽的隐藏占位,使左栏「探索+占位」与
|
|
||||||
右栏「注册/登录」两项等宽,logo 真正居中,左右视觉平衡 */
|
|
||||||
.tb-mobile-balancer { display: block; }
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 标签样式的按钮(管理页置顶等):
|
|
||||||
尺寸完全继承 .uk-label(font-size/padding/line-height/text-transform 等),
|
|
||||||
仅覆盖 button 元素特有的默认样式(边框/字体族/光标等),保证与相邻 span 标签完全一致。 */
|
|
||||||
.tb-label-btn {
|
|
||||||
border: none !important;
|
|
||||||
cursor: pointer;
|
|
||||||
font-family: inherit;
|
|
||||||
margin: 0;
|
|
||||||
vertical-align: middle;
|
|
||||||
outline: none;
|
|
||||||
background-image: none;
|
|
||||||
box-sizing: border-box;
|
|
||||||
-webkit-appearance: none;
|
|
||||||
appearance: none;
|
|
||||||
}
|
|
||||||
.tb-label-btn:hover {
|
|
||||||
opacity: 0.85;
|
|
||||||
}
|
|
||||||
/* 公开页置顶小图标:仅一个图钉,不占行高、不影响原布局 */
|
|
||||||
.tb-pin-flag {
|
|
||||||
font-size: 0.9em;
|
|
||||||
margin-right: 4px;
|
|
||||||
vertical-align: -1px;
|
|
||||||
cursor: default;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Markdown 渲染排版(问题/回答/追问正文,左对齐以保留排版格式) */
|
|
||||||
/* 纯文本列表:保留换行与连续空格(pre-wrap),不渲染 Markdown 大字号/彩色 */
|
|
||||||
.tb-preline {
|
|
||||||
white-space: pre-wrap;
|
|
||||||
}
|
|
||||||
/* 纯文本列表:超过 5 行截断并显示省略号(不足 5 行则完整显示) */
|
|
||||||
.tb-clamp-5 {
|
|
||||||
display: -webkit-box;
|
|
||||||
-webkit-box-orient: vertical;
|
|
||||||
-webkit-line-clamp: 5;
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
.md-body {
|
|
||||||
line-height: 1.7;
|
|
||||||
text-align: left;
|
|
||||||
word-break: break-word;
|
|
||||||
}
|
|
||||||
.md-body p { margin: 0.5em 0; }
|
|
||||||
.md-body h1, .md-body h2, .md-body h3,
|
|
||||||
.md-body h4, .md-body h5, .md-body h6 {
|
|
||||||
margin: 0.8em 0 0.4em;
|
|
||||||
font-weight: 600;
|
|
||||||
line-height: 1.4;
|
|
||||||
}
|
|
||||||
.md-body ul, .md-body ol { padding-left: 1.6em; margin: 0.5em 0; }
|
|
||||||
.md-body li { margin: 0.2em 0; }
|
|
||||||
.md-body blockquote {
|
|
||||||
border-left: 3px solid #d3d1c7;
|
|
||||||
margin: 0.6em 0;
|
|
||||||
padding: 0.2em 1em;
|
|
||||||
color: #5f5e5a;
|
|
||||||
}
|
|
||||||
.md-body pre {
|
|
||||||
background: #f5f5f5;
|
|
||||||
padding: 0.8em 1em;
|
|
||||||
border-radius: 6px;
|
|
||||||
overflow-x: auto;
|
|
||||||
margin: 0.6em 0;
|
|
||||||
}
|
|
||||||
.md-body code {
|
|
||||||
background: #f0f0f0;
|
|
||||||
padding: 0.1em 0.35em;
|
|
||||||
border-radius: 4px;
|
|
||||||
font-size: 0.9em;
|
|
||||||
}
|
|
||||||
.md-body pre code { background: none; padding: 0; }
|
|
||||||
.md-body img { max-width: 100%; height: auto; }
|
|
||||||
.md-body table { border-collapse: collapse; margin: 0.6em 0; }
|
|
||||||
.md-body th, .md-body td {
|
|
||||||
border: 1px solid #ddd;
|
|
||||||
padding: 0.4em 0.8em;
|
|
||||||
}
|
|
||||||
.md-body hr { margin: 1em 0; }
|
|
||||||
html[data-theme="dark"] .md-body blockquote {
|
|
||||||
border-color: #3a404c;
|
|
||||||
color: #8b93a1;
|
|
||||||
}
|
|
||||||
html[data-theme="dark"] .md-body pre,
|
|
||||||
html[data-theme="dark"] .md-body code { background: #2d323c; }
|
|
||||||
html[data-theme="dark"] .md-body th,
|
|
||||||
html[data-theme="dark"] .md-body td { border-color: #3a404c; }
|
|
||||||
|
|
||||||
/* 投票结果占比条:模板已改用 UIkit 3 原生 <progress class="uk-progress" value max>,
|
|
||||||
这里只把默认的 15px 高 / 500px 圆角 / 20px 外边距收紧到与页面一致的规格。
|
|
||||||
(原先为 UIkit 2 的 .uk-progressbar 结构打的补丁已删除) */
|
|
||||||
.uk-progress {
|
|
||||||
height: 10px;
|
|
||||||
margin: 0;
|
|
||||||
border-radius: var(--tb-radius-xs);
|
|
||||||
background-color: var(--tb-surface-2);
|
|
||||||
}
|
|
||||||
.uk-progress::-webkit-progress-bar {
|
|
||||||
background-color: var(--tb-surface-2);
|
|
||||||
border-radius: var(--tb-radius-xs);
|
|
||||||
}
|
|
||||||
.uk-progress::-webkit-progress-value {
|
|
||||||
background-color: var(--tb-primary);
|
|
||||||
border-radius: var(--tb-radius-xs) 0 0 var(--tb-radius-xs);
|
|
||||||
}
|
|
||||||
.uk-progress::-moz-progress-bar {
|
|
||||||
background-color: var(--tb-primary);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 移动端底部操作栏:固定底栏承载语言切换与深色模式,桌面端隐藏 */
|
|
||||||
#tb-mobile-utils {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
@media (max-width: 640px) {
|
|
||||||
/* 顶栏不再容纳语言/深色按钮,恢复原有导航空间 */
|
|
||||||
.tb-nav-utils {
|
|
||||||
display: none !important;
|
|
||||||
}
|
|
||||||
/* 手机端隐藏登录用户名(左边仅保留"探索"),保证 logo 居中、
|
|
||||||
两侧各不超过 2 个短按钮,避免用户名宽度挤压布局 */
|
|
||||||
.tb-nav-username {
|
|
||||||
display: none !important;
|
|
||||||
}
|
|
||||||
/* 固定底部操作栏 */
|
|
||||||
#tb-mobile-utils {
|
|
||||||
display: flex;
|
|
||||||
position: fixed;
|
|
||||||
left: 0;
|
|
||||||
right: 0;
|
|
||||||
bottom: 0;
|
|
||||||
z-index: 1000;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
gap: 10px;
|
|
||||||
padding: 8px 12px calc(8px + env(safe-area-inset-bottom));
|
|
||||||
background: rgba(255, 255, 255, 0.92);
|
|
||||||
-webkit-backdrop-filter: blur(8px);
|
|
||||||
backdrop-filter: blur(8px);
|
|
||||||
box-shadow: 0 -2px 12px rgba(0, 0, 0, 0.08);
|
|
||||||
}
|
|
||||||
#tb-mobile-utils .uk-select {
|
|
||||||
width: 110px;
|
|
||||||
}
|
|
||||||
html[data-theme="dark"] #tb-mobile-utils {
|
|
||||||
background: rgba(36, 40, 48, 0.92);
|
|
||||||
box-shadow: 0 -2px 12px rgba(0, 0, 0, 0.4);
|
|
||||||
}
|
|
||||||
/* 给页面底部预留空间,避免页脚内容被固定底栏遮挡 */
|
|
||||||
body {
|
|
||||||
padding-bottom: 56px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
||||||
<link rel="stylesheet" href="https://r2.337845818.best/tamabox/cdn/waline/client/v2/waline-no-commits.css" media="print" onload="this.media='all'"/>
|
<link rel="stylesheet" href="https://r2.337845818.best/tamabox/cdn/waline/client/v2/waline-no-commits.css" media="print" onload="this.media='all'"/>
|
||||||
<script defer src="https://cdnjs.cloudflare.com/ajax/libs/uikit/3.3.3/js/uikit.min.js"></script>
|
<script defer src="https://cdnjs.cloudflare.com/ajax/libs/uikit/3.3.3/js/uikit.min.js"></script>
|
||||||
@@ -1303,7 +636,7 @@ document.getElementById("introcolor").style.color = "#ffffff";
|
|||||||
href="/_/tester/1">查看回答</a>
|
href="/_/tester/1">查看回答</a>
|
||||||
<div class="uk-text-left uk-text-small uk-text-muted">
|
<div class="uk-text-left uk-text-small uk-text-muted">
|
||||||
<span class="tb-pin-flag" title="已置顶">⭐</span>
|
<span class="tb-pin-flag" title="已置顶">⭐</span>
|
||||||
2026-10-19 12:01:52
|
2026-10-19 15:15:39
|
||||||
</div>
|
</div>
|
||||||
<p class="uk-text-small uk-text-break tb-preline tb-clamp-5">置顶的问题
|
<p class="uk-text-small uk-text-break tb-preline tb-clamp-5">置顶的问题
|
||||||
</p>
|
</p>
|
||||||
@@ -1315,7 +648,7 @@ document.getElementById("introcolor").style.color = "#ffffff";
|
|||||||
href="/_/tester/2">查看回答</a>
|
href="/_/tester/2">查看回答</a>
|
||||||
<div class="uk-text-left uk-text-small uk-text-muted">
|
<div class="uk-text-left uk-text-small uk-text-muted">
|
||||||
|
|
||||||
2026-10-19 11:01:52
|
2026-10-19 14:15:39
|
||||||
</div>
|
</div>
|
||||||
<p class="uk-text-small uk-text-break tb-preline tb-clamp-5">普通问题
|
<p class="uk-text-small uk-text-break tb-preline tb-clamp-5">普通问题
|
||||||
</p>
|
</p>
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
<title>预览 12:01 · </title>
|
<title>预览 15:15 · </title>
|
||||||
<meta name="msvalidate.01" content="2F185E8E63C93635F50B3574F3B31E42" />
|
<meta name="msvalidate.01" content="2F185E8E63C93635F50B3574F3B31E42" />
|
||||||
<meta name="description" content="狼的提问箱——一个无需注册、可匿名提问的匿名提问箱,安全地倾诉与回应。">
|
<meta name="description" content="狼的提问箱——一个无需注册、可匿名提问的匿名提问箱,安全地倾诉与回应。">
|
||||||
<meta name="keywords" content="匿名提问箱,提问箱,匿名提问,狼的提问箱,匿名问答,匿名提问网站">
|
<meta name="keywords" content="匿名提问箱,提问箱,匿名提问,狼的提问箱,匿名问答,匿名提问网站">
|
||||||
@@ -20,675 +20,8 @@
|
|||||||
|
|
||||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/uikit/3.3.3/css/uikit.min.css"/>
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/uikit/3.3.3/css/uikit.min.css"/>
|
||||||
|
|
||||||
<style>/* TamaBox 全站基础样式:设计令牌 / 主题覆盖 / 组件质感 / 响应式。
|
<link rel="stylesheet" href="/static/css/base.css?v="/>
|
||||||
由 base/header.html 内联块抽出,集中一份便于缓存与维护。
|
|
||||||
⚠️ 改完务必把 header 里的 ?v= 版本号 +1,否则老访客仍用缓存。 */
|
|
||||||
|
|
||||||
/* 设计令牌:亮色为默认(:root),深色在 html[data-theme="dark"] 覆盖。
|
|
||||||
页面与组件样式一律引用 var(--tb-*),不再写死色值/圆角/阴影;
|
|
||||||
var() 的第二个参数仅作兜底(旧缓存页、邮件模板等不引入本文件的场景)。
|
|
||||||
改配色只动这一块,亮暗两套自动保持一致。 */
|
|
||||||
:root {
|
|
||||||
--tb-bg: #f7f8fa;
|
|
||||||
--tb-surface: #ffffff;
|
|
||||||
--tb-surface-2: #f4f6f8;
|
|
||||||
--tb-surface-hover: #f3f7ff;
|
|
||||||
--tb-border: #e8eaee;
|
|
||||||
--tb-text: #1f2329;
|
|
||||||
--tb-text-secondary: #5c6370;
|
|
||||||
--tb-text-muted: #8a919c;
|
|
||||||
--tb-primary: #1e87f0;
|
|
||||||
--tb-primary-weak: rgba(30, 135, 240, 0.10);
|
|
||||||
--tb-radius: 12px;
|
|
||||||
--tb-radius-sm: 8px;
|
|
||||||
--tb-radius-xs: 6px;
|
|
||||||
--tb-shadow: 0 1px 2px rgba(16, 24, 40, 0.04), 0 12px 28px -18px rgba(16, 24, 40, 0.20);
|
|
||||||
--tb-shadow-hover: 0 1px 2px rgba(16, 24, 40, 0.05), 0 18px 40px -20px rgba(16, 24, 40, 0.28);
|
|
||||||
--tb-font: system-ui, -apple-system, "Segoe UI", "PingFang SC", "Hiragino Sans GB", "Noto Sans CJK SC", "Microsoft YaHei", sans-serif;
|
|
||||||
}
|
|
||||||
html[data-theme="dark"] {
|
|
||||||
--tb-bg: #1a1d23;
|
|
||||||
--tb-surface: #242830;
|
|
||||||
--tb-surface-2: #2d323c;
|
|
||||||
--tb-surface-hover: rgba(92, 141, 255, 0.12);
|
|
||||||
--tb-border: #3a404c;
|
|
||||||
--tb-text: #d8dce4;
|
|
||||||
--tb-text-secondary: #a8b0bd;
|
|
||||||
--tb-text-muted: #8b93a1;
|
|
||||||
--tb-primary: #5c8dff;
|
|
||||||
--tb-primary-weak: rgba(92, 141, 255, 0.14);
|
|
||||||
--tb-shadow: 0 1px 2px rgba(0, 0, 0, 0.30), 0 12px 28px -18px rgba(0, 0, 0, 0.55);
|
|
||||||
--tb-shadow-hover: 0 1px 2px rgba(0, 0, 0, 0.35), 0 18px 40px -20px rgba(0, 0, 0, 0.65);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* UIkit 补丁:复刻原自建版 "modify-black-font"(官方版与自建版仅 3 处颜色差异——把有色容器内默认白字/白标题改为黑字)。
|
|
||||||
模板当前只用到 .uk-light 容器(用户背景封面,question/list.html、question-not-found.html;
|
|
||||||
其中 h3/p 已由 #usernamecolor/#introcolor 内联 style 覆盖),故只需补该容器的 3 处投影即可保持渲染一致。
|
|
||||||
若日后新增 .uk-card-primary/.uk-card-secondary/.uk-section-primary/.uk-tile-*/.uk-overlay-primary 等容器且需黑字,须同步扩展。 */
|
|
||||||
.uk-light { color: rgba(0,0,0,.7); }
|
|
||||||
.uk-light .uk-h1, .uk-light .uk-h2, .uk-light .uk-h3, .uk-light .uk-h4, .uk-light .uk-h5, .uk-light .uk-h6,
|
|
||||||
.uk-light .uk-heading-2xlarge, .uk-light .uk-heading-large, .uk-light .uk-heading-medium, .uk-light .uk-heading-small, .uk-light .uk-heading-xlarge,
|
|
||||||
.uk-light h1, .uk-light h2, .uk-light h3, .uk-light h4, .uk-light h5, .uk-light h6 { color: #000; }
|
|
||||||
.uk-light .uk-table th { color: rgba(0,0,0,.7); }
|
|
||||||
|
|
||||||
.grecaptcha-badge {visibility: hidden;}
|
|
||||||
.icon-container {
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
.icon {
|
|
||||||
margin-left: 10px;
|
|
||||||
width: 20px; /* 设置图标的宽度 */
|
|
||||||
height: auto; /* 保持图标的高度自动调整 */
|
|
||||||
}
|
|
||||||
.emoji-placeholder {
|
|
||||||
display: inline-block;
|
|
||||||
animation: jump 0.5s ease-in-out;
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes jump {
|
|
||||||
0%, 100% { transform: translateY(0); }
|
|
||||||
50% { transform: translateY(-5px); }
|
|
||||||
}
|
|
||||||
/* 防止 UIkit Dropbar 初始闪烁 */
|
|
||||||
.uk-dropbar {
|
|
||||||
opacity: 0;
|
|
||||||
visibility: hidden;
|
|
||||||
transition: opacity 0.2s ease, visibility 0.2s ease;
|
|
||||||
}
|
|
||||||
|
|
||||||
.uk-dropbar.uk-open {
|
|
||||||
opacity: 1;
|
|
||||||
visibility: visible;
|
|
||||||
}
|
|
||||||
|
|
||||||
a.uk-button.uk-button-link {
|
|
||||||
text-transform: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 移动端优化:缩小字体和间距,避免右侧空白 */
|
|
||||||
@media (max-width: 640px) {
|
|
||||||
.uk-logo {
|
|
||||||
font-size: 1rem;
|
|
||||||
}
|
|
||||||
.uk-navbar-nav a {
|
|
||||||
font-size: 0.78rem;
|
|
||||||
padding: 0 4px;
|
|
||||||
}
|
|
||||||
.emoji-placeholder {
|
|
||||||
font-size: 1rem;
|
|
||||||
}
|
|
||||||
/* 移动端用户名限宽省略,避免长英文用户名撑爆顶栏 */
|
|
||||||
.tb-nav-username {
|
|
||||||
max-width: 64px;
|
|
||||||
overflow: hidden;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
white-space: nowrap;
|
|
||||||
display: inline-block;
|
|
||||||
vertical-align: middle;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 深色模式:html[data-theme="dark"] 时覆盖 UIkit 3.3.3 编译主题的关键颜色 */
|
|
||||||
/* 变量(--tb-*)已上移到 head 顶部的令牌块,亮暗两套同名常量在那里定义。 */
|
|
||||||
/* 根元素与 body 一起覆盖,确保整个视口(含内容不足一屏时的空白区)都是深色背景 */
|
|
||||||
html[data-theme="dark"],
|
|
||||||
html[data-theme="dark"] body {
|
|
||||||
background-color: var(--tb-bg) !important;
|
|
||||||
color: var(--tb-text) !important;
|
|
||||||
}
|
|
||||||
/* 通用表面容器 */
|
|
||||||
html[data-theme="dark"] .uk-card,
|
|
||||||
html[data-theme="dark"] .uk-card-default,
|
|
||||||
html[data-theme="dark"] .uk-card-secondary,
|
|
||||||
html[data-theme="dark"] .uk-dropbar,
|
|
||||||
html[data-theme="dark"] .uk-navbar-dropdown,
|
|
||||||
html[data-theme="dark"] .uk-modal-dialog,
|
|
||||||
html[data-theme="dark"] .uk-dropdown,
|
|
||||||
html[data-theme="dark"] .uk-offcanvas-bar,
|
|
||||||
html[data-theme="dark"] .uk-section,
|
|
||||||
html[data-theme="dark"] .uk-tile,
|
|
||||||
html[data-theme="dark"] .uk-panel,
|
|
||||||
html[data-theme="dark"] .uk-background-default,
|
|
||||||
html[data-theme="dark"] .uk-search-default .uk-search-input {
|
|
||||||
background-color: var(--tb-surface) !important;
|
|
||||||
color: var(--tb-text) !important;
|
|
||||||
}
|
|
||||||
html[data-theme="dark"] .uk-navbar-container {
|
|
||||||
background-color: var(--tb-surface) !important;
|
|
||||||
color: var(--tb-text) !important;
|
|
||||||
}
|
|
||||||
html[data-theme="dark"] .uk-navbar-nav > li > a,
|
|
||||||
html[data-theme="dark"] .uk-card a,
|
|
||||||
html[data-theme="dark"] .uk-link,
|
|
||||||
html[data-theme="dark"] a.uk-button-link,
|
|
||||||
html[data-theme="dark"] .uk-navbar-dropdown-nav > li > a,
|
|
||||||
html[data-theme="dark"] .uk-dropdown-nav > li > a,
|
|
||||||
html[data-theme="dark"] .uk-list a {
|
|
||||||
color: var(--tb-text) !important;
|
|
||||||
}
|
|
||||||
html[data-theme="dark"] .uk-navbar-nav > li > a:hover,
|
|
||||||
html[data-theme="dark"] .uk-card a:hover,
|
|
||||||
html[data-theme="dark"] .uk-navbar-dropdown-nav > li > a:hover,
|
|
||||||
html[data-theme="dark"] .uk-dropdown-nav > li > a:hover {
|
|
||||||
color: var(--tb-primary) !important;
|
|
||||||
}
|
|
||||||
html[data-theme="dark"] .uk-input,
|
|
||||||
html[data-theme="dark"] .uk-textarea,
|
|
||||||
html[data-theme="dark"] .uk-select {
|
|
||||||
background-color: var(--tb-surface-2) !important;
|
|
||||||
color: var(--tb-text) !important;
|
|
||||||
border-color: var(--tb-border) !important;
|
|
||||||
}
|
|
||||||
html[data-theme="dark"] .uk-input:focus,
|
|
||||||
html[data-theme="dark"] .uk-textarea:focus,
|
|
||||||
html[data-theme="dark"] .uk-select:focus {
|
|
||||||
border-color: var(--tb-primary) !important;
|
|
||||||
}
|
|
||||||
html[data-theme="dark"] .uk-text-muted,
|
|
||||||
html[data-theme="dark"] .uk-text-meta,
|
|
||||||
html[data-theme="dark"] .uk-text-secondary,
|
|
||||||
html[data-theme="dark"] .uk-text-muted a,
|
|
||||||
html[data-theme="dark"] .uk-text-small.uk-text-muted {
|
|
||||||
color: var(--tb-text-muted) !important;
|
|
||||||
}
|
|
||||||
html[data-theme="dark"] .uk-divider-icon::after,
|
|
||||||
html[data-theme="dark"] hr,
|
|
||||||
html[data-theme="dark"] .uk-table th,
|
|
||||||
html[data-theme="dark"] .uk-table td,
|
|
||||||
html[data-theme="dark"] .uk-list-divider > li:nth-child(n+2) {
|
|
||||||
border-color: var(--tb-border) !important;
|
|
||||||
}
|
|
||||||
html[data-theme="dark"] .uk-button-default {
|
|
||||||
background-color: var(--tb-surface-2) !important;
|
|
||||||
color: var(--tb-text) !important;
|
|
||||||
border-color: var(--tb-border) !important;
|
|
||||||
}
|
|
||||||
html[data-theme="dark"] .uk-modal-title,
|
|
||||||
html[data-theme="dark"] h1, html[data-theme="dark"] h2, html[data-theme="dark"] h3,
|
|
||||||
html[data-theme="dark"] h4, html[data-theme="dark"] h5, html[data-theme="dark"] h6,
|
|
||||||
html[data-theme="dark"] .uk-card-title {
|
|
||||||
color: var(--tb-text) !important;
|
|
||||||
}
|
|
||||||
html[data-theme="dark"] .uk-alert-warning,
|
|
||||||
html[data-theme="dark"] .uk-alert-danger,
|
|
||||||
html[data-theme="dark"] .uk-alert-success,
|
|
||||||
html[data-theme="dark"] .uk-alert-primary {
|
|
||||||
background-color: var(--tb-surface-2) !important;
|
|
||||||
color: var(--tb-text) !important;
|
|
||||||
}
|
|
||||||
html[data-theme="dark"] #math-captcha-modal .uk-modal-dialog {
|
|
||||||
background-color: var(--tb-surface) !important;
|
|
||||||
color: var(--tb-text) !important;
|
|
||||||
}
|
|
||||||
html[data-theme="dark"] #math-captcha-modal .captcha-equation-box {
|
|
||||||
background-color: var(--tb-surface-2) !important;
|
|
||||||
border-color: var(--tb-border) !important;
|
|
||||||
}
|
|
||||||
html[data-theme="dark"] #math-captcha-modal .math-captcha-modal-question {
|
|
||||||
color: var(--tb-text) !important;
|
|
||||||
}
|
|
||||||
html[data-theme="dark"] #math-captcha-modal #captcha-modal-answer {
|
|
||||||
background-color: var(--tb-surface) !important;
|
|
||||||
color: var(--tb-text) !important;
|
|
||||||
border-color: var(--tb-border) !important;
|
|
||||||
}
|
|
||||||
html[data-theme="dark"] #math-captcha-modal #captcha-modal-answer::placeholder {
|
|
||||||
color: var(--tb-text-muted) !important;
|
|
||||||
}
|
|
||||||
html[data-theme="dark"] #math-captcha-modal .uk-text-meta,
|
|
||||||
html[data-theme="dark"] #math-captcha-modal #captcha-modal-refresh {
|
|
||||||
color: var(--tb-text-muted) !important;
|
|
||||||
}
|
|
||||||
html[data-theme="dark"] #math-captcha-modal #captcha-modal-refresh:hover {
|
|
||||||
color: var(--tb-primary) !important;
|
|
||||||
}
|
|
||||||
html[data-theme="dark"] .uk-label {
|
|
||||||
color: #fff !important;
|
|
||||||
}
|
|
||||||
/* 自定义组件(探索页推荐卡片等)深色覆盖 */
|
|
||||||
html[data-theme="dark"] .recommend-card,
|
|
||||||
html[data-theme="dark"] .recommend-card:hover {
|
|
||||||
background-color: var(--tb-surface-2) !important;
|
|
||||||
}
|
|
||||||
html[data-theme="dark"] .explore-name a {
|
|
||||||
color: var(--tb-text) !important;
|
|
||||||
}
|
|
||||||
html[data-theme="dark"] .explore-name a:hover {
|
|
||||||
color: var(--tb-primary) !important;
|
|
||||||
}
|
|
||||||
html[data-theme="dark"] .explore-intro {
|
|
||||||
color: var(--tb-text-muted) !important;
|
|
||||||
}
|
|
||||||
/* 切换按钮图标切换(内联 SVG,不依赖 UIkit 图标库) */
|
|
||||||
#theme-toggle .tb-icon-light, #theme-toggle-mobile .tb-icon-light,
|
|
||||||
#theme-toggle .tb-icon-dark, #theme-toggle-mobile .tb-icon-dark {
|
|
||||||
display: inline-flex;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
#theme-toggle .tb-icon-light svg, #theme-toggle-mobile .tb-icon-light svg,
|
|
||||||
#theme-toggle .tb-icon-dark svg, #theme-toggle-mobile .tb-icon-dark svg { display: block; }
|
|
||||||
#theme-toggle .tb-icon-dark, #theme-toggle-mobile .tb-icon-dark { display: none; }
|
|
||||||
html[data-theme="dark"] #theme-toggle .tb-icon-light,
|
|
||||||
html[data-theme="dark"] #theme-toggle-mobile .tb-icon-light { display: none; }
|
|
||||||
html[data-theme="dark"] #theme-toggle .tb-icon-dark,
|
|
||||||
html[data-theme="dark"] #theme-toggle-mobile .tb-icon-dark { display: inline-flex; }
|
|
||||||
|
|
||||||
/* 基础质感层:只调整外观(圆角/投影/字体/数字对齐),不改任何结构与布局。
|
|
||||||
颜色一律取自头部令牌,亮暗两套自动生效,因此这里不需要再写 html[data-theme="dark"] 分支。 */
|
|
||||||
/* 根元素与 body 同时上色:内容不足一屏时,body 之外的视口区域也要是同一底色 */
|
|
||||||
html,
|
|
||||||
body {
|
|
||||||
font-family: var(--tb-font);
|
|
||||||
background-color: var(--tb-bg);
|
|
||||||
color: var(--tb-text);
|
|
||||||
-webkit-font-smoothing: antialiased;
|
|
||||||
-moz-osx-font-smoothing: grayscale;
|
|
||||||
}
|
|
||||||
/* 卡片:12px 圆角 + 一层极淡接触影 + 一层大扩散影(UIkit 默认的 0 5px 15px 偏硬) */
|
|
||||||
.uk-card {
|
|
||||||
border-radius: var(--tb-radius);
|
|
||||||
}
|
|
||||||
.uk-card-default {
|
|
||||||
background-color: var(--tb-surface);
|
|
||||||
box-shadow: var(--tb-shadow);
|
|
||||||
}
|
|
||||||
.uk-card-default.uk-card-hover:hover {
|
|
||||||
box-shadow: var(--tb-shadow-hover);
|
|
||||||
}
|
|
||||||
.uk-card-header {
|
|
||||||
border-radius: var(--tb-radius) var(--tb-radius) 0 0;
|
|
||||||
}
|
|
||||||
.uk-card-footer {
|
|
||||||
border-radius: 0 0 var(--tb-radius) var(--tb-radius);
|
|
||||||
}
|
|
||||||
.uk-card,
|
|
||||||
.uk-button,
|
|
||||||
.uk-alert,
|
|
||||||
.uk-label {
|
|
||||||
transition: box-shadow 0.18s ease, background-color 0.18s ease, border-color 0.18s ease, color 0.18s ease;
|
|
||||||
}
|
|
||||||
/* 交互元素:统一 8px 圆角,标签 6px */
|
|
||||||
.uk-button {
|
|
||||||
border-radius: var(--tb-radius-sm);
|
|
||||||
}
|
|
||||||
.uk-input,
|
|
||||||
.uk-select,
|
|
||||||
.uk-textarea,
|
|
||||||
.uk-form-small,
|
|
||||||
.uk-search-input {
|
|
||||||
border-radius: var(--tb-radius-sm);
|
|
||||||
}
|
|
||||||
.uk-label {
|
|
||||||
border-radius: var(--tb-radius-xs);
|
|
||||||
}
|
|
||||||
.uk-alert {
|
|
||||||
border-radius: 10px;
|
|
||||||
}
|
|
||||||
.uk-modal-dialog {
|
|
||||||
border-radius: 14px;
|
|
||||||
}
|
|
||||||
.uk-dropdown,
|
|
||||||
.uk-navbar-dropdown {
|
|
||||||
border-radius: 10px;
|
|
||||||
box-shadow: var(--tb-shadow);
|
|
||||||
}
|
|
||||||
.uk-navbar-container:not(.uk-navbar-transparent) {
|
|
||||||
background-color: var(--tb-surface);
|
|
||||||
}
|
|
||||||
/* 键盘可达性:仅在键盘聚焦时出现描边,鼠标点击不出现 */
|
|
||||||
.uk-button:focus-visible,
|
|
||||||
.uk-navbar-nav > li > a:focus-visible {
|
|
||||||
outline: 2px solid var(--tb-primary);
|
|
||||||
outline-offset: 2px;
|
|
||||||
}
|
|
||||||
/* 次要文字统一走令牌,避免 #999 / #8a919c 混用 */
|
|
||||||
.uk-text-muted,
|
|
||||||
.uk-text-meta {
|
|
||||||
color: var(--tb-text-muted);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 轻量胶囊:用于投票类型、热门标签等「只是分类信息」的位置。
|
|
||||||
实心 uk-label 一屏多个会变成一排色块,这里统一降级为浅底 + 次要色文字。 */
|
|
||||||
.tb-chip {
|
|
||||||
display: inline-block;
|
|
||||||
padding: 1px 8px;
|
|
||||||
border-radius: var(--tb-radius-xs);
|
|
||||||
background-color: var(--tb-surface-2);
|
|
||||||
color: var(--tb-text-secondary);
|
|
||||||
font-size: 0.72rem;
|
|
||||||
line-height: 1.7;
|
|
||||||
white-space: nowrap;
|
|
||||||
}
|
|
||||||
a.tb-chip:hover {
|
|
||||||
background-color: var(--tb-primary-weak);
|
|
||||||
color: var(--tb-primary);
|
|
||||||
text-decoration: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 统计/日期等数字列等宽对齐,避免刷新时左右跳动 */
|
|
||||||
.uk-table,
|
|
||||||
.tb-num {
|
|
||||||
font-variant-numeric: tabular-nums;
|
|
||||||
}
|
|
||||||
/* 图片上传条:原为 item/new-question 两处各写一份内联 style(写死 #f8f8f8,深色下露白),
|
|
||||||
收敛到一处并走令牌,亮暗自动适配 */
|
|
||||||
.tb-img-uploader {
|
|
||||||
width: 100%;
|
|
||||||
background-color: var(--tb-surface-2);
|
|
||||||
display: flex;
|
|
||||||
padding-top: 5px;
|
|
||||||
padding-bottom: 5px;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: flex-start;
|
|
||||||
gap: 5px;
|
|
||||||
}
|
|
||||||
/* 背景图封面(提问箱主页):渐变遮罩,保证用户自选文字色叠加后仍可读。
|
|
||||||
默认浅色遮罩(页面 .uk-light 补丁把文字兜底成深色);若箱主选了浅色文字,
|
|
||||||
question/list.html 会按亮度加上 .tb-cover-dark 换成深色遮罩。 */
|
|
||||||
.tb-cover {
|
|
||||||
position: relative;
|
|
||||||
border-radius: var(--tb-radius) var(--tb-radius) 0 0;
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
/* ⚠️ 必须带 .uk-flex 复合选择器:UIkit 3.3.3 里有
|
|
||||||
.uk-flex::after,.uk-flex::before{display:none}(优先级 0,2,0),
|
|
||||||
会把这个遮罩伪元素整个干掉——不报错、只是什么都不显示(踩过一次)。
|
|
||||||
单写 .tb-cover::after 优先级不够,会被它压回 display:none。 */
|
|
||||||
.tb-cover::after,
|
|
||||||
.tb-cover.uk-flex::after {
|
|
||||||
content: "";
|
|
||||||
display: block;
|
|
||||||
position: absolute;
|
|
||||||
inset: 0;
|
|
||||||
z-index: 0;
|
|
||||||
background: linear-gradient(180deg, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.58) 55%, rgba(255, 255, 255, 0.84) 100%);
|
|
||||||
pointer-events: none;
|
|
||||||
}
|
|
||||||
.tb-cover.tb-cover-dark::after {
|
|
||||||
background: linear-gradient(180deg, rgba(0, 0, 0, 0) 0%, rgba(0, 0, 0, 0.16) 45%, rgba(0, 0, 0, 0.46) 100%);
|
|
||||||
}
|
|
||||||
.tb-cover > * {
|
|
||||||
position: relative;
|
|
||||||
z-index: 1;
|
|
||||||
}
|
|
||||||
.tb-cover h3,
|
|
||||||
.tb-cover p {
|
|
||||||
text-shadow: 0 1px 10px rgba(255, 255, 255, 0.65);
|
|
||||||
}
|
|
||||||
.tb-cover.tb-cover-dark h3,
|
|
||||||
.tb-cover.tb-cover-dark p {
|
|
||||||
text-shadow: 0 1px 12px rgba(0, 0, 0, 0.45);
|
|
||||||
}
|
|
||||||
/* 尊重系统的减少动效设置 */
|
|
||||||
@media (prefers-reduced-motion: reduce) {
|
|
||||||
.uk-card,
|
|
||||||
.uk-button,
|
|
||||||
.emoji-placeholder {
|
|
||||||
transition: none;
|
|
||||||
animation: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 顶栏自适应:导航全部直接显示,窄屏时分级缩小字号/间距,保证英文/日文等长文字不溢出 */
|
|
||||||
.uk-navbar-nav a {
|
|
||||||
font-size: 0.95rem;
|
|
||||||
padding: 0 10px;
|
|
||||||
}
|
|
||||||
/* 未登录移动端占位:桌面端隐藏,仅 ≤640px 显示(见下方 media 查询)。
|
|
||||||
桌面端布局与改动前完全一致,不受影响。 */
|
|
||||||
.tb-mobile-balancer { display: none; }
|
|
||||||
/* 桌面端保持 UIkit 原生居中三列布局(无需额外 CSS) */
|
|
||||||
.tb-navbar .uk-logo {
|
|
||||||
white-space: nowrap;
|
|
||||||
}
|
|
||||||
@media (max-width: 1200px) {
|
|
||||||
.uk-navbar-nav a {
|
|
||||||
font-size: 0.88rem;
|
|
||||||
padding: 0 8px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@media (max-width: 1000px) {
|
|
||||||
.uk-navbar-nav a {
|
|
||||||
font-size: 0.82rem;
|
|
||||||
padding: 0 6px;
|
|
||||||
}
|
|
||||||
.uk-logo {
|
|
||||||
font-size: 1.1rem;
|
|
||||||
}
|
|
||||||
/* 登录用户名限宽,过长省略号截断 */
|
|
||||||
.tb-nav-username {
|
|
||||||
max-width: 110px;
|
|
||||||
overflow: hidden;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
white-space: nowrap;
|
|
||||||
display: inline-block;
|
|
||||||
vertical-align: middle;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@media (max-width: 800px) {
|
|
||||||
.uk-navbar-nav a {
|
|
||||||
font-size: 0.78rem;
|
|
||||||
padding: 0 4px;
|
|
||||||
}
|
|
||||||
.uk-logo {
|
|
||||||
font-size: 1rem;
|
|
||||||
}
|
|
||||||
.tb-nav-username {
|
|
||||||
max-width: 80px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* 手机端(≤640px):沿用 UIkit 桌面端 navbar 的原生三列定位。
|
|
||||||
不再重写 .uk-navbar-center / center-left / center-right 的定位,
|
|
||||||
避免 logo 被挤到下一行;底部语言与深色模式按钮仍由下方独立栏承载。 */
|
|
||||||
@media (max-width: 640px) {
|
|
||||||
.tb-navbar {
|
|
||||||
position: relative;
|
|
||||||
min-height: 56px;
|
|
||||||
overflow: visible;
|
|
||||||
}
|
|
||||||
.tb-navbar > .uk-navbar-center {
|
|
||||||
position: relative !important;
|
|
||||||
top: auto !important;
|
|
||||||
left: auto !important;
|
|
||||||
right: auto !important;
|
|
||||||
bottom: auto !important;
|
|
||||||
transform: none !important;
|
|
||||||
display: flex !important;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
width: 100%;
|
|
||||||
min-height: 56px;
|
|
||||||
white-space: nowrap;
|
|
||||||
flex-wrap: nowrap;
|
|
||||||
}
|
|
||||||
.tb-navbar .uk-navbar-center-left,
|
|
||||||
.tb-navbar .uk-navbar-center-right {
|
|
||||||
position: static !important;
|
|
||||||
top: auto !important;
|
|
||||||
left: auto !important;
|
|
||||||
right: auto !important;
|
|
||||||
bottom: auto !important;
|
|
||||||
transform: none !important;
|
|
||||||
display: flex !important;
|
|
||||||
align-items: center;
|
|
||||||
flex: 0 0 auto;
|
|
||||||
white-space: nowrap;
|
|
||||||
}
|
|
||||||
.tb-navbar .uk-navbar-center-left > div,
|
|
||||||
.tb-navbar .uk-navbar-center-right > div {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
white-space: nowrap;
|
|
||||||
}
|
|
||||||
.tb-navbar .uk-navbar-nav {
|
|
||||||
display: flex;
|
|
||||||
flex-wrap: nowrap;
|
|
||||||
flex: 0 0 auto;
|
|
||||||
}
|
|
||||||
.tb-navbar .uk-navbar-nav > li > a,
|
|
||||||
.tb-navbar .uk-logo {
|
|
||||||
white-space: nowrap;
|
|
||||||
}
|
|
||||||
/* 未登录:移动端显示与「我的」等宽的隐藏占位,使左栏「探索+占位」与
|
|
||||||
右栏「注册/登录」两项等宽,logo 真正居中,左右视觉平衡 */
|
|
||||||
.tb-mobile-balancer { display: block; }
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 标签样式的按钮(管理页置顶等):
|
|
||||||
尺寸完全继承 .uk-label(font-size/padding/line-height/text-transform 等),
|
|
||||||
仅覆盖 button 元素特有的默认样式(边框/字体族/光标等),保证与相邻 span 标签完全一致。 */
|
|
||||||
.tb-label-btn {
|
|
||||||
border: none !important;
|
|
||||||
cursor: pointer;
|
|
||||||
font-family: inherit;
|
|
||||||
margin: 0;
|
|
||||||
vertical-align: middle;
|
|
||||||
outline: none;
|
|
||||||
background-image: none;
|
|
||||||
box-sizing: border-box;
|
|
||||||
-webkit-appearance: none;
|
|
||||||
appearance: none;
|
|
||||||
}
|
|
||||||
.tb-label-btn:hover {
|
|
||||||
opacity: 0.85;
|
|
||||||
}
|
|
||||||
/* 公开页置顶小图标:仅一个图钉,不占行高、不影响原布局 */
|
|
||||||
.tb-pin-flag {
|
|
||||||
font-size: 0.9em;
|
|
||||||
margin-right: 4px;
|
|
||||||
vertical-align: -1px;
|
|
||||||
cursor: default;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Markdown 渲染排版(问题/回答/追问正文,左对齐以保留排版格式) */
|
|
||||||
/* 纯文本列表:保留换行与连续空格(pre-wrap),不渲染 Markdown 大字号/彩色 */
|
|
||||||
.tb-preline {
|
|
||||||
white-space: pre-wrap;
|
|
||||||
}
|
|
||||||
/* 纯文本列表:超过 5 行截断并显示省略号(不足 5 行则完整显示) */
|
|
||||||
.tb-clamp-5 {
|
|
||||||
display: -webkit-box;
|
|
||||||
-webkit-box-orient: vertical;
|
|
||||||
-webkit-line-clamp: 5;
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
.md-body {
|
|
||||||
line-height: 1.7;
|
|
||||||
text-align: left;
|
|
||||||
word-break: break-word;
|
|
||||||
}
|
|
||||||
.md-body p { margin: 0.5em 0; }
|
|
||||||
.md-body h1, .md-body h2, .md-body h3,
|
|
||||||
.md-body h4, .md-body h5, .md-body h6 {
|
|
||||||
margin: 0.8em 0 0.4em;
|
|
||||||
font-weight: 600;
|
|
||||||
line-height: 1.4;
|
|
||||||
}
|
|
||||||
.md-body ul, .md-body ol { padding-left: 1.6em; margin: 0.5em 0; }
|
|
||||||
.md-body li { margin: 0.2em 0; }
|
|
||||||
.md-body blockquote {
|
|
||||||
border-left: 3px solid #d3d1c7;
|
|
||||||
margin: 0.6em 0;
|
|
||||||
padding: 0.2em 1em;
|
|
||||||
color: #5f5e5a;
|
|
||||||
}
|
|
||||||
.md-body pre {
|
|
||||||
background: #f5f5f5;
|
|
||||||
padding: 0.8em 1em;
|
|
||||||
border-radius: 6px;
|
|
||||||
overflow-x: auto;
|
|
||||||
margin: 0.6em 0;
|
|
||||||
}
|
|
||||||
.md-body code {
|
|
||||||
background: #f0f0f0;
|
|
||||||
padding: 0.1em 0.35em;
|
|
||||||
border-radius: 4px;
|
|
||||||
font-size: 0.9em;
|
|
||||||
}
|
|
||||||
.md-body pre code { background: none; padding: 0; }
|
|
||||||
.md-body img { max-width: 100%; height: auto; }
|
|
||||||
.md-body table { border-collapse: collapse; margin: 0.6em 0; }
|
|
||||||
.md-body th, .md-body td {
|
|
||||||
border: 1px solid #ddd;
|
|
||||||
padding: 0.4em 0.8em;
|
|
||||||
}
|
|
||||||
.md-body hr { margin: 1em 0; }
|
|
||||||
html[data-theme="dark"] .md-body blockquote {
|
|
||||||
border-color: #3a404c;
|
|
||||||
color: #8b93a1;
|
|
||||||
}
|
|
||||||
html[data-theme="dark"] .md-body pre,
|
|
||||||
html[data-theme="dark"] .md-body code { background: #2d323c; }
|
|
||||||
html[data-theme="dark"] .md-body th,
|
|
||||||
html[data-theme="dark"] .md-body td { border-color: #3a404c; }
|
|
||||||
|
|
||||||
/* 投票结果占比条:模板已改用 UIkit 3 原生 <progress class="uk-progress" value max>,
|
|
||||||
这里只把默认的 15px 高 / 500px 圆角 / 20px 外边距收紧到与页面一致的规格。
|
|
||||||
(原先为 UIkit 2 的 .uk-progressbar 结构打的补丁已删除) */
|
|
||||||
.uk-progress {
|
|
||||||
height: 10px;
|
|
||||||
margin: 0;
|
|
||||||
border-radius: var(--tb-radius-xs);
|
|
||||||
background-color: var(--tb-surface-2);
|
|
||||||
}
|
|
||||||
.uk-progress::-webkit-progress-bar {
|
|
||||||
background-color: var(--tb-surface-2);
|
|
||||||
border-radius: var(--tb-radius-xs);
|
|
||||||
}
|
|
||||||
.uk-progress::-webkit-progress-value {
|
|
||||||
background-color: var(--tb-primary);
|
|
||||||
border-radius: var(--tb-radius-xs) 0 0 var(--tb-radius-xs);
|
|
||||||
}
|
|
||||||
.uk-progress::-moz-progress-bar {
|
|
||||||
background-color: var(--tb-primary);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 移动端底部操作栏:固定底栏承载语言切换与深色模式,桌面端隐藏 */
|
|
||||||
#tb-mobile-utils {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
@media (max-width: 640px) {
|
|
||||||
/* 顶栏不再容纳语言/深色按钮,恢复原有导航空间 */
|
|
||||||
.tb-nav-utils {
|
|
||||||
display: none !important;
|
|
||||||
}
|
|
||||||
/* 手机端隐藏登录用户名(左边仅保留"探索"),保证 logo 居中、
|
|
||||||
两侧各不超过 2 个短按钮,避免用户名宽度挤压布局 */
|
|
||||||
.tb-nav-username {
|
|
||||||
display: none !important;
|
|
||||||
}
|
|
||||||
/* 固定底部操作栏 */
|
|
||||||
#tb-mobile-utils {
|
|
||||||
display: flex;
|
|
||||||
position: fixed;
|
|
||||||
left: 0;
|
|
||||||
right: 0;
|
|
||||||
bottom: 0;
|
|
||||||
z-index: 1000;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
gap: 10px;
|
|
||||||
padding: 8px 12px calc(8px + env(safe-area-inset-bottom));
|
|
||||||
background: rgba(255, 255, 255, 0.92);
|
|
||||||
-webkit-backdrop-filter: blur(8px);
|
|
||||||
backdrop-filter: blur(8px);
|
|
||||||
box-shadow: 0 -2px 12px rgba(0, 0, 0, 0.08);
|
|
||||||
}
|
|
||||||
#tb-mobile-utils .uk-select {
|
|
||||||
width: 110px;
|
|
||||||
}
|
|
||||||
html[data-theme="dark"] #tb-mobile-utils {
|
|
||||||
background: rgba(36, 40, 48, 0.92);
|
|
||||||
box-shadow: 0 -2px 12px rgba(0, 0, 0, 0.4);
|
|
||||||
}
|
|
||||||
/* 给页面底部预留空间,避免页脚内容被固定底栏遮挡 */
|
|
||||||
body {
|
|
||||||
padding-bottom: 56px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
||||||
<link rel="stylesheet" href="https://r2.337845818.best/tamabox/cdn/waline/client/v2/waline-no-commits.css" media="print" onload="this.media='all'"/>
|
<link rel="stylesheet" href="https://r2.337845818.best/tamabox/cdn/waline/client/v2/waline-no-commits.css" media="print" onload="this.media='all'"/>
|
||||||
<script defer src="https://cdnjs.cloudflare.com/ajax/libs/uikit/3.3.3/js/uikit.min.js"></script>
|
<script defer src="https://cdnjs.cloudflare.com/ajax/libs/uikit/3.3.3/js/uikit.min.js"></script>
|
||||||
@@ -1303,7 +636,7 @@ document.getElementById("introcolor").style.color = "#ffffff";
|
|||||||
href="/_/tester/1">查看回答</a>
|
href="/_/tester/1">查看回答</a>
|
||||||
<div class="uk-text-left uk-text-small uk-text-muted">
|
<div class="uk-text-left uk-text-small uk-text-muted">
|
||||||
<span class="tb-pin-flag" title="已置顶">⭐</span>
|
<span class="tb-pin-flag" title="已置顶">⭐</span>
|
||||||
2026-10-19 12:01:52
|
2026-10-19 15:15:39
|
||||||
</div>
|
</div>
|
||||||
<p class="uk-text-small uk-text-break tb-preline tb-clamp-5">置顶的问题
|
<p class="uk-text-small uk-text-break tb-preline tb-clamp-5">置顶的问题
|
||||||
</p>
|
</p>
|
||||||
@@ -1315,7 +648,7 @@ document.getElementById("introcolor").style.color = "#ffffff";
|
|||||||
href="/_/tester/2">查看回答</a>
|
href="/_/tester/2">查看回答</a>
|
||||||
<div class="uk-text-left uk-text-small uk-text-muted">
|
<div class="uk-text-left uk-text-small uk-text-muted">
|
||||||
|
|
||||||
2026-10-19 11:01:52
|
2026-10-19 14:15:39
|
||||||
</div>
|
</div>
|
||||||
<p class="uk-text-small uk-text-break tb-preline tb-clamp-5">普通问题
|
<p class="uk-text-small uk-text-break tb-preline tb-clamp-5">普通问题
|
||||||
</p>
|
</p>
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
<title>预览 12:01 · 投票</title>
|
<title>预览 15:15 · 投票</title>
|
||||||
<meta name="msvalidate.01" content="2F185E8E63C93635F50B3574F3B31E42" />
|
<meta name="msvalidate.01" content="2F185E8E63C93635F50B3574F3B31E42" />
|
||||||
<meta name="description" content="狼的提问箱——一个无需注册、可匿名提问的匿名提问箱,安全地倾诉与回应。">
|
<meta name="description" content="狼的提问箱——一个无需注册、可匿名提问的匿名提问箱,安全地倾诉与回应。">
|
||||||
<meta name="keywords" content="匿名提问箱,提问箱,匿名提问,狼的提问箱,匿名问答,匿名提问网站">
|
<meta name="keywords" content="匿名提问箱,提问箱,匿名提问,狼的提问箱,匿名问答,匿名提问网站">
|
||||||
@@ -20,675 +20,8 @@
|
|||||||
|
|
||||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/uikit/3.3.3/css/uikit.min.css"/>
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/uikit/3.3.3/css/uikit.min.css"/>
|
||||||
|
|
||||||
<style>/* TamaBox 全站基础样式:设计令牌 / 主题覆盖 / 组件质感 / 响应式。
|
<link rel="stylesheet" href="/static/css/base.css?v="/>
|
||||||
由 base/header.html 内联块抽出,集中一份便于缓存与维护。
|
|
||||||
⚠️ 改完务必把 header 里的 ?v= 版本号 +1,否则老访客仍用缓存。 */
|
|
||||||
|
|
||||||
/* 设计令牌:亮色为默认(:root),深色在 html[data-theme="dark"] 覆盖。
|
|
||||||
页面与组件样式一律引用 var(--tb-*),不再写死色值/圆角/阴影;
|
|
||||||
var() 的第二个参数仅作兜底(旧缓存页、邮件模板等不引入本文件的场景)。
|
|
||||||
改配色只动这一块,亮暗两套自动保持一致。 */
|
|
||||||
:root {
|
|
||||||
--tb-bg: #f7f8fa;
|
|
||||||
--tb-surface: #ffffff;
|
|
||||||
--tb-surface-2: #f4f6f8;
|
|
||||||
--tb-surface-hover: #f3f7ff;
|
|
||||||
--tb-border: #e8eaee;
|
|
||||||
--tb-text: #1f2329;
|
|
||||||
--tb-text-secondary: #5c6370;
|
|
||||||
--tb-text-muted: #8a919c;
|
|
||||||
--tb-primary: #1e87f0;
|
|
||||||
--tb-primary-weak: rgba(30, 135, 240, 0.10);
|
|
||||||
--tb-radius: 12px;
|
|
||||||
--tb-radius-sm: 8px;
|
|
||||||
--tb-radius-xs: 6px;
|
|
||||||
--tb-shadow: 0 1px 2px rgba(16, 24, 40, 0.04), 0 12px 28px -18px rgba(16, 24, 40, 0.20);
|
|
||||||
--tb-shadow-hover: 0 1px 2px rgba(16, 24, 40, 0.05), 0 18px 40px -20px rgba(16, 24, 40, 0.28);
|
|
||||||
--tb-font: system-ui, -apple-system, "Segoe UI", "PingFang SC", "Hiragino Sans GB", "Noto Sans CJK SC", "Microsoft YaHei", sans-serif;
|
|
||||||
}
|
|
||||||
html[data-theme="dark"] {
|
|
||||||
--tb-bg: #1a1d23;
|
|
||||||
--tb-surface: #242830;
|
|
||||||
--tb-surface-2: #2d323c;
|
|
||||||
--tb-surface-hover: rgba(92, 141, 255, 0.12);
|
|
||||||
--tb-border: #3a404c;
|
|
||||||
--tb-text: #d8dce4;
|
|
||||||
--tb-text-secondary: #a8b0bd;
|
|
||||||
--tb-text-muted: #8b93a1;
|
|
||||||
--tb-primary: #5c8dff;
|
|
||||||
--tb-primary-weak: rgba(92, 141, 255, 0.14);
|
|
||||||
--tb-shadow: 0 1px 2px rgba(0, 0, 0, 0.30), 0 12px 28px -18px rgba(0, 0, 0, 0.55);
|
|
||||||
--tb-shadow-hover: 0 1px 2px rgba(0, 0, 0, 0.35), 0 18px 40px -20px rgba(0, 0, 0, 0.65);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* UIkit 补丁:复刻原自建版 "modify-black-font"(官方版与自建版仅 3 处颜色差异——把有色容器内默认白字/白标题改为黑字)。
|
|
||||||
模板当前只用到 .uk-light 容器(用户背景封面,question/list.html、question-not-found.html;
|
|
||||||
其中 h3/p 已由 #usernamecolor/#introcolor 内联 style 覆盖),故只需补该容器的 3 处投影即可保持渲染一致。
|
|
||||||
若日后新增 .uk-card-primary/.uk-card-secondary/.uk-section-primary/.uk-tile-*/.uk-overlay-primary 等容器且需黑字,须同步扩展。 */
|
|
||||||
.uk-light { color: rgba(0,0,0,.7); }
|
|
||||||
.uk-light .uk-h1, .uk-light .uk-h2, .uk-light .uk-h3, .uk-light .uk-h4, .uk-light .uk-h5, .uk-light .uk-h6,
|
|
||||||
.uk-light .uk-heading-2xlarge, .uk-light .uk-heading-large, .uk-light .uk-heading-medium, .uk-light .uk-heading-small, .uk-light .uk-heading-xlarge,
|
|
||||||
.uk-light h1, .uk-light h2, .uk-light h3, .uk-light h4, .uk-light h5, .uk-light h6 { color: #000; }
|
|
||||||
.uk-light .uk-table th { color: rgba(0,0,0,.7); }
|
|
||||||
|
|
||||||
.grecaptcha-badge {visibility: hidden;}
|
|
||||||
.icon-container {
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
.icon {
|
|
||||||
margin-left: 10px;
|
|
||||||
width: 20px; /* 设置图标的宽度 */
|
|
||||||
height: auto; /* 保持图标的高度自动调整 */
|
|
||||||
}
|
|
||||||
.emoji-placeholder {
|
|
||||||
display: inline-block;
|
|
||||||
animation: jump 0.5s ease-in-out;
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes jump {
|
|
||||||
0%, 100% { transform: translateY(0); }
|
|
||||||
50% { transform: translateY(-5px); }
|
|
||||||
}
|
|
||||||
/* 防止 UIkit Dropbar 初始闪烁 */
|
|
||||||
.uk-dropbar {
|
|
||||||
opacity: 0;
|
|
||||||
visibility: hidden;
|
|
||||||
transition: opacity 0.2s ease, visibility 0.2s ease;
|
|
||||||
}
|
|
||||||
|
|
||||||
.uk-dropbar.uk-open {
|
|
||||||
opacity: 1;
|
|
||||||
visibility: visible;
|
|
||||||
}
|
|
||||||
|
|
||||||
a.uk-button.uk-button-link {
|
|
||||||
text-transform: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 移动端优化:缩小字体和间距,避免右侧空白 */
|
|
||||||
@media (max-width: 640px) {
|
|
||||||
.uk-logo {
|
|
||||||
font-size: 1rem;
|
|
||||||
}
|
|
||||||
.uk-navbar-nav a {
|
|
||||||
font-size: 0.78rem;
|
|
||||||
padding: 0 4px;
|
|
||||||
}
|
|
||||||
.emoji-placeholder {
|
|
||||||
font-size: 1rem;
|
|
||||||
}
|
|
||||||
/* 移动端用户名限宽省略,避免长英文用户名撑爆顶栏 */
|
|
||||||
.tb-nav-username {
|
|
||||||
max-width: 64px;
|
|
||||||
overflow: hidden;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
white-space: nowrap;
|
|
||||||
display: inline-block;
|
|
||||||
vertical-align: middle;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 深色模式:html[data-theme="dark"] 时覆盖 UIkit 3.3.3 编译主题的关键颜色 */
|
|
||||||
/* 变量(--tb-*)已上移到 head 顶部的令牌块,亮暗两套同名常量在那里定义。 */
|
|
||||||
/* 根元素与 body 一起覆盖,确保整个视口(含内容不足一屏时的空白区)都是深色背景 */
|
|
||||||
html[data-theme="dark"],
|
|
||||||
html[data-theme="dark"] body {
|
|
||||||
background-color: var(--tb-bg) !important;
|
|
||||||
color: var(--tb-text) !important;
|
|
||||||
}
|
|
||||||
/* 通用表面容器 */
|
|
||||||
html[data-theme="dark"] .uk-card,
|
|
||||||
html[data-theme="dark"] .uk-card-default,
|
|
||||||
html[data-theme="dark"] .uk-card-secondary,
|
|
||||||
html[data-theme="dark"] .uk-dropbar,
|
|
||||||
html[data-theme="dark"] .uk-navbar-dropdown,
|
|
||||||
html[data-theme="dark"] .uk-modal-dialog,
|
|
||||||
html[data-theme="dark"] .uk-dropdown,
|
|
||||||
html[data-theme="dark"] .uk-offcanvas-bar,
|
|
||||||
html[data-theme="dark"] .uk-section,
|
|
||||||
html[data-theme="dark"] .uk-tile,
|
|
||||||
html[data-theme="dark"] .uk-panel,
|
|
||||||
html[data-theme="dark"] .uk-background-default,
|
|
||||||
html[data-theme="dark"] .uk-search-default .uk-search-input {
|
|
||||||
background-color: var(--tb-surface) !important;
|
|
||||||
color: var(--tb-text) !important;
|
|
||||||
}
|
|
||||||
html[data-theme="dark"] .uk-navbar-container {
|
|
||||||
background-color: var(--tb-surface) !important;
|
|
||||||
color: var(--tb-text) !important;
|
|
||||||
}
|
|
||||||
html[data-theme="dark"] .uk-navbar-nav > li > a,
|
|
||||||
html[data-theme="dark"] .uk-card a,
|
|
||||||
html[data-theme="dark"] .uk-link,
|
|
||||||
html[data-theme="dark"] a.uk-button-link,
|
|
||||||
html[data-theme="dark"] .uk-navbar-dropdown-nav > li > a,
|
|
||||||
html[data-theme="dark"] .uk-dropdown-nav > li > a,
|
|
||||||
html[data-theme="dark"] .uk-list a {
|
|
||||||
color: var(--tb-text) !important;
|
|
||||||
}
|
|
||||||
html[data-theme="dark"] .uk-navbar-nav > li > a:hover,
|
|
||||||
html[data-theme="dark"] .uk-card a:hover,
|
|
||||||
html[data-theme="dark"] .uk-navbar-dropdown-nav > li > a:hover,
|
|
||||||
html[data-theme="dark"] .uk-dropdown-nav > li > a:hover {
|
|
||||||
color: var(--tb-primary) !important;
|
|
||||||
}
|
|
||||||
html[data-theme="dark"] .uk-input,
|
|
||||||
html[data-theme="dark"] .uk-textarea,
|
|
||||||
html[data-theme="dark"] .uk-select {
|
|
||||||
background-color: var(--tb-surface-2) !important;
|
|
||||||
color: var(--tb-text) !important;
|
|
||||||
border-color: var(--tb-border) !important;
|
|
||||||
}
|
|
||||||
html[data-theme="dark"] .uk-input:focus,
|
|
||||||
html[data-theme="dark"] .uk-textarea:focus,
|
|
||||||
html[data-theme="dark"] .uk-select:focus {
|
|
||||||
border-color: var(--tb-primary) !important;
|
|
||||||
}
|
|
||||||
html[data-theme="dark"] .uk-text-muted,
|
|
||||||
html[data-theme="dark"] .uk-text-meta,
|
|
||||||
html[data-theme="dark"] .uk-text-secondary,
|
|
||||||
html[data-theme="dark"] .uk-text-muted a,
|
|
||||||
html[data-theme="dark"] .uk-text-small.uk-text-muted {
|
|
||||||
color: var(--tb-text-muted) !important;
|
|
||||||
}
|
|
||||||
html[data-theme="dark"] .uk-divider-icon::after,
|
|
||||||
html[data-theme="dark"] hr,
|
|
||||||
html[data-theme="dark"] .uk-table th,
|
|
||||||
html[data-theme="dark"] .uk-table td,
|
|
||||||
html[data-theme="dark"] .uk-list-divider > li:nth-child(n+2) {
|
|
||||||
border-color: var(--tb-border) !important;
|
|
||||||
}
|
|
||||||
html[data-theme="dark"] .uk-button-default {
|
|
||||||
background-color: var(--tb-surface-2) !important;
|
|
||||||
color: var(--tb-text) !important;
|
|
||||||
border-color: var(--tb-border) !important;
|
|
||||||
}
|
|
||||||
html[data-theme="dark"] .uk-modal-title,
|
|
||||||
html[data-theme="dark"] h1, html[data-theme="dark"] h2, html[data-theme="dark"] h3,
|
|
||||||
html[data-theme="dark"] h4, html[data-theme="dark"] h5, html[data-theme="dark"] h6,
|
|
||||||
html[data-theme="dark"] .uk-card-title {
|
|
||||||
color: var(--tb-text) !important;
|
|
||||||
}
|
|
||||||
html[data-theme="dark"] .uk-alert-warning,
|
|
||||||
html[data-theme="dark"] .uk-alert-danger,
|
|
||||||
html[data-theme="dark"] .uk-alert-success,
|
|
||||||
html[data-theme="dark"] .uk-alert-primary {
|
|
||||||
background-color: var(--tb-surface-2) !important;
|
|
||||||
color: var(--tb-text) !important;
|
|
||||||
}
|
|
||||||
html[data-theme="dark"] #math-captcha-modal .uk-modal-dialog {
|
|
||||||
background-color: var(--tb-surface) !important;
|
|
||||||
color: var(--tb-text) !important;
|
|
||||||
}
|
|
||||||
html[data-theme="dark"] #math-captcha-modal .captcha-equation-box {
|
|
||||||
background-color: var(--tb-surface-2) !important;
|
|
||||||
border-color: var(--tb-border) !important;
|
|
||||||
}
|
|
||||||
html[data-theme="dark"] #math-captcha-modal .math-captcha-modal-question {
|
|
||||||
color: var(--tb-text) !important;
|
|
||||||
}
|
|
||||||
html[data-theme="dark"] #math-captcha-modal #captcha-modal-answer {
|
|
||||||
background-color: var(--tb-surface) !important;
|
|
||||||
color: var(--tb-text) !important;
|
|
||||||
border-color: var(--tb-border) !important;
|
|
||||||
}
|
|
||||||
html[data-theme="dark"] #math-captcha-modal #captcha-modal-answer::placeholder {
|
|
||||||
color: var(--tb-text-muted) !important;
|
|
||||||
}
|
|
||||||
html[data-theme="dark"] #math-captcha-modal .uk-text-meta,
|
|
||||||
html[data-theme="dark"] #math-captcha-modal #captcha-modal-refresh {
|
|
||||||
color: var(--tb-text-muted) !important;
|
|
||||||
}
|
|
||||||
html[data-theme="dark"] #math-captcha-modal #captcha-modal-refresh:hover {
|
|
||||||
color: var(--tb-primary) !important;
|
|
||||||
}
|
|
||||||
html[data-theme="dark"] .uk-label {
|
|
||||||
color: #fff !important;
|
|
||||||
}
|
|
||||||
/* 自定义组件(探索页推荐卡片等)深色覆盖 */
|
|
||||||
html[data-theme="dark"] .recommend-card,
|
|
||||||
html[data-theme="dark"] .recommend-card:hover {
|
|
||||||
background-color: var(--tb-surface-2) !important;
|
|
||||||
}
|
|
||||||
html[data-theme="dark"] .explore-name a {
|
|
||||||
color: var(--tb-text) !important;
|
|
||||||
}
|
|
||||||
html[data-theme="dark"] .explore-name a:hover {
|
|
||||||
color: var(--tb-primary) !important;
|
|
||||||
}
|
|
||||||
html[data-theme="dark"] .explore-intro {
|
|
||||||
color: var(--tb-text-muted) !important;
|
|
||||||
}
|
|
||||||
/* 切换按钮图标切换(内联 SVG,不依赖 UIkit 图标库) */
|
|
||||||
#theme-toggle .tb-icon-light, #theme-toggle-mobile .tb-icon-light,
|
|
||||||
#theme-toggle .tb-icon-dark, #theme-toggle-mobile .tb-icon-dark {
|
|
||||||
display: inline-flex;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
#theme-toggle .tb-icon-light svg, #theme-toggle-mobile .tb-icon-light svg,
|
|
||||||
#theme-toggle .tb-icon-dark svg, #theme-toggle-mobile .tb-icon-dark svg { display: block; }
|
|
||||||
#theme-toggle .tb-icon-dark, #theme-toggle-mobile .tb-icon-dark { display: none; }
|
|
||||||
html[data-theme="dark"] #theme-toggle .tb-icon-light,
|
|
||||||
html[data-theme="dark"] #theme-toggle-mobile .tb-icon-light { display: none; }
|
|
||||||
html[data-theme="dark"] #theme-toggle .tb-icon-dark,
|
|
||||||
html[data-theme="dark"] #theme-toggle-mobile .tb-icon-dark { display: inline-flex; }
|
|
||||||
|
|
||||||
/* 基础质感层:只调整外观(圆角/投影/字体/数字对齐),不改任何结构与布局。
|
|
||||||
颜色一律取自头部令牌,亮暗两套自动生效,因此这里不需要再写 html[data-theme="dark"] 分支。 */
|
|
||||||
/* 根元素与 body 同时上色:内容不足一屏时,body 之外的视口区域也要是同一底色 */
|
|
||||||
html,
|
|
||||||
body {
|
|
||||||
font-family: var(--tb-font);
|
|
||||||
background-color: var(--tb-bg);
|
|
||||||
color: var(--tb-text);
|
|
||||||
-webkit-font-smoothing: antialiased;
|
|
||||||
-moz-osx-font-smoothing: grayscale;
|
|
||||||
}
|
|
||||||
/* 卡片:12px 圆角 + 一层极淡接触影 + 一层大扩散影(UIkit 默认的 0 5px 15px 偏硬) */
|
|
||||||
.uk-card {
|
|
||||||
border-radius: var(--tb-radius);
|
|
||||||
}
|
|
||||||
.uk-card-default {
|
|
||||||
background-color: var(--tb-surface);
|
|
||||||
box-shadow: var(--tb-shadow);
|
|
||||||
}
|
|
||||||
.uk-card-default.uk-card-hover:hover {
|
|
||||||
box-shadow: var(--tb-shadow-hover);
|
|
||||||
}
|
|
||||||
.uk-card-header {
|
|
||||||
border-radius: var(--tb-radius) var(--tb-radius) 0 0;
|
|
||||||
}
|
|
||||||
.uk-card-footer {
|
|
||||||
border-radius: 0 0 var(--tb-radius) var(--tb-radius);
|
|
||||||
}
|
|
||||||
.uk-card,
|
|
||||||
.uk-button,
|
|
||||||
.uk-alert,
|
|
||||||
.uk-label {
|
|
||||||
transition: box-shadow 0.18s ease, background-color 0.18s ease, border-color 0.18s ease, color 0.18s ease;
|
|
||||||
}
|
|
||||||
/* 交互元素:统一 8px 圆角,标签 6px */
|
|
||||||
.uk-button {
|
|
||||||
border-radius: var(--tb-radius-sm);
|
|
||||||
}
|
|
||||||
.uk-input,
|
|
||||||
.uk-select,
|
|
||||||
.uk-textarea,
|
|
||||||
.uk-form-small,
|
|
||||||
.uk-search-input {
|
|
||||||
border-radius: var(--tb-radius-sm);
|
|
||||||
}
|
|
||||||
.uk-label {
|
|
||||||
border-radius: var(--tb-radius-xs);
|
|
||||||
}
|
|
||||||
.uk-alert {
|
|
||||||
border-radius: 10px;
|
|
||||||
}
|
|
||||||
.uk-modal-dialog {
|
|
||||||
border-radius: 14px;
|
|
||||||
}
|
|
||||||
.uk-dropdown,
|
|
||||||
.uk-navbar-dropdown {
|
|
||||||
border-radius: 10px;
|
|
||||||
box-shadow: var(--tb-shadow);
|
|
||||||
}
|
|
||||||
.uk-navbar-container:not(.uk-navbar-transparent) {
|
|
||||||
background-color: var(--tb-surface);
|
|
||||||
}
|
|
||||||
/* 键盘可达性:仅在键盘聚焦时出现描边,鼠标点击不出现 */
|
|
||||||
.uk-button:focus-visible,
|
|
||||||
.uk-navbar-nav > li > a:focus-visible {
|
|
||||||
outline: 2px solid var(--tb-primary);
|
|
||||||
outline-offset: 2px;
|
|
||||||
}
|
|
||||||
/* 次要文字统一走令牌,避免 #999 / #8a919c 混用 */
|
|
||||||
.uk-text-muted,
|
|
||||||
.uk-text-meta {
|
|
||||||
color: var(--tb-text-muted);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 轻量胶囊:用于投票类型、热门标签等「只是分类信息」的位置。
|
|
||||||
实心 uk-label 一屏多个会变成一排色块,这里统一降级为浅底 + 次要色文字。 */
|
|
||||||
.tb-chip {
|
|
||||||
display: inline-block;
|
|
||||||
padding: 1px 8px;
|
|
||||||
border-radius: var(--tb-radius-xs);
|
|
||||||
background-color: var(--tb-surface-2);
|
|
||||||
color: var(--tb-text-secondary);
|
|
||||||
font-size: 0.72rem;
|
|
||||||
line-height: 1.7;
|
|
||||||
white-space: nowrap;
|
|
||||||
}
|
|
||||||
a.tb-chip:hover {
|
|
||||||
background-color: var(--tb-primary-weak);
|
|
||||||
color: var(--tb-primary);
|
|
||||||
text-decoration: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 统计/日期等数字列等宽对齐,避免刷新时左右跳动 */
|
|
||||||
.uk-table,
|
|
||||||
.tb-num {
|
|
||||||
font-variant-numeric: tabular-nums;
|
|
||||||
}
|
|
||||||
/* 图片上传条:原为 item/new-question 两处各写一份内联 style(写死 #f8f8f8,深色下露白),
|
|
||||||
收敛到一处并走令牌,亮暗自动适配 */
|
|
||||||
.tb-img-uploader {
|
|
||||||
width: 100%;
|
|
||||||
background-color: var(--tb-surface-2);
|
|
||||||
display: flex;
|
|
||||||
padding-top: 5px;
|
|
||||||
padding-bottom: 5px;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: flex-start;
|
|
||||||
gap: 5px;
|
|
||||||
}
|
|
||||||
/* 背景图封面(提问箱主页):渐变遮罩,保证用户自选文字色叠加后仍可读。
|
|
||||||
默认浅色遮罩(页面 .uk-light 补丁把文字兜底成深色);若箱主选了浅色文字,
|
|
||||||
question/list.html 会按亮度加上 .tb-cover-dark 换成深色遮罩。 */
|
|
||||||
.tb-cover {
|
|
||||||
position: relative;
|
|
||||||
border-radius: var(--tb-radius) var(--tb-radius) 0 0;
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
/* ⚠️ 必须带 .uk-flex 复合选择器:UIkit 3.3.3 里有
|
|
||||||
.uk-flex::after,.uk-flex::before{display:none}(优先级 0,2,0),
|
|
||||||
会把这个遮罩伪元素整个干掉——不报错、只是什么都不显示(踩过一次)。
|
|
||||||
单写 .tb-cover::after 优先级不够,会被它压回 display:none。 */
|
|
||||||
.tb-cover::after,
|
|
||||||
.tb-cover.uk-flex::after {
|
|
||||||
content: "";
|
|
||||||
display: block;
|
|
||||||
position: absolute;
|
|
||||||
inset: 0;
|
|
||||||
z-index: 0;
|
|
||||||
background: linear-gradient(180deg, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.58) 55%, rgba(255, 255, 255, 0.84) 100%);
|
|
||||||
pointer-events: none;
|
|
||||||
}
|
|
||||||
.tb-cover.tb-cover-dark::after {
|
|
||||||
background: linear-gradient(180deg, rgba(0, 0, 0, 0) 0%, rgba(0, 0, 0, 0.16) 45%, rgba(0, 0, 0, 0.46) 100%);
|
|
||||||
}
|
|
||||||
.tb-cover > * {
|
|
||||||
position: relative;
|
|
||||||
z-index: 1;
|
|
||||||
}
|
|
||||||
.tb-cover h3,
|
|
||||||
.tb-cover p {
|
|
||||||
text-shadow: 0 1px 10px rgba(255, 255, 255, 0.65);
|
|
||||||
}
|
|
||||||
.tb-cover.tb-cover-dark h3,
|
|
||||||
.tb-cover.tb-cover-dark p {
|
|
||||||
text-shadow: 0 1px 12px rgba(0, 0, 0, 0.45);
|
|
||||||
}
|
|
||||||
/* 尊重系统的减少动效设置 */
|
|
||||||
@media (prefers-reduced-motion: reduce) {
|
|
||||||
.uk-card,
|
|
||||||
.uk-button,
|
|
||||||
.emoji-placeholder {
|
|
||||||
transition: none;
|
|
||||||
animation: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 顶栏自适应:导航全部直接显示,窄屏时分级缩小字号/间距,保证英文/日文等长文字不溢出 */
|
|
||||||
.uk-navbar-nav a {
|
|
||||||
font-size: 0.95rem;
|
|
||||||
padding: 0 10px;
|
|
||||||
}
|
|
||||||
/* 未登录移动端占位:桌面端隐藏,仅 ≤640px 显示(见下方 media 查询)。
|
|
||||||
桌面端布局与改动前完全一致,不受影响。 */
|
|
||||||
.tb-mobile-balancer { display: none; }
|
|
||||||
/* 桌面端保持 UIkit 原生居中三列布局(无需额外 CSS) */
|
|
||||||
.tb-navbar .uk-logo {
|
|
||||||
white-space: nowrap;
|
|
||||||
}
|
|
||||||
@media (max-width: 1200px) {
|
|
||||||
.uk-navbar-nav a {
|
|
||||||
font-size: 0.88rem;
|
|
||||||
padding: 0 8px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@media (max-width: 1000px) {
|
|
||||||
.uk-navbar-nav a {
|
|
||||||
font-size: 0.82rem;
|
|
||||||
padding: 0 6px;
|
|
||||||
}
|
|
||||||
.uk-logo {
|
|
||||||
font-size: 1.1rem;
|
|
||||||
}
|
|
||||||
/* 登录用户名限宽,过长省略号截断 */
|
|
||||||
.tb-nav-username {
|
|
||||||
max-width: 110px;
|
|
||||||
overflow: hidden;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
white-space: nowrap;
|
|
||||||
display: inline-block;
|
|
||||||
vertical-align: middle;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@media (max-width: 800px) {
|
|
||||||
.uk-navbar-nav a {
|
|
||||||
font-size: 0.78rem;
|
|
||||||
padding: 0 4px;
|
|
||||||
}
|
|
||||||
.uk-logo {
|
|
||||||
font-size: 1rem;
|
|
||||||
}
|
|
||||||
.tb-nav-username {
|
|
||||||
max-width: 80px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* 手机端(≤640px):沿用 UIkit 桌面端 navbar 的原生三列定位。
|
|
||||||
不再重写 .uk-navbar-center / center-left / center-right 的定位,
|
|
||||||
避免 logo 被挤到下一行;底部语言与深色模式按钮仍由下方独立栏承载。 */
|
|
||||||
@media (max-width: 640px) {
|
|
||||||
.tb-navbar {
|
|
||||||
position: relative;
|
|
||||||
min-height: 56px;
|
|
||||||
overflow: visible;
|
|
||||||
}
|
|
||||||
.tb-navbar > .uk-navbar-center {
|
|
||||||
position: relative !important;
|
|
||||||
top: auto !important;
|
|
||||||
left: auto !important;
|
|
||||||
right: auto !important;
|
|
||||||
bottom: auto !important;
|
|
||||||
transform: none !important;
|
|
||||||
display: flex !important;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
width: 100%;
|
|
||||||
min-height: 56px;
|
|
||||||
white-space: nowrap;
|
|
||||||
flex-wrap: nowrap;
|
|
||||||
}
|
|
||||||
.tb-navbar .uk-navbar-center-left,
|
|
||||||
.tb-navbar .uk-navbar-center-right {
|
|
||||||
position: static !important;
|
|
||||||
top: auto !important;
|
|
||||||
left: auto !important;
|
|
||||||
right: auto !important;
|
|
||||||
bottom: auto !important;
|
|
||||||
transform: none !important;
|
|
||||||
display: flex !important;
|
|
||||||
align-items: center;
|
|
||||||
flex: 0 0 auto;
|
|
||||||
white-space: nowrap;
|
|
||||||
}
|
|
||||||
.tb-navbar .uk-navbar-center-left > div,
|
|
||||||
.tb-navbar .uk-navbar-center-right > div {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
white-space: nowrap;
|
|
||||||
}
|
|
||||||
.tb-navbar .uk-navbar-nav {
|
|
||||||
display: flex;
|
|
||||||
flex-wrap: nowrap;
|
|
||||||
flex: 0 0 auto;
|
|
||||||
}
|
|
||||||
.tb-navbar .uk-navbar-nav > li > a,
|
|
||||||
.tb-navbar .uk-logo {
|
|
||||||
white-space: nowrap;
|
|
||||||
}
|
|
||||||
/* 未登录:移动端显示与「我的」等宽的隐藏占位,使左栏「探索+占位」与
|
|
||||||
右栏「注册/登录」两项等宽,logo 真正居中,左右视觉平衡 */
|
|
||||||
.tb-mobile-balancer { display: block; }
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 标签样式的按钮(管理页置顶等):
|
|
||||||
尺寸完全继承 .uk-label(font-size/padding/line-height/text-transform 等),
|
|
||||||
仅覆盖 button 元素特有的默认样式(边框/字体族/光标等),保证与相邻 span 标签完全一致。 */
|
|
||||||
.tb-label-btn {
|
|
||||||
border: none !important;
|
|
||||||
cursor: pointer;
|
|
||||||
font-family: inherit;
|
|
||||||
margin: 0;
|
|
||||||
vertical-align: middle;
|
|
||||||
outline: none;
|
|
||||||
background-image: none;
|
|
||||||
box-sizing: border-box;
|
|
||||||
-webkit-appearance: none;
|
|
||||||
appearance: none;
|
|
||||||
}
|
|
||||||
.tb-label-btn:hover {
|
|
||||||
opacity: 0.85;
|
|
||||||
}
|
|
||||||
/* 公开页置顶小图标:仅一个图钉,不占行高、不影响原布局 */
|
|
||||||
.tb-pin-flag {
|
|
||||||
font-size: 0.9em;
|
|
||||||
margin-right: 4px;
|
|
||||||
vertical-align: -1px;
|
|
||||||
cursor: default;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Markdown 渲染排版(问题/回答/追问正文,左对齐以保留排版格式) */
|
|
||||||
/* 纯文本列表:保留换行与连续空格(pre-wrap),不渲染 Markdown 大字号/彩色 */
|
|
||||||
.tb-preline {
|
|
||||||
white-space: pre-wrap;
|
|
||||||
}
|
|
||||||
/* 纯文本列表:超过 5 行截断并显示省略号(不足 5 行则完整显示) */
|
|
||||||
.tb-clamp-5 {
|
|
||||||
display: -webkit-box;
|
|
||||||
-webkit-box-orient: vertical;
|
|
||||||
-webkit-line-clamp: 5;
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
.md-body {
|
|
||||||
line-height: 1.7;
|
|
||||||
text-align: left;
|
|
||||||
word-break: break-word;
|
|
||||||
}
|
|
||||||
.md-body p { margin: 0.5em 0; }
|
|
||||||
.md-body h1, .md-body h2, .md-body h3,
|
|
||||||
.md-body h4, .md-body h5, .md-body h6 {
|
|
||||||
margin: 0.8em 0 0.4em;
|
|
||||||
font-weight: 600;
|
|
||||||
line-height: 1.4;
|
|
||||||
}
|
|
||||||
.md-body ul, .md-body ol { padding-left: 1.6em; margin: 0.5em 0; }
|
|
||||||
.md-body li { margin: 0.2em 0; }
|
|
||||||
.md-body blockquote {
|
|
||||||
border-left: 3px solid #d3d1c7;
|
|
||||||
margin: 0.6em 0;
|
|
||||||
padding: 0.2em 1em;
|
|
||||||
color: #5f5e5a;
|
|
||||||
}
|
|
||||||
.md-body pre {
|
|
||||||
background: #f5f5f5;
|
|
||||||
padding: 0.8em 1em;
|
|
||||||
border-radius: 6px;
|
|
||||||
overflow-x: auto;
|
|
||||||
margin: 0.6em 0;
|
|
||||||
}
|
|
||||||
.md-body code {
|
|
||||||
background: #f0f0f0;
|
|
||||||
padding: 0.1em 0.35em;
|
|
||||||
border-radius: 4px;
|
|
||||||
font-size: 0.9em;
|
|
||||||
}
|
|
||||||
.md-body pre code { background: none; padding: 0; }
|
|
||||||
.md-body img { max-width: 100%; height: auto; }
|
|
||||||
.md-body table { border-collapse: collapse; margin: 0.6em 0; }
|
|
||||||
.md-body th, .md-body td {
|
|
||||||
border: 1px solid #ddd;
|
|
||||||
padding: 0.4em 0.8em;
|
|
||||||
}
|
|
||||||
.md-body hr { margin: 1em 0; }
|
|
||||||
html[data-theme="dark"] .md-body blockquote {
|
|
||||||
border-color: #3a404c;
|
|
||||||
color: #8b93a1;
|
|
||||||
}
|
|
||||||
html[data-theme="dark"] .md-body pre,
|
|
||||||
html[data-theme="dark"] .md-body code { background: #2d323c; }
|
|
||||||
html[data-theme="dark"] .md-body th,
|
|
||||||
html[data-theme="dark"] .md-body td { border-color: #3a404c; }
|
|
||||||
|
|
||||||
/* 投票结果占比条:模板已改用 UIkit 3 原生 <progress class="uk-progress" value max>,
|
|
||||||
这里只把默认的 15px 高 / 500px 圆角 / 20px 外边距收紧到与页面一致的规格。
|
|
||||||
(原先为 UIkit 2 的 .uk-progressbar 结构打的补丁已删除) */
|
|
||||||
.uk-progress {
|
|
||||||
height: 10px;
|
|
||||||
margin: 0;
|
|
||||||
border-radius: var(--tb-radius-xs);
|
|
||||||
background-color: var(--tb-surface-2);
|
|
||||||
}
|
|
||||||
.uk-progress::-webkit-progress-bar {
|
|
||||||
background-color: var(--tb-surface-2);
|
|
||||||
border-radius: var(--tb-radius-xs);
|
|
||||||
}
|
|
||||||
.uk-progress::-webkit-progress-value {
|
|
||||||
background-color: var(--tb-primary);
|
|
||||||
border-radius: var(--tb-radius-xs) 0 0 var(--tb-radius-xs);
|
|
||||||
}
|
|
||||||
.uk-progress::-moz-progress-bar {
|
|
||||||
background-color: var(--tb-primary);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 移动端底部操作栏:固定底栏承载语言切换与深色模式,桌面端隐藏 */
|
|
||||||
#tb-mobile-utils {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
@media (max-width: 640px) {
|
|
||||||
/* 顶栏不再容纳语言/深色按钮,恢复原有导航空间 */
|
|
||||||
.tb-nav-utils {
|
|
||||||
display: none !important;
|
|
||||||
}
|
|
||||||
/* 手机端隐藏登录用户名(左边仅保留"探索"),保证 logo 居中、
|
|
||||||
两侧各不超过 2 个短按钮,避免用户名宽度挤压布局 */
|
|
||||||
.tb-nav-username {
|
|
||||||
display: none !important;
|
|
||||||
}
|
|
||||||
/* 固定底部操作栏 */
|
|
||||||
#tb-mobile-utils {
|
|
||||||
display: flex;
|
|
||||||
position: fixed;
|
|
||||||
left: 0;
|
|
||||||
right: 0;
|
|
||||||
bottom: 0;
|
|
||||||
z-index: 1000;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
gap: 10px;
|
|
||||||
padding: 8px 12px calc(8px + env(safe-area-inset-bottom));
|
|
||||||
background: rgba(255, 255, 255, 0.92);
|
|
||||||
-webkit-backdrop-filter: blur(8px);
|
|
||||||
backdrop-filter: blur(8px);
|
|
||||||
box-shadow: 0 -2px 12px rgba(0, 0, 0, 0.08);
|
|
||||||
}
|
|
||||||
#tb-mobile-utils .uk-select {
|
|
||||||
width: 110px;
|
|
||||||
}
|
|
||||||
html[data-theme="dark"] #tb-mobile-utils {
|
|
||||||
background: rgba(36, 40, 48, 0.92);
|
|
||||||
box-shadow: 0 -2px 12px rgba(0, 0, 0, 0.4);
|
|
||||||
}
|
|
||||||
/* 给页面底部预留空间,避免页脚内容被固定底栏遮挡 */
|
|
||||||
body {
|
|
||||||
padding-bottom: 56px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
||||||
<link rel="stylesheet" href="https://r2.337845818.best/tamabox/cdn/waline/client/v2/waline-no-commits.css" media="print" onload="this.media='all'"/>
|
<link rel="stylesheet" href="https://r2.337845818.best/tamabox/cdn/waline/client/v2/waline-no-commits.css" media="print" onload="this.media='all'"/>
|
||||||
<script defer src="https://cdnjs.cloudflare.com/ajax/libs/uikit/3.3.3/js/uikit.min.js"></script>
|
<script defer src="https://cdnjs.cloudflare.com/ajax/libs/uikit/3.3.3/js/uikit.min.js"></script>
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
<title>预览 12:01 · 投票</title>
|
<title>预览 15:15 · 投票</title>
|
||||||
<meta name="msvalidate.01" content="2F185E8E63C93635F50B3574F3B31E42" />
|
<meta name="msvalidate.01" content="2F185E8E63C93635F50B3574F3B31E42" />
|
||||||
<meta name="description" content="狼的提问箱——一个无需注册、可匿名提问的匿名提问箱,安全地倾诉与回应。">
|
<meta name="description" content="狼的提问箱——一个无需注册、可匿名提问的匿名提问箱,安全地倾诉与回应。">
|
||||||
<meta name="keywords" content="匿名提问箱,提问箱,匿名提问,狼的提问箱,匿名问答,匿名提问网站">
|
<meta name="keywords" content="匿名提问箱,提问箱,匿名提问,狼的提问箱,匿名问答,匿名提问网站">
|
||||||
@@ -20,675 +20,8 @@
|
|||||||
|
|
||||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/uikit/3.3.3/css/uikit.min.css"/>
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/uikit/3.3.3/css/uikit.min.css"/>
|
||||||
|
|
||||||
<style>/* TamaBox 全站基础样式:设计令牌 / 主题覆盖 / 组件质感 / 响应式。
|
<link rel="stylesheet" href="/static/css/base.css?v="/>
|
||||||
由 base/header.html 内联块抽出,集中一份便于缓存与维护。
|
|
||||||
⚠️ 改完务必把 header 里的 ?v= 版本号 +1,否则老访客仍用缓存。 */
|
|
||||||
|
|
||||||
/* 设计令牌:亮色为默认(:root),深色在 html[data-theme="dark"] 覆盖。
|
|
||||||
页面与组件样式一律引用 var(--tb-*),不再写死色值/圆角/阴影;
|
|
||||||
var() 的第二个参数仅作兜底(旧缓存页、邮件模板等不引入本文件的场景)。
|
|
||||||
改配色只动这一块,亮暗两套自动保持一致。 */
|
|
||||||
:root {
|
|
||||||
--tb-bg: #f7f8fa;
|
|
||||||
--tb-surface: #ffffff;
|
|
||||||
--tb-surface-2: #f4f6f8;
|
|
||||||
--tb-surface-hover: #f3f7ff;
|
|
||||||
--tb-border: #e8eaee;
|
|
||||||
--tb-text: #1f2329;
|
|
||||||
--tb-text-secondary: #5c6370;
|
|
||||||
--tb-text-muted: #8a919c;
|
|
||||||
--tb-primary: #1e87f0;
|
|
||||||
--tb-primary-weak: rgba(30, 135, 240, 0.10);
|
|
||||||
--tb-radius: 12px;
|
|
||||||
--tb-radius-sm: 8px;
|
|
||||||
--tb-radius-xs: 6px;
|
|
||||||
--tb-shadow: 0 1px 2px rgba(16, 24, 40, 0.04), 0 12px 28px -18px rgba(16, 24, 40, 0.20);
|
|
||||||
--tb-shadow-hover: 0 1px 2px rgba(16, 24, 40, 0.05), 0 18px 40px -20px rgba(16, 24, 40, 0.28);
|
|
||||||
--tb-font: system-ui, -apple-system, "Segoe UI", "PingFang SC", "Hiragino Sans GB", "Noto Sans CJK SC", "Microsoft YaHei", sans-serif;
|
|
||||||
}
|
|
||||||
html[data-theme="dark"] {
|
|
||||||
--tb-bg: #1a1d23;
|
|
||||||
--tb-surface: #242830;
|
|
||||||
--tb-surface-2: #2d323c;
|
|
||||||
--tb-surface-hover: rgba(92, 141, 255, 0.12);
|
|
||||||
--tb-border: #3a404c;
|
|
||||||
--tb-text: #d8dce4;
|
|
||||||
--tb-text-secondary: #a8b0bd;
|
|
||||||
--tb-text-muted: #8b93a1;
|
|
||||||
--tb-primary: #5c8dff;
|
|
||||||
--tb-primary-weak: rgba(92, 141, 255, 0.14);
|
|
||||||
--tb-shadow: 0 1px 2px rgba(0, 0, 0, 0.30), 0 12px 28px -18px rgba(0, 0, 0, 0.55);
|
|
||||||
--tb-shadow-hover: 0 1px 2px rgba(0, 0, 0, 0.35), 0 18px 40px -20px rgba(0, 0, 0, 0.65);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* UIkit 补丁:复刻原自建版 "modify-black-font"(官方版与自建版仅 3 处颜色差异——把有色容器内默认白字/白标题改为黑字)。
|
|
||||||
模板当前只用到 .uk-light 容器(用户背景封面,question/list.html、question-not-found.html;
|
|
||||||
其中 h3/p 已由 #usernamecolor/#introcolor 内联 style 覆盖),故只需补该容器的 3 处投影即可保持渲染一致。
|
|
||||||
若日后新增 .uk-card-primary/.uk-card-secondary/.uk-section-primary/.uk-tile-*/.uk-overlay-primary 等容器且需黑字,须同步扩展。 */
|
|
||||||
.uk-light { color: rgba(0,0,0,.7); }
|
|
||||||
.uk-light .uk-h1, .uk-light .uk-h2, .uk-light .uk-h3, .uk-light .uk-h4, .uk-light .uk-h5, .uk-light .uk-h6,
|
|
||||||
.uk-light .uk-heading-2xlarge, .uk-light .uk-heading-large, .uk-light .uk-heading-medium, .uk-light .uk-heading-small, .uk-light .uk-heading-xlarge,
|
|
||||||
.uk-light h1, .uk-light h2, .uk-light h3, .uk-light h4, .uk-light h5, .uk-light h6 { color: #000; }
|
|
||||||
.uk-light .uk-table th { color: rgba(0,0,0,.7); }
|
|
||||||
|
|
||||||
.grecaptcha-badge {visibility: hidden;}
|
|
||||||
.icon-container {
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
.icon {
|
|
||||||
margin-left: 10px;
|
|
||||||
width: 20px; /* 设置图标的宽度 */
|
|
||||||
height: auto; /* 保持图标的高度自动调整 */
|
|
||||||
}
|
|
||||||
.emoji-placeholder {
|
|
||||||
display: inline-block;
|
|
||||||
animation: jump 0.5s ease-in-out;
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes jump {
|
|
||||||
0%, 100% { transform: translateY(0); }
|
|
||||||
50% { transform: translateY(-5px); }
|
|
||||||
}
|
|
||||||
/* 防止 UIkit Dropbar 初始闪烁 */
|
|
||||||
.uk-dropbar {
|
|
||||||
opacity: 0;
|
|
||||||
visibility: hidden;
|
|
||||||
transition: opacity 0.2s ease, visibility 0.2s ease;
|
|
||||||
}
|
|
||||||
|
|
||||||
.uk-dropbar.uk-open {
|
|
||||||
opacity: 1;
|
|
||||||
visibility: visible;
|
|
||||||
}
|
|
||||||
|
|
||||||
a.uk-button.uk-button-link {
|
|
||||||
text-transform: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 移动端优化:缩小字体和间距,避免右侧空白 */
|
|
||||||
@media (max-width: 640px) {
|
|
||||||
.uk-logo {
|
|
||||||
font-size: 1rem;
|
|
||||||
}
|
|
||||||
.uk-navbar-nav a {
|
|
||||||
font-size: 0.78rem;
|
|
||||||
padding: 0 4px;
|
|
||||||
}
|
|
||||||
.emoji-placeholder {
|
|
||||||
font-size: 1rem;
|
|
||||||
}
|
|
||||||
/* 移动端用户名限宽省略,避免长英文用户名撑爆顶栏 */
|
|
||||||
.tb-nav-username {
|
|
||||||
max-width: 64px;
|
|
||||||
overflow: hidden;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
white-space: nowrap;
|
|
||||||
display: inline-block;
|
|
||||||
vertical-align: middle;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 深色模式:html[data-theme="dark"] 时覆盖 UIkit 3.3.3 编译主题的关键颜色 */
|
|
||||||
/* 变量(--tb-*)已上移到 head 顶部的令牌块,亮暗两套同名常量在那里定义。 */
|
|
||||||
/* 根元素与 body 一起覆盖,确保整个视口(含内容不足一屏时的空白区)都是深色背景 */
|
|
||||||
html[data-theme="dark"],
|
|
||||||
html[data-theme="dark"] body {
|
|
||||||
background-color: var(--tb-bg) !important;
|
|
||||||
color: var(--tb-text) !important;
|
|
||||||
}
|
|
||||||
/* 通用表面容器 */
|
|
||||||
html[data-theme="dark"] .uk-card,
|
|
||||||
html[data-theme="dark"] .uk-card-default,
|
|
||||||
html[data-theme="dark"] .uk-card-secondary,
|
|
||||||
html[data-theme="dark"] .uk-dropbar,
|
|
||||||
html[data-theme="dark"] .uk-navbar-dropdown,
|
|
||||||
html[data-theme="dark"] .uk-modal-dialog,
|
|
||||||
html[data-theme="dark"] .uk-dropdown,
|
|
||||||
html[data-theme="dark"] .uk-offcanvas-bar,
|
|
||||||
html[data-theme="dark"] .uk-section,
|
|
||||||
html[data-theme="dark"] .uk-tile,
|
|
||||||
html[data-theme="dark"] .uk-panel,
|
|
||||||
html[data-theme="dark"] .uk-background-default,
|
|
||||||
html[data-theme="dark"] .uk-search-default .uk-search-input {
|
|
||||||
background-color: var(--tb-surface) !important;
|
|
||||||
color: var(--tb-text) !important;
|
|
||||||
}
|
|
||||||
html[data-theme="dark"] .uk-navbar-container {
|
|
||||||
background-color: var(--tb-surface) !important;
|
|
||||||
color: var(--tb-text) !important;
|
|
||||||
}
|
|
||||||
html[data-theme="dark"] .uk-navbar-nav > li > a,
|
|
||||||
html[data-theme="dark"] .uk-card a,
|
|
||||||
html[data-theme="dark"] .uk-link,
|
|
||||||
html[data-theme="dark"] a.uk-button-link,
|
|
||||||
html[data-theme="dark"] .uk-navbar-dropdown-nav > li > a,
|
|
||||||
html[data-theme="dark"] .uk-dropdown-nav > li > a,
|
|
||||||
html[data-theme="dark"] .uk-list a {
|
|
||||||
color: var(--tb-text) !important;
|
|
||||||
}
|
|
||||||
html[data-theme="dark"] .uk-navbar-nav > li > a:hover,
|
|
||||||
html[data-theme="dark"] .uk-card a:hover,
|
|
||||||
html[data-theme="dark"] .uk-navbar-dropdown-nav > li > a:hover,
|
|
||||||
html[data-theme="dark"] .uk-dropdown-nav > li > a:hover {
|
|
||||||
color: var(--tb-primary) !important;
|
|
||||||
}
|
|
||||||
html[data-theme="dark"] .uk-input,
|
|
||||||
html[data-theme="dark"] .uk-textarea,
|
|
||||||
html[data-theme="dark"] .uk-select {
|
|
||||||
background-color: var(--tb-surface-2) !important;
|
|
||||||
color: var(--tb-text) !important;
|
|
||||||
border-color: var(--tb-border) !important;
|
|
||||||
}
|
|
||||||
html[data-theme="dark"] .uk-input:focus,
|
|
||||||
html[data-theme="dark"] .uk-textarea:focus,
|
|
||||||
html[data-theme="dark"] .uk-select:focus {
|
|
||||||
border-color: var(--tb-primary) !important;
|
|
||||||
}
|
|
||||||
html[data-theme="dark"] .uk-text-muted,
|
|
||||||
html[data-theme="dark"] .uk-text-meta,
|
|
||||||
html[data-theme="dark"] .uk-text-secondary,
|
|
||||||
html[data-theme="dark"] .uk-text-muted a,
|
|
||||||
html[data-theme="dark"] .uk-text-small.uk-text-muted {
|
|
||||||
color: var(--tb-text-muted) !important;
|
|
||||||
}
|
|
||||||
html[data-theme="dark"] .uk-divider-icon::after,
|
|
||||||
html[data-theme="dark"] hr,
|
|
||||||
html[data-theme="dark"] .uk-table th,
|
|
||||||
html[data-theme="dark"] .uk-table td,
|
|
||||||
html[data-theme="dark"] .uk-list-divider > li:nth-child(n+2) {
|
|
||||||
border-color: var(--tb-border) !important;
|
|
||||||
}
|
|
||||||
html[data-theme="dark"] .uk-button-default {
|
|
||||||
background-color: var(--tb-surface-2) !important;
|
|
||||||
color: var(--tb-text) !important;
|
|
||||||
border-color: var(--tb-border) !important;
|
|
||||||
}
|
|
||||||
html[data-theme="dark"] .uk-modal-title,
|
|
||||||
html[data-theme="dark"] h1, html[data-theme="dark"] h2, html[data-theme="dark"] h3,
|
|
||||||
html[data-theme="dark"] h4, html[data-theme="dark"] h5, html[data-theme="dark"] h6,
|
|
||||||
html[data-theme="dark"] .uk-card-title {
|
|
||||||
color: var(--tb-text) !important;
|
|
||||||
}
|
|
||||||
html[data-theme="dark"] .uk-alert-warning,
|
|
||||||
html[data-theme="dark"] .uk-alert-danger,
|
|
||||||
html[data-theme="dark"] .uk-alert-success,
|
|
||||||
html[data-theme="dark"] .uk-alert-primary {
|
|
||||||
background-color: var(--tb-surface-2) !important;
|
|
||||||
color: var(--tb-text) !important;
|
|
||||||
}
|
|
||||||
html[data-theme="dark"] #math-captcha-modal .uk-modal-dialog {
|
|
||||||
background-color: var(--tb-surface) !important;
|
|
||||||
color: var(--tb-text) !important;
|
|
||||||
}
|
|
||||||
html[data-theme="dark"] #math-captcha-modal .captcha-equation-box {
|
|
||||||
background-color: var(--tb-surface-2) !important;
|
|
||||||
border-color: var(--tb-border) !important;
|
|
||||||
}
|
|
||||||
html[data-theme="dark"] #math-captcha-modal .math-captcha-modal-question {
|
|
||||||
color: var(--tb-text) !important;
|
|
||||||
}
|
|
||||||
html[data-theme="dark"] #math-captcha-modal #captcha-modal-answer {
|
|
||||||
background-color: var(--tb-surface) !important;
|
|
||||||
color: var(--tb-text) !important;
|
|
||||||
border-color: var(--tb-border) !important;
|
|
||||||
}
|
|
||||||
html[data-theme="dark"] #math-captcha-modal #captcha-modal-answer::placeholder {
|
|
||||||
color: var(--tb-text-muted) !important;
|
|
||||||
}
|
|
||||||
html[data-theme="dark"] #math-captcha-modal .uk-text-meta,
|
|
||||||
html[data-theme="dark"] #math-captcha-modal #captcha-modal-refresh {
|
|
||||||
color: var(--tb-text-muted) !important;
|
|
||||||
}
|
|
||||||
html[data-theme="dark"] #math-captcha-modal #captcha-modal-refresh:hover {
|
|
||||||
color: var(--tb-primary) !important;
|
|
||||||
}
|
|
||||||
html[data-theme="dark"] .uk-label {
|
|
||||||
color: #fff !important;
|
|
||||||
}
|
|
||||||
/* 自定义组件(探索页推荐卡片等)深色覆盖 */
|
|
||||||
html[data-theme="dark"] .recommend-card,
|
|
||||||
html[data-theme="dark"] .recommend-card:hover {
|
|
||||||
background-color: var(--tb-surface-2) !important;
|
|
||||||
}
|
|
||||||
html[data-theme="dark"] .explore-name a {
|
|
||||||
color: var(--tb-text) !important;
|
|
||||||
}
|
|
||||||
html[data-theme="dark"] .explore-name a:hover {
|
|
||||||
color: var(--tb-primary) !important;
|
|
||||||
}
|
|
||||||
html[data-theme="dark"] .explore-intro {
|
|
||||||
color: var(--tb-text-muted) !important;
|
|
||||||
}
|
|
||||||
/* 切换按钮图标切换(内联 SVG,不依赖 UIkit 图标库) */
|
|
||||||
#theme-toggle .tb-icon-light, #theme-toggle-mobile .tb-icon-light,
|
|
||||||
#theme-toggle .tb-icon-dark, #theme-toggle-mobile .tb-icon-dark {
|
|
||||||
display: inline-flex;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
#theme-toggle .tb-icon-light svg, #theme-toggle-mobile .tb-icon-light svg,
|
|
||||||
#theme-toggle .tb-icon-dark svg, #theme-toggle-mobile .tb-icon-dark svg { display: block; }
|
|
||||||
#theme-toggle .tb-icon-dark, #theme-toggle-mobile .tb-icon-dark { display: none; }
|
|
||||||
html[data-theme="dark"] #theme-toggle .tb-icon-light,
|
|
||||||
html[data-theme="dark"] #theme-toggle-mobile .tb-icon-light { display: none; }
|
|
||||||
html[data-theme="dark"] #theme-toggle .tb-icon-dark,
|
|
||||||
html[data-theme="dark"] #theme-toggle-mobile .tb-icon-dark { display: inline-flex; }
|
|
||||||
|
|
||||||
/* 基础质感层:只调整外观(圆角/投影/字体/数字对齐),不改任何结构与布局。
|
|
||||||
颜色一律取自头部令牌,亮暗两套自动生效,因此这里不需要再写 html[data-theme="dark"] 分支。 */
|
|
||||||
/* 根元素与 body 同时上色:内容不足一屏时,body 之外的视口区域也要是同一底色 */
|
|
||||||
html,
|
|
||||||
body {
|
|
||||||
font-family: var(--tb-font);
|
|
||||||
background-color: var(--tb-bg);
|
|
||||||
color: var(--tb-text);
|
|
||||||
-webkit-font-smoothing: antialiased;
|
|
||||||
-moz-osx-font-smoothing: grayscale;
|
|
||||||
}
|
|
||||||
/* 卡片:12px 圆角 + 一层极淡接触影 + 一层大扩散影(UIkit 默认的 0 5px 15px 偏硬) */
|
|
||||||
.uk-card {
|
|
||||||
border-radius: var(--tb-radius);
|
|
||||||
}
|
|
||||||
.uk-card-default {
|
|
||||||
background-color: var(--tb-surface);
|
|
||||||
box-shadow: var(--tb-shadow);
|
|
||||||
}
|
|
||||||
.uk-card-default.uk-card-hover:hover {
|
|
||||||
box-shadow: var(--tb-shadow-hover);
|
|
||||||
}
|
|
||||||
.uk-card-header {
|
|
||||||
border-radius: var(--tb-radius) var(--tb-radius) 0 0;
|
|
||||||
}
|
|
||||||
.uk-card-footer {
|
|
||||||
border-radius: 0 0 var(--tb-radius) var(--tb-radius);
|
|
||||||
}
|
|
||||||
.uk-card,
|
|
||||||
.uk-button,
|
|
||||||
.uk-alert,
|
|
||||||
.uk-label {
|
|
||||||
transition: box-shadow 0.18s ease, background-color 0.18s ease, border-color 0.18s ease, color 0.18s ease;
|
|
||||||
}
|
|
||||||
/* 交互元素:统一 8px 圆角,标签 6px */
|
|
||||||
.uk-button {
|
|
||||||
border-radius: var(--tb-radius-sm);
|
|
||||||
}
|
|
||||||
.uk-input,
|
|
||||||
.uk-select,
|
|
||||||
.uk-textarea,
|
|
||||||
.uk-form-small,
|
|
||||||
.uk-search-input {
|
|
||||||
border-radius: var(--tb-radius-sm);
|
|
||||||
}
|
|
||||||
.uk-label {
|
|
||||||
border-radius: var(--tb-radius-xs);
|
|
||||||
}
|
|
||||||
.uk-alert {
|
|
||||||
border-radius: 10px;
|
|
||||||
}
|
|
||||||
.uk-modal-dialog {
|
|
||||||
border-radius: 14px;
|
|
||||||
}
|
|
||||||
.uk-dropdown,
|
|
||||||
.uk-navbar-dropdown {
|
|
||||||
border-radius: 10px;
|
|
||||||
box-shadow: var(--tb-shadow);
|
|
||||||
}
|
|
||||||
.uk-navbar-container:not(.uk-navbar-transparent) {
|
|
||||||
background-color: var(--tb-surface);
|
|
||||||
}
|
|
||||||
/* 键盘可达性:仅在键盘聚焦时出现描边,鼠标点击不出现 */
|
|
||||||
.uk-button:focus-visible,
|
|
||||||
.uk-navbar-nav > li > a:focus-visible {
|
|
||||||
outline: 2px solid var(--tb-primary);
|
|
||||||
outline-offset: 2px;
|
|
||||||
}
|
|
||||||
/* 次要文字统一走令牌,避免 #999 / #8a919c 混用 */
|
|
||||||
.uk-text-muted,
|
|
||||||
.uk-text-meta {
|
|
||||||
color: var(--tb-text-muted);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 轻量胶囊:用于投票类型、热门标签等「只是分类信息」的位置。
|
|
||||||
实心 uk-label 一屏多个会变成一排色块,这里统一降级为浅底 + 次要色文字。 */
|
|
||||||
.tb-chip {
|
|
||||||
display: inline-block;
|
|
||||||
padding: 1px 8px;
|
|
||||||
border-radius: var(--tb-radius-xs);
|
|
||||||
background-color: var(--tb-surface-2);
|
|
||||||
color: var(--tb-text-secondary);
|
|
||||||
font-size: 0.72rem;
|
|
||||||
line-height: 1.7;
|
|
||||||
white-space: nowrap;
|
|
||||||
}
|
|
||||||
a.tb-chip:hover {
|
|
||||||
background-color: var(--tb-primary-weak);
|
|
||||||
color: var(--tb-primary);
|
|
||||||
text-decoration: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 统计/日期等数字列等宽对齐,避免刷新时左右跳动 */
|
|
||||||
.uk-table,
|
|
||||||
.tb-num {
|
|
||||||
font-variant-numeric: tabular-nums;
|
|
||||||
}
|
|
||||||
/* 图片上传条:原为 item/new-question 两处各写一份内联 style(写死 #f8f8f8,深色下露白),
|
|
||||||
收敛到一处并走令牌,亮暗自动适配 */
|
|
||||||
.tb-img-uploader {
|
|
||||||
width: 100%;
|
|
||||||
background-color: var(--tb-surface-2);
|
|
||||||
display: flex;
|
|
||||||
padding-top: 5px;
|
|
||||||
padding-bottom: 5px;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: flex-start;
|
|
||||||
gap: 5px;
|
|
||||||
}
|
|
||||||
/* 背景图封面(提问箱主页):渐变遮罩,保证用户自选文字色叠加后仍可读。
|
|
||||||
默认浅色遮罩(页面 .uk-light 补丁把文字兜底成深色);若箱主选了浅色文字,
|
|
||||||
question/list.html 会按亮度加上 .tb-cover-dark 换成深色遮罩。 */
|
|
||||||
.tb-cover {
|
|
||||||
position: relative;
|
|
||||||
border-radius: var(--tb-radius) var(--tb-radius) 0 0;
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
/* ⚠️ 必须带 .uk-flex 复合选择器:UIkit 3.3.3 里有
|
|
||||||
.uk-flex::after,.uk-flex::before{display:none}(优先级 0,2,0),
|
|
||||||
会把这个遮罩伪元素整个干掉——不报错、只是什么都不显示(踩过一次)。
|
|
||||||
单写 .tb-cover::after 优先级不够,会被它压回 display:none。 */
|
|
||||||
.tb-cover::after,
|
|
||||||
.tb-cover.uk-flex::after {
|
|
||||||
content: "";
|
|
||||||
display: block;
|
|
||||||
position: absolute;
|
|
||||||
inset: 0;
|
|
||||||
z-index: 0;
|
|
||||||
background: linear-gradient(180deg, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.58) 55%, rgba(255, 255, 255, 0.84) 100%);
|
|
||||||
pointer-events: none;
|
|
||||||
}
|
|
||||||
.tb-cover.tb-cover-dark::after {
|
|
||||||
background: linear-gradient(180deg, rgba(0, 0, 0, 0) 0%, rgba(0, 0, 0, 0.16) 45%, rgba(0, 0, 0, 0.46) 100%);
|
|
||||||
}
|
|
||||||
.tb-cover > * {
|
|
||||||
position: relative;
|
|
||||||
z-index: 1;
|
|
||||||
}
|
|
||||||
.tb-cover h3,
|
|
||||||
.tb-cover p {
|
|
||||||
text-shadow: 0 1px 10px rgba(255, 255, 255, 0.65);
|
|
||||||
}
|
|
||||||
.tb-cover.tb-cover-dark h3,
|
|
||||||
.tb-cover.tb-cover-dark p {
|
|
||||||
text-shadow: 0 1px 12px rgba(0, 0, 0, 0.45);
|
|
||||||
}
|
|
||||||
/* 尊重系统的减少动效设置 */
|
|
||||||
@media (prefers-reduced-motion: reduce) {
|
|
||||||
.uk-card,
|
|
||||||
.uk-button,
|
|
||||||
.emoji-placeholder {
|
|
||||||
transition: none;
|
|
||||||
animation: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 顶栏自适应:导航全部直接显示,窄屏时分级缩小字号/间距,保证英文/日文等长文字不溢出 */
|
|
||||||
.uk-navbar-nav a {
|
|
||||||
font-size: 0.95rem;
|
|
||||||
padding: 0 10px;
|
|
||||||
}
|
|
||||||
/* 未登录移动端占位:桌面端隐藏,仅 ≤640px 显示(见下方 media 查询)。
|
|
||||||
桌面端布局与改动前完全一致,不受影响。 */
|
|
||||||
.tb-mobile-balancer { display: none; }
|
|
||||||
/* 桌面端保持 UIkit 原生居中三列布局(无需额外 CSS) */
|
|
||||||
.tb-navbar .uk-logo {
|
|
||||||
white-space: nowrap;
|
|
||||||
}
|
|
||||||
@media (max-width: 1200px) {
|
|
||||||
.uk-navbar-nav a {
|
|
||||||
font-size: 0.88rem;
|
|
||||||
padding: 0 8px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@media (max-width: 1000px) {
|
|
||||||
.uk-navbar-nav a {
|
|
||||||
font-size: 0.82rem;
|
|
||||||
padding: 0 6px;
|
|
||||||
}
|
|
||||||
.uk-logo {
|
|
||||||
font-size: 1.1rem;
|
|
||||||
}
|
|
||||||
/* 登录用户名限宽,过长省略号截断 */
|
|
||||||
.tb-nav-username {
|
|
||||||
max-width: 110px;
|
|
||||||
overflow: hidden;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
white-space: nowrap;
|
|
||||||
display: inline-block;
|
|
||||||
vertical-align: middle;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@media (max-width: 800px) {
|
|
||||||
.uk-navbar-nav a {
|
|
||||||
font-size: 0.78rem;
|
|
||||||
padding: 0 4px;
|
|
||||||
}
|
|
||||||
.uk-logo {
|
|
||||||
font-size: 1rem;
|
|
||||||
}
|
|
||||||
.tb-nav-username {
|
|
||||||
max-width: 80px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* 手机端(≤640px):沿用 UIkit 桌面端 navbar 的原生三列定位。
|
|
||||||
不再重写 .uk-navbar-center / center-left / center-right 的定位,
|
|
||||||
避免 logo 被挤到下一行;底部语言与深色模式按钮仍由下方独立栏承载。 */
|
|
||||||
@media (max-width: 640px) {
|
|
||||||
.tb-navbar {
|
|
||||||
position: relative;
|
|
||||||
min-height: 56px;
|
|
||||||
overflow: visible;
|
|
||||||
}
|
|
||||||
.tb-navbar > .uk-navbar-center {
|
|
||||||
position: relative !important;
|
|
||||||
top: auto !important;
|
|
||||||
left: auto !important;
|
|
||||||
right: auto !important;
|
|
||||||
bottom: auto !important;
|
|
||||||
transform: none !important;
|
|
||||||
display: flex !important;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
width: 100%;
|
|
||||||
min-height: 56px;
|
|
||||||
white-space: nowrap;
|
|
||||||
flex-wrap: nowrap;
|
|
||||||
}
|
|
||||||
.tb-navbar .uk-navbar-center-left,
|
|
||||||
.tb-navbar .uk-navbar-center-right {
|
|
||||||
position: static !important;
|
|
||||||
top: auto !important;
|
|
||||||
left: auto !important;
|
|
||||||
right: auto !important;
|
|
||||||
bottom: auto !important;
|
|
||||||
transform: none !important;
|
|
||||||
display: flex !important;
|
|
||||||
align-items: center;
|
|
||||||
flex: 0 0 auto;
|
|
||||||
white-space: nowrap;
|
|
||||||
}
|
|
||||||
.tb-navbar .uk-navbar-center-left > div,
|
|
||||||
.tb-navbar .uk-navbar-center-right > div {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
white-space: nowrap;
|
|
||||||
}
|
|
||||||
.tb-navbar .uk-navbar-nav {
|
|
||||||
display: flex;
|
|
||||||
flex-wrap: nowrap;
|
|
||||||
flex: 0 0 auto;
|
|
||||||
}
|
|
||||||
.tb-navbar .uk-navbar-nav > li > a,
|
|
||||||
.tb-navbar .uk-logo {
|
|
||||||
white-space: nowrap;
|
|
||||||
}
|
|
||||||
/* 未登录:移动端显示与「我的」等宽的隐藏占位,使左栏「探索+占位」与
|
|
||||||
右栏「注册/登录」两项等宽,logo 真正居中,左右视觉平衡 */
|
|
||||||
.tb-mobile-balancer { display: block; }
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 标签样式的按钮(管理页置顶等):
|
|
||||||
尺寸完全继承 .uk-label(font-size/padding/line-height/text-transform 等),
|
|
||||||
仅覆盖 button 元素特有的默认样式(边框/字体族/光标等),保证与相邻 span 标签完全一致。 */
|
|
||||||
.tb-label-btn {
|
|
||||||
border: none !important;
|
|
||||||
cursor: pointer;
|
|
||||||
font-family: inherit;
|
|
||||||
margin: 0;
|
|
||||||
vertical-align: middle;
|
|
||||||
outline: none;
|
|
||||||
background-image: none;
|
|
||||||
box-sizing: border-box;
|
|
||||||
-webkit-appearance: none;
|
|
||||||
appearance: none;
|
|
||||||
}
|
|
||||||
.tb-label-btn:hover {
|
|
||||||
opacity: 0.85;
|
|
||||||
}
|
|
||||||
/* 公开页置顶小图标:仅一个图钉,不占行高、不影响原布局 */
|
|
||||||
.tb-pin-flag {
|
|
||||||
font-size: 0.9em;
|
|
||||||
margin-right: 4px;
|
|
||||||
vertical-align: -1px;
|
|
||||||
cursor: default;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Markdown 渲染排版(问题/回答/追问正文,左对齐以保留排版格式) */
|
|
||||||
/* 纯文本列表:保留换行与连续空格(pre-wrap),不渲染 Markdown 大字号/彩色 */
|
|
||||||
.tb-preline {
|
|
||||||
white-space: pre-wrap;
|
|
||||||
}
|
|
||||||
/* 纯文本列表:超过 5 行截断并显示省略号(不足 5 行则完整显示) */
|
|
||||||
.tb-clamp-5 {
|
|
||||||
display: -webkit-box;
|
|
||||||
-webkit-box-orient: vertical;
|
|
||||||
-webkit-line-clamp: 5;
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
.md-body {
|
|
||||||
line-height: 1.7;
|
|
||||||
text-align: left;
|
|
||||||
word-break: break-word;
|
|
||||||
}
|
|
||||||
.md-body p { margin: 0.5em 0; }
|
|
||||||
.md-body h1, .md-body h2, .md-body h3,
|
|
||||||
.md-body h4, .md-body h5, .md-body h6 {
|
|
||||||
margin: 0.8em 0 0.4em;
|
|
||||||
font-weight: 600;
|
|
||||||
line-height: 1.4;
|
|
||||||
}
|
|
||||||
.md-body ul, .md-body ol { padding-left: 1.6em; margin: 0.5em 0; }
|
|
||||||
.md-body li { margin: 0.2em 0; }
|
|
||||||
.md-body blockquote {
|
|
||||||
border-left: 3px solid #d3d1c7;
|
|
||||||
margin: 0.6em 0;
|
|
||||||
padding: 0.2em 1em;
|
|
||||||
color: #5f5e5a;
|
|
||||||
}
|
|
||||||
.md-body pre {
|
|
||||||
background: #f5f5f5;
|
|
||||||
padding: 0.8em 1em;
|
|
||||||
border-radius: 6px;
|
|
||||||
overflow-x: auto;
|
|
||||||
margin: 0.6em 0;
|
|
||||||
}
|
|
||||||
.md-body code {
|
|
||||||
background: #f0f0f0;
|
|
||||||
padding: 0.1em 0.35em;
|
|
||||||
border-radius: 4px;
|
|
||||||
font-size: 0.9em;
|
|
||||||
}
|
|
||||||
.md-body pre code { background: none; padding: 0; }
|
|
||||||
.md-body img { max-width: 100%; height: auto; }
|
|
||||||
.md-body table { border-collapse: collapse; margin: 0.6em 0; }
|
|
||||||
.md-body th, .md-body td {
|
|
||||||
border: 1px solid #ddd;
|
|
||||||
padding: 0.4em 0.8em;
|
|
||||||
}
|
|
||||||
.md-body hr { margin: 1em 0; }
|
|
||||||
html[data-theme="dark"] .md-body blockquote {
|
|
||||||
border-color: #3a404c;
|
|
||||||
color: #8b93a1;
|
|
||||||
}
|
|
||||||
html[data-theme="dark"] .md-body pre,
|
|
||||||
html[data-theme="dark"] .md-body code { background: #2d323c; }
|
|
||||||
html[data-theme="dark"] .md-body th,
|
|
||||||
html[data-theme="dark"] .md-body td { border-color: #3a404c; }
|
|
||||||
|
|
||||||
/* 投票结果占比条:模板已改用 UIkit 3 原生 <progress class="uk-progress" value max>,
|
|
||||||
这里只把默认的 15px 高 / 500px 圆角 / 20px 外边距收紧到与页面一致的规格。
|
|
||||||
(原先为 UIkit 2 的 .uk-progressbar 结构打的补丁已删除) */
|
|
||||||
.uk-progress {
|
|
||||||
height: 10px;
|
|
||||||
margin: 0;
|
|
||||||
border-radius: var(--tb-radius-xs);
|
|
||||||
background-color: var(--tb-surface-2);
|
|
||||||
}
|
|
||||||
.uk-progress::-webkit-progress-bar {
|
|
||||||
background-color: var(--tb-surface-2);
|
|
||||||
border-radius: var(--tb-radius-xs);
|
|
||||||
}
|
|
||||||
.uk-progress::-webkit-progress-value {
|
|
||||||
background-color: var(--tb-primary);
|
|
||||||
border-radius: var(--tb-radius-xs) 0 0 var(--tb-radius-xs);
|
|
||||||
}
|
|
||||||
.uk-progress::-moz-progress-bar {
|
|
||||||
background-color: var(--tb-primary);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 移动端底部操作栏:固定底栏承载语言切换与深色模式,桌面端隐藏 */
|
|
||||||
#tb-mobile-utils {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
@media (max-width: 640px) {
|
|
||||||
/* 顶栏不再容纳语言/深色按钮,恢复原有导航空间 */
|
|
||||||
.tb-nav-utils {
|
|
||||||
display: none !important;
|
|
||||||
}
|
|
||||||
/* 手机端隐藏登录用户名(左边仅保留"探索"),保证 logo 居中、
|
|
||||||
两侧各不超过 2 个短按钮,避免用户名宽度挤压布局 */
|
|
||||||
.tb-nav-username {
|
|
||||||
display: none !important;
|
|
||||||
}
|
|
||||||
/* 固定底部操作栏 */
|
|
||||||
#tb-mobile-utils {
|
|
||||||
display: flex;
|
|
||||||
position: fixed;
|
|
||||||
left: 0;
|
|
||||||
right: 0;
|
|
||||||
bottom: 0;
|
|
||||||
z-index: 1000;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
gap: 10px;
|
|
||||||
padding: 8px 12px calc(8px + env(safe-area-inset-bottom));
|
|
||||||
background: rgba(255, 255, 255, 0.92);
|
|
||||||
-webkit-backdrop-filter: blur(8px);
|
|
||||||
backdrop-filter: blur(8px);
|
|
||||||
box-shadow: 0 -2px 12px rgba(0, 0, 0, 0.08);
|
|
||||||
}
|
|
||||||
#tb-mobile-utils .uk-select {
|
|
||||||
width: 110px;
|
|
||||||
}
|
|
||||||
html[data-theme="dark"] #tb-mobile-utils {
|
|
||||||
background: rgba(36, 40, 48, 0.92);
|
|
||||||
box-shadow: 0 -2px 12px rgba(0, 0, 0, 0.4);
|
|
||||||
}
|
|
||||||
/* 给页面底部预留空间,避免页脚内容被固定底栏遮挡 */
|
|
||||||
body {
|
|
||||||
padding-bottom: 56px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
||||||
<link rel="stylesheet" href="https://r2.337845818.best/tamabox/cdn/waline/client/v2/waline-no-commits.css" media="print" onload="this.media='all'"/>
|
<link rel="stylesheet" href="https://r2.337845818.best/tamabox/cdn/waline/client/v2/waline-no-commits.css" media="print" onload="this.media='all'"/>
|
||||||
<script defer src="https://cdnjs.cloudflare.com/ajax/libs/uikit/3.3.3/js/uikit.min.js"></script>
|
<script defer src="https://cdnjs.cloudflare.com/ajax/libs/uikit/3.3.3/js/uikit.min.js"></script>
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
<title>预览 12:01 · TamaBox</title>
|
<title>预览 15:15 · TamaBox</title>
|
||||||
<meta name="msvalidate.01" content="2F185E8E63C93635F50B3574F3B31E42" />
|
<meta name="msvalidate.01" content="2F185E8E63C93635F50B3574F3B31E42" />
|
||||||
<meta name="description" content="狼的提问箱——一个无需注册、可匿名提问的匿名提问箱,安全地倾诉与回应。">
|
<meta name="description" content="狼的提问箱——一个无需注册、可匿名提问的匿名提问箱,安全地倾诉与回应。">
|
||||||
<meta name="keywords" content="匿名提问箱,提问箱,匿名提问,狼的提问箱,匿名问答,匿名提问网站">
|
<meta name="keywords" content="匿名提问箱,提问箱,匿名提问,狼的提问箱,匿名问答,匿名提问网站">
|
||||||
@@ -20,675 +20,8 @@
|
|||||||
|
|
||||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/uikit/3.3.3/css/uikit.min.css"/>
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/uikit/3.3.3/css/uikit.min.css"/>
|
||||||
|
|
||||||
<style>/* TamaBox 全站基础样式:设计令牌 / 主题覆盖 / 组件质感 / 响应式。
|
<link rel="stylesheet" href="/static/css/base.css?v="/>
|
||||||
由 base/header.html 内联块抽出,集中一份便于缓存与维护。
|
|
||||||
⚠️ 改完务必把 header 里的 ?v= 版本号 +1,否则老访客仍用缓存。 */
|
|
||||||
|
|
||||||
/* 设计令牌:亮色为默认(:root),深色在 html[data-theme="dark"] 覆盖。
|
|
||||||
页面与组件样式一律引用 var(--tb-*),不再写死色值/圆角/阴影;
|
|
||||||
var() 的第二个参数仅作兜底(旧缓存页、邮件模板等不引入本文件的场景)。
|
|
||||||
改配色只动这一块,亮暗两套自动保持一致。 */
|
|
||||||
:root {
|
|
||||||
--tb-bg: #f7f8fa;
|
|
||||||
--tb-surface: #ffffff;
|
|
||||||
--tb-surface-2: #f4f6f8;
|
|
||||||
--tb-surface-hover: #f3f7ff;
|
|
||||||
--tb-border: #e8eaee;
|
|
||||||
--tb-text: #1f2329;
|
|
||||||
--tb-text-secondary: #5c6370;
|
|
||||||
--tb-text-muted: #8a919c;
|
|
||||||
--tb-primary: #1e87f0;
|
|
||||||
--tb-primary-weak: rgba(30, 135, 240, 0.10);
|
|
||||||
--tb-radius: 12px;
|
|
||||||
--tb-radius-sm: 8px;
|
|
||||||
--tb-radius-xs: 6px;
|
|
||||||
--tb-shadow: 0 1px 2px rgba(16, 24, 40, 0.04), 0 12px 28px -18px rgba(16, 24, 40, 0.20);
|
|
||||||
--tb-shadow-hover: 0 1px 2px rgba(16, 24, 40, 0.05), 0 18px 40px -20px rgba(16, 24, 40, 0.28);
|
|
||||||
--tb-font: system-ui, -apple-system, "Segoe UI", "PingFang SC", "Hiragino Sans GB", "Noto Sans CJK SC", "Microsoft YaHei", sans-serif;
|
|
||||||
}
|
|
||||||
html[data-theme="dark"] {
|
|
||||||
--tb-bg: #1a1d23;
|
|
||||||
--tb-surface: #242830;
|
|
||||||
--tb-surface-2: #2d323c;
|
|
||||||
--tb-surface-hover: rgba(92, 141, 255, 0.12);
|
|
||||||
--tb-border: #3a404c;
|
|
||||||
--tb-text: #d8dce4;
|
|
||||||
--tb-text-secondary: #a8b0bd;
|
|
||||||
--tb-text-muted: #8b93a1;
|
|
||||||
--tb-primary: #5c8dff;
|
|
||||||
--tb-primary-weak: rgba(92, 141, 255, 0.14);
|
|
||||||
--tb-shadow: 0 1px 2px rgba(0, 0, 0, 0.30), 0 12px 28px -18px rgba(0, 0, 0, 0.55);
|
|
||||||
--tb-shadow-hover: 0 1px 2px rgba(0, 0, 0, 0.35), 0 18px 40px -20px rgba(0, 0, 0, 0.65);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* UIkit 补丁:复刻原自建版 "modify-black-font"(官方版与自建版仅 3 处颜色差异——把有色容器内默认白字/白标题改为黑字)。
|
|
||||||
模板当前只用到 .uk-light 容器(用户背景封面,question/list.html、question-not-found.html;
|
|
||||||
其中 h3/p 已由 #usernamecolor/#introcolor 内联 style 覆盖),故只需补该容器的 3 处投影即可保持渲染一致。
|
|
||||||
若日后新增 .uk-card-primary/.uk-card-secondary/.uk-section-primary/.uk-tile-*/.uk-overlay-primary 等容器且需黑字,须同步扩展。 */
|
|
||||||
.uk-light { color: rgba(0,0,0,.7); }
|
|
||||||
.uk-light .uk-h1, .uk-light .uk-h2, .uk-light .uk-h3, .uk-light .uk-h4, .uk-light .uk-h5, .uk-light .uk-h6,
|
|
||||||
.uk-light .uk-heading-2xlarge, .uk-light .uk-heading-large, .uk-light .uk-heading-medium, .uk-light .uk-heading-small, .uk-light .uk-heading-xlarge,
|
|
||||||
.uk-light h1, .uk-light h2, .uk-light h3, .uk-light h4, .uk-light h5, .uk-light h6 { color: #000; }
|
|
||||||
.uk-light .uk-table th { color: rgba(0,0,0,.7); }
|
|
||||||
|
|
||||||
.grecaptcha-badge {visibility: hidden;}
|
|
||||||
.icon-container {
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
.icon {
|
|
||||||
margin-left: 10px;
|
|
||||||
width: 20px; /* 设置图标的宽度 */
|
|
||||||
height: auto; /* 保持图标的高度自动调整 */
|
|
||||||
}
|
|
||||||
.emoji-placeholder {
|
|
||||||
display: inline-block;
|
|
||||||
animation: jump 0.5s ease-in-out;
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes jump {
|
|
||||||
0%, 100% { transform: translateY(0); }
|
|
||||||
50% { transform: translateY(-5px); }
|
|
||||||
}
|
|
||||||
/* 防止 UIkit Dropbar 初始闪烁 */
|
|
||||||
.uk-dropbar {
|
|
||||||
opacity: 0;
|
|
||||||
visibility: hidden;
|
|
||||||
transition: opacity 0.2s ease, visibility 0.2s ease;
|
|
||||||
}
|
|
||||||
|
|
||||||
.uk-dropbar.uk-open {
|
|
||||||
opacity: 1;
|
|
||||||
visibility: visible;
|
|
||||||
}
|
|
||||||
|
|
||||||
a.uk-button.uk-button-link {
|
|
||||||
text-transform: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 移动端优化:缩小字体和间距,避免右侧空白 */
|
|
||||||
@media (max-width: 640px) {
|
|
||||||
.uk-logo {
|
|
||||||
font-size: 1rem;
|
|
||||||
}
|
|
||||||
.uk-navbar-nav a {
|
|
||||||
font-size: 0.78rem;
|
|
||||||
padding: 0 4px;
|
|
||||||
}
|
|
||||||
.emoji-placeholder {
|
|
||||||
font-size: 1rem;
|
|
||||||
}
|
|
||||||
/* 移动端用户名限宽省略,避免长英文用户名撑爆顶栏 */
|
|
||||||
.tb-nav-username {
|
|
||||||
max-width: 64px;
|
|
||||||
overflow: hidden;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
white-space: nowrap;
|
|
||||||
display: inline-block;
|
|
||||||
vertical-align: middle;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 深色模式:html[data-theme="dark"] 时覆盖 UIkit 3.3.3 编译主题的关键颜色 */
|
|
||||||
/* 变量(--tb-*)已上移到 head 顶部的令牌块,亮暗两套同名常量在那里定义。 */
|
|
||||||
/* 根元素与 body 一起覆盖,确保整个视口(含内容不足一屏时的空白区)都是深色背景 */
|
|
||||||
html[data-theme="dark"],
|
|
||||||
html[data-theme="dark"] body {
|
|
||||||
background-color: var(--tb-bg) !important;
|
|
||||||
color: var(--tb-text) !important;
|
|
||||||
}
|
|
||||||
/* 通用表面容器 */
|
|
||||||
html[data-theme="dark"] .uk-card,
|
|
||||||
html[data-theme="dark"] .uk-card-default,
|
|
||||||
html[data-theme="dark"] .uk-card-secondary,
|
|
||||||
html[data-theme="dark"] .uk-dropbar,
|
|
||||||
html[data-theme="dark"] .uk-navbar-dropdown,
|
|
||||||
html[data-theme="dark"] .uk-modal-dialog,
|
|
||||||
html[data-theme="dark"] .uk-dropdown,
|
|
||||||
html[data-theme="dark"] .uk-offcanvas-bar,
|
|
||||||
html[data-theme="dark"] .uk-section,
|
|
||||||
html[data-theme="dark"] .uk-tile,
|
|
||||||
html[data-theme="dark"] .uk-panel,
|
|
||||||
html[data-theme="dark"] .uk-background-default,
|
|
||||||
html[data-theme="dark"] .uk-search-default .uk-search-input {
|
|
||||||
background-color: var(--tb-surface) !important;
|
|
||||||
color: var(--tb-text) !important;
|
|
||||||
}
|
|
||||||
html[data-theme="dark"] .uk-navbar-container {
|
|
||||||
background-color: var(--tb-surface) !important;
|
|
||||||
color: var(--tb-text) !important;
|
|
||||||
}
|
|
||||||
html[data-theme="dark"] .uk-navbar-nav > li > a,
|
|
||||||
html[data-theme="dark"] .uk-card a,
|
|
||||||
html[data-theme="dark"] .uk-link,
|
|
||||||
html[data-theme="dark"] a.uk-button-link,
|
|
||||||
html[data-theme="dark"] .uk-navbar-dropdown-nav > li > a,
|
|
||||||
html[data-theme="dark"] .uk-dropdown-nav > li > a,
|
|
||||||
html[data-theme="dark"] .uk-list a {
|
|
||||||
color: var(--tb-text) !important;
|
|
||||||
}
|
|
||||||
html[data-theme="dark"] .uk-navbar-nav > li > a:hover,
|
|
||||||
html[data-theme="dark"] .uk-card a:hover,
|
|
||||||
html[data-theme="dark"] .uk-navbar-dropdown-nav > li > a:hover,
|
|
||||||
html[data-theme="dark"] .uk-dropdown-nav > li > a:hover {
|
|
||||||
color: var(--tb-primary) !important;
|
|
||||||
}
|
|
||||||
html[data-theme="dark"] .uk-input,
|
|
||||||
html[data-theme="dark"] .uk-textarea,
|
|
||||||
html[data-theme="dark"] .uk-select {
|
|
||||||
background-color: var(--tb-surface-2) !important;
|
|
||||||
color: var(--tb-text) !important;
|
|
||||||
border-color: var(--tb-border) !important;
|
|
||||||
}
|
|
||||||
html[data-theme="dark"] .uk-input:focus,
|
|
||||||
html[data-theme="dark"] .uk-textarea:focus,
|
|
||||||
html[data-theme="dark"] .uk-select:focus {
|
|
||||||
border-color: var(--tb-primary) !important;
|
|
||||||
}
|
|
||||||
html[data-theme="dark"] .uk-text-muted,
|
|
||||||
html[data-theme="dark"] .uk-text-meta,
|
|
||||||
html[data-theme="dark"] .uk-text-secondary,
|
|
||||||
html[data-theme="dark"] .uk-text-muted a,
|
|
||||||
html[data-theme="dark"] .uk-text-small.uk-text-muted {
|
|
||||||
color: var(--tb-text-muted) !important;
|
|
||||||
}
|
|
||||||
html[data-theme="dark"] .uk-divider-icon::after,
|
|
||||||
html[data-theme="dark"] hr,
|
|
||||||
html[data-theme="dark"] .uk-table th,
|
|
||||||
html[data-theme="dark"] .uk-table td,
|
|
||||||
html[data-theme="dark"] .uk-list-divider > li:nth-child(n+2) {
|
|
||||||
border-color: var(--tb-border) !important;
|
|
||||||
}
|
|
||||||
html[data-theme="dark"] .uk-button-default {
|
|
||||||
background-color: var(--tb-surface-2) !important;
|
|
||||||
color: var(--tb-text) !important;
|
|
||||||
border-color: var(--tb-border) !important;
|
|
||||||
}
|
|
||||||
html[data-theme="dark"] .uk-modal-title,
|
|
||||||
html[data-theme="dark"] h1, html[data-theme="dark"] h2, html[data-theme="dark"] h3,
|
|
||||||
html[data-theme="dark"] h4, html[data-theme="dark"] h5, html[data-theme="dark"] h6,
|
|
||||||
html[data-theme="dark"] .uk-card-title {
|
|
||||||
color: var(--tb-text) !important;
|
|
||||||
}
|
|
||||||
html[data-theme="dark"] .uk-alert-warning,
|
|
||||||
html[data-theme="dark"] .uk-alert-danger,
|
|
||||||
html[data-theme="dark"] .uk-alert-success,
|
|
||||||
html[data-theme="dark"] .uk-alert-primary {
|
|
||||||
background-color: var(--tb-surface-2) !important;
|
|
||||||
color: var(--tb-text) !important;
|
|
||||||
}
|
|
||||||
html[data-theme="dark"] #math-captcha-modal .uk-modal-dialog {
|
|
||||||
background-color: var(--tb-surface) !important;
|
|
||||||
color: var(--tb-text) !important;
|
|
||||||
}
|
|
||||||
html[data-theme="dark"] #math-captcha-modal .captcha-equation-box {
|
|
||||||
background-color: var(--tb-surface-2) !important;
|
|
||||||
border-color: var(--tb-border) !important;
|
|
||||||
}
|
|
||||||
html[data-theme="dark"] #math-captcha-modal .math-captcha-modal-question {
|
|
||||||
color: var(--tb-text) !important;
|
|
||||||
}
|
|
||||||
html[data-theme="dark"] #math-captcha-modal #captcha-modal-answer {
|
|
||||||
background-color: var(--tb-surface) !important;
|
|
||||||
color: var(--tb-text) !important;
|
|
||||||
border-color: var(--tb-border) !important;
|
|
||||||
}
|
|
||||||
html[data-theme="dark"] #math-captcha-modal #captcha-modal-answer::placeholder {
|
|
||||||
color: var(--tb-text-muted) !important;
|
|
||||||
}
|
|
||||||
html[data-theme="dark"] #math-captcha-modal .uk-text-meta,
|
|
||||||
html[data-theme="dark"] #math-captcha-modal #captcha-modal-refresh {
|
|
||||||
color: var(--tb-text-muted) !important;
|
|
||||||
}
|
|
||||||
html[data-theme="dark"] #math-captcha-modal #captcha-modal-refresh:hover {
|
|
||||||
color: var(--tb-primary) !important;
|
|
||||||
}
|
|
||||||
html[data-theme="dark"] .uk-label {
|
|
||||||
color: #fff !important;
|
|
||||||
}
|
|
||||||
/* 自定义组件(探索页推荐卡片等)深色覆盖 */
|
|
||||||
html[data-theme="dark"] .recommend-card,
|
|
||||||
html[data-theme="dark"] .recommend-card:hover {
|
|
||||||
background-color: var(--tb-surface-2) !important;
|
|
||||||
}
|
|
||||||
html[data-theme="dark"] .explore-name a {
|
|
||||||
color: var(--tb-text) !important;
|
|
||||||
}
|
|
||||||
html[data-theme="dark"] .explore-name a:hover {
|
|
||||||
color: var(--tb-primary) !important;
|
|
||||||
}
|
|
||||||
html[data-theme="dark"] .explore-intro {
|
|
||||||
color: var(--tb-text-muted) !important;
|
|
||||||
}
|
|
||||||
/* 切换按钮图标切换(内联 SVG,不依赖 UIkit 图标库) */
|
|
||||||
#theme-toggle .tb-icon-light, #theme-toggle-mobile .tb-icon-light,
|
|
||||||
#theme-toggle .tb-icon-dark, #theme-toggle-mobile .tb-icon-dark {
|
|
||||||
display: inline-flex;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
#theme-toggle .tb-icon-light svg, #theme-toggle-mobile .tb-icon-light svg,
|
|
||||||
#theme-toggle .tb-icon-dark svg, #theme-toggle-mobile .tb-icon-dark svg { display: block; }
|
|
||||||
#theme-toggle .tb-icon-dark, #theme-toggle-mobile .tb-icon-dark { display: none; }
|
|
||||||
html[data-theme="dark"] #theme-toggle .tb-icon-light,
|
|
||||||
html[data-theme="dark"] #theme-toggle-mobile .tb-icon-light { display: none; }
|
|
||||||
html[data-theme="dark"] #theme-toggle .tb-icon-dark,
|
|
||||||
html[data-theme="dark"] #theme-toggle-mobile .tb-icon-dark { display: inline-flex; }
|
|
||||||
|
|
||||||
/* 基础质感层:只调整外观(圆角/投影/字体/数字对齐),不改任何结构与布局。
|
|
||||||
颜色一律取自头部令牌,亮暗两套自动生效,因此这里不需要再写 html[data-theme="dark"] 分支。 */
|
|
||||||
/* 根元素与 body 同时上色:内容不足一屏时,body 之外的视口区域也要是同一底色 */
|
|
||||||
html,
|
|
||||||
body {
|
|
||||||
font-family: var(--tb-font);
|
|
||||||
background-color: var(--tb-bg);
|
|
||||||
color: var(--tb-text);
|
|
||||||
-webkit-font-smoothing: antialiased;
|
|
||||||
-moz-osx-font-smoothing: grayscale;
|
|
||||||
}
|
|
||||||
/* 卡片:12px 圆角 + 一层极淡接触影 + 一层大扩散影(UIkit 默认的 0 5px 15px 偏硬) */
|
|
||||||
.uk-card {
|
|
||||||
border-radius: var(--tb-radius);
|
|
||||||
}
|
|
||||||
.uk-card-default {
|
|
||||||
background-color: var(--tb-surface);
|
|
||||||
box-shadow: var(--tb-shadow);
|
|
||||||
}
|
|
||||||
.uk-card-default.uk-card-hover:hover {
|
|
||||||
box-shadow: var(--tb-shadow-hover);
|
|
||||||
}
|
|
||||||
.uk-card-header {
|
|
||||||
border-radius: var(--tb-radius) var(--tb-radius) 0 0;
|
|
||||||
}
|
|
||||||
.uk-card-footer {
|
|
||||||
border-radius: 0 0 var(--tb-radius) var(--tb-radius);
|
|
||||||
}
|
|
||||||
.uk-card,
|
|
||||||
.uk-button,
|
|
||||||
.uk-alert,
|
|
||||||
.uk-label {
|
|
||||||
transition: box-shadow 0.18s ease, background-color 0.18s ease, border-color 0.18s ease, color 0.18s ease;
|
|
||||||
}
|
|
||||||
/* 交互元素:统一 8px 圆角,标签 6px */
|
|
||||||
.uk-button {
|
|
||||||
border-radius: var(--tb-radius-sm);
|
|
||||||
}
|
|
||||||
.uk-input,
|
|
||||||
.uk-select,
|
|
||||||
.uk-textarea,
|
|
||||||
.uk-form-small,
|
|
||||||
.uk-search-input {
|
|
||||||
border-radius: var(--tb-radius-sm);
|
|
||||||
}
|
|
||||||
.uk-label {
|
|
||||||
border-radius: var(--tb-radius-xs);
|
|
||||||
}
|
|
||||||
.uk-alert {
|
|
||||||
border-radius: 10px;
|
|
||||||
}
|
|
||||||
.uk-modal-dialog {
|
|
||||||
border-radius: 14px;
|
|
||||||
}
|
|
||||||
.uk-dropdown,
|
|
||||||
.uk-navbar-dropdown {
|
|
||||||
border-radius: 10px;
|
|
||||||
box-shadow: var(--tb-shadow);
|
|
||||||
}
|
|
||||||
.uk-navbar-container:not(.uk-navbar-transparent) {
|
|
||||||
background-color: var(--tb-surface);
|
|
||||||
}
|
|
||||||
/* 键盘可达性:仅在键盘聚焦时出现描边,鼠标点击不出现 */
|
|
||||||
.uk-button:focus-visible,
|
|
||||||
.uk-navbar-nav > li > a:focus-visible {
|
|
||||||
outline: 2px solid var(--tb-primary);
|
|
||||||
outline-offset: 2px;
|
|
||||||
}
|
|
||||||
/* 次要文字统一走令牌,避免 #999 / #8a919c 混用 */
|
|
||||||
.uk-text-muted,
|
|
||||||
.uk-text-meta {
|
|
||||||
color: var(--tb-text-muted);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 轻量胶囊:用于投票类型、热门标签等「只是分类信息」的位置。
|
|
||||||
实心 uk-label 一屏多个会变成一排色块,这里统一降级为浅底 + 次要色文字。 */
|
|
||||||
.tb-chip {
|
|
||||||
display: inline-block;
|
|
||||||
padding: 1px 8px;
|
|
||||||
border-radius: var(--tb-radius-xs);
|
|
||||||
background-color: var(--tb-surface-2);
|
|
||||||
color: var(--tb-text-secondary);
|
|
||||||
font-size: 0.72rem;
|
|
||||||
line-height: 1.7;
|
|
||||||
white-space: nowrap;
|
|
||||||
}
|
|
||||||
a.tb-chip:hover {
|
|
||||||
background-color: var(--tb-primary-weak);
|
|
||||||
color: var(--tb-primary);
|
|
||||||
text-decoration: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 统计/日期等数字列等宽对齐,避免刷新时左右跳动 */
|
|
||||||
.uk-table,
|
|
||||||
.tb-num {
|
|
||||||
font-variant-numeric: tabular-nums;
|
|
||||||
}
|
|
||||||
/* 图片上传条:原为 item/new-question 两处各写一份内联 style(写死 #f8f8f8,深色下露白),
|
|
||||||
收敛到一处并走令牌,亮暗自动适配 */
|
|
||||||
.tb-img-uploader {
|
|
||||||
width: 100%;
|
|
||||||
background-color: var(--tb-surface-2);
|
|
||||||
display: flex;
|
|
||||||
padding-top: 5px;
|
|
||||||
padding-bottom: 5px;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: flex-start;
|
|
||||||
gap: 5px;
|
|
||||||
}
|
|
||||||
/* 背景图封面(提问箱主页):渐变遮罩,保证用户自选文字色叠加后仍可读。
|
|
||||||
默认浅色遮罩(页面 .uk-light 补丁把文字兜底成深色);若箱主选了浅色文字,
|
|
||||||
question/list.html 会按亮度加上 .tb-cover-dark 换成深色遮罩。 */
|
|
||||||
.tb-cover {
|
|
||||||
position: relative;
|
|
||||||
border-radius: var(--tb-radius) var(--tb-radius) 0 0;
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
/* ⚠️ 必须带 .uk-flex 复合选择器:UIkit 3.3.3 里有
|
|
||||||
.uk-flex::after,.uk-flex::before{display:none}(优先级 0,2,0),
|
|
||||||
会把这个遮罩伪元素整个干掉——不报错、只是什么都不显示(踩过一次)。
|
|
||||||
单写 .tb-cover::after 优先级不够,会被它压回 display:none。 */
|
|
||||||
.tb-cover::after,
|
|
||||||
.tb-cover.uk-flex::after {
|
|
||||||
content: "";
|
|
||||||
display: block;
|
|
||||||
position: absolute;
|
|
||||||
inset: 0;
|
|
||||||
z-index: 0;
|
|
||||||
background: linear-gradient(180deg, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.58) 55%, rgba(255, 255, 255, 0.84) 100%);
|
|
||||||
pointer-events: none;
|
|
||||||
}
|
|
||||||
.tb-cover.tb-cover-dark::after {
|
|
||||||
background: linear-gradient(180deg, rgba(0, 0, 0, 0) 0%, rgba(0, 0, 0, 0.16) 45%, rgba(0, 0, 0, 0.46) 100%);
|
|
||||||
}
|
|
||||||
.tb-cover > * {
|
|
||||||
position: relative;
|
|
||||||
z-index: 1;
|
|
||||||
}
|
|
||||||
.tb-cover h3,
|
|
||||||
.tb-cover p {
|
|
||||||
text-shadow: 0 1px 10px rgba(255, 255, 255, 0.65);
|
|
||||||
}
|
|
||||||
.tb-cover.tb-cover-dark h3,
|
|
||||||
.tb-cover.tb-cover-dark p {
|
|
||||||
text-shadow: 0 1px 12px rgba(0, 0, 0, 0.45);
|
|
||||||
}
|
|
||||||
/* 尊重系统的减少动效设置 */
|
|
||||||
@media (prefers-reduced-motion: reduce) {
|
|
||||||
.uk-card,
|
|
||||||
.uk-button,
|
|
||||||
.emoji-placeholder {
|
|
||||||
transition: none;
|
|
||||||
animation: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 顶栏自适应:导航全部直接显示,窄屏时分级缩小字号/间距,保证英文/日文等长文字不溢出 */
|
|
||||||
.uk-navbar-nav a {
|
|
||||||
font-size: 0.95rem;
|
|
||||||
padding: 0 10px;
|
|
||||||
}
|
|
||||||
/* 未登录移动端占位:桌面端隐藏,仅 ≤640px 显示(见下方 media 查询)。
|
|
||||||
桌面端布局与改动前完全一致,不受影响。 */
|
|
||||||
.tb-mobile-balancer { display: none; }
|
|
||||||
/* 桌面端保持 UIkit 原生居中三列布局(无需额外 CSS) */
|
|
||||||
.tb-navbar .uk-logo {
|
|
||||||
white-space: nowrap;
|
|
||||||
}
|
|
||||||
@media (max-width: 1200px) {
|
|
||||||
.uk-navbar-nav a {
|
|
||||||
font-size: 0.88rem;
|
|
||||||
padding: 0 8px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@media (max-width: 1000px) {
|
|
||||||
.uk-navbar-nav a {
|
|
||||||
font-size: 0.82rem;
|
|
||||||
padding: 0 6px;
|
|
||||||
}
|
|
||||||
.uk-logo {
|
|
||||||
font-size: 1.1rem;
|
|
||||||
}
|
|
||||||
/* 登录用户名限宽,过长省略号截断 */
|
|
||||||
.tb-nav-username {
|
|
||||||
max-width: 110px;
|
|
||||||
overflow: hidden;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
white-space: nowrap;
|
|
||||||
display: inline-block;
|
|
||||||
vertical-align: middle;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@media (max-width: 800px) {
|
|
||||||
.uk-navbar-nav a {
|
|
||||||
font-size: 0.78rem;
|
|
||||||
padding: 0 4px;
|
|
||||||
}
|
|
||||||
.uk-logo {
|
|
||||||
font-size: 1rem;
|
|
||||||
}
|
|
||||||
.tb-nav-username {
|
|
||||||
max-width: 80px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* 手机端(≤640px):沿用 UIkit 桌面端 navbar 的原生三列定位。
|
|
||||||
不再重写 .uk-navbar-center / center-left / center-right 的定位,
|
|
||||||
避免 logo 被挤到下一行;底部语言与深色模式按钮仍由下方独立栏承载。 */
|
|
||||||
@media (max-width: 640px) {
|
|
||||||
.tb-navbar {
|
|
||||||
position: relative;
|
|
||||||
min-height: 56px;
|
|
||||||
overflow: visible;
|
|
||||||
}
|
|
||||||
.tb-navbar > .uk-navbar-center {
|
|
||||||
position: relative !important;
|
|
||||||
top: auto !important;
|
|
||||||
left: auto !important;
|
|
||||||
right: auto !important;
|
|
||||||
bottom: auto !important;
|
|
||||||
transform: none !important;
|
|
||||||
display: flex !important;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
width: 100%;
|
|
||||||
min-height: 56px;
|
|
||||||
white-space: nowrap;
|
|
||||||
flex-wrap: nowrap;
|
|
||||||
}
|
|
||||||
.tb-navbar .uk-navbar-center-left,
|
|
||||||
.tb-navbar .uk-navbar-center-right {
|
|
||||||
position: static !important;
|
|
||||||
top: auto !important;
|
|
||||||
left: auto !important;
|
|
||||||
right: auto !important;
|
|
||||||
bottom: auto !important;
|
|
||||||
transform: none !important;
|
|
||||||
display: flex !important;
|
|
||||||
align-items: center;
|
|
||||||
flex: 0 0 auto;
|
|
||||||
white-space: nowrap;
|
|
||||||
}
|
|
||||||
.tb-navbar .uk-navbar-center-left > div,
|
|
||||||
.tb-navbar .uk-navbar-center-right > div {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
white-space: nowrap;
|
|
||||||
}
|
|
||||||
.tb-navbar .uk-navbar-nav {
|
|
||||||
display: flex;
|
|
||||||
flex-wrap: nowrap;
|
|
||||||
flex: 0 0 auto;
|
|
||||||
}
|
|
||||||
.tb-navbar .uk-navbar-nav > li > a,
|
|
||||||
.tb-navbar .uk-logo {
|
|
||||||
white-space: nowrap;
|
|
||||||
}
|
|
||||||
/* 未登录:移动端显示与「我的」等宽的隐藏占位,使左栏「探索+占位」与
|
|
||||||
右栏「注册/登录」两项等宽,logo 真正居中,左右视觉平衡 */
|
|
||||||
.tb-mobile-balancer { display: block; }
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 标签样式的按钮(管理页置顶等):
|
|
||||||
尺寸完全继承 .uk-label(font-size/padding/line-height/text-transform 等),
|
|
||||||
仅覆盖 button 元素特有的默认样式(边框/字体族/光标等),保证与相邻 span 标签完全一致。 */
|
|
||||||
.tb-label-btn {
|
|
||||||
border: none !important;
|
|
||||||
cursor: pointer;
|
|
||||||
font-family: inherit;
|
|
||||||
margin: 0;
|
|
||||||
vertical-align: middle;
|
|
||||||
outline: none;
|
|
||||||
background-image: none;
|
|
||||||
box-sizing: border-box;
|
|
||||||
-webkit-appearance: none;
|
|
||||||
appearance: none;
|
|
||||||
}
|
|
||||||
.tb-label-btn:hover {
|
|
||||||
opacity: 0.85;
|
|
||||||
}
|
|
||||||
/* 公开页置顶小图标:仅一个图钉,不占行高、不影响原布局 */
|
|
||||||
.tb-pin-flag {
|
|
||||||
font-size: 0.9em;
|
|
||||||
margin-right: 4px;
|
|
||||||
vertical-align: -1px;
|
|
||||||
cursor: default;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Markdown 渲染排版(问题/回答/追问正文,左对齐以保留排版格式) */
|
|
||||||
/* 纯文本列表:保留换行与连续空格(pre-wrap),不渲染 Markdown 大字号/彩色 */
|
|
||||||
.tb-preline {
|
|
||||||
white-space: pre-wrap;
|
|
||||||
}
|
|
||||||
/* 纯文本列表:超过 5 行截断并显示省略号(不足 5 行则完整显示) */
|
|
||||||
.tb-clamp-5 {
|
|
||||||
display: -webkit-box;
|
|
||||||
-webkit-box-orient: vertical;
|
|
||||||
-webkit-line-clamp: 5;
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
.md-body {
|
|
||||||
line-height: 1.7;
|
|
||||||
text-align: left;
|
|
||||||
word-break: break-word;
|
|
||||||
}
|
|
||||||
.md-body p { margin: 0.5em 0; }
|
|
||||||
.md-body h1, .md-body h2, .md-body h3,
|
|
||||||
.md-body h4, .md-body h5, .md-body h6 {
|
|
||||||
margin: 0.8em 0 0.4em;
|
|
||||||
font-weight: 600;
|
|
||||||
line-height: 1.4;
|
|
||||||
}
|
|
||||||
.md-body ul, .md-body ol { padding-left: 1.6em; margin: 0.5em 0; }
|
|
||||||
.md-body li { margin: 0.2em 0; }
|
|
||||||
.md-body blockquote {
|
|
||||||
border-left: 3px solid #d3d1c7;
|
|
||||||
margin: 0.6em 0;
|
|
||||||
padding: 0.2em 1em;
|
|
||||||
color: #5f5e5a;
|
|
||||||
}
|
|
||||||
.md-body pre {
|
|
||||||
background: #f5f5f5;
|
|
||||||
padding: 0.8em 1em;
|
|
||||||
border-radius: 6px;
|
|
||||||
overflow-x: auto;
|
|
||||||
margin: 0.6em 0;
|
|
||||||
}
|
|
||||||
.md-body code {
|
|
||||||
background: #f0f0f0;
|
|
||||||
padding: 0.1em 0.35em;
|
|
||||||
border-radius: 4px;
|
|
||||||
font-size: 0.9em;
|
|
||||||
}
|
|
||||||
.md-body pre code { background: none; padding: 0; }
|
|
||||||
.md-body img { max-width: 100%; height: auto; }
|
|
||||||
.md-body table { border-collapse: collapse; margin: 0.6em 0; }
|
|
||||||
.md-body th, .md-body td {
|
|
||||||
border: 1px solid #ddd;
|
|
||||||
padding: 0.4em 0.8em;
|
|
||||||
}
|
|
||||||
.md-body hr { margin: 1em 0; }
|
|
||||||
html[data-theme="dark"] .md-body blockquote {
|
|
||||||
border-color: #3a404c;
|
|
||||||
color: #8b93a1;
|
|
||||||
}
|
|
||||||
html[data-theme="dark"] .md-body pre,
|
|
||||||
html[data-theme="dark"] .md-body code { background: #2d323c; }
|
|
||||||
html[data-theme="dark"] .md-body th,
|
|
||||||
html[data-theme="dark"] .md-body td { border-color: #3a404c; }
|
|
||||||
|
|
||||||
/* 投票结果占比条:模板已改用 UIkit 3 原生 <progress class="uk-progress" value max>,
|
|
||||||
这里只把默认的 15px 高 / 500px 圆角 / 20px 外边距收紧到与页面一致的规格。
|
|
||||||
(原先为 UIkit 2 的 .uk-progressbar 结构打的补丁已删除) */
|
|
||||||
.uk-progress {
|
|
||||||
height: 10px;
|
|
||||||
margin: 0;
|
|
||||||
border-radius: var(--tb-radius-xs);
|
|
||||||
background-color: var(--tb-surface-2);
|
|
||||||
}
|
|
||||||
.uk-progress::-webkit-progress-bar {
|
|
||||||
background-color: var(--tb-surface-2);
|
|
||||||
border-radius: var(--tb-radius-xs);
|
|
||||||
}
|
|
||||||
.uk-progress::-webkit-progress-value {
|
|
||||||
background-color: var(--tb-primary);
|
|
||||||
border-radius: var(--tb-radius-xs) 0 0 var(--tb-radius-xs);
|
|
||||||
}
|
|
||||||
.uk-progress::-moz-progress-bar {
|
|
||||||
background-color: var(--tb-primary);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 移动端底部操作栏:固定底栏承载语言切换与深色模式,桌面端隐藏 */
|
|
||||||
#tb-mobile-utils {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
@media (max-width: 640px) {
|
|
||||||
/* 顶栏不再容纳语言/深色按钮,恢复原有导航空间 */
|
|
||||||
.tb-nav-utils {
|
|
||||||
display: none !important;
|
|
||||||
}
|
|
||||||
/* 手机端隐藏登录用户名(左边仅保留"探索"),保证 logo 居中、
|
|
||||||
两侧各不超过 2 个短按钮,避免用户名宽度挤压布局 */
|
|
||||||
.tb-nav-username {
|
|
||||||
display: none !important;
|
|
||||||
}
|
|
||||||
/* 固定底部操作栏 */
|
|
||||||
#tb-mobile-utils {
|
|
||||||
display: flex;
|
|
||||||
position: fixed;
|
|
||||||
left: 0;
|
|
||||||
right: 0;
|
|
||||||
bottom: 0;
|
|
||||||
z-index: 1000;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
gap: 10px;
|
|
||||||
padding: 8px 12px calc(8px + env(safe-area-inset-bottom));
|
|
||||||
background: rgba(255, 255, 255, 0.92);
|
|
||||||
-webkit-backdrop-filter: blur(8px);
|
|
||||||
backdrop-filter: blur(8px);
|
|
||||||
box-shadow: 0 -2px 12px rgba(0, 0, 0, 0.08);
|
|
||||||
}
|
|
||||||
#tb-mobile-utils .uk-select {
|
|
||||||
width: 110px;
|
|
||||||
}
|
|
||||||
html[data-theme="dark"] #tb-mobile-utils {
|
|
||||||
background: rgba(36, 40, 48, 0.92);
|
|
||||||
box-shadow: 0 -2px 12px rgba(0, 0, 0, 0.4);
|
|
||||||
}
|
|
||||||
/* 给页面底部预留空间,避免页脚内容被固定底栏遮挡 */
|
|
||||||
body {
|
|
||||||
padding-bottom: 56px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
||||||
<link rel="stylesheet" href="https://r2.337845818.best/tamabox/cdn/waline/client/v2/waline-no-commits.css" media="print" onload="this.media='all'"/>
|
<link rel="stylesheet" href="https://r2.337845818.best/tamabox/cdn/waline/client/v2/waline-no-commits.css" media="print" onload="this.media='all'"/>
|
||||||
<script defer src="https://cdnjs.cloudflare.com/ajax/libs/uikit/3.3.3/js/uikit.min.js"></script>
|
<script defer src="https://cdnjs.cloudflare.com/ajax/libs/uikit/3.3.3/js/uikit.min.js"></script>
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
<title>预览 12:01 · TamaBox</title>
|
<title>预览 15:15 · TamaBox</title>
|
||||||
<meta name="msvalidate.01" content="2F185E8E63C93635F50B3574F3B31E42" />
|
<meta name="msvalidate.01" content="2F185E8E63C93635F50B3574F3B31E42" />
|
||||||
<meta name="description" content="狼的提问箱——一个无需注册、可匿名提问的匿名提问箱,安全地倾诉与回应。">
|
<meta name="description" content="狼的提问箱——一个无需注册、可匿名提问的匿名提问箱,安全地倾诉与回应。">
|
||||||
<meta name="keywords" content="匿名提问箱,提问箱,匿名提问,狼的提问箱,匿名问答,匿名提问网站">
|
<meta name="keywords" content="匿名提问箱,提问箱,匿名提问,狼的提问箱,匿名问答,匿名提问网站">
|
||||||
@@ -20,675 +20,8 @@
|
|||||||
|
|
||||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/uikit/3.3.3/css/uikit.min.css"/>
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/uikit/3.3.3/css/uikit.min.css"/>
|
||||||
|
|
||||||
<style>/* TamaBox 全站基础样式:设计令牌 / 主题覆盖 / 组件质感 / 响应式。
|
<link rel="stylesheet" href="/static/css/base.css?v="/>
|
||||||
由 base/header.html 内联块抽出,集中一份便于缓存与维护。
|
|
||||||
⚠️ 改完务必把 header 里的 ?v= 版本号 +1,否则老访客仍用缓存。 */
|
|
||||||
|
|
||||||
/* 设计令牌:亮色为默认(:root),深色在 html[data-theme="dark"] 覆盖。
|
|
||||||
页面与组件样式一律引用 var(--tb-*),不再写死色值/圆角/阴影;
|
|
||||||
var() 的第二个参数仅作兜底(旧缓存页、邮件模板等不引入本文件的场景)。
|
|
||||||
改配色只动这一块,亮暗两套自动保持一致。 */
|
|
||||||
:root {
|
|
||||||
--tb-bg: #f7f8fa;
|
|
||||||
--tb-surface: #ffffff;
|
|
||||||
--tb-surface-2: #f4f6f8;
|
|
||||||
--tb-surface-hover: #f3f7ff;
|
|
||||||
--tb-border: #e8eaee;
|
|
||||||
--tb-text: #1f2329;
|
|
||||||
--tb-text-secondary: #5c6370;
|
|
||||||
--tb-text-muted: #8a919c;
|
|
||||||
--tb-primary: #1e87f0;
|
|
||||||
--tb-primary-weak: rgba(30, 135, 240, 0.10);
|
|
||||||
--tb-radius: 12px;
|
|
||||||
--tb-radius-sm: 8px;
|
|
||||||
--tb-radius-xs: 6px;
|
|
||||||
--tb-shadow: 0 1px 2px rgba(16, 24, 40, 0.04), 0 12px 28px -18px rgba(16, 24, 40, 0.20);
|
|
||||||
--tb-shadow-hover: 0 1px 2px rgba(16, 24, 40, 0.05), 0 18px 40px -20px rgba(16, 24, 40, 0.28);
|
|
||||||
--tb-font: system-ui, -apple-system, "Segoe UI", "PingFang SC", "Hiragino Sans GB", "Noto Sans CJK SC", "Microsoft YaHei", sans-serif;
|
|
||||||
}
|
|
||||||
html[data-theme="dark"] {
|
|
||||||
--tb-bg: #1a1d23;
|
|
||||||
--tb-surface: #242830;
|
|
||||||
--tb-surface-2: #2d323c;
|
|
||||||
--tb-surface-hover: rgba(92, 141, 255, 0.12);
|
|
||||||
--tb-border: #3a404c;
|
|
||||||
--tb-text: #d8dce4;
|
|
||||||
--tb-text-secondary: #a8b0bd;
|
|
||||||
--tb-text-muted: #8b93a1;
|
|
||||||
--tb-primary: #5c8dff;
|
|
||||||
--tb-primary-weak: rgba(92, 141, 255, 0.14);
|
|
||||||
--tb-shadow: 0 1px 2px rgba(0, 0, 0, 0.30), 0 12px 28px -18px rgba(0, 0, 0, 0.55);
|
|
||||||
--tb-shadow-hover: 0 1px 2px rgba(0, 0, 0, 0.35), 0 18px 40px -20px rgba(0, 0, 0, 0.65);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* UIkit 补丁:复刻原自建版 "modify-black-font"(官方版与自建版仅 3 处颜色差异——把有色容器内默认白字/白标题改为黑字)。
|
|
||||||
模板当前只用到 .uk-light 容器(用户背景封面,question/list.html、question-not-found.html;
|
|
||||||
其中 h3/p 已由 #usernamecolor/#introcolor 内联 style 覆盖),故只需补该容器的 3 处投影即可保持渲染一致。
|
|
||||||
若日后新增 .uk-card-primary/.uk-card-secondary/.uk-section-primary/.uk-tile-*/.uk-overlay-primary 等容器且需黑字,须同步扩展。 */
|
|
||||||
.uk-light { color: rgba(0,0,0,.7); }
|
|
||||||
.uk-light .uk-h1, .uk-light .uk-h2, .uk-light .uk-h3, .uk-light .uk-h4, .uk-light .uk-h5, .uk-light .uk-h6,
|
|
||||||
.uk-light .uk-heading-2xlarge, .uk-light .uk-heading-large, .uk-light .uk-heading-medium, .uk-light .uk-heading-small, .uk-light .uk-heading-xlarge,
|
|
||||||
.uk-light h1, .uk-light h2, .uk-light h3, .uk-light h4, .uk-light h5, .uk-light h6 { color: #000; }
|
|
||||||
.uk-light .uk-table th { color: rgba(0,0,0,.7); }
|
|
||||||
|
|
||||||
.grecaptcha-badge {visibility: hidden;}
|
|
||||||
.icon-container {
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
.icon {
|
|
||||||
margin-left: 10px;
|
|
||||||
width: 20px; /* 设置图标的宽度 */
|
|
||||||
height: auto; /* 保持图标的高度自动调整 */
|
|
||||||
}
|
|
||||||
.emoji-placeholder {
|
|
||||||
display: inline-block;
|
|
||||||
animation: jump 0.5s ease-in-out;
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes jump {
|
|
||||||
0%, 100% { transform: translateY(0); }
|
|
||||||
50% { transform: translateY(-5px); }
|
|
||||||
}
|
|
||||||
/* 防止 UIkit Dropbar 初始闪烁 */
|
|
||||||
.uk-dropbar {
|
|
||||||
opacity: 0;
|
|
||||||
visibility: hidden;
|
|
||||||
transition: opacity 0.2s ease, visibility 0.2s ease;
|
|
||||||
}
|
|
||||||
|
|
||||||
.uk-dropbar.uk-open {
|
|
||||||
opacity: 1;
|
|
||||||
visibility: visible;
|
|
||||||
}
|
|
||||||
|
|
||||||
a.uk-button.uk-button-link {
|
|
||||||
text-transform: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 移动端优化:缩小字体和间距,避免右侧空白 */
|
|
||||||
@media (max-width: 640px) {
|
|
||||||
.uk-logo {
|
|
||||||
font-size: 1rem;
|
|
||||||
}
|
|
||||||
.uk-navbar-nav a {
|
|
||||||
font-size: 0.78rem;
|
|
||||||
padding: 0 4px;
|
|
||||||
}
|
|
||||||
.emoji-placeholder {
|
|
||||||
font-size: 1rem;
|
|
||||||
}
|
|
||||||
/* 移动端用户名限宽省略,避免长英文用户名撑爆顶栏 */
|
|
||||||
.tb-nav-username {
|
|
||||||
max-width: 64px;
|
|
||||||
overflow: hidden;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
white-space: nowrap;
|
|
||||||
display: inline-block;
|
|
||||||
vertical-align: middle;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 深色模式:html[data-theme="dark"] 时覆盖 UIkit 3.3.3 编译主题的关键颜色 */
|
|
||||||
/* 变量(--tb-*)已上移到 head 顶部的令牌块,亮暗两套同名常量在那里定义。 */
|
|
||||||
/* 根元素与 body 一起覆盖,确保整个视口(含内容不足一屏时的空白区)都是深色背景 */
|
|
||||||
html[data-theme="dark"],
|
|
||||||
html[data-theme="dark"] body {
|
|
||||||
background-color: var(--tb-bg) !important;
|
|
||||||
color: var(--tb-text) !important;
|
|
||||||
}
|
|
||||||
/* 通用表面容器 */
|
|
||||||
html[data-theme="dark"] .uk-card,
|
|
||||||
html[data-theme="dark"] .uk-card-default,
|
|
||||||
html[data-theme="dark"] .uk-card-secondary,
|
|
||||||
html[data-theme="dark"] .uk-dropbar,
|
|
||||||
html[data-theme="dark"] .uk-navbar-dropdown,
|
|
||||||
html[data-theme="dark"] .uk-modal-dialog,
|
|
||||||
html[data-theme="dark"] .uk-dropdown,
|
|
||||||
html[data-theme="dark"] .uk-offcanvas-bar,
|
|
||||||
html[data-theme="dark"] .uk-section,
|
|
||||||
html[data-theme="dark"] .uk-tile,
|
|
||||||
html[data-theme="dark"] .uk-panel,
|
|
||||||
html[data-theme="dark"] .uk-background-default,
|
|
||||||
html[data-theme="dark"] .uk-search-default .uk-search-input {
|
|
||||||
background-color: var(--tb-surface) !important;
|
|
||||||
color: var(--tb-text) !important;
|
|
||||||
}
|
|
||||||
html[data-theme="dark"] .uk-navbar-container {
|
|
||||||
background-color: var(--tb-surface) !important;
|
|
||||||
color: var(--tb-text) !important;
|
|
||||||
}
|
|
||||||
html[data-theme="dark"] .uk-navbar-nav > li > a,
|
|
||||||
html[data-theme="dark"] .uk-card a,
|
|
||||||
html[data-theme="dark"] .uk-link,
|
|
||||||
html[data-theme="dark"] a.uk-button-link,
|
|
||||||
html[data-theme="dark"] .uk-navbar-dropdown-nav > li > a,
|
|
||||||
html[data-theme="dark"] .uk-dropdown-nav > li > a,
|
|
||||||
html[data-theme="dark"] .uk-list a {
|
|
||||||
color: var(--tb-text) !important;
|
|
||||||
}
|
|
||||||
html[data-theme="dark"] .uk-navbar-nav > li > a:hover,
|
|
||||||
html[data-theme="dark"] .uk-card a:hover,
|
|
||||||
html[data-theme="dark"] .uk-navbar-dropdown-nav > li > a:hover,
|
|
||||||
html[data-theme="dark"] .uk-dropdown-nav > li > a:hover {
|
|
||||||
color: var(--tb-primary) !important;
|
|
||||||
}
|
|
||||||
html[data-theme="dark"] .uk-input,
|
|
||||||
html[data-theme="dark"] .uk-textarea,
|
|
||||||
html[data-theme="dark"] .uk-select {
|
|
||||||
background-color: var(--tb-surface-2) !important;
|
|
||||||
color: var(--tb-text) !important;
|
|
||||||
border-color: var(--tb-border) !important;
|
|
||||||
}
|
|
||||||
html[data-theme="dark"] .uk-input:focus,
|
|
||||||
html[data-theme="dark"] .uk-textarea:focus,
|
|
||||||
html[data-theme="dark"] .uk-select:focus {
|
|
||||||
border-color: var(--tb-primary) !important;
|
|
||||||
}
|
|
||||||
html[data-theme="dark"] .uk-text-muted,
|
|
||||||
html[data-theme="dark"] .uk-text-meta,
|
|
||||||
html[data-theme="dark"] .uk-text-secondary,
|
|
||||||
html[data-theme="dark"] .uk-text-muted a,
|
|
||||||
html[data-theme="dark"] .uk-text-small.uk-text-muted {
|
|
||||||
color: var(--tb-text-muted) !important;
|
|
||||||
}
|
|
||||||
html[data-theme="dark"] .uk-divider-icon::after,
|
|
||||||
html[data-theme="dark"] hr,
|
|
||||||
html[data-theme="dark"] .uk-table th,
|
|
||||||
html[data-theme="dark"] .uk-table td,
|
|
||||||
html[data-theme="dark"] .uk-list-divider > li:nth-child(n+2) {
|
|
||||||
border-color: var(--tb-border) !important;
|
|
||||||
}
|
|
||||||
html[data-theme="dark"] .uk-button-default {
|
|
||||||
background-color: var(--tb-surface-2) !important;
|
|
||||||
color: var(--tb-text) !important;
|
|
||||||
border-color: var(--tb-border) !important;
|
|
||||||
}
|
|
||||||
html[data-theme="dark"] .uk-modal-title,
|
|
||||||
html[data-theme="dark"] h1, html[data-theme="dark"] h2, html[data-theme="dark"] h3,
|
|
||||||
html[data-theme="dark"] h4, html[data-theme="dark"] h5, html[data-theme="dark"] h6,
|
|
||||||
html[data-theme="dark"] .uk-card-title {
|
|
||||||
color: var(--tb-text) !important;
|
|
||||||
}
|
|
||||||
html[data-theme="dark"] .uk-alert-warning,
|
|
||||||
html[data-theme="dark"] .uk-alert-danger,
|
|
||||||
html[data-theme="dark"] .uk-alert-success,
|
|
||||||
html[data-theme="dark"] .uk-alert-primary {
|
|
||||||
background-color: var(--tb-surface-2) !important;
|
|
||||||
color: var(--tb-text) !important;
|
|
||||||
}
|
|
||||||
html[data-theme="dark"] #math-captcha-modal .uk-modal-dialog {
|
|
||||||
background-color: var(--tb-surface) !important;
|
|
||||||
color: var(--tb-text) !important;
|
|
||||||
}
|
|
||||||
html[data-theme="dark"] #math-captcha-modal .captcha-equation-box {
|
|
||||||
background-color: var(--tb-surface-2) !important;
|
|
||||||
border-color: var(--tb-border) !important;
|
|
||||||
}
|
|
||||||
html[data-theme="dark"] #math-captcha-modal .math-captcha-modal-question {
|
|
||||||
color: var(--tb-text) !important;
|
|
||||||
}
|
|
||||||
html[data-theme="dark"] #math-captcha-modal #captcha-modal-answer {
|
|
||||||
background-color: var(--tb-surface) !important;
|
|
||||||
color: var(--tb-text) !important;
|
|
||||||
border-color: var(--tb-border) !important;
|
|
||||||
}
|
|
||||||
html[data-theme="dark"] #math-captcha-modal #captcha-modal-answer::placeholder {
|
|
||||||
color: var(--tb-text-muted) !important;
|
|
||||||
}
|
|
||||||
html[data-theme="dark"] #math-captcha-modal .uk-text-meta,
|
|
||||||
html[data-theme="dark"] #math-captcha-modal #captcha-modal-refresh {
|
|
||||||
color: var(--tb-text-muted) !important;
|
|
||||||
}
|
|
||||||
html[data-theme="dark"] #math-captcha-modal #captcha-modal-refresh:hover {
|
|
||||||
color: var(--tb-primary) !important;
|
|
||||||
}
|
|
||||||
html[data-theme="dark"] .uk-label {
|
|
||||||
color: #fff !important;
|
|
||||||
}
|
|
||||||
/* 自定义组件(探索页推荐卡片等)深色覆盖 */
|
|
||||||
html[data-theme="dark"] .recommend-card,
|
|
||||||
html[data-theme="dark"] .recommend-card:hover {
|
|
||||||
background-color: var(--tb-surface-2) !important;
|
|
||||||
}
|
|
||||||
html[data-theme="dark"] .explore-name a {
|
|
||||||
color: var(--tb-text) !important;
|
|
||||||
}
|
|
||||||
html[data-theme="dark"] .explore-name a:hover {
|
|
||||||
color: var(--tb-primary) !important;
|
|
||||||
}
|
|
||||||
html[data-theme="dark"] .explore-intro {
|
|
||||||
color: var(--tb-text-muted) !important;
|
|
||||||
}
|
|
||||||
/* 切换按钮图标切换(内联 SVG,不依赖 UIkit 图标库) */
|
|
||||||
#theme-toggle .tb-icon-light, #theme-toggle-mobile .tb-icon-light,
|
|
||||||
#theme-toggle .tb-icon-dark, #theme-toggle-mobile .tb-icon-dark {
|
|
||||||
display: inline-flex;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
#theme-toggle .tb-icon-light svg, #theme-toggle-mobile .tb-icon-light svg,
|
|
||||||
#theme-toggle .tb-icon-dark svg, #theme-toggle-mobile .tb-icon-dark svg { display: block; }
|
|
||||||
#theme-toggle .tb-icon-dark, #theme-toggle-mobile .tb-icon-dark { display: none; }
|
|
||||||
html[data-theme="dark"] #theme-toggle .tb-icon-light,
|
|
||||||
html[data-theme="dark"] #theme-toggle-mobile .tb-icon-light { display: none; }
|
|
||||||
html[data-theme="dark"] #theme-toggle .tb-icon-dark,
|
|
||||||
html[data-theme="dark"] #theme-toggle-mobile .tb-icon-dark { display: inline-flex; }
|
|
||||||
|
|
||||||
/* 基础质感层:只调整外观(圆角/投影/字体/数字对齐),不改任何结构与布局。
|
|
||||||
颜色一律取自头部令牌,亮暗两套自动生效,因此这里不需要再写 html[data-theme="dark"] 分支。 */
|
|
||||||
/* 根元素与 body 同时上色:内容不足一屏时,body 之外的视口区域也要是同一底色 */
|
|
||||||
html,
|
|
||||||
body {
|
|
||||||
font-family: var(--tb-font);
|
|
||||||
background-color: var(--tb-bg);
|
|
||||||
color: var(--tb-text);
|
|
||||||
-webkit-font-smoothing: antialiased;
|
|
||||||
-moz-osx-font-smoothing: grayscale;
|
|
||||||
}
|
|
||||||
/* 卡片:12px 圆角 + 一层极淡接触影 + 一层大扩散影(UIkit 默认的 0 5px 15px 偏硬) */
|
|
||||||
.uk-card {
|
|
||||||
border-radius: var(--tb-radius);
|
|
||||||
}
|
|
||||||
.uk-card-default {
|
|
||||||
background-color: var(--tb-surface);
|
|
||||||
box-shadow: var(--tb-shadow);
|
|
||||||
}
|
|
||||||
.uk-card-default.uk-card-hover:hover {
|
|
||||||
box-shadow: var(--tb-shadow-hover);
|
|
||||||
}
|
|
||||||
.uk-card-header {
|
|
||||||
border-radius: var(--tb-radius) var(--tb-radius) 0 0;
|
|
||||||
}
|
|
||||||
.uk-card-footer {
|
|
||||||
border-radius: 0 0 var(--tb-radius) var(--tb-radius);
|
|
||||||
}
|
|
||||||
.uk-card,
|
|
||||||
.uk-button,
|
|
||||||
.uk-alert,
|
|
||||||
.uk-label {
|
|
||||||
transition: box-shadow 0.18s ease, background-color 0.18s ease, border-color 0.18s ease, color 0.18s ease;
|
|
||||||
}
|
|
||||||
/* 交互元素:统一 8px 圆角,标签 6px */
|
|
||||||
.uk-button {
|
|
||||||
border-radius: var(--tb-radius-sm);
|
|
||||||
}
|
|
||||||
.uk-input,
|
|
||||||
.uk-select,
|
|
||||||
.uk-textarea,
|
|
||||||
.uk-form-small,
|
|
||||||
.uk-search-input {
|
|
||||||
border-radius: var(--tb-radius-sm);
|
|
||||||
}
|
|
||||||
.uk-label {
|
|
||||||
border-radius: var(--tb-radius-xs);
|
|
||||||
}
|
|
||||||
.uk-alert {
|
|
||||||
border-radius: 10px;
|
|
||||||
}
|
|
||||||
.uk-modal-dialog {
|
|
||||||
border-radius: 14px;
|
|
||||||
}
|
|
||||||
.uk-dropdown,
|
|
||||||
.uk-navbar-dropdown {
|
|
||||||
border-radius: 10px;
|
|
||||||
box-shadow: var(--tb-shadow);
|
|
||||||
}
|
|
||||||
.uk-navbar-container:not(.uk-navbar-transparent) {
|
|
||||||
background-color: var(--tb-surface);
|
|
||||||
}
|
|
||||||
/* 键盘可达性:仅在键盘聚焦时出现描边,鼠标点击不出现 */
|
|
||||||
.uk-button:focus-visible,
|
|
||||||
.uk-navbar-nav > li > a:focus-visible {
|
|
||||||
outline: 2px solid var(--tb-primary);
|
|
||||||
outline-offset: 2px;
|
|
||||||
}
|
|
||||||
/* 次要文字统一走令牌,避免 #999 / #8a919c 混用 */
|
|
||||||
.uk-text-muted,
|
|
||||||
.uk-text-meta {
|
|
||||||
color: var(--tb-text-muted);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 轻量胶囊:用于投票类型、热门标签等「只是分类信息」的位置。
|
|
||||||
实心 uk-label 一屏多个会变成一排色块,这里统一降级为浅底 + 次要色文字。 */
|
|
||||||
.tb-chip {
|
|
||||||
display: inline-block;
|
|
||||||
padding: 1px 8px;
|
|
||||||
border-radius: var(--tb-radius-xs);
|
|
||||||
background-color: var(--tb-surface-2);
|
|
||||||
color: var(--tb-text-secondary);
|
|
||||||
font-size: 0.72rem;
|
|
||||||
line-height: 1.7;
|
|
||||||
white-space: nowrap;
|
|
||||||
}
|
|
||||||
a.tb-chip:hover {
|
|
||||||
background-color: var(--tb-primary-weak);
|
|
||||||
color: var(--tb-primary);
|
|
||||||
text-decoration: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 统计/日期等数字列等宽对齐,避免刷新时左右跳动 */
|
|
||||||
.uk-table,
|
|
||||||
.tb-num {
|
|
||||||
font-variant-numeric: tabular-nums;
|
|
||||||
}
|
|
||||||
/* 图片上传条:原为 item/new-question 两处各写一份内联 style(写死 #f8f8f8,深色下露白),
|
|
||||||
收敛到一处并走令牌,亮暗自动适配 */
|
|
||||||
.tb-img-uploader {
|
|
||||||
width: 100%;
|
|
||||||
background-color: var(--tb-surface-2);
|
|
||||||
display: flex;
|
|
||||||
padding-top: 5px;
|
|
||||||
padding-bottom: 5px;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: flex-start;
|
|
||||||
gap: 5px;
|
|
||||||
}
|
|
||||||
/* 背景图封面(提问箱主页):渐变遮罩,保证用户自选文字色叠加后仍可读。
|
|
||||||
默认浅色遮罩(页面 .uk-light 补丁把文字兜底成深色);若箱主选了浅色文字,
|
|
||||||
question/list.html 会按亮度加上 .tb-cover-dark 换成深色遮罩。 */
|
|
||||||
.tb-cover {
|
|
||||||
position: relative;
|
|
||||||
border-radius: var(--tb-radius) var(--tb-radius) 0 0;
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
/* ⚠️ 必须带 .uk-flex 复合选择器:UIkit 3.3.3 里有
|
|
||||||
.uk-flex::after,.uk-flex::before{display:none}(优先级 0,2,0),
|
|
||||||
会把这个遮罩伪元素整个干掉——不报错、只是什么都不显示(踩过一次)。
|
|
||||||
单写 .tb-cover::after 优先级不够,会被它压回 display:none。 */
|
|
||||||
.tb-cover::after,
|
|
||||||
.tb-cover.uk-flex::after {
|
|
||||||
content: "";
|
|
||||||
display: block;
|
|
||||||
position: absolute;
|
|
||||||
inset: 0;
|
|
||||||
z-index: 0;
|
|
||||||
background: linear-gradient(180deg, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.58) 55%, rgba(255, 255, 255, 0.84) 100%);
|
|
||||||
pointer-events: none;
|
|
||||||
}
|
|
||||||
.tb-cover.tb-cover-dark::after {
|
|
||||||
background: linear-gradient(180deg, rgba(0, 0, 0, 0) 0%, rgba(0, 0, 0, 0.16) 45%, rgba(0, 0, 0, 0.46) 100%);
|
|
||||||
}
|
|
||||||
.tb-cover > * {
|
|
||||||
position: relative;
|
|
||||||
z-index: 1;
|
|
||||||
}
|
|
||||||
.tb-cover h3,
|
|
||||||
.tb-cover p {
|
|
||||||
text-shadow: 0 1px 10px rgba(255, 255, 255, 0.65);
|
|
||||||
}
|
|
||||||
.tb-cover.tb-cover-dark h3,
|
|
||||||
.tb-cover.tb-cover-dark p {
|
|
||||||
text-shadow: 0 1px 12px rgba(0, 0, 0, 0.45);
|
|
||||||
}
|
|
||||||
/* 尊重系统的减少动效设置 */
|
|
||||||
@media (prefers-reduced-motion: reduce) {
|
|
||||||
.uk-card,
|
|
||||||
.uk-button,
|
|
||||||
.emoji-placeholder {
|
|
||||||
transition: none;
|
|
||||||
animation: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 顶栏自适应:导航全部直接显示,窄屏时分级缩小字号/间距,保证英文/日文等长文字不溢出 */
|
|
||||||
.uk-navbar-nav a {
|
|
||||||
font-size: 0.95rem;
|
|
||||||
padding: 0 10px;
|
|
||||||
}
|
|
||||||
/* 未登录移动端占位:桌面端隐藏,仅 ≤640px 显示(见下方 media 查询)。
|
|
||||||
桌面端布局与改动前完全一致,不受影响。 */
|
|
||||||
.tb-mobile-balancer { display: none; }
|
|
||||||
/* 桌面端保持 UIkit 原生居中三列布局(无需额外 CSS) */
|
|
||||||
.tb-navbar .uk-logo {
|
|
||||||
white-space: nowrap;
|
|
||||||
}
|
|
||||||
@media (max-width: 1200px) {
|
|
||||||
.uk-navbar-nav a {
|
|
||||||
font-size: 0.88rem;
|
|
||||||
padding: 0 8px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@media (max-width: 1000px) {
|
|
||||||
.uk-navbar-nav a {
|
|
||||||
font-size: 0.82rem;
|
|
||||||
padding: 0 6px;
|
|
||||||
}
|
|
||||||
.uk-logo {
|
|
||||||
font-size: 1.1rem;
|
|
||||||
}
|
|
||||||
/* 登录用户名限宽,过长省略号截断 */
|
|
||||||
.tb-nav-username {
|
|
||||||
max-width: 110px;
|
|
||||||
overflow: hidden;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
white-space: nowrap;
|
|
||||||
display: inline-block;
|
|
||||||
vertical-align: middle;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@media (max-width: 800px) {
|
|
||||||
.uk-navbar-nav a {
|
|
||||||
font-size: 0.78rem;
|
|
||||||
padding: 0 4px;
|
|
||||||
}
|
|
||||||
.uk-logo {
|
|
||||||
font-size: 1rem;
|
|
||||||
}
|
|
||||||
.tb-nav-username {
|
|
||||||
max-width: 80px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* 手机端(≤640px):沿用 UIkit 桌面端 navbar 的原生三列定位。
|
|
||||||
不再重写 .uk-navbar-center / center-left / center-right 的定位,
|
|
||||||
避免 logo 被挤到下一行;底部语言与深色模式按钮仍由下方独立栏承载。 */
|
|
||||||
@media (max-width: 640px) {
|
|
||||||
.tb-navbar {
|
|
||||||
position: relative;
|
|
||||||
min-height: 56px;
|
|
||||||
overflow: visible;
|
|
||||||
}
|
|
||||||
.tb-navbar > .uk-navbar-center {
|
|
||||||
position: relative !important;
|
|
||||||
top: auto !important;
|
|
||||||
left: auto !important;
|
|
||||||
right: auto !important;
|
|
||||||
bottom: auto !important;
|
|
||||||
transform: none !important;
|
|
||||||
display: flex !important;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
width: 100%;
|
|
||||||
min-height: 56px;
|
|
||||||
white-space: nowrap;
|
|
||||||
flex-wrap: nowrap;
|
|
||||||
}
|
|
||||||
.tb-navbar .uk-navbar-center-left,
|
|
||||||
.tb-navbar .uk-navbar-center-right {
|
|
||||||
position: static !important;
|
|
||||||
top: auto !important;
|
|
||||||
left: auto !important;
|
|
||||||
right: auto !important;
|
|
||||||
bottom: auto !important;
|
|
||||||
transform: none !important;
|
|
||||||
display: flex !important;
|
|
||||||
align-items: center;
|
|
||||||
flex: 0 0 auto;
|
|
||||||
white-space: nowrap;
|
|
||||||
}
|
|
||||||
.tb-navbar .uk-navbar-center-left > div,
|
|
||||||
.tb-navbar .uk-navbar-center-right > div {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
white-space: nowrap;
|
|
||||||
}
|
|
||||||
.tb-navbar .uk-navbar-nav {
|
|
||||||
display: flex;
|
|
||||||
flex-wrap: nowrap;
|
|
||||||
flex: 0 0 auto;
|
|
||||||
}
|
|
||||||
.tb-navbar .uk-navbar-nav > li > a,
|
|
||||||
.tb-navbar .uk-logo {
|
|
||||||
white-space: nowrap;
|
|
||||||
}
|
|
||||||
/* 未登录:移动端显示与「我的」等宽的隐藏占位,使左栏「探索+占位」与
|
|
||||||
右栏「注册/登录」两项等宽,logo 真正居中,左右视觉平衡 */
|
|
||||||
.tb-mobile-balancer { display: block; }
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 标签样式的按钮(管理页置顶等):
|
|
||||||
尺寸完全继承 .uk-label(font-size/padding/line-height/text-transform 等),
|
|
||||||
仅覆盖 button 元素特有的默认样式(边框/字体族/光标等),保证与相邻 span 标签完全一致。 */
|
|
||||||
.tb-label-btn {
|
|
||||||
border: none !important;
|
|
||||||
cursor: pointer;
|
|
||||||
font-family: inherit;
|
|
||||||
margin: 0;
|
|
||||||
vertical-align: middle;
|
|
||||||
outline: none;
|
|
||||||
background-image: none;
|
|
||||||
box-sizing: border-box;
|
|
||||||
-webkit-appearance: none;
|
|
||||||
appearance: none;
|
|
||||||
}
|
|
||||||
.tb-label-btn:hover {
|
|
||||||
opacity: 0.85;
|
|
||||||
}
|
|
||||||
/* 公开页置顶小图标:仅一个图钉,不占行高、不影响原布局 */
|
|
||||||
.tb-pin-flag {
|
|
||||||
font-size: 0.9em;
|
|
||||||
margin-right: 4px;
|
|
||||||
vertical-align: -1px;
|
|
||||||
cursor: default;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Markdown 渲染排版(问题/回答/追问正文,左对齐以保留排版格式) */
|
|
||||||
/* 纯文本列表:保留换行与连续空格(pre-wrap),不渲染 Markdown 大字号/彩色 */
|
|
||||||
.tb-preline {
|
|
||||||
white-space: pre-wrap;
|
|
||||||
}
|
|
||||||
/* 纯文本列表:超过 5 行截断并显示省略号(不足 5 行则完整显示) */
|
|
||||||
.tb-clamp-5 {
|
|
||||||
display: -webkit-box;
|
|
||||||
-webkit-box-orient: vertical;
|
|
||||||
-webkit-line-clamp: 5;
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
.md-body {
|
|
||||||
line-height: 1.7;
|
|
||||||
text-align: left;
|
|
||||||
word-break: break-word;
|
|
||||||
}
|
|
||||||
.md-body p { margin: 0.5em 0; }
|
|
||||||
.md-body h1, .md-body h2, .md-body h3,
|
|
||||||
.md-body h4, .md-body h5, .md-body h6 {
|
|
||||||
margin: 0.8em 0 0.4em;
|
|
||||||
font-weight: 600;
|
|
||||||
line-height: 1.4;
|
|
||||||
}
|
|
||||||
.md-body ul, .md-body ol { padding-left: 1.6em; margin: 0.5em 0; }
|
|
||||||
.md-body li { margin: 0.2em 0; }
|
|
||||||
.md-body blockquote {
|
|
||||||
border-left: 3px solid #d3d1c7;
|
|
||||||
margin: 0.6em 0;
|
|
||||||
padding: 0.2em 1em;
|
|
||||||
color: #5f5e5a;
|
|
||||||
}
|
|
||||||
.md-body pre {
|
|
||||||
background: #f5f5f5;
|
|
||||||
padding: 0.8em 1em;
|
|
||||||
border-radius: 6px;
|
|
||||||
overflow-x: auto;
|
|
||||||
margin: 0.6em 0;
|
|
||||||
}
|
|
||||||
.md-body code {
|
|
||||||
background: #f0f0f0;
|
|
||||||
padding: 0.1em 0.35em;
|
|
||||||
border-radius: 4px;
|
|
||||||
font-size: 0.9em;
|
|
||||||
}
|
|
||||||
.md-body pre code { background: none; padding: 0; }
|
|
||||||
.md-body img { max-width: 100%; height: auto; }
|
|
||||||
.md-body table { border-collapse: collapse; margin: 0.6em 0; }
|
|
||||||
.md-body th, .md-body td {
|
|
||||||
border: 1px solid #ddd;
|
|
||||||
padding: 0.4em 0.8em;
|
|
||||||
}
|
|
||||||
.md-body hr { margin: 1em 0; }
|
|
||||||
html[data-theme="dark"] .md-body blockquote {
|
|
||||||
border-color: #3a404c;
|
|
||||||
color: #8b93a1;
|
|
||||||
}
|
|
||||||
html[data-theme="dark"] .md-body pre,
|
|
||||||
html[data-theme="dark"] .md-body code { background: #2d323c; }
|
|
||||||
html[data-theme="dark"] .md-body th,
|
|
||||||
html[data-theme="dark"] .md-body td { border-color: #3a404c; }
|
|
||||||
|
|
||||||
/* 投票结果占比条:模板已改用 UIkit 3 原生 <progress class="uk-progress" value max>,
|
|
||||||
这里只把默认的 15px 高 / 500px 圆角 / 20px 外边距收紧到与页面一致的规格。
|
|
||||||
(原先为 UIkit 2 的 .uk-progressbar 结构打的补丁已删除) */
|
|
||||||
.uk-progress {
|
|
||||||
height: 10px;
|
|
||||||
margin: 0;
|
|
||||||
border-radius: var(--tb-radius-xs);
|
|
||||||
background-color: var(--tb-surface-2);
|
|
||||||
}
|
|
||||||
.uk-progress::-webkit-progress-bar {
|
|
||||||
background-color: var(--tb-surface-2);
|
|
||||||
border-radius: var(--tb-radius-xs);
|
|
||||||
}
|
|
||||||
.uk-progress::-webkit-progress-value {
|
|
||||||
background-color: var(--tb-primary);
|
|
||||||
border-radius: var(--tb-radius-xs) 0 0 var(--tb-radius-xs);
|
|
||||||
}
|
|
||||||
.uk-progress::-moz-progress-bar {
|
|
||||||
background-color: var(--tb-primary);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 移动端底部操作栏:固定底栏承载语言切换与深色模式,桌面端隐藏 */
|
|
||||||
#tb-mobile-utils {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
@media (max-width: 640px) {
|
|
||||||
/* 顶栏不再容纳语言/深色按钮,恢复原有导航空间 */
|
|
||||||
.tb-nav-utils {
|
|
||||||
display: none !important;
|
|
||||||
}
|
|
||||||
/* 手机端隐藏登录用户名(左边仅保留"探索"),保证 logo 居中、
|
|
||||||
两侧各不超过 2 个短按钮,避免用户名宽度挤压布局 */
|
|
||||||
.tb-nav-username {
|
|
||||||
display: none !important;
|
|
||||||
}
|
|
||||||
/* 固定底部操作栏 */
|
|
||||||
#tb-mobile-utils {
|
|
||||||
display: flex;
|
|
||||||
position: fixed;
|
|
||||||
left: 0;
|
|
||||||
right: 0;
|
|
||||||
bottom: 0;
|
|
||||||
z-index: 1000;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
gap: 10px;
|
|
||||||
padding: 8px 12px calc(8px + env(safe-area-inset-bottom));
|
|
||||||
background: rgba(255, 255, 255, 0.92);
|
|
||||||
-webkit-backdrop-filter: blur(8px);
|
|
||||||
backdrop-filter: blur(8px);
|
|
||||||
box-shadow: 0 -2px 12px rgba(0, 0, 0, 0.08);
|
|
||||||
}
|
|
||||||
#tb-mobile-utils .uk-select {
|
|
||||||
width: 110px;
|
|
||||||
}
|
|
||||||
html[data-theme="dark"] #tb-mobile-utils {
|
|
||||||
background: rgba(36, 40, 48, 0.92);
|
|
||||||
box-shadow: 0 -2px 12px rgba(0, 0, 0, 0.4);
|
|
||||||
}
|
|
||||||
/* 给页面底部预留空间,避免页脚内容被固定底栏遮挡 */
|
|
||||||
body {
|
|
||||||
padding-bottom: 56px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
||||||
<link rel="stylesheet" href="https://r2.337845818.best/tamabox/cdn/waline/client/v2/waline-no-commits.css" media="print" onload="this.media='all'"/>
|
<link rel="stylesheet" href="https://r2.337845818.best/tamabox/cdn/waline/client/v2/waline-no-commits.css" media="print" onload="this.media='all'"/>
|
||||||
<script defer src="https://cdnjs.cloudflare.com/ajax/libs/uikit/3.3.3/js/uikit.min.js"></script>
|
<script defer src="https://cdnjs.cloudflare.com/ajax/libs/uikit/3.3.3/js/uikit.min.js"></script>
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
<title>预览 12:01 · 设置</title>
|
<title>预览 15:15 · 设置</title>
|
||||||
<meta name="msvalidate.01" content="2F185E8E63C93635F50B3574F3B31E42" />
|
<meta name="msvalidate.01" content="2F185E8E63C93635F50B3574F3B31E42" />
|
||||||
<meta name="description" content="狼的提问箱——一个无需注册、可匿名提问的匿名提问箱,安全地倾诉与回应。">
|
<meta name="description" content="狼的提问箱——一个无需注册、可匿名提问的匿名提问箱,安全地倾诉与回应。">
|
||||||
<meta name="keywords" content="匿名提问箱,提问箱,匿名提问,狼的提问箱,匿名问答,匿名提问网站">
|
<meta name="keywords" content="匿名提问箱,提问箱,匿名提问,狼的提问箱,匿名问答,匿名提问网站">
|
||||||
@@ -20,675 +20,8 @@
|
|||||||
|
|
||||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/uikit/3.3.3/css/uikit.min.css"/>
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/uikit/3.3.3/css/uikit.min.css"/>
|
||||||
|
|
||||||
<style>/* TamaBox 全站基础样式:设计令牌 / 主题覆盖 / 组件质感 / 响应式。
|
<link rel="stylesheet" href="/static/css/base.css?v="/>
|
||||||
由 base/header.html 内联块抽出,集中一份便于缓存与维护。
|
|
||||||
⚠️ 改完务必把 header 里的 ?v= 版本号 +1,否则老访客仍用缓存。 */
|
|
||||||
|
|
||||||
/* 设计令牌:亮色为默认(:root),深色在 html[data-theme="dark"] 覆盖。
|
|
||||||
页面与组件样式一律引用 var(--tb-*),不再写死色值/圆角/阴影;
|
|
||||||
var() 的第二个参数仅作兜底(旧缓存页、邮件模板等不引入本文件的场景)。
|
|
||||||
改配色只动这一块,亮暗两套自动保持一致。 */
|
|
||||||
:root {
|
|
||||||
--tb-bg: #f7f8fa;
|
|
||||||
--tb-surface: #ffffff;
|
|
||||||
--tb-surface-2: #f4f6f8;
|
|
||||||
--tb-surface-hover: #f3f7ff;
|
|
||||||
--tb-border: #e8eaee;
|
|
||||||
--tb-text: #1f2329;
|
|
||||||
--tb-text-secondary: #5c6370;
|
|
||||||
--tb-text-muted: #8a919c;
|
|
||||||
--tb-primary: #1e87f0;
|
|
||||||
--tb-primary-weak: rgba(30, 135, 240, 0.10);
|
|
||||||
--tb-radius: 12px;
|
|
||||||
--tb-radius-sm: 8px;
|
|
||||||
--tb-radius-xs: 6px;
|
|
||||||
--tb-shadow: 0 1px 2px rgba(16, 24, 40, 0.04), 0 12px 28px -18px rgba(16, 24, 40, 0.20);
|
|
||||||
--tb-shadow-hover: 0 1px 2px rgba(16, 24, 40, 0.05), 0 18px 40px -20px rgba(16, 24, 40, 0.28);
|
|
||||||
--tb-font: system-ui, -apple-system, "Segoe UI", "PingFang SC", "Hiragino Sans GB", "Noto Sans CJK SC", "Microsoft YaHei", sans-serif;
|
|
||||||
}
|
|
||||||
html[data-theme="dark"] {
|
|
||||||
--tb-bg: #1a1d23;
|
|
||||||
--tb-surface: #242830;
|
|
||||||
--tb-surface-2: #2d323c;
|
|
||||||
--tb-surface-hover: rgba(92, 141, 255, 0.12);
|
|
||||||
--tb-border: #3a404c;
|
|
||||||
--tb-text: #d8dce4;
|
|
||||||
--tb-text-secondary: #a8b0bd;
|
|
||||||
--tb-text-muted: #8b93a1;
|
|
||||||
--tb-primary: #5c8dff;
|
|
||||||
--tb-primary-weak: rgba(92, 141, 255, 0.14);
|
|
||||||
--tb-shadow: 0 1px 2px rgba(0, 0, 0, 0.30), 0 12px 28px -18px rgba(0, 0, 0, 0.55);
|
|
||||||
--tb-shadow-hover: 0 1px 2px rgba(0, 0, 0, 0.35), 0 18px 40px -20px rgba(0, 0, 0, 0.65);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* UIkit 补丁:复刻原自建版 "modify-black-font"(官方版与自建版仅 3 处颜色差异——把有色容器内默认白字/白标题改为黑字)。
|
|
||||||
模板当前只用到 .uk-light 容器(用户背景封面,question/list.html、question-not-found.html;
|
|
||||||
其中 h3/p 已由 #usernamecolor/#introcolor 内联 style 覆盖),故只需补该容器的 3 处投影即可保持渲染一致。
|
|
||||||
若日后新增 .uk-card-primary/.uk-card-secondary/.uk-section-primary/.uk-tile-*/.uk-overlay-primary 等容器且需黑字,须同步扩展。 */
|
|
||||||
.uk-light { color: rgba(0,0,0,.7); }
|
|
||||||
.uk-light .uk-h1, .uk-light .uk-h2, .uk-light .uk-h3, .uk-light .uk-h4, .uk-light .uk-h5, .uk-light .uk-h6,
|
|
||||||
.uk-light .uk-heading-2xlarge, .uk-light .uk-heading-large, .uk-light .uk-heading-medium, .uk-light .uk-heading-small, .uk-light .uk-heading-xlarge,
|
|
||||||
.uk-light h1, .uk-light h2, .uk-light h3, .uk-light h4, .uk-light h5, .uk-light h6 { color: #000; }
|
|
||||||
.uk-light .uk-table th { color: rgba(0,0,0,.7); }
|
|
||||||
|
|
||||||
.grecaptcha-badge {visibility: hidden;}
|
|
||||||
.icon-container {
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
.icon {
|
|
||||||
margin-left: 10px;
|
|
||||||
width: 20px; /* 设置图标的宽度 */
|
|
||||||
height: auto; /* 保持图标的高度自动调整 */
|
|
||||||
}
|
|
||||||
.emoji-placeholder {
|
|
||||||
display: inline-block;
|
|
||||||
animation: jump 0.5s ease-in-out;
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes jump {
|
|
||||||
0%, 100% { transform: translateY(0); }
|
|
||||||
50% { transform: translateY(-5px); }
|
|
||||||
}
|
|
||||||
/* 防止 UIkit Dropbar 初始闪烁 */
|
|
||||||
.uk-dropbar {
|
|
||||||
opacity: 0;
|
|
||||||
visibility: hidden;
|
|
||||||
transition: opacity 0.2s ease, visibility 0.2s ease;
|
|
||||||
}
|
|
||||||
|
|
||||||
.uk-dropbar.uk-open {
|
|
||||||
opacity: 1;
|
|
||||||
visibility: visible;
|
|
||||||
}
|
|
||||||
|
|
||||||
a.uk-button.uk-button-link {
|
|
||||||
text-transform: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 移动端优化:缩小字体和间距,避免右侧空白 */
|
|
||||||
@media (max-width: 640px) {
|
|
||||||
.uk-logo {
|
|
||||||
font-size: 1rem;
|
|
||||||
}
|
|
||||||
.uk-navbar-nav a {
|
|
||||||
font-size: 0.78rem;
|
|
||||||
padding: 0 4px;
|
|
||||||
}
|
|
||||||
.emoji-placeholder {
|
|
||||||
font-size: 1rem;
|
|
||||||
}
|
|
||||||
/* 移动端用户名限宽省略,避免长英文用户名撑爆顶栏 */
|
|
||||||
.tb-nav-username {
|
|
||||||
max-width: 64px;
|
|
||||||
overflow: hidden;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
white-space: nowrap;
|
|
||||||
display: inline-block;
|
|
||||||
vertical-align: middle;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 深色模式:html[data-theme="dark"] 时覆盖 UIkit 3.3.3 编译主题的关键颜色 */
|
|
||||||
/* 变量(--tb-*)已上移到 head 顶部的令牌块,亮暗两套同名常量在那里定义。 */
|
|
||||||
/* 根元素与 body 一起覆盖,确保整个视口(含内容不足一屏时的空白区)都是深色背景 */
|
|
||||||
html[data-theme="dark"],
|
|
||||||
html[data-theme="dark"] body {
|
|
||||||
background-color: var(--tb-bg) !important;
|
|
||||||
color: var(--tb-text) !important;
|
|
||||||
}
|
|
||||||
/* 通用表面容器 */
|
|
||||||
html[data-theme="dark"] .uk-card,
|
|
||||||
html[data-theme="dark"] .uk-card-default,
|
|
||||||
html[data-theme="dark"] .uk-card-secondary,
|
|
||||||
html[data-theme="dark"] .uk-dropbar,
|
|
||||||
html[data-theme="dark"] .uk-navbar-dropdown,
|
|
||||||
html[data-theme="dark"] .uk-modal-dialog,
|
|
||||||
html[data-theme="dark"] .uk-dropdown,
|
|
||||||
html[data-theme="dark"] .uk-offcanvas-bar,
|
|
||||||
html[data-theme="dark"] .uk-section,
|
|
||||||
html[data-theme="dark"] .uk-tile,
|
|
||||||
html[data-theme="dark"] .uk-panel,
|
|
||||||
html[data-theme="dark"] .uk-background-default,
|
|
||||||
html[data-theme="dark"] .uk-search-default .uk-search-input {
|
|
||||||
background-color: var(--tb-surface) !important;
|
|
||||||
color: var(--tb-text) !important;
|
|
||||||
}
|
|
||||||
html[data-theme="dark"] .uk-navbar-container {
|
|
||||||
background-color: var(--tb-surface) !important;
|
|
||||||
color: var(--tb-text) !important;
|
|
||||||
}
|
|
||||||
html[data-theme="dark"] .uk-navbar-nav > li > a,
|
|
||||||
html[data-theme="dark"] .uk-card a,
|
|
||||||
html[data-theme="dark"] .uk-link,
|
|
||||||
html[data-theme="dark"] a.uk-button-link,
|
|
||||||
html[data-theme="dark"] .uk-navbar-dropdown-nav > li > a,
|
|
||||||
html[data-theme="dark"] .uk-dropdown-nav > li > a,
|
|
||||||
html[data-theme="dark"] .uk-list a {
|
|
||||||
color: var(--tb-text) !important;
|
|
||||||
}
|
|
||||||
html[data-theme="dark"] .uk-navbar-nav > li > a:hover,
|
|
||||||
html[data-theme="dark"] .uk-card a:hover,
|
|
||||||
html[data-theme="dark"] .uk-navbar-dropdown-nav > li > a:hover,
|
|
||||||
html[data-theme="dark"] .uk-dropdown-nav > li > a:hover {
|
|
||||||
color: var(--tb-primary) !important;
|
|
||||||
}
|
|
||||||
html[data-theme="dark"] .uk-input,
|
|
||||||
html[data-theme="dark"] .uk-textarea,
|
|
||||||
html[data-theme="dark"] .uk-select {
|
|
||||||
background-color: var(--tb-surface-2) !important;
|
|
||||||
color: var(--tb-text) !important;
|
|
||||||
border-color: var(--tb-border) !important;
|
|
||||||
}
|
|
||||||
html[data-theme="dark"] .uk-input:focus,
|
|
||||||
html[data-theme="dark"] .uk-textarea:focus,
|
|
||||||
html[data-theme="dark"] .uk-select:focus {
|
|
||||||
border-color: var(--tb-primary) !important;
|
|
||||||
}
|
|
||||||
html[data-theme="dark"] .uk-text-muted,
|
|
||||||
html[data-theme="dark"] .uk-text-meta,
|
|
||||||
html[data-theme="dark"] .uk-text-secondary,
|
|
||||||
html[data-theme="dark"] .uk-text-muted a,
|
|
||||||
html[data-theme="dark"] .uk-text-small.uk-text-muted {
|
|
||||||
color: var(--tb-text-muted) !important;
|
|
||||||
}
|
|
||||||
html[data-theme="dark"] .uk-divider-icon::after,
|
|
||||||
html[data-theme="dark"] hr,
|
|
||||||
html[data-theme="dark"] .uk-table th,
|
|
||||||
html[data-theme="dark"] .uk-table td,
|
|
||||||
html[data-theme="dark"] .uk-list-divider > li:nth-child(n+2) {
|
|
||||||
border-color: var(--tb-border) !important;
|
|
||||||
}
|
|
||||||
html[data-theme="dark"] .uk-button-default {
|
|
||||||
background-color: var(--tb-surface-2) !important;
|
|
||||||
color: var(--tb-text) !important;
|
|
||||||
border-color: var(--tb-border) !important;
|
|
||||||
}
|
|
||||||
html[data-theme="dark"] .uk-modal-title,
|
|
||||||
html[data-theme="dark"] h1, html[data-theme="dark"] h2, html[data-theme="dark"] h3,
|
|
||||||
html[data-theme="dark"] h4, html[data-theme="dark"] h5, html[data-theme="dark"] h6,
|
|
||||||
html[data-theme="dark"] .uk-card-title {
|
|
||||||
color: var(--tb-text) !important;
|
|
||||||
}
|
|
||||||
html[data-theme="dark"] .uk-alert-warning,
|
|
||||||
html[data-theme="dark"] .uk-alert-danger,
|
|
||||||
html[data-theme="dark"] .uk-alert-success,
|
|
||||||
html[data-theme="dark"] .uk-alert-primary {
|
|
||||||
background-color: var(--tb-surface-2) !important;
|
|
||||||
color: var(--tb-text) !important;
|
|
||||||
}
|
|
||||||
html[data-theme="dark"] #math-captcha-modal .uk-modal-dialog {
|
|
||||||
background-color: var(--tb-surface) !important;
|
|
||||||
color: var(--tb-text) !important;
|
|
||||||
}
|
|
||||||
html[data-theme="dark"] #math-captcha-modal .captcha-equation-box {
|
|
||||||
background-color: var(--tb-surface-2) !important;
|
|
||||||
border-color: var(--tb-border) !important;
|
|
||||||
}
|
|
||||||
html[data-theme="dark"] #math-captcha-modal .math-captcha-modal-question {
|
|
||||||
color: var(--tb-text) !important;
|
|
||||||
}
|
|
||||||
html[data-theme="dark"] #math-captcha-modal #captcha-modal-answer {
|
|
||||||
background-color: var(--tb-surface) !important;
|
|
||||||
color: var(--tb-text) !important;
|
|
||||||
border-color: var(--tb-border) !important;
|
|
||||||
}
|
|
||||||
html[data-theme="dark"] #math-captcha-modal #captcha-modal-answer::placeholder {
|
|
||||||
color: var(--tb-text-muted) !important;
|
|
||||||
}
|
|
||||||
html[data-theme="dark"] #math-captcha-modal .uk-text-meta,
|
|
||||||
html[data-theme="dark"] #math-captcha-modal #captcha-modal-refresh {
|
|
||||||
color: var(--tb-text-muted) !important;
|
|
||||||
}
|
|
||||||
html[data-theme="dark"] #math-captcha-modal #captcha-modal-refresh:hover {
|
|
||||||
color: var(--tb-primary) !important;
|
|
||||||
}
|
|
||||||
html[data-theme="dark"] .uk-label {
|
|
||||||
color: #fff !important;
|
|
||||||
}
|
|
||||||
/* 自定义组件(探索页推荐卡片等)深色覆盖 */
|
|
||||||
html[data-theme="dark"] .recommend-card,
|
|
||||||
html[data-theme="dark"] .recommend-card:hover {
|
|
||||||
background-color: var(--tb-surface-2) !important;
|
|
||||||
}
|
|
||||||
html[data-theme="dark"] .explore-name a {
|
|
||||||
color: var(--tb-text) !important;
|
|
||||||
}
|
|
||||||
html[data-theme="dark"] .explore-name a:hover {
|
|
||||||
color: var(--tb-primary) !important;
|
|
||||||
}
|
|
||||||
html[data-theme="dark"] .explore-intro {
|
|
||||||
color: var(--tb-text-muted) !important;
|
|
||||||
}
|
|
||||||
/* 切换按钮图标切换(内联 SVG,不依赖 UIkit 图标库) */
|
|
||||||
#theme-toggle .tb-icon-light, #theme-toggle-mobile .tb-icon-light,
|
|
||||||
#theme-toggle .tb-icon-dark, #theme-toggle-mobile .tb-icon-dark {
|
|
||||||
display: inline-flex;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
#theme-toggle .tb-icon-light svg, #theme-toggle-mobile .tb-icon-light svg,
|
|
||||||
#theme-toggle .tb-icon-dark svg, #theme-toggle-mobile .tb-icon-dark svg { display: block; }
|
|
||||||
#theme-toggle .tb-icon-dark, #theme-toggle-mobile .tb-icon-dark { display: none; }
|
|
||||||
html[data-theme="dark"] #theme-toggle .tb-icon-light,
|
|
||||||
html[data-theme="dark"] #theme-toggle-mobile .tb-icon-light { display: none; }
|
|
||||||
html[data-theme="dark"] #theme-toggle .tb-icon-dark,
|
|
||||||
html[data-theme="dark"] #theme-toggle-mobile .tb-icon-dark { display: inline-flex; }
|
|
||||||
|
|
||||||
/* 基础质感层:只调整外观(圆角/投影/字体/数字对齐),不改任何结构与布局。
|
|
||||||
颜色一律取自头部令牌,亮暗两套自动生效,因此这里不需要再写 html[data-theme="dark"] 分支。 */
|
|
||||||
/* 根元素与 body 同时上色:内容不足一屏时,body 之外的视口区域也要是同一底色 */
|
|
||||||
html,
|
|
||||||
body {
|
|
||||||
font-family: var(--tb-font);
|
|
||||||
background-color: var(--tb-bg);
|
|
||||||
color: var(--tb-text);
|
|
||||||
-webkit-font-smoothing: antialiased;
|
|
||||||
-moz-osx-font-smoothing: grayscale;
|
|
||||||
}
|
|
||||||
/* 卡片:12px 圆角 + 一层极淡接触影 + 一层大扩散影(UIkit 默认的 0 5px 15px 偏硬) */
|
|
||||||
.uk-card {
|
|
||||||
border-radius: var(--tb-radius);
|
|
||||||
}
|
|
||||||
.uk-card-default {
|
|
||||||
background-color: var(--tb-surface);
|
|
||||||
box-shadow: var(--tb-shadow);
|
|
||||||
}
|
|
||||||
.uk-card-default.uk-card-hover:hover {
|
|
||||||
box-shadow: var(--tb-shadow-hover);
|
|
||||||
}
|
|
||||||
.uk-card-header {
|
|
||||||
border-radius: var(--tb-radius) var(--tb-radius) 0 0;
|
|
||||||
}
|
|
||||||
.uk-card-footer {
|
|
||||||
border-radius: 0 0 var(--tb-radius) var(--tb-radius);
|
|
||||||
}
|
|
||||||
.uk-card,
|
|
||||||
.uk-button,
|
|
||||||
.uk-alert,
|
|
||||||
.uk-label {
|
|
||||||
transition: box-shadow 0.18s ease, background-color 0.18s ease, border-color 0.18s ease, color 0.18s ease;
|
|
||||||
}
|
|
||||||
/* 交互元素:统一 8px 圆角,标签 6px */
|
|
||||||
.uk-button {
|
|
||||||
border-radius: var(--tb-radius-sm);
|
|
||||||
}
|
|
||||||
.uk-input,
|
|
||||||
.uk-select,
|
|
||||||
.uk-textarea,
|
|
||||||
.uk-form-small,
|
|
||||||
.uk-search-input {
|
|
||||||
border-radius: var(--tb-radius-sm);
|
|
||||||
}
|
|
||||||
.uk-label {
|
|
||||||
border-radius: var(--tb-radius-xs);
|
|
||||||
}
|
|
||||||
.uk-alert {
|
|
||||||
border-radius: 10px;
|
|
||||||
}
|
|
||||||
.uk-modal-dialog {
|
|
||||||
border-radius: 14px;
|
|
||||||
}
|
|
||||||
.uk-dropdown,
|
|
||||||
.uk-navbar-dropdown {
|
|
||||||
border-radius: 10px;
|
|
||||||
box-shadow: var(--tb-shadow);
|
|
||||||
}
|
|
||||||
.uk-navbar-container:not(.uk-navbar-transparent) {
|
|
||||||
background-color: var(--tb-surface);
|
|
||||||
}
|
|
||||||
/* 键盘可达性:仅在键盘聚焦时出现描边,鼠标点击不出现 */
|
|
||||||
.uk-button:focus-visible,
|
|
||||||
.uk-navbar-nav > li > a:focus-visible {
|
|
||||||
outline: 2px solid var(--tb-primary);
|
|
||||||
outline-offset: 2px;
|
|
||||||
}
|
|
||||||
/* 次要文字统一走令牌,避免 #999 / #8a919c 混用 */
|
|
||||||
.uk-text-muted,
|
|
||||||
.uk-text-meta {
|
|
||||||
color: var(--tb-text-muted);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 轻量胶囊:用于投票类型、热门标签等「只是分类信息」的位置。
|
|
||||||
实心 uk-label 一屏多个会变成一排色块,这里统一降级为浅底 + 次要色文字。 */
|
|
||||||
.tb-chip {
|
|
||||||
display: inline-block;
|
|
||||||
padding: 1px 8px;
|
|
||||||
border-radius: var(--tb-radius-xs);
|
|
||||||
background-color: var(--tb-surface-2);
|
|
||||||
color: var(--tb-text-secondary);
|
|
||||||
font-size: 0.72rem;
|
|
||||||
line-height: 1.7;
|
|
||||||
white-space: nowrap;
|
|
||||||
}
|
|
||||||
a.tb-chip:hover {
|
|
||||||
background-color: var(--tb-primary-weak);
|
|
||||||
color: var(--tb-primary);
|
|
||||||
text-decoration: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 统计/日期等数字列等宽对齐,避免刷新时左右跳动 */
|
|
||||||
.uk-table,
|
|
||||||
.tb-num {
|
|
||||||
font-variant-numeric: tabular-nums;
|
|
||||||
}
|
|
||||||
/* 图片上传条:原为 item/new-question 两处各写一份内联 style(写死 #f8f8f8,深色下露白),
|
|
||||||
收敛到一处并走令牌,亮暗自动适配 */
|
|
||||||
.tb-img-uploader {
|
|
||||||
width: 100%;
|
|
||||||
background-color: var(--tb-surface-2);
|
|
||||||
display: flex;
|
|
||||||
padding-top: 5px;
|
|
||||||
padding-bottom: 5px;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: flex-start;
|
|
||||||
gap: 5px;
|
|
||||||
}
|
|
||||||
/* 背景图封面(提问箱主页):渐变遮罩,保证用户自选文字色叠加后仍可读。
|
|
||||||
默认浅色遮罩(页面 .uk-light 补丁把文字兜底成深色);若箱主选了浅色文字,
|
|
||||||
question/list.html 会按亮度加上 .tb-cover-dark 换成深色遮罩。 */
|
|
||||||
.tb-cover {
|
|
||||||
position: relative;
|
|
||||||
border-radius: var(--tb-radius) var(--tb-radius) 0 0;
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
/* ⚠️ 必须带 .uk-flex 复合选择器:UIkit 3.3.3 里有
|
|
||||||
.uk-flex::after,.uk-flex::before{display:none}(优先级 0,2,0),
|
|
||||||
会把这个遮罩伪元素整个干掉——不报错、只是什么都不显示(踩过一次)。
|
|
||||||
单写 .tb-cover::after 优先级不够,会被它压回 display:none。 */
|
|
||||||
.tb-cover::after,
|
|
||||||
.tb-cover.uk-flex::after {
|
|
||||||
content: "";
|
|
||||||
display: block;
|
|
||||||
position: absolute;
|
|
||||||
inset: 0;
|
|
||||||
z-index: 0;
|
|
||||||
background: linear-gradient(180deg, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.58) 55%, rgba(255, 255, 255, 0.84) 100%);
|
|
||||||
pointer-events: none;
|
|
||||||
}
|
|
||||||
.tb-cover.tb-cover-dark::after {
|
|
||||||
background: linear-gradient(180deg, rgba(0, 0, 0, 0) 0%, rgba(0, 0, 0, 0.16) 45%, rgba(0, 0, 0, 0.46) 100%);
|
|
||||||
}
|
|
||||||
.tb-cover > * {
|
|
||||||
position: relative;
|
|
||||||
z-index: 1;
|
|
||||||
}
|
|
||||||
.tb-cover h3,
|
|
||||||
.tb-cover p {
|
|
||||||
text-shadow: 0 1px 10px rgba(255, 255, 255, 0.65);
|
|
||||||
}
|
|
||||||
.tb-cover.tb-cover-dark h3,
|
|
||||||
.tb-cover.tb-cover-dark p {
|
|
||||||
text-shadow: 0 1px 12px rgba(0, 0, 0, 0.45);
|
|
||||||
}
|
|
||||||
/* 尊重系统的减少动效设置 */
|
|
||||||
@media (prefers-reduced-motion: reduce) {
|
|
||||||
.uk-card,
|
|
||||||
.uk-button,
|
|
||||||
.emoji-placeholder {
|
|
||||||
transition: none;
|
|
||||||
animation: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 顶栏自适应:导航全部直接显示,窄屏时分级缩小字号/间距,保证英文/日文等长文字不溢出 */
|
|
||||||
.uk-navbar-nav a {
|
|
||||||
font-size: 0.95rem;
|
|
||||||
padding: 0 10px;
|
|
||||||
}
|
|
||||||
/* 未登录移动端占位:桌面端隐藏,仅 ≤640px 显示(见下方 media 查询)。
|
|
||||||
桌面端布局与改动前完全一致,不受影响。 */
|
|
||||||
.tb-mobile-balancer { display: none; }
|
|
||||||
/* 桌面端保持 UIkit 原生居中三列布局(无需额外 CSS) */
|
|
||||||
.tb-navbar .uk-logo {
|
|
||||||
white-space: nowrap;
|
|
||||||
}
|
|
||||||
@media (max-width: 1200px) {
|
|
||||||
.uk-navbar-nav a {
|
|
||||||
font-size: 0.88rem;
|
|
||||||
padding: 0 8px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@media (max-width: 1000px) {
|
|
||||||
.uk-navbar-nav a {
|
|
||||||
font-size: 0.82rem;
|
|
||||||
padding: 0 6px;
|
|
||||||
}
|
|
||||||
.uk-logo {
|
|
||||||
font-size: 1.1rem;
|
|
||||||
}
|
|
||||||
/* 登录用户名限宽,过长省略号截断 */
|
|
||||||
.tb-nav-username {
|
|
||||||
max-width: 110px;
|
|
||||||
overflow: hidden;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
white-space: nowrap;
|
|
||||||
display: inline-block;
|
|
||||||
vertical-align: middle;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@media (max-width: 800px) {
|
|
||||||
.uk-navbar-nav a {
|
|
||||||
font-size: 0.78rem;
|
|
||||||
padding: 0 4px;
|
|
||||||
}
|
|
||||||
.uk-logo {
|
|
||||||
font-size: 1rem;
|
|
||||||
}
|
|
||||||
.tb-nav-username {
|
|
||||||
max-width: 80px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* 手机端(≤640px):沿用 UIkit 桌面端 navbar 的原生三列定位。
|
|
||||||
不再重写 .uk-navbar-center / center-left / center-right 的定位,
|
|
||||||
避免 logo 被挤到下一行;底部语言与深色模式按钮仍由下方独立栏承载。 */
|
|
||||||
@media (max-width: 640px) {
|
|
||||||
.tb-navbar {
|
|
||||||
position: relative;
|
|
||||||
min-height: 56px;
|
|
||||||
overflow: visible;
|
|
||||||
}
|
|
||||||
.tb-navbar > .uk-navbar-center {
|
|
||||||
position: relative !important;
|
|
||||||
top: auto !important;
|
|
||||||
left: auto !important;
|
|
||||||
right: auto !important;
|
|
||||||
bottom: auto !important;
|
|
||||||
transform: none !important;
|
|
||||||
display: flex !important;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
width: 100%;
|
|
||||||
min-height: 56px;
|
|
||||||
white-space: nowrap;
|
|
||||||
flex-wrap: nowrap;
|
|
||||||
}
|
|
||||||
.tb-navbar .uk-navbar-center-left,
|
|
||||||
.tb-navbar .uk-navbar-center-right {
|
|
||||||
position: static !important;
|
|
||||||
top: auto !important;
|
|
||||||
left: auto !important;
|
|
||||||
right: auto !important;
|
|
||||||
bottom: auto !important;
|
|
||||||
transform: none !important;
|
|
||||||
display: flex !important;
|
|
||||||
align-items: center;
|
|
||||||
flex: 0 0 auto;
|
|
||||||
white-space: nowrap;
|
|
||||||
}
|
|
||||||
.tb-navbar .uk-navbar-center-left > div,
|
|
||||||
.tb-navbar .uk-navbar-center-right > div {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
white-space: nowrap;
|
|
||||||
}
|
|
||||||
.tb-navbar .uk-navbar-nav {
|
|
||||||
display: flex;
|
|
||||||
flex-wrap: nowrap;
|
|
||||||
flex: 0 0 auto;
|
|
||||||
}
|
|
||||||
.tb-navbar .uk-navbar-nav > li > a,
|
|
||||||
.tb-navbar .uk-logo {
|
|
||||||
white-space: nowrap;
|
|
||||||
}
|
|
||||||
/* 未登录:移动端显示与「我的」等宽的隐藏占位,使左栏「探索+占位」与
|
|
||||||
右栏「注册/登录」两项等宽,logo 真正居中,左右视觉平衡 */
|
|
||||||
.tb-mobile-balancer { display: block; }
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 标签样式的按钮(管理页置顶等):
|
|
||||||
尺寸完全继承 .uk-label(font-size/padding/line-height/text-transform 等),
|
|
||||||
仅覆盖 button 元素特有的默认样式(边框/字体族/光标等),保证与相邻 span 标签完全一致。 */
|
|
||||||
.tb-label-btn {
|
|
||||||
border: none !important;
|
|
||||||
cursor: pointer;
|
|
||||||
font-family: inherit;
|
|
||||||
margin: 0;
|
|
||||||
vertical-align: middle;
|
|
||||||
outline: none;
|
|
||||||
background-image: none;
|
|
||||||
box-sizing: border-box;
|
|
||||||
-webkit-appearance: none;
|
|
||||||
appearance: none;
|
|
||||||
}
|
|
||||||
.tb-label-btn:hover {
|
|
||||||
opacity: 0.85;
|
|
||||||
}
|
|
||||||
/* 公开页置顶小图标:仅一个图钉,不占行高、不影响原布局 */
|
|
||||||
.tb-pin-flag {
|
|
||||||
font-size: 0.9em;
|
|
||||||
margin-right: 4px;
|
|
||||||
vertical-align: -1px;
|
|
||||||
cursor: default;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Markdown 渲染排版(问题/回答/追问正文,左对齐以保留排版格式) */
|
|
||||||
/* 纯文本列表:保留换行与连续空格(pre-wrap),不渲染 Markdown 大字号/彩色 */
|
|
||||||
.tb-preline {
|
|
||||||
white-space: pre-wrap;
|
|
||||||
}
|
|
||||||
/* 纯文本列表:超过 5 行截断并显示省略号(不足 5 行则完整显示) */
|
|
||||||
.tb-clamp-5 {
|
|
||||||
display: -webkit-box;
|
|
||||||
-webkit-box-orient: vertical;
|
|
||||||
-webkit-line-clamp: 5;
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
.md-body {
|
|
||||||
line-height: 1.7;
|
|
||||||
text-align: left;
|
|
||||||
word-break: break-word;
|
|
||||||
}
|
|
||||||
.md-body p { margin: 0.5em 0; }
|
|
||||||
.md-body h1, .md-body h2, .md-body h3,
|
|
||||||
.md-body h4, .md-body h5, .md-body h6 {
|
|
||||||
margin: 0.8em 0 0.4em;
|
|
||||||
font-weight: 600;
|
|
||||||
line-height: 1.4;
|
|
||||||
}
|
|
||||||
.md-body ul, .md-body ol { padding-left: 1.6em; margin: 0.5em 0; }
|
|
||||||
.md-body li { margin: 0.2em 0; }
|
|
||||||
.md-body blockquote {
|
|
||||||
border-left: 3px solid #d3d1c7;
|
|
||||||
margin: 0.6em 0;
|
|
||||||
padding: 0.2em 1em;
|
|
||||||
color: #5f5e5a;
|
|
||||||
}
|
|
||||||
.md-body pre {
|
|
||||||
background: #f5f5f5;
|
|
||||||
padding: 0.8em 1em;
|
|
||||||
border-radius: 6px;
|
|
||||||
overflow-x: auto;
|
|
||||||
margin: 0.6em 0;
|
|
||||||
}
|
|
||||||
.md-body code {
|
|
||||||
background: #f0f0f0;
|
|
||||||
padding: 0.1em 0.35em;
|
|
||||||
border-radius: 4px;
|
|
||||||
font-size: 0.9em;
|
|
||||||
}
|
|
||||||
.md-body pre code { background: none; padding: 0; }
|
|
||||||
.md-body img { max-width: 100%; height: auto; }
|
|
||||||
.md-body table { border-collapse: collapse; margin: 0.6em 0; }
|
|
||||||
.md-body th, .md-body td {
|
|
||||||
border: 1px solid #ddd;
|
|
||||||
padding: 0.4em 0.8em;
|
|
||||||
}
|
|
||||||
.md-body hr { margin: 1em 0; }
|
|
||||||
html[data-theme="dark"] .md-body blockquote {
|
|
||||||
border-color: #3a404c;
|
|
||||||
color: #8b93a1;
|
|
||||||
}
|
|
||||||
html[data-theme="dark"] .md-body pre,
|
|
||||||
html[data-theme="dark"] .md-body code { background: #2d323c; }
|
|
||||||
html[data-theme="dark"] .md-body th,
|
|
||||||
html[data-theme="dark"] .md-body td { border-color: #3a404c; }
|
|
||||||
|
|
||||||
/* 投票结果占比条:模板已改用 UIkit 3 原生 <progress class="uk-progress" value max>,
|
|
||||||
这里只把默认的 15px 高 / 500px 圆角 / 20px 外边距收紧到与页面一致的规格。
|
|
||||||
(原先为 UIkit 2 的 .uk-progressbar 结构打的补丁已删除) */
|
|
||||||
.uk-progress {
|
|
||||||
height: 10px;
|
|
||||||
margin: 0;
|
|
||||||
border-radius: var(--tb-radius-xs);
|
|
||||||
background-color: var(--tb-surface-2);
|
|
||||||
}
|
|
||||||
.uk-progress::-webkit-progress-bar {
|
|
||||||
background-color: var(--tb-surface-2);
|
|
||||||
border-radius: var(--tb-radius-xs);
|
|
||||||
}
|
|
||||||
.uk-progress::-webkit-progress-value {
|
|
||||||
background-color: var(--tb-primary);
|
|
||||||
border-radius: var(--tb-radius-xs) 0 0 var(--tb-radius-xs);
|
|
||||||
}
|
|
||||||
.uk-progress::-moz-progress-bar {
|
|
||||||
background-color: var(--tb-primary);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 移动端底部操作栏:固定底栏承载语言切换与深色模式,桌面端隐藏 */
|
|
||||||
#tb-mobile-utils {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
@media (max-width: 640px) {
|
|
||||||
/* 顶栏不再容纳语言/深色按钮,恢复原有导航空间 */
|
|
||||||
.tb-nav-utils {
|
|
||||||
display: none !important;
|
|
||||||
}
|
|
||||||
/* 手机端隐藏登录用户名(左边仅保留"探索"),保证 logo 居中、
|
|
||||||
两侧各不超过 2 个短按钮,避免用户名宽度挤压布局 */
|
|
||||||
.tb-nav-username {
|
|
||||||
display: none !important;
|
|
||||||
}
|
|
||||||
/* 固定底部操作栏 */
|
|
||||||
#tb-mobile-utils {
|
|
||||||
display: flex;
|
|
||||||
position: fixed;
|
|
||||||
left: 0;
|
|
||||||
right: 0;
|
|
||||||
bottom: 0;
|
|
||||||
z-index: 1000;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
gap: 10px;
|
|
||||||
padding: 8px 12px calc(8px + env(safe-area-inset-bottom));
|
|
||||||
background: rgba(255, 255, 255, 0.92);
|
|
||||||
-webkit-backdrop-filter: blur(8px);
|
|
||||||
backdrop-filter: blur(8px);
|
|
||||||
box-shadow: 0 -2px 12px rgba(0, 0, 0, 0.08);
|
|
||||||
}
|
|
||||||
#tb-mobile-utils .uk-select {
|
|
||||||
width: 110px;
|
|
||||||
}
|
|
||||||
html[data-theme="dark"] #tb-mobile-utils {
|
|
||||||
background: rgba(36, 40, 48, 0.92);
|
|
||||||
box-shadow: 0 -2px 12px rgba(0, 0, 0, 0.4);
|
|
||||||
}
|
|
||||||
/* 给页面底部预留空间,避免页脚内容被固定底栏遮挡 */
|
|
||||||
body {
|
|
||||||
padding-bottom: 56px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
||||||
<link rel="stylesheet" href="https://r2.337845818.best/tamabox/cdn/waline/client/v2/waline-no-commits.css" media="print" onload="this.media='all'"/>
|
<link rel="stylesheet" href="https://r2.337845818.best/tamabox/cdn/waline/client/v2/waline-no-commits.css" media="print" onload="this.media='all'"/>
|
||||||
<script defer src="https://cdnjs.cloudflare.com/ajax/libs/uikit/3.3.3/js/uikit.min.js"></script>
|
<script defer src="https://cdnjs.cloudflare.com/ajax/libs/uikit/3.3.3/js/uikit.min.js"></script>
|
||||||
@@ -1728,6 +1061,40 @@ document.addEventListener("DOMContentLoaded", function() {
|
|||||||
<span class="tb-account-note">您随时可以选择停用您的账号。停用后,您的账号将无法登录,您的提问箱页面以及提问将无法访问,其他人也无法再给您发送新的提问。<b>该操作无法撤销!请谨慎操作!</b></span>
|
<span class="tb-account-note">您随时可以选择停用您的账号。停用后,您的账号将无法登录,您的提问箱页面以及提问将无法访问,其他人也无法再给您发送新的提问。<b>该操作无法撤销!请谨慎操作!</b></span>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
|
||||||
|
<section class="tb-pcard">
|
||||||
|
<h3 class="tb-pcard-title">主题外观</h3>
|
||||||
|
<form method="post" action="/user/profile/theme">
|
||||||
|
<input type="hidden" name="_csrf" value="x">
|
||||||
|
<p class="tb-theme-hint">仅对提问箱页面生效,站内其它页面保持默认外观。</p>
|
||||||
|
<div class="tb-theme-grid">
|
||||||
|
<label class="tb-theme-opt">
|
||||||
|
<input class="uk-radio" type="radio" name="theme" value="">
|
||||||
|
<span class="tb-theme-swatch" style="background: linear-gradient(135deg, var(--tb-surface-2) 0 55%, var(--tb-border) 55% 100%)"></span>
|
||||||
|
<span class="tb-theme-name">跟随站点默认</span>
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<label class="tb-theme-opt">
|
||||||
|
<input class="uk-radio" type="radio" name="theme" value="default">
|
||||||
|
<span class="tb-theme-swatch"></span>
|
||||||
|
<span class="tb-theme-name">基础外观</span>
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<label class="tb-theme-opt">
|
||||||
|
<input class="uk-radio" type="radio" name="theme" value="sakura" checked>
|
||||||
|
<span class="tb-theme-swatch" style="background: ZgotmplZ"></span>
|
||||||
|
<span class="tb-theme-name">樱花</span>
|
||||||
|
</label>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<div class="tb-card-save">
|
||||||
|
<button type="submit" class="uk-button uk-button-primary">保存主题</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
<title>预览 12:01 · 设置</title>
|
<title>预览 15:15 · 设置</title>
|
||||||
<meta name="msvalidate.01" content="2F185E8E63C93635F50B3574F3B31E42" />
|
<meta name="msvalidate.01" content="2F185E8E63C93635F50B3574F3B31E42" />
|
||||||
<meta name="description" content="狼的提问箱——一个无需注册、可匿名提问的匿名提问箱,安全地倾诉与回应。">
|
<meta name="description" content="狼的提问箱——一个无需注册、可匿名提问的匿名提问箱,安全地倾诉与回应。">
|
||||||
<meta name="keywords" content="匿名提问箱,提问箱,匿名提问,狼的提问箱,匿名问答,匿名提问网站">
|
<meta name="keywords" content="匿名提问箱,提问箱,匿名提问,狼的提问箱,匿名问答,匿名提问网站">
|
||||||
@@ -20,675 +20,8 @@
|
|||||||
|
|
||||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/uikit/3.3.3/css/uikit.min.css"/>
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/uikit/3.3.3/css/uikit.min.css"/>
|
||||||
|
|
||||||
<style>/* TamaBox 全站基础样式:设计令牌 / 主题覆盖 / 组件质感 / 响应式。
|
<link rel="stylesheet" href="/static/css/base.css?v="/>
|
||||||
由 base/header.html 内联块抽出,集中一份便于缓存与维护。
|
|
||||||
⚠️ 改完务必把 header 里的 ?v= 版本号 +1,否则老访客仍用缓存。 */
|
|
||||||
|
|
||||||
/* 设计令牌:亮色为默认(:root),深色在 html[data-theme="dark"] 覆盖。
|
|
||||||
页面与组件样式一律引用 var(--tb-*),不再写死色值/圆角/阴影;
|
|
||||||
var() 的第二个参数仅作兜底(旧缓存页、邮件模板等不引入本文件的场景)。
|
|
||||||
改配色只动这一块,亮暗两套自动保持一致。 */
|
|
||||||
:root {
|
|
||||||
--tb-bg: #f7f8fa;
|
|
||||||
--tb-surface: #ffffff;
|
|
||||||
--tb-surface-2: #f4f6f8;
|
|
||||||
--tb-surface-hover: #f3f7ff;
|
|
||||||
--tb-border: #e8eaee;
|
|
||||||
--tb-text: #1f2329;
|
|
||||||
--tb-text-secondary: #5c6370;
|
|
||||||
--tb-text-muted: #8a919c;
|
|
||||||
--tb-primary: #1e87f0;
|
|
||||||
--tb-primary-weak: rgba(30, 135, 240, 0.10);
|
|
||||||
--tb-radius: 12px;
|
|
||||||
--tb-radius-sm: 8px;
|
|
||||||
--tb-radius-xs: 6px;
|
|
||||||
--tb-shadow: 0 1px 2px rgba(16, 24, 40, 0.04), 0 12px 28px -18px rgba(16, 24, 40, 0.20);
|
|
||||||
--tb-shadow-hover: 0 1px 2px rgba(16, 24, 40, 0.05), 0 18px 40px -20px rgba(16, 24, 40, 0.28);
|
|
||||||
--tb-font: system-ui, -apple-system, "Segoe UI", "PingFang SC", "Hiragino Sans GB", "Noto Sans CJK SC", "Microsoft YaHei", sans-serif;
|
|
||||||
}
|
|
||||||
html[data-theme="dark"] {
|
|
||||||
--tb-bg: #1a1d23;
|
|
||||||
--tb-surface: #242830;
|
|
||||||
--tb-surface-2: #2d323c;
|
|
||||||
--tb-surface-hover: rgba(92, 141, 255, 0.12);
|
|
||||||
--tb-border: #3a404c;
|
|
||||||
--tb-text: #d8dce4;
|
|
||||||
--tb-text-secondary: #a8b0bd;
|
|
||||||
--tb-text-muted: #8b93a1;
|
|
||||||
--tb-primary: #5c8dff;
|
|
||||||
--tb-primary-weak: rgba(92, 141, 255, 0.14);
|
|
||||||
--tb-shadow: 0 1px 2px rgba(0, 0, 0, 0.30), 0 12px 28px -18px rgba(0, 0, 0, 0.55);
|
|
||||||
--tb-shadow-hover: 0 1px 2px rgba(0, 0, 0, 0.35), 0 18px 40px -20px rgba(0, 0, 0, 0.65);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* UIkit 补丁:复刻原自建版 "modify-black-font"(官方版与自建版仅 3 处颜色差异——把有色容器内默认白字/白标题改为黑字)。
|
|
||||||
模板当前只用到 .uk-light 容器(用户背景封面,question/list.html、question-not-found.html;
|
|
||||||
其中 h3/p 已由 #usernamecolor/#introcolor 内联 style 覆盖),故只需补该容器的 3 处投影即可保持渲染一致。
|
|
||||||
若日后新增 .uk-card-primary/.uk-card-secondary/.uk-section-primary/.uk-tile-*/.uk-overlay-primary 等容器且需黑字,须同步扩展。 */
|
|
||||||
.uk-light { color: rgba(0,0,0,.7); }
|
|
||||||
.uk-light .uk-h1, .uk-light .uk-h2, .uk-light .uk-h3, .uk-light .uk-h4, .uk-light .uk-h5, .uk-light .uk-h6,
|
|
||||||
.uk-light .uk-heading-2xlarge, .uk-light .uk-heading-large, .uk-light .uk-heading-medium, .uk-light .uk-heading-small, .uk-light .uk-heading-xlarge,
|
|
||||||
.uk-light h1, .uk-light h2, .uk-light h3, .uk-light h4, .uk-light h5, .uk-light h6 { color: #000; }
|
|
||||||
.uk-light .uk-table th { color: rgba(0,0,0,.7); }
|
|
||||||
|
|
||||||
.grecaptcha-badge {visibility: hidden;}
|
|
||||||
.icon-container {
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
.icon {
|
|
||||||
margin-left: 10px;
|
|
||||||
width: 20px; /* 设置图标的宽度 */
|
|
||||||
height: auto; /* 保持图标的高度自动调整 */
|
|
||||||
}
|
|
||||||
.emoji-placeholder {
|
|
||||||
display: inline-block;
|
|
||||||
animation: jump 0.5s ease-in-out;
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes jump {
|
|
||||||
0%, 100% { transform: translateY(0); }
|
|
||||||
50% { transform: translateY(-5px); }
|
|
||||||
}
|
|
||||||
/* 防止 UIkit Dropbar 初始闪烁 */
|
|
||||||
.uk-dropbar {
|
|
||||||
opacity: 0;
|
|
||||||
visibility: hidden;
|
|
||||||
transition: opacity 0.2s ease, visibility 0.2s ease;
|
|
||||||
}
|
|
||||||
|
|
||||||
.uk-dropbar.uk-open {
|
|
||||||
opacity: 1;
|
|
||||||
visibility: visible;
|
|
||||||
}
|
|
||||||
|
|
||||||
a.uk-button.uk-button-link {
|
|
||||||
text-transform: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 移动端优化:缩小字体和间距,避免右侧空白 */
|
|
||||||
@media (max-width: 640px) {
|
|
||||||
.uk-logo {
|
|
||||||
font-size: 1rem;
|
|
||||||
}
|
|
||||||
.uk-navbar-nav a {
|
|
||||||
font-size: 0.78rem;
|
|
||||||
padding: 0 4px;
|
|
||||||
}
|
|
||||||
.emoji-placeholder {
|
|
||||||
font-size: 1rem;
|
|
||||||
}
|
|
||||||
/* 移动端用户名限宽省略,避免长英文用户名撑爆顶栏 */
|
|
||||||
.tb-nav-username {
|
|
||||||
max-width: 64px;
|
|
||||||
overflow: hidden;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
white-space: nowrap;
|
|
||||||
display: inline-block;
|
|
||||||
vertical-align: middle;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 深色模式:html[data-theme="dark"] 时覆盖 UIkit 3.3.3 编译主题的关键颜色 */
|
|
||||||
/* 变量(--tb-*)已上移到 head 顶部的令牌块,亮暗两套同名常量在那里定义。 */
|
|
||||||
/* 根元素与 body 一起覆盖,确保整个视口(含内容不足一屏时的空白区)都是深色背景 */
|
|
||||||
html[data-theme="dark"],
|
|
||||||
html[data-theme="dark"] body {
|
|
||||||
background-color: var(--tb-bg) !important;
|
|
||||||
color: var(--tb-text) !important;
|
|
||||||
}
|
|
||||||
/* 通用表面容器 */
|
|
||||||
html[data-theme="dark"] .uk-card,
|
|
||||||
html[data-theme="dark"] .uk-card-default,
|
|
||||||
html[data-theme="dark"] .uk-card-secondary,
|
|
||||||
html[data-theme="dark"] .uk-dropbar,
|
|
||||||
html[data-theme="dark"] .uk-navbar-dropdown,
|
|
||||||
html[data-theme="dark"] .uk-modal-dialog,
|
|
||||||
html[data-theme="dark"] .uk-dropdown,
|
|
||||||
html[data-theme="dark"] .uk-offcanvas-bar,
|
|
||||||
html[data-theme="dark"] .uk-section,
|
|
||||||
html[data-theme="dark"] .uk-tile,
|
|
||||||
html[data-theme="dark"] .uk-panel,
|
|
||||||
html[data-theme="dark"] .uk-background-default,
|
|
||||||
html[data-theme="dark"] .uk-search-default .uk-search-input {
|
|
||||||
background-color: var(--tb-surface) !important;
|
|
||||||
color: var(--tb-text) !important;
|
|
||||||
}
|
|
||||||
html[data-theme="dark"] .uk-navbar-container {
|
|
||||||
background-color: var(--tb-surface) !important;
|
|
||||||
color: var(--tb-text) !important;
|
|
||||||
}
|
|
||||||
html[data-theme="dark"] .uk-navbar-nav > li > a,
|
|
||||||
html[data-theme="dark"] .uk-card a,
|
|
||||||
html[data-theme="dark"] .uk-link,
|
|
||||||
html[data-theme="dark"] a.uk-button-link,
|
|
||||||
html[data-theme="dark"] .uk-navbar-dropdown-nav > li > a,
|
|
||||||
html[data-theme="dark"] .uk-dropdown-nav > li > a,
|
|
||||||
html[data-theme="dark"] .uk-list a {
|
|
||||||
color: var(--tb-text) !important;
|
|
||||||
}
|
|
||||||
html[data-theme="dark"] .uk-navbar-nav > li > a:hover,
|
|
||||||
html[data-theme="dark"] .uk-card a:hover,
|
|
||||||
html[data-theme="dark"] .uk-navbar-dropdown-nav > li > a:hover,
|
|
||||||
html[data-theme="dark"] .uk-dropdown-nav > li > a:hover {
|
|
||||||
color: var(--tb-primary) !important;
|
|
||||||
}
|
|
||||||
html[data-theme="dark"] .uk-input,
|
|
||||||
html[data-theme="dark"] .uk-textarea,
|
|
||||||
html[data-theme="dark"] .uk-select {
|
|
||||||
background-color: var(--tb-surface-2) !important;
|
|
||||||
color: var(--tb-text) !important;
|
|
||||||
border-color: var(--tb-border) !important;
|
|
||||||
}
|
|
||||||
html[data-theme="dark"] .uk-input:focus,
|
|
||||||
html[data-theme="dark"] .uk-textarea:focus,
|
|
||||||
html[data-theme="dark"] .uk-select:focus {
|
|
||||||
border-color: var(--tb-primary) !important;
|
|
||||||
}
|
|
||||||
html[data-theme="dark"] .uk-text-muted,
|
|
||||||
html[data-theme="dark"] .uk-text-meta,
|
|
||||||
html[data-theme="dark"] .uk-text-secondary,
|
|
||||||
html[data-theme="dark"] .uk-text-muted a,
|
|
||||||
html[data-theme="dark"] .uk-text-small.uk-text-muted {
|
|
||||||
color: var(--tb-text-muted) !important;
|
|
||||||
}
|
|
||||||
html[data-theme="dark"] .uk-divider-icon::after,
|
|
||||||
html[data-theme="dark"] hr,
|
|
||||||
html[data-theme="dark"] .uk-table th,
|
|
||||||
html[data-theme="dark"] .uk-table td,
|
|
||||||
html[data-theme="dark"] .uk-list-divider > li:nth-child(n+2) {
|
|
||||||
border-color: var(--tb-border) !important;
|
|
||||||
}
|
|
||||||
html[data-theme="dark"] .uk-button-default {
|
|
||||||
background-color: var(--tb-surface-2) !important;
|
|
||||||
color: var(--tb-text) !important;
|
|
||||||
border-color: var(--tb-border) !important;
|
|
||||||
}
|
|
||||||
html[data-theme="dark"] .uk-modal-title,
|
|
||||||
html[data-theme="dark"] h1, html[data-theme="dark"] h2, html[data-theme="dark"] h3,
|
|
||||||
html[data-theme="dark"] h4, html[data-theme="dark"] h5, html[data-theme="dark"] h6,
|
|
||||||
html[data-theme="dark"] .uk-card-title {
|
|
||||||
color: var(--tb-text) !important;
|
|
||||||
}
|
|
||||||
html[data-theme="dark"] .uk-alert-warning,
|
|
||||||
html[data-theme="dark"] .uk-alert-danger,
|
|
||||||
html[data-theme="dark"] .uk-alert-success,
|
|
||||||
html[data-theme="dark"] .uk-alert-primary {
|
|
||||||
background-color: var(--tb-surface-2) !important;
|
|
||||||
color: var(--tb-text) !important;
|
|
||||||
}
|
|
||||||
html[data-theme="dark"] #math-captcha-modal .uk-modal-dialog {
|
|
||||||
background-color: var(--tb-surface) !important;
|
|
||||||
color: var(--tb-text) !important;
|
|
||||||
}
|
|
||||||
html[data-theme="dark"] #math-captcha-modal .captcha-equation-box {
|
|
||||||
background-color: var(--tb-surface-2) !important;
|
|
||||||
border-color: var(--tb-border) !important;
|
|
||||||
}
|
|
||||||
html[data-theme="dark"] #math-captcha-modal .math-captcha-modal-question {
|
|
||||||
color: var(--tb-text) !important;
|
|
||||||
}
|
|
||||||
html[data-theme="dark"] #math-captcha-modal #captcha-modal-answer {
|
|
||||||
background-color: var(--tb-surface) !important;
|
|
||||||
color: var(--tb-text) !important;
|
|
||||||
border-color: var(--tb-border) !important;
|
|
||||||
}
|
|
||||||
html[data-theme="dark"] #math-captcha-modal #captcha-modal-answer::placeholder {
|
|
||||||
color: var(--tb-text-muted) !important;
|
|
||||||
}
|
|
||||||
html[data-theme="dark"] #math-captcha-modal .uk-text-meta,
|
|
||||||
html[data-theme="dark"] #math-captcha-modal #captcha-modal-refresh {
|
|
||||||
color: var(--tb-text-muted) !important;
|
|
||||||
}
|
|
||||||
html[data-theme="dark"] #math-captcha-modal #captcha-modal-refresh:hover {
|
|
||||||
color: var(--tb-primary) !important;
|
|
||||||
}
|
|
||||||
html[data-theme="dark"] .uk-label {
|
|
||||||
color: #fff !important;
|
|
||||||
}
|
|
||||||
/* 自定义组件(探索页推荐卡片等)深色覆盖 */
|
|
||||||
html[data-theme="dark"] .recommend-card,
|
|
||||||
html[data-theme="dark"] .recommend-card:hover {
|
|
||||||
background-color: var(--tb-surface-2) !important;
|
|
||||||
}
|
|
||||||
html[data-theme="dark"] .explore-name a {
|
|
||||||
color: var(--tb-text) !important;
|
|
||||||
}
|
|
||||||
html[data-theme="dark"] .explore-name a:hover {
|
|
||||||
color: var(--tb-primary) !important;
|
|
||||||
}
|
|
||||||
html[data-theme="dark"] .explore-intro {
|
|
||||||
color: var(--tb-text-muted) !important;
|
|
||||||
}
|
|
||||||
/* 切换按钮图标切换(内联 SVG,不依赖 UIkit 图标库) */
|
|
||||||
#theme-toggle .tb-icon-light, #theme-toggle-mobile .tb-icon-light,
|
|
||||||
#theme-toggle .tb-icon-dark, #theme-toggle-mobile .tb-icon-dark {
|
|
||||||
display: inline-flex;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
#theme-toggle .tb-icon-light svg, #theme-toggle-mobile .tb-icon-light svg,
|
|
||||||
#theme-toggle .tb-icon-dark svg, #theme-toggle-mobile .tb-icon-dark svg { display: block; }
|
|
||||||
#theme-toggle .tb-icon-dark, #theme-toggle-mobile .tb-icon-dark { display: none; }
|
|
||||||
html[data-theme="dark"] #theme-toggle .tb-icon-light,
|
|
||||||
html[data-theme="dark"] #theme-toggle-mobile .tb-icon-light { display: none; }
|
|
||||||
html[data-theme="dark"] #theme-toggle .tb-icon-dark,
|
|
||||||
html[data-theme="dark"] #theme-toggle-mobile .tb-icon-dark { display: inline-flex; }
|
|
||||||
|
|
||||||
/* 基础质感层:只调整外观(圆角/投影/字体/数字对齐),不改任何结构与布局。
|
|
||||||
颜色一律取自头部令牌,亮暗两套自动生效,因此这里不需要再写 html[data-theme="dark"] 分支。 */
|
|
||||||
/* 根元素与 body 同时上色:内容不足一屏时,body 之外的视口区域也要是同一底色 */
|
|
||||||
html,
|
|
||||||
body {
|
|
||||||
font-family: var(--tb-font);
|
|
||||||
background-color: var(--tb-bg);
|
|
||||||
color: var(--tb-text);
|
|
||||||
-webkit-font-smoothing: antialiased;
|
|
||||||
-moz-osx-font-smoothing: grayscale;
|
|
||||||
}
|
|
||||||
/* 卡片:12px 圆角 + 一层极淡接触影 + 一层大扩散影(UIkit 默认的 0 5px 15px 偏硬) */
|
|
||||||
.uk-card {
|
|
||||||
border-radius: var(--tb-radius);
|
|
||||||
}
|
|
||||||
.uk-card-default {
|
|
||||||
background-color: var(--tb-surface);
|
|
||||||
box-shadow: var(--tb-shadow);
|
|
||||||
}
|
|
||||||
.uk-card-default.uk-card-hover:hover {
|
|
||||||
box-shadow: var(--tb-shadow-hover);
|
|
||||||
}
|
|
||||||
.uk-card-header {
|
|
||||||
border-radius: var(--tb-radius) var(--tb-radius) 0 0;
|
|
||||||
}
|
|
||||||
.uk-card-footer {
|
|
||||||
border-radius: 0 0 var(--tb-radius) var(--tb-radius);
|
|
||||||
}
|
|
||||||
.uk-card,
|
|
||||||
.uk-button,
|
|
||||||
.uk-alert,
|
|
||||||
.uk-label {
|
|
||||||
transition: box-shadow 0.18s ease, background-color 0.18s ease, border-color 0.18s ease, color 0.18s ease;
|
|
||||||
}
|
|
||||||
/* 交互元素:统一 8px 圆角,标签 6px */
|
|
||||||
.uk-button {
|
|
||||||
border-radius: var(--tb-radius-sm);
|
|
||||||
}
|
|
||||||
.uk-input,
|
|
||||||
.uk-select,
|
|
||||||
.uk-textarea,
|
|
||||||
.uk-form-small,
|
|
||||||
.uk-search-input {
|
|
||||||
border-radius: var(--tb-radius-sm);
|
|
||||||
}
|
|
||||||
.uk-label {
|
|
||||||
border-radius: var(--tb-radius-xs);
|
|
||||||
}
|
|
||||||
.uk-alert {
|
|
||||||
border-radius: 10px;
|
|
||||||
}
|
|
||||||
.uk-modal-dialog {
|
|
||||||
border-radius: 14px;
|
|
||||||
}
|
|
||||||
.uk-dropdown,
|
|
||||||
.uk-navbar-dropdown {
|
|
||||||
border-radius: 10px;
|
|
||||||
box-shadow: var(--tb-shadow);
|
|
||||||
}
|
|
||||||
.uk-navbar-container:not(.uk-navbar-transparent) {
|
|
||||||
background-color: var(--tb-surface);
|
|
||||||
}
|
|
||||||
/* 键盘可达性:仅在键盘聚焦时出现描边,鼠标点击不出现 */
|
|
||||||
.uk-button:focus-visible,
|
|
||||||
.uk-navbar-nav > li > a:focus-visible {
|
|
||||||
outline: 2px solid var(--tb-primary);
|
|
||||||
outline-offset: 2px;
|
|
||||||
}
|
|
||||||
/* 次要文字统一走令牌,避免 #999 / #8a919c 混用 */
|
|
||||||
.uk-text-muted,
|
|
||||||
.uk-text-meta {
|
|
||||||
color: var(--tb-text-muted);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 轻量胶囊:用于投票类型、热门标签等「只是分类信息」的位置。
|
|
||||||
实心 uk-label 一屏多个会变成一排色块,这里统一降级为浅底 + 次要色文字。 */
|
|
||||||
.tb-chip {
|
|
||||||
display: inline-block;
|
|
||||||
padding: 1px 8px;
|
|
||||||
border-radius: var(--tb-radius-xs);
|
|
||||||
background-color: var(--tb-surface-2);
|
|
||||||
color: var(--tb-text-secondary);
|
|
||||||
font-size: 0.72rem;
|
|
||||||
line-height: 1.7;
|
|
||||||
white-space: nowrap;
|
|
||||||
}
|
|
||||||
a.tb-chip:hover {
|
|
||||||
background-color: var(--tb-primary-weak);
|
|
||||||
color: var(--tb-primary);
|
|
||||||
text-decoration: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 统计/日期等数字列等宽对齐,避免刷新时左右跳动 */
|
|
||||||
.uk-table,
|
|
||||||
.tb-num {
|
|
||||||
font-variant-numeric: tabular-nums;
|
|
||||||
}
|
|
||||||
/* 图片上传条:原为 item/new-question 两处各写一份内联 style(写死 #f8f8f8,深色下露白),
|
|
||||||
收敛到一处并走令牌,亮暗自动适配 */
|
|
||||||
.tb-img-uploader {
|
|
||||||
width: 100%;
|
|
||||||
background-color: var(--tb-surface-2);
|
|
||||||
display: flex;
|
|
||||||
padding-top: 5px;
|
|
||||||
padding-bottom: 5px;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: flex-start;
|
|
||||||
gap: 5px;
|
|
||||||
}
|
|
||||||
/* 背景图封面(提问箱主页):渐变遮罩,保证用户自选文字色叠加后仍可读。
|
|
||||||
默认浅色遮罩(页面 .uk-light 补丁把文字兜底成深色);若箱主选了浅色文字,
|
|
||||||
question/list.html 会按亮度加上 .tb-cover-dark 换成深色遮罩。 */
|
|
||||||
.tb-cover {
|
|
||||||
position: relative;
|
|
||||||
border-radius: var(--tb-radius) var(--tb-radius) 0 0;
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
/* ⚠️ 必须带 .uk-flex 复合选择器:UIkit 3.3.3 里有
|
|
||||||
.uk-flex::after,.uk-flex::before{display:none}(优先级 0,2,0),
|
|
||||||
会把这个遮罩伪元素整个干掉——不报错、只是什么都不显示(踩过一次)。
|
|
||||||
单写 .tb-cover::after 优先级不够,会被它压回 display:none。 */
|
|
||||||
.tb-cover::after,
|
|
||||||
.tb-cover.uk-flex::after {
|
|
||||||
content: "";
|
|
||||||
display: block;
|
|
||||||
position: absolute;
|
|
||||||
inset: 0;
|
|
||||||
z-index: 0;
|
|
||||||
background: linear-gradient(180deg, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.58) 55%, rgba(255, 255, 255, 0.84) 100%);
|
|
||||||
pointer-events: none;
|
|
||||||
}
|
|
||||||
.tb-cover.tb-cover-dark::after {
|
|
||||||
background: linear-gradient(180deg, rgba(0, 0, 0, 0) 0%, rgba(0, 0, 0, 0.16) 45%, rgba(0, 0, 0, 0.46) 100%);
|
|
||||||
}
|
|
||||||
.tb-cover > * {
|
|
||||||
position: relative;
|
|
||||||
z-index: 1;
|
|
||||||
}
|
|
||||||
.tb-cover h3,
|
|
||||||
.tb-cover p {
|
|
||||||
text-shadow: 0 1px 10px rgba(255, 255, 255, 0.65);
|
|
||||||
}
|
|
||||||
.tb-cover.tb-cover-dark h3,
|
|
||||||
.tb-cover.tb-cover-dark p {
|
|
||||||
text-shadow: 0 1px 12px rgba(0, 0, 0, 0.45);
|
|
||||||
}
|
|
||||||
/* 尊重系统的减少动效设置 */
|
|
||||||
@media (prefers-reduced-motion: reduce) {
|
|
||||||
.uk-card,
|
|
||||||
.uk-button,
|
|
||||||
.emoji-placeholder {
|
|
||||||
transition: none;
|
|
||||||
animation: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 顶栏自适应:导航全部直接显示,窄屏时分级缩小字号/间距,保证英文/日文等长文字不溢出 */
|
|
||||||
.uk-navbar-nav a {
|
|
||||||
font-size: 0.95rem;
|
|
||||||
padding: 0 10px;
|
|
||||||
}
|
|
||||||
/* 未登录移动端占位:桌面端隐藏,仅 ≤640px 显示(见下方 media 查询)。
|
|
||||||
桌面端布局与改动前完全一致,不受影响。 */
|
|
||||||
.tb-mobile-balancer { display: none; }
|
|
||||||
/* 桌面端保持 UIkit 原生居中三列布局(无需额外 CSS) */
|
|
||||||
.tb-navbar .uk-logo {
|
|
||||||
white-space: nowrap;
|
|
||||||
}
|
|
||||||
@media (max-width: 1200px) {
|
|
||||||
.uk-navbar-nav a {
|
|
||||||
font-size: 0.88rem;
|
|
||||||
padding: 0 8px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@media (max-width: 1000px) {
|
|
||||||
.uk-navbar-nav a {
|
|
||||||
font-size: 0.82rem;
|
|
||||||
padding: 0 6px;
|
|
||||||
}
|
|
||||||
.uk-logo {
|
|
||||||
font-size: 1.1rem;
|
|
||||||
}
|
|
||||||
/* 登录用户名限宽,过长省略号截断 */
|
|
||||||
.tb-nav-username {
|
|
||||||
max-width: 110px;
|
|
||||||
overflow: hidden;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
white-space: nowrap;
|
|
||||||
display: inline-block;
|
|
||||||
vertical-align: middle;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@media (max-width: 800px) {
|
|
||||||
.uk-navbar-nav a {
|
|
||||||
font-size: 0.78rem;
|
|
||||||
padding: 0 4px;
|
|
||||||
}
|
|
||||||
.uk-logo {
|
|
||||||
font-size: 1rem;
|
|
||||||
}
|
|
||||||
.tb-nav-username {
|
|
||||||
max-width: 80px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* 手机端(≤640px):沿用 UIkit 桌面端 navbar 的原生三列定位。
|
|
||||||
不再重写 .uk-navbar-center / center-left / center-right 的定位,
|
|
||||||
避免 logo 被挤到下一行;底部语言与深色模式按钮仍由下方独立栏承载。 */
|
|
||||||
@media (max-width: 640px) {
|
|
||||||
.tb-navbar {
|
|
||||||
position: relative;
|
|
||||||
min-height: 56px;
|
|
||||||
overflow: visible;
|
|
||||||
}
|
|
||||||
.tb-navbar > .uk-navbar-center {
|
|
||||||
position: relative !important;
|
|
||||||
top: auto !important;
|
|
||||||
left: auto !important;
|
|
||||||
right: auto !important;
|
|
||||||
bottom: auto !important;
|
|
||||||
transform: none !important;
|
|
||||||
display: flex !important;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
width: 100%;
|
|
||||||
min-height: 56px;
|
|
||||||
white-space: nowrap;
|
|
||||||
flex-wrap: nowrap;
|
|
||||||
}
|
|
||||||
.tb-navbar .uk-navbar-center-left,
|
|
||||||
.tb-navbar .uk-navbar-center-right {
|
|
||||||
position: static !important;
|
|
||||||
top: auto !important;
|
|
||||||
left: auto !important;
|
|
||||||
right: auto !important;
|
|
||||||
bottom: auto !important;
|
|
||||||
transform: none !important;
|
|
||||||
display: flex !important;
|
|
||||||
align-items: center;
|
|
||||||
flex: 0 0 auto;
|
|
||||||
white-space: nowrap;
|
|
||||||
}
|
|
||||||
.tb-navbar .uk-navbar-center-left > div,
|
|
||||||
.tb-navbar .uk-navbar-center-right > div {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
white-space: nowrap;
|
|
||||||
}
|
|
||||||
.tb-navbar .uk-navbar-nav {
|
|
||||||
display: flex;
|
|
||||||
flex-wrap: nowrap;
|
|
||||||
flex: 0 0 auto;
|
|
||||||
}
|
|
||||||
.tb-navbar .uk-navbar-nav > li > a,
|
|
||||||
.tb-navbar .uk-logo {
|
|
||||||
white-space: nowrap;
|
|
||||||
}
|
|
||||||
/* 未登录:移动端显示与「我的」等宽的隐藏占位,使左栏「探索+占位」与
|
|
||||||
右栏「注册/登录」两项等宽,logo 真正居中,左右视觉平衡 */
|
|
||||||
.tb-mobile-balancer { display: block; }
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 标签样式的按钮(管理页置顶等):
|
|
||||||
尺寸完全继承 .uk-label(font-size/padding/line-height/text-transform 等),
|
|
||||||
仅覆盖 button 元素特有的默认样式(边框/字体族/光标等),保证与相邻 span 标签完全一致。 */
|
|
||||||
.tb-label-btn {
|
|
||||||
border: none !important;
|
|
||||||
cursor: pointer;
|
|
||||||
font-family: inherit;
|
|
||||||
margin: 0;
|
|
||||||
vertical-align: middle;
|
|
||||||
outline: none;
|
|
||||||
background-image: none;
|
|
||||||
box-sizing: border-box;
|
|
||||||
-webkit-appearance: none;
|
|
||||||
appearance: none;
|
|
||||||
}
|
|
||||||
.tb-label-btn:hover {
|
|
||||||
opacity: 0.85;
|
|
||||||
}
|
|
||||||
/* 公开页置顶小图标:仅一个图钉,不占行高、不影响原布局 */
|
|
||||||
.tb-pin-flag {
|
|
||||||
font-size: 0.9em;
|
|
||||||
margin-right: 4px;
|
|
||||||
vertical-align: -1px;
|
|
||||||
cursor: default;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Markdown 渲染排版(问题/回答/追问正文,左对齐以保留排版格式) */
|
|
||||||
/* 纯文本列表:保留换行与连续空格(pre-wrap),不渲染 Markdown 大字号/彩色 */
|
|
||||||
.tb-preline {
|
|
||||||
white-space: pre-wrap;
|
|
||||||
}
|
|
||||||
/* 纯文本列表:超过 5 行截断并显示省略号(不足 5 行则完整显示) */
|
|
||||||
.tb-clamp-5 {
|
|
||||||
display: -webkit-box;
|
|
||||||
-webkit-box-orient: vertical;
|
|
||||||
-webkit-line-clamp: 5;
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
.md-body {
|
|
||||||
line-height: 1.7;
|
|
||||||
text-align: left;
|
|
||||||
word-break: break-word;
|
|
||||||
}
|
|
||||||
.md-body p { margin: 0.5em 0; }
|
|
||||||
.md-body h1, .md-body h2, .md-body h3,
|
|
||||||
.md-body h4, .md-body h5, .md-body h6 {
|
|
||||||
margin: 0.8em 0 0.4em;
|
|
||||||
font-weight: 600;
|
|
||||||
line-height: 1.4;
|
|
||||||
}
|
|
||||||
.md-body ul, .md-body ol { padding-left: 1.6em; margin: 0.5em 0; }
|
|
||||||
.md-body li { margin: 0.2em 0; }
|
|
||||||
.md-body blockquote {
|
|
||||||
border-left: 3px solid #d3d1c7;
|
|
||||||
margin: 0.6em 0;
|
|
||||||
padding: 0.2em 1em;
|
|
||||||
color: #5f5e5a;
|
|
||||||
}
|
|
||||||
.md-body pre {
|
|
||||||
background: #f5f5f5;
|
|
||||||
padding: 0.8em 1em;
|
|
||||||
border-radius: 6px;
|
|
||||||
overflow-x: auto;
|
|
||||||
margin: 0.6em 0;
|
|
||||||
}
|
|
||||||
.md-body code {
|
|
||||||
background: #f0f0f0;
|
|
||||||
padding: 0.1em 0.35em;
|
|
||||||
border-radius: 4px;
|
|
||||||
font-size: 0.9em;
|
|
||||||
}
|
|
||||||
.md-body pre code { background: none; padding: 0; }
|
|
||||||
.md-body img { max-width: 100%; height: auto; }
|
|
||||||
.md-body table { border-collapse: collapse; margin: 0.6em 0; }
|
|
||||||
.md-body th, .md-body td {
|
|
||||||
border: 1px solid #ddd;
|
|
||||||
padding: 0.4em 0.8em;
|
|
||||||
}
|
|
||||||
.md-body hr { margin: 1em 0; }
|
|
||||||
html[data-theme="dark"] .md-body blockquote {
|
|
||||||
border-color: #3a404c;
|
|
||||||
color: #8b93a1;
|
|
||||||
}
|
|
||||||
html[data-theme="dark"] .md-body pre,
|
|
||||||
html[data-theme="dark"] .md-body code { background: #2d323c; }
|
|
||||||
html[data-theme="dark"] .md-body th,
|
|
||||||
html[data-theme="dark"] .md-body td { border-color: #3a404c; }
|
|
||||||
|
|
||||||
/* 投票结果占比条:模板已改用 UIkit 3 原生 <progress class="uk-progress" value max>,
|
|
||||||
这里只把默认的 15px 高 / 500px 圆角 / 20px 外边距收紧到与页面一致的规格。
|
|
||||||
(原先为 UIkit 2 的 .uk-progressbar 结构打的补丁已删除) */
|
|
||||||
.uk-progress {
|
|
||||||
height: 10px;
|
|
||||||
margin: 0;
|
|
||||||
border-radius: var(--tb-radius-xs);
|
|
||||||
background-color: var(--tb-surface-2);
|
|
||||||
}
|
|
||||||
.uk-progress::-webkit-progress-bar {
|
|
||||||
background-color: var(--tb-surface-2);
|
|
||||||
border-radius: var(--tb-radius-xs);
|
|
||||||
}
|
|
||||||
.uk-progress::-webkit-progress-value {
|
|
||||||
background-color: var(--tb-primary);
|
|
||||||
border-radius: var(--tb-radius-xs) 0 0 var(--tb-radius-xs);
|
|
||||||
}
|
|
||||||
.uk-progress::-moz-progress-bar {
|
|
||||||
background-color: var(--tb-primary);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 移动端底部操作栏:固定底栏承载语言切换与深色模式,桌面端隐藏 */
|
|
||||||
#tb-mobile-utils {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
@media (max-width: 640px) {
|
|
||||||
/* 顶栏不再容纳语言/深色按钮,恢复原有导航空间 */
|
|
||||||
.tb-nav-utils {
|
|
||||||
display: none !important;
|
|
||||||
}
|
|
||||||
/* 手机端隐藏登录用户名(左边仅保留"探索"),保证 logo 居中、
|
|
||||||
两侧各不超过 2 个短按钮,避免用户名宽度挤压布局 */
|
|
||||||
.tb-nav-username {
|
|
||||||
display: none !important;
|
|
||||||
}
|
|
||||||
/* 固定底部操作栏 */
|
|
||||||
#tb-mobile-utils {
|
|
||||||
display: flex;
|
|
||||||
position: fixed;
|
|
||||||
left: 0;
|
|
||||||
right: 0;
|
|
||||||
bottom: 0;
|
|
||||||
z-index: 1000;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
gap: 10px;
|
|
||||||
padding: 8px 12px calc(8px + env(safe-area-inset-bottom));
|
|
||||||
background: rgba(255, 255, 255, 0.92);
|
|
||||||
-webkit-backdrop-filter: blur(8px);
|
|
||||||
backdrop-filter: blur(8px);
|
|
||||||
box-shadow: 0 -2px 12px rgba(0, 0, 0, 0.08);
|
|
||||||
}
|
|
||||||
#tb-mobile-utils .uk-select {
|
|
||||||
width: 110px;
|
|
||||||
}
|
|
||||||
html[data-theme="dark"] #tb-mobile-utils {
|
|
||||||
background: rgba(36, 40, 48, 0.92);
|
|
||||||
box-shadow: 0 -2px 12px rgba(0, 0, 0, 0.4);
|
|
||||||
}
|
|
||||||
/* 给页面底部预留空间,避免页脚内容被固定底栏遮挡 */
|
|
||||||
body {
|
|
||||||
padding-bottom: 56px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
||||||
<link rel="stylesheet" href="https://r2.337845818.best/tamabox/cdn/waline/client/v2/waline-no-commits.css" media="print" onload="this.media='all'"/>
|
<link rel="stylesheet" href="https://r2.337845818.best/tamabox/cdn/waline/client/v2/waline-no-commits.css" media="print" onload="this.media='all'"/>
|
||||||
<script defer src="https://cdnjs.cloudflare.com/ajax/libs/uikit/3.3.3/js/uikit.min.js"></script>
|
<script defer src="https://cdnjs.cloudflare.com/ajax/libs/uikit/3.3.3/js/uikit.min.js"></script>
|
||||||
@@ -1728,6 +1061,40 @@ document.addEventListener("DOMContentLoaded", function() {
|
|||||||
<span class="tb-account-note">您随时可以选择停用您的账号。停用后,您的账号将无法登录,您的提问箱页面以及提问将无法访问,其他人也无法再给您发送新的提问。<b>该操作无法撤销!请谨慎操作!</b></span>
|
<span class="tb-account-note">您随时可以选择停用您的账号。停用后,您的账号将无法登录,您的提问箱页面以及提问将无法访问,其他人也无法再给您发送新的提问。<b>该操作无法撤销!请谨慎操作!</b></span>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
|
||||||
|
<section class="tb-pcard">
|
||||||
|
<h3 class="tb-pcard-title">主题外观</h3>
|
||||||
|
<form method="post" action="/user/profile/theme">
|
||||||
|
<input type="hidden" name="_csrf" value="x">
|
||||||
|
<p class="tb-theme-hint">仅对提问箱页面生效,站内其它页面保持默认外观。</p>
|
||||||
|
<div class="tb-theme-grid">
|
||||||
|
<label class="tb-theme-opt">
|
||||||
|
<input class="uk-radio" type="radio" name="theme" value="">
|
||||||
|
<span class="tb-theme-swatch" style="background: linear-gradient(135deg, var(--tb-surface-2) 0 55%, var(--tb-border) 55% 100%)"></span>
|
||||||
|
<span class="tb-theme-name">跟随站点默认</span>
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<label class="tb-theme-opt">
|
||||||
|
<input class="uk-radio" type="radio" name="theme" value="default">
|
||||||
|
<span class="tb-theme-swatch"></span>
|
||||||
|
<span class="tb-theme-name">基础外观</span>
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<label class="tb-theme-opt">
|
||||||
|
<input class="uk-radio" type="radio" name="theme" value="sakura" checked>
|
||||||
|
<span class="tb-theme-swatch" style="background: ZgotmplZ"></span>
|
||||||
|
<span class="tb-theme-name">樱花</span>
|
||||||
|
</label>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<div class="tb-card-save">
|
||||||
|
<button type="submit" class="uk-button uk-button-primary">保存主题</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,911 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="zh-CN" data-theme-style="sakura" data-theme="dark">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<title>预览 15:15 · </title>
|
||||||
|
<meta name="msvalidate.01" content="2F185E8E63C93635F50B3574F3B31E42" />
|
||||||
|
<meta name="description" content="狼的提问箱——一个无需注册、可匿名提问的匿名提问箱,安全地倾诉与回应。">
|
||||||
|
<meta name="keywords" content="匿名提问箱,提问箱,匿名提问,狼的提问箱,匿名问答,匿名提问网站">
|
||||||
|
|
||||||
|
<script>
|
||||||
|
(function () {
|
||||||
|
var m = document.cookie.match(/(?:^|;\s*)theme=([^;]*)/);
|
||||||
|
if (m && m[1] === 'dark') document.documentElement.setAttribute('data-theme', 'dark');
|
||||||
|
})();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<link rel="preconnect" href="https://r2.337845818.best" crossorigin>
|
||||||
|
<link rel="preconnect" href="https://cdnjs.snrat.com" crossorigin>
|
||||||
|
|
||||||
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/uikit/3.3.3/css/uikit.min.css"/>
|
||||||
|
|
||||||
|
<link rel="stylesheet" href="/static/css/base.css?v="/>
|
||||||
|
|
||||||
|
<style>/* 樱花(sakura):粉调 + 细网点图案,纯 CSS 实现,不依赖图片素材。
|
||||||
|
复制 _scaffold.css 写的示例:只覆盖令牌,未改动任何布局。 */
|
||||||
|
html[data-theme-style="sakura"] {
|
||||||
|
--tb-bg: #fff6f8;
|
||||||
|
--tb-surface: #ffffff;
|
||||||
|
--tb-surface-2: #fdeef2;
|
||||||
|
--tb-surface-hover: #fdf1f5;
|
||||||
|
--tb-border: #f2dde4;
|
||||||
|
|
||||||
|
--tb-text: #3a2b30;
|
||||||
|
--tb-text-secondary: #6b545c;
|
||||||
|
--tb-text-muted: #a08c94;
|
||||||
|
|
||||||
|
--tb-primary: #e5678f;
|
||||||
|
--tb-primary-weak: rgba(229, 103, 143, 0.12);
|
||||||
|
|
||||||
|
--tb-shadow: 0 1px 2px rgba(120, 60, 80, 0.05), 0 12px 28px -18px rgba(120, 60, 80, 0.22);
|
||||||
|
--tb-shadow-hover: 0 1px 2px rgba(120, 60, 80, 0.07), 0 18px 40px -20px rgba(120, 60, 80, 0.30);
|
||||||
|
|
||||||
|
--tb-page-image: none;
|
||||||
|
--tb-page-pattern: radial-gradient(circle at 1px 1px, rgba(229, 103, 143, 0.14) 1px, transparent 0);
|
||||||
|
--tb-page-pattern-size: 16px 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
html[data-theme="dark"][data-theme-style="sakura"] {
|
||||||
|
--tb-bg: #241a1f;
|
||||||
|
--tb-surface: #2e2129;
|
||||||
|
--tb-surface-2: #3a2a33;
|
||||||
|
--tb-surface-hover: rgba(255, 138, 176, 0.10);
|
||||||
|
--tb-border: #49333d;
|
||||||
|
|
||||||
|
--tb-text: #f2e4e9;
|
||||||
|
--tb-text-secondary: #c6aab4;
|
||||||
|
--tb-text-muted: #9d818b;
|
||||||
|
|
||||||
|
--tb-primary: #ff8ab0;
|
||||||
|
--tb-primary-weak: rgba(255, 138, 176, 0.16);
|
||||||
|
|
||||||
|
--tb-shadow: 0 1px 2px rgba(0, 0, 0, 0.34), 0 12px 28px -18px rgba(0, 0, 0, 0.58);
|
||||||
|
--tb-shadow-hover: 0 1px 2px rgba(0, 0, 0, 0.40), 0 18px 40px -20px rgba(0, 0, 0, 0.68);
|
||||||
|
|
||||||
|
--tb-page-image: none;
|
||||||
|
--tb-page-pattern: radial-gradient(circle at 1px 1px, rgba(255, 138, 176, 0.10) 1px, transparent 0);
|
||||||
|
--tb-page-pattern-size: 16px 16px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<link rel="stylesheet" href="https://r2.337845818.best/tamabox/cdn/waline/client/v2/waline-no-commits.css" media="print" onload="this.media='all'"/>
|
||||||
|
<script defer src="https://cdnjs.cloudflare.com/ajax/libs/uikit/3.3.3/js/uikit.min.js"></script>
|
||||||
|
<script defer src="https://cdnjs.cloudflare.com/ajax/libs/uikit/3.3.3/js/uikit-icons.min.js"></script>
|
||||||
|
|
||||||
|
<script defer src="https://cdnjs.cloudflare.com/ajax/libs/dayjs/1.10.8/dayjs.min.js"></script>
|
||||||
|
<script defer src="https://cdnjs.cloudflare.com/ajax/libs/alpinejs/3.9.0/cdn.min.js"></script>
|
||||||
|
|
||||||
|
|
||||||
|
<script defer src="https://cdnjs.cloudflare.com/ajax/libs/waline/2.15.8/waline.js"></script>
|
||||||
|
|
||||||
|
<script src="/recaptcha/api.js" async defer></script>
|
||||||
|
<script>function onSubmit() {document.getElementById('form').submit();}</script>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<meta property="og:site_name" content="狼的提问箱 | 匿名提问箱" />
|
||||||
|
<meta property="og:type" content="website" />
|
||||||
|
<meta property="og:title" content="测试箱主 - 狼的提问箱 | 匿名提问箱" />
|
||||||
|
<meta property="og:url" content="" />
|
||||||
|
<meta property="og:description" content="测试箱主 - 狼的提问箱——一个无需注册、可匿名提问的匿名提问箱,安全地倾诉与回应。" />
|
||||||
|
|
||||||
|
|
||||||
|
<meta property="og:image" content="?og-image=1" />
|
||||||
|
<meta property="og:image:alt" content="测试箱主" />
|
||||||
|
<meta itemprop="image" content="?og-image=1"/>
|
||||||
|
<meta name="msapplication-TileImage" content=""/>
|
||||||
|
<link rel="shortcut icon" href="?og-image=1"/>
|
||||||
|
<link rel="apple-touch-icon" href="?og-image=1"/>
|
||||||
|
<link rel="icon" sizes="192x192" href="?og-image=1">
|
||||||
|
<meta name="twitter:image:src" content="?og-image=1" />
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<meta name="google-site-verification" content="fEPwRRJfiGsgwc5SINBQwZhPK8F0cwRaOvRx0YRurI4" />
|
||||||
|
|
||||||
|
<script>
|
||||||
|
window.addEventListener("load", function () {
|
||||||
|
var s = document.createElement("script");
|
||||||
|
s.src = "https://mami.shiroko.one/tamami.js";
|
||||||
|
s.setAttribute("data-website-id", "c42ebe8b-9281-4da0-83a4-8f18b3e710fe");
|
||||||
|
document.body.appendChild(s);
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<script>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
window.tbRenderQR = function (el, getOptions) {
|
||||||
|
if (!el || typeof QRCode === 'undefined') return;
|
||||||
|
var opts = getOptions();
|
||||||
|
function remoteOf(o, key) {
|
||||||
|
var v = o[key];
|
||||||
|
return (typeof v === 'string' && v.indexOf('http') === 0) ? v : '';
|
||||||
|
}
|
||||||
|
var good = window._tbQrGood || (window._tbQrGood = {});
|
||||||
|
var bad = window._tbQrBad || (window._tbQrBad = {});
|
||||||
|
|
||||||
|
function layerState(url) { return !url ? '' : (good[url] ? 1 : (bad[url] ? 0 : null)); }
|
||||||
|
var layers = [
|
||||||
|
{ url: remoteOf(opts, 'logo'), st: null, present: function (o, on) {
|
||||||
|
if (on) { } else { o.logo = undefined; o.logoWidth = undefined; o.logoHeight = undefined; o.logoBackgroundTransparent = undefined; }
|
||||||
|
} },
|
||||||
|
{ url: remoteOf(opts, 'backgroundImage'), st: null, present: function (o, on) {
|
||||||
|
if (on) { } else { o.backgroundImage = undefined; o.backgroundImageAlpha = undefined; }
|
||||||
|
} }
|
||||||
|
];
|
||||||
|
var needProbe = false;
|
||||||
|
for (var i = 0; i < layers.length; i++) {
|
||||||
|
layers[i].st = layerState(layers[i].url);
|
||||||
|
if (layers[i].st === null) needProbe = true;
|
||||||
|
}
|
||||||
|
function paint(states) {
|
||||||
|
var o = {};
|
||||||
|
for (var k in opts) o[k] = opts[k];
|
||||||
|
for (var j = 0; j < layers.length; j++) layers[j].present(o, states[j] === 1);
|
||||||
|
el.innerHTML = '';
|
||||||
|
new QRCode(el, o);
|
||||||
|
}
|
||||||
|
|
||||||
|
var initStates = [];
|
||||||
|
for (var n = 0; n < layers.length; n++) initStates.push(layers[n].st === 1 ? 1 : 0);
|
||||||
|
paint(initStates);
|
||||||
|
if (!needProbe) return;
|
||||||
|
|
||||||
|
var pending = 0, cross = opts.crossOrigin || 'anonymous';
|
||||||
|
layers.forEach(function (L) {
|
||||||
|
if (L.st !== null) return;
|
||||||
|
pending++;
|
||||||
|
var im = new Image();
|
||||||
|
im.onload = function () { good[L.url] = true; L.st = 1; onDone(); };
|
||||||
|
im.onerror = function () { bad[L.url] = true; L.st = 0; onDone(); };
|
||||||
|
if (cross) im.crossOrigin = cross;
|
||||||
|
im.src = L.url;
|
||||||
|
});
|
||||||
|
function onDone() {
|
||||||
|
if (--pending > 0) return;
|
||||||
|
var finalStates = [];
|
||||||
|
for (var m = 0; m < layers.length; m++) finalStates.push(layers[m].st === 1 ? 1 : 0);
|
||||||
|
var changed = false;
|
||||||
|
for (var q = 0; q < finalStates.length; q++) if (finalStates[q] !== initStates[q]) changed = true;
|
||||||
|
if (changed) paint(finalStates);
|
||||||
|
}
|
||||||
|
|
||||||
|
setTimeout(function () { if (pending > 0) { pending = 0; onDone(); } }, 3000);
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
<nav class="uk-navbar-container uk-margin tb-navbar" uk-navbar>
|
||||||
|
<div class="uk-navbar-center">
|
||||||
|
<div class="uk-navbar-center-left">
|
||||||
|
<div>
|
||||||
|
<ul class="uk-navbar-nav">
|
||||||
|
|
||||||
|
<li><a href="/explore">探索</a></li>
|
||||||
|
|
||||||
|
|
||||||
|
<li class="tb-mobile-balancer" aria-hidden="true"><a tabindex="-1" style="visibility:hidden">我的</a></li>
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<a class="uk-navbar-item uk-logo" href="/"><span class="emoji-placeholder" aria-label="random animal">🐺</span>的提问箱</a>
|
||||||
|
|
||||||
|
<div class="uk-navbar-center-right">
|
||||||
|
<div>
|
||||||
|
|
||||||
|
<ul class="uk-navbar-nav">
|
||||||
|
<li><a href="/register">注册</a></li>
|
||||||
|
</ul>
|
||||||
|
<ul class="uk-navbar-nav">
|
||||||
|
<li><a href="/login">登录</a></li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<ul class="uk-navbar-nav tb-nav-utils">
|
||||||
|
<li>
|
||||||
|
<a href="#" id="theme-toggle" title="切换深色/浅色模式" aria-label="切换深色/浅色模式">
|
||||||
|
<span class="tb-icon-light"><svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M20.5 14.3A8.6 8.6 0 0 1 9.7 3.5a8.6 8.6 0 1 0 10.8 10.8z"/></svg></span><span class="tb-icon-dark"><svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><circle cx="12" cy="12" r="4"/><path d="M12 2.5v2M12 19.5v2M2.5 12h2M19.5 12h2M5.2 5.2l1.4 1.4M17.4 17.4l1.4 1.4M18.8 5.2l-1.4 1.4M6.6 17.4l-1.4 1.4"/></svg></span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
document.addEventListener("DOMContentLoaded", function() {
|
||||||
|
const emojis = ["🐺","🐗","🐻","🐨","🐼","🐹","🐭","🐰","🦊","🐮","🐷","🐽","🐸","🐒","🦍","🐔","🐧","🐦","🐤","🐦⬛","🦅","🦉","🦇","🐴","🦄","🐝","🦎","🦖","🦕","🐙","🦑","🦐","🦞","🦀","🐡","🐠","🐟","🐬","🐳","🐋","🦈","🐊","🐅","🐆","🦓","🦍","🦧","🐘","🦛","🦏","🐪","🐫","🦒","🦘","🐃","🐂","🐄","🐎","🐖","🐏","🐑","🦙","🐐","🦌","🐕","🐩","🦮","🐕🦺","🐈","🐋","🐳","🐬","🐉","🐲"];
|
||||||
|
const placeholder = document.querySelector('.emoji-placeholder');
|
||||||
|
if (placeholder) {
|
||||||
|
placeholder.textContent = emojis[Math.floor(Math.random() * emojis.length)];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
<div id="tb-mobile-utils">
|
||||||
|
|
||||||
|
<button type="button" id="theme-toggle-mobile" class="uk-button uk-button-default uk-button-small"
|
||||||
|
title="切换深色/浅色模式" aria-label="切换深色/浅色模式">
|
||||||
|
<span class="tb-icon-light"><svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M20.5 14.3A8.6 8.6 0 0 1 9.7 3.5a8.6 8.6 0 1 0 10.8 10.8z"/></svg></span><span class="tb-icon-dark"><svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><circle cx="12" cy="12" r="4"/><path d="M12 2.5v2M12 19.5v2M2.5 12h2M19.5 12h2M5.2 5.2l1.4 1.4M17.4 17.4l1.4 1.4M18.8 5.2l-1.4 1.4M6.6 17.4l-1.4 1.4"/></svg></span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
(function() {
|
||||||
|
|
||||||
|
var THEME_COOKIE = 'theme';
|
||||||
|
function getTheme() {
|
||||||
|
var m = document.cookie.match(/(?:^|;\s*)theme=([^;]*)/);
|
||||||
|
return m ? m[1] : '';
|
||||||
|
}
|
||||||
|
function applyTheme(theme) {
|
||||||
|
if (theme === 'dark') {
|
||||||
|
document.documentElement.setAttribute('data-theme', 'dark');
|
||||||
|
} else {
|
||||||
|
document.documentElement.removeAttribute('data-theme');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function toggleTheme() {
|
||||||
|
var next = getTheme() === 'dark' ? 'light' : 'dark';
|
||||||
|
applyTheme(next);
|
||||||
|
var expires = new Date(Date.now() + 365 * 24 * 3600 * 1000).toUTCString();
|
||||||
|
document.cookie = THEME_COOKIE + '=' + next + '; path=/; max-age=' + (365 * 24 * 3600) + '; SameSite=Lax';
|
||||||
|
}
|
||||||
|
|
||||||
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
|
|
||||||
|
var buttons = document.querySelectorAll('#theme-toggle, #theme-toggle-mobile');
|
||||||
|
buttons.forEach(function(btn) {
|
||||||
|
btn.addEventListener('click', function(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
toggleTheme();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
var langSel = document.getElementById('mobile-lang-select');
|
||||||
|
if (langSel) {
|
||||||
|
langSel.addEventListener('change', function() {
|
||||||
|
if (!this.value) return;
|
||||||
|
var to = window.location.pathname + window.location.search;
|
||||||
|
window.location.href = '/i18n/' + encodeURIComponent(this.value) + '?to=' + encodeURIComponent(to);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
})();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
<div class="uk-container uk-container-xsmall">
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<link rel="shortcut icon" href="?v=2" crossorigin="anonymous"/>
|
||||||
|
<link rel="apple-touch-icon" href="?v=2" crossorigin="anonymous"/>
|
||||||
|
<link rel="icon" sizes="192x192" href="?v=2" crossorigin="anonymous">
|
||||||
|
<style>
|
||||||
|
|
||||||
|
.tb-profile-cover { min-height: 260px; }
|
||||||
|
|
||||||
|
.profile-votes-list { display: grid; gap: 0; }
|
||||||
|
.profile-vote-item {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
gap: 16px;
|
||||||
|
min-width: 0;
|
||||||
|
padding: 14px 16px;
|
||||||
|
border-bottom: 1px solid var(--tb-border);
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
.profile-vote-item:first-child { border-top: 1px solid var(--tb-border); }
|
||||||
|
.profile-vote-item:hover { background: var(--tb-surface-hover); text-decoration: none; }
|
||||||
|
.profile-vote-content { min-width: 0; }
|
||||||
|
.profile-vote-title {
|
||||||
|
display: block;
|
||||||
|
overflow: hidden;
|
||||||
|
color: var(--tb-text);
|
||||||
|
font-size: 0.98rem;
|
||||||
|
font-weight: 600;
|
||||||
|
line-height: 1.45;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
.profile-vote-meta {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
align-items: center;
|
||||||
|
gap: 7px;
|
||||||
|
margin-top: 8px;
|
||||||
|
}
|
||||||
|
.profile-vote-meta .uk-label { font-size: 0.72rem; line-height: 1.6; }
|
||||||
|
.profile-vote-action {
|
||||||
|
flex: 0 0 auto;
|
||||||
|
color: var(--tb-primary);
|
||||||
|
font-size: 0.82rem;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
html[data-theme="dark"] .profile-vote-item { border-color: var(--tb-border); }
|
||||||
|
html[data-theme="dark"] .profile-vote-title { color: var(--tb-text); }
|
||||||
|
html[data-theme="dark"] .profile-vote-item:hover { background: rgba(78, 168, 245, 0.10); }
|
||||||
|
|
||||||
|
|
||||||
|
.profile-tabs {
|
||||||
|
display: flex;
|
||||||
|
gap: 4px;
|
||||||
|
padding: 4px;
|
||||||
|
margin-top: 20px;
|
||||||
|
margin-bottom: 18px;
|
||||||
|
border: 1px solid var(--tb-border);
|
||||||
|
border-radius: 9px;
|
||||||
|
background: var(--tb-surface-2);
|
||||||
|
}
|
||||||
|
.profile-tab {
|
||||||
|
flex: 1;
|
||||||
|
border: 0;
|
||||||
|
border-radius: 6px;
|
||||||
|
padding: 9px 15px;
|
||||||
|
background: transparent;
|
||||||
|
color: var(--tb-text-muted);
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 0.9rem;
|
||||||
|
transition: background 0.2s ease, color 0.2s ease;
|
||||||
|
}
|
||||||
|
.profile-tab:hover { color: var(--tb-primary); }
|
||||||
|
.profile-tab.is-active {
|
||||||
|
background: var(--tb-surface);
|
||||||
|
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.10);
|
||||||
|
color: var(--tb-primary);
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.profile-tab.is-disabled,
|
||||||
|
.profile-tab:disabled {
|
||||||
|
cursor: not-allowed;
|
||||||
|
color: var(--tb-text-muted);
|
||||||
|
opacity: 0.7;
|
||||||
|
}
|
||||||
|
.profile-tab.is-disabled:hover { color: var(--tb-text-muted); }
|
||||||
|
.profile-panel[hidden] { display: none !important; }
|
||||||
|
html[data-theme="dark"] .profile-tabs {
|
||||||
|
border-color: var(--tb-border);
|
||||||
|
background: var(--tb-surface-2);
|
||||||
|
}
|
||||||
|
html[data-theme="dark"] .profile-tab { color: var(--tb-text-muted); }
|
||||||
|
html[data-theme="dark"] .profile-tab.is-active { background: var(--tb-surface); color: var(--tb-primary); }
|
||||||
|
html[data-theme="dark"] .profile-tab.is-disabled { color: var(--tb-text-muted); opacity: 0.55; }
|
||||||
|
</style>
|
||||||
|
<div class="uk-card uk-card-default uk-text-center">
|
||||||
|
<div class="tb-profile-cover uk-flex uk-flex-center uk-flex-middle uk-background-cover uk-light tb-cover" data-src="#ZgotmplZ" uk-img>
|
||||||
|
<div class="uk-card-body">
|
||||||
|
<img class="uk-border-circle uk-box-shadow-large" src="" crossorigin="anonymous" style="width: 100px; height: 100px; max-width: 100%; max-height: 100%;">
|
||||||
|
<h3 id="usernamecolor">测试箱主</h3>
|
||||||
|
<p id="introcolor">欢迎提问</p>
|
||||||
|
<div class="icon-container">
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<script>
|
||||||
|
document.getElementById("usernamecolor").style.color = "#3a2b30";
|
||||||
|
document.getElementById("introcolor").style.color = "#6b545c";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
(function () {
|
||||||
|
var cover = document.querySelector('.tb-cover');
|
||||||
|
var el = document.getElementById('usernamecolor');
|
||||||
|
if (!cover || !el) return;
|
||||||
|
var m = window.getComputedStyle(el).color.match(/\d+/g);
|
||||||
|
if (!m || m.length < 3) return;
|
||||||
|
var lum = (0.299 * m[0] + 0.587 * m[1] + 0.114 * m[2]) / 255;
|
||||||
|
if (lum > 0.62) cover.classList.add('tb-cover-dark');
|
||||||
|
})();
|
||||||
|
</script>
|
||||||
|
<div>
|
||||||
|
<div class="uk-card uk-card-default uk-card-small uk-card-body">
|
||||||
|
|
||||||
|
|
||||||
|
<script defer src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
|
||||||
|
<script defer src='https://r2.337845818.best/tamabox/cdn/js/remake/easy.qrcode.min.js' type="text/javascript" charset="utf-8"></script>
|
||||||
|
<div class="uk-text-center"><div id="boxqrimg"></div></div>
|
||||||
|
<script type="text/javascript">
|
||||||
|
document.addEventListener('DOMContentLoaded', function () {
|
||||||
|
var options = {
|
||||||
|
text: window.location.href,
|
||||||
|
width: 200,
|
||||||
|
height: 200,
|
||||||
|
|
||||||
|
|
||||||
|
colorDark: ( null ? "#fff" : "#000000") || "#000000",
|
||||||
|
colorLight: "#000" || "#FFFFFF",
|
||||||
|
dotScale: parseFloat("0.35") || 0.4,
|
||||||
|
dotScaleTiming: parseFloat("0.35") || 0.4,
|
||||||
|
dotScaleA: parseFloat("0.35") || 0.4,
|
||||||
|
correctLevel: QRCode.CorrectLevel.H,
|
||||||
|
logo: (function () {
|
||||||
|
|
||||||
|
var a = "" || "";
|
||||||
|
return a ? (a.indexOf("http") === 0 ? a + "?v=2" : a) : undefined;
|
||||||
|
})(),
|
||||||
|
logoWidth: 60,
|
||||||
|
logoHeight: 60,
|
||||||
|
logoBackgroundTransparent: true,
|
||||||
|
|
||||||
|
crossOrigin: 'anonymous',
|
||||||
|
backgroundImage: ("" ? "" : undefined),
|
||||||
|
backgroundImageAlpha: parseFloat("0.8") || 0.8,
|
||||||
|
autoColor: false,
|
||||||
|
PO: "#000" || "#000000",
|
||||||
|
PI: "#000" || "#000000",
|
||||||
|
AO: '',
|
||||||
|
AI: '',
|
||||||
|
timing: "#000" || "#000000"
|
||||||
|
};
|
||||||
|
|
||||||
|
window.tbRenderQR(document.getElementById("boxqrimg"), function () { return options; });
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<p class="uk-text-center uk-text-small">扫码向@测试箱主提问<br>谁都可以以匿名的形式提问</p>
|
||||||
|
|
||||||
|
<div class="uk-text-center uk-margin-small-top">
|
||||||
|
<a id="share-btn" href="/_/tester/share-card" download class="uk-button uk-button-default uk-button-small">
|
||||||
|
📤 分享提问箱
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="share-loading-overlay" style="display:none; position: fixed; top:0; left:0; width:100%; height:100%; background: rgba(255,255,255,0.85); z-index:9999;">
|
||||||
|
<div style="display:flex; flex-direction:column; align-items:center; justify-content:center; height:100%;">
|
||||||
|
<div uk-spinner="ratio: 2" class="uk-margin-bottom"></div>
|
||||||
|
<p class="uk-text-large uk-text-muted">正在生成分享图…</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
(function() {
|
||||||
|
var btn = document.getElementById('share-btn');
|
||||||
|
var overlay = document.getElementById('share-loading-overlay');
|
||||||
|
if (!btn || !overlay) return;
|
||||||
|
btn.addEventListener('click', function(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
overlay.style.display = 'block';
|
||||||
|
btn.style.pointerEvents = 'none';
|
||||||
|
fetch(btn.href)
|
||||||
|
.then(function(response) {
|
||||||
|
if (!response.ok) throw new Error('网络错误');
|
||||||
|
return response.blob();
|
||||||
|
})
|
||||||
|
.then(function(blob) {
|
||||||
|
var url = URL.createObjectURL(blob);
|
||||||
|
var a = document.createElement('a');
|
||||||
|
a.href = url;
|
||||||
|
a.download = 'share.png';
|
||||||
|
document.body.appendChild(a);
|
||||||
|
a.click();
|
||||||
|
setTimeout(function() {
|
||||||
|
document.body.removeChild(a);
|
||||||
|
URL.revokeObjectURL(url);
|
||||||
|
}, 100);
|
||||||
|
})
|
||||||
|
.catch(function(err) {
|
||||||
|
alert('生成分享图失败,请稍后重试');
|
||||||
|
console.error(err);
|
||||||
|
})
|
||||||
|
.finally(function() {
|
||||||
|
overlay.style.display = 'none';
|
||||||
|
btn.style.pointerEvents = 'auto';
|
||||||
|
});
|
||||||
|
});
|
||||||
|
})();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<div class="profile-tabs" role="tablist">
|
||||||
|
<button type="button" class="profile-tab" data-profile-tab="questions" role="tab" aria-selected="false">提问</button>
|
||||||
|
|
||||||
|
|
||||||
|
<button type="button" class="profile-tab is-disabled" disabled aria-disabled="true" uk-tooltip="">投票 <span uk-icon="icon: lock; ratio: 0.8"></span></button>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="profile-panel" data-profile-panel="questions">
|
||||||
|
|
||||||
|
<form method="post" action="/_/tester" enctype="multipart/form-data" id="form">
|
||||||
|
<input type="hidden" name="_csrf" value="x">
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<input type="hidden" name="start_chat_val" id="start_chat_val" value="false">
|
||||||
|
<input type="hidden" name="g-recaptcha-response" id="g-recaptcha-response" value="">
|
||||||
|
|
||||||
|
<div class="uk-margin uk-text-center">
|
||||||
|
<textarea name="content" class="uk-textarea" rows="5" placeholder="在此处撰写你的问题..."
|
||||||
|
maxlength="1000"></textarea>
|
||||||
|
<div x-data="{ files: null }" class="tb-img-uploader">
|
||||||
|
<div uk-form-custom>
|
||||||
|
<a href="#" class="uk-icon-link" uk-icon="image" style="margin-left: 10px"></a>
|
||||||
|
<span style="font-size: 12px" x-text="files ? files[0].name : '添加图片'"></span>
|
||||||
|
<input id="uploader" name="images" type="file" accept="image/*" x-on:change="files = Object.values($event.target.files)">
|
||||||
|
</div>
|
||||||
|
<button x-show="files" type="button" class="uk-icon-link" uk-icon="close" style="margin-left: 10px;"
|
||||||
|
@click="files = null"></button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="uk-margin uk-grid-small">
|
||||||
|
<label class="uk-text-small">
|
||||||
|
<input name="private" class="uk-checkbox" type="checkbox"> 回复后不公开
|
||||||
|
</label>
|
||||||
|
<label class="uk-text-small">
|
||||||
|
<input name="receive_reply_via_email" id="notify-checkbox" class="uk-checkbox" type="checkbox"> 接收通知
|
||||||
|
</label>
|
||||||
|
<div id="email-container" style="width: 100%; display: none;" class="uk-margin-small-top">
|
||||||
|
<input class="uk-input uk-form-small" type="email" name="receive_reply_email" id="email-input" placeholder="请输入你的邮箱地址">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="uk-margin uk-text-center">
|
||||||
|
<div class="uk-grid-small uk-flex-center" uk-grid>
|
||||||
|
<div>
|
||||||
|
|
||||||
|
<button type="submit" class="uk-button uk-button-primary g-recaptcha"
|
||||||
|
data-sitekey="" data-callback="onSubmit"
|
||||||
|
id="normal-submit-btn">发送提问</button>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<button type="button" class="uk-button uk-button-secondary" disabled
|
||||||
|
uk-tooltip="该提问箱未开启私聊">发起私聊</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
|
||||||
|
var notifyCheckbox = document.getElementById('notify-checkbox');
|
||||||
|
var emailContainer = document.getElementById('email-container');
|
||||||
|
var emailInput = document.getElementById('email-input');
|
||||||
|
|
||||||
|
if (notifyCheckbox && emailContainer && emailInput) {
|
||||||
|
notifyCheckbox.addEventListener('change', function() {
|
||||||
|
if (this.checked) {
|
||||||
|
emailContainer.style.display = 'block';
|
||||||
|
emailInput.setAttribute('required', 'required');
|
||||||
|
} else {
|
||||||
|
emailContainer.style.display = 'none';
|
||||||
|
emailInput.removeAttribute('required');
|
||||||
|
emailInput.value = '';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
var chatBtn = document.getElementById('chat-submit-btn');
|
||||||
|
if (chatBtn) {
|
||||||
|
chatBtn.addEventListener('click', function() {
|
||||||
|
var isLogged = false;
|
||||||
|
if (!isLogged) {
|
||||||
|
var currentURI = '';
|
||||||
|
UIkit.modal.dialog(
|
||||||
|
'<div class="uk-text-center uk-padding" style="min-height: 150px; display: flex; flex-direction: column; justify-content: center;">' +
|
||||||
|
'<h3 class="uk-modal-title uk-margin-small-bottom">需要登录</h3>' +
|
||||||
|
'<p class="uk-text-muted uk-margin-small-bottom">发起私聊需要登录账号</p>' +
|
||||||
|
'<a href="/login?to=' + encodeURIComponent(currentURI) + '" class="uk-button uk-button-primary">去登录</a>' +
|
||||||
|
'</div>',
|
||||||
|
{width: '400px'}
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
document.getElementById('start_chat_val').value = 'true';
|
||||||
|
|
||||||
|
document.getElementById('normal-submit-btn').click();
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function onSubmit(token) {
|
||||||
|
var btn = document.querySelector('.g-recaptcha');
|
||||||
|
var originalText = btn.innerText;
|
||||||
|
|
||||||
|
if (notifyCheckbox && notifyCheckbox.checked && emailInput && emailInput.value.trim() === '') {
|
||||||
|
alert(CAPTCHA_I18N.needEmail);
|
||||||
|
grecaptcha.reset();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
btn.disabled = true;
|
||||||
|
btn.innerText = '验证中...';
|
||||||
|
|
||||||
|
var needPassword = false;
|
||||||
|
if (needPassword) {
|
||||||
|
UIkit.modal.prompt(CAPTCHA_I18N.needPassword, '', 'password')
|
||||||
|
.then(function(password) {
|
||||||
|
if (password) {
|
||||||
|
document.getElementById('ask_password_input').value = password;
|
||||||
|
document.getElementById('form').submit();
|
||||||
|
} else {
|
||||||
|
btn.disabled = false;
|
||||||
|
btn.innerText = originalText;
|
||||||
|
grecaptcha.reset();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
document.getElementById('form').submit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<p class="uk-text-left uk-text-muted uk-text-small">@测试箱主 以前回答过的问题 (2)</p>
|
||||||
|
|
||||||
|
<div id="question-list">
|
||||||
|
|
||||||
|
<div data-qid="1">
|
||||||
|
<hr>
|
||||||
|
<a class="uk-button uk-button-default uk-button-small uk-float-right"
|
||||||
|
href="/_/tester/1">查看回答</a>
|
||||||
|
<div class="uk-text-left uk-text-small uk-text-muted">
|
||||||
|
<span class="tb-pin-flag" title="已置顶">⭐</span>
|
||||||
|
2026-10-19 15:15:39
|
||||||
|
</div>
|
||||||
|
<p class="uk-text-small uk-text-break tb-preline tb-clamp-5">置顶的问题
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div data-qid="2">
|
||||||
|
<hr>
|
||||||
|
<a class="uk-button uk-button-default uk-button-small uk-float-right"
|
||||||
|
href="/_/tester/2">查看回答</a>
|
||||||
|
<div class="uk-text-left uk-text-small uk-text-muted">
|
||||||
|
|
||||||
|
2026-10-19 14:15:39
|
||||||
|
</div>
|
||||||
|
<p class="uk-text-small uk-text-break tb-preline tb-clamp-5">普通问题
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<div x-data="{ more: false, loading: false, cursor: '2' }">
|
||||||
|
<button x-show="more" x-bind:disabled="loading" x-on:click.debounce="() => {
|
||||||
|
if (loading) return
|
||||||
|
loading = true
|
||||||
|
fetch(`/api/v1/user/tester/questions?cursor=${cursor}`)
|
||||||
|
.then(response => response.json())
|
||||||
|
.then(resp => {
|
||||||
|
loading = false
|
||||||
|
// 外层为 ctx.JSON 的统一包装 {code, data, message},内层才是分页负载;
|
||||||
|
// code !== 0(接口报错)时保持 more 不变,仅复位 loading,下次可重试。
|
||||||
|
if (!resp || resp.code !== 0) return
|
||||||
|
const payload = resp.data || {}
|
||||||
|
let items = Array.isArray(payload.data) ? payload.data : []
|
||||||
|
if (items.length === 0) {
|
||||||
|
more = false
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 防重兜底:先扫描 #question-list 下全部已渲染条目(含服务端首屏与既往
|
||||||
|
// 追加)的 data-qid 构造“已见”集合,仅追加未出现过的提问。若服务端因游标
|
||||||
|
// 未前进等原因返回了与已见内容相同的批次(重复加载历史 bug 的表现形态),
|
||||||
|
// 直接按“到底”处理并隐藏按钮,杜绝无限重复追加。
|
||||||
|
const seenQIDs = new Set()
|
||||||
|
document.querySelectorAll('#question-list [data-qid]').forEach(el => seenQIDs.add(Number(el.dataset.qid)))
|
||||||
|
items = items.filter(q => !seenQIDs.has(q.id))
|
||||||
|
if (items.length === 0) {
|
||||||
|
more = false
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 服务端下发复合键集游标(见上方注释),前端不自行拼接;
|
||||||
|
// has_more 由服务端多取一条探测得出,最后一页加载完立即隐藏按钮。
|
||||||
|
more = payload.has_more !== false
|
||||||
|
cursor = payload.next_cursor || cursor
|
||||||
|
items.forEach(question => {
|
||||||
|
const div = document.createElement('div')
|
||||||
|
div.dataset.qid = question.id
|
||||||
|
div.innerHTML = `
|
||||||
|
<div>
|
||||||
|
<hr>
|
||||||
|
<a class='uk-button uk-button-default uk-button-small uk-float-right'
|
||||||
|
href='/_/tester/${question.id}'>查看回答</a>
|
||||||
|
<div class='uk-text-left uk-text-small uk-text-muted'>
|
||||||
|
${question.is_pinned ? '<span class=\'tb-pin-flag\' title=\'已置顶\'>⭐</span>' : ''}
|
||||||
|
${dayjs(question.created_at).format('YYYY-MM-DD HH:mm:ss')}
|
||||||
|
</div>
|
||||||
|
<p class='uk-text-small uk-text-break tb-preline tb-clamp-5'></p>
|
||||||
|
</div>`
|
||||||
|
div.getElementsByTagName('p')[0].innerText = question.content
|
||||||
|
document.getElementById('question-list').appendChild(div)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
// 网络失败/响应非法 JSON 时复位 loading,避免按钮永远停留在加载中状态
|
||||||
|
.catch(() => { loading = false })
|
||||||
|
}" class="uk-button uk-button-default uk-width-1-1 uk-margin-small-bottom">
|
||||||
|
<span x-show="!loading">加载更多</span>
|
||||||
|
<span x-show="loading"><div uk-spinner="ratio: 0.8"></div> 加载中...</span>
|
||||||
|
</button>
|
||||||
|
<div x-show="!more" class="uk-text-meta uk-text-center">
|
||||||
|
<hr>
|
||||||
|
无更多留言
|
||||||
|
<br><br>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="profile-panel" data-profile-panel="votes" hidden>
|
||||||
|
|
||||||
|
<div class="uk-alert uk-alert-primary uk-margin-remove-top">暂时没有可参与的公开投票。</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<script>
|
||||||
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
|
var tabs = document.querySelectorAll('[data-profile-tab]');
|
||||||
|
var panels = document.querySelectorAll('[data-profile-panel]');
|
||||||
|
function showPanel(name) {
|
||||||
|
tabs.forEach(function(tab) {
|
||||||
|
var active = tab.dataset.profileTab === name;
|
||||||
|
tab.classList.toggle('is-active', active);
|
||||||
|
tab.setAttribute('aria-selected', active ? 'true' : 'false');
|
||||||
|
});
|
||||||
|
panels.forEach(function(panel) {
|
||||||
|
panel.hidden = panel.dataset.profilePanel !== name;
|
||||||
|
});
|
||||||
|
if (window.history && window.history.replaceState) {
|
||||||
|
window.history.replaceState({}, document.title, window.location.pathname + window.location.search + (name === 'votes' ? '#votes' : ''));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tabs.forEach(function(tab) {
|
||||||
|
tab.addEventListener('click', function() { showPanel(tab.dataset.profileTab); });
|
||||||
|
});
|
||||||
|
|
||||||
|
if (window.location.hash === '#votes' && document.querySelector('[data-profile-tab="votes"]')) {
|
||||||
|
showPanel('votes');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
<p class=" uk-text-right uk-text-muted uk-text-small">
|
||||||
|
<br>
|
||||||
|
<a href="/rules">社区规则</a> |
|
||||||
|
|
||||||
|
<a href="https://box.shiroko.one/_/tamakyi" target="_blank">找站长</a>
|
||||||
|
<br>
|
||||||
|
<a href="https://share.shiroko.one" target="_blank">盘</a>
|
||||||
|
| <a href="https://blog.shiroko.one" target="_blank">公告板</a>
|
||||||
|
| <a href="https://chat.shiroko.one" target="_blank">聊天室</a>
|
||||||
|
| <a href="https://status.shiroko.one" target="_blank">监控板</a>
|
||||||
|
| <a href="https://shiroko.one" target="_blank">导航页</a>
|
||||||
|
<br>Powered by NekoBox |
|
||||||
|
<br>提问箱已成功存活:<span id="box_runtime"></span>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
(function () {
|
||||||
|
var create = Math.round(Date.UTC(2023, 6, 1, 18, 15, 43) / 1000);
|
||||||
|
function tick() {
|
||||||
|
var el = document.getElementById("box_runtime");
|
||||||
|
if (!el) return;
|
||||||
|
var s = Math.round((Date.now() + 8 * 3600 * 1000) / 1000) - create;
|
||||||
|
var t = [0, 0, 0, 0, 0];
|
||||||
|
if (s >= 31536000) { t[0] = s / 31536000 | 0; s %= 31536000; }
|
||||||
|
if (s >= 86400) { t[1] = s / 86400 | 0; s %= 86400; }
|
||||||
|
if (s >= 3600) { t[2] = s / 3600 | 0; s %= 3600; }
|
||||||
|
if (s >= 60) { t[3] = s / 60 | 0; s %= 60; }
|
||||||
|
if (s > 0) { t[4] = s; }
|
||||||
|
el.innerHTML = t[0] + '年 ' + t[1] + '天 ' + t[2] + '时 ' + t[3] + '分 ' + t[4] + '秒 ';
|
||||||
|
}
|
||||||
|
tick();
|
||||||
|
setInterval(tick, 1000);
|
||||||
|
})();
|
||||||
|
</script>
|
||||||
|
<br>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
var SUBMIT_I18N = {
|
||||||
|
submitting: '提交中...',
|
||||||
|
uploading: '上传中...'
|
||||||
|
};
|
||||||
|
|
||||||
|
function tbResetSubmitButtons() {
|
||||||
|
document.querySelectorAll('button[data-tb-submitting]').forEach(function(b) {
|
||||||
|
b.disabled = false;
|
||||||
|
b.removeAttribute('data-tb-submitting');
|
||||||
|
var orig = b.getAttribute('data-tb-restore');
|
||||||
|
if (orig !== null) {
|
||||||
|
b.innerHTML = orig;
|
||||||
|
b.removeAttribute('data-tb-restore');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
document.addEventListener('submit', function(e) {
|
||||||
|
var form = e.target;
|
||||||
|
if (!form || form.tagName !== 'FORM') return;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if (e.defaultPrevented || form.getAttribute('data-tb-skip-submit-feedback') === '1') {
|
||||||
|
form.removeAttribute('data-tb-skip-submit-feedback');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if (form.getAttribute('target') === '_blank') return;
|
||||||
|
|
||||||
|
|
||||||
|
var trigger = e.submitter || form.querySelector('button[type="submit"]');
|
||||||
|
|
||||||
|
|
||||||
|
var hasFile = false;
|
||||||
|
form.querySelectorAll('input[type="file"]').forEach(function(f) {
|
||||||
|
if (f.files && f.files.length > 0) hasFile = true;
|
||||||
|
});
|
||||||
|
var label = hasFile ? SUBMIT_I18N.uploading : SUBMIT_I18N.submitting;
|
||||||
|
|
||||||
|
if (trigger && trigger.tagName === 'BUTTON') {
|
||||||
|
trigger.setAttribute('data-tb-restore', trigger.innerHTML);
|
||||||
|
trigger.innerHTML = '<span uk-spinner="ratio: 0.6"></span> ' + label;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
form.querySelectorAll('button').forEach(function(b) {
|
||||||
|
b.disabled = true;
|
||||||
|
b.setAttribute('data-tb-submitting', '1');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
window.addEventListener('pageshow', tbResetSubmitButtons);
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,911 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="zh-CN" data-theme-style="sakura">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<title>预览 15:15 · </title>
|
||||||
|
<meta name="msvalidate.01" content="2F185E8E63C93635F50B3574F3B31E42" />
|
||||||
|
<meta name="description" content="狼的提问箱——一个无需注册、可匿名提问的匿名提问箱,安全地倾诉与回应。">
|
||||||
|
<meta name="keywords" content="匿名提问箱,提问箱,匿名提问,狼的提问箱,匿名问答,匿名提问网站">
|
||||||
|
|
||||||
|
<script>
|
||||||
|
(function () {
|
||||||
|
var m = document.cookie.match(/(?:^|;\s*)theme=([^;]*)/);
|
||||||
|
if (m && m[1] === 'dark') document.documentElement.setAttribute('data-theme', 'dark');
|
||||||
|
})();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<link rel="preconnect" href="https://r2.337845818.best" crossorigin>
|
||||||
|
<link rel="preconnect" href="https://cdnjs.snrat.com" crossorigin>
|
||||||
|
|
||||||
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/uikit/3.3.3/css/uikit.min.css"/>
|
||||||
|
|
||||||
|
<link rel="stylesheet" href="/static/css/base.css?v="/>
|
||||||
|
|
||||||
|
<style>/* 樱花(sakura):粉调 + 细网点图案,纯 CSS 实现,不依赖图片素材。
|
||||||
|
复制 _scaffold.css 写的示例:只覆盖令牌,未改动任何布局。 */
|
||||||
|
html[data-theme-style="sakura"] {
|
||||||
|
--tb-bg: #fff6f8;
|
||||||
|
--tb-surface: #ffffff;
|
||||||
|
--tb-surface-2: #fdeef2;
|
||||||
|
--tb-surface-hover: #fdf1f5;
|
||||||
|
--tb-border: #f2dde4;
|
||||||
|
|
||||||
|
--tb-text: #3a2b30;
|
||||||
|
--tb-text-secondary: #6b545c;
|
||||||
|
--tb-text-muted: #a08c94;
|
||||||
|
|
||||||
|
--tb-primary: #e5678f;
|
||||||
|
--tb-primary-weak: rgba(229, 103, 143, 0.12);
|
||||||
|
|
||||||
|
--tb-shadow: 0 1px 2px rgba(120, 60, 80, 0.05), 0 12px 28px -18px rgba(120, 60, 80, 0.22);
|
||||||
|
--tb-shadow-hover: 0 1px 2px rgba(120, 60, 80, 0.07), 0 18px 40px -20px rgba(120, 60, 80, 0.30);
|
||||||
|
|
||||||
|
--tb-page-image: none;
|
||||||
|
--tb-page-pattern: radial-gradient(circle at 1px 1px, rgba(229, 103, 143, 0.14) 1px, transparent 0);
|
||||||
|
--tb-page-pattern-size: 16px 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
html[data-theme="dark"][data-theme-style="sakura"] {
|
||||||
|
--tb-bg: #241a1f;
|
||||||
|
--tb-surface: #2e2129;
|
||||||
|
--tb-surface-2: #3a2a33;
|
||||||
|
--tb-surface-hover: rgba(255, 138, 176, 0.10);
|
||||||
|
--tb-border: #49333d;
|
||||||
|
|
||||||
|
--tb-text: #f2e4e9;
|
||||||
|
--tb-text-secondary: #c6aab4;
|
||||||
|
--tb-text-muted: #9d818b;
|
||||||
|
|
||||||
|
--tb-primary: #ff8ab0;
|
||||||
|
--tb-primary-weak: rgba(255, 138, 176, 0.16);
|
||||||
|
|
||||||
|
--tb-shadow: 0 1px 2px rgba(0, 0, 0, 0.34), 0 12px 28px -18px rgba(0, 0, 0, 0.58);
|
||||||
|
--tb-shadow-hover: 0 1px 2px rgba(0, 0, 0, 0.40), 0 18px 40px -20px rgba(0, 0, 0, 0.68);
|
||||||
|
|
||||||
|
--tb-page-image: none;
|
||||||
|
--tb-page-pattern: radial-gradient(circle at 1px 1px, rgba(255, 138, 176, 0.10) 1px, transparent 0);
|
||||||
|
--tb-page-pattern-size: 16px 16px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<link rel="stylesheet" href="https://r2.337845818.best/tamabox/cdn/waline/client/v2/waline-no-commits.css" media="print" onload="this.media='all'"/>
|
||||||
|
<script defer src="https://cdnjs.cloudflare.com/ajax/libs/uikit/3.3.3/js/uikit.min.js"></script>
|
||||||
|
<script defer src="https://cdnjs.cloudflare.com/ajax/libs/uikit/3.3.3/js/uikit-icons.min.js"></script>
|
||||||
|
|
||||||
|
<script defer src="https://cdnjs.cloudflare.com/ajax/libs/dayjs/1.10.8/dayjs.min.js"></script>
|
||||||
|
<script defer src="https://cdnjs.cloudflare.com/ajax/libs/alpinejs/3.9.0/cdn.min.js"></script>
|
||||||
|
|
||||||
|
|
||||||
|
<script defer src="https://cdnjs.cloudflare.com/ajax/libs/waline/2.15.8/waline.js"></script>
|
||||||
|
|
||||||
|
<script src="/recaptcha/api.js" async defer></script>
|
||||||
|
<script>function onSubmit() {document.getElementById('form').submit();}</script>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<meta property="og:site_name" content="狼的提问箱 | 匿名提问箱" />
|
||||||
|
<meta property="og:type" content="website" />
|
||||||
|
<meta property="og:title" content="测试箱主 - 狼的提问箱 | 匿名提问箱" />
|
||||||
|
<meta property="og:url" content="" />
|
||||||
|
<meta property="og:description" content="测试箱主 - 狼的提问箱——一个无需注册、可匿名提问的匿名提问箱,安全地倾诉与回应。" />
|
||||||
|
|
||||||
|
|
||||||
|
<meta property="og:image" content="?og-image=1" />
|
||||||
|
<meta property="og:image:alt" content="测试箱主" />
|
||||||
|
<meta itemprop="image" content="?og-image=1"/>
|
||||||
|
<meta name="msapplication-TileImage" content=""/>
|
||||||
|
<link rel="shortcut icon" href="?og-image=1"/>
|
||||||
|
<link rel="apple-touch-icon" href="?og-image=1"/>
|
||||||
|
<link rel="icon" sizes="192x192" href="?og-image=1">
|
||||||
|
<meta name="twitter:image:src" content="?og-image=1" />
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<meta name="google-site-verification" content="fEPwRRJfiGsgwc5SINBQwZhPK8F0cwRaOvRx0YRurI4" />
|
||||||
|
|
||||||
|
<script>
|
||||||
|
window.addEventListener("load", function () {
|
||||||
|
var s = document.createElement("script");
|
||||||
|
s.src = "https://mami.shiroko.one/tamami.js";
|
||||||
|
s.setAttribute("data-website-id", "c42ebe8b-9281-4da0-83a4-8f18b3e710fe");
|
||||||
|
document.body.appendChild(s);
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<script>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
window.tbRenderQR = function (el, getOptions) {
|
||||||
|
if (!el || typeof QRCode === 'undefined') return;
|
||||||
|
var opts = getOptions();
|
||||||
|
function remoteOf(o, key) {
|
||||||
|
var v = o[key];
|
||||||
|
return (typeof v === 'string' && v.indexOf('http') === 0) ? v : '';
|
||||||
|
}
|
||||||
|
var good = window._tbQrGood || (window._tbQrGood = {});
|
||||||
|
var bad = window._tbQrBad || (window._tbQrBad = {});
|
||||||
|
|
||||||
|
function layerState(url) { return !url ? '' : (good[url] ? 1 : (bad[url] ? 0 : null)); }
|
||||||
|
var layers = [
|
||||||
|
{ url: remoteOf(opts, 'logo'), st: null, present: function (o, on) {
|
||||||
|
if (on) { } else { o.logo = undefined; o.logoWidth = undefined; o.logoHeight = undefined; o.logoBackgroundTransparent = undefined; }
|
||||||
|
} },
|
||||||
|
{ url: remoteOf(opts, 'backgroundImage'), st: null, present: function (o, on) {
|
||||||
|
if (on) { } else { o.backgroundImage = undefined; o.backgroundImageAlpha = undefined; }
|
||||||
|
} }
|
||||||
|
];
|
||||||
|
var needProbe = false;
|
||||||
|
for (var i = 0; i < layers.length; i++) {
|
||||||
|
layers[i].st = layerState(layers[i].url);
|
||||||
|
if (layers[i].st === null) needProbe = true;
|
||||||
|
}
|
||||||
|
function paint(states) {
|
||||||
|
var o = {};
|
||||||
|
for (var k in opts) o[k] = opts[k];
|
||||||
|
for (var j = 0; j < layers.length; j++) layers[j].present(o, states[j] === 1);
|
||||||
|
el.innerHTML = '';
|
||||||
|
new QRCode(el, o);
|
||||||
|
}
|
||||||
|
|
||||||
|
var initStates = [];
|
||||||
|
for (var n = 0; n < layers.length; n++) initStates.push(layers[n].st === 1 ? 1 : 0);
|
||||||
|
paint(initStates);
|
||||||
|
if (!needProbe) return;
|
||||||
|
|
||||||
|
var pending = 0, cross = opts.crossOrigin || 'anonymous';
|
||||||
|
layers.forEach(function (L) {
|
||||||
|
if (L.st !== null) return;
|
||||||
|
pending++;
|
||||||
|
var im = new Image();
|
||||||
|
im.onload = function () { good[L.url] = true; L.st = 1; onDone(); };
|
||||||
|
im.onerror = function () { bad[L.url] = true; L.st = 0; onDone(); };
|
||||||
|
if (cross) im.crossOrigin = cross;
|
||||||
|
im.src = L.url;
|
||||||
|
});
|
||||||
|
function onDone() {
|
||||||
|
if (--pending > 0) return;
|
||||||
|
var finalStates = [];
|
||||||
|
for (var m = 0; m < layers.length; m++) finalStates.push(layers[m].st === 1 ? 1 : 0);
|
||||||
|
var changed = false;
|
||||||
|
for (var q = 0; q < finalStates.length; q++) if (finalStates[q] !== initStates[q]) changed = true;
|
||||||
|
if (changed) paint(finalStates);
|
||||||
|
}
|
||||||
|
|
||||||
|
setTimeout(function () { if (pending > 0) { pending = 0; onDone(); } }, 3000);
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
<nav class="uk-navbar-container uk-margin tb-navbar" uk-navbar>
|
||||||
|
<div class="uk-navbar-center">
|
||||||
|
<div class="uk-navbar-center-left">
|
||||||
|
<div>
|
||||||
|
<ul class="uk-navbar-nav">
|
||||||
|
|
||||||
|
<li><a href="/explore">探索</a></li>
|
||||||
|
|
||||||
|
|
||||||
|
<li class="tb-mobile-balancer" aria-hidden="true"><a tabindex="-1" style="visibility:hidden">我的</a></li>
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<a class="uk-navbar-item uk-logo" href="/"><span class="emoji-placeholder" aria-label="random animal">🐺</span>的提问箱</a>
|
||||||
|
|
||||||
|
<div class="uk-navbar-center-right">
|
||||||
|
<div>
|
||||||
|
|
||||||
|
<ul class="uk-navbar-nav">
|
||||||
|
<li><a href="/register">注册</a></li>
|
||||||
|
</ul>
|
||||||
|
<ul class="uk-navbar-nav">
|
||||||
|
<li><a href="/login">登录</a></li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<ul class="uk-navbar-nav tb-nav-utils">
|
||||||
|
<li>
|
||||||
|
<a href="#" id="theme-toggle" title="切换深色/浅色模式" aria-label="切换深色/浅色模式">
|
||||||
|
<span class="tb-icon-light"><svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M20.5 14.3A8.6 8.6 0 0 1 9.7 3.5a8.6 8.6 0 1 0 10.8 10.8z"/></svg></span><span class="tb-icon-dark"><svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><circle cx="12" cy="12" r="4"/><path d="M12 2.5v2M12 19.5v2M2.5 12h2M19.5 12h2M5.2 5.2l1.4 1.4M17.4 17.4l1.4 1.4M18.8 5.2l-1.4 1.4M6.6 17.4l-1.4 1.4"/></svg></span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
document.addEventListener("DOMContentLoaded", function() {
|
||||||
|
const emojis = ["🐺","🐗","🐻","🐨","🐼","🐹","🐭","🐰","🦊","🐮","🐷","🐽","🐸","🐒","🦍","🐔","🐧","🐦","🐤","🐦⬛","🦅","🦉","🦇","🐴","🦄","🐝","🦎","🦖","🦕","🐙","🦑","🦐","🦞","🦀","🐡","🐠","🐟","🐬","🐳","🐋","🦈","🐊","🐅","🐆","🦓","🦍","🦧","🐘","🦛","🦏","🐪","🐫","🦒","🦘","🐃","🐂","🐄","🐎","🐖","🐏","🐑","🦙","🐐","🦌","🐕","🐩","🦮","🐕🦺","🐈","🐋","🐳","🐬","🐉","🐲"];
|
||||||
|
const placeholder = document.querySelector('.emoji-placeholder');
|
||||||
|
if (placeholder) {
|
||||||
|
placeholder.textContent = emojis[Math.floor(Math.random() * emojis.length)];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
<div id="tb-mobile-utils">
|
||||||
|
|
||||||
|
<button type="button" id="theme-toggle-mobile" class="uk-button uk-button-default uk-button-small"
|
||||||
|
title="切换深色/浅色模式" aria-label="切换深色/浅色模式">
|
||||||
|
<span class="tb-icon-light"><svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M20.5 14.3A8.6 8.6 0 0 1 9.7 3.5a8.6 8.6 0 1 0 10.8 10.8z"/></svg></span><span class="tb-icon-dark"><svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><circle cx="12" cy="12" r="4"/><path d="M12 2.5v2M12 19.5v2M2.5 12h2M19.5 12h2M5.2 5.2l1.4 1.4M17.4 17.4l1.4 1.4M18.8 5.2l-1.4 1.4M6.6 17.4l-1.4 1.4"/></svg></span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
(function() {
|
||||||
|
|
||||||
|
var THEME_COOKIE = 'theme';
|
||||||
|
function getTheme() {
|
||||||
|
var m = document.cookie.match(/(?:^|;\s*)theme=([^;]*)/);
|
||||||
|
return m ? m[1] : '';
|
||||||
|
}
|
||||||
|
function applyTheme(theme) {
|
||||||
|
if (theme === 'dark') {
|
||||||
|
document.documentElement.setAttribute('data-theme', 'dark');
|
||||||
|
} else {
|
||||||
|
document.documentElement.removeAttribute('data-theme');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function toggleTheme() {
|
||||||
|
var next = getTheme() === 'dark' ? 'light' : 'dark';
|
||||||
|
applyTheme(next);
|
||||||
|
var expires = new Date(Date.now() + 365 * 24 * 3600 * 1000).toUTCString();
|
||||||
|
document.cookie = THEME_COOKIE + '=' + next + '; path=/; max-age=' + (365 * 24 * 3600) + '; SameSite=Lax';
|
||||||
|
}
|
||||||
|
|
||||||
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
|
|
||||||
|
var buttons = document.querySelectorAll('#theme-toggle, #theme-toggle-mobile');
|
||||||
|
buttons.forEach(function(btn) {
|
||||||
|
btn.addEventListener('click', function(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
toggleTheme();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
var langSel = document.getElementById('mobile-lang-select');
|
||||||
|
if (langSel) {
|
||||||
|
langSel.addEventListener('change', function() {
|
||||||
|
if (!this.value) return;
|
||||||
|
var to = window.location.pathname + window.location.search;
|
||||||
|
window.location.href = '/i18n/' + encodeURIComponent(this.value) + '?to=' + encodeURIComponent(to);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
})();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
<div class="uk-container uk-container-xsmall">
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<link rel="shortcut icon" href="?v=2" crossorigin="anonymous"/>
|
||||||
|
<link rel="apple-touch-icon" href="?v=2" crossorigin="anonymous"/>
|
||||||
|
<link rel="icon" sizes="192x192" href="?v=2" crossorigin="anonymous">
|
||||||
|
<style>
|
||||||
|
|
||||||
|
.tb-profile-cover { min-height: 260px; }
|
||||||
|
|
||||||
|
.profile-votes-list { display: grid; gap: 0; }
|
||||||
|
.profile-vote-item {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
gap: 16px;
|
||||||
|
min-width: 0;
|
||||||
|
padding: 14px 16px;
|
||||||
|
border-bottom: 1px solid var(--tb-border);
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
.profile-vote-item:first-child { border-top: 1px solid var(--tb-border); }
|
||||||
|
.profile-vote-item:hover { background: var(--tb-surface-hover); text-decoration: none; }
|
||||||
|
.profile-vote-content { min-width: 0; }
|
||||||
|
.profile-vote-title {
|
||||||
|
display: block;
|
||||||
|
overflow: hidden;
|
||||||
|
color: var(--tb-text);
|
||||||
|
font-size: 0.98rem;
|
||||||
|
font-weight: 600;
|
||||||
|
line-height: 1.45;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
.profile-vote-meta {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
align-items: center;
|
||||||
|
gap: 7px;
|
||||||
|
margin-top: 8px;
|
||||||
|
}
|
||||||
|
.profile-vote-meta .uk-label { font-size: 0.72rem; line-height: 1.6; }
|
||||||
|
.profile-vote-action {
|
||||||
|
flex: 0 0 auto;
|
||||||
|
color: var(--tb-primary);
|
||||||
|
font-size: 0.82rem;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
html[data-theme="dark"] .profile-vote-item { border-color: var(--tb-border); }
|
||||||
|
html[data-theme="dark"] .profile-vote-title { color: var(--tb-text); }
|
||||||
|
html[data-theme="dark"] .profile-vote-item:hover { background: rgba(78, 168, 245, 0.10); }
|
||||||
|
|
||||||
|
|
||||||
|
.profile-tabs {
|
||||||
|
display: flex;
|
||||||
|
gap: 4px;
|
||||||
|
padding: 4px;
|
||||||
|
margin-top: 20px;
|
||||||
|
margin-bottom: 18px;
|
||||||
|
border: 1px solid var(--tb-border);
|
||||||
|
border-radius: 9px;
|
||||||
|
background: var(--tb-surface-2);
|
||||||
|
}
|
||||||
|
.profile-tab {
|
||||||
|
flex: 1;
|
||||||
|
border: 0;
|
||||||
|
border-radius: 6px;
|
||||||
|
padding: 9px 15px;
|
||||||
|
background: transparent;
|
||||||
|
color: var(--tb-text-muted);
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 0.9rem;
|
||||||
|
transition: background 0.2s ease, color 0.2s ease;
|
||||||
|
}
|
||||||
|
.profile-tab:hover { color: var(--tb-primary); }
|
||||||
|
.profile-tab.is-active {
|
||||||
|
background: var(--tb-surface);
|
||||||
|
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.10);
|
||||||
|
color: var(--tb-primary);
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.profile-tab.is-disabled,
|
||||||
|
.profile-tab:disabled {
|
||||||
|
cursor: not-allowed;
|
||||||
|
color: var(--tb-text-muted);
|
||||||
|
opacity: 0.7;
|
||||||
|
}
|
||||||
|
.profile-tab.is-disabled:hover { color: var(--tb-text-muted); }
|
||||||
|
.profile-panel[hidden] { display: none !important; }
|
||||||
|
html[data-theme="dark"] .profile-tabs {
|
||||||
|
border-color: var(--tb-border);
|
||||||
|
background: var(--tb-surface-2);
|
||||||
|
}
|
||||||
|
html[data-theme="dark"] .profile-tab { color: var(--tb-text-muted); }
|
||||||
|
html[data-theme="dark"] .profile-tab.is-active { background: var(--tb-surface); color: var(--tb-primary); }
|
||||||
|
html[data-theme="dark"] .profile-tab.is-disabled { color: var(--tb-text-muted); opacity: 0.55; }
|
||||||
|
</style>
|
||||||
|
<div class="uk-card uk-card-default uk-text-center">
|
||||||
|
<div class="tb-profile-cover uk-flex uk-flex-center uk-flex-middle uk-background-cover uk-light tb-cover" data-src="#ZgotmplZ" uk-img>
|
||||||
|
<div class="uk-card-body">
|
||||||
|
<img class="uk-border-circle uk-box-shadow-large" src="" crossorigin="anonymous" style="width: 100px; height: 100px; max-width: 100%; max-height: 100%;">
|
||||||
|
<h3 id="usernamecolor">测试箱主</h3>
|
||||||
|
<p id="introcolor">欢迎提问</p>
|
||||||
|
<div class="icon-container">
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<script>
|
||||||
|
document.getElementById("usernamecolor").style.color = "#3a2b30";
|
||||||
|
document.getElementById("introcolor").style.color = "#6b545c";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
(function () {
|
||||||
|
var cover = document.querySelector('.tb-cover');
|
||||||
|
var el = document.getElementById('usernamecolor');
|
||||||
|
if (!cover || !el) return;
|
||||||
|
var m = window.getComputedStyle(el).color.match(/\d+/g);
|
||||||
|
if (!m || m.length < 3) return;
|
||||||
|
var lum = (0.299 * m[0] + 0.587 * m[1] + 0.114 * m[2]) / 255;
|
||||||
|
if (lum > 0.62) cover.classList.add('tb-cover-dark');
|
||||||
|
})();
|
||||||
|
</script>
|
||||||
|
<div>
|
||||||
|
<div class="uk-card uk-card-default uk-card-small uk-card-body">
|
||||||
|
|
||||||
|
|
||||||
|
<script defer src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
|
||||||
|
<script defer src='https://r2.337845818.best/tamabox/cdn/js/remake/easy.qrcode.min.js' type="text/javascript" charset="utf-8"></script>
|
||||||
|
<div class="uk-text-center"><div id="boxqrimg"></div></div>
|
||||||
|
<script type="text/javascript">
|
||||||
|
document.addEventListener('DOMContentLoaded', function () {
|
||||||
|
var options = {
|
||||||
|
text: window.location.href,
|
||||||
|
width: 200,
|
||||||
|
height: 200,
|
||||||
|
|
||||||
|
|
||||||
|
colorDark: ( null ? "#fff" : "#000000") || "#000000",
|
||||||
|
colorLight: "#000" || "#FFFFFF",
|
||||||
|
dotScale: parseFloat("0.35") || 0.4,
|
||||||
|
dotScaleTiming: parseFloat("0.35") || 0.4,
|
||||||
|
dotScaleA: parseFloat("0.35") || 0.4,
|
||||||
|
correctLevel: QRCode.CorrectLevel.H,
|
||||||
|
logo: (function () {
|
||||||
|
|
||||||
|
var a = "" || "";
|
||||||
|
return a ? (a.indexOf("http") === 0 ? a + "?v=2" : a) : undefined;
|
||||||
|
})(),
|
||||||
|
logoWidth: 60,
|
||||||
|
logoHeight: 60,
|
||||||
|
logoBackgroundTransparent: true,
|
||||||
|
|
||||||
|
crossOrigin: 'anonymous',
|
||||||
|
backgroundImage: ("" ? "" : undefined),
|
||||||
|
backgroundImageAlpha: parseFloat("0.8") || 0.8,
|
||||||
|
autoColor: false,
|
||||||
|
PO: "#000" || "#000000",
|
||||||
|
PI: "#000" || "#000000",
|
||||||
|
AO: '',
|
||||||
|
AI: '',
|
||||||
|
timing: "#000" || "#000000"
|
||||||
|
};
|
||||||
|
|
||||||
|
window.tbRenderQR(document.getElementById("boxqrimg"), function () { return options; });
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<p class="uk-text-center uk-text-small">扫码向@测试箱主提问<br>谁都可以以匿名的形式提问</p>
|
||||||
|
|
||||||
|
<div class="uk-text-center uk-margin-small-top">
|
||||||
|
<a id="share-btn" href="/_/tester/share-card" download class="uk-button uk-button-default uk-button-small">
|
||||||
|
📤 分享提问箱
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="share-loading-overlay" style="display:none; position: fixed; top:0; left:0; width:100%; height:100%; background: rgba(255,255,255,0.85); z-index:9999;">
|
||||||
|
<div style="display:flex; flex-direction:column; align-items:center; justify-content:center; height:100%;">
|
||||||
|
<div uk-spinner="ratio: 2" class="uk-margin-bottom"></div>
|
||||||
|
<p class="uk-text-large uk-text-muted">正在生成分享图…</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
(function() {
|
||||||
|
var btn = document.getElementById('share-btn');
|
||||||
|
var overlay = document.getElementById('share-loading-overlay');
|
||||||
|
if (!btn || !overlay) return;
|
||||||
|
btn.addEventListener('click', function(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
overlay.style.display = 'block';
|
||||||
|
btn.style.pointerEvents = 'none';
|
||||||
|
fetch(btn.href)
|
||||||
|
.then(function(response) {
|
||||||
|
if (!response.ok) throw new Error('网络错误');
|
||||||
|
return response.blob();
|
||||||
|
})
|
||||||
|
.then(function(blob) {
|
||||||
|
var url = URL.createObjectURL(blob);
|
||||||
|
var a = document.createElement('a');
|
||||||
|
a.href = url;
|
||||||
|
a.download = 'share.png';
|
||||||
|
document.body.appendChild(a);
|
||||||
|
a.click();
|
||||||
|
setTimeout(function() {
|
||||||
|
document.body.removeChild(a);
|
||||||
|
URL.revokeObjectURL(url);
|
||||||
|
}, 100);
|
||||||
|
})
|
||||||
|
.catch(function(err) {
|
||||||
|
alert('生成分享图失败,请稍后重试');
|
||||||
|
console.error(err);
|
||||||
|
})
|
||||||
|
.finally(function() {
|
||||||
|
overlay.style.display = 'none';
|
||||||
|
btn.style.pointerEvents = 'auto';
|
||||||
|
});
|
||||||
|
});
|
||||||
|
})();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<div class="profile-tabs" role="tablist">
|
||||||
|
<button type="button" class="profile-tab" data-profile-tab="questions" role="tab" aria-selected="false">提问</button>
|
||||||
|
|
||||||
|
|
||||||
|
<button type="button" class="profile-tab is-disabled" disabled aria-disabled="true" uk-tooltip="">投票 <span uk-icon="icon: lock; ratio: 0.8"></span></button>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="profile-panel" data-profile-panel="questions">
|
||||||
|
|
||||||
|
<form method="post" action="/_/tester" enctype="multipart/form-data" id="form">
|
||||||
|
<input type="hidden" name="_csrf" value="x">
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<input type="hidden" name="start_chat_val" id="start_chat_val" value="false">
|
||||||
|
<input type="hidden" name="g-recaptcha-response" id="g-recaptcha-response" value="">
|
||||||
|
|
||||||
|
<div class="uk-margin uk-text-center">
|
||||||
|
<textarea name="content" class="uk-textarea" rows="5" placeholder="在此处撰写你的问题..."
|
||||||
|
maxlength="1000"></textarea>
|
||||||
|
<div x-data="{ files: null }" class="tb-img-uploader">
|
||||||
|
<div uk-form-custom>
|
||||||
|
<a href="#" class="uk-icon-link" uk-icon="image" style="margin-left: 10px"></a>
|
||||||
|
<span style="font-size: 12px" x-text="files ? files[0].name : '添加图片'"></span>
|
||||||
|
<input id="uploader" name="images" type="file" accept="image/*" x-on:change="files = Object.values($event.target.files)">
|
||||||
|
</div>
|
||||||
|
<button x-show="files" type="button" class="uk-icon-link" uk-icon="close" style="margin-left: 10px;"
|
||||||
|
@click="files = null"></button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="uk-margin uk-grid-small">
|
||||||
|
<label class="uk-text-small">
|
||||||
|
<input name="private" class="uk-checkbox" type="checkbox"> 回复后不公开
|
||||||
|
</label>
|
||||||
|
<label class="uk-text-small">
|
||||||
|
<input name="receive_reply_via_email" id="notify-checkbox" class="uk-checkbox" type="checkbox"> 接收通知
|
||||||
|
</label>
|
||||||
|
<div id="email-container" style="width: 100%; display: none;" class="uk-margin-small-top">
|
||||||
|
<input class="uk-input uk-form-small" type="email" name="receive_reply_email" id="email-input" placeholder="请输入你的邮箱地址">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="uk-margin uk-text-center">
|
||||||
|
<div class="uk-grid-small uk-flex-center" uk-grid>
|
||||||
|
<div>
|
||||||
|
|
||||||
|
<button type="submit" class="uk-button uk-button-primary g-recaptcha"
|
||||||
|
data-sitekey="" data-callback="onSubmit"
|
||||||
|
id="normal-submit-btn">发送提问</button>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<button type="button" class="uk-button uk-button-secondary" disabled
|
||||||
|
uk-tooltip="该提问箱未开启私聊">发起私聊</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
|
||||||
|
var notifyCheckbox = document.getElementById('notify-checkbox');
|
||||||
|
var emailContainer = document.getElementById('email-container');
|
||||||
|
var emailInput = document.getElementById('email-input');
|
||||||
|
|
||||||
|
if (notifyCheckbox && emailContainer && emailInput) {
|
||||||
|
notifyCheckbox.addEventListener('change', function() {
|
||||||
|
if (this.checked) {
|
||||||
|
emailContainer.style.display = 'block';
|
||||||
|
emailInput.setAttribute('required', 'required');
|
||||||
|
} else {
|
||||||
|
emailContainer.style.display = 'none';
|
||||||
|
emailInput.removeAttribute('required');
|
||||||
|
emailInput.value = '';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
var chatBtn = document.getElementById('chat-submit-btn');
|
||||||
|
if (chatBtn) {
|
||||||
|
chatBtn.addEventListener('click', function() {
|
||||||
|
var isLogged = false;
|
||||||
|
if (!isLogged) {
|
||||||
|
var currentURI = '';
|
||||||
|
UIkit.modal.dialog(
|
||||||
|
'<div class="uk-text-center uk-padding" style="min-height: 150px; display: flex; flex-direction: column; justify-content: center;">' +
|
||||||
|
'<h3 class="uk-modal-title uk-margin-small-bottom">需要登录</h3>' +
|
||||||
|
'<p class="uk-text-muted uk-margin-small-bottom">发起私聊需要登录账号</p>' +
|
||||||
|
'<a href="/login?to=' + encodeURIComponent(currentURI) + '" class="uk-button uk-button-primary">去登录</a>' +
|
||||||
|
'</div>',
|
||||||
|
{width: '400px'}
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
document.getElementById('start_chat_val').value = 'true';
|
||||||
|
|
||||||
|
document.getElementById('normal-submit-btn').click();
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function onSubmit(token) {
|
||||||
|
var btn = document.querySelector('.g-recaptcha');
|
||||||
|
var originalText = btn.innerText;
|
||||||
|
|
||||||
|
if (notifyCheckbox && notifyCheckbox.checked && emailInput && emailInput.value.trim() === '') {
|
||||||
|
alert(CAPTCHA_I18N.needEmail);
|
||||||
|
grecaptcha.reset();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
btn.disabled = true;
|
||||||
|
btn.innerText = '验证中...';
|
||||||
|
|
||||||
|
var needPassword = false;
|
||||||
|
if (needPassword) {
|
||||||
|
UIkit.modal.prompt(CAPTCHA_I18N.needPassword, '', 'password')
|
||||||
|
.then(function(password) {
|
||||||
|
if (password) {
|
||||||
|
document.getElementById('ask_password_input').value = password;
|
||||||
|
document.getElementById('form').submit();
|
||||||
|
} else {
|
||||||
|
btn.disabled = false;
|
||||||
|
btn.innerText = originalText;
|
||||||
|
grecaptcha.reset();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
document.getElementById('form').submit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<p class="uk-text-left uk-text-muted uk-text-small">@测试箱主 以前回答过的问题 (2)</p>
|
||||||
|
|
||||||
|
<div id="question-list">
|
||||||
|
|
||||||
|
<div data-qid="1">
|
||||||
|
<hr>
|
||||||
|
<a class="uk-button uk-button-default uk-button-small uk-float-right"
|
||||||
|
href="/_/tester/1">查看回答</a>
|
||||||
|
<div class="uk-text-left uk-text-small uk-text-muted">
|
||||||
|
<span class="tb-pin-flag" title="已置顶">⭐</span>
|
||||||
|
2026-10-19 15:15:39
|
||||||
|
</div>
|
||||||
|
<p class="uk-text-small uk-text-break tb-preline tb-clamp-5">置顶的问题
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div data-qid="2">
|
||||||
|
<hr>
|
||||||
|
<a class="uk-button uk-button-default uk-button-small uk-float-right"
|
||||||
|
href="/_/tester/2">查看回答</a>
|
||||||
|
<div class="uk-text-left uk-text-small uk-text-muted">
|
||||||
|
|
||||||
|
2026-10-19 14:15:39
|
||||||
|
</div>
|
||||||
|
<p class="uk-text-small uk-text-break tb-preline tb-clamp-5">普通问题
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<div x-data="{ more: false, loading: false, cursor: '2' }">
|
||||||
|
<button x-show="more" x-bind:disabled="loading" x-on:click.debounce="() => {
|
||||||
|
if (loading) return
|
||||||
|
loading = true
|
||||||
|
fetch(`/api/v1/user/tester/questions?cursor=${cursor}`)
|
||||||
|
.then(response => response.json())
|
||||||
|
.then(resp => {
|
||||||
|
loading = false
|
||||||
|
// 外层为 ctx.JSON 的统一包装 {code, data, message},内层才是分页负载;
|
||||||
|
// code !== 0(接口报错)时保持 more 不变,仅复位 loading,下次可重试。
|
||||||
|
if (!resp || resp.code !== 0) return
|
||||||
|
const payload = resp.data || {}
|
||||||
|
let items = Array.isArray(payload.data) ? payload.data : []
|
||||||
|
if (items.length === 0) {
|
||||||
|
more = false
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 防重兜底:先扫描 #question-list 下全部已渲染条目(含服务端首屏与既往
|
||||||
|
// 追加)的 data-qid 构造“已见”集合,仅追加未出现过的提问。若服务端因游标
|
||||||
|
// 未前进等原因返回了与已见内容相同的批次(重复加载历史 bug 的表现形态),
|
||||||
|
// 直接按“到底”处理并隐藏按钮,杜绝无限重复追加。
|
||||||
|
const seenQIDs = new Set()
|
||||||
|
document.querySelectorAll('#question-list [data-qid]').forEach(el => seenQIDs.add(Number(el.dataset.qid)))
|
||||||
|
items = items.filter(q => !seenQIDs.has(q.id))
|
||||||
|
if (items.length === 0) {
|
||||||
|
more = false
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 服务端下发复合键集游标(见上方注释),前端不自行拼接;
|
||||||
|
// has_more 由服务端多取一条探测得出,最后一页加载完立即隐藏按钮。
|
||||||
|
more = payload.has_more !== false
|
||||||
|
cursor = payload.next_cursor || cursor
|
||||||
|
items.forEach(question => {
|
||||||
|
const div = document.createElement('div')
|
||||||
|
div.dataset.qid = question.id
|
||||||
|
div.innerHTML = `
|
||||||
|
<div>
|
||||||
|
<hr>
|
||||||
|
<a class='uk-button uk-button-default uk-button-small uk-float-right'
|
||||||
|
href='/_/tester/${question.id}'>查看回答</a>
|
||||||
|
<div class='uk-text-left uk-text-small uk-text-muted'>
|
||||||
|
${question.is_pinned ? '<span class=\'tb-pin-flag\' title=\'已置顶\'>⭐</span>' : ''}
|
||||||
|
${dayjs(question.created_at).format('YYYY-MM-DD HH:mm:ss')}
|
||||||
|
</div>
|
||||||
|
<p class='uk-text-small uk-text-break tb-preline tb-clamp-5'></p>
|
||||||
|
</div>`
|
||||||
|
div.getElementsByTagName('p')[0].innerText = question.content
|
||||||
|
document.getElementById('question-list').appendChild(div)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
// 网络失败/响应非法 JSON 时复位 loading,避免按钮永远停留在加载中状态
|
||||||
|
.catch(() => { loading = false })
|
||||||
|
}" class="uk-button uk-button-default uk-width-1-1 uk-margin-small-bottom">
|
||||||
|
<span x-show="!loading">加载更多</span>
|
||||||
|
<span x-show="loading"><div uk-spinner="ratio: 0.8"></div> 加载中...</span>
|
||||||
|
</button>
|
||||||
|
<div x-show="!more" class="uk-text-meta uk-text-center">
|
||||||
|
<hr>
|
||||||
|
无更多留言
|
||||||
|
<br><br>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="profile-panel" data-profile-panel="votes" hidden>
|
||||||
|
|
||||||
|
<div class="uk-alert uk-alert-primary uk-margin-remove-top">暂时没有可参与的公开投票。</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<script>
|
||||||
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
|
var tabs = document.querySelectorAll('[data-profile-tab]');
|
||||||
|
var panels = document.querySelectorAll('[data-profile-panel]');
|
||||||
|
function showPanel(name) {
|
||||||
|
tabs.forEach(function(tab) {
|
||||||
|
var active = tab.dataset.profileTab === name;
|
||||||
|
tab.classList.toggle('is-active', active);
|
||||||
|
tab.setAttribute('aria-selected', active ? 'true' : 'false');
|
||||||
|
});
|
||||||
|
panels.forEach(function(panel) {
|
||||||
|
panel.hidden = panel.dataset.profilePanel !== name;
|
||||||
|
});
|
||||||
|
if (window.history && window.history.replaceState) {
|
||||||
|
window.history.replaceState({}, document.title, window.location.pathname + window.location.search + (name === 'votes' ? '#votes' : ''));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tabs.forEach(function(tab) {
|
||||||
|
tab.addEventListener('click', function() { showPanel(tab.dataset.profileTab); });
|
||||||
|
});
|
||||||
|
|
||||||
|
if (window.location.hash === '#votes' && document.querySelector('[data-profile-tab="votes"]')) {
|
||||||
|
showPanel('votes');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
<p class=" uk-text-right uk-text-muted uk-text-small">
|
||||||
|
<br>
|
||||||
|
<a href="/rules">社区规则</a> |
|
||||||
|
|
||||||
|
<a href="https://box.shiroko.one/_/tamakyi" target="_blank">找站长</a>
|
||||||
|
<br>
|
||||||
|
<a href="https://share.shiroko.one" target="_blank">盘</a>
|
||||||
|
| <a href="https://blog.shiroko.one" target="_blank">公告板</a>
|
||||||
|
| <a href="https://chat.shiroko.one" target="_blank">聊天室</a>
|
||||||
|
| <a href="https://status.shiroko.one" target="_blank">监控板</a>
|
||||||
|
| <a href="https://shiroko.one" target="_blank">导航页</a>
|
||||||
|
<br>Powered by NekoBox |
|
||||||
|
<br>提问箱已成功存活:<span id="box_runtime"></span>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
(function () {
|
||||||
|
var create = Math.round(Date.UTC(2023, 6, 1, 18, 15, 43) / 1000);
|
||||||
|
function tick() {
|
||||||
|
var el = document.getElementById("box_runtime");
|
||||||
|
if (!el) return;
|
||||||
|
var s = Math.round((Date.now() + 8 * 3600 * 1000) / 1000) - create;
|
||||||
|
var t = [0, 0, 0, 0, 0];
|
||||||
|
if (s >= 31536000) { t[0] = s / 31536000 | 0; s %= 31536000; }
|
||||||
|
if (s >= 86400) { t[1] = s / 86400 | 0; s %= 86400; }
|
||||||
|
if (s >= 3600) { t[2] = s / 3600 | 0; s %= 3600; }
|
||||||
|
if (s >= 60) { t[3] = s / 60 | 0; s %= 60; }
|
||||||
|
if (s > 0) { t[4] = s; }
|
||||||
|
el.innerHTML = t[0] + '年 ' + t[1] + '天 ' + t[2] + '时 ' + t[3] + '分 ' + t[4] + '秒 ';
|
||||||
|
}
|
||||||
|
tick();
|
||||||
|
setInterval(tick, 1000);
|
||||||
|
})();
|
||||||
|
</script>
|
||||||
|
<br>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
var SUBMIT_I18N = {
|
||||||
|
submitting: '提交中...',
|
||||||
|
uploading: '上传中...'
|
||||||
|
};
|
||||||
|
|
||||||
|
function tbResetSubmitButtons() {
|
||||||
|
document.querySelectorAll('button[data-tb-submitting]').forEach(function(b) {
|
||||||
|
b.disabled = false;
|
||||||
|
b.removeAttribute('data-tb-submitting');
|
||||||
|
var orig = b.getAttribute('data-tb-restore');
|
||||||
|
if (orig !== null) {
|
||||||
|
b.innerHTML = orig;
|
||||||
|
b.removeAttribute('data-tb-restore');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
document.addEventListener('submit', function(e) {
|
||||||
|
var form = e.target;
|
||||||
|
if (!form || form.tagName !== 'FORM') return;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if (e.defaultPrevented || form.getAttribute('data-tb-skip-submit-feedback') === '1') {
|
||||||
|
form.removeAttribute('data-tb-skip-submit-feedback');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if (form.getAttribute('target') === '_blank') return;
|
||||||
|
|
||||||
|
|
||||||
|
var trigger = e.submitter || form.querySelector('button[type="submit"]');
|
||||||
|
|
||||||
|
|
||||||
|
var hasFile = false;
|
||||||
|
form.querySelectorAll('input[type="file"]').forEach(function(f) {
|
||||||
|
if (f.files && f.files.length > 0) hasFile = true;
|
||||||
|
});
|
||||||
|
var label = hasFile ? SUBMIT_I18N.uploading : SUBMIT_I18N.submitting;
|
||||||
|
|
||||||
|
if (trigger && trigger.tagName === 'BUTTON') {
|
||||||
|
trigger.setAttribute('data-tb-restore', trigger.innerHTML);
|
||||||
|
trigger.innerHTML = '<span uk-spinner="ratio: 0.6"></span> ' + label;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
form.querySelectorAll('button').forEach(function(b) {
|
||||||
|
b.disabled = true;
|
||||||
|
b.setAttribute('data-tb-submitting', '1');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
window.addEventListener('pageshow', tbResetSubmitButtons);
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
After Width: | Height: | Size: 5.1 KiB |
|
After Width: | Height: | Size: 85 KiB |
|
After Width: | Height: | Size: 103 KiB |
|
After Width: | Height: | Size: 180 KiB |
|
After Width: | Height: | Size: 15 KiB |
|
After Width: | Height: | Size: 64 KiB |
|
After Width: | Height: | Size: 64 KiB |
|
After Width: | Height: | Size: 67 KiB |
|
After Width: | Height: | Size: 11 KiB |
|
After Width: | Height: | Size: 53 KiB |
|
After Width: | Height: | Size: 42 KiB |
@@ -0,0 +1 @@
|
|||||||
|
{"code":0,"data":{"id":"af87f847522ec487","question":"10 × 5 ="}}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
# Netscape HTTP Cookie File
|
||||||
|
# https://curl.se/docs/http-cookies.html
|
||||||
|
# This file was generated by libcurl! Edit at your own risk.
|
||||||
|
|
||||||
|
#HttpOnly_box-dev-api.337845818.best FALSE / TRUE 0 flamego_session xzuo76g1wkt93yde
|
||||||
@@ -0,0 +1,670 @@
|
|||||||
|
/* TamaBox 全站基础样式:设计令牌 / 主题覆盖 / 组件质感 / 响应式。
|
||||||
|
由 base/header.html 内联块抽出,集中一份便于缓存与维护。
|
||||||
|
⚠️ 改完务必把 header 里的 ?v= 版本号 +1,否则老访客仍用缓存。 */
|
||||||
|
|
||||||
|
/* 设计令牌:亮色为默认(:root),深色在 html[data-theme="dark"] 覆盖。
|
||||||
|
页面与组件样式一律引用 var(--tb-*),不再写死色值/圆角/阴影;
|
||||||
|
var() 的第二个参数仅作兜底(旧缓存页、邮件模板等不引入本文件的场景)。
|
||||||
|
改配色只动这一块,亮暗两套自动保持一致。 */
|
||||||
|
:root {
|
||||||
|
--tb-bg: #f7f8fa;
|
||||||
|
--tb-surface: #ffffff;
|
||||||
|
--tb-surface-2: #f4f6f8;
|
||||||
|
--tb-surface-hover: #f3f7ff;
|
||||||
|
--tb-border: #e8eaee;
|
||||||
|
--tb-text: #1f2329;
|
||||||
|
--tb-text-secondary: #5c6370;
|
||||||
|
--tb-text-muted: #8a919c;
|
||||||
|
--tb-primary: #1e87f0;
|
||||||
|
--tb-primary-weak: rgba(30, 135, 240, 0.10);
|
||||||
|
--tb-radius: 12px;
|
||||||
|
--tb-radius-sm: 8px;
|
||||||
|
--tb-radius-xs: 6px;
|
||||||
|
--tb-shadow: 0 1px 2px rgba(16, 24, 40, 0.04), 0 12px 28px -18px rgba(16, 24, 40, 0.20);
|
||||||
|
--tb-shadow-hover: 0 1px 2px rgba(16, 24, 40, 0.05), 0 18px 40px -20px rgba(16, 24, 40, 0.28);
|
||||||
|
--tb-font: system-ui, -apple-system, "Segoe UI", "PingFang SC", "Hiragino Sans GB", "Noto Sans CJK SC", "Microsoft YaHei", sans-serif;
|
||||||
|
}
|
||||||
|
html[data-theme="dark"] {
|
||||||
|
--tb-bg: #1a1d23;
|
||||||
|
--tb-surface: #242830;
|
||||||
|
--tb-surface-2: #2d323c;
|
||||||
|
--tb-surface-hover: rgba(92, 141, 255, 0.12);
|
||||||
|
--tb-border: #3a404c;
|
||||||
|
--tb-text: #d8dce4;
|
||||||
|
--tb-text-secondary: #a8b0bd;
|
||||||
|
--tb-text-muted: #8b93a1;
|
||||||
|
--tb-primary: #5c8dff;
|
||||||
|
--tb-primary-weak: rgba(92, 141, 255, 0.14);
|
||||||
|
--tb-shadow: 0 1px 2px rgba(0, 0, 0, 0.30), 0 12px 28px -18px rgba(0, 0, 0, 0.55);
|
||||||
|
--tb-shadow-hover: 0 1px 2px rgba(0, 0, 0, 0.35), 0 18px 40px -20px rgba(0, 0, 0, 0.65);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* UIkit 补丁:复刻原自建版 "modify-black-font"(官方版与自建版仅 3 处颜色差异——把有色容器内默认白字/白标题改为黑字)。
|
||||||
|
模板当前只用到 .uk-light 容器(用户背景封面,question/list.html、question-not-found.html;
|
||||||
|
其中 h3/p 已由 #usernamecolor/#introcolor 内联 style 覆盖),故只需补该容器的 3 处投影即可保持渲染一致。
|
||||||
|
若日后新增 .uk-card-primary/.uk-card-secondary/.uk-section-primary/.uk-tile-*/.uk-overlay-primary 等容器且需黑字,须同步扩展。 */
|
||||||
|
.uk-light { color: rgba(0,0,0,.7); }
|
||||||
|
.uk-light .uk-h1, .uk-light .uk-h2, .uk-light .uk-h3, .uk-light .uk-h4, .uk-light .uk-h5, .uk-light .uk-h6,
|
||||||
|
.uk-light .uk-heading-2xlarge, .uk-light .uk-heading-large, .uk-light .uk-heading-medium, .uk-light .uk-heading-small, .uk-light .uk-heading-xlarge,
|
||||||
|
.uk-light h1, .uk-light h2, .uk-light h3, .uk-light h4, .uk-light h5, .uk-light h6 { color: #000; }
|
||||||
|
.uk-light .uk-table th { color: rgba(0,0,0,.7); }
|
||||||
|
|
||||||
|
.grecaptcha-badge {visibility: hidden;}
|
||||||
|
.icon-container {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
.icon {
|
||||||
|
margin-left: 10px;
|
||||||
|
width: 20px; /* 设置图标的宽度 */
|
||||||
|
height: auto; /* 保持图标的高度自动调整 */
|
||||||
|
}
|
||||||
|
.emoji-placeholder {
|
||||||
|
display: inline-block;
|
||||||
|
animation: jump 0.5s ease-in-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes jump {
|
||||||
|
0%, 100% { transform: translateY(0); }
|
||||||
|
50% { transform: translateY(-5px); }
|
||||||
|
}
|
||||||
|
/* 防止 UIkit Dropbar 初始闪烁 */
|
||||||
|
.uk-dropbar {
|
||||||
|
opacity: 0;
|
||||||
|
visibility: hidden;
|
||||||
|
transition: opacity 0.2s ease, visibility 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.uk-dropbar.uk-open {
|
||||||
|
opacity: 1;
|
||||||
|
visibility: visible;
|
||||||
|
}
|
||||||
|
|
||||||
|
a.uk-button.uk-button-link {
|
||||||
|
text-transform: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 移动端优化:缩小字体和间距,避免右侧空白 */
|
||||||
|
@media (max-width: 640px) {
|
||||||
|
.uk-logo {
|
||||||
|
font-size: 1rem;
|
||||||
|
}
|
||||||
|
.uk-navbar-nav a {
|
||||||
|
font-size: 0.78rem;
|
||||||
|
padding: 0 4px;
|
||||||
|
}
|
||||||
|
.emoji-placeholder {
|
||||||
|
font-size: 1rem;
|
||||||
|
}
|
||||||
|
/* 移动端用户名限宽省略,避免长英文用户名撑爆顶栏 */
|
||||||
|
.tb-nav-username {
|
||||||
|
max-width: 64px;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
display: inline-block;
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 深色模式:html[data-theme="dark"] 时覆盖 UIkit 3.3.3 编译主题的关键颜色 */
|
||||||
|
/* 变量(--tb-*)已上移到 head 顶部的令牌块,亮暗两套同名常量在那里定义。 */
|
||||||
|
/* 根元素与 body 一起覆盖,确保整个视口(含内容不足一屏时的空白区)都是深色背景 */
|
||||||
|
html[data-theme="dark"],
|
||||||
|
html[data-theme="dark"] body {
|
||||||
|
background-color: var(--tb-bg) !important;
|
||||||
|
color: var(--tb-text) !important;
|
||||||
|
}
|
||||||
|
/* 通用表面容器 */
|
||||||
|
html[data-theme="dark"] .uk-card,
|
||||||
|
html[data-theme="dark"] .uk-card-default,
|
||||||
|
html[data-theme="dark"] .uk-card-secondary,
|
||||||
|
html[data-theme="dark"] .uk-dropbar,
|
||||||
|
html[data-theme="dark"] .uk-navbar-dropdown,
|
||||||
|
html[data-theme="dark"] .uk-modal-dialog,
|
||||||
|
html[data-theme="dark"] .uk-dropdown,
|
||||||
|
html[data-theme="dark"] .uk-offcanvas-bar,
|
||||||
|
html[data-theme="dark"] .uk-section,
|
||||||
|
html[data-theme="dark"] .uk-tile,
|
||||||
|
html[data-theme="dark"] .uk-panel,
|
||||||
|
html[data-theme="dark"] .uk-background-default,
|
||||||
|
html[data-theme="dark"] .uk-search-default .uk-search-input {
|
||||||
|
background-color: var(--tb-surface) !important;
|
||||||
|
color: var(--tb-text) !important;
|
||||||
|
}
|
||||||
|
html[data-theme="dark"] .uk-navbar-container {
|
||||||
|
background-color: var(--tb-surface) !important;
|
||||||
|
color: var(--tb-text) !important;
|
||||||
|
}
|
||||||
|
html[data-theme="dark"] .uk-navbar-nav > li > a,
|
||||||
|
html[data-theme="dark"] .uk-card a,
|
||||||
|
html[data-theme="dark"] .uk-link,
|
||||||
|
html[data-theme="dark"] a.uk-button-link,
|
||||||
|
html[data-theme="dark"] .uk-navbar-dropdown-nav > li > a,
|
||||||
|
html[data-theme="dark"] .uk-dropdown-nav > li > a,
|
||||||
|
html[data-theme="dark"] .uk-list a {
|
||||||
|
color: var(--tb-text) !important;
|
||||||
|
}
|
||||||
|
html[data-theme="dark"] .uk-navbar-nav > li > a:hover,
|
||||||
|
html[data-theme="dark"] .uk-card a:hover,
|
||||||
|
html[data-theme="dark"] .uk-navbar-dropdown-nav > li > a:hover,
|
||||||
|
html[data-theme="dark"] .uk-dropdown-nav > li > a:hover {
|
||||||
|
color: var(--tb-primary) !important;
|
||||||
|
}
|
||||||
|
html[data-theme="dark"] .uk-input,
|
||||||
|
html[data-theme="dark"] .uk-textarea,
|
||||||
|
html[data-theme="dark"] .uk-select {
|
||||||
|
background-color: var(--tb-surface-2) !important;
|
||||||
|
color: var(--tb-text) !important;
|
||||||
|
border-color: var(--tb-border) !important;
|
||||||
|
}
|
||||||
|
html[data-theme="dark"] .uk-input:focus,
|
||||||
|
html[data-theme="dark"] .uk-textarea:focus,
|
||||||
|
html[data-theme="dark"] .uk-select:focus {
|
||||||
|
border-color: var(--tb-primary) !important;
|
||||||
|
}
|
||||||
|
html[data-theme="dark"] .uk-text-muted,
|
||||||
|
html[data-theme="dark"] .uk-text-meta,
|
||||||
|
html[data-theme="dark"] .uk-text-secondary,
|
||||||
|
html[data-theme="dark"] .uk-text-muted a,
|
||||||
|
html[data-theme="dark"] .uk-text-small.uk-text-muted {
|
||||||
|
color: var(--tb-text-muted) !important;
|
||||||
|
}
|
||||||
|
html[data-theme="dark"] .uk-divider-icon::after,
|
||||||
|
html[data-theme="dark"] hr,
|
||||||
|
html[data-theme="dark"] .uk-table th,
|
||||||
|
html[data-theme="dark"] .uk-table td,
|
||||||
|
html[data-theme="dark"] .uk-list-divider > li:nth-child(n+2) {
|
||||||
|
border-color: var(--tb-border) !important;
|
||||||
|
}
|
||||||
|
html[data-theme="dark"] .uk-button-default {
|
||||||
|
background-color: var(--tb-surface-2) !important;
|
||||||
|
color: var(--tb-text) !important;
|
||||||
|
border-color: var(--tb-border) !important;
|
||||||
|
}
|
||||||
|
html[data-theme="dark"] .uk-modal-title,
|
||||||
|
html[data-theme="dark"] h1, html[data-theme="dark"] h2, html[data-theme="dark"] h3,
|
||||||
|
html[data-theme="dark"] h4, html[data-theme="dark"] h5, html[data-theme="dark"] h6,
|
||||||
|
html[data-theme="dark"] .uk-card-title {
|
||||||
|
color: var(--tb-text) !important;
|
||||||
|
}
|
||||||
|
html[data-theme="dark"] .uk-alert-warning,
|
||||||
|
html[data-theme="dark"] .uk-alert-danger,
|
||||||
|
html[data-theme="dark"] .uk-alert-success,
|
||||||
|
html[data-theme="dark"] .uk-alert-primary {
|
||||||
|
background-color: var(--tb-surface-2) !important;
|
||||||
|
color: var(--tb-text) !important;
|
||||||
|
}
|
||||||
|
html[data-theme="dark"] #math-captcha-modal .uk-modal-dialog {
|
||||||
|
background-color: var(--tb-surface) !important;
|
||||||
|
color: var(--tb-text) !important;
|
||||||
|
}
|
||||||
|
html[data-theme="dark"] #math-captcha-modal .captcha-equation-box {
|
||||||
|
background-color: var(--tb-surface-2) !important;
|
||||||
|
border-color: var(--tb-border) !important;
|
||||||
|
}
|
||||||
|
html[data-theme="dark"] #math-captcha-modal .math-captcha-modal-question {
|
||||||
|
color: var(--tb-text) !important;
|
||||||
|
}
|
||||||
|
html[data-theme="dark"] #math-captcha-modal #captcha-modal-answer {
|
||||||
|
background-color: var(--tb-surface) !important;
|
||||||
|
color: var(--tb-text) !important;
|
||||||
|
border-color: var(--tb-border) !important;
|
||||||
|
}
|
||||||
|
html[data-theme="dark"] #math-captcha-modal #captcha-modal-answer::placeholder {
|
||||||
|
color: var(--tb-text-muted) !important;
|
||||||
|
}
|
||||||
|
html[data-theme="dark"] #math-captcha-modal .uk-text-meta,
|
||||||
|
html[data-theme="dark"] #math-captcha-modal #captcha-modal-refresh {
|
||||||
|
color: var(--tb-text-muted) !important;
|
||||||
|
}
|
||||||
|
html[data-theme="dark"] #math-captcha-modal #captcha-modal-refresh:hover {
|
||||||
|
color: var(--tb-primary) !important;
|
||||||
|
}
|
||||||
|
html[data-theme="dark"] .uk-label {
|
||||||
|
color: #fff !important;
|
||||||
|
}
|
||||||
|
/* 自定义组件(探索页推荐卡片等)深色覆盖 */
|
||||||
|
html[data-theme="dark"] .recommend-card,
|
||||||
|
html[data-theme="dark"] .recommend-card:hover {
|
||||||
|
background-color: var(--tb-surface-2) !important;
|
||||||
|
}
|
||||||
|
html[data-theme="dark"] .explore-name a {
|
||||||
|
color: var(--tb-text) !important;
|
||||||
|
}
|
||||||
|
html[data-theme="dark"] .explore-name a:hover {
|
||||||
|
color: var(--tb-primary) !important;
|
||||||
|
}
|
||||||
|
html[data-theme="dark"] .explore-intro {
|
||||||
|
color: var(--tb-text-muted) !important;
|
||||||
|
}
|
||||||
|
/* 切换按钮图标切换(内联 SVG,不依赖 UIkit 图标库) */
|
||||||
|
#theme-toggle .tb-icon-light, #theme-toggle-mobile .tb-icon-light,
|
||||||
|
#theme-toggle .tb-icon-dark, #theme-toggle-mobile .tb-icon-dark {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
#theme-toggle .tb-icon-light svg, #theme-toggle-mobile .tb-icon-light svg,
|
||||||
|
#theme-toggle .tb-icon-dark svg, #theme-toggle-mobile .tb-icon-dark svg { display: block; }
|
||||||
|
#theme-toggle .tb-icon-dark, #theme-toggle-mobile .tb-icon-dark { display: none; }
|
||||||
|
html[data-theme="dark"] #theme-toggle .tb-icon-light,
|
||||||
|
html[data-theme="dark"] #theme-toggle-mobile .tb-icon-light { display: none; }
|
||||||
|
html[data-theme="dark"] #theme-toggle .tb-icon-dark,
|
||||||
|
html[data-theme="dark"] #theme-toggle-mobile .tb-icon-dark { display: inline-flex; }
|
||||||
|
|
||||||
|
/* 基础质感层:只调整外观(圆角/投影/字体/数字对齐),不改任何结构与布局。
|
||||||
|
颜色一律取自头部令牌,亮暗两套自动生效,因此这里不需要再写 html[data-theme="dark"] 分支。 */
|
||||||
|
/* 根元素与 body 同时上色:内容不足一屏时,body 之外的视口区域也要是同一底色 */
|
||||||
|
html,
|
||||||
|
body {
|
||||||
|
font-family: var(--tb-font);
|
||||||
|
background-color: var(--tb-bg);
|
||||||
|
color: var(--tb-text);
|
||||||
|
-webkit-font-smoothing: antialiased;
|
||||||
|
-moz-osx-font-smoothing: grayscale;
|
||||||
|
}
|
||||||
|
/* 卡片:12px 圆角 + 一层极淡接触影 + 一层大扩散影(UIkit 默认的 0 5px 15px 偏硬) */
|
||||||
|
.uk-card {
|
||||||
|
border-radius: var(--tb-radius);
|
||||||
|
}
|
||||||
|
.uk-card-default {
|
||||||
|
background-color: var(--tb-surface);
|
||||||
|
box-shadow: var(--tb-shadow);
|
||||||
|
}
|
||||||
|
.uk-card-default.uk-card-hover:hover {
|
||||||
|
box-shadow: var(--tb-shadow-hover);
|
||||||
|
}
|
||||||
|
.uk-card-header {
|
||||||
|
border-radius: var(--tb-radius) var(--tb-radius) 0 0;
|
||||||
|
}
|
||||||
|
.uk-card-footer {
|
||||||
|
border-radius: 0 0 var(--tb-radius) var(--tb-radius);
|
||||||
|
}
|
||||||
|
.uk-card,
|
||||||
|
.uk-button,
|
||||||
|
.uk-alert,
|
||||||
|
.uk-label {
|
||||||
|
transition: box-shadow 0.18s ease, background-color 0.18s ease, border-color 0.18s ease, color 0.18s ease;
|
||||||
|
}
|
||||||
|
/* 交互元素:统一 8px 圆角,标签 6px */
|
||||||
|
.uk-button {
|
||||||
|
border-radius: var(--tb-radius-sm);
|
||||||
|
}
|
||||||
|
.uk-input,
|
||||||
|
.uk-select,
|
||||||
|
.uk-textarea,
|
||||||
|
.uk-form-small,
|
||||||
|
.uk-search-input {
|
||||||
|
border-radius: var(--tb-radius-sm);
|
||||||
|
}
|
||||||
|
.uk-label {
|
||||||
|
border-radius: var(--tb-radius-xs);
|
||||||
|
}
|
||||||
|
.uk-alert {
|
||||||
|
border-radius: 10px;
|
||||||
|
}
|
||||||
|
.uk-modal-dialog {
|
||||||
|
border-radius: 14px;
|
||||||
|
}
|
||||||
|
.uk-dropdown,
|
||||||
|
.uk-navbar-dropdown {
|
||||||
|
border-radius: 10px;
|
||||||
|
box-shadow: var(--tb-shadow);
|
||||||
|
}
|
||||||
|
.uk-navbar-container:not(.uk-navbar-transparent) {
|
||||||
|
background-color: var(--tb-surface);
|
||||||
|
}
|
||||||
|
/* 键盘可达性:仅在键盘聚焦时出现描边,鼠标点击不出现 */
|
||||||
|
.uk-button:focus-visible,
|
||||||
|
.uk-navbar-nav > li > a:focus-visible {
|
||||||
|
outline: 2px solid var(--tb-primary);
|
||||||
|
outline-offset: 2px;
|
||||||
|
}
|
||||||
|
/* 次要文字统一走令牌,避免 #999 / #8a919c 混用 */
|
||||||
|
.uk-text-muted,
|
||||||
|
.uk-text-meta {
|
||||||
|
color: var(--tb-text-muted);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 轻量胶囊:用于投票类型、热门标签等「只是分类信息」的位置。
|
||||||
|
实心 uk-label 一屏多个会变成一排色块,这里统一降级为浅底 + 次要色文字。 */
|
||||||
|
.tb-chip {
|
||||||
|
display: inline-block;
|
||||||
|
padding: 1px 8px;
|
||||||
|
border-radius: var(--tb-radius-xs);
|
||||||
|
background-color: var(--tb-surface-2);
|
||||||
|
color: var(--tb-text-secondary);
|
||||||
|
font-size: 0.72rem;
|
||||||
|
line-height: 1.7;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
a.tb-chip:hover {
|
||||||
|
background-color: var(--tb-primary-weak);
|
||||||
|
color: var(--tb-primary);
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 统计/日期等数字列等宽对齐,避免刷新时左右跳动 */
|
||||||
|
.uk-table,
|
||||||
|
.tb-num {
|
||||||
|
font-variant-numeric: tabular-nums;
|
||||||
|
}
|
||||||
|
/* 图片上传条:原为 item/new-question 两处各写一份内联 style(写死 #f8f8f8,深色下露白),
|
||||||
|
收敛到一处并走令牌,亮暗自动适配 */
|
||||||
|
.tb-img-uploader {
|
||||||
|
width: 100%;
|
||||||
|
background-color: var(--tb-surface-2);
|
||||||
|
display: flex;
|
||||||
|
padding-top: 5px;
|
||||||
|
padding-bottom: 5px;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: flex-start;
|
||||||
|
gap: 5px;
|
||||||
|
}
|
||||||
|
/* 背景图封面(提问箱主页):渐变遮罩,保证用户自选文字色叠加后仍可读。
|
||||||
|
默认浅色遮罩(页面 .uk-light 补丁把文字兜底成深色);若箱主选了浅色文字,
|
||||||
|
question/list.html 会按亮度加上 .tb-cover-dark 换成深色遮罩。 */
|
||||||
|
.tb-cover {
|
||||||
|
position: relative;
|
||||||
|
border-radius: var(--tb-radius) var(--tb-radius) 0 0;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
/* ⚠️ 必须带 .uk-flex 复合选择器:UIkit 3.3.3 里有
|
||||||
|
.uk-flex::after,.uk-flex::before{display:none}(优先级 0,2,0),
|
||||||
|
会把这个遮罩伪元素整个干掉——不报错、只是什么都不显示(踩过一次)。
|
||||||
|
单写 .tb-cover::after 优先级不够,会被它压回 display:none。 */
|
||||||
|
.tb-cover::after,
|
||||||
|
.tb-cover.uk-flex::after {
|
||||||
|
content: "";
|
||||||
|
display: block;
|
||||||
|
position: absolute;
|
||||||
|
inset: 0;
|
||||||
|
z-index: 0;
|
||||||
|
background: linear-gradient(180deg, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.58) 55%, rgba(255, 255, 255, 0.84) 100%);
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
.tb-cover.tb-cover-dark::after {
|
||||||
|
background: linear-gradient(180deg, rgba(0, 0, 0, 0) 0%, rgba(0, 0, 0, 0.16) 45%, rgba(0, 0, 0, 0.46) 100%);
|
||||||
|
}
|
||||||
|
.tb-cover > * {
|
||||||
|
position: relative;
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
.tb-cover h3,
|
||||||
|
.tb-cover p {
|
||||||
|
text-shadow: 0 1px 10px rgba(255, 255, 255, 0.65);
|
||||||
|
}
|
||||||
|
.tb-cover.tb-cover-dark h3,
|
||||||
|
.tb-cover.tb-cover-dark p {
|
||||||
|
text-shadow: 0 1px 12px rgba(0, 0, 0, 0.45);
|
||||||
|
}
|
||||||
|
/* 尊重系统的减少动效设置 */
|
||||||
|
@media (prefers-reduced-motion: reduce) {
|
||||||
|
.uk-card,
|
||||||
|
.uk-button,
|
||||||
|
.emoji-placeholder {
|
||||||
|
transition: none;
|
||||||
|
animation: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 顶栏自适应:导航全部直接显示,窄屏时分级缩小字号/间距,保证英文/日文等长文字不溢出 */
|
||||||
|
.uk-navbar-nav a {
|
||||||
|
font-size: 0.95rem;
|
||||||
|
padding: 0 10px;
|
||||||
|
}
|
||||||
|
/* 未登录移动端占位:桌面端隐藏,仅 ≤640px 显示(见下方 media 查询)。
|
||||||
|
桌面端布局与改动前完全一致,不受影响。 */
|
||||||
|
.tb-mobile-balancer { display: none; }
|
||||||
|
/* 桌面端保持 UIkit 原生居中三列布局(无需额外 CSS) */
|
||||||
|
.tb-navbar .uk-logo {
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
@media (max-width: 1200px) {
|
||||||
|
.uk-navbar-nav a {
|
||||||
|
font-size: 0.88rem;
|
||||||
|
padding: 0 8px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@media (max-width: 1000px) {
|
||||||
|
.uk-navbar-nav a {
|
||||||
|
font-size: 0.82rem;
|
||||||
|
padding: 0 6px;
|
||||||
|
}
|
||||||
|
.uk-logo {
|
||||||
|
font-size: 1.1rem;
|
||||||
|
}
|
||||||
|
/* 登录用户名限宽,过长省略号截断 */
|
||||||
|
.tb-nav-username {
|
||||||
|
max-width: 110px;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
display: inline-block;
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@media (max-width: 800px) {
|
||||||
|
.uk-navbar-nav a {
|
||||||
|
font-size: 0.78rem;
|
||||||
|
padding: 0 4px;
|
||||||
|
}
|
||||||
|
.uk-logo {
|
||||||
|
font-size: 1rem;
|
||||||
|
}
|
||||||
|
.tb-nav-username {
|
||||||
|
max-width: 80px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* 手机端(≤640px):沿用 UIkit 桌面端 navbar 的原生三列定位。
|
||||||
|
不再重写 .uk-navbar-center / center-left / center-right 的定位,
|
||||||
|
避免 logo 被挤到下一行;底部语言与深色模式按钮仍由下方独立栏承载。 */
|
||||||
|
@media (max-width: 640px) {
|
||||||
|
.tb-navbar {
|
||||||
|
position: relative;
|
||||||
|
min-height: 56px;
|
||||||
|
overflow: visible;
|
||||||
|
}
|
||||||
|
.tb-navbar > .uk-navbar-center {
|
||||||
|
position: relative !important;
|
||||||
|
top: auto !important;
|
||||||
|
left: auto !important;
|
||||||
|
right: auto !important;
|
||||||
|
bottom: auto !important;
|
||||||
|
transform: none !important;
|
||||||
|
display: flex !important;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
width: 100%;
|
||||||
|
min-height: 56px;
|
||||||
|
white-space: nowrap;
|
||||||
|
flex-wrap: nowrap;
|
||||||
|
}
|
||||||
|
.tb-navbar .uk-navbar-center-left,
|
||||||
|
.tb-navbar .uk-navbar-center-right {
|
||||||
|
position: static !important;
|
||||||
|
top: auto !important;
|
||||||
|
left: auto !important;
|
||||||
|
right: auto !important;
|
||||||
|
bottom: auto !important;
|
||||||
|
transform: none !important;
|
||||||
|
display: flex !important;
|
||||||
|
align-items: center;
|
||||||
|
flex: 0 0 auto;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
.tb-navbar .uk-navbar-center-left > div,
|
||||||
|
.tb-navbar .uk-navbar-center-right > div {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
.tb-navbar .uk-navbar-nav {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: nowrap;
|
||||||
|
flex: 0 0 auto;
|
||||||
|
}
|
||||||
|
.tb-navbar .uk-navbar-nav > li > a,
|
||||||
|
.tb-navbar .uk-logo {
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
/* 未登录:移动端显示与「我的」等宽的隐藏占位,使左栏「探索+占位」与
|
||||||
|
右栏「注册/登录」两项等宽,logo 真正居中,左右视觉平衡 */
|
||||||
|
.tb-mobile-balancer { display: block; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 标签样式的按钮(管理页置顶等):
|
||||||
|
尺寸完全继承 .uk-label(font-size/padding/line-height/text-transform 等),
|
||||||
|
仅覆盖 button 元素特有的默认样式(边框/字体族/光标等),保证与相邻 span 标签完全一致。 */
|
||||||
|
.tb-label-btn {
|
||||||
|
border: none !important;
|
||||||
|
cursor: pointer;
|
||||||
|
font-family: inherit;
|
||||||
|
margin: 0;
|
||||||
|
vertical-align: middle;
|
||||||
|
outline: none;
|
||||||
|
background-image: none;
|
||||||
|
box-sizing: border-box;
|
||||||
|
-webkit-appearance: none;
|
||||||
|
appearance: none;
|
||||||
|
}
|
||||||
|
.tb-label-btn:hover {
|
||||||
|
opacity: 0.85;
|
||||||
|
}
|
||||||
|
/* 公开页置顶小图标:仅一个图钉,不占行高、不影响原布局 */
|
||||||
|
.tb-pin-flag {
|
||||||
|
font-size: 0.9em;
|
||||||
|
margin-right: 4px;
|
||||||
|
vertical-align: -1px;
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Markdown 渲染排版(问题/回答/追问正文,左对齐以保留排版格式) */
|
||||||
|
/* 纯文本列表:保留换行与连续空格(pre-wrap),不渲染 Markdown 大字号/彩色 */
|
||||||
|
.tb-preline {
|
||||||
|
white-space: pre-wrap;
|
||||||
|
}
|
||||||
|
/* 纯文本列表:超过 5 行截断并显示省略号(不足 5 行则完整显示) */
|
||||||
|
.tb-clamp-5 {
|
||||||
|
display: -webkit-box;
|
||||||
|
-webkit-box-orient: vertical;
|
||||||
|
-webkit-line-clamp: 5;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
.md-body {
|
||||||
|
line-height: 1.7;
|
||||||
|
text-align: left;
|
||||||
|
word-break: break-word;
|
||||||
|
}
|
||||||
|
.md-body p { margin: 0.5em 0; }
|
||||||
|
.md-body h1, .md-body h2, .md-body h3,
|
||||||
|
.md-body h4, .md-body h5, .md-body h6 {
|
||||||
|
margin: 0.8em 0 0.4em;
|
||||||
|
font-weight: 600;
|
||||||
|
line-height: 1.4;
|
||||||
|
}
|
||||||
|
.md-body ul, .md-body ol { padding-left: 1.6em; margin: 0.5em 0; }
|
||||||
|
.md-body li { margin: 0.2em 0; }
|
||||||
|
.md-body blockquote {
|
||||||
|
border-left: 3px solid #d3d1c7;
|
||||||
|
margin: 0.6em 0;
|
||||||
|
padding: 0.2em 1em;
|
||||||
|
color: #5f5e5a;
|
||||||
|
}
|
||||||
|
.md-body pre {
|
||||||
|
background: #f5f5f5;
|
||||||
|
padding: 0.8em 1em;
|
||||||
|
border-radius: 6px;
|
||||||
|
overflow-x: auto;
|
||||||
|
margin: 0.6em 0;
|
||||||
|
}
|
||||||
|
.md-body code {
|
||||||
|
background: #f0f0f0;
|
||||||
|
padding: 0.1em 0.35em;
|
||||||
|
border-radius: 4px;
|
||||||
|
font-size: 0.9em;
|
||||||
|
}
|
||||||
|
.md-body pre code { background: none; padding: 0; }
|
||||||
|
.md-body img { max-width: 100%; height: auto; }
|
||||||
|
.md-body table { border-collapse: collapse; margin: 0.6em 0; }
|
||||||
|
.md-body th, .md-body td {
|
||||||
|
border: 1px solid #ddd;
|
||||||
|
padding: 0.4em 0.8em;
|
||||||
|
}
|
||||||
|
.md-body hr { margin: 1em 0; }
|
||||||
|
html[data-theme="dark"] .md-body blockquote {
|
||||||
|
border-color: #3a404c;
|
||||||
|
color: #8b93a1;
|
||||||
|
}
|
||||||
|
html[data-theme="dark"] .md-body pre,
|
||||||
|
html[data-theme="dark"] .md-body code { background: #2d323c; }
|
||||||
|
html[data-theme="dark"] .md-body th,
|
||||||
|
html[data-theme="dark"] .md-body td { border-color: #3a404c; }
|
||||||
|
|
||||||
|
/* 投票结果占比条:模板已改用 UIkit 3 原生 <progress class="uk-progress" value max>,
|
||||||
|
这里只把默认的 15px 高 / 500px 圆角 / 20px 外边距收紧到与页面一致的规格。
|
||||||
|
(原先为 UIkit 2 的 .uk-progressbar 结构打的补丁已删除) */
|
||||||
|
.uk-progress {
|
||||||
|
height: 10px;
|
||||||
|
margin: 0;
|
||||||
|
border-radius: var(--tb-radius-xs);
|
||||||
|
background-color: var(--tb-surface-2);
|
||||||
|
}
|
||||||
|
.uk-progress::-webkit-progress-bar {
|
||||||
|
background-color: var(--tb-surface-2);
|
||||||
|
border-radius: var(--tb-radius-xs);
|
||||||
|
}
|
||||||
|
.uk-progress::-webkit-progress-value {
|
||||||
|
/* 两端都圆:值 100% 时若只圆左边,右端方角会顶出轨道圆角 */
|
||||||
|
background-color: var(--tb-primary);
|
||||||
|
border-radius: var(--tb-radius-xs);
|
||||||
|
}
|
||||||
|
.uk-progress::-moz-progress-bar {
|
||||||
|
background-color: var(--tb-primary);
|
||||||
|
border-radius: var(--tb-radius-xs);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 移动端底部操作栏:固定底栏承载语言切换与深色模式,桌面端隐藏 */
|
||||||
|
#tb-mobile-utils {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
@media (max-width: 640px) {
|
||||||
|
/* 顶栏不再容纳语言/深色按钮,恢复原有导航空间 */
|
||||||
|
.tb-nav-utils {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
/* 手机端隐藏登录用户名(左边仅保留"探索"),保证 logo 居中、
|
||||||
|
两侧各不超过 2 个短按钮,避免用户名宽度挤压布局 */
|
||||||
|
.tb-nav-username {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
/* 固定底部操作栏 */
|
||||||
|
#tb-mobile-utils {
|
||||||
|
display: flex;
|
||||||
|
position: fixed;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
z-index: 1000;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
gap: 10px;
|
||||||
|
padding: 8px 12px calc(8px + env(safe-area-inset-bottom));
|
||||||
|
background: rgba(255, 255, 255, 0.92);
|
||||||
|
-webkit-backdrop-filter: blur(8px);
|
||||||
|
backdrop-filter: blur(8px);
|
||||||
|
box-shadow: 0 -2px 12px rgba(0, 0, 0, 0.08);
|
||||||
|
}
|
||||||
|
#tb-mobile-utils .uk-select {
|
||||||
|
width: 110px;
|
||||||
|
}
|
||||||
|
html[data-theme="dark"] #tb-mobile-utils {
|
||||||
|
background: rgba(36, 40, 48, 0.92);
|
||||||
|
box-shadow: 0 -2px 12px rgba(0, 0, 0, 0.4);
|
||||||
|
}
|
||||||
|
/* 给页面底部预留空间,避免页脚内容被固定底栏遮挡 */
|
||||||
|
body {
|
||||||
|
padding-bottom: 56px;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,937 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="ja">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<title>狼の質問箱 | 匿名質問箱</title>
|
||||||
|
<meta name="msvalidate.01" content="2F185E8E63C93635F50B3574F3B31E42" />
|
||||||
|
<meta name="description" content="狼の質問箱は登録不要で使える匿名質問箱。誰でも匿名で質問でき、安心してやり取りできる場所です。">
|
||||||
|
<meta name="keywords" content="匿名質問箱,質問箱,匿名質問,狼の質問箱,匿名で質問,匿名Q&A">
|
||||||
|
|
||||||
|
<script>
|
||||||
|
(function () {
|
||||||
|
var m = document.cookie.match(/(?:^|;\s*)theme=([^;]*)/);
|
||||||
|
if (m && m[1] === 'dark') document.documentElement.setAttribute('data-theme', 'dark');
|
||||||
|
})();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<link rel="preconnect" href="https://r2.337845818.best" crossorigin>
|
||||||
|
<link rel="preconnect" href="https://cdnjs.snrat.com" crossorigin>
|
||||||
|
|
||||||
|
<link rel="stylesheet" href="https://cdnjs.snrat.com/ajax/libs/uikit/3.3.3/css/uikit.min.css"/>
|
||||||
|
|
||||||
|
<link rel="stylesheet" href="/static/css/base.css?v=20261019d"/>
|
||||||
|
|
||||||
|
<link rel="stylesheet" href="https://r2.337845818.best/tamabox/cdn/waline/client/v2/waline-no-commits.css" media="print" onload="this.media='all'"/>
|
||||||
|
<script defer src="https://cdnjs.snrat.com/ajax/libs/uikit/3.3.3/js/uikit.min.js"></script>
|
||||||
|
<script defer src="https://cdnjs.snrat.com/ajax/libs/uikit/3.3.3/js/uikit-icons.min.js"></script>
|
||||||
|
|
||||||
|
<script defer src="https://cdnjs.snrat.com/ajax/libs/dayjs/1.10.8/dayjs.min.js"></script>
|
||||||
|
<script defer src="https://cdnjs.snrat.com/ajax/libs/alpinejs/3.9.0/cdn.min.js"></script>
|
||||||
|
|
||||||
|
|
||||||
|
<script defer src="https://cdnjs.snrat.com/ajax/libs/waline/2.15.8/waline.js"></script>
|
||||||
|
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.captcha-equation-box {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
background: #f0f2f5;
|
||||||
|
border: 1px solid #dcdcdc;
|
||||||
|
border-radius: 8px;
|
||||||
|
padding: 8px 8px 8px 16px;
|
||||||
|
gap: 6px;
|
||||||
|
transition: border-color 0.2s;
|
||||||
|
}
|
||||||
|
.captcha-equation-box:focus-within {
|
||||||
|
border-color: #1e87f0;
|
||||||
|
box-shadow: 0 0 0 3px rgba(30,135,240,0.12);
|
||||||
|
}
|
||||||
|
.math-captcha-modal-question {
|
||||||
|
font-size: 1.4rem;
|
||||||
|
font-family: "Courier New", monospace;
|
||||||
|
font-weight: 700;
|
||||||
|
color: #333;
|
||||||
|
letter-spacing: 1px;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
#captcha-modal-answer {
|
||||||
|
width: 80px;
|
||||||
|
padding: 6px 10px;
|
||||||
|
text-align: center;
|
||||||
|
font-size: 1.2rem;
|
||||||
|
font-family: "Courier New", monospace;
|
||||||
|
font-weight: 600;
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
border-radius: 5px;
|
||||||
|
outline: none;
|
||||||
|
transition: border-color 0.15s, box-shadow 0.15s;
|
||||||
|
background: #fff;
|
||||||
|
}
|
||||||
|
#captcha-modal-answer:focus {
|
||||||
|
border-color: #1e87f0;
|
||||||
|
box-shadow: 0 0 0 2px rgba(30,135,240,0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
#captcha-modal-answer::-webkit-inner-spin-button,
|
||||||
|
#captcha-modal-answer::-webkit-outer-spin-button {
|
||||||
|
-webkit-appearance: none;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
#captcha-modal-answer {
|
||||||
|
-moz-appearance: textfield;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<meta property="og:site_name" content="狼の質問箱 | 匿名質問箱" />
|
||||||
|
<meta property="og:type" content="website" />
|
||||||
|
<meta property="og:title" content="狼の質問箱 | 匿名質問箱" />
|
||||||
|
<meta property="og:url" content="https://box-dev-api.337845818.best/" />
|
||||||
|
<meta property="og:description" content="狼の質問箱は登録不要で使える匿名質問箱。誰でも匿名で質問でき、安心してやり取りできる場所です。" />
|
||||||
|
|
||||||
|
|
||||||
|
<meta itemprop="image" content="https://r2.337845818.best/tamabox/tamabox_low.png"/>
|
||||||
|
<meta name="msapplication-TileImage" content="https://r2.337845818.best/tamabox/tamabox_low.png"/>
|
||||||
|
<link rel="shortcut icon" href="https://r2.337845818.best/tamabox/tamabox_low.png" />
|
||||||
|
<link rel="apple-touch-icon" href="https://r2.337845818.best/tamabox/tamabox_low.png"/>
|
||||||
|
<link rel="icon" sizes="192x192" href="https://r2.337845818.best/tamabox/tamabox_low.png">
|
||||||
|
<meta name="twitter:image:src" content="https://r2.337845818.best/tamabox/tamabox_low.png" />
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<meta name="google-site-verification" content="fEPwRRJfiGsgwc5SINBQwZhPK8F0cwRaOvRx0YRurI4" />
|
||||||
|
|
||||||
|
<script>
|
||||||
|
window.addEventListener("load", function () {
|
||||||
|
var s = document.createElement("script");
|
||||||
|
s.src = "https://mami.shiroko.one/tamami.js";
|
||||||
|
s.setAttribute("data-website-id", "c42ebe8b-9281-4da0-83a4-8f18b3e710fe");
|
||||||
|
document.body.appendChild(s);
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<script>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
window.tbRenderQR = function (el, getOptions) {
|
||||||
|
if (!el || typeof QRCode === 'undefined') return;
|
||||||
|
var opts = getOptions();
|
||||||
|
function remoteOf(o, key) {
|
||||||
|
var v = o[key];
|
||||||
|
return (typeof v === 'string' && v.indexOf('http') === 0) ? v : '';
|
||||||
|
}
|
||||||
|
var good = window._tbQrGood || (window._tbQrGood = {});
|
||||||
|
var bad = window._tbQrBad || (window._tbQrBad = {});
|
||||||
|
|
||||||
|
function layerState(url) { return !url ? '' : (good[url] ? 1 : (bad[url] ? 0 : null)); }
|
||||||
|
var layers = [
|
||||||
|
{ url: remoteOf(opts, 'logo'), st: null, present: function (o, on) {
|
||||||
|
if (on) { } else { o.logo = undefined; o.logoWidth = undefined; o.logoHeight = undefined; o.logoBackgroundTransparent = undefined; }
|
||||||
|
} },
|
||||||
|
{ url: remoteOf(opts, 'backgroundImage'), st: null, present: function (o, on) {
|
||||||
|
if (on) { } else { o.backgroundImage = undefined; o.backgroundImageAlpha = undefined; }
|
||||||
|
} }
|
||||||
|
];
|
||||||
|
var needProbe = false;
|
||||||
|
for (var i = 0; i < layers.length; i++) {
|
||||||
|
layers[i].st = layerState(layers[i].url);
|
||||||
|
if (layers[i].st === null) needProbe = true;
|
||||||
|
}
|
||||||
|
function paint(states) {
|
||||||
|
var o = {};
|
||||||
|
for (var k in opts) o[k] = opts[k];
|
||||||
|
for (var j = 0; j < layers.length; j++) layers[j].present(o, states[j] === 1);
|
||||||
|
el.innerHTML = '';
|
||||||
|
new QRCode(el, o);
|
||||||
|
}
|
||||||
|
|
||||||
|
var initStates = [];
|
||||||
|
for (var n = 0; n < layers.length; n++) initStates.push(layers[n].st === 1 ? 1 : 0);
|
||||||
|
paint(initStates);
|
||||||
|
if (!needProbe) return;
|
||||||
|
|
||||||
|
var pending = 0, cross = opts.crossOrigin || 'anonymous';
|
||||||
|
layers.forEach(function (L) {
|
||||||
|
if (L.st !== null) return;
|
||||||
|
pending++;
|
||||||
|
var im = new Image();
|
||||||
|
im.onload = function () { good[L.url] = true; L.st = 1; onDone(); };
|
||||||
|
im.onerror = function () { bad[L.url] = true; L.st = 0; onDone(); };
|
||||||
|
if (cross) im.crossOrigin = cross;
|
||||||
|
im.src = L.url;
|
||||||
|
});
|
||||||
|
function onDone() {
|
||||||
|
if (--pending > 0) return;
|
||||||
|
var finalStates = [];
|
||||||
|
for (var m = 0; m < layers.length; m++) finalStates.push(layers[m].st === 1 ? 1 : 0);
|
||||||
|
var changed = false;
|
||||||
|
for (var q = 0; q < finalStates.length; q++) if (finalStates[q] !== initStates[q]) changed = true;
|
||||||
|
if (changed) paint(finalStates);
|
||||||
|
}
|
||||||
|
|
||||||
|
setTimeout(function () { if (pending > 0) { pending = 0; onDone(); } }, 3000);
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
<nav class="uk-navbar-container uk-margin tb-navbar" uk-navbar>
|
||||||
|
<div class="uk-navbar-center">
|
||||||
|
<div class="uk-navbar-center-left">
|
||||||
|
<div>
|
||||||
|
<ul class="uk-navbar-nav">
|
||||||
|
|
||||||
|
<li><a href="/explore">探索</a></li>
|
||||||
|
|
||||||
|
|
||||||
|
<li class="tb-mobile-balancer" aria-hidden="true"><a tabindex="-1" style="visibility:hidden">マイ</a></li>
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<a class="uk-navbar-item uk-logo" href="/"><span class="emoji-placeholder" aria-label="random animal">🐺</span>の質問箱</a>
|
||||||
|
|
||||||
|
<div class="uk-navbar-center-right">
|
||||||
|
<div>
|
||||||
|
|
||||||
|
<ul class="uk-navbar-nav">
|
||||||
|
<li><a href="/register">登録</a></li>
|
||||||
|
</ul>
|
||||||
|
<ul class="uk-navbar-nav">
|
||||||
|
<li><a href="/login">ログイン</a></li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<ul class="uk-navbar-nav tb-nav-utils">
|
||||||
|
<li>
|
||||||
|
<a href="#" aria-label="言語" title="言語"><svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><circle cx="12" cy="12" r="9"/><path d="M3.2 9h17.6M3.2 15h17.6"/><ellipse cx="12" cy="12" rx="4" ry="9"/></svg></a>
|
||||||
|
<div class="uk-navbar-dropdown" uk-drop="mode: click; pos: bottom-right">
|
||||||
|
<ul class="uk-nav uk-navbar-dropdown-nav">
|
||||||
|
|
||||||
|
<li class="">
|
||||||
|
<a href="/i18n/zh-CN?to=%2F">简体中文</a>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li class="">
|
||||||
|
<a href="/i18n/zh-TW?to=%2F">繁體中文</a>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li class="">
|
||||||
|
<a href="/i18n/en?to=%2F">English</a>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li class="uk-active">
|
||||||
|
<a href="/i18n/ja?to=%2F">日本語</a>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
|
||||||
|
<ul class="uk-navbar-nav tb-nav-utils">
|
||||||
|
<li>
|
||||||
|
<a href="#" id="theme-toggle" title="ダーク/ライトモード切替" aria-label="ダーク/ライトモード切替">
|
||||||
|
<span class="tb-icon-light"><svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M20.5 14.3A8.6 8.6 0 0 1 9.7 3.5a8.6 8.6 0 1 0 10.8 10.8z"/></svg></span><span class="tb-icon-dark"><svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><circle cx="12" cy="12" r="4"/><path d="M12 2.5v2M12 19.5v2M2.5 12h2M19.5 12h2M5.2 5.2l1.4 1.4M17.4 17.4l1.4 1.4M18.8 5.2l-1.4 1.4M6.6 17.4l-1.4 1.4"/></svg></span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
document.addEventListener("DOMContentLoaded", function() {
|
||||||
|
const emojis = ["🐺","🐗","🐻","🐨","🐼","🐹","🐭","🐰","🦊","🐮","🐷","🐽","🐸","🐒","🦍","🐔","🐧","🐦","🐤","🐦⬛","🦅","🦉","🦇","🐴","🦄","🐝","🦎","🦖","🦕","🐙","🦑","🦐","🦞","🦀","🐡","🐠","🐟","🐬","🐳","🐋","🦈","🐊","🐅","🐆","🦓","🦍","🦧","🐘","🦛","🦏","🐪","🐫","🦒","🦘","🐃","🐂","🐄","🐎","🐖","🐏","🐑","🦙","🐐","🦌","🐕","🐩","🦮","🐕🦺","🐈","🐋","🐳","🐬","🐉","🐲"];
|
||||||
|
const placeholder = document.querySelector('.emoji-placeholder');
|
||||||
|
if (placeholder) {
|
||||||
|
placeholder.textContent = emojis[Math.floor(Math.random() * emojis.length)];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
<div id="tb-mobile-utils">
|
||||||
|
|
||||||
|
<select id="mobile-lang-select" class="uk-select uk-form-small" aria-label="言語">
|
||||||
|
|
||||||
|
<option value="zh-CN" >简体中文</option>
|
||||||
|
|
||||||
|
<option value="zh-TW" >繁體中文</option>
|
||||||
|
|
||||||
|
<option value="en" >English</option>
|
||||||
|
|
||||||
|
<option value="ja" selected>日本語</option>
|
||||||
|
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<button type="button" id="theme-toggle-mobile" class="uk-button uk-button-default uk-button-small"
|
||||||
|
title="ダーク/ライトモード切替" aria-label="ダーク/ライトモード切替">
|
||||||
|
<span class="tb-icon-light"><svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M20.5 14.3A8.6 8.6 0 0 1 9.7 3.5a8.6 8.6 0 1 0 10.8 10.8z"/></svg></span><span class="tb-icon-dark"><svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><circle cx="12" cy="12" r="4"/><path d="M12 2.5v2M12 19.5v2M2.5 12h2M19.5 12h2M5.2 5.2l1.4 1.4M17.4 17.4l1.4 1.4M18.8 5.2l-1.4 1.4M6.6 17.4l-1.4 1.4"/></svg></span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
(function() {
|
||||||
|
|
||||||
|
var THEME_COOKIE = 'theme';
|
||||||
|
function getTheme() {
|
||||||
|
var m = document.cookie.match(/(?:^|;\s*)theme=([^;]*)/);
|
||||||
|
return m ? m[1] : '';
|
||||||
|
}
|
||||||
|
function applyTheme(theme) {
|
||||||
|
if (theme === 'dark') {
|
||||||
|
document.documentElement.setAttribute('data-theme', 'dark');
|
||||||
|
} else {
|
||||||
|
document.documentElement.removeAttribute('data-theme');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function toggleTheme() {
|
||||||
|
var next = getTheme() === 'dark' ? 'light' : 'dark';
|
||||||
|
applyTheme(next);
|
||||||
|
var expires = new Date(Date.now() + 365 * 24 * 3600 * 1000).toUTCString();
|
||||||
|
document.cookie = THEME_COOKIE + '=' + next + '; path=/; max-age=' + (365 * 24 * 3600) + '; SameSite=Lax';
|
||||||
|
}
|
||||||
|
|
||||||
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
|
|
||||||
|
var buttons = document.querySelectorAll('#theme-toggle, #theme-toggle-mobile');
|
||||||
|
buttons.forEach(function(btn) {
|
||||||
|
btn.addEventListener('click', function(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
toggleTheme();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
var langSel = document.getElementById('mobile-lang-select');
|
||||||
|
if (langSel) {
|
||||||
|
langSel.addEventListener('change', function() {
|
||||||
|
if (!this.value) return;
|
||||||
|
var to = window.location.pathname + window.location.search;
|
||||||
|
window.location.href = '/i18n/' + encodeURIComponent(this.value) + '?to=' + encodeURIComponent(to);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
})();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
<div class="uk-container uk-container-xsmall">
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<div id="math-captcha-modal" uk-modal>
|
||||||
|
<div class="uk-modal-dialog uk-modal-body uk-text-center">
|
||||||
|
<h3 class="uk-modal-title">人機認証</h3>
|
||||||
|
<p class="uk-text-meta">以下の計算問題を解いて、ロボットでないことを証明してください</p>
|
||||||
|
<div class="captcha-equation-box">
|
||||||
|
<span id="captcha-modal-question" class="math-captcha-modal-question">読み込み中...</span>
|
||||||
|
<input type="number" id="captcha-modal-answer" placeholder="?" autocomplete="off" inputmode="numeric">
|
||||||
|
</div>
|
||||||
|
<div style="margin-top:6px;">
|
||||||
|
<button type="button" class="uk-button uk-button-text uk-text-small" id="captcha-modal-refresh">別の問題</button>
|
||||||
|
</div>
|
||||||
|
<div id="captcha-modal-error" class="uk-text-danger uk-text-small" style="display:none;min-height:20px;"></div>
|
||||||
|
<div class="uk-margin-small-top">
|
||||||
|
<button type="button" class="uk-button uk-button-primary" id="captcha-modal-submit">送信</button>
|
||||||
|
<button type="button" class="uk-button uk-button-default uk-modal-close">キャンセル</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
var CAPTCHA_I18N = {
|
||||||
|
loading: "読み込み中...",
|
||||||
|
loadFailed: "読み込み失敗",
|
||||||
|
loadRetry: "読み込み失敗、再試行してください",
|
||||||
|
inputAnswer: "答えを入力してください",
|
||||||
|
wrongAnswer: "答えが違います。もう一度計算してください",
|
||||||
|
verifyFailed: "認証失敗、再試行してください",
|
||||||
|
needPassword: "この質問箱にはパスワードが必要です",
|
||||||
|
needEmail: "通知を受け取るメールアドレスを入力してください"
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
(function() {
|
||||||
|
var captchaId = '';
|
||||||
|
var pendingForm = null;
|
||||||
|
var pendingNeedPassword = false;
|
||||||
|
var verifying = false;
|
||||||
|
|
||||||
|
function fetchCaptcha() {
|
||||||
|
var qEl = document.getElementById('captcha-modal-question');
|
||||||
|
var errEl = document.getElementById('captcha-modal-error');
|
||||||
|
var ansEl = document.getElementById('captcha-modal-answer');
|
||||||
|
qEl.textContent = CAPTCHA_I18N.loading;
|
||||||
|
fetch('/api/captcha/generate')
|
||||||
|
.then(function(r) { return r.json(); })
|
||||||
|
.then(function(data) {
|
||||||
|
if (data.code === 0 && data.data) {
|
||||||
|
captchaId = data.data.id;
|
||||||
|
qEl.textContent = data.data.question;
|
||||||
|
if (errEl) errEl.style.display = 'none';
|
||||||
|
if (ansEl) { ansEl.value = ''; ansEl.focus(); }
|
||||||
|
} else {
|
||||||
|
qEl.textContent = CAPTCHA_I18N.loadFailed;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(function() {
|
||||||
|
qEl.textContent = CAPTCHA_I18N.loadRetry;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function getCSRFToken() {
|
||||||
|
var input = document.querySelector('input[name="_csrf"]');
|
||||||
|
return input ? input.value : '';
|
||||||
|
}
|
||||||
|
|
||||||
|
function doSubmit(form) {
|
||||||
|
|
||||||
|
var ans = document.getElementById('captcha-modal-answer').value.trim();
|
||||||
|
var hidden = form.querySelector('[name="g-recaptcha-response"]');
|
||||||
|
if (hidden) hidden.value = captchaId + ':' + (ans || '0');
|
||||||
|
|
||||||
|
UIkit.modal('#math-captcha-modal').hide();
|
||||||
|
|
||||||
|
|
||||||
|
if (pendingNeedPassword) {
|
||||||
|
UIkit.modal.prompt(CAPTCHA_I18N.needPassword, '', 'password')
|
||||||
|
.then(function(password) {
|
||||||
|
if (password) {
|
||||||
|
var pwInput = document.getElementById('ask_password_input');
|
||||||
|
if (pwInput) pwInput.value = password;
|
||||||
|
form.submit();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
form.submit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
document.getElementById('captcha-modal-submit').addEventListener('click', function() {
|
||||||
|
if (verifying) return;
|
||||||
|
var ans = document.getElementById('captcha-modal-answer').value.trim();
|
||||||
|
if (!ans) {
|
||||||
|
var errEl = document.getElementById('captcha-modal-error');
|
||||||
|
errEl.textContent = CAPTCHA_I18N.inputAnswer;
|
||||||
|
errEl.style.display = 'block';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
verifying = true;
|
||||||
|
fetch('/api/captcha/verify', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'X-CSRF-Token': getCSRFToken()
|
||||||
|
},
|
||||||
|
body: JSON.stringify({ id: captchaId, answer: parseInt(ans, 10) })
|
||||||
|
})
|
||||||
|
.then(function(r) { return r.json(); })
|
||||||
|
.then(function(data) {
|
||||||
|
verifying = false;
|
||||||
|
if (data.correct) {
|
||||||
|
if (pendingForm) doSubmit(pendingForm);
|
||||||
|
} else {
|
||||||
|
var errEl = document.getElementById('captcha-modal-error');
|
||||||
|
errEl.textContent = CAPTCHA_I18N.wrongAnswer;
|
||||||
|
errEl.style.display = 'block';
|
||||||
|
fetchCaptcha();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(function() {
|
||||||
|
verifying = false;
|
||||||
|
var errEl = document.getElementById('captcha-modal-error');
|
||||||
|
errEl.textContent = CAPTCHA_I18N.verifyFailed;
|
||||||
|
errEl.style.display = 'block';
|
||||||
|
fetchCaptcha();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
document.getElementById('captcha-modal-answer').addEventListener('keydown', function(e) {
|
||||||
|
if (e.key === 'Enter') {
|
||||||
|
e.preventDefault();
|
||||||
|
document.getElementById('captcha-modal-submit').click();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
document.getElementById('captcha-modal-refresh').addEventListener('click', fetchCaptcha);
|
||||||
|
|
||||||
|
|
||||||
|
document.addEventListener('click', function(e) {
|
||||||
|
var btn = e.target.closest('.math-captcha-trigger');
|
||||||
|
if (!btn) return;
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
var form = btn.closest('form');
|
||||||
|
if (!form) return;
|
||||||
|
pendingForm = form;
|
||||||
|
|
||||||
|
|
||||||
|
pendingNeedPassword = !!(form.querySelector('#ask_password_input'));
|
||||||
|
|
||||||
|
|
||||||
|
var notifyCb = document.getElementById('notify-checkbox');
|
||||||
|
var emailInput = document.getElementById('email-input');
|
||||||
|
if (notifyCb && notifyCb.checked && emailInput && emailInput.value.trim() === '') {
|
||||||
|
UIkit.modal.alert(CAPTCHA_I18N.needEmail);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
fetchCaptcha();
|
||||||
|
UIkit.modal('#math-captcha-modal').show();
|
||||||
|
});
|
||||||
|
})();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
|
||||||
|
.tb-hero {
|
||||||
|
padding: 36px 24px 32px;
|
||||||
|
text-align: center;
|
||||||
|
background-image: linear-gradient(180deg, var(--tb-primary-weak), rgba(255, 255, 255, 0));
|
||||||
|
}
|
||||||
|
.tb-hero-title {
|
||||||
|
margin: 0;
|
||||||
|
font-size: 1.75rem;
|
||||||
|
line-height: 1.35;
|
||||||
|
font-weight: 600;
|
||||||
|
color: var(--tb-text);
|
||||||
|
}
|
||||||
|
.tb-hero-lead {
|
||||||
|
margin: 12px auto 0;
|
||||||
|
max-width: 30rem;
|
||||||
|
font-size: 0.95rem;
|
||||||
|
line-height: 1.8;
|
||||||
|
color: var(--tb-text-muted);
|
||||||
|
}
|
||||||
|
.tb-hero-actions {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 10px;
|
||||||
|
margin-top: 22px;
|
||||||
|
}
|
||||||
|
.tb-hero-actions .uk-button {
|
||||||
|
min-width: 112px;
|
||||||
|
}
|
||||||
|
.tb-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
|
||||||
|
gap: 12px;
|
||||||
|
margin-top: 12px;
|
||||||
|
}
|
||||||
|
.tb-grid .uk-card {
|
||||||
|
padding: 18px 18px 20px;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
.tb-card-title {
|
||||||
|
margin: 0 0 6px;
|
||||||
|
font-size: 0.98rem;
|
||||||
|
font-weight: 600;
|
||||||
|
color: var(--tb-text);
|
||||||
|
}
|
||||||
|
.tb-card-text {
|
||||||
|
margin: 0;
|
||||||
|
font-size: 0.86rem;
|
||||||
|
line-height: 1.7;
|
||||||
|
color: var(--tb-text-muted);
|
||||||
|
}
|
||||||
|
.tb-card-text + .tb-card-text {
|
||||||
|
margin-top: 8px;
|
||||||
|
}
|
||||||
|
.tb-card-text.tb-lead {
|
||||||
|
margin-top: 12px;
|
||||||
|
}
|
||||||
|
.tb-changelog summary + ul {
|
||||||
|
margin-top: 10px;
|
||||||
|
}
|
||||||
|
.tb-section-title {
|
||||||
|
margin: 0 0 10px;
|
||||||
|
font-size: 0.95rem;
|
||||||
|
font-weight: 600;
|
||||||
|
color: var(--tb-text);
|
||||||
|
}
|
||||||
|
.tb-notice-tag {
|
||||||
|
display: inline-block;
|
||||||
|
margin: 0 0 8px;
|
||||||
|
padding: 2px 8px;
|
||||||
|
border-radius: var(--tb-radius-xs);
|
||||||
|
background: var(--tb-primary-weak);
|
||||||
|
color: var(--tb-primary);
|
||||||
|
font-size: 0.75rem;
|
||||||
|
}
|
||||||
|
.tb-list {
|
||||||
|
margin: 0;
|
||||||
|
padding-left: 1.15em;
|
||||||
|
font-size: 0.9rem;
|
||||||
|
line-height: 1.9;
|
||||||
|
color: var(--tb-text);
|
||||||
|
}
|
||||||
|
.tb-changelog summary {
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 0.9rem;
|
||||||
|
font-weight: 600;
|
||||||
|
color: var(--tb-text);
|
||||||
|
list-style: none;
|
||||||
|
}
|
||||||
|
.tb-changelog summary::-webkit-details-marker { display: none; }
|
||||||
|
.tb-changelog summary::before {
|
||||||
|
content: "▸";
|
||||||
|
display: inline-block;
|
||||||
|
margin-right: 8px;
|
||||||
|
color: var(--tb-text-muted);
|
||||||
|
transition: transform 0.2s ease;
|
||||||
|
}
|
||||||
|
.tb-changelog[open] summary::before { transform: rotate(90deg); }
|
||||||
|
.tb-stats {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||||||
|
gap: 8px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
.tb-stat-num {
|
||||||
|
display: block;
|
||||||
|
font-size: 1.5rem;
|
||||||
|
font-weight: 600;
|
||||||
|
line-height: 1.3;
|
||||||
|
color: var(--tb-text);
|
||||||
|
}
|
||||||
|
.tb-stat-label {
|
||||||
|
display: block;
|
||||||
|
margin-top: 2px;
|
||||||
|
font-size: 0.78rem;
|
||||||
|
color: var(--tb-text-muted);
|
||||||
|
}
|
||||||
|
.tb-stats-meta {
|
||||||
|
margin: 14px 0 0;
|
||||||
|
font-size: 0.78rem;
|
||||||
|
line-height: 1.8;
|
||||||
|
color: var(--tb-text-muted);
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
@media (max-width: 480px) {
|
||||||
|
.tb-hero { padding: 28px 16px 24px; }
|
||||||
|
.tb-hero-title { font-size: 1.4rem; }
|
||||||
|
.tb-stat-num { font-size: 1.25rem; }
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<div class="uk-card uk-card-default tb-hero">
|
||||||
|
<h1 class="tb-hero-title">狼の質問箱 | 匿名質問箱</h1>
|
||||||
|
<p class="tb-hero-lead">
|
||||||
|
一个无需注册即可提问的匿名提问箱。不用下载 App,不用绑定社交账号,连邮箱都不必是真的。
|
||||||
|
</p>
|
||||||
|
<div class="tb-hero-actions">
|
||||||
|
<a href="/explore" class="uk-button uk-button-primary">探索</a>
|
||||||
|
<a href="/rules" class="uk-button uk-button-default">ルール</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="tb-grid">
|
||||||
|
<div class="uk-card uk-card-default">
|
||||||
|
<p class="tb-card-title">匿名也能问</p>
|
||||||
|
<p class="tb-card-text">不需要账号、不需要真实邮箱,打开就能写。想收到回复再留邮箱即可。</p>
|
||||||
|
</div>
|
||||||
|
<div class="uk-card uk-card-default">
|
||||||
|
<p class="tb-card-title">不止一问一答</p>
|
||||||
|
<p class="tb-card-text">问题二维码、私聊、投票、追加提问、Markdown 排版,原版没有的这里都有。</p>
|
||||||
|
</div>
|
||||||
|
<div class="uk-card uk-card-default">
|
||||||
|
<p class="tb-card-title">箱子归你</p>
|
||||||
|
<p class="tb-card-text">头像、背景、二维码配色都能自己调,还能设置审核严格度和收集时段。</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="uk-card uk-card-default uk-card-body">
|
||||||
|
<p class="tb-notice-tag">域名迁移</p>
|
||||||
|
<p class="tb-card-text">
|
||||||
|
本站已切换到 <a href="https://box.shiroko.one/">box.shiroko.one</a>,原域名将在 2026 年 12 月 24 日到期,
|
||||||
|
期间通过 301 转发指向新域名,到期后旧域名将彻底不再使用。
|
||||||
|
</p>
|
||||||
|
<p class="tb-card-text">
|
||||||
|
审核服务已切换到阿里云,审核速度提升且误伤更少;同时允许用户调整审核严格度,在不碰底线的前提下
|
||||||
|
可以设置不接受辱骂、广告等信息(即「不听坏话模式」)。
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="uk-card uk-card-default uk-card-body">
|
||||||
|
<h2 class="tb-section-title">一点提醒</h2>
|
||||||
|
<ul class="tb-list">
|
||||||
|
<li>本站唯一指定认证站长:<a href="https://box.shiroko.one/_/tamakyi">小狼</a>,注意不要被骗。</li>
|
||||||
|
<li>本站提倡友好、友善的发言,请遵守<a href="/rules">社区规则</a>。无论匿名与否,都要为自己的发言负责。</li>
|
||||||
|
<li>不允许垃圾信息、广告、辱骂、涉政、暴恐、色情、违禁、无意义、灌水提问,涉政或不良言论将直接删除。</li>
|
||||||
|
</ul>
|
||||||
|
<p class="tb-card-text tb-lead">
|
||||||
|
想先试试功能,可以到站长的提问箱
|
||||||
|
<a href="//box.shiroko.one/_/tamakyi">小狼的提问箱</a> 提问或提意见。
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<details class="uk-card uk-card-default uk-card-body tb-changelog">
|
||||||
|
<summary>近期更新</summary>
|
||||||
|
<ul class="tb-list">
|
||||||
|
<li><strong>2026.9</strong> 新增审核严格度选项,增加提问、投票、私聊的总开关,可设置定时收集、定量收集或关闭功能,前后端显示也更易用了。</li>
|
||||||
|
<li><strong>2026.8</strong> 新增<a href="https://box.shiroko.one/vote/sANyLkiBNUGN">投票功能</a>、追加提问、多语言、<a href="https://box.shiroko.one/_/tamakyi/2894">Markdown 显示</a>、置顶显示等,详情见<a href="https://blog.shiroko.one/record/tamabox_changelog_20260813">这里</a>。</li>
|
||||||
|
<li><strong>2026.8</strong> 放弃使用 recaptcha 等对国内用户不友好的验证方式,更新密码加密方式,修复图片上传等一系列问题。</li>
|
||||||
|
<li><strong>2026.5</strong> 增加私聊功能,可连续对话,详见<a href="https://blog.shiroko.one/record/tamabox-update-20260513">介绍</a>;另有提问箱卡片分享。</li>
|
||||||
|
<li><strong>2026.2</strong> 新增用户展示和标签功能,可给自己贴 5 个标签并选择是否在<a href="https://box.shiroko.one/explore">探索页</a>展示,详情见<a href="https://blog.shiroko.one/record/tamabox-tags">狼的公告板</a>。</li>
|
||||||
|
</ul>
|
||||||
|
</details>
|
||||||
|
|
||||||
|
<div class="uk-card uk-card-default uk-card-body">
|
||||||
|
<h2 class="tb-section-title">質問箱の統計</h2>
|
||||||
|
<div class="tb-stats">
|
||||||
|
<div>
|
||||||
|
<span class="tb-stat-num tb-num" data-stat="registered_users">28</span>
|
||||||
|
<span class="tb-stat-label">注册用户</span>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<span class="tb-stat-num tb-num" data-stat="total_questions">94</span>
|
||||||
|
<span class="tb-stat-label">累计提问</span>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<span class="tb-stat-num tb-num" data-stat="answered_questions">21</span>
|
||||||
|
<span class="tb-stat-label">已获回答</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<p class="tb-stats-meta">
|
||||||
|
最后提问:<span data-stat="last_question_at">2026-10-19 00:58:03</span><br>
|
||||||
|
最后回答:<span data-stat="last_answer_at">2026-10-19 02:44:47</span><br>
|
||||||
|
数据更新于:<span data-stat="updated_at">2026-10-19 12:48:26</span>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<script type="text/javascript">
|
||||||
|
|
||||||
|
|
||||||
|
document.addEventListener('DOMContentLoaded', function () {
|
||||||
|
setInterval(function () {
|
||||||
|
fetch("/api/v1/site-stats")
|
||||||
|
.then(function (r) { return r.json(); })
|
||||||
|
.then(function (resp) {
|
||||||
|
var d = resp.data;
|
||||||
|
if (!d) return;
|
||||||
|
["registered_users", "total_questions", "answered_questions",
|
||||||
|
"last_question_at", "last_answer_at", "updated_at"].forEach(function (k) {
|
||||||
|
var v = d[k];
|
||||||
|
if (v === undefined || v === null || v === "") return;
|
||||||
|
var el = document.querySelector('[data-stat="' + k + '"]');
|
||||||
|
if (el) el.textContent = v;
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.catch(function () {});
|
||||||
|
}, 30 * 60 * 1000);
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
<div id="waline"></div>
|
||||||
|
<script>
|
||||||
|
document.addEventListener('DOMContentLoaded', function () {
|
||||||
|
const waline = Waline.init({
|
||||||
|
el: '#waline',
|
||||||
|
|
||||||
|
serverURL: 'https://waline.337845818.best/',
|
||||||
|
path: window.location.href,
|
||||||
|
|
||||||
|
locale: {
|
||||||
|
nick: '昵称',
|
||||||
|
nickError: '昵称不能少于3个字符',
|
||||||
|
mail: '邮箱',
|
||||||
|
mailError: '请填写正确的邮件地址',
|
||||||
|
link: '网址',
|
||||||
|
optional: '可选',
|
||||||
|
placeholder: '欢迎评论(可以无需登录,但需要手工审核,不会立即展现)',
|
||||||
|
sofa: '来发评论吧~',
|
||||||
|
submit: '提交',
|
||||||
|
like: '喜欢',
|
||||||
|
cancelLike: '取消喜欢',
|
||||||
|
reply: '回复',
|
||||||
|
cancelReply: '取消回复',
|
||||||
|
comment: '评论',
|
||||||
|
refresh: '刷新',
|
||||||
|
more: '加载更多...',
|
||||||
|
preview: '预览',
|
||||||
|
emoji: '表情',
|
||||||
|
uploadImage: '上传图片',
|
||||||
|
seconds: '秒前',
|
||||||
|
minutes: '分钟前',
|
||||||
|
hours: '小时前',
|
||||||
|
days: '天前',
|
||||||
|
now: '刚刚',
|
||||||
|
uploading: '正在上传',
|
||||||
|
login: '登录',
|
||||||
|
logout: '退出',
|
||||||
|
admin: '博主',
|
||||||
|
sticky: '置顶',
|
||||||
|
word: '字',
|
||||||
|
wordHint: '评论字数应在 $0 到 $1 字之间!\n当前字数:$2',
|
||||||
|
anonymous: '无名小狼',
|
||||||
|
level0: '潜水',
|
||||||
|
level1: '冒泡',
|
||||||
|
level2: '吐槽',
|
||||||
|
level3: '活跃',
|
||||||
|
level4: '话痨',
|
||||||
|
level5: '传说',
|
||||||
|
gif: '表情包',
|
||||||
|
gifSearchPlaceholder: '搜索表情包',
|
||||||
|
profile: '个人资料',
|
||||||
|
approved: '通过',
|
||||||
|
waiting: '待审核',
|
||||||
|
spam: '垃圾',
|
||||||
|
unsticky: '取消置顶',
|
||||||
|
oldest: '按倒序',
|
||||||
|
latest: '按正序',
|
||||||
|
hottest: '按热度',
|
||||||
|
reactionTitle: '',
|
||||||
|
reaction0: '哇哦',
|
||||||
|
reaction1: 'prpr',
|
||||||
|
reaction2: '流汗',
|
||||||
|
reaction3: '生气',
|
||||||
|
reaction4: '流鼻血',
|
||||||
|
reaction5: 'あべ',
|
||||||
|
},
|
||||||
|
reaction: [
|
||||||
|
'https://ali-imgs.acfun.cn/kimg/bs2/zt-image-host/ChYwOGQ3OTRhYzRjMTBkZmZhZDVmZTA1EIjM1y8.gif',
|
||||||
|
'https://ali-imgs.acfun.cn/kimg/bs2/zt-image-host/ChQwOGEyOTlhYzRjMTBmOWFkZjAwYRCIzNcv.gif',
|
||||||
|
'https://ali-imgs.acfun.cn/kimg/bs2/zt-image-host/ChYwOGRhOTVhYzRjMTBkNmViYTVlNTA2EIjM1y8.gif',
|
||||||
|
'https://ali-imgs.acfun.cn/kimg/bs2/zt-image-host/ChYwOGU1OTJhYzRjMTBmMzk3ZmVmNTAyEIjM1y8.gif',
|
||||||
|
'https://ali-imgs.acfun.cn/kimg/bs2/zt-image-host/ChYwOGNkODdhYzRjMTBjYmEwOTFjNjAxEIjM1y8.gif',
|
||||||
|
'https://ali-imgs.acfun.cn/kimg/bs2/zt-image-host/ChQwODliOGVhYzRjMTBmOGM0ZWY1ZRCIzNcv.gif',
|
||||||
|
],
|
||||||
|
meta: ['nick','mail'],
|
||||||
|
requiredMeta: ['mail'],
|
||||||
|
pageview: true,
|
||||||
|
search: false,
|
||||||
|
login: 'enable',
|
||||||
|
wordLimit: 50,
|
||||||
|
pageSize: 5,
|
||||||
|
avatar: 'identicon',
|
||||||
|
emoji: [
|
||||||
|
'https://gcore.jsdelivr.net/gh/tamakyi/emoji-collection@main/acfun-color/60x60',
|
||||||
|
],
|
||||||
|
|
||||||
|
imageUploader: false,
|
||||||
|
|
||||||
|
copyright: false,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
<p class=" uk-text-right uk-text-muted uk-text-small">
|
||||||
|
<br>
|
||||||
|
<a href="/rules">ルール</a> |
|
||||||
|
|
||||||
|
<a href="https://box.shiroko.one/_/tamakyi" target="_blank">管理者へ</a>
|
||||||
|
<br>
|
||||||
|
<a href="https://share.shiroko.one" target="_blank">ドライブ</a>
|
||||||
|
| <a href="https://blog.shiroko.one" target="_blank">お知らせ</a>
|
||||||
|
| <a href="https://chat.shiroko.one" target="_blank">チャット</a>
|
||||||
|
| <a href="https://status.shiroko.one" target="_blank">ステータス</a>
|
||||||
|
| <a href="https://shiroko.one" target="_blank">リンク</a>
|
||||||
|
<br>Powered by NekoBox | 狼ICP备 20230101
|
||||||
|
<br>質問箱は稼働中:<span id="box_runtime"></span>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
(function () {
|
||||||
|
var create = Math.round(Date.UTC(2023, 6, 1, 18, 15, 43) / 1000);
|
||||||
|
function tick() {
|
||||||
|
var el = document.getElementById("box_runtime");
|
||||||
|
if (!el) return;
|
||||||
|
var s = Math.round((Date.now() + 8 * 3600 * 1000) / 1000) - create;
|
||||||
|
var t = [0, 0, 0, 0, 0];
|
||||||
|
if (s >= 31536000) { t[0] = s / 31536000 | 0; s %= 31536000; }
|
||||||
|
if (s >= 86400) { t[1] = s / 86400 | 0; s %= 86400; }
|
||||||
|
if (s >= 3600) { t[2] = s / 3600 | 0; s %= 3600; }
|
||||||
|
if (s >= 60) { t[3] = s / 60 | 0; s %= 60; }
|
||||||
|
if (s > 0) { t[4] = s; }
|
||||||
|
el.innerHTML = t[0] + '年 ' + t[1] + '天 ' + t[2] + '时 ' + t[3] + '分 ' + t[4] + '秒 ';
|
||||||
|
}
|
||||||
|
tick();
|
||||||
|
setInterval(tick, 1000);
|
||||||
|
})();
|
||||||
|
</script>
|
||||||
|
<br>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
var SUBMIT_I18N = {
|
||||||
|
submitting: '送信中...',
|
||||||
|
uploading: 'アップロード中...'
|
||||||
|
};
|
||||||
|
|
||||||
|
function tbResetSubmitButtons() {
|
||||||
|
document.querySelectorAll('button[data-tb-submitting]').forEach(function(b) {
|
||||||
|
b.disabled = false;
|
||||||
|
b.removeAttribute('data-tb-submitting');
|
||||||
|
var orig = b.getAttribute('data-tb-restore');
|
||||||
|
if (orig !== null) {
|
||||||
|
b.innerHTML = orig;
|
||||||
|
b.removeAttribute('data-tb-restore');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
document.addEventListener('submit', function(e) {
|
||||||
|
var form = e.target;
|
||||||
|
if (!form || form.tagName !== 'FORM') return;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if (e.defaultPrevented || form.getAttribute('data-tb-skip-submit-feedback') === '1') {
|
||||||
|
form.removeAttribute('data-tb-skip-submit-feedback');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if (form.getAttribute('target') === '_blank') return;
|
||||||
|
|
||||||
|
|
||||||
|
var trigger = e.submitter || form.querySelector('button[type="submit"]');
|
||||||
|
|
||||||
|
|
||||||
|
var hasFile = false;
|
||||||
|
form.querySelectorAll('input[type="file"]').forEach(function(f) {
|
||||||
|
if (f.files && f.files.length > 0) hasFile = true;
|
||||||
|
});
|
||||||
|
var label = hasFile ? SUBMIT_I18N.uploading : SUBMIT_I18N.submitting;
|
||||||
|
|
||||||
|
if (trigger && trigger.tagName === 'BUTTON') {
|
||||||
|
trigger.setAttribute('data-tb-restore', trigger.innerHTML);
|
||||||
|
trigger.innerHTML = '<span uk-spinner="ratio: 0.6"></span> ' + label;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
form.querySelectorAll('button').forEach(function(b) {
|
||||||
|
b.disabled = true;
|
||||||
|
b.setAttribute('data-tb-submitting', '1');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
window.addEventListener('pageshow', tbResetSubmitButtons);
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,854 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<title>预览:测试</title>
|
||||||
|
<meta name="msvalidate.01" content="2F185E8E63C93635F50B3574F3B31E42" />
|
||||||
|
<meta name="description" content="狼的提问箱——一个无需注册、可匿名提问的匿名提问箱,安全地倾诉与回应。">
|
||||||
|
<meta name="keywords" content="匿名提问箱,提问箱,匿名提问,狼的提问箱,匿名问答,匿名提问网站">
|
||||||
|
|
||||||
|
<script>
|
||||||
|
(function () {
|
||||||
|
var m = document.cookie.match(/(?:^|;\s*)theme=([^;]*)/);
|
||||||
|
if (m && m[1] === 'dark') document.documentElement.setAttribute('data-theme', 'dark');
|
||||||
|
})();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<link rel="preconnect" href="https://r2.337845818.best" crossorigin>
|
||||||
|
<link rel="preconnect" href="https://cdnjs.snrat.com" crossorigin>
|
||||||
|
|
||||||
|
<link rel="stylesheet" href="https://cdnjs.snrat.com/ajax/libs/uikit/3.3.3/css/uikit.min.css"/>
|
||||||
|
|
||||||
|
<link rel="stylesheet" href="/static/css/base.css?v=20261019d"/>
|
||||||
|
|
||||||
|
<link rel="stylesheet" href="https://r2.337845818.best/tamabox/cdn/waline/client/v2/waline-no-commits.css" media="print" onload="this.media='all'"/>
|
||||||
|
<script defer src="https://cdnjs.snrat.com/ajax/libs/uikit/3.3.3/js/uikit.min.js"></script>
|
||||||
|
<script defer src="https://cdnjs.snrat.com/ajax/libs/uikit/3.3.3/js/uikit-icons.min.js"></script>
|
||||||
|
|
||||||
|
<script defer src="https://cdnjs.snrat.com/ajax/libs/dayjs/1.10.8/dayjs.min.js"></script>
|
||||||
|
<script defer src="https://cdnjs.snrat.com/ajax/libs/alpinejs/3.9.0/cdn.min.js"></script>
|
||||||
|
|
||||||
|
|
||||||
|
<script defer src="https://cdnjs.snrat.com/ajax/libs/waline/2.15.8/waline.js"></script>
|
||||||
|
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.captcha-equation-box {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
background: #f0f2f5;
|
||||||
|
border: 1px solid #dcdcdc;
|
||||||
|
border-radius: 8px;
|
||||||
|
padding: 8px 8px 8px 16px;
|
||||||
|
gap: 6px;
|
||||||
|
transition: border-color 0.2s;
|
||||||
|
}
|
||||||
|
.captcha-equation-box:focus-within {
|
||||||
|
border-color: #1e87f0;
|
||||||
|
box-shadow: 0 0 0 3px rgba(30,135,240,0.12);
|
||||||
|
}
|
||||||
|
.math-captcha-modal-question {
|
||||||
|
font-size: 1.4rem;
|
||||||
|
font-family: "Courier New", monospace;
|
||||||
|
font-weight: 700;
|
||||||
|
color: #333;
|
||||||
|
letter-spacing: 1px;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
#captcha-modal-answer {
|
||||||
|
width: 80px;
|
||||||
|
padding: 6px 10px;
|
||||||
|
text-align: center;
|
||||||
|
font-size: 1.2rem;
|
||||||
|
font-family: "Courier New", monospace;
|
||||||
|
font-weight: 600;
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
border-radius: 5px;
|
||||||
|
outline: none;
|
||||||
|
transition: border-color 0.15s, box-shadow 0.15s;
|
||||||
|
background: #fff;
|
||||||
|
}
|
||||||
|
#captcha-modal-answer:focus {
|
||||||
|
border-color: #1e87f0;
|
||||||
|
box-shadow: 0 0 0 2px rgba(30,135,240,0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
#captcha-modal-answer::-webkit-inner-spin-button,
|
||||||
|
#captcha-modal-answer::-webkit-outer-spin-button {
|
||||||
|
-webkit-appearance: none;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
#captcha-modal-answer {
|
||||||
|
-moz-appearance: textfield;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<meta property="og:site_name" content="狼的提问箱 | 匿名提问箱" />
|
||||||
|
<meta property="og:type" content="website" />
|
||||||
|
<meta property="og:title" content=" - 狼的提问箱 | 匿名提问箱" />
|
||||||
|
<meta property="og:url" content="https://box-dev-api.337845818.best/user/votes/10/preview" />
|
||||||
|
<meta property="og:description" content=" - 狼的提问箱——一个无需注册、可匿名提问的匿名提问箱,安全地倾诉与回应。" />
|
||||||
|
<meta name="robots" content="noindex">
|
||||||
|
|
||||||
|
<meta property="og:image" content="?og-image=1" />
|
||||||
|
<meta property="og:image:alt" content="" />
|
||||||
|
<meta itemprop="image" content="?og-image=1"/>
|
||||||
|
<meta name="msapplication-TileImage" content=""/>
|
||||||
|
<link rel="shortcut icon" href="?og-image=1"/>
|
||||||
|
<link rel="apple-touch-icon" href="?og-image=1"/>
|
||||||
|
<link rel="icon" sizes="192x192" href="?og-image=1">
|
||||||
|
<meta name="twitter:image:src" content="?og-image=1" />
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<meta name="google-site-verification" content="fEPwRRJfiGsgwc5SINBQwZhPK8F0cwRaOvRx0YRurI4" />
|
||||||
|
|
||||||
|
<script>
|
||||||
|
window.addEventListener("load", function () {
|
||||||
|
var s = document.createElement("script");
|
||||||
|
s.src = "https://mami.shiroko.one/tamami.js";
|
||||||
|
s.setAttribute("data-website-id", "c42ebe8b-9281-4da0-83a4-8f18b3e710fe");
|
||||||
|
document.body.appendChild(s);
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<script>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
window.tbRenderQR = function (el, getOptions) {
|
||||||
|
if (!el || typeof QRCode === 'undefined') return;
|
||||||
|
var opts = getOptions();
|
||||||
|
function remoteOf(o, key) {
|
||||||
|
var v = o[key];
|
||||||
|
return (typeof v === 'string' && v.indexOf('http') === 0) ? v : '';
|
||||||
|
}
|
||||||
|
var good = window._tbQrGood || (window._tbQrGood = {});
|
||||||
|
var bad = window._tbQrBad || (window._tbQrBad = {});
|
||||||
|
|
||||||
|
function layerState(url) { return !url ? '' : (good[url] ? 1 : (bad[url] ? 0 : null)); }
|
||||||
|
var layers = [
|
||||||
|
{ url: remoteOf(opts, 'logo'), st: null, present: function (o, on) {
|
||||||
|
if (on) { } else { o.logo = undefined; o.logoWidth = undefined; o.logoHeight = undefined; o.logoBackgroundTransparent = undefined; }
|
||||||
|
} },
|
||||||
|
{ url: remoteOf(opts, 'backgroundImage'), st: null, present: function (o, on) {
|
||||||
|
if (on) { } else { o.backgroundImage = undefined; o.backgroundImageAlpha = undefined; }
|
||||||
|
} }
|
||||||
|
];
|
||||||
|
var needProbe = false;
|
||||||
|
for (var i = 0; i < layers.length; i++) {
|
||||||
|
layers[i].st = layerState(layers[i].url);
|
||||||
|
if (layers[i].st === null) needProbe = true;
|
||||||
|
}
|
||||||
|
function paint(states) {
|
||||||
|
var o = {};
|
||||||
|
for (var k in opts) o[k] = opts[k];
|
||||||
|
for (var j = 0; j < layers.length; j++) layers[j].present(o, states[j] === 1);
|
||||||
|
el.innerHTML = '';
|
||||||
|
new QRCode(el, o);
|
||||||
|
}
|
||||||
|
|
||||||
|
var initStates = [];
|
||||||
|
for (var n = 0; n < layers.length; n++) initStates.push(layers[n].st === 1 ? 1 : 0);
|
||||||
|
paint(initStates);
|
||||||
|
if (!needProbe) return;
|
||||||
|
|
||||||
|
var pending = 0, cross = opts.crossOrigin || 'anonymous';
|
||||||
|
layers.forEach(function (L) {
|
||||||
|
if (L.st !== null) return;
|
||||||
|
pending++;
|
||||||
|
var im = new Image();
|
||||||
|
im.onload = function () { good[L.url] = true; L.st = 1; onDone(); };
|
||||||
|
im.onerror = function () { bad[L.url] = true; L.st = 0; onDone(); };
|
||||||
|
if (cross) im.crossOrigin = cross;
|
||||||
|
im.src = L.url;
|
||||||
|
});
|
||||||
|
function onDone() {
|
||||||
|
if (--pending > 0) return;
|
||||||
|
var finalStates = [];
|
||||||
|
for (var m = 0; m < layers.length; m++) finalStates.push(layers[m].st === 1 ? 1 : 0);
|
||||||
|
var changed = false;
|
||||||
|
for (var q = 0; q < finalStates.length; q++) if (finalStates[q] !== initStates[q]) changed = true;
|
||||||
|
if (changed) paint(finalStates);
|
||||||
|
}
|
||||||
|
|
||||||
|
setTimeout(function () { if (pending > 0) { pending = 0; onDone(); } }, 3000);
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
<nav class="uk-navbar-container uk-margin tb-navbar" uk-navbar>
|
||||||
|
<div class="uk-navbar-center">
|
||||||
|
<div class="uk-navbar-center-left">
|
||||||
|
<div>
|
||||||
|
<ul class="uk-navbar-nav">
|
||||||
|
|
||||||
|
<li><a href="/explore">探索</a></li>
|
||||||
|
|
||||||
|
|
||||||
|
<li><a href="/_/admin6">我的</a></li>
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<a class="uk-navbar-item uk-logo" href="/"><span class="emoji-placeholder" aria-label="random animal">🐺</span>的提问箱</a>
|
||||||
|
|
||||||
|
<div class="uk-navbar-center-right">
|
||||||
|
<div>
|
||||||
|
|
||||||
|
<ul class="uk-navbar-nav">
|
||||||
|
<li><a href="/user/questions">提问</a></li>
|
||||||
|
</ul>
|
||||||
|
<ul class="uk-navbar-nav">
|
||||||
|
<li><a href="/user/profile">设置</a></li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<ul class="uk-navbar-nav tb-nav-utils">
|
||||||
|
<li>
|
||||||
|
<a href="#" id="theme-toggle" title="切换深色/浅色模式" aria-label="切换深色/浅色模式">
|
||||||
|
<span class="tb-icon-light"><svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M20.5 14.3A8.6 8.6 0 0 1 9.7 3.5a8.6 8.6 0 1 0 10.8 10.8z"/></svg></span><span class="tb-icon-dark"><svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><circle cx="12" cy="12" r="4"/><path d="M12 2.5v2M12 19.5v2M2.5 12h2M19.5 12h2M5.2 5.2l1.4 1.4M17.4 17.4l1.4 1.4M18.8 5.2l-1.4 1.4M6.6 17.4l-1.4 1.4"/></svg></span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
document.addEventListener("DOMContentLoaded", function() {
|
||||||
|
const emojis = ["🐺","🐗","🐻","🐨","🐼","🐹","🐭","🐰","🦊","🐮","🐷","🐽","🐸","🐒","🦍","🐔","🐧","🐦","🐤","🐦⬛","🦅","🦉","🦇","🐴","🦄","🐝","🦎","🦖","🦕","🐙","🦑","🦐","🦞","🦀","🐡","🐠","🐟","🐬","🐳","🐋","🦈","🐊","🐅","🐆","🦓","🦍","🦧","🐘","🦛","🦏","🐪","🐫","🦒","🦘","🐃","🐂","🐄","🐎","🐖","🐏","🐑","🦙","🐐","🦌","🐕","🐩","🦮","🐕🦺","🐈","🐋","🐳","🐬","🐉","🐲"];
|
||||||
|
const placeholder = document.querySelector('.emoji-placeholder');
|
||||||
|
if (placeholder) {
|
||||||
|
placeholder.textContent = emojis[Math.floor(Math.random() * emojis.length)];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
<div id="tb-mobile-utils">
|
||||||
|
|
||||||
|
<button type="button" id="theme-toggle-mobile" class="uk-button uk-button-default uk-button-small"
|
||||||
|
title="切换深色/浅色模式" aria-label="切换深色/浅色模式">
|
||||||
|
<span class="tb-icon-light"><svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M20.5 14.3A8.6 8.6 0 0 1 9.7 3.5a8.6 8.6 0 1 0 10.8 10.8z"/></svg></span><span class="tb-icon-dark"><svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><circle cx="12" cy="12" r="4"/><path d="M12 2.5v2M12 19.5v2M2.5 12h2M19.5 12h2M5.2 5.2l1.4 1.4M17.4 17.4l1.4 1.4M18.8 5.2l-1.4 1.4M6.6 17.4l-1.4 1.4"/></svg></span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
(function() {
|
||||||
|
|
||||||
|
var THEME_COOKIE = 'theme';
|
||||||
|
function getTheme() {
|
||||||
|
var m = document.cookie.match(/(?:^|;\s*)theme=([^;]*)/);
|
||||||
|
return m ? m[1] : '';
|
||||||
|
}
|
||||||
|
function applyTheme(theme) {
|
||||||
|
if (theme === 'dark') {
|
||||||
|
document.documentElement.setAttribute('data-theme', 'dark');
|
||||||
|
} else {
|
||||||
|
document.documentElement.removeAttribute('data-theme');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function toggleTheme() {
|
||||||
|
var next = getTheme() === 'dark' ? 'light' : 'dark';
|
||||||
|
applyTheme(next);
|
||||||
|
var expires = new Date(Date.now() + 365 * 24 * 3600 * 1000).toUTCString();
|
||||||
|
document.cookie = THEME_COOKIE + '=' + next + '; path=/; max-age=' + (365 * 24 * 3600) + '; SameSite=Lax';
|
||||||
|
}
|
||||||
|
|
||||||
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
|
|
||||||
|
var buttons = document.querySelectorAll('#theme-toggle, #theme-toggle-mobile');
|
||||||
|
buttons.forEach(function(btn) {
|
||||||
|
btn.addEventListener('click', function(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
toggleTheme();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
var langSel = document.getElementById('mobile-lang-select');
|
||||||
|
if (langSel) {
|
||||||
|
langSel.addEventListener('change', function() {
|
||||||
|
if (!this.value) return;
|
||||||
|
var to = window.location.pathname + window.location.search;
|
||||||
|
window.location.href = '/i18n/' + encodeURIComponent(this.value) + '?to=' + encodeURIComponent(to);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
})();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
<div class="uk-container uk-container-xsmall">
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<div id="math-captcha-modal" uk-modal>
|
||||||
|
<div class="uk-modal-dialog uk-modal-body uk-text-center">
|
||||||
|
<h3 class="uk-modal-title">人机验证</h3>
|
||||||
|
<p class="uk-text-meta">请计算下方的算术题以验证你不是机器人</p>
|
||||||
|
<div class="captcha-equation-box">
|
||||||
|
<span id="captcha-modal-question" class="math-captcha-modal-question">加载中...</span>
|
||||||
|
<input type="number" id="captcha-modal-answer" placeholder="?" autocomplete="off" inputmode="numeric">
|
||||||
|
</div>
|
||||||
|
<div style="margin-top:6px;">
|
||||||
|
<button type="button" class="uk-button uk-button-text uk-text-small" id="captcha-modal-refresh">换一题</button>
|
||||||
|
</div>
|
||||||
|
<div id="captcha-modal-error" class="uk-text-danger uk-text-small" style="display:none;min-height:20px;"></div>
|
||||||
|
<div class="uk-margin-small-top">
|
||||||
|
<button type="button" class="uk-button uk-button-primary" id="captcha-modal-submit">提交</button>
|
||||||
|
<button type="button" class="uk-button uk-button-default uk-modal-close">取消</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
var CAPTCHA_I18N = {
|
||||||
|
loading: "加载中...",
|
||||||
|
loadFailed: "加载失败",
|
||||||
|
loadRetry: "加载失败,请重试",
|
||||||
|
inputAnswer: "请输入答案",
|
||||||
|
wrongAnswer: "答案错误,请重新计算",
|
||||||
|
verifyFailed: "验证失败,请重试",
|
||||||
|
needPassword: "此提问箱需要密码",
|
||||||
|
needEmail: "请填写接收通知的邮箱地址"
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
(function() {
|
||||||
|
var captchaId = '';
|
||||||
|
var pendingForm = null;
|
||||||
|
var pendingNeedPassword = false;
|
||||||
|
var verifying = false;
|
||||||
|
|
||||||
|
function fetchCaptcha() {
|
||||||
|
var qEl = document.getElementById('captcha-modal-question');
|
||||||
|
var errEl = document.getElementById('captcha-modal-error');
|
||||||
|
var ansEl = document.getElementById('captcha-modal-answer');
|
||||||
|
qEl.textContent = CAPTCHA_I18N.loading;
|
||||||
|
fetch('/api/captcha/generate')
|
||||||
|
.then(function(r) { return r.json(); })
|
||||||
|
.then(function(data) {
|
||||||
|
if (data.code === 0 && data.data) {
|
||||||
|
captchaId = data.data.id;
|
||||||
|
qEl.textContent = data.data.question;
|
||||||
|
if (errEl) errEl.style.display = 'none';
|
||||||
|
if (ansEl) { ansEl.value = ''; ansEl.focus(); }
|
||||||
|
} else {
|
||||||
|
qEl.textContent = CAPTCHA_I18N.loadFailed;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(function() {
|
||||||
|
qEl.textContent = CAPTCHA_I18N.loadRetry;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function getCSRFToken() {
|
||||||
|
var input = document.querySelector('input[name="_csrf"]');
|
||||||
|
return input ? input.value : '';
|
||||||
|
}
|
||||||
|
|
||||||
|
function doSubmit(form) {
|
||||||
|
|
||||||
|
var ans = document.getElementById('captcha-modal-answer').value.trim();
|
||||||
|
var hidden = form.querySelector('[name="g-recaptcha-response"]');
|
||||||
|
if (hidden) hidden.value = captchaId + ':' + (ans || '0');
|
||||||
|
|
||||||
|
UIkit.modal('#math-captcha-modal').hide();
|
||||||
|
|
||||||
|
|
||||||
|
if (pendingNeedPassword) {
|
||||||
|
UIkit.modal.prompt(CAPTCHA_I18N.needPassword, '', 'password')
|
||||||
|
.then(function(password) {
|
||||||
|
if (password) {
|
||||||
|
var pwInput = document.getElementById('ask_password_input');
|
||||||
|
if (pwInput) pwInput.value = password;
|
||||||
|
form.submit();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
form.submit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
document.getElementById('captcha-modal-submit').addEventListener('click', function() {
|
||||||
|
if (verifying) return;
|
||||||
|
var ans = document.getElementById('captcha-modal-answer').value.trim();
|
||||||
|
if (!ans) {
|
||||||
|
var errEl = document.getElementById('captcha-modal-error');
|
||||||
|
errEl.textContent = CAPTCHA_I18N.inputAnswer;
|
||||||
|
errEl.style.display = 'block';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
verifying = true;
|
||||||
|
fetch('/api/captcha/verify', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'X-CSRF-Token': getCSRFToken()
|
||||||
|
},
|
||||||
|
body: JSON.stringify({ id: captchaId, answer: parseInt(ans, 10) })
|
||||||
|
})
|
||||||
|
.then(function(r) { return r.json(); })
|
||||||
|
.then(function(data) {
|
||||||
|
verifying = false;
|
||||||
|
if (data.correct) {
|
||||||
|
if (pendingForm) doSubmit(pendingForm);
|
||||||
|
} else {
|
||||||
|
var errEl = document.getElementById('captcha-modal-error');
|
||||||
|
errEl.textContent = CAPTCHA_I18N.wrongAnswer;
|
||||||
|
errEl.style.display = 'block';
|
||||||
|
fetchCaptcha();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(function() {
|
||||||
|
verifying = false;
|
||||||
|
var errEl = document.getElementById('captcha-modal-error');
|
||||||
|
errEl.textContent = CAPTCHA_I18N.verifyFailed;
|
||||||
|
errEl.style.display = 'block';
|
||||||
|
fetchCaptcha();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
document.getElementById('captcha-modal-answer').addEventListener('keydown', function(e) {
|
||||||
|
if (e.key === 'Enter') {
|
||||||
|
e.preventDefault();
|
||||||
|
document.getElementById('captcha-modal-submit').click();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
document.getElementById('captcha-modal-refresh').addEventListener('click', fetchCaptcha);
|
||||||
|
|
||||||
|
|
||||||
|
document.addEventListener('click', function(e) {
|
||||||
|
var btn = e.target.closest('.math-captcha-trigger');
|
||||||
|
if (!btn) return;
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
var form = btn.closest('form');
|
||||||
|
if (!form) return;
|
||||||
|
pendingForm = form;
|
||||||
|
|
||||||
|
|
||||||
|
pendingNeedPassword = !!(form.querySelector('#ask_password_input'));
|
||||||
|
|
||||||
|
|
||||||
|
var notifyCb = document.getElementById('notify-checkbox');
|
||||||
|
var emailInput = document.getElementById('email-input');
|
||||||
|
if (notifyCb && notifyCb.checked && emailInput && emailInput.value.trim() === '') {
|
||||||
|
UIkit.modal.alert(CAPTCHA_I18N.needEmail);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
fetchCaptcha();
|
||||||
|
UIkit.modal('#math-captcha-modal').show();
|
||||||
|
});
|
||||||
|
})();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
<style>
|
||||||
|
|
||||||
|
.tb-field-head {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
align-items: center;
|
||||||
|
gap: 6px 8px;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
.tb-field-head .tb-field-label {
|
||||||
|
flex-basis: 100%;
|
||||||
|
font-weight: 600;
|
||||||
|
line-height: 1.5;
|
||||||
|
word-break: break-word;
|
||||||
|
overflow-wrap: anywhere;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tb-choice {
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-start;
|
||||||
|
gap: 10px;
|
||||||
|
padding: 12px 14px;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
border: 1px solid var(--tb-border);
|
||||||
|
border-radius: 8px;
|
||||||
|
background: var(--tb-surface);
|
||||||
|
cursor: pointer;
|
||||||
|
transition: border-color 0.2s ease, background 0.2s ease;
|
||||||
|
}
|
||||||
|
.tb-choice:last-child { margin-bottom: 0; }
|
||||||
|
.tb-choice input[type="radio"], .tb-choice input[type="checkbox"] {
|
||||||
|
margin-top: 3px;
|
||||||
|
}
|
||||||
|
.tb-choice span {
|
||||||
|
flex: 1;
|
||||||
|
min-width: 0;
|
||||||
|
line-height: 1.5;
|
||||||
|
word-break: break-word;
|
||||||
|
overflow-wrap: anywhere;
|
||||||
|
}
|
||||||
|
.tb-choice:hover {
|
||||||
|
border-color: var(--tb-primary);
|
||||||
|
background: var(--tb-surface-hover);
|
||||||
|
}
|
||||||
|
.tb-choice:has(input:checked) {
|
||||||
|
border-color: var(--tb-primary);
|
||||||
|
background: var(--tb-surface-active);
|
||||||
|
}
|
||||||
|
html[data-theme="dark"] .tb-choice {
|
||||||
|
border-color: var(--tb-border);
|
||||||
|
background: var(--tb-surface);
|
||||||
|
}
|
||||||
|
html[data-theme="dark"] .tb-choice:hover {
|
||||||
|
border-color: var(--tb-primary);
|
||||||
|
background: rgba(78, 168, 245, 0.08);
|
||||||
|
}
|
||||||
|
html[data-theme="dark"] .tb-choice:has(input:checked) {
|
||||||
|
border-color: var(--tb-primary);
|
||||||
|
background: rgba(78, 168, 245, 0.14);
|
||||||
|
}
|
||||||
|
|
||||||
|
.tb-custom-input {
|
||||||
|
margin-top: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tb-text-counter {
|
||||||
|
margin-top: 2px;
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
@media (max-width: 480px) {
|
||||||
|
.tb-choice { padding: 10px 12px; }
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<div class="uk-card uk-card-default uk-card-body uk-margin-bottom">
|
||||||
|
<div class="uk-flex uk-flex-middle uk-margin-small-bottom" style="gap: 10px;">
|
||||||
|
|
||||||
|
<img class="uk-border-circle" src="https://r2.337845818.best/tamabox/picture/2026/08/19/9af3e38222d972ff9141e9cfdb0475" style="width: 40px; height: 40px;">
|
||||||
|
<div>
|
||||||
|
<a class="uk-text-bold" href="/_admin6">admin6</a>
|
||||||
|
<div class="uk-text-meta uk-text-small">发起的投票</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="uk-margin-auto-left">
|
||||||
|
|
||||||
|
|
||||||
|
<span class="uk-label uk-label-success">进行中</span>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h3 class="uk-margin-remove-top uk-margin-small-bottom">测试</h3>
|
||||||
|
|
||||||
|
<p class="uk-margin-remove-top">测试</p>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<div class="uk-alert uk-alert-warning">预览模式:这是发布前的页面样例,提交已禁用</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<div class="uk-alert uk-alert-primary uk-text-small">该投票允许匿名参与,你的身份不会被记录(同一设备最多可参与 1 次)。</div>
|
||||||
|
|
||||||
|
|
||||||
|
<form method="post" action="/vote/wgaMjcwQJFhL/submit" id="vote-form">
|
||||||
|
<input type="hidden" name="_csrf" value="Tj0N6dXdjpejP3JANEKdlPVFyus6MTc5MjM4NTM0MjE2NTQxMDMzMQ">
|
||||||
|
<input type="hidden" name="g-recaptcha-response" id="g-recaptcha-response" value="">
|
||||||
|
|
||||||
|
<div class="uk-card uk-card-default uk-card-body uk-margin-bottom">
|
||||||
|
|
||||||
|
|
||||||
|
<div class="uk-margin">
|
||||||
|
<div class="tb-field-head">
|
||||||
|
<span class="tb-chip">1</span>
|
||||||
|
<span class="tb-chip">多行文本</span>
|
||||||
|
<div class="tb-field-label">测是</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<textarea class="uk-textarea" rows="3" name="field_22" ></textarea>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="uk-margin">
|
||||||
|
|
||||||
|
<button type="button" class="uk-button uk-button-primary" disabled>提交投票</button>
|
||||||
|
<span class="uk-text-meta uk-text-small uk-margin-small-left">预览模式,发布后即可提交</span>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<div class="uk-margin-top uk-text-small">
|
||||||
|
<a href="/user/votes/10/results">管理此投票(仅你可见结果)</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<script>
|
||||||
|
|
||||||
|
|
||||||
|
var MAX_CUSTOM_LEN = null ;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
function countChars(s) { return Array.from(String(s || '')).length; }
|
||||||
|
|
||||||
|
|
||||||
|
function setupTextCounters() {
|
||||||
|
var form = document.getElementById('vote-form');
|
||||||
|
if (!form) { return; }
|
||||||
|
form.querySelectorAll('[data-tb-text-counter]').forEach(function (input) {
|
||||||
|
var max = parseInt(input.getAttribute('data-tb-text-max'), 10);
|
||||||
|
if (!max || max < 1) { max = MAX_CUSTOM_LEN; }
|
||||||
|
var counter = document.createElement('div');
|
||||||
|
counter.className = 'uk-text-meta uk-text-small tb-text-counter';
|
||||||
|
if (input.parentNode) { input.parentNode.insertBefore(counter, input.nextSibling); }
|
||||||
|
var update = function () {
|
||||||
|
var n = countChars(input.value);
|
||||||
|
counter.textContent = n + ' / ' + max;
|
||||||
|
if (n > max) {
|
||||||
|
counter.classList.add('uk-text-danger');
|
||||||
|
input.setAttribute('data-tb-too-long', '1');
|
||||||
|
} else {
|
||||||
|
counter.classList.remove('uk-text-danger');
|
||||||
|
input.removeAttribute('data-tb-too-long');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
input.addEventListener('input', update);
|
||||||
|
update();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
function validateVoteForm() {
|
||||||
|
var form = document.getElementById('vote-form');
|
||||||
|
if (!form) { return true; }
|
||||||
|
|
||||||
|
var tooLong = form.querySelector('[data-tb-text-counter][data-tb-too-long]');
|
||||||
|
if (tooLong) {
|
||||||
|
alert('自定义选项不能超过 %!d(\u003cnil\u003e) 字');
|
||||||
|
tooLong.focus();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
var groups = {};
|
||||||
|
form.querySelectorAll('input[data-vote-required][type="radio"], input[data-vote-required][type="checkbox"]').forEach(function (el) {
|
||||||
|
(groups[el.name] = groups[el.name] || []).push(el);
|
||||||
|
});
|
||||||
|
for (var name in groups) {
|
||||||
|
var any = groups[name].some(function (el) { return el.checked; });
|
||||||
|
if (!any) {
|
||||||
|
alert('请完成「' + groups[name][0].getAttribute('data-vote-label') + '」');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var els = form.querySelectorAll('[data-vote-required]:not(input[type="radio"]):not(input[type="checkbox"])');
|
||||||
|
for (var i = 0; i < els.length; i++) {
|
||||||
|
var el = els[i];
|
||||||
|
if (el.disabled) { continue; }
|
||||||
|
if ((el.value || '').trim() === '') {
|
||||||
|
alert('请完成「' + el.getAttribute('data-vote-label') + '」');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function voteValidate(e) {
|
||||||
|
if (!validateVoteForm()) {
|
||||||
|
if (e) { e.stopPropagation(); e.preventDefault(); }
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function onSubmit() {
|
||||||
|
if (validateVoteForm()) {
|
||||||
|
document.getElementById('vote-form').submit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
(function () {
|
||||||
|
var form = document.getElementById('vote-form');
|
||||||
|
if (!form) { return; }
|
||||||
|
setupTextCounters();
|
||||||
|
var maxChoices = 0;
|
||||||
|
if (maxChoices > 0) {
|
||||||
|
var boxes = form.querySelectorAll('input[type="checkbox"][name="option_ids"]');
|
||||||
|
boxes.forEach(function (box) {
|
||||||
|
box.addEventListener('change', function () {
|
||||||
|
var checked = form.querySelectorAll('input[type="checkbox"][name="option_ids"]:checked').length;
|
||||||
|
if (checked > maxChoices) { this.checked = false; }
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
var CUSTOM_MARKER = "__tb_custom_option__";
|
||||||
|
form.querySelectorAll('[data-vote-custom-input]').forEach(function (input) {
|
||||||
|
var fid = input.getAttribute('data-vote-custom-input');
|
||||||
|
var group = form.querySelectorAll('input[name="field_' + fid + '"]');
|
||||||
|
var select = form.querySelector('select[name="field_' + fid + '"]');
|
||||||
|
var sync = function () {
|
||||||
|
var on = false;
|
||||||
|
if (select) {
|
||||||
|
on = (select.value === CUSTOM_MARKER);
|
||||||
|
} else {
|
||||||
|
group.forEach(function (r) { if (r.value === CUSTOM_MARKER && r.checked) { on = true; } });
|
||||||
|
}
|
||||||
|
input.disabled = !on;
|
||||||
|
if (!on) { input.value = ''; }
|
||||||
|
};
|
||||||
|
if (select) { select.addEventListener('change', sync); } else { group.forEach(function (r) { r.addEventListener('change', sync); }); }
|
||||||
|
sync();
|
||||||
|
});
|
||||||
|
})();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<p class=" uk-text-right uk-text-muted uk-text-small">
|
||||||
|
<br>
|
||||||
|
<a href="/rules">社区规则</a> |
|
||||||
|
|
||||||
|
<a href="https://box.shiroko.one/_/tamakyi" target="_blank">找站长</a>
|
||||||
|
<br>
|
||||||
|
<a href="https://share.shiroko.one" target="_blank">盘</a>
|
||||||
|
| <a href="https://blog.shiroko.one" target="_blank">公告板</a>
|
||||||
|
| <a href="https://chat.shiroko.one" target="_blank">聊天室</a>
|
||||||
|
| <a href="https://status.shiroko.one" target="_blank">监控板</a>
|
||||||
|
| <a href="https://shiroko.one" target="_blank">导航页</a>
|
||||||
|
<br>Powered by NekoBox | 狼ICP备 20230101
|
||||||
|
<br>提问箱已成功存活:<span id="box_runtime"></span>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
(function () {
|
||||||
|
var create = Math.round(Date.UTC(2023, 6, 1, 18, 15, 43) / 1000);
|
||||||
|
function tick() {
|
||||||
|
var el = document.getElementById("box_runtime");
|
||||||
|
if (!el) return;
|
||||||
|
var s = Math.round((Date.now() + 8 * 3600 * 1000) / 1000) - create;
|
||||||
|
var t = [0, 0, 0, 0, 0];
|
||||||
|
if (s >= 31536000) { t[0] = s / 31536000 | 0; s %= 31536000; }
|
||||||
|
if (s >= 86400) { t[1] = s / 86400 | 0; s %= 86400; }
|
||||||
|
if (s >= 3600) { t[2] = s / 3600 | 0; s %= 3600; }
|
||||||
|
if (s >= 60) { t[3] = s / 60 | 0; s %= 60; }
|
||||||
|
if (s > 0) { t[4] = s; }
|
||||||
|
el.innerHTML = t[0] + '年 ' + t[1] + '天 ' + t[2] + '时 ' + t[3] + '分 ' + t[4] + '秒 ';
|
||||||
|
}
|
||||||
|
tick();
|
||||||
|
setInterval(tick, 1000);
|
||||||
|
})();
|
||||||
|
</script>
|
||||||
|
<br>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
var SUBMIT_I18N = {
|
||||||
|
submitting: '提交中...',
|
||||||
|
uploading: '上传中...'
|
||||||
|
};
|
||||||
|
|
||||||
|
function tbResetSubmitButtons() {
|
||||||
|
document.querySelectorAll('button[data-tb-submitting]').forEach(function(b) {
|
||||||
|
b.disabled = false;
|
||||||
|
b.removeAttribute('data-tb-submitting');
|
||||||
|
var orig = b.getAttribute('data-tb-restore');
|
||||||
|
if (orig !== null) {
|
||||||
|
b.innerHTML = orig;
|
||||||
|
b.removeAttribute('data-tb-restore');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
document.addEventListener('submit', function(e) {
|
||||||
|
var form = e.target;
|
||||||
|
if (!form || form.tagName !== 'FORM') return;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if (e.defaultPrevented || form.getAttribute('data-tb-skip-submit-feedback') === '1') {
|
||||||
|
form.removeAttribute('data-tb-skip-submit-feedback');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if (form.getAttribute('target') === '_blank') return;
|
||||||
|
|
||||||
|
|
||||||
|
var trigger = e.submitter || form.querySelector('button[type="submit"]');
|
||||||
|
|
||||||
|
|
||||||
|
var hasFile = false;
|
||||||
|
form.querySelectorAll('input[type="file"]').forEach(function(f) {
|
||||||
|
if (f.files && f.files.length > 0) hasFile = true;
|
||||||
|
});
|
||||||
|
var label = hasFile ? SUBMIT_I18N.uploading : SUBMIT_I18N.submitting;
|
||||||
|
|
||||||
|
if (trigger && trigger.tagName === 'BUTTON') {
|
||||||
|
trigger.setAttribute('data-tb-restore', trigger.innerHTML);
|
||||||
|
trigger.innerHTML = '<span uk-spinner="ratio: 0.6"></span> ' + label;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
form.querySelectorAll('button').forEach(function(b) {
|
||||||
|
b.disabled = true;
|
||||||
|
b.setAttribute('data-tb-submitting', '1');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
window.addEventListener('pageshow', tbResetSubmitButtons);
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
||||||
@@ -0,0 +1,902 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<title>预览:今天吃什么</title>
|
||||||
|
<meta name="msvalidate.01" content="2F185E8E63C93635F50B3574F3B31E42" />
|
||||||
|
<meta name="description" content="狼的提问箱——一个无需注册、可匿名提问的匿名提问箱,安全地倾诉与回应。">
|
||||||
|
<meta name="keywords" content="匿名提问箱,提问箱,匿名提问,狼的提问箱,匿名问答,匿名提问网站">
|
||||||
|
|
||||||
|
<script>
|
||||||
|
(function () {
|
||||||
|
var m = document.cookie.match(/(?:^|;\s*)theme=([^;]*)/);
|
||||||
|
if (m && m[1] === 'dark') document.documentElement.setAttribute('data-theme', 'dark');
|
||||||
|
})();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<link rel="preconnect" href="https://r2.337845818.best" crossorigin>
|
||||||
|
<link rel="preconnect" href="https://cdnjs.snrat.com" crossorigin>
|
||||||
|
|
||||||
|
<link rel="stylesheet" href="https://cdnjs.snrat.com/ajax/libs/uikit/3.3.3/css/uikit.min.css"/>
|
||||||
|
|
||||||
|
<link rel="stylesheet" href="/static/css/base.css?v=20261019d"/>
|
||||||
|
|
||||||
|
<link rel="stylesheet" href="https://r2.337845818.best/tamabox/cdn/waline/client/v2/waline-no-commits.css" media="print" onload="this.media='all'"/>
|
||||||
|
<script defer src="https://cdnjs.snrat.com/ajax/libs/uikit/3.3.3/js/uikit.min.js"></script>
|
||||||
|
<script defer src="https://cdnjs.snrat.com/ajax/libs/uikit/3.3.3/js/uikit-icons.min.js"></script>
|
||||||
|
|
||||||
|
<script defer src="https://cdnjs.snrat.com/ajax/libs/dayjs/1.10.8/dayjs.min.js"></script>
|
||||||
|
<script defer src="https://cdnjs.snrat.com/ajax/libs/alpinejs/3.9.0/cdn.min.js"></script>
|
||||||
|
|
||||||
|
|
||||||
|
<script defer src="https://cdnjs.snrat.com/ajax/libs/waline/2.15.8/waline.js"></script>
|
||||||
|
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.captcha-equation-box {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
background: #f0f2f5;
|
||||||
|
border: 1px solid #dcdcdc;
|
||||||
|
border-radius: 8px;
|
||||||
|
padding: 8px 8px 8px 16px;
|
||||||
|
gap: 6px;
|
||||||
|
transition: border-color 0.2s;
|
||||||
|
}
|
||||||
|
.captcha-equation-box:focus-within {
|
||||||
|
border-color: #1e87f0;
|
||||||
|
box-shadow: 0 0 0 3px rgba(30,135,240,0.12);
|
||||||
|
}
|
||||||
|
.math-captcha-modal-question {
|
||||||
|
font-size: 1.4rem;
|
||||||
|
font-family: "Courier New", monospace;
|
||||||
|
font-weight: 700;
|
||||||
|
color: #333;
|
||||||
|
letter-spacing: 1px;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
#captcha-modal-answer {
|
||||||
|
width: 80px;
|
||||||
|
padding: 6px 10px;
|
||||||
|
text-align: center;
|
||||||
|
font-size: 1.2rem;
|
||||||
|
font-family: "Courier New", monospace;
|
||||||
|
font-weight: 600;
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
border-radius: 5px;
|
||||||
|
outline: none;
|
||||||
|
transition: border-color 0.15s, box-shadow 0.15s;
|
||||||
|
background: #fff;
|
||||||
|
}
|
||||||
|
#captcha-modal-answer:focus {
|
||||||
|
border-color: #1e87f0;
|
||||||
|
box-shadow: 0 0 0 2px rgba(30,135,240,0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
#captcha-modal-answer::-webkit-inner-spin-button,
|
||||||
|
#captcha-modal-answer::-webkit-outer-spin-button {
|
||||||
|
-webkit-appearance: none;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
#captcha-modal-answer {
|
||||||
|
-moz-appearance: textfield;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<meta property="og:site_name" content="狼的提问箱 | 匿名提问箱" />
|
||||||
|
<meta property="og:type" content="website" />
|
||||||
|
<meta property="og:title" content=" - 狼的提问箱 | 匿名提问箱" />
|
||||||
|
<meta property="og:url" content="https://box-dev-api.337845818.best/user/votes/11/preview" />
|
||||||
|
<meta property="og:description" content=" - 狼的提问箱——一个无需注册、可匿名提问的匿名提问箱,安全地倾诉与回应。" />
|
||||||
|
<meta name="robots" content="noindex">
|
||||||
|
|
||||||
|
<meta property="og:image" content="?og-image=1" />
|
||||||
|
<meta property="og:image:alt" content="" />
|
||||||
|
<meta itemprop="image" content="?og-image=1"/>
|
||||||
|
<meta name="msapplication-TileImage" content=""/>
|
||||||
|
<link rel="shortcut icon" href="?og-image=1"/>
|
||||||
|
<link rel="apple-touch-icon" href="?og-image=1"/>
|
||||||
|
<link rel="icon" sizes="192x192" href="?og-image=1">
|
||||||
|
<meta name="twitter:image:src" content="?og-image=1" />
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<meta name="google-site-verification" content="fEPwRRJfiGsgwc5SINBQwZhPK8F0cwRaOvRx0YRurI4" />
|
||||||
|
|
||||||
|
<script>
|
||||||
|
window.addEventListener("load", function () {
|
||||||
|
var s = document.createElement("script");
|
||||||
|
s.src = "https://mami.shiroko.one/tamami.js";
|
||||||
|
s.setAttribute("data-website-id", "c42ebe8b-9281-4da0-83a4-8f18b3e710fe");
|
||||||
|
document.body.appendChild(s);
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<script>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
window.tbRenderQR = function (el, getOptions) {
|
||||||
|
if (!el || typeof QRCode === 'undefined') return;
|
||||||
|
var opts = getOptions();
|
||||||
|
function remoteOf(o, key) {
|
||||||
|
var v = o[key];
|
||||||
|
return (typeof v === 'string' && v.indexOf('http') === 0) ? v : '';
|
||||||
|
}
|
||||||
|
var good = window._tbQrGood || (window._tbQrGood = {});
|
||||||
|
var bad = window._tbQrBad || (window._tbQrBad = {});
|
||||||
|
|
||||||
|
function layerState(url) { return !url ? '' : (good[url] ? 1 : (bad[url] ? 0 : null)); }
|
||||||
|
var layers = [
|
||||||
|
{ url: remoteOf(opts, 'logo'), st: null, present: function (o, on) {
|
||||||
|
if (on) { } else { o.logo = undefined; o.logoWidth = undefined; o.logoHeight = undefined; o.logoBackgroundTransparent = undefined; }
|
||||||
|
} },
|
||||||
|
{ url: remoteOf(opts, 'backgroundImage'), st: null, present: function (o, on) {
|
||||||
|
if (on) { } else { o.backgroundImage = undefined; o.backgroundImageAlpha = undefined; }
|
||||||
|
} }
|
||||||
|
];
|
||||||
|
var needProbe = false;
|
||||||
|
for (var i = 0; i < layers.length; i++) {
|
||||||
|
layers[i].st = layerState(layers[i].url);
|
||||||
|
if (layers[i].st === null) needProbe = true;
|
||||||
|
}
|
||||||
|
function paint(states) {
|
||||||
|
var o = {};
|
||||||
|
for (var k in opts) o[k] = opts[k];
|
||||||
|
for (var j = 0; j < layers.length; j++) layers[j].present(o, states[j] === 1);
|
||||||
|
el.innerHTML = '';
|
||||||
|
new QRCode(el, o);
|
||||||
|
}
|
||||||
|
|
||||||
|
var initStates = [];
|
||||||
|
for (var n = 0; n < layers.length; n++) initStates.push(layers[n].st === 1 ? 1 : 0);
|
||||||
|
paint(initStates);
|
||||||
|
if (!needProbe) return;
|
||||||
|
|
||||||
|
var pending = 0, cross = opts.crossOrigin || 'anonymous';
|
||||||
|
layers.forEach(function (L) {
|
||||||
|
if (L.st !== null) return;
|
||||||
|
pending++;
|
||||||
|
var im = new Image();
|
||||||
|
im.onload = function () { good[L.url] = true; L.st = 1; onDone(); };
|
||||||
|
im.onerror = function () { bad[L.url] = true; L.st = 0; onDone(); };
|
||||||
|
if (cross) im.crossOrigin = cross;
|
||||||
|
im.src = L.url;
|
||||||
|
});
|
||||||
|
function onDone() {
|
||||||
|
if (--pending > 0) return;
|
||||||
|
var finalStates = [];
|
||||||
|
for (var m = 0; m < layers.length; m++) finalStates.push(layers[m].st === 1 ? 1 : 0);
|
||||||
|
var changed = false;
|
||||||
|
for (var q = 0; q < finalStates.length; q++) if (finalStates[q] !== initStates[q]) changed = true;
|
||||||
|
if (changed) paint(finalStates);
|
||||||
|
}
|
||||||
|
|
||||||
|
setTimeout(function () { if (pending > 0) { pending = 0; onDone(); } }, 3000);
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
<nav class="uk-navbar-container uk-margin tb-navbar" uk-navbar>
|
||||||
|
<div class="uk-navbar-center">
|
||||||
|
<div class="uk-navbar-center-left">
|
||||||
|
<div>
|
||||||
|
<ul class="uk-navbar-nav">
|
||||||
|
|
||||||
|
<li><a href="/explore">探索</a></li>
|
||||||
|
|
||||||
|
|
||||||
|
<li><a href="/_/admin6">我的</a></li>
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<a class="uk-navbar-item uk-logo" href="/"><span class="emoji-placeholder" aria-label="random animal">🐺</span>的提问箱</a>
|
||||||
|
|
||||||
|
<div class="uk-navbar-center-right">
|
||||||
|
<div>
|
||||||
|
|
||||||
|
<ul class="uk-navbar-nav">
|
||||||
|
<li><a href="/user/questions">提问</a></li>
|
||||||
|
</ul>
|
||||||
|
<ul class="uk-navbar-nav">
|
||||||
|
<li><a href="/user/profile">设置</a></li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<ul class="uk-navbar-nav tb-nav-utils">
|
||||||
|
<li>
|
||||||
|
<a href="#" id="theme-toggle" title="切换深色/浅色模式" aria-label="切换深色/浅色模式">
|
||||||
|
<span class="tb-icon-light"><svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M20.5 14.3A8.6 8.6 0 0 1 9.7 3.5a8.6 8.6 0 1 0 10.8 10.8z"/></svg></span><span class="tb-icon-dark"><svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><circle cx="12" cy="12" r="4"/><path d="M12 2.5v2M12 19.5v2M2.5 12h2M19.5 12h2M5.2 5.2l1.4 1.4M17.4 17.4l1.4 1.4M18.8 5.2l-1.4 1.4M6.6 17.4l-1.4 1.4"/></svg></span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
document.addEventListener("DOMContentLoaded", function() {
|
||||||
|
const emojis = ["🐺","🐗","🐻","🐨","🐼","🐹","🐭","🐰","🦊","🐮","🐷","🐽","🐸","🐒","🦍","🐔","🐧","🐦","🐤","🐦⬛","🦅","🦉","🦇","🐴","🦄","🐝","🦎","🦖","🦕","🐙","🦑","🦐","🦞","🦀","🐡","🐠","🐟","🐬","🐳","🐋","🦈","🐊","🐅","🐆","🦓","🦍","🦧","🐘","🦛","🦏","🐪","🐫","🦒","🦘","🐃","🐂","🐄","🐎","🐖","🐏","🐑","🦙","🐐","🦌","🐕","🐩","🦮","🐕🦺","🐈","🐋","🐳","🐬","🐉","🐲"];
|
||||||
|
const placeholder = document.querySelector('.emoji-placeholder');
|
||||||
|
if (placeholder) {
|
||||||
|
placeholder.textContent = emojis[Math.floor(Math.random() * emojis.length)];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
<div id="tb-mobile-utils">
|
||||||
|
|
||||||
|
<button type="button" id="theme-toggle-mobile" class="uk-button uk-button-default uk-button-small"
|
||||||
|
title="切换深色/浅色模式" aria-label="切换深色/浅色模式">
|
||||||
|
<span class="tb-icon-light"><svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M20.5 14.3A8.6 8.6 0 0 1 9.7 3.5a8.6 8.6 0 1 0 10.8 10.8z"/></svg></span><span class="tb-icon-dark"><svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><circle cx="12" cy="12" r="4"/><path d="M12 2.5v2M12 19.5v2M2.5 12h2M19.5 12h2M5.2 5.2l1.4 1.4M17.4 17.4l1.4 1.4M18.8 5.2l-1.4 1.4M6.6 17.4l-1.4 1.4"/></svg></span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
(function() {
|
||||||
|
|
||||||
|
var THEME_COOKIE = 'theme';
|
||||||
|
function getTheme() {
|
||||||
|
var m = document.cookie.match(/(?:^|;\s*)theme=([^;]*)/);
|
||||||
|
return m ? m[1] : '';
|
||||||
|
}
|
||||||
|
function applyTheme(theme) {
|
||||||
|
if (theme === 'dark') {
|
||||||
|
document.documentElement.setAttribute('data-theme', 'dark');
|
||||||
|
} else {
|
||||||
|
document.documentElement.removeAttribute('data-theme');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function toggleTheme() {
|
||||||
|
var next = getTheme() === 'dark' ? 'light' : 'dark';
|
||||||
|
applyTheme(next);
|
||||||
|
var expires = new Date(Date.now() + 365 * 24 * 3600 * 1000).toUTCString();
|
||||||
|
document.cookie = THEME_COOKIE + '=' + next + '; path=/; max-age=' + (365 * 24 * 3600) + '; SameSite=Lax';
|
||||||
|
}
|
||||||
|
|
||||||
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
|
|
||||||
|
var buttons = document.querySelectorAll('#theme-toggle, #theme-toggle-mobile');
|
||||||
|
buttons.forEach(function(btn) {
|
||||||
|
btn.addEventListener('click', function(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
toggleTheme();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
var langSel = document.getElementById('mobile-lang-select');
|
||||||
|
if (langSel) {
|
||||||
|
langSel.addEventListener('change', function() {
|
||||||
|
if (!this.value) return;
|
||||||
|
var to = window.location.pathname + window.location.search;
|
||||||
|
window.location.href = '/i18n/' + encodeURIComponent(this.value) + '?to=' + encodeURIComponent(to);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
})();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
<div class="uk-container uk-container-xsmall">
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<div id="math-captcha-modal" uk-modal>
|
||||||
|
<div class="uk-modal-dialog uk-modal-body uk-text-center">
|
||||||
|
<h3 class="uk-modal-title">人机验证</h3>
|
||||||
|
<p class="uk-text-meta">请计算下方的算术题以验证你不是机器人</p>
|
||||||
|
<div class="captcha-equation-box">
|
||||||
|
<span id="captcha-modal-question" class="math-captcha-modal-question">加载中...</span>
|
||||||
|
<input type="number" id="captcha-modal-answer" placeholder="?" autocomplete="off" inputmode="numeric">
|
||||||
|
</div>
|
||||||
|
<div style="margin-top:6px;">
|
||||||
|
<button type="button" class="uk-button uk-button-text uk-text-small" id="captcha-modal-refresh">换一题</button>
|
||||||
|
</div>
|
||||||
|
<div id="captcha-modal-error" class="uk-text-danger uk-text-small" style="display:none;min-height:20px;"></div>
|
||||||
|
<div class="uk-margin-small-top">
|
||||||
|
<button type="button" class="uk-button uk-button-primary" id="captcha-modal-submit">提交</button>
|
||||||
|
<button type="button" class="uk-button uk-button-default uk-modal-close">取消</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
var CAPTCHA_I18N = {
|
||||||
|
loading: "加载中...",
|
||||||
|
loadFailed: "加载失败",
|
||||||
|
loadRetry: "加载失败,请重试",
|
||||||
|
inputAnswer: "请输入答案",
|
||||||
|
wrongAnswer: "答案错误,请重新计算",
|
||||||
|
verifyFailed: "验证失败,请重试",
|
||||||
|
needPassword: "此提问箱需要密码",
|
||||||
|
needEmail: "请填写接收通知的邮箱地址"
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
(function() {
|
||||||
|
var captchaId = '';
|
||||||
|
var pendingForm = null;
|
||||||
|
var pendingNeedPassword = false;
|
||||||
|
var verifying = false;
|
||||||
|
|
||||||
|
function fetchCaptcha() {
|
||||||
|
var qEl = document.getElementById('captcha-modal-question');
|
||||||
|
var errEl = document.getElementById('captcha-modal-error');
|
||||||
|
var ansEl = document.getElementById('captcha-modal-answer');
|
||||||
|
qEl.textContent = CAPTCHA_I18N.loading;
|
||||||
|
fetch('/api/captcha/generate')
|
||||||
|
.then(function(r) { return r.json(); })
|
||||||
|
.then(function(data) {
|
||||||
|
if (data.code === 0 && data.data) {
|
||||||
|
captchaId = data.data.id;
|
||||||
|
qEl.textContent = data.data.question;
|
||||||
|
if (errEl) errEl.style.display = 'none';
|
||||||
|
if (ansEl) { ansEl.value = ''; ansEl.focus(); }
|
||||||
|
} else {
|
||||||
|
qEl.textContent = CAPTCHA_I18N.loadFailed;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(function() {
|
||||||
|
qEl.textContent = CAPTCHA_I18N.loadRetry;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function getCSRFToken() {
|
||||||
|
var input = document.querySelector('input[name="_csrf"]');
|
||||||
|
return input ? input.value : '';
|
||||||
|
}
|
||||||
|
|
||||||
|
function doSubmit(form) {
|
||||||
|
|
||||||
|
var ans = document.getElementById('captcha-modal-answer').value.trim();
|
||||||
|
var hidden = form.querySelector('[name="g-recaptcha-response"]');
|
||||||
|
if (hidden) hidden.value = captchaId + ':' + (ans || '0');
|
||||||
|
|
||||||
|
UIkit.modal('#math-captcha-modal').hide();
|
||||||
|
|
||||||
|
|
||||||
|
if (pendingNeedPassword) {
|
||||||
|
UIkit.modal.prompt(CAPTCHA_I18N.needPassword, '', 'password')
|
||||||
|
.then(function(password) {
|
||||||
|
if (password) {
|
||||||
|
var pwInput = document.getElementById('ask_password_input');
|
||||||
|
if (pwInput) pwInput.value = password;
|
||||||
|
form.submit();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
form.submit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
document.getElementById('captcha-modal-submit').addEventListener('click', function() {
|
||||||
|
if (verifying) return;
|
||||||
|
var ans = document.getElementById('captcha-modal-answer').value.trim();
|
||||||
|
if (!ans) {
|
||||||
|
var errEl = document.getElementById('captcha-modal-error');
|
||||||
|
errEl.textContent = CAPTCHA_I18N.inputAnswer;
|
||||||
|
errEl.style.display = 'block';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
verifying = true;
|
||||||
|
fetch('/api/captcha/verify', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'X-CSRF-Token': getCSRFToken()
|
||||||
|
},
|
||||||
|
body: JSON.stringify({ id: captchaId, answer: parseInt(ans, 10) })
|
||||||
|
})
|
||||||
|
.then(function(r) { return r.json(); })
|
||||||
|
.then(function(data) {
|
||||||
|
verifying = false;
|
||||||
|
if (data.correct) {
|
||||||
|
if (pendingForm) doSubmit(pendingForm);
|
||||||
|
} else {
|
||||||
|
var errEl = document.getElementById('captcha-modal-error');
|
||||||
|
errEl.textContent = CAPTCHA_I18N.wrongAnswer;
|
||||||
|
errEl.style.display = 'block';
|
||||||
|
fetchCaptcha();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(function() {
|
||||||
|
verifying = false;
|
||||||
|
var errEl = document.getElementById('captcha-modal-error');
|
||||||
|
errEl.textContent = CAPTCHA_I18N.verifyFailed;
|
||||||
|
errEl.style.display = 'block';
|
||||||
|
fetchCaptcha();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
document.getElementById('captcha-modal-answer').addEventListener('keydown', function(e) {
|
||||||
|
if (e.key === 'Enter') {
|
||||||
|
e.preventDefault();
|
||||||
|
document.getElementById('captcha-modal-submit').click();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
document.getElementById('captcha-modal-refresh').addEventListener('click', fetchCaptcha);
|
||||||
|
|
||||||
|
|
||||||
|
document.addEventListener('click', function(e) {
|
||||||
|
var btn = e.target.closest('.math-captcha-trigger');
|
||||||
|
if (!btn) return;
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
var form = btn.closest('form');
|
||||||
|
if (!form) return;
|
||||||
|
pendingForm = form;
|
||||||
|
|
||||||
|
|
||||||
|
pendingNeedPassword = !!(form.querySelector('#ask_password_input'));
|
||||||
|
|
||||||
|
|
||||||
|
var notifyCb = document.getElementById('notify-checkbox');
|
||||||
|
var emailInput = document.getElementById('email-input');
|
||||||
|
if (notifyCb && notifyCb.checked && emailInput && emailInput.value.trim() === '') {
|
||||||
|
UIkit.modal.alert(CAPTCHA_I18N.needEmail);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
fetchCaptcha();
|
||||||
|
UIkit.modal('#math-captcha-modal').show();
|
||||||
|
});
|
||||||
|
})();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
<style>
|
||||||
|
|
||||||
|
.tb-field-head {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
align-items: center;
|
||||||
|
gap: 6px 8px;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
.tb-field-head .tb-field-label {
|
||||||
|
flex-basis: 100%;
|
||||||
|
font-weight: 600;
|
||||||
|
line-height: 1.5;
|
||||||
|
word-break: break-word;
|
||||||
|
overflow-wrap: anywhere;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tb-choice {
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-start;
|
||||||
|
gap: 10px;
|
||||||
|
padding: 12px 14px;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
border: 1px solid var(--tb-border);
|
||||||
|
border-radius: 8px;
|
||||||
|
background: var(--tb-surface);
|
||||||
|
cursor: pointer;
|
||||||
|
transition: border-color 0.2s ease, background 0.2s ease;
|
||||||
|
}
|
||||||
|
.tb-choice:last-child { margin-bottom: 0; }
|
||||||
|
.tb-choice input[type="radio"], .tb-choice input[type="checkbox"] {
|
||||||
|
margin-top: 3px;
|
||||||
|
}
|
||||||
|
.tb-choice span {
|
||||||
|
flex: 1;
|
||||||
|
min-width: 0;
|
||||||
|
line-height: 1.5;
|
||||||
|
word-break: break-word;
|
||||||
|
overflow-wrap: anywhere;
|
||||||
|
}
|
||||||
|
.tb-choice:hover {
|
||||||
|
border-color: var(--tb-primary);
|
||||||
|
background: var(--tb-surface-hover);
|
||||||
|
}
|
||||||
|
.tb-choice:has(input:checked) {
|
||||||
|
border-color: var(--tb-primary);
|
||||||
|
background: var(--tb-surface-active);
|
||||||
|
}
|
||||||
|
html[data-theme="dark"] .tb-choice {
|
||||||
|
border-color: var(--tb-border);
|
||||||
|
background: var(--tb-surface);
|
||||||
|
}
|
||||||
|
html[data-theme="dark"] .tb-choice:hover {
|
||||||
|
border-color: var(--tb-primary);
|
||||||
|
background: rgba(78, 168, 245, 0.08);
|
||||||
|
}
|
||||||
|
html[data-theme="dark"] .tb-choice:has(input:checked) {
|
||||||
|
border-color: var(--tb-primary);
|
||||||
|
background: rgba(78, 168, 245, 0.14);
|
||||||
|
}
|
||||||
|
|
||||||
|
.tb-custom-input {
|
||||||
|
margin-top: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tb-text-counter {
|
||||||
|
margin-top: 2px;
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
@media (max-width: 480px) {
|
||||||
|
.tb-choice { padding: 10px 12px; }
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<div class="uk-card uk-card-default uk-card-body uk-margin-bottom">
|
||||||
|
<div class="uk-flex uk-flex-middle uk-margin-small-bottom" style="gap: 10px;">
|
||||||
|
|
||||||
|
<img class="uk-border-circle" src="https://r2.337845818.best/tamabox/picture/2026/08/19/9af3e38222d972ff9141e9cfdb0475" style="width: 40px; height: 40px;">
|
||||||
|
<div>
|
||||||
|
<a class="uk-text-bold" href="/_admin6">admin6</a>
|
||||||
|
<div class="uk-text-meta uk-text-small">发起的投票</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="uk-margin-auto-left">
|
||||||
|
|
||||||
|
|
||||||
|
<span class="uk-label uk-label-success">进行中</span>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h3 class="uk-margin-remove-top uk-margin-small-bottom">今天吃什么</h3>
|
||||||
|
|
||||||
|
<p class="uk-margin-remove-top">是啊,吃什么?</p>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<div class="uk-alert uk-alert-warning">预览模式:这是发布前的页面样例,提交已禁用</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<div class="uk-alert uk-alert-primary uk-text-small">该投票允许匿名参与,你的身份不会被记录(同一设备最多可参与 1 次)。</div>
|
||||||
|
|
||||||
|
|
||||||
|
<form method="post" action="/vote/NCtv9CwWyUDl/submit" id="vote-form">
|
||||||
|
<input type="hidden" name="_csrf" value="Tj0N6dXdjpejP3JANEKdlPVFyus6MTc5MjM4NTM0MjE2NTQxMDMzMQ">
|
||||||
|
<input type="hidden" name="g-recaptcha-response" id="g-recaptcha-response" value="">
|
||||||
|
|
||||||
|
<div class="uk-card uk-card-default uk-card-body uk-margin-bottom">
|
||||||
|
|
||||||
|
|
||||||
|
<div class="uk-margin">
|
||||||
|
<div class="tb-field-head">
|
||||||
|
<span class="tb-chip">1</span>
|
||||||
|
<span class="tb-chip">单选</span>
|
||||||
|
<div class="tb-field-label">水果</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<label class="tb-choice">
|
||||||
|
<input class="uk-radio" type="radio" name="field_26" value="苹果" ><span>苹果</span>
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<label class="tb-choice">
|
||||||
|
<input class="uk-radio" type="radio" name="field_26" value="香蕉" ><span>香蕉</span>
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<label class="tb-choice">
|
||||||
|
<input class="uk-radio" type="radio" name="field_26" value="葡萄" ><span>葡萄</span>
|
||||||
|
</label>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="uk-margin">
|
||||||
|
<div class="tb-field-head">
|
||||||
|
<span class="tb-chip">2</span>
|
||||||
|
<span class="tb-chip">多选</span>
|
||||||
|
<div class="tb-field-label">主食 <span class="uk-text-danger">*</span></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<label class="tb-choice">
|
||||||
|
<input class="uk-checkbox" type="checkbox" name="field_27" value="米饭" data-vote-required data-vote-label="主食"><span>米饭</span>
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<label class="tb-choice">
|
||||||
|
<input class="uk-checkbox" type="checkbox" name="field_27" value="面包" data-vote-required data-vote-label="主食"><span>面包</span>
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<label class="tb-choice">
|
||||||
|
<input class="uk-checkbox" type="checkbox" name="field_27" value="馒头" data-vote-required data-vote-label="主食"><span>馒头</span>
|
||||||
|
</label>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="uk-margin">
|
||||||
|
<div class="tb-field-head">
|
||||||
|
<span class="tb-chip">3</span>
|
||||||
|
<span class="tb-chip">数字</span>
|
||||||
|
<div class="tb-field-label">吃多少 <span class="uk-text-danger">*</span></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<input class="uk-input" type="number" name="field_28" data-vote-required data-vote-label="吃多少">
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="uk-margin">
|
||||||
|
|
||||||
|
<button type="button" class="uk-button uk-button-primary" disabled>提交投票</button>
|
||||||
|
<span class="uk-text-meta uk-text-small uk-margin-small-left">预览模式,发布后即可提交</span>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<div class="uk-margin-top uk-text-small">
|
||||||
|
<a href="/user/votes/11/results">管理此投票(仅你可见结果)</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<script>
|
||||||
|
|
||||||
|
|
||||||
|
var MAX_CUSTOM_LEN = null ;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
function countChars(s) { return Array.from(String(s || '')).length; }
|
||||||
|
|
||||||
|
|
||||||
|
function setupTextCounters() {
|
||||||
|
var form = document.getElementById('vote-form');
|
||||||
|
if (!form) { return; }
|
||||||
|
form.querySelectorAll('[data-tb-text-counter]').forEach(function (input) {
|
||||||
|
var max = parseInt(input.getAttribute('data-tb-text-max'), 10);
|
||||||
|
if (!max || max < 1) { max = MAX_CUSTOM_LEN; }
|
||||||
|
var counter = document.createElement('div');
|
||||||
|
counter.className = 'uk-text-meta uk-text-small tb-text-counter';
|
||||||
|
if (input.parentNode) { input.parentNode.insertBefore(counter, input.nextSibling); }
|
||||||
|
var update = function () {
|
||||||
|
var n = countChars(input.value);
|
||||||
|
counter.textContent = n + ' / ' + max;
|
||||||
|
if (n > max) {
|
||||||
|
counter.classList.add('uk-text-danger');
|
||||||
|
input.setAttribute('data-tb-too-long', '1');
|
||||||
|
} else {
|
||||||
|
counter.classList.remove('uk-text-danger');
|
||||||
|
input.removeAttribute('data-tb-too-long');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
input.addEventListener('input', update);
|
||||||
|
update();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
function validateVoteForm() {
|
||||||
|
var form = document.getElementById('vote-form');
|
||||||
|
if (!form) { return true; }
|
||||||
|
|
||||||
|
var tooLong = form.querySelector('[data-tb-text-counter][data-tb-too-long]');
|
||||||
|
if (tooLong) {
|
||||||
|
alert('自定义选项不能超过 %!d(\u003cnil\u003e) 字');
|
||||||
|
tooLong.focus();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
var groups = {};
|
||||||
|
form.querySelectorAll('input[data-vote-required][type="radio"], input[data-vote-required][type="checkbox"]').forEach(function (el) {
|
||||||
|
(groups[el.name] = groups[el.name] || []).push(el);
|
||||||
|
});
|
||||||
|
for (var name in groups) {
|
||||||
|
var any = groups[name].some(function (el) { return el.checked; });
|
||||||
|
if (!any) {
|
||||||
|
alert('请完成「' + groups[name][0].getAttribute('data-vote-label') + '」');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var els = form.querySelectorAll('[data-vote-required]:not(input[type="radio"]):not(input[type="checkbox"])');
|
||||||
|
for (var i = 0; i < els.length; i++) {
|
||||||
|
var el = els[i];
|
||||||
|
if (el.disabled) { continue; }
|
||||||
|
if ((el.value || '').trim() === '') {
|
||||||
|
alert('请完成「' + el.getAttribute('data-vote-label') + '」');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function voteValidate(e) {
|
||||||
|
if (!validateVoteForm()) {
|
||||||
|
if (e) { e.stopPropagation(); e.preventDefault(); }
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function onSubmit() {
|
||||||
|
if (validateVoteForm()) {
|
||||||
|
document.getElementById('vote-form').submit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
(function () {
|
||||||
|
var form = document.getElementById('vote-form');
|
||||||
|
if (!form) { return; }
|
||||||
|
setupTextCounters();
|
||||||
|
var maxChoices = 0;
|
||||||
|
if (maxChoices > 0) {
|
||||||
|
var boxes = form.querySelectorAll('input[type="checkbox"][name="option_ids"]');
|
||||||
|
boxes.forEach(function (box) {
|
||||||
|
box.addEventListener('change', function () {
|
||||||
|
var checked = form.querySelectorAll('input[type="checkbox"][name="option_ids"]:checked').length;
|
||||||
|
if (checked > maxChoices) { this.checked = false; }
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
var CUSTOM_MARKER = "__tb_custom_option__";
|
||||||
|
form.querySelectorAll('[data-vote-custom-input]').forEach(function (input) {
|
||||||
|
var fid = input.getAttribute('data-vote-custom-input');
|
||||||
|
var group = form.querySelectorAll('input[name="field_' + fid + '"]');
|
||||||
|
var select = form.querySelector('select[name="field_' + fid + '"]');
|
||||||
|
var sync = function () {
|
||||||
|
var on = false;
|
||||||
|
if (select) {
|
||||||
|
on = (select.value === CUSTOM_MARKER);
|
||||||
|
} else {
|
||||||
|
group.forEach(function (r) { if (r.value === CUSTOM_MARKER && r.checked) { on = true; } });
|
||||||
|
}
|
||||||
|
input.disabled = !on;
|
||||||
|
if (!on) { input.value = ''; }
|
||||||
|
};
|
||||||
|
if (select) { select.addEventListener('change', sync); } else { group.forEach(function (r) { r.addEventListener('change', sync); }); }
|
||||||
|
sync();
|
||||||
|
});
|
||||||
|
})();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<p class=" uk-text-right uk-text-muted uk-text-small">
|
||||||
|
<br>
|
||||||
|
<a href="/rules">社区规则</a> |
|
||||||
|
|
||||||
|
<a href="https://box.shiroko.one/_/tamakyi" target="_blank">找站长</a>
|
||||||
|
<br>
|
||||||
|
<a href="https://share.shiroko.one" target="_blank">盘</a>
|
||||||
|
| <a href="https://blog.shiroko.one" target="_blank">公告板</a>
|
||||||
|
| <a href="https://chat.shiroko.one" target="_blank">聊天室</a>
|
||||||
|
| <a href="https://status.shiroko.one" target="_blank">监控板</a>
|
||||||
|
| <a href="https://shiroko.one" target="_blank">导航页</a>
|
||||||
|
<br>Powered by NekoBox | 狼ICP备 20230101
|
||||||
|
<br>提问箱已成功存活:<span id="box_runtime"></span>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
(function () {
|
||||||
|
var create = Math.round(Date.UTC(2023, 6, 1, 18, 15, 43) / 1000);
|
||||||
|
function tick() {
|
||||||
|
var el = document.getElementById("box_runtime");
|
||||||
|
if (!el) return;
|
||||||
|
var s = Math.round((Date.now() + 8 * 3600 * 1000) / 1000) - create;
|
||||||
|
var t = [0, 0, 0, 0, 0];
|
||||||
|
if (s >= 31536000) { t[0] = s / 31536000 | 0; s %= 31536000; }
|
||||||
|
if (s >= 86400) { t[1] = s / 86400 | 0; s %= 86400; }
|
||||||
|
if (s >= 3600) { t[2] = s / 3600 | 0; s %= 3600; }
|
||||||
|
if (s >= 60) { t[3] = s / 60 | 0; s %= 60; }
|
||||||
|
if (s > 0) { t[4] = s; }
|
||||||
|
el.innerHTML = t[0] + '年 ' + t[1] + '天 ' + t[2] + '时 ' + t[3] + '分 ' + t[4] + '秒 ';
|
||||||
|
}
|
||||||
|
tick();
|
||||||
|
setInterval(tick, 1000);
|
||||||
|
})();
|
||||||
|
</script>
|
||||||
|
<br>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
var SUBMIT_I18N = {
|
||||||
|
submitting: '提交中...',
|
||||||
|
uploading: '上传中...'
|
||||||
|
};
|
||||||
|
|
||||||
|
function tbResetSubmitButtons() {
|
||||||
|
document.querySelectorAll('button[data-tb-submitting]').forEach(function(b) {
|
||||||
|
b.disabled = false;
|
||||||
|
b.removeAttribute('data-tb-submitting');
|
||||||
|
var orig = b.getAttribute('data-tb-restore');
|
||||||
|
if (orig !== null) {
|
||||||
|
b.innerHTML = orig;
|
||||||
|
b.removeAttribute('data-tb-restore');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
document.addEventListener('submit', function(e) {
|
||||||
|
var form = e.target;
|
||||||
|
if (!form || form.tagName !== 'FORM') return;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if (e.defaultPrevented || form.getAttribute('data-tb-skip-submit-feedback') === '1') {
|
||||||
|
form.removeAttribute('data-tb-skip-submit-feedback');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if (form.getAttribute('target') === '_blank') return;
|
||||||
|
|
||||||
|
|
||||||
|
var trigger = e.submitter || form.querySelector('button[type="submit"]');
|
||||||
|
|
||||||
|
|
||||||
|
var hasFile = false;
|
||||||
|
form.querySelectorAll('input[type="file"]').forEach(function(f) {
|
||||||
|
if (f.files && f.files.length > 0) hasFile = true;
|
||||||
|
});
|
||||||
|
var label = hasFile ? SUBMIT_I18N.uploading : SUBMIT_I18N.submitting;
|
||||||
|
|
||||||
|
if (trigger && trigger.tagName === 'BUTTON') {
|
||||||
|
trigger.setAttribute('data-tb-restore', trigger.innerHTML);
|
||||||
|
trigger.innerHTML = '<span uk-spinner="ratio: 0.6"></span> ' + label;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
form.querySelectorAll('button').forEach(function(b) {
|
||||||
|
b.disabled = true;
|
||||||
|
b.setAttribute('data-tb-submitting', '1');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
window.addEventListener('pageshow', tbResetSubmitButtons);
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
||||||
@@ -0,0 +1,758 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<title>投票结果</title>
|
||||||
|
<meta name="msvalidate.01" content="2F185E8E63C93635F50B3574F3B31E42" />
|
||||||
|
<meta name="description" content="狼的提问箱——一个无需注册、可匿名提问的匿名提问箱,安全地倾诉与回应。">
|
||||||
|
<meta name="keywords" content="匿名提问箱,提问箱,匿名提问,狼的提问箱,匿名问答,匿名提问网站">
|
||||||
|
|
||||||
|
<script>
|
||||||
|
(function () {
|
||||||
|
var m = document.cookie.match(/(?:^|;\s*)theme=([^;]*)/);
|
||||||
|
if (m && m[1] === 'dark') document.documentElement.setAttribute('data-theme', 'dark');
|
||||||
|
})();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<link rel="preconnect" href="https://r2.337845818.best" crossorigin>
|
||||||
|
<link rel="preconnect" href="https://cdnjs.snrat.com" crossorigin>
|
||||||
|
|
||||||
|
<link rel="stylesheet" href="https://cdnjs.snrat.com/ajax/libs/uikit/3.3.3/css/uikit.min.css"/>
|
||||||
|
|
||||||
|
<link rel="stylesheet" href="/static/css/base.css?v=20261019d"/>
|
||||||
|
|
||||||
|
<link rel="stylesheet" href="https://r2.337845818.best/tamabox/cdn/waline/client/v2/waline-no-commits.css" media="print" onload="this.media='all'"/>
|
||||||
|
<script defer src="https://cdnjs.snrat.com/ajax/libs/uikit/3.3.3/js/uikit.min.js"></script>
|
||||||
|
<script defer src="https://cdnjs.snrat.com/ajax/libs/uikit/3.3.3/js/uikit-icons.min.js"></script>
|
||||||
|
|
||||||
|
<script defer src="https://cdnjs.snrat.com/ajax/libs/dayjs/1.10.8/dayjs.min.js"></script>
|
||||||
|
<script defer src="https://cdnjs.snrat.com/ajax/libs/alpinejs/3.9.0/cdn.min.js"></script>
|
||||||
|
|
||||||
|
|
||||||
|
<script defer src="https://cdnjs.snrat.com/ajax/libs/waline/2.15.8/waline.js"></script>
|
||||||
|
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.captcha-equation-box {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
background: #f0f2f5;
|
||||||
|
border: 1px solid #dcdcdc;
|
||||||
|
border-radius: 8px;
|
||||||
|
padding: 8px 8px 8px 16px;
|
||||||
|
gap: 6px;
|
||||||
|
transition: border-color 0.2s;
|
||||||
|
}
|
||||||
|
.captcha-equation-box:focus-within {
|
||||||
|
border-color: #1e87f0;
|
||||||
|
box-shadow: 0 0 0 3px rgba(30,135,240,0.12);
|
||||||
|
}
|
||||||
|
.math-captcha-modal-question {
|
||||||
|
font-size: 1.4rem;
|
||||||
|
font-family: "Courier New", monospace;
|
||||||
|
font-weight: 700;
|
||||||
|
color: #333;
|
||||||
|
letter-spacing: 1px;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
#captcha-modal-answer {
|
||||||
|
width: 80px;
|
||||||
|
padding: 6px 10px;
|
||||||
|
text-align: center;
|
||||||
|
font-size: 1.2rem;
|
||||||
|
font-family: "Courier New", monospace;
|
||||||
|
font-weight: 600;
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
border-radius: 5px;
|
||||||
|
outline: none;
|
||||||
|
transition: border-color 0.15s, box-shadow 0.15s;
|
||||||
|
background: #fff;
|
||||||
|
}
|
||||||
|
#captcha-modal-answer:focus {
|
||||||
|
border-color: #1e87f0;
|
||||||
|
box-shadow: 0 0 0 2px rgba(30,135,240,0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
#captcha-modal-answer::-webkit-inner-spin-button,
|
||||||
|
#captcha-modal-answer::-webkit-outer-spin-button {
|
||||||
|
-webkit-appearance: none;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
#captcha-modal-answer {
|
||||||
|
-moz-appearance: textfield;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<meta property="og:site_name" content="狼的提问箱 | 匿名提问箱" />
|
||||||
|
<meta property="og:type" content="website" />
|
||||||
|
<meta property="og:title" content=" - 狼的提问箱 | 匿名提问箱" />
|
||||||
|
<meta property="og:url" content="https://box-dev-api.337845818.best/user/votes/12/results" />
|
||||||
|
<meta property="og:description" content=" - 狼的提问箱——一个无需注册、可匿名提问的匿名提问箱,安全地倾诉与回应。" />
|
||||||
|
<meta name="robots" content="noindex">
|
||||||
|
|
||||||
|
<meta property="og:image" content="?og-image=1" />
|
||||||
|
<meta property="og:image:alt" content="" />
|
||||||
|
<meta itemprop="image" content="?og-image=1"/>
|
||||||
|
<meta name="msapplication-TileImage" content=""/>
|
||||||
|
<link rel="shortcut icon" href="?og-image=1"/>
|
||||||
|
<link rel="apple-touch-icon" href="?og-image=1"/>
|
||||||
|
<link rel="icon" sizes="192x192" href="?og-image=1">
|
||||||
|
<meta name="twitter:image:src" content="?og-image=1" />
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<meta name="google-site-verification" content="fEPwRRJfiGsgwc5SINBQwZhPK8F0cwRaOvRx0YRurI4" />
|
||||||
|
|
||||||
|
<script>
|
||||||
|
window.addEventListener("load", function () {
|
||||||
|
var s = document.createElement("script");
|
||||||
|
s.src = "https://mami.shiroko.one/tamami.js";
|
||||||
|
s.setAttribute("data-website-id", "c42ebe8b-9281-4da0-83a4-8f18b3e710fe");
|
||||||
|
document.body.appendChild(s);
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<script>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
window.tbRenderQR = function (el, getOptions) {
|
||||||
|
if (!el || typeof QRCode === 'undefined') return;
|
||||||
|
var opts = getOptions();
|
||||||
|
function remoteOf(o, key) {
|
||||||
|
var v = o[key];
|
||||||
|
return (typeof v === 'string' && v.indexOf('http') === 0) ? v : '';
|
||||||
|
}
|
||||||
|
var good = window._tbQrGood || (window._tbQrGood = {});
|
||||||
|
var bad = window._tbQrBad || (window._tbQrBad = {});
|
||||||
|
|
||||||
|
function layerState(url) { return !url ? '' : (good[url] ? 1 : (bad[url] ? 0 : null)); }
|
||||||
|
var layers = [
|
||||||
|
{ url: remoteOf(opts, 'logo'), st: null, present: function (o, on) {
|
||||||
|
if (on) { } else { o.logo = undefined; o.logoWidth = undefined; o.logoHeight = undefined; o.logoBackgroundTransparent = undefined; }
|
||||||
|
} },
|
||||||
|
{ url: remoteOf(opts, 'backgroundImage'), st: null, present: function (o, on) {
|
||||||
|
if (on) { } else { o.backgroundImage = undefined; o.backgroundImageAlpha = undefined; }
|
||||||
|
} }
|
||||||
|
];
|
||||||
|
var needProbe = false;
|
||||||
|
for (var i = 0; i < layers.length; i++) {
|
||||||
|
layers[i].st = layerState(layers[i].url);
|
||||||
|
if (layers[i].st === null) needProbe = true;
|
||||||
|
}
|
||||||
|
function paint(states) {
|
||||||
|
var o = {};
|
||||||
|
for (var k in opts) o[k] = opts[k];
|
||||||
|
for (var j = 0; j < layers.length; j++) layers[j].present(o, states[j] === 1);
|
||||||
|
el.innerHTML = '';
|
||||||
|
new QRCode(el, o);
|
||||||
|
}
|
||||||
|
|
||||||
|
var initStates = [];
|
||||||
|
for (var n = 0; n < layers.length; n++) initStates.push(layers[n].st === 1 ? 1 : 0);
|
||||||
|
paint(initStates);
|
||||||
|
if (!needProbe) return;
|
||||||
|
|
||||||
|
var pending = 0, cross = opts.crossOrigin || 'anonymous';
|
||||||
|
layers.forEach(function (L) {
|
||||||
|
if (L.st !== null) return;
|
||||||
|
pending++;
|
||||||
|
var im = new Image();
|
||||||
|
im.onload = function () { good[L.url] = true; L.st = 1; onDone(); };
|
||||||
|
im.onerror = function () { bad[L.url] = true; L.st = 0; onDone(); };
|
||||||
|
if (cross) im.crossOrigin = cross;
|
||||||
|
im.src = L.url;
|
||||||
|
});
|
||||||
|
function onDone() {
|
||||||
|
if (--pending > 0) return;
|
||||||
|
var finalStates = [];
|
||||||
|
for (var m = 0; m < layers.length; m++) finalStates.push(layers[m].st === 1 ? 1 : 0);
|
||||||
|
var changed = false;
|
||||||
|
for (var q = 0; q < finalStates.length; q++) if (finalStates[q] !== initStates[q]) changed = true;
|
||||||
|
if (changed) paint(finalStates);
|
||||||
|
}
|
||||||
|
|
||||||
|
setTimeout(function () { if (pending > 0) { pending = 0; onDone(); } }, 3000);
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
<nav class="uk-navbar-container uk-margin tb-navbar" uk-navbar>
|
||||||
|
<div class="uk-navbar-center">
|
||||||
|
<div class="uk-navbar-center-left">
|
||||||
|
<div>
|
||||||
|
<ul class="uk-navbar-nav">
|
||||||
|
|
||||||
|
<li><a href="/explore">探索</a></li>
|
||||||
|
|
||||||
|
|
||||||
|
<li><a href="/_/admin6">我的</a></li>
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<a class="uk-navbar-item uk-logo" href="/"><span class="emoji-placeholder" aria-label="random animal">🐺</span>的提问箱</a>
|
||||||
|
|
||||||
|
<div class="uk-navbar-center-right">
|
||||||
|
<div>
|
||||||
|
|
||||||
|
<ul class="uk-navbar-nav">
|
||||||
|
<li><a href="/user/questions">提问</a></li>
|
||||||
|
</ul>
|
||||||
|
<ul class="uk-navbar-nav">
|
||||||
|
<li><a href="/user/profile">设置</a></li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<ul class="uk-navbar-nav tb-nav-utils">
|
||||||
|
<li>
|
||||||
|
<a href="#" id="theme-toggle" title="切换深色/浅色模式" aria-label="切换深色/浅色模式">
|
||||||
|
<span class="tb-icon-light"><svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M20.5 14.3A8.6 8.6 0 0 1 9.7 3.5a8.6 8.6 0 1 0 10.8 10.8z"/></svg></span><span class="tb-icon-dark"><svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><circle cx="12" cy="12" r="4"/><path d="M12 2.5v2M12 19.5v2M2.5 12h2M19.5 12h2M5.2 5.2l1.4 1.4M17.4 17.4l1.4 1.4M18.8 5.2l-1.4 1.4M6.6 17.4l-1.4 1.4"/></svg></span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
document.addEventListener("DOMContentLoaded", function() {
|
||||||
|
const emojis = ["🐺","🐗","🐻","🐨","🐼","🐹","🐭","🐰","🦊","🐮","🐷","🐽","🐸","🐒","🦍","🐔","🐧","🐦","🐤","🐦⬛","🦅","🦉","🦇","🐴","🦄","🐝","🦎","🦖","🦕","🐙","🦑","🦐","🦞","🦀","🐡","🐠","🐟","🐬","🐳","🐋","🦈","🐊","🐅","🐆","🦓","🦍","🦧","🐘","🦛","🦏","🐪","🐫","🦒","🦘","🐃","🐂","🐄","🐎","🐖","🐏","🐑","🦙","🐐","🦌","🐕","🐩","🦮","🐕🦺","🐈","🐋","🐳","🐬","🐉","🐲"];
|
||||||
|
const placeholder = document.querySelector('.emoji-placeholder');
|
||||||
|
if (placeholder) {
|
||||||
|
placeholder.textContent = emojis[Math.floor(Math.random() * emojis.length)];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
<div id="tb-mobile-utils">
|
||||||
|
|
||||||
|
<button type="button" id="theme-toggle-mobile" class="uk-button uk-button-default uk-button-small"
|
||||||
|
title="切换深色/浅色模式" aria-label="切换深色/浅色模式">
|
||||||
|
<span class="tb-icon-light"><svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M20.5 14.3A8.6 8.6 0 0 1 9.7 3.5a8.6 8.6 0 1 0 10.8 10.8z"/></svg></span><span class="tb-icon-dark"><svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><circle cx="12" cy="12" r="4"/><path d="M12 2.5v2M12 19.5v2M2.5 12h2M19.5 12h2M5.2 5.2l1.4 1.4M17.4 17.4l1.4 1.4M18.8 5.2l-1.4 1.4M6.6 17.4l-1.4 1.4"/></svg></span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
(function() {
|
||||||
|
|
||||||
|
var THEME_COOKIE = 'theme';
|
||||||
|
function getTheme() {
|
||||||
|
var m = document.cookie.match(/(?:^|;\s*)theme=([^;]*)/);
|
||||||
|
return m ? m[1] : '';
|
||||||
|
}
|
||||||
|
function applyTheme(theme) {
|
||||||
|
if (theme === 'dark') {
|
||||||
|
document.documentElement.setAttribute('data-theme', 'dark');
|
||||||
|
} else {
|
||||||
|
document.documentElement.removeAttribute('data-theme');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function toggleTheme() {
|
||||||
|
var next = getTheme() === 'dark' ? 'light' : 'dark';
|
||||||
|
applyTheme(next);
|
||||||
|
var expires = new Date(Date.now() + 365 * 24 * 3600 * 1000).toUTCString();
|
||||||
|
document.cookie = THEME_COOKIE + '=' + next + '; path=/; max-age=' + (365 * 24 * 3600) + '; SameSite=Lax';
|
||||||
|
}
|
||||||
|
|
||||||
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
|
|
||||||
|
var buttons = document.querySelectorAll('#theme-toggle, #theme-toggle-mobile');
|
||||||
|
buttons.forEach(function(btn) {
|
||||||
|
btn.addEventListener('click', function(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
toggleTheme();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
var langSel = document.getElementById('mobile-lang-select');
|
||||||
|
if (langSel) {
|
||||||
|
langSel.addEventListener('change', function() {
|
||||||
|
if (!this.value) return;
|
||||||
|
var to = window.location.pathname + window.location.search;
|
||||||
|
window.location.href = '/i18n/' + encodeURIComponent(this.value) + '?to=' + encodeURIComponent(to);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
})();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
<div class="uk-container uk-container-xsmall">
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<div id="math-captcha-modal" uk-modal>
|
||||||
|
<div class="uk-modal-dialog uk-modal-body uk-text-center">
|
||||||
|
<h3 class="uk-modal-title">人机验证</h3>
|
||||||
|
<p class="uk-text-meta">请计算下方的算术题以验证你不是机器人</p>
|
||||||
|
<div class="captcha-equation-box">
|
||||||
|
<span id="captcha-modal-question" class="math-captcha-modal-question">加载中...</span>
|
||||||
|
<input type="number" id="captcha-modal-answer" placeholder="?" autocomplete="off" inputmode="numeric">
|
||||||
|
</div>
|
||||||
|
<div style="margin-top:6px;">
|
||||||
|
<button type="button" class="uk-button uk-button-text uk-text-small" id="captcha-modal-refresh">换一题</button>
|
||||||
|
</div>
|
||||||
|
<div id="captcha-modal-error" class="uk-text-danger uk-text-small" style="display:none;min-height:20px;"></div>
|
||||||
|
<div class="uk-margin-small-top">
|
||||||
|
<button type="button" class="uk-button uk-button-primary" id="captcha-modal-submit">提交</button>
|
||||||
|
<button type="button" class="uk-button uk-button-default uk-modal-close">取消</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
var CAPTCHA_I18N = {
|
||||||
|
loading: "加载中...",
|
||||||
|
loadFailed: "加载失败",
|
||||||
|
loadRetry: "加载失败,请重试",
|
||||||
|
inputAnswer: "请输入答案",
|
||||||
|
wrongAnswer: "答案错误,请重新计算",
|
||||||
|
verifyFailed: "验证失败,请重试",
|
||||||
|
needPassword: "此提问箱需要密码",
|
||||||
|
needEmail: "请填写接收通知的邮箱地址"
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
(function() {
|
||||||
|
var captchaId = '';
|
||||||
|
var pendingForm = null;
|
||||||
|
var pendingNeedPassword = false;
|
||||||
|
var verifying = false;
|
||||||
|
|
||||||
|
function fetchCaptcha() {
|
||||||
|
var qEl = document.getElementById('captcha-modal-question');
|
||||||
|
var errEl = document.getElementById('captcha-modal-error');
|
||||||
|
var ansEl = document.getElementById('captcha-modal-answer');
|
||||||
|
qEl.textContent = CAPTCHA_I18N.loading;
|
||||||
|
fetch('/api/captcha/generate')
|
||||||
|
.then(function(r) { return r.json(); })
|
||||||
|
.then(function(data) {
|
||||||
|
if (data.code === 0 && data.data) {
|
||||||
|
captchaId = data.data.id;
|
||||||
|
qEl.textContent = data.data.question;
|
||||||
|
if (errEl) errEl.style.display = 'none';
|
||||||
|
if (ansEl) { ansEl.value = ''; ansEl.focus(); }
|
||||||
|
} else {
|
||||||
|
qEl.textContent = CAPTCHA_I18N.loadFailed;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(function() {
|
||||||
|
qEl.textContent = CAPTCHA_I18N.loadRetry;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function getCSRFToken() {
|
||||||
|
var input = document.querySelector('input[name="_csrf"]');
|
||||||
|
return input ? input.value : '';
|
||||||
|
}
|
||||||
|
|
||||||
|
function doSubmit(form) {
|
||||||
|
|
||||||
|
var ans = document.getElementById('captcha-modal-answer').value.trim();
|
||||||
|
var hidden = form.querySelector('[name="g-recaptcha-response"]');
|
||||||
|
if (hidden) hidden.value = captchaId + ':' + (ans || '0');
|
||||||
|
|
||||||
|
UIkit.modal('#math-captcha-modal').hide();
|
||||||
|
|
||||||
|
|
||||||
|
if (pendingNeedPassword) {
|
||||||
|
UIkit.modal.prompt(CAPTCHA_I18N.needPassword, '', 'password')
|
||||||
|
.then(function(password) {
|
||||||
|
if (password) {
|
||||||
|
var pwInput = document.getElementById('ask_password_input');
|
||||||
|
if (pwInput) pwInput.value = password;
|
||||||
|
form.submit();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
form.submit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
document.getElementById('captcha-modal-submit').addEventListener('click', function() {
|
||||||
|
if (verifying) return;
|
||||||
|
var ans = document.getElementById('captcha-modal-answer').value.trim();
|
||||||
|
if (!ans) {
|
||||||
|
var errEl = document.getElementById('captcha-modal-error');
|
||||||
|
errEl.textContent = CAPTCHA_I18N.inputAnswer;
|
||||||
|
errEl.style.display = 'block';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
verifying = true;
|
||||||
|
fetch('/api/captcha/verify', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'X-CSRF-Token': getCSRFToken()
|
||||||
|
},
|
||||||
|
body: JSON.stringify({ id: captchaId, answer: parseInt(ans, 10) })
|
||||||
|
})
|
||||||
|
.then(function(r) { return r.json(); })
|
||||||
|
.then(function(data) {
|
||||||
|
verifying = false;
|
||||||
|
if (data.correct) {
|
||||||
|
if (pendingForm) doSubmit(pendingForm);
|
||||||
|
} else {
|
||||||
|
var errEl = document.getElementById('captcha-modal-error');
|
||||||
|
errEl.textContent = CAPTCHA_I18N.wrongAnswer;
|
||||||
|
errEl.style.display = 'block';
|
||||||
|
fetchCaptcha();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(function() {
|
||||||
|
verifying = false;
|
||||||
|
var errEl = document.getElementById('captcha-modal-error');
|
||||||
|
errEl.textContent = CAPTCHA_I18N.verifyFailed;
|
||||||
|
errEl.style.display = 'block';
|
||||||
|
fetchCaptcha();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
document.getElementById('captcha-modal-answer').addEventListener('keydown', function(e) {
|
||||||
|
if (e.key === 'Enter') {
|
||||||
|
e.preventDefault();
|
||||||
|
document.getElementById('captcha-modal-submit').click();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
document.getElementById('captcha-modal-refresh').addEventListener('click', fetchCaptcha);
|
||||||
|
|
||||||
|
|
||||||
|
document.addEventListener('click', function(e) {
|
||||||
|
var btn = e.target.closest('.math-captcha-trigger');
|
||||||
|
if (!btn) return;
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
var form = btn.closest('form');
|
||||||
|
if (!form) return;
|
||||||
|
pendingForm = form;
|
||||||
|
|
||||||
|
|
||||||
|
pendingNeedPassword = !!(form.querySelector('#ask_password_input'));
|
||||||
|
|
||||||
|
|
||||||
|
var notifyCb = document.getElementById('notify-checkbox');
|
||||||
|
var emailInput = document.getElementById('email-input');
|
||||||
|
if (notifyCb && notifyCb.checked && emailInput && emailInput.value.trim() === '') {
|
||||||
|
UIkit.modal.alert(CAPTCHA_I18N.needEmail);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
fetchCaptcha();
|
||||||
|
UIkit.modal('#math-captcha-modal').show();
|
||||||
|
});
|
||||||
|
})();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
<div class="uk-flex uk-flex-between uk-flex-middle uk-margin-bottom">
|
||||||
|
<h3 class="uk-margin-remove">投票结果:测试功能</h3>
|
||||||
|
<div class="uk-flex uk-flex-middle" style="gap: 8px;">
|
||||||
|
<a class="uk-button uk-button-default uk-button-small" href="/user/votes/12/export">导出 CSV</a>
|
||||||
|
<a class="uk-button uk-button-default uk-button-small" href="/user/questions#votes">返回</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="uk-card uk-card-default uk-card-small uk-card-body uk-margin-bottom">
|
||||||
|
<div class="uk-text-large uk-text-bold">3</div>
|
||||||
|
<div class="uk-text-meta">总参与人数</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<h4>投票结果</h4>
|
||||||
|
<div class="uk-card uk-card-default uk-card-small uk-card-body uk-margin-bottom">
|
||||||
|
|
||||||
|
<div class="uk-margin">
|
||||||
|
<div class="uk-flex uk-flex-middle uk-margin-small-bottom" style="gap: 8px;">
|
||||||
|
<span class="tb-chip">1</span>
|
||||||
|
<span class="tb-chip">单选</span>
|
||||||
|
<span class="uk-text-bold">必填</span>
|
||||||
|
<span class="uk-text-meta uk-text-small">回答数: 3</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<div class="uk-margin-small-top">
|
||||||
|
<div class="uk-flex uk-flex-between">
|
||||||
|
<span>A</span>
|
||||||
|
<span class="uk-text-meta">3 票(100%)</span>
|
||||||
|
</div>
|
||||||
|
<progress class="uk-progress uk-margin-small-top" value="100" max="100"></progress>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="uk-margin-small-top">
|
||||||
|
<div class="uk-flex uk-flex-between">
|
||||||
|
<span>B</span>
|
||||||
|
<span class="uk-text-meta">0 票(0%)</span>
|
||||||
|
</div>
|
||||||
|
<progress class="uk-progress uk-margin-small-top" value="0" max="100"></progress>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="uk-margin-small-top">
|
||||||
|
<div class="uk-flex uk-flex-between">
|
||||||
|
<span>C</span>
|
||||||
|
<span class="uk-text-meta">0 票(0%)</span>
|
||||||
|
</div>
|
||||||
|
<progress class="uk-progress uk-margin-small-top" value="0" max="100"></progress>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="uk-margin">
|
||||||
|
<div class="uk-flex uk-flex-middle uk-margin-small-bottom" style="gap: 8px;">
|
||||||
|
<span class="tb-chip">2</span>
|
||||||
|
<span class="tb-chip">多选</span>
|
||||||
|
<span class="uk-text-bold">非必填</span>
|
||||||
|
<span class="uk-text-meta uk-text-small">回答数: 1</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<div class="uk-margin-small-top">
|
||||||
|
<div class="uk-flex uk-flex-between">
|
||||||
|
<span>A</span>
|
||||||
|
<span class="uk-text-meta">1 票(100%)</span>
|
||||||
|
</div>
|
||||||
|
<progress class="uk-progress uk-margin-small-top" value="100" max="100"></progress>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="uk-margin-small-top">
|
||||||
|
<div class="uk-flex uk-flex-between">
|
||||||
|
<span>B</span>
|
||||||
|
<span class="uk-text-meta">0 票(0%)</span>
|
||||||
|
</div>
|
||||||
|
<progress class="uk-progress uk-margin-small-top" value="0" max="100"></progress>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="uk-margin-small-top">
|
||||||
|
<div class="uk-flex uk-flex-between">
|
||||||
|
<span>C</span>
|
||||||
|
<span class="uk-text-meta">0 票(0%)</span>
|
||||||
|
</div>
|
||||||
|
<progress class="uk-progress uk-margin-small-top" value="0" max="100"></progress>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="uk-margin-small-top">
|
||||||
|
<div class="uk-flex uk-flex-between">
|
||||||
|
<span>D</span>
|
||||||
|
<span class="uk-text-meta">0 票(0%)</span>
|
||||||
|
</div>
|
||||||
|
<progress class="uk-progress uk-margin-small-top" value="0" max="100"></progress>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="uk-margin">
|
||||||
|
<div class="uk-flex uk-flex-middle uk-margin-small-bottom" style="gap: 8px;">
|
||||||
|
<span class="tb-chip">3</span>
|
||||||
|
<span class="tb-chip">单行文本</span>
|
||||||
|
<span class="uk-text-bold">文本1</span>
|
||||||
|
<span class="uk-text-meta uk-text-small">回答数: 0</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<div class="uk-text-meta uk-margin-small-top">已填写: 0</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="uk-margin">
|
||||||
|
<div class="uk-flex uk-flex-middle uk-margin-small-bottom" style="gap: 8px;">
|
||||||
|
<span class="tb-chip">4</span>
|
||||||
|
<span class="tb-chip">多行文本</span>
|
||||||
|
<span class="uk-text-bold">文本2</span>
|
||||||
|
<span class="uk-text-meta uk-text-small">回答数: 3</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<div class="uk-text-meta uk-margin-small-top">已填写: 3</div>
|
||||||
|
|
||||||
|
|
||||||
|
<div class="uk-margin-small-top">
|
||||||
|
<div class="uk-text-small" style="cursor:pointer; user-select:none; color:#1e87f0;" onclick="toggleFieldReplies('40')" title="点击展开或收起文本回复明细">
|
||||||
|
<span id="caret-40" style="display:inline-block; transition:transform .15s; transform:rotate(-90deg);">▾</span>
|
||||||
|
查看文本提交(3)
|
||||||
|
</div>
|
||||||
|
<div id="replies-40" hidden>
|
||||||
|
<ul class="uk-list uk-list-divider uk-margin-small-top">
|
||||||
|
|
||||||
|
<li>
|
||||||
|
<div class="uk-text-meta uk-text-small">2026-08-26 01:06</div>
|
||||||
|
<div style="white-space:pre-wrap;">ddd</div>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li>
|
||||||
|
<div class="uk-text-meta uk-text-small">2026-08-26 00:57</div>
|
||||||
|
<div style="white-space:pre-wrap;">cc</div>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li>
|
||||||
|
<div class="uk-text-meta uk-text-small">2026-08-25 19:05</div>
|
||||||
|
<div style="white-space:pre-wrap;">1212</div>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<script>
|
||||||
|
|
||||||
|
function toggleFieldReplies(id) {
|
||||||
|
var box = document.getElementById('replies-' + id);
|
||||||
|
var caret = document.getElementById('caret-' + id);
|
||||||
|
if (!box) { return; }
|
||||||
|
if (box.hasAttribute('hidden')) {
|
||||||
|
box.removeAttribute('hidden');
|
||||||
|
if (caret) { caret.style.transform = 'rotate(0deg)'; }
|
||||||
|
} else {
|
||||||
|
box.setAttribute('hidden', '');
|
||||||
|
if (caret) { caret.style.transform = 'rotate(-90deg)'; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<p class=" uk-text-right uk-text-muted uk-text-small">
|
||||||
|
<br>
|
||||||
|
<a href="/rules">社区规则</a> |
|
||||||
|
|
||||||
|
<a href="https://box.shiroko.one/_/tamakyi" target="_blank">找站长</a>
|
||||||
|
<br>
|
||||||
|
<a href="https://share.shiroko.one" target="_blank">盘</a>
|
||||||
|
| <a href="https://blog.shiroko.one" target="_blank">公告板</a>
|
||||||
|
| <a href="https://chat.shiroko.one" target="_blank">聊天室</a>
|
||||||
|
| <a href="https://status.shiroko.one" target="_blank">监控板</a>
|
||||||
|
| <a href="https://shiroko.one" target="_blank">导航页</a>
|
||||||
|
<br>Powered by NekoBox | 狼ICP备 20230101
|
||||||
|
<br>提问箱已成功存活:<span id="box_runtime"></span>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
(function () {
|
||||||
|
var create = Math.round(Date.UTC(2023, 6, 1, 18, 15, 43) / 1000);
|
||||||
|
function tick() {
|
||||||
|
var el = document.getElementById("box_runtime");
|
||||||
|
if (!el) return;
|
||||||
|
var s = Math.round((Date.now() + 8 * 3600 * 1000) / 1000) - create;
|
||||||
|
var t = [0, 0, 0, 0, 0];
|
||||||
|
if (s >= 31536000) { t[0] = s / 31536000 | 0; s %= 31536000; }
|
||||||
|
if (s >= 86400) { t[1] = s / 86400 | 0; s %= 86400; }
|
||||||
|
if (s >= 3600) { t[2] = s / 3600 | 0; s %= 3600; }
|
||||||
|
if (s >= 60) { t[3] = s / 60 | 0; s %= 60; }
|
||||||
|
if (s > 0) { t[4] = s; }
|
||||||
|
el.innerHTML = t[0] + '年 ' + t[1] + '天 ' + t[2] + '时 ' + t[3] + '分 ' + t[4] + '秒 ';
|
||||||
|
}
|
||||||
|
tick();
|
||||||
|
setInterval(tick, 1000);
|
||||||
|
})();
|
||||||
|
</script>
|
||||||
|
<br>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
var SUBMIT_I18N = {
|
||||||
|
submitting: '提交中...',
|
||||||
|
uploading: '上传中...'
|
||||||
|
};
|
||||||
|
|
||||||
|
function tbResetSubmitButtons() {
|
||||||
|
document.querySelectorAll('button[data-tb-submitting]').forEach(function(b) {
|
||||||
|
b.disabled = false;
|
||||||
|
b.removeAttribute('data-tb-submitting');
|
||||||
|
var orig = b.getAttribute('data-tb-restore');
|
||||||
|
if (orig !== null) {
|
||||||
|
b.innerHTML = orig;
|
||||||
|
b.removeAttribute('data-tb-restore');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
document.addEventListener('submit', function(e) {
|
||||||
|
var form = e.target;
|
||||||
|
if (!form || form.tagName !== 'FORM') return;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if (e.defaultPrevented || form.getAttribute('data-tb-skip-submit-feedback') === '1') {
|
||||||
|
form.removeAttribute('data-tb-skip-submit-feedback');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if (form.getAttribute('target') === '_blank') return;
|
||||||
|
|
||||||
|
|
||||||
|
var trigger = e.submitter || form.querySelector('button[type="submit"]');
|
||||||
|
|
||||||
|
|
||||||
|
var hasFile = false;
|
||||||
|
form.querySelectorAll('input[type="file"]').forEach(function(f) {
|
||||||
|
if (f.files && f.files.length > 0) hasFile = true;
|
||||||
|
});
|
||||||
|
var label = hasFile ? SUBMIT_I18N.uploading : SUBMIT_I18N.submitting;
|
||||||
|
|
||||||
|
if (trigger && trigger.tagName === 'BUTTON') {
|
||||||
|
trigger.setAttribute('data-tb-restore', trigger.innerHTML);
|
||||||
|
trigger.innerHTML = '<span uk-spinner="ratio: 0.6"></span> ' + label;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
form.querySelectorAll('button').forEach(function(b) {
|
||||||
|
b.disabled = true;
|
||||||
|
b.setAttribute('data-tb-submitting', '1');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
window.addEventListener('pageshow', tbResetSubmitButtons);
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
||||||
@@ -0,0 +1,626 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<title>投票结果</title>
|
||||||
|
<meta name="msvalidate.01" content="2F185E8E63C93635F50B3574F3B31E42" />
|
||||||
|
<meta name="description" content="狼的提问箱——一个无需注册、可匿名提问的匿名提问箱,安全地倾诉与回应。">
|
||||||
|
<meta name="keywords" content="匿名提问箱,提问箱,匿名提问,狼的提问箱,匿名问答,匿名提问网站">
|
||||||
|
|
||||||
|
<script>
|
||||||
|
(function () {
|
||||||
|
var m = document.cookie.match(/(?:^|;\s*)theme=([^;]*)/);
|
||||||
|
if (m && m[1] === 'dark') document.documentElement.setAttribute('data-theme', 'dark');
|
||||||
|
})();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<link rel="preconnect" href="https://r2.337845818.best" crossorigin>
|
||||||
|
<link rel="preconnect" href="https://cdnjs.snrat.com" crossorigin>
|
||||||
|
|
||||||
|
<link rel="stylesheet" href="https://cdnjs.snrat.com/ajax/libs/uikit/3.3.3/css/uikit.min.css"/>
|
||||||
|
|
||||||
|
<link rel="stylesheet" href="/static/css/base.css?v=20261019d"/>
|
||||||
|
|
||||||
|
<link rel="stylesheet" href="https://r2.337845818.best/tamabox/cdn/waline/client/v2/waline-no-commits.css" media="print" onload="this.media='all'"/>
|
||||||
|
<script defer src="https://cdnjs.snrat.com/ajax/libs/uikit/3.3.3/js/uikit.min.js"></script>
|
||||||
|
<script defer src="https://cdnjs.snrat.com/ajax/libs/uikit/3.3.3/js/uikit-icons.min.js"></script>
|
||||||
|
|
||||||
|
<script defer src="https://cdnjs.snrat.com/ajax/libs/dayjs/1.10.8/dayjs.min.js"></script>
|
||||||
|
<script defer src="https://cdnjs.snrat.com/ajax/libs/alpinejs/3.9.0/cdn.min.js"></script>
|
||||||
|
|
||||||
|
|
||||||
|
<script defer src="https://cdnjs.snrat.com/ajax/libs/waline/2.15.8/waline.js"></script>
|
||||||
|
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.captcha-equation-box {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
background: #f0f2f5;
|
||||||
|
border: 1px solid #dcdcdc;
|
||||||
|
border-radius: 8px;
|
||||||
|
padding: 8px 8px 8px 16px;
|
||||||
|
gap: 6px;
|
||||||
|
transition: border-color 0.2s;
|
||||||
|
}
|
||||||
|
.captcha-equation-box:focus-within {
|
||||||
|
border-color: #1e87f0;
|
||||||
|
box-shadow: 0 0 0 3px rgba(30,135,240,0.12);
|
||||||
|
}
|
||||||
|
.math-captcha-modal-question {
|
||||||
|
font-size: 1.4rem;
|
||||||
|
font-family: "Courier New", monospace;
|
||||||
|
font-weight: 700;
|
||||||
|
color: #333;
|
||||||
|
letter-spacing: 1px;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
#captcha-modal-answer {
|
||||||
|
width: 80px;
|
||||||
|
padding: 6px 10px;
|
||||||
|
text-align: center;
|
||||||
|
font-size: 1.2rem;
|
||||||
|
font-family: "Courier New", monospace;
|
||||||
|
font-weight: 600;
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
border-radius: 5px;
|
||||||
|
outline: none;
|
||||||
|
transition: border-color 0.15s, box-shadow 0.15s;
|
||||||
|
background: #fff;
|
||||||
|
}
|
||||||
|
#captcha-modal-answer:focus {
|
||||||
|
border-color: #1e87f0;
|
||||||
|
box-shadow: 0 0 0 2px rgba(30,135,240,0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
#captcha-modal-answer::-webkit-inner-spin-button,
|
||||||
|
#captcha-modal-answer::-webkit-outer-spin-button {
|
||||||
|
-webkit-appearance: none;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
#captcha-modal-answer {
|
||||||
|
-moz-appearance: textfield;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<meta property="og:site_name" content="狼的提问箱 | 匿名提问箱" />
|
||||||
|
<meta property="og:type" content="website" />
|
||||||
|
<meta property="og:title" content=" - 狼的提问箱 | 匿名提问箱" />
|
||||||
|
<meta property="og:url" content="https://box-dev-api.337845818.best/user/votes/13/results" />
|
||||||
|
<meta property="og:description" content=" - 狼的提问箱——一个无需注册、可匿名提问的匿名提问箱,安全地倾诉与回应。" />
|
||||||
|
<meta name="robots" content="noindex">
|
||||||
|
|
||||||
|
<meta property="og:image" content="?og-image=1" />
|
||||||
|
<meta property="og:image:alt" content="" />
|
||||||
|
<meta itemprop="image" content="?og-image=1"/>
|
||||||
|
<meta name="msapplication-TileImage" content=""/>
|
||||||
|
<link rel="shortcut icon" href="?og-image=1"/>
|
||||||
|
<link rel="apple-touch-icon" href="?og-image=1"/>
|
||||||
|
<link rel="icon" sizes="192x192" href="?og-image=1">
|
||||||
|
<meta name="twitter:image:src" content="?og-image=1" />
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<meta name="google-site-verification" content="fEPwRRJfiGsgwc5SINBQwZhPK8F0cwRaOvRx0YRurI4" />
|
||||||
|
|
||||||
|
<script>
|
||||||
|
window.addEventListener("load", function () {
|
||||||
|
var s = document.createElement("script");
|
||||||
|
s.src = "https://mami.shiroko.one/tamami.js";
|
||||||
|
s.setAttribute("data-website-id", "c42ebe8b-9281-4da0-83a4-8f18b3e710fe");
|
||||||
|
document.body.appendChild(s);
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<script>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
window.tbRenderQR = function (el, getOptions) {
|
||||||
|
if (!el || typeof QRCode === 'undefined') return;
|
||||||
|
var opts = getOptions();
|
||||||
|
function remoteOf(o, key) {
|
||||||
|
var v = o[key];
|
||||||
|
return (typeof v === 'string' && v.indexOf('http') === 0) ? v : '';
|
||||||
|
}
|
||||||
|
var good = window._tbQrGood || (window._tbQrGood = {});
|
||||||
|
var bad = window._tbQrBad || (window._tbQrBad = {});
|
||||||
|
|
||||||
|
function layerState(url) { return !url ? '' : (good[url] ? 1 : (bad[url] ? 0 : null)); }
|
||||||
|
var layers = [
|
||||||
|
{ url: remoteOf(opts, 'logo'), st: null, present: function (o, on) {
|
||||||
|
if (on) { } else { o.logo = undefined; o.logoWidth = undefined; o.logoHeight = undefined; o.logoBackgroundTransparent = undefined; }
|
||||||
|
} },
|
||||||
|
{ url: remoteOf(opts, 'backgroundImage'), st: null, present: function (o, on) {
|
||||||
|
if (on) { } else { o.backgroundImage = undefined; o.backgroundImageAlpha = undefined; }
|
||||||
|
} }
|
||||||
|
];
|
||||||
|
var needProbe = false;
|
||||||
|
for (var i = 0; i < layers.length; i++) {
|
||||||
|
layers[i].st = layerState(layers[i].url);
|
||||||
|
if (layers[i].st === null) needProbe = true;
|
||||||
|
}
|
||||||
|
function paint(states) {
|
||||||
|
var o = {};
|
||||||
|
for (var k in opts) o[k] = opts[k];
|
||||||
|
for (var j = 0; j < layers.length; j++) layers[j].present(o, states[j] === 1);
|
||||||
|
el.innerHTML = '';
|
||||||
|
new QRCode(el, o);
|
||||||
|
}
|
||||||
|
|
||||||
|
var initStates = [];
|
||||||
|
for (var n = 0; n < layers.length; n++) initStates.push(layers[n].st === 1 ? 1 : 0);
|
||||||
|
paint(initStates);
|
||||||
|
if (!needProbe) return;
|
||||||
|
|
||||||
|
var pending = 0, cross = opts.crossOrigin || 'anonymous';
|
||||||
|
layers.forEach(function (L) {
|
||||||
|
if (L.st !== null) return;
|
||||||
|
pending++;
|
||||||
|
var im = new Image();
|
||||||
|
im.onload = function () { good[L.url] = true; L.st = 1; onDone(); };
|
||||||
|
im.onerror = function () { bad[L.url] = true; L.st = 0; onDone(); };
|
||||||
|
if (cross) im.crossOrigin = cross;
|
||||||
|
im.src = L.url;
|
||||||
|
});
|
||||||
|
function onDone() {
|
||||||
|
if (--pending > 0) return;
|
||||||
|
var finalStates = [];
|
||||||
|
for (var m = 0; m < layers.length; m++) finalStates.push(layers[m].st === 1 ? 1 : 0);
|
||||||
|
var changed = false;
|
||||||
|
for (var q = 0; q < finalStates.length; q++) if (finalStates[q] !== initStates[q]) changed = true;
|
||||||
|
if (changed) paint(finalStates);
|
||||||
|
}
|
||||||
|
|
||||||
|
setTimeout(function () { if (pending > 0) { pending = 0; onDone(); } }, 3000);
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
<nav class="uk-navbar-container uk-margin tb-navbar" uk-navbar>
|
||||||
|
<div class="uk-navbar-center">
|
||||||
|
<div class="uk-navbar-center-left">
|
||||||
|
<div>
|
||||||
|
<ul class="uk-navbar-nav">
|
||||||
|
|
||||||
|
<li><a href="/explore">探索</a></li>
|
||||||
|
|
||||||
|
|
||||||
|
<li><a href="/_/admin6">我的</a></li>
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<a class="uk-navbar-item uk-logo" href="/"><span class="emoji-placeholder" aria-label="random animal">🐺</span>的提问箱</a>
|
||||||
|
|
||||||
|
<div class="uk-navbar-center-right">
|
||||||
|
<div>
|
||||||
|
|
||||||
|
<ul class="uk-navbar-nav">
|
||||||
|
<li><a href="/user/questions">提问</a></li>
|
||||||
|
</ul>
|
||||||
|
<ul class="uk-navbar-nav">
|
||||||
|
<li><a href="/user/profile">设置</a></li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<ul class="uk-navbar-nav tb-nav-utils">
|
||||||
|
<li>
|
||||||
|
<a href="#" id="theme-toggle" title="切换深色/浅色模式" aria-label="切换深色/浅色模式">
|
||||||
|
<span class="tb-icon-light"><svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M20.5 14.3A8.6 8.6 0 0 1 9.7 3.5a8.6 8.6 0 1 0 10.8 10.8z"/></svg></span><span class="tb-icon-dark"><svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><circle cx="12" cy="12" r="4"/><path d="M12 2.5v2M12 19.5v2M2.5 12h2M19.5 12h2M5.2 5.2l1.4 1.4M17.4 17.4l1.4 1.4M18.8 5.2l-1.4 1.4M6.6 17.4l-1.4 1.4"/></svg></span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
document.addEventListener("DOMContentLoaded", function() {
|
||||||
|
const emojis = ["🐺","🐗","🐻","🐨","🐼","🐹","🐭","🐰","🦊","🐮","🐷","🐽","🐸","🐒","🦍","🐔","🐧","🐦","🐤","🐦⬛","🦅","🦉","🦇","🐴","🦄","🐝","🦎","🦖","🦕","🐙","🦑","🦐","🦞","🦀","🐡","🐠","🐟","🐬","🐳","🐋","🦈","🐊","🐅","🐆","🦓","🦍","🦧","🐘","🦛","🦏","🐪","🐫","🦒","🦘","🐃","🐂","🐄","🐎","🐖","🐏","🐑","🦙","🐐","🦌","🐕","🐩","🦮","🐕🦺","🐈","🐋","🐳","🐬","🐉","🐲"];
|
||||||
|
const placeholder = document.querySelector('.emoji-placeholder');
|
||||||
|
if (placeholder) {
|
||||||
|
placeholder.textContent = emojis[Math.floor(Math.random() * emojis.length)];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
<div id="tb-mobile-utils">
|
||||||
|
|
||||||
|
<button type="button" id="theme-toggle-mobile" class="uk-button uk-button-default uk-button-small"
|
||||||
|
title="切换深色/浅色模式" aria-label="切换深色/浅色模式">
|
||||||
|
<span class="tb-icon-light"><svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M20.5 14.3A8.6 8.6 0 0 1 9.7 3.5a8.6 8.6 0 1 0 10.8 10.8z"/></svg></span><span class="tb-icon-dark"><svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><circle cx="12" cy="12" r="4"/><path d="M12 2.5v2M12 19.5v2M2.5 12h2M19.5 12h2M5.2 5.2l1.4 1.4M17.4 17.4l1.4 1.4M18.8 5.2l-1.4 1.4M6.6 17.4l-1.4 1.4"/></svg></span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
(function() {
|
||||||
|
|
||||||
|
var THEME_COOKIE = 'theme';
|
||||||
|
function getTheme() {
|
||||||
|
var m = document.cookie.match(/(?:^|;\s*)theme=([^;]*)/);
|
||||||
|
return m ? m[1] : '';
|
||||||
|
}
|
||||||
|
function applyTheme(theme) {
|
||||||
|
if (theme === 'dark') {
|
||||||
|
document.documentElement.setAttribute('data-theme', 'dark');
|
||||||
|
} else {
|
||||||
|
document.documentElement.removeAttribute('data-theme');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function toggleTheme() {
|
||||||
|
var next = getTheme() === 'dark' ? 'light' : 'dark';
|
||||||
|
applyTheme(next);
|
||||||
|
var expires = new Date(Date.now() + 365 * 24 * 3600 * 1000).toUTCString();
|
||||||
|
document.cookie = THEME_COOKIE + '=' + next + '; path=/; max-age=' + (365 * 24 * 3600) + '; SameSite=Lax';
|
||||||
|
}
|
||||||
|
|
||||||
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
|
|
||||||
|
var buttons = document.querySelectorAll('#theme-toggle, #theme-toggle-mobile');
|
||||||
|
buttons.forEach(function(btn) {
|
||||||
|
btn.addEventListener('click', function(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
toggleTheme();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
var langSel = document.getElementById('mobile-lang-select');
|
||||||
|
if (langSel) {
|
||||||
|
langSel.addEventListener('change', function() {
|
||||||
|
if (!this.value) return;
|
||||||
|
var to = window.location.pathname + window.location.search;
|
||||||
|
window.location.href = '/i18n/' + encodeURIComponent(this.value) + '?to=' + encodeURIComponent(to);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
})();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
<div class="uk-container uk-container-xsmall">
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<div id="math-captcha-modal" uk-modal>
|
||||||
|
<div class="uk-modal-dialog uk-modal-body uk-text-center">
|
||||||
|
<h3 class="uk-modal-title">人机验证</h3>
|
||||||
|
<p class="uk-text-meta">请计算下方的算术题以验证你不是机器人</p>
|
||||||
|
<div class="captcha-equation-box">
|
||||||
|
<span id="captcha-modal-question" class="math-captcha-modal-question">加载中...</span>
|
||||||
|
<input type="number" id="captcha-modal-answer" placeholder="?" autocomplete="off" inputmode="numeric">
|
||||||
|
</div>
|
||||||
|
<div style="margin-top:6px;">
|
||||||
|
<button type="button" class="uk-button uk-button-text uk-text-small" id="captcha-modal-refresh">换一题</button>
|
||||||
|
</div>
|
||||||
|
<div id="captcha-modal-error" class="uk-text-danger uk-text-small" style="display:none;min-height:20px;"></div>
|
||||||
|
<div class="uk-margin-small-top">
|
||||||
|
<button type="button" class="uk-button uk-button-primary" id="captcha-modal-submit">提交</button>
|
||||||
|
<button type="button" class="uk-button uk-button-default uk-modal-close">取消</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
var CAPTCHA_I18N = {
|
||||||
|
loading: "加载中...",
|
||||||
|
loadFailed: "加载失败",
|
||||||
|
loadRetry: "加载失败,请重试",
|
||||||
|
inputAnswer: "请输入答案",
|
||||||
|
wrongAnswer: "答案错误,请重新计算",
|
||||||
|
verifyFailed: "验证失败,请重试",
|
||||||
|
needPassword: "此提问箱需要密码",
|
||||||
|
needEmail: "请填写接收通知的邮箱地址"
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
(function() {
|
||||||
|
var captchaId = '';
|
||||||
|
var pendingForm = null;
|
||||||
|
var pendingNeedPassword = false;
|
||||||
|
var verifying = false;
|
||||||
|
|
||||||
|
function fetchCaptcha() {
|
||||||
|
var qEl = document.getElementById('captcha-modal-question');
|
||||||
|
var errEl = document.getElementById('captcha-modal-error');
|
||||||
|
var ansEl = document.getElementById('captcha-modal-answer');
|
||||||
|
qEl.textContent = CAPTCHA_I18N.loading;
|
||||||
|
fetch('/api/captcha/generate')
|
||||||
|
.then(function(r) { return r.json(); })
|
||||||
|
.then(function(data) {
|
||||||
|
if (data.code === 0 && data.data) {
|
||||||
|
captchaId = data.data.id;
|
||||||
|
qEl.textContent = data.data.question;
|
||||||
|
if (errEl) errEl.style.display = 'none';
|
||||||
|
if (ansEl) { ansEl.value = ''; ansEl.focus(); }
|
||||||
|
} else {
|
||||||
|
qEl.textContent = CAPTCHA_I18N.loadFailed;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(function() {
|
||||||
|
qEl.textContent = CAPTCHA_I18N.loadRetry;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function getCSRFToken() {
|
||||||
|
var input = document.querySelector('input[name="_csrf"]');
|
||||||
|
return input ? input.value : '';
|
||||||
|
}
|
||||||
|
|
||||||
|
function doSubmit(form) {
|
||||||
|
|
||||||
|
var ans = document.getElementById('captcha-modal-answer').value.trim();
|
||||||
|
var hidden = form.querySelector('[name="g-recaptcha-response"]');
|
||||||
|
if (hidden) hidden.value = captchaId + ':' + (ans || '0');
|
||||||
|
|
||||||
|
UIkit.modal('#math-captcha-modal').hide();
|
||||||
|
|
||||||
|
|
||||||
|
if (pendingNeedPassword) {
|
||||||
|
UIkit.modal.prompt(CAPTCHA_I18N.needPassword, '', 'password')
|
||||||
|
.then(function(password) {
|
||||||
|
if (password) {
|
||||||
|
var pwInput = document.getElementById('ask_password_input');
|
||||||
|
if (pwInput) pwInput.value = password;
|
||||||
|
form.submit();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
form.submit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
document.getElementById('captcha-modal-submit').addEventListener('click', function() {
|
||||||
|
if (verifying) return;
|
||||||
|
var ans = document.getElementById('captcha-modal-answer').value.trim();
|
||||||
|
if (!ans) {
|
||||||
|
var errEl = document.getElementById('captcha-modal-error');
|
||||||
|
errEl.textContent = CAPTCHA_I18N.inputAnswer;
|
||||||
|
errEl.style.display = 'block';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
verifying = true;
|
||||||
|
fetch('/api/captcha/verify', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'X-CSRF-Token': getCSRFToken()
|
||||||
|
},
|
||||||
|
body: JSON.stringify({ id: captchaId, answer: parseInt(ans, 10) })
|
||||||
|
})
|
||||||
|
.then(function(r) { return r.json(); })
|
||||||
|
.then(function(data) {
|
||||||
|
verifying = false;
|
||||||
|
if (data.correct) {
|
||||||
|
if (pendingForm) doSubmit(pendingForm);
|
||||||
|
} else {
|
||||||
|
var errEl = document.getElementById('captcha-modal-error');
|
||||||
|
errEl.textContent = CAPTCHA_I18N.wrongAnswer;
|
||||||
|
errEl.style.display = 'block';
|
||||||
|
fetchCaptcha();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(function() {
|
||||||
|
verifying = false;
|
||||||
|
var errEl = document.getElementById('captcha-modal-error');
|
||||||
|
errEl.textContent = CAPTCHA_I18N.verifyFailed;
|
||||||
|
errEl.style.display = 'block';
|
||||||
|
fetchCaptcha();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
document.getElementById('captcha-modal-answer').addEventListener('keydown', function(e) {
|
||||||
|
if (e.key === 'Enter') {
|
||||||
|
e.preventDefault();
|
||||||
|
document.getElementById('captcha-modal-submit').click();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
document.getElementById('captcha-modal-refresh').addEventListener('click', fetchCaptcha);
|
||||||
|
|
||||||
|
|
||||||
|
document.addEventListener('click', function(e) {
|
||||||
|
var btn = e.target.closest('.math-captcha-trigger');
|
||||||
|
if (!btn) return;
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
var form = btn.closest('form');
|
||||||
|
if (!form) return;
|
||||||
|
pendingForm = form;
|
||||||
|
|
||||||
|
|
||||||
|
pendingNeedPassword = !!(form.querySelector('#ask_password_input'));
|
||||||
|
|
||||||
|
|
||||||
|
var notifyCb = document.getElementById('notify-checkbox');
|
||||||
|
var emailInput = document.getElementById('email-input');
|
||||||
|
if (notifyCb && notifyCb.checked && emailInput && emailInput.value.trim() === '') {
|
||||||
|
UIkit.modal.alert(CAPTCHA_I18N.needEmail);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
fetchCaptcha();
|
||||||
|
UIkit.modal('#math-captcha-modal').show();
|
||||||
|
});
|
||||||
|
})();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
<div class="uk-flex uk-flex-between uk-flex-middle uk-margin-bottom">
|
||||||
|
<h3 class="uk-margin-remove">投票结果:吃什么</h3>
|
||||||
|
<div class="uk-flex uk-flex-middle" style="gap: 8px;">
|
||||||
|
<a class="uk-button uk-button-default uk-button-small" href="/user/votes/13/export">导出 CSV</a>
|
||||||
|
<a class="uk-button uk-button-default uk-button-small" href="/user/questions#votes">返回</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="uk-card uk-card-default uk-card-small uk-card-body uk-margin-bottom">
|
||||||
|
<div class="uk-text-large uk-text-bold">0</div>
|
||||||
|
<div class="uk-text-meta">总参与人数</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<h4>投票结果</h4>
|
||||||
|
<div class="uk-card uk-card-default uk-card-small uk-card-body uk-margin-bottom">
|
||||||
|
|
||||||
|
<div class="uk-margin">
|
||||||
|
<div class="uk-flex uk-flex-middle uk-margin-small-bottom" style="gap: 8px;">
|
||||||
|
<span class="tb-chip">1</span>
|
||||||
|
<span class="tb-chip">单行文本</span>
|
||||||
|
<span class="uk-text-bold">是啊,吃什么?</span>
|
||||||
|
<span class="uk-text-meta uk-text-small">回答数: 0</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<div class="uk-text-meta uk-margin-small-top">已填写: 0</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<script>
|
||||||
|
|
||||||
|
function toggleFieldReplies(id) {
|
||||||
|
var box = document.getElementById('replies-' + id);
|
||||||
|
var caret = document.getElementById('caret-' + id);
|
||||||
|
if (!box) { return; }
|
||||||
|
if (box.hasAttribute('hidden')) {
|
||||||
|
box.removeAttribute('hidden');
|
||||||
|
if (caret) { caret.style.transform = 'rotate(0deg)'; }
|
||||||
|
} else {
|
||||||
|
box.setAttribute('hidden', '');
|
||||||
|
if (caret) { caret.style.transform = 'rotate(-90deg)'; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<p class=" uk-text-right uk-text-muted uk-text-small">
|
||||||
|
<br>
|
||||||
|
<a href="/rules">社区规则</a> |
|
||||||
|
|
||||||
|
<a href="https://box.shiroko.one/_/tamakyi" target="_blank">找站长</a>
|
||||||
|
<br>
|
||||||
|
<a href="https://share.shiroko.one" target="_blank">盘</a>
|
||||||
|
| <a href="https://blog.shiroko.one" target="_blank">公告板</a>
|
||||||
|
| <a href="https://chat.shiroko.one" target="_blank">聊天室</a>
|
||||||
|
| <a href="https://status.shiroko.one" target="_blank">监控板</a>
|
||||||
|
| <a href="https://shiroko.one" target="_blank">导航页</a>
|
||||||
|
<br>Powered by NekoBox | 狼ICP备 20230101
|
||||||
|
<br>提问箱已成功存活:<span id="box_runtime"></span>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
(function () {
|
||||||
|
var create = Math.round(Date.UTC(2023, 6, 1, 18, 15, 43) / 1000);
|
||||||
|
function tick() {
|
||||||
|
var el = document.getElementById("box_runtime");
|
||||||
|
if (!el) return;
|
||||||
|
var s = Math.round((Date.now() + 8 * 3600 * 1000) / 1000) - create;
|
||||||
|
var t = [0, 0, 0, 0, 0];
|
||||||
|
if (s >= 31536000) { t[0] = s / 31536000 | 0; s %= 31536000; }
|
||||||
|
if (s >= 86400) { t[1] = s / 86400 | 0; s %= 86400; }
|
||||||
|
if (s >= 3600) { t[2] = s / 3600 | 0; s %= 3600; }
|
||||||
|
if (s >= 60) { t[3] = s / 60 | 0; s %= 60; }
|
||||||
|
if (s > 0) { t[4] = s; }
|
||||||
|
el.innerHTML = t[0] + '年 ' + t[1] + '天 ' + t[2] + '时 ' + t[3] + '分 ' + t[4] + '秒 ';
|
||||||
|
}
|
||||||
|
tick();
|
||||||
|
setInterval(tick, 1000);
|
||||||
|
})();
|
||||||
|
</script>
|
||||||
|
<br>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
var SUBMIT_I18N = {
|
||||||
|
submitting: '提交中...',
|
||||||
|
uploading: '上传中...'
|
||||||
|
};
|
||||||
|
|
||||||
|
function tbResetSubmitButtons() {
|
||||||
|
document.querySelectorAll('button[data-tb-submitting]').forEach(function(b) {
|
||||||
|
b.disabled = false;
|
||||||
|
b.removeAttribute('data-tb-submitting');
|
||||||
|
var orig = b.getAttribute('data-tb-restore');
|
||||||
|
if (orig !== null) {
|
||||||
|
b.innerHTML = orig;
|
||||||
|
b.removeAttribute('data-tb-restore');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
document.addEventListener('submit', function(e) {
|
||||||
|
var form = e.target;
|
||||||
|
if (!form || form.tagName !== 'FORM') return;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if (e.defaultPrevented || form.getAttribute('data-tb-skip-submit-feedback') === '1') {
|
||||||
|
form.removeAttribute('data-tb-skip-submit-feedback');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if (form.getAttribute('target') === '_blank') return;
|
||||||
|
|
||||||
|
|
||||||
|
var trigger = e.submitter || form.querySelector('button[type="submit"]');
|
||||||
|
|
||||||
|
|
||||||
|
var hasFile = false;
|
||||||
|
form.querySelectorAll('input[type="file"]').forEach(function(f) {
|
||||||
|
if (f.files && f.files.length > 0) hasFile = true;
|
||||||
|
});
|
||||||
|
var label = hasFile ? SUBMIT_I18N.uploading : SUBMIT_I18N.submitting;
|
||||||
|
|
||||||
|
if (trigger && trigger.tagName === 'BUTTON') {
|
||||||
|
trigger.setAttribute('data-tb-restore', trigger.innerHTML);
|
||||||
|
trigger.innerHTML = '<span uk-spinner="ratio: 0.6"></span> ' + label;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
form.querySelectorAll('button').forEach(function(b) {
|
||||||
|
b.disabled = true;
|
||||||
|
b.setAttribute('data-tb-submitting', '1');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
window.addEventListener('pageshow', tbResetSubmitButtons);
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
||||||
@@ -0,0 +1,693 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<title>投票结果</title>
|
||||||
|
<meta name="msvalidate.01" content="2F185E8E63C93635F50B3574F3B31E42" />
|
||||||
|
<meta name="description" content="狼的提问箱——一个无需注册、可匿名提问的匿名提问箱,安全地倾诉与回应。">
|
||||||
|
<meta name="keywords" content="匿名提问箱,提问箱,匿名提问,狼的提问箱,匿名问答,匿名提问网站">
|
||||||
|
|
||||||
|
<script>
|
||||||
|
(function () {
|
||||||
|
var m = document.cookie.match(/(?:^|;\s*)theme=([^;]*)/);
|
||||||
|
if (m && m[1] === 'dark') document.documentElement.setAttribute('data-theme', 'dark');
|
||||||
|
})();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<link rel="preconnect" href="https://r2.337845818.best" crossorigin>
|
||||||
|
<link rel="preconnect" href="https://cdnjs.snrat.com" crossorigin>
|
||||||
|
|
||||||
|
<link rel="stylesheet" href="https://cdnjs.snrat.com/ajax/libs/uikit/3.3.3/css/uikit.min.css"/>
|
||||||
|
|
||||||
|
<link rel="stylesheet" href="/static/css/base.css?v=20261019d"/>
|
||||||
|
|
||||||
|
<link rel="stylesheet" href="https://r2.337845818.best/tamabox/cdn/waline/client/v2/waline-no-commits.css" media="print" onload="this.media='all'"/>
|
||||||
|
<script defer src="https://cdnjs.snrat.com/ajax/libs/uikit/3.3.3/js/uikit.min.js"></script>
|
||||||
|
<script defer src="https://cdnjs.snrat.com/ajax/libs/uikit/3.3.3/js/uikit-icons.min.js"></script>
|
||||||
|
|
||||||
|
<script defer src="https://cdnjs.snrat.com/ajax/libs/dayjs/1.10.8/dayjs.min.js"></script>
|
||||||
|
<script defer src="https://cdnjs.snrat.com/ajax/libs/alpinejs/3.9.0/cdn.min.js"></script>
|
||||||
|
|
||||||
|
|
||||||
|
<script defer src="https://cdnjs.snrat.com/ajax/libs/waline/2.15.8/waline.js"></script>
|
||||||
|
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.captcha-equation-box {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
background: #f0f2f5;
|
||||||
|
border: 1px solid #dcdcdc;
|
||||||
|
border-radius: 8px;
|
||||||
|
padding: 8px 8px 8px 16px;
|
||||||
|
gap: 6px;
|
||||||
|
transition: border-color 0.2s;
|
||||||
|
}
|
||||||
|
.captcha-equation-box:focus-within {
|
||||||
|
border-color: #1e87f0;
|
||||||
|
box-shadow: 0 0 0 3px rgba(30,135,240,0.12);
|
||||||
|
}
|
||||||
|
.math-captcha-modal-question {
|
||||||
|
font-size: 1.4rem;
|
||||||
|
font-family: "Courier New", monospace;
|
||||||
|
font-weight: 700;
|
||||||
|
color: #333;
|
||||||
|
letter-spacing: 1px;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
#captcha-modal-answer {
|
||||||
|
width: 80px;
|
||||||
|
padding: 6px 10px;
|
||||||
|
text-align: center;
|
||||||
|
font-size: 1.2rem;
|
||||||
|
font-family: "Courier New", monospace;
|
||||||
|
font-weight: 600;
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
border-radius: 5px;
|
||||||
|
outline: none;
|
||||||
|
transition: border-color 0.15s, box-shadow 0.15s;
|
||||||
|
background: #fff;
|
||||||
|
}
|
||||||
|
#captcha-modal-answer:focus {
|
||||||
|
border-color: #1e87f0;
|
||||||
|
box-shadow: 0 0 0 2px rgba(30,135,240,0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
#captcha-modal-answer::-webkit-inner-spin-button,
|
||||||
|
#captcha-modal-answer::-webkit-outer-spin-button {
|
||||||
|
-webkit-appearance: none;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
#captcha-modal-answer {
|
||||||
|
-moz-appearance: textfield;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<meta property="og:site_name" content="狼的提问箱 | 匿名提问箱" />
|
||||||
|
<meta property="og:type" content="website" />
|
||||||
|
<meta property="og:title" content=" - 狼的提问箱 | 匿名提问箱" />
|
||||||
|
<meta property="og:url" content="https://box-dev-api.337845818.best/user/votes/3/results" />
|
||||||
|
<meta property="og:description" content=" - 狼的提问箱——一个无需注册、可匿名提问的匿名提问箱,安全地倾诉与回应。" />
|
||||||
|
<meta name="robots" content="noindex">
|
||||||
|
|
||||||
|
<meta property="og:image" content="?og-image=1" />
|
||||||
|
<meta property="og:image:alt" content="" />
|
||||||
|
<meta itemprop="image" content="?og-image=1"/>
|
||||||
|
<meta name="msapplication-TileImage" content=""/>
|
||||||
|
<link rel="shortcut icon" href="?og-image=1"/>
|
||||||
|
<link rel="apple-touch-icon" href="?og-image=1"/>
|
||||||
|
<link rel="icon" sizes="192x192" href="?og-image=1">
|
||||||
|
<meta name="twitter:image:src" content="?og-image=1" />
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<meta name="google-site-verification" content="fEPwRRJfiGsgwc5SINBQwZhPK8F0cwRaOvRx0YRurI4" />
|
||||||
|
|
||||||
|
<script>
|
||||||
|
window.addEventListener("load", function () {
|
||||||
|
var s = document.createElement("script");
|
||||||
|
s.src = "https://mami.shiroko.one/tamami.js";
|
||||||
|
s.setAttribute("data-website-id", "c42ebe8b-9281-4da0-83a4-8f18b3e710fe");
|
||||||
|
document.body.appendChild(s);
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<script>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
window.tbRenderQR = function (el, getOptions) {
|
||||||
|
if (!el || typeof QRCode === 'undefined') return;
|
||||||
|
var opts = getOptions();
|
||||||
|
function remoteOf(o, key) {
|
||||||
|
var v = o[key];
|
||||||
|
return (typeof v === 'string' && v.indexOf('http') === 0) ? v : '';
|
||||||
|
}
|
||||||
|
var good = window._tbQrGood || (window._tbQrGood = {});
|
||||||
|
var bad = window._tbQrBad || (window._tbQrBad = {});
|
||||||
|
|
||||||
|
function layerState(url) { return !url ? '' : (good[url] ? 1 : (bad[url] ? 0 : null)); }
|
||||||
|
var layers = [
|
||||||
|
{ url: remoteOf(opts, 'logo'), st: null, present: function (o, on) {
|
||||||
|
if (on) { } else { o.logo = undefined; o.logoWidth = undefined; o.logoHeight = undefined; o.logoBackgroundTransparent = undefined; }
|
||||||
|
} },
|
||||||
|
{ url: remoteOf(opts, 'backgroundImage'), st: null, present: function (o, on) {
|
||||||
|
if (on) { } else { o.backgroundImage = undefined; o.backgroundImageAlpha = undefined; }
|
||||||
|
} }
|
||||||
|
];
|
||||||
|
var needProbe = false;
|
||||||
|
for (var i = 0; i < layers.length; i++) {
|
||||||
|
layers[i].st = layerState(layers[i].url);
|
||||||
|
if (layers[i].st === null) needProbe = true;
|
||||||
|
}
|
||||||
|
function paint(states) {
|
||||||
|
var o = {};
|
||||||
|
for (var k in opts) o[k] = opts[k];
|
||||||
|
for (var j = 0; j < layers.length; j++) layers[j].present(o, states[j] === 1);
|
||||||
|
el.innerHTML = '';
|
||||||
|
new QRCode(el, o);
|
||||||
|
}
|
||||||
|
|
||||||
|
var initStates = [];
|
||||||
|
for (var n = 0; n < layers.length; n++) initStates.push(layers[n].st === 1 ? 1 : 0);
|
||||||
|
paint(initStates);
|
||||||
|
if (!needProbe) return;
|
||||||
|
|
||||||
|
var pending = 0, cross = opts.crossOrigin || 'anonymous';
|
||||||
|
layers.forEach(function (L) {
|
||||||
|
if (L.st !== null) return;
|
||||||
|
pending++;
|
||||||
|
var im = new Image();
|
||||||
|
im.onload = function () { good[L.url] = true; L.st = 1; onDone(); };
|
||||||
|
im.onerror = function () { bad[L.url] = true; L.st = 0; onDone(); };
|
||||||
|
if (cross) im.crossOrigin = cross;
|
||||||
|
im.src = L.url;
|
||||||
|
});
|
||||||
|
function onDone() {
|
||||||
|
if (--pending > 0) return;
|
||||||
|
var finalStates = [];
|
||||||
|
for (var m = 0; m < layers.length; m++) finalStates.push(layers[m].st === 1 ? 1 : 0);
|
||||||
|
var changed = false;
|
||||||
|
for (var q = 0; q < finalStates.length; q++) if (finalStates[q] !== initStates[q]) changed = true;
|
||||||
|
if (changed) paint(finalStates);
|
||||||
|
}
|
||||||
|
|
||||||
|
setTimeout(function () { if (pending > 0) { pending = 0; onDone(); } }, 3000);
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
<nav class="uk-navbar-container uk-margin tb-navbar" uk-navbar>
|
||||||
|
<div class="uk-navbar-center">
|
||||||
|
<div class="uk-navbar-center-left">
|
||||||
|
<div>
|
||||||
|
<ul class="uk-navbar-nav">
|
||||||
|
|
||||||
|
<li><a href="/explore">探索</a></li>
|
||||||
|
|
||||||
|
|
||||||
|
<li><a href="/_/admin6">我的</a></li>
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<a class="uk-navbar-item uk-logo" href="/"><span class="emoji-placeholder" aria-label="random animal">🐺</span>的提问箱</a>
|
||||||
|
|
||||||
|
<div class="uk-navbar-center-right">
|
||||||
|
<div>
|
||||||
|
|
||||||
|
<ul class="uk-navbar-nav">
|
||||||
|
<li><a href="/user/questions">提问</a></li>
|
||||||
|
</ul>
|
||||||
|
<ul class="uk-navbar-nav">
|
||||||
|
<li><a href="/user/profile">设置</a></li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<ul class="uk-navbar-nav tb-nav-utils">
|
||||||
|
<li>
|
||||||
|
<a href="#" id="theme-toggle" title="切换深色/浅色模式" aria-label="切换深色/浅色模式">
|
||||||
|
<span class="tb-icon-light"><svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M20.5 14.3A8.6 8.6 0 0 1 9.7 3.5a8.6 8.6 0 1 0 10.8 10.8z"/></svg></span><span class="tb-icon-dark"><svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><circle cx="12" cy="12" r="4"/><path d="M12 2.5v2M12 19.5v2M2.5 12h2M19.5 12h2M5.2 5.2l1.4 1.4M17.4 17.4l1.4 1.4M18.8 5.2l-1.4 1.4M6.6 17.4l-1.4 1.4"/></svg></span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
document.addEventListener("DOMContentLoaded", function() {
|
||||||
|
const emojis = ["🐺","🐗","🐻","🐨","🐼","🐹","🐭","🐰","🦊","🐮","🐷","🐽","🐸","🐒","🦍","🐔","🐧","🐦","🐤","🐦⬛","🦅","🦉","🦇","🐴","🦄","🐝","🦎","🦖","🦕","🐙","🦑","🦐","🦞","🦀","🐡","🐠","🐟","🐬","🐳","🐋","🦈","🐊","🐅","🐆","🦓","🦍","🦧","🐘","🦛","🦏","🐪","🐫","🦒","🦘","🐃","🐂","🐄","🐎","🐖","🐏","🐑","🦙","🐐","🦌","🐕","🐩","🦮","🐕🦺","🐈","🐋","🐳","🐬","🐉","🐲"];
|
||||||
|
const placeholder = document.querySelector('.emoji-placeholder');
|
||||||
|
if (placeholder) {
|
||||||
|
placeholder.textContent = emojis[Math.floor(Math.random() * emojis.length)];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
<div id="tb-mobile-utils">
|
||||||
|
|
||||||
|
<button type="button" id="theme-toggle-mobile" class="uk-button uk-button-default uk-button-small"
|
||||||
|
title="切换深色/浅色模式" aria-label="切换深色/浅色模式">
|
||||||
|
<span class="tb-icon-light"><svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M20.5 14.3A8.6 8.6 0 0 1 9.7 3.5a8.6 8.6 0 1 0 10.8 10.8z"/></svg></span><span class="tb-icon-dark"><svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><circle cx="12" cy="12" r="4"/><path d="M12 2.5v2M12 19.5v2M2.5 12h2M19.5 12h2M5.2 5.2l1.4 1.4M17.4 17.4l1.4 1.4M18.8 5.2l-1.4 1.4M6.6 17.4l-1.4 1.4"/></svg></span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
(function() {
|
||||||
|
|
||||||
|
var THEME_COOKIE = 'theme';
|
||||||
|
function getTheme() {
|
||||||
|
var m = document.cookie.match(/(?:^|;\s*)theme=([^;]*)/);
|
||||||
|
return m ? m[1] : '';
|
||||||
|
}
|
||||||
|
function applyTheme(theme) {
|
||||||
|
if (theme === 'dark') {
|
||||||
|
document.documentElement.setAttribute('data-theme', 'dark');
|
||||||
|
} else {
|
||||||
|
document.documentElement.removeAttribute('data-theme');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function toggleTheme() {
|
||||||
|
var next = getTheme() === 'dark' ? 'light' : 'dark';
|
||||||
|
applyTheme(next);
|
||||||
|
var expires = new Date(Date.now() + 365 * 24 * 3600 * 1000).toUTCString();
|
||||||
|
document.cookie = THEME_COOKIE + '=' + next + '; path=/; max-age=' + (365 * 24 * 3600) + '; SameSite=Lax';
|
||||||
|
}
|
||||||
|
|
||||||
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
|
|
||||||
|
var buttons = document.querySelectorAll('#theme-toggle, #theme-toggle-mobile');
|
||||||
|
buttons.forEach(function(btn) {
|
||||||
|
btn.addEventListener('click', function(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
toggleTheme();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
var langSel = document.getElementById('mobile-lang-select');
|
||||||
|
if (langSel) {
|
||||||
|
langSel.addEventListener('change', function() {
|
||||||
|
if (!this.value) return;
|
||||||
|
var to = window.location.pathname + window.location.search;
|
||||||
|
window.location.href = '/i18n/' + encodeURIComponent(this.value) + '?to=' + encodeURIComponent(to);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
})();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
<div class="uk-container uk-container-xsmall">
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<div id="math-captcha-modal" uk-modal>
|
||||||
|
<div class="uk-modal-dialog uk-modal-body uk-text-center">
|
||||||
|
<h3 class="uk-modal-title">人机验证</h3>
|
||||||
|
<p class="uk-text-meta">请计算下方的算术题以验证你不是机器人</p>
|
||||||
|
<div class="captcha-equation-box">
|
||||||
|
<span id="captcha-modal-question" class="math-captcha-modal-question">加载中...</span>
|
||||||
|
<input type="number" id="captcha-modal-answer" placeholder="?" autocomplete="off" inputmode="numeric">
|
||||||
|
</div>
|
||||||
|
<div style="margin-top:6px;">
|
||||||
|
<button type="button" class="uk-button uk-button-text uk-text-small" id="captcha-modal-refresh">换一题</button>
|
||||||
|
</div>
|
||||||
|
<div id="captcha-modal-error" class="uk-text-danger uk-text-small" style="display:none;min-height:20px;"></div>
|
||||||
|
<div class="uk-margin-small-top">
|
||||||
|
<button type="button" class="uk-button uk-button-primary" id="captcha-modal-submit">提交</button>
|
||||||
|
<button type="button" class="uk-button uk-button-default uk-modal-close">取消</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
var CAPTCHA_I18N = {
|
||||||
|
loading: "加载中...",
|
||||||
|
loadFailed: "加载失败",
|
||||||
|
loadRetry: "加载失败,请重试",
|
||||||
|
inputAnswer: "请输入答案",
|
||||||
|
wrongAnswer: "答案错误,请重新计算",
|
||||||
|
verifyFailed: "验证失败,请重试",
|
||||||
|
needPassword: "此提问箱需要密码",
|
||||||
|
needEmail: "请填写接收通知的邮箱地址"
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
(function() {
|
||||||
|
var captchaId = '';
|
||||||
|
var pendingForm = null;
|
||||||
|
var pendingNeedPassword = false;
|
||||||
|
var verifying = false;
|
||||||
|
|
||||||
|
function fetchCaptcha() {
|
||||||
|
var qEl = document.getElementById('captcha-modal-question');
|
||||||
|
var errEl = document.getElementById('captcha-modal-error');
|
||||||
|
var ansEl = document.getElementById('captcha-modal-answer');
|
||||||
|
qEl.textContent = CAPTCHA_I18N.loading;
|
||||||
|
fetch('/api/captcha/generate')
|
||||||
|
.then(function(r) { return r.json(); })
|
||||||
|
.then(function(data) {
|
||||||
|
if (data.code === 0 && data.data) {
|
||||||
|
captchaId = data.data.id;
|
||||||
|
qEl.textContent = data.data.question;
|
||||||
|
if (errEl) errEl.style.display = 'none';
|
||||||
|
if (ansEl) { ansEl.value = ''; ansEl.focus(); }
|
||||||
|
} else {
|
||||||
|
qEl.textContent = CAPTCHA_I18N.loadFailed;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(function() {
|
||||||
|
qEl.textContent = CAPTCHA_I18N.loadRetry;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function getCSRFToken() {
|
||||||
|
var input = document.querySelector('input[name="_csrf"]');
|
||||||
|
return input ? input.value : '';
|
||||||
|
}
|
||||||
|
|
||||||
|
function doSubmit(form) {
|
||||||
|
|
||||||
|
var ans = document.getElementById('captcha-modal-answer').value.trim();
|
||||||
|
var hidden = form.querySelector('[name="g-recaptcha-response"]');
|
||||||
|
if (hidden) hidden.value = captchaId + ':' + (ans || '0');
|
||||||
|
|
||||||
|
UIkit.modal('#math-captcha-modal').hide();
|
||||||
|
|
||||||
|
|
||||||
|
if (pendingNeedPassword) {
|
||||||
|
UIkit.modal.prompt(CAPTCHA_I18N.needPassword, '', 'password')
|
||||||
|
.then(function(password) {
|
||||||
|
if (password) {
|
||||||
|
var pwInput = document.getElementById('ask_password_input');
|
||||||
|
if (pwInput) pwInput.value = password;
|
||||||
|
form.submit();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
form.submit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
document.getElementById('captcha-modal-submit').addEventListener('click', function() {
|
||||||
|
if (verifying) return;
|
||||||
|
var ans = document.getElementById('captcha-modal-answer').value.trim();
|
||||||
|
if (!ans) {
|
||||||
|
var errEl = document.getElementById('captcha-modal-error');
|
||||||
|
errEl.textContent = CAPTCHA_I18N.inputAnswer;
|
||||||
|
errEl.style.display = 'block';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
verifying = true;
|
||||||
|
fetch('/api/captcha/verify', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'X-CSRF-Token': getCSRFToken()
|
||||||
|
},
|
||||||
|
body: JSON.stringify({ id: captchaId, answer: parseInt(ans, 10) })
|
||||||
|
})
|
||||||
|
.then(function(r) { return r.json(); })
|
||||||
|
.then(function(data) {
|
||||||
|
verifying = false;
|
||||||
|
if (data.correct) {
|
||||||
|
if (pendingForm) doSubmit(pendingForm);
|
||||||
|
} else {
|
||||||
|
var errEl = document.getElementById('captcha-modal-error');
|
||||||
|
errEl.textContent = CAPTCHA_I18N.wrongAnswer;
|
||||||
|
errEl.style.display = 'block';
|
||||||
|
fetchCaptcha();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(function() {
|
||||||
|
verifying = false;
|
||||||
|
var errEl = document.getElementById('captcha-modal-error');
|
||||||
|
errEl.textContent = CAPTCHA_I18N.verifyFailed;
|
||||||
|
errEl.style.display = 'block';
|
||||||
|
fetchCaptcha();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
document.getElementById('captcha-modal-answer').addEventListener('keydown', function(e) {
|
||||||
|
if (e.key === 'Enter') {
|
||||||
|
e.preventDefault();
|
||||||
|
document.getElementById('captcha-modal-submit').click();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
document.getElementById('captcha-modal-refresh').addEventListener('click', fetchCaptcha);
|
||||||
|
|
||||||
|
|
||||||
|
document.addEventListener('click', function(e) {
|
||||||
|
var btn = e.target.closest('.math-captcha-trigger');
|
||||||
|
if (!btn) return;
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
var form = btn.closest('form');
|
||||||
|
if (!form) return;
|
||||||
|
pendingForm = form;
|
||||||
|
|
||||||
|
|
||||||
|
pendingNeedPassword = !!(form.querySelector('#ask_password_input'));
|
||||||
|
|
||||||
|
|
||||||
|
var notifyCb = document.getElementById('notify-checkbox');
|
||||||
|
var emailInput = document.getElementById('email-input');
|
||||||
|
if (notifyCb && notifyCb.checked && emailInput && emailInput.value.trim() === '') {
|
||||||
|
UIkit.modal.alert(CAPTCHA_I18N.needEmail);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
fetchCaptcha();
|
||||||
|
UIkit.modal('#math-captcha-modal').show();
|
||||||
|
});
|
||||||
|
})();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
<div class="uk-flex uk-flex-between uk-flex-middle uk-margin-bottom">
|
||||||
|
<h3 class="uk-margin-remove">投票结果:明天吃什么</h3>
|
||||||
|
<div class="uk-flex uk-flex-middle" style="gap: 8px;">
|
||||||
|
<a class="uk-button uk-button-default uk-button-small" href="/user/votes/3/export">导出 CSV</a>
|
||||||
|
<a class="uk-button uk-button-default uk-button-small" href="/user/questions#votes">返回</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="uk-card uk-card-default uk-card-small uk-card-body uk-margin-bottom">
|
||||||
|
<div class="uk-text-large uk-text-bold">1</div>
|
||||||
|
<div class="uk-text-meta">总参与人数</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<h4>投票结果</h4>
|
||||||
|
<div class="uk-card uk-card-default uk-card-small uk-card-body">
|
||||||
|
|
||||||
|
<div class="uk-text-meta uk-margin-small-bottom">平均分: 8.0</div>
|
||||||
|
|
||||||
|
<div class="uk-margin">
|
||||||
|
<div class="uk-flex uk-flex-between">
|
||||||
|
<span>1 分</span>
|
||||||
|
<span class="uk-text-meta">0 票</span>
|
||||||
|
</div>
|
||||||
|
<progress class="uk-progress uk-margin-small-top" value="0" max="100"></progress>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="uk-margin">
|
||||||
|
<div class="uk-flex uk-flex-between">
|
||||||
|
<span>2 分</span>
|
||||||
|
<span class="uk-text-meta">0 票</span>
|
||||||
|
</div>
|
||||||
|
<progress class="uk-progress uk-margin-small-top" value="0" max="100"></progress>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="uk-margin">
|
||||||
|
<div class="uk-flex uk-flex-between">
|
||||||
|
<span>3 分</span>
|
||||||
|
<span class="uk-text-meta">0 票</span>
|
||||||
|
</div>
|
||||||
|
<progress class="uk-progress uk-margin-small-top" value="0" max="100"></progress>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="uk-margin">
|
||||||
|
<div class="uk-flex uk-flex-between">
|
||||||
|
<span>4 分</span>
|
||||||
|
<span class="uk-text-meta">0 票</span>
|
||||||
|
</div>
|
||||||
|
<progress class="uk-progress uk-margin-small-top" value="0" max="100"></progress>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="uk-margin">
|
||||||
|
<div class="uk-flex uk-flex-between">
|
||||||
|
<span>5 分</span>
|
||||||
|
<span class="uk-text-meta">0 票</span>
|
||||||
|
</div>
|
||||||
|
<progress class="uk-progress uk-margin-small-top" value="0" max="100"></progress>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="uk-margin">
|
||||||
|
<div class="uk-flex uk-flex-between">
|
||||||
|
<span>6 分</span>
|
||||||
|
<span class="uk-text-meta">0 票</span>
|
||||||
|
</div>
|
||||||
|
<progress class="uk-progress uk-margin-small-top" value="0" max="100"></progress>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="uk-margin">
|
||||||
|
<div class="uk-flex uk-flex-between">
|
||||||
|
<span>7 分</span>
|
||||||
|
<span class="uk-text-meta">0 票</span>
|
||||||
|
</div>
|
||||||
|
<progress class="uk-progress uk-margin-small-top" value="0" max="100"></progress>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="uk-margin">
|
||||||
|
<div class="uk-flex uk-flex-between">
|
||||||
|
<span>8 分</span>
|
||||||
|
<span class="uk-text-meta">1 票</span>
|
||||||
|
</div>
|
||||||
|
<progress class="uk-progress uk-margin-small-top" value="100" max="100"></progress>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="uk-margin">
|
||||||
|
<div class="uk-flex uk-flex-between">
|
||||||
|
<span>9 分</span>
|
||||||
|
<span class="uk-text-meta">0 票</span>
|
||||||
|
</div>
|
||||||
|
<progress class="uk-progress uk-margin-small-top" value="0" max="100"></progress>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="uk-margin">
|
||||||
|
<div class="uk-flex uk-flex-between">
|
||||||
|
<span>10 分</span>
|
||||||
|
<span class="uk-text-meta">0 票</span>
|
||||||
|
</div>
|
||||||
|
<progress class="uk-progress uk-margin-small-top" value="0" max="100"></progress>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<script>
|
||||||
|
|
||||||
|
function toggleFieldReplies(id) {
|
||||||
|
var box = document.getElementById('replies-' + id);
|
||||||
|
var caret = document.getElementById('caret-' + id);
|
||||||
|
if (!box) { return; }
|
||||||
|
if (box.hasAttribute('hidden')) {
|
||||||
|
box.removeAttribute('hidden');
|
||||||
|
if (caret) { caret.style.transform = 'rotate(0deg)'; }
|
||||||
|
} else {
|
||||||
|
box.setAttribute('hidden', '');
|
||||||
|
if (caret) { caret.style.transform = 'rotate(-90deg)'; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<p class=" uk-text-right uk-text-muted uk-text-small">
|
||||||
|
<br>
|
||||||
|
<a href="/rules">社区规则</a> |
|
||||||
|
|
||||||
|
<a href="https://box.shiroko.one/_/tamakyi" target="_blank">找站长</a>
|
||||||
|
<br>
|
||||||
|
<a href="https://share.shiroko.one" target="_blank">盘</a>
|
||||||
|
| <a href="https://blog.shiroko.one" target="_blank">公告板</a>
|
||||||
|
| <a href="https://chat.shiroko.one" target="_blank">聊天室</a>
|
||||||
|
| <a href="https://status.shiroko.one" target="_blank">监控板</a>
|
||||||
|
| <a href="https://shiroko.one" target="_blank">导航页</a>
|
||||||
|
<br>Powered by NekoBox | 狼ICP备 20230101
|
||||||
|
<br>提问箱已成功存活:<span id="box_runtime"></span>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
(function () {
|
||||||
|
var create = Math.round(Date.UTC(2023, 6, 1, 18, 15, 43) / 1000);
|
||||||
|
function tick() {
|
||||||
|
var el = document.getElementById("box_runtime");
|
||||||
|
if (!el) return;
|
||||||
|
var s = Math.round((Date.now() + 8 * 3600 * 1000) / 1000) - create;
|
||||||
|
var t = [0, 0, 0, 0, 0];
|
||||||
|
if (s >= 31536000) { t[0] = s / 31536000 | 0; s %= 31536000; }
|
||||||
|
if (s >= 86400) { t[1] = s / 86400 | 0; s %= 86400; }
|
||||||
|
if (s >= 3600) { t[2] = s / 3600 | 0; s %= 3600; }
|
||||||
|
if (s >= 60) { t[3] = s / 60 | 0; s %= 60; }
|
||||||
|
if (s > 0) { t[4] = s; }
|
||||||
|
el.innerHTML = t[0] + '年 ' + t[1] + '天 ' + t[2] + '时 ' + t[3] + '分 ' + t[4] + '秒 ';
|
||||||
|
}
|
||||||
|
tick();
|
||||||
|
setInterval(tick, 1000);
|
||||||
|
})();
|
||||||
|
</script>
|
||||||
|
<br>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
var SUBMIT_I18N = {
|
||||||
|
submitting: '提交中...',
|
||||||
|
uploading: '上传中...'
|
||||||
|
};
|
||||||
|
|
||||||
|
function tbResetSubmitButtons() {
|
||||||
|
document.querySelectorAll('button[data-tb-submitting]').forEach(function(b) {
|
||||||
|
b.disabled = false;
|
||||||
|
b.removeAttribute('data-tb-submitting');
|
||||||
|
var orig = b.getAttribute('data-tb-restore');
|
||||||
|
if (orig !== null) {
|
||||||
|
b.innerHTML = orig;
|
||||||
|
b.removeAttribute('data-tb-restore');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
document.addEventListener('submit', function(e) {
|
||||||
|
var form = e.target;
|
||||||
|
if (!form || form.tagName !== 'FORM') return;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if (e.defaultPrevented || form.getAttribute('data-tb-skip-submit-feedback') === '1') {
|
||||||
|
form.removeAttribute('data-tb-skip-submit-feedback');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if (form.getAttribute('target') === '_blank') return;
|
||||||
|
|
||||||
|
|
||||||
|
var trigger = e.submitter || form.querySelector('button[type="submit"]');
|
||||||
|
|
||||||
|
|
||||||
|
var hasFile = false;
|
||||||
|
form.querySelectorAll('input[type="file"]').forEach(function(f) {
|
||||||
|
if (f.files && f.files.length > 0) hasFile = true;
|
||||||
|
});
|
||||||
|
var label = hasFile ? SUBMIT_I18N.uploading : SUBMIT_I18N.submitting;
|
||||||
|
|
||||||
|
if (trigger && trigger.tagName === 'BUTTON') {
|
||||||
|
trigger.setAttribute('data-tb-restore', trigger.innerHTML);
|
||||||
|
trigger.innerHTML = '<span uk-spinner="ratio: 0.6"></span> ' + label;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
form.querySelectorAll('button').forEach(function(b) {
|
||||||
|
b.disabled = true;
|
||||||
|
b.setAttribute('data-tb-submitting', '1');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
window.addEventListener('pageshow', tbResetSubmitButtons);
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
||||||
@@ -0,0 +1,929 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<title>投票结果</title>
|
||||||
|
<meta name="msvalidate.01" content="2F185E8E63C93635F50B3574F3B31E42" />
|
||||||
|
<meta name="description" content="狼的提问箱——一个无需注册、可匿名提问的匿名提问箱,安全地倾诉与回应。">
|
||||||
|
<meta name="keywords" content="匿名提问箱,提问箱,匿名提问,狼的提问箱,匿名问答,匿名提问网站">
|
||||||
|
|
||||||
|
<script>
|
||||||
|
(function () {
|
||||||
|
var m = document.cookie.match(/(?:^|;\s*)theme=([^;]*)/);
|
||||||
|
if (m && m[1] === 'dark') document.documentElement.setAttribute('data-theme', 'dark');
|
||||||
|
})();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<link rel="preconnect" href="https://r2.337845818.best" crossorigin>
|
||||||
|
<link rel="preconnect" href="https://cdnjs.snrat.com" crossorigin>
|
||||||
|
|
||||||
|
<link rel="stylesheet" href="https://cdnjs.snrat.com/ajax/libs/uikit/3.3.3/css/uikit.min.css"/>
|
||||||
|
|
||||||
|
<link rel="stylesheet" href="/static/css/base.css?v=20261019d"/>
|
||||||
|
|
||||||
|
<link rel="stylesheet" href="https://r2.337845818.best/tamabox/cdn/waline/client/v2/waline-no-commits.css" media="print" onload="this.media='all'"/>
|
||||||
|
<script defer src="https://cdnjs.snrat.com/ajax/libs/uikit/3.3.3/js/uikit.min.js"></script>
|
||||||
|
<script defer src="https://cdnjs.snrat.com/ajax/libs/uikit/3.3.3/js/uikit-icons.min.js"></script>
|
||||||
|
|
||||||
|
<script defer src="https://cdnjs.snrat.com/ajax/libs/dayjs/1.10.8/dayjs.min.js"></script>
|
||||||
|
<script defer src="https://cdnjs.snrat.com/ajax/libs/alpinejs/3.9.0/cdn.min.js"></script>
|
||||||
|
|
||||||
|
|
||||||
|
<script defer src="https://cdnjs.snrat.com/ajax/libs/waline/2.15.8/waline.js"></script>
|
||||||
|
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.captcha-equation-box {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
background: #f0f2f5;
|
||||||
|
border: 1px solid #dcdcdc;
|
||||||
|
border-radius: 8px;
|
||||||
|
padding: 8px 8px 8px 16px;
|
||||||
|
gap: 6px;
|
||||||
|
transition: border-color 0.2s;
|
||||||
|
}
|
||||||
|
.captcha-equation-box:focus-within {
|
||||||
|
border-color: #1e87f0;
|
||||||
|
box-shadow: 0 0 0 3px rgba(30,135,240,0.12);
|
||||||
|
}
|
||||||
|
.math-captcha-modal-question {
|
||||||
|
font-size: 1.4rem;
|
||||||
|
font-family: "Courier New", monospace;
|
||||||
|
font-weight: 700;
|
||||||
|
color: #333;
|
||||||
|
letter-spacing: 1px;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
#captcha-modal-answer {
|
||||||
|
width: 80px;
|
||||||
|
padding: 6px 10px;
|
||||||
|
text-align: center;
|
||||||
|
font-size: 1.2rem;
|
||||||
|
font-family: "Courier New", monospace;
|
||||||
|
font-weight: 600;
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
border-radius: 5px;
|
||||||
|
outline: none;
|
||||||
|
transition: border-color 0.15s, box-shadow 0.15s;
|
||||||
|
background: #fff;
|
||||||
|
}
|
||||||
|
#captcha-modal-answer:focus {
|
||||||
|
border-color: #1e87f0;
|
||||||
|
box-shadow: 0 0 0 2px rgba(30,135,240,0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
#captcha-modal-answer::-webkit-inner-spin-button,
|
||||||
|
#captcha-modal-answer::-webkit-outer-spin-button {
|
||||||
|
-webkit-appearance: none;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
#captcha-modal-answer {
|
||||||
|
-moz-appearance: textfield;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<meta property="og:site_name" content="狼的提问箱 | 匿名提问箱" />
|
||||||
|
<meta property="og:type" content="website" />
|
||||||
|
<meta property="og:title" content=" - 狼的提问箱 | 匿名提问箱" />
|
||||||
|
<meta property="og:url" content="https://box-dev-api.337845818.best/user/votes/5/results" />
|
||||||
|
<meta property="og:description" content=" - 狼的提问箱——一个无需注册、可匿名提问的匿名提问箱,安全地倾诉与回应。" />
|
||||||
|
<meta name="robots" content="noindex">
|
||||||
|
|
||||||
|
<meta property="og:image" content="?og-image=1" />
|
||||||
|
<meta property="og:image:alt" content="" />
|
||||||
|
<meta itemprop="image" content="?og-image=1"/>
|
||||||
|
<meta name="msapplication-TileImage" content=""/>
|
||||||
|
<link rel="shortcut icon" href="?og-image=1"/>
|
||||||
|
<link rel="apple-touch-icon" href="?og-image=1"/>
|
||||||
|
<link rel="icon" sizes="192x192" href="?og-image=1">
|
||||||
|
<meta name="twitter:image:src" content="?og-image=1" />
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<meta name="google-site-verification" content="fEPwRRJfiGsgwc5SINBQwZhPK8F0cwRaOvRx0YRurI4" />
|
||||||
|
|
||||||
|
<script>
|
||||||
|
window.addEventListener("load", function () {
|
||||||
|
var s = document.createElement("script");
|
||||||
|
s.src = "https://mami.shiroko.one/tamami.js";
|
||||||
|
s.setAttribute("data-website-id", "c42ebe8b-9281-4da0-83a4-8f18b3e710fe");
|
||||||
|
document.body.appendChild(s);
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<script>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
window.tbRenderQR = function (el, getOptions) {
|
||||||
|
if (!el || typeof QRCode === 'undefined') return;
|
||||||
|
var opts = getOptions();
|
||||||
|
function remoteOf(o, key) {
|
||||||
|
var v = o[key];
|
||||||
|
return (typeof v === 'string' && v.indexOf('http') === 0) ? v : '';
|
||||||
|
}
|
||||||
|
var good = window._tbQrGood || (window._tbQrGood = {});
|
||||||
|
var bad = window._tbQrBad || (window._tbQrBad = {});
|
||||||
|
|
||||||
|
function layerState(url) { return !url ? '' : (good[url] ? 1 : (bad[url] ? 0 : null)); }
|
||||||
|
var layers = [
|
||||||
|
{ url: remoteOf(opts, 'logo'), st: null, present: function (o, on) {
|
||||||
|
if (on) { } else { o.logo = undefined; o.logoWidth = undefined; o.logoHeight = undefined; o.logoBackgroundTransparent = undefined; }
|
||||||
|
} },
|
||||||
|
{ url: remoteOf(opts, 'backgroundImage'), st: null, present: function (o, on) {
|
||||||
|
if (on) { } else { o.backgroundImage = undefined; o.backgroundImageAlpha = undefined; }
|
||||||
|
} }
|
||||||
|
];
|
||||||
|
var needProbe = false;
|
||||||
|
for (var i = 0; i < layers.length; i++) {
|
||||||
|
layers[i].st = layerState(layers[i].url);
|
||||||
|
if (layers[i].st === null) needProbe = true;
|
||||||
|
}
|
||||||
|
function paint(states) {
|
||||||
|
var o = {};
|
||||||
|
for (var k in opts) o[k] = opts[k];
|
||||||
|
for (var j = 0; j < layers.length; j++) layers[j].present(o, states[j] === 1);
|
||||||
|
el.innerHTML = '';
|
||||||
|
new QRCode(el, o);
|
||||||
|
}
|
||||||
|
|
||||||
|
var initStates = [];
|
||||||
|
for (var n = 0; n < layers.length; n++) initStates.push(layers[n].st === 1 ? 1 : 0);
|
||||||
|
paint(initStates);
|
||||||
|
if (!needProbe) return;
|
||||||
|
|
||||||
|
var pending = 0, cross = opts.crossOrigin || 'anonymous';
|
||||||
|
layers.forEach(function (L) {
|
||||||
|
if (L.st !== null) return;
|
||||||
|
pending++;
|
||||||
|
var im = new Image();
|
||||||
|
im.onload = function () { good[L.url] = true; L.st = 1; onDone(); };
|
||||||
|
im.onerror = function () { bad[L.url] = true; L.st = 0; onDone(); };
|
||||||
|
if (cross) im.crossOrigin = cross;
|
||||||
|
im.src = L.url;
|
||||||
|
});
|
||||||
|
function onDone() {
|
||||||
|
if (--pending > 0) return;
|
||||||
|
var finalStates = [];
|
||||||
|
for (var m = 0; m < layers.length; m++) finalStates.push(layers[m].st === 1 ? 1 : 0);
|
||||||
|
var changed = false;
|
||||||
|
for (var q = 0; q < finalStates.length; q++) if (finalStates[q] !== initStates[q]) changed = true;
|
||||||
|
if (changed) paint(finalStates);
|
||||||
|
}
|
||||||
|
|
||||||
|
setTimeout(function () { if (pending > 0) { pending = 0; onDone(); } }, 3000);
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
<nav class="uk-navbar-container uk-margin tb-navbar" uk-navbar>
|
||||||
|
<div class="uk-navbar-center">
|
||||||
|
<div class="uk-navbar-center-left">
|
||||||
|
<div>
|
||||||
|
<ul class="uk-navbar-nav">
|
||||||
|
|
||||||
|
<li><a href="/explore">探索</a></li>
|
||||||
|
|
||||||
|
|
||||||
|
<li><a href="/_/admin6">我的</a></li>
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<a class="uk-navbar-item uk-logo" href="/"><span class="emoji-placeholder" aria-label="random animal">🐺</span>的提问箱</a>
|
||||||
|
|
||||||
|
<div class="uk-navbar-center-right">
|
||||||
|
<div>
|
||||||
|
|
||||||
|
<ul class="uk-navbar-nav">
|
||||||
|
<li><a href="/user/questions">提问</a></li>
|
||||||
|
</ul>
|
||||||
|
<ul class="uk-navbar-nav">
|
||||||
|
<li><a href="/user/profile">设置</a></li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<ul class="uk-navbar-nav tb-nav-utils">
|
||||||
|
<li>
|
||||||
|
<a href="#" id="theme-toggle" title="切换深色/浅色模式" aria-label="切换深色/浅色模式">
|
||||||
|
<span class="tb-icon-light"><svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M20.5 14.3A8.6 8.6 0 0 1 9.7 3.5a8.6 8.6 0 1 0 10.8 10.8z"/></svg></span><span class="tb-icon-dark"><svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><circle cx="12" cy="12" r="4"/><path d="M12 2.5v2M12 19.5v2M2.5 12h2M19.5 12h2M5.2 5.2l1.4 1.4M17.4 17.4l1.4 1.4M18.8 5.2l-1.4 1.4M6.6 17.4l-1.4 1.4"/></svg></span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
document.addEventListener("DOMContentLoaded", function() {
|
||||||
|
const emojis = ["🐺","🐗","🐻","🐨","🐼","🐹","🐭","🐰","🦊","🐮","🐷","🐽","🐸","🐒","🦍","🐔","🐧","🐦","🐤","🐦⬛","🦅","🦉","🦇","🐴","🦄","🐝","🦎","🦖","🦕","🐙","🦑","🦐","🦞","🦀","🐡","🐠","🐟","🐬","🐳","🐋","🦈","🐊","🐅","🐆","🦓","🦍","🦧","🐘","🦛","🦏","🐪","🐫","🦒","🦘","🐃","🐂","🐄","🐎","🐖","🐏","🐑","🦙","🐐","🦌","🐕","🐩","🦮","🐕🦺","🐈","🐋","🐳","🐬","🐉","🐲"];
|
||||||
|
const placeholder = document.querySelector('.emoji-placeholder');
|
||||||
|
if (placeholder) {
|
||||||
|
placeholder.textContent = emojis[Math.floor(Math.random() * emojis.length)];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
<div id="tb-mobile-utils">
|
||||||
|
|
||||||
|
<button type="button" id="theme-toggle-mobile" class="uk-button uk-button-default uk-button-small"
|
||||||
|
title="切换深色/浅色模式" aria-label="切换深色/浅色模式">
|
||||||
|
<span class="tb-icon-light"><svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M20.5 14.3A8.6 8.6 0 0 1 9.7 3.5a8.6 8.6 0 1 0 10.8 10.8z"/></svg></span><span class="tb-icon-dark"><svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><circle cx="12" cy="12" r="4"/><path d="M12 2.5v2M12 19.5v2M2.5 12h2M19.5 12h2M5.2 5.2l1.4 1.4M17.4 17.4l1.4 1.4M18.8 5.2l-1.4 1.4M6.6 17.4l-1.4 1.4"/></svg></span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
(function() {
|
||||||
|
|
||||||
|
var THEME_COOKIE = 'theme';
|
||||||
|
function getTheme() {
|
||||||
|
var m = document.cookie.match(/(?:^|;\s*)theme=([^;]*)/);
|
||||||
|
return m ? m[1] : '';
|
||||||
|
}
|
||||||
|
function applyTheme(theme) {
|
||||||
|
if (theme === 'dark') {
|
||||||
|
document.documentElement.setAttribute('data-theme', 'dark');
|
||||||
|
} else {
|
||||||
|
document.documentElement.removeAttribute('data-theme');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function toggleTheme() {
|
||||||
|
var next = getTheme() === 'dark' ? 'light' : 'dark';
|
||||||
|
applyTheme(next);
|
||||||
|
var expires = new Date(Date.now() + 365 * 24 * 3600 * 1000).toUTCString();
|
||||||
|
document.cookie = THEME_COOKIE + '=' + next + '; path=/; max-age=' + (365 * 24 * 3600) + '; SameSite=Lax';
|
||||||
|
}
|
||||||
|
|
||||||
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
|
|
||||||
|
var buttons = document.querySelectorAll('#theme-toggle, #theme-toggle-mobile');
|
||||||
|
buttons.forEach(function(btn) {
|
||||||
|
btn.addEventListener('click', function(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
toggleTheme();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
var langSel = document.getElementById('mobile-lang-select');
|
||||||
|
if (langSel) {
|
||||||
|
langSel.addEventListener('change', function() {
|
||||||
|
if (!this.value) return;
|
||||||
|
var to = window.location.pathname + window.location.search;
|
||||||
|
window.location.href = '/i18n/' + encodeURIComponent(this.value) + '?to=' + encodeURIComponent(to);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
})();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
<div class="uk-container uk-container-xsmall">
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<div id="math-captcha-modal" uk-modal>
|
||||||
|
<div class="uk-modal-dialog uk-modal-body uk-text-center">
|
||||||
|
<h3 class="uk-modal-title">人机验证</h3>
|
||||||
|
<p class="uk-text-meta">请计算下方的算术题以验证你不是机器人</p>
|
||||||
|
<div class="captcha-equation-box">
|
||||||
|
<span id="captcha-modal-question" class="math-captcha-modal-question">加载中...</span>
|
||||||
|
<input type="number" id="captcha-modal-answer" placeholder="?" autocomplete="off" inputmode="numeric">
|
||||||
|
</div>
|
||||||
|
<div style="margin-top:6px;">
|
||||||
|
<button type="button" class="uk-button uk-button-text uk-text-small" id="captcha-modal-refresh">换一题</button>
|
||||||
|
</div>
|
||||||
|
<div id="captcha-modal-error" class="uk-text-danger uk-text-small" style="display:none;min-height:20px;"></div>
|
||||||
|
<div class="uk-margin-small-top">
|
||||||
|
<button type="button" class="uk-button uk-button-primary" id="captcha-modal-submit">提交</button>
|
||||||
|
<button type="button" class="uk-button uk-button-default uk-modal-close">取消</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
var CAPTCHA_I18N = {
|
||||||
|
loading: "加载中...",
|
||||||
|
loadFailed: "加载失败",
|
||||||
|
loadRetry: "加载失败,请重试",
|
||||||
|
inputAnswer: "请输入答案",
|
||||||
|
wrongAnswer: "答案错误,请重新计算",
|
||||||
|
verifyFailed: "验证失败,请重试",
|
||||||
|
needPassword: "此提问箱需要密码",
|
||||||
|
needEmail: "请填写接收通知的邮箱地址"
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
(function() {
|
||||||
|
var captchaId = '';
|
||||||
|
var pendingForm = null;
|
||||||
|
var pendingNeedPassword = false;
|
||||||
|
var verifying = false;
|
||||||
|
|
||||||
|
function fetchCaptcha() {
|
||||||
|
var qEl = document.getElementById('captcha-modal-question');
|
||||||
|
var errEl = document.getElementById('captcha-modal-error');
|
||||||
|
var ansEl = document.getElementById('captcha-modal-answer');
|
||||||
|
qEl.textContent = CAPTCHA_I18N.loading;
|
||||||
|
fetch('/api/captcha/generate')
|
||||||
|
.then(function(r) { return r.json(); })
|
||||||
|
.then(function(data) {
|
||||||
|
if (data.code === 0 && data.data) {
|
||||||
|
captchaId = data.data.id;
|
||||||
|
qEl.textContent = data.data.question;
|
||||||
|
if (errEl) errEl.style.display = 'none';
|
||||||
|
if (ansEl) { ansEl.value = ''; ansEl.focus(); }
|
||||||
|
} else {
|
||||||
|
qEl.textContent = CAPTCHA_I18N.loadFailed;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(function() {
|
||||||
|
qEl.textContent = CAPTCHA_I18N.loadRetry;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function getCSRFToken() {
|
||||||
|
var input = document.querySelector('input[name="_csrf"]');
|
||||||
|
return input ? input.value : '';
|
||||||
|
}
|
||||||
|
|
||||||
|
function doSubmit(form) {
|
||||||
|
|
||||||
|
var ans = document.getElementById('captcha-modal-answer').value.trim();
|
||||||
|
var hidden = form.querySelector('[name="g-recaptcha-response"]');
|
||||||
|
if (hidden) hidden.value = captchaId + ':' + (ans || '0');
|
||||||
|
|
||||||
|
UIkit.modal('#math-captcha-modal').hide();
|
||||||
|
|
||||||
|
|
||||||
|
if (pendingNeedPassword) {
|
||||||
|
UIkit.modal.prompt(CAPTCHA_I18N.needPassword, '', 'password')
|
||||||
|
.then(function(password) {
|
||||||
|
if (password) {
|
||||||
|
var pwInput = document.getElementById('ask_password_input');
|
||||||
|
if (pwInput) pwInput.value = password;
|
||||||
|
form.submit();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
form.submit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
document.getElementById('captcha-modal-submit').addEventListener('click', function() {
|
||||||
|
if (verifying) return;
|
||||||
|
var ans = document.getElementById('captcha-modal-answer').value.trim();
|
||||||
|
if (!ans) {
|
||||||
|
var errEl = document.getElementById('captcha-modal-error');
|
||||||
|
errEl.textContent = CAPTCHA_I18N.inputAnswer;
|
||||||
|
errEl.style.display = 'block';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
verifying = true;
|
||||||
|
fetch('/api/captcha/verify', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'X-CSRF-Token': getCSRFToken()
|
||||||
|
},
|
||||||
|
body: JSON.stringify({ id: captchaId, answer: parseInt(ans, 10) })
|
||||||
|
})
|
||||||
|
.then(function(r) { return r.json(); })
|
||||||
|
.then(function(data) {
|
||||||
|
verifying = false;
|
||||||
|
if (data.correct) {
|
||||||
|
if (pendingForm) doSubmit(pendingForm);
|
||||||
|
} else {
|
||||||
|
var errEl = document.getElementById('captcha-modal-error');
|
||||||
|
errEl.textContent = CAPTCHA_I18N.wrongAnswer;
|
||||||
|
errEl.style.display = 'block';
|
||||||
|
fetchCaptcha();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(function() {
|
||||||
|
verifying = false;
|
||||||
|
var errEl = document.getElementById('captcha-modal-error');
|
||||||
|
errEl.textContent = CAPTCHA_I18N.verifyFailed;
|
||||||
|
errEl.style.display = 'block';
|
||||||
|
fetchCaptcha();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
document.getElementById('captcha-modal-answer').addEventListener('keydown', function(e) {
|
||||||
|
if (e.key === 'Enter') {
|
||||||
|
e.preventDefault();
|
||||||
|
document.getElementById('captcha-modal-submit').click();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
document.getElementById('captcha-modal-refresh').addEventListener('click', fetchCaptcha);
|
||||||
|
|
||||||
|
|
||||||
|
document.addEventListener('click', function(e) {
|
||||||
|
var btn = e.target.closest('.math-captcha-trigger');
|
||||||
|
if (!btn) return;
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
var form = btn.closest('form');
|
||||||
|
if (!form) return;
|
||||||
|
pendingForm = form;
|
||||||
|
|
||||||
|
|
||||||
|
pendingNeedPassword = !!(form.querySelector('#ask_password_input'));
|
||||||
|
|
||||||
|
|
||||||
|
var notifyCb = document.getElementById('notify-checkbox');
|
||||||
|
var emailInput = document.getElementById('email-input');
|
||||||
|
if (notifyCb && notifyCb.checked && emailInput && emailInput.value.trim() === '') {
|
||||||
|
UIkit.modal.alert(CAPTCHA_I18N.needEmail);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
fetchCaptcha();
|
||||||
|
UIkit.modal('#math-captcha-modal').show();
|
||||||
|
});
|
||||||
|
})();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
<div class="uk-flex uk-flex-between uk-flex-middle uk-margin-bottom">
|
||||||
|
<h3 class="uk-margin-remove">投票结果:11</h3>
|
||||||
|
<div class="uk-flex uk-flex-middle" style="gap: 8px;">
|
||||||
|
<a class="uk-button uk-button-default uk-button-small" href="/user/votes/5/export">导出 CSV</a>
|
||||||
|
<a class="uk-button uk-button-default uk-button-small" href="/user/questions#votes">返回</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="uk-card uk-card-default uk-card-small uk-card-body uk-margin-bottom">
|
||||||
|
<div class="uk-text-large uk-text-bold">2</div>
|
||||||
|
<div class="uk-text-meta">总参与人数</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<h4>投票结果</h4>
|
||||||
|
<div class="uk-card uk-card-default uk-card-small uk-card-body uk-margin-bottom">
|
||||||
|
|
||||||
|
<div class="uk-margin">
|
||||||
|
<div class="uk-flex uk-flex-middle uk-margin-small-bottom" style="gap: 8px;">
|
||||||
|
<span class="tb-chip">1</span>
|
||||||
|
<span class="tb-chip">单选</span>
|
||||||
|
<span class="uk-text-bold">11</span>
|
||||||
|
<span class="uk-text-meta uk-text-small">回答数: 2</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<div class="uk-margin-small-top">
|
||||||
|
<div class="uk-flex uk-flex-between">
|
||||||
|
<span>11</span>
|
||||||
|
<span class="uk-text-meta">2 票(100%)</span>
|
||||||
|
</div>
|
||||||
|
<progress class="uk-progress uk-margin-small-top" value="100" max="100"></progress>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="uk-margin-small-top">
|
||||||
|
<div class="uk-flex uk-flex-between">
|
||||||
|
<span>22</span>
|
||||||
|
<span class="uk-text-meta">0 票(0%)</span>
|
||||||
|
</div>
|
||||||
|
<progress class="uk-progress uk-margin-small-top" value="0" max="100"></progress>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="uk-margin-small-top">
|
||||||
|
<div class="uk-flex uk-flex-between">
|
||||||
|
<span>33</span>
|
||||||
|
<span class="uk-text-meta">0 票(0%)</span>
|
||||||
|
</div>
|
||||||
|
<progress class="uk-progress uk-margin-small-top" value="0" max="100"></progress>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="uk-margin">
|
||||||
|
<div class="uk-flex uk-flex-middle uk-margin-small-bottom" style="gap: 8px;">
|
||||||
|
<span class="tb-chip">2</span>
|
||||||
|
<span class="tb-chip">多选</span>
|
||||||
|
<span class="uk-text-bold">22</span>
|
||||||
|
<span class="uk-text-meta uk-text-small">回答数: 2</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<div class="uk-margin-small-top">
|
||||||
|
<div class="uk-flex uk-flex-between">
|
||||||
|
<span>11</span>
|
||||||
|
<span class="uk-text-meta">2 票(66%)</span>
|
||||||
|
</div>
|
||||||
|
<progress class="uk-progress uk-margin-small-top" value="66" max="100"></progress>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="uk-margin-small-top">
|
||||||
|
<div class="uk-flex uk-flex-between">
|
||||||
|
<span>22</span>
|
||||||
|
<span class="uk-text-meta">1 票(33%)</span>
|
||||||
|
</div>
|
||||||
|
<progress class="uk-progress uk-margin-small-top" value="33" max="100"></progress>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="uk-margin-small-top">
|
||||||
|
<div class="uk-flex uk-flex-between">
|
||||||
|
<span>33</span>
|
||||||
|
<span class="uk-text-meta">0 票(0%)</span>
|
||||||
|
</div>
|
||||||
|
<progress class="uk-progress uk-margin-small-top" value="0" max="100"></progress>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="uk-margin">
|
||||||
|
<div class="uk-flex uk-flex-middle uk-margin-small-bottom" style="gap: 8px;">
|
||||||
|
<span class="tb-chip">3</span>
|
||||||
|
<span class="tb-chip">单行文本</span>
|
||||||
|
<span class="uk-text-bold">33</span>
|
||||||
|
<span class="uk-text-meta uk-text-small">回答数: 2</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<div class="uk-text-meta uk-margin-small-top">已填写: 2</div>
|
||||||
|
|
||||||
|
|
||||||
|
<div class="uk-margin-small-top">
|
||||||
|
<div class="uk-text-small" style="cursor:pointer; user-select:none; color:#1e87f0;" onclick="toggleFieldReplies('4')" title="点击展开或收起文本回复明细">
|
||||||
|
<span id="caret-4" style="display:inline-block; transition:transform .15s; transform:rotate(-90deg);">▾</span>
|
||||||
|
查看文本提交(2)
|
||||||
|
</div>
|
||||||
|
<div id="replies-4" hidden>
|
||||||
|
<ul class="uk-list uk-list-divider uk-margin-small-top">
|
||||||
|
|
||||||
|
<li>
|
||||||
|
<div class="uk-text-meta uk-text-small">2026-08-24 16:05</div>
|
||||||
|
<div style="white-space:pre-wrap;">12</div>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li>
|
||||||
|
<div class="uk-text-meta uk-text-small">2026-08-24 15:26</div>
|
||||||
|
<div style="white-space:pre-wrap;">12</div>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="uk-margin">
|
||||||
|
<div class="uk-flex uk-flex-middle uk-margin-small-bottom" style="gap: 8px;">
|
||||||
|
<span class="tb-chip">4</span>
|
||||||
|
<span class="tb-chip">多行文本</span>
|
||||||
|
<span class="uk-text-bold">44</span>
|
||||||
|
<span class="uk-text-meta uk-text-small">回答数: 2</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<div class="uk-text-meta uk-margin-small-top">已填写: 2</div>
|
||||||
|
|
||||||
|
|
||||||
|
<div class="uk-margin-small-top">
|
||||||
|
<div class="uk-text-small" style="cursor:pointer; user-select:none; color:#1e87f0;" onclick="toggleFieldReplies('5')" title="点击展开或收起文本回复明细">
|
||||||
|
<span id="caret-5" style="display:inline-block; transition:transform .15s; transform:rotate(-90deg);">▾</span>
|
||||||
|
查看文本提交(2)
|
||||||
|
</div>
|
||||||
|
<div id="replies-5" hidden>
|
||||||
|
<ul class="uk-list uk-list-divider uk-margin-small-top">
|
||||||
|
|
||||||
|
<li>
|
||||||
|
<div class="uk-text-meta uk-text-small">2026-08-24 16:05</div>
|
||||||
|
<div style="white-space:pre-wrap;">12</div>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li>
|
||||||
|
<div class="uk-text-meta uk-text-small">2026-08-24 15:26</div>
|
||||||
|
<div style="white-space:pre-wrap;">12
|
||||||
|
1212
|
||||||
|
121212</div>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="uk-margin">
|
||||||
|
<div class="uk-flex uk-flex-middle uk-margin-small-bottom" style="gap: 8px;">
|
||||||
|
<span class="tb-chip">5</span>
|
||||||
|
<span class="tb-chip">下拉选择</span>
|
||||||
|
<span class="uk-text-bold">55</span>
|
||||||
|
<span class="uk-text-meta uk-text-small">回答数: 2</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<div class="uk-margin-small-top">
|
||||||
|
<div class="uk-flex uk-flex-between">
|
||||||
|
<span>11</span>
|
||||||
|
<span class="uk-text-meta">2 票(100%)</span>
|
||||||
|
</div>
|
||||||
|
<progress class="uk-progress uk-margin-small-top" value="100" max="100"></progress>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="uk-margin-small-top">
|
||||||
|
<div class="uk-flex uk-flex-between">
|
||||||
|
<span>22</span>
|
||||||
|
<span class="uk-text-meta">0 票(0%)</span>
|
||||||
|
</div>
|
||||||
|
<progress class="uk-progress uk-margin-small-top" value="0" max="100"></progress>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="uk-margin-small-top">
|
||||||
|
<div class="uk-flex uk-flex-between">
|
||||||
|
<span>33</span>
|
||||||
|
<span class="uk-text-meta">0 票(0%)</span>
|
||||||
|
</div>
|
||||||
|
<progress class="uk-progress uk-margin-small-top" value="0" max="100"></progress>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="uk-margin">
|
||||||
|
<div class="uk-flex uk-flex-middle uk-margin-small-bottom" style="gap: 8px;">
|
||||||
|
<span class="tb-chip">6</span>
|
||||||
|
<span class="tb-chip">数字</span>
|
||||||
|
<span class="uk-text-bold">66</span>
|
||||||
|
<span class="uk-text-meta uk-text-small">回答数: 2</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<div class="uk-text-meta uk-margin-small-top">平均: 4.0(2 票)</div>
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="uk-margin">
|
||||||
|
<div class="uk-flex uk-flex-middle uk-margin-small-bottom" style="gap: 8px;">
|
||||||
|
<span class="tb-chip">7</span>
|
||||||
|
<span class="tb-chip">评分</span>
|
||||||
|
<span class="uk-text-bold">77</span>
|
||||||
|
<span class="uk-text-meta uk-text-small">回答数: 2</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<div class="uk-text-meta uk-margin-small-top">平均分: 9.0(2 票)</div>
|
||||||
|
|
||||||
|
<div class="uk-flex uk-flex-between uk-margin-small-top">
|
||||||
|
<span>1 分</span>
|
||||||
|
<span class="uk-text-meta">0 票(0%)</span>
|
||||||
|
</div>
|
||||||
|
<progress class="uk-progress uk-margin-small-top" value="0" max="100"></progress>
|
||||||
|
|
||||||
|
<div class="uk-flex uk-flex-between uk-margin-small-top">
|
||||||
|
<span>2 分</span>
|
||||||
|
<span class="uk-text-meta">0 票(0%)</span>
|
||||||
|
</div>
|
||||||
|
<progress class="uk-progress uk-margin-small-top" value="0" max="100"></progress>
|
||||||
|
|
||||||
|
<div class="uk-flex uk-flex-between uk-margin-small-top">
|
||||||
|
<span>3 分</span>
|
||||||
|
<span class="uk-text-meta">0 票(0%)</span>
|
||||||
|
</div>
|
||||||
|
<progress class="uk-progress uk-margin-small-top" value="0" max="100"></progress>
|
||||||
|
|
||||||
|
<div class="uk-flex uk-flex-between uk-margin-small-top">
|
||||||
|
<span>4 分</span>
|
||||||
|
<span class="uk-text-meta">0 票(0%)</span>
|
||||||
|
</div>
|
||||||
|
<progress class="uk-progress uk-margin-small-top" value="0" max="100"></progress>
|
||||||
|
|
||||||
|
<div class="uk-flex uk-flex-between uk-margin-small-top">
|
||||||
|
<span>5 分</span>
|
||||||
|
<span class="uk-text-meta">0 票(0%)</span>
|
||||||
|
</div>
|
||||||
|
<progress class="uk-progress uk-margin-small-top" value="0" max="100"></progress>
|
||||||
|
|
||||||
|
<div class="uk-flex uk-flex-between uk-margin-small-top">
|
||||||
|
<span>6 分</span>
|
||||||
|
<span class="uk-text-meta">0 票(0%)</span>
|
||||||
|
</div>
|
||||||
|
<progress class="uk-progress uk-margin-small-top" value="0" max="100"></progress>
|
||||||
|
|
||||||
|
<div class="uk-flex uk-flex-between uk-margin-small-top">
|
||||||
|
<span>7 分</span>
|
||||||
|
<span class="uk-text-meta">0 票(0%)</span>
|
||||||
|
</div>
|
||||||
|
<progress class="uk-progress uk-margin-small-top" value="0" max="100"></progress>
|
||||||
|
|
||||||
|
<div class="uk-flex uk-flex-between uk-margin-small-top">
|
||||||
|
<span>8 分</span>
|
||||||
|
<span class="uk-text-meta">1 票(50%)</span>
|
||||||
|
</div>
|
||||||
|
<progress class="uk-progress uk-margin-small-top" value="50" max="100"></progress>
|
||||||
|
|
||||||
|
<div class="uk-flex uk-flex-between uk-margin-small-top">
|
||||||
|
<span>9 分</span>
|
||||||
|
<span class="uk-text-meta">0 票(0%)</span>
|
||||||
|
</div>
|
||||||
|
<progress class="uk-progress uk-margin-small-top" value="0" max="100"></progress>
|
||||||
|
|
||||||
|
<div class="uk-flex uk-flex-between uk-margin-small-top">
|
||||||
|
<span>10 分</span>
|
||||||
|
<span class="uk-text-meta">1 票(50%)</span>
|
||||||
|
</div>
|
||||||
|
<progress class="uk-progress uk-margin-small-top" value="50" max="100"></progress>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="uk-margin">
|
||||||
|
<div class="uk-flex uk-flex-middle uk-margin-small-bottom" style="gap: 8px;">
|
||||||
|
<span class="tb-chip">8</span>
|
||||||
|
<span class="tb-chip">排序</span>
|
||||||
|
<span class="uk-text-bold">88</span>
|
||||||
|
<span class="uk-text-meta uk-text-small">回答数: 2</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<div class="uk-text-meta uk-margin-small-top">平均排名: 1.48(2 票)</div>
|
||||||
|
|
||||||
|
<div class="uk-flex uk-flex-between uk-margin-small-top">
|
||||||
|
<span>11</span>
|
||||||
|
<span class="uk-text-meta">平均排名: 1.10 · 被排次数: 2</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="uk-flex uk-flex-between uk-margin-small-top">
|
||||||
|
<span>22</span>
|
||||||
|
<span class="uk-text-meta">平均排名: 1.25 · 被排次数: 2</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="uk-flex uk-flex-between uk-margin-small-top">
|
||||||
|
<span>33</span>
|
||||||
|
<span class="uk-text-meta">平均排名: 2.10 · 被排次数: 2</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<script>
|
||||||
|
|
||||||
|
function toggleFieldReplies(id) {
|
||||||
|
var box = document.getElementById('replies-' + id);
|
||||||
|
var caret = document.getElementById('caret-' + id);
|
||||||
|
if (!box) { return; }
|
||||||
|
if (box.hasAttribute('hidden')) {
|
||||||
|
box.removeAttribute('hidden');
|
||||||
|
if (caret) { caret.style.transform = 'rotate(0deg)'; }
|
||||||
|
} else {
|
||||||
|
box.setAttribute('hidden', '');
|
||||||
|
if (caret) { caret.style.transform = 'rotate(-90deg)'; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<p class=" uk-text-right uk-text-muted uk-text-small">
|
||||||
|
<br>
|
||||||
|
<a href="/rules">社区规则</a> |
|
||||||
|
|
||||||
|
<a href="https://box.shiroko.one/_/tamakyi" target="_blank">找站长</a>
|
||||||
|
<br>
|
||||||
|
<a href="https://share.shiroko.one" target="_blank">盘</a>
|
||||||
|
| <a href="https://blog.shiroko.one" target="_blank">公告板</a>
|
||||||
|
| <a href="https://chat.shiroko.one" target="_blank">聊天室</a>
|
||||||
|
| <a href="https://status.shiroko.one" target="_blank">监控板</a>
|
||||||
|
| <a href="https://shiroko.one" target="_blank">导航页</a>
|
||||||
|
<br>Powered by NekoBox | 狼ICP备 20230101
|
||||||
|
<br>提问箱已成功存活:<span id="box_runtime"></span>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
(function () {
|
||||||
|
var create = Math.round(Date.UTC(2023, 6, 1, 18, 15, 43) / 1000);
|
||||||
|
function tick() {
|
||||||
|
var el = document.getElementById("box_runtime");
|
||||||
|
if (!el) return;
|
||||||
|
var s = Math.round((Date.now() + 8 * 3600 * 1000) / 1000) - create;
|
||||||
|
var t = [0, 0, 0, 0, 0];
|
||||||
|
if (s >= 31536000) { t[0] = s / 31536000 | 0; s %= 31536000; }
|
||||||
|
if (s >= 86400) { t[1] = s / 86400 | 0; s %= 86400; }
|
||||||
|
if (s >= 3600) { t[2] = s / 3600 | 0; s %= 3600; }
|
||||||
|
if (s >= 60) { t[3] = s / 60 | 0; s %= 60; }
|
||||||
|
if (s > 0) { t[4] = s; }
|
||||||
|
el.innerHTML = t[0] + '年 ' + t[1] + '天 ' + t[2] + '时 ' + t[3] + '分 ' + t[4] + '秒 ';
|
||||||
|
}
|
||||||
|
tick();
|
||||||
|
setInterval(tick, 1000);
|
||||||
|
})();
|
||||||
|
</script>
|
||||||
|
<br>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
var SUBMIT_I18N = {
|
||||||
|
submitting: '提交中...',
|
||||||
|
uploading: '上传中...'
|
||||||
|
};
|
||||||
|
|
||||||
|
function tbResetSubmitButtons() {
|
||||||
|
document.querySelectorAll('button[data-tb-submitting]').forEach(function(b) {
|
||||||
|
b.disabled = false;
|
||||||
|
b.removeAttribute('data-tb-submitting');
|
||||||
|
var orig = b.getAttribute('data-tb-restore');
|
||||||
|
if (orig !== null) {
|
||||||
|
b.innerHTML = orig;
|
||||||
|
b.removeAttribute('data-tb-restore');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
document.addEventListener('submit', function(e) {
|
||||||
|
var form = e.target;
|
||||||
|
if (!form || form.tagName !== 'FORM') return;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if (e.defaultPrevented || form.getAttribute('data-tb-skip-submit-feedback') === '1') {
|
||||||
|
form.removeAttribute('data-tb-skip-submit-feedback');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if (form.getAttribute('target') === '_blank') return;
|
||||||
|
|
||||||
|
|
||||||
|
var trigger = e.submitter || form.querySelector('button[type="submit"]');
|
||||||
|
|
||||||
|
|
||||||
|
var hasFile = false;
|
||||||
|
form.querySelectorAll('input[type="file"]').forEach(function(f) {
|
||||||
|
if (f.files && f.files.length > 0) hasFile = true;
|
||||||
|
});
|
||||||
|
var label = hasFile ? SUBMIT_I18N.uploading : SUBMIT_I18N.submitting;
|
||||||
|
|
||||||
|
if (trigger && trigger.tagName === 'BUTTON') {
|
||||||
|
trigger.setAttribute('data-tb-restore', trigger.innerHTML);
|
||||||
|
trigger.innerHTML = '<span uk-spinner="ratio: 0.6"></span> ' + label;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
form.querySelectorAll('button').forEach(function(b) {
|
||||||
|
b.disabled = true;
|
||||||
|
b.setAttribute('data-tb-submitting', '1');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
window.addEventListener('pageshow', tbResetSubmitButtons);
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
||||||
@@ -0,0 +1,946 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="ja">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<title>测试功能</title>
|
||||||
|
<meta name="msvalidate.01" content="2F185E8E63C93635F50B3574F3B31E42" />
|
||||||
|
<meta name="description" content="狼の質問箱は登録不要で使える匿名質問箱。誰でも匿名で質問でき、安心してやり取りできる場所です。">
|
||||||
|
<meta name="keywords" content="匿名質問箱,質問箱,匿名質問,狼の質問箱,匿名で質問,匿名Q&A">
|
||||||
|
|
||||||
|
<script>
|
||||||
|
(function () {
|
||||||
|
var m = document.cookie.match(/(?:^|;\s*)theme=([^;]*)/);
|
||||||
|
if (m && m[1] === 'dark') document.documentElement.setAttribute('data-theme', 'dark');
|
||||||
|
})();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<link rel="preconnect" href="https://r2.337845818.best" crossorigin>
|
||||||
|
<link rel="preconnect" href="https://cdnjs.snrat.com" crossorigin>
|
||||||
|
|
||||||
|
<link rel="stylesheet" href="https://cdnjs.snrat.com/ajax/libs/uikit/3.3.3/css/uikit.min.css"/>
|
||||||
|
|
||||||
|
<link rel="stylesheet" href="/static/css/base.css?v=20261019d"/>
|
||||||
|
|
||||||
|
<link rel="stylesheet" href="https://r2.337845818.best/tamabox/cdn/waline/client/v2/waline-no-commits.css" media="print" onload="this.media='all'"/>
|
||||||
|
<script defer src="https://cdnjs.snrat.com/ajax/libs/uikit/3.3.3/js/uikit.min.js"></script>
|
||||||
|
<script defer src="https://cdnjs.snrat.com/ajax/libs/uikit/3.3.3/js/uikit-icons.min.js"></script>
|
||||||
|
|
||||||
|
<script defer src="https://cdnjs.snrat.com/ajax/libs/dayjs/1.10.8/dayjs.min.js"></script>
|
||||||
|
<script defer src="https://cdnjs.snrat.com/ajax/libs/alpinejs/3.9.0/cdn.min.js"></script>
|
||||||
|
|
||||||
|
|
||||||
|
<script defer src="https://cdnjs.snrat.com/ajax/libs/waline/2.15.8/waline.js"></script>
|
||||||
|
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.captcha-equation-box {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
background: #f0f2f5;
|
||||||
|
border: 1px solid #dcdcdc;
|
||||||
|
border-radius: 8px;
|
||||||
|
padding: 8px 8px 8px 16px;
|
||||||
|
gap: 6px;
|
||||||
|
transition: border-color 0.2s;
|
||||||
|
}
|
||||||
|
.captcha-equation-box:focus-within {
|
||||||
|
border-color: #1e87f0;
|
||||||
|
box-shadow: 0 0 0 3px rgba(30,135,240,0.12);
|
||||||
|
}
|
||||||
|
.math-captcha-modal-question {
|
||||||
|
font-size: 1.4rem;
|
||||||
|
font-family: "Courier New", monospace;
|
||||||
|
font-weight: 700;
|
||||||
|
color: #333;
|
||||||
|
letter-spacing: 1px;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
#captcha-modal-answer {
|
||||||
|
width: 80px;
|
||||||
|
padding: 6px 10px;
|
||||||
|
text-align: center;
|
||||||
|
font-size: 1.2rem;
|
||||||
|
font-family: "Courier New", monospace;
|
||||||
|
font-weight: 600;
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
border-radius: 5px;
|
||||||
|
outline: none;
|
||||||
|
transition: border-color 0.15s, box-shadow 0.15s;
|
||||||
|
background: #fff;
|
||||||
|
}
|
||||||
|
#captcha-modal-answer:focus {
|
||||||
|
border-color: #1e87f0;
|
||||||
|
box-shadow: 0 0 0 2px rgba(30,135,240,0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
#captcha-modal-answer::-webkit-inner-spin-button,
|
||||||
|
#captcha-modal-answer::-webkit-outer-spin-button {
|
||||||
|
-webkit-appearance: none;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
#captcha-modal-answer {
|
||||||
|
-moz-appearance: textfield;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<meta property="og:site_name" content="狼の質問箱 | 匿名質問箱" />
|
||||||
|
<meta property="og:type" content="website" />
|
||||||
|
<meta property="og:title" content="狼の質問箱 | 匿名質問箱" />
|
||||||
|
<meta property="og:url" content="https://box-dev-api.337845818.best/vote/9wfpVjXi73mc" />
|
||||||
|
<meta property="og:description" content="狼の質問箱は登録不要で使える匿名質問箱。誰でも匿名で質問でき、安心してやり取りできる場所です。" />
|
||||||
|
<meta name="robots" content="noindex">
|
||||||
|
|
||||||
|
<meta itemprop="image" content="https://r2.337845818.best/tamabox/tamabox_low.png"/>
|
||||||
|
<meta name="msapplication-TileImage" content="https://r2.337845818.best/tamabox/tamabox_low.png"/>
|
||||||
|
<link rel="shortcut icon" href="https://r2.337845818.best/tamabox/tamabox_low.png" />
|
||||||
|
<link rel="apple-touch-icon" href="https://r2.337845818.best/tamabox/tamabox_low.png"/>
|
||||||
|
<link rel="icon" sizes="192x192" href="https://r2.337845818.best/tamabox/tamabox_low.png">
|
||||||
|
<meta name="twitter:image:src" content="https://r2.337845818.best/tamabox/tamabox_low.png" />
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<meta name="google-site-verification" content="fEPwRRJfiGsgwc5SINBQwZhPK8F0cwRaOvRx0YRurI4" />
|
||||||
|
|
||||||
|
<script>
|
||||||
|
window.addEventListener("load", function () {
|
||||||
|
var s = document.createElement("script");
|
||||||
|
s.src = "https://mami.shiroko.one/tamami.js";
|
||||||
|
s.setAttribute("data-website-id", "c42ebe8b-9281-4da0-83a4-8f18b3e710fe");
|
||||||
|
document.body.appendChild(s);
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<script>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
window.tbRenderQR = function (el, getOptions) {
|
||||||
|
if (!el || typeof QRCode === 'undefined') return;
|
||||||
|
var opts = getOptions();
|
||||||
|
function remoteOf(o, key) {
|
||||||
|
var v = o[key];
|
||||||
|
return (typeof v === 'string' && v.indexOf('http') === 0) ? v : '';
|
||||||
|
}
|
||||||
|
var good = window._tbQrGood || (window._tbQrGood = {});
|
||||||
|
var bad = window._tbQrBad || (window._tbQrBad = {});
|
||||||
|
|
||||||
|
function layerState(url) { return !url ? '' : (good[url] ? 1 : (bad[url] ? 0 : null)); }
|
||||||
|
var layers = [
|
||||||
|
{ url: remoteOf(opts, 'logo'), st: null, present: function (o, on) {
|
||||||
|
if (on) { } else { o.logo = undefined; o.logoWidth = undefined; o.logoHeight = undefined; o.logoBackgroundTransparent = undefined; }
|
||||||
|
} },
|
||||||
|
{ url: remoteOf(opts, 'backgroundImage'), st: null, present: function (o, on) {
|
||||||
|
if (on) { } else { o.backgroundImage = undefined; o.backgroundImageAlpha = undefined; }
|
||||||
|
} }
|
||||||
|
];
|
||||||
|
var needProbe = false;
|
||||||
|
for (var i = 0; i < layers.length; i++) {
|
||||||
|
layers[i].st = layerState(layers[i].url);
|
||||||
|
if (layers[i].st === null) needProbe = true;
|
||||||
|
}
|
||||||
|
function paint(states) {
|
||||||
|
var o = {};
|
||||||
|
for (var k in opts) o[k] = opts[k];
|
||||||
|
for (var j = 0; j < layers.length; j++) layers[j].present(o, states[j] === 1);
|
||||||
|
el.innerHTML = '';
|
||||||
|
new QRCode(el, o);
|
||||||
|
}
|
||||||
|
|
||||||
|
var initStates = [];
|
||||||
|
for (var n = 0; n < layers.length; n++) initStates.push(layers[n].st === 1 ? 1 : 0);
|
||||||
|
paint(initStates);
|
||||||
|
if (!needProbe) return;
|
||||||
|
|
||||||
|
var pending = 0, cross = opts.crossOrigin || 'anonymous';
|
||||||
|
layers.forEach(function (L) {
|
||||||
|
if (L.st !== null) return;
|
||||||
|
pending++;
|
||||||
|
var im = new Image();
|
||||||
|
im.onload = function () { good[L.url] = true; L.st = 1; onDone(); };
|
||||||
|
im.onerror = function () { bad[L.url] = true; L.st = 0; onDone(); };
|
||||||
|
if (cross) im.crossOrigin = cross;
|
||||||
|
im.src = L.url;
|
||||||
|
});
|
||||||
|
function onDone() {
|
||||||
|
if (--pending > 0) return;
|
||||||
|
var finalStates = [];
|
||||||
|
for (var m = 0; m < layers.length; m++) finalStates.push(layers[m].st === 1 ? 1 : 0);
|
||||||
|
var changed = false;
|
||||||
|
for (var q = 0; q < finalStates.length; q++) if (finalStates[q] !== initStates[q]) changed = true;
|
||||||
|
if (changed) paint(finalStates);
|
||||||
|
}
|
||||||
|
|
||||||
|
setTimeout(function () { if (pending > 0) { pending = 0; onDone(); } }, 3000);
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
<nav class="uk-navbar-container uk-margin tb-navbar" uk-navbar>
|
||||||
|
<div class="uk-navbar-center">
|
||||||
|
<div class="uk-navbar-center-left">
|
||||||
|
<div>
|
||||||
|
<ul class="uk-navbar-nav">
|
||||||
|
|
||||||
|
<li><a href="/explore">探索</a></li>
|
||||||
|
|
||||||
|
|
||||||
|
<li class="tb-mobile-balancer" aria-hidden="true"><a tabindex="-1" style="visibility:hidden">マイ</a></li>
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<a class="uk-navbar-item uk-logo" href="/"><span class="emoji-placeholder" aria-label="random animal">🐺</span>の質問箱</a>
|
||||||
|
|
||||||
|
<div class="uk-navbar-center-right">
|
||||||
|
<div>
|
||||||
|
|
||||||
|
<ul class="uk-navbar-nav">
|
||||||
|
<li><a href="/register">登録</a></li>
|
||||||
|
</ul>
|
||||||
|
<ul class="uk-navbar-nav">
|
||||||
|
<li><a href="/login">ログイン</a></li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<ul class="uk-navbar-nav tb-nav-utils">
|
||||||
|
<li>
|
||||||
|
<a href="#" aria-label="言語" title="言語"><svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><circle cx="12" cy="12" r="9"/><path d="M3.2 9h17.6M3.2 15h17.6"/><ellipse cx="12" cy="12" rx="4" ry="9"/></svg></a>
|
||||||
|
<div class="uk-navbar-dropdown" uk-drop="mode: click; pos: bottom-right">
|
||||||
|
<ul class="uk-nav uk-navbar-dropdown-nav">
|
||||||
|
|
||||||
|
<li class="">
|
||||||
|
<a href="/i18n/zh-CN?to=%2Fvote%2F9wfpVjXi73mc">简体中文</a>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li class="">
|
||||||
|
<a href="/i18n/zh-TW?to=%2Fvote%2F9wfpVjXi73mc">繁體中文</a>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li class="">
|
||||||
|
<a href="/i18n/en?to=%2Fvote%2F9wfpVjXi73mc">English</a>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li class="uk-active">
|
||||||
|
<a href="/i18n/ja?to=%2Fvote%2F9wfpVjXi73mc">日本語</a>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
|
||||||
|
<ul class="uk-navbar-nav tb-nav-utils">
|
||||||
|
<li>
|
||||||
|
<a href="#" id="theme-toggle" title="ダーク/ライトモード切替" aria-label="ダーク/ライトモード切替">
|
||||||
|
<span class="tb-icon-light"><svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M20.5 14.3A8.6 8.6 0 0 1 9.7 3.5a8.6 8.6 0 1 0 10.8 10.8z"/></svg></span><span class="tb-icon-dark"><svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><circle cx="12" cy="12" r="4"/><path d="M12 2.5v2M12 19.5v2M2.5 12h2M19.5 12h2M5.2 5.2l1.4 1.4M17.4 17.4l1.4 1.4M18.8 5.2l-1.4 1.4M6.6 17.4l-1.4 1.4"/></svg></span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
document.addEventListener("DOMContentLoaded", function() {
|
||||||
|
const emojis = ["🐺","🐗","🐻","🐨","🐼","🐹","🐭","🐰","🦊","🐮","🐷","🐽","🐸","🐒","🦍","🐔","🐧","🐦","🐤","🐦⬛","🦅","🦉","🦇","🐴","🦄","🐝","🦎","🦖","🦕","🐙","🦑","🦐","🦞","🦀","🐡","🐠","🐟","🐬","🐳","🐋","🦈","🐊","🐅","🐆","🦓","🦍","🦧","🐘","🦛","🦏","🐪","🐫","🦒","🦘","🐃","🐂","🐄","🐎","🐖","🐏","🐑","🦙","🐐","🦌","🐕","🐩","🦮","🐕🦺","🐈","🐋","🐳","🐬","🐉","🐲"];
|
||||||
|
const placeholder = document.querySelector('.emoji-placeholder');
|
||||||
|
if (placeholder) {
|
||||||
|
placeholder.textContent = emojis[Math.floor(Math.random() * emojis.length)];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
<div id="tb-mobile-utils">
|
||||||
|
|
||||||
|
<select id="mobile-lang-select" class="uk-select uk-form-small" aria-label="言語">
|
||||||
|
|
||||||
|
<option value="zh-CN" >简体中文</option>
|
||||||
|
|
||||||
|
<option value="zh-TW" >繁體中文</option>
|
||||||
|
|
||||||
|
<option value="en" >English</option>
|
||||||
|
|
||||||
|
<option value="ja" selected>日本語</option>
|
||||||
|
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<button type="button" id="theme-toggle-mobile" class="uk-button uk-button-default uk-button-small"
|
||||||
|
title="ダーク/ライトモード切替" aria-label="ダーク/ライトモード切替">
|
||||||
|
<span class="tb-icon-light"><svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M20.5 14.3A8.6 8.6 0 0 1 9.7 3.5a8.6 8.6 0 1 0 10.8 10.8z"/></svg></span><span class="tb-icon-dark"><svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><circle cx="12" cy="12" r="4"/><path d="M12 2.5v2M12 19.5v2M2.5 12h2M19.5 12h2M5.2 5.2l1.4 1.4M17.4 17.4l1.4 1.4M18.8 5.2l-1.4 1.4M6.6 17.4l-1.4 1.4"/></svg></span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
(function() {
|
||||||
|
|
||||||
|
var THEME_COOKIE = 'theme';
|
||||||
|
function getTheme() {
|
||||||
|
var m = document.cookie.match(/(?:^|;\s*)theme=([^;]*)/);
|
||||||
|
return m ? m[1] : '';
|
||||||
|
}
|
||||||
|
function applyTheme(theme) {
|
||||||
|
if (theme === 'dark') {
|
||||||
|
document.documentElement.setAttribute('data-theme', 'dark');
|
||||||
|
} else {
|
||||||
|
document.documentElement.removeAttribute('data-theme');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function toggleTheme() {
|
||||||
|
var next = getTheme() === 'dark' ? 'light' : 'dark';
|
||||||
|
applyTheme(next);
|
||||||
|
var expires = new Date(Date.now() + 365 * 24 * 3600 * 1000).toUTCString();
|
||||||
|
document.cookie = THEME_COOKIE + '=' + next + '; path=/; max-age=' + (365 * 24 * 3600) + '; SameSite=Lax';
|
||||||
|
}
|
||||||
|
|
||||||
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
|
|
||||||
|
var buttons = document.querySelectorAll('#theme-toggle, #theme-toggle-mobile');
|
||||||
|
buttons.forEach(function(btn) {
|
||||||
|
btn.addEventListener('click', function(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
toggleTheme();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
var langSel = document.getElementById('mobile-lang-select');
|
||||||
|
if (langSel) {
|
||||||
|
langSel.addEventListener('change', function() {
|
||||||
|
if (!this.value) return;
|
||||||
|
var to = window.location.pathname + window.location.search;
|
||||||
|
window.location.href = '/i18n/' + encodeURIComponent(this.value) + '?to=' + encodeURIComponent(to);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
})();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
<div class="uk-container uk-container-xsmall">
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<div id="math-captcha-modal" uk-modal>
|
||||||
|
<div class="uk-modal-dialog uk-modal-body uk-text-center">
|
||||||
|
<h3 class="uk-modal-title">人機認証</h3>
|
||||||
|
<p class="uk-text-meta">以下の計算問題を解いて、ロボットでないことを証明してください</p>
|
||||||
|
<div class="captcha-equation-box">
|
||||||
|
<span id="captcha-modal-question" class="math-captcha-modal-question">読み込み中...</span>
|
||||||
|
<input type="number" id="captcha-modal-answer" placeholder="?" autocomplete="off" inputmode="numeric">
|
||||||
|
</div>
|
||||||
|
<div style="margin-top:6px;">
|
||||||
|
<button type="button" class="uk-button uk-button-text uk-text-small" id="captcha-modal-refresh">別の問題</button>
|
||||||
|
</div>
|
||||||
|
<div id="captcha-modal-error" class="uk-text-danger uk-text-small" style="display:none;min-height:20px;"></div>
|
||||||
|
<div class="uk-margin-small-top">
|
||||||
|
<button type="button" class="uk-button uk-button-primary" id="captcha-modal-submit">送信</button>
|
||||||
|
<button type="button" class="uk-button uk-button-default uk-modal-close">キャンセル</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
var CAPTCHA_I18N = {
|
||||||
|
loading: "読み込み中...",
|
||||||
|
loadFailed: "読み込み失敗",
|
||||||
|
loadRetry: "読み込み失敗、再試行してください",
|
||||||
|
inputAnswer: "答えを入力してください",
|
||||||
|
wrongAnswer: "答えが違います。もう一度計算してください",
|
||||||
|
verifyFailed: "認証失敗、再試行してください",
|
||||||
|
needPassword: "この質問箱にはパスワードが必要です",
|
||||||
|
needEmail: "通知を受け取るメールアドレスを入力してください"
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
(function() {
|
||||||
|
var captchaId = '';
|
||||||
|
var pendingForm = null;
|
||||||
|
var pendingNeedPassword = false;
|
||||||
|
var verifying = false;
|
||||||
|
|
||||||
|
function fetchCaptcha() {
|
||||||
|
var qEl = document.getElementById('captcha-modal-question');
|
||||||
|
var errEl = document.getElementById('captcha-modal-error');
|
||||||
|
var ansEl = document.getElementById('captcha-modal-answer');
|
||||||
|
qEl.textContent = CAPTCHA_I18N.loading;
|
||||||
|
fetch('/api/captcha/generate')
|
||||||
|
.then(function(r) { return r.json(); })
|
||||||
|
.then(function(data) {
|
||||||
|
if (data.code === 0 && data.data) {
|
||||||
|
captchaId = data.data.id;
|
||||||
|
qEl.textContent = data.data.question;
|
||||||
|
if (errEl) errEl.style.display = 'none';
|
||||||
|
if (ansEl) { ansEl.value = ''; ansEl.focus(); }
|
||||||
|
} else {
|
||||||
|
qEl.textContent = CAPTCHA_I18N.loadFailed;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(function() {
|
||||||
|
qEl.textContent = CAPTCHA_I18N.loadRetry;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function getCSRFToken() {
|
||||||
|
var input = document.querySelector('input[name="_csrf"]');
|
||||||
|
return input ? input.value : '';
|
||||||
|
}
|
||||||
|
|
||||||
|
function doSubmit(form) {
|
||||||
|
|
||||||
|
var ans = document.getElementById('captcha-modal-answer').value.trim();
|
||||||
|
var hidden = form.querySelector('[name="g-recaptcha-response"]');
|
||||||
|
if (hidden) hidden.value = captchaId + ':' + (ans || '0');
|
||||||
|
|
||||||
|
UIkit.modal('#math-captcha-modal').hide();
|
||||||
|
|
||||||
|
|
||||||
|
if (pendingNeedPassword) {
|
||||||
|
UIkit.modal.prompt(CAPTCHA_I18N.needPassword, '', 'password')
|
||||||
|
.then(function(password) {
|
||||||
|
if (password) {
|
||||||
|
var pwInput = document.getElementById('ask_password_input');
|
||||||
|
if (pwInput) pwInput.value = password;
|
||||||
|
form.submit();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
form.submit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
document.getElementById('captcha-modal-submit').addEventListener('click', function() {
|
||||||
|
if (verifying) return;
|
||||||
|
var ans = document.getElementById('captcha-modal-answer').value.trim();
|
||||||
|
if (!ans) {
|
||||||
|
var errEl = document.getElementById('captcha-modal-error');
|
||||||
|
errEl.textContent = CAPTCHA_I18N.inputAnswer;
|
||||||
|
errEl.style.display = 'block';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
verifying = true;
|
||||||
|
fetch('/api/captcha/verify', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'X-CSRF-Token': getCSRFToken()
|
||||||
|
},
|
||||||
|
body: JSON.stringify({ id: captchaId, answer: parseInt(ans, 10) })
|
||||||
|
})
|
||||||
|
.then(function(r) { return r.json(); })
|
||||||
|
.then(function(data) {
|
||||||
|
verifying = false;
|
||||||
|
if (data.correct) {
|
||||||
|
if (pendingForm) doSubmit(pendingForm);
|
||||||
|
} else {
|
||||||
|
var errEl = document.getElementById('captcha-modal-error');
|
||||||
|
errEl.textContent = CAPTCHA_I18N.wrongAnswer;
|
||||||
|
errEl.style.display = 'block';
|
||||||
|
fetchCaptcha();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(function() {
|
||||||
|
verifying = false;
|
||||||
|
var errEl = document.getElementById('captcha-modal-error');
|
||||||
|
errEl.textContent = CAPTCHA_I18N.verifyFailed;
|
||||||
|
errEl.style.display = 'block';
|
||||||
|
fetchCaptcha();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
document.getElementById('captcha-modal-answer').addEventListener('keydown', function(e) {
|
||||||
|
if (e.key === 'Enter') {
|
||||||
|
e.preventDefault();
|
||||||
|
document.getElementById('captcha-modal-submit').click();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
document.getElementById('captcha-modal-refresh').addEventListener('click', fetchCaptcha);
|
||||||
|
|
||||||
|
|
||||||
|
document.addEventListener('click', function(e) {
|
||||||
|
var btn = e.target.closest('.math-captcha-trigger');
|
||||||
|
if (!btn) return;
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
var form = btn.closest('form');
|
||||||
|
if (!form) return;
|
||||||
|
pendingForm = form;
|
||||||
|
|
||||||
|
|
||||||
|
pendingNeedPassword = !!(form.querySelector('#ask_password_input'));
|
||||||
|
|
||||||
|
|
||||||
|
var notifyCb = document.getElementById('notify-checkbox');
|
||||||
|
var emailInput = document.getElementById('email-input');
|
||||||
|
if (notifyCb && notifyCb.checked && emailInput && emailInput.value.trim() === '') {
|
||||||
|
UIkit.modal.alert(CAPTCHA_I18N.needEmail);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
fetchCaptcha();
|
||||||
|
UIkit.modal('#math-captcha-modal').show();
|
||||||
|
});
|
||||||
|
})();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
<style>
|
||||||
|
|
||||||
|
.tb-field-head {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
align-items: center;
|
||||||
|
gap: 6px 8px;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
.tb-field-head .tb-field-label {
|
||||||
|
flex-basis: 100%;
|
||||||
|
font-weight: 600;
|
||||||
|
line-height: 1.5;
|
||||||
|
word-break: break-word;
|
||||||
|
overflow-wrap: anywhere;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tb-choice {
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-start;
|
||||||
|
gap: 10px;
|
||||||
|
padding: 12px 14px;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
border: 1px solid var(--tb-border);
|
||||||
|
border-radius: 8px;
|
||||||
|
background: var(--tb-surface);
|
||||||
|
cursor: pointer;
|
||||||
|
transition: border-color 0.2s ease, background 0.2s ease;
|
||||||
|
}
|
||||||
|
.tb-choice:last-child { margin-bottom: 0; }
|
||||||
|
.tb-choice input[type="radio"], .tb-choice input[type="checkbox"] {
|
||||||
|
margin-top: 3px;
|
||||||
|
}
|
||||||
|
.tb-choice span {
|
||||||
|
flex: 1;
|
||||||
|
min-width: 0;
|
||||||
|
line-height: 1.5;
|
||||||
|
word-break: break-word;
|
||||||
|
overflow-wrap: anywhere;
|
||||||
|
}
|
||||||
|
.tb-choice:hover {
|
||||||
|
border-color: var(--tb-primary);
|
||||||
|
background: var(--tb-surface-hover);
|
||||||
|
}
|
||||||
|
.tb-choice:has(input:checked) {
|
||||||
|
border-color: var(--tb-primary);
|
||||||
|
background: var(--tb-surface-active);
|
||||||
|
}
|
||||||
|
html[data-theme="dark"] .tb-choice {
|
||||||
|
border-color: var(--tb-border);
|
||||||
|
background: var(--tb-surface);
|
||||||
|
}
|
||||||
|
html[data-theme="dark"] .tb-choice:hover {
|
||||||
|
border-color: var(--tb-primary);
|
||||||
|
background: rgba(78, 168, 245, 0.08);
|
||||||
|
}
|
||||||
|
html[data-theme="dark"] .tb-choice:has(input:checked) {
|
||||||
|
border-color: var(--tb-primary);
|
||||||
|
background: rgba(78, 168, 245, 0.14);
|
||||||
|
}
|
||||||
|
|
||||||
|
.tb-custom-input {
|
||||||
|
margin-top: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tb-text-counter {
|
||||||
|
margin-top: 2px;
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
@media (max-width: 480px) {
|
||||||
|
.tb-choice { padding: 10px 12px; }
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<div class="uk-card uk-card-default uk-card-body uk-margin-bottom">
|
||||||
|
<div class="uk-flex uk-flex-middle uk-margin-small-bottom" style="gap: 10px;">
|
||||||
|
|
||||||
|
<img class="uk-border-circle" src="https://r2.337845818.best/tamabox/picture/2026/08/19/9af3e38222d972ff9141e9cfdb0475" style="width: 40px; height: 40px;">
|
||||||
|
<div>
|
||||||
|
<a class="uk-text-bold" href="/_admin6">admin6</a>
|
||||||
|
<div class="uk-text-meta uk-text-small">の投票</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="uk-margin-auto-left">
|
||||||
|
|
||||||
|
|
||||||
|
<span class="uk-label uk-label-success">進行中</span>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h3 class="uk-margin-remove-top uk-margin-small-bottom">测试功能</h3>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<div class="uk-alert uk-alert-primary uk-text-small">匿名での参加が可能で、あなたの身元は記録されません(同一端末で最大1回)。</div>
|
||||||
|
|
||||||
|
|
||||||
|
<form method="post" action="/vote/9wfpVjXi73mc/submit" id="vote-form" onsubmit="return validateVoteForm()">
|
||||||
|
<input type="hidden" name="_csrf" value="bI4L81P22p0soR2CX69aptIQoIE6MTc5MjM4NTMwNjcwNTYxMjQ0OQ">
|
||||||
|
<input type="hidden" name="g-recaptcha-response" id="g-recaptcha-response" value="">
|
||||||
|
|
||||||
|
<div class="uk-card uk-card-default uk-card-body uk-margin-bottom">
|
||||||
|
|
||||||
|
|
||||||
|
<div class="uk-margin">
|
||||||
|
<div class="tb-field-head">
|
||||||
|
<span class="tb-chip">1</span>
|
||||||
|
<span class="tb-chip">単一選択</span>
|
||||||
|
<div class="tb-field-label">必填 <span class="uk-text-danger">*</span></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<label class="tb-choice">
|
||||||
|
<input class="uk-radio" type="radio" name="field_37" value="A" data-vote-required data-vote-label="必填"><span>A</span>
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<label class="tb-choice">
|
||||||
|
<input class="uk-radio" type="radio" name="field_37" value="B" data-vote-required data-vote-label="必填"><span>B</span>
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<label class="tb-choice">
|
||||||
|
<input class="uk-radio" type="radio" name="field_37" value="C" data-vote-required data-vote-label="必填"><span>C</span>
|
||||||
|
</label>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="uk-margin">
|
||||||
|
<div class="tb-field-head">
|
||||||
|
<span class="tb-chip">2</span>
|
||||||
|
<span class="tb-chip">複数選択</span>
|
||||||
|
<div class="tb-field-label">非必填</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<label class="tb-choice">
|
||||||
|
<input class="uk-checkbox" type="checkbox" name="field_38" value="A" ><span>A</span>
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<label class="tb-choice">
|
||||||
|
<input class="uk-checkbox" type="checkbox" name="field_38" value="B" ><span>B</span>
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<label class="tb-choice">
|
||||||
|
<input class="uk-checkbox" type="checkbox" name="field_38" value="C" ><span>C</span>
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<label class="tb-choice">
|
||||||
|
<input class="uk-checkbox" type="checkbox" name="field_38" value="D" ><span>D</span>
|
||||||
|
</label>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="uk-margin">
|
||||||
|
<div class="tb-field-head">
|
||||||
|
<span class="tb-chip">3</span>
|
||||||
|
<span class="tb-chip">一行テキスト</span>
|
||||||
|
<div class="tb-field-label">文本1</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<input class="uk-input" type="text" name="field_39" >
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="uk-margin">
|
||||||
|
<div class="tb-field-head">
|
||||||
|
<span class="tb-chip">4</span>
|
||||||
|
<span class="tb-chip">複数行テキスト</span>
|
||||||
|
<div class="tb-field-label">文本2 <span class="uk-text-danger">*</span></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<textarea class="uk-textarea" rows="3" name="field_40" data-vote-required data-vote-label="文本2"></textarea>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="uk-margin">
|
||||||
|
|
||||||
|
<button type="button" class="uk-button uk-button-primary math-captcha-trigger" onclick="return voteValidate(event)">投票する</button>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<script>
|
||||||
|
|
||||||
|
|
||||||
|
var MAX_CUSTOM_LEN = 200 ;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
function countChars(s) { return Array.from(String(s || '')).length; }
|
||||||
|
|
||||||
|
|
||||||
|
function setupTextCounters() {
|
||||||
|
var form = document.getElementById('vote-form');
|
||||||
|
if (!form) { return; }
|
||||||
|
form.querySelectorAll('[data-tb-text-counter]').forEach(function (input) {
|
||||||
|
var max = parseInt(input.getAttribute('data-tb-text-max'), 10);
|
||||||
|
if (!max || max < 1) { max = MAX_CUSTOM_LEN; }
|
||||||
|
var counter = document.createElement('div');
|
||||||
|
counter.className = 'uk-text-meta uk-text-small tb-text-counter';
|
||||||
|
if (input.parentNode) { input.parentNode.insertBefore(counter, input.nextSibling); }
|
||||||
|
var update = function () {
|
||||||
|
var n = countChars(input.value);
|
||||||
|
counter.textContent = n + ' / ' + max;
|
||||||
|
if (n > max) {
|
||||||
|
counter.classList.add('uk-text-danger');
|
||||||
|
input.setAttribute('data-tb-too-long', '1');
|
||||||
|
} else {
|
||||||
|
counter.classList.remove('uk-text-danger');
|
||||||
|
input.removeAttribute('data-tb-too-long');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
input.addEventListener('input', update);
|
||||||
|
update();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
function validateVoteForm() {
|
||||||
|
var form = document.getElementById('vote-form');
|
||||||
|
if (!form) { return true; }
|
||||||
|
|
||||||
|
var tooLong = form.querySelector('[data-tb-text-counter][data-tb-too-long]');
|
||||||
|
if (tooLong) {
|
||||||
|
alert('自由記入オプションは 200 字以内にしてください');
|
||||||
|
tooLong.focus();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
var groups = {};
|
||||||
|
form.querySelectorAll('input[data-vote-required][type="radio"], input[data-vote-required][type="checkbox"]').forEach(function (el) {
|
||||||
|
(groups[el.name] = groups[el.name] || []).push(el);
|
||||||
|
});
|
||||||
|
for (var name in groups) {
|
||||||
|
var any = groups[name].some(function (el) { return el.checked; });
|
||||||
|
if (!any) {
|
||||||
|
alert('入力してください「' + groups[name][0].getAttribute('data-vote-label') + '」');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var els = form.querySelectorAll('[data-vote-required]:not(input[type="radio"]):not(input[type="checkbox"])');
|
||||||
|
for (var i = 0; i < els.length; i++) {
|
||||||
|
var el = els[i];
|
||||||
|
if (el.disabled) { continue; }
|
||||||
|
if ((el.value || '').trim() === '') {
|
||||||
|
alert('入力してください「' + el.getAttribute('data-vote-label') + '」');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function voteValidate(e) {
|
||||||
|
if (!validateVoteForm()) {
|
||||||
|
if (e) { e.stopPropagation(); e.preventDefault(); }
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function onSubmit() {
|
||||||
|
if (validateVoteForm()) {
|
||||||
|
document.getElementById('vote-form').submit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
(function () {
|
||||||
|
var form = document.getElementById('vote-form');
|
||||||
|
if (!form) { return; }
|
||||||
|
setupTextCounters();
|
||||||
|
var maxChoices = 0;
|
||||||
|
if (maxChoices > 0) {
|
||||||
|
var boxes = form.querySelectorAll('input[type="checkbox"][name="option_ids"]');
|
||||||
|
boxes.forEach(function (box) {
|
||||||
|
box.addEventListener('change', function () {
|
||||||
|
var checked = form.querySelectorAll('input[type="checkbox"][name="option_ids"]:checked').length;
|
||||||
|
if (checked > maxChoices) { this.checked = false; }
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
var CUSTOM_MARKER = "__tb_custom_option__";
|
||||||
|
form.querySelectorAll('[data-vote-custom-input]').forEach(function (input) {
|
||||||
|
var fid = input.getAttribute('data-vote-custom-input');
|
||||||
|
var group = form.querySelectorAll('input[name="field_' + fid + '"]');
|
||||||
|
var select = form.querySelector('select[name="field_' + fid + '"]');
|
||||||
|
var sync = function () {
|
||||||
|
var on = false;
|
||||||
|
if (select) {
|
||||||
|
on = (select.value === CUSTOM_MARKER);
|
||||||
|
} else {
|
||||||
|
group.forEach(function (r) { if (r.value === CUSTOM_MARKER && r.checked) { on = true; } });
|
||||||
|
}
|
||||||
|
input.disabled = !on;
|
||||||
|
if (!on) { input.value = ''; }
|
||||||
|
};
|
||||||
|
if (select) { select.addEventListener('change', sync); } else { group.forEach(function (r) { r.addEventListener('change', sync); }); }
|
||||||
|
sync();
|
||||||
|
});
|
||||||
|
})();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<p class=" uk-text-right uk-text-muted uk-text-small">
|
||||||
|
<br>
|
||||||
|
<a href="/rules">ルール</a> |
|
||||||
|
|
||||||
|
<a href="https://box.shiroko.one/_/tamakyi" target="_blank">管理者へ</a>
|
||||||
|
<br>
|
||||||
|
<a href="https://share.shiroko.one" target="_blank">ドライブ</a>
|
||||||
|
| <a href="https://blog.shiroko.one" target="_blank">お知らせ</a>
|
||||||
|
| <a href="https://chat.shiroko.one" target="_blank">チャット</a>
|
||||||
|
| <a href="https://status.shiroko.one" target="_blank">ステータス</a>
|
||||||
|
| <a href="https://shiroko.one" target="_blank">リンク</a>
|
||||||
|
<br>Powered by NekoBox | 狼ICP备 20230101
|
||||||
|
<br>質問箱は稼働中:<span id="box_runtime"></span>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
(function () {
|
||||||
|
var create = Math.round(Date.UTC(2023, 6, 1, 18, 15, 43) / 1000);
|
||||||
|
function tick() {
|
||||||
|
var el = document.getElementById("box_runtime");
|
||||||
|
if (!el) return;
|
||||||
|
var s = Math.round((Date.now() + 8 * 3600 * 1000) / 1000) - create;
|
||||||
|
var t = [0, 0, 0, 0, 0];
|
||||||
|
if (s >= 31536000) { t[0] = s / 31536000 | 0; s %= 31536000; }
|
||||||
|
if (s >= 86400) { t[1] = s / 86400 | 0; s %= 86400; }
|
||||||
|
if (s >= 3600) { t[2] = s / 3600 | 0; s %= 3600; }
|
||||||
|
if (s >= 60) { t[3] = s / 60 | 0; s %= 60; }
|
||||||
|
if (s > 0) { t[4] = s; }
|
||||||
|
el.innerHTML = t[0] + '年 ' + t[1] + '天 ' + t[2] + '时 ' + t[3] + '分 ' + t[4] + '秒 ';
|
||||||
|
}
|
||||||
|
tick();
|
||||||
|
setInterval(tick, 1000);
|
||||||
|
})();
|
||||||
|
</script>
|
||||||
|
<br>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
var SUBMIT_I18N = {
|
||||||
|
submitting: '送信中...',
|
||||||
|
uploading: 'アップロード中...'
|
||||||
|
};
|
||||||
|
|
||||||
|
function tbResetSubmitButtons() {
|
||||||
|
document.querySelectorAll('button[data-tb-submitting]').forEach(function(b) {
|
||||||
|
b.disabled = false;
|
||||||
|
b.removeAttribute('data-tb-submitting');
|
||||||
|
var orig = b.getAttribute('data-tb-restore');
|
||||||
|
if (orig !== null) {
|
||||||
|
b.innerHTML = orig;
|
||||||
|
b.removeAttribute('data-tb-restore');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
document.addEventListener('submit', function(e) {
|
||||||
|
var form = e.target;
|
||||||
|
if (!form || form.tagName !== 'FORM') return;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if (e.defaultPrevented || form.getAttribute('data-tb-skip-submit-feedback') === '1') {
|
||||||
|
form.removeAttribute('data-tb-skip-submit-feedback');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if (form.getAttribute('target') === '_blank') return;
|
||||||
|
|
||||||
|
|
||||||
|
var trigger = e.submitter || form.querySelector('button[type="submit"]');
|
||||||
|
|
||||||
|
|
||||||
|
var hasFile = false;
|
||||||
|
form.querySelectorAll('input[type="file"]').forEach(function(f) {
|
||||||
|
if (f.files && f.files.length > 0) hasFile = true;
|
||||||
|
});
|
||||||
|
var label = hasFile ? SUBMIT_I18N.uploading : SUBMIT_I18N.submitting;
|
||||||
|
|
||||||
|
if (trigger && trigger.tagName === 'BUTTON') {
|
||||||
|
trigger.setAttribute('data-tb-restore', trigger.innerHTML);
|
||||||
|
trigger.innerHTML = '<span uk-spinner="ratio: 0.6"></span> ' + label;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
form.querySelectorAll('button').forEach(function(b) {
|
||||||
|
b.disabled = true;
|
||||||
|
b.setAttribute('data-tb-submitting', '1');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
window.addEventListener('pageshow', tbResetSubmitButtons);
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
||||||
@@ -0,0 +1,924 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="ja">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<title>测试4</title>
|
||||||
|
<meta name="msvalidate.01" content="2F185E8E63C93635F50B3574F3B31E42" />
|
||||||
|
<meta name="description" content="狼の質問箱は登録不要で使える匿名質問箱。誰でも匿名で質問でき、安心してやり取りできる場所です。">
|
||||||
|
<meta name="keywords" content="匿名質問箱,質問箱,匿名質問,狼の質問箱,匿名で質問,匿名Q&A">
|
||||||
|
|
||||||
|
<script>
|
||||||
|
(function () {
|
||||||
|
var m = document.cookie.match(/(?:^|;\s*)theme=([^;]*)/);
|
||||||
|
if (m && m[1] === 'dark') document.documentElement.setAttribute('data-theme', 'dark');
|
||||||
|
})();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<link rel="preconnect" href="https://r2.337845818.best" crossorigin>
|
||||||
|
<link rel="preconnect" href="https://cdnjs.snrat.com" crossorigin>
|
||||||
|
|
||||||
|
<link rel="stylesheet" href="https://cdnjs.snrat.com/ajax/libs/uikit/3.3.3/css/uikit.min.css"/>
|
||||||
|
|
||||||
|
<link rel="stylesheet" href="/static/css/base.css?v=20261019d"/>
|
||||||
|
|
||||||
|
<link rel="stylesheet" href="https://r2.337845818.best/tamabox/cdn/waline/client/v2/waline-no-commits.css" media="print" onload="this.media='all'"/>
|
||||||
|
<script defer src="https://cdnjs.snrat.com/ajax/libs/uikit/3.3.3/js/uikit.min.js"></script>
|
||||||
|
<script defer src="https://cdnjs.snrat.com/ajax/libs/uikit/3.3.3/js/uikit-icons.min.js"></script>
|
||||||
|
|
||||||
|
<script defer src="https://cdnjs.snrat.com/ajax/libs/dayjs/1.10.8/dayjs.min.js"></script>
|
||||||
|
<script defer src="https://cdnjs.snrat.com/ajax/libs/alpinejs/3.9.0/cdn.min.js"></script>
|
||||||
|
|
||||||
|
|
||||||
|
<script defer src="https://cdnjs.snrat.com/ajax/libs/waline/2.15.8/waline.js"></script>
|
||||||
|
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.captcha-equation-box {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
background: #f0f2f5;
|
||||||
|
border: 1px solid #dcdcdc;
|
||||||
|
border-radius: 8px;
|
||||||
|
padding: 8px 8px 8px 16px;
|
||||||
|
gap: 6px;
|
||||||
|
transition: border-color 0.2s;
|
||||||
|
}
|
||||||
|
.captcha-equation-box:focus-within {
|
||||||
|
border-color: #1e87f0;
|
||||||
|
box-shadow: 0 0 0 3px rgba(30,135,240,0.12);
|
||||||
|
}
|
||||||
|
.math-captcha-modal-question {
|
||||||
|
font-size: 1.4rem;
|
||||||
|
font-family: "Courier New", monospace;
|
||||||
|
font-weight: 700;
|
||||||
|
color: #333;
|
||||||
|
letter-spacing: 1px;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
#captcha-modal-answer {
|
||||||
|
width: 80px;
|
||||||
|
padding: 6px 10px;
|
||||||
|
text-align: center;
|
||||||
|
font-size: 1.2rem;
|
||||||
|
font-family: "Courier New", monospace;
|
||||||
|
font-weight: 600;
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
border-radius: 5px;
|
||||||
|
outline: none;
|
||||||
|
transition: border-color 0.15s, box-shadow 0.15s;
|
||||||
|
background: #fff;
|
||||||
|
}
|
||||||
|
#captcha-modal-answer:focus {
|
||||||
|
border-color: #1e87f0;
|
||||||
|
box-shadow: 0 0 0 2px rgba(30,135,240,0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
#captcha-modal-answer::-webkit-inner-spin-button,
|
||||||
|
#captcha-modal-answer::-webkit-outer-spin-button {
|
||||||
|
-webkit-appearance: none;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
#captcha-modal-answer {
|
||||||
|
-moz-appearance: textfield;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<meta property="og:site_name" content="狼の質問箱 | 匿名質問箱" />
|
||||||
|
<meta property="og:type" content="website" />
|
||||||
|
<meta property="og:title" content="狼の質問箱 | 匿名質問箱" />
|
||||||
|
<meta property="og:url" content="https://box-dev-api.337845818.best/vote/z9F8mIqPtDOA" />
|
||||||
|
<meta property="og:description" content="狼の質問箱は登録不要で使える匿名質問箱。誰でも匿名で質問でき、安心してやり取りできる場所です。" />
|
||||||
|
<meta name="robots" content="noindex">
|
||||||
|
|
||||||
|
<meta itemprop="image" content="https://r2.337845818.best/tamabox/tamabox_low.png"/>
|
||||||
|
<meta name="msapplication-TileImage" content="https://r2.337845818.best/tamabox/tamabox_low.png"/>
|
||||||
|
<link rel="shortcut icon" href="https://r2.337845818.best/tamabox/tamabox_low.png" />
|
||||||
|
<link rel="apple-touch-icon" href="https://r2.337845818.best/tamabox/tamabox_low.png"/>
|
||||||
|
<link rel="icon" sizes="192x192" href="https://r2.337845818.best/tamabox/tamabox_low.png">
|
||||||
|
<meta name="twitter:image:src" content="https://r2.337845818.best/tamabox/tamabox_low.png" />
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<meta name="google-site-verification" content="fEPwRRJfiGsgwc5SINBQwZhPK8F0cwRaOvRx0YRurI4" />
|
||||||
|
|
||||||
|
<script>
|
||||||
|
window.addEventListener("load", function () {
|
||||||
|
var s = document.createElement("script");
|
||||||
|
s.src = "https://mami.shiroko.one/tamami.js";
|
||||||
|
s.setAttribute("data-website-id", "c42ebe8b-9281-4da0-83a4-8f18b3e710fe");
|
||||||
|
document.body.appendChild(s);
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<script>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
window.tbRenderQR = function (el, getOptions) {
|
||||||
|
if (!el || typeof QRCode === 'undefined') return;
|
||||||
|
var opts = getOptions();
|
||||||
|
function remoteOf(o, key) {
|
||||||
|
var v = o[key];
|
||||||
|
return (typeof v === 'string' && v.indexOf('http') === 0) ? v : '';
|
||||||
|
}
|
||||||
|
var good = window._tbQrGood || (window._tbQrGood = {});
|
||||||
|
var bad = window._tbQrBad || (window._tbQrBad = {});
|
||||||
|
|
||||||
|
function layerState(url) { return !url ? '' : (good[url] ? 1 : (bad[url] ? 0 : null)); }
|
||||||
|
var layers = [
|
||||||
|
{ url: remoteOf(opts, 'logo'), st: null, present: function (o, on) {
|
||||||
|
if (on) { } else { o.logo = undefined; o.logoWidth = undefined; o.logoHeight = undefined; o.logoBackgroundTransparent = undefined; }
|
||||||
|
} },
|
||||||
|
{ url: remoteOf(opts, 'backgroundImage'), st: null, present: function (o, on) {
|
||||||
|
if (on) { } else { o.backgroundImage = undefined; o.backgroundImageAlpha = undefined; }
|
||||||
|
} }
|
||||||
|
];
|
||||||
|
var needProbe = false;
|
||||||
|
for (var i = 0; i < layers.length; i++) {
|
||||||
|
layers[i].st = layerState(layers[i].url);
|
||||||
|
if (layers[i].st === null) needProbe = true;
|
||||||
|
}
|
||||||
|
function paint(states) {
|
||||||
|
var o = {};
|
||||||
|
for (var k in opts) o[k] = opts[k];
|
||||||
|
for (var j = 0; j < layers.length; j++) layers[j].present(o, states[j] === 1);
|
||||||
|
el.innerHTML = '';
|
||||||
|
new QRCode(el, o);
|
||||||
|
}
|
||||||
|
|
||||||
|
var initStates = [];
|
||||||
|
for (var n = 0; n < layers.length; n++) initStates.push(layers[n].st === 1 ? 1 : 0);
|
||||||
|
paint(initStates);
|
||||||
|
if (!needProbe) return;
|
||||||
|
|
||||||
|
var pending = 0, cross = opts.crossOrigin || 'anonymous';
|
||||||
|
layers.forEach(function (L) {
|
||||||
|
if (L.st !== null) return;
|
||||||
|
pending++;
|
||||||
|
var im = new Image();
|
||||||
|
im.onload = function () { good[L.url] = true; L.st = 1; onDone(); };
|
||||||
|
im.onerror = function () { bad[L.url] = true; L.st = 0; onDone(); };
|
||||||
|
if (cross) im.crossOrigin = cross;
|
||||||
|
im.src = L.url;
|
||||||
|
});
|
||||||
|
function onDone() {
|
||||||
|
if (--pending > 0) return;
|
||||||
|
var finalStates = [];
|
||||||
|
for (var m = 0; m < layers.length; m++) finalStates.push(layers[m].st === 1 ? 1 : 0);
|
||||||
|
var changed = false;
|
||||||
|
for (var q = 0; q < finalStates.length; q++) if (finalStates[q] !== initStates[q]) changed = true;
|
||||||
|
if (changed) paint(finalStates);
|
||||||
|
}
|
||||||
|
|
||||||
|
setTimeout(function () { if (pending > 0) { pending = 0; onDone(); } }, 3000);
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
<nav class="uk-navbar-container uk-margin tb-navbar" uk-navbar>
|
||||||
|
<div class="uk-navbar-center">
|
||||||
|
<div class="uk-navbar-center-left">
|
||||||
|
<div>
|
||||||
|
<ul class="uk-navbar-nav">
|
||||||
|
|
||||||
|
<li><a href="/explore">探索</a></li>
|
||||||
|
|
||||||
|
|
||||||
|
<li class="tb-mobile-balancer" aria-hidden="true"><a tabindex="-1" style="visibility:hidden">マイ</a></li>
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<a class="uk-navbar-item uk-logo" href="/"><span class="emoji-placeholder" aria-label="random animal">🐺</span>の質問箱</a>
|
||||||
|
|
||||||
|
<div class="uk-navbar-center-right">
|
||||||
|
<div>
|
||||||
|
|
||||||
|
<ul class="uk-navbar-nav">
|
||||||
|
<li><a href="/register">登録</a></li>
|
||||||
|
</ul>
|
||||||
|
<ul class="uk-navbar-nav">
|
||||||
|
<li><a href="/login">ログイン</a></li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<ul class="uk-navbar-nav tb-nav-utils">
|
||||||
|
<li>
|
||||||
|
<a href="#" aria-label="言語" title="言語"><svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><circle cx="12" cy="12" r="9"/><path d="M3.2 9h17.6M3.2 15h17.6"/><ellipse cx="12" cy="12" rx="4" ry="9"/></svg></a>
|
||||||
|
<div class="uk-navbar-dropdown" uk-drop="mode: click; pos: bottom-right">
|
||||||
|
<ul class="uk-nav uk-navbar-dropdown-nav">
|
||||||
|
|
||||||
|
<li class="">
|
||||||
|
<a href="/i18n/zh-CN?to=%2Fvote%2Fz9F8mIqPtDOA">简体中文</a>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li class="">
|
||||||
|
<a href="/i18n/zh-TW?to=%2Fvote%2Fz9F8mIqPtDOA">繁體中文</a>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li class="">
|
||||||
|
<a href="/i18n/en?to=%2Fvote%2Fz9F8mIqPtDOA">English</a>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li class="uk-active">
|
||||||
|
<a href="/i18n/ja?to=%2Fvote%2Fz9F8mIqPtDOA">日本語</a>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
|
||||||
|
<ul class="uk-navbar-nav tb-nav-utils">
|
||||||
|
<li>
|
||||||
|
<a href="#" id="theme-toggle" title="ダーク/ライトモード切替" aria-label="ダーク/ライトモード切替">
|
||||||
|
<span class="tb-icon-light"><svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M20.5 14.3A8.6 8.6 0 0 1 9.7 3.5a8.6 8.6 0 1 0 10.8 10.8z"/></svg></span><span class="tb-icon-dark"><svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><circle cx="12" cy="12" r="4"/><path d="M12 2.5v2M12 19.5v2M2.5 12h2M19.5 12h2M5.2 5.2l1.4 1.4M17.4 17.4l1.4 1.4M18.8 5.2l-1.4 1.4M6.6 17.4l-1.4 1.4"/></svg></span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
document.addEventListener("DOMContentLoaded", function() {
|
||||||
|
const emojis = ["🐺","🐗","🐻","🐨","🐼","🐹","🐭","🐰","🦊","🐮","🐷","🐽","🐸","🐒","🦍","🐔","🐧","🐦","🐤","🐦⬛","🦅","🦉","🦇","🐴","🦄","🐝","🦎","🦖","🦕","🐙","🦑","🦐","🦞","🦀","🐡","🐠","🐟","🐬","🐳","🐋","🦈","🐊","🐅","🐆","🦓","🦍","🦧","🐘","🦛","🦏","🐪","🐫","🦒","🦘","🐃","🐂","🐄","🐎","🐖","🐏","🐑","🦙","🐐","🦌","🐕","🐩","🦮","🐕🦺","🐈","🐋","🐳","🐬","🐉","🐲"];
|
||||||
|
const placeholder = document.querySelector('.emoji-placeholder');
|
||||||
|
if (placeholder) {
|
||||||
|
placeholder.textContent = emojis[Math.floor(Math.random() * emojis.length)];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
<div id="tb-mobile-utils">
|
||||||
|
|
||||||
|
<select id="mobile-lang-select" class="uk-select uk-form-small" aria-label="言語">
|
||||||
|
|
||||||
|
<option value="zh-CN" >简体中文</option>
|
||||||
|
|
||||||
|
<option value="zh-TW" >繁體中文</option>
|
||||||
|
|
||||||
|
<option value="en" >English</option>
|
||||||
|
|
||||||
|
<option value="ja" selected>日本語</option>
|
||||||
|
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<button type="button" id="theme-toggle-mobile" class="uk-button uk-button-default uk-button-small"
|
||||||
|
title="ダーク/ライトモード切替" aria-label="ダーク/ライトモード切替">
|
||||||
|
<span class="tb-icon-light"><svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M20.5 14.3A8.6 8.6 0 0 1 9.7 3.5a8.6 8.6 0 1 0 10.8 10.8z"/></svg></span><span class="tb-icon-dark"><svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><circle cx="12" cy="12" r="4"/><path d="M12 2.5v2M12 19.5v2M2.5 12h2M19.5 12h2M5.2 5.2l1.4 1.4M17.4 17.4l1.4 1.4M18.8 5.2l-1.4 1.4M6.6 17.4l-1.4 1.4"/></svg></span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
(function() {
|
||||||
|
|
||||||
|
var THEME_COOKIE = 'theme';
|
||||||
|
function getTheme() {
|
||||||
|
var m = document.cookie.match(/(?:^|;\s*)theme=([^;]*)/);
|
||||||
|
return m ? m[1] : '';
|
||||||
|
}
|
||||||
|
function applyTheme(theme) {
|
||||||
|
if (theme === 'dark') {
|
||||||
|
document.documentElement.setAttribute('data-theme', 'dark');
|
||||||
|
} else {
|
||||||
|
document.documentElement.removeAttribute('data-theme');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function toggleTheme() {
|
||||||
|
var next = getTheme() === 'dark' ? 'light' : 'dark';
|
||||||
|
applyTheme(next);
|
||||||
|
var expires = new Date(Date.now() + 365 * 24 * 3600 * 1000).toUTCString();
|
||||||
|
document.cookie = THEME_COOKIE + '=' + next + '; path=/; max-age=' + (365 * 24 * 3600) + '; SameSite=Lax';
|
||||||
|
}
|
||||||
|
|
||||||
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
|
|
||||||
|
var buttons = document.querySelectorAll('#theme-toggle, #theme-toggle-mobile');
|
||||||
|
buttons.forEach(function(btn) {
|
||||||
|
btn.addEventListener('click', function(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
toggleTheme();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
var langSel = document.getElementById('mobile-lang-select');
|
||||||
|
if (langSel) {
|
||||||
|
langSel.addEventListener('change', function() {
|
||||||
|
if (!this.value) return;
|
||||||
|
var to = window.location.pathname + window.location.search;
|
||||||
|
window.location.href = '/i18n/' + encodeURIComponent(this.value) + '?to=' + encodeURIComponent(to);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
})();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
<div class="uk-container uk-container-xsmall">
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<div id="math-captcha-modal" uk-modal>
|
||||||
|
<div class="uk-modal-dialog uk-modal-body uk-text-center">
|
||||||
|
<h3 class="uk-modal-title">人機認証</h3>
|
||||||
|
<p class="uk-text-meta">以下の計算問題を解いて、ロボットでないことを証明してください</p>
|
||||||
|
<div class="captcha-equation-box">
|
||||||
|
<span id="captcha-modal-question" class="math-captcha-modal-question">読み込み中...</span>
|
||||||
|
<input type="number" id="captcha-modal-answer" placeholder="?" autocomplete="off" inputmode="numeric">
|
||||||
|
</div>
|
||||||
|
<div style="margin-top:6px;">
|
||||||
|
<button type="button" class="uk-button uk-button-text uk-text-small" id="captcha-modal-refresh">別の問題</button>
|
||||||
|
</div>
|
||||||
|
<div id="captcha-modal-error" class="uk-text-danger uk-text-small" style="display:none;min-height:20px;"></div>
|
||||||
|
<div class="uk-margin-small-top">
|
||||||
|
<button type="button" class="uk-button uk-button-primary" id="captcha-modal-submit">送信</button>
|
||||||
|
<button type="button" class="uk-button uk-button-default uk-modal-close">キャンセル</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
var CAPTCHA_I18N = {
|
||||||
|
loading: "読み込み中...",
|
||||||
|
loadFailed: "読み込み失敗",
|
||||||
|
loadRetry: "読み込み失敗、再試行してください",
|
||||||
|
inputAnswer: "答えを入力してください",
|
||||||
|
wrongAnswer: "答えが違います。もう一度計算してください",
|
||||||
|
verifyFailed: "認証失敗、再試行してください",
|
||||||
|
needPassword: "この質問箱にはパスワードが必要です",
|
||||||
|
needEmail: "通知を受け取るメールアドレスを入力してください"
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
(function() {
|
||||||
|
var captchaId = '';
|
||||||
|
var pendingForm = null;
|
||||||
|
var pendingNeedPassword = false;
|
||||||
|
var verifying = false;
|
||||||
|
|
||||||
|
function fetchCaptcha() {
|
||||||
|
var qEl = document.getElementById('captcha-modal-question');
|
||||||
|
var errEl = document.getElementById('captcha-modal-error');
|
||||||
|
var ansEl = document.getElementById('captcha-modal-answer');
|
||||||
|
qEl.textContent = CAPTCHA_I18N.loading;
|
||||||
|
fetch('/api/captcha/generate')
|
||||||
|
.then(function(r) { return r.json(); })
|
||||||
|
.then(function(data) {
|
||||||
|
if (data.code === 0 && data.data) {
|
||||||
|
captchaId = data.data.id;
|
||||||
|
qEl.textContent = data.data.question;
|
||||||
|
if (errEl) errEl.style.display = 'none';
|
||||||
|
if (ansEl) { ansEl.value = ''; ansEl.focus(); }
|
||||||
|
} else {
|
||||||
|
qEl.textContent = CAPTCHA_I18N.loadFailed;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(function() {
|
||||||
|
qEl.textContent = CAPTCHA_I18N.loadRetry;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function getCSRFToken() {
|
||||||
|
var input = document.querySelector('input[name="_csrf"]');
|
||||||
|
return input ? input.value : '';
|
||||||
|
}
|
||||||
|
|
||||||
|
function doSubmit(form) {
|
||||||
|
|
||||||
|
var ans = document.getElementById('captcha-modal-answer').value.trim();
|
||||||
|
var hidden = form.querySelector('[name="g-recaptcha-response"]');
|
||||||
|
if (hidden) hidden.value = captchaId + ':' + (ans || '0');
|
||||||
|
|
||||||
|
UIkit.modal('#math-captcha-modal').hide();
|
||||||
|
|
||||||
|
|
||||||
|
if (pendingNeedPassword) {
|
||||||
|
UIkit.modal.prompt(CAPTCHA_I18N.needPassword, '', 'password')
|
||||||
|
.then(function(password) {
|
||||||
|
if (password) {
|
||||||
|
var pwInput = document.getElementById('ask_password_input');
|
||||||
|
if (pwInput) pwInput.value = password;
|
||||||
|
form.submit();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
form.submit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
document.getElementById('captcha-modal-submit').addEventListener('click', function() {
|
||||||
|
if (verifying) return;
|
||||||
|
var ans = document.getElementById('captcha-modal-answer').value.trim();
|
||||||
|
if (!ans) {
|
||||||
|
var errEl = document.getElementById('captcha-modal-error');
|
||||||
|
errEl.textContent = CAPTCHA_I18N.inputAnswer;
|
||||||
|
errEl.style.display = 'block';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
verifying = true;
|
||||||
|
fetch('/api/captcha/verify', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'X-CSRF-Token': getCSRFToken()
|
||||||
|
},
|
||||||
|
body: JSON.stringify({ id: captchaId, answer: parseInt(ans, 10) })
|
||||||
|
})
|
||||||
|
.then(function(r) { return r.json(); })
|
||||||
|
.then(function(data) {
|
||||||
|
verifying = false;
|
||||||
|
if (data.correct) {
|
||||||
|
if (pendingForm) doSubmit(pendingForm);
|
||||||
|
} else {
|
||||||
|
var errEl = document.getElementById('captcha-modal-error');
|
||||||
|
errEl.textContent = CAPTCHA_I18N.wrongAnswer;
|
||||||
|
errEl.style.display = 'block';
|
||||||
|
fetchCaptcha();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(function() {
|
||||||
|
verifying = false;
|
||||||
|
var errEl = document.getElementById('captcha-modal-error');
|
||||||
|
errEl.textContent = CAPTCHA_I18N.verifyFailed;
|
||||||
|
errEl.style.display = 'block';
|
||||||
|
fetchCaptcha();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
document.getElementById('captcha-modal-answer').addEventListener('keydown', function(e) {
|
||||||
|
if (e.key === 'Enter') {
|
||||||
|
e.preventDefault();
|
||||||
|
document.getElementById('captcha-modal-submit').click();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
document.getElementById('captcha-modal-refresh').addEventListener('click', fetchCaptcha);
|
||||||
|
|
||||||
|
|
||||||
|
document.addEventListener('click', function(e) {
|
||||||
|
var btn = e.target.closest('.math-captcha-trigger');
|
||||||
|
if (!btn) return;
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
var form = btn.closest('form');
|
||||||
|
if (!form) return;
|
||||||
|
pendingForm = form;
|
||||||
|
|
||||||
|
|
||||||
|
pendingNeedPassword = !!(form.querySelector('#ask_password_input'));
|
||||||
|
|
||||||
|
|
||||||
|
var notifyCb = document.getElementById('notify-checkbox');
|
||||||
|
var emailInput = document.getElementById('email-input');
|
||||||
|
if (notifyCb && notifyCb.checked && emailInput && emailInput.value.trim() === '') {
|
||||||
|
UIkit.modal.alert(CAPTCHA_I18N.needEmail);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
fetchCaptcha();
|
||||||
|
UIkit.modal('#math-captcha-modal').show();
|
||||||
|
});
|
||||||
|
})();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
<style>
|
||||||
|
|
||||||
|
.tb-field-head {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
align-items: center;
|
||||||
|
gap: 6px 8px;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
.tb-field-head .tb-field-label {
|
||||||
|
flex-basis: 100%;
|
||||||
|
font-weight: 600;
|
||||||
|
line-height: 1.5;
|
||||||
|
word-break: break-word;
|
||||||
|
overflow-wrap: anywhere;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tb-choice {
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-start;
|
||||||
|
gap: 10px;
|
||||||
|
padding: 12px 14px;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
border: 1px solid var(--tb-border);
|
||||||
|
border-radius: 8px;
|
||||||
|
background: var(--tb-surface);
|
||||||
|
cursor: pointer;
|
||||||
|
transition: border-color 0.2s ease, background 0.2s ease;
|
||||||
|
}
|
||||||
|
.tb-choice:last-child { margin-bottom: 0; }
|
||||||
|
.tb-choice input[type="radio"], .tb-choice input[type="checkbox"] {
|
||||||
|
margin-top: 3px;
|
||||||
|
}
|
||||||
|
.tb-choice span {
|
||||||
|
flex: 1;
|
||||||
|
min-width: 0;
|
||||||
|
line-height: 1.5;
|
||||||
|
word-break: break-word;
|
||||||
|
overflow-wrap: anywhere;
|
||||||
|
}
|
||||||
|
.tb-choice:hover {
|
||||||
|
border-color: var(--tb-primary);
|
||||||
|
background: var(--tb-surface-hover);
|
||||||
|
}
|
||||||
|
.tb-choice:has(input:checked) {
|
||||||
|
border-color: var(--tb-primary);
|
||||||
|
background: var(--tb-surface-active);
|
||||||
|
}
|
||||||
|
html[data-theme="dark"] .tb-choice {
|
||||||
|
border-color: var(--tb-border);
|
||||||
|
background: var(--tb-surface);
|
||||||
|
}
|
||||||
|
html[data-theme="dark"] .tb-choice:hover {
|
||||||
|
border-color: var(--tb-primary);
|
||||||
|
background: rgba(78, 168, 245, 0.08);
|
||||||
|
}
|
||||||
|
html[data-theme="dark"] .tb-choice:has(input:checked) {
|
||||||
|
border-color: var(--tb-primary);
|
||||||
|
background: rgba(78, 168, 245, 0.14);
|
||||||
|
}
|
||||||
|
|
||||||
|
.tb-custom-input {
|
||||||
|
margin-top: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tb-text-counter {
|
||||||
|
margin-top: 2px;
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
@media (max-width: 480px) {
|
||||||
|
.tb-choice { padding: 10px 12px; }
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<div class="uk-card uk-card-default uk-card-body uk-margin-bottom">
|
||||||
|
<div class="uk-flex uk-flex-middle uk-margin-small-bottom" style="gap: 10px;">
|
||||||
|
|
||||||
|
<img class="uk-border-circle" src="https://r2.337845818.best/tamabox/picture/2026/08/19/9af3e38222d972ff9141e9cfdb0475" style="width: 40px; height: 40px;">
|
||||||
|
<div>
|
||||||
|
<a class="uk-text-bold" href="/_admin6">admin6</a>
|
||||||
|
<div class="uk-text-meta uk-text-small">の投票</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="uk-margin-auto-left">
|
||||||
|
|
||||||
|
|
||||||
|
<span class="uk-label uk-label-success">進行中</span>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h3 class="uk-margin-remove-top uk-margin-small-bottom">测试4</h3>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<div class="uk-alert uk-alert-primary uk-text-small">匿名での参加が可能で、あなたの身元は記録されません(同一端末で最大1回)。</div>
|
||||||
|
|
||||||
|
|
||||||
|
<form method="post" action="/vote/z9F8mIqPtDOA/submit" id="vote-form" onsubmit="return validateVoteForm()">
|
||||||
|
<input type="hidden" name="_csrf" value="qBbXZwRVpmkq4Eu5WACxCt_Z1hA6MTc5MjM4NTMxNTE1OTQ4ODAxMQ">
|
||||||
|
<input type="hidden" name="g-recaptcha-response" id="g-recaptcha-response" value="">
|
||||||
|
|
||||||
|
<div class="uk-card uk-card-default uk-card-body uk-margin-bottom">
|
||||||
|
|
||||||
|
|
||||||
|
<div class="uk-margin">
|
||||||
|
<div class="tb-field-head">
|
||||||
|
<span class="tb-chip">1</span>
|
||||||
|
<span class="tb-chip">単一選択</span>
|
||||||
|
<div class="tb-field-label">这里显示第一题</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<label class="tb-choice">
|
||||||
|
<input class="uk-radio" type="radio" name="field_19" value="A" ><span>A</span>
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<label class="tb-choice">
|
||||||
|
<input class="uk-radio" type="radio" name="field_19" value="B" ><span>B</span>
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<label class="tb-choice">
|
||||||
|
<input class="uk-radio" type="radio" name="field_19" value="C" ><span>C</span>
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<label class="tb-choice">
|
||||||
|
<input class="uk-radio" type="radio" name="field_19" value="D" ><span>D</span>
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<label class="tb-choice">
|
||||||
|
<input class="uk-radio" type="radio" name="field_19" value="E" ><span>E</span>
|
||||||
|
</label>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="uk-margin">
|
||||||
|
<div class="tb-field-head">
|
||||||
|
<span class="tb-chip">2</span>
|
||||||
|
<span class="tb-chip">単一選択</span>
|
||||||
|
<div class="tb-field-label">11</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<label class="tb-choice">
|
||||||
|
<input class="uk-radio" type="radio" name="field_20" value="1" ><span>1</span>
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<label class="tb-choice">
|
||||||
|
<input class="uk-radio" type="radio" name="field_20" value="2" ><span>2</span>
|
||||||
|
</label>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="uk-margin">
|
||||||
|
|
||||||
|
<button type="button" class="uk-button uk-button-primary math-captcha-trigger" onclick="return voteValidate(event)">投票する</button>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<script>
|
||||||
|
|
||||||
|
|
||||||
|
var MAX_CUSTOM_LEN = 200 ;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
function countChars(s) { return Array.from(String(s || '')).length; }
|
||||||
|
|
||||||
|
|
||||||
|
function setupTextCounters() {
|
||||||
|
var form = document.getElementById('vote-form');
|
||||||
|
if (!form) { return; }
|
||||||
|
form.querySelectorAll('[data-tb-text-counter]').forEach(function (input) {
|
||||||
|
var max = parseInt(input.getAttribute('data-tb-text-max'), 10);
|
||||||
|
if (!max || max < 1) { max = MAX_CUSTOM_LEN; }
|
||||||
|
var counter = document.createElement('div');
|
||||||
|
counter.className = 'uk-text-meta uk-text-small tb-text-counter';
|
||||||
|
if (input.parentNode) { input.parentNode.insertBefore(counter, input.nextSibling); }
|
||||||
|
var update = function () {
|
||||||
|
var n = countChars(input.value);
|
||||||
|
counter.textContent = n + ' / ' + max;
|
||||||
|
if (n > max) {
|
||||||
|
counter.classList.add('uk-text-danger');
|
||||||
|
input.setAttribute('data-tb-too-long', '1');
|
||||||
|
} else {
|
||||||
|
counter.classList.remove('uk-text-danger');
|
||||||
|
input.removeAttribute('data-tb-too-long');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
input.addEventListener('input', update);
|
||||||
|
update();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
function validateVoteForm() {
|
||||||
|
var form = document.getElementById('vote-form');
|
||||||
|
if (!form) { return true; }
|
||||||
|
|
||||||
|
var tooLong = form.querySelector('[data-tb-text-counter][data-tb-too-long]');
|
||||||
|
if (tooLong) {
|
||||||
|
alert('自由記入オプションは 200 字以内にしてください');
|
||||||
|
tooLong.focus();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
var groups = {};
|
||||||
|
form.querySelectorAll('input[data-vote-required][type="radio"], input[data-vote-required][type="checkbox"]').forEach(function (el) {
|
||||||
|
(groups[el.name] = groups[el.name] || []).push(el);
|
||||||
|
});
|
||||||
|
for (var name in groups) {
|
||||||
|
var any = groups[name].some(function (el) { return el.checked; });
|
||||||
|
if (!any) {
|
||||||
|
alert('入力してください「' + groups[name][0].getAttribute('data-vote-label') + '」');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var els = form.querySelectorAll('[data-vote-required]:not(input[type="radio"]):not(input[type="checkbox"])');
|
||||||
|
for (var i = 0; i < els.length; i++) {
|
||||||
|
var el = els[i];
|
||||||
|
if (el.disabled) { continue; }
|
||||||
|
if ((el.value || '').trim() === '') {
|
||||||
|
alert('入力してください「' + el.getAttribute('data-vote-label') + '」');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function voteValidate(e) {
|
||||||
|
if (!validateVoteForm()) {
|
||||||
|
if (e) { e.stopPropagation(); e.preventDefault(); }
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function onSubmit() {
|
||||||
|
if (validateVoteForm()) {
|
||||||
|
document.getElementById('vote-form').submit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
(function () {
|
||||||
|
var form = document.getElementById('vote-form');
|
||||||
|
if (!form) { return; }
|
||||||
|
setupTextCounters();
|
||||||
|
var maxChoices = 0;
|
||||||
|
if (maxChoices > 0) {
|
||||||
|
var boxes = form.querySelectorAll('input[type="checkbox"][name="option_ids"]');
|
||||||
|
boxes.forEach(function (box) {
|
||||||
|
box.addEventListener('change', function () {
|
||||||
|
var checked = form.querySelectorAll('input[type="checkbox"][name="option_ids"]:checked').length;
|
||||||
|
if (checked > maxChoices) { this.checked = false; }
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
var CUSTOM_MARKER = "__tb_custom_option__";
|
||||||
|
form.querySelectorAll('[data-vote-custom-input]').forEach(function (input) {
|
||||||
|
var fid = input.getAttribute('data-vote-custom-input');
|
||||||
|
var group = form.querySelectorAll('input[name="field_' + fid + '"]');
|
||||||
|
var select = form.querySelector('select[name="field_' + fid + '"]');
|
||||||
|
var sync = function () {
|
||||||
|
var on = false;
|
||||||
|
if (select) {
|
||||||
|
on = (select.value === CUSTOM_MARKER);
|
||||||
|
} else {
|
||||||
|
group.forEach(function (r) { if (r.value === CUSTOM_MARKER && r.checked) { on = true; } });
|
||||||
|
}
|
||||||
|
input.disabled = !on;
|
||||||
|
if (!on) { input.value = ''; }
|
||||||
|
};
|
||||||
|
if (select) { select.addEventListener('change', sync); } else { group.forEach(function (r) { r.addEventListener('change', sync); }); }
|
||||||
|
sync();
|
||||||
|
});
|
||||||
|
})();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<p class=" uk-text-right uk-text-muted uk-text-small">
|
||||||
|
<br>
|
||||||
|
<a href="/rules">ルール</a> |
|
||||||
|
|
||||||
|
<a href="https://box.shiroko.one/_/tamakyi" target="_blank">管理者へ</a>
|
||||||
|
<br>
|
||||||
|
<a href="https://share.shiroko.one" target="_blank">ドライブ</a>
|
||||||
|
| <a href="https://blog.shiroko.one" target="_blank">お知らせ</a>
|
||||||
|
| <a href="https://chat.shiroko.one" target="_blank">チャット</a>
|
||||||
|
| <a href="https://status.shiroko.one" target="_blank">ステータス</a>
|
||||||
|
| <a href="https://shiroko.one" target="_blank">リンク</a>
|
||||||
|
<br>Powered by NekoBox | 狼ICP备 20230101
|
||||||
|
<br>質問箱は稼働中:<span id="box_runtime"></span>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
(function () {
|
||||||
|
var create = Math.round(Date.UTC(2023, 6, 1, 18, 15, 43) / 1000);
|
||||||
|
function tick() {
|
||||||
|
var el = document.getElementById("box_runtime");
|
||||||
|
if (!el) return;
|
||||||
|
var s = Math.round((Date.now() + 8 * 3600 * 1000) / 1000) - create;
|
||||||
|
var t = [0, 0, 0, 0, 0];
|
||||||
|
if (s >= 31536000) { t[0] = s / 31536000 | 0; s %= 31536000; }
|
||||||
|
if (s >= 86400) { t[1] = s / 86400 | 0; s %= 86400; }
|
||||||
|
if (s >= 3600) { t[2] = s / 3600 | 0; s %= 3600; }
|
||||||
|
if (s >= 60) { t[3] = s / 60 | 0; s %= 60; }
|
||||||
|
if (s > 0) { t[4] = s; }
|
||||||
|
el.innerHTML = t[0] + '年 ' + t[1] + '天 ' + t[2] + '时 ' + t[3] + '分 ' + t[4] + '秒 ';
|
||||||
|
}
|
||||||
|
tick();
|
||||||
|
setInterval(tick, 1000);
|
||||||
|
})();
|
||||||
|
</script>
|
||||||
|
<br>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
var SUBMIT_I18N = {
|
||||||
|
submitting: '送信中...',
|
||||||
|
uploading: 'アップロード中...'
|
||||||
|
};
|
||||||
|
|
||||||
|
function tbResetSubmitButtons() {
|
||||||
|
document.querySelectorAll('button[data-tb-submitting]').forEach(function(b) {
|
||||||
|
b.disabled = false;
|
||||||
|
b.removeAttribute('data-tb-submitting');
|
||||||
|
var orig = b.getAttribute('data-tb-restore');
|
||||||
|
if (orig !== null) {
|
||||||
|
b.innerHTML = orig;
|
||||||
|
b.removeAttribute('data-tb-restore');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
document.addEventListener('submit', function(e) {
|
||||||
|
var form = e.target;
|
||||||
|
if (!form || form.tagName !== 'FORM') return;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if (e.defaultPrevented || form.getAttribute('data-tb-skip-submit-feedback') === '1') {
|
||||||
|
form.removeAttribute('data-tb-skip-submit-feedback');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if (form.getAttribute('target') === '_blank') return;
|
||||||
|
|
||||||
|
|
||||||
|
var trigger = e.submitter || form.querySelector('button[type="submit"]');
|
||||||
|
|
||||||
|
|
||||||
|
var hasFile = false;
|
||||||
|
form.querySelectorAll('input[type="file"]').forEach(function(f) {
|
||||||
|
if (f.files && f.files.length > 0) hasFile = true;
|
||||||
|
});
|
||||||
|
var label = hasFile ? SUBMIT_I18N.uploading : SUBMIT_I18N.submitting;
|
||||||
|
|
||||||
|
if (trigger && trigger.tagName === 'BUTTON') {
|
||||||
|
trigger.setAttribute('data-tb-restore', trigger.innerHTML);
|
||||||
|
trigger.innerHTML = '<span uk-spinner="ratio: 0.6"></span> ' + label;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
form.querySelectorAll('button').forEach(function(b) {
|
||||||
|
b.disabled = true;
|
||||||
|
b.setAttribute('data-tb-submitting', '1');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
window.addEventListener('pageshow', tbResetSubmitButtons);
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
HTTP/1.1 200 Connection Established
|
||||||
|
|
||||||
|
HTTP/1.1 200 OK
|
||||||
|
Date: Mon, 19 Oct 2026 04:50:43 GMT
|
||||||
|
Content-Type: text/html; charset=utf-8
|
||||||
|
Transfer-Encoding: chunked
|
||||||
|
Connection: keep-alive
|
||||||
|
Speculation-Rules: "/cdn-cgi/speculation"
|
||||||
|
referrer-policy: strict-origin-when-cross-origin
|
||||||
|
strict-transport-security: max-age=31536000; includeSubDomains
|
||||||
|
trace-id: 00000000000000000000000000000000
|
||||||
|
vary: Accept-Encoding
|
||||||
|
x-content-type-options: nosniff
|
||||||
|
x-frame-options: DENY
|
||||||
|
x-xss-protection: 1; mode=block
|
||||||
|
cf-cache-status: DYNAMIC
|
||||||
|
Nel: {"report_to":"cf-nel","success_fraction":0.0,"max_age":604800}
|
||||||
|
Report-To: {"group":"cf-nel","max_age":604800,"endpoints":[{"url":"https://a.nel.cloudflare.com/report/v4?s=LNNyS3fb%2BRQ4lDSreatYe3z7vYXJ5DBvFEY39WJc%2B8HZ1NjXYKxVWdDWaiWMQ%2B%2FvlEA0T2DYuliVVbPWsERm5o1d9QfSG0wMX8hF5b0XBHoxociB8pPyH1LZDRlllEINsKtHcLfseGtFGQr58g%3D%3D"}]}
|
||||||
|
Server: cloudflare
|
||||||
|
CF-RAY: a4cd29d93d591ca5-AMS
|
||||||
|
alt-svc: h3=":443"; ma=86400
|
||||||
|
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
HTTP/1.1 200 Connection Established
|
||||||
|
|
||||||
|
HTTP/1.1 200 OK
|
||||||
|
Date: Mon, 19 Oct 2026 04:50:47 GMT
|
||||||
|
Content-Type: text/html; charset=utf-8
|
||||||
|
Transfer-Encoding: chunked
|
||||||
|
Connection: keep-alive
|
||||||
|
Speculation-Rules: "/cdn-cgi/speculation"
|
||||||
|
referrer-policy: strict-origin-when-cross-origin
|
||||||
|
strict-transport-security: max-age=31536000; includeSubDomains
|
||||||
|
trace-id: 00000000000000000000000000000000
|
||||||
|
vary: Accept-Encoding
|
||||||
|
x-content-type-options: nosniff
|
||||||
|
x-frame-options: DENY
|
||||||
|
x-xss-protection: 1; mode=block
|
||||||
|
cf-cache-status: DYNAMIC
|
||||||
|
Nel: {"report_to":"cf-nel","success_fraction":0.0,"max_age":604800}
|
||||||
|
Report-To: {"group":"cf-nel","max_age":604800,"endpoints":[{"url":"https://a.nel.cloudflare.com/report/v4?s=s9ceWO0ESedGa5u0nddaXW07CHQrtIc9OIdjAPsRo7ngWVNAPIIdFbgiTZR5%2Bl3u2H9LTwdWSKOYpb1U90XF09z4x88W0xbDzjFZio9EwdShj1rTkK3E6WboqRk75JfBct3otKwp8vRlSed8vg%3D%3D"}]}
|
||||||
|
Server: cloudflare
|
||||||
|
CF-RAY: a4cd29f74dae1af9-AMS
|
||||||
|
alt-svc: h3=":443"; ma=86400
|
||||||
|
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
HTTP/1.1 200 Connection Established
|
||||||
|
|
||||||
|
HTTP/1.1 302 Found
|
||||||
|
Date: Mon, 19 Oct 2026 04:48:53 GMT
|
||||||
|
Content-Length: 0
|
||||||
|
Connection: keep-alive
|
||||||
|
location: /
|
||||||
|
referrer-policy: strict-origin-when-cross-origin
|
||||||
|
Set-Cookie: flamego_session=xzuo76g1wkt93yde; Path=/; HttpOnly; Secure; SameSite=Lax
|
||||||
|
strict-transport-security: max-age=31536000; includeSubDomains
|
||||||
|
trace-id: 00000000000000000000000000000000
|
||||||
|
x-content-type-options: nosniff
|
||||||
|
x-frame-options: DENY
|
||||||
|
x-xss-protection: 1; mode=block
|
||||||
|
cf-cache-status: DYNAMIC
|
||||||
|
Nel: {"report_to":"cf-nel","success_fraction":0.0,"max_age":604800}
|
||||||
|
Report-To: {"group":"cf-nel","max_age":604800,"endpoints":[{"url":"https://a.nel.cloudflare.com/report/v4?s=4lN%2FjpiiXhqAFEa04LgpyUx1T6gq6As3ND39p0U%2B%2B%2BnV18I8OPf%2B3C4P1hF2ZbvemgZD3yKBN0KGjMXH3MKidzjjBRg0UN0glf5LWn9QPaATLorzaAcF3cY3eMFsZ%2BFA3GJVVI%2FAv4v2dquZoA%3D%3D"}]}
|
||||||
|
Server: cloudflare
|
||||||
|
CF-RAY: a4cd27291b28a007-AMS
|
||||||
|
alt-svc: h3=":443"; ma=86400
|
||||||
|
|
||||||
@@ -0,0 +1,638 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="ja">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<title>狼の質問箱 | 匿名質問箱</title>
|
||||||
|
<meta name="msvalidate.01" content="2F185E8E63C93635F50B3574F3B31E42" />
|
||||||
|
<meta name="description" content="狼の質問箱は登録不要で使える匿名質問箱。誰でも匿名で質問でき、安心してやり取りできる場所です。">
|
||||||
|
<meta name="keywords" content="匿名質問箱,質問箱,匿名質問,狼の質問箱,匿名で質問,匿名Q&A">
|
||||||
|
|
||||||
|
<script>
|
||||||
|
(function () {
|
||||||
|
var m = document.cookie.match(/(?:^|;\s*)theme=([^;]*)/);
|
||||||
|
if (m && m[1] === 'dark') document.documentElement.setAttribute('data-theme', 'dark');
|
||||||
|
})();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<link rel="preconnect" href="https://r2.337845818.best" crossorigin>
|
||||||
|
<link rel="preconnect" href="https://cdnjs.snrat.com" crossorigin>
|
||||||
|
|
||||||
|
<link rel="stylesheet" href="https://cdnjs.snrat.com/ajax/libs/uikit/3.3.3/css/uikit.min.css"/>
|
||||||
|
|
||||||
|
<link rel="stylesheet" href="/static/css/base.css?v=20261019d"/>
|
||||||
|
|
||||||
|
<link rel="stylesheet" href="https://r2.337845818.best/tamabox/cdn/waline/client/v2/waline-no-commits.css" media="print" onload="this.media='all'"/>
|
||||||
|
<script defer src="https://cdnjs.snrat.com/ajax/libs/uikit/3.3.3/js/uikit.min.js"></script>
|
||||||
|
<script defer src="https://cdnjs.snrat.com/ajax/libs/uikit/3.3.3/js/uikit-icons.min.js"></script>
|
||||||
|
|
||||||
|
<script defer src="https://cdnjs.snrat.com/ajax/libs/dayjs/1.10.8/dayjs.min.js"></script>
|
||||||
|
<script defer src="https://cdnjs.snrat.com/ajax/libs/alpinejs/3.9.0/cdn.min.js"></script>
|
||||||
|
|
||||||
|
|
||||||
|
<script defer src="https://cdnjs.snrat.com/ajax/libs/waline/2.15.8/waline.js"></script>
|
||||||
|
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.captcha-equation-box {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
background: #f0f2f5;
|
||||||
|
border: 1px solid #dcdcdc;
|
||||||
|
border-radius: 8px;
|
||||||
|
padding: 8px 8px 8px 16px;
|
||||||
|
gap: 6px;
|
||||||
|
transition: border-color 0.2s;
|
||||||
|
}
|
||||||
|
.captcha-equation-box:focus-within {
|
||||||
|
border-color: #1e87f0;
|
||||||
|
box-shadow: 0 0 0 3px rgba(30,135,240,0.12);
|
||||||
|
}
|
||||||
|
.math-captcha-modal-question {
|
||||||
|
font-size: 1.4rem;
|
||||||
|
font-family: "Courier New", monospace;
|
||||||
|
font-weight: 700;
|
||||||
|
color: #333;
|
||||||
|
letter-spacing: 1px;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
#captcha-modal-answer {
|
||||||
|
width: 80px;
|
||||||
|
padding: 6px 10px;
|
||||||
|
text-align: center;
|
||||||
|
font-size: 1.2rem;
|
||||||
|
font-family: "Courier New", monospace;
|
||||||
|
font-weight: 600;
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
border-radius: 5px;
|
||||||
|
outline: none;
|
||||||
|
transition: border-color 0.15s, box-shadow 0.15s;
|
||||||
|
background: #fff;
|
||||||
|
}
|
||||||
|
#captcha-modal-answer:focus {
|
||||||
|
border-color: #1e87f0;
|
||||||
|
box-shadow: 0 0 0 2px rgba(30,135,240,0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
#captcha-modal-answer::-webkit-inner-spin-button,
|
||||||
|
#captcha-modal-answer::-webkit-outer-spin-button {
|
||||||
|
-webkit-appearance: none;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
#captcha-modal-answer {
|
||||||
|
-moz-appearance: textfield;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<meta property="og:site_name" content="狼の質問箱 | 匿名質問箱" />
|
||||||
|
<meta property="og:type" content="website" />
|
||||||
|
<meta property="og:title" content="狼の質問箱 | 匿名質問箱" />
|
||||||
|
<meta property="og:url" content="https://box-dev-api.337845818.best/login" />
|
||||||
|
<meta property="og:description" content="狼の質問箱は登録不要で使える匿名質問箱。誰でも匿名で質問でき、安心してやり取りできる場所です。" />
|
||||||
|
|
||||||
|
|
||||||
|
<meta itemprop="image" content="https://r2.337845818.best/tamabox/tamabox_low.png"/>
|
||||||
|
<meta name="msapplication-TileImage" content="https://r2.337845818.best/tamabox/tamabox_low.png"/>
|
||||||
|
<link rel="shortcut icon" href="https://r2.337845818.best/tamabox/tamabox_low.png" />
|
||||||
|
<link rel="apple-touch-icon" href="https://r2.337845818.best/tamabox/tamabox_low.png"/>
|
||||||
|
<link rel="icon" sizes="192x192" href="https://r2.337845818.best/tamabox/tamabox_low.png">
|
||||||
|
<meta name="twitter:image:src" content="https://r2.337845818.best/tamabox/tamabox_low.png" />
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<meta name="google-site-verification" content="fEPwRRJfiGsgwc5SINBQwZhPK8F0cwRaOvRx0YRurI4" />
|
||||||
|
|
||||||
|
<script>
|
||||||
|
window.addEventListener("load", function () {
|
||||||
|
var s = document.createElement("script");
|
||||||
|
s.src = "https://mami.shiroko.one/tamami.js";
|
||||||
|
s.setAttribute("data-website-id", "c42ebe8b-9281-4da0-83a4-8f18b3e710fe");
|
||||||
|
document.body.appendChild(s);
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<script>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
window.tbRenderQR = function (el, getOptions) {
|
||||||
|
if (!el || typeof QRCode === 'undefined') return;
|
||||||
|
var opts = getOptions();
|
||||||
|
function remoteOf(o, key) {
|
||||||
|
var v = o[key];
|
||||||
|
return (typeof v === 'string' && v.indexOf('http') === 0) ? v : '';
|
||||||
|
}
|
||||||
|
var good = window._tbQrGood || (window._tbQrGood = {});
|
||||||
|
var bad = window._tbQrBad || (window._tbQrBad = {});
|
||||||
|
|
||||||
|
function layerState(url) { return !url ? '' : (good[url] ? 1 : (bad[url] ? 0 : null)); }
|
||||||
|
var layers = [
|
||||||
|
{ url: remoteOf(opts, 'logo'), st: null, present: function (o, on) {
|
||||||
|
if (on) { } else { o.logo = undefined; o.logoWidth = undefined; o.logoHeight = undefined; o.logoBackgroundTransparent = undefined; }
|
||||||
|
} },
|
||||||
|
{ url: remoteOf(opts, 'backgroundImage'), st: null, present: function (o, on) {
|
||||||
|
if (on) { } else { o.backgroundImage = undefined; o.backgroundImageAlpha = undefined; }
|
||||||
|
} }
|
||||||
|
];
|
||||||
|
var needProbe = false;
|
||||||
|
for (var i = 0; i < layers.length; i++) {
|
||||||
|
layers[i].st = layerState(layers[i].url);
|
||||||
|
if (layers[i].st === null) needProbe = true;
|
||||||
|
}
|
||||||
|
function paint(states) {
|
||||||
|
var o = {};
|
||||||
|
for (var k in opts) o[k] = opts[k];
|
||||||
|
for (var j = 0; j < layers.length; j++) layers[j].present(o, states[j] === 1);
|
||||||
|
el.innerHTML = '';
|
||||||
|
new QRCode(el, o);
|
||||||
|
}
|
||||||
|
|
||||||
|
var initStates = [];
|
||||||
|
for (var n = 0; n < layers.length; n++) initStates.push(layers[n].st === 1 ? 1 : 0);
|
||||||
|
paint(initStates);
|
||||||
|
if (!needProbe) return;
|
||||||
|
|
||||||
|
var pending = 0, cross = opts.crossOrigin || 'anonymous';
|
||||||
|
layers.forEach(function (L) {
|
||||||
|
if (L.st !== null) return;
|
||||||
|
pending++;
|
||||||
|
var im = new Image();
|
||||||
|
im.onload = function () { good[L.url] = true; L.st = 1; onDone(); };
|
||||||
|
im.onerror = function () { bad[L.url] = true; L.st = 0; onDone(); };
|
||||||
|
if (cross) im.crossOrigin = cross;
|
||||||
|
im.src = L.url;
|
||||||
|
});
|
||||||
|
function onDone() {
|
||||||
|
if (--pending > 0) return;
|
||||||
|
var finalStates = [];
|
||||||
|
for (var m = 0; m < layers.length; m++) finalStates.push(layers[m].st === 1 ? 1 : 0);
|
||||||
|
var changed = false;
|
||||||
|
for (var q = 0; q < finalStates.length; q++) if (finalStates[q] !== initStates[q]) changed = true;
|
||||||
|
if (changed) paint(finalStates);
|
||||||
|
}
|
||||||
|
|
||||||
|
setTimeout(function () { if (pending > 0) { pending = 0; onDone(); } }, 3000);
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
<nav class="uk-navbar-container uk-margin tb-navbar" uk-navbar>
|
||||||
|
<div class="uk-navbar-center">
|
||||||
|
<div class="uk-navbar-center-left">
|
||||||
|
<div>
|
||||||
|
<ul class="uk-navbar-nav">
|
||||||
|
|
||||||
|
<li><a href="/explore">探索</a></li>
|
||||||
|
|
||||||
|
|
||||||
|
<li class="tb-mobile-balancer" aria-hidden="true"><a tabindex="-1" style="visibility:hidden">マイ</a></li>
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<a class="uk-navbar-item uk-logo" href="/"><span class="emoji-placeholder" aria-label="random animal">🐺</span>の質問箱</a>
|
||||||
|
|
||||||
|
<div class="uk-navbar-center-right">
|
||||||
|
<div>
|
||||||
|
|
||||||
|
<ul class="uk-navbar-nav">
|
||||||
|
<li><a href="/register">登録</a></li>
|
||||||
|
</ul>
|
||||||
|
<ul class="uk-navbar-nav">
|
||||||
|
<li><a href="/login">ログイン</a></li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<ul class="uk-navbar-nav tb-nav-utils">
|
||||||
|
<li>
|
||||||
|
<a href="#" aria-label="言語" title="言語"><svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><circle cx="12" cy="12" r="9"/><path d="M3.2 9h17.6M3.2 15h17.6"/><ellipse cx="12" cy="12" rx="4" ry="9"/></svg></a>
|
||||||
|
<div class="uk-navbar-dropdown" uk-drop="mode: click; pos: bottom-right">
|
||||||
|
<ul class="uk-nav uk-navbar-dropdown-nav">
|
||||||
|
|
||||||
|
<li class="">
|
||||||
|
<a href="/i18n/zh-CN?to=%2Flogin">简体中文</a>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li class="">
|
||||||
|
<a href="/i18n/zh-TW?to=%2Flogin">繁體中文</a>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li class="">
|
||||||
|
<a href="/i18n/en?to=%2Flogin">English</a>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li class="uk-active">
|
||||||
|
<a href="/i18n/ja?to=%2Flogin">日本語</a>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
|
||||||
|
<ul class="uk-navbar-nav tb-nav-utils">
|
||||||
|
<li>
|
||||||
|
<a href="#" id="theme-toggle" title="ダーク/ライトモード切替" aria-label="ダーク/ライトモード切替">
|
||||||
|
<span class="tb-icon-light"><svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M20.5 14.3A8.6 8.6 0 0 1 9.7 3.5a8.6 8.6 0 1 0 10.8 10.8z"/></svg></span><span class="tb-icon-dark"><svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><circle cx="12" cy="12" r="4"/><path d="M12 2.5v2M12 19.5v2M2.5 12h2M19.5 12h2M5.2 5.2l1.4 1.4M17.4 17.4l1.4 1.4M18.8 5.2l-1.4 1.4M6.6 17.4l-1.4 1.4"/></svg></span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
document.addEventListener("DOMContentLoaded", function() {
|
||||||
|
const emojis = ["🐺","🐗","🐻","🐨","🐼","🐹","🐭","🐰","🦊","🐮","🐷","🐽","🐸","🐒","🦍","🐔","🐧","🐦","🐤","🐦⬛","🦅","🦉","🦇","🐴","🦄","🐝","🦎","🦖","🦕","🐙","🦑","🦐","🦞","🦀","🐡","🐠","🐟","🐬","🐳","🐋","🦈","🐊","🐅","🐆","🦓","🦍","🦧","🐘","🦛","🦏","🐪","🐫","🦒","🦘","🐃","🐂","🐄","🐎","🐖","🐏","🐑","🦙","🐐","🦌","🐕","🐩","🦮","🐕🦺","🐈","🐋","🐳","🐬","🐉","🐲"];
|
||||||
|
const placeholder = document.querySelector('.emoji-placeholder');
|
||||||
|
if (placeholder) {
|
||||||
|
placeholder.textContent = emojis[Math.floor(Math.random() * emojis.length)];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
<div id="tb-mobile-utils">
|
||||||
|
|
||||||
|
<select id="mobile-lang-select" class="uk-select uk-form-small" aria-label="言語">
|
||||||
|
|
||||||
|
<option value="zh-CN" >简体中文</option>
|
||||||
|
|
||||||
|
<option value="zh-TW" >繁體中文</option>
|
||||||
|
|
||||||
|
<option value="en" >English</option>
|
||||||
|
|
||||||
|
<option value="ja" selected>日本語</option>
|
||||||
|
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<button type="button" id="theme-toggle-mobile" class="uk-button uk-button-default uk-button-small"
|
||||||
|
title="ダーク/ライトモード切替" aria-label="ダーク/ライトモード切替">
|
||||||
|
<span class="tb-icon-light"><svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M20.5 14.3A8.6 8.6 0 0 1 9.7 3.5a8.6 8.6 0 1 0 10.8 10.8z"/></svg></span><span class="tb-icon-dark"><svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><circle cx="12" cy="12" r="4"/><path d="M12 2.5v2M12 19.5v2M2.5 12h2M19.5 12h2M5.2 5.2l1.4 1.4M17.4 17.4l1.4 1.4M18.8 5.2l-1.4 1.4M6.6 17.4l-1.4 1.4"/></svg></span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
(function() {
|
||||||
|
|
||||||
|
var THEME_COOKIE = 'theme';
|
||||||
|
function getTheme() {
|
||||||
|
var m = document.cookie.match(/(?:^|;\s*)theme=([^;]*)/);
|
||||||
|
return m ? m[1] : '';
|
||||||
|
}
|
||||||
|
function applyTheme(theme) {
|
||||||
|
if (theme === 'dark') {
|
||||||
|
document.documentElement.setAttribute('data-theme', 'dark');
|
||||||
|
} else {
|
||||||
|
document.documentElement.removeAttribute('data-theme');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function toggleTheme() {
|
||||||
|
var next = getTheme() === 'dark' ? 'light' : 'dark';
|
||||||
|
applyTheme(next);
|
||||||
|
var expires = new Date(Date.now() + 365 * 24 * 3600 * 1000).toUTCString();
|
||||||
|
document.cookie = THEME_COOKIE + '=' + next + '; path=/; max-age=' + (365 * 24 * 3600) + '; SameSite=Lax';
|
||||||
|
}
|
||||||
|
|
||||||
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
|
|
||||||
|
var buttons = document.querySelectorAll('#theme-toggle, #theme-toggle-mobile');
|
||||||
|
buttons.forEach(function(btn) {
|
||||||
|
btn.addEventListener('click', function(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
toggleTheme();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
var langSel = document.getElementById('mobile-lang-select');
|
||||||
|
if (langSel) {
|
||||||
|
langSel.addEventListener('change', function() {
|
||||||
|
if (!this.value) return;
|
||||||
|
var to = window.location.pathname + window.location.search;
|
||||||
|
window.location.href = '/i18n/' + encodeURIComponent(this.value) + '?to=' + encodeURIComponent(to);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
})();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
<div class="uk-container uk-container-xsmall">
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<div id="math-captcha-modal" uk-modal>
|
||||||
|
<div class="uk-modal-dialog uk-modal-body uk-text-center">
|
||||||
|
<h3 class="uk-modal-title">人機認証</h3>
|
||||||
|
<p class="uk-text-meta">以下の計算問題を解いて、ロボットでないことを証明してください</p>
|
||||||
|
<div class="captcha-equation-box">
|
||||||
|
<span id="captcha-modal-question" class="math-captcha-modal-question">読み込み中...</span>
|
||||||
|
<input type="number" id="captcha-modal-answer" placeholder="?" autocomplete="off" inputmode="numeric">
|
||||||
|
</div>
|
||||||
|
<div style="margin-top:6px;">
|
||||||
|
<button type="button" class="uk-button uk-button-text uk-text-small" id="captcha-modal-refresh">別の問題</button>
|
||||||
|
</div>
|
||||||
|
<div id="captcha-modal-error" class="uk-text-danger uk-text-small" style="display:none;min-height:20px;"></div>
|
||||||
|
<div class="uk-margin-small-top">
|
||||||
|
<button type="button" class="uk-button uk-button-primary" id="captcha-modal-submit">送信</button>
|
||||||
|
<button type="button" class="uk-button uk-button-default uk-modal-close">キャンセル</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
var CAPTCHA_I18N = {
|
||||||
|
loading: "読み込み中...",
|
||||||
|
loadFailed: "読み込み失敗",
|
||||||
|
loadRetry: "読み込み失敗、再試行してください",
|
||||||
|
inputAnswer: "答えを入力してください",
|
||||||
|
wrongAnswer: "答えが違います。もう一度計算してください",
|
||||||
|
verifyFailed: "認証失敗、再試行してください",
|
||||||
|
needPassword: "この質問箱にはパスワードが必要です",
|
||||||
|
needEmail: "通知を受け取るメールアドレスを入力してください"
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
(function() {
|
||||||
|
var captchaId = '';
|
||||||
|
var pendingForm = null;
|
||||||
|
var pendingNeedPassword = false;
|
||||||
|
var verifying = false;
|
||||||
|
|
||||||
|
function fetchCaptcha() {
|
||||||
|
var qEl = document.getElementById('captcha-modal-question');
|
||||||
|
var errEl = document.getElementById('captcha-modal-error');
|
||||||
|
var ansEl = document.getElementById('captcha-modal-answer');
|
||||||
|
qEl.textContent = CAPTCHA_I18N.loading;
|
||||||
|
fetch('/api/captcha/generate')
|
||||||
|
.then(function(r) { return r.json(); })
|
||||||
|
.then(function(data) {
|
||||||
|
if (data.code === 0 && data.data) {
|
||||||
|
captchaId = data.data.id;
|
||||||
|
qEl.textContent = data.data.question;
|
||||||
|
if (errEl) errEl.style.display = 'none';
|
||||||
|
if (ansEl) { ansEl.value = ''; ansEl.focus(); }
|
||||||
|
} else {
|
||||||
|
qEl.textContent = CAPTCHA_I18N.loadFailed;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(function() {
|
||||||
|
qEl.textContent = CAPTCHA_I18N.loadRetry;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function getCSRFToken() {
|
||||||
|
var input = document.querySelector('input[name="_csrf"]');
|
||||||
|
return input ? input.value : '';
|
||||||
|
}
|
||||||
|
|
||||||
|
function doSubmit(form) {
|
||||||
|
|
||||||
|
var ans = document.getElementById('captcha-modal-answer').value.trim();
|
||||||
|
var hidden = form.querySelector('[name="g-recaptcha-response"]');
|
||||||
|
if (hidden) hidden.value = captchaId + ':' + (ans || '0');
|
||||||
|
|
||||||
|
UIkit.modal('#math-captcha-modal').hide();
|
||||||
|
|
||||||
|
|
||||||
|
if (pendingNeedPassword) {
|
||||||
|
UIkit.modal.prompt(CAPTCHA_I18N.needPassword, '', 'password')
|
||||||
|
.then(function(password) {
|
||||||
|
if (password) {
|
||||||
|
var pwInput = document.getElementById('ask_password_input');
|
||||||
|
if (pwInput) pwInput.value = password;
|
||||||
|
form.submit();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
form.submit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
document.getElementById('captcha-modal-submit').addEventListener('click', function() {
|
||||||
|
if (verifying) return;
|
||||||
|
var ans = document.getElementById('captcha-modal-answer').value.trim();
|
||||||
|
if (!ans) {
|
||||||
|
var errEl = document.getElementById('captcha-modal-error');
|
||||||
|
errEl.textContent = CAPTCHA_I18N.inputAnswer;
|
||||||
|
errEl.style.display = 'block';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
verifying = true;
|
||||||
|
fetch('/api/captcha/verify', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'X-CSRF-Token': getCSRFToken()
|
||||||
|
},
|
||||||
|
body: JSON.stringify({ id: captchaId, answer: parseInt(ans, 10) })
|
||||||
|
})
|
||||||
|
.then(function(r) { return r.json(); })
|
||||||
|
.then(function(data) {
|
||||||
|
verifying = false;
|
||||||
|
if (data.correct) {
|
||||||
|
if (pendingForm) doSubmit(pendingForm);
|
||||||
|
} else {
|
||||||
|
var errEl = document.getElementById('captcha-modal-error');
|
||||||
|
errEl.textContent = CAPTCHA_I18N.wrongAnswer;
|
||||||
|
errEl.style.display = 'block';
|
||||||
|
fetchCaptcha();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(function() {
|
||||||
|
verifying = false;
|
||||||
|
var errEl = document.getElementById('captcha-modal-error');
|
||||||
|
errEl.textContent = CAPTCHA_I18N.verifyFailed;
|
||||||
|
errEl.style.display = 'block';
|
||||||
|
fetchCaptcha();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
document.getElementById('captcha-modal-answer').addEventListener('keydown', function(e) {
|
||||||
|
if (e.key === 'Enter') {
|
||||||
|
e.preventDefault();
|
||||||
|
document.getElementById('captcha-modal-submit').click();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
document.getElementById('captcha-modal-refresh').addEventListener('click', fetchCaptcha);
|
||||||
|
|
||||||
|
|
||||||
|
document.addEventListener('click', function(e) {
|
||||||
|
var btn = e.target.closest('.math-captcha-trigger');
|
||||||
|
if (!btn) return;
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
var form = btn.closest('form');
|
||||||
|
if (!form) return;
|
||||||
|
pendingForm = form;
|
||||||
|
|
||||||
|
|
||||||
|
pendingNeedPassword = !!(form.querySelector('#ask_password_input'));
|
||||||
|
|
||||||
|
|
||||||
|
var notifyCb = document.getElementById('notify-checkbox');
|
||||||
|
var emailInput = document.getElementById('email-input');
|
||||||
|
if (notifyCb && notifyCb.checked && emailInput && emailInput.value.trim() === '') {
|
||||||
|
UIkit.modal.alert(CAPTCHA_I18N.needEmail);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
fetchCaptcha();
|
||||||
|
UIkit.modal('#math-captcha-modal').show();
|
||||||
|
});
|
||||||
|
})();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<form method="post" id="form">
|
||||||
|
<fieldset class="uk-fieldset">
|
||||||
|
<input type="hidden" name="_csrf" value="rXiiG2aGBmVYYZ3ooWT-q2lji706MTc5MjM4NTMyNzEyMDg4MTAyNw">
|
||||||
|
<legend class="uk-legend">ログイン</legend>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<div class="uk-margin">
|
||||||
|
<label class="uk-form-label" for="email">メールアドレス</label>
|
||||||
|
<input name="email" id="email" class="uk-input" type="text" value="">
|
||||||
|
</div>
|
||||||
|
<div class="uk-margin">
|
||||||
|
<label class="uk-form-label" for="password">パスワード</label>
|
||||||
|
<input type="password" name="password" id="password" class="uk-input">
|
||||||
|
</div>
|
||||||
|
<div class="uk-margin">
|
||||||
|
|
||||||
|
<input type="hidden" name="g-recaptcha-response" id="g-recaptcha-response" value="">
|
||||||
|
<button type="button" class="uk-button uk-button-primary math-captcha-trigger">ログイン</button>
|
||||||
|
|
||||||
|
<a href="/forgot-password" class="uk-button uk-button-default">パスワードを忘れた
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</fieldset>
|
||||||
|
</form>
|
||||||
|
<p class=" uk-text-right uk-text-muted uk-text-small">
|
||||||
|
<br>
|
||||||
|
<a href="/rules">ルール</a> |
|
||||||
|
|
||||||
|
<a href="https://box.shiroko.one/_/tamakyi" target="_blank">管理者へ</a>
|
||||||
|
<br>
|
||||||
|
<a href="https://share.shiroko.one" target="_blank">ドライブ</a>
|
||||||
|
| <a href="https://blog.shiroko.one" target="_blank">お知らせ</a>
|
||||||
|
| <a href="https://chat.shiroko.one" target="_blank">チャット</a>
|
||||||
|
| <a href="https://status.shiroko.one" target="_blank">ステータス</a>
|
||||||
|
| <a href="https://shiroko.one" target="_blank">リンク</a>
|
||||||
|
<br>Powered by NekoBox | 狼ICP备 20230101
|
||||||
|
<br>質問箱は稼働中:<span id="box_runtime"></span>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
(function () {
|
||||||
|
var create = Math.round(Date.UTC(2023, 6, 1, 18, 15, 43) / 1000);
|
||||||
|
function tick() {
|
||||||
|
var el = document.getElementById("box_runtime");
|
||||||
|
if (!el) return;
|
||||||
|
var s = Math.round((Date.now() + 8 * 3600 * 1000) / 1000) - create;
|
||||||
|
var t = [0, 0, 0, 0, 0];
|
||||||
|
if (s >= 31536000) { t[0] = s / 31536000 | 0; s %= 31536000; }
|
||||||
|
if (s >= 86400) { t[1] = s / 86400 | 0; s %= 86400; }
|
||||||
|
if (s >= 3600) { t[2] = s / 3600 | 0; s %= 3600; }
|
||||||
|
if (s >= 60) { t[3] = s / 60 | 0; s %= 60; }
|
||||||
|
if (s > 0) { t[4] = s; }
|
||||||
|
el.innerHTML = t[0] + '年 ' + t[1] + '天 ' + t[2] + '时 ' + t[3] + '分 ' + t[4] + '秒 ';
|
||||||
|
}
|
||||||
|
tick();
|
||||||
|
setInterval(tick, 1000);
|
||||||
|
})();
|
||||||
|
</script>
|
||||||
|
<br>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
var SUBMIT_I18N = {
|
||||||
|
submitting: '送信中...',
|
||||||
|
uploading: 'アップロード中...'
|
||||||
|
};
|
||||||
|
|
||||||
|
function tbResetSubmitButtons() {
|
||||||
|
document.querySelectorAll('button[data-tb-submitting]').forEach(function(b) {
|
||||||
|
b.disabled = false;
|
||||||
|
b.removeAttribute('data-tb-submitting');
|
||||||
|
var orig = b.getAttribute('data-tb-restore');
|
||||||
|
if (orig !== null) {
|
||||||
|
b.innerHTML = orig;
|
||||||
|
b.removeAttribute('data-tb-restore');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
document.addEventListener('submit', function(e) {
|
||||||
|
var form = e.target;
|
||||||
|
if (!form || form.tagName !== 'FORM') return;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if (e.defaultPrevented || form.getAttribute('data-tb-skip-submit-feedback') === '1') {
|
||||||
|
form.removeAttribute('data-tb-skip-submit-feedback');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if (form.getAttribute('target') === '_blank') return;
|
||||||
|
|
||||||
|
|
||||||
|
var trigger = e.submitter || form.querySelector('button[type="submit"]');
|
||||||
|
|
||||||
|
|
||||||
|
var hasFile = false;
|
||||||
|
form.querySelectorAll('input[type="file"]').forEach(function(f) {
|
||||||
|
if (f.files && f.files.length > 0) hasFile = true;
|
||||||
|
});
|
||||||
|
var label = hasFile ? SUBMIT_I18N.uploading : SUBMIT_I18N.submitting;
|
||||||
|
|
||||||
|
if (trigger && trigger.tagName === 'BUTTON') {
|
||||||
|
trigger.setAttribute('data-tb-restore', trigger.innerHTML);
|
||||||
|
trigger.innerHTML = '<span uk-spinner="ratio: 0.6"></span> ' + label;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
form.querySelectorAll('button').forEach(function(b) {
|
||||||
|
b.disabled = true;
|
||||||
|
b.setAttribute('data-tb-submitting', '1');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
window.addEventListener('pageshow', tbResetSubmitButtons);
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
||||||
@@ -40,6 +40,7 @@ import (
|
|||||||
"github.com/tamakyi/TamaBox/internal/shared"
|
"github.com/tamakyi/TamaBox/internal/shared"
|
||||||
"github.com/tamakyi/TamaBox/internal/storage"
|
"github.com/tamakyi/TamaBox/internal/storage"
|
||||||
templatepkg "github.com/tamakyi/TamaBox/internal/template"
|
templatepkg "github.com/tamakyi/TamaBox/internal/template"
|
||||||
|
"github.com/tamakyi/TamaBox/internal/theme"
|
||||||
)
|
)
|
||||||
|
|
||||||
func Pager(ctx context.Context) {
|
func Pager(ctx context.Context) {
|
||||||
@@ -76,6 +77,10 @@ func Pager(ctx context.Context) {
|
|||||||
ctx.Data["LangCode"] = lang
|
ctx.Data["LangCode"] = lang
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 主题只作用于箱主相关页面(提问箱主页 / 单题页 / 密码页 / 分享卡路由),
|
||||||
|
// 与背景图、颜色同属箱主个性化配置;/user 后台保持中性外观。
|
||||||
|
// 空串 = 不加载主题 css(站点默认就是基础外观时省掉一次请求)。
|
||||||
|
ctx.Data["ThemeSlug"] = theme.Resolve(pageUser.Theme)
|
||||||
// 页面密码检查
|
// 页面密码检查
|
||||||
if pageUser.PagePassword != "" && !(ctx.IsLogged && ctx.User.ID == pageUser.ID) {
|
if pageUser.PagePassword != "" && !(ctx.IsLogged && ctx.User.ID == pageUser.ID) {
|
||||||
passKey := fmt.Sprintf("page_pass_%d", pageUser.ID)
|
passKey := fmt.Sprintf("page_pass_%d", pageUser.ID)
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"net/url"
|
"net/url"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
@@ -22,6 +23,7 @@ import (
|
|||||||
"github.com/tamakyi/TamaBox/internal/i18n"
|
"github.com/tamakyi/TamaBox/internal/i18n"
|
||||||
"github.com/tamakyi/TamaBox/internal/imagecheck"
|
"github.com/tamakyi/TamaBox/internal/imagecheck"
|
||||||
"github.com/tamakyi/TamaBox/internal/storage"
|
"github.com/tamakyi/TamaBox/internal/storage"
|
||||||
|
"github.com/tamakyi/TamaBox/internal/theme"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Profile 账号设置页。按面板分区:
|
// Profile 账号设置页。按面板分区:
|
||||||
@@ -39,6 +41,14 @@ func Profile(ctx context.Context) {
|
|||||||
ctx.Data["StrictnessLocked"] = true
|
ctx.Data["StrictnessLocked"] = true
|
||||||
}
|
}
|
||||||
ctx.Data["TagLimits"] = tagLimits()
|
ctx.Data["TagLimits"] = tagLimits()
|
||||||
|
// 主题:可选清单(顺序同 [theme] available)+ 当前选择。
|
||||||
|
// 当前值取原始存储值,非法/已下线主题归零为「跟随站点默认」,避免单选一个都不选中。
|
||||||
|
ctx.Data["Themes"] = theme.List()
|
||||||
|
if theme.IsAvailable(ctx.User.Theme) {
|
||||||
|
ctx.Data["CurrentTheme"] = strings.ToLower(strings.TrimSpace(ctx.User.Theme))
|
||||||
|
} else {
|
||||||
|
ctx.Data["CurrentTheme"] = ""
|
||||||
|
}
|
||||||
ctx.Data["ChatLimits"] = chatLimits()
|
ctx.Data["ChatLimits"] = chatLimits()
|
||||||
InjectFeatureViews(ctx)
|
InjectFeatureViews(ctx)
|
||||||
ctx.Success("user/profile")
|
ctx.Success("user/profile")
|
||||||
@@ -64,6 +74,34 @@ func chatLimits() map[string]int {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// UpdateTheme 保存箱主选择的主题。只写 users.theme 一列,
|
||||||
|
// 与背景图/颜色等个性化设置互不影响(各自独立的表单入口)。
|
||||||
|
func UpdateTheme(ctx context.Context, f form.UpdateProfileTheme) {
|
||||||
|
if ctx.HasError() {
|
||||||
|
ctx.Success("user/profile")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
slug := strings.ToLower(strings.TrimSpace(f.Theme))
|
||||||
|
// 白名单校验:既挡住拼写错误,也挡住把任意字符串拼进 <link href> 的路径穿越尝试。
|
||||||
|
// 用 flash + 重定向而不是原地渲染:本页数据由 Profile() 装配(可选主题清单等),
|
||||||
|
// 直接 Success 会渲染出缺数据的页面。
|
||||||
|
if slug != "" && !theme.IsAvailable(slug) {
|
||||||
|
ctx.SetErrorFlash(i18n.T(ctx.Lang(), "profile.theme.invalid"))
|
||||||
|
ctx.Redirect("/user/profile")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := db.Users.UpdateTheme(ctx.Request().Context(), ctx.User.ID, slug); err != nil {
|
||||||
|
logrus.WithContext(ctx.Request().Context()).WithError(err).Error("Failed to update theme")
|
||||||
|
ctx.SetInternalErrorFlash()
|
||||||
|
ctx.Redirect("/user/profile")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ctx.SetSuccessFlash(i18n.T(ctx.Lang(), "profile.theme.saved"))
|
||||||
|
ctx.Redirect("/user/profile")
|
||||||
|
}
|
||||||
|
|
||||||
func ProfileAPI(ctx context.Context) error {
|
func ProfileAPI(ctx context.Context) error {
|
||||||
return ctx.JSON(ctx.User)
|
return ctx.JSON(ctx.User)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,6 +23,10 @@
|
|||||||
--tb-shadow: 0 1px 2px rgba(16, 24, 40, 0.04), 0 12px 28px -18px rgba(16, 24, 40, 0.20);
|
--tb-shadow: 0 1px 2px rgba(16, 24, 40, 0.04), 0 12px 28px -18px rgba(16, 24, 40, 0.20);
|
||||||
--tb-shadow-hover: 0 1px 2px rgba(16, 24, 40, 0.05), 0 18px 40px -20px rgba(16, 24, 40, 0.28);
|
--tb-shadow-hover: 0 1px 2px rgba(16, 24, 40, 0.05), 0 18px 40px -20px rgba(16, 24, 40, 0.28);
|
||||||
--tb-font: system-ui, -apple-system, "Segoe UI", "PingFang SC", "Hiragino Sans GB", "Noto Sans CJK SC", "Microsoft YaHei", sans-serif;
|
--tb-font: system-ui, -apple-system, "Segoe UI", "PingFang SC", "Hiragino Sans GB", "Noto Sans CJK SC", "Microsoft YaHei", sans-serif;
|
||||||
|
/* 整页背景:主题可覆盖。图案层叠在背景图之上,两者都不用时保持纯色底。 */
|
||||||
|
--tb-page-image: none;
|
||||||
|
--tb-page-pattern: none;
|
||||||
|
--tb-page-pattern-size: auto;
|
||||||
}
|
}
|
||||||
html[data-theme="dark"] {
|
html[data-theme="dark"] {
|
||||||
--tb-bg: #1a1d23;
|
--tb-bg: #1a1d23;
|
||||||
@@ -260,6 +264,12 @@
|
|||||||
body {
|
body {
|
||||||
font-family: var(--tb-font);
|
font-family: var(--tb-font);
|
||||||
background-color: var(--tb-bg);
|
background-color: var(--tb-bg);
|
||||||
|
/* 主题的整页背景:图案(平铺)在上,图片(cover)在下,都不设置时等价于纯色 */
|
||||||
|
background-image: var(--tb-page-pattern, none), var(--tb-page-image, none);
|
||||||
|
background-size: var(--tb-page-pattern-size, auto), cover;
|
||||||
|
background-repeat: repeat, no-repeat;
|
||||||
|
background-position: left top, center center;
|
||||||
|
background-attachment: scroll, fixed;
|
||||||
color: var(--tb-text);
|
color: var(--tb-text);
|
||||||
-webkit-font-smoothing: antialiased;
|
-webkit-font-smoothing: antialiased;
|
||||||
-moz-osx-font-smoothing: grayscale;
|
-moz-osx-font-smoothing: grayscale;
|
||||||
@@ -327,6 +337,89 @@
|
|||||||
color: var(--tb-text-muted);
|
color: var(--tb-text-muted);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 主题选择器(设置页):色块 + 名称。纯展示,不参与主题令牌,所以放在基础层。 */
|
||||||
|
.tb-theme-hint {
|
||||||
|
margin: 0 0 6px;
|
||||||
|
font-size: 0.8rem;
|
||||||
|
color: var(--tb-text-muted);
|
||||||
|
}
|
||||||
|
.tb-theme-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));
|
||||||
|
gap: 8px;
|
||||||
|
margin: 8px 0 2px;
|
||||||
|
}
|
||||||
|
.tb-theme-opt {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
padding: 7px 9px;
|
||||||
|
border: 1px solid var(--tb-border);
|
||||||
|
border-radius: var(--tb-radius-sm);
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
.tb-theme-opt:hover {
|
||||||
|
background-color: var(--tb-surface-hover);
|
||||||
|
}
|
||||||
|
.tb-theme-opt input {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
.tb-theme-swatch {
|
||||||
|
flex: 0 0 auto;
|
||||||
|
width: 26px;
|
||||||
|
height: 26px;
|
||||||
|
border-radius: var(--tb-radius-xs);
|
||||||
|
border: 1px solid var(--tb-border);
|
||||||
|
background-color: var(--tb-surface-2);
|
||||||
|
}
|
||||||
|
/* 选中态用描边而不是 :has(),兼容老 WebView */
|
||||||
|
.tb-theme-opt input:checked + .tb-theme-swatch {
|
||||||
|
outline: 2px solid var(--tb-primary);
|
||||||
|
outline-offset: 1px;
|
||||||
|
}
|
||||||
|
.tb-theme-name {
|
||||||
|
font-size: 0.84rem;
|
||||||
|
line-height: 1.3;
|
||||||
|
}
|
||||||
|
.tb-theme-opt input:checked ~ .tb-theme-name {
|
||||||
|
color: var(--tb-primary);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* UIkit 组件跟随主题色:UIkit 3.3.3 的主色是编译期常量(#1e87f0),
|
||||||
|
CSS 变量注入不进去,只能按组件覆盖。基础主题的 --tb-primary 恰好就是 #1e87f0,
|
||||||
|
所以这段对默认外观零改动,只是让箱主主题能贯穿到按钮/链接/勾选。 */
|
||||||
|
a, .uk-link {
|
||||||
|
color: var(--tb-primary);
|
||||||
|
}
|
||||||
|
a:hover, .uk-link:hover {
|
||||||
|
color: var(--tb-primary);
|
||||||
|
}
|
||||||
|
.uk-button-primary {
|
||||||
|
background-color: var(--tb-primary);
|
||||||
|
}
|
||||||
|
.uk-button-primary:hover,
|
||||||
|
.uk-button-primary:focus {
|
||||||
|
background-color: var(--tb-primary);
|
||||||
|
filter: brightness(1.07);
|
||||||
|
}
|
||||||
|
.uk-checkbox:checked,
|
||||||
|
.uk-checkbox:indeterminate,
|
||||||
|
.uk-radio:checked {
|
||||||
|
background-color: var(--tb-primary);
|
||||||
|
border-color: transparent;
|
||||||
|
}
|
||||||
|
.uk-input:focus,
|
||||||
|
.uk-select:focus,
|
||||||
|
.uk-textarea:focus {
|
||||||
|
border-color: var(--tb-primary);
|
||||||
|
}
|
||||||
|
.uk-tab > .uk-active > a {
|
||||||
|
border-color: var(--tb-primary);
|
||||||
|
}
|
||||||
|
.uk-text-primary {
|
||||||
|
color: var(--tb-primary) !important;
|
||||||
|
}
|
||||||
|
|
||||||
/* 轻量胶囊:用于投票类型、热门标签等「只是分类信息」的位置。
|
/* 轻量胶囊:用于投票类型、热门标签等「只是分类信息」的位置。
|
||||||
实心 uk-label 一屏多个会变成一排色块,这里统一降级为浅底 + 次要色文字。 */
|
实心 uk-label 一屏多个会变成一排色块,这里统一降级为浅底 + 次要色文字。 */
|
||||||
.tb-chip {
|
.tb-chip {
|
||||||
|
|||||||
@@ -0,0 +1,110 @@
|
|||||||
|
/* ============================================================================
|
||||||
|
主题底稿(scaffold)—— 复制本文件改名为 <slug>.css 即可新增一套主题。
|
||||||
|
文件名即 slug:只允许小写字母、数字、连字符(如 sakura / ocean-mist)。
|
||||||
|
新增后需在 conf/app.ini 登记:
|
||||||
|
|
||||||
|
[theme]
|
||||||
|
default = default
|
||||||
|
available = default,sakura,ocean-mist
|
||||||
|
|
||||||
|
⚠️ 硬规则(违反会导致深色模式错乱或整页错位):
|
||||||
|
1. 两个块都必须写:浅色「html[data-theme-style="SLUG"]」
|
||||||
|
与深色「html[data-theme="dark"][data-theme-style="SLUG"]」。
|
||||||
|
只写浅色块会连深色模式一起覆盖(同特异性 + 本文件在 base.css 之后加载)。
|
||||||
|
2. 只改令牌(下方变量)与「组件微调」段。不要改布局:宽高、margin、padding、
|
||||||
|
display / flex / grid、position 一律不动 —— 主题不是换皮模板。
|
||||||
|
3. 本文件不参与构建,仅作参考;真正生效的是同目录下的 <slug>.css。
|
||||||
|
|
||||||
|
── 可用的 19 个令牌 ──────────────────────────────────────────────
|
||||||
|
底色层 --tb-bg 页面底色(html/body)
|
||||||
|
--tb-surface 卡片、输入框等前景面板
|
||||||
|
--tb-surface-2 次级面(标签底、进度条轨道、代码块)
|
||||||
|
--tb-surface-hover 悬停底(列表行、下拉项)
|
||||||
|
线条 --tb-border 边框、分隔线
|
||||||
|
文字 --tb-text 正文
|
||||||
|
--tb-text-secondary 次要文字(说明、meta)
|
||||||
|
--tb-text-muted 弱化文字(占位、时间戳)
|
||||||
|
强调 --tb-primary 主色:链接、主按钮、进度条
|
||||||
|
--tb-primary-weak 主色 10% 左右的浅底(选中态、标签)
|
||||||
|
形状 --tb-radius 卡片 12px / --tb-radius-sm 8px / --tb-radius-xs 6px
|
||||||
|
阴影 --tb-shadow 卡片默认 / --tb-shadow-hover 悬停
|
||||||
|
字体 --tb-font 字体栈(一般不改)
|
||||||
|
页面背景 --tb-page-image 整页背景图(cover,fixed)
|
||||||
|
--tb-page-pattern 整页图案(平铺,可叠加在背景图之上)
|
||||||
|
--tb-page-pattern-size 图案平铺尺寸(默认 auto)
|
||||||
|
|
||||||
|
── 素材规格(放 R2,不需要重新编译) ─────────────────────────────
|
||||||
|
页面背景图 2400×1600(3:2)或 2560×1440,WebP q80,≤300KB;明暗各一张:
|
||||||
|
https://r2.337845818.best/tamabox/themes/<slug>/bg-light.webp
|
||||||
|
https://r2.337845818.best/tamabox/themes/<slug>/bg-dark.webp
|
||||||
|
注意:背景图上还要叠卡片和文字,主题要保证「--tb-surface 不透明」
|
||||||
|
或足够对比;照片类背景建议配 10%~20% 的同色半透明遮罩。
|
||||||
|
平铺图案 200×200 或 400×400 可无缝平铺,PNG/WebP,≤40KB;
|
||||||
|
建议透明度 ≤15%,否则会和正文抢注意力。
|
||||||
|
设置页色块 由本文件浅色块的 --tb-bg 与 --tb-primary 自动生成,无需额外素材。
|
||||||
|
============================================================================ */
|
||||||
|
|
||||||
|
/* 1) 浅色(必须)—— 选择器里的 SLUG 换成文件名 */
|
||||||
|
html[data-theme-style="SLUG"] {
|
||||||
|
--tb-bg: #f7f8fa;
|
||||||
|
--tb-surface: #ffffff;
|
||||||
|
--tb-surface-2: #f4f6f8;
|
||||||
|
--tb-surface-hover: #f3f7ff;
|
||||||
|
--tb-border: #e8eaee;
|
||||||
|
|
||||||
|
--tb-text: #1f2329;
|
||||||
|
--tb-text-secondary: #5c6370;
|
||||||
|
--tb-text-muted: #8a919c;
|
||||||
|
|
||||||
|
--tb-primary: #1e87f0;
|
||||||
|
--tb-primary-weak: rgba(30, 135, 240, 0.10);
|
||||||
|
|
||||||
|
--tb-radius: 12px;
|
||||||
|
--tb-radius-sm: 8px;
|
||||||
|
--tb-radius-xs: 6px;
|
||||||
|
|
||||||
|
--tb-shadow: 0 1px 2px rgba(16, 24, 40, 0.04), 0 12px 28px -18px rgba(16, 24, 40, 0.20);
|
||||||
|
--tb-shadow-hover: 0 1px 2px rgba(16, 24, 40, 0.05), 0 18px 40px -20px rgba(16, 24, 40, 0.28);
|
||||||
|
|
||||||
|
--tb-font: system-ui, -apple-system, "Segoe UI", "PingFang SC", "Hiragino Sans GB", "Noto Sans CJK SC", "Microsoft YaHei", sans-serif;
|
||||||
|
|
||||||
|
/* 整页背景:两者可同时用,图案叠在图片之上;不需要就保持 none */
|
||||||
|
--tb-page-image: none;
|
||||||
|
--tb-page-pattern: none;
|
||||||
|
--tb-page-pattern-size: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 2) 深色(必须)—— 深浅两套必须成对,缺一段会让深色用户看到「浅色的深色主题」 */
|
||||||
|
html[data-theme="dark"][data-theme-style="SLUG"] {
|
||||||
|
--tb-bg: #1a1d23;
|
||||||
|
--tb-surface: #242830;
|
||||||
|
--tb-surface-2: #2d323c;
|
||||||
|
--tb-surface-hover: rgba(92, 141, 255, 0.12);
|
||||||
|
--tb-border: #3a404c;
|
||||||
|
|
||||||
|
--tb-text: #d8dce4;
|
||||||
|
--tb-text-secondary: #a8b0bd;
|
||||||
|
--tb-text-muted: #8b93a1;
|
||||||
|
|
||||||
|
--tb-primary: #5c8dff;
|
||||||
|
--tb-primary-weak: rgba(92, 141, 255, 0.14);
|
||||||
|
|
||||||
|
--tb-shadow: 0 1px 2px rgba(0, 0, 0, 0.30), 0 12px 28px -18px rgba(0, 0, 0, 0.55);
|
||||||
|
--tb-shadow-hover: 0 1px 2px rgba(0, 0, 0, 0.35), 0 18px 40px -20px rgba(0, 0, 0, 0.65);
|
||||||
|
|
||||||
|
--tb-page-image: none;
|
||||||
|
--tb-page-pattern: none;
|
||||||
|
--tb-page-pattern-size: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 3) 组件微调(可选,默认整段注释掉)
|
||||||
|
只允许「外观」层面的补充:边框、阴影、封面遮罩浓度等。
|
||||||
|
禁止改尺寸/间距/定位 —— 那属于布局,主题不管。 */
|
||||||
|
/*
|
||||||
|
html[data-theme-style="SLUG"] .uk-card-default {
|
||||||
|
border-color: transparent;
|
||||||
|
}
|
||||||
|
html[data-theme-style="SLUG"] .tb-pcard {
|
||||||
|
box-shadow: var(--tb-shadow);
|
||||||
|
}
|
||||||
|
*/
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
/* 基础外观(default):与 base.css 完全一致,不覆盖任何令牌。
|
||||||
|
它的存在只为让 [theme] 里可以显式写 default(= 不使用主题)。
|
||||||
|
实际渲染时不会加载本文件 —— internal/theme.Resolve 对 default 返回空串,
|
||||||
|
省掉一次静态请求;下方令牌仅用于设置页色块预览。 */
|
||||||
|
html[data-theme-style="default"] {
|
||||||
|
--tb-bg: #f7f8fa;
|
||||||
|
--tb-primary: #1e87f0;
|
||||||
|
}
|
||||||
|
|
||||||
|
html[data-theme="dark"][data-theme-style="default"] {
|
||||||
|
--tb-bg: #1a1d23;
|
||||||
|
--tb-primary: #5c8dff;
|
||||||
|
}
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
/* 樱花(sakura):粉调 + 细网点图案,纯 CSS 实现,不依赖图片素材。
|
||||||
|
复制 _scaffold.css 写的示例:只覆盖令牌,未改动任何布局。 */
|
||||||
|
html[data-theme-style="sakura"] {
|
||||||
|
--tb-bg: #fff6f8;
|
||||||
|
--tb-surface: #ffffff;
|
||||||
|
--tb-surface-2: #fdeef2;
|
||||||
|
--tb-surface-hover: #fdf1f5;
|
||||||
|
--tb-border: #f2dde4;
|
||||||
|
|
||||||
|
--tb-text: #3a2b30;
|
||||||
|
--tb-text-secondary: #6b545c;
|
||||||
|
--tb-text-muted: #a08c94;
|
||||||
|
|
||||||
|
--tb-primary: #e5678f;
|
||||||
|
--tb-primary-weak: rgba(229, 103, 143, 0.12);
|
||||||
|
|
||||||
|
--tb-shadow: 0 1px 2px rgba(120, 60, 80, 0.05), 0 12px 28px -18px rgba(120, 60, 80, 0.22);
|
||||||
|
--tb-shadow-hover: 0 1px 2px rgba(120, 60, 80, 0.07), 0 18px 40px -20px rgba(120, 60, 80, 0.30);
|
||||||
|
|
||||||
|
--tb-page-image: none;
|
||||||
|
--tb-page-pattern: radial-gradient(circle at 1px 1px, rgba(229, 103, 143, 0.14) 1px, transparent 0);
|
||||||
|
--tb-page-pattern-size: 16px 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
html[data-theme="dark"][data-theme-style="sakura"] {
|
||||||
|
--tb-bg: #241a1f;
|
||||||
|
--tb-surface: #2e2129;
|
||||||
|
--tb-surface-2: #3a2a33;
|
||||||
|
--tb-surface-hover: rgba(255, 138, 176, 0.10);
|
||||||
|
--tb-border: #49333d;
|
||||||
|
|
||||||
|
--tb-text: #f2e4e9;
|
||||||
|
--tb-text-secondary: #c6aab4;
|
||||||
|
--tb-text-muted: #9d818b;
|
||||||
|
|
||||||
|
--tb-primary: #ff8ab0;
|
||||||
|
--tb-primary-weak: rgba(255, 138, 176, 0.16);
|
||||||
|
|
||||||
|
--tb-shadow: 0 1px 2px rgba(0, 0, 0, 0.34), 0 12px 28px -18px rgba(0, 0, 0, 0.58);
|
||||||
|
--tb-shadow-hover: 0 1px 2px rgba(0, 0, 0, 0.40), 0 18px 40px -20px rgba(0, 0, 0, 0.68);
|
||||||
|
|
||||||
|
--tb-page-image: none;
|
||||||
|
--tb-page-pattern: radial-gradient(circle at 1px 1px, rgba(255, 138, 176, 0.10) 1px, transparent 0);
|
||||||
|
--tb-page-pattern-size: 16px 16px;
|
||||||
|
}
|
||||||
@@ -8,5 +8,5 @@ import (
|
|||||||
"embed"
|
"embed"
|
||||||
)
|
)
|
||||||
|
|
||||||
//go:embed favicon.ico sitemap.xml llms.txt llms-full.txt robots.txt tamabox.changelogs.json index-now/66e5e0911b0941f2ba7dbfbbd961e9be.txt css/base.css
|
//go:embed favicon.ico sitemap.xml llms.txt llms-full.txt robots.txt tamabox.changelogs.json index-now/66e5e0911b0941f2ba7dbfbbd961e9be.txt css/base.css css/themes
|
||||||
var FS embed.FS
|
var FS embed.FS
|
||||||
|
|||||||
@@ -1,9 +1,18 @@
|
|||||||
{
|
{
|
||||||
"page": 1,
|
"page": 1,
|
||||||
"perPage": 3,
|
"perPage": 3,
|
||||||
"totalItems": 4,
|
"totalItems": 5,
|
||||||
"totalPages": 2,
|
"totalPages": 2,
|
||||||
"items": [
|
"items": [
|
||||||
|
{
|
||||||
|
"collectionId": "tamabox",
|
||||||
|
"collectionName": "tamabox-changelogs",
|
||||||
|
"content": "新增:箱主主题功能。设置页可为主题箱主页与单题页选择配色,只影响配色、图案与整页背景,不影响布局;未选择时跟随站点默认主题。<br>\n新增:主题底稿 static/css/themes/_scaffold.css,复制改名为 <slug>.css 并在 [theme] available 登记即可新增一套主题,无需改模板;示例主题「樱花」。",
|
||||||
|
"created": "2026-10-19 15:10:00.000Z",
|
||||||
|
"id": "none",
|
||||||
|
"published_at": "2026-10-19 15:10:00.000Z",
|
||||||
|
"updated": "2026-10-19 15:10:00.000Z"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"collectionId": "tamabox",
|
"collectionId": "tamabox",
|
||||||
"collectionName": "tamabox-changelogs",
|
"collectionName": "tamabox-changelogs",
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="{{.LangCode}}">
|
<html lang="{{.LangCode}}"{{ if .ThemeSlug }} data-theme-style="{{ .ThemeSlug }}"{{ end }}>
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
@@ -20,8 +20,10 @@
|
|||||||
<link rel="preconnect" href="https://cdnjs.snrat.com" crossorigin>
|
<link rel="preconnect" href="https://cdnjs.snrat.com" crossorigin>
|
||||||
<!-- UIkit 3.3.3 切到公共 CDN(cdnjs.snrat.com,国内实测全量下载 ~0.25s,原 R2 自建 ~1.4-2.0s) -->
|
<!-- UIkit 3.3.3 切到公共 CDN(cdnjs.snrat.com,国内实测全量下载 ~0.25s,原 R2 自建 ~1.4-2.0s) -->
|
||||||
<link rel="stylesheet" href="https://cdnjs.snrat.com/ajax/libs/uikit/3.3.3/css/uikit.min.css"/>
|
<link rel="stylesheet" href="https://cdnjs.snrat.com/ajax/libs/uikit/3.3.3/css/uikit.min.css"/>
|
||||||
<!-- 全站基础样式(由原内联块抽出,可被浏览器缓存):改 static/css/base.css 后把 v 版本号 +1 -->
|
<!-- 全站基础样式(由原内联块抽出,可被浏览器缓存):改样式后把 conf.StaticVersion +1 -->
|
||||||
<link rel="stylesheet" href="/static/css/base.css?v=20261019d"/>
|
<link rel="stylesheet" href="/static/css/base.css?v={{ .StaticVersion }}"/>
|
||||||
|
{{ if .ThemeSlug }}<!-- 箱主主题:只覆盖配色/图案/页面背景,不涉及布局;仅提问箱相关页面加载 -->
|
||||||
|
<link rel="stylesheet" href="/static/css/themes/{{ .ThemeSlug }}.css?v={{ .StaticVersion }}"/>{{ end }}
|
||||||
<!-- Waline 评论区样式:非阻塞加载,不阻塞首屏渲染 -->
|
<!-- Waline 评论区样式:非阻塞加载,不阻塞首屏渲染 -->
|
||||||
<link rel="stylesheet" href="https://r2.337845818.best/tamabox/cdn/waline/client/v2/waline-no-commits.css" media="print" onload="this.media='all'"/>
|
<link rel="stylesheet" href="https://r2.337845818.best/tamabox/cdn/waline/client/v2/waline-no-commits.css" media="print" onload="this.media='all'"/>
|
||||||
<script defer src="https://cdnjs.snrat.com/ajax/libs/uikit/3.3.3/js/uikit.min.js"></script>
|
<script defer src="https://cdnjs.snrat.com/ajax/libs/uikit/3.3.3/js/uikit.min.js"></script>
|
||||||
|
|||||||
@@ -788,6 +788,34 @@
|
|||||||
<span class="tb-account-note">{{t .LangCode "admin.deactivateHint" | safe}}</span>
|
<span class="tb-account-note">{{t .LangCode "admin.deactivateHint" | safe}}</span>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
<!-- 主题外观:只改配色 / 图案 / 整页背景,不涉及布局;仅提问箱相关页面生效 -->
|
||||||
|
{{ if .Themes }}
|
||||||
|
<section class="tb-pcard">
|
||||||
|
<h3 class="tb-pcard-title">{{t .LangCode "profile.theme.title"}}</h3>
|
||||||
|
<form method="post" action="/user/profile/theme">
|
||||||
|
{{ .CSRFTokenHTML }}
|
||||||
|
<p class="tb-theme-hint">{{t .LangCode "profile.theme.hint"}}</p>
|
||||||
|
<div class="tb-theme-grid">
|
||||||
|
<label class="tb-theme-opt">
|
||||||
|
<input class="uk-radio" type="radio" name="theme" value=""{{ if eq .CurrentTheme "" }} checked{{ end }}>
|
||||||
|
<span class="tb-theme-swatch" style="background: linear-gradient(135deg, var(--tb-surface-2) 0 55%, var(--tb-border) 55% 100%)"></span>
|
||||||
|
<span class="tb-theme-name">{{t .LangCode "profile.theme.followDefault"}}</span>
|
||||||
|
</label>
|
||||||
|
{{ range .Themes }}
|
||||||
|
<label class="tb-theme-opt">
|
||||||
|
<input class="uk-radio" type="radio" name="theme" value="{{ .Slug }}"{{ if eq $.CurrentTheme .Slug }} checked{{ end }}>
|
||||||
|
<span class="tb-theme-swatch"{{ if .Swatch }} style="background: {{ .Swatch }}"{{ end }}></span>
|
||||||
|
<span class="tb-theme-name">{{ t $.LangCode (printf "theme.name.%s" .Slug) }}</span>
|
||||||
|
</label>
|
||||||
|
{{ end }}
|
||||||
|
</div>
|
||||||
|
<div class="tb-card-save">
|
||||||
|
<button type="submit" class="uk-button uk-button-primary">{{t .LangCode "profile.theme.save"}}</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</section>
|
||||||
|
{{ end }}
|
||||||
|
|
||||||
</div><!-- /用户设置面板 -->
|
</div><!-- /用户设置面板 -->
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package templates
|
|||||||
import (
|
import (
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
@@ -72,6 +73,29 @@ func TestGenPreview(t *testing.T) {
|
|||||||
writePreview(t, outDir, "preview-box-"+theme+".html", box, theme, "../static")
|
writePreview(t, outDir, "preview-box-"+theme+".html", box, theme, "../static")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 主题预览:与箱主页同一份数据,只是打开 sakura 主题(验证令牌覆盖与深色块)
|
||||||
|
themeBox := publicBaseData()
|
||||||
|
themeBox["VConsole"] = false
|
||||||
|
themeBox["ThemeSlug"] = "sakura"
|
||||||
|
themeBox["PageUser"].(map[string]interface{})["Background"] = bgURI
|
||||||
|
themeBox["PageUser"].(map[string]interface{})["Usernamecolor"] = "#3a2b30"
|
||||||
|
themeBox["PageUser"].(map[string]interface{})["Introcolor"] = "#6b545c"
|
||||||
|
themeCSS, err := os.ReadFile(filepath.Join("..", "static", "css", "themes", "sakura.css"))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("read theme css: %v", err)
|
||||||
|
}
|
||||||
|
for _, theme := range []string{"light", "dark"} {
|
||||||
|
page, err := renderToString(t, "question/list", themeBox)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("render themed list: %v", err)
|
||||||
|
}
|
||||||
|
// 预览页走 file://,把主题 css 内联进去(真实页面是一次带缓存的静态请求)。
|
||||||
|
// 用正则匹配:预览数据里没有 StaticVersion,v 参数为空串,不能按固定串替换。
|
||||||
|
link := regexp.MustCompile(`<link rel="stylesheet" href="/static/css/themes/sakura\.css\?v=[^"]*"/>`)
|
||||||
|
page = link.ReplaceAllString(page, "<style>"+string(themeCSS)+"</style>")
|
||||||
|
writePreview(t, outDir, "preview-theme-sakura-"+theme+".html", page, theme, "../static")
|
||||||
|
}
|
||||||
|
|
||||||
// 探索页:核对令牌替换后的卡片/列表配色
|
// 探索页:核对令牌替换后的卡片/列表配色
|
||||||
explore := voteBaseData()
|
explore := voteBaseData()
|
||||||
explore["LangCode"] = "zh-CN"
|
explore["LangCode"] = "zh-CN"
|
||||||
@@ -102,6 +126,12 @@ func TestGenPreview(t *testing.T) {
|
|||||||
|
|
||||||
// 设置页「内容防护」面板:核对是否与其它面板同样是白底卡片
|
// 设置页「内容防护」面板:核对是否与其它面板同样是白底卡片
|
||||||
profile := profileBaseData()
|
profile := profileBaseData()
|
||||||
|
// 主题选择器(account 面板):用固定假数据,避免测试依赖 conf 的 [theme] 段
|
||||||
|
profile["Themes"] = []map[string]interface{}{
|
||||||
|
{"Slug": "default", "Swatch": ""},
|
||||||
|
{"Slug": "sakura", "Swatch": "linear-gradient(135deg, #fff6f8 0 55%, #e5678f 55% 100%)"},
|
||||||
|
}
|
||||||
|
profile["CurrentTheme"] = "sakura"
|
||||||
profile["ActiveProfileTab"] = "security"
|
profile["ActiveProfileTab"] = "security"
|
||||||
profile["FeatureQuestion"] = nil
|
profile["FeatureQuestion"] = nil
|
||||||
profile["FeatureChat"] = nil
|
profile["FeatureChat"] = nil
|
||||||
@@ -113,6 +143,22 @@ func TestGenPreview(t *testing.T) {
|
|||||||
}
|
}
|
||||||
writePreview(t, outDir, "preview-profile-"+theme+".html", page, theme, "../static")
|
writePreview(t, outDir, "preview-profile-"+theme+".html", page, theme, "../static")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 设置页「账号」面板:主题选择器的实际排版(卡片在面板末尾)
|
||||||
|
profileAccount := profileBaseData()
|
||||||
|
profileAccount["Themes"] = profile["Themes"]
|
||||||
|
profileAccount["CurrentTheme"] = "sakura"
|
||||||
|
profileAccount["ActiveProfileTab"] = "account"
|
||||||
|
profileAccount["FeatureQuestion"] = nil
|
||||||
|
profileAccount["FeatureChat"] = nil
|
||||||
|
profileAccount["FeatureVote"] = nil
|
||||||
|
for _, theme := range []string{"light"} {
|
||||||
|
page, err := renderToString(t, "user/profile", profileAccount)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("render account profile: %v", err)
|
||||||
|
}
|
||||||
|
writePreview(t, outDir, "preview-profile-account-"+theme+".html", page, theme, "../static")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// writePreview 把 CDN 换成可直连的镜像、钉死主题,仅用于本地预览。
|
// writePreview 把 CDN 换成可直连的镜像、钉死主题,仅用于本地预览。
|
||||||
@@ -120,7 +166,16 @@ func writePreview(t *testing.T, dir, name, html, theme, staticPrefix string) {
|
|||||||
t.Helper()
|
t.Helper()
|
||||||
html = strings.ReplaceAll(html, "https://cdnjs.snrat.com/", "https://cdnjs.cloudflare.com/")
|
html = strings.ReplaceAll(html, "https://cdnjs.snrat.com/", "https://cdnjs.cloudflare.com/")
|
||||||
if theme == "dark" {
|
if theme == "dark" {
|
||||||
html = strings.Replace(html, `<html lang="zh-CN">`, `<html lang="zh-CN" data-theme="dark">`, 1)
|
// <html> 上可能还有 data-theme-style,只在这个开标签内判断/插入;
|
||||||
|
// 不能全文搜索 —— 内联的主题 css 里有 html[data-theme="dark"] 选择器
|
||||||
|
if i := strings.Index(html, "<html"); i >= 0 {
|
||||||
|
if j := strings.Index(html[i:], ">"); j > 0 {
|
||||||
|
tag := html[i : i+j]
|
||||||
|
if !strings.Contains(tag, "data-theme=") {
|
||||||
|
html = html[:i+j] + ` data-theme="dark"` + html[i+j:]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
html = strings.ReplaceAll(html, `href="/favicon.ico"`, `href="`+staticPrefix+`/favicon.ico"`)
|
html = strings.ReplaceAll(html, `href="/favicon.ico"`, `href="`+staticPrefix+`/favicon.ico"`)
|
||||||
html = strings.Replace(html, `<title>`, `<title>预览 `+time.Now().Format("15:04")+` · `, 1)
|
html = strings.Replace(html, `<title>`, `<title>预览 `+time.Now().Format("15:04")+` · `, 1)
|
||||||
|
|||||||