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:
@@ -0,0 +1,152 @@
|
||||
.demo-container {
|
||||
padding: 2rem;
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
|
||||
h2 {
|
||||
margin-bottom: 1.5rem;
|
||||
font-size: 1.875rem;
|
||||
}
|
||||
}
|
||||
|
||||
.demo-section {
|
||||
margin-bottom: 3rem;
|
||||
|
||||
h3 {
|
||||
margin-bottom: 1rem;
|
||||
font-size: 1.25rem;
|
||||
border-bottom: 1px solid #e5e7eb;
|
||||
padding-bottom: 0.5rem;
|
||||
}
|
||||
}
|
||||
|
||||
.demo-row {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
|
||||
gap: 1.5rem;
|
||||
}
|
||||
|
||||
.demo-item {
|
||||
h4 {
|
||||
margin-bottom: 0.75rem;
|
||||
font-size: 1rem;
|
||||
font-weight: 500;
|
||||
color: #6b7280;
|
||||
}
|
||||
}
|
||||
|
||||
.demo-interactive {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: 1.5rem;
|
||||
padding: 1.5rem;
|
||||
border: 1px solid #e5e7eb;
|
||||
border-radius: 0.5rem;
|
||||
background: #f9fafb;
|
||||
}
|
||||
|
||||
.demo-output {
|
||||
h4 {
|
||||
margin-bottom: 0.5rem;
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
p {
|
||||
color: #6b7280;
|
||||
margin-bottom: 0.25rem;
|
||||
font-size: 0.875rem;
|
||||
}
|
||||
}
|
||||
|
||||
.demo-form {
|
||||
padding: 1.5rem;
|
||||
border: 1px solid #e5e7eb;
|
||||
border-radius: 0.5rem;
|
||||
background: #ffffff;
|
||||
}
|
||||
|
||||
.form-row {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: 1.5rem;
|
||||
margin-bottom: 1.5rem;
|
||||
}
|
||||
|
||||
.form-actions {
|
||||
display: flex;
|
||||
gap: 0.75rem;
|
||||
margin-bottom: 1.5rem;
|
||||
}
|
||||
|
||||
.submit-btn, .reset-btn {
|
||||
padding: 0.5rem 1rem;
|
||||
border-radius: 0.375rem;
|
||||
font-size: 0.875rem;
|
||||
font-weight: 500;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
.submit-btn {
|
||||
background: #3b82f6;
|
||||
color: white;
|
||||
border: 1px solid #3b82f6;
|
||||
|
||||
&:hover:not(:disabled) {
|
||||
background: #2563eb;
|
||||
border-color: #2563eb;
|
||||
}
|
||||
|
||||
&:disabled {
|
||||
opacity: 0.6;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
}
|
||||
|
||||
.reset-btn {
|
||||
background: transparent;
|
||||
color: #6b7280;
|
||||
border: 1px solid #d1d5db;
|
||||
|
||||
&:hover {
|
||||
background: #f3f4f6;
|
||||
color: #374151;
|
||||
}
|
||||
}
|
||||
|
||||
.form-status {
|
||||
background: #f3f4f6;
|
||||
padding: 0.75rem;
|
||||
border-radius: 0.375rem;
|
||||
|
||||
p {
|
||||
margin-bottom: 0.5rem;
|
||||
font-size: 0.875rem;
|
||||
|
||||
&:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
pre {
|
||||
background: #e5e7eb;
|
||||
padding: 0.5rem;
|
||||
border-radius: 0.25rem;
|
||||
font-size: 0.75rem;
|
||||
overflow-x: auto;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.demo-row {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.demo-interactive {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.form-row {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,394 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { FormsModule } from '@angular/forms';
|
||||
import { TimePickerComponent, TimeValue } from '../../../../../ui-essentials/src/lib/components/forms/time-picker/time-picker.component';
|
||||
|
||||
@Component({
|
||||
selector: 'ui-time-picker-demo',
|
||||
standalone: true,
|
||||
imports: [CommonModule, FormsModule, TimePickerComponent],
|
||||
template: `
|
||||
<div class="demo-container">
|
||||
<h2>Time Picker Demo</h2>
|
||||
|
||||
<!-- Size Variants -->
|
||||
<section class="demo-section">
|
||||
<h3>Sizes</h3>
|
||||
<div class="demo-row">
|
||||
@for (size of sizes; track size) {
|
||||
<div class="demo-item">
|
||||
<h4>{{ size | uppercase }}</h4>
|
||||
<ui-time-picker
|
||||
[size]="size"
|
||||
[label]="size + ' Time Picker'"
|
||||
[placeholder]="'Select time'"
|
||||
[(ngModel)]="sampleValues[size]">
|
||||
</ui-time-picker>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Variant Styles -->
|
||||
<section class="demo-section">
|
||||
<h3>Variants</h3>
|
||||
<div class="demo-row">
|
||||
@for (variant of variants; track variant) {
|
||||
<div class="demo-item">
|
||||
<h4>{{ variant | titlecase }}</h4>
|
||||
<ui-time-picker
|
||||
[variant]="variant"
|
||||
[label]="variant + ' Variant'"
|
||||
[placeholder]="'Select time'"
|
||||
[(ngModel)]="variantValues[variant]">
|
||||
</ui-time-picker>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Time Formats -->
|
||||
<section class="demo-section">
|
||||
<h3>Time Formats</h3>
|
||||
<div class="demo-row">
|
||||
<div class="demo-item">
|
||||
<h4>12-Hour Format</h4>
|
||||
<ui-time-picker
|
||||
label="12-Hour Time"
|
||||
placeholder="Select time"
|
||||
timeFormat="12"
|
||||
helperText="Uses AM/PM format"
|
||||
[(ngModel)]="formatValues['twelve']">
|
||||
</ui-time-picker>
|
||||
</div>
|
||||
|
||||
<div class="demo-item">
|
||||
<h4>24-Hour Format</h4>
|
||||
<ui-time-picker
|
||||
label="24-Hour Time"
|
||||
placeholder="Select time"
|
||||
timeFormat="24"
|
||||
helperText="Military time format"
|
||||
[(ngModel)]="formatValues['twentyFour']">
|
||||
</ui-time-picker>
|
||||
</div>
|
||||
|
||||
<div class="demo-item">
|
||||
<h4>With Seconds</h4>
|
||||
<ui-time-picker
|
||||
label="Time with Seconds"
|
||||
placeholder="Select time"
|
||||
[showSeconds]="true"
|
||||
helperText="Includes seconds picker"
|
||||
[(ngModel)]="formatValues['withSeconds']">
|
||||
</ui-time-picker>
|
||||
</div>
|
||||
|
||||
<div class="demo-item">
|
||||
<h4>Custom Steps</h4>
|
||||
<ui-time-picker
|
||||
label="Custom Minute Steps"
|
||||
placeholder="Select time"
|
||||
[minuteStep]="15"
|
||||
[secondStep]="30"
|
||||
[showSeconds]="true"
|
||||
helperText="15-minute and 30-second steps"
|
||||
[(ngModel)]="formatValues['customSteps']">
|
||||
</ui-time-picker>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- States -->
|
||||
<section class="demo-section">
|
||||
<h3>States</h3>
|
||||
<div class="demo-row">
|
||||
<div class="demo-item">
|
||||
<h4>Default</h4>
|
||||
<ui-time-picker
|
||||
label="Default State"
|
||||
placeholder="Select time"
|
||||
helperText="Choose your preferred time"
|
||||
[(ngModel)]="stateValues['default']">
|
||||
</ui-time-picker>
|
||||
</div>
|
||||
|
||||
<div class="demo-item">
|
||||
<h4>Error</h4>
|
||||
<ui-time-picker
|
||||
label="Error State"
|
||||
placeholder="Select time"
|
||||
state="error"
|
||||
errorMessage="Please select a valid time"
|
||||
[(ngModel)]="stateValues['error']">
|
||||
</ui-time-picker>
|
||||
</div>
|
||||
|
||||
<div class="demo-item">
|
||||
<h4>Success</h4>
|
||||
<ui-time-picker
|
||||
label="Success State"
|
||||
placeholder="Select time"
|
||||
state="success"
|
||||
helperText="Perfect timing!"
|
||||
[(ngModel)]="stateValues['success']">
|
||||
</ui-time-picker>
|
||||
</div>
|
||||
|
||||
<div class="demo-item">
|
||||
<h4>Warning</h4>
|
||||
<ui-time-picker
|
||||
label="Warning State"
|
||||
placeholder="Select time"
|
||||
state="warning"
|
||||
helperText="Time is outside business hours"
|
||||
[(ngModel)]="stateValues['warning']">
|
||||
</ui-time-picker>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Special Features -->
|
||||
<section class="demo-section">
|
||||
<h3>Features</h3>
|
||||
<div class="demo-row">
|
||||
<div class="demo-item">
|
||||
<h4>Required Field</h4>
|
||||
<ui-time-picker
|
||||
label="Required Time"
|
||||
placeholder="Select time"
|
||||
[required]="true"
|
||||
helperText="This field is required"
|
||||
[(ngModel)]="featureValues['required']">
|
||||
</ui-time-picker>
|
||||
</div>
|
||||
|
||||
<div class="demo-item">
|
||||
<h4>Disabled</h4>
|
||||
<ui-time-picker
|
||||
label="Disabled Time Picker"
|
||||
placeholder="Cannot select"
|
||||
[disabled]="true"
|
||||
helperText="This field is disabled"
|
||||
[(ngModel)]="featureValues['disabled']">
|
||||
</ui-time-picker>
|
||||
</div>
|
||||
|
||||
<div class="demo-item">
|
||||
<h4>Not Clearable</h4>
|
||||
<ui-time-picker
|
||||
label="No Clear Button"
|
||||
placeholder="Select time"
|
||||
[clearable]="false"
|
||||
helperText="Clear button is hidden"
|
||||
[(ngModel)]="featureValues['notClearable']">
|
||||
</ui-time-picker>
|
||||
</div>
|
||||
|
||||
<div class="demo-item">
|
||||
<h4>With Presets</h4>
|
||||
<ui-time-picker
|
||||
label="Quick Time Selection"
|
||||
placeholder="Select time"
|
||||
[presetTimes]="presetTimes"
|
||||
helperText="Includes common time presets"
|
||||
[(ngModel)]="featureValues['presets']">
|
||||
</ui-time-picker>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Interactive Example -->
|
||||
<section class="demo-section">
|
||||
<h3>Interactive Example</h3>
|
||||
<div class="demo-interactive">
|
||||
<ui-time-picker
|
||||
label="Meeting Time"
|
||||
placeholder="Select meeting time"
|
||||
helperText="Choose a time for your meeting"
|
||||
[showSeconds]="true"
|
||||
[(ngModel)]="interactiveValue"
|
||||
(timeChange)="onTimeChange($event)">
|
||||
</ui-time-picker>
|
||||
|
||||
<div class="demo-output">
|
||||
<h4>Selected Time:</h4>
|
||||
<p>{{ interactiveValue ? formatTime(interactiveValue) : 'No time selected' }}</p>
|
||||
<p><strong>24-hour format:</strong> {{ interactiveValue ? format24Hour(interactiveValue) : 'N/A' }}</p>
|
||||
<p><strong>Change count:</strong> {{ changeCount }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Form Integration -->
|
||||
<section class="demo-section">
|
||||
<h3>Form Integration</h3>
|
||||
<form (ngSubmit)="onSubmit()" #demoForm="ngForm" class="demo-form">
|
||||
<div class="form-row">
|
||||
<ui-time-picker
|
||||
label="Start Time"
|
||||
name="startTime"
|
||||
placeholder="Select start time"
|
||||
[(ngModel)]="formValues.startTime"
|
||||
[required]="true"
|
||||
#startTime="ngModel">
|
||||
</ui-time-picker>
|
||||
|
||||
<ui-time-picker
|
||||
label="End Time"
|
||||
name="endTime"
|
||||
placeholder="Select end time"
|
||||
[(ngModel)]="formValues.endTime"
|
||||
[required]="true"
|
||||
#endTime="ngModel">
|
||||
</ui-time-picker>
|
||||
</div>
|
||||
|
||||
<div class="form-row">
|
||||
<ui-time-picker
|
||||
label="Break Time"
|
||||
name="breakTime"
|
||||
placeholder="Select break time"
|
||||
[presetTimes]="breakPresets"
|
||||
[(ngModel)]="formValues.breakTime"
|
||||
#breakTime="ngModel">
|
||||
</ui-time-picker>
|
||||
|
||||
<ui-time-picker
|
||||
label="Meeting Duration"
|
||||
name="duration"
|
||||
placeholder="Select duration"
|
||||
[showSeconds]="true"
|
||||
[minuteStep]="15"
|
||||
[(ngModel)]="formValues.duration"
|
||||
#duration="ngModel">
|
||||
</ui-time-picker>
|
||||
</div>
|
||||
|
||||
<div class="form-actions">
|
||||
<button type="submit" [disabled]="!demoForm.valid" class="submit-btn">
|
||||
Submit Form
|
||||
</button>
|
||||
<button type="button" (click)="resetForm(demoForm)" class="reset-btn">
|
||||
Reset
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="form-status">
|
||||
<p><strong>Form Valid:</strong> {{ demoForm.valid }}</p>
|
||||
<p><strong>Form Values:</strong></p>
|
||||
<pre>{{ formValues | json }}</pre>
|
||||
</div>
|
||||
</form>
|
||||
</section>
|
||||
</div>
|
||||
`,
|
||||
styleUrl: './time-picker-demo.component.scss'
|
||||
})
|
||||
export class TimePickerDemoComponent {
|
||||
sizes = ['sm', 'md', 'lg'] as const;
|
||||
variants = ['outlined', 'filled', 'underlined'] as const;
|
||||
|
||||
sampleValues: Record<string, TimeValue | null> = {
|
||||
sm: null,
|
||||
md: null,
|
||||
lg: null
|
||||
};
|
||||
|
||||
variantValues: Record<string, TimeValue | null> = {
|
||||
outlined: null,
|
||||
filled: null,
|
||||
underlined: null
|
||||
};
|
||||
|
||||
formatValues: Record<string, TimeValue | null> = {
|
||||
twelve: null,
|
||||
twentyFour: null,
|
||||
withSeconds: null,
|
||||
customSteps: null
|
||||
};
|
||||
|
||||
stateValues: Record<string, TimeValue | null> = {
|
||||
default: null,
|
||||
error: null,
|
||||
success: { hours: 9, minutes: 30, seconds: 0 },
|
||||
warning: null
|
||||
};
|
||||
|
||||
featureValues: Record<string, TimeValue | null> = {
|
||||
required: null,
|
||||
disabled: { hours: 12, minutes: 0, seconds: 0 },
|
||||
notClearable: null,
|
||||
presets: null
|
||||
};
|
||||
|
||||
interactiveValue: TimeValue | null = null;
|
||||
changeCount = 0;
|
||||
|
||||
formValues = {
|
||||
startTime: null as TimeValue | null,
|
||||
endTime: null as TimeValue | null,
|
||||
breakTime: null as TimeValue | null,
|
||||
duration: null as TimeValue | null
|
||||
};
|
||||
|
||||
// Preset times for demo
|
||||
presetTimes = [
|
||||
{ label: '9:00 AM', value: { hours: 9, minutes: 0, seconds: 0 } },
|
||||
{ label: '12:00 PM', value: { hours: 12, minutes: 0, seconds: 0 } },
|
||||
{ label: '1:00 PM', value: { hours: 13, minutes: 0, seconds: 0 } },
|
||||
{ label: '5:00 PM', value: { hours: 17, minutes: 0, seconds: 0 } }
|
||||
];
|
||||
|
||||
breakPresets = [
|
||||
{ label: '15 min', value: { hours: 0, minutes: 15, seconds: 0 } },
|
||||
{ label: '30 min', value: { hours: 0, minutes: 30, seconds: 0 } },
|
||||
{ label: '1 hour', value: { hours: 1, minutes: 0, seconds: 0 } }
|
||||
];
|
||||
|
||||
onTimeChange(time: TimeValue | null): void {
|
||||
this.changeCount++;
|
||||
console.log('Time changed:', time);
|
||||
}
|
||||
|
||||
onSubmit(): void {
|
||||
console.log('Form submitted:', this.formValues);
|
||||
alert('Form submitted! Check console for values.');
|
||||
}
|
||||
|
||||
resetForm(form: any): void {
|
||||
form.resetForm();
|
||||
this.formValues = {
|
||||
startTime: null,
|
||||
endTime: null,
|
||||
breakTime: null,
|
||||
duration: null
|
||||
};
|
||||
}
|
||||
|
||||
formatTime(time: TimeValue): string {
|
||||
const hours = time.hours;
|
||||
const displayHour = hours === 0 ? 12 : hours > 12 ? hours - 12 : hours;
|
||||
const period = hours >= 12 ? 'PM' : 'AM';
|
||||
const minutes = time.minutes.toString().padStart(2, '0');
|
||||
|
||||
if (time.seconds !== undefined && time.seconds > 0) {
|
||||
const seconds = time.seconds.toString().padStart(2, '0');
|
||||
return `${displayHour}:${minutes}:${seconds} ${period}`;
|
||||
}
|
||||
|
||||
return `${displayHour}:${minutes} ${period}`;
|
||||
}
|
||||
|
||||
format24Hour(time: TimeValue): string {
|
||||
const hours = time.hours.toString().padStart(2, '0');
|
||||
const minutes = time.minutes.toString().padStart(2, '0');
|
||||
|
||||
if (time.seconds !== undefined && time.seconds > 0) {
|
||||
const seconds = time.seconds.toString().padStart(2, '0');
|
||||
return `${hours}:${minutes}:${seconds}`;
|
||||
}
|
||||
|
||||
return `${hours}:${minutes}`;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user