Improve breadcrumb and code block controls
This commit is contained in:
+68
-31
@@ -103,6 +103,72 @@ function renderPage({ title, nav, docTheme, customThemeHref, themes, initialThem
|
||||
});
|
||||
}
|
||||
|
||||
function normalizeEntryName(name) {
|
||||
return String(name)
|
||||
.replace(/\.(md|markdown)$/i, '')
|
||||
.toLowerCase()
|
||||
.replace(/[\s\-_.]+/g, '');
|
||||
}
|
||||
|
||||
function selectDefaultFile(nav, rootDir) {
|
||||
const rootFiles = Array.isArray(nav)
|
||||
? nav.filter((item) => item.type === 'file')
|
||||
: [];
|
||||
|
||||
if (rootFiles.length === 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const rootDirName = normalizeEntryName(path.basename(rootDir));
|
||||
const matchers = [
|
||||
(name) => name.includes('index'),
|
||||
(name) => name.includes('首页'),
|
||||
(name) => rootDirName && (name.includes(rootDirName) || rootDirName.includes(name)),
|
||||
(name) => name.includes('readme')
|
||||
];
|
||||
|
||||
for (const matcher of matchers) {
|
||||
const matched = rootFiles.find((item) => matcher(normalizeEntryName(item.name)));
|
||||
if (matched) {
|
||||
return matched.path;
|
||||
}
|
||||
}
|
||||
|
||||
return rootFiles[0].path;
|
||||
}
|
||||
|
||||
function buildInitialContent(renderer, rootDir, relativeFilePath) {
|
||||
if (!relativeFilePath) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const fullPath = path.join(rootDir, relativeFilePath);
|
||||
if (!fs.existsSync(fullPath)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const content = fs.readFileSync(fullPath, 'utf-8');
|
||||
const env = { filePath: relativeFilePath };
|
||||
const html = renderer.render(stripLeadingTitle(content), env);
|
||||
const stats = fs.statSync(fullPath);
|
||||
const match = content.match(/^#\s+(.+)$/m);
|
||||
const fileName = path.basename(relativeFilePath);
|
||||
const pageTitle = match ? match[1].trim() : fileName.replace(/\.(md|markdown)$/i, '');
|
||||
const chineseChars = (content.match(/[\u4e00-\u9fff\u3400-\u4dbf\uf900-\ufaff]/g) || []).length;
|
||||
const englishWords = (content.match(/[a-zA-Z0-9]+/g) || []).length;
|
||||
|
||||
return {
|
||||
title: pageTitle,
|
||||
html,
|
||||
meta: {
|
||||
created: stats.birthtime.toISOString(),
|
||||
modified: stats.mtime.toISOString(),
|
||||
wordCount: chineseChars + englishWords,
|
||||
fileName
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Create and start the webook server
|
||||
*/
|
||||
@@ -205,37 +271,8 @@ function createServer(opts) {
|
||||
app.get('/', (req, res) => {
|
||||
try {
|
||||
const nav = scanDirectory(dir);
|
||||
// Try to find a README.md or index.md as default
|
||||
const defaultFiles = ['README.md', 'readme.md', 'index.md', 'INDEX.md'];
|
||||
let initialContent = null;
|
||||
let defaultFile = null;
|
||||
|
||||
for (const df of defaultFiles) {
|
||||
const dfPath = path.join(dir, df);
|
||||
if (fs.existsSync(dfPath)) {
|
||||
defaultFile = df;
|
||||
const content = fs.readFileSync(dfPath, 'utf-8');
|
||||
const env = { filePath: df };
|
||||
const html = renderer.render(stripLeadingTitle(content), env);
|
||||
const stats = fs.statSync(dfPath);
|
||||
const match = content.match(/^#\s+(.+)$/m);
|
||||
const dfTitle = match ? match[1].trim() : df.replace(/\.md$/i, '');
|
||||
const chineseChars = (content.match(/[\u4e00-\u9fff\u3400-\u4dbf\uf900-\ufaff]/g) || []).length;
|
||||
const englishWords = (content.match(/[a-zA-Z0-9]+/g) || []).length;
|
||||
|
||||
initialContent = {
|
||||
title: dfTitle,
|
||||
html,
|
||||
meta: {
|
||||
created: stats.birthtime.toISOString(),
|
||||
modified: stats.mtime.toISOString(),
|
||||
wordCount: chineseChars + englishWords,
|
||||
fileName: df
|
||||
}
|
||||
};
|
||||
break;
|
||||
}
|
||||
}
|
||||
const defaultFile = selectDefaultFile(nav, dir);
|
||||
const initialContent = buildInitialContent(renderer, dir, defaultFile);
|
||||
|
||||
res.send(renderPage({
|
||||
title,
|
||||
|
||||
Reference in New Issue
Block a user