UPDATE export from electroshot to puppeteer
0
.travis.yml
Normal file → Executable file
6
DEVELOPER.md
Normal file → Executable file
@ -31,7 +31,9 @@ Your new resume will be now reachable at localhost:8080/#/resume/TEMPLATE-NAME.
|
||||
<br>
|
||||
<br>
|
||||
|
||||
4. Generate previews with `npm run preview`. PDF- and PNG-files will be generated.
|
||||
5. Export resumes as PDF with `npm run export`. Verify export of new template.
|
||||
|
||||
4. Generate previews by converting PDF-files to PNG-files with `npm run preview`.
|
||||
|
||||
5. Add preview to `/src/pages/home.vue`:
|
||||
```javascript
|
||||
@ -73,7 +75,7 @@ All fonts are installed via npm. To add a new font, search for the associated np
|
||||
|
||||
## Export
|
||||
|
||||
Resumes are being exported with [Electroshot](https://github.com/mixu/electroshot).
|
||||
Resumes are being exported with [Puppeteer](https://github.com/GoogleChrome/puppeteer).
|
||||
|
||||
### Box Shadows
|
||||
|
||||
|
||||
0
ISSUE_TEMPLATE.md
Normal file → Executable file
0
LICENCE.md
Normal file → Executable file
0
PULL_REQUEST_TEMPLATE.md
Normal file → Executable file
@ -68,8 +68,8 @@ Feel free to add your own templates, language supports, fix bugs or improve the
|
||||
This project uses several open source packages:
|
||||
|
||||
* <a href="https://github.com/vuejs/vue" target="_blank">Vue</a>
|
||||
* <a href="https://github.com/GoogleChrome/puppeteer" target="_blank">Puppeteer</a>
|
||||
* <a href="https://github.com/less/less.js" target="_blank">LESS</a>
|
||||
* <a href="https://github.com/mixu/electroshot" target="_blank">Electroshot</a>
|
||||
|
||||
<br>
|
||||
|
||||
|
||||
0
build/webpack.prod.conf.js
Normal file → Executable file
33
node/app.js
@ -1,7 +1,8 @@
|
||||
const puppeteer = require('puppeteer');
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const exec = require('child_process').exec;
|
||||
const Rx = require('rxjs/Rx');
|
||||
const isRoot = require('is-root');
|
||||
const http = require('http');
|
||||
|
||||
const fetchResponse = () => {
|
||||
@ -36,26 +37,28 @@ const timedOut = timeout => {
|
||||
};
|
||||
|
||||
const convert = async() => {
|
||||
if(isRoot()) {
|
||||
console.log('ERROR: Please run this without root (admin) permissions.');
|
||||
return;
|
||||
}
|
||||
await waitForServerReachable().first().toPromise();
|
||||
console.log('Connected to server ...');
|
||||
console.log('Exporting ...');
|
||||
try {
|
||||
const directories = getResumesFromDirectories();
|
||||
const scripts = directories.map(resume => electroshotScript(resume.path));
|
||||
await execBash(scripts.join(' && '));
|
||||
directories.forEach(async(dir) => {
|
||||
const browser = await puppeteer.launch();
|
||||
const page = await browser.newPage();
|
||||
await page.goto('http://localhost:8080/#/resume/' + dir.name, {waitUntil: 'networkidle'});
|
||||
await page.pdf({path: path.join(__dirname, '../pdf/' + dir.name + '.pdf'), format: 'A4'});
|
||||
await browser.close();
|
||||
});
|
||||
} catch (err) {
|
||||
throw new Error(err);
|
||||
}
|
||||
console.log('Finished exports.');
|
||||
};
|
||||
|
||||
const electroshotScript = resume => {
|
||||
const dir = path.join(__dirname, '../pdf');
|
||||
return 'electroshot localhost:8080/#/resume/' + resume +
|
||||
' 2481x3508 --pdf-margin none --format pdf --out ' + dir +
|
||||
' --filename "' + resume + '.pdf" --pdf-background';
|
||||
};
|
||||
|
||||
const getResumesFromDirectories = () => {
|
||||
const directories = getDirectories();
|
||||
return directories
|
||||
@ -74,14 +77,4 @@ const getDirectories = () => {
|
||||
.filter(file => file !== 'resumes.js' && file !== 'template.vue');
|
||||
};
|
||||
|
||||
const execBash = script => {
|
||||
return new Promise((resolve, reject) => {
|
||||
exec(script,
|
||||
error => {
|
||||
if (error) reject(error);
|
||||
else resolve();
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
convert();
|
||||
|
||||
0
node/preview.js
Normal file → Executable file
@ -13,7 +13,7 @@
|
||||
"build": "node build/build.js",
|
||||
"start": "node build/dev-server.js",
|
||||
"pdf": "node node/app.js",
|
||||
"preview": "npm run export && node node/preview.js",
|
||||
"preview": "node node/preview.js",
|
||||
"template": "node node/template/template.js",
|
||||
"export": "concurrently \"npm run dev\" \"npm run pdf\" --success first --kill-others --raw",
|
||||
"lint": "eslint --ext .js,.vue src test/unit/specs test/e2e/specs"
|
||||
@ -46,7 +46,6 @@
|
||||
"copy-webpack-plugin": "^4.0.1",
|
||||
"cpx": "^1.5.0",
|
||||
"css-loader": "^0.28.0",
|
||||
"electroshot": "^1.4.0",
|
||||
"eslint": "^4.6.1",
|
||||
"eslint-config-standard": "^10.2.1",
|
||||
"eslint-friendly-formatter": "^3.0.0",
|
||||
@ -64,6 +63,7 @@
|
||||
"html-webpack-plugin": "^2.30.1",
|
||||
"http": "0.0.0",
|
||||
"http-proxy-middleware": "^0.17.3",
|
||||
"is-root": "^1.0.0",
|
||||
"less": "^2.7.2",
|
||||
"less-loader": "^4.0.5",
|
||||
"lolex": "^1.5.2",
|
||||
@ -74,6 +74,7 @@
|
||||
"pdf-image": "^1.1.0",
|
||||
"postcss": "^6.0.11",
|
||||
"postcss-cssnext": "^2.11.0",
|
||||
"puppeteer": "^0.12.0",
|
||||
"rename": "^1.0.4",
|
||||
"request": "^2.81.0",
|
||||
"request-promise": "^4.2.1",
|
||||
@ -94,7 +95,7 @@
|
||||
"webpack-merge": "^4.1.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 7.4.0",
|
||||
"node": ">= 8.0.0",
|
||||
"npm": ">= 5.0.0"
|
||||
}
|
||||
}
|
||||
|
||||
BIN
pdf/oblique.pdf
BIN
pdf/purple.pdf
BIN
pdf/side-bar.pdf
0
src/assets/logo.png
Normal file → Executable file
|
Before Width: | Height: | Size: 46 KiB After Width: | Height: | Size: 46 KiB |
|
Before Width: | Height: | Size: 61 KiB After Width: | Height: | Size: 61 KiB |
|
Before Width: | Height: | Size: 54 KiB After Width: | Height: | Size: 54 KiB |
|
Before Width: | Height: | Size: 38 KiB After Width: | Height: | Size: 38 KiB |
|
Before Width: | Height: | Size: 68 KiB After Width: | Height: | Size: 31 KiB |
|
Before Width: | Height: | Size: 53 KiB After Width: | Height: | Size: 53 KiB |
|
Before Width: | Height: | Size: 53 KiB After Width: | Height: | Size: 53 KiB |
0
src/assets/profile-images/girl.png
Normal file → Executable file
|
Before Width: | Height: | Size: 88 KiB After Width: | Height: | Size: 88 KiB |
0
src/assets/profile-images/guy.png
Normal file → Executable file
|
Before Width: | Height: | Size: 78 KiB After Width: | Height: | Size: 78 KiB |
0
src/lang/cn.js
Normal file → Executable file
0
src/lang/de.js
Normal file → Executable file
0
src/lang/en.js
Normal file → Executable file
0
src/lang/es.js
Normal file → Executable file
0
src/lang/fr.js
Normal file → Executable file
0
src/lang/he.js
Normal file → Executable file
0
src/lang/hu.js
Normal file → Executable file
0
src/lang/id.js
Normal file → Executable file
0
src/lang/it.js
Normal file → Executable file
0
src/lang/ja.js
Normal file → Executable file
0
src/lang/nl.js
Normal file → Executable file
0
src/lang/pl.js
Normal file → Executable file
0
src/lang/pt-br.js
Normal file → Executable file
0
src/lang/pt.js
Normal file → Executable file
0
src/lang/ru.js
Normal file → Executable file
0
src/lang/sv.js
Normal file → Executable file
0
src/lang/th.js
Normal file → Executable file
@ -1,49 +0,0 @@
|
||||
|
||||
const getElements = elements => {
|
||||
if (elements && elements.length > 0) return elements;
|
||||
elements = document.getElementsByTagName('*');
|
||||
let ret = [];
|
||||
for (const element of elements) {
|
||||
const style = window.getComputedStyle(element, null).getPropertyValue('box-shadow');
|
||||
if (style !== 'none') {
|
||||
element.style.boxShadow = 'none';
|
||||
ret.push({
|
||||
shadow: style,
|
||||
top: element.offsetTop + 'px',
|
||||
left: element.offsetLeft + 'px',
|
||||
width: element.getBoundingClientRect().width + 'px',
|
||||
height: element.getBoundingClientRect().height + 'px'
|
||||
});
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
};
|
||||
|
||||
const generateElements = elements => {
|
||||
let ret = '<div id="chrome-shadow-fixer">';
|
||||
elements.forEach((el, i) => (ret += '<div id="chrome-shadow-fixer-' + i + '"></div>'));
|
||||
ret += '</div>';
|
||||
return ret;
|
||||
};
|
||||
|
||||
export const fix = elements => {
|
||||
const elementsWithShadows = getElements(elements);
|
||||
if (elementsWithShadows.length < 1) {
|
||||
console.warn('fixShadows(): No elements to fix shadows.');
|
||||
return;
|
||||
}
|
||||
const generatedElements = generateElements(elementsWithShadows);
|
||||
document.body.innerHTML += generatedElements;
|
||||
elementsWithShadows.forEach((el, i) => {
|
||||
const element = document.querySelector('#chrome-shadow-fixer-' + i);
|
||||
element.style.height = el.height;
|
||||
element.style.width = el.width;
|
||||
element.style.left = el.left;
|
||||
element.style.top = el.top;
|
||||
element.style.position = 'absolute';
|
||||
element.style.boxShadow = el.shadow;
|
||||
element.style['-webkit-print-color-adjust'] = 'exact';
|
||||
element.style['-webkit-filter'] = 'opacity(1)';
|
||||
});
|
||||
return elementsWithShadows;
|
||||
};
|
||||
@ -10,18 +10,9 @@
|
||||
|
||||
<script>
|
||||
import Vue from 'vue';
|
||||
// import * as chromeShadowFixer from 'chrome-shadow-fixer';
|
||||
import * as chromeShadowFixer from './chromeShadowFixer';
|
||||
import '../resumes/resumes';
|
||||
export default Vue.component('resume', {
|
||||
name: 'app',
|
||||
mounted: () => {
|
||||
const els = chromeShadowFixer.fix();
|
||||
if (
|
||||
els &&
|
||||
els.length > 0
|
||||
) window.onhashchange = () => { location.reload(); };
|
||||
}
|
||||
name: 'app'
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||