@t8/docsgen 0.3.36 → 0.4.1

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/dist/bin.js CHANGED
@@ -319,6 +319,105 @@ function escapeHTML(x) {
319
319
  return s;
320
320
  }
321
321
 
322
+ // src/bin/content/getCounterContent.ts
323
+ function getCounterContent({ ymid }) {
324
+ if (!ymid) return "";
325
+ return `
326
+ <script>
327
+ (function(m,e,t,r,i,k,a){m[i]=m[i]||function(){(m[i].a=m[i].a||[]).push(arguments)};
328
+ m[i].l=1*new Date();
329
+ for (var j = 0; j < document.scripts.length; j++) {if (document.scripts[j].src === r) { return; }}
330
+ k=e.createElement(t),a=e.getElementsByTagName(t)[0],k.async=1,k.src=r,a.parentNode.insertBefore(k,a)})
331
+ (window, document, "script", "https://mc.yandex.com/metrika/tag.js", "ym");
332
+ ym(${ymid}, "init", {clickmap: true, trackLinks: true, accurateTrackBounce: true});
333
+ </script>
334
+ <noscript><div><img src="https://mc.yandex.com/watch/${ymid}" style="position:absolute;left:-9999px;" alt=""></div></noscript>
335
+ `.trim();
336
+ }
337
+
338
+ // src/bin/content/getIcon.ts
339
+ var iconTypeMap = {
340
+ ico: "image/x-icon",
341
+ svg: "image/svg+xml",
342
+ png: "image/png",
343
+ gif: "image/gif",
344
+ jpg: "image/jpeg",
345
+ jpeg: "image/jpeg"
346
+ };
347
+ function getIcon({ favicon, faviconType }) {
348
+ let icon = {
349
+ url: favicon,
350
+ type: faviconType
351
+ };
352
+ if (icon.url && !icon.type) {
353
+ let ext = icon.url.split("/").at(-1)?.split(".").at(-1)?.toLowerCase();
354
+ if (ext) icon.type = iconTypeMap[ext];
355
+ }
356
+ return icon;
357
+ }
358
+
359
+ // src/bin/content/getIconTag.ts
360
+ function getIconTag(ctx) {
361
+ let { url, type } = getIcon(ctx);
362
+ return url ? `<link rel="icon"${type ? ` type="${type}"` : ""} href="${url}">` : "";
363
+ }
364
+
365
+ // src/bin/content/getInjectedContent.ts
366
+ function getInjectedContent(ctx, page, target, mode) {
367
+ let injectedContent = ctx[mode]?.[target];
368
+ if (!injectedContent) return "";
369
+ return (Array.isArray(injectedContent) ? injectedContent : [injectedContent]).reduce((s, item) => {
370
+ if (item === void 0) return s;
371
+ if (typeof item === "string") return `${s}${s ? "\n" : ""}${item}`;
372
+ let { content, pages } = item;
373
+ if (!content || pages && !pages.includes(page)) return s;
374
+ return `${s}${s ? "\n" : ""}${content}`;
375
+ }, "");
376
+ }
377
+
378
+ // src/bin/content/toFileContent.ts
379
+ function toFileContent(x) {
380
+ let s = x.replace(
381
+ /\s+(\r?\n *<\/?(script|link|head|body|html|meta|title)[> ])/g,
382
+ "$1"
383
+ ).replace(
384
+ /\s+(\r?\n *<\/?(main|header|footer|nav|section|div|h\d|p|ul|ol|li|table)[> ])/g,
385
+ "$1"
386
+ ).trim();
387
+ return `${s}
388
+ `;
389
+ }
390
+
391
+ // src/bin/content/getRedirectContent.ts
392
+ function getRedirectContent(ctx) {
393
+ let { redirect } = ctx;
394
+ let escapedRedirect = escapeHTML(redirect);
395
+ return toFileContent(`
396
+ <!DOCTYPE html>
397
+ <html lang="en" data-layout="redirect" class="blank">
398
+ <head>
399
+ ${getInjectedContent(ctx, "redirect", "head", "prepend")}
400
+ <meta charset="utf-8">
401
+ <meta name="viewport" content="width=device-width">
402
+ <meta http-equiv="refresh" content="0; URL=${escapedRedirect}">
403
+ ${getIconTag(ctx)}
404
+ ${getInjectedContent(ctx, "redirect", "head", "append")}
405
+ </head>
406
+ <body>
407
+ ${getInjectedContent(ctx, "redirect", "body", "prepend")}
408
+ ${getCounterContent(ctx)}
409
+ ${getInjectedContent(ctx, "redirect", "body", "append")}
410
+ <script>window.location.replace("${escapedRedirect}");</script>
411
+ </body>
412
+ </html>
413
+ `);
414
+ }
415
+
416
+ // src/utils/escapeRegExp.ts
417
+ function escapeRegExp(s) {
418
+ return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
419
+ }
420
+
322
421
  // src/bin/getRepoLink.ts
