diff --git a/.claude/settings.local.json b/.claude/settings.local.json new file mode 100644 index 0000000..7e63862 --- /dev/null +++ b/.claude/settings.local.json @@ -0,0 +1,22 @@ +{ + "permissions": { + "allow": [ + "Bash(npm run:*)", + "Bash(npm install:*)", + "Bash(netstat -ano)", + "Bash(powershell -Command \"Get-NetTCPConnection -LocalPort 3000 -ErrorAction SilentlyContinue | Select-Object LocalPort, State\")", + "Bash(findstr \":3000\")", + "Bash(findstr \"LISTENING\")", + "Bash(git config:*)", + "Bash(git fetch:*)", + "Bash(git add:*)", + "Bash(git commit:*)", + "Bash(git push:*)", + "Bash(start:*)", + "Bash(git remote:*)", + "Bash(ssh-keygen:*)", + "Bash(ssh -T git@gitlink.org.cn)", + "Bash(git branch:*)" + ] + } +} diff --git a/Dockerfile b/Dockerfile index 597e466..09b6efe 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,43 +1,10 @@ -FROM crpi-1x701qgqjia2gdeu.cn-chengdu.personal.cr.aliyuncs.com/gitlink-help-center/gitlink-help-center:node-20-alpine +FROM node:18-alpine LABEL maintainer="yuankaifneg <2894340009@qq.com>" -# 设置为root用户以安装系统依赖 -USER root +WORKDIR /gitlink_help_center -# 安装必要的系统依赖 -RUN yum install -y \ - git \ - python3 \ - make \ - gcc-c++ \ - bash && \ - yum clean all +COPY ./ /gitlink_help_center/ -# 设置工作目录 -WORKDIR /app - -# 优先复制package.json和package-lock.json以利用Docker缓存 -COPY package.json package-lock.json ./ - -# 安装依赖(忽略peer依赖冲突) -RUN npm install --legacy-peer-deps - -# 复制项目文件 -COPY . . - -# 构建应用 -RUN npm run build - -# 暴露端口 -EXPOSE 3000 - -# 设置环境变量 -ENV NODE_ENV=production -ENV PORT=3000 - -# 健康检查 -HEALTHCHECK --interval=30s --timeout=3s --start-period=40s --retries=3 \ - CMD node -e "require('http').get('http://localhost:3000', (r) => {process.exit(r.statusCode === 200 ? 0 : 1)})" - -# 启动应用 +RUN yarn install +RUN npm run build -- --locale zh-cn CMD ["npm", "run", "serve"] diff --git a/docs/intro.md b/docs/intro.md index f8aec7a..73610ec 100644 --- a/docs/intro.md +++ b/docs/intro.md @@ -32,7 +32,7 @@ GitLink(确实开源)是CCF官方指定的开源创新服务平台,旨在

代码库管理

-

代码库使用及设置[8个文档]

+

代码库使用及设置[9个文档]

@@ -60,9 +60,9 @@ GitLink(确实开源)是CCF官方指定的开源创新服务平台,旨在

维基(Wiki)使用及设置[2个文档]

- -

Bot市场

-

Bot市场使用及设置[4个文档]

+
+

bot市场

+

bot市场使用及设置[3个文档]

