nibula 1.2.3 → 1.2.5

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.
Files changed (106) hide show
  1. package/.eleventy.js +81 -81
  2. package/.eleventyignore +3 -3
  3. package/.github/workflows/publish.yml +37 -0
  4. package/CHANGELOG.md +166 -135
  5. package/LICENSE +169 -169
  6. package/NOTICE +4 -4
  7. package/README.md +120 -123
  8. package/bin/create.js +507 -507
  9. package/bin/nibula.js +316 -307
  10. package/docs/Assistant CLI.md +65 -65
  11. package/docs/Backend.md +295 -295
  12. package/docs/Components.md +84 -84
  13. package/docs/Creating pages.md +64 -64
  14. package/docs/Deploy.md +189 -189
  15. package/docs/Head and SEO.md +138 -138
  16. package/docs/Javascript.md +50 -50
  17. package/docs/Styling with SCSS.md +141 -141
  18. package/nginx.conf +75 -75
  19. package/package.json +1 -1
  20. package/src/backend/.htaccess +6 -6
  21. package/src/backend/_core/composer.json +5 -5
  22. package/src/backend/_core/composer.lock +492 -492
  23. package/src/backend/_core/index.js +267 -267
  24. package/src/backend/_core/index.php +147 -147
  25. package/src/backend/_core/init.js +52 -52
  26. package/src/backend/_core/init.php +33 -33
  27. package/src/backend/_core/modules/RateLimiter.js +58 -58
  28. package/src/backend/_core/modules/RateLimiter.php +30 -30
  29. package/src/backend/_core/modules/Response.js +59 -59
  30. package/src/backend/_core/modules/Response.php +48 -48
  31. package/src/backend/api/protected/example-protected.js +23 -23
  32. package/src/backend/api/protected/example-protected.php +16 -16
  33. package/src/backend/api/public/example-public.js +24 -24
  34. package/src/backend/api/public/example-public.php +16 -16
  35. package/src/backend/backend-node.service.example +30 -30
  36. package/src/backend/database/Database.js +46 -46
  37. package/src/backend/database/Database.php +23 -23
  38. package/src/backend/example.config.js +37 -37
  39. package/src/backend/example.config.php +27 -27
  40. package/src/backend/package.json +18 -18
  41. package/src/backend/web.config +16 -16
  42. package/src/frontend/.htaccess +51 -51
  43. package/src/frontend/404.njk +17 -17
  44. package/src/frontend/assets/brand/favicon.svg +54 -54
  45. package/src/frontend/assets/brand/logo.svg +54 -54
  46. package/src/frontend/components/global/footer.njk +25 -25
  47. package/src/frontend/components/global/header.njk +6 -6
  48. package/src/frontend/components/welcome.njk +114 -114
  49. package/src/frontend/data/site.json +48 -48
  50. package/src/frontend/index.njk +8 -8
  51. package/src/frontend/js/modules/exampleModule.js +2 -2
  52. package/src/frontend/js/pages/404.js +6 -6
  53. package/src/frontend/js/pages/homepage.js +6 -6
  54. package/src/frontend/layouts/base.njk +132 -132
  55. package/src/frontend/layouts/page-components.njk +13 -13
  56. package/src/frontend/llms.njk +17 -17
  57. package/src/frontend/robots.njk +7 -7
  58. package/src/frontend/scss/modules/_animations.scss +24 -24
  59. package/src/frontend/scss/modules/_footer.scss +27 -27
  60. package/src/frontend/scss/modules/_global.scss +47 -47
  61. package/src/frontend/scss/modules/_header.scss +27 -27
  62. package/src/frontend/scss/modules/_mobile.scss +29 -29
  63. package/src/frontend/scss/modules/_root.scss +34 -34
  64. package/src/frontend/scss/modules/_typography.scss +14 -14
  65. package/src/frontend/scss/modules/frameworks/_bootstrap.scss +109 -109
  66. package/src/frontend/scss/modules/frameworks/_bulma.scss +108 -108
  67. package/src/frontend/scss/modules/frameworks/_foundation.scss +138 -139
  68. package/src/frontend/scss/modules/frameworks/_uikit.scss +109 -109
  69. package/src/frontend/scss/pages/404.scss +27 -27
  70. package/src/frontend/scss/pages/homepage.scss +22 -22
  71. package/src/frontend/sitemap.njk +17 -17
  72. package/src/frontend/ts/modules/exampleModule.ts +2 -2
  73. package/src/frontend/ts/pages/404.ts +6 -6
  74. package/src/frontend/ts/pages/homepage.ts +6 -6
  75. package/src/frontend/web.config +55 -55
  76. package/tools/assistant.js +122 -151
  77. package/tools/buildJs.js +39 -37
  78. package/tools/cleanOutput.js +23 -25
  79. package/tools/cli/prompt.js +40 -0
  80. package/tools/cli/ui.js +74 -0
  81. package/tools/config/messages.json +78 -0
  82. package/tools/config/settings.json +135 -0
  83. package/tools/lib/colors.js +17 -0
  84. package/tools/lib/files.js +65 -0
  85. package/tools/lib/logger.js +22 -0
  86. package/tools/lib/outputPath.js +141 -0
  87. package/tools/lib/pageActions.js +138 -0
  88. package/tools/lib/pageArtifacts.js +46 -0
  89. package/tools/lib/pageComponents.js +88 -0
  90. package/tools/lib/paths.js +61 -0
  91. package/tools/lib/project.js +54 -0
  92. package/tools/lib/siteData.js +93 -0
  93. package/tools/lib/text.js +47 -0
  94. package/tools/lib/validation.js +39 -0
  95. package/tools/res/templates/template.js +7 -5
  96. package/tools/res/templates/template.njk +8 -8
  97. package/tools/res/templates/template.scss +22 -22
  98. package/tools/res/templates/template.ts +7 -5
  99. package/tsconfig.json +24 -24
  100. package/tools/modules/constants.js +0 -66
  101. package/tools/modules/pageComponents.js +0 -77
  102. package/tools/modules/updateData.js +0 -90
  103. package/tools/modules/updateOutputPath.js +0 -133
  104. package/tools/modules/updatePage.js +0 -162
  105. package/tools/modules/utils.js +0 -27
  106. package/tools/modules/validation.js +0 -30
