Add comprehensive component library and demo application

Added extensive component library with feedback components (empty state, loading spinner, skeleton loader), enhanced form components (autocomplete, date picker, file upload, form field, time picker), navigation components (pagination), and overlay components (backdrop, drawer, modal, overlay container). Updated demo application with comprehensive showcase components and enhanced styling throughout the project. Excluded font files from repository to reduce size.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
skyai_dev
2025-09-03 05:38:09 +10:00
parent c803831f60
commit 5983722793
246 changed files with 52845 additions and 25 deletions

View File

@@ -0,0 +1,303 @@
import { Component } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormsModule } from '@angular/forms';
import { SKELETON_COMPONENTS } from '../../../../../ui-essentials/src/lib/components/feedback/skeleton-loader';
@Component({
selector: 'ui-skeleton-loader-demo',
standalone: true,
imports: [CommonModule, FormsModule, ...SKELETON_COMPONENTS],
template: `
<div class="demo-container">
<h2>Skeleton Loader Demo</h2>
<p>Skeleton loaders provide visual placeholders while content is loading, improving perceived performance and user experience.</p>
<!-- Basic Sizes -->
<section class="demo-section">
<h3>Sizes</h3>
<div class="demo-row">
@for (size of sizes; track size) {
<div class="demo-item">
<label>{{ size }}</label>
<ui-skeleton-loader [size]="size" shape="text"></ui-skeleton-loader>
</div>
}
</div>
</section>
<!-- Shapes -->
<section class="demo-section">
<h3>Shapes</h3>
<div class="demo-grid">
@for (shape of shapes; track shape) {
<div class="demo-item">
<label>{{ shape }}</label>
<ui-skeleton-loader [shape]="shape" size="md"></ui-skeleton-loader>
</div>
}
</div>
</section>
<!-- Animations -->
<section class="demo-section">
<h3>Animation Types</h3>
<div class="demo-row">
@for (animation of animations; track animation) {
<div class="demo-item">
<label>{{ animation }}</label>
<ui-skeleton-loader
shape="text"
[animation]="animation"
size="md">
</ui-skeleton-loader>
</div>
}
</div>
</section>
<!-- Width Variants -->
<section class="demo-section">
<h3>Width Variants</h3>
<div class="demo-column">
@for (width of widths; track width) {
<div class="demo-item">
<label>{{ width }}</label>
<ui-skeleton-loader
shape="text"
[width]="width"
size="md">
</ui-skeleton-loader>
</div>
}
</div>
</section>
<!-- Pre-built Components -->
<section class="demo-section">
<h3>Pre-built Components</h3>
<!-- Text Block -->
<div class="demo-subsection">
<h4>Text Block</h4>
<div class="demo-grid">
<div class="demo-item">
<label>3 lines (default)</label>
<ui-skeleton-text-block></ui-skeleton-text-block>
</div>
<div class="demo-item">
<label>5 lines</label>
<ui-skeleton-text-block [lines]="5"></ui-skeleton-text-block>
</div>
<div class="demo-item">
<label>Custom last line width</label>
<ui-skeleton-text-block [lines]="4" lastLineWidth="w-25"></ui-skeleton-text-block>
</div>
</div>
</div>
<!-- Profile -->
<div class="demo-subsection">
<h4>Profile</h4>
<div class="demo-grid">
<div class="demo-item">
<label>Default</label>
<ui-skeleton-profile></ui-skeleton-profile>
</div>
<div class="demo-item">
<label>Small Avatar</label>
<ui-skeleton-profile avatarSize="sm"></ui-skeleton-profile>
</div>
<div class="demo-item">
<label>No Extra Info</label>
<ui-skeleton-profile [showExtraInfo]="false"></ui-skeleton-profile>
</div>
</div>
</div>
<!-- Cards -->
<div class="demo-subsection">
<h4>Card</h4>
<div class="demo-grid">
<div class="demo-item">
<label>Full Card</label>
<ui-skeleton-card></ui-skeleton-card>
</div>
<div class="demo-item">
<label>No Image</label>
<ui-skeleton-card [showImage]="false"></ui-skeleton-card>
</div>
<div class="demo-item">
<label>No Actions</label>
<ui-skeleton-card [showActions]="false"></ui-skeleton-card>
</div>
</div>
</div>
<!-- Article -->
<div class="demo-subsection">
<h4>Article</h4>
<div class="demo-item">
<label>Full Article</label>
<ui-skeleton-article></ui-skeleton-article>
</div>
<div class="demo-item">
<label>Article without Image</label>
<ui-skeleton-article [showImage]="false"></ui-skeleton-article>
</div>
</div>
<!-- Table Rows -->
<div class="demo-subsection">
<h4>Table Rows</h4>
<div class="demo-column">
<label>Table Skeleton (3 rows)</label>
@for (row of [1,2,3]; track row) {
<ui-skeleton-table-row [columns]="4"></ui-skeleton-table-row>
}
</div>
</div>
</section>
<!-- Custom Groups -->
<section class="demo-section">
<h3>Skeleton Groups</h3>
<div class="demo-subsection">
<h4>Vertical Group</h4>
<div class="demo-item">
<ui-skeleton-group>
<ui-skeleton-loader shape="heading" size="lg" width="w-75"></ui-skeleton-loader>
<ui-skeleton-loader shape="text" width="w-full"></ui-skeleton-loader>
<ui-skeleton-loader shape="text" width="w-50"></ui-skeleton-loader>
</ui-skeleton-group>
</div>
</div>
<div class="demo-subsection">
<h4>Horizontal Group</h4>
<div class="demo-item">
<ui-skeleton-group variant="horizontal">
<ui-skeleton-loader shape="avatar" size="md"></ui-skeleton-loader>
<ui-skeleton-loader shape="button" customWidth="100px"></ui-skeleton-loader>
<ui-skeleton-loader shape="button" customWidth="80px"></ui-skeleton-loader>
</ui-skeleton-group>
</div>
</div>
<div class="demo-subsection">
<h4>Grid Group</h4>
<div class="demo-item">
<ui-skeleton-group variant="grid">
<ui-skeleton-loader shape="card"></ui-skeleton-loader>
<ui-skeleton-loader shape="card"></ui-skeleton-loader>
<ui-skeleton-loader shape="card"></ui-skeleton-loader>
<ui-skeleton-loader shape="card"></ui-skeleton-loader>
</ui-skeleton-group>
</div>
</div>
</section>
<!-- Interactive Demo -->
<section class="demo-section">
<h3>Interactive Loading Simulation</h3>
<div class="demo-interactive">
<div class="demo-controls">
<button (click)="toggleLoading()" class="toggle-button">
{{ isLoading ? 'Show Content' : 'Show Loading' }}
</button>
<label>
Animation:
<select [(ngModel)]="selectedAnimation" (change)="onAnimationChange()">
@for (animation of animations; track animation) {
<option [value]="animation">{{ animation }}</option>
}
</select>
</label>
</div>
<div class="demo-content">
@if (isLoading) {
<!-- Loading state with selected animation -->
<ui-skeleton-article
[animation]="selectedAnimation"
[showImage]="true">
</ui-skeleton-article>
} @else {
<!-- Actual content -->
<article class="real-content">
<h3>Sample Article Title</h3>
<p class="meta">Published on January 15, 2024 by John Doe</p>
<img src="data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNDAwIiBoZWlnaHQ9IjIwMCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZGRkIi8+PHRleHQgeD0iNTAlIiB5PSI1MCUiIGZvbnQtZmFtaWx5PSJBcmlhbCwgc2Fucy1zZXJpZiIgZm9udC1zaXplPSIxNCIgZmlsbD0iIzk5OSIgdGV4dC1hbmNob3I9Im1pZGRsZSIgZHk9Ii4zZW0iPjQwMCB4IDIwMDwvdGV4dD48L3N2Zz4=" alt="Sample image" />
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
<p>Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.</p>
<p>Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.</p>
</article>
}
</div>
</div>
</section>
<!-- Best Practices -->
<section class="demo-section">
<h3>Best Practices</h3>
<div class="best-practices">
<ul>
<li><strong>Match Content Structure:</strong> Skeleton shapes should closely match the final content layout</li>
<li><strong>Use Appropriate Animations:</strong> Shimmer for fast loading, pulse for slower operations</li>
<li><strong>Respect Accessibility:</strong> Include proper ARIA labels and roles</li>
<li><strong>Consider Performance:</strong> Reduce animation complexity on low-performance devices</li>
<li><strong>Maintain Consistency:</strong> Use consistent skeleton patterns across your application</li>
</ul>
</div>
</section>
<!-- Code Examples -->
<section class="demo-section">
<h3>Code Examples</h3>
<div class="code-examples">
<div class="code-example">
<h4>Basic Skeleton</h4>
<pre><code>&lt;ui-skeleton-loader shape="text" size="md"&gt;&lt;/ui-skeleton-loader&gt;</code></pre>
</div>
<div class="code-example">
<h4>Profile Skeleton</h4>
<pre><code>&lt;ui-skeleton-profile avatarSize="lg"&gt;&lt;/ui-skeleton-profile&gt;</code></pre>
</div>
<div class="code-example">
<h4>Custom Group</h4>
<pre><code>&lt;ui-skeleton-group variant="horizontal"&gt;
&lt;ui-skeleton-loader shape="avatar" size="sm"&gt;&lt;/ui-skeleton-loader&gt;
&lt;ui-skeleton-loader shape="text" width="w-75"&gt;&lt;/ui-skeleton-loader&gt;
&lt;/ui-skeleton-group&gt;</code></pre>
</div>
</div>
</section>
</div>
`,
styleUrl: './skeleton-loader-demo.component.scss'
})
export class SkeletonLoaderDemoComponent {
sizes = ['xs', 'sm', 'md', 'lg', 'xl'] as const;
shapes = ['text', 'heading', 'avatar', 'card', 'button', 'image', 'circle', 'rounded', 'square'] as const;
animations = ['shimmer', 'pulse', 'wave'] as const;
widths = ['w-25', 'w-50', 'w-75', 'w-full'] as const;
isLoading = true;
selectedAnimation = 'shimmer' as any;
toggleLoading(): void {
this.isLoading = !this.isLoading;
}
onAnimationChange(): void {
// Force re-render by toggling loading state
if (this.isLoading) {
this.isLoading = false;
setTimeout(() => {
this.isLoading = true;
}, 50);
}
}
}