@caweb/webpack 1.3.16 → 1.3.18
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/changelog.txt +6 -0
- package/package.json +3 -3
- package/plugins/html/changelog.txt +6 -0
- package/plugins/html/package-lock.json +2 -10
- package/plugins/html/package.json +4 -4
- package/plugins/html/sample/default.html +22 -0
- package/plugins/jshint/.customrc +29 -0
- package/plugins/jshint/README.md +1 -3
- package/plugins/jshint/changelog.txt +3 -0
- package/plugins/jshint/index.js +10 -15
- package/plugins/jshint/package-lock.json +23886 -1212
- package/plugins/jshint/package.json +10 -5
- package/plugins/jshint/reporter.cjs +121 -483
- package/plugins/jshint/scripts/webpack.test.js +18 -0
- package/plugins/jshint/sample/jshint.css +0 -247
- package/plugins/jshint/sample/jshint.html +0 -7
- package/plugins/jshint/sample/jshint.js +0 -25
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@caweb/jshint-webpack-plugin",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.0",
|
|
4
4
|
"description": "CAWebPublishing Webpack Plugin to run JSHint",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "index.js",
|
|
@@ -12,6 +12,9 @@
|
|
|
12
12
|
"README.md"
|
|
13
13
|
],
|
|
14
14
|
"scripts": {
|
|
15
|
+
"webpack": "webpack",
|
|
16
|
+
"build": "webpack build --config node_modules/@caweb/html-webpack-plugin/webpack.config.js",
|
|
17
|
+
"serve": "set NODE_OPTIONS='--no-audit --no-a11y --no-jshint' && webpack serve --config node_modules/@caweb/html-webpack-plugin/webpack.config.js ./scripts/webpack.test.js --merge",
|
|
15
18
|
"test": "echo \"Error: run tests from root\" && exit 0"
|
|
16
19
|
},
|
|
17
20
|
"author": "CAWebPublishing",
|
|
@@ -35,11 +38,13 @@
|
|
|
35
38
|
],
|
|
36
39
|
"dependencies": {
|
|
37
40
|
"get-all-files": "^5.0.0",
|
|
41
|
+
"handlebars": "^4.7.8",
|
|
38
42
|
"html-format": "^1.1.7",
|
|
39
|
-
"jshint": "^2.13.6"
|
|
43
|
+
"jshint": "^2.13.6",
|
|
44
|
+
"webpack": "^5.97.1",
|
|
45
|
+
"webpack-cli": "^6.0.1"
|
|
40
46
|
},
|
|
41
|
-
"
|
|
42
|
-
"webpack": "^5.
|
|
43
|
-
"webpack-cli": "^5.1.4"
|
|
47
|
+
"peerDependencies": {
|
|
48
|
+
"@caweb/html-webpack-plugin": "^1.5.19"
|
|
44
49
|
}
|
|
45
50
|
}
|
|
@@ -2,6 +2,22 @@
|
|
|
2
2
|
const path = require('path');
|
|
3
3
|
const fs = require('fs');
|
|
4
4
|
const htmlFormat = require('html-format');
|
|
5
|
+
const HandleBars = require('handlebars');
|
|
6
|
+
|
|
7
|
+
const endsWith = require('@caweb/html-webpack-plugin/helpers/logic/endsWith.js');
|
|
8
|
+
|
|
9
|
+
const templateDir = path.resolve('node_modules', '@caweb', 'html-webpack-plugin', 'sample' );
|
|
10
|
+
|
|
11
|
+
let templatePartials = {
|
|
12
|
+
'header': 'structural/header.html',
|
|
13
|
+
'footer': 'structural/footer.html',
|
|
14
|
+
'../components/alerts.html': 'components/alerts.html',
|
|
15
|
+
'./utility-header.html': 'structural/utility-header.html',
|
|
16
|
+
'./branding.html': 'structural/branding.html',
|
|
17
|
+
'./mobile-controls.html': 'structural/mobile-controls.html',
|
|
18
|
+
'./navigation.html': 'structural/navigation.html',
|
|
19
|
+
'./search.html': 'structural/search.html'
|
|
20
|
+
}
|
|
5
21
|
|
|
6
22
|
let sortedReport = {
|
|
7
23
|
errors: [],
|
|
@@ -9,106 +25,10 @@ let sortedReport = {
|
|
|
9
25
|
info: []
|
|
10
26
|
};
|
|
11
27
|
|
|
12
|
-
let title = process.cwd().split('\\').pop()
|
|
28
|
+
let title = `JSHint Report for ${process.cwd().split('\\').pop()}`;
|
|
13
29
|
|
|
14
30
|
let output = [];
|
|
15
31
|
|
|
16
|
-
/**
|
|
17
|
-
* Adds Head to output.
|
|
18
|
-
*/
|
|
19
|
-
function addHead(){
|
|
20
|
-
|
|
21
|
-
output.push(
|
|
22
|
-
'<head>',
|
|
23
|
-
'<meta charset="UTF-8">',
|
|
24
|
-
'<meta name="viewport" content="width=device-width, initial-scale=1.0">',
|
|
25
|
-
`<title>JSHint Report for ${title}</title>`,
|
|
26
|
-
'<script src="./jshint.js"></script>',
|
|
27
|
-
'<link rel="stylesheet" href="./jshint.css">',
|
|
28
|
-
'</head>'
|
|
29
|
-
)
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
/**
|
|
33
|
-
* Adds Header to output.
|
|
34
|
-
*/
|
|
35
|
-
function addHeader(){
|
|
36
|
-
let navItems = []
|
|
37
|
-
|
|
38
|
-
// add dark mode switch just for fun.
|
|
39
|
-
navItems.push(
|
|
40
|
-
'<li>',
|
|
41
|
-
'<button onclick="jsHint.toggleDarkMode()" class="btn button__theme-toggle" aria-label="Dark Mode"></button>',
|
|
42
|
-
'</li>'
|
|
43
|
-
);
|
|
44
|
-
// open header and add title
|
|
45
|
-
output.push(
|
|
46
|
-
'<header id="top" class="site__header">',
|
|
47
|
-
`<h1>JSHint Report for ${title}</h1>`,
|
|
48
|
-
)
|
|
49
|
-
|
|
50
|
-
// add navigation if items were found
|
|
51
|
-
if( navItems.length ){
|
|
52
|
-
output.push(
|
|
53
|
-
'<nav class="nav">',
|
|
54
|
-
'<ul>',
|
|
55
|
-
...navItems,
|
|
56
|
-
'</ul>',
|
|
57
|
-
'</nav>',
|
|
58
|
-
)
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
// close the header.
|
|
62
|
-
output.push(
|
|
63
|
-
'</header>',
|
|
64
|
-
)
|
|
65
|
-
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
/**
|
|
69
|
-
* Adds Result Summary to output.
|
|
70
|
-
* @param {Array} results
|
|
71
|
-
*/
|
|
72
|
-
function addSummary(results){
|
|
73
|
-
let items = [];
|
|
74
|
-
|
|
75
|
-
// summary
|
|
76
|
-
results.forEach(function(result) {
|
|
77
|
-
var file = result.file;
|
|
78
|
-
var error = result.error;
|
|
79
|
-
|
|
80
|
-
items.push(
|
|
81
|
-
'<li>',
|
|
82
|
-
`<a href="#${file.replace(/[\\:\.]/g, '-').toLowerCase()}" target="_blank">${file}</a>: line ${error.line}, col ${error.character}, ${error.reason}`,
|
|
83
|
-
'</li>'
|
|
84
|
-
)
|
|
85
|
-
})
|
|
86
|
-
|
|
87
|
-
let summary = [];
|
|
88
|
-
for(let [category] of Object.entries(sortedReport) ){
|
|
89
|
-
if( sortedReport[category].length ){
|
|
90
|
-
let cCase = capitalCase(category);
|
|
91
|
-
// if there is just 1, drop the plural
|
|
92
|
-
if( 1 === sortedReport[category].length ){
|
|
93
|
-
cCase = cCase.slice(0, -1)
|
|
94
|
-
}
|
|
95
|
-
summary.push(`${sortedReport[category].length} ${cCase} Detected`)
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
output.push(
|
|
100
|
-
'<section class="hint" id="summary">',
|
|
101
|
-
'<header class="hint__header">',
|
|
102
|
-
`<h2 class="hint__title">Summary: <em>${summary.join(' & ')}</em></h2>`,
|
|
103
|
-
'</header>',
|
|
104
|
-
'<ol>',
|
|
105
|
-
...items,
|
|
106
|
-
'</ol>',
|
|
107
|
-
'</section>'
|
|
108
|
-
);
|
|
109
|
-
|
|
110
|
-
}
|
|
111
|
-
|
|
112
32
|
/**
|
|
113
33
|
* Process data
|
|
114
34
|
*
|
|
@@ -229,43 +149,17 @@ function addBreakdown({
|
|
|
229
149
|
})
|
|
230
150
|
}
|
|
231
151
|
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
unusedList.length ? `<ol>${unusedList.join('\n')}</ol>` : '',
|
|
244
|
-
'</section>'
|
|
245
|
-
)
|
|
246
|
-
}
|
|
247
|
-
|
|
248
|
-
/**
|
|
249
|
-
* Add file list sidebar
|
|
250
|
-
*/
|
|
251
|
-
function addSidebar(data){
|
|
252
|
-
let fileList = [];
|
|
253
|
-
|
|
254
|
-
data.forEach(({file}) => {
|
|
255
|
-
fileList.push(
|
|
256
|
-
`<li><a href="#${ file.replace(/[\\:\.]/g, '-').toLowerCase() }">${file}</a></li>`
|
|
257
|
-
)
|
|
258
|
-
})
|
|
259
|
-
output.push(
|
|
260
|
-
'<aside>',
|
|
261
|
-
'<section>',
|
|
262
|
-
'<header class="hint__header"><h2 class="hint__title">Files</h2></header>',
|
|
263
|
-
'<ol>',
|
|
264
|
-
fileList.join('\n'),
|
|
265
|
-
'</section>',
|
|
266
|
-
'</ol>',
|
|
267
|
-
'</aside>'
|
|
268
|
-
)
|
|
152
|
+
return `<section id="${file.replace(/[\\:\.]/g, '-').toLowerCase()}" class="mb-5 border border-2">
|
|
153
|
+
<div class="bg-light p-4"><h4>File: <a href="file://${file}" target="_blank" class="fst-italic fs-md text-break">${file}</a></h4></div>
|
|
154
|
+
<div class="p-4">
|
|
155
|
+
<h5>Functions: <span class="bg-light rounded-circle p-2">${functions.length}</span></h5>
|
|
156
|
+
${ functionList.length ? `<ol>${functionList.join('\n')}</ol>` : ''}
|
|
157
|
+
<h5>Errors: <span class="bg-light rounded-circle p-2">${errors ? errors.length : 0}</span></h5>
|
|
158
|
+
${ errorList.length ? `<ol>${errorList.join('\n')}</ol>` : '' }
|
|
159
|
+
<h5>Unused: <span class="bg-light rounded-circle p-2">${unused ? unused.length : 0}</span></h5>
|
|
160
|
+
${ unusedList.length ? `<ol>${unusedList.join('\n')}</ol>` : '' }
|
|
161
|
+
</div>
|
|
162
|
+
</section>`;
|
|
269
163
|
}
|
|
270
164
|
|
|
271
165
|
/**
|
|
@@ -280,384 +174,128 @@ function reporter(results, data, opts){
|
|
|
280
174
|
path.resolve( process.env.JSHINT_OUTPUT_DIR ) :
|
|
281
175
|
path.join(__dirname, 'public')
|
|
282
176
|
let outputFilename = path.join(outputFolder, `${process.env.JSHINT_OUTPUT_FILENAME ?? 'jshint'}.html` );
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
var error = result.error;
|
|
288
|
-
|
|
289
|
-
// add error to sorted report array
|
|
290
|
-
switch( error.code.charAt(0) ){
|
|
291
|
-
case 'E': // errors
|
|
292
|
-
sortedReport.errors.push({...error, file: file})
|
|
293
|
-
break;
|
|
294
|
-
case 'I': // info
|
|
295
|
-
sortedReport.info.push({...error, file: file})
|
|
296
|
-
break;
|
|
297
|
-
case 'W': // warnings
|
|
298
|
-
sortedReport.warnings.push({...error, file: file})
|
|
299
|
-
break;
|
|
300
|
-
}
|
|
301
|
-
})
|
|
177
|
+
let fileList = [];
|
|
178
|
+
let fileSummary = [];
|
|
179
|
+
let fileBreakdown = [];
|
|
180
|
+
let summaryHeader = [];
|
|
302
181
|
|
|
303
182
|
try{
|
|
304
183
|
|
|
305
|
-
//
|
|
306
|
-
|
|
184
|
+
// process results.
|
|
185
|
+
results.forEach((result) => {
|
|
186
|
+
var file = result.file;
|
|
187
|
+
var error = result.error;
|
|
188
|
+
|
|
189
|
+
// add error to sorted report array
|
|
190
|
+
switch( error.code.charAt(0) ){
|
|
191
|
+
case 'E': // errors
|
|
192
|
+
sortedReport.errors.push({...error, file: file})
|
|
193
|
+
break;
|
|
194
|
+
case 'I': // info
|
|
195
|
+
sortedReport.info.push({...error, file: file})
|
|
196
|
+
break;
|
|
197
|
+
case 'W': // warnings
|
|
198
|
+
sortedReport.warnings.push({...error, file: file})
|
|
199
|
+
break;
|
|
200
|
+
}
|
|
307
201
|
|
|
308
|
-
|
|
309
|
-
|
|
202
|
+
fileList.push(
|
|
203
|
+
`<li class="text-break mb-4"><a href="#${ file.replace(/[\\:\.]/g, '-').toLowerCase() }">${file}</a></li>`
|
|
204
|
+
)
|
|
310
205
|
|
|
311
|
-
|
|
206
|
+
fileSummary.push(
|
|
207
|
+
`<li class="mb-3"><a href="#${ file.replace(/[\\:\.]/g, '-').toLowerCase( )}">${file}</a>: line ${error.line}, col ${error.character}, ${error.reason}</li>`
|
|
208
|
+
)
|
|
312
209
|
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
output.push ('<div id="information">');
|
|
316
|
-
|
|
317
|
-
// Add Summary.
|
|
318
|
-
addSummary(results);
|
|
210
|
+
})
|
|
319
211
|
|
|
320
|
-
// process data.
|
|
321
212
|
data.forEach((d) => {
|
|
322
|
-
|
|
323
|
-
Only used to see what the data is passing
|
|
324
|
-
for(let [prop, value] of Object.entries(d) ){
|
|
325
|
-
output.push(prop)
|
|
326
|
-
output.push('object' == typeof value ? value[0] : value)
|
|
327
|
-
output.push('<br />')
|
|
328
|
-
}
|
|
329
|
-
*/
|
|
330
|
-
addBreakdown(d)
|
|
213
|
+
fileBreakdown.push( addBreakdown(d) );
|
|
331
214
|
})
|
|
332
215
|
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
216
|
+
|
|
217
|
+
for(let [category] of Object.entries(sortedReport) ){
|
|
218
|
+
if( sortedReport[category].length ){
|
|
219
|
+
let cCase = capitalCase(category);
|
|
220
|
+
// if there is just 1, drop the plural
|
|
221
|
+
if( 1 === sortedReport[category].length ){
|
|
222
|
+
cCase = cCase.slice(0, -1)
|
|
223
|
+
}
|
|
224
|
+
summaryHeader.push(`${sortedReport[category].length} ${cCase} Detected`)
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
|
|
229
|
+
fileList = Array.from( new Set( fileList ) );
|
|
230
|
+
|
|
231
|
+
output.push(
|
|
232
|
+
`<h1 class="page-title my-4">${title}</h1>`,
|
|
233
|
+
'<div class="container">',
|
|
234
|
+
'<div class="row">',
|
|
235
|
+
'<div id="sidebar" class="col-4">',
|
|
236
|
+
'<h2>Files</h2>',
|
|
237
|
+
'<ol class="border-end border-2 pe-3">',
|
|
238
|
+
...fileList,
|
|
239
|
+
'</ol>',
|
|
240
|
+
'</div>',
|
|
241
|
+
'<!-- End of Sidebar Column -->',
|
|
242
|
+
'<div id="content" class="col-8">',
|
|
243
|
+
`<h2>Summary: <em>${summaryHeader.join(' & ')}</em></h2>`,
|
|
244
|
+
'<ol>',
|
|
245
|
+
...fileSummary,
|
|
246
|
+
'</ol>',
|
|
247
|
+
...fileBreakdown,
|
|
248
|
+
'</div>',
|
|
249
|
+
'<!-- End of Content Column -->',
|
|
250
|
+
'</div>',
|
|
251
|
+
'<!-- End of Row -->',
|
|
252
|
+
'</div>',
|
|
253
|
+
'<!-- End of Container -->'
|
|
254
|
+
)
|
|
255
|
+
|
|
337
256
|
|
|
338
257
|
}catch(err){
|
|
339
258
|
process.stderr.write(err.toString())
|
|
340
259
|
process.exit(1)
|
|
341
260
|
}
|
|
342
261
|
|
|
343
|
-
// wrap the output in html tags.
|
|
344
|
-
output = ['<html>', ...output, '</html>']
|
|
345
|
-
|
|
346
262
|
fs.mkdirSync( outputFolder, {recursive: true} );
|
|
347
263
|
|
|
264
|
+
// Register partials.
|
|
265
|
+
Object.entries(templatePartials).forEach(([p, f]) => HandleBars.registerPartial(p, fs.readFileSync(path.resolve(templateDir, f )).toString() ) );
|
|
266
|
+
|
|
267
|
+
// Register custom helpers.
|
|
268
|
+
HandleBars.registerHelper('endsWith', (w,s,o) => { return w.endsWith(s); } )
|
|
269
|
+
|
|
270
|
+
let template = HandleBars.compile(fs.readFileSync(path.resolve(templateDir, 'default.html')).toString() )
|
|
271
|
+
|
|
348
272
|
// write html file
|
|
349
|
-
fs.writeFileSync(
|
|
273
|
+
fs.writeFileSync(
|
|
350
274
|
outputFilename,
|
|
351
|
-
htmlFormat(
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
275
|
+
htmlFormat(
|
|
276
|
+
template({
|
|
277
|
+
title,
|
|
278
|
+
scheme: 'oceanside',
|
|
279
|
+
logo: 'https://caweb.cdt.ca.gov/wp-content/uploads/sites/221/2023/06/caweb-publishing-logo.png',
|
|
280
|
+
htmlWebpackPlugin: {
|
|
281
|
+
options: {
|
|
282
|
+
templateParameters: {
|
|
283
|
+
bodyHtmlSnippet: output.join('\n')
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
}),
|
|
288
|
+
" ".repeat(4), 250
|
|
289
|
+
)
|
|
358
290
|
);
|
|
359
291
|
|
|
360
|
-
// write jshint.css file.
|
|
361
|
-
fs.writeFileSync(
|
|
362
|
-
path.join(outputFolder, 'jshint.css'),
|
|
363
|
-
cssContent()
|
|
364
|
-
);
|
|
365
292
|
|
|
366
|
-
// console.log( htmlFormat(output.join('\n')," ".repeat(4), 250) );
|
|
367
293
|
}
|
|
368
294
|
|
|
369
295
|
function capitalCase(str){
|
|
370
296
|
return str.charAt(0).toUpperCase() + str.slice(1)
|
|
371
297
|
}
|
|
372
298
|
|
|
373
|
-
/**
|
|
374
|
-
* Returns string content for css file
|
|
375
|
-
* @returns string
|
|
376
|
-
*/
|
|
377
|
-
function cssContent(){
|
|
378
|
-
return `
|
|
379
|
-
/*
|
|
380
|
-
* JSHint
|
|
381
|
-
*/
|
|
382
|
-
body {
|
|
383
|
-
--body-margin: 2rem;
|
|
384
|
-
|
|
385
|
-
/* Body colours */
|
|
386
|
-
--body-bg: #fff;
|
|
387
|
-
--body-fg: #111;
|
|
388
|
-
|
|
389
|
-
/* Nav & link colours */
|
|
390
|
-
--nav-bg: #eee;
|
|
391
|
-
--nav-bg-hover: #bbb;
|
|
392
|
-
--nav-fg: #11c;
|
|
393
|
-
|
|
394
|
-
/* Heading colours */
|
|
395
|
-
--h-fg: #222;
|
|
396
|
-
--h-bg: #eee;
|
|
397
|
-
|
|
398
|
-
/* Border style for bordered components */
|
|
399
|
-
--component-border: 1px solid #aaa;
|
|
400
|
-
|
|
401
|
-
/* Consistent component margins */
|
|
402
|
-
--component-margin-sm: 1.5rem;
|
|
403
|
-
--component-margin-lg: 3rem;
|
|
404
|
-
|
|
405
|
-
/* Colour chips */
|
|
406
|
-
--count-bg: #eee;
|
|
407
|
-
--count-border: var(--component-border);
|
|
408
|
-
}
|
|
409
|
-
/*
|
|
410
|
-
* Dark mode
|
|
411
|
-
*/
|
|
412
|
-
body.is-dark-mode {
|
|
413
|
-
/* Body colours */
|
|
414
|
-
--body-bg: #111;
|
|
415
|
-
--body-fg: #fff;
|
|
416
|
-
|
|
417
|
-
/* Nav & link colours */
|
|
418
|
-
--nav-bg: #444;
|
|
419
|
-
--nav-bg-hover: #222;
|
|
420
|
-
--nav-fg: #bcf;
|
|
421
|
-
|
|
422
|
-
/* Heading colours */
|
|
423
|
-
--h-fg: #eee;
|
|
424
|
-
--h-bg: #222;
|
|
425
|
-
|
|
426
|
-
/* Border style for bordered components */
|
|
427
|
-
--component-border: 1px solid #666;
|
|
428
|
-
|
|
429
|
-
/* Consistent component margins */
|
|
430
|
-
--component-margin-sm: 1.5rem;
|
|
431
|
-
--component-margin-lg: 3rem;
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
/* Colour chips */
|
|
435
|
-
--count-bg: #111;
|
|
436
|
-
--count-border: var(--component-border);
|
|
437
|
-
}
|
|
438
|
-
/*
|
|
439
|
-
* General
|
|
440
|
-
*/
|
|
441
|
-
* {
|
|
442
|
-
box-sizing: border-box;
|
|
443
|
-
}
|
|
444
|
-
|
|
445
|
-
html {
|
|
446
|
-
scroll-behavior: smooth;
|
|
447
|
-
|
|
448
|
-
@media (prefers-reduced-motion: reduce) {
|
|
449
|
-
scroll-behavior: auto;
|
|
450
|
-
}
|
|
451
|
-
}
|
|
452
|
-
|
|
453
|
-
body {
|
|
454
|
-
background-color: var(--body-bg);
|
|
455
|
-
color: var(--body-fg);
|
|
456
|
-
font-family: sans-serif;
|
|
457
|
-
margin: var(--body-margin);
|
|
458
|
-
}
|
|
459
|
-
|
|
460
|
-
a {
|
|
461
|
-
color: var(--nav-fg);
|
|
462
|
-
}
|
|
463
|
-
p{
|
|
464
|
-
margin: 0 0 .5em 0
|
|
465
|
-
}
|
|
466
|
-
h1, h2 {
|
|
467
|
-
font-weight: normal;
|
|
468
|
-
}
|
|
469
|
-
|
|
470
|
-
h1, h2, h3 {
|
|
471
|
-
color: var(--h-fg);
|
|
472
|
-
margin: 0 0 var(--component-margin-sm) 0;
|
|
473
|
-
}
|
|
474
|
-
/*
|
|
475
|
-
* Layout
|
|
476
|
-
*/
|
|
477
|
-
#main{
|
|
478
|
-
display: flex;
|
|
479
|
-
}
|
|
480
|
-
aside {
|
|
481
|
-
margin-right: calc(1.5* var(--body-margin));
|
|
482
|
-
padding-right: calc(1* var(--body-margin));
|
|
483
|
-
border-right: var(--component-border);
|
|
484
|
-
}
|
|
485
|
-
#information{
|
|
486
|
-
flex-grow: 1
|
|
487
|
-
}
|
|
488
|
-
/*
|
|
489
|
-
* Hints
|
|
490
|
-
*/
|
|
491
|
-
.hint {
|
|
492
|
-
margin-bottom: var(--component-margin-lg);
|
|
493
|
-
}
|
|
494
|
-
.hint__header {
|
|
495
|
-
align-items: baseline;
|
|
496
|
-
background-color: var(--h-bg);
|
|
497
|
-
display: flex;
|
|
498
|
-
justify-content: space-between;
|
|
499
|
-
margin-right: calc(-1 * var(--body-margin));
|
|
500
|
-
margin-left: calc(-1 * var(--body-margin));
|
|
501
|
-
margin-bottom: var(--component-margin-sm);
|
|
502
|
-
padding: var(--component-margin-sm) var(--body-margin) 0;
|
|
503
|
-
position: sticky;
|
|
504
|
-
top: 0;
|
|
505
|
-
z-index: 1;
|
|
506
|
-
}
|
|
507
|
-
|
|
508
|
-
/*
|
|
509
|
-
* Lists
|
|
510
|
-
*/
|
|
511
|
-
ul,
|
|
512
|
-
ol {
|
|
513
|
-
padding: 0 0 0 2em;
|
|
514
|
-
}
|
|
515
|
-
li {
|
|
516
|
-
margin: 0 0 2em 0;
|
|
517
|
-
}
|
|
518
|
-
li li {
|
|
519
|
-
margin: 0;
|
|
520
|
-
}
|
|
521
|
-
/*
|
|
522
|
-
* Header, nav, 'back to top' button
|
|
523
|
-
*/
|
|
524
|
-
.site__header {
|
|
525
|
-
align-items: baseline;
|
|
526
|
-
display: flex;
|
|
527
|
-
flex-wrap: wrap;
|
|
528
|
-
justify-content: space-between;
|
|
529
|
-
}
|
|
530
|
-
.nav {
|
|
531
|
-
margin-bottom: var(--component-margin-sm);
|
|
532
|
-
}
|
|
533
|
-
|
|
534
|
-
.nav ul {
|
|
535
|
-
display: flex;
|
|
536
|
-
justify-content: flex-start;
|
|
537
|
-
align-items: center;
|
|
538
|
-
list-style: none;
|
|
539
|
-
padding: 0;
|
|
540
|
-
}
|
|
541
|
-
|
|
542
|
-
.nav li {
|
|
543
|
-
margin-bottom: var(--component-margin-sm);
|
|
544
|
-
margin: 0 0.5em 0 0;
|
|
545
|
-
}
|
|
546
|
-
|
|
547
|
-
.nav a {
|
|
548
|
-
display: block;
|
|
549
|
-
height: 100%;
|
|
550
|
-
}
|
|
551
|
-
|
|
552
|
-
.nav a,
|
|
553
|
-
.btn {
|
|
554
|
-
background-color: var(--nav-bg);
|
|
555
|
-
padding: 0.5em;
|
|
556
|
-
text-decoration: none;
|
|
557
|
-
transition: background-color 0.2s ease;
|
|
558
|
-
}
|
|
559
|
-
|
|
560
|
-
.nav a:hover,
|
|
561
|
-
.nav a:focus,
|
|
562
|
-
.btn:hover,
|
|
563
|
-
.btn:focus {
|
|
564
|
-
background-color: var(--nav-bg-hover);
|
|
565
|
-
}
|
|
566
|
-
|
|
567
|
-
.nav a:focus,
|
|
568
|
-
.btn:focus {
|
|
569
|
-
outline: 4px dashed var(--nav-fg);
|
|
570
|
-
}
|
|
571
|
-
|
|
572
|
-
.btn {
|
|
573
|
-
font-size: 1.2em;
|
|
574
|
-
margin-bottom: var(--component-margin-sm);
|
|
575
|
-
text-align: center;
|
|
576
|
-
}
|
|
577
|
-
/*
|
|
578
|
-
* Count component on colour chips
|
|
579
|
-
*/
|
|
580
|
-
.count {
|
|
581
|
-
background-color: var(--count-bg);
|
|
582
|
-
border: var(--count-border);
|
|
583
|
-
border-radius: 50%;
|
|
584
|
-
box-sizing: border-box;
|
|
585
|
-
color: var(--count-fg);
|
|
586
|
-
display: inline-block;
|
|
587
|
-
height: auto;
|
|
588
|
-
min-width: 2.3em;
|
|
589
|
-
padding: 0.5em;
|
|
590
|
-
text-align: center;
|
|
591
|
-
|
|
592
|
-
/* Counteract .chip:hover */
|
|
593
|
-
font-weight: normal;
|
|
594
|
-
text-shadow: none;
|
|
595
|
-
}
|
|
596
|
-
/*
|
|
597
|
-
* Darkmode switch
|
|
598
|
-
*/
|
|
599
|
-
.button__theme-toggle {
|
|
600
|
-
background: transparent;
|
|
601
|
-
border: none;
|
|
602
|
-
cursor: pointer;
|
|
603
|
-
margin-bottom: 0;
|
|
604
|
-
}
|
|
605
|
-
|
|
606
|
-
.button__theme-toggle::before {
|
|
607
|
-
content: "🌛";
|
|
608
|
-
font-size: 1.5rem;
|
|
609
|
-
}
|
|
610
|
-
|
|
611
|
-
body.is-dark-mode .button__theme-toggle::before {
|
|
612
|
-
content: "🌞";
|
|
613
|
-
}
|
|
614
|
-
|
|
615
|
-
/*
|
|
616
|
-
* Link Icon
|
|
617
|
-
*/
|
|
618
|
-
.link{
|
|
619
|
-
text-decoration: none;
|
|
620
|
-
cursor: pointer;
|
|
621
|
-
}
|
|
622
|
-
.link::before{
|
|
623
|
-
content: "🔗";
|
|
624
|
-
}
|
|
625
|
-
`;
|
|
626
|
-
}
|
|
627
|
-
|
|
628
|
-
/**
|
|
629
|
-
* Returns string content for js file
|
|
630
|
-
* @returns string
|
|
631
|
-
*/
|
|
632
|
-
function jsContent(){
|
|
633
|
-
return `
|
|
634
|
-
|
|
635
|
-
const jsHint = {};
|
|
636
|
-
|
|
637
|
-
document.addEventListener( 'DOMContentLoaded', () => {
|
|
638
|
-
const button = document.querySelector( '.button__theme-toggle' );
|
|
639
|
-
|
|
640
|
-
jsHint.toggleDarkMode = function() {
|
|
641
|
-
const isDarkMode = document.body.classList.contains( 'is-dark-mode' );
|
|
642
|
-
if ( isDarkMode ) {
|
|
643
|
-
button.setAttribute( 'aria-pressed', 'false' );
|
|
644
|
-
document.body.classList.remove( 'is-dark-mode' );
|
|
645
|
-
} else {
|
|
646
|
-
button.setAttribute( 'aria-pressed', 'true' );
|
|
647
|
-
document.body.classList.add( 'is-dark-mode' );
|
|
648
|
-
}
|
|
649
|
-
}
|
|
650
|
-
|
|
651
|
-
// Set is-dark-mode class if user has requested dark mode.
|
|
652
|
-
if ( window.matchMedia( '(prefers-color-scheme: dark)' ).matches ){
|
|
653
|
-
document.body.classList.add( 'is-dark-mode' );
|
|
654
|
-
button.setAttribute( 'aria-pressed', 'true' );
|
|
655
|
-
}
|
|
656
|
-
|
|
657
|
-
});
|
|
658
|
-
`;
|
|
659
|
-
}
|
|
660
|
-
|
|
661
299
|
module.exports = {
|
|
662
300
|
reporter
|
|
663
301
|
}
|