wally-ui 1.7.0 → 1.8.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.
- package/package.json +1 -1
- package/playground/showcase/src/app/components/carousel/carousel.html +14 -21
- package/playground/showcase/src/app/components/carousel/carousel.ts +235 -15
- package/playground/showcase/src/app/pages/documentation/components/carousel-docs/carousel-docs.examples.ts +32 -1
- package/playground/showcase/src/app/pages/documentation/components/carousel-docs/carousel-docs.html +49 -73
- package/playground/showcase/src/app/pages/documentation/components/carousel-docs/carousel-docs.ts +2 -0
- package/playground/showcase/src/app/pages/home/home.html +0 -1
- package/playground/showcase/src/app/pages/home/home.ts +1 -2
package/package.json
CHANGED
|
@@ -1,38 +1,31 @@
|
|
|
1
1
|
<div class="w-full flex flex-col items-center gap-4">
|
|
2
|
-
<div class="relative w-
|
|
3
|
-
|
|
4
|
-
<div class="absolute inset-0 flex items-center justify-center bg-blue-500 text-white text-2xl
|
|
5
|
-
transition-all duration-700 ease-in-out"
|
|
6
|
-
[ngClass]="{
|
|
7
|
-
'translate-x-0 opacity-100': i === itemVisible(),
|
|
8
|
-
'translate-x-full opacity-0': i > itemVisible(),
|
|
9
|
-
'-translate-x-full opacity-0': i < itemVisible()
|
|
10
|
-
}">
|
|
11
|
-
{{ item }}
|
|
12
|
-
</div>
|
|
13
|
-
}
|
|
2
|
+
<div class="relative w-96 h-96 overflow-hidden shadow rounded-lg" #carouselContainer>
|
|
3
|
+
<ng-content></ng-content>
|
|
14
4
|
</div>
|
|
15
5
|
|
|
16
|
-
<div class="flex gap-
|
|
17
|
-
@for (
|
|
6
|
+
<div class="flex items-center gap-3">
|
|
7
|
+
@for (navigationDot of navigationDotsArray; track $index; let dotIndex = $index) {
|
|
18
8
|
<button
|
|
19
|
-
class="
|
|
9
|
+
class="size-2 rounded-full transition-all duration-500 ease-in-out cursor-pointer"
|
|
20
10
|
[ngClass]="{
|
|
21
|
-
'bg-blue-500 scale-
|
|
22
|
-
'bg-
|
|
11
|
+
'bg-blue-500 border scale-150': dotIndex === currentVisibleItemIndex(),
|
|
12
|
+
'bg-white hover:bg-gray-400 hover:scale-125': dotIndex !== currentVisibleItemIndex()
|
|
23
13
|
}"
|
|
24
|
-
(click)="
|
|
14
|
+
(click)="navigateToSpecificItem(dotIndex)"
|
|
15
|
+
[attr.aria-label]="'Navigate to slide ' + (dotIndex + 1)">
|
|
25
16
|
</button>
|
|
26
17
|
}
|
|
27
18
|
</div>
|
|
28
19
|
|
|
29
20
|
<div class="flex gap-4">
|
|
30
21
|
<button class="px-4 py-2 bg-gray-700 text-white rounded hover:bg-gray-600 transition-colors duration-200"
|
|
31
|
-
(click)="
|
|
32
|
-
|
|
22
|
+
(click)="navigateToPreviousItem()"
|
|
23
|
+
aria-label="Go to previous slide">
|
|
24
|
+
Previous
|
|
33
25
|
</button>
|
|
34
26
|
<button class="px-4 py-2 bg-gray-700 text-white rounded hover:bg-gray-600 transition-colors duration-200"
|
|
35
|
-
(click)="
|
|
27
|
+
(click)="navigateToNextItem()"
|
|
28
|
+
aria-label="Go to next slide">
|
|
36
29
|
Next
|
|
37
30
|
</button>
|
|
38
31
|
</div>
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Component, input, OnInit, signal } from '@angular/core';
|
|
1
|
+
import { Component, input, OnInit, signal, ViewChild, ElementRef, AfterViewInit, Renderer2, OnDestroy, HostListener } from '@angular/core';
|
|
2
2
|
import { CommonModule } from '@angular/common';
|
|
3
3
|
|
|
4
4
|
@Component({
|
|
@@ -6,32 +6,252 @@ import { CommonModule } from '@angular/common';
|
|
|
6
6
|
imports: [CommonModule],
|
|
7
7
|
templateUrl: './carousel.html',
|
|
8
8
|
})
|
|
9
|
-
export class Carousel implements OnInit {
|
|
10
|
-
|
|
11
|
-
|
|
9
|
+
export class Carousel implements OnInit, AfterViewInit, OnDestroy {
|
|
10
|
+
@ViewChild('carouselContainer', { static: false }) carouselContainer!: ElementRef;
|
|
11
|
+
|
|
12
|
+
totalItemsCount = signal<number>(0);
|
|
13
|
+
currentVisibleItemIndex = signal<number>(0);
|
|
14
|
+
carouselItemElements: HTMLElement[] = [];
|
|
15
|
+
|
|
16
|
+
// Touch and swipe gesture state
|
|
17
|
+
private gestureState = {
|
|
18
|
+
startPositionX: 0,
|
|
19
|
+
startPositionY: 0,
|
|
20
|
+
currentPositionX: 0,
|
|
21
|
+
currentPositionY: 0,
|
|
22
|
+
isCurrentlyDragging: false,
|
|
23
|
+
gestureStartTime: 0
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
// Configuration constants for touch and swipe behavior
|
|
27
|
+
private readonly MINIMUM_SWIPE_DISTANCE = 50; // minimum pixels to register as swipe
|
|
28
|
+
private readonly MINIMUM_SWIPE_VELOCITY = 0.3; // minimum velocity to register as swipe
|
|
29
|
+
private readonly MAXIMUM_SWIPE_DURATION = 300; // maximum milliseconds for swipe gesture
|
|
30
|
+
|
|
31
|
+
// Event listener cleanup functions
|
|
32
|
+
private eventListenerCleanupFunctions: (() => void)[] = [];
|
|
33
|
+
|
|
34
|
+
get navigationDotsArray() {
|
|
35
|
+
return Array(this.totalItemsCount()).fill(0);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
constructor(private renderer: Renderer2) { }
|
|
12
39
|
|
|
13
40
|
ngOnInit(): void {
|
|
14
41
|
}
|
|
15
42
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
43
|
+
ngAfterViewInit(): void {
|
|
44
|
+
if (this.carouselContainer) {
|
|
45
|
+
this.initializeCarouselItems();
|
|
46
|
+
this.setupTouchAndMouseEvents();
|
|
47
|
+
this.setupAccessibilityAttributes();
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
ngOnDestroy(): void {
|
|
52
|
+
// Clean up all event listeners to prevent memory leaks
|
|
53
|
+
this.eventListenerCleanupFunctions.forEach(cleanupFunction => cleanupFunction());
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
private initializeCarouselItems(): void {
|
|
57
|
+
// Get all direct children elements of the carousel container
|
|
58
|
+
this.carouselItemElements = Array.from(this.carouselContainer.nativeElement.children);
|
|
59
|
+
this.totalItemsCount.set(this.carouselItemElements.length);
|
|
60
|
+
|
|
61
|
+
// Apply positioning and styling to each carousel item using Renderer2
|
|
62
|
+
this.carouselItemElements.forEach((itemElement, itemIndex) => {
|
|
63
|
+
this.renderer.setStyle(itemElement, 'position', 'absolute');
|
|
64
|
+
this.renderer.setStyle(itemElement, 'inset', '0');
|
|
65
|
+
this.renderer.setStyle(itemElement, 'transition', 'transform 700ms ease-out');
|
|
66
|
+
this.renderer.setStyle(itemElement, 'display', 'flex');
|
|
67
|
+
this.renderer.setStyle(itemElement, 'align-items', 'center');
|
|
68
|
+
this.renderer.setStyle(itemElement, 'justify-content', 'center');
|
|
69
|
+
this.updateItemElementPosition(itemElement, itemIndex);
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
private setupTouchAndMouseEvents(): void {
|
|
74
|
+
const carouselContainerElement = this.carouselContainer.nativeElement;
|
|
75
|
+
|
|
76
|
+
// Touch events for mobile devices
|
|
77
|
+
const touchStartListener = this.renderer.listen(carouselContainerElement, 'touchstart', (event) => this.handleTouchStart(event));
|
|
78
|
+
const touchMoveListener = this.renderer.listen(carouselContainerElement, 'touchmove', (event) => this.handleTouchMove(event));
|
|
79
|
+
const touchEndListener = this.renderer.listen(carouselContainerElement, 'touchend', () => this.handleTouchEnd());
|
|
80
|
+
|
|
81
|
+
// Mouse events for desktop devices
|
|
82
|
+
const mouseDownListener = this.renderer.listen(carouselContainerElement, 'mousedown', (event) => this.handleMouseDown(event));
|
|
83
|
+
const mouseMoveListener = this.renderer.listen(carouselContainerElement, 'mousemove', (event) => this.handleMouseMove(event));
|
|
84
|
+
const mouseUpListener = this.renderer.listen(carouselContainerElement, 'mouseup', () => this.handleMouseUp());
|
|
85
|
+
const mouseLeaveListener = this.renderer.listen(carouselContainerElement, 'mouseleave', () => this.handleMouseUp());
|
|
86
|
+
|
|
87
|
+
// Store all cleanup functions for proper memory management
|
|
88
|
+
this.eventListenerCleanupFunctions.push(
|
|
89
|
+
touchStartListener,
|
|
90
|
+
touchMoveListener,
|
|
91
|
+
touchEndListener,
|
|
92
|
+
mouseDownListener,
|
|
93
|
+
mouseMoveListener,
|
|
94
|
+
mouseUpListener,
|
|
95
|
+
mouseLeaveListener
|
|
96
|
+
);
|
|
97
|
+
|
|
98
|
+
// Optimize touch performance by restricting to horizontal panning only
|
|
99
|
+
this.renderer.setStyle(carouselContainerElement, 'touch-action', 'pan-x');
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
private setupAccessibilityAttributes(): void {
|
|
103
|
+
const carouselContainerElement = this.carouselContainer.nativeElement;
|
|
104
|
+
|
|
105
|
+
// Set ARIA attributes for screen readers and accessibility
|
|
106
|
+
this.renderer.setAttribute(carouselContainerElement, 'role', 'region');
|
|
107
|
+
this.renderer.setAttribute(carouselContainerElement, 'aria-label', 'Carousel');
|
|
108
|
+
this.renderer.setAttribute(carouselContainerElement, 'tabindex', '0');
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
updateItemElementPosition(carouselItemElement: HTMLElement, itemIndex: number): void {
|
|
112
|
+
const currentVisibleIndex = this.currentVisibleItemIndex();
|
|
113
|
+
|
|
114
|
+
if (itemIndex === currentVisibleIndex) {
|
|
115
|
+
// Position the currently visible item at center (0% translation)
|
|
116
|
+
this.renderer.setStyle(carouselItemElement, 'transform', 'translateX(0)');
|
|
117
|
+
} else if (itemIndex > currentVisibleIndex) {
|
|
118
|
+
// Position items to the right of current item (110% translation to the right)
|
|
119
|
+
this.renderer.setStyle(carouselItemElement, 'transform', 'translateX(110%)');
|
|
120
|
+
} else {
|
|
121
|
+
// Position items to the left of current item (110% translation to the left)
|
|
122
|
+
this.renderer.setStyle(carouselItemElement, 'transform', 'translateX(-110%)');
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
updateAllItemElementPositions(): void {
|
|
127
|
+
this.carouselItemElements.forEach((itemElement, itemIndex) => {
|
|
128
|
+
this.updateItemElementPosition(itemElement, itemIndex);
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// Touch event handlers for mobile devices
|
|
133
|
+
private handleTouchStart(touchEvent: TouchEvent): void {
|
|
134
|
+
this.initializeGesture(touchEvent.touches[0].clientX, touchEvent.touches[0].clientY);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
private handleTouchMove(touchEvent: TouchEvent): void {
|
|
138
|
+
if (this.gestureState.isCurrentlyDragging) {
|
|
139
|
+
touchEvent.preventDefault(); // Prevent page scrolling during swipe
|
|
140
|
+
this.updateGesturePosition(touchEvent.touches[0].clientX, touchEvent.touches[0].clientY);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
private handleTouchEnd(): void {
|
|
145
|
+
this.finalizeGestureAndNavigate();
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// Mouse event handlers for desktop devices
|
|
149
|
+
private handleMouseDown(mouseEvent: MouseEvent): void {
|
|
150
|
+
this.initializeGesture(mouseEvent.clientX, mouseEvent.clientY);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
private handleMouseMove(mouseEvent: MouseEvent): void {
|
|
154
|
+
if (this.gestureState.isCurrentlyDragging) {
|
|
155
|
+
mouseEvent.preventDefault(); // Prevent text selection during drag
|
|
156
|
+
this.updateGesturePosition(mouseEvent.clientX, mouseEvent.clientY);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
private handleMouseUp(): void {
|
|
161
|
+
this.finalizeGestureAndNavigate();
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
// Unified gesture handling methods
|
|
165
|
+
private initializeGesture(xPosition: number, yPosition: number): void {
|
|
166
|
+
this.gestureState = {
|
|
167
|
+
startPositionX: xPosition,
|
|
168
|
+
startPositionY: yPosition,
|
|
169
|
+
currentPositionX: xPosition,
|
|
170
|
+
currentPositionY: yPosition,
|
|
171
|
+
isCurrentlyDragging: true,
|
|
172
|
+
gestureStartTime: Date.now()
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
private updateGesturePosition(xPosition: number, yPosition: number): void {
|
|
177
|
+
if (!this.gestureState.isCurrentlyDragging) return;
|
|
178
|
+
|
|
179
|
+
this.gestureState.currentPositionX = xPosition;
|
|
180
|
+
this.gestureState.currentPositionY = yPosition;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
private finalizeGestureAndNavigate(): void {
|
|
184
|
+
if (!this.gestureState.isCurrentlyDragging) return;
|
|
185
|
+
|
|
186
|
+
const horizontalDistanceMoved = this.gestureState.currentPositionX - this.gestureState.startPositionX;
|
|
187
|
+
const verticalDistanceMoved = this.gestureState.currentPositionY - this.gestureState.startPositionY;
|
|
188
|
+
const gestureDuration = Date.now() - this.gestureState.gestureStartTime;
|
|
189
|
+
const gestureVelocity = Math.abs(horizontalDistanceMoved) / gestureDuration;
|
|
190
|
+
|
|
191
|
+
// Only process horizontal swipes (ignore vertical movements)
|
|
192
|
+
if (Math.abs(horizontalDistanceMoved) > Math.abs(verticalDistanceMoved)) {
|
|
193
|
+
// Check if gesture meets minimum requirements for navigation
|
|
194
|
+
const isValidSwipeGesture = Math.abs(horizontalDistanceMoved) > this.MINIMUM_SWIPE_DISTANCE ||
|
|
195
|
+
(gestureVelocity > this.MINIMUM_SWIPE_VELOCITY && gestureDuration < this.MAXIMUM_SWIPE_DURATION);
|
|
196
|
+
|
|
197
|
+
if (isValidSwipeGesture) {
|
|
198
|
+
if (horizontalDistanceMoved > 0) {
|
|
199
|
+
this.navigateToPreviousItem(); // Swipe right = go to previous item
|
|
200
|
+
} else {
|
|
201
|
+
this.navigateToNextItem(); // Swipe left = go to next item
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
// Reset gesture state after processing
|
|
207
|
+
this.gestureState.isCurrentlyDragging = false;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
// Keyboard navigation handler
|
|
211
|
+
@HostListener('keydown', ['$event'])
|
|
212
|
+
handleKeyboardNavigation(keyboardEvent: KeyboardEvent): void {
|
|
213
|
+
switch (keyboardEvent.key) {
|
|
214
|
+
case 'ArrowLeft':
|
|
215
|
+
keyboardEvent.preventDefault();
|
|
216
|
+
this.navigateToPreviousItem();
|
|
217
|
+
break;
|
|
218
|
+
case 'ArrowRight':
|
|
219
|
+
keyboardEvent.preventDefault();
|
|
220
|
+
this.navigateToNextItem();
|
|
221
|
+
break;
|
|
222
|
+
case 'Home':
|
|
223
|
+
keyboardEvent.preventDefault();
|
|
224
|
+
this.navigateToSpecificItem(0);
|
|
225
|
+
break;
|
|
226
|
+
case 'End':
|
|
227
|
+
keyboardEvent.preventDefault();
|
|
228
|
+
this.navigateToSpecificItem(this.totalItemsCount() - 1);
|
|
229
|
+
break;
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
// Circular buffer algorithm implementation for infinite carousel navigation
|
|
234
|
+
calculateNextItemIndex(currentItemIndex: number): number {
|
|
235
|
+
return (currentItemIndex + 1) % this.totalItemsCount();
|
|
19
236
|
}
|
|
20
237
|
|
|
21
|
-
|
|
22
|
-
return (
|
|
238
|
+
calculatePreviousItemIndex(currentItemIndex: number): number {
|
|
239
|
+
return (currentItemIndex - 1 + this.totalItemsCount()) % this.totalItemsCount();
|
|
23
240
|
}
|
|
24
241
|
|
|
25
|
-
|
|
26
|
-
this.
|
|
242
|
+
navigateToNextItem(): void {
|
|
243
|
+
this.currentVisibleItemIndex.set(this.calculateNextItemIndex(this.currentVisibleItemIndex()));
|
|
244
|
+
this.updateAllItemElementPositions();
|
|
27
245
|
}
|
|
28
246
|
|
|
29
|
-
|
|
30
|
-
this.
|
|
247
|
+
navigateToPreviousItem(): void {
|
|
248
|
+
this.currentVisibleItemIndex.set(this.calculatePreviousItemIndex(this.currentVisibleItemIndex()));
|
|
249
|
+
this.updateAllItemElementPositions();
|
|
31
250
|
}
|
|
32
251
|
|
|
33
|
-
|
|
34
|
-
this.
|
|
252
|
+
navigateToSpecificItem(targetItemIndex: number): void {
|
|
253
|
+
this.currentVisibleItemIndex.set(targetItemIndex);
|
|
254
|
+
this.updateAllItemElementPositions();
|
|
35
255
|
}
|
|
36
256
|
// end test Circular Buffer ---
|
|
37
257
|
}
|
|
@@ -13,5 +13,36 @@ export const CarouselCodeExamples = {
|
|
|
13
13
|
})`,
|
|
14
14
|
|
|
15
15
|
// Basic usage
|
|
16
|
-
basicUsage: `<wally-carousel
|
|
16
|
+
basicUsage: `<wally-carousel>
|
|
17
|
+
<div>Item 1</div>
|
|
18
|
+
<div>Item 2</div>
|
|
19
|
+
</wally-carousel>`,
|
|
20
|
+
|
|
21
|
+
// Custom content example
|
|
22
|
+
customContent: `<wally-carousel>
|
|
23
|
+
<div class="w-full h-full bg-gradient-to-r from-blue-500 to-purple-600 text-white flex flex-col items-center justify-center p-6">
|
|
24
|
+
<h3 class="text-xl font-bold mb-2">Feature 1</h3>
|
|
25
|
+
<p class="text-center text-sm">Custom slide with rich content</p>
|
|
26
|
+
</div>
|
|
27
|
+
<div class="w-full h-full bg-gradient-to-r from-green-500 to-blue-500 text-white flex flex-col items-center justify-center p-6">
|
|
28
|
+
<h3 class="text-xl font-bold mb-2">Feature 2</h3>
|
|
29
|
+
<p class="text-center text-sm">Another slide with different styling</p>
|
|
30
|
+
</div>
|
|
31
|
+
</wally-carousel>`,
|
|
32
|
+
|
|
33
|
+
// Properties
|
|
34
|
+
properties: `// Component properties
|
|
35
|
+
// The carousel automatically detects child elements and creates navigation
|
|
36
|
+
// Currently no input properties - content projection only
|
|
37
|
+
|
|
38
|
+
// Available interactions:
|
|
39
|
+
// • Click navigation buttons (Previous/Next)
|
|
40
|
+
// • Click dot indicators for direct navigation
|
|
41
|
+
// • Touch/swipe gestures on mobile and desktop
|
|
42
|
+
// • Keyboard navigation (Arrow keys, Home, End)
|
|
43
|
+
|
|
44
|
+
// Auto-detected features:
|
|
45
|
+
totalItemsCount: number; // Automatically set based on child elements
|
|
46
|
+
currentVisibleItemIndex: number; // Currently visible slide index (0-based)
|
|
47
|
+
navigationDotsArray: any[]; // Auto-generated dot indicators`
|
|
17
48
|
};
|
package/playground/showcase/src/app/pages/documentation/components/carousel-docs/carousel-docs.html
CHANGED
|
@@ -8,14 +8,14 @@
|
|
|
8
8
|
Carousel
|
|
9
9
|
</h1>
|
|
10
10
|
<p class="text-gray-700 dark:text-gray-400 mb-4">
|
|
11
|
-
A
|
|
11
|
+
A carousel component with navigation controls, touch gestures, and smooth transitions.
|
|
12
12
|
</p>
|
|
13
13
|
|
|
14
14
|
<!-- Under Construction Badge -->
|
|
15
15
|
<div class="mb-6">
|
|
16
16
|
<span class="text-xs bg-yellow-500 text-black px-3 py-1 rounded-full font-medium">Under Construction</span>
|
|
17
17
|
<p class="text-sm text-gray-600 dark:text-gray-400 mt-2">
|
|
18
|
-
This component is actively being developed.
|
|
18
|
+
This component is actively being developed. Touch gestures, accessibility, and customization options are coming soon.
|
|
19
19
|
</p>
|
|
20
20
|
</div>
|
|
21
21
|
|
|
@@ -63,7 +63,17 @@
|
|
|
63
63
|
<h2 class="text-lg font-semibold mb-4 text-[#0a0a0a] dark:text-white">Preview</h2>
|
|
64
64
|
<div class="p-6 border rounded-lg bg-white dark:bg-[#121212]">
|
|
65
65
|
<div class="flex justify-center">
|
|
66
|
-
<wally-carousel
|
|
66
|
+
<wally-carousel>
|
|
67
|
+
<div class="w-full h-full bg-blue-500 text-white flex items-center justify-center text-lg font-semibold">
|
|
68
|
+
Slide 1
|
|
69
|
+
</div>
|
|
70
|
+
<div class="w-full h-full bg-green-500 text-white flex items-center justify-center text-lg font-semibold">
|
|
71
|
+
Slide 2
|
|
72
|
+
</div>
|
|
73
|
+
<div class="w-full h-full bg-purple-500 text-white flex items-center justify-center text-lg font-semibold">
|
|
74
|
+
Slide 3
|
|
75
|
+
</div>
|
|
76
|
+
</wally-carousel>
|
|
67
77
|
</div>
|
|
68
78
|
</div>
|
|
69
79
|
</section>
|
|
@@ -90,91 +100,57 @@
|
|
|
90
100
|
</div>
|
|
91
101
|
<div class="p-6 border rounded-lg bg-white dark:bg-[#121212]">
|
|
92
102
|
<div class="flex justify-center">
|
|
93
|
-
<wally-carousel
|
|
103
|
+
<wally-carousel>
|
|
104
|
+
<div class="w-full h-full bg-blue-400 text-white flex items-center justify-center">
|
|
105
|
+
Item 1
|
|
106
|
+
</div>
|
|
107
|
+
<div class="w-full h-full bg-green-400 text-white flex items-center justify-center">
|
|
108
|
+
Item 2
|
|
109
|
+
</div>
|
|
110
|
+
</wally-carousel>
|
|
94
111
|
</div>
|
|
95
112
|
</div>
|
|
96
113
|
</section>
|
|
97
114
|
|
|
98
|
-
<!--
|
|
115
|
+
<!-- Advanced Examples -->
|
|
99
116
|
<section class="mb-8">
|
|
100
|
-
<h2 class="text-lg font-semibold mb-4 text-[#0a0a0a] dark:text-white">
|
|
117
|
+
<h2 class="text-lg font-semibold mb-4 text-[#0a0a0a] dark:text-white">Advanced Examples</h2>
|
|
101
118
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
<p class="text-sm text-gray-700 dark:text-gray-400">
|
|
108
|
-
Infinite navigation using circular buffer data structure for seamless looping.
|
|
109
|
-
</p>
|
|
110
|
-
</div>
|
|
111
|
-
|
|
112
|
-
<div class="bg-gray-200 dark:bg-[#121212] p-4 rounded-lg">
|
|
113
|
-
<div class="flex items-center gap-2 mb-2">
|
|
114
|
-
<h3 class="text-md font-medium text-[#0a0a0a] dark:text-white">Smooth Transitions</h3>
|
|
115
|
-
</div>
|
|
116
|
-
<p class="text-sm text-gray-700 dark:text-gray-400">
|
|
117
|
-
Tailwind CSS v4 powered transitions with transform and opacity animations.
|
|
118
|
-
</p>
|
|
119
|
+
<!-- Custom Content Example -->
|
|
120
|
+
<div class="mb-6">
|
|
121
|
+
<h3 class="text-md font-medium mb-3 text-[#0a0a0a] dark:text-white">Custom Content</h3>
|
|
122
|
+
<div class="bg-gray-200 dark:bg-[#121212] p-4 rounded-lg mb-4">
|
|
123
|
+
<pre><code [innerHTML]="customContentCode" class="text-sm text-[#0a0a0a] dark:text-white"></code></pre>
|
|
119
124
|
</div>
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
125
|
+
<div class="p-6 border rounded-lg bg-white dark:bg-[#121212]">
|
|
126
|
+
<div class="flex justify-center">
|
|
127
|
+
<wally-carousel>
|
|
128
|
+
<div class="w-full h-full bg-gradient-to-r from-blue-500 to-purple-600 text-white flex flex-col items-center justify-center p-6">
|
|
129
|
+
<h3 class="text-xl font-bold mb-2">Feature 1</h3>
|
|
130
|
+
<p class="text-center text-sm">This is a custom slide with rich content</p>
|
|
131
|
+
</div>
|
|
132
|
+
<div class="w-full h-full bg-gradient-to-r from-green-500 to-blue-500 text-white flex flex-col items-center justify-center p-6">
|
|
133
|
+
<h3 class="text-xl font-bold mb-2">Feature 2</h3>
|
|
134
|
+
<p class="text-center text-sm">Another slide with different styling</p>
|
|
135
|
+
</div>
|
|
136
|
+
<div class="w-full h-full bg-gradient-to-r from-purple-500 to-pink-500 text-white flex flex-col items-center justify-center p-6">
|
|
137
|
+
<h3 class="text-xl font-bold mb-2">Feature 3</h3>
|
|
138
|
+
<p class="text-center text-sm">Beautiful gradients and typography</p>
|
|
139
|
+
</div>
|
|
140
|
+
</wally-carousel>
|
|
124
141
|
</div>
|
|
125
|
-
<p class="text-sm text-gray-700 dark:text-gray-400">
|
|
126
|
-
Previous/Next buttons and dot indicators for direct slide navigation.
|
|
127
|
-
</p>
|
|
128
142
|
</div>
|
|
129
143
|
</div>
|
|
130
144
|
</section>
|
|
131
145
|
|
|
132
|
-
<!--
|
|
146
|
+
<!-- Properties -->
|
|
133
147
|
<section class="mb-8">
|
|
134
|
-
<h2 class="text-lg font-semibold mb-4 text-[#0a0a0a] dark:text-white">
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
<div class="bg-gray-200 dark:bg-[#121212] p-4 rounded-lg">
|
|
138
|
-
<div class="flex items-center gap-2 mb-2">
|
|
139
|
-
<h3 class="text-md font-medium text-[#0a0a0a] dark:text-white">Auto-play</h3>
|
|
140
|
-
<span class="text-xs bg-blue-500 text-white px-2 py-1 rounded">Coming Soon</span>
|
|
141
|
-
</div>
|
|
142
|
-
<p class="text-sm text-gray-700 dark:text-gray-400">
|
|
143
|
-
Automatic slide progression with configurable intervals and pause on hover.
|
|
144
|
-
</p>
|
|
145
|
-
</div>
|
|
146
|
-
|
|
147
|
-
<div class="bg-gray-200 dark:bg-[#121212] p-4 rounded-lg">
|
|
148
|
-
<div class="flex items-center gap-2 mb-2">
|
|
149
|
-
<h3 class="text-md font-medium text-[#0a0a0a] dark:text-white">Touch Gestures</h3>
|
|
150
|
-
<span class="text-xs bg-blue-500 text-white px-2 py-1 rounded">Coming Soon</span>
|
|
151
|
-
</div>
|
|
152
|
-
<p class="text-sm text-gray-700 dark:text-gray-400">
|
|
153
|
-
Swipe support for mobile devices with momentum scrolling and gesture recognition.
|
|
154
|
-
</p>
|
|
155
|
-
</div>
|
|
156
|
-
|
|
157
|
-
<div class="bg-gray-200 dark:bg-[#121212] p-4 rounded-lg">
|
|
158
|
-
<div class="flex items-center gap-2 mb-2">
|
|
159
|
-
<h3 class="text-md font-medium text-[#0a0a0a] dark:text-white">Accessibility</h3>
|
|
160
|
-
<span class="text-xs bg-blue-500 text-white px-2 py-1 rounded">Coming Soon</span>
|
|
161
|
-
</div>
|
|
162
|
-
<p class="text-sm text-gray-700 dark:text-gray-400">
|
|
163
|
-
ARIA labels, keyboard navigation, and screen reader support for better accessibility.
|
|
164
|
-
</p>
|
|
165
|
-
</div>
|
|
166
|
-
|
|
167
|
-
<div class="bg-gray-200 dark:bg-[#121212] p-4 rounded-lg">
|
|
168
|
-
<div class="flex items-center gap-2 mb-2">
|
|
169
|
-
<h3 class="text-md font-medium text-[#0a0a0a] dark:text-white">Custom Content</h3>
|
|
170
|
-
<span class="text-xs bg-blue-500 text-white px-2 py-1 rounded">Coming Soon</span>
|
|
171
|
-
</div>
|
|
172
|
-
<p class="text-sm text-gray-700 dark:text-gray-400">
|
|
173
|
-
Support for custom slide content through content projection and templates.
|
|
174
|
-
</p>
|
|
175
|
-
</div>
|
|
148
|
+
<h2 class="text-lg font-semibold mb-4 text-[#0a0a0a] dark:text-white">Properties</h2>
|
|
149
|
+
<div class="bg-gray-200 dark:bg-[#121212] p-4 rounded-lg">
|
|
150
|
+
<pre><code [innerHTML]="propertiesCode" class="text-sm text-[#0a0a0a] dark:text-white"></code></pre>
|
|
176
151
|
</div>
|
|
177
152
|
</section>
|
|
178
153
|
|
|
154
|
+
|
|
179
155
|
</div>
|
|
180
156
|
</div>
|
package/playground/showcase/src/app/pages/documentation/components/carousel-docs/carousel-docs.ts
CHANGED
|
@@ -29,6 +29,8 @@ export class CarouselDocs {
|
|
|
29
29
|
importCode = getFormattedCode(CarouselCodeExamples.import, 'typescript');
|
|
30
30
|
componentImportCode = getFormattedCode(CarouselCodeExamples.componentImport, 'typescript');
|
|
31
31
|
basicUsageCode = getFormattedCode(CarouselCodeExamples.basicUsage, 'html');
|
|
32
|
+
customContentCode = getFormattedCode(CarouselCodeExamples.customContent, 'html');
|
|
33
|
+
propertiesCode = getFormattedCode(CarouselCodeExamples.properties, 'typescript');
|
|
32
34
|
|
|
33
35
|
constructor(
|
|
34
36
|
private aiPromptService: AiPromptService
|