Browse Source

Added editorconfig and option to set section layout.

pull/1/head
Roman Axelrod 4 years ago
parent
commit
210b600f21
  1. 23
      .editorconfig
  2. 4
      .gitignore
  3. 49
      README.md
  4. 4
      config/default.cjs
  5. 6
      config/development.cjs
  6. 10
      data/default.json
  7. 10
      data/two.json
  8. 4
      layouts/alignfull.hbs
  9. 2
      layouts/container.hbs
  10. 12
      layouts/partials/head.hbs
  11. 16
      layouts/partials/toolbar.hbs
  12. 16
      layouts/scripts/page--toolbar.js
  13. 22
      layouts/styles/page--main.css
  14. 10
      package-template.json
  15. 159
      server.js
  16. 2
      src/scripts/template.min.js.map
  17. 8
      src/scripts/template.mjs
  18. 110
      src/template.template.hbs

23
.editorconfig

@ -0,0 +1,23 @@
# This file is for unifying the coding style for different editors and IDEs
# editorconfig.org
# WordPress Coding Standards
# https://make.wordpress.org/core/handbook/coding-standards/
root = true
[*]
charset = utf-8
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
indent_style = space
indent_size = 2
[*.json]
indent_style = tab
indent_size = 4
[*.md]
trim_trailing_whitespace = false

4
.gitignore

@ -9,7 +9,3 @@ deploy.sh
deploy-*.sh deploy-*.sh
# Custom # Custom
assets/css/**/*.min.css*
assets/css-old/**/*.min.css*
components/**/*.min.css*
config.js

49
README.md

