Styles Ma Nizzle

At every company, style guides are the boss of the design. They take a bit of lovely hand crafted time but in the end it gives clients the perspective and power they need to crank up the content power. We love ❤️ our style guides here at Fastspot and as a result we went from maticulously crafting component templates to detailing settings and then running one command to rule all.

A Bulky Past

Before the hottness we had Grunt and HTML partials. They were clunky, hard to customize, and tough to saddle. We used these partials to create component pages for the 4 main types of components - feature , full-width , in-content , and sidebar :

< html > < body > @@include ... @@include('../partials/ameribev/components/in-content/event-promotion.html', { "month": "April", "days": "18-20", "title": "ABA Annual Fly-in", "location": "Washington, DC", "tel": "202-463-6732", "description": "Each year, the American Beverage Association hosts a legislative Fly-In, allowing for representatives from ABA member companies to travel to Washington, D.C., for top-level meetings with an impressive group of policymakers.", "link": "Learn More", "image": "2" }); @@include ... </ body > </ html >

A Bit of Salt

To add salt to our wounds, the colors and fonts were also added by hand (which can get fiesty when there could be over 20 colors and 8 fonts):

< ... > < div class = "cr_color_block_cell" > < div class = "cr_color_block slim bg_maroon color_white" > < div class = "cr_color_block_content" > #B23156 </ div > </ div > < div class = "cr_color_block slim bg_charcoal color_white" > < div class = "cr_color_block_content" > #4C4C4C </ div > </ div > </ div > < div class = "cr_heading" > Proxima Nova, Bold </ div > < div class = "cr_font proxima_bold" > The Five Boxing Wizards Jump Quickly </ div > < div class = "cr_heading" > Bembo Pro, Regular </ div > < div class = "cr_font bembo_regular" > The Five Boxing Wizards Jump Quickly </ div > < ... >

Bang, that's it

You heard me! That's the old school 19th Century Quagga style guide. Clients can see all their components in one hot spot and all their usual WYSIWYG components styled up. But we had to do so much work and in the end, the client still doesn't have an organized collection of their components, a solid grasp of their colors and type, or a surfable content strategy.

Blazin to the New 🔥

Jump into 2018 and at Fastspot we created a swanky new process. One born from the need to beef up our style guides to mega stallion level. Our design team whipped one firey bundle of styles:

Landing Page

A solid start to an awesome deliverable

Content Strategy Page

A lively place for UX to deliver their content strategy

Visual Styles Page

From colors to fonts through quotes to lists

Components Page

Placeholders used to hide proprietary component images

The Dev Trot

Pretty dope huh? Now this is where things get real spicy! At this point in time, we have a whole new group of cuddle bugs in our process midst - Trello, Twig, Gulp, & Node. These baddies will help us achieve what the designers had in mind with a trello based content strategy page, a package.json fed visual styles page, and a trello pumped components grid.

T-rello-MS

Trello will be our first target for the day and shoot, every site we build has a trello board herdin by the wayside. They detail everything from journey maps to analytics recommendations. The real Trello butter is that each dev component gets its own trello card:

Gulp & Node Hook

To pull from these whimsical Trello boards, we looked for a node module that can make an API request to Trello. After a gallop through the node plains, node-trello became our defacto Trello endpoint request machine:

{ "key" : "XXXmuohohohohhohoXXX" , "token" : "XXXshimmyshammywhammyXXX" }

var trelloKeyToken = require ( './trello.json' ), Trello = require ( 'node-trello' ), trello = new Trello(trelloKeyToken.key, trelloKeyToken.token), markdown = require ( 'markdown' ).markdown; gulp.task( 'trello' , function ( done ) { trello.get( '/1/boards/idBoardXwoheX/cards' , function ( err, data ) {}); });

Here's the down low:

trelloKeyToken stores our super secret trello key and token! Trello stores a reference to node-trello trello stores an instance of Trello with our secrets markdown stores a reference to our markdown parser

Then we have some gulpin goin on:

Gulp will run gulp.task('trello') Node then makes a call to the '/1/boards/idBoardXwoheX/cards' endpoint