323
422
  function getRepoLink({ repo }, className) {
324
423
  if (!repo) return "";
@@ -547,22 +646,6 @@ async function getParsedContent(ctx) {
547
646
  return parsedContent;
548
647
  }
549
648
 
550
- // src/bin/content/getCounterContent.ts
551
- function getCounterContent({ ymid }) {
552
- if (!ymid) return "";
553
- return `
554
- <script>
555
- (function(m,e,t,r,i,k,a){m[i]=m[i]||function(){(m[i].a=m[i].a||[]).push(arguments)};
556
- m[i].l=1*new Date();
557
- for (var j = 0; j < document.scripts.length; j++) {if (document.scripts[j].src === r) { return; }}
558
- k=e.createElement(t),a=e.getElementsByTagName(t)[0],k.async=1,k.src=r,a.parentNode.insertBefore(k,a)})
559
- (window, document, "script", "https://mc.yandex.com/metrika/tag.js", "ym");
560
- ym(${ymid}, "init", {clickmap: true, trackLinks: true, accurateTrackBounce: true});
561
- </script>
562
- <noscript><div><img src="https://mc.yandex.com/watch/${ymid}" style="position:absolute;left:-9999px;" alt=""></div></noscript>
563
- `.trim();
564
- }
565
-
566
649
  // src/bin/content/getCSSRoot.ts
567
650
  import { exec as defaultExec } from "node:child_process";
568
651
  import { cp } from "node:fs/promises";
@@ -579,6 +662,7 @@ var __filename = fileURLToPath(import.meta.url);
579
662
  var __dirname = dirname(__filename);
580
663
  var packageURL = "";
581
664
  var packageVersionRequest = null;
665
+ var assetsCreated = /* @__PURE__ */ new Map();
582
666
  async function getCSSRoot(ctx, type) {
583
667
  let { dir = "", assetsDir } = ctx;
584
668
  let cssRoot = {
@@ -588,10 +672,14 @@ async function getCSSRoot(ctx, type) {
588
672
  if (assetsDir) {
589
673
  cssRoot.index = assetsDir;
590
674
  cssRoot.content = `../${assetsDir}`;
591
- await cp(join4(__dirname, "css"), join4(dir, cssRoot.index), {
592
- force: true,
593
- recursive: true
594
- });
675
+ let assetsDestination = join4(dir, cssRoot.index);
676
+ if (!assetsCreated.get(assetsDestination)) {
677
+ assetsCreated.set(assetsDestination, true);
678
+ await cp(join4(__dirname, "css"), assetsDestination, {
679
+ force: true,
680
+ recursive: true
681
+ });
682
+ }
595
683
  } else {
596
684
  if (!packageURL) {
597
685
  packageVersionRequest ??= exec(`npm view ${packageName} version`);
@@ -615,44 +703,13 @@ function getDefaultCodeStyleContent(cssRoot) {
615
703
  `.trim();
616
704
  }
617
705
 
618
- // src/bin/content/getIcon.ts
619
- var iconTypeMap = {
620
- ico: "image/x-icon",
621
- svg: "image/svg+xml",
622
- png: "image/png",
623
- gif: "image/gif",
624
- jpg: "image/jpeg",
625
- jpeg: "image/jpeg"
626
- };
627
- function getIcon({ favicon, faviconType }) {
628
- let icon = {
629
- url: favicon,
630
- type: faviconType
631
- };
632
- if (icon.url && !icon.type) {
633
- let ext = icon.url.split("/").at(-1)?.split(".").at(-1)?.toLowerCase();
634
- if (ext) icon.type = iconTypeMap[ext];
635
- }
636
- return icon;
637
- }
638
-
639
- // src/bin/content/getIconTag.ts
640
- function getIconTag(ctx) {
641
- let { url, type } = getIcon(ctx);
642
- return url ? `<link rel="icon"${type ? ` type="${type}"` : ""} href="${url}">` : "";
643
- }
644
-
645
- // src/bin/content/getInjectedContent.ts
646
- function getInjectedContent(ctx, page, target, mode) {
647
- let injectedContent = ctx[mode]?.[target];
648
- if (!injectedContent) return "";
649
- return (Array.isArray(injectedContent) ? injectedContent : [injectedContent]).reduce((s, item) => {
650
- if (item === void 0) return s;
651
- if (typeof item === "string") return `${s}${s ? "\n" : ""}${item}`;
652
- let { content, pages } = item;
653
- if (!content || pages && !pages.includes(page)) return s;
654
- return `${s}${s ? "\n" : ""}${content}`;
655
- }, "");
706
+ // src/bin/content/getInstallationContent.ts
707
+ async function getInstallationContent(ctx) {
708
+ let { name, isDevDep } = ctx;
709
+ let { installation } = await getParsedContent(ctx);
710
+ if (!installation || isDevDep !== void 0)
711
+ installation = `npm i${isDevDep ? " -D" : ""} ${name}`;
712
+ return `<code>${escapeHTML(installation)}</code>`;
656
713
  }
657
714
 
658
715
  // src/bin/content/getPlainTitle.ts
@@ -662,140 +719,12 @@ async function getPlainTitle(ctx) {
662
719
  return escapeHTML(title || stripHTML(htmlTitle || parsedTitle, true) || name);
663
720
  }
664
721
 
665
- // src/bin/content/toFileContent.ts
666
- function toFileContent(x) {
667
- let s = x.replace(
668
- /\s+(\r?\n *<\/?(script|link|head|body|html|meta|title)[> ])/g,
669
- "$1"
670
- ).replace(
671
- /\s+(\r?\n *<\/?(main|header|footer|nav|section|div|h\d|p|ul|ol|li|table)[> ])/g,
672
- "$1"
673
- ).trim();
674
- return `${s}
675
- `;
676
- }
677
-
678
- // src/bin/content/tweakTypography.ts
679
- function tweakTypography(s = "") {
680
- return s.replace(/\b(for|in|on|at|to|with|a|an|the|its)\s+/gi, "$1\xA0").replace(/\b(React)\s+(apps?)\b/gi, "$1\xA0$2");
681
- }
682
-
683
- // src/bin/content/getIndexContent.ts
684
- async function getIndexContent(ctx) {
685
- let {
686
- root,
687
- contentDir = "",
688
- name,
689
- htmlTitle,
690
- description: packageDescription,
691
- isDevDep,
692
- backstory
693
- } = ctx;
694
- let counterContent = getCounterContent(ctx);
695
- let escapedPackageDescription = escapeHTML(packageDescription);
696
- let {
697
- title: parsedTitle,
698
- description,
699
- intro,
700
- features,
701
- note,
702
- installation,
703
- nav
704
- } = await getParsedContent(ctx);
722
+ // src/bin/content/getMainTitle.ts
723
+ async function getMainTitle(ctx) {
724
+ let { htmlTitle } = ctx;
725
+ let { title: parsedTitle } = await getParsedContent(ctx);
705
726
  let plainTitle = await getPlainTitle(ctx);
706
- let coverTitle = htmlTitle || parsedTitle || plainTitle;
707
- let descriptionContent = tweakTypography(description) || (escapedPackageDescription ? `<p>${tweakTypography(escapedPackageDescription)}<p>` : "");
708
- if (!installation || isDevDep !== void 0)
709
- installation = `npm i${isDevDep ? " -D" : ""} ${name}`;
710
- let cssRoot = await getCSSRoot(ctx, "index");
711
- return toFileContent(`
712
- <!DOCTYPE html>
713
- <html lang="en" data-layout="index">
714
- <head>
715
- ${getInjectedContent(ctx, "index", "head", "prepend")}
716
- <meta charset="utf-8">
717
- <meta name="viewport" content="width=device-width, initial-scale=1">
718
- <meta name="description" content="${plainTitle}${escapedPackageDescription ? `: ${escapedPackageDescription}` : ""}">
719
- <title>${plainTitle}${escapedPackageDescription ? ` | ${escapedPackageDescription}` : ""}</title>
720
- <link rel="stylesheet" href="${cssRoot}/base.css">
721
- <link rel="stylesheet" href="${cssRoot}/index.css">
722
- ${getIconTag(ctx)}
723
- <link rel="prefetch" href="${root}start">
724
- ${nav[0] ? `<link rel="prefetch" href="${root}${contentDir}/${nav[0]?.id ?? ""}">` : ""}
725
- ${getInjectedContent(ctx, "index", "head", "append")}
726
- </head>
727
- <body>
728
- ${getInjectedContent(ctx, "index", "body", "prepend")}
729
- <div class="layout">
730
- <main>
731
- <section class="aux intro-title">
732
- <div class="section-content">
733
- ${getInjectedContent(ctx, "index", "cover", "prepend")}
734
- <h1>${coverTitle}</h1>
735
- <div class="description">
736
- ${descriptionContent}
737
- </div>
738
- <p class="actions">
739
- <a href="${root}start" class="primary">Docs</a>
740
- <span class="sep"> \u2022 </span>
741
- ${getRepoLink(ctx)}
742
- </p>
743
- ${backstory ? `<p class="ref"><a href="${backstory}">Backstory</a></p>` : ""}
744
- <p class="installation"><code>${escapeHTML(installation)}</code></p>
745
- ${getInjectedContent(ctx, "index", "cover", "append")}
746
- </div>
747
- </section>
748
- ${intro || features || note ? `
749
- <section class="intro">
750
- <div class="section-content">
751
- ${intro ? `<div class="intro">${intro}</div>` : ""}
752
- ${features ? `<div class="features">${features}</div>` : ""}
753
- ${note ? `<div class="note">${note}</div>` : ""}
754
- <p class="pagenav">
755
- <span class="next"><a href="${root}start">To the docs</a> <span class="icon">\u2192</span></span>
756
- </p>
757
- </div>
758
- </section>
759
- ` : ""}
760
- </main>
761
- </div>
762
-
763
- ${[description, intro, features, note].some((s) => s.includes("<pre><code ")) ? getInjectedContent(ctx, "index", ":has-code", "append") || getDefaultCodeStyleContent(cssRoot) : ""}
764
- ${counterContent}
765
- ${getInjectedContent(ctx, "index", "body", "append")}
766
- </body>
767
- </html>
768
- `);
769
- }
770
-
771
- // src/bin/content/getRedirectContent.ts
772
- function getRedirectContent(ctx) {
773
- let { redirect } = ctx;
774
- let escapedRedirect = escapeHTML(redirect);
775
- return toFileContent(`
776
- <!DOCTYPE html>
777
- <html lang="en" data-layout="redirect" class="blank">
778
- <head>
779
- ${getInjectedContent(ctx, "redirect", "head", "prepend")}
780
- <meta charset="utf-8">
781
- <meta name="viewport" content="width=device-width">
782
- <meta http-equiv="refresh" content="0; URL=${escapedRedirect}">
783
- ${getIconTag(ctx)}
784
- ${getInjectedContent(ctx, "redirect", "head", "append")}
785
- </head>
786
- <body>
787
- ${getInjectedContent(ctx, "redirect", "body", "prepend")}
788
- ${getCounterContent(ctx)}
789
- ${getInjectedContent(ctx, "redirect", "body", "append")}
790
- <script>window.location.replace("${escapedRedirect}");</script>
791
- </body>
792
- </html>
793
- `);
794
- }
795
-
796
- // src/utils/escapeRegExp.ts
797
- function escapeRegExp(s) {
798
- return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
727
+ return htmlTitle || parsedTitle || plainTitle;
799
728
  }
800
729
 
801
730
  // src/bin/content/getNav.ts
@@ -875,7 +804,7 @@ async function getNav(ctx, navItems) {
875
804
  s = s ? `<section>
876
805
  ${s}
877
806
  </section>` : "";
878
- return `<nav class="aux">
807
+ return `<nav>
879
808
  ${s}
880
809
  ${navContent}
881
810
  </nav>`;
@@ -884,10 +813,12 @@ ${navContent}
884
813
  // src/bin/content/getSectionContent.ts
885
814
  async function getSectionContent(ctx, index) {
886
815
  let { root, contentDir = "" } = ctx;
816
+ let escapedPackageDescription = escapeHTML(ctx.description);
887
817
  let cssRoot = await getCSSRoot(ctx, "content");
888
818
  let { sections, nav } = await getParsedContent(ctx);
889
819
  let content = sections[index];
890
820
  let navContent = await getNav(ctx, nav);
821
+ let mainTitle = await getMainTitle(ctx);
891
822
  let plainTitle = await getPlainTitle(ctx);
892
823
  return toFileContent(`
893
824
  <!DOCTYPE html>
@@ -908,9 +839,14 @@ async function getSectionContent(ctx, index) {
908
839
  <body>
909
840
  ${getInjectedContent(ctx, "section", "body", "prepend")}
910
841
  <div class="layout">
842
+ <header class="aux">
843
+ <h1>${mainTitle}</h1>
844
+ <div class="description">
845
+ <p>${escapedPackageDescription}</p>
846
+ </div>
847
+ </header>
911
848
  <div class="${navContent ? "" : "no-nav "}body">
912
849
  <main>
913
- <h1><a href="${root}">${plainTitle}</a></h1>
914
850
  ${content}
915
851
 
916
852
  <p class="pagenav">
@@ -922,13 +858,22 @@ ${content}
922
858
  ${nav[index + 1]?.id ? `<span class="next"><a href="${root}${contentDir}/${nav[index + 1]?.id}">${nav[index + 1]?.title}</a> <span class="icon">\u2192</span></span>` : `<span class="repo">${getRepoLink(ctx)}</span>`}
923
859
  </p>
924
860
  </main>
925
- ${navContent ? "<hr>" : ""}
861
+ <hr>
862
+ <aside class="aux">
863
+ <div class="header" hidden>
864
+ <h1>${mainTitle}</h1>
865
+ <div class="description">
866
+ <p>${escapedPackageDescription}</p>
867
+ <p class="installation">${await getInstallationContent(ctx)}</p>
868
+ </div>
869
+ </div>
926
870
  ${navContent.replace(
927
871
  new RegExp(
928
872
  `(<li data-id="${escapeRegExp(nav[index]?.id)}">)<a href="[^"]+">([^<]+)</a>`
929
873
  ),
930
874
  "$1<strong>$2</strong>"
931
875
  )}
876
+ </aside>
932
877
  </div>
933
878
  </div>
934
879
 
@@ -988,7 +933,8 @@ async function setContent(ctx) {
988
933
  await getSectionContent(ctx, i)
989
934
  )
990
935
  ),
991
- writeFile2(join5(dir, "index.html"), await getIndexContent(ctx)),
936
+ // writeFile(join(dir, "index.html"), await getIndexContent(ctx)),
937
+ writeFile2(join5(dir, "index.html"), await getStartContent(ctx)),
992
938
  writeFile2(join5(dir, "start.html"), await getStartContent(ctx))
993
939
  ]);
994
940
  }
package/dist/css/base.css CHANGED
@@ -41,9 +41,9 @@
41
41
  }
