项目展示

一个 Typecho 主题和一个可选的 REST 接口插件;这一页由它自己画

主题版本 1.29.6 就是正在渲染这一页的那份
接口插件 已启用 和主题同一个包、同一次交换
接口端点 12条 鉴权走请求头 X-Noline-Key
本站在跑 173篇 315 条评论 · 开站第 2416 天

环境:Typecho 1.2.x · PHP 7.4 及以上 · 主题当前版本 1.29.6。 前端没有 CDN:图标是内联 SVG,highlight.js 走本地文件且只在有代码块的那几页加载。

主题画了什么

令牌驱动配色

颜色全部集中在两个 :root 块:一支墨色按浓度派生出文字四档、表面三档、描边三档,浅色 103 条 / 深色 66 条一一对齐。强调色在后台填一个十六进制就够。

深色模式无闪烁

主题初始化脚本前置在 head 顶部,data-theme 先落地再画第一帧;两档之间切换时卡片、图表、代码块、玻璃浮层一起翻,不用逐个抄色值。

首页信息流

masthead 头图 + 站名 + 座右铭,上面自动压一层渐变罩保证文字读得清。封面卡带缩略图、阅读时长和最近评论预览;分类收成一条吸顶药丸带,溢出的收进「更多」面板,支持方向键漫游。

动态卡

命中「日记」分类的文章不当文章处理:不显示标题、正文原地铺开、超过六行折叠出「全文」。首页和分类页同一套 partial。

文章页

hero 头图 + 正文排版(二级标题下划线、引用块、表格、脚注、嵌套列表)+ 代码块红绿灯与复制按钮+ 图片灯箱 + 目录 + 上下篇 + 相关文章 + 文末版权卡。

右栏组件

双列 card-widget:月历、那年今日、分类、标签、目录、近期评论、站点信息,尾部 sticky 跟着滚动走。分类卡是可选的,默认关——分类已经在信息流那条药丸带里出现过一次。

软跳转

站内跳转主路径是浏览器原生的跨文档视图过渡:新页没就绪之前旧页原样挂着,顶栏整块跨页连续。浏览器不认就自动退回淡出 + 顶部进度条,两边都不白屏硬切。

失效图自愈

图挂了不留浏览器碎图标:换成主题自带的占位图说明「图片资料已失效」,圆形头像换中性剪影,顶栏 logo 换回首字母块;没被链接包住的失效图点一下会拿原地址重试。

密度与空态

根字号是一个全局旋钮(rem 化),移动端不降字号、只收留白。各处空态有自绘图标和文案而不是一行灰字,按钮和药丸都有「按下去瘪一点」的反馈。

SEO 与性能

canonical + Open Graph + Twitter card + JSON-LD;CSS 走压缩版并按版本号 busting,重查询按天缓存、发新文章主动失效;滚动接近底部时提前取好下一页;站点头像转存成站内文件。

颜色只有两支

这一排是实时取的 后台还没填强调色
--accent 主色:链接、圆点、当前项 --accent-hover 它的 hover --accent-bg 掺一成透明度:胶囊底、选中底 --accent-container 掺一成四:需要一块淡底的地方 --heading-marker 唯一不参与派生的:正文标题那颗暖金标记

后台「设置外观 → 强调色」填一支十六进制,整站连同上面这五格立刻跟着换;深色模式按亮度自动推亮一档,剩下的层次全是这两支掺透明度。 切到深色模式再看一次,这五格会跟着翻,因为每一格挂的都是变量而不是色值。

插件管了什么

对外接口

一把 X-Noline-Key 管住除 ping 以外的全部端点;写入和「写主题配置」各有一道独立开关,默认只读。体重和记账的记录文件在 usr/uploads/noline_api/,各自一把锁,互不阻塞。页面只画不能写,写进去只有接口一条路。

Cloudreve 图床

在插件设置里填网盘地址和那个账号的邮箱、密码,写文章和写页面的附件面板顶部就多一块图床区:选文件、粘贴截图、拖图片进去都能传,传完按当前编辑器形态(Markdown 或富文本)把永久直链插进正文。Typecho 自带的附件上传一点不动,两者并存;邮箱、密码和令牌都只待在服务端。

自动覆盖更新

后台路过任意一个页面时查一次 Release(结论缓存 6 小时),发现新版本就当场下载、验收,把旧主题和旧插件各整份挪进 usr/uploads/noline_backup/,再让新版本顶上,不需要点任何东西。成对交换要么两边都成、要么两边都退回旧版本;历史版本全留在备份目录里,回滚同样成对。连不上 GitHub 的站点可以配镜像,token 只发给 api.github.com,绝不发给镜像。

