wally-ui 1.14.1 → 1.16.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (62) hide show
  1. package/dist/cli.js +0 -0
  2. package/package.json +1 -1
  3. package/playground/showcase/public/sitemap.xml +15 -0
  4. package/playground/showcase/src/app/app.routes.server.ts +8 -0
  5. package/playground/showcase/src/app/components/ai/ai-composer/ai-composer.html +11 -2
  6. package/playground/showcase/src/app/components/ai/ai-composer/ai-composer.ts +13 -3
  7. package/playground/showcase/src/app/components/audio-waveform/audio-waveform.css +0 -0
  8. package/playground/showcase/src/app/components/audio-waveform/audio-waveform.html +41 -0
  9. package/playground/showcase/src/app/components/audio-waveform/audio-waveform.service.spec.ts +16 -0
  10. package/playground/showcase/src/app/components/audio-waveform/audio-waveform.service.ts +175 -0
  11. package/playground/showcase/src/app/components/audio-waveform/audio-waveform.spec.ts +23 -0
  12. package/playground/showcase/src/app/components/audio-waveform/audio-waveform.ts +64 -0
  13. package/playground/showcase/src/app/components/combobox/combobox-content/combobox-content.css +0 -0
  14. package/playground/showcase/src/app/components/combobox/combobox-content/combobox-content.html +41 -0
  15. package/playground/showcase/src/app/components/combobox/combobox-content/combobox-content.spec.ts +228 -0
  16. package/playground/showcase/src/app/components/combobox/combobox-content/combobox-content.ts +217 -0
  17. package/playground/showcase/src/app/components/combobox/combobox-empty/combobox-empty.css +0 -0
  18. package/playground/showcase/src/app/components/combobox/combobox-empty/combobox-empty.html +3 -0
  19. package/playground/showcase/src/app/components/combobox/combobox-empty/combobox-empty.spec.ts +56 -0
  20. package/playground/showcase/src/app/components/combobox/combobox-empty/combobox-empty.ts +11 -0
  21. package/playground/showcase/src/app/components/combobox/combobox-group/combobox-group.css +0 -0
  22. package/playground/showcase/src/app/components/combobox/combobox-group/combobox-group.html +11 -0
  23. package/playground/showcase/src/app/components/combobox/combobox-group/combobox-group.spec.ts +57 -0
  24. package/playground/showcase/src/app/components/combobox/combobox-group/combobox-group.ts +11 -0
  25. package/playground/showcase/src/app/components/combobox/combobox-input/combobox-input.css +0 -0
  26. package/playground/showcase/src/app/components/combobox/combobox-input/combobox-input.html +71 -0
  27. package/playground/showcase/src/app/components/combobox/combobox-input/combobox-input.spec.ts +468 -0
  28. package/playground/showcase/src/app/components/combobox/combobox-input/combobox-input.ts +90 -0
  29. package/playground/showcase/src/app/components/combobox/combobox-item/combobox-item.css +0 -0
  30. package/playground/showcase/src/app/components/combobox/combobox-item/combobox-item.html +58 -0
  31. package/playground/showcase/src/app/components/combobox/combobox-item/combobox-item.spec.ts +173 -0
  32. package/playground/showcase/src/app/components/combobox/combobox-item/combobox-item.ts +37 -0
  33. package/playground/showcase/src/app/components/combobox/combobox-search/combobox-search.css +0 -0
  34. package/playground/showcase/src/app/components/combobox/combobox-search/combobox-search.html +11 -0
  35. package/playground/showcase/src/app/components/combobox/combobox-search/combobox-search.spec.ts +166 -0
  36. package/playground/showcase/src/app/components/combobox/combobox-search/combobox-search.ts +36 -0
  37. package/playground/showcase/src/app/components/combobox/combobox-trigger/combobox-trigger.css +0 -0
  38. package/playground/showcase/src/app/components/combobox/combobox-trigger/combobox-trigger.html +8 -0
  39. package/playground/showcase/src/app/components/combobox/combobox-trigger/combobox-trigger.spec.ts +137 -0
  40. package/playground/showcase/src/app/components/combobox/combobox-trigger/combobox-trigger.ts +30 -0
  41. package/playground/showcase/src/app/components/combobox/combobox.css +0 -0
  42. package/playground/showcase/src/app/components/combobox/combobox.html +3 -0
  43. package/playground/showcase/src/app/components/combobox/combobox.spec.ts +391 -0
  44. package/playground/showcase/src/app/components/combobox/combobox.ts +59 -0
  45. package/playground/showcase/src/app/components/combobox/lib/models/combobox.model.ts +13 -0
  46. package/playground/showcase/src/app/components/combobox/lib/service/combobox.service.spec.ts +530 -0
  47. package/playground/showcase/src/app/components/combobox/lib/service/combobox.service.ts +191 -0
  48. package/playground/showcase/src/app/components/combobox/lib/types/combobox-position.type.ts +1 -0
  49. package/playground/showcase/src/app/components/combobox/lib/types/combobox-trigger-mode.type.ts +1 -0
  50. package/playground/showcase/src/app/core/services/seo.service.ts +100 -0
  51. package/playground/showcase/src/app/pages/documentation/components/audio-waveform-docs/audio-waveform-docs.css +1 -0
  52. package/playground/showcase/src/app/pages/documentation/components/audio-waveform-docs/audio-waveform-docs.examples.ts +146 -0
  53. package/playground/showcase/src/app/pages/documentation/components/audio-waveform-docs/audio-waveform-docs.html +576 -0
  54. package/playground/showcase/src/app/pages/documentation/components/audio-waveform-docs/audio-waveform-docs.ts +124 -0
  55. package/playground/showcase/src/app/pages/documentation/components/combobox-docs/combobox-docs.component.css +0 -0
  56. package/playground/showcase/src/app/pages/documentation/components/combobox-docs/combobox-docs.component.html +383 -0
  57. package/playground/showcase/src/app/pages/documentation/components/combobox-docs/combobox-docs.component.spec.ts +23 -0
  58. package/playground/showcase/src/app/pages/documentation/components/combobox-docs/combobox-docs.component.ts +333 -0
  59. package/playground/showcase/src/app/pages/documentation/components/combobox-docs/combobox-docs.examples.ts +226 -0
  60. package/playground/showcase/src/app/pages/documentation/components/components.html +27 -0
  61. package/playground/showcase/src/app/pages/documentation/components/components.routes.ts +8 -0
  62. package/playground/showcase/src/app/pages/home/home.html +1 -1
