From fastlane-ui-design
Build scalable design systems with Pangea design tokens, Angular Material theming, and component architecture patterns for Fastlane. Use when implementing token-based theming, building Angular component abstractions, or establishing Pangea-aligned component foundations.
How this skill is triggered — by the user, by Claude, or both
Slash command
/fastlane-ui-design:design-system-patternsThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
Master design system architecture to create consistent, maintainable, and scalable UI foundations across the Fastlane application.
Master design system architecture to create consistent, maintainable, and scalable UI foundations across the Fastlane application.
:root)// Angular component file — use Pangea tokens from _root
.my-component {
color: var(--on-surface);
background: var(--surface);
padding: var(--spacing-sm); // 16px
&__title {
color: var(--on-surface);
font-weight: 600;
}
&__secondary-text {
color: var(--pangea-text-secondary);
}
:host-context(body.dark-theme) & {
background: var(--surface-alt);
}
}
import { Injectable, signal } from '@angular/core';
@Injectable({ providedIn: 'root' })
export class ThemeService {
private readonly darkMode = signal<boolean>(false);
readonly isDark = this.darkMode.asReadonly();
constructor() {
this.initializeTheme();
}
private initializeTheme(): void {
const isDark = localStorage.getItem('theme') === 'dark' ||
(window.matchMedia('(prefers-color-scheme: dark)').matches &&
!localStorage.getItem('theme'));
if (isDark) {
this.applyDarkTheme();
}
}
toggleDark(): void {
const isDark = !this.darkMode();
this.darkMode.set(isDark);
if (isDark) {
this.applyDarkTheme();
} else {
this.applyLightTheme();
}
localStorage.setItem('theme', isDark ? 'dark' : 'light');
}
private applyDarkTheme(): void {
document.body.classList.add('dark-theme');
this.darkMode.set(true);
}
private applyLightTheme(): void {
document.body.classList.remove('dark-theme');
this.darkMode.set(false);
}
}
/* Layer 1: Primitive tokens (raw values) */
:root {
/* Pangea color palette — defined once */
--color-primary: #2563eb;
--color-primary-dark: #1e40af;
--color-success: #16a34a;
--color-error: #dc2626;
--color-warning: #f59e0b;
/* Neutral grays */
--color-gray-50: #f9fafb;
--color-gray-100: #f3f4f6;
--color-gray-900: #111827;
/* Spacing scale (8px base) */
--spacing-xs: 0.5rem; /* 8px */
--spacing-sm: 1rem; /* 16px */
--spacing-md: 1.5rem; /* 24px */
--spacing-lg: 2rem; /* 32px */
--spacing-xl: 2.5rem; /* 40px */
/* Font sizes */
--font-size-sm: 0.875rem;
--font-size-base: 1rem;
--font-size-lg: 1.125rem;
--radius-sm: 0.25rem;
--radius-md: 0.5rem;
--radius-lg: 1rem;
}
/* Layer 2: Semantic tokens (light mode) */
:root {
--surface: white;
--surface-alt: #f9fafb;
--on-surface: #111827;
--pangea-text-secondary: #6b7280;
--border-default: #e5e7eb;
--interactive-primary: var(--color-primary);
--interactive-primary-hover: var(--color-primary-dark);
}
/* Layer 3: Dark mode overrides */
body.dark-theme {
--surface: #111827;
--surface-alt: #1f2937;
--on-surface: #f9fafb;
--pangea-text-secondary: #9ca3af;
--border-default: #374151;
--interactive-primary: var(--color-primary);
}
/* Layer 4: Component tokens (specific usage) */
:root {
--button-primary-bg: var(--interactive-primary);
--button-primary-text: white;
--button-primary-radius: var(--radius-md);
--button-padding-x: var(--spacing-sm);
--button-padding-y: 0.5rem;
}
<!-- Primary action — preferred action -->
<button mat-raised-button color="primary">Submit</button>
<!-- Success action (secondary emphasis) -->
<button mat-raised-button color="accent">Confirm</button>
<!-- Destructive action (danger) -->
<button mat-raised-button color="warn">Delete</button>
<!-- Secondary action (outlined) -->
<button mat-stroked-button>Cancel</button>
<!-- Tertiary action (text-only) -->
<button mat-icon-button aria-label="More actions">
<mat-icon>more_vert</mat-icon>
</button>
import {
Component,
Input,
input,
ChangeDetectionStrategy,
} from '@angular/core';
import { CommonModule } from '@angular/common';
import { MatButtonModule } from '@angular/material/button';
@Component({
selector: 'app-action-button',
standalone: true,
imports: [CommonModule, MatButtonModule],
template: `
<button
mat-raised-button
[color]="color()"
[disabled]="disabled()"
(click)="handleClick()"
class="action-button"
>
<ng-content />
</button>
`,
styleUrl: './action-button.component.scss',
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class ActionButtonComponent {
readonly color = input<'primary' | 'accent' | 'warn'>('primary');
readonly disabled = input<boolean>(false);
handleClick(): void {
// Component logic
}
}
SCSS:
.action-button {
min-width: 120px;
:host-context(body.dark-theme) & {
// Material handles dark mode automatically
// but you can override specific tokens if needed
}
}
:host for encapsulationFastlane uses Pangea's token system:
:root (default)body.dark-themeapps/web/src/styles.scss contains token definitionsThemeService to switch modespangea-design-system skill — complete Pangea token catalog and Material slot remappingdesign-system-patterns — Angular Material integration patternsvisual-design-foundations — token vocabulary and semantic namingnpx claudepluginhub pat-richardson/fastlane-ui-design --plugin fastlane-ui-designCreates, edits, and optimizes skills for Claude Code, including drafting, evaluating with test prompts, iterating on performance, and improving skill descriptions for better triggering accuracy.