20260601173222
This commit is contained in:
1 parent
8b08d18010
commit
44dce232f4
5 files changed
+416
-149
No files matched your search
@@ -0,0 +1,66 @@
|
||||
# 书签导入与整理计划
|
||||
|
||||
## 需求分析
|
||||
|
||||
用户希望将浏览器书签文件 `D:\bookmarks_2026_5_26.html` 中的内容导入并整理到 `docs/resources.mdx` 文件中。
|
||||
|
||||
## 书签文件结构分析
|
||||
|
||||
从读取的书签文件中识别出以下主要分组:
|
||||
|
||||
### 第一层分组
|
||||
|
||||
1. **AI 智能助手** - 包含 ChatGPT、腾讯元宝、v0 等
|
||||
2. **前端开发** - 包含多个子文件夹:
|
||||
|
||||
* 图标库 (expo icons, iconfont, icones, lucide)
|
||||
|
||||
* 前端模板库 (uiverse, codepen, htmlrev, lottiefiles, mockuphone)
|
||||
|
||||
* TinyMCE 相关
|
||||
|
||||
* Uniapp 相关
|
||||
|
||||
* 前端组件库 (Arco Design)
|
||||
|
||||
* React Native 第三方库
|
||||
|
||||
* 插画库 (undraw, storyset, manypixels)
|
||||
|
||||
* React Native 开发相关
|
||||
3. **Python** - PaddlePaddle 相关
|
||||
|
||||
## 实现方案
|
||||
|
||||
### 步骤
|
||||
|
||||
1. 创建一个 Node.js 脚本来解析书签 HTML 文件
|
||||
2. 将解析结果转换为资源导航所需的分组格式
|
||||
3. 更新 `docs/resources.mdx` 文件
|
||||
|
||||
### 修改文件
|
||||
|
||||
* `docs/resources.mdx` - 更新为解析后的书签内容
|
||||
|
||||
## 输出格式
|
||||
|
||||
使用现有的 `SearchableLinkGrid` 组件格式,保持分组结构清晰。
|
||||
|
||||
## 过滤规则
|
||||
|
||||
1. 跳过重复链接
|
||||
2. 清理过长的标题(超过50字符截断)
|
||||
3. 提取有意义的描述信息
|
||||
|
||||
## 风险评估
|
||||
|
||||
* 文件较大(50KB+),需要处理大量数据
|
||||
|
||||
* 部分链接可能失效,建议用户后续验证
|
||||
|
||||
## 测试计划
|
||||
|
||||
1. 解析书签文件
|
||||
2. 生成新的 resources.mdx
|
||||
3. 启动开发服务器验证显示效果
|
||||
|
||||
@@ -10,7 +10,7 @@ import SearchableLinkGrid from '@site/src/components/Link/SearchableLinkGrid';
|
||||
<SearchableLinkGrid
|
||||
groups={[
|
||||
{
|
||||
groupName: 'AI 助手',
|
||||
groupName: 'AI助手',
|
||||
items: [
|
||||
{
|
||||
title: 'ChatGPT',
|
||||
@@ -30,33 +30,28 @@ import SearchableLinkGrid from '@site/src/components/Link/SearchableLinkGrid';
|
||||
],
|
||||
},
|
||||
{
|
||||
groupName: '大模型与AI',
|
||||
groupName: '大模型',
|
||||
items: [
|
||||
{
|
||||
title: 'Ollama',
|
||||
description: '本地大模型运行工具',
|
||||
href: 'https://ollama.com/',
|
||||
},
|
||||
{
|
||||
title: 'OpenCompass',
|
||||
description: '大模型评测榜单',
|
||||
href: 'https://rank.opencompass.org.cn/leaderboard-multimodal/',
|
||||
title: 'Qwen',
|
||||
description: '阿里云通义千问',
|
||||
href: 'https://mcp.csdn.net/683559a9606a8318e85a74e7.html',
|
||||
},
|
||||
{
|
||||
title: 'InternVL',
|
||||
description: '多模态大模型',
|
||||
href: 'https://internvl.readthedocs.io/en/latest/internvl3.0/quick_start.html',
|
||||
},
|
||||
{
|
||||
title: 'Qwen',
|
||||
description: '阿里云通义千问',
|
||||
href: 'https://mcp.csdn.net/683559a9606a8318e85a74e7.html',
|
||||
},
|
||||
{
|
||||
title: '腾讯混元',
|
||||
description: '腾讯大模型',
|
||||
href: 'https://github.com/Tencent-Hunyuan/Tencent-Hunyuan-Large',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
groupName: 'AI工具',
|
||||
items: [
|
||||
{
|
||||
title: 'MinerU',
|
||||
description: '文档解析工具',
|
||||
@@ -67,16 +62,36 @@ import SearchableLinkGrid from '@site/src/components/Link/SearchableLinkGrid';
|
||||
description: 'OCR 识别工具',
|
||||
href: 'https://paddlepaddle.github.io/PaddleOCR/latest/version3.x/pipeline_usage/OCR.html',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
groupName: 'AI部署与推理',
|
||||
items: [
|
||||
{
|
||||
title: 'PaddleNLP',
|
||||
description: '自然语言处理框架',
|
||||
href: 'https://paddlenlp.readthedocs.io/zh/latest/advanced_guide/distributed_training.html',
|
||||
title: 'Ollama',
|
||||
description: '本地大模型运行工具',
|
||||
href: 'https://ollama.com/',
|
||||
},
|
||||
{
|
||||
title: 'PaddleServing',
|
||||
description: '模型部署服务',
|
||||
href: 'https://github.com/PaddlePaddle/Serving/blob/v0.9.0/examples/Pipeline/PaddleOCR/ocr/README_CN.md',
|
||||
},
|
||||
{
|
||||
title: 'PaddleNLP',
|
||||
description: '自然语言处理框架',
|
||||
href: 'https://paddlenlp.readthedocs.io/zh/latest/advanced_guide/distributed_training.html',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
groupName: 'AI评测与资源',
|
||||
items: [
|
||||
{
|
||||
title: 'OpenCompass',
|
||||
description: '大模型评测榜单',
|
||||
href: 'https://rank.opencompass.org.cn/leaderboard-multimodal/',
|
||||
},
|
||||
{
|
||||
title: '免费 AI 接口整理',
|
||||
description: '4种免费 AI 接口',
|
||||
@@ -90,18 +105,13 @@ import SearchableLinkGrid from '@site/src/components/Link/SearchableLinkGrid';
|
||||
],
|
||||
},
|
||||
{
|
||||
groupName: '计算机视觉',
|
||||
groupName: '视觉与OCR',
|
||||
items: [
|
||||
{
|
||||
title: 'YOLOv11',
|
||||
description: '目标检测模型',
|
||||
href: 'https://modelers.csdn.net/683fe614606a8318e85b0e13.html',
|
||||
},
|
||||
{
|
||||
title: 'X-AnyLabeling',
|
||||
description: '标注工具',
|
||||
href: 'https://github.com/CVHub520/X-AnyLabeling',
|
||||
},
|
||||
{
|
||||
title: 'GeoLayoutLM',
|
||||
description: '文档智能模型',
|
||||
@@ -117,21 +127,31 @@ import SearchableLinkGrid from '@site/src/components/Link/SearchableLinkGrid';
|
||||
description: '文档布局数据集',
|
||||
href: 'https://opendatalab.com/OpenDataLab/PubLayNet/tree/main',
|
||||
},
|
||||
{
|
||||
title: 'X-AnyLabeling',
|
||||
description: '标注工具',
|
||||
href: 'https://github.com/CVHub520/X-AnyLabeling',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
groupName: '前端开发',
|
||||
items: [
|
||||
{
|
||||
title: 'Tauri',
|
||||
description: '跨平台桌面应用框架',
|
||||
href: 'https://v2.tauri.app/zh-cn/',
|
||||
},
|
||||
{
|
||||
title: 'Arco Design Vue',
|
||||
description: '字节跳动前端组件库',
|
||||
href: 'https://arco.design/vue/docs/start',
|
||||
},
|
||||
{
|
||||
title: 'Tauri',
|
||||
description: '跨平台桌面应用框架',
|
||||
href: 'https://v2.tauri.app/zh-cn/',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
groupName: '移动端开发',
|
||||
items: [
|
||||
{
|
||||
title: 'gluestack-ui',
|
||||
description: 'React Native UI 套件',
|
||||
@@ -180,33 +200,53 @@ import SearchableLinkGrid from '@site/src/components/Link/SearchableLinkGrid';
|
||||
],
|
||||
},
|
||||
{
|
||||
groupName: 'UI 资源',
|
||||
groupName: 'UI资源',
|
||||
items: [
|
||||
{
|
||||
title: 'Expo Vector Icons',
|
||||
description: 'React Native 图标库',
|
||||
href: 'https://icons.expo.fyi/Index',
|
||||
},
|
||||
{
|
||||
title: 'IconFont',
|
||||
description: '阿里巴巴矢量图标库',
|
||||
href: 'https://www.iconfont.cn/',
|
||||
},
|
||||
{
|
||||
title: 'Icônes',
|
||||
description: '开源图标库集合',
|
||||
href: 'https://icones.js.org/collection/all',
|
||||
},
|
||||
{
|
||||
title: 'Lucide',
|
||||
description: '精美的开源图标库',
|
||||
href: 'https://lucide.dev/icons/',
|
||||
},
|
||||
{
|
||||
title: 'Icônes',
|
||||
description: '开源图标库集合',
|
||||
href: 'https://icones.js.org/collection/all',
|
||||
},
|
||||
{
|
||||
title: 'SVG Repo',
|
||||
description: '免费 SVG 矢量图标',
|
||||
href: 'https://www.svgrepo.com/',
|
||||
},
|
||||
{
|
||||
title: 'Expo Vector Icons',
|
||||
description: 'React Native 图标库',
|
||||
href: 'https://icons.expo.fyi/Index',
|
||||
},
|
||||
{
|
||||
title: 'unDraw',
|
||||
description: '开源插画库',
|
||||
href: 'https://undraw.co/',
|
||||
},
|
||||
{
|
||||
title: 'Storyset',
|
||||
description: '可自定义插画',
|
||||
href: 'https://storyset.com/',
|
||||
},
|
||||
{
|
||||
title: 'ManyPixels',
|
||||
description: '免费插画素材',
|
||||
href: 'https://www.manypixels.co/gallery',
|
||||
},
|
||||
{
|
||||
title: 'LottieFiles',
|
||||
description: '动画资源平台',
|
||||
href: 'https://app.lottiefiles.com/search',
|
||||
},
|
||||
{
|
||||
title: 'UIverse',
|
||||
description: 'CSS & Tailwind UI 组件',
|
||||
@@ -222,45 +262,30 @@ import SearchableLinkGrid from '@site/src/components/Link/SearchableLinkGrid';
|
||||
description: '免费 HTML 网站模板',
|
||||
href: 'https://htmlrev.com/',
|
||||
},
|
||||
{
|
||||
title: 'LottieFiles',
|
||||
description: '动画资源平台',
|
||||
href: 'https://app.lottiefiles.com/search',
|
||||
},
|
||||
{
|
||||
title: 'MockUPhone',
|
||||
description: '设备样机展示',
|
||||
href: 'https://mockuphone.com/model/iphone-15/',
|
||||
},
|
||||
{
|
||||
title: 'unDraw',
|
||||
description: '开源插画库',
|
||||
href: 'https://undraw.co/',
|
||||
},
|
||||
{
|
||||
title: 'Storyset',
|
||||
description: '可自定义插画',
|
||||
href: 'https://storyset.com/',
|
||||
},
|
||||
{
|
||||
title: 'ManyPixels',
|
||||
description: '免费插画素材',
|
||||
href: 'https://www.manypixels.co/gallery',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
groupName: '开发工具',
|
||||
groupName: '后端开发',
|
||||
items: [
|
||||
{
|
||||
title: 'NestJS',
|
||||
description: 'Node.js 企业级框架',
|
||||
href: 'https://nest.nodejs.cn/',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
groupName: '开发环境',
|
||||
items: [
|
||||
{
|
||||
title: 'JDK 8',
|
||||
title: 'JDK',
|
||||
description: 'Java 开发工具包',
|
||||
href: 'https://adoptium.net/zh-CN/temurin/releases?version=8',
|
||||
href: 'https://adoptium.net/zh-CN/temurin/releases',
|
||||
},
|
||||
{
|
||||
title: 'Go',
|
||||
@@ -270,42 +295,72 @@ import SearchableLinkGrid from '@site/src/components/Link/SearchableLinkGrid';
|
||||
{
|
||||
title: 'nvm-windows',
|
||||
description: 'Node 版本管理',
|
||||
href: 'https://github.com/coreybutler/nvm-windows/releases',
|
||||
href: 'https://nvm.uihtm.com/doc/download-nvm.html',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
groupName: 'IDE',
|
||||
items: [
|
||||
{
|
||||
title: 'IntelliJ IDEA',
|
||||
description: 'Java IDE',
|
||||
href: 'https://www.jetbrains.com/zh-cn/idea/',
|
||||
},
|
||||
{
|
||||
title: 'URL Encoder',
|
||||
description: 'SVG URL 编码工具',
|
||||
href: 'https://yoksel.github.io/url-encoder/zh-cn/',
|
||||
title: 'GoLand',
|
||||
description: 'Go 语言 IDE',
|
||||
href: 'https://www.jetbrains.com/zh-cn/go/',
|
||||
},
|
||||
{
|
||||
title: 'Dependency Walker',
|
||||
description: '依赖分析工具',
|
||||
href: 'https://www.dependencywalker.com/',
|
||||
title: 'DataGrip',
|
||||
description: '数据库管理工具',
|
||||
href: 'https://www.jetbrains.com/zh-cn/datagrip/',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
groupName: '地图服务',
|
||||
items: [
|
||||
{
|
||||
title: '天地图 API',
|
||||
title: '天地图',
|
||||
description: '地理编码服务',
|
||||
href: 'http://lbs.tianditu.gov.cn/server/geocoding.html',
|
||||
},
|
||||
{
|
||||
title: '天地图示例',
|
||||
description: 'JS API 示例',
|
||||
href: 'http://lbs.tianditu.gov.cn/api/js4.0/examples.html',
|
||||
href: 'http://lbs.tianditu.gov.cn/home.html',
|
||||
},
|
||||
{
|
||||
title: '天地图 UniApp',
|
||||
description: 'UniApp 插件',
|
||||
href: 'https://ext.dcloud.net.cn/plugin?id=22630',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
groupName: '开发资源',
|
||||
items: [
|
||||
{
|
||||
title: 'Ollama 完整教程',
|
||||
description: '本地 LLM 管理',
|
||||
href: 'https://www.cnblogs.com/obullxl/p/18295202',
|
||||
title: '清华镜像源',
|
||||
description: '清华大学开源软件镜像站',
|
||||
href: 'https://mirrors.tuna.tsinghua.edu.cn/',
|
||||
},
|
||||
{
|
||||
title: 'URL Encoder',
|
||||
description: 'SVG URL 编码工具',
|
||||
href: 'https://yoksel.github.io/url-encoder/zh-cn/',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
groupName: '效率工具',
|
||||
groupName: '系统工具',
|
||||
items: [
|
||||
{
|
||||
title: 'VMware Workstation',
|
||||
description: 'VMware Pro 下载',
|
||||
href: 'https://github.com/201853910/VMwareWorkstation',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
groupName: '效率办公',
|
||||
items: [
|
||||
{
|
||||
title: 'DeepL翻译',
|
||||
@@ -330,4 +385,4 @@ import SearchableLinkGrid from '@site/src/components/Link/SearchableLinkGrid';
|
||||
],
|
||||
},
|
||||
]}
|
||||
/>
|
||||
/>
|
||||
@@ -82,7 +82,7 @@ const config: Config = {
|
||||
alt: 'oneao',
|
||||
src: 'img/logo.png',
|
||||
},
|
||||
hideOnScroll: true,
|
||||
hideOnScroll: false,
|
||||
items: [
|
||||
{
|
||||
type: 'docSidebar',
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import React, { useState, useMemo } from 'react'
|
||||
import LinkCard, { LinkCardProps } from './LinkCard'
|
||||
import type { LinkCardProps } from './LinkCard'
|
||||
import React, { useEffect, useMemo, useRef, useState } from 'react'
|
||||
import LinkCard from './LinkCard'
|
||||
import styles from './styles.module.css'
|
||||
|
||||
export interface GroupedLinkCardProps {
|
||||
@@ -13,17 +14,61 @@ interface SearchableLinkGridProps {
|
||||
|
||||
export default function SearchableLinkGrid({ groups }: SearchableLinkGridProps) {
|
||||
const [searchTerm, setSearchTerm] = useState('')
|
||||
const [activeSection, setActiveSection] = useState('')
|
||||
const sidebarRef = useRef<HTMLDivElement>(null)
|
||||
|
||||
useEffect(() => {
|
||||
const navbar = document.querySelector('.navbar')
|
||||
const navbarHeight = navbar ? navbar.offsetHeight : 64
|
||||
const threshold = navbarHeight + 32
|
||||
|
||||
if (sidebarRef.current) {
|
||||
sidebarRef.current.style.top = `${threshold}px`
|
||||
}
|
||||
}, [])
|
||||
|
||||
useEffect(() => {
|
||||
const navbar = document.querySelector('.navbar')
|
||||
const navbarHeight = navbar ? navbar.offsetHeight : 64
|
||||
const threshold = navbarHeight + 20
|
||||
|
||||
const observer = new IntersectionObserver(
|
||||
(entries) => {
|
||||
for (const entry of entries) {
|
||||
if (entry.isIntersecting) {
|
||||
setActiveSection(entry.target.id)
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
rootMargin: `-${threshold}px 0px -80% 0px`,
|
||||
threshold: 0.1,
|
||||
},
|
||||
)
|
||||
|
||||
groups.forEach((_, index) => {
|
||||
const element = document.getElementById(`group-${index}`)
|
||||
if (element) {
|
||||
observer.observe(element)
|
||||
}
|
||||
})
|
||||
|
||||
return () => {
|
||||
observer.disconnect()
|
||||
}
|
||||
}, [groups])
|
||||
|
||||
const filteredGroups = useMemo(() => {
|
||||
if (!searchTerm.trim()) return groups
|
||||
|
||||
if (!searchTerm.trim())
|
||||
return groups
|
||||
|
||||
const lowerTerm = searchTerm.toLowerCase()
|
||||
return groups.map(group => ({
|
||||
...group,
|
||||
items: group.items.filter(
|
||||
item =>
|
||||
item.title.toLowerCase().includes(lowerTerm) ||
|
||||
item.description.toLowerCase().includes(lowerTerm),
|
||||
item.title.toLowerCase().includes(lowerTerm)
|
||||
|| item.description.toLowerCase().includes(lowerTerm),
|
||||
),
|
||||
})).filter(group => group.items.length > 0)
|
||||
}, [searchTerm, groups])
|
||||
@@ -31,68 +76,99 @@ export default function SearchableLinkGrid({ groups }: SearchableLinkGridProps)
|
||||
const totalItems = groups.reduce((sum, group) => sum + group.items.length, 0)
|
||||
const filteredTotalItems = filteredGroups.reduce((sum, group) => sum + group.items.length, 0)
|
||||
|
||||
const scrollToSection = (index: number) => {
|
||||
const element = document.getElementById(`group-${index}`)
|
||||
if (element) {
|
||||
element.scrollIntoView({ behavior: 'smooth', block: 'start' })
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className={styles.searchContainer}>
|
||||
<div className={styles.searchWrapper}>
|
||||
<svg
|
||||
className={styles.searchIcon}
|
||||
width="18"
|
||||
height="18"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
strokeWidth="2"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
>
|
||||
<circle cx="11" cy="11" r="8" />
|
||||
<path d="m21 21-4.35-4.35" />
|
||||
</svg>
|
||||
<input
|
||||
type="text"
|
||||
placeholder="搜索资源..."
|
||||
value={searchTerm}
|
||||
onChange={e => setSearchTerm(e.target.value)}
|
||||
className={styles.searchInput}
|
||||
/>
|
||||
</div>
|
||||
<span className={styles.searchCount}>
|
||||
{filteredTotalItems} / {totalItems} 项
|
||||
</span>
|
||||
</div>
|
||||
|
||||
{filteredGroups.length > 0 ? (
|
||||
filteredGroups.map((group, groupIndex) => (
|
||||
<div key={groupIndex} className={styles.group}>
|
||||
<h3 className={styles.groupTitle}>{group.groupName}</h3>
|
||||
<div className={styles.grid}>
|
||||
{group.items.map((item, itemIndex) => (
|
||||
<LinkCard key={itemIndex} {...item} />
|
||||
))}
|
||||
</div>
|
||||
<div className={styles.container}>
|
||||
<div className={styles.mainContent}>
|
||||
<div className={styles.searchContainer}>
|
||||
<div className={styles.searchWrapper}>
|
||||
<svg
|
||||
className={styles.searchIcon}
|
||||
width="18"
|
||||
height="18"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
strokeWidth="2"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
>
|
||||
<circle cx="11" cy="11" r="8" />
|
||||
<path d="m21 21-4.35-4.35" />
|
||||
</svg>
|
||||
<input
|
||||
type="text"
|
||||
placeholder="搜索资源..."
|
||||
value={searchTerm}
|
||||
onChange={e => setSearchTerm(e.target.value)}
|
||||
className={styles.searchInput}
|
||||
/>
|
||||
</div>
|
||||
))
|
||||
) : (
|
||||
<div className={styles.noResults}>
|
||||
<svg
|
||||
className={styles.noResultsIcon}
|
||||
width="48"
|
||||
height="48"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
strokeWidth="1.5"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
>
|
||||
<circle cx="11" cy="11" r="8" />
|
||||
<path d="m21 21-4.35-4.35" />
|
||||
<path d="M8 11s1.5-2 4-2 4 2 4 2" />
|
||||
</svg>
|
||||
<p>未找到匹配的资源</p>
|
||||
<span className={styles.searchCount}>
|
||||
{filteredTotalItems}
|
||||
{' '}
|
||||
/
|
||||
{totalItems}
|
||||
{' '}
|
||||
项
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{filteredGroups.length > 0
|
||||
? (
|
||||
filteredGroups.map((group, groupIndex) => (
|
||||
<div key={groupIndex} id={`group-${groupIndex}`} className={styles.group}>
|
||||
<h3 className={styles.groupTitle}>{group.groupName}</h3>
|
||||
<div className={styles.grid}>
|
||||
{group.items.map((item, itemIndex) => (
|
||||
<LinkCard key={itemIndex} {...item} />
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
))
|
||||
)
|
||||
: (
|
||||
<div className={styles.noResults}>
|
||||
<svg
|
||||
className={styles.noResultsIcon}
|
||||
width="48"
|
||||
height="48"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
strokeWidth="1.5"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
>
|
||||
<circle cx="11" cy="11" r="8" />
|
||||
<path d="m21 21-4.35-4.35" />
|
||||
<path d="M8 11s1.5-2 4-2 4 2 4 2" />
|
||||
</svg>
|
||||
<p>未找到匹配的资源</p>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<nav className={styles.sidebar} ref={sidebarRef}>
|
||||
<div className={styles.sidebarHeader}>快速导航</div>
|
||||
<div className={styles.sidebarLinks}>
|
||||
{groups.map((group, index) => (
|
||||
<button
|
||||
key={index}
|
||||
onClick={() => scrollToSection(index)}
|
||||
className={`${styles.sidebarLink} ${activeSection === `group-${index}` ? styles.active : ''}`}
|
||||
>
|
||||
{group.groupName}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
</nav>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,65 @@
|
||||
/* 容器布局 */
|
||||
.container {
|
||||
display: flex;
|
||||
gap: 24px;
|
||||
}
|
||||
|
||||
.mainContent {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
/* 右侧导航 */
|
||||
.sidebar {
|
||||
width: 180px;
|
||||
flex-shrink: 0;
|
||||
position: sticky;
|
||||
top: 2rem;
|
||||
height: fit-content;
|
||||
}
|
||||
|
||||
.sidebarHeader {
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
color: var(--ifm-color-emphasis-600);
|
||||
margin-bottom: 12px;
|
||||
padding-left: 8px;
|
||||
}
|
||||
|
||||
.sidebarLinks {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
.sidebarLink {
|
||||
display: block;
|
||||
padding: 8px 12px;
|
||||
font-size: 14px;
|
||||
text-align: left;
|
||||
border: none;
|
||||
background: transparent;
|
||||
color: var(--ifm-color-emphasis-700);
|
||||
border-radius: 8px;
|
||||
cursor: pointer;
|
||||
transition:
|
||||
background-color 0.2s ease,
|
||||
color 0.2s ease;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.sidebarLink:hover {
|
||||
background-color: var(--ifm-color-emphasis-100);
|
||||
color: var(--ifm-color-emphasis-900);
|
||||
}
|
||||
|
||||
.sidebarLink.active {
|
||||
background-color: var(--ifm-color-primary);
|
||||
color: white;
|
||||
}
|
||||
|
||||
/* 网格布局 */
|
||||
.grid {
|
||||
display: grid;
|
||||
gap: 16px;
|
||||
@@ -28,6 +90,13 @@
|
||||
}
|
||||
}
|
||||
|
||||
/* 响应式:隐藏右侧导航 */
|
||||
@media (max-width: 1200px) {
|
||||
.sidebar {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
/* 卡片 */
|
||||
|
||||
.card {
|
||||
@@ -194,6 +263,7 @@
|
||||
|
||||
.group {
|
||||
margin-bottom: 32px;
|
||||
scroll-margin-top: calc(var(--ifm-navbar-height, 64px) + 1rem);
|
||||
}
|
||||
|
||||
.group:last-child {
|
||||
|
||||
Reference in new issue
Block a user