Filtering Through the Request

When that task is run in its current form, a call to the largest endpoint on Trello is made. That means we ended up getting a huge json response:

[{ id : '5a0a0a36e17bfee30881fb75' , checkItemStates : null , closed : false , dateLastActivity : '2017-11-13T21:10:20.691Z' , desc : '' , descData : null , idBoard : '59918e10a8c7276a1754a904' , idList : '59918e10a8c7276a1754a909' , idMembersVoted : [], idShort : 54 , idAttachmentCover : '5a0a0a390d072be8e03cb0bb' , idLabels : [], manualCoverAttachment : false , name : 'Template: Case Study Detail' , pos : 393215 , shortLink : '83Sh9Scq' , badges : { votes : 0 , attachmentsByType : [ Object ], viewingMemberVoted : false , subscribed : false , fogbugz : '' , checkItems : 0 , checkItemsChecked : 0 , comments : 0 , attachments : 1 , description : false , due : null , dueComplete : false }, dueComplete : false , due : null , idChecklists : [], idMembers : [], labels : [], shortUrl : 'https://trello.com/c/83Sh9Scq' , subscribed : false , url : 'https://trello.com/c/83Sh9Scq/54-template-case-study-detail' , attachments : [ [ Object ] ] }]

Luckily, an endpoint request to Trello can accept a bunch of parameters to help us filter through the wild. For our needs, we just need a teeny set of requirements:

Cover

Cover URL

Cover Previews

Title

Labels

Description

Node Trello's second argument can make it happen. All we had to do was pass in an object of requirements we wanted from our request:

trello.get( '/1/boards/' + packageJSON.vars.idBoardTrello + '/cards' , { attachments : "cover" , attachment_fields : [ "url" , "previews" ], fields : [ "name" , "labels" , "desc" ] }, function ( err, data ) { if (err) { console .log(err); } else { console .log(data); } });

Awww yeaaa, now we're blazin! We still get a doozy but its so much better!:

[ { id : '59918e10a8c7276a1754a918' , name : 'Materials Review & Internal Hand-Off' , desc : 'Scope:



* X - Strategy

* X - Design

__________



Notes:

__________



Billing Instructions:



Bill against your department when attaching your Harvest time report.' , labels : [], attachments : [] }, { id : '59918e10a8c7276a1754a932' , name : 'Topic Row' , desc : '#Title



Hi there



## Please delete me' , labels : [ [ Object ], [ Object ], [ Object ] ], attachments : [ [ Object ] ] } ]

Through the Roses

Once we got all that data, we can manipulate it all we want. Muhohohoho! For the deep trigger fingers, the entire script is over in our boilerplate. For this post, I'll show ya the very psuedo basics of processing the data and then passing it to twig:

api call ... }, function ( err, data ) { if (err) { console .log(err); } else { for every card if it has an attachment find its labels for every label assign the labels to a closer object reference parse the markdown description into html push the card to the deck otherwise parse the markdown description into html push the card to content strategy A B sort the cards for every component type push a blank deck for every card if it matches the blank deck type push the card to that deck run gulp-twig with data: deck: deck, contentStrategy : contentStrategy output html to static /templates } });

Twiggy Bodacious

At this moment, we injected a pretty nicely structured object straight into twig. Gulp twig does its do on our two big templates, fs-components.twig and fs-content-strategy.twig :

{% extends "_guidebook.twig" %} page settings ... {% block content %} {% include '../partials/guidebook/trello-sections.twig' with { trelloCards: true } %} {% endblock %} {% block trelloDetails %} {% include '../partials/guidebook/trello-details.twig' with { trelloCards: true } %} {% endblock %}

Trello Sections

The first pass to block content included a partial called trello-sections.twig which is dedicated to displaying basic trello items:

{% if trelloCards %} {% for group in deck %} {{group.type}} {% for item in group.cards %} {{item.name}} {{item.attachments[0].previews[3].url}} {% endfor %} {% endfor %} {% else %} {% for item in contentStrategy %} {{item.name}} {{item.desc}} {% endfor %} {% endif %}