@@ -0,0 +1,46 @@
1
+ const path = require('path');
2
+ const settings = require('../config/settings.json');
3
+ const { PATHS } = require('./paths');
4
+ const { exists } = require('./files');
5
+ const { languageSettings, scriptPagesDirectory } = require('./project');
6
+ const { getCurrentOutputPath } = require('./outputPath');
7
+ const { toCamelCase, formatText } = require('./text');
8
+
9
+ const PATH_SEPARATOR = '/';
10
+
11
+ function outputRoot() {
12
+ return path.join(PATHS.root, getCurrentOutputPath() || settings.project.defaultOutputDirectory);
13
+ }
14
+
15
+ function resolveOutput(root, template, values) {
16
+ return path.join(root, ...formatText(template, values).split(PATH_SEPARATOR));
17
+ }
18
+
19
+ function routeFile(pageName) {
20
+ return path.join(PATHS.routes, `${pageName}.${settings.page.routeExtension}`);
21
+ }
22
+
23
+ function pageExists(pageName) {
24
+ return exists(routeFile(pageName));
25
+ }
26
+
27
+ function getPageArtifacts(pageName) {
28
+ const camelName = toCamelCase(pageName);
29
+ const values = { camelName, pageName };
30
+ const root = outputRoot();
31
+
32
+ return {
33
+ camelName,
34
+ source: {
35
+ style: path.join(PATHS.stylePages, `${camelName}.${settings.page.styleExtension}`),
36
+ script: path.join(scriptPagesDirectory(), `${camelName}.${languageSettings().extension}`),
37
+ route: routeFile(pageName),
38
+ },
39
+ output: {
40
+ files: settings.page.outputFiles.map((template) => resolveOutput(root, template, values)),
41
+ directories: settings.page.outputDirectories.map((template) => resolveOutput(root, template, values)),
42
+ },
43
+ };
44
+ }
45
+
46
+ module.exports = { getPageArtifacts, pageExists };
@@ -0,0 +1,88 @@
1
+ const path = require('path');
2
+ const settings = require('../config/settings.json');
3
+ const { PATHS } = require('./paths');
4
+ const { exists, readText, writeText } = require('./files');
5
+ const { log } = require('./logger');
6
+ const { toCamelCase, formatText } = require('./text');
7
+
8
+ const EXTRA_BLANK_LINES_PATTERN = /\n\s*\n\s*\n/g;
9
+ const BLANK_LINES = '\n\n';
10
+ const ANCHOR = settings.pageComponents.anchor;
11
+
12
+ function blockPattern(camelName) {
13
+ return new RegExp(
14
+ `[ \\t]*\\{%\\s*elif\\s+title\\s*==\\s*"${camelName}"\\s*%\\}[\\s\\S]*?(?=[ \\t]*\\{%\\s*(?:elif|else|endif))`
15
+ );
16
+ }
17
+
18
+ function conditionFor(camelName) {
19
+ return formatText(settings.pageComponents.condition, { camelName });
20
+ }
21
+
22
+ function readPageComponents() {
23
+ if (!exists(PATHS.pageComponents)) {
24
+ log('components.fileMissing', { path: PATHS.pageComponents });
25
+ return null;
26
+ }
27
+ return readText(PATHS.pageComponents);
28
+ }
29
+
30
+ function writePageComponents(content) {
31
+ writeText(PATHS.pageComponents, content);
32
+ }
33
+
34
+ function addPageBlock(pageName) {
35
+ const content = readPageComponents();
36
+ if (content === null) return;
37
+
38
+ const camelName = toCamelCase(pageName);
39
+ const condition = conditionFor(camelName);
40
+ if (content.includes(condition)) return;
41
+
42
+ if (!content.includes(ANCHOR)) {
43
+ log('components.anchorMissing', { anchor: ANCHOR, file: path.basename(PATHS.pageComponents) });
44
+ return;
45
+ }
46
+
47
+ const block = `${condition}\n${settings.pageComponents.include}\n\n`;
48
+
49
+ writePageComponents(content.replace(ANCHOR, `${block}${ANCHOR}`));
50
+ log('components.blockAdded', { name: camelName });
51
+ }
52
+
53
+ function removePageBlock(pageName) {
54
+ const content = readPageComponents();
55
+ if (content === null) return;
56
+
57
+ const camelName = toCamelCase(pageName);
58
+ if (!blockPattern(camelName).test(content)) {
59
+ log('components.blockMissing', { name: camelName });
60
+ return;
61
+ }
62
+
63
+ const updated = content
64
+ .replace(blockPattern(camelName), '')
65
+ .replace(EXTRA_BLANK_LINES_PATTERN, BLANK_LINES);
66
+
67
+ writePageComponents(updated);
68
+ log('components.blockRemoved', { name: camelName });
69
+ }
70
+
71
+ function renamePageBlock(oldName, newName) {
72
+ const content = readPageComponents();
73
+ if (content === null) return;
74
+
75
+ const oldCamelName = toCamelCase(oldName);
76
+ const newCamelName = toCamelCase(newName);
77
+ const oldCondition = conditionFor(oldCamelName);
78
+
79
+ if (!content.includes(oldCondition)) {
80
+ log('components.blockMissing', { name: oldCamelName });
81
+ return;
82
+ }
83
+
84
+ writePageComponents(content.replace(oldCondition, conditionFor(newCamelName)));
85
+ log('components.blockRenamed', { source: oldCamelName, destination: newCamelName });
86
+ }
87
+
88
+ module.exports = { addPageBlock, removePageBlock, renamePageBlock };
@@ -0,0 +1,61 @@
1
+ const fs = require('fs');
2
+ const path = require('path');
3
+ const settings = require('../config/settings.json');
4
+ const { paint } = require('./colors');
5
+ const { message } = require('./logger');
6
+
7
+ const PACKAGE_ROOT = path.resolve(__dirname, '..', '..');
8
+ const PATH_SEPARATOR = '/';
9
+ const NOT_INSIDE_PROJECT_MESSAGE = paint('red', message('project.notInside'));
10
+
11
+ let cachedProjectRoot = null;
12
+
13
+ function findProjectRoot(start) {
14
+ let directory = path.resolve(start ?? process.cwd());
15
+ while (true) {
16
+ if (fs.existsSync(path.join(directory, settings.project.marker))) return directory;
17
+ const parent = path.dirname(directory);
18
+ if (parent === directory) return null;
19
+ directory = parent;
20
+ }
21
+ }
22
+
23
+ function projectRoot() {
24
+ if (cachedProjectRoot) return cachedProjectRoot;
25
+ const root = findProjectRoot();
26
+ if (!root) {
27
+ console.error(NOT_INSIDE_PROJECT_MESSAGE);
28
+ process.exit(1);
29
+ }
30
+ cachedProjectRoot = root;
31
+ return root;
32
+ }
33
+
34
+ function resolveFromProject(relativePath) {
35
+ return path.join(projectRoot(), ...relativePath.split(PATH_SEPARATOR));
36
+ }
37
+
38
+ function resolveFromPackage(relativePath) {
39
+ return path.join(PACKAGE_ROOT, ...relativePath.split(PATH_SEPARATOR));
40
+ }
41
+
42
+ const PATHS = Object.freeze({
43
+ get root() { return projectRoot(); },
44
+ get eleventyConfig() { return resolveFromProject(settings.paths.eleventyConfig); },
45
+ get packageJson() { return resolveFromProject(settings.paths.packageJson); },
46
+ get typescriptConfig() { return resolveFromProject(settings.paths.typescriptConfig); },
47
+ get routes() { return resolveFromProject(settings.paths.routes); },
48
+ get stylePages() { return resolveFromProject(settings.paths.stylePages); },
49
+ get siteData() { return resolveFromProject(settings.paths.siteData); },
50
+ get pageComponents() { return resolveFromProject(settings.paths.pageComponents); },
51
+ get templates() { return resolveFromPackage(settings.paths.templates); },
52
+ });
53
+
54
+ module.exports = {
55
+ PATHS,
56
+ PACKAGE_ROOT,
57
+ NOT_INSIDE_PROJECT_MESSAGE,
58
+ findProjectRoot,
59
+ resolveFromProject,
60
+ resolveFromPackage,
61
+ };
@@ -0,0 +1,54 @@
1
+ const fs = require('fs');
2
+ const settings = require('../config/settings.json');
3
+ const { PATHS, resolveFromProject } = require('./paths');
4
+ const { readJson, writeJson } = require('./files');
5
+
6
+ const JAVASCRIPT = 'javascript';
7
+ const TYPESCRIPT = 'typescript';
8
+ const ENTRY_WILDCARD = '*';
9
+
10
+ function isTypeScriptProject() {
11
+ return fs.existsSync(PATHS.typescriptConfig);
12
+ }
13
+
14
+ function currentLanguage() {
15
+ return isTypeScriptProject() ? TYPESCRIPT : JAVASCRIPT;
16
+ }
17
+
18
+ function languageSettings(language) {
19
+ return settings.languages[language ?? currentLanguage()];
20
+ }
21
+
22
+ function scriptPagesDirectory(language) {
23
+ return resolveFromProject(languageSettings(language).pages);
24
+ }
25
+
26
+ function scriptEntries(language) {
27
+ const { pages, extension } = languageSettings(language);
28
+ return `${pages}/${ENTRY_WILDCARD}.${extension}`;
29
+ }
30
+
31
+ function allScriptEntries() {
32
+ return Object.keys(settings.languages).map((language) => scriptEntries(language));
33
+ }
34
+
35
+ function readPackageJson() {
36
+ return readJson(PATHS.packageJson);
37
+ }
38
+
39
+ function writePackageJson(content) {
40
+ writeJson(PATHS.packageJson, content);
41
+ }
42
+
43
+ module.exports = {
44
+ JAVASCRIPT,
45
+ TYPESCRIPT,
46
+ isTypeScriptProject,
47
+ currentLanguage,
48
+ languageSettings,
49
+ scriptPagesDirectory,
50
+ scriptEntries,
51
+ allScriptEntries,
52
+ readPackageJson,
53
+ writePackageJson,
54
+ };
@@ -0,0 +1,93 @@
1
+ const path = require('path');
2
+ const settings = require('../config/settings.json');
3
+ const { PATHS } = require('./paths');
4
+ const { exists, readText, writeJson } = require('./files');
5
+ const { log } = require('./logger');
6
+ const { toCamelCase, toTitleCase, formatValue } = require('./text');
7
+
8
+ const PAGES_KEY = settings.page.dataKeys.pages;
9
+ const SEO_KEY = settings.page.dataKeys.seo;
10
+ const TITLE_KEY = settings.page.dataKeys.title;
11
+
12
+ function readSiteData() {
13
+ if (!exists(PATHS.siteData)) {
14
+ log('siteData.fileMissing', { path: PATHS.siteData });
15
+ return null;
16
+ }
17
+ try {
18
+ const data = JSON.parse(readText(PATHS.siteData));
19
+ if (!data[PAGES_KEY] || typeof data[PAGES_KEY] !== 'object') data[PAGES_KEY] = {};
20
+ return data;
21
+ } catch (error) {
22
+ log('siteData.parseFailed', { file: path.basename(PATHS.siteData), error: error.message });
23
+ return null;
24
+ }
25
+ }
26
+
27
+ function writeSiteData(data) {
28
+ writeJson(PATHS.siteData, data);
29
+ }
30
+
31
+ function createRecord(pageName) {
32
+ return formatValue(settings.page.defaultData, { title: toTitleCase(pageName) });
33
+ }
34
+
35
+ function addSiteData(pageName) {
36
+ const data = readSiteData();
37
+ if (!data) return;
38
+
39
+ const camelName = toCamelCase(pageName);
40
+ if (data[PAGES_KEY][camelName]) {
41
+ log('siteData.recordExists', { name: camelName });
42
+ return;
43
+ }
44
+
45
+ data[PAGES_KEY][camelName] = createRecord(pageName);
46
+
47
+ writeSiteData(data);
48
+ log('siteData.recordAdded', { name: camelName });
49
+ }
50
+
51
+ function removeSiteData(pageName) {
52
+ const data = readSiteData();
53
+ if (!data) return;
54
+
55
+ const camelName = toCamelCase(pageName);
56
+ if (!data[PAGES_KEY][camelName]) {
57
+ log('siteData.recordMissing', { name: camelName });
58
+ return;
59
+ }
60
+
61
+ delete data[PAGES_KEY][camelName];
62
+ writeSiteData(data);
63
+ log('siteData.recordRemoved', { name: camelName });
64
+ }
65
+
66
+ function renameSiteData(oldName, newName) {
67
+ const data = readSiteData();
68
+ if (!data) return;
69
+
70
+ const oldCamelName = toCamelCase(oldName);
71
+ const newCamelName = toCamelCase(newName);
72
+
73
+ if (!data[PAGES_KEY][oldCamelName]) {
74
+ log('siteData.recordMissing', { name: oldCamelName });
75
+ return;
76
+ }
77
+ if (data[PAGES_KEY][newCamelName]) {
78
+ log('siteData.recordExists', { name: newCamelName });
79
+ return;
80
+ }
81
+
82
+ const record = data[PAGES_KEY][oldCamelName];
83
+ data[PAGES_KEY][newCamelName] = {
84
+ ...record,
85
+ [SEO_KEY]: { ...record[SEO_KEY], [TITLE_KEY]: toTitleCase(newName) },
86
+ };
87
+ delete data[PAGES_KEY][oldCamelName];
88
+
89
+ writeSiteData(data);
90
+ log('siteData.recordRenamed', { source: oldCamelName, destination: newCamelName });
91
+ }
92
+
93
+ module.exports = { addSiteData, removeSiteData, renameSiteData };
@@ -0,0 +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 };
@@ -0,0 +1,39 @@
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.pageComponents, path: PATHS.pageComponents },
16
+ { label: message('validation.templatesLabel'), path: PATHS.templates },
17
+ ];
18
+ }
19
+
20
+ function validatePageName(name) {
21
+ if (!name) return message('validation.invalidName');
22
+ if (!NAME_PATTERN.test(name)) return message('validation.invalidNameCharacters');
23
+ if (LEADING_DIGIT_PATTERN.test(name)) return message('validation.nameStartsWithNumber');
24
+ if (settings.page.protected.includes(name)) return message('validation.protectedName', { name });
25
+ return null;
26
+ }
27
+
28
+ function validateOutputPath(input) {
29
+ const value = (input ?? '').trim();
30
+ if (!value) return message('validation.invalidPath');
31
+ if (INVALID_PATH_PATTERN.test(value)) return message('validation.invalidPathCharacters');
32
+ return null;
33
+ }
34
+
35
+ function checkRequiredFiles() {
36
+ return requiredFiles().filter((item) => !exists(item.path));
37
+ }
38
+
39
+ module.exports = { validatePageName, validateOutputPath, checkRequiredFiles };
@@ -1,5 +1,7 @@
1
- // import { initExampleModule } from '../modules/exampleModule.js';
2
-
3
- document.addEventListener("DOMContentLoaded", () => {
4
- // initExampleModule();
5
- });
1
+ // import { initExampleModule } from '../modules/exampleModule.js';
2
+
3
+ document.addEventListener("DOMContentLoaded", () => {
4
+ // initExampleModule();
5
+ });
6
+
7
+ // 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 "../modules/root" as root;
8
-
9
- // This global module contains the import framework, necessary modules for each page and any other common styles
10
- @import "../modules/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;
1
+ //==========================
2
+ // CSS MODULES IMPORTS
3
+ //==========================
4
+
5
+ // Use @use with a namespace to avoid framework variable conflicts:
6
+ // Example: root.$primary
7
+ @use "../modules/root" as root;
8
+
9
+ // This global module contains the import framework, necessary modules for each page and any other common styles
10
+ @import "../modules/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;
23
23
  // }
