hdoc-tools 0.8.13 → 0.8.14

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2022 Hornbill Docs
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/hdoc-build.js CHANGED
@@ -3,9 +3,7 @@
3
3
 
4
4
  const {
5
5
  createHash
6
- } = require('crypto'), {
7
- lutimesSync
8
- } = require('fs'),
6
+ } = require('crypto'),
9
7
  dree = require('dree'),
10
8
  fs = require('fs-extra'),
11
9
  mdfm = require('markdown-it-front-matter'),
@@ -27,22 +25,27 @@
27
25
  'doc_content',
28
26
  'doc_preview UNINDEXED',
29
27
  'doc_family_id'
30
- ];
28
+ ],
29
+ doc_header_template_path = path.join(__dirname, 'templates', 'doc-header.html');
31
30
 
32
- let conversion_attempted = 0,
31
+ let bc = {}, // Breadcrumbs map
32
+ book_read_time = 0,
33
+ built_file_hashes = [],
34
+ conversion_attempted = 0,
33
35
  conversion_success = 0,
34
36
  conversion_failed = 0,
37
+ doc_header_template = '',
38
+ doc_id = '',
39
+ git_token = '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', // Github fine-grained personal access token that has minimum read-only access to Hornbill Docs org repo content
40
+ hdocbook_config = {},
41
+ hdocbook_project,
35
42
  includes_found = 0,
36
43
  includes_success = 0,
37
44
  includes_failed = 0,
38
- book_read_time = 0,
39
- hdocbook_project,
40
- docId = '',
45
+ index_records = [],
41
46
  md_files = [],
42
47
  static_html_files = [],
43
- index_records = [],
44
- work_path_content = '',
45
- built_file_hashes = [];
48
+ work_path_content = '';
46
49
 
47
50
  const transform_static_html = function (file_path) {
48
51
  if (fs.existsSync(file_path.path)) {
@@ -205,7 +208,9 @@
205
208
  let fm_content = frontmatter_content.split(/\r?\n/);
206
209
 
207
210
  let fm_contains_title = false,
208
- fm_contains_reading_time = false;
211
+ fm_contains_reading_time = false,
212
+ doc_title = '',
213
+ doc_type = 'Article';
209
214
 
210
215
  if (fm_content.length >= 0) {
211
216
  fm_content.forEach(function (fm_prop) {
@@ -218,6 +223,11 @@
218
223
 
219
224
  if (fm_property[0].trim() === 'title') {
220
225
  fm_contains_title = true;
226
+ doc_title = fm_property[1].trim();
227
+ }
228
+ if (fm_property[0].trim() === 'type') {
229
+ fm_contains_type = true;
230
+ doc_type = fm_property[1].trim();
221
231
  }
222
232
  if (fm_property[0].trim() === 'reading-time') {
223
233
  book_read_time += parseInt(fm_property[1].trim(), 10);
@@ -227,6 +237,12 @@
227
237
  });
228
238
  }
229
239
 
240
+ // Add doc type
241
+ fm_headers.push({
242
+ id: 'type',
243
+ value: doc_type
244
+ });
245
+
230
246
  // Does frontmatter tag contain a title property
231
247
  if (!fm_contains_title) {
232
248
  // Frontmatter tags don't contain a title property - go pull the first one from the html heading tags
@@ -238,12 +254,16 @@
238
254
  id: 'title',
239
255
  value: html_heading[0].children[0].data.trim()
240
256
  });
257
+ doc_title = html_heading[0].children[0].data.trim();
241
258
  } else {
242
259
  // No header tag, no frontmatter title, output a warning
243
260
  console.log(`No frontmatter title property, or h1, h2 or h3 header tags detected in ${file_path}`);
244
261
  }
245
262
  }
246
263
 
264
+ // Remove the first <h1>title</h1> from the HTML as we'll ass that in the document header
265
+ html_txt = html_txt.replace(/(<h1.*?>)\s*.*\s*(.*<\/h1>)/, '');
266
+
247
267
  // Does frontmatter tag contain a reading-time property
248
268
  if (!fm_contains_reading_time) {
249
269
  const read_time_mins = hdoc.get_html_read_time(html_txt);
@@ -254,15 +274,51 @@
254
274
  });
255
275
  }
256
276
 
