82
Theming the Modern Toolkit Phil Guerrant Senior Software Engineer, Sencha

SenchaCon 2016: Theming the Modern Toolkit - Phil Guerrant

  • Upload
    sencha

  • View
    108

  • Download
    0

Embed Size (px)

Citation preview

Page 1: SenchaCon 2016: Theming the Modern Toolkit - Phil Guerrant

Theming the Modern Toolkit

Phil GuerrantSenior Software Engineer, Sencha

Page 2: SenchaCon 2016: Theming the Modern Toolkit - Phil Guerrant

Getting Started

Page 3: SenchaCon 2016: Theming the Modern Toolkit - Phil Guerrant

Choosing Between App and Theme

• Both can contain styling

• Theme contains shared styling

• Application contains its own styling

Page 4: SenchaCon 2016: Theming the Modern Toolkit - Phil Guerrant

Generating an Application

sencha -sdk path/to/sdk generate app -modern ThemeDemo theme-demo

Page 5: SenchaCon 2016: Theming the Modern Toolkit - Phil Guerrant

Application Structure

Set theme variables in sass/var/all.scss

$base-color: green;

$panel-body-font-size: 15px;

Page 6: SenchaCon 2016: Theming the Modern Toolkit - Phil Guerrant

Theme Variableshttp://docs.sencha.com

Page 7: SenchaCon 2016: Theming the Modern Toolkit - Phil Guerrant

Application Structure

• Rule generating code goes in sass/src/• Mixin calls

• CSS rules

• scss files are auto-included based on class-path of classes in your application• Ext class - ThemeDemo.view.Main

• Includes sass/src/view/Main.scss

Page 8: SenchaCon 2016: Theming the Modern Toolkit - Phil Guerrant

Rapid Development Using Fashion

sencha app watch --fashion

[INF] Server started at port : 1841[INF] Application available at http://localhost:1841

Page 9: SenchaCon 2016: Theming the Modern Toolkit - Phil Guerrant

Generating a Theme PackageAllows styling to be shared between applications

# your application directory

cd theme-demo sencha generate package --type theme --extend theme-triton --name my-theme

Page 10: SenchaCon 2016: Theming the Modern Toolkit - Phil Guerrant

Generating a Theme Package

Page 11: SenchaCon 2016: Theming the Modern Toolkit - Phil Guerrant

Theme Package Structure

• scss files are auto-included based on class-path of framework classes

• e.g. Ext.field.Text

Page 12: SenchaCon 2016: Theming the Modern Toolkit - Phil Guerrant

Theme HierarchyClassic Toolkit Modern Toolkit

base

neutral

classic

gray

neptune

crisp

crisp-touch

neptune-touch

triton

base

neptune

triton

ios

material

Page 13: SenchaCon 2016: Theming the Modern Toolkit - Phil Guerrant

Variables

Page 14: SenchaCon 2016: Theming the Modern Toolkit - Phil Guerrant

VariablesAll theme variables must be dynamic

• dynamic() must be used for any newly declared variables.

• When overriding framework variables dynamic() is not required

• When in doubt it is safe to always use dynamic()

Page 15: SenchaCon 2016: Theming the Modern Toolkit - Phil Guerrant

Dynamic VariablesLast assignment wins, and is valid throughout entire scope

$base-color: dynamic(blue);

/* CSS Output */ .foo { background: red; }

$base-color: dynamic(red);

.foo { background: $base-color; }

Page 16: SenchaCon 2016: Theming the Modern Toolkit - Phil Guerrant

Component VariablesBegin with xtype, end with CSS property name

$button-font-size

$tab-background-color

$listitem-border-width

Page 17: SenchaCon 2016: Theming the Modern Toolkit - Phil Guerrant

Element VariablesElement name after xtype but before CSS property name

$button-badge-color

$textfield-input-padding

$listitem-disclosure-margin

Page 18: SenchaCon 2016: Theming the Modern Toolkit - Phil Guerrant

