增开滚动条样式,搜索内容,修复代码块解析html,表情周围有空格才会解析
This commit is contained in:
parent
e356212737
commit
a1a4d74493
108
astro.config.mjs
108
astro.config.mjs
@ -1,35 +1,35 @@
|
|||||||
// @ts-check
|
// @ts-check
|
||||||
import { defineConfig } from 'astro/config';
|
import { defineConfig } from "astro/config";
|
||||||
|
|
||||||
import tailwindcss from '@tailwindcss/vite';
|
import tailwindcss from "@tailwindcss/vite";
|
||||||
import mdx from '@astrojs/mdx';
|
import mdx from "@astrojs/mdx";
|
||||||
import react from '@astrojs/react';
|
import react from "@astrojs/react";
|
||||||
import remarkEmoji from 'remark-emoji';
|
import remarkEmoji from "remark-emoji";
|
||||||
import rehypeExternalLinks from 'rehype-external-links';
|
import rehypeExternalLinks from "rehype-external-links";
|
||||||
import sitemap from '@astrojs/sitemap';
|
import sitemap from "@astrojs/sitemap";
|
||||||
import fs from 'node:fs';
|
import fs from "node:fs";
|
||||||
import path from 'node:path';
|
import path from "node:path";
|
||||||
import { SITE_URL } from './src/consts';
|
import { SITE_URL } from "./src/consts";
|
||||||
|
|
||||||
import vercel from '@astrojs/vercel';
|
import vercel from "@astrojs/vercel";
|
||||||
|
|
||||||
function getArticleDate(articleId) {
|
function getArticleDate(articleId) {
|
||||||
try {
|
try {
|
||||||
// 处理多级目录的文章路径
|
// 处理多级目录的文章路径
|
||||||
const mdPath = path.join(process.cwd(), 'src/content', articleId + '.md');
|
const mdPath = path.join(process.cwd(), "src/content", articleId + ".md");
|
||||||
const mdxPath = path.join(process.cwd(), 'src/content', articleId + '.mdx');
|
const mdxPath = path.join(process.cwd(), "src/content", articleId + ".mdx");
|
||||||
|
|
||||||
let filePath = fs.existsSync(mdPath) ? mdPath : mdxPath;
|
let filePath = fs.existsSync(mdPath) ? mdPath : mdxPath;
|
||||||
|
|
||||||
if (fs.existsSync(filePath)) {
|
if (fs.existsSync(filePath)) {
|
||||||
const content = fs.readFileSync(filePath, 'utf-8');
|
const content = fs.readFileSync(filePath, "utf-8");
|
||||||
const match = content.match(/date:\s*(\d{4}-\d{2}-\d{2})/);
|
const match = content.match(/date:\s*(\d{4}-\d{2}-\d{2})/);
|
||||||
if (match) {
|
if (match) {
|
||||||
return new Date(match[1]).toISOString();
|
return new Date(match[1]).toISOString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error reading article date:', error);
|
console.error("Error reading article date:", error);
|
||||||
}
|
}
|
||||||
return new Date().toISOString(); // 如果没有日期,返回当前时间
|
return new Date().toISOString(); // 如果没有日期,返回当前时间
|
||||||
}
|
}
|
||||||
@ -37,11 +37,11 @@ function getArticleDate(articleId) {
|
|||||||
// https://astro.build/config
|
// https://astro.build/config
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
site: SITE_URL,
|
site: SITE_URL,
|
||||||
output: 'static',
|
output: "static",
|
||||||
trailingSlash: 'ignore',
|
trailingSlash: "ignore",
|
||||||
|
|
||||||
build: {
|
build: {
|
||||||
format: 'directory'
|
format: "directory",
|
||||||
},
|
},
|
||||||
|
|
||||||
vite: {
|
vite: {
|
||||||
@ -52,54 +52,59 @@ export default defineConfig({
|
|||||||
// 手动分块配置
|
// 手动分块配置
|
||||||
manualChunks: {
|
manualChunks: {
|
||||||
// 将地图组件单独打包
|
// 将地图组件单独打包
|
||||||
'world-heatmap': ['./src/components/WorldHeatmap.tsx'],
|
"world-heatmap": ["./src/components/WorldHeatmap.tsx"],
|
||||||
// 将 React 相关库单独打包
|
// 将 React 相关库单独打包
|
||||||
'react-vendor': ['react', 'react-dom'],
|
"react-vendor": ["react", "react-dom"],
|
||||||
// 其他大型依赖也可以单独打包
|
// 其他大型依赖也可以单独打包
|
||||||
'chart-vendor': ['chart.js'],
|
"chart-vendor": ["chart.js"],
|
||||||
// 将 ECharts 单独打包
|
// 将 ECharts 单独打包
|
||||||
'echarts-vendor': ['echarts'],
|
"echarts-vendor": ["echarts"],
|
||||||
// 将其他组件打包到一起
|
// 将其他组件打包到一起
|
||||||
'components': ['./src/components']
|
components: ["./src/components"],
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
// 提高警告阈值,避免不必要的警告
|
// 提高警告阈值,避免不必要的警告
|
||||||
chunkSizeWarningLimit: 1000
|
chunkSizeWarningLimit: 1000,
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
integrations: [
|
integrations: [
|
||||||
|
// MDX 集成配置
|
||||||
mdx({
|
mdx({
|
||||||
syntaxHighlight: 'prism',
|
// 不使用共享的 markdown 配置
|
||||||
|
extendMarkdownConfig: false,
|
||||||
|
// 为 MDX 单独配置所需功能
|
||||||
remarkPlugins: [
|
remarkPlugins: [
|
||||||
[remarkEmoji, { emoticon: true }]
|
// 添加表情符号支持
|
||||||
|
[remarkEmoji, { emoticon: true, padded: true }]
|
||||||
],
|
],
|
||||||
rehypePlugins: [
|
rehypePlugins: [
|
||||||
[rehypeExternalLinks, { target: '_blank', rel: ['nofollow', 'noopener', 'noreferrer'] }]
|
[rehypeExternalLinks, { target: '_blank', rel: ['nofollow', 'noopener', 'noreferrer'] }]
|
||||||
],
|
],
|
||||||
gfm: true,
|
// 设置代码块处理行为
|
||||||
shikiConfig: {
|
remarkRehype: {
|
||||||
theme: 'github-dark',
|
allowDangerousHtml: false // 不解析 HTML
|
||||||
langs: [],
|
},
|
||||||
wrap: true,
|
gfm: true
|
||||||
}
|
|
||||||
}),
|
}),
|
||||||
react(),
|
react(),
|
||||||
sitemap({
|
sitemap({
|
||||||
filter: (page) => !page.includes('/api/'),
|
filter: (page) => !page.includes("/api/"),
|
||||||
serialize(item) {
|
serialize(item) {
|
||||||
if (!item) return undefined;
|
if (!item) return undefined;
|
||||||
|
|
||||||
// 文章页面
|
// 文章页面
|
||||||
if (item.url.includes('/articles/')) {
|
if (item.url.includes("/articles/")) {
|
||||||
// 从 URL 中提取文章 ID
|
// 从 URL 中提取文章 ID
|
||||||
const articleId = item.url.replace(SITE_URL + '/articles/', '').replace(/\/$/, '');
|
const articleId = item.url
|
||||||
|
.replace(SITE_URL + "/articles/", "")
|
||||||
|
.replace(/\/$/, "");
|
||||||
const publishDate = getArticleDate(articleId);
|
const publishDate = getArticleDate(articleId);
|
||||||
return {
|
return {
|
||||||
...item,
|
...item,
|
||||||
priority: 0.8,
|
priority: 0.8,
|
||||||
lastmod: publishDate
|
lastmod: publishDate,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
// 其他页面
|
// 其他页面
|
||||||
@ -107,39 +112,46 @@ export default defineConfig({
|
|||||||
let priority = 0.7; // 默认优先级
|
let priority = 0.7; // 默认优先级
|
||||||
|
|
||||||
// 首页最高优先级
|
// 首页最高优先级
|
||||||
if (item.url === SITE_URL + '/') {
|
if (item.url === SITE_URL + "/") {
|
||||||
priority = 1.0;
|
priority = 1.0;
|
||||||
}
|
}
|
||||||
// 文章列表页次高优先级
|
// 文章列表页次高优先级
|
||||||
else if (item.url === SITE_URL + '/articles/') {
|
else if (item.url === SITE_URL + "/articles/") {
|
||||||
priority = 0.9;
|
priority = 0.9;
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...item,
|
...item,
|
||||||
priority
|
priority,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
})
|
}),
|
||||||
],
|
],
|
||||||
|
|
||||||
// Markdown 配置
|
// Markdown 配置
|
||||||
markdown: {
|
markdown: {
|
||||||
syntaxHighlight: 'prism',
|
syntaxHighlight: 'prism',
|
||||||
remarkPlugins: [
|
remarkPlugins: [
|
||||||
[remarkEmoji, { emoticon: true }]
|
[remarkEmoji, { emoticon: true, padded: true }]
|
||||||
],
|
],
|
||||||
rehypePlugins: [
|
rehypePlugins: [
|
||||||
[rehypeExternalLinks, { target: '_blank', rel: ['nofollow', 'noopener', 'noreferrer'] }]
|
[rehypeExternalLinks, { target: '_blank', rel: ['nofollow', 'noopener', 'noreferrer'] }]
|
||||||
],
|
],
|
||||||
gfm: true,
|
gfm: true,
|
||||||
|
// 设置 remark-rehype 选项,以控制HTML处理
|
||||||
|
remarkRehype: {
|
||||||
|
// 保留原始HTML格式,但仅在非代码块区域
|
||||||
|
allowDangerousHtml: true,
|
||||||
|
// 确保代码块内容不被解析
|
||||||
|
passThrough: ['code']
|
||||||
|
},
|
||||||
shikiConfig: {
|
shikiConfig: {
|
||||||
theme: 'github-dark',
|
theme: "github-dark",
|
||||||
langs: [],
|
langs: [],
|
||||||
wrap: true,
|
wrap: true,
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
adapter: vercel()
|
adapter: vercel(),
|
||||||
});
|
});
|
@ -43,7 +43,7 @@ const currentYear = new Date().getFullYear();
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="text-sm text-gray-500 dark:text-gray-500 font-light flex items-center gap-2">
|
<div class="text-sm text-gray-500 dark:text-gray-500 font-light flex items-center gap-2">
|
||||||
<span>© {currentYear} New Echoes. All rights reserved.</span>
|
<a href="https://blog.lsy22.com" class="hover:text-primary-600 dark:hover:text-primary-400 transition-colors">© {currentYear} New Echoes. All rights reserved.</a>
|
||||||
<span>·</span>
|
<span>·</span>
|
||||||
<a
|
<a
|
||||||
href="/sitemap-index.xml"
|
href="/sitemap-index.xml"
|
||||||
|
@ -303,6 +303,7 @@ const normalizedPath = currentPath.endsWith('/') ? currentPath.slice(0, -1) : cu
|
|||||||
summary?: string;
|
summary?: string;
|
||||||
tags?: string[];
|
tags?: string[];
|
||||||
image?: string;
|
image?: string;
|
||||||
|
content?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
let articles: Article[] = [];
|
let articles: Article[] = [];
|
||||||
@ -320,6 +321,17 @@ const normalizedPath = currentPath.endsWith('/') ? currentPath.slice(0, -1) : cu
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 高亮文本中的匹配部分
|
||||||
|
function highlightText(text: string, query: string): string {
|
||||||
|
if (!text || !query.trim()) return text;
|
||||||
|
|
||||||
|
// 转义正则表达式中的特殊字符
|
||||||
|
const escapedQuery = query.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
||||||
|
const regex = new RegExp(`(${escapedQuery})`, 'gi');
|
||||||
|
|
||||||
|
return text.replace(regex, '<mark class="bg-yellow-100 dark:bg-yellow-900/30 text-gray-900 dark:text-gray-100 px-0.5 rounded">$1</mark>');
|
||||||
|
}
|
||||||
|
|
||||||
// 搜索文章
|
// 搜索文章
|
||||||
function searchArticles(query: string, resultsList: HTMLElement, resultsMessage: HTMLElement) {
|
function searchArticles(query: string, resultsList: HTMLElement, resultsMessage: HTMLElement) {
|
||||||
if (!query.trim()) {
|
if (!query.trim()) {
|
||||||
@ -339,16 +351,18 @@ const normalizedPath = currentPath.endsWith('/') ? currentPath.slice(0, -1) : cu
|
|||||||
|
|
||||||
// 过滤并排序结果
|
// 过滤并排序结果
|
||||||
const filteredArticles = articles
|
const filteredArticles = articles
|
||||||
.filter(article => {
|
.filter((article: Article) => {
|
||||||
const title = article.title.toLowerCase();
|
const title = article.title.toLowerCase();
|
||||||
const tags = article.tags ? article.tags.map(tag => tag.toLowerCase()) : [];
|
const tags = article.tags ? article.tags.map((tag: string) => tag.toLowerCase()) : [];
|
||||||
const summary = article.summary ? article.summary.toLowerCase() : '';
|
const summary = article.summary ? article.summary.toLowerCase() : '';
|
||||||
|
const content = article.content ? article.content.toLowerCase() : '';
|
||||||
|
|
||||||
return title.includes(lowerQuery) ||
|
return title.includes(lowerQuery) ||
|
||||||
tags.some(tag => tag.includes(lowerQuery)) ||
|
tags.some((tag: string) => tag.includes(lowerQuery)) ||
|
||||||
summary.includes(lowerQuery);
|
summary.includes(lowerQuery) ||
|
||||||
|
content.includes(lowerQuery);
|
||||||
})
|
})
|
||||||
.sort((a, b) => {
|
.sort((a: Article, b: Article) => {
|
||||||
// 标题匹配优先
|
// 标题匹配优先
|
||||||
const aTitle = a.title.toLowerCase();
|
const aTitle = a.title.toLowerCase();
|
||||||
const bTitle = b.title.toLowerCase();
|
const bTitle = b.title.toLowerCase();
|
||||||
@ -360,6 +374,17 @@ const normalizedPath = currentPath.endsWith('/') ? currentPath.slice(0, -1) : cu
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 内容匹配次之
|
||||||
|
const aContent = a.content ? a.content.toLowerCase() : '';
|
||||||
|
const bContent = b.content ? b.content.toLowerCase() : '';
|
||||||
|
|
||||||
|
if (aContent.includes(lowerQuery) && !bContent.includes(lowerQuery)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (!aContent.includes(lowerQuery) && bContent.includes(lowerQuery)) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
// 日期排序
|
// 日期排序
|
||||||
return new Date(b.date).getTime() - new Date(a.date).getTime();
|
return new Date(b.date).getTime() - new Date(a.date).getTime();
|
||||||
})
|
})
|
||||||
@ -374,14 +399,43 @@ const normalizedPath = currentPath.endsWith('/') ? currentPath.slice(0, -1) : cu
|
|||||||
|
|
||||||
// 显示结果
|
// 显示结果
|
||||||
resultsMessage.style.display = 'none';
|
resultsMessage.style.display = 'none';
|
||||||
resultsList.innerHTML = filteredArticles.map(article => `
|
resultsList.innerHTML = filteredArticles.map((article: Article) => {
|
||||||
|
// 生成匹配的内容片段
|
||||||
|
let contentMatch = '';
|
||||||
|
if (article.content && article.content.toLowerCase().includes(lowerQuery)) {
|
||||||
|
// 找到匹配文本在内容中的位置
|
||||||
|
const matchIndex = article.content.toLowerCase().indexOf(lowerQuery);
|
||||||
|
// 计算片段的起始和结束位置
|
||||||
|
const startPos = Math.max(0, matchIndex - 50);
|
||||||
|
const endPos = Math.min(article.content.length, matchIndex + 100);
|
||||||
|
// 提取片段
|
||||||
|
let snippet = article.content.substring(startPos, endPos);
|
||||||
|
// 如果不是从文章开头开始,添加省略号
|
||||||
|
if (startPos > 0) {
|
||||||
|
snippet = '...' + snippet;
|
||||||
|
}
|
||||||
|
// 如果不是到文章结尾,添加省略号
|
||||||
|
if (endPos < article.content.length) {
|
||||||
|
snippet = snippet + '...';
|
||||||
|
}
|
||||||
|
// 高亮匹配的文本
|
||||||
|
snippet = highlightText(snippet, query);
|
||||||
|
contentMatch = `<p class="text-xs text-gray-500 dark:text-gray-400 mt-1 line-clamp-2">${snippet}</p>`;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 高亮标题和摘要中的匹配文本
|
||||||
|
const highlightedTitle = highlightText(article.title, query);
|
||||||
|
const highlightedSummary = article.summary ? highlightText(article.summary, query) : '';
|
||||||
|
|
||||||
|
return `
|
||||||
<li>
|
<li>
|
||||||
<a href="/articles/${article.id}" class="block px-4 py-3 hover:bg-gray-50/70 dark:hover:bg-gray-700/70 transition-colors duration-200">
|
<a href="/articles/${article.id}" class="block px-4 py-3 hover:bg-gray-100 dark:hover:bg-gray-700/70 transition-colors duration-200">
|
||||||
<h3 class="text-sm font-medium text-gray-800 dark:text-gray-200 truncate">${article.title}</h3>
|
<h3 class="text-sm font-medium text-gray-800 dark:text-gray-200 truncate">${highlightedTitle}</h3>
|
||||||
${article.summary ? `<p class="text-xs text-gray-500 dark:text-gray-400 mt-1 truncate">${article.summary}</p>` : ''}
|
${article.summary ? `<p class="text-xs text-gray-500 dark:text-gray-400 mt-1 truncate">${highlightedSummary}</p>` : ''}
|
||||||
|
${contentMatch}
|
||||||
${article.tags && article.tags.length > 0 ? `
|
${article.tags && article.tags.length > 0 ? `
|
||||||
<div class="flex flex-wrap gap-1 mt-1.5">
|
<div class="flex flex-wrap gap-1 mt-1.5">
|
||||||
${article.tags.slice(0, 3).map(tag => `
|
${article.tags.slice(0, 3).map((tag: string) => `
|
||||||
<span class="inline-block text-xs bg-primary-50/50 dark:bg-primary-900/20 text-primary-600 dark:text-primary-400 py-0.5 px-1.5 rounded-full">#${tag}</span>
|
<span class="inline-block text-xs bg-primary-50/50 dark:bg-primary-900/20 text-primary-600 dark:text-primary-400 py-0.5 px-1.5 rounded-full">#${tag}</span>
|
||||||
`).join('')}
|
`).join('')}
|
||||||
${article.tags.length > 3 ? `<span class="text-xs text-gray-400 dark:text-gray-500">+${article.tags.length - 3}</span>` : ''}
|
${article.tags.length > 3 ? `<span class="text-xs text-gray-400 dark:text-gray-500">+${article.tags.length - 3}</span>` : ''}
|
||||||
@ -389,7 +443,7 @@ const normalizedPath = currentPath.endsWith('/') ? currentPath.slice(0, -1) : cu
|
|||||||
` : ''}
|
` : ''}
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
`).join('');
|
`}).join('');
|
||||||
}
|
}
|
||||||
|
|
||||||
// 节流搜索
|
// 节流搜索
|
||||||
|
@ -201,6 +201,20 @@ function greet(user: User): string {
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
### 1.9 表情符号
|
||||||
|
|
||||||
|
|
||||||
|
| 表情名称 | 语法 | 效果 |
|
||||||
|
|:--------|:-----|:-----|
|
||||||
|
| 笑脸 | `:smile:` | :smile: |
|
||||||
|
| 大笑 | `:laughing:` | :laughing: |
|
||||||
|
| 哭泣 | `:cry:` | :cry: |
|
||||||
|
| 心形 | `:heart:` | :heart: |
|
||||||
|
| 火箭 | `:rocket:` | :rocket: |
|
||||||
|
| 星星 | `:star:` | :star: |
|
||||||
|
| 警告 | `:warning:` | :warning: |
|
||||||
|
| 检查标记 | `:white_check_mark:` | :white_check_mark: |
|
||||||
|
|
||||||
## 2. HTML/JSX 语法部分
|
## 2. HTML/JSX 语法部分
|
||||||
|
|
||||||
### 2.1 HTML 标签
|
### 2.1 HTML 标签
|
||||||
@ -241,50 +255,3 @@ function greet(user: User): string {
|
|||||||
|
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
### 2.2 React 组件使用
|
|
||||||
|
|
||||||
```mdx
|
|
||||||
import { Button } from './Button'
|
|
||||||
|
|
||||||
<Button variant="primary">
|
|
||||||
点击我
|
|
||||||
</Button>
|
|
||||||
```
|
|
||||||
|
|
||||||
### 2.3 导出和使用变量
|
|
||||||
|
|
||||||
```mdx
|
|
||||||
export const myVariable = "Hello MDX!"
|
|
||||||
|
|
||||||
# {myVariable}
|
|
||||||
```
|
|
||||||
|
|
||||||
### 2.4 使用 JavaScript 表达式
|
|
||||||
|
|
||||||
```mdx
|
|
||||||
{new Date().getFullYear()}
|
|
||||||
|
|
||||||
{['React', 'Vue', 'Angular'].map(framework => (
|
|
||||||
<li key={framework}>{framework}</li>
|
|
||||||
))}
|
|
||||||
```
|
|
||||||
|
|
||||||
### 2.5 组件属性传递
|
|
||||||
|
|
||||||
```mdx
|
|
||||||
<Card
|
|
||||||
title="我的卡片"
|
|
||||||
description="这是一个示例卡片"
|
|
||||||
image="path/to/image.jpg"
|
|
||||||
>
|
|
||||||
这里是卡片内容
|
|
||||||
</Card>
|
|
||||||
```
|
|
||||||
|
|
||||||
### 2.6 导入其他 MDX 文件
|
|
||||||
|
|
||||||
```mdx
|
|
||||||
import OtherContent from './other-content.mdx'
|
|
||||||
|
|
||||||
<OtherContent />
|
|
||||||
```
|
|
@ -8,14 +8,28 @@ export async function GET() {
|
|||||||
// 过滤掉草稿文章,并转换为简化的数据结构
|
// 过滤掉草稿文章,并转换为简化的数据结构
|
||||||
const formattedArticles = articles
|
const formattedArticles = articles
|
||||||
.filter(article => !article.data.draft) // 过滤掉草稿
|
.filter(article => !article.data.draft) // 过滤掉草稿
|
||||||
.map(article => ({
|
.map(article => {
|
||||||
|
// 提取文章内容,去除 Markdown 标记
|
||||||
|
let contentText = '';
|
||||||
|
if (article.body) {
|
||||||
|
contentText = article.body
|
||||||
|
.replace(/---[\s\S]*?---/, '') // 移除 frontmatter
|
||||||
|
.replace(/\[([^\]]+)\]\([^)]+\)/g, '$1') // 将链接转换为纯文本
|
||||||
|
.replace(/[#*`~>]/g, '') // 移除特殊字符
|
||||||
|
.replace(/\n+/g, ' ') // 将换行转换为空格
|
||||||
|
.trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
id: article.id,
|
id: article.id,
|
||||||
title: article.data.title,
|
title: article.data.title,
|
||||||
date: article.data.date,
|
date: article.data.date,
|
||||||
summary: article.data.summary || '',
|
summary: article.data.summary || '',
|
||||||
tags: article.data.tags || [],
|
tags: article.data.tags || [],
|
||||||
image: article.data.image || ''
|
image: article.data.image || '',
|
||||||
}))
|
content: contentText // 添加文章内容
|
||||||
|
};
|
||||||
|
})
|
||||||
.sort((a, b) => new Date(b.date).getTime() - new Date(a.date).getTime()); // 按日期排序
|
.sort((a, b) => new Date(b.date).getTime() - new Date(a.date).getTime()); // 按日期排序
|
||||||
|
|
||||||
return new Response(JSON.stringify(formattedArticles), {
|
return new Response(JSON.stringify(formattedArticles), {
|
||||||
|
@ -659,6 +659,25 @@
|
|||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 添加 details 内部内容的内边距 */
|
||||||
|
.prose details > *:not(summary) {
|
||||||
|
padding: 1.5em;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.prose details > p,
|
||||||
|
.prose details > ul,
|
||||||
|
.prose details > ol,
|
||||||
|
.prose details > div,
|
||||||
|
.prose details > pre {
|
||||||
|
margin-top: 0;
|
||||||
|
margin-bottom: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.prose details > *:last-child {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
.prose details summary {
|
.prose details summary {
|
||||||
padding: 1em;
|
padding: 1em;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
@ -41,6 +41,14 @@
|
|||||||
--color-dark-border: #475569;
|
--color-dark-border: #475569;
|
||||||
--color-dark-text: #e2e8f0;
|
--color-dark-text: #e2e8f0;
|
||||||
--color-dark-text-secondary: #94a3b8;
|
--color-dark-text-secondary: #94a3b8;
|
||||||
|
|
||||||
|
/* 滚动条颜色变量 */
|
||||||
|
--scrollbar-track: #f1f5f9;
|
||||||
|
--scrollbar-thumb: #94a3b8;
|
||||||
|
--scrollbar-thumb-hover: #64748b;
|
||||||
|
--scrollbar-dark-track: #1e293b;
|
||||||
|
--scrollbar-dark-thumb: #475569;
|
||||||
|
--scrollbar-dark-thumb-hover: #64748b;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 深色模式样式 */
|
/* 深色模式样式 */
|
||||||
@ -54,3 +62,62 @@
|
|||||||
background-color: var(--bg-primary);
|
background-color: var(--bg-primary);
|
||||||
color: var(--text-primary);
|
color: var(--text-primary);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 自定义滚动条样式 - 适用于所有浏览器 */
|
||||||
|
/* 滚动条基础样式 */
|
||||||
|
::-webkit-scrollbar {
|
||||||
|
width: 10px;
|
||||||
|
height: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 滚动条轨道 */
|
||||||
|
::-webkit-scrollbar-track {
|
||||||
|
background: var(--scrollbar-track);
|
||||||
|
border-radius: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 滚动条滑块 */
|
||||||
|
::-webkit-scrollbar-thumb {
|
||||||
|
background: var(--scrollbar-thumb);
|
||||||
|
border-radius: 8px;
|
||||||
|
border: 2px solid var(--scrollbar-track);
|
||||||
|
transition: background-color 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 滚动条滑块悬停 */
|
||||||
|
::-webkit-scrollbar-thumb:hover {
|
||||||
|
background: var(--scrollbar-thumb-hover);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 滚动条角落 */
|
||||||
|
::-webkit-scrollbar-corner {
|
||||||
|
background: var(--scrollbar-track);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 深色模式滚动条样式 */
|
||||||
|
[data-theme='dark'] ::-webkit-scrollbar-track {
|
||||||
|
background: var(--scrollbar-dark-track);
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-theme='dark'] ::-webkit-scrollbar-thumb {
|
||||||
|
background: var(--scrollbar-dark-thumb);
|
||||||
|
border: 2px solid var(--scrollbar-dark-track);
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-theme='dark'] ::-webkit-scrollbar-thumb:hover {
|
||||||
|
background: var(--scrollbar-dark-thumb-hover);
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-theme='dark'] ::-webkit-scrollbar-corner {
|
||||||
|
background: var(--scrollbar-dark-track);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Firefox 滚动条样式 */
|
||||||
|
* {
|
||||||
|
scrollbar-width: thin;
|
||||||
|
scrollbar-color: var(--scrollbar-thumb) var(--scrollbar-track);
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-theme='dark'] * {
|
||||||
|
scrollbar-color: var(--scrollbar-dark-thumb) var(--scrollbar-dark-track);
|
||||||
|
}
|
@ -135,5 +135,3 @@ pre[class*="language-"] {
|
|||||||
[data-theme="dark"] pre[class*="language-"] {
|
[data-theme="dark"] pre[class*="language-"] {
|
||||||
background: #282c34 !important;
|
background: #282c34 !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 添加其他token的暗色模式样式... */
|
|
Loading…
Reference in New Issue
Block a user