update all
This commit is contained in:
230
README.md
230
README.md
@@ -1,16 +1,37 @@
|
||||
# Nuxt Content 博客
|
||||
# Nuxt Content 博客系统
|
||||
|
||||
这是一个使用 Nuxt 3 和 Nuxt Content 构建的博客系统。
|
||||
这是一个使用 Nuxt 3 和 Nuxt Content 构建的现代化个人博客系统,支持 Markdown 内容管理,具有清新的设计风格和丰富的功能特性。
|
||||
|
||||
## 功能特点
|
||||
## ✨ 功能特点
|
||||
|
||||
- 📝 基于 Markdown 的内容管理
|
||||
- 🎨 使用 TailwindCSS 构建的响应式设计
|
||||
- 🚀 基于 Nuxt 3 的快速渲染
|
||||
- 📋 自动生成文章列表
|
||||
- 📅 支持文章元数据(标题、描述、日期等)
|
||||
### 📝 内容管理
|
||||
- 基于 Markdown 的内容创作
|
||||
- 支持文章封面图
|
||||
- 文章标签系统
|
||||
- 自动生成文章目录
|
||||
- 代码块语法高亮
|
||||
- 代码块一键复制功能
|
||||
- 按日期自动排序文章
|
||||
|
||||
## 快速开始
|
||||
### 🎨 界面设计
|
||||
- 响应式布局,适配多种设备
|
||||
- 清新现代的设计风格
|
||||
- 平滑过渡动画效果
|
||||
- 暗色模式支持(开发中)
|
||||
|
||||
### 🚀 核心页面
|
||||
- 个性化首页展示
|
||||
- 文章列表页
|
||||
- 友情链接页
|
||||
- 关于我页面
|
||||
|
||||
### 🛠 技术特性
|
||||
- 基于 Nuxt 3 的快速渲染
|
||||
- TailwindCSS 的原子化 CSS
|
||||
- 支持 Vue 组件在 Markdown 中使用
|
||||
- TypeScript 支持
|
||||
|
||||
## 🚀 快速开始
|
||||
|
||||
### 安装依赖
|
||||
|
||||
@@ -32,7 +53,7 @@ pnpm dev
|
||||
pnpm build
|
||||
```
|
||||
|
||||
## 添加新文章
|
||||
## 📝 创建文章
|
||||
|
||||
在 `content` 目录下创建新的 `.md` 文件。文件需要包含以下格式的头部信息:
|
||||
|
||||
@@ -41,27 +62,206 @@ pnpm build
|
||||
title: 文章标题
|
||||
description: 文章描述
|
||||
date: YYYY-MM-DD
|
||||
tags: ['标签1', '标签2']
|
||||
cover: '封面图片URL' # 可选
|
||||
---
|
||||
|
||||
# 文章内容
|
||||
```
|
||||
|
||||
## 项目结构
|
||||
## 📁 项目结构
|
||||
|
||||
```
|
||||
├── content/ # Markdown 文章
|
||||
│ └── posts/ # 博客文章
|
||||
├── components/ # Vue 组件
|
||||
├── layouts/ # 页面布局
|
||||
├── layouts/ # 页面布局
|
||||
├── pages/ # 页面路由
|
||||
└── public/ # 静态资源
|
||||
│ ├── index.vue # 首页
|
||||
│ ├── articles.vue # 文章列表
|
||||
│ ├── friends.vue # 友链页面
|
||||
│ └── about.vue # 关于页面
|
||||
├── public/ # 静态资源
|
||||
└── assets/ # 样式和资源文件
|
||||
```
|
||||
|
||||
## 技术栈
|
||||
## 🔧 自定义配置
|
||||
|
||||
### 修改个人信息
|
||||
1. 替换 `public/avatar.jpg` 更换头像
|
||||
2. 编辑 `pages/about.vue` 更新个人介绍
|
||||
3. 在 `pages/friends.vue` 中修改友链信息
|
||||
|
||||
### 自定义主题
|
||||
- 在 `tailwind.config.js` 中修改主题配置
|
||||
- 编辑 `layouts/default.vue` 调整全局样式
|
||||
|
||||
## 🔮 即将推出的功能
|
||||
|
||||
- [ ] 文章评论系统
|
||||
- [ ] 全文搜索功能
|
||||
- [ ] 文章目录导航
|
||||
- [ ] 暗色模式
|
||||
- [ ] SEO 优化
|
||||
- [ ] RSS 订阅
|
||||
|
||||
## <20> 部署指南
|
||||
|
||||
### 静态部署 (推荐)
|
||||
|
||||
1. 构建静态文件:
|
||||
|
||||
```bash
|
||||
# 生成静态文件
|
||||
pnpm generate
|
||||
```
|
||||
|
||||
生成的静态文件将位于 `.output/public` 目录中。
|
||||
|
||||
2. 将生成的文件部署到任意静态托管服务:
|
||||
|
||||
- GitHub Pages
|
||||
- Netlify
|
||||
- Vercel
|
||||
- 自有服务器
|
||||
|
||||
#### Nginx配置示例
|
||||
|
||||
```nginx
|
||||
server {
|
||||
listen 80;
|
||||
server_name yourdomain.com;
|
||||
root /path/to/your/blog/.output/public;
|
||||
index index.html;
|
||||
|
||||
# 启用 gzip 压缩
|
||||
gzip on;
|
||||
gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;
|
||||
|
||||
location / {
|
||||
try_files $uri $uri/ /index.html;
|
||||
}
|
||||
|
||||
# 缓存静态资源
|
||||
location /assets {
|
||||
expires 7d;
|
||||
add_header Cache-Control "public, no-transform";
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Node.js 服务器部署
|
||||
|
||||
1. 构建项目:
|
||||
|
||||
```bash
|
||||
pnpm build
|
||||
```
|
||||
|
||||
2. 在服务器上启动:
|
||||
|
||||
```bash
|
||||
# 使用 PM2 启动(推荐)
|
||||
pm2 start .output/server/index.mjs --name "blog"
|
||||
|
||||
# 或直接启动
|
||||
node .output/server/index.mjs
|
||||
```
|
||||
|
||||
#### PM2 配置示例 (ecosystem.config.js)
|
||||
|
||||
```javascript
|
||||
module.exports = {
|
||||
apps: [{
|
||||
name: 'blog',
|
||||
script: '.output/server/index.mjs',
|
||||
instances: 'max',
|
||||
exec_mode: 'cluster',
|
||||
env: {
|
||||
PORT: 3000,
|
||||
NODE_ENV: 'production'
|
||||
}
|
||||
}]
|
||||
}
|
||||
```
|
||||
|
||||
### Docker 部署
|
||||
|
||||
1. 创建 Dockerfile:
|
||||
|
||||
```dockerfile
|
||||
FROM node:18-alpine
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
# 安装 pnpm
|
||||
RUN npm install -g pnpm
|
||||
|
||||
# 复制项目文件
|
||||
COPY . .
|
||||
|
||||
# 安装依赖并构建
|
||||
RUN pnpm install
|
||||
RUN pnpm build
|
||||
|
||||
# 暴露端口
|
||||
EXPOSE 3000
|
||||
|
||||
# 启动服务
|
||||
CMD ["node", ".output/server/index.mjs"]
|
||||
```
|
||||
|
||||
2. 构建并运行容器:
|
||||
|
||||
```bash
|
||||
# 构建镜像
|
||||
docker build -t nuxt-blog .
|
||||
|
||||
# 运行容器
|
||||
docker run -d -p 3000:3000 nuxt-blog
|
||||
```
|
||||
|
||||
### Docker Compose 部署
|
||||
|
||||
创建 `docker-compose.yml`:
|
||||
|
||||
```yaml
|
||||
version: '3'
|
||||
|
||||
services:
|
||||
blog:
|
||||
build: .
|
||||
ports:
|
||||
- "3000:3000"
|
||||
restart: always
|
||||
environment:
|
||||
- NODE_ENV=production
|
||||
```
|
||||
|
||||
启动服务:
|
||||
|
||||
```bash
|
||||
docker-compose up -d
|
||||
```
|
||||
|
||||
## <20>🛠 技术栈
|
||||
|
||||
- [Nuxt 3](https://nuxt.com/)
|
||||
- [Nuxt Content](https://content.nuxt.com/)
|
||||
- [TailwindCSS](https://tailwindcss.com/)
|
||||
- [Vue 3](https://vuejs.org/)
|
||||
- [TypeScript](https://www.typescriptlang.org/)
|
||||
|
||||
## 许可证
|
||||
## 📝 许可证
|
||||
|
||||
MIT
|
||||
|
||||
## 🤝 贡献
|
||||
|
||||
欢迎提交 Issue 和 Pull Request!
|
||||
|
||||
1. Fork 本项目
|
||||
2. 创建您的特性分支 (`git checkout -b feature/AmazingFeature`)
|
||||
3. 提交您的修改 (`git commit -m 'Add some AmazingFeature'`)
|
||||
4. 推送到分支 (`git push origin feature/AmazingFeature`)
|
||||
5. 打开一个 Pull Request
|
||||
|
27
assets/css/code.css
Normal file
27
assets/css/code.css
Normal file
@@ -0,0 +1,27 @@
|
||||
/* 代码块样式 */
|
||||
.prose pre {
|
||||
position: relative !important;
|
||||
padding: 0.5rem 0.75rem !important;
|
||||
margin: 0.5rem 0 !important;
|
||||
border-radius: 0.375rem !important;
|
||||
background-color: #1f2937 !important;
|
||||
overflow-x: auto !important;
|
||||
}
|
||||
|
||||
.prose pre code {
|
||||
display: block !important;
|
||||
padding: 0 !important;
|
||||
padding-right: 2.5rem !important;
|
||||
margin: 0 !important;
|
||||
border-radius: 0 !important;
|
||||
background: none !important;
|
||||
color: #e5e7eb !important;
|
||||
font-size: 0.875rem !important;
|
||||
line-height: 1.25 !important;
|
||||
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace !important;
|
||||
}
|
||||
|
||||
/* 代码块语言标签 */
|
||||
.prose pre::before {
|
||||
display: none; /* 隐藏语言标签 */
|
||||
}
|
104
components/CopyCode.vue
Normal file
104
components/CopyCode.vue
Normal file
@@ -0,0 +1,104 @@
|
||||
<script setup>
|
||||
const props = defineProps({
|
||||
code: {
|
||||
type: String,
|
||||
required: true
|
||||
}
|
||||
})
|
||||
|
||||
const copied = ref(false)
|
||||
const buttonRef = ref(null)
|
||||
|
||||
onMounted(() => {
|
||||
// 确保按钮在代码块内部正确定位
|
||||
if (buttonRef.value) {
|
||||
const preElement = buttonRef.value.closest('pre')
|
||||
if (preElement) {
|
||||
preElement.style.position = 'relative'
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
const copyCode = () => {
|
||||
navigator.clipboard.writeText(props.code).then(() => {
|
||||
copied.value = true
|
||||
setTimeout(() => {
|
||||
copied.value = false
|
||||
}, 2000)
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="code-block-wrapper">
|
||||
<slot />
|
||||
<button
|
||||
ref="buttonRef"
|
||||
@click="copyCode"
|
||||
class="copy-button"
|
||||
:class="{ 'copied': copied }"
|
||||
type="button"
|
||||
>
|
||||
<span v-if="!copied" class="flex items-center">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4 mr-1" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 7v8a2 2 0 002 2h6M8 7V5a2 2 0 012-2h4.586a1 1 0 01.707.293l4.414 4.414a1 1 0 01.293.707V15a2 2 0 01-2 2h-2M8 7H6a2 2 0 00-2 2v10a2 2 0 002 2h8a2 2 0 002-2v-2" />
|
||||
</svg>
|
||||
复制
|
||||
</span>
|
||||
<span v-else class="flex items-center text-green-400">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4 mr-1" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7" />
|
||||
</svg>
|
||||
已复制!
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style>
|
||||
.code-block-wrapper {
|
||||
display: block;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.code-block-wrapper pre {
|
||||
margin: 0;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.copy-button {
|
||||
position: absolute !important;
|
||||
top: 0.5rem !important;
|
||||
right: 0.5rem !important;
|
||||
display: flex !important;
|
||||
align-items: center !important;
|
||||
padding: 0.375rem 0.5rem !important;
|
||||
font-size: 0.75rem !important;
|
||||
color: #ffffff !important;
|
||||
background-color: rgba(55, 65, 81, 0.9) !important;
|
||||
border-radius: 0.375rem !important;
|
||||
opacity: 0;
|
||||
transition: all 0.2s ease !important;
|
||||
z-index: 20 !important;
|
||||
cursor: pointer !important;
|
||||
border: none !important;
|
||||
outline: none !important;
|
||||
}
|
||||
|
||||
pre:hover .copy-button {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.copy-button:hover {
|
||||
background-color: rgba(55, 65, 81, 1) !important;
|
||||
transform: scale(1.05);
|
||||
}
|
||||
|
||||
.copy-button.copied {
|
||||
background-color: rgba(5, 150, 105, 0.9) !important;
|
||||
}
|
||||
|
||||
.copy-button.copied:hover {
|
||||
background-color: rgba(5, 150, 105, 1) !important;
|
||||
}
|
||||
</style>
|
110
components/content/ProseCode.vue
Normal file
110
components/content/ProseCode.vue
Normal file
@@ -0,0 +1,110 @@
|
||||
<template>
|
||||
<div class="relative group">
|
||||
<pre ref="codeBlock"
|
||||
:class="[`language-${language}`, 'overflow-x-auto']"
|
||||
><code :class="`language-${language}`"><slot /></code></pre>
|
||||
<button
|
||||
@click="copyCode"
|
||||
class="copy-button"
|
||||
:class="{ 'copied': copied }"
|
||||
type="button"
|
||||
>
|
||||
<span v-if="!copied" class="flex items-center">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4 mr-1" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 7v8a2 2 0 002 2h6M8 7V5a2 2 0 012-2h4.586a1 1 0 01.707.293l4.414 4.414a1 1 0 01.293.707V15a2 2 0 01-2 2h-2M8 7H6a2 2 0 00-2 2v10a2 2 0 002 2h8a2 2 0 002-2v-2" />
|
||||
</svg>
|
||||
复制
|
||||
</span>
|
||||
<span v-else class="flex items-center text-green-400">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4 mr-1" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7" />
|
||||
</svg>
|
||||
已复制!
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
const props = defineProps({
|
||||
code: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
language: {
|
||||
type: String,
|
||||
default: 'plaintext'
|
||||
},
|
||||
filename: {
|
||||
type: String,
|
||||
default: ''
|
||||
}
|
||||
})
|
||||
|
||||
const copied = ref(false)
|
||||
const codeBlock = ref(null)
|
||||
|
||||
const copyCode = async () => {
|
||||
const code = props.code || codeBlock.value?.querySelector('code')?.textContent || ''
|
||||
await navigator.clipboard.writeText(code)
|
||||
copied.value = true
|
||||
setTimeout(() => {
|
||||
copied.value = false
|
||||
}, 2000)
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.copy-button {
|
||||
position: absolute;
|
||||
top: 0.5rem;
|
||||
right: 0.5rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 0.375rem 0.5rem;
|
||||
font-size: 0.75rem;
|
||||
color: #ffffff;
|
||||
background-color: rgba(55, 65, 81, 0.9);
|
||||
border-radius: 0.375rem;
|
||||
opacity: 0;
|
||||
transition: all 0.2s ease;
|
||||
z-index: 20;
|
||||
cursor: pointer;
|
||||
border: none;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.group:hover .copy-button {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.copy-button:hover {
|
||||
background-color: rgba(55, 65, 81, 1);
|
||||
transform: scale(1.05);
|
||||
}
|
||||
|
||||
.copy-button.copied {
|
||||
background-color: rgba(5, 150, 105, 0.9);
|
||||
}
|
||||
|
||||
.copy-button.copied:hover {
|
||||
background-color: rgba(5, 150, 105, 1);
|
||||
}
|
||||
|
||||
pre {
|
||||
margin: 0;
|
||||
padding: 1rem;
|
||||
border-radius: 0.5rem;
|
||||
background-color: #1f2937;
|
||||
overflow-x: auto;
|
||||
}
|
||||
|
||||
pre code {
|
||||
display: block;
|
||||
padding-right: 2.5rem;
|
||||
color: #e5e7eb;
|
||||
font-size: 0.875rem;
|
||||
line-height: 1.5;
|
||||
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
|
||||
}
|
||||
</style>
|
37
content/build-blog-with-nuxt-content.md
Normal file
37
content/build-blog-with-nuxt-content.md
Normal file
@@ -0,0 +1,37 @@
|
||||
---
|
||||
title: 使用 Nuxt Content 搭建个人博客
|
||||
description: 本文介绍如何使用 Nuxt Content 模块快速搭建一个现代化的个人博客系统
|
||||
date: 2025-07-21
|
||||
tags: ['Nuxt', 'Vue', 'Web开发']
|
||||
cover: 'https://picsum.photos/800/400'
|
||||
---
|
||||
|
||||
Nuxt Content 是一个强大的文档驱动模块,让我们可以轻松地使用 Markdown 文件来管理博客内容。本文将介绍如何使用它来搭建一个现代化的个人博客系统。
|
||||
|
||||
## 特性
|
||||
|
||||
- 基于文件的 CMS
|
||||
- Markdown 支持
|
||||
- 强大的 MDC 语法
|
||||
- 自动生成目录
|
||||
- 代码高亮
|
||||
- 全文搜索
|
||||
- 支持 Vue 组件
|
||||
|
||||
## 示例代码
|
||||
|
||||
```js
|
||||
// nuxt.config.ts
|
||||
export default defineNuxtConfig({
|
||||
modules: ['@nuxt/content'],
|
||||
content: {
|
||||
highlight: {
|
||||
theme: 'github-dark'
|
||||
}
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
## 总结
|
||||
|
||||
Nuxt Content 提供了一个简单而强大的方式来构建内容驱动的网站。通过合理的目录结构和配置,我们可以快速搭建出一个功能完善的博客系统。
|
118
content/ssh-key-linux.md
Normal file
118
content/ssh-key-linux.md
Normal file
@@ -0,0 +1,118 @@
|
||||
---
|
||||
title: 通过SSH密钥连接LINUX服务器
|
||||
description: 本文介绍如何通过SSH密钥连接LINUX服务器
|
||||
date: 2025-07-22
|
||||
tags: ['SSH', '密钥', 'Linux']
|
||||
cover: 'https://picsum.photos/800/221'
|
||||
---
|
||||
|
||||
## 前提条件
|
||||
使用**ROOT**用户(个人喜好)、客户端使用Windows PowerShell终端、服务端使用Debian12+或是Ubuntu24+
|
||||
## 客户端操作
|
||||
### 创建密钥对
|
||||
随便在哪按 WIN + X 再按 I 打开<mark>PowerShell</mark>终端
|
||||
进入用户的.ssh文件夹
|
||||
```shell
|
||||
cd ~\.ssh
|
||||
```
|
||||
创建密钥对,使用椭圆加密算法,相比RSA更加短小精悍
|
||||
```shell
|
||||
ssh-keygen -t ed25519
|
||||
```
|
||||
输出Enter file in which to save the key,是对密钥对进行命名,我这里输入test
|
||||
之后输出Enter passphrase (empty for no passphrase),是对私钥进行加密,输入私钥的密码(不会显示),不设置就按Enter跳过
|
||||
然后确认密码,依旧按Enter跳过
|
||||
出现一个方框图形,表示创建成功
|
||||
之后 ~\.ssh 文件夹中会出现一个 test 私钥文件和一个 test.pub 公钥文件
|
||||
至此,客户端的操作暂时结束
|
||||
|
||||
## 服务端操作
|
||||
### 上传公钥至服务器
|
||||
#### 创建实例阶段
|
||||
在创建实例阶段,如阿里云服务器,可以在**管理设置-登录凭证**中选择密钥对;**登录名**选择root;**密钥**对选择右边创建密钥对
|
||||
创建密钥对界面,密钥对名称随意;创建类型选择导入已有密钥对,
|
||||
在客户端Windows电脑中进入 ~\.ssh文件夹中,找到第一步创建的test.pub,用任意编辑器打开后,复制其内容到公钥内容框中,标签键随意,
|
||||
然后回到实例创建页面,在密钥对选择刚刚创建的密钥对即可
|
||||
#### 已有服务器
|
||||
使用SSH密码登录到服务器,切换到ROOT用户
|
||||
```shell
|
||||
sudo -i
|
||||
```
|
||||
##### 复制公钥到服务器
|
||||
进入/root/.ssh文件夹
|
||||
```shell
|
||||
cd /root/.ssh
|
||||
```
|
||||
创建或编辑 authorized_keys 文件
|
||||
```shell
|
||||
vim authorized_keys
|
||||
```
|
||||
按 I 进入编辑模式,将公钥内容复制进去
|
||||
按 Esc ,输入 :wq 保存并退出
|
||||
##### 编辑SSH-SERVER配置文件
|
||||
进入/etc/ssh文件夹
|
||||
```shell
|
||||
cd /etc/ssh
|
||||
```
|
||||
编辑sshd_config文件
|
||||
```shell
|
||||
vim sshd_config
|
||||
```
|
||||
同样按 I 进入编辑模式,并确保下列三个参数如下
|
||||
```shell
|
||||
PermitRootLogin yes #允许使用ROOT用户登录
|
||||
PubkeyAuthentication yes #使用密钥对
|
||||
PasswordAuthentication no #禁用密码
|
||||
```
|
||||
按 Esc 退出编辑模式,输入 :wq 保存并退出
|
||||
##### 重启SSH-SERVER服务
|
||||
一般使用
|
||||
```shell
|
||||
systemctl restart sshd
|
||||
```
|
||||
不行就试试
|
||||
```shell
|
||||
service ssh restart
|
||||
```
|
||||
##### **不要断开SSH连接,防止配置有问题连接不上**
|
||||
## 使用密钥对进行连接
|
||||
### 直接连接
|
||||
新开一个PowerShell终端
|
||||
```shell
|
||||
ssh -i ~/.ssh/test root@192.168.21.5
|
||||
```
|
||||
输出 Enter passphrase for key 提示输入私钥密码(输入的内容不会显示),之前没设置就直接按 Enter ;不出意外就可以连接上了
|
||||
### 编辑config文件进行简便连接
|
||||
**注意:** 只用使用Windows的终端才能简便连接,使用mobaxterm等ssh软件这个配置是没用的
|
||||
在Windows客户端中,进入 ~\.ssh 文件夹
|
||||
|
||||
```shell
|
||||
cd ~\.ssh
|
||||
```
|
||||
使用记事本编辑config文件
|
||||
```shell
|
||||
noteapd config
|
||||
```
|
||||
格式如
|
||||
```shell
|
||||
Host test
|
||||
HostName 192.168.21.5
|
||||
IdentityFile ~/.ssh/test
|
||||
User root
|
||||
```
|
||||
如果端口不是22,则需要加上端口,如ssh使用222端口
|
||||
```shell
|
||||
Host test
|
||||
HostName 192.168.21.5
|
||||
IdentityFile ~/.ssh/test
|
||||
Port 222
|
||||
User root
|
||||
```
|
||||
保存
|
||||
然后在PowerShell终端中就可以进行简便连接如
|
||||
```shell
|
||||
ssh test
|
||||
```
|
||||
这里的test是 config 文件 Host 后的字符,可以用Emoji表情
|
||||
**注意:** 在使用SSH密钥对克隆GitHub或是其他git相关网站时,Host最好设置为网站的域名,你问为什么?时间的教训罢了~
|
||||
## 至此教程结束
|
@@ -1,7 +1,7 @@
|
||||
---
|
||||
title: 欢迎来到我的博客
|
||||
description: 这是我的第一篇博客文章
|
||||
date: 2025-07-22
|
||||
date: 2025-07-21
|
||||
---
|
||||
|
||||
# 欢迎来到我的博客
|
||||
|
@@ -1,17 +1,46 @@
|
||||
<template>
|
||||
<div class="min-h-screen bg-gray-100">
|
||||
<header class="bg-white shadow">
|
||||
<nav class="container mx-auto px-4 py-6">
|
||||
<NuxtLink to="/" class="text-2xl font-bold text-gray-800">我的博客</NuxtLink>
|
||||
<div class="min-h-screen bg-[#faf6f1]">
|
||||
<header class="bg-white/80 backdrop-blur-sm sticky top-0 z-50 border-b border-gray-200">
|
||||
<nav class="container mx-auto px-4 py-4">
|
||||
<div class="flex justify-center space-x-8">
|
||||
<NuxtLink to="/" class="nav-link">首页</NuxtLink>
|
||||
<NuxtLink to="/articles" class="nav-link">文稿</NuxtLink>
|
||||
<NuxtLink to="/friends" class="nav-link">朋友们</NuxtLink>
|
||||
<NuxtLink to="/about" class="nav-link">留言</NuxtLink>
|
||||
</div>
|
||||
</nav>
|
||||
</header>
|
||||
<main class="container mx-auto px-4 py-8">
|
||||
<slot />
|
||||
</main>
|
||||
<footer class="bg-white shadow mt-8">
|
||||
<footer class="bg-white/80 mt-8 border-t border-gray-200">
|
||||
<div class="container mx-auto px-4 py-6 text-center text-gray-600">
|
||||
© 2025 我的博客. 保留所有权利.
|
||||
<p class="mb-2">© 2025 我的博客. 保留所有权利.</p>
|
||||
<div class="flex justify-center space-x-4 mt-4">
|
||||
<a href="https://github.com/yourusername" target="_blank" class="text-gray-400 hover:text-gray-600">
|
||||
<span class="sr-only">GitHub</span>
|
||||
<svg class="h-6 w-6" fill="currentColor" viewBox="0 0 24 24"><path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/></svg>
|
||||
</a>
|
||||
<a href="https://space.bilibili.com/yourid" target="_blank" class="text-gray-400 hover:text-gray-600">
|
||||
<span class="sr-only">Bilibili</span>
|
||||
<svg class="h-6 w-6" fill="currentColor" viewBox="0 0 24 24"><path d="M17.813 4.653h.854c1.51.054 2.769.578 3.773 1.574 1.004.995 1.524 2.249 1.56 3.76v7.36c-.036 1.51-.556 2.769-1.56 3.773s-2.262 1.524-3.773 1.56H5.333c-1.51-.036-2.769-.556-3.773-1.56S.036 18.858 0 17.347v-7.36c.036-1.511.556-2.765 1.56-3.76 1.004-.996 2.262-1.52 3.773-1.574h.774l-1.174-1.12a1.234 1.234 0 0 1-.373-.906c0-.356.124-.658.373-.907l.027-.027c.267-.249.573-.373.92-.373.347 0 .653.124.92.373L9.653 4.44c.071.071.134.142.187.213h4.267a.836.836 0 0 1 .16-.213l2.853-2.747c.267-.249.573-.373.92-.373.347 0 .662.151.929.4.267.249.391.551.391.907 0 .355-.124.657-.373.906zM5.333 7.24c-.746.018-1.373.276-1.88.773-.506.498-.769 1.13-.786 1.894v7.52c.017.764.28 1.395.786 1.893.507.498 1.134.756 1.88.773h13.334c.746-.017 1.373-.275 1.88-.773.506-.498.769-1.129.786-1.893v-7.52c-.017-.765-.28-1.396-.786-1.894-.507-.497-1.134-.755-1.88-.773zM8 11.107c.373 0 .684.124.933.373.25.249.383.569.4.96v1.173c-.017.391-.15.711-.4.96-.249.25-.56.374-.933.374s-.684-.125-.933-.374c-.25-.249-.383-.569-.4-.96V12.44c0-.373.129-.689.386-.947.258-.257.574-.386.947-.386zm8 0c.373 0 .684.124.933.373.25.249.383.569.4.96v1.173c-.017.391-.15.711-.4.96-.249.25-.56.374-.933.374s-.684-.125-.933-.374c-.25-.249-.383-.569-.4-.96V12.44c.017-.391.15-.711.4-.96.249-.249.56-.373.933-.373z"/></svg>
|
||||
</a>
|
||||
<a href="mailto:your@email.com" class="text-gray-400 hover:text-gray-600">
|
||||
<span class="sr-only">Email</span>
|
||||
<svg class="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 8l7.89 5.26a2 2 0 002.22 0L21 8M5 19h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v10a2 2 0 002 2z"/></svg>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style>
|
||||
.nav-link {
|
||||
@apply px-4 py-2 text-gray-600 hover:text-gray-900 rounded-full hover:bg-gray-100 transition-colors;
|
||||
}
|
||||
|
||||
.nav-link.router-link-active {
|
||||
@apply text-gray-900 bg-gray-100;
|
||||
}
|
||||
</style>
|
||||
|
@@ -2,10 +2,15 @@
|
||||
export default defineNuxtConfig({
|
||||
devtools: { enabled: true },
|
||||
modules: ['@nuxt/content', '@nuxtjs/tailwindcss'],
|
||||
css: ['~/assets/css/code.css'],
|
||||
content: {
|
||||
// https://content.nuxtjs.org/api/configuration
|
||||
highlight: {
|
||||
theme: 'github-dark'
|
||||
theme: {
|
||||
default: 'github-dark',
|
||||
dark: 'github-dark'
|
||||
},
|
||||
preload: ['bash', 'shell', 'sh', 'javascript', 'js', 'typescript', 'ts', 'json', 'md', 'yaml', 'vue'],
|
||||
},
|
||||
markdown: {
|
||||
toc: {
|
||||
@@ -13,5 +18,17 @@ export default defineNuxtConfig({
|
||||
searchDepth: 3
|
||||
}
|
||||
}
|
||||
},
|
||||
app: {
|
||||
head: {
|
||||
charset: 'utf-8',
|
||||
viewport: 'width=device-width, initial-scale=1'
|
||||
}
|
||||
},
|
||||
nitro: {
|
||||
compressPublicAssets: true
|
||||
},
|
||||
experimental: {
|
||||
componentIslands: true
|
||||
}
|
||||
})
|
||||
|
@@ -12,6 +12,7 @@
|
||||
"@nuxt/content": "^2.12.0",
|
||||
"@nuxt/devtools": "latest",
|
||||
"@nuxtjs/tailwindcss": "^6.11.4",
|
||||
"@tailwindcss/typography": "^0.5.16",
|
||||
"nuxt": "^3.10.0"
|
||||
}
|
||||
}
|
||||
|
@@ -1,11 +1,28 @@
|
||||
<script setup>
|
||||
const route = useRoute()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<article class="prose lg:prose-xl mx-auto">
|
||||
<ContentDoc />
|
||||
<article class="prose prose-slate lg:prose-lg dark:prose-invert mx-auto px-4 py-8">
|
||||
<ContentDoc :path="route.path" v-slot="{ doc }">
|
||||
<div class="mb-8">
|
||||
<h1 class="text-4xl font-bold mb-4">{{ doc.title }}</h1>
|
||||
<div class="flex items-center gap-4 text-gray-500">
|
||||
<time :datetime="doc.date">{{ new Date(doc.date).toLocaleDateString('zh-CN', {
|
||||
year: 'numeric',
|
||||
month: 'long',
|
||||
day: 'numeric'
|
||||
}) }}</time>
|
||||
<div v-if="doc.tags" class="flex gap-2">
|
||||
<span v-for="tag in doc.tags" :key="tag"
|
||||
class="px-2 py-1 bg-gray-100 rounded-full text-sm">
|
||||
{{ tag }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<ContentRenderer :value="doc" :components="{ prose }" />
|
||||
</ContentDoc>
|
||||
</article>
|
||||
</template>
|
||||
|
||||
<style>
|
||||
.prose {
|
||||
max-width: 65ch;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
44
pages/about.vue
Normal file
44
pages/about.vue
Normal file
@@ -0,0 +1,44 @@
|
||||
<template>
|
||||
<div class="max-w-4xl mx-auto">
|
||||
<div class="bg-white rounded-2xl shadow-sm p-8 mb-8">
|
||||
<div class="flex flex-col md:flex-row items-center gap-8">
|
||||
<div class="w-48 h-48 rounded-full overflow-hidden">
|
||||
<img src="/avatar.jpg" alt="头像" class="w-full h-full object-cover"
|
||||
onerror="this.src='https://api.dicebear.com/7.x/adventurer/svg?seed=custom'"/>
|
||||
</div>
|
||||
<div class="flex-1 text-center md:text-left">
|
||||
<h1 class="text-3xl font-bold mb-4">ZiBright</h1>
|
||||
<p class="text-gray-600 mb-4">在不停学习中~</p>
|
||||
<div class="flex justify-center md:justify-start space-x-4">
|
||||
<a href="https://github.com/yourusername" target="_blank"
|
||||
class="p-2 rounded-lg hover:bg-gray-100 transition-colors">
|
||||
<svg class="h-6 w-6 text-gray-600" fill="currentColor" viewBox="0 0 24 24">
|
||||
<path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/>
|
||||
</svg>
|
||||
</a>
|
||||
<a href="https://space.bilibili.com/yourid" target="_blank"
|
||||
class="p-2 rounded-lg hover:bg-gray-100 transition-colors">
|
||||
<svg class="h-6 w-6 text-gray-600" fill="currentColor" viewBox="0 0 24 24">
|
||||
<path d="M17.813 4.653h.854c1.51.054 2.769.578 3.773 1.574 1.004.995 1.524 2.249 1.56 3.76v7.36c-.036 1.51-.556 2.769-1.56 3.773s-2.262 1.524-3.773 1.56H5.333c-1.51-.036-2.769-.556-3.773-1.56S.036 18.858 0 17.347v-7.36c.036-1.511.556-2.765 1.56-3.76 1.004-.996 2.262-1.52 3.773-1.574h.774l-1.174-1.12a1.234 1.234 0 0 1-.373-.906c0-.356.124-.658.373-.907l.027-.027c.267-.249.573-.373.92-.373.347 0 .653.124.92.373L9.653 4.44c.071.071.134.142.187.213h4.267a.836.836 0 0 1 .16-.213l2.853-2.747c.267-.249.573-.373.92-.373.347 0 .662.151.929.4.267.249.391.551.391.907 0 .355-.124.657-.373.906zM5.333 7.24c-.746.018-1.373.276-1.88.773-.506.498-.769 1.13-.786 1.894v7.52c.017.764.28 1.395.786 1.893.507.498 1.134.756 1.88.773h13.334c.746-.017 1.373-.275 1.88-.773.506-.498.769-1.129.786-1.893v-7.52c-.017-.765-.28-1.396-.786-1.894-.507-.497-1.134-.755-1.88-.773zM8 11.107c.373 0 .684.124.933.373.25.249.383.569.4.96v1.173c-.017.391-.15.711-.4.96-.249.25-.56.374-.933.374s-.684-.125-.933-.374c-.25-.249-.383-.569-.4-.96V12.44c0-.373.129-.689.386-.947.258-.257.574-.386.947-.386zm8 0c.373 0 .684.124.933.373.25.249.383.569.4.96v1.173c-.017.391-.15.711-.4.96-.249.25-.56.374-.933.374s-.684-.125-.933-.374c-.25-.249-.383-.569-.4-.96V12.44c.017-.391.15-.711.4-.96.249-.249.56-.373.933-.373z"/>
|
||||
</svg>
|
||||
</a>
|
||||
<a href="mailto:your@email.com"
|
||||
class="p-2 rounded-lg hover:bg-gray-100 transition-colors">
|
||||
<svg class="h-6 w-6 text-gray-600" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 8l7.89 5.26a2 2 0 002.22 0L21 8M5 19h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v10a2 2 0 002 2z"/>
|
||||
</svg>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="bg-white rounded-2xl shadow-sm p-8">
|
||||
<h2 class="text-2xl font-bold mb-6">关于我</h2>
|
||||
<div class="prose max-w-none">
|
||||
<p>这里是一段关于我的介绍,你可以写一些个人经历、兴趣爱好等。</p>
|
||||
<p>支持 Markdown 格式,可以自由发挥~</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
45
pages/articles.vue
Normal file
45
pages/articles.vue
Normal file
@@ -0,0 +1,45 @@
|
||||
<template>
|
||||
<div class="max-w-4xl mx-auto">
|
||||
<div class="mb-8">
|
||||
<h1 class="text-3xl font-bold mb-4">所有文章</h1>
|
||||
<div class="text-gray-600">记录学习与生活的点点滴滴</div>
|
||||
</div>
|
||||
|
||||
<div class="grid gap-6">
|
||||
<ContentList path="/" :query="{ sort: [{ date: -1 }] }" v-slot="{ list }">
|
||||
<div v-for="article in list" :key="article._path"
|
||||
class="bg-white rounded-lg shadow-sm p-6 hover:shadow-md transition-shadow">
|
||||
<NuxtLink :to="article._path" class="block group">
|
||||
<div class="flex justify-between items-start gap-4">
|
||||
<div>
|
||||
<h2 class="text-xl font-bold mb-2 group-hover:text-blue-600 transition-colors">
|
||||
{{ article.title }}
|
||||
</h2>
|
||||
<p class="text-gray-600 mb-4 line-clamp-2">{{ article.description }}</p>
|
||||
<div class="flex items-center text-sm text-gray-500 gap-4">
|
||||
<span>
|
||||
{{ new Date(article.date).toLocaleDateString('zh-CN', {
|
||||
year: 'numeric',
|
||||
month: 'long',
|
||||
day: 'numeric'
|
||||
}) }}
|
||||
</span>
|
||||
<span v-if="article.tags" class="flex gap-2">
|
||||
<span v-for="tag in article.tags" :key="tag"
|
||||
class="px-2 py-1 bg-gray-100 rounded-full text-xs">
|
||||
{{ tag }}
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="article.cover" class="flex-shrink-0">
|
||||
<img :src="article.cover" :alt="article.title"
|
||||
class="w-32 h-24 object-cover rounded-lg" />
|
||||
</div>
|
||||
</div>
|
||||
</NuxtLink>
|
||||
</div>
|
||||
</ContentList>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
57
pages/friends.vue
Normal file
57
pages/friends.vue
Normal file
@@ -0,0 +1,57 @@
|
||||
<script setup>
|
||||
const friends = [
|
||||
{
|
||||
name: '示例博客',
|
||||
avatar: 'https://api.dicebear.com/7.x/adventurer/svg?seed=demo1',
|
||||
url: 'https://example.com',
|
||||
description: '这是一个示例博客'
|
||||
},
|
||||
{
|
||||
name: '另一个博客',
|
||||
avatar: 'https://api.dicebear.com/7.x/adventurer/svg?seed=demo2',
|
||||
url: 'https://example2.com',
|
||||
description: '这是另一个示例博客'
|
||||
}
|
||||
]
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="max-w-4xl mx-auto">
|
||||
<div class="mb-8">
|
||||
<h1 class="text-3xl font-bold mb-4">友链</h1>
|
||||
<div class="text-gray-600">友情链接</div>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
|
||||
<a v-for="friend in friends" :key="friend.name" :href="friend.url" target="_blank"
|
||||
class="block bg-white rounded-lg shadow-sm p-6 hover:shadow-md transition-all">
|
||||
<div class="flex items-center gap-4">
|
||||
<img :src="friend.avatar" :alt="friend.name" class="w-16 h-16 rounded-full" />
|
||||
<div>
|
||||
<h3 class="text-lg font-bold mb-1">{{ friend.name }}</h3>
|
||||
<p class="text-gray-600 text-sm">{{ friend.description }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="mt-12 bg-white rounded-lg shadow-sm p-6">
|
||||
<h2 class="text-xl font-bold mb-4">申请友链</h2>
|
||||
<p class="text-gray-600 mb-4">如果您想要申请友链,请确保您的网站满足以下条件:</p>
|
||||
<ul class="list-disc list-inside text-gray-600 mb-6">
|
||||
<li>网站内容合法合规</li>
|
||||
<li>网站能够正常访问</li>
|
||||
<li>网站已添加本站友链</li>
|
||||
</ul>
|
||||
<p class="text-gray-600">
|
||||
符合条件的朋友可以通过以下格式发送邮件至
|
||||
<a href="mailto:your@email.com" class="text-blue-600 hover:underline">your@email.com</a>:
|
||||
</p>
|
||||
<pre class="bg-gray-50 p-4 rounded-lg mt-4 text-sm">
|
||||
名称:您的网站名称
|
||||
简介:网站简介
|
||||
链接:网站链接
|
||||
头像:头像链接</pre>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
@@ -1,18 +1,71 @@
|
||||
<template>
|
||||
<div>
|
||||
<h1 class="text-4xl font-bold mb-8">最新文章</h1>
|
||||
<div class="grid gap-6">
|
||||
<ContentList path="/" v-slot="{ list }">
|
||||
<div v-for="article in list" :key="article._path" class="bg-white shadow rounded-lg p-6">
|
||||
<NuxtLink :to="article._path">
|
||||
<h2 class="text-2xl font-bold mb-2">{{ article.title }}</h2>
|
||||
<p class="text-gray-600">{{ article.description }}</p>
|
||||
<div class="mt-4 text-sm text-gray-500">
|
||||
{{ new Date(article.date).toLocaleDateString() }}
|
||||
</div>
|
||||
</NuxtLink>
|
||||
<div class="max-w-4xl mx-auto">
|
||||
<!-- 个人信息卡片 -->
|
||||
<div class="bg-white rounded-2xl shadow-sm p-8 mb-8">
|
||||
<div class="flex flex-col md:flex-row items-center gap-8">
|
||||
<div class="w-48 h-48 rounded-full overflow-hidden">
|
||||
<img src="/avatar.jpg" alt="头像" class="w-full h-full object-cover"
|
||||
onerror="this.src='https://api.dicebear.com/7.x/adventurer/svg?seed=custom'"/>
|
||||
</div>
|
||||
</ContentList>
|
||||
<div class="flex-1 text-center md:text-left">
|
||||
<h1 class="text-3xl font-bold mb-4">ZiBright</h1>
|
||||
<div class="text-lg text-gray-600 mb-6">这里是我的博客</div>
|
||||
<div class="flex justify-center md:justify-start gap-4">
|
||||
<NuxtLink to="/about" class="inline-flex items-center gap-2 px-4 py-2 bg-gray-100 rounded-full hover:bg-gray-200 transition-colors">
|
||||
<span>关于我</span>
|
||||
</NuxtLink>
|
||||
<NuxtLink to="/friends" class="inline-flex items-center gap-2 px-4 py-2 bg-gray-100 rounded-full hover:bg-gray-200 transition-colors">
|
||||
<span>朋友们</span>
|
||||
</NuxtLink>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 最新文章 -->
|
||||
<div class="mb-8">
|
||||
<div class="flex justify-between items-center mb-6">
|
||||
<h2 class="text-2xl font-bold">最新文章</h2>
|
||||
<NuxtLink to="/articles" class="text-gray-600 hover:text-gray-900">
|
||||
查看全部 →
|
||||
</NuxtLink>
|
||||
</div>
|
||||
<div class="grid gap-6">
|
||||
<ContentList path="/" :query="{ sort: [{ date: -1 }] }" v-slot="{ list }">
|
||||
<div v-for="article in list.slice(0, 5)" :key="article._path"
|
||||
class="bg-white rounded-lg shadow-sm p-6 hover:shadow-md transition-shadow">
|
||||
<NuxtLink :to="article._path" class="block group">
|
||||
<div class="flex justify-between items-start gap-4">
|
||||
<div>
|
||||
<h3 class="text-xl font-bold mb-2 group-hover:text-blue-600 transition-colors">
|
||||
{{ article.title }}
|
||||
</h3>
|
||||
<p class="text-gray-600 mb-4 line-clamp-2">{{ article.description }}</p>
|
||||
<div class="flex items-center text-sm text-gray-500 gap-4">
|
||||
<span>
|
||||
{{ new Date(article.date).toLocaleDateString('zh-CN', {
|
||||
year: 'numeric',
|
||||
month: 'long',
|
||||
day: 'numeric'
|
||||
}) }}
|
||||
</span>
|
||||
<span v-if="article.tags" class="flex gap-2">
|
||||
<span v-for="tag in article.tags" :key="tag"
|
||||
class="px-2 py-1 bg-gray-100 rounded-full text-xs">
|
||||
{{ tag }}
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="article.cover" class="flex-shrink-0">
|
||||
<img :src="article.cover" :alt="article.title"
|
||||
class="w-32 h-24 object-cover rounded-lg" />
|
||||
</div>
|
||||
</div>
|
||||
</NuxtLink>
|
||||
</div>
|
||||
</ContentList>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
40
pnpm-lock.yaml
generated
40
pnpm-lock.yaml
generated
@@ -17,6 +17,9 @@ importers:
|
||||
'@nuxtjs/tailwindcss':
|
||||
specifier: ^6.11.4
|
||||
version: 6.14.0(magicast@0.3.5)
|
||||
'@tailwindcss/typography':
|
||||
specifier: ^0.5.16
|
||||
version: 0.5.16(tailwindcss@3.4.17)
|
||||
nuxt:
|
||||
specifier: ^3.10.0
|
||||
version: 3.17.7(@netlify/blobs@9.1.2)(@parcel/watcher@2.5.1)(@types/node@24.0.15)(@vue/compiler-sfc@3.5.17)(db0@0.3.2)(ioredis@5.6.1)(magicast@0.3.5)(rollup@4.45.1)(terser@5.43.1)(typescript@5.8.3)(vite@6.3.5(@types/node@24.0.15)(jiti@2.4.2)(terser@5.43.1)(yaml@2.8.0))(yaml@2.8.0)
|
||||
@@ -1054,6 +1057,11 @@ packages:
|
||||
'@speed-highlight/core@1.2.7':
|
||||
resolution: {integrity: sha512-0dxmVj4gxg3Jg879kvFS/msl4s9F3T9UXC1InxgOf7t5NvcPD97u/WTA5vL/IxWHMn7qSxBozqrnnE2wvl1m8g==}
|
||||
|
||||
'@tailwindcss/typography@0.5.16':
|
||||
resolution: {integrity: sha512-0wDLwCVF5V3x3b1SGXPCDcdsbDHMBe+lkFzBRaHeLvNi+nrrnZ1lA18u+OTWO8iSWU2GxUOCvlXtDuqftc1oiA==}
|
||||
peerDependencies:
|
||||
tailwindcss: '>=3.0.0 || insiders || >=4.0.0-alpha.20 || >=4.0.0-beta.1'
|
||||
|
||||
'@tybys/wasm-util@0.10.0':
|
||||
resolution: {integrity: sha512-VyyPYFlOMNylG45GoAe0xDoLwWuowvf92F9kySqzYh8vmYm7D2u4iUJKa1tOUpS70Ku13ASrOkS4ScXFsTaCNQ==}
|
||||
|
||||
@@ -2653,6 +2661,9 @@ packages:
|
||||
lodash-es@4.17.21:
|
||||
resolution: {integrity: sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==}
|
||||
|
||||
lodash.castarray@4.4.0:
|
||||
resolution: {integrity: sha512-aVx8ztPv7/2ULbArGJ2Y42bG1mEQ5mGjpdvrbJcJFU3TbYybe+QlLS4pst9zV52ymy2in1KpFPiZnAOATxD4+Q==}
|
||||
|
||||
lodash.debounce@4.0.8:
|
||||
resolution: {integrity: sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==}
|
||||
|
||||
@@ -2662,9 +2673,15 @@ packages:
|
||||
lodash.isarguments@3.1.0:
|
||||
resolution: {integrity: sha512-chi4NHZlZqZD18a0imDHnZPrDeBbTtVN7GXMwuGdRH9qotxAjYs3aVLKc7zNOG9eddR5Ksd8rvFEBc9SsggPpg==}
|
||||
|
||||
lodash.isplainobject@4.0.6:
|
||||
resolution: {integrity: sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==}
|
||||
|
||||
lodash.memoize@4.1.2:
|
||||
resolution: {integrity: sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==}
|
||||
|
||||
lodash.merge@4.6.2:
|
||||
resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==}
|
||||
|
||||
lodash.uniq@4.5.0:
|
||||
resolution: {integrity: sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==}
|
||||
|
||||
@@ -3447,6 +3464,10 @@ packages:
|
||||
peerDependencies:
|
||||
postcss: ^8.4.32
|
||||
|
||||
postcss-selector-parser@6.0.10:
|
||||
resolution: {integrity: sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w==}
|
||||
engines: {node: '>=4'}
|
||||
|
||||
postcss-selector-parser@6.1.2:
|
||||
resolution: {integrity: sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==}
|
||||
engines: {node: '>=4'}
|
||||
@@ -5709,6 +5730,14 @@ snapshots:
|
||||
|
||||
'@speed-highlight/core@1.2.7': {}
|
||||
|
||||
'@tailwindcss/typography@0.5.16(tailwindcss@3.4.17)':
|
||||
dependencies:
|
||||
lodash.castarray: 4.4.0
|
||||
lodash.isplainobject: 4.0.6
|
||||
lodash.merge: 4.6.2
|
||||
postcss-selector-parser: 6.0.10
|
||||
tailwindcss: 3.4.17
|
||||
|
||||
'@tybys/wasm-util@0.10.0':
|
||||
dependencies:
|
||||
tslib: 2.8.1
|
||||
@@ -7488,14 +7517,20 @@ snapshots:
|
||||
|
||||
lodash-es@4.17.21: {}
|
||||
|
||||
lodash.castarray@4.4.0: {}
|
||||
|
||||
lodash.debounce@4.0.8: {}
|
||||
|
||||
lodash.defaults@4.2.0: {}
|
||||
|
||||
lodash.isarguments@3.1.0: {}
|
||||
|
||||
lodash.isplainobject@4.0.6: {}
|
||||
|
||||
lodash.memoize@4.1.2: {}
|
||||
|
||||
lodash.merge@4.6.2: {}
|
||||
|
||||
lodash.uniq@4.5.0: {}
|
||||
|
||||
lodash@4.17.21: {}
|
||||
@@ -8610,6 +8645,11 @@ snapshots:
|
||||
postcss: 8.5.6
|
||||
postcss-value-parser: 4.2.0
|
||||
|
||||
postcss-selector-parser@6.0.10:
|
||||
dependencies:
|
||||
cssesc: 3.0.0
|
||||
util-deprecate: 1.0.2
|
||||
|
||||
postcss-selector-parser@6.1.2:
|
||||
dependencies:
|
||||
cssesc: 3.0.0
|
||||
|
BIN
public/avatar.jpg
Normal file
BIN
public/avatar.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 178 KiB |
22
tailwind.config.js
Normal file
22
tailwind.config.js
Normal file
@@ -0,0 +1,22 @@
|
||||
/** @type {import('tailwindcss').Config} */
|
||||
export default {
|
||||
theme: {
|
||||
extend: {
|
||||
typography: {
|
||||
DEFAULT: {
|
||||
css: {
|
||||
'code::before': {
|
||||
content: '""'
|
||||
},
|
||||
'code::after': {
|
||||
content: '""'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
plugins: [
|
||||
require('@tailwindcss/typography')
|
||||
]
|
||||
}
|
Reference in New Issue
Block a user