257
- // Add frontmatter tags as comment to front of HTML
277
+ // Get contributor data from Github, if exists
278
+ if (hdocbook_config.publicSource && hdocbook_config.publicSource !== '') {
279
+ const github_paths = hdoc.get_github_api_path(hdocbook_config.publicSource, file_path.relativePath);
280
+ const contributors = hdoc.get_github_contributors(github_paths.api_path, git_token);
281
+ if (!contributors.success) {
282
+ console.log(`Error retrieving contributors from Github: ${contributors.error}`);
283
+ } else {
284
+ fm_headers.push({
285
+ id: 'contributor-count',
286
+ value: contributors.contributor_count
287
+ });
288
+ fm_headers.push({
289
+ id: 'last-commit',
290
+ value: contributors.last_commit_date
291
+ });
292
+ }
293
+ fm_headers.push({
294
+ id: 'edit-path',
295
+ value: github_paths.edit_path
296
+ });
297
+ const target_file = file_path.path.replace(path.extname(file_path.path), '._info.json');
298
+ delete contributors.success;
299
+ delete contributors.error;
300
+ contributors.editPath = github_paths.edit_path;
301
+ try {
302
+ fs.writeFileSync(target_file, JSON.stringify(contributors, null, 2));
303
+ } catch (err) {
304
+ console.log('Error writing:', target_file, '\n', err);
305
+ }
306
+ }
307
+
308
+ // Build doc header from template and frontmatter tags
309
+ const doc_header = process_doc_header(fm_headers, file_path.relativePath);
310
+
311
+ // Add frontmatter tags as comment to front of HTML
312
+
313
+ let fm_header = '<!--[[FRONTMATTER\n';
258
314
  if (fm_headers.length > 0) {
259
- let fm_header = '<!--[[FRONTMATTER\n';
260
315
  for (let i = 0; i < fm_headers.length; i++) {
261
316
  fm_header += `${fm_headers[i].id}: ${fm_headers[i].value}\n`;
262
317
  }
263
- fm_header += ']]-->';
264
- html_txt = `${fm_header}\n${html_txt}`;
265
318
  }
319
+ fm_header += ']]-->';
320
+
321
+ html_txt = `${fm_header}\n${doc_header}\n${html_txt}`;
266
322
 
267
323
  // Save HTML into HTML file
268
324
  const target_file = file_path.path.replace(path.extname(file_path.path), '.html');
@@ -292,6 +348,46 @@
292
348
  return false;
293
349
  };
294
350
 
351
+ const process_doc_header = function (fm_headers, doc_path) {
352
+ let wip_doc_header = doc_header_template;
353
+
354
+ // Process fm_headers properties first
355
+ for (let i = 0; i < fm_headers.length; i++) {
356
+ switch (fm_headers[i].id) {
357
+ case 'title':
358
+ wip_doc_header = wip_doc_header.replaceAll('{{title}}', fm_headers[i].value);
359
+ break;
360
+ case 'reading-time':
361
+ wip_doc_header = wip_doc_header.replaceAll('{{reading-time}}', fm_headers[i].value);
362
+ break;
363
+ case 'contributor-count':
364
+ wip_doc_header = wip_doc_header.replaceAll('{{contributor-count}}', fm_headers[i].value);
365
+ break;
366
+ case 'type':
367
+ wip_doc_header = wip_doc_header.replaceAll('{{doc-type}}', fm_headers[i].value);
368
+ break;
369
+ case 'edit-path':
370
+ wip_doc_header = wip_doc_header.replaceAll('{{edit-url}}', fm_headers[i].value);
371
+ break;
372
+ case 'last-commit':
373
+ const last_commit_date = new Date(fm_headers[i].value).toDateString();
374
+ wip_doc_header = wip_doc_header.replaceAll('{{last-update}}', last_commit_date);
375
+ break;
376
+ }
377
+ }
378
+
379
+ // Now sort out breadcrumbs
380
+ const logical_path = doc_path.replace(path.extname(doc_path), '');
381
+ const bc_for_path = bc[logical_path];
382
+ let bc_tags = '\n';
383
+ for (let i = 0; i < bc_for_path.length - 1; i++) {
384
+ bc_tags += `\t\t\t\t<li class="mt-0 nav-bar-item"><a href="${bc_for_path[i].link}" class="ps-0 pe-0 text-decoration-none">${bc_for_path[i].text}</a></li>\n`;
385
+ }
386
+ bc_tags += '\t\t\t';
387
+ wip_doc_header = wip_doc_header.replaceAll('{{breadcrumbs}}', bc_tags);
388
+ return wip_doc_header;
389
+ };
390
+
295
391
  // File callback for build scan