State VariablesState name after the thing it describes (xtype or element)

$button-pressed-color

$listitem-selected-border-color

$listitem-disclosure-pressed-background-color

Page 19: SenchaCon 2016: Theming the Modern Toolkit - Phil Guerrant

State Names

• pressed

• hovered

• selected

• focused

• disabled

Page 20: SenchaCon 2016: Theming the Modern Toolkit - Phil Guerrant

Style Inheritance

Page 21: SenchaCon 2016: Theming the Modern Toolkit - Phil Guerrant

Style Inheritance

Components should inherit styles defined by their superclasses

Page 22: SenchaCon 2016: Theming the Modern Toolkit - Phil Guerrant

Style Inheritance

classCls – the inheritable baseCls

Page 23: SenchaCon 2016: Theming the Modern Toolkit - Phil Guerrant

Ext.define('Child', { extend: 'Parent', classCls: 'x-child' });

Style InheritanceclassCls allows styles to cascade through the Component hierarchyExt.define('Parent', { extend: 'Ext.Component', classCls: 'x-parent' });

<div class="x-component x-parent x-child"></div>

Ext.create('Child');

Page 24: SenchaCon 2016: Theming the Modern Toolkit - Phil Guerrant

Ext.define('Child', { extend: 'Parent', classCls: 'x-child', classClsRoot: true });

Style Inheritance – Opting OutclassClsRoot defines inheritance boundaryExt.define('Parent', { extend: 'Ext.Component', classCls: 'x-parent' });

<div class="x-child"></div>

Ext.create('Child');

Page 25: SenchaCon 2016: Theming the Modern Toolkit - Phil Guerrant

Component UIs

Page 26: SenchaCon 2016: Theming the Modern Toolkit - Phil Guerrant

Component UIsOne component, multiple presentations

Page 27: SenchaCon 2016: Theming the Modern Toolkit - Phil Guerrant

Component UIsOne component, multiple presentationsExt.create({ xtype: 'button', ui: 'action' });

<div class="x-button x-button-action"></div>

Page 28: SenchaCon 2016: Theming the Modern Toolkit - Phil Guerrant

Ext.define('Child', { extend: 'Parent', classCls: 'x-child' });

UI InheritanceUI name is appended to each classCls in the hierarchyExt.define('Parent', { extend: 'Ext.Component', classCls: 'x-parent' });

<div class="x-component x-parent x-child x-component-foo x-parent-foo x-child-foo"></div>

Ext.create('Child', { ui: 'foo' });

Page 29: SenchaCon 2016: Theming the Modern Toolkit - Phil Guerrant

UIs are ComposableUse one or many, your choiceExt.create({ xtype: 'button', ui: 'action round' });

<div class="x-button x-button-action x-button-round"></div>

Page 30: SenchaCon 2016: Theming the Modern Toolkit - Phil Guerrant

UI MixinsThe structure of a UI mixin// theme-neptune/sass/var/Button.scss@mixin button-ui( $ui: null, $color: null, $border-color: null ) { $ui-suffix: ui-suffix($ui); // -#{$ui} OR empty string .x-button#{$ui-suffix} { // .x-button[-ui] color: $color; border-color: $border-color; } }

Page 31: SenchaCon 2016: Theming the Modern Toolkit - Phil Guerrant

UI MixinsThe magic of null

$color1: null; $color2: red;

/* CSS Output */ .button { border-color: red; }

.button { color: $color1; border-color: $color2; }

Page 32: SenchaCon 2016: Theming the Modern Toolkit - Phil Guerrant

UI MixinsThe magic of null

@include button-ui( $ui: foo );

/* CSS Output */

Empty!

Page 33: SenchaCon 2016: Theming the Modern Toolkit - Phil Guerrant

UI MixinsThe magic of null

@include button-ui( $ui: foo, $color: green );

/* CSS Output */ .x-button { color: green; }

Page 34: SenchaCon 2016: Theming the Modern Toolkit - Phil Guerrant