@@ -1,5 +1,7 @@
1
- // import { initExampleModule } from '../modules/exampleModule';
2
-
3
- document.addEventListener("DOMContentLoaded", (): void => {
4
- // initExampleModule();
5
- });
1
+ // import { initExampleModule } from '../modules/exampleModule';
2
+
3
+ document.addEventListener("DOMContentLoaded", (): void => {
4
+ // initExampleModule();
5
+ });
6
+
7
+ // 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,66 +0,0 @@
1
- const fs = require('fs');
2
- const path = require('path');
3
-
4
- const PACKAGE_ROOT = path.resolve(__dirname, '..', '..');
5
- const TEMPLATES_DIR = path.join(PACKAGE_ROOT, 'tools', 'res', 'templates');
6
-
7
- const PROJECT_MARKER = '.eleventy.js';
8
-
9
- const PROTECTED_PAGES = Object.freeze(['homepage', '404']);
10
-
11
- const color = Object.freeze({
12
- reset: '\x1b[0m',
13
- bold: '\x1b[1m',
14
- dim: '\x1b[2m',
15
- red: '\x1b[31m',
16
- green: '\x1b[32m',
17
- yellow: '\x1b[33m',
18
- blue: '\x1b[34m',
19
- magenta: '\x1b[35m',
20
- cyan: '\x1b[36m',
21
- });
22
-
23
- const NOT_INSIDE_PROJECT_MESSAGE = `${color.red}Not inside a Nibula project.${color.reset}`;
24
-
25
- function findProjectRoot(start) {
26
- let dir = path.resolve(start ?? process.cwd());
27
- while (true) {
28
- if (fs.existsSync(path.join(dir, PROJECT_MARKER))) return dir;
29
- const parent = path.dirname(dir);
30
- if (parent === dir) return null;
31
- dir = parent;
32
- }
33
- }
34
-
35
- let cachedRoot = null;
36
-
37
- function projectRoot() {
38
- if (cachedRoot) return cachedRoot;
39
- const root = findProjectRoot();
40
- if (!root) {
41
- console.error(NOT_INSIDE_PROJECT_MESSAGE);
42
- process.exit(1);
43
- }
44
- cachedRoot = root;
45
- return root;
46
- }
47
-
48
- function frontendDir() {
49
- return path.join(projectRoot(), 'src', 'frontend');
50
- }
51
-
52
- const PATHS = Object.freeze({
53
- get root() { return projectRoot(); },
54
- get routes() { return path.join(frontendDir(), 'routes'); },
55
- get scssPages() { return path.join(frontendDir(), 'scss', 'pages'); },
56
- get jsPages() { return path.join(frontendDir(), 'js', 'pages'); },
57
- get tsPages() { return path.join(frontendDir(), 'ts', 'pages'); },
58
- get siteData() { return path.join(frontendDir(), 'data', 'site.json'); },
59
- get pageComponents() { return path.join(frontendDir(), 'layouts', 'page-components.njk'); },
60
- get eleventyConfig() { return path.join(projectRoot(), '.eleventy.js'); },
61
- get packageJson() { return path.join(projectRoot(), 'package.json'); },
62
- get tsconfig() { return path.join(projectRoot(), 'tsconfig.json'); },
63
- templates: TEMPLATES_DIR,
64
- });
65
-
66
- module.exports = { PATHS, PROJECT_MARKER, PROTECTED_PAGES, color, NOT_INSIDE_PROJECT_MESSAGE, findProjectRoot };