Opinionated tools to build Design Systems
Christopher Bloom
Phase2 Technology
If you're working your way through these slides yourself, note a couple of things to help you along:
* Codin' subject to bandwidth and technology not explodin'
brew update
brew install php
php --version
nvm install v12
nvm alias default v12
node --version
sudo add-apt-repository ppa:ondrej/php
sudo apt-get update
sudo apt-get install php7.2-cli
<-- Use NVM
# 1. Skip steps if you already have the tools listed
# 2. Run source ~/.bashrc or source ~/.zshrc after each step to ensure command is registered
# Install Homebrew, if not installed
/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
# Update Homebrew installed packages
brew update && brew upgrade
# Install PHP 7.2, if not installed
brew install php
# Install NVM, if not installed
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.35.1/install.sh | bash
# Node 10 or 12. Leave off `nvm alias default v12` to prevent setting system wide node version
nvm install v12 && nvm alias default v12
# NPM 6+
npm install -g npm@latest
# Option 1: Get particle via starter script
npm create @phase2/particle particle && cd particle
# Option 2: Get particle via git clone
git clone git@github.com:phase2/particle.git && cd particle
# Install Particle dependencies. Run only once at the start of a project.
npm install && npm run setup
# Start Particle every time you want to work in Pattern Lab
npm start
You have to build a thing
There are designs
Those designs have to become code
That code will be consumed by some final system
Frontenders couldn't theme before content types and servers and databases and features and designs were done. This meant frontend was usually the frantic end of a project.
Frontenders work on design systems and tooling long before backend decisions, working in parallel to the rest of the build. Components are agnostic but "schema-driven".
... a collection of reusable components, guided by clear standards, that can be assembled together to build any number of applications."
Colors
Typography
Spacing
Grids
Image treatment
Iconography
Application of Style Guide to many small UI components
Assemble like Lego to build more complex screens
Iteratable, evolving
REAL CODE (HTML, Twig, React)
UI interactive behaviors
+
We will use the principles of Atomic Design to break up designs into coded Twig files:
Simply a tool to apply Atomic Design principles to Twig components.
Renders all components to HTML.
Provides a UI to navigate the components.
Using Pattern Lab Node! (via Twig PHP renderer)
A bunch of tools to build design systems
source/molecules/card/index.js
source/default/index.js
apps/pl
source/
node_modules/bootstrap
Most of a frontender's job is generating assets.
webpack.particle.js
source/default/webpack.config.js
apps/drupal/webpack.config.js
DEV
PROD
DEV
PROD
Overall, shared config
Design System-specific config
("Where are 'atoms'?")
App-specifc overrides
("Where is the bundle output?")
npm create @phase2/particle particle
cd particle
npm run setup
npm start
Build this card: html5up.net/phantom
Deconstruct using
Atomic Design principles
Download the zip and extract:
Move html5up-phantom/
to
source/default/tokens/sass/libraries/html5up-phantom/
Now edit:
source/default/tokens/sass/tokens.scss
////
/// Library printing
////
@use 'libraries/bootstrap';
// Add this
import './html5up-phantom/assets/css/main.css';
// ...
(Sass errors? Delete html5up-phantom/assets/sass/)
Our active Pattern Lab running at http://localhost:8080/app-node-pl/pl should look different!
Visit http://localhost:8080/app-node-pl/pl/?p=viewall-molecules-demo-card for a sense of the difference.
The new CSS is being compiled in!
Now, let's make new molecule called
phantom-card
The following file structure is created by running:
npm run new
Steal card markup from
source/default/tokens/sass/libraries/html5up-phantom/index.html
and paste it into
_phantom-card.twig
<article class="style1">
<span class="image">
<img
src="https://www.fillmurray.com/353/326"
alt="Bill"
/>
</span>
<a href="#">
<h2>Magna</h2>
<div class="content">
<p>Sed nisl arcu euismod sit amet nisi
lorem etiam dolor veroeros et feugiat.</p>
</div>
</a>
</article>
It's not pretty, but let's roll with it. Change img src and href to something generic for now.
Our card should show up in PL!
This looks gross because the CSS we inherited is ... not good.
<div class="tiles">
{% include '@molecules/phantom-card/_phantom-card.twig' %}
</div>
In
apps/node-pl/pattern-lab/_patterns/02-molecules-demo/phantom-card/phantom-cards.twig
surround the include with .tiles:
If we truly want to do this the RIGHT way, we'd
<article class="phantom-card phantom-card--style1">
<span class="phantom-card__image-wrapper">
<img
class="phantom-card__image"
src="https://www.fillmurray.com/353/326"
alt=""
/>
</span>
<a href="#" class="phantom-card__link">
<h2 class="phantom-card__title">Magna</h2>
<div class="phantom-card__content">
<p>Sed nisl arcu euismod sit amet nisi
lorem etiam dolor veroeros et feugiat.</p>
</div>
</a>
</article>
.phantom-card {
transition: transform 0.5s ease, opacity 0.5s ease;
position: relative;
width: calc(33.33333% - 2.5em);
margin: 2.5em 0 0 2.5em;
}
.phantom-card__image-wrapper {
transition: transform 0.5s ease;
position: relative;
display: block;
width: 100%;
border-radius: 4px;
overflow: hidden;
}
.phantom-card__image {
display: block;
width: 100%;
}
// ...
Let's make our Twig files dynamic!
Add variables to _phantom-card.twig
Update phantom-cards.yml to provide data automatically to twig.
Ta da!
Variables from .yml files are automatically provided to .twig files of the same base name.
<article class="phantom-card phantom-card--style1">
<span class="phantom-card__image-wrapper">
<img
class="phantom-card__image"
src="{{ phantom_card.image }}"
alt="{{ phantom_card.image_alt }}"
/>
</span>
<a href="{{ phantom_card.url }}" class="phantom-card__link">
<h2 class="phantom-card__title">{{ phantom_card.title }}</h2>
<div class="phantom-card__content">
<p>{{ phantom_card.content }}</p>
</div>
</a>
</article>
phantom_card:
image: https://www.fillmurray.com/353/326
image_alt: Picture of Bill Murray
url: '#'
title: This is Bill!
content: Lorem ipsum dolor sit amet.
1. In Drupal, install and enable Component Libraries module.
2. Enable Particle theme and set as default.
3. See:
apps/drupal/templates/content/node--article--teaser.html.twig
{% set article_card = {
card_border: 'none',
card_title: label,
card_text: content.body,
button: {
button_element: 'a',
button_color: 'secondary',
button_text: 'View details »'|t,
button_link: url,
}
} %}
{% include '@molecules/card/_card.twig' with article_card %}
particle.info.yml
(No templates or pages namespace due to empty folders blowing up the module)
name: Particle
type: theme
description: A Theme with Pattern Lab
base theme: stable
core: 8.x
libraries:
- particle/core
libraries-override:
core/jquery: particle/jquery
# ...
component-libraries:
protons:
paths: []
atoms:
paths:
- ../../dist/app-drupal/assets/atomic/_patterns/01-atoms
molecules:
paths:
- ../../dist/app-drupal/assets/atomic/_patterns/02-molecules
organisms:
paths:
- ../../dist/app-drupal/assets/atomic/_patterns/03-organisms
templates:
paths: []
pages:
paths: []
Node view modes
Views content and fields
Paragraphs
Field templates
Entities
Blocks
Menus
Custom theme hooks
MODEL: Drupal data provided to a hook
VIEW: The actual Particle twig component
PRESENTER: The intermediate Drupal "translator" between Drupal data and the Particle Twig component, ie: node--article--teaser.html.twig
# Define Particle theme's library CSS and JS assets along with dependencies
core:
css:
theme:
../../dist/app-drupal/assets/app.styles.css:
preprocess: true
js:
../../dist/app-drupal/assets/app.js:
preprocess: true
# see all in Drupal's `core/core.libraries.yml`
dependencies:
- particle/jquery
- core/drupal
- core/drupalSettings
# Create custom jQuery libraries
# that'll override the Drupal core jQuery libraries
# See `libraries-override` in particle.info.yml
jquery:
js:
../../dist/app-drupal/assets/drupal-jquery.js:
{ minified: true, weight: -20 }
particle.libraries.yml
# ...
libraries:
- particle/core
libraries-override:
core/jquery: particle/jquery
# ...
particle.info.yml
!!!!!!
Javascript unit testing with Jest
Accessibility testing with pa11y
Visual regression testing with Backstop (soon)
End-to-end testing with Cypress.io (soon)
We write A LOT of JavaScript on client projects.
NONE OF IT IS TESTED. Until now.
Write your JavaScript in such a way that it CAN be tested. Stop storing state in the DOM. Make your functions pure. Use libraries (like Redux) that move logic away from HTML.
Use pa11y automated accessibility testing against a running Pattern Lab prototype to catch most issues early.
Start up your local PL:
In another session, install then run pa11y:
See ./tools/tests/accessibility/pa11y.js:
ALL Pattern Lab urls are automatically tested!
npm start
npm install pa11y
npm run test:pa11y
"The best parts of React and Angular8 with no boilerplate."
Industry-leading virtual DOM and Reactivity Engine
Simple to learn, incredible resources
All tooling preconfigured in Particle, use .vue files immediately
Never build another widget in jQuery again
Starter examples and guide at @molecules/vue-widgets
Non-trivial Phase2 client app here.
Yugi Nali
Mike Potter
Kenny Black
Brigette Eckert
Daniel Lemay
Frederick Engelhardt