feat: 赞助卡片支持头像展示,优化布局
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,73 +1,84 @@
|
||||
# Sublog - Nuxt 3 博客
|
||||
# SuBlog
|
||||
|
||||
基于 Nuxt 3 的静态博客站点,使用 @nuxt/content 管理 Markdown 文章。
|
||||
尼克的小窝 — 个人技术博客
|
||||
|
||||
🔗 官方网站:[https://nixus.top/](https://nixus.top/)
|
||||
|
||||
## 为什么做这个
|
||||
|
||||
之前一直在用各种博客平台,但总觉得不够自由,想折腾点什么也不方便。后来决定自己搭一个,顺便把平时学的技术实践一下。
|
||||
|
||||
选 Nuxt 3 是因为 Vue 生态比较熟,SSG 静态生成部署也方便。UI 参考了 [二叉树树](https://2x.nz) 的设计,感谢大佬的开源精神。
|
||||
|
||||
## 主要功能
|
||||
|
||||
写文章、搜文章这些基本功能就不说了,主要说说我觉得比较实用的:
|
||||
|
||||
- **标签系统** — 文章打标签,首页展示高频标签,点击就能快速筛选
|
||||
- **封面制作** — 在线生成封面图,支持自定义文字、图标、背景,导出 PNG/SVG
|
||||
- **网易云热评** — 首页随机展示一条音乐评论,每次刷新都不一样
|
||||
- **暗色模式** — 跟随系统自动切换,也可以手动控制
|
||||
- **Giscus 评论** — 基于 GitHub Discussions,不用自己搞后端
|
||||
|
||||
## 技术栈
|
||||
|
||||
- **Nuxt 3** - Vue 3 全栈框架
|
||||
- **@nuxt/content** - Markdown 内容管理
|
||||
- **Tailwind CSS** - 样式框架
|
||||
- **TypeScript** - 类型安全
|
||||
- **Giscus** - GitHub Discussions 评论系统
|
||||
| 技术 | 用途 |
|
||||
|------|------|
|
||||
| Nuxt 3 | Vue 3 全栈框架,SSG 静态生成 |
|
||||
| TypeScript | 类型安全 |
|
||||
| Tailwind CSS v4 | 原子化样式 |
|
||||
| @nuxt/content | Markdown 文章管理 |
|
||||
| Shiki | 代码语法高亮(支持 60+ 语言) |
|
||||
| Giscus | 评论系统 |
|
||||
|
||||
## 开发
|
||||
|
||||
### 启动开发服务器
|
||||
## 快速开始
|
||||
|
||||
```bash
|
||||
npm run dev
|
||||
# 安装依赖
|
||||
pnpm install
|
||||
|
||||
# 开发
|
||||
pnpm dev
|
||||
|
||||
# 构建静态站点
|
||||
pnpm generate
|
||||
```
|
||||
|
||||
### 构建静态站点
|
||||
## 写文章
|
||||
|
||||
```bash
|
||||
npm run generate
|
||||
pnpm new-post <文章名称>
|
||||
```
|
||||
|
||||
构建产物输出到 `.output/public`,文章图片会自动复制。
|
||||
|
||||
### 预览构建结果
|
||||
|
||||
```bash
|
||||
npm run preview
|
||||
```
|
||||
|
||||
## 新建文章
|
||||
|
||||
```bash
|
||||
npm run new-post <slug>
|
||||
```
|
||||
|
||||
会在 `content/posts/<slug>/` 下创建 `index.md` 和 `img/` 目录。
|
||||
自动生成目录结构和 frontmatter 模板,填上 `description` 和 `tags` 就能写了。
|
||||
|
||||
## 项目结构
|
||||
|
||||
```
|
||||
├── config/site.ts # 站点配置(改这一个文件定制全站)
|
||||
├── content/posts/ # Markdown 文章
|
||||
│ └── <slug>/
|
||||
│ ├── index.md # 文章内容
|
||||
│ └── img/ # 文章图片
|
||||
├── assets/css/ # 全局样式和主题变量
|
||||
├── components/
|
||||
│ ├── layout/ # 布局组件(NavBar, Footer)
|
||||
│ └── blog/ # 博客组件(PostCard, PostToc, Giscus)
|
||||
├── composables/ # 组合式函数
|
||||
├── pages/ # 页面路由
|
||||
├── layouts/ # 布局模板
|
||||
├── server/routes/ # API 路由
|
||||
└── utils/ # 工具函数
|
||||
│ ├── layout/ # 导航栏、页脚、主题切换
|
||||
│ └── blog/ # 文章卡片、目录、评论
|
||||
├── config/site.ts # 全站配置(改这一个文件就行)
|
||||
├── content/posts/ # Markdown 文章
|
||||
├── pages/ # 页面路由
|
||||
├── public/ # 静态资源
|
||||
├── server/ # API 代理(网易云热评等)
|
||||
└── utils/ # 工具函数
|
||||
```
|
||||
|
||||
## 配置
|
||||
|
||||
站点信息集中在 `config/site.ts`:
|
||||
|
||||
- 站点名称、描述、关键词
|
||||
- 头像、favicon
|
||||
- 社交链接
|
||||
- 导航菜单
|
||||
- Giscus 评论配置
|
||||
所有站点配置集中在 `config/site.ts`,站点名称、头像、社交链接、导航菜单、友链、赞助、Giscus 都在这里改,改完自动生效。
|
||||
|
||||
## 部署
|
||||
|
||||
构建后将 `.output/public` 目录部署到任意静态托管服务(Vercel、Netlify、Cloudflare Pages 等)。
|
||||
```bash
|
||||
pnpm generate
|
||||
```
|
||||
|
||||
产物在 `.output/public` 目录,直接丢到 Nginx、Vercel、Netlify 或者 1Panel 都行。
|
||||
|
||||
## 开源计划
|
||||
|
||||
目前代码还不够整洁,等整理好了会考虑开源。如果你对这个项目感兴趣,欢迎先访问 [官方网站](https://nixus.top/) 看看效果。
|
||||
|
||||
@@ -39,7 +39,7 @@ export const siteConfig = {
|
||||
qrcode: {
|
||||
wechat: '/sponsors/qrcode/wechat.png',
|
||||
},
|
||||
list: [] as { name: string; date: string; amount: string }[],
|
||||
list: [] as { name: string; date: string; amount: string; avatar?: string }[],
|
||||
},
|
||||
|
||||
// Giscus 评论配置
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="1067" height="600" viewBox="0 0 1067 600" style="max-width:100%;height:auto;cursor:default;"><defs><pattern id="checkerboard" width="20" height="20" patternUnits="userSpaceOnUse"><rect width="10" height="10" fill="#e0e0e0"/><rect x="10" y="0" width="10" height="10" fill="#ffffff"/><rect x="0" y="10" width="10" height="10" fill="#ffffff"/><rect x="10" y="10" width="10" height="10" fill="#e0e0e0"/></pattern></defs><rect width="100%" height="100%" fill="url(#checkerboard)"/><rect width="100%" height="100%" fill="rgba(255, 255, 255, 1)"/><!----><foreignObject x="0" y="0" width="100%" height="100%" style="pointer-events:none;"><div xmlns="http://www.w3.org/1999/xhtml" style=" width: 100%; height: 100%; display: flex; align-items: center; justify-content: center; gap: 20px; font-family: sans-serif; font-weight: 700; "><div style="order: 0; width: 127px; height: 127px; display: flex; align-items: center; justify-content: center; background-color: transparent; backdrop-filter: none; border-radius: 0px;"><div style="max-width: 107px; max-height: 107px; flex-shrink: 0; color: rgb(0, 0, 0); filter: drop-shadow(rgba(0, 0, 0, 0) 0px 0px 0px); display: flex; align-items: center; justify-content: center; border-radius: 0%; overflow: hidden;"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="100%" height="100%" preserveAspectRatio="xMidYMid meet"><path fill="#000000" d="M12 2C6.477 2 2 6.477 2 12s4.477 10 10 10s10-4.477 10-10S17.523 2 12 2m4.49 9.04l-.006.014c-.42.898-1.516 2.66-1.516 2.66l-.005-.012l-.32.558h1.543l-2.948 3.919l.67-2.666h-1.215l.422-1.763a17 17 0 0 0-1.223.349s-.646.378-1.862-.729c0 0-.82-.722-.344-.902c.202-.077.981-.175 1.595-.257a80 80 0 0 1 1.338-.172s-2.555.039-3.161-.057c-.606-.095-1.375-1.107-1.539-1.996c0 0-.253-.488.545-.257s4.101.9 4.101.9S8.27 9.312 7.983 8.99c-.286-.32-.841-1.754-.769-2.634c0 0 .031-.22.257-.16c0 0 3.176 1.45 5.347 2.245s4.06 1.199 3.816 2.228c-.02.087-.072.216-.144.37"/></svg></div></div><span style=" order: 1; font-size: 80px; color: #000000; text-shadow: 0px 0px 0px rgba(0, 0, 0, 0); line-height: 1; white-space: nowrap; ">DWS</span><span style=" order: 2; font-size: 80px; color: #000000; text-shadow: 0px 0px 0px rgba(0, 0, 0, 0); line-height: 1; white-space: nowrap; ">钉钉cli</span></div></foreignObject><!--[--><g class="ratio-guide" style="display: none;"><rect x="0.16666666666674246" y="0" width="1066.6666666666665" height="600" fill="none" stroke="rgba(255,0,0,0.5)" stroke-width="2" stroke-dasharray="10 5"/><text x="10.166666666666742" y="30" fill="rgba(255,0,0,0.5)" font-size="20">16:9</text></g><!--]--><rect x="0" y="0" width="100%" height="100%" fill="none" stroke="rgba(255,0,0,0.8)" stroke-width="2" class="canvas-border" style="display: none;"/></svg>
|
||||
|
After Width: | Height: | Size: 3.1 KiB |
+9
-3
@@ -47,14 +47,20 @@ useSeoMeta({
|
||||
style="border-color: var(--color-border); background-color: var(--color-bg-card);"
|
||||
>
|
||||
<div class="flex items-center gap-4">
|
||||
<div class="flex h-12 w-12 shrink-0 items-center justify-center rounded-full text-lg font-bold" style="background: var(--color-bg-hover); color: var(--color-text-secondary);">
|
||||
<img
|
||||
v-if="sponsor.avatar"
|
||||
:src="sponsor.avatar"
|
||||
:alt="sponsor.name"
|
||||
class="h-12 w-12 shrink-0 rounded-full object-cover"
|
||||
/>
|
||||
<div v-else class="flex h-12 w-12 shrink-0 items-center justify-center rounded-full text-lg font-bold" style="background: var(--color-bg-hover); color: var(--color-text-secondary);">
|
||||
{{ sponsor.name.charAt(0) }}
|
||||
</div>
|
||||
<div class="flex-1">
|
||||
<div class="flex-1 min-w-0">
|
||||
<div class="font-semibold">{{ sponsor.name }}</div>
|
||||
<div class="text-sm text-muted-foreground">{{ sponsor.date }}</div>
|
||||
<div v-if="sponsor.amount" class="text-sm font-medium text-primary mt-1">{{ sponsor.amount }}</div>
|
||||
</div>
|
||||
<div class="text-sm font-medium text-primary">{{ sponsor.amount }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user