diff --git a/code/docusaurus/.trae/documents/subgroup_plan.md b/code/docusaurus/.trae/documents/subgroup_plan.md new file mode 100644 index 00000000..94461fac --- /dev/null +++ b/code/docusaurus/.trae/documents/subgroup_plan.md @@ -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. 启动开发服务器验证显示效果 + diff --git a/code/docusaurus/docs/resources.mdx b/code/docusaurus/docs/resources.mdx index 35a38059..e0b539dc 100644 --- a/code/docusaurus/docs/resources.mdx +++ b/code/docusaurus/docs/resources.mdx @@ -30,77 +30,82 @@ import SearchableLinkGrid from '@site/src/components/Link/SearchableLinkGrid'; ], }, { - groupName: '大模型', - items: [ + groupName: '大模型与AI', + subGroups: [ { - title: 'Qwen', - description: '阿里云通义千问', - href: 'https://mcp.csdn.net/683559a9606a8318e85a74e7.html', + title: '大模型', + items: [ + { + 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: '腾讯混元', + description: '腾讯大模型', + href: 'https://github.com/Tencent-Hunyuan/Tencent-Hunyuan-Large', + }, + ], }, { - title: 'InternVL', - description: '多模态大模型', - href: 'https://internvl.readthedocs.io/en/latest/internvl3.0/quick_start.html', + title: 'AI工具', + items: [ + { + title: 'MinerU', + description: '文档解析工具', + href: 'https://opendatalab.github.io/MinerU/zh/', + }, + { + title: 'PaddleOCR', + description: 'OCR 识别工具', + href: 'https://paddlepaddle.github.io/PaddleOCR/latest/version3.x/pipeline_usage/OCR.html', + }, + ], }, { - title: '腾讯混元', - description: '腾讯大模型', - href: 'https://github.com/Tencent-Hunyuan/Tencent-Hunyuan-Large', - }, - ], - }, - { - groupName: 'AI工具', - items: [ - { - title: 'MinerU', - description: '文档解析工具', - href: 'https://opendatalab.github.io/MinerU/zh/', + title: 'AI部署与推理', + items: [ + { + 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', + }, + ], }, { - title: 'PaddleOCR', - description: 'OCR 识别工具', - href: 'https://paddlepaddle.github.io/PaddleOCR/latest/version3.x/pipeline_usage/OCR.html', - }, - ], - }, - { - groupName: 'AI部署与推理', - items: [ - { - 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 接口', - href: 'https://www.cnblogs.com/vipstone/p/19142030', - }, - { - title: 'HuggingFace 模型转换', - description: 'GGUF 格式转换教程', - href: 'https://zhuanlan.zhihu.com/p/721617987', + title: 'AI评测与资源', + items: [ + { + title: 'OpenCompass', + description: '大模型评测榜单', + href: 'https://rank.opencompass.org.cn/leaderboard-multimodal/', + }, + { + title: '免费 AI 接口整理', + description: '4种免费 AI 接口', + href: 'https://www.cnblogs.com/vipstone/p/19142030', + }, + { + title: 'HuggingFace 模型转换', + description: 'GGUF 格式转换教程', + href: 'https://zhuanlan.zhihu.com/p/721617987', + }, + ], }, ], }, @@ -151,121 +156,151 @@ import SearchableLinkGrid from '@site/src/components/Link/SearchableLinkGrid'; }, { groupName: '移动端开发', - items: [ + subGroups: [ { - title: 'gluestack-ui', - description: 'React Native UI 套件', - href: 'https://gluestack.io/ui/docs/home/overview/quick-start', + title: 'React Native', + items: [ + { + title: 'gluestack-ui', + description: 'React Native UI 套件', + href: 'https://gluestack.io/ui/docs/home/overview/quick-start', + }, + { + title: 'React Native Directory', + description: '第三方库目录', + href: 'https://reactnative.directory/packages', + }, + { + title: 'Awesome RN', + description: '学习资源精选', + href: 'https://github.com/wabg/awesome-react-native', + }, + { + title: 'RN UI Datepicker', + description: '日期选择组件', + href: 'https://farhoudshapouran.github.io/react-native-ui-datepicker/', + }, + { + title: 'Victory Charts', + description: '数据可视化库', + href: 'https://nearform.com/open-source/victory/docs/introduction/', + }, + { + title: 'React Native 第三方库', + description: '常用库汇总', + href: 'https://www.cnblogs.com/youhui/articles/11771865.html', + }, + { + title: 'Expo 热更新', + description: '不使用 EAS 的热更新方案', + href: 'https://juejin.cn/post/7390659669113929779', + }, + ], }, { - title: 'React Native Directory', - description: '第三方库目录', - href: 'https://reactnative.directory/packages', - }, - { - title: 'Awesome RN', - description: '学习资源精选', - href: 'https://github.com/wabg/awesome-react-native', - }, - { - title: 'RN UI Datepicker', - description: '日期选择组件', - href: 'https://farhoudshapouran.github.io/react-native-ui-datepicker/', - }, - { - title: 'Victory Charts', - description: '数据可视化库', - href: 'https://nearform.com/open-source/victory/docs/introduction/', - }, - { - title: 'React Native 第三方库', - description: '常用库汇总', - href: 'https://www.cnblogs.com/youhui/articles/11771865.html', - }, - { - title: 'Expo 热更新', - description: '不使用 EAS 的热更新方案', - href: 'https://juejin.cn/post/7390659669113929779', - }, - { - title: '原生插件集成指南', - description: 'uni-app 原生插件文档', - href: 'https://nativesupport.dcloud.net.cn/NativePlugin/offline_package/android.html', - }, - { - title: '离线打包教程', - description: 'Android 离线打包制作', - href: 'https://ask.dcloud.net.cn/article/35482', + title: 'UniApp', + items: [ + { + title: '原生插件集成指南', + description: 'uni-app 原生插件文档', + href: 'https://nativesupport.dcloud.net.cn/NativePlugin/offline_package/android.html', + }, + { + title: '离线打包教程', + description: 'Android 离线打包制作', + href: 'https://ask.dcloud.net.cn/article/35482', + }, + { + title: '天地图 UniApp', + description: 'UniApp 插件', + href: 'https://ext.dcloud.net.cn/plugin?id=22630', + }, + ], }, ], }, { groupName: 'UI资源', - items: [ + subGroups: [ { - title: 'IconFont', - description: '阿里巴巴矢量图标库', - href: 'https://www.iconfont.cn/', + title: '图标资源', + items: [ + { + title: 'IconFont', + description: '阿里巴巴矢量图标库', + href: 'https://www.iconfont.cn/', + }, + { + 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: 'Lucide', - description: '精美的开源图标库', - href: 'https://lucide.dev/icons/', + title: '插画素材', + items: [ + { + title: 'unDraw', + description: '开源插画库', + href: 'https://undraw.co/', + }, + { + title: 'Storyset', + description: '可自定义插画', + href: 'https://storyset.com/', + }, + { + title: 'ManyPixels', + description: '免费插画素材', + href: 'https://www.manypixels.co/gallery', + }, + ], }, { - 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 组件', - href: 'https://uiverse.io/elements', - }, - { - title: 'CodePen', - description: '前端代码分享社区', - href: 'https://codepen.io/trending', - }, - { - title: 'HTML Rev', - description: '免费 HTML 网站模板', - href: 'https://htmlrev.com/', - }, - { - title: 'MockUPhone', - description: '设备样机展示', - href: 'https://mockuphone.com/model/iphone-15/', + title: '动画与模板', + items: [ + { + title: 'LottieFiles', + description: '动画资源平台', + href: 'https://app.lottiefiles.com/search', + }, + { + title: 'UIverse', + description: 'CSS & Tailwind UI 组件', + href: 'https://uiverse.io/elements', + }, + { + title: 'CodePen', + description: '前端代码分享社区', + href: 'https://codepen.io/trending', + }, + { + title: 'HTML Rev', + description: '免费 HTML 网站模板', + href: 'https://htmlrev.com/', + }, + { + title: 'MockUPhone', + description: '设备样机展示', + href: 'https://mockuphone.com/model/iphone-15/', + }, + ], }, ], }, @@ -281,106 +316,141 @@ import SearchableLinkGrid from '@site/src/components/Link/SearchableLinkGrid'; }, { groupName: '开发环境', - items: [ + subGroups: [ { - title: 'JDK', - description: 'Java 开发工具包', - href: 'https://adoptium.net/zh-CN/temurin/releases', + title: '编程语言', + items: [ + { + title: 'JDK', + description: 'Java 开发工具包', + href: 'https://adoptium.net/zh-CN/temurin/releases', + }, + { + title: 'Go', + description: 'Golang 下载', + href: 'https://go.dev/dl/', + }, + { + title: 'nvm-windows', + description: 'Node 版本管理', + href: 'https://nvm.uihtm.com/doc/download-nvm.html', + }, + ], }, { - title: 'Go', - description: 'Golang 下载', - href: 'https://go.dev/dl/', + title: '传统IDE', + items: [ + { + title: 'IntelliJ IDEA', + description: 'Java IDE', + href: 'https://www.jetbrains.com/zh-cn/idea/', + }, + { + title: 'GoLand', + description: 'Go 语言 IDE', + href: 'https://www.jetbrains.com/zh-cn/go/', + }, + { + title: 'DataGrip', + description: '数据库管理工具', + href: 'https://www.jetbrains.com/zh-cn/datagrip/', + }, + ], }, { - title: 'nvm-windows', - description: 'Node 版本管理', - 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: 'GoLand', - description: 'Go 语言 IDE', - href: 'https://www.jetbrains.com/zh-cn/go/', - }, - { - title: 'DataGrip', - description: '数据库管理工具', - href: 'https://www.jetbrains.com/zh-cn/datagrip/', - }, - ], - }, - { - groupName: '地图服务', - items: [ - { - title: '天地图', - description: '地理编码服务', - href: 'http://lbs.tianditu.gov.cn/home.html', - }, - { - title: '天地图 UniApp', - description: 'UniApp 插件', - href: 'https://ext.dcloud.net.cn/plugin?id=22630', + title: 'AI IDE', + items: [ + { + title: 'Cursor', + description: 'AI 驱动的代码编辑器', + href: 'https://cursor.com/', + }, + { + title: 'ChatGPT Codex', + description: 'AI 代码生成助手', + href: 'https://chatgpt.com/zh-Hans-CN/codex/', + }, + { + title: 'Trae', + description: 'Trae AI 助手平台', + href: 'https://www.trae.cn/', + }, + ], }, ], }, { groupName: '开发资源', - items: [ + subGroups: [ { - title: '清华镜像源', - description: '清华大学开源软件镜像站', - href: 'https://mirrors.tuna.tsinghua.edu.cn/', + title: '镜像源', + items: [ + { + title: '清华镜像源', + description: '清华大学开源软件镜像站', + href: 'https://mirrors.tuna.tsinghua.edu.cn/', + }, + ], }, { - title: 'URL Encoder', - description: 'SVG URL 编码工具', - href: 'https://yoksel.github.io/url-encoder/zh-cn/', + title: '地图服务', + items: [ + { + title: '天地图', + description: '地理编码服务', + href: 'http://lbs.tianditu.gov.cn/home.html', + }, + ], + }, + { + title: '工具网站', + items: [ + { + title: 'URL Encoder', + description: 'SVG URL 编码工具', + href: 'https://yoksel.github.io/url-encoder/zh-cn/', + }, + ], }, ], }, { - groupName: '系统工具', - items: [ + groupName: '系统与效率工具', + subGroups: [ { - title: 'VMware Workstation', - description: 'VMware Pro 下载', - href: 'https://github.com/201853910/VMwareWorkstation', - }, - ], - }, - { - groupName: '效率办公', - items: [ - { - title: 'DeepL翻译', - description: 'AI 驱动的翻译工具', - href: 'https://www.deepl.com/zh/translator', + title: '系统工具', + items: [ + { + title: 'VMware Workstation', + description: 'VMware Pro 下载', + href: 'https://github.com/201853910/VMwareWorkstation', + }, + ], }, { - title: 'Snipaste', - description: '截图工具', - href: 'https://www.snipaste.com/', - }, - { - title: '腾讯桌面整理', - description: '桌面文件整理工具', - href: 'https://guanjia.qq.com/product/zmzl/', - }, - { - title: 'Twinkle Tray', - description: '屏幕亮度调节', - href: 'https://twinkletray.com/', + title: '效率办公', + items: [ + { + title: 'DeepL翻译', + description: 'AI 驱动的翻译工具', + href: 'https://www.deepl.com/zh/translator', + }, + { + title: 'Snipaste', + description: '截图工具', + href: 'https://www.snipaste.com/', + }, + { + title: '腾讯桌面整理', + description: '桌面文件整理工具', + href: 'https://guanjia.qq.com/product/zmzl/', + }, + { + title: 'Twinkle Tray', + description: '屏幕亮度调节', + href: 'https://twinkletray.com/', + }, + ], }, ], }, diff --git a/code/docusaurus/src/components/Link/SearchableLinkGrid.tsx b/code/docusaurus/src/components/Link/SearchableLinkGrid.tsx index 52e34b45..20db8d97 100644 --- a/code/docusaurus/src/components/Link/SearchableLinkGrid.tsx +++ b/code/docusaurus/src/components/Link/SearchableLinkGrid.tsx @@ -3,9 +3,15 @@ import React, { useEffect, useMemo, useRef, useState } from 'react' import LinkCard from './LinkCard' import styles from './styles.module.css' +export interface SubGroup { + title: string + items: LinkCardProps[] +} + export interface GroupedLinkCardProps { groupName: string - items: LinkCardProps[] + items?: LinkCardProps[] + subGroups?: SubGroup[] } interface SearchableLinkGridProps { @@ -15,6 +21,7 @@ interface SearchableLinkGridProps { export default function SearchableLinkGrid({ groups }: SearchableLinkGridProps) { const [searchTerm, setSearchTerm] = useState('') const [activeSection, setActiveSection] = useState('') + const [expandedGroups, setExpandedGroups] = useState>(new Set([0])) const sidebarRef = useRef(null) useEffect(() => { @@ -46,11 +53,17 @@ export default function SearchableLinkGrid({ groups }: SearchableLinkGridProps) }, ) - groups.forEach((_, index) => { - const element = document.getElementById(`group-${index}`) - if (element) { - observer.observe(element) + groups.forEach((group, groupIndex) => { + const groupElement = document.getElementById(`group-${groupIndex}`) + if (groupElement) { + observer.observe(groupElement) } + group.subGroups?.forEach((_, subIndex) => { + const subGroupElement = document.getElementById(`subgroup-${groupIndex}-${subIndex}`) + if (subGroupElement) { + observer.observe(subGroupElement) + } + }) }) return () => { @@ -58,31 +71,102 @@ export default function SearchableLinkGrid({ groups }: SearchableLinkGridProps) } }, [groups]) + const countGroupItems = (group: GroupedLinkCardProps): number => { + let count = group.items?.length || 0 + if (group.subGroups) { + count += group.subGroups.reduce((sum, sg) => sum + sg.items.length, 0) + } + return count + } + + const filterGroup = (group: GroupedLinkCardProps, lowerTerm: string): GroupedLinkCardProps | null => { + const filteredItems = group.items?.filter( + item => + item.title.toLowerCase().includes(lowerTerm) + || item.description.toLowerCase().includes(lowerTerm), + ) || [] + + const filteredSubGroups = group.subGroups?.map(sg => ({ + ...sg, + items: sg.items.filter( + item => + item.title.toLowerCase().includes(lowerTerm) + || item.description.toLowerCase().includes(lowerTerm), + ), + })).filter(sg => sg.items.length > 0) || [] + + if (filteredItems.length > 0 || filteredSubGroups.length > 0) { + return { + ...group, + items: filteredItems.length > 0 ? filteredItems : undefined, + subGroups: filteredSubGroups.length > 0 ? filteredSubGroups : undefined, + } + } + + return null + } + const filteredGroups = useMemo(() => { 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), - ), - })).filter(group => group.items.length > 0) + return groups.map(group => filterGroup(group, lowerTerm)).filter(Boolean) as GroupedLinkCardProps[] }, [searchTerm, groups]) - const totalItems = groups.reduce((sum, group) => sum + group.items.length, 0) - const filteredTotalItems = filteredGroups.reduce((sum, group) => sum + group.items.length, 0) + const totalItems = groups.reduce((sum, group) => sum + countGroupItems(group), 0) + const filteredTotalItems = filteredGroups.reduce((sum, group) => sum + countGroupItems(group), 0) - const scrollToSection = (index: number) => { - const element = document.getElementById(`group-${index}`) + const scrollToSection = (groupIndex: number, subGroupIndex?: number) => { + if (subGroupIndex !== undefined) { + const element = document.getElementById(`subgroup-${groupIndex}-${subGroupIndex}`) + if (element) { + element.scrollIntoView({ behavior: 'smooth', block: 'start' }) + return + } + } + const element = document.getElementById(`group-${groupIndex}`) if (element) { element.scrollIntoView({ behavior: 'smooth', block: 'start' }) } } + const toggleGroup = (index: number) => { + setExpandedGroups((prev) => { + const newSet = new Set(prev) + if (newSet.has(index)) { + newSet.delete(index) + } + else { + newSet.add(index) + } + return newSet + }) + } + + const renderItems = (items: LinkCardProps[]) => ( +
+ {items.map((item, itemIndex) => ( + + ))} +
+ ) + + const renderGroup = (group: GroupedLinkCardProps, groupIndex: number) => ( +
+

{group.groupName}

+ {group.items && group.items.length > 0 && renderItems(group.items)} + {group.subGroups && group.subGroups.map((subGroup, subIndex) => ( +
+

{subGroup.title}

+
+ {renderItems(subGroup.items)} +
+
+ ))} +
+ ) + return (
@@ -122,16 +206,7 @@ export default function SearchableLinkGrid({ groups }: SearchableLinkGridProps) {filteredGroups.length > 0 ? ( - filteredGroups.map((group, groupIndex) => ( -
-

{group.groupName}

-
- {group.items.map((item, itemIndex) => ( - - ))} -
-
- )) + filteredGroups.map((group, groupIndex) => renderGroup(group, groupIndex)) ) : (
@@ -158,15 +233,44 @@ export default function SearchableLinkGrid({ groups }: SearchableLinkGridProps)
diff --git a/code/docusaurus/src/components/Link/styles.module.css b/code/docusaurus/src/components/Link/styles.module.css index 36123f3f..8335922b 100644 --- a/code/docusaurus/src/components/Link/styles.module.css +++ b/code/docusaurus/src/components/Link/styles.module.css @@ -1,7 +1,7 @@ /* 容器布局 */ .container { display: flex; - gap: 24px; + gap: 32px; } .mainContent { @@ -10,40 +10,45 @@ /* 右侧导航 */ .sidebar { - width: 180px; + width: 192px; flex-shrink: 0; position: sticky; - top: 2rem; + top: calc(var(--ifm-navbar-height, 64px) + 1.5rem); height: fit-content; + padding: 16px; + background: var(--ifm-card-background-color); + border-radius: 16px; + border: 1px solid var(--ifm-color-emphasis-200); } .sidebarHeader { - font-size: 14px; + font-size: 13px; font-weight: 600; - color: var(--ifm-color-emphasis-600); + color: var(--ifm-color-emphasis-500); + text-transform: uppercase; + letter-spacing: 0.5px; margin-bottom: 12px; - padding-left: 8px; + padding: 0 4px; } .sidebarLinks { display: flex; flex-direction: column; - gap: 4px; + gap: 2px; } .sidebarLink { - display: block; - padding: 8px 12px; + display: flex; + align-items: center; + padding: 9px 12px; font-size: 14px; text-align: left; border: none; background: transparent; color: var(--ifm-color-emphasis-700); - border-radius: 8px; + border-radius: 10px; cursor: pointer; - transition: - background-color 0.2s ease, - color 0.2s ease; + transition: all 0.2s ease; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; @@ -59,151 +64,177 @@ color: white; } +.sidebarGroup { + display: flex; + flex-direction: column; +} + +.sidebarLinkParent { + gap: 8px; +} + +.sidebarLinkParent.hasChildren { + padding-right: 8px; +} + +.chevron { + width: 18px; + height: 18px; + display: flex; + align-items: center; + justify-content: center; + flex-shrink: 0; + color: var(--ifm-color-emphasis-400); + font-size: 11px; + line-height: 1; + transition: color 0.2s ease; +} + +.sidebarLinkParent:hover .chevron { + color: var(--ifm-color-emphasis-600); +} + +.sidebarLinkParent.active .chevron { + color: white; +} + +.sidebarSubLinks { + display: flex; + flex-direction: column; + gap: 3px; + padding-left: 8px; + margin: 4px 0 6px 16px; +} + +.sidebarLinkChild { + padding: 9px 14px; + font-size: 14px; + padding-left: 26px; + color: var(--ifm-color-emphasis-600); + border-radius: 10px; +} + +.sidebarLinkChild:hover { + background-color: rgba(0, 0, 0, 0.04); + color: var(--ifm-color-emphasis-800); +} + +.sidebarLinkChild.active { + background-color: var(--ifm-color-primary); + color: white; +} + /* 网格布局 */ .grid { display: grid; gap: 16px; margin-top: 16px; - - /* 默认桌面4列 */ grid-template-columns: repeat(4, minmax(0, 1fr)); } -/* 平板 */ @media (max-width: 1200px) { .grid { grid-template-columns: repeat(3, minmax(0, 1fr)); } } -/* 小平板 */ @media (max-width: 996px) { .grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } } -/* 手机 */ @media (max-width: 576px) { .grid { grid-template-columns: 1fr; } } -/* 响应式:隐藏右侧导航 */ -@media (max-width: 1200px) { +@media (max-width: 1280px) { .sidebar { display: none; } } /* 卡片 */ - .card { display: flex; flex-direction: column; - - padding: 18px; - - border-radius: 14px; + padding: 20px; + border-radius: 16px; border: 1px solid var(--ifm-color-emphasis-200); - background: var(--ifm-card-background-color); - color: inherit; text-decoration: none; - - transition: - transform 0.2s ease, - border-color 0.2s ease, - box-shadow 0.2s ease; + transition: all 0.25s ease; } .card:hover { color: inherit; text-decoration: none; - - transform: translateY(-3px); - + transform: translateY(-4px); border-color: var(--ifm-color-primary); - - box-shadow: 0 8px 20px rgba(0, 0, 0, 0.08); + box-shadow: 0 12px 28px rgba(0, 0, 0, 0.08); } /* 标题区域 */ - .header { display: flex; align-items: center; - gap: 12px; + gap: 14px; } /* 图标 */ - .icon { - width: 32px; - height: 32px; - + width: 36px; + height: 36px; object-fit: contain; - flex-shrink: 0; } .placeholder { - width: 40px; - height: 40px; - - border-radius: 10px; - + width: 44px; + height: 44px; + border-radius: 12px; display: flex; align-items: center; justify-content: center; - - background: var(--ifm-color-primary); + background: linear-gradient(135deg, var(--ifm-color-primary) 0%, var(--ifm-color-primary-dark) 100%); color: white; - font-size: 18px; font-weight: 700; - flex-shrink: 0; + box-shadow: 0 4px 12px rgba(var(--ifm-color-primary-rgb), 0.2); } /* 标题 */ - .title { - font-size: 17px; + font-size: 16px; font-weight: 600; line-height: 1.4; - overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } /* 描述 */ - .description { - margin-top: 14px; - + margin-top: 12px; font-size: 14px; line-height: 1.6; - - color: var(--ifm-color-emphasis-700); - + color: var(--ifm-color-emphasis-600); overflow: hidden; - display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; } /* 搜索容器 */ - .searchContainer { display: flex; align-items: center; gap: 16px; - margin-bottom: 24px; + margin-bottom: 28px; width: 100%; } @@ -213,11 +244,9 @@ align-items: center; background: var(--ifm-card-background-color); border: 1px solid var(--ifm-color-emphasis-200); - border-radius: 12px; - padding: 2px 2px 2px 16px; - transition: - border-color 0.2s ease, - box-shadow 0.2s ease; + border-radius: 14px; + padding: 4px 4px 4px 18px; + transition: all 0.2s ease; } .searchWrapper:focus-within { @@ -229,14 +258,16 @@ color: var(--ifm-color-emphasis-400); margin-right: 12px; flex-shrink: 0; + width: 18px; + height: 18px; } .searchInput { flex: 1; width: 100%; - padding: 12px 16px 12px 0; + padding: 13px 16px 13px 0; border: none; - border-radius: 0 10px 10px 0; + border-radius: 0 12px 12px 0; font-size: 15px; background: transparent; color: var(--ifm-font-color-base); @@ -254,16 +285,16 @@ font-size: 13px; color: var(--ifm-color-emphasis-500); white-space: nowrap; - padding: 6px 12px; + padding: 8px 14px; background: var(--ifm-color-emphasis-100); border-radius: 20px; + font-weight: 500; } /* 分组样式 */ - .group { - margin-bottom: 32px; - scroll-margin-top: calc(var(--ifm-navbar-height, 64px) + 1rem); + margin-bottom: 36px; + scroll-margin-top: calc(var(--ifm-navbar-height, 64px) + 1.5rem); } .group:last-child { @@ -273,26 +304,53 @@ .groupTitle { font-size: 18px; font-weight: 700; - color: var(--ifm-color-emphasis-800); + color: var(--ifm-color-emphasis-900); margin-bottom: 20px; - padding-left: 14px; + padding: 8px 0 8px 16px; border-left: 4px solid var(--ifm-color-primary); + background: linear-gradient(90deg, rgba(var(--ifm-color-primary-rgb), 0.05) 0%, transparent 100%); +} + +/* 子分组样式 */ +.subGroup { + margin-top: 24px; + scroll-margin-top: calc(var(--ifm-navbar-height, 64px) + 1rem); +} + +.subGroup:first-child { + margin-top: 16px; +} + +.subGroupTitle { + font-size: 16px; + font-weight: 600; + color: var(--ifm-color-emphasis-800); + margin-bottom: 14px; + padding: 6px 0 6px 24px; + position: relative; +} + +.subGroupContent { + margin-left: 24px; + padding-left: 16px; + border-left: 2px solid var(--ifm-color-emphasis-100); } /* 无结果状态 */ - .noResults { display: flex; flex-direction: column; align-items: center; justify-content: center; - padding: 60px 20px; + padding: 80px 20px; color: var(--ifm-color-emphasis-600); } .noResultsIcon { color: var(--ifm-color-emphasis-400); - margin-bottom: 16px; + margin-bottom: 20px; + width: 56px; + height: 56px; } .noResults p {