feat: 新增发布日期自选、站点 Logo、回收站清空等十项改进
- 编辑页标题改 filled 变体;标签改 tags 选择器(可勾选既有/输入新建) - 笔记发布日期可自选(schema v2 新增 published_at 并回填),前台展示发布日期 - 登录页移除「请输入管理密码以继续」「连续失败将被暂时锁定」文案 - 站点设置每页条数收敛为 10/20/30/50 选择器,后端白名单同源校验 - 站点设置两卡片宽屏左右/窄屏上下;修改密码按钮改常规大小 - 后台各页顶栏固定高度,切换页面不再抖动 - 站点 Logo:settings 新增 site_logo(站内路径),gc/孤儿清单豁免 Logo 图片, 博客 header 站点名前展示,设置页支持上传/更换/清除 - 回收站右上角一键清空(DELETE /api/admin/trash,含确认弹窗) - pn init 写入 Markdown 语法示例文档(slug welcome,公开)与程序生成的示例图片
This commit is contained in:
+183
@@ -0,0 +1,183 @@
|
||||
// init 种子内容:一篇展示常用 Markdown 语法的初始文档 + 一张程序生成的示例图片。
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/sha256"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"image"
|
||||
"image/color"
|
||||
"image/png"
|
||||
"time"
|
||||
|
||||
"pure-note/internal/store"
|
||||
)
|
||||
|
||||
// welcomeSlug 固定 slug,便于用户识别与重装后覆盖判断(init 幂等由口令守卫保证)。
|
||||
const welcomeSlug = "welcome"
|
||||
|
||||
// seedWelcome 写入初始文档(公开)与其引用的示例图片;返回写入的笔记 id。
|
||||
func seedWelcome(st *store.Store) (int64, error) {
|
||||
imgID, err := seedWelcomeImage(st)
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("写入示例图片: %w", err)
|
||||
}
|
||||
content := welcomeMarkdown(imgID)
|
||||
now := time.Now().Unix()
|
||||
n := &store.Note{
|
||||
Slug: welcomeSlug,
|
||||
Title: "欢迎使用 Pure Note:Markdown 速览",
|
||||
Summary: "一篇入门笔记,覆盖日常写作会用到的全部 Markdown 语法:标题、列表、引用、代码、表格与图片。",
|
||||
Content: content,
|
||||
Status: "public",
|
||||
Tags: []string{"Markdown", "入门"},
|
||||
PublishedAt: now,
|
||||
CreatedAt: now,
|
||||
UpdatedAt: now,
|
||||
}
|
||||
id, err := st.CreateNote(n)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if err := st.RebuildImageRefs(id, content); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return id, nil
|
||||
}
|
||||
|
||||
// welcomeMarkdown 初始文档正文:覆盖常用语法,并引用示例图片。
|
||||
func welcomeMarkdown(imgID int64) string {
|
||||
return fmt.Sprintf(`这是一篇初始化时自动创建的示例笔记,覆盖日常写作会用到的绝大部分 Markdown 语法。随时可以编辑或删除它。
|
||||
|
||||
## 基础排版
|
||||
|
||||
普通段落之间用一个空行分隔。行内语法有:**加粗**、*斜体*、***粗斜体***、~~删除线~~,以及行内代码 `+"`pn start`"+`。也可以直接粘贴链接:<https://github.com>
|
||||
|
||||
## 标题层级
|
||||
|
||||
### 三级标题
|
||||
|
||||
#### 四级标题
|
||||
|
||||
标题会进入文章大纲,正文建议从二级标题用起。
|
||||
|
||||
## 列表
|
||||
|
||||
无序列表:
|
||||
|
||||
- 支持嵌套
|
||||
- 子项缩进两个空格
|
||||
- 快捷键 `+"`Ctrl/⌘ + S`"+` 可手动保存
|
||||
|
||||
有序列表:
|
||||
|
||||
1. 在编辑器里写 Markdown
|
||||
2. 粘贴图片直接上传
|
||||
3. 点击发布即可访问
|
||||
|
||||
任务列表:
|
||||
|
||||
- [x] 初始化站点
|
||||
- [x] 阅读本文档
|
||||
- [ ] 写第一篇笔记
|
||||
|
||||
## 引用
|
||||
|
||||
> 简单,可靠,只有一个数据文件。
|
||||
> —— Pure Note 设计哲学
|
||||
|
||||
## 代码块
|
||||
|
||||
代码块支持语法高亮:
|
||||
|
||||
`+"```go"+`
|
||||
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
func main() {
|
||||
fmt.Println("Hello, Pure Note!")
|
||||
}
|
||||
|
||||
`+"```"+`
|
||||
|
||||
`+"```"+`javascript
|
||||
const note = { title: "你好", tags: ["Markdown"] };
|
||||
console.log(`+"`开始写作:${note.title}`"+`);
|
||||
`+"```"+`
|
||||
|
||||
## 表格
|
||||
|
||||
| 语法 | 用途 | 示例 |
|
||||
| --- | --- | --- |
|
||||
| **文本** | 加粗 | **重要** |
|
||||
| `+"`代码`"+` | 行内代码 | `+"`npm run dev`"+` |
|
||||
| [文本](url) | 超链接 | [首页](/) |
|
||||
|
||||
## 图片
|
||||
|
||||
在编辑器里直接粘贴或拖入图片即可上传(≤5MB),下面这张就是初始化时自动生成的示例图:
|
||||
|
||||

|
||||
|
||||
## 其他
|
||||
|
||||
---
|
||||
|
||||
私有笔记仅自己可见,公开笔记会出现在首页与 RSS 中;删除的笔记进入回收站保留 30 天。祝写作愉快。
|
||||
`, imgID)
|
||||
}
|
||||
|
||||
// seedWelcomeImage 生成一张对角渐变 PNG(zinc 色系),入库后返回图片 id。
|
||||
func seedWelcomeImage(st *store.Store) (int64, error) {
|
||||
data, err := gradientPNG()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return st.UpsertImage(sha256Hex(data), "image/png", len(data), data, time.Now().Unix())
|
||||
}
|
||||
|
||||
// gradientPNG 绘制 960×360 对角渐变:zinc-950 → zinc-400,叠加一条高光斜带。
|
||||
func gradientPNG() ([]byte, error) {
|
||||
const w, h = 960, 360
|
||||
img := image.NewNRGBA(image.Rect(0, 0, w, h))
|
||||
from := color.RGBA{R: 24, G: 24, B: 27, A: 255} // #18181b
|
||||
to := color.RGBA{R: 161, G: 161, B: 170, A: 255} // #a1a1aa
|
||||
for y := 0; y < h; y++ {
|
||||
for x := 0; x < w; x++ {
|
||||
t := (float64(x)/float64(w-1) + float64(y)/float64(h-1)) / 2
|
||||
// 高光斜带:在 t≈0.55 附近提亮,形成柔和的光泽过渡
|
||||
band := 0.16 * float64(1) / (1 + pow2((t-0.55)*9))
|
||||
c := color.RGBA{
|
||||
R: lerp(from.R, to.R, t+band),
|
||||
G: lerp(from.G, to.G, t+band),
|
||||
B: lerp(from.B, to.B, t+band),
|
||||
A: 255,
|
||||
}
|
||||
img.Set(x, y, c)
|
||||
}
|
||||
}
|
||||
var buf bytes.Buffer
|
||||
if err := png.Encode(&buf, img); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return buf.Bytes(), nil
|
||||
}
|
||||
|
||||
func lerp(a, b uint8, t float64) uint8 {
|
||||
if t < 0 {
|
||||
t = 0
|
||||
} else if t > 1 {
|
||||
t = 1
|
||||
}
|
||||
return uint8(float64(a) + (float64(b)-float64(a))*t)
|
||||
}
|
||||
|
||||
func pow2(x float64) float64 { return x * x }
|
||||
|
||||
func sha256Hex(b []byte) string {
|
||||
sum := sha256.Sum256(b)
|
||||
return hex.EncodeToString(sum[:])
|
||||
}
|
||||
Reference in New Issue
Block a user