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

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

View File

@ -507,9 +507,48 @@ const Search: React.FC<SearchProps> = ({
}
}
// 回车键直接执行搜索
// 回车键处理逻辑
if (e.key === "Enter") {
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);
}
};
@ -561,7 +600,7 @@ const Search: React.FC<SearchProps> = ({
}, [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()) {
return;
}
@ -639,6 +678,11 @@ const Search: React.FC<SearchProps> = ({
// 更新加载状态
setLoadingState(prev => ({ ...prev, status: 'success' }));
// 如果需要导航到第一个结果,并且有结果
if (shouldNavigateToFirstResult && result.items.length > 0) {
window.location.href = result.items[0].url;
}
} catch (err) {
// 检查组件是否仍然挂载
if (!isMountedRef.current) return;
@ -652,7 +696,7 @@ const Search: React.FC<SearchProps> = ({
};
// 自动补全内联建议 - 不使用useCallback避免循环依赖
const completeInlineSuggestion = () => {
const completeInlineSuggestion = (shouldNavigateToFirstResult = false) => {
if (inlineSuggestion.visible && inlineSuggestion.text) {
// 保存建议文本
const textToComplete = inlineSuggestion.text;
@ -678,7 +722,7 @@ const Search: React.FC<SearchProps> = ({
setQuery(textToComplete);
// 立即执行搜索
performSearch(textToComplete, false);
performSearch(textToComplete, false, shouldNavigateToFirstResult);
// 聚焦输入框并设置光标位置
if (searchInputRef.current) {

View File

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

View File

@ -200,6 +200,20 @@ export function rehypeCodeBlocks() {
{ 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 = {
type: 'element',
@ -235,25 +249,40 @@ export function rehypeCodeBlocks() {
}
]
},
// 代码内容区域 - 保留原始结构
// 代码内容区域 - 修改结构,将代码内容和行号分离
{
type: 'element',
tagName: 'div',
properties: { className: ['code-block-content'] },
children: [
// 保留原始的 pre 元素及其所有关键属性
// 行号容器
{
type: 'element',
tagName: 'pre',
properties: {
style: nodeStyle,
className: nodeClasses,
// 其他可能的重要属性
'data-theme': node.properties['data-theme']
},
tagName: 'div',
properties: { className: ['line-numbers-container'] },
children: lineNumberElements
},
// 代码内容容器
{
type: 'element',
tagName: 'div',
properties: { className: ['code-content-container'] },
children: [
// 保留原始的code元素不做修改
codeElement
// 保留原始的 pre 元素及其所有关键属性
{
type: 'element',
tagName: 'pre',
properties: {
style: nodeStyle,
className: nodeClasses,
// 其他可能的重要属性
'data-theme': node.properties['data-theme']
},
children: [
// 保留原始的code元素不做修改
codeElement
]
}
]
}
]

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;
}
/* 代码内容容器 - 移除背景 */
/* 代码内容容器 - 修改为 flex 布局 */
.code-block-content {
position: relative;
overflow-x: auto;
display: flex;
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 {
margin: 0;
padding: 0.15rem 0;
overflow-x: auto;
overflow-x: visible; /* 改为 visible滚动由父容器处理 */
}
pre code {
@ -85,47 +118,16 @@ pre code {
position: relative;
}
/* 行号背景条 - 减小宽度 */
.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;
}
/* 行样式 - 进一步减小行间距和缩进 */
/* 行样式 - 移除左侧 padding */
.line-numbers .line {
position: relative;
counter-increment: line;
padding-left: 3rem;
padding-left: 0.5rem; /* 减小左侧内边距 */
padding-right: 0.4rem;
min-height: 1.4rem;
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 {
border-color: #334155;
@ -154,17 +156,17 @@ pre code {
background-color: transparent;
}
/* 暗色模式行号样式 */
[data-theme='dark'] .line-numbers::before {
/* 暗色模式行号容器样式 */
[data-theme='dark'] .line-numbers-container {
background-color: #1e293b;
border-right-color: #334155;
}
[data-theme='dark'] .line-numbers .line::before {
/* 暗色模式行号样式 */
[data-theme='dark'] .line-number {
color: #64748b;
}
/* 确保所有代码元素没有背景 */
code, pre, .code-block-content,
.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-size: 0.875rem;
color: var(--color-primary-700);
background-color: var(--color-primary-50);
padding: 0.2rem 0.4rem;
margin: 0 0.2rem;
border-radius: 0.3rem;
border: 1px solid var(--color-primary-100);
white-space: normal;
word-wrap: break-word;
overflow-wrap: break-word;
@ -219,8 +218,6 @@ pre.shiki, pre.astro-code,
/* 行内代码块黑暗模式样式 */
[data-theme='dark'] :not(pre) > code {
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路径 */
:not(pre) > code.file-path {
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 {
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%;
margin-bottom: 1.5rem;
border-collapse: separate;
border-spacing: 0;
border-radius: 0.5rem;
overflow-x: auto;
display: block;
max-width: 100%;
border-radius: 0.5rem;
}
table {
display: table;
width: 100%;
}
thead {