// 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`"+`。也可以直接粘贴链接: ## 标题层级 ### 三级标题 #### 四级标题 标题会进入文章大纲,正文建议从二级标题用起。 ## 列表 无序列表: - 支持嵌套 - 子项缩进两个空格 - 快捷键 `+"`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),下面这张就是初始化时自动生成的示例图: ![示例图片](/api/images/%d) ## 其他 --- 私有笔记仅自己可见,公开笔记会出现在首页与 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[:]) }