diff --git a/src/client/theme-default/components/Page.vue b/src/client/theme-default/components/Page.vue
index 676886eaede5..8589f0a69c32 100644
--- a/src/client/theme-default/components/Page.vue
+++ b/src/client/theme-default/components/Page.vue
@@ -2,6 +2,7 @@
@@ -35,3 +36,9 @@ export default {
margin-top: 0;
} */
+
\ No newline at end of file
diff --git a/src/client/theme-default/components/PageEdit.ts b/src/client/theme-default/components/PageEdit.ts
new file mode 100644
index 000000000000..753a5fa98184
--- /dev/null
+++ b/src/client/theme-default/components/PageEdit.ts
@@ -0,0 +1,81 @@
+import { defineComponent, computed } from 'vue'
+import OutboundLink from './icons/OutboundLink.vue'
+import { endingSlashRE, isExternal } from '/@theme/utils'
+import { usePageData, useSiteData, useSiteDataByRoute } from 'vitepress'
+
+function createEditLink(
+ repo: string,
+ docsRepo: string,
+ docsDir: string,
+ docsBranch: string,
+ path: string
+) {
+ const bitbucket = /bitbucket.org/
+ if (bitbucket.test(repo)) {
+ const base = isExternal(docsRepo) ? docsRepo : repo
+ return (
+ base.replace(endingSlashRE, '') +
+ `/src` +
+ `/${docsBranch}/` +
+ (docsDir ? docsDir.replace(endingSlashRE, '') + '/' : '') +
+ path +
+ `?mode=edit&spa=0&at=${docsBranch}&fileviewer=file-view-default`
+ )
+ }
+
+ const base = isExternal(docsRepo)
+ ? docsRepo
+ : `https://github.com/${docsRepo}`
+ return (
+ base.replace(endingSlashRE, '') +
+ `/edit` +
+ `/${docsBranch}/` +
+ (docsDir ? docsDir.replace(endingSlashRE, '') + '/' : '') +
+ path
+ )
+}
+
+export default defineComponent({
+ components: {
+ OutboundLink
+ },
+
+ setup() {
+ const pageData = usePageData()
+ const siteData = useSiteData()
+ const siteDataByRoute = useSiteDataByRoute()
+
+ const {
+ repo,
+ text,
+ dir = '',
+ branch = 'master',
+ docsRepo = repo
+ } = siteData.value.themeConfig.editLink
+ const { relativePath } = pageData.value
+
+ const editLink = computed(() => {
+ const showEditLink =
+ pageData.value.frontmatter.editLink == null
+ ? siteData.value.themeConfig.editLink
+ : pageData.value.frontmatter.editLink
+
+ if (showEditLink && relativePath) {
+ return createEditLink(repo, docsRepo, dir, branch, relativePath)
+ }
+ return null
+ })
+ const editLinkText = computed(() => {
+ return (
+ siteDataByRoute.value.themeConfig.editLink.text ||
+ text ||
+ `Edit this page`
+ )
+ })
+
+ return {
+ editLink,
+ editLinkText
+ }
+ }
+})
diff --git a/src/client/theme-default/components/PageEdit.vue b/src/client/theme-default/components/PageEdit.vue
new file mode 100644
index 000000000000..5d8b0829ab36
--- /dev/null
+++ b/src/client/theme-default/components/PageEdit.vue
@@ -0,0 +1,32 @@
+
+
+
+
+
+
+
diff --git a/src/client/theme-default/config.ts b/src/client/theme-default/config.ts
index 7fe5f028867a..b8c72e70115a 100644
--- a/src/client/theme-default/config.ts
+++ b/src/client/theme-default/config.ts
@@ -75,6 +75,7 @@ export namespace DefaultTheme {
export interface EditLinkConfig {
repo: string
+ docsRepo?: string
dir?: string
branch?: string
text?: string
diff --git a/src/client/theme-default/utils.ts b/src/client/theme-default/utils.ts
index 25d6580a8371..5a9f50dd59bd 100644
--- a/src/client/theme-default/utils.ts
+++ b/src/client/theme-default/utils.ts
@@ -2,6 +2,7 @@ import { useSiteData, Route } from 'vitepress'
export const hashRE = /#.*$/
export const extRE = /\.(md|html)$/
+export const endingSlashRE = /\/$/
export const outboundRE = /^[a-z]+:/i
export function withBase(path: string) {
diff --git a/src/node/markdownToVue.ts b/src/node/markdownToVue.ts
index cb6c917ca029..f6715b1e349a 100644
--- a/src/node/markdownToVue.ts
+++ b/src/node/markdownToVue.ts
@@ -43,6 +43,7 @@ export function createMarkdownToVueRenderFn(
title: inferTitle(frontmatter, content),
frontmatter,
headers: data.headers,
+ relativePath: file.replace(/\\/g, '/'),
lastUpdated
}
diff --git a/types/shared.d.ts b/types/shared.d.ts
index 3cf71d5dfa2e..840e6aebbea5 100644
--- a/types/shared.d.ts
+++ b/types/shared.d.ts
@@ -25,6 +25,7 @@ export interface PageData {
title: string
frontmatter: Record
headers: Header[]
+ relativePath: string
lastUpdated: number
next?: { text: string; link: string }
prev?: { text: string; link: string }