Skip to content

Commit

Permalink
Initial version and readme
Browse files Browse the repository at this point in the history
  • Loading branch information
franciscop committed Jun 23, 2018
1 parent ce88460 commit 8f4ac65
Show file tree
Hide file tree
Showing 10 changed files with 2,896 additions and 0 deletions.
43 changes: 43 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# Logs
logs
*.log
npm-debug.log*

# Runtime data
pids
*.pid
*.seed
.tmp

# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov

# Coverage directory used by tools like istanbul
coverage

# nyc test coverage
.nyc_output

# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
.grunt

# node-waf configuration
.lock-wscript

# Compiled binary addons (http://nodejs.org/api/addons.html)
build/Release

# Dependency directories
node_modules
.env
jspm_packages

# Optional npm cache directory
.npm

# Optional REPL history
.node_repl_history


# SASS
.sass-cache
13 changes: 13 additions & 0 deletions demo/_web.hbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>{{title}}</title>
<link rel="stylesheet" href="https://unpkg.com/picnic">
<link rel="stylesheet" href="/style.min.css">
</head>
<body>
<em>Rendered with Handlebars</em>
{{{body}}}{{{content}}}
</body>
</html>
13 changes: 13 additions & 0 deletions demo/_web.liquid
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>{{title}}</title>
<link rel="stylesheet" href="https://unpkg.com/picnic">
<link rel="stylesheet" href="/style.min.css">
</head>
<body>
<em>Rendered with Liquid!</em>
{{ body }}{{ content }}
</body>
</html>
126 changes: 126 additions & 0 deletions index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Hello world!</title>
<link rel="stylesheet" href="https://unpkg.com/picnic">
<link rel="stylesheet" href="/style.min.css">
</head>
<body>
<em>Rendered with Liquid!</em>
<h1 id="create-static-web">Create-Static-Web</h1>
<p>Another static site generator:</p>
<pre><code class="language-bash">$ npm install create-static-web -g
$ web</code></pre>
<table>
<thead>
<tr>
<th>Transformations</th>
<th>Features</th>
</tr>
</thead>
<tbody><tr>
<td><code>.liquid</code> <code>.hbs</code><code>.html</code></td>
<td>• Works out of the box</td>
</tr>
<tr>
<td><code>.md</code> + <code>layout:</code><code>.html</code></td>
<td>• Livereload</td>
</tr>
<tr>
<td><code>.scss</code> <code>.sass</code><code>.min.css</code></td>
<td>• Extensible with hooks [WIP]</td>
</tr>
<tr>
<td><code>.src.js</code><code>.min.js</code> [WIP]</td>
<td>• Basic compatibility with Jekyll</td>
</tr>
</tbody></table>
<h2 id="getting-started">Getting Started</h2>
<p>Create your <code>readme.md</code>:</p>
<pre><code class="language-md">---
layout: hello.hbs
---

Front-matter enabled website</code></pre>
<p>Also your <code>_hello.hbs</code> file:</p>
<pre><code class="language-js">&lt;p&gt;{{ content }}&lt;/p&gt;</code></pre>
<p>Voila! Your site should be ready to go:</p>
<pre><code class="language-html">&lt;p&gt;Front-matter enabled website&lt;/p&gt;</code></pre>
<h2 id="demo">Demo</h2>
<p>Clone this repo and run web:</p>
<pre><code class="language-bash">$ git clone
</code></pre>
<h2 id="automatic-compilation">Automatic compilation</h2>
<p>The command <code>web</code> will automatically compile some extensions (explained below). <strong>Except</strong> if they also start by an underscore. Then they will be considered partials and not be rendered by default.</p>
<h3 id="liquid-template">Liquid template</h3>
<p>These will be rendered (excluding <a href="#partials">Partials</a>) into a file with the same name and the extension <code>html</code>:</p>
<ul>
<li><code>./index.liquid</code><code>./index.html</code></li>
<li><code>./demo.liquid</code><code>./demo.html</code></li>
<li><code>./blog/index.liquid</code><code>./blog/index.html</code></li>
</ul>
<p>They will receive the data as specified in the <a href="#data-specification">Data Specification</a>:</p>
<pre><code class="language-html">// index.liquid
&lt;!DOCTYPE html&gt;
&lt;html&gt;
&lt;head&gt;
&lt;title&gt;{{title}}&lt;/title&gt;
...
&lt;/head&gt;
...
&lt;/html&gt;</code></pre>
<h3 id="sass-and-scss">SASS and SCSS</h3>
<p>The style files (excluding <a href="#partials">Partials</a>) will be compiled to a file with the same name in the same folder, with the extension <code>.min.css</code>:</p>
<ul>
<li><code>./style.scss</code><code>./style.min.css</code></li>
<li><code>./demo.scss</code><code>./demo.min.css</code></li>
<li><code>./blog/style.scss</code><code>./blog/style.min.css</code></li>
</ul>
<p>Then you have to include it in your template as normal:</p>
<pre><code class="language-hbs">// index.hbs
&lt;!DOCTYPE html&gt;
&lt;html&gt;
&lt;head&gt;
...
&lt;link rel=&quot;stylesheet&quot; href=&quot;/style.min.css&quot;&gt;
&lt;/head&gt;
...
&lt;/html&gt;</code></pre>
<p>Files ending with these extensions will be automatically compiled:</p>
<p><code>.liquid</code>, <code>.hbs</code>, <code>.sass</code>, <code>.scss</code></p>
<p>They are compiled to the same folder with the same filename. SASS and SCSS will add a <code>.min</code> to the extension to differentiate in case you have any <code>.css</code>.</p>
<h2 id="partials">Partials</h2>
<p>Partials are useful in two situation: as layouts and to be included in another files.</p>
<h2 id="data-specification">Data Specification</h2>
<blockquote>
<p>Work in Progress</p>
</blockquote>
<p>Any <code>.json</code> found in the filesystem will be parsed and its value will be set into a variable with the same name as the filename:</p>
<p>For example, for the filename <code>info.json</code>:</p>
<pre><code class="language-json">{ &quot;title&quot;: &quot;My Cool Website&quot; }</code></pre>
<p>You can access this variable within your templates as:</p>
<pre><code class="language-html">&lt;!DOCTYPE html&gt;
&lt;html&gt;
&lt;head&gt;
&lt;title&gt;{{info.title}}&lt;/title&gt;
...
&lt;/head&gt;
...
&lt;/html&gt;</code></pre>
<h3 id="front-matter">Front Matter</h3>
<p>There is a special variable called <code>content</code> (aliased as <code>body</code>) which represents the Markdown content as html into your template:</p>
<pre><code class="language-html">// index.liquid
&lt;!DOCTYPE html&gt;
&lt;html&gt;
&lt;head&gt;
&lt;title&gt;{{title}}&lt;/title&gt;
...
&lt;/head&gt;
&lt;body&gt;
{{ content }}
&lt;/body&gt;
&lt;/html&gt;</code></pre>

