@reldens/cms 0.9.0 → 0.10.0

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/lib/installer.js CHANGED
@@ -8,7 +8,6 @@ const { FileHandler, Encryptor } = require('@reldens/server-utils');
8
8
  const { DriversMap, EntitiesGenerator, PrismaSchemaGenerator } = require('@reldens/storage');
9
9
  const { EntitiesLoader } = require('./entities-loader');
10
10
  const { Logger, sc } = require('@reldens/utils');
11
- const mustache = require('mustache');
12
11
 
13
12
  class Installer
14
13
  {
@@ -18,6 +17,7 @@ class Installer
18
17
  this.app = sc.get(props, 'app', false);
19
18
  this.appServer = sc.get(props, 'appServer', false);
20
19
  this.appServerFactory = sc.get(props, 'appServerFactory', false);
20
+ this.renderEngine = sc.get(props, 'renderEngine', false);
21
21
  this.projectRoot = sc.get(props, 'projectRoot', './');
22
22
  this.projectTemplatesPath = FileHandler.joinPaths(this.projectRoot, 'templates');
23
23
  this.projectPublicPath = FileHandler.joinPaths(this.projectRoot, 'public');
@@ -43,7 +43,7 @@ class Installer
43
43
  return FileHandler.exists(this.installLockPath);
44
44
  }
45
45
 
