Skip to content

Commit

Permalink
[gem-book] Support gitlab repo
Browse files Browse the repository at this point in the history
Closed #186
  • Loading branch information
mantou132 committed Aug 17, 2024
1 parent 89cab16 commit 3f4b107
Show file tree
Hide file tree
Showing 11 changed files with 123 additions and 53 deletions.
2 changes: 1 addition & 1 deletion packages/gem-book/src/bin/builder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@ export async function buildApp(dir: string, options: Required<CliUniqueConfig>,
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: {
Expand Down
5 changes: 3 additions & 2 deletions packages/gem-book/src/bin/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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 });
Expand Down
8 changes: 7 additions & 1 deletion packages/gem-book/src/bin/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 {}
}
Expand Down Expand Up @@ -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;
}
}
34 changes: 23 additions & 11 deletions packages/gem-book/src/element/elements/404.ts
Original file line number Diff line number Diff line change
@@ -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';
Expand Down Expand Up @@ -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`
<h1><gem-title inert>Not Found</gem-title></h1>
${noGithub
${!url
? ''
: html`
<div>
<gem-link href=${`${github}/new/${sourceBranch}${fullPath}`}>
<gem-link href=${url}>
<gem-use .element=${icons.compose}></gem-use>
<span>${selfI18n.get('createOnGithub')}</span>
<span>${selfI18n.get('createOnGithub', getPlatform())}</span>
</gem-link>
</div>
`}
Expand Down
84 changes: 58 additions & 26 deletions packages/gem-book/src/element/elements/edit-link.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -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;
Expand All @@ -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`
<gem-link href=${`${github}/edit/${sourceBranch}${this.#fullPath}`}>
<gem-link href=${url}>
<gem-use .element=${icons.compose}></gem-use>
<span>${selfI18n.get('editOnGithub')}</span>
<span>${selfI18n.get('editOnGithub', getPlatform())}</span>
</gem-link>
${lastUpdated &&
html`
Expand Down
5 changes: 5 additions & 0 deletions packages/gem-book/src/element/elements/icons.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,11 @@ export const icons = {
<path fill="currentColor" d="M8 0a8.1 8.1 0 0 0-8 8.2c0 3.63 2.3 6.7 5.47 7.79l.14.01c.3 0 .4-.22.4-.4v-1.4c-.3.06-.57.1-.81.1-1.54 0-1.89-1.2-1.89-1.2-.36-.95-.89-1.2-.89-1.2-.7-.5 0-.5.05-.5.8.06 1.23.84 1.23.84.4.7.94.9 1.41.9.38 0 .72-.12.92-.21.07-.53.28-.9.5-1.1-1.77-.2-3.64-.91-3.64-4.05 0-.9.31-1.63.82-2.2-.08-.21-.35-1.05.08-2.18l.18-.01c.3 0 .94.1 2.02.86a7.5 7.5 0 0 1 4.01 0c1.08-.75 1.73-.86 2.02-.86l.18.01c.44 1.13.16 1.97.08 2.18.5.57.82 1.3.82 2.2 0 3.15-1.87 3.84-3.65 4.04.28.25.54.75.54 1.52l-.01 2.25c0 .2.1.41.4.41l.15-.01A8.19 8.19 0 0 0 16 8.2 8.1 8.1 0 0 0 8 0Z"/>
</svg>
`,
gitlab: raw`
<svg focusable="false" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896">
<path d="M910.5 553.2l-109-370.8c-6.8-20.4-23.1-34.1-44.9-34.1s-39.5 12.3-46.3 32.7l-72.2 215.4H386.2L314 181.1c-6.8-20.4-24.5-32.7-46.3-32.7s-39.5 13.6-44.9 34.1L113.9 553.2c-4.1 13.6 1.4 28.6 12.3 36.8l385.4 289 386.7-289c10.8-8.1 16.3-23.1 12.2-36.8z"></path>
</svg>
`,
menu: raw`
<svg part="icon" aria-hidden="true" height="24px" viewBox="0 0 24 24" width="24px" fill="currentColor">
<path d="M0 0h24v24H0z" fill="none" stroke="none"></path>
Expand Down
6 changes: 4 additions & 2 deletions packages/gem-book/src/element/elements/nav.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import { mediaQuery } from '@mantou/gem/helper/mediaquery';

import { NavItem } from '../../common/config';
import { theme } from '../helper/theme';
import { capitalize, isSameOrigin } from '../lib/utils';
import { capitalize, isGitLab, isSameOrigin } from '../lib/utils';
import { bookStore, updateBookConfig } from '../store';

import { icons } from './icons';
Expand Down Expand Up @@ -195,7 +195,9 @@ export class Nav extends GemElement {
render() {
const { config, nav = [] } = bookStore;
const { github = '' } = config || {};
const githubLink = config ? this.#renderExternalItem({ title: 'github', link: github }, icons.github) : null;
const githubLink = config
? this.#renderExternalItem({ title: 'github', link: github }, isGitLab() ? icons.gitlab : icons.github)
: null;
const internals = nav?.filter((e) => isSameOrigin(e.link)) || [];
const externals = nav?.filter((e) => !isSameOrigin(e.link)) || [];
const textExternals = externals.filter((e) => !(e.title.toLowerCase() in icons));
Expand Down
7 changes: 3 additions & 4 deletions packages/gem-book/src/element/elements/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { bookStore, locationStore } from '../store';
import { BookConfig } from '../../common/config';
import { debounce } from '../../common/utils';
import { icons } from '../elements/icons';
import { getRanges, getParts, joinPath, getURL, escapeHTML, capitalize } from '../lib/utils';
import { getRanges, getParts, joinPath, getURL, escapeHTML, capitalize, isGitLab } from '../lib/utils';
import { parseMarkdown, unsafeRenderHTML } from '../lib/renderer';
import { originDocLang, selfI18n } from '../helper/i18n';

Expand All @@ -26,8 +26,6 @@ function getRemoteURL(originSrc = '', dev = GemBookPluginElement.devMode) {
let url = originSrc;
if (originSrc && !/^(https?:)?\/\//.test(originSrc)) {
if (!github || !sourceBranch) return '';
const rawOrigin = 'https://raw.githubusercontent.com';
const repo = new URL(github).pathname;
let src = originSrc.startsWith('/') ? originSrc : `/${originSrc}`;
if (originSrc.startsWith('.')) {
const absPath = new URL(originSrc, `${location.origin}${currentLink!.originLink}`).pathname;
Expand All @@ -37,7 +35,7 @@ function getRemoteURL(originSrc = '', dev = GemBookPluginElement.devMode) {
if (linkItem) return getURL(joinPath(lang, linkItem.originLink), linkItem.hash);
src = new URL(originSrc, `${location.origin}${joinPath(sourceDir, lang, currentLink!.originLink)}`).pathname;
}
url = dev ? `/_assets${src}` : `${rawOrigin}${repo}/${sourceBranch}${joinPath(base, src)}`;
url = dev ? `/_assets${src}` : `${github}/raw/${sourceBranch}${joinPath(base, src)}`;
}
return url;
}
Expand All @@ -55,6 +53,7 @@ export class GemBookPluginElement extends GemElement {
getRemoteURL,
parseMarkdown,
unsafeRenderHTML,
isGitLab,
};

static caches = new Map<typeof GemBookPluginElement, Map<string, any>>();
Expand Down
13 changes: 9 additions & 4 deletions packages/gem-book/src/element/helper/i18n.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,22 @@
import { I18n } from '@mantou/gem/helper/i18n';

import { SupportLang } from '../../common/config';
import { isGitLab } from '../lib/utils';

export function getPlatform() {
return isGitLab() ? 'Gitlab' : 'Github';
}

const resources = {
en: {
editOnGithub: 'Edit this page on GitHub',
createOnGithub: 'Create on GitHub',
editOnGithub: 'Edit this page on $1',
createOnGithub: 'Create on $1',
footer: 'Generated by $1<GemBook>',
lastUpdated: 'Last Updated',
},
zh: {
editOnGithub: '在 Github 编辑此页',
createOnGithub: '在 Github 上创建此页面',
editOnGithub: '在 $1 编辑此页',
createOnGithub: '在 $1 上创建此页面',
footer: '通过 $1<GemBook> 生成',
lastUpdated: '上次更新',
},
Expand Down
9 changes: 7 additions & 2 deletions packages/gem-book/src/element/lib/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ export function flatNav(nav: NavItem[]): NavItemWithLink[] {
}

export function joinPath(...paths: (string | undefined)[]) {
const toPath = (base: string) => (base.startsWith('/') ? base : base ? `/${base}` : '');
const toPath = (part: string) => (part.startsWith('/') ? part : part ? `/${part}` : '');
return paths.reduce<string>((base = '', path = '') => {
return `${toPath(base)}${toPath(path)}`;
}, '');
Expand All @@ -81,7 +81,7 @@ export function joinPath(...paths: (string | undefined)[]) {
export function getGithubPath(link: string) {
const { config, lang } = bookStore;
const { sourceDir, base } = config || {};
return joinPath(base, sourceDir, lang, link);
return joinPath(base, sourceDir !== '.' ? sourceDir : '', lang, link);
}

export function getURL(originPath: string, hash = '') {
Expand Down Expand Up @@ -113,3 +113,8 @@ export function checkBuiltInPlugin(container: HTMLElement) {
}
});
}

export function isGitLab() {
const { config } = bookStore;
return config?.github && !new URL(config.github).host.endsWith('github.com');
}
3 changes: 3 additions & 0 deletions packages/gem-book/src/plugins/docsearch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -283,6 +283,9 @@ customElements.whenDefined('gem-book').then(({ GemBookPluginElement }: typeof Ge
},
getMissingResultsUrl: config.github
? ({ query }: { query: string }) => {
if (Utils.isGitLab()) {
return `${config.github}/-/issues/new?issue[title]=${query}`;
}
return `${config.github}/issues/new?title=${query}`;
}
: undefined,
Expand Down

0 comments on commit 3f4b107

Please sign in to comment.