sitemodels

Builds a front-end pattern library from Sass source code

Usage no npm install needed!

<script type="module">
  import sitemodels from 'https://cdn.skypack.dev/sitemodels';
</script>

README

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 the js 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-)