From c8f40f36164e70169648e1b567282f5d96ac37c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=A0=91=E8=90=8C=E8=8A=BD?= <3205788256@qq.com> Date: Mon, 29 Sep 2025 15:05:43 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E7=BD=91=E7=AB=99markdown?= =?UTF-8?q?=E8=A7=A3=E6=9E=90=E6=A0=BC=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 129 ++++- public/mengyanote/.obsidian/workspace.json | 8 +- .../Android/安卓Gradle构建常用命令总结.md | 24 +- src/App.css | 59 ++- src/components/MarkdownRenderer.css | 474 ++++++------------ src/components/MarkdownRenderer.jsx | 266 +++------- src/components/Sidebar.css | 167 +++--- src/components/Sidebar.jsx | 20 +- src/data/fileContents.json | 2 +- src/data/stats.json | 4 +- src/index.css | 6 +- 11 files changed, 482 insertions(+), 677 deletions(-) diff --git a/README.md b/README.md index e1bb550..1ca15fa 100644 --- a/README.md +++ b/README.md @@ -1,16 +1,127 @@ -# React + Vite +# Markdown To Web -This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules. +此仓库将一组本地 Markdown 笔记(位于 `public/mengyanote`)转换成一个静态的 React 网站,便于浏览、检索和发布到网络上。 -Currently, two official plugins are available: +本 README 为中文说明,包含项目简介、运行/构建步骤、目录结构、如何编辑笔记以及部署和贡献指南,方便直接发布到 GitHub。 -- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react) uses [Babel](https://babeljs.io/) for Fast Refresh -- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh +## 主要特性 -## React Compiler +- 从本地目录(`public/mengyanote`)递归读取 Markdown 文件并生成静态数据(`src/data`)。 +- 使用 `react-markdown` 渲染 Markdown,支持数学公式(remark/rehype 插件)与代码高亮。 +- 目录树侧边栏、内容渲染器等基础浏览功能。 +- 通过简单脚本将 Markdown 文件转为项目需要的 JSON 数据,便于在静态站点中直接使用。 -The React Compiler is not enabled on this template. To add it, see [this documentation](https://react.dev/learn/react-compiler/installation). +## 技术栈 -## Expanding the ESLint configuration +- React 19 +- Vite +- react-markdown + remark/rehype 插件(remark-gfm、remark-math、rehype-katex、rehype-highlight 等) + +## 快速开始(Windows / cmd.exe) + +1. 安装依赖 + +``` +npm install +``` + +2. 本地开发(会先生成静态数据) + +``` +npm run dev +``` + +这会先执行 `node scripts/generateData.js` 从 `public/mengyanote` 读取 Markdown 并生成 `src/data` 下的 `directoryTree.json` / `fileContents.json` / `stats.json`,然后启动 Vite 开发服务器。 + +3. 生成生产构建 + +``` +npm run build +``` + +4. 预览构建产物 + +``` +npm run preview +``` + +5. 单独生成数据(不启动服务器) + +``` +npm run generate-data +``` + +6. 代码检查 + +``` +npm run lint +``` + +## 项目结构(重要文件/目录) + +- `public/mengyanote/` - 源 Markdown 笔记目录(请把你的 .md 文件放在这里以纳入站点)。 +- `scripts/generateData.js` - 将 Markdown 文件读取并生成 `src/data` 的脚本。 +- `src/data/` - 由脚本生成的 JSON 数据(目录树、文件内容、统计信息)。 +- `src/components/MarkdownRenderer.jsx` - Markdown 渲染组件(样式与功能定制点)。 +- `src/components/MarkdownRenderer.css` - Markdown 渲染相关样式(可在此处简化或替换为你喜欢的样式)。 +- `src/components/Sidebar.jsx` - 侧边栏目录树组件。 +- `src/context/AppContext.jsx` - 全局上下文与路由状态。 +- `scripts/` - 工具脚本(目前包含 `generateData.js`)。 + +示例:如果你想让 Markdown 渲染更简洁(“换成我图片那种”样式),可以编辑 `src/components/MarkdownRenderer.css` 或直接修改 `MarkdownRenderer.jsx` 中的渲染类名/元素结构。 + +## 如何编辑/添加笔记 + +1. 在 `public/mengyanote` 下增加或修改 `.md` 文件,保持目录组织即可。 +2. 运行 `npm run generate-data`(或 `npm run dev`)以重新生成 `src/data`。 +3. 刷新浏览器查看最新内容。 + +注意:脚本会忽略以 `.` 开头的文件/目录(例如 `.obsidian`)和一些预设项(`node_modules`、`.git` 等)。 + +## 部署建议 + +- 静态站点:`npm run build` 会在 `dist/` 生成静态文件,适合部署到 GitHub Pages、Netlify、Vercel、或任意静态文件托管服务。 +- GitHub Pages:构建后将 `dist/` 的内容发布到 gh-pages 分支或通过 GitHub Actions 自动发布。 + +示例(手工): + +1. 构建 + +``` +npm run build +``` + +2. 将 `dist/` 内容上传到你的静态托管服务或 gh-pages 分支。 + +如果需要,我可以为你添加一个自动部署到 GitHub Pages 的 GitHub Actions 工作流。 + +## 定制渲染样式 + +如果你觉得当前 Markdown 美化太重并想改回更简洁的“图片优先”或原始样式: + +- 编辑 `src/components/MarkdownRenderer.css`:移除或覆盖过度的样式(字体、背景、代码块高亮等)。 +- 编辑 `src/components/MarkdownRenderer.jsx`:调整渲染器的 className、元素包装或忽略某些 remark/rehype 插件。 + +常见修改点: +- 移除 KaTeX 或代码高亮:在 `src/components/MarkdownRenderer.jsx` 中删除相应的 rehype 插件 import 与使用。 +- 简化图片样式:在 CSS 中将 img 的 max-width、margin 等属性调整为你想要的样式。 + +## 贡献与许可 + +欢迎提交 Issue 或 Pull Request。仓库包含 `LICENSE`(请查看该文件以确认许可证类型)。 + +为了保持项目干净: +- 新功能请先创建 issue 讨论。 +- 提交 PR 时附带简短说明和相关截图(如果是 UI 变更)。 + +## 联系方式 + +如需帮助或定制:在 Issue 中描述你想要的样式和示例图片/链接,我可以帮你修改 `MarkdownRenderer.css` / `MarkdownRenderer.jsx` 实现视觉风格。 + +--- + +祝发布顺利!如果你想,我可以: + +- 帮你把 README 翻译成英文版本并放在 `README.en.md`; +- 或直接替你修改 Markdown 渲染样式(把渲染改成更像你“图片那种”的风格)。 -If you are developing a production application, we recommend using TypeScript with type-aware lint rules enabled. Check out the [TS template](https://github.com/vitejs/vite/tree/main/packages/create-vite/template-react-ts) for information on how to integrate TypeScript and [`typescript-eslint`](https://typescript-eslint.io) in your project. diff --git a/public/mengyanote/.obsidian/workspace.json b/public/mengyanote/.obsidian/workspace.json index 8149bcd..b971563 100644 --- a/public/mengyanote/.obsidian/workspace.json +++ b/public/mengyanote/.obsidian/workspace.json @@ -13,12 +13,12 @@ "state": { "type": "markdown", "state": { - "file": "树萌芽的小本本/目前已部署网站.md", + "file": "编程语言/Android/Linux配置安卓Gradle构建环境.md", "mode": "source", "source": false }, "icon": "lucide-file", - "title": "目前已部署网站" + "title": "Linux配置安卓Gradle构建环境" } }, { @@ -186,8 +186,9 @@ }, "active": "8304b0e105b08ed0", "lastOpenFiles": [ - "树萌芽的小本本/网站小技巧.md", + "编程语言/Android/安卓Gradle构建常用命令总结.md", "树萌芽的小本本/目前已部署网站.md", + "树萌芽的小本本/网站小技巧.md", "Docker/优秀好用的Docker镜像/FileCodeBox-文件快递柜.md", "Docker/优秀好用的Docker镜像/Postgres数据库.md", "Docker/优秀好用的Docker镜像/未命名.md", @@ -207,7 +208,6 @@ "Docker/Docker镜像快速迁移.md", "无线-HCIA 02.md", "Linux相关/把Ubuntu镜像源切换到阿里云.md", - "编程语言/Android/安卓Gradle构建常用命令总结.md", "临时解决方案/修改hosts方式来直连Github.md", "临时解决方案/萌芽云剪切板.md", "2025年9月紧急规划.md", diff --git a/public/mengyanote/编程语言/Android/安卓Gradle构建常用命令总结.md b/public/mengyanote/编程语言/Android/安卓Gradle构建常用命令总结.md index b9c2074..aca376a 100644 --- a/public/mengyanote/编程语言/Android/安卓Gradle构建常用命令总结.md +++ b/public/mengyanote/编程语言/Android/安卓Gradle构建常用命令总结.md @@ -1,7 +1,6 @@ -# Android Gradle 常用命令速查(基于 `./gradlew`) -**基础** +##### **基础** - `./gradlew tasks` 列出可用的 Gradle 任务(查看当前项目能跑什么任务)。 @@ -13,7 +12,7 @@ 清理构建产物(删除 `build/` 目录)。 -**构建 APK / AAB** +##### **构建 APK / AAB** - `./gradlew assembleDebug` 构建 debug APK(输出:`app/build/outputs/apk/debug/*.apk`)。 @@ -28,7 +27,7 @@ 生成 debug bundle(少用,通常用于测试)。 -**按 module / productFlavor / buildType 构建** +##### **按 module / productFlavor / buildType 构建** - `./gradlew :moduleName:assembleRelease` 构建指定 module(多模块项目时用)。 @@ -37,7 +36,7 @@ 构建指定 flavor + buildType(例如 `assemblePaidRelease`)。 -**安装与卸载** +##### **安装与卸载** - `./gradlew installDebug` 将 debug APK 安装到连接的设备/模拟器(需要 adb 可用)。 @@ -48,14 +47,14 @@ - 如果用生成的 APK 手动安装:`adb install -r app/build/outputs/apk/debug/app-debug.apk` -**测试** +##### **测试** - 单元测试(JVM):`./gradlew test` 或 `./gradlew testDebugUnitTest` - 仪器/设备测试(connected devices):`./gradlew connectedAndroidTest` 或 `./gradlew connectedCheck` -**静态检查 / 报表** +##### **静态检查 / 报表** - `./gradlew lint` 或 `./gradlew lintDebug` 运行 Android Lint。 @@ -64,7 +63,7 @@ 输出签名信息(SHA1/SHA256),常用于配置 API key(Google/Firebase)。 -**调试构建问题的常用参数** +##### **调试构建问题的常用参数** - `--stacktrace` / `--full-stacktrace`:打印堆栈跟踪(排错用) @@ -83,7 +82,7 @@ - `--refresh-dependencies`:刷新依赖缓存 -**性能 / CI 常用组合示例** +##### **性能 / CI 常用组合示例** - 本地快速一把:`./gradlew clean assembleDebug --parallel --info` @@ -92,7 +91,7 @@ - 只构建 moduleA 的 release:`./gradlew :moduleA:assembleRelease` -**常见路径** +##### **常见路径** - APK:`app/build/outputs/apk//...` @@ -101,13 +100,10 @@ - 临时构建缓存:`~/.gradle/caches/` -**小贴士** +##### **小贴士** - 始终用项目里的 Gradle Wrapper(`./gradlew`),保证 Gradle 版本一致。 - Release 构建需要正确的 `signingConfig`(通常放在 `gradle.properties` + `build.gradle`),也可以在 CI 用 `-P` 传参数(注意不要把敏感信息放在日志里)。 - 出问题先加 `--stacktrace --info` 看详情,再定位是依赖、ProGuard/R8、签名还是资源冲突。 - - -如果你想,我可以把你常用的几条命令做成一个可复用的脚本/CI job 模板(GitHub Actions/GitLab CI),或者按你项目的 flavor 给出精确的 assemble 命令。要哪个直接说。 \ No newline at end of file diff --git a/src/App.css b/src/App.css index fabf3e0..ff64e18 100644 --- a/src/App.css +++ b/src/App.css @@ -1,19 +1,17 @@ :root { - --color-bg: #eafbf2; - --color-bg-secondary: #d6f3e3; - --color-surface: rgba(255, 255, 255, 0.88); - --color-surface-strong: #ffffff; - --color-border: rgba(47, 177, 112, 0.2); - --color-text: #1f3a2c; - --color-muted: #4a6c5a; - --color-link: #269c66; - --color-link-hover: #1e7a51; - --color-accent: #33c57a; - --color-accent-contrast: #0f3322; - --shadow-soft: 0 18px 38px rgba(36, 118, 74, 0.18); - --radius-lg: 24px; - --sidebar-width: clamp(240px, 21vw, 320px); - --gradient-bg: linear-gradient(135deg, #f2fff8 0%, #c9f4df 40%, #a6e7d0 100%); + --color-bg: #f5f7fb; + --color-surface: #ffffff; + --color-surface-alt: #f1f4fa; + --color-border: #d8deed; + --color-text: #1f2a44; + --color-muted: #6f7b92; + --color-accent: #3a7afe; + --color-accent-soft: rgba(58, 122, 254, 0.1); + --color-danger: #d6455d; + --sidebar-width: clamp(250px, 20vw, 320px); + --shadow-soft: 0 20px 45px rgba(86, 105, 141, 0.15); + --radius-lg: 22px; + --font-family-base: 'Inter', 'Segoe UI', 'PingFang SC', 'Microsoft YaHei', sans-serif; } * { @@ -25,32 +23,32 @@ body { margin: 0; padding: 0; min-height: 100vh; - background: var(--gradient-bg); + background: linear-gradient(135deg, #f6f9ff 0%, #edf2fb 45%, #fbfdff 100%); color: var(--color-text); - font-family: 'Inter', 'Segoe UI', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei', sans-serif; + font-family: var(--font-family-base); } #root { min-height: 100vh; display: flex; - padding: clamp(0.75rem, 2vw, 2rem); + padding: clamp(1rem, 4vw, 2.5rem); } .app { flex: 1; display: flex; - min-height: calc(100vh - clamp(1.5rem, 4vw, 4rem)); + min-height: calc(100vh - clamp(2rem, 6vw, 5rem)); border-radius: var(--radius-lg); background: var(--color-surface); - backdrop-filter: blur(16px); + border: 1px solid var(--color-border); box-shadow: var(--shadow-soft); overflow: hidden; position: relative; } body ::selection { - background-color: rgba(51, 197, 122, 0.35); - color: var(--color-accent-contrast); + background-color: rgba(58, 122, 254, 0.18); + color: var(--color-text); } ::-webkit-scrollbar { @@ -58,38 +56,39 @@ body ::selection { } ::-webkit-scrollbar-track { - background: transparent; + background: rgba(216, 222, 237, 0.4); + border-radius: 999px; } ::-webkit-scrollbar-thumb { - background: rgba(43, 156, 105, 0.25); - border-radius: 9999px; + background: rgba(111, 123, 146, 0.35); + border-radius: 999px; } ::-webkit-scrollbar-thumb:hover { - background: rgba(43, 156, 105, 0.4); + background: rgba(111, 123, 146, 0.55); } button:focus, a:focus { - outline: 3px solid rgba(51, 197, 122, 0.45); + outline: 2px solid rgba(58, 122, 254, 0.45); outline-offset: 2px; } @media (max-width: 1024px) { #root { - padding: clamp(0.5rem, 3vw, 1.25rem); + padding: clamp(0.75rem, 4vw, 1.75rem); } .app { - min-height: calc(100vh - clamp(1rem, 6vw, 3rem)); + min-height: calc(100vh - clamp(1.5rem, 7vw, 3.5rem)); border-radius: 18px; } } @media (max-width: 768px) { #root { - padding: clamp(0.5rem, 4vw, 1rem); + padding: clamp(0.5rem, 5vw, 1.2rem); } .app { diff --git a/src/components/MarkdownRenderer.css b/src/components/MarkdownRenderer.css index 4e10f10..60f7b87 100644 --- a/src/components/MarkdownRenderer.css +++ b/src/components/MarkdownRenderer.css @@ -2,172 +2,68 @@ flex: 1; display: flex; flex-direction: column; - background: linear-gradient(180deg, rgba(255, 255, 255, 0.85) 0%, rgba(233, 250, 240, 0.92) 100%); - overflow-y: auto; - position: relative; + background: var(--color-surface); + color: var(--color-text); } .content-area.with-sidebar { - border-left: 1px solid rgba(47, 177, 112, 0.12); + border-left: 1px solid var(--color-border); } .content-header { position: sticky; top: 0; - z-index: 100; - padding: clamp(1.25rem, 3vw, 2rem) clamp(1.25rem, 4vw, 2.5rem) clamp(0.75rem, 2vw, 1.25rem); - background: rgba(255, 255, 255, 0.92); - backdrop-filter: blur(12px); - border-bottom: 1px solid rgba(47, 177, 112, 0.12); + z-index: 10; + padding: 1.75rem clamp(2rem, 5vw, 3rem) 1.25rem; + background: var(--color-surface); + border-bottom: 1px solid var(--color-border); } .breadcrumbs { display: flex; flex-wrap: wrap; - gap: 0.35rem; + gap: 0.45rem; font-size: 0.85rem; color: var(--color-muted); - margin-bottom: 0.75rem; + margin-bottom: 0.8rem; } .breadcrumb-item { display: inline-flex; align-items: center; - gap: 0.35rem; + gap: 0.4rem; } .breadcrumb-separator { - color: rgba(47, 177, 112, 0.35); + color: rgba(31, 42, 68, 0.3); } .breadcrumb-text { - padding: 0.25rem 0.55rem; + padding: 0.2rem 0.55rem; border-radius: 999px; - background: rgba(51, 197, 122, 0.12); - transition: background 0.2s ease, color 0.2s ease; -} - -.breadcrumb-text:hover { - background: rgba(51, 197, 122, 0.22); - color: var(--color-text); + background: rgba(58, 122, 254, 0.08); } .content-title { margin: 0; - font-size: clamp(1.8rem, 3vw, 2.4rem); - font-weight: 700; + font-size: clamp(2rem, 3.5vw, 2.6rem); + font-weight: 600; color: var(--color-text); - letter-spacing: 0.01em; } .content-body { - padding: clamp(1.5rem, 4vw, 3rem) clamp(1.25rem, 6vw, 3.5rem) clamp(2.5rem, 6vw, 4rem); - width: 100%; - max-width: 1200px; - margin: 0 auto; - display: grid; - gap: clamp(2rem, 4vw, 3.5rem); - grid-template-columns: minmax(0, 1fr); -} - -.content-body.with-toc { - grid-template-columns: minmax(0, 1fr) minmax(220px, 260px); + flex: 1; + overflow-y: auto; + display: flex; + justify-content: center; + padding: clamp(2rem, 6vw, 3.5rem); } .markdown-pane { - min-width: 0; -} - -.content-toc { - position: sticky; - top: clamp(6rem, 12vw, 7rem); - align-self: start; - padding: 1.25rem 1.1rem; - border-radius: 18px; - background: rgba(255, 255, 255, 0.84); - border: 1px solid rgba(47, 177, 112, 0.14); - box-shadow: 0 16px 32px rgba(31, 58, 44, 0.12); - max-height: calc(100vh - clamp(8rem, 14vw, 10rem)); - overflow-y: auto; -} - -.content-toc h3 { - margin: 0 0 0.75rem; - font-size: 0.95rem; - font-weight: 700; - color: var(--color-muted); - letter-spacing: 0.05em; - text-transform: uppercase; -} - -.toc-list { - list-style: none; - margin: 0; - padding: 0; - display: flex; - flex-direction: column; - gap: 0.4rem; -} - -.toc-item { - display: block; -} - -.toc-link { - display: block; - padding: 0.35rem 0.6rem; - border-radius: 10px; - color: var(--color-muted); - font-size: 0.9rem; - transition: background 0.2s ease, color 0.2s ease, transform 0.2s ease; -} - -.toc-link.level-2 { - padding-left: 1.15rem; - font-size: 0.85rem; -} - -.toc-link.level-3 { - padding-left: 1.85rem; - font-size: 0.82rem; -} - -.toc-link:hover, -.toc-link.active { - background: rgba(51, 197, 122, 0.18); - color: var(--color-text); - transform: translateX(2px); -} - -.loading-content { - display: flex; - align-items: center; - justify-content: center; - gap: 0.65rem; - padding: 4rem; - color: var(--color-muted); -} - -.loading-spinner { - width: 24px; - height: 24px; - border: 2px solid rgba(51, 197, 122, 0.2); - border-top: 2px solid var(--color-accent); - border-radius: 50%; - animation: spin 1s linear infinite; -} - -@keyframes spin { - from { - transform: rotate(0deg); - } - to { - transform: rotate(360deg); - } + width: min(860px, 100%); } .markdown-content { - color: var(--color-text); line-height: 1.75; font-size: 1rem; } @@ -182,31 +78,31 @@ .markdown-content h4, .markdown-content h5, .markdown-content h6 { - margin: 2.2rem 0 1rem; - font-weight: 700; - line-height: 1.25; + margin: 2rem 0 1rem; + font-weight: 600; color: var(--color-text); position: relative; } .markdown-content h1 { - font-size: clamp(2rem, 3vw, 2.6rem); - border-bottom: 2px solid rgba(47, 177, 112, 0.14); - padding-bottom: 0.75rem; + font-size: clamp(2.1rem, 3vw, 2.8rem); + border-bottom: 2px solid rgba(31, 42, 68, 0.08); + padding-bottom: 0.6rem; } .markdown-content h2 { - font-size: clamp(1.6rem, 2.4vw, 2.1rem); - border-bottom: 1px solid rgba(47, 177, 112, 0.16); - padding-bottom: 0.5rem; + font-size: clamp(1.7rem, 2.5vw, 2.2rem); + border-bottom: 1px solid rgba(31, 42, 68, 0.08); + padding-bottom: 0.45rem; } .markdown-content h3 { - font-size: clamp(1.35rem, 2vw, 1.6rem); + font-size: clamp(1.4rem, 2vw, 1.7rem); } .markdown-content h4 { - font-size: 1.2rem; + font-size: 1.15rem; + letter-spacing: 0.01em; } .heading-anchor { @@ -214,16 +110,16 @@ left: -1.5rem; top: 50%; transform: translateY(-50%); - opacity: 0; font-size: 0.9rem; - color: rgba(47, 177, 112, 0.8); + color: rgba(31, 42, 68, 0.35); + opacity: 0; transition: opacity 0.2s ease, transform 0.2s ease; } +.markdown-content h1:hover .heading-anchor, .markdown-content h2:hover .heading-anchor, .markdown-content h3:hover .heading-anchor, -.markdown-content h4:hover .heading-anchor, -.markdown-content h1:hover .heading-anchor { +.markdown-content h4:hover .heading-anchor { opacity: 1; transform: translate(-4px, -50%); } @@ -232,10 +128,9 @@ .markdown-content ul, .markdown-content ol, .markdown-content blockquote, -.markdown-content table, -.markdown-content pre { - margin-top: 0; - margin-bottom: 1.35rem; +.markdown-content pre, +.markdown-content table { + margin: 0 0 1.35rem; } .markdown-content ul, @@ -248,32 +143,27 @@ } .markdown-content a { - color: var(--color-link); + color: var(--color-accent); text-decoration: underline; text-decoration-thickness: 2px; - text-underline-offset: 4px; -} - -.markdown-content a:hover { - color: var(--color-link-hover); + text-underline-offset: 3px; } .inline-code { display: inline-flex; align-items: center; - padding: 0.1rem 0.35rem; + padding: 0.15rem 0.4rem; border-radius: 6px; - background: rgba(33, 169, 102, 0.12); - border: 1px solid rgba(33, 169, 102, 0.18); + background: rgba(58, 122, 254, 0.08); + border: 1px solid rgba(58, 122, 254, 0.16); color: var(--color-text); font-size: 0.95em; } .code-block-wrapper { - position: relative; - background: #0f2c1f; - border-radius: 16px; - box-shadow: 0 18px 36px rgba(12, 52, 34, 0.45); + background: #f6f8ff; + border: 1px solid rgba(58, 122, 254, 0.15); + border-radius: 14px; overflow: hidden; } @@ -282,75 +172,99 @@ align-items: center; justify-content: space-between; padding: 0.75rem 1rem; - background: rgba(255, 255, 255, 0.04); - border-bottom: 1px solid rgba(255, 255, 255, 0.08); - color: #bcf8d9; - text-transform: uppercase; + background: rgba(58, 122, 254, 0.08); + color: var(--color-muted); font-size: 0.75rem; - letter-spacing: 0.12em; -} - -.code-language { - letter-spacing: 0.1em; + letter-spacing: 0.08em; + text-transform: uppercase; } .code-copy-button { - background: rgba(188, 248, 217, 0.14); - color: #bcf8d9; - border: 1px solid rgba(188, 248, 217, 0.25); - border-radius: 999px; - padding: 0.35rem 0.75rem; - font-size: 0.75rem; + border: 1px solid rgba(58, 122, 254, 0.25); + background: #fff; + color: var(--color-muted); + border-radius: 8px; + padding: 0.35rem 0.7rem; cursor: pointer; - transition: background 0.2s ease, transform 0.2s ease; + transition: all 0.2s ease; } .code-copy-button:hover { - background: rgba(188, 248, 217, 0.24); - transform: translateY(-1px); + color: var(--color-accent); + border-color: rgba(58, 122, 254, 0.5); } .code-copy-button.copied { - background: rgba(188, 248, 217, 0.4); - color: #0f2c1f; + color: var(--color-accent); + border-color: rgba(58, 122, 254, 0.7); } pre { margin: 0; - padding: 1.25rem 1.5rem; + padding: 1.1rem 1.35rem; overflow-x: auto; + font-size: 0.95rem; } pre code { background: transparent !important; - color: #e9fff2; - font-size: 0.95rem; + color: #1f2a44; +} + +.markdown-image { + margin: 1.6rem 0; + text-align: center; +} + +.markdown-image img { + border-radius: 14px; + border: 1px solid rgba(31, 42, 68, 0.1); + box-shadow: 0 18px 38px rgba(31, 42, 68, 0.12); +} + +.markdown-image figcaption { + margin-top: 0.55rem; + font-size: 0.85rem; + color: var(--color-muted); +} + +.markdown-content blockquote { + margin: 1.6rem 0; + padding: 1rem 1.25rem; + border-left: 4px solid rgba(58, 122, 254, 0.45); + background: rgba(58, 122, 254, 0.1); + border-radius: 0 14px 14px 0; + color: var(--color-text); +} + +.markdown-content hr { + border: none; + border-top: 1px dashed rgba(31, 42, 68, 0.12); + margin: 2.25rem 0; } .table-wrapper { - width: 100%; overflow-x: auto; - border-radius: 16px; - background: rgba(255, 255, 255, 0.92); - border: 1px solid rgba(47, 177, 112, 0.14); - box-shadow: 0 14px 28px rgba(31, 58, 44, 0.12); + border-radius: 14px; + border: 1px solid rgba(31, 42, 68, 0.12); + background: #ffffff; } .table-wrapper table { width: 100%; border-collapse: collapse; + min-width: 520px; } .table-wrapper th, .table-wrapper td { padding: 0.85rem 1rem; - border-bottom: 1px solid rgba(47, 177, 112, 0.12); + border-bottom: 1px solid rgba(31, 42, 68, 0.1); text-align: left; } .table-wrapper th { - background: rgba(51, 197, 122, 0.12); - color: var(--color-text); + color: var(--color-muted); font-weight: 600; } @@ -358,205 +272,117 @@ pre code { border-bottom: none; } -.table-wrapper tr:hover td { - background: rgba(51, 197, 122, 0.08); -} - -.custom-blockquote { - margin: 1.75rem 0; - padding: 1.1rem 1.4rem 1.1rem 1.2rem; - border-left: 5px solid rgba(47, 177, 112, 0.6); - border-radius: 0 16px 16px 0; - background: rgba(51, 197, 122, 0.12); - color: var(--color-text); - box-shadow: 0 12px 24px rgba(31, 58, 44, 0.1); -} - -.custom-blockquote strong:first-child { - display: block; - margin-bottom: 0.4rem; -} - -.markdown-content hr { - border: none; - border-top: 1px dashed rgba(47, 177, 112, 0.35); - margin: 2.5rem 0; -} - -.markdown-content img { - border-radius: 16px; - box-shadow: 0 18px 36px rgba(31, 58, 44, 0.18); - margin: 1.5rem auto; -} - -.markdown-image { - margin: 1.5rem 0; - text-align: center; -} - -.markdown-image figcaption { - margin-top: 0.5rem; - font-size: 0.85rem; - color: var(--color-muted); -} - -.custom-blockquote.callout-info { - border-left-color: rgba(70, 199, 150, 0.7); - background: rgba(70, 199, 150, 0.18); -} - -.custom-blockquote.callout-warning { - border-left-color: rgba(255, 187, 92, 0.85); - background: rgba(255, 187, 92, 0.2); -} - -.custom-blockquote.callout-danger { - border-left-color: rgba(255, 107, 107, 0.85); - background: rgba(255, 107, 107, 0.18); -} - -.custom-blockquote.callout-success { - border-left-color: rgba(62, 201, 133, 0.85); - background: rgba(62, 201, 133, 0.2); -} - .external-link { display: inline-flex; align-items: center; - gap: 0.25rem; + gap: 0.3rem; } .external-link-icon { font-size: 0.8rem; } +.loading-content { + display: flex; + align-items: center; + gap: 0.7rem; + padding: 3rem 0; + color: var(--color-muted); +} + +.loading-spinner { + width: 18px; + height: 18px; + border: 2px solid rgba(111, 123, 146, 0.25); + border-top: 2px solid var(--color-accent); + border-radius: 50%; + animation: spin 0.9s linear infinite; +} + +@keyframes spin { + to { + transform: rotate(360deg); + } +} + .welcome-message { display: flex; align-items: center; justify-content: center; padding: clamp(2rem, 6vw, 4rem); - min-height: calc(100vh - clamp(10rem, 16vw, 12rem)); + min-height: calc(100vh - 7rem); } .welcome-content { text-align: center; - max-width: 640px; - padding: clamp(2rem, 6vw, 3rem); - border-radius: 28px; - background: rgba(255, 255, 255, 0.9); - box-shadow: 0 28px 48px rgba(31, 58, 44, 0.16); + max-width: 520px; + padding: 2.4rem; + border-radius: 18px; + background: #ffffff; + border: 1px solid var(--color-border); + box-shadow: 0 24px 48px rgba(86, 105, 141, 0.18); } .welcome-content h1 { - font-size: clamp(2.4rem, 4vw, 3rem); - color: var(--color-text); - margin-bottom: 1rem; + margin-bottom: 0.9rem; + font-size: clamp(2.1rem, 3.2vw, 2.6rem); } .welcome-content p { - font-size: 1.1rem; + margin: 0 auto 1.6rem; color: var(--color-muted); - margin-bottom: 2rem; } .welcome-features { display: grid; - grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); - gap: 1.1rem; + grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); + gap: 0.8rem; } .feature-item { display: flex; align-items: center; justify-content: center; - gap: 0.75rem; - padding: 1rem; - background: rgba(51, 197, 122, 0.12); - border-radius: 16px; - border: 1px solid rgba(47, 177, 112, 0.14); - color: var(--color-text); + gap: 0.6rem; + padding: 0.85rem; + border: 1px solid var(--color-border); + border-radius: 12px; + background: var(--color-surface); + color: var(--color-muted); } .feature-icon { - font-size: 1.5rem; -} - -.katex-display { - padding: 1.25rem; - border-radius: 14px; - background: rgba(51, 197, 122, 0.1); - overflow-x: auto; -} - -.markdown-content .task-list-item { - list-style: none; -} - -.markdown-content .task-list-item input[type='checkbox'] { - margin-right: 0.6rem; - transform: scale(1.1); - accent-color: var(--color-accent); -} - -@media (max-width: 1200px) { - .content-body.with-toc { - grid-template-columns: minmax(0, 1fr); - } - - .content-toc { - position: relative; - top: auto; - max-height: none; - order: -1; - margin-bottom: 1.5rem; - } + font-size: 1.1rem; } @media (max-width: 768px) { .content-header { - padding: 1rem 1.25rem; + padding: 1.2rem 1.5rem 0.9rem; } .content-body { - padding: 1.25rem; + padding: 1.5rem; } - .content-title { - font-size: clamp(1.6rem, 6vw, 2rem); - } - - .markdown-content { - font-size: 0.98rem; + .markdown-pane { + width: 100%; } .heading-anchor { display: none; } - - .welcome-content { - padding: 2rem; - } - - .welcome-features { - grid-template-columns: 1fr; - } } @media (max-width: 480px) { .content-header { - padding: 0.85rem 1rem; + padding: 1rem 1.1rem 0.75rem; } .content-body { padding: 1rem; } - .breadcrumbs { - font-size: 0.8rem; - } - .feature-item { flex-direction: column; - text-align: center; } } diff --git a/src/components/MarkdownRenderer.jsx b/src/components/MarkdownRenderer.jsx index c8a36eb..8ad23d6 100644 --- a/src/components/MarkdownRenderer.jsx +++ b/src/components/MarkdownRenderer.jsx @@ -1,4 +1,4 @@ -import React, { useMemo, useState, useEffect, useCallback } from 'react'; +import React, { useMemo, useState } from 'react'; import ReactMarkdown from 'react-markdown'; import remarkGfm from 'remark-gfm'; import remarkMath from 'remark-math'; @@ -15,6 +15,7 @@ import 'highlight.js/styles/github.css'; function Breadcrumbs({ filePath }) { const breadcrumbs = generateBreadcrumbs(filePath); if (breadcrumbs.length === 0) return null; + return (