UIs MixinsThe default UI// theme-neptune/sass/var/Button.scss

$button-color: #606060; $button-border-color: #e4e4e4; . . .

// theme-neptune/sass/src/Button.scss @include button-ui( $color: $button-color, $border-color: $button-border-color . . . );

No $ui parameter($ui == null)

Page 35: SenchaCon 2016: Theming the Modern Toolkit - Phil Guerrant

UIs MixinsThe default UI/* CSS Output */ .x-button { . . . } .x-button.x-pressed { . . . } .x-button .x-icon-el { . . . }

Page 36: SenchaCon 2016: Theming the Modern Toolkit - Phil Guerrant

UIs MixinsAdditional UIs/* CSS Output */ .x-button-alert { . . . } .x-button-alert.x-pressed { . . . } .x-button-alert .x-icon-el { . . . }

Page 37: SenchaCon 2016: Theming the Modern Toolkit - Phil Guerrant

Theming Lists and Grids

Page 38: SenchaCon 2016: Theming the Modern Toolkit - Phil Guerrant

Can Grids have UIs?

Page 39: SenchaCon 2016: Theming the Modern Toolkit - Phil Guerrant

Column Header Check Column Header

GroupHeader

Row

CheckCell

ExpanderCell Paging

Toolbar

TextCell

Row NumbererCell

NumberCell

WidgetCell

DateCell

Page 40: SenchaCon 2016: Theming the Modern Toolkit - Phil Guerrant

Grids are ListsUse itemConfig to configure the UI of list items

Ext.create({ xtype: 'list', itemConfig: { ui: 'contact' } });

