diff --git a/gulp.d/tasks/build.js b/gulp.d/tasks/build.js index 1efcfd6c..1e91064e 100644 --- a/gulp.d/tasks/build.js +++ b/gulp.d/tasks/build.js @@ -7,6 +7,16 @@ const concat = require('gulp-concat') const cssnano = require('cssnano') const fs = require('fs') const { promises: fsp } = fs +const iconPacks = { + fa: require('@fortawesome/free-solid-svg-icons'), + fas: require('@fortawesome/free-solid-svg-icons'), + far: require('@fortawesome/free-regular-svg-icons'), + fab: require('@fortawesome/free-brands-svg-icons'), + __v4__: require('@fortawesome/fontawesome-free/js/v4-shims').reduce( + (accum, it) => accum.set(`fa-${it[0]}`, [it[1] || 'fas', `fa-${it[2] || it[0]}`]), + new Map() + ), +} const imagemin = require('gulp-imagemin') const merge = require('merge-stream') const ospath = require('path') @@ -88,6 +98,9 @@ module.exports = (src, dest, preview) => () => { next(bundleError, file) }) ) + } else if (file.relative === 'js/vendor/fontawesome-icon-defs.js') { + file.contents = Buffer.from(populateIconDefs(require(file.path))) + next(null, file) } else { fsp.readFile(file.path, 'UTF-8').then((contents) => { file.contents = Buffer.from(contents) @@ -129,3 +142,32 @@ function postcssPseudoElementFixer (css, result) { rule.selector = rule.selectors.map((it) => it.replace(/(^|[^:]):(before|after)$/, '$1::$2')).join(',') }) } + +function populateIconDefs ({ FontAwesomeIconDefs: { includes = [], admonitionIcons = {} } }) { + const iconDefs = [...new Set(includes)].reduce((accum, iconKey) => { + if (accum.has(iconKey)) return accum + const [iconPrefix, iconName] = iconKey.split(' ').slice(0, 2) + let iconDef = (iconPacks[iconPrefix] || {})[camelCase(iconName)] + if (iconDef) { + return accum.set(iconKey, { ...iconDef, prefix: iconPrefix }) + } else if (iconPrefix === 'fa') { + const [realIconPrefix, realIconName] = iconPacks.__v4__.get(iconName) || [] + if ( + realIconName && + !accum.has((iconKey = `${realIconPrefix} ${realIconName}`)) && + (iconDef = (iconPacks[realIconPrefix] || {})[camelCase(realIconName)]) + ) { + return accum.set(iconKey, { ...iconDef, prefix: realIconPrefix }) + } + } + return accum + }, new Map()) + return [ + `window.FontAwesomeIconDefs = ${JSON.stringify([...iconDefs.values()])}\n`, + `window.FontAwesomeIconDefs.admonitionIcons = ${JSON.stringify(admonitionIcons)}\n`, + ].join() +} + +function camelCase (str) { + return str.replace(/-(.)/g, (_, l) => l.toUpperCase()) +} diff --git a/package-lock.json b/package-lock.json index d32d1ece..c5d54055 100644 --- a/package-lock.json +++ b/package-lock.json @@ -356,6 +356,54 @@ } } }, + "@fortawesome/fontawesome-common-types": { + "version": "0.2.32", + "resolved": "https://npm.fontawesome.com/@fortawesome/fontawesome-common-types/-/0.2.32/fontawesome-common-types-0.2.32.tgz", + "integrity": "sha512-ux2EDjKMpcdHBVLi/eWZynnPxs0BtFVXJkgHIxXRl+9ZFaHPvYamAfCzeeQFqHRjuJtX90wVnMRaMQAAlctz3w==", + "dev": true + }, + "@fortawesome/fontawesome-free": { + "version": "5.15.1", + "resolved": "https://npm.fontawesome.com/@fortawesome/fontawesome-free/-/5.15.1/fontawesome-free-5.15.1.tgz", + "integrity": "sha512-OEdH7SyC1suTdhBGW91/zBfR6qaIhThbcN8PUXtXilY4GYnSBbVqOntdHbC1vXwsDnX0Qix2m2+DSU1J51ybOQ==", + "dev": true + }, + "@fortawesome/fontawesome-svg-core": { + "version": "1.2.32", + "resolved": "https://npm.fontawesome.com/@fortawesome/fontawesome-svg-core/-/1.2.32/fontawesome-svg-core-1.2.32.tgz", + "integrity": "sha512-XjqyeLCsR/c/usUpdWcOdVtWFVjPbDFBTQkn2fQRrWhhUoxriQohO2RWDxLyUM8XpD+Zzg5xwJ8gqTYGDLeGaQ==", + "dev": true, + "requires": { + "@fortawesome/fontawesome-common-types": "^0.2.32" + } + }, + "@fortawesome/free-brands-svg-icons": { + "version": "5.15.1", + "resolved": "https://npm.fontawesome.com/@fortawesome/free-brands-svg-icons/-/5.15.1/free-brands-svg-icons-5.15.1.tgz", + "integrity": "sha512-pkTZIWn7iuliCCgV+huDfZmZb2UjslalXGDA2PcqOVUYJmYL11y6ooFiMJkJvUZu+xgAc1gZgQe+Px12mZF0CA==", + "dev": true, + "requires": { + "@fortawesome/fontawesome-common-types": "^0.2.32" + } + }, + "@fortawesome/free-regular-svg-icons": { + "version": "5.15.1", + "resolved": "https://npm.fontawesome.com/@fortawesome/free-regular-svg-icons/-/5.15.1/free-regular-svg-icons-5.15.1.tgz", + "integrity": "sha512-eD9NWFy89e7SVVtrLedJUxIpCBGhd4x7s7dhesokjyo1Tw62daqN5UcuAGu1NrepLLq1IeAYUVfWwnOjZ/j3HA==", + "dev": true, + "requires": { + "@fortawesome/fontawesome-common-types": "^0.2.32" + } + }, + "@fortawesome/free-solid-svg-icons": { + "version": "5.15.1", + "resolved": "https://npm.fontawesome.com/@fortawesome/free-solid-svg-icons/-/5.15.1/free-solid-svg-icons-5.15.1.tgz", + "integrity": "sha512-EFMuKtzRMNbvjab/SvJBaOOpaqJfdSap/Nl6hst7CgrJxwfORR1drdTV6q1Ib/JVzq4xObdTDcT6sqTaXMqfdg==", + "dev": true, + "requires": { + "@fortawesome/fontawesome-common-types": "^0.2.32" + } + }, "@nodelib/fs.scandir": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.3.tgz", diff --git a/package.json b/package.json index 4443561b..958dcea1 100644 --- a/package.json +++ b/package.json @@ -15,6 +15,11 @@ ], "devDependencies": { "@octokit/rest": "~18.0", + "@fortawesome/fontawesome-free": "~5.15", + "@fortawesome/fontawesome-svg-core": "~1.2", + "@fortawesome/free-brands-svg-icons": "~5.15", + "@fortawesome/free-solid-svg-icons": "~5.15", + "@fortawesome/free-regular-svg-icons": "~5.15", "asciidoctor.js": "1.5.9", "autoprefixer": "~10.0", "browser-pack-flat": "~3.4", diff --git a/src/css/doc.css b/src/css/doc.css index ab654efd..671390c6 100644 --- a/src/css/doc.css +++ b/src/css/doc.css @@ -123,8 +123,10 @@ color: var(--link_unresolved-font-color); } +/* NOTE reserve space for icon */ .doc i.fa { - font-style: normal; + display: inline-block; + width: 1em; } .doc p code, @@ -332,7 +334,7 @@ width: 100%; } -.doc .admonitionblock .icon { +.doc .admonitionblock td.icon { position: absolute; top: 0; left: 0; @@ -346,39 +348,52 @@ transform: translate(-0.5rem, -50%); } -.doc .admonitionblock.caution .icon { +.doc .admonitionblock td.icon i { + display: inline-flex; + align-items: center; + width: auto; + height: 100%; +} + +.doc .admonitionblock td.icon i:empty::before, +.doc .admonitionblock td.icon .svga { + content: ""; + height: inherit; + width: 1.5rem; + margin: 0 0.25rem 0 -0.5rem; + border-radius: 0.45rem 0 0 0.45rem; + padding: 0.2em 0.2em 0.3em 0.3em; + background-color: rgba(0, 0, 0, 0.2); +} + +.doc .admonitionblock.caution td.icon { background-color: var(--caution-color); color: var(--caution-on-color); } -.doc .admonitionblock.important .icon { +.doc .admonitionblock.important td.icon { background-color: var(--important-color); color: var(--important-on-color); } -.doc .admonitionblock.note .icon { +.doc .admonitionblock.note td.icon { background-color: var(--note-color); color: var(--note-on-color); } -.doc .admonitionblock.tip .icon { +.doc .admonitionblock.tip td.icon { background-color: var(--tip-color); color: var(--tip-on-color); } -.doc .admonitionblock.warning .icon { +.doc .admonitionblock.warning td.icon { background-color: var(--warning-color); color: var(--warning-on-color); } -.doc .admonitionblock .icon i { - display: inline-flex; - align-items: center; - height: 100%; -} - -.doc .admonitionblock .icon i::after { +.doc .admonitionblock td.icon i::after { content: attr(title); + font-style: normal; } .doc .imageblock { @@ -516,21 +531,14 @@ padding-left: 0.5rem; } -.doc ul.checklist p > i.fa-check-square-o:first-child, -.doc ul.checklist p > i.fa-square-o:first-child { - display: inline-flex; - justify-content: center; +.doc ul.checklist p > .fa-check-square-o:first-child, +.doc ul.checklist p > .fa-square-o:first-child, +.doc ul.checklist p > :first-child .svga.fa-check-square, +.doc ul.checklist p > :first-child .svga.fa-square { + display: inline-block; width: 1.25rem; } -.doc ul.checklist i.fa-check-square-o::before { - content: "\2713"; -} - -.doc ul.checklist i.fa-square-o::before { - content: "\274f"; -} - .doc .dlist .dlist, .doc .dlist .olist, .doc .dlist .ulist, @@ -825,11 +833,9 @@ margin-right: 0; } -.doc .menuseq i.caret::before { - content: "\203a"; - font-size: 1.1em; - font-weight: var(--body-font-weight-bold); - line-height: calc(1 / 1.1); +.doc .menuseq .caret { + display: inline-block; + width: 0.5em; } .doc a.bare, diff --git a/src/css/header.css b/src/css/header.css index 472750c3..ba9ca1fd 100644 --- a/src/css/header.css +++ b/src/css/header.css @@ -182,10 +182,11 @@ body { padding: 0; } -.navbar-item .icon { +.navbar-item .icon, +.navbar-item .icon .svga { width: 1.25rem; height: 1.25rem; - display: block; + display: inline-block; } .navbar-link { diff --git a/src/css/vars.css b/src/css/vars.css index 560d8578..28d7e77c 100644 --- a/src/css/vars.css +++ b/src/css/vars.css @@ -68,16 +68,15 @@ --toc-border-color: var(--panel-border-color); --toc-line-height: 1.2; /* admonitions */ - --caution-color: #a0439c; + --caution-color: #802392; --caution-on-color: var(--color-white); - --important-color: #d32f2f; --important-color: var(--color-brand-primary); --important-on-color: var(--color-white); - --note-color: #217ee7; + --note-color: #2d7dd2; --note-on-color: var(--color-white); - --tip-color: #41af46; + --tip-color: #43b929; --tip-on-color: var(--color-white); - --warning-color: #e18114; + --warning-color: #f70; --warning-on-color: var(--color-white); /* doc */ --doc-font-color: var(--color-jet-50); diff --git a/src/js/vendor/fontawesome-icon-defs.js b/src/js/vendor/fontawesome-icon-defs.js new file mode 100644 index 00000000..e48c19d1 --- /dev/null +++ b/src/js/vendor/fontawesome-icon-defs.js @@ -0,0 +1,23 @@ +var window +;(function (scope) { + 'use strict' + + var admonitionIcons = { + caution: 'fas fa-fire', + important: 'fas fa-exclamation-circle', + note: 'fas fa-info-circle', + tip: 'fas fa-lightbulb', + warning: 'fas fa-exclamation-triangle', + } + var additionalIcons = [ + 'fas fa-angle-right', + 'far fa-copy', + 'far fa-check-square', + 'fab fa-github', + 'far fa-square', + 'fab fa-twitter', + ] + var iconDefs = (scope.FontAwesomeIconDefs = []) + iconDefs.admonitionIcons = admonitionIcons + iconDefs.includes = Object.values(admonitionIcons).concat(additionalIcons) +})(window || module.exports) diff --git a/src/js/vendor/fontawesome.bundle.js b/src/js/vendor/fontawesome.bundle.js new file mode 100644 index 00000000..3470e7f0 --- /dev/null +++ b/src/js/vendor/fontawesome.bundle.js @@ -0,0 +1,30 @@ +;(function () { + 'use strict' + + // NOTE: v4-shims required to support the output of icon macro generated from AsciiDoc content + require('@fortawesome/fontawesome-free/js/v4-shims') + var fa = require('@fortawesome/fontawesome-svg-core') + + Object.assign(fa.config, { + autoReplaceSvg: 'nest', + keepOriginalSource: false, + observeMutations: false, + replacementClass: 'svga', + }) + + var iconDefs = window.FontAwesomeIconDefs || [] + iconDefs.forEach(function (iconDef) { + fa.library.add(iconDef) + }) + + var admonitionIcons = iconDefs.admonitionIcons || {} + ;[].slice.call(document.querySelectorAll('td.icon > i.fa')).forEach(function (i) { + var name = i.className.substr(8) + i.className = admonitionIcons[name] || 'fas fa-' + name + }) + + fa.dom.i2svg() + + delete window.___FONT_AWESOME___ + delete window.FontAwesomeIconDefs +})() diff --git a/src/partials/footer-scripts.hbs b/src/partials/footer-scripts.hbs index 1e2a62c8..174ec965 100644 --- a/src/partials/footer-scripts.hbs +++ b/src/partials/footer-scripts.hbs @@ -1,4 +1,6 @@ + + {{#with (resolvePage page.relativeSrcPath model=false)}} {{#unless (eq ./asciidoc.attributes.stem undefined)}} diff --git a/src/partials/header-content.hbs b/src/partials/header-content.hbs index 3e6b5aaf..f8868129 100644 --- a/src/partials/header-content.hbs +++ b/src/partials/header-content.hbs @@ -83,12 +83,7 @@ --}} - - - - +