Handlebars templates: DRY principle

This commit is contained in:
DarkCat09 2022-12-30 19:07:12 +04:00
parent 027672e530
commit 7ea4eb886b
7 changed files with 719 additions and 1026 deletions

48
dc09.js
View file

@ -10,6 +10,7 @@ const exec = (cmd) => {
} }
const CleanCSS = require('clean-css') const CleanCSS = require('clean-css')
const Handlebars = require('handlebars')
const html = require('html-minifier') const html = require('html-minifier')
@ -85,17 +86,14 @@ function buildOne(dir) {
print(`${bold}Building:${reset} ${dir}`) print(`${bold}Building:${reset} ${dir}`)
const config = `${dir}/webpage.json` const config = `${dir}/webpage.json`
let files if (!fs.existsSync(config)) {
if (fs.existsSync(config)) {
files = JSON.parse(fs.readFileSync(config))
}
else {
print( print(
'Unable to find webpage.json, skipping', 'Unable to find webpage.json, skipping',
false, '!', yellow, false, '!', yellow,
) )
return return
} }
const files = JSON.parse(fs.readFileSync(config))
fs.mkdirSync(`dist/${dir}`, { fs.mkdirSync(`dist/${dir}`, {
recursive: true recursive: true
@ -107,6 +105,8 @@ function buildOne(dir) {
renderLess(dir, files) renderLess(dir, files)
print('Minifying CSS') print('Minifying CSS')
minifyCss(dir, files) minifyCss(dir, files)
print('Compiling Handlebars HTML')
compileHbHtml(dir, files)
print('Converting paths in HTML') print('Converting paths in HTML')
convertPathsHtml(dir, files) convertPathsHtml(dir, files)
print('Minifying HTML') print('Minifying HTML')
@ -128,7 +128,7 @@ function minifyJs(dir, files) {
function renderLess(dir, files) { function renderLess(dir, files) {
files.less = files.less || [] files.less = files.less || []
if (files.less.length == 0) return; if (files.less.length == 0) return;
rendered = path.resolve(`dist/${dir}/${mincss}`) const rendered = path.resolve(`dist/${dir}/${mincss}`)
exec( exec(
'node_modules/.bin/lessc ' + 'node_modules/.bin/lessc ' +
files.less.map(less => `"${dir}/${less}"`).join(' ') + files.less.map(less => `"${dir}/${less}"`).join(' ') +
@ -147,12 +147,45 @@ function minifyCss(dir, files) {
fs.writeFileSync(`dist/${dir}/${mincss}`, content) fs.writeFileSync(`dist/${dir}/${mincss}`, content)
} }
function compileHbHtml(dir, files) {
files.hb = files.hb || []
const compiled = []
for (let file of files.hb) {
const parts = file.split('.')
const base = parts.slice(0, -1).join('.') || ''
const name = path.resolve(`${dir}/${file}`)
const conf = path.resolve(`${dir}/${base}.json`)
const built = path.resolve(`dist/${dir}/${base}.html`)
if (!fs.existsSync(conf)) {
print(
`Unable to find ${conf} \n` +
' for the template, skipping',
false, '!', yellow,
)
continue
}
const ctx = JSON.parse(fs.readFileSync(conf))
const template = Handlebars.compile(
fs.readFileSync(name).toString()
)
fs.writeFileSync(built, template(ctx))
compiled.push(built)
}
files.html = [
...(files.html || []),
...compiled,
]
}
function convertPathsHtml(dir, files) { function convertPathsHtml(dir, files) {
const scriptRegex = /(?:<script src=['"]?js\/\w+\.js['"]?><\/script>[\s\r\n]*)+/gm const scriptRegex = /(?:<script src=['"]?js\/\w+\.js['"]?><\/script>[\s\r\n]*)+/gm
const converted = [] const converted = []
files.html = files.html || [] files.html = files.html || []
for (let file of files.html) { for (let file of files.html) {
const content = fs.readFileSync(`${dir}/${file}`) const isAbs = path.isAbsolute(file)
const name = path.resolve(isAbs ? file : `${dir}/${file}`)
const built = path.resolve(isAbs ? file : `dist/${dir}/${file}`)
const content = fs.readFileSync(name)
.toString() .toString()
.replace( .replace(
'<script src="https://cdn.jsdelivr.net/npm/less"></script>', '<script src="https://cdn.jsdelivr.net/npm/less"></script>',
@ -166,7 +199,6 @@ function convertPathsHtml(dir, files) {
scriptRegex, scriptRegex,
`<script src="${minjs}"></script>` `<script src="${minjs}"></script>`
) )
const built = path.resolve(`dist/${dir}/${file}`)
fs.writeFileSync(built, content) fs.writeFileSync(built, content)
converted.push(built) converted.push(built)
} }

View file

@ -1,6 +1,7 @@
{ {
"dependencies": { "dependencies": {
"clean-css": "^5.3.1", "clean-css": "^5.3.1",
"handlebars": "^4.7.7",
"html-minifier": "^4.0.0", "html-minifier": "^4.0.0",
"less": "^4.1.3", "less": "^4.1.3",
"terser": "^5.16.1" "terser": "^5.16.1"

214
space/index.handlebars Normal file
View file

@ -0,0 +1,214 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>DarkCat09's Web Site</title>
<link rel="stylesheet/less" type="text/css" href="styles.less" />
<link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/gh/shakrmedia/tuesday@v1.1.0/build/tuesday.min.css" />
<link rel="stylesheet" href="fontawesome/css/fontawesome.min.css" />
<link rel="stylesheet" href="fontawesome/css/solid.min.css" />
<link rel="stylesheet" href="fontawesome/css/regular.min.css" />
<link rel="stylesheet" href="fontawesome/css/brands.min.css" />
<script src="https://cdn.jsdelivr.net/npm/less"></script>
</head>
<body onload="init()">
<!-- The Universe -->
<div class="space-wrapper">
<div class="space">
<canvas id="stars"></canvas>
<img id="space-obj" src="img/earth.gif" alt="Unable to load image" />
</div>
</div>
<!-- About Menu -->
<div class="menu about-menu">
<div class="top-menu">
<ul class="section">
{{#each menu}}
<li>
<input type="radio" name="section-input" id="{{this.id}}-section">
<label for="{{this.id}}-section">
<a href="#{{this.id}}">
<i class="{{this.icon}}"></i>
</a>
</label>
</li>
{{/each}}
</ul>
<div class="row-fill"></div>
<ul class="section">
<li id="move">
<label>
<a href="javascript:void(0)">
<i class="fa-solid fa-arrows-up-down-left-right"></i>
</a>
</label>
</li>
</ul>
</div>
<div class="hidden" id="about">
<div class="card about-card">
<div class="title">
Hi! I'm Andrew.
</div>
{{#each about}}
<div>
<div class="icon">
<i class="{{this.icon}}"></i>
</div>
<div class="content">
{{{this.content}}}
{{#if this.expand}}
<div class="expand-wrapper">
<input type="checkbox" id="expand-{{this.id}}">
<label class="expand link" for="expand-{{this.id}}">
<i class="fa-solid fa-angle-down"></i>
Details
</label>
<div class="hidden" id="details-{{this.id}}">
{{this.code}}
</div>
</div>
{{/if}}
</div>
</div>
{{/each}}
</div>
<div class="card profiles">
{{#each profiles}}
<div>
<div class="icon">
<i class="{{this.icon}}"></i>
</div>
<div class="content">
<a class="name" target="_blank" href="{{this.url}}">
{{this.name}}: {{this.user}}
</a>
<div class="copylink">
<span class="link profile-link" data-link="{{#if this.copy}}{{this.copy}}{{else}}{{this.url}}{{/if}}">
<i class="fa-solid fa-copy"></i>
</span>
</div>
</div>
<div class="copied inline-popup right">
Copied
</div>
</div>
{{/each}}
</div>
</div>
<div class="hidden" id="code">
<div class="card">
{{#each langs}}
<div>
<div class="icon">
{{#if this.svg}}
<span>
<img src="{{this.icon}}">
</span>
{{else}}
<i class="{{this.icon}}"></i>
{{/if}}
</div>
<div class="content">
<div class="lang-name">{{this.name}}</div>
<div class="details">
<div class="expand-wrapper">
<input type="checkbox" id="expand-{{this.id1}}">
<label class="expand link" for="expand-{{this.id1}}">
<i class="fa-solid fa-angle-down"></i>
Details
</label>
<div class="hidden" id="{{this.id2}}">
<div class="lang-wrapper">
<div class="lang-skills">
<div class="caption">
I know:
</div>
<ol>
{{#each this.skills}}
<li>{{{this}}}</li>
{{/each}}
</ol>
</div>
<div class="projects">
{{#each this.projects}}
<div class="repo">
<a target="_blank" href="{{this.url}}">
{{this.name}}
</a>
<div class="stars-icon">
<i class="fa-regular fa-star"></i>
</div>
<div class="stars-num">{{this.stars}}</div>
</div>
{{/each}}
</div>
</div>
</div>
</div>
</div>
</div>
</div>
{{/each}}
</div>
</div>
<div class="hidden" id="selfhosted">
<div class="card">
<div>Hosted on Raspberry Pi 4B</div>
{{#each selfhosted}}
<div>
<div class="icon">
<i class="{{this.icon}}"></i>
</div>
<div class="content">
<a href="https://{{this.domain}}" target="_blank">
{{this.domain}}
</a>
</div>
</div>
{{/each}}
</div>
</div>
</div>
<!-- Context Menu -->
<div class="menu context-menu">
<ul>
{{#each spaceobj}}
<li class="change-img">
<span class="li-wrapper" data-img="{{this.img}}">
<span class="icon">
<i class="{{this.icon}}"></i>
</span>
{{this.name}}
</span>
</li>
{{/each}}
<li class="change-speed">
<span class="li-wrapper">
<span class="icon">
<i class="fas fa-wrench"></i>
</span>
Speed:
<input type="range" min="0" max="1170" step="30" value="720" />
</span>
</li>
<li class="land-to">
<span class="li-wrapper">
<span class="icon">
<i class="fa-solid fa-rocket"></i>
</span>
Land to Earth
</span>
</li>
</ul>
</div>
<!-- JavaScript -->
<script src="js/anim.js"></script>
<script src="js/script.js"></script>
<script src="js/init.js"></script>
<script src="js/menu.js"></script>
<script src="js/control.js"></script>
<script src="js/handlers.js"></script>
</body>
</html>

File diff suppressed because it is too large Load diff

459
space/index.json Normal file
View file

@ -0,0 +1,459 @@
{
"spaceobj": [
{
"img": "img/earth.gif",
"icon": "fas fa-globe-americas",
"name": "Earth"
},
{
"img": "img/moon.gif",
"icon": "fas fa-moon",
"name": "Moon"
},
{
"img": "img/sun.gif",
"icon": "fas fa-sun",
"name": "Sun"
},
{
"img": "img/mars.gif",
"icon": "fa-solid fa-earth-europe",
"name": "Mars"
},
{
"img": "data:image/gif;base64,R0lGODlhAQABAIABAAAAAP///yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==",
"icon": "fa-regular fa-circle-xmark",
"name": "Space"
}
],
"menu": [
{
"id": "about",
"icon": "fa-solid fa-user"
},
{
"id": "code",
"icon": "fa-solid fa-code"
},
{
"id": "selfhosted",
"icon": "fa-solid fa-cube"
}
],
"about": [
{
"icon": "fa-solid fa-calendar-days",
"content": "Birthday: July, 2009 (<span id=\"age-js\"></span>)"
},
{
"icon": "fa-solid fa-location-dot",
"content": "Russia, Ulyanovsk"
},
{
"icon": "fa-solid fa-headphones",
"content": "One Direction<br>Linkin Park<br>Imagine Dragons<br>Pizza"
},
{
"icon": "fa-solid fa-desktop",
"content": "Manjaro KDE",
"expand": {
"id": 1,
"code": "<pre id=\"inxi\"></pre>"
}
}
],
"profiles": [
{
"icon": "fa-brands fa-github",
"url": "https://github.com/DarkCat09",
"name": "GitHub",
"user": "DarkCat09"
},
{
"icon": "fa-brands fa-git-alt",
"url": "https://codeberg.org/DarkCat09",
"name": "Codeberg",
"user": "DarkCat09"
},
{
"icon": "fa-solid fa-envelope",
"url": "mailto:a.chehckenev@yandex.ru",
"name": "E-mail",
"user": "a.chechkenev",
"copy": "a.chechkenev@yandex.ru"
},
{
"icon": "fa-brands fa-telegram",
"url": "https://t.me/darkcat09",
"name": "Telegram",
"user": "@darkcat09"
},
{
"icon": "fa-solid fa-4",
"url": "https://4pda.to/forum/index.php?showuser=8898436",
"name": "4PDA",
"user": "8898436"
},
{
"icon": "fa-brands fa-discord",
"url": "https://discord.com/app",
"name": "Discord",
"user": "DarkCat09#5587",
"copy": "DarkCat09#5587"
}
],
"langs": [
{
"icon": "fa-brands fa-python",
"name": "Python",
"id1": "py",
"id2": "python",
"skills": [
"Basics",
"OOP",
"PEP8, MyPy",
"Unpacking, filter/map",
"List/dict comprehension",
"Flask",
"PyPI packaging",
"Unittests",
"MkDocs",
"Lots of modules"
],
"projects": [
{
"url": "https://github.com/DarkCat09/python-aternos",
"name": "python-aternos",
"stars": 51
},
{
"url": "https://github.com/DarkCat09/python-scripts",
"name": "python-scripts",
"stars": 5
},
{
"url": "https://github.com/DarkCat09/showdialog",
"name": "showdialog",
"stars": 0
},
{
"url": "https://github.com/DarkCat09/randomus",
"name": "randomus",
"stars": 0
},
{
"url": "https://github.com/DarkCat09/knigavuhe",
"name": "knigavuhe",
"stars": 0
},
{
"url": "https://gist.github.com/DarkCat09/1e2d1c79d038392adab5280d79626eab",
"name": "discord bots",
"stars": 1
},
{
"url": "https://gist.github.com/DarkCat09/b53a72d94786aed696372e889a3b7885",
"name": "bb pixel art",
"stars": 1
}
]
},
{
"icon": "fa-brands fa-html5",
"name": "HTML & CSS",
"id1": "css",
"id2": "css",
"skills": [
"<img src=\"https://lesscss.org/public/img/less_logo.png\" alt=\"{less}\">",
"Handlebars",
"HTML, CSS basics",
"Forms, inputs",
"Animations",
"Flexboxes",
"Grid (learning)"
],
"projects": [
{
"url": "https://codeberg.org/DarkCat09/pages-src",
"name": "this page",
"stars": 0
},
{
"url": "https://github.com/DarkCat09/cmdsminew",
"name": "cmdsmine",
"stars": 0
},
{
"url": "https://github.com/DarkCat09/monolight",
"name": "monolight",
"stars": 0
}
]
},
{
"icon": "fa-brands fa-square-js",
"name": "JavaScript",
"id1": "js",
"id2": "js",
"skills": [
"Basics",
"Loops, conditions",
"Sort, filter, etc.",
"Arrow expresions",
"Destructuring",
"Promises, async/await",
"DOM, Event Handlers",
"2D Canvas",
"Handlebars",
"OOP (learning)",
"NodeJS & NPM (learning)"
],
"projects": [
{
"url": "https://codeberg.org/DarkCat09/pages-src",
"name": "this page",
"stars": 0
},
{
"url": "https://codeberg.org/DarkCat09/pages-src/src/branch/main/dc09.js",
"name": "build script (nodejs)",
"stars": 0
},
{
"url": "https://github.com/DarkCat09/monolight",
"name": "monolight",
"stars": 0
}
]
},
{
"svg": true,
"icon": "svg/kotlin.svg",
"name": "Kotlin",
"id1": "kt",
"id2": "kotlin",
"skills": [
"(currently learning)",
"Basics",
"If, when",
"Loops, ranges",
"Lists, Maps",
"OOP, data classes",
"Lambdas, Vararg",
"Null safety operators",
"Android development"
],
"projects": [
{
"url": "https://github.com/DarkCat09/helloapp",
"name": "helloapp",
"stars": 0
},
{
"url": "https://github.com/DarkCat09/replace-input",
"name": "replace-input",
"stars": 0
}
]
},
{
"icon": "fa-solid fa-hashtag",
"name": "CSharp",
"id1": "cs",
"id2": "csharp",
"skills": [
"Syntax",
"Loops, conditions",
"WinForms",
"MySql.Data",
"Tuples, destructuring",
"Null safety operators"
],
"projects": [
{
"url": "https://github.com/DarkCat09/dumptool",
"name": "windows dump tool",
"stars": 0
},
{
"url": "https://github.com/DarkCat09/AchSmartHome",
"name": "AchSmartHome",
"stars": 0
},
{
"url": "https://github.com/DarkCat09/RecurseWinFormsTest",
"name": "recursion example",
"stars": 0
},
{
"url": "https://github.com/DarkCat09/Tariffs",
"name": "tariffs",
"stars": 0
}
]
},
{
"icon": "fa-brands fa-windows",
"name": "VBScript",
"id1": "vbs",
"id2": "vbs",
"skills": [
"Syntax",
"Arrays",
"Loops, conditions",
"Message boxes",
"WScript.Shell",
"FileSystemObject",
"Registry Editing"
],
"projects": [
{
"url": "https://github.com/DarkCat09/vbscripting",
"name": "vbscripting",
"stars": 0
},
{
"url": "https://github.com/DarkCat09/vbs-season-wallpaper",
"name": "season-wallpaper",
"stars": 0
},
{
"url": "https://gist.github.com/DarkCat09/6b7226dc5afea2f4b5c8f6407e323a65",
"name": "add-to-startup",
"stars": 0
},
{
"url": "https://gist.github.com/DarkCat09/5f12095cbef4d299f2b8124410ca3e48",
"name": "winrestart",
"stars": 0
}
]
},
{
"icon": "fa-solid fa-terminal",
"name": "Bash",
"id1": "bash",
"id2": "bash",
"skills": [
"Basics",
"Loops and conditions",
"Functions",
"Crontab",
"Some escape codes",
"Arrays (learning)"
],
"projects": [
{
"url": "https://github.com/DarkCat09/saveyoureyes",
"name": "save-your-eyes",
"stars": 0
},
{
"url": "https://gist.github.com/DarkCat09/cba140c921a5bed7f042e157b2319808",
"name": "1compiler api",
"stars": 0
},
{
"url": "https://gist.github.com/DarkCat09/29e4628664dc53666f0b6242395aeab8",
"name": "bashrc",
"stars": 0
},
{
"url": "https://gist.github.com/DarkCat09/eb40c544a4a722bb3a62d23e8ad418cb",
"name": "floating window",
"stars": 0
}
]
},
{
"icon": "fa-brands fa-java",
"name": "Java",
"id1": "java",
"id2": "java",
"skills": [
"Syntax",
"Loops, conditions",
"Lists, HashMap",
"JavaFX + SceneBuilder",
"Android development"
],
"projects": [
{
"url": "https://github.com/DarkCat09/blockapp",
"name": "blockapp",
"stars": 0
},
{
"url": "https://gist.github.com/DarkCat09/ce7286f7acca79177b440bae9251e819",
"name": "magic substring",
"stars": 0
},
{
"url": "https://github.com/DarkCat09/mtkfwtools",
"name": "mtkfwtools",
"stars": 0
},
{
"url": "https://github.com/DarkCat09/virustotal-gui-fx",
"name": "virustotal-gui-fx",
"stars": 0
}
]
},{
"icon": "fa-brands fa-php",
"name": "PHP",
"id1": "php",
"id2": "php",
"skills": [
"Variables",
"Arrays",
"Conditions, loops",
"Headers",
"Drawing images",
"MySQLi",
"Bcrypt"
],
"projects": [
{
"url": "https://github.com/DarkCat09/englearn",
"name": "englearn",
"stars": 0
}
]
},
{
"icon": "fa-brands fa-android",
"name": "Smali",
"id1": "smali",
"id2": "smali",
"skills": [
"Main syntax",
"Can read non-obfuscated code",
"Can change simple code"
],
"projects": []
}
],
"selfhosted": [
{
"icon": "fa-solid fa-house",
"domain": "dc09.ru"
},
{
"icon": "fa-brands fa-git-alt",
"domain": "git.dc09.ru"
},
{
"icon": "fa-solid fa-link",
"domain": "url.dc09.ru"
},
{
"icon": "fa-solid fa-address-book",
"domain": "sync.dc09.ru"
},
{
"icon": "fa-brands fa-wikipedia-w",
"domain": "wt.dc09.ru"
}
]
}

View file

@ -322,11 +322,6 @@ a {
margin: 0; margin: 0;
padding: 0; padding: 0;
.less-logo {
margin: 0;
padding: 0;
img { img {
margin: 0; margin: 0;
padding: 0; padding: 0;
@ -335,7 +330,6 @@ a {
} }
} }
} }
}
.projects:not(:empty) { .projects:not(:empty) {

View file

@ -1,5 +1,6 @@
{ {
"html": ["index.html"], "html": [],
"hb": ["index.handlebars"],
"less": ["styles.less"], "less": ["styles.less"],
"css": [], "css": [],
"js": [ "js": [