shellfie 1.3.3 → 1.3.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +7 -0
- package/package.json +2 -2
- package/shellfie.js +93 -81
package/README.md
CHANGED
|
@@ -41,6 +41,13 @@ outputs:
|
|
|
41
41
|
<img src="./shellfies/shellfie.png" />
|
|
42
42
|
|
|
43
43
|
|
|
44
|
+
### Apple Silicon
|
|
45
|
+
```bash
|
|
46
|
+
# NOTE! if you are running on Apple Silicon you may need to set the following env variables:
|
|
47
|
+
export PUPPETEER_EXECUTABLE_PATH=`which chromium`
|
|
48
|
+
export PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=true
|
|
49
|
+
```f
|
|
50
|
+
|
|
44
51
|
# data
|
|
45
52
|
**type**: `string[]` || `string`
|
|
46
53
|
**description**: string data to output to the terminal
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "shellfie",
|
|
3
|
-
"version": "1.3.
|
|
3
|
+
"version": "1.3.7",
|
|
4
4
|
"description": "create beautiful terminal screenshots programmatically",
|
|
5
5
|
"main": "shellfie.js",
|
|
6
6
|
"directories": {
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
"author": "Tal Hayut",
|
|
25
25
|
"license": "MIT",
|
|
26
26
|
"dependencies": {
|
|
27
|
-
"puppeteer": "
|
|
27
|
+
"puppeteer": "latest",
|
|
28
28
|
"xterm": "^4.14.1",
|
|
29
29
|
"xterm-addon-fit": "^0.5.0"
|
|
30
30
|
},
|
package/shellfie.js
CHANGED
|
@@ -5,98 +5,110 @@ const fs = require('fs').promises;
|
|
|
5
5
|
const { getStyles } = require('./utils/styles');
|
|
6
6
|
|
|
7
7
|
async function shellfie(data, config) {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
8
|
+
try {
|
|
9
|
+
if (!data || data.length === 0) {
|
|
10
|
+
throw new Error('no data provided.\nshelffie needs a string || string[] to produce an image.');
|
|
11
|
+
}
|
|
12
|
+
const localPath = process.env.INIT_CWD || process.cwd();
|
|
13
|
+
const {
|
|
14
|
+
name,
|
|
15
|
+
location,
|
|
16
|
+
style,
|
|
17
|
+
theme,
|
|
18
|
+
ext,
|
|
19
|
+
puppeteerOptions,
|
|
20
|
+
viewport,
|
|
21
|
+
mode,
|
|
22
|
+
rendererType
|
|
23
|
+
} = getConfig(config,localPath);
|
|
24
|
+
const browser = await puppeteer.launch(puppeteerOptions);
|
|
25
|
+
const page = await browser.newPage();
|
|
16
26
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
27
|
+
await page.setViewport({ ...viewport, deviceScaleFactor: 4 });
|
|
28
|
+
// read html template
|
|
29
|
+
const templatePath = __dirname + '/template/template.html';
|
|
30
|
+
let html = await fs.readFile(templatePath, 'utf-8');
|
|
31
|
+
const lines = Array.isArray(data) || mode === 'raw' ? data : data.split('\n');
|
|
22
32
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
33
|
+
// inject js scripts
|
|
34
|
+
await page.addScriptTag({ path: require.resolve('xterm/lib/xterm.js') });
|
|
35
|
+
await page.addScriptTag({ path: require.resolve('xterm-addon-fit/lib/xterm-addon-fit.js') });
|
|
26
36
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
// setup terminal
|
|
33
|
-
await page.evaluate(({ options, lines, mode, viewport }) => {
|
|
34
|
-
const fit = new FitAddon.FitAddon();
|
|
35
|
-
const term = new Terminal({ ...options });
|
|
36
|
-
term.open(document.getElementById('terminal'));
|
|
37
|
-
term.loadAddon(fit);
|
|
38
|
-
term.writeln('');
|
|
39
|
-
|
|
40
|
-
if (mode === 'default') {
|
|
41
|
-
lines.forEach(line => {
|
|
42
|
-
line = line.replace(/\\x1.?\[/g, "\x1b[");
|
|
43
|
-
line = `${line}\x1b[0m`;
|
|
44
|
-
term.writeln(line);
|
|
45
|
-
});
|
|
46
|
-
} else {
|
|
47
|
-
if (Array.isArray(lines)) {
|
|
48
|
-
lines = lines.length > 1 ? lines : lines[0]
|
|
49
|
-
}
|
|
50
|
-
lines = lines.replace(/\n/g, '\r\n');
|
|
51
|
-
term.write(lines.trim());
|
|
52
|
-
}
|
|
53
|
-
const height = viewport.height - 60;
|
|
54
|
-
document.querySelector('.xterm-screen').style.width = `${viewport.width}px`;
|
|
55
|
-
document.querySelector('.xterm-screen').style.height = `${height}px`;
|
|
56
|
-
fit.fit();
|
|
37
|
+
// set page html
|
|
38
|
+
await page.setContent(html);
|
|
39
|
+
await page.waitForSelector('.main');
|
|
40
|
+
page.on('console', (txt) => console.log(txt.text()));
|
|
57
41
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
const
|
|
42
|
+
// setup terminal
|
|
43
|
+
await page.evaluate(
|
|
44
|
+
({ options, lines, mode, viewport }) => {
|
|
45
|
+
const fit = new FitAddon.FitAddon();
|
|
46
|
+
const term = new Terminal({ ...options, convertEol: true });
|
|
47
|
+
term.open(document.getElementById('terminal'));
|
|
48
|
+
term.loadAddon(fit);
|
|
49
|
+
term.writeln('');
|
|
62
50
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
51
|
+
if (mode === 'default') {
|
|
52
|
+
lines.forEach((line) => {
|
|
53
|
+
line = line.replace(/\\x1.?\[/g, "\x1b[");
|
|
54
|
+
line = `${line}\x1b[0m`;
|
|
55
|
+
term.writeln(line);
|
|
56
|
+
});
|
|
57
|
+
} else {
|
|
58
|
+
if (Array.isArray(lines)) {
|
|
59
|
+
lines = lines.length > 1 ? lines : lines[0];
|
|
60
|
+
}
|
|
61
|
+
lines = lines.replace(/\n/g, '\r\n');
|
|
62
|
+
term.write(lines.trim());
|
|
69
63
|
}
|
|
64
|
+
const height = viewport.height - 60;
|
|
65
|
+
document.querySelector('.xterm-screen').style.width = `${viewport.width}px`;
|
|
66
|
+
document.querySelector('.xterm-screen').style.height = `${height}px`;
|
|
67
|
+
fit.fit();
|
|
68
|
+
},
|
|
69
|
+
{ lines, mode, options: { theme, rendererType }, viewport }
|
|
70
|
+
);
|
|
70
71
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
await page.addStyleTag({ path: `${localPath}/node_modules/xterm/css/xterm.css` });
|
|
74
|
-
|
|
72
|
+
await page.evaluate((theme) => (document.querySelector('.terminal').style.background = theme.background), theme);
|
|
73
|
+
const templateStyle = __dirname + '/template/template.css';
|
|
75
74
|
|
|
75
|
+
// inject user style
|
|
76
|
+
if (style) {
|
|
77
|
+
const styles = getStyles(style);
|
|
78
|
+
const className = rendererType === 'dom' ? '.terminal.xterm' : 'canvas';
|
|
79
|
+
const content = `${className} {${styles}}`;
|
|
80
|
+
await page.addStyleTag({ content });
|
|
81
|
+
}
|
|
76
82
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
const clip = await (await page.$(".main")).boundingBox();
|
|
81
|
-
clip.height = Math.min(clip.height, page.viewport().height);
|
|
82
|
-
clip.width = Math.min(clip.width, page.viewport().width);
|
|
83
|
+
// inject styles
|
|
84
|
+
await page.addStyleTag({ path: templateStyle });
|
|
85
|
+
await page.addStyleTag({ path: `${localPath}/node_modules/xterm/css/xterm.css` });
|
|
83
86
|
|
|
84
|
-
|
|
87
|
+
await page.evaluateHandle('document.fonts.ready');
|
|
85
88
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
89
|
+
// crop image
|
|
90
|
+
const clip = await (await page.$('.main')).boundingBox();
|
|
91
|
+
clip.height = Math.min(clip.height, page.viewport().height);
|
|
92
|
+
clip.width = Math.min(clip.width, page.viewport().width);
|
|
90
93
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
94
|
+
await page.evaluate((height) => (document.querySelector('.main').style.height = height), clip.height);
|
|
95
|
+
|
|
96
|
+
// create shellfies dir
|
|
97
|
+
const pngsDir = path.resolve(location);
|
|
98
|
+
const exists = await fs
|
|
99
|
+
.access(pngsDir)
|
|
100
|
+
.then(() => 1)
|
|
101
|
+
.catch(() => 0);
|
|
102
|
+
if (!exists) await fs.mkdir(pngsDir);
|
|
100
103
|
|
|
104
|
+
// take screenshot
|
|
105
|
+
await page.screenshot({ path: `${pngsDir}/${name}.${ext}`, clip, omitBackground: true, type: ext });
|
|
106
|
+
await browser.close();
|
|
107
|
+
} catch (err) {
|
|
108
|
+
console.error(new Error(`\x1b[32mshellfie error: ${err.message}\x1b[0m`));
|
|
109
|
+
console.error(err.stack);
|
|
110
|
+
throw err;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
101
113
|
|
|
102
|
-
module.exports = shellfie
|
|
114
|
+
module.exports = shellfie;
|