const fs = require('fs')
const path = require('path')
const marked = require('marked')
const pretty = require('pretty')
const caniuseDb = require('caniuse-db/data.json')
const sass = require('node-sass')
const { toKebabCase, createElement, template, dom, getCode } = require('../utils/utils.js')
const { differenceInDays } = require('date-fns')
const SNIPPETS_PATH = './snippets'
const TAGS = [
{
name: 'all',
icon: 'check'
},
{
name: 'layout',
icon: 'layout'
},
{
name: 'visual',
icon: 'eye'
},
{
name: 'animation',
icon: 'loader'
},
{
name: 'interactivity',
icon: 'edit-2'
},
{
name: 'other',
icon: 'tag'
}
]
const renderer = new marked.Renderer()
renderer.heading = (text, level) => {
if (level === 3) {
return `${text}`
} else {
return ['HTML', 'CSS', 'JavaScript'].includes(text)
? `${text}`
: `${text}`
}
}
renderer.link = (url, _, text) => `${text || url}`
const document = dom('./src/html/index.html')
const components = {
backToTopButton: dom('./src/html/components/back-to-top-button.html'),
sidebar: dom('./src/html/components/sidebar.html'),
header: dom('./src/html/components/header.html'),
main: dom('./src/html/components/main.html'),
tags: dom('./src/html/components/tags.html')
}
const snippetContainer = components.main.querySelector('.container')
const sidebarLinkContainer = components.sidebar.querySelector('.sidebar__links')
TAGS.slice(1).forEach(tag => {
sidebarLinkContainer.append(
createElement(`
`)
)
})
for (const snippetFile of fs.readdirSync(SNIPPETS_PATH)) {
const snippetPath = path.join(SNIPPETS_PATH, snippetFile)
const snippetData = fs.readFileSync(snippetPath, 'utf8')
const html = getCode('html', snippetData).trim()
const css = getCode('css', snippetData)
const scopedCSS = sass.renderSync({
data: `[data-scope="${snippetFile}"] { ${css} }`
})
const js = getCode('js', snippetData)
const demo =
`
${html}
` +
`` +
`${js ? `` : ''}`
const markdown = marked(snippetData, { renderer }).replace(
'Demo
',
`Demo
${demo}`
)
const snippetEl = createElement(`${markdown}
`)
snippetContainer.append(snippetEl)
// browser support usage
const featUsageShares = (snippetData.match(/https?:\/\/caniuse\.com\/#feat=.*/g) || []).map(
feat => {
const featData = caniuseDb.data[feat.match(/#feat=(.*)/)[1]]
return featData ? Number(featData.usage_perc_y + featData.usage_perc_a) : 100
}
)
const browserSupportHeading = snippetEl.querySelector('h4:last-of-type')
browserSupportHeading.after(
createElement(`
${featUsageShares.length ? Math.min(...featUsageShares).toPrecision(3) : '99+'}%
`)
)
// sidebar link
const link = createElement(
``
)
// new icon = less than 31 days old
const date = (snippetData.match(//) || [, ''])[1]
if (date && differenceInDays(new Date(), new Date(date)) < 31) {
const newIcon = '
'
snippetEl.prepend(createElement(newIcon))
link.prepend(createElement(newIcon))
}
// tags
const tags = (snippetData.match(//) || [, ''])[1]
.split(/,\s*/)
.forEach(tag => {
tag = tag.trim().toLowerCase()
snippetEl
.querySelector('h3')
.append(
createElement(
`${tag}`
)
)
sidebarLinkContainer.querySelector(`section[data-type="${tag}"]`).append(link)
})
}
// build dom
TAGS.forEach(tag =>
components.tags.append(
createElement(
``
)
)
)
const content = document.querySelector('.content-wrapper')
content.before(components.backToTopButton)
content.before(components.sidebar)
content.append(components.header)
content.append(components.main)
components.main.querySelector('.container').prepend(components.tags)
// doctype declaration gets stripped, add it back in
const html = `
${pretty(document.documentElement.outerHTML, { ocd: true })}
`
fs.writeFileSync('./index.html', html)