Automating UI development

Automating UI development

Design systems and pattern libraries help designers and developers to get a common understanding of user interfaces. But even with such tools in place, there's a ton of processes and handovers involved. Each one causing possible friction and information loss. Especially over time. This might lead to new features feeling outdated on release, and screens and mock-ups getting too old too fast.

With our recent move to Angular and Sketch, we were able to automate 70% of our UI development. Helping our developers to focus on the real problems, and reducing the UI review efforts tremendously. Join us and see how we produce a single source of truth for developers and designers, and how we are able to consume this source in our tool of choice.

187d92c9284160ad908885ab096f5209?s=128

Stefan Baumgartner

November 06, 2018
Tweet

Transcript

  1. Automating UI Development Angular Connect 2018 @ddprrt @Ka_TriN_F

  2. Slide about us Katrin Freihofner
 @Ka_TriN_F devone.at

  3. Slide about us Stefan Baumgartner
 @ddprrt javascript-podcast.com

  4. None
  5. None
  6. None
  7. expert groups

  8. Highly specialised screens … with lots of generic, flexible components

  9. None
  10. None
  11. None
  12. None
  13. None
  14. None
  15. None
  16. None
  17. None
  18. Git Design System update Symbols library

  19. Git Design System update Symbols library

  20. Design System update

  21. Design System update

  22. None
  23. You might wonder …how will this affect the product?

  24. None
  25. Initial idea

  26. UX + design Initial idea

  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
  36. None
  37. None
  38. None
  39. Angular component lib

  40. Barista Design System Product code Angular component lib

  41. Barista Design System Product code ? Angular component lib

  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

    json Sketch 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

    json Sketch Generator App CSS scraper
  75. Parsing component code Angular component lib

  76. TS Parsing component code Angular component lib Parses AST

  77. A ‘pure’ example and component variants TS Angular component lib

    Parses AST
  78. A ‘pure’ example and component variants TS Angular component lib

    examples
  79. A ‘pure’ example and component variants TS Angular component lib

    @Component({ moduleId: module.id, template: `<button dt-button>Simple button</button>`, }) export class ButtonPureExampleComponent { } examples
  80. A ‘pure’ example and component variants TS Angular component lib

    @Component({ moduleId: module.id, template: `<button dt-button>Simple button</button>`, }) export class ButtonPureExampleComponent { } examples
  81. A ‘pure’ example and component variants TS Angular 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 TS Angular 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 TS Angular 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 TS Angular 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 TS Angular 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 TS Angular component lib

    examples variants
  87. A ‘pure’ example and component variants TS Angular component lib

    examples + variants
  88. A ‘pure’ example and component variants TS Angular component lib

    examples + variants
  89. A ‘pure’ example and component variants TS Angular component lib

    examples + variants
  90. A ‘pure’ example and component variants TS Angular component lib

    examples + variants
  91. Transform Angular to Sketch Angular library Sketch library CSSDecl json

    Sketch Generator App CSS scraper Library App generator
  92. None
  93. None
  94. UX + design Initial idea Angular component lib Product code

    Sketch lib Barista Design System
  95. Angular component lib Barista Design System Sketch lib Product code

    UX + design
  96. None
  97. None
  98. $royalblue-700: #393db0; dt-theme-palette($green-600, $green-700, $green-800),

  99. None
  100. None
  101. None
  102. Lukas Holzer
 @luka5c0m

  103. Katrin Freihofner
 @Ka_TriN_F Stefan Baumgartner
 @ddprrt Office hours
 12:30 -

    13:00