Sitemodels
Sitemodels generates a front-end pattern repository from your project's Sass code. It's helpful for organizing larger front-end systems, prototyping UI components, encouraging modular design, and providing a lasting resource for current and future team members.
Some Features:
- Custom comment tags to define UI models
- Custom templating language for cross-referencing models
- Resizable iframe laboratory for responsive testing
- Preview mode
- Sass, CSS, HTML, and Template modals
- Simple documentation system
Some Limitations:
- Only works with Sass at the moment
- Only runs in Node at the moment
- Sort of the first real thing I've written with node.js
License
This project is licensed under the MIT License.
Setup
Install
npm install --save sitemodels
Basic Use
These options are required.
var makemodels = require('sitemodels');
var options = {
sass: '../path/to/sass/files',
output: '../path/to/app/'
}
makemodels(options);
Note: sitemodels operates on non-partial sass files first to generate a global CSS file. If your project contains nothing but sass partials, it will throw an error.
Options
var options = {
sass: '../path/to/sass/files',
output: '../path/to/output',
// Displays in toolbar and documentation
name: 'Project Name',
// For linking to project assets from the sitemodel app
root: 'path/to/project/root',
// The order your model sections will appear in the index
structure: ['Elements', 'Modules', 'Sections', 'States'],
// Path to project notes markdown file
notes: 'tests/docs/testnotes.md',
// If your models require js files to function
js: '../path/to/js/files',
// If your js files have dependencies, declare them here
// Note: they will be called in each iframe if a model
// uses javascript files
js_dependencies: ['jquery-3.1.1.min.js'],
// How your CSS will output in the code modal
css_output_style: 'expanded',
// Path to sassdoc folder for sassdoc integration
sassdoc: '../path/to/sassdoc/folder'
}
Modeling
Structure
Models are written directly into your project's sass files through the use of special comment blocks. A model consists of two parts and a closing statement. The first part is the comment block that holds model information. A valid model comment begins with /***
and ends with ***/
.
The comment block has two sections divided by ===
: tags and templates.
Tags look like @tag: value
and are pretty straightforward. Templates are a mixture of HTML and a custom templating language written for Sitemodels.
After the comment block, you write the Sass for that model and close it off with /*** end-model ***/
.
Here is an example of the structure:
/***
@tags: go here
===
<div>
{{ templates [[go]]>> here <<}}
</div>
***/
.sass {
code: here;
}
/*** end-model ***/
Tags
Tags are used to name, organize, and describe a model's characteristics. Here is the full list:
Required Tags:
-
@name (string)
The unique machine name for the model that satisfies/[a-z0-9\_\-]+/
. -
@display (string)
The name that will display in output. Must be a valid string cabale of acting as a json key. -
@section (string)
Top level category. -
@group (string)
Sub level category.
Additional Tags:
-
@author (string)
Name of the model author. -
@js (comma-separated list)
Any scripts that a model needs to showcase functionality. Requirers you pass thejs
option to sitemodels since each listed item will be relative to that path. -
@note (string)
Any information about this model that would be important for you or your team to remember. -
@scaffold
Flags a model with no visible properties so users can still view its information and codebase from the Model Index while eliminating it from potential rendering. -
@include (comma-separated list)
The CSS of the listed models will be available for the present model. -
@global
The css of this model will be included in the global.css file and available to all other models -
@wip
Flags a model as a work-in-progress so no one on your team attempts implementation.
Example
/***
@name: unique-model-name
@display: Unique Model Name
@section: Components
@group: Layout
@author: J. Smith
@js: flashy.js, ui-interaction.js
@note: You should only use this model on pages that contain the .foo class on the body tag.
@scaffold
@include: 2-col-layout, dark-bg, vertical-spacing
@global
@wip
***/
Templating
Sitemodels ships with a simple custom templating language to use for cross referencing models. There are two basic concepts when composing models: Model Inputs and Model References.
Model Inputs
When you write a template for a model, you can define points in the template that can be overwritten or filled in when referenced. For instance, if you wanted an HTML element within your template to have more class names than the default, you would define the area like this:
<h1 class="default-class{+ classes +}">Main Heading Content</h1>
The syntax {+ [name] +}
is a String Input. It defines a region that can be filled in with new content when referenced. The example above just leaves room for additional classes, however. If you wanted to enter default content for the classes input, you would write:
{+ classes: default-but-subject-to-change+}
Note: Everything after the colon is whitespace sensitive!
Additionally, if you wanted to create a structural model for layout purposes but leave the content subject to change, you could define a Model Input. Model Inputs work exactly like String Inputs except they take default model references and can be filled in with other model references.
You can define model references like this:
<div class="content-left__wrap">
{{+ left +}}
</div>
<div class="content-right__wrap">
{{+ right +}}
</div>
The examples above don't have any default models, which is fine. You would probably want to add the @scaffold
flag if your model had no default content as it wouldn't display anything in output. If you want to add a default model reference, use the same syntax as the String Input: {{+ [name]: [reference] +}}
.
Model References
When you want to call a model into another model you're making a Model Reference. You can call the model alone with no input changes, or you can declare which Model Inputs you'd like to fill in or overwrite. You reference models by their given @name
.
Calling a model with all defaults:
<div class="reference-wrap">
{{ main-heading }}
{{ paragraph }}
</div>
Overwriting Model Inputs:
<div class="reference-wrap">
{{ main-heading
[[content]] This Is Different Heading Text
}}
{{ paragraph
[[content]] Normally you would see some strange Latin incantations. In this case, we've chosen to overwrite the default Latin and display something that makes a little more sense to native English speakers.
}}
</div>
Wait, there's more!
Here are a couple more things to keep in mind:
Link to Project Assets
If you want sitemodels output to link to an asset located in your project, surround your link with the root syntax {% ... %}
. This presupposes you passed the root
option in your initial function call. When sitemodels encounters this syntax it will create a symlink in output/links
that points to the absolute path of the referenced asset. The model's html page will then populate with the symlink so it works in the iframe.
<img src="{% from/root/to/img/fileA.svg %}" />
...
<img src="{% from/root/to/img/fileB.png %}" />
Converts to:
<img src="../links/asset0" />
...
<img src="../links/asset1" />
Add Context-Specific Markup
If a model needs some extra markup for context but you don't want that markup to appear when it is referenced, surround it in {# ... #}
. Anything inside those hash braces will display when the model is selected and in view. If the model is referenced, that content will be removed.
{#
<style>
body {
background: black;
}
</style>
#}
<div class="has-white-text">This won't show up against white backgrounds</div>
You can also use this feature to create models that will showcase more content when viewed individually and less content when called as a reference:
<!-- Model Template -->
{#This #}<a href="{+href:#+}"{+attrs+}>{+text:link+}</a>{# is against a plain background.#}
{#<div class="bg-pattern--dark">
{{ p
[[content]] This <a href="#">link</a> is against a patterned background.
}}
</div>#}
<!-- When Viewed: -->
This <a href="#">link</a> is against a plain background.
<div class="bg-pattern--dark">
<p>This <a href="#">link</a> is against a patterned background.
</div>
<!-- When Referenced: -->
<a href="#">link</a>
Whitespace Agnostic!
{{+ref:paragraph[[content]]Overwriting content in default ref.+}}
{{
col-1
[[ content ]]
{{ ref
[[ footer-text ]] Within a ref!
}}
}}
>>...<<
Force Whitespace Sensitivity with Note: This only works when overwriting Model Inputs
<!-- @name: paragraph -->
<p{+attrs+}>{+content:Default paragraph content+}</p>
<!-- When referenced -->
{{ paragraph
[[attrs]]>> class="foo" data-attr="sure-why-not"<<
}}
<!-- Output -->
<p class="foo" data-attr="sure-why-not">Default paragraph content</p>
Do Not Nest Input Definitions
<div class="bad-decision">
{{+ inputName: defaultRef
[[content]] {+ not: going to work +} <!-- outputs as a string -->
+}}
</div>
Output
How It Works
Sitemodels generates some json and injects it into the output page. The particular view is managed by these URL parameters:
-
models: the model(s) in view categorized by
section | group | display name
- preview: if a model is in preview mode (0 or 1)
- bundle: if a model's references are also displayed (0 or 1)
- docs: if sitemodels documentation is open (0 or 1)
- notes: if project notes are open (0 or 1)
Model Index
The Model Index is displayed as a collapsable list of models organized by section, group, and display name. If you passed the structure
option to sitemodels, the sections will appear in the order given. If not, they will appear in the order they were input based on file names and file content. Within sections, groups and models are sorted alphabetically.
Model Stage
If you select a model from the index (or a collection of models via the all
button) the state updates and refreshes the page with the appropriate parameters. One iframe per model will generate in the center stage area. Each iframe has resizable width (to test basic media queries) which can also be entered in by typing for more precision.
Model Info
When hovered over, the icon at the top-left of each model displays the model information (mostly the stuff you entered into tags). The model note will be first, followed by a list of data including file, author, js, and any model references called by that model. Those references will be links that refresh the page and bring the model into view.
Model Code
The code button in the info modal displays each model's Sass, CSS, HTML, and Template. This window also has a resizable width. If a model references any other models or includes the CSS from other models, the Sass and CSS code window will display a button to show/hide the stylistic dependencies.
Additionally, if you passed the sassdoc
option to sitemodels, any Sass variable, placeholder, function, or mixin you have notated with Sassdoc comments will turn into a link in the Sass code modal. When clicked, a new modal slides into view displaying the sassdoc information.
Model Preview
The preview button sets the model's iframe to the full width and height of the viewport to simulate production view.
Model Bundles
The bundle button sets the stage with the model in question along with each of the models it references below it.
Shortcuts
Since preview mode removes all interactive sitemodels UI, keyboard shortcuts are available to switch views.
-
alt + h
displays sitemodels documentation -
alt + n
displays project notes (if available) -
alt + m
displays the model index -
alt + c
displays a model's code (the top model if a collection is in view) -
alt + p
toggles preview mode
Documenting
If your project is large enough, you likely have a documentation system already. If not, you can use the built-in documentation system to house any notes about your project's front-end design system. It takes a single markdown file and generates a single-page view with nested navigation.
Splash Page
The documentation's splash page consists of all content from the <h1>
to the first <h2>
. If you passed the name
option to sitemodels, its value will be used as the heading of your navigation (otherwise it defaults to your <h1>
).
Navigation
Navigation is comprised of your document's <h2>
and <h3>
tags. Each <h2>
represents a single content area and each <h3>
is a subheading nested within that group.
IDs
Sitemodels uses marked.js to compile the markdown. All headings convert their content to ids, making all lowercase and replacing all /\W/
with -
. The navigation system joins section and subheading together with a +
. As a fringe example, the section "Templating" and subheading "Wait, there's more!" can be linked to as:
[Link](#templating+wait-there-s-more-)