Skip to content

Commit 986e6a0

Browse files
authored
Merge pull request #58 from InvolutionHell/editButton
添加Edit button,打包github相关函数,lint了文本
2 parents 3b8b284 + e7096ca commit 986e6a0

File tree

5 files changed

+102
-16
lines changed

5 files changed

+102
-16
lines changed

app/components/Contribute.tsx

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -19,17 +19,13 @@ import styles from "./Contribute.module.css";
1919
import { TreeSelect } from "antd";
2020
import type { DefaultOptionType } from "antd/es/select";
2121
import { DataNode } from "antd/es/tree";
22-
23-
const REPO_OWNER = "InvolutionHell";
24-
const REPO_NAME = "involutionhell.github.io";
25-
const DEFAULT_BRANCH = "main";
26-
const DOCS_BASE = "app/docs";
22+
import { buildDocsNewUrl } from "@/lib/github";
2723

2824
type DirNode = { name: string; path: string; children?: DirNode[] };
2925

26+
// 统一调用工具函数生成 GitHub 新建链接,路径规则与 Edit 按钮一致
3027
function buildGithubNewUrl(dirPath: string, filename: string, title: string) {
3128
const file = filename.endsWith(".mdx") ? filename : `${filename}.mdx`;
32-
const fullDir = `${DOCS_BASE}/${dirPath}`.replace(/\/+/g, "/");
3329
const frontMatter = `---
3430
title: ${title || "New Article"}
3531
description:
@@ -42,7 +38,7 @@ tags: []
4238
Write your content here.
4339
`;
4440
const params = new URLSearchParams({ filename: file, value: frontMatter });
45-
return `https://github.com/${REPO_OWNER}/${REPO_NAME}/new/${DEFAULT_BRANCH}/${encodeURIComponent(fullDir)}?${params.toString()}`;
41+
return buildDocsNewUrl(dirPath, params);
4642
}
4743

4844
// ✅ 用纯文本 label + 一级节点 selectable:false

app/components/EditOnGithub.tsx

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import Link from "next/link";
2+
3+
// 复用的编辑链接按钮,统一封装图标与样式
4+
interface EditOnGithubProps {
5+
href: string;
6+
}
7+
8+
export function EditOnGithub({ href }: EditOnGithubProps) {
9+
return (
10+
<Link
11+
href={href}
12+
target="_blank"
13+
rel="noopener noreferrer"
14+
className="inline-flex items-center justify-center rounded-md border border-transparent w-9 h-9 text-muted-foreground transition-colors hover:bg-muted/80 hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2"
15+
aria-label="Edit on GitHub"
16+
>
17+
<span
18+
aria-hidden
19+
className="material-symbols-outlined text-lg flex items-center justify-center"
20+
>
21+
edit
22+
</span>
23+
</Link>
24+
);
25+
}

app/docs/[...slug]/page.tsx

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@ import { notFound } from "next/navigation";
44
import type { Metadata } from "next";
55
import { getMDXComponents } from "@/mdx-components";
66
import { GiscusComments } from "@/app/components/GiscusComments";
7-
import { getContributors } from "@/lib/github";
7+
import { EditOnGithub } from "@/app/components/EditOnGithub";
8+
import { buildDocsEditUrl, getContributors } from "@/lib/github";
89
import { Contributors } from "@/app/components/Contributors";
910

