This commit is contained in:
unpregnant 2017-02-14 21:51:02 +01:00
parent 0652c45c18
commit ef04b8e0c7
23 changed files with 326 additions and 206 deletions

0
index.html Executable file → Normal file
View File

View File

@ -9,13 +9,13 @@
"author": "salomonelli",
"homepage": "https://github.com/salomonelli/best-resume-ever",
"scripts": {
"server": "node --harmony-async-await src/server.js",
"less": "node --harmony-async-await src/compileLess.js",
"babel": "babel --presets es2015 src/javascript.js -o public/javascript.js",
"readme": "node --harmony-async-await src/renderReadMe.js",
"server": "node --harmony-async-await src/app.js",
"less": "node --harmony-async-await src/less.js",
"babel": "babel --presets es2015 src/public/javascript.js -o public/javascript.js",
"readme": "node --harmony-async-await src/RenderReadMe.js",
"start": "npm run babel && npm run less && npm run server",
"dev": "watch 'npm start' src/ resumes/ less/",
"pdf": "npm run babel && npm run less && node --harmony-async-await src/htmlToPdf.js"
"pdf": "npm run babel && npm run less && node --harmony-async-await src/ResumeToPdf.js"
},
"dependencies": {
"@typopro/web-montserrat": "3.4.9",

BIN
pdf/resume-grey-boxes.pdf Executable file → Normal file

Binary file not shown.

BIN
pdf/resume-left-right.pdf Executable file → Normal file

Binary file not shown.

BIN
pdf/resume-oblique.pdf Executable file → Normal file

Binary file not shown.

BIN
pdf/resume-side-bar.pdf Executable file → Normal file

Binary file not shown.

BIN
pdf/resume-spotify.pdf Executable file → Normal file

Binary file not shown.

BIN
pdf/resume-wanted.pdf Executable file → Normal file

Binary file not shown.

9
public/javascript.js Executable file → Normal file
View File

@ -56,7 +56,7 @@ var removeBoxShadowOfElement = function removeBoxShadowOfElement(element) {
/**
* gets border radius of element
* @param {HTMLElement} element
* @return {String} e.g. '50%'
* @return {string} e.g. '50%'
*/
var getBorderRadiusOfElement = function getBorderRadiusOfElement(element) {
return window.getComputedStyle(element, null).getPropertyValue('border-radius');
@ -123,10 +123,17 @@ var fixBoxShadows = function fixBoxShadows() {
}
};
/**
* checks if the page contains a resume
* @return {Boolean} true if page contains resume
*/
var isResume = function isResume() {
if (document.getElementsByTagName('page')[0]) return true;else return false;
};
/**
* fixes resume
*/
var fixResume = function fixResume() {
if (!isResume()) return;
getAllDOMElements();

0
public/style.min.css vendored Executable file → Normal file
View File

5
src/Config.js Normal file
View File

@ -0,0 +1,5 @@
const Config = {
port: 3000
};
module.exports = Config;

27
src/RenderReadMe.js Executable file
View File

@ -0,0 +1,27 @@
const showdown = require('showdown');
const converter = new showdown.Converter();
const fs = require('fs');
const path = require('path');
const Mustache = require('mustache');
const writeFile = require('write');
const Util = require('./Util');
/**
* renders readme to html for github Pages
* @return {Promise}
*/
RenderReadMe = async function() {
let dir = path.join(__dirname, '../' + 'README.md');
const readmeContent = await Util.readFileContent(dir);
const readmeHTML = converter.makeHtml(readmeContent);
dir = path.join(__dirname, '../' + 'resumes/views/githubPages.mustache');
const githubPagesTemplate = await Util.readFileContent(dir);
const readme = Mustache.render(githubPagesTemplate, {
content: readmeHTML
});
await Util.writeFile('index.html', readme);
}
RenderReadMe();
module.exports = RenderReadMe;

35
src/ResumeToPdf.js Executable file
View File

@ -0,0 +1,35 @@
const pdf = require('html-pdf');
const path = require('path');
const Config = require('./Config');
const Util = require('./Util');
const Server = require('./Server');
const ResumeToPdf = {
/**
* generates electroshot command for screenshoting resume
* @param {string} resume resume name in URL
* @return {string} electroshot command
*/
electroshotScript: function(resume) {
const dir = path.join(__dirname, '../pdf');
return 'electroshot localhost:3000/' + resume +
' 2481x3508 --pdf-margin none --format pdf --out ' + dir +
' --filename "' + resume + '.pdf" --pdf-background; ';
},
/**
* converts resumes to pdf
* @return {Promise}
*/
convert: async function() {
Server.run();
const directories = Util.getResumesFromDirectories();
let script = '';
directories.forEach(async(resume) => script += ResumeToPdf.electroshotScript(resume.path));
script = script.substring(0, script.length - 2);
await Util.execBash(script);
await Server.kill();
}
}
ResumeToPdf.convert();

83
src/Server.js Executable file
View File

@ -0,0 +1,83 @@
const path = require('path');
const fs = require('fs');
const express = require('express');
const mustacheExpress = require('mustache-express');
const request = require('request-promise');
const Config = require('./Config');
const Util = require('./Util');
const person = require('./person.js');
let app, resumes;
const Server = {
/**
* sets configurations of express app
*/
setup: function() {
if (!app) app = express();
app.set('views', path.join(__dirname, '../resumes'));
app.engine('mustache', require('hogan-express'));
app.set('view engine', 'mustache');
app.use(express.static(path.join(__dirname, '../public')));
app.use(express.static(path.join(__dirname, '../node_modules')));
},
/**
* starts up express app
*/
start: function() {
app.listen(Config.port, '0.0.0.0', () => console.log('Listening on localhost:' + Config.port + '!'));
},
/**
* kills express app
*/
kill: function() {
request.get('http://localhost:' + Config.port + '/kill')
.catch(error => {});
},
/**
* sets route of express app
* @param {string} path e.g. '/' or '/resumes'
* @param {string} template e.g. 'views/resumeX/index'
*/
setRoute: function(path, template) {
app.get(path, (req, res) => {
res.render('views/layout', {
partials: {
content: template
},
resumes: resumes,
person: person
});
});
},
/**
* sets route to kill app
*/
setKillRoute: function() {
app.get('/kill', () => process.exit());
},
/**
* sets routes for each resume
*/
setRoutesForResumes: function() {
const directories = Util.getDirectories();
for (let resume of directories) {
Server.setRoute('/' + resume, resume + '/index');
}
},
/**
* run server
* @return {Promise} resolves when server is running
*/
run: async function() {
resumes = Util.getResumesFromDirectories();
Server.setup();
Server.setRoute('/', 'views/index');
Server.setRoutesForResumes();
Server.setKillRoute();
Server.kill();
await Util.setTimeout(500);
Server.start();
}
}
module.exports = Server;

65
src/StyleCompiler.js Executable file
View File

@ -0,0 +1,65 @@
const less = require('less');
const path = require('path');
const fs = require('fs');
const CleanCSS = require('clean-css');
const writeFile = require('write');
const Util = require('./Util');
const StyleCompiler = {
/**
* compiles less string to css string
* @param {string} lessContent
* @return {string} css
*/
compile: function(lessContent) {
let lessDir = path.join(__dirname, '../less');
return new Promise((res, rej) => {
less.render(lessContent, {
paths: [lessDir, lessDir + '/fonts'],
}, (e, output) => {
if (e) rej(e);
else res(output.css);
});
});
},
/**
* minifies css
* @param {string} css
* @return {string} minified css
*/
minify: function(css) {
return new Promise((res, rej) => {
new CleanCSS().minify(css, (err, output) => {
if (err) rej(err);
else res(output)
});
});
},
/**
* compiles less files to minified css file
* @return {Promise}
*/
run: async function() {
const directories = Util.getResumesFromDirectories();
const styleLess = await Util.readFileContent(path.join(__dirname, '../less/style.less'));
let css = await StyleCompiler.compile(styleLess);
const contents = await Promise.all(
directories
.map(resume => Util.readFileContent(
path.join(__dirname, '../resumes/' + resume.path + '/style.less')
))
);
const compiledContents = await Promise.all(
contents
.map(content => StyleCompiler.compile(content))
);
const ret = compiledContents.reduce((pre, cur) => pre += cur, css);
// minify
const minCSS = await StyleCompiler.minify(ret);
// write file
const p = path.join(__dirname, '../public/style.min.css');
await Util.writeFile(p, minCSS.styles);
}
}
module.exports = StyleCompiler;

86
src/Util.js Normal file
View File

@ -0,0 +1,86 @@
const path = require('path');
const request = require('request-promise');
const writeFile = require('write');
const fs = require('fs');
const Config = require('./Util');
var exec = require('child_process').exec;
const Util = {
/**
* gets directories starting with 'resume-'
* @return {[]}
*/
getDirectories: function() {
const srcpath = path.join(__dirname, '../resumes');
return fs.readdirSync(srcpath)
.filter(file => file.includes('resume-'))
},
/**
* gets resumes names and paths from directories
* @return {Object[]} array with resumes object {path: '', name: ''}
*/
getResumesFromDirectories: function() {
const directories = Util.getDirectories();
let resumes = [];
directories.forEach(dir => {
let name = dir.replace('resume-', '');
resumes.push({
path: dir,
name: name.replace('-', ' ')
})
});
return resumes;
},
/**
* setTimeout as Promise
* @param {number} time time in ms
* @return {Promise}
*/
setTimeout: function(time) {
return new Promise(res => setTimeout(res, time));
},
/**
* reads file of content
* @param {string} dir directory
* @return {Promise}
*/
readFileContent: function(dir) {
return new Promise((res, rej) => {
fs.readFile(dir, 'utf8', (err, template) => {
if (err) rej(err);
else res(template);
});
});
},
/**
* writes content to given file
* @param {string} dir directory
* @param {string} content content of file
* @return {Promise}
*/
writeFile: function(dir, content) {
return new Promise((res, rej) => {
writeFile(dir, content, err => {
if (err) rej(err);
res();
});
});
},
/**
* executes command
* @param {string} script e.g. 'echo "Hello World"'
* @return {Promise}
*/
execBash: function(script) {
return new Promise((res, rej) => {
exec(script,
(error, stdout, stderr) => {
if (error) rej(err);
else res();
});
});
}
}
module.exports = Util;

2
src/app.js Normal file
View File

@ -0,0 +1,2 @@
const Server = require('./Server');
Server.run();

View File

@ -1,70 +0,0 @@
const less = require('less');
const path = require('path');
const fs = require('fs');
const CleanCSS = require('clean-css');
const writeFile = require('write');
const dir = path.join(__dirname, '../resumes');
const directories = getDirectories(dir);
function getDirectories(srcpath) {
return fs.readdirSync(srcpath)
.filter(file => file.includes('resume-'))
}
function compileToCSS(lessContent) {
let lessDir = path.join(__dirname, '../less');
return new Promise((res, rej) => {
less.render(lessContent, {
paths: [lessDir, lessDir + '/fonts'],
}, (e, output) => {
if (e) rej(e);
else res(output.css);
});
});
}
function readFileContent(fileName) {
const dir = path.join(__dirname, '../' + fileName);
return new Promise((res, rej) => {
fs.readFile(dir, 'utf8', (err, template) => {
if (err) rej(err);
else res(template);
});
});
}
function minifyCSS(css) {
return new Promise((res, rej) => {
new CleanCSS().minify(css, (err, output) => {
if (err) rej(err);
else res(output)
});
});
}
async function compileLessFiles() {
const styleLess = await readFileContent('less/style.less');
let css = await compileToCSS(styleLess);
const contents = await Promise.all(
directories
.map(resume => readFileContent('resumes/' + resume + '/style.less'))
);
const compiledContents = await Promise.all(
contents
.map(content => compileToCSS(content))
);
const ret = compiledContents.reduce((pre, cur) => pre += cur, css);
// minify
const minCSS = await minifyCSS(ret);
// write file
const p = path.join(__dirname, '../public/style.min.css');
writeFile(p, minCSS.styles, err => {
if (err) console.log(err);
});
}
compileLessFiles();

View File

@ -1,38 +0,0 @@
const person = require('./person.js');
const Mustache = require('mustache');
const pdf = require('html-pdf');
const fs = require('fs');
const path = require('path');
var exec = require('child_process').exec;
const dir = path.join(__dirname, '../resumes');
const directories = getDirectories(dir);
const request = require('request-promise');
const port = 3000;
require('./server');
function getDirectories(srcpath) {
return fs.readdirSync(srcpath)
.filter(file => file.includes('resume-'))
}
async function convertToPdf() {
let script = '';
let dir = path.join(__dirname, '../pdf');
directories.forEach(async(resume) => {
script += 'electroshot localhost:3000/' + resume +
' 2481x3508 --pdf-margin none --format pdf --out ' + dir +
' --filename "' + resume + '.pdf" --pdf-background; ';
});
script = script.substring(0, script.length - 2);
exec(script,
(error, stdout, stderr) => {
if (error) console.log(error);
else console.log(stderr);
request.get('http://localhost:' + port + '/kill')
.catch(error => {});
});
}
convertToPdf();

2
src/less.js Normal file
View File

@ -0,0 +1,2 @@
const StyleCompiler = require('./StyleCompiler');
StyleCompiler.run();

View File

@ -60,7 +60,7 @@ const removeBoxShadowOfElement = element => {
/**
* gets border radius of element
* @param {HTMLElement} element
* @return {String} e.g. '50%'
* @return {string} e.g. '50%'
*/
const getBorderRadiusOfElement = element => {
return window
@ -128,11 +128,18 @@ const fixBoxShadows = () => {
}
}
/**
* checks if the page contains a resume
* @return {Boolean} true if page contains resume
*/
const isResume = () => {
if (document.getElementsByTagName('page')[0]) return true;
else return false;
}
/**
* fixes resume
*/
const fixResume = () => {
if (!isResume()) return;
getAllDOMElements();

View File

@ -1,31 +0,0 @@
const showdown = require('showdown');
const converter = new showdown.Converter();
const fs = require('fs');
const path = require('path');
const Mustache = require('mustache');
const writeFile = require('write');
function readFileContent(fileName) {
const dir = path.join(__dirname, '../' + fileName);
return new Promise((res, rej) => {
fs.readFile(dir, 'utf8', (err, template) => {
if (err) rej(err);
else res(template);
});
});
}
async function renderReadMe() {
const readmeContent = await readFileContent('README.md');
const readmeHTML = converter.makeHtml(readmeContent);
const githubPagesTemplate = await readFileContent('resumes/views/githubPages.mustache');
const readme = Mustache.render(githubPagesTemplate, {
content: readmeHTML
});
writeFile('index.html', readme, err => {
if (err) console.log(err)
else console.log('Github pages index.html was successfully generated from README.');
});
}
renderReadMe();

View File

@ -1,60 +0,0 @@
const path = require('path');
const fs = require('fs');
const person = require('./person.js');
const express = require('express');
const mustacheExpress = require('mustache-express');
const request = require('request-promise');
const port = 3000;
let app = express();
app.set('views', path.join(__dirname, '../resumes'));
app.engine('mustache', require('hogan-express'));
app.set('view engine', 'mustache');
app.use(express.static(path.join(__dirname, '../public')));
app.use(express.static(path.join(__dirname, '../node_modules')));
const dir = path.join(__dirname, '../resumes');
const directories = getDirectories(dir);
function getDirectories(srcpath) {
return fs.readdirSync(srcpath)
.filter(file => file.includes('resume-'))
}
let resumes = [];
directories.forEach(dir => {
let name = dir.replace('resume-', '');
resumes.push({
path: dir,
name: name.replace('-', ' ')
})
});
app.get('/', (req, res) => {
res.render('views/layout', {
partials: {
content: 'views/index'
},
resumes: resumes
});
});
app.get('/kill', () => process.exit());
for (let resume of directories) {
app.get('/' + resume, (req, res) => {
res.render('views/layout', {
partials: {
content: resume + '/index'
},
person: person
});
});
}
request.get('http://localhost:' + port + '/kill')
.catch(error => {});
setTimeout(() => {
app.listen(port, '0.0.0.0', () => console.log('Listening on localhost:' + port + '!'));
}, 500);