Added multi-tagging (#159)
Updated all scripts to deal with multiple tags, the only thing missing is to actually multi-tag all snippets retroactively.
This commit is contained in:
1
advanced.svg
Normal file
1
advanced.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="78" height="20"><linearGradient id="b" x2="0" y2="100%"><stop offset="0" stop-color="#bbb" stop-opacity=".1"/><stop offset="1" stop-opacity=".1"/></linearGradient><clipPath id="a"><rect height="20" rx="3" fill="#fff" width="64"/></clipPath><g clip-path="url(#a)"><path fill="#555" d="M0 0h65v20H0z"/></g><g fill="#fff" text-anchor="middle" font-family="DejaVu Sans,Verdana,Geneva,sans-serif" font-size="110"><text x="325" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)" textLength="530">advanced</text><text x="325" y="140" transform="scale(.1)" textLength="530">advanced</text></g> </svg>
|
||||
|
After Width: | Height: | Size: 695 B |
@ -131,6 +131,8 @@ $_drawer-right: false;
|
||||
|
||||
@import 'navigation';
|
||||
|
||||
$mark-back-color: #424242;
|
||||
$mark-font-size: 0.5em;
|
||||
|
||||
$toast-back-color: #212121;
|
||||
|
||||
@ -163,6 +165,12 @@ $_include-collapse: false;
|
||||
transition: opacity 0.3s ease-in-out;
|
||||
}
|
||||
|
||||
mark {
|
||||
position: relative;
|
||||
top: -0.25rem;
|
||||
left: 0.25rem;
|
||||
}
|
||||
|
||||
/*
|
||||
Custom elements for contextual background elements, toasts and tooltips.
|
||||
*/
|
||||
|
||||
@ -73,7 +73,11 @@ try {
|
||||
.readFileSync('tag_database', 'utf8')
|
||||
.split('\n')
|
||||
.slice(0, -1)
|
||||
.map(v => v.split(':').slice(0, 2))
|
||||
.map(v => {
|
||||
let data = v.split(':').slice(0, 2);
|
||||
data[1] = data[1].split(',').map(t => t.trim());
|
||||
return data;
|
||||
})
|
||||
);
|
||||
} catch (err) {
|
||||
console.log(`${chalk.red('ERROR!')} During tag database loading: ${err}`);
|
||||
@ -85,7 +89,7 @@ try {
|
||||
const tags = [
|
||||
...new Set(
|
||||
Object.entries(tagDbData)
|
||||
.map(t => t[1])
|
||||
.map(t => t[1][0])
|
||||
.filter(v => v)
|
||||
.sort((a, b) => a.localeCompare(b))
|
||||
)
|
||||
@ -101,7 +105,7 @@ try {
|
||||
|
||||
if (capitalizedTag === 'Uncategorized') {
|
||||
uncategorizedOutput += `### _${capitalizedTag}_\n\n<details>\n<summary>View contents</summary>\n\n`;
|
||||
for (const taggedSnippet of Object.entries(tagDbData).filter(v => v[1] === tag)) {
|
||||
for (const taggedSnippet of Object.entries(tagDbData).filter(v => v[1][0] === tag)) {
|
||||
uncategorizedOutput += `* [\`${taggedSnippet[0]}\`](#${taggedSnippet[0].toLowerCase()})\n`;
|
||||
}
|
||||
uncategorizedOutput += '\n</details>\n\n';
|
||||
@ -109,7 +113,7 @@ try {
|
||||
output += `### ${
|
||||
EMOJIS[tag] || ''
|
||||
} ${capitalizedTag}\n\n<details>\n<summary>View contents</summary>\n\n`;
|
||||
for (const taggedSnippet of Object.entries(tagDbData).filter(v => v[1] === tag)) {
|
||||
for (const taggedSnippet of Object.entries(tagDbData).filter(v => v[1][0] === tag)) {
|
||||
output += `* [\`${taggedSnippet[0]}\`](#${taggedSnippet[0].toLowerCase()})\n`;
|
||||
}
|
||||
output += '\n</details>\n\n';
|
||||
@ -122,17 +126,23 @@ try {
|
||||
// Loop over tags and snippets to create the list of snippets
|
||||
for (const tag of tags) {
|
||||
const capitalizedTag = capitalize(tag, true);
|
||||
|
||||
// 
|
||||
if (capitalizedTag == 'Uncategorized') {
|
||||
uncategorizedOutput += `---\n ## _${capitalizedTag}_\n`;
|
||||
for (const taggedSnippet of Object.entries(tagDbData).filter(v => v[1] === tag)) {
|
||||
for (const taggedSnippet of Object.entries(tagDbData).filter(v => v[1][0] === tag)) {
|
||||
uncategorizedOutput += `\n${snippets[taggedSnippet[0] + '.md'] +
|
||||
'\n<br>[⬆ back to top](#table-of-contents)\n\n'}`;
|
||||
}
|
||||
} else {
|
||||
output += `---\n ## ${EMOJIS[tag] || ''} ${capitalizedTag}\n`;
|
||||
for (const taggedSnippet of Object.entries(tagDbData).filter(v => v[1] === tag)) {
|
||||
for (const taggedSnippet of Object.entries(tagDbData).filter(v => v[1][0] === tag)) {
|
||||
let data = snippets[taggedSnippet[0] + '.md'];
|
||||
// Add advanced tag
|
||||
if(taggedSnippet[1].includes('advanced')){
|
||||
data = data.split(/\r?\n/);
|
||||
data[0] = data[0] +' ';
|
||||
data = data.join('\n');
|
||||
}
|
||||
data =
|
||||
data.slice(0, data.lastIndexOf('```js')) +
|
||||
'<details>\n<summary>Examples</summary>\n\n' +
|
||||
|
||||
@ -50,10 +50,14 @@ try {
|
||||
.readFileSync('tag_database', 'utf8')
|
||||
.split('\n')
|
||||
.slice(0, -1)
|
||||
.map(v => v.split(':').slice(0, 2))
|
||||
.map(v => {
|
||||
let data = v.split(':').slice(0, 2);
|
||||
data[1] = data[1].split(',').map(t => t.trim());
|
||||
return data;
|
||||
})
|
||||
);
|
||||
tagDbStats = Object.entries(tagDbData)
|
||||
.sort((a, b) => a[1].localeCompare(b[1]))
|
||||
.sort((a, b) => a[1][0].localeCompare(b[1][0]))
|
||||
.reduce((acc, val) => {
|
||||
acc.hasOwnProperty(val[1]) ? acc[val[1]]++ : (acc[val[1]] = 1);
|
||||
return acc;
|
||||
@ -68,9 +72,9 @@ try {
|
||||
for (let snippet of Object.entries(snippets))
|
||||
if (
|
||||
tagDbData.hasOwnProperty(snippet[0].slice(0, -3)) &&
|
||||
tagDbData[snippet[0].slice(0, -3)].trim()
|
||||
tagDbData[snippet[0].slice(0, -3)].join(',').trim()
|
||||
)
|
||||
output += `${snippet[0].slice(0, -3)}:${tagDbData[snippet[0].slice(0, -3)].trim()}\n`;
|
||||
output += `${snippet[0].slice(0, -3)}:${tagDbData[snippet[0].slice(0, -3)].join(',').trim()}\n`;
|
||||
else {
|
||||
output += `${snippet[0].slice(0, -3)}:uncategorized\n`;
|
||||
missingTags++;
|
||||
|
||||
@ -61,7 +61,7 @@ const objectFromPairs = arr => arr.reduce((a, v) => ((a[v[0]] = v[1]), a), {});
|
||||
const capitalize = (str, lowerRest = false) =>
|
||||
str.slice(0, 1).toUpperCase() + (lowerRest ? str.slice(1).toLowerCase() : str.slice(1));
|
||||
// Start the timer of the script
|
||||
console.time('Builder');
|
||||
console.time('Webber');
|
||||
// Synchronously read all snippets and sort them as necessary (case-insensitive)
|
||||
try {
|
||||
let snippetFilenames = fs.readdirSync(snippetsPath);
|
||||
@ -96,7 +96,11 @@ try {
|
||||
.readFileSync('tag_database', 'utf8')
|
||||
.split('\n')
|
||||
.slice(0, -1)
|
||||
.map(v => v.split(':').slice(0, 2))
|
||||
.map(v => {
|
||||
let data = v.split(':').slice(0, 2);
|
||||
data[1] = data[1].split(',').map(t => t.trim());
|
||||
return data;
|
||||
})
|
||||
);
|
||||
} catch (err) {
|
||||
// Handle errors (hopefully not!)
|
||||
@ -109,7 +113,7 @@ try {
|
||||
output += `${startPart + '\n'}`;
|
||||
let uncategorizedOutput = '';
|
||||
// Loop over tags and snippets to create the table of contents
|
||||
for (let tag of [...new Set(Object.entries(tagDbData).map(t => t[1]))]
|
||||
for (let tag of [...new Set(Object.entries(tagDbData).map(t => t[1][0]))]
|
||||
.filter(v => v)
|
||||
.sort((a, b) => a.localeCompare(b))) {
|
||||
if (capitalize(tag, true) == 'Uncategorized') {
|
||||
@ -120,12 +124,12 @@ try {
|
||||
.replace(/<p>/g, '')
|
||||
.replace(/<\/p>/g, '') +
|
||||
`</h3>`;
|
||||
for (let taggedSnippet of Object.entries(tagDbData).filter(v => v[1] === tag))
|
||||
for (let taggedSnippet of Object.entries(tagDbData).filter(v => v[1][0] === tag))
|
||||
uncategorizedOutput += md
|
||||
.render(`[${taggedSnippet[0]}](#${taggedSnippet[0].toLowerCase()})\n`)
|
||||
.replace(/<p>/g, '')
|
||||
.replace(/<\/p>/g, '')
|
||||
.replace(/<a/g, '<a class="sublink-1"');
|
||||
.replace(/<a/g, `<a class="sublink-1" tags="${taggedSnippet[1].join(',')}"`);
|
||||
uncategorizedOutput += '\n';
|
||||
} else {
|
||||
output +=
|
||||
@ -135,12 +139,12 @@ try {
|
||||
.replace(/<p>/g, '')
|
||||
.replace(/<\/p>/g, '') +
|
||||
`</h3>`;
|
||||
for (let taggedSnippet of Object.entries(tagDbData).filter(v => v[1] === tag))
|
||||
for (let taggedSnippet of Object.entries(tagDbData).filter(v => v[1][0] === tag))
|
||||
output += md
|
||||
.render(`[${taggedSnippet[0]}](#${taggedSnippet[0].toLowerCase()})\n`)
|
||||
.replace(/<p>/g, '')
|
||||
.replace(/<\/p>/g, '')
|
||||
.replace(/<a/g, '<a class="sublink-1"');
|
||||
.replace(/<a/g, `<a class="sublink-1" tags="${taggedSnippet[1].join(',')}"`);
|
||||
output += '\n';
|
||||
}
|
||||
}
|
||||
@ -149,19 +153,20 @@ try {
|
||||
output += `<a id="top"> </a>`;
|
||||
uncategorizedOutput = '';
|
||||
// Loop over tags and snippets to create the list of snippets
|
||||
for (let tag of [...new Set(Object.entries(tagDbData).map(t => t[1]))]
|
||||
for (let tag of [...new Set(Object.entries(tagDbData).map(t => t[1][0]))]
|
||||
.filter(v => v)
|
||||
.sort((a, b) => a.localeCompare(b))) {
|
||||
if (capitalize(tag, true) == 'Uncategorized') {
|
||||
uncategorizedOutput += md
|
||||
.render(`## ${capitalize(tag, true)}\n`)
|
||||
.replace(/<h2>/g, '<h2 style="text-align:center;">');
|
||||
for (let taggedSnippet of Object.entries(tagDbData).filter(v => v[1] === tag))
|
||||
for (let taggedSnippet of Object.entries(tagDbData).filter(v => v[1][0] === tag))
|
||||
uncategorizedOutput +=
|
||||
'<div class="card fluid">' +
|
||||
md
|
||||
.render(`\n${snippets[taggedSnippet[0] + '.md']}`)
|
||||
.replace(/<h3/g, `<h3 id="${taggedSnippet[0].toLowerCase()}" class="section double-padded"`)
|
||||
.replace(/<\/h3>/g, `${taggedSnippet[1].includes('advanced')?'<mark class="tag">advanced</mark>':''}</h3>`)
|
||||
.replace(/<pre><code class="language-js">([^\0]*?)<\/code><\/pre>/gm, (match, p1) => `<pre class="language-js">${Prism.highlight(unescapeHTML(p1), Prism.languages.javascript)}</pre>`)
|
||||
.replace(/<\/pre>\s+<pre/g, '</pre><label class="collapse">Show examples</label><pre') +
|
||||
'<button class="primary clipboard-copy"><img src="clipboard.svg" alt="clipboard"> Copy to clipboard</button>' +
|
||||
@ -170,12 +175,13 @@ try {
|
||||
output += md
|
||||
.render(`## ${capitalize(tag, true)}\n`)
|
||||
.replace(/<h2>/g, '<h2 style="text-align:center;">');
|
||||
for (let taggedSnippet of Object.entries(tagDbData).filter(v => v[1] === tag))
|
||||
for (let taggedSnippet of Object.entries(tagDbData).filter(v => v[1][0] === tag))
|
||||
output +=
|
||||
'<div class="card fluid">' +
|
||||
md
|
||||
.render(`\n${snippets[taggedSnippet[0] + '.md']}`)
|
||||
.replace(/<h3/g, `<h3 id="${taggedSnippet[0].toLowerCase()}" class="section double-padded"`)
|
||||
.replace(/<\/h3>/g, `${taggedSnippet[1].includes('advanced')?'<mark class="tag">advanced</mark>':''}</h3>`)
|
||||
.replace(/<\/h3>/g, '</h3><div class="section double-padded">')
|
||||
.replace(/<pre><code class="language-js">([^\0]*?)<\/code><\/pre>/gm, (match, p1) => `<pre class="language-js">${Prism.highlight(unescapeHTML(p1), Prism.languages.javascript)}</pre>`)
|
||||
.replace(/<\/pre>\s+<pre/g, '</pre><label class="collapse">Show examples</label><pre') +
|
||||
@ -247,4 +253,4 @@ try {
|
||||
// Log a success message
|
||||
console.log(`${chalk.green('SUCCESS!')} index.html file generated!`);
|
||||
// Log the time taken
|
||||
console.timeEnd('Builder');
|
||||
console.timeEnd('Webber');
|
||||
|
||||
@ -18,7 +18,7 @@
|
||||
|
||||
⚠️ **WARNING:** Snippets are not production ready.
|
||||
|
||||
You can find a package with all the snippets on [npm](https://www.npmjs.com/package/30-seconds-of-code).
|
||||
You can find a package with all the snippets on [npm](https://www.npmjs.com/package/30-seconds-of-code).
|
||||
|
||||
```
|
||||
npm install 30-seconds-of-code
|
||||
|
||||
@ -14,13 +14,17 @@
|
||||
<link rel="icon" type="image/png" href="favicon.png">
|
||||
<script>
|
||||
const search = (node) => {
|
||||
let matchingTags = [];
|
||||
Array.from(node.parentElement.parentElement.getElementsByTagName('a')).forEach(x => {
|
||||
x.style.display = x.getAttribute("href").toUpperCase().indexOf(node.value.toUpperCase()) + 1 ? '' : 'none'
|
||||
let data = [x.innerText.toLowerCase(), ...x.getAttribute('tags').split(',')].map(v => !!(v.indexOf(node.value.toLowerCase()) + 1));
|
||||
if(data.includes(true)){
|
||||
x.style.display = '';
|
||||
matchingTags.push(x.getAttribute('tags').split(',')[0]);
|
||||
}
|
||||
else x.style.display = 'none';
|
||||
});
|
||||
Array.from( node.parentElement.parentElement.children )
|
||||
.filter( x => !( x.tagName == 'A' && x.style.display == 'none' ) )
|
||||
.forEach( ( element, index, source) => {
|
||||
element.style.display = (element.tagName == 'H3' && index + 1 == source.length ? 'none' : element.tagName == 'H3' && source[index + 1].tagName == 'H3' ? 'none' : '')
|
||||
Array.from(node.parentElement.parentElement.getElementsByTagName('h3')).forEach(x => {
|
||||
x.style.display = matchingTags.includes(x.innerText.toLowerCase()) ? '' : 'none';
|
||||
})
|
||||
}
|
||||
function loader() {
|
||||
|
||||
Reference in New Issue
Block a user