Skip to content

perfectsense/brightspot-base

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation


DO NOT USE THIS REPOSITORY. USE BRIGHTSPOT EXPRESS INSTEAD.


Brightspot Base


Stack


Naming

Based on BEM:

  • Block: "A logically and functionally independent page component, the equivalent of a component in Web Components. A block encapsulates behavior (JavaScript), templates, styles (CSS), and other implementation technologies. Blocks being independent allows for their re-use, as well as facilitating the project development and support process."
  • Element: "A constituent part of a block that can't be used outside of it."

Naming Rules

Java-like:

  • PascalCase block names, e.g. ListPromo.
  • Suffix block names with their parent names, e.g. ListPromo which extends Promo.
  • camelCase element names, e.g. title.
  • Prefix element names with their parent names (blocks and elements), separated by a dash, e.g. ListPromo-title, ListPromo-items-item.

Naming Example - Handlebars

<div class="ListPromo">
    <div class="ListPromo-title">{{title}}</div>
    <ul class="ListPromo-items">
        {{#each items}}
            <li class="ListPromo-items-item">{{this}}</li>
        {{/each}}
    </ul>
    <div class="ListPromo-cta">{{cta}}</div>
</div>

Names can be generated automatically via BEM helpers, which are explained later.


Naming Example - Less

.ListPromo {
    border: solid 1px black;
    padding: 1em;

    &-title {
        font-size: 2em;
    }

    &-items {
        list-style: none;
        padding: 0;

        &-item {
            margin-top: .5em;
        }
    }
}

Naming Example - Less Alternative

.ListPromo {
    border: solid 1px black;
    padding: 1em;
}

.ListPromo-title {
    font-size: 2em;
}

.ListPromo-items {
    list-style: none;
    padding: 0;
}

.ListPromo-items-item {
    margin-top: .5em;
}

Only use this style when using Base blocks, not when creating them.


Organization

  • Handlebars, Less, and JavaScript files all together in the same directory, e.g. ArticleMain files in main.
  • One block per file.
  • Flat as possible by minimizing the number of nested directories.
  • Logically group blocks, e.g. all promo blocks in promo.

Usage


Usage Example

To use ListPromo as is, specify it directly in the Styleguide example JSON:

{
    "_template": "ListPromo",
    "title": "foo",
    "items": [ "bar" ],
    "cta": "qux"
}

HTML output:

<div class="ListPromo">
    <div class="ListPromo-title">foo</div>
    <ul class="ListPromo-items">
        <li>bar</li>
    </ul>
    <div class="ListPromo-cta">qux</div>
</div>

Usage Example - Copy

To create a wide version of ListPromo named WideListPromo, use the {{#defineBlock}} helper and reference the path to the template you want to extend. Make sure to define your new defineBlockContainer and/or defineBlockBody in the extending template:

WideListPromo.hbs

{{#defineBlock "WideListPromo" extend="ListPromo.hbs"}}
    {{#defineBlockContainer}}
        {{#defineBlockBody}}
            <div class="{{blockName}}">
                {{element "title"}}
                {{element "items"}}
                {{element "cta"}}
            </div>
        {{/defineBlockBody}}
    {{/defineBlockContainer}}
{{/defineBlock}}

HTML output:

<div class="WideListPromo">
    <div class="WideListPromo-title">...</div>
    <ul class="WideListPromo-items">...</ul>
    <div class="WideListPromo-cta">...</div>
</div>

Usage Example - Reorder

To move the cta element in between the title element and the items element, use the {{element}} helper:

CtaFirstListPromo.hbs

{{#defineBlock "CtaFirstListPromo" extend="ListPromo.hbs"}}
    {{#defineBlockContainer}}
        {{#defineBlockBody}}
            <div class="{{blockName}}">
                {{element "title"}}
                {{element "cta"}}
                {{element "items"}}
            </div>
        {{/defineBlockBody}}
    {{/defineBlockContainer}}
{{/defineBlock}}

HTML output:

<div class="CtaFirstListPromo">
    <div class="CtaFirstListPromo-title">...</div>
    <div class="CtaFirstListPromo-cta">...</div>
    <ul class="CtaFirstListPromo-items">...</ul>
</div>

Usage Example - Add

To add the subTitle element below the title element:

SubTitledListPromo.hbs

{{#defineBlock "SubTitledListPromo" extend="ListPromo.hbs"}}
    {{#defineBlockContainer}}
        {{#defineBlockBody}}
            <div class="{{blockName}}">
                {{element "title"}}
                {{#with subTitle}}
                    <div class="{{blockName}}-subTitle">{{this}}</div>
                {{/with}}
                {{element "items"}}
                {{element "cta"}}
            </div>
        {{/defineBlockBody}}
    {{/defineBlockContainer}}
{{/defineBlock}}

HTML output:

<div class="SubTitledListPromo">
    <div class="SubTitledListPromo-title">...</div>
    <div class="SubTitledListPromo-subTitle">...</div>
    <ul class="SubTitledListPromo-items">...</ul>
    <div class="SubTitledListPromo-cta">...</div>
</div>

Usage Example - Style All

Change all promo titles to 3em:

All.less

@import 'base/promo/Promo';
@import 'promo/Promo';
@import 'base/promo/ImagePromo';
@import 'base/promo/ListPromo';

promo/Promo.less

.Promo-title {
    font-size: 3em;
}

Usage Example - Style One

Change just list promo titles to 3em:

All.less

@import 'base/promo/Promo';
@import 'base/promo/ImagePromo';
@import 'base/promo/ListPromo';
@import 'promo/ListPromo';

promo/ListPromo.less

.ListPromo-title {
    font-size: 3em;
}

Creating Base Blocks


Handlebars Example - Not Reusable

<div class="ListPromo">
    <div class="ListPromo-title">{{title}}</div>
    <ul class="ListPromo-items">
        {{#each items}}
            <li class="ListPromo-items-item">{{this}}</li>
        {{/each}}
    </ul>
    <div class="ListPromo-cta">{{cta}}</div>
</div>

Handlebars - Reusability

BEM helpers:

  • defineBlock: Defines a block.
  • blockName: Returns the current block name.
  • defineBlockContainer: Marks the template as the block container.
  • defineBlockBody: Marks the template as the block body.
  • defineElement: Defines an element within a block.
  • elementName: Returns the current element name.
  • element: Renders the named element.

Handlebars Example - Reusable

{{#defineBlock "ListPromo"}}
    {{#defineElement "title"}}
        <div class="{{elementName}}">{{this}}</div>
    {{/defineElement}}

    {{#defineElement "items"}}
        <ul class="{{elementName}}">
            {{#each this}}
                <li class="{{elementName}}-item">{{this}}</li>
            {{/each}}
        </ul>
    {{/defineElement}}

    {{#defineElement "cta"}}
        <div class="{{elementName}}">{{this}}</div>
    {{/defineElement}}

    {{#defineBlockContainer}}
        {{#defineBlockBody}}
            <div class="{{blockName}}">
                {{element "title"}}
                {{element "items"}}
                {{element "cta"}}
            </div>
        {{/defineBlockBody}}
    {{/defineBlockContainer}}
{{/defineBlock}}

Less Example - Parent

Promo.less

.Promo {
    &-title {
        &:extend(.Promo-title all);
        font-size: 2em;
    }

    &-cta {
        &:extend(.Promo-cta all);
        border: 5px solid black;
    }
}

Less Example - Simple Extend

ImagePromo.less

.ImagePromo {
    &:extend(.Promo all);
}

Less Example - Extend & Add

ListPromo.less

.ListPromo {
    &:extend(.Promo all);

    &-items {
        &:extend(.ListPromo-items all);
        list-style: none;
        padding: 0;

        &-item {
            &:extend(.ListPromo-items-item all);
            margin-top: .5em;
        }
    }
}

Bonus


Save yourself time and keystrokes when writing Base handlebars helpers in your favorite editor.