diff --git a/src/plugins/remote-gh-viewer-plugin.ts b/src/plugins/remote-gh-viewer-plugin.ts
new file mode 100644
index 000000000..67cf9d9cf
--- /dev/null
+++ b/src/plugins/remote-gh-viewer-plugin.ts
@@ -0,0 +1,191 @@
+import type { LoadContext, Plugin } from "@docusaurus/types";
+import * as fs from "fs";
+import * as path from "path";
+import { unified } from "unified";
+import remarkParse from "remark-parse";
+import remarkGfm from "remark-gfm";
+import remarkRehype from "remark-rehype";
+import rehypeStringify from "rehype-stringify";
+import rehypeRaw from "rehype-raw";
+
+interface RemoteGHConfig {
+ "remote-repo": string;
+ file: string;
+ version: Record
;
+}
+
+interface FetchedContent {
+ config: RemoteGHConfig;
+ configPath: string;
+ versions: Record;
+}
+
+interface PluginContent {
+ configs: FetchedContent[];
+}
+
+interface RemoteGHData {
+ repo: string;
+ file: string;
+ versions: Record;
+ versionList: string[];
+}
+
+/**
+ * 将 Markdown 转换为 HTML
+ */
+async function markdownToHtml(markdown: string): Promise {
+ const result = await unified()
+ .use(remarkParse)
+ .use(remarkGfm)
+ .use(remarkRehype, { allowDangerousHtml: true })
+ .use(rehypeRaw)
+ .use(rehypeStringify)
+ .process(markdown);
+
+ return String(result);
+}
+
+/**
+ * 生成配置文件的唯一标识符
+ */
+function getConfigKey(config: RemoteGHConfig): string {
+ return `${config["remote-repo"]}:${config.file}`;
+}
+
+/**
+ * 从 GitHub 拉取文件内容
+ */
+async function fetchGitHubContent(repo: string, commit: string, filePath: string): Promise {
+ const url = `https://raw.githubusercontent.com/${repo}/${commit}/${filePath}`;
+ console.log(`[RemoteGHViewer] Fetching: ${url}`);
+
+ const response = await fetch(url);
+ if (!response.ok) {
+ throw new Error(`Failed to fetch ${url}: ${response.status} ${response.statusText}`);
+ }
+ return await response.text();
+}
+
+/**
+ * 递归扫描目录查找 .remote-gh.json 文件
+ */
+function scanForConfigs(dir: string, configs: string[] = []): string[] {
+ if (!fs.existsSync(dir)) {
+ return configs;
+ }
+
+ const entries = fs.readdirSync(dir, { withFileTypes: true });
+
+ for (const entry of entries) {
+ const fullPath = path.join(dir, entry.name);
+ if (entry.isDirectory() && !entry.name.startsWith(".") && entry.name !== "node_modules") {
+ scanForConfigs(fullPath, configs);
+ } else if (entry.isFile() && entry.name.endsWith(".remote-gh.json")) {
+ configs.push(fullPath);
+ }
+ }
+
+ return configs;
+}
+
+/**
+ * RemoteGHViewer 插件
+ * 在构建时从 GitHub 拉取远程内容并缓存
+ */
+export default function remoteGHViewerPlugin(context: LoadContext): Plugin {
+ const { siteDir } = context;
+
+ return {
+ name: "remote-gh-viewer-plugin",
+
+ async loadContent(): Promise {
+ // 扫描所有文档目录
+ const docDirs = ["docs", "docs-java", "docs-bedrock", "docs-about"];
+ const allConfigPaths: string[] = [];
+
+ for (const docDir of docDirs) {
+ const fullPath = path.join(siteDir, docDir);
+ scanForConfigs(fullPath, allConfigPaths);
+ }
+
+ console.log(`[RemoteGHViewer] Found ${allConfigPaths.length} config files`);
+
+ const fetchedConfigs: FetchedContent[] = [];
+
+ for (const configPath of allConfigPaths) {
+ try {
+ const configContent = fs.readFileSync(configPath, "utf-8");
+ const config: RemoteGHConfig = JSON.parse(configContent);
+
+ const versions: Record = {};
+
+ // 并行拉取所有版本内容并转换为 HTML
+ const versionEntries = Object.entries(config.version);
+ const fetchPromises = versionEntries.map(async ([version, commit]) => {
+ try {
+ const markdown = await fetchGitHubContent(config["remote-repo"], commit, config.file);
+ const html = await markdownToHtml(markdown);
+ return { version, content: html };
+ } catch (error) {
+ console.error(`[RemoteGHViewer] Failed to fetch ${version}:`, error);
+ return {
+ version,
+ content: `无法加载版本 ${version} 的内容
`
+ };
+ }
+ });
+
+ const results = await Promise.all(fetchPromises);
+ for (const { version, content } of results) {
+ versions[version] = content;
+ }
+
+ fetchedConfigs.push({
+ config,
+ configPath: path.relative(siteDir, configPath),
+ versions
+ });
+
+ console.log(
+ `[RemoteGHViewer] Loaded ${versionEntries.length} versions for ${config["remote-repo"]}/${config.file}`
+ );
+ } catch (error) {
+ console.error(`[RemoteGHViewer] Error processing ${configPath}:`, error);
+ }
+ }
+
+ return { configs: fetchedConfigs };
+ },
+
+ async contentLoaded({ content, actions }): Promise {
+ const { setGlobalData } = actions;
+
+ // 创建汇总数据,以配置标识符为键
+ const allData: Record = {};
+
+ for (const fetchedConfig of content.configs) {
+ const configKey = getConfigKey(fetchedConfig.config);
+ allData[configKey] = {
+ repo: fetchedConfig.config["remote-repo"],
+ file: fetchedConfig.config.file,
+ versions: fetchedConfig.versions,
+ versionList: Object.keys(fetchedConfig.config.version)
+ };
+ }
+
+ // 使用 setGlobalData 存储数据,组件通过 useGlobalData 访问
+ setGlobalData(allData);
+
+ console.log(`[RemoteGHViewer] Set global data with ${Object.keys(allData).length} configs`);
+ },
+
+ getPathsToWatch(): string[] {
+ // 监听配置文件变化
+ const docDirs = ["docs", "docs-java", "docs-bedrock", "docs-about"];
+ return docDirs.map((dir) => path.join(siteDir, dir, "**/*.remote-gh.json"));
+ }
+ };
+}
+
+module.exports = remoteGHViewerPlugin;
diff --git a/src/theme/Navbar/index.js b/src/theme/Navbar/index.js
deleted file mode 100644
index b1e5855ee..000000000
--- a/src/theme/Navbar/index.js
+++ /dev/null
@@ -1,93 +0,0 @@
-import React, { useEffect, useState } from "react";
-import Navbar from "@theme-original/Navbar";
-import GitHubButton from "@site/src/components/GitHubButton";
-import { useThemeConfig } from "@docusaurus/theme-common";
-
-export default function NavbarWrapper(props) {
- const {
- navbar: { items }
- } = useThemeConfig();
-
- // 追踪窗口宽度
- const [isMobile, setIsMobile] = useState(false);
-
- // 过滤掉原始的GitHub链接项
- const filteredItems = items.filter(
- (item) => !(item.className === "header-github-link" && item.href?.includes("github.com"))
- );
-
- // 监听窗口大小变化
- useEffect(() => {
- const checkMobile = () => {
- setIsMobile(window.innerWidth <= 996);
- };
-
- // 初始检查
- checkMobile();
-
- // 监听窗口大小变化
- window.addEventListener("resize", checkMobile);
-
- return () => {
- window.removeEventListener("resize", checkMobile);
- };
- }, []);
-
- // 在DOM操作后插入GitHub按钮(仅在非移动设备上)
- useEffect(() => {
- if (isMobile) {
- // 移动设备上,移除任何可能存在的GitHub按钮
- const existingButton = document.querySelector("#github-button-container");
- if (existingButton) {
- existingButton.parentNode.removeChild(existingButton);
- }
- return;
- }
-
- const insertGitHubButton = () => {
- // 找到主题切换按钮
- const colorModeToggle = document.querySelector(".navbar__items--right .colorModeToggle");
- if (!colorModeToggle) return;
-
- // 检查是否已经存在GitHub按钮
- const existingButton = document.querySelector("#github-button-container");
- if (existingButton) return;
-
- // 创建一个新的包装器来包含GitHub按钮
- const wrapper = document.createElement("div");
- wrapper.className = "navbar__item";
-
- // 创建GitHub按钮的容器
- const githubButtonContainer = document.createElement("div");
- githubButtonContainer.id = "github-button-container";
-
- // 将GitHub按钮容器添加到包装器中
- wrapper.appendChild(githubButtonContainer);
-
- // 将包装器添加到主题切换按钮前面
- colorModeToggle.parentNode.insertBefore(wrapper, colorModeToggle);
-
- // 渲染React组件到容器中
- const React = require("react");
- const ReactDOM = require("react-dom");
- ReactDOM.render(, githubButtonContainer);
- };
-
- // 初始插入和页面变化时重新插入
- insertGitHubButton();
-
- // 监听导航栏的变化
- const observer = new MutationObserver(insertGitHubButton);
- const navbar = document.querySelector(".navbar__items--right");
- if (navbar) {
- observer.observe(navbar, { childList: true, subtree: true });
- }
-
- return () => {
- // 组件卸载时停止观察
- observer.disconnect();
- };
- }, [isMobile]); // 依赖isMobile,当设备类型变化时重新运行
-
- return ;
-}