@include listitem-ui( $ui: contact, $color: #fff, $background-color: #444, $border-color: #777 );

Page 41: SenchaCon 2016: Theming the Modern Toolkit - Phil Guerrant

Before After

Page 42: SenchaCon 2016: Theming the Modern Toolkit - Phil Guerrant

Row

Page 43: SenchaCon 2016: Theming the Modern Toolkit - Phil Guerrant

Grids are ListsUse itemConfig to configure the UI of grid rows

Ext.create({ xtype: 'grid', itemConfig: { ui: 'contact' } });

@include gridrow-ui( $ui: contact, $background-color: #888 );

Page 44: SenchaCon 2016: Theming the Modern Toolkit - Phil Guerrant

GroupHeader

Page 45: SenchaCon 2016: Theming the Modern Toolkit - Phil Guerrant

Grids Group Row UIUse the “header” config of the grid row

Ext.create({ xtype: 'grid', itemConfig: { header: { ui: 'contact' } } });

@include rowheader-ui( $ui: contact, $background-color: #ccc );

Page 46: SenchaCon 2016: Theming the Modern Toolkit - Phil Guerrant

Column Header

Page 47: SenchaCon 2016: Theming the Modern Toolkit - Phil Guerrant

Grid Column Header UISet the UI on the column config

Ext.create({ xtype: 'grid', columns: [{ text: 'Name', ui: 'contact' }] });

@include gridcolumn-ui( $ui: contact, $color: white, $background-color: gray );

Page 48: SenchaCon 2016: Theming the Modern Toolkit - Phil Guerrant

TextCell

Page 49: SenchaCon 2016: Theming the Modern Toolkit - Phil Guerrant

Grid Cell UIUse the “cell” config of the column

Ext.create({ xtype: 'grid', columns: [{ text: 'Name', cell: { ui: 'contact' } }] });

@include gridcell-ui( $ui: contact, $font-weight: bold );

Page 50: SenchaCon 2016: Theming the Modern Toolkit - Phil Guerrant

PagingToolbar

Page 51: SenchaCon 2016: Theming the Modern Toolkit - Phil Guerrant

Grid Paging Toolbar UIUse the “toolbar” config of the Paging Toolbar plugin

Ext.create({ xtype: 'grid', plugins: [{ type: 'pagingtoolbar', toolbar: { ui: 'contact' } }] });

@include pagingtoolbar-ui( $ui: contact, $padding: 30px, $background-color: #ddd );

Page 52: SenchaCon 2016: Theming the Modern Toolkit - Phil Guerrant
Page 53: SenchaCon 2016: Theming the Modern Toolkit - Phil Guerrant
Page 54: SenchaCon 2016: Theming the Modern Toolkit - Phil Guerrant

Compound Components are the Sum of Their PartsThis pattern is repeated throughout the framework

Other Examples:

• Slider/Thumb

• TextField/Trigger

Exceptions:

Panel/Panel Header/Tools (on roadmap for improvement)

Page 55: SenchaCon 2016: Theming the Modern Toolkit - Phil Guerrant

Big Mode

Page 56: SenchaCon 2016: Theming the Modern Toolkit - Phil Guerrant

Big ModeLarger sizing and spacing for touch screens

• Classic toolkit used separate themes (neptune vs. neptune-touch)

• Modern toolkit – single theme

Page 57: SenchaCon 2016: Theming the Modern Toolkit - Phil Guerrant

Big ModeLarger sizing and spacing for touch screens

<html class="x-big">

Page 58: SenchaCon 2016: Theming the Modern Toolkit - Phil Guerrant

Big ModeChoosing between big and normal modes

// theme-neptune/overrides/init.js Ext.theme.getDocCls = function() { return Ext.platformTags.desktop ? '' : 'x-big'; };

Page 59: SenchaCon 2016: Theming the Modern Toolkit - Phil Guerrant

Big ModeOpting Out

$enable-big: false;

Page 60: SenchaCon 2016: Theming the Modern Toolkit - Phil Guerrant

Big ModeImplementing big mode rules // UI mixin code .x-button { padding: $padding; @if $enable-big { .x-big & { padding: $padding-big; } } }

/* CSS Output */ .x-button { padding: 5px; } .x-big .x-button { padding: 10px; }

Page 61: SenchaCon 2016: Theming the Modern Toolkit - Phil Guerrant

Breaking the Rules

Page 62: SenchaCon 2016: Theming the Modern Toolkit - Phil Guerrant

Before Breaking the RulesWhat do I do when the theming API does not meet my needs?

1. Let us know on the forums – https://sencha.com/forum

2. Add your own styling using the same techniques that the framework uses.

Page 63: SenchaCon 2016: Theming the Modern Toolkit - Phil Guerrant

classClsAlways matches the xtype and goes on the main elementExt.define('Ext.grid.column.Column', { xtype: 'gridcolumn', classCls: 'x-gridcolumn'});

<div class="x-gridcolumn x-gridcolumn-contact"></div>

// instance config { ui: 'contact' }

Page 64: SenchaCon 2016: Theming the Modern Toolkit - Phil Guerrant

State and Configuration CSS ClassesAlways on the main elementExt.define('Ext.grid.column.Column', { xtype: 'gridcolumn', classCls: 'x-gridcolumn', config: { align: 'left' } });

<div class="x-gridcolumn x-sorted x-align-left"></div>

Page 65: SenchaCon 2016: Theming the Modern Toolkit - Phil Guerrant

State and Configuration CSS ClassesAlways chain to the classCls

.x-align-left .x-title-el

.x-gridcolumn.x-sorted .x-sorted

.x-gridcolumn-contact.x-align-left

Page 66: SenchaCon 2016: Theming the Modern Toolkit - Phil Guerrant

Reference ElementsShould be named x-[name]-el

Ext.define('Ext.grid.column.Column', { template: [{ reference: 'titleElement', className: 'x-title-el' }] });

Page 67: SenchaCon 2016: Theming the Modern Toolkit - Phil Guerrant

Reference ElementsPrefer descendant selectors over child selectors

.x-gridcolumn .x-title-el { . . .}

.x-gridcolumn > .x-title-el { . . .}

Page 68: SenchaCon 2016: Theming the Modern Toolkit - Phil Guerrant

Reference ElementsPrefer descendant selectors over child selectors

• Except when container nesting is possible

• Include xtype/ui info in class name

.x-panel-inner-foo { . . . }

Page 69: SenchaCon 2016: Theming the Modern Toolkit - Phil Guerrant

When in DoubtCopy the selectors used by the framework

Page 70: SenchaCon 2016: Theming the Modern Toolkit - Phil Guerrant

Material and iOS

Page 71: SenchaCon 2016: Theming the Modern Toolkit - Phil Guerrant

iOS Material Material Dark

Page 72: SenchaCon 2016: Theming the Modern Toolkit - Phil Guerrant

iOS Theme

• Based on Triton

• Follows the latest iOS look and feel

• Will evolve with iOS

• Customizable – all framework theme variables and mixins are available

Page 73: SenchaCon 2016: Theming the Modern Toolkit - Phil Guerrant

Material Theme

• Based on Neptune

• Follows the material design guidelines https://material.google.com

• Material Color Palette

• Supports CSS Variables

Page 74: SenchaCon 2016: Theming the Modern Toolkit - Phil Guerrant

Material Color Palette

Page 75: SenchaCon 2016: Theming the Modern Toolkit - Phil Guerrant

Deep Purple #673AB7

Red #F44336

Material Color Palettehttps://material.google.com/style/color.html

Light Blue #03A9F4

Green #4CAF50

Yellow #FFEB3B

Deep Orange #FF5722

Blue Grey #607D8B

Pink #E91E63 Purple #9C27B0

Indigo #3F51B5 Blue #2196F3

Cyan #00BCD4 Teal #009688

Light Green #8BC34A Lime #CDDC39

Amber #FFC107 Orange #FF9800

Brown #795548 Grey #9E9E9E

Black #000000 White #FFFFFF

Page 76: SenchaCon 2016: Theming the Modern Toolkit - Phil Guerrant

$base-color-name: indigo;

$accent-color-name: yellow;

$dark-mode: true;

Configuring the Material Theme

• Configure base color, accent color, and dark mode

• All derived colors, spacing and sizing are handled automatically

• Can be further customized using theme variables and mixins but this is outside the scope of material design.

Page 77: SenchaCon 2016: Theming the Modern Toolkit - Phil Guerrant

Selecting Themes by PlatformStep 1: Setup multiple build profiles in app.json{ "builds": { "material": { "theme": "theme-material" }, "ios": { "theme": "theme-ios" }, "triton": { "theme": "theme-triton" } } }

Page 78: SenchaCon 2016: Theming the Modern Toolkit - Phil Guerrant

Selecting Themes by PlatformStep 2: Setup output directories in app.json (same as universal app){ "output": { "base": "${workspace.build.dir}/${build.environment}/${app.name}", "page": "index.html", "manifest": "${build.id}.json", "js": "${build.id}/app.js", "appCache": { "enable": false }, "resources": { "path": "${build.id}/resources", "shared": "resources" } } }

Page 79: SenchaCon 2016: Theming the Modern Toolkit - Phil Guerrant

Selecting Themes by PlatformStep 3: Use Ext.beforeLoad to select a profile<script type="text/javascript"> var Ext = Ext || {}; // Ext namespace won't be defined yet... Ext.beforeLoad = function (tags) { var profile; if (tags.ios) { profile = 'ios'; } else if (tags.android) { profile = 'material'; } else { profile = 'triton'; } Ext.manifest = profile; }; </script>

Page 80: SenchaCon 2016: Theming the Modern Toolkit - Phil Guerrant

Demo

Page 81: SenchaCon 2016: Theming the Modern Toolkit - Phil Guerrant

Please Take the Survey in the Mobile App

• Navigate to this session in the mobile app

• Click on “Evaluate Session”

• Respondents will be entered into a drawing to win one of five $50 Amazon gift cards

Page 82: SenchaCon 2016: Theming the Modern Toolkit - Phil Guerrant