hdoc-tools 0.8.22 → 0.8.24

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.
Files changed (38) hide show
  1. package/hdoc-build-db.js +141 -0
  2. package/hdoc-build-pdf.js +169 -0
  3. package/hdoc-build.js +44 -14
  4. package/hdoc-init.js +0 -1
  5. package/hdoc-validate.js +0 -2
  6. package/hdoc.js +2 -2
  7. package/package.json +5 -2
  8. package/templates/pdf/css/custom-block.css +90 -0
  9. package/templates/pdf/css/fonts.css +221 -0
  10. package/templates/pdf/css/hdocs-pdf.css +242 -0
  11. package/templates/pdf/css/vars.css +393 -0
  12. package/templates/pdf/fonts/inter-cyrillic copy.woff2 +0 -0
  13. package/templates/pdf/fonts/inter-cyrillic-ext.woff2 +0 -0
  14. package/templates/pdf/fonts/inter-cyrillic.woff2 +0 -0
  15. package/templates/pdf/fonts/inter-greek-ext.woff2 +0 -0
  16. package/templates/pdf/fonts/inter-greek.woff2 +0 -0
  17. package/templates/pdf/fonts/inter-italic-cyrillic-ext.woff2 +0 -0
  18. package/templates/pdf/fonts/inter-italic-cyrillic.woff2 +0 -0
  19. package/templates/pdf/fonts/inter-italic-greek-ext.woff2 +0 -0
  20. package/templates/pdf/fonts/inter-italic-greek.woff2 +0 -0
  21. package/templates/pdf/fonts/inter-italic-latin-ext.woff2 +0 -0
  22. package/templates/pdf/fonts/inter-italic-latin.woff2 +0 -0
  23. package/templates/pdf/fonts/inter-italic-vietnamese.woff2 +0 -0
  24. package/templates/pdf/fonts/inter-latin-ext.woff2 +0 -0
  25. package/templates/pdf/fonts/inter-latin.woff2 +0 -0
  26. package/templates/pdf/fonts/inter-roman-cyrillic-ext.woff2 +0 -0
  27. package/templates/pdf/fonts/inter-roman-cyrillic.woff2 +0 -0
  28. package/templates/pdf/fonts/inter-roman-greek-ext.woff2 +0 -0
  29. package/templates/pdf/fonts/inter-roman-greek.woff2 +0 -0
  30. package/templates/pdf/fonts/inter-roman-latin-ext.woff2 +0 -0
  31. package/templates/pdf/fonts/inter-roman-latin.woff2 +0 -0
  32. package/templates/pdf/fonts/inter-roman-vietnamese.woff2 +0 -0
  33. package/templates/pdf/fonts/inter-vietnamese.woff2 +0 -0
  34. package/templates/pdf/images/hornbill-logo-full.svg +92 -0
  35. package/templates/pdf/template-footer.html +19 -0
  36. package/templates/pdf/template.html +13 -0
  37. package/templates/pdf-header-non-git.html +13 -0
  38. package/templates/pdf-header.html +17 -0
