Advanced

OpenValue

Rachèl Heimbach

Principal Consultant @ OpenValue

Solution Architect @ Rabobank

"The Great Divide"

Front-of-the-front-End

vs.

Back-of-the-front-End

  development

A front-of-the-front-end developer is a web developer who specializes in writing HTML, CSS, and presentational JavaScript code.

A back-of-the-front-end developer is a web developer who specializes in writing JavaScript code necessary to make a web application function properly.

Back-of-the-front-end

  • Writing application business logic.
  • Wiring up, integrating with, and even authoring data sources, services, and APIs.
  • Consuming the UI code.
  • Optimizing the performance of JS code.
  • Writing end-to-end, integration, and other tests.
  • Architecting and managing JS-based infra.
  • Managing devops stuff.
  • Working with front-of-the-front-end devs.
  • Working with the product team.
  • Working with other backend devs and IT

Front-of-the-front-end

  • Crafting semantic HTML.
  • Creating CSS code.
  • Authoring JS that primarily manipulates objects in the DOM.
  • Testing across browsers and devices.
  • Optimizing the performance of FE code.
  • Working with back-of-the-front-end devs.
  • Working with designers.
  • Creating a lib of presentational UI comp.
  • Authoring and documenting a robust intuitive component API for each component.
  • Writing unit tests for UI component library.
  • Architecting the flexibility/composability of the component library.
  • Maintaining the presentational components as a product.

Training Objectives day 1

  • Master Angular fundamentals Front-of-the-Frontend
  • Maintain design system effectively at scale

Understanding Design Systems

Key principles and benefits of design systems.

UI Design

  • Accessibility
  • Theming
  • Dark mode
  • High contrast mode
  • Redesigns

Benefits Design System

  • Consisten UI
  • Faster development
  • Separation of concerns
  • Building blocks...

Atomic Design Methodology

Breaking down UI into fundamental building blocks.

Atomic Design

https://atomicdesign.bradfrost.com/chapter-2/

 Custom Properties

.button {
  background-color: #2563eb;
}

 Custom Properties

:root {
  --color-blue: #2563eb;
}


button {
  background-color: var(--color-blue);
}

 Custom Properties

:root {
  --button-bg-color: #2563eb;
}


button {
  background-color: var(--button-bg-color);
}

 Custom Properties

:root {
  
  // ...
  --color-primary-500: #3b82f6;
  --color-primary-600: #2563eb;
  --color-primary-700: #1d4ed8;
  // ...
  
  --button-bg-color: var(--color-primary-600);
}


button {
  background-color: var(--button-bg-color);
}

 Custom Properties

:root {
  
  // ...
  --color-primary-500: #3b82f6;
  --color-primary-600: #2563eb;
  --color-primary-700: #1d4ed8;
  // ...
  --color-secondary-500: #a855f7;
  --color-secondary-600: #9333ea;
  --color-secondary-700: #7e22ce;
  // ...
  
  --button-primary-bg-color: var(--color-primary-600);
  --button-secondary-bg-color: var(--color-secondary-600);
  // ...
}


button.primary {
  background-color: var(--button-primary-bg-color);
}

button.secondary {
  background-color: var(--button-secondary-bg-color);
}

 Custom Properties

:root {
  /* ... */
  --button-primary-bg-color: var(--color-primary-600);
  --button-secondary-bg-color: var(--color-secondary-600);
}


button.primary {
  background-color: var(--button-primary-bg-color);
}

button.secondary {
  background-color: var(--button-secondary-bg-color);
}

/* Dark Theme */
[data-theme='dark'] {
  --button-primary-background: var(--color-primary-500);
  --button-secondary-background: var(--color-secondary-500);
  /* ... */
}

 Custom Properties

:root {
  /* Core spacing variables */
  --space-xxs: 4px; /* 0.25 × base */
  --space-xs: 8px; /* 0.5 × base */
  --space-sm: 12px; /* 0.75 × base */
  --space-md: 16px; /* 1 × base */
  --space-lg: 24px; /* 1.5 × base */
  --space-xl: 32px; /* 2 × base */
  --space-xxl: 48px; /* 3 × base */
  /* ... */
  --button-padding: var(--space-xs) var(--space-md);
}

 Custom Properties

:root {
  /* Font Sizes */
  --font-xs: 0.75rem; /* 12px */
  --font-sm: 0.875rem; /* 14px */
  --font-base: 1rem; /* 16px */
  --font-lg: 1.125rem; /* 18px */
  --font-xl: 1.25rem; /* 20px */
  --font-2xl: 1.5rem; /* 24px */
  --font-3xl: 1.875rem; /* 30px */
  --font-4xl: 2.25rem; /* 36px */
  --font-5xl: 3rem; /* 48px */

  /* Font Weights */
  --font-thin: 100;
  --font-extralight: 200;
  --font-light: 300;
  --font-normal: 400;
  --font-medium: 500;
  --font-semibold: 600;
  --font-bold: 700;
  --font-extrabold: 800;
}

Atomic Design

https://atomicdesign.bradfrost.com/chapter-2/

https://atomicdesign.bradfrost.com/chapter-2/

https://atomicdesign.bradfrost.com/chapter-2/

https://atomicdesign.bradfrost.com/chapter-2/

https://atomicdesign.bradfrost.com/chapter-2/

https://atomicdesign.bradfrost.com/chapter-2/

https://atomicdesign.bradfrost.com/chapter-2/

https://atomicdesign.bradfrost.com/chapter-2/

UI Components in Angular

Creating reusable and efficient UI components.

"Build UIs without the grunt work"

Component Isolation

​​"Build components without starting a complex dev setup, force certain data into your database, or navigate around your application"

Atomic Design Storybook demo

