pict-docuserve 1.3.2 → 1.3.4
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/indoctrinate_content_staging/Indoctrinate-Catalog-AppData.json +1183 -992
- package/dist/pict-docuserve.js +610 -370
- package/dist/pict-docuserve.js.map +1 -1
- package/dist/pict-docuserve.min.js +6 -6
- package/dist/pict-docuserve.min.js.map +1 -1
- package/package.json +6 -6
- package/source/Pict-Application-Docuserve.js +14 -1
- package/source/cli/Docuserve-CLI-Program.js +3 -1
- package/source/cli/commands/Docuserve-Command-CheckLinks.js +428 -0
- package/source/cli/commands/Docuserve-Command-StageExamples.js +606 -0
- package/source/providers/Pict-Provider-Docuserve-Documentation.js +245 -15
- package/source/views/PictView-Docuserve-Splash.js +126 -0
- package/dist/css/docuserve.css +0 -327
|
@@ -17,6 +17,7 @@ class DocuserveDocumentationProvider extends libPictProvider
|
|
|
17
17
|
super(pFable, pOptions, pServiceHash);
|
|
18
18
|
|
|
19
19
|
this._Catalog = null;
|
|
20
|
+
this._KeywordIndexMode = null;
|
|
20
21
|
this._ContentCache = {};
|
|
21
22
|
// (group, module) -> playground config | null (negative cache).
|
|
22
23
|
// Loaded lazily by loadPlaygroundConfig on first navigation into
|
|
@@ -43,18 +44,44 @@ class DocuserveDocumentationProvider extends libPictProvider
|
|
|
43
44
|
{
|
|
44
45
|
return (pHref, pLinkText) =>
|
|
45
46
|
{
|
|
47
|
+
let tmpHref = String(pHref || '');
|
|
48
|
+
let tmpIsModuleMode = (this.getDocsMode() === 'module');
|
|
49
|
+
|
|
50
|
+
// Built example applications (and other static .html pages) are
|
|
51
|
+
// served as plain files alongside the docs. Link straight to
|
|
52
|
+
// them in a new tab rather than SPA-routing through #/page/. In
|
|
53
|
+
// module mode the href is resolved against the current
|
|
54
|
+
// document's directory, exactly the way a .md link is — so every
|
|
55
|
+
// relative link in the docs shares one base.
|
|
56
|
+
if (!tmpHref.match(/^[a-z][a-z0-9+.-]*:/i) && tmpHref.match(/\.html($|[?#])/i))
|
|
57
|
+
{
|
|
58
|
+
let tmpAssetHref = tmpIsModuleMode ? this._toModuleAssetHref(tmpHref, pCurrentDocPath) : tmpHref;
|
|
59
|
+
return { href: tmpAssetHref, target: '_blank', rel: 'noopener' };
|
|
60
|
+
}
|
|
46
61
|
// Convert internal doc links to hash routes
|
|
47
|
-
if (
|
|
62
|
+
if (tmpHref.match(/^\//) || tmpHref.match(/^[^:]+\.md/))
|
|
48
63
|
{
|
|
49
|
-
let tmpRoute = this.convertDocLink(
|
|
64
|
+
let tmpRoute = this.convertDocLink(tmpHref, pCurrentGroup, pCurrentModule, pCurrentDocPath);
|
|
50
65
|
return { href: tmpRoute };
|
|
51
66
|
}
|
|
52
67
|
// Check if this is a GitHub URL that matches a catalog module
|
|
53
|
-
let tmpCatalogRoute = this.resolveGitHubURLToRoute(
|
|
68
|
+
let tmpCatalogRoute = this.resolveGitHubURLToRoute(tmpHref);
|
|
54
69
|
if (tmpCatalogRoute)
|
|
55
70
|
{
|
|
56
71
|
return { href: tmpCatalogRoute };
|
|
57
72
|
}
|
|
73
|
+
// Module mode: a remaining relative link (a directory, a media
|
|
74
|
+
// file, a .json) is resolved against the current document's
|
|
75
|
+
// directory too, so it shares the one base every other link uses
|
|
76
|
+
// rather than silently falling back to the docs root.
|
|
77
|
+
if (tmpIsModuleMode
|
|
78
|
+
&& tmpHref
|
|
79
|
+
&& (tmpHref.charAt(0) !== '#')
|
|
80
|
+
&& (tmpHref.indexOf('//') !== 0)
|
|
81
|
+
&& !tmpHref.match(/^[a-z][a-z0-9+.-]*:/i))
|
|
82
|
+
{
|
|
83
|
+
return { href: this._toModuleAssetHref(tmpHref, pCurrentDocPath) };
|
|
84
|
+
}
|
|
58
85
|
// Use default behavior for other links
|
|
59
86
|
return null;
|
|
60
87
|
};
|
|
@@ -306,15 +333,38 @@ class DocuserveDocumentationProvider extends libPictProvider
|
|
|
306
333
|
Tagline: '',
|
|
307
334
|
Description: '',
|
|
308
335
|
Highlights: [],
|
|
309
|
-
Actions: []
|
|
336
|
+
Actions: [],
|
|
337
|
+
ExamplesMarkdown: ''
|
|
310
338
|
};
|
|
311
339
|
|
|
312
340
|
let tmpLines = pMarkdown.split('\n');
|
|
341
|
+
let tmpInExamples = false;
|
|
313
342
|
|
|
314
343
|
for (let i = 0; i < tmpLines.length; i++)
|
|
315
344
|
{
|
|
316
345
|
let tmpLine = tmpLines[i].trim();
|
|
317
346
|
|
|
347
|
+
// Generated examples region — collected verbatim for the splash's
|
|
348
|
+
// "Interactive Examples" section, never parsed as cover fields.
|
|
349
|
+
if (tmpLine === '<!-- docuserve:examples:start -->')
|
|
350
|
+
{
|
|
351
|
+
tmpInExamples = true;
|
|
352
|
+
continue;
|
|
353
|
+
}
|
|
354
|
+
if (tmpLine === '<!-- docuserve:examples:end -->')
|
|
355
|
+
{
|
|
356
|
+
tmpInExamples = false;
|
|
357
|
+
continue;
|
|
358
|
+
}
|
|
359
|
+
if (tmpInExamples)
|
|
360
|
+
{
|
|
361
|
+
if (tmpLine)
|
|
362
|
+
{
|
|
363
|
+
tmpCover.ExamplesMarkdown += (tmpCover.ExamplesMarkdown ? '\n' : '') + tmpLine;
|
|
364
|
+
}
|
|
365
|
+
continue;
|
|
366
|
+
}
|
|
367
|
+
|
|
318
368
|
if (!tmpLine)
|
|
319
369
|
{
|
|
320
370
|
continue;
|
|
@@ -728,6 +778,7 @@ class DocuserveDocumentationProvider extends libPictProvider
|
|
|
728
778
|
{
|
|
729
779
|
this._LunrIndex = libLunr.Index.load(pIndexData.LunrIndex);
|
|
730
780
|
this._KeywordDocuments = pIndexData.Documents;
|
|
781
|
+
this._KeywordIndexMode = (pIndexData.Mode === 'module' || pIndexData.Mode === 'ecosystem') ? pIndexData.Mode : null;
|
|
731
782
|
this.pict.AppData.Docuserve.KeywordIndexLoaded = true;
|
|
732
783
|
this.pict.AppData.Docuserve.KeywordDocumentCount = pIndexData.DocumentCount || 0;
|
|
733
784
|
this.log.info(`Docuserve: Keyword index loaded (${pIndexData.DocumentCount || 0} documents).`);
|
|
@@ -746,6 +797,141 @@ class DocuserveDocumentationProvider extends libPictProvider
|
|
|
746
797
|
});
|
|
747
798
|
}
|
|
748
799
|
|
|
800
|
+
/**
|
|
801
|
+
* Resolve the documentation site mode.
|
|
802
|
+
*
|
|
803
|
+
* 'module' — a single module's own docs site; every doc is a local
|
|
804
|
+
* page (#/page/<docpath>).
|
|
805
|
+
* 'ecosystem' — a catalog of <group>/<module> repos (#/doc/...).
|
|
806
|
+
* 'legacy' — built before the Mode stamp existed; callers keep the
|
|
807
|
+
* pre-Mode heuristic so old docs sites are unaffected.
|
|
808
|
+
*
|
|
809
|
+
* @returns {string} 'module' | 'ecosystem' | 'legacy'
|
|
810
|
+
*/
|
|
811
|
+
getDocsMode()
|
|
812
|
+
{
|
|
813
|
+
if (this._Catalog && (this._Catalog.Mode === 'module' || this._Catalog.Mode === 'ecosystem'))
|
|
814
|
+
{
|
|
815
|
+
return this._Catalog.Mode;
|
|
816
|
+
}
|
|
817
|
+
if (this._KeywordIndexMode === 'module' || this._KeywordIndexMode === 'ecosystem')
|
|
818
|
+
{
|
|
819
|
+
return this._KeywordIndexMode;
|
|
820
|
+
}
|
|
821
|
+
return 'legacy';
|
|
822
|
+
}
|
|
823
|
+
|
|
824
|
+
/**
|
|
825
|
+
* Module-mode link resolution: every internal documentation reference is
|
|
826
|
+
* a local page. Relative links (./sibling.md, ../other.md, bare names)
|
|
827
|
+
* resolve against the directory of the document that contains them — the
|
|
828
|
+
* way the links read on disk — while a /-rooted href resolves against the
|
|
829
|
+
* docs root. "." and ".." segments are collapsed; ".." is clamped at the
|
|
830
|
+
* docs root so a link can never escape above it.
|
|
831
|
+
*
|
|
832
|
+
* @param {string} pHref - The raw link href
|
|
833
|
+
* @param {string} [pCurrentDocPath] - Docs-root-relative path of the
|
|
834
|
+
* document the link lives in (e.g.
|
|
835
|
+
* "examples/gradebook/README.md"). Absent for root-level
|
|
836
|
+
* contexts such as the sidebar.
|
|
837
|
+
* @returns {string} A #/page/ hash route (#/Home for an empty path)
|
|
838
|
+
*/
|
|
839
|
+
_toModulePageRoute(pHref, pCurrentDocPath)
|
|
840
|
+
{
|
|
841
|
+
let tmpHref = String(pHref || '').trim();
|
|
842
|
+
|
|
843
|
+
// A /-rooted href resolves against the docs root; every other href
|
|
844
|
+
// resolves against the current document's directory.
|
|
845
|
+
let tmpBaseDir = '';
|
|
846
|
+
if (tmpHref.charAt(0) === '/')
|
|
847
|
+
{
|
|
848
|
+
tmpHref = tmpHref.replace(/^\/+/, '');
|
|
849
|
+
}
|
|
850
|
+
else if (pCurrentDocPath)
|
|
851
|
+
{
|
|
852
|
+
let tmpDirParts = String(pCurrentDocPath).split('/');
|
|
853
|
+
tmpDirParts.pop();
|
|
854
|
+
tmpBaseDir = tmpDirParts.join('/');
|
|
855
|
+
}
|
|
856
|
+
|
|
857
|
+
let tmpPath = this._resolveRelativeDocPath(tmpBaseDir, tmpHref);
|
|
858
|
+
if (!tmpPath)
|
|
859
|
+
{
|
|
860
|
+
return '#/Home';
|
|
861
|
+
}
|
|
862
|
+
return '#/page/' + tmpPath.replace(/\.md$/i, '');
|
|
863
|
+
}
|
|
864
|
+
|
|
865
|
+
/**
|
|
866
|
+
* Resolve a relative href against a base directory, collapsing "." and
|
|
867
|
+
* ".." segments. ".." is clamped at the docs root — it can never escape
|
|
868
|
+
* above it. Both arguments are POSIX-style docs-root-relative paths.
|
|
869
|
+
*
|
|
870
|
+
* @param {string} pBaseDir - The directory the href is relative to.
|
|
871
|
+
* @param {string} pHref - The href to resolve.
|
|
872
|
+
* @returns {string} The resolved docs-root-relative path (no leading slash).
|
|
873
|
+
*/
|
|
874
|
+
_resolveRelativeDocPath(pBaseDir, pHref)
|
|
875
|
+
{
|
|
876
|
+
let tmpSegments = [];
|
|
877
|
+
let tmpCombined = (pBaseDir ? pBaseDir + '/' : '') + String(pHref || '');
|
|
878
|
+
let tmpParts = tmpCombined.split('/');
|
|
879
|
+
for (let i = 0; i < tmpParts.length; i++)
|
|
880
|
+
{
|
|
881
|
+
let tmpPart = tmpParts[i];
|
|
882
|
+
if ((tmpPart === '') || (tmpPart === '.'))
|
|
883
|
+
{
|
|
884
|
+
continue;
|
|
885
|
+
}
|
|
886
|
+
if (tmpPart === '..')
|
|
887
|
+
{
|
|
888
|
+
if (tmpSegments.length > 0)
|
|
889
|
+
{
|
|
890
|
+
tmpSegments.pop();
|
|
891
|
+
}
|
|
892
|
+
continue;
|
|
893
|
+
}
|
|
894
|
+
tmpSegments.push(tmpPart);
|
|
895
|
+
}
|
|
896
|
+
return tmpSegments.join('/');
|
|
897
|
+
}
|
|
898
|
+
|
|
899
|
+
/**
|
|
900
|
+
* Module-mode resolution for a non-routed link — a built .html page, a
|
|
901
|
+
* media file, a directory. Resolves the href against the current
|
|
902
|
+
* document's directory (a /-rooted href against the docs root), the same
|
|
903
|
+
* way _toModulePageRoute resolves a .md link, and returns a plain
|
|
904
|
+
* docs-root-relative href. The browser resolves that href against the
|
|
905
|
+
* docs-root index.html, so it points at the right file from any page.
|
|
906
|
+
*
|
|
907
|
+
* @param {string} pHref - The raw link href
|
|
908
|
+
* @param {string} [pCurrentDocPath] - Docs-root-relative path of the
|
|
909
|
+
* document the link lives in.
|
|
910
|
+
* @returns {string} A docs-root-relative href.
|
|
911
|
+
*/
|
|
912
|
+
_toModuleAssetHref(pHref, pCurrentDocPath)
|
|
913
|
+
{
|
|
914
|
+
let tmpHref = String(pHref || '').trim();
|
|
915
|
+
if (!tmpHref)
|
|
916
|
+
{
|
|
917
|
+
return tmpHref;
|
|
918
|
+
}
|
|
919
|
+
|
|
920
|
+
let tmpBaseDir = '';
|
|
921
|
+
if (tmpHref.charAt(0) === '/')
|
|
922
|
+
{
|
|
923
|
+
tmpHref = tmpHref.replace(/^\/+/, '');
|
|
924
|
+
}
|
|
925
|
+
else if (pCurrentDocPath)
|
|
926
|
+
{
|
|
927
|
+
let tmpDirParts = String(pCurrentDocPath).split('/');
|
|
928
|
+
tmpDirParts.pop();
|
|
929
|
+
tmpBaseDir = tmpDirParts.join('/');
|
|
930
|
+
}
|
|
931
|
+
|
|
932
|
+
return this._resolveRelativeDocPath(tmpBaseDir, tmpHref);
|
|
933
|
+
}
|
|
934
|
+
|
|
749
935
|
/**
|
|
750
936
|
* Check whether a group/module pair exists in the loaded catalog.
|
|
751
937
|
*
|
|
@@ -864,6 +1050,7 @@ class DocuserveDocumentationProvider extends libPictProvider
|
|
|
864
1050
|
try
|
|
865
1051
|
{
|
|
866
1052
|
let tmpLunrResults = this._LunrIndex.search(pQuery);
|
|
1053
|
+
let tmpMode = this.getDocsMode();
|
|
867
1054
|
|
|
868
1055
|
for (let i = 0; i < tmpLunrResults.length; i++)
|
|
869
1056
|
{
|
|
@@ -876,24 +1063,37 @@ class DocuserveDocumentationProvider extends libPictProvider
|
|
|
876
1063
|
continue;
|
|
877
1064
|
}
|
|
878
1065
|
|
|
879
|
-
// Build the hash route
|
|
880
|
-
let tmpParts = tmpRef.split('/');
|
|
1066
|
+
// Build the hash route for this result based on the site mode.
|
|
881
1067
|
let tmpRoute = '';
|
|
882
|
-
if (
|
|
1068
|
+
if (tmpMode === 'module')
|
|
883
1069
|
{
|
|
884
|
-
//
|
|
885
|
-
//
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
1070
|
+
// Single-module site: every doc is a local page; the
|
|
1071
|
+
// keyword-index key is the docs-relative path.
|
|
1072
|
+
tmpRoute = '#/page/' + (tmpDoc.DocPath || tmpRef);
|
|
1073
|
+
}
|
|
1074
|
+
else if (tmpMode === 'ecosystem')
|
|
1075
|
+
{
|
|
1076
|
+
// Ecosystem: catalog modules render from their GitHub docs.
|
|
1077
|
+
if (tmpDoc.Group && tmpDoc.Module && tmpDoc.DocPath)
|
|
1078
|
+
{
|
|
1079
|
+
tmpRoute = '#/doc/' + tmpDoc.Group + '/' + tmpDoc.Module + '/' + tmpDoc.DocPath;
|
|
1080
|
+
}
|
|
1081
|
+
else
|
|
1082
|
+
{
|
|
1083
|
+
tmpRoute = '#/page/' + tmpRef;
|
|
1084
|
+
}
|
|
1085
|
+
}
|
|
1086
|
+
else
|
|
1087
|
+
{
|
|
1088
|
+
// Legacy keyword index (no Mode stamp) — the pre-Mode
|
|
1089
|
+
// heuristic: split the key and check the catalog.
|
|
1090
|
+
let tmpParts = tmpRef.split('/');
|
|
1091
|
+
if (tmpParts.length >= 2 && this.isModuleInCatalog(tmpParts[0], tmpParts[1]))
|
|
891
1092
|
{
|
|
892
1093
|
tmpRoute = '#/doc/' + tmpRef;
|
|
893
1094
|
}
|
|
894
1095
|
else
|
|
895
1096
|
{
|
|
896
|
-
// Local document — route via #/page/ using the full ref path
|
|
897
1097
|
tmpRoute = '#/page/' + tmpRef;
|
|
898
1098
|
}
|
|
899
1099
|
}
|
|
@@ -1076,6 +1276,14 @@ class DocuserveDocumentationProvider extends libPictProvider
|
|
|
1076
1276
|
return '';
|
|
1077
1277
|
}
|
|
1078
1278
|
|
|
1279
|
+
// Already a fully-formed hash route (e.g. "#/page/examples/foo/README").
|
|
1280
|
+
// Pass it straight through — the author has named the exact route, so
|
|
1281
|
+
// do not re-derive one (re-deriving would mangle it into "#/page/#/...").
|
|
1282
|
+
if (pHref.match(/^#\//))
|
|
1283
|
+
{
|
|
1284
|
+
return pHref;
|
|
1285
|
+
}
|
|
1286
|
+
|
|
1079
1287
|
// Root home link
|
|
1080
1288
|
if (pHref === '/')
|
|
1081
1289
|
{
|
|
@@ -1112,6 +1320,21 @@ class DocuserveDocumentationProvider extends libPictProvider
|
|
|
1112
1320
|
return '#/Home';
|
|
1113
1321
|
}
|
|
1114
1322
|
|
|
1323
|
+
// Static .html pages (built example apps, etc.) — link straight to
|
|
1324
|
+
// the file rather than SPA-routing it through #/page/. Scoped
|
|
1325
|
+
// strictly to the .html extension.
|
|
1326
|
+
if (pHref.match(/\.html($|[?#])/i) && !pHref.match(/^[a-z][a-z0-9+.-]*:/i))
|
|
1327
|
+
{
|
|
1328
|
+
return pHref;
|
|
1329
|
+
}
|
|
1330
|
+
|
|
1331
|
+
// Single-module docs site: every internal reference is a local page —
|
|
1332
|
+
// no catalog #/doc/ routing, no group/module guesswork.
|
|
1333
|
+
if (this.getDocsMode() === 'module')
|
|
1334
|
+
{
|
|
1335
|
+
return this._toModulePageRoute(pHref);
|
|
1336
|
+
}
|
|
1337
|
+
|
|
1115
1338
|
// Strip leading/trailing slashes for parsing
|
|
1116
1339
|
let tmpPath = pHref.replace(/^\//, '').replace(/\/$/, '');
|
|
1117
1340
|
|
|
@@ -1572,6 +1795,13 @@ class DocuserveDocumentationProvider extends libPictProvider
|
|
|
1572
1795
|
*/
|
|
1573
1796
|
convertDocLink(pHref, pCurrentGroup, pCurrentModule, pCurrentDocPath)
|
|
1574
1797
|
{
|
|
1798
|
+
// Single-module docs site: every internal reference is a local page,
|
|
1799
|
+
// resolved relative to the current document's directory.
|
|
1800
|
+
if (this.getDocsMode() === 'module')
|
|
1801
|
+
{
|
|
1802
|
+
return this._toModulePageRoute(pHref, pCurrentDocPath);
|
|
1803
|
+
}
|
|
1804
|
+
|
|
1575
1805
|
// Strip leading ./ prefix for relative paths
|
|
1576
1806
|
let tmpPath = pHref.replace(/^\.\//, '');
|
|
1577
1807
|
// Remove leading slash
|
|
@@ -111,6 +111,70 @@ const _ViewConfiguration =
|
|
|
111
111
|
border-color: var(--theme-color-brand-primary-hover, #236660);
|
|
112
112
|
color: var(--theme-color-brand-primary, #2E7D74);
|
|
113
113
|
}
|
|
114
|
+
.docuserve-splash-examples {
|
|
115
|
+
max-width: 900px;
|
|
116
|
+
width: 100%;
|
|
117
|
+
margin-bottom: 2.5em;
|
|
118
|
+
}
|
|
119
|
+
/* No staged examples — collapse the section entirely. */
|
|
120
|
+
.docuserve-splash-examples:empty {
|
|
121
|
+
display: none;
|
|
122
|
+
margin: 0;
|
|
123
|
+
}
|
|
124
|
+
.docuserve-splash-examples-heading {
|
|
125
|
+
font-size: 0.95em;
|
|
126
|
+
font-weight: 700;
|
|
127
|
+
text-transform: uppercase;
|
|
128
|
+
letter-spacing: 0.08em;
|
|
129
|
+
color: var(--theme-color-text-muted, #8A7F72);
|
|
130
|
+
margin: 0 0 0.85em 0;
|
|
131
|
+
}
|
|
132
|
+
.docuserve-splash-examples table {
|
|
133
|
+
width: 100%;
|
|
134
|
+
border-collapse: collapse;
|
|
135
|
+
background: var(--theme-color-background-panel, #FFFFFF);
|
|
136
|
+
border: 1px solid var(--theme-color-border-default, #DDD6CA);
|
|
137
|
+
border-radius: 8px;
|
|
138
|
+
overflow: hidden;
|
|
139
|
+
}
|
|
140
|
+
.docuserve-splash-examples thead th {
|
|
141
|
+
text-align: left;
|
|
142
|
+
font-size: 0.72em;
|
|
143
|
+
font-weight: 700;
|
|
144
|
+
text-transform: uppercase;
|
|
145
|
+
letter-spacing: 0.06em;
|
|
146
|
+
color: var(--theme-color-text-muted, #8A7F72);
|
|
147
|
+
padding: 0.7em 1.1em;
|
|
148
|
+
background: var(--theme-color-background-tertiary, #F4EFE6);
|
|
149
|
+
}
|
|
150
|
+
.docuserve-splash-examples tbody td {
|
|
151
|
+
padding: 0.7em 1.1em;
|
|
152
|
+
border-top: 1px solid var(--theme-color-border-default, #DDD6CA);
|
|
153
|
+
font-size: 0.9em;
|
|
154
|
+
color: var(--theme-color-text-secondary, #5E5549);
|
|
155
|
+
text-align: left;
|
|
156
|
+
}
|
|
157
|
+
.docuserve-splash-examples tbody tr:hover td {
|
|
158
|
+
background: var(--theme-color-background-tertiary, #F4EFE6);
|
|
159
|
+
}
|
|
160
|
+
.docuserve-splash-examples a {
|
|
161
|
+
color: var(--theme-color-brand-primary, #2E7D74);
|
|
162
|
+
font-weight: 600;
|
|
163
|
+
text-decoration: none;
|
|
164
|
+
}
|
|
165
|
+
.docuserve-splash-examples a:hover {
|
|
166
|
+
text-decoration: underline;
|
|
167
|
+
}
|
|
168
|
+
/* docs/README.md content rendered beneath the hero. */
|
|
169
|
+
.docuserve-splash-readme {
|
|
170
|
+
max-width: 820px;
|
|
171
|
+
margin: 0 auto;
|
|
172
|
+
padding: 3.5em 2em 5em 2em;
|
|
173
|
+
text-align: left;
|
|
174
|
+
}
|
|
175
|
+
.docuserve-splash-readme:empty {
|
|
176
|
+
display: none;
|
|
177
|
+
}
|
|
114
178
|
`,
|
|
115
179
|
|
|
116
180
|
Templates:
|
|
@@ -123,8 +187,10 @@ const _ViewConfiguration =
|
|
|
123
187
|
<div class="docuserve-splash-tagline" id="Docuserve-Splash-Tagline"></div>
|
|
124
188
|
<div class="docuserve-splash-description" id="Docuserve-Splash-Description"></div>
|
|
125
189
|
<div class="docuserve-splash-highlights" id="Docuserve-Splash-Highlights"></div>
|
|
190
|
+
<div class="docuserve-splash-examples" id="Docuserve-Splash-Examples"></div>
|
|
126
191
|
<div class="docuserve-splash-actions" id="Docuserve-Splash-Actions"></div>
|
|
127
192
|
</div>
|
|
193
|
+
<div class="docuserve-splash-readme" id="Docuserve-Splash-Readme"></div>
|
|
128
194
|
`
|
|
129
195
|
}
|
|
130
196
|
],
|
|
@@ -154,12 +220,17 @@ class DocusserveSplashView extends libPictView
|
|
|
154
220
|
if (tmpDocuserve.CoverLoaded && tmpDocuserve.Cover)
|
|
155
221
|
{
|
|
156
222
|
this.renderFromCover(tmpDocuserve.Cover);
|
|
223
|
+
this.renderExamples(tmpDocuserve.Cover);
|
|
157
224
|
}
|
|
158
225
|
else
|
|
159
226
|
{
|
|
160
227
|
this.renderFromCatalog(tmpDocuserve);
|
|
161
228
|
}
|
|
162
229
|
|
|
230
|
+
// Render docs/README.md beneath the hero — the splash fills the
|
|
231
|
+
// viewport above the fold, the README content follows on scroll.
|
|
232
|
+
this.renderReadme();
|
|
233
|
+
|
|
163
234
|
return super.onAfterRender(pRenderable, pRenderDestinationAddress, pRecord, pContent);
|
|
164
235
|
}
|
|
165
236
|
|
|
@@ -270,6 +341,61 @@ class DocusserveSplashView extends libPictView
|
|
|
270
341
|
this.pict.ContentAssignment.assignContent('#Docuserve-Splash-Actions', '');
|
|
271
342
|
}
|
|
272
343
|
|
|
344
|
+
/**
|
|
345
|
+
* Render the "Interactive Examples" section of the splash from the
|
|
346
|
+
* examples region of _cover.md. When the cover carries no examples the
|
|
347
|
+
* section is left empty — CSS collapses it — so it appears only when a
|
|
348
|
+
* module has staged interactive examples.
|
|
349
|
+
*
|
|
350
|
+
* @param {Object} pCover - The parsed cover data.
|
|
351
|
+
*/
|
|
352
|
+
renderExamples(pCover)
|
|
353
|
+
{
|
|
354
|
+
let tmpExamplesMarkdown = (pCover && pCover.ExamplesMarkdown) ? pCover.ExamplesMarkdown : '';
|
|
355
|
+
let tmpDocProvider = this.pict.providers['Docuserve-Documentation'];
|
|
356
|
+
|
|
357
|
+
if (!tmpExamplesMarkdown || !tmpDocProvider || !tmpDocProvider._ContentProvider)
|
|
358
|
+
{
|
|
359
|
+
this.pict.ContentAssignment.assignContent('#Docuserve-Splash-Examples', '');
|
|
360
|
+
return;
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
let tmpLinkResolver = tmpDocProvider._createLinkResolver('', '', '');
|
|
364
|
+
let tmpExamplesHTML = tmpDocProvider._ContentProvider.parseMarkdown(tmpExamplesMarkdown, tmpLinkResolver);
|
|
365
|
+
this.pict.ContentAssignment.assignContent('#Docuserve-Splash-Examples',
|
|
366
|
+
'<h2 class="docuserve-splash-examples-heading">Interactive Examples</h2>' + tmpExamplesHTML);
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
/**
|
|
370
|
+
* Render docs/README.md beneath the splash hero. The landing page is the
|
|
371
|
+
* full-viewport splash above the fold and the module's README content on
|
|
372
|
+
* scroll. A missing or unreadable README simply leaves the section empty.
|
|
373
|
+
*/
|
|
374
|
+
renderReadme()
|
|
375
|
+
{
|
|
376
|
+
let tmpDocProvider = this.pict.providers['Docuserve-Documentation'];
|
|
377
|
+
let tmpDocsBase = this.pict.AppData.Docuserve.DocsBaseURL || '';
|
|
378
|
+
|
|
379
|
+
fetch(tmpDocsBase + 'README.md')
|
|
380
|
+
.then((pResponse) => (pResponse.ok ? pResponse.text() : null))
|
|
381
|
+
.then((pMarkdown) =>
|
|
382
|
+
{
|
|
383
|
+
if (!pMarkdown || !tmpDocProvider || !tmpDocProvider._ContentProvider)
|
|
384
|
+
{
|
|
385
|
+
this.pict.ContentAssignment.assignContent('#Docuserve-Splash-Readme', '');
|
|
386
|
+
return;
|
|
387
|
+
}
|
|
388
|
+
let tmpLinkResolver = tmpDocProvider._createLinkResolver('', '', 'README.md');
|
|
389
|
+
let tmpImageResolver = tmpDocProvider._createImageResolver(tmpDocsBase + 'README.md');
|
|
390
|
+
let tmpHTML = tmpDocProvider._ContentProvider.parseMarkdown(pMarkdown, tmpLinkResolver, tmpImageResolver);
|
|
391
|
+
this.pict.ContentAssignment.assignContent('#Docuserve-Splash-Readme', '<div class="pict-content">' + tmpHTML + '</div>');
|
|
392
|
+
})
|
|
393
|
+
.catch(() =>
|
|
394
|
+
{
|
|
395
|
+
this.pict.ContentAssignment.assignContent('#Docuserve-Splash-Readme', '');
|
|
396
|
+
});
|
|
397
|
+
}
|
|
398
|
+
|
|
273
399
|
/**
|
|
274
400
|
* Sanitize a title string, preserving only <small> tags.
|
|
275
401
|
* All other HTML is escaped.
|