Import gatsby from starter
This commit is contained in:
@ -9,7 +9,6 @@ before_install:
|
||||
- npm install -g prettier
|
||||
- npm install -g eslint
|
||||
script:
|
||||
- npm run tagger
|
||||
- npm run linter
|
||||
- npm run packager
|
||||
- npm run tester
|
||||
|
||||
4
_headers
Normal file
4
_headers
Normal file
@ -0,0 +1,4 @@
|
||||
[[headers]]
|
||||
for = "/static/*"
|
||||
[headers.values]
|
||||
Cache-Control = "public, max-age=360000"
|
||||
16
config.js
Normal file
16
config.js
Normal file
@ -0,0 +1,16 @@
|
||||
module.exports = {
|
||||
// Project metadata
|
||||
name: `30 seconds starter`,
|
||||
description: `Kick off your next, great 30 seconds project with this starter.`,
|
||||
shortName: `30s`,
|
||||
repositoryUrl: `https://github.com/30-seconds/30-seconds-starter`,
|
||||
// Path information
|
||||
snippetPath: `snippets`,
|
||||
snippetArchivePath: `snippets_archive`,
|
||||
snippetDataPath: `snippet_data`,
|
||||
assetPath: `assets`,
|
||||
pagePath: `src/docs/pages`,
|
||||
staticPartsPath: `src/static-parts`,
|
||||
// General information
|
||||
language: `js`,
|
||||
};
|
||||
8
gatsby-browser.js
Normal file
8
gatsby-browser.js
Normal file
@ -0,0 +1,8 @@
|
||||
/**
|
||||
* Implement Gatsby's Browser APIs in this file.
|
||||
*
|
||||
* See: https://www.gatsbyjs.org/docs/browser-apis/
|
||||
*/
|
||||
|
||||
// You can delete this file if you're not using it
|
||||
export { default as wrapRootElement } from './src/docs/state/ReduxWrapper';
|
||||
82
gatsby-config.js
Normal file
82
gatsby-config.js
Normal file
@ -0,0 +1,82 @@
|
||||
const config = require('./config');
|
||||
|
||||
module.exports = {
|
||||
siteMetadata: {
|
||||
title: `${config.name}`,
|
||||
description: `${config.description}`,
|
||||
author: `@30-seconds`,
|
||||
},
|
||||
plugins: [
|
||||
`gatsby-plugin-transition-link`,
|
||||
{
|
||||
resolve: `gatsby-source-filesystem`,
|
||||
options: {
|
||||
name: `snippets`,
|
||||
path: `${__dirname}/${config.snippetPath}`,
|
||||
},
|
||||
},
|
||||
{
|
||||
resolve: `gatsby-source-filesystem`,
|
||||
options: {
|
||||
name: `snippet_data`,
|
||||
path: `${__dirname}/${config.snippetDataPath}`,
|
||||
},
|
||||
},
|
||||
{
|
||||
resolve: `gatsby-source-filesystem`,
|
||||
options: {
|
||||
name: `assets`,
|
||||
path: `${__dirname}/${config.assetPath}`,
|
||||
},
|
||||
},
|
||||
{
|
||||
resolve: `gatsby-plugin-page-creator`,
|
||||
options: {
|
||||
path: `${__dirname}/${config.pagePath}`,
|
||||
},
|
||||
},
|
||||
{
|
||||
resolve: `gatsby-transformer-remark`,
|
||||
options: {
|
||||
plugins: [
|
||||
{
|
||||
resolve: `gatsby-remark-images`,
|
||||
options: {
|
||||
maxWidth: 590,
|
||||
},
|
||||
},
|
||||
`gatsby-remark-prismjs`,
|
||||
`gatsby-remark-copy-linked-files`,
|
||||
],
|
||||
},
|
||||
},
|
||||
`gatsby-plugin-sass`,
|
||||
`gatsby-transformer-json`,
|
||||
`gatsby-transformer-sharp`,
|
||||
`gatsby-plugin-sharp`,
|
||||
{
|
||||
resolve: `gatsby-plugin-google-analytics`,
|
||||
options: {
|
||||
//trackingId: `ADD YOUR TRACKING ID HERE`,
|
||||
anonymize: true, // Always set this to true, try to comply with GDPR out of the box
|
||||
respectDNT: true, // Always set to true, be respectful of people who ask not to be tracked
|
||||
cookieExpires: 0, // Always set to 0, minimum tracking for your users
|
||||
},
|
||||
},
|
||||
{
|
||||
resolve: `gatsby-plugin-manifest`,
|
||||
options: {
|
||||
name: `${config.name}`,
|
||||
short_name: `${config.shortName}`,
|
||||
start_url: `/`,
|
||||
background_color: `#1e253d`,
|
||||
theme_color: `#1e253d`,
|
||||
display: `standalone`,
|
||||
icon: `assets/30s-icon.png`, // This path is relative to the root of the site.
|
||||
},
|
||||
},
|
||||
`gatsby-plugin-offline`,
|
||||
`gatsby-plugin-react-helmet`,
|
||||
`gatsby-plugin-netlify`,
|
||||
],
|
||||
};
|
||||
96
gatsby-node.js
Normal file
96
gatsby-node.js
Normal file
@ -0,0 +1,96 @@
|
||||
const path = require(`path`);
|
||||
const { createFilePath } = require(`gatsby-source-filesystem`);
|
||||
|
||||
const toKebabCase = str =>
|
||||
str &&
|
||||
str
|
||||
.match(/[A-Z]{2,}(?=[A-Z][a-z]+[0-9]*|\b)|[A-Z]?[a-z]+[0-9]*|[A-Z]|[0-9]+/g)
|
||||
.map(x => x.toLowerCase())
|
||||
.join('-');
|
||||
|
||||
exports.createPages = ({ graphql, actions }) => {
|
||||
const { createPage } = actions;
|
||||
|
||||
const snippetPage = path.resolve(`./src/docs/templates/SnippetPage.js`);
|
||||
const tagPage = path.resolve(`./src/docs/templates/TagPage.js`);
|
||||
return graphql(
|
||||
`
|
||||
{
|
||||
allMarkdownRemark(
|
||||
sort: { fields: [frontmatter___title], order: ASC }
|
||||
limit: 1000
|
||||
) {
|
||||
edges {
|
||||
node {
|
||||
fields {
|
||||
slug
|
||||
}
|
||||
frontmatter {
|
||||
tags
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`,
|
||||
).then(result => {
|
||||
if (result.errors) {
|
||||
throw result.errors;
|
||||
}
|
||||
|
||||
// Create individual snippet pages.
|
||||
const snippets = result.data.allMarkdownRemark.edges;
|
||||
|
||||
snippets.forEach((post, index) => {
|
||||
const previous =
|
||||
index === snippets.length - 1 ? null : snippets[index + 1].node;
|
||||
const next = index === 0 ? null : snippets[index - 1].node;
|
||||
|
||||
createPage({
|
||||
path: post.node.fields.slug,
|
||||
component: snippetPage,
|
||||
context: {
|
||||
slug: post.node.fields.slug,
|
||||
previous,
|
||||
next,
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
// Create tag pages.
|
||||
const tags = snippets.reduce((acc, post) => {
|
||||
if (!post.node.frontmatter || !post.node.frontmatter.tags) return acc;
|
||||
const primaryTag = post.node.frontmatter.tags.split(',')[0];
|
||||
if (!acc.includes(primaryTag)) acc.push(primaryTag);
|
||||
return acc;
|
||||
}, []);
|
||||
|
||||
tags.forEach(tag => {
|
||||
const tagPath = `/tags/${toKebabCase(tag)}/`;
|
||||
const tagRegex = `/^\\s*${tag}/`;
|
||||
createPage({
|
||||
path: tagPath,
|
||||
component: tagPage,
|
||||
context: {
|
||||
tag,
|
||||
tagRegex,
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
return null;
|
||||
});
|
||||
};
|
||||
|
||||
exports.onCreateNode = ({ node, actions, getNode }) => {
|
||||
const { createNodeField } = actions;
|
||||
|
||||
if (node.internal.type === `MarkdownRemark`) {
|
||||
const value = createFilePath({ node, getNode });
|
||||
createNodeField({
|
||||
name: `slug`,
|
||||
node,
|
||||
value,
|
||||
});
|
||||
}
|
||||
};
|
||||
8
gatsby-ssr.js
Normal file
8
gatsby-ssr.js
Normal file
@ -0,0 +1,8 @@
|
||||
/**
|
||||
* Implement Gatsby's SSR (Server Side Rendering) APIs in this file.
|
||||
*
|
||||
* See: https://www.gatsbyjs.org/docs/ssr-apis/
|
||||
*/
|
||||
|
||||
// You can delete this file if you're not using it
|
||||
export { default as wrapRootElement } from './src/docs/state/ReduxWrapper';
|
||||
@ -1,101 +0,0 @@
|
||||
ajax
|
||||
api
|
||||
argument
|
||||
array
|
||||
asynchronous-programming
|
||||
automatic-semicolon-insertion
|
||||
boolean
|
||||
callback
|
||||
character-encoding
|
||||
class
|
||||
closure
|
||||
coffeescript
|
||||
constant
|
||||
constructor
|
||||
continuous-deployment
|
||||
continuous-integration
|
||||
cors
|
||||
cross-site-scripting-xss
|
||||
css
|
||||
csv
|
||||
currying
|
||||
deserialization
|
||||
dns
|
||||
dom
|
||||
domain-name-registrar
|
||||
domain-name
|
||||
element
|
||||
es6
|
||||
event-driven-programming
|
||||
event-loop
|
||||
express
|
||||
factory-functions
|
||||
first-class-function
|
||||
flexbox
|
||||
function
|
||||
functional-programming
|
||||
functor
|
||||
garbage-collection
|
||||
git
|
||||
higher-order-function
|
||||
hoisting
|
||||
html
|
||||
http-and-https
|
||||
integer
|
||||
integration-testing
|
||||
ip
|
||||
jquery
|
||||
json
|
||||
keyword_database
|
||||
mdn
|
||||
module
|
||||
mongodb
|
||||
mutabe-value
|
||||
mvc
|
||||
node-js
|
||||
nosql
|
||||
npm
|
||||
object-oriented-programming
|
||||
object
|
||||
prepared-statements
|
||||
promise
|
||||
prototype-based-programming
|
||||
pseudo-class
|
||||
pseudo-element
|
||||
pwa
|
||||
react
|
||||
readme
|
||||
recursion
|
||||
regular-expressions
|
||||
repository
|
||||
responsive-web-design
|
||||
scope
|
||||
selector
|
||||
seo
|
||||
serialization
|
||||
shadowdom
|
||||
sql-injection
|
||||
sql
|
||||
ssl
|
||||
stream
|
||||
strict-mode
|
||||
string
|
||||
svg
|
||||
template-literals
|
||||
typescript
|
||||
unit-testing
|
||||
uri
|
||||
url
|
||||
utf-8
|
||||
value-vs-reference
|
||||
variable
|
||||
viewport
|
||||
vue
|
||||
webassembly
|
||||
webcomponents
|
||||
webgl
|
||||
webrtc
|
||||
websockets
|
||||
xhtml
|
||||
xml
|
||||
yarn
|
||||
6
netlify.toml
Normal file
6
netlify.toml
Normal file
@ -0,0 +1,6 @@
|
||||
[build]
|
||||
publish = "public"
|
||||
command = "npm run webber"
|
||||
[build.environment]
|
||||
YARN_VERSION = "1.9.4"
|
||||
YARN_FLAGS = "--no-ignore-optional"
|
||||
19706
package-lock.json
generated
19706
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
46
package.json
46
package.json
@ -10,7 +10,9 @@
|
||||
"glossary:keymaker": "node ./scripts/glossary/keyword.js",
|
||||
"builder": "node ./scripts/build.js",
|
||||
"linter": "node ./scripts/lint.js",
|
||||
"webber": "node ./scripts/web.js",
|
||||
"webber": "gatsby build",
|
||||
"webber:dev": "gatsby develop",
|
||||
"webber:serve": "gatsby serve",
|
||||
"tester": "node ./scripts/tdd.js",
|
||||
"extractor": "node ./scripts/extract.js",
|
||||
"vscoder": "node ./scripts/vscodegen.js",
|
||||
@ -35,19 +37,51 @@
|
||||
"dependencies": {},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.1.2",
|
||||
"@babel/preset-env": "^7.1.0",
|
||||
"@babel/plugin-proposal-class-properties": "^7.5.0",
|
||||
"@babel/plugin-syntax-dynamic-import": "^7.2.0",
|
||||
"@babel/preset-env": "^7.5.4",
|
||||
"@babel/preset-react": "^7.0.0",
|
||||
"babel-plugin-transform-es2015-modules-commonjs": "^6.26.2",
|
||||
"codacy-coverage": "^3.2.0",
|
||||
"eslint": "^5.7.0",
|
||||
"front-matter": "^3.0.2",
|
||||
"fs-extra": "^6.0.0",
|
||||
"gatsby": "^2.12.0",
|
||||
"gatsby-image": "^2.2.6",
|
||||
"gatsby-plugin-google-analytics": "^2.1.6",
|
||||
"gatsby-plugin-manifest": "^2.2.3",
|
||||
"gatsby-plugin-netlify": "^2.1.3",
|
||||
"gatsby-plugin-offline": "^2.2.4",
|
||||
"gatsby-plugin-page-creator": "^2.1.5",
|
||||
"gatsby-plugin-react-helmet": "^3.1.2",
|
||||
"gatsby-plugin-sass": "^2.1.3",
|
||||
"gatsby-plugin-sharp": "^2.2.7",
|
||||
"gatsby-plugin-transition-link": "^1.12.4",
|
||||
"gatsby-remark-copy-linked-files": "^2.1.3",
|
||||
"gatsby-remark-images": "^3.1.6",
|
||||
"gatsby-remark-prismjs": "^3.3.3",
|
||||
"gatsby-source-filesystem": "^2.1.5",
|
||||
"gatsby-transformer-json": "^2.2.2",
|
||||
"gatsby-transformer-remark": "^2.6.6",
|
||||
"gatsby-transformer-sharp": "^2.2.3",
|
||||
"gsap": "^2.1.3",
|
||||
"html-minifier": "^3.5.20",
|
||||
"jest": "^23.6.0",
|
||||
"kleur": "^3.0.3",
|
||||
"markdown-builder": "^0.8.4",
|
||||
"markdown-builder": "^0.9.0",
|
||||
"markdown-it": "^8.4.2",
|
||||
"node-sass": "^4.9.3",
|
||||
"node-sass": "^4.12.0",
|
||||
"octicons": "^7.4.0",
|
||||
"prettier": "^1.14.2",
|
||||
"prismjs": "^1.15.0",
|
||||
"prettier": "^1.18.2",
|
||||
"prismjs": "^1.16.0",
|
||||
"prop-types": "^15.7.2",
|
||||
"react": "^16.8.6",
|
||||
"react-copy-to-clipboard": "^5.0.1",
|
||||
"react-css-transition-replace": "^3.0.3",
|
||||
"react-dom": "^16.8.6",
|
||||
"react-helmet": "^5.2.1",
|
||||
"react-redux": "^7.1.0",
|
||||
"redux": "^4.0.4",
|
||||
"rollup": "^0.58.2",
|
||||
"rollup-plugin-babel": "^4.0.3",
|
||||
"rollup-plugin-babel-minify": "^4.0.0"
|
||||
|
||||
429
scripts/web.js
429
scripts/web.js
@ -1,429 +0,0 @@
|
||||
/*
|
||||
This is the web builder script that generates the web files.
|
||||
Run using `npm run webber`.
|
||||
*/
|
||||
// Load modules
|
||||
const fs = require('fs-extra'),
|
||||
path = require('path'),
|
||||
{ green, red } = require('kleur'),
|
||||
md = require('markdown-it')(),
|
||||
minify = require('html-minifier').minify;
|
||||
const util = require('./util');
|
||||
var Prism = require('prismjs');
|
||||
const minifyHTML = str =>
|
||||
minify(str, {
|
||||
collapseBooleanAttributes: true,
|
||||
collapseWhitespace: true,
|
||||
decodeEntities: false,
|
||||
minifyCSS: true,
|
||||
minifyJS: true,
|
||||
keepClosingSlash: true,
|
||||
processConditionalComments: true,
|
||||
removeAttributeQuotes: false,
|
||||
removeComments: true,
|
||||
removeEmptyAttributes: false,
|
||||
removeOptionalTags: false,
|
||||
removeScriptTypeAttributes: false,
|
||||
removeStyleLinkTypeAttributes: false,
|
||||
trimCustomFragments: true
|
||||
});
|
||||
const unescapeHTML = str =>
|
||||
str.replace(
|
||||
/&|<|>|'|"/g,
|
||||
tag =>
|
||||
({
|
||||
'&': '&',
|
||||
'<': '<',
|
||||
'>': '>',
|
||||
''': "'",
|
||||
'"': '"'
|
||||
}[tag] || tag)
|
||||
);
|
||||
const generateSnippetCard = (
|
||||
snippetList,
|
||||
snippetKey,
|
||||
addCornerTag = false
|
||||
) => `<div class="card code-card">
|
||||
${
|
||||
addCornerTag
|
||||
? `<div class="corner ${
|
||||
snippetKey[1].includes('advanced')
|
||||
? 'advanced'
|
||||
: snippetKey[1].includes('beginner')
|
||||
? 'beginner'
|
||||
: 'intermediate'
|
||||
}" aria-label="${
|
||||
snippetKey[1].includes('advanced')
|
||||
? 'advanced'
|
||||
: snippetKey[1].includes('beginner')
|
||||
? 'beginner'
|
||||
: 'intermediate'
|
||||
}" title="${
|
||||
snippetKey[1].includes('advanced')
|
||||
? 'advanced'
|
||||
: snippetKey[1].includes('beginner')
|
||||
? 'beginner'
|
||||
: 'intermediate'
|
||||
}" ></div>`
|
||||
: ''
|
||||
}
|
||||
${md
|
||||
.render(`\n${addCornerTag ? snippetList[snippetKey[0] + '.md'] : snippetList[snippetKey[0]]}`)
|
||||
.replace(/<h3/g, `<div class="section card-content"><h4 id="${snippetKey[0].toLowerCase()}"`)
|
||||
.replace(/<\/h3>/g, '</h4>')
|
||||
.replace(
|
||||
/<pre><code class="language-js">/m,
|
||||
'</div><div class="copy-button-container"><button class="copy-button" aria-label="Copy to clipboard"></button></div><pre><code class="language-js">'
|
||||
)
|
||||
.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(/<\/div>\s*<pre class="/g, '</div><pre class="section card-code ')
|
||||
.replace(
|
||||
/<\/pre>\s+<pre class="/g,
|
||||
'</pre><label class="collapse">examples</label><pre class="section card-examples '
|
||||
)}
|
||||
</div>`;
|
||||
const embedCard = tag => `<div class="card code-card"><div class="section card-content">
|
||||
${['adapter','array','function','object'].includes(tag) ?
|
||||
'<h4><a href="https://frontendmasters.com/courses/es6-right-parts/" target="_blank" rel="noopener noreferrer">Recommended Resource - ES6: The Right Parts</a></h4><p>Learn new ES6 JavaScript language features like arrow function, destructuring, generators & more to write cleaner and more productive, readable programs.</p>'
|
||||
: ['browser', 'node', 'date'].includes(tag) ?
|
||||
'<h4><a href="https://frontendmasters.com/courses/javascript-hard-parts/" target="_blank" rel="noopener noreferrer">Recommended Resource - JavaScript: The Hard Parts</a></h4><p>Take your JavaScript to the next level. Gain an understanding of callbacks, higher order functions, closure, asynchronous and object-oriented JavaScript!</p>'
|
||||
: '<h4><a href="https://frontendmasters.com/courses/js-fundamentals-functional-v2/" target="_blank" rel="noopener noreferrer">Recommended Resource - JavaScript: From Fundamentals to Functional JS</a></h4><p>Learn higher-order functions, closures, scope, master key functional methods like map, reduce and filter and promises and ES6+ asynchronous JavaScript.</p>'
|
||||
}</div></div>`;
|
||||
const filterSnippets = (snippetList, excludedFiles) =>
|
||||
Object.keys(snippetList)
|
||||
.filter(key => !excludedFiles.includes(key))
|
||||
.reduce((obj, key) => {
|
||||
obj[key] = snippetList[key];
|
||||
return obj;
|
||||
}, {});
|
||||
if (
|
||||
util.isTravisCI() &&
|
||||
/^Travis build: \d+/g.test(process.env['TRAVIS_COMMIT_MESSAGE']) &&
|
||||
process.env['TRAVIS_EVENT_TYPE'] !== 'cron' &&
|
||||
process.env['TRAVIS_EVENT_TYPE'] !== 'api'
|
||||
) {
|
||||
console.log(
|
||||
`${green('NOBUILD')} website build terminated, parent commit is a Travis build!`
|
||||
);
|
||||
process.exit(0);
|
||||
}
|
||||
// Compile the SCSS file, using `node-sass`.
|
||||
const sass = require('node-sass');
|
||||
sass.render(
|
||||
{
|
||||
file: path.join('docs', 'scss', 'style.scss'),
|
||||
outFile: path.join('docs', 'style.css'),
|
||||
outputStyle: 'compressed'
|
||||
},
|
||||
function(err, result) {
|
||||
if (!err) {
|
||||
fs.writeFile(path.join('docs', 'style.css'), result.css, function(err2) {
|
||||
if (!err2) console.log(`${green('SUCCESS!')} style.css file generated!`);
|
||||
else console.log(`${red('ERROR!')} During style.css file generation: ${err}`);
|
||||
});
|
||||
} else
|
||||
console.log(`${red('ERROR!')} During style.css file generation: ${err}`);
|
||||
|
||||
}
|
||||
);
|
||||
// Set variables for paths
|
||||
const snippetsPath = './snippets',
|
||||
archivedSnippetsPath = './snippets_archive',
|
||||
glossarySnippetsPath = './glossary',
|
||||
staticPartsPath = './static-parts',
|
||||
docsPath = './docs',
|
||||
staticFiles = ['about.html', 'contributing.html', 'array.html'];
|
||||
// Set variables for script
|
||||
let snippets = {},
|
||||
archivedSnippets = {},
|
||||
glossarySnippets = {},
|
||||
startPart = '',
|
||||
endPart = '',
|
||||
output = '',
|
||||
archivedOutput = '',
|
||||
glossaryOutput = '',
|
||||
pagesOutput = [],
|
||||
tagDbData = {};
|
||||
// Start the timer of the script
|
||||
console.time('Webber');
|
||||
// Synchronously read all snippets and sort them as necessary (case-insensitive)
|
||||
snippets = util.readSnippets(snippetsPath);
|
||||
archivedSnippets = util.readSnippets(archivedSnippetsPath);
|
||||
glossarySnippets = util.readSnippets(glossarySnippetsPath);
|
||||
|
||||
// Load static parts for all pages
|
||||
try {
|
||||
[startPart, endPart, staticPageStartPart, staticPageEndPart] = [
|
||||
'page-start.html',
|
||||
'page-end.html',
|
||||
'static-page-start.html',
|
||||
'static-page-end.html'
|
||||
].map(filename => fs.readFileSync(path.join(staticPartsPath, filename), 'utf8'));
|
||||
} catch (err) {
|
||||
// Handle errors (hopefully not!)
|
||||
console.log(`${red('ERROR!')} During static part loading: ${err}`);
|
||||
process.exit(1);
|
||||
}
|
||||
// Load tag data from the database
|
||||
tagDbData = util.readTags();
|
||||
|
||||
// Create the output for individual category pages
|
||||
try {
|
||||
let taggedData = util.prepTaggedData(tagDbData);
|
||||
// Add the start static part
|
||||
output += `${startPart}${'\n'}`;
|
||||
// Loop over tags and snippets to create the table of contents
|
||||
for (let tag of taggedData) {
|
||||
output +=
|
||||
'<h4 class="collapse">' +
|
||||
md
|
||||
.render(`${util.capitalize(tag, true)}\n`)
|
||||
.replace(/<p>/g, '')
|
||||
.replace(/<\/p>/g, '') +
|
||||
'</h4><ul>';
|
||||
for (let taggedSnippet of Object.entries(tagDbData).filter(v => v[1][0] === tag)) {
|
||||
output += md
|
||||
.render(
|
||||
`[${taggedSnippet[0]}](./${
|
||||
tag === 'array' ? 'index' : tag
|
||||
}#${taggedSnippet[0].toLowerCase()})\n`
|
||||
)
|
||||
.replace(/<p>/g, '')
|
||||
.replace(/<\/p>/g, '</li>')
|
||||
.replace(/<a/g, `<li><a tags="${taggedSnippet[1].join(',')}"`);
|
||||
}
|
||||
output += '</ul>\n';
|
||||
}
|
||||
output += `<h4 class="static-link"><a href="./archive">Archive</a></h4>
|
||||
<h4 class="static-link"><a href="./glossary">Glossary</a></h4>
|
||||
<h4 class="static-link"><a href="./contributing">Contributing</a></h4>
|
||||
<h4 class="static-link"><a href="./about">About</a></h4>
|
||||
<div><button class="social fb"></button><button class="social instagram"></button><button class="social twitter"></button></div>
|
||||
</nav><main class="col-centered"><span id="top"><br/><br/></span>`;
|
||||
// Loop over tags and snippets to create the list of snippets
|
||||
for (let tag of taggedData) {
|
||||
let notEmbedded = true;
|
||||
let localOutput = output
|
||||
.replace(/\$tag/g, util.capitalize(tag))
|
||||
.replace(new RegExp(`./${tag}#`, 'g'), '#');
|
||||
if (tag === 'array') localOutput = localOutput.replace(new RegExp('./index#', 'g'), '#');
|
||||
localOutput += md
|
||||
.render(`## ${util.capitalize(tag, true)}\n`)
|
||||
.replace(/<h2>/g, '<h2 class="category-name">');
|
||||
for (let taggedSnippet of Object.entries(tagDbData).filter(v => v[1][0] === tag)) {
|
||||
localOutput += generateSnippetCard(snippets, taggedSnippet, true);
|
||||
if (Object.entries(tagDbData).filter(v => v[1][0] === tag).findIndex(v => v[0] === taggedSnippet[0]) >= Object.entries(tagDbData).filter(v => v[1][0] === tag).length * 0.5 && notEmbedded) {
|
||||
notEmbedded = !notEmbedded;
|
||||
localOutput += embedCard(tag);
|
||||
}
|
||||
}
|
||||
// Add the ending static part
|
||||
localOutput += `\n${endPart + '\n'}`;
|
||||
// Optimize punctuation nodes
|
||||
localOutput = util.optimizeNodes(
|
||||
localOutput,
|
||||
/<span class="token punctuation">([^\0<]*?)<\/span>([\n\r\s]*)<span class="token punctuation">([^\0]*?)<\/span>/gm,
|
||||
(match, p1, p2, p3) => `<span class="token punctuation">${p1}${p2}${p3}</span>`
|
||||
);
|
||||
// Optimize operator nodes
|
||||
localOutput = util.optimizeNodes(
|
||||
localOutput,
|
||||
/<span class="token operator">([^\0<]*?)<\/span>([\n\r\s]*)<span class="token operator">([^\0]*?)<\/span>/gm,
|
||||
(match, p1, p2, p3) => `<span class="token operator">${p1}${p2}${p3}</span>`
|
||||
);
|
||||
// Optimize keyword nodes
|
||||
localOutput = util.optimizeNodes(
|
||||
localOutput,
|
||||
/<span class="token keyword">([^\0<]*?)<\/span>([\n\r\s]*)<span class="token keyword">([^\0]*?)<\/span>/gm,
|
||||
(match, p1, p2, p3) => `<span class="token keyword">${p1}${p2}${p3}</span>`
|
||||
);
|
||||
pagesOutput.push({ tag, content: localOutput });
|
||||
}
|
||||
// Minify output
|
||||
pagesOutput.forEach(page => {
|
||||
page.content = minifyHTML(page.content);
|
||||
fs.writeFileSync(
|
||||
path.join(docsPath, (page.tag === 'array' ? 'index' : page.tag) + '.html'),
|
||||
page.content
|
||||
);
|
||||
console.log(
|
||||
`${green('SUCCESS!')} ${page.tag === 'array' ? 'index' : page.tag}.html file generated!`
|
||||
);
|
||||
});
|
||||
} catch (err) {
|
||||
// Handle errors (hopefully not!)
|
||||
console.log(`${red('ERROR!')} During category page generation: ${err}`);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const generateMenuForStaticPage = staticPart => {
|
||||
let taggedData = util.prepTaggedData(tagDbData);
|
||||
// Add the start static part
|
||||
let htmlCode;
|
||||
|
||||
for (let tag of taggedData) {
|
||||
htmlCode +=
|
||||
'<h4 class="collapse">' +
|
||||
md
|
||||
.render(`${util.capitalize(tag, true)}\n`)
|
||||
.replace(/<p>/g, '')
|
||||
.replace(/<\/p>/g, '') +
|
||||
'</h4><ul>';
|
||||
for (let taggedSnippet of Object.entries(tagDbData).filter(v => v[1][0] === tag)) {
|
||||
htmlCode += md
|
||||
.render(
|
||||
`[${taggedSnippet[0]}](./${
|
||||
tag === 'array' ? 'index' : tag
|
||||
}#${taggedSnippet[0].toLowerCase()})\n`
|
||||
)
|
||||
.replace(/<p>/g, '')
|
||||
.replace(/<\/p>/g, '</li>')
|
||||
.replace(/<a/g, `<li><a tags="${taggedSnippet[1].join(',')}"`);
|
||||
}
|
||||
htmlCode += '</ul>\n';
|
||||
}
|
||||
return staticPart.replace('$nav-menu-data', htmlCode);
|
||||
};
|
||||
|
||||
const staticPageStartGenerator = (staticPart, heading, description) => {
|
||||
let taggedData = util.prepTaggedData(tagDbData);
|
||||
// Add the start static part
|
||||
let htmlCode = `${staticPart}\n`;
|
||||
|
||||
// Loop over tags and snippets to create the table of contents
|
||||
for (let tag of taggedData) {
|
||||
htmlCode +=
|
||||
'<h4 class="collapse">' +
|
||||
md
|
||||
.render(`${util.capitalize(tag, true)}\n`)
|
||||
.replace(/<p>/g, '')
|
||||
.replace(/<\/p>/g, '') +
|
||||
'</h4><ul>';
|
||||
for (let taggedSnippet of Object.entries(tagDbData).filter(v => v[1][0] === tag)) {
|
||||
htmlCode += md
|
||||
.render(
|
||||
`[${taggedSnippet[0]}](./${
|
||||
tag === 'array' ? 'index' : tag
|
||||
}#${taggedSnippet[0].toLowerCase()})\n`
|
||||
)
|
||||
.replace(/<p>/g, '')
|
||||
.replace(/<\/p>/g, '</li>')
|
||||
.replace(/<a/g, `<li><a tags="${taggedSnippet[1].join(',')}"`);
|
||||
}
|
||||
htmlCode += '</ul>\n';
|
||||
}
|
||||
htmlCode += `<h4 class="static-link"><a href="./archive">Archive</a></h4>
|
||||
<h4 class="static-link"><a href="./glossary">Glossary</a></h4>
|
||||
<h4 class="static-link"><a href="./contributing">Contributing</a></h4>
|
||||
<h4 class="static-link"><a href="./about">About</a></h4>
|
||||
<div><button class="social fb"></button><button class="social instagram"></button><button class="social twitter"></button></div>
|
||||
</nav><main class="col-centered"><span id="top"><br/><br/></span><h2 class="category-name">${heading}</h2>
|
||||
<p style="text-align: justify">${description}</p><br />`;
|
||||
return htmlCode.replace(/\$page_name/g, util.capitalize(heading));
|
||||
};
|
||||
|
||||
|
||||
// Create the output for the archive.html file
|
||||
try {
|
||||
// Add the static part
|
||||
let heading = 'Snippets Archive';
|
||||
let description = "These snippets, while useful and interesting, didn't quite make it into the repository due to either having very specific use-cases or being outdated. However we felt like they might still be useful to some readers, so here they are.";
|
||||
let htmlCode = staticPageStartGenerator(staticPageStartPart, heading, description);
|
||||
|
||||
archivedOutput += htmlCode;
|
||||
|
||||
// Filter README.md from folder
|
||||
const filteredArchivedSnippets = filterSnippets(archivedSnippets, ['README.md']);
|
||||
|
||||
// Generate archived snippets from md files
|
||||
for (let snippet of Object.entries(filteredArchivedSnippets))
|
||||
archivedOutput += generateSnippetCard(filteredArchivedSnippets, snippet, false);
|
||||
|
||||
// Optimize punctuation nodes
|
||||
archivedOutput = util.optimizeNodes(
|
||||
archivedOutput,
|
||||
/<span class="token punctuation">([^\0<]*?)<\/span>([\n\r\s]*)<span class="token punctuation">([^\0]*?)<\/span>/gm,
|
||||
(match, p1, p2, p3) => `<span class="token punctuation">${p1}${p2}${p3}</span>`
|
||||
);
|
||||
// Optimize operator nodes
|
||||
archivedOutput = util.optimizeNodes(
|
||||
archivedOutput,
|
||||
/<span class="token operator">([^\0<]*?)<\/span>([\n\r\s]*)<span class="token operator">([^\0]*?)<\/span>/gm,
|
||||
(match, p1, p2, p3) => `<span class="token operator">${p1}${p2}${p3}</span>`
|
||||
);
|
||||
// Optimize keyword nodes
|
||||
archivedOutput = util.optimizeNodes(
|
||||
archivedOutput,
|
||||
/<span class="token keyword">([^\0<]*?)<\/span>([\n\r\s]*)<span class="token keyword">([^\0]*?)<\/span>/gm,
|
||||
(match, p1, p2, p3) => `<span class="token keyword">${p1}${p2}${p3}</span>`
|
||||
);
|
||||
|
||||
archivedOutput += `${staticPageEndPart}`;
|
||||
|
||||
// Generate and minify 'archive.html' file
|
||||
const minifiedArchivedOutput = minifyHTML(archivedOutput);
|
||||
|
||||
fs.writeFileSync(path.join(docsPath, 'archive.html'), minifiedArchivedOutput);
|
||||
console.log(`${green('SUCCESS!')} archive.html file generated!`);
|
||||
} catch (err) {
|
||||
console.log(`${red('ERROR!')} During archive.html generation: ${err}`);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
// Create the output for the glossary.html file
|
||||
try {
|
||||
// Add the static part
|
||||
let heading = 'Glossary';
|
||||
let description = 'Developers use a lot of terminology daily. Every once in a while, you might find a term you do not know. We know how frustrating that can get, so we provide you with a handy glossary of frequently used web development terms.';
|
||||
let htmlCode = staticPageStartGenerator(staticPageStartPart, heading, description);
|
||||
glossaryOutput += htmlCode;
|
||||
|
||||
// Filter README.md from folder
|
||||
const filteredGlossarySnippets = filterSnippets(glossarySnippets, ['README.md']);
|
||||
|
||||
// Generate glossary snippets from md files
|
||||
for (let snippet of Object.entries(filteredGlossarySnippets)) {
|
||||
glossaryOutput +=
|
||||
'<div class="card code-card"><div class="section card-content">' +
|
||||
md
|
||||
.render(`\n${filteredGlossarySnippets[snippet[0]]}`)
|
||||
.replace(/<h3/g, `<h4 id="${snippet[0].toLowerCase()}"`)
|
||||
.replace(/<\/h3>/g, '</h4>') +
|
||||
'</div></div>';
|
||||
}
|
||||
|
||||
glossaryOutput += `${staticPageEndPart}`;
|
||||
|
||||
// Generate and minify 'glossary.html' file
|
||||
const minifiedGlossaryOutput = minifyHTML(glossaryOutput);
|
||||
fs.writeFileSync(path.join(docsPath, 'glossary.html'), minifiedGlossaryOutput);
|
||||
console.log(`${green('SUCCESS!')} glossary.html file generated!`);
|
||||
} catch (err) {
|
||||
console.log(`${red('ERROR!')} During glossary.html generation: ${err}`);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
// Copy static files
|
||||
staticFiles.forEach(f => {
|
||||
try {
|
||||
if(f !== 'array.html') {
|
||||
let fileData = fs.readFileSync(path.join(staticPartsPath, f), 'utf8');
|
||||
fs.writeFileSync(path.join(docsPath, f), generateMenuForStaticPage(fileData));
|
||||
} else
|
||||
fs.copyFileSync(path.join(staticPartsPath, f), path.join(docsPath, f));
|
||||
console.log(`${green('SUCCESS!')} ${f} file copied!`);
|
||||
} catch (err) {
|
||||
console.log(`${red('ERROR!')} During ${f} copying: ${err}`);
|
||||
process.exit(1);
|
||||
}
|
||||
});
|
||||
|
||||
// Log the time taken
|
||||
console.timeEnd('Webber');
|
||||
Reference in New Issue
Block a user