296
392
  const build_file_callback = function (element) {
297
393
  if (element.extension === 'md') {
@@ -330,7 +426,111 @@
330
426
  sorted: true
331
427
  };
332
428
 
333
- exports.run = function (source_path, verbose) {
429
+ const build_breadcrumbs = function (nav_items) {
430
+ console.log('Processing navigation breadcrumbs...\n');
431
+ // Steve - need to rework this to use recursion, as it's hard-coded for a maximum of 4 levels deep right now
432
+ for (let a = 0; a < nav_items.length; a++) {
433
+ const nav_a = nav_items[a];
434
+ const parent_a = nav_a.text;
435
+ if (nav_a.link) {
436
+ if (nav_a.link.includes('\\')) {
437
+ console.log(`Navigation items should not contain backslashes: ${nav_a.link}`);
438
+ process.exit(1);
439
+ }
440
+ bc[nav_a.link] = [{
441
+ text: nav_a.text,
442
+ link: nav_a.link
443
+ }];
444
+ }
445
+ if (nav_a.items) {
446
+ for (let b = 0; b < nav_a.items.length; b++) {
447
+ const nav_b = nav_a.items[b];
448
+ const parent_b = nav_b.text;
449
+ if (nav_b.link) {
450
+ if (nav_b.link.includes('\\')) {
451
+ console.log(`Navigation items should not contain backslashes: ${nav_b.link}`);
452
+ process.exit(1);
453
+ }
454
+ if (bc[nav_a.link]) {
455
+ bc[nav_b.link] = bc[nav_a.link];
456
+ } else {
457
+ bc[nav_b.link] = [{
458
+ text: parent_a,
459
+ link: nav_a.items[0].link
460
+ }];
461
+ }
462
+ bc[nav_b.link].push({
463
+ text: nav_b.text,
464
+ link: nav_b.link
465
+ });
466
+ }
467
+
468
+ if (nav_b.items) {
469
+ for (let c = 0; c < nav_b.items.length; c++) {
470
+ const nav_c = nav_b.items[c];
471
+ const parent_c = nav_c.text;
472
+ if (nav_c.link) {
473
+ if (nav_c.link.includes('\\')) {
474
+ console.log(`Navigation items should not contain backslashes: ${nav_c.link}`);
475
+ process.exit(1);
476
+ }
477
+ if (bc[nav_b.link]) {
478
+ bc[nav_c.link] = bc[nav_b.link];
479
+ } else {
480
+ bc[nav_c.link] = [{
481
+ text: parent_a,
482
+ link: nav_a.items[0].link
483
+ }];
484
+ bc[nav_c.link].push({
485
+ text: parent_b,
486
+ link: nav_b.items[0].link
487
+ });
488
+ }
489
+ bc[nav_c.link].push({
490
+ text: nav_c.text,
491
+ link: nav_c.link
492
+ });
493
+ }
494
+
495
+ if (nav_c.items) {
496
+ for (let d = 0; d < nav_c.items.length; d++) {
497
+ const nav_d = nav_c.items[d];
498
+ if (nav_d.link) {
499
+ if (bc[nav_c.link]) {
500
+ bc[nav_d.link] = bc[nav_c.link];
501
+ } else {
502
+ bc[nav_d.link] = [{
503
+ text: parent_a,
504
+ link: nav_a.items[0].link
505
+ }];
506
+ bc[nav_d.link].push({
507
+ text: parent_b,
508
+ link: nav_b.items[0].link
509
+ });
510
+ bc[nav_d.link].push({
511
+ text: parent_c,
512
+ link: nav_c.items[0].link
513
+ });
514
+ }
515
+ bc[nav_d.link].push({
516
+ text: nav_d.text,
517
+ link: nav_d.link
518
+ });
519
+ }
520
+ }
521
+
522
+ }
523
+ }
524
+ }
525
+ }
526
+ }
527
+
528
+ }
529
+ //console.log(JSON.stringify(bc, null, 2));
530
+ };
531
+
532
+ exports.run = function (source_path, verbose, github_api_token) {
533
+ git_token = github_api_token;
334
534
  // GERRY: The purpose of this function is to create a zip file containing the hdocbook content,
335
535
  // * Create a _work folder
336
536
  // * copy the hdocbook content to the work folder
@@ -348,20 +548,19 @@
348
548
  // use the docId to get the book config
349
549
  const hdocbook_project_config_path = path.join(source_path, 'hdocbook-project.json');
350
550
  hdocbook_project = require(hdocbook_project_config_path);
551
+ doc_id = hdocbook_project.docId;
351
552
 
352
- docId = hdocbook_project.docId;
353
-
354
- const book_path = path.join(source_path, docId),
553
+ const book_path = path.join(source_path, doc_id),
355
554
  hdocbook_path = path.join(book_path, 'hdocbook.json'),
356
- hdocbook_config = require(hdocbook_path),
357
555
  work_path = path.join(source_path, '_work'),
358
- work_hdocbook_path = path.join(work_path, docId, 'hdocbook.json');
556
+ work_hdocbook_path = path.join(work_path, doc_id, 'hdocbook.json');
359
557
 
360
- console.log(`Building: ${docId} v${hdocbook_config.version}...\n`);
558
+ hdocbook_config = require(hdocbook_path);
559
+
560
+ console.log(`Building: ${doc_id} v${hdocbook_config.version}...\n`);
361
561
 
362
-
363
- work_path_content = path.join(work_path, docId);
364
562
  // Make _work folder to copy everything into
563
+ work_path_content = path.join(work_path, doc_id);
365
564
  if (fs.existsSync(work_path)) {
366
565
  fs.rmSync(work_path, {
367
566
  recursive: true,
@@ -370,14 +569,24 @@
370
569
  }
371
570
  fs.mkdirSync(work_path);
372
571
 
373
- // Copy files from book into _work-docId folder
572
+ // Copy files from book into _work-doc_id folder
374
573
  try {
375
- fs.copySync(path.join(source_path, docId), work_path_content);
574
+ fs.copySync(path.join(source_path, doc_id), work_path_content);
376
575
  } catch (e) {
377
576
  console.error('Error copying from source_path:\n', e);
378
577
  process.exit(1);
379
578
  }
380
579
 
580
+ // Load document header template
581
+ try {
582
+ doc_header_template = fs.readFileSync(doc_header_template_path, 'utf8');
583
+ } catch (err) {
584
+ console.log(`Error reading document header template: ${err}`);
585
+ process.exit(1);
586
+ }
587
+
588
+ build_breadcrumbs(hdocbook_config.navigation.items);
589
+
381
590
  // Get a list of MD files in work_path
382
591
  dree.scan(work_path, dreeOptions, build_file_callback);
383
592
 
@@ -391,25 +600,23 @@
391
600
  transform_static_html(static_html_file);
392
601
  });
393
602
 
394
-
395
603
  console.log(` MD files found: ${conversion_attempted}`);
396
604
  console.log(`Successfully converted to HTML: ${conversion_success}`);
397
605
  console.log(` Failed to convert: ${conversion_failed}\n`);
398
606
  console.log(` Includes Found: ${includes_found}`);
399
607
  console.log(` Includes Success: ${includes_success}`);
400
608
  console.log(` Includes Failed: ${includes_failed}\n`);
401
-
402
609
  console.log(` Static HTML Files Found: ${static_html_files.length}\n`);
403
610
 
404
611
  // Validate content
405
- const validation_success = validate.run(work_path, docId, verbose);
612
+ const validation_success = validate.run(work_path, doc_id, verbose);
406
613
  if (!validation_success) {
407
614
  process.exit(1);
408
615
  }
409
616
 
410
617
  // Now build the index
411
618
  console.log('Performing SQlite index creation...');
412
- let db_name = path.join(work_path, docId, 'index.db');
619
+ let db_name = path.join(work_path, doc_id, 'index.db');
413
620
  const db = new Database(db_name);
414
621
  db.pragma('encoding="UTF-8"');
415
622
  console.log(`\nDatabase created: ${db_name}`);
@@ -425,11 +632,11 @@
425
632
  if (!hdocbook_config.tags) hdocbook_config.tags = [];
426
633
  let index_success_count = 0;
427
634
  for (let i = 0; i < index_records.length; i++) {
428
- let index_path_name = index_records[i].relative_path.replace('\\', '/').replace(`${hdocbook_config.docId}/`, '');
635
+ let index_path_name = index_records[i].relative_path.replace('\\', '/').replace(`${doc_id}/`, '');
429
636
  index_path_name = index_path_name.replace(path.extname(index_records[i].relative_path), '');
430
637
  const index_vals = [
431
638
  index_path_name,
432
- hdocbook_config.docId,
639
+ doc_id,
433
640
  hdocbook_config.audience.join(','),
434
641
  hdocbook_config.tags.join(','),
435
642
  index_records[i].index_html.fm_props.title,
@@ -437,14 +644,14 @@
437
644
  index_records[i].index_html.preview,
438
645
  hdocbook_config.productFamily
439
646
  ];
440
- const index_response = hdoc_index.insert_record(db, table_name, index_cols, index_vals, hdocbook_config.docId, index_records[i].index_html.fm_props.title);
647
+ const index_response = hdoc_index.insert_record(db, table_name, index_cols, index_vals, doc_id, index_records[i].index_html.fm_props.title);
441
648
  if (!index_response.success) {
442
- console.log(`Index record creation failed - ${hdocbook_config.docId}/${index_records[i].index_html.fm_props.title}: ${index_response.error}`);
649
+ console.log(`Index record creation failed - ${doc_id}/${index_records[i].index_html.fm_props.title}: ${index_response.error}`);
443
650
  continue;
444
651
  }
445
652
  index_success_count++;
446
653
  if (verbose) {
447
- console.log(`Inserted index record ${index_response.row_id}: ${hdocbook_config.docId} - ${index_records[i].index_html.fm_props.title}`);
654
+ console.log(`Inserted index record ${index_response.row_id}: ${doc_id} - ${index_records[i].index_html.fm_props.title}`);
448
655
  }
449
656
  }
450
657
  console.log(`\nIndex Build Complete: ${index_success_count} records created.`);
@@ -483,7 +690,7 @@
483
690
  }
484
691
 
485
692
  try {
486
- const zip_path = path.join(work_path, docId + '.zip');
693
+ const zip_path = path.join(work_path, doc_id + '.zip');
487
694
  zipper.sync.zip(work_path_content).compress().save(zip_path);
488
695
  console.log(`\nZIP Creation Success: ${zip_path}\n`);
489
696
  console.log('Build Complete\n');
package/hdoc-module.js CHANGED
@@ -213,4 +213,73 @@
213
213
  if (read_time === 0) read_time = 1;
214
214
  return read_time;
215
215
  };
216
+
217
+ exports.get_github_api_path = function(repo, relative_path) {
218
+ repo = repo.endsWith('/') ? repo.slice(0, -1) : repo;
219
+ let github_paths = {};
220
+ github_paths.api_path = repo.replace('https://github.com/', 'https://api.github.com/repos/');
221
+ github_paths.api_path += '/commits?path=/' + relative_path.replace('\\\\', '/').replace('\\', '/');
222
+ github_paths.edit_path = repo + '/blob/main/' + relative_path.replace('\\\\', '/').replace('\\', '/');
223
+ return github_paths;
224
+ };
225
+
226
+ exports.get_github_contributors = function(github_url, github_api_token) {
227
+ let response = {
228
+ success: false,
229
+ error: '',
230
+ contributors: [],
231
+ contributor_count: 0,
232
+ last_commit_date:''
233
+ };
234
+
235
+ let contributors = {};
236
+
237
+ let request_options = {
238
+ headers: {
239
+ 'User-Agent': 'HornbillDocsBuild',
240
+ 'Cache-Control': 'no-cache',
241
+ 'Host': 'api.github.com',
242
+ 'Accept': 'application/json'
243
+ }
244
+ };
245
+ if (github_api_token !== '') {
246
+ request_options.headers.authorization = `Bearer ${github_api_token}`;
247
+ }
248
+ const github_response = request('GET', github_url, request_options);
249
+
250
+ if (github_response.statusCode === 200) {
251
+ response.success = true;
252
+ let commits = github_response.getBody('UTF8');
253
+ commits = JSON.parse(commits);
254
+ commits.forEach(function(commit){
255
+ if (commit.committer.type.toLowerCase() === 'user' && commit.committer.login.toLowerCase() !== 'web-flow') {
256
+ if (!contributors[commit.committer.id]) {
257
+ response.contributor_count++;
258
+ contributors[commit.committer.id] = {
259
+ login: commit.committer.login,
260
+ avatar_url: commit.committer.avatar_url,
261
+ html_url: commit.committer.html_url,
262
+ name: commit.commit.committer.name
263
+ };
264
+ }
265
+ if (response.last_commit_date !== '') {
266
+ const new_commit_date = new Date(commit.commit.committer.date);
267
+ const exist_commit_date = new Date(response.last_commit_date);
268
+ if (new_commit_date > exist_commit_date) response.last_commit_date = commit.commit.committer.date;
269
+ } else {
270
+ response.last_commit_date = commit.commit.committer.date;
271
+ }
272
+ }
273
+ });
274
+ for (const key in contributors) {
275
+ if (contributors.hasOwnProperty(key)) {
276
+ response.contributors.push(contributors[key]);
277
+ }
278
+ }
279
+ } else {
280
+ response.error = `Unexpected Status ${github_response.statusCode}. ${JSON.parse(github_response.body.toString('utf8')).message}`;
281
+ }
282
+ return response;
283
+ };
284
+
216
285
  })();
