From 3f4b10732bb8fa036ce80d9cde7fde21b263d5a4 Mon Sep 17 00:00:00 2001 From: mantou132 <709922234@qq.com> Date: Sat, 17 Aug 2024 16:05:17 +0800 Subject: [PATCH] [gem-book] Support gitlab repo Closed #186 --- packages/gem-book/src/bin/builder.ts | 2 +- packages/gem-book/src/bin/index.ts | 5 +- packages/gem-book/src/bin/utils.ts | 8 +- packages/gem-book/src/element/elements/404.ts | 34 +++++--- .../src/element/elements/edit-link.ts | 84 +++++++++++++------ .../gem-book/src/element/elements/icons.ts | 5 ++ packages/gem-book/src/element/elements/nav.ts | 6 +- .../gem-book/src/element/elements/plugin.ts | 7 +- packages/gem-book/src/element/helper/i18n.ts | 13 ++- packages/gem-book/src/element/lib/utils.ts | 9 +- packages/gem-book/src/plugins/docsearch.ts | 3 + 11 files changed, 123 insertions(+), 53 deletions(-) diff --git a/packages/gem-book/src/bin/builder.ts b/packages/gem-book/src/bin/builder.ts index 9cc14487..8738da1e 100644 --- a/packages/gem-book/src/bin/builder.ts +++ b/packages/gem-book/src/bin/builder.ts @@ -173,7 +173,7 @@ export async function buildApp(dir: string, options: Required, plugins: [ new HtmlWebpackPlugin({ title: bookConfig.title || 'GemBook App', - template: template ? path.resolve(process.cwd(), template) : undefined, + template: template ? path.resolve(process.cwd(), template) : 'auto', // Automatically copied to the output directory favicon: !isRemoteIcon && icon, meta: { diff --git a/packages/gem-book/src/bin/index.ts b/packages/gem-book/src/bin/index.ts index f72f0747..782c0fca 100644 --- a/packages/gem-book/src/bin/index.ts +++ b/packages/gem-book/src/bin/index.ts @@ -40,6 +40,7 @@ import { importObject, resolveModule, getMdFile, + isGithubOrGitLabNav, } from './utils'; import { buildApp } from './builder'; import lang from './lang.json'; // https://developers.google.com/search/docs/advanced/crawling/localized-versions#language-codes @@ -96,7 +97,7 @@ async function syncConfig(fullPath?: string) { if (obj.nav) { obj.nav = obj.nav?.filter((e) => { - if (e.title?.toLowerCase() === 'github') { + if (isGithubOrGitLabNav(e.title)) { bookConfig.github = e.link; } else { return true; @@ -424,7 +425,7 @@ program print(chalk.red('nav options error')); process.exit(1); } - if (title.toLowerCase() === 'github') { + if (isGithubOrGitLabNav(title)) { bookConfig.github = link; } else { bookConfig.nav.push({ title, link }); diff --git a/packages/gem-book/src/bin/utils.ts b/packages/gem-book/src/bin/utils.ts index 7c9aa547..6601cc8d 100644 --- a/packages/gem-book/src/bin/utils.ts +++ b/packages/gem-book/src/bin/utils.ts @@ -24,7 +24,7 @@ export async function getGithubUrl() { const git = typeof repo === 'string' ? repo : repo?.url || (await gitRemoteOriginUrl(repoDir)); const parsed = parseGithub(git); if (parsed?.repository) { - return `https://github.com/${parsed.repository}`; + return `https://${parsed.host}/${parsed.repository}`; } } catch {} } @@ -266,3 +266,9 @@ export async function getIconDataUrl(filePath: string) { return ''; } } + +export function isGithubOrGitLabNav(title?: string) { + if (title && ['github', 'gitlab'].includes(title.toLowerCase())) { + return true; + } +} diff --git a/packages/gem-book/src/element/elements/404.ts b/packages/gem-book/src/element/elements/404.ts index 076386b6..a2cdf730 100644 --- a/packages/gem-book/src/element/elements/404.ts +++ b/packages/gem-book/src/element/elements/404.ts @@ -1,8 +1,8 @@ import { adoptedStyle, createCSSSheet, css, customElement, GemElement, html } from '@mantou/gem'; -import { getGithubPath } from '../lib/utils'; +import { getGithubPath, isGitLab } from '../lib/utils'; import { bookStore, locationStore } from '../store'; -import { selfI18n } from '../helper/i18n'; +import { getPlatform, selfI18n } from '../helper/i18n'; import { getUserLink } from '../../common/utils'; import { icons } from './icons'; @@ -40,29 +40,41 @@ const styles = createCSSSheet(css` export class Meta extends GemElement { #getMdFullPath = () => { const { links = [] } = bookStore; - const parts = locationStore.path.replace(/\/$/, '').split('/'); - const newFile = parts.pop(); + const parts = locationStore.path.split('/'); + const newFile = parts.pop() || 'README.md'; const parentPath = parts.join('/'); const link = links.find(({ originLink }) => getUserLink(originLink).startsWith(parentPath)); if (!link) return; - return getGithubPath(link.originLink.replace(/\/[^/]*$/, `/${newFile}`)); + return [ + getGithubPath(link.originLink.replace(/\/[^/]*$/, '')), + newFile.toLowerCase().endsWith('.md') ? newFile : `${newFile}.md`, + ]; }; - render() { + #getGitHubUrl = () => { const { config } = bookStore; const { github, sourceBranch = '' } = config || {}; - const fullPath = this.#getMdFullPath(); - const noGithub = !github || !sourceBranch || !fullPath; + const [fullPath, fileName] = this.#getMdFullPath() || []; + if (!github || !sourceBranch || !fullPath) return; + const filenameParams = encodeURIComponent(fileName); + if (isGitLab()) { + return `${github}/-/new/${sourceBranch}${fullPath}?file_name=${filenameParams}`; + } + return `${github}/new/${sourceBranch}${fullPath}?filename=${filenameParams}`; + }; + + render() { + const url = this.#getGitHubUrl(); return html`