46
- async prepareSetup(app, appServer, appServerFactory)
46
+ async prepareSetup(app, appServer, appServerFactory, renderEngine)
47
47
  {
48
48
  if(!app){
49
49
  Logger.error('Missing app on prepareSetup for Installer.');
@@ -53,9 +53,14 @@ class Installer
53
53
  Logger.error('Missing appServerFactory on prepareSetup for Installer.');
54
54
  return false;
55
55
  }
56
+ if(!renderEngine){
57
+ Logger.error('Missing renderEngine for Installer.');
58
+ return false;
59
+ }
56
60
  this.app = app;
57
61
  this.appServerFactory = appServerFactory;
58
62
  this.appServer = appServer;
63
+ this.renderEngine = renderEngine;
59
64
  app.use('/install-assets', appServerFactory.applicationFramework.static(this.installerPath, {index: false}));
60
65
  app.use(appServerFactory.session({
61
66
  secret: Encryptor.generateSecretKey(),
@@ -88,7 +93,7 @@ class Installer
88
93
  if(errorParam){
89
94
  contentParams.errorMessage = this.getErrorMessage(errorParam);
90
95
  }
91
- return res.send(mustache.render(content, contentParams));
96
+ return res.send(this.renderEngine.render(content, contentParams));
92
97
  }
93
98
  if('/install' !== urlPath){
94
99
  return res.redirect('/');
@@ -161,7 +166,9 @@ class Installer
161
166
  'install-cms-tables': 'install.sql',
162
167
  'install-user-auth': 'users-authentication.sql',
163
168
  'install-default-user': 'default-user.sql',
164
- 'install-default-homepage': 'default-homepage.sql'
169
+ 'install-default-homepage': 'default-homepage.sql',
170
+ 'install-default-blocks': 'default-blocks.sql',
171
+ 'install-entity-access': 'default-entity-access.sql'
165
172
  };
166
173
  for(let checkboxName of Object.keys(executeFiles)){
167
174
  let fileName = executeFiles[checkboxName];
@@ -191,17 +198,24 @@ class Installer
191
198
  await this.appServer.close();
192
199
  }
193
200
  Logger.debug('Running postInstallCallback.');
194
- await this.postInstallCallback({
201
+ let callbackResult = await this.postInstallCallback({
195
202
  loadedEntities: this.entitiesLoader.loadEntities(selectedDriver),
196
203
  mappedVariablesForConfig
197
204
  });
205
+ if(false === callbackResult){
206
+ Logger.error('Post-install callback failed.');
207
+ return res.redirect('/?error=installation-entities-callback-failed');
208
+ }
198
209
  }
199
210
  await this.createLockFile();
200
211
  Logger.info('Installation successful!');
201
212
  let successContent = 'Installation successful! Run "node ." to start your CMS.';
202
213
  let successFileContent = FileHandler.readFile(FileHandler.joinPaths(this.installerPath, 'success.html'));
203
214
  if(successFileContent){
204
- successContent = mustache.render(successFileContent, {adminPath: templateVariables['app-admin-path']});
215
+ successContent = this.renderEngine.render(
216
+ successFileContent,
217
+ {adminPath: templateVariables['app-admin-path']}
218
+ );
205
219
  }
206
220
  return res.send(successContent);
207
221
  } catch (error) {
@@ -245,6 +259,7 @@ class Installer
245
259
  {
246
260
  let generator = new PrismaSchemaGenerator({
247
261
  ...connectionData,
262
+ dataProxy: true,
248
263
  prismaSchemaPath: this.projectRoot+'/prisma'
249
264
  });
250
265
  let success = await generator.generate();
@@ -263,7 +278,7 @@ class Installer
263
278
  Logger.error('Template ".env.dist" not found: '+envTemplatePath);
264
279
  return false;
265
280
  }
266
- return FileHandler.writeFile(this.envFilePath, mustache.render(envTemplateContent, templateVariables));
281
+ return FileHandler.writeFile(this.envFilePath, this.renderEngine.render(envTemplateContent, templateVariables));
267
282
  }
268
283
 
269
284
  mapVariablesForTemplate(configVariables)
@@ -310,7 +325,7 @@ class Installer
310
325
  }
311
326
  let indexTemplate = FileHandler.readFile(this.indexTemplatePath);
312
327
  let driverKey = templateVariables['db-storage-driver'];
313
- let indexContent = mustache.render(indexTemplate, {driverKey});
328
+ let indexContent = this.renderEngine.render(indexTemplate, {driverKey});
314
329
  let indexFilePath = FileHandler.joinPaths(this.projectRoot, 'index.js');
315
330
  if(FileHandler.exists(indexFilePath)){
316
331
  Logger.info('Index.js file already exists, the CMS installer will not override the existent one.');
@@ -353,6 +368,7 @@ class Installer
353
368
  async prepareProjectDirectories()
354
369
  {
355
370
  FileHandler.createFolder(this.projectTemplatesPath);
371
+ FileHandler.createFolder(FileHandler.joinPaths(this.projectTemplatesPath, 'layouts'));
356
372
  FileHandler.createFolder(this.projectPublicPath);
357
373
  FileHandler.createFolder(this.projectPublicAssetsPath);
358
374
  FileHandler.createFolder(this.projectCssPath);
@@ -360,7 +376,6 @@ class Installer
360
376
  let baseFiles = [
361
377
  'page.html',
362
378
  '404.html',
363
- 'layout.html',
364
379
  'browserconfig.xml',
365
380
  'favicon.ico',
366
381
  'site.webmanifest'
@@ -371,6 +386,10 @@ class Installer
371
386
  FileHandler.joinPaths(this.projectTemplatesPath, fileName)
372
387
  );
373
388
  }
389
+ FileHandler.copyFile(
390
+ FileHandler.joinPaths(this.defaultTemplatesPath, 'layouts', 'default.html'),
391
+ FileHandler.joinPaths(this.projectTemplatesPath, 'layouts', 'default.html')
392
+ );
374
393
  FileHandler.copyFile(
375
394
  FileHandler.joinPaths(this.defaultTemplatesPath, 'css', 'styles.css'),
376
395
  FileHandler.joinPaths(this.projectCssPath, 'styles.css')
@@ -379,6 +398,14 @@ class Installer
379
398
  FileHandler.joinPaths(this.defaultTemplatesPath, 'js', 'scripts.js'),
380
399
  FileHandler.joinPaths(this.projectJsPath, 'scripts.js')
381
400
  );
401
+ FileHandler.copyFolderSync(
402
+ FileHandler.joinPaths(this.defaultTemplatesPath, 'partials'),
403
+ FileHandler.joinPaths(this.projectTemplatesPath, 'partials')
404
+ );
405
+ FileHandler.copyFolderSync(
406
+ FileHandler.joinPaths(this.defaultTemplatesPath, 'domains'),
407
+ FileHandler.joinPaths(this.projectTemplatesPath, 'domains')
408
+ );
382
409
  return true;
383
410
  }
384
411
 
package/lib/manager.js CHANGED
@@ -37,6 +37,7 @@ class Manager
37
37
  this.entitiesTranslations = sc.get(props, 'entitiesTranslations', {});
38
38
  this.entitiesConfig = sc.get(props, 'entitiesConfig', {});
39
39
  this.processedEntities = sc.get(props, 'processedEntities', {});
40
+ this.entityAccess = sc.get(props, 'entityAccess', {});
40
41
  this.authenticationMethod = sc.get(props, 'authenticationMethod', 'db-users');
41
42
  this.authenticationCallback = sc.get(props, 'authenticationCallback', false);
42
43
  this.events = sc.get(props, 'events', EventsManagerSingleton);
@@ -51,11 +52,16 @@ class Manager
51
52
  this.companyName = sc.get(props, 'companyName', 'Reldens - CMS');
52
53
  this.logo = sc.get(props, 'logo', '/assets/web/reldens-your-logo-mage.png');
53
54
  this.favicon = sc.get(props, 'favicon', '/assets/web/favicon.ico');
55
+ this.defaultDomain = sc.get(props, 'defaultDomain', (process.env.RELDENS_DEFAULT_DOMAIN || ''));
56
+ this.domainMapping = sc.get(props, 'domainMapping', sc.toJson(process.env.RELDENS_DOMAIN_MAPPING));
57
+ this.siteKeyMapping = sc.get(props, 'siteKeyMapping', sc.toJson(process.env.RELDENS_SITE_KEY_MAPPING));
58
+ this.templateExtensions = sc.get(props, 'templateExtensions', ['.html', '.mustache', '.template']);
54
59
  this.app = sc.get(props, 'app', false);
55
60
  this.appServer = sc.get(props, 'appServer', false);
56
61
  this.dataServer = sc.get(props, 'dataServer', false);
57
62
  this.adminManager = sc.get(props, 'adminManager', false);
58
63
  this.frontend = sc.get(props, 'frontend', false);
64
+ this.renderEngine = sc.get(props, 'renderEngine', mustache);
59
65
  this.appServerFactory = new AppServerFactory();
60
66
  this.adminEntitiesGenerator = new AdminEntitiesGenerator();
61
67
  this.installer = new Installer({
@@ -165,7 +171,7 @@ class Manager
165
171
  }
166
172
  if(!this.isInstalled()){
167
173
  Logger.info('CMS not installed, preparing setup');
168
- await this.installer.prepareSetup(this.app, this.appServer, this.appServerFactory);
174
+ await this.installer.prepareSetup(this.app, this.appServer, this.appServerFactory, this.renderEngine);
169
175
  if(!this.useProvidedServer){
170
176
  await this.appServer.listen(this.config.port);
171
177
  }
@@ -185,7 +191,6 @@ class Manager
185
191
  async initializeCmsAfterInstall(props)
186
192
  {
187
193
  try {
188
- //Logger.debug('Loaded entities post install.', props.loadedEntities);
189
194
  this.rawRegisteredEntities = props.loadedEntities.rawRegisteredEntities;
190
195
  this.entitiesTranslations = props.loadedEntities.entitiesTranslations;
191
196
  this.entitiesConfig = props.loadedEntities.entitiesConfig;
@@ -206,6 +211,9 @@ class Manager
206
211
  return false;
207
212
  }
208
213
  }
214
+ if(0 < Object.keys(this.entityAccess).length){
215
+ await this.setupEntityAccess();
216
+ }
209
217
  if(!this.loadProcessedEntities()){
210
218
  return false;
211
219
  }
@@ -228,6 +236,25 @@ class Manager
228
236
  return true;
229
237
  }
230
238
 
239
+ async setupEntityAccess()
240
+ {
241
+ let accessEntity = this.dataServer.getEntity('cmsEntityAccess');
242
+ if(!accessEntity){
243
+ Logger.warning('Entity access control table not found.');
244
+ return;
245
+ }
246
+ for(let entityName of Object.keys(this.entityAccess)){
247
+ let accessConfig = this.entityAccess[entityName];
248
+ if(!await accessEntity.loadOneBy('entity_name', entityName)){
249
+ await accessEntity.create({
250
+ entity_name: entityName,
251
+ is_public: sc.get(accessConfig, 'public', false),
252
+ allowed_operations: JSON.stringify(sc.get(accessConfig, 'operations', ['read']))
253
+ });
254
+ }
255
+ }
256
+ }
257
+
231
258
  loadProcessedEntities()
232
259
  {
233
260
  if(0 === Object.keys(this.processedEntities).length){
@@ -354,12 +381,12 @@ class Manager
354
381
  return true;
355
382
  }
356
383
 
357
- async renderCallback(template, params)
384
+ async renderCallback(template, params = {})
358
385
  {
359
386
  if(!template){
360
387
  return '';
361
388
  }
362
- return mustache.render(template, params);
389
+ return this.renderEngine.render(template, params);
363
390
  }
364
391
 
365
392
  async initializeFrontend()
@@ -367,8 +394,13 @@ class Manager
367
394
  this.frontend = new Frontend({
368
395
  app: this.app,
369
396
  dataServer: this.dataServer,
397
+ renderEngine: this.renderEngine,
370
398
  projectRoot: this.projectRoot,
371
- appServerFactory: this.appServerFactory
399
+ appServerFactory: this.appServerFactory,
400
+ defaultDomain: this.defaultDomain,
401
+ domainMapping: this.domainMapping,
402
+ siteKeyMapping: this.siteKeyMapping,
403
+ templateExtensions: this.templateExtensions
372
404
  });
373
405
  return await this.frontend.initialize();
374
406
  }
@@ -0,0 +1,8 @@
1
+
2
+ -- Default CMS blocks:
3
+
4
+ REPLACE INTO `cms_blocks` (`name`, `title`, `content`, `is_active`) VALUES
5
+ ('header-main', 'Main Header', '{{>header}}', 1),
6
+ ('sidebar-left', 'Left Sidebar', '<aside class="sidebar-left">{{>sidebar}}</aside>', 1),
7
+ ('sidebar-right', 'Right Sidebar', '<aside class="sidebar-right">{{>sidebar}}</aside>', 1),
8
+ ('footer-main', 'Main Footer', '{{>footer}}', 1);
@@ -0,0 +1,9 @@
1
+
2
+ -- Default entity access rules:
3
+
4
+ REPLACE INTO `cms_entity_access` (`entity_name`, `is_public`, `allowed_operations`) VALUES
5
+ ('cms_pages', TRUE, '["read"]'),
6
+ ('routes', FALSE, '[]'),
7
+ ('users', FALSE, '[]'),
8
+ ('cms_blocks', FALSE, '[]'),
9
+ ('cms_entity_access', FALSE, '[]');
@@ -3,7 +3,7 @@
3
3
 
4
4
  -- Create a default homepage route if not exists
5
5
  REPLACE INTO `cms_pages` (`id`, `title`, `content`, `template`, `created_at`) VALUES
6
- (1, 'Home', '<h1>Welcome to Reldens CMS</h1><p>This is your homepage. Edit this content in the admin panel.</p>', 'page', NOW());
6
+ (1, 'Home', '<h1>Welcome to Reldens CMS</h1><p>This is your homepage. Edit this content in the admin panel.</p>', NULL, NOW());
7
7
 
8
8
  -- Create a default route to the homepage
9
9
  REPLACE INTO `routes` (`id`, `path`, `router`, `content_id`, `title`, `meta_description`, `status`, `created_at`) VALUES
@@ -2,10 +2,10 @@
2
2
  -- Install Reldens CMS
3
3
 
4
4
  CREATE TABLE IF NOT EXISTS `routes` (
5
- `id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
5
+ `id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
6
6
  `path` VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
7
7
  `router` VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
8
- `content_id` INT(10) UNSIGNED NOT NULL,
8
+ `content_id` INT UNSIGNED NOT NULL,
9
9
  `title` VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
10
10
  `meta_description` TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL,
11
11
  `canonical_url` VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL,
@@ -25,12 +25,10 @@ CREATE TABLE IF NOT EXISTS `routes` (
25
25
  ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
26
26
 
27
27
  CREATE TABLE IF NOT EXISTS `cms_pages_meta` (
28
- `id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
29
- `page_id` INT(10) UNSIGNED NOT NULL,
30
- `layout` VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL,
28
+ `id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
29
+ `page_id` INT UNSIGNED NOT NULL,
31
30
  `publish_date` TIMESTAMP NULL,
32
31
  `expire_date` TIMESTAMP NULL,
33
- `author_id` INT(10) UNSIGNED NULL,
34
32
  `created_at` TIMESTAMP NOT NULL DEFAULT (NOW()),
35
33
  `updated_at` TIMESTAMP NOT NULL DEFAULT (NOW()) ON UPDATE CURRENT_TIMESTAMP,
36
34
  PRIMARY KEY (`id`) USING BTREE,
@@ -38,21 +36,22 @@ CREATE TABLE IF NOT EXISTS `cms_pages_meta` (
38
36
  ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
39
37
 
40
38
  CREATE TABLE IF NOT EXISTS `cms_pages` (
41
- `id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
39
+ `id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
42
40
  `title` VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
43
41
  `content` LONGTEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL,
44
42
  `markdown` LONGTEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL,
45
43
  `json_data` JSON NULL,
46
44
  `template` VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL,
45
+ `layout` VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT 'default',
47
46
  `created_at` TIMESTAMP NOT NULL DEFAULT (NOW()),
48
47
  `updated_at` TIMESTAMP NOT NULL DEFAULT (NOW()) ON UPDATE CURRENT_TIMESTAMP,
49
48
  PRIMARY KEY (`id`) USING BTREE
50
49
  ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
51
50
 
52
51
  CREATE TABLE IF NOT EXISTS `entities_meta` (
53
- `id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
52
+ `id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
54
53
  `entity_name` VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
55
- `entity_id` INT(10) UNSIGNED NOT NULL,
54
+ `entity_id` INT UNSIGNED NOT NULL,
56
55
  `meta_key` VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
57
56
  `meta_value` LONGTEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL,
58
57
  `created_at` TIMESTAMP NOT NULL DEFAULT (NOW()),
@@ -60,3 +59,29 @@ CREATE TABLE IF NOT EXISTS `entities_meta` (
60
59
  PRIMARY KEY (`id`) USING BTREE,
61
60
  UNIQUE KEY `entity_meta` (`entity_name`, `entity_id`, `meta_key`) USING BTREE
62
61
  ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
62
+
63
+ CREATE TABLE IF NOT EXISTS `cms_blocks` (
64
+ `id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
65
+ `name` VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
66
+ `title` VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL,
67
+ `content` LONGTEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL,
68
+ `template_file` VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL,
69
+ `variables` JSON NULL,
70
+ `is_active` BOOLEAN NOT NULL DEFAULT TRUE,
71
+ `created_at` TIMESTAMP NOT NULL DEFAULT (NOW()),
72
+ `updated_at` TIMESTAMP NOT NULL DEFAULT (NOW()) ON UPDATE CURRENT_TIMESTAMP,
73
+ PRIMARY KEY (`id`) USING BTREE,
74
+ UNIQUE KEY `name` (`name`) USING BTREE
75
+ ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
76
+
77
+ CREATE TABLE IF NOT EXISTS `cms_entity_access` (
78
+ `id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
79
+ `entity_name` VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
80
+ `is_public` BOOLEAN NOT NULL DEFAULT FALSE,
81
+ `allowed_operations` JSON NULL DEFAULT ('["read"]'),
82
+ `access_rules` JSON NULL,
83
+ `created_at` TIMESTAMP NOT NULL DEFAULT (NOW()),
84
+ `updated_at` TIMESTAMP NOT NULL DEFAULT (NOW()) ON UPDATE CURRENT_TIMESTAMP,
85
+ PRIMARY KEY (`id`) USING BTREE,
86
+ UNIQUE KEY `entity_name` (`entity_name`) USING BTREE
87
+ ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
@@ -2,11 +2,11 @@
2
2
  -- Default db-users authentication:
3
3
 
4
4
  CREATE TABLE IF NOT EXISTS `users` (
5
- `id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
5
+ `id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
6
6
  `email` VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
7
7
  `username` VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
8
8
  `password` VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
9
- `role_id` INT(10) UNSIGNED NOT NULL,
9
+ `role_id` INT UNSIGNED NOT NULL,
10
10
  `status` VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
11
11
  `created_at` TIMESTAMP NOT NULL DEFAULT (NOW()),
12
12
  `updated_at` TIMESTAMP NOT NULL DEFAULT (NOW()) ON UPDATE CURRENT_TIMESTAMP,
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@reldens/cms",
3
3
  "scope": "@reldens",
4
- "version": "0.9.0",
4
+ "version": "0.10.0",
5
5
  "description": "Reldens - CMS",
6
6
  "author": "Damian A. Pastorini",
7
7
  "license": "MIT",
@@ -32,9 +32,9 @@
32
32
  "url": "https://github.com/damian-pastorini/reldens-cms/issues"
33
33
  },
34
34
  "dependencies": {
35
- "@reldens/server-utils": "^0.17.0",
36
- "@reldens/storage": "^0.45.0",
37
- "@reldens/utils": "^0.47.0",
35
+ "@reldens/server-utils": "^0.18.0",
36
+ "@reldens/storage": "^0.47.0",
37
+ "@reldens/utils": "^0.49.0",
38
38
  "dotenv": "^16.5.0",
39
39
  "mustache": "^4.2.0"
40
40
  }
@@ -1,30 +1,8 @@
1
- <!DOCTYPE html>
2
- <html>
3
- <head>
4
- <title>404 - Page Not Found</title>
5
- <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
6
- <link rel="stylesheet" href="/css/styles.css">
7
- <script src="/js/scripts.js"></script>
8
- </head>
9
- <body>
10
- <header>
11
- <div class="container">
12
- <h1>Reldens CMS</h1>
13
- <nav>
14
- <a href="/">Home</a>
15
- </nav>
1
+ <section class="hero d-flex align-items-center">
2
+ <div class="container text-center">
3
+ <h1>404</h1>
4
+ <h2>Page Not Found</h2>
5
+ <p>The page you are looking for doesn't exist.</p>
6
+ <a href="/" class="btn-get-started">Go Home</a>
16
7
  </div>
17
- </header>
18
- <div class="container">
19
- <main class="error-container">
20
- <h1>404 - Page Not Found</h1>
21
- <p>The page you are looking for might have been removed, had its name changed, or is temporarily unavailable.</p>
22
- <a href="/" class="button">Return to Homepage</a>
23
- </main>
24
- </div>
25
- <footer>
26
- <p>&copy; {{current_year}} - Built with Reldens CMS</p>
27
- </footer>
28
- </body>
29
- </html>
30
-
8
+ </section>
@@ -1,4 +1,7 @@
1
- /* Frontend styles */
1
+ /**
2
+ * Reldens - CMS - Styles
3
+ */
4
+
2
5
  body {
3
6
  font-family: 'Open Sans', sans-serif;
4
7
  line-height: 1.6;
File without changes
@@ -1,12 +1,14 @@
1
- // Frontend JavaScript
1
+ /**
2
+ * Reldens - CMS - Scripts
3
+ */
4
+
2
5
  document.addEventListener('DOMContentLoaded', function() {
3
- // Add active class to current navigation item
4
- const currentPath = window.location.pathname;
5
- const navLinks = document.querySelectorAll('nav a');
6
+ let currentPath = window.location.pathname;
6
7
 
7
- navLinks.forEach(link => {
8
- if (link.getAttribute('href') === currentPath) {
8
+ let navLinks = document.querySelectorAll('nav a');
9
+ for(let link of navLinks){
10
+ if(link.getAttribute('href') === currentPath){
9
11
  link.classList.add('active');
10
12
  }
11
- });
13
+ }
12
14
  });
@@ -0,0 +1,21 @@
1
+
2
+ {{>header}}
3
+
4
+ {{ entity('cmsBlocks', 'header-main') }}
5
+
6
+ <main id="main" class="main-container">
7
+ <div class="container">
8
+ <div class="row">
9
+ <div class="col-md-3">
10
+ {{ entity('cmsBlocks', 'sidebar-left') }}
11
+ </div>
12
+ <div class="col-md-9">
13
+ {{{content}}}
14
+ </div>
15
+ </div>
16
+ </div>
17
+ </main>
18
+
19
+ {{ entity('cmsBlocks', 'footer-main') }}
20
+
21
+ {{>footer}}
@@ -1,38 +1,20 @@
1
1
  <!DOCTYPE html>
2
- <html>
2
+ <html lang="{{locale}}">
3
3
  <head>
4
4
  <title>{{title}}</title>
5
- <meta name="description" content="{{meta_description}}">
6
- <meta property="og:title" content="{{og_title}}">
7
- <meta property="og:description" content="{{og_description}}">
8
- <meta property="og:image" content="{{og_image}}">
9
- <meta name="twitter:card" content="{{twitter_card_type}}">
10
- <meta name="robots" content="{{meta_robots}}">
11
- {{#canonical_url}}<link rel="canonical" href="{{canonical_url}}">{{/canonical_url}}
12
- <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
13
- <link rel="stylesheet" href="/css/styles.css">
14
- <script src="/js/scripts.js"></script>
5
+ <meta charset="utf-8">
6
+ <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=5.0, user-scalable=yes, viewport-fit=cover"/>
7
+ <meta name="theme-color" content="#000000"/>
8
+ <meta name="description" content="{{description}}"/>
9
+ <meta property="og:title" content="{{title}}"/>
10
+ <meta property="og:description" content="{{description}}"/>
11
+ <link href="/css/styles.css" rel="stylesheet"/>
15
12
  </head>
16
- <body>
17
- <header>
18
- <div class="container">
19
- <h1>Reldens CMS</h1>
20
- <nav>
21
- <a href="/">Home</a>
22
- {{#navigation}}
23
- <a href="{{url}}">{{label}}</a>
24
- {{/navigation}}
25
- </nav>
26
- </div>
27
- </header>
28
- <div class="container">
29
- <main>
30
- <h1>{{title}}</h1>
31
- {{{content}}}
32
- </main>
33
- </div>
34
- <footer>
35
- <p>&copy; {{current_year}} - Built with Reldens CMS</p>
36
- </footer>
13
+ <body class="{{siteHandle}}{{#elementClassName}} {{elementClassName}}{{/elementClassName}}"{{#backgroundImage}} style="background-image: url('{{backgroundImage}}');"{{/backgroundImage}}>
14
+ {{{content}}}
15
+ <script type="text/javascript" defer src="/js/scripts.js"></script>
16
+ <script type="text/javascript">
17
+ const currentYear = {{currentYear}};
18
+ </script>
37
19
  </body>
38
20
  </html>
@@ -0,0 +1,35 @@
1
+ <div class="footer-top">
2
+ <div class="container top-border">
3
+ <div class="row">
4
+ <div class="col-lg-4 col-md-6 footer-contact">
5
+ <h3>{{site_name}}</h3>
6
+ <p><strong>E-mail:</strong> <a href="mailto:{{contact_email}}">{{contact_email}}</a></p>
7
+ </div>
8
+ <div class="col-lg-4 col-md-6 footer-links">
9
+ {{#footer_menu}}
10
+ <h4>Useful Links</h4>
11
+ <ul>
12
+ {{#items}}
13
+ <li><a href="{{url}}">{{title}}</a></li>
14
+ {{/items}}
15
+ </ul>
16
+ {{/footer_menu}}
17
+ </div>
18
+ {{#social_links}}
19
+ <div class="col-lg-4 col-md-12 footer-links text-right">
20
+ <h4>Networks</h4>
21
+ <div class="social-links mt-3">
22
+ {{#links}}
23
+ <a href="{{url}}" target="_blank"><i class="bx {{icon}}"></i></a>
24
+ {{/links}}
25
+ </div>
26
+ </div>
27
+ {{/social_links}}
28
+ </div>
29
+ </div>
30
+ </div>
31
+ <div class="container footer-bottom clearfix">
32
+ <div class="copyright">
33
+ &copy; Copyright {{currentYear}} <strong><a href="https://www.dwdeveloper.com" target="_blank">DwDeveloper</a></strong>. All Rights Reserved
34
+ </div>
35
+ </div>
@@ -0,0 +1,36 @@
1
+ <div class="container d-flex align-items-center">
2
+ <div class="logo{{#is_reldens}} reldens-logo{{/is_reldens}}">
3
+ {{#logo_image}}
4
+ <a href="{{home_url}}">
5
+ <img src="{{logo_image}}" alt="{{site_name}}">
6
+ </a>
7
+ {{/logo_image}}
8
+ {{^logo_image}}
9
+ <a href="{{home_url}}">{{site_name}}</a>
10
+ {{/logo_image}}
11
+ </div>
12
+ {{#menu_items}}
13
+ <nav class="nav-menu d-none d-lg-block">
14
+ <ul>
15
+ {{#items}}
16
+ <li{{#has_children}} class="drop-down"{{/has_children}}>
17
+ <a href="{{url}}"{{#is_external}} target="_blank"{{/is_external}}>{{title}}</a>
18
+ {{#has_children}}
19
+ <ul>
20
+ {{#children}}
21
+ <li>
22
+ <a href="{{url}}"{{#is_external}} target="_blank"{{/is_external}}>{{title}}</a>
23
+ </li>
24
+ {{/children}}
25
+ </ul>
26
+ {{/has_children}}
27
+ </li>
28
+ {{/items}}
29
+ </ul>
30
+ </nav>
31
+ {{/menu_items}}
32
+ <form class="search" action="/search" method="get">
33
+ <input type="search" class="quicksearch" name="q" value="{{search_query}}" placeholder="Search..."/>
34
+ <button type="submit"><i class="bx bx-search"></i></button>
35
+ </form>
36
+ </div>