🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
810 lines
23 KiB
Markdown
810 lines
23 KiB
Markdown
# UI Landing Pages Library Implementation Plan
|
|
|
|
## Executive Summary
|
|
|
|
This document outlines the implementation strategy for creating a comprehensive `ui-landing-pages` library within the SSuite Angular workspace. The library will provide production-ready components specifically designed for building modern websites and landing pages, leveraging Angular 19 features and integrating seamlessly with existing libraries: `ui-design-system`, `ui-essentials`, `ui-animations`, `ui-backgrounds`, `ui-code-display`, and `shared-utils`.
|
|
|
|
## Technical Foundation
|
|
|
|
### Angular 19 Requirements
|
|
- **Standalone Components**: All components will be standalone (no NgModules)
|
|
- **Control Flow Syntax**: Use `@if`, `@for`, `@switch` (not `*ngIf`, `*ngFor`)
|
|
- **Signals**: Prefer signals over observables for state management
|
|
- **Inject Function**: Use `inject()` function over constructor injection
|
|
- **OnPush Change Detection**: Default for all components
|
|
- **@defer**: Implement lazy loading where appropriate
|
|
|
|
### Design System Integration
|
|
|
|
#### Token Import Path
|
|
```scss
|
|
// Correct import path for semantic tokens
|
|
@use '../../../../../ui-design-system/src/styles/semantic/index' as *;
|
|
```
|
|
|
|
#### Typography Strategy
|
|
The design system provides comprehensive typography tokens as maps and single values:
|
|
- **Headings**: Use `$semantic-typography-heading-h1` through `h5` (maps)
|
|
- **Body Text**: Use `$semantic-typography-body-large/medium/small` (maps)
|
|
- **Component Text**: Use `$semantic-typography-button-*` variants (maps)
|
|
|
|
#### Component Architecture Principles
|
|
- **NO hardcoded values**: All styling must use semantic tokens
|
|
- **BEM methodology**: Consistent class naming convention
|
|
- **Component composition**: Leverage existing `ui-essentials` components
|
|
- **Accessibility first**: WCAG 2.1 AA compliance required
|
|
|
|
## Architecture Overview
|
|
|
|
### Library Structure
|
|
```
|
|
projects/ui-landing-pages/
|
|
├── src/
|
|
│ ├── lib/
|
|
│ │ ├── components/
|
|
│ │ │ ├── heroes/ # Hero section components
|
|
│ │ │ ├── features/ # Feature showcase components
|
|
│ │ │ ├── social-proof/ # Testimonials, logos, stats
|
|
│ │ │ ├── conversion/ # CTAs, pricing, forms
|
|
│ │ │ ├── navigation/ # Headers, menus, footers
|
|
│ │ │ ├── content/ # FAQ, team, timeline
|
|
│ │ │ └── templates/ # Complete page templates
|
|
│ │ ├── services/ # Landing page utilities
|
|
│ │ ├── interfaces/ # TypeScript interfaces
|
|
│ │ └── directives/ # Reusable directives
|
|
│ ├── public-api.ts
|
|
│ └── test.ts
|
|
├── ng-package.json
|
|
├── package.json
|
|
├── tsconfig.lib.json
|
|
├── tsconfig.lib.prod.json
|
|
├── tsconfig.spec.json
|
|
└── README.md
|
|
```
|
|
|
|
### Component Naming Convention
|
|
All components follow the pattern: `ui-lp-[component-name]`
|
|
- Prefix: `ui-lp-` (ui landing pages)
|
|
- Examples: `ui-lp-hero`, `ui-lp-feature-grid`, `ui-lp-pricing-table`
|
|
|
|
## Implementation Phases
|
|
|
|
---
|
|
|
|
## Phase 1: Foundation & Hero Components
|
|
|
|
### Objective
|
|
Establish library foundation and implement essential hero section components using Angular 19 best practices.
|
|
|
|
### Components to Implement
|
|
|
|
#### 1.1 HeroSection Component (`ui-lp-hero`)
|
|
|
|
**TypeScript Implementation**:
|
|
```typescript
|
|
import { Component, Input, Output, EventEmitter, ChangeDetectionStrategy, ViewEncapsulation, signal } from '@angular/core';
|
|
import { CommonModule } from '@angular/common';
|
|
import { ButtonComponent } from 'ui-essentials';
|
|
import { ContainerComponent } from 'ui-essentials';
|
|
import { AnimationDirective } from 'ui-animations';
|
|
|
|
export interface HeroConfig {
|
|
title: string;
|
|
subtitle?: string;
|
|
ctaPrimary?: CTAButton;
|
|
ctaSecondary?: CTAButton;
|
|
backgroundType?: 'solid' | 'gradient' | 'image' | 'video' | 'animated';
|
|
alignment?: 'left' | 'center' | 'right';
|
|
minHeight?: 'full' | 'large' | 'medium';
|
|
animationType?: 'fade' | 'slide' | 'zoom';
|
|
}
|
|
|
|
export interface CTAButton {
|
|
text: string;
|
|
variant: 'primary' | 'secondary' | 'outline';
|
|
size?: 'sm' | 'md' | 'lg';
|
|
icon?: string;
|
|
action: () => void;
|
|
}
|
|
|
|
@Component({
|
|
selector: 'ui-lp-hero',
|
|
standalone: true,
|
|
imports: [CommonModule, ButtonComponent, ContainerComponent, AnimationDirective],
|
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
encapsulation: ViewEncapsulation.None,
|
|
template: `
|
|
<section
|
|
class="ui-lp-hero"
|
|
[class.ui-lp-hero--{{config().backgroundType}}]="config().backgroundType"
|
|
[class.ui-lp-hero--{{config().alignment}}]="config().alignment"
|
|
[class.ui-lp-hero--{{config().minHeight}}]="config().minHeight"
|
|
[attr.aria-label]="'Hero section'"
|
|
uiAnimation
|
|
[animationType]="config().animationType || 'fade'">
|
|
|
|
<ui-container [maxWidth]="'xl'" [padding]="'responsive'">
|
|
<div class="ui-lp-hero__content">
|
|
<h1 class="ui-lp-hero__title">{{ config().title }}</h1>
|
|
|
|
@if (config().subtitle) {
|
|
<p class="ui-lp-hero__subtitle">{{ config().subtitle }}</p>
|
|
}
|
|
|
|
@if (config().ctaPrimary || config().ctaSecondary) {
|
|
<div class="ui-lp-hero__actions">
|
|
@if (config().ctaPrimary) {
|
|
<ui-button
|
|
[variant]="config().ctaPrimary.variant"
|
|
[size]="config().ctaPrimary.size || 'lg'"
|
|
(clicked)="handleCTAClick(config().ctaPrimary)">
|
|
{{ config().ctaPrimary.text }}
|
|
</ui-button>
|
|
}
|
|
|
|
@if (config().ctaSecondary) {
|
|
<ui-button
|
|
[variant]="config().ctaSecondary.variant"
|
|
[size]="config().ctaSecondary.size || 'lg'"
|
|
(clicked)="handleCTAClick(config().ctaSecondary)">
|
|
{{ config().ctaSecondary.text }}
|
|
</ui-button>
|
|
}
|
|
</div>
|
|
}
|
|
</div>
|
|
</ui-container>
|
|
|
|
@if (config().backgroundType === 'animated') {
|
|
<div class="ui-lp-hero__animated-bg" aria-hidden="true"></div>
|
|
}
|
|
</section>
|
|
`,
|
|
styleUrl: './hero-section.component.scss'
|
|
})
|
|
export class HeroSectionComponent {
|
|
config = signal<HeroConfig>({
|
|
title: '',
|
|
alignment: 'center',
|
|
backgroundType: 'solid',
|
|
minHeight: 'large'
|
|
});
|
|
|
|
@Input() set configuration(value: HeroConfig) {
|
|
this.config.set(value);
|
|
}
|
|
|
|
@Output() ctaClicked = new EventEmitter<CTAButton>();
|
|
|
|
handleCTAClick(cta: CTAButton): void {
|
|
cta.action();
|
|
this.ctaClicked.emit(cta);
|
|
}
|
|
}
|
|
```
|
|
|
|
**SCSS Implementation**:
|
|
```scss
|
|
@use '../../../../../ui-design-system/src/styles/semantic/index' as *;
|
|
|
|
.ui-lp-hero {
|
|
position: relative;
|
|
display: flex;
|
|
align-items: center;
|
|
width: 100%;
|
|
|
|
// Min Height Variants
|
|
&--full {
|
|
min-height: 100vh;
|
|
}
|
|
|
|
&--large {
|
|
min-height: 80vh;
|
|
}
|
|
|
|
&--medium {
|
|
min-height: 60vh;
|
|
}
|
|
|
|
// Background Variants
|
|
&--solid {
|
|
background: $semantic-color-surface-primary;
|
|
}
|
|
|
|
&--gradient {
|
|
background: linear-gradient(
|
|
135deg,
|
|
$semantic-color-primary,
|
|
$semantic-color-secondary
|
|
);
|
|
}
|
|
|
|
&--animated {
|
|
background: $semantic-color-surface-primary;
|
|
overflow: hidden;
|
|
}
|
|
|
|
// Content Container
|
|
&__content {
|
|
position: relative;
|
|
z-index: $semantic-z-index-dropdown;
|
|
padding: $semantic-spacing-layout-section-lg 0;
|
|
}
|
|
|
|
// Alignment Variants
|
|
&--left &__content {
|
|
text-align: left;
|
|
}
|
|
|
|
&--center &__content {
|
|
text-align: center;
|
|
margin: 0 auto;
|
|
max-width: 800px;
|
|
}
|
|
|
|
&--right &__content {
|
|
text-align: right;
|
|
}
|
|
|
|
// Typography
|
|
&__title {
|
|
font-family: map-get($semantic-typography-heading-h1, font-family);
|
|
font-size: map-get($semantic-typography-heading-h1, font-size);
|
|
font-weight: map-get($semantic-typography-heading-h1, font-weight);
|
|
line-height: map-get($semantic-typography-heading-h1, line-height);
|
|
color: $semantic-color-text-primary;
|
|
margin-bottom: $semantic-spacing-content-heading;
|
|
|
|
.ui-lp-hero--gradient &,
|
|
.ui-lp-hero--image & {
|
|
color: $semantic-color-on-primary;
|
|
}
|
|
}
|
|
|
|
&__subtitle {
|
|
font-family: map-get($semantic-typography-body-large, font-family);
|
|
font-size: map-get($semantic-typography-body-large, font-size);
|
|
font-weight: map-get($semantic-typography-body-large, font-weight);
|
|
line-height: map-get($semantic-typography-body-large, line-height);
|
|
color: $semantic-color-text-secondary;
|
|
margin-bottom: $semantic-spacing-content-paragraph;
|
|
|
|
.ui-lp-hero--gradient &,
|
|
.ui-lp-hero--image & {
|
|
color: $semantic-color-on-primary;
|
|
opacity: $semantic-opacity-subtle;
|
|
}
|
|
}
|
|
|
|
&__actions {
|
|
display: flex;
|
|
gap: $semantic-spacing-component-md;
|
|
margin-top: $semantic-spacing-layout-section-sm;
|
|
|
|
.ui-lp-hero--center & {
|
|
justify-content: center;
|
|
}
|
|
|
|
.ui-lp-hero--right & {
|
|
justify-content: flex-end;
|
|
}
|
|
}
|
|
|
|
// Animated Background
|
|
&__animated-bg {
|
|
position: absolute;
|
|
inset: 0;
|
|
background: linear-gradient(
|
|
-45deg,
|
|
$semantic-color-primary,
|
|
$semantic-color-secondary,
|
|
$semantic-color-primary,
|
|
$semantic-color-secondary
|
|
);
|
|
background-size: 400% 400%;
|
|
animation: gradientShift 15s ease infinite;
|
|
z-index: $semantic-z-index-dropdown - 1;
|
|
}
|
|
|
|
// Responsive Design
|
|
@media (max-width: $semantic-breakpoint-md - 1) {
|
|
&--full {
|
|
min-height: 100svh; // Use small viewport height for mobile
|
|
}
|
|
|
|
&__title {
|
|
font-family: map-get($semantic-typography-heading-h2, font-family);
|
|
font-size: map-get($semantic-typography-heading-h2, font-size);
|
|
font-weight: map-get($semantic-typography-heading-h2, font-weight);
|
|
line-height: map-get($semantic-typography-heading-h2, line-height);
|
|
}
|
|
|
|
&__actions {
|
|
flex-direction: column;
|
|
align-items: stretch;
|
|
}
|
|
}
|
|
|
|
@media (max-width: $semantic-breakpoint-sm - 1) {
|
|
&__title {
|
|
font-family: map-get($semantic-typography-heading-h3, font-family);
|
|
font-size: map-get($semantic-typography-heading-h3, font-size);
|
|
font-weight: map-get($semantic-typography-heading-h3, font-weight);
|
|
line-height: map-get($semantic-typography-heading-h3, line-height);
|
|
}
|
|
|
|
&__subtitle {
|
|
font-family: map-get($semantic-typography-body-medium, font-family);
|
|
font-size: map-get($semantic-typography-body-medium, font-size);
|
|
font-weight: map-get($semantic-typography-body-medium, font-weight);
|
|
line-height: map-get($semantic-typography-body-medium, line-height);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Keyframes for animated background
|
|
@keyframes gradientShift {
|
|
0% {
|
|
background-position: 0% 50%;
|
|
}
|
|
50% {
|
|
background-position: 100% 50%;
|
|
}
|
|
100% {
|
|
background-position: 0% 50%;
|
|
}
|
|
}
|
|
```
|
|
|
|
#### 1.2 HeroWithImage Component (`ui-lp-hero-image`)
|
|
|
|
Similar structure with image handling capabilities, lazy loading, and responsive image optimization.
|
|
|
|
#### 1.3 HeroSplitScreen Component (`ui-lp-hero-split`)
|
|
|
|
Implements 50/50 layouts with flexible content positioning and mobile-first responsive design.
|
|
|
|
### Integration with Existing Libraries
|
|
|
|
**UI Essentials Components**:
|
|
- `ButtonComponent` for CTAs
|
|
- `ContainerComponent` for responsive layout
|
|
- `ImageComponent` for optimized image loading
|
|
- `FlexComponent` for flexible layouts
|
|
|
|
**UI Animations**:
|
|
- `AnimationDirective` for entrance effects
|
|
- `ScrollTriggerDirective` for scroll-based animations
|
|
- `ParallaxDirective` for depth effects
|
|
|
|
**UI Backgrounds**:
|
|
- `GradientBackgroundComponent` for dynamic backgrounds
|
|
- `ParticleBackgroundComponent` for animated effects
|
|
- `VideoBackgroundComponent` for video backgrounds
|
|
|
|
---
|
|
|
|
## Phase 2: Feature Sections & Social Proof
|
|
|
|
### Components to Implement
|
|
|
|
#### 2.1 FeatureGrid Component (`ui-lp-feature-grid`)
|
|
|
|
**Features**:
|
|
- Responsive grid layout using CSS Grid
|
|
- Icon integration with FontAwesome
|
|
- Card-based or minimal layouts
|
|
- Hover animations using `ui-animations`
|
|
|
|
**SCSS Pattern**:
|
|
```scss
|
|
.ui-lp-feature-grid {
|
|
display: grid;
|
|
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
|
|
gap: $semantic-spacing-grid-gap-lg;
|
|
|
|
&__item {
|
|
padding: $semantic-spacing-component-lg;
|
|
background: $semantic-color-surface-elevated;
|
|
border-radius: $semantic-border-card-radius;
|
|
box-shadow: $semantic-shadow-card-rest;
|
|
transition: all $semantic-motion-duration-fast $semantic-motion-easing-ease;
|
|
|
|
&:hover {
|
|
box-shadow: $semantic-shadow-card-hover;
|
|
transform: translateY(-2px);
|
|
}
|
|
}
|
|
|
|
&__icon {
|
|
font-size: $semantic-sizing-icon-navigation;
|
|
color: $semantic-color-primary;
|
|
margin-bottom: $semantic-spacing-component-md;
|
|
}
|
|
|
|
&__title {
|
|
font-family: map-get($semantic-typography-heading-h4, font-family);
|
|
font-size: map-get($semantic-typography-heading-h4, font-size);
|
|
font-weight: map-get($semantic-typography-heading-h4, font-weight);
|
|
line-height: map-get($semantic-typography-heading-h4, line-height);
|
|
color: $semantic-color-text-primary;
|
|
margin-bottom: $semantic-spacing-component-sm;
|
|
}
|
|
|
|
&__description {
|
|
font-family: map-get($semantic-typography-body-medium, font-family);
|
|
font-size: map-get($semantic-typography-body-medium, font-size);
|
|
font-weight: map-get($semantic-typography-body-medium, font-weight);
|
|
line-height: map-get($semantic-typography-body-medium, line-height);
|
|
color: $semantic-color-text-secondary;
|
|
}
|
|
}
|
|
```
|
|
|
|
#### 2.2 TestimonialCarousel Component (`ui-lp-testimonials`)
|
|
|
|
Leverages existing carousel functionality with custom testimonial card design.
|
|
|
|
#### 2.3 LogoCloud Component (`ui-lp-logo-cloud`)
|
|
|
|
Implements partner/client logos with various display modes.
|
|
|
|
#### 2.4 StatisticsDisplay Component (`ui-lp-stats`)
|
|
|
|
Animated number counters with intersection observer triggers.
|
|
|
|
---
|
|
|
|
## Phase 3: Conversion Components
|
|
|
|
### Components to Implement
|
|
|
|
#### 3.1 PricingTable Component (`ui-lp-pricing`)
|
|
|
|
**Features**:
|
|
- Monthly/yearly toggle with smooth transitions
|
|
- Popular plan highlighting
|
|
- Feature comparison matrix
|
|
- Responsive card layout
|
|
|
|
**Angular Implementation Pattern**:
|
|
```typescript
|
|
import { Component, Input, signal, computed } from '@angular/core';
|
|
import { CommonModule } from '@angular/common';
|
|
import { SwitchComponent } from 'ui-essentials';
|
|
import { TableComponent } from 'ui-essentials';
|
|
|
|
@Component({
|
|
selector: 'ui-lp-pricing',
|
|
standalone: true,
|
|
imports: [CommonModule, SwitchComponent, TableComponent],
|
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
template: `
|
|
<div class="ui-lp-pricing">
|
|
<div class="ui-lp-pricing__header">
|
|
<h2 class="ui-lp-pricing__title">{{ title }}</h2>
|
|
|
|
@if (showBillingToggle) {
|
|
<div class="ui-lp-pricing__toggle">
|
|
<span [class.active]="!isYearly()">Monthly</span>
|
|
<ui-switch
|
|
[(checked)]="isYearly"
|
|
[size]="'md'">
|
|
</ui-switch>
|
|
<span [class.active]="isYearly()">
|
|
Yearly
|
|
@if (yearlySavings) {
|
|
<span class="ui-lp-pricing__badge">Save {{ yearlySavings }}%</span>
|
|
}
|
|
</span>
|
|
</div>
|
|
}
|
|
</div>
|
|
|
|
<div class="ui-lp-pricing__plans">
|
|
@for (plan of plans(); track plan.id) {
|
|
<div
|
|
class="ui-lp-pricing__plan"
|
|
[class.ui-lp-pricing__plan--popular]="plan.popular">
|
|
|
|
@if (plan.badge) {
|
|
<div class="ui-lp-pricing__plan-badge">{{ plan.badge }}</div>
|
|
}
|
|
|
|
<h3 class="ui-lp-pricing__plan-name">{{ plan.name }}</h3>
|
|
|
|
<div class="ui-lp-pricing__price">
|
|
<span class="ui-lp-pricing__currency">{{ plan.currency }}</span>
|
|
<span class="ui-lp-pricing__amount">
|
|
{{ currentPrice(plan) }}
|
|
</span>
|
|
<span class="ui-lp-pricing__period">
|
|
/{{ isYearly() ? 'year' : 'month' }}
|
|
</span>
|
|
</div>
|
|
|
|
<ul class="ui-lp-pricing__features">
|
|
@for (feature of plan.features; track feature.id) {
|
|
<li class="ui-lp-pricing__feature"
|
|
[class.ui-lp-pricing__feature--included]="feature.included">
|
|
@if (feature.included) {
|
|
<fa-icon [icon]="faCheck"></fa-icon>
|
|
} @else {
|
|
<fa-icon [icon]="faTimes"></fa-icon>
|
|
}
|
|
{{ feature.text }}
|
|
</li>
|
|
}
|
|
</ul>
|
|
|
|
<ui-button
|
|
[variant]="plan.popular ? 'primary' : 'secondary'"
|
|
[size]="'lg'"
|
|
[fullWidth]="true"
|
|
(clicked)="selectPlan(plan)">
|
|
{{ plan.ctaText || 'Get Started' }}
|
|
</ui-button>
|
|
</div>
|
|
}
|
|
</div>
|
|
</div>
|
|
`
|
|
})
|
|
export class PricingTableComponent {
|
|
@Input() plans = signal<PricingPlan[]>([]);
|
|
@Input() title = 'Choose Your Plan';
|
|
@Input() showBillingToggle = true;
|
|
@Input() yearlySavings = 20;
|
|
|
|
isYearly = signal(false);
|
|
|
|
currentPrice = computed(() => (plan: PricingPlan) => {
|
|
return this.isYearly() ? plan.yearlyPrice : plan.monthlyPrice;
|
|
});
|
|
|
|
selectPlan(plan: PricingPlan): void {
|
|
// Implementation
|
|
}
|
|
}
|
|
```
|
|
|
|
#### 3.2 CTASection Component (`ui-lp-cta`)
|
|
|
|
High-converting call-to-action sections with urgency indicators.
|
|
|
|
#### 3.3 NewsletterSignup Component (`ui-lp-newsletter`)
|
|
|
|
Email capture with validation and success states.
|
|
|
|
---
|
|
|
|
## Phase 4: Navigation & Layout
|
|
|
|
### Components to Implement
|
|
|
|
#### 4.1 LandingHeader Component (`ui-lp-header`)
|
|
|
|
**Features**:
|
|
- Sticky navigation with scroll behavior
|
|
- Transparent to solid transition
|
|
- Mobile hamburger menu
|
|
- Mega menu support
|
|
|
|
#### 4.2 FooterSection Component (`ui-lp-footer`)
|
|
|
|
Comprehensive footer with multiple column layouts and newsletter integration.
|
|
|
|
---
|
|
|
|
## Phase 5: Content & Templates
|
|
|
|
### Content Components
|
|
|
|
#### 5.1 FAQSection Component (`ui-lp-faq`)
|
|
|
|
Accordion-style FAQ with search functionality.
|
|
|
|
#### 5.2 TeamGrid Component (`ui-lp-team`)
|
|
|
|
Team member cards with social links.
|
|
|
|
#### 5.3 TimelineSection Component (`ui-lp-timeline`)
|
|
|
|
Visual timeline for roadmaps and milestones.
|
|
|
|
### Page Templates
|
|
|
|
#### 5.4 Complete Landing Page Templates
|
|
|
|
Pre-built templates combining all components:
|
|
- **SaaS Landing Page**: Hero → Features → Social Proof → Pricing → CTA
|
|
- **Product Landing Page**: Hero → Product Showcase → Reviews → Purchase
|
|
- **Agency Landing Page**: Hero → Services → Portfolio → Team → Contact
|
|
|
|
---
|
|
|
|
## Technical Implementation Guidelines
|
|
|
|
### Performance Optimization
|
|
- **Lazy Loading**: Use `@defer` for below-fold components
|
|
- **Image Optimization**: Implement responsive images with srcset
|
|
- **Bundle Size**: Tree-shakeable exports, <50kb per component
|
|
- **Critical CSS**: Inline critical styles for above-fold content
|
|
|
|
### Accessibility Requirements
|
|
- **ARIA Labels**: Proper semantic HTML and ARIA attributes
|
|
- **Keyboard Navigation**: Full keyboard support with visible focus
|
|
- **Screen Readers**: Meaningful alt text and announcements
|
|
- **Color Contrast**: Minimum 4.5:1 ratio for text
|
|
|
|
### Testing Strategy
|
|
```typescript
|
|
// Example test structure
|
|
describe('HeroSectionComponent', () => {
|
|
let component: HeroSectionComponent;
|
|
let fixture: ComponentFixture<HeroSectionComponent>;
|
|
|
|
beforeEach(async () => {
|
|
await TestBed.configureTestingModule({
|
|
imports: [HeroSectionComponent]
|
|
}).compileComponents();
|
|
|
|
fixture = TestBed.createComponent(HeroSectionComponent);
|
|
component = fixture.componentInstance;
|
|
});
|
|
|
|
it('should apply correct alignment class', () => {
|
|
component.configuration = {
|
|
title: 'Test',
|
|
alignment: 'left'
|
|
};
|
|
fixture.detectChanges();
|
|
|
|
const element = fixture.nativeElement.querySelector('.ui-lp-hero');
|
|
expect(element).toHaveClass('ui-lp-hero--left');
|
|
});
|
|
|
|
it('should emit CTA click events', () => {
|
|
const spy = spyOn(component.ctaClicked, 'emit');
|
|
const mockCTA = {
|
|
text: 'Click',
|
|
variant: 'primary' as const,
|
|
action: () => {}
|
|
};
|
|
|
|
component.handleCTAClick(mockCTA);
|
|
expect(spy).toHaveBeenCalledWith(mockCTA);
|
|
});
|
|
});
|
|
```
|
|
|
|
### Demo Application Integration
|
|
|
|
Each component will have a comprehensive demo in `demo-ui-essentials`:
|
|
|
|
```typescript
|
|
// demos.routes.ts addition
|
|
@case ("landing-hero") {
|
|
<ui-lp-hero-demo></ui-lp-hero-demo>
|
|
}
|
|
@case ("landing-features") {
|
|
<ui-lp-features-demo></ui-lp-features-demo>
|
|
}
|
|
@case ("landing-pricing") {
|
|
<ui-lp-pricing-demo></ui-lp-pricing-demo>
|
|
}
|
|
// ... etc
|
|
```
|
|
|
|
### Build Configuration
|
|
|
|
```json
|
|
// ng-package.json
|
|
{
|
|
"$schema": "../../node_modules/ng-packagr/ng-package.schema.json",
|
|
"dest": "../../dist/ui-landing-pages",
|
|
"lib": {
|
|
"entryFile": "src/public-api.ts"
|
|
}
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Quality Assurance Checklist
|
|
|
|
### Design System Compliance
|
|
- [ ] All colors from `$semantic-color-*` tokens only
|
|
- [ ] All spacing from `$semantic-spacing-*` tokens only
|
|
- [ ] Typography using `map-get()` for map tokens
|
|
- [ ] Shadows from `$semantic-shadow-*` tokens only
|
|
- [ ] Borders from `$semantic-border-*` tokens only
|
|
- [ ] No hardcoded values anywhere
|
|
|
|
### Angular 19 Standards
|
|
- [ ] Standalone components throughout
|
|
- [ ] New control flow syntax (@if, @for, @switch)
|
|
- [ ] Signals for state management
|
|
- [ ] OnPush change detection
|
|
- [ ] Proper TypeScript typing
|
|
|
|
### Component Quality
|
|
- [ ] BEM class naming convention
|
|
- [ ] Responsive design implemented
|
|
- [ ] Accessibility standards met
|
|
- [ ] Unit tests with >90% coverage
|
|
- [ ] Demo component created
|
|
- [ ] Public API exports added
|
|
|
|
### Integration
|
|
- [ ] Works with existing ui-essentials components
|
|
- [ ] Leverages ui-animations directives
|
|
- [ ] Uses ui-backgrounds where applicable
|
|
- [ ] Follows workspace patterns
|
|
|
|
---
|
|
|
|
## Implementation Timeline
|
|
|
|
### Week 1-2: Foundation Setup
|
|
- Library scaffolding and configuration
|
|
- Hero components (3 variants)
|
|
- Basic demo application integration
|
|
|
|
### Week 3-4: Feature Components
|
|
- Feature grid and showcase
|
|
- Social proof components
|
|
- Statistics and counters
|
|
|
|
### Week 5-6: Conversion Components
|
|
- Pricing tables
|
|
- CTA sections
|
|
- Newsletter signup
|
|
- Contact forms
|
|
|
|
### Week 7: Navigation & Layout
|
|
- Landing page header
|
|
- Footer variations
|
|
- Sticky navigation
|
|
|
|
### Week 8-9: Content & Templates
|
|
- FAQ, Team, Timeline components
|
|
- Complete page templates
|
|
- Documentation
|
|
|
|
### Week 10: Polish & Optimization
|
|
- Performance optimization
|
|
- Accessibility audit
|
|
- Final testing
|
|
- Documentation completion
|
|
|
|
---
|
|
|
|
## Success Metrics
|
|
|
|
### Development Metrics
|
|
- 100% TypeScript coverage
|
|
- Zero accessibility violations
|
|
- All components use semantic tokens
|
|
- Bundle size under 200kb total
|
|
- Lighthouse score >95
|
|
|
|
### Quality Metrics
|
|
- All components have demos
|
|
- Unit test coverage >90%
|
|
- Documentation complete
|
|
- No hardcoded values
|
|
- Consistent API patterns
|
|
|
|
---
|
|
|
|
## Conclusion
|
|
|
|
This implementation plan provides a comprehensive roadmap for building a production-ready `ui-landing-pages` library that:
|
|
- Leverages Angular 19's latest features
|
|
- Strictly adheres to the design token system
|
|
- Integrates seamlessly with existing SSuite libraries
|
|
- Provides high-quality, accessible components
|
|
- Enables rapid landing page development
|
|
|
|
The library will empower developers to create professional, performant landing pages while maintaining consistency with the SSuite design system and development standards. |