Skip to content
This repository was archived by the owner on Dec 27, 2024. It is now read-only.

Commit 1ef9ef6

Browse files
authored
Merge pull request #277 from mtdvlpr/feat/docs
feat: documentation website
2 parents 0723a38 + ecf459b commit 1ef9ef6

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

139 files changed

+5073
-89
lines changed

.github/workflows/build.yml

+4
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,11 @@ name: Build/release
22

33
on:
44
push:
5+
paths-ignore:
6+
- 'docs/**'
57
pull_request:
8+
paths-ignore:
9+
- 'docs/**'
610
workflow_dispatch:
711

812
jobs:

.github/workflows/docs.yml

+66
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
# Sample workflow for building and deploying a VitePress site to GitHub Pages
2+
#
3+
name: Deploy Docs site to Pages
4+
5+
on:
6+
push:
7+
branches:
8+
- main
9+
- master
10+
paths:
11+
- docs/**
12+
- package.json
13+
- yarn.lock
14+
15+
# Allows you to run this workflow manually from the Actions tab
16+
workflow_dispatch:
17+
18+
# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages
19+
permissions:
20+
contents: read
21+
pages: write
22+
id-token: write
23+
24+
# Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued.
25+
# However, do NOT cancel in-progress runs as we want to allow these production deployments to complete.
26+
concurrency:
27+
group: pages
28+
cancel-in-progress: false
29+
30+
jobs:
31+
# Build job
32+
build:
33+
runs-on: ubuntu-latest
34+
steps:
35+
- name: Checkout
36+
uses: actions/checkout@v4
37+
with:
38+
fetch-depth: 0
39+
- name: Setup Node
40+
uses: actions/setup-node@v4
41+
with:
42+
node-version: 20
43+
cache: yarn
44+
- name: Setup Pages
45+
uses: actions/configure-pages@v4
46+
- name: Install dependencies
47+
run: yarn install
48+
- name: Build with VitePress
49+
run: yarn docs:build
50+
- name: Upload artifact
51+
uses: actions/upload-pages-artifact@v3
52+
with:
53+
path: docs/.vitepress/dist
54+
55+
# Deployment job
56+
deploy:
57+
environment:
58+
name: github-pages
59+
url: ${{ steps.deployment.outputs.page_url }}
60+
needs: build
61+
runs-on: ubuntu-latest
62+
name: Deploy
63+
steps:
64+
- name: Deploy to GitHub Pages
65+
id: deployment
66+
uses: actions/deploy-pages@v4

.gitignore

+4
Original file line numberDiff line numberDiff line change
@@ -48,3 +48,7 @@ yarn-error.log*
4848
!.yarn/sdks
4949
!.yarn/versions
5050
.yarn/install-state.gz
51+
52+
# VitePress
53+
docs/.vitepress/dist
54+
docs/.vitepress/cache

docs/.vitepress/config.mts

+163
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
1+
import { defineConfig } from 'vitepress';
2+
import { localeOptions } from './../locales';
3+
import { mapLocales, mapSearch } from './../utils/locales';
4+
import { CANONICAL_URL, GH_REPO, GH_REPO_URL } from './../utils/constants';
5+
import { camelToKebabCase } from './../utils/general';
6+
7+
const base = `/${GH_REPO}/`;
8+
9+
// https://vitepress.dev/reference/site-config
10+
export default defineConfig({
11+
base,
12+
srcDir: './src',
13+
cleanUrls: true,
14+
lastUpdated: true,
15+
rewrites: { 'en/:rest*': ':rest*' },
16+
markdown: { image: { lazyLoading: true } },
17+
head: [
18+
[
19+
'link',
20+
{
21+
rel: 'icon',
22+
type: 'image/png',
23+
sizes: '128x128',
24+
href: `${base}icons/favicon-128x128.png`,
25+
},
26+
],
27+
[
28+
'link',
29+
{
30+
rel: 'icon',
31+
type: 'image/png',
32+
sizes: '96x96',
33+
href: `${base}icons/favicon-96x96.png`,
34+
},
35+
],
36+
[
37+
'link',
38+
{
39+
rel: 'icon',
40+
type: 'image/png',
41+
sizes: '32x32',
42+
href: `${base}icons/favicon-32x32.png`,
43+
},
44+
],
45+
[
46+
'link',
47+
{
48+
rel: 'icon',
49+
type: 'image/png',
50+
sizes: '16x16',
51+
href: `${base}icons/favicon-16x16.png`,
52+
},
53+
],
54+
['link', { rel: 'icon', type: 'image/ico', href: `${base}favicon.ico` }],
55+
[
56+
'link',
57+
{
58+
rel: 'icon',
59+
type: 'image/svg+xml',
60+
href: `${base}logo-no-background.svg`,
61+
},
62+
],
63+
['meta', { property: 'og:type', content: 'website' }],
64+
['meta', { content: `${CANONICAL_URL}icon.png`, property: 'og:image' }],
65+
['meta', { content: 'image/png', property: 'og:image:type' }],
66+
['meta', { content: '512', property: 'og:image:width' }],
67+
['meta', { content: '513', property: 'og:image:height' }],
68+
['meta', { content: 'The logo of M³', property: 'og:image:alt' }],
69+
],
70+
transformPageData(pageData) {
71+
const canonicalUrl = `${CANONICAL_URL}${pageData.relativePath}`
72+
.replace(/index\.md$/, '')
73+
.replace(/\.md$/, '');
74+
75+
const pageLang = pageData.relativePath.split('/')[0];
76+
const isEnglish = pageData.relativePath.split('/').length === 1;
77+
78+
pageData.frontmatter.head ??= [];
79+
pageData.frontmatter.head.push(
80+
['link', { rel: 'canonical', href: canonicalUrl }],
81+
[
82+
'meta',
83+
{
84+
name: 'og:title',
85+
content:
86+
pageData.frontmatter.layout === 'home'
87+
? `M³ docs`
88+
: `${pageData.title} | M³ docs`,
89+
},
90+
],
91+
[
92+
'link',
93+
{
94+
rel: 'alternate',
95+
hreflang: 'x-default',
96+
href: isEnglish
97+
? canonicalUrl
98+
: canonicalUrl.replace(`/${pageLang}/`, '/'),
99+
},
100+
],
101+
...localeOptions.map((l): [string, Record<string, string>] => {
102+
const lang = camelToKebabCase(l.value);
103+
return [
104+
'link',
105+
{
106+
rel: 'alternate',
107+
hreflang: lang,
108+
href: (!isEnglish
109+
? canonicalUrl.replace(`/${pageLang}/`, `/${lang}/`)
110+
: `${CANONICAL_URL}${lang}/${pageData.relativePath}`
111+
).replace('/en/', '/'),
112+
},
113+
];
114+
}),
115+
[
116+
'script',
117+
{},
118+
`
119+
const initialVisit = localStorage.getItem('initialVisit') !== 'false'
120+
121+
if (initialVisit) {
122+
const langs = [${localeOptions.map((l) => `"${camelToKebabCase(l.value)}"`)}]
123+
124+
function mapLang(lang) {
125+
switch (lang) {
126+
case 'zh':
127+
case 'zh-CN':
128+
case 'zh-TW':
129+
return 'cmn-hans';
130+
default:
131+
return lang.toLowerCase();
132+
}
133+
}
134+
135+
let match;
136+
navigator.languages.forEach((lang) => {
137+
const mapped = mapLang(lang);
138+
if (!match) match = langs.find((l) => l === mapped);
139+
if (!match) match = langs.find((l) => l === mapped.split('-')[0]);
140+
})
141+
142+
if (match) {
143+
localStorage.setItem('initialVisit', false);
144+
const parts = window.location.pathname.split('/');
145+
const isEnglish = parts.length === 3;
146+
const page = isEnglish ? parts[2] : parts[3]
147+
window.location.pathname = "${base}" + (match !== 'en' ? match + '/' : '') + page
148+
}
149+
}
150+
`,
151+
],
152+
);
153+
},
154+
locales: mapLocales(),
155+
themeConfig: {
156+
externalLinkIcon: true,
157+
logo: '/icon.png',
158+
outline: { level: 'deep' },
159+
search: mapSearch(),
160+
lastUpdated: { formatOptions: { dateStyle: 'full', forceLocale: true } },
161+
socialLinks: [{ icon: 'github', link: GH_REPO_URL, ariaLabel: 'GitHub' }],
162+
},
163+
});

docs/.vitepress/theme/index.ts

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// https://vitepress.dev/guide/custom-theme
2+
import { h } from 'vue'
3+
import type { Theme } from 'vitepress'
4+
import DefaultTheme from 'vitepress/theme'
5+
import './style.css'
6+
7+
export default {
8+
extends: DefaultTheme,
9+
Layout: () => {
10+
return h(DefaultTheme.Layout, null, {
11+
// https://vitepress.dev/guide/extending-default-theme#layout-slots
12+
})
13+
},
14+
enhanceApp({ app, router, siteData }) {
15+
// ...
16+
}
17+
} satisfies Theme

0 commit comments

Comments
 (0)