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
Angular Advanced
By rachnerd
Angular Advanced
- 20