Skip to content

Commit

Permalink
Merge branch 'multi-sidebar'
Browse files Browse the repository at this point in the history
  • Loading branch information
sharpchen committed Feb 6, 2024
2 parents 439e1c6 + 838f0cc commit 46eccfe
Show file tree
Hide file tree
Showing 5 changed files with 168 additions and 21 deletions.
14 changes: 7 additions & 7 deletions docs/.vitepress/config.mts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { defineConfig } from 'vitepress';
import { transformerTwoslash } from 'vitepress-plugin-twoslash';
import { getRegisteredMarkdownTheme, getSidebar } from '../shared/utils';
import { fileURLToPath } from 'url';
import { getRegisteredMarkdownTheme } from '../shared/utils';
// https://vitepress.dev/reference/site-config
import { builder } from '../shared/multipleSidebarBuilder';
export default defineConfig({
markdown: {
lineNumbers: true,
Expand Down Expand Up @@ -32,7 +32,7 @@ export default defineConfig({
{ text: 'Contact', link: '../contact.md' },
],
logo: '/favicon.ico',
sidebar: getSidebar(),
sidebar: builder.emitSidebar(), //getSidebar(),
outline: {
level: 'deep',
},
Expand All @@ -45,10 +45,10 @@ export default defineConfig({
search: {
provider: 'local',
},
docFooter: {
prev: false,
next: false,
},
// docFooter: {
// prev: false,
// next: false,
// },
editLink: {
pattern: ({ filePath }) => {
return `https://github.com/sharpchen/sharpchen.github.io/edit/main/docs/${filePath}`;
Expand Down
2 changes: 1 addition & 1 deletion docs/.vitepress/theme/custom.css
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
--vp-home-hero-name-background: -webkit-linear-gradient(120deg, #fa5c15, rgb(251, 70, 202));
--vp-font-family-mono: ui-monospace, 'SF Mono SC', SFMono-Regular, 'SF Mono', 'Cascadia Code', Menlo, 'JetBrains Mono', Monaco,
Consolas, 'Liberation Mono', 'Courier New', monospace;
--vp-font-family-base: Roboto, 'Chinese Quotes', 'Inter var', 'Inter', ui-sans-serif,
--vp-font-family-base: 'Chinese Quotes', 'Inter var', 'Inter', ui-sans-serif,
system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto,
'Helvetica Neue', Helvetica, Arial, 'Noto Sans', sans-serif,
'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji';
Expand Down
65 changes: 61 additions & 4 deletions docs/data/Features.data.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
import matter from 'gray-matter';
import Enumerable from 'linq';
import { type Feature } from 'vitepress/dist/client/theme-default/components/VPFeatures.vue';
import { Path, documentRoot } from '../shared/FileSystem';

// const matter = require('gray-matter');
const featuresLiteral = `---
features:
Expand Down Expand Up @@ -50,11 +53,65 @@ features:
linkText: Get started
---
`;

const featuresItems: Feature[] = matter(featuresLiteral).data.features;
const articleLiteral = `---
features:
- title: Articles
details: Regular articles
icon: 📰
linkText: Let's go
#link: /document/Articles/docs/Start your first npm package - Build, CI and Publish.md
---`;
const getIndexLink = (title: string): string | undefined => {
const docs = documentRoot()
.getDirectories()
.find(x => x.name.toLowerCase() === title.toLowerCase())
?.getDirectories()
.find(x => x.name === 'docs');
if (!docs) return;
if (docs.getDirectories().length > 0) {
const folder = Enumerable.from(docs.getDirectories())
.where(x => x.getFiles().length > 0)
.orderBy(x => x.name)
.firstOrDefault();
const file = folder?.getFiles()[0];
return `${documentRoot().name}/${title}/docs/${folder?.name}/${Path.GetFileNameWithoutExtension(file?.name!)}`;
}
if (docs.getFiles().length > 0) {
const file = Enumerable.from(docs.getFiles())
.orderBy(x => x.name)
.firstOrDefault();
return `${documentRoot().name}/${title}/docs/${Path.GetFileNameWithoutExtension(file?.name!)}`;
}
};
function addLinkToFeature(features: Feature[]): Feature[] {
const names = documentRoot()
.getDirectories()
.map(x => x.name);
for (const key in features) {
if (Object.prototype.hasOwnProperty.call(features, key)) {
const feature = features[key];
const match = names.find(x => x.toLowerCase() === feature.title.toLowerCase());
if (match) {
const link = getIndexLink(
// cs design pattern has conflict that I just leave it with a simple solution.
feature.title.includes('CSharp') ? feature.title.replace('CSharp', 'Csharp') : feature.title
);
feature.link = link ? link : '/';
}
}
}
return features;
}
const featuresItems: Feature[] = addLinkToFeature(matter(featuresLiteral).data.features);
const articleFeature: Feature[] = addLinkToFeature(matter(articleLiteral).data.features);
const loader = {
load: (): Feature[] => featuresItems,
load: (): FeatureCompose => ({ features: featuresItems, articleFeature: articleFeature }),
};

export default loader;
export declare const data: Feature[];
type FeatureCompose = {
features: Feature[];
articleFeature: Feature[];
};

export declare const data: FeatureCompose;
13 changes: 4 additions & 9 deletions docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,23 +7,18 @@ hero:
image:
# src: /favicon.ico
alt: sharpchen
features:
- title: Articles
details: Regular articles
icon: 📰
linkText: Let's go
link: /articles
---

<VPFeatures :features="articleFeature"/>
<VPHero name="Documents"/>
<VPFeatures :features="features"/>

<script lang="ts" setup>
import Enumerable from 'linq';
import VPFeatures, { type Feature } from 'vitepress/dist/client/theme-default/components/VPFeatures.vue';
import VPHero from 'vitepress/dist/client/theme-default/components/VPHero.vue';
import { ref } from 'vue';
import { data } from './data/Features.data';

const features: Feature[] = Enumerable.from(data).orderBy(_x => Math.random()).toArray()

const features: Feature[] = Enumerable.from(data.features).orderBy(_x => Math.random()).toArray();
const articleFeature = ref(data.articleFeature);
</script>
95 changes: 95 additions & 0 deletions docs/shared/multipleSidebarBuilder.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
import Enumerable from 'linq';
import { DefaultTheme } from 'vitepress';
import { DirectoryInfo, FileInfo, Path, documentRoot } from '../shared/FileSystem';
const docRoot = documentRoot();
export const builder = {
base: `/${docRoot.name}` as string | undefined,
sidebar: {} as DefaultTheme.SidebarMulti,
rewrites: {} as Record<string, string>,
registerSidebarAuto: function () {
if (!this.base) throw new Error('base not set');
const docFolders = docRoot.getDirectories();
for (const index in docFolders) {
if (Object.prototype.hasOwnProperty.call(docFolders, index)) {
const docParent = docFolders[index];
const docs = docParent.getDirectories().find(d => d.name === 'docs');
if (!docs) throw new Error(`doc folder not found`);
const current: DefaultTheme.SidebarItem[] = [
{
text: docParent.name,
items: folderToSidebarItems(docs, `${this.base}/${docParent.name}`),
},
];
this.sidebar[`${this.base}/${docParent.name}/docs/`] = current;
}
}
return this;
},
emitSidebar: function (): DefaultTheme.SidebarMulti {
return this.sidebar;
},
emitRewrites: function (): Record<string, string> {
return this.rewrites;
},
registerRewritesAuto: function () {
if (!Object.keys(this.sidebar).length) throw new Error('sidebar not set');
for (const sidebarRoute in this.sidebar) {
if (Object.prototype.hasOwnProperty.call(this.sidebar, sidebarRoute)) {
const sidebar = (this.sidebar as DefaultTheme.SidebarMulti)[sidebarRoute] as DefaultTheme.SidebarItem[];
const { items: collapsibleOrLinkOnly } = sidebar[0]; // the items of first is the actual content
let index: string;
// if no second level
if (Enumerable.from(collapsibleOrLinkOnly!).any(i => i.items === void 0)) {
index = Enumerable.from(collapsibleOrLinkOnly!)
.where(i => i.link !== void 0)
.firstOrDefault()?.link!;
this.rewrites[`${index}`] = `${sidebarRoute}index.html`;
continue;
}
// find a collapsible
const parentOfIndex = Enumerable.from(collapsibleOrLinkOnly!)
.where(i => i.items !== void 0 && i.items.length > 0)
.orderBy(i => i.text)
.firstOrDefault();
index = Enumerable.from(parentOfIndex?.items!)
.where(i => i.link !== void 0)
.orderBy(i => i.text)
.firstOrDefault()?.link!;
this.rewrites[`${index}`] = `${sidebarRoute}index.html`;
}
}
return this;
},
};
builder.registerSidebarAuto().registerRewritesAuto();

function filesToSidebarItems(files: FileInfo[], base: string): DefaultTheme.SidebarItem[] {
return files.map(file => {
const link = `${base}/${file.name}`;
return {
text: Path.GetFileNameWithoutExtension(file.name),
link: link.substring(0, link.lastIndexOf('.')),
};
});
}

function folderToSidebarItems(folder: DirectoryInfo, base: string): DefaultTheme.SidebarItem[] {
if (!folder.exists) throw new Error(`folder: ${folder.name} not found`);
const subs = folder.getDirectories();
// load files in this folder
let items: DefaultTheme.SidebarItem[] = folder.getFiles().length
? filesToSidebarItems(folder.getFiles(), `${base}/${folder.name}`)
: [];
for (const index in subs) {
if (Object.prototype.hasOwnProperty.call(subs, index)) {
const sub = subs[index];
const currentSidebarItem: DefaultTheme.SidebarItem = {
collapsed: false,
text: sub.name.replace(/^\d+\.\s*/, ''), // remove leading index
items: folderToSidebarItems(sub, `${base}/${folder.name}`),
};
items.push(currentSidebarItem);
}
}
return items;
}

0 comments on commit 46eccfe

Please sign in to comment.