From 50404ca409ef401577eadb3474877401ae92823b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maximilian=20Kr=C3=B6g?= Date: Sun, 19 Jul 2020 17:21:32 +0200 Subject: [PATCH 1/2] Add number of occurence to tags It can be a bit frustrating to click on a tag only to realise it was the only example with that tag. --- examples/index.js | 6 +- examples/templates/example.html | 2 +- examples/webpack/example-builder.js | 121 ++++++++++++++++++++-------- 3 files changed, 91 insertions(+), 38 deletions(-) diff --git a/examples/index.js b/examples/index.js index f6d2c2efde..1c0d754434 100644 --- a/examples/index.js +++ b/examples/index.js @@ -43,15 +43,15 @@ } }; words.forEach(function (word) { - const dict = info.index[word]; + const dict = info.wordIndex[word]; if (dict) { updateScores(dict, word); } else { const r = new RegExp(word); // eslint-disable-next-line prefer-const - for (let idx in info.index) { + for (let idx in info.wordIndex) { if (r.test(idx)) { - updateScores(info.index[idx], word); + updateScores(info.wordIndex[idx], word); } } } diff --git a/examples/templates/example.html b/examples/templates/example.html index 29c3e7463d..4acd5e0e47 100644 --- a/examples/templates/example.html +++ b/examples/templates/example.html @@ -113,7 +113,7 @@

{{#each tags}} - {{.}} + {{ ./tag }} ({{ ./amount }}) {{/each}}

{{{ contents }}} diff --git a/examples/webpack/example-builder.js b/examples/webpack/example-builder.js index 39a94acec7..301cce23c5 100644 --- a/examples/webpack/example-builder.js +++ b/examples/webpack/example-builder.js @@ -30,6 +30,43 @@ handlebars.registerHelper('indent', (text, options) => { .join('\n'); }); +/** + * Returns the object with the keys inserted in alphabetic order. + * When exporting with `JSON.stringify(obj)` the keys are sorted. + * @param {Object} obj Any object + * @return {Object} New object + */ +function sortObjectByKey(obj) { + return Object.keys(obj) + .sort() // sort twice to get predictable, case insensitve order + .sort((a, b) => a.localeCompare(b, 'en', {sensitivity: 'base'})) + .reduce((idx, tag) => { + idx[tag] = obj[tag]; + return idx; + }, {}); +} + +/** + * Create an index of tags belonging to examples + * @param {Array} exampleData Array of example data objects. + * @return {Object} Word index. + */ +function createTagIndex(exampleData) { + const index = {}; + exampleData.forEach((data, i) => { + data.tags.forEach((tag) => { + tag = tag.toLowerCase(); + let tagIndex = index[tag]; + if (!tagIndex) { + tagIndex = []; + index[tag] = tagIndex; + } + tagIndex.push(i); + }); + }); + return index; +} + /** * Create an inverted index of keywords from examples. Property names are * lowercased words. Property values are objects mapping example index to word @@ -140,59 +177,68 @@ class ExampleBuilder { .chunks.filter((chunk) => chunk.names[0] !== this.common); const exampleData = []; - const uniqueTags = new Set(); - const promises = chunks.map(async (chunk) => { - const [assets, data] = await this.render(compiler.context, chunk); - - // collect tags for main page... TODO: implement index tag links - data.tags.forEach((tag) => uniqueTags.add(tag)); - - exampleData.push({ + await Promise.all( + chunks.map(async (chunk) => { + const data = await this.readHtml(compiler.context, chunk); + exampleData.push(data); + }) + ); + const examples = exampleData.map((data) => { + return { link: data.filename, example: data.filename, title: data.title, shortdesc: data.shortdesc, tags: data.tags, - }); - - for (const file in assets) { - compilation.assets[file] = new RawSource(assets[file]); - } + }; }); - await Promise.all(promises); - - exampleData.sort((a, b) => + examples.sort((a, b) => a.title.localeCompare(b.title, 'en', {sensitivity: 'base'}) ); + const tagIndex = createTagIndex(examples); const info = { - examples: exampleData, - index: createWordIndex(exampleData), - tags: Array.from(uniqueTags) - .sort() // sort twice to get predictable, case insensitve order - .sort((a, b) => a.localeCompare(b, 'en', {sensitivity: 'base'})), + examples: examples, + // Tags for main page... TODO: implement index tag links + // tagIndex: sortObjectByKey(tagIndex), + wordIndex: sortObjectByKey(createWordIndex(examples)), }; + exampleData.forEach((data) => { + data.tags = data.tags.map((tag) => { + return { + tag: tag, + amount: tagIndex[tag.toLowerCase()].length, + }; + }); + }); + await Promise.all( + exampleData.map(async (data) => { + const assets = await this.render(data, data.chunk); + for (const file in assets) { + compilation.assets[file] = new RawSource(assets[file]); + } + }) + ); const indexSource = `const info = ${JSON.stringify(info)};`; compilation.assets['examples-info.js'] = new RawSource(indexSource); }); } - async render(dir, chunk) { + async readHtml(dir, chunk) { const name = chunk.names[0]; - - const assets = {}; - const readOptions = {encoding: 'utf8'}; - const htmlName = `${name}.html`; const htmlPath = path.join(dir, htmlName); - const htmlSource = await readFile(htmlPath, readOptions); + const htmlSource = await readFile(htmlPath, {encoding: 'utf8'}); const {attributes, body} = frontMatter(htmlSource); + assert(!!attributes.layout, `missing layout in ${htmlPath}`); const data = Object.assign(attributes, {contents: body}); data.olVersion = pkg.version; data.filename = htmlName; + data.dir = dir; + data.chunk = chunk; // process tags if (data.tags) { @@ -200,6 +246,14 @@ class ExampleBuilder { } else { data.tags = []; } + return data; + } + + async render(data, chunk) { + const name = chunk.names[0]; + + const assets = {}; + const readOptions = {encoding: 'utf8'}; // add in script tag const jsName = `${name}.js`; @@ -234,7 +288,7 @@ class ExampleBuilder { // check for worker js const workerName = `${name}.worker.js`; - const workerPath = path.join(dir, workerName); + const workerPath = path.join(data.dir, workerName); let workerSource; try { workerSource = await readFile(workerPath, readOptions); @@ -280,7 +334,7 @@ class ExampleBuilder { // check for example css const cssName = `${name}.css`; - const cssPath = path.join(dir, cssName); + const cssPath = path.join(data.dir, cssName); let cssSource; try { cssSource = await readFile(cssPath, readOptions); @@ -321,7 +375,7 @@ class ExampleBuilder { 'Invalid value for resource: ' + resource + ' is not .js or .css: ' + - htmlName + data.filename ); } } @@ -334,12 +388,11 @@ class ExampleBuilder { : ''; } - assert(!!attributes.layout, `missing layout in ${htmlPath}`); - const templatePath = path.join(this.templates, attributes.layout); + const templatePath = path.join(this.templates, data.layout); const templateSource = await readFile(templatePath, readOptions); - assets[htmlName] = handlebars.compile(templateSource)(data); - return [assets, data]; + assets[data.filename] = handlebars.compile(templateSource)(data); + return assets; } } From 9093478016717f87832fa74244a7656930b18b54 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maximilian=20Kr=C3=B6g?= Date: Sat, 25 Jul 2020 10:20:03 +0200 Subject: [PATCH 2/2] Add modal to tag count with direct links to other examples --- examples/resources/layout.css | 29 +++++++++++++++++++++ examples/templates/example.html | 39 ++++++++++++++++++++++++++++- examples/webpack/example-builder.js | 17 ++++++++++++- 3 files changed, 83 insertions(+), 2 deletions(-) diff --git a/examples/resources/layout.css b/examples/resources/layout.css index 4913023f77..e81ce5c2a8 100644 --- a/examples/resources/layout.css +++ b/examples/resources/layout.css @@ -64,6 +64,35 @@ a:hover, a:focus, footer a:hover, footer a:focus { margin-top: 0; } +.badge-group { + display: inline-block; +} +.badge-group > .badge:not(:last-child) { + border-top-right-radius: 0; + border-bottom-right-radius: 0; +} +.badge-group > .badge:not(:first-child) { + border-top-left-radius: 0; + border-bottom-left-radius: 0; +} +.tag-modal-toggle { + cursor: pointer; +} +.modal-tag-example .modal-body { + padding: 0; +} +.modal-tag-example .list-group-item:focus, +.modal-tag-example .list-group-item:hover, +.modal-tag-example .list-group-item:active { + background-color: rgba(31, 107, 117, .6875); + border-color: #1F6B75; + color: white; +} +.modal-tag-example .list-group-item.active { + background-color: #1F6B75; + color: white; +} + #docs { margin-top: 1em; } diff --git a/examples/templates/example.html b/examples/templates/example.html index 4acd5e0e47..5c25af781f 100644 --- a/examples/templates/example.html +++ b/examples/templates/example.html @@ -113,9 +113,36 @@

{{#each tags}} - {{ ./tag }} ({{ ./amount }}) + + {{ ./tag }}{{ ./examples.length }} + {{/each}}

+ {{{ contents }}}
@@ -186,6 +213,16 @@ {{{ js.tag }}} +