@ -2,16 +2,22 @@
Install required modules: Install required modules:
``` ```sh
npm install npm install
``` ```
Run development environment: Run development environment:
``` ```sh
npm start npm start
``` ```
## How it works
The project runs `gulp` and `browsersync` beyond the scenes.
Each change in template, styling or script files will reload the page. The idea is to have a comfortable development
environment.
# Block Structure # Block Structure
You will find all the block files in `/src` folder. You will find all the block files in `/src` folder.
@ -35,26 +41,31 @@ We have a “blocks system”, means you will have to follow strict rules and us
## Template Layout & Data ## Template Layout & Data
### Handlebars
In this project, [Handlebars](https://handlebarsjs.com/guide/ "What is Handlebars") used as a template engine.
All the template layout must be in a single `*.hbs` file that located in `/src` folder.
### Data ### Data
You will find multiple `*.json` files in `/data` folder after the first run of `npm start`. You will find multiple `*.json` files in `/data` folder after the first run of `npm start`.
These files are used as data sources in layout. By reviewing these files you can understand what parameters you have and These files are used as data sources in layout. By reviewing these files you can understand what parameters you have and
how the data is stored. Don't change or edit these files - use the data as it is. how the data is stored.
There are multiple data sources since the block can be reused in different situations with different data. We have to There are multiple data sources since the block can be reused in different situations with different data. We have to
make sure that the block is always rendered properly. make sure that the block is always rendered properly.
> Don't change or edit these files - use the data as it is!
### Handlebars
[Handlebars](https://handlebarsjs.com/guide/ "What is Handlebars") used as a template engine in the project.
All the template layout must be in a single `*.hbs` file that located in `/src` folder.
> Use the data that is available in `/data` folder.
> Avoid using any kind of "freestyle" input/content. Your template file must contain only HTML tags and Handlebars parameters.
### Static Media Files ### Static Media Files
Use the `/src/images` folder in case you need to upload images or video files to the template. These files will be Use the `/src/images` folder in case you need to upload images or video files to the template.
available by the next URL: http://localhost:3000/images/${filename} These files will be available by the next URL: http://localhost:3000/images/${filename}
### Class Naming Convention ### Class Naming Convention
@ -69,10 +80,10 @@ min-width: ...px).
### CSS Units ### CSS Units
Use `rem` units instead of pixels. `1rem = 16pixels`. Use `rem` units instead of pixels.
For example, `1rem = 16pixels` depends on project.
No need to use rem in situations of `1px` or `2px`. (usually used for borders width).
No need to use rem in situations of `1px`, `2px` or `3px`. (usually used for borders width).
It's important to mention that the block is "elastic". By using `rem` units we are able to scale the layout and keep the It's important to mention that the block is "elastic". By using `rem` units we are able to scale the layout and keep the
aspect ratio. aspect ratio.
@ -81,7 +92,7 @@ aspect ratio.
The development environment includes CSS rules of the original project. This is including fonts, CSS variables, The development environment includes CSS rules of the original project. This is including fonts, CSS variables,
container logic etc... container logic etc...
The CSS file is embedded in served HTML. The CSS file is already embedded in served HTML.
# JavaScript # JavaScript
@ -97,6 +108,11 @@ The lib is included in the project and ready for use. Test with `window.Swiper`
Use development toolbar to switch between data sources. Use development toolbar to switch between data sources.
## Hover/Focus States
Make sure all "clickable" elements have `&:hover` & `&:focus` states in CSS rules.
This might be related to links, buttons or any other interactive elements.
## Responsiveness ## Responsiveness
Make sure the layout is rendered correctly on all standard breakpoint size: Make sure the layout is rendered correctly on all standard breakpoint size:
@ -122,7 +138,6 @@ Compare the final result with provided screenshots.
You can use You can use
available [Browser Extensions](https://chrome.google.com/webstore/detail/perfectpixel-by-welldonec/dkaagdgjmgdmbnecmcefdhjekcoceebi?hl=en) available [Browser Extensions](https://chrome.google.com/webstore/detail/perfectpixel-by-welldonec/dkaagdgjmgdmbnecmcefdhjekcoceebi?hl=en)
or any other tool/approach that you're familiar with. or any other tool/approach that you're familiar with.
The idea is to have "pretty close" result to requested design. The idea is to have "pretty close" result to requested design.

4
config/default.cjs

@ -1,4 +1,4 @@
module.exports = { module.exports = {
cssUrl: "https://", cssUrl: "https://",
blockName: "template", blockName: "template",
} }

6
config/development.cjs

@ -1,5 +1,5 @@
module.exports = { module.exports = {
mode: "development", mode: "development",
cssUrl: "https://", cssUrl: "https://",
blockName: "template", blockName: "template",
} }

10
data/default.json

@ -1,6 +1,6 @@
{ {
"title": "As a Global Salesforce Partner,\n we deliver Service Cloud solutions\n and complex Field Service Management\n in diverse industries worldwide", "title": "As a Global Salesforce Partner,\n we deliver Service Cloud solutions\n and complex Field Service Management\n in diverse industries worldwide",
"phrases": "<p><b>Delivering top results to industry leaders:</b></p>", "phrases": "<p><b>Delivering top results to industry leaders:</b></p>",
"cta_text": "Our Success Stories", "cta_text": "Our Success Stories",
"url": "https://google.com" "url": "https://google.com"
} }

10
data/two.json

@ -1,6 +1,6 @@
{ {
"title": "Option Two", "title": "Option Two",
"phrases": "<p><b>Delivering top results to industry leaders:</b></p>", "phrases": "<p><b>Delivering top results to industry leaders:</b></p>",
"cta_text": "Our Success Stories", "cta_text": "Our Success Stories",
"url": "https://google.com" "url": "https://google.com"
} }

4
layouts/page-container.hbs → layouts/alignfull.hbs

@ -7,9 +7,7 @@
{{> (include_partial "layouts/partials/toolbar") }} {{> (include_partial "layouts/partials/toolbar") }}
<main> <main>
<div class="container"> {{> (include_block_template) }}
{{> (include_block_template) }}
</div>
</main> </main>
{{> (include_partial "layouts/partials/scripts") }} {{> (include_partial "layouts/partials/scripts") }}

2
layouts/page.hbs → layouts/container.hbs

@ -7,7 +7,9 @@
{{> (include_partial "layouts/partials/toolbar") }} {{> (include_partial "layouts/partials/toolbar") }}
<main> <main>
<div class="container">
{{> (include_block_template) }} {{> (include_block_template) }}
</div>
</main> </main>
{{> (include_partial "layouts/partials/scripts") }} {{> (include_partial "layouts/partials/scripts") }}

12
layouts/partials/head.hbs

@ -1,9 +1,9 @@
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="{{ config.cssUrl }}"> <link rel="stylesheet" href="{{ config.cssUrl }}">
<link rel="stylesheet" href="styles/page--main.css"> <link rel="stylesheet" href="styles/page--main.css">
<link rel="stylesheet" href="styles/{{ config.blockName }}.min.css"> <link rel="stylesheet" href="styles/{{ config.blockName }}.min.css">
<link rel="stylesheet" href="https://unpkg.com/swiper@8/swiper-bundle.min.css"/> <link rel="stylesheet" href="https://unpkg.com/swiper@8/swiper-bundle.min.css"/>
</head> </head>

16
layouts/partials/toolbar.hbs

@ -1,11 +1,11 @@
<header class="page_toolbar"> <header class="page_toolbar">
<div> <div>
<label for="data-options">Data Options: </label> <label for="data-options">Data Options: </label>
<select name="data" id="data-options"> <select name="data" id="data-options">
{{#each config.dataFiles }} {{#each config.dataFiles }}
<option value="{{ name }}" {{#if active }}selected="selected"{{/if}}>{{ name }}</option> <option value="{{ name }}" {{#if active }}selected="selected"{{/if}}>{{ name }}</option>
{{/each}} {{/each}}
</select> </select>
</div> </div>
</header> </header>

16
layouts/scripts/page--toolbar.js

@ -1,13 +1,13 @@
(function () { (function () {
const dataOptionsSelect = document.getElementById('data-options'); const dataOptionsSelect = document.getElementById('data-options');
if (!dataOptionsSelect) { if (!dataOptionsSelect) {
return; return;
} }
dataOptionsSelect.addEventListener('change', function () { dataOptionsSelect.addEventListener('change', function () {
console.log(this.value) console.log(this.value)
window.location = '?data=' + this.value; window.location = '?data=' + this.value;
}) })
})(); })();

22
layouts/styles/page--main.css

@ -1,20 +1,20 @@
body { body {
margin: 0; margin: 0;
font-size: 1rem; font-size: 1rem;
} }
header.page_toolbar { header.page_toolbar {
font-family: Arial, sans-serif; font-family: Arial, sans-serif;
background-color: #ccc; background-color: #ccc;
padding: 1rem; padding: 1rem;
display: flex; display: flex;
justify-content: center; justify-content: center;
align-items: center; align-items: center;
margin-bottom: 2rem; margin-bottom: 2rem;
} }
header.page_toolbar select { header.page_toolbar select {
font-size: 0.85rem; font-size: 0.85rem;
padding: 0.25rem; padding: 0.25rem;
} }

10
package-template.json

@ -0,0 +1,10 @@
{
"name": "template-block",
"version": "1.0.0",
"scripts": {
"start": "component-dev"
},
"devDependencies": {
"axe-web-component": "git+https://git.devdevdev.life/roman/axe-web-component.git#master"
}
}

159
server.js

@ -18,13 +18,16 @@ import fs from "fs/promises";
* Constants * Constants
*/ */
const isDev = config.get('mode') === 'development'; const isDev = config.has('mode') && config.get('mode') === 'development';
const modulePath = 'node_modules/axe-web-component/'; const modulePath = 'node_modules/axe-web-component/';
const projectDir = isDev ? '' : modulePath; const projectDir = isDev ? '' : modulePath;
console.log('Development Mode:', isDev); console.log('Development Mode:', isDev);
const sass = gulpSass(dartSass); const sass = gulpSass(dartSass);
buildStyleFiles()
buildScriptFiles()
/** /**
* Init server * Init server
*/ */
@ -32,7 +35,7 @@ const sass = gulpSass(dartSass);
const app = express(); const app = express();
const hbs = create({ const hbs = create({
extname: '.hbs', defaultLayout: false, partialsDir: ['.'], extname: '.hbs', defaultLayout: false, partialsDir: ['.'],
}); });
app.engine('.hbs', hbs.engine); app.engine('.hbs', hbs.engine);
@ -42,66 +45,68 @@ app.set('views', projectDir + 'layouts');
const dataFiles = prepareListOfDataFiles(await fs.readdir('./data')); const dataFiles = prepareListOfDataFiles(await fs.readdir('./data'));
app.get('/', async (req, res) => { app.get('/', async (req, res) => {
let jsonFileName = (req.query.data) ? req.query.data : 'default'; let jsonFileName = (req.query.data) ? req.query.data : 'default';
if (!jsonFileName || !await fsExtra.exists(`./data/${jsonFileName}.json`)) { if (!jsonFileName || !await fsExtra.exists(`./data/${jsonFileName}.json`)) {
jsonFileName = 'default'; jsonFileName = 'default';
}
const data = await fsExtra.readJson(`./data/${jsonFileName}.json`);
Object.assign(data, {
config: {
projectDir,
dataFiles: dataFiles.map((name) => {
return {
name,
active: jsonFileName === name,
};
}),
cssUrl: config.get('cssUrl'),
blockName: config.get('blockName')
} }
});
const data = await fsExtra.readJson(`./data/${jsonFileName}.json`); data.helpers = {
include_partial: (path) => projectDir + path,
Object.assign(data, { include_block_template: (path) => 'src/' + config.get('blockName') + '.template',
config: { }
projectDir,
dataFiles: dataFiles.map((name) => { const baseView = config.has('baseView') ? config.get('baseView') : 'container';
return {
name,
active: jsonFileName === name,
};
}),
cssUrl: config.get('cssUrl'),
blockName: config.get('blockName')
}
});
data.helpers = {
include_partial: (path) => projectDir + path,
include_block_template: (path) => 'src/' + config.get('blockName') + '.template',
}
res.render('page-container', data); res.render(baseView, data);
}); });
app.use(express.static('src')); app.use(express.static('src'));
app.use(express.static(projectDir + 'layouts')); app.use(express.static(projectDir + 'layouts'));
const listener = app.listen(0, () => { const listener = app.listen(0, () => {
const PORT = listener.address().port; const PORT = listener.address().port;
console.log(`The web server has started on port ${PORT}`); console.log(`The web server has started on port ${PORT}`);
const bs = browserSync.create(); const bs = browserSync.create();
gulp.watch(['src/**/*.js', 'src/**/*.mjs', '!src/**/*.min.js'], {delay: 400}, gulp.series([buildScriptFiles, function (cb) { gulp.watch(['src/**/*.js', 'src/**/*.mjs', '!src/**/*.min.js'], {delay: 400}, gulp.series([buildScriptFiles, function (cb) {
browserSyncReload(bs, 'js', 'Script Files Change'); browserSyncReload(bs, 'js', 'Script Files Change');
return cb(); return cb();
}])); }]));
gulp.watch('src/**/*.scss', {delay: 400}, gulp.series([buildStyleFiles, function (cb) { gulp.watch('src/**/*.scss', {delay: 400}, gulp.series([buildStyleFiles, function (cb) {
browserSyncReload(bs, 'css', 'Style Files Change'); browserSyncReload(bs, 'css', 'Style Files Change');
return cb(); return cb();
}])); }]));
// bs.watch("src/**/*.js", function (event, file) {}); // bs.watch("src/**/*.js", function (event, file) {});
// bs.watch("src/**/*.css", function (event, file) {}); // bs.watch("src/**/*.css", function (event, file) {});
bs.watch("src/**/*.hbs", function (event, file) { bs.watch("src/**/*.hbs", function (event, file) {
browserSyncReload(bs, '', 'Template File Change: ' + file) browserSyncReload(bs, '', 'Template File Change: ' + file)
}); });
bs.init({ bs.init({
proxy: `http://localhost:${PORT}`, proxy: `http://localhost:${PORT}`,
}); });
}); });
/** /**
@ -109,49 +114,49 @@ const listener = app.listen(0, () => {
*/ */
function browserSyncReload(bs, extension = '', message = '') { function browserSyncReload(bs, extension = '', message = '') {
if (isDev) { if (isDev) {
// console.log(event, file); // console.log(event, file);
console.log(message); console.log(message);
} }
if (extension) { if (extension) {
extension = "*." + extension; extension = "*." + extension;
} }
bs.reload(extension); bs.reload(extension);
} }
function buildScriptFiles() { function buildScriptFiles() {
return gulp.src(['src/**/*.js', 'src/**/*.mjs', '!src/**/*.min.js']) return gulp.src(['src/**/*.js', 'src/**/*.mjs', '!src/**/*.min.js'])
.pipe(sourcemaps.init({})) .pipe(sourcemaps.init({}))
.pipe(babel()) .pipe(babel())
.pipe(gulp.src('vendor/*.js')) .pipe(gulp.src('vendor/*.js'))
// .pipe(gulp.dest('src/')) // .pipe(gulp.dest('src/'))
.pipe(uglify()) .pipe(uglify())
.pipe(rename({extname: '.min.js'})) .pipe(rename({extname: '.min.js'}))
.pipe(sourcemaps.write('.')) .pipe(sourcemaps.write('.'))
.pipe(gulp.dest('src/')); .pipe(gulp.dest('src/'));
} }
function buildStyleFiles() { function buildStyleFiles() {
return gulp.src('src/**/*.scss') return gulp.src('src/**/*.scss')
.pipe(sourcemaps.init({})) .pipe(sourcemaps.init({}))
.pipe(sass.sync().on('error', sass.logError)) .pipe(sass.sync().on('error', sass.logError))
// .pipe(gulp.dest('src/')) // .pipe(gulp.dest('src/'))
.pipe(rename({extname: '.min.css'})) .pipe(rename({extname: '.min.css'}))
.pipe(sourcemaps.write('.')) .pipe(sourcemaps.write('.'))
.pipe(gulp.dest('src/')) .pipe(gulp.dest('src/'))
} }
function prepareListOfDataFiles(dataFiles) { function prepareListOfDataFiles(dataFiles) {
return dataFiles return dataFiles
.filter((fileName) => fileName.split('.').pop() === 'json') .filter((fileName) => fileName.split('.').pop() === 'json')
.map((fileName) => { .map((fileName) => {
const splitName = fileName.split('.'); const splitName = fileName.split('.');
splitName.pop(); splitName.pop();
return splitName.join(''); return splitName.join('');
}) })
.sort(); .sort();
} }
// TODO: // TODO:

2
src/scripts/template.min.js.map

@ -1 +1 @@
{"version":3,"sources":["scripts/template.mjs"],"names":["$","console","log","window","Swiper","jQuery"],"mappings":"CAAA,SAAWA,GAEPC,QAAQC,IAAI,UACZD,QAAQC,IAAI,WAAYF,GACxBC,QAAQC,IAAI,WAAYC,OAAOC,QAJnC,CAMGD,OAAOE","file":"template.min.js","sourcesContent":["(function ($) {\n\n console.log('Ready!');\n console.log('jQuery =', $);\n console.log('Swiper =', window.Swiper);\n\n})(window.jQuery);"]} {"version":3,"sources":["scripts/template.mjs"],"names":["$","console","log","window","Swiper","jQuery"],"mappings":"CAAA,SAAWA,GAETC,QAAQC,IAAI,UACZD,QAAQC,IAAI,WAAYF,GACxBC,QAAQC,IAAI,WAAYC,OAAOC,QAJjC,CAMGD,OAAOE","file":"template.min.js","sourcesContent":["(function ($) {\n\n console.log('Ready!');\n console.log('jQuery =', $);\n console.log('Swiper =', window.Swiper);\n\n})(window.jQuery);\n"]}

8
src/scripts/template.mjs

@ -1,7 +1,7 @@
(function ($) { (function ($) {
console.log('Ready!'); console.log('Ready!');
console.log('jQuery =', $); console.log('jQuery =', $);
console.log('Swiper =', window.Swiper); console.log('Swiper =', window.Swiper);
})(window.jQuery); })(window.jQuery);

110
src/template.template.hbs

@ -1,70 +1,70 @@
<section class="template"> <section class="template">
{{! {{!
Remove Everything Below: Remove Everything Below:
}} }}
<style> <style>
code { code {
background-color: #eee; background-color: #eee;
color: #333; color: #333;
padding: 1rem 1.5rem; padding: 1rem 1.5rem;
border: 2px solid #d8d8d8; border: 2px solid #d8d8d8;
display: inline-block; display: inline-block;
border-radius: 2px; border-radius: 2px;
font-size: 14px; font-size: 14px;
} }
</style> </style>
<header class="template__header"> <header class="template__header">
<h1 class="template__header-heading">Ready!</h1> <h1 class="template__header-heading">Ready!</h1>
</header> </header>
<div class="template__content"> <div class="template__content">
<p> <p>
Review the `/data` folder with JSON data files.<br> Review the `/data` folder with JSON data files.<br>
Don't change data JSON files - use the data as it is. Don't change data JSON files - use the data as it is.
</p> </p>
<p>Build the layout based on provided data structure.</p> <p>Build the layout based on provided data structure.</p>
<br><br> <br><br>
<hr> <hr>
<h2>Image Example</h2> <h2>Image Example</h2>
<div> <div>
<img src="images/demo.jpeg" alt=""> <img src="images/demo.jpeg" alt="">
<br> <br>
<code> <code>
&lt;img src=&quot;images/demo.jpeg&quot; alt=&quot;&quot;&gt; &lt;img src=&quot;images/demo.jpeg&quot; alt=&quot;&quot;&gt;
</code> </code>
</div> </div>
<br><br> <br><br>
<hr> <hr>
<h2>Available Buttons Styling</h2> <h2>Available Buttons Styling</h2>
<div> <div>
<a href="#" class="btn btn--primary">Primary</a> <a href="#" class="btn btn--primary">Primary</a>
<br> <br>
<code> <code>
&lt;a href=&quot;#&quot; class=&quot;btn btn--primary&quot;&gt;Primary&lt;/a&gt; &lt;a href=&quot;#&quot; class=&quot;btn btn--primary&quot;&gt;Primary&lt;/a&gt;
</code> </code>
</div> </div>
<br> <br>
<div> <div>
<a href="#" class="btn btn--secondary">Secondary</a> <a href="#" class="btn btn--secondary">Secondary</a>
<br> <br>
<code> <code>
&lt;a href=&quot;#&quot; class=&quot;btn btn--secondary&quot;&gt;Secondary&lt;/a&gt; &lt;a href=&quot;#&quot; class=&quot;btn btn--secondary&quot;&gt;Secondary&lt;/a&gt;
</code> </code>
</div>
</div> </div>
</div>
{{! {{!
Remove END Remove END
}} }}
</section> </section>

Loading…
Cancel
Save