package/hdoc.js CHANGED
@@ -25,7 +25,7 @@
25
25
  // Default source path to working directory
26
26
  let source_path = process.cwd();
27
27
  let ui_path = path.join(__dirname, 'ui');
28
-
28
+ let git_token = '';
29
29
  let command = '', // Our command to run
30
30
  verbose = false;
31
31
 
@@ -50,6 +50,11 @@
50
50
  if (x < process.argv.length) {
51
51
  ui_path = process.argv[x];
52
52
  }
53
+ } else if (process.argv[x] == '-git-token') {
54
+ x++;
55
+ if (x < process.argv.length) {
56
+ git_token = process.argv[x];
57
+ }
53
58
  }
54
59
 
55
60
  if (process.argv[x] === '-v') {
@@ -66,7 +71,7 @@
66
71
  server.run(ui_path, source_path);
67
72
  } else if (command == 'build') {
68
73
  const builder = require(path.join(__dirname, 'hdoc-build.js'));
69
- builder.run(source_path, verbose);
74
+ builder.run(source_path, verbose, git_token);
70
75
  } else if (command == 'stats') {
71
76
  const stats = require(path.join(__dirname, 'hdoc-stats.js'));
72
77
  stats.run(ui_path, source_path, verbose);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hdoc-tools",
3
- "version": "0.8.13",
3
+ "version": "0.8.14",
4
4
  "description": "Hornbill HDocBook Development Support Tool",
5
5
  "main": "hdoc.js",
6
6
  "bin": {
@@ -0,0 +1,30 @@
1
+ <div class="document-header">
2
+ <div class="hb-container-horizontal">
3
+ <div class="hb-center-v hb-container-expand">
4
+ <ul class="ps-0 nav-bar-nav-list noeffects after-fslash overflow-ellipsis">{{breadcrumbs}}</ul>
5
+ </div>
6
+ <div class="toolbar-right hb-center-v">
7
+ <a target="_blank" class="toolbar-action" href="{{edit-url}}">
8
+ <i class="bi bi-pencil"></i>
9
+ </a>
10
+ <a class="toolbar-action documentation-menu-popper">
11
+ <i class="bi bi-three-dots-vertical"></i>
12
+ </a>
13
+ </div>
14
+ </div>
15
+
16
+ <h1>{{title}}</h1>
17
+
18
+ <div class="hb-container-horizontal">
19
+ <div class="hb-center-v hb-container-expand">
20
+ <ul class="ps-0 nav-bar-nav-list noeffects after-bullets overflow-ellipsis text-light-2">
21
+ <li class="ps-0 mt-0 nav-bar-item">{{doc-type}}</li>
22
+ <li class="ps-0 mt-0 nav-bar-item">{{last-update}}</li>
23
+ <li class="ps-0 mt-0 nav-bar-item">{{reading-time}} minutes to read</li>
24
+ <li class="ps-0 mt-0 nav-bar-item">
25
+ <a class="link c-pointer" data-bs-toggle="modal" data-bs-target="#contributersModal">{{contributor-count}} contributors</a>
26
+ </li>
27
+ </ul>
28
+ </div>
29
+ </div>
30
+ </div>
@@ -112,7 +112,7 @@ samp {
112
112
 
113
113
  img,
114
114
  svg {
115
- display: inline;
115
+ display: inline-block;
116
116
  }
117
117
 
118
118
  video,