@kenjura/ursa 0.39.0 → 0.41.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +10 -0
- package/meta/default-template.html +3 -0
- package/meta/default.css +37 -0
- package/package.json +1 -1
- package/src/helper/automenu.js +1 -1
- package/src/jobs/generate.js +91 -2
package/CHANGELOG.md
CHANGED
package/meta/default.css
CHANGED
|
@@ -432,6 +432,43 @@ article#main-content {
|
|
|
432
432
|
}
|
|
433
433
|
}
|
|
434
434
|
|
|
435
|
+
/* Footer styles */
|
|
436
|
+
footer#site-footer {
|
|
437
|
+
width: var(--article-width);
|
|
438
|
+
margin: 3rem auto 2rem auto;
|
|
439
|
+
padding-top: 2rem;
|
|
440
|
+
border-top: 1px solid rgba(128, 128, 128, 0.3);
|
|
441
|
+
text-align: center;
|
|
442
|
+
|
|
443
|
+
.footer-content {
|
|
444
|
+
margin-bottom: 1.5rem;
|
|
445
|
+
font-size: 0.95rem;
|
|
446
|
+
opacity: 0.85;
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
.footer-meta {
|
|
450
|
+
font-size: 0.8rem;
|
|
451
|
+
opacity: 0.6;
|
|
452
|
+
margin-bottom: 0.5rem;
|
|
453
|
+
|
|
454
|
+
a {
|
|
455
|
+
color: inherit;
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
.footer-copyright {
|
|
460
|
+
font-size: 0.8rem;
|
|
461
|
+
opacity: 0.6;
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
@media (max-width: 800px) {
|
|
466
|
+
footer#site-footer {
|
|
467
|
+
width: calc(100vw - 2rem);
|
|
468
|
+
margin: 3rem 1rem 2rem 1rem;
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
|
|
435
472
|
@media (max-width: 800px) {
|
|
436
473
|
nav#nav-global {
|
|
437
474
|
display: flex;
|
package/package.json
CHANGED
package/src/helper/automenu.js
CHANGED
|
@@ -129,7 +129,7 @@ function buildMenuData(tree, source, validPaths, parentPath = '') {
|
|
|
129
129
|
const items = [];
|
|
130
130
|
|
|
131
131
|
// Files to hide from menu by default
|
|
132
|
-
const hiddenFiles = ['config.json', 'style.css'];
|
|
132
|
+
const hiddenFiles = ['config.json', 'style.css', 'footer.md'];
|
|
133
133
|
|
|
134
134
|
for (const item of tree.children || []) {
|
|
135
135
|
const ext = extname(item.path);
|
package/src/jobs/generate.js
CHANGED
|
@@ -128,6 +128,9 @@ export async function generate({
|
|
|
128
128
|
|
|
129
129
|
const menu = await getMenu(allSourceFilenames, source, validPaths);
|
|
130
130
|
|
|
131
|
+
// Generate footer content
|
|
132
|
+
const footer = await getFooter(source, _source);
|
|
133
|
+
|
|
131
134
|
// Load content hash cache from .ursa folder in source directory
|
|
132
135
|
let hashCache = new Map();
|
|
133
136
|
if (!_clean) {
|
|
@@ -285,7 +288,8 @@ export async function generate({
|
|
|
285
288
|
.replace("${transformedMetadata}", transformedMetadata)
|
|
286
289
|
.replace("${body}", body)
|
|
287
290
|
.replace("${embeddedStyle}", embeddedStyle)
|
|
288
|
-
.replace("${searchIndex}", JSON.stringify(searchIndex))
|
|
291
|
+
.replace("${searchIndex}", JSON.stringify(searchIndex))
|
|
292
|
+
.replace("${footer}", footer);
|
|
289
293
|
|
|
290
294
|
// Resolve links and mark broken internal links as inactive (debug mode on)
|
|
291
295
|
// Pass docUrlPath so relative links can be resolved correctly
|
|
@@ -378,7 +382,8 @@ export async function generate({
|
|
|
378
382
|
.replace("${title}", "Index")
|
|
379
383
|
.replace("${meta}", "{}")
|
|
380
384
|
.replace("${transformedMetadata}", "")
|
|
381
|
-
.replace("${embeddedStyle}", "")
|
|
385
|
+
.replace("${embeddedStyle}", "")
|
|
386
|
+
.replace("${footer}", footer);
|
|
382
387
|
console.log(`writing directory index to ${htmlOutputFilename}`);
|
|
383
388
|
await outputFile(htmlOutputFilename, finalHtml);
|
|
384
389
|
}
|
|
@@ -541,3 +546,87 @@ function addTrailingSlash(somePath) {
|
|
|
541
546
|
if (somePath[somePath.length - 1] == "/") return somePath;
|
|
542
547
|
return `${somePath}/`;
|
|
543
548
|
}
|
|
549
|
+
|
|
550
|
+
/**
|
|
551
|
+
* Generate footer HTML from footer.md and package.json
|
|
552
|
+
* @param {string} source - resolved source path with trailing slash
|
|
553
|
+
* @param {string} _source - original source path
|
|
554
|
+
*/
|
|
555
|
+
async function getFooter(source, _source) {
|
|
556
|
+
const footerParts = [];
|
|
557
|
+
|
|
558
|
+
// Try to read footer.md from source root
|
|
559
|
+
const footerPath = join(source, 'footer.md');
|
|
560
|
+
try {
|
|
561
|
+
if (existsSync(footerPath)) {
|
|
562
|
+
const footerMd = await readFile(footerPath, 'utf8');
|
|
563
|
+
const footerHtml = renderFile({ fileContents: footerMd, type: '.md' });
|
|
564
|
+
footerParts.push(`<div class="footer-content">${footerHtml}</div>`);
|
|
565
|
+
}
|
|
566
|
+
} catch (e) {
|
|
567
|
+
console.error(`Error reading footer.md: ${e.message}`);
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
// Try to read package.json from doc repo (check both source dir and parent)
|
|
571
|
+
let docPackage = null;
|
|
572
|
+
const sourceDir = resolve(_source);
|
|
573
|
+
const packagePaths = [
|
|
574
|
+
join(sourceDir, 'package.json'), // In source dir itself
|
|
575
|
+
join(sourceDir, '..', 'package.json'), // One level up (if docs is a subfolder)
|
|
576
|
+
];
|
|
577
|
+
|
|
578
|
+
for (const packagePath of packagePaths) {
|
|
579
|
+
try {
|
|
580
|
+
if (existsSync(packagePath)) {
|
|
581
|
+
const packageJson = await readFile(packagePath, 'utf8');
|
|
582
|
+
docPackage = JSON.parse(packageJson);
|
|
583
|
+
console.log(`Found doc package.json at ${packagePath}`);
|
|
584
|
+
break;
|
|
585
|
+
}
|
|
586
|
+
} catch (e) {
|
|
587
|
+
// Continue to next path
|
|
588
|
+
}
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
// Get ursa version from ursa's own package.json
|
|
592
|
+
// Use import.meta.url to find the package.json relative to this file
|
|
593
|
+
let ursaVersion = 'unknown';
|
|
594
|
+
try {
|
|
595
|
+
// From src/jobs/generate.js, go up to package root
|
|
596
|
+
const currentFileUrl = new URL(import.meta.url);
|
|
597
|
+
const currentDir = dirname(currentFileUrl.pathname);
|
|
598
|
+
const ursaPackagePath = resolve(currentDir, '..', '..', 'package.json');
|
|
599
|
+
|
|
600
|
+
if (existsSync(ursaPackagePath)) {
|
|
601
|
+
const ursaPackageJson = await readFile(ursaPackagePath, 'utf8');
|
|
602
|
+
const ursaPackage = JSON.parse(ursaPackageJson);
|
|
603
|
+
ursaVersion = ursaPackage.version;
|
|
604
|
+
console.log(`Found ursa package.json at ${ursaPackagePath}, version: ${ursaVersion}`);
|
|
605
|
+
}
|
|
606
|
+
} catch (e) {
|
|
607
|
+
console.error(`Error reading ursa package.json: ${e.message}`);
|
|
608
|
+
}
|
|
609
|
+
|
|
610
|
+
// Build meta line: version, timestamp, "generated by ursa"
|
|
611
|
+
const metaParts = [];
|
|
612
|
+
if (docPackage?.version) {
|
|
613
|
+
metaParts.push(`v${docPackage.version}`);
|
|
614
|
+
}
|
|
615
|
+
metaParts.push(new Date().toISOString().split('T')[0]); // YYYY-MM-DD
|
|
616
|
+
metaParts.push(`Generated by <a href="https://www.npmjs.com/package/@kenjura/ursa">ursa</a> v${ursaVersion}`);
|
|
617
|
+
|
|
618
|
+
footerParts.push(`<div class="footer-meta">${metaParts.join(' • ')}</div>`);
|
|
619
|
+
|
|
620
|
+
// Copyright line from doc package.json
|
|
621
|
+
if (docPackage?.copyright) {
|
|
622
|
+
footerParts.push(`<div class="footer-copyright">${docPackage.copyright}</div>`);
|
|
623
|
+
} else if (docPackage?.author) {
|
|
624
|
+
const year = new Date().getFullYear();
|
|
625
|
+
const author = typeof docPackage.author === 'string' ? docPackage.author : docPackage.author.name;
|
|
626
|
+
if (author) {
|
|
627
|
+
footerParts.push(`<div class="footer-copyright">© ${year} ${author}</div>`);
|
|
628
|
+
}
|
|
629
|
+
}
|
|
630
|
+
|
|
631
|
+
return footerParts.join('\n');
|
|
632
|
+
}
|