-
Notifications
You must be signed in to change notification settings - Fork 71
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
CASSANDRA-16066: Add Example site-ui components
Added to the 'site-ui' directory an example an Antora site UI implementation. The example was taken from https://gitlab.com/antora/antora-ui-default. It shows the styling components that are needed in the 'site-ui' and how the ui-bundle.zip can be generated. The associated tooling to call Gulp to preview, build and generate the ui-bundle.zip will be added in another commit. patch by Anthony Grasso; reviewed by Mick Semb Wever, Lorina Poland, Melissa Logan, Paul Au for CASSANDRA-16066
- Loading branch information
1 parent
3701033
commit e833a5d
Showing
118 changed files
with
19,170 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,8 @@ | ||
.DS_Store | ||
/.idea/ | ||
.DS_Store | ||
|
||
/site-content/build/ | ||
|
||
/site-ui/build/ | ||
/site-ui/node_modules/ | ||
/site-ui/public/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
{ | ||
"extends": "standard", | ||
"rules": { | ||
"arrow-parens": ["error", "always"], | ||
"comma-dangle": ["error", { | ||
"arrays": "always-multiline", | ||
"objects": "always-multiline", | ||
"imports": "always-multiline", | ||
"exports": "always-multiline" | ||
}], | ||
"max-len": [1, 120, 2], | ||
"spaced-comment": "off" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
{ | ||
"extends": "stylelint-config-standard", | ||
"rules": { | ||
"comment-empty-line-before": null, | ||
"no-descending-specificity": null, | ||
} | ||
} |
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
'use strict' | ||
|
||
const metadata = require('undertaker/lib/helpers/metadata') | ||
const { watch } = require('gulp') | ||
|
||
module.exports = ({ name, desc, opts, call: fn, loop }) => { | ||
if (name) { | ||
const displayName = fn.displayName | ||
if (displayName === '<series>' || displayName === '<parallel>') { | ||
metadata.get(fn).tree.label = `${displayName} ${name}` | ||
} | ||
fn.displayName = name | ||
} | ||
if (loop) { | ||
const delegate = fn | ||
name = delegate.displayName | ||
delegate.displayName = `${name}:loop` | ||
fn = () => watch(loop, { ignoreInitial: false }, delegate) | ||
fn.displayName = name | ||
} | ||
if (desc) fn.description = desc | ||
if (opts) fn.flags = opts | ||
return fn | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
'use strict' | ||
|
||
module.exports = (...tasks) => { | ||
const seed = {} | ||
if (tasks.length) { | ||
if (tasks.lastIndexOf(tasks[0]) > 0) { | ||
const task1 = tasks.shift() | ||
seed.default = Object.assign(task1.bind(null), { description: `=> ${task1.displayName}`, displayName: 'default' }) | ||
} | ||
return tasks.reduce((acc, it) => (acc[it.displayName || it.name] = it) && acc, seed) | ||
} else { | ||
return seed | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
'use strict' | ||
|
||
const log = require('fancy-log') | ||
const PluginError = require('plugin-error') | ||
const prettierEslint = require('prettier-eslint') | ||
const { Transform } = require('stream') | ||
const map = (transform) => new Transform({ objectMode: true, transform }) | ||
|
||
module.exports = () => { | ||
const report = { changed: 0, unchanged: 0 } | ||
return map(format).on('finish', () => { | ||
if (report.changed > 0) { | ||
const changed = 'formatted ' | ||
.concat(report.changed) | ||
.concat(' file') | ||
.concat(report.changed === 1 ? '' : 's') | ||
const unchanged = 'left ' | ||
.concat(report.unchanged) | ||
.concat(' file') | ||
.concat(report.unchanged === 1 ? '' : 's') | ||
.concat(' unchanged') | ||
log(`prettier-eslint: ${changed}; ${unchanged}`) | ||
} else { | ||
log(`prettier-eslint: left ${report.unchanged} file${report.unchanged === 1 ? '' : 's'} unchanged`) | ||
} | ||
}) | ||
|
||
function format (file, enc, next) { | ||
if (file.isNull()) return next() | ||
if (file.isStream()) return next(new PluginError('gulp-prettier-eslint', 'Streaming not supported')) | ||
|
||
const input = file.contents.toString() | ||
const output = prettierEslint({ text: input, filePath: file.path }) | ||
|
||
if (input === output) { | ||
report.unchanged += 1 | ||
} else { | ||
report.changed += 1 | ||
file.contents = Buffer.from(output) | ||
} | ||
|
||
next(null, file) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,214 @@ | ||
'use strict' | ||
|
||
const asciidoctor = require('asciidoctor.js')() | ||
const fs = require('fs-extra') | ||
const handlebars = require('handlebars') | ||
const merge = require('merge-stream') | ||
const ospath = require('path') | ||
const path = ospath.posix | ||
const requireFromString = require('require-from-string') | ||
const { Transform } = require('stream') | ||
const map = (transform = () => {}, flush = undefined) => new Transform({ objectMode: true, transform, flush }) | ||
const vfs = require('vinyl-fs') | ||
const yaml = require('js-yaml') | ||
|
||
const ASCIIDOC_ATTRIBUTES = { experimental: '', icons: 'font', sectanchors: '', 'source-highlighter': 'highlight.js' } | ||
|
||
module.exports = (src, previewSrc, previewDest, sink = () => map()) => (done) => | ||
Promise.all([ | ||
loadSampleUiModel(previewSrc), | ||
toPromise( | ||
merge(compileLayouts(src), registerPartials(src), registerHelpers(src), copyImages(previewSrc, previewDest)) | ||
), | ||
]) | ||
.then(([baseUiModel, { layouts }]) => [{ ...baseUiModel, env: process.env }, layouts]) | ||
.then(([baseUiModel, layouts]) => | ||
vfs | ||
.src('**/*.adoc', { base: previewSrc, cwd: previewSrc }) | ||
.pipe( | ||
map((file, enc, next) => { | ||
const siteRootPath = path.relative(ospath.dirname(file.path), ospath.resolve(previewSrc)) | ||
const uiModel = { ...baseUiModel } | ||
uiModel.siteRootPath = siteRootPath | ||
uiModel.siteRootUrl = path.join(siteRootPath, 'index.html') | ||
uiModel.uiRootPath = path.join(siteRootPath, '_') | ||
if (file.stem === '404') { | ||
uiModel.page = { layout: '404', title: 'Page Not Found' } | ||
} else { | ||
const pageModel = (uiModel.page = { ...uiModel.page }) | ||
const doc = asciidoctor.load(file.contents, { safe: 'safe', attributes: ASCIIDOC_ATTRIBUTES }) | ||
const attributes = doc.getAttributes() | ||
pageModel.layout = doc.getAttribute('page-layout', 'default') | ||
pageModel.title = doc.getDocumentTitle() | ||
pageModel.url = '/' + file.relative.slice(0, -5) + '.html' | ||
if (file.stem === 'tutorials') pageModel.tutorials = true | ||
const componentName = doc.getAttribute('page-component-name', pageModel.src.component) | ||
const versionString = doc.getAttribute( | ||
'page-version', | ||
doc.hasAttribute('page-component-name') ? undefined : pageModel.src.version | ||
) | ||
let component | ||
let componentVersion | ||
if (componentName) { | ||
component = pageModel.component = uiModel.site.components[componentName] | ||
componentVersion = pageModel.componentVersion = versionString | ||
? component.versions.find(({ version }) => version === versionString) | ||
: component.latest | ||
} else { | ||
component = pageModel.component = Object.values(uiModel.site.components)[0] | ||
componentVersion = pageModel.componentVersion = component.latest | ||
} | ||
pageModel.module = 'ROOT' | ||
pageModel.relativeSrcPath = file.relative | ||
pageModel.version = componentVersion.version | ||
pageModel.displayVersion = componentVersion.displayVersion | ||
pageModel.editUrl = pageModel.origin.editUrlPattern.replace('%s', file.relative) | ||
pageModel.navigation = componentVersion.navigation || [] | ||
pageModel.breadcrumbs = findNavPath(pageModel.url, pageModel.navigation) | ||
if (pageModel.component.versions.length > 1) { | ||
pageModel.versions = pageModel.component.versions.map(({ version, displayVersion, url }, idx, arr) => { | ||
const pageVersion = { version, displayVersion: displayVersion || version, url } | ||
if (version === component.latest.version) pageVersion.latest = true | ||
if (idx === arr.length - 1) { | ||
delete pageVersion.url | ||
pageVersion.missing = true | ||
} | ||
return pageVersion | ||
}) | ||
} | ||
pageModel.attributes = Object.entries({ ...attributes, ...componentVersion.asciidoc.attributes }) | ||
.filter(([name, val]) => name.startsWith('page-')) | ||
.reduce((accum, [name, val]) => ({ ...accum, [name.substr(5)]: val }), {}) | ||
pageModel.contents = Buffer.from(doc.convert()) | ||
} | ||
file.extname = '.html' | ||
try { | ||
file.contents = Buffer.from(layouts.get(uiModel.page.layout)(uiModel)) | ||
next(null, file) | ||
} catch (e) { | ||
next(transformHandlebarsError(e, uiModel.page.layout)) | ||
} | ||
}) | ||
) | ||
.pipe(vfs.dest(previewDest)) | ||
.on('error', done) | ||
.pipe(sink()) | ||
) | ||
|
||
function loadSampleUiModel (src) { | ||
return fs.readFile(ospath.join(src, 'ui-model.yml'), 'utf8').then((contents) => { | ||
const uiModel = yaml.safeLoad(contents) | ||
uiModel.env = process.env | ||
Object.entries(uiModel.site.components).forEach(([name, component]) => { | ||
component.name = name | ||
if (!component.versions) component.versions = [(component.latest = { url: '#' })] | ||
component.versions.forEach((version) => { | ||
Object.defineProperty(version, 'name', { value: component.name, enumerable: true }) | ||
if (!('displayVersion' in version)) version.displayVersion = version.version | ||
if (!('asciidoc' in version)) version.asciidoc = { attributes: {} } | ||
}) | ||
Object.defineProperties(component, { | ||
asciidoc: { | ||
get () { | ||
return this.latest.asciidoc | ||
}, | ||
}, | ||
title: { | ||
get () { | ||
return this.latest.title | ||
}, | ||
}, | ||
url: { | ||
get () { | ||
return this.latest.url | ||
}, | ||
}, | ||
}) | ||
}) | ||
return uiModel | ||
}) | ||
} | ||
|
||
function registerPartials (src) { | ||
return vfs.src('partials/*.hbs', { base: src, cwd: src }).pipe( | ||
map((file, enc, next) => { | ||
handlebars.registerPartial(file.stem, file.contents.toString()) | ||
next() | ||
}) | ||
) | ||
} | ||
|
||
function registerHelpers (src) { | ||
handlebars.registerHelper('relativize', relativize) | ||
handlebars.registerHelper('resolvePage', resolvePage) | ||
handlebars.registerHelper('resolvePageURL', resolvePageURL) | ||
return vfs.src('helpers/*.js', { base: src, cwd: src }).pipe( | ||
map((file, enc, next) => { | ||
handlebars.registerHelper(file.stem, requireFromString(file.contents.toString())) | ||
next() | ||
}) | ||
) | ||
} | ||
|
||
function compileLayouts (src) { | ||
const layouts = new Map() | ||
return vfs.src('layouts/*.hbs', { base: src, cwd: src }).pipe( | ||
map( | ||
(file, enc, next) => { | ||
const srcName = path.join(src, file.relative) | ||
layouts.set(file.stem, handlebars.compile(file.contents.toString(), { preventIndent: true, srcName })) | ||
next() | ||
}, | ||
function (done) { | ||
this.push({ layouts }) | ||
done() | ||
} | ||
) | ||
) | ||
} | ||
|
||
function copyImages (src, dest) { | ||
return vfs.src('**/*.{png,svg}', { base: src, cwd: src }).pipe(vfs.dest(dest)) | ||
} | ||
|
||
function findNavPath (currentUrl, node = [], current_path = [], root = true) { | ||
for (const item of node) { | ||
const { url, items } = item | ||
if (url === currentUrl) { | ||
return current_path.concat(item) | ||
} else if (items) { | ||
const activePath = findNavPath(currentUrl, items, current_path.concat(item), false) | ||
if (activePath) return activePath | ||
} | ||
} | ||
if (root) return [] | ||
} | ||
|
||
function relativize (url) { | ||
return url ? (url.charAt() === '#' ? url : url.slice(1)) : '#' | ||
} | ||
|
||
function resolvePage (spec, context = {}) { | ||
if (spec) return { pub: { url: resolvePageURL(spec) } } | ||
} | ||
|
||
function resolvePageURL (spec, context = {}) { | ||
if (spec) return '/' + (spec = spec.split(':').pop()).slice(0, spec.lastIndexOf('.')) + '.html' | ||
} | ||
|
||
function transformHandlebarsError ({ message, stack }, layout) { | ||
const m = stack.match(/^ *at Object\.ret \[as (.+?)\]/m) | ||
const templatePath = `src/${m ? 'partials/' + m[1] : 'layouts/' + layout}.hbs` | ||
const err = new Error(`${message}${~message.indexOf('\n') ? '\n^ ' : ' '}in UI template ${templatePath}`) | ||
err.stack = [err.toString()].concat(stack.substr(message.length + 8)).join('\n') | ||
return err | ||
} | ||
|
||
function toPromise (stream) { | ||
return new Promise((resolve, reject, data = {}) => | ||
stream | ||
.on('error', reject) | ||
.on('data', (chunk) => chunk.constructor === Object && Object.assign(data, chunk)) | ||
.on('finish', () => resolve(data)) | ||
) | ||
} |
Oops, something went wrong.