Automating UI development

Stefan Baumgartner
Stefan BaumgartnerWeb Architect at Dynatrace
Automating UI
Development
Angular Connect 2018
@ddprrt @Ka_TriN_F
Slide about usKatrin Freihofner

@Ka_TriN_F
devone.at
Slide about usStefan Baumgartner

@ddprrt
javascript-podcast.com
Automating UI development
Automating UI development
Automating UI development
expert groups
Highly specialised screens
… with lots of generic, flexible components
Automating UI development
Automating UI development
Automating UI development
Automating UI development
Automating UI development
Automating UI development
Automating UI development
Automating UI development
Automating UI development
Git
Design System update
Symbols library
Git
Design System update
Symbols library
Design System update
Design System update
Automating UI development
You might wonder
…how will this affect the product?
Automating UI development
Initial idea
UX + design
Initial idea
UX + design
Initial idea
Sketch lib
UX + design
Initial idea
Angular
component lib
Product
code
Sketch lib
UX + design
Initial idea
Angular
component lib
Product
code
Sketch lib
Barista
Design System
UX + design
Initial idea
Angular
component lib
Product
code
Sketch lib
Barista
Design System
UX + design
Initial idea
Angular
component lib
Product
code
Sketch lib
Barista
Design System
UX + design
Initial idea
Angular
component lib
Product
code
Sketch lib
Barista
Design System
UX + design
Initial idea
Angular
component lib
Product
code
Sketch lib
Barista
Design System
UX + design
Initial idea
Angular
component lib
Product
code
Sketch lib
Barista
Design System
UX + design
Initial idea
Angular
component lib
Product
code
Sketch lib
Barista
Design System
Automating UI development
Automating UI development
Automating UI development
Angular
component lib
Barista
Design System
Product
code
Angular
component lib
Barista
Design System
Product
code
? Angular
component lib
Barista
Design System
Product
code
UX + design
Sketch lib Angular
component lib
Transform Angular to Sketch
Angular library Sketch library
?
.sketch is bunch of JSON files
library.sketch
pages
D91775B4-2C6C-4FCC-9209-6D8C930B9013.json
document.json
meta.json
user.json
.sketch is bunch of JSON files
library.sketch
pages
D91775B4-2C6C-4FCC-9209-6D8C930B9013.json
document.json
meta.json
user.json
We can hack that!
CSS equivalents in .sketch JSON
button {
width: 122px;
height: 32px;
background-color: #00f;
}
ShapeGroup: {
frame: {x: 0, y: 0, width: 122, height: 32}
layers: [
ShapePath: {
points: [‘{0,0}’,‘{0,1}’,‘{1,1}’,‘{1,0}’]
}
],
style: {
fills: [
color: {
red: 0, green: 0, blue: 1, alpha: 1
}
]
}
}
CSS equivalents in .sketch JSON
button {
width: 122px;
height: 32px;
background-color: #00f;
}
ShapeGroup: {
frame: {x: 0, y: 0, width: 122, height: 32}
layers: [
ShapePath: {
points: [‘{0,0}’,‘{0,1}’,‘{1,1}’,‘{1,0}’]
}
],
style: {
fills: [
color: {
red: 0, green: 0, blue: 1, alpha: 1
}
]
}
}
{
"_class": "page",
"do_objectID": "6224EB85-9573-4D33-BEE5-C57F892B94E4",
"exportOptions": {
"_class": "exportOptions",
"exportFormats": [],
"includedLayerIds": [],
"layerOptions": 0,
"shouldTrim": false
},
"frame": {
"_class": "rect",
"constrainProportions": false,
"height": 300,
"width": 300,
"x": 0,
"y": 0
},
"isFlippedHorizontal": false,
CSS equivalents in .sketch JSON
button {
width: 122px;
height: 32px;
background-color: #00f;
}
CSS equivalents in .sketch JSON
button {
width: 122px;
height: 32px;
background-color: #00f;
}
parsable properties
export class StyleDeclaration {
borderTop = '0px none rgb(0, 0, 0)’; borderLeft = '0px none rgb(0, 0, 0)’;
borderBottom = '0px none rgb(0, 0, 0)'; borderRight = '0px none rgb(0, 0, 0)';
borderColor = 'rgb(0, 0, 0)'; borderTopLeftRadius = '0px';
borderTopRightRadius = '0px'; borderBottomRightRadius = '0px';
borderBottomLeftRadius = '0px'; borderWidth = '0px';
boxShadow = 'none'; padding = '0px';
backgroundImage = ‘none'; backgroundColor = 'rgba(0, 0, 0, 0)’; color = 'rgb(0, 0, 0)';
fill = 'rgb(0, 0, 0)’; strokeWidth = '1px';
fontFamily = 'Helvetica Neue'; fontSize = '16px'; fontStyle = 'normal'; fontWeight = '400';
letterSpacing = ‘normal'; whiteSpace = ‘normal'; lineHeight = 'normal';
textDecoration = 'none solid rgb(0, 0, 0)';
textAlign = 'start'; textTransform = 'none'; transform = 'none';
opacity = ‘1'; display = ‘block'; visibility = 'visible';
}
parsable properties
export class StyleDeclaration {
borderTop = '0px none rgb(0, 0, 0)’; borderLeft = '0px none rgb(0, 0, 0)’;
borderBottom = '0px none rgb(0, 0, 0)'; borderRight = '0px none rgb(0, 0, 0)';
borderColor = 'rgb(0, 0, 0)'; borderTopLeftRadius = '0px';
borderTopRightRadius = '0px'; borderBottomRightRadius = '0px';
borderBottomLeftRadius = '0px'; borderWidth = '0px';
boxShadow = 'none'; padding = '0px';
backgroundImage = ‘none'; backgroundColor = 'rgba(0, 0, 0, 0)’; color = 'rgb(0, 0, 0)';
fill = 'rgb(0, 0, 0)’; strokeWidth = '1px';
fontFamily = 'Helvetica Neue'; fontSize = '16px'; fontStyle = 'normal'; fontWeight = '400';
letterSpacing = ‘normal'; whiteSpace = ‘normal'; lineHeight = 'normal';
textDecoration = 'none solid rgb(0, 0, 0)';
textAlign = 'start'; textTransform = 'none'; transform = 'none';
opacity = ‘1'; display = ‘block'; visibility = 'visible';
}
parsable properties
export class StyleDeclaration {
borderTop = '0px none rgb(0, 0, 0)’; borderLeft = '0px none rgb(0, 0, 0)’;
borderBottom = '0px none rgb(0, 0, 0)'; borderRight = '0px none rgb(0, 0, 0)';
borderColor = 'rgb(0, 0, 0)'; borderTopLeftRadius = '0px';
borderTopRightRadius = '0px'; borderBottomRightRadius = '0px';
borderBottomLeftRadius = '0px'; borderWidth = '0px';
boxShadow = 'none'; padding = '0px';
backgroundImage = ‘none'; backgroundColor = 'rgba(0, 0, 0, 0)’; color = 'rgb(0, 0, 0)';
fill = 'rgb(0, 0, 0)’; strokeWidth = '1px';
fontFamily = 'Helvetica Neue'; fontSize = '16px'; fontStyle = 'normal'; fontWeight = '400';
letterSpacing = ‘normal'; whiteSpace = ‘normal'; lineHeight = 'normal';
textDecoration = 'none solid rgb(0, 0, 0)';
textAlign = 'start'; textTransform = 'none'; transform = 'none';
opacity = ‘1'; display = ‘block'; visibility = 'visible';
}
parsable properties
export class StyleDeclaration {
borderTop = '0px none rgb(0, 0, 0)’; borderLeft = '0px none rgb(0, 0, 0)’;
borderBottom = '0px none rgb(0, 0, 0)'; borderRight = '0px none rgb(0, 0, 0)';
borderColor = 'rgb(0, 0, 0)'; borderTopLeftRadius = '0px';
borderTopRightRadius = '0px'; borderBottomRightRadius = '0px';
borderBottomLeftRadius = '0px'; borderWidth = '0px';
boxShadow = 'none'; padding = '0px';
backgroundImage = ‘none'; backgroundColor = 'rgba(0, 0, 0, 0)’; color = 'rgb(0, 0, 0)';
fill = 'rgb(0, 0, 0)’; strokeWidth = '1px';
fontFamily = 'Helvetica Neue'; fontSize = '16px'; fontStyle = 'normal'; fontWeight = '400';
letterSpacing = ‘normal'; whiteSpace = ‘normal'; lineHeight = 'normal';
textDecoration = 'none solid rgb(0, 0, 0)';
textAlign = 'start'; textTransform = 'none'; transform = 'none';
opacity = ‘1'; display = ‘block'; visibility = 'visible';
}
parsable properties
export class StyleDeclaration {
borderTop = '0px none rgb(0, 0, 0)’; borderLeft = '0px none rgb(0, 0, 0)’;
borderBottom = '0px none rgb(0, 0, 0)'; borderRight = '0px none rgb(0, 0, 0)';
borderColor = 'rgb(0, 0, 0)'; borderTopLeftRadius = '0px';
borderTopRightRadius = '0px'; borderBottomRightRadius = '0px';
borderBottomLeftRadius = '0px'; borderWidth = '0px';
boxShadow = 'none'; padding = '0px';
backgroundImage = ‘none'; backgroundColor = 'rgba(0, 0, 0, 0)’; color = 'rgb(0, 0, 0)';
fill = 'rgb(0, 0, 0)’; strokeWidth = '1px';
fontFamily = 'Helvetica Neue'; fontSize = '16px'; fontStyle = 'normal'; fontWeight = '400';
letterSpacing = ‘normal'; whiteSpace = ‘normal'; lineHeight = 'normal';
textDecoration = 'none solid rgb(0, 0, 0)';
textAlign = 'start'; textTransform = 'none'; transform = 'none';
opacity = ‘1'; display = ‘block'; visibility = 'visible';
}
parsable properties
export class StyleDeclaration {
borderTop = '0px none rgb(0, 0, 0)’; borderLeft = '0px none rgb(0, 0, 0)’;
borderBottom = '0px none rgb(0, 0, 0)'; borderRight = '0px none rgb(0, 0, 0)';
borderColor = 'rgb(0, 0, 0)'; borderTopLeftRadius = '0px';
borderTopRightRadius = '0px'; borderBottomRightRadius = '0px';
borderBottomLeftRadius = '0px'; borderWidth = '0px';
boxShadow = 'none'; padding = '0px';
backgroundImage = ‘none'; backgroundColor = 'rgba(0, 0, 0, 0)’; color = 'rgb(0, 0, 0)';
fill = 'rgb(0, 0, 0)’; strokeWidth = '1px';
fontFamily = 'Helvetica Neue'; fontSize = '16px'; fontStyle = 'normal'; fontWeight = '400';
letterSpacing = ‘normal'; whiteSpace = ‘normal'; lineHeight = 'normal';
textDecoration = 'none solid rgb(0, 0, 0)';
textAlign = 'start'; textTransform = 'none'; transform = 'none';
opacity = ‘1'; display = ‘block'; visibility = 'visible';
}
parsable properties
export class StyleDeclaration {
borderTop = '0px none rgb(0, 0, 0)’; borderLeft = '0px none rgb(0, 0, 0)’;
borderBottom = '0px none rgb(0, 0, 0)'; borderRight = '0px none rgb(0, 0, 0)';
borderColor = 'rgb(0, 0, 0)'; borderTopLeftRadius = '0px';
borderTopRightRadius = '0px'; borderBottomRightRadius = '0px';
borderBottomLeftRadius = '0px'; borderWidth = '0px';
boxShadow = 'none'; padding = '0px';
backgroundImage = ‘none'; backgroundColor = 'rgba(0, 0, 0, 0)’; color = 'rgb(0, 0, 0)';
fill = 'rgb(0, 0, 0)’; strokeWidth = '1px';
fontFamily = 'Helvetica Neue'; fontSize = '16px'; fontStyle = 'normal'; fontWeight = '400';
letterSpacing = ‘normal'; whiteSpace = ‘normal'; lineHeight = 'normal';
textDecoration = 'none solid rgb(0, 0, 0)';
textAlign = 'start'; textTransform = 'none'; transform = 'none';
opacity = ‘1'; display = ‘block'; visibility = 'visible';
}
export class StyleDeclaration {
borderTop = '0px none rgb(0, 0, 0)’; borderLeft = '0px none rgb(0, 0, 0)’;
borderBottom = '0px none rgb(0, 0, 0)'; borderRight = '0px none rgb(0, 0, 0)';
borderColor = 'rgb(0, 0, 0)'; borderTopLeftRadius = '0px';
borderTopRightRadius = '0px'; borderBottomRightRadius = '0px';
borderBottomLeftRadius = '0px'; borderWidth = '0px';
boxShadow = 'none'; padding = '0px';
backgroundImage = ‘none'; backgroundColor = 'rgba(0, 0, 0, 0)’; color = 'rgb(0, 0, 0)';
fill = 'rgb(0, 0, 0)’; strokeWidth = '1px';
fontFamily = 'Helvetica Neue'; fontSize = '16px'; fontStyle = 'normal'; fontWeight = '400';
letterSpacing = ‘normal'; whiteSpace = ‘normal'; lineHeight = 'normal';
textDecoration = 'none solid rgb(0, 0, 0)';
textAlign = 'start'; textTransform = 'none'; transform = 'none';
opacity = ‘1'; display = ‘block'; visibility = 'visible';
}
“browser stylesheet”
CSS+HTML to Sketch
<button …>
+ CSSStyleDeclaration
<div …>
+ CSSStyleDeclaration
<h1>
+ CSSStyleDeclaration
…
…
"frame": {
"_class": "rect",
"constrainProportions":
false,
"height": 44,
"width": 764,
"x": 0,
"y": 0
},
…
.json
Transform Angular to Sketch
Angular library Sketch library
? CSSDecl jsonSketch Generator
Generate CSS Declaration files
CSS
scraper
Generate CSS Declaration files
CSS
scraper
Generate CSS Declaration files
CSS
scraper
<button …>
Generate CSS Declaration files
CSS
scraper
<button …>
➡ getComputedStyle()
Generate CSS Declaration files
CSS
scraper
<button …>
➡ getComputedStyle()
➡ getBoundingClientRect()
Generate CSS Declaration files
CSS
scraper
<button …>
➡ getComputedStyle()
➡ getBoundingClientRect()
<div …>
Generate CSS Declaration files
CSS
scraper
<button …>
➡ getComputedStyle()
➡ getBoundingClientRect()
<div …>
➡ getComputedStyle()
➡ getBoundingClientRect()
Generate CSS Declaration files
CSS
scraper
<button …>
➡ getComputedStyle()
➡ getBoundingClientRect()
<div …>
➡ getComputedStyle()
➡ getBoundingClientRect()
<h1>
➡ getComputedStyle()
➡ getBoundingClientRect()
…
Generate CSS Declaration files
CSS
scraper
<button …>
➡ getComputedStyle()
➡ getBoundingClientRect()
<div …>
➡ getComputedStyle()
➡ getBoundingClientRect()
<h1>
➡ getComputedStyle()
➡ getBoundingClientRect()
…
<button …>
+ CSSStyleDeclaration
<div …>
+ CSSStyleDeclaration
<h1>
+ CSSStyleDeclaration
…
Generate CSS Declaration files
CSS
scraper
<button …>
➡ getComputedStyle()
➡ getBoundingClientRect()
<div …>
➡ getComputedStyle()
➡ getBoundingClientRect()
<h1>
➡ getComputedStyle()
➡ getBoundingClientRect()
…
Generate CSS Declaration files
CSS
scraper
Generate CSS Declaration files
CSS
scraper
update!
Generate CSS Declaration files
CSS
scraper
update!
Generate CSS Declaration files
CSS
scraper
update!
Transform angular to sketch
Angular library Sketch library
? CSSDecl jsonSketch GeneratorApp CSS scraper
Parsing component code
Angular
component lib
TS
Parsing component code
Angular
component lib
Parses AST
A ‘pure’ example and component variants
TSAngular
component lib
Parses AST
A ‘pure’ example and component variants
TSAngular
component lib
examples
A ‘pure’ example and component variants
TSAngular
component lib
@Component({
moduleId: module.id,
template: `<button dt-button>Simple button</button>`,
})
export class ButtonPureExampleComponent { }
examples
A ‘pure’ example and component variants
TSAngular
component lib
@Component({
moduleId: module.id,
template: `<button dt-button>Simple button</button>`,
})
export class ButtonPureExampleComponent { }
examples
A ‘pure’ example and component variants
TSAngular
component lib
@Component({
moduleId: module.id,
template: `<button dt-button>Simple button</button>`,
})
export class ButtonPureExampleComponent { }
examples
variants
A ‘pure’ example and component variants
TSAngular
component lib
@Component({
moduleId: module.id,
template: `<button dt-button>Simple button</button>`,
})
export class ButtonPureExampleComponent { }
@Component({
selector: `button[dt-button], button[dt-icon-button]`,
templateUrl: 'button.html',
})
export class DtButton extends … {
@Input()
get variant(): ‘primary’ | ‘secondary’ { return this._variant; }
}
examples
variants
A ‘pure’ example and component variants
TSAngular
component lib
@Component({
moduleId: module.id,
template: `<button dt-button>Simple button</button>`,
})
export class ButtonPureExampleComponent { }
@Component({
selector: `button[dt-button], button[dt-icon-button]`,
templateUrl: 'button.html',
})
export class DtButton extends … {
@Input()
get variant(): ‘primary’ | ‘secondary’ { return this._variant; }
}
examples
variants
A ‘pure’ example and component variants
TSAngular
component lib
@Component({
moduleId: module.id,
template: `<button dt-button>Simple button</button>`,
})
export class ButtonPureExampleComponent { }
@Component({
selector: `button[dt-button], button[dt-icon-button]`,
templateUrl: 'button.html',
})
export class DtButton extends … {
@Input()
get variant(): ‘primary’ | ‘secondary’ { return this._variant; }
}
examples
variants
A ‘pure’ example and component variants
TSAngular
component lib
@Component({
moduleId: module.id,
template: `<button dt-button>Simple button</button>`,
})
export class ButtonPureExampleComponent { }
@Component({
selector: `button[dt-button], button[dt-icon-button]`,
templateUrl: 'button.html',
})
export class DtButton extends … {
@Input()
get variant(): ‘primary’ | ‘secondary’ { return this._variant; }
}
examples
variants
A ‘pure’ example and component variants
TSAngular
component lib
examples
variants
A ‘pure’ example and component variants
TSAngular
component lib
examples
+
variants
A ‘pure’ example and component variants
TSAngular
component lib
examples
+
variants
A ‘pure’ example and component variants
TSAngular
component lib
examples
+
variants
A ‘pure’ example and component variants
TSAngular
component lib
examples
+
variants
Transform Angular to Sketch
Angular library Sketch libraryCSSDecl json
Sketch GeneratorApp
CSS
scraper
Library
App
generator
Automating UI development
Automating UI development
UX + design
Initial idea
Angular
component lib
Product
code
Sketch lib
Barista
Design System
Angular
component lib
Barista
Design System
Sketch lib
Product
code
UX + design
Automating UI development
Automating UI development
$royalblue-700: #393db0;
dt-theme-palette($green-600,
$green-700, $green-800),
Automating UI development
Automating UI development
Automating UI development
Lukas Holzer

@luka5c0m
Katrin Freihofner

@Ka_TriN_F
Stefan Baumgartner

@ddprrt
Office hours

12:30 - 13:00
1 of 103

Recommended

Theme03 by
Theme03Theme03
Theme03Atleta De Taekwondo
474 views5 slides
Theme02 by
Theme02Theme02
Theme02Atleta De Taekwondo
496 views6 slides
City life project by ajay mishra121 by
City life project by ajay mishra121City life project by ajay mishra121
City life project by ajay mishra121Ajay_Mishra121
37 views17 slides
UI Design From Scratch - Part 4 - transcript.pdf by
UI Design From Scratch - Part 4 - transcript.pdfUI Design From Scratch - Part 4 - transcript.pdf
UI Design From Scratch - Part 4 - transcript.pdfShaiAlmog1
328 views9 slides
This is a test by
This is a testThis is a test
This is a testcmailhotos4
1.2K views34 slides
Sass, Compass by
Sass, CompassSass, Compass
Sass, CompassSerg Diniovskiy
1.6K views48 slides

More Related Content

Similar to Automating UI development

cssstyle.cssbody { font-family Montserrat, Arial, sa by
cssstyle.cssbody {    font-family Montserrat, Arial, sacssstyle.cssbody {    font-family Montserrat, Arial, sa
cssstyle.cssbody { font-family Montserrat, Arial, saMargenePurnell14
3 views433 slides
Theme01 by
Theme01Theme01
Theme01Atleta De Taekwondo
583 views6 slides
Week ThreeExpress Holidayscssstyle.csshtml{ height 100.docx by
Week ThreeExpress Holidayscssstyle.csshtml{ height 100.docxWeek ThreeExpress Holidayscssstyle.csshtml{ height 100.docx
Week ThreeExpress Holidayscssstyle.csshtml{ height 100.docxphilipnelson29183
3 views99 slides
Sassive Aggressive: Using Sass to Make Your Life Easier (NSWG Version) by
Sassive Aggressive: Using Sass to Make Your Life Easier (NSWG Version)Sassive Aggressive: Using Sass to Make Your Life Easier (NSWG Version)
Sassive Aggressive: Using Sass to Make Your Life Easier (NSWG Version)Adam Darowski
5.4K views80 slides
Simple Blue Blog Template XML 的副本 by
Simple Blue Blog Template XML 的副本Simple Blue Blog Template XML 的副本
Simple Blue Blog Template XML 的副本a5494535
588 views5 slides
Theme04 by
Theme04Theme04
Theme04Atleta De Taekwondo
450 views5 slides

Similar to Automating UI development(20)

cssstyle.cssbody { font-family Montserrat, Arial, sa by MargenePurnell14
cssstyle.cssbody {    font-family Montserrat, Arial, sacssstyle.cssbody {    font-family Montserrat, Arial, sa
cssstyle.cssbody { font-family Montserrat, Arial, sa
Week ThreeExpress Holidayscssstyle.csshtml{ height 100.docx by philipnelson29183
Week ThreeExpress Holidayscssstyle.csshtml{ height 100.docxWeek ThreeExpress Holidayscssstyle.csshtml{ height 100.docx
Week ThreeExpress Holidayscssstyle.csshtml{ height 100.docx
Sassive Aggressive: Using Sass to Make Your Life Easier (NSWG Version) by Adam Darowski
Sassive Aggressive: Using Sass to Make Your Life Easier (NSWG Version)Sassive Aggressive: Using Sass to Make Your Life Easier (NSWG Version)
Sassive Aggressive: Using Sass to Make Your Life Easier (NSWG Version)
Adam Darowski5.4K views
Simple Blue Blog Template XML 的副本 by a5494535
Simple Blue Blog Template XML 的副本Simple Blue Blog Template XML 的副本
Simple Blue Blog Template XML 的副本
a5494535588 views
Yeni metin belgesi (2) by makarnalar
Yeni metin belgesi (2)Yeni metin belgesi (2)
Yeni metin belgesi (2)
makarnalar953 views
JDRF: Improving Lives. Curing Type 1 Diabetes by stella6copeland43
JDRF: Improving Lives. Curing Type 1 DiabetesJDRF: Improving Lives. Curing Type 1 Diabetes
JDRF: Improving Lives. Curing Type 1 Diabetes
stella6copeland43235 views
LessCSS Presentation @ April 2015 GTALUG Meeting by Myles Braithwaite
LessCSS Presentation @ April 2015 GTALUG MeetingLessCSS Presentation @ April 2015 GTALUG Meeting
LessCSS Presentation @ April 2015 GTALUG Meeting
Myles Braithwaite383 views
Theme futura suicida não use como base e nem copie by Rafaela Souza
Theme futura suicida não use como base e nem copieTheme futura suicida não use como base e nem copie
Theme futura suicida não use como base e nem copie
Rafaela Souza314 views
Theme futura suicida não use como base e nem copie by Rafaela Souza
Theme futura suicida não use como base e nem copieTheme futura suicida não use como base e nem copie
Theme futura suicida não use como base e nem copie
Rafaela Souza185 views
Version1.0 StartHTML000000217 EndHTML000067516 StartFragment0000 by tidwellerin392
Version1.0 StartHTML000000217 EndHTML000067516 StartFragment0000Version1.0 StartHTML000000217 EndHTML000067516 StartFragment0000
Version1.0 StartHTML000000217 EndHTML000067516 StartFragment0000
tidwellerin3920 views
User Interface Design by Elie Khoury
User Interface DesignUser Interface Design
User Interface Design
Elie Khoury481 views
Corilennyg gmail-com-rsp2 by cori0506
Corilennyg gmail-com-rsp2Corilennyg gmail-com-rsp2
Corilennyg gmail-com-rsp2
cori0506568 views
Horario by 1wwefan
HorarioHorario
Horario
1wwefan44 views
hotel-3index.htmlNavbarHome (current)AboutContactAboutEnjoy You by meagantobias
hotel-3index.htmlNavbarHome (current)AboutContactAboutEnjoy Youhotel-3index.htmlNavbarHome (current)AboutContactAboutEnjoy You
hotel-3index.htmlNavbarHome (current)AboutContactAboutEnjoy You
meagantobias0 views
Demystifying CSS & WordPress by Justin Carmony
Demystifying CSS & WordPressDemystifying CSS & WordPress
Demystifying CSS & WordPress
Justin Carmony1.8K views

More from Stefan Baumgartner

WASM! WASI! WAGI! WAT? by
WASM! WASI! WAGI! WAT?WASM! WASI! WAGI! WAT?
WASM! WASI! WAGI! WAT?Stefan Baumgartner
530 views74 slides
Serverless Rust by
Serverless RustServerless Rust
Serverless RustStefan Baumgartner
389 views54 slides
What TypeScript taught me about JavaScript by
What TypeScript taught me about JavaScriptWhat TypeScript taught me about JavaScript
What TypeScript taught me about JavaScriptStefan Baumgartner
98 views28 slides
Real-world component libraries at scale by
Real-world component libraries at scaleReal-world component libraries at scale
Real-world component libraries at scaleStefan Baumgartner
690 views103 slides
Jamstack on Azure by
Jamstack on AzureJamstack on Azure
Jamstack on AzureStefan Baumgartner
1.1K views55 slides
TypeScript's Type System by
TypeScript's Type SystemTypeScript's Type System
TypeScript's Type SystemStefan Baumgartner
222 views53 slides

Recently uploaded

AIM102-S_Cognizant_CognizantCognitive by
AIM102-S_Cognizant_CognizantCognitiveAIM102-S_Cognizant_CognizantCognitive
AIM102-S_Cognizant_CognizantCognitivePhilipBasford
23 views36 slides
PCCC23:日本AMD株式会社 テーマ1「AMD Instinct™ アクセラレーターの概要」 by
PCCC23:日本AMD株式会社 テーマ1「AMD Instinct™ アクセラレーターの概要」PCCC23:日本AMD株式会社 テーマ1「AMD Instinct™ アクセラレーターの概要」
PCCC23:日本AMD株式会社 テーマ1「AMD Instinct™ アクセラレーターの概要」PC Cluster Consortium
29 views68 slides
Generative AI: Shifting the AI Landscape by
Generative AI: Shifting the AI LandscapeGenerative AI: Shifting the AI Landscape
Generative AI: Shifting the AI LandscapeDeakin University
78 views55 slides
MVP and prioritization.pdf by
MVP and prioritization.pdfMVP and prioritization.pdf
MVP and prioritization.pdfrahuldharwal141
40 views8 slides
Netmera Presentation.pdf by
Netmera Presentation.pdfNetmera Presentation.pdf
Netmera Presentation.pdfMustafa Kuğu
22 views50 slides
"Node.js vs workers — A comparison of two JavaScript runtimes", James M Snell by
"Node.js vs workers — A comparison of two JavaScript runtimes", James M Snell"Node.js vs workers — A comparison of two JavaScript runtimes", James M Snell
"Node.js vs workers — A comparison of two JavaScript runtimes", James M SnellFwdays
14 views30 slides

Recently uploaded(20)

AIM102-S_Cognizant_CognizantCognitive by PhilipBasford
AIM102-S_Cognizant_CognizantCognitiveAIM102-S_Cognizant_CognizantCognitive
AIM102-S_Cognizant_CognizantCognitive
PhilipBasford23 views
PCCC23:日本AMD株式会社 テーマ1「AMD Instinct™ アクセラレーターの概要」 by PC Cluster Consortium
PCCC23:日本AMD株式会社 テーマ1「AMD Instinct™ アクセラレーターの概要」PCCC23:日本AMD株式会社 テーマ1「AMD Instinct™ アクセラレーターの概要」
PCCC23:日本AMD株式会社 テーマ1「AMD Instinct™ アクセラレーターの概要」
"Node.js vs workers — A comparison of two JavaScript runtimes", James M Snell by Fwdays
"Node.js vs workers — A comparison of two JavaScript runtimes", James M Snell"Node.js vs workers — A comparison of two JavaScript runtimes", James M Snell
"Node.js vs workers — A comparison of two JavaScript runtimes", James M Snell
Fwdays14 views
Initiating and Advancing Your Strategic GIS Governance Strategy by Safe Software
Initiating and Advancing Your Strategic GIS Governance StrategyInitiating and Advancing Your Strategic GIS Governance Strategy
Initiating and Advancing Your Strategic GIS Governance Strategy
Safe Software198 views
What is Authentication Active Directory_.pptx by HeenaMehta35
What is Authentication Active Directory_.pptxWhat is Authentication Active Directory_.pptx
What is Authentication Active Directory_.pptx
HeenaMehta3515 views
GDSC GLAU Info Session.pptx by gauriverrma4
GDSC GLAU Info Session.pptxGDSC GLAU Info Session.pptx
GDSC GLAU Info Session.pptx
gauriverrma415 views
The Coming AI Tsunami.pptx by johnhandby
The Coming AI Tsunami.pptxThe Coming AI Tsunami.pptx
The Coming AI Tsunami.pptx
johnhandby14 views
"Surviving highload with Node.js", Andrii Shumada by Fwdays
"Surviving highload with Node.js", Andrii Shumada "Surviving highload with Node.js", Andrii Shumada
"Surviving highload with Node.js", Andrii Shumada
Fwdays59 views
Business Analyst Series 2023 - Week 4 Session 8 by DianaGray10
Business Analyst Series 2023 -  Week 4 Session 8Business Analyst Series 2023 -  Week 4 Session 8
Business Analyst Series 2023 - Week 4 Session 8
DianaGray10180 views
Transcript: Redefining the book supply chain: A glimpse into the future - Tec... by BookNet Canada
Transcript: Redefining the book supply chain: A glimpse into the future - Tec...Transcript: Redefining the book supply chain: A glimpse into the future - Tec...
Transcript: Redefining the book supply chain: A glimpse into the future - Tec...
BookNet Canada43 views
Deep Tech and the Amplified Organisation: Core Concepts by Holonomics
Deep Tech and the Amplified Organisation: Core ConceptsDeep Tech and the Amplified Organisation: Core Concepts
Deep Tech and the Amplified Organisation: Core Concepts
Holonomics17 views
Adopting Karpenter for Cost and Simplicity at Grafana Labs.pdf by MichaelOLeary82
Adopting Karpenter for Cost and Simplicity at Grafana Labs.pdfAdopting Karpenter for Cost and Simplicity at Grafana Labs.pdf
Adopting Karpenter for Cost and Simplicity at Grafana Labs.pdf
MichaelOLeary8213 views
Business Analyst Series 2023 - Week 4 Session 7 by DianaGray10
Business Analyst Series 2023 -  Week 4 Session 7Business Analyst Series 2023 -  Week 4 Session 7
Business Analyst Series 2023 - Week 4 Session 7
DianaGray10152 views
Innovation & Entrepreneurship strategies in Dairy Industry by PervaizDar1
Innovation & Entrepreneurship strategies in Dairy IndustryInnovation & Entrepreneurship strategies in Dairy Industry
Innovation & Entrepreneurship strategies in Dairy Industry
PervaizDar139 views
Redefining the book supply chain: A glimpse into the future - Tech Forum 2023 by BookNet Canada
Redefining the book supply chain: A glimpse into the future - Tech Forum 2023Redefining the book supply chain: A glimpse into the future - Tech Forum 2023
Redefining the book supply chain: A glimpse into the future - Tech Forum 2023
BookNet Canada46 views

Automating UI development

  • 2. Slide about usKatrin Freihofner
 @Ka_TriN_F devone.at
  • 3. Slide about usStefan Baumgartner
 @ddprrt javascript-podcast.com
  • 8. Highly specialised screens … with lots of generic, flexible components
  • 23. You might wonder …how will this affect the product?
  • 27. UX + design Initial idea Sketch lib
  • 28. UX + design Initial idea Angular component lib Product code Sketch lib
  • 29. UX + design Initial idea Angular component lib Product code Sketch lib Barista Design System
  • 30. UX + design Initial idea Angular component lib Product code Sketch lib Barista Design System
  • 31. UX + design Initial idea Angular component lib Product code Sketch lib Barista Design System
  • 32. UX + design Initial idea Angular component lib Product code Sketch lib Barista Design System
  • 33. UX + design Initial idea Angular component lib Product code Sketch lib Barista Design System
  • 34. UX + design Initial idea Angular component lib Product code Sketch lib Barista Design System
  • 35. UX + design Initial idea Angular component lib Product code Sketch lib Barista Design System
  • 42. Barista Design System Product code UX + design Sketch lib Angular component lib
  • 43. Transform Angular to Sketch Angular library Sketch library ?
  • 44. .sketch is bunch of JSON files library.sketch pages D91775B4-2C6C-4FCC-9209-6D8C930B9013.json document.json meta.json user.json
  • 45. .sketch is bunch of JSON files library.sketch pages D91775B4-2C6C-4FCC-9209-6D8C930B9013.json document.json meta.json user.json We can hack that!
  • 46. CSS equivalents in .sketch JSON button { width: 122px; height: 32px; background-color: #00f; } ShapeGroup: { frame: {x: 0, y: 0, width: 122, height: 32} layers: [ ShapePath: { points: [‘{0,0}’,‘{0,1}’,‘{1,1}’,‘{1,0}’] } ], style: { fills: [ color: { red: 0, green: 0, blue: 1, alpha: 1 } ] } }
  • 47. CSS equivalents in .sketch JSON button { width: 122px; height: 32px; background-color: #00f; } ShapeGroup: { frame: {x: 0, y: 0, width: 122, height: 32} layers: [ ShapePath: { points: [‘{0,0}’,‘{0,1}’,‘{1,1}’,‘{1,0}’] } ], style: { fills: [ color: { red: 0, green: 0, blue: 1, alpha: 1 } ] } }
  • 48. { "_class": "page", "do_objectID": "6224EB85-9573-4D33-BEE5-C57F892B94E4", "exportOptions": { "_class": "exportOptions", "exportFormats": [], "includedLayerIds": [], "layerOptions": 0, "shouldTrim": false }, "frame": { "_class": "rect", "constrainProportions": false, "height": 300, "width": 300, "x": 0, "y": 0 }, "isFlippedHorizontal": false, CSS equivalents in .sketch JSON button { width: 122px; height: 32px; background-color: #00f; }
  • 49. CSS equivalents in .sketch JSON button { width: 122px; height: 32px; background-color: #00f; }
  • 50. parsable properties export class StyleDeclaration { borderTop = '0px none rgb(0, 0, 0)’; borderLeft = '0px none rgb(0, 0, 0)’; borderBottom = '0px none rgb(0, 0, 0)'; borderRight = '0px none rgb(0, 0, 0)'; borderColor = 'rgb(0, 0, 0)'; borderTopLeftRadius = '0px'; borderTopRightRadius = '0px'; borderBottomRightRadius = '0px'; borderBottomLeftRadius = '0px'; borderWidth = '0px'; boxShadow = 'none'; padding = '0px'; backgroundImage = ‘none'; backgroundColor = 'rgba(0, 0, 0, 0)’; color = 'rgb(0, 0, 0)'; fill = 'rgb(0, 0, 0)’; strokeWidth = '1px'; fontFamily = 'Helvetica Neue'; fontSize = '16px'; fontStyle = 'normal'; fontWeight = '400'; letterSpacing = ‘normal'; whiteSpace = ‘normal'; lineHeight = 'normal'; textDecoration = 'none solid rgb(0, 0, 0)'; textAlign = 'start'; textTransform = 'none'; transform = 'none'; opacity = ‘1'; display = ‘block'; visibility = 'visible'; }
  • 51. parsable properties export class StyleDeclaration { borderTop = '0px none rgb(0, 0, 0)’; borderLeft = '0px none rgb(0, 0, 0)’; borderBottom = '0px none rgb(0, 0, 0)'; borderRight = '0px none rgb(0, 0, 0)'; borderColor = 'rgb(0, 0, 0)'; borderTopLeftRadius = '0px'; borderTopRightRadius = '0px'; borderBottomRightRadius = '0px'; borderBottomLeftRadius = '0px'; borderWidth = '0px'; boxShadow = 'none'; padding = '0px'; backgroundImage = ‘none'; backgroundColor = 'rgba(0, 0, 0, 0)’; color = 'rgb(0, 0, 0)'; fill = 'rgb(0, 0, 0)’; strokeWidth = '1px'; fontFamily = 'Helvetica Neue'; fontSize = '16px'; fontStyle = 'normal'; fontWeight = '400'; letterSpacing = ‘normal'; whiteSpace = ‘normal'; lineHeight = 'normal'; textDecoration = 'none solid rgb(0, 0, 0)'; textAlign = 'start'; textTransform = 'none'; transform = 'none'; opacity = ‘1'; display = ‘block'; visibility = 'visible'; }
  • 52. parsable properties export class StyleDeclaration { borderTop = '0px none rgb(0, 0, 0)’; borderLeft = '0px none rgb(0, 0, 0)’; borderBottom = '0px none rgb(0, 0, 0)'; borderRight = '0px none rgb(0, 0, 0)'; borderColor = 'rgb(0, 0, 0)'; borderTopLeftRadius = '0px'; borderTopRightRadius = '0px'; borderBottomRightRadius = '0px'; borderBottomLeftRadius = '0px'; borderWidth = '0px'; boxShadow = 'none'; padding = '0px'; backgroundImage = ‘none'; backgroundColor = 'rgba(0, 0, 0, 0)’; color = 'rgb(0, 0, 0)'; fill = 'rgb(0, 0, 0)’; strokeWidth = '1px'; fontFamily = 'Helvetica Neue'; fontSize = '16px'; fontStyle = 'normal'; fontWeight = '400'; letterSpacing = ‘normal'; whiteSpace = ‘normal'; lineHeight = 'normal'; textDecoration = 'none solid rgb(0, 0, 0)'; textAlign = 'start'; textTransform = 'none'; transform = 'none'; opacity = ‘1'; display = ‘block'; visibility = 'visible'; }
  • 53. parsable properties export class StyleDeclaration { borderTop = '0px none rgb(0, 0, 0)’; borderLeft = '0px none rgb(0, 0, 0)’; borderBottom = '0px none rgb(0, 0, 0)'; borderRight = '0px none rgb(0, 0, 0)'; borderColor = 'rgb(0, 0, 0)'; borderTopLeftRadius = '0px'; borderTopRightRadius = '0px'; borderBottomRightRadius = '0px'; borderBottomLeftRadius = '0px'; borderWidth = '0px'; boxShadow = 'none'; padding = '0px'; backgroundImage = ‘none'; backgroundColor = 'rgba(0, 0, 0, 0)’; color = 'rgb(0, 0, 0)'; fill = 'rgb(0, 0, 0)’; strokeWidth = '1px'; fontFamily = 'Helvetica Neue'; fontSize = '16px'; fontStyle = 'normal'; fontWeight = '400'; letterSpacing = ‘normal'; whiteSpace = ‘normal'; lineHeight = 'normal'; textDecoration = 'none solid rgb(0, 0, 0)'; textAlign = 'start'; textTransform = 'none'; transform = 'none'; opacity = ‘1'; display = ‘block'; visibility = 'visible'; }
  • 54. parsable properties export class StyleDeclaration { borderTop = '0px none rgb(0, 0, 0)’; borderLeft = '0px none rgb(0, 0, 0)’; borderBottom = '0px none rgb(0, 0, 0)'; borderRight = '0px none rgb(0, 0, 0)'; borderColor = 'rgb(0, 0, 0)'; borderTopLeftRadius = '0px'; borderTopRightRadius = '0px'; borderBottomRightRadius = '0px'; borderBottomLeftRadius = '0px'; borderWidth = '0px'; boxShadow = 'none'; padding = '0px'; backgroundImage = ‘none'; backgroundColor = 'rgba(0, 0, 0, 0)’; color = 'rgb(0, 0, 0)'; fill = 'rgb(0, 0, 0)’; strokeWidth = '1px'; fontFamily = 'Helvetica Neue'; fontSize = '16px'; fontStyle = 'normal'; fontWeight = '400'; letterSpacing = ‘normal'; whiteSpace = ‘normal'; lineHeight = 'normal'; textDecoration = 'none solid rgb(0, 0, 0)'; textAlign = 'start'; textTransform = 'none'; transform = 'none'; opacity = ‘1'; display = ‘block'; visibility = 'visible'; }
  • 55. parsable properties export class StyleDeclaration { borderTop = '0px none rgb(0, 0, 0)’; borderLeft = '0px none rgb(0, 0, 0)’; borderBottom = '0px none rgb(0, 0, 0)'; borderRight = '0px none rgb(0, 0, 0)'; borderColor = 'rgb(0, 0, 0)'; borderTopLeftRadius = '0px'; borderTopRightRadius = '0px'; borderBottomRightRadius = '0px'; borderBottomLeftRadius = '0px'; borderWidth = '0px'; boxShadow = 'none'; padding = '0px'; backgroundImage = ‘none'; backgroundColor = 'rgba(0, 0, 0, 0)’; color = 'rgb(0, 0, 0)'; fill = 'rgb(0, 0, 0)’; strokeWidth = '1px'; fontFamily = 'Helvetica Neue'; fontSize = '16px'; fontStyle = 'normal'; fontWeight = '400'; letterSpacing = ‘normal'; whiteSpace = ‘normal'; lineHeight = 'normal'; textDecoration = 'none solid rgb(0, 0, 0)'; textAlign = 'start'; textTransform = 'none'; transform = 'none'; opacity = ‘1'; display = ‘block'; visibility = 'visible'; }
  • 56. parsable properties export class StyleDeclaration { borderTop = '0px none rgb(0, 0, 0)’; borderLeft = '0px none rgb(0, 0, 0)’; borderBottom = '0px none rgb(0, 0, 0)'; borderRight = '0px none rgb(0, 0, 0)'; borderColor = 'rgb(0, 0, 0)'; borderTopLeftRadius = '0px'; borderTopRightRadius = '0px'; borderBottomRightRadius = '0px'; borderBottomLeftRadius = '0px'; borderWidth = '0px'; boxShadow = 'none'; padding = '0px'; backgroundImage = ‘none'; backgroundColor = 'rgba(0, 0, 0, 0)’; color = 'rgb(0, 0, 0)'; fill = 'rgb(0, 0, 0)’; strokeWidth = '1px'; fontFamily = 'Helvetica Neue'; fontSize = '16px'; fontStyle = 'normal'; fontWeight = '400'; letterSpacing = ‘normal'; whiteSpace = ‘normal'; lineHeight = 'normal'; textDecoration = 'none solid rgb(0, 0, 0)'; textAlign = 'start'; textTransform = 'none'; transform = 'none'; opacity = ‘1'; display = ‘block'; visibility = 'visible'; }
  • 57. export class StyleDeclaration { borderTop = '0px none rgb(0, 0, 0)’; borderLeft = '0px none rgb(0, 0, 0)’; borderBottom = '0px none rgb(0, 0, 0)'; borderRight = '0px none rgb(0, 0, 0)'; borderColor = 'rgb(0, 0, 0)'; borderTopLeftRadius = '0px'; borderTopRightRadius = '0px'; borderBottomRightRadius = '0px'; borderBottomLeftRadius = '0px'; borderWidth = '0px'; boxShadow = 'none'; padding = '0px'; backgroundImage = ‘none'; backgroundColor = 'rgba(0, 0, 0, 0)’; color = 'rgb(0, 0, 0)'; fill = 'rgb(0, 0, 0)’; strokeWidth = '1px'; fontFamily = 'Helvetica Neue'; fontSize = '16px'; fontStyle = 'normal'; fontWeight = '400'; letterSpacing = ‘normal'; whiteSpace = ‘normal'; lineHeight = 'normal'; textDecoration = 'none solid rgb(0, 0, 0)'; textAlign = 'start'; textTransform = 'none'; transform = 'none'; opacity = ‘1'; display = ‘block'; visibility = 'visible'; } “browser stylesheet”
  • 58. CSS+HTML to Sketch <button …> + CSSStyleDeclaration <div …> + CSSStyleDeclaration <h1> + CSSStyleDeclaration … … "frame": { "_class": "rect", "constrainProportions": false, "height": 44, "width": 764, "x": 0, "y": 0 }, … .json
  • 59. Transform Angular to Sketch Angular library Sketch library ? CSSDecl jsonSketch Generator
  • 60. Generate CSS Declaration files CSS scraper
  • 61. Generate CSS Declaration files CSS scraper
  • 62. Generate CSS Declaration files CSS scraper <button …>
  • 63. Generate CSS Declaration files CSS scraper <button …> ➡ getComputedStyle()
  • 64. Generate CSS Declaration files CSS scraper <button …> ➡ getComputedStyle() ➡ getBoundingClientRect()
  • 65. Generate CSS Declaration files CSS scraper <button …> ➡ getComputedStyle() ➡ getBoundingClientRect() <div …>
  • 66. Generate CSS Declaration files CSS scraper <button …> ➡ getComputedStyle() ➡ getBoundingClientRect() <div …> ➡ getComputedStyle() ➡ getBoundingClientRect()
  • 67. Generate CSS Declaration files CSS scraper <button …> ➡ getComputedStyle() ➡ getBoundingClientRect() <div …> ➡ getComputedStyle() ➡ getBoundingClientRect() <h1> ➡ getComputedStyle() ➡ getBoundingClientRect() …
  • 68. Generate CSS Declaration files CSS scraper <button …> ➡ getComputedStyle() ➡ getBoundingClientRect() <div …> ➡ getComputedStyle() ➡ getBoundingClientRect() <h1> ➡ getComputedStyle() ➡ getBoundingClientRect() … <button …> + CSSStyleDeclaration <div …> + CSSStyleDeclaration <h1> + CSSStyleDeclaration …
  • 69. Generate CSS Declaration files CSS scraper <button …> ➡ getComputedStyle() ➡ getBoundingClientRect() <div …> ➡ getComputedStyle() ➡ getBoundingClientRect() <h1> ➡ getComputedStyle() ➡ getBoundingClientRect() …
  • 70. Generate CSS Declaration files CSS scraper
  • 71. Generate CSS Declaration files CSS scraper update!
  • 72. Generate CSS Declaration files CSS scraper update!
  • 73. Generate CSS Declaration files CSS scraper update!
  • 74. Transform angular to sketch Angular library Sketch library ? CSSDecl jsonSketch GeneratorApp CSS scraper
  • 77. A ‘pure’ example and component variants TSAngular component lib Parses AST
  • 78. A ‘pure’ example and component variants TSAngular component lib examples
  • 79. A ‘pure’ example and component variants TSAngular component lib @Component({ moduleId: module.id, template: `<button dt-button>Simple button</button>`, }) export class ButtonPureExampleComponent { } examples
  • 80. A ‘pure’ example and component variants TSAngular component lib @Component({ moduleId: module.id, template: `<button dt-button>Simple button</button>`, }) export class ButtonPureExampleComponent { } examples
  • 81. A ‘pure’ example and component variants TSAngular component lib @Component({ moduleId: module.id, template: `<button dt-button>Simple button</button>`, }) export class ButtonPureExampleComponent { } examples variants
  • 82. A ‘pure’ example and component variants TSAngular component lib @Component({ moduleId: module.id, template: `<button dt-button>Simple button</button>`, }) export class ButtonPureExampleComponent { } @Component({ selector: `button[dt-button], button[dt-icon-button]`, templateUrl: 'button.html', }) export class DtButton extends … { @Input() get variant(): ‘primary’ | ‘secondary’ { return this._variant; } } examples variants
  • 83. A ‘pure’ example and component variants TSAngular component lib @Component({ moduleId: module.id, template: `<button dt-button>Simple button</button>`, }) export class ButtonPureExampleComponent { } @Component({ selector: `button[dt-button], button[dt-icon-button]`, templateUrl: 'button.html', }) export class DtButton extends … { @Input() get variant(): ‘primary’ | ‘secondary’ { return this._variant; } } examples variants
  • 84. A ‘pure’ example and component variants TSAngular component lib @Component({ moduleId: module.id, template: `<button dt-button>Simple button</button>`, }) export class ButtonPureExampleComponent { } @Component({ selector: `button[dt-button], button[dt-icon-button]`, templateUrl: 'button.html', }) export class DtButton extends … { @Input() get variant(): ‘primary’ | ‘secondary’ { return this._variant; } } examples variants
  • 85. A ‘pure’ example and component variants TSAngular component lib @Component({ moduleId: module.id, template: `<button dt-button>Simple button</button>`, }) export class ButtonPureExampleComponent { } @Component({ selector: `button[dt-button], button[dt-icon-button]`, templateUrl: 'button.html', }) export class DtButton extends … { @Input() get variant(): ‘primary’ | ‘secondary’ { return this._variant; } } examples variants
  • 86. A ‘pure’ example and component variants TSAngular component lib examples variants
  • 87. A ‘pure’ example and component variants TSAngular component lib examples + variants
  • 88. A ‘pure’ example and component variants TSAngular component lib examples + variants
  • 89. A ‘pure’ example and component variants TSAngular component lib examples + variants
  • 90. A ‘pure’ example and component variants TSAngular component lib examples + variants
  • 91. Transform Angular to Sketch Angular library Sketch libraryCSSDecl json Sketch GeneratorApp CSS scraper Library App generator
  • 94. UX + design Initial idea Angular component lib Product code Sketch lib Barista Design System