Not Found

- ${noGithub + ${!url ? '' : html`
- + - ${selfI18n.get('createOnGithub')} + ${selfI18n.get('createOnGithub', getPlatform())}
`} diff --git a/packages/gem-book/src/element/elements/edit-link.ts b/packages/gem-book/src/element/elements/edit-link.ts index 245b2ec2..f519e891 100644 --- a/packages/gem-book/src/element/elements/edit-link.ts +++ b/packages/gem-book/src/element/elements/edit-link.ts @@ -12,8 +12,8 @@ import { } from '@mantou/gem'; import { mediaQuery } from '@mantou/gem/helper/mediaquery'; -import { getGithubPath } from '../lib/utils'; -import { selfI18n } from '../helper/i18n'; +import { getGithubPath, isGitLab } from '../lib/utils'; +import { getPlatform, selfI18n } from '../helper/i18n'; import { bookStore, locationStore } from '../store'; import { icons } from './icons'; @@ -77,7 +77,11 @@ export class EditLink extends GemElement { #fullPath = ''; @memo() - #calc = () => (this.#fullPath = this.#getMdFullPath()); + #calc = () => { + const link = bookStore.getCurrentLink?.(); + if (!link) return (this.#fullPath = ''); + this.#fullPath = getGithubPath(link.originLink); + }; #getLastUpdated() { const { lastUpdated } = this.#state; @@ -94,49 +98,77 @@ export class EditLink extends GemElement { ); } - #getMdFullPath = () => { - const link = bookStore.getCurrentLink?.(); - if (!link) return ''; - return getGithubPath(link.originLink); + #fetchCommit = async () => { + const { config } = bookStore; + const { github, sourceBranch = '' } = config || {}; + if (!github) return; + const repo = new URL(github).pathname; + if (isGitLab()) { + const api = `${new URL(github).origin}/api/v4/projects/${encodeURIComponent( + repo.replace(/^\//, ''), + )}/repository/commits?${new URLSearchParams({ + path: this.#fullPath.replace(/^\//, ''), + page: '1', + per_page: '1', + ref_name: sourceBranch, + })}`; + const commit = await fetchData(api); + return { + date: commit.committed_date, + message: commit.message, + commitUrl: commit.web_url, + }; + } else { + const api = `https://api.github.com/repos${repo}/commits?${new URLSearchParams({ + path: this.#fullPath, + page: '1', + per_page: '1', + sha: sourceBranch, + })}`; + const commit = await fetchData(api); + return { + date: commit?.commit?.committer?.date, + message: commit.commit.message, + commitUrl: commit.html_url, + }; + } }; @effect((i) => [i.#fullPath]) #fetchData = async () => { const { config } = bookStore; - const { github, sourceBranch = '' } = config || {}; + const { github } = config || {}; if (!github) return; - const repo = new URL(github).pathname; if (!this.#fullPath) return; - const query = new URLSearchParams({ - path: this.#fullPath, - page: '1', - per_page: '1', - sha: sourceBranch, - }); try { - const api = `https://api.github.com/repos${repo}/commits?${query}`; - const commit = await fetchData(api); - const date = commit?.commit?.committer?.date; + const commit = await this.#fetchCommit(); this.#state({ - lastUpdated: date || '', - message: date ? commit.commit.message : '', - commitUrl: date ? commit.html_url : '', + lastUpdated: commit?.date || '', + message: commit?.date ? commit.message : '', + commitUrl: commit?.date ? commit.commitUrl : '', }); } catch { this.#state({ lastUpdated: '' }); } }; - render() { - const lastUpdated = this.#getLastUpdated(); - const { message, commitUrl } = this.#state; + #getGitHubUrl = () => { const { config } = bookStore; const { github, sourceBranch = '' } = config || {}; if (!github || !sourceBranch || !this.#fullPath) return; + // 兼容 github/gitlab + return `${github}/edit/${sourceBranch}${this.#fullPath}`; + }; + + render() { + const { message, commitUrl } = this.#state; + const lastUpdated = this.#getLastUpdated(); + const url = this.#getGitHubUrl(); + if (!url) return; return html` - + - ${selfI18n.get('editOnGithub')} + ${selfI18n.get('editOnGithub', getPlatform())} ${lastUpdated && html` diff --git a/packages/gem-book/src/element/elements/icons.ts b/packages/gem-book/src/element/elements/icons.ts index d30cb2f7..bfe7532d 100644 --- a/packages/gem-book/src/element/elements/icons.ts +++ b/packages/gem-book/src/element/elements/icons.ts @@ -16,6 +16,11 @@ export const icons = { `, + gitlab: raw` + + `, menu: raw`