42
42
  }
43
43
  :root {
44
- --max-content-width: 45em;
44
+ --max-content-width: 720px;
45
45
  --content-padding-x: 1.75rem;
46
- --content-padding-y: 1.75rem;
46
+ --content-padding-y: 1rem;
47
47
  --block-margin-y: 1em;
48
48
  --sep-line: 0.3rem solid var(--line-color);
49
49
 
@@ -70,7 +70,7 @@ body {
70
70
  :root {
71
71
  --max-content-width: 100%;
72
72
  --content-padding-x: 0.85rem;
73
- --content-padding-y: 1rem;
73
+ --content-padding-y: 0.65rem;
74
74
  }
75
75
  body {
76
76
  font-size: 100%;
@@ -8,6 +8,25 @@ footer {
8
8
  padding: 0 var(--content-padding-x);
9
9
  }
10
10
 
11
+ header {
12
+ display: none;
13
+ text-align: center;
14
+ padding-top: 0.5em;
15
+ padding-bottom: 0.5em;
16
+ }
17
+ header h1 {
18
+ font-size: 1.25em;
19
+ font-weight: 900;
20
+ margin: 0;
21
+ }
22
+ header .description {
23
+ font-size: 0.8em;
24
+ margin-top: 0.15em;
25
+ }
26
+ header .description p {
27
+ margin: 0;
28
+ }
29
+
11
30
  .body {
12
31
  min-height: 100vh;
13
32
  display: flex;
@@ -20,19 +39,22 @@ footer {
20
39
  display: none;
21
40
  }
22
41
  @media (max-width: 840px) {
42
+ header {
43
+ display: block;
44
+ }
23
45
  .body {
24
46
  flex-direction: column;
25
47
  padding: 0;
26
48
  }
27
49
  }
28
- .body > nav {
50
+ aside {
29
51
  width: 25%;
30
52
  display: flex;
31
53
  flex-direction: column;
32
54
  align-items: flex-end;
33
55
  flex: none;
34
56
  align-self: stretch;
35
- font-size: 0.9em;
57
+ font-size: 0.87em;
36
58
  line-height: 1.25;
37
59
  text-align: end;
38
60
  background: linear-gradient(
@@ -41,65 +63,104 @@ footer {
41
63
  var(--aux-background-end)
42
64
  );
43
65
  border-right: 0.05em solid var(--aux-border-color);
44
- padding: 0.75rem var(--content-padding-x);
66
+ padding: var(--content-padding-y) var(--content-padding-x);
45
67
  margin: 0;
46
68
  box-sizing: border-box;
47
69
  }
48
- .body > nav section {
70
+ aside > .header {
71
+ display: block;
72
+ margin: 0.5rem 0 0.25rem;
73
+ }
74
+ aside > .header .description p:not(.installation) {
75
+ font-size: 0.9em;
76
+ margin: 0.35em 0 0;
77
+ }
78
+ aside > .header .description p.installation {
79
+ margin: 1em 0 0;
80
+ }
81
+ aside > .header .installation code {
82
+ display: inline-block;
83
+ background: transparent;
84
+ border: 0.05em solid;
85
+ border-radius: 0.5em;
86
+ padding: 0.35em 0.75em;
87
+ margin: 0;
88
+ }
89
+ aside h1 {
90
+ font-size: 1.35em;
91
+ font-weight: 900;
92
+ margin: 0;
93
+ }
94
+ aside h1 > a,
95
+ aside h1 > a:link,
96
+ aside h1 > a:hover,
97
+ aside h1 > a:visited,
98
+ aside h1 > a:active {
99
+ --color: var(--aux-color);
100
+ text-decoration: underline;
101
+ border-bottom: none;
102
+ }
103
+ aside h1 sup {
104
+ font-size: 0.5em;
105
+ }
106
+ aside nav {
107
+ font-size: 0.8rem;
108
+ }
109
+ aside section {
49
110
  width: 100%;
50
111
  max-width: 16em;
51
112
  padding: 1rem 0;
52
113
  box-sizing: border-box;
53
114
  }
54
- .body > nav section + section {
115
+ aside section + section {
55
116
  border-top: 0.05rem solid;
56
117
  }
57
- .body > nav h2,
58
- .body > nav p.title {
118
+ aside h2,
119
+ aside p.title {
59
120
  font-size: 0.7rem;
60
121
  font-weight: normal;
61
122
  text-transform: uppercase;
62
123
  margin: 1.1rem 0 0.75rem 0;
63
124
  }
64
- .body > nav h2:first-of-type,
65
- .body > nav p.title:first-of-type {
125
+ aside h2:first-of-type,
126
+ aside p.title:first-of-type {
66
127
  margin-top: 0;
67
128
  }
68
- .body > nav ul {
129
+ aside ul {
69
130
  list-style: none;
70
131
  padding: 0;
71
132
  margin: 0;
72
133
  box-sizing: border-box;
73
134
  }
74
- .body > nav > ul + ul {
135
+ aside > ul + ul {
75
136
  border-top: 0.05rem solid;
76
137
  padding-top: 1.2em;
77
138
  margin-top: 1.5em;
78
139
  }
79
- .body > nav ul ul {
140
+ aside ul ul {
80
141
  margin: 0.65em 0 0.5em;
81
142
  }
82
- .body > nav li {
143
+ aside li {
83
144
  text-align: end;
84
145
  padding-inline-end: 1em;
85
146
  margin-top: 0;
86
147
  margin-bottom: 0;
87
148
  position: relative;
88
149
  }
89
- .body > nav li::before {
150
+ aside li::before {
90
151
  content: "•";
91
152
  position: absolute;
92
153
  right: 0;
93
154
  top: 0;
94
155
  }
95
- .body > nav li + li {
156
+ aside li + li {
96
157
  margin-top: 0.55em;
97
158
  }
98
- .body > nav li > strong {
159
+ aside li > strong {
99
160
  color: var(--emphatic-color);
100
161
  }
101
162
  @media (max-width: 840px) {
102
- .body > nav {
163
+ aside {
103
164
  width: 100%;
104
165
  display: block;
105
166
  font-size: inherit;
@@ -114,30 +175,33 @@ footer {
114
175
  padding: 0.25rem var(--content-padding-x) 0.35rem;
115
176
  margin: 0;
116
177
  }
117
- .body > nav section {
178
+ aside > .header {
179
+ display: none;
180
+ }
181
+ aside section {
118
182
  max-width: 100%;
119
183
  }
120
- .body > nav li {
184
+ aside li {
121
185
  text-align: start;
122
186
  padding-inline-start: 1em;
123
187
  padding-inline-end: 0;
124
188
  }
125
- .body > nav li::before {
189
+ aside li::before {
126
190
  left: 0;
127
191
  right: auto;
128
192
  }
129
193
  }
130
- .body > nav > ul:last-child,
131
- .body > nav > ul:last-child > li:last-child {
194
+ aside > ul:last-child,
195
+ aside > ul:last-child > li:last-child {
132
196
  margin-bottom: 0;
133
197
  }
134
- .body > nav a.active {
198
+ aside a.active {
135
199
  font-weight: bold;
136
200
  text-decoration: none;
137
201
  color: inherit;
138
202
  pointer-events: none;
139
203
  }
140
- .body > nav a.anchorjs-link {
204
+ aside a.anchorjs-link {
141
205
  display: none;
142
206
  }
143
207
 
@@ -178,14 +242,6 @@ main h1 {
178
242
  h1 .sep {
179
243
  margin: 0 0.1em;
180
244
  }
181
- h1 a,
182
- h1 a:link,
183
- h1 a:hover,
184
- h1 a:visited,
185
- h1 a:active {
186
- color: inherit;
187
- text-decoration: none;
188
- }
189
245
  @media (max-width: 840px) {
190
246
  main h1 {
191
247
  margin-top: 0;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@t8/docsgen",
3
- "version": "0.3.36",
3
+ "version": "0.4.1",
4
4
  "description": "",
5
5
  "main": "dist/bin.js",
6
6
  "type": "module",
@@ -14,6 +14,8 @@ const __dirname = dirname(__filename);
14
14
  let packageURL = "";
15
15
  let packageVersionRequest: Promise<{ stdout: string }> | null = null;
16
16
 
17
+ let assetsCreated = new Map<string, boolean>();
18
+
17
19
  export async function getCSSRoot(ctx: Context, type: "index" | "content") {
18
20
  let { dir = "", assetsDir } = ctx;
19
21
 
@@ -26,10 +28,16 @@ export async function getCSSRoot(ctx: Context, type: "index" | "content") {
26
28
  cssRoot.index = assetsDir;
27
29
  cssRoot.content = `../${assetsDir}`;
28
30
 
29
- await cp(join(__dirname, "css"), join(dir, cssRoot.index), {
30
- force: true,
31
- recursive: true,
32
- });
31
+ let assetsDestination = join(dir, cssRoot.index);
32
+
33
+ if (!assetsCreated.get(assetsDestination)) {
34
+ assetsCreated.set(assetsDestination, true);
35
+
36
+ await cp(join(__dirname, "css"), assetsDestination, {
37
+ force: true,
38
+ recursive: true,
39
+ });
40
+ }
33
41
  } else {
34
42
  if (!packageURL) {
35
43
  packageVersionRequest ??= exec(`npm view ${packageName} version`);
@@ -0,0 +1,16 @@
1
+ import type { Context } from "../../types/Context.ts";
2
+ import { escapeHTML } from "../../utils/escapeHTML.ts";
3
+ import { getParsedContent } from "../parsing/getParsedContent.ts";
4
+ import { tweakTypography } from "./tweakTypography.ts";
5
+
6
+ export async function getDescriptionContent(ctx: Context) {
7
+ let escapedPackageDescription = escapeHTML(ctx.description);
8
+ let { description } = await getParsedContent(ctx);
9
+
10
+ return (
11
+ tweakTypography(description) ||
12
+ (escapedPackageDescription
13
+ ? `<p>${tweakTypography(escapedPackageDescription)}<p>`
14
+ : "")
15
+ );
16
+ }
@@ -5,48 +5,28 @@ import { getParsedContent } from "../parsing/getParsedContent.ts";
5
5
  import { getCounterContent } from "./getCounterContent.ts";
6
6
  import { getCSSRoot } from "./getCSSRoot.ts";
7
7
  import { getDefaultCodeStyleContent } from "./getDefaultCodeStyleContent.ts";
8
+ import { getDescriptionContent } from "./getDescriptionContent.ts";
8
9
  import { getIconTag } from "./getIconTag.ts";
9
10
  import { getInjectedContent } from "./getInjectedContent.ts";
11
+ import { getInstallationContent } from "./getInstallationContent.ts";
12
+ import { getMainTitle } from "./getMainTitle.ts";
10
13
  import { getPlainTitle } from "./getPlainTitle.ts";
11
14
  import { toFileContent } from "./toFileContent.ts";
12
- import { tweakTypography } from "./tweakTypography.ts";
13
15
 
14
16
  export async function getIndexContent(ctx: Context) {
15
17
  let {
16
18
  root,
17
19
  contentDir = "",
18
- name,
19
- htmlTitle,
20
20
  description: packageDescription,
21
- isDevDep,
22
21
  backstory,
23
22
  } = ctx;
24
23
 
25
24
  let counterContent = getCounterContent(ctx);
26
25
  let escapedPackageDescription = escapeHTML(packageDescription);
27
26
 
28
- let {
29
- title: parsedTitle,
30
- description,
31
- intro,
32
- features,
33
- note,
34
- installation,
35
- nav,
36
- } = await getParsedContent(ctx);
27
+ let { description, intro, features, note, nav } = await getParsedContent(ctx);
37
28
 
38
29
  let plainTitle = await getPlainTitle(ctx);
39
- let coverTitle = htmlTitle || parsedTitle || plainTitle;
40
-
41
- let descriptionContent =
42
- tweakTypography(description) ||
43
- (escapedPackageDescription
44
- ? `<p>${tweakTypography(escapedPackageDescription)}<p>`
45
- : "");
46
-
47
- if (!installation || isDevDep !== undefined)
48
- installation = `npm i${isDevDep ? " -D" : ""} ${name}`;
49
-
50
30
  let cssRoot = await getCSSRoot(ctx, "index");
51
31
 
52
32
  return toFileContent(`
@@ -72,9 +52,9 @@ ${getInjectedContent(ctx, "index", "body", "prepend")}
72
52
  <section class="aux intro-title">
73
53
  <div class="section-content">
74
54
  ${getInjectedContent(ctx, "index", "cover", "prepend")}
75
- <h1>${coverTitle}</h1>
55
+ <h1>${await getMainTitle(ctx)}</h1>
76
56
  <div class="description">
77
- ${descriptionContent}
57
+ ${await getDescriptionContent(ctx)}
78
58
  </div>
79
59
  <p class="actions">
80
60
  <a href="${root}start" class="primary">Docs</a>
@@ -82,7 +62,7 @@ ${getInjectedContent(ctx, "index", "body", "prepend")}
82
62
  ${getRepoLink(ctx)}
83
63
  </p>
84
64
  ${backstory ? `<p class="ref"><a href="${backstory}">Backstory</a></p>` : ""}
85
- <p class="installation"><code>${escapeHTML(installation)}</code></p>
65
+ <p class="installation">${await getInstallationContent(ctx)}</p>
86
66
  ${getInjectedContent(ctx, "index", "cover", "append")}
87
67
  </div>
88
68
  </section>
@@ -0,0 +1,13 @@
1
+ import type { Context } from "../../types/Context.ts";
2
+ import { escapeHTML } from "../../utils/escapeHTML.ts";
3
+ import { getParsedContent } from "../parsing/getParsedContent.ts";
4
+
5
+ export async function getInstallationContent(ctx: Context) {
6
+ let { name, isDevDep } = ctx;
7
+ let { installation } = await getParsedContent(ctx);
8
+
9
+ if (!installation || isDevDep !== undefined)
10
+ installation = `npm i${isDevDep ? " -D" : ""} ${name}`;
11
+
12
+ return `<code>${escapeHTML(installation)}</code>`;
13
+ }
@@ -0,0 +1,12 @@
1
+ import type { Context } from "../../types/Context.ts";
2
+ import { getParsedContent } from "../parsing/getParsedContent.ts";
3
+ import { getPlainTitle } from "./getPlainTitle.ts";
4
+
5
+ export async function getMainTitle(ctx: Context) {
6
+ let { htmlTitle } = ctx;
7
+ let { title: parsedTitle } = await getParsedContent(ctx);
8
+
9
+ let plainTitle = await getPlainTitle(ctx);
10
+
11
+ return htmlTitle || parsedTitle || plainTitle;
12
+ }
@@ -84,5 +84,5 @@ export async function getNav(ctx: Context, navItems: NavItem[]) {
84
84
  s = s.trim();
85
85
  s = s ? `<section>\n${s}\n</section>` : "";
86
86
 
87
- return `<nav class="aux">\n${s}\n${navContent}\n</nav>`;
87
+ return `<nav>\n${s}\n${navContent}\n</nav>`;
88
88
  }
@@ -9,18 +9,23 @@ import { getCSSRoot } from "./getCSSRoot.ts";
9
9
  import { getDefaultCodeStyleContent } from "./getDefaultCodeStyleContent.ts";
10
10
  import { getIconTag } from "./getIconTag.ts";
11
11
  import { getInjectedContent } from "./getInjectedContent.ts";
12
+ import { getInstallationContent } from "./getInstallationContent.ts";
13
+ import { getMainTitle } from "./getMainTitle.ts";
12
14
  import { getNav } from "./getNav.ts";
13
15
  import { getPlainTitle } from "./getPlainTitle.ts";
14
16
  import { toFileContent } from "./toFileContent.ts";
15
17
 
16
18
  export async function getSectionContent(ctx: Context, index: number) {
17
19
  let { root, contentDir = "" } = ctx;
20
+ let escapedPackageDescription = escapeHTML(ctx.description);
18
21
 
19
22
  let cssRoot = await getCSSRoot(ctx, "content");
20
23
  let { sections, nav } = await getParsedContent(ctx);
21
24
 
22
25
  let content = sections[index];
23
26
  let navContent = await getNav(ctx, nav);
27
+
28
+ let mainTitle = await getMainTitle(ctx);
24
29
  let plainTitle = await getPlainTitle(ctx);
25
30
 
26
31
  return toFileContent(`
@@ -42,9 +47,14 @@ export async function getSectionContent(ctx: Context, index: number) {
42
47
  <body>
43
48
  ${getInjectedContent(ctx, "section", "body", "prepend")}
44
49
  <div class="layout">
50
+ <header class="aux">
51
+ <h1>${mainTitle}</h1>
52
+ <div class="description">
53
+ <p>${escapedPackageDescription}</p>
54
+ </div>
55
+ </header>
45
56
  <div class="${navContent ? "" : "no-nav "}body">
46
57
  <main>
47
- <h1><a href="${root}">${plainTitle}</a></h1>
48
58
  ${content}
49
59
 
50
60
  <p class="pagenav">
@@ -56,13 +66,22 @@ ${content}
56
66
  ${nav[index + 1]?.id ? `<span class="next"><a href="${root}${contentDir}/${nav[index + 1]?.id}">${nav[index + 1]?.title}</a> <span class="icon">→</span></span>` : `<span class="repo">${getRepoLink(ctx)}</span>`}
57
67
  </p>
58
68
  </main>
59
- ${navContent ? "<hr>" : ""}
69
+ <hr>
70
+ <aside class="aux">
71
+ <div class="header" hidden>
72
+ <h1>${mainTitle}</h1>
73
+ <div class="description">
74
+ <p>${escapedPackageDescription}</p>
75
+ <p class="installation">${await getInstallationContent(ctx)}</p>
76
+ </div>
77
+ </div>
60
78
  ${navContent.replace(
61
79
  new RegExp(
62
80
  `(<li data-id="${escapeRegExp(nav[index]?.id)}">)<a href="[^"]+">([^<]+)</a>`,
63
81
  ),
64
82
  "$1<strong>$2</strong>",
65
83
  )}
84
+ </aside>
66
85
  </div>
67
86
  </div>
68
87
 
@@ -2,7 +2,7 @@ import { writeFile } from "node:fs/promises";
2
2
  import { join } from "node:path";
3
3
  import type { Context } from "../types/Context.ts";
4
4
  import { createDirs } from "./content/createDirs.ts";
5
- import { getIndexContent } from "./content/getIndexContent.ts";
5
+ // import { getIndexContent } from "./content/getIndexContent.ts";
6
6
  import { getRedirectContent } from "./content/getRedirectContent.ts";
7
7
  import { getSectionContent } from "./content/getSectionContent.ts";
8
8
  import { getStartContent } from "./content/getStartContent.ts";
@@ -27,7 +27,8 @@ export async function setContent(ctx: Context) {
27
27
  await getSectionContent(ctx, i),
28
28
  ),
29
29
  ),
30
- writeFile(join(dir, "index.html"), await getIndexContent(ctx)),
30
+ // writeFile(join(dir, "index.html"), await getIndexContent(ctx)),
31
+ writeFile(join(dir, "index.html"), await getStartContent(ctx)),
31
32
  writeFile(join(dir, "start.html"), await getStartContent(ctx)),
32
33
  ]);
33
34
  }
package/src/css/base.css CHANGED
@@ -41,9 +41,9 @@
41
41
  }
42
42
  }
43
43
  :root {
44
- --max-content-width: 45em;
44
+ --max-content-width: 720px;
45
45
  --content-padding-x: 1.75rem;
46
- --content-padding-y: 1.75rem;
46
+ --content-padding-y: 1rem;
47
47
  --block-margin-y: 1em;
48
48
  --sep-line: 0.3rem solid var(--line-color);
49
49
 
@@ -70,7 +70,7 @@ body {
70
70
  :root {
71
71
  --max-content-width: 100%;
72
72
  --content-padding-x: 0.85rem;
73
- --content-padding-y: 1rem;
73
+ --content-padding-y: 0.65rem;
74
74
  }
75
75
  body {
76
76
  font-size: 100%;
@@ -8,6 +8,25 @@ footer {
8
8
  padding: 0 var(--content-padding-x);
9
9
  }
10
10
 
11
+ header {
12
+ display: none;
13
+ text-align: center;
14
+ padding-top: 0.5em;
15
+ padding-bottom: 0.5em;
16
+ }
17
+ header h1 {
18
+ font-size: 1.25em;
19
+ font-weight: 900;
20
+ margin: 0;
21
+ }
22
+ header .description {
23
+ font-size: 0.8em;
24
+ margin-top: 0.15em;
25
+ }
26
+ header .description p {
27
+ margin: 0;
28
+ }
29
+
11
30
  .body {
12
31
  min-height: 100vh;
13
32
  display: flex;
@@ -20,19 +39,22 @@ footer {
20
39
  display: none;
21
40
  }
22
41
  @media (max-width: 840px) {
42
+ header {
43
+ display: block;
44
+ }
23
45
  .body {
24
46
  flex-direction: column;
25
47
  padding: 0;
26
48
  }
27
49
  }
28
- .body > nav {
50
+ aside {
29
51
  width: 25%;
30
52
  display: flex;
31
53
  flex-direction: column;
32
54
  align-items: flex-end;
33
55
  flex: none;
34
56
  align-self: stretch;
35
- font-size: 0.9em;
57
+ font-size: 0.87em;
36
58
  line-height: 1.25;
37
59
  text-align: end;
38
60
  background: linear-gradient(
@@ -41,65 +63,104 @@ footer {
41
63
  var(--aux-background-end)
42
64
  );
43
65
  border-right: 0.05em solid var(--aux-border-color);
44
- padding: 0.75rem var(--content-padding-x);
66
+ padding: var(--content-padding-y) var(--content-padding-x);
45
67
  margin: 0;
46
68
  box-sizing: border-box;
47
69
  }
48
- .body > nav section {
70
+ aside > .header {
71
+ display: block;
72
+ margin: 0.5rem 0 0.25rem;
73
+ }
74
+ aside > .header .description p:not(.installation) {
75
+ font-size: 0.9em;
76
+ margin: 0.35em 0 0;
77
+ }
78
+ aside > .header .description p.installation {
79
+ margin: 1em 0 0;
80
+ }
81
+ aside > .header .installation code {
82
+ display: inline-block;
83
+ background: transparent;
84
+ border: 0.05em solid;
85
+ border-radius: 0.5em;
86
+ padding: 0.35em 0.75em;
87
+ margin: 0;
88
+ }
89
+ aside h1 {
90
+ font-size: 1.35em;
91
+ font-weight: 900;
92
+ margin: 0;
93
+ }
94
+ aside h1 > a,
95
+ aside h1 > a:link,
96
+ aside h1 > a:hover,
97
+ aside h1 > a:visited,
98
+ aside h1 > a:active {
99
+ --color: var(--aux-color);
100
+ text-decoration: underline;
101
+ border-bottom: none;
102
+ }
103
+ aside h1 sup {
104
+ font-size: 0.5em;
105
+ }
106
+ aside nav {
107
+ font-size: 0.8rem;
108
+ }
109
+ aside section {
49
110
  width: 100%;
50
111
  max-width: 16em;
51
112
  padding: 1rem 0;
52
113
  box-sizing: border-box;
53
114
  }
54
- .body > nav section + section {
115
+ aside section + section {
55
116
  border-top: 0.05rem solid;
56
117
  }
57
- .body > nav h2,
58
- .body > nav p.title {
118
+ aside h2,
119
+ aside p.title {
59
120
  font-size: 0.7rem;
60
121
  font-weight: normal;
61
122
  text-transform: uppercase;
62
123
  margin: 1.1rem 0 0.75rem 0;
63
124
  }
64
- .body > nav h2:first-of-type,
65
- .body > nav p.title:first-of-type {
125
+ aside h2:first-of-type,
126
+ aside p.title:first-of-type {
66
127
  margin-top: 0;
67
128
  }
68
- .body > nav ul {
129
+ aside ul {
69
130
  list-style: none;
70
131
  padding: 0;
71
132
  margin: 0;
72
133
  box-sizing: border-box;
73
134
  }
74
- .body > nav > ul + ul {
135
+ aside > ul + ul {
75
136
  border-top: 0.05rem solid;
76
137
  padding-top: 1.2em;
77
138
  margin-top: 1.5em;
78
139
  }
79
- .body > nav ul ul {
140
+ aside ul ul {
80
141
  margin: 0.65em 0 0.5em;
81
142
  }
82
- .body > nav li {
143
+ aside li {
83
144
  text-align: end;
84
145
  padding-inline-end: 1em;
85
146
  margin-top: 0;
86
147
  margin-bottom: 0;
87
148
  position: relative;
88
149
  }
89
- .body > nav li::before {
150
+ aside li::before {
90
151
  content: "•";
91
152
  position: absolute;
92
153
  right: 0;
93
154
  top: 0;
94
155
  }
95
- .body > nav li + li {
156
+ aside li + li {
96
157
  margin-top: 0.55em;
97
158
  }
98
- .body > nav li > strong {
159
+ aside li > strong {
99
160
  color: var(--emphatic-color);
100
161
  }
101
162
  @media (max-width: 840px) {
102
- .body > nav {
163
+ aside {
103
164
  width: 100%;
104
165
  display: block;
105
166
  font-size: inherit;
@@ -114,30 +175,33 @@ footer {
114
175
  padding: 0.25rem var(--content-padding-x) 0.35rem;
115
176
  margin: 0;
116
177
  }
117
- .body > nav section {
178
+ aside > .header {
179
+ display: none;
180
+ }
181
+ aside section {
118
182
  max-width: 100%;
119
183
  }
120
- .body > nav li {
184
+ aside li {
121
185
  text-align: start;
122
186
  padding-inline-start: 1em;
123
187
  padding-inline-end: 0;
124
188
  }
125
- .body > nav li::before {
189
+ aside li::before {
126
190
  left: 0;
127
191
  right: auto;
128
192
  }
129
193
  }
130
- .body > nav > ul:last-child,
131
- .body > nav > ul:last-child > li:last-child {
194
+ aside > ul:last-child,
195
+ aside > ul:last-child > li:last-child {
132
196
  margin-bottom: 0;
133
197
  }
134
- .body > nav a.active {
198
+ aside a.active {
135
199
  font-weight: bold;
136
200
  text-decoration: none;
137
201
  color: inherit;
138
202
  pointer-events: none;
139
203
  }
140
- .body > nav a.anchorjs-link {
204
+ aside a.anchorjs-link {
141
205
  display: none;
142
206
  }
143
207
 
@@ -178,14 +242,6 @@ main h1 {
178
242
  h1 .sep {
179
243
  margin: 0 0.1em;
180
244
  }
181
- h1 a,
182
- h1 a:link,
183
- h1 a:hover,
184
- h1 a:visited,
185
- h1 a:active {
186
- color: inherit;
187
- text-decoration: none;
188
- }
189
245
  @media (max-width: 840px) {
190
246
  main h1 {
191
247
  margin-top: 0;