接口清单 本机正在提供这些端点
GET /api/ping 连通性自检,不要密钥
GET /api/theme 站点门面 + 14 项主题配置 + 由强调色推出的配色
PUT /api/theme 写主题配置,另一个开关单独控制,body 只带要改的键
GET /api/health 体重概览:最新值 / BMI / 统计 / 趋势 / 目标
GET /api/health/records 体重明细,limit 到 366
POST /api/health/records 写一条或批量写,同一天覆盖
DELETE /api/health/records 按 date 删掉那天的记录
GET /api/bills 记账概览:周 / 月 / 累计 / 近 7 个月 / 本月分类占比
GET /api/bills/records 流水明细,limit 到 1000,可带 from / to / kind
POST /api/bills/records 记一笔或批量记,返回 ids[],永远新增
PUT /api/bills/records 按 id 改一条,只改传了的那些键
DELETE /api/bills/records 按 id 删一条

三种写法都认:/api/health(伪静态开着)、/index.php/api/health(伪静态关了)、?noline_api=health(服务器把 /api 抢走了时的兜底)。 后台顶栏的「主题管理」页是另一个入口,它看的是登录态,不吃接口密钥。

页面模板

showcase.php 就是这一页。不依赖插件,纯静态说明
health.php 健康记录页,体重/BMI 折线与统计;数据来自插件
bills.php 买菜记账页,周/月/累计开销、月度柱、分类占比与流水;数据来自插件
dcument.php 归档页,一次列全文章(代价:查询数是 O(文章数),文章上千会慢)
xiaoshi.php 单分类页,靠页面的自定义字段 category 指定分类缩略名
links.php 友链页,依赖 Links 插件;没装时只显示提示,不硬编码站点列表
404.php 带空态插画的错误页

怎么装进去

  1. 1
    下载发布包

    拿 Release 附件 noline.zip(或在仓库里跑 python3 _dev/build.py)。包里有两棵根:noline/ 落到 usr/themes/noline,plugins/NolineApi/ 落到 usr/plugins/NolineApi,在线更新一次把主题和插件一起换掉,不留版本错配的那一半。

  2. 2
    启用主题

    后台「控制台 → 主题」启用 Noline,到「设置外观」填这 14 项:站点头像地址、博主名字、座右铭、首页头图、强调色、动态分类、导航图标、首页公告、右栏分类卡、GitHub 显示名与链接、Bilibili 显示名与链接、站点底部版权。这 14 项就是接口能读写的全部字段,一一对应,没有隐藏项。

  3. 3
    要接口再装插件

    把 plugins/NolineApi 整个目录拷到 usr/plugins/,后台「插件」里启用并填密钥。启用后顶栏多一个「主题管理」:14 项设置的可视化编辑、接口自检、更新与回滚、图床接入都在那一页。不需要「停用 → 再启用」——插件每次路过前台入口和后台菜单都会拿数据库里的登记和当前代码比一遍,对不上就当场按核心语义重登记。

  4. 4
    建个人页

    想要那两个数据页就在「新建页面」里选模板:健康记录(slug 建议 health)、买菜记账(slug 建议 bills);这一页选「项目展示」(slug 建议 showcase)。三张页面都不存数据,删掉只是没了入口,记录还在插件的文件里。

  5. 5
    一句提醒

    usr/themes/noline/views/ 目录别删:里面是历史浏览量的兜底文件。新计数写在 usr/uploads/noline_views/,找不到才回读 views/,删了全站计数会从 0 重来。

已知取舍

  • 首页公告和底部版权原样存 HTML、不做标签清洗,接口写入也一样。这是有意的:公告里要能放链接和样式。代价是拿到接口密钥的人能往前台注入脚本,所以 PUT /api/theme 有独立开关。
  • 自动更新只认「Release 里的版本号比本机高」,不判断那个包本身是不是坏的。装上就生效,靠成对备份 + 成对回滚兜底,发布前自己验一遍。
  • 图床只实现「走 Cloudreve 服务端」的上传策略。实例把存储策略配成浏览器直传第三方对象存储时插件会明确拒绝并提示去后台改成云端/本地,而不是自作主张去接一套签名协议。实例开了登录验证码、或账号开了两步验证,插件绕不过去,只会在设置页把话说清楚。
  • 不做「首屏关键 CSS 内联 + 其余异步」:异步补 CSS 会重新引入首屏白闪,这一版宁可留全量阻塞 CSS。