@@ -0,0 +1,141 @@
1
+ (function () {
2
+ 'use strict';
3
+
4
+ const path = require('path'),
5
+ hdoc_index = require(path.join(__dirname, 'hdoc-db.js')),
6
+ database = require('better-sqlite3');
7
+
8
+ const db_schema = {
9
+ hdoc_index: [
10
+ 'relative_url UNINDEXED',
11
+ 'book_id',
12
+ 'book_audience UNINDEXED',
13
+ 'book_tags',
14
+ 'doc_title',
15
+ 'doc_content',
16
+ 'doc_preview UNINDEXED',
17
+ 'doc_family_id'
18
+ ],
19
+ hdoc_meta: [
20
+ 'doc_id INTEGER',
21
+ 'contributor_count INTEGER UNINDEXED',
22
+ 'edit_url UNINDEXED',
23
+ 'last_commit UNINDEXED'
24
+ ],
25
+ hdoc_contributors: [
26
+ 'doc_id INTEGER',
27
+ 'login',
28
+ 'name',
29
+ 'avatar UNINDEXED',
30
+ 'url UNINDEXED'
31
+ ]
32
+ };
33
+
34
+ exports.create_table = function (db, table, cols, virtual, fts5) {
35
+ const table_created = hdoc_index.create_table(db, table, cols, virtual, fts5);
36
+ if (table_created !== null) {
37
+ return `\nError creating table: ${table_created}`;
38
+ } else {
39
+ console.log(`\nTable created: ${table}`);
40
+ }
41
+ return null;
42
+ };
43
+
44
+ exports.create_db = function (db_path, doc_id) {
45
+ let response = {
46
+ error: null,
47
+ db: null
48
+ };
49
+ console.log('Performing SQlite index creation...');
50
+ let db_name = path.join(db_path, doc_id, 'index.db');
51
+ response.db = new database(db_name);
52
+ response.db.pragma('encoding="UTF-8"');
53
+ console.log(`\nDatabase created: ${db_name}`);
54
+
55
+ // Create tables
56
+ for (const key in db_schema) {
57
+ if (db_schema.hasOwnProperty(key)) {
58
+ const virtual = key === 'hdoc_index' ? true : false;
59
+ const fts5 = key === 'hdoc_index' ? true : false;
60
+ const table_created_error = this.create_table(response.db, key, db_schema[key], virtual, fts5);
61
+ if (table_created_error !== null) {
62
+ console.log(table_created_error);
63
+ }
64
+ }
65
+ }
66
+ return response;
67
+ };
68
+
69
+ exports.populate_index = function (db, doc_id, book_config, index_records, verbose = false) {
70
+ let response = {
71
+ success: false,
72
+ index_success_count: 0,
73
+ error: ''
74
+ };
75
+
76
+ if (!book_config.tags) book_config.tags = [];
77
+
78
+ for (let i = 0; i < index_records.length; i++) {
79
+ let index_path_name = index_records[i].relative_path.replace('\\', '/').replace(`${doc_id}/`, '');
80
+ index_path_name = index_path_name.replace(path.extname(index_records[i].relative_path), '');
81
+ const index_vals = [
82
+ index_path_name,
83
+ doc_id,
84
+ book_config.audience.join(','),
85
+ book_config.tags.join(','),
86
+ index_records[i].index_html.fm_props.title,
87
+ index_records[i].index_html.text,
88
+ index_records[i].index_html.preview,
89
+ book_config.productFamily
90
+ ];
91
+ const index_response = hdoc_index.insert_record(db, 'hdoc_index', db_schema.hdoc_index, index_vals);
92
+ if (!index_response.success) {
93
+ console.log(`Index record creation failed - ${doc_id}/${index_records[i].index_html.fm_props.title}: ${index_response.error}`);
94
+ continue;
95
+ }
96
+
97
+ // Now add metadata
98
+ const meta_vals = [
99
+ parseInt(index_response.row_id, 10),
100
+ index_records[i].metadata.contributor_count,
101
+ index_records[i].metadata.edit_url,
102
+ index_records[i].metadata.last_commit
103
+ ];
104
+ const meta_response = hdoc_index.insert_record(db, 'hdoc_meta', db_schema.hdoc_meta, meta_vals);
105
+ if (!meta_response.success) {
106
+ console.log(`Index metadata record creation failed - ${doc_id}/${index_response.row_id}/${index_records[i].index_html.fm_props.title}: ${meta_response.error}`);
107
+ continue;
108
+ }
109
+ if (verbose) {
110
+ console.log(`Inserted index record ${index_response.row_id}: ${doc_id} - ${index_records[i].index_html.fm_props.title}`);
111
+ console.log(`Inserted index metadata record for index ID: ${meta_response.row_id}`);
112
+ }
113
+
114
+ // Now add contributor records
115
+ for (let j = 0; j < index_records[i].contributors.length; j++) {
116
+ const contrib_vals = [
117
+ parseInt(index_response.row_id, 10),
118
+ index_records[i].contributors[j].login,
119
+ index_records[i].contributors[j].name,
120
+ index_records[i].contributors[j].avatar_url,
121
+ index_records[i].contributors[j].html_url
122
+ ];
123
+ const cont_response = hdoc_index.insert_record(db, 'hdoc_contributors', db_schema.hdoc_contributors, contrib_vals);
124
+ if (!cont_response.success) {
125
+ console.log(`Index document contributor record creation failed - ${doc_id}/${index_response.row_id}/${index_records[i].index_html.fm_props.title}: ${cont_response.error}`);
126
+ continue;
127
+ }
128
+ if (verbose) {
129
+ console.log(`Inserted document contributor recordL ${cont_response.row_id}`);
130
+ }
131
+ }
132
+
133
+ response.index_success_count++;
134
+
135
+ }
136
+ response.success = true;
137
+ console.log(`\nIndex Build Complete:`);
138
+ console.log(`${response.index_success_count} document index records created.`);
139
+ return response;
140
+ };
141
+ })();
@@ -0,0 +1,169 @@
1
+ (function () {
2
+ 'use strict';
3
+
4
+ const cheerio = require('cheerio'),
5
+ dree = require('dree'),
6
+ fs = require('fs-extra'),
7
+ mime = require('mime-types'),
8
+ path = require('path'),
9
+ puppeteer = require('puppeteer'),
10
+ request = require('sync-request'),
11
+ hdoc = require(path.join(__dirname, 'hdoc-module.js'));
12
+
13
+ const dree_options = {
14
+ extensions: ['css'],
15
+ normalize: true,
16
+ };
17
+
18
+ let css_files = [],
19
+ hb_logo = '',
20
+ header = '',
21
+ footer = '';
22
+
23
+ const file_callback = function (element) {
24
+ css_files.push(element.path);
25
+ };
26
+
27
+ const get_footer = function (template_path) {
28
+ let footer_content = null;
29
+ try {
30
+ footer_content = fs.readFileSync(path.join(template_path, 'template-footer.html'), 'utf8');
31
+ } catch (err) {
32
+ console.log(`Error loading template: ${err}`);
33
+ }
34
+ return footer_content;
35
+ };
36
+
37
+ exports.process_images = async function (file_path, html_source, verbose) {
38
+ const book_work_root = file_path.path.replace(file_path.relativePath, '');
39
+ if (verbose) console.log('Parsing img tags from HTML source');
40
+
41
+ // Use cheerio to parse html
42
+ const $ = cheerio.load(html_source);
43
+
44
+ // Get iFrames from HTML, to replace with a tags
45
+ let iframes = [];
46
+ const iframe_html = $('iframe').map(function () {
47
+ const response = {
48
+ html: $.html(this),
49
+ src: $(this).attr('src'),
50
+ title: $(this).attr('title') ? $(this).attr('title') : 'No Link Title Provided'
51
+ };
52
+ return response;
53
+ }).get();
54
+ iframes.push(...iframe_html);
55
+ for (let i = 0; i < iframes.length; i++) {
56
+ const link = `<p><a href="${iframes[i].src}">${iframes[i].title}</a></p>`;
57
+ const regex = new RegExp(`<iframe.*src="${iframes[i].src.replace('/', '\\/')}".*</iframe>`);
58
+ html_source = html_source.replace(regex, link);
59
+ }
60
+
61
+ // Get image links from HTML, to embed into the pdf
62
+ let imgs = [];
63
+ const srcs = $('img').map(function (i) {
64
+ return $(this).attr('src');
65
+ }).get();
66
+ imgs.push(...srcs);
67
+ for (let i = 0; i < imgs.length; i++) {
68
+ if (hdoc.valid_url(imgs[i]).valid) {
69
+ // External Link
70
+ const file_response = request('GET', imgs[i]);
71
+ if (file_response.statusCode === 200) {
72
+ const image_buffer = file_response.getBody();
73
+ const mime_type = mime.lookup(imgs[i]);
74
+ let image_b64 = image_buffer.toString("base64");
75
+ image_b64 = `data:${mime_type};base64,${image_b64}`;
76
+ html_source = html_source.replace(imgs[i], image_b64);
77
+ } else {
78
+ throw `Unexpected Status ${file_response.statusCode}`;
79
+ }
80
+ } else {
81
+ // Internal link
82
+ const image_path = path.join(book_work_root, imgs[i].replace('_books/', ''));
83
+ try {
84
+ const image_buffer = fs.readFileSync(image_path);
85
+ const mime_type = mime.lookup(image_path);
86
+ let image_b64 = image_buffer.toString("base64");
87
+ image_b64 = `data:${mime_type};base64,${image_b64}`;
88
+ html_source = html_source.replace(imgs[i], image_b64);
89
+ } catch (err) {
90
+ console.log('Error reading image from HTML source [', image_path, '] - ', err);
91
+ return null;
92
+ }
93
+ }
94
+ }
95
+
96
+ return html_source;
97
+ };
98
+
99
+ exports.generate_pdf = async function (pdf_template_path, pdf_template_content, book_config, html_source, target_file, verbose = false) {
100
+ if (verbose) console.log(`Generating PDF: ${target_file}`);
101
+
102
+ // Cache footer
103
+ if (footer === '') footer = get_footer(pdf_template_path);
104
+
105
+ // Read svg logo file into buffer, convert to B64 string
106
+ if (hb_logo === '') {
107
+ const hb_logo_path = path.join(pdf_template_path, 'images', 'hornbill-logo-full.svg');
108
+ try {
109
+ const hb_logo_file_buffer = fs.readFileSync(hb_logo_path);
110
+ hb_logo = hb_logo_file_buffer.toString("base64");
111
+ hb_logo = `data:image/svg+xml;base64,${hb_logo}`;
112
+ } catch (err) {
113
+ console.log('Error reading logo from template:', err);
114
+ return;
115
+ }
116
+ }
117
+
118
+ html_source = pdf_template_content.replace('{{book_title}}', book_config.title).replace('{{document_content}}', html_source).replace('{{hb_logo}}', hb_logo);
119
+
120
+ // Create a browser instance
121
+ const browser = await puppeteer.launch();
122
+
123
+ // Create a new page
124
+ const page = await browser.newPage();
125
+
126
+ // Set HTML content from HTML source
127
+ await page.setContent(html_source, {
128
+ waitUntil: 'domcontentloaded'
129
+ });
130
+
131
+ // To reflect CSS used for screens instead of print
132
+ await page.emulateMediaType('screen');
133
+
134
+ if (css_files.length === 0) {
135
+ // Get a list of CSS files
136
+ dree.scan(pdf_template_path, dree_options, file_callback);
137
+ }
138
+
139
+ for (let i = 0; i < css_files.length; i++) {
140
+ await page.addStyleTag({
141
+ path: css_files[i]
142
+ });
143
+ }
144
+
145
+ try {
146
+ await page.pdf({
147
+ path: target_file,
148
+ margin: {
149
+ top: '30px',
150
+ right: '35px',
151
+ bottom: '80px',
152
+ left: '35px'
153
+ },
154
+ printBackground: true,
155
+ format: 'A4',
156
+ displayHeaderFooter: true,
157
+ headerTemplate: '<div />',
158
+ footerTemplate: footer
159
+ });
160
+ if (verbose) console.log('PDF generation success.');
161
+
162
+ } catch (err) {
163
+ console.log(`Error generating PDF ${target_file} - ${err}`);
164
+ }
165
+
166
+ // Close the browser instance
167
+ await browser.close();
168
+ };
169
+ })();
package/hdoc-build.js CHANGED
@@ -1,3 +1,7 @@
1
+ const {
2
+ verbose
3
+ } = require('sqlite3');
4
+
1
5
  (function () {
2
6
  'use strict';
3
7
 
@@ -10,12 +14,17 @@
10
14
  validate = require(path.join(__dirname, 'hdoc-validate.js')),
11
15
  hdoc = require(path.join(__dirname, 'hdoc-module.js')),
12
16
  hdoc_build_db = require(path.join(__dirname, 'hdoc-build-db.js')),
17
+ hdoc_build_pdf = require(path.join(__dirname, 'hdoc-build-pdf.js')),
13
18
  hdoc_index = require(path.join(__dirname, 'hdoc-db.js')),
14
19
  zipper = require('zip-local');
15
20
 
16
21
  const h_tags_to_search = ['h1', 'h2', 'h3'],
17
22
  doc_header_template_path = path.join(__dirname, 'templates', 'doc-header.html'),
18
- non_git_doc_header_template_path = path.join(__dirname, 'templates', 'doc-header-non-git.html');
23
+ non_git_doc_header_template_path = path.join(__dirname, 'templates', 'doc-header-non-git.html'),
24
+ pdf_header_template_path = path.join(__dirname, 'templates', 'pdf-header.html'),
25
+ non_git_pdf_header_template_path = path.join(__dirname, 'templates', 'pdf-header-non-git.html'),
26
+ pdf_template_path = path.join(__dirname, 'templates', 'pdf'),
27
+ pdf_template_file_path = path.join(pdf_template_path, 'template.html');
19
28
 
20
29
  let bc = {}, // Breadcrumbs map
21
30
  book_read_time = 0,
@@ -25,6 +34,9 @@
25
34
  conversion_failed = 0,
26
35
  doc_header_template = '',
27
36
  doc_header_template_non_git = '',
37
+ pdf_header_template = '',
38
+ pdf_header_template_non_git = '',
39
+ pdf_template = '',
28
40
  doc_id = '',
29
41
  git_token = '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', // Github fine-grained personal access token that has minimum read-only access to Hornbill Docs org repo content
30
42
  hdocbook_config = {},
@@ -37,7 +49,7 @@
37
49
  static_html_files = [],
38
50
  work_path_content = '';
39
51
 
40
- const transform_static_html = function (file_path) {
52
+ const transform_static_html = async function (file_path) {
41
53
  if (fs.existsSync(file_path.path)) {
42
54
  // Load HTML file
43
55
  let html_txt = fs.readFileSync(file_path.path, 'utf8');
@@ -211,7 +223,7 @@
211
223
  }
212
224
  };
213
225
 
214
- const transform_markdown_and_save_html = function (file_path) {
226
+ const transform_markdown_and_save_html = async function (file_path, verbose) {
215
227
  conversion_attempted++;
216
228
  if (fs.existsSync(file_path.path)) {
217
229
  // Load markdown file
@@ -372,17 +384,24 @@
372
384
  fm_header += ']]-->';
373
385
 
374
386
  let doc_header = '';
387
+ let pdf_header = '';
375
388
  if (hdocbook_config.publicSource.includes('github.com/Hornbill-Docs')) {
376
389
  // Build doc header from template and frontmatter tags
377
390
  doc_header = process_doc_header(fm_headers, file_path.relativePath, doc_header_template);
391
+ pdf_header = process_doc_header(fm_headers, file_path.relativePath, pdf_header_template);
378
392
  } else {
379
393
  // Build doc header from template and frontmatter tags
380
394
  doc_header = process_doc_header(fm_headers, file_path.relativePath, doc_header_template_non_git);
395
+ pdf_header = process_doc_header(fm_headers, file_path.relativePath, pdf_header_template_non_git);
381
396
  }
382
- /*
383
- const pdf_html = `${fm_header}\n${doc_header}\n${html_txt}`;
384
- const pdf_file = file_path.path.replace(path.extname(file_path.path), '.pdf');
385
- */
397
+
398
+ let pdf_txt = await hdoc_build_pdf.process_images(file_path, html_txt);
399
+ pdf_txt = `${pdf_header}\n${pdf_txt}`;
400
+
401
+ // Generate PDF file from HTML
402
+ const pdf_file_path = file_path.path.replace(path.extname(file_path.path), '.pdf');
403
+ await hdoc_build_pdf.generate_pdf(pdf_template_path, pdf_template, hdocbook_config, pdf_txt, pdf_file_path, verbose);
404
+
386
405
  html_txt = `${fm_header}\n${doc_header}\n${html_txt}`;
387
406
 
388
407
  // Save HTML into HTML file
@@ -603,7 +622,7 @@
603
622
  //console.log(JSON.stringify(bc, null, 2));
604
623
  };
605
624
 
606
- exports.run = function (source_path, verbose, github_api_token) {
625
+ exports.run = async function (source_path, verbose, github_api_token) {
607
626
  if (github_api_token !== '') {
608
627
  git_token = github_api_token;
609
628
  }
@@ -658,25 +677,36 @@
658
677
  try {
659
678
  doc_header_template = fs.readFileSync(doc_header_template_path, 'utf8');
660
679
  doc_header_template_non_git = fs.readFileSync(non_git_doc_header_template_path, 'utf8');
680
+ pdf_header_template = fs.readFileSync(pdf_header_template_path, 'utf8');
681
+ pdf_header_template_non_git = fs.readFileSync(non_git_pdf_header_template_path, 'utf8');
661
682
  } catch (err) {
662
683
  console.log(`Error reading document header template: ${err}`);
663
684
  process.exit(1);
664
685
  }
665
686
 
687
+ // Load PDF templates
688
+ try {
689
+ pdf_template = fs.readFileSync(pdf_template_file_path, 'utf8');
690
+ } catch (err) {
691
+ console.log(`Error reading PDF template: ${err}`);
692
+ process.exit(1);
693
+ }
694
+
666
695
  build_breadcrumbs(hdocbook_config.navigation.items);
667
696
 
697
+ console.log('Processing content...');
668
698
  // Get a list of MD files in work_path
669
699
  dree.scan(work_path, dreeOptions, build_file_callback);
670
700
 
671
701
  // Work through MD files and convert to HTML
672
- md_files.forEach(function (md_file) {
673
- transform_markdown_and_save_html(md_file);
674
- });
702
+ for (let i = 0; i < md_files.length; i++) {
703
+ await transform_markdown_and_save_html(md_files[i], verbose);
704
+ }
675
705
 
676
706
  // Work through Static HTML files and add Frontmatter tags
677
- static_html_files.forEach(function (static_html_file) {
678
- transform_static_html(static_html_file);
679
- });
707
+ for (let i = 0; i < static_html_files.length; i++) {
708
+ await transform_static_html(static_html_files[i]);
709
+ }
680
710
 
681
711
  // Output to console
682
712
  console.log(` MD files found: ${conversion_attempted}`);
package/hdoc-init.js CHANGED
@@ -3,7 +3,6 @@
3
3
 
4
4
  // Required modules
5
5
  const prompt = require('prompt');
6
- //const fs = require('fs');
7
6
  const fs = require('fs-extra');
8
7
  const path = require('path');
9
8
 
package/hdoc-validate.js CHANGED
@@ -1,5 +1,3 @@
1
- const parseLinkDestination = require('markdown-it/lib/helpers/parse_link_destination');
2
-
3
1
  (function () {
4
2
  'use strict';
5
3
 
package/hdoc.js CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
 
3
- (function () {
3
+ (async function () {
4
4
  'use strict';
5
5
 
6
6
  const preRun = require('./validateNodeVer.js'),
@@ -71,7 +71,7 @@
71
71
  server.run(ui_path, source_path);
72
72
  } else if (command == 'build') {
73
73
  const builder = require(path.join(__dirname, 'hdoc-build.js'));
74
- builder.run(source_path, verbose, git_token);
74
+ await builder.run(source_path, verbose, git_token);
75
75
  } else if (command == 'stats') {
76
76
  const stats = require(path.join(__dirname, 'hdoc-stats.js'));
77
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.22",
3
+ "version": "0.8.24",
4
4
  "description": "Hornbill HDocBook Development Support Tool",
5
5
  "main": "hdoc.js",
6
6
  "bin": {
@@ -10,6 +10,8 @@
10
10
  "hdoc.js",
11
11
  "hdoc-db.js",
12
12
  "hdoc-build.js",
13
+ "hdoc-build-db.js",
14
+ "hdoc-build-pdf.js",
13
15
  "hdoc-help.js",
14
16
  "hdoc-init.js",
15
17
  "hdoc-module.js",
@@ -42,9 +44,10 @@
42
44
  "markdown-it": "^13.0.1",
43
45
  "markdown-it-container": "^3.0.0",
44
46
  "markdown-it-front-matter": "^0.2.3",
47
+ "mime-types": "^2.1.35",
45
48
  "multer": "^1.4.5-lts.1",
46
- "pdf-creator-node": "^2.3.5",
47
49
  "prompt": "^1.3.0",
50
+ "puppeteer": "^19.6.0",
48
51
  "stream": "0.0.2",
49
52
  "sync-request": "^6.1.0",
50
53
  "words-count": "^2.0.2",
@@ -0,0 +1,90 @@
1
+ .custom-block {
2
+ border: 1px solid transparent;
3
+ border-radius: 8px;
4
+ padding: 16px 16px 8px;
5
+ line-height: 24px;
6
+ font-size: var(--htl-default-font-size);
7
+ color: var(--htl-c-text-2);
8
+ }
9
+
10
+ .custom-block.info {
11
+ border-color: var(--htl-custom-block-info-border);
12
+ color: var(--htl-custom-block-info-text);
13
+ background-color: var(--htl-custom-block-info-bg);
14
+ }
15
+
16
+ .custom-block.info code {
17
+ background-color: var(--htl-custom-block-info-code-bg);
18
+ }
19
+
20
+ .custom-block.tip {
21
+ border-color: var(--htl-custom-block-tip-border);
22
+ color: var(--htl-custom-block-tip-text);
23
+ background-color: var(--htl-custom-block-tip-bg);
24
+ }
25
+
26
+ .custom-block.tip code {
27
+ background-color: var(--htl-custom-block-tip-code-bg);
28
+ }
29
+
30
+ .custom-block.warning {
31
+ border-color: var(--htl-custom-block-warning-border);
32
+ color: var(--htl-custom-block-warning-text);
33
+ background-color: var(--htl-custom-block-warning-bg);
34
+ }
35
+
36
+ .custom-block.warning code {
37
+ background-color: var(--htl-custom-block-warning-code-bg);
38
+ }
39
+
40
+ .custom-block.danger {
41
+ border-color: var(--htl-custom-block-danger-border);
42
+ color: var(--htl-custom-block-danger-text);
43
+ background-color: var(--htl-custom-block-danger-bg);
44
+ }
45
+
46
+ .custom-block.danger code {
47
+ background-color: var(--htl-custom-block-danger-code-bg);
48
+ }
49
+
50
+ .custom-block.details {
51
+ border-color: var(--htl-custom-block-details-border);
52
+ color: var(--htl-custom-block-details-text);
53
+ background-color: var(--htl-custom-block-details-bg);
54
+ }
55
+
56
+ .custom-block.details code {
57
+ background-color: var(--htl-custom-block-details-code-bg);
58
+ }
59
+
60
+ .custom-block-title {
61
+ font-weight: 700;
62
+ }
63
+
64
+ .custom-block p + p {
65
+ margin: 8px 0;
66
+ }
67
+
68
+ .custom-block.details summary {
69
+ margin: 0 0 8px;
70
+ font-weight: 700;
71
+ }
72
+
73
+ .custom-block.details summary + p {
74
+ margin: 8px 0;
75
+ }
76
+
77
+ .custom-block a {
78
+ color: inherit;
79
+ font-weight: 600;
80
+ text-decoration: underline;
81
+ transition: opacity 0.25s;
82
+ }
83
+
84
+ .custom-block a:hover {
85
+ opacity: 0.6;
86
+ }
87
+
88
+ .custom-block code {
89
+ font-size: var(--htl-custom-block-code-font-size);
90
+ }