@nzz/q-cli 1.5.1 → 1.5.6
Sign up to get free protection for your applications and to get access to all the features.
- package/.vscode/settings.json +5 -0
- package/README.md +16 -1
- package/bin/commands/bootstrap.js +6 -0
- package/bin/commands/updateItem/helpers.js +52 -18
- package/bin/commands/updateItem/resourcesHelpers.js +4 -2
- package/dev-server/routes/rendering-info.js +0 -1
- package/dev-server/routes/tool-default.js +0 -2
- package/dev-server/server.js +3 -0
- package/package.json +1 -1
- package/skeletons/custom-code-skeleton/.nvmrc +1 -1
- package/skeletons/custom-code-skeleton/.vscode/settings.json +5 -0
- package/skeletons/custom-code-skeleton/package-lock.json +5335 -627
- package/skeletons/custom-code-skeleton/package.json +10 -7
- package/skeletons/custom-code-skeleton/rollup.config.js +63 -17
- package/skeletons/custom-code-skeleton/src/App.scss +3 -0
- package/skeletons/custom-code-skeleton/src/App.svelte +1 -7
- package/skeletons/custom-code-skeleton/src/main-prod.js +1 -0
- package/skeletons/custom-code-skeleton/src/main.js +1 -0
- package/skeletons/custom-code-skeleton/src/main.scss +1 -0
- package/skeletons/server-skeleton/auth/routes.js +0 -9
- package/skeletons/server-skeleton/index.js +1 -3
- package/skeletons/tool-skeleton/.nvmrc +1 -1
- package/skeletons/tool-skeleton/.travis.yml +26 -0
- package/skeletons/tool-skeleton/.vscode/settings.json +5 -0
- package/skeletons/tool-skeleton/Dockerfile +1 -1
- package/skeletons/tool-skeleton/LICENSE +20 -0
- package/skeletons/tool-skeleton/README.md +1 -1
- package/skeletons/tool-skeleton/index.js +1 -6
- package/skeletons/tool-skeleton/package-lock.json +8540 -2741
- package/skeletons/tool-skeleton/package.json +24 -12
- package/skeletons/tool-skeleton/rollup.config.js +75 -0
- package/skeletons/tool-skeleton/routes/fixtures/data.js +1 -3
- package/skeletons/tool-skeleton/routes/rendering-info/web.js +43 -20
- package/skeletons/tool-skeleton/routes/routes.js +1 -1
- package/skeletons/tool-skeleton/routes/script.js +4 -5
- package/skeletons/tool-skeleton/routes/stylesheet.js +4 -5
- package/skeletons/tool-skeleton/sass.config.js +66 -0
- package/skeletons/tool-skeleton/scripts_src/default.js +3 -0
- package/skeletons/tool-skeleton/styles_src/_variables.scss +1 -0
- package/skeletons/tool-skeleton/styles_src/main.scss +2 -0
- package/skeletons/tool-skeleton/test/e2e-tests.js +4 -6
- package/skeletons/tool-skeleton/views/dynamic/YourTool.scss +5 -0
- package/skeletons/tool-skeleton/views/dynamic/YourTool.svelte +19 -0
- package/skeletons/tool-skeleton/views/static/App.scss +5 -0
- package/skeletons/tool-skeleton/views/static/App.svelte +21 -0
- package/skeletons/tool-skeleton/views/static/components/Footer.svelte +31 -0
- package/skeletons/tool-skeleton/views/static/components/Header.svelte +7 -0
- package/skeletons/tool-skeleton/styles_src/default.scss +0 -4
- package/skeletons/tool-skeleton/tasks/build.js +0 -98
@@ -4,7 +4,10 @@
|
|
4
4
|
"description": "",
|
5
5
|
"main": "index.js",
|
6
6
|
"scripts": {
|
7
|
-
"build": "
|
7
|
+
"build": "rollup -c",
|
8
|
+
"autobuild": "rollup -c -w",
|
9
|
+
"dev": "run-p autobuild start",
|
10
|
+
"start": "nodemon index.js",
|
8
11
|
"test": "lab -a @hapi/code -c -P tests --verbose --leaks"
|
9
12
|
},
|
10
13
|
"author": "",
|
@@ -14,20 +17,29 @@
|
|
14
17
|
"url": "https://github.com/github/tool-skeleton.git"
|
15
18
|
},
|
16
19
|
"dependencies": {
|
17
|
-
"@hapi/boom": "^9.1.
|
18
|
-
"@hapi/hapi": "^20.
|
19
|
-
"@hapi/inert": "^6.0.
|
20
|
-
"ajv": "^6.
|
21
|
-
"joi": "^17.4.
|
20
|
+
"@hapi/boom": "^9.1.4",
|
21
|
+
"@hapi/hapi": "^20.2.0",
|
22
|
+
"@hapi/inert": "^6.0.4",
|
23
|
+
"ajv": "^8.6.3",
|
24
|
+
"joi": "^17.4.2",
|
25
|
+
"svelte": "^3.44.2"
|
22
26
|
},
|
23
27
|
"devDependencies": {
|
24
28
|
"@hapi/code": "^8.0.3",
|
25
|
-
"@hapi/lab": "^
|
26
|
-
"
|
27
|
-
"
|
29
|
+
"@hapi/lab": "^24.3.2",
|
30
|
+
"@rollup/plugin-commonjs": "^21.0.0",
|
31
|
+
"@rollup/plugin-node-resolve": "^13.0.5",
|
32
|
+
"autoprefixer": "^10.4.0",
|
33
|
+
"cssnano": "^5.0.10",
|
28
34
|
"glob": "^7.1.7",
|
29
|
-
"
|
30
|
-
"
|
31
|
-
"
|
35
|
+
"nodemon": "^2.0.13",
|
36
|
+
"npm-run-all": "^4.1.5",
|
37
|
+
"postcss": "^8.3.11",
|
38
|
+
"rollup": "^2.60.0",
|
39
|
+
"rollup-plugin-livereload": "^2.0.5",
|
40
|
+
"rollup-plugin-scss": "^3.0.0",
|
41
|
+
"rollup-plugin-svelte": "^7.1.0",
|
42
|
+
"rollup-plugin-terser": "^7.0.2",
|
43
|
+
"sass": "^1.43.4"
|
32
44
|
}
|
33
45
|
}
|
@@ -0,0 +1,75 @@
|
|
1
|
+
import * as fs from "fs";
|
2
|
+
import * as path from "path";
|
3
|
+
import * as crypto from "crypto";
|
4
|
+
import nodeResolve from "@rollup/plugin-node-resolve";
|
5
|
+
import commonjs from "@rollup/plugin-commonjs";
|
6
|
+
import svelte from "rollup-plugin-svelte";
|
7
|
+
import { terser } from "rollup-plugin-terser";
|
8
|
+
import livereload from "rollup-plugin-livereload";
|
9
|
+
import scss from "rollup-plugin-scss";
|
10
|
+
const sassConfig = require("./sass.config");
|
11
|
+
|
12
|
+
const production = !process.env.ROLLUP_WATCH;
|
13
|
+
const scriptsDir = path.join(__dirname, "/scripts_src/");
|
14
|
+
const filename = "default";
|
15
|
+
const scriptDirDefaultFileName = path.join(scriptsDir, `/${filename}.js`);
|
16
|
+
|
17
|
+
function writeHashmap(hashmapPath, file, fileext) {
|
18
|
+
const hash = crypto.createHash("md5");
|
19
|
+
hash.update(file.content, { encoding: "utf8" });
|
20
|
+
file.hash = hash.digest("hex");
|
21
|
+
|
22
|
+
const hashMap = {};
|
23
|
+
hashMap[file.name] = `${file.name}.${file.hash.substring(0, 8)}.${fileext}`;
|
24
|
+
fs.writeFileSync(hashmapPath, JSON.stringify(hashMap));
|
25
|
+
}
|
26
|
+
|
27
|
+
function generateHashmap() {
|
28
|
+
return {
|
29
|
+
name: "generateHashmap",
|
30
|
+
async generateBundle(outputOptions, bundle, isWrite) {
|
31
|
+
const scriptsDir = "scripts";
|
32
|
+
// Create directory if not yet exist or recreate directory if it already exists
|
33
|
+
if (!fs.existsSync(scriptsDir)) {
|
34
|
+
fs.mkdirSync(scriptsDir);
|
35
|
+
} else {
|
36
|
+
fs.rmdirSync(scriptsDir, { recursive: true });
|
37
|
+
fs.mkdirSync(scriptsDir);
|
38
|
+
}
|
39
|
+
writeHashmap(
|
40
|
+
"scripts/hashMap.json",
|
41
|
+
{
|
42
|
+
name: filename,
|
43
|
+
content: bundle[`${filename}.js`].code,
|
44
|
+
},
|
45
|
+
"js"
|
46
|
+
);
|
47
|
+
},
|
48
|
+
};
|
49
|
+
}
|
50
|
+
|
51
|
+
export default {
|
52
|
+
input: scriptDirDefaultFileName,
|
53
|
+
output: {
|
54
|
+
format: "iife",
|
55
|
+
// TODO: Rename 'window._q_your_tool.YourTool' to 'window._q_<tool-name>.<ToolName>'
|
56
|
+
name: "window._q_your_tool.YourTool",
|
57
|
+
file: `scripts/${filename}.js`,
|
58
|
+
},
|
59
|
+
plugins: [
|
60
|
+
svelte(),
|
61
|
+
scss({ ...sassConfig.get(production, writeHashmap) }),
|
62
|
+
nodeResolve({ browser: true }),
|
63
|
+
commonjs(),
|
64
|
+
!production && livereload({ watch: ["scripts"], delay: 800 }),
|
65
|
+
production && terser(),
|
66
|
+
generateHashmap(),
|
67
|
+
],
|
68
|
+
watch: {
|
69
|
+
clearScreen: false,
|
70
|
+
},
|
71
|
+
onwarn: function (warning, warn) {
|
72
|
+
if (warning.code === "CIRCULAR_DEPENDENCY") return;
|
73
|
+
warn(warning);
|
74
|
+
},
|
75
|
+
};
|
@@ -1,7 +1,6 @@
|
|
1
1
|
const fixtureDataDirectory = "../../resources/fixtures/data";
|
2
2
|
|
3
3
|
// provide every fixture data file present in ../../resources/fixtures/data
|
4
|
-
// has to be in sync with files created in build task - see ../../tasks/build.js
|
5
4
|
const fixtureData = [require(`${fixtureDataDirectory}/basic.json`)];
|
6
5
|
|
7
6
|
module.exports = {
|
@@ -9,9 +8,8 @@ module.exports = {
|
|
9
8
|
method: "GET",
|
10
9
|
options: {
|
11
10
|
tags: ["api"],
|
12
|
-
cors: true
|
13
11
|
},
|
14
12
|
handler: (request, h) => {
|
15
13
|
return fixtureData;
|
16
|
-
}
|
14
|
+
},
|
17
15
|
};
|
@@ -1,21 +1,32 @@
|
|
1
1
|
const Boom = require("@hapi/boom");
|
2
2
|
const fs = require("fs");
|
3
3
|
const path = require("path");
|
4
|
+
const Ajv = require("ajv");
|
4
5
|
|
6
|
+
const staticViewsDir = path.join(__dirname, "/../../views/static/");
|
5
7
|
const stylesDir = path.join(__dirname, "/../../styles/");
|
8
|
+
const scriptsDir = path.join(__dirname, "../../scripts/");
|
9
|
+
|
10
|
+
require("svelte/register");
|
11
|
+
const staticTemplate = require(path.join(
|
12
|
+
staticViewsDir,
|
13
|
+
"/App.svelte"
|
14
|
+
)).default;
|
15
|
+
const styles = fs.readFileSync(path.join(stylesDir, "/default.css")).toString();
|
6
16
|
const styleHashMap = require(path.join(stylesDir, "hashMap.json"));
|
17
|
+
const scriptHashMap = require(path.join(scriptsDir, "hashMap.json"));
|
7
18
|
|
8
19
|
// POSTed item will be validated against given schema
|
9
20
|
// hence we fetch the JSON schema...
|
10
21
|
const schemaString = JSON.parse(
|
11
22
|
fs.readFileSync(path.join(__dirname, "../../resources/", "schema.json"), {
|
12
|
-
encoding: "utf-8"
|
23
|
+
encoding: "utf-8",
|
13
24
|
})
|
14
25
|
);
|
15
|
-
const Ajv = require("ajv");
|
16
|
-
const ajv = new Ajv();
|
17
26
|
|
27
|
+
const ajv = new Ajv({ strict: false });
|
18
28
|
const validate = ajv.compile(schemaString);
|
29
|
+
|
19
30
|
function validateAgainstSchema(item, options) {
|
20
31
|
if (validate(item)) {
|
21
32
|
return item;
|
@@ -43,32 +54,44 @@ module.exports = {
|
|
43
54
|
options: {
|
44
55
|
validate: {
|
45
56
|
options: {
|
46
|
-
allowUnknown: true
|
57
|
+
allowUnknown: true,
|
47
58
|
},
|
48
|
-
payload: validatePayload
|
49
|
-
}
|
59
|
+
payload: validatePayload,
|
60
|
+
},
|
50
61
|
},
|
51
|
-
handler: async function(request, h) {
|
52
|
-
const
|
62
|
+
handler: async function (request, h) {
|
63
|
+
const toolRuntimeConfig = request.payload.toolRuntimeConfig;
|
64
|
+
const context = {
|
65
|
+
// TODO: Rename 'q_your_tool_' to 'q_<tool_name>_'
|
66
|
+
id: `q_your_tool_${toolRuntimeConfig.requestId}`,
|
67
|
+
displayOptions: toolRuntimeConfig.displayOptions || {},
|
68
|
+
item: request.payload.item,
|
69
|
+
};
|
70
|
+
|
71
|
+
const staticTemplateRender = staticTemplate.render(context);
|
53
72
|
|
54
73
|
const renderingInfo = {
|
55
74
|
polyfills: ["Promise"],
|
56
|
-
stylesheets: [
|
57
|
-
{
|
58
|
-
name: styleHashMap["default"]
|
59
|
-
}
|
60
|
-
],
|
75
|
+
stylesheets: [{ content: styles }, { name: styleHashMap["default"] }],
|
61
76
|
scripts: [
|
77
|
+
{ name: scriptHashMap["default"] },
|
78
|
+
// TODO: Rename 'new window._q_your_tool.YourTool' to 'new window._q_<tool-name>.<ToolName>'
|
62
79
|
{
|
63
|
-
content:
|
64
|
-
|
65
|
-
|
80
|
+
content: `
|
81
|
+
(function () {
|
82
|
+
var target = document.querySelector('#${context.id}_container');
|
83
|
+
target.innerHTML = "";
|
84
|
+
var props = ${JSON.stringify(context)};
|
85
|
+
new window._q_your_tool.YourTool({
|
86
|
+
"target": target,
|
87
|
+
"props": props
|
88
|
+
})
|
89
|
+
})();`,
|
90
|
+
},
|
66
91
|
],
|
67
|
-
markup:
|
68
|
-
item.subtitle
|
69
|
-
}</h2><p>rendered by tool-skeleton`
|
92
|
+
markup: staticTemplateRender.html,
|
70
93
|
};
|
71
94
|
|
72
95
|
return renderingInfo;
|
73
|
-
}
|
96
|
+
},
|
74
97
|
};
|
@@ -4,15 +4,14 @@ module.exports = {
|
|
4
4
|
method: "GET",
|
5
5
|
path: "/script/{filename}.{hash}.{extension}",
|
6
6
|
options: {
|
7
|
-
cors: true,
|
8
7
|
files: {
|
9
|
-
relativeTo: path.join(__dirname, "/../scripts/")
|
10
|
-
}
|
8
|
+
relativeTo: path.join(__dirname, "/../scripts/"),
|
9
|
+
},
|
11
10
|
},
|
12
|
-
handler: function(request, h) {
|
11
|
+
handler: function (request, h) {
|
13
12
|
return h
|
14
13
|
.file(`${request.params.filename}.${request.params.extension}`)
|
15
14
|
.type("text/javascript")
|
16
15
|
.header("cache-control", `max-age=${60 * 60 * 24 * 365}, immutable`); // 1 year
|
17
|
-
}
|
16
|
+
},
|
18
17
|
};
|
@@ -4,15 +4,14 @@ module.exports = {
|
|
4
4
|
method: "GET",
|
5
5
|
path: "/stylesheet/{filename}.{hash}.{extension}",
|
6
6
|
options: {
|
7
|
-
cors: true,
|
8
7
|
files: {
|
9
|
-
relativeTo: path.join(__dirname, "/../styles/")
|
10
|
-
}
|
8
|
+
relativeTo: path.join(__dirname, "/../styles/"),
|
9
|
+
},
|
11
10
|
},
|
12
|
-
handler: function(request, h) {
|
11
|
+
handler: function (request, h) {
|
13
12
|
return h
|
14
13
|
.file(`${request.params.filename}.${request.params.extension}`)
|
15
14
|
.type("text/css")
|
16
15
|
.header("cache-control", `max-age=${60 * 60 * 24 * 365}, immutable`); // 1 year
|
17
|
-
}
|
16
|
+
},
|
18
17
|
};
|
@@ -0,0 +1,66 @@
|
|
1
|
+
const fs = require("fs");
|
2
|
+
const path = require("path");
|
3
|
+
const postcss = require("postcss");
|
4
|
+
const autoprefixer = require("autoprefixer");
|
5
|
+
const cssnano = require("cssnano");
|
6
|
+
|
7
|
+
function createOutputCssFunction(writeHashmapFunction) {
|
8
|
+
const outputCssFunction = (styles, styleNodes) => {
|
9
|
+
const stylesDir = "styles";
|
10
|
+
|
11
|
+
if (!fs.existsSync(stylesDir)) {
|
12
|
+
fs.mkdirSync(stylesDir);
|
13
|
+
}
|
14
|
+
|
15
|
+
fs.writeFileSync(`styles/default.css`, styles);
|
16
|
+
writeHashmapFunction(
|
17
|
+
"styles/hashMap.json",
|
18
|
+
{
|
19
|
+
name: "default",
|
20
|
+
content: styles,
|
21
|
+
},
|
22
|
+
"css"
|
23
|
+
);
|
24
|
+
};
|
25
|
+
|
26
|
+
return outputCssFunction;
|
27
|
+
}
|
28
|
+
|
29
|
+
function getPostcssPlugins(isProduction) {
|
30
|
+
const postcssPlugins = [autoprefixer];
|
31
|
+
|
32
|
+
if (isProduction) {
|
33
|
+
postcssPlugins.push(cssnano);
|
34
|
+
}
|
35
|
+
|
36
|
+
return postcssPlugins;
|
37
|
+
}
|
38
|
+
|
39
|
+
function get(isProduction, writeHashmapFunction) {
|
40
|
+
const config = {
|
41
|
+
outputStyle: isProduction ? "compressed" : "expanded",
|
42
|
+
// Sourcemap generation (specifically writing the file to system) is currently not supported by rollup-plugin-sass (but soon!)
|
43
|
+
// See: https://github.com/thgh/rollup-plugin-scss/issues/7
|
44
|
+
// outFile: path.join(__dirname, "/styles/default.css"), // <- Uncomment after: https://github.com/thgh/rollup-plugin-scss/issues/7
|
45
|
+
sourceMap: !isProduction,
|
46
|
+
sourceMapEmbed: !isProduction, // Remove after: https://github.com/thgh/rollup-plugin-scss/issues/7
|
47
|
+
failOnError: !isProduction,
|
48
|
+
watch: [
|
49
|
+
path.join(__dirname, "/styles_src"),
|
50
|
+
path.join(__dirname, "/views"),
|
51
|
+
],
|
52
|
+
processor: (css) =>
|
53
|
+
postcss(getPostcssPlugins(isProduction))
|
54
|
+
.process(css, {
|
55
|
+
from: path.join(__dirname, "/styles/default.css"),
|
56
|
+
to: path.join(__dirname, "/styles/default.css"),
|
57
|
+
map: isProduction ? false : { inline: true }, // Set to false after: https://github.com/thgh/rollup-plugin-scss/issues/7
|
58
|
+
})
|
59
|
+
.then((result) => result.css),
|
60
|
+
output: createOutputCssFunction(writeHashmapFunction),
|
61
|
+
};
|
62
|
+
|
63
|
+
return config;
|
64
|
+
}
|
65
|
+
|
66
|
+
module.exports = { get };
|
@@ -0,0 +1 @@
|
|
1
|
+
$color: salmon;
|
@@ -20,9 +20,7 @@ before(async () => {
|
|
20
20
|
try {
|
21
21
|
server = Hapi.server({
|
22
22
|
port: process.env.PORT || 3000,
|
23
|
-
routes: {
|
24
|
-
cors: true,
|
25
|
-
},
|
23
|
+
routes: {},
|
26
24
|
});
|
27
25
|
server.validator(Joi);
|
28
26
|
await server.register(require("@hapi/inert"));
|
@@ -103,7 +101,7 @@ lab.experiment("stylesheets endpoint", () => {
|
|
103
101
|
});
|
104
102
|
|
105
103
|
// all the fixtures render
|
106
|
-
lab.experiment("all fixtures render",
|
104
|
+
lab.experiment("all fixtures render", () => {
|
107
105
|
const fixtureFiles = glob.sync(
|
108
106
|
`${__dirname}/../resources/fixtures/data/*.json`
|
109
107
|
);
|
@@ -143,7 +141,7 @@ lab.experiment("rendering-info", () => {
|
|
143
141
|
});
|
144
142
|
|
145
143
|
lab.experiment("assets", () => {
|
146
|
-
it("
|
144
|
+
it("returns stylesheet", async () => {
|
147
145
|
const fixture = fs.readFileSync(
|
148
146
|
`${__dirname}/../resources/fixtures/data/basic.json`,
|
149
147
|
{ encoding: "utf-8" }
|
@@ -157,7 +155,7 @@ lab.experiment("assets", () => {
|
|
157
155
|
},
|
158
156
|
});
|
159
157
|
const stylesheetRes = await server.inject(
|
160
|
-
`/stylesheet/${res.result.stylesheets[
|
158
|
+
`/stylesheet/${res.result.stylesheets[1].name}`
|
161
159
|
);
|
162
160
|
expect(stylesheetRes.statusCode).to.be.equal(200);
|
163
161
|
});
|
@@ -0,0 +1,19 @@
|
|
1
|
+
<script>
|
2
|
+
// TODO: Rename 'YourTool.svelte' to '<Tool-Name>.svelte' & change all references
|
3
|
+
let isWorkingLabel = "";
|
4
|
+
let i = 0;
|
5
|
+
|
6
|
+
function worksOnClick() {
|
7
|
+
i++;
|
8
|
+
isWorkingLabel = i < 5 ? "is working!" : "is still working!";
|
9
|
+
}
|
10
|
+
</script>
|
11
|
+
|
12
|
+
<!-- Client side code is written/imported inside this component (e.g. Client interaction components) -->
|
13
|
+
<div class="s-font-title">
|
14
|
+
Client-Side code
|
15
|
+
<span class="your-tool__is-working-label">{isWorkingLabel}</span>
|
16
|
+
</div>
|
17
|
+
<button class="s-button s-button--small" on:click={worksOnClick}>
|
18
|
+
Click me!
|
19
|
+
</button>
|
@@ -0,0 +1,21 @@
|
|
1
|
+
<script>
|
2
|
+
import Header from "./components/Header.svelte";
|
3
|
+
import Footer from "./components/Footer.svelte";
|
4
|
+
|
5
|
+
export let item;
|
6
|
+
export let id;
|
7
|
+
export let displayOptions;
|
8
|
+
</script>
|
9
|
+
|
10
|
+
<!-- Static code is written/imported inside 'q-item-container' (e.g. Header, Title components) -->
|
11
|
+
<div class="q-item-container">
|
12
|
+
{#if !displayOptions.hideTitle}
|
13
|
+
<Header title={item.title} />
|
14
|
+
{#if item.subtitle}
|
15
|
+
<div class="s-q-item__subtitle s-font-note">{item.subtitle}</div>
|
16
|
+
{/if}
|
17
|
+
{/if}
|
18
|
+
<!-- TODO: Rename 'q-your-tool-container' to 'q-<tool-name>-container' & change all references -->
|
19
|
+
<div id="{id}_container" class="q-your-tool-container" />
|
20
|
+
<Footer notes={item.notes} sources={item.sources} acronym={item.acronym} />
|
21
|
+
</div>
|
@@ -0,0 +1,31 @@
|
|
1
|
+
<script>
|
2
|
+
export let notes;
|
3
|
+
export let sources;
|
4
|
+
export let acronym;
|
5
|
+
</script>
|
6
|
+
|
7
|
+
<div class="s-q-item__footer">
|
8
|
+
{#if notes}
|
9
|
+
<div class="s-q-item__footer__notes">{notes}</div>
|
10
|
+
{/if}
|
11
|
+
<div class="s-q-item__footer__details">
|
12
|
+
{#if sources && sources.length > 0}
|
13
|
+
<div class="s-q-item__footer__sources">
|
14
|
+
{#if sources.length > 1}Quellen:{:else}Quelle:{/if}
|
15
|
+
{#each sources as source, index}
|
16
|
+
{#if source.text !== ""}
|
17
|
+
{#if source.link && source.link.url && source.link.isValid}<a
|
18
|
+
href={source.link.url}
|
19
|
+
target="blank"
|
20
|
+
rel="noopener noreferrer">{source.text}</a
|
21
|
+
>{:else}{source.text}{/if}{#if index !== sources.length - 1 && sources[index + 1] !== ""}, {/if}{/if}
|
22
|
+
{/each}
|
23
|
+
</div>
|
24
|
+
{/if}
|
25
|
+
{#if acronym}
|
26
|
+
<div class="s-q-item__footer__acronym">NZZ / {acronym}</div>
|
27
|
+
{:else}
|
28
|
+
<div class="s-q-item__footer__acronym">NZZ</div>
|
29
|
+
{/if}
|
30
|
+
</div>
|
31
|
+
</div>
|
@@ -1,98 +0,0 @@
|
|
1
|
-
const fs = require("fs");
|
2
|
-
const path = require("path");
|
3
|
-
const crypto = require("crypto");
|
4
|
-
|
5
|
-
const sass = require("sass");
|
6
|
-
const postcss = require("postcss");
|
7
|
-
const postcssImport = require("postcss-import");
|
8
|
-
const autoprefixer = require("autoprefixer");
|
9
|
-
const cssnano = require("cssnano");
|
10
|
-
|
11
|
-
const stylesDir = path.join(__dirname, "/../styles_src/");
|
12
|
-
|
13
|
-
function writeHashmap(hashmapPath, files, fileext) {
|
14
|
-
const hashMap = {};
|
15
|
-
files
|
16
|
-
.map(file => {
|
17
|
-
const hash = crypto.createHash("md5");
|
18
|
-
hash.update(file.content, { encoding: "utf8" });
|
19
|
-
file.hash = hash.digest("hex");
|
20
|
-
return file;
|
21
|
-
})
|
22
|
-
.map(file => {
|
23
|
-
hashMap[file.name] = `${file.name}.${file.hash.substring(
|
24
|
-
0,
|
25
|
-
8
|
26
|
-
)}.${fileext}`;
|
27
|
-
});
|
28
|
-
|
29
|
-
fs.writeFileSync(hashmapPath, JSON.stringify(hashMap));
|
30
|
-
}
|
31
|
-
|
32
|
-
async function compileStylesheet(name) {
|
33
|
-
return new Promise((resolve, reject) => {
|
34
|
-
const filePath = path.join(stylesDir, `${name}.scss`);
|
35
|
-
fs.access(filePath, fs.constants.R_OK, err => {
|
36
|
-
if (err) {
|
37
|
-
reject(new Error(`stylesheet ${filePath} cannot be read`));
|
38
|
-
process.exit(1);
|
39
|
-
}
|
40
|
-
sass.render(
|
41
|
-
{
|
42
|
-
file: filePath,
|
43
|
-
outputStyle: "compressed"
|
44
|
-
},
|
45
|
-
(err, sassResult) => {
|
46
|
-
if (err) {
|
47
|
-
reject(err);
|
48
|
-
} else {
|
49
|
-
postcss()
|
50
|
-
.use(postcssImport)
|
51
|
-
.use(autoprefixer)
|
52
|
-
.use(cssnano)
|
53
|
-
.process(sassResult.css, {
|
54
|
-
from: path.join(stylesDir, `${name}.css`)
|
55
|
-
})
|
56
|
-
.then(prefixedResult => {
|
57
|
-
if (prefixedResult.warnings().length > 0) {
|
58
|
-
console.log(`failed to compile stylesheet ${name}`);
|
59
|
-
process.exit(1);
|
60
|
-
}
|
61
|
-
resolve(prefixedResult.css);
|
62
|
-
});
|
63
|
-
}
|
64
|
-
}
|
65
|
-
);
|
66
|
-
});
|
67
|
-
});
|
68
|
-
}
|
69
|
-
|
70
|
-
async function buildStyles() {
|
71
|
-
try {
|
72
|
-
// compile styles
|
73
|
-
const styleFiles = [
|
74
|
-
{
|
75
|
-
name: "default",
|
76
|
-
content: await compileStylesheet("default")
|
77
|
-
}
|
78
|
-
];
|
79
|
-
|
80
|
-
styleFiles.map(file => {
|
81
|
-
fs.writeFileSync(`styles/${file.name}.css`, file.content);
|
82
|
-
});
|
83
|
-
|
84
|
-
writeHashmap("styles/hashMap.json", styleFiles, "css");
|
85
|
-
} catch (err) {
|
86
|
-
console.error(err);
|
87
|
-
process.exit(1);
|
88
|
-
}
|
89
|
-
}
|
90
|
-
|
91
|
-
Promise.all([buildStyles()])
|
92
|
-
.then(res => {
|
93
|
-
console.log("build complete");
|
94
|
-
})
|
95
|
-
.catch(err => {
|
96
|
-
console.error(err.message);
|
97
|
-
process.exit(1);
|
98
|
-
});
|