1011
interface Param {
@@ -21,25 +22,26 @@ export default async function DocPage({ params }: Param) {
2122
notFound();
2223
}
2324

25+
// 统一通过工具函数生成 Edit 链接,内部已处理中文目录编码
26+
const editUrl = buildDocsEditUrl(page.path);
2427
// Get file path for contributors
2528
const filePath = "app/docs/" + page.file.path;
26-
2729
// Fetch contributors data on server side
2830
const contributors = await getContributors(filePath);
29-
3031
const Mdx = page.data.body;
3132

3233
return (
3334
<DocsPage toc={page.data.toc}>
3435
<DocsBody>
35-
<h1 className="mb-4 text-3xl font-extrabold tracking-tight md:text-4xl">
36-
{page.data.title}
37-
</h1>
36+
<div className="mb-6 flex flex-col gap-3 border-b border-border pb-6 md:mb-8 md:flex-row md:items-center md:justify-between">
37+
<h1 className="text-3xl font-extrabold tracking-tight md:text-4xl">
38+
{page.data.title}
39+
</h1>
40+
<EditOnGithub href={editUrl} />
41+
</div>
3842
<Mdx components={getMDXComponents()} />
43+
<GiscusComments className="mt-16" />
3944
<Contributors contributors={contributors} />
40-
<section className="mt-16">
41-
<GiscusComments />
42-
</section>
4345
</DocsBody>
4446
</DocsPage>
4547
);

app/layout.tsx

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,11 @@ export default function RootLayout({
3131
<html lang="en" suppressHydrationWarning>
3232
<head>
3333
<link rel="preload" href="/mascot.webp" as="image" type="image/webp" />
34+
{/* 谷歌图标字体用于 Edit 按钮的 material symbol */}
35+
<link
36+
rel="stylesheet"
37+
href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL,GRAD@20..48,100..700,0..1,-50..200&icon_names=edit"
38+
/>
3439
</head>
3540
<body
3641
suppressHydrationWarning

lib/github.ts

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,63 @@
11
import { cache } from "react";
22

3+
// GitHub 相关工具方法:集中维护仓库常量与文档路径生成逻辑
4+
const GITHUB_OWNER = "InvolutionHell";
5+
const GITHUB_REPO = "involutionhell.github.io";
6+
const DEFAULT_BRANCH = "main";
7+
const DOCS_BASE = "app/docs";
8+
9+
const REPO_BASE_URL = `https://github.com/${GITHUB_OWNER}/${GITHUB_REPO}`;
10+
11+
// 拼接路径并清理多余斜杠,避免出现 // 或首尾斜杠
12+
function joinPath(...segments: (string | undefined)[]) {
13+
return segments
14+
.filter((segment) => (segment ?? "").trim().length > 0)
15+
.join("/")
16+
.replace(/\/+/g, "/")
17+
.replace(/^\/+/, "")
18+
.replace(/\/+$/, "");
19+
}
20+
21+
// 将路径逐段 URL 编码,处理中文等特殊字符
22+
function encodeRepoPath(...segments: (string | undefined)[]) {
23+
const joined = joinPath(...segments);
24+
if (!joined) return "";
25+
return joined
26+
.split("/")
27+
.map((segment) => encodeURIComponent(segment))
28+
.join("/");
29+
}
30+
31+
// 构建文档的 GitHub 编辑链接
32+
export function buildDocsEditUrl(relativeDocPath: string) {
33+
const encoded = encodeRepoPath(DOCS_BASE, relativeDocPath);
34+
return `${REPO_BASE_URL}/edit/${DEFAULT_BRANCH}/${encoded}`;
35+
}
36+
37+
// 构建在 GitHub 新建文档的链接,附带 frontmatter 参数
38+
export function buildDocsNewUrl(relativeDir: string, params: URLSearchParams) {
39+
const encodedDir = encodeRepoPath(DOCS_BASE, relativeDir);
40+
const query = params.toString();
41+
const suffix = query ? `?${query}` : "";
42+
return `${REPO_BASE_URL}/new/${DEFAULT_BRANCH}/${encodedDir}${suffix}`;
43+
}
44+
45+
// 帮助预览完整 docs 路径(未编码)
46+
export function normalizeDocsPath(relative: string) {
47+
return joinPath(DOCS_BASE, relative);
48+
}
49+
50+
// 暴露常量给其他场景复用
51+
export const githubConstants = {
52+
owner: GITHUB_OWNER,
53+
repo: GITHUB_REPO,
54+
defaultBranch: DEFAULT_BRANCH,
55+
docsBase: DOCS_BASE,
56+
repoBaseUrl: REPO_BASE_URL,
57+
};
58+
59+
60+
361
// Define contributor data structure
462
interface Contributor {
563
login: string;

0 commit comments

Comments
 (0)