Trello Details

But we also have a trippin detail page with a unique trello-details.twig partial. That's the twig partial dedicated to displaying detailed trello items and generating trello item navigation:

{% for group in deck %} {% for item in group.cards %} navigation ... card ... {% endfor %} {% endfor %}

Navin Through dem Cards

This is where shiii gets heavy (and where trello-js.twig makes a helpful appearance). At the top of the detail page is a way to go back and move forward through the trello cards. Twig makes this way difficult by having the loop index start at 1 and arrays start at 0! Kinda makes me wanna eat an acorn or fry a leaf but forget that. Anyway, to utilize the previous and next items within our {% for item in group.cards %} loop, we have to do a bunch of muscle work:

{% if loop.index - 2 >= 0 %} {% set prev = group.cards[loop.index - 2] %} {% else %} {% set prevSize = deck[loop.parent.loop.index - 2].cards.length - 1 %} {% set prev = deck[loop.parent.loop.index - 2].cards[prevSize] %} {% endif %} {% if loop.index + 1 <= loop.length %} {% set next = group.cards[loop.index] %} {% else %} {% set next = deck[loop.parent.loop.index].cards[0] %} {% endif %}

Building Trello Navigation

With prev and next under our belt, trello-js.twig is all set to trigger a hashchange function to active the respective trello card detail:

< div id = "trello_ {{item.id}} " > {% if prev %} < a href = "#trello_ {{prev.id}} " > {{prev.name}} </ a > {% endif %} < a href = "#" > View All Components </ a > {% if next is not empty %} < a href = "#trello_ {{next.id}} " > {{next.name}} </ a > {% endif %} </ div >

Showing off that Card

There are a few other goodies that reside in trello-details.twig . Namely a cover shot, parsed markdown description and a way to see the component live:

< a class = "gb_trello_detail_live" href = "dev- {{item.type| lower }} .html# {{item.name| replace ({ " ": "-", "&": "and", "/": "-" })| lower }} " target = "_blank" > See Component Live </ a >

Classy right? We used the current group type to send a link to it's own type page with a prettified hash of the component name. But hey, that page with all the components doesn't exist yet!

Compiling Live Components

Heavy node comin through ~ To get live components onto the page, we originally planned to have a bunch of test content and a generic component include:

{% set theme = "banana" %} {% set label = "jazz" %} {% include "../component-type/component-name.twig" %}

That was all willy barilly until we found out that we have tons of variations of everything! A single set of test data could never accommodate for every permutation of a component.

Scoping Partials

We needed a scoped partial include without the heavy lifting. So we ended up putting a sample right inside a commented section within the component itself:

component markup ...

Parsing Every Partial

The real lifting then occurs with another gulp task called components; this time heavily focusing on reading each component file in order to match a regex expression equal to the beginning comment section:

gulp.task( 'components' , function ( done ) { Read the contents of the components folder For every component type folder Read the contents of that folder open a result variable by extending the base template store page data into the result variable determine the type of folder and open a respective block For every component file store the contents of the file store the string of contents.match( /({#)+[^]+(#})+/ ) if a string exists remove the comments store the string to the main result end type block write the result to a file in the templates folder done(); });

As a result of the components task, we get a few files with scoped sample partials for each component type:

src/ twig/ templates/ dev-feature.twig dev-full-width.twig dev-in-content.twig dev-sidebar.twig

All Linked Up

With then end of the components task we have all the Trello integration we need:

Cards are pulled from trello Sorted by type

A-B sorted Twig parses the sorted cards from the request Content Strategy cards are compiled onto fs-content-strategy.twig

Cards are compiled onto fs-components.twig Component partials are pulled and compiled into their component templates

Extras Bites

And for those yearning for some extra spicy bites:

Gulp uses our package.json object to find the correct Trello endpoint

Each color swap has a copy to clipboard button

Twig uses our package.json object to: Loop through colors within colors.twig Loop through fonts within types.twig



Success!

I hope you come out of this feeling great about next gen style guides. Especially spicy enough to kick up one of your own 😊