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,665 @@
import { Component, ChangeDetectionStrategy, signal } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormsModule } from '@angular/forms';
import {
RadioButtonComponent,
RadioGroupComponent,
RadioButtonData
} from '../../../../../ui-essentials/src/lib/components/forms/radio';
@Component({
selector: 'ui-radio-demo',
standalone: true,
imports: [
CommonModule,
FormsModule,
RadioButtonComponent,
RadioGroupComponent
],
changeDetection: ChangeDetectionStrategy.OnPush,
template: `
<div style="padding: 2rem;">
<h2>Radio Button Component Showcase</h2>
<!-- Basic Radio Buttons -->
<section style="margin-bottom: 3rem;">
<h3>Basic Radio Buttons</h3>
<!-- Individual Radio Buttons -->
<div style="margin-bottom: 2rem;">
<h4>Individual Radio Buttons</h4>
<div style="display: flex; flex-direction: column; gap: 1rem;">
<ui-radio-button
value="option1"
label="Option 1"
name="basic-group"
[(ngModel)]="basicSelection"
(selectionChange)="handleSelectionChange('basic', $event)"
/>
<ui-radio-button
value="option2"
label="Option 2"
name="basic-group"
[(ngModel)]="basicSelection"
(selectionChange)="handleSelectionChange('basic', $event)"
/>
<ui-radio-button
value="option3"
label="Option 3"
name="basic-group"
[(ngModel)]="basicSelection"
(selectionChange)="handleSelectionChange('basic', $event)"
/>
</div>
</div>
<!-- Radio Group -->
<div style="margin-bottom: 2rem;">
<h4>Radio Group</h4>
<ui-radio-group
label="Choose your preferred option"
[options]="basicOptions"
name="group-demo"
[(ngModel)]="groupSelection"
(selectionChange)="handleSelectionChange('group', $event)"
/>
</div>
</section>
<!-- Size Variants -->
<section style="margin-bottom: 3rem;">
<h3>Size Variants</h3>
<!-- Small -->
<div style="margin-bottom: 2rem;">
<h4>Small (sm)</h4>
<ui-radio-group
label="Small radio buttons"
size="sm"
[options]="sizeOptions"
name="small-group"
[(ngModel)]="sizeSelections['sm']"
(selectionChange)="handleSizeSelection('sm', $event)"
/>
</div>
<!-- Medium -->
<div style="margin-bottom: 2rem;">
<h4>Medium (md) - Default</h4>
<ui-radio-group
label="Medium radio buttons"
size="md"
[options]="sizeOptions"
name="medium-group"
[(ngModel)]="sizeSelections['md']"
(selectionChange)="handleSizeSelection('md', $event)"
/>
</div>
<!-- Large -->
<div style="margin-bottom: 2rem;">
<h4>Large (lg)</h4>
<ui-radio-group
label="Large radio buttons"
size="lg"
[options]="sizeOptions"
name="large-group"
[(ngModel)]="sizeSelections['lg']"
(selectionChange)="handleSizeSelection('lg', $event)"
/>
</div>
</section>
<!-- Variant Colors -->
<section style="margin-bottom: 3rem;">
<h3>Color Variants</h3>
<!-- Primary -->
<div style="margin-bottom: 2rem;">
<h4>Primary (Default)</h4>
<ui-radio-group
label="Primary variant"
variant="primary"
[options]="colorOptions"
name="primary-group"
[(ngModel)]="variantSelections['primary']"
(selectionChange)="handleVariantSelection('primary', $event)"
/>
</div>
<!-- Secondary -->
<div style="margin-bottom: 2rem;">
<h4>Secondary</h4>
<ui-radio-group
label="Secondary variant"
variant="secondary"
[options]="colorOptions"
name="secondary-group"
[(ngModel)]="variantSelections['secondary']"
(selectionChange)="handleVariantSelection('secondary', $event)"
/>
</div>
<!-- Success -->
<div style="margin-bottom: 2rem;">
<h4>Success</h4>
<ui-radio-group
label="Success variant"
variant="success"
[options]="colorOptions"
name="success-group"
[(ngModel)]="variantSelections['success']"
(selectionChange)="handleVariantSelection('success', $event)"
/>
</div>
<!-- Warning -->
<div style="margin-bottom: 2rem;">
<h4>Warning</h4>
<ui-radio-group
label="Warning variant"
variant="warning"
[options]="colorOptions"
name="warning-group"
[(ngModel)]="variantSelections['warning']"
(selectionChange)="handleVariantSelection('warning', $event)"
/>
</div>
<!-- Danger -->
<div style="margin-bottom: 2rem;">
<h4>Danger</h4>
<ui-radio-group
label="Danger variant"
variant="danger"
[options]="colorOptions"
name="danger-group"
[(ngModel)]="variantSelections['danger']"
(selectionChange)="handleVariantSelection('danger', $event)"
/>
</div>
</section>
<!-- Orientation -->
<section style="margin-bottom: 3rem;">
<h3>Orientation</h3>
<!-- Vertical -->
<div style="margin-bottom: 2rem;">
<h4>Vertical (Default)</h4>
<ui-radio-group
label="Vertical orientation"
orientation="vertical"
[options]="orientationOptions"
name="vertical-group"
[(ngModel)]="orientationSelections['vertical']"
(selectionChange)="handleOrientationSelection('vertical', $event)"
/>
</div>
<!-- Horizontal -->
<div style="margin-bottom: 2rem;">
<h4>Horizontal</h4>
<ui-radio-group
label="Horizontal orientation"
orientation="horizontal"
[options]="orientationOptions"
name="horizontal-group"
[(ngModel)]="orientationSelections['horizontal']"
(selectionChange)="handleOrientationSelection('horizontal', $event)"
/>
</div>
</section>
<!-- With Descriptions -->
<section style="margin-bottom: 3rem;">
<h3>Radio Buttons with Descriptions</h3>
<ui-radio-group
label="Choose your subscription plan"
[options]="planOptions"
name="plan-group"
[(ngModel)]="planSelection"
(selectionChange)="handleSelectionChange('plan', $event)"
/>
</section>
<!-- States -->
<section style="margin-bottom: 3rem;">
<h3>Radio Button States</h3>
<!-- Disabled Group -->
<div style="margin-bottom: 2rem;">
<h4>Disabled Group</h4>
<ui-radio-group
label="Disabled radio group"
[options]="stateOptions"
name="disabled-group"
[disabled]="true"
helperText="This entire group is disabled"
/>
</div>
<!-- Individual Disabled Options -->
<div style="margin-bottom: 2rem;">
<h4>Individual Disabled Options</h4>
<ui-radio-group
label="Some options disabled"
[options]="disabledOptions"
name="individual-disabled-group"
[(ngModel)]="disabledSelection"
(selectionChange)="handleSelectionChange('disabled', $event)"
/>
</div>
<!-- Error State -->
<div style="margin-bottom: 2rem;">
<h4>Error State</h4>
<ui-radio-group
label="Required selection"
[options]="errorOptions"
name="error-group"
[required]="true"
errorMessage="Please select an option to continue"
[(ngModel)]="errorSelection"
(selectionChange)="handleSelectionChange('error', $event)"
/>
</div>
<!-- With Helper Text -->
<div style="margin-bottom: 2rem;">
<h4>With Helper Text</h4>
<ui-radio-group
label="Notification preferences"
[options]="notificationOptions"
name="notification-group"
helperText="Choose how you'd like to receive notifications"
[(ngModel)]="notificationSelection"
(selectionChange)="handleSelectionChange('notification', $event)"
/>
</div>
</section>
<!-- Dense Layout -->
<section style="margin-bottom: 3rem;">
<h3>Dense Layout</h3>
<div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: 2rem;">
<!-- Normal Spacing -->
<div>
<h4>Normal Spacing</h4>
<ui-radio-group
label="Normal spacing"
[options]="denseOptions"
name="normal-spacing-group"
[(ngModel)]="denseSelections['normal']"
(selectionChange)="handleDenseSelection('normal', $event)"
/>
</div>
<!-- Dense Spacing -->
<div>
<h4>Dense Spacing</h4>
<ui-radio-group
label="Dense spacing"
[options]="denseOptions"
name="dense-spacing-group"
[dense]="true"
[(ngModel)]="denseSelections['dense']"
(selectionChange)="handleDenseSelection('dense', $event)"
/>
</div>
</div>
</section>
<!-- Usage Examples -->
<section style="margin-bottom: 3rem;">
<h3>Usage Examples</h3>
<div style="background: #f8f9fa; padding: 1.5rem; border-radius: 8px; border-left: 4px solid #007bff;">
<h4>Basic Radio Group:</h4>
<pre style="background: #fff; padding: 1rem; border-radius: 4px; overflow-x: auto;"><code>&lt;ui-radio-group
label="Choose an option"
[options]="options"
name="radio-group"
[(ngModel)]="selectedValue"
(selectionChange)="onSelectionChange($event)"&gt;
&lt;/ui-radio-group&gt;</code></pre>
<h4>Individual Radio Button:</h4>
<pre style="background: #fff; padding: 1rem; border-radius: 4px; overflow-x: auto;"><code>&lt;ui-radio-button
value="option1"
label="Option 1"
name="radio-name"
size="md"
variant="primary"
[(ngModel)]="selectedValue"
(selectionChange)="onSelectionChange($event)"&gt;
&lt;/ui-radio-button&gt;</code></pre>
<h4>With Descriptions:</h4>
<pre style="background: #fff; padding: 1rem; border-radius: 4px; overflow-x: auto;"><code>&lt;ui-radio-group
label="Subscription Plans"
[options]="[
{{ '{' }}
value: 'basic',
label: 'Basic Plan',
description: 'Perfect for individuals'
{{ '}' }},
{{ '{' }}
value: 'pro',
label: 'Pro Plan',
description: 'For small teams'
{{ '}' }}
]"
name="subscription"
[(ngModel)]="plan"&gt;
&lt;/ui-radio-group&gt;</code></pre>
<h4>Horizontal Layout:</h4>
<pre style="background: #fff; padding: 1rem; border-radius: 4px; overflow-x: auto;"><code>&lt;ui-radio-group
label="Payment Method"
[options]="paymentOptions"
orientation="horizontal"
name="payment"
[(ngModel)]="paymentMethod"&gt;
&lt;/ui-radio-group&gt;</code></pre>
</div>
</section>
<!-- Interactive Controls -->
<section style="margin-bottom: 3rem;">
<h3>Interactive Controls</h3>
<div style="display: flex; gap: 1rem; flex-wrap: wrap; margin-bottom: 1rem;">
<button
style="padding: 0.5rem 1rem; background: #007bff; color: white; border: none; border-radius: 4px; cursor: pointer;"
(click)="resetAllSelections()"
>
Reset All Selections
</button>
<button
style="padding: 0.5rem 1rem; background: #28a745; color: white; border: none; border-radius: 4px; cursor: pointer;"
(click)="fillSampleSelections()"
>
Fill Sample Selections
</button>
<button
style="padding: 0.5rem 1rem; background: #6f42c1; color: white; border: none; border-radius: 4px; cursor: pointer;"
(click)="toggleDisabled()"
>
{{ globalDisabled() ? 'Enable All' : 'Disable All' }}
</button>
</div>
@if (lastSelection()) {
<div style="margin-top: 1rem; padding: 1rem; background: #e3f2fd; border-radius: 4px;">
<strong>Last selection:</strong> {{ lastSelection() }}
</div>
}
</section>
<!-- Current Values -->
<section style="margin-bottom: 3rem;">
<h3>Current Values</h3>
<div style="background: #f8f9fa; padding: 1rem; border-radius: 4px; max-height: 400px; overflow-y: auto;">
<pre>{{ getCurrentValues() }}</pre>
</div>
</section>
</div>
`,
styles: [`
h2 {
color: hsl(279, 14%, 11%);
font-size: 2rem;
margin-bottom: 2rem;
border-bottom: 2px solid hsl(258, 100%, 47%);
padding-bottom: 0.5rem;
}
h3 {
color: hsl(279, 14%, 25%);
font-size: 1.5rem;
margin-bottom: 1rem;
}
h4 {
color: hsl(287, 12%, 35%);
font-size: 1.125rem;
margin-bottom: 0.75rem;
}
section {
border: 1px solid hsl(289, 14%, 90%);
border-radius: 8px;
padding: 1.5rem;
background: hsl(286, 20%, 99%);
}
pre {
font-size: 0.875rem;
line-height: 1.5;
margin: 0.5rem 0;
}
code {
font-family: 'JetBrains Mono', monospace;
color: #d63384;
}
button {
transition: all 0.2s ease-in-out;
}
button:hover {
opacity: 0.9;
transform: translateY(-1px);
}
`]
})
export class RadioDemoComponent {
// Basic selections
basicSelection = '';
groupSelection = '';
// Size selections
sizeSelections: Record<string, string> = {
'sm': '',
'md': '',
'lg': ''
};
// Variant selections
variantSelections: Record<string, string> = {
'primary': '',
'secondary': '',
'success': '',
'warning': '',
'danger': ''
};
// Orientation selections
orientationSelections: Record<string, string> = {
'vertical': '',
'horizontal': ''
};
// Other selections
planSelection = '';
disabledSelection = '';
errorSelection = '';
notificationSelection = '';
// Dense selections
denseSelections: Record<string, string> = {
'normal': '',
'dense': ''
};
// Signals for reactive state
lastSelection = signal<string>('');
globalDisabled = signal<boolean>(false);
// Option data
basicOptions: RadioButtonData[] = [
{ value: 'basic1', label: 'Basic Option 1' },
{ value: 'basic2', label: 'Basic Option 2' },
{ value: 'basic3', label: 'Basic Option 3' }
];
sizeOptions: RadioButtonData[] = [
{ value: 'size1', label: 'First Choice' },
{ value: 'size2', label: 'Second Choice' },
{ value: 'size3', label: 'Third Choice' }
];
colorOptions: RadioButtonData[] = [
{ value: 'color1', label: 'Red' },
{ value: 'color2', label: 'Blue' },
{ value: 'color3', label: 'Green' }
];
orientationOptions: RadioButtonData[] = [
{ value: 'orient1', label: 'Option A' },
{ value: 'orient2', label: 'Option B' },
{ value: 'orient3', label: 'Option C' },
{ value: 'orient4', label: 'Option D' }
];
planOptions: RadioButtonData[] = [
{
value: 'basic',
label: 'Basic Plan',
description: 'Perfect for individuals and small projects. Includes 5GB storage and basic support.'
},
{
value: 'pro',
label: 'Professional Plan',
description: 'Great for small teams. Includes 50GB storage, priority support, and advanced features.'
},
{
value: 'enterprise',
label: 'Enterprise Plan',
description: 'For large organizations. Unlimited storage, 24/7 support, and custom integrations.'
}
];
stateOptions: RadioButtonData[] = [
{ value: 'state1', label: 'Option 1' },
{ value: 'state2', label: 'Option 2' },
{ value: 'state3', label: 'Option 3' }
];
disabledOptions: RadioButtonData[] = [
{ value: 'available1', label: 'Available Option 1' },
{ value: 'disabled1', label: 'Disabled Option', disabled: true },
{ value: 'available2', label: 'Available Option 2' },
{ value: 'disabled2', label: 'Another Disabled Option', disabled: true }
];
errorOptions: RadioButtonData[] = [
{ value: 'error1', label: 'Option 1' },
{ value: 'error2', label: 'Option 2' },
{ value: 'error3', label: 'Option 3' }
];
notificationOptions: RadioButtonData[] = [
{ value: 'email', label: 'Email notifications' },
{ value: 'sms', label: 'SMS notifications' },
{ value: 'push', label: 'Push notifications' },
{ value: 'none', label: 'No notifications' }
];
denseOptions: RadioButtonData[] = [
{ value: 'dense1', label: 'Compact Option 1' },
{ value: 'dense2', label: 'Compact Option 2' },
{ value: 'dense3', label: 'Compact Option 3' },
{ value: 'dense4', label: 'Compact Option 4' }
];
handleSelectionChange(group: string, value: string): void {
this.lastSelection.set(`${group}: ${value}`);
console.log(`Selection changed in ${group}: ${value}`);
}
handleSizeSelection(size: string, value: string): void {
this.sizeSelections[size] = value;
this.handleSelectionChange(`size-${size}`, value);
}
handleVariantSelection(variant: string, value: string): void {
this.variantSelections[variant] = value;
this.handleSelectionChange(`variant-${variant}`, value);
}
handleOrientationSelection(orientation: string, value: string): void {
this.orientationSelections[orientation] = value;
this.handleSelectionChange(`orientation-${orientation}`, value);
}
handleDenseSelection(type: string, value: string): void {
this.denseSelections[type] = value;
this.handleSelectionChange(`dense-${type}`, value);
}
resetAllSelections(): void {
this.basicSelection = '';
this.groupSelection = '';
this.planSelection = '';
this.disabledSelection = '';
this.errorSelection = '';
this.notificationSelection = '';
Object.keys(this.sizeSelections).forEach(key => {
this.sizeSelections[key] = '';
});
Object.keys(this.variantSelections).forEach(key => {
this.variantSelections[key] = '';
});
Object.keys(this.orientationSelections).forEach(key => {
this.orientationSelections[key] = '';
});
Object.keys(this.denseSelections).forEach(key => {
this.denseSelections[key] = '';
});
this.lastSelection.set('All selections reset');
console.log('All selections reset');
}
fillSampleSelections(): void {
this.basicSelection = 'option2';
this.groupSelection = 'basic2';
this.planSelection = 'pro';
this.notificationSelection = 'email';
this.sizeSelections['md'] = 'size2';
this.variantSelections['primary'] = 'color1';
this.orientationSelections['horizontal'] = 'orient3';
this.denseSelections['dense'] = 'dense2';
this.lastSelection.set('Sample selections filled');
console.log('Sample selections filled');
}
toggleDisabled(): void {
this.globalDisabled.set(!this.globalDisabled());
this.lastSelection.set(`All controls ${this.globalDisabled() ? 'disabled' : 'enabled'}`);
console.log(`Global disabled state: ${this.globalDisabled()}`);
}
getCurrentValues(): string {
const values = {
basic: this.basicSelection,
group: this.groupSelection,
plan: this.planSelection,
disabled: this.disabledSelection,
error: this.errorSelection,
notification: this.notificationSelection,
sizes: this.sizeSelections,
variants: this.variantSelections,
orientations: this.orientationSelections,
dense: this.denseSelections
};
return JSON.stringify(values, null, 2);
}
}