From d4106104944a49c51e8ea7c26b0d980689313c16 Mon Sep 17 00:00:00 2001 From: Loong Loong Date: Thu, 18 Sep 2025 01:57:28 +0800 Subject: [PATCH 1/2] =?UTF-8?q?feat:=20=E6=B7=BB=E5=8A=A0=E4=BF=AE?= =?UTF-8?q?=E6=94=B9=E6=8C=89=E9=92=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/components/EditOnGithub.tsx | 24 ++++++++++++++++++++++++ app/docs/[...slug]/page.tsx | 20 ++++++++++++++------ app/layout.tsx | 4 ++++ 3 files changed, 42 insertions(+), 6 deletions(-) create mode 100644 app/components/EditOnGithub.tsx diff --git a/app/components/EditOnGithub.tsx b/app/components/EditOnGithub.tsx new file mode 100644 index 0000000..ccbbee2 --- /dev/null +++ b/app/components/EditOnGithub.tsx @@ -0,0 +1,24 @@ +import Link from "next/link"; + +interface EditOnGithubProps { + href: string; +} + +export function EditOnGithub({ href }: EditOnGithubProps) { + return ( + + + edit + + + ); +} diff --git a/app/docs/[...slug]/page.tsx b/app/docs/[...slug]/page.tsx index f243b8a..a194ca3 100644 --- a/app/docs/[...slug]/page.tsx +++ b/app/docs/[...slug]/page.tsx @@ -4,6 +4,7 @@ import { notFound } from "next/navigation"; import type { Metadata } from "next"; import { getMDXComponents } from "@/mdx-components"; import { GiscusComments } from "@/app/components/GiscusComments"; +import { EditOnGithub } from "@/app/components/EditOnGithub"; interface Param { params: Promise<{ @@ -19,18 +20,25 @@ export default async function DocPage({ params }: Param) { notFound(); } + const encodedPath = page.path + .split("/") + .map((segment) => encodeURIComponent(segment)) + .join("/"); + const editUrl = `https://github.com/InvolutionHell/involutionhell.github.io/edit/main/app/docs/${encodedPath}`; + const Mdx = page.data.body; return ( -

- {page.data.title} -

+
+

+ {page.data.title} +

+ +
-
- -
+
); diff --git a/app/layout.tsx b/app/layout.tsx index c609f04..413a135 100644 --- a/app/layout.tsx +++ b/app/layout.tsx @@ -31,6 +31,10 @@ export default function RootLayout({ + Date: Thu, 18 Sep 2025 02:30:46 +0800 Subject: [PATCH 2/2] =?UTF-8?q?refactor:=20=E6=8F=90=E5=8F=96=20GitHub=20?= =?UTF-8?q?=E7=9B=B8=E5=85=B3=E5=B7=A5=E5=85=B7=E5=87=BD=E6=95=B0=EF=BC=8C?= =?UTF-8?q?=E7=AE=80=E5=8C=96=E6=96=87=E6=A1=A3=E7=BC=96=E8=BE=91=E9=93=BE?= =?UTF-8?q?=E6=8E=A5=E7=94=9F=E6=88=90=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/components/Contribute.tsx | 10 ++---- app/components/EditOnGithub.tsx | 1 + app/docs/[...slug]/page.tsx | 8 ++--- app/layout.tsx | 1 + lib/github.ts | 55 +++++++++++++++++++++++++++++++++ 5 files changed, 63 insertions(+), 12 deletions(-) create mode 100644 lib/github.ts diff --git a/app/components/Contribute.tsx b/app/components/Contribute.tsx index 02254b4..f104e39 100644 --- a/app/components/Contribute.tsx +++ b/app/components/Contribute.tsx @@ -19,17 +19,13 @@ import styles from "./Contribute.module.css"; import { TreeSelect } from "antd"; import type { DefaultOptionType } from "antd/es/select"; import { DataNode } from "antd/es/tree"; - -const REPO_OWNER = "InvolutionHell"; -const REPO_NAME = "involutionhell.github.io"; -const DEFAULT_BRANCH = "main"; -const DOCS_BASE = "app/docs"; +import { buildDocsNewUrl } from "@/lib/github"; type DirNode = { name: string; path: string; children?: DirNode[] }; +// 统一调用工具函数生成 GitHub 新建链接,路径规则与 Edit 按钮一致 function buildGithubNewUrl(dirPath: string, filename: string, title: string) { const file = filename.endsWith(".mdx") ? filename : `${filename}.mdx`; - const fullDir = `${DOCS_BASE}/${dirPath}`.replace(/\/+/g, "/"); const frontMatter = `--- title: ${title || "New Article"} description: @@ -42,7 +38,7 @@ tags: [] Write your content here. `; const params = new URLSearchParams({ filename: file, value: frontMatter }); - return `https://github.com/${REPO_OWNER}/${REPO_NAME}/new/${DEFAULT_BRANCH}/${encodeURIComponent(fullDir)}?${params.toString()}`; + return buildDocsNewUrl(dirPath, params); } // ✅ 用纯文本 label + 一级节点 selectable:false diff --git a/app/components/EditOnGithub.tsx b/app/components/EditOnGithub.tsx index ccbbee2..2e2ec0d 100644 --- a/app/components/EditOnGithub.tsx +++ b/app/components/EditOnGithub.tsx @@ -1,5 +1,6 @@ import Link from "next/link"; +// 复用的编辑链接按钮,统一封装图标与样式 interface EditOnGithubProps { href: string; } diff --git a/app/docs/[...slug]/page.tsx b/app/docs/[...slug]/page.tsx index a194ca3..6db807c 100644 --- a/app/docs/[...slug]/page.tsx +++ b/app/docs/[...slug]/page.tsx @@ -5,6 +5,7 @@ import type { Metadata } from "next"; import { getMDXComponents } from "@/mdx-components"; import { GiscusComments } from "@/app/components/GiscusComments"; import { EditOnGithub } from "@/app/components/EditOnGithub"; +import { buildDocsEditUrl } from "@/lib/github"; interface Param { params: Promise<{ @@ -20,11 +21,8 @@ export default async function DocPage({ params }: Param) { notFound(); } - const encodedPath = page.path - .split("/") - .map((segment) => encodeURIComponent(segment)) - .join("/"); - const editUrl = `https://github.com/InvolutionHell/involutionhell.github.io/edit/main/app/docs/${encodedPath}`; + // 统一通过工具函数生成 Edit 链接,内部已处理中文目录编码 + const editUrl = buildDocsEditUrl(page.path); const Mdx = page.data.body; diff --git a/app/layout.tsx b/app/layout.tsx index 413a135..0bc4091 100644 --- a/app/layout.tsx +++ b/app/layout.tsx @@ -31,6 +31,7 @@ export default function RootLayout({ + {/* 谷歌图标字体用于 Edit 按钮的 material symbol */} (segment ?? "").trim().length > 0) + .join("/") + .replace(/\/+/g, "/") + .replace(/^\/+/, "") + .replace(/\/+$/, ""); +} + +// 将路径逐段 URL 编码,处理中文等特殊字符 +function encodeRepoPath(...segments: (string | undefined)[]) { + const joined = joinPath(...segments); + if (!joined) return ""; + return joined + .split("/") + .map((segment) => encodeURIComponent(segment)) + .join("/"); +} + +// 构建文档的 GitHub 编辑链接 +export function buildDocsEditUrl(relativeDocPath: string) { + const encoded = encodeRepoPath(DOCS_BASE, relativeDocPath); + return `${REPO_BASE_URL}/edit/${DEFAULT_BRANCH}/${encoded}`; +} + +// 构建在 GitHub 新建文档的链接,附带 frontmatter 参数 +export function buildDocsNewUrl(relativeDir: string, params: URLSearchParams) { + const encodedDir = encodeRepoPath(DOCS_BASE, relativeDir); + const query = params.toString(); + const suffix = query ? `?${query}` : ""; + return `${REPO_BASE_URL}/new/${DEFAULT_BRANCH}/${encodedDir}${suffix}`; +} + +// 帮助预览完整 docs 路径(未编码) +export function normalizeDocsPath(relative: string) { + return joinPath(DOCS_BASE, relative); +} + +// 暴露常量给其他场景复用 +export const githubConstants = { + owner: GITHUB_OWNER, + repo: GITHUB_REPO, + defaultBranch: DEFAULT_BRANCH, + docsBase: DOCS_BASE, + repoBaseUrl: REPO_BASE_URL, +};