nibula 1.6.0 → 1.6.2
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/.eleventy.js +82 -81
- package/CHANGELOG.md +395 -377
- package/LICENSE +169 -169
- package/NOTICE +4 -4
- package/README.md +110 -110
- package/bin/create.js +540 -505
- package/bin/delegate.js +58 -57
- package/bin/nibula.js +302 -302
- package/docs/Assistant CLI.md +65 -65
- package/docs/Backend.md +201 -201
- package/docs/Components.md +140 -140
- package/docs/Creating pages.md +69 -69
- package/docs/Deploy.md +210 -210
- package/docs/Head and SEO.md +139 -139
- package/docs/Javascript.md +126 -126
- package/docs/Styling with SCSS.md +141 -139
- package/nginx.conf +113 -113
- package/package.json +69 -69
- package/src/backend/.htaccess +6 -6
- package/src/backend/_core/composer.json +5 -5
- package/src/backend/_core/composer.lock +492 -492
- package/src/backend/_core/index.js +267 -267
- package/src/backend/_core/index.php +160 -160
- package/src/backend/_core/init.js +52 -52
- package/src/backend/_core/init.php +33 -33
- package/src/backend/_core/modules/RateLimiter.js +58 -58
- package/src/backend/_core/modules/RateLimiter.php +30 -30
- package/src/backend/_core/modules/Response.js +59 -59
- package/src/backend/_core/modules/Response.php +48 -48
- package/src/backend/api/protected/example-protected.js +23 -23
- package/src/backend/api/protected/example-protected.php +16 -16
- package/src/backend/api/public/example-public.js +24 -24
- package/src/backend/api/public/example-public.php +16 -16
- package/src/backend/database/Database.js +46 -46
- package/src/backend/database/Database.php +23 -23
- package/src/backend/example.config.js +37 -37
- package/src/backend/example.config.php +37 -37
- package/src/backend/package.json +17 -17
- package/src/backend/web.config +43 -43
- package/src/frontend/.htaccess +51 -51
- package/src/frontend/404.njk +17 -17
- package/src/frontend/assets/brand/favicon.svg +54 -54
- package/src/frontend/assets/brand/logo.svg +54 -54
- package/src/frontend/components/global/footer.njk +25 -25
- package/src/frontend/components/global/header.njk +6 -6
- package/src/frontend/components/welcome.njk +115 -115
- package/src/frontend/index.njk +8 -8
- package/src/frontend/js/global.js +10 -10
- package/src/frontend/js/modules/exampleModule.js +2 -2
- package/src/frontend/js/pages/404.js +8 -8
- package/src/frontend/js/pages/homepage.js +8 -8
- package/src/frontend/layouts/base.njk +135 -136
- package/src/frontend/layouts/page-components.njk +13 -13
- package/src/frontend/llms.njk +17 -17
- package/src/frontend/robots.njk +7 -7
- package/src/frontend/scss/_global.scss +46 -46
- package/src/frontend/scss/_root.scss +13 -13
- package/src/frontend/scss/modules/_animations.scss +24 -24
- package/src/frontend/scss/modules/_footer.scss +28 -28
- package/src/frontend/scss/modules/_header.scss +26 -26
- package/src/frontend/scss/modules/_mobile.scss +29 -29
- package/src/frontend/scss/modules/_typography.scss +18 -18
- package/src/frontend/scss/modules/frameworks/_bootstrap.scss +109 -109
- package/src/frontend/scss/modules/frameworks/_bulma.scss +108 -108
- package/src/frontend/scss/modules/frameworks/_foundation.scss +137 -137
- package/src/frontend/scss/modules/frameworks/_uikit.scss +109 -109
- package/src/frontend/scss/pages/404.scss +27 -27
- package/src/frontend/scss/pages/homepage.scss +22 -22
- package/src/frontend/sitemap.njk +17 -17
- package/src/frontend/ts/global.ts +11 -11
- package/src/frontend/ts/modules/exampleModule.ts +2 -2
- package/src/frontend/ts/pages/404.ts +8 -8
- package/src/frontend/ts/pages/homepage.ts +8 -8
- package/src/frontend/web.config +51 -51
- package/tools/assistant.js +122 -122
- package/tools/buildJs.js +39 -39
- package/tools/cleanOutput.js +23 -23
- package/tools/cli/prompt.js +40 -40
- package/tools/cli/ui.js +87 -87
- package/tools/config/messages.json +80 -80
- package/tools/config/settings.json +130 -130
- package/tools/lib/colors.js +17 -17
- package/tools/lib/files.js +75 -75
- package/tools/lib/logger.js +22 -22
- package/tools/lib/outputPath.js +141 -141
- package/tools/lib/pageActions.js +146 -146
- package/tools/lib/pageArtifacts.js +46 -46
- package/tools/lib/pageComponents.js +88 -88
- package/tools/lib/pagesData.js +87 -87
- package/tools/lib/paths.js +63 -63
- package/tools/lib/project.js +54 -54
- package/tools/lib/text.js +47 -47
- package/tools/lib/validation.js +40 -40
- package/tools/res/templates/template.js +7 -7
- package/tools/res/templates/template.njk +8 -8
- package/tools/res/templates/template.scss +22 -22
- package/tools/res/templates/template.ts +8 -8
- package/tsconfig.json +24 -24
- package/src/frontend/scss/pages/prova.scss +0 -23
package/tools/lib/text.js
CHANGED
|
@@ -1,47 +1,47 @@
|
|
|
1
|
-
const PLACEHOLDER_PATTERN = /\{(\w+)\}/g;
|
|
2
|
-
const CAMEL_SEPARATOR_PATTERN = /[-_][a-z0-9]/g;
|
|
3
|
-
const INVALID_KEBAB_PATTERN = /[^a-z0-9\s_-]/g;
|
|
4
|
-
const KEBAB_SEPARATOR_PATTERN = /[\s_]+/g;
|
|
5
|
-
const REPEATED_HYPHEN_PATTERN = /-+/g;
|
|
6
|
-
const EDGE_HYPHEN_PATTERN = /^-+|-+$/g;
|
|
7
|
-
const WORD_SEPARATOR = '-';
|
|
8
|
-
const SPACE = ' ';
|
|
9
|
-
const EMPTY = '';
|
|
10
|
-
|
|
11
|
-
function formatText(template, values = {}) {
|
|
12
|
-
return String(template).replace(PLACEHOLDER_PATTERN, (match, key) =>
|
|
13
|
-
Object.prototype.hasOwnProperty.call(values, key) ? String(values[key]) : match
|
|
14
|
-
);
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
function formatValue(value, values = {}) {
|
|
18
|
-
if (typeof value === 'string') return formatText(value, values);
|
|
19
|
-
if (Array.isArray(value)) return value.map((item) => formatValue(item, values));
|
|
20
|
-
if (value !== null && typeof value === 'object') {
|
|
21
|
-
return Object.fromEntries(
|
|
22
|
-
Object.entries(value).map(([key, item]) => [key, formatValue(item, values)])
|
|
23
|
-
);
|
|
24
|
-
}
|
|
25
|
-
return value;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
function toCamelCase(value) {
|
|
29
|
-
return value.toLowerCase().replace(CAMEL_SEPARATOR_PATTERN, (group) => group.slice(1).toUpperCase());
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
function toKebabCase(value) {
|
|
33
|
-
return value.trim().toLowerCase()
|
|
34
|
-
.replace(INVALID_KEBAB_PATTERN, EMPTY)
|
|
35
|
-
.replace(KEBAB_SEPARATOR_PATTERN, WORD_SEPARATOR)
|
|
36
|
-
.replace(REPEATED_HYPHEN_PATTERN, WORD_SEPARATOR)
|
|
37
|
-
.replace(EDGE_HYPHEN_PATTERN, EMPTY);
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
function toTitleCase(value) {
|
|
41
|
-
return value.split(WORD_SEPARATOR)
|
|
42
|
-
.filter(Boolean)
|
|
43
|
-
.map((word) => word.charAt(0).toUpperCase() + word.slice(1))
|
|
44
|
-
.join(SPACE);
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
module.exports = { formatText, formatValue, toCamelCase, toKebabCase, toTitleCase };
|
|
1
|
+
const PLACEHOLDER_PATTERN = /\{(\w+)\}/g;
|
|
2
|
+
const CAMEL_SEPARATOR_PATTERN = /[-_][a-z0-9]/g;
|
|
3
|
+
const INVALID_KEBAB_PATTERN = /[^a-z0-9\s_-]/g;
|
|
4
|
+
const KEBAB_SEPARATOR_PATTERN = /[\s_]+/g;
|
|
5
|
+
const REPEATED_HYPHEN_PATTERN = /-+/g;
|
|
6
|
+
const EDGE_HYPHEN_PATTERN = /^-+|-+$/g;
|
|
7
|
+
const WORD_SEPARATOR = '-';
|
|
8
|
+
const SPACE = ' ';
|
|
9
|
+
const EMPTY = '';
|
|
10
|
+
|
|
11
|
+
function formatText(template, values = {}) {
|
|
12
|
+
return String(template).replace(PLACEHOLDER_PATTERN, (match, key) =>
|
|
13
|
+
Object.prototype.hasOwnProperty.call(values, key) ? String(values[key]) : match
|
|
14
|
+
);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function formatValue(value, values = {}) {
|
|
18
|
+
if (typeof value === 'string') return formatText(value, values);
|
|
19
|
+
if (Array.isArray(value)) return value.map((item) => formatValue(item, values));
|
|
20
|
+
if (value !== null && typeof value === 'object') {
|
|
21
|
+
return Object.fromEntries(
|
|
22
|
+
Object.entries(value).map(([key, item]) => [key, formatValue(item, values)])
|
|
23
|
+
);
|
|
24
|
+
}
|
|
25
|
+
return value;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function toCamelCase(value) {
|
|
29
|
+
return value.toLowerCase().replace(CAMEL_SEPARATOR_PATTERN, (group) => group.slice(1).toUpperCase());
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function toKebabCase(value) {
|
|
33
|
+
return value.trim().toLowerCase()
|
|
34
|
+
.replace(INVALID_KEBAB_PATTERN, EMPTY)
|
|
35
|
+
.replace(KEBAB_SEPARATOR_PATTERN, WORD_SEPARATOR)
|
|
36
|
+
.replace(REPEATED_HYPHEN_PATTERN, WORD_SEPARATOR)
|
|
37
|
+
.replace(EDGE_HYPHEN_PATTERN, EMPTY);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function toTitleCase(value) {
|
|
41
|
+
return value.split(WORD_SEPARATOR)
|
|
42
|
+
.filter(Boolean)
|
|
43
|
+
.map((word) => word.charAt(0).toUpperCase() + word.slice(1))
|
|
44
|
+
.join(SPACE);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
module.exports = { formatText, formatValue, toCamelCase, toKebabCase, toTitleCase };
|
package/tools/lib/validation.js
CHANGED
|
@@ -1,40 +1,40 @@
|
|
|
1
|
-
const settings = require('../config/settings.json');
|
|
2
|
-
const { PATHS } = require('./paths');
|
|
3
|
-
const { exists } = require('./files');
|
|
4
|
-
const { message } = require('./logger');
|
|
5
|
-
|
|
6
|
-
const NAME_PATTERN = /^[a-z0-9-]+$/;
|
|
7
|
-
const LEADING_DIGIT_PATTERN = /^\d/;
|
|
8
|
-
const INVALID_PATH_PATTERN = /[<>|?*"']/;
|
|
9
|
-
|
|
10
|
-
function requiredFiles() {
|
|
11
|
-
return [
|
|
12
|
-
{ label: settings.paths.eleventyConfig, path: PATHS.eleventyConfig },
|
|
13
|
-
{ label: settings.paths.packageJson, path: PATHS.packageJson },
|
|
14
|
-
{ label: settings.paths.siteData, path: PATHS.siteData },
|
|
15
|
-
{ label: settings.paths.pagesData, path: PATHS.pagesData },
|
|
16
|
-
{ label: settings.paths.pageComponents, path: PATHS.pageComponents },
|
|
17
|
-
{ label: message('validation.templatesLabel'), path: PATHS.templates },
|
|
18
|
-
];
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
function validatePageName(name) {
|
|
22
|
-
if (!name) return message('validation.invalidName');
|
|
23
|
-
if (!NAME_PATTERN.test(name)) return message('validation.invalidNameCharacters');
|
|
24
|
-
if (LEADING_DIGIT_PATTERN.test(name)) return message('validation.nameStartsWithNumber');
|
|
25
|
-
if (settings.page.protected.includes(name)) return message('validation.protectedName', { name });
|
|
26
|
-
return null;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
function validateOutputPath(input) {
|
|
30
|
-
const value = (input ?? '').trim();
|
|
31
|
-
if (!value) return message('validation.invalidPath');
|
|
32
|
-
if (INVALID_PATH_PATTERN.test(value)) return message('validation.invalidPathCharacters');
|
|
33
|
-
return null;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
function checkRequiredFiles() {
|
|
37
|
-
return requiredFiles().filter((item) => !exists(item.path));
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
module.exports = { validatePageName, validateOutputPath, checkRequiredFiles };
|
|
1
|
+
const settings = require('../config/settings.json');
|
|
2
|
+
const { PATHS } = require('./paths');
|
|
3
|
+
const { exists } = require('./files');
|
|
4
|
+
const { message } = require('./logger');
|
|
5
|
+
|
|
6
|
+
const NAME_PATTERN = /^[a-z0-9-]+$/;
|
|
7
|
+
const LEADING_DIGIT_PATTERN = /^\d/;
|
|
8
|
+
const INVALID_PATH_PATTERN = /[<>|?*"']/;
|
|
9
|
+
|
|
10
|
+
function requiredFiles() {
|
|
11
|
+
return [
|
|
12
|
+
{ label: settings.paths.eleventyConfig, path: PATHS.eleventyConfig },
|
|
13
|
+
{ label: settings.paths.packageJson, path: PATHS.packageJson },
|
|
14
|
+
{ label: settings.paths.siteData, path: PATHS.siteData },
|
|
15
|
+
{ label: settings.paths.pagesData, path: PATHS.pagesData },
|
|
16
|
+
{ label: settings.paths.pageComponents, path: PATHS.pageComponents },
|
|
17
|
+
{ label: message('validation.templatesLabel'), path: PATHS.templates },
|
|
18
|
+
];
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function validatePageName(name) {
|
|
22
|
+
if (!name) return message('validation.invalidName');
|
|
23
|
+
if (!NAME_PATTERN.test(name)) return message('validation.invalidNameCharacters');
|
|
24
|
+
if (LEADING_DIGIT_PATTERN.test(name)) return message('validation.nameStartsWithNumber');
|
|
25
|
+
if (settings.page.protected.includes(name)) return message('validation.protectedName', { name });
|
|
26
|
+
return null;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function validateOutputPath(input) {
|
|
30
|
+
const value = (input ?? '').trim();
|
|
31
|
+
if (!value) return message('validation.invalidPath');
|
|
32
|
+
if (INVALID_PATH_PATTERN.test(value)) return message('validation.invalidPathCharacters');
|
|
33
|
+
return null;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function checkRequiredFiles() {
|
|
37
|
+
return requiredFiles().filter((item) => !exists(item.path));
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
module.exports = { validatePageName, validateOutputPath, checkRequiredFiles };
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import '../global.js';
|
|
2
|
-
// import { initExampleModule } from '../modules/exampleModule';
|
|
3
|
-
|
|
4
|
-
document.addEventListener("DOMContentLoaded", () => {
|
|
5
|
-
// initExampleModule();
|
|
6
|
-
});
|
|
7
|
-
|
|
1
|
+
import '../global.js';
|
|
2
|
+
// import { initExampleModule } from '../modules/exampleModule';
|
|
3
|
+
|
|
4
|
+
document.addEventListener("DOMContentLoaded", () => {
|
|
5
|
+
// initExampleModule();
|
|
6
|
+
});
|
|
7
|
+
|
|
8
8
|
// Page logic here
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
---
|
|
2
|
-
title: ""
|
|
3
|
-
permalink: ""
|
|
4
|
-
layout: page-components.njk
|
|
5
|
-
---
|
|
6
|
-
|
|
7
|
-
<!-- !IMPORTANT -->
|
|
8
|
-
<!-- DO NOT ADD ANYTHING HERE -->
|
|
1
|
+
---
|
|
2
|
+
title: ""
|
|
3
|
+
permalink: ""
|
|
4
|
+
layout: page-components.njk
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
<!-- !IMPORTANT -->
|
|
8
|
+
<!-- DO NOT ADD ANYTHING HERE -->
|
|
9
9
|
<!-- You should create a new component.njk into src/frontend and include that in layouts/page-components.njk -->
|
|
@@ -1,23 +1,23 @@
|
|
|
1
|
-
//==========================
|
|
2
|
-
// CSS MODULES IMPORTS
|
|
3
|
-
//==========================
|
|
4
|
-
|
|
5
|
-
// Use @use with a namespace to avoid framework variable conflicts:
|
|
6
|
-
// Example: root.$primary
|
|
7
|
-
@use "../root" as root;
|
|
8
|
-
|
|
9
|
-
// This global module contains the import framework, necessary modules for each page and any other common styles
|
|
10
|
-
@import "../global";
|
|
11
|
-
|
|
12
|
-
// Import any other module you need by import down here
|
|
13
|
-
// @import "../modules/moduleName";
|
|
14
|
-
|
|
15
|
-
//==========================
|
|
16
|
-
// PAGE CUSTOM CSS RULES
|
|
17
|
-
//==========================
|
|
18
|
-
|
|
19
|
-
// Add any custom rule specific to this page below
|
|
20
|
-
// These rules override the framework and module styles
|
|
21
|
-
// body {
|
|
22
|
-
// background-color: root.$primary-color;
|
|
1
|
+
//==========================
|
|
2
|
+
// CSS MODULES IMPORTS
|
|
3
|
+
//==========================
|
|
4
|
+
|
|
5
|
+
// Use @use with a namespace to avoid framework variable conflicts:
|
|
6
|
+
// Example: root.$primary
|
|
7
|
+
@use "../root" as root;
|
|
8
|
+
|
|
9
|
+
// This global module contains the import framework, necessary modules for each page and any other common styles
|
|
10
|
+
@import "../global";
|
|
11
|
+
|
|
12
|
+
// Import any other module you need by import down here
|
|
13
|
+
// @import "../modules/moduleName";
|
|
14
|
+
|
|
15
|
+
//==========================
|
|
16
|
+
// PAGE CUSTOM CSS RULES
|
|
17
|
+
//==========================
|
|
18
|
+
|
|
19
|
+
// Add any custom rule specific to this page below
|
|
20
|
+
// These rules override the framework and module styles
|
|
21
|
+
// body {
|
|
22
|
+
// background-color: root.$primary-color;
|
|
23
23
|
// }
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import '../global';
|
|
2
|
-
|
|
3
|
-
// import { initExampleModule } from '../modules/exampleModule';
|
|
4
|
-
|
|
5
|
-
document.addEventListener("DOMContentLoaded", (): void => {
|
|
6
|
-
// initExampleModule();
|
|
7
|
-
});
|
|
8
|
-
|
|
1
|
+
import '../global';
|
|
2
|
+
|
|
3
|
+
// import { initExampleModule } from '../modules/exampleModule';
|
|
4
|
+
|
|
5
|
+
document.addEventListener("DOMContentLoaded", (): void => {
|
|
6
|
+
// initExampleModule();
|
|
7
|
+
});
|
|
8
|
+
|
|
9
9
|
// Page logic here
|
package/tsconfig.json
CHANGED
|
@@ -1,25 +1,25 @@
|
|
|
1
|
-
{
|
|
2
|
-
// https://aka.ms/tsconfig
|
|
3
|
-
|
|
4
|
-
// Add options by uncommenting or adding "<key>": <value> pairs inside compilerOptions
|
|
5
|
-
|
|
6
|
-
"include": ["src/frontend/ts/**/*.ts"], // DO NOT CHANGE
|
|
7
|
-
|
|
8
|
-
"compilerOptions": {
|
|
9
|
-
"rootDir": "./src/frontend/ts", // DO NOT CHANGE
|
|
10
|
-
"outDir": "./out/ts", // DO NOT CHANGE
|
|
11
|
-
"module": "esnext",
|
|
12
|
-
"target": "esnext",
|
|
13
|
-
"types": [],
|
|
14
|
-
"noUncheckedIndexedAccess": true,
|
|
15
|
-
"exactOptionalPropertyTypes": true,
|
|
16
|
-
"strict": true,
|
|
17
|
-
"jsx": "react-jsx",
|
|
18
|
-
"verbatimModuleSyntax": true,
|
|
19
|
-
"isolatedModules": true,
|
|
20
|
-
"noUncheckedSideEffectImports": true,
|
|
21
|
-
"moduleDetection": "force",
|
|
22
|
-
"skipLibCheck": true,
|
|
23
|
-
"experimentalDecorators": true
|
|
24
|
-
}
|
|
1
|
+
{
|
|
2
|
+
// https://aka.ms/tsconfig
|
|
3
|
+
|
|
4
|
+
// Add options by uncommenting or adding "<key>": <value> pairs inside compilerOptions
|
|
5
|
+
|
|
6
|
+
"include": ["src/frontend/ts/**/*.ts"], // DO NOT CHANGE
|
|
7
|
+
|
|
8
|
+
"compilerOptions": {
|
|
9
|
+
"rootDir": "./src/frontend/ts", // DO NOT CHANGE
|
|
10
|
+
"outDir": "./out/ts", // DO NOT CHANGE
|
|
11
|
+
"module": "esnext",
|
|
12
|
+
"target": "esnext",
|
|
13
|
+
"types": [],
|
|
14
|
+
"noUncheckedIndexedAccess": true,
|
|
15
|
+
"exactOptionalPropertyTypes": true,
|
|
16
|
+
"strict": true,
|
|
17
|
+
"jsx": "react-jsx",
|
|
18
|
+
"verbatimModuleSyntax": true,
|
|
19
|
+
"isolatedModules": true,
|
|
20
|
+
"noUncheckedSideEffectImports": true,
|
|
21
|
+
"moduleDetection": "force",
|
|
22
|
+
"skipLibCheck": true,
|
|
23
|
+
"experimentalDecorators": true
|
|
24
|
+
}
|
|
25
25
|
}
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
//==========================
|
|
2
|
-
// CSS MODULES IMPORTS
|
|
3
|
-
//==========================
|
|
4
|
-
|
|
5
|
-
// Use @use with a namespace to avoid framework variable conflicts:
|
|
6
|
-
// Example: root.$primary
|
|
7
|
-
@use "../root" as root;
|
|
8
|
-
|
|
9
|
-
// This global module contains the import framework, necessary modules for each page and any other common styles
|
|
10
|
-
@import "../global";
|
|
11
|
-
|
|
12
|
-
// Import any other module you need by import down here
|
|
13
|
-
// @import "../modules/moduleName";
|
|
14
|
-
|
|
15
|
-
//==========================
|
|
16
|
-
// PAGE CUSTOM CSS RULES
|
|
17
|
-
//==========================
|
|
18
|
-
|
|
19
|
-
// Add any custom rule specific to this page below
|
|
20
|
-
// These rules override the framework and module styles
|
|
21
|
-
// body {
|
|
22
|
-
// background-color: root.$primary-color;
|
|
23
|
-
// }
|