优化搜索逻辑,代码和表格样式

This commit is contained in:
lsy 2025-05-08 09:46:43 +08:00
parent e859a1294e
commit 851c3ef386
7 changed files with 165 additions and 74 deletions

View File

@ -15,6 +15,7 @@ import compressor from "astro-compressor";
import vercel from "@astrojs/vercel"; import vercel from "@astrojs/vercel";
import { articleIndexerIntegration } from "./src/plugins/build-article-index.js"; import { articleIndexerIntegration } from "./src/plugins/build-article-index.js";
import { rehypeCodeBlocks } from "./src/plugins/rehype-code-blocks.js"; import { rehypeCodeBlocks } from "./src/plugins/rehype-code-blocks.js";
import { rehypeTables } from "./src/plugins/rehype-tables.js";
function getArticleDate(articleId) { function getArticleDate(articleId) {
try { try {
@ -129,7 +130,8 @@ export default defineConfig({
], ],
rehypePlugins: [ rehypePlugins: [
[rehypeExternalLinks, { target: '_blank', rel: ['nofollow', 'noopener', 'noreferrer'] }], [rehypeExternalLinks, { target: '_blank', rel: ['nofollow', 'noopener', 'noreferrer'] }],
rehypeCodeBlocks rehypeCodeBlocks,
rehypeTables
], ],
gfm: true, gfm: true,
}, },

View File

@ -507,9 +507,48 @@ const Search: React.FC<SearchProps> = ({
} }
} }
// 回车键直接执行搜索 // 回车键处理逻辑
if (e.key === "Enter") { if (e.key === "Enter") {
e.preventDefault(); e.preventDefault();
// 情况1: 如果有当前选中的内联建议(推荐或纠正)
if (inlineSuggestion.visible && inlineSuggestion.text) {
const suggestionText = inlineSuggestion.text;
// 先检查当前搜索结果中是否有完全匹配的结果
const exactMatchForSuggestion = allItems.find(item =>
item.title.replace(/<\/?mark>/g, '').toLowerCase() === suggestionText.toLowerCase()
);
if (exactMatchForSuggestion) {
// 如果有完全匹配的结果,直接导航
window.location.href = exactMatchForSuggestion.url;
return;
}
// 没有完全匹配,先补全建议并导航到第一个结果
completeInlineSuggestion(true); // 传入true表示需要导航到第一个结果
return;
}
// 情况2: 如果没有内联建议,但有搜索结果
else if (allItems.length > 0 && query.trim()) {
// 尝试找到完全匹配当前查询的结果
const exactMatch = allItems.find(item =>
item.title.replace(/<\/?mark>/g, '').toLowerCase() === query.trim().toLowerCase()
);
if (exactMatch) {
// 找到完全匹配,直接导航到该文章
window.location.href = exactMatch.url;
return;
}
// 如果没有完全匹配,但有搜索结果,进入第一个结果
window.location.href = allItems[0].url;
return;
}
// 如果以上条件都不满足,执行普通搜索
performSearch(query, false); performSearch(query, false);
} }
}; };
@ -561,7 +600,7 @@ const Search: React.FC<SearchProps> = ({
}, [updateCaretPosition]); }, [updateCaretPosition]);
// 执行搜索 // 执行搜索
const performSearch = async (searchQuery: string, isLoadMore: boolean = false) => { const performSearch = async (searchQuery: string, isLoadMore: boolean = false, shouldNavigateToFirstResult: boolean = false) => {
if (!wasmModule || !isIndexLoaded || !indexData || !searchQuery.trim()) { if (!wasmModule || !isIndexLoaded || !indexData || !searchQuery.trim()) {
return; return;
} }
@ -639,6 +678,11 @@ const Search: React.FC<SearchProps> = ({
// 更新加载状态 // 更新加载状态
setLoadingState(prev => ({ ...prev, status: 'success' })); setLoadingState(prev => ({ ...prev, status: 'success' }));
// 如果需要导航到第一个结果,并且有结果
if (shouldNavigateToFirstResult && result.items.length > 0) {
window.location.href = result.items[0].url;
}
} catch (err) { } catch (err) {
// 检查组件是否仍然挂载 // 检查组件是否仍然挂载
if (!isMountedRef.current) return; if (!isMountedRef.current) return;
@ -652,7 +696,7 @@ const Search: React.FC<SearchProps> = ({
}; };
// 自动补全内联建议 - 不使用useCallback避免循环依赖 // 自动补全内联建议 - 不使用useCallback避免循环依赖
const completeInlineSuggestion = () => { const completeInlineSuggestion = (shouldNavigateToFirstResult = false) => {
if (inlineSuggestion.visible && inlineSuggestion.text) { if (inlineSuggestion.visible && inlineSuggestion.text) {
// 保存建议文本 // 保存建议文本
const textToComplete = inlineSuggestion.text; const textToComplete = inlineSuggestion.text;
@ -678,7 +722,7 @@ const Search: React.FC<SearchProps> = ({
setQuery(textToComplete); setQuery(textToComplete);
// 立即执行搜索 // 立即执行搜索
performSearch(textToComplete, false); performSearch(textToComplete, false, shouldNavigateToFirstResult);
// 聚焦输入框并设置光标位置 // 聚焦输入框并设置光标位置
if (searchInputRef.current) { if (searchInputRef.current) {

View File

@ -37,10 +37,10 @@ export const NAV_STRUCTURE = [
] ]
}, },
{ {
id: 'others', id: 'other',
text: '其他', text: '其他',
items: [ items: [
{ id: 'other', text: '其他', href: '/other' }, { id: 'about', text: '关于', href: '/other' },
{ id: 'projects', text: '项目', href: '/projects' } { id: 'projects', text: '项目', href: '/projects' }
] ]
} }

View File

@ -200,6 +200,20 @@ export function rehypeCodeBlocks() {
{ type: 'text', value: ' 复制' } { type: 'text', value: ' 复制' }
]; ];
// 计算代码行数,用于生成行号
const lineCount = originalCode.split('\n').length;
// 生成行号元素
const lineNumberElements = [];
for (let i = 1; i <= lineCount; i++) {
lineNumberElements.push({
type: 'element',
tagName: 'div',
properties: { className: ['line-number'] },
children: [{ type: 'text', value: String(i) }]
});
}
// 创建新的代码块容器结构 // 创建新的代码块容器结构
const codeBlockContainer = { const codeBlockContainer = {
type: 'element', type: 'element',
@ -235,11 +249,24 @@ export function rehypeCodeBlocks() {
} }
] ]
}, },
// 代码内容区域 - 保留原始结构 // 代码内容区域 - 修改结构,将代码内容和行号分离
{ {
type: 'element', type: 'element',
tagName: 'div', tagName: 'div',
properties: { className: ['code-block-content'] }, properties: { className: ['code-block-content'] },
children: [
// 行号容器
{
type: 'element',
tagName: 'div',
properties: { className: ['line-numbers-container'] },
children: lineNumberElements
},
// 代码内容容器
{
type: 'element',
tagName: 'div',
properties: { className: ['code-content-container'] },
children: [ children: [
// 保留原始的 pre 元素及其所有关键属性 // 保留原始的 pre 元素及其所有关键属性
{ {
@ -259,6 +286,8 @@ export function rehypeCodeBlocks() {
] ]
} }
] ]
}
]
}; };
// 替换原始节点 // 替换原始节点

View File

@ -0,0 +1,22 @@
import { visit } from 'unist-util-visit';
export function rehypeTables() {
return (tree) => {
visit(tree, 'element', (node, index, parent) => {
if (node.tagName === 'table') {
// 创建表格容器
const tableContainer = {
type: 'element',
tagName: 'div',
properties: {
className: ['table-container']
},
children: [node]
};
// 替换原始表格节点
parent.children[index] = tableContainer;
}
});
};
}

View File

@ -57,18 +57,51 @@
color: #10b981; color: #10b981;
} }
/* 代码内容容器 - 移除背景 */ /* 代码内容容器 - 修改为 flex 布局 */
.code-block-content { .code-block-content {
position: relative; position: relative;
overflow-x: auto; display: flex;
background-color: transparent; background-color: transparent;
} }
/* 行号容器 - 固定宽度和位置 */
.line-numbers-container {
flex: 0 0 2.5rem;
background-color: #f1f5f9;
border-right: 1px solid #e2e8f0;
z-index: 1;
position: sticky;
left: 0;
display: flex;
flex-direction: column;
align-items: center;
padding: 0.15rem 0;
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
}
/* 行号元素样式 */
.line-number {
width: 100%;
height: 1.4rem;
display: flex;
align-items: center;
justify-content: center;
color: #94a3b8;
font-size: 0.85rem;
user-select: none;
}
/* 代码内容容器 - 允许水平滚动 */
.code-content-container {
flex: 1;
overflow-x: auto;
}
/* 基础代码块样式 - 减小内边距 */ /* 基础代码块样式 - 减小内边距 */
pre { pre {
margin: 0; margin: 0;
padding: 0.15rem 0; padding: 0.15rem 0;
overflow-x: auto; overflow-x: visible; /* 改为 visible滚动由父容器处理 */
} }
pre code { pre code {
@ -85,47 +118,16 @@ pre code {
position: relative; position: relative;
} }
/* 行号背景条 - 减小宽度 */ /* 行样式 - 移除左侧 padding */
.line-numbers::before {
content: "";
position: absolute;
left: 0;
top: 0;
bottom: 0;
width: 2.5rem;
background-color: #f1f5f9;
border-right: 1px solid #e2e8f0;
z-index: 1;
}
/* 行样式 - 进一步减小行间距和缩进 */
.line-numbers .line { .line-numbers .line {
position: relative; position: relative;
counter-increment: line; counter-increment: line;
padding-left: 3rem; padding-left: 0.5rem; /* 减小左侧内边距 */
padding-right: 0.4rem; padding-right: 0.4rem;
min-height: 1.4rem; min-height: 1.4rem;
white-space: pre; white-space: pre;
} }
/* 行号 - 调整位置 */
.line-numbers .line::before {
content: counter(line);
position: absolute;
left: 0;
top: 0;
width: 2.5rem;
height: 100%;
text-align: center;
color: #94a3b8;
font-size: 0.85rem;
user-select: none;
z-index: 2;
display: flex;
align-items: center;
justify-content: center;
}
/* 暗色模式 */ /* 暗色模式 */
[data-theme='dark'] .code-block-container { [data-theme='dark'] .code-block-container {
border-color: #334155; border-color: #334155;
@ -154,17 +156,17 @@ pre code {
background-color: transparent; background-color: transparent;
} }
/* 暗色模式行号样式 */ /* 暗色模式行号容器样式 */
[data-theme='dark'] .line-numbers::before { [data-theme='dark'] .line-numbers-container {
background-color: #1e293b; background-color: #1e293b;
border-right-color: #334155; border-right-color: #334155;
} }
[data-theme='dark'] .line-numbers .line::before { /* 暗色模式行号样式 */
[data-theme='dark'] .line-number {
color: #64748b; color: #64748b;
} }
/* 确保所有代码元素没有背景 */ /* 确保所有代码元素没有背景 */
code, pre, .code-block-content, code, pre, .code-block-content,
.code-block-content pre.shiki, .code-block-content pre.shiki,
@ -201,11 +203,8 @@ pre.shiki, pre.astro-code,
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
font-size: 0.875rem; font-size: 0.875rem;
color: var(--color-primary-700); color: var(--color-primary-700);
background-color: var(--color-primary-50);
padding: 0.2rem 0.4rem;
margin: 0 0.2rem; margin: 0 0.2rem;
border-radius: 0.3rem; border-radius: 0.3rem;
border: 1px solid var(--color-primary-100);
white-space: normal; white-space: normal;
word-wrap: break-word; word-wrap: break-word;
overflow-wrap: break-word; overflow-wrap: break-word;
@ -219,8 +218,6 @@ pre.shiki, pre.astro-code,
/* 行内代码块黑暗模式样式 */ /* 行内代码块黑暗模式样式 */
[data-theme='dark'] :not(pre) > code { [data-theme='dark'] :not(pre) > code {
color: var(--color-primary-300); color: var(--color-primary-300);
background-color: rgba(75, 107, 255, 0.1);
border-color: var(--color-primary-700);
} }
/* 长路径的行内代码块样式特殊处理 */ /* 长路径的行内代码块样式特殊处理 */
@ -239,14 +236,10 @@ pre.shiki, pre.astro-code,
/* 针对文件路径的特殊样式 - 适用于Windows路径 */ /* 针对文件路径的特殊样式 - 适用于Windows路径 */
:not(pre) > code.file-path { :not(pre) > code.file-path {
color: var(--color-gray-700); color: var(--color-gray-700);
background-color: var(--color-gray-100);
border-color: var(--color-gray-200);
} }
/* 针对文件路径的特殊样式 - 黑暗模式 */ /* 针对文件路径的特殊样式 - 黑暗模式 */
[data-theme='dark'] :not(pre) > code.file-path { [data-theme='dark'] :not(pre) > code.file-path {
color: var(--color-gray-300); color: var(--color-gray-300);
background-color: var(--color-gray-800);
border-color: var(--color-gray-700);
} }

View File

@ -1,13 +1,14 @@
/* 表格样式 - 与全局主题配色协调 */ /* 表格样式 - 与全局主题配色协调 */
table { .table-container {
container-type: inline-size;
width: 100%; width: 100%;
margin-bottom: 1.5rem;
border-collapse: separate;
border-spacing: 0;
border-radius: 0.5rem;
overflow-x: auto; overflow-x: auto;
display: block; border-radius: 0.5rem;
max-width: 100%; }
table {
display: table;
width: 100%;
} }
thead { thead {