Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add git repo link and edit links #55

Merged
merged 7 commits into from
Sep 17, 2020
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/client/theme-default/components/NavBar.vue
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
/>
<span>{{ $site.title }}</span>
</a>
<NavBarLinks class="hide-mobile"/>
<NavBarLinks class="hide-mobile" />
</template>

<script src="./NavBar"></script>
Expand Down
44 changes: 41 additions & 3 deletions src/client/theme-default/components/NavBarLinks.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
import { computed } from 'vue'
import { useSiteDataByRoute } from 'vitepress'
import { useSiteData, useSiteDataByRoute } from 'vitepress'
import NavBarLink from './NavBarLink.vue'
import NavDropdownLink from './NavDropdownLink.vue'
import { DefaultTheme } from '../config'

const platforms = ['GitHub', 'GitLab', 'Bitbucket'].map(
(platform) => [platform, new RegExp(platform, 'i')] as const
)

export default {
components: {
Expand All @@ -10,13 +15,46 @@ export default {
},

setup() {
const siteDataByRoute = useSiteDataByRoute()
const siteData = useSiteData()
const repoInfo = computed(() => {
const theme = siteData.value.themeConfig as DefaultTheme.Config
// return theme.editLinks
// ? {
// repo: theme.docsRepo || theme.repo,
// label: theme.repoLabel
// }
// : null

posva marked this conversation as resolved.
Show resolved Hide resolved
const repo = theme.docsRepo || theme.repo
let text: string | undefined = theme.repoLabel

if (repo) {
const link = /^https?:/.test(repo) ? repo : `https://github.com/${repo}`
if (!text) {
// if no label is provided, deduce it from the repo url
const repoHosts = link.match(/^https?:\/\/[^/]+/)
if (repoHosts) {
const repoHost = repoHosts[0]
const foundPlatform = platforms.find(([_platform, re]) =>
re.test(repoHost)
)
text = foundPlatform && foundPlatform[0]
}
}

return { link, text: text || 'Source' }
}
return null
})
return {
navData:
process.env.NODE_ENV === 'production'
? // navbar items do not change in production
useSiteDataByRoute().value.themeConfig.nav
siteDataByRoute.value.themeConfig.nav
: // use computed in dev for hot reload
computed(() => useSiteDataByRoute().value.themeConfig.nav)
computed(() => siteDataByRoute.value.themeConfig.nav),
repoInfo
}
}
}
11 changes: 7 additions & 4 deletions src/client/theme-default/components/NavBarLinks.vue
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
<template>
<nav class="nav-links" v-if="navData">
<template v-for="item of navData">
<NavDropdownLink v-if='item.items' :item="item"/>
<NavBarLink v-else :item="item"/>
<nav class="nav-links">
<template v-if="navData">
<template v-for="item of navData">
<NavDropdownLink v-if="item.items" :item="item" />
<NavBarLink v-else :item="item" />
</template>
<NavBarLink v-if="repoInfo" :item="repoInfo" />
</template>
</nav>
</template>
Expand Down
4 changes: 3 additions & 1 deletion src/client/theme-default/components/Page.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,15 @@
<div class="content">
<Content />
<NextAndPrevLinks />
<PageEdit />
</div>
</template>

<script>
import NextAndPrevLinks from './NextAndPrevLinks.vue'
import PageEdit from './PageEdit.vue'
export default {
components:{ NextAndPrevLinks }
components:{ NextAndPrevLinks, PageEdit }
}
</script>

Expand Down
81 changes: 81 additions & 0 deletions src/client/theme-default/components/PageEdit.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import { computed } from 'vue'
import OutboundLink from './icons/OutboundLink.vue'
import { endingSlashRE, isExternal } from '/@theme/utils'
import { usePageData, useSiteData } from 'vitepress'
import { DefaultTheme } from '../config'

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 {
components: {
OutboundLink
},

setup() {
const pageData = usePageData()
const siteData = useSiteData<DefaultTheme.Config>()

const editLink = computed(() => {
const showEditLink: boolean | undefined =
pageData.value.frontmatter.editLink == null
? siteData.value.themeConfig.editLinks
: pageData.value.frontmatter.editLink
const {
repo,
docsDir = '',
docsBranch = 'master',
docsRepo = repo
} = siteData.value.themeConfig

const { relativePath } = pageData.value
if (showEditLink && relativePath && repo) {
return createEditLink(
repo,
docsRepo || repo,
docsDir,
docsBranch,
relativePath
)
}
return null
})
const editLinkText = computed(
() => siteData.value.themeConfig.editLinkText || 'Edit this page'
)

return {
editLink,
editLinkText
}
}
}
27 changes: 27 additions & 0 deletions src/client/theme-default/components/PageEdit.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<template>
<footer class="page-edit">
<div v-if="editLink" class="edit-link">
<a :href="editLink" target="_blank" rel="noopener noreferrer">
{{ editLinkText }}
<OutboundLink />
</a>
</div>
</footer>
</template>

<script src="./PageEdit"></script>

<style>
.page-edit {
padding-top: 1rem;
padding-bottom: 1rem;
overflow: auto;
}
.page-edit .edit-link {
display: inline-block;
}
.page-edit .edit-link a {
color: #4e6e8e;
margin-right: 0.25rem;
}
</style>
52 changes: 42 additions & 10 deletions src/client/theme-default/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,48 @@ export namespace DefaultTheme {
nav?: NavItem[] | false
sidebar?: SideBarConfig | MultiSideBarConfig
search?: SearchConfig | false
editLink?: EditLinkConfig | false

/**
* GitHub repository following the format <user>/<project>.
*
* @example vuejs/vue-next
*/
repo?: string
/**
* Customize the header label. Defaults to GitHub/Gitlab/Bitbucket depending
* on the provided repo
*
* @exampe `"Contribute!"`
*/
repoLabel?: string

/**
* If your docs are in a different repository from your main project
*
* @example `"vuejs/docs-next"`
*/
docsRepo?: string
/**
* If your docs are not at the root of the repo.
*
* @example `"docs"`
*/
docsDir?: string
/**
* If your docs are in a different branch. Defaults to `master`
* @example `"next"`
*/
docsBranch?: string

/**
* Enable links to edit pages at the bottom of the page
*/
editLinks?: boolean
/**
* Custom text for edit link. Defaults to "Edit this page"
*/
editLinkText?: string

lastUpdated?: string | boolean
prevLink?: boolean
nextLink?: boolean
Expand Down Expand Up @@ -70,13 +111,4 @@ export namespace DefaultTheme {
indexName: string
}
}

// edit link -----------------------------------------------------------------

export interface EditLinkConfig {
repo: string
dir?: string
branch?: string
text?: string
}
}
1 change: 1 addition & 0 deletions src/client/theme-default/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
1 change: 1 addition & 0 deletions src/node/markdownToVue.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ export function createMarkdownToVueRenderFn(
title: inferTitle(frontmatter, content),
frontmatter,
headers: data.headers,
relativePath: file.replace(/\\/g, '/'),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@sin-tanaka What does this represent? Why are you replacing / with /? is it for Windows? I saw it in the vuepress code base too

lastUpdated
}

Expand Down
1 change: 1 addition & 0 deletions types/shared.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ export interface PageData {
title: string
frontmatter: Record<string, any>
headers: Header[]
relativePath: string
lastUpdated: number
next?: { text: string; link: string }
prev?: { text: string; link: string }
Expand Down