@@ -0,0 +1 @@
1
+ export type ComboboxPosition = 'bottom' | 'top' | 'left' | 'right';
@@ -0,0 +1 @@
1
+ export type ComboboxTriggerMode = 'input' | 'custom';
@@ -0,0 +1,100 @@
1
+ import { Injectable, inject, PLATFORM_ID } from '@angular/core';
2
+ import { isPlatformBrowser, DOCUMENT } from '@angular/common';
3
+ import { Meta, Title } from '@angular/platform-browser';
4
+
5
+ export interface SeoConfig {
6
+ title: string;
7
+ description: string;
8
+ url?: string;
9
+ image?: string;
10
+ keywords?: string;
11
+ type?: 'website' | 'article';
12
+ }
13
+
14
+ @Injectable({
15
+ providedIn: 'root'
16
+ })
17
+ export class SeoService {
18
+ private meta = inject(Meta);
19
+ private titleService = inject(Title);
20
+ private platformId = inject(PLATFORM_ID);
21
+ private document = inject(DOCUMENT);
22
+
23
+ private readonly baseUrl = 'https://wally-ui.com';
24
+ private readonly defaultImage = 'https://wally-ui.com/assets/og-image.png';
25
+
26
+ /**
27
+ * Updates all SEO meta tags for the current page
28
+ */
29
+ updateTags(config: SeoConfig): void {
30
+ const {
31
+ title,
32
+ description,
33
+ url = '',
34
+ image = this.defaultImage,
35
+ keywords = 'Angular, TypeScript, UI Components, Design System, Open Source',
36
+ type = 'website'
37
+ } = config;
38
+
39
+ const fullTitle = `${title} - Wally UI`;
40
+ const fullUrl = `${this.baseUrl}${url}`;
41
+
42
+ // Update page title
43
+ this.titleService.setTitle(fullTitle);
44
+
45
+ // Update or create meta tags
46
+ this.meta.updateTag({ name: 'description', content: description });
47
+ this.meta.updateTag({ name: 'keywords', content: keywords });
48
+
49
+ // Open Graph tags
50
+ this.meta.updateTag({ property: 'og:title', content: fullTitle });
51
+ this.meta.updateTag({ property: 'og:description', content: description });
52
+ this.meta.updateTag({ property: 'og:url', content: fullUrl });
53
+ this.meta.updateTag({ property: 'og:image', content: image });
54
+ this.meta.updateTag({ property: 'og:type', content: type });
55
+
56
+ // Twitter Card tags
57
+ this.meta.updateTag({ name: 'twitter:card', content: 'summary_large_image' });
58
+ this.meta.updateTag({ name: 'twitter:title', content: fullTitle });
59
+ this.meta.updateTag({ name: 'twitter:description', content: description });
60
+ this.meta.updateTag({ name: 'twitter:image', content: image });
61
+
62
+ // Canonical URL
63
+ this.updateCanonicalUrl(fullUrl);
64
+ }
65
+
66
+ /**
67
+ * Updates or creates canonical link tag (browser only)
68
+ */
69
+ private updateCanonicalUrl(url: string): void {
70
+ if (!isPlatformBrowser(this.platformId)) {
71
+ return;
72
+ }
73
+
74
+ let link: HTMLLinkElement | null = this.document.querySelector('link[rel="canonical"]');
75
+
76
+ if (!link) {
77
+ link = this.document.createElement('link');
78
+ link.setAttribute('rel', 'canonical');
79
+ this.document.head.appendChild(link);
80
+ }
81
+
82
+ link.setAttribute('href', url);
83
+ }
84
+
85
+ /**
86
+ * Removes all dynamic meta tags (useful for cleanup)
87
+ */
88
+ clearTags(): void {
89
+ this.meta.removeTag('name="description"');
90
+ this.meta.removeTag('name="keywords"');
91
+ this.meta.removeTag('property="og:title"');
92
+ this.meta.removeTag('property="og:description"');
93
+ this.meta.removeTag('property="og:url"');
94
+ this.meta.removeTag('property="og:image"');
95
+ this.meta.removeTag('name="twitter:card"');
96
+ this.meta.removeTag('name="twitter:title"');
97
+ this.meta.removeTag('name="twitter:description"');
98
+ this.meta.removeTag('name="twitter:image"');
99
+ }
100
+ }
@@ -0,0 +1,146 @@
1
+ // Audio Waveform documentation code examples
2
+ export const AudioWaveformCodeExamples = {
3
+ // Installation
4
+ installation: `npx wally-ui add audio-waveform`,
5
+
6
+ // Import examples
7
+ import: `import { AudioWaveform } from './components/wally-ui/audio-waveform/audio-waveform';
8
+ import { AudioWaveformService } from './components/wally-ui/audio-waveform/audio-waveform.service';`,
9
+
10
+ componentImport: `@Component({
11
+ selector: 'app-example',
12
+ imports: [AudioWaveform],
13
+ templateUrl: './example.html'
14
+ })`,
15
+
16
+ // Basic usage
17
+ basicUsage: `<wally-audio-waveform
18
+ [isStartRecording]="isRecording()"
19
+ [isStopRecording]="!isRecording()">
20
+ </wally-audio-waveform>`,
21
+
22
+ // With timer
23
+ withTimer: `<wally-audio-waveform
24
+ [isStartRecording]="isRecording()"
25
+ [isStopRecording]="!isRecording()"
26
+ [showTimer]="true">
27
+ </wally-audio-waveform>`,
28
+
29
+ // Complete Example with Controls
30
+ completeExample: `<div class="flex flex-col gap-4">
31
+ <!-- Waveform Visualizer -->
32
+ <wally-audio-waveform
33
+ [isStartRecording]="isRecording()"
34
+ [isStopRecording]="!isRecording()"
35
+ [showTimer]="true">
36
+ </wally-audio-waveform>
37
+
38
+ <!-- Recording Controls -->
39
+ <div class="flex gap-2">
40
+ @if (!isRecording()) {
41
+ <button (click)="startRecording()"
42
+ class="px-4 py-2 bg-red-500 text-white rounded-full">
43
+ Start Recording
44
+ </button>
45
+ } @else {
46
+ <button (click)="stopRecording()"
47
+ class="px-4 py-2 bg-neutral-500 text-white rounded-full">
48
+ Stop Recording
49
+ </button>
50
+ }
51
+ </div>
52
+ </div>`,
53
+
54
+ completeExampleTs: `export class RecordingComponent {
55
+ isRecording = signal(false);
56
+
57
+ startRecording() {
58
+ this.isRecording.set(true);
59
+ }
60
+
61
+ stopRecording() {
62
+ this.isRecording.set(false);
63
+ }
64
+ }`,
65
+
66
+ // Service Integration
67
+ serviceIntegration: `// Access the service to get recorded audio
68
+ export class RecordingComponent {
69
+ @ViewChild(AudioWaveform) audioWaveform!: AudioWaveform;
70
+
71
+ downloadRecording() {
72
+ const service = this.audioWaveform.audioWaveformService;
73
+ service.downloadRecording('my-recording.webm');
74
+ }
75
+
76
+ getRecordedBlob() {
77
+ const service = this.audioWaveform.audioWaveformService;
78
+ const blob = service.recordedAudioBlob();
79
+ return blob;
80
+ }
81
+
82
+ clearRecording() {
83
+ const service = this.audioWaveform.audioWaveformService;
84
+ service.clearRecording();
85
+ }
86
+ }`,
87
+
88
+ // Responsive Configuration
89
+ responsiveConfig: `// Service Configuration (auto-responsive)
90
+ // Mobile (< 768px): 30 bars
91
+ // Desktop (>= 768px): 65 bars
92
+ // Automatically adjusts based on screen width`,
93
+
94
+ // Future: Audio Transcription
95
+ futureTranscription: `// COMING SOON: Audio Transcription
96
+ // The component will support automatic transcription in a future release
97
+
98
+ <wally-audio-waveform
99
+ [isStartRecording]="isRecording()"
100
+ [isStopRecording]="!isRecording()"
101
+ [enableTranscription]="true"
102
+ (transcriptionComplete)="onTranscription($event)">
103
+ </wally-audio-waveform>`,
104
+
105
+ // Web Audio API Concepts
106
+ webAudioConcepts: `// How it works under the hood:
107
+ // 1. getUserMedia() - Request microphone access
108
+ // 2. AudioContext - Process audio in real-time
109
+ // 3. AnalyserNode - FFT analysis (256 samples → 128 frequencies)
110
+ // 4. getByteFrequencyData() - Get frequency values (0-255)
111
+ // 5. Normalize to 0-100% for bar heights
112
+ // 6. requestAnimationFrame - Smooth 60fps animation`,
113
+
114
+ // Properties: Inputs
115
+ propertyIsStartRecording: `isStartRecording: InputSignal<boolean> = input<boolean>(false);`,
116
+ propertyIsStopRecording: `isStopRecording: InputSignal<boolean> = input<boolean>(false);`,
117
+ propertyShowTimer: `showTimer: InputSignal<boolean> = input<boolean>(false);`,
118
+
119
+ // Properties: Service Signals
120
+ servicePropertyIsRecording: `isRecording: WritableSignal<boolean>`,
121
+ servicePropertyAudioData: `audioData: WritableSignal<number[]> // Bar heights (0-100%)`,
122
+ servicePropertyRecordedAudioBlob: `recordedAudioBlob: WritableSignal<Blob | null>`,
123
+ servicePropertyRecordedAudioUrl: `recordedAudioUrl: WritableSignal<string | null>`,
124
+
125
+ // Methods
126
+ methodDownloadRecording: `downloadRecording(filename?: string): void`,
127
+ methodClearRecording: `clearRecording(): void`,
128
+
129
+ // Configuration constants
130
+ configFFTSize: `FFT_SIZE = 256 // Higher = more frequency detail`,
131
+ configBarCount: `BAR_COUNT = 30 (mobile) | 65 (desktop) // Auto-responsive`,
132
+ configSmoothing: `SMOOTHING = 0.8 // 0 (no smoothing) to 1 (max smoothing)`,
133
+
134
+ // Accessibility
135
+ accessibilityExample: `<!-- The component includes built-in accessibility -->
136
+ <!-- Timer updates announced via aria-live region (when showTimer=true) -->
137
+ <!-- Waveform visualizer is decorative (aria-hidden) -->`,
138
+
139
+ // Browser Support
140
+ browserSupport: `// Requires modern browsers with:
141
+ // - Web Audio API
142
+ // - MediaStream API
143
+ // - MediaRecorder API
144
+ //
145
+ // Supported: Chrome 60+, Firefox 55+, Safari 14+, Edge 79+`,
146
+ };