</body>
</html>
110 changes: 110 additions & 0 deletions index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
#! /usr/bin/env node

// Static website generator. Compiles three things:
// - Handlbars: compile all "name.hbs" into "name.html"
// - Markdown: compile all "name.md" into "index.html" using the layout template
// - SASS: compile all "name.scss" into "name.min.css"
// All of this while ignoring the partials (filenames startig by "_")
const { start } = require("live-server");

const ignoreFiles = require('ignore');
const marked = require('marked');
const hbs = require('handlebars');
const liquid = require('liquidjs')();
const sass = require('node-sass');
const watch = require('node-watch');
const fm = require('front-matter');
const { abs, dir, exists, join, name, read, stat, walk, write } = require('fs-array');

// Check whether a folder has a 'readme.md' file or not
const hasReadme = src => exists(join(src, 'readme.md'));

// Find all the relevant data for a blog post entry (a folder)
const parseData = (file, i, blog) => {
// const file = join(folder, 'readme.md');
const folder = file.replace(/readme\.md$/, '');
const { attributes: { layout, ...attr }, body } = fm(read(file));
if (!layout) return;
attr.layout = layout + ((/\.\w+$/.test(layout)) ? '' : '.liquid');
attr.layout = '_' + attr.layout.replace(/^_/, '');
return {
id: folder.split('/').slice(-2).shift(),
file,
folder,
...attr,
// Create the main handlebars template based on the selected layout
// template: hbs.compile(`{{> ${attr.layout}}}`),
body: marked(body)
};
};

// Folders to ignore
const svc = ignoreFiles().add('.git');
if (exists('.gitignore')) svc.add(read('.gitignore'));
const ignore = src => !svc.ignores(src);

// Extensions to handle to changes
const filter = /\.(js|sass|scss|md|hbs|liquid)$/;
const isPartial = src => name(src)[0] === '_';
const isFull = src => !isPartial(src);
const ext = (...end) => src => end.find(ext => src.slice(-ext.length) === ext);


const compile = (err, file) => {

// All of the valid filenames within the project
const walked = walk(__dirname).filter(ignore).filter(src => filter.test(src));

const templates = { hbs: {}, liquid: {}, pug: {} };

// Handlebars import all '_name.hbs' in the blog folder as partials
walked.filter(isPartial).filter(ext('hbs')).forEach(src => {
const file = name(src, '.hbs').slice(1);
templates.hbs[file] = read(src);
hbs.registerPartial(file, read(src));
});

walked.filter(isPartial).filter(ext('liquid')).forEach(src => {
templates.liquid[name(src, '.liquid').slice(1)] = src;
});

// Render any .hbs in the page in place for a .html file
walked.filter(isFull).filter(ext('hbs')).forEach(src => {
const output = src.replace(/\.hbs$/, '.html');
write(output, hbs.compile(read(src))({ blog }));
});

// Actual markdown parsing
// const blog = dir(folder).filter(hasReadme).map(parseData).filter(a => a);
const blog = walked.filter(ext('md')).map(parseData).filter(Boolean);
blog.forEach(data => {
const [layout, ext] = data.layout.slice(1).split('.');
if (!templates[ext][layout]) {
return console.log(`Couldn't find template "${layout}". Make sure you have a file named "${data.layout}"`);
}
if (ext === 'liquid') {
liquid.renderFile(templates.liquid[layout], data).then(html => {
write(join(data.folder, 'index.html'), html);
});
}
if (ext === 'hbs') {
const html = hbs.compile(`{{> ${layout}}}`)(data);
write(join(data.folder, 'index.html'), html);
}
});

// The SASS or SCSS is being modified, rebuild them all
if (!file || /\.s(a|c)ss$/.test(file)) {
// Only main scss that are not partials (ignore "_name.scss" )
walked.filter(isFull).filter(ext('scss')).forEach(style => {
const options = { file: style, outputStyle: 'compressed' };
const output = style.replace(/\.s(a|c)ss$/, '.min.css');
write(output, sass.renderSync(options).css.toString());
});
}
};

watch(__dirname, { recursive: true, filter }, compile);
compile();

start({ port: 3000, host: "localhost", open: true });
Loading

0 comments on commit 8f4ac65

Please sign in to comment.