diff --git a/docs/个人主页建站/站点创建流程.md b/docs/个人主页建站/站点创建流程.md index 7a73db6..292375e 100644 --- a/docs/个人主页建站/站点创建流程.md +++ b/docs/个人主页建站/站点创建流程.md @@ -8,39 +8,39 @@ sidebar_position: 1 ![img](../../static/img/建站工具/1.png) -点击左测面板中 个人建站 - 我的站点 +点击左侧面板中 个人建站 - 我的站点 ![img](../../static/img/建站工具/3.png) ### 创建站点 -在我的站点界面点击 新建站点 按钮,进入新建站点界面 +在**我的站点**界面点击**新建站点**按钮,进入新建站点界面 -在新建站点界面输入站点名称,此名称将在我的站点列表中展示 +在新建站点界面输入站点名称,此名称将在**我的站点**的**站点列表**中展示 并且选择对应的建站工具与主题,我们为您提供了3种不同的工具,每个工具10种主题,一共30种供您挑选 ![img](../../static/img/建站工具/4.png) -填写完毕后,点击页面下方蓝色按钮: 创建站点 +填写完毕后,点击页面下方蓝色按钮**创建站点** ![img](../../static/img/建站工具/5.png) 这样您就拥有了一个网站,并且有了一个代码仓库。 -在仓库的 服务 一栏中 个人建站服务的操作界面,这里您可以查看一些您的站点状态、站点名称、网站地址、建站工具、建站时间 +在仓库的**服务**一栏中**个人建站**服务的操作界面,这里您可以查看一些您的站点状态、站点名称、网站地址、建站工具、建站时间。 ### 部署站点 ![img](../../static/img/建站工具/6.png) -点击去部署按钮,选择想要部署的分支后点击确定 +点击**去部署**按钮,选择想要部署的分支后点击**确定** ![img](../../static/img/建站工具/7.png) -等待程序运行一会儿后,会返回一些服务器部署信息给您 +等待程序运行一会儿后,会返回一些服务器部署信息给您,部署成功后您就可以访问站点了。 -部署成功后您就可以访问站点了。点击网站地址就可以跳转 +点击网站地址就可以跳转 ![img](../../static/img/建站工具/8.png) diff --git a/docs/代码库管理/成员管理.md b/docs/代码库管理/成员管理.md index cbf6199..4024432 100644 --- a/docs/代码库管理/成员管理.md +++ b/docs/代码库管理/成员管理.md @@ -3,15 +3,15 @@ sidebar_label: '成员管理' sidebar_position: 7 --- ### **1. 成员管理入口** -在仓库主页,点击“仓库设置”按键,再点击”成员管理“按键,即可进入成员管理模块,如下图所示。 +在仓库主页,点击**仓库设置**按键,再点击**成员管理**按键,即可进入成员管理模块,如下图所示。 ![](../../static/img/代码库管理/成员管理/成员管理入口.png)
### **2. 筛选、搜索项目成员** -进入成员管理模块后,可以通过”角色筛选“按键来筛选项目成员类型,通过”搜索“按键可以检索具体的项目成员,如下图所示。 +进入成员管理模块后,可以通过**角色筛选**按键来筛选项目成员类型,通过**搜索**按键可以检索具体的项目成员,如下图所示。 ![](../../static/img/代码库管理/成员管理/筛选、搜索项目成员.png)
-### **3. 筛选、搜索项目成员** -进入成员管理模块后,可以通过”添加成员“按键来添加项目成员,左侧搜索框检索到具体用户并选中后,单击”添加成员“按键即可成功添加项目成员。 +### **3. 添加成员** +进入成员管理模块后,可以通过**添加成员**按键来添加项目成员,左侧搜索框检索到具体用户并选中后,单击**添加成员**按键即可成功添加项目成员。 ![](../../static/img/代码库管理/成员管理/添加成员.png)
### **4. 项目成员权限管理** @@ -19,5 +19,5 @@ sidebar_position: 7 ![](../../static/img/代码库管理/成员管理/项目成员权限管理.png)
### **5. 删除项目成员** -进入成员管理模块后,单击项目成员右侧的”删除“按键,可以删除改名项目成员,如下图所示。 +进入成员管理模块后,单击项目成员右侧的**删除**按键,可以删除改名项目成员,如下图所示。 ![](../../static/img/代码库管理/成员管理/删除项目成员.png)
diff --git a/docs/合并请求/合并请求关联疑修.md b/docs/合并请求/合并请求关联疑修.md index ac29313..5051252 100644 --- a/docs/合并请求/合并请求关联疑修.md +++ b/docs/合并请求/合并请求关联疑修.md @@ -3,4 +3,6 @@ sidebar_label: '合并请求关联疑修' sidebar_position: 5 --- -# 合并请求关联疑修 \ No newline at end of file +# 合并请求关联疑修 + +该功能还在开发完善中,敬请期待...... \ No newline at end of file diff --git a/docs/平台公告/平台公告.md b/docs/平台公告/平台公告.md index 3b451a8..caff2c4 100644 --- a/docs/平台公告/平台公告.md +++ b/docs/平台公告/平台公告.md @@ -1,4 +1,12 @@ --- sidebar_label: '平台公告' sidebar_position: 1 ---- \ No newline at end of file +--- + +# 平台公告 + +GitLink帮助中心致力于帮助开发者快速熟悉平台功能,掌握开源协作的正确方法。在这里,您可以找到从账号注册到项目管理的完整指南,也可以通过实际使用中发现平台存在的问题并提出改进建议。我们希望通过文档与社区的共同努力,让GitLink成为更好的开源创新服务平台。如果您在使用过程中遇到任何问题,欢迎在平台中提交疑修(Issue)获得帮助。 + +帮助中心项目地址是:https://gitlink.org.cn/Gitlink/gitlink_help_center/ + +开发者可以先复刻帮助中心项目,然后在本地进行开发。 \ No newline at end of file diff --git a/docs/第三方服务/跨平台代码同步.md b/docs/第三方服务/跨平台代码同步.md index c63abac..7e9d875 100644 --- a/docs/第三方服务/跨平台代码同步.md +++ b/docs/第三方服务/跨平台代码同步.md @@ -33,7 +33,7 @@ Gitee配置方式为:个人头像→设置→私人令牌→生成新令牌→ ![5.配置webhook](../../static/img/reposyncer/5.配置webhook.jpg) -②访问点击前往按钮前往目标仓库webhook页新建一个webhook,以github为例 +②访问“点击前往”按钮前往目标仓库webhook页新建一个webhook,以github为例 ![6.webhook示例](../../static/img/reposyncer/6.webhook示例.png) diff --git a/docs/组织管理/组织创建及设置.md b/docs/组织管理/组织创建及设置.md index b39a71b..fdb270b 100644 --- a/docs/组织管理/组织创建及设置.md +++ b/docs/组织管理/组织创建及设置.md @@ -2,13 +2,13 @@ sidebar_label: '组织创建及设置' sidebar_position: 2 --- -# 组织创建(Organization Creation) +# 组织创建 - 在 *https://www.gitlink.org.cn* 页面点击顶部导航栏的“+”符号可以进行组织新建操作。 + 在 https://www.gitlink.org.cn 页面点击顶部导航栏的“+”符号可以进行组织新建操作。 ![](/img/Org/imageOrg1.png) - 在新建页面中输入**组织账号**、**组织名称**、**组织描述**、**所在地区**、**可见性**以及**组织头像**等信息后,点击“**创建组织**”按钮完成组织的创建。 + 在新建页面中输入组织账号、组织名称、组织描述、所在地区、可见性以及组织头像等信息后,点击**创建组织**按钮完成组织的创建。 ![](/img/Org/imageOrg2.png) diff --git a/docs/组织管理/组织团队管理.md b/docs/组织管理/组织团队管理.md index ce0c356..ab8dd1a 100644 --- a/docs/组织管理/组织团队管理.md +++ b/docs/组织管理/组织团队管理.md @@ -7,7 +7,7 @@ sidebar_position: 3 ## 创建组织团队 点击组织信息页面中的“新建团队”按钮可以创建属于该组织的团队(平台默认创建“Owners”团队,成员为组织的创建者)。 -在团队新建页面,输入团队标识、团队名称、团队描述、项目权限以及版本库权限等信息后,点击“新建团队”完成团队的创建。 +在团队新建页面,输入团队标识、团队名称、团队描述、项目权限以及版本库权限等信息后,点击 **新建团队** 按钮完成团队的创建。 ![](/img/Org/imageOrg9.png) @@ -19,7 +19,7 @@ sidebar_position: 3 ## 管理组织团队 -点击团队信息页面中的“团队设置”按钮可以对团队进行管理 +点击团队信息页面中的 **团队设置** 按钮可以对团队进行管理。 - 基本设置:修改项目的基本信息,如名称和描述等。 ![](/img/Org/imageOrg10.png) diff --git a/docs/组织管理/组织成员管理.md b/docs/组织管理/组织成员管理.md index 8c78b2b..0118466 100644 --- a/docs/组织管理/组织成员管理.md +++ b/docs/组织管理/组织成员管理.md @@ -2,9 +2,9 @@ sidebar_label: '组织成员管理' sidebar_position: 4 --- -# 成员管理(Members Management) +# 成员管理 - 在 个人所管理的项目当中的**仓库设置**当中的**成员管理**可以进入成员管理界面 + 在个人所管理的项目当中的**仓库设置**当中的**成员管理**可以进入成员管理界面 ![](/img/Org/imageOrg14.png) diff --git a/docs/维基/模板导入及导出.md b/docs/维基/模板导入及导出.md index 8245753..3182e17 100644 --- a/docs/维基/模板导入及导出.md +++ b/docs/维基/模板导入及导出.md @@ -3,9 +3,7 @@ sidebar_label: '模板导入及导出' sidebar_position: 2 --- -# 确实开源帮助中心 - -## 模板的导入及导出管理 +# 模板导入及导出 #### 1.模板导入 通过点击wiki界面的**导入模板**按钮即可导入本地的txt,markdown等格式文件进行Wiki文档的创建,当前平台此项功能尚在开发测试环节 [](/img/wiki/img4.png) diff --git a/docs/维基/维基页面管理.md b/docs/维基/维基页面管理.md index 976a092..bd45a88 100644 --- a/docs/维基/维基页面管理.md +++ b/docs/维基/维基页面管理.md @@ -4,20 +4,21 @@ sidebar_position: 1 --- -# 确实开源帮助中心 +# 维基页面管理 -## 维基界面管理 #### 1.维基界面 -GitLink项目安排了专门的**维基(Wiki)界面**来展示项目的一些情况 -[](/img/wiki/img1.png) +GitLink项目安排了专门的**维基(Wiki)界面**来展示项目的一些情况。 +![](/img/wiki/img1.png) #### 2.创建维基内容 -在初始化的维基界面当中点击**创建Wiki文档**或者**导入模板**即可进行Wiki文档的编辑 +在初始化的维基界面当中点击**创建Wiki文档**或者**导入模板**即可进行Wiki文档的编辑。
+![](/img/wiki/img4.png) + #### 3.进行Wiki文档的编辑 点击**创建Wiki文档**后即跳转到编辑界面,初始内容为空白的文档 -[](/img/wiki/img3.png) -也可以通过勾选*添加模板*来进行模板的导入,平台提供的模板包括*周报*和*月报*的格式 -[](/img/wiki/img2.png) -完成编辑后点击左下角的的保存即可 \ No newline at end of file +![](/img/wiki/img3.png) +也可以通过勾选**添加模板**来进行模板的导入,平台提供的模板包括*周报*和*月报*的格式 +![](/img/wiki/img2.png) +完成编辑后点击左下角的的**保存**即可 \ No newline at end of file diff --git a/docs/通知/通知简介.md b/docs/通知/通知简介.md index 278389b..83130ba 100644 --- a/docs/通知/通知简介.md +++ b/docs/通知/通知简介.md @@ -3,9 +3,8 @@ sidebar_label: '通知简介' sidebar_position: 1 --- -# 确实开源帮助中心 +# 通知简介 -## 通知简介 #### 1.通知类型 GitLink将通知分为“系统通知”和“@我”的两种类型: * 系统通知包括“我的状态”、“我创建的或负责的”、“我管理的仓库”三种类型的通知: @@ -25,5 +24,5 @@ GitLink将通知分为“系统通知”和“@我”的两种类型:
-点击通知按钮可以进入消息通知界面,“我的通知”界面可以进行“进查看未读消息”和“所有消息一键已读”的选择。 +点击“通知”按钮可以进入消息通知界面,“我的通知”界面可以进行“仅看未读消息”和“所有系统通知一键已读”的选择。 ![](/img/notice/my_notice2.png) \ No newline at end of file diff --git a/docs/通知/通知设置.md b/docs/通知/通知设置.md index bfde209..b50a036 100644 --- a/docs/通知/通知设置.md +++ b/docs/通知/通知设置.md @@ -3,19 +3,16 @@ sidebar_label: '通知设置' sidebar_position: 2 --- - -# 确实开源帮助中心 - -## 通知设置 +# 通知设置 #### 1.进入通知设置界面 -通过点击首页的通知按钮进入通知设置界面; +通过点击首页的通知按钮进入通知设置界面 ![](/img/notice/home_notice.png)
-或在头像下拉列表中选择设置可以进入消息通知设置界面; +或在头像下拉列表中选择设置可以进入消息通知设置界面 ![](/img/notice/into_notice.png) #### 2.进行通知设置 -通过“通知管理”可以对接受通知的方式进行设置,默认所有通知都是通过站内信的方式接受,可以通过勾选为重要的通知类型增加邮件接受方式。 +通过**通知管理**可以对接受通知的方式进行设置,默认所有通知都是通过站内信的方式接受,可以通过勾选为重要的通知类型增加邮件接受方式。 ![](/img/notice/notice_set.png) \ No newline at end of file diff --git a/docusaurus.config.js b/docusaurus.config.js index c1a620d..424ef17 100644 --- a/docusaurus.config.js +++ b/docusaurus.config.js @@ -185,23 +185,22 @@ module.exports = { ], themes: [ // ... Your other themes. - // Local search plugin temporarily disabled due to compatibility issues with Docusaurus 3.9.2 - // [ - // require.resolve("@easyops-cn/docusaurus-search-local"), - // { - // // ... Your options. - // // `hashed` is recommended as long-term-cache of index file is possible. - // hashed: true, - // language: ["en", "zh"], - // highlightSearchTermsOnTargetPage: true, - // blogRouteBasePath: "/", - // explicitSearchResultPath: true, - // // For Docs using Chinese, The `language` is recommended to set to: - // // ``` - // // language: ["en", "zh"], - // // ``` - // }, - // ], + [ + require.resolve("@easyops-cn/docusaurus-search-local"), + { + // ... Your options. + // `hashed` is recommended as long-term-cache of index file is possible. + hashed: true, + language: ["en", "zh"], + highlightSearchTermsOnTargetPage: true, + blogRouteBasePath: "/", + explicitSearchResultPath: true, + // For Docs using Chinese, The `language` is recommended to set to: + // ``` + // language: ["en", "zh"], + // ``` + }, + ], ], i18n: { defaultLocale: 'zh-cn', diff --git a/gitlink_help_center b/gitlink_help_center new file mode 160000 index 0000000..2936750 --- /dev/null +++ b/gitlink_help_center @@ -0,0 +1 @@ +Subproject commit 293675001acfe7c74caa0bcf78765ec29034c715 diff --git a/package-lock.json b/package-lock.json index d3f4f45..e919ab2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "docusaurus", - "version": "0.0.0", + "version": "3.0.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "docusaurus", - "version": "0.0.0", + "version": "3.0.0", "dependencies": { "@cmfcmf/docusaurus-search-local": "1.1.0", "@docusaurus/core": "3.9.2", @@ -26,7 +26,7 @@ "react-modal": "3.16.1" }, "engines": { - "node": ">=14.18.1 <=18.x" + "node": ">=18.x" } }, "node_modules/@algolia/abtesting": { @@ -19901,13 +19901,6 @@ "url": "https://opencollective.com/webpack" } }, - "node_modules/search-insights": { - "version": "2.17.3", - "resolved": "https://registry.npmjs.org/search-insights/-/search-insights-2.17.3.tgz", - "integrity": "sha512-RQPdCYTa8A68uM2jwxoY842xDhvx3E5LFL1LxvxCNMev4o5mLuokczhzjAgGwUZBAmOKZknArSxLKmXtIi2AxQ==", - "license": "MIT", - "peer": true - }, "node_modules/section-matter": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/section-matter/-/section-matter-1.0.0.tgz", @@ -20994,20 +20987,6 @@ "is-typedarray": "^1.0.0" } }, - "node_modules/typescript": { - "version": "5.9.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", - "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", - "license": "Apache-2.0", - "peer": true, - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=14.17" - } - }, "node_modules/undici": { "version": "7.22.0", "resolved": "https://registry.npmjs.org/undici/-/undici-7.22.0.tgz", diff --git a/sidebars.js b/sidebars.js index 889a90e..a055208 100644 --- a/sidebars.js +++ b/sidebars.js @@ -1,9 +1,8 @@ module.exports = { - DocsSidebar: [ + docs: [ { - type: 'doc', - id: 'index', - label: 'Docs', - } + type: 'autogenerated', + dirName: '.', // 自动生成 docs/ 下所有文档的侧边栏 + }, ], -}; +}; \ No newline at end of file diff --git a/src/components/VoteButtons.js b/src/components/VoteButtons.js new file mode 100644 index 0000000..8fd610d --- /dev/null +++ b/src/components/VoteButtons.js @@ -0,0 +1,151 @@ +import { useState, useEffect } from 'react'; + +const GITEE_API = 'https://gitee.com/api/v5/repos/camelliamc/gitlink-feedback'; +const TOKEN = 'f8433b20f2a07a28cf95aa0e17edfac4'; + +const getDocTitle = (path) => { + const cleanPath = path.replace(/^\//, ''); + return `Vote_${cleanPath.replace(/\//g, '_')}`; +}; + +export default function VoteButtons() { + const [upvotes, setUpvotes] = useState(0); + const [downvotes, setDownvotes] = useState(0); + const [userVote, setUserVote] = useState(null); // null | 'up' | 'down' + const [docPath, setDocPath] = useState(''); + const [loading, setLoading] = useState(false); + + useEffect(() => { + const path = window.location.pathname; + setDocPath(path); + const stored = localStorage.getItem(`vote_${path}`); + if (stored === 'up' || stored === 'down') { + setUserVote(stored); + } + fetchVotes(path); + }, []); + + const fetchVotes = async (path) => { + try { + const res = await fetch(`${GITEE_API}/issues?access_token=${TOKEN}&state=open&labels=vote`); + const data = await res.json(); + const title = getDocTitle(path); + const issue = data.find(i => i.title === title); + + if (issue) { + const labels = issue.labels || []; + const upLabel = labels.find(l => l.name.startsWith('up:')); + const downLabel = labels.find(l => l.name.startsWith('down:')); + if (upLabel) setUpvotes(parseInt(upLabel.name.split(':')[1]) || 0); + if (downLabel) setDownvotes(parseInt(downLabel.name.split(':')[1]) || 0); + } + } catch (e) { + console.error('获取投票失败:', e); + } + }; + + const updateGiteeIssue = async (newUp, newDown) => { + const title = getDocTitle(docPath); + const res = await fetch(`${GITEE_API}/issues?access_token=${TOKEN}&state=open&labels=vote`); + const data = await res.json(); + const existingIssue = data.find(i => i.title === title); + const labels = [`vote`, `up:${newUp}`, `down:${newDown}`]; + + if (existingIssue) { + await fetch(`${GITEE_API}/issues/${existingIssue.number}?access_token=${TOKEN}`, { + method: 'PATCH', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ labels }) + }); + } else { + await fetch(`${GITEE_API}/issues?access_token=${TOKEN}`, { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ + title, + body: `文档投票 - ${docPath}`, + labels + }) + }); + } + }; + + const handleVote = async (type) => { + if (loading || !docPath) return; + setLoading(true); + + try { + let newUp = upvotes; + let newDown = downvotes; + let newVote = null; + + if (userVote === null) { + // 未投票 → 投票 + if (type === 'up') { + newUp = upvotes + 1; + } else { + newDown = downvotes + 1; + } + newVote = type; + } else if (userVote === type) { + // 点击已选中的 → 取消投票 + if (type === 'up') { + newUp = Math.max(0, upvotes - 1); + } else { + newDown = Math.max(0, downvotes - 1); + } + newVote = null; + } else { + // 切换投票 + if (type === 'up') { + newUp = upvotes + 1; + newDown = Math.max(0, downvotes - 1); + } else { + newDown = downvotes + 1; + newUp = Math.max(0, upvotes - 1); + } + newVote = type; + } + + await updateGiteeIssue(newUp, newDown); + + setUpvotes(newUp); + setDownvotes(newDown); + setUserVote(newVote); + + if (newVote) { + localStorage.setItem(`vote_${docPath}`, newVote); + } else { + localStorage.removeItem(`vote_${docPath}`); + } + } catch (e) { + console.error('投票失败:', e); + } finally { + setLoading(false); + } + }; + + return ( +
+ 这篇文档有帮助吗? +
+ + +
+
+ ); +} \ No newline at end of file diff --git a/src/css/custom.css b/src/css/custom.css index 01ab68e..8f02718 100644 --- a/src/css/custom.css +++ b/src/css/custom.css @@ -148,4 +148,143 @@ html[data-theme='dark'] .docusaurus-highlight-code-line { .widget{ display: none!important; opacity: 0; -} \ No newline at end of file +} +/* 帮助文档卡片背景 */ +.cardContainer { + background-color: #e6f0ff !important; + border-radius: 12px; + transition: all 0.3s ease; +} + +.cardContainer:hover { + background-color: #cce0ff !important; + box-shadow: 0 4px 12px rgba(70, 106, 255, 0.15); +} + +/* ===== 文档投票组件样式 ===== */ +.vote-container { + display: flex; + align-items: center; + justify-content: flex-end; + gap: 1.2rem; + padding: 1.5rem 0 0.5rem 0; + margin-top: 1.5rem; + border-top: 1px solid var(--ifm-toc-border-color); +} + +.vote-label { + font-weight: 500; + color: var(--ifm-color-emphasis-600); + font-size: 0.95rem; + white-space: nowrap; +} + +.vote-buttons { + display: flex; + align-items: center; + gap: 0.6rem; +} + +.vote-btn { + display: flex; + align-items: center; + gap: 0.35rem; + padding: 0.4rem 0.85rem; + border: none; + border-radius: 20px; + background: var(--ifm-color-emphasis-100); + cursor: pointer; + font-size: 1rem; + transition: all 0.2s ease; + user-select: none; + outline: none; +} + +.vote-btn:hover { + background: var(--ifm-color-emphasis-200); + transform: scale(1.05); +} + +.vote-btn:active { + transform: scale(0.97); +} + +.vote-emoji { + font-size: 1.25rem; + line-height: 1; +} + +.vote-count { + color: var(--ifm-color-emphasis-700); + font-weight: 600; + font-size: 0.95rem; + min-width: 1ch; + text-align: center; +} + +/* 👍 高亮状态 */ +.vote-btn-active-up { + background: #e6f0ff; + box-shadow: 0 0 0 2px rgba(70, 106, 255, 0.25); +} + +.vote-btn-active-up:hover { + background: #d6e4ff; +} + +.vote-btn-active-up .vote-count { + color: #466aff; +} + +/* 👎 高亮状态 */ +.vote-btn-active-down { + background: #fff0e6; + box-shadow: 0 0 0 2px rgba(255, 102, 0, 0.25); +} + +.vote-btn-active-down:hover { + background: #ffe4d0; +} + +.vote-btn-active-down .vote-count { + color: #ff6600; +} + +/* 暗色模式适配 */ +html[data-theme='dark'] .vote-btn { + background: var(--ifm-color-emphasis-200); +} + +html[data-theme='dark'] .vote-btn:hover { + background: var(--ifm-color-emphasis-300); +} + +html[data-theme='dark'] .vote-count { + color: var(--ifm-color-emphasis-600); +} + +html[data-theme='dark'] .vote-btn-active-up { + background: rgba(70, 106, 255, 0.2); + box-shadow: 0 0 0 2px rgba(70, 106, 255, 0.35); +} + +html[data-theme='dark'] .vote-btn-active-up:hover { + background: rgba(70, 106, 255, 0.3); +} + +html[data-theme='dark'] .vote-btn-active-up .vote-count { + color: #8aa3ff; +} + +html[data-theme='dark'] .vote-btn-active-down { + background: rgba(255, 102, 0, 0.15); + box-shadow: 0 0 0 2px rgba(255, 102, 0, 0.3); +} + +html[data-theme='dark'] .vote-btn-active-down:hover { + background: rgba(255, 102, 0, 0.25); +} + +html[data-theme='dark'] .vote-btn-active-down .vote-count { + color: #ff9944; +} diff --git a/src/theme/DocItem/Layout/index.js b/src/theme/DocItem/Layout/index.js new file mode 100644 index 0000000..e738b64 --- /dev/null +++ b/src/theme/DocItem/Layout/index.js @@ -0,0 +1,57 @@ +import React from 'react'; +import clsx from 'clsx'; +import {useWindowSize} from '@docusaurus/theme-common'; +import {useDoc} from '@docusaurus/plugin-content-docs/client'; +import DocItemPaginator from '@theme/DocItem/Paginator'; +import DocVersionBanner from '@theme/DocVersionBanner'; +import DocVersionBadge from '@theme/DocVersionBadge'; +import DocItemFooter from '@theme/DocItem/Footer'; +import DocItemTOCMobile from '@theme/DocItem/TOC/Mobile'; +import DocItemTOCDesktop from '@theme/DocItem/TOC/Desktop'; +import DocItemContent from '@theme/DocItem/Content'; +import DocBreadcrumbs from '@theme/DocBreadcrumbs'; +import ContentVisibility from '@theme/ContentVisibility'; +import VoteButtons from '@site/src/components/VoteButtons'; +import styles from './styles.module.css'; + +function useDocTOC() { + const {frontMatter, toc} = useDoc(); + const windowSize = useWindowSize(); + const hidden = frontMatter.hide_table_of_contents; + const canRender = !hidden && toc.length > 0; + const mobile = canRender ? : undefined; + const desktop = + canRender && (windowSize === 'desktop' || windowSize === 'ssr') ? ( + + ) : undefined; + return { + hidden, + mobile, + desktop, + }; +} + +export default function DocItemLayout({children}) { + const docTOC = useDocTOC(); + const {metadata} = useDoc(); + return ( +
+
+ + +
+
+ + + {docTOC.mobile} + {children} + + +
+ +
+
+ {docTOC.desktop &&
{docTOC.desktop}
} +
+ ); +} \ No newline at end of file diff --git a/src/theme/DocItem/Layout/styles.module.css b/src/theme/DocItem/Layout/styles.module.css new file mode 100644 index 0000000..37252fa --- /dev/null +++ b/src/theme/DocItem/Layout/styles.module.css @@ -0,0 +1,10 @@ +.docItemContainer header + *, +.docItemContainer article > *:first-child { + margin-top: 0; +} + +@media (min-width: 997px) { + .docItemCol { + max-width: 75% !important; + } +} \ No newline at end of file diff --git a/src/theme/Footer/Layout/index.js b/src/theme/Footer/Layout/index.js new file mode 100644 index 0000000..6a67523 --- /dev/null +++ b/src/theme/Footer/Layout/index.js @@ -0,0 +1,11 @@ +import OriginalFooter from '@docusaurus/theme-classic/lib/theme/Footer/Layout'; +import VoteButtons from '@site/src/components/VoteButtons'; + +export default function Layout(props) { + return ( + <> + + + + ); +} \ No newline at end of file