Design tokens + UI components library

Portrait

landscape

Primary

Max

Min

Max

Min

Max

Min

Primary

Primary

Primary

Max

Min

Max

Min

Style | Layout

Product

  • It should display product information
<section class="product">
  <ov-thumbnail></ov-thumbnail>
  <div class="info">
    <ov-sub-title></ov-sub-title>
    <ov-title></ov-title>
    <div class="details">
      <div>
        <ov-rating></ov-rating>
        <ov-price></ov-price>
      </div>
    </div>
  </div>
</section>

Product

  • It should display product information
  • It should display availability
<section class="product">
  <ov-thumbnail></ov-thumbnail>
  <div class="info">
    <ov-sub-title></ov-sub-title>
    <ov-title></ov-title>
    <div class="details">
      <div>
        <ov-rating></ov-rating>
        <ov-price></ov-price>
      </div>
      <div>
        <ov-quantity-picker>
        </ov-quantity-picker>
      </div>
    </div>
    <div class="footer">
      <ov-message type="ok"></ov-message>
    </div>
  </div>
</section>

Product

  • It should display product information
  • It should display availability
  • It should warn about limited availability
<section class="product">
  <ov-thumbnail></ov-thumbnail>
  <div class="info">
    <ov-sub-title></ov-sub-title>
    <ov-title></ov-title>
    <div class="details">
      <div>
        <ov-rating></ov-rating>
        <ov-price></ov-price>
      </div>
      <div>
        <ov-quantity-picker>
        </ov-quantity-picker>
      </div>
    </div>
    <div class="footer">
      <ov-message type="ok" 
        *ngIf="!isLimited; else limited">
      </ov-message>
      <ng-template #limited>
        <ov-message type="warn"></ov-message>
      </ng-template>
    </div>
  </div>
</section>

Product

<section class="product">
  <ov-thumbnail></ov-thumbnail>
  <div class="info">
    <ov-sub-title></ov-sub-title>
    <ov-title></ov-title>
    <div class="details">
      <div>
        <ov-rating></ov-rating>
        <ov-price></ov-price>
      </div>
      <div>
        <ov-quantity-picker 
          *ngIf="!isOutOfStock; else outOfStock">
        </ov-quantity-picker>
        <ng-template #outOfStock>
          <ov-button>
            <ov-icon></ov-icon>
          </ov-button>
      	</ng-template>
      </div>
    </div>
    <div class="footer">
      <ov-message type="ok" 
        *ngIf="!isLimited">
      </ov-message>
      <ov-message type="warn" 
        *ngIf="isLimited">
      </ov-message>
      <ov-message type="error" 
        *ngIf="isOutOfStock">
      </ov-message>
    </div>
  </div>
</section>
  • It should display product information
  • It should display availability
  • It should warn about limited availability
  • It could be out of stock and show a contact option

Product

<section class="product" *ngIf="!isReplaced">
  <ov-thumbnail></ov-thumbnail>
  <div class="info">
    <ov-sub-title></ov-sub-title>
    <ov-title></ov-title>
    <div class="details">
      <div>
        <ov-rating></ov-rating>
        <ov-price></ov-price>
      </div>
      <div>
        <ov-quantity-picker 
          *ngIf="!isOutOfStock; else outOfStock">
        </ov-quantity-picker>
        <ng-template #outOfStock>
          <ov-button></ov-button>
      	</ng-template>
      </div>
    </div>
    <div class="footer">
      <ov-message type="ok" 
        *ngIf="!isLimited">
      </ov-message>
      <ov-message type="warn" 
        *ngIf="isLimited">
      </ov-message>
      <ov-message type="error" 
        *ngIf="isOutOfStock">
      </ov-message>
    </div>
  </div>
</section>
<section *ngIf="isReplaced">
  ...
</section>
  • It should display product information
  • It should display availability
  • It should warn about limited availability
  • It could be out of stock and show a contact option
  • It could be completely replaced by an alternative product

Product

@Component({ ... })
export class ProductComponent {
  @Input() product!: Product;
}
  • It should display product information
  • It should display availability
  • It should warn about limited availability
  • It could be out of stock and show a contact option
  • It could be completely replaced by an alternative product

Product

@Component({ ... })
export class ProductComponent {
  @Input() product!: Product;   
  
  @Input() isLimited = false;
}
  • It should display product information
  • It should display availability
  • It should warn about limited availability
  • It could be out of stock and show a contact option
  • It could be completely replaced by an alternative product

Product

@Component({ ... })
export class ProductComponent {
  @Input() product!: Product;   
  
  @Input() isLimited = false;

  @Input() isOutOfStock = false;
}
  • It should display product information
  • It should display availability
  • It should warn about limited availability
  • It could be out of stock and show a contact option
  • It could be completely replaced by an alternative product

Product

@Component({ ... })
export class ProductComponent {
  @Input() product!: Product;   
  
  @Input() isLimited = false;

  @Input() isOutOfStock = false;

  @Input() isReplaced? = false;
  @Input() replacement?: Product;
}
  • It should display product information
  • It should display availability
  • It should warn about limited availability
  • It could be out of stock and show a contact option
  • It could be completely replaced by an alternative product

Product

@Component({ ... })
export class ProductComponent {
  @Input() product!: Product;   
  
  @Input() isLimited = false;

  @Input() isOutOfStock = false;

  @Input() isReplaced? = false;
  @Input() replacement?: Product;
  
  @Output() addToCart = new EventEmitter<number>();
  @Output() contactUs = new EventEmitter<Product>();
}
  • It should display product information
  • It should display availability
  • It should warn about limited availability
  • It could be out of stock and show a contact option
  • It could be completely replaced by an alternative product